cli-agent-runner 0.2.24__tar.gz → 0.3.1__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.24 → cli_agent_runner-0.3.1}/.github/workflows/ci.yml +3 -3
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/.github/workflows/release.yml +3 -3
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/.vulture-whitelist.py +32 -11
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/CHANGELOG.md +22 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/PKG-INFO +2 -2
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/README.md +1 -1
- cli_agent_runner-0.3.1/agent_runner/__init__.py +102 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/_docgen.py +13 -1
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/_emit/__init__.py +2 -2
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/_emit/memory.py +33 -3
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/_emit/rounds.py +1 -1
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/_emit/serve.py +0 -20
- cli_agent_runner-0.3.1/agent_runner/_install.py +187 -0
- cli_agent_runner-0.3.1/agent_runner/_lifecycle.py +338 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/_monitor_detectors.py +13 -12
- cli_agent_runner-0.3.1/agent_runner/_observe.py +405 -0
- cli_agent_runner-0.3.1/agent_runner/_plugin_manifest.py +113 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/_plugin_scan.py +9 -8
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/_serve_policy.py +3 -3
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/_version.py +2 -2
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/agent_runtime.py +20 -0
- cli_agent_runner-0.3.1/agent_runner/api.py +181 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/api_types.py +5 -3
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/builtin_plugins/claude_rate_limit.py +3 -2
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/builtin_plugins/codewhale.py +3 -2
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/builtin_plugins/default_dirty_handler.py +3 -2
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/builtin_plugins/gemini.py +3 -2
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/builtin_plugins/kimi.py +3 -2
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/builtin_plugins/pi.py +3 -2
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/cli/__init__.py +9 -4
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/cli/_serve_cgroup.py +4 -3
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/cli/_serve_round.py +78 -13
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/cli/common.py +1 -1
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/cli/serve_cmd.py +6 -9
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/config/__init__.py +10 -1
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/config/loader.py +28 -1
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/config/models.py +59 -33
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/config/parsers.py +70 -48
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/config/validators.py +13 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/defenses.py +3 -3
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/events.py +4 -3
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/host_health.py +43 -21
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/lifecycle.py +2 -2
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/migrations.py +203 -19
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/monitor.py +15 -17
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/phase_select.py +30 -8
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/presets/aider.toml +2 -1
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/presets/claude.toml +2 -1
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/presets/codewhale.toml +2 -1
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/presets/gemini.toml +2 -1
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/presets/kimi.toml +2 -1
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/presets/pi.toml +2 -1
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/runner.py +2 -2
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/service_unit.py +4 -4
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/startup_check.py +19 -1
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/docs/architecture.md +9 -7
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/docs/commands.md +23 -9
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/docs/configuration.md +60 -27
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/docs/events.md +3 -3
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/docs/long-running-agents.md +5 -6
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/docs/memory-efficiency.md +84 -4
- cli_agent_runner-0.3.1/docs/migrations/0.3.md +103 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/docs/plugins.md +122 -96
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/docs/quickstart.md +1 -1
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/docs/recipes/aider.md +2 -1
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/docs/recipes/codewhale.md +4 -3
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/docs/recipes/container-pi.md +1 -1
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/docs/recipes/pi.md +2 -2
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/docs/runbook.md +22 -21
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/pyproject.toml +11 -9
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/_test_helpers.py +4 -1
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/contract/test_public_api_surface.py +1 -1
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/e2e/conftest.py +1 -1
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/integration/test_auto_stop_e2e.py +2 -2
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/integration/test_dirty_handler_seam.py +2 -2
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/integration/test_grace_kill_emission.py +5 -5
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/integration/test_install_dry_run.py +3 -3
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/integration/test_plugin_real_flow.py +1 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/integration/test_run_one_round_with_fake_agent.py +10 -9
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/integration/test_serve_loop.py +7 -12
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/integration/test_spawn_round_mem_floor.py +33 -23
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/invariants/test_architecture.py +15 -2
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/invariants/test_config_error_consistency.py +4 -4
- cli_agent_runner-0.3.1/tests/invariants/test_doc_builtin_plugins.py +57 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/invariants/test_doc_claims_match_ssot.py +2 -2
- cli_agent_runner-0.3.1/tests/invariants/test_entry_points_resolve.py +71 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/invariants/test_import_footprint.py +12 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/invariants/test_module_boundaries.py +2 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/invariants/test_no_price_logic.py +2 -2
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/invariants/test_peek_schema_version.py +1 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/invariants/test_timeout_budget_invariant.py +2 -2
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_agent_runtime_grace.py +66 -3
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_api_install.py +22 -17
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_api_observation.py +38 -4
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_api_resolve_phase.py +6 -6
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_api_service.py +77 -64
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_auto_stop_gating.py +6 -3
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_cli.py +3 -2
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_cli_common.py +2 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_cli_main_boundary.py +50 -1
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_cli_service_peek_monitor.py +1 -1
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_config.py +299 -78
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_config_nested_strictness.py +1 -1
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_config_schedule.py +1 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_config_strictness.py +3 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_control_char_config.py +1 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_defenses.py +3 -3
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_detect_hung_latch.py +4 -4
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_docgen.py +12 -8
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_doctor_cmd.py +24 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_events.py +27 -4
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_hooks.py +1 -1
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_host_health.py +67 -5
- cli_agent_runner-0.3.1/tests/unit/test_init_entry_points.py +171 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_migrate_cmd.py +9 -8
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_migrations.py +195 -24
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_monitor_assembly.py +2 -2
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_monitor_dedup_identity.py +3 -2
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_monitor_dedup_rearm.py +5 -5
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_monitor_detectors.py +34 -17
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_monitor_loop.py +7 -7
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_outer_round_ceiling.py +19 -2
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_phase_agent_launch.py +1 -1
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_phase_profiles.py +8 -8
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_phase_select.py +27 -0
- cli_agent_runner-0.3.1/tests/unit/test_plugin_manifest.py +94 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_plugin_scan_parity.py +13 -12
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_resolve.py +2 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_runner.py +6 -6
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_serve_mem_gate.py +3 -2
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_serve_round.py +8 -8
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_serve_round_cgroup_spine.py +168 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_serve_round_log.py +1 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_service_unit.py +10 -10
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_startup_check.py +5 -3
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_upgrade_migrate.py +37 -1
- cli_agent_runner-0.2.24/agent_runner/__init__.py +0 -165
- cli_agent_runner-0.2.24/agent_runner/api.py +0 -990
- cli_agent_runner-0.2.24/tests/invariants/test_doc_builtin_plugins.py +0 -41
- cli_agent_runner-0.2.24/tests/invariants/test_entry_points_resolve.py +0 -63
- cli_agent_runner-0.2.24/tests/unit/test_init_entry_points.py +0 -226
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/.codecov.yml +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/.github/dependabot.yml +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/.gitignore +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/BACKLOG.md +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/CODE_OF_CONDUCT.md +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/CONTRIBUTING.md +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/LICENSE +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/README.zh.md +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/SECURITY.md +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/_emit/agent.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/_monitor_registry.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/_monitor_state.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/_redact.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/_registry.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/_resolve.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/_round_outcome.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/_round_support.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/_substrate.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/_throttle.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/builtin_plugins/__init__.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/builtin_plugins/_constants.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/cli/__main__.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/cli/doctor_cmd.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/cli/events_cmd.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/cli/init_cmd.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/cli/install_cmd.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/cli/migrate_cmd.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/cli/monitor_cmd.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/cli/peek_cmd.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/cli/round_cmd.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/cli/service_cmd.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/cli/upgrade_cmd.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/clock.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/config/errors.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/context_store.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/hooks.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/http_progress.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/metrics.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/presets/__init__.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/prompt_loader.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/remote_relay.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/round_log.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/round_view.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/scaffold.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/schedule.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/agent_runner/vcs_state.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/build.sh +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/deploy/Dockerfile +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/deploy/docker-compose.yml +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/docs/README.md +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/docs/migrations/0.2.md +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/docs/recipes/deploy-all-in-one.md +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/docs/recipes/kimi.md +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/docs/thesis.md +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/__init__.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/_clock.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/conftest.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/contract/__init__.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/e2e/__init__.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/e2e/test_e2e_graceful_stop.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/e2e/test_e2e_install_systemd.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/e2e/test_e2e_monitor_remote.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/e2e/test_e2e_round_lifecycle.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/fixtures/cli-real-output/claude-2.1.143-assistant-tool-use.jsonl +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/fixtures/cli-real-output/claude-2.1.143-result-event.jsonl +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/fixtures/cli-real-output/gemini-0.42.0-result-event.jsonl +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/generate_vulture_whitelist.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/integration/__init__.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/integration/test_bounded_run.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/integration/test_context_enricher_namespacing.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/integration/test_fresh_eyes_signal.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/integration/test_monitor_seeded.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/integration/test_plugin_detector_loaded.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/integration/test_plugin_owned_paths.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/integration/test_prompt_delivery_stdin.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/integration/test_scaffold_presets.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/integration/test_spawn_round_wedged.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/integration/test_substrate_fingerprint.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/integration/test_transient_error_backoff.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/invariants/__init__.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/invariants/_docs.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/invariants/_event_scan.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/invariants/test_atomic_write_enforced.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/invariants/test_authored_facts_declared.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/invariants/test_auto_stop_policy_ssot.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/invariants/test_bdd_test_conventions.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/invariants/test_catalogs.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/invariants/test_classification_ssot.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/invariants/test_config_value_set_ssot.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/invariants/test_container_stop_bound.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/invariants/test_dataclass_fields_have_producers.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/invariants/test_doc_cli_claims.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/invariants/test_doc_operator_surface.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/invariants/test_doc_test_pointers_exist.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/invariants/test_doc_transient_error_claims.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/invariants/test_doc_usage_event_fields.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/invariants/test_docs_generated.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/invariants/test_docs_index_complete.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/invariants/test_event_int_coercion.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/invariants/test_event_kind_registry.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/invariants/test_event_kinds_ssot.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/invariants/test_events_doc_contract.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/invariants/test_gen_blocks_name_their_source.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/invariants/test_hook_contract_docs.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/invariants/test_layer_2_loop_size.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/invariants/test_migrations_registry_ssot.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/invariants/test_module_sizes.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/invariants/test_monitor_self_exclusion.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/invariants/test_no_ai_signatures.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/invariants/test_no_internal_refs.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/invariants/test_no_pytest_skip_on_parse_fail.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/invariants/test_no_raw_time.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/invariants/test_no_vacuous_invariants.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/invariants/test_no_version_refs.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/invariants/test_phase_select_stateless.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/invariants/test_plugins_config_stable.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/invariants/test_readme_zh_is_pointer.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/invariants/test_repo_constants_patched_in_tests.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/invariants/test_round_alloc_growth.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/invariants/test_round_log_decode_boundary.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/invariants/test_round_num_single_source.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/invariants/test_round_result_stable.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/invariants/test_set_diff_for_auto_tool_classification.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/invariants/test_stash_uses_sha_not_index.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/invariants/test_upstream_schema_canary.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/invariants/test_vulture_whitelist_generated.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/literate/__init__.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/literate/parser.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/literate/test_parser.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/literate/test_quickstart.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/__init__.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_agent_runtime.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_agent_runtime_container.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_agent_runtime_marker_scan.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_agent_runtime_progress.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_agent_runtime_reap.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_agent_runtime_signal_name.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_api_assemble_prompt.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_api_events_stream.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_api_read_round_num.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_api_types.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_catalogs.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_cgroup_probe.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_claude_error_detector.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_claude_foreign_schema.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_cli_init_install.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_cli_monitor_http.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_cli_upgrade.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_codewhale_code_precedence.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_codewhale_plugin.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_coerce_int_poison.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_config_fresh_eyes.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_config_max_rounds.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_config_prompt_delivery.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_config_stop_file.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_config_substrate_fingerprint_paths.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_config_transient_error_action.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_context_store.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_default_dirty_handler.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_detector_isolation.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_detector_protocol.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_dirty_handlers.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_effective_throttle_view.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_emit_config_migrated.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_emit_schedule.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_emit_schedule_phase_skipped.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_events_cmd.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_events_cmd_rollover.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_events_cmd_tail.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_events_jsonl_decode.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_example_dirty_handler.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_example_plugin.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_exec_prefix.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_exit_cause.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_exit_classifier.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_fresh_eyes_trigger.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_gemini_plugin.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_git_timeout.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_hook_failure_isolation.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_hook_redact_order.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_http_progress.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_http_progress_epoch.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_interruptible_sleep_should_stop.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_kimi_plugin.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_lifecycle.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_metrics.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_metrics_cgroup_usage.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_metrics_swap.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_monitor_cmd_severity.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_monitor_detect_anomaly_repetitive.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_monitor_detect_rate_limit.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_monitor_detect_supervisor_stale.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_monitor_event_tail.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_monitor_on_alert.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_monitor_remote.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_monitor_round_deferred_stale.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_monitor_schedule_pause.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_network_blip_signal_guard.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_open_round_log.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_orphan_chain_single_pass.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_peek_argparse.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_peek_project_isolation.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_peek_schedule.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_peek_select.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_pi_plugin.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_plugin_constants.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_presets.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_primary_prompt_file_home.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_prompt_loader.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_read_json_hardening.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_redact.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_round_cmd.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_round_cmd_sigterm.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_round_log_helpers.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_round_outcome.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_round_outcome_agent_axis.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_round_view.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_runner_sidecar_ordering.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_runner_throttle.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_scaffold.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_schedule.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_serve_cmd_bounded.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_serve_config_broken.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_serve_crash_loop.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_serve_phase_schedule.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_serve_policy.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_serve_round_oom_killed.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_serve_round_terminate.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_serve_schedule_gate.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_serve_sentinel.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_serve_startup_hooks.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_service_mode.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_startup_battery_exit.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_substrate.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_supervisor_stale_self_blind.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_throttle_back_off_ladder.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_throttle_epoch_bound.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_throttle_plugin_classification.py +0 -0
- {cli_agent_runner-0.2.24 → cli_agent_runner-0.3.1}/tests/unit/test_vcs_state.py +0 -0
|
@@ -18,7 +18,7 @@ jobs:
|
|
|
18
18
|
runs-on: ubuntu-latest
|
|
19
19
|
timeout-minutes: 2
|
|
20
20
|
steps:
|
|
21
|
-
- uses: actions/checkout@
|
|
21
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
22
22
|
with:
|
|
23
23
|
# PR: scan only new commits the PR introduces (base..head).
|
|
24
24
|
# Push to main: scan the just-pushed commits (before..after).
|
|
@@ -74,10 +74,10 @@ jobs:
|
|
|
74
74
|
# granularity AND because coverage requires extra pytest flags not in
|
|
75
75
|
# the local `test` task. CONTRIBUTING.md states the parity intentionally.
|
|
76
76
|
steps:
|
|
77
|
-
- uses: actions/checkout@
|
|
77
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
78
78
|
with:
|
|
79
79
|
fetch-depth: 0
|
|
80
|
-
- uses: actions/setup-python@
|
|
80
|
+
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
|
81
81
|
with:
|
|
82
82
|
python-version: ${{ matrix.python }}
|
|
83
83
|
cache: pip
|
|
@@ -26,10 +26,10 @@ jobs:
|
|
|
26
26
|
runs-on: ubuntu-latest
|
|
27
27
|
timeout-minutes: 10
|
|
28
28
|
steps:
|
|
29
|
-
- uses: actions/checkout@
|
|
29
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
30
30
|
with:
|
|
31
31
|
fetch-depth: 0
|
|
32
|
-
- uses: actions/setup-python@
|
|
32
|
+
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
|
33
33
|
with:
|
|
34
34
|
python-version: "3.12"
|
|
35
35
|
- name: install build
|
|
@@ -72,7 +72,7 @@ jobs:
|
|
|
72
72
|
permissions:
|
|
73
73
|
contents: write
|
|
74
74
|
steps:
|
|
75
|
-
- uses: actions/checkout@
|
|
75
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
76
76
|
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
|
77
77
|
with:
|
|
78
78
|
name: dist
|
|
@@ -13,6 +13,16 @@ log_dir
|
|
|
13
13
|
offsets
|
|
14
14
|
buffer
|
|
15
15
|
|
|
16
|
+
# agent_runner._plugin_manifest.PluginManifest
|
|
17
|
+
name
|
|
18
|
+
pre_round_hooks
|
|
19
|
+
context_enrichers
|
|
20
|
+
post_round_hooks
|
|
21
|
+
serve_startup_hooks
|
|
22
|
+
dirty_handlers
|
|
23
|
+
detectors
|
|
24
|
+
event_kinds
|
|
25
|
+
|
|
16
26
|
# agent_runner._round_outcome.RoundOutcome
|
|
17
27
|
mem_terminated
|
|
18
28
|
usage_capable
|
|
@@ -67,6 +77,7 @@ service
|
|
|
67
77
|
recent_events
|
|
68
78
|
recent_hook_failures
|
|
69
79
|
recent_blips
|
|
80
|
+
recent_cgroup_growth_warnings
|
|
70
81
|
schedule
|
|
71
82
|
|
|
72
83
|
# agent_runner.api_types.RateLimitState
|
|
@@ -164,18 +175,12 @@ round_progress_interval_s
|
|
|
164
175
|
supervisor_stale_threshold_s
|
|
165
176
|
|
|
166
177
|
# agent_runner.config.models.MonitorHostHealthConfig
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
swap_sout_noise_floor_mb
|
|
171
|
-
mem_free_low_mb
|
|
172
|
-
psi_full_avg10_critical
|
|
173
|
-
psi_some_avg10_warning
|
|
174
|
-
mem_critical_consecutive_samples
|
|
175
|
-
in_round_mem_terminate
|
|
178
|
+
disk
|
|
179
|
+
memory
|
|
180
|
+
pressure
|
|
176
181
|
|
|
177
182
|
# agent_runner.config.models.PhaseOverride
|
|
178
|
-
|
|
183
|
+
round_budget_s
|
|
179
184
|
disable_pre_round_hooks
|
|
180
185
|
prompt_files
|
|
181
186
|
agent
|
|
@@ -207,7 +212,7 @@ strip_yaml_frontmatter
|
|
|
207
212
|
# agent_runner.config.models.RuntimeConfig
|
|
208
213
|
work_dir
|
|
209
214
|
log_dir
|
|
210
|
-
|
|
215
|
+
round_budget_s
|
|
211
216
|
restart_delay_s
|
|
212
217
|
disable_pre_round_hooks
|
|
213
218
|
round_log_retention
|
|
@@ -230,6 +235,22 @@ pause_windows
|
|
|
230
235
|
stash_idempotency_s
|
|
231
236
|
dirty_action
|
|
232
237
|
|
|
238
|
+
# agent_runner.config.models._HostHealthDiskConfig
|
|
239
|
+
warning_pct
|
|
240
|
+
critical_pct
|
|
241
|
+
|
|
242
|
+
# agent_runner.config.models._HostHealthMemoryConfig
|
|
243
|
+
avail_min_mb
|
|
244
|
+
free_low_mb
|
|
245
|
+
swap_out_noise_floor_mb
|
|
246
|
+
|
|
247
|
+
# agent_runner.config.models._HostHealthPressureConfig
|
|
248
|
+
full_avg10_critical
|
|
249
|
+
some_avg10_warning
|
|
250
|
+
critical_consecutive_samples
|
|
251
|
+
in_round_terminate
|
|
252
|
+
cgroup_growth_rate_warning_mb_per_min
|
|
253
|
+
|
|
233
254
|
# agent_runner.context_store.OrphanState
|
|
234
255
|
round_num
|
|
235
256
|
files
|
|
@@ -5,6 +5,28 @@ 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.3.1] - 2026-09-14
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- `monitor.host_health.pressure.cgroup_growth_rate_warning_mb_per_min` (default 512.0): a mid-round memory-growth-rate detector gives an earlier growth signal than the existing PSI/MemFree floors catch, ahead of a runaway climb reaching them. Observability only — no round action.
|
|
12
|
+
- `cgroup_growth_rate_warning` event, surfaced in `peek --json` as `recent_cgroup_growth_warnings` (schema `2.1`).
|
|
13
|
+
|
|
14
|
+
## [0.3.0] - 2026-09-13
|
|
15
|
+
|
|
16
|
+
**The one breaking release of the 0.3 line.** Run `agent-runner migrate` before upgrading — it rewrites everything below in one pass.
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
- `[monitor.host_health]`'s 9 flat keys regroup into `.disk`/`.memory`/`.pressure` sub-tables (defaults unchanged).
|
|
20
|
+
- `round_timeout_s` renamed to `round_budget_s` in `[runtime]` and `[phases.*]` (flat and nested forms).
|
|
21
|
+
- The plugin ABI collapses from 7 entry-point groups to one (`agent_runner.plugins`), each resolving a typed `PluginManifest` instead of an import-time side effect. External plugins need a manual port — see `docs/migrations/0.3.md`.
|
|
22
|
+
- A phase-window overlap now refuses `serve` boot (was a warning); `doctor` reports it as a failing check.
|
|
23
|
+
- `peek --json` schema bumps to `2.0`.
|
|
24
|
+
- Config now carries a top-level `schema_version`; a pre-0.3 or unversioned config is rejected with a pointed `agent-runner migrate` instruction.
|
|
25
|
+
- `api.py` split into `_install`/`_lifecycle`/`_observe` behind an unchanged public facade — no external-surface change.
|
|
26
|
+
|
|
27
|
+
### Renamed
|
|
28
|
+
- Tenet-3 terminology: "price-blind" → "price-agnostic" (no logic change).
|
|
29
|
+
|
|
8
30
|
## [0.2.24] - 2026-09-12
|
|
9
31
|
|
|
10
32
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: cli-agent-runner
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.1
|
|
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
|
|
@@ -100,7 +100,7 @@ Verb reference: [`docs/commands.md`](docs/commands.md).
|
|
|
100
100
|
Each carries the historical incident it codifies and the invariant test that
|
|
101
101
|
guards it. Highlights:
|
|
102
102
|
|
|
103
|
-
- **
|
|
103
|
+
- **round_budget_s** — hard wall, never the agent's word on when to stop
|
|
104
104
|
- **process_group_isolation** — kill the round, not just the parent
|
|
105
105
|
- **orphan_stash_idempotency_s** — no 3-stashes-per-second pile-ups
|
|
106
106
|
- **sha_locked_stash** — `stash@{N}` indices drift; SHAs don't
|
|
@@ -62,7 +62,7 @@ Verb reference: [`docs/commands.md`](docs/commands.md).
|
|
|
62
62
|
Each carries the historical incident it codifies and the invariant test that
|
|
63
63
|
guards it. Highlights:
|
|
64
64
|
|
|
65
|
-
- **
|
|
65
|
+
- **round_budget_s** — hard wall, never the agent's word on when to stop
|
|
66
66
|
- **process_group_isolation** — kill the round, not just the parent
|
|
67
67
|
- **orphan_stash_idempotency_s** — no 3-stashes-per-second pile-ups
|
|
68
68
|
- **sha_locked_stash** — `stash@{N}` indices drift; SHAs don't
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"""Agent Runner — restart-on-exit supervisor for autonomous CLI agents."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
try:
|
|
6
|
+
from agent_runner._version import __version__
|
|
7
|
+
except ImportError: # editable install before hatch-vcs has generated _version.py
|
|
8
|
+
__version__ = "0.0.0+unknown"
|
|
9
|
+
|
|
10
|
+
_PLUGIN_GROUP = "agent_runner.plugins"
|
|
11
|
+
|
|
12
|
+
# Tracks the names passed to the most recent ``apply_plugin_disable`` call.
|
|
13
|
+
# Surfaced via peek --json `plugins.disabled` for operator visibility.
|
|
14
|
+
_DISABLED_PLUGIN_NAMES: list[str] = []
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _load_plugin_manifests() -> None:
|
|
18
|
+
"""Discover agent_runner.plugins entry points, resolve each to a
|
|
19
|
+
module-level PluginManifest, and register its declared capabilities.
|
|
20
|
+
|
|
21
|
+
Called at package import. A broken plugin (bad import, missing PLUGIN
|
|
22
|
+
attribute, malformed manifest) must never crash the supervisor — isolated
|
|
23
|
+
as a UserWarning.
|
|
24
|
+
|
|
25
|
+
Discovery goes through the ``entry_points.txt`` scanner (cheaper than a
|
|
26
|
+
fresh ``importlib.metadata.entry_points()`` scan per process; see
|
|
27
|
+
``_plugin_scan``), with a hard fallback to ``importlib.metadata`` on any
|
|
28
|
+
parse failure.
|
|
29
|
+
"""
|
|
30
|
+
import importlib
|
|
31
|
+
import sys
|
|
32
|
+
import warnings
|
|
33
|
+
|
|
34
|
+
from agent_runner._plugin_manifest import register_manifest
|
|
35
|
+
from agent_runner._plugin_scan import scan_entry_points
|
|
36
|
+
|
|
37
|
+
for name, value in scan_entry_points(sys.path, _PLUGIN_GROUP):
|
|
38
|
+
try:
|
|
39
|
+
# An entry-point value may carry a trailing extras marker
|
|
40
|
+
# (``module:attr [extra1,extra2]``); importlib.metadata.EntryPoint's
|
|
41
|
+
# own module/attr grammar excludes "[", so anything from the first
|
|
42
|
+
# "[" onward is always extras, never part of the path — strip it
|
|
43
|
+
# before resolving, or it glues onto attr_path and breaks getattr().
|
|
44
|
+
module_path, _, attr_path = value.partition("[")[0].rstrip().partition(":")
|
|
45
|
+
mod = importlib.import_module(module_path)
|
|
46
|
+
target = mod
|
|
47
|
+
for attr in filter(None, attr_path.split(".")):
|
|
48
|
+
target = getattr(target, attr)
|
|
49
|
+
register_manifest(target)
|
|
50
|
+
except Exception as e:
|
|
51
|
+
warnings.warn(
|
|
52
|
+
f"failed to load {_PLUGIN_GROUP} plugin {name!r}: {e}",
|
|
53
|
+
stacklevel=3,
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
_load_plugin_manifests()
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def apply_plugin_disable(names: list[str]) -> None:
|
|
61
|
+
"""Remove plugins matching ``names`` (manifest names) from all in-memory
|
|
62
|
+
registries.
|
|
63
|
+
|
|
64
|
+
Called after config-load to honor ``[plugins] disable``. Idempotent for
|
|
65
|
+
already-removed names. Emits a UserWarning for names that match no
|
|
66
|
+
loaded manifest (typo catcher; tolerates cross-env config drift).
|
|
67
|
+
|
|
68
|
+
Plugin packages still load at import time — this removes from the registries
|
|
69
|
+
that the runner and peek consult. Side effects from loading (module-level
|
|
70
|
+
imports, etc.) have already happened by the time this runs.
|
|
71
|
+
|
|
72
|
+
Known limitation: vcs_state._PLUGIN_OWNED_PATHS lacks per-plugin name
|
|
73
|
+
attribution today, so owned-paths are NOT filtered here. Disabled plugin's
|
|
74
|
+
paths remain registered (mostly inert).
|
|
75
|
+
"""
|
|
76
|
+
import warnings
|
|
77
|
+
|
|
78
|
+
from agent_runner._plugin_manifest import unregister_by_name
|
|
79
|
+
|
|
80
|
+
if not names:
|
|
81
|
+
return
|
|
82
|
+
|
|
83
|
+
global _DISABLED_PLUGIN_NAMES
|
|
84
|
+
_DISABLED_PLUGIN_NAMES = list(names)
|
|
85
|
+
|
|
86
|
+
found = unregister_by_name(set(names))
|
|
87
|
+
unknown = set(names) - found
|
|
88
|
+
if unknown:
|
|
89
|
+
warnings.warn(
|
|
90
|
+
f"[plugins] disable references unknown plugin name(s): {sorted(unknown)}. "
|
|
91
|
+
f"(Names matched no loaded PluginManifest; check spelling or installed packages.)",
|
|
92
|
+
stacklevel=2,
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def disabled_plugin_names() -> list[str]:
|
|
97
|
+
"""Names passed to the most recent ``apply_plugin_disable`` call.
|
|
98
|
+
|
|
99
|
+
Used by peek --json to surface ``plugins.disabled`` for operator visibility.
|
|
100
|
+
Returns the LIST (not set) preserving configured order.
|
|
101
|
+
"""
|
|
102
|
+
return list(_DISABLED_PLUGIN_NAMES)
|
|
@@ -29,6 +29,9 @@ from agent_runner.config import (
|
|
|
29
29
|
RuntimeConfig,
|
|
30
30
|
ScheduleConfig,
|
|
31
31
|
VcsConfig,
|
|
32
|
+
_HostHealthDiskConfig,
|
|
33
|
+
_HostHealthMemoryConfig,
|
|
34
|
+
_HostHealthPressureConfig,
|
|
32
35
|
)
|
|
33
36
|
from agent_runner.defenses import catalog
|
|
34
37
|
from agent_runner.events import (
|
|
@@ -55,7 +58,16 @@ _SECTIONS: list[tuple[str, type, list[tuple[str, type]]]] = [
|
|
|
55
58
|
("runtime", RuntimeConfig, []),
|
|
56
59
|
("prompt", PromptConfig, []),
|
|
57
60
|
("vcs", VcsConfig, []),
|
|
58
|
-
(
|
|
61
|
+
(
|
|
62
|
+
"monitor",
|
|
63
|
+
MonitorConfig,
|
|
64
|
+
[
|
|
65
|
+
("monitor.host_health", MonitorHostHealthConfig),
|
|
66
|
+
("monitor.host_health.disk", _HostHealthDiskConfig),
|
|
67
|
+
("monitor.host_health.memory", _HostHealthMemoryConfig),
|
|
68
|
+
("monitor.host_health.pressure", _HostHealthPressureConfig),
|
|
69
|
+
],
|
|
70
|
+
),
|
|
59
71
|
("phases", PhasesConfig, []),
|
|
60
72
|
("plugins", PluginsConfig, []),
|
|
61
73
|
("schedule", ScheduleConfig, []),
|
|
@@ -29,6 +29,7 @@ from agent_runner._emit.agent import ( # noqa: F401 — public re-export
|
|
|
29
29
|
emit_transient_error_recovered,
|
|
30
30
|
)
|
|
31
31
|
from agent_runner._emit.memory import ( # noqa: F401 — public re-export
|
|
32
|
+
emit_cgroup_growth_rate_warning,
|
|
32
33
|
emit_host_cgroup_memory_limit,
|
|
33
34
|
emit_mem_pressure_deferred_to_cgroup,
|
|
34
35
|
emit_round_cgroup_memory,
|
|
@@ -57,7 +58,6 @@ from agent_runner._emit.serve import ( # noqa: F401 — public re-export
|
|
|
57
58
|
emit_max_rounds_reached,
|
|
58
59
|
emit_mem_loop,
|
|
59
60
|
emit_mem_loop_persistent,
|
|
60
|
-
emit_phase_window_overlap,
|
|
61
61
|
emit_rate_limit_stop,
|
|
62
62
|
emit_schedule_paused,
|
|
63
63
|
emit_schedule_phase_skipped,
|
|
@@ -70,6 +70,7 @@ __all__ = [
|
|
|
70
70
|
"emit_agent_auth_error_detected",
|
|
71
71
|
"emit_agent_usage_recorded",
|
|
72
72
|
"emit_anomaly_repetitive_tool",
|
|
73
|
+
"emit_cgroup_growth_rate_warning",
|
|
73
74
|
"emit_config_broken",
|
|
74
75
|
"emit_config_migrated",
|
|
75
76
|
"emit_crash_loop",
|
|
@@ -79,7 +80,6 @@ __all__ = [
|
|
|
79
80
|
"emit_mem_loop",
|
|
80
81
|
"emit_mem_loop_persistent",
|
|
81
82
|
"emit_mem_pressure_deferred_to_cgroup",
|
|
82
|
-
"emit_phase_window_overlap",
|
|
83
83
|
"emit_rate_limit_stop",
|
|
84
84
|
"emit_round_cgroup_memory",
|
|
85
85
|
"emit_round_container_orphan_risk",
|
|
@@ -78,10 +78,10 @@ def emit_round_mem_critical_sample(
|
|
|
78
78
|
sample-level signal, distinct from mem_pressure_deferred_to_cgroup's
|
|
79
79
|
once-per-episode terminate-vs-defer notice).
|
|
80
80
|
|
|
81
|
-
The caller caps this at ``2 *
|
|
81
|
+
The caller caps this at ``2 * pressure.critical_consecutive_samples``
|
|
82
82
|
consecutive ticks (1..6 at the default 3) -- a sustained-critical
|
|
83
83
|
don't-terminate run (cgroup-defer, or the off switch) would otherwise
|
|
84
|
-
write one event per ~10s tick for up to a whole ``
|
|
84
|
+
write one event per ~10s tick for up to a whole ``round_budget_s`` on a
|
|
85
85
|
permanently-deferred/off host. The cap is per streak-episode, not a
|
|
86
86
|
lifetime limit: any non-critical tick still resets the streak to 0, and
|
|
87
87
|
sampling resumes from 1 the next time critical pressure recurs."""
|
|
@@ -233,8 +233,38 @@ def emit_mem_pressure_deferred_to_cgroup(
|
|
|
233
233
|
(both memory.max and memory.swap.max finite) -- kernel cgroup-OOM will
|
|
234
234
|
contain the agent and keep the host responsive on its own, so the
|
|
235
235
|
cruder host-wide round-kill steps back instead of firing
|
|
236
|
-
round_mem_terminated. This OVERRIDES
|
|
236
|
+
round_mem_terminated. This OVERRIDES in_round_terminate=True: a
|
|
237
237
|
bounded cgroup makes the host floor strictly worse, not just redundant."""
|
|
238
238
|
from agent_runner.events import MEM_PRESSURE_DEFERRED_TO_CGROUP, emit
|
|
239
239
|
|
|
240
240
|
emit(log_dir, MEM_PRESSURE_DEFERRED_TO_CGROUP, pid=pid, signal=signal, message=message)
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
def emit_cgroup_growth_rate_warning(
|
|
244
|
+
log_dir: Path,
|
|
245
|
+
*,
|
|
246
|
+
round_num: int,
|
|
247
|
+
rate_mb_per_min: float,
|
|
248
|
+
threshold_mb_per_min: float,
|
|
249
|
+
source: str,
|
|
250
|
+
context: dict,
|
|
251
|
+
) -> None:
|
|
252
|
+
"""Emit on a False->True crossing of _spawn_round's mid-round growth-rate
|
|
253
|
+
derivative (host_health.cgroup_growth_rate_pressure) -- observability
|
|
254
|
+
only, no action path. ``source`` names which per-tick reading the
|
|
255
|
+
derivative used: "cgroup" (a finite cgroup memory.max bound exists,
|
|
256
|
+
memory.current is read) or "rss_sum" (no finite bound -- the psutil
|
|
257
|
+
children_rss_sum_bytes tree sum is used instead). Edge-triggered: fires
|
|
258
|
+
once per crossing episode, not once per tick, so a sustained climb does
|
|
259
|
+
not spam the event stream."""
|
|
260
|
+
from agent_runner.events import CGROUP_GROWTH_RATE_WARNING, emit
|
|
261
|
+
|
|
262
|
+
emit(
|
|
263
|
+
log_dir,
|
|
264
|
+
CGROUP_GROWTH_RATE_WARNING,
|
|
265
|
+
round_num=round_num,
|
|
266
|
+
rate_mb_per_min=rate_mb_per_min,
|
|
267
|
+
threshold_mb_per_min=threshold_mb_per_min,
|
|
268
|
+
source=source,
|
|
269
|
+
context=context,
|
|
270
|
+
)
|
|
@@ -169,7 +169,7 @@ def emit_round_grace_extended(
|
|
|
169
169
|
) -> None:
|
|
170
170
|
"""Emit when the grace-after-result timer expired but the agent still had
|
|
171
171
|
live worker processes (e.g. a backgrounded build), so the round was NOT
|
|
172
|
-
killed; it continues until it finishes or hits
|
|
172
|
+
killed; it continues until it finishes or hits round_budget_s.
|
|
173
173
|
|
|
174
174
|
live_children: list of ``{"name": <exe basename>, "pid": <int>}`` dicts
|
|
175
175
|
(previously a list of cmdline strings).
|
|
@@ -191,23 +191,3 @@ def emit_schedule_resumed(log_dir: Path, *, paused_for_s: int) -> None:
|
|
|
191
191
|
from agent_runner.events import SCHEDULE_RESUMED, emit
|
|
192
192
|
|
|
193
193
|
emit(log_dir, SCHEDULE_RESUMED, paused_for_s=paused_for_s)
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
def emit_phase_window_overlap(
|
|
197
|
-
log_dir: Path, *, phase_a: str, phase_b: str, window_a: str, window_b: str
|
|
198
|
-
) -> None:
|
|
199
|
-
"""Emit phase_window_overlap: two agent-overriding phases' own run_windows
|
|
200
|
-
collide (a rotation footgun; a later release promotes this exact detection
|
|
201
|
-
to a hard error). Called once at serve boot -- the collision is a property of the
|
|
202
|
-
static config, not of any one round, so (like emit_max_rounds_reached's
|
|
203
|
-
cgroup-probe sibling) this must not be called from the per-round path."""
|
|
204
|
-
from agent_runner.events import PHASE_WINDOW_OVERLAP, emit
|
|
205
|
-
|
|
206
|
-
emit(
|
|
207
|
-
log_dir,
|
|
208
|
-
PHASE_WINDOW_OVERLAP,
|
|
209
|
-
phase_a=phase_a,
|
|
210
|
-
phase_b=phase_b,
|
|
211
|
-
window_a=window_a,
|
|
212
|
-
window_b=window_b,
|
|
213
|
-
)
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
"""Systemd install / uninstall: ``init``, ``install``, ``uninstall``.
|
|
2
|
+
|
|
3
|
+
Depends one-directionally on ``_lifecycle.py`` for the shared
|
|
4
|
+
``_project_name`` / ``_check_user_systemd_available`` / ``_SYSTEM_UNITS_DIR`` /
|
|
5
|
+
``_system_unit_exists`` / ``_PID_SIGNAL_GRACE_S`` helpers — never the reverse.
|
|
6
|
+
|
|
7
|
+
Re-exported from ``agent_runner.api`` (the thin facade) so external callers
|
|
8
|
+
and existing internal callers keep working unchanged.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import os
|
|
14
|
+
import shutil
|
|
15
|
+
import subprocess # noqa: TID251 — install uses systemctl, subprocess
|
|
16
|
+
import sysconfig
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
|
|
19
|
+
from agent_runner import _resolve, lifecycle
|
|
20
|
+
from agent_runner._lifecycle import (
|
|
21
|
+
_PID_SIGNAL_GRACE_S,
|
|
22
|
+
_SYSTEM_UNITS_DIR,
|
|
23
|
+
_check_user_systemd_available,
|
|
24
|
+
_project_name,
|
|
25
|
+
_system_unit_exists,
|
|
26
|
+
)
|
|
27
|
+
from agent_runner.api_types import InitResult, InstallResult
|
|
28
|
+
from agent_runner.clock import SYSTEM_CLOCK
|
|
29
|
+
from agent_runner.config import Config, load_config
|
|
30
|
+
from agent_runner.lifecycle import _systemctl_user
|
|
31
|
+
from agent_runner.scaffold import scaffold_project
|
|
32
|
+
from agent_runner.service_unit import (
|
|
33
|
+
monitor_unit_filename,
|
|
34
|
+
render_monitor_unit,
|
|
35
|
+
render_serve_unit,
|
|
36
|
+
serve_unit_filename,
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _agent_runner_script_path() -> Path:
|
|
41
|
+
"""Locate the agent-runner CLI script for systemd ExecStart.
|
|
42
|
+
|
|
43
|
+
Tries shutil.which first (honors PATH). Falls back to sysconfig's
|
|
44
|
+
scripts dir (handles cases where PATH excludes the install dir).
|
|
45
|
+
Raises FileNotFoundError if neither resolves to an existing file.
|
|
46
|
+
"""
|
|
47
|
+
which = shutil.which("agent-runner")
|
|
48
|
+
if which:
|
|
49
|
+
return Path(which)
|
|
50
|
+
scripts_dir = Path(sysconfig.get_path("scripts"))
|
|
51
|
+
candidate = scripts_dir / "agent-runner"
|
|
52
|
+
if candidate.exists():
|
|
53
|
+
return candidate
|
|
54
|
+
raise FileNotFoundError(
|
|
55
|
+
"agent-runner script not found in PATH or "
|
|
56
|
+
f"{scripts_dir}; reinstall via pip or activate the right venv"
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def init(
|
|
61
|
+
work_dir: Path | None = None,
|
|
62
|
+
*,
|
|
63
|
+
preset: str = "claude",
|
|
64
|
+
force: bool = False,
|
|
65
|
+
commit: bool = True,
|
|
66
|
+
) -> InitResult:
|
|
67
|
+
if work_dir is None:
|
|
68
|
+
work_dir = Path.cwd()
|
|
69
|
+
return scaffold_project(work_dir, preset=preset, force=force, commit=commit)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def _install_system(
|
|
73
|
+
cfg: Config, project: str, *, config_path: Path, with_monitor: bool
|
|
74
|
+
) -> InstallResult:
|
|
75
|
+
if os.geteuid() != 0:
|
|
76
|
+
raise RuntimeError(
|
|
77
|
+
"--system requires sudo; run via `sudo -E agent-runner install --system`"
|
|
78
|
+
)
|
|
79
|
+
sudo_user = os.environ.get("SUDO_USER")
|
|
80
|
+
if not sudo_user:
|
|
81
|
+
raise RuntimeError(
|
|
82
|
+
"--system needs SUDO_USER env var; run via "
|
|
83
|
+
"`sudo -E agent-runner install --system` to preserve env"
|
|
84
|
+
)
|
|
85
|
+
script_path = _agent_runner_script_path()
|
|
86
|
+
serve_path = _SYSTEM_UNITS_DIR / serve_unit_filename(project)
|
|
87
|
+
serve_path.write_text(
|
|
88
|
+
render_serve_unit(cfg, script_path=script_path, config_path=config_path, user=sudo_user)
|
|
89
|
+
)
|
|
90
|
+
monitor_path: Path | None = None
|
|
91
|
+
if with_monitor:
|
|
92
|
+
monitor_path = _SYSTEM_UNITS_DIR / monitor_unit_filename(project)
|
|
93
|
+
monitor_path.write_text(
|
|
94
|
+
render_monitor_unit(
|
|
95
|
+
cfg, script_path=script_path, config_path=config_path, user=sudo_user
|
|
96
|
+
)
|
|
97
|
+
)
|
|
98
|
+
subprocess.run(["systemctl", "daemon-reload"], check=True)
|
|
99
|
+
subprocess.run(["systemctl", "enable", serve_unit_filename(project)], check=True)
|
|
100
|
+
if with_monitor:
|
|
101
|
+
subprocess.run(["systemctl", "enable", monitor_unit_filename(project)], check=True)
|
|
102
|
+
return InstallResult(
|
|
103
|
+
unit_path=serve_path,
|
|
104
|
+
monitor_unit_path=monitor_path,
|
|
105
|
+
enabled=True,
|
|
106
|
+
started=False,
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def install(
|
|
111
|
+
work_dir: Path | None = None,
|
|
112
|
+
*,
|
|
113
|
+
system: bool = False,
|
|
114
|
+
with_monitor: bool = False,
|
|
115
|
+
force: bool = False,
|
|
116
|
+
) -> InstallResult:
|
|
117
|
+
if work_dir is None:
|
|
118
|
+
work_dir = Path.cwd()
|
|
119
|
+
cfg_path = work_dir / "agent-runner.toml"
|
|
120
|
+
cfg = load_config(cfg_path)
|
|
121
|
+
project = _project_name(work_dir)
|
|
122
|
+
|
|
123
|
+
units_dir = _SYSTEM_UNITS_DIR if system else lifecycle._user_systemd_dir()
|
|
124
|
+
_resolve.guard_against_clobber(
|
|
125
|
+
units_dir / serve_unit_filename(project), cfg.runtime.work_dir, force=force
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
if system:
|
|
129
|
+
return _install_system(cfg, project, config_path=cfg_path, with_monitor=with_monitor)
|
|
130
|
+
|
|
131
|
+
_check_user_systemd_available()
|
|
132
|
+
script_path = _agent_runner_script_path()
|
|
133
|
+
|
|
134
|
+
units_dir.mkdir(parents=True, exist_ok=True)
|
|
135
|
+
|
|
136
|
+
serve_path = units_dir / serve_unit_filename(project)
|
|
137
|
+
serve_path.write_text(render_serve_unit(cfg, script_path=script_path, config_path=cfg_path))
|
|
138
|
+
|
|
139
|
+
monitor_path: Path | None = None
|
|
140
|
+
if with_monitor:
|
|
141
|
+
monitor_path = units_dir / monitor_unit_filename(project)
|
|
142
|
+
monitor_path.write_text(
|
|
143
|
+
render_monitor_unit(cfg, script_path=script_path, config_path=cfg_path)
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
_systemctl_user("daemon-reload")
|
|
147
|
+
_systemctl_user("enable", serve_unit_filename(project))
|
|
148
|
+
_systemctl_user("start", serve_unit_filename(project))
|
|
149
|
+
if with_monitor:
|
|
150
|
+
_systemctl_user("enable", monitor_unit_filename(project))
|
|
151
|
+
_systemctl_user("start", monitor_unit_filename(project))
|
|
152
|
+
|
|
153
|
+
return InstallResult(
|
|
154
|
+
unit_path=serve_path, monitor_unit_path=monitor_path, enabled=True, started=True
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def uninstall(work_dir: Path | None = None) -> bool:
|
|
159
|
+
if work_dir is None:
|
|
160
|
+
work_dir = Path.cwd()
|
|
161
|
+
project = _project_name(work_dir)
|
|
162
|
+
if _system_unit_exists(project): # root-owned -- don't silently no-op the user-scope dir
|
|
163
|
+
units = [serve_unit_filename(project)]
|
|
164
|
+
if (_SYSTEM_UNITS_DIR / monitor_unit_filename(project)).exists():
|
|
165
|
+
units.append(monitor_unit_filename(project))
|
|
166
|
+
remedy = " && ".join(
|
|
167
|
+
f"sudo systemctl disable --now {u} && sudo rm {_SYSTEM_UNITS_DIR / u}" for u in units
|
|
168
|
+
)
|
|
169
|
+
print(f"{project} is managed by a system unit; run: {remedy}")
|
|
170
|
+
return False
|
|
171
|
+
units_dir = lifecycle._user_systemd_dir()
|
|
172
|
+
serve = units_dir / serve_unit_filename(project)
|
|
173
|
+
monitor = units_dir / monitor_unit_filename(project)
|
|
174
|
+
for p in (serve, monitor):
|
|
175
|
+
if p.exists():
|
|
176
|
+
# Drain-aware (see stop_unit_draining, the same primitive api.stop/
|
|
177
|
+
# api.restart use): a blocking `systemctl stop` would TimeoutExpired
|
|
178
|
+
# while serve drains its round -- queue it and confirm within a
|
|
179
|
+
# bounded window instead, same as stop(), before disabling/unlinking.
|
|
180
|
+
lifecycle.stop_unit_draining(p.name, clock=SYSTEM_CLOCK, confirm_s=_PID_SIGNAL_GRACE_S)
|
|
181
|
+
_systemctl_user("disable", p.name)
|
|
182
|
+
p.unlink(missing_ok=True)
|
|
183
|
+
try:
|
|
184
|
+
_systemctl_user("daemon-reload")
|
|
185
|
+
except (subprocess.CalledProcessError, FileNotFoundError):
|
|
186
|
+
pass # no user bus on this host -- units above (if any) already gone
|
|
187
|
+
return True
|