cli-agent-runner 0.2.1__tar.gz → 0.2.2__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.
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/.github/workflows/ci.yml +4 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/.gitignore +5 -0
- cli_agent_runner-0.2.2/.vulture-whitelist.py +244 -0
- cli_agent_runner-0.2.2/BACKLOG.md +90 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/CHANGELOG.md +23 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/CONTRIBUTING.md +26 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/PKG-INFO +7 -7
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/README.md +6 -5
- cli_agent_runner-0.2.2/README.zh.md +37 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/SECURITY.md +17 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/agent_runner/_docgen.py +45 -19
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/agent_runner/_throttle.py +13 -4
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/agent_runner/_version.py +2 -2
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/agent_runner/agent_runtime.py +0 -19
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/agent_runner/api.py +11 -17
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/agent_runner/builtin_plugins/default_dirty_handler.py +20 -12
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/agent_runner/cli/events_cmd.py +4 -2
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/agent_runner/cli/install_cmd.py +1 -3
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/agent_runner/cli/serve_cmd.py +4 -25
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/agent_runner/cli/service_cmd.py +1 -7
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/agent_runner/cli/upgrade_cmd.py +1 -1
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/agent_runner/config.py +62 -28
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/agent_runner/context_store.py +0 -23
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/agent_runner/defenses.py +21 -11
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/agent_runner/events.py +0 -1
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/agent_runner/hooks.py +10 -9
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/agent_runner/http_progress.py +1 -1
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/agent_runner/lifecycle.py +1 -1
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/agent_runner/monitor.py +28 -18
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/agent_runner/prompt_loader.py +0 -7
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/agent_runner/round_view.py +3 -2
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/agent_runner/runner.py +12 -8
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/agent_runner/vcs_state.py +162 -108
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/build.sh +13 -1
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/docs/README.md +12 -5
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/docs/architecture.md +16 -14
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/docs/commands.md +9 -9
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/docs/configuration.md +43 -20
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/docs/events.md +1 -1
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/docs/migrations/0.1.23.md +7 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/docs/migrations/0.1.26.md +6 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/docs/migrations/0.1.27.md +7 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/docs/migrations/0.1.32.md +11 -0
- cli_agent_runner-0.2.2/docs/migrations/0.2.2.md +242 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/docs/plugins.md +111 -142
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/docs/quickstart.md +3 -4
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/docs/recipes/aider.md +5 -3
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/docs/runbook.md +3 -7
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/docs/thesis.md +1 -1
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/pyproject.toml +22 -8
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/contract/test_public_api_surface.py +25 -12
- cli_agent_runner-0.2.2/tests/generate_vulture_whitelist.py +82 -0
- cli_agent_runner-0.2.2/tests/integration/test_fresh_eyes_signal.py +135 -0
- cli_agent_runner-0.2.2/tests/integration/test_plugin_owned_paths.py +279 -0
- cli_agent_runner-0.2.2/tests/invariants/_event_scan.py +94 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/invariants/test_architecture.py +1 -1
- cli_agent_runner-0.2.2/tests/invariants/test_auto_stop_policy_ssot.py +39 -0
- cli_agent_runner-0.2.2/tests/invariants/test_catalogs.py +82 -0
- cli_agent_runner-0.2.2/tests/invariants/test_config_error_consistency.py +73 -0
- cli_agent_runner-0.2.2/tests/invariants/test_config_value_set_ssot.py +64 -0
- cli_agent_runner-0.2.2/tests/invariants/test_doc_builtin_plugins.py +42 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/invariants/test_doc_claims_match_ssot.py +34 -5
- cli_agent_runner-0.2.2/tests/invariants/test_doc_cli_claims.py +122 -0
- cli_agent_runner-0.2.2/tests/invariants/test_doc_operator_surface.py +83 -0
- cli_agent_runner-0.2.2/tests/invariants/test_doc_transient_error_claims.py +58 -0
- cli_agent_runner-0.2.2/tests/invariants/test_docs_index_complete.py +34 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/invariants/test_event_kind_registry.py +16 -24
- cli_agent_runner-0.2.2/tests/invariants/test_event_kinds_ssot.py +151 -0
- cli_agent_runner-0.2.2/tests/invariants/test_hook_contract_docs.py +77 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/invariants/test_module_boundaries.py +39 -15
- cli_agent_runner-0.2.2/tests/invariants/test_plugins_config_stable.py +38 -0
- cli_agent_runner-0.2.2/tests/invariants/test_readme_zh_is_pointer.py +54 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/invariants/test_round_result_stable.py +1 -0
- cli_agent_runner-0.2.2/tests/invariants/test_set_diff_for_auto_tool_classification.py +97 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/invariants/test_stash_uses_sha_not_index.py +3 -12
- cli_agent_runner-0.2.2/tests/invariants/test_vulture_whitelist_generated.py +19 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_agent_runtime.py +1 -13
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_api_service.py +0 -15
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_cli_service_peek_monitor.py +0 -10
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_config.py +102 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_context_store.py +0 -36
- cli_agent_runner-0.2.2/tests/unit/test_default_dirty_handler.py +177 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_defenses.py +59 -3
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_docgen.py +66 -1
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_events.py +0 -1
- cli_agent_runner-0.2.2/tests/unit/test_events_cmd_tail.py +73 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_prompt_loader.py +0 -12
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_runner.py +61 -4
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_serve_cmd_bounded.py +2 -3
- cli_agent_runner-0.2.2/tests/unit/test_throttle_plugin_classification.py +42 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_vcs_state.py +29 -38
- cli_agent_runner-0.2.1/.vulture-whitelist.py +0 -6
- cli_agent_runner-0.2.1/README.zh.md +0 -157
- cli_agent_runner-0.2.1/agent_runner/detector_helpers.py +0 -115
- cli_agent_runner-0.2.1/deploy/example-agent-runner.toml +0 -24
- cli_agent_runner-0.2.1/deploy/launchd.plist.tmpl +0 -39
- cli_agent_runner-0.2.1/deploy/run-loop.sh +0 -27
- cli_agent_runner-0.2.1/deploy/systemd.service.tmpl +0 -15
- cli_agent_runner-0.2.1/docs/marketing/README.md +0 -34
- cli_agent_runner-0.2.1/docs/marketing/promo-cn.html +0 -287
- cli_agent_runner-0.2.1/tests/integration/test_fresh_eyes_signal.py +0 -69
- cli_agent_runner-0.2.1/tests/integration/test_plugin_owned_paths.py +0 -88
- cli_agent_runner-0.2.1/tests/invariants/test_catalogs.py +0 -228
- cli_agent_runner-0.2.1/tests/invariants/test_event_kinds_ssot.py +0 -41
- cli_agent_runner-0.2.1/tests/unit/test_default_dirty_handler.py +0 -77
- cli_agent_runner-0.2.1/tests/unit/test_detector_helpers.py +0 -141
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/.codecov.yml +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/.github/workflows/release.yml +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/CODE_OF_CONDUCT.md +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/LICENSE +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/agent_runner/__init__.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/agent_runner/_emit.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/agent_runner/_redact.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/agent_runner/_registry.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/agent_runner/_substrate.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/agent_runner/api_types.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/agent_runner/builtin_plugins/__init__.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/agent_runner/builtin_plugins/_constants.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/agent_runner/builtin_plugins/claude_rate_limit.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/agent_runner/builtin_plugins/codewhale.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/agent_runner/builtin_plugins/gemini.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/agent_runner/cli/__init__.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/agent_runner/cli/__main__.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/agent_runner/cli/common.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/agent_runner/cli/init_cmd.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/agent_runner/cli/monitor_cmd.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/agent_runner/cli/peek_cmd.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/agent_runner/cli/round_cmd.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/agent_runner/metrics.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/agent_runner/presets/__init__.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/agent_runner/presets/aider.toml +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/agent_runner/presets/claude.toml +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/agent_runner/presets/codewhale.toml +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/agent_runner/presets/gemini.toml +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/agent_runner/round_log.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/agent_runner/scaffold.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/agent_runner/service_unit.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/agent_runner/startup_check.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/docs/long-running-agents.md +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/docs/migrations/0.1.16.md +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/docs/migrations/0.1.17.md +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/docs/migrations/0.1.19.md +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/docs/migrations/0.1.20.md +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/docs/migrations/0.1.21.md +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/docs/migrations/0.1.22.md +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/docs/migrations/0.1.24.md +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/docs/migrations/0.1.25.md +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/docs/migrations/0.1.28.md +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/docs/migrations/0.1.29.md +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/docs/migrations/0.1.30.md +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/docs/migrations/0.1.31.md +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/docs/migrations/0.1.33.md +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/docs/migrations/0.1.34.md +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/docs/migrations/0.1.35.md +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/docs/migrations/0.1.36.md +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/docs/migrations/0.1.37.md +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/docs/migrations/0.1.38.md +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/docs/migrations/0.1.39.md +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/docs/migrations/0.1.40.md +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/docs/migrations/0.1.42.md +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/docs/migrations/0.2.0.md +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/docs/migrations/0.2.1.md +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/docs/recipes/codewhale.md +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/__init__.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/_test_helpers.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/conftest.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/contract/__init__.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/e2e/__init__.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/e2e/conftest.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/e2e/test_e2e_graceful_stop.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/e2e/test_e2e_install_systemd.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/e2e/test_e2e_monitor_remote.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/e2e/test_e2e_round_lifecycle.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/fixtures/cli-real-output/claude-2.1.143-assistant-tool-use.jsonl +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/fixtures/cli-real-output/claude-2.1.143-result-event.jsonl +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/fixtures/cli-real-output/gemini-0.42.0-result-event.jsonl +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/integration/__init__.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/integration/test_bounded_run.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/integration/test_context_enricher_namespacing.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/integration/test_dirty_handler_seam.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/integration/test_grace_kill_emission.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/integration/test_install_dry_run.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/integration/test_monitor_seeded.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/integration/test_plugin_detector_loaded.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/integration/test_plugin_real_flow.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/integration/test_prompt_delivery_stdin.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/integration/test_run_one_round_with_fake_agent.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/integration/test_scaffold_presets.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/integration/test_serve_loop.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/integration/test_substrate_fingerprint.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/integration/test_transient_error_backoff.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/invariants/__init__.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/invariants/test_atomic_write_enforced.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/invariants/test_classification_ssot.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/invariants/test_docs_generated.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/invariants/test_entry_points_resolve.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/invariants/test_events_doc_contract.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/invariants/test_layer_2_loop_size.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/invariants/test_module_sizes.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/invariants/test_no_ai_signatures.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/invariants/test_no_pytest_skip_on_parse_fail.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/invariants/test_peek_schema_version.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/invariants/test_repo_constants_patched_in_tests.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/invariants/test_upstream_schema_canary.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/literate/__init__.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/literate/parser.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/literate/test_parser.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/literate/test_quickstart.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/__init__.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_agent_runtime_grace.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_agent_runtime_progress.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_agent_runtime_signal_name.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_api_assemble_prompt.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_api_events_stream.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_api_install.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_api_observation.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_api_read_round_num.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_api_resolve_phase.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_api_types.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_auto_stop_gating.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_catalogs.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_claude_error_detector.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_cli.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_cli_common.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_cli_init_install.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_cli_monitor_http.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_cli_upgrade.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_codewhale_plugin.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_config_fresh_eyes.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_config_max_rounds.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_config_prompt_delivery.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_config_stop_file.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_config_substrate_fingerprint_paths.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_config_transient_error_action.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_detector_protocol.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_dirty_handlers.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_events_cmd.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_exit_cause.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_fresh_eyes_trigger.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_gemini_plugin.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_hook_failure_isolation.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_hooks.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_http_progress.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_init_entry_points.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_lifecycle.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_metrics.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_monitor_assembly.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_monitor_detect_anomaly_repetitive.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_monitor_detect_rate_limit.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_monitor_detect_supervisor_stale.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_monitor_detectors.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_monitor_remote.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_network_blip_signal_guard.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_peek_argparse.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_peek_select.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_presets.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_redact.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_round_log_helpers.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_round_view.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_runner_throttle.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_scaffold.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_serve_config_broken.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_serve_crash_loop.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_serve_round_log.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_serve_sentinel.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_serve_startup_hooks.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_service_unit.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_startup_check.py +0 -0
- {cli_agent_runner-0.2.1 → cli_agent_runner-0.2.2}/tests/unit/test_substrate.py +0 -0
|
@@ -87,6 +87,10 @@ jobs:
|
|
|
87
87
|
run: |
|
|
88
88
|
ruff check .
|
|
89
89
|
ruff format --check .
|
|
90
|
+
- name: vulture (dead-code scan)
|
|
91
|
+
# Config in [tool.vulture]; exits nonzero on any finding. No pipe — a
|
|
92
|
+
# `| tail` would swallow the exit code and let dead code through.
|
|
93
|
+
run: vulture
|
|
90
94
|
- name: tests with coverage
|
|
91
95
|
run: pytest -q --ignore=tests/e2e --ignore=tests/literate --cov --cov-report=xml --cov-report=term
|
|
92
96
|
- name: docs CI gate
|
|
@@ -30,3 +30,8 @@ htmlcov/
|
|
|
30
30
|
|
|
31
31
|
# Personal /team-onboarding artifact — not project content
|
|
32
32
|
ONBOARDING.md
|
|
33
|
+
|
|
34
|
+
# Local tooling scratch directories — never project content, never published.
|
|
35
|
+
# Defense in depth only: releases build from a fresh CI checkout, and every
|
|
36
|
+
# sdist 0.1.1–0.2.1 was checked clean. This only guards a local `python -m build`.
|
|
37
|
+
.superpowers/
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
# GENERATED by tests/generate_vulture_whitelist.py — DO NOT EDIT BY HAND.
|
|
2
|
+
# Regenerate: ./build.sh vulture-whitelist
|
|
3
|
+
#
|
|
4
|
+
# vulture (min_confidence=60) reports @dataclass fields as "unused variable":
|
|
5
|
+
# they cross a JSON / CLI / plugin boundary static analysis cannot see. Each
|
|
6
|
+
# bare name below marks one field "used". SSOT = the @dataclass definitions in
|
|
7
|
+
# agent_runner/; a new field is covered by regenerating, never by editing here.
|
|
8
|
+
|
|
9
|
+
# agent_runner.agent_runtime.RunResult
|
|
10
|
+
exit_code
|
|
11
|
+
duration_s
|
|
12
|
+
timed_out
|
|
13
|
+
pid
|
|
14
|
+
killed_for_grace
|
|
15
|
+
grace_kill_children
|
|
16
|
+
|
|
17
|
+
# agent_runner.api_types.Alert
|
|
18
|
+
severity
|
|
19
|
+
detector
|
|
20
|
+
message
|
|
21
|
+
context
|
|
22
|
+
ts
|
|
23
|
+
auto_action
|
|
24
|
+
|
|
25
|
+
# agent_runner.api_types.DirtyOutcome
|
|
26
|
+
kind
|
|
27
|
+
ref
|
|
28
|
+
|
|
29
|
+
# agent_runner.api_types.InitResult
|
|
30
|
+
work_dir
|
|
31
|
+
files_created
|
|
32
|
+
committed
|
|
33
|
+
preset
|
|
34
|
+
|
|
35
|
+
# agent_runner.api_types.InstallResult
|
|
36
|
+
unit_path
|
|
37
|
+
monitor_unit_path
|
|
38
|
+
enabled
|
|
39
|
+
started
|
|
40
|
+
|
|
41
|
+
# agent_runner.api_types.ProjectState
|
|
42
|
+
project
|
|
43
|
+
status
|
|
44
|
+
defenses
|
|
45
|
+
current_round
|
|
46
|
+
recent_rounds
|
|
47
|
+
orphan
|
|
48
|
+
system
|
|
49
|
+
service
|
|
50
|
+
recent_events
|
|
51
|
+
recent_hook_failures
|
|
52
|
+
recent_blips
|
|
53
|
+
|
|
54
|
+
# agent_runner.api_types.RateLimitState
|
|
55
|
+
throttled_until_epoch
|
|
56
|
+
limit_type
|
|
57
|
+
agent
|
|
58
|
+
since_round
|
|
59
|
+
|
|
60
|
+
# agent_runner.api_types.RoundResult
|
|
61
|
+
round_num
|
|
62
|
+
phase
|
|
63
|
+
started_at
|
|
64
|
+
ended_at
|
|
65
|
+
exit_code
|
|
66
|
+
duration_s
|
|
67
|
+
timed_out
|
|
68
|
+
log_path
|
|
69
|
+
dirty_files
|
|
70
|
+
stashed
|
|
71
|
+
dirty_outcome
|
|
72
|
+
killed_for_grace
|
|
73
|
+
|
|
74
|
+
# agent_runner.api_types.RoundView
|
|
75
|
+
round_num
|
|
76
|
+
phase
|
|
77
|
+
started_at
|
|
78
|
+
duration_so_far_s
|
|
79
|
+
pid
|
|
80
|
+
exit_code
|
|
81
|
+
timed_out
|
|
82
|
+
log_path
|
|
83
|
+
log_tail
|
|
84
|
+
recent_events
|
|
85
|
+
|
|
86
|
+
# agent_runner.api_types.ServiceStatus
|
|
87
|
+
mode
|
|
88
|
+
active
|
|
89
|
+
pid
|
|
90
|
+
uptime_s
|
|
91
|
+
unit_file
|
|
92
|
+
rate_limit
|
|
93
|
+
|
|
94
|
+
# agent_runner.api_types.SystemMetrics
|
|
95
|
+
mem_total_mb
|
|
96
|
+
mem_available_mb
|
|
97
|
+
disk_used_pct
|
|
98
|
+
disk_free_gb
|
|
99
|
+
load_1m
|
|
100
|
+
cpu_pct
|
|
101
|
+
agent_process_count
|
|
102
|
+
|
|
103
|
+
# agent_runner.api_types.TransientErrorState
|
|
104
|
+
reset_at_epoch
|
|
105
|
+
classification
|
|
106
|
+
agent
|
|
107
|
+
since_round
|
|
108
|
+
|
|
109
|
+
# agent_runner.config.AgentConfig
|
|
110
|
+
command
|
|
111
|
+
prompt_arg_template
|
|
112
|
+
name
|
|
113
|
+
env
|
|
114
|
+
prompt_delivery
|
|
115
|
+
|
|
116
|
+
# agent_runner.config.Config
|
|
117
|
+
agent
|
|
118
|
+
runtime
|
|
119
|
+
prompt
|
|
120
|
+
vcs
|
|
121
|
+
monitor
|
|
122
|
+
phases
|
|
123
|
+
plugins
|
|
124
|
+
|
|
125
|
+
# agent_runner.config.MonitorConfig
|
|
126
|
+
auth_fail_patterns
|
|
127
|
+
auth_fail_hint
|
|
128
|
+
auto_stop_on
|
|
129
|
+
remote_failure_tolerance_s
|
|
130
|
+
anomaly_repetitive_window
|
|
131
|
+
anomaly_repetitive_threshold
|
|
132
|
+
host_health
|
|
133
|
+
round_progress_interval_s
|
|
134
|
+
supervisor_stale_threshold_s
|
|
135
|
+
|
|
136
|
+
# agent_runner.config.MonitorHostHealthConfig
|
|
137
|
+
mem_avail_min_mb
|
|
138
|
+
disk_warning_pct
|
|
139
|
+
disk_critical_pct
|
|
140
|
+
|
|
141
|
+
# agent_runner.config.PhaseOverride
|
|
142
|
+
round_timeout_s
|
|
143
|
+
disable_pre_round_hooks
|
|
144
|
+
prompt_files
|
|
145
|
+
|
|
146
|
+
# agent_runner.config.PhasesConfig
|
|
147
|
+
list
|
|
148
|
+
overrides
|
|
149
|
+
|
|
150
|
+
# agent_runner.config.PluginsConfig
|
|
151
|
+
disable
|
|
152
|
+
raw
|
|
153
|
+
|
|
154
|
+
# agent_runner.config.PromptConfig
|
|
155
|
+
file
|
|
156
|
+
files
|
|
157
|
+
inject_context
|
|
158
|
+
context_injection_mode
|
|
159
|
+
concat_separator
|
|
160
|
+
strip_yaml_frontmatter
|
|
161
|
+
|
|
162
|
+
# agent_runner.config.RuntimeConfig
|
|
163
|
+
work_dir
|
|
164
|
+
log_dir
|
|
165
|
+
round_timeout_s
|
|
166
|
+
restart_delay_s
|
|
167
|
+
disable_pre_round_hooks
|
|
168
|
+
round_log_retention
|
|
169
|
+
narrative_file
|
|
170
|
+
transient_error_action
|
|
171
|
+
max_rounds
|
|
172
|
+
stop_file
|
|
173
|
+
substrate_fingerprint_paths
|
|
174
|
+
fresh_eyes_every_n
|
|
175
|
+
dry_run
|
|
176
|
+
max_grace_after_result_s
|
|
177
|
+
grace_kill_ignore_patterns
|
|
178
|
+
|
|
179
|
+
# agent_runner.config.VcsConfig
|
|
180
|
+
stash_idempotency_s
|
|
181
|
+
dirty_action
|
|
182
|
+
|
|
183
|
+
# agent_runner.context_store.OrphanState
|
|
184
|
+
round_num
|
|
185
|
+
files
|
|
186
|
+
stashed_ref
|
|
187
|
+
stash_message
|
|
188
|
+
timestamp
|
|
189
|
+
phase
|
|
190
|
+
|
|
191
|
+
# agent_runner.context_store.Status
|
|
192
|
+
round_num
|
|
193
|
+
running
|
|
194
|
+
last_completed_at
|
|
195
|
+
last_exit_code
|
|
196
|
+
last_duration_s
|
|
197
|
+
current_phase
|
|
198
|
+
phase_index
|
|
199
|
+
|
|
200
|
+
# agent_runner.defenses.Defense
|
|
201
|
+
name
|
|
202
|
+
value
|
|
203
|
+
codifies
|
|
204
|
+
guarded_by
|
|
205
|
+
current_state
|
|
206
|
+
|
|
207
|
+
# agent_runner.hooks.HookContext
|
|
208
|
+
work_dir
|
|
209
|
+
log_dir
|
|
210
|
+
project
|
|
211
|
+
round_num
|
|
212
|
+
phase
|
|
213
|
+
agent_name
|
|
214
|
+
agent_binary
|
|
215
|
+
agent_log_path
|
|
216
|
+
dry_run
|
|
217
|
+
anomaly_repetitive_window
|
|
218
|
+
anomaly_repetitive_threshold
|
|
219
|
+
vcs
|
|
220
|
+
|
|
221
|
+
# agent_runner.hooks.VcsHookView
|
|
222
|
+
dirty_action
|
|
223
|
+
stash_idempotency_s
|
|
224
|
+
|
|
225
|
+
# agent_runner.lifecycle.PIDFile
|
|
226
|
+
path
|
|
227
|
+
|
|
228
|
+
# agent_runner.monitor.LocalSource
|
|
229
|
+
log_dir
|
|
230
|
+
|
|
231
|
+
# agent_runner.monitor.RemoteSource
|
|
232
|
+
host
|
|
233
|
+
project
|
|
234
|
+
|
|
235
|
+
# agent_runner.startup_check.CheckResult
|
|
236
|
+
name
|
|
237
|
+
ok
|
|
238
|
+
reason
|
|
239
|
+
how_to_fix
|
|
240
|
+
|
|
241
|
+
# agent_runner.vcs_state.StashRef
|
|
242
|
+
sha
|
|
243
|
+
message
|
|
244
|
+
reused
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# Backlog
|
|
2
|
+
|
|
3
|
+
Known follow-ups that are real design or behavior decisions, not defects. Each
|
|
4
|
+
entry carries enough context to act on without re-deriving it.
|
|
5
|
+
|
|
6
|
+
Items marked **NEEDS_DESIGN** change user-visible behavior and are held for an
|
|
7
|
+
explicit decision — they are not shipped silently in a maintenance release.
|
|
8
|
+
|
|
9
|
+
## `try_auto_commit` sweeps plugin-owned paths
|
|
10
|
+
|
|
11
|
+
`vcs_state.try_auto_commit` runs `git add -A` with an exclude pathspec built only
|
|
12
|
+
from the log directory (`_log_dir_exclude_pathspec`), so under
|
|
13
|
+
`vcs.dirty_action = "auto_commit"` paths registered via
|
|
14
|
+
`register_plugin_owned_paths` are committed along with the agent's work.
|
|
15
|
+
|
|
16
|
+
0.2.2 made the registry authoritative at the git boundary for `stash_orphan`
|
|
17
|
+
only. That fix discharged the specific promise in `docs/plugins.md` that owned
|
|
18
|
+
paths are not silently swept into an orphan stash. `auto_commit` is a different
|
|
19
|
+
promise with a different harm (a commit, not a hidden stash) and no equivalent
|
|
20
|
+
published guarantee, so it needs its own call: should `auto_commit` honor the
|
|
21
|
+
registry, or is committing a plugin deliverable alongside agent work the
|
|
22
|
+
intended behavior?
|
|
23
|
+
|
|
24
|
+
## `_tail_events` / `_tail_events_jsonl` duplication
|
|
25
|
+
|
|
26
|
+
`cli/events_cmd.py:_tail_events` and `api.py:_tail_events_jsonl` both tail the
|
|
27
|
+
event stream, deliberately at different scopes: `api` globs every
|
|
28
|
+
`events-*.jsonl`; `events_cmd` is current-month-scoped and resets its offset to
|
|
29
|
+
0 on truncation. They are not accidental copies. Collapsing them means first
|
|
30
|
+
deciding which scope is correct for each caller.
|
|
31
|
+
|
|
32
|
+
Related, from the same area: the kind-read loops in `_throttle.py` and
|
|
33
|
+
`monitor.py` (`kind = ev.get("event")` over `reversed(events)`) are
|
|
34
|
+
character-identical after the 0.2.2 constant normalization. Extracting a shared
|
|
35
|
+
helper is a structural change, not a literal swap.
|
|
36
|
+
|
|
37
|
+
## Detector fixtures pin raw event-kind literals
|
|
38
|
+
|
|
39
|
+
Detector test fixtures construct events from hardcoded strings (`{"event":
|
|
40
|
+
"round_start"}`) rather than emitting through `events.emit()`. Fixture and
|
|
41
|
+
reader therefore agree with each other while both can diverge from what the
|
|
42
|
+
supervisor actually writes.
|
|
43
|
+
|
|
44
|
+
Proven by mutation: point the emitter at a different kind value and the 28
|
|
45
|
+
`test_claude_error_detector.py` tests stay green while every detector is blind.
|
|
46
|
+
The 0.2.2 constant normalization does not close this — it moves the pin from the
|
|
47
|
+
reader to the fixture. Closing it means fixtures emitting through
|
|
48
|
+
`events.emit()`, or an end-to-end test asserting a real round produces events
|
|
49
|
+
the detectors actually match.
|
|
50
|
+
|
|
51
|
+
Bounded by `docs/events.md`, which forbids renaming a kind value outright (the
|
|
52
|
+
kind name is the version discriminator; a breaking change ships as
|
|
53
|
+
`round_start_v2`). Reaching this failure requires a contract violation — but the
|
|
54
|
+
suite would not report it.
|
|
55
|
+
|
|
56
|
+
## `remote_failure_tolerance_s` does not cover `subprocess.TimeoutExpired` — NEEDS_DESIGN
|
|
57
|
+
|
|
58
|
+
The tolerance window covers ssh exit code 255 only. `monitor.run_remote_command`
|
|
59
|
+
raises `MonitorRemoteError` on rc=255, and `api.monitor_loop`'s retry loop
|
|
60
|
+
catches exactly that. A hung (not failed) ssh connection instead trips the
|
|
61
|
+
`subprocess.run(timeout=...)` guard and raises `subprocess.TimeoutExpired`,
|
|
62
|
+
which bypasses the window and kills the monitor.
|
|
63
|
+
|
|
64
|
+
The rc=255-only scope is intentional and pinned by the monitor-signals design,
|
|
65
|
+
and the documentation matches the code exactly — there is no drift here. Widening
|
|
66
|
+
it changes a documented recovery path, so it is a design decision, not debt.
|
|
67
|
+
|
|
68
|
+
## `anomaly_repetitive_*` default — NEEDS_DESIGN
|
|
69
|
+
|
|
70
|
+
`monitor.anomaly_repetitive_window` and `anomaly_repetitive_threshold` both
|
|
71
|
+
default to `0`, which disables the detector. This is a deliberate opt-in kill
|
|
72
|
+
switch, documented since the field's first commit, and the detector fires
|
|
73
|
+
correctly the moment an operator opts in.
|
|
74
|
+
|
|
75
|
+
The open question is whether opt-in is the right default, or whether this belongs
|
|
76
|
+
in a preset. Flipping the default would arm a new alert for every existing
|
|
77
|
+
deployment.
|
|
78
|
+
|
|
79
|
+
## `stash_orphan` loses the ref when the post-push listing fails
|
|
80
|
+
|
|
81
|
+
`vcs_state.stash_orphan` returns `None` in three cases; two are true no-ops. The
|
|
82
|
+
third — `git stash push` succeeded but the follow-up `git stash list` failed —
|
|
83
|
+
means the WIP *is* stashed yet callers read "nothing stashed" and report the
|
|
84
|
+
tree as ignored. It is already documented in-code as a KNOWN GAP and judged
|
|
85
|
+
effectively unreachable (a listing that fails microseconds after a push that
|
|
86
|
+
just succeeded in the same repo).
|
|
87
|
+
|
|
88
|
+
Deferred because closing it is a naming decision, not cleanup: no event kind
|
|
89
|
+
carries the meaning "stashed but ref lost" (`orphan_stash_failed` would be wrong
|
|
90
|
+
— the stash exists). Left as-is until that kind is designed.
|
|
@@ -5,6 +5,29 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.2.2] - 2026-07-18
|
|
9
|
+
|
|
10
|
+
### Removed
|
|
11
|
+
- `agent_runner.detector_helpers` and its three helpers (`cumulative_window_check`, `dual_source_silence`, `phase_filter`) — **breaking** for any out-of-tree detector that imported them; vendor the ~115 LOC.
|
|
12
|
+
- `agent-runner cancel` and `api.cancel()` — **breaking**; they never delivered the documented SIGINT-to-round semantics (nothing ever wrote the `round.pid` they read), so `cancel` was only a slower alias for `stop`. Use `stop`; `serve` no longer traps `SIGUSR1`.
|
|
13
|
+
- `events.SIGTERM_RECEIVED` (the `sigterm_received` kind) — declared but never emitted, so nothing could ever observe it.
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
- Paths registered with `register_plugin_owned_paths` are no longer swept into the orphan stash: all three documented pattern forms (trailing-slash prefix, glob, `**/*`) are now honored at the git boundary, not only the report boundary, so a deliverable is no longer silently stashed — and possibly lost — when the agent also touches a non-owned file. `**/*` patterns now also match files directly in the registered directory, changing which paths `detect_dirty_files` filters. **Check `git stash list` if you register owned paths.**
|
|
17
|
+
- Config-load rejections now raise `ConfigError` (a subclass of `ValueError`) consistently; fully backward compatible — any `except ValueError` still catches them.
|
|
18
|
+
- `[monitor.host_health]` percent thresholds, `[prompt] inject_context`, and `[monitor] auth_fail_patterns` are validated at load, so configs that were previously accepted-but-silently-broken now fail loudly at startup.
|
|
19
|
+
|
|
20
|
+
### Fixed
|
|
21
|
+
- `agent-runner events --tail` no longer re-emits events appended while a poll's read loop was in flight.
|
|
22
|
+
- The orphan-stash defense now signals push failure (`orphan_stash_failed`) and idempotent reuse (`orphan_idempotent_skip`) — both kinds were declared but never emitted — instead of degrading silently; `stash_orphan` raises `StashError` (re-exported from `agent_runner.api`) on push failure.
|
|
23
|
+
- Plugin-supplied transient-error classifications no longer crash the supervisor with `KeyError`.
|
|
24
|
+
- Defense-catalog honesty (every advertised defense now names a real guarding test) and ~31 false claims across README, docs, and docstrings.
|
|
25
|
+
|
|
26
|
+
### Added
|
|
27
|
+
- Housekeeping: the build gate runs `vulture` (dead-code scan, whitelist auto-generated from `@dataclass` fields); `AGENT_RUNNER_FRESH_EYES` is now a documented, tested round-subprocess env-var contract; `SECURITY.md` gains a threat model (agent-runner is a supervisor, not a sandbox).
|
|
28
|
+
|
|
29
|
+
See `docs/migrations/0.2.2.md`.
|
|
30
|
+
|
|
8
31
|
## [0.2.1] - 2026-07-16
|
|
9
32
|
|
|
10
33
|
### Added
|
|
@@ -29,6 +29,26 @@ what GitHub Actions runs on every push and PR.
|
|
|
29
29
|
reject auto-generated trailers and robot signatures — keep messages
|
|
30
30
|
human-authored.
|
|
31
31
|
|
|
32
|
+
## Migration docs
|
|
33
|
+
|
|
34
|
+
A `docs/migrations/<version>.md` guide is written **only** when a release:
|
|
35
|
+
|
|
36
|
+
- makes a **breaking change** — a removed or renamed public symbol, or a
|
|
37
|
+
config that used to load and now does not; or
|
|
38
|
+
- **requires operator action** — a TOML edit, a manual recovery step, or a
|
|
39
|
+
data/format migration.
|
|
40
|
+
|
|
41
|
+
Otherwise `CHANGELOG.md` carries the whole story; a guide that only restates
|
|
42
|
+
the changelog is upkeep with no reader. When a guide does exist, keep the
|
|
43
|
+
CHANGELOG entry terse and link it (`See docs/migrations/<version>.md.`).
|
|
44
|
+
|
|
45
|
+
0.2.2 is the first release written under this policy: it removes two public
|
|
46
|
+
symbols — the `detector_helpers` module and the `cancel` verb — so it ships a
|
|
47
|
+
guide. Existing `docs/migrations/` files are history: append-only, never
|
|
48
|
+
rewritten or deleted, including ones this policy would not have produced.
|
|
49
|
+
Correct a shipped guide with a dated `**Correction (<version>)**:` note, not
|
|
50
|
+
an edit in place.
|
|
51
|
+
|
|
32
52
|
## Architecture / docs
|
|
33
53
|
|
|
34
54
|
- [`docs/architecture.md`](docs/architecture.md) — 3-layer model, defenses-as-data.
|
|
@@ -40,6 +60,12 @@ table in `docs/*.md` are auto-generated by `./build.sh docs`. The CI gate
|
|
|
40
60
|
fails if those regions drift from the code's source of truth. Don't edit
|
|
41
61
|
them manually — edit the generator or the data source.
|
|
42
62
|
|
|
63
|
+
`.vulture-whitelist.py` is likewise generated — from every `@dataclass` field
|
|
64
|
+
in `agent_runner/`. If you add or rename a dataclass field, run
|
|
65
|
+
`./build.sh vulture-whitelist` and commit the regenerated file;
|
|
66
|
+
`tests/invariants/test_vulture_whitelist_generated.py` fails the gate if it
|
|
67
|
+
drifts.
|
|
68
|
+
|
|
43
69
|
## Tests
|
|
44
70
|
|
|
45
71
|
- Unit + integration: `pytest -q --ignore=tests/e2e --ignore=tests/literate`
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cli-agent-runner
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: Restart-on-exit supervisor for autonomous CLI agents
|
|
5
5
|
Project-URL: Homepage, https://github.com/wan9yu/cli-agent-runner
|
|
6
6
|
Project-URL: Documentation, https://github.com/wan9yu/cli-agent-runner#readme
|
|
@@ -31,7 +31,6 @@ Requires-Dist: pytest>=8; extra == 'dev'
|
|
|
31
31
|
Requires-Dist: ruff>=0.5; extra == 'dev'
|
|
32
32
|
Requires-Dist: vulture>=2.13; extra == 'dev'
|
|
33
33
|
Provides-Extra: e2e
|
|
34
|
-
Requires-Dist: fabric>=3; extra == 'e2e'
|
|
35
34
|
Requires-Dist: pytest>=8; extra == 'e2e'
|
|
36
35
|
Description-Content-Type: text/markdown
|
|
37
36
|
|
|
@@ -41,9 +40,10 @@ Description-Content-Type: text/markdown
|
|
|
41
40
|
|
|
42
41
|
# agent-runner
|
|
43
42
|
|
|
44
|
-
A restart-on-exit supervisor for autonomous coding CLIs.
|
|
45
|
-
Code
|
|
46
|
-
the agent round-after-round under defenses that prevent the
|
|
43
|
+
A restart-on-exit supervisor for autonomous coding CLIs. Ships presets for
|
|
44
|
+
Claude Code, aider, gemini and codewhale; any prompt-arg CLI via custom
|
|
45
|
+
config. Spawn the agent round-after-round under defenses that prevent the
|
|
46
|
+
failure modes
|
|
47
47
|
that bite in production: stuck rounds, orphan commits, OAuth burn loops,
|
|
48
48
|
full disks, runaway memory.
|
|
49
49
|
|
|
@@ -80,12 +80,12 @@ agent-runner monitor # live anomaly detection
|
|
|
80
80
|
|
|
81
81
|
Full walkthrough: [`docs/quickstart.md`](docs/quickstart.md).
|
|
82
82
|
|
|
83
|
-
##
|
|
83
|
+
## 15 verbs
|
|
84
84
|
|
|
85
85
|
| Lifecycle | Observation |
|
|
86
86
|
|---|---|
|
|
87
87
|
| `init` / `install` / `uninstall` | `peek` — state snapshot |
|
|
88
|
-
| `start` / `stop` / `kill`
|
|
88
|
+
| `start` / `stop` / `kill` | `watch` — peek in a refresh loop |
|
|
89
89
|
| `restart` / `status` | `monitor` — 11 detectors, alerts, auto-stop |
|
|
90
90
|
| `round` / `serve` / `upgrade` | `events` — query / stream events.jsonl |
|
|
91
91
|
|
|
@@ -4,9 +4,10 @@
|
|
|
4
4
|
|
|
5
5
|
# agent-runner
|
|
6
6
|
|
|
7
|
-
A restart-on-exit supervisor for autonomous coding CLIs.
|
|
8
|
-
Code
|
|
9
|
-
the agent round-after-round under defenses that prevent the
|
|
7
|
+
A restart-on-exit supervisor for autonomous coding CLIs. Ships presets for
|
|
8
|
+
Claude Code, aider, gemini and codewhale; any prompt-arg CLI via custom
|
|
9
|
+
config. Spawn the agent round-after-round under defenses that prevent the
|
|
10
|
+
failure modes
|
|
10
11
|
that bite in production: stuck rounds, orphan commits, OAuth burn loops,
|
|
11
12
|
full disks, runaway memory.
|
|
12
13
|
|
|
@@ -43,12 +44,12 @@ agent-runner monitor # live anomaly detection
|
|
|
43
44
|
|
|
44
45
|
Full walkthrough: [`docs/quickstart.md`](docs/quickstart.md).
|
|
45
46
|
|
|
46
|
-
##
|
|
47
|
+
## 15 verbs
|
|
47
48
|
|
|
48
49
|
| Lifecycle | Observation |
|
|
49
50
|
|---|---|
|
|
50
51
|
| `init` / `install` / `uninstall` | `peek` — state snapshot |
|
|
51
|
-
| `start` / `stop` / `kill`
|
|
52
|
+
| `start` / `stop` / `kill` | `watch` — peek in a refresh loop |
|
|
52
53
|
| `restart` / `status` | `monitor` — 11 detectors, alerts, auto-stop |
|
|
53
54
|
| `round` / `serve` / `upgrade` | `events` — query / stream events.jsonl |
|
|
54
55
|
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
> 中文 · **[English](README.md)**
|
|
2
|
+
|
|
3
|
+
# agent-runner
|
|
4
|
+
|
|
5
|
+
把任意 CLI agent(Claude Code、aider、任何接受 prompt 参数的命令)包装成能被
|
|
6
|
+
systemd / launchd 拉起、能被远程观测的服务。**每轮跑完进程退出**,外层
|
|
7
|
+
supervisor 重启 —— 这是核心模式。中间穿插一组防御,避开 production 上最容易
|
|
8
|
+
翻车的几条路:轮卡死、脏文件没 commit、OAuth 失效烧 quota、磁盘写满、
|
|
9
|
+
两个 supervisor 抢同一个仓库。
|
|
10
|
+
|
|
11
|
+
三层,每层都能独立运行,上层都是可选的:`round` 跑一次 agent 跑完即退;
|
|
12
|
+
`serve` 捕获信号循环拉起 round;`monitor` 检测器 + 告警,critical 时自动停服
|
|
13
|
+
(本机或 ssh 远程)。
|
|
14
|
+
|
|
15
|
+
## 安装
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pip install cli-agent-runner
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
CLI 命令是 `agent-runner`(PyPI 包名加 `cli-` 前缀只是为了规避命名冲突,
|
|
22
|
+
导入名 `agent_runner` 和命令名都不变)。
|
|
23
|
+
|
|
24
|
+
## 完整文档
|
|
25
|
+
|
|
26
|
+
文档以英文为准。下面 `docs/` 各页末尾都附有中文摘要,完整细节见英文正文:
|
|
27
|
+
|
|
28
|
+
- [`docs/quickstart.md`](docs/quickstart.md) —— 5 步装好并跑通第一轮
|
|
29
|
+
- [`README.md`](README.md) —— 定位、动词表、内置防御、Monitor 检测器
|
|
30
|
+
- [`docs/architecture.md`](docs/architecture.md) —— 三层模型 + defenses-as-data
|
|
31
|
+
- [`docs/commands.md`](docs/commands.md) —— 动词参考
|
|
32
|
+
- [`docs/configuration.md`](docs/configuration.md) —— `agent-runner.toml` schema
|
|
33
|
+
- [`docs/runbook.md`](docs/runbook.md) —— 操作手册 + 故障排查
|
|
34
|
+
|
|
35
|
+
## License
|
|
36
|
+
|
|
37
|
+
[Apache License 2.0](LICENSE).
|
|
@@ -20,6 +20,23 @@ Please **do not** open a public issue for security problems.
|
|
|
20
20
|
- An initial assessment within 7 business days.
|
|
21
21
|
- A fix and coordinated disclosure timeline once the scope is understood.
|
|
22
22
|
|
|
23
|
+
## Threat model
|
|
24
|
+
|
|
25
|
+
agent-runner is a **supervisor**, not a sandbox. It provides observability
|
|
26
|
+
(structured events, peek/watch/monitor) and lifecycle safety (round timeouts,
|
|
27
|
+
process-group reaping, orphan stashing, auto-stop on critical alerts). It does
|
|
28
|
+
**not** confine the agent process: the agent runs with the invoking user's full
|
|
29
|
+
privileges and can read, write, and execute anything that user can.
|
|
30
|
+
|
|
31
|
+
Prompt injection from untrusted repository content is unsolved and out of the
|
|
32
|
+
supervisor's reach — a malicious file in the work tree can steer the agent, and
|
|
33
|
+
no defense in this project prevents that.
|
|
34
|
+
|
|
35
|
+
Operators supervising untrusted input should run the agent as a dedicated
|
|
36
|
+
unprivileged user, inside a container or VM, without passwordless sudo, and
|
|
37
|
+
with egress limits. The supervisor's defenses bound the blast radius of a
|
|
38
|
+
*misbehaving* agent, not a *hostile* one.
|
|
39
|
+
|
|
23
40
|
## Scope
|
|
24
41
|
|
|
25
42
|
In scope: the `agent_runner` Python package, its CLI, its bundled systemd
|
|
@@ -17,6 +17,9 @@ from agent_runner.config import (
|
|
|
17
17
|
AgentConfig,
|
|
18
18
|
Config,
|
|
19
19
|
MonitorConfig,
|
|
20
|
+
MonitorHostHealthConfig,
|
|
21
|
+
PhasesConfig,
|
|
22
|
+
PluginsConfig,
|
|
20
23
|
PromptConfig,
|
|
21
24
|
RuntimeConfig,
|
|
22
25
|
VcsConfig,
|
|
@@ -25,41 +28,60 @@ from agent_runner.defenses import catalog
|
|
|
25
28
|
from agent_runner.events import KNOWN_EVENT_KINDS
|
|
26
29
|
from agent_runner.monitor import AUTO_STOP_ALERTS, KNOWN_ALERT_KINDS
|
|
27
30
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
# (toml_section_name, dataclass, nested_sub_sections). Nesting is an EXPLICIT
|
|
32
|
+
# registry, not reflection, on two counts:
|
|
33
|
+
# - field name != TOML key: PhaseOverride.prompt_files is written as
|
|
34
|
+
# [phases.<name>.prompt] files=[...], and PluginsConfig.raw is a catch-all
|
|
35
|
+
# for unknown keys. Recursing generically would document TOML keys that do
|
|
36
|
+
# not exist.
|
|
37
|
+
# - typing.get_type_hints() raises TypeError on PhasesConfig — its `list`
|
|
38
|
+
# field shadows the builtin, so `list[str] | None` resolves against
|
|
39
|
+
# None. Do not reach for it here.
|
|
40
|
+
_SECTIONS: list[tuple[str, type, list[tuple[str, type]]]] = [
|
|
41
|
+
("agent", AgentConfig, []),
|
|
42
|
+
("runtime", RuntimeConfig, []),
|
|
43
|
+
("prompt", PromptConfig, []),
|
|
44
|
+
("vcs", VcsConfig, []),
|
|
45
|
+
("monitor", MonitorConfig, [("monitor.host_health", MonitorHostHealthConfig)]),
|
|
46
|
+
("phases", PhasesConfig, []),
|
|
47
|
+
("plugins", PluginsConfig, []),
|
|
34
48
|
]
|
|
35
49
|
|
|
36
50
|
|
|
51
|
+
def _cell(s: str) -> str:
|
|
52
|
+
# A bare `|` ends the markdown cell. Live sources: `X | None` annotations
|
|
53
|
+
# and the auth_fail_patterns regex default.
|
|
54
|
+
return s.replace("|", "\\|")
|
|
55
|
+
|
|
56
|
+
|
|
37
57
|
def _type_label(t: typing.Any) -> str:
|
|
38
58
|
# dataclasses.fields exposes `.type` as a string (PEP 563), so we render
|
|
39
59
|
# the raw annotation. Strip ``Path`` / ``Path | None`` wrappers cosmetically.
|
|
40
|
-
|
|
41
|
-
return s
|
|
60
|
+
return _cell(str(t).replace("pathlib.", ""))
|
|
42
61
|
|
|
43
62
|
|
|
44
63
|
def _default_label(field: dataclasses.Field) -> str:
|
|
45
64
|
if field.default is not dataclasses.MISSING:
|
|
46
|
-
return repr(field.default)
|
|
65
|
+
return _cell(repr(field.default))
|
|
47
66
|
if field.default_factory is not dataclasses.MISSING: # type: ignore[misc]
|
|
48
|
-
return repr(field.default_factory())
|
|
67
|
+
return _cell(repr(field.default_factory()))
|
|
49
68
|
return "—"
|
|
50
69
|
|
|
51
70
|
|
|
71
|
+
def _field_table(dc: type) -> list[str]:
|
|
72
|
+
rows = ["| Field | Type | Default |", "|---|---|---|"]
|
|
73
|
+
for f in dataclasses.fields(dc):
|
|
74
|
+
rows.append(f"| `{f.name}` | `{_type_label(f.type)}` | {_default_label(f)} |")
|
|
75
|
+
return rows
|
|
76
|
+
|
|
77
|
+
|
|
52
78
|
def render_config_schema_table() -> str:
|
|
53
79
|
"""Markdown sub-sections per Config dataclass with field/type/default."""
|
|
54
80
|
parts: list[str] = []
|
|
55
|
-
for name, dc in _SECTIONS:
|
|
56
|
-
parts
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
parts.append("|---|---|---|")
|
|
60
|
-
for f in dataclasses.fields(dc):
|
|
61
|
-
parts.append(f"| `{f.name}` | `{_type_label(f.type)}` | {_default_label(f)} |")
|
|
62
|
-
parts.append("")
|
|
81
|
+
for name, dc, nested in _SECTIONS:
|
|
82
|
+
parts += [f"### `[{name}]`", "", *_field_table(dc), ""]
|
|
83
|
+
for sub_name, sub_dc in nested:
|
|
84
|
+
parts += [f"#### `[{sub_name}]`", "", *_field_table(sub_dc), ""]
|
|
63
85
|
return "\n".join(parts).rstrip()
|
|
64
86
|
|
|
65
87
|
|
|
@@ -80,7 +102,11 @@ def replace_block(text: str, name: str, new_content: str) -> str:
|
|
|
80
102
|
re.escape(open_tag) + r".*?" + re.escape(close_tag),
|
|
81
103
|
re.DOTALL,
|
|
82
104
|
)
|
|
83
|
-
|
|
105
|
+
replacement = f"{open_tag}\n{new_content}\n{close_tag}"
|
|
106
|
+
# A string repl is a TEMPLATE (expands \n, \t, \1, \g<...>); a callable repl
|
|
107
|
+
# is inserted literally. new_content carries rendered config defaults, which
|
|
108
|
+
# may contain backslashes.
|
|
109
|
+
return pattern.sub(lambda _m: replacement, text)
|
|
84
110
|
|
|
85
111
|
|
|
86
112
|
def _default_cfg() -> Config:
|