cli-agent-runner 0.1.1__tar.gz → 0.1.6__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.1.6/CHANGELOG.md +235 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/PKG-INFO +2 -8
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/README.md +1 -7
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/README.zh.md +1 -6
- cli_agent_runner-0.1.6/agent_runner/__init__.py +54 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/agent_runner/_docgen.py +2 -0
- cli_agent_runner-0.1.6/agent_runner/_registry.py +23 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/agent_runner/_version.py +2 -2
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/agent_runner/api.py +12 -4
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/agent_runner/api_types.py +53 -4
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/agent_runner/cli/common.py +19 -1
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/agent_runner/cli/install_cmd.py +1 -1
- cli_agent_runner-0.1.6/agent_runner/config.py +144 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/agent_runner/defenses.py +2 -2
- cli_agent_runner-0.1.6/agent_runner/detector_helpers.py +115 -0
- cli_agent_runner-0.1.6/agent_runner/events.py +130 -0
- cli_agent_runner-0.1.6/agent_runner/hooks.py +143 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/agent_runner/monitor.py +107 -39
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/agent_runner/prompt_loader.py +3 -2
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/agent_runner/runner.py +98 -18
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/agent_runner/scaffold.py +3 -5
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/agent_runner/startup_check.py +4 -1
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/docs/architecture.md +18 -23
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/docs/commands.md +1 -1
- cli_agent_runner-0.1.6/docs/configuration.md +103 -0
- cli_agent_runner-0.1.6/docs/plugins.md +311 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/docs/quickstart.md +29 -6
- cli_agent_runner-0.1.6/tests/integration/test_context_enricher_namespacing.py +57 -0
- cli_agent_runner-0.1.6/tests/integration/test_plugin_detector_loaded.py +105 -0
- cli_agent_runner-0.1.1/tests/invariants/test_phase2_architecture.py → cli_agent_runner-0.1.6/tests/invariants/test_architecture.py +2 -19
- cli_agent_runner-0.1.6/tests/invariants/test_event_kind_registry.py +74 -0
- cli_agent_runner-0.1.1/tests/invariants/test_phase2_module_sizes.py → cli_agent_runner-0.1.6/tests/invariants/test_module_sizes.py +7 -10
- cli_agent_runner-0.1.6/tests/invariants/test_peek_schema_version.py +78 -0
- cli_agent_runner-0.1.6/tests/invariants/test_round_result_stable.py +75 -0
- cli_agent_runner-0.1.6/tests/unit/test_auto_stop_gating.py +91 -0
- cli_agent_runner-0.1.6/tests/unit/test_config.py +331 -0
- cli_agent_runner-0.1.6/tests/unit/test_detector_helpers.py +141 -0
- cli_agent_runner-0.1.6/tests/unit/test_detector_protocol.py +69 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/unit/test_docgen.py +1 -1
- cli_agent_runner-0.1.6/tests/unit/test_events.py +150 -0
- cli_agent_runner-0.1.6/tests/unit/test_hook_failure_isolation.py +77 -0
- cli_agent_runner-0.1.6/tests/unit/test_hooks.py +139 -0
- cli_agent_runner-0.1.6/tests/unit/test_init_entry_points.py +107 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/unit/test_monitor_detectors.py +55 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/unit/test_prompt_loader.py +66 -0
- cli_agent_runner-0.1.1/CHANGELOG.md +0 -62
- cli_agent_runner-0.1.1/agent_runner/__init__.py +0 -3
- cli_agent_runner-0.1.1/agent_runner/config.py +0 -92
- cli_agent_runner-0.1.1/agent_runner/critic.py +0 -33
- cli_agent_runner-0.1.1/agent_runner/events.py +0 -53
- cli_agent_runner-0.1.1/docs/configuration.md +0 -78
- cli_agent_runner-0.1.1/tests/invariants/test_event_kind_registry.py +0 -39
- cli_agent_runner-0.1.1/tests/unit/test_config.py +0 -115
- cli_agent_runner-0.1.1/tests/unit/test_critic.py +0 -27
- cli_agent_runner-0.1.1/tests/unit/test_events.py +0 -79
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/.codecov.yml +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/.github/workflows/ci.yml +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/.github/workflows/release.yml +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/.gitignore +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/.vulture-whitelist.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/CODE_OF_CONDUCT.md +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/CONTRIBUTING.md +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/LICENSE +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/SECURITY.md +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/agent_runner/agent_runtime.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/agent_runner/cli/__init__.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/agent_runner/cli/__main__.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/agent_runner/cli/init_cmd.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/agent_runner/cli/monitor_cmd.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/agent_runner/cli/peek_cmd.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/agent_runner/cli/round_cmd.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/agent_runner/cli/serve_cmd.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/agent_runner/cli/service_cmd.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/agent_runner/context_store.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/agent_runner/lifecycle.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/agent_runner/metrics.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/agent_runner/round_view.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/agent_runner/service_unit.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/agent_runner/vcs_state.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/build.sh +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/deploy/example-agent-runner.toml +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/deploy/launchd.plist.tmpl +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/deploy/run-loop.sh +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/deploy/systemd.service.tmpl +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/docs/README.md +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/docs/runbook.md +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/pyproject.toml +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/__init__.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/conftest.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/e2e/__init__.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/e2e/conftest.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/e2e/test_e2e_graceful_stop.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/e2e/test_e2e_install_systemd.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/e2e/test_e2e_monitor_remote.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/e2e/test_e2e_round_lifecycle.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/integration/__init__.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/integration/test_install_dry_run.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/integration/test_monitor_seeded.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/integration/test_run_loop_backoff.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/integration/test_run_one_round_with_fake_agent.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/integration/test_serve_loop.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/invariants/__init__.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/invariants/test_atomic_write_enforced.py +0 -0
- /cli_agent_runner-0.1.1/tests/invariants/test_phase2_catalogs.py → /cli_agent_runner-0.1.6/tests/invariants/test_catalogs.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/invariants/test_docs_generated.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/invariants/test_module_boundaries.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/invariants/test_no_pytest_skip_on_parse_fail.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/invariants/test_repo_constants_patched_in_tests.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/invariants/test_stash_uses_sha_not_index.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/literate/__init__.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/literate/parser.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/literate/test_parser.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/literate/test_quickstart.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/unit/__init__.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/unit/test_agent_runtime.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/unit/test_api_observation.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/unit/test_api_service.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/unit/test_api_types.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/unit/test_cli.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/unit/test_cli_common.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/unit/test_cli_init_install.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/unit/test_cli_service_peek_monitor.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/unit/test_context_store.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/unit/test_defenses.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/unit/test_lifecycle.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/unit/test_metrics.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/unit/test_monitor_assembly.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/unit/test_monitor_remote.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/unit/test_peek_argparse.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/unit/test_round_view.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/unit/test_runner.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/unit/test_scaffold.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/unit/test_service_unit.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/unit/test_startup_check.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/unit/test_vcs_state.py +0 -0
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [0.1.6] - 2026-05-12
|
|
11
|
+
|
|
12
|
+
Zero-feature maintenance release — internal cleanup pass after the 0.1.x plugin
|
|
13
|
+
extension surface completed in 0.1.5. No runtime behavior change for users
|
|
14
|
+
without plugins; plugin authors written against 0.1.5 keep working unchanged.
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
- Public `Alert.severity` / `Alert.auto_action` and `Detector.severity` /
|
|
18
|
+
`Detector.auto_action` are now typed with `Severity = Literal["info", "warning",
|
|
19
|
+
"critical"]` and `AutoAction = Literal["none", "stop_service"]` aliases
|
|
20
|
+
exported from `agent_runner.api_types`. Plain-string values continue to work
|
|
21
|
+
- `__version__` is read from the hatch-vcs generated `_version.py` instead of a
|
|
22
|
+
hardcoded constant; released packages report the actual release version
|
|
23
|
+
- Internal duplication reduced: shared `agent_runner._registry.ensure_unique`
|
|
24
|
+
for hooks + detectors registries; `cli/common.emit()` plugin-namespace imports
|
|
25
|
+
hoisted to module top; `events.parse_iso_ms` centralizes the ISO-8601 trailing-`Z`
|
|
26
|
+
parsing workaround; `MonitorConfig.auto_stop_on` default now references the
|
|
27
|
+
`_DEFAULT_AUTO_STOP_ON` constant
|
|
28
|
+
- `monitor.dual_source_silence` is now TOCTOU-safe (uses `try/except
|
|
29
|
+
FileNotFoundError` instead of `exists()` + `stat()`)
|
|
30
|
+
- `api._poll_once` short-circuits when no plugin detectors are registered,
|
|
31
|
+
skipping `assemble_project_state` (saves a file read per local poll and an
|
|
32
|
+
SSH round-trip per remote poll)
|
|
33
|
+
- `agent_runner/__init__.py` plugin loaders share a single
|
|
34
|
+
`_load_plugins_from_group` helper
|
|
35
|
+
- `monitor._alert` no longer asserts builtin detector names against
|
|
36
|
+
`KNOWN_ALERT_KINDS` (assertion was redundant and would crash under
|
|
37
|
+
`python -O`); test + docgen layers continue to validate the builtin name set
|
|
38
|
+
|
|
39
|
+
### Removed
|
|
40
|
+
- `agent_runner.critic` — empty Protocol stub for an unimplemented Critic
|
|
41
|
+
concept that was retired during the framework-first redesign
|
|
42
|
+
- `[llm]` commented block from the scaffold TOML template and its corresponding
|
|
43
|
+
section in `docs/configuration.md` — unused placeholder
|
|
44
|
+
- Legacy phase nomenclature from source docstrings, error messages, and CLI
|
|
45
|
+
help text; `tests/invariants/test_phase2_*.py` files renamed to drop the
|
|
46
|
+
`phase2_` prefix
|
|
47
|
+
|
|
48
|
+
### Backward compatibility
|
|
49
|
+
- Existing `agent-runner.toml` files continue to load (the removed `[llm]`
|
|
50
|
+
block was never parsed by the supervisor)
|
|
51
|
+
- Plugin code written for 0.1.5 continues to work — Protocol contracts and
|
|
52
|
+
`peek --json` schema 1.3 unchanged
|
|
53
|
+
|
|
54
|
+
## [0.1.5] - 2026-05-12
|
|
55
|
+
|
|
56
|
+
### Added
|
|
57
|
+
- `agent_runner.api_types.Detector` — public Protocol for plugin detectors
|
|
58
|
+
(attributes `name`, `severity`, `auto_action`; method `detect(state) -> Alert | None`).
|
|
59
|
+
`@runtime_checkable` — plugin classes structurally satisfying the shape are accepted
|
|
60
|
+
- `agent_runner.monitor.register_detector(detector)` and `plugin_detectors()` — public
|
|
61
|
+
registration API + sorted list of currently-registered detector names
|
|
62
|
+
- `agent_runner.monitor.run_plugin_detectors(state)` — invokes each registered plugin
|
|
63
|
+
detector with the assembled `ProjectState`; per-detector exceptions surface as
|
|
64
|
+
`UserWarning` (round continues)
|
|
65
|
+
- `agent_runner` package now also discovers and loads entry_points in group
|
|
66
|
+
`agent_runner.detectors` at first import; failures degrade to `UserWarning`
|
|
67
|
+
- `agent_runner.detector_helpers` module — three production-tested helpers for
|
|
68
|
+
plugin detector authors:
|
|
69
|
+
- `cumulative_window_check(events, *, kind, window_s, min_count)` —
|
|
70
|
+
sliding-window event counter; robust against wall-clock skew at boundaries
|
|
71
|
+
- `dual_source_silence(scheduler_log, round_log, threshold_s)` — both-source
|
|
72
|
+
silence check; avoids false positives during long rounds when only the
|
|
73
|
+
scheduler log is stale
|
|
74
|
+
- `phase_filter(state, *, exclude_phases)` — skip detection during phases
|
|
75
|
+
that intentionally produce no commits (e.g., retrospective rounds)
|
|
76
|
+
- `MonitorConfig.auto_stop_on: list[str]` — explicit allow-list of detector
|
|
77
|
+
names whose `stop_service` action is honored. Defaults to
|
|
78
|
+
`["oauth_fail", "disk_critical"]` (builtin pair); operators must add plugin
|
|
79
|
+
detector names to opt them into auto-stop
|
|
80
|
+
- `monitor.on_alert` gains `allowed_stop_names: list[str] | None` keyword
|
|
81
|
+
argument; backward-compatible default falls back to the legacy builtin pair
|
|
82
|
+
- `peek --json` schema bumped to `"1.3"`; new `plugins.detectors: list[str]`
|
|
83
|
+
surfaces what's registered
|
|
84
|
+
- `docs/plugins.md` gains a Detector Protocol chapter + DetectorHelpers
|
|
85
|
+
chapter with worked examples for each helper
|
|
86
|
+
|
|
87
|
+
### Changed
|
|
88
|
+
- `agent_runner.api._poll_once` now concatenates builtin detector alerts
|
|
89
|
+
with plugin detector alerts (`run_plugin_detectors(state)`) before returning
|
|
90
|
+
- `agent_runner.api.monitor_loop` threads `cfg.monitor.auto_stop_on` into
|
|
91
|
+
`monitor.on_alert` for strict gating
|
|
92
|
+
- `tests/invariants/test_peek_schema_version.py` tightened to require
|
|
93
|
+
`schema_version >= "1.3"` and the `plugins.detectors` list shape
|
|
94
|
+
|
|
95
|
+
### Backward compatibility
|
|
96
|
+
- Zero plugins installed → monitor behavior identical to 0.1.4
|
|
97
|
+
- Existing 9 builtin detectors keep their current signatures unchanged
|
|
98
|
+
- Existing `agent-runner.toml` files load without modification; default
|
|
99
|
+
`auto_stop_on` matches the previously-implicit behavior
|
|
100
|
+
- `on_alert(...)` callers without the new kwarg continue to work via the
|
|
101
|
+
default `["oauth_fail", "disk_critical"]` allow-list
|
|
102
|
+
|
|
103
|
+
## [0.1.4] - 2026-05-12
|
|
104
|
+
|
|
105
|
+
### Added
|
|
106
|
+
- `agent_runner.hooks` module — three Protocol-typed plugin extension points:
|
|
107
|
+
`PreRoundHook` (runs after lock acquire, before context write),
|
|
108
|
+
`ContextEnricher` (returns a per-plugin slice stitched into `round-context.json`
|
|
109
|
+
under `base_context[enricher.name]`), and `PostRoundHook` (runs after agent exit,
|
|
110
|
+
before `round_end` event)
|
|
111
|
+
- `agent_runner.hooks.HookContext` — narrow runtime context passed to all hooks
|
|
112
|
+
(`work_dir`, `log_dir`, `project`, `round_num`, `phase`, `agent_name`); does NOT
|
|
113
|
+
expose the full `Config` so internal refactors remain safe
|
|
114
|
+
- `agent_runner.hooks.register_pre_round_hook` / `register_context_enricher` /
|
|
115
|
+
`register_post_round_hook` — public registration API; rejects duplicate `name`
|
|
116
|
+
- `agent_runner.hooks.plugin_context_enrichers()` — sorted list of registered
|
|
117
|
+
enricher names, surfaced via `peek --json`
|
|
118
|
+
- `agent_runner.api_types.RoundResult` — promoted from `runner.py`; superset of
|
|
119
|
+
the prior internal fields plus `phase`, `started_at`, `ended_at`, `log_path` for
|
|
120
|
+
stable `PostRoundHook` consumption
|
|
121
|
+
- `agent_runner` package now also discovers and loads three new entry_points groups
|
|
122
|
+
at first import: `agent_runner.pre_round_hooks`, `agent_runner.context_enrichers`,
|
|
123
|
+
`agent_runner.post_round_hooks`; plugin failures degrade to a `UserWarning`
|
|
124
|
+
- Built-in event kind `hook_failed` — emitted by the runner whenever a plugin hook
|
|
125
|
+
raises; payload includes `{hook_name, hook_kind, error_type, error_message, traceback}`
|
|
126
|
+
with traceback truncated to 2KB (head 1KB + tail 1KB joined by `[truncated]`)
|
|
127
|
+
- `peek --json` schema bumped to `"1.2"`; new `plugins.context_enrichers: list[str]`
|
|
128
|
+
- `docs/plugins.md` — new chapter with end-to-end ContextEnricher example
|
|
129
|
+
- New invariant `tests/invariants/test_round_result_stable.py` guards `RoundResult`
|
|
130
|
+
field set + types across future minors
|
|
131
|
+
|
|
132
|
+
### Changed
|
|
133
|
+
- `agent_runner.runner.run_one_round` integrates hooks at three checkpoints; each
|
|
134
|
+
call is wrapped in `try/except` and surfaces failures via `hook_failed`
|
|
135
|
+
- `tests/invariants/test_peek_schema_version.py` tightened to require
|
|
136
|
+
`schema_version >= "1.2"` and the `plugins.context_enrichers` list shape
|
|
137
|
+
|
|
138
|
+
### Backward compatibility
|
|
139
|
+
- Zero plugins installed → runner behavior identical to 0.1.3
|
|
140
|
+
- `RoundResult` field set is a superset; every prior field is preserved
|
|
141
|
+
- Existing 0.1.x user `agent-runner.toml` files load without modification
|
|
142
|
+
|
|
143
|
+
## [0.1.3] - 2026-05-12
|
|
144
|
+
|
|
145
|
+
### Added
|
|
146
|
+
- `agent_runner.events.register_event_kind(name, *, source)` — public API for plugins to register custom event kinds
|
|
147
|
+
- `agent_runner.events.plugin_event_kinds()` — sorted list of currently-registered plugin event kind names
|
|
148
|
+
- `agent_runner` package now discovers and loads entry_points in group `agent_runner.event_kinds` at first import; plugin failures degrade to a `UserWarning` instead of crashing the supervisor
|
|
149
|
+
- `peek --json` schema bumped to `"1.1"`; new top-level `plugins.event_kinds: list[str]` surfaces what's registered
|
|
150
|
+
- `docs/plugins.md` — plugin authoring stub covering the entry_points convention and the event-kind example
|
|
151
|
+
|
|
152
|
+
### Changed
|
|
153
|
+
- `agent_runner.events.KNOWN_EVENT_KINDS` is now a read-only union view (built-in + plugin) instead of a `frozenset`; `in` and iteration semantics preserved
|
|
154
|
+
- `tests/invariants/test_event_kind_registry.py` rewritten to validate the built-in/plugin split and the registration conflict rules
|
|
155
|
+
- `tests/invariants/test_peek_schema_version.py` tightened to require `schema_version >= "1.1"` and the `plugins.event_kinds` list shape
|
|
156
|
+
|
|
157
|
+
### Backward compatibility
|
|
158
|
+
- Every existing `from agent_runner.events import KNOWN_EVENT_KINDS` import continues to work
|
|
159
|
+
- Every existing `events.emit(...)` callsite continues to work with the same kind strings
|
|
160
|
+
- Existing 0.1.x user `agent-runner.toml` files load without modification
|
|
161
|
+
|
|
162
|
+
## [0.1.2] - 2026-05-12
|
|
163
|
+
|
|
164
|
+
### Added
|
|
165
|
+
- `cfg.agent.name` — optional provider identifier; defaults to `None` (consumers may fall back to `command[0]`)
|
|
166
|
+
- `cfg.prompt.context_injection_mode` — `prepend` (default) / `file` / `none`; controls how round-context reaches the agent
|
|
167
|
+
- `cfg.monitor.auth_fail_patterns` and `cfg.monitor.auth_fail_hint` — generalize the OAuth-fail detector for any provider
|
|
168
|
+
- `cfg.plugins` — placeholder for 0.1.3+ plugin enable/disable; parsed-but-unused in 0.1.2
|
|
169
|
+
- `peek --json` now emits top-level `schema_version: "1.0"` and `plugins: {}` namespace
|
|
170
|
+
|
|
171
|
+
### Changed
|
|
172
|
+
- `startup_check` prompt-smoke error text reframed away from provider-specific wording
|
|
173
|
+
- `scaffold.py` generated TOML annotates `[agent]` block as the reference; encourages swapping for other CLIs
|
|
174
|
+
- Public docs (architecture, quickstart, configuration) reframed: the reference agent is one of many supported CLIs
|
|
175
|
+
- `monitor.detect_oauth_fail` now reads patterns + hint from `cfg.monitor` (SSOT migrated from a hardcoded module constant to `MonitorConfig`)
|
|
176
|
+
|
|
177
|
+
### Backward compatibility
|
|
178
|
+
- All defaults preserve the existing prepend-mode behavior
|
|
179
|
+
- Existing `agent-runner.toml` files continue to load without modification
|
|
180
|
+
- Existing tests pass without modification
|
|
181
|
+
|
|
182
|
+
## [0.1.1] — 2026-05-12
|
|
183
|
+
|
|
184
|
+
Post-release polish: PyPI install path is documented as the primary entry,
|
|
185
|
+
the repository was renamed for naming parity with the distribution, and the
|
|
186
|
+
release workflow now auto-creates GitHub Releases.
|
|
187
|
+
|
|
188
|
+
### Changed
|
|
189
|
+
- README + README.zh now show `pip install cli-agent-runner` as the primary
|
|
190
|
+
install path; the previous `git clone` flow moved to the Development section.
|
|
191
|
+
- Repository renamed from `wan9yu/agent-runner` to `wan9yu/cli-agent-runner`
|
|
192
|
+
for parity with the PyPI distribution name. All in-tree URL references
|
|
193
|
+
updated; GitHub redirects keep old links working.
|
|
194
|
+
|
|
195
|
+
### Build & CI
|
|
196
|
+
- Release workflow now creates a GitHub Release after PyPI publish, attaches
|
|
197
|
+
the sdist + wheel as release artifacts, and pulls release notes from the
|
|
198
|
+
matching CHANGELOG section.
|
|
199
|
+
|
|
200
|
+
## [0.1.0] — 2026-05-12
|
|
201
|
+
|
|
202
|
+
Initial public release on PyPI as `cli-agent-runner`.
|
|
203
|
+
|
|
204
|
+
### Added
|
|
205
|
+
- Three-layer model: Round / Loop / Witness.
|
|
206
|
+
- 13 CLI verbs: `init`, `install`, `uninstall`, `start`, `stop`, `kill`,
|
|
207
|
+
`cancel`, `restart`, `status`, `round`, `serve`, `peek`, `watch`, `monitor`.
|
|
208
|
+
- 11 named defenses (round timeout, process group isolation, orphan stash
|
|
209
|
+
with SHA lock, set-diff classification, smoke check, flock concurrency,
|
|
210
|
+
atomic state writes, event kind registry, and others).
|
|
211
|
+
- 9 monitor detectors (`timeout_rate`, `hung`, `orphan_chain`,
|
|
212
|
+
`disk_warning`, `disk_critical`, `mem_pressure`, `smoke_fail_rate`,
|
|
213
|
+
`oauth_fail`, `network_fail`); `oauth_fail` and `disk_critical` auto-stop
|
|
214
|
+
the service.
|
|
215
|
+
- Local-only and remote (via ssh) monitor modes.
|
|
216
|
+
- Auto-generated docs (`./build.sh docs`) for defenses table, detectors,
|
|
217
|
+
events, config schema, CLI verbs.
|
|
218
|
+
- Literate quickstart: `docs/quickstart.md` is executed as a pytest test.
|
|
219
|
+
- Python public API (`from agent_runner import api`) mirroring CLI verbs.
|
|
220
|
+
- Phase 3 reservation: `[llm]` config section + `agent_runner.critic`
|
|
221
|
+
Protocol stubs (no implementation).
|
|
222
|
+
|
|
223
|
+
### Documentation
|
|
224
|
+
- English README + full Chinese `README.zh.md`.
|
|
225
|
+
- 5 user-facing docs: quickstart, commands, configuration, runbook, architecture.
|
|
226
|
+
|
|
227
|
+
### Build & CI
|
|
228
|
+
- GitHub Actions matrix: Python 3.11/3.12/3.13 × ubuntu / macos.
|
|
229
|
+
- Codecov-uploaded coverage from one canonical matrix cell.
|
|
230
|
+
- Tag-triggered release publishing to PyPI via Trusted Publishing OIDC,
|
|
231
|
+
gated by a manual approval on the `pypi` GitHub environment.
|
|
232
|
+
|
|
233
|
+
[Unreleased]: https://github.com/wan9yu/cli-agent-runner/compare/v0.1.1...HEAD
|
|
234
|
+
[0.1.1]: https://github.com/wan9yu/cli-agent-runner/releases/tag/v0.1.1
|
|
235
|
+
[0.1.0]: https://github.com/wan9yu/cli-agent-runner/releases/tag/v0.1.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cli-agent-runner
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.6
|
|
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
|
|
@@ -37,7 +37,7 @@ Description-Content-Type: text/markdown
|
|
|
37
37
|
|
|
38
38
|
> **[中文](README.zh.md)** · English
|
|
39
39
|
|
|
40
|
-
[](https://github.com/wan9yu/cli-agent-runner/actions/workflows/ci.yml) [](https://pypi.org/project/cli-agent-runner/) [](https://github.com/wan9yu/cli-agent-runner/actions/workflows/ci.yml) [](https://pypi.org/project/cli-agent-runner/) [](https://pypi.org/project/cli-agent-runner/) [](https://opensource.org/licenses/Apache-2.0) [](https://codecov.io/gh/wan9yu/cli-agent-runner)
|
|
41
41
|
|
|
42
42
|
# agent-runner
|
|
43
43
|
|
|
@@ -130,12 +130,6 @@ agent-runner monitor --json | jq -c # pipe to downstream consumers
|
|
|
130
130
|
- [`docs/runbook.md`](docs/runbook.md) — operator troubleshooting (OAuth, disk, orphan)
|
|
131
131
|
- [`docs/architecture.md`](docs/architecture.md) — 3-layer model, defenses-as-data
|
|
132
132
|
|
|
133
|
-
## Status
|
|
134
|
-
|
|
135
|
-
Phase 2 (operator surface) shipped. Phase 3 (LLM-augmented Critic) reserved —
|
|
136
|
-
`[llm]` config block and `agent_runner.critic` Protocol stubs are in place,
|
|
137
|
-
implementation TBD.
|
|
138
|
-
|
|
139
133
|
## Development
|
|
140
134
|
|
|
141
135
|
```bash
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
> **[中文](README.zh.md)** · English
|
|
2
2
|
|
|
3
|
-
[](https://github.com/wan9yu/cli-agent-runner/actions/workflows/ci.yml) [](https://pypi.org/project/cli-agent-runner/) [](https://github.com/wan9yu/cli-agent-runner/actions/workflows/ci.yml) [](https://pypi.org/project/cli-agent-runner/) [](https://pypi.org/project/cli-agent-runner/) [](https://opensource.org/licenses/Apache-2.0) [](https://codecov.io/gh/wan9yu/cli-agent-runner)
|
|
4
4
|
|
|
5
5
|
# agent-runner
|
|
6
6
|
|
|
@@ -93,12 +93,6 @@ agent-runner monitor --json | jq -c # pipe to downstream consumers
|
|
|
93
93
|
- [`docs/runbook.md`](docs/runbook.md) — operator troubleshooting (OAuth, disk, orphan)
|
|
94
94
|
- [`docs/architecture.md`](docs/architecture.md) — 3-layer model, defenses-as-data
|
|
95
95
|
|
|
96
|
-
## Status
|
|
97
|
-
|
|
98
|
-
Phase 2 (operator surface) shipped. Phase 3 (LLM-augmented Critic) reserved —
|
|
99
|
-
`[llm]` config block and `agent_runner.critic` Protocol stubs are in place,
|
|
100
|
-
implementation TBD.
|
|
101
|
-
|
|
102
96
|
## Development
|
|
103
97
|
|
|
104
98
|
```bash
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
> 中文 · **[English](README.md)**
|
|
2
2
|
|
|
3
|
-
[](https://github.com/wan9yu/cli-agent-runner/actions/workflows/ci.yml) [](https://pypi.org/project/cli-agent-runner/) [](https://github.com/wan9yu/cli-agent-runner/actions/workflows/ci.yml) [](https://pypi.org/project/cli-agent-runner/) [](https://pypi.org/project/cli-agent-runner/) [](https://opensource.org/licenses/Apache-2.0) [](https://codecov.io/gh/wan9yu/cli-agent-runner)
|
|
4
4
|
|
|
5
5
|
# agent-runner
|
|
6
6
|
|
|
@@ -151,11 +151,6 @@ pip install -e ".[dev]"
|
|
|
151
151
|
|
|
152
152
|
只支持 POSIX(Linux / macOS)。Python 3.11+。x86_64 与 aarch64 都跑过。
|
|
153
153
|
|
|
154
|
-
## 项目状态
|
|
155
|
-
|
|
156
|
-
Phase 2(运维界面)已发。Phase 3(LLM Critic)留了接口:`[llm]` 配置段 +
|
|
157
|
-
`agent_runner.critic` Protocol stubs,实现待定。
|
|
158
|
-
|
|
159
154
|
## License
|
|
160
155
|
|
|
161
156
|
[Apache License 2.0](LICENSE).
|
|
@@ -0,0 +1,54 @@
|
|
|
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
|
+
_HOOK_GROUPS = (
|
|
11
|
+
"agent_runner.pre_round_hooks",
|
|
12
|
+
"agent_runner.context_enrichers",
|
|
13
|
+
"agent_runner.post_round_hooks",
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _load_plugins_from_group(group: str) -> None:
|
|
18
|
+
"""Discover and load entry_points in ``group``, isolating per-plugin failures.
|
|
19
|
+
|
|
20
|
+
Called at package import. A broken plugin must not crash the supervisor;
|
|
21
|
+
each failure surfaces as a ``UserWarning``.
|
|
22
|
+
"""
|
|
23
|
+
import warnings
|
|
24
|
+
from importlib.metadata import entry_points
|
|
25
|
+
|
|
26
|
+
for ep in entry_points(group=group):
|
|
27
|
+
try:
|
|
28
|
+
ep.load()
|
|
29
|
+
except Exception as e:
|
|
30
|
+
warnings.warn(
|
|
31
|
+
f"failed to load {group} plugin {ep.name!r}: {e}",
|
|
32
|
+
stacklevel=3,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _load_event_kind_plugins() -> None:
|
|
37
|
+
"""Load plugins that register custom event kinds via ``events.register_event_kind``."""
|
|
38
|
+
_load_plugins_from_group("agent_runner.event_kinds")
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _load_hook_plugins() -> None:
|
|
42
|
+
"""Load plugins that register pre_round / context_enricher / post_round hooks."""
|
|
43
|
+
for group in _HOOK_GROUPS:
|
|
44
|
+
_load_plugins_from_group(group)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _load_detector_plugins() -> None:
|
|
48
|
+
"""Load plugins that register custom monitor detectors via ``monitor.register_detector``."""
|
|
49
|
+
_load_plugins_from_group("agent_runner.detectors")
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
_load_event_kind_plugins()
|
|
53
|
+
_load_hook_plugins()
|
|
54
|
+
_load_detector_plugins()
|
|
@@ -16,6 +16,7 @@ from pathlib import Path
|
|
|
16
16
|
from agent_runner.config import (
|
|
17
17
|
AgentConfig,
|
|
18
18
|
Config,
|
|
19
|
+
MonitorConfig,
|
|
19
20
|
PromptConfig,
|
|
20
21
|
RuntimeConfig,
|
|
21
22
|
VcsConfig,
|
|
@@ -29,6 +30,7 @@ _SECTIONS = [
|
|
|
29
30
|
("runtime", RuntimeConfig),
|
|
30
31
|
("prompt", PromptConfig),
|
|
31
32
|
("vcs", VcsConfig),
|
|
33
|
+
("monitor", MonitorConfig),
|
|
32
34
|
]
|
|
33
35
|
|
|
34
36
|
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""Shared registry helpers for plugin-extension surfaces.
|
|
2
|
+
|
|
3
|
+
The `name`-keyed unique-registration check is identical across hooks
|
|
4
|
+
(:mod:`agent_runner.hooks`) and detectors (:mod:`agent_runner.monitor`).
|
|
5
|
+
This module is its single source of truth.
|
|
6
|
+
|
|
7
|
+
Event-kind registration in :mod:`agent_runner.events` has DIFFERENT
|
|
8
|
+
semantics (idempotent for same-source re-registration, conflict on
|
|
9
|
+
different-source) and stays in that module.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def ensure_unique(name: str, existing: list, kind: str) -> None:
|
|
16
|
+
"""Raise ValueError if any item in ``existing`` already has ``.name == name``.
|
|
17
|
+
|
|
18
|
+
``kind`` is a short label embedded in the error message (e.g. ``"detector"``,
|
|
19
|
+
``"context_enricher"``).
|
|
20
|
+
"""
|
|
21
|
+
for item in existing:
|
|
22
|
+
if getattr(item, "name", None) == name:
|
|
23
|
+
raise ValueError(f"{kind} {name!r} already registered; refusing to add a second")
|
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '0.1.
|
|
22
|
-
__version_tuple__ = version_tuple = (0, 1,
|
|
21
|
+
__version__ = version = '0.1.6'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 1, 6)
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
Every CLI subcommand has a corresponding api function. CLI files do
|
|
4
4
|
``api.X(...)`` and format the returned dataclass for display. External
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
callers can ``from agent_runner import api`` and skip CLI text parsing
|
|
6
|
+
entirely.
|
|
7
7
|
"""
|
|
8
8
|
|
|
9
9
|
from __future__ import annotations
|
|
@@ -83,7 +83,7 @@ def install(
|
|
|
83
83
|
if work_dir is None:
|
|
84
84
|
work_dir = Path.cwd()
|
|
85
85
|
if system:
|
|
86
|
-
raise NotImplementedError("--system install not yet implemented
|
|
86
|
+
raise NotImplementedError("--system install not yet implemented")
|
|
87
87
|
cfg_path = work_dir / "agent-runner.toml"
|
|
88
88
|
cfg = load_config(cfg_path)
|
|
89
89
|
project = _project_name(work_dir)
|
|
@@ -295,12 +295,19 @@ def _poll_once(project: str | Path, *, host: str | None) -> list[monitor.Alert]:
|
|
|
295
295
|
events = monitor.parse_events_from_jsonl_files(src.events_files())
|
|
296
296
|
metrics = monitor.parse_events_from_jsonl_files(src.metrics_files())
|
|
297
297
|
log_tails = monitor.load_round_log_tails(src.rounds_dir())
|
|
298
|
-
|
|
298
|
+
builtin = monitor.run_all_detectors(
|
|
299
299
|
events=events,
|
|
300
300
|
metrics=metrics,
|
|
301
301
|
log_tails=log_tails,
|
|
302
302
|
round_timeout_s=cfg.runtime.round_timeout_s,
|
|
303
|
+
auth_fail_patterns=cfg.monitor.auth_fail_patterns,
|
|
304
|
+
auth_fail_hint=cfg.monitor.auth_fail_hint,
|
|
303
305
|
)
|
|
306
|
+
if not monitor._PLUGIN_DETECTORS:
|
|
307
|
+
return builtin # skip ProjectState assembly when no plugins to feed
|
|
308
|
+
state = monitor.assemble_project_state(src, project=_project_name(work_dir))
|
|
309
|
+
plugin = monitor.run_plugin_detectors(state)
|
|
310
|
+
return builtin + plugin
|
|
304
311
|
|
|
305
312
|
|
|
306
313
|
def monitor_loop(
|
|
@@ -327,5 +334,6 @@ def monitor_loop(
|
|
|
327
334
|
project=_project_name(work_dir),
|
|
328
335
|
host=host,
|
|
329
336
|
log_dir=cfg.runtime.log_dir,
|
|
337
|
+
allowed_stop_names=cfg.monitor.auto_stop_on,
|
|
330
338
|
)
|
|
331
339
|
time.sleep(interval_s)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""Dataclasses for the Python API state tree.
|
|
2
2
|
|
|
3
3
|
These are the public types that ``agent_runner.api`` returns and that
|
|
4
|
-
``cli/`` formats.
|
|
4
|
+
``cli/`` formats. Plugins (hooks, context enrichers, detectors) consume them.
|
|
5
5
|
|
|
6
6
|
All frozen — state is immutable, no in-place mutation.
|
|
7
7
|
"""
|
|
@@ -11,7 +11,15 @@ from __future__ import annotations
|
|
|
11
11
|
from dataclasses import dataclass, field
|
|
12
12
|
from enum import StrEnum
|
|
13
13
|
from pathlib import Path
|
|
14
|
-
from typing import Any
|
|
14
|
+
from typing import Any, Literal, Protocol, runtime_checkable
|
|
15
|
+
|
|
16
|
+
Severity = Literal["info", "warning", "critical"]
|
|
17
|
+
"""Alert / Detector severity level. ``critical`` is the only level that may
|
|
18
|
+
trigger ``auto_action="stop_service"``."""
|
|
19
|
+
|
|
20
|
+
AutoAction = Literal["none", "stop_service"]
|
|
21
|
+
"""What the monitor does when this Alert fires. ``stop_service`` only takes
|
|
22
|
+
effect if the detector's ``name`` is in ``cfg.monitor.auto_stop_on``."""
|
|
15
23
|
|
|
16
24
|
|
|
17
25
|
class ServiceMode(StrEnum):
|
|
@@ -68,12 +76,53 @@ class ProjectState:
|
|
|
68
76
|
|
|
69
77
|
@dataclass(frozen=True)
|
|
70
78
|
class Alert:
|
|
71
|
-
severity:
|
|
79
|
+
severity: Severity
|
|
72
80
|
detector: str
|
|
73
81
|
message: str
|
|
74
82
|
context: dict[str, Any]
|
|
75
83
|
ts: str
|
|
76
|
-
auto_action:
|
|
84
|
+
auto_action: AutoAction = "none"
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
@runtime_checkable
|
|
88
|
+
class Detector(Protocol):
|
|
89
|
+
"""Public plugin contract for monitor detectors.
|
|
90
|
+
|
|
91
|
+
Plugins implementing this Protocol can be registered via
|
|
92
|
+
``monitor.register_detector`` (or auto-loaded via entry_points group
|
|
93
|
+
``agent_runner.detectors``) and will be invoked alongside built-in
|
|
94
|
+
detectors during each monitor poll.
|
|
95
|
+
|
|
96
|
+
``auto_action="stop_service"`` is honored only if the plugin's ``name``
|
|
97
|
+
appears in ``cfg.monitor.auto_stop_on`` — operators must explicitly
|
|
98
|
+
opt plugins into the auto-stop policy.
|
|
99
|
+
"""
|
|
100
|
+
|
|
101
|
+
name: str
|
|
102
|
+
severity: Severity
|
|
103
|
+
auto_action: AutoAction
|
|
104
|
+
|
|
105
|
+
def detect(self, state: ProjectState) -> Alert | None: ...
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
@dataclass(frozen=True)
|
|
109
|
+
class RoundResult:
|
|
110
|
+
"""Result of one ``run_one_round`` call.
|
|
111
|
+
|
|
112
|
+
Stable across 0.1.x for PostRoundHook consumers. Fields may be ADDED in
|
|
113
|
+
a minor; removed or retyped only on a major bump.
|
|
114
|
+
"""
|
|
115
|
+
|
|
116
|
+
round_num: int
|
|
117
|
+
phase: str | None
|
|
118
|
+
started_at: str
|
|
119
|
+
ended_at: str
|
|
120
|
+
exit_code: int
|
|
121
|
+
duration_s: float
|
|
122
|
+
timed_out: bool
|
|
123
|
+
log_path: Path
|
|
124
|
+
dirty_files: list[str]
|
|
125
|
+
stashed: bool
|
|
77
126
|
|
|
78
127
|
|
|
79
128
|
@dataclass(frozen=True)
|
|
@@ -9,7 +9,13 @@ from enum import Enum
|
|
|
9
9
|
from pathlib import Path
|
|
10
10
|
from typing import Any
|
|
11
11
|
|
|
12
|
+
from agent_runner.api_types import ProjectState
|
|
12
13
|
from agent_runner.config import Config, load_config
|
|
14
|
+
from agent_runner.events import plugin_event_kinds
|
|
15
|
+
from agent_runner.hooks import plugin_context_enrichers
|
|
16
|
+
from agent_runner.monitor import plugin_detectors
|
|
17
|
+
|
|
18
|
+
PEEK_SCHEMA_VERSION = "1.3"
|
|
13
19
|
|
|
14
20
|
|
|
15
21
|
def cfg_from_args(args) -> Config:
|
|
@@ -36,7 +42,19 @@ def work_dir_from_args(args) -> Path:
|
|
|
36
42
|
|
|
37
43
|
def emit(value: Any, *, json_mode: bool) -> None:
|
|
38
44
|
if json_mode:
|
|
39
|
-
|
|
45
|
+
if isinstance(value, ProjectState):
|
|
46
|
+
wrapped = {
|
|
47
|
+
"schema_version": PEEK_SCHEMA_VERSION,
|
|
48
|
+
"plugins": {
|
|
49
|
+
"event_kinds": plugin_event_kinds(),
|
|
50
|
+
"context_enrichers": plugin_context_enrichers(),
|
|
51
|
+
"detectors": plugin_detectors(),
|
|
52
|
+
},
|
|
53
|
+
**_to_jsonable(value),
|
|
54
|
+
}
|
|
55
|
+
print(json.dumps(wrapped, indent=2, default=str))
|
|
56
|
+
else:
|
|
57
|
+
print(json.dumps(_to_jsonable(value), indent=2, default=str))
|
|
40
58
|
else:
|
|
41
59
|
print(_pretty(value))
|
|
42
60
|
|