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.
Files changed (139) hide show
  1. cli_agent_runner-0.1.6/CHANGELOG.md +235 -0
  2. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/PKG-INFO +2 -8
  3. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/README.md +1 -7
  4. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/README.zh.md +1 -6
  5. cli_agent_runner-0.1.6/agent_runner/__init__.py +54 -0
  6. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/agent_runner/_docgen.py +2 -0
  7. cli_agent_runner-0.1.6/agent_runner/_registry.py +23 -0
  8. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/agent_runner/_version.py +2 -2
  9. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/agent_runner/api.py +12 -4
  10. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/agent_runner/api_types.py +53 -4
  11. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/agent_runner/cli/common.py +19 -1
  12. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/agent_runner/cli/install_cmd.py +1 -1
  13. cli_agent_runner-0.1.6/agent_runner/config.py +144 -0
  14. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/agent_runner/defenses.py +2 -2
  15. cli_agent_runner-0.1.6/agent_runner/detector_helpers.py +115 -0
  16. cli_agent_runner-0.1.6/agent_runner/events.py +130 -0
  17. cli_agent_runner-0.1.6/agent_runner/hooks.py +143 -0
  18. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/agent_runner/monitor.py +107 -39
  19. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/agent_runner/prompt_loader.py +3 -2
  20. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/agent_runner/runner.py +98 -18
  21. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/agent_runner/scaffold.py +3 -5
  22. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/agent_runner/startup_check.py +4 -1
  23. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/docs/architecture.md +18 -23
  24. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/docs/commands.md +1 -1
  25. cli_agent_runner-0.1.6/docs/configuration.md +103 -0
  26. cli_agent_runner-0.1.6/docs/plugins.md +311 -0
  27. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/docs/quickstart.md +29 -6
  28. cli_agent_runner-0.1.6/tests/integration/test_context_enricher_namespacing.py +57 -0
  29. cli_agent_runner-0.1.6/tests/integration/test_plugin_detector_loaded.py +105 -0
  30. 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
  31. cli_agent_runner-0.1.6/tests/invariants/test_event_kind_registry.py +74 -0
  32. 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
  33. cli_agent_runner-0.1.6/tests/invariants/test_peek_schema_version.py +78 -0
  34. cli_agent_runner-0.1.6/tests/invariants/test_round_result_stable.py +75 -0
  35. cli_agent_runner-0.1.6/tests/unit/test_auto_stop_gating.py +91 -0
  36. cli_agent_runner-0.1.6/tests/unit/test_config.py +331 -0
  37. cli_agent_runner-0.1.6/tests/unit/test_detector_helpers.py +141 -0
  38. cli_agent_runner-0.1.6/tests/unit/test_detector_protocol.py +69 -0
  39. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/unit/test_docgen.py +1 -1
  40. cli_agent_runner-0.1.6/tests/unit/test_events.py +150 -0
  41. cli_agent_runner-0.1.6/tests/unit/test_hook_failure_isolation.py +77 -0
  42. cli_agent_runner-0.1.6/tests/unit/test_hooks.py +139 -0
  43. cli_agent_runner-0.1.6/tests/unit/test_init_entry_points.py +107 -0
  44. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/unit/test_monitor_detectors.py +55 -0
  45. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/unit/test_prompt_loader.py +66 -0
  46. cli_agent_runner-0.1.1/CHANGELOG.md +0 -62
  47. cli_agent_runner-0.1.1/agent_runner/__init__.py +0 -3
  48. cli_agent_runner-0.1.1/agent_runner/config.py +0 -92
  49. cli_agent_runner-0.1.1/agent_runner/critic.py +0 -33
  50. cli_agent_runner-0.1.1/agent_runner/events.py +0 -53
  51. cli_agent_runner-0.1.1/docs/configuration.md +0 -78
  52. cli_agent_runner-0.1.1/tests/invariants/test_event_kind_registry.py +0 -39
  53. cli_agent_runner-0.1.1/tests/unit/test_config.py +0 -115
  54. cli_agent_runner-0.1.1/tests/unit/test_critic.py +0 -27
  55. cli_agent_runner-0.1.1/tests/unit/test_events.py +0 -79
  56. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/.codecov.yml +0 -0
  57. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  58. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  59. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  60. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  61. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/.github/workflows/ci.yml +0 -0
  62. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/.github/workflows/release.yml +0 -0
  63. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/.gitignore +0 -0
  64. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/.vulture-whitelist.py +0 -0
  65. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/CODE_OF_CONDUCT.md +0 -0
  66. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/CONTRIBUTING.md +0 -0
  67. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/LICENSE +0 -0
  68. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/SECURITY.md +0 -0
  69. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/agent_runner/agent_runtime.py +0 -0
  70. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/agent_runner/cli/__init__.py +0 -0
  71. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/agent_runner/cli/__main__.py +0 -0
  72. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/agent_runner/cli/init_cmd.py +0 -0
  73. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/agent_runner/cli/monitor_cmd.py +0 -0
  74. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/agent_runner/cli/peek_cmd.py +0 -0
  75. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/agent_runner/cli/round_cmd.py +0 -0
  76. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/agent_runner/cli/serve_cmd.py +0 -0
  77. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/agent_runner/cli/service_cmd.py +0 -0
  78. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/agent_runner/context_store.py +0 -0
  79. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/agent_runner/lifecycle.py +0 -0
  80. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/agent_runner/metrics.py +0 -0
  81. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/agent_runner/round_view.py +0 -0
  82. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/agent_runner/service_unit.py +0 -0
  83. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/agent_runner/vcs_state.py +0 -0
  84. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/build.sh +0 -0
  85. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/deploy/example-agent-runner.toml +0 -0
  86. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/deploy/launchd.plist.tmpl +0 -0
  87. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/deploy/run-loop.sh +0 -0
  88. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/deploy/systemd.service.tmpl +0 -0
  89. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/docs/README.md +0 -0
  90. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/docs/runbook.md +0 -0
  91. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/pyproject.toml +0 -0
  92. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/__init__.py +0 -0
  93. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/conftest.py +0 -0
  94. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/e2e/__init__.py +0 -0
  95. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/e2e/conftest.py +0 -0
  96. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/e2e/test_e2e_graceful_stop.py +0 -0
  97. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/e2e/test_e2e_install_systemd.py +0 -0
  98. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/e2e/test_e2e_monitor_remote.py +0 -0
  99. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/e2e/test_e2e_round_lifecycle.py +0 -0
  100. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/integration/__init__.py +0 -0
  101. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/integration/test_install_dry_run.py +0 -0
  102. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/integration/test_monitor_seeded.py +0 -0
  103. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/integration/test_run_loop_backoff.py +0 -0
  104. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/integration/test_run_one_round_with_fake_agent.py +0 -0
  105. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/integration/test_serve_loop.py +0 -0
  106. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/invariants/__init__.py +0 -0
  107. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/invariants/test_atomic_write_enforced.py +0 -0
  108. /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
  109. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/invariants/test_docs_generated.py +0 -0
  110. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/invariants/test_module_boundaries.py +0 -0
  111. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/invariants/test_no_pytest_skip_on_parse_fail.py +0 -0
  112. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/invariants/test_repo_constants_patched_in_tests.py +0 -0
  113. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/invariants/test_stash_uses_sha_not_index.py +0 -0
  114. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/literate/__init__.py +0 -0
  115. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/literate/parser.py +0 -0
  116. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/literate/test_parser.py +0 -0
  117. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/literate/test_quickstart.py +0 -0
  118. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/unit/__init__.py +0 -0
  119. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/unit/test_agent_runtime.py +0 -0
  120. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/unit/test_api_observation.py +0 -0
  121. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/unit/test_api_service.py +0 -0
  122. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/unit/test_api_types.py +0 -0
  123. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/unit/test_cli.py +0 -0
  124. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/unit/test_cli_common.py +0 -0
  125. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/unit/test_cli_init_install.py +0 -0
  126. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/unit/test_cli_service_peek_monitor.py +0 -0
  127. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/unit/test_context_store.py +0 -0
  128. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/unit/test_defenses.py +0 -0
  129. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/unit/test_lifecycle.py +0 -0
  130. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/unit/test_metrics.py +0 -0
  131. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/unit/test_monitor_assembly.py +0 -0
  132. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/unit/test_monitor_remote.py +0 -0
  133. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/unit/test_peek_argparse.py +0 -0
  134. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/unit/test_round_view.py +0 -0
  135. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/unit/test_runner.py +0 -0
  136. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/unit/test_scaffold.py +0 -0
  137. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/unit/test_service_unit.py +0 -0
  138. {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.6}/tests/unit/test_startup_check.py +0 -0
  139. {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.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
- [![CI](https://github.com/wan9yu/cli-agent-runner/actions/workflows/ci.yml/badge.svg)](https://github.com/wan9yu/cli-agent-runner/actions/workflows/ci.yml) [![PyPI](https://img.shields.io/pypi/v/cli-agent-runner.svg)](https://pypi.org/project/cli-agent-runner/) [![Python](https://img.shields.io/pypi/pyversions/cli-agent-runner.svg)](https://pypi.org/project/cli-agent-runner/) [![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![codecov](https://codecov.io/gh/wan9yu/cli-agent-runner/branch/main/graph/badge.svg)](https://codecov.io/gh/wan9yu/cli-agent-runner) [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
40
+ [![CI](https://github.com/wan9yu/cli-agent-runner/actions/workflows/ci.yml/badge.svg)](https://github.com/wan9yu/cli-agent-runner/actions/workflows/ci.yml) [![PyPI](https://img.shields.io/pypi/v/cli-agent-runner.svg)](https://pypi.org/project/cli-agent-runner/) [![Downloads](https://img.shields.io/pypi/dm/cli-agent-runner.svg)](https://pypi.org/project/cli-agent-runner/) [![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![codecov](https://codecov.io/gh/wan9yu/cli-agent-runner/branch/main/graph/badge.svg)](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
- [![CI](https://github.com/wan9yu/cli-agent-runner/actions/workflows/ci.yml/badge.svg)](https://github.com/wan9yu/cli-agent-runner/actions/workflows/ci.yml) [![PyPI](https://img.shields.io/pypi/v/cli-agent-runner.svg)](https://pypi.org/project/cli-agent-runner/) [![Python](https://img.shields.io/pypi/pyversions/cli-agent-runner.svg)](https://pypi.org/project/cli-agent-runner/) [![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![codecov](https://codecov.io/gh/wan9yu/cli-agent-runner/branch/main/graph/badge.svg)](https://codecov.io/gh/wan9yu/cli-agent-runner) [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
3
+ [![CI](https://github.com/wan9yu/cli-agent-runner/actions/workflows/ci.yml/badge.svg)](https://github.com/wan9yu/cli-agent-runner/actions/workflows/ci.yml) [![PyPI](https://img.shields.io/pypi/v/cli-agent-runner.svg)](https://pypi.org/project/cli-agent-runner/) [![Downloads](https://img.shields.io/pypi/dm/cli-agent-runner.svg)](https://pypi.org/project/cli-agent-runner/) [![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![codecov](https://codecov.io/gh/wan9yu/cli-agent-runner/branch/main/graph/badge.svg)](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
- [![CI](https://github.com/wan9yu/cli-agent-runner/actions/workflows/ci.yml/badge.svg)](https://github.com/wan9yu/cli-agent-runner/actions/workflows/ci.yml) [![PyPI](https://img.shields.io/pypi/v/cli-agent-runner.svg)](https://pypi.org/project/cli-agent-runner/) [![Python](https://img.shields.io/pypi/pyversions/cli-agent-runner.svg)](https://pypi.org/project/cli-agent-runner/) [![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![codecov](https://codecov.io/gh/wan9yu/cli-agent-runner/branch/main/graph/badge.svg)](https://codecov.io/gh/wan9yu/cli-agent-runner) [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
3
+ [![CI](https://github.com/wan9yu/cli-agent-runner/actions/workflows/ci.yml/badge.svg)](https://github.com/wan9yu/cli-agent-runner/actions/workflows/ci.yml) [![PyPI](https://img.shields.io/pypi/v/cli-agent-runner.svg)](https://pypi.org/project/cli-agent-runner/) [![Downloads](https://img.shields.io/pypi/dm/cli-agent-runner.svg)](https://pypi.org/project/cli-agent-runner/) [![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![codecov](https://codecov.io/gh/wan9yu/cli-agent-runner/branch/main/graph/badge.svg)](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.1'
22
- __version_tuple__ = version_tuple = (0, 1, 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
- agents (Phase 3 outer Claude Code) can `from agent_runner import api`
6
- and skip CLI text parsing entirely.
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 in Phase 2")
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
- return monitor.run_all_detectors(
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. Phase 3 LLM/Critic will read these structures.
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: str
79
+ severity: Severity
72
80
  detector: str
73
81
  message: str
74
82
  context: dict[str, Any]
75
83
  ts: str
76
- auto_action: str = "none"
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
- print(json.dumps(_to_jsonable(value), indent=2, default=str))
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
 
@@ -13,7 +13,7 @@ def add_parser(sub, parent) -> None:
13
13
  p.add_argument(
14
14
  "--system",
15
15
  action="store_true",
16
- help="Install at system level (not yet supported in Phase 2)",
16
+ help="Install at system level (not yet supported)",
17
17
  )
18
18
  p.add_argument(
19
19
  "--monitor",