code-mower 0.5.0b38__tar.gz → 0.5.0b40__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 (275) hide show
  1. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/PKG-INFO +6 -6
  2. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/README.md +5 -5
  3. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/pyproject.toml +1 -1
  4. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/__init__.py +1 -1
  5. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/cli.py +1 -1
  6. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/grok_build_audit_pr.py +44 -1
  7. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/init.py +55 -0
  8. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/templates/code-mower.example.yml +2 -0
  9. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/templates/workflows/saas-reviewer-labeler.yml.j2 +3 -9
  10. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/templates/workflows/trailer-comment-labeler.yml.j2 +2 -8
  11. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower.egg-info/PKG-INFO +6 -6
  12. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/templates/workflows/saas-reviewer-labeler.yml.j2 +3 -9
  13. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/templates/workflows/trailer-comment-labeler.yml.j2 +2 -8
  14. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/tests/test_provider_local_cli.py +123 -0
  15. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/tests/test_release_hygiene.py +69 -37
  16. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/CODE_OF_CONDUCT.md +0 -0
  17. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/LICENSE +0 -0
  18. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/MANIFEST.in +0 -0
  19. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/NOTICE +0 -0
  20. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/SUPPORT.md +0 -0
  21. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/requirements/requirements.txt +0 -0
  22. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/setup.cfg +0 -0
  23. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/adapters/__init__.py +0 -0
  24. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/adapters/_base.py +0 -0
  25. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/adapters/cursor_bugbot.py +0 -0
  26. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/adapters/gitar.py +0 -0
  27. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/adapters/greptile.py +0 -0
  28. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/adapters/qodo.py +0 -0
  29. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/antigravity_cli_audit_pr.py +0 -0
  30. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/audit_handoff_log.py +0 -0
  31. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/audit_labeler_lib.py +0 -0
  32. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/audit_progress.py +0 -0
  33. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/blind_review_artifacts.py +0 -0
  34. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/blind_review_coordinator.py +0 -0
  35. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/bootstrap.py +0 -0
  36. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/builder_experiment.py +0 -0
  37. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/calibration/__init__.py +0 -0
  38. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/calibration/arms.py +0 -0
  39. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/calibration/auto_discovery.py +0 -0
  40. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/calibration/commands.py +0 -0
  41. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/calibration/context_inputs.py +0 -0
  42. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/calibration/corpus.py +0 -0
  43. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/calibration/effect_report.py +0 -0
  44. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/calibration/evidence.py +0 -0
  45. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/calibration/evidence_report.py +0 -0
  46. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/calibration/identity.py +0 -0
  47. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/calibration/metrics.py +0 -0
  48. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/calibration/overlap.py +0 -0
  49. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/calibration/planning.py +0 -0
  50. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/calibration/policy.py +0 -0
  51. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/calibration/results.py +0 -0
  52. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/calibration/run_results.py +0 -0
  53. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/calibration/run_status.py +0 -0
  54. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/calibration/runner.py +0 -0
  55. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/calibration/truth.py +0 -0
  56. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/calibration/value_report.py +0 -0
  57. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/checks.py +0 -0
  58. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/claude_audit_pr.py +0 -0
  59. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/claude_cli_bounce.py +0 -0
  60. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/claude_cli_environment.py +0 -0
  61. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/clear_stale.py +0 -0
  62. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/cloud.py +0 -0
  63. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/cloud_client/__init__.py +0 -0
  64. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/cloud_client/bundle.py +0 -0
  65. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/cloud_client/doctor.py +0 -0
  66. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/cloud_client/dogfood.py +0 -0
  67. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/cloud_client/endpoints.py +0 -0
  68. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/cloud_client/errors.py +0 -0
  69. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/cloud_client/events.py +0 -0
  70. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/cloud_client/export.py +0 -0
  71. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/cloud_client/git_metadata.py +0 -0
  72. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/cloud_client/manifest.py +0 -0
  73. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/cloud_client/operations.py +0 -0
  74. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/cloud_client/reports.py +0 -0
  75. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/cloud_client/setup.py +0 -0
  76. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/cloud_client/upload.py +0 -0
  77. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/code_mower_calibration.py +0 -0
  78. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/code_mower_context_packs.py +0 -0
  79. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/code_mower_merge.py +0 -0
  80. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/code_mower_telemetry.py +0 -0
  81. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/coderabbit_cli_audit_pr.py +0 -0
  82. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/codex_audit_env_preflight.py +0 -0
  83. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/codex_audit_pr.py +0 -0
  84. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/codex_audit_schema_smoke.py +0 -0
  85. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/codex_audit_verdict.schema.json +0 -0
  86. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/config.py +0 -0
  87. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/doctor.py +0 -0
  88. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/doctor_checks/__init__.py +0 -0
  89. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/doctor_checks/cloud.py +0 -0
  90. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/doctor_checks/common.py +0 -0
  91. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/doctor_checks/github.py +0 -0
  92. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/doctor_checks/github_actions.py +0 -0
  93. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/doctor_checks/github_actions_cost.py +0 -0
  94. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/doctor_checks/github_actions_cost_summary.py +0 -0
  95. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/doctor_checks/github_actions_failure_annotations.py +0 -0
  96. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/doctor_checks/github_actions_failure_models.py +0 -0
  97. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/doctor_checks/github_actions_failure_scan.py +0 -0
  98. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/doctor_checks/github_actions_failure_selection.py +0 -0
  99. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/doctor_checks/github_actions_failures.py +0 -0
  100. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/doctor_checks/github_actions_permissions.py +0 -0
  101. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/doctor_checks/github_api.py +0 -0
  102. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/doctor_checks/github_branch.py +0 -0
  103. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/doctor_checks/github_config.py +0 -0
  104. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/doctor_checks/github_provider.py +0 -0
  105. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/doctor_checks/github_repo.py +0 -0
  106. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/doctor_checks/groups.py +0 -0
  107. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/doctor_checks/models.py +0 -0
  108. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/doctor_checks/output.py +0 -0
  109. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/doctor_checks/presets.py +0 -0
  110. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/doctor_checks/privacy.py +0 -0
  111. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/doctor_checks/provider_api_model.py +0 -0
  112. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/doctor_checks/provider_api_model_openai.py +0 -0
  113. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/doctor_checks/provider_api_model_profiles.py +0 -0
  114. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/doctor_checks/provider_env.py +0 -0
  115. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/doctor_checks/provider_env_required.py +0 -0
  116. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/doctor_checks/provider_env_tokens.py +0 -0
  117. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/doctor_checks/provider_local_cli.py +0 -0
  118. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/doctor_checks/provider_local_cli_commands.py +0 -0
  119. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/doctor_checks/provider_local_cli_probe_config.py +0 -0
  120. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/doctor_checks/provider_probe.py +0 -0
  121. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/doctor_checks/provider_probe_auth.py +0 -0
  122. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/doctor_checks/provider_probe_evaluation.py +0 -0
  123. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/doctor_checks/provider_probe_json.py +0 -0
  124. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/doctor_checks/provider_probe_remediation.py +0 -0
  125. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/doctor_checks/provider_review_hygiene.py +0 -0
  126. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/doctor_checks/providers.py +0 -0
  127. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/doctor_checks/registry.py +0 -0
  128. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/doctor_checks/runner.py +0 -0
  129. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/doctor_checks/runtime.py +0 -0
  130. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/doctor_checks/runtime_github_auth.py +0 -0
  131. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/gemini_cli_audit_pr.py +0 -0
  132. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/hermes_cli_audit_pr.py +0 -0
  133. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/lane_configs/__init__.py +0 -0
  134. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/lane_configs/aider.py +0 -0
  135. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/lane_configs/antigravity_cli.py +0 -0
  136. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/lane_configs/claude.py +0 -0
  137. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/lane_configs/codex.py +0 -0
  138. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/lane_configs/devin.py +0 -0
  139. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/lane_configs/gemini_cli.py +0 -0
  140. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/lane_configs/grok_build.py +0 -0
  141. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/lane_configs/hermes_cli.py +0 -0
  142. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/lane_configs/local_llm.py +0 -0
  143. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/local_llm_audit_pr.py +0 -0
  144. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/local_llm_bakeoff.py +0 -0
  145. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/local_llm_calibration.py +0 -0
  146. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/local_llm_profiles.py +0 -0
  147. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/migration.py +0 -0
  148. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/migration_install.py +0 -0
  149. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/migration_mirror.py +0 -0
  150. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/migration_readiness.py +0 -0
  151. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/migration_rehearsal.py +0 -0
  152. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/next_steps.py +0 -0
  153. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/package.py +0 -0
  154. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/package_content.py +0 -0
  155. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/package_manifest.py +0 -0
  156. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/package_paths.py +0 -0
  157. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/package_rendering.py +0 -0
  158. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/package_static.py +0 -0
  159. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/prompts.py +0 -0
  160. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/provider_registry.py +0 -0
  161. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/provider_runners/__init__.py +0 -0
  162. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/provider_runners/comments.py +0 -0
  163. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/provider_runners/git.py +0 -0
  164. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/provider_runners/github_auth.py +0 -0
  165. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/provider_runners/github_pr.py +0 -0
  166. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/provider_runners/pr_worktree.py +0 -0
  167. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/provider_runners/process.py +0 -0
  168. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/provider_runners/repo_paths.py +0 -0
  169. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/provider_runners/text_schema.py +0 -0
  170. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/provider_runners/verdict_artifacts.py +0 -0
  171. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/provider_runners/workspace.py +0 -0
  172. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/providers/__init__.py +0 -0
  173. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/providers/local_cli.py +0 -0
  174. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/providers/provenance.py +0 -0
  175. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/release_readiness.py +0 -0
  176. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/reviewer_metrics.py +0 -0
  177. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/saas_reviewer_labeler.py +0 -0
  178. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/secrets.py +0 -0
  179. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/templates/builder-experiment.example.json +0 -0
  180. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/templates/calibration-corpus.example.json +0 -0
  181. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/templates/calibration-corpus.json +0 -0
  182. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/templates/context-packs.example.json +0 -0
  183. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/templates/lane_prompts/base-audit.md +0 -0
  184. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/templates/lane_prompts/calibration-policy.md +0 -0
  185. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/templates/lane_prompts/context-driven-quality.md +0 -0
  186. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/templates/lane_prompts/docs-design.md +0 -0
  187. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/templates/lane_prompts/generic-programming.md +0 -0
  188. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/templates/lane_prompts/operability.md +0 -0
  189. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/templates/lane_prompts/package-runtime.md +0 -0
  190. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/templates/lane_prompts/security-threat-model.md +0 -0
  191. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/templates/product-support/code_mower +0 -0
  192. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/templates/product-support/code_mower_standalone_pin.env +0 -0
  193. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/templates/product-support/code_mower_standalone_shadow.sh +0 -0
  194. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/templates/product-support/run_claude_audit_pr.sh +0 -0
  195. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/templates/product-support/run_codex_audit_pr.sh +0 -0
  196. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/templates/product-support/safe_gh_comment.py +0 -0
  197. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/templates/providers.yml +0 -0
  198. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/templates/reviewer-spend.example.json +0 -0
  199. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/templates/reviewer-value-report.example.md +0 -0
  200. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/templates/workflows/audit-label-cleanup.yml.j2 +0 -0
  201. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/templates/workflows/hosted-bridge.yml.j2 +0 -0
  202. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/templates/workflows/local-cli-audit.yml.j2 +0 -0
  203. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/templates/workflows/private-standalone-shadow.yml.j2 +0 -0
  204. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/templates/workflows/review-clear-stale.yml.j2 +0 -0
  205. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/trailer_comment_labeler.py +0 -0
  206. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/versioning.py +0 -0
  207. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower/work_orders.py +0 -0
  208. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower.egg-info/SOURCES.txt +0 -0
  209. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower.egg-info/dependency_links.txt +0 -0
  210. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower.egg-info/entry_points.txt +0 -0
  211. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower.egg-info/requires.txt +0 -0
  212. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/src/code_mower.egg-info/top_level.txt +0 -0
  213. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/templates/builder-experiment.example.json +0 -0
  214. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/templates/calibration-corpus.example.json +0 -0
  215. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/templates/calibration-corpus.json +0 -0
  216. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/templates/code-mower.yml.j2 +0 -0
  217. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/templates/context-packs.example.json +0 -0
  218. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/templates/cursor/BUGBOT.md +0 -0
  219. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/templates/providers/acp_bridge.yml +0 -0
  220. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/templates/providers/aider.yml +0 -0
  221. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/templates/providers/antigravity_cli.yml +0 -0
  222. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/templates/providers/claude_audit.yml +0 -0
  223. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/templates/providers/claude_review.yml +0 -0
  224. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/templates/providers/coderabbit_cli.yml +0 -0
  225. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/templates/providers/codex.yml +0 -0
  226. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/templates/providers/cursor_bugbot.yml +0 -0
  227. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/templates/providers/devin.yml +0 -0
  228. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/templates/providers/gemini_cli.yml +0 -0
  229. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/templates/providers/gitar.yml +0 -0
  230. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/templates/providers/greptile.yml +0 -0
  231. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/templates/providers/hermes_cli.yml +0 -0
  232. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/templates/providers/local_llm.yml +0 -0
  233. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/templates/providers/qodo.yml +0 -0
  234. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/templates/providers.yml +0 -0
  235. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/templates/reviewer-spend.example.json +0 -0
  236. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/templates/reviewer-value-report.example.md +0 -0
  237. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/templates/workflows/audit-label-cleanup.yml.j2 +0 -0
  238. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/templates/workflows/blind-review-artifacts-dry-run.yml.j2 +0 -0
  239. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/templates/workflows/hosted-bridge.yml.j2 +0 -0
  240. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/templates/workflows/local-cli-audit.yml.j2 +0 -0
  241. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/templates/workflows/private-standalone-shadow.yml.j2 +0 -0
  242. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/templates/workflows/review-clear-stale.yml.j2 +0 -0
  243. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/tests/test_calibration_effect_report.py +0 -0
  244. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/tests/test_calibration_truth.py +0 -0
  245. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/tests/test_checks.py +0 -0
  246. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/tests/test_claude_cli_bounce.py +0 -0
  247. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/tests/test_clear_stale.py +0 -0
  248. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/tests/test_cloud_client.py +0 -0
  249. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/tests/test_cloud_git_metadata.py +0 -0
  250. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/tests/test_cloud_manifest.py +0 -0
  251. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/tests/test_cloud_reports.py +0 -0
  252. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/tests/test_coderabbit_cli_audit_pr.py +0 -0
  253. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/tests/test_codex_audit_env_preflight.py +0 -0
  254. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/tests/test_doctor_actions_cost_summary.py +0 -0
  255. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/tests/test_doctor_actions_failure_selection.py +0 -0
  256. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/tests/test_doctor_boundaries.py +0 -0
  257. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/tests/test_doctor_github_checks.py +0 -0
  258. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/tests/test_doctor_output.py +0 -0
  259. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/tests/test_doctor_privacy.py +0 -0
  260. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/tests/test_doctor_provider_env_required.py +0 -0
  261. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/tests/test_doctor_provider_env_tokens.py +0 -0
  262. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/tests/test_doctor_provider_probe.py +0 -0
  263. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/tests/test_doctor_provider_review_hygiene.py +0 -0
  264. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/tests/test_doctor_registry.py +0 -0
  265. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/tests/test_local_llm_github_helpers.py +0 -0
  266. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/tests/test_provider_runners_comments.py +0 -0
  267. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/tests/test_provider_runners_git.py +0 -0
  268. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/tests/test_provider_runners_github_pr.py +0 -0
  269. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/tests/test_provider_runners_pr_worktree.py +0 -0
  270. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/tests/test_provider_runners_process.py +0 -0
  271. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/tests/test_provider_runners_repo_paths.py +0 -0
  272. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/tests/test_provider_runners_text_schema.py +0 -0
  273. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/tests/test_provider_runners_workspace.py +0 -0
  274. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/tests/test_reviewer_metrics_core.py +0 -0
  275. {code_mower-0.5.0b38 → code_mower-0.5.0b40}/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.5.0b38
3
+ Version: 0.5.0b40
4
4
  Summary: Multi-reviewer AI code audit orchestration
5
5
  License-Expression: Apache-2.0
6
6
  Requires-Python: >=3.11
@@ -103,11 +103,11 @@ Code Mower currently targets Python 3.11+; Python 3.12 is recommended.
103
103
 
104
104
  ```bash
105
105
  python3.12 --version
106
- pipx install --python python3.12 code-mower==0.5.0b38
106
+ pipx install --python python3.12 code-mower==0.5.0b40
107
107
  code-mower --version
108
108
  ```
109
109
 
110
- `0.5.0b38` is a beta release. Until Code Mower publishes a stable `1.0`
110
+ `0.5.0b40` is a beta release. Until Code Mower publishes a stable `1.0`
111
111
  line, use the explicit beta version above or allow prereleases with:
112
112
 
113
113
  ```bash
@@ -150,7 +150,7 @@ First-time command map: [docs/launch-command-surface.md](docs/launch-command-sur
150
150
 
151
151
  The current PyPI beta has been rehearsed end-to-end from a clean install:
152
152
  [First-User Install Rehearsal](docs/first-user-install-rehearsal.md) records
153
- the latest 10/10 public-package readiness proof for `code-mower==0.5.0b38`.
153
+ the latest 10/10 public-package readiness proof for `code-mower==0.5.0b40`.
154
154
 
155
155
  ## Optional: Plan Before Coding
156
156
 
@@ -291,9 +291,9 @@ best?" to "which AI builder plus reviewer loop ships best on this product?" See
291
291
 
292
292
  ## Installation Status
293
293
 
294
- The current public beta is `v0.5.0-beta.38` from
294
+ The current public beta is `v0.5.0-beta.40` from
295
295
  [codemower-ai/code-mower](https://github.com/codemower-ai/code-mower), published
296
- as `code-mower==0.5.0b38` on [PyPI](https://pypi.org/project/code-mower/).
296
+ as `code-mower==0.5.0b40` on [PyPI](https://pypi.org/project/code-mower/).
297
297
  GitHub releases remain the auditable source for tags, build artifacts, and
298
298
  release notes.
299
299
 
@@ -88,11 +88,11 @@ Code Mower currently targets Python 3.11+; Python 3.12 is recommended.
88
88
 
89
89
  ```bash
90
90
  python3.12 --version
91
- pipx install --python python3.12 code-mower==0.5.0b38
91
+ pipx install --python python3.12 code-mower==0.5.0b40
92
92
  code-mower --version
93
93
  ```
94
94
 
95
- `0.5.0b38` is a beta release. Until Code Mower publishes a stable `1.0`
95
+ `0.5.0b40` is a beta release. Until Code Mower publishes a stable `1.0`
96
96
  line, use the explicit beta version above or allow prereleases with:
97
97
 
98
98
  ```bash
@@ -135,7 +135,7 @@ First-time command map: [docs/launch-command-surface.md](docs/launch-command-sur
135
135
 
136
136
  The current PyPI beta has been rehearsed end-to-end from a clean install:
137
137
  [First-User Install Rehearsal](docs/first-user-install-rehearsal.md) records
138
- the latest 10/10 public-package readiness proof for `code-mower==0.5.0b38`.
138
+ the latest 10/10 public-package readiness proof for `code-mower==0.5.0b40`.
139
139
 
140
140
  ## Optional: Plan Before Coding
141
141
 
@@ -276,9 +276,9 @@ best?" to "which AI builder plus reviewer loop ships best on this product?" See
276
276
 
277
277
  ## Installation Status
278
278
 
279
- The current public beta is `v0.5.0-beta.38` from
279
+ The current public beta is `v0.5.0-beta.40` from
280
280
  [codemower-ai/code-mower](https://github.com/codemower-ai/code-mower), published
281
- as `code-mower==0.5.0b38` on [PyPI](https://pypi.org/project/code-mower/).
281
+ as `code-mower==0.5.0b40` on [PyPI](https://pypi.org/project/code-mower/).
282
282
  GitHub releases remain the auditable source for tags, build artifacts, and
283
283
  release notes.
284
284
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "code-mower"
7
- version = "0.5.0b38"
7
+ version = "0.5.0b40"
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.0b38"
3
+ __version__ = "0.5.0b40"
@@ -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.0b38`, or run source checkouts with "
17
+ "`pipx install code-mower==0.5.0b40`, or run source checkouts with "
18
18
  "`PYTHONPATH=src python -m code_mower.cli`."
19
19
  )
20
20
 
@@ -39,6 +39,7 @@ DEFAULT_GROK_COMMAND = "grok"
39
39
  DEFAULT_GROK_MODE = "grok-build-audit"
40
40
  DEFAULT_GROK_OUTPUT_STEM = "grok-build"
41
41
  DEFAULT_GROK_DISPLAY_NAME = "Grok Build"
42
+ DEFAULT_GROK_MAX_TURNS = 4
42
43
  DEFAULT_GROK_MODEL_ENV = "GROK_MODEL"
43
44
  CODE_MOWER_GROK_MODEL_ENV = "CODE_MOWER_GROK_MODEL"
44
45
  GROK_AMBIENT_HOME_ENV = "GROK_BUILD_USE_AMBIENT_HOME"
@@ -147,9 +148,34 @@ def _response_text_from_grok_payload(
147
148
  parsed_response = raw_payload
148
149
  if parsed_response is None:
149
150
  parsed_response = gemini_cli_audit_pr.parse_response_json(response_text)
151
+ if parsed_response is None:
152
+ parsed_response = _last_verdict_json_object(response_text)
150
153
  return response_text, parsed_response
151
154
 
152
155
 
156
+ def _last_verdict_json_object(text: str) -> Mapping[str, Any] | None:
157
+ """Recover the final verdict object from chatty multi-turn Grok output."""
158
+
159
+ decoder = json.JSONDecoder()
160
+ candidates: list[Mapping[str, Any]] = []
161
+ index = 0
162
+ while index < len(text):
163
+ if text[index] != "{":
164
+ index += 1
165
+ continue
166
+ try:
167
+ payload, end = decoder.raw_decode(text[index:])
168
+ except json.JSONDecodeError:
169
+ index += 1
170
+ continue
171
+ if isinstance(payload, Mapping) and "verdict" in payload and (
172
+ "findings" in payload or "summary" in payload
173
+ ):
174
+ candidates.append(payload)
175
+ index += max(end, 1)
176
+ return candidates[-1] if candidates else None
177
+
178
+
153
179
  def run_grok_build_audit(
154
180
  *,
155
181
  repo: str,
@@ -161,6 +187,7 @@ def run_grok_build_audit(
161
187
  prompt_dir: Path | None = None,
162
188
  max_diff_bytes: int = gemini_cli_audit_pr.DEFAULT_MAX_DIFF_BYTES,
163
189
  timeout_seconds: int = gemini_cli_audit_pr.DEFAULT_TIMEOUT_SECONDS,
190
+ grok_max_turns: int = DEFAULT_GROK_MAX_TURNS,
164
191
  output_dir: Path | None = None,
165
192
  grok_api_key: str | None = None,
166
193
  repo_path: Path | None = None,
@@ -234,6 +261,7 @@ def run_grok_build_audit(
234
261
  diagnostics["base_ref"] = base_ref if repo_path is not None else None
235
262
  diagnostics["cli_transport"] = "prompt_file"
236
263
  diagnostics["preserve_ambient_home"] = allow_ambient_home
264
+ diagnostics["grok_max_turns"] = max(1, grok_max_turns)
237
265
 
238
266
  started = time.monotonic()
239
267
  grok_model = resolve_grok_model()
@@ -263,7 +291,7 @@ def run_grok_build_audit(
263
291
  "--disable-web-search",
264
292
  "--no-memory",
265
293
  "--max-turns",
266
- "1",
294
+ str(max(1, grok_max_turns)),
267
295
  ]
268
296
  if grok_model:
269
297
  grok_args.extend(["--model", grok_model])
@@ -291,6 +319,11 @@ def run_grok_build_audit(
291
319
  completed.stdout,
292
320
  )
293
321
  verdict = gemini_cli_audit_pr._validate_verdict(parsed_response)
322
+ if verdict.get("parse_failed"):
323
+ verdict = {
324
+ **verdict,
325
+ "summary": "Grok Build response did not contain parseable verdict JSON.",
326
+ }
294
327
  if repo_path is None:
295
328
  head_after_meta = gemini_cli_audit_pr.fetch_pull_request(
296
329
  repo,
@@ -381,6 +414,15 @@ def main(argv: list[str] | None = None) -> int:
381
414
  default=gemini_cli_audit_pr.DEFAULT_MAX_DIFF_BYTES,
382
415
  )
383
416
  parser.add_argument("--timeout", type=int, default=gemini_cli_audit_pr.DEFAULT_TIMEOUT_SECONDS)
417
+ parser.add_argument(
418
+ "--grok-max-turns",
419
+ type=int,
420
+ default=DEFAULT_GROK_MAX_TURNS,
421
+ help=(
422
+ "Maximum Grok Build agent turns for a PR audit. The smoke probe can "
423
+ "use one turn, but real audits need enough room to return verdict JSON."
424
+ ),
425
+ )
384
426
  parser.add_argument("--output-dir", type=Path, default=None)
385
427
  parser.add_argument("--json", action="store_true")
386
428
  parser.add_argument(
@@ -416,6 +458,7 @@ def main(argv: list[str] | None = None) -> int:
416
458
  prompt_dir=args.prompt_dir,
417
459
  max_diff_bytes=args.max_diff_bytes,
418
460
  timeout_seconds=args.timeout,
461
+ grok_max_turns=args.grok_max_turns,
419
462
  output_dir=args.output_dir,
420
463
  grok_api_key=grok_api_key,
421
464
  repo_path=args.repo_path,
@@ -192,7 +192,24 @@ def _audit_token_env(lane: Mapping[str, Any]) -> str:
192
192
  return "CODE_MOWER_AUDIT_LABEL_TOKEN"
193
193
 
194
194
 
195
+ def _token_env_names(lane: Mapping[str, Any]) -> tuple[str, ...]:
196
+ token_env = lane.get("token_env", [])
197
+ if isinstance(token_env, str):
198
+ return (token_env,)
199
+ if isinstance(token_env, list):
200
+ return tuple(str(name) for name in token_env)
201
+ return ()
202
+
203
+
204
+ def _bot_author_csv(authors: str, lane: Mapping[str, Any]) -> str:
205
+ values = [author.strip() for author in authors.split(",") if author.strip()]
206
+ return ",".join(dict.fromkeys(values))
207
+
208
+
195
209
  def _authors_env_for_trailer_lane(trailer_lane: str) -> str:
210
+ lane_config = _load_trailer_lane_config(trailer_lane)
211
+ if lane_config is not None:
212
+ return lane_config.authors_env_var
196
213
  normalized = trailer_lane.replace("-", "_").upper()
197
214
  explicit = {
198
215
  "CLAUDE": "CLAUDE_AUDIT_BOT_AUTHORS",
@@ -202,6 +219,36 @@ def _authors_env_for_trailer_lane(trailer_lane: str) -> str:
202
219
  return explicit.get(normalized, f"{normalized}_BOT_AUTHORS")
203
220
 
204
221
 
222
+ def _load_trailer_lane_config(trailer_lane: str) -> Any | None:
223
+ try:
224
+ if __package__ in {None, "", "tools"}:
225
+ from tools.lane_configs import load_lane_config
226
+ else: # pragma: no cover - package import path covered by CLI tests.
227
+ from .lane_configs import load_lane_config
228
+
229
+ return load_lane_config(trailer_lane)
230
+ except (ImportError, ModuleNotFoundError, ValueError):
231
+ return None
232
+
233
+
234
+ def _default_trailer_bot_authors(trailer_lane: str) -> str:
235
+ lane_config = _load_trailer_lane_config(trailer_lane)
236
+ if lane_config is not None:
237
+ return ",".join(lane_config.default_authors)
238
+ stem = trailer_lane.replace("_", "-")
239
+ return f"{stem}-audit-bot,{stem}-audit-bot[bot]"
240
+
241
+
242
+ def _configured_bot_authors(lane: Mapping[str, Any]) -> str:
243
+ provider_config = lane.get("provider_config")
244
+ if not isinstance(provider_config, Mapping):
245
+ return ""
246
+ authors = provider_config.get("bot_authors", [])
247
+ if not isinstance(authors, list):
248
+ return ""
249
+ return ",".join(str(author).strip() for author in authors if str(author).strip())
250
+
251
+
205
252
  def _trailer_prefix_for_lane(trailer_lane: str) -> str:
206
253
  return f"{trailer_lane.replace('-', '_').upper()}_AUDIT_STATE"
207
254
 
@@ -240,6 +287,7 @@ def _workflow_entry_for_target(
240
287
  "package_copy_from": "templates/workflows/saas-reviewer-labeler.yml.j2",
241
288
  "adapter": adapter,
242
289
  "authors_env": f"{adapter.replace('-', '_').upper()}_BOT_AUTHORS",
290
+ "bot_authors": _bot_author_csv(_configured_bot_authors(lane), lane),
243
291
  }
244
292
  return {
245
293
  **common,
@@ -249,6 +297,7 @@ def _workflow_entry_for_target(
249
297
  "trailer_lane": trailer_lane,
250
298
  "trailer_prefix": _trailer_prefix_for_lane(trailer_lane),
251
299
  "authors_env": _authors_env_for_trailer_lane(trailer_lane),
300
+ "bot_authors": _bot_author_csv(_default_trailer_bot_authors(trailer_lane), lane),
252
301
  }
253
302
 
254
303
 
@@ -335,6 +384,11 @@ def _lane_warnings(
335
384
  warnings.append(f"{lane_id}: opt-in lane selected by profile")
336
385
  if lane.get("trigger_policy") == "manual":
337
386
  warnings.append(f"{lane_id}: manual trigger policy; installer must not auto-dispatch")
387
+ if "GITHUB_TOKEN" in _token_env_names(lane):
388
+ warnings.append(
389
+ f"{lane_id}: GITHUB_TOKEN posting comments as github-actions[bot] requires "
390
+ "an explicit *_BOT_AUTHORS repository variable"
391
+ )
338
392
  if package_mode:
339
393
  driver = lane.get("driver")
340
394
  if driver in {"local_cli", "hosted_bridge", "api_model"}:
@@ -566,6 +620,7 @@ def _render_workflow_template(text: str, entry: Mapping[str, Any]) -> str:
566
620
  "__ADAPTER__": str(entry.get("adapter") or ""),
567
621
  "__AUTHORS_ENV__": str(entry.get("authors_env") or ""),
568
622
  "__BLOCKED_LABEL__": str(entry.get("blocked_label") or ""),
623
+ "__BOT_AUTHORS__": str(entry.get("bot_authors") or ""),
569
624
  "__DISPLAY_NAME__": str(entry.get("display_name") or ""),
570
625
  "__DONE_LABEL__": str(entry.get("done_label") or ""),
571
626
  "__LABEL_TOKEN_ENV__": str(entry.get("label_token_env") or ""),
@@ -112,6 +112,8 @@ lanes:
112
112
  - GREPTILE_AUDIT_LABEL_TOKEN
113
113
  - GITHUB_TOKEN
114
114
  provider_config:
115
+ # Required by generated issue-comment labeler prefilters. Keep SaaS
116
+ # reviewer bot authors explicit so unrelated bots cannot spoof labels.
115
117
  bot_authors:
116
118
  - greptile-apps[bot]
117
119
  - greptile-apps
@@ -10,12 +10,6 @@ on:
10
10
  types: [submitted, edited]
11
11
  check_run:
12
12
  types: [completed]
13
- workflow_dispatch:
14
- inputs:
15
- adapter:
16
- description: "SaaS reviewer adapter to classify"
17
- required: false
18
- default: "__ADAPTER__"
19
13
 
20
14
  permissions:
21
15
  contents: read
@@ -29,10 +23,10 @@ env:
29
23
  jobs:
30
24
  label:
31
25
  if: >-
32
- github.event_name == 'workflow_dispatch' ||
33
26
  (
34
27
  github.event_name == 'issue_comment' &&
35
- github.event.issue.pull_request
28
+ github.event.issue.pull_request &&
29
+ contains(format(',__BOT_AUTHORS__,{0},', vars.__AUTHORS_ENV__), format(',{0},', github.event.comment.user.login))
36
30
  ) ||
37
31
  (
38
32
  github.event_name == 'issues' &&
@@ -54,5 +48,5 @@ jobs:
54
48
  GITHUB_TOKEN: {% raw %}${{ github.token }}{% endraw %}
55
49
  __LABEL_TOKEN_ENV__: {% raw %}${{ secrets.__LABEL_TOKEN_ENV__ }}{% endraw %}
56
50
  __AUTHORS_ENV__: {% raw %}${{ vars.__AUTHORS_ENV__ }}{% endraw %}
57
- REVIEWER_ADAPTER: {% raw %}${{ github.event.inputs.adapter || '__ADAPTER__' }}{% endraw %}
51
+ REVIEWER_ADAPTER: __ADAPTER__
58
52
  run: tools/code_mower saas-reviewer-labeler --adapter "${REVIEWER_ADAPTER}"
@@ -4,12 +4,6 @@ name: __WORKFLOW_NAME__
4
4
  on:
5
5
  issue_comment:
6
6
  types: [created]
7
- workflow_dispatch:
8
- inputs:
9
- lane:
10
- description: "Trailer-comment lane to classify"
11
- required: false
12
- default: "__TRAILER_LANE__"
13
7
 
14
8
  permissions:
15
9
  contents: read
@@ -22,10 +16,10 @@ env:
22
16
  jobs:
23
17
  label:
24
18
  if: >-
25
- github.event_name == 'workflow_dispatch' ||
26
19
  (
27
20
  github.event_name == 'issue_comment' &&
28
21
  github.event.issue.pull_request &&
22
+ contains(format(',__BOT_AUTHORS__,{0},', vars.__AUTHORS_ENV__), format(',{0},', github.event.comment.user.login)) &&
29
23
  (
30
24
  contains(github.event.comment.body, '__TRAILER_PREFIX__') ||
31
25
  contains(github.event.comment.body, '__DISPLAY_NAME__ Audit') ||
@@ -53,5 +47,5 @@ jobs:
53
47
  GITHUB_TOKEN: {% raw %}${{ github.token }}{% endraw %}
54
48
  __LABEL_TOKEN_ENV__: {% raw %}${{ secrets.__LABEL_TOKEN_ENV__ }}{% endraw %}
55
49
  __AUTHORS_ENV__: {% raw %}${{ vars.__AUTHORS_ENV__ }}{% endraw %}
56
- TRAILER_LANE: {% raw %}${{ github.event.inputs.lane || '__TRAILER_LANE__' }}{% endraw %}
50
+ TRAILER_LANE: __TRAILER_LANE__
57
51
  run: tools/code_mower trailer-comment-labeler --lane "${TRAILER_LANE}"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: code-mower
3
- Version: 0.5.0b38
3
+ Version: 0.5.0b40
4
4
  Summary: Multi-reviewer AI code audit orchestration
5
5
  License-Expression: Apache-2.0
6
6
  Requires-Python: >=3.11
@@ -103,11 +103,11 @@ Code Mower currently targets Python 3.11+; Python 3.12 is recommended.
103
103
 
104
104
  ```bash
105
105
  python3.12 --version
106
- pipx install --python python3.12 code-mower==0.5.0b38
106
+ pipx install --python python3.12 code-mower==0.5.0b40
107
107
  code-mower --version
108
108
  ```
109
109
 
110
- `0.5.0b38` is a beta release. Until Code Mower publishes a stable `1.0`
110
+ `0.5.0b40` is a beta release. Until Code Mower publishes a stable `1.0`
111
111
  line, use the explicit beta version above or allow prereleases with:
112
112
 
113
113
  ```bash
@@ -150,7 +150,7 @@ First-time command map: [docs/launch-command-surface.md](docs/launch-command-sur
150
150
 
151
151
  The current PyPI beta has been rehearsed end-to-end from a clean install:
152
152
  [First-User Install Rehearsal](docs/first-user-install-rehearsal.md) records
153
- the latest 10/10 public-package readiness proof for `code-mower==0.5.0b38`.
153
+ the latest 10/10 public-package readiness proof for `code-mower==0.5.0b40`.
154
154
 
155
155
  ## Optional: Plan Before Coding
156
156
 
@@ -291,9 +291,9 @@ best?" to "which AI builder plus reviewer loop ships best on this product?" See
291
291
 
292
292
  ## Installation Status
293
293
 
294
- The current public beta is `v0.5.0-beta.38` from
294
+ The current public beta is `v0.5.0-beta.40` from
295
295
  [codemower-ai/code-mower](https://github.com/codemower-ai/code-mower), published
296
- as `code-mower==0.5.0b38` on [PyPI](https://pypi.org/project/code-mower/).
296
+ as `code-mower==0.5.0b40` on [PyPI](https://pypi.org/project/code-mower/).
297
297
  GitHub releases remain the auditable source for tags, build artifacts, and
298
298
  release notes.
299
299
 
@@ -10,12 +10,6 @@ on:
10
10
  types: [submitted, edited]
11
11
  check_run:
12
12
  types: [completed]
13
- workflow_dispatch:
14
- inputs:
15
- adapter:
16
- description: "SaaS reviewer adapter to classify"
17
- required: false
18
- default: "__ADAPTER__"
19
13
 
20
14
  permissions:
21
15
  contents: read
@@ -29,10 +23,10 @@ env:
29
23
  jobs:
30
24
  label:
31
25
  if: >-
32
- github.event_name == 'workflow_dispatch' ||
33
26
  (
34
27
  github.event_name == 'issue_comment' &&
35
- github.event.issue.pull_request
28
+ github.event.issue.pull_request &&
29
+ contains(format(',__BOT_AUTHORS__,{0},', vars.__AUTHORS_ENV__), format(',{0},', github.event.comment.user.login))
36
30
  ) ||
37
31
  (
38
32
  github.event_name == 'issues' &&
@@ -54,5 +48,5 @@ jobs:
54
48
  GITHUB_TOKEN: {% raw %}${{ github.token }}{% endraw %}
55
49
  __LABEL_TOKEN_ENV__: {% raw %}${{ secrets.__LABEL_TOKEN_ENV__ }}{% endraw %}
56
50
  __AUTHORS_ENV__: {% raw %}${{ vars.__AUTHORS_ENV__ }}{% endraw %}
57
- REVIEWER_ADAPTER: {% raw %}${{ github.event.inputs.adapter || '__ADAPTER__' }}{% endraw %}
51
+ REVIEWER_ADAPTER: __ADAPTER__
58
52
  run: tools/code_mower saas-reviewer-labeler --adapter "${REVIEWER_ADAPTER}"
@@ -4,12 +4,6 @@ name: __WORKFLOW_NAME__
4
4
  on:
5
5
  issue_comment:
6
6
  types: [created]
7
- workflow_dispatch:
8
- inputs:
9
- lane:
10
- description: "Trailer-comment lane to classify"
11
- required: false
12
- default: "__TRAILER_LANE__"
13
7
 
14
8
  permissions:
15
9
  contents: read
@@ -22,10 +16,10 @@ env:
22
16
  jobs:
23
17
  label:
24
18
  if: >-
25
- github.event_name == 'workflow_dispatch' ||
26
19
  (
27
20
  github.event_name == 'issue_comment' &&
28
21
  github.event.issue.pull_request &&
22
+ contains(format(',__BOT_AUTHORS__,{0},', vars.__AUTHORS_ENV__), format(',{0},', github.event.comment.user.login)) &&
29
23
  (
30
24
  contains(github.event.comment.body, '__TRAILER_PREFIX__') ||
31
25
  contains(github.event.comment.body, '__DISPLAY_NAME__ Audit') ||
@@ -53,5 +47,5 @@ jobs:
53
47
  GITHUB_TOKEN: {% raw %}${{ github.token }}{% endraw %}
54
48
  __LABEL_TOKEN_ENV__: {% raw %}${{ secrets.__LABEL_TOKEN_ENV__ }}{% endraw %}
55
49
  __AUTHORS_ENV__: {% raw %}${{ vars.__AUTHORS_ENV__ }}{% endraw %}
56
- TRAILER_LANE: {% raw %}${{ github.event.inputs.lane || '__TRAILER_LANE__' }}{% endraw %}
50
+ TRAILER_LANE: __TRAILER_LANE__
57
51
  run: tools/code_mower trailer-comment-labeler --lane "${TRAILER_LANE}"
@@ -1,6 +1,8 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import json
3
4
  import os
5
+ import subprocess
4
6
  from pathlib import Path
5
7
 
6
8
  from code_mower.provider_registry import REFERENCE_PROVIDERS
@@ -403,6 +405,127 @@ def test_grok_build_runner_prefers_code_mower_model_env(monkeypatch) -> None:
403
405
  assert grok_build_audit_pr.resolve_grok_model() == "grok-4.6-build"
404
406
 
405
407
 
408
+ def test_grok_build_runner_uses_configurable_audit_turn_budget(
409
+ monkeypatch,
410
+ tmp_path: Path,
411
+ ) -> None:
412
+ calls: list[list[str]] = []
413
+
414
+ monkeypatch.setattr(
415
+ grok_build_audit_pr.gemini_cli_audit_pr,
416
+ "fetch_pull_request",
417
+ lambda repo, pr_number, *, token: {"head": {"sha": "abc123"}},
418
+ )
419
+ monkeypatch.setattr(
420
+ grok_build_audit_pr.gemini_cli_audit_pr,
421
+ "fetch_local_checkout_diff",
422
+ lambda repo_path, *, base_ref: ("abc123", "diff --git a/a b/a\n"),
423
+ )
424
+ monkeypatch.setattr(
425
+ grok_build_audit_pr.gemini_cli_audit_pr,
426
+ "_local_head_sha",
427
+ lambda repo_path: "abc123",
428
+ )
429
+ monkeypatch.setattr(
430
+ grok_build_audit_pr.gemini_cli_audit_pr,
431
+ "build_prompt",
432
+ lambda **kwargs: ("review prompt", {}),
433
+ )
434
+
435
+ def fake_run(args, **kwargs):
436
+ calls.append(list(args))
437
+ return subprocess.CompletedProcess(
438
+ args,
439
+ 0,
440
+ stdout=json.dumps(
441
+ {
442
+ "text": json.dumps(
443
+ {
444
+ "verdict": "pass",
445
+ "summary": "No findings.",
446
+ "findings": [],
447
+ }
448
+ )
449
+ }
450
+ ),
451
+ stderr="",
452
+ )
453
+
454
+ monkeypatch.setattr(grok_build_audit_pr.subprocess, "run", fake_run)
455
+
456
+ default_payload = grok_build_audit_pr.run_grok_build_audit(
457
+ repo="owner/repo",
458
+ pr_number=7,
459
+ github_token="token",
460
+ command="grok",
461
+ repo_path=tmp_path,
462
+ allow_ambient_home=True,
463
+ )
464
+ custom_payload = grok_build_audit_pr.run_grok_build_audit(
465
+ repo="owner/repo",
466
+ pr_number=7,
467
+ github_token="token",
468
+ command="grok",
469
+ repo_path=tmp_path,
470
+ allow_ambient_home=True,
471
+ grok_max_turns=8,
472
+ )
473
+
474
+ assert default_payload["diagnostics"]["grok_max_turns"] == 4
475
+ assert custom_payload["diagnostics"]["grok_max_turns"] == 8
476
+ assert calls[0][calls[0].index("--max-turns") + 1] == "4"
477
+ assert calls[1][calls[1].index("--max-turns") + 1] == "8"
478
+
479
+
480
+ def test_grok_build_parser_prefers_last_verdict_json() -> None:
481
+ response_text = """
482
+ I found a possible issue first.
483
+ {
484
+ "verdict": "blocked",
485
+ "summary": "Intermediate thought.",
486
+ "findings": [{"severity": "P1", "title": "old", "file": "a", "line": 1, "detail": "old"}]
487
+ }
488
+
489
+ After reading the rest of the diff:
490
+ {
491
+ "verdict": "pass",
492
+ "summary": "Final answer.",
493
+ "findings": []
494
+ }
495
+ """
496
+
497
+ _, parsed = grok_build_audit_pr._response_text_from_grok_payload(
498
+ {"text": response_text},
499
+ "",
500
+ )
501
+
502
+ assert parsed is not None
503
+ assert parsed["verdict"] == "pass"
504
+ assert parsed["findings"] == []
505
+
506
+
507
+ def test_grok_build_parser_ignores_nested_verdict_json() -> None:
508
+ response_text = """
509
+ {
510
+ "verdict": "pass",
511
+ "summary": {
512
+ "verdict": "blocked",
513
+ "summary": "Nested diagnostic text should not win."
514
+ },
515
+ "findings": []
516
+ }
517
+ """
518
+
519
+ _, parsed = grok_build_audit_pr._response_text_from_grok_payload(
520
+ {"text": response_text},
521
+ "",
522
+ )
523
+
524
+ assert parsed is not None
525
+ assert parsed["verdict"] == "pass"
526
+ assert parsed["findings"] == []
527
+
528
+
406
529
  def test_provider_lane_tool_provenance_marks_hosted_model_as_vendor_hidden() -> None:
407
530
  lane = {
408
531
  "driver": "saas_event",