code-mower 0.5.0b49__tar.gz → 0.5.0b51__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.
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/PKG-INFO +6 -6
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/README.md +5 -5
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/pyproject.toml +1 -1
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/__init__.py +1 -1
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/cli.py +1 -1
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/cloud.py +10 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/cloud_client/operations.py +122 -11
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/config.py +39 -2
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/__init__.py +8 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/github.py +10 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/github_branch.py +40 -2
- code_mower-0.5.0b51/src/code_mower/doctor_checks/github_human_token.py +199 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/gate_health.py +228 -4
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/init.py +324 -4
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/lane_configs/claude.py +1 -1
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/lane_configs/codex.py +1 -1
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/package_manifest.py +9 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/provider_registry.py +2 -2
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/templates/code-mower.example.yml +11 -2
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/templates/lane_prompts/operability.md +1 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/templates/lane_prompts/security-threat-model.md +1 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/templates/product-support/status_report.py +30 -4
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/templates/providers.yml +2 -2
- {code_mower-0.5.0b49 → code_mower-0.5.0b51/src/code_mower}/templates/workflows/builder-provenance.yml.j2 +1 -1
- code_mower-0.5.0b51/src/code_mower/templates/workflows/code-mower-agent-pr-labeler.yml.j2 +138 -0
- code_mower-0.5.0b51/src/code_mower/templates/workflows/code-mower-fix-round-dispatch.yml.j2 +153 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/templates/workflows/code-mower-gate-health.yml.j2 +5 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51/src/code_mower}/templates/workflows/code-mower-gate.yml.j2 +7 -1
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/templates/workflows/needs-owner-notify.yml.j2 +9 -1
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/templates/workflows/weekly-status.yml.j2 +2 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower.egg-info/PKG-INFO +6 -6
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower.egg-info/SOURCES.txt +5 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/templates/providers/claude_audit.yml +1 -1
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/templates/providers/codex.yml +1 -1
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/templates/providers.yml +2 -2
- {code_mower-0.5.0b49/src/code_mower → code_mower-0.5.0b51}/templates/workflows/builder-provenance.yml.j2 +1 -1
- code_mower-0.5.0b51/templates/workflows/code-mower-agent-pr-labeler.yml.j2 +138 -0
- code_mower-0.5.0b51/templates/workflows/code-mower-fix-round-dispatch.yml.j2 +153 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/templates/workflows/code-mower-gate-health.yml.j2 +5 -0
- {code_mower-0.5.0b49/src/code_mower → code_mower-0.5.0b51}/templates/workflows/code-mower-gate.yml.j2 +7 -1
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/tests/test_builder_identity.py +38 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/tests/test_doctor_github_checks.py +143 -2
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/tests/test_gate_health.py +214 -4
- code_mower-0.5.0b51/tests/test_prompts.py +27 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/tests/test_release_hygiene.py +215 -42
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/tests/test_reviewer_metrics_core.py +190 -0
- code_mower-0.5.0b49/tests/test_prompts.py +0 -18
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/CODE_OF_CONDUCT.md +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/LICENSE +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/MANIFEST.in +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/NOTICE +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/SUPPORT.md +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/requirements/requirements.txt +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/setup.cfg +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/adapters/__init__.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/adapters/_base.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/adapters/cursor_bugbot.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/adapters/gitar.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/adapters/greptile.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/adapters/qodo.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/antigravity_cli_audit_pr.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/audit_handoff_log.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/audit_labeler_lib.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/audit_progress.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/blind_review_artifacts.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/blind_review_coordinator.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/bootstrap.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/builder_experiment.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/builder_runs.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/calibration/__init__.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/calibration/arms.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/calibration/auto_discovery.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/calibration/commands.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/calibration/context_inputs.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/calibration/corpus.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/calibration/effect_report.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/calibration/evidence.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/calibration/evidence_report.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/calibration/identity.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/calibration/metrics.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/calibration/overlap.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/calibration/planning.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/calibration/policy.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/calibration/results.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/calibration/run_results.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/calibration/run_status.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/calibration/runner.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/calibration/truth.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/calibration/value_report.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/checks.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/claude_audit_pr.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/claude_cli_bounce.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/claude_cli_environment.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/clear_stale.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/cloud_client/__init__.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/cloud_client/bundle.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/cloud_client/doctor.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/cloud_client/dogfood.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/cloud_client/endpoints.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/cloud_client/errors.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/cloud_client/events.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/cloud_client/export.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/cloud_client/git_metadata.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/cloud_client/manifest.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/cloud_client/reports.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/cloud_client/setup.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/cloud_client/upload.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/code_mower_calibration.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/code_mower_context_packs.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/code_mower_merge.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/code_mower_telemetry.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/coderabbit_cli_audit_pr.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/codex_audit_env_preflight.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/codex_audit_pr.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/codex_audit_schema_smoke.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/codex_audit_verdict.schema.json +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/doctor.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/cloud.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/common.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/github_actions.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/github_actions_cost.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/github_actions_cost_summary.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/github_actions_failure_annotations.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/github_actions_failure_models.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/github_actions_failure_scan.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/github_actions_failure_selection.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/github_actions_failures.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/github_actions_permissions.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/github_api.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/github_config.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/github_provider.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/github_repo.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/groups.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/models.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/output.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/presets.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/privacy.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/provider_api_model.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/provider_api_model_openai.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/provider_api_model_profiles.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/provider_env.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/provider_env_required.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/provider_env_tokens.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/provider_local_cli.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/provider_local_cli_commands.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/provider_local_cli_probe_config.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/provider_probe.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/provider_probe_auth.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/provider_probe_evaluation.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/provider_probe_json.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/provider_probe_remediation.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/provider_review_hygiene.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/providers.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/registry.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/runner.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/runtime.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/runtime_github_auth.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/gemini_cli_audit_pr.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/grok_build_audit_pr.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/hermes_cli_audit_pr.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/lane_configs/__init__.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/lane_configs/aider.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/lane_configs/antigravity_cli.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/lane_configs/devin.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/lane_configs/gemini_cli.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/lane_configs/grok_build.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/lane_configs/hermes_cli.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/lane_configs/local_llm.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/local_llm_audit_pr.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/local_llm_bakeoff.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/local_llm_calibration.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/local_llm_profiles.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/migration.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/migration_install.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/migration_mirror.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/migration_readiness.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/migration_rehearsal.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/next_steps.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/package.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/package_content.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/package_paths.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/package_rendering.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/package_static.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/plan_context.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/prompts.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/provider_runners/__init__.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/provider_runners/comments.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/provider_runners/git.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/provider_runners/github_auth.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/provider_runners/github_pr.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/provider_runners/pr_worktree.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/provider_runners/process.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/provider_runners/repo_paths.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/provider_runners/text_schema.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/provider_runners/verdict_artifacts.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/provider_runners/workspace.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/providers/__init__.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/providers/local_cli.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/providers/provenance.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/release_readiness.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/reviewer_metrics.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/reviewer_spend.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/saas_reviewer_labeler.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/secrets.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/templates/builder-experiment.example.json +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/templates/calibration-corpus.example.json +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/templates/calibration-corpus.json +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/templates/context-packs.example.json +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/templates/lane_prompts/base-audit.md +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/templates/lane_prompts/calibration-policy.md +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/templates/lane_prompts/context-driven-quality.md +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/templates/lane_prompts/docs-design.md +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/templates/lane_prompts/generic-programming.md +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/templates/lane_prompts/package-runtime.md +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/templates/lane_prompts/plan-conformance.md +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/templates/product-support/code_mower +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/templates/product-support/code_mower_standalone_pin.env +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/templates/product-support/code_mower_standalone_shadow.sh +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/templates/product-support/run_claude_audit_pr.sh +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/templates/product-support/run_codex_audit_pr.sh +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/templates/product-support/safe_gh_comment.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/templates/reviewer-spend.example.json +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/templates/reviewer-value-report.example.md +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/templates/workflows/audit-label-cleanup.yml.j2 +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/templates/workflows/hosted-bridge.yml.j2 +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/templates/workflows/local-cli-audit.yml.j2 +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/templates/workflows/private-standalone-shadow.yml.j2 +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/templates/workflows/review-clear-stale.yml.j2 +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/templates/workflows/saas-reviewer-labeler.yml.j2 +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/templates/workflows/self-hosted-local-audit.yml.j2 +1 -1
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/templates/workflows/trailer-comment-labeler.yml.j2 +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/trailer_comment_labeler.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/versioning.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower/work_orders.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower.egg-info/dependency_links.txt +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower.egg-info/entry_points.txt +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower.egg-info/requires.txt +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/src/code_mower.egg-info/top_level.txt +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/templates/builder-experiment.example.json +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/templates/calibration-corpus.example.json +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/templates/calibration-corpus.json +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/templates/code-mower.yml.j2 +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/templates/context-packs.example.json +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/templates/cursor/BUGBOT.md +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/templates/providers/acp_bridge.yml +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/templates/providers/aider.yml +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/templates/providers/antigravity_cli.yml +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/templates/providers/claude_review.yml +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/templates/providers/coderabbit_cli.yml +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/templates/providers/cursor_bugbot.yml +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/templates/providers/devin.yml +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/templates/providers/gemini_cli.yml +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/templates/providers/gitar.yml +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/templates/providers/greptile.yml +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/templates/providers/hermes_cli.yml +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/templates/providers/local_llm.yml +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/templates/providers/qodo.yml +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/templates/reviewer-spend.example.json +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/templates/reviewer-value-report.example.md +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/templates/workflows/audit-label-cleanup.yml.j2 +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/templates/workflows/blind-review-artifacts-dry-run.yml.j2 +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/templates/workflows/hosted-bridge.yml.j2 +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/templates/workflows/local-cli-audit.yml.j2 +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/templates/workflows/private-standalone-shadow.yml.j2 +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/templates/workflows/review-clear-stale.yml.j2 +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/templates/workflows/saas-reviewer-labeler.yml.j2 +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/templates/workflows/self-hosted-local-audit.yml.j2 +1 -1
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/templates/workflows/trailer-comment-labeler.yml.j2 +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/tests/test_audit_comment_posture.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/tests/test_builder_runs.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/tests/test_calibration_effect_report.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/tests/test_calibration_truth.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/tests/test_checks.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/tests/test_claude_audit_pr.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/tests/test_claude_cli_bounce.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/tests/test_clear_stale.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/tests/test_cloud_client.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/tests/test_cloud_git_metadata.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/tests/test_cloud_manifest.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/tests/test_cloud_reports.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/tests/test_coderabbit_cli_audit_pr.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/tests/test_codex_audit_env_preflight.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/tests/test_codex_audit_pr.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/tests/test_doctor_actions_cost_summary.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/tests/test_doctor_actions_failure_selection.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/tests/test_doctor_boundaries.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/tests/test_doctor_output.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/tests/test_doctor_privacy.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/tests/test_doctor_provider_env_required.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/tests/test_doctor_provider_env_tokens.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/tests/test_doctor_provider_probe.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/tests/test_doctor_provider_review_hygiene.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/tests/test_doctor_registry.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/tests/test_doctor_runtime.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/tests/test_local_llm_github_helpers.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/tests/test_plan_context.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/tests/test_provider_local_cli.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/tests/test_provider_runners_comments.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/tests/test_provider_runners_git.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/tests/test_provider_runners_github_pr.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/tests/test_provider_runners_pr_worktree.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/tests/test_provider_runners_process.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/tests/test_provider_runners_repo_paths.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/tests/test_provider_runners_text_schema.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/tests/test_provider_runners_workspace.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/tests/test_reviewer_spend.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/tests/test_trailer_comment_labeler.py +0 -0
- {code_mower-0.5.0b49 → code_mower-0.5.0b51}/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.
|
|
3
|
+
Version: 0.5.0b51
|
|
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.
|
|
106
|
+
pipx install --python python3.12 code-mower==0.5.0b51
|
|
107
107
|
code-mower --version
|
|
108
108
|
```
|
|
109
109
|
|
|
110
|
-
`0.5.
|
|
110
|
+
`0.5.0b51` 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
|
|
@@ -155,7 +155,7 @@ First-time command map: [docs/launch-command-surface.md](docs/launch-command-sur
|
|
|
155
155
|
|
|
156
156
|
The current PyPI beta has been rehearsed end-to-end from a clean install:
|
|
157
157
|
[First-User Install Rehearsal](docs/first-user-install-rehearsal.md) records
|
|
158
|
-
the latest 10/10 public-package readiness proof for `code-mower==0.5.
|
|
158
|
+
the latest 10/10 public-package readiness proof for `code-mower==0.5.0b51`.
|
|
159
159
|
|
|
160
160
|
## Optional: Plan Before Coding
|
|
161
161
|
|
|
@@ -310,9 +310,9 @@ builder provenance, start with
|
|
|
310
310
|
|
|
311
311
|
## Installation Status
|
|
312
312
|
|
|
313
|
-
The current public beta is `v0.5.0-beta.
|
|
313
|
+
The current public beta is `v0.5.0-beta.51` from
|
|
314
314
|
[codemower-ai/code-mower](https://github.com/codemower-ai/code-mower), published
|
|
315
|
-
as `code-mower==0.5.
|
|
315
|
+
as `code-mower==0.5.0b51` on [PyPI](https://pypi.org/project/code-mower/).
|
|
316
316
|
GitHub releases remain the auditable source for tags, build artifacts, and
|
|
317
317
|
release notes.
|
|
318
318
|
|
|
@@ -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.
|
|
91
|
+
pipx install --python python3.12 code-mower==0.5.0b51
|
|
92
92
|
code-mower --version
|
|
93
93
|
```
|
|
94
94
|
|
|
95
|
-
`0.5.
|
|
95
|
+
`0.5.0b51` 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
|
|
@@ -140,7 +140,7 @@ First-time command map: [docs/launch-command-surface.md](docs/launch-command-sur
|
|
|
140
140
|
|
|
141
141
|
The current PyPI beta has been rehearsed end-to-end from a clean install:
|
|
142
142
|
[First-User Install Rehearsal](docs/first-user-install-rehearsal.md) records
|
|
143
|
-
the latest 10/10 public-package readiness proof for `code-mower==0.5.
|
|
143
|
+
the latest 10/10 public-package readiness proof for `code-mower==0.5.0b51`.
|
|
144
144
|
|
|
145
145
|
## Optional: Plan Before Coding
|
|
146
146
|
|
|
@@ -295,9 +295,9 @@ builder provenance, start with
|
|
|
295
295
|
|
|
296
296
|
## Installation Status
|
|
297
297
|
|
|
298
|
-
The current public beta is `v0.5.0-beta.
|
|
298
|
+
The current public beta is `v0.5.0-beta.51` from
|
|
299
299
|
[codemower-ai/code-mower](https://github.com/codemower-ai/code-mower), published
|
|
300
|
-
as `code-mower==0.5.
|
|
300
|
+
as `code-mower==0.5.0b51` on [PyPI](https://pypi.org/project/code-mower/).
|
|
301
301
|
GitHub releases remain the auditable source for tags, build artifacts, and
|
|
302
302
|
release notes.
|
|
303
303
|
|
|
@@ -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.
|
|
17
|
+
"`pipx install code-mower==0.5.0b51`, or run source checkouts with "
|
|
18
18
|
"`PYTHONPATH=src python -m code_mower.cli`."
|
|
19
19
|
)
|
|
20
20
|
|
|
@@ -429,6 +429,15 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
429
429
|
action="store_true",
|
|
430
430
|
help="include verdict head SHA metadata",
|
|
431
431
|
)
|
|
432
|
+
reviewer_runs.add_argument(
|
|
433
|
+
"--spend",
|
|
434
|
+
type=Path,
|
|
435
|
+
default=None,
|
|
436
|
+
help=(
|
|
437
|
+
"reviewer spend ledger to merge into reviewer_run events; defaults "
|
|
438
|
+
"to .code-mower/reviewer-spend.json when present"
|
|
439
|
+
),
|
|
440
|
+
)
|
|
432
441
|
reviewer_runs.add_argument(
|
|
433
442
|
"--endpoint",
|
|
434
443
|
default=os.environ.get("CODE_MOWER_CLOUD_ENDPOINT", DEFAULT_UPLOAD_ENDPOINT),
|
|
@@ -686,6 +695,7 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
686
695
|
yes=args.yes,
|
|
687
696
|
timeout=args.timeout,
|
|
688
697
|
include_git_ref=args.include_git_ref,
|
|
698
|
+
spend_path=args.spend,
|
|
689
699
|
)
|
|
690
700
|
if args.json:
|
|
691
701
|
print(json.dumps(result, indent=2, sort_keys=True))
|
|
@@ -4,7 +4,7 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
import os
|
|
6
6
|
from pathlib import Path
|
|
7
|
-
from typing import Any
|
|
7
|
+
from typing import Any, Mapping
|
|
8
8
|
|
|
9
9
|
from .. import code_mower_telemetry
|
|
10
10
|
from .. import reviewer_spend
|
|
@@ -86,6 +86,108 @@ def build_catch_up_summary(
|
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
|
|
89
|
+
def _reviewer_spend_events(
|
|
90
|
+
*,
|
|
91
|
+
repo_path: Path,
|
|
92
|
+
spend_path: Path | None,
|
|
93
|
+
repo_slug: str,
|
|
94
|
+
team_id: str,
|
|
95
|
+
install_id: str,
|
|
96
|
+
source: str,
|
|
97
|
+
) -> list[dict[str, Any]]:
|
|
98
|
+
resolved_spend_path = spend_path or repo_path / reviewer_spend.DEFAULT_SPEND_PATH
|
|
99
|
+
if not resolved_spend_path.is_file():
|
|
100
|
+
return []
|
|
101
|
+
return reviewer_spend.spend_runs_to_events(
|
|
102
|
+
reviewer_spend.load_spend_file(resolved_spend_path),
|
|
103
|
+
repo_slug=repo_slug,
|
|
104
|
+
team_id=team_id,
|
|
105
|
+
install_id=install_id,
|
|
106
|
+
source=source,
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def _mapping(value: object) -> Mapping[str, Any]:
|
|
111
|
+
return value if isinstance(value, Mapping) else {}
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def _event_match_values(event: Mapping[str, Any]) -> tuple[str, str, str, str]:
|
|
115
|
+
dimensions = _mapping(event.get("dimensions"))
|
|
116
|
+
lane = str(
|
|
117
|
+
dimensions.get("audit_comment_lane_id")
|
|
118
|
+
or dimensions.get("lane_id")
|
|
119
|
+
or dimensions.get("lane")
|
|
120
|
+
or event.get("lens")
|
|
121
|
+
or event.get("provider")
|
|
122
|
+
or ""
|
|
123
|
+
).strip()
|
|
124
|
+
return (
|
|
125
|
+
str(event.get("repo_slug") or "").strip(),
|
|
126
|
+
str(dimensions.get("pr_number") or "").strip(),
|
|
127
|
+
lane,
|
|
128
|
+
str(dimensions.get("head_sha") or "").strip(),
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def _merge_spend_metrics(
|
|
133
|
+
event: dict[str, Any],
|
|
134
|
+
spend_event: Mapping[str, Any],
|
|
135
|
+
) -> dict[str, Any]:
|
|
136
|
+
merged = dict(event)
|
|
137
|
+
metrics = dict(_mapping(event.get("metrics")))
|
|
138
|
+
for key, value in _mapping(spend_event.get("metrics")).items():
|
|
139
|
+
metrics.setdefault(key, value)
|
|
140
|
+
dimensions = dict(_mapping(event.get("dimensions")))
|
|
141
|
+
spend_dimensions = _mapping(spend_event.get("dimensions"))
|
|
142
|
+
if spend_dimensions.get("spend_run_id"):
|
|
143
|
+
dimensions["spend_run_id"] = spend_dimensions["spend_run_id"]
|
|
144
|
+
if spend_event.get("source"):
|
|
145
|
+
dimensions["spend_source"] = spend_event["source"]
|
|
146
|
+
merged["metrics"] = metrics
|
|
147
|
+
merged["dimensions"] = dimensions
|
|
148
|
+
if not _mapping(event.get("tool")) and isinstance(spend_event.get("tool"), Mapping):
|
|
149
|
+
merged["tool"] = dict(spend_event["tool"])
|
|
150
|
+
return merged
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def _merge_reviewer_spend_events(
|
|
154
|
+
events: list[dict[str, Any]],
|
|
155
|
+
spend_events: list[dict[str, Any]],
|
|
156
|
+
) -> list[dict[str, Any]]:
|
|
157
|
+
if not spend_events:
|
|
158
|
+
return events
|
|
159
|
+
merged = list(events)
|
|
160
|
+
exact_matches: dict[tuple[str, str, str, str], int] = {}
|
|
161
|
+
fallback_matches: dict[tuple[str, str, str], int | None] = {}
|
|
162
|
+
for index, event in enumerate(merged):
|
|
163
|
+
repo_slug, pr_number, lane, head_sha = _event_match_values(event)
|
|
164
|
+
if not repo_slug or not pr_number or not lane:
|
|
165
|
+
continue
|
|
166
|
+
if head_sha:
|
|
167
|
+
exact_matches[(repo_slug, pr_number, lane, head_sha)] = index
|
|
168
|
+
fallback_key = (repo_slug, pr_number, lane)
|
|
169
|
+
fallback_matches[fallback_key] = (
|
|
170
|
+
None if fallback_key in fallback_matches else index
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
unmatched: list[dict[str, Any]] = []
|
|
174
|
+
merged_targets: set[int] = set()
|
|
175
|
+
for spend_event in spend_events:
|
|
176
|
+
repo_slug, pr_number, lane, head_sha = _event_match_values(spend_event)
|
|
177
|
+
target_index = None
|
|
178
|
+
if head_sha:
|
|
179
|
+
target_index = exact_matches.get((repo_slug, pr_number, lane, head_sha))
|
|
180
|
+
if target_index is None:
|
|
181
|
+
target_index = fallback_matches.get((repo_slug, pr_number, lane))
|
|
182
|
+
if target_index is None or target_index in merged_targets:
|
|
183
|
+
unmatched.append(spend_event)
|
|
184
|
+
continue
|
|
185
|
+
merged_targets.add(target_index)
|
|
186
|
+
merged[target_index] = _merge_spend_metrics(merged[target_index], spend_event)
|
|
187
|
+
remaining = max(0, MAX_EVENT_COUNT - len(merged))
|
|
188
|
+
return [*merged, *unmatched[:remaining]]
|
|
189
|
+
|
|
190
|
+
|
|
89
191
|
def dogfood_upload(
|
|
90
192
|
*,
|
|
91
193
|
repo_path: Path,
|
|
@@ -112,16 +214,14 @@ def dogfood_upload(
|
|
|
112
214
|
resolved_team_id = team_id or os.environ.get(DEFAULT_TEAM_ID_ENV, "")
|
|
113
215
|
resolved_install_id = install_id or os.environ.get(DEFAULT_INSTALL_ID_ENV, "")
|
|
114
216
|
resolved_reports = reports or default_dogfood_reports(repo_path)
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
source="code-mower cloud dogfood spend",
|
|
124
|
-
)
|
|
217
|
+
spend_events = _reviewer_spend_events(
|
|
218
|
+
repo_path=repo_path,
|
|
219
|
+
spend_path=spend_path,
|
|
220
|
+
repo_slug=detected_repo_slug,
|
|
221
|
+
team_id=resolved_team_id,
|
|
222
|
+
install_id=resolved_install_id,
|
|
223
|
+
source="code-mower cloud dogfood spend",
|
|
224
|
+
)
|
|
125
225
|
dogfood_plan = build_dogfood_plan(
|
|
126
226
|
repo_slug=detected_repo_slug,
|
|
127
227
|
team_id=resolved_team_id,
|
|
@@ -321,6 +421,7 @@ def reviewer_runs_upload(
|
|
|
321
421
|
yes: bool,
|
|
322
422
|
timeout: float,
|
|
323
423
|
include_git_ref: bool,
|
|
424
|
+
spend_path: Path | None = None,
|
|
324
425
|
) -> dict[str, Any]:
|
|
325
426
|
if limit < 1 or limit > MAX_EVENT_COUNT:
|
|
326
427
|
raise CloudBundleError(f"--limit must be between 1 and {MAX_EVENT_COUNT}")
|
|
@@ -344,6 +445,15 @@ def reviewer_runs_upload(
|
|
|
344
445
|
)
|
|
345
446
|
except ValueError as exc:
|
|
346
447
|
raise CloudBundleError(str(exc)) from exc
|
|
448
|
+
spend_events = _reviewer_spend_events(
|
|
449
|
+
repo_path=repo_path,
|
|
450
|
+
spend_path=spend_path,
|
|
451
|
+
repo_slug=detected_repo_slug,
|
|
452
|
+
team_id=resolved_team_id,
|
|
453
|
+
install_id=resolved_install_id,
|
|
454
|
+
source="code-mower cloud reviewer-runs spend",
|
|
455
|
+
)
|
|
456
|
+
events = _merge_reviewer_spend_events(events, spend_events)
|
|
347
457
|
if not events:
|
|
348
458
|
return {
|
|
349
459
|
"mode": "cloud-reviewer-runs",
|
|
@@ -566,6 +676,7 @@ def repo_sync_upload(
|
|
|
566
676
|
yes=yes,
|
|
567
677
|
timeout=timeout,
|
|
568
678
|
include_git_ref=include_git_ref,
|
|
679
|
+
spend_path=None,
|
|
569
680
|
)
|
|
570
681
|
else: # pragma: no cover - argparse constrains modes.
|
|
571
682
|
raise CloudBundleError(f"unsupported repo-sync mode: {mode}")
|
|
@@ -21,8 +21,15 @@ ALLOWED_LANE_TYPES = {"audit", "review"}
|
|
|
21
21
|
ALLOWED_DRIVERS = {"local_cli", "manual", "hosted_bridge", "saas_event", "api_model"}
|
|
22
22
|
ALLOWED_EVENTS = {"issue_comment", "pull_request_review", "check_run"}
|
|
23
23
|
ALLOWED_SPEND_POLICIES = {"none", "local", "included", "paid"}
|
|
24
|
-
BUILDER_IDENTITY_SECTIONS = {
|
|
24
|
+
BUILDER_IDENTITY_SECTIONS = {
|
|
25
|
+
"labels",
|
|
26
|
+
"authors",
|
|
27
|
+
"trailers",
|
|
28
|
+
"branch_prefixes",
|
|
29
|
+
"fix_round_mentions",
|
|
30
|
+
}
|
|
25
31
|
SAFE_IDENTIFIER_RE = re.compile(r"^[A-Za-z0-9][A-Za-z0-9_-]*$")
|
|
32
|
+
SAFE_ENV_NAME_RE = re.compile(r"^[A-Za-z_][A-Za-z0-9_]*$")
|
|
26
33
|
SAFE_WORKFLOW_FILENAME_RE = re.compile(r"^[A-Za-z0-9][A-Za-z0-9_-]*\.ya?ml$")
|
|
27
34
|
GENERATED_WORKFLOW_BY_DRIVER = {
|
|
28
35
|
"api_model": "trailer-comment labeler + API/model runner",
|
|
@@ -305,6 +312,21 @@ def _require_identifier(value: Any, path: str, issues: list[ConfigIssue]) -> str
|
|
|
305
312
|
return text
|
|
306
313
|
|
|
307
314
|
|
|
315
|
+
def _require_env_name(value: Any, path: str, issues: list[ConfigIssue]) -> str | None:
|
|
316
|
+
text = _require_string(value, path, issues)
|
|
317
|
+
if text is None:
|
|
318
|
+
return None
|
|
319
|
+
if not SAFE_ENV_NAME_RE.fullmatch(text):
|
|
320
|
+
issues.append(
|
|
321
|
+
ConfigIssue(
|
|
322
|
+
path,
|
|
323
|
+
"must match [A-Za-z_][A-Za-z0-9_]* for generated workflow safety",
|
|
324
|
+
)
|
|
325
|
+
)
|
|
326
|
+
return None
|
|
327
|
+
return text
|
|
328
|
+
|
|
329
|
+
|
|
308
330
|
def _require_workflow_path(value: Any, path: str, issues: list[ConfigIssue]) -> str | None:
|
|
309
331
|
text = _require_string(value, path, issues)
|
|
310
332
|
if text is None:
|
|
@@ -403,13 +425,28 @@ def validate_config(config: Mapping[str, Any]) -> list[ConfigIssue]:
|
|
|
403
425
|
section_path = f"builder_identity.{section}"
|
|
404
426
|
if section not in BUILDER_IDENTITY_SECTIONS:
|
|
405
427
|
issues.append(
|
|
406
|
-
ConfigIssue(
|
|
428
|
+
ConfigIssue(
|
|
429
|
+
section_path,
|
|
430
|
+
"must be labels, authors, trailers, branch_prefixes, or fix_round_mentions",
|
|
431
|
+
)
|
|
407
432
|
)
|
|
408
433
|
continue
|
|
434
|
+
if section == "fix_round_mentions":
|
|
435
|
+
for lane_name, mention in _as_mapping(values, section_path, issues).items():
|
|
436
|
+
_require_identifier(lane_name, f"{section_path}.{lane_name}", issues)
|
|
437
|
+
_require_string(mention, f"{section_path}.{lane_name}", issues)
|
|
438
|
+
continue
|
|
409
439
|
for key, lane_name in _as_mapping(values, section_path, issues).items():
|
|
410
440
|
_require_string(str(key), f"{section_path}.{key}", issues)
|
|
411
441
|
_require_identifier(lane_name, f"{section_path}.{key}", issues)
|
|
412
442
|
|
|
443
|
+
owner_surface = config.get("owner_surface")
|
|
444
|
+
if owner_surface is not None:
|
|
445
|
+
owner_surface_map = _as_mapping(owner_surface, "owner_surface", issues)
|
|
446
|
+
for key in ("dispatch_token_env", "dispatch_token_expires_var"):
|
|
447
|
+
if key in owner_surface_map:
|
|
448
|
+
_require_env_name(owner_surface_map.get(key), f"owner_surface.{key}", issues)
|
|
449
|
+
|
|
413
450
|
all_labels: dict[str, str] = {}
|
|
414
451
|
for lane_id, lane in lanes.items():
|
|
415
452
|
path = f"lanes.{lane_id}"
|
|
@@ -19,6 +19,11 @@ from .common import (
|
|
|
19
19
|
)
|
|
20
20
|
from .github import check_github_setup
|
|
21
21
|
from .github_config import check_repository_posture
|
|
22
|
+
from .github_human_token import (
|
|
23
|
+
check_human_automation_token,
|
|
24
|
+
human_automation_token_config,
|
|
25
|
+
human_automation_token_required,
|
|
26
|
+
)
|
|
22
27
|
from .groups import GROUP_LABELS, doctor_check_group_id
|
|
23
28
|
from .models import (
|
|
24
29
|
STATUS_FAIL,
|
|
@@ -86,6 +91,7 @@ __all__ = [
|
|
|
86
91
|
"check_github_auth_surface",
|
|
87
92
|
"check_macos_runner_launchagent",
|
|
88
93
|
"check_github_setup",
|
|
94
|
+
"check_human_automation_token",
|
|
89
95
|
"check_repository_posture",
|
|
90
96
|
"check_lane_runtime",
|
|
91
97
|
"check_review_hygiene",
|
|
@@ -97,6 +103,8 @@ __all__ = [
|
|
|
97
103
|
"doctor_output_group",
|
|
98
104
|
"effective_lane",
|
|
99
105
|
"evaluate_json_probe",
|
|
106
|
+
"human_automation_token_config",
|
|
107
|
+
"human_automation_token_required",
|
|
100
108
|
"load_inputs",
|
|
101
109
|
"local_cli_probe_remediation",
|
|
102
110
|
"provider_template_coverage",
|
|
@@ -18,6 +18,7 @@ from .github_actions import (
|
|
|
18
18
|
from .github_actions_permissions import check_actions_permissions
|
|
19
19
|
from .github_branch import check_branch_protection
|
|
20
20
|
from .github_config import configured_repositories, selected_saas_or_hosted_lanes
|
|
21
|
+
from .github_human_token import check_human_automation_token
|
|
21
22
|
from .github_provider import check_private_repo_provider_surface
|
|
22
23
|
from .github_repo import (
|
|
23
24
|
check_repo_auto_merge,
|
|
@@ -124,6 +125,15 @@ def check_github_setup(
|
|
|
124
125
|
),
|
|
125
126
|
]
|
|
126
127
|
)
|
|
128
|
+
checks.append(
|
|
129
|
+
check_human_automation_token(
|
|
130
|
+
gh_path=gh_path,
|
|
131
|
+
slug=slug,
|
|
132
|
+
config=config,
|
|
133
|
+
lanes=lanes,
|
|
134
|
+
http_timeout=http_timeout,
|
|
135
|
+
)
|
|
136
|
+
)
|
|
127
137
|
if has_merge_authority:
|
|
128
138
|
checks.append(
|
|
129
139
|
check_repo_auto_merge(slug=slug, repo_payload=metadata.payload)
|
|
@@ -8,6 +8,8 @@ from typing import Mapping
|
|
|
8
8
|
from .common import DoctorCheck, STATUS_PASS, STATUS_WARN
|
|
9
9
|
from .github_api import _github_api_json
|
|
10
10
|
|
|
11
|
+
GITHUB_ACTIONS_APP_ID = 15368
|
|
12
|
+
|
|
11
13
|
|
|
12
14
|
def check_branch_protection(
|
|
13
15
|
*,
|
|
@@ -41,6 +43,7 @@ def check_branch_protection(
|
|
|
41
43
|
|
|
42
44
|
required_checks = protection_payload.get("required_status_checks")
|
|
43
45
|
contexts: list[str] = []
|
|
46
|
+
check_bindings: list[dict[str, object]] = []
|
|
44
47
|
if isinstance(required_checks, Mapping):
|
|
45
48
|
raw_contexts = required_checks.get("contexts")
|
|
46
49
|
if isinstance(raw_contexts, list):
|
|
@@ -49,8 +52,42 @@ def check_branch_protection(
|
|
|
49
52
|
if isinstance(raw_checks, list):
|
|
50
53
|
for check in raw_checks:
|
|
51
54
|
if isinstance(check, Mapping) and check.get("context"):
|
|
52
|
-
|
|
55
|
+
context = str(check["context"])
|
|
56
|
+
contexts.append(context)
|
|
57
|
+
check_bindings.append(
|
|
58
|
+
{"context": context, "app_id": check.get("app_id")}
|
|
59
|
+
)
|
|
53
60
|
contexts = list(dict.fromkeys(contexts))
|
|
61
|
+
wrong_gate_bindings = [
|
|
62
|
+
binding
|
|
63
|
+
for binding in check_bindings
|
|
64
|
+
if binding.get("context") == required_status_context
|
|
65
|
+
and binding.get("app_id") == GITHUB_ACTIONS_APP_ID
|
|
66
|
+
]
|
|
67
|
+
if required_status_context and wrong_gate_bindings:
|
|
68
|
+
return DoctorCheck(
|
|
69
|
+
name="github.branch_protection",
|
|
70
|
+
status=STATUS_WARN,
|
|
71
|
+
message=(
|
|
72
|
+
f"{slug}@{default_branch} requires {required_status_context} "
|
|
73
|
+
"from GitHub Actions instead of Any source"
|
|
74
|
+
),
|
|
75
|
+
detail={
|
|
76
|
+
"repo": slug,
|
|
77
|
+
"default_branch": default_branch,
|
|
78
|
+
"required_status_context": required_status_context,
|
|
79
|
+
"required_status_contexts": contexts,
|
|
80
|
+
"required_status_check_count": len(contexts),
|
|
81
|
+
"required_status_check_bindings": check_bindings,
|
|
82
|
+
},
|
|
83
|
+
remediation=(
|
|
84
|
+
f"Rebind `{required_status_context}` in branch protection to "
|
|
85
|
+
"Any source, not GitHub Actions. In the API response, the "
|
|
86
|
+
f"`checks[]` entry for `{required_status_context}` should have "
|
|
87
|
+
"`app_id: null`; `app_id: 15368` means GitHub is evaluating "
|
|
88
|
+
"the Actions job check-run instead of the Code Mower commit status."
|
|
89
|
+
),
|
|
90
|
+
)
|
|
54
91
|
if required_status_context and required_status_context not in contexts:
|
|
55
92
|
return DoctorCheck(
|
|
56
93
|
name="github.branch_protection",
|
|
@@ -70,7 +107,7 @@ def check_branch_protection(
|
|
|
70
107
|
"unattended merge. Inspect existing checks with "
|
|
71
108
|
f"`gh api repos/{slug}/branches/{encoded_branch}/protection/required_status_checks`, "
|
|
72
109
|
"then PATCH that endpoint with all existing contexts plus "
|
|
73
|
-
f"`{required_status_context}
|
|
110
|
+
f"`{required_status_context}` from Any source."
|
|
74
111
|
),
|
|
75
112
|
)
|
|
76
113
|
return DoctorCheck(
|
|
@@ -86,5 +123,6 @@ def check_branch_protection(
|
|
|
86
123
|
"default_branch": default_branch,
|
|
87
124
|
"required_status_check_count": len(contexts),
|
|
88
125
|
"required_status_contexts": contexts,
|
|
126
|
+
"required_status_check_bindings": check_bindings,
|
|
89
127
|
},
|
|
90
128
|
)
|