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.
- code_mower/__init__.py +3 -0
- code_mower/adapters/__init__.py +39 -0
- code_mower/adapters/_base.py +148 -0
- code_mower/adapters/cursor_bugbot.py +97 -0
- code_mower/adapters/gitar.py +111 -0
- code_mower/adapters/greptile.py +191 -0
- code_mower/adapters/qodo.py +140 -0
- code_mower/antigravity_cli_audit_pr.py +241 -0
- code_mower/audit_handoff_log.py +345 -0
- code_mower/audit_labeler_lib.py +311 -0
- code_mower/audit_progress.py +203 -0
- code_mower/blind_review_artifacts.py +562 -0
- code_mower/blind_review_coordinator.py +276 -0
- code_mower/bootstrap.py +524 -0
- code_mower/builder_experiment.py +539 -0
- code_mower/calibration/__init__.py +181 -0
- code_mower/calibration/arms.py +267 -0
- code_mower/calibration/auto_discovery.py +348 -0
- code_mower/calibration/commands.py +192 -0
- code_mower/calibration/context_inputs.py +199 -0
- code_mower/calibration/corpus.py +91 -0
- code_mower/calibration/evidence.py +20 -0
- code_mower/calibration/evidence_report.py +360 -0
- code_mower/calibration/identity.py +27 -0
- code_mower/calibration/metrics.py +18 -0
- code_mower/calibration/overlap.py +103 -0
- code_mower/calibration/planning.py +309 -0
- code_mower/calibration/policy.py +207 -0
- code_mower/calibration/results.py +315 -0
- code_mower/calibration/run_results.py +147 -0
- code_mower/calibration/run_status.py +64 -0
- code_mower/calibration/runner.py +360 -0
- code_mower/calibration/truth.py +188 -0
- code_mower/calibration/value_report.py +142 -0
- code_mower/checks.py +402 -0
- code_mower/claude_audit_pr.py +1126 -0
- code_mower/claude_cli_bounce.py +303 -0
- code_mower/claude_cli_environment.py +73 -0
- code_mower/clear_stale.py +374 -0
- code_mower/cli.py +537 -0
- code_mower/cloud.py +674 -0
- code_mower/cloud_client/__init__.py +173 -0
- code_mower/cloud_client/bundle.py +155 -0
- code_mower/cloud_client/doctor.py +206 -0
- code_mower/cloud_client/dogfood.py +78 -0
- code_mower/cloud_client/endpoints.py +114 -0
- code_mower/cloud_client/errors.py +7 -0
- code_mower/cloud_client/events.py +278 -0
- code_mower/cloud_client/export.py +272 -0
- code_mower/cloud_client/git_metadata.py +46 -0
- code_mower/cloud_client/manifest.py +39 -0
- code_mower/cloud_client/operations.py +448 -0
- code_mower/cloud_client/reports.py +45 -0
- code_mower/cloud_client/setup.py +205 -0
- code_mower/cloud_client/upload.py +97 -0
- code_mower/code_mower_calibration.py +598 -0
- code_mower/code_mower_context_packs.py +591 -0
- code_mower/code_mower_merge.py +227 -0
- code_mower/code_mower_telemetry.py +561 -0
- code_mower/coderabbit_cli_audit_pr.py +526 -0
- code_mower/codex_audit_env_preflight.py +220 -0
- code_mower/codex_audit_pr.py +1738 -0
- code_mower/codex_audit_schema_smoke.py +160 -0
- code_mower/codex_audit_verdict.schema.json +44 -0
- code_mower/config.py +655 -0
- code_mower/doctor.py +161 -0
- code_mower/doctor_checks/__init__.py +104 -0
- code_mower/doctor_checks/cloud.py +129 -0
- code_mower/doctor_checks/common.py +215 -0
- code_mower/doctor_checks/github.py +128 -0
- code_mower/doctor_checks/github_actions.py +11 -0
- code_mower/doctor_checks/github_actions_cost.py +99 -0
- code_mower/doctor_checks/github_actions_cost_summary.py +111 -0
- code_mower/doctor_checks/github_actions_failure_annotations.py +27 -0
- code_mower/doctor_checks/github_actions_failure_models.py +47 -0
- code_mower/doctor_checks/github_actions_failure_scan.py +200 -0
- code_mower/doctor_checks/github_actions_failure_selection.py +63 -0
- code_mower/doctor_checks/github_actions_failures.py +103 -0
- code_mower/doctor_checks/github_actions_permissions.py +55 -0
- code_mower/doctor_checks/github_api.py +79 -0
- code_mower/doctor_checks/github_branch.py +56 -0
- code_mower/doctor_checks/github_config.py +25 -0
- code_mower/doctor_checks/github_provider.py +61 -0
- code_mower/doctor_checks/github_repo.py +120 -0
- code_mower/doctor_checks/groups.py +36 -0
- code_mower/doctor_checks/models.py +96 -0
- code_mower/doctor_checks/output.py +86 -0
- code_mower/doctor_checks/presets.py +64 -0
- code_mower/doctor_checks/privacy.py +20 -0
- code_mower/doctor_checks/provider_api_model.py +138 -0
- code_mower/doctor_checks/provider_api_model_openai.py +29 -0
- code_mower/doctor_checks/provider_api_model_profiles.py +137 -0
- code_mower/doctor_checks/provider_env.py +113 -0
- code_mower/doctor_checks/provider_env_required.py +56 -0
- code_mower/doctor_checks/provider_env_tokens.py +100 -0
- code_mower/doctor_checks/provider_local_cli.py +162 -0
- code_mower/doctor_checks/provider_local_cli_commands.py +47 -0
- code_mower/doctor_checks/provider_local_cli_probe_config.py +70 -0
- code_mower/doctor_checks/provider_probe.py +20 -0
- code_mower/doctor_checks/provider_probe_auth.py +52 -0
- code_mower/doctor_checks/provider_probe_evaluation.py +109 -0
- code_mower/doctor_checks/provider_probe_json.py +45 -0
- code_mower/doctor_checks/provider_probe_remediation.py +39 -0
- code_mower/doctor_checks/providers.py +159 -0
- code_mower/doctor_checks/registry.py +69 -0
- code_mower/doctor_checks/runner.py +188 -0
- code_mower/doctor_checks/runtime.py +89 -0
- code_mower/doctor_checks/runtime_github_auth.py +148 -0
- code_mower/gemini_cli_audit_pr.py +897 -0
- code_mower/hermes_cli_audit_pr.py +436 -0
- code_mower/init.py +888 -0
- code_mower/lane_configs/__init__.py +37 -0
- code_mower/lane_configs/aider.py +32 -0
- code_mower/lane_configs/antigravity_cli.py +35 -0
- code_mower/lane_configs/claude.py +35 -0
- code_mower/lane_configs/codex.py +32 -0
- code_mower/lane_configs/devin.py +33 -0
- code_mower/lane_configs/gemini_cli.py +35 -0
- code_mower/lane_configs/hermes_cli.py +35 -0
- code_mower/lane_configs/local_llm.py +31 -0
- code_mower/local_llm_audit_pr.py +1364 -0
- code_mower/local_llm_bakeoff.py +458 -0
- code_mower/local_llm_calibration.py +441 -0
- code_mower/local_llm_profiles.py +66 -0
- code_mower/migration.py +508 -0
- code_mower/migration_install.py +292 -0
- code_mower/migration_mirror.py +392 -0
- code_mower/migration_readiness.py +237 -0
- code_mower/migration_rehearsal.py +718 -0
- code_mower/next_steps.py +441 -0
- code_mower/package.py +673 -0
- code_mower/package_content.py +444 -0
- code_mower/package_manifest.py +452 -0
- code_mower/package_paths.py +53 -0
- code_mower/package_rendering.py +90 -0
- code_mower/package_static.py +585 -0
- code_mower/prompts.py +267 -0
- code_mower/provider_registry.py +469 -0
- code_mower/provider_runners/__init__.py +60 -0
- code_mower/provider_runners/comments.py +31 -0
- code_mower/provider_runners/git.py +46 -0
- code_mower/provider_runners/github_auth.py +61 -0
- code_mower/provider_runners/github_pr.py +120 -0
- code_mower/provider_runners/process.py +58 -0
- code_mower/provider_runners/repo_paths.py +23 -0
- code_mower/provider_runners/text_schema.py +41 -0
- code_mower/provider_runners/verdict_artifacts.py +103 -0
- code_mower/provider_runners/workspace.py +57 -0
- code_mower/release_readiness.py +549 -0
- code_mower/reviewer_metrics.py +389 -0
- code_mower/saas_reviewer_labeler.py +809 -0
- code_mower/secrets.py +89 -0
- code_mower/templates/builder-experiment.example.json +55 -0
- code_mower/templates/calibration-corpus.example.json +129 -0
- code_mower/templates/calibration-corpus.json +129 -0
- code_mower/templates/code-mower.example.yml +423 -0
- code_mower/templates/context-packs.example.json +150 -0
- code_mower/templates/lane_prompts/base-audit.md +22 -0
- code_mower/templates/lane_prompts/calibration-policy.md +21 -0
- code_mower/templates/lane_prompts/context-driven-quality.md +21 -0
- code_mower/templates/lane_prompts/docs-design.md +12 -0
- code_mower/templates/lane_prompts/generic-programming.md +21 -0
- code_mower/templates/lane_prompts/operability.md +22 -0
- code_mower/templates/lane_prompts/package-runtime.md +12 -0
- code_mower/templates/lane_prompts/security-threat-model.md +22 -0
- code_mower/templates/product-support/code_mower +216 -0
- code_mower/templates/product-support/code_mower_standalone_pin.env +7 -0
- code_mower/templates/product-support/code_mower_standalone_shadow.sh +151 -0
- code_mower/templates/product-support/run_claude_audit_pr.sh +32 -0
- code_mower/templates/product-support/run_codex_audit_pr.sh +32 -0
- code_mower/templates/product-support/safe_gh_comment.py +96 -0
- code_mower/templates/providers.yml +454 -0
- code_mower/templates/reviewer-spend.example.json +28 -0
- code_mower/templates/reviewer-value-report.example.md +20 -0
- code_mower/templates/workflows/private-standalone-shadow.yml.j2 +106 -0
- code_mower/templates/workflows/review-clear-stale.yml.j2 +83 -0
- code_mower/trailer_comment_labeler.py +207 -0
- code_mower/versioning.py +32 -0
- code_mower-0.5.0b5.dist-info/METADATA +302 -0
- code_mower-0.5.0b5.dist-info/RECORD +185 -0
- code_mower-0.5.0b5.dist-info/WHEEL +5 -0
- code_mower-0.5.0b5.dist-info/entry_points.txt +2 -0
- code_mower-0.5.0b5.dist-info/licenses/LICENSE +202 -0
- code_mower-0.5.0b5.dist-info/licenses/NOTICE +10 -0
- code_mower-0.5.0b5.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,585 @@
|
|
|
1
|
+
"""Static generated package file contents."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
STATIC_PACKAGE_FILES = (
|
|
6
|
+
("src/code_mower/__init__.py", ""),
|
|
7
|
+
(
|
|
8
|
+
"README.md",
|
|
9
|
+
"\n".join(
|
|
10
|
+
[
|
|
11
|
+
"# Code Mower",
|
|
12
|
+
"",
|
|
13
|
+
"Code Mower is the fastest way to build a peer-programmer and "
|
|
14
|
+
"reviewer system around the best AI coding agents.",
|
|
15
|
+
"",
|
|
16
|
+
"It helps teams drive from plan to merge at maximum safe velocity "
|
|
17
|
+
"while preserving code quality, architecture, and deployment "
|
|
18
|
+
"confidence. It also turns your real codebase into a "
|
|
19
|
+
"quality-and-velocity benchmark, measuring which AI builders and "
|
|
20
|
+
"reviewers deliver the best quality, speed, and cost results for "
|
|
21
|
+
"your actual product.",
|
|
22
|
+
"",
|
|
23
|
+
"The Code Mower open-source core is licensed under Apache-2.0. "
|
|
24
|
+
"Hosted benchmarking and reporting, managed integrations, "
|
|
25
|
+
"private telemetry and benchmark data products, enterprise "
|
|
26
|
+
"controls, and support are commercial surfaces unless licensed "
|
|
27
|
+
"otherwise.",
|
|
28
|
+
"",
|
|
29
|
+
"Code Mower is extracted from a production multi-repo development "
|
|
30
|
+
"workflow and packaged as a standalone OSS tool. Start with "
|
|
31
|
+
"`code-mower init --easy`, then run "
|
|
32
|
+
"`code-mower doctor --easy` to verify local CLIs, "
|
|
33
|
+
"tokens, provider catalog coverage, and runtime probes.",
|
|
34
|
+
"",
|
|
35
|
+
"For existing repos that still carry product-local Code Mower "
|
|
36
|
+
"tools, run `code-mower migration wrapper-rehearsal "
|
|
37
|
+
"--repo-path /path/to/repo --json` before flipping to a pinned "
|
|
38
|
+
"standalone package. The rehearsal compares safe read-only "
|
|
39
|
+
"commands and gives a low-risk path away from mirrored "
|
|
40
|
+
"maintenance.",
|
|
41
|
+
"",
|
|
42
|
+
"For public release readiness, see `docs/repo-strategy.md`, "
|
|
43
|
+
"`docs/mirror-removal-runbook.md`, "
|
|
44
|
+
"`docs/commercial-boundary.md`, and "
|
|
45
|
+
"`docs/public-release-checklist.md`.",
|
|
46
|
+
"",
|
|
47
|
+
]
|
|
48
|
+
),
|
|
49
|
+
),
|
|
50
|
+
(
|
|
51
|
+
"MANIFEST.in",
|
|
52
|
+
"\n".join(
|
|
53
|
+
[
|
|
54
|
+
"recursive-include src/code_mower/templates *.yml *.yaml *.json",
|
|
55
|
+
"recursive-include src/code_mower/templates *.md",
|
|
56
|
+
"recursive-include src/code_mower/templates *.j2",
|
|
57
|
+
"recursive-include src/code_mower/templates/product-support *",
|
|
58
|
+
"include src/code_mower/*.json",
|
|
59
|
+
"recursive-include templates *.j2 *.json *.md *.yml *.yaml",
|
|
60
|
+
"include requirements/*.txt",
|
|
61
|
+
"include LICENSE",
|
|
62
|
+
"include NOTICE",
|
|
63
|
+
"",
|
|
64
|
+
]
|
|
65
|
+
),
|
|
66
|
+
),
|
|
67
|
+
(
|
|
68
|
+
".gitignore",
|
|
69
|
+
"\n".join(
|
|
70
|
+
[
|
|
71
|
+
".venv/",
|
|
72
|
+
"__pycache__/",
|
|
73
|
+
"*.py[cod]",
|
|
74
|
+
"*.egg-info/",
|
|
75
|
+
"build/",
|
|
76
|
+
"dist/",
|
|
77
|
+
".pytest_cache/",
|
|
78
|
+
".mypy_cache/",
|
|
79
|
+
".ruff_cache/",
|
|
80
|
+
".code-mower/",
|
|
81
|
+
".code-mower.generated/",
|
|
82
|
+
"",
|
|
83
|
+
]
|
|
84
|
+
),
|
|
85
|
+
),
|
|
86
|
+
(
|
|
87
|
+
".github/workflows/ci.yml",
|
|
88
|
+
"\n".join(
|
|
89
|
+
[
|
|
90
|
+
"name: Code Mower CI",
|
|
91
|
+
"",
|
|
92
|
+
"on:",
|
|
93
|
+
" push:",
|
|
94
|
+
" branches: [main]",
|
|
95
|
+
" pull_request:",
|
|
96
|
+
" workflow_dispatch:",
|
|
97
|
+
"",
|
|
98
|
+
"jobs:",
|
|
99
|
+
" package:",
|
|
100
|
+
" runs-on: ubuntu-latest",
|
|
101
|
+
" steps:",
|
|
102
|
+
" - name: Check out",
|
|
103
|
+
" uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10",
|
|
104
|
+
"",
|
|
105
|
+
" - name: Set up Python",
|
|
106
|
+
" uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405",
|
|
107
|
+
" with:",
|
|
108
|
+
" python-version: '3.12'",
|
|
109
|
+
"",
|
|
110
|
+
" - name: Install package",
|
|
111
|
+
" run: |",
|
|
112
|
+
" python -m pip install --upgrade pip",
|
|
113
|
+
" python -m pip install -e .",
|
|
114
|
+
" python -m pip check",
|
|
115
|
+
"",
|
|
116
|
+
" - name: Compile sources",
|
|
117
|
+
" run: python -m compileall src scripts",
|
|
118
|
+
"",
|
|
119
|
+
" - name: Easy-mode smoke",
|
|
120
|
+
" run: python scripts/smoke_easy_mode.py --work-dir \"$RUNNER_TEMP/code-mower-smoke\" --json",
|
|
121
|
+
"",
|
|
122
|
+
" - name: Fresh-clone rehearsal",
|
|
123
|
+
" run: >-",
|
|
124
|
+
" python scripts/fresh_clone_rehearsal.py",
|
|
125
|
+
" --repo-url \"$GITHUB_WORKSPACE\"",
|
|
126
|
+
" --ref \"$GITHUB_SHA\"",
|
|
127
|
+
" --work-dir \"$RUNNER_TEMP/code-mower-fresh-clone\"",
|
|
128
|
+
" --json",
|
|
129
|
+
"",
|
|
130
|
+
]
|
|
131
|
+
),
|
|
132
|
+
),
|
|
133
|
+
(
|
|
134
|
+
"scripts/smoke_easy_mode.py",
|
|
135
|
+
"""#!/usr/bin/env python3
|
|
136
|
+
\"\"\"Smoke test the standalone Code Mower easy-mode package flow.\"\"\"
|
|
137
|
+
|
|
138
|
+
from __future__ import annotations
|
|
139
|
+
|
|
140
|
+
import argparse
|
|
141
|
+
import json
|
|
142
|
+
import os
|
|
143
|
+
import shutil
|
|
144
|
+
import subprocess
|
|
145
|
+
import sys
|
|
146
|
+
import tempfile
|
|
147
|
+
from pathlib import Path
|
|
148
|
+
from typing import Any
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
DEFAULT_CODE_MOWER_BIN = \"__CODE_MOWER_CONSOLE_SCRIPT__\"
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def _run(
|
|
155
|
+
command: list[str],
|
|
156
|
+
*,
|
|
157
|
+
cwd: Path,
|
|
158
|
+
env: dict[str, str],
|
|
159
|
+
stdout_path: Path | None = None,
|
|
160
|
+
) -> dict[str, Any]:
|
|
161
|
+
completed = subprocess.run(
|
|
162
|
+
command,
|
|
163
|
+
cwd=cwd,
|
|
164
|
+
env=env,
|
|
165
|
+
text=True,
|
|
166
|
+
stdout=subprocess.PIPE,
|
|
167
|
+
stderr=subprocess.PIPE,
|
|
168
|
+
)
|
|
169
|
+
if stdout_path is not None:
|
|
170
|
+
stdout_path.parent.mkdir(parents=True, exist_ok=True)
|
|
171
|
+
stdout_path.write_text(completed.stdout, encoding=\"utf-8\")
|
|
172
|
+
result = {
|
|
173
|
+
\"command\": command,
|
|
174
|
+
\"cwd\": str(cwd),
|
|
175
|
+
\"returncode\": completed.returncode,
|
|
176
|
+
\"stdout_path\": str(stdout_path) if stdout_path else None,
|
|
177
|
+
\"stderr\": completed.stderr[-4000:],
|
|
178
|
+
}
|
|
179
|
+
if completed.returncode != 0:
|
|
180
|
+
raise RuntimeError(json.dumps(result, indent=2, sort_keys=True))
|
|
181
|
+
return result
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def _write_json(path: Path, data: Any) -> None:
|
|
185
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
186
|
+
path.write_text(json.dumps(data, indent=2, sort_keys=True) + \"\\n\", encoding=\"utf-8\")
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def _resolve_executable(path_text: str) -> Path:
|
|
190
|
+
resolved = shutil.which(path_text)
|
|
191
|
+
if resolved:
|
|
192
|
+
return Path(resolved).resolve()
|
|
193
|
+
return Path(path_text).expanduser().resolve()
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def _default_code_mower_bin() -> str:
|
|
197
|
+
resolved = shutil.which(DEFAULT_CODE_MOWER_BIN)
|
|
198
|
+
if resolved:
|
|
199
|
+
return resolved
|
|
200
|
+
|
|
201
|
+
sibling_script = Path(sys.executable).parent / DEFAULT_CODE_MOWER_BIN
|
|
202
|
+
if sibling_script.is_file():
|
|
203
|
+
return str(sibling_script)
|
|
204
|
+
|
|
205
|
+
resolved_sibling_script = Path(sys.executable).resolve().parent / DEFAULT_CODE_MOWER_BIN
|
|
206
|
+
if resolved_sibling_script.is_file():
|
|
207
|
+
return str(resolved_sibling_script)
|
|
208
|
+
|
|
209
|
+
return DEFAULT_CODE_MOWER_BIN
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
def run_smoke(*, code_mower_bin: Path, work_dir: Path) -> dict[str, Any]:
|
|
213
|
+
if not code_mower_bin.is_file():
|
|
214
|
+
raise RuntimeError(f\"code-mower executable not found: {code_mower_bin}\")
|
|
215
|
+
|
|
216
|
+
toy_repo = work_dir / \"toy-repo\"
|
|
217
|
+
outputs = work_dir / \"outputs\"
|
|
218
|
+
if toy_repo.exists():
|
|
219
|
+
shutil.rmtree(toy_repo)
|
|
220
|
+
toy_repo.mkdir(parents=True)
|
|
221
|
+
outputs.mkdir(parents=True, exist_ok=True)
|
|
222
|
+
|
|
223
|
+
env = os.environ.copy()
|
|
224
|
+
env[\"PATH\"] = f\"{code_mower_bin.parent}{os.pathsep}{env.get('PATH', '')}\"
|
|
225
|
+
|
|
226
|
+
git = shutil.which(\"git\")
|
|
227
|
+
if git:
|
|
228
|
+
_run([git, \"init\", \"-q\"], cwd=toy_repo, env=env)
|
|
229
|
+
_run([git, \"config\", \"user.name\", \"Code Mower Smoke\"], cwd=toy_repo, env=env)
|
|
230
|
+
_run([git, \"config\", \"user.email\", \"smoke@example.com\"], cwd=toy_repo, env=env)
|
|
231
|
+
_run([git, \"config\", \"commit.gpgSign\", \"false\"], cwd=toy_repo, env=env)
|
|
232
|
+
(toy_repo / \"README.md\").write_text(
|
|
233
|
+
\"# Code Mower smoke toy repo\\n\", encoding=\"utf-8\"
|
|
234
|
+
)
|
|
235
|
+
if git:
|
|
236
|
+
_run([git, \"add\", \"README.md\"], cwd=toy_repo, env=env)
|
|
237
|
+
_run(
|
|
238
|
+
[git, \"-c\", \"commit.gpgSign=false\", \"commit\", \"-q\", \"-m\", \"Initial smoke repo\"],
|
|
239
|
+
cwd=toy_repo,
|
|
240
|
+
env=env,
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
steps: list[dict[str, Any]] = []
|
|
244
|
+
cm = str(code_mower_bin)
|
|
245
|
+
steps.append(
|
|
246
|
+
_run([cm, \"providers\", \"list\"], cwd=toy_repo, env=env, stdout_path=outputs / \"providers.txt\")
|
|
247
|
+
)
|
|
248
|
+
steps.append(
|
|
249
|
+
_run(
|
|
250
|
+
[cm, \"init\", \"--easy\", \"--apply\", \"--output-dir\", \".code-mower.generated\", \"--json\"],
|
|
251
|
+
cwd=toy_repo,
|
|
252
|
+
env=env,
|
|
253
|
+
stdout_path=outputs / \"init-apply.json\",
|
|
254
|
+
)
|
|
255
|
+
)
|
|
256
|
+
steps.append(
|
|
257
|
+
_run(
|
|
258
|
+
[\"bash\", \".code-mower.generated/smoke-tests.sh\"],
|
|
259
|
+
cwd=toy_repo,
|
|
260
|
+
env=env,
|
|
261
|
+
stdout_path=outputs / \"generated-smoke-tests.txt\",
|
|
262
|
+
)
|
|
263
|
+
)
|
|
264
|
+
steps.append(
|
|
265
|
+
_run([cm, \"doctor\", \"--easy\", \"--json\"], cwd=toy_repo, env=env, stdout_path=outputs / \"doctor.json\")
|
|
266
|
+
)
|
|
267
|
+
steps.append(
|
|
268
|
+
_run(
|
|
269
|
+
[cm, \"next-steps\", \"--profile\", \"recommended\", \"--json\"],
|
|
270
|
+
cwd=toy_repo,
|
|
271
|
+
env=env,
|
|
272
|
+
stdout_path=outputs / \"next-steps.json\",
|
|
273
|
+
)
|
|
274
|
+
)
|
|
275
|
+
steps.append(
|
|
276
|
+
_run(
|
|
277
|
+
[
|
|
278
|
+
cm,
|
|
279
|
+
\"migration\",
|
|
280
|
+
\"wrapper-rehearsal\",
|
|
281
|
+
\"--repo-path\",
|
|
282
|
+
str(toy_repo),
|
|
283
|
+
\"--local-command\",
|
|
284
|
+
cm,
|
|
285
|
+
\"--package-command\",
|
|
286
|
+
cm,
|
|
287
|
+
\"--json\",
|
|
288
|
+
],
|
|
289
|
+
cwd=toy_repo,
|
|
290
|
+
env=env,
|
|
291
|
+
stdout_path=outputs / \"wrapper-rehearsal.json\",
|
|
292
|
+
)
|
|
293
|
+
)
|
|
294
|
+
|
|
295
|
+
code_mower_dir = toy_repo / \".code-mower\"
|
|
296
|
+
code_mower_dir.mkdir(exist_ok=True)
|
|
297
|
+
steps.append(
|
|
298
|
+
_run(
|
|
299
|
+
[
|
|
300
|
+
cm,
|
|
301
|
+
\"calibration\",
|
|
302
|
+
\"plan\",
|
|
303
|
+
\".code-mower.generated/calibration-corpus.json\",
|
|
304
|
+
\"--replicates\",
|
|
305
|
+
\"2\",
|
|
306
|
+
\"--json\",
|
|
307
|
+
],
|
|
308
|
+
cwd=toy_repo,
|
|
309
|
+
env=env,
|
|
310
|
+
stdout_path=code_mower_dir / \"calibration-plan.json\",
|
|
311
|
+
)
|
|
312
|
+
)
|
|
313
|
+
steps.append(
|
|
314
|
+
_run(
|
|
315
|
+
[cm, \"calibration\", \"evidence\", \".code-mower.generated/calibration-corpus.json\", \"--json\"],
|
|
316
|
+
cwd=toy_repo,
|
|
317
|
+
env=env,
|
|
318
|
+
stdout_path=toy_repo / \"calibration-evidence.json\",
|
|
319
|
+
)
|
|
320
|
+
)
|
|
321
|
+
steps.append(
|
|
322
|
+
_run(
|
|
323
|
+
[
|
|
324
|
+
cm,
|
|
325
|
+
\"reviewer-metrics\",
|
|
326
|
+
\"calibration-evidence.json\",
|
|
327
|
+
\"--spend\",
|
|
328
|
+
\".code-mower.generated/reviewer-spend.json\",
|
|
329
|
+
\"--json\",
|
|
330
|
+
],
|
|
331
|
+
cwd=toy_repo,
|
|
332
|
+
env=env,
|
|
333
|
+
stdout_path=toy_repo / \"reviewer-metrics.json\",
|
|
334
|
+
)
|
|
335
|
+
)
|
|
336
|
+
steps.append(
|
|
337
|
+
_run(
|
|
338
|
+
[cm, \"calibration\", \"policy\", \"reviewer-metrics.json\", \"--json\"],
|
|
339
|
+
cwd=toy_repo,
|
|
340
|
+
env=env,
|
|
341
|
+
stdout_path=toy_repo / \"lane-policy.json\",
|
|
342
|
+
)
|
|
343
|
+
)
|
|
344
|
+
steps.append(
|
|
345
|
+
_run(
|
|
346
|
+
[
|
|
347
|
+
cm,
|
|
348
|
+
\"calibration\",
|
|
349
|
+
\"value-report\",
|
|
350
|
+
\".code-mower.generated/calibration-corpus.json\",
|
|
351
|
+
\"--spend\",
|
|
352
|
+
\".code-mower.generated/reviewer-spend.json\",
|
|
353
|
+
\"--output\",
|
|
354
|
+
\"reviewer-value-report.md\",
|
|
355
|
+
],
|
|
356
|
+
cwd=toy_repo,
|
|
357
|
+
env=env,
|
|
358
|
+
stdout_path=outputs / \"value-report.txt\",
|
|
359
|
+
)
|
|
360
|
+
)
|
|
361
|
+
steps.append(
|
|
362
|
+
_run(
|
|
363
|
+
[
|
|
364
|
+
cm,
|
|
365
|
+
\"cloud\",
|
|
366
|
+
\"export\",
|
|
367
|
+
\"--report\",
|
|
368
|
+
\"reviewer-metrics=reviewer-metrics.json\",
|
|
369
|
+
\"--report\",
|
|
370
|
+
\"lane-policy=lane-policy.json\",
|
|
371
|
+
\"--report\",
|
|
372
|
+
\"value-report=reviewer-value-report.md\",
|
|
373
|
+
\"--output-dir\",
|
|
374
|
+
\".code-mower/cloud-benchmark-bundle\",
|
|
375
|
+
\"--json\",
|
|
376
|
+
],
|
|
377
|
+
cwd=toy_repo,
|
|
378
|
+
env=env,
|
|
379
|
+
stdout_path=toy_repo / \"cloud-export.json\",
|
|
380
|
+
)
|
|
381
|
+
)
|
|
382
|
+
steps.append(
|
|
383
|
+
_run(
|
|
384
|
+
[
|
|
385
|
+
cm,
|
|
386
|
+
\"cloud\",
|
|
387
|
+
\"upload\",
|
|
388
|
+
\".code-mower/cloud-benchmark-bundle\",
|
|
389
|
+
\"--dry-run\",
|
|
390
|
+
\"--json\",
|
|
391
|
+
],
|
|
392
|
+
cwd=toy_repo,
|
|
393
|
+
env=env,
|
|
394
|
+
stdout_path=toy_repo / \"cloud-upload-dry-run.json\",
|
|
395
|
+
)
|
|
396
|
+
)
|
|
397
|
+
|
|
398
|
+
summary = {
|
|
399
|
+
\"mode\": \"code-mower-easy-mode-smoke\",
|
|
400
|
+
\"status\": \"pass\",
|
|
401
|
+
\"code_mower_bin\": str(code_mower_bin),
|
|
402
|
+
\"work_dir\": str(work_dir),
|
|
403
|
+
\"toy_repo\": str(toy_repo),
|
|
404
|
+
\"outputs_dir\": str(outputs),
|
|
405
|
+
\"steps\": steps,
|
|
406
|
+
}
|
|
407
|
+
_write_json(outputs / \"smoke-summary.json\", summary)
|
|
408
|
+
return summary
|
|
409
|
+
|
|
410
|
+
|
|
411
|
+
def main(argv: list[str] | None = None) -> int:
|
|
412
|
+
parser = argparse.ArgumentParser(description=__doc__)
|
|
413
|
+
parser.add_argument(
|
|
414
|
+
\"--code-mower-bin\",
|
|
415
|
+
default=_default_code_mower_bin(),
|
|
416
|
+
help=\"Path to the installed code-mower executable.\",
|
|
417
|
+
)
|
|
418
|
+
parser.add_argument(
|
|
419
|
+
\"--work-dir\",
|
|
420
|
+
default=None,
|
|
421
|
+
help=\"Directory for the generated toy repo and outputs. Defaults to a temp dir.\",
|
|
422
|
+
)
|
|
423
|
+
parser.add_argument(\"--json\", action=\"store_true\")
|
|
424
|
+
args = parser.parse_args(argv)
|
|
425
|
+
|
|
426
|
+
work_dir = Path(args.work_dir) if args.work_dir else Path(
|
|
427
|
+
tempfile.mkdtemp(prefix=\"code-mower-easy-smoke-\")
|
|
428
|
+
)
|
|
429
|
+
try:
|
|
430
|
+
summary = run_smoke(code_mower_bin=_resolve_executable(args.code_mower_bin), work_dir=work_dir)
|
|
431
|
+
except RuntimeError as exc:
|
|
432
|
+
print(f\"error: {exc}\", file=sys.stderr)
|
|
433
|
+
return 1
|
|
434
|
+
|
|
435
|
+
if args.json:
|
|
436
|
+
print(json.dumps(summary, indent=2, sort_keys=True))
|
|
437
|
+
else:
|
|
438
|
+
print(f\"Code Mower easy-mode smoke passed: {work_dir}\")
|
|
439
|
+
return 0
|
|
440
|
+
|
|
441
|
+
|
|
442
|
+
if __name__ == \"__main__\":
|
|
443
|
+
raise SystemExit(main())
|
|
444
|
+
""",
|
|
445
|
+
),
|
|
446
|
+
(
|
|
447
|
+
"scripts/fresh_clone_rehearsal.py",
|
|
448
|
+
"""#!/usr/bin/env python3
|
|
449
|
+
\"\"\"Rehearse Code Mower from a fresh clone and clean virtual environment.\"\"\"
|
|
450
|
+
|
|
451
|
+
from __future__ import annotations
|
|
452
|
+
|
|
453
|
+
import argparse
|
|
454
|
+
import json
|
|
455
|
+
import subprocess
|
|
456
|
+
import sys
|
|
457
|
+
import tempfile
|
|
458
|
+
from pathlib import Path
|
|
459
|
+
from typing import Any
|
|
460
|
+
|
|
461
|
+
|
|
462
|
+
class RehearsalError(RuntimeError):
|
|
463
|
+
def __init__(self, message: str, steps: list[dict[str, Any]]) -> None:
|
|
464
|
+
super().__init__(message)
|
|
465
|
+
self.steps = steps
|
|
466
|
+
|
|
467
|
+
|
|
468
|
+
def _venv_python(venv_dir: Path) -> Path:
|
|
469
|
+
unix_python = venv_dir / \"bin\" / \"python\"
|
|
470
|
+
if unix_python.exists():
|
|
471
|
+
return unix_python
|
|
472
|
+
return venv_dir / \"Scripts\" / \"python.exe\"
|
|
473
|
+
|
|
474
|
+
|
|
475
|
+
def _default_repo_url() -> str:
|
|
476
|
+
package_root = Path(__file__).resolve().parents[1]
|
|
477
|
+
return str(package_root)
|
|
478
|
+
|
|
479
|
+
|
|
480
|
+
def _run(command: list[str], *, cwd: Path, steps: list[dict[str, Any]]) -> None:
|
|
481
|
+
completed = subprocess.run(
|
|
482
|
+
command,
|
|
483
|
+
cwd=cwd,
|
|
484
|
+
text=True,
|
|
485
|
+
stdout=subprocess.PIPE,
|
|
486
|
+
stderr=subprocess.PIPE,
|
|
487
|
+
check=False,
|
|
488
|
+
)
|
|
489
|
+
step = {
|
|
490
|
+
\"command\": command,
|
|
491
|
+
\"cwd\": str(cwd),
|
|
492
|
+
\"returncode\": completed.returncode,
|
|
493
|
+
\"stdout\": completed.stdout[-4000:],
|
|
494
|
+
\"stderr\": completed.stderr[-4000:],
|
|
495
|
+
}
|
|
496
|
+
steps.append(step)
|
|
497
|
+
if completed.returncode != 0:
|
|
498
|
+
raise RehearsalError(f\"command failed: {' '.join(command)}\", steps)
|
|
499
|
+
|
|
500
|
+
|
|
501
|
+
def run_rehearsal(args: argparse.Namespace) -> dict[str, Any]:
|
|
502
|
+
work_dir = (
|
|
503
|
+
Path(args.work_dir).expanduser().resolve()
|
|
504
|
+
if args.work_dir
|
|
505
|
+
else Path(tempfile.mkdtemp(prefix=\"code-mower-fresh-clone-\"))
|
|
506
|
+
)
|
|
507
|
+
clone_dir = work_dir / \"clone\"
|
|
508
|
+
venv_dir = work_dir / \"venv\"
|
|
509
|
+
smoke_dir = work_dir / \"smoke\"
|
|
510
|
+
steps: list[dict[str, Any]] = []
|
|
511
|
+
|
|
512
|
+
if clone_dir.exists() or venv_dir.exists() or smoke_dir.exists():
|
|
513
|
+
raise RuntimeError(f\"work directory is not clean: {work_dir}\")
|
|
514
|
+
work_dir.mkdir(parents=True, exist_ok=True)
|
|
515
|
+
|
|
516
|
+
repo_url = args.repo_url or _default_repo_url()
|
|
517
|
+
_run([\"git\", \"clone\", repo_url, str(clone_dir)], cwd=work_dir, steps=steps)
|
|
518
|
+
if args.ref:
|
|
519
|
+
_run([\"git\", \"checkout\", args.ref], cwd=clone_dir, steps=steps)
|
|
520
|
+
|
|
521
|
+
python_bin = Path(args.python).expanduser().resolve() if args.python else Path(sys.executable)
|
|
522
|
+
_run([str(python_bin), \"-m\", \"venv\", str(venv_dir)], cwd=work_dir, steps=steps)
|
|
523
|
+
venv_python = _venv_python(venv_dir)
|
|
524
|
+
_run([str(venv_python), \"-m\", \"pip\", \"install\", \"--upgrade\", \"pip\"], cwd=clone_dir, steps=steps)
|
|
525
|
+
_run([str(venv_python), \"-m\", \"pip\", \"install\", \"-e\", \".\"], cwd=clone_dir, steps=steps)
|
|
526
|
+
_run([str(venv_python), \"-m\", \"pip\", \"check\"], cwd=clone_dir, steps=steps)
|
|
527
|
+
_run(
|
|
528
|
+
[
|
|
529
|
+
str(venv_python),
|
|
530
|
+
\"scripts/smoke_easy_mode.py\",
|
|
531
|
+
\"--work-dir\",
|
|
532
|
+
str(smoke_dir),
|
|
533
|
+
\"--json\",
|
|
534
|
+
],
|
|
535
|
+
cwd=clone_dir,
|
|
536
|
+
steps=steps,
|
|
537
|
+
)
|
|
538
|
+
|
|
539
|
+
return {
|
|
540
|
+
\"mode\": \"code-mower-fresh-clone-rehearsal\",
|
|
541
|
+
\"status\": \"pass\",
|
|
542
|
+
\"repo_url\": repo_url,
|
|
543
|
+
\"ref\": args.ref,
|
|
544
|
+
\"work_dir\": str(work_dir),
|
|
545
|
+
\"clone_dir\": str(clone_dir),
|
|
546
|
+
\"steps\": steps,
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
|
|
550
|
+
def main(argv: list[str] | None = None) -> int:
|
|
551
|
+
parser = argparse.ArgumentParser(description=__doc__)
|
|
552
|
+
parser.add_argument(\"--repo-url\", help=\"Repository URL or local path to clone.\")
|
|
553
|
+
parser.add_argument(\"--ref\", help=\"Branch, tag, or commit to check out after cloning.\")
|
|
554
|
+
parser.add_argument(\"--work-dir\", help=\"Clean work directory for clone, venv, and smoke output.\")
|
|
555
|
+
parser.add_argument(\"--python\", help=\"Python executable used to create the rehearsal venv.\")
|
|
556
|
+
parser.add_argument(\"--json\", action=\"store_true\", help=\"Emit JSON output.\")
|
|
557
|
+
args = parser.parse_args(argv)
|
|
558
|
+
|
|
559
|
+
try:
|
|
560
|
+
payload = run_rehearsal(args)
|
|
561
|
+
except Exception as exc: # pragma: no cover - exercised by CLI failure paths.
|
|
562
|
+
payload = {
|
|
563
|
+
\"mode\": \"code-mower-fresh-clone-rehearsal\",
|
|
564
|
+
\"status\": \"fail\",
|
|
565
|
+
\"error\": str(exc),
|
|
566
|
+
\"steps\": getattr(exc, \"steps\", []),
|
|
567
|
+
}
|
|
568
|
+
if args.json:
|
|
569
|
+
print(json.dumps(payload, indent=2, sort_keys=True))
|
|
570
|
+
else:
|
|
571
|
+
print(f\"fresh clone rehearsal failed: {exc}\", file=sys.stderr)
|
|
572
|
+
return 1
|
|
573
|
+
|
|
574
|
+
if args.json:
|
|
575
|
+
print(json.dumps(payload, indent=2, sort_keys=True))
|
|
576
|
+
else:
|
|
577
|
+
print(f\"fresh clone rehearsal passed: {payload['clone_dir']}\")
|
|
578
|
+
return 0
|
|
579
|
+
|
|
580
|
+
|
|
581
|
+
if __name__ == \"__main__\":
|
|
582
|
+
raise SystemExit(main())
|
|
583
|
+
""",
|
|
584
|
+
),
|
|
585
|
+
)
|