code-mower 0.8.0b1__tar.gz → 0.9.1b1__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 (353) hide show
  1. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/PKG-INFO +34 -11
  2. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/README.md +33 -10
  3. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/pyproject.toml +1 -1
  4. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/__init__.py +1 -1
  5. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/board.py +94 -26
  6. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/cli.py +2 -1
  7. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/doctor.py +41 -1
  8. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/doctor_checks/__init__.py +4 -0
  9. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/doctor_checks/adoption.py +176 -20
  10. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/doctor_checks/common.py +2 -0
  11. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/doctor_checks/github.py +2 -0
  12. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/doctor_checks/github_human_token.py +39 -7
  13. code_mower-0.9.1b1/src/code_mower/doctor_checks/github_trusted_authors.py +38 -0
  14. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/doctor_checks/provider_review_hygiene.py +53 -30
  15. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/doctor_checks/providers.py +9 -4
  16. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/doctor_checks/runner.py +36 -1
  17. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/doctor_checks/self_hosted_runner.py +0 -3
  18. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/lane_status.py +80 -12
  19. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/migration.py +351 -1
  20. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/migration_install.py +22 -0
  21. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/migration_rehearsal.py +30 -7
  22. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/next_steps.py +4 -4
  23. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/package_content.py +1 -1
  24. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/package_manifest.py +5 -0
  25. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/release_readiness.py +3 -0
  26. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/templates/workflows/builder-provenance.yml.j2 +1 -1
  27. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower.egg-info/PKG-INFO +34 -11
  28. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower.egg-info/SOURCES.txt +2 -0
  29. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/templates/workflows/builder-provenance.yml.j2 +1 -1
  30. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/tests/test_board.py +83 -0
  31. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/tests/test_doctor_github_checks.py +85 -0
  32. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/tests/test_doctor_provider_review_hygiene.py +4 -6
  33. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/tests/test_doctor_registry.py +253 -0
  34. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/tests/test_doctor_self_hosted_runner.py +31 -0
  35. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/tests/test_lane_status.py +60 -0
  36. code_mower-0.9.1b1/tests/test_migration_setup_drift.py +82 -0
  37. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/tests/test_release_hygiene.py +252 -39
  38. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/CODE_OF_CONDUCT.md +0 -0
  39. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/LICENSE +0 -0
  40. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/MANIFEST.in +0 -0
  41. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/NOTICE +0 -0
  42. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/SUPPORT.md +0 -0
  43. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/requirements/requirements.txt +0 -0
  44. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/setup.cfg +0 -0
  45. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/adapters/__init__.py +0 -0
  46. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/adapters/_base.py +0 -0
  47. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/adapters/cursor_bugbot.py +0 -0
  48. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/adapters/gitar.py +0 -0
  49. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/adapters/greptile.py +0 -0
  50. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/adapters/qodo.py +0 -0
  51. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/antigravity_cli_audit_pr.py +0 -0
  52. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/antigravity_sdk_probe.py +0 -0
  53. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/audit_handoff_log.py +0 -0
  54. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/audit_labeler_lib.py +0 -0
  55. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/audit_limits.py +0 -0
  56. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/audit_progress.py +0 -0
  57. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/blind_review_artifacts.py +0 -0
  58. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/blind_review_coordinator.py +0 -0
  59. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/board_store.py +0 -0
  60. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/bootstrap.py +0 -0
  61. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/builder_experiment.py +0 -0
  62. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/builder_runs.py +0 -0
  63. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/calibration/__init__.py +0 -0
  64. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/calibration/arms.py +0 -0
  65. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/calibration/auto_discovery.py +0 -0
  66. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/calibration/commands.py +0 -0
  67. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/calibration/context_inputs.py +0 -0
  68. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/calibration/corpus.py +0 -0
  69. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/calibration/effect_report.py +0 -0
  70. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/calibration/evidence.py +0 -0
  71. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/calibration/evidence_report.py +0 -0
  72. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/calibration/identity.py +0 -0
  73. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/calibration/metrics.py +0 -0
  74. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/calibration/overlap.py +0 -0
  75. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/calibration/planning.py +0 -0
  76. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/calibration/policy.py +0 -0
  77. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/calibration/results.py +0 -0
  78. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/calibration/run_results.py +0 -0
  79. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/calibration/run_status.py +0 -0
  80. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/calibration/runner.py +0 -0
  81. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/calibration/truth.py +0 -0
  82. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/calibration/value_report.py +0 -0
  83. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/checks.py +0 -0
  84. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/claude_audit_pr.py +0 -0
  85. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/claude_cli_bounce.py +0 -0
  86. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/claude_cli_environment.py +0 -0
  87. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/clear_stale.py +0 -0
  88. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/cloud.py +0 -0
  89. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/cloud_client/__init__.py +0 -0
  90. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/cloud_client/bundle.py +0 -0
  91. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/cloud_client/doctor.py +0 -0
  92. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/cloud_client/dogfood.py +0 -0
  93. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/cloud_client/endpoints.py +0 -0
  94. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/cloud_client/errors.py +0 -0
  95. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/cloud_client/events.py +0 -0
  96. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/cloud_client/export.py +0 -0
  97. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/cloud_client/git_metadata.py +0 -0
  98. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/cloud_client/manifest.py +0 -0
  99. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/cloud_client/operations.py +0 -0
  100. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/cloud_client/reports.py +0 -0
  101. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/cloud_client/setup.py +0 -0
  102. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/cloud_client/tokens.py +0 -0
  103. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/cloud_client/upload.py +0 -0
  104. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/code_mower_calibration.py +0 -0
  105. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/code_mower_context_packs.py +0 -0
  106. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/code_mower_merge.py +0 -0
  107. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/code_mower_telemetry.py +0 -0
  108. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/coderabbit_cli_audit_pr.py +0 -0
  109. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/codex_audit_env_preflight.py +0 -0
  110. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/codex_audit_pr.py +0 -0
  111. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/codex_audit_schema_smoke.py +0 -0
  112. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/codex_audit_verdict.schema.json +0 -0
  113. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/config.py +0 -0
  114. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/decisions.py +0 -0
  115. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/doctor_checks/audit_limits.py +0 -0
  116. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/doctor_checks/cloud.py +0 -0
  117. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/doctor_checks/github_actions.py +0 -0
  118. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/doctor_checks/github_actions_cost.py +0 -0
  119. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/doctor_checks/github_actions_cost_summary.py +0 -0
  120. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/doctor_checks/github_actions_failure_annotations.py +0 -0
  121. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/doctor_checks/github_actions_failure_models.py +0 -0
  122. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/doctor_checks/github_actions_failure_scan.py +0 -0
  123. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/doctor_checks/github_actions_failure_selection.py +0 -0
  124. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/doctor_checks/github_actions_failures.py +0 -0
  125. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/doctor_checks/github_actions_permissions.py +0 -0
  126. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/doctor_checks/github_api.py +0 -0
  127. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/doctor_checks/github_branch.py +0 -0
  128. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/doctor_checks/github_config.py +0 -0
  129. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/doctor_checks/github_provider.py +0 -0
  130. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/doctor_checks/github_repo.py +0 -0
  131. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/doctor_checks/groups.py +0 -0
  132. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/doctor_checks/models.py +0 -0
  133. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/doctor_checks/output.py +0 -0
  134. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/doctor_checks/presets.py +0 -0
  135. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/doctor_checks/privacy.py +0 -0
  136. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/doctor_checks/provider_api_model.py +0 -0
  137. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/doctor_checks/provider_api_model_openai.py +0 -0
  138. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/doctor_checks/provider_api_model_profiles.py +0 -0
  139. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/doctor_checks/provider_env.py +0 -0
  140. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/doctor_checks/provider_env_required.py +0 -0
  141. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/doctor_checks/provider_env_tokens.py +0 -0
  142. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/doctor_checks/provider_local_audit_setup.py +0 -0
  143. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/doctor_checks/provider_local_cli.py +0 -0
  144. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/doctor_checks/provider_local_cli_commands.py +0 -0
  145. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/doctor_checks/provider_local_cli_probe_config.py +0 -0
  146. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/doctor_checks/provider_probe.py +0 -0
  147. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/doctor_checks/provider_probe_auth.py +0 -0
  148. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/doctor_checks/provider_probe_evaluation.py +0 -0
  149. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/doctor_checks/provider_probe_json.py +0 -0
  150. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/doctor_checks/provider_probe_remediation.py +0 -0
  151. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/doctor_checks/registry.py +0 -0
  152. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/doctor_checks/runtime.py +0 -0
  153. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/doctor_checks/runtime_github_auth.py +0 -0
  154. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/gate_health.py +0 -0
  155. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/gemini_cli_audit_pr.py +0 -0
  156. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/git_identity.py +0 -0
  157. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/grok_build_audit_pr.py +0 -0
  158. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/hermes_cli_audit_pr.py +0 -0
  159. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/init.py +0 -0
  160. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/lane_configs/__init__.py +0 -0
  161. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/lane_configs/aider.py +0 -0
  162. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/lane_configs/antigravity_cli.py +0 -0
  163. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/lane_configs/claude.py +0 -0
  164. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/lane_configs/codex.py +0 -0
  165. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/lane_configs/devin.py +0 -0
  166. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/lane_configs/gemini_cli.py +0 -0
  167. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/lane_configs/grok_build.py +0 -0
  168. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/lane_configs/hermes_cli.py +0 -0
  169. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/lane_configs/local_llm.py +0 -0
  170. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/local_llm_audit_pr.py +0 -0
  171. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/local_llm_bakeoff.py +0 -0
  172. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/local_llm_calibration.py +0 -0
  173. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/local_llm_profiles.py +0 -0
  174. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/migration_mirror.py +0 -0
  175. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/migration_readiness.py +0 -0
  176. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/observe.py +0 -0
  177. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/package.py +0 -0
  178. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/package_paths.py +0 -0
  179. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/package_rendering.py +0 -0
  180. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/package_static.py +0 -0
  181. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/plan_context.py +0 -0
  182. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/prompts.py +0 -0
  183. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/provider_registry.py +0 -0
  184. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/provider_runners/__init__.py +0 -0
  185. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/provider_runners/comments.py +0 -0
  186. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/provider_runners/exit_codes.py +0 -0
  187. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/provider_runners/git.py +0 -0
  188. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/provider_runners/github_auth.py +0 -0
  189. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/provider_runners/github_pr.py +0 -0
  190. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/provider_runners/pr_worktree.py +0 -0
  191. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/provider_runners/process.py +0 -0
  192. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/provider_runners/repo_paths.py +0 -0
  193. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/provider_runners/text_schema.py +0 -0
  194. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/provider_runners/verdict_artifacts.py +0 -0
  195. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/provider_runners/workspace.py +0 -0
  196. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/providers/__init__.py +0 -0
  197. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/providers/local_cli.py +0 -0
  198. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/providers/provenance.py +0 -0
  199. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/reviewer_metrics.py +0 -0
  200. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/reviewer_spend.py +0 -0
  201. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/saas_reviewer_labeler.py +0 -0
  202. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/secrets.py +0 -0
  203. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/templates/builder-experiment.example.json +0 -0
  204. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/templates/calibration-corpus.example.json +0 -0
  205. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/templates/calibration-corpus.json +0 -0
  206. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/templates/code-mower.example.yml +0 -0
  207. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/templates/context-packs.example.json +0 -0
  208. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/templates/lane_prompts/base-audit.md +0 -0
  209. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/templates/lane_prompts/calibration-policy.md +0 -0
  210. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/templates/lane_prompts/context-driven-quality.md +0 -0
  211. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/templates/lane_prompts/docs-design.md +0 -0
  212. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/templates/lane_prompts/generic-programming.md +0 -0
  213. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/templates/lane_prompts/operability.md +0 -0
  214. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/templates/lane_prompts/package-runtime.md +0 -0
  215. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/templates/lane_prompts/plan-conformance.md +0 -0
  216. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/templates/lane_prompts/security-threat-model.md +0 -0
  217. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/templates/lanes/README.md +0 -0
  218. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/templates/lanes/claude.md +0 -0
  219. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/templates/lanes/codex.md +0 -0
  220. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/templates/lanes/cursor.md +0 -0
  221. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/templates/lanes/generic.md +0 -0
  222. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/templates/lanes/run_mac_lane.sh +0 -0
  223. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/templates/product-support/code_mower +0 -0
  224. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/templates/product-support/code_mower_standalone_pin.env +0 -0
  225. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/templates/product-support/code_mower_standalone_shadow.sh +0 -0
  226. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/templates/product-support/run_claude_audit_pr.sh +0 -0
  227. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/templates/product-support/run_codex_audit_pr.sh +0 -0
  228. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/templates/product-support/safe_gh_comment.py +0 -0
  229. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/templates/product-support/status_report.py +0 -0
  230. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/templates/providers.yml +0 -0
  231. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/templates/reviewer-spend.example.json +0 -0
  232. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/templates/reviewer-value-report.example.md +0 -0
  233. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/templates/workflows/audit-label-cleanup.yml.j2 +0 -0
  234. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/templates/workflows/code-mower-agent-pr-labeler.yml.j2 +0 -0
  235. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/templates/workflows/code-mower-fix-round-dispatch.yml.j2 +0 -0
  236. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/templates/workflows/code-mower-gate-health.yml.j2 +0 -0
  237. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/templates/workflows/code-mower-gate.yml.j2 +0 -0
  238. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/templates/workflows/dispatch-lanes.yml.j2 +0 -0
  239. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/templates/workflows/hosted-bridge.yml.j2 +0 -0
  240. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/templates/workflows/lane-mac-runner.yml.j2 +0 -0
  241. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/templates/workflows/local-cli-audit.yml.j2 +0 -0
  242. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/templates/workflows/needs-owner-notify.yml.j2 +0 -0
  243. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/templates/workflows/private-standalone-shadow.yml.j2 +0 -0
  244. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/templates/workflows/review-clear-stale.yml.j2 +0 -0
  245. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/templates/workflows/saas-reviewer-labeler.yml.j2 +0 -0
  246. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/templates/workflows/self-hosted-local-audit.yml.j2 +0 -0
  247. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/templates/workflows/trailer-comment-labeler.yml.j2 +0 -0
  248. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/templates/workflows/weekly-status.yml.j2 +0 -0
  249. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/trailer_comment_labeler.py +0 -0
  250. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/versioning.py +0 -0
  251. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/work_orders.py +0 -0
  252. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower/workflow_actionlint.py +0 -0
  253. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower.egg-info/dependency_links.txt +0 -0
  254. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower.egg-info/entry_points.txt +0 -0
  255. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower.egg-info/requires.txt +0 -0
  256. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/src/code_mower.egg-info/top_level.txt +0 -0
  257. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/templates/builder-experiment.example.json +0 -0
  258. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/templates/calibration-corpus.example.json +0 -0
  259. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/templates/calibration-corpus.json +0 -0
  260. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/templates/code-mower.yml.j2 +0 -0
  261. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/templates/context-packs.example.json +0 -0
  262. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/templates/cursor/BUGBOT.md +0 -0
  263. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/templates/lanes/README.md +0 -0
  264. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/templates/lanes/claude.md +0 -0
  265. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/templates/lanes/codex.md +0 -0
  266. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/templates/lanes/cursor.md +0 -0
  267. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/templates/lanes/generic.md +0 -0
  268. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/templates/lanes/run_mac_lane.sh +0 -0
  269. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/templates/providers/acp_bridge.yml +0 -0
  270. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/templates/providers/aider.yml +0 -0
  271. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/templates/providers/antigravity_cli.yml +0 -0
  272. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/templates/providers/claude_audit.yml +0 -0
  273. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/templates/providers/claude_review.yml +0 -0
  274. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/templates/providers/coderabbit_cli.yml +0 -0
  275. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/templates/providers/codex.yml +0 -0
  276. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/templates/providers/cursor_bugbot.yml +0 -0
  277. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/templates/providers/devin.yml +0 -0
  278. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/templates/providers/gemini_cli.yml +0 -0
  279. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/templates/providers/gitar.yml +0 -0
  280. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/templates/providers/greptile.yml +0 -0
  281. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/templates/providers/hermes_cli.yml +0 -0
  282. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/templates/providers/local_llm.yml +0 -0
  283. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/templates/providers/qodo.yml +0 -0
  284. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/templates/providers.yml +0 -0
  285. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/templates/reviewer-spend.example.json +0 -0
  286. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/templates/reviewer-value-report.example.md +0 -0
  287. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/templates/workflows/audit-label-cleanup.yml.j2 +0 -0
  288. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/templates/workflows/blind-review-artifacts-dry-run.yml.j2 +0 -0
  289. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/templates/workflows/code-mower-agent-pr-labeler.yml.j2 +0 -0
  290. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/templates/workflows/code-mower-fix-round-dispatch.yml.j2 +0 -0
  291. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/templates/workflows/code-mower-gate-health.yml.j2 +0 -0
  292. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/templates/workflows/code-mower-gate.yml.j2 +0 -0
  293. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/templates/workflows/dispatch-lanes.yml.j2 +0 -0
  294. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/templates/workflows/hosted-bridge.yml.j2 +0 -0
  295. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/templates/workflows/lane-mac-runner.yml.j2 +0 -0
  296. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/templates/workflows/local-cli-audit.yml.j2 +0 -0
  297. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/templates/workflows/private-standalone-shadow.yml.j2 +0 -0
  298. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/templates/workflows/review-clear-stale.yml.j2 +0 -0
  299. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/templates/workflows/saas-reviewer-labeler.yml.j2 +0 -0
  300. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/templates/workflows/self-hosted-local-audit.yml.j2 +0 -0
  301. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/templates/workflows/trailer-comment-labeler.yml.j2 +0 -0
  302. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/tests/test_antigravity_sdk_probe.py +0 -0
  303. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/tests/test_audit_comment_posture.py +0 -0
  304. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/tests/test_audit_limits.py +0 -0
  305. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/tests/test_builder_experiment.py +0 -0
  306. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/tests/test_builder_identity.py +0 -0
  307. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/tests/test_builder_runs.py +0 -0
  308. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/tests/test_calibration_effect_report.py +0 -0
  309. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/tests/test_calibration_truth.py +0 -0
  310. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/tests/test_checks.py +0 -0
  311. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/tests/test_claude_audit_pr.py +0 -0
  312. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/tests/test_claude_cli_bounce.py +0 -0
  313. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/tests/test_clear_stale.py +0 -0
  314. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/tests/test_cloud_client.py +0 -0
  315. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/tests/test_cloud_git_metadata.py +0 -0
  316. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/tests/test_cloud_manifest.py +0 -0
  317. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/tests/test_cloud_reports.py +0 -0
  318. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/tests/test_coderabbit_cli_audit_pr.py +0 -0
  319. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/tests/test_codex_audit_env_preflight.py +0 -0
  320. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/tests/test_codex_audit_pr.py +0 -0
  321. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/tests/test_decision_audit_integration.py +0 -0
  322. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/tests/test_decisions.py +0 -0
  323. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/tests/test_doctor_actions_cost_summary.py +0 -0
  324. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/tests/test_doctor_actions_failure_selection.py +0 -0
  325. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/tests/test_doctor_boundaries.py +0 -0
  326. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/tests/test_doctor_output.py +0 -0
  327. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/tests/test_doctor_privacy.py +0 -0
  328. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/tests/test_doctor_provider_env_required.py +0 -0
  329. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/tests/test_doctor_provider_env_tokens.py +0 -0
  330. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/tests/test_doctor_provider_local_audit_setup.py +0 -0
  331. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/tests/test_doctor_provider_probe.py +0 -0
  332. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/tests/test_doctor_runtime.py +0 -0
  333. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/tests/test_gate_health.py +0 -0
  334. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/tests/test_init_actionlint.py +0 -0
  335. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/tests/test_init_build_loop.py +0 -0
  336. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/tests/test_local_llm_github_helpers.py +0 -0
  337. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/tests/test_observe.py +0 -0
  338. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/tests/test_plan_context.py +0 -0
  339. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/tests/test_prompts.py +0 -0
  340. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/tests/test_provider_fixture_contracts.py +0 -0
  341. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/tests/test_provider_local_cli.py +0 -0
  342. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/tests/test_provider_runners_comments.py +0 -0
  343. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/tests/test_provider_runners_git.py +0 -0
  344. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/tests/test_provider_runners_github_pr.py +0 -0
  345. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/tests/test_provider_runners_pr_worktree.py +0 -0
  346. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/tests/test_provider_runners_process.py +0 -0
  347. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/tests/test_provider_runners_repo_paths.py +0 -0
  348. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/tests/test_provider_runners_text_schema.py +0 -0
  349. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/tests/test_provider_runners_workspace.py +0 -0
  350. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/tests/test_reviewer_metrics_core.py +0 -0
  351. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/tests/test_reviewer_spend.py +0 -0
  352. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/tests/test_trailer_comment_labeler.py +0 -0
  353. {code_mower-0.8.0b1 → code_mower-0.9.1b1}/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.8.0b1
3
+ Version: 0.9.1b1
4
4
  Summary: Multi-reviewer AI code audit orchestration
5
5
  License-Expression: Apache-2.0
6
6
  Requires-Python: >=3.12
@@ -64,6 +64,8 @@ for a real repository. It checks your runtime, GitHub setup, provider CLIs,
64
64
  token posture, optional cloud setup, private-repo Actions cost traps, and
65
65
  first-run adoption gaps. `--preflight` remains the compatibility preset for
66
66
  older scripts; `--adoption` adds explicit repo targeting and setup guidance.
67
+ Use `--hosted-builders` or `--orchestrator-only` when the current machine is
68
+ observing/coordinating lanes and will not run local Codex or Claude wrappers.
67
69
 
68
70
  Example, shortened:
69
71
 
@@ -88,16 +90,29 @@ boundaries visible before you promote any reviewer lane.
88
90
 
89
91
  See a fuller static transcript: [docs/first-run-transcript.md](docs/first-run-transcript.md).
90
92
 
93
+ For an existing repository that already has Code Mower generated workflows or
94
+ wrappers, run `code-mower migration setup-drift --repo-path .` before copying a
95
+ fresh `.code-mower.generated` tree. It is read-only and reports path-level
96
+ classifications (`same`, `differs`, `new`, `repo-only`,
97
+ `missing-from-output`) without file contents or diffs.
98
+ Use [Upgrade An Existing Repository](docs/upgrade-existing-repo.md) for the
99
+ reviewed PR flow, repo-only file handling, builder identity checks, and
100
+ wrapper/pin drift checks.
101
+
91
102
  After `init` and `doctor`, use `code-mower lanes status --repo OWNER/REPO` to
92
103
  see active builder/reviewer lanes, gate/check state, recent Code Mower
93
104
  workflows, local board/process hints when present, and the next operator
94
105
  action. Text and JSON output redact local cwd paths by default; use
95
- `--show-local-paths` only for local debugging.
106
+ `--show-local-paths` only for local debugging. Local Board discovery is
107
+ best-effort across common macOS and Linux listener tools; when a host restricts
108
+ listener inventory, remote PR/check status still reports normally.
96
109
 
97
110
  For the same redacted metadata in a local browser view, run
98
111
  `code-mower board serve --repo OWNER/REPO` and open the printed localhost URL.
99
- Plain `board serve` is read-only. To build local history while the browser view
100
- is open, run `code-mower board serve --repo OWNER/REPO --record-events`; it
112
+ Plain `board serve` is read-only. If the default Board port is busy, the CLI
113
+ uses a nearby free loopback port and prints the URL; an explicit `--port` stays
114
+ strict and reports a friendly conflict. To build local history while the browser
115
+ view is open, run `code-mower board serve --repo OWNER/REPO --record-events`; it
101
116
  records at most one snapshot every 60 seconds by default. To append one snapshot
102
117
  without serving the browser view, run
103
118
  `code-mower board record --repo OWNER/REPO` from the repository checkout; it
@@ -143,7 +158,9 @@ observable.
143
158
 
144
159
  Install first from the [Install And Bootstrap](docs/install.md) matrix: pipx for
145
160
  laptops, uv tool installs for hosted agents or CI boxes, and an editable venv
146
- for Code Mower contributors. All paths require Python 3.12 or newer.
161
+ for Code Mower contributors. All paths require Python 3.12 or newer. For
162
+ upgrades, record `command -v code-mower` and `code-mower --version` before and
163
+ after reinstalling, especially when switching between pipx and uv.
147
164
 
148
165
  | Path | Use When | Route | Guide |
149
166
  | --- | --- | --- | --- |
@@ -152,9 +169,11 @@ for Code Mower contributors. All paths require Python 3.12 or newer.
152
169
  | 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
170
 
154
171
  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.8.0-beta.1/docs/try-in-10-minutes.md)
156
- guide. The v0.8 beta includes the completed adoption-polish and native Board
157
- work, so package-only users can start from the public package rather than a
172
+ [Try Code Mower In 10 Minutes](https://github.com/codemower-ai/code-mower/blob/v0.9.1-beta.1/docs/try-in-10-minutes.md)
173
+ guide. The v0.9 beta includes the completed native Board work plus the adoption
174
+ and upgrade hardening from recent install rehearsals; v0.9.1 adds a smaller
175
+ announcement-hardening pass on Board visibility, doctor guidance, and safer
176
+ setup docs. Package-only users can start from the public package rather than a
158
177
  source checkout.
159
178
 
160
179
  ## What Calibration Does And Does Not Prove
@@ -178,13 +197,15 @@ review-request signals to propose known-clean and known-blocked cases. Review
178
197
  every disposition before using it for lane promotion or merge policy.
179
198
 
180
199
  Full walkthrough: [docs/try-in-10-minutes.md](docs/try-in-10-minutes.md).
200
+ Existing-repo upgrade flow:
201
+ [docs/upgrade-existing-repo.md](docs/upgrade-existing-repo.md).
181
202
  First-time command map: [docs/launch-command-surface.md](docs/launch-command-surface.md).
182
203
  Provider-contract baseline for the next release train:
183
204
  [docs/v06-truth-baseline.md](docs/v06-truth-baseline.md).
184
205
 
185
206
  For release verification,
186
207
  [First-User Install Rehearsal](docs/first-user-install-rehearsal.md) records
187
- the package-index procedure for `v0.8.0-beta.1` / `code-mower==0.8.0b1`. The
208
+ the package-index procedure for `v0.9.1-beta.1` / `code-mower==0.9.1b1`. The
188
209
  GitHub release records the workflow and rehearsal evidence for the exact tag.
189
210
 
190
211
  ## Optional: Plan Before Coding
@@ -370,8 +391,8 @@ measurement work.
370
391
 
371
392
  ## Installation Status
372
393
 
373
- The current package-index beta baseline is `v0.8.0-beta.1`, with pinned package
374
- install spec `code-mower==0.8.0b1`. Release evidence is recorded on the GitHub
394
+ The current package-index beta baseline is `v0.9.1-beta.1`, with pinned package
395
+ install spec `code-mower==0.9.1b1`. Release evidence is recorded on the GitHub
375
396
  release and in the first-user install rehearsal. The public repository is
376
397
  [codemower-ai/code-mower](https://github.com/codemower-ai/code-mower), and
377
398
  GitHub releases remain the auditable source for tags, build artifacts, and
@@ -412,6 +433,7 @@ first so local work exercises the same package entrypoint users install.
412
433
  ## Docs Map
413
434
 
414
435
  - [Install And Bootstrap](docs/install.md)
436
+ - [Upgrade An Existing Repository](docs/upgrade-existing-repo.md)
415
437
  - [Try Code Mower In 10 Minutes](docs/try-in-10-minutes.md)
416
438
  - [Build Loop In 30 Minutes](docs/build-loop-in-30-minutes.md)
417
439
  - [Quickstart Reference](docs/quickstart.md)
@@ -434,6 +456,7 @@ first so local work exercises the same package entrypoint users install.
434
456
  - [v0.6 Truth Baseline](docs/v06-truth-baseline.md)
435
457
  - [v0.6 Release Notes](docs/v06-release-notes.md)
436
458
  - [v0.8 Release Notes](docs/v08-release-notes.md)
459
+ - [v0.9 Release Notes](docs/v09-release-notes.md)
437
460
  - [Post-v0.8 Effectiveness Assessment](docs/post-v08-effectiveness-assessment.md)
438
461
  - [Demo Calibration Example](examples/demo-calibration/README.md)
439
462
  - [Board Demo Rehearsal](examples/board-demo/README.md)
@@ -47,6 +47,8 @@ for a real repository. It checks your runtime, GitHub setup, provider CLIs,
47
47
  token posture, optional cloud setup, private-repo Actions cost traps, and
48
48
  first-run adoption gaps. `--preflight` remains the compatibility preset for
49
49
  older scripts; `--adoption` adds explicit repo targeting and setup guidance.
50
+ Use `--hosted-builders` or `--orchestrator-only` when the current machine is
51
+ observing/coordinating lanes and will not run local Codex or Claude wrappers.
50
52
 
51
53
  Example, shortened:
52
54
 
@@ -71,16 +73,29 @@ boundaries visible before you promote any reviewer lane.
71
73
 
72
74
  See a fuller static transcript: [docs/first-run-transcript.md](docs/first-run-transcript.md).
73
75
 
76
+ For an existing repository that already has Code Mower generated workflows or
77
+ wrappers, run `code-mower migration setup-drift --repo-path .` before copying a
78
+ fresh `.code-mower.generated` tree. It is read-only and reports path-level
79
+ classifications (`same`, `differs`, `new`, `repo-only`,
80
+ `missing-from-output`) without file contents or diffs.
81
+ Use [Upgrade An Existing Repository](docs/upgrade-existing-repo.md) for the
82
+ reviewed PR flow, repo-only file handling, builder identity checks, and
83
+ wrapper/pin drift checks.
84
+
74
85
  After `init` and `doctor`, use `code-mower lanes status --repo OWNER/REPO` to
75
86
  see active builder/reviewer lanes, gate/check state, recent Code Mower
76
87
  workflows, local board/process hints when present, and the next operator
77
88
  action. Text and JSON output redact local cwd paths by default; use
78
- `--show-local-paths` only for local debugging.
89
+ `--show-local-paths` only for local debugging. Local Board discovery is
90
+ best-effort across common macOS and Linux listener tools; when a host restricts
91
+ listener inventory, remote PR/check status still reports normally.
79
92
 
80
93
  For the same redacted metadata in a local browser view, run
81
94
  `code-mower board serve --repo OWNER/REPO` and open the printed localhost URL.
82
- Plain `board serve` is read-only. To build local history while the browser view
83
- is open, run `code-mower board serve --repo OWNER/REPO --record-events`; it
95
+ Plain `board serve` is read-only. If the default Board port is busy, the CLI
96
+ uses a nearby free loopback port and prints the URL; an explicit `--port` stays
97
+ strict and reports a friendly conflict. To build local history while the browser
98
+ view is open, run `code-mower board serve --repo OWNER/REPO --record-events`; it
84
99
  records at most one snapshot every 60 seconds by default. To append one snapshot
85
100
  without serving the browser view, run
86
101
  `code-mower board record --repo OWNER/REPO` from the repository checkout; it
@@ -126,7 +141,9 @@ observable.
126
141
 
127
142
  Install first from the [Install And Bootstrap](docs/install.md) matrix: pipx for
128
143
  laptops, uv tool installs for hosted agents or CI boxes, and an editable venv
129
- for Code Mower contributors. All paths require Python 3.12 or newer.
144
+ for Code Mower contributors. All paths require Python 3.12 or newer. For
145
+ upgrades, record `command -v code-mower` and `code-mower --version` before and
146
+ after reinstalling, especially when switching between pipx and uv.
130
147
 
131
148
  | Path | Use When | Route | Guide |
132
149
  | --- | --- | --- | --- |
@@ -135,9 +152,11 @@ for Code Mower contributors. All paths require Python 3.12 or newer.
135
152
  | 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) |
136
153
 
137
154
  The current package-index announcement entry point is the tagged
138
- [Try Code Mower In 10 Minutes](https://github.com/codemower-ai/code-mower/blob/v0.8.0-beta.1/docs/try-in-10-minutes.md)
139
- guide. The v0.8 beta includes the completed adoption-polish and native Board
140
- work, so package-only users can start from the public package rather than a
155
+ [Try Code Mower In 10 Minutes](https://github.com/codemower-ai/code-mower/blob/v0.9.1-beta.1/docs/try-in-10-minutes.md)
156
+ guide. The v0.9 beta includes the completed native Board work plus the adoption
157
+ and upgrade hardening from recent install rehearsals; v0.9.1 adds a smaller
158
+ announcement-hardening pass on Board visibility, doctor guidance, and safer
159
+ setup docs. Package-only users can start from the public package rather than a
141
160
  source checkout.
142
161
 
143
162
  ## What Calibration Does And Does Not Prove
@@ -161,13 +180,15 @@ review-request signals to propose known-clean and known-blocked cases. Review
161
180
  every disposition before using it for lane promotion or merge policy.
162
181
 
163
182
  Full walkthrough: [docs/try-in-10-minutes.md](docs/try-in-10-minutes.md).
183
+ Existing-repo upgrade flow:
184
+ [docs/upgrade-existing-repo.md](docs/upgrade-existing-repo.md).
164
185
  First-time command map: [docs/launch-command-surface.md](docs/launch-command-surface.md).
165
186
  Provider-contract baseline for the next release train:
166
187
  [docs/v06-truth-baseline.md](docs/v06-truth-baseline.md).
167
188
 
168
189
  For release verification,
169
190
  [First-User Install Rehearsal](docs/first-user-install-rehearsal.md) records
170
- the package-index procedure for `v0.8.0-beta.1` / `code-mower==0.8.0b1`. The
191
+ the package-index procedure for `v0.9.1-beta.1` / `code-mower==0.9.1b1`. The
171
192
  GitHub release records the workflow and rehearsal evidence for the exact tag.
172
193
 
173
194
  ## Optional: Plan Before Coding
@@ -353,8 +374,8 @@ measurement work.
353
374
 
354
375
  ## Installation Status
355
376
 
356
- The current package-index beta baseline is `v0.8.0-beta.1`, with pinned package
357
- install spec `code-mower==0.8.0b1`. Release evidence is recorded on the GitHub
377
+ The current package-index beta baseline is `v0.9.1-beta.1`, with pinned package
378
+ install spec `code-mower==0.9.1b1`. Release evidence is recorded on the GitHub
358
379
  release and in the first-user install rehearsal. The public repository is
359
380
  [codemower-ai/code-mower](https://github.com/codemower-ai/code-mower), and
360
381
  GitHub releases remain the auditable source for tags, build artifacts, and
@@ -395,6 +416,7 @@ first so local work exercises the same package entrypoint users install.
395
416
  ## Docs Map
396
417
 
397
418
  - [Install And Bootstrap](docs/install.md)
419
+ - [Upgrade An Existing Repository](docs/upgrade-existing-repo.md)
398
420
  - [Try Code Mower In 10 Minutes](docs/try-in-10-minutes.md)
399
421
  - [Build Loop In 30 Minutes](docs/build-loop-in-30-minutes.md)
400
422
  - [Quickstart Reference](docs/quickstart.md)
@@ -417,6 +439,7 @@ first so local work exercises the same package entrypoint users install.
417
439
  - [v0.6 Truth Baseline](docs/v06-truth-baseline.md)
418
440
  - [v0.6 Release Notes](docs/v06-release-notes.md)
419
441
  - [v0.8 Release Notes](docs/v08-release-notes.md)
442
+ - [v0.9 Release Notes](docs/v09-release-notes.md)
420
443
  - [Post-v0.8 Effectiveness Assessment](docs/post-v08-effectiveness-assessment.md)
421
444
  - [Demo Calibration Example](examples/demo-calibration/README.md)
422
445
  - [Board Demo Rehearsal](examples/board-demo/README.md)
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "code-mower"
7
- version = "0.8.0b1"
7
+ version = "0.9.1b1"
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.8.0b1"
3
+ __version__ = "0.9.1b1"
@@ -4,6 +4,7 @@
4
4
  from __future__ import annotations
5
5
 
6
6
  import argparse
7
+ import errno
7
8
  import json
8
9
  import re
9
10
  import socket
@@ -41,6 +42,7 @@ class BoardConfig:
41
42
  repo: str
42
43
  host: str = DEFAULT_HOST
43
44
  port: int = DEFAULT_PORT
45
+ port_was_default: bool = True
44
46
  pr_limit: int = 50
45
47
  workflow_limit: int = 20
46
48
  stale_minutes: int = 30
@@ -111,6 +113,46 @@ def _server_url(host: str, port: int) -> str:
111
113
  return f"http://{display_host}:{port}/"
112
114
 
113
115
 
116
+ def _candidate_ports(config: BoardConfig) -> list[int]:
117
+ if not config.port_was_default:
118
+ return [config.port]
119
+ last_port = min(65535, config.port + 9)
120
+ return list(range(config.port, last_port + 1))
121
+
122
+
123
+ def _explicit_port_conflict_message(host: str, port: int) -> str:
124
+ suggestions = list(range(port + 1, min(65535, port + 3) + 1))
125
+ suggestion_text = f" such as {', '.join(str(candidate) for candidate in suggestions)}" if suggestions else ""
126
+ return (
127
+ f"error: Code Mower Board port {port} is already in use on {host}. "
128
+ f"Pass --port with a free loopback port{suggestion_text}."
129
+ )
130
+
131
+
132
+ def _bind_board_server(
133
+ config: BoardConfig,
134
+ handler: type[BaseHTTPRequestHandler],
135
+ ) -> ThreadingHTTPServer | None:
136
+ server_type = _server_class(config.host)
137
+ tried: list[int] = []
138
+ for port in _candidate_ports(config):
139
+ tried.append(port)
140
+ try:
141
+ return server_type((config.host, port), handler)
142
+ except OSError as exc:
143
+ if exc.errno != errno.EADDRINUSE:
144
+ raise
145
+ if not config.port_was_default:
146
+ print(_explicit_port_conflict_message(config.host, port), file=sys.stderr)
147
+ return None
148
+ print(
149
+ "error: Code Mower Board could not find a free loopback port in "
150
+ f"{tried[0]}-{tried[-1]}; pass --port with a free port.",
151
+ file=sys.stderr,
152
+ )
153
+ return None
154
+
155
+
114
156
  def status_payload(
115
157
  config: BoardConfig,
116
158
  *,
@@ -613,6 +655,14 @@ def render_board_html(config: BoardConfig) -> str:
613
655
  const stateClass = (value) => /fail|error|blocked/i.test(text(value)) ? "bad" : /warn|pending|waiting|queued|progress/i.test(text(value)) ? "warn" : "ok";
614
656
  const seconds = (value) => Number.isFinite(Number(value)) ? `${{Number(value).toFixed(1)}}s` : "n/a";
615
657
  const money = (value) => Number.isFinite(Number(value)) ? `$${{Number(value).toFixed(3)}}` : "n/a";
658
+ const localTime = (value) => {{
659
+ const raw = text(value);
660
+ if (!raw) return "";
661
+ const date = new Date(raw);
662
+ if (Number.isNaN(date.getTime())) return esc(raw);
663
+ const local = new Intl.DateTimeFormat(undefined, {{year:"numeric", month:"short", day:"numeric", hour:"numeric", minute:"2-digit", second:"2-digit", timeZoneName:"short"}}).format(date);
664
+ return `<time datetime="${{esc(raw)}}" title="UTC ${{esc(raw)}}">${{esc(local)}}</time>`;
665
+ }};
616
666
  function labels(groups) {{
617
667
  return Object.values(groups || {{}}).flat().map(pill).join(" ") || '<span class="muted">none</span>';
618
668
  }}
@@ -621,7 +671,7 @@ def render_board_html(config: BoardConfig) -> str:
621
671
  }}
622
672
  function render(data) {{
623
673
  document.getElementById("repo").textContent = REPO;
624
- document.getElementById("generated").textContent = `Generated ${{data.generated_at || ""}}`;
674
+ document.getElementById("generated").innerHTML = data.generated_at ? `Generated ${{localTime(data.generated_at)}}` : "Loading...";
625
675
  const prs = data.remote?.pull_requests || [];
626
676
  const runs = data.remote?.workflow_runs || [];
627
677
  const alerts = data.remote?.gate_health?.alerts || [];
@@ -639,18 +689,18 @@ def render_board_html(config: BoardConfig) -> str:
639
689
  `<div class="metric"><span class="muted">Agent cards</span><b>${{agentCards.length}}</b></div>`,
640
690
  `<div class="metric"><span class="muted">Gate alerts</span><b class="${{alerts.length ? "warn" : "ok"}}">${{alerts.length}}</b></div>`
641
691
  ].join(""));
642
- put("owner", ownerQueue.length ? ownerQueue.map(item => `<div class="row"><div class="line"><a href="${{esc(href(item.url))}}">#${{esc(item.pr_number)}} ${{esc(item.kind)}}</a>${{pill(item.next_action)}}${{pill(item.head_sha_prefix)}}</div><div class="muted">${{esc(item.branch)}} by ${{esc(item.author)}} updated ${{esc(item.updated_at)}}</div></div>`).join("") : empty(data.owner_queue?.message || "No owner queue items."));
643
- put("agents", agentCards.length ? agentCards.map(agent => `<div class="row"><div class="line"><b>${{esc(agent.provider)}}</b>${{pill(agent.role)}}${{pill(agent.status)}}${{agent.lane ? pill(agent.lane) : ""}}${{agent.pr_number ? pill(`#${{agent.pr_number}}`) : ""}}</div><div>${{esc(agent.title || agent.next_action || "local agent")}}</div><div class="muted">${{esc(agent.branch || agent.repo || "")}}${{agent.pid ? ` pid=${{esc(agent.pid)}}` : ""}}${{agent.cwd ? ` cwd=${{esc(agent.cwd)}}` : ""}}${{agent.updated_at ? ` updated ${{esc(agent.updated_at)}}` : ""}}</div></div>`).join("") : empty(data.agent_adapters?.message || "No local agent adapter cards."));
692
+ put("owner", ownerQueue.length ? ownerQueue.map(item => `<div class="row"><div class="line"><a href="${{esc(href(item.url))}}">#${{esc(item.pr_number)}} ${{esc(item.kind)}}</a>${{pill(item.next_action)}}${{pill(item.head_sha_prefix)}}</div><div class="muted">${{esc(item.branch)}} by ${{esc(item.author)}}${{item.updated_at ? ` updated ${{localTime(item.updated_at)}}` : ""}}</div></div>`).join("") : empty(data.owner_queue?.message || "No owner queue items."));
693
+ put("agents", agentCards.length ? agentCards.map(agent => `<div class="row"><div class="line"><b>${{esc(agent.provider)}}</b>${{pill(agent.role)}}${{pill(agent.status)}}${{agent.lane ? pill(agent.lane) : ""}}${{agent.pr_number ? pill(`#${{agent.pr_number}}`) : ""}}</div><div>${{esc(agent.title || agent.next_action || "local agent")}}</div><div class="muted">${{esc(agent.branch || agent.repo || "")}}${{agent.pid ? ` pid=${{esc(agent.pid)}}` : ""}}${{agent.cwd ? ` cwd=${{esc(agent.cwd)}}` : ""}}${{agent.updated_at ? ` updated ${{localTime(agent.updated_at)}}` : ""}}</div></div>`).join("") : empty(data.agent_adapters?.message || "No local agent adapter cards."));
644
694
  put("prs", prs.length ? prs.map(pr => `<div class="row">
645
695
  <div class="line"><a href="${{esc(href(pr.url))}}">#${{esc(pr.number)}} ${{esc(pr.title)}}</a>${{pill(pr.merge_state)}}${{pr.is_draft ? pill("draft") : ""}}${{pr.stale ? pill("stale") : ""}}</div>
646
- <div class="muted">${{esc(pr.branch)}} by ${{esc(pr.author)}} updated ${{esc(pr.updated_at)}}</div>
696
+ <div class="muted">${{esc(pr.branch)}} by ${{esc(pr.author)}}${{pr.updated_at ? ` updated ${{localTime(pr.updated_at)}}` : ""}}</div>
647
697
  <div>labels: ${{labels(pr.labels)}}</div>
648
698
  <div>checks: ${{checks(pr.checks)}}</div>
649
699
  <div>next: <b>${{esc(pr.next_action)}}</b></div>
650
700
  </div>`).join("") : empty("No open pull requests."));
651
701
  put("alerts", alerts.length ? alerts.map(a => `<div class="row"><b class="warn">${{esc(a.kind)}}</b> ${{esc(a.message)}}</div>`).join("") : empty("No gate alerts."));
652
- put("runs", runs.length ? runs.slice(0, 8).map(run => `<div class="row"><div class="line"><a href="${{esc(href(run.url))}}">${{esc(run.workflow || "workflow")}}</a>${{pill(run.conclusion || run.status || "unknown")}}</div><div class="muted">${{esc(run.branch)}} updated ${{esc(run.updated_at)}}</div></div>`).join("") : empty("No recent Code Mower workflow runs."));
653
- put("verdicts", verdicts.length ? verdicts.map(v => `<div class="row"><div class="line"><a href="${{esc(href(v.url))}}">#${{esc(v.pr_number)}} ${{esc(v.lane)}}</a>${{pill(v.verdict)}}${{pill(v.head_sha_prefix)}}</div><div class="muted">${{esc(v.created_at)}}</div></div>`).join("") : empty(timelines.verdicts?.message || "No local reviewer verdict history yet."));
702
+ put("runs", runs.length ? runs.slice(0, 8).map(run => `<div class="row"><div class="line"><a href="${{esc(href(run.url))}}">${{esc(run.workflow || "workflow")}}</a>${{pill(run.conclusion || run.status || "unknown")}}</div><div class="muted">${{esc(run.branch)}}${{run.updated_at ? ` updated ${{localTime(run.updated_at)}}` : ""}}</div></div>`).join("") : empty("No recent Code Mower workflow runs."));
703
+ put("verdicts", verdicts.length ? verdicts.map(v => `<div class="row"><div class="line"><a href="${{esc(href(v.url))}}">#${{esc(v.pr_number)}} ${{esc(v.lane)}}</a>${{pill(v.verdict)}}${{pill(v.head_sha_prefix)}}</div><div class="muted">${{localTime(v.created_at)}}</div></div>`).join("") : empty(timelines.verdicts?.message || "No local reviewer verdict history yet."));
654
704
  const spendRows = [
655
705
  ...spendGroups.map(g => `<div class="row"><div class="line"><b>${{esc(g.lane)}}</b>${{pill(g.verdict)}}${{pill(`${{g.runs}} runs`)}}</div><div class="muted">${{seconds(g.wall_seconds_total)}} total / ${{seconds(g.wall_seconds_avg)}} avg / ${{money(g.cost_usd_total)}} / ${{esc(g.total_tokens || 0)}} tokens</div></div>`),
656
706
  spend.skipped_rows ? `<div class="row muted">Skipped ${{esc(spend.skipped_rows)}} malformed spend row(s).</div>` : "",
@@ -666,7 +716,7 @@ def render_board_html(config: BoardConfig) -> str:
666
716
  put("history", events.length ? events.slice().reverse().map(event => {{
667
717
  const s = event.summary || {{}};
668
718
  const remote = s.remote_available ? "remote available" : "remote unavailable";
669
- return `<div class="row"><div class="line"><b>${{esc(event.created_at)}}</b>${{pill(remote)}}</div><div>next: <b>${{esc(s.next_action || "inspect")}}</b></div><div class="muted">PRs ${{esc(s.open_prs ?? 0)}} / alerts ${{esc(s.gate_alerts ?? 0)}} / local ${{esc((s.local_boards ?? 0) + (s.local_processes ?? 0))}}</div></div>`;
719
+ return `<div class="row"><div class="line"><b>${{localTime(event.created_at)}}</b>${{pill(remote)}}</div><div>next: <b>${{esc(s.next_action || "inspect")}}</b></div><div class="muted">PRs ${{esc(s.open_prs ?? 0)}} / alerts ${{esc(s.gate_alerts ?? 0)}} / local ${{esc((s.local_boards ?? 0) + (s.local_processes ?? 0))}}</div></div>`;
670
720
  }}).join("") : empty(history.message || "No local board events recorded yet."));
671
721
  }}
672
722
  async function load() {{
@@ -781,6 +831,9 @@ def serve(config: BoardConfig, *, open_browser: bool = False) -> int:
781
831
  if not _is_loopback(config.host):
782
832
  print("error: board host must be loopback; use 127.0.0.1 or localhost", file=sys.stderr)
783
833
  return 2
834
+ if not 0 <= config.port <= 65535:
835
+ print("error: --port must be between 0 and 65535", file=sys.stderr)
836
+ return 2
784
837
  if config.record_interval_seconds < 0:
785
838
  print("error: --record-interval-seconds must be non-negative", file=sys.stderr)
786
839
  return 2
@@ -791,10 +844,14 @@ def serve(config: BoardConfig, *, open_browser: bool = False) -> int:
791
844
  print("error: --max-events must be at least 1", file=sys.stderr)
792
845
  return 2
793
846
  handler = make_handler(config)
794
- server_type = _server_class(config.host)
795
- with server_type((config.host, config.port), handler) as server:
847
+ server = _bind_board_server(config, handler)
848
+ if server is None:
849
+ return 2
850
+ with server:
796
851
  port = int(server.server_address[1])
797
852
  url = _server_url(config.host, port)
853
+ if config.port_was_default and port != config.port:
854
+ print(f"Code Mower Board: default port {config.port} was busy; using {port}", file=sys.stderr)
798
855
  print(f"Code Mower Board: {url}", flush=True)
799
856
  if open_browser:
800
857
  webbrowser.open(url)
@@ -1057,22 +1114,32 @@ def main(argv: list[str] | None = None) -> int:
1057
1114
  subparsers = parser.add_subparsers(dest="command", required=True)
1058
1115
  serve_parser = subparsers.add_parser("serve")
1059
1116
  serve_parser.add_argument("--repo", required=True)
1060
- serve_parser.add_argument("--host", default=DEFAULT_HOST)
1061
- serve_parser.add_argument("--port", type=int, default=DEFAULT_PORT)
1062
- serve_parser.add_argument("--pr-limit", type=int, default=50)
1063
- serve_parser.add_argument("--workflow-limit", type=int, default=20)
1064
- serve_parser.add_argument("--stale-minutes", type=int, default=30)
1065
- serve_parser.add_argument("--refresh-seconds", type=int, default=15)
1066
- serve_parser.add_argument("--show-local-paths", action="store_true")
1067
- serve_parser.add_argument("--repo-path", default=".")
1068
- serve_parser.add_argument("--store-path")
1069
- serve_parser.add_argument("--spend-path")
1070
- serve_parser.add_argument("--agent-adapters-path")
1071
- serve_parser.add_argument("--event-limit", type=int, default=20)
1072
- serve_parser.add_argument("--record-events", action="store_true")
1073
- serve_parser.add_argument("--record-interval-seconds", type=int, default=60)
1074
- serve_parser.add_argument("--retention-days", type=int, default=board_store.DEFAULT_RETENTION_DAYS)
1075
- serve_parser.add_argument("--max-events", type=int, default=board_store.DEFAULT_MAX_EVENTS)
1117
+ serve_parser.add_argument("--host", default=DEFAULT_HOST, help="loopback host to bind; default: 127.0.0.1")
1118
+ serve_parser.add_argument(
1119
+ "--port",
1120
+ type=int,
1121
+ default=None,
1122
+ help="loopback port; the default auto-falls forward when busy",
1123
+ )
1124
+ serve_parser.add_argument("--pr-limit", type=int, default=50, help="open PRs to show")
1125
+ serve_parser.add_argument("--workflow-limit", type=int, default=20, help="recent Code Mower workflow runs to show")
1126
+ serve_parser.add_argument("--stale-minutes", type=int, default=30, help="minutes before gate evidence is stale")
1127
+ serve_parser.add_argument("--refresh-seconds", type=int, default=15, help="browser refresh interval")
1128
+ serve_parser.add_argument("--show-local-paths", action="store_true", help="show local cwd paths for debugging")
1129
+ serve_parser.add_argument("--repo-path", default=".", help="repository checkout used for local Board files")
1130
+ serve_parser.add_argument("--store-path", help="custom local Board event store path")
1131
+ serve_parser.add_argument("--spend-path", help="custom reviewer spend ledger path")
1132
+ serve_parser.add_argument("--agent-adapters-path", help="custom local agent card directory")
1133
+ serve_parser.add_argument("--event-limit", type=int, default=20, help="local history events to show")
1134
+ serve_parser.add_argument("--record-events", action="store_true", help="append local history while the Board is open")
1135
+ serve_parser.add_argument("--record-interval-seconds", type=int, default=60, help="minimum seconds between records")
1136
+ serve_parser.add_argument(
1137
+ "--retention-days",
1138
+ type=int,
1139
+ default=board_store.DEFAULT_RETENTION_DAYS,
1140
+ help="local history retention window",
1141
+ )
1142
+ serve_parser.add_argument("--max-events", type=int, default=board_store.DEFAULT_MAX_EVENTS, help="maximum local events")
1076
1143
  serve_parser.add_argument("--open", action="store_true", help="open the local board in a browser")
1077
1144
  record_parser = subparsers.add_parser("record")
1078
1145
  record_parser.add_argument("--repo", required=True)
@@ -1115,7 +1182,8 @@ def main(argv: list[str] | None = None) -> int:
1115
1182
  BoardConfig(
1116
1183
  repo=args.repo,
1117
1184
  host=args.host,
1118
- port=args.port,
1185
+ port=DEFAULT_PORT if args.port is None else args.port,
1186
+ port_was_default=args.port is None,
1119
1187
  pr_limit=args.pr_limit,
1120
1188
  workflow_limit=args.workflow_limit,
1121
1189
  stale_minutes=args.stale_minutes,
@@ -556,7 +556,8 @@ def _top_level_help(show_all: bool) -> str:
556
556
  " code-mower board serve --repo OWNER/REPO",
557
557
  (
558
558
  " code-mower migration package-install-rehearsal "
559
- f"--package-spec {code_mower_next_steps.current_alpha_package_spec()} --json"
559
+ f"--package-spec {code_mower_next_steps.current_alpha_package_spec()} "
560
+ "--allow-package-index --json"
560
561
  ),
561
562
  ]
562
563
  )
@@ -51,6 +51,39 @@ detect_repo_slug = _doctor_checks.detect_repo_slug
51
51
  normalize_repo_slug = _doctor_checks.normalize_repo_slug
52
52
 
53
53
 
54
+ def _source_repo_uses_starter_config(cwd: Path, config_path: Path) -> bool:
55
+ """Return true when doctor is running from Code Mower's source tree."""
56
+
57
+ try:
58
+ config_path.resolve().relative_to(cwd.resolve())
59
+ except ValueError:
60
+ return False
61
+ return (
62
+ config_path.name == "code-mower.example.yml"
63
+ and (cwd / "pyproject.toml").is_file()
64
+ and (cwd / "src" / "code_mower" / "templates" / "code-mower.example.yml").is_file()
65
+ )
66
+
67
+
68
+ def _doctor_config_source_label(
69
+ *,
70
+ config_arg: str,
71
+ config_path: Path,
72
+ easy: bool,
73
+ cwd: Path | None = None,
74
+ ) -> str:
75
+ """Classify the config source for adoption-facing doctor output."""
76
+
77
+ cwd = cwd or Path.cwd()
78
+ if config_arg != "code-mower.yml":
79
+ return "explicit_config"
80
+ if config_path.name == "code-mower.example.yml" and easy:
81
+ if _source_repo_uses_starter_config(cwd, config_path):
82
+ return "source_tree_starter"
83
+ return "packaged_starter"
84
+ return "repository_config"
85
+
86
+
54
87
  _DOCTOR_COMPAT_EXPORTS = (
55
88
  DEFAULT_CLOUD_TOKEN_DIR,
56
89
  DEFAULT_CLOUD_TOKEN_ENV,
@@ -68,6 +101,7 @@ _DOCTOR_COMPAT_EXPORTS = (
68
101
  resolve_doctor_config_path_for_script,
69
102
  resolve_doctor_provider_templates_path,
70
103
  _token_file_mentions_cloud_token,
104
+ _doctor_config_source_label,
71
105
  )
72
106
 
73
107
 
@@ -202,12 +236,18 @@ def main(argv: Sequence[str] | None = None) -> int:
202
236
  repo_slug = detect_repo_slug(Path.cwd())
203
237
  repo_source = "git_remote" if repo_slug else ""
204
238
  provider_templates_path = resolve_doctor_provider_templates_path(args.provider_templates)
239
+ config_path = resolve_doctor_config_path(args.config, easy=args.easy)
205
240
  report = run_doctor(
206
- config_path=resolve_doctor_config_path(args.config, easy=args.easy),
241
+ config_path=config_path,
207
242
  provider_templates_path=provider_templates_path,
208
243
  profile=args.profile,
209
244
  repo_slug=repo_slug,
210
245
  repo_source=repo_source,
246
+ config_source=_doctor_config_source_label(
247
+ config_arg=args.config,
248
+ config_path=config_path,
249
+ easy=args.easy,
250
+ ),
211
251
  adoption=args.adoption,
212
252
  adoption_posture=args.adoption_posture,
213
253
  probe_runtime=args.probe_runtime,
@@ -13,6 +13,7 @@ from .cloud import (
13
13
  token_file_mentions_cloud_token,
14
14
  )
15
15
  from .adoption import (
16
+ check_adoption_posture_guidance,
16
17
  check_adoption_setup,
17
18
  config_with_repository_target,
18
19
  detect_repo_slug,
@@ -31,6 +32,7 @@ from .github_human_token import (
31
32
  human_automation_token_config,
32
33
  human_automation_token_required,
33
34
  )
35
+ from .github_trusted_authors import trusted_author_variable_statuses
34
36
  from .groups import GROUP_LABELS, doctor_check_group_id
35
37
  from .models import (
36
38
  STATUS_FAIL,
@@ -105,11 +107,13 @@ __all__ = [
105
107
  "auth_probe_output_detail",
106
108
  "build_doctor_run_plan",
107
109
  "check_cloud_token_surface",
110
+ "check_adoption_posture_guidance",
108
111
  "check_adoption_setup",
109
112
  "check_github_auth_surface",
110
113
  "check_macos_runner_launchagent",
111
114
  "check_github_setup",
112
115
  "check_human_automation_token",
116
+ "trusted_author_variable_statuses",
113
117
  "check_repository_posture",
114
118
  "check_lane_runtime",
115
119
  "check_review_hygiene",