code-mower 0.5.0b16__tar.gz → 0.5.0b18__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 (271) hide show
  1. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/PKG-INFO +6 -6
  2. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/README.md +5 -5
  3. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/pyproject.toml +1 -1
  4. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/__init__.py +1 -1
  5. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/cli.py +1 -1
  6. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/doctor_checks/provider_review_hygiene.py +32 -0
  7. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/doctor_checks/providers.py +10 -1
  8. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/doctor_checks/runner.py +5 -0
  9. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/providers/provenance.py +29 -1
  10. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower.egg-info/PKG-INFO +6 -6
  11. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/tests/test_doctor_provider_review_hygiene.py +46 -0
  12. code_mower-0.5.0b18/tests/test_doctor_registry.py +140 -0
  13. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/tests/test_provider_local_cli.py +42 -0
  14. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/tests/test_release_hygiene.py +34 -34
  15. code_mower-0.5.0b16/tests/test_doctor_registry.py +0 -68
  16. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/CODE_OF_CONDUCT.md +0 -0
  17. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/LICENSE +0 -0
  18. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/MANIFEST.in +0 -0
  19. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/NOTICE +0 -0
  20. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/SUPPORT.md +0 -0
  21. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/requirements/requirements.txt +0 -0
  22. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/setup.cfg +0 -0
  23. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/adapters/__init__.py +0 -0
  24. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/adapters/_base.py +0 -0
  25. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/adapters/cursor_bugbot.py +0 -0
  26. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/adapters/gitar.py +0 -0
  27. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/adapters/greptile.py +0 -0
  28. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/adapters/qodo.py +0 -0
  29. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/antigravity_cli_audit_pr.py +0 -0
  30. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/audit_handoff_log.py +0 -0
  31. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/audit_labeler_lib.py +0 -0
  32. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/audit_progress.py +0 -0
  33. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/blind_review_artifacts.py +0 -0
  34. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/blind_review_coordinator.py +0 -0
  35. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/bootstrap.py +0 -0
  36. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/builder_experiment.py +0 -0
  37. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/calibration/__init__.py +0 -0
  38. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/calibration/arms.py +0 -0
  39. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/calibration/auto_discovery.py +0 -0
  40. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/calibration/commands.py +0 -0
  41. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/calibration/context_inputs.py +0 -0
  42. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/calibration/corpus.py +0 -0
  43. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/calibration/effect_report.py +0 -0
  44. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/calibration/evidence.py +0 -0
  45. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/calibration/evidence_report.py +0 -0
  46. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/calibration/identity.py +0 -0
  47. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/calibration/metrics.py +0 -0
  48. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/calibration/overlap.py +0 -0
  49. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/calibration/planning.py +0 -0
  50. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/calibration/policy.py +0 -0
  51. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/calibration/results.py +0 -0
  52. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/calibration/run_results.py +0 -0
  53. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/calibration/run_status.py +0 -0
  54. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/calibration/runner.py +0 -0
  55. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/calibration/truth.py +0 -0
  56. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/calibration/value_report.py +0 -0
  57. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/checks.py +0 -0
  58. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/claude_audit_pr.py +0 -0
  59. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/claude_cli_bounce.py +0 -0
  60. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/claude_cli_environment.py +0 -0
  61. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/clear_stale.py +0 -0
  62. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/cloud.py +0 -0
  63. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/cloud_client/__init__.py +0 -0
  64. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/cloud_client/bundle.py +0 -0
  65. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/cloud_client/doctor.py +0 -0
  66. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/cloud_client/dogfood.py +0 -0
  67. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/cloud_client/endpoints.py +0 -0
  68. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/cloud_client/errors.py +0 -0
  69. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/cloud_client/events.py +0 -0
  70. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/cloud_client/export.py +0 -0
  71. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/cloud_client/git_metadata.py +0 -0
  72. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/cloud_client/manifest.py +0 -0
  73. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/cloud_client/operations.py +0 -0
  74. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/cloud_client/reports.py +0 -0
  75. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/cloud_client/setup.py +0 -0
  76. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/cloud_client/upload.py +0 -0
  77. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/code_mower_calibration.py +0 -0
  78. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/code_mower_context_packs.py +0 -0
  79. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/code_mower_merge.py +0 -0
  80. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/code_mower_telemetry.py +0 -0
  81. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/coderabbit_cli_audit_pr.py +0 -0
  82. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/codex_audit_env_preflight.py +0 -0
  83. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/codex_audit_pr.py +0 -0
  84. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/codex_audit_schema_smoke.py +0 -0
  85. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/codex_audit_verdict.schema.json +0 -0
  86. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/config.py +0 -0
  87. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/doctor.py +0 -0
  88. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/doctor_checks/__init__.py +0 -0
  89. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/doctor_checks/cloud.py +0 -0
  90. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/doctor_checks/common.py +0 -0
  91. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/doctor_checks/github.py +0 -0
  92. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/doctor_checks/github_actions.py +0 -0
  93. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/doctor_checks/github_actions_cost.py +0 -0
  94. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/doctor_checks/github_actions_cost_summary.py +0 -0
  95. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/doctor_checks/github_actions_failure_annotations.py +0 -0
  96. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/doctor_checks/github_actions_failure_models.py +0 -0
  97. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/doctor_checks/github_actions_failure_scan.py +0 -0
  98. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/doctor_checks/github_actions_failure_selection.py +0 -0
  99. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/doctor_checks/github_actions_failures.py +0 -0
  100. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/doctor_checks/github_actions_permissions.py +0 -0
  101. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/doctor_checks/github_api.py +0 -0
  102. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/doctor_checks/github_branch.py +0 -0
  103. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/doctor_checks/github_config.py +0 -0
  104. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/doctor_checks/github_provider.py +0 -0
  105. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/doctor_checks/github_repo.py +0 -0
  106. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/doctor_checks/groups.py +0 -0
  107. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/doctor_checks/models.py +0 -0
  108. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/doctor_checks/output.py +0 -0
  109. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/doctor_checks/presets.py +0 -0
  110. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/doctor_checks/privacy.py +0 -0
  111. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/doctor_checks/provider_api_model.py +0 -0
  112. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/doctor_checks/provider_api_model_openai.py +0 -0
  113. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/doctor_checks/provider_api_model_profiles.py +0 -0
  114. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/doctor_checks/provider_env.py +0 -0
  115. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/doctor_checks/provider_env_required.py +0 -0
  116. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/doctor_checks/provider_env_tokens.py +0 -0
  117. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/doctor_checks/provider_local_cli.py +0 -0
  118. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/doctor_checks/provider_local_cli_commands.py +0 -0
  119. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/doctor_checks/provider_local_cli_probe_config.py +0 -0
  120. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/doctor_checks/provider_probe.py +0 -0
  121. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/doctor_checks/provider_probe_auth.py +0 -0
  122. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/doctor_checks/provider_probe_evaluation.py +0 -0
  123. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/doctor_checks/provider_probe_json.py +0 -0
  124. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/doctor_checks/provider_probe_remediation.py +0 -0
  125. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/doctor_checks/registry.py +0 -0
  126. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/doctor_checks/runtime.py +0 -0
  127. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/doctor_checks/runtime_github_auth.py +0 -0
  128. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/gemini_cli_audit_pr.py +0 -0
  129. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/hermes_cli_audit_pr.py +0 -0
  130. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/init.py +0 -0
  131. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/lane_configs/__init__.py +0 -0
  132. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/lane_configs/aider.py +0 -0
  133. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/lane_configs/antigravity_cli.py +0 -0
  134. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/lane_configs/claude.py +0 -0
  135. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/lane_configs/codex.py +0 -0
  136. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/lane_configs/devin.py +0 -0
  137. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/lane_configs/gemini_cli.py +0 -0
  138. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/lane_configs/hermes_cli.py +0 -0
  139. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/lane_configs/local_llm.py +0 -0
  140. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/local_llm_audit_pr.py +0 -0
  141. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/local_llm_bakeoff.py +0 -0
  142. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/local_llm_calibration.py +0 -0
  143. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/local_llm_profiles.py +0 -0
  144. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/migration.py +0 -0
  145. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/migration_install.py +0 -0
  146. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/migration_mirror.py +0 -0
  147. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/migration_readiness.py +0 -0
  148. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/migration_rehearsal.py +0 -0
  149. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/next_steps.py +0 -0
  150. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/package.py +0 -0
  151. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/package_content.py +0 -0
  152. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/package_manifest.py +0 -0
  153. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/package_paths.py +0 -0
  154. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/package_rendering.py +0 -0
  155. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/package_static.py +0 -0
  156. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/prompts.py +0 -0
  157. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/provider_registry.py +0 -0
  158. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/provider_runners/__init__.py +0 -0
  159. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/provider_runners/comments.py +0 -0
  160. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/provider_runners/git.py +0 -0
  161. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/provider_runners/github_auth.py +0 -0
  162. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/provider_runners/github_pr.py +0 -0
  163. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/provider_runners/pr_worktree.py +0 -0
  164. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/provider_runners/process.py +0 -0
  165. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/provider_runners/repo_paths.py +0 -0
  166. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/provider_runners/text_schema.py +0 -0
  167. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/provider_runners/verdict_artifacts.py +0 -0
  168. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/provider_runners/workspace.py +0 -0
  169. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/providers/__init__.py +0 -0
  170. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/providers/local_cli.py +0 -0
  171. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/release_readiness.py +0 -0
  172. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/reviewer_metrics.py +0 -0
  173. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/saas_reviewer_labeler.py +0 -0
  174. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/secrets.py +0 -0
  175. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/templates/builder-experiment.example.json +0 -0
  176. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/templates/calibration-corpus.example.json +0 -0
  177. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/templates/calibration-corpus.json +0 -0
  178. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/templates/code-mower.example.yml +0 -0
  179. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/templates/context-packs.example.json +0 -0
  180. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/templates/lane_prompts/base-audit.md +0 -0
  181. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/templates/lane_prompts/calibration-policy.md +0 -0
  182. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/templates/lane_prompts/context-driven-quality.md +0 -0
  183. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/templates/lane_prompts/docs-design.md +0 -0
  184. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/templates/lane_prompts/generic-programming.md +0 -0
  185. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/templates/lane_prompts/operability.md +0 -0
  186. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/templates/lane_prompts/package-runtime.md +0 -0
  187. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/templates/lane_prompts/security-threat-model.md +0 -0
  188. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/templates/product-support/code_mower +0 -0
  189. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/templates/product-support/code_mower_standalone_pin.env +0 -0
  190. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/templates/product-support/code_mower_standalone_shadow.sh +0 -0
  191. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/templates/product-support/run_claude_audit_pr.sh +0 -0
  192. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/templates/product-support/run_codex_audit_pr.sh +0 -0
  193. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/templates/product-support/safe_gh_comment.py +0 -0
  194. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/templates/providers.yml +0 -0
  195. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/templates/reviewer-spend.example.json +0 -0
  196. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/templates/reviewer-value-report.example.md +0 -0
  197. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/templates/workflows/audit-label-cleanup.yml.j2 +0 -0
  198. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/templates/workflows/hosted-bridge.yml.j2 +0 -0
  199. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/templates/workflows/local-cli-audit.yml.j2 +0 -0
  200. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/templates/workflows/private-standalone-shadow.yml.j2 +0 -0
  201. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/templates/workflows/review-clear-stale.yml.j2 +0 -0
  202. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/templates/workflows/saas-reviewer-labeler.yml.j2 +0 -0
  203. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/templates/workflows/trailer-comment-labeler.yml.j2 +0 -0
  204. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/trailer_comment_labeler.py +0 -0
  205. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower/versioning.py +0 -0
  206. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower.egg-info/SOURCES.txt +0 -0
  207. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower.egg-info/dependency_links.txt +0 -0
  208. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower.egg-info/entry_points.txt +0 -0
  209. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower.egg-info/requires.txt +0 -0
  210. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/src/code_mower.egg-info/top_level.txt +0 -0
  211. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/templates/builder-experiment.example.json +0 -0
  212. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/templates/calibration-corpus.example.json +0 -0
  213. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/templates/calibration-corpus.json +0 -0
  214. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/templates/code-mower.yml.j2 +0 -0
  215. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/templates/context-packs.example.json +0 -0
  216. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/templates/cursor/BUGBOT.md +0 -0
  217. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/templates/providers/acp_bridge.yml +0 -0
  218. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/templates/providers/aider.yml +0 -0
  219. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/templates/providers/antigravity_cli.yml +0 -0
  220. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/templates/providers/claude_audit.yml +0 -0
  221. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/templates/providers/claude_review.yml +0 -0
  222. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/templates/providers/coderabbit_cli.yml +0 -0
  223. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/templates/providers/codex.yml +0 -0
  224. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/templates/providers/cursor_bugbot.yml +0 -0
  225. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/templates/providers/devin.yml +0 -0
  226. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/templates/providers/gemini_cli.yml +0 -0
  227. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/templates/providers/gitar.yml +0 -0
  228. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/templates/providers/greptile.yml +0 -0
  229. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/templates/providers/hermes_cli.yml +0 -0
  230. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/templates/providers/local_llm.yml +0 -0
  231. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/templates/providers/qodo.yml +0 -0
  232. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/templates/providers.yml +0 -0
  233. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/templates/reviewer-spend.example.json +0 -0
  234. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/templates/reviewer-value-report.example.md +0 -0
  235. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/templates/workflows/audit-label-cleanup.yml.j2 +0 -0
  236. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/templates/workflows/blind-review-artifacts-dry-run.yml.j2 +0 -0
  237. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/templates/workflows/hosted-bridge.yml.j2 +0 -0
  238. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/templates/workflows/local-cli-audit.yml.j2 +0 -0
  239. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/templates/workflows/private-standalone-shadow.yml.j2 +0 -0
  240. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/templates/workflows/review-clear-stale.yml.j2 +0 -0
  241. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/templates/workflows/saas-reviewer-labeler.yml.j2 +0 -0
  242. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/templates/workflows/trailer-comment-labeler.yml.j2 +0 -0
  243. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/tests/test_calibration_effect_report.py +0 -0
  244. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/tests/test_calibration_truth.py +0 -0
  245. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/tests/test_checks.py +0 -0
  246. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/tests/test_claude_cli_bounce.py +0 -0
  247. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/tests/test_clear_stale.py +0 -0
  248. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/tests/test_cloud_client.py +0 -0
  249. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/tests/test_cloud_git_metadata.py +0 -0
  250. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/tests/test_cloud_manifest.py +0 -0
  251. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/tests/test_cloud_reports.py +0 -0
  252. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/tests/test_coderabbit_cli_audit_pr.py +0 -0
  253. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/tests/test_doctor_actions_cost_summary.py +0 -0
  254. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/tests/test_doctor_actions_failure_selection.py +0 -0
  255. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/tests/test_doctor_boundaries.py +0 -0
  256. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/tests/test_doctor_github_checks.py +0 -0
  257. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/tests/test_doctor_output.py +0 -0
  258. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/tests/test_doctor_privacy.py +0 -0
  259. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/tests/test_doctor_provider_env_required.py +0 -0
  260. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/tests/test_doctor_provider_env_tokens.py +0 -0
  261. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/tests/test_doctor_provider_probe.py +0 -0
  262. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/tests/test_local_llm_github_helpers.py +0 -0
  263. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/tests/test_provider_runners_comments.py +0 -0
  264. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/tests/test_provider_runners_git.py +0 -0
  265. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/tests/test_provider_runners_github_pr.py +0 -0
  266. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/tests/test_provider_runners_pr_worktree.py +0 -0
  267. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/tests/test_provider_runners_process.py +0 -0
  268. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/tests/test_provider_runners_repo_paths.py +0 -0
  269. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/tests/test_provider_runners_text_schema.py +0 -0
  270. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/tests/test_provider_runners_workspace.py +0 -0
  271. {code_mower-0.5.0b16 → code_mower-0.5.0b18}/tests/test_reviewer_metrics_core.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: code-mower
3
- Version: 0.5.0b16
3
+ Version: 0.5.0b18
4
4
  Summary: Multi-reviewer AI code audit orchestration
5
5
  License-Expression: Apache-2.0
6
6
  Requires-Python: >=3.11
@@ -101,11 +101,11 @@ Code Mower currently targets Python 3.11+; Python 3.12 is recommended.
101
101
 
102
102
  ```bash
103
103
  python3.12 --version
104
- pipx install --python python3.12 code-mower==0.5.0b16
104
+ pipx install --python python3.12 code-mower==0.5.0b18
105
105
  code-mower --version
106
106
  ```
107
107
 
108
- `0.5.0b16` is a beta release. Until Code Mower publishes a stable `1.0`
108
+ `0.5.0b18` is a beta release. Until Code Mower publishes a stable `1.0`
109
109
  line, use the explicit beta version above or allow prereleases with:
110
110
 
111
111
  ```bash
@@ -148,7 +148,7 @@ First-time command map: [docs/launch-command-surface.md](docs/launch-command-sur
148
148
 
149
149
  The current PyPI beta has been rehearsed end-to-end from a clean install:
150
150
  [First-User Install Rehearsal](docs/first-user-install-rehearsal.md) records
151
- the latest 10/10 public-package readiness proof for `code-mower==0.5.0b16`.
151
+ the latest 10/10 public-package readiness proof for `code-mower==0.5.0b18`.
152
152
 
153
153
  ## Why Not Just Run Codex Or Claude Yourself?
154
154
 
@@ -253,9 +253,9 @@ best?" to "which AI builder plus reviewer loop ships best on this product?" See
253
253
 
254
254
  ## Installation Status
255
255
 
256
- The current public beta is `v0.5.0-beta.16` from
256
+ The current public beta is `v0.5.0-beta.18` from
257
257
  [codemower-ai/code-mower](https://github.com/codemower-ai/code-mower), published
258
- as `code-mower==0.5.0b16` on [PyPI](https://pypi.org/project/code-mower/).
258
+ as `code-mower==0.5.0b18` on [PyPI](https://pypi.org/project/code-mower/).
259
259
  GitHub releases remain the auditable source for tags, build artifacts, and
260
260
  release notes.
261
261
 
@@ -86,11 +86,11 @@ Code Mower currently targets Python 3.11+; Python 3.12 is recommended.
86
86
 
87
87
  ```bash
88
88
  python3.12 --version
89
- pipx install --python python3.12 code-mower==0.5.0b16
89
+ pipx install --python python3.12 code-mower==0.5.0b18
90
90
  code-mower --version
91
91
  ```
92
92
 
93
- `0.5.0b16` is a beta release. Until Code Mower publishes a stable `1.0`
93
+ `0.5.0b18` is a beta release. Until Code Mower publishes a stable `1.0`
94
94
  line, use the explicit beta version above or allow prereleases with:
95
95
 
96
96
  ```bash
@@ -133,7 +133,7 @@ First-time command map: [docs/launch-command-surface.md](docs/launch-command-sur
133
133
 
134
134
  The current PyPI beta has been rehearsed end-to-end from a clean install:
135
135
  [First-User Install Rehearsal](docs/first-user-install-rehearsal.md) records
136
- the latest 10/10 public-package readiness proof for `code-mower==0.5.0b16`.
136
+ the latest 10/10 public-package readiness proof for `code-mower==0.5.0b18`.
137
137
 
138
138
  ## Why Not Just Run Codex Or Claude Yourself?
139
139
 
@@ -238,9 +238,9 @@ best?" to "which AI builder plus reviewer loop ships best on this product?" See
238
238
 
239
239
  ## Installation Status
240
240
 
241
- The current public beta is `v0.5.0-beta.16` from
241
+ The current public beta is `v0.5.0-beta.18` from
242
242
  [codemower-ai/code-mower](https://github.com/codemower-ai/code-mower), published
243
- as `code-mower==0.5.0b16` on [PyPI](https://pypi.org/project/code-mower/).
243
+ as `code-mower==0.5.0b18` on [PyPI](https://pypi.org/project/code-mower/).
244
244
  GitHub releases remain the auditable source for tags, build artifacts, and
245
245
  release notes.
246
246
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "code-mower"
7
- version = "0.5.0b16"
7
+ version = "0.5.0b18"
8
8
  description = "Multi-reviewer AI code audit orchestration"
9
9
  requires-python = ">=3.11"
10
10
  readme = "README.md"
@@ -1,3 +1,3 @@
1
1
  """Code Mower package."""
2
2
 
3
- __version__ = "0.5.0b16"
3
+ __version__ = "0.5.0b18"
@@ -14,7 +14,7 @@ from pathlib import Path
14
14
  if __package__ in {None, ""}:
15
15
  raise SystemExit(
16
16
  "code_mower.cli is a packaged entrypoint. Install Code Mower with "
17
- "`pipx install code-mower==0.5.0b16`, or run source checkouts with "
17
+ "`pipx install code-mower==0.5.0b18`, or run source checkouts with "
18
18
  "`PYTHONPATH=src python -m code_mower.cli`."
19
19
  )
20
20
 
@@ -2,6 +2,7 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ from pathlib import Path
5
6
  from typing import Any, Mapping
6
7
 
7
8
  from .common import DoctorCheck, STATUS_FAIL, STATUS_PASS, STATUS_SKIP, as_sequence
@@ -12,6 +13,7 @@ def check_review_hygiene(
12
13
  lane: Mapping[str, Any],
13
14
  *,
14
15
  effective_lane: Mapping[str, Any] | None = None,
16
+ repo_root: Path | None = None,
15
17
  ) -> DoctorCheck:
16
18
  """Verify that merge-authority lanes have stale terminal-label protection."""
17
19
 
@@ -78,6 +80,36 @@ def check_review_hygiene(
78
80
  ),
79
81
  )
80
82
 
83
+ if repo_root is not None:
84
+ workflow_path = Path(workflow)
85
+ if not workflow_path.is_absolute():
86
+ workflow_path = repo_root / workflow_path
87
+ if not workflow_path.is_file():
88
+ return DoctorCheck(
89
+ name="provider.review_hygiene",
90
+ status=STATUS_FAIL,
91
+ lane=lane_id,
92
+ message=(
93
+ "merge-authority lane stale terminal-label workflow is "
94
+ f"configured but missing from the repo: {workflow}"
95
+ ),
96
+ detail={
97
+ **detail,
98
+ "workflow_exists": False,
99
+ "workflow_path": str(workflow_path),
100
+ },
101
+ remediation=(
102
+ "Run `code-mower init --easy --apply` from the repository "
103
+ "root, commit the generated clear-stale workflow, then rerun "
104
+ "doctor before relying on this lane as merge authority."
105
+ ),
106
+ )
107
+ detail = {
108
+ **detail,
109
+ "workflow_exists": True,
110
+ "workflow_path": str(workflow_path),
111
+ }
112
+
81
113
  return DoctorCheck(
82
114
  name="provider.review_hygiene",
83
115
  status=STATUS_PASS,
@@ -2,6 +2,7 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ from pathlib import Path
5
6
  from typing import Any, Mapping
6
7
 
7
8
  from .common import (
@@ -112,11 +113,19 @@ def check_lane_runtime(
112
113
  lane: Mapping[str, Any],
113
114
  *,
114
115
  source_lane: Mapping[str, Any] | None = None,
116
+ repo_root: Path | None = None,
115
117
  probe_runtime: bool,
116
118
  http_timeout: int,
117
119
  ) -> list[DoctorCheck]:
118
120
  hygiene_source = source_lane if source_lane is not None else lane
119
- checks = [check_review_hygiene(lane_id, hygiene_source, effective_lane=lane)]
121
+ checks = [
122
+ check_review_hygiene(
123
+ lane_id,
124
+ hygiene_source,
125
+ effective_lane=lane,
126
+ repo_root=repo_root,
127
+ )
128
+ ]
120
129
  checks.extend(check_token_env(lane_id, lane))
121
130
  checks.extend(check_required_env(lane_id, lane))
122
131
  driver = str(lane.get("driver", ""))
@@ -75,6 +75,10 @@ def run_doctor(
75
75
  ) -> DoctorReport:
76
76
  plan = build_doctor_run_plan(github=github, cloud=cloud)
77
77
  enabled_stages = {stage.id for stage in plan}
78
+ # `doctor --easy` can inspect the packaged example before a repo has written
79
+ # code-mower.yml. In that mode the example should teach the user about stale
80
+ # guards without failing because product workflow files are not installed yet.
81
+ repo_root = None if config_path.name == "code-mower.example.yml" else config_path.parent
78
82
  config, templates, checks = load_inputs(config_path, provider_templates_path)
79
83
  checks.append(
80
84
  _run_plan_check(
@@ -163,6 +167,7 @@ def run_doctor(
163
167
  lane_id,
164
168
  effective,
165
169
  source_lane=lane,
170
+ repo_root=repo_root,
166
171
  probe_runtime=probe_runtime,
167
172
  http_timeout=http_timeout,
168
173
  )
@@ -162,6 +162,31 @@ def _env_value(config: Mapping[str, Any], key: str) -> str:
162
162
  return _safe_text(os.environ.get(env_name)) if env_name else ""
163
163
 
164
164
 
165
+ def _profile_model(config: Mapping[str, Any]) -> tuple[str, str]:
166
+ profile_env = _safe_text(config.get("profile_env"))
167
+ profile_id = _safe_text(os.environ.get(profile_env)) if profile_env else ""
168
+ profiles = config.get("profiles")
169
+ if not profile_id or not isinstance(profiles, Mapping):
170
+ return "", ""
171
+ profile = profiles.get(profile_id)
172
+ if not isinstance(profile, Mapping):
173
+ return "", profile_id
174
+ return _safe_text(profile.get("model")), profile_id
175
+
176
+
177
+ def _configured_model(config: Mapping[str, Any]) -> tuple[str, str]:
178
+ env_model = _env_value(config, "model_env")
179
+ if env_model:
180
+ return env_model, "env"
181
+ profile_model, profile_id = _profile_model(config)
182
+ if profile_model:
183
+ return profile_model, f"profile:{profile_id}"
184
+ default_model = _safe_text(config.get("default_model"))
185
+ if default_model:
186
+ return default_model, "default"
187
+ return "", "missing"
188
+
189
+
165
190
  def _configured_command_candidates(
166
191
  config: Mapping[str, Any],
167
192
  provider: str,
@@ -208,7 +233,7 @@ def build_provider_lane_tool_provenance(
208
233
  driver = _safe_text(_lane_value(lane, "driver")) or "unknown"
209
234
  command_candidates = _configured_command_candidates(config, provider)
210
235
  command, resolved_command = _select_available_command(command_candidates)
211
- model = _env_value(config, "model_env") or _safe_text(config.get("default_model"))
236
+ model, model_source = _configured_model(config)
212
237
  provider_from_env = _env_value(config, "provider_env")
213
238
  if provider_from_env:
214
239
  provider = provider_from_env
@@ -228,7 +253,9 @@ def build_provider_lane_tool_provenance(
228
253
  "command": command if driver == "local_cli" else "",
229
254
  "command_candidates": list(command_candidates) if driver == "local_cli" else [],
230
255
  "model_known": bool(model),
256
+ "model_source": model_source,
231
257
  "version_known": False,
258
+ "version_source": "not_probed" if driver != "local_cli" else "missing",
232
259
  }
233
260
  tool_version = ""
234
261
  if driver == "local_cli" and include_version_probe and command:
@@ -238,6 +265,7 @@ def build_provider_lane_tool_provenance(
238
265
  version_detail = detect_local_cli_version(resolved_command)
239
266
  tool_version = _safe_text(version_detail.get("tool_version"))
240
267
  detail["version_known"] = bool(tool_version)
268
+ detail["version_source"] = "cli_version_probe" if tool_version else "missing"
241
269
  detail["tool_version_available"] = bool(
242
270
  version_detail.get("tool_version_available")
243
271
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: code-mower
3
- Version: 0.5.0b16
3
+ Version: 0.5.0b18
4
4
  Summary: Multi-reviewer AI code audit orchestration
5
5
  License-Expression: Apache-2.0
6
6
  Requires-Python: >=3.11
@@ -101,11 +101,11 @@ Code Mower currently targets Python 3.11+; Python 3.12 is recommended.
101
101
 
102
102
  ```bash
103
103
  python3.12 --version
104
- pipx install --python python3.12 code-mower==0.5.0b16
104
+ pipx install --python python3.12 code-mower==0.5.0b18
105
105
  code-mower --version
106
106
  ```
107
107
 
108
- `0.5.0b16` is a beta release. Until Code Mower publishes a stable `1.0`
108
+ `0.5.0b18` is a beta release. Until Code Mower publishes a stable `1.0`
109
109
  line, use the explicit beta version above or allow prereleases with:
110
110
 
111
111
  ```bash
@@ -148,7 +148,7 @@ First-time command map: [docs/launch-command-surface.md](docs/launch-command-sur
148
148
 
149
149
  The current PyPI beta has been rehearsed end-to-end from a clean install:
150
150
  [First-User Install Rehearsal](docs/first-user-install-rehearsal.md) records
151
- the latest 10/10 public-package readiness proof for `code-mower==0.5.0b16`.
151
+ the latest 10/10 public-package readiness proof for `code-mower==0.5.0b18`.
152
152
 
153
153
  ## Why Not Just Run Codex Or Claude Yourself?
154
154
 
@@ -253,9 +253,9 @@ best?" to "which AI builder plus reviewer loop ships best on this product?" See
253
253
 
254
254
  ## Installation Status
255
255
 
256
- The current public beta is `v0.5.0-beta.16` from
256
+ The current public beta is `v0.5.0-beta.18` from
257
257
  [codemower-ai/code-mower](https://github.com/codemower-ai/code-mower), published
258
- as `code-mower==0.5.0b16` on [PyPI](https://pypi.org/project/code-mower/).
258
+ as `code-mower==0.5.0b18` on [PyPI](https://pypi.org/project/code-mower/).
259
259
  GitHub releases remain the auditable source for tags, build artifacts, and
260
260
  release notes.
261
261
 
@@ -1,5 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
+ from pathlib import Path
4
+ from tempfile import TemporaryDirectory
3
5
  import unittest
4
6
 
5
7
  from code_mower.doctor_checks.provider_review_hygiene import check_review_hygiene
@@ -63,6 +65,50 @@ class DoctorProviderReviewHygieneTests(unittest.TestCase):
63
65
  self.assertEqual(check.detail["dispatch_workflow"], "codex-audit-labeler.yml")
64
66
  self.assertEqual(check.detail["trusted_authors"], ["codex[bot]"])
65
67
 
68
+ def test_merge_authority_lane_fails_when_configured_workflow_is_missing(self) -> None:
69
+ with TemporaryDirectory() as tmp:
70
+ repo_root = Path(tmp)
71
+ check = check_review_hygiene(
72
+ "codex",
73
+ {
74
+ "merge_authority": True,
75
+ "review_hygiene": {
76
+ "workflow": ".github/workflows/codex-clear-stale.yml",
77
+ "token_env": "GITHUB_TOKEN",
78
+ },
79
+ },
80
+ repo_root=repo_root,
81
+ )
82
+
83
+ self.assertEqual(check.status, "fail")
84
+ self.assertIn("configured but missing", check.message)
85
+ self.assertEqual(check.detail["workflow_exists"], False)
86
+ self.assertIn(".github/workflows/codex-clear-stale.yml", check.detail["workflow_path"])
87
+ self.assertIn("code-mower init --easy --apply", check.remediation)
88
+
89
+ def test_merge_authority_lane_passes_when_configured_workflow_exists(self) -> None:
90
+ with TemporaryDirectory() as tmp:
91
+ repo_root = Path(tmp)
92
+ workflow = repo_root / ".github/workflows/codex-clear-stale.yml"
93
+ workflow.parent.mkdir(parents=True)
94
+ workflow.write_text("name: clear stale\n", encoding="utf-8")
95
+
96
+ check = check_review_hygiene(
97
+ "codex",
98
+ {
99
+ "merge_authority": True,
100
+ "review_hygiene": {
101
+ "workflow": ".github/workflows/codex-clear-stale.yml",
102
+ "token_env": "GITHUB_TOKEN",
103
+ },
104
+ },
105
+ repo_root=repo_root,
106
+ )
107
+
108
+ self.assertEqual(check.status, "pass")
109
+ self.assertEqual(check.detail["workflow_exists"], True)
110
+ self.assertEqual(check.detail["workflow_path"], str(workflow))
111
+
66
112
  def test_merge_authority_lane_rejects_custom_hygiene_token_until_template_supports_it(self) -> None:
67
113
  check = check_review_hygiene(
68
114
  "devin",
@@ -0,0 +1,140 @@
1
+ import tempfile
2
+ import unittest
3
+ from pathlib import Path
4
+
5
+ from code_mower.doctor_checks import (
6
+ build_doctor_run_plan,
7
+ default_check_group_ids,
8
+ run_doctor,
9
+ )
10
+
11
+ ROOT = Path(__file__).resolve().parents[1]
12
+
13
+
14
+ class DoctorRegistryTests(unittest.TestCase):
15
+ def test_default_check_groups_stay_stable(self) -> None:
16
+ self.assertEqual(
17
+ default_check_group_ids(),
18
+ ("runtime", "github", "providers", "cloud", "output"),
19
+ )
20
+
21
+ def test_run_plan_enables_optional_stages_explicitly(self) -> None:
22
+ base_plan = build_doctor_run_plan()
23
+ self.assertEqual(
24
+ tuple(stage.id for stage in base_plan),
25
+ ("load-inputs", "select-profile", "runtime", "providers"),
26
+ )
27
+ self.assertTrue(all(not stage.optional for stage in base_plan))
28
+
29
+ full_plan = build_doctor_run_plan(github=True, cloud=True)
30
+ self.assertEqual(
31
+ tuple(stage.id for stage in full_plan),
32
+ ("load-inputs", "select-profile", "runtime", "providers", "github", "cloud"),
33
+ )
34
+ self.assertEqual(
35
+ {stage.id for stage in full_plan if stage.optional},
36
+ {"github", "cloud"},
37
+ )
38
+
39
+ def test_runner_emits_sanitized_run_plan_check_even_when_inputs_fail(self) -> None:
40
+ with tempfile.TemporaryDirectory() as root:
41
+ root_path = Path(root)
42
+ report = run_doctor(
43
+ config_path=root_path / "missing-code-mower.yml",
44
+ provider_templates_path=root_path / "missing-providers.yml",
45
+ profile="recommended",
46
+ github=True,
47
+ cloud=True,
48
+ )
49
+
50
+ plan_check = next(check for check in report.checks if check.name == "doctor.plan")
51
+ self.assertEqual(plan_check.status, "pass")
52
+ self.assertIn("github", plan_check.message)
53
+ self.assertIn("cloud", plan_check.message)
54
+ self.assertEqual(plan_check.detail["probe_runtime"], False)
55
+ self.assertEqual(
56
+ tuple(stage["id"] for stage in plan_check.detail["stages"]),
57
+ ("load-inputs", "select-profile", "runtime", "providers", "github", "cloud"),
58
+ )
59
+ self.assertEqual(
60
+ tuple(stage["id"] for stage in report.run_plan),
61
+ ("load-inputs", "select-profile", "runtime", "providers", "github", "cloud"),
62
+ )
63
+ self.assertEqual(
64
+ tuple(stage["id"] for stage in report.as_dict()["run_plan"]),
65
+ ("load-inputs", "select-profile", "runtime", "providers", "github", "cloud"),
66
+ )
67
+
68
+ def test_packaged_example_config_does_not_require_installed_stale_workflow(self) -> None:
69
+ report = run_doctor(
70
+ config_path=ROOT / "src/code_mower/templates/code-mower.example.yml",
71
+ provider_templates_path=ROOT / "src/code_mower/templates/providers.yml",
72
+ profile="recommended",
73
+ )
74
+
75
+ hygiene_checks = [
76
+ check for check in report.checks if check.name == "provider.review_hygiene"
77
+ ]
78
+ self.assertTrue(hygiene_checks)
79
+ self.assertFalse(
80
+ any(
81
+ check.status == "fail"
82
+ and "workflow is configured but missing" in check.message
83
+ for check in hygiene_checks
84
+ )
85
+ )
86
+
87
+ def test_real_config_requires_configured_stale_workflow_file(self) -> None:
88
+ with tempfile.TemporaryDirectory() as root:
89
+ root_path = Path(root)
90
+ config_path = root_path / "code-mower.yml"
91
+ config_path.write_text(
92
+ "\n".join(
93
+ [
94
+ "version: 1",
95
+ "project:",
96
+ " name: test",
97
+ " state_dir: .code-mower",
98
+ "repositories:",
99
+ " - slug: owner/repo",
100
+ " default_branch: main",
101
+ "lanes:",
102
+ " codex:",
103
+ " type: audit",
104
+ " provider: codex",
105
+ " merge_authority: true",
106
+ " driver: manual",
107
+ " labels:",
108
+ " needs: needs-codex-audit",
109
+ " done: codex-audit-done",
110
+ " blocked: codex-audit-blocked",
111
+ " review_hygiene:",
112
+ " workflow: .github/workflows/codex-clear-stale.yml",
113
+ " token_env: GITHUB_TOKEN",
114
+ "profiles:",
115
+ " recommended:",
116
+ " description: recommended lanes",
117
+ " lanes: [codex]",
118
+ ]
119
+ ),
120
+ encoding="utf-8",
121
+ )
122
+
123
+ report = run_doctor(
124
+ config_path=config_path,
125
+ provider_templates_path=ROOT / "src/code_mower/templates/providers.yml",
126
+ profile="recommended",
127
+ )
128
+
129
+ hygiene_check = next(
130
+ check
131
+ for check in report.checks
132
+ if check.name == "provider.review_hygiene" and check.lane == "codex"
133
+ )
134
+ self.assertEqual(hygiene_check.status, "fail")
135
+ self.assertEqual(hygiene_check.detail["workflow_exists"], False)
136
+ self.assertIn("configured but missing", hygiene_check.message)
137
+
138
+
139
+ if __name__ == "__main__":
140
+ unittest.main()
@@ -86,7 +86,9 @@ def test_provider_lane_tool_provenance_reads_version_and_model_env(
86
86
  assert detail["command_candidates"] == ["provider-cli"]
87
87
  assert detail["command_found"] is True
88
88
  assert detail["model_known"] is True
89
+ assert detail["model_source"] == "env"
89
90
  assert detail["version_known"] is True
91
+ assert detail["version_source"] == "cli_version_probe"
90
92
 
91
93
 
92
94
  def test_provider_lane_tool_provenance_uses_available_alternate_command(
@@ -121,3 +123,43 @@ def test_provider_lane_tool_provenance_uses_available_alternate_command(
121
123
  assert detail["command_candidates"] == ["agy", "antigravity"]
122
124
  assert detail["command_found"] is True
123
125
  assert detail["version_known"] is True
126
+
127
+
128
+ def test_provider_lane_tool_provenance_reads_model_from_selected_profile(
129
+ monkeypatch,
130
+ tmp_path: Path,
131
+ ) -> None:
132
+ executable = _write_executable(
133
+ tmp_path / "local-model-cli",
134
+ "#!/bin/sh\nprintf 'local-model-cli 1.0.0\\n'\n",
135
+ )
136
+ monkeypatch.setenv("PATH", os.fspath(executable.parent))
137
+ monkeypatch.setenv("LOCAL_LLM_PROFILE", "qwen3-coder-next-lmstudio")
138
+ monkeypatch.delenv("LOCAL_LLM_MODEL", raising=False)
139
+ lane = {
140
+ "driver": "local_cli",
141
+ "provider": "openai_compatible",
142
+ "provider_config": {
143
+ "command": "local-model-cli",
144
+ "model_env": "LOCAL_LLM_MODEL",
145
+ "profile_env": "LOCAL_LLM_PROFILE",
146
+ "profiles": {
147
+ "qwen3-coder-next-lmstudio": {
148
+ "model": "qwen/qwen3-coder-next",
149
+ "endpoint": "lmstudio",
150
+ }
151
+ },
152
+ },
153
+ }
154
+
155
+ tool, detail = build_provider_lane_tool_provenance(
156
+ "local_llm",
157
+ lane,
158
+ source="unit-test",
159
+ )
160
+
161
+ assert tool["model"] == "qwen/qwen3-coder-next"
162
+ assert detail["model_known"] is True
163
+ assert detail["model_source"] == "profile:qwen3-coder-next-lmstudio"
164
+ assert detail["version_known"] is True
165
+ assert detail["version_source"] == "cli_version_probe"