code-mower 0.5.0b14__tar.gz → 0.5.0b16__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.0b14 → code_mower-0.5.0b16}/PKG-INFO +6 -6
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/README.md +5 -5
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/pyproject.toml +1 -1
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/__init__.py +1 -1
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/cli.py +1 -1
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/doctor_checks/__init__.py +2 -0
- code_mower-0.5.0b16/src/code_mower/doctor_checks/provider_review_hygiene.py +87 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/doctor_checks/providers.py +6 -1
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/doctor_checks/runner.py +1 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/package_manifest.py +5 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/providers/provenance.py +42 -13
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/release_readiness.py +6 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower.egg-info/PKG-INFO +6 -6
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower.egg-info/SOURCES.txt +2 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/tests/test_doctor_boundaries.py +1 -0
- code_mower-0.5.0b16/tests/test_doctor_provider_review_hygiene.py +98 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/tests/test_provider_local_cli.py +35 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/tests/test_release_hygiene.py +65 -34
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/CODE_OF_CONDUCT.md +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/LICENSE +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/MANIFEST.in +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/NOTICE +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/SUPPORT.md +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/requirements/requirements.txt +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/setup.cfg +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/adapters/__init__.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/adapters/_base.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/adapters/cursor_bugbot.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/adapters/gitar.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/adapters/greptile.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/adapters/qodo.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/antigravity_cli_audit_pr.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/audit_handoff_log.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/audit_labeler_lib.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/audit_progress.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/blind_review_artifacts.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/blind_review_coordinator.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/bootstrap.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/builder_experiment.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/calibration/__init__.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/calibration/arms.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/calibration/auto_discovery.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/calibration/commands.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/calibration/context_inputs.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/calibration/corpus.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/calibration/effect_report.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/calibration/evidence.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/calibration/evidence_report.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/calibration/identity.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/calibration/metrics.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/calibration/overlap.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/calibration/planning.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/calibration/policy.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/calibration/results.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/calibration/run_results.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/calibration/run_status.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/calibration/runner.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/calibration/truth.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/calibration/value_report.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/checks.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/claude_audit_pr.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/claude_cli_bounce.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/claude_cli_environment.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/clear_stale.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/cloud.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/cloud_client/__init__.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/cloud_client/bundle.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/cloud_client/doctor.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/cloud_client/dogfood.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/cloud_client/endpoints.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/cloud_client/errors.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/cloud_client/events.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/cloud_client/export.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/cloud_client/git_metadata.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/cloud_client/manifest.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/cloud_client/operations.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/cloud_client/reports.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/cloud_client/setup.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/cloud_client/upload.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/code_mower_calibration.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/code_mower_context_packs.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/code_mower_merge.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/code_mower_telemetry.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/coderabbit_cli_audit_pr.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/codex_audit_env_preflight.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/codex_audit_pr.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/codex_audit_schema_smoke.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/codex_audit_verdict.schema.json +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/config.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/doctor.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/doctor_checks/cloud.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/doctor_checks/common.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/doctor_checks/github.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/doctor_checks/github_actions.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/doctor_checks/github_actions_cost.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/doctor_checks/github_actions_cost_summary.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/doctor_checks/github_actions_failure_annotations.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/doctor_checks/github_actions_failure_models.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/doctor_checks/github_actions_failure_scan.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/doctor_checks/github_actions_failure_selection.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/doctor_checks/github_actions_failures.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/doctor_checks/github_actions_permissions.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/doctor_checks/github_api.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/doctor_checks/github_branch.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/doctor_checks/github_config.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/doctor_checks/github_provider.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/doctor_checks/github_repo.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/doctor_checks/groups.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/doctor_checks/models.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/doctor_checks/output.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/doctor_checks/presets.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/doctor_checks/privacy.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/doctor_checks/provider_api_model.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/doctor_checks/provider_api_model_openai.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/doctor_checks/provider_api_model_profiles.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/doctor_checks/provider_env.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/doctor_checks/provider_env_required.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/doctor_checks/provider_env_tokens.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/doctor_checks/provider_local_cli.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/doctor_checks/provider_local_cli_commands.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/doctor_checks/provider_local_cli_probe_config.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/doctor_checks/provider_probe.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/doctor_checks/provider_probe_auth.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/doctor_checks/provider_probe_evaluation.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/doctor_checks/provider_probe_json.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/doctor_checks/provider_probe_remediation.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/doctor_checks/registry.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/doctor_checks/runtime.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/doctor_checks/runtime_github_auth.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/gemini_cli_audit_pr.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/hermes_cli_audit_pr.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/init.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/lane_configs/__init__.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/lane_configs/aider.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/lane_configs/antigravity_cli.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/lane_configs/claude.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/lane_configs/codex.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/lane_configs/devin.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/lane_configs/gemini_cli.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/lane_configs/hermes_cli.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/lane_configs/local_llm.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/local_llm_audit_pr.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/local_llm_bakeoff.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/local_llm_calibration.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/local_llm_profiles.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/migration.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/migration_install.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/migration_mirror.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/migration_readiness.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/migration_rehearsal.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/next_steps.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/package.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/package_content.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/package_paths.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/package_rendering.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/package_static.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/prompts.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/provider_registry.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/provider_runners/__init__.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/provider_runners/comments.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/provider_runners/git.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/provider_runners/github_auth.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/provider_runners/github_pr.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/provider_runners/pr_worktree.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/provider_runners/process.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/provider_runners/repo_paths.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/provider_runners/text_schema.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/provider_runners/verdict_artifacts.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/provider_runners/workspace.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/providers/__init__.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/providers/local_cli.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/reviewer_metrics.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/saas_reviewer_labeler.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/secrets.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/templates/builder-experiment.example.json +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/templates/calibration-corpus.example.json +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/templates/calibration-corpus.json +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/templates/code-mower.example.yml +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/templates/context-packs.example.json +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/templates/lane_prompts/base-audit.md +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/templates/lane_prompts/calibration-policy.md +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/templates/lane_prompts/context-driven-quality.md +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/templates/lane_prompts/docs-design.md +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/templates/lane_prompts/generic-programming.md +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/templates/lane_prompts/operability.md +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/templates/lane_prompts/package-runtime.md +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/templates/lane_prompts/security-threat-model.md +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/templates/product-support/code_mower +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/templates/product-support/code_mower_standalone_pin.env +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/templates/product-support/code_mower_standalone_shadow.sh +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/templates/product-support/run_claude_audit_pr.sh +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/templates/product-support/run_codex_audit_pr.sh +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/templates/product-support/safe_gh_comment.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/templates/providers.yml +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/templates/reviewer-spend.example.json +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/templates/reviewer-value-report.example.md +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/templates/workflows/audit-label-cleanup.yml.j2 +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/templates/workflows/hosted-bridge.yml.j2 +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/templates/workflows/local-cli-audit.yml.j2 +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/templates/workflows/private-standalone-shadow.yml.j2 +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/templates/workflows/review-clear-stale.yml.j2 +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/templates/workflows/saas-reviewer-labeler.yml.j2 +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/templates/workflows/trailer-comment-labeler.yml.j2 +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/trailer_comment_labeler.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower/versioning.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower.egg-info/dependency_links.txt +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower.egg-info/entry_points.txt +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower.egg-info/requires.txt +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/src/code_mower.egg-info/top_level.txt +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/templates/builder-experiment.example.json +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/templates/calibration-corpus.example.json +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/templates/calibration-corpus.json +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/templates/code-mower.yml.j2 +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/templates/context-packs.example.json +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/templates/cursor/BUGBOT.md +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/templates/providers/acp_bridge.yml +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/templates/providers/aider.yml +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/templates/providers/antigravity_cli.yml +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/templates/providers/claude_audit.yml +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/templates/providers/claude_review.yml +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/templates/providers/coderabbit_cli.yml +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/templates/providers/codex.yml +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/templates/providers/cursor_bugbot.yml +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/templates/providers/devin.yml +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/templates/providers/gemini_cli.yml +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/templates/providers/gitar.yml +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/templates/providers/greptile.yml +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/templates/providers/hermes_cli.yml +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/templates/providers/local_llm.yml +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/templates/providers/qodo.yml +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/templates/providers.yml +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/templates/reviewer-spend.example.json +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/templates/reviewer-value-report.example.md +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/templates/workflows/audit-label-cleanup.yml.j2 +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/templates/workflows/blind-review-artifacts-dry-run.yml.j2 +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/templates/workflows/hosted-bridge.yml.j2 +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/templates/workflows/local-cli-audit.yml.j2 +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/templates/workflows/private-standalone-shadow.yml.j2 +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/templates/workflows/review-clear-stale.yml.j2 +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/templates/workflows/saas-reviewer-labeler.yml.j2 +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/templates/workflows/trailer-comment-labeler.yml.j2 +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/tests/test_calibration_effect_report.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/tests/test_calibration_truth.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/tests/test_checks.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/tests/test_claude_cli_bounce.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/tests/test_clear_stale.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/tests/test_cloud_client.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/tests/test_cloud_git_metadata.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/tests/test_cloud_manifest.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/tests/test_cloud_reports.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/tests/test_coderabbit_cli_audit_pr.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/tests/test_doctor_actions_cost_summary.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/tests/test_doctor_actions_failure_selection.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/tests/test_doctor_github_checks.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/tests/test_doctor_output.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/tests/test_doctor_privacy.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/tests/test_doctor_provider_env_required.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/tests/test_doctor_provider_env_tokens.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/tests/test_doctor_provider_probe.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/tests/test_doctor_registry.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/tests/test_local_llm_github_helpers.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/tests/test_provider_runners_comments.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/tests/test_provider_runners_git.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/tests/test_provider_runners_github_pr.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/tests/test_provider_runners_pr_worktree.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/tests/test_provider_runners_process.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/tests/test_provider_runners_repo_paths.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/tests/test_provider_runners_text_schema.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/tests/test_provider_runners_workspace.py +0 -0
- {code_mower-0.5.0b14 → code_mower-0.5.0b16}/tests/test_reviewer_metrics_core.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.0b16
|
|
4
4
|
Summary: Multi-reviewer AI code audit orchestration
|
|
5
5
|
License-Expression: Apache-2.0
|
|
6
6
|
Requires-Python: >=3.11
|
|
@@ -101,11 +101,11 @@ Code Mower currently targets Python 3.11+; Python 3.12 is recommended.
|
|
|
101
101
|
|
|
102
102
|
```bash
|
|
103
103
|
python3.12 --version
|
|
104
|
-
pipx install --python python3.12 code-mower==0.5.
|
|
104
|
+
pipx install --python python3.12 code-mower==0.5.0b16
|
|
105
105
|
code-mower --version
|
|
106
106
|
```
|
|
107
107
|
|
|
108
|
-
`0.5.
|
|
108
|
+
`0.5.0b16` is a beta release. Until Code Mower publishes a stable `1.0`
|
|
109
109
|
line, use the explicit beta version above or allow prereleases with:
|
|
110
110
|
|
|
111
111
|
```bash
|
|
@@ -148,7 +148,7 @@ First-time command map: [docs/launch-command-surface.md](docs/launch-command-sur
|
|
|
148
148
|
|
|
149
149
|
The current PyPI beta has been rehearsed end-to-end from a clean install:
|
|
150
150
|
[First-User Install Rehearsal](docs/first-user-install-rehearsal.md) records
|
|
151
|
-
the latest 10/10 public-package readiness proof for `code-mower==0.5.
|
|
151
|
+
the latest 10/10 public-package readiness proof for `code-mower==0.5.0b16`.
|
|
152
152
|
|
|
153
153
|
## Why Not Just Run Codex Or Claude Yourself?
|
|
154
154
|
|
|
@@ -253,9 +253,9 @@ best?" to "which AI builder plus reviewer loop ships best on this product?" See
|
|
|
253
253
|
|
|
254
254
|
## Installation Status
|
|
255
255
|
|
|
256
|
-
The current public beta is `v0.5.0-beta.
|
|
256
|
+
The current public beta is `v0.5.0-beta.16` from
|
|
257
257
|
[codemower-ai/code-mower](https://github.com/codemower-ai/code-mower), published
|
|
258
|
-
as `code-mower==0.5.
|
|
258
|
+
as `code-mower==0.5.0b16` on [PyPI](https://pypi.org/project/code-mower/).
|
|
259
259
|
GitHub releases remain the auditable source for tags, build artifacts, and
|
|
260
260
|
release notes.
|
|
261
261
|
|
|
@@ -86,11 +86,11 @@ Code Mower currently targets Python 3.11+; Python 3.12 is recommended.
|
|
|
86
86
|
|
|
87
87
|
```bash
|
|
88
88
|
python3.12 --version
|
|
89
|
-
pipx install --python python3.12 code-mower==0.5.
|
|
89
|
+
pipx install --python python3.12 code-mower==0.5.0b16
|
|
90
90
|
code-mower --version
|
|
91
91
|
```
|
|
92
92
|
|
|
93
|
-
`0.5.
|
|
93
|
+
`0.5.0b16` is a beta release. Until Code Mower publishes a stable `1.0`
|
|
94
94
|
line, use the explicit beta version above or allow prereleases with:
|
|
95
95
|
|
|
96
96
|
```bash
|
|
@@ -133,7 +133,7 @@ First-time command map: [docs/launch-command-surface.md](docs/launch-command-sur
|
|
|
133
133
|
|
|
134
134
|
The current PyPI beta has been rehearsed end-to-end from a clean install:
|
|
135
135
|
[First-User Install Rehearsal](docs/first-user-install-rehearsal.md) records
|
|
136
|
-
the latest 10/10 public-package readiness proof for `code-mower==0.5.
|
|
136
|
+
the latest 10/10 public-package readiness proof for `code-mower==0.5.0b16`.
|
|
137
137
|
|
|
138
138
|
## Why Not Just Run Codex Or Claude Yourself?
|
|
139
139
|
|
|
@@ -238,9 +238,9 @@ best?" to "which AI builder plus reviewer loop ships best on this product?" See
|
|
|
238
238
|
|
|
239
239
|
## Installation Status
|
|
240
240
|
|
|
241
|
-
The current public beta is `v0.5.0-beta.
|
|
241
|
+
The current public beta is `v0.5.0-beta.16` from
|
|
242
242
|
[codemower-ai/code-mower](https://github.com/codemower-ai/code-mower), published
|
|
243
|
-
as `code-mower==0.5.
|
|
243
|
+
as `code-mower==0.5.0b16` on [PyPI](https://pypi.org/project/code-mower/).
|
|
244
244
|
GitHub releases remain the auditable source for tags, build artifacts, and
|
|
245
245
|
release notes.
|
|
246
246
|
|
|
@@ -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.0b16`, or run source checkouts with "
|
|
18
18
|
"`PYTHONPATH=src python -m code_mower.cli`."
|
|
19
19
|
)
|
|
20
20
|
|
|
@@ -36,6 +36,7 @@ from .presets import (
|
|
|
36
36
|
)
|
|
37
37
|
from .providers import (
|
|
38
38
|
check_lane_runtime,
|
|
39
|
+
check_review_hygiene,
|
|
39
40
|
effective_lane,
|
|
40
41
|
provider_template_coverage,
|
|
41
42
|
selected_lanes,
|
|
@@ -83,6 +84,7 @@ __all__ = [
|
|
|
83
84
|
"check_github_auth_surface",
|
|
84
85
|
"check_github_setup",
|
|
85
86
|
"check_lane_runtime",
|
|
87
|
+
"check_review_hygiene",
|
|
86
88
|
"check_pytest",
|
|
87
89
|
"check_python_runtime",
|
|
88
90
|
"check_ripgrep",
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"""Review-hygiene checks for merge-authority provider lanes."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any, Mapping
|
|
6
|
+
|
|
7
|
+
from .common import DoctorCheck, STATUS_FAIL, STATUS_PASS, STATUS_SKIP, as_sequence
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def check_review_hygiene(
|
|
11
|
+
lane_id: str,
|
|
12
|
+
lane: Mapping[str, Any],
|
|
13
|
+
*,
|
|
14
|
+
effective_lane: Mapping[str, Any] | None = None,
|
|
15
|
+
) -> DoctorCheck:
|
|
16
|
+
"""Verify that merge-authority lanes have stale terminal-label protection."""
|
|
17
|
+
|
|
18
|
+
merge_authority_lane = effective_lane if effective_lane is not None else lane
|
|
19
|
+
if not bool(merge_authority_lane.get("merge_authority", False)):
|
|
20
|
+
return DoctorCheck(
|
|
21
|
+
name="provider.review_hygiene",
|
|
22
|
+
status=STATUS_SKIP,
|
|
23
|
+
lane=lane_id,
|
|
24
|
+
message="lane is not merge authority; stale terminal-label guard is optional",
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
review_hygiene = lane.get("review_hygiene")
|
|
28
|
+
if not isinstance(review_hygiene, Mapping):
|
|
29
|
+
review_hygiene = {}
|
|
30
|
+
|
|
31
|
+
workflow = str(review_hygiene.get("workflow") or "").strip()
|
|
32
|
+
token_env = str(review_hygiene.get("token_env") or "").strip()
|
|
33
|
+
dispatch_workflow = str(review_hygiene.get("dispatch_workflow") or "").strip()
|
|
34
|
+
trusted_authors = tuple(str(author) for author in as_sequence(review_hygiene.get("trusted_authors", [])))
|
|
35
|
+
missing: list[str] = []
|
|
36
|
+
if not workflow:
|
|
37
|
+
missing.append("workflow")
|
|
38
|
+
if not token_env:
|
|
39
|
+
missing.append("token_env")
|
|
40
|
+
|
|
41
|
+
detail = {
|
|
42
|
+
"workflow": workflow,
|
|
43
|
+
"token_env": token_env,
|
|
44
|
+
"dispatch_workflow": dispatch_workflow,
|
|
45
|
+
"trusted_authors": list(trusted_authors),
|
|
46
|
+
"merge_authority": True,
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if missing:
|
|
50
|
+
return DoctorCheck(
|
|
51
|
+
name="provider.review_hygiene",
|
|
52
|
+
status=STATUS_FAIL,
|
|
53
|
+
lane=lane_id,
|
|
54
|
+
message=(
|
|
55
|
+
"merge-authority lane is missing stale terminal-label guard config: "
|
|
56
|
+
+ ", ".join(missing)
|
|
57
|
+
),
|
|
58
|
+
detail={**detail, "missing": missing},
|
|
59
|
+
remediation=(
|
|
60
|
+
"Add review_hygiene.workflow and review_hygiene.token_env to this "
|
|
61
|
+
"lane, or regenerate workflows with `code-mower init --easy --apply`."
|
|
62
|
+
),
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
if token_env != "GITHUB_TOKEN":
|
|
66
|
+
return DoctorCheck(
|
|
67
|
+
name="provider.review_hygiene",
|
|
68
|
+
status=STATUS_FAIL,
|
|
69
|
+
lane=lane_id,
|
|
70
|
+
message=(
|
|
71
|
+
"merge-authority lane uses unsupported stale terminal-label token_env: "
|
|
72
|
+
f"{token_env}"
|
|
73
|
+
),
|
|
74
|
+
detail={**detail, "supported_token_env": "GITHUB_TOKEN"},
|
|
75
|
+
remediation=(
|
|
76
|
+
"Use review_hygiene.token_env: GITHUB_TOKEN, or update the generated "
|
|
77
|
+
"clear-stale workflow template before relying on a custom token."
|
|
78
|
+
),
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
return DoctorCheck(
|
|
82
|
+
name="provider.review_hygiene",
|
|
83
|
+
status=STATUS_PASS,
|
|
84
|
+
lane=lane_id,
|
|
85
|
+
message=f"stale terminal-label guard configured via {workflow}",
|
|
86
|
+
detail=detail,
|
|
87
|
+
)
|
|
@@ -24,9 +24,11 @@ from .provider_probe import (
|
|
|
24
24
|
evaluate_json_probe,
|
|
25
25
|
local_cli_probe_remediation,
|
|
26
26
|
)
|
|
27
|
+
from .provider_review_hygiene import check_review_hygiene
|
|
27
28
|
|
|
28
29
|
__all__ = [
|
|
29
30
|
"check_lane_runtime",
|
|
31
|
+
"check_review_hygiene",
|
|
30
32
|
"effective_lane",
|
|
31
33
|
"evaluate_json_probe",
|
|
32
34
|
"local_cli_probe_remediation",
|
|
@@ -109,10 +111,13 @@ def check_lane_runtime(
|
|
|
109
111
|
lane_id: str,
|
|
110
112
|
lane: Mapping[str, Any],
|
|
111
113
|
*,
|
|
114
|
+
source_lane: Mapping[str, Any] | None = None,
|
|
112
115
|
probe_runtime: bool,
|
|
113
116
|
http_timeout: int,
|
|
114
117
|
) -> list[DoctorCheck]:
|
|
115
|
-
|
|
118
|
+
hygiene_source = source_lane if source_lane is not None else lane
|
|
119
|
+
checks = [check_review_hygiene(lane_id, hygiene_source, effective_lane=lane)]
|
|
120
|
+
checks.extend(check_token_env(lane_id, lane))
|
|
116
121
|
checks.extend(check_required_env(lane_id, lane))
|
|
117
122
|
driver = str(lane.get("driver", ""))
|
|
118
123
|
if driver == "local_cli":
|
|
@@ -187,6 +187,11 @@ PACKAGE_FILES = (
|
|
|
187
187
|
"src/code_mower/doctor_checks/provider_probe_remediation.py",
|
|
188
188
|
"core",
|
|
189
189
|
),
|
|
190
|
+
(
|
|
191
|
+
"src/code_mower/doctor_checks/provider_review_hygiene.py",
|
|
192
|
+
"src/code_mower/doctor_checks/provider_review_hygiene.py",
|
|
193
|
+
"core",
|
|
194
|
+
),
|
|
190
195
|
("src/code_mower/doctor_checks/privacy.py", "src/code_mower/doctor_checks/privacy.py", "core"),
|
|
191
196
|
("src/code_mower/doctor_checks/providers.py", "src/code_mower/doctor_checks/providers.py", "core"),
|
|
192
197
|
("src/code_mower/doctor_checks/registry.py", "src/code_mower/doctor_checks/registry.py", "core"),
|
|
@@ -143,22 +143,50 @@ def _first_text(values: Any) -> str:
|
|
|
143
143
|
return ""
|
|
144
144
|
|
|
145
145
|
|
|
146
|
+
def _text_values(values: Any) -> tuple[str, ...]:
|
|
147
|
+
if isinstance(values, str):
|
|
148
|
+
text = _safe_text(values)
|
|
149
|
+
return (text,) if text else ()
|
|
150
|
+
if isinstance(values, (list, tuple)):
|
|
151
|
+
result: list[str] = []
|
|
152
|
+
for value in values:
|
|
153
|
+
text = _safe_text(value)
|
|
154
|
+
if text and text not in result:
|
|
155
|
+
result.append(text)
|
|
156
|
+
return tuple(result)
|
|
157
|
+
return ()
|
|
158
|
+
|
|
159
|
+
|
|
146
160
|
def _env_value(config: Mapping[str, Any], key: str) -> str:
|
|
147
161
|
env_name = _safe_text(config.get(key))
|
|
148
162
|
return _safe_text(os.environ.get(env_name)) if env_name else ""
|
|
149
163
|
|
|
150
164
|
|
|
151
|
-
def
|
|
165
|
+
def _configured_command_candidates(
|
|
166
|
+
config: Mapping[str, Any],
|
|
167
|
+
provider: str,
|
|
168
|
+
) -> tuple[str, ...]:
|
|
152
169
|
override = _env_value(config, "command_env")
|
|
153
170
|
if override:
|
|
154
|
-
return override
|
|
171
|
+
return (override,)
|
|
172
|
+
candidates: list[str] = []
|
|
155
173
|
command = _safe_text(config.get("command"))
|
|
156
174
|
if command:
|
|
157
|
-
|
|
158
|
-
alternate
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
175
|
+
candidates.append(command)
|
|
176
|
+
for alternate in _text_values(config.get("alternate_commands")):
|
|
177
|
+
if alternate not in candidates:
|
|
178
|
+
candidates.append(alternate)
|
|
179
|
+
if not candidates:
|
|
180
|
+
candidates.append(provider)
|
|
181
|
+
return tuple(candidates)
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def _select_available_command(candidates: tuple[str, ...]) -> tuple[str, str]:
|
|
185
|
+
for command in candidates:
|
|
186
|
+
resolved = shutil.which(command)
|
|
187
|
+
if resolved:
|
|
188
|
+
return command, resolved
|
|
189
|
+
return (candidates[0] if candidates else "", "")
|
|
162
190
|
|
|
163
191
|
|
|
164
192
|
def build_provider_lane_tool_provenance(
|
|
@@ -178,7 +206,8 @@ def build_provider_lane_tool_provenance(
|
|
|
178
206
|
config = _provider_config(lane)
|
|
179
207
|
provider = _safe_text(_lane_value(lane, "provider")) or lane_id
|
|
180
208
|
driver = _safe_text(_lane_value(lane, "driver")) or "unknown"
|
|
181
|
-
|
|
209
|
+
command_candidates = _configured_command_candidates(config, provider)
|
|
210
|
+
command, resolved_command = _select_available_command(command_candidates)
|
|
182
211
|
model = _env_value(config, "model_env") or _safe_text(config.get("default_model"))
|
|
183
212
|
provider_from_env = _env_value(config, "provider_env")
|
|
184
213
|
if provider_from_env:
|
|
@@ -197,16 +226,16 @@ def build_provider_lane_tool_provenance(
|
|
|
197
226
|
"lane_id": lane_id,
|
|
198
227
|
"driver": driver,
|
|
199
228
|
"command": command if driver == "local_cli" else "",
|
|
229
|
+
"command_candidates": list(command_candidates) if driver == "local_cli" else [],
|
|
200
230
|
"model_known": bool(model),
|
|
201
231
|
"version_known": False,
|
|
202
232
|
}
|
|
203
233
|
tool_version = ""
|
|
204
234
|
if driver == "local_cli" and include_version_probe and command:
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
version_detail = detect_local_cli_version(resolved)
|
|
235
|
+
detail["command_found"] = bool(resolved_command)
|
|
236
|
+
if resolved_command:
|
|
237
|
+
detail["path_basename"] = os.path.basename(resolved_command)
|
|
238
|
+
version_detail = detect_local_cli_version(resolved_command)
|
|
210
239
|
tool_version = _safe_text(version_detail.get("tool_version"))
|
|
211
240
|
detail["version_known"] = bool(tool_version)
|
|
212
241
|
detail["tool_version_available"] = bool(
|
|
@@ -358,6 +358,9 @@ def render_release_readiness(repo_path: Path) -> dict[str, Any]:
|
|
|
358
358
|
if (
|
|
359
359
|
_needs_job(testpypi_job, "verify-distributions")
|
|
360
360
|
and "inputs.publish_testpypi" in testpypi_job_text
|
|
361
|
+
and "inputs.publish_testpypi == true" in testpypi_job_text
|
|
362
|
+
and "github.event_name == 'workflow_dispatch'" in testpypi_job_text
|
|
363
|
+
and "github.event_name == 'release'" in testpypi_job_text
|
|
361
364
|
and "CODE_MOWER_TESTPYPI_PUBLISH" in testpypi_job_text
|
|
362
365
|
and _job_uses_environment(testpypi_job, "testpypi")
|
|
363
366
|
and _permissions_include(testpypi_job, "id-token", "write")
|
|
@@ -376,6 +379,9 @@ def render_release_readiness(repo_path: Path) -> dict[str, Any]:
|
|
|
376
379
|
if (
|
|
377
380
|
_needs_job(pypi_job, "verify-distributions")
|
|
378
381
|
and "inputs.publish_pypi" in pypi_job_text
|
|
382
|
+
and "inputs.publish_pypi == true" in pypi_job_text
|
|
383
|
+
and "github.event_name == 'workflow_dispatch'" in pypi_job_text
|
|
384
|
+
and "github.event_name == 'release'" in pypi_job_text
|
|
379
385
|
and "CODE_MOWER_PYPI_PUBLISH" in pypi_job_text
|
|
380
386
|
and _job_uses_environment(pypi_job, "pypi")
|
|
381
387
|
and _permissions_include(pypi_job, "id-token", "write")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: code-mower
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.0b16
|
|
4
4
|
Summary: Multi-reviewer AI code audit orchestration
|
|
5
5
|
License-Expression: Apache-2.0
|
|
6
6
|
Requires-Python: >=3.11
|
|
@@ -101,11 +101,11 @@ Code Mower currently targets Python 3.11+; Python 3.12 is recommended.
|
|
|
101
101
|
|
|
102
102
|
```bash
|
|
103
103
|
python3.12 --version
|
|
104
|
-
pipx install --python python3.12 code-mower==0.5.
|
|
104
|
+
pipx install --python python3.12 code-mower==0.5.0b16
|
|
105
105
|
code-mower --version
|
|
106
106
|
```
|
|
107
107
|
|
|
108
|
-
`0.5.
|
|
108
|
+
`0.5.0b16` is a beta release. Until Code Mower publishes a stable `1.0`
|
|
109
109
|
line, use the explicit beta version above or allow prereleases with:
|
|
110
110
|
|
|
111
111
|
```bash
|
|
@@ -148,7 +148,7 @@ First-time command map: [docs/launch-command-surface.md](docs/launch-command-sur
|
|
|
148
148
|
|
|
149
149
|
The current PyPI beta has been rehearsed end-to-end from a clean install:
|
|
150
150
|
[First-User Install Rehearsal](docs/first-user-install-rehearsal.md) records
|
|
151
|
-
the latest 10/10 public-package readiness proof for `code-mower==0.5.
|
|
151
|
+
the latest 10/10 public-package readiness proof for `code-mower==0.5.0b16`.
|
|
152
152
|
|
|
153
153
|
## Why Not Just Run Codex Or Claude Yourself?
|
|
154
154
|
|
|
@@ -253,9 +253,9 @@ best?" to "which AI builder plus reviewer loop ships best on this product?" See
|
|
|
253
253
|
|
|
254
254
|
## Installation Status
|
|
255
255
|
|
|
256
|
-
The current public beta is `v0.5.0-beta.
|
|
256
|
+
The current public beta is `v0.5.0-beta.16` from
|
|
257
257
|
[codemower-ai/code-mower](https://github.com/codemower-ai/code-mower), published
|
|
258
|
-
as `code-mower==0.5.
|
|
258
|
+
as `code-mower==0.5.0b16` on [PyPI](https://pypi.org/project/code-mower/).
|
|
259
259
|
GitHub releases remain the auditable source for tags, build artifacts, and
|
|
260
260
|
release notes.
|
|
261
261
|
|
|
@@ -143,6 +143,7 @@ src/code_mower/doctor_checks/provider_probe_auth.py
|
|
|
143
143
|
src/code_mower/doctor_checks/provider_probe_evaluation.py
|
|
144
144
|
src/code_mower/doctor_checks/provider_probe_json.py
|
|
145
145
|
src/code_mower/doctor_checks/provider_probe_remediation.py
|
|
146
|
+
src/code_mower/doctor_checks/provider_review_hygiene.py
|
|
146
147
|
src/code_mower/doctor_checks/providers.py
|
|
147
148
|
src/code_mower/doctor_checks/registry.py
|
|
148
149
|
src/code_mower/doctor_checks/runner.py
|
|
@@ -251,6 +252,7 @@ tests/test_doctor_privacy.py
|
|
|
251
252
|
tests/test_doctor_provider_env_required.py
|
|
252
253
|
tests/test_doctor_provider_env_tokens.py
|
|
253
254
|
tests/test_doctor_provider_probe.py
|
|
255
|
+
tests/test_doctor_provider_review_hygiene.py
|
|
254
256
|
tests/test_doctor_registry.py
|
|
255
257
|
tests/test_local_llm_github_helpers.py
|
|
256
258
|
tests/test_provider_local_cli.py
|
|
@@ -107,6 +107,7 @@ class DoctorBoundaryTests(unittest.TestCase):
|
|
|
107
107
|
"code_mower.doctor_checks.provider_probe_evaluation",
|
|
108
108
|
"code_mower.doctor_checks.provider_probe_json",
|
|
109
109
|
"code_mower.doctor_checks.provider_probe_remediation",
|
|
110
|
+
"code_mower.doctor_checks.provider_review_hygiene",
|
|
110
111
|
"code_mower.doctor_checks.providers",
|
|
111
112
|
"code_mower.doctor_checks.privacy",
|
|
112
113
|
"code_mower.doctor_checks.registry",
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import unittest
|
|
4
|
+
|
|
5
|
+
from code_mower.doctor_checks.provider_review_hygiene import check_review_hygiene
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class DoctorProviderReviewHygieneTests(unittest.TestCase):
|
|
9
|
+
def test_merge_authority_lane_requires_stale_guard(self) -> None:
|
|
10
|
+
check = check_review_hygiene(
|
|
11
|
+
"devin",
|
|
12
|
+
{
|
|
13
|
+
"merge_authority": True,
|
|
14
|
+
"review_hygiene": {},
|
|
15
|
+
},
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
self.assertEqual(check.status, "fail")
|
|
19
|
+
self.assertEqual(check.name, "provider.review_hygiene")
|
|
20
|
+
self.assertEqual(check.lane, "devin")
|
|
21
|
+
self.assertIn("workflow", check.detail["missing"])
|
|
22
|
+
self.assertIn("token_env", check.detail["missing"])
|
|
23
|
+
self.assertIn("code-mower init --easy --apply", check.remediation)
|
|
24
|
+
|
|
25
|
+
def test_template_defaults_do_not_satisfy_source_hygiene_requirement(self) -> None:
|
|
26
|
+
check = check_review_hygiene(
|
|
27
|
+
"codex",
|
|
28
|
+
{},
|
|
29
|
+
effective_lane={
|
|
30
|
+
"merge_authority": True,
|
|
31
|
+
"review_hygiene": {
|
|
32
|
+
"workflow": ".github/workflows/codex-clear-stale.yml",
|
|
33
|
+
"token_env": "GITHUB_TOKEN",
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
self.assertEqual(check.status, "fail")
|
|
39
|
+
self.assertEqual(check.detail["missing"], ["workflow", "token_env"])
|
|
40
|
+
self.assertIn("missing stale terminal-label guard config", check.message)
|
|
41
|
+
|
|
42
|
+
def test_merge_authority_lane_passes_with_stale_guard(self) -> None:
|
|
43
|
+
check = check_review_hygiene(
|
|
44
|
+
"codex",
|
|
45
|
+
{
|
|
46
|
+
"merge_authority": True,
|
|
47
|
+
"review_hygiene": {
|
|
48
|
+
"workflow": ".github/workflows/codex-clear-stale.yml",
|
|
49
|
+
"token_env": "GITHUB_TOKEN",
|
|
50
|
+
"dispatch_workflow": "codex-audit-labeler.yml",
|
|
51
|
+
"trusted_authors": ["codex[bot]"],
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
self.assertEqual(check.status, "pass")
|
|
57
|
+
self.assertEqual(
|
|
58
|
+
check.message,
|
|
59
|
+
"stale terminal-label guard configured via .github/workflows/codex-clear-stale.yml",
|
|
60
|
+
)
|
|
61
|
+
self.assertEqual(check.detail["workflow"], ".github/workflows/codex-clear-stale.yml")
|
|
62
|
+
self.assertEqual(check.detail["token_env"], "GITHUB_TOKEN")
|
|
63
|
+
self.assertEqual(check.detail["dispatch_workflow"], "codex-audit-labeler.yml")
|
|
64
|
+
self.assertEqual(check.detail["trusted_authors"], ["codex[bot]"])
|
|
65
|
+
|
|
66
|
+
def test_merge_authority_lane_rejects_custom_hygiene_token_until_template_supports_it(self) -> None:
|
|
67
|
+
check = check_review_hygiene(
|
|
68
|
+
"devin",
|
|
69
|
+
{
|
|
70
|
+
"merge_authority": True,
|
|
71
|
+
"review_hygiene": {
|
|
72
|
+
"workflow": ".github/workflows/devin-clear-stale.yml",
|
|
73
|
+
"token_env": "DEVIN_AUDIT_LABEL_TOKEN",
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
self.assertEqual(check.status, "fail")
|
|
79
|
+
self.assertEqual(check.detail["token_env"], "DEVIN_AUDIT_LABEL_TOKEN")
|
|
80
|
+
self.assertEqual(check.detail["supported_token_env"], "GITHUB_TOKEN")
|
|
81
|
+
self.assertIn("unsupported", check.message)
|
|
82
|
+
|
|
83
|
+
def test_informational_lane_skips_stale_guard_requirement(self) -> None:
|
|
84
|
+
check = check_review_hygiene(
|
|
85
|
+
"gitar",
|
|
86
|
+
{
|
|
87
|
+
"merge_authority": False,
|
|
88
|
+
"review_hygiene": {},
|
|
89
|
+
},
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
self.assertEqual(check.status, "skip")
|
|
93
|
+
self.assertEqual(check.lane, "gitar")
|
|
94
|
+
self.assertIn("optional", check.message)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
if __name__ == "__main__":
|
|
98
|
+
unittest.main()
|
|
@@ -83,6 +83,41 @@ def test_provider_lane_tool_provenance_reads_version_and_model_env(
|
|
|
83
83
|
assert tool["model"] == "model-v1"
|
|
84
84
|
assert tool["lens"] == "security-threat-model"
|
|
85
85
|
assert detail["lane_id"] == "gemini_cli"
|
|
86
|
+
assert detail["command_candidates"] == ["provider-cli"]
|
|
86
87
|
assert detail["command_found"] is True
|
|
87
88
|
assert detail["model_known"] is True
|
|
88
89
|
assert detail["version_known"] is True
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def test_provider_lane_tool_provenance_uses_available_alternate_command(
|
|
93
|
+
monkeypatch,
|
|
94
|
+
tmp_path: Path,
|
|
95
|
+
) -> None:
|
|
96
|
+
executable = _write_executable(
|
|
97
|
+
tmp_path / "antigravity",
|
|
98
|
+
"#!/bin/sh\nprintf 'antigravity 1.2.3\\n'\n",
|
|
99
|
+
)
|
|
100
|
+
monkeypatch.setenv("PATH", os.fspath(executable.parent))
|
|
101
|
+
lane = {
|
|
102
|
+
"driver": "local_cli",
|
|
103
|
+
"provider": "antigravity",
|
|
104
|
+
"provider_config": {
|
|
105
|
+
"command": "agy",
|
|
106
|
+
"alternate_commands": ("antigravity",),
|
|
107
|
+
"model_env": "ANTIGRAVITY_MODEL",
|
|
108
|
+
},
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
tool, detail = build_provider_lane_tool_provenance(
|
|
112
|
+
"antigravity_cli",
|
|
113
|
+
lane,
|
|
114
|
+
source="unit-test",
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
assert tool["tool_name"] == "antigravity"
|
|
118
|
+
assert tool["tool_version"] == "antigravity 1.2.3"
|
|
119
|
+
assert tool["provider"] == "antigravity"
|
|
120
|
+
assert detail["command"] == "antigravity"
|
|
121
|
+
assert detail["command_candidates"] == ["agy", "antigravity"]
|
|
122
|
+
assert detail["command_found"] is True
|
|
123
|
+
assert detail["version_known"] is True
|