cli-agent-runner 0.1.26__tar.gz → 0.1.27__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 (197) hide show
  1. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/CHANGELOG.md +13 -0
  2. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/PKG-INFO +1 -1
  3. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/agent_runner/_version.py +2 -2
  4. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/agent_runner/builtin_plugins/claude_rate_limit.py +3 -1
  5. cli_agent_runner-0.1.27/docs/migrations/0.1.27.md +169 -0
  6. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/unit/test_claude_error_detector.py +46 -0
  7. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/.codecov.yml +0 -0
  8. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/.githooks/commit-msg +0 -0
  9. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  10. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  11. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  12. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  13. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/.github/workflows/ci.yml +0 -0
  14. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/.github/workflows/release.yml +0 -0
  15. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/.gitignore +0 -0
  16. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/.vulture-whitelist.py +0 -0
  17. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/CODE_OF_CONDUCT.md +0 -0
  18. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/CONTRIBUTING.md +0 -0
  19. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/LICENSE +0 -0
  20. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/README.md +0 -0
  21. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/README.zh.md +0 -0
  22. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/SECURITY.md +0 -0
  23. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/agent_runner/__init__.py +0 -0
  24. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/agent_runner/_docgen.py +0 -0
  25. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/agent_runner/_emit.py +0 -0
  26. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/agent_runner/_registry.py +0 -0
  27. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/agent_runner/_substrate.py +0 -0
  28. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/agent_runner/_throttle.py +0 -0
  29. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/agent_runner/agent_runtime.py +0 -0
  30. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/agent_runner/api.py +0 -0
  31. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/agent_runner/api_types.py +0 -0
  32. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/agent_runner/builtin_plugins/__init__.py +0 -0
  33. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/agent_runner/builtin_plugins/_constants.py +0 -0
  34. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/agent_runner/builtin_plugins/gemini.py +0 -0
  35. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/agent_runner/cli/__init__.py +0 -0
  36. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/agent_runner/cli/__main__.py +0 -0
  37. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/agent_runner/cli/common.py +0 -0
  38. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/agent_runner/cli/init_cmd.py +0 -0
  39. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/agent_runner/cli/install_cmd.py +0 -0
  40. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/agent_runner/cli/monitor_cmd.py +0 -0
  41. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/agent_runner/cli/peek_cmd.py +0 -0
  42. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/agent_runner/cli/round_cmd.py +0 -0
  43. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/agent_runner/cli/serve_cmd.py +0 -0
  44. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/agent_runner/cli/service_cmd.py +0 -0
  45. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/agent_runner/cli/upgrade_cmd.py +0 -0
  46. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/agent_runner/config.py +0 -0
  47. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/agent_runner/context_store.py +0 -0
  48. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/agent_runner/defenses.py +0 -0
  49. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/agent_runner/detector_helpers.py +0 -0
  50. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/agent_runner/events.py +0 -0
  51. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/agent_runner/hooks.py +0 -0
  52. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/agent_runner/http_progress.py +0 -0
  53. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/agent_runner/lifecycle.py +0 -0
  54. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/agent_runner/metrics.py +0 -0
  55. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/agent_runner/monitor.py +0 -0
  56. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/agent_runner/presets/__init__.py +0 -0
  57. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/agent_runner/presets/aider.toml +0 -0
  58. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/agent_runner/presets/claude.toml +0 -0
  59. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/agent_runner/presets/gemini.toml +0 -0
  60. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/agent_runner/prompt_loader.py +0 -0
  61. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/agent_runner/round_log.py +0 -0
  62. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/agent_runner/round_view.py +0 -0
  63. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/agent_runner/runner.py +0 -0
  64. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/agent_runner/scaffold.py +0 -0
  65. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/agent_runner/service_unit.py +0 -0
  66. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/agent_runner/startup_check.py +0 -0
  67. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/agent_runner/vcs_state.py +0 -0
  68. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/build.sh +0 -0
  69. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/deploy/example-agent-runner.toml +0 -0
  70. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/deploy/launchd.plist.tmpl +0 -0
  71. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/deploy/run-loop.sh +0 -0
  72. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/deploy/systemd.service.tmpl +0 -0
  73. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/docs/README.md +0 -0
  74. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/docs/architecture.md +0 -0
  75. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/docs/commands.md +0 -0
  76. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/docs/configuration.md +0 -0
  77. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/docs/events.md +0 -0
  78. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/docs/long-running-agents.md +0 -0
  79. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/docs/marketing/README.md +0 -0
  80. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/docs/marketing/promo-cn.html +0 -0
  81. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/docs/migrations/0.1.16.md +0 -0
  82. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/docs/migrations/0.1.17.md +0 -0
  83. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/docs/migrations/0.1.19.md +0 -0
  84. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/docs/migrations/0.1.20.md +0 -0
  85. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/docs/migrations/0.1.21.md +0 -0
  86. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/docs/migrations/0.1.22.md +0 -0
  87. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/docs/migrations/0.1.23.md +0 -0
  88. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/docs/migrations/0.1.24.md +0 -0
  89. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/docs/migrations/0.1.25.md +0 -0
  90. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/docs/migrations/0.1.26.md +0 -0
  91. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/docs/plugins.md +0 -0
  92. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/docs/quickstart.md +0 -0
  93. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/docs/recipes/aider.md +0 -0
  94. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/docs/runbook.md +0 -0
  95. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/pyproject.toml +0 -0
  96. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/__init__.py +0 -0
  97. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/_test_helpers.py +0 -0
  98. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/conftest.py +0 -0
  99. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/contract/__init__.py +0 -0
  100. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/contract/test_public_api_surface.py +0 -0
  101. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/e2e/__init__.py +0 -0
  102. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/e2e/conftest.py +0 -0
  103. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/e2e/test_e2e_graceful_stop.py +0 -0
  104. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/e2e/test_e2e_install_systemd.py +0 -0
  105. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/e2e/test_e2e_monitor_remote.py +0 -0
  106. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/e2e/test_e2e_round_lifecycle.py +0 -0
  107. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/integration/__init__.py +0 -0
  108. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/integration/test_bounded_run.py +0 -0
  109. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/integration/test_context_enricher_namespacing.py +0 -0
  110. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/integration/test_fresh_eyes_signal.py +0 -0
  111. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/integration/test_install_dry_run.py +0 -0
  112. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/integration/test_monitor_seeded.py +0 -0
  113. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/integration/test_plugin_detector_loaded.py +0 -0
  114. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/integration/test_plugin_owned_paths.py +0 -0
  115. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/integration/test_plugin_real_flow.py +0 -0
  116. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/integration/test_run_one_round_with_fake_agent.py +0 -0
  117. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/integration/test_scaffold_presets.py +0 -0
  118. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/integration/test_serve_loop.py +0 -0
  119. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/integration/test_substrate_fingerprint.py +0 -0
  120. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/integration/test_transient_error_backoff.py +0 -0
  121. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/invariants/__init__.py +0 -0
  122. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/invariants/test_architecture.py +0 -0
  123. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/invariants/test_atomic_write_enforced.py +0 -0
  124. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/invariants/test_catalogs.py +0 -0
  125. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/invariants/test_docs_generated.py +0 -0
  126. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/invariants/test_event_kind_registry.py +0 -0
  127. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/invariants/test_events_doc_contract.py +0 -0
  128. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/invariants/test_module_boundaries.py +0 -0
  129. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/invariants/test_module_sizes.py +0 -0
  130. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/invariants/test_no_ai_signatures.py +0 -0
  131. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/invariants/test_no_pytest_skip_on_parse_fail.py +0 -0
  132. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/invariants/test_peek_schema_version.py +0 -0
  133. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/invariants/test_repo_constants_patched_in_tests.py +0 -0
  134. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/invariants/test_round_result_stable.py +0 -0
  135. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/invariants/test_stash_uses_sha_not_index.py +0 -0
  136. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/literate/__init__.py +0 -0
  137. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/literate/parser.py +0 -0
  138. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/literate/test_parser.py +0 -0
  139. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/literate/test_quickstart.py +0 -0
  140. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/unit/__init__.py +0 -0
  141. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/unit/test_agent_runtime.py +0 -0
  142. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/unit/test_api_assemble_prompt.py +0 -0
  143. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/unit/test_api_events_stream.py +0 -0
  144. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/unit/test_api_install.py +0 -0
  145. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/unit/test_api_observation.py +0 -0
  146. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/unit/test_api_read_round_num.py +0 -0
  147. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/unit/test_api_resolve_phase.py +0 -0
  148. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/unit/test_api_service.py +0 -0
  149. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/unit/test_api_types.py +0 -0
  150. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/unit/test_auto_stop_gating.py +0 -0
  151. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/unit/test_cli.py +0 -0
  152. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/unit/test_cli_common.py +0 -0
  153. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/unit/test_cli_init_install.py +0 -0
  154. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/unit/test_cli_monitor_http.py +0 -0
  155. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/unit/test_cli_service_peek_monitor.py +0 -0
  156. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/unit/test_cli_upgrade.py +0 -0
  157. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/unit/test_config.py +0 -0
  158. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/unit/test_config_fresh_eyes.py +0 -0
  159. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/unit/test_config_max_rounds.py +0 -0
  160. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/unit/test_config_rate_limit_action.py +0 -0
  161. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/unit/test_config_stop_file.py +0 -0
  162. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/unit/test_config_substrate_fingerprint_paths.py +0 -0
  163. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/unit/test_config_transient_error_action.py +0 -0
  164. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/unit/test_context_store.py +0 -0
  165. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/unit/test_defenses.py +0 -0
  166. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/unit/test_detector_helpers.py +0 -0
  167. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/unit/test_detector_protocol.py +0 -0
  168. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/unit/test_docgen.py +0 -0
  169. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/unit/test_events.py +0 -0
  170. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/unit/test_fresh_eyes_trigger.py +0 -0
  171. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/unit/test_gemini_plugin.py +0 -0
  172. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/unit/test_hook_failure_isolation.py +0 -0
  173. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/unit/test_hooks.py +0 -0
  174. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/unit/test_http_progress.py +0 -0
  175. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/unit/test_init_entry_points.py +0 -0
  176. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/unit/test_lifecycle.py +0 -0
  177. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/unit/test_metrics.py +0 -0
  178. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/unit/test_monitor_assembly.py +0 -0
  179. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/unit/test_monitor_detect_rate_limit.py +0 -0
  180. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/unit/test_monitor_detectors.py +0 -0
  181. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/unit/test_monitor_remote.py +0 -0
  182. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/unit/test_peek_argparse.py +0 -0
  183. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/unit/test_presets.py +0 -0
  184. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/unit/test_prompt_loader.py +0 -0
  185. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/unit/test_round_log_helpers.py +0 -0
  186. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/unit/test_round_view.py +0 -0
  187. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/unit/test_runner.py +0 -0
  188. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/unit/test_runner_throttle.py +0 -0
  189. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/unit/test_scaffold.py +0 -0
  190. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/unit/test_serve_cmd_bounded.py +0 -0
  191. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/unit/test_serve_round_log.py +0 -0
  192. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/unit/test_serve_sentinel.py +0 -0
  193. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/unit/test_serve_startup_hooks.py +0 -0
  194. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/unit/test_service_unit.py +0 -0
  195. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/unit/test_startup_check.py +0 -0
  196. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/unit/test_substrate.py +0 -0
  197. {cli_agent_runner-0.1.26 → cli_agent_runner-0.1.27}/tests/unit/test_vcs_state.py +0 -0
@@ -7,6 +7,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.1.27] - 2026-05-17
11
+
12
+ ### Fixed
13
+ - claude plugin: rate_limit_event with rateLimitType=null no longer misclassified as account
14
+ 5h quota; falls through to api_error_status-based bucket (e.g. infra 429 → rate_limit_model).
15
+ Affects supervisors consuming transient_error_detected.
16
+
17
+ ### Added
18
+ - docs/migrations/0.1.27.md: supervisor usage guide for transient_error_detected event
19
+ (4-bucket dispatch table + back-off recipe).
20
+
21
+ See `docs/migrations/0.1.27.md`.
22
+
10
23
  ## [0.1.26] - 2026-05-17
11
24
 
12
25
  - Fix claude `agent_usage_recorded` `model` field (was always
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cli-agent-runner
3
- Version: 0.1.26
3
+ Version: 0.1.27
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
@@ -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.26'
22
- __version_tuple__ = version_tuple = (0, 1, 26)
21
+ __version__ = version = '0.1.27'
22
+ __version_tuple__ = version_tuple = (0, 1, 27)
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -118,13 +118,15 @@ def _classify_transient_error(
118
118
  """Refactored from prior _scan_log_for_transient_error 0.1.23 logic; same shape, same
119
119
  priority (rate_limit_event.rejected > 429 > 5xx > 408).
120
120
  """
121
- if rate_limit_info is not None:
121
+ if rate_limit_info is not None and rate_limit_info.get("rateLimitType") == "five_hour":
122
122
  return {
123
123
  "classification": "rate_limit_account",
124
124
  "agent": "claude",
125
125
  "reset_at_epoch": int(rate_limit_info.get("resetsAt", time.time() + 300)),
126
126
  "raw": str((result_event or {}).get("result", ""))[:_RAW_CAP],
127
127
  }
128
+ # rate_limit_event with null/other rateLimitType falls through to status-based
129
+ # classification below.
128
130
  if result_event is None or result_event.get("is_error") is not True:
129
131
  return None
130
132
  status = result_event.get("api_error_status")
@@ -0,0 +1,169 @@
1
+ # 0.1.27 — Rate-limit classifier fix + supervisor usage guide
2
+
3
+ ## What changed
4
+
5
+ The claude built-in plugin (`agent_runner.builtin_plugins.claude_rate_limit`) previously
6
+ misclassified any `rate_limit_event` with `status="rejected"` as `rate_limit_account`
7
+ (account-level 5-hour quota exhaustion), regardless of `rateLimitType`. As of 0.1.27, the
8
+ `rate_limit_account` branch requires `rateLimitType == "five_hour"`; other `rate_limit_event`
9
+ values (e.g. `rateLimitType: null` for claude.ai infrastructure throttling) fall through to
10
+ status-code-based classification.
11
+
12
+ Concretely: a claude.ai 429 with `rateLimitType: null` is now correctly emitted as
13
+ `transient_error_detected` with `classification: "rate_limit_model"` and a 60-second default
14
+ `reset_at_epoch`, instead of `rate_limit_account` with a synthetic 5-minute fallback epoch.
15
+
16
+ No event schema changes. No new event kinds. No new public API.
17
+
18
+ ## Supervisor usage — consuming `transient_error_detected`
19
+
20
+ External supervisors should subscribe to the `transient_error_detected` event family (added in
21
+ 0.1.23). The event carries a `classification` discriminator with one of 4 values:
22
+
23
+ | classification | Trigger | reset_at_epoch semantics | Suggested supervisor action |
24
+ |--------------------|------------------------------------------------------|-------------------------------------|-------------------------------------------|
25
+ | rate_limit_account | rate_limit_event.rateLimitType == "five_hour" | Server-provided `resetsAt` (exact) | Sleep until reset_at_epoch (multi-hour) |
26
+ | rate_limit_model | api_error_status == 429 (and not five_hour) | now + 60s default (no server hint) | Sleep until reset_at_epoch or exp-backoff |
27
+ | api_transient_5xx | api_error_status in {500, 502, 503, 504} | now + 60s default | Sleep until reset_at_epoch or exp-backoff |
28
+ | api_timeout | api_error_status == 408 | now + 30s default | Sleep until reset_at_epoch or exp-backoff |
29
+
30
+ ### Event payload shape
31
+
32
+ Each line in `events-YYYY-MM.jsonl` looks like:
33
+
34
+ ```json
35
+ {
36
+ "ts": "2026-05-17T02:13:44.123Z",
37
+ "event": "transient_error_detected",
38
+ "classification": "rate_limit_model",
39
+ "agent": "claude",
40
+ "reset_at_epoch": 1747450424,
41
+ "round_num": 7,
42
+ "raw": "API Error: Server is temporarily limiting requests (not your usage limit) · Rate limited"
43
+ }
44
+ ```
45
+
46
+ Fields:
47
+
48
+ - `ts` — ISO 8601 UTC timestamp of event emission.
49
+ - `event` — always `"transient_error_detected"`.
50
+ - `classification` — one of the 4 buckets above.
51
+ - `agent` — `"claude"` (gemini uses same schema via its own plugin).
52
+ - `reset_at_epoch` — Unix epoch seconds; supervisor sleeps until this time. For
53
+ `rate_limit_account` this is the server-provided exact unblock time; for all other buckets
54
+ it is `now + default_seconds` at the moment of emission.
55
+ - `round_num` — which agent round triggered the error.
56
+ - `raw` — first 200 chars of the result text (useful for logging/alerting).
57
+
58
+ ### Dispatch recipe (Python)
59
+
60
+ ```python
61
+ import time
62
+
63
+
64
+ def handle_transient_error(event: dict) -> None:
65
+ """React to a transient_error_detected event from agent-runner."""
66
+ bucket = event["classification"]
67
+ reset_at = event["reset_at_epoch"]
68
+ now = time.time()
69
+ wait_s = max(reset_at - now, 0)
70
+
71
+ if bucket == "rate_limit_account":
72
+ # Server-provided exact unblock time; respect it (multi-hour wait typical).
73
+ time.sleep(wait_s)
74
+ elif bucket == "rate_limit_model":
75
+ # Infra-level 429; 60s default. Apply your own exp-backoff curve if desired.
76
+ time.sleep(wait_s) # or: time.sleep(exp_backoff_with_cap(attempts, cap=300))
77
+ elif bucket == "api_transient_5xx":
78
+ # Transient server error; 60s default.
79
+ time.sleep(wait_s)
80
+ elif bucket == "api_timeout":
81
+ # Request timed out; 30s default.
82
+ time.sleep(wait_s)
83
+ else:
84
+ # Unknown future bucket — safe fallback.
85
+ time.sleep(max(wait_s, 30))
86
+ ```
87
+
88
+ ### Default back-off vs. your own curve
89
+
90
+ Agent-runner's defaults (`rate_limit_model` and `api_transient_5xx` → 60s, `api_timeout` → 30s)
91
+ are a conservative baseline — a flat one-shot sleep. Supervisors that track consecutive failures
92
+ may apply an exponential curve with a cap (e.g. 30s → 60s → 120s → 300s max) for
93
+ `rate_limit_model` and `api_transient_5xx`. For `rate_limit_account`, always respect
94
+ `reset_at_epoch` verbatim — the server provides the exact unblock time.
95
+
96
+ ## Migration from legacy `rate_limit_rejected` event
97
+
98
+ Consumers that still listen to `rate_limit_rejected` (added in 0.1.20) continue to receive it
99
+ for `rate_limit_account` events only. It is emitted as a back-compat dual-emit alongside
100
+ `transient_error_detected`. New consumers should subscribe to `transient_error_detected` for
101
+ full 4-bucket coverage; `rate_limit_rejected` only fires for the `five_hour` bucket and carries
102
+ no `classification` field.
103
+
104
+ ## Verification
105
+
106
+ Write the incident JSONL into a temporary file and call `_parse_claude_log` directly:
107
+
108
+ ```bash
109
+ mkdir -p /tmp/verify-0.1.27
110
+ cat > /tmp/verify-0.1.27/round-1.log <<'EOF'
111
+ {"type":"rate_limit_event","rate_limit_info":{"status":"rejected","rateLimitType":null}}
112
+ {"type":"assistant","message":{"model":"claude-opus-4-7","content":[{"type":"text","text":"API Error: rate limited"}]}}
113
+ {"type":"result","is_error":true,"api_error_status":429,"result":"API Error: rate limited","usage":{"input_tokens":100,"output_tokens":10,"cache_read_input_tokens":0},"duration_ms":1000,"total_cost_usd":0.01}
114
+ EOF
115
+
116
+ .venv/bin/python -c "
117
+ from pathlib import Path
118
+ from agent_runner.builtin_plugins.claude_rate_limit import _parse_claude_log
119
+ import json
120
+ print(json.dumps(_parse_claude_log(Path('/tmp/verify-0.1.27/round-1.log')), indent=2, default=str))
121
+ "
122
+ ```
123
+
124
+ Expected output:
125
+
126
+ ```json
127
+ {
128
+ "transient_error": {
129
+ "classification": "rate_limit_model",
130
+ "agent": "claude",
131
+ "reset_at_epoch": 1747450484,
132
+ "raw": "API Error: rate limited"
133
+ },
134
+ "usage": {
135
+ "agent": "claude",
136
+ "model": "claude-opus-4-7",
137
+ "input_tokens": 100,
138
+ "output_tokens": 10,
139
+ "cached_tokens": 10,
140
+ "cost_usd": 0.01,
141
+ "duration_ms": 1000
142
+ }
143
+ }
144
+ ```
145
+
146
+ `classification` must be `"rate_limit_model"` and `reset_at_epoch` must be approximately
147
+ `now + 60`. Clean up with `rm -rf /tmp/verify-0.1.27`.
148
+
149
+ ## Impact summary
150
+
151
+ Supervisors that dispatch semantically on `classification == "rate_limit_account"` (e.g. "this
152
+ is the 5-hour quota — wait until reset") will no longer trigger that path for infrastructure
153
+ 429s with `rateLimitType: null`. Instead, a `rate_limit_model` event fires with a 60-second
154
+ `reset_at_epoch`.
155
+
156
+ Supervisors that dispatch only on `reset_at_epoch` (ignoring classification) will see a shorter
157
+ wait (60s instead of ~300s) for infra 429s — a net improvement.
158
+
159
+ Supervisors subscribed to the legacy `rate_limit_rejected` event are unaffected: that event
160
+ only fires for genuine `rate_limit_account` (five_hour) events, which continue to work as
161
+ before.
162
+
163
+ ## What did NOT change
164
+
165
+ - `transient_error_detected` event schema — field names, field types unchanged.
166
+ - `_BACK_OFF_DEFAULTS` table — unchanged.
167
+ - Legacy `rate_limit_rejected` back-compat emission for `rate_limit_account` — unchanged.
168
+ - Other plugins (gemini) — no equivalent `rate_limit_event` semantics; not touched.
169
+ - Public API surface — no new functions, no new event kinds, no signature changes.
@@ -4,6 +4,7 @@
4
4
  from __future__ import annotations
5
5
 
6
6
  import json
7
+ import time
7
8
  from unittest.mock import MagicMock, patch
8
9
 
9
10
  from tests._test_helpers import make_hook_context, write_round_log
@@ -355,3 +356,48 @@ def test_given_claude_log_without_assistant_event_when_extracted_then_model_unkn
355
356
  with patch(f"{_MOD}.time.time", return_value=1000):
356
357
  ClaudeErrorDetector().after_round(make_hook_context(tmp_path), result=MagicMock())
357
358
  assert usage_emit.call_args.kwargs["model"] == "unknown"
359
+
360
+
361
+ def test_given_429_with_null_rate_limit_type_when_classified_then_rate_limit_model(tmp_path):
362
+ """rate_limit_event with rateLimitType=null + api_error_status=429 must classify as
363
+ rate_limit_model (infra), not rate_limit_account (5h quota).
364
+ """
365
+ from agent_runner.builtin_plugins.claude_rate_limit import _parse_claude_log
366
+
367
+ log = tmp_path / "round-1.log"
368
+ assistant_line = (
369
+ '{"type":"assistant","message":{"model":"claude-opus-4-7",'
370
+ '"content":[{"type":"text","text":"API Error: rate limited"}]}}\n'
371
+ )
372
+ result_line = (
373
+ '{"type":"result","is_error":true,"api_error_status":429,'
374
+ '"stop_reason":"stop_sequence","result":"API Error: rate limited",'
375
+ '"usage":{"input_tokens":100,"output_tokens":10,"cache_read_input_tokens":0},'
376
+ '"duration_ms":1000,"total_cost_usd":0.01}\n'
377
+ )
378
+ log.write_text(
379
+ '{"type":"rate_limit_event","rate_limit_info":{"status":"rejected","rateLimitType":null}}\n'
380
+ + assistant_line
381
+ + result_line,
382
+ encoding="utf-8",
383
+ )
384
+ parsed = _parse_claude_log(log)
385
+ assert parsed["transient_error"]["classification"] == "rate_limit_model"
386
+ # reset_at_epoch ≈ now + 60 (_BACK_OFF_DEFAULTS["rate_limit_model"])
387
+ now = int(time.time())
388
+ assert now + 55 <= parsed["transient_error"]["reset_at_epoch"] <= now + 65
389
+
390
+
391
+ def test_given_rate_limit_event_null_type_without_result_when_classified_then_none(tmp_path):
392
+ """Edge: rate_limit_event with rateLimitType=null but no result_event returns no
393
+ transient_error (without a status code we can't bucket; supervisor uses generic retry).
394
+ """
395
+ from agent_runner.builtin_plugins.claude_rate_limit import _parse_claude_log
396
+
397
+ log = tmp_path / "round-1.log"
398
+ log.write_text(
399
+ '{"type":"rate_limit_event","rate_limit_info":{"status":"rejected","rateLimitType":null}}\n',
400
+ encoding="utf-8",
401
+ )
402
+ parsed = _parse_claude_log(log)
403
+ assert "transient_error" not in parsed