code-mower 0.5.0b50__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.0b50 → code_mower-0.5.0b51}/PKG-INFO +6 -6
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/README.md +5 -5
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/pyproject.toml +1 -1
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/__init__.py +1 -1
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/cli.py +1 -1
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/github_branch.py +40 -2
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/init.py +12 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51/src/code_mower}/templates/workflows/builder-provenance.yml.j2 +1 -1
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/templates/workflows/code-mower-agent-pr-labeler.yml.j2 +34 -1
- {code_mower-0.5.0b50 → code_mower-0.5.0b51/src/code_mower}/templates/workflows/code-mower-fix-round-dispatch.yml.j2 +44 -2
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/templates/workflows/code-mower-gate.yml.j2 +3 -1
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower.egg-info/PKG-INFO +6 -6
- {code_mower-0.5.0b50/src/code_mower → code_mower-0.5.0b51}/templates/workflows/builder-provenance.yml.j2 +1 -1
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/templates/workflows/code-mower-agent-pr-labeler.yml.j2 +34 -1
- {code_mower-0.5.0b50/src/code_mower → code_mower-0.5.0b51}/templates/workflows/code-mower-fix-round-dispatch.yml.j2 +44 -2
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/templates/workflows/code-mower-gate.yml.j2 +3 -1
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/tests/test_doctor_github_checks.py +35 -2
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/tests/test_release_hygiene.py +50 -35
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/CODE_OF_CONDUCT.md +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/LICENSE +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/MANIFEST.in +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/NOTICE +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/SUPPORT.md +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/requirements/requirements.txt +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/setup.cfg +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/adapters/__init__.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/adapters/_base.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/adapters/cursor_bugbot.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/adapters/gitar.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/adapters/greptile.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/adapters/qodo.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/antigravity_cli_audit_pr.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/audit_handoff_log.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/audit_labeler_lib.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/audit_progress.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/blind_review_artifacts.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/blind_review_coordinator.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/bootstrap.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/builder_experiment.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/builder_runs.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/calibration/__init__.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/calibration/arms.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/calibration/auto_discovery.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/calibration/commands.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/calibration/context_inputs.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/calibration/corpus.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/calibration/effect_report.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/calibration/evidence.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/calibration/evidence_report.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/calibration/identity.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/calibration/metrics.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/calibration/overlap.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/calibration/planning.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/calibration/policy.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/calibration/results.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/calibration/run_results.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/calibration/run_status.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/calibration/runner.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/calibration/truth.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/calibration/value_report.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/checks.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/claude_audit_pr.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/claude_cli_bounce.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/claude_cli_environment.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/clear_stale.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/cloud.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/cloud_client/__init__.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/cloud_client/bundle.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/cloud_client/doctor.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/cloud_client/dogfood.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/cloud_client/endpoints.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/cloud_client/errors.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/cloud_client/events.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/cloud_client/export.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/cloud_client/git_metadata.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/cloud_client/manifest.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/cloud_client/operations.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/cloud_client/reports.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/cloud_client/setup.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/cloud_client/upload.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/code_mower_calibration.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/code_mower_context_packs.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/code_mower_merge.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/code_mower_telemetry.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/coderabbit_cli_audit_pr.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/codex_audit_env_preflight.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/codex_audit_pr.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/codex_audit_schema_smoke.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/codex_audit_verdict.schema.json +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/config.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/doctor.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/__init__.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/cloud.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/common.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/github.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/github_actions.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/github_actions_cost.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/github_actions_cost_summary.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/github_actions_failure_annotations.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/github_actions_failure_models.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/github_actions_failure_scan.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/github_actions_failure_selection.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/github_actions_failures.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/github_actions_permissions.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/github_api.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/github_config.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/github_human_token.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/github_provider.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/github_repo.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/groups.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/models.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/output.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/presets.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/privacy.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/provider_api_model.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/provider_api_model_openai.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/provider_api_model_profiles.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/provider_env.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/provider_env_required.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/provider_env_tokens.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/provider_local_cli.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/provider_local_cli_commands.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/provider_local_cli_probe_config.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/provider_probe.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/provider_probe_auth.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/provider_probe_evaluation.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/provider_probe_json.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/provider_probe_remediation.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/provider_review_hygiene.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/providers.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/registry.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/runner.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/runtime.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/doctor_checks/runtime_github_auth.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/gate_health.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/gemini_cli_audit_pr.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/grok_build_audit_pr.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/hermes_cli_audit_pr.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/lane_configs/__init__.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/lane_configs/aider.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/lane_configs/antigravity_cli.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/lane_configs/claude.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/lane_configs/codex.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/lane_configs/devin.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/lane_configs/gemini_cli.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/lane_configs/grok_build.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/lane_configs/hermes_cli.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/lane_configs/local_llm.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/local_llm_audit_pr.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/local_llm_bakeoff.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/local_llm_calibration.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/local_llm_profiles.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/migration.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/migration_install.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/migration_mirror.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/migration_readiness.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/migration_rehearsal.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/next_steps.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/package.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/package_content.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/package_manifest.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/package_paths.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/package_rendering.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/package_static.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/plan_context.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/prompts.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/provider_registry.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/provider_runners/__init__.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/provider_runners/comments.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/provider_runners/git.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/provider_runners/github_auth.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/provider_runners/github_pr.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/provider_runners/pr_worktree.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/provider_runners/process.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/provider_runners/repo_paths.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/provider_runners/text_schema.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/provider_runners/verdict_artifacts.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/provider_runners/workspace.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/providers/__init__.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/providers/local_cli.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/providers/provenance.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/release_readiness.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/reviewer_metrics.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/reviewer_spend.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/saas_reviewer_labeler.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/secrets.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/templates/builder-experiment.example.json +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/templates/calibration-corpus.example.json +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/templates/calibration-corpus.json +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/templates/code-mower.example.yml +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/templates/context-packs.example.json +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/templates/lane_prompts/base-audit.md +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/templates/lane_prompts/calibration-policy.md +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/templates/lane_prompts/context-driven-quality.md +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/templates/lane_prompts/docs-design.md +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/templates/lane_prompts/generic-programming.md +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/templates/lane_prompts/operability.md +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/templates/lane_prompts/package-runtime.md +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/templates/lane_prompts/plan-conformance.md +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/templates/lane_prompts/security-threat-model.md +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/templates/product-support/code_mower +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/templates/product-support/code_mower_standalone_pin.env +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/templates/product-support/code_mower_standalone_shadow.sh +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/templates/product-support/run_claude_audit_pr.sh +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/templates/product-support/run_codex_audit_pr.sh +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/templates/product-support/safe_gh_comment.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/templates/product-support/status_report.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/templates/providers.yml +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/templates/reviewer-spend.example.json +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/templates/reviewer-value-report.example.md +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/templates/workflows/audit-label-cleanup.yml.j2 +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/templates/workflows/code-mower-gate-health.yml.j2 +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/templates/workflows/hosted-bridge.yml.j2 +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/templates/workflows/local-cli-audit.yml.j2 +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/templates/workflows/needs-owner-notify.yml.j2 +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/templates/workflows/private-standalone-shadow.yml.j2 +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/templates/workflows/review-clear-stale.yml.j2 +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/templates/workflows/saas-reviewer-labeler.yml.j2 +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/templates/workflows/self-hosted-local-audit.yml.j2 +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/templates/workflows/trailer-comment-labeler.yml.j2 +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/templates/workflows/weekly-status.yml.j2 +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/trailer_comment_labeler.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/versioning.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower/work_orders.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower.egg-info/SOURCES.txt +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower.egg-info/dependency_links.txt +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower.egg-info/entry_points.txt +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower.egg-info/requires.txt +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/src/code_mower.egg-info/top_level.txt +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/templates/builder-experiment.example.json +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/templates/calibration-corpus.example.json +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/templates/calibration-corpus.json +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/templates/code-mower.yml.j2 +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/templates/context-packs.example.json +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/templates/cursor/BUGBOT.md +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/templates/providers/acp_bridge.yml +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/templates/providers/aider.yml +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/templates/providers/antigravity_cli.yml +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/templates/providers/claude_audit.yml +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/templates/providers/claude_review.yml +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/templates/providers/coderabbit_cli.yml +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/templates/providers/codex.yml +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/templates/providers/cursor_bugbot.yml +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/templates/providers/devin.yml +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/templates/providers/gemini_cli.yml +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/templates/providers/gitar.yml +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/templates/providers/greptile.yml +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/templates/providers/hermes_cli.yml +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/templates/providers/local_llm.yml +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/templates/providers/qodo.yml +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/templates/providers.yml +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/templates/reviewer-spend.example.json +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/templates/reviewer-value-report.example.md +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/templates/workflows/audit-label-cleanup.yml.j2 +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/templates/workflows/blind-review-artifacts-dry-run.yml.j2 +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/templates/workflows/code-mower-gate-health.yml.j2 +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/templates/workflows/hosted-bridge.yml.j2 +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/templates/workflows/local-cli-audit.yml.j2 +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/templates/workflows/private-standalone-shadow.yml.j2 +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/templates/workflows/review-clear-stale.yml.j2 +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/templates/workflows/saas-reviewer-labeler.yml.j2 +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/templates/workflows/self-hosted-local-audit.yml.j2 +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/templates/workflows/trailer-comment-labeler.yml.j2 +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/tests/test_audit_comment_posture.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/tests/test_builder_identity.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/tests/test_builder_runs.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/tests/test_calibration_effect_report.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/tests/test_calibration_truth.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/tests/test_checks.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/tests/test_claude_audit_pr.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/tests/test_claude_cli_bounce.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/tests/test_clear_stale.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/tests/test_cloud_client.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/tests/test_cloud_git_metadata.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/tests/test_cloud_manifest.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/tests/test_cloud_reports.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/tests/test_coderabbit_cli_audit_pr.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/tests/test_codex_audit_env_preflight.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/tests/test_codex_audit_pr.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/tests/test_doctor_actions_cost_summary.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/tests/test_doctor_actions_failure_selection.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/tests/test_doctor_boundaries.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/tests/test_doctor_output.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/tests/test_doctor_privacy.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/tests/test_doctor_provider_env_required.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/tests/test_doctor_provider_env_tokens.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/tests/test_doctor_provider_probe.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/tests/test_doctor_provider_review_hygiene.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/tests/test_doctor_registry.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/tests/test_doctor_runtime.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/tests/test_gate_health.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/tests/test_local_llm_github_helpers.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/tests/test_plan_context.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/tests/test_prompts.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/tests/test_provider_local_cli.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/tests/test_provider_runners_comments.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/tests/test_provider_runners_git.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/tests/test_provider_runners_github_pr.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/tests/test_provider_runners_pr_worktree.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/tests/test_provider_runners_process.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/tests/test_provider_runners_repo_paths.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/tests/test_provider_runners_text_schema.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/tests/test_provider_runners_workspace.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/tests/test_reviewer_metrics_core.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/tests/test_reviewer_spend.py +0 -0
- {code_mower-0.5.0b50 → code_mower-0.5.0b51}/tests/test_trailer_comment_labeler.py +0 -0
- {code_mower-0.5.0b50 → 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
|
|
|
@@ -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
|
)
|
|
@@ -1828,6 +1828,18 @@ def render_init_plan(
|
|
|
1828
1828
|
lines.extend(["", "Additional repository targets from --add-repo:"])
|
|
1829
1829
|
lines.extend(f"- {slug}" for slug in add_repositories)
|
|
1830
1830
|
|
|
1831
|
+
if merge_authority_lanes:
|
|
1832
|
+
lines.extend(
|
|
1833
|
+
[
|
|
1834
|
+
"",
|
|
1835
|
+
"Branch protection:",
|
|
1836
|
+
"- require `code-mower/gate` from Any source "
|
|
1837
|
+
"(API checks[].app_id: null), not GitHub Actions "
|
|
1838
|
+
"(app_id: 15368)",
|
|
1839
|
+
"- inspect: gh api repos/OWNER/REPO/branches/main/protection/required_status_checks",
|
|
1840
|
+
]
|
|
1841
|
+
)
|
|
1842
|
+
|
|
1831
1843
|
lines.extend(["", "Required secrets/PAT fallbacks:"])
|
|
1832
1844
|
if data["required_secrets"]:
|
|
1833
1845
|
lines.extend(f"- {secret}" for secret in data["required_secrets"])
|
|
@@ -88,6 +88,32 @@ jobs:
|
|
|
88
88
|
echo "::error::${CODE_MOWER_DISPATCH_TOKEN_ENV} secret is missing; labels must be applied by a human-owned token so audit workflows trigger"
|
|
89
89
|
exit 1
|
|
90
90
|
fi
|
|
91
|
+
code_mower_handle_rate_limit() {
|
|
92
|
+
rate_limited=false
|
|
93
|
+
for file in "$@"; do
|
|
94
|
+
if [ -s "${file}" ] && grep -qiE 'API rate limit exceeded|rate limit' "${file}"; then
|
|
95
|
+
rate_limited=true
|
|
96
|
+
fi
|
|
97
|
+
done
|
|
98
|
+
[ "${rate_limited}" = "true" ] || return 1
|
|
99
|
+
|
|
100
|
+
reset_epoch="$(gh api rate_limit --jq '.resources.core.reset // .rate.reset // ""' 2>/dev/null || true)"
|
|
101
|
+
if [[ "${reset_epoch}" =~ ^[0-9]+$ ]]; then
|
|
102
|
+
now_epoch="$(date -u +%s)"
|
|
103
|
+
wait_seconds=$((reset_epoch - now_epoch + 5))
|
|
104
|
+
reset_iso="$(date -u -d "@${reset_epoch}" "+%Y-%m-%dT%H:%M:%SZ" 2>/dev/null || echo "${reset_epoch}")"
|
|
105
|
+
if [ "${wait_seconds}" -gt 0 ] && [ "${wait_seconds}" -le 240 ]; then
|
|
106
|
+
echo "::notice::GitHub API rate limit hit; backing off until ${reset_iso}."
|
|
107
|
+
sleep "${wait_seconds}"
|
|
108
|
+
else
|
|
109
|
+
echo "::notice::GitHub API rate limit hit; reset at ${reset_iso}; exiting cleanly so a later event can retry."
|
|
110
|
+
fi
|
|
111
|
+
else
|
|
112
|
+
echo "::notice::GitHub API rate limit hit; reset time unavailable; exiting cleanly so a later event can retry."
|
|
113
|
+
fi
|
|
114
|
+
return 0
|
|
115
|
+
}
|
|
116
|
+
|
|
91
117
|
mapfile -t remove_labels < .code-mower-agent-remove-labels.txt
|
|
92
118
|
mapfile -t add_labels < .code-mower-agent-add-labels.txt
|
|
93
119
|
remove_args=()
|
|
@@ -101,5 +127,12 @@ jobs:
|
|
|
101
127
|
for label in "${add_labels[@]}"; do
|
|
102
128
|
[ -n "${label}" ] && add_args+=(--add-label "${label}")
|
|
103
129
|
done
|
|
104
|
-
|
|
130
|
+
label_error="$(mktemp)"
|
|
131
|
+
if ! gh pr edit "${PR_NUMBER}" --repo "${GITHUB_REPOSITORY}" "${add_args[@]}" 2>"${label_error}"; then
|
|
132
|
+
if code_mower_handle_rate_limit "${label_error}"; then
|
|
133
|
+
exit 0
|
|
134
|
+
fi
|
|
135
|
+
cat "${label_error}" >&2
|
|
136
|
+
exit 1
|
|
137
|
+
fi
|
|
105
138
|
printf '#%s (%s): %s\n' "${PR_NUMBER}" "${PR_ACTION}" "$(paste -sd ', ' .code-mower-agent-add-labels.txt)"
|
|
@@ -97,7 +97,42 @@ jobs:
|
|
|
97
97
|
echo "::error::${CODE_MOWER_DISPATCH_TOKEN_ENV} secret is missing or empty; fix-round mentions must be posted by a human-owned token"
|
|
98
98
|
exit 1
|
|
99
99
|
fi
|
|
100
|
-
|
|
100
|
+
code_mower_handle_rate_limit() {
|
|
101
|
+
rate_limited=false
|
|
102
|
+
for file in "$@"; do
|
|
103
|
+
if [ -s "${file}" ] && grep -qiE 'API rate limit exceeded|rate limit' "${file}"; then
|
|
104
|
+
rate_limited=true
|
|
105
|
+
fi
|
|
106
|
+
done
|
|
107
|
+
[ "${rate_limited}" = "true" ] || return 1
|
|
108
|
+
|
|
109
|
+
reset_epoch="$(gh api rate_limit --jq '.resources.core.reset // .rate.reset // ""' 2>/dev/null || true)"
|
|
110
|
+
if [[ "${reset_epoch}" =~ ^[0-9]+$ ]]; then
|
|
111
|
+
now_epoch="$(date -u +%s)"
|
|
112
|
+
wait_seconds=$((reset_epoch - now_epoch + 5))
|
|
113
|
+
reset_iso="$(date -u -d "@${reset_epoch}" "+%Y-%m-%dT%H:%M:%SZ" 2>/dev/null || echo "${reset_epoch}")"
|
|
114
|
+
if [ "${wait_seconds}" -gt 0 ] && [ "${wait_seconds}" -le 240 ]; then
|
|
115
|
+
echo "::notice::GitHub API rate limit hit; backing off until ${reset_iso}."
|
|
116
|
+
sleep "${wait_seconds}"
|
|
117
|
+
else
|
|
118
|
+
echo "::notice::GitHub API rate limit hit; reset at ${reset_iso}; exiting cleanly so a later event can retry."
|
|
119
|
+
fi
|
|
120
|
+
else
|
|
121
|
+
echo "::notice::GitHub API rate limit hit; reset time unavailable; exiting cleanly so a later event can retry."
|
|
122
|
+
fi
|
|
123
|
+
return 0
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
comments_output="$(mktemp)"
|
|
127
|
+
comments_error="$(mktemp)"
|
|
128
|
+
if ! gh api "repos/${GITHUB_REPOSITORY}/issues/${PR_NUMBER}/comments" --paginate -q '.[].body' >"${comments_output}" 2>"${comments_error}"; then
|
|
129
|
+
if code_mower_handle_rate_limit "${comments_error}" "${comments_output}"; then
|
|
130
|
+
exit 0
|
|
131
|
+
fi
|
|
132
|
+
cat "${comments_error}" >&2
|
|
133
|
+
exit 1
|
|
134
|
+
fi
|
|
135
|
+
bodies="$(cat "${comments_output}")"
|
|
101
136
|
if printf '%s' "${bodies}" | grep -qF -- "${MARKER}"; then
|
|
102
137
|
echo "fix round already dispatched for ${HEAD_SHA} (${AUDIT_LANE}/${BUILDER_LANE})"
|
|
103
138
|
exit 0
|
|
@@ -107,5 +142,12 @@ jobs:
|
|
|
107
142
|
body="${FIX_ROUND_MENTION} The **${AUDIT_LANE}** audit lane BLOCKED this PR (head ${short_sha}). Read the latest Code Mower audit comments on this PR, address every blocking finding without scope additions, push to this branch, then re-add: \`${needs_labels}\`. If a finding is wrong, reply with evidence and add \`${NEEDS_OWNER_LABEL}\`.
|
|
108
143
|
|
|
109
144
|
${MARKER}"
|
|
110
|
-
|
|
145
|
+
comment_error="$(mktemp)"
|
|
146
|
+
if ! gh pr comment "${PR_NUMBER}" --repo "${GITHUB_REPOSITORY}" --body "${body}" 2>"${comment_error}"; then
|
|
147
|
+
if code_mower_handle_rate_limit "${comment_error}"; then
|
|
148
|
+
exit 0
|
|
149
|
+
fi
|
|
150
|
+
cat "${comment_error}" >&2
|
|
151
|
+
exit 1
|
|
152
|
+
fi
|
|
111
153
|
echo "dispatched fix round for #${PR_NUMBER} (${AUDIT_LANE}/${BUILDER_LANE}, ${short_sha})"
|
|
@@ -38,7 +38,7 @@ env:
|
|
|
38
38
|
|
|
39
39
|
jobs:
|
|
40
40
|
gate:
|
|
41
|
-
name:
|
|
41
|
+
name: publish Code Mower gate status
|
|
42
42
|
runs-on: ubuntu-latest
|
|
43
43
|
timeout-minutes: 5
|
|
44
44
|
steps:
|
|
@@ -590,6 +590,8 @@ __GATE_AUTHOR_ENV_ASSIGNMENTS__
|
|
|
590
590
|
|
|
591
591
|
echo "Code Mower gate: ${gate_state} - ${gate_description}"
|
|
592
592
|
|
|
593
|
+
# The merge signal is the commit status above. Keep expected
|
|
594
|
+
# pending/failure verdicts from creating a second required check-run.
|
|
593
595
|
if [ "${gate_state}" != "success" ] || [ "${CODE_MOWER_GATE_ENABLE_AUTO_MERGE}" != "true" ]; then
|
|
594
596
|
exit 0
|
|
595
597
|
fi
|
|
@@ -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
|
|
{code_mower-0.5.0b50 → code_mower-0.5.0b51}/templates/workflows/code-mower-agent-pr-labeler.yml.j2
RENAMED
|
@@ -88,6 +88,32 @@ jobs:
|
|
|
88
88
|
echo "::error::${CODE_MOWER_DISPATCH_TOKEN_ENV} secret is missing; labels must be applied by a human-owned token so audit workflows trigger"
|
|
89
89
|
exit 1
|
|
90
90
|
fi
|
|
91
|
+
code_mower_handle_rate_limit() {
|
|
92
|
+
rate_limited=false
|
|
93
|
+
for file in "$@"; do
|
|
94
|
+
if [ -s "${file}" ] && grep -qiE 'API rate limit exceeded|rate limit' "${file}"; then
|
|
95
|
+
rate_limited=true
|
|
96
|
+
fi
|
|
97
|
+
done
|
|
98
|
+
[ "${rate_limited}" = "true" ] || return 1
|
|
99
|
+
|
|
100
|
+
reset_epoch="$(gh api rate_limit --jq '.resources.core.reset // .rate.reset // ""' 2>/dev/null || true)"
|
|
101
|
+
if [[ "${reset_epoch}" =~ ^[0-9]+$ ]]; then
|
|
102
|
+
now_epoch="$(date -u +%s)"
|
|
103
|
+
wait_seconds=$((reset_epoch - now_epoch + 5))
|
|
104
|
+
reset_iso="$(date -u -d "@${reset_epoch}" "+%Y-%m-%dT%H:%M:%SZ" 2>/dev/null || echo "${reset_epoch}")"
|
|
105
|
+
if [ "${wait_seconds}" -gt 0 ] && [ "${wait_seconds}" -le 240 ]; then
|
|
106
|
+
echo "::notice::GitHub API rate limit hit; backing off until ${reset_iso}."
|
|
107
|
+
sleep "${wait_seconds}"
|
|
108
|
+
else
|
|
109
|
+
echo "::notice::GitHub API rate limit hit; reset at ${reset_iso}; exiting cleanly so a later event can retry."
|
|
110
|
+
fi
|
|
111
|
+
else
|
|
112
|
+
echo "::notice::GitHub API rate limit hit; reset time unavailable; exiting cleanly so a later event can retry."
|
|
113
|
+
fi
|
|
114
|
+
return 0
|
|
115
|
+
}
|
|
116
|
+
|
|
91
117
|
mapfile -t remove_labels < .code-mower-agent-remove-labels.txt
|
|
92
118
|
mapfile -t add_labels < .code-mower-agent-add-labels.txt
|
|
93
119
|
remove_args=()
|
|
@@ -101,5 +127,12 @@ jobs:
|
|
|
101
127
|
for label in "${add_labels[@]}"; do
|
|
102
128
|
[ -n "${label}" ] && add_args+=(--add-label "${label}")
|
|
103
129
|
done
|
|
104
|
-
|
|
130
|
+
label_error="$(mktemp)"
|
|
131
|
+
if ! gh pr edit "${PR_NUMBER}" --repo "${GITHUB_REPOSITORY}" "${add_args[@]}" 2>"${label_error}"; then
|
|
132
|
+
if code_mower_handle_rate_limit "${label_error}"; then
|
|
133
|
+
exit 0
|
|
134
|
+
fi
|
|
135
|
+
cat "${label_error}" >&2
|
|
136
|
+
exit 1
|
|
137
|
+
fi
|
|
105
138
|
printf '#%s (%s): %s\n' "${PR_NUMBER}" "${PR_ACTION}" "$(paste -sd ', ' .code-mower-agent-add-labels.txt)"
|
|
@@ -97,7 +97,42 @@ jobs:
|
|
|
97
97
|
echo "::error::${CODE_MOWER_DISPATCH_TOKEN_ENV} secret is missing or empty; fix-round mentions must be posted by a human-owned token"
|
|
98
98
|
exit 1
|
|
99
99
|
fi
|
|
100
|
-
|
|
100
|
+
code_mower_handle_rate_limit() {
|
|
101
|
+
rate_limited=false
|
|
102
|
+
for file in "$@"; do
|
|
103
|
+
if [ -s "${file}" ] && grep -qiE 'API rate limit exceeded|rate limit' "${file}"; then
|
|
104
|
+
rate_limited=true
|
|
105
|
+
fi
|
|
106
|
+
done
|
|
107
|
+
[ "${rate_limited}" = "true" ] || return 1
|
|
108
|
+
|
|
109
|
+
reset_epoch="$(gh api rate_limit --jq '.resources.core.reset // .rate.reset // ""' 2>/dev/null || true)"
|
|
110
|
+
if [[ "${reset_epoch}" =~ ^[0-9]+$ ]]; then
|
|
111
|
+
now_epoch="$(date -u +%s)"
|
|
112
|
+
wait_seconds=$((reset_epoch - now_epoch + 5))
|
|
113
|
+
reset_iso="$(date -u -d "@${reset_epoch}" "+%Y-%m-%dT%H:%M:%SZ" 2>/dev/null || echo "${reset_epoch}")"
|
|
114
|
+
if [ "${wait_seconds}" -gt 0 ] && [ "${wait_seconds}" -le 240 ]; then
|
|
115
|
+
echo "::notice::GitHub API rate limit hit; backing off until ${reset_iso}."
|
|
116
|
+
sleep "${wait_seconds}"
|
|
117
|
+
else
|
|
118
|
+
echo "::notice::GitHub API rate limit hit; reset at ${reset_iso}; exiting cleanly so a later event can retry."
|
|
119
|
+
fi
|
|
120
|
+
else
|
|
121
|
+
echo "::notice::GitHub API rate limit hit; reset time unavailable; exiting cleanly so a later event can retry."
|
|
122
|
+
fi
|
|
123
|
+
return 0
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
comments_output="$(mktemp)"
|
|
127
|
+
comments_error="$(mktemp)"
|
|
128
|
+
if ! gh api "repos/${GITHUB_REPOSITORY}/issues/${PR_NUMBER}/comments" --paginate -q '.[].body' >"${comments_output}" 2>"${comments_error}"; then
|
|
129
|
+
if code_mower_handle_rate_limit "${comments_error}" "${comments_output}"; then
|
|
130
|
+
exit 0
|
|
131
|
+
fi
|
|
132
|
+
cat "${comments_error}" >&2
|
|
133
|
+
exit 1
|
|
134
|
+
fi
|
|
135
|
+
bodies="$(cat "${comments_output}")"
|
|
101
136
|
if printf '%s' "${bodies}" | grep -qF -- "${MARKER}"; then
|
|
102
137
|
echo "fix round already dispatched for ${HEAD_SHA} (${AUDIT_LANE}/${BUILDER_LANE})"
|
|
103
138
|
exit 0
|
|
@@ -107,5 +142,12 @@ jobs:
|
|
|
107
142
|
body="${FIX_ROUND_MENTION} The **${AUDIT_LANE}** audit lane BLOCKED this PR (head ${short_sha}). Read the latest Code Mower audit comments on this PR, address every blocking finding without scope additions, push to this branch, then re-add: \`${needs_labels}\`. If a finding is wrong, reply with evidence and add \`${NEEDS_OWNER_LABEL}\`.
|
|
108
143
|
|
|
109
144
|
${MARKER}"
|
|
110
|
-
|
|
145
|
+
comment_error="$(mktemp)"
|
|
146
|
+
if ! gh pr comment "${PR_NUMBER}" --repo "${GITHUB_REPOSITORY}" --body "${body}" 2>"${comment_error}"; then
|
|
147
|
+
if code_mower_handle_rate_limit "${comment_error}"; then
|
|
148
|
+
exit 0
|
|
149
|
+
fi
|
|
150
|
+
cat "${comment_error}" >&2
|
|
151
|
+
exit 1
|
|
152
|
+
fi
|
|
111
153
|
echo "dispatched fix round for #${PR_NUMBER} (${AUDIT_LANE}/${BUILDER_LANE}, ${short_sha})"
|
|
@@ -38,7 +38,7 @@ env:
|
|
|
38
38
|
|
|
39
39
|
jobs:
|
|
40
40
|
gate:
|
|
41
|
-
name:
|
|
41
|
+
name: publish Code Mower gate status
|
|
42
42
|
runs-on: ubuntu-latest
|
|
43
43
|
timeout-minutes: 5
|
|
44
44
|
steps:
|
|
@@ -590,6 +590,8 @@ __GATE_AUTHOR_ENV_ASSIGNMENTS__
|
|
|
590
590
|
|
|
591
591
|
echo "Code Mower gate: ${gate_state} - ${gate_description}"
|
|
592
592
|
|
|
593
|
+
# The merge signal is the commit status above. Keep expected
|
|
594
|
+
# pending/failure verdicts from creating a second required check-run.
|
|
593
595
|
if [ "${gate_state}" != "success" ] || [ "${CODE_MOWER_GATE_ENABLE_AUTO_MERGE}" != "true" ]; then
|
|
594
596
|
exit 0
|
|
595
597
|
fi
|
|
@@ -368,14 +368,14 @@ class GitHubDoctorCheckTests(unittest.TestCase):
|
|
|
368
368
|
self.assertIn("code-mower/gate", check.message)
|
|
369
369
|
self.assertEqual(check.detail["required_status_context"], "code-mower/gate")
|
|
370
370
|
|
|
371
|
-
def
|
|
371
|
+
def test_branch_protection_accepts_any_source_gate_status_binding(self) -> None:
|
|
372
372
|
with mock.patch(
|
|
373
373
|
"code_mower.doctor_checks.github_branch._github_api_json",
|
|
374
374
|
return_value=(
|
|
375
375
|
{
|
|
376
376
|
"required_status_checks": {
|
|
377
377
|
"contexts": ["ci"],
|
|
378
|
-
"checks": [{"context": "code-mower/gate"}],
|
|
378
|
+
"checks": [{"context": "code-mower/gate", "app_id": None}],
|
|
379
379
|
}
|
|
380
380
|
},
|
|
381
381
|
{},
|
|
@@ -391,6 +391,39 @@ class GitHubDoctorCheckTests(unittest.TestCase):
|
|
|
391
391
|
|
|
392
392
|
self.assertEqual(check.status, "pass")
|
|
393
393
|
self.assertIn("code-mower/gate", check.detail["required_status_contexts"])
|
|
394
|
+
self.assertEqual(
|
|
395
|
+
check.detail["required_status_check_bindings"],
|
|
396
|
+
[{"context": "code-mower/gate", "app_id": None}],
|
|
397
|
+
)
|
|
398
|
+
|
|
399
|
+
def test_branch_protection_warns_when_gate_status_bound_to_actions(self) -> None:
|
|
400
|
+
with mock.patch(
|
|
401
|
+
"code_mower.doctor_checks.github_branch._github_api_json",
|
|
402
|
+
return_value=(
|
|
403
|
+
{
|
|
404
|
+
"required_status_checks": {
|
|
405
|
+
"contexts": ["code-mower/gate"],
|
|
406
|
+
"checks": [{"context": "code-mower/gate", "app_id": 15368}],
|
|
407
|
+
}
|
|
408
|
+
},
|
|
409
|
+
{},
|
|
410
|
+
),
|
|
411
|
+
):
|
|
412
|
+
check = check_branch_protection(
|
|
413
|
+
gh_path="/usr/bin/gh",
|
|
414
|
+
slug="owner/repo",
|
|
415
|
+
default_branch="main",
|
|
416
|
+
http_timeout=1,
|
|
417
|
+
required_status_context="code-mower/gate",
|
|
418
|
+
)
|
|
419
|
+
|
|
420
|
+
self.assertEqual(check.status, "warn")
|
|
421
|
+
self.assertIn("GitHub Actions instead of Any source", check.message)
|
|
422
|
+
self.assertIn("app_id: null", check.remediation)
|
|
423
|
+
self.assertEqual(
|
|
424
|
+
check.detail["required_status_check_bindings"],
|
|
425
|
+
[{"context": "code-mower/gate", "app_id": 15368}],
|
|
426
|
+
)
|
|
394
427
|
|
|
395
428
|
def test_repo_auto_merge_warns_when_disabled(self) -> None:
|
|
396
429
|
check = check_repo_auto_merge(
|