diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..bfe79ad --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,46 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + branches: [main] + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + +permissions: + contents: read + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 + + - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5 + with: + python-version: '3.12' + + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + with: + node-version: '24' + + - name: Install Python package and checks + run: python -m pip install -e '.[dev]' + + - name: Check Python + run: | + ruff check src tests + ruff format --check src tests + mypy src + python -m pytest -q + + - name: Install Bun and JavaScript dependencies + run: | + npm install --global bun@1.4.2 + bun install --frozen-lockfile + + - name: Check OpenCode binding + run: bun test diff --git a/src/musubi_opencode/bridge.py b/src/musubi_opencode/bridge.py index e031fca..814880f 100644 --- a/src/musubi_opencode/bridge.py +++ b/src/musubi_opencode/bridge.py @@ -25,9 +25,7 @@ def _degraded(reason: str) -> None: root = runtime.data_root() root.mkdir(parents=True, exist_ok=True, mode=0o700) with (root / "degraded.jsonl").open("a", encoding="utf-8") as handle: - handle.write( - json.dumps({"at": datetime.now(UTC).isoformat(), "reason": reason}) + "\n" - ) + handle.write(json.dumps({"at": datetime.now(UTC).isoformat(), "reason": reason}) + "\n") except OSError: pass @@ -152,7 +150,11 @@ def main() -> int: raise AdapterError("request_invalid") response = handle(request) except ( - AdapterError, RuntimeConfigError, ValueError, OSError, subprocess.SubprocessError + AdapterError, + RuntimeConfigError, + ValueError, + OSError, + subprocess.SubprocessError, ) as exc: reason = ( str(exc) diff --git a/tests/test_mcp.py b/tests/test_mcp.py index e4859ae..44b6162 100644 --- a/tests/test_mcp.py +++ b/tests/test_mcp.py @@ -14,7 +14,11 @@ def test_mcp_lists_tools_without_seat_token(monkeypatch): response = json.loads(output.getvalue()) names = {tool["name"] for tool in response["result"]["tools"]} assert names == { - "musubi_recent", "musubi_search", "musubi_get", "musubi_remember", "musubi_status" + "musubi_recent", + "musubi_search", + "musubi_get", + "musubi_remember", + "musubi_status", } @@ -26,7 +30,9 @@ def test_mcp_call_without_identity_reports_unavailable(monkeypatch): [ json.dumps( { - "jsonrpc": "2.0", "id": 2, "method": "tools/call", + "jsonrpc": "2.0", + "id": 2, + "method": "tools/call", "params": {"name": "musubi_status", "arguments": {}}, } )