agent-shell-py 0.4.0__tar.gz → 0.5.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/.github/workflows/build.yml +13 -2
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/.github/workflows/ci.yml +15 -2
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/.gitignore +9 -0
- agent_shell_py-0.5.0/AGENTS.md +115 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/PKG-INFO +1 -1
- agent_shell_py-0.5.0/docs/architecture/class_diagram.md +501 -0
- agent_shell_py-0.5.0/docs/architecture/dependency_boundaries.md +88 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/docs/development/agent_parameter_comparison.md +113 -1
- agent_shell_py-0.5.0/docs/development/import_linter_audit.md +79 -0
- agent_shell_py-0.5.0/docs/development/issue_25_plan.md +64 -0
- agent_shell_py-0.5.0/docs/development/package_management.md +64 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/docs/examples.md +138 -1
- agent_shell_py-0.5.0/pyproject.toml +133 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/src/agent_shell/__init__.py +4 -1
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/src/agent_shell/_version.py +2 -2
- agent_shell_py-0.5.0/src/agent_shell/adapters/agent_adapter_protocol.py +3 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/src/agent_shell/adapters/claude_code_adapter.py +46 -30
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/src/agent_shell/adapters/codex_adapter.py +25 -29
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/src/agent_shell/adapters/copilot_cli_adapter.py +38 -33
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/src/agent_shell/adapters/cursor_adapter.py +31 -30
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/src/agent_shell/adapters/grok_adapter.py +27 -27
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/src/agent_shell/adapters/opencode_adapter.py +37 -31
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/src/agent_shell/adapters/pi_adapter.py +76 -30
- agent_shell_py-0.5.0/src/agent_shell/adapters/pi_resources.py +97 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/src/agent_shell/adapters/response.py +15 -3
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/src/agent_shell/adapters/tool_denial.py +6 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/src/agent_shell/execution.py +7 -79
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/src/agent_shell/interactive.py +43 -34
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/src/agent_shell/interactive_terminal.py +117 -64
- agent_shell_py-0.5.0/src/agent_shell/models/resources.py +25 -0
- agent_shell_py-0.5.0/src/agent_shell/ports/__init__.py +1 -0
- agent_shell_py-0.4.0/src/agent_shell/adapters/agent_adapter_protocol.py → agent_shell_py-0.5.0/src/agent_shell/ports/agent.py +7 -2
- agent_shell_py-0.5.0/src/agent_shell/ports/execution.py +84 -0
- agent_shell_py-0.5.0/src/agent_shell/ports/interactive.py +68 -0
- agent_shell_py-0.5.0/src/agent_shell/ports/resources.py +28 -0
- agent_shell_py-0.5.0/src/agent_shell/resources.py +162 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/src/agent_shell/shell.py +65 -33
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/src/agent_shell/tmux.py +101 -1
- agent_shell_py-0.5.0/tests/e2e/test_interactive_attachment_e2e.py +60 -0
- agent_shell_py-0.5.0/tests/e2e/test_session_resources_e2e.py +190 -0
- agent_shell_py-0.5.0/tests/integration/test_architecture.py +296 -0
- agent_shell_py-0.5.0/tests/integration/test_interactive_attachment.py +342 -0
- agent_shell_py-0.5.0/tests/integration/test_session_resources.py +778 -0
- agent_shell_py-0.5.0/tests/unit/test_interactive_attachment.py +93 -0
- agent_shell_py-0.5.0/tests/unit/test_port_exports.py +36 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/unit/test_shell.py +10 -10
- agent_shell_py-0.5.0/tests/unit/test_shell_cancellation.py +32 -0
- agent_shell_py-0.5.0/uv.lock +244 -0
- agent_shell_py-0.4.0/AGENTS.md +0 -310
- agent_shell_py-0.4.0/docs/development/package_management.md +0 -24
- agent_shell_py-0.4.0/pyproject.toml +0 -33
- agent_shell_py-0.4.0/tests/unit/test_shell_cancellation.py +0 -72
- agent_shell_py-0.4.0/uv.lock +0 -104
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/.github/workflows/publish.yml +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/.python-version +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/LICENSE +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/README.md +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/docs/assets/agentshell-banner.png +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/docs/assets/agentshell-banner.svg +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/docs/development/disabled_tools.md +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/docs/development/info.md +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/docs/development/total_token_count.md +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/examples/interactive_demo.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/skills/delegating-code-review/SKILL.md +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/skills/invoking-cli-agents/SKILL.md +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/skills/invoking-cli-agents/api-reference.md +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/src/agent_shell/adapters/__init__.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/src/agent_shell/adapters/health.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/src/agent_shell/adapters/model_discovery.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/src/agent_shell/adapters/outcome.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/src/agent_shell/adapters/process_failure.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/src/agent_shell/adapters/stderr_format.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/src/agent_shell/herdr.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/src/agent_shell/herdr_protocol.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/src/agent_shell/herdr_worker.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/src/agent_shell/interactive_event_writer.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/src/agent_shell/interactive_worker.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/src/agent_shell/models/__init__.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/src/agent_shell/models/agent.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/src/agent_shell/process_cleanup.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/src/agent_shell/process_guardian.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/src/agent_shell/terminal_protocol.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/src/agent_shell/terminal_window.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/src/agent_shell/terminal_worker.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/src/agent_shell/tmux_bridge.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/src/agent_shell/tmux_ownership.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/src/agent_shell/tmux_protocol.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/__init__.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/conftest.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/e2e/__init__.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/e2e/test_claude_code_e2e.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/e2e/test_codex_e2e.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/e2e/test_copilot_cli_e2e.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/e2e/test_cursor_e2e.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/e2e/test_execution_host_e2e.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/e2e/test_grok_e2e.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/e2e/test_health_check_e2e.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/e2e/test_interactive_harness_e2e.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/e2e/test_model_discovery_e2e.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/e2e/test_opencode_e2e.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/e2e/test_pi_e2e.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/e2e/test_pi_packages_e2e.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/e2e/test_terminal_window_execution_host_e2e.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/e2e/test_tmux_execution_host_e2e.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/integration/__init__.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/integration/test_claude_code_integration.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/integration/test_claude_code_mcp_integration.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/integration/test_codex_integration.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/integration/test_codex_mcp_integration.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/integration/test_copilot_cli_integration.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/integration/test_copilot_cli_mcp_integration.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/integration/test_cursor_integration.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/integration/test_cursor_mcp_integration.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/integration/test_execution_host.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/integration/test_grok_integration.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/integration/test_grok_mcp_integration.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/integration/test_health_check_integration.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/integration/test_herdr_execution_host.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/integration/test_interactive_agents.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/integration/test_interactive_terminal.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/integration/test_model_discovery_integration.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/integration/test_opencode_integration.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/integration/test_opencode_mcp_integration.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/integration/test_packages_unsupported.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/integration/test_pi_integration.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/integration/test_pi_mcp_integration.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/integration/test_pi_packages.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/integration/test_process_lifecycle.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/integration/test_terminal_window_execution_host.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/integration/test_tmux_execution_host.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/unit/__init__.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/unit/adapter_matrix.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/unit/codex_fixtures.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/unit/copilot_fixtures.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/unit/cursor_fixtures.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/unit/fixtures.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/unit/grok_fixtures.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/unit/opencode_fixtures.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/unit/pi_fixtures.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/unit/test_adapter_transport.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/unit/test_cancel.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/unit/test_codex_cancel.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/unit/test_codex_execute.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/unit/test_codex_parse_event.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/unit/test_codex_warnings.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/unit/test_copilot_cli_cancel.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/unit/test_copilot_cli_execute.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/unit/test_copilot_cli_parse_event.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/unit/test_copilot_cli_stream.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/unit/test_cursor_cancel.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/unit/test_cursor_execute.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/unit/test_cursor_parse_event.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/unit/test_cursor_warnings.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/unit/test_execute.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/unit/test_execute_outcome.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/unit/test_grok_cancel.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/unit/test_grok_execute.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/unit/test_grok_parse_event.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/unit/test_grok_warnings.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/unit/test_health_probe.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/unit/test_mcp_server_spec.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/unit/test_model_discovery.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/unit/test_models.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/unit/test_opencode_cancel.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/unit/test_opencode_execute.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/unit/test_opencode_parse_event.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/unit/test_opencode_spawn.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/unit/test_opencode_stream.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/unit/test_package_spec.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/unit/test_parse_event.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/unit/test_pi_cancel.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/unit/test_pi_execute.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/unit/test_pi_parse_event.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/unit/test_pi_warnings.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/unit/test_process_cleanup.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/unit/test_process_group_registration.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/unit/test_public_exports.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/unit/test_response_aggregation.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/unit/test_shell_mcp.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/unit/test_stderr_format.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/unit/test_stream.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/unit/test_terminal_window_execution_host.py +0 -0
- {agent_shell_py-0.4.0 → agent_shell_py-0.5.0}/tests/unit/test_tool_denial.py +0 -0
|
@@ -4,6 +4,13 @@ on:
|
|
|
4
4
|
push:
|
|
5
5
|
tags: ["v*"]
|
|
6
6
|
|
|
7
|
+
permissions:
|
|
8
|
+
contents: read
|
|
9
|
+
|
|
10
|
+
concurrency:
|
|
11
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
12
|
+
cancel-in-progress: true
|
|
13
|
+
|
|
7
14
|
jobs:
|
|
8
15
|
build:
|
|
9
16
|
runs-on: ubuntu-latest
|
|
@@ -12,6 +19,7 @@ jobs:
|
|
|
12
19
|
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
13
20
|
with:
|
|
14
21
|
fetch-depth: 0
|
|
22
|
+
persist-credentials: false
|
|
15
23
|
|
|
16
24
|
- name: Install uv
|
|
17
25
|
uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
|
|
@@ -20,10 +28,13 @@ jobs:
|
|
|
20
28
|
run: uv python install 3.12
|
|
21
29
|
|
|
22
30
|
- name: Install dependencies
|
|
23
|
-
run: uv sync --group dev
|
|
31
|
+
run: uv sync --locked --group dev
|
|
32
|
+
|
|
33
|
+
- name: Check architecture boundaries
|
|
34
|
+
run: uv run --no-sync lint-imports --no-cache
|
|
24
35
|
|
|
25
36
|
- name: Run unit and integration tests
|
|
26
|
-
run: uv run pytest tests/unit tests/integration -v
|
|
37
|
+
run: uv run --no-sync pytest tests/unit tests/integration -v
|
|
27
38
|
|
|
28
39
|
- name: Build package
|
|
29
40
|
run: uv build
|
|
@@ -6,15 +6,25 @@ on:
|
|
|
6
6
|
pull_request:
|
|
7
7
|
branches: [main]
|
|
8
8
|
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
concurrency:
|
|
13
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
14
|
+
cancel-in-progress: true
|
|
15
|
+
|
|
9
16
|
jobs:
|
|
10
17
|
test:
|
|
11
18
|
runs-on: ubuntu-latest
|
|
12
19
|
strategy:
|
|
20
|
+
fail-fast: false
|
|
13
21
|
matrix:
|
|
14
22
|
python-version: ["3.12"]
|
|
15
23
|
|
|
16
24
|
steps:
|
|
17
25
|
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
26
|
+
with:
|
|
27
|
+
persist-credentials: false
|
|
18
28
|
|
|
19
29
|
- name: Install uv
|
|
20
30
|
uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
|
|
@@ -23,7 +33,10 @@ jobs:
|
|
|
23
33
|
run: uv python install ${{ matrix.python-version }}
|
|
24
34
|
|
|
25
35
|
- name: Install dependencies
|
|
26
|
-
run: uv sync --group dev
|
|
36
|
+
run: uv sync --locked --group dev
|
|
37
|
+
|
|
38
|
+
- name: Check architecture boundaries
|
|
39
|
+
run: uv run --no-sync lint-imports --no-cache
|
|
27
40
|
|
|
28
41
|
- name: Run unit and integration tests
|
|
29
|
-
run: uv run pytest tests/unit tests/integration -v
|
|
42
|
+
run: uv run --no-sync pytest tests/unit tests/integration -v
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# Agent Shell
|
|
2
|
+
|
|
3
|
+
A lightweight, async Python package that executes CLI coding agents headlessly and returns output
|
|
4
|
+
through a unified interface. Each agent's CLI differences are hidden behind a common adapter
|
|
5
|
+
protocol, so consuming code never changes regardless of which agent is running underneath.
|
|
6
|
+
|
|
7
|
+
## Architecture
|
|
8
|
+
|
|
9
|
+
Before any planning, discussion of solution or code change work begins, you must read the
|
|
10
|
+
[architecture class diagram](docs/architecture/class_diagram.md). It documents the interfaces,
|
|
11
|
+
execution hosts, isolation policies, interactive sessions, and API behaviour.
|
|
12
|
+
|
|
13
|
+
Keep agent-specific CLI flags, raw output parsing, configuration formats, and workarounds in
|
|
14
|
+
that agent's adapter or agent-specific helpers. Shared code must use protocols and normalised
|
|
15
|
+
models, not agent-name branches, concrete-adapter checks, private adapter state, or copied
|
|
16
|
+
agent-specific logic. Host-specific terminal/process details belong in execution hosts.
|
|
17
|
+
Concrete agent-adapter imports are permitted only in `shell.py` for construction/selection;
|
|
18
|
+
shared helpers under `adapters/` are not exempt. Import Linter contracts in `pyproject.toml`
|
|
19
|
+
enforce the [dependency boundaries](docs/architecture/dependency_boundaries.md), including
|
|
20
|
+
indirect imports. New inner code uses `ports/`, not implementation-bearing compatibility
|
|
21
|
+
facades. New top-level modules and adapter helpers must be classified in the contracts.
|
|
22
|
+
Review must still catch copied agent-specific logic and dynamic imports.
|
|
23
|
+
If a shared contract cannot express a feature, discuss the boundary change before adding a
|
|
24
|
+
workaround or weakening the test.
|
|
25
|
+
|
|
26
|
+
## Supported Agents
|
|
27
|
+
|
|
28
|
+
- [x] Claude Code
|
|
29
|
+
- [x] OpenCode
|
|
30
|
+
- [x] Copilot CLI
|
|
31
|
+
- [x] Codex
|
|
32
|
+
- [x] Pi
|
|
33
|
+
- [x] Cursor
|
|
34
|
+
- [x] Grok
|
|
35
|
+
|
|
36
|
+
## MCP Server Configuration
|
|
37
|
+
|
|
38
|
+
`AgentShell` exposes a unified API for registering MCP servers across all supported agents:
|
|
39
|
+
|
|
40
|
+
```python
|
|
41
|
+
from agent_shell.shell import AgentShell
|
|
42
|
+
from agent_shell.models.agent import AgentType, MCPServerSpec, MCPServerType
|
|
43
|
+
|
|
44
|
+
shell = AgentShell(agent_type=AgentType.CLAUDE_CODE)
|
|
45
|
+
|
|
46
|
+
await shell.add_mcp_server(MCPServerSpec(
|
|
47
|
+
name="forgetful",
|
|
48
|
+
type=MCPServerType.STDIO,
|
|
49
|
+
command="uvx",
|
|
50
|
+
args=["forgetful-ai"],
|
|
51
|
+
env={"FORGETFUL_API_KEY": "..."},
|
|
52
|
+
))
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
All adapters write to user-scope configuration:
|
|
56
|
+
|
|
57
|
+
| Agent | Mechanism | Location |
|
|
58
|
+
|-------|-----------|----------|
|
|
59
|
+
| Claude Code | `claude mcp add --scope user` subprocess | `~/.claude.json` (managed by CLI) |
|
|
60
|
+
| OpenCode | direct JSON file write | `~/.config/opencode/opencode.json` |
|
|
61
|
+
| Copilot CLI | direct JSON file write | `~/.copilot/mcp-config.json` |
|
|
62
|
+
| Codex | `codex mcp add` subprocess | Codex config |
|
|
63
|
+
| Cursor | direct JSON file write | `~/.cursor/mcp.json` |
|
|
64
|
+
| Grok | `grok mcp add --scope user` subprocess | `~/.grok/config.toml` (managed by CLI) |
|
|
65
|
+
|
|
66
|
+
Adds are idempotent (update existing entries with the same name). Cursor preserves native fields
|
|
67
|
+
that `MCPServerSpec` cannot represent when an update keeps the same transport, and writes its file
|
|
68
|
+
atomically with user-only permissions. Removes warn rather than raise when the named server is not
|
|
69
|
+
found. Claude Code listing reads the user-scope `mcpServers`
|
|
70
|
+
entries from `~/.claude.json` directly, avoiding the health checks and human-readable output of
|
|
71
|
+
`claude mcp list`. Cursor manages user-scope MCP entries directly in `~/.cursor/mcp.json` because
|
|
72
|
+
its `mcp` subcommands have no add/remove commands. Grok listing reads user-scope `mcp_servers`
|
|
73
|
+
entries from `~/.grok/config.toml` directly for the same reason. Pi's MCP add/remove/list methods
|
|
74
|
+
raise `NotImplementedError`.
|
|
75
|
+
|
|
76
|
+
## Package Management
|
|
77
|
+
|
|
78
|
+
See [package management](docs/development/package_management.md) for the API, Pi behaviour,
|
|
79
|
+
scope, and validation details.
|
|
80
|
+
|
|
81
|
+
## Test Philosophy
|
|
82
|
+
|
|
83
|
+
Tests validate real functionality, not code coverage metrics. Three tiers, each with a distinct
|
|
84
|
+
purpose:
|
|
85
|
+
|
|
86
|
+
| Tier | Scope | Runs in CI | Real CLI calls |
|
|
87
|
+
|------|-------|-----------|----------------|
|
|
88
|
+
| **Unit** | Isolated parsing, adapter resolution, input validation | Yes | No |
|
|
89
|
+
| **Integration** | Shell -> adapter -> parser, with mocked agent subprocess | Yes | No |
|
|
90
|
+
| **E2E** | Real CLI calls; usually real API costs | No (local only) | Yes |
|
|
91
|
+
|
|
92
|
+
The model-discovery E2E test is the exception: it calls all seven real CLIs but only reads
|
|
93
|
+
metadata, so it sends no inference request and incurs no model-token cost.
|
|
94
|
+
|
|
95
|
+
Integration tests mirror the E2E tests but substitute mocked subprocesses emitting captured CLI
|
|
96
|
+
output fixtures. This lets CI validate the full class interaction chain without credentials or API
|
|
97
|
+
spend. E2E tests remain local smoke tests for the real agents.
|
|
98
|
+
|
|
99
|
+
All tests follow the **AAA pattern** (Arrange, Act, Assert).
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
# Architecture contracts (development dependency only)
|
|
103
|
+
uv run --locked lint-imports --no-cache
|
|
104
|
+
|
|
105
|
+
# CI suite (unit + integration, including deliberate boundary violations in temp copies)
|
|
106
|
+
uv run --locked pytest tests/unit tests/integration -v
|
|
107
|
+
|
|
108
|
+
# Full suite including E2E (requires agent CLI + credentials)
|
|
109
|
+
uv run pytest -v
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## CI/CD
|
|
113
|
+
|
|
114
|
+
- **CI**: Runs architecture contracts and unit + integration tests on every push and PR
|
|
115
|
+
- **Build**: Triggers on `v*` tags, runs contracts/tests then builds release artifacts
|