code-mower 0.9.2b1__tar.gz → 0.9.3b1__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 (352) hide show
  1. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/PKG-INFO +13 -12
  2. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/README.md +12 -11
  3. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/pyproject.toml +1 -1
  4. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/__init__.py +1 -1
  5. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/board.py +27 -1
  6. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/doctor_checks/__init__.py +5 -1
  7. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/doctor_checks/adoption.py +36 -5
  8. code_mower-0.9.3b1/src/code_mower/doctor_checks/github_trusted_authors.py +72 -0
  9. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/doctor_checks/provider_review_hygiene.py +22 -10
  10. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/doctor_checks/providers.py +2 -0
  11. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/doctor_checks/runner.py +19 -6
  12. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/lane_status.py +11 -6
  13. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/migration.py +139 -6
  14. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/templates/workflows/builder-provenance.yml.j2 +1 -1
  15. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower.egg-info/PKG-INFO +13 -12
  16. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/templates/workflows/builder-provenance.yml.j2 +1 -1
  17. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/tests/test_board.py +13 -0
  18. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/tests/test_doctor_github_checks.py +26 -1
  19. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/tests/test_doctor_provider_review_hygiene.py +22 -0
  20. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/tests/test_doctor_registry.py +84 -9
  21. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/tests/test_lane_status.py +5 -0
  22. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/tests/test_release_hygiene.py +208 -34
  23. code_mower-0.9.2b1/src/code_mower/doctor_checks/github_trusted_authors.py +0 -38
  24. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/CODE_OF_CONDUCT.md +0 -0
  25. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/LICENSE +0 -0
  26. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/MANIFEST.in +0 -0
  27. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/NOTICE +0 -0
  28. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/SUPPORT.md +0 -0
  29. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/requirements/requirements.txt +0 -0
  30. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/setup.cfg +0 -0
  31. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/adapters/__init__.py +0 -0
  32. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/adapters/_base.py +0 -0
  33. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/adapters/cursor_bugbot.py +0 -0
  34. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/adapters/gitar.py +0 -0
  35. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/adapters/greptile.py +0 -0
  36. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/adapters/qodo.py +0 -0
  37. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/antigravity_cli_audit_pr.py +0 -0
  38. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/antigravity_sdk_probe.py +0 -0
  39. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/audit_handoff_log.py +0 -0
  40. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/audit_labeler_lib.py +0 -0
  41. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/audit_limits.py +0 -0
  42. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/audit_progress.py +0 -0
  43. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/blind_review_artifacts.py +0 -0
  44. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/blind_review_coordinator.py +0 -0
  45. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/board_store.py +0 -0
  46. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/bootstrap.py +0 -0
  47. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/builder_experiment.py +0 -0
  48. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/builder_runs.py +0 -0
  49. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/calibration/__init__.py +0 -0
  50. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/calibration/arms.py +0 -0
  51. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/calibration/auto_discovery.py +0 -0
  52. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/calibration/commands.py +0 -0
  53. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/calibration/context_inputs.py +0 -0
  54. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/calibration/corpus.py +0 -0
  55. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/calibration/effect_report.py +0 -0
  56. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/calibration/evidence.py +0 -0
  57. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/calibration/evidence_report.py +0 -0
  58. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/calibration/identity.py +0 -0
  59. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/calibration/metrics.py +0 -0
  60. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/calibration/overlap.py +0 -0
  61. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/calibration/planning.py +0 -0
  62. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/calibration/policy.py +0 -0
  63. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/calibration/results.py +0 -0
  64. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/calibration/run_results.py +0 -0
  65. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/calibration/run_status.py +0 -0
  66. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/calibration/runner.py +0 -0
  67. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/calibration/truth.py +0 -0
  68. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/calibration/value_report.py +0 -0
  69. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/checks.py +0 -0
  70. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/claude_audit_pr.py +0 -0
  71. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/claude_cli_bounce.py +0 -0
  72. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/claude_cli_environment.py +0 -0
  73. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/clear_stale.py +0 -0
  74. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/cli.py +0 -0
  75. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/cloud.py +0 -0
  76. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/cloud_client/__init__.py +0 -0
  77. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/cloud_client/bundle.py +0 -0
  78. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/cloud_client/doctor.py +0 -0
  79. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/cloud_client/dogfood.py +0 -0
  80. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/cloud_client/endpoints.py +0 -0
  81. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/cloud_client/errors.py +0 -0
  82. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/cloud_client/events.py +0 -0
  83. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/cloud_client/export.py +0 -0
  84. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/cloud_client/git_metadata.py +0 -0
  85. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/cloud_client/manifest.py +0 -0
  86. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/cloud_client/operations.py +0 -0
  87. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/cloud_client/reports.py +0 -0
  88. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/cloud_client/setup.py +0 -0
  89. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/cloud_client/tokens.py +0 -0
  90. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/cloud_client/upload.py +0 -0
  91. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/code_mower_calibration.py +0 -0
  92. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/code_mower_context_packs.py +0 -0
  93. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/code_mower_merge.py +0 -0
  94. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/code_mower_telemetry.py +0 -0
  95. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/coderabbit_cli_audit_pr.py +0 -0
  96. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/codex_audit_env_preflight.py +0 -0
  97. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/codex_audit_pr.py +0 -0
  98. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/codex_audit_schema_smoke.py +0 -0
  99. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/codex_audit_verdict.schema.json +0 -0
  100. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/config.py +0 -0
  101. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/decisions.py +0 -0
  102. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/doctor.py +0 -0
  103. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/doctor_checks/audit_limits.py +0 -0
  104. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/doctor_checks/cloud.py +0 -0
  105. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/doctor_checks/common.py +0 -0
  106. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/doctor_checks/github.py +0 -0
  107. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/doctor_checks/github_actions.py +0 -0
  108. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/doctor_checks/github_actions_cost.py +0 -0
  109. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/doctor_checks/github_actions_cost_summary.py +0 -0
  110. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/doctor_checks/github_actions_failure_annotations.py +0 -0
  111. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/doctor_checks/github_actions_failure_models.py +0 -0
  112. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/doctor_checks/github_actions_failure_scan.py +0 -0
  113. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/doctor_checks/github_actions_failure_selection.py +0 -0
  114. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/doctor_checks/github_actions_failures.py +0 -0
  115. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/doctor_checks/github_actions_permissions.py +0 -0
  116. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/doctor_checks/github_api.py +0 -0
  117. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/doctor_checks/github_branch.py +0 -0
  118. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/doctor_checks/github_config.py +0 -0
  119. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/doctor_checks/github_human_token.py +0 -0
  120. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/doctor_checks/github_provider.py +0 -0
  121. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/doctor_checks/github_repo.py +0 -0
  122. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/doctor_checks/groups.py +0 -0
  123. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/doctor_checks/models.py +0 -0
  124. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/doctor_checks/output.py +0 -0
  125. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/doctor_checks/presets.py +0 -0
  126. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/doctor_checks/privacy.py +0 -0
  127. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/doctor_checks/provider_api_model.py +0 -0
  128. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/doctor_checks/provider_api_model_openai.py +0 -0
  129. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/doctor_checks/provider_api_model_profiles.py +0 -0
  130. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/doctor_checks/provider_env.py +0 -0
  131. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/doctor_checks/provider_env_required.py +0 -0
  132. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/doctor_checks/provider_env_tokens.py +0 -0
  133. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/doctor_checks/provider_local_audit_setup.py +0 -0
  134. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/doctor_checks/provider_local_cli.py +0 -0
  135. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/doctor_checks/provider_local_cli_commands.py +0 -0
  136. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/doctor_checks/provider_local_cli_probe_config.py +0 -0
  137. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/doctor_checks/provider_probe.py +0 -0
  138. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/doctor_checks/provider_probe_auth.py +0 -0
  139. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/doctor_checks/provider_probe_evaluation.py +0 -0
  140. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/doctor_checks/provider_probe_json.py +0 -0
  141. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/doctor_checks/provider_probe_remediation.py +0 -0
  142. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/doctor_checks/registry.py +0 -0
  143. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/doctor_checks/runtime.py +0 -0
  144. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/doctor_checks/runtime_github_auth.py +0 -0
  145. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/doctor_checks/self_hosted_runner.py +0 -0
  146. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/gate_health.py +0 -0
  147. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/gemini_cli_audit_pr.py +0 -0
  148. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/git_identity.py +0 -0
  149. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/grok_build_audit_pr.py +0 -0
  150. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/hermes_cli_audit_pr.py +0 -0
  151. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/init.py +0 -0
  152. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/lane_configs/__init__.py +0 -0
  153. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/lane_configs/aider.py +0 -0
  154. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/lane_configs/antigravity_cli.py +0 -0
  155. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/lane_configs/claude.py +0 -0
  156. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/lane_configs/codex.py +0 -0
  157. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/lane_configs/devin.py +0 -0
  158. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/lane_configs/gemini_cli.py +0 -0
  159. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/lane_configs/grok_build.py +0 -0
  160. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/lane_configs/hermes_cli.py +0 -0
  161. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/lane_configs/local_llm.py +0 -0
  162. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/local_llm_audit_pr.py +0 -0
  163. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/local_llm_bakeoff.py +0 -0
  164. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/local_llm_calibration.py +0 -0
  165. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/local_llm_profiles.py +0 -0
  166. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/migration_install.py +0 -0
  167. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/migration_mirror.py +0 -0
  168. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/migration_readiness.py +0 -0
  169. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/migration_rehearsal.py +0 -0
  170. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/next_steps.py +0 -0
  171. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/package.py +0 -0
  172. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/package_content.py +0 -0
  173. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/package_manifest.py +0 -0
  174. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/package_paths.py +0 -0
  175. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/package_rendering.py +0 -0
  176. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/package_static.py +0 -0
  177. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/plan_context.py +0 -0
  178. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/prompts.py +0 -0
  179. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/provider_registry.py +0 -0
  180. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/provider_runners/__init__.py +0 -0
  181. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/provider_runners/comments.py +0 -0
  182. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/provider_runners/exit_codes.py +0 -0
  183. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/provider_runners/git.py +0 -0
  184. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/provider_runners/github_auth.py +0 -0
  185. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/provider_runners/github_pr.py +0 -0
  186. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/provider_runners/pr_worktree.py +0 -0
  187. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/provider_runners/process.py +0 -0
  188. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/provider_runners/repo_paths.py +0 -0
  189. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/provider_runners/text_schema.py +0 -0
  190. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/provider_runners/verdict_artifacts.py +0 -0
  191. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/provider_runners/workspace.py +0 -0
  192. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/providers/__init__.py +0 -0
  193. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/providers/local_cli.py +0 -0
  194. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/providers/provenance.py +0 -0
  195. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/release_readiness.py +0 -0
  196. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/reviewer_metrics.py +0 -0
  197. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/reviewer_spend.py +0 -0
  198. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/saas_reviewer_labeler.py +0 -0
  199. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/secrets.py +0 -0
  200. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/templates/builder-experiment.example.json +0 -0
  201. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/templates/calibration-corpus.example.json +0 -0
  202. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/templates/calibration-corpus.json +0 -0
  203. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/templates/code-mower.example.yml +0 -0
  204. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/templates/context-packs.example.json +0 -0
  205. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/templates/lane_prompts/base-audit.md +0 -0
  206. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/templates/lane_prompts/calibration-policy.md +0 -0
  207. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/templates/lane_prompts/context-driven-quality.md +0 -0
  208. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/templates/lane_prompts/docs-design.md +0 -0
  209. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/templates/lane_prompts/generic-programming.md +0 -0
  210. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/templates/lane_prompts/operability.md +0 -0
  211. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/templates/lane_prompts/package-runtime.md +0 -0
  212. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/templates/lane_prompts/plan-conformance.md +0 -0
  213. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/templates/lane_prompts/security-threat-model.md +0 -0
  214. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/templates/lanes/README.md +0 -0
  215. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/templates/lanes/claude.md +0 -0
  216. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/templates/lanes/codex.md +0 -0
  217. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/templates/lanes/cursor.md +0 -0
  218. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/templates/lanes/generic.md +0 -0
  219. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/templates/lanes/run_mac_lane.sh +0 -0
  220. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/templates/product-support/code_mower +0 -0
  221. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/templates/product-support/code_mower_standalone_pin.env +0 -0
  222. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/templates/product-support/code_mower_standalone_shadow.sh +0 -0
  223. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/templates/product-support/run_claude_audit_pr.sh +0 -0
  224. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/templates/product-support/run_codex_audit_pr.sh +0 -0
  225. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/templates/product-support/safe_gh_comment.py +0 -0
  226. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/templates/product-support/status_report.py +0 -0
  227. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/templates/providers.yml +0 -0
  228. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/templates/reviewer-spend.example.json +0 -0
  229. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/templates/reviewer-value-report.example.md +0 -0
  230. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/templates/workflows/audit-label-cleanup.yml.j2 +0 -0
  231. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/templates/workflows/code-mower-agent-pr-labeler.yml.j2 +0 -0
  232. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/templates/workflows/code-mower-fix-round-dispatch.yml.j2 +0 -0
  233. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/templates/workflows/code-mower-gate-health.yml.j2 +0 -0
  234. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/templates/workflows/code-mower-gate.yml.j2 +0 -0
  235. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/templates/workflows/dispatch-lanes.yml.j2 +0 -0
  236. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/templates/workflows/hosted-bridge.yml.j2 +0 -0
  237. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/templates/workflows/lane-mac-runner.yml.j2 +0 -0
  238. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/templates/workflows/local-cli-audit.yml.j2 +0 -0
  239. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/templates/workflows/needs-owner-notify.yml.j2 +0 -0
  240. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/templates/workflows/private-standalone-shadow.yml.j2 +0 -0
  241. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/templates/workflows/review-clear-stale.yml.j2 +0 -0
  242. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/templates/workflows/saas-reviewer-labeler.yml.j2 +0 -0
  243. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/templates/workflows/self-hosted-local-audit.yml.j2 +0 -0
  244. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/templates/workflows/trailer-comment-labeler.yml.j2 +0 -0
  245. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/templates/workflows/weekly-status.yml.j2 +0 -0
  246. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/trailer_comment_labeler.py +0 -0
  247. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/versioning.py +0 -0
  248. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/work_orders.py +0 -0
  249. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower/workflow_actionlint.py +0 -0
  250. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower.egg-info/SOURCES.txt +0 -0
  251. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower.egg-info/dependency_links.txt +0 -0
  252. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower.egg-info/entry_points.txt +0 -0
  253. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower.egg-info/requires.txt +0 -0
  254. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/src/code_mower.egg-info/top_level.txt +0 -0
  255. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/templates/builder-experiment.example.json +0 -0
  256. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/templates/calibration-corpus.example.json +0 -0
  257. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/templates/calibration-corpus.json +0 -0
  258. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/templates/code-mower.yml.j2 +0 -0
  259. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/templates/context-packs.example.json +0 -0
  260. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/templates/cursor/BUGBOT.md +0 -0
  261. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/templates/lanes/README.md +0 -0
  262. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/templates/lanes/claude.md +0 -0
  263. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/templates/lanes/codex.md +0 -0
  264. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/templates/lanes/cursor.md +0 -0
  265. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/templates/lanes/generic.md +0 -0
  266. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/templates/lanes/run_mac_lane.sh +0 -0
  267. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/templates/providers/acp_bridge.yml +0 -0
  268. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/templates/providers/aider.yml +0 -0
  269. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/templates/providers/antigravity_cli.yml +0 -0
  270. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/templates/providers/claude_audit.yml +0 -0
  271. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/templates/providers/claude_review.yml +0 -0
  272. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/templates/providers/coderabbit_cli.yml +0 -0
  273. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/templates/providers/codex.yml +0 -0
  274. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/templates/providers/cursor_bugbot.yml +0 -0
  275. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/templates/providers/devin.yml +0 -0
  276. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/templates/providers/gemini_cli.yml +0 -0
  277. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/templates/providers/gitar.yml +0 -0
  278. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/templates/providers/greptile.yml +0 -0
  279. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/templates/providers/hermes_cli.yml +0 -0
  280. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/templates/providers/local_llm.yml +0 -0
  281. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/templates/providers/qodo.yml +0 -0
  282. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/templates/providers.yml +0 -0
  283. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/templates/reviewer-spend.example.json +0 -0
  284. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/templates/reviewer-value-report.example.md +0 -0
  285. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/templates/workflows/audit-label-cleanup.yml.j2 +0 -0
  286. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/templates/workflows/blind-review-artifacts-dry-run.yml.j2 +0 -0
  287. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/templates/workflows/code-mower-agent-pr-labeler.yml.j2 +0 -0
  288. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/templates/workflows/code-mower-fix-round-dispatch.yml.j2 +0 -0
  289. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/templates/workflows/code-mower-gate-health.yml.j2 +0 -0
  290. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/templates/workflows/code-mower-gate.yml.j2 +0 -0
  291. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/templates/workflows/dispatch-lanes.yml.j2 +0 -0
  292. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/templates/workflows/hosted-bridge.yml.j2 +0 -0
  293. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/templates/workflows/lane-mac-runner.yml.j2 +0 -0
  294. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/templates/workflows/local-cli-audit.yml.j2 +0 -0
  295. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/templates/workflows/private-standalone-shadow.yml.j2 +0 -0
  296. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/templates/workflows/review-clear-stale.yml.j2 +0 -0
  297. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/templates/workflows/saas-reviewer-labeler.yml.j2 +0 -0
  298. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/templates/workflows/self-hosted-local-audit.yml.j2 +0 -0
  299. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/templates/workflows/trailer-comment-labeler.yml.j2 +0 -0
  300. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/tests/test_antigravity_sdk_probe.py +0 -0
  301. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/tests/test_audit_comment_posture.py +0 -0
  302. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/tests/test_audit_limits.py +0 -0
  303. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/tests/test_builder_experiment.py +0 -0
  304. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/tests/test_builder_identity.py +0 -0
  305. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/tests/test_builder_runs.py +0 -0
  306. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/tests/test_calibration_effect_report.py +0 -0
  307. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/tests/test_calibration_truth.py +0 -0
  308. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/tests/test_checks.py +0 -0
  309. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/tests/test_claude_audit_pr.py +0 -0
  310. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/tests/test_claude_cli_bounce.py +0 -0
  311. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/tests/test_clear_stale.py +0 -0
  312. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/tests/test_cloud_client.py +0 -0
  313. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/tests/test_cloud_git_metadata.py +0 -0
  314. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/tests/test_cloud_manifest.py +0 -0
  315. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/tests/test_cloud_reports.py +0 -0
  316. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/tests/test_coderabbit_cli_audit_pr.py +0 -0
  317. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/tests/test_codex_audit_env_preflight.py +0 -0
  318. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/tests/test_codex_audit_pr.py +0 -0
  319. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/tests/test_decision_audit_integration.py +0 -0
  320. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/tests/test_decisions.py +0 -0
  321. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/tests/test_doctor_actions_cost_summary.py +0 -0
  322. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/tests/test_doctor_actions_failure_selection.py +0 -0
  323. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/tests/test_doctor_boundaries.py +0 -0
  324. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/tests/test_doctor_output.py +0 -0
  325. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/tests/test_doctor_privacy.py +0 -0
  326. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/tests/test_doctor_provider_env_required.py +0 -0
  327. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/tests/test_doctor_provider_env_tokens.py +0 -0
  328. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/tests/test_doctor_provider_local_audit_setup.py +0 -0
  329. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/tests/test_doctor_provider_probe.py +0 -0
  330. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/tests/test_doctor_runtime.py +0 -0
  331. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/tests/test_doctor_self_hosted_runner.py +0 -0
  332. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/tests/test_gate_health.py +0 -0
  333. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/tests/test_init_actionlint.py +0 -0
  334. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/tests/test_init_build_loop.py +0 -0
  335. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/tests/test_local_llm_github_helpers.py +0 -0
  336. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/tests/test_migration_setup_drift.py +0 -0
  337. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/tests/test_plan_context.py +0 -0
  338. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/tests/test_prompts.py +0 -0
  339. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/tests/test_provider_fixture_contracts.py +0 -0
  340. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/tests/test_provider_local_cli.py +0 -0
  341. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/tests/test_provider_runners_comments.py +0 -0
  342. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/tests/test_provider_runners_git.py +0 -0
  343. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/tests/test_provider_runners_github_pr.py +0 -0
  344. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/tests/test_provider_runners_pr_worktree.py +0 -0
  345. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/tests/test_provider_runners_process.py +0 -0
  346. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/tests/test_provider_runners_repo_paths.py +0 -0
  347. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/tests/test_provider_runners_text_schema.py +0 -0
  348. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/tests/test_provider_runners_workspace.py +0 -0
  349. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/tests/test_reviewer_metrics_core.py +0 -0
  350. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/tests/test_reviewer_spend.py +0 -0
  351. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/tests/test_trailer_comment_labeler.py +0 -0
  352. {code_mower-0.9.2b1 → code_mower-0.9.3b1}/tests/test_work_orders.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: code-mower
3
- Version: 0.9.2b1
3
+ Version: 0.9.3b1
4
4
  Summary: Multi-reviewer AI code audit orchestration
5
5
  License-Expression: Apache-2.0
6
6
  Requires-Python: >=3.12
@@ -113,8 +113,9 @@ Plain `board serve` is read-only. If the default Board port is busy, the CLI
113
113
  uses a nearby free loopback port and prints the URL; an explicit `--port` stays
114
114
  strict and reports a friendly conflict. To build local history while the browser
115
115
  view is open, run `code-mower board serve --repo OWNER/REPO --record-events`; it
116
- records at most one snapshot every 60 seconds by default. To append one snapshot
117
- without serving the browser view, run
116
+ records at most one snapshot every 60 seconds by default. The Board header shows
117
+ the Code Mower version serving the page and flags when a restart is needed after
118
+ an upgrade. To append one snapshot without serving the browser view, run
118
119
  `code-mower board record --repo OWNER/REPO` from the repository checkout; it
119
120
  writes metadata-only snapshots to `.code-mower/board/events.jsonl` with default
120
121
  14-day and 500-event retention. `code-mower board events` prints recent stored
@@ -169,13 +170,13 @@ after reinstalling, especially when switching between pipx and uv.
169
170
  | C. Builder experiment | You want to compare authoring loops before trusting them broadly. | Use a work order or experiment spec, run `code-mower builder-experiment run` around an explicit command, then review the source-free `authoringRun` artifact and normal audit evidence. | [Builder Experiments](docs/builder-experiments.md) |
170
171
 
171
172
  The current package-index announcement entry point is the tagged
172
- [Try Code Mower In 10 Minutes](https://github.com/codemower-ai/code-mower/blob/v0.9.2-beta.1/docs/try-in-10-minutes.md)
173
+ [Try Code Mower In 10 Minutes](https://github.com/codemower-ai/code-mower/blob/v0.9.3-beta.1/docs/try-in-10-minutes.md)
173
174
  guide. The v0.9 beta includes the completed native Board work plus the adoption
174
- and upgrade hardening from recent install rehearsals; v0.9.2 keeps the path
175
- simple by removing the retired third-party observe bridge, softening
176
- dispatch-token expiry metadata when the secret is present, and making
177
- stale-audit waits name the runner/dispatcher requeue path. Package-only users
178
- can start from the public package rather than a source checkout.
175
+ and upgrade hardening from recent install rehearsals; v0.9.3 keeps the path
176
+ smooth by clarifying starter-package diagnostics, surfacing richer top-level
177
+ lane status detail, showing Board version drift, and reporting standalone pin
178
+ drift during existing-repo upgrades. Package-only users can start from the
179
+ public package rather than a source checkout.
179
180
 
180
181
  ## What Calibration Does And Does Not Prove
181
182
 
@@ -206,7 +207,7 @@ Provider-contract baseline for the next release train:
206
207
 
207
208
  For release verification,
208
209
  [First-User Install Rehearsal](docs/first-user-install-rehearsal.md) records
209
- the package-index procedure for `v0.9.2-beta.1` / `code-mower==0.9.2b1`. The
210
+ the package-index procedure for `v0.9.3-beta.1` / `code-mower==0.9.3b1`. The
210
211
  GitHub release records the workflow and rehearsal evidence for the exact tag.
211
212
 
212
213
  ## Optional: Plan Before Coding
@@ -392,8 +393,8 @@ measurement work.
392
393
 
393
394
  ## Installation Status
394
395
 
395
- The current package-index beta baseline is `v0.9.2-beta.1`, with pinned package
396
- install spec `code-mower==0.9.2b1`. Release evidence is recorded on the GitHub
396
+ The current package-index beta baseline is `v0.9.3-beta.1`, with pinned package
397
+ install spec `code-mower==0.9.3b1`. Release evidence is recorded on the GitHub
397
398
  release and in the first-user install rehearsal. The public repository is
398
399
  [codemower-ai/code-mower](https://github.com/codemower-ai/code-mower), and
399
400
  GitHub releases remain the auditable source for tags, build artifacts, and
@@ -96,8 +96,9 @@ Plain `board serve` is read-only. If the default Board port is busy, the CLI
96
96
  uses a nearby free loopback port and prints the URL; an explicit `--port` stays
97
97
  strict and reports a friendly conflict. To build local history while the browser
98
98
  view is open, run `code-mower board serve --repo OWNER/REPO --record-events`; it
99
- records at most one snapshot every 60 seconds by default. To append one snapshot
100
- without serving the browser view, run
99
+ records at most one snapshot every 60 seconds by default. The Board header shows
100
+ the Code Mower version serving the page and flags when a restart is needed after
101
+ an upgrade. To append one snapshot without serving the browser view, run
101
102
  `code-mower board record --repo OWNER/REPO` from the repository checkout; it
102
103
  writes metadata-only snapshots to `.code-mower/board/events.jsonl` with default
103
104
  14-day and 500-event retention. `code-mower board events` prints recent stored
@@ -152,13 +153,13 @@ after reinstalling, especially when switching between pipx and uv.
152
153
  | C. Builder experiment | You want to compare authoring loops before trusting them broadly. | Use a work order or experiment spec, run `code-mower builder-experiment run` around an explicit command, then review the source-free `authoringRun` artifact and normal audit evidence. | [Builder Experiments](docs/builder-experiments.md) |
153
154
 
154
155
  The current package-index announcement entry point is the tagged
155
- [Try Code Mower In 10 Minutes](https://github.com/codemower-ai/code-mower/blob/v0.9.2-beta.1/docs/try-in-10-minutes.md)
156
+ [Try Code Mower In 10 Minutes](https://github.com/codemower-ai/code-mower/blob/v0.9.3-beta.1/docs/try-in-10-minutes.md)
156
157
  guide. The v0.9 beta includes the completed native Board work plus the adoption
157
- and upgrade hardening from recent install rehearsals; v0.9.2 keeps the path
158
- simple by removing the retired third-party observe bridge, softening
159
- dispatch-token expiry metadata when the secret is present, and making
160
- stale-audit waits name the runner/dispatcher requeue path. Package-only users
161
- can start from the public package rather than a source checkout.
158
+ and upgrade hardening from recent install rehearsals; v0.9.3 keeps the path
159
+ smooth by clarifying starter-package diagnostics, surfacing richer top-level
160
+ lane status detail, showing Board version drift, and reporting standalone pin
161
+ drift during existing-repo upgrades. Package-only users can start from the
162
+ public package rather than a source checkout.
162
163
 
163
164
  ## What Calibration Does And Does Not Prove
164
165
 
@@ -189,7 +190,7 @@ Provider-contract baseline for the next release train:
189
190
 
190
191
  For release verification,
191
192
  [First-User Install Rehearsal](docs/first-user-install-rehearsal.md) records
192
- the package-index procedure for `v0.9.2-beta.1` / `code-mower==0.9.2b1`. The
193
+ the package-index procedure for `v0.9.3-beta.1` / `code-mower==0.9.3b1`. The
193
194
  GitHub release records the workflow and rehearsal evidence for the exact tag.
194
195
 
195
196
  ## Optional: Plan Before Coding
@@ -375,8 +376,8 @@ measurement work.
375
376
 
376
377
  ## Installation Status
377
378
 
378
- The current package-index beta baseline is `v0.9.2-beta.1`, with pinned package
379
- install spec `code-mower==0.9.2b1`. Release evidence is recorded on the GitHub
379
+ The current package-index beta baseline is `v0.9.3-beta.1`, with pinned package
380
+ install spec `code-mower==0.9.3b1`. Release evidence is recorded on the GitHub
380
381
  release and in the first-user install rehearsal. The public repository is
381
382
  [codemower-ai/code-mower](https://github.com/codemower-ai/code-mower), and
382
383
  GitHub releases remain the auditable source for tags, build artifacts, and
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "code-mower"
7
- version = "0.9.2b1"
7
+ version = "0.9.3b1"
8
8
  description = "Multi-reviewer AI code audit orchestration"
9
9
  requires-python = ">=3.12"
10
10
  readme = "README.md"
@@ -1,3 +1,3 @@
1
1
  """Code Mower package."""
2
2
 
3
- __version__ = "0.9.2b1"
3
+ __version__ = "0.9.3b1"
@@ -15,11 +15,13 @@ from dataclasses import dataclass
15
15
  from datetime import UTC, datetime
16
16
  from http import HTTPStatus
17
17
  from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
18
+ from importlib import metadata
18
19
  from pathlib import Path
19
20
  from threading import Lock
20
21
  from typing import Any
21
22
  from urllib.parse import urlparse
22
23
 
24
+ from . import __version__ as CODE_MOWER_VERSION
23
25
  from . import board_store
24
26
  from . import lane_status
25
27
  from . import reviewer_spend
@@ -120,6 +122,22 @@ def _candidate_ports(config: BoardConfig) -> list[int]:
120
122
  return list(range(config.port, last_port + 1))
121
123
 
122
124
 
125
+ def _installed_package_version() -> str:
126
+ try:
127
+ return metadata.version("code-mower")
128
+ except metadata.PackageNotFoundError:
129
+ return ""
130
+
131
+
132
+ def board_version_payload() -> dict[str, Any]:
133
+ installed_version = _installed_package_version()
134
+ return {
135
+ "serving_version": CODE_MOWER_VERSION,
136
+ "installed_version": installed_version,
137
+ "restart_recommended": bool(installed_version and installed_version != CODE_MOWER_VERSION),
138
+ }
139
+
140
+
123
141
  def _explicit_port_conflict_message(host: str, port: int) -> str:
124
142
  suggestions = list(range(port + 1, min(65535, port + 3) + 1))
125
143
  suggestion_text = f" such as {', '.join(str(candidate) for candidate in suggestions)}" if suggestions else ""
@@ -171,6 +189,7 @@ def status_payload(
171
189
  payload["board"] = {
172
190
  "schema": "code_mower.board.v1",
173
191
  "mode": "local_recording" if config.record_events else "local_read_only",
192
+ "version": board_version_payload(),
174
193
  "refresh_seconds": config.refresh_seconds,
175
194
  "local_paths": "shown" if config.show_local_paths else "redacted",
176
195
  "recording": {
@@ -628,7 +647,7 @@ def render_board_html(config: BoardConfig) -> str:
628
647
  </head>
629
648
  <body>
630
649
  <header>
631
- <div><h1>Code Mower Board</h1><div class="muted" id="repo"></div></div>
650
+ <div><h1>Code Mower Board</h1><div class="muted" id="repo"></div><div class="muted" id="version"></div></div>
632
651
  <div class="muted" id="generated">Loading...</div>
633
652
  </header>
634
653
  <main>
@@ -671,6 +690,12 @@ def render_board_html(config: BoardConfig) -> str:
671
690
  }}
672
691
  function render(data) {{
673
692
  document.getElementById("repo").textContent = REPO;
693
+ const version = data.board?.version || {{}};
694
+ const servingVersion = version.serving_version || "unknown";
695
+ const installedVersion = version.installed_version || servingVersion;
696
+ document.getElementById("version").textContent = version.restart_recommended
697
+ ? `serving ${{servingVersion}}; installed ${{installedVersion}} available after restart`
698
+ : `serving ${{servingVersion}}`;
674
699
  document.getElementById("generated").innerHTML = data.generated_at ? `Generated ${{localTime(data.generated_at)}}` : "Loading...";
675
700
  const prs = data.remote?.pull_requests || [];
676
701
  const runs = data.remote?.workflow_runs || [];
@@ -683,6 +708,7 @@ def render_board_html(config: BoardConfig) -> str:
683
708
  const spendGroups = spend.groups || [];
684
709
  put("summary", [
685
710
  `<div class="metric"><span class="muted">Next action</span><b>${{esc(data.next_action || "inspect")}}</b></div>`,
711
+ data.next_detail ? `<div class="metric"><span class="muted">Detail</span><b>${{esc(data.next_detail)}}</b></div>` : "",
686
712
  `<div class="metric"><span class="muted">GitHub</span><b class="${{data.remote?.available ? "ok" : "warn"}}">${{data.remote?.available ? "available" : "unavailable"}}</b></div>`,
687
713
  `<div class="metric"><span class="muted">Open PRs</span><b>${{prs.length}}</b></div>`,
688
714
  `<div class="metric"><span class="muted">Owner queue</span><b class="${{ownerQueue.length ? "warn" : "ok"}}">${{ownerQueue.length}}</b></div>`,
@@ -32,7 +32,10 @@ from .github_human_token import (
32
32
  human_automation_token_config,
33
33
  human_automation_token_required,
34
34
  )
35
- from .github_trusted_authors import trusted_author_variable_statuses
35
+ from .github_trusted_authors import (
36
+ trusted_author_variable_probe,
37
+ trusted_author_variable_statuses,
38
+ )
36
39
  from .groups import GROUP_LABELS, doctor_check_group_id
37
40
  from .models import (
38
41
  STATUS_FAIL,
@@ -113,6 +116,7 @@ __all__ = [
113
116
  "check_macos_runner_launchagent",
114
117
  "check_github_setup",
115
118
  "check_human_automation_token",
119
+ "trusted_author_variable_probe",
116
120
  "trusted_author_variable_statuses",
117
121
  "check_repository_posture",
118
122
  "check_lane_runtime",
@@ -170,7 +170,7 @@ def check_adoption_posture_guidance(
170
170
  name="doctor.adoption.posture_hint",
171
171
  status=STATUS_WARN,
172
172
  message=(
173
- "default reviewer-gate posture found local provider setup gaps"
173
+ "default reviewer-gate posture checks local reviewer CLIs on this host"
174
174
  ),
175
175
  detail={
176
176
  "adoption_posture": adoption_posture,
@@ -186,9 +186,12 @@ def check_adoption_posture_guidance(
186
186
  ],
187
187
  },
188
188
  remediation=(
189
- "If this host only coordinates or observes hosted builders, "
190
- "rerun with `--orchestrator-only` or `--hosted-builders`; "
191
- "otherwise finish the local CLI/token setup for the listed lanes."
189
+ "If this host only coordinates work, rerun "
190
+ "`code-mower doctor --adoption --orchestrator-only --repo OWNER/REPO`. "
191
+ "If it observes hosted builder lanes, rerun "
192
+ "`code-mower doctor --adoption --hosted-builders --repo OWNER/REPO`. "
193
+ "Only keep the default reviewer-gate posture on machines that "
194
+ "run local reviewer CLIs."
192
195
  ),
193
196
  ),
194
197
  )
@@ -205,6 +208,7 @@ def check_adoption_setup(
205
208
  config_source: str = "",
206
209
  repo_root: Path | None = None,
207
210
  trusted_author_variables: Mapping[str, str] | None = None,
211
+ trusted_author_variable_errors: Mapping[str, Any] | None = None,
208
212
  ) -> tuple[DoctorCheck, ...]:
209
213
  """Return first-run adoption posture checks."""
210
214
 
@@ -371,10 +375,16 @@ def check_adoption_setup(
371
375
  }
372
376
  if trusted_author_variables is not None:
373
377
  variable_status = {
374
- name: str(trusted_author_variables.get(name) or "missing")
378
+ name: str(trusted_author_variables.get(name) or "not_confirmed")
375
379
  for name in TRUSTED_AUDIT_AUTHOR_VARIABLES
376
380
  }
377
381
  trusted_detail["variable_status"] = variable_status
382
+ if trusted_author_variable_errors:
383
+ trusted_detail["variable_read_errors"] = {
384
+ name: trusted_author_variable_errors[name]
385
+ for name in sorted(trusted_author_variable_errors)
386
+ if name in TRUSTED_AUDIT_AUTHOR_VARIABLES
387
+ }
378
388
  all_present = all(
379
389
  variable_status[name] == "present" for name in TRUSTED_AUDIT_AUTHOR_VARIABLES
380
390
  )
@@ -388,6 +398,27 @@ def check_adoption_setup(
388
398
  )
389
399
  )
390
400
  return tuple(checks)
401
+ if any(
402
+ variable_status[name] == "not_confirmed"
403
+ for name in TRUSTED_AUDIT_AUTHOR_VARIABLES
404
+ ):
405
+ checks.append(
406
+ DoctorCheck(
407
+ name="doctor.adoption.trusted_authors",
408
+ status=STATUS_WARN,
409
+ message=(
410
+ "trusted audit-comment author variables were not fully confirmed"
411
+ ),
412
+ detail=trusted_detail,
413
+ remediation=(
414
+ "Ensure `gh auth status` can read repository Actions "
415
+ "variables for this repo, then set CLAUDE_AUDIT_BOT_AUTHORS "
416
+ "and CODEX_BOT_AUTHORS to the GitHub logins that may post "
417
+ "trusted audit verdicts."
418
+ ),
419
+ )
420
+ )
421
+ return tuple(checks)
391
422
 
392
423
  checks.append(
393
424
  DoctorCheck(
@@ -0,0 +1,72 @@
1
+ """GitHub repository variable checks for trusted audit-comment authors."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections.abc import Iterable
6
+ from typing import Any
7
+
8
+ from .github_api import _github_api_json
9
+
10
+
11
+ def trusted_author_variable_probe(
12
+ *,
13
+ gh_path: str,
14
+ slug: str,
15
+ variables: Iterable[str],
16
+ http_timeout: int,
17
+ ) -> dict[str, Any]:
18
+ """Return safe probe results for trusted-author repository variables."""
19
+
20
+ statuses: dict[str, str] = {}
21
+ read_errors: dict[str, dict[str, Any]] = {}
22
+ for variable in variables:
23
+ name = str(variable).strip()
24
+ if not name:
25
+ continue
26
+ payload, _detail = _github_api_json(
27
+ gh_path,
28
+ f"repos/{slug}/actions/variables/{name}",
29
+ http_timeout=http_timeout,
30
+ )
31
+ if payload is None:
32
+ statuses[name] = "not_confirmed"
33
+ read_errors[name] = {
34
+ key: value
35
+ for key, value in _detail.items()
36
+ if key
37
+ in {
38
+ "endpoint",
39
+ "returncode",
40
+ "error_type",
41
+ "parse_error",
42
+ "output_redacted",
43
+ "output_line_count",
44
+ }
45
+ }
46
+ elif str(payload.get("value") or "").strip():
47
+ statuses[name] = "present"
48
+ else:
49
+ statuses[name] = "empty"
50
+ return {"statuses": statuses, "read_errors": read_errors}
51
+
52
+
53
+ def trusted_author_variable_statuses(
54
+ *,
55
+ gh_path: str,
56
+ slug: str,
57
+ variables: Iterable[str],
58
+ http_timeout: int,
59
+ ) -> dict[str, str]:
60
+ """Return safe presence statuses for trusted-author repository variables."""
61
+
62
+ probe = trusted_author_variable_probe(
63
+ gh_path=gh_path,
64
+ slug=slug,
65
+ variables=variables,
66
+ http_timeout=http_timeout,
67
+ )
68
+ statuses = probe.get("statuses")
69
+ return dict(statuses) if isinstance(statuses, dict) else {}
70
+
71
+
72
+ __all__ = ("trusted_author_variable_probe", "trusted_author_variable_statuses")
@@ -21,6 +21,7 @@ def check_review_hygiene(
21
21
  *,
22
22
  effective_lane: Mapping[str, Any] | None = None,
23
23
  repo_root: Path | None = None,
24
+ missing_workflow_is_warning: bool = False,
24
25
  ) -> DoctorCheck:
25
26
  """Verify that merge-authority lanes have stale terminal-label protection."""
26
27
 
@@ -108,24 +109,35 @@ def check_review_hygiene(
108
109
  if not workflow_path.is_absolute():
109
110
  workflow_path = repo_root / workflow_path
110
111
  if not workflow_path.is_file():
112
+ status = STATUS_WARN if missing_workflow_is_warning else STATUS_FAIL
113
+ message = (
114
+ "starter config names stale terminal-label workflow, but it is not "
115
+ f"present in this checkout yet: {workflow}"
116
+ if missing_workflow_is_warning
117
+ else "merge-authority lane stale terminal-label workflow is "
118
+ f"configured but missing from the repo: {workflow}"
119
+ )
120
+ remediation = (
121
+ "This is expected before generated workflows are applied. Run "
122
+ "`code-mower init --easy --apply` from the repository root, review "
123
+ "and commit the generated clear-stale workflow, then rerun doctor."
124
+ if missing_workflow_is_warning
125
+ else "Run `code-mower init --easy --apply` from the repository "
126
+ "root, commit the generated clear-stale workflow, then rerun "
127
+ "doctor before relying on this lane as merge authority."
128
+ )
111
129
  return DoctorCheck(
112
130
  name="provider.review_hygiene",
113
- status=STATUS_FAIL,
131
+ status=status,
114
132
  lane=lane_id,
115
- message=(
116
- "merge-authority lane stale terminal-label workflow is "
117
- f"configured but missing from the repo: {workflow}"
118
- ),
133
+ message=message,
119
134
  detail={
120
135
  **detail,
121
136
  "workflow_exists": False,
122
137
  "workflow_path": str(workflow_path),
138
+ "missing_workflow_is_warning": missing_workflow_is_warning,
123
139
  },
124
- remediation=(
125
- "Run `code-mower init --easy --apply` from the repository "
126
- "root, commit the generated clear-stale workflow, then rerun "
127
- "doctor before relying on this lane as merge authority."
128
- ),
140
+ remediation=remediation,
129
141
  )
130
142
  detail = {
131
143
  **detail,
@@ -176,6 +176,7 @@ def check_lane_runtime(
176
176
  probe_runtime: bool,
177
177
  http_timeout: int,
178
178
  adoption_posture: str = "reviewer-gate",
179
+ missing_workflow_is_warning: bool = False,
179
180
  ) -> list[DoctorCheck]:
180
181
  hygiene_source = source_lane if source_lane is not None else lane
181
182
  checks = [
@@ -184,6 +185,7 @@ def check_lane_runtime(
184
185
  hygiene_source,
185
186
  effective_lane=lane,
186
187
  repo_root=repo_root,
188
+ missing_workflow_is_warning=missing_workflow_is_warning,
187
189
  )
188
190
  ]
189
191
  driver = str(lane.get("driver", ""))
@@ -19,7 +19,7 @@ from .cloud import check_cloud_token_surface
19
19
  from .common import ACTIONS_COST_SAMPLE_DEFAULT, load_inputs
20
20
  from .github import check_github_setup
21
21
  from .github_config import check_repository_posture
22
- from .github_trusted_authors import trusted_author_variable_statuses
22
+ from .github_trusted_authors import trusted_author_variable_probe
23
23
  from .models import STATUS_FAIL, STATUS_PASS, DoctorCheck, DoctorReport
24
24
  from .providers import check_lane_runtime, effective_lane, provider_template_coverage, selected_lanes
25
25
  from .registry import DoctorCheckStage, build_doctor_run_plan
@@ -109,13 +109,15 @@ def run_doctor(
109
109
  adoption=adoption or bool(repo_slug),
110
110
  )
111
111
  enabled_stages = {stage.id for stage in plan}
112
- # `doctor --easy` can inspect the packaged example before a repo has written
113
- # code-mower.yml. In that mode the example should teach the user about stale
114
- # guards without failing because product workflow files are not installed yet.
115
- repo_root = None if config_path.name == "code-mower.example.yml" else config_path.parent
116
112
  config, templates, checks = load_inputs(config_path, provider_templates_path)
117
113
  using_packaged_example = config_path.name == "code-mower.example.yml"
114
+ # `doctor --easy` can inspect the packaged example before a repo has written
115
+ # code-mower.yml. In that mode the example should teach the user about stale
116
+ # guards without failing because product workflow files are not installed
117
+ # yet, but it may still verify workflows already present in the checkout.
118
+ repo_root = Path.cwd() if using_packaged_example else config_path.parent
118
119
  trusted_author_variables = None
120
+ trusted_author_variable_errors = None
119
121
  trusted_author_repo_slug = repo_slug
120
122
  if not trusted_author_repo_slug and isinstance(config, Mapping):
121
123
  for repository in config.get("repositories") or []:
@@ -125,12 +127,21 @@ def run_doctor(
125
127
  if github and trusted_author_repo_slug:
126
128
  gh_path = shutil.which("gh")
127
129
  if gh_path:
128
- trusted_author_variables = trusted_author_variable_statuses(
130
+ trusted_author_probe = trusted_author_variable_probe(
129
131
  gh_path=gh_path,
130
132
  slug=trusted_author_repo_slug,
131
133
  variables=TRUSTED_AUDIT_AUTHOR_VARIABLES,
132
134
  http_timeout=http_timeout,
133
135
  )
136
+ statuses = trusted_author_probe.get("statuses")
137
+ if isinstance(statuses, Mapping):
138
+ trusted_author_variables = {
139
+ str(name): str(status)
140
+ for name, status in statuses.items()
141
+ }
142
+ errors = trusted_author_probe.get("read_errors")
143
+ if isinstance(errors, Mapping):
144
+ trusted_author_variable_errors = dict(errors)
134
145
  checks.extend(
135
146
  check_adoption_setup(
136
147
  config=config,
@@ -142,6 +153,7 @@ def run_doctor(
142
153
  using_packaged_example=using_packaged_example,
143
154
  repo_root=Path.cwd() if using_packaged_example else config_path.parent,
144
155
  trusted_author_variables=trusted_author_variables,
156
+ trusted_author_variable_errors=trusted_author_variable_errors,
145
157
  )
146
158
  )
147
159
  if config is not None and repo_slug:
@@ -237,6 +249,7 @@ def run_doctor(
237
249
  effective,
238
250
  source_lane=lane,
239
251
  repo_root=repo_root,
252
+ missing_workflow_is_warning=using_packaged_example,
240
253
  adoption_posture=adoption_posture,
241
254
  probe_runtime=probe_runtime,
242
255
  http_timeout=http_timeout,
@@ -472,7 +472,7 @@ def _redact_local_paths(report: dict[str, Any]) -> None:
472
472
  process["cwd_redacted"] = True
473
473
 
474
474
 
475
- def _global_next(report: Mapping[str, Any]) -> str:
475
+ def _global_next(report: Mapping[str, Any]) -> tuple[str, str]:
476
476
  prs = report["remote"].get("pull_requests", [])
477
477
  local_active = bool(report["local_boards"].get("boards")) or bool(report["local_processes"].get("processes"))
478
478
  if not report["remote"].get("available"):
@@ -480,7 +480,7 @@ def _global_next(report: Mapping[str, Any]) -> str:
480
480
  "remote unavailable; inspect local lanes"
481
481
  if local_active
482
482
  else "remote unavailable; fix GitHub access"
483
- )
483
+ ), ""
484
484
  for action in (
485
485
  "fix BLOCKED audit",
486
486
  "fix failing check",
@@ -491,9 +491,12 @@ def _global_next(report: Mapping[str, Any]) -> str:
491
491
  "waiting for checks",
492
492
  "ready for merge or auto-merge",
493
493
  ):
494
- if any(pr.get("next_action") == action for pr in prs):
495
- return action
496
- return "inspect PRs" if prs else ("local lanes visible; connect them to PR evidence" if local_active else "no active lanes")
494
+ for pr in prs:
495
+ if pr.get("next_action") == action:
496
+ return action, str(pr.get("next_detail") or "")
497
+ return (
498
+ "inspect PRs" if prs else ("local lanes visible; connect them to PR evidence" if local_active else "no active lanes")
499
+ ), ""
497
500
 
498
501
 
499
502
  def collect_status(
@@ -518,7 +521,7 @@ def collect_status(
518
521
  }
519
522
  if not show_local_paths:
520
523
  _redact_local_paths(report)
521
- report["next_action"] = _global_next(report)
524
+ report["next_action"], report["next_detail"] = _global_next(report)
522
525
  return report
523
526
 
524
527
 
@@ -589,6 +592,8 @@ def render_text(report: Mapping[str, Any]) -> str:
589
592
  cwd = f" cwd={process['cwd']}" if process.get("cwd") else ""
590
593
  lines.append(f"- {process['provider']} pid={process['pid']} process={process['process']}{cwd}")
591
594
  lines.extend(["", f"Next: {report['next_action']}"])
595
+ if report.get("next_detail"):
596
+ lines.append(f"Detail: {report['next_detail']}")
592
597
  return "\n".join(lines) + "\n"
593
598
 
594
599