Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions .github/actions/setup-python-env/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: Set up Python environment
description: Install Python and uv, then sync the locked project environment.

inputs:
python-version:
description: Python version to install.
default: '3.12'

runs:
using: composite
steps:
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
with:
python-version: ${{ inputs.python-version }}
- uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5.4.2
with:
enable-cache: true
- run: uv sync --frozen --python "$PYTHON_VERSION"
shell: bash
env:
PYTHON_VERSION: ${{ inputs.python-version }}
49 changes: 49 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
version: 2

updates:
- package-ecosystem: github-actions
directory: /
schedule:
interval: weekly
cooldown:
default-days: 7
groups:
actions:
patterns:
- '*'

- package-ecosystem: uv
directory: /
schedule:
interval: weekly
cooldown:
default-days: 7
groups:
python:
update-types:
- minor
- patch

- package-ecosystem: gomod
directory: /strix/interface/tui
schedule:
interval: weekly
cooldown:
default-days: 7
groups:
go:
update-types:
- minor
- patch

- package-ecosystem: npm
directory: /strix/interface/viewer/frontend
schedule:
interval: weekly
cooldown:
default-days: 7
groups:
viewer:
update-types:
- minor
- patch
4 changes: 3 additions & 1 deletion .github/workflows/build-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,14 @@ jobs:
python-version: '3.12'

- uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5.4.2
with:
enable-cache: false

- uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
with:
go-version: '1.24.x'
check-latest: true
cache-dependency-path: strix/interface/tui/go.sum
cache: false

- name: Build
shell: bash
Expand Down
55 changes: 55 additions & 0 deletions .github/workflows/ci-package.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
name: Package

on:
workflow_call:

permissions:
contents: read

jobs:
wheel:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
with:
persist-credentials: false
- uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
with:
go-version-file: strix/interface/tui/go.mod
cache-dependency-path: strix/interface/tui/go.sum
- uses: ./.github/actions/setup-python-env
- run: uv build --wheel
- name: Wheel ships the TUI sidecar and the viewer bundle
run: |
uv run --frozen python - <<'PY'
import glob, zipfile
(wheel,) = glob.glob("dist/*.whl")
names = zipfile.ZipFile(wheel).namelist()
assert "strix/bin/strix-tui" in names, names
assert "strix/interface/viewer/static/index.html" in names, names
assert not any(name.startswith("strix/interface/viewer/frontend/") for name in names)
assert not any(name.startswith("strix/interface/tui/cmd/") for name in names)
PY
- name: Install into a clean environment and run the CLI
run: |
uv venv --python 3.12 /tmp/strix-smoke
uv pip install --python /tmp/strix-smoke/bin/python dist/*.whl
/tmp/strix-smoke/bin/strix --version
/tmp/strix-smoke/bin/strix --help >/dev/null

binary:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
with:
persist-credentials: false
- uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
with:
go-version-file: strix/interface/tui/go.mod
cache-dependency-path: strix/interface/tui/go.sum
- uses: ./.github/actions/setup-python-env
- run: make tui-build
- run: uv run --frozen pyinstaller strix.spec --noconfirm
- run: dist/strix --version
- name: Binary bundles the TUI sidecar
run: uv run --frozen pyi-archive_viewer -l dist/strix | grep -E "strix/bin/strix-tui" >/dev/null
61 changes: 61 additions & 0 deletions .github/workflows/ci-python.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
name: Python

on:
workflow_call:

permissions:
contents: read

jobs:
lock:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
with:
persist-credentials: false
- uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5.4.2
- run: uv lock --check

ruff:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
with:
persist-credentials: false
- uses: ./.github/actions/setup-python-env
- run: uv run --frozen ruff check .
- run: uv run --frozen ruff format --check .

mypy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
with:
persist-credentials: false
- uses: ./.github/actions/setup-python-env
- run: uv run --frozen mypy strix/

bandit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
with:
persist-credentials: false
- uses: ./.github/actions/setup-python-env
- run: uv run --frozen bandit -r strix/ -c pyproject.toml

pytest:
name: pytest (${{ matrix.python-version }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ['3.12', '3.13', '3.14']
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
with:
persist-credentials: false
- uses: ./.github/actions/setup-python-env
with:
python-version: ${{ matrix.python-version }}
- run: uv run --frozen pytest -q
26 changes: 26 additions & 0 deletions .github/workflows/ci-tui.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: TUI

on:
workflow_call:

permissions:
contents: read

jobs:
go:
runs-on: ubuntu-latest
defaults:
run:
working-directory: strix/interface/tui
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
with:
persist-credentials: false
- uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
with:
go-version-file: strix/interface/tui/go.mod
cache-dependency-path: strix/interface/tui/go.sum
- run: test -z "$(gofmt -l .)"
- run: go vet ./...
- run: CGO_ENABLED=0 go build -trimpath -o /dev/null ./cmd/strix-tui
- run: go test -race ./...
27 changes: 27 additions & 0 deletions .github/workflows/ci-viewer.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: Viewer

on:
workflow_call:

permissions:
contents: read

jobs:
build:
runs-on: ubuntu-latest
defaults:
run:
working-directory: strix/interface/viewer/frontend
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
with:
persist-credentials: false
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: '24'
cache: npm
cache-dependency-path: strix/interface/viewer/frontend/package-lock.json
- run: npm ci --no-audit --no-fund
- run: npm run build
- name: Committed viewer bundle matches the build
run: git -C "$GITHUB_WORKSPACE" diff --exit-code --stat -- strix/interface/viewer/static && test -z "$(git -C "$GITHUB_WORKSPACE" status --porcelain -- strix/interface/viewer/static)"
37 changes: 37 additions & 0 deletions .github/workflows/ci-workflows.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: Workflows

on:
workflow_call:

permissions:
contents: read

jobs:
actionlint:
runs-on: ubuntu-latest
env:
ACTIONLINT_VERSION: 1.7.12
ACTIONLINT_SCRIPT_REF: 914e7df21a07ef503a81201c76d2b11c789d3fca # v1.7.12
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
with:
persist-credentials: false
- name: Install actionlint
run: |
mkdir -p "$RUNNER_TEMP/actionlint"
curl -fsSL --retry 5 -o "$RUNNER_TEMP/actionlint/download.bash" \
"https://raw.githubusercontent.com/rhysd/actionlint/$ACTIONLINT_SCRIPT_REF/scripts/download-actionlint.bash"
bash "$RUNNER_TEMP/actionlint/download.bash" "$ACTIONLINT_VERSION" "$RUNNER_TEMP/actionlint"
- run: |
"$RUNNER_TEMP/actionlint/actionlint" -color

zizmor:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
with:
persist-credentials: false
- uses: zizmorcore/zizmor-action@cc914d7f3750a2d13d75c7f184a1060aa0e9d482 # v0.6.4
with:
advanced-security: false
version: 1.22.0
52 changes: 52 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
name: CI

on:
pull_request:
push:
branches:
- main
workflow_dispatch:

permissions:
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
python:
uses: ./.github/workflows/ci-python.yml

tui:
uses: ./.github/workflows/ci-tui.yml

viewer:
uses: ./.github/workflows/ci-viewer.yml

package:
uses: ./.github/workflows/ci-package.yml

workflows:
uses: ./.github/workflows/ci-workflows.yml

ci-passed:
name: ci-passed
if: always()
needs:
- python
- tui
- viewer
- package
- workflows
runs-on: ubuntu-latest
steps:
- name: Every job succeeded
env:
NEEDS: ${{ toJSON(needs) }}
run: |
failing=$(jq -r 'to_entries[] | select(.value.result != "success") | "\(.key): \(.value.result)"' <<< "$NEEDS")
if [ -n "$failing" ]; then
echo "$failing"
exit 1
fi
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ exclude: ^strix/interface/viewer/static/assets/
repos:
# Ruff for fast linting and formatting
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.11.13
rev: v0.15.20
hooks:
- id: ruff
args: [--fix, --exit-non-zero-on-fix]
Expand Down
2 changes: 1 addition & 1 deletion tests/test_tool_call_ids_providers.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ class _Gateway(BaseHTTPRequestHandler):
def log_message(self, *args: Any) -> None:
pass

def do_POST(self) -> None: # noqa: N802
def do_POST(self) -> None:
length = int(self.headers.get("Content-Length", 0))
body = json.loads(self.rfile.read(length) or b"{}")
messages = body.get("messages", [])
Expand Down
Loading