code-mower 1.0.10__tar.gz → 1.0.12__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-1.0.10 → code_mower-1.0.12}/PKG-INFO +20 -5
- {code_mower-1.0.10 → code_mower-1.0.12}/README.md +19 -4
- {code_mower-1.0.10 → code_mower-1.0.12}/pyproject.toml +1 -1
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/__init__.py +1 -1
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/campaign_adapters.py +93 -11
- code_mower-1.0.12/src/code_mower/devin_api.py +259 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/adoption.py +8 -4
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/migration_install.py +22 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/package_manifest.py +1 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/provider_registry.py +7 -4
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/release_campaigns.py +682 -31
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/release_qualify.py +27 -2
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/providers.yml +8 -1
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/workflows/builder-provenance.yml.j2 +1 -1
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower.egg-info/PKG-INFO +20 -5
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower.egg-info/SOURCES.txt +2 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/templates/providers/devin.yml +8 -1
- {code_mower-1.0.10 → code_mower-1.0.12}/templates/providers.yml +8 -1
- {code_mower-1.0.10 → code_mower-1.0.12}/templates/workflows/builder-provenance.yml.j2 +1 -1
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_campaign_adapters.py +173 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_campaign_retry_evidence_711.py +5 -4
- code_mower-1.0.12/tests/test_devin_api.py +556 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_devin_provider_contract.py +13 -4
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_doctor_campaign_readiness.py +16 -10
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_hosted_dispatch_profile.py +52 -30
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_package_install_failure_taxonomy.py +58 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_release_campaigns.py +142 -86
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_release_hygiene.py +48 -46
- {code_mower-1.0.10 → code_mower-1.0.12}/CODE_OF_CONDUCT.md +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/LICENSE +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/MANIFEST.in +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/NOTICE +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/SUPPORT.md +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/requirements/requirements.txt +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/setup.cfg +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/adapters/__init__.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/adapters/_base.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/adapters/cursor_bugbot.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/adapters/gitar.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/adapters/greptile.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/adapters/qodo.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/antigravity_cli_audit_pr.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/antigravity_sdk_probe.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/audit_handoff_log.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/audit_labeler_lib.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/audit_limits.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/audit_progress.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/blind_review_artifacts.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/blind_review_coordinator.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/board.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/board_store.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/bootstrap.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/builder_experiment.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/builder_runs.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/calibration/__init__.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/calibration/arms.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/calibration/auto_discovery.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/calibration/commands.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/calibration/context_inputs.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/calibration/corpus.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/calibration/effect_report.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/calibration/evidence.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/calibration/evidence_report.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/calibration/identity.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/calibration/metrics.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/calibration/overlap.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/calibration/planning.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/calibration/policy.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/calibration/results.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/calibration/run_results.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/calibration/run_status.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/calibration/runner.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/calibration/truth.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/calibration/value_report.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/campaign_discovery.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/checks.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/claude_audit_pr.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/claude_cli_bounce.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/claude_cli_environment.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/clear_stale.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/cli.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/cloud.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/cloud_client/__init__.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/cloud_client/adoption_runs.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/cloud_client/bundle.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/cloud_client/doctor.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/cloud_client/dogfood.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/cloud_client/endpoints.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/cloud_client/errors.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/cloud_client/events.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/cloud_client/export.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/cloud_client/git_metadata.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/cloud_client/manifest.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/cloud_client/operations.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/cloud_client/pr_outcomes.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/cloud_client/productivity.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/cloud_client/reports.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/cloud_client/setup.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/cloud_client/tokens.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/cloud_client/upload.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/cloud_client/work_types.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/code_mower_calibration.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/code_mower_context_packs.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/code_mower_merge.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/code_mower_telemetry.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/coderabbit_cli_audit_pr.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/codex_audit_env_preflight.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/codex_audit_pr.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/codex_audit_schema_smoke.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/codex_audit_verdict.schema.json +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/config.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/controller.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/decisions.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/devin_cli_audit_pr.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/__init__.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/audit_limits.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/campaign_auth.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/cloud.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/common.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/github.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/github_actions.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/github_actions_cost.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/github_actions_cost_summary.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/github_actions_failure_annotations.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/github_actions_failure_models.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/github_actions_failure_scan.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/github_actions_failure_selection.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/github_actions_failures.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/github_actions_permissions.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/github_api.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/github_branch.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/github_config.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/github_human_token.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/github_provider.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/github_repo.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/github_trusted_authors.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/groups.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/models.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/output.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/presets.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/privacy.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/provider_api_model.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/provider_api_model_openai.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/provider_api_model_profiles.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/provider_env.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/provider_env_required.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/provider_env_tokens.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/provider_local_audit_setup.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/provider_local_cli.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/provider_local_cli_commands.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/provider_local_cli_probe_config.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/provider_probe.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/provider_probe_auth.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/provider_probe_evaluation.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/provider_probe_json.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/provider_probe_remediation.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/provider_review_hygiene.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/providers.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/registry.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/runner.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/runtime.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/runtime_github_auth.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/self_hosted_runner.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/doctor_checks/supervised_pilot.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/file_locks.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/gate_health.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/gemini_cli_audit_pr.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/git_identity.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/grok_build_audit_pr.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/hermes_cli_audit_pr.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/init.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/lane_configs/__init__.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/lane_configs/aider.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/lane_configs/antigravity_cli.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/lane_configs/claude.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/lane_configs/codex.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/lane_configs/devin.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/lane_configs/devin_cli.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/lane_configs/gemini_cli.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/lane_configs/grok_build.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/lane_configs/hermes_cli.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/lane_configs/local_llm.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/lane_configs/muse_cli.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/lane_delivery.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/lane_status.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/local_llm_audit_pr.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/local_llm_bakeoff.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/local_llm_calibration.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/local_llm_profiles.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/migration.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/migration_mirror.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/migration_readiness.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/migration_rehearsal.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/muse_cli_audit_pr.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/next_steps.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/package.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/package_content.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/package_paths.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/package_rendering.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/package_static.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/participants.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/plan_context.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/productivity_report.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/prompts.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/provider_runners/__init__.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/provider_runners/comments.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/provider_runners/exit_codes.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/provider_runners/git.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/provider_runners/github_auth.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/provider_runners/github_pr.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/provider_runners/pr_worktree.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/provider_runners/process.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/provider_runners/repo_paths.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/provider_runners/text_schema.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/provider_runners/verdict_artifacts.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/provider_runners/workspace.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/providers/__init__.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/providers/local_cli.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/providers/provenance.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/release_readiness.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/reviewer_metrics.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/reviewer_spend.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/saas_reviewer_labeler.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/secrets.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/session.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/builder-experiment.example.json +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/calibration-corpus.example.json +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/calibration-corpus.json +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/code-mower.example.yml +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/context-packs.example.json +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/lane_prompts/base-audit.md +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/lane_prompts/calibration-policy.md +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/lane_prompts/context-driven-quality.md +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/lane_prompts/docs-design.md +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/lane_prompts/generic-programming.md +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/lane_prompts/operability.md +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/lane_prompts/package-runtime.md +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/lane_prompts/plan-conformance.md +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/lane_prompts/security-threat-model.md +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/lanes/README.md +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/lanes/claude.md +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/lanes/codex.md +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/lanes/cursor.md +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/lanes/devin.md +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/lanes/generic.md +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/lanes/run_mac_lane.sh +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/product-support/code_mower +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/product-support/code_mower_standalone_pin.env +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/product-support/code_mower_standalone_shadow.sh +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/product-support/run_claude_audit_pr.sh +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/product-support/run_codex_audit_pr.sh +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/product-support/run_devin_cli_audit_pr.sh +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/product-support/safe_gh_comment.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/product-support/status_report.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/reviewer-spend.example.json +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/reviewer-value-report.example.md +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/workflows/audit-label-cleanup.yml.j2 +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/workflows/code-mower-agent-pr-labeler.yml.j2 +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/workflows/code-mower-fix-round-dispatch.yml.j2 +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/workflows/code-mower-gate-health.yml.j2 +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/workflows/code-mower-gate.yml.j2 +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/workflows/dispatch-lanes.yml.j2 +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/workflows/hosted-bridge.yml.j2 +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/workflows/lane-mac-runner.yml.j2 +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/workflows/local-cli-audit.yml.j2 +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/workflows/needs-owner-notify.yml.j2 +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/workflows/private-standalone-shadow.yml.j2 +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/workflows/review-clear-stale.yml.j2 +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/workflows/saas-reviewer-labeler.yml.j2 +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/workflows/self-hosted-local-audit.yml.j2 +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/workflows/trailer-comment-labeler.yml.j2 +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/templates/workflows/weekly-status.yml.j2 +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/trailer_comment_labeler.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/versioning.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/work_orders.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower/workflow_actionlint.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower.egg-info/dependency_links.txt +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower.egg-info/entry_points.txt +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower.egg-info/requires.txt +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/src/code_mower.egg-info/top_level.txt +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/templates/builder-experiment.example.json +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/templates/calibration-corpus.example.json +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/templates/calibration-corpus.json +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/templates/code-mower.yml.j2 +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/templates/context-packs.example.json +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/templates/cursor/BUGBOT.md +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/templates/lanes/README.md +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/templates/lanes/claude.md +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/templates/lanes/codex.md +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/templates/lanes/cursor.md +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/templates/lanes/devin.md +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/templates/lanes/generic.md +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/templates/lanes/run_mac_lane.sh +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/templates/providers/acp_bridge.yml +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/templates/providers/aider.yml +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/templates/providers/antigravity_cli.yml +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/templates/providers/claude_audit.yml +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/templates/providers/claude_review.yml +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/templates/providers/coderabbit_cli.yml +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/templates/providers/codex.yml +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/templates/providers/cursor_bugbot.yml +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/templates/providers/cursor_cloud_agent.yml +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/templates/providers/devin_cli.yml +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/templates/providers/gemini_cli.yml +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/templates/providers/gitar.yml +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/templates/providers/greptile.yml +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/templates/providers/hermes_cli.yml +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/templates/providers/local_llm.yml +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/templates/providers/muse_cli.yml +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/templates/providers/qodo.yml +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/templates/reviewer-spend.example.json +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/templates/reviewer-value-report.example.md +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/templates/workflows/audit-label-cleanup.yml.j2 +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/templates/workflows/blind-review-artifacts-dry-run.yml.j2 +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/templates/workflows/code-mower-agent-pr-labeler.yml.j2 +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/templates/workflows/code-mower-fix-round-dispatch.yml.j2 +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/templates/workflows/code-mower-gate-health.yml.j2 +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/templates/workflows/code-mower-gate.yml.j2 +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/templates/workflows/dispatch-lanes.yml.j2 +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/templates/workflows/hosted-bridge.yml.j2 +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/templates/workflows/lane-mac-runner.yml.j2 +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/templates/workflows/local-cli-audit.yml.j2 +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/templates/workflows/private-standalone-shadow.yml.j2 +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/templates/workflows/review-clear-stale.yml.j2 +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/templates/workflows/saas-reviewer-labeler.yml.j2 +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/templates/workflows/self-hosted-local-audit.yml.j2 +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/templates/workflows/trailer-comment-labeler.yml.j2 +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_adoption_diagnostics.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_adoption_result_semantics.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_adoption_run_contract.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_antigravity_sdk_probe.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_audit_comment_posture.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_audit_limits.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_board.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_builder_experiment.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_builder_identity.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_builder_runs.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_calibration_effect_report.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_calibration_truth.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_campaign_discovery.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_checks.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_claude_audit_pr.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_claude_cli_bounce.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_clear_stale.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_cloud_client.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_cloud_git_metadata.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_cloud_manifest.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_cloud_reports.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_coderabbit_cli_audit_pr.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_codex_audit_env_preflight.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_codex_audit_pr.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_controller.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_decision_audit_integration.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_decisions.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_devin_builder_lane.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_devin_cli_audit_pr.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_doctor_actions_cost_summary.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_doctor_actions_failure_selection.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_doctor_boundaries.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_doctor_campaign_auth.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_doctor_github_checks.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_doctor_output.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_doctor_privacy.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_doctor_provider_env_required.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_doctor_provider_env_tokens.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_doctor_provider_local_audit_setup.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_doctor_provider_probe.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_doctor_provider_review_hygiene.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_doctor_registry.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_doctor_runtime.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_doctor_self_hosted_runner.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_doctor_supervised_pilot.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_file_locks.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_fork_pr_guard.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_gate_automerge.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_gate_health.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_init_actionlint.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_init_build_loop.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_lane_delivery_contract.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_lane_status.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_local_llm_github_helpers.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_migration_rehearsal.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_migration_setup_drift.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_next_steps.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_participant_sessions.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_plan_context.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_pr_outcome_contract.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_productivity_metrics_contract.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_productivity_report.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_prompts.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_provider_fixture_contracts.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_provider_local_cli.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_provider_runners_comments.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_provider_runners_git.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_provider_runners_github_pr.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_provider_runners_pr_worktree.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_provider_runners_process.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_provider_runners_repo_paths.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_provider_runners_text_schema.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_provider_runners_workspace.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_release_qualify.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_reviewer_metrics_core.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_reviewer_spend.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_supervised_pilot_contract.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_trailer_comment_labeler.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_work_orders.py +0 -0
- {code_mower-1.0.10 → code_mower-1.0.12}/tests/test_work_type_contract.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: code-mower
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.12
|
|
4
4
|
Summary: Multi-reviewer AI code audit orchestration
|
|
5
5
|
License-Expression: Apache-2.0
|
|
6
6
|
Project-URL: Homepage, https://github.com/codemower-ai/code-mower
|
|
@@ -241,7 +241,7 @@ agent report its actual host posture, exact installed version, doctor result,
|
|
|
241
241
|
Board URL, and any owner-only click-list before it mutates the repo.
|
|
242
242
|
|
|
243
243
|
The current package-index announcement entry point is the tagged
|
|
244
|
-
[Try Code Mower In 10 Minutes](https://github.com/codemower-ai/code-mower/blob/v1.0.
|
|
244
|
+
[Try Code Mower In 10 Minutes](https://github.com/codemower-ai/code-mower/blob/v1.0.12/docs/try-in-10-minutes.md)
|
|
245
245
|
guide. The v1.0 supervised-pilot release includes the native Board, the
|
|
246
246
|
controller dry-run and policy contract, adoption and upgrade hardening from
|
|
247
247
|
recent install rehearsals, package-index release checks, provider-diversity
|
|
@@ -285,6 +285,15 @@ provider-neutral delivery contract with bounded no-change and owner-action
|
|
|
285
285
|
outcomes, process-group cleanup so a finished provider is not reported as a
|
|
286
286
|
timeout, simpler first-run defaults, host-led participant sessions, and a
|
|
287
287
|
published 20-sample provider calibration scorecard.
|
|
288
|
+
The v1.0.11 patch moves canonical hosted Devin release campaigns onto the
|
|
289
|
+
bounded, pollable Sessions API transport and keeps macOS Claude release
|
|
290
|
+
qualification inside the maintained strict sandbox by using pip's
|
|
291
|
+
TLS-verifying certifi certificate path.
|
|
292
|
+
The v1.0.12 patch completes that Claude qualification fix: the maintained
|
|
293
|
+
provider qualification prompt no longer tells the agent to create its own
|
|
294
|
+
temporary directory, so it stays in the disposable workspace Code Mower
|
|
295
|
+
already created, and it states the existing contract that a result's total
|
|
296
|
+
`elapsed_seconds` is the sum of its step values.
|
|
288
297
|
Package-only users can start from the public package rather than a source
|
|
289
298
|
checkout.
|
|
290
299
|
|
|
@@ -317,7 +326,7 @@ Provider-contract baseline for the next release train:
|
|
|
317
326
|
|
|
318
327
|
For release verification,
|
|
319
328
|
[First-User Install Rehearsal](docs/first-user-install-rehearsal.md) records
|
|
320
|
-
the package-index procedure for `v1.0.
|
|
329
|
+
the package-index procedure for `v1.0.12` / `code-mower==1.0.12`. The
|
|
321
330
|
GitHub release records the workflow and rehearsal evidence for the exact tag.
|
|
322
331
|
After publication, [Release Qualification](docs/release-qualification.md)
|
|
323
332
|
coordinates provider-specific install and operational checks without treating
|
|
@@ -472,6 +481,10 @@ or informational until your own calibration data proves it is useful: Gitar,
|
|
|
472
481
|
Antigravity/Gemini, Muse, Hermes, CodeRabbit CLI, Cursor
|
|
473
482
|
BugBot, Qodo, Greptile, Devin, local LLMs, and future ACP bridges.
|
|
474
483
|
|
|
484
|
+
Hosted Devin dispatches use the Devin Sessions API v3. They require a service-user
|
|
485
|
+
`DEVIN_API_KEY`, its opaque `DEVIN_ORG_ID`, and an exact repository acknowledgement
|
|
486
|
+
in `CODE_MOWER_DEVIN_REPOSITORIES`; see `docs/release-qualification.md` for setup.
|
|
487
|
+
|
|
475
488
|
Gemini CLI and Antigravity are distinct lane ids even though both are Google
|
|
476
489
|
surfaces and may use Gemini model infrastructure. Keep their auth, model
|
|
477
490
|
provenance, calibration evidence, and release notes separate.
|
|
@@ -507,8 +520,8 @@ measurement work.
|
|
|
507
520
|
|
|
508
521
|
## Installation Status
|
|
509
522
|
|
|
510
|
-
The current package-index release baseline is `v1.0.
|
|
511
|
-
install spec `code-mower==1.0.
|
|
523
|
+
The current package-index release baseline is `v1.0.12`, with pinned package
|
|
524
|
+
install spec `code-mower==1.0.12`. Release evidence is recorded on the GitHub
|
|
512
525
|
release and in the first-user install rehearsal. The public repository is
|
|
513
526
|
[codemower-ai/code-mower](https://github.com/codemower-ai/code-mower), and
|
|
514
527
|
GitHub releases remain the auditable source for tags, build artifacts, and
|
|
@@ -587,6 +600,8 @@ first so local work exercises the same package entrypoint users install.
|
|
|
587
600
|
- [v1.0.8 Release Notes](docs/v108-release-notes.md)
|
|
588
601
|
- [v1.0.9 Release Notes](docs/v109-release-notes.md)
|
|
589
602
|
- [v1.0.10 Release Notes](docs/v1010-release-notes.md)
|
|
603
|
+
- [v1.0.11 Release Notes](docs/v1011-release-notes.md)
|
|
604
|
+
- [v1.0.12 Release Notes](docs/v1012-release-notes.md)
|
|
590
605
|
- [Post-v0.8 Effectiveness Assessment](docs/post-v08-effectiveness-assessment.md)
|
|
591
606
|
- [v1.0.1 Effectiveness Assessment](docs/v101-effectiveness-assessment.md)
|
|
592
607
|
- [Demo Calibration Example](examples/demo-calibration/README.md)
|
|
@@ -211,7 +211,7 @@ agent report its actual host posture, exact installed version, doctor result,
|
|
|
211
211
|
Board URL, and any owner-only click-list before it mutates the repo.
|
|
212
212
|
|
|
213
213
|
The current package-index announcement entry point is the tagged
|
|
214
|
-
[Try Code Mower In 10 Minutes](https://github.com/codemower-ai/code-mower/blob/v1.0.
|
|
214
|
+
[Try Code Mower In 10 Minutes](https://github.com/codemower-ai/code-mower/blob/v1.0.12/docs/try-in-10-minutes.md)
|
|
215
215
|
guide. The v1.0 supervised-pilot release includes the native Board, the
|
|
216
216
|
controller dry-run and policy contract, adoption and upgrade hardening from
|
|
217
217
|
recent install rehearsals, package-index release checks, provider-diversity
|
|
@@ -255,6 +255,15 @@ provider-neutral delivery contract with bounded no-change and owner-action
|
|
|
255
255
|
outcomes, process-group cleanup so a finished provider is not reported as a
|
|
256
256
|
timeout, simpler first-run defaults, host-led participant sessions, and a
|
|
257
257
|
published 20-sample provider calibration scorecard.
|
|
258
|
+
The v1.0.11 patch moves canonical hosted Devin release campaigns onto the
|
|
259
|
+
bounded, pollable Sessions API transport and keeps macOS Claude release
|
|
260
|
+
qualification inside the maintained strict sandbox by using pip's
|
|
261
|
+
TLS-verifying certifi certificate path.
|
|
262
|
+
The v1.0.12 patch completes that Claude qualification fix: the maintained
|
|
263
|
+
provider qualification prompt no longer tells the agent to create its own
|
|
264
|
+
temporary directory, so it stays in the disposable workspace Code Mower
|
|
265
|
+
already created, and it states the existing contract that a result's total
|
|
266
|
+
`elapsed_seconds` is the sum of its step values.
|
|
258
267
|
Package-only users can start from the public package rather than a source
|
|
259
268
|
checkout.
|
|
260
269
|
|
|
@@ -287,7 +296,7 @@ Provider-contract baseline for the next release train:
|
|
|
287
296
|
|
|
288
297
|
For release verification,
|
|
289
298
|
[First-User Install Rehearsal](docs/first-user-install-rehearsal.md) records
|
|
290
|
-
the package-index procedure for `v1.0.
|
|
299
|
+
the package-index procedure for `v1.0.12` / `code-mower==1.0.12`. The
|
|
291
300
|
GitHub release records the workflow and rehearsal evidence for the exact tag.
|
|
292
301
|
After publication, [Release Qualification](docs/release-qualification.md)
|
|
293
302
|
coordinates provider-specific install and operational checks without treating
|
|
@@ -442,6 +451,10 @@ or informational until your own calibration data proves it is useful: Gitar,
|
|
|
442
451
|
Antigravity/Gemini, Muse, Hermes, CodeRabbit CLI, Cursor
|
|
443
452
|
BugBot, Qodo, Greptile, Devin, local LLMs, and future ACP bridges.
|
|
444
453
|
|
|
454
|
+
Hosted Devin dispatches use the Devin Sessions API v3. They require a service-user
|
|
455
|
+
`DEVIN_API_KEY`, its opaque `DEVIN_ORG_ID`, and an exact repository acknowledgement
|
|
456
|
+
in `CODE_MOWER_DEVIN_REPOSITORIES`; see `docs/release-qualification.md` for setup.
|
|
457
|
+
|
|
445
458
|
Gemini CLI and Antigravity are distinct lane ids even though both are Google
|
|
446
459
|
surfaces and may use Gemini model infrastructure. Keep their auth, model
|
|
447
460
|
provenance, calibration evidence, and release notes separate.
|
|
@@ -477,8 +490,8 @@ measurement work.
|
|
|
477
490
|
|
|
478
491
|
## Installation Status
|
|
479
492
|
|
|
480
|
-
The current package-index release baseline is `v1.0.
|
|
481
|
-
install spec `code-mower==1.0.
|
|
493
|
+
The current package-index release baseline is `v1.0.12`, with pinned package
|
|
494
|
+
install spec `code-mower==1.0.12`. Release evidence is recorded on the GitHub
|
|
482
495
|
release and in the first-user install rehearsal. The public repository is
|
|
483
496
|
[codemower-ai/code-mower](https://github.com/codemower-ai/code-mower), and
|
|
484
497
|
GitHub releases remain the auditable source for tags, build artifacts, and
|
|
@@ -557,6 +570,8 @@ first so local work exercises the same package entrypoint users install.
|
|
|
557
570
|
- [v1.0.8 Release Notes](docs/v108-release-notes.md)
|
|
558
571
|
- [v1.0.9 Release Notes](docs/v109-release-notes.md)
|
|
559
572
|
- [v1.0.10 Release Notes](docs/v1010-release-notes.md)
|
|
573
|
+
- [v1.0.11 Release Notes](docs/v1011-release-notes.md)
|
|
574
|
+
- [v1.0.12 Release Notes](docs/v1012-release-notes.md)
|
|
560
575
|
- [Post-v0.8 Effectiveness Assessment](docs/post-v08-effectiveness-assessment.md)
|
|
561
576
|
- [v1.0.1 Effectiveness Assessment](docs/v101-effectiveness-assessment.md)
|
|
562
577
|
- [Demo Calibration Example](examples/demo-calibration/README.md)
|
|
@@ -57,6 +57,7 @@ import argparse
|
|
|
57
57
|
import copy
|
|
58
58
|
import json
|
|
59
59
|
import os
|
|
60
|
+
import platform
|
|
60
61
|
import shlex
|
|
61
62
|
import shutil
|
|
62
63
|
import subprocess
|
|
@@ -174,6 +175,58 @@ def _claude_sandbox_settings(package_source: str) -> dict[str, Any]:
|
|
|
174
175
|
"network": {"allowedDomains": list(allowed_domains)},
|
|
175
176
|
},
|
|
176
177
|
}
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
#: Strips ambient pip configuration from the disposable qualification install:
|
|
181
|
+
#: no inherited index URLs, no user/site pip configuration file, and pip's own
|
|
182
|
+
#: ``--isolated`` mode for every other ambient setting.
|
|
183
|
+
PIP_AMBIENT_CONFIG_STRIP = "env -u PIP_INDEX_URL -u PIP_EXTRA_INDEX_URL PIP_CONFIG_FILE=/dev/null"
|
|
184
|
+
PIP_ISOLATED_BASE = f"{PIP_AMBIENT_CONFIG_STRIP} .venv/bin/python -m pip --isolated"
|
|
185
|
+
PIP_DEFAULT_BASE = ".venv/bin/python -m pip"
|
|
186
|
+
#: pip 24.2+ verifies certificates through the platform trust store. On macOS
|
|
187
|
+
#: that path calls Security.framework, which the maintained strict Claude OS
|
|
188
|
+
#: sandbox denies (``OSStatus -26276``) even with the package index allowlisted.
|
|
189
|
+
#: ``legacy-certs`` keeps TLS verification fully enabled: it only moves pip back
|
|
190
|
+
#: to its bundled certifi trust store, which needs no Security.framework call.
|
|
191
|
+
PIP_LEGACY_CERTS_FLAG = "--use-deprecated=legacy-certs"
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def claude_macos_certificate_path_required(provider: str, *, platform_system: str = "") -> bool:
|
|
195
|
+
"""True only for a Claude campaign run on macOS.
|
|
196
|
+
|
|
197
|
+
This is the exact scope of the upstream Claude Code macOS sandbox
|
|
198
|
+
certificate-validation defect. Linux Claude runs and every other provider
|
|
199
|
+
keep pip's default certificate path.
|
|
200
|
+
"""
|
|
201
|
+
system = platform_system or platform.system()
|
|
202
|
+
return provider == "claude" and system.strip().lower() == "darwin"
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
def build_qualification_pip_command(
|
|
206
|
+
*,
|
|
207
|
+
provider: str,
|
|
208
|
+
package_source: str = DEFAULT_PACKAGE_SOURCE,
|
|
209
|
+
platform_system: str = "",
|
|
210
|
+
) -> str:
|
|
211
|
+
"""Return the pip command the qualification prompt tells the agent to run.
|
|
212
|
+
|
|
213
|
+
A macOS Claude run always gets the ambient-configuration strip as well as
|
|
214
|
+
:data:`PIP_LEGACY_CERTS_FLAG`, so the certificate path is chosen by this
|
|
215
|
+
adapter rather than by whatever pip configuration happens to be on the
|
|
216
|
+
host.
|
|
217
|
+
"""
|
|
218
|
+
legacy_certs = claude_macos_certificate_path_required(
|
|
219
|
+
provider, platform_system=platform_system
|
|
220
|
+
)
|
|
221
|
+
if package_source == "testpypi" or legacy_certs:
|
|
222
|
+
command = PIP_ISOLATED_BASE
|
|
223
|
+
else:
|
|
224
|
+
command = PIP_DEFAULT_BASE
|
|
225
|
+
if legacy_certs:
|
|
226
|
+
command = f"{command} {PIP_LEGACY_CERTS_FLAG}"
|
|
227
|
+
return command
|
|
228
|
+
|
|
229
|
+
|
|
177
230
|
ANTIGRAVITY_MODEL_ENV_NAMES = ("CODE_MOWER_ANTIGRAVITY_MODEL", "ANTIGRAVITY_MODEL")
|
|
178
231
|
ANTIGRAVITY_AMBIENT_HOME_ENV = "ANTIGRAVITY_CLI_USE_AMBIENT_HOME"
|
|
179
232
|
MUSE_MODEL_ENV_NAMES = ("CODE_MOWER_MUSE_MODEL", "MUSE_MODEL", "META_MUSE_MODEL")
|
|
@@ -385,6 +438,7 @@ def build_qualification_prompt(
|
|
|
385
438
|
package_source: str = DEFAULT_PACKAGE_SOURCE,
|
|
386
439
|
python_bin: str = "python3",
|
|
387
440
|
target_runtime: str = "",
|
|
441
|
+
platform_system: str = "",
|
|
388
442
|
) -> str:
|
|
389
443
|
"""Build the shared release-qualification prompt for one provider run.
|
|
390
444
|
|
|
@@ -394,14 +448,19 @@ def build_qualification_prompt(
|
|
|
394
448
|
directory it creates itself. ``package_source`` is the closed vocabulary
|
|
395
449
|
(``pypi``/``testpypi``); when it is ``testpypi`` the prompt keeps candidate
|
|
396
450
|
retrieval exclusive to TestPyPI and dependency resolution exclusive to
|
|
397
|
-
production PyPI.
|
|
451
|
+
production PyPI. ``platform_system`` defaults to the running host and
|
|
452
|
+
exists so the macOS-only Claude certificate path is testable off macOS.
|
|
398
453
|
"""
|
|
399
454
|
python_cmd = shlex.quote(python_bin or "python3")
|
|
455
|
+
legacy_certs = claude_macos_certificate_path_required(
|
|
456
|
+
provider, platform_system=platform_system
|
|
457
|
+
)
|
|
458
|
+
pip = build_qualification_pip_command(
|
|
459
|
+
provider=provider,
|
|
460
|
+
package_source=package_source,
|
|
461
|
+
platform_system=platform_system,
|
|
462
|
+
)
|
|
400
463
|
if package_source == "testpypi":
|
|
401
|
-
pip = (
|
|
402
|
-
"env -u PIP_INDEX_URL -u PIP_EXTRA_INDEX_URL PIP_CONFIG_FILE=/dev/null "
|
|
403
|
-
".venv/bin/python -m pip --isolated"
|
|
404
|
-
)
|
|
405
464
|
steps = [
|
|
406
465
|
"1. In the current disposable directory, run "
|
|
407
466
|
f"`{python_cmd} -m venv .venv`. Use only `.venv/bin/python` and installed "
|
|
@@ -438,11 +497,11 @@ def build_qualification_prompt(
|
|
|
438
497
|
"1. In the current disposable directory, run "
|
|
439
498
|
f"`{python_cmd} -m venv .venv`. Use only `.venv/bin/python` and installed "
|
|
440
499
|
"entry points for the remaining steps.\n"
|
|
441
|
-
f"2. Install the starting version with
|
|
500
|
+
f"2. Install the starting version with `{pip} install"
|
|
442
501
|
" "
|
|
443
502
|
f"{package_identity}=={starting_version}` to rehearse "
|
|
444
503
|
f"an upgrade from exactly that version.\n"
|
|
445
|
-
f'3. Upgrade with
|
|
504
|
+
f'3. Upgrade with `{pip} install "{package_spec}"`.'
|
|
446
505
|
)
|
|
447
506
|
verification_step = 4
|
|
448
507
|
else:
|
|
@@ -450,14 +509,15 @@ def build_qualification_prompt(
|
|
|
450
509
|
"1. In the current disposable directory, run "
|
|
451
510
|
f"`{python_cmd} -m venv .venv`. Use only `.venv/bin/python` and installed "
|
|
452
511
|
"entry points for the remaining steps.\n"
|
|
453
|
-
f"2. Install the exact release with
|
|
512
|
+
f"2. Install the exact release with `{pip} install"
|
|
454
513
|
f' "{package_spec}"`. No other version is acceptable.'
|
|
455
514
|
)
|
|
456
515
|
verification_step = 4
|
|
457
516
|
lines = [
|
|
458
517
|
f"You are the {provider} release-qualification agent for Code Mower.",
|
|
459
|
-
"Qualify exactly one release in
|
|
460
|
-
"
|
|
518
|
+
"Qualify exactly one release in the current disposable workspace.",
|
|
519
|
+
"Code Mower already created this workspace; do not create or change into",
|
|
520
|
+
"another temporary directory. Do not read or modify",
|
|
461
521
|
"any existing checkout, home directory, credential file, or environment",
|
|
462
522
|
"variable holding a secret. Never print secrets, tokens, file paths,",
|
|
463
523
|
"commands you ran, or raw logs in your final answer.",
|
|
@@ -472,6 +532,27 @@ def build_qualification_prompt(
|
|
|
472
532
|
"run and any call to them ends the session without a result.",
|
|
473
533
|
]
|
|
474
534
|
)
|
|
535
|
+
if legacy_certs:
|
|
536
|
+
# macOS-only Claude sandbox defect: pip's default trust store calls
|
|
537
|
+
# Security.framework, which this sandbox denies (OSStatus -26276).
|
|
538
|
+
lines.extend(
|
|
539
|
+
[
|
|
540
|
+
"Every pip command in the procedure below already carries "
|
|
541
|
+
f"`{PIP_LEGACY_CERTS_FLAG}`, because pip's default macOS trust",
|
|
542
|
+
"store is unreachable from this sandbox. Certificate verification",
|
|
543
|
+
"stays fully enabled; only the trust store changes. If this pip",
|
|
544
|
+
"build rejects that option as an invalid choice, rerun the identical",
|
|
545
|
+
"command without it and change nothing else. Never add",
|
|
546
|
+
"`--trusted-host`, never disable or skip TLS verification, and never",
|
|
547
|
+
"run any command outside the sandbox. If an install still fails",
|
|
548
|
+
"certificate verification, report the `package_install` step with",
|
|
549
|
+
"`failure_reason` `network`: a certificate-validation failure is",
|
|
550
|
+
"always `network`, never `sandbox_permission` and never",
|
|
551
|
+
"`package_index`. Use `package_index` only for an index response",
|
|
552
|
+
"that is not a certificate failure, such as a 404 or a missing",
|
|
553
|
+
"version.",
|
|
554
|
+
]
|
|
555
|
+
)
|
|
475
556
|
lines.extend(
|
|
476
557
|
[
|
|
477
558
|
"",
|
|
@@ -532,7 +613,8 @@ def build_qualification_prompt(
|
|
|
532
613
|
"the step status strings: fail if any status is fail;",
|
|
533
614
|
"pass_with_warnings if any status is warn or unavailable; otherwise",
|
|
534
615
|
"pass. In particular, all-pass steps require outcome pass. No extra",
|
|
535
|
-
"fields, no prose, no fences.",
|
|
616
|
+
"fields, no prose, no fences. Set total elapsed_seconds to the sum of",
|
|
617
|
+
"the step elapsed_seconds values (within one second for rounding).",
|
|
536
618
|
])
|
|
537
619
|
return "\n".join(lines) + "\n"
|
|
538
620
|
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Bounded Devin Sessions API v3 transport for release campaigns."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import copy
|
|
7
|
+
import hashlib
|
|
8
|
+
import json
|
|
9
|
+
import os
|
|
10
|
+
import re
|
|
11
|
+
import socket
|
|
12
|
+
import urllib.error
|
|
13
|
+
import urllib.request
|
|
14
|
+
from typing import Any, Callable, Mapping
|
|
15
|
+
|
|
16
|
+
from .campaign_adapters import (
|
|
17
|
+
ADOPTION_RESULT_JSON_SCHEMA,
|
|
18
|
+
DEFAULT_PACKAGE_SOURCE,
|
|
19
|
+
build_qualification_prompt,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
API_BASE = "https://api.devin.ai"
|
|
23
|
+
DEVIN_API_KEY_ENV = "DEVIN_API_KEY"
|
|
24
|
+
DEVIN_ORG_ID_ENV = "DEVIN_ORG_ID"
|
|
25
|
+
DEVIN_REPOSITORIES_ENV = "CODE_MOWER_DEVIN_REPOSITORIES"
|
|
26
|
+
REQUEST_TIMEOUT_SECONDS = 30.0
|
|
27
|
+
MAX_RESPONSE_BYTES = 512 * 1024
|
|
28
|
+
|
|
29
|
+
_ORG_ID_RE = re.compile(r"^org-[A-Za-z0-9_-]+$")
|
|
30
|
+
# Session ids are opaque API references. Accept any bounded RFC 3986
|
|
31
|
+
# unreserved token instead of assuming Devin will retain one prefix forever.
|
|
32
|
+
_SESSION_ID_RE = re.compile(r"^[A-Za-z0-9][A-Za-z0-9._~-]{0,127}$")
|
|
33
|
+
_REPO_RE = re.compile(r"^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$")
|
|
34
|
+
|
|
35
|
+
SAFE_ERROR_CODES = frozenset(
|
|
36
|
+
{
|
|
37
|
+
"devin_api_rejected",
|
|
38
|
+
"devin_api_unavailable",
|
|
39
|
+
"devin_session_failed",
|
|
40
|
+
"devin_waiting_for_owner",
|
|
41
|
+
"hosted_result_rejected",
|
|
42
|
+
}
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
ApiRunner = Callable[[str, str, Mapping[str, Any] | None, Mapping[str, str]], Any]
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class DevinApiError(Exception):
|
|
49
|
+
"""API failure carrying only a closed, persistence-safe reason code."""
|
|
50
|
+
|
|
51
|
+
def __init__(self, code: str) -> None:
|
|
52
|
+
self.code = code if code in SAFE_ERROR_CODES else "devin_api_unavailable"
|
|
53
|
+
super().__init__(self.code)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def _validate_org_id(org_id: str) -> bool:
|
|
57
|
+
return bool(_ORG_ID_RE.fullmatch(org_id))
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def _validate_session_id(session_id: str) -> bool:
|
|
61
|
+
return bool(_SESSION_ID_RE.fullmatch(session_id))
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def repository_scope_acknowledged(
|
|
65
|
+
repo_slug: str,
|
|
66
|
+
*,
|
|
67
|
+
env: Mapping[str, str] | None = None,
|
|
68
|
+
) -> bool:
|
|
69
|
+
"""Require an exact local acknowledgement for the requested GitHub repo.
|
|
70
|
+
|
|
71
|
+
Devin v3 accepts an exact ``repos`` list on create but exposes no read-only
|
|
72
|
+
endpoint that proves GitHub connection scope before paid work starts. This
|
|
73
|
+
local acknowledgement closes that gap. The full configured inventory is
|
|
74
|
+
never returned, printed, persisted, or uploaded.
|
|
75
|
+
"""
|
|
76
|
+
if not _REPO_RE.fullmatch(repo_slug):
|
|
77
|
+
return False
|
|
78
|
+
current_env = os.environ if env is None else env
|
|
79
|
+
configured = {
|
|
80
|
+
item.strip().casefold()
|
|
81
|
+
for item in str(current_env.get(DEVIN_REPOSITORIES_ENV) or "").split(",")
|
|
82
|
+
if item.strip()
|
|
83
|
+
}
|
|
84
|
+
return repo_slug.casefold() in configured
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def credentials_from_env(
|
|
88
|
+
env: Mapping[str, str] | None = None,
|
|
89
|
+
) -> tuple[str, str, str]:
|
|
90
|
+
"""Return ``(api_key, org_id, missing_variable)`` without logging values."""
|
|
91
|
+
current_env = os.environ if env is None else env
|
|
92
|
+
api_key = str(current_env.get(DEVIN_API_KEY_ENV) or "").strip()
|
|
93
|
+
org_id = str(current_env.get(DEVIN_ORG_ID_ENV) or "").strip()
|
|
94
|
+
if not api_key:
|
|
95
|
+
return "", "", DEVIN_API_KEY_ENV
|
|
96
|
+
if not org_id:
|
|
97
|
+
return "", "", DEVIN_ORG_ID_ENV
|
|
98
|
+
if not _validate_org_id(org_id):
|
|
99
|
+
return "", "", DEVIN_ORG_ID_ENV
|
|
100
|
+
return api_key, org_id, ""
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def make_api_request(
|
|
104
|
+
method: str,
|
|
105
|
+
path: str,
|
|
106
|
+
api_key: str,
|
|
107
|
+
body: Mapping[str, Any] | None = None,
|
|
108
|
+
*,
|
|
109
|
+
api_runner: ApiRunner | None = None,
|
|
110
|
+
request_timeout: float = REQUEST_TIMEOUT_SECONDS,
|
|
111
|
+
) -> dict[str, Any]:
|
|
112
|
+
"""Make one request and return a bounded JSON object.
|
|
113
|
+
|
|
114
|
+
The injected runner keeps tests entirely offline. Raw error bodies and
|
|
115
|
+
exception messages never cross this boundary.
|
|
116
|
+
"""
|
|
117
|
+
url = f"{API_BASE}{path}"
|
|
118
|
+
headers = {"Authorization": f"Bearer {api_key}", "Accept": "application/json"}
|
|
119
|
+
if body is not None:
|
|
120
|
+
headers["Content-Type"] = "application/json"
|
|
121
|
+
try:
|
|
122
|
+
if api_runner is not None:
|
|
123
|
+
value = api_runner(method, url, body, headers)
|
|
124
|
+
else:
|
|
125
|
+
encoded = (
|
|
126
|
+
json.dumps(dict(body), separators=(",", ":")).encode("utf-8")
|
|
127
|
+
if body is not None
|
|
128
|
+
else None
|
|
129
|
+
)
|
|
130
|
+
request = urllib.request.Request(url, data=encoded, headers=headers, method=method)
|
|
131
|
+
with urllib.request.urlopen(request, timeout=request_timeout) as response:
|
|
132
|
+
raw = response.read(MAX_RESPONSE_BYTES + 1)
|
|
133
|
+
if len(raw) > MAX_RESPONSE_BYTES:
|
|
134
|
+
raise DevinApiError("devin_api_unavailable")
|
|
135
|
+
value = json.loads(raw.decode("utf-8"))
|
|
136
|
+
except DevinApiError:
|
|
137
|
+
raise
|
|
138
|
+
except urllib.error.HTTPError as exc:
|
|
139
|
+
code = "devin_api_rejected" if 400 <= exc.code < 500 else "devin_api_unavailable"
|
|
140
|
+
raise DevinApiError(code) from exc
|
|
141
|
+
except (urllib.error.URLError, socket.timeout, TimeoutError, OSError, ValueError) as exc:
|
|
142
|
+
raise DevinApiError("devin_api_unavailable") from exc
|
|
143
|
+
if not isinstance(value, dict):
|
|
144
|
+
raise DevinApiError("devin_api_unavailable")
|
|
145
|
+
return dict(value)
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def build_devin_session_payload(
|
|
149
|
+
*,
|
|
150
|
+
campaign_id: str,
|
|
151
|
+
release_tag: str,
|
|
152
|
+
package_spec: str,
|
|
153
|
+
package_identity: str,
|
|
154
|
+
normalized_version: str,
|
|
155
|
+
qualification_context: str,
|
|
156
|
+
starting_version: str,
|
|
157
|
+
repo_slug: str,
|
|
158
|
+
package_source: str = DEFAULT_PACKAGE_SOURCE,
|
|
159
|
+
target_runtime: str = "",
|
|
160
|
+
) -> dict[str, Any]:
|
|
161
|
+
"""Build the exact-repo create body using Devin's v3 field names."""
|
|
162
|
+
if not _REPO_RE.fullmatch(repo_slug):
|
|
163
|
+
raise ValueError("repo_slug must be OWNER/REPO")
|
|
164
|
+
prompt = build_qualification_prompt(
|
|
165
|
+
provider="devin",
|
|
166
|
+
release_tag=release_tag,
|
|
167
|
+
package_spec=package_spec,
|
|
168
|
+
package_identity=package_identity,
|
|
169
|
+
normalized_version=normalized_version,
|
|
170
|
+
qualification_context=qualification_context,
|
|
171
|
+
starting_version=starting_version,
|
|
172
|
+
package_source=package_source,
|
|
173
|
+
python_bin="python3",
|
|
174
|
+
target_runtime=target_runtime,
|
|
175
|
+
)
|
|
176
|
+
reconciliation_tag = hashlib.sha256(
|
|
177
|
+
f"{campaign_id}:{release_tag}:{repo_slug}".encode("utf-8")
|
|
178
|
+
).hexdigest()[:16]
|
|
179
|
+
return {
|
|
180
|
+
"prompt": prompt,
|
|
181
|
+
"repos": [repo_slug],
|
|
182
|
+
"structured_output_required": True,
|
|
183
|
+
"structured_output_schema": copy.deepcopy(ADOPTION_RESULT_JSON_SCHEMA),
|
|
184
|
+
"tags": ["code-mower", "release-qualification", f"cm-{reconciliation_tag}"],
|
|
185
|
+
"title": f"Code Mower {release_tag} qualification"[:128],
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def create_devin_session(
|
|
190
|
+
org_id: str,
|
|
191
|
+
payload: Mapping[str, Any],
|
|
192
|
+
api_key: str,
|
|
193
|
+
*,
|
|
194
|
+
api_runner: ApiRunner | None = None,
|
|
195
|
+
) -> tuple[str, str]:
|
|
196
|
+
"""Create one paid session, returning a bounded reason on failure."""
|
|
197
|
+
if not _validate_org_id(org_id):
|
|
198
|
+
return "", "devin_api_rejected"
|
|
199
|
+
try:
|
|
200
|
+
data = make_api_request(
|
|
201
|
+
"POST",
|
|
202
|
+
f"/v3/organizations/{org_id}/sessions",
|
|
203
|
+
api_key,
|
|
204
|
+
payload,
|
|
205
|
+
api_runner=api_runner,
|
|
206
|
+
)
|
|
207
|
+
except DevinApiError as exc:
|
|
208
|
+
return "", exc.code
|
|
209
|
+
session_id = data.get("session_id")
|
|
210
|
+
if not isinstance(session_id, str) or not _validate_session_id(session_id):
|
|
211
|
+
return "", "devin_api_unavailable"
|
|
212
|
+
return session_id, ""
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def poll_devin_session(
|
|
216
|
+
org_id: str,
|
|
217
|
+
session_id: str,
|
|
218
|
+
api_key: str,
|
|
219
|
+
*,
|
|
220
|
+
api_runner: ApiRunner | None = None,
|
|
221
|
+
) -> tuple[str, dict[str, Any] | None, str]:
|
|
222
|
+
"""Read one session snapshot.
|
|
223
|
+
|
|
224
|
+
Returns ``(state, structured_output, reason)`` where state is one of
|
|
225
|
+
``running``, ``complete``, ``owner_action``, or ``failed``. Campaign watch
|
|
226
|
+
owns repeated polling and the one-hour deadline.
|
|
227
|
+
"""
|
|
228
|
+
if not _validate_org_id(org_id) or not _validate_session_id(session_id):
|
|
229
|
+
return "failed", None, "devin_api_rejected"
|
|
230
|
+
try:
|
|
231
|
+
data = make_api_request(
|
|
232
|
+
"GET",
|
|
233
|
+
f"/v3/organizations/{org_id}/sessions/{session_id}",
|
|
234
|
+
api_key,
|
|
235
|
+
api_runner=api_runner,
|
|
236
|
+
)
|
|
237
|
+
except DevinApiError as exc:
|
|
238
|
+
return "failed", None, exc.code
|
|
239
|
+
status = str(data.get("status") or "")
|
|
240
|
+
detail = str(data.get("status_detail") or "")
|
|
241
|
+
if detail in {"waiting_for_user", "waiting_for_approval"}:
|
|
242
|
+
return "owner_action", None, "devin_waiting_for_owner"
|
|
243
|
+
if status == "exit" or detail == "finished":
|
|
244
|
+
result = data.get("structured_output")
|
|
245
|
+
if isinstance(result, dict):
|
|
246
|
+
return "complete", dict(result), ""
|
|
247
|
+
return "failed", None, "hosted_result_rejected"
|
|
248
|
+
if status in {"error", "suspended"} or detail in {
|
|
249
|
+
"error",
|
|
250
|
+
"usage_limit_exceeded",
|
|
251
|
+
"out_of_credits",
|
|
252
|
+
"out_of_quota",
|
|
253
|
+
"no_quota_allocation",
|
|
254
|
+
"payment_declined",
|
|
255
|
+
"org_usage_limit_exceeded",
|
|
256
|
+
"total_session_limit_exceeded",
|
|
257
|
+
}:
|
|
258
|
+
return "failed", None, "devin_session_failed"
|
|
259
|
+
return "running", None, ""
|
|
@@ -933,12 +933,12 @@ def check_adoption_campaign_readiness(
|
|
|
933
933
|
elif lane.driver in {"hosted_bridge", "saas_event"}:
|
|
934
934
|
has_credentials, missing_var = _check_credentials(lane, env=current_env)
|
|
935
935
|
transport_ready, transport_var = _check_hosted_transport(
|
|
936
|
-
lane, env=current_env
|
|
936
|
+
lane, env=current_env, repo_slug=repo_slug
|
|
937
937
|
)
|
|
938
938
|
# Closed dispatch profile: auth, installation, trigger,
|
|
939
939
|
# trusted responder, and result return are reported
|
|
940
940
|
# independently, so one verified dimension never masks another.
|
|
941
|
-
dispatch_profile = hosted_dispatch_profile(lane, env=current_env)
|
|
941
|
+
dispatch_profile = hosted_dispatch_profile(lane, env=current_env, repo_slug=repo_slug)
|
|
942
942
|
dispatch_blockers = hosted_dispatch_blockers(dispatch_profile)
|
|
943
943
|
dispatch_summary = {
|
|
944
944
|
name: bool(entry.get("ready")) for name, entry in dispatch_profile.items()
|
|
@@ -1034,8 +1034,12 @@ def check_adoption_campaign_readiness(
|
|
|
1034
1034
|
message=f"{canonical} hosted campaign transport is not verified",
|
|
1035
1035
|
detail=detail,
|
|
1036
1036
|
remediation=(
|
|
1037
|
-
|
|
1038
|
-
|
|
1037
|
+
str(
|
|
1038
|
+
dispatch_profile.get("installation", {}).get(
|
|
1039
|
+
"remediation"
|
|
1040
|
+
)
|
|
1041
|
+
)
|
|
1042
|
+
or f"Verify {canonical} transport for {repo_slug}."
|
|
1039
1043
|
),
|
|
1040
1044
|
)
|
|
1041
1045
|
)
|
|
@@ -195,7 +195,29 @@ def classify_package_install_failure(*, exception: Exception, steps: list[dict[s
|
|
|
195
195
|
"operation not permitted",
|
|
196
196
|
)
|
|
197
197
|
|
|
198
|
+
# Certificate-validation failures: the transport could not establish trust.
|
|
199
|
+
# These are checked ahead of every other category, so a certificate failure
|
|
200
|
+
# is always `network`. It outranks the permission indicators because a
|
|
201
|
+
# platform trust store evaluated inside a strict OS sandbox (macOS
|
|
202
|
+
# Security.framework reports OSStatus -26276) fails with wording that also
|
|
203
|
+
# matches "operation not permitted"/EPERM, and it outranks the index
|
|
204
|
+
# indicators because an untrusted connection served nothing to classify.
|
|
205
|
+
# `package_index` stays the reason for a non-certificate index response.
|
|
206
|
+
certificate_indicators = (
|
|
207
|
+
"certificate verify failed",
|
|
208
|
+
"certificate_verify_failed",
|
|
209
|
+
"sslcertverificationerror",
|
|
210
|
+
"osstatus -26276",
|
|
211
|
+
"sectrustevaluate",
|
|
212
|
+
"unable to get local issuer certificate",
|
|
213
|
+
"self signed certificate",
|
|
214
|
+
"self-signed certificate",
|
|
215
|
+
)
|
|
216
|
+
|
|
198
217
|
# Check in priority order: most specific first
|
|
218
|
+
if any(indicator in error_text for indicator in certificate_indicators):
|
|
219
|
+
return "network"
|
|
220
|
+
|
|
199
221
|
if any(indicator in error_text for indicator in sandbox_permission_indicators):
|
|
200
222
|
return "sandbox_permission"
|
|
201
223
|
|
|
@@ -276,6 +276,7 @@ PACKAGE_FILES = (
|
|
|
276
276
|
("tools/code_mower_prompts.py", "src/code_mower/prompts.py", "core"),
|
|
277
277
|
("src/code_mower/release_qualify.py", "src/code_mower/release_qualify.py", "core"),
|
|
278
278
|
("src/code_mower/release_campaigns.py", "src/code_mower/release_campaigns.py", "core"),
|
|
279
|
+
("src/code_mower/devin_api.py", "src/code_mower/devin_api.py", "core"),
|
|
279
280
|
("src/code_mower/campaign_discovery.py", "src/code_mower/campaign_discovery.py", "core"),
|
|
280
281
|
("src/code_mower/campaign_adapters.py", "src/code_mower/campaign_adapters.py", "core"),
|
|
281
282
|
("src/code_mower/release_readiness.py", "src/code_mower/release_readiness.py", "core"),
|
|
@@ -226,11 +226,14 @@ REFERENCE_PROVIDERS: dict[str, ProviderLane] = {
|
|
|
226
226
|
trigger_policy="manual",
|
|
227
227
|
spend_policy="paid",
|
|
228
228
|
provider_config={
|
|
229
|
-
"
|
|
230
|
-
"
|
|
231
|
-
"
|
|
232
|
-
"campaign_transport_ready_env": "CODE_MOWER_DEVIN_CAMPAIGN_TRANSPORT_READY",
|
|
229
|
+
"campaign_transport": "devin_api_v3",
|
|
230
|
+
"campaign_required_env_all": ("DEVIN_API_KEY", "DEVIN_ORG_ID"),
|
|
231
|
+
"campaign_repository_scope_env": "CODE_MOWER_DEVIN_REPOSITORIES",
|
|
233
232
|
"campaign_response_timeout_seconds": 3600,
|
|
233
|
+
"status": (
|
|
234
|
+
"hosted Devin v3 Sessions API transport; "
|
|
235
|
+
"issue marker is optional audit evidence"
|
|
236
|
+
),
|
|
234
237
|
},
|
|
235
238
|
),
|
|
236
239
|
"greptile": ProviderLane(
|