cli-agent-runner 0.3.9__tar.gz → 0.3.10__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 (396) hide show
  1. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/.vulture-whitelist.py +1 -0
  2. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/CHANGELOG.md +9 -0
  3. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/PKG-INFO +1 -1
  4. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/_emit/__init__.py +2 -0
  5. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/_emit/serve.py +12 -0
  6. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/_plugin_manifest.py +26 -0
  7. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/_version.py +2 -2
  8. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/agent_runtime.py +12 -2
  9. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/api.py +1 -0
  10. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/builtin_plugins/pi.py +4 -1
  11. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/cli/serve_cmd.py +50 -3
  12. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/config/loader.py +26 -0
  13. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/events.py +1 -0
  14. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/runner.py +15 -0
  15. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/docs/architecture.md +1 -0
  16. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/docs/memory-efficiency.md +65 -0
  17. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/docs/migrations/0.3.md +11 -0
  18. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/docs/plugins.md +1 -0
  19. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/contract/test_public_api_surface.py +1 -0
  20. cli_agent_runner-0.3.10/tests/e2e/test_e2e_pi_resume.py +344 -0
  21. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/invariants/test_architecture.py +6 -1
  22. cli_agent_runner-0.3.10/tests/unit/test_apply_resume_env.py +255 -0
  23. cli_agent_runner-0.3.10/tests/unit/test_config_resume_guard.py +44 -0
  24. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_plugin_manifest.py +29 -0
  25. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/.codecov.yml +0 -0
  26. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  27. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  28. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  29. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  30. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/.github/dependabot.yml +0 -0
  31. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/.github/workflows/ci.yml +0 -0
  32. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/.github/workflows/release.yml +0 -0
  33. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/.gitignore +0 -0
  34. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/BACKLOG.md +0 -0
  35. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/CODE_OF_CONDUCT.md +0 -0
  36. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/CONTRIBUTING.md +0 -0
  37. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/LICENSE +0 -0
  38. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/README.md +0 -0
  39. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/README.zh.md +0 -0
  40. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/SECURITY.md +0 -0
  41. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/__init__.py +0 -0
  42. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/_docgen.py +0 -0
  43. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/_emit/agent.py +0 -0
  44. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/_emit/memory.py +0 -0
  45. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/_emit/rounds.py +0 -0
  46. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/_install.py +0 -0
  47. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/_lifecycle.py +0 -0
  48. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/_monitor_detectors.py +0 -0
  49. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/_monitor_registry.py +0 -0
  50. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/_monitor_state.py +0 -0
  51. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/_notify.py +0 -0
  52. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/_observe.py +0 -0
  53. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/_plugin_scan.py +0 -0
  54. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/_procwait.py +0 -0
  55. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/_redact.py +0 -0
  56. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/_registry.py +0 -0
  57. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/_resolve.py +0 -0
  58. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/_round_outcome.py +0 -0
  59. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/_round_support.py +0 -0
  60. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/_serve_policy.py +0 -0
  61. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/_substrate.py +0 -0
  62. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/_throttle.py +0 -0
  63. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/api_types.py +0 -0
  64. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/builtin_plugins/__init__.py +0 -0
  65. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/builtin_plugins/_constants.py +0 -0
  66. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/builtin_plugins/claude_rate_limit.py +0 -0
  67. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/builtin_plugins/codewhale.py +0 -0
  68. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/builtin_plugins/gemini.py +0 -0
  69. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/builtin_plugins/kimi.py +0 -0
  70. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/cli/__init__.py +0 -0
  71. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/cli/__main__.py +0 -0
  72. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/cli/_serve_cgroup.py +0 -0
  73. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/cli/_serve_round.py +0 -0
  74. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/cli/common.py +0 -0
  75. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/cli/doctor_cmd.py +0 -0
  76. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/cli/events_cmd.py +0 -0
  77. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/cli/init_cmd.py +0 -0
  78. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/cli/install_cmd.py +0 -0
  79. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/cli/migrate_cmd.py +0 -0
  80. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/cli/monitor_cmd.py +0 -0
  81. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/cli/peek_cmd.py +0 -0
  82. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/cli/round_cmd.py +0 -0
  83. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/cli/service_cmd.py +0 -0
  84. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/cli/upgrade_cmd.py +0 -0
  85. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/clock.py +0 -0
  86. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/config/__init__.py +0 -0
  87. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/config/errors.py +0 -0
  88. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/config/models.py +0 -0
  89. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/config/parsers.py +0 -0
  90. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/config/validators.py +0 -0
  91. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/context_store.py +0 -0
  92. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/defenses.py +0 -0
  93. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/event_log.py +0 -0
  94. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/hooks.py +0 -0
  95. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/host_health.py +0 -0
  96. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/http_progress.py +0 -0
  97. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/lifecycle.py +0 -0
  98. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/metrics.py +0 -0
  99. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/migrations.py +0 -0
  100. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/monitor.py +0 -0
  101. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/phase_select.py +0 -0
  102. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/presets/__init__.py +0 -0
  103. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/presets/aider.toml +0 -0
  104. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/presets/claude.toml +0 -0
  105. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/presets/codewhale.toml +0 -0
  106. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/presets/gemini.toml +0 -0
  107. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/presets/kimi.toml +0 -0
  108. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/presets/pi.toml +0 -0
  109. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/prompt_loader.py +0 -0
  110. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/remote_relay.py +0 -0
  111. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/round_log.py +0 -0
  112. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/round_view.py +0 -0
  113. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/scaffold.py +0 -0
  114. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/schedule.py +0 -0
  115. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/service_unit.py +0 -0
  116. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/startup_check.py +0 -0
  117. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/agent_runner/vcs_state.py +0 -0
  118. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/build.sh +0 -0
  119. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/deploy/Dockerfile +0 -0
  120. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/deploy/docker-compose.yml +0 -0
  121. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/docs/README.md +0 -0
  122. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/docs/commands.md +0 -0
  123. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/docs/configuration.md +0 -0
  124. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/docs/events.md +0 -0
  125. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/docs/long-running-agents.md +0 -0
  126. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/docs/migrations/0.2.md +0 -0
  127. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/docs/quickstart.md +0 -0
  128. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/docs/recipes/aider.md +0 -0
  129. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/docs/recipes/codewhale.md +0 -0
  130. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/docs/recipes/container-pi.md +0 -0
  131. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/docs/recipes/deploy-all-in-one.md +0 -0
  132. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/docs/recipes/kimi.md +0 -0
  133. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/docs/recipes/pi.md +0 -0
  134. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/docs/runbook.md +0 -0
  135. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/docs/thesis.md +0 -0
  136. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/pyproject.toml +0 -0
  137. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/__init__.py +0 -0
  138. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/_clock.py +0 -0
  139. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/_test_helpers.py +0 -0
  140. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/conftest.py +0 -0
  141. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/contract/__init__.py +0 -0
  142. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/e2e/__init__.py +0 -0
  143. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/e2e/conftest.py +0 -0
  144. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/e2e/test_e2e_graceful_stop.py +0 -0
  145. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/e2e/test_e2e_install_systemd.py +0 -0
  146. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/e2e/test_e2e_monitor_remote.py +0 -0
  147. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/e2e/test_e2e_round_lifecycle.py +0 -0
  148. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/fixtures/cli-real-output/claude-2.1.143-assistant-tool-use.jsonl +0 -0
  149. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/fixtures/cli-real-output/claude-2.1.143-result-event.jsonl +0 -0
  150. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/fixtures/cli-real-output/gemini-0.42.0-result-event.jsonl +0 -0
  151. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/generate_vulture_whitelist.py +0 -0
  152. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/integration/__init__.py +0 -0
  153. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/integration/test_auto_stop_e2e.py +0 -0
  154. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/integration/test_bounded_run.py +0 -0
  155. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/integration/test_cooperative_grace_property.py +0 -0
  156. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/integration/test_cooperative_stop_signal.py +0 -0
  157. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/integration/test_fresh_eyes_signal.py +0 -0
  158. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/integration/test_grace_kill_emission.py +0 -0
  159. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/integration/test_install_dry_run.py +0 -0
  160. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/integration/test_monitor_seeded.py +0 -0
  161. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/integration/test_plugin_real_flow.py +0 -0
  162. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/integration/test_prompt_delivery_stdin.py +0 -0
  163. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/integration/test_reap_property.py +0 -0
  164. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/integration/test_run_one_round_with_fake_agent.py +0 -0
  165. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/integration/test_scaffold_presets.py +0 -0
  166. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/integration/test_serve_loop.py +0 -0
  167. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/integration/test_spawn_round_mem_floor.py +0 -0
  168. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/integration/test_spawn_round_wedged.py +0 -0
  169. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/integration/test_substrate_fingerprint.py +0 -0
  170. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/integration/test_transient_error_backoff.py +0 -0
  171. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/invariants/__init__.py +0 -0
  172. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/invariants/_docs.py +0 -0
  173. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/invariants/_event_scan.py +0 -0
  174. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/invariants/test_atomic_write_enforced.py +0 -0
  175. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/invariants/test_authored_facts_declared.py +0 -0
  176. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/invariants/test_auto_stop_policy_ssot.py +0 -0
  177. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/invariants/test_bdd_test_conventions.py +0 -0
  178. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/invariants/test_brake_defaults_off.py +0 -0
  179. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/invariants/test_catalogs.py +0 -0
  180. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/invariants/test_classification_ssot.py +0 -0
  181. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/invariants/test_config_error_consistency.py +0 -0
  182. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/invariants/test_config_value_set_ssot.py +0 -0
  183. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/invariants/test_container_stop_bound.py +0 -0
  184. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/invariants/test_dataclass_fields_have_producers.py +0 -0
  185. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/invariants/test_doc_builtin_plugins.py +0 -0
  186. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/invariants/test_doc_claims_match_ssot.py +0 -0
  187. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/invariants/test_doc_cli_claims.py +0 -0
  188. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/invariants/test_doc_operator_surface.py +0 -0
  189. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/invariants/test_doc_test_pointers_exist.py +0 -0
  190. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/invariants/test_doc_transient_error_claims.py +0 -0
  191. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/invariants/test_doc_usage_event_fields.py +0 -0
  192. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/invariants/test_docs_generated.py +0 -0
  193. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/invariants/test_docs_index_complete.py +0 -0
  194. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/invariants/test_entry_points_resolve.py +0 -0
  195. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/invariants/test_event_int_coercion.py +0 -0
  196. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/invariants/test_event_kind_registry.py +0 -0
  197. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/invariants/test_event_kinds_ssot.py +0 -0
  198. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/invariants/test_events_doc_contract.py +0 -0
  199. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/invariants/test_gen_blocks_name_their_source.py +0 -0
  200. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/invariants/test_hard_wall_signal.py +0 -0
  201. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/invariants/test_hook_contract_docs.py +0 -0
  202. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/invariants/test_import_footprint.py +0 -0
  203. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/invariants/test_layer_2_loop_size.py +0 -0
  204. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/invariants/test_migrations_registry_ssot.py +0 -0
  205. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/invariants/test_module_boundaries.py +0 -0
  206. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/invariants/test_module_sizes.py +0 -0
  207. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/invariants/test_monitor_self_exclusion.py +0 -0
  208. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/invariants/test_no_ai_signatures.py +0 -0
  209. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/invariants/test_no_asyncio_select.py +0 -0
  210. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/invariants/test_no_direct_inspect_import.py +0 -0
  211. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/invariants/test_no_internal_refs.py +0 -0
  212. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/invariants/test_no_price_logic.py +0 -0
  213. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/invariants/test_no_pytest_skip_on_parse_fail.py +0 -0
  214. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/invariants/test_no_raw_time.py +0 -0
  215. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/invariants/test_no_vacuous_invariants.py +0 -0
  216. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/invariants/test_no_version_refs.py +0 -0
  217. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/invariants/test_peek_schema_version.py +0 -0
  218. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/invariants/test_phase_select_stateless.py +0 -0
  219. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/invariants/test_plugins_config_stable.py +0 -0
  220. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/invariants/test_procwait_shield.py +0 -0
  221. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/invariants/test_readme_zh_is_pointer.py +0 -0
  222. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/invariants/test_repo_constants_patched_in_tests.py +0 -0
  223. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/invariants/test_round_alloc_growth.py +0 -0
  224. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/invariants/test_round_log_decode_boundary.py +0 -0
  225. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/invariants/test_round_num_single_source.py +0 -0
  226. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/invariants/test_round_result_stable.py +0 -0
  227. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/invariants/test_set_diff_for_auto_tool_classification.py +0 -0
  228. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/invariants/test_stash_uses_sha_not_index.py +0 -0
  229. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/invariants/test_throttle_stateless_imports.py +0 -0
  230. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/invariants/test_timeout_budget_invariant.py +0 -0
  231. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/invariants/test_upstream_schema_canary.py +0 -0
  232. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/invariants/test_vulture_whitelist_generated.py +0 -0
  233. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/linux/__init__.py +0 -0
  234. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/linux/test_memory_high_nudge_e2e.py +0 -0
  235. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/literate/__init__.py +0 -0
  236. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/literate/parser.py +0 -0
  237. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/literate/test_parser.py +0 -0
  238. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/literate/test_quickstart.py +0 -0
  239. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/__init__.py +0 -0
  240. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_agent_runtime.py +0 -0
  241. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_agent_runtime_container.py +0 -0
  242. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_agent_runtime_grace.py +0 -0
  243. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_agent_runtime_marker_scan.py +0 -0
  244. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_agent_runtime_progress.py +0 -0
  245. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_agent_runtime_reap.py +0 -0
  246. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_agent_runtime_signal_name.py +0 -0
  247. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_api_assemble_prompt.py +0 -0
  248. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_api_events_stream.py +0 -0
  249. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_api_install.py +0 -0
  250. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_api_observation.py +0 -0
  251. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_api_read_round_num.py +0 -0
  252. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_api_resolve_phase.py +0 -0
  253. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_api_service.py +0 -0
  254. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_api_types.py +0 -0
  255. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_apply_reap_grace_env.py +0 -0
  256. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_auto_stop_gating.py +0 -0
  257. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_catalogs.py +0 -0
  258. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_cgroup_probe.py +0 -0
  259. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_claude_error_detector.py +0 -0
  260. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_claude_foreign_schema.py +0 -0
  261. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_cli.py +0 -0
  262. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_cli_common.py +0 -0
  263. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_cli_init_install.py +0 -0
  264. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_cli_main_boundary.py +0 -0
  265. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_cli_monitor_http.py +0 -0
  266. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_cli_service_peek_monitor.py +0 -0
  267. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_cli_upgrade.py +0 -0
  268. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_codewhale_code_precedence.py +0 -0
  269. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_codewhale_plugin.py +0 -0
  270. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_coerce_int_poison.py +0 -0
  271. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_config.py +0 -0
  272. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_config_fresh_eyes.py +0 -0
  273. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_config_max_rounds.py +0 -0
  274. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_config_nested_strictness.py +0 -0
  275. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_config_prompt_delivery.py +0 -0
  276. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_config_schedule.py +0 -0
  277. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_config_stop_file.py +0 -0
  278. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_config_strictness.py +0 -0
  279. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_config_substrate_fingerprint_paths.py +0 -0
  280. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_config_transient_error_action.py +0 -0
  281. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_context_store.py +0 -0
  282. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_control_char_config.py +0 -0
  283. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_cooperative_signal_env.py +0 -0
  284. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_defenses.py +0 -0
  285. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_detect_hung_latch.py +0 -0
  286. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_detector_isolation.py +0 -0
  287. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_docgen.py +0 -0
  288. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_doctor_cmd.py +0 -0
  289. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_effective_throttle_view.py +0 -0
  290. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_emit_config_migrated.py +0 -0
  291. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_emit_schedule.py +0 -0
  292. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_emit_schedule_phase_skipped.py +0 -0
  293. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_event_log.py +0 -0
  294. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_events.py +0 -0
  295. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_events_cmd.py +0 -0
  296. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_events_cmd_rollover.py +0 -0
  297. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_events_cmd_tail.py +0 -0
  298. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_events_jsonl_decode.py +0 -0
  299. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_example_plugin.py +0 -0
  300. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_exec_prefix.py +0 -0
  301. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_exit_cause.py +0 -0
  302. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_exit_classifier.py +0 -0
  303. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_fresh_eyes_trigger.py +0 -0
  304. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_gemini_plugin.py +0 -0
  305. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_git_timeout.py +0 -0
  306. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_hook_redact_order.py +0 -0
  307. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_hooks.py +0 -0
  308. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_host_health.py +0 -0
  309. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_http_progress.py +0 -0
  310. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_http_progress_epoch.py +0 -0
  311. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_init_entry_points.py +0 -0
  312. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_interruptible_sleep_should_stop.py +0 -0
  313. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_kill_pgroup_shielding.py +0 -0
  314. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_kimi_plugin.py +0 -0
  315. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_lifecycle.py +0 -0
  316. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_loader_split.py +0 -0
  317. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_metrics.py +0 -0
  318. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_metrics_cgroup_usage.py +0 -0
  319. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_metrics_swap.py +0 -0
  320. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_migrate_cmd.py +0 -0
  321. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_migrations.py +0 -0
  322. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_monitor_assembly.py +0 -0
  323. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_monitor_cmd_severity.py +0 -0
  324. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_monitor_dedup_identity.py +0 -0
  325. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_monitor_dedup_rearm.py +0 -0
  326. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_monitor_detect_anomaly_repetitive.py +0 -0
  327. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_monitor_detect_rate_limit.py +0 -0
  328. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_monitor_detect_supervisor_stale.py +0 -0
  329. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_monitor_detectors.py +0 -0
  330. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_monitor_event_tail.py +0 -0
  331. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_monitor_loop.py +0 -0
  332. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_monitor_on_alert.py +0 -0
  333. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_monitor_remote.py +0 -0
  334. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_monitor_round_deferred_stale.py +0 -0
  335. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_monitor_schedule_pause.py +0 -0
  336. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_network_blip_signal_guard.py +0 -0
  337. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_notify.py +0 -0
  338. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_open_round_log.py +0 -0
  339. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_orphan_chain_single_pass.py +0 -0
  340. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_outer_round_ceiling.py +0 -0
  341. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_peek_argparse.py +0 -0
  342. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_peek_project_isolation.py +0 -0
  343. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_peek_schedule.py +0 -0
  344. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_peek_select.py +0 -0
  345. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_phase_agent_launch.py +0 -0
  346. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_phase_profiles.py +0 -0
  347. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_phase_select.py +0 -0
  348. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_pi_plugin.py +0 -0
  349. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_plugin_constants.py +0 -0
  350. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_plugin_scan_parity.py +0 -0
  351. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_plugins_config_fields.py +0 -0
  352. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_presets.py +0 -0
  353. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_procwait.py +0 -0
  354. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_prompt_loader.py +0 -0
  355. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_read_json_hardening.py +0 -0
  356. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_redact.py +0 -0
  357. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_resolve.py +0 -0
  358. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_resolve_dirty_tree.py +0 -0
  359. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_round_cmd.py +0 -0
  360. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_round_cmd_sigterm.py +0 -0
  361. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_round_log_helpers.py +0 -0
  362. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_round_outcome.py +0 -0
  363. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_round_outcome_agent_axis.py +0 -0
  364. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_round_view.py +0 -0
  365. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_runner.py +0 -0
  366. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_runner_sidecar_ordering.py +0 -0
  367. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_runner_throttle.py +0 -0
  368. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_scaffold.py +0 -0
  369. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_schedule.py +0 -0
  370. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_serve_cmd_bounded.py +0 -0
  371. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_serve_config_broken.py +0 -0
  372. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_serve_crash_loop.py +0 -0
  373. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_serve_mem_gate.py +0 -0
  374. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_serve_phase_schedule.py +0 -0
  375. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_serve_policy.py +0 -0
  376. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_serve_round.py +0 -0
  377. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_serve_round_cgroup_spine.py +0 -0
  378. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_serve_round_log.py +0 -0
  379. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_serve_round_oom_killed.py +0 -0
  380. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_serve_round_terminate.py +0 -0
  381. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_serve_round_wait_exit.py +0 -0
  382. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_serve_schedule_gate.py +0 -0
  383. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_serve_sentinel.py +0 -0
  384. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_serve_wakeup.py +0 -0
  385. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_service_mode.py +0 -0
  386. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_service_unit.py +0 -0
  387. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_startup_battery_exit.py +0 -0
  388. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_startup_check.py +0 -0
  389. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_substrate.py +0 -0
  390. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_supervisor_stale_self_blind.py +0 -0
  391. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_terminate_round_wait_exit.py +0 -0
  392. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_throttle_back_off_ladder.py +0 -0
  393. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_throttle_epoch_bound.py +0 -0
  394. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_throttle_plugin_classification.py +0 -0
  395. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_upgrade_migrate.py +0 -0
  396. {cli_agent_runner-0.3.9 → cli_agent_runner-0.3.10}/tests/unit/test_vcs_state.py +0 -0
@@ -17,6 +17,7 @@ buffer
17
17
  name
18
18
  post_round_hooks
19
19
  cooperative_stop
20
+ resume_flag
20
21
 
21
22
  # agent_runner._round_outcome.RoundOutcome
22
23
  mem_terminated
@@ -5,6 +5,15 @@ 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.10] - 2026-09-17
9
+
10
+ ### Added
11
+ - Cross-round resume for `pi`: `PluginManifest.resume_flag` (pi = `--session-id`) lets a preset declare an idempotent session flag; `serve` mints one session id per phase and publishes it via `AGENT_RUNNER_RESUME_FLAG`/`AGENT_RUNNER_RESUME_SESSION_ID`, and the round child appends `[flag, id]` to its command. claude/gemini/codewhale/kimi are untouched (`resume_flag` stays `None`) — later release.
12
+ - A new `session_resumed` event records when a round reuses a prior session id.
13
+ - Boot guard: a preset whose static command already contains its `resume_flag` token now fails config load (agent-runner injects it per round; remove the static copy).
14
+
15
+ No config migration — `resume_flag` is a manifest field, not a TOML key. `peek --json` schema stays `2.6`.
16
+
8
17
  ## [0.3.9] - 2026-09-17
9
18
 
10
19
  ### Changed
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: cli-agent-runner
3
- Version: 0.3.9
3
+ Version: 0.3.10
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
@@ -65,6 +65,7 @@ from agent_runner._emit.serve import ( # noqa: F401 — public re-export
65
65
  emit_schedule_paused,
66
66
  emit_schedule_phase_skipped,
67
67
  emit_schedule_resumed,
68
+ emit_session_resumed,
68
69
  emit_stalled_no_progress,
69
70
  emit_stop_file_detected,
70
71
  )
@@ -104,6 +105,7 @@ __all__ = [
104
105
  "emit_schedule_paused",
105
106
  "emit_schedule_phase_skipped",
106
107
  "emit_schedule_resumed",
108
+ "emit_session_resumed",
107
109
  "emit_stale_index_lock_cleared",
108
110
  "emit_stalled_no_progress",
109
111
  "emit_stop_file_detected",
@@ -191,3 +191,15 @@ 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_session_resumed(log_dir: Path, *, session_id: str, phase: str = "") -> None:
197
+ """Emit session_resumed when serve resumes an existing agent session on a
198
+ non-first round of an epoch (the runtime property peek cannot show). ``phase``
199
+ is omitted when empty so the base (no-override) phase stays a clean payload."""
200
+ from agent_runner.events import SESSION_RESUMED, emit
201
+
202
+ fields = {"session_id": session_id}
203
+ if phase:
204
+ fields["phase"] = phase
205
+ emit(log_dir, SESSION_RESUMED, **fields)
@@ -43,6 +43,13 @@ class PluginManifest:
43
43
  SIGTERM-first at the reap site (today's behavior), never "skip the first
44
44
  signal"."""
45
45
 
46
+ resume_flag: str | None = None
47
+ """The flag that carries a supervisor-chosen session id on EVERY round for a
48
+ CLI whose session flag is IDEMPOTENT (create-or-resume). pi = "--session-id".
49
+ ``None`` = no resume (today's cold start). Resolved ONLY by
50
+ ``resolve_resume_flag``; ``__post_init__`` rejects an empty string. Source-
51
+ verified per preset (pi's --session-id is idempotent), NEVER assumed."""
52
+
46
53
  def __post_init__(self) -> None:
47
54
  # Errors-unlikely-by-construction: an unknown signal name (or a
48
55
  # freeze/zero-grace one like SIGSTOP/SIGKILL) is unrepresentable -- it
@@ -52,6 +59,10 @@ class PluginManifest:
52
59
  "cooperative_stop must be one of {None, 'SIGTERM', 'SIGINT'}, "
53
60
  f"got {self.cooperative_stop!r}"
54
61
  )
62
+ if self.resume_flag is not None and not self.resume_flag:
63
+ raise ValueError(
64
+ f"resume_flag must be None or a non-empty flag string, got {self.resume_flag!r}"
65
+ )
55
66
 
56
67
 
57
68
  _LOADED_MANIFESTS: list[PluginManifest] = []
@@ -102,6 +113,21 @@ def resolve_cooperative_signal(agent_binary: str | None) -> signal.Signals | Non
102
113
  return _COOPERATIVE_SIGNALS.get(_cooperative_stop_for_name(agent_binary))
103
114
 
104
115
 
116
+ def resolve_resume_flag(agent_binary: str | None) -> str | None:
117
+ """The resume flag the agent named `agent_binary` declares, or None when no
118
+ such manifest is registered (or it declares no resume). THE registry lookup
119
+ for resume -- sibling to resolve_cooperative_signal, the SAME
120
+ ``m.name == agent_binary`` join (so it stays correct whenever a preset's
121
+ manifest name is kept equal to its agent binary). serve resolves it once
122
+ per phase and publishes the id via env so the round child never
123
+ re-derives. No signal table: the flag string IS what serve publishes and
124
+ the child appends, so the scan IS the resolve."""
125
+ for m in _LOADED_MANIFESTS:
126
+ if m.name == agent_binary:
127
+ return m.resume_flag
128
+ return None
129
+
130
+
105
131
  def cooperative_signal_from_name(name: str | None) -> signal.Signals | None:
106
132
  """Map a published cooperative-stop signal NAME (e.g. from
107
133
  AGENT_RUNNER_COOPERATIVE_STOP_SIGNAL) back to a ``signal.Signals`` through
@@ -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.3.9'
22
- __version_tuple__ = version_tuple = (0, 3, 9)
21
+ __version__ = version = '0.3.10'
22
+ __version_tuple__ = version_tuple = (0, 3, 10)
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -634,6 +634,7 @@ def run(
634
634
  clock: Clock = SYSTEM_CLOCK,
635
635
  reap_grace_s: int = REAP_GRACE_S,
636
636
  cooperative_first_signal: signal.Signals = signal.SIGTERM,
637
+ resume_args: tuple[str, ...] = (),
637
638
  ) -> RunResult:
638
639
  """Spawn the agent subprocess and wait for exit or timeout.
639
640
 
@@ -653,6 +654,14 @@ def run(
653
654
  cooperative_stop / standalone `agent-runner round`), so every existing caller
654
655
  is unchanged.
655
656
 
657
+ resume_args: ``[flag, session_id]`` appended after ``command`` and before
658
+ the prompt args, for a resume-capable agent picking its session back up
659
+ across rounds. The id is minted once by the caller's own env-published
660
+ single-source (``runner._resolve_resume_args``) and copied verbatim here --
661
+ this module never mints or derives one (no ``os.environ`` read for the
662
+ session id; see the module docstring). Defaults to ``()``, so every
663
+ existing caller's argv is byte-identical to before.
664
+
656
665
  work_dir: the agent child's working directory; callers pass the
657
666
  already-absolute cfg.runtime.work_dir. CLIs with no --cwd flag of their
658
667
  own (e.g. pi) depend on this.
@@ -760,10 +769,11 @@ def run(
760
769
  # template for stdin mode, but run() must be safe even if called
761
770
  # directly with a mismatched template. In stdin mode, never substitute
762
771
  # {prompt} into argv — build it verbatim so the prompt cannot reach argv.
772
+ resumed_command = list(spawn_command) + list(resume_args)
763
773
  argv = (
764
- list(spawn_command) + list(prompt_arg_template)
774
+ list(resumed_command) + list(prompt_arg_template)
765
775
  if stdin_mode
766
- else _build_argv(spawn_command, prompt_arg_template, prompt)
776
+ else _build_argv(resumed_command, prompt_arg_template, prompt)
767
777
  )
768
778
  # PWD pinned last — it mirrors cwd= (a correctness pin, not a knob), so
769
779
  # an [agent.env] PWD cannot silently diverge from where the child runs.
@@ -62,6 +62,7 @@ from agent_runner._emit import ( # noqa: E402,F401 — intentional bottom re-ex
62
62
  emit_schedule_paused,
63
63
  emit_schedule_phase_skipped,
64
64
  emit_schedule_resumed,
65
+ emit_session_resumed,
65
66
  emit_stale_index_lock_cleared,
66
67
  emit_stalled_no_progress,
67
68
  emit_stop_file_detected,
@@ -281,5 +281,8 @@ def _is_auth_error(text: str | None) -> bool:
281
281
 
282
282
 
283
283
  PLUGIN = PluginManifest(
284
- name="pi", post_round_hooks=(PiErrorDetector(),), cooperative_stop="SIGTERM"
284
+ name="pi",
285
+ post_round_hooks=(PiErrorDetector(),),
286
+ cooperative_stop="SIGTERM",
287
+ resume_flag="--session-id",
285
288
  )
@@ -43,6 +43,7 @@ from agent_runner.api import (
43
43
  emit_schedule_paused,
44
44
  emit_schedule_phase_skipped,
45
45
  emit_schedule_resumed,
46
+ emit_session_resumed,
46
47
  emit_stop_file_detected,
47
48
  outer_round_ceiling_s,
48
49
  )
@@ -558,9 +559,8 @@ def _is_fresh_eyes_round(*, round_num: int, every_n: int | None) -> bool:
558
559
  return round_num % every_n == 0
559
560
 
560
561
 
561
- def _apply_fresh_eyes(cfg, log_dir, round_num: int, round_env: dict) -> None:
562
+ def _apply_fresh_eyes(cfg, log_dir, round_num: int, round_env: dict, fresh_eyes: bool) -> None:
562
563
  """Set the round's fresh-eyes env flag and emit the trigger event when due."""
563
- fresh_eyes = _is_fresh_eyes_round(round_num=round_num, every_n=cfg.runtime.fresh_eyes_every_n)
564
564
  round_env["AGENT_RUNNER_FRESH_EYES"] = "1" if fresh_eyes else "0"
565
565
  if fresh_eyes:
566
566
  emit_fresh_eyes_round_triggered(
@@ -659,6 +659,45 @@ def _apply_cooperative_signal_env(
659
659
  round_env["AGENT_RUNNER_COOPERATIVE_STOP_SIGNAL"] = name
660
660
 
661
661
 
662
+ def _apply_resume_env(
663
+ cfg, round_env: dict, phase_arg: str | None, is_fresh_eyes: bool, session_ids: dict, log_dir
664
+ ) -> None:
665
+ """Publish this round's cross-round-resume flag + session id via
666
+ AGENT_RUNNER_RESUME_FLAG / AGENT_RUNNER_RESUME_SESSION_ID -- the 4th
667
+ serve->child env single-source (siblings _apply_reap_grace_env /
668
+ _apply_cooperative_signal_env). UNLIKE those boot-invariant siblings the id
669
+ is MUTABLE per-phase state: `session_ids` (keyed by PHASE, not binary --
670
+ per-role continuity) carries it across rounds; a first-use OR fresh-eyes
671
+ round mints a new uuid. A non-resume phase (resolve_resume_flag is None)
672
+ POPS both keys so a prior resume-capable phase's id never leaks onto this
673
+ round's child argv. Emits session_resumed only when RESUMING (id reused)."""
674
+ import uuid
675
+
676
+ from agent_runner._plugin_manifest import resolve_resume_flag
677
+
678
+ # Resume needs serve to PIN the child's phase. When phase_arg is None but
679
+ # [phases] exists, serve is non-phase-aware (phase_policy="wait", or
680
+ # --ignore-schedule) and the round child SELF-ROTATES phases by round_num --
681
+ # serve cannot know which agent ran, so publishing the base id would bleed
682
+ # one role's session across all rotated roles. Cold-start (pop) when the
683
+ # phase is ambiguous; resume only with an explicit phase or a single base
684
+ # agent (empty phases.list).
685
+ flag = resolve_resume_flag(cfg.profile_for(phase_arg).agent.binary)
686
+ if flag is None or (phase_arg is None and cfg.phases.list):
687
+ round_env.pop("AGENT_RUNNER_RESUME_FLAG", None)
688
+ round_env.pop("AGENT_RUNNER_RESUME_SESSION_ID", None)
689
+ return
690
+ sid = session_ids.get(phase_arg)
691
+ resuming = sid is not None and not is_fresh_eyes
692
+ if not resuming:
693
+ sid = str(uuid.uuid4())
694
+ session_ids[phase_arg] = sid
695
+ round_env["AGENT_RUNNER_RESUME_FLAG"] = flag
696
+ round_env["AGENT_RUNNER_RESUME_SESSION_ID"] = sid
697
+ if resuming:
698
+ emit_session_resumed(log_dir, session_id=sid, phase=phase_arg or "")
699
+
700
+
662
701
  def _capture_substrate(work_dir, cfg, log_dir, round_num, *, when):
663
702
  """Snapshot git-head + paths-hash and emit the round-substrate event for `when`."""
664
703
  git_head = compute_git_head(work_dir)
@@ -742,6 +781,10 @@ def cmd(args) -> int:
742
781
  _release_serve_lock(serve_lock_fd)
743
782
  raise ConfigError(f"phase-window overlap: {detail}; run `agent-runner doctor` for details")
744
783
  rounds_completed = 0
784
+ # Cross-round resume: this serve lifetime's minted session id per phase
785
+ # (None key = the base, no-override agent). Mutable, unlike grace_by_phase/
786
+ # cooperative_signal_by_phase above -- see _apply_resume_env.
787
+ session_ids: dict[str | None, str] = {}
745
788
  # Three independent consecutive-failure counters, one per breaker: b12
746
789
  # crash-loop (unknown short crashes), mem-loop (mem-terminated
747
790
  # rounds), no-progress (exit-0, no usage). LOC-neutral
@@ -801,10 +844,14 @@ def cmd(args) -> int:
801
844
  if stop["requested"]:
802
845
  break # SIGTERM landed during selection/back-off — don't spawn a round
803
846
  _capture_substrate(work_dir, cfg, log_dir, round_num, when="before")
804
- _apply_fresh_eyes(cfg, log_dir, round_num, round_env)
847
+ is_fresh_eyes = _is_fresh_eyes_round(
848
+ round_num=round_num, every_n=cfg.runtime.fresh_eyes_every_n
849
+ )
850
+ _apply_fresh_eyes(cfg, log_dir, round_num, round_env, is_fresh_eyes)
805
851
  _apply_round_num_env(round_env, round_num)
806
852
  _apply_reap_grace_env(cfg, round_env, phase_arg, grace_by_phase)
807
853
  _apply_cooperative_signal_env(cfg, round_env, phase_arg, cooperative_signal_by_phase)
854
+ _apply_resume_env(cfg, round_env, phase_arg, is_fresh_eyes, session_ids, log_dir)
808
855
  round_log_path = log_dir / f"round-{round_num}.log"
809
856
  round_started = SYSTEM_CLOCK.monotonic()
810
857
  round_argv = [
@@ -32,6 +32,30 @@ from agent_runner.config.validators import (
32
32
  _CURRENT_SCHEMA_VERSION = 1
33
33
 
34
34
 
35
+ def _reject_static_resume_flag(cfg) -> None:
36
+ """A resume-capable preset must not already carry its resume_flag token in
37
+ the static command/prompt_arg_template -- agent-runner injects [flag, id]
38
+ per round, so a static copy would duplicate it. Boot refusal (ConfigError)
39
+ keeps best-effort-never-error at round time. Runs AFTER
40
+ load_and_register_plugins so resolve_resume_flag can see the manifests
41
+ (it is registry-backed, unlike the boot-time {prompt} guard)."""
42
+ from agent_runner._plugin_manifest import resolve_resume_flag
43
+
44
+ agents = [(None, cfg.agent)] + [
45
+ (name, ov.agent) for name, ov in cfg.phases.overrides.items() if ov.agent is not None
46
+ ]
47
+ for phase_name, a in agents:
48
+ flag = resolve_resume_flag(a.binary)
49
+ if flag is None:
50
+ continue
51
+ if flag in a.command or flag in a.prompt_arg_template:
52
+ where = "[agent]" if phase_name is None else f"[phases.{phase_name}.agent]"
53
+ raise ConfigError(
54
+ f"{where} command already contains {flag!r}: agent-runner injects it "
55
+ "per round for cross-round resume; remove it from the static command"
56
+ )
57
+
58
+
35
59
  def _check_schema_version(raw: dict) -> None:
36
60
  """Boot gate: a config's ``schema_version`` decouples the on-disk config
37
61
  shape from the installed package version, so a config can be migrated
@@ -133,4 +157,6 @@ def load_config(toml_path: Path) -> Config:
133
157
  if plugins.disable:
134
158
  apply_plugin_disable(plugins.disable)
135
159
 
160
+ _reject_static_resume_flag(cfg)
161
+
136
162
  return cfg
@@ -84,6 +84,7 @@ SELF_TERMINATED = "agent_self_terminated"
84
84
  SERVICE_UPGRADE_ROLLBACK_FAILED = "service_upgrade_rollback_failed"
85
85
  SERVICE_UPGRADE_ROLLED_BACK = "service_upgrade_rolled_back"
86
86
  SERVICE_UPGRADED = "service_upgraded"
87
+ SESSION_RESUMED = "session_resumed"
87
88
  SMOKE_CHECK_FAILED = "smoke_check_failed"
88
89
  STALE_INDEX_LOCK_CLEARED = "stale_index_lock_cleared"
89
90
  STALLED_NO_PROGRESS = "stalled_no_progress"
@@ -220,6 +220,20 @@ def _resolve_cooperative_signal() -> signal.Signals:
220
220
  return resolved if resolved is not None else signal.SIGTERM
221
221
 
222
222
 
223
+ def _resolve_resume_args() -> list[str]:
224
+ """The ``[flag, session_id]`` the round child appends for cross-round
225
+ resume, or ``[]`` when no serve parent published them (systemd / standalone
226
+ ``round`` -> cold start by construction). Pure consumption -- the id is
227
+ minted once serve-side and copied verbatim; the child NEVER derives it.
228
+ Sibling of ``_resolve_reap_grace_s`` / ``_resolve_cooperative_signal``: the
229
+ same serve->child env single-source, both-vars-or-neither."""
230
+ flag = os.environ.get("AGENT_RUNNER_RESUME_FLAG")
231
+ session_id = os.environ.get("AGENT_RUNNER_RESUME_SESSION_ID")
232
+ if flag and session_id:
233
+ return [flag, session_id]
234
+ return []
235
+
236
+
223
237
  def _previous_block(prev: context_store.Status | None, dirty_last: bool) -> dict[str, Any] | None:
224
238
  if prev is None:
225
239
  return None
@@ -507,6 +521,7 @@ def _run_one_round_inner(cfg: Config, *, phase_override: str | None = None) -> R
507
521
  on_container_orphan_risk=_container_orphan_risk_emit,
508
522
  reap_grace_s=_resolve_reap_grace_s(),
509
523
  cooperative_first_signal=_resolve_cooperative_signal(),
524
+ resume_args=_resolve_resume_args(),
510
525
  )
511
526
  events.emit(
512
527
  log_dir,
@@ -248,6 +248,7 @@ The result is recorded as `RoundResult.dirty_outcome: DirtyOutcome | None`, whic
248
248
  - `service_upgrade_rollback_failed`
249
249
  - `service_upgrade_rolled_back`
250
250
  - `service_upgraded`
251
+ - `session_resumed`
251
252
  - `smoke_check_failed`
252
253
  - `stale_index_lock_cleared`
253
254
  - `stalled_no_progress`
@@ -652,6 +652,71 @@ since 0.2.17. No constrained-host-specific claim this release — the
652
652
  subtraction is host-independent code removal, not a runtime-behavior change
653
653
  under pressure.
654
654
 
655
+ ## 0.3.9 → 0.3.10
656
+
657
+ Cross-round resume for `pi`: `PluginManifest.resume_flag` (a new dataclass
658
+ field, `str | None`, default `None`), `resolve_resume_flag`, a per-phase
659
+ session-id mint + env publish (`AGENT_RUNNER_RESUME_FLAG`/
660
+ `AGENT_RUNNER_RESUME_SESSION_ID`) in `serve_cmd`, the round child appending
661
+ `[flag, id]`, a `session_resumed` event, and a config boot guard. Same macOS
662
+ harness (§ methodology above), comparing **v0.3.9** = `095c5f1` (measured in a
663
+ throwaway worktree) against **0.3.10**, the tip of this branch.
664
+
665
+ ### 1. Import/startup RSS
666
+
667
+ | | v0.3.9 | 0.3.10 | Δ |
668
+ |---|---|---|---|
669
+ | RSS (avg of 5 cold runs) | 23.42 MB | 23.39 MB | −0.03 MB (flat, within noise) |
670
+ | RSS range | 23.39–23.45 MB | 23.34–23.42 MB | |
671
+ | `sys.modules` count | 211 | 211 | +0 |
672
+
673
+ Flat, as expected: `uuid` (the only new stdlib name resume touches) is
674
+ imported inside `_apply_resume_env`, not at module level, so it never joins
675
+ the cold-startup graph — confirmed directly (`"uuid" in sys.modules` is
676
+ `False` after `import agent_runner.cli`), not just inferred from a flat RSS
677
+ number. A direct `sys.modules` set diff (not just the count) confirms the
678
+ `agent_runner.*` module set `import agent_runner.cli` loads is byte-for-byte
679
+ identical, 211 modules, before and after — the same check this page has run
680
+ at every release since 0.3.9's own close-out.
681
+
682
+ ### 2. Base dependencies
683
+
684
+ Unchanged: `psutil>=5.9` is still the only runtime dependency
685
+ (`pip show cli-agent-runner` → `Requires: psutil`). Resume introduces no new
686
+ dependency and no new extra.
687
+
688
+ ### 3. Module count, source LOC, largest module
689
+
690
+ Tracked source only (`git ls-tree`, same convention as the rows above).
691
+
692
+ | | v0.3.9 | 0.3.10 | Δ |
693
+ |---|---|---|---|
694
+ | `.py` files | 81 | 81 | +0 |
695
+ | total LOC | 20,195 | 20,338 | +143 |
696
+ | largest module | `migrations.py`, 972 | `migrations.py`, 972 | +0 |
697
+
698
+ The `+143` LOC is the new manifest field, its resolver, the boot guard, the
699
+ per-phase env publish/consume, the `session_resumed` event, and their tests
700
+ — no module decomposition this release.
701
+
702
+ ### 4. Per-round allocation growth
703
+
704
+ `tests/invariants/test_round_alloc_growth.py` green, unmodified harness.
705
+ `_apply_resume_env` runs once per round (same call site as the other
706
+ per-round `serve_cmd` readers) and, on the no-resume branch every
707
+ non-`pi` preset takes, does two dict `.pop()`s and returns — no new retained
708
+ per-round state. On the resume branch (`pi` only), the session id is minted
709
+ once per phase at `serve` startup (`session_ids` dict, sized by phase count,
710
+ not by round count) and reused verbatim every round after — not re-allocated
711
+ per round.
712
+
713
+ ### Constrained-host (honesty)
714
+
715
+ Dev-host-relative (macOS) numbers only, same methodology as every release
716
+ since 0.2.17. No constrained-host-specific claim this release — resume is a
717
+ pi-only session-id mechanism verified so far by an ssh-pi property test, not
718
+ a memory-pressure-path change.
719
+
655
720
  ## Enforcement
656
721
 
657
722
  Four invariant tests keep these numbers from drifting silently:
@@ -127,3 +127,14 @@ rather than partially trusted. The exact errors:
127
127
 
128
128
  Any of these means the same fix: run `agent-runner migrate` (or, for the
129
129
  newer-than-supported case, upgrade the `agent-runner` package instead).
130
+
131
+ ## Upgrading to 0.3.10 — no config migration
132
+
133
+ 0.3.10 adds cross-round resume (`PluginManifest.resume_flag`, pi's
134
+ `--session-id`). It is additive and inert for every preset that doesn't
135
+ declare a `resume_flag` — nothing to run, nothing to rewrite. If your config
136
+ already passes `--session-id` (or another preset's resume flag) as a static
137
+ argument in `[agent] command`/`prompt_arg_template` (or a `[phases.<name>]`
138
+ override), remove it: agent-runner now injects `[flag, session id]` itself on
139
+ every round for a resume-capable preset, and a static copy of the same flag
140
+ fails config load at boot.
@@ -47,6 +47,7 @@ empty:
47
47
  | `name` | `str` | The plugin's own identity — `[plugins] disable` keys on this, not on any individual hook's own `.name`. |
48
48
  | `post_round_hooks` | `tuple[PostRoundHook, ...]` | Runs after each agent round. |
49
49
  | `cooperative_stop` | `Literal["SIGTERM", "SIGINT"] \| None` | The signal this preset's agent CLI catches to drain/wrap up when a round is stopped (`None` = no cooperative drain — the hard SIGTERM-first path). Reported under `peek --json`'s `plugins.cooperative_stop` (§ below). |
50
+ | `resume_flag` | `str \| None` | The idempotent session flag `serve` injects on every round of this preset for cross-round resume (pi = `--session-id`); `serve` mints one session id per phase and the round child appends `[flag, id]` to its command. `None` = no resume (cold start every round, today's behavior for every other preset). |
50
51
 
51
52
  A plugin that provides more than one capability just fills in more than one
52
53
  field on the same manifest — there is nothing to register per-capability.
@@ -217,6 +217,7 @@ EXPECTED_API_SURFACE = {
217
217
  "emit_schedule_paused",
218
218
  "emit_schedule_phase_skipped",
219
219
  "emit_schedule_resumed",
220
+ "emit_session_resumed",
220
221
  "emit_stale_index_lock_cleared",
221
222
  # "emit_stalled_no_progress" added 0.2.16 Task 6: exit-0 no-progress breaker
222
223
  # (pi-class CLIs exit 0 on a provider failure that never reaches the model).