agent-shell-py 0.3.2__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.3.2 → agent_shell_py-0.5.0}/.github/workflows/build.yml +13 -2
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/.github/workflows/ci.yml +15 -2
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/.gitignore +9 -0
- agent_shell_py-0.5.0/AGENTS.md +115 -0
- agent_shell_py-0.5.0/PKG-INFO +120 -0
- agent_shell_py-0.5.0/README.md +111 -0
- 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.5.0/docs/assets/agentshell-banner.png +0 -0
- agent_shell_py-0.5.0/docs/assets/agentshell-banner.svg +1 -0
- {agent_shell_py-0.3.2 → 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.3.2/PKG-INFO → agent_shell_py-0.5.0/docs/examples.md +229 -127
- agent_shell_py-0.5.0/examples/interactive_demo.py +129 -0
- agent_shell_py-0.5.0/pyproject.toml +133 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/src/agent_shell/__init__.py +4 -1
- {agent_shell_py-0.3.2 → 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.3.2 → agent_shell_py-0.5.0}/src/agent_shell/adapters/claude_code_adapter.py +108 -27
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/src/agent_shell/adapters/codex_adapter.py +73 -26
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/src/agent_shell/adapters/copilot_cli_adapter.py +97 -27
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/src/agent_shell/adapters/cursor_adapter.py +85 -26
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/src/agent_shell/adapters/grok_adapter.py +101 -26
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/src/agent_shell/adapters/health.py +2 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/src/agent_shell/adapters/opencode_adapter.py +111 -27
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/src/agent_shell/adapters/pi_adapter.py +264 -27
- agent_shell_py-0.5.0/src/agent_shell/adapters/pi_resources.py +97 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/src/agent_shell/adapters/response.py +15 -3
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/src/agent_shell/adapters/tool_denial.py +6 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/src/agent_shell/execution.py +7 -79
- agent_shell_py-0.5.0/src/agent_shell/interactive.py +196 -0
- agent_shell_py-0.5.0/src/agent_shell/interactive_event_writer.py +19 -0
- agent_shell_py-0.5.0/src/agent_shell/interactive_terminal.py +287 -0
- agent_shell_py-0.5.0/src/agent_shell/interactive_worker.py +111 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/src/agent_shell/models/agent.py +12 -0
- 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.3.2/src/agent_shell/adapters/agent_adapter_protocol.py → agent_shell_py-0.5.0/src/agent_shell/ports/agent.py +23 -3
- 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.3.2 → agent_shell_py-0.5.0}/src/agent_shell/process_cleanup.py +7 -68
- agent_shell_py-0.5.0/src/agent_shell/process_guardian.py +98 -0
- agent_shell_py-0.5.0/src/agent_shell/resources.py +162 -0
- agent_shell_py-0.5.0/src/agent_shell/shell.py +253 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/src/agent_shell/tmux.py +178 -73
- agent_shell_py-0.5.0/src/agent_shell/tmux_ownership.py +39 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/e2e/test_codex_e2e.py +9 -2
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/e2e/test_execution_host_e2e.py +4 -2
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/e2e/test_health_check_e2e.py +9 -3
- agent_shell_py-0.5.0/tests/e2e/test_interactive_attachment_e2e.py +60 -0
- agent_shell_py-0.5.0/tests/e2e/test_interactive_harness_e2e.py +136 -0
- agent_shell_py-0.5.0/tests/e2e/test_pi_packages_e2e.py +114 -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.3.2 → agent_shell_py-0.5.0}/tests/integration/test_health_check_integration.py +18 -0
- agent_shell_py-0.5.0/tests/integration/test_interactive_agents.py +549 -0
- agent_shell_py-0.5.0/tests/integration/test_interactive_attachment.py +342 -0
- agent_shell_py-0.5.0/tests/integration/test_interactive_terminal.py +748 -0
- agent_shell_py-0.5.0/tests/integration/test_packages_unsupported.py +20 -0
- agent_shell_py-0.5.0/tests/integration/test_pi_packages.py +337 -0
- agent_shell_py-0.5.0/tests/integration/test_session_resources.py +778 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/integration/test_tmux_execution_host.py +45 -21
- agent_shell_py-0.5.0/tests/unit/test_interactive_attachment.py +93 -0
- agent_shell_py-0.5.0/tests/unit/test_package_spec.py +10 -0
- agent_shell_py-0.5.0/tests/unit/test_port_exports.py +36 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_process_cleanup.py +1 -1
- {agent_shell_py-0.3.2 → 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.3.2/AGENTS.md +0 -300
- agent_shell_py-0.3.2/README.md +0 -542
- agent_shell_py-0.3.2/docs/assets/skill_banner.png +0 -0
- agent_shell_py-0.3.2/pyproject.toml +0 -33
- agent_shell_py-0.3.2/src/agent_shell/shell.py +0 -181
- agent_shell_py-0.3.2/tests/unit/test_shell_cancellation.py +0 -72
- agent_shell_py-0.3.2/uv.lock +0 -104
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/.github/workflows/publish.yml +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/.python-version +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/LICENSE +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/docs/development/disabled_tools.md +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/docs/development/info.md +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/docs/development/total_token_count.md +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/skills/delegating-code-review/SKILL.md +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/skills/invoking-cli-agents/SKILL.md +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/skills/invoking-cli-agents/api-reference.md +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/src/agent_shell/adapters/__init__.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/src/agent_shell/adapters/model_discovery.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/src/agent_shell/adapters/outcome.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/src/agent_shell/adapters/process_failure.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/src/agent_shell/adapters/stderr_format.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/src/agent_shell/herdr.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/src/agent_shell/herdr_protocol.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/src/agent_shell/herdr_worker.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/src/agent_shell/models/__init__.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/src/agent_shell/terminal_protocol.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/src/agent_shell/terminal_window.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/src/agent_shell/terminal_worker.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/src/agent_shell/tmux_bridge.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/src/agent_shell/tmux_protocol.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/__init__.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/conftest.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/e2e/__init__.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/e2e/test_claude_code_e2e.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/e2e/test_copilot_cli_e2e.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/e2e/test_cursor_e2e.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/e2e/test_grok_e2e.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/e2e/test_model_discovery_e2e.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/e2e/test_opencode_e2e.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/e2e/test_pi_e2e.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/e2e/test_terminal_window_execution_host_e2e.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/e2e/test_tmux_execution_host_e2e.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/integration/__init__.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/integration/test_claude_code_integration.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/integration/test_claude_code_mcp_integration.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/integration/test_codex_integration.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/integration/test_codex_mcp_integration.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/integration/test_copilot_cli_integration.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/integration/test_copilot_cli_mcp_integration.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/integration/test_cursor_integration.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/integration/test_cursor_mcp_integration.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/integration/test_execution_host.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/integration/test_grok_integration.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/integration/test_grok_mcp_integration.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/integration/test_herdr_execution_host.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/integration/test_model_discovery_integration.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/integration/test_opencode_integration.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/integration/test_opencode_mcp_integration.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/integration/test_pi_integration.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/integration/test_pi_mcp_integration.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/integration/test_process_lifecycle.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/integration/test_terminal_window_execution_host.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/__init__.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/adapter_matrix.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/codex_fixtures.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/copilot_fixtures.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/cursor_fixtures.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/fixtures.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/grok_fixtures.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/opencode_fixtures.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/pi_fixtures.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_adapter_transport.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_cancel.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_codex_cancel.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_codex_execute.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_codex_parse_event.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_codex_warnings.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_copilot_cli_cancel.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_copilot_cli_execute.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_copilot_cli_parse_event.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_copilot_cli_stream.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_cursor_cancel.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_cursor_execute.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_cursor_parse_event.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_cursor_warnings.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_execute.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_execute_outcome.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_grok_cancel.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_grok_execute.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_grok_parse_event.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_grok_warnings.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_health_probe.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_mcp_server_spec.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_model_discovery.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_models.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_opencode_cancel.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_opencode_execute.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_opencode_parse_event.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_opencode_spawn.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_opencode_stream.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_parse_event.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_pi_cancel.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_pi_execute.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_pi_parse_event.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_pi_warnings.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_process_group_registration.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_public_exports.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_response_aggregation.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_shell_mcp.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_stderr_format.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_stream.py +0 -0
- {agent_shell_py-0.3.2 → agent_shell_py-0.5.0}/tests/unit/test_terminal_window_execution_host.py +0 -0
- {agent_shell_py-0.3.2 → 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
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: agent-shell-py
|
|
3
|
+
Version: 0.5.0
|
|
4
|
+
Summary: A lightweight abstraction for executing CLI coding agents headlessly
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
License-File: LICENSE
|
|
7
|
+
Requires-Python: >=3.12
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
|
|
10
|
+

|
|
11
|
+
|
|
12
|
+
<h1 align="center">Agent Shell</h1>
|
|
13
|
+
Agent Shell is a light weight abstraction for executing a cli coding agent headlessly
|
|
14
|
+
and returning the output that can be used programatically as a unified contract
|
|
15
|
+
|
|
16
|
+
## Features
|
|
17
|
+
|
|
18
|
+
- **One unified contract** — the same `execute`, `stream`, `health_check`, and
|
|
19
|
+
`list_models` API across every agent; swap the backend without changing consuming code.
|
|
20
|
+
- **Seven CLI agents** — Claude Code, OpenCode, Copilot CLI, Codex, Pi, Cursor, and Grok
|
|
21
|
+
behind a common adapter protocol.
|
|
22
|
+
- **Execute or stream** — get one `AgentResponse` (raises `AgentExecutionError` on a failed run),
|
|
23
|
+
or async-iterate normalized `StreamEvent`s with optional thinking/reasoning.
|
|
24
|
+
- **Composable execution policy** — preserve native execution by default, or opt into Linux PID
|
|
25
|
+
namespace isolation without changing an agent adapter.
|
|
26
|
+
- **Session resumption** — continue any conversation by passing back its `session_id`.
|
|
27
|
+
- **Normalized cost & tokens** — consistent `cost` and `output_tokens` (reasoning included)
|
|
28
|
+
regardless of how each CLI reports them.
|
|
29
|
+
- **Model discovery** — retrieve the exact account/workspace-aware model strings accepted by
|
|
30
|
+
each CLI, without inference calls, SDK dependencies, or static catalogs.
|
|
31
|
+
- **Health checks** — confirm an agent + model combination actually works before you rely on
|
|
32
|
+
it, read from the event stream rather than unreliable exit codes.
|
|
33
|
+
- **Portable tool control** — one canonical allow/deny vocabulary
|
|
34
|
+
(`bash, edit, read, web_search, web_fetch`) translated to each CLI's own tool names.
|
|
35
|
+
- **Unified MCP management** — register, remove, and list MCP servers across agents through a
|
|
36
|
+
single API.
|
|
37
|
+
- **Package management** — install/register, list, and remove harness packages through a shared
|
|
38
|
+
API, with Pi as the first supported agent.
|
|
39
|
+
- **Async & dependency-free** — pure `asyncio`, zero runtime dependencies, Python 3.12+.
|
|
40
|
+
|
|
41
|
+
## Installation
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
uv add agent-shell-py
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
or with pip:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
pip install agent-shell-py
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Agent skills
|
|
54
|
+
|
|
55
|
+
The repository includes reusable skills that teach coding agents how to use AgentShell:
|
|
56
|
+
|
|
57
|
+
- `invoking-cli-agents` — invoke, stream, resume, and restrict CLI agents.
|
|
58
|
+
- `delegating-code-review` — delegate an independent code review through AgentShell.
|
|
59
|
+
|
|
60
|
+
Install them interactively with the Vercel Skills CLI:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
npx skills add ScottRBK/agent-shell
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Or install both skills globally for every coding agent supported by AgentShell:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
npx skills add ScottRBK/agent-shell --global \
|
|
70
|
+
--skill '*' \
|
|
71
|
+
--agent claude-code opencode github-copilot codex pi cursor grok \
|
|
72
|
+
--yes
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Install only the core AgentShell skill with:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
npx skills add ScottRBK/agent-shell --skill invoking-cli-agents
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
The skills provide agent instructions. Install `agent-shell-py` and the chosen coding-agent CLIs
|
|
82
|
+
separately.
|
|
83
|
+
|
|
84
|
+
## Examples
|
|
85
|
+
|
|
86
|
+
### Execute
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
from agent_shell.shell import AgentShell
|
|
90
|
+
from agent_shell.models.agent import AgentType
|
|
91
|
+
|
|
92
|
+
shell = AgentShell(agent_type=AgentType.CLAUDE_CODE)
|
|
93
|
+
|
|
94
|
+
response = await shell.execute(
|
|
95
|
+
cwd="/path/to/project",
|
|
96
|
+
prompt="Can you tell me about this project?",
|
|
97
|
+
allowed_tools=["Read", "Glob", "Grep"],
|
|
98
|
+
model="sonnet",
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
print(response.response)
|
|
102
|
+
print(f"Cost: ${response.cost:.4f}")
|
|
103
|
+
print(f"Output tokens: {response.output_tokens}") # billed output, reasoning included
|
|
104
|
+
print(f"Session: {response.session_id}")
|
|
105
|
+
|
|
106
|
+
# Resume the conversation using the session_id
|
|
107
|
+
follow_up = await shell.execute(
|
|
108
|
+
cwd="/path/to/project",
|
|
109
|
+
prompt="Now refactor the auth module based on your findings",
|
|
110
|
+
allowed_tools=["Read", "Edit", "Bash"],
|
|
111
|
+
model="sonnet",
|
|
112
|
+
session_id=response.session_id,
|
|
113
|
+
)
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
> `output_tokens` is a cost measure: the billed output-token count, which **includes reasoning
|
|
117
|
+
> tokens** (they are billed at the output rate). It is reported consistently across all adapters.
|
|
118
|
+
|
|
119
|
+
See [more examples](docs/examples.md) for isolation and execution hosts, failure handling,
|
|
120
|
+
streaming, model discovery, health checks, tool restrictions, MCP servers, packages, and logging.
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+

|
|
2
|
+
|
|
3
|
+
<h1 align="center">Agent Shell</h1>
|
|
4
|
+
Agent Shell is a light weight abstraction for executing a cli coding agent headlessly
|
|
5
|
+
and returning the output that can be used programatically as a unified contract
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- **One unified contract** — the same `execute`, `stream`, `health_check`, and
|
|
10
|
+
`list_models` API across every agent; swap the backend without changing consuming code.
|
|
11
|
+
- **Seven CLI agents** — Claude Code, OpenCode, Copilot CLI, Codex, Pi, Cursor, and Grok
|
|
12
|
+
behind a common adapter protocol.
|
|
13
|
+
- **Execute or stream** — get one `AgentResponse` (raises `AgentExecutionError` on a failed run),
|
|
14
|
+
or async-iterate normalized `StreamEvent`s with optional thinking/reasoning.
|
|
15
|
+
- **Composable execution policy** — preserve native execution by default, or opt into Linux PID
|
|
16
|
+
namespace isolation without changing an agent adapter.
|
|
17
|
+
- **Session resumption** — continue any conversation by passing back its `session_id`.
|
|
18
|
+
- **Normalized cost & tokens** — consistent `cost` and `output_tokens` (reasoning included)
|
|
19
|
+
regardless of how each CLI reports them.
|
|
20
|
+
- **Model discovery** — retrieve the exact account/workspace-aware model strings accepted by
|
|
21
|
+
each CLI, without inference calls, SDK dependencies, or static catalogs.
|
|
22
|
+
- **Health checks** — confirm an agent + model combination actually works before you rely on
|
|
23
|
+
it, read from the event stream rather than unreliable exit codes.
|
|
24
|
+
- **Portable tool control** — one canonical allow/deny vocabulary
|
|
25
|
+
(`bash, edit, read, web_search, web_fetch`) translated to each CLI's own tool names.
|
|
26
|
+
- **Unified MCP management** — register, remove, and list MCP servers across agents through a
|
|
27
|
+
single API.
|
|
28
|
+
- **Package management** — install/register, list, and remove harness packages through a shared
|
|
29
|
+
API, with Pi as the first supported agent.
|
|
30
|
+
- **Async & dependency-free** — pure `asyncio`, zero runtime dependencies, Python 3.12+.
|
|
31
|
+
|
|
32
|
+
## Installation
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
uv add agent-shell-py
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
or with pip:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
pip install agent-shell-py
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Agent skills
|
|
45
|
+
|
|
46
|
+
The repository includes reusable skills that teach coding agents how to use AgentShell:
|
|
47
|
+
|
|
48
|
+
- `invoking-cli-agents` — invoke, stream, resume, and restrict CLI agents.
|
|
49
|
+
- `delegating-code-review` — delegate an independent code review through AgentShell.
|
|
50
|
+
|
|
51
|
+
Install them interactively with the Vercel Skills CLI:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
npx skills add ScottRBK/agent-shell
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Or install both skills globally for every coding agent supported by AgentShell:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
npx skills add ScottRBK/agent-shell --global \
|
|
61
|
+
--skill '*' \
|
|
62
|
+
--agent claude-code opencode github-copilot codex pi cursor grok \
|
|
63
|
+
--yes
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Install only the core AgentShell skill with:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
npx skills add ScottRBK/agent-shell --skill invoking-cli-agents
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
The skills provide agent instructions. Install `agent-shell-py` and the chosen coding-agent CLIs
|
|
73
|
+
separately.
|
|
74
|
+
|
|
75
|
+
## Examples
|
|
76
|
+
|
|
77
|
+
### Execute
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
from agent_shell.shell import AgentShell
|
|
81
|
+
from agent_shell.models.agent import AgentType
|
|
82
|
+
|
|
83
|
+
shell = AgentShell(agent_type=AgentType.CLAUDE_CODE)
|
|
84
|
+
|
|
85
|
+
response = await shell.execute(
|
|
86
|
+
cwd="/path/to/project",
|
|
87
|
+
prompt="Can you tell me about this project?",
|
|
88
|
+
allowed_tools=["Read", "Glob", "Grep"],
|
|
89
|
+
model="sonnet",
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
print(response.response)
|
|
93
|
+
print(f"Cost: ${response.cost:.4f}")
|
|
94
|
+
print(f"Output tokens: {response.output_tokens}") # billed output, reasoning included
|
|
95
|
+
print(f"Session: {response.session_id}")
|
|
96
|
+
|
|
97
|
+
# Resume the conversation using the session_id
|
|
98
|
+
follow_up = await shell.execute(
|
|
99
|
+
cwd="/path/to/project",
|
|
100
|
+
prompt="Now refactor the auth module based on your findings",
|
|
101
|
+
allowed_tools=["Read", "Edit", "Bash"],
|
|
102
|
+
model="sonnet",
|
|
103
|
+
session_id=response.session_id,
|
|
104
|
+
)
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
> `output_tokens` is a cost measure: the billed output-token count, which **includes reasoning
|
|
108
|
+
> tokens** (they are billed at the output rate). It is reported consistently across all adapters.
|
|
109
|
+
|
|
110
|
+
See [more examples](docs/examples.md) for isolation and execution hosts, failure handling,
|
|
111
|
+
streaming, model discovery, health checks, tool restrictions, MCP servers, packages, and logging.
|