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,203 @@
1
+ #!/usr/bin/env python3
2
+ """Small progress helpers for local Code Mower audit wrappers.
3
+
4
+ The wrappers can run a reviewer subprocess for many minutes. This module keeps
5
+ status reporting generic: providers pass a lane name and phase name, while the
6
+ core emits elapsed-time progress without knowing provider-specific semantics.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import re
12
+ import shlex
13
+ import subprocess
14
+ import sys
15
+ import threading
16
+ import time
17
+ import urllib.parse
18
+ from dataclasses import dataclass
19
+ from typing import Any, Callable, Optional, Sequence, TextIO
20
+
21
+
22
+ RunFn = Callable[..., subprocess.CompletedProcess]
23
+
24
+ SENSITIVE_VALUE_FLAGS = {
25
+ "--api-key",
26
+ "--apikey",
27
+ "--authorization",
28
+ "--bearer-token",
29
+ "--github-token",
30
+ "--password",
31
+ "--secret",
32
+ "--token",
33
+ }
34
+ SENSITIVE_KEYWORDS = (
35
+ "api-key",
36
+ "apikey",
37
+ "api_key",
38
+ "authorization",
39
+ "bearer",
40
+ "password",
41
+ "passwd",
42
+ "secret",
43
+ "token",
44
+ )
45
+ SENSITIVE_ASSIGNMENT_PATTERN = re.compile(
46
+ r"\b([A-Za-z0-9_.-]*(?:api[-_]?key|apikey|authorization|bearer|password|passwd|secret|token)[A-Za-z0-9_.-]*)=([^\s&]+)",
47
+ flags=re.IGNORECASE,
48
+ )
49
+ SENSITIVE_FLAG_PATTERN = re.compile(
50
+ r"(--(?:api-key|apikey|authorization|bearer-token|github-token|password|secret|token)\s+)(\S+)",
51
+ flags=re.IGNORECASE,
52
+ )
53
+
54
+
55
+ def _looks_sensitive_key(value: str) -> bool:
56
+ normalized = value.lower().replace("_", "-")
57
+ return any(keyword.replace("_", "-") in normalized for keyword in SENSITIVE_KEYWORDS)
58
+
59
+
60
+ def redact_command(command: Sequence[str]) -> list[str]:
61
+ """Mask common secret-bearing command arguments before progress logging."""
62
+ redacted: list[str] = []
63
+ mask_next = False
64
+
65
+ for part in command:
66
+ if mask_next:
67
+ redacted.append("REDACTED")
68
+ mask_next = False
69
+ continue
70
+
71
+ key, sep, _value = part.partition("=")
72
+ if sep and _looks_sensitive_key(key):
73
+ redacted.append(f"{key}=REDACTED")
74
+ continue
75
+
76
+ redacted.append(part)
77
+ if part in SENSITIVE_VALUE_FLAGS:
78
+ mask_next = True
79
+
80
+ return redacted
81
+
82
+
83
+ def redact_detail(value: str) -> str:
84
+ """Mask common secret-bearing key/value fragments in free-form detail text."""
85
+ value = SENSITIVE_ASSIGNMENT_PATTERN.sub(lambda match: f"{match.group(1)}=REDACTED", value)
86
+ return SENSITIVE_FLAG_PATTERN.sub(lambda match: f"{match.group(1)}REDACTED", value)
87
+
88
+
89
+ def format_command(command: Sequence[str], *, max_args: int = 16) -> str:
90
+ """Return a compact shell-ish command string for progress logs."""
91
+ redacted = redact_command(command)
92
+ shown = list(redacted[:max_args])
93
+ suffix = ["..."] if len(redacted) > max_args else []
94
+ return " ".join(shlex.quote(part) for part in [*shown, *suffix])
95
+
96
+
97
+ def format_detail(value: str) -> str:
98
+ """Return a single-token detail value for key=value progress logs."""
99
+ return urllib.parse.quote(redact_detail(value), safe="/:._@=,+-#")
100
+
101
+
102
+ @dataclass
103
+ class AuditProgress:
104
+ lane: str
105
+ heartbeat_seconds: float = 60.0
106
+ stream: Optional[TextIO] = None
107
+ started_at: float = 0.0
108
+
109
+ def __post_init__(self) -> None:
110
+ if self.started_at <= 0:
111
+ self.started_at = time.monotonic()
112
+
113
+ def emit(
114
+ self,
115
+ phase: str,
116
+ *,
117
+ status: str,
118
+ detail: str = "",
119
+ elapsed: Optional[float] = None,
120
+ ) -> None:
121
+ if elapsed is None:
122
+ elapsed = time.monotonic() - self.started_at
123
+ stream = self.stream if self.stream is not None else sys.stderr
124
+ detail_part = f" detail={format_detail(detail)}" if detail else ""
125
+ print(
126
+ f"audit-progress lane={self.lane} phase={phase} "
127
+ f"status={status} elapsed={elapsed:.0f}s{detail_part}",
128
+ file=stream,
129
+ flush=True,
130
+ )
131
+
132
+
133
+ def run_subprocess_with_progress(
134
+ command: Sequence[str],
135
+ *,
136
+ progress: AuditProgress,
137
+ phase: str,
138
+ run: RunFn = subprocess.run,
139
+ heartbeat_seconds: Optional[float] = None,
140
+ redacted_command: Optional[Sequence[str]] = None,
141
+ **kwargs: Any,
142
+ ) -> subprocess.CompletedProcess:
143
+ """Run a subprocess while emitting start/heartbeat/finish progress.
144
+
145
+ The `run` callable is injectable so existing wrapper tests can monkeypatch
146
+ their module-local `subprocess.run` without learning about this helper.
147
+ """
148
+ interval = progress.heartbeat_seconds if heartbeat_seconds is None else heartbeat_seconds
149
+ display_command = format_command(redacted_command or command)
150
+ started_at = time.monotonic()
151
+ progress.emit(phase, status="start", detail=display_command, elapsed=0)
152
+
153
+ stop = threading.Event()
154
+ heartbeat: Optional[threading.Thread] = None
155
+
156
+ if interval > 0:
157
+
158
+ def heartbeat_loop() -> None:
159
+ while not stop.wait(interval):
160
+ progress.emit(
161
+ phase,
162
+ status="running",
163
+ detail=display_command,
164
+ elapsed=time.monotonic() - started_at,
165
+ )
166
+
167
+ heartbeat = threading.Thread(
168
+ target=heartbeat_loop,
169
+ name=f"{progress.lane}-{phase}-progress",
170
+ daemon=True,
171
+ )
172
+ heartbeat.start()
173
+
174
+ try:
175
+ result = run(list(command), **kwargs)
176
+ except subprocess.TimeoutExpired:
177
+ progress.emit(
178
+ phase,
179
+ status="timeout",
180
+ detail=display_command,
181
+ elapsed=time.monotonic() - started_at,
182
+ )
183
+ raise
184
+ except Exception:
185
+ progress.emit(
186
+ phase,
187
+ status="error",
188
+ detail=display_command,
189
+ elapsed=time.monotonic() - started_at,
190
+ )
191
+ raise
192
+ finally:
193
+ stop.set()
194
+ if heartbeat is not None:
195
+ heartbeat.join(timeout=1)
196
+
197
+ progress.emit(
198
+ phase,
199
+ status=f"exit-{result.returncode}",
200
+ detail=display_command,
201
+ elapsed=time.monotonic() - started_at,
202
+ )
203
+ return result