code-mower 0.5.0b5__py3-none-any.whl

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 (185) hide show
  1. code_mower/__init__.py +3 -0
  2. code_mower/adapters/__init__.py +39 -0
  3. code_mower/adapters/_base.py +148 -0
  4. code_mower/adapters/cursor_bugbot.py +97 -0
  5. code_mower/adapters/gitar.py +111 -0
  6. code_mower/adapters/greptile.py +191 -0
  7. code_mower/adapters/qodo.py +140 -0
  8. code_mower/antigravity_cli_audit_pr.py +241 -0
  9. code_mower/audit_handoff_log.py +345 -0
  10. code_mower/audit_labeler_lib.py +311 -0
  11. code_mower/audit_progress.py +203 -0
  12. code_mower/blind_review_artifacts.py +562 -0
  13. code_mower/blind_review_coordinator.py +276 -0
  14. code_mower/bootstrap.py +524 -0
  15. code_mower/builder_experiment.py +539 -0
  16. code_mower/calibration/__init__.py +181 -0
  17. code_mower/calibration/arms.py +267 -0
  18. code_mower/calibration/auto_discovery.py +348 -0
  19. code_mower/calibration/commands.py +192 -0
  20. code_mower/calibration/context_inputs.py +199 -0
  21. code_mower/calibration/corpus.py +91 -0
  22. code_mower/calibration/evidence.py +20 -0
  23. code_mower/calibration/evidence_report.py +360 -0
  24. code_mower/calibration/identity.py +27 -0
  25. code_mower/calibration/metrics.py +18 -0
  26. code_mower/calibration/overlap.py +103 -0
  27. code_mower/calibration/planning.py +309 -0
  28. code_mower/calibration/policy.py +207 -0
  29. code_mower/calibration/results.py +315 -0
  30. code_mower/calibration/run_results.py +147 -0
  31. code_mower/calibration/run_status.py +64 -0
  32. code_mower/calibration/runner.py +360 -0
  33. code_mower/calibration/truth.py +188 -0
  34. code_mower/calibration/value_report.py +142 -0
  35. code_mower/checks.py +402 -0
  36. code_mower/claude_audit_pr.py +1126 -0
  37. code_mower/claude_cli_bounce.py +303 -0
  38. code_mower/claude_cli_environment.py +73 -0
  39. code_mower/clear_stale.py +374 -0
  40. code_mower/cli.py +537 -0
  41. code_mower/cloud.py +674 -0
  42. code_mower/cloud_client/__init__.py +173 -0
  43. code_mower/cloud_client/bundle.py +155 -0
  44. code_mower/cloud_client/doctor.py +206 -0
  45. code_mower/cloud_client/dogfood.py +78 -0
  46. code_mower/cloud_client/endpoints.py +114 -0
  47. code_mower/cloud_client/errors.py +7 -0
  48. code_mower/cloud_client/events.py +278 -0
  49. code_mower/cloud_client/export.py +272 -0
  50. code_mower/cloud_client/git_metadata.py +46 -0
  51. code_mower/cloud_client/manifest.py +39 -0
  52. code_mower/cloud_client/operations.py +448 -0
  53. code_mower/cloud_client/reports.py +45 -0
  54. code_mower/cloud_client/setup.py +205 -0
  55. code_mower/cloud_client/upload.py +97 -0
  56. code_mower/code_mower_calibration.py +598 -0
  57. code_mower/code_mower_context_packs.py +591 -0
  58. code_mower/code_mower_merge.py +227 -0
  59. code_mower/code_mower_telemetry.py +561 -0
  60. code_mower/coderabbit_cli_audit_pr.py +526 -0
  61. code_mower/codex_audit_env_preflight.py +220 -0
  62. code_mower/codex_audit_pr.py +1738 -0
  63. code_mower/codex_audit_schema_smoke.py +160 -0
  64. code_mower/codex_audit_verdict.schema.json +44 -0
  65. code_mower/config.py +655 -0
  66. code_mower/doctor.py +161 -0
  67. code_mower/doctor_checks/__init__.py +104 -0
  68. code_mower/doctor_checks/cloud.py +129 -0
  69. code_mower/doctor_checks/common.py +215 -0
  70. code_mower/doctor_checks/github.py +128 -0
  71. code_mower/doctor_checks/github_actions.py +11 -0
  72. code_mower/doctor_checks/github_actions_cost.py +99 -0
  73. code_mower/doctor_checks/github_actions_cost_summary.py +111 -0
  74. code_mower/doctor_checks/github_actions_failure_annotations.py +27 -0
  75. code_mower/doctor_checks/github_actions_failure_models.py +47 -0
  76. code_mower/doctor_checks/github_actions_failure_scan.py +200 -0
  77. code_mower/doctor_checks/github_actions_failure_selection.py +63 -0
  78. code_mower/doctor_checks/github_actions_failures.py +103 -0
  79. code_mower/doctor_checks/github_actions_permissions.py +55 -0
  80. code_mower/doctor_checks/github_api.py +79 -0
  81. code_mower/doctor_checks/github_branch.py +56 -0
  82. code_mower/doctor_checks/github_config.py +25 -0
  83. code_mower/doctor_checks/github_provider.py +61 -0
  84. code_mower/doctor_checks/github_repo.py +120 -0
  85. code_mower/doctor_checks/groups.py +36 -0
  86. code_mower/doctor_checks/models.py +96 -0
  87. code_mower/doctor_checks/output.py +86 -0
  88. code_mower/doctor_checks/presets.py +64 -0
  89. code_mower/doctor_checks/privacy.py +20 -0
  90. code_mower/doctor_checks/provider_api_model.py +138 -0
  91. code_mower/doctor_checks/provider_api_model_openai.py +29 -0
  92. code_mower/doctor_checks/provider_api_model_profiles.py +137 -0
  93. code_mower/doctor_checks/provider_env.py +113 -0
  94. code_mower/doctor_checks/provider_env_required.py +56 -0
  95. code_mower/doctor_checks/provider_env_tokens.py +100 -0
  96. code_mower/doctor_checks/provider_local_cli.py +162 -0
  97. code_mower/doctor_checks/provider_local_cli_commands.py +47 -0
  98. code_mower/doctor_checks/provider_local_cli_probe_config.py +70 -0
  99. code_mower/doctor_checks/provider_probe.py +20 -0
  100. code_mower/doctor_checks/provider_probe_auth.py +52 -0
  101. code_mower/doctor_checks/provider_probe_evaluation.py +109 -0
  102. code_mower/doctor_checks/provider_probe_json.py +45 -0
  103. code_mower/doctor_checks/provider_probe_remediation.py +39 -0
  104. code_mower/doctor_checks/providers.py +159 -0
  105. code_mower/doctor_checks/registry.py +69 -0
  106. code_mower/doctor_checks/runner.py +188 -0
  107. code_mower/doctor_checks/runtime.py +89 -0
  108. code_mower/doctor_checks/runtime_github_auth.py +148 -0
  109. code_mower/gemini_cli_audit_pr.py +897 -0
  110. code_mower/hermes_cli_audit_pr.py +436 -0
  111. code_mower/init.py +888 -0
  112. code_mower/lane_configs/__init__.py +37 -0
  113. code_mower/lane_configs/aider.py +32 -0
  114. code_mower/lane_configs/antigravity_cli.py +35 -0
  115. code_mower/lane_configs/claude.py +35 -0
  116. code_mower/lane_configs/codex.py +32 -0
  117. code_mower/lane_configs/devin.py +33 -0
  118. code_mower/lane_configs/gemini_cli.py +35 -0
  119. code_mower/lane_configs/hermes_cli.py +35 -0
  120. code_mower/lane_configs/local_llm.py +31 -0
  121. code_mower/local_llm_audit_pr.py +1364 -0
  122. code_mower/local_llm_bakeoff.py +458 -0
  123. code_mower/local_llm_calibration.py +441 -0
  124. code_mower/local_llm_profiles.py +66 -0
  125. code_mower/migration.py +508 -0
  126. code_mower/migration_install.py +292 -0
  127. code_mower/migration_mirror.py +392 -0
  128. code_mower/migration_readiness.py +237 -0
  129. code_mower/migration_rehearsal.py +718 -0
  130. code_mower/next_steps.py +441 -0
  131. code_mower/package.py +673 -0
  132. code_mower/package_content.py +444 -0
  133. code_mower/package_manifest.py +452 -0
  134. code_mower/package_paths.py +53 -0
  135. code_mower/package_rendering.py +90 -0
  136. code_mower/package_static.py +585 -0
  137. code_mower/prompts.py +267 -0
  138. code_mower/provider_registry.py +469 -0
  139. code_mower/provider_runners/__init__.py +60 -0
  140. code_mower/provider_runners/comments.py +31 -0
  141. code_mower/provider_runners/git.py +46 -0
  142. code_mower/provider_runners/github_auth.py +61 -0
  143. code_mower/provider_runners/github_pr.py +120 -0
  144. code_mower/provider_runners/process.py +58 -0
  145. code_mower/provider_runners/repo_paths.py +23 -0
  146. code_mower/provider_runners/text_schema.py +41 -0
  147. code_mower/provider_runners/verdict_artifacts.py +103 -0
  148. code_mower/provider_runners/workspace.py +57 -0
  149. code_mower/release_readiness.py +549 -0
  150. code_mower/reviewer_metrics.py +389 -0
  151. code_mower/saas_reviewer_labeler.py +809 -0
  152. code_mower/secrets.py +89 -0
  153. code_mower/templates/builder-experiment.example.json +55 -0
  154. code_mower/templates/calibration-corpus.example.json +129 -0
  155. code_mower/templates/calibration-corpus.json +129 -0
  156. code_mower/templates/code-mower.example.yml +423 -0
  157. code_mower/templates/context-packs.example.json +150 -0
  158. code_mower/templates/lane_prompts/base-audit.md +22 -0
  159. code_mower/templates/lane_prompts/calibration-policy.md +21 -0
  160. code_mower/templates/lane_prompts/context-driven-quality.md +21 -0
  161. code_mower/templates/lane_prompts/docs-design.md +12 -0
  162. code_mower/templates/lane_prompts/generic-programming.md +21 -0
  163. code_mower/templates/lane_prompts/operability.md +22 -0
  164. code_mower/templates/lane_prompts/package-runtime.md +12 -0
  165. code_mower/templates/lane_prompts/security-threat-model.md +22 -0
  166. code_mower/templates/product-support/code_mower +216 -0
  167. code_mower/templates/product-support/code_mower_standalone_pin.env +7 -0
  168. code_mower/templates/product-support/code_mower_standalone_shadow.sh +151 -0
  169. code_mower/templates/product-support/run_claude_audit_pr.sh +32 -0
  170. code_mower/templates/product-support/run_codex_audit_pr.sh +32 -0
  171. code_mower/templates/product-support/safe_gh_comment.py +96 -0
  172. code_mower/templates/providers.yml +454 -0
  173. code_mower/templates/reviewer-spend.example.json +28 -0
  174. code_mower/templates/reviewer-value-report.example.md +20 -0
  175. code_mower/templates/workflows/private-standalone-shadow.yml.j2 +106 -0
  176. code_mower/templates/workflows/review-clear-stale.yml.j2 +83 -0
  177. code_mower/trailer_comment_labeler.py +207 -0
  178. code_mower/versioning.py +32 -0
  179. code_mower-0.5.0b5.dist-info/METADATA +302 -0
  180. code_mower-0.5.0b5.dist-info/RECORD +185 -0
  181. code_mower-0.5.0b5.dist-info/WHEEL +5 -0
  182. code_mower-0.5.0b5.dist-info/entry_points.txt +2 -0
  183. code_mower-0.5.0b5.dist-info/licenses/LICENSE +202 -0
  184. code_mower-0.5.0b5.dist-info/licenses/NOTICE +10 -0
  185. code_mower-0.5.0b5.dist-info/top_level.txt +1 -0
@@ -0,0 +1,227 @@
1
+ #!/usr/bin/env python3
2
+ """Build repo-scoped merge and post-merge verification command plans."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import argparse
7
+ import json
8
+ import re
9
+ import shlex
10
+ import sys
11
+ from dataclasses import dataclass
12
+ from typing import Any, Mapping, Sequence
13
+
14
+
15
+ PR_SPEC_RE = re.compile(r"^(?P<repo>[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+)#(?P<pr>[1-9][0-9]*)$")
16
+
17
+
18
+ @dataclass(frozen=True)
19
+ class PullRequestSpec:
20
+ repo: str
21
+ pr_number: int
22
+
23
+ @property
24
+ def api_repo(self) -> str:
25
+ return self.repo
26
+
27
+
28
+ def parse_pr_spec(value: str) -> PullRequestSpec:
29
+ match = PR_SPEC_RE.fullmatch(value.strip())
30
+ if not match:
31
+ raise ValueError(f"PR spec must be OWNER/REPO#NUMBER: {value!r}")
32
+ return PullRequestSpec(
33
+ repo=match.group("repo"),
34
+ pr_number=int(match.group("pr")),
35
+ )
36
+
37
+
38
+ def _shell_join(parts: Sequence[str]) -> str:
39
+ rendered = []
40
+ for part in parts:
41
+ if "$MERGE_SHA" in part:
42
+ pieces = part.split("$MERGE_SHA")
43
+ rendered.append("$MERGE_SHA".join(shlex.quote(piece) for piece in pieces))
44
+ else:
45
+ rendered.append(shlex.quote(part))
46
+ return " ".join(rendered)
47
+
48
+
49
+ def _merge_command(spec: PullRequestSpec, *, method: str, delete_branch: bool) -> list[str]:
50
+ command = [
51
+ "gh",
52
+ "pr",
53
+ "merge",
54
+ str(spec.pr_number),
55
+ "--repo",
56
+ spec.repo,
57
+ f"--{method}",
58
+ ]
59
+ if delete_branch:
60
+ command.append("--delete-branch")
61
+ return command
62
+
63
+
64
+ def _preflight_command(spec: PullRequestSpec) -> list[str]:
65
+ return [
66
+ "gh",
67
+ "pr",
68
+ "view",
69
+ str(spec.pr_number),
70
+ "--repo",
71
+ spec.repo,
72
+ "--json",
73
+ "state,isDraft,headRefName,headRefOid,labels,mergeStateStatus,reviewDecision,statusCheckRollup",
74
+ ]
75
+
76
+
77
+ def _post_merge_pr_command(spec: PullRequestSpec) -> list[str]:
78
+ return [
79
+ "gh",
80
+ "pr",
81
+ "view",
82
+ str(spec.pr_number),
83
+ "--repo",
84
+ spec.repo,
85
+ "--json",
86
+ "state,mergedAt,mergeCommit,headRefName,headRefOid",
87
+ ]
88
+
89
+
90
+ def _check_runs_command(spec: PullRequestSpec) -> list[str]:
91
+ return [
92
+ "gh",
93
+ "api",
94
+ f"repos/{spec.api_repo}/commits/$MERGE_SHA/check-runs",
95
+ "--paginate",
96
+ "--jq",
97
+ ".check_runs[] | {name,status,conclusion,html_url,completed_at}",
98
+ ]
99
+
100
+
101
+ def _status_command(spec: PullRequestSpec) -> list[str]:
102
+ return [
103
+ "gh",
104
+ "api",
105
+ f"repos/{spec.api_repo}/commits/$MERGE_SHA/status",
106
+ "--jq",
107
+ "{state, statuses:[.statuses[] | {context,state,description,target_url}]}",
108
+ ]
109
+
110
+
111
+ def build_merge_plan(
112
+ specs: Sequence[PullRequestSpec],
113
+ *,
114
+ method: str = "squash",
115
+ delete_branch: bool = True,
116
+ ) -> dict[str, Any]:
117
+ if method not in {"squash", "merge", "rebase"}:
118
+ raise ValueError("merge method must be squash, merge, or rebase")
119
+ if not specs:
120
+ raise ValueError("at least one PR spec is required")
121
+
122
+ prs = []
123
+ for spec in specs:
124
+ preflight = _preflight_command(spec)
125
+ merge = _merge_command(spec, method=method, delete_branch=delete_branch)
126
+ post_pr = _post_merge_pr_command(spec)
127
+ check_runs = _check_runs_command(spec)
128
+ statuses = _status_command(spec)
129
+ prs.append(
130
+ {
131
+ "repo": spec.repo,
132
+ "pr_number": spec.pr_number,
133
+ "preflight_command": preflight,
134
+ "merge_command": merge,
135
+ "post_merge_pr_command": post_pr,
136
+ "check_runs_command": check_runs,
137
+ "status_command": statuses,
138
+ "commands": {
139
+ "preflight": _shell_join(preflight),
140
+ "merge": _shell_join(merge),
141
+ "post_merge_pr": _shell_join(post_pr),
142
+ "check_runs": _shell_join(check_runs),
143
+ "statuses": _shell_join(statuses),
144
+ },
145
+ }
146
+ )
147
+
148
+ return {
149
+ "mode": "code-mower-merge-plan",
150
+ "method": method,
151
+ "delete_branch": delete_branch,
152
+ "pull_requests": prs,
153
+ "guardrails": [
154
+ "Run from any directory; every GitHub command is repo-scoped with --repo or repos/OWNER/REPO.",
155
+ "Verify the PR is open, non-draft, mergeStateStatus is CLEAN, and required audit labels are current-head before merging.",
156
+ "After merge, set MERGE_SHA from gh pr view .mergeCommit.oid before running check/status commands.",
157
+ "This planner does not grant merge authority; it only renders safer commands for already-approved merges.",
158
+ ],
159
+ }
160
+
161
+
162
+ def render_merge_plan_text(plan: Mapping[str, Any]) -> str:
163
+ lines = [
164
+ "Code Mower merge plan",
165
+ f"Method: {plan.get('method')}",
166
+ f"Delete branch: {plan.get('delete_branch')}",
167
+ "",
168
+ ]
169
+ for pr in plan.get("pull_requests", []) or []:
170
+ if not isinstance(pr, Mapping):
171
+ continue
172
+ commands = pr.get("commands", {})
173
+ if not isinstance(commands, Mapping):
174
+ commands = {}
175
+ lines.extend(
176
+ [
177
+ f"{pr.get('repo')}#{pr.get('pr_number')}",
178
+ f"- preflight: {commands.get('preflight')}",
179
+ f"- merge: {commands.get('merge')}",
180
+ f"- post-merge PR: {commands.get('post_merge_pr')}",
181
+ f"- check-runs: {commands.get('check_runs')}",
182
+ f"- statuses: {commands.get('statuses')}",
183
+ "",
184
+ ]
185
+ )
186
+ lines.append("Guardrails:")
187
+ for guardrail in plan.get("guardrails", []) or []:
188
+ lines.append(f"- {guardrail}")
189
+ return "\n".join(lines) + "\n"
190
+
191
+
192
+ def main(argv: list[str] | None = None) -> int:
193
+ parser = argparse.ArgumentParser(description=__doc__)
194
+ parser.add_argument("pull_requests", nargs="+", help="PR specs like OWNER/REPO#123")
195
+ parser.add_argument(
196
+ "--method",
197
+ choices=("squash", "merge", "rebase"),
198
+ default="squash",
199
+ )
200
+ parser.add_argument(
201
+ "--keep-branch",
202
+ action="store_true",
203
+ help="Render merge commands without --delete-branch.",
204
+ )
205
+ parser.add_argument("--json", action="store_true")
206
+ args = parser.parse_args(argv)
207
+
208
+ try:
209
+ specs = [parse_pr_spec(value) for value in args.pull_requests]
210
+ plan = build_merge_plan(
211
+ specs,
212
+ method=args.method,
213
+ delete_branch=not args.keep_branch,
214
+ )
215
+ except ValueError as exc:
216
+ print(f"error: {exc}", file=sys.stderr)
217
+ return 1
218
+
219
+ if args.json:
220
+ print(json.dumps(plan, indent=2, sort_keys=True))
221
+ else:
222
+ print(render_merge_plan_text(plan), end="")
223
+ return 0
224
+
225
+
226
+ if __name__ == "__main__":
227
+ raise SystemExit(main())