pi-dev-team 0.2.0
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.
- package/LICENSE +21 -0
- package/PORTING.md +134 -0
- package/README.md +207 -0
- package/UPSTREAM.json +64 -0
- package/agents/Explore.md +15 -0
- package/agents/a11y-review.md +118 -0
- package/agents/adr-author.md +70 -0
- package/agents/ai-provenance-review.md +120 -0
- package/agents/angular-reactivity-review.md +95 -0
- package/agents/arch-review.md +135 -0
- package/agents/architect.md +78 -0
- package/agents/autoship-batch-proposer.md +69 -0
- package/agents/claude-setup-review.md +136 -0
- package/agents/codebase-recon.md +184 -0
- package/agents/component-architecture-review.md +119 -0
- package/agents/concurrency-review.md +109 -0
- package/agents/correctness-review.md +290 -0
- package/agents/data-flow-tracer.md +120 -0
- package/agents/doc-review.md +165 -0
- package/agents/domain-review.md +136 -0
- package/agents/general-purpose.md +10 -0
- package/agents/gherkin-quality-critic.md +113 -0
- package/agents/js-fp-review.md +114 -0
- package/agents/mutation-kill.md +684 -0
- package/agents/naming-review.md +142 -0
- package/agents/orchestrator.md +339 -0
- package/agents/performance-review.md +105 -0
- package/agents/plan-review-acceptance.md +115 -0
- package/agents/plan-review-design.md +90 -0
- package/agents/plan-review-parallelization.md +84 -0
- package/agents/plan-review-strategic.md +96 -0
- package/agents/plan-review-ux.md +110 -0
- package/agents/platform-engineer.md +64 -0
- package/agents/product-manager.md +68 -0
- package/agents/progress-guardian.md +79 -0
- package/agents/qa-engineer.md +289 -0
- package/agents/quality-reviewer.md +132 -0
- package/agents/react-reactivity-review.md +102 -0
- package/agents/refactor-opportunity-review.md +128 -0
- package/agents/security-engineer.md +60 -0
- package/agents/security-review.md +218 -0
- package/agents/session-analysis.md +95 -0
- package/agents/software-engineer.md +105 -0
- package/agents/spec-compliance-review.md +100 -0
- package/agents/spec-reviewer.md +114 -0
- package/agents/structure-review.md +146 -0
- package/agents/tech-writer.md +84 -0
- package/agents/test-review.md +246 -0
- package/agents/test-smell-review.md +188 -0
- package/agents/token-efficiency-review.md +139 -0
- package/agents/ui-ux-designer.md +54 -0
- package/agents/vue-reactivity-review.md +95 -0
- package/bin/__pycache__/claudecpython-314.pyc +0 -0
- package/bin/claude +258 -0
- package/docs/upstream/.pages +1 -0
- package/docs/upstream/CHANGELOG.md +2586 -0
- package/docs/upstream/README.md +155 -0
- package/docs/upstream/agent-architecture.md +214 -0
- package/docs/upstream/agent_info.md +187 -0
- package/docs/upstream/artifact-migration.md +124 -0
- package/docs/upstream/code-intelligence-nudge.md +149 -0
- package/docs/upstream/code-review-process.md +294 -0
- package/docs/upstream/concurrent-use.md +73 -0
- package/docs/upstream/context-management.md +111 -0
- package/docs/upstream/developer-notes.md +280 -0
- package/docs/upstream/diagrams/architecture-overview.svg +101 -0
- package/docs/upstream/diagrams/review-dispatch.svg +139 -0
- package/docs/upstream/diagrams/team-agents.svg +128 -0
- package/docs/upstream/diagrams/test-improve-flow.svg +166 -0
- package/docs/upstream/diagrams/workflow-linear.svg +66 -0
- package/docs/upstream/diagrams/workflow-three-phase.svg +200 -0
- package/docs/upstream/eval-maintenance.md +95 -0
- package/docs/upstream/eval-running-guide.md +147 -0
- package/docs/upstream/eval-system.md +291 -0
- package/docs/upstream/session-review-oss-complements.md +75 -0
- package/docs/upstream/session-review.md +212 -0
- package/docs/upstream/skills.md +188 -0
- package/docs/upstream/team-structure.md +21 -0
- package/docs/upstream/telemetry-ci-access.md +129 -0
- package/docs/upstream/telemetry-repo-security.md +120 -0
- package/docs/upstream/test-evaluation.md +277 -0
- package/docs/upstream/test-improve.md +154 -0
- package/docs/upstream/triage-workflow.md +282 -0
- package/docs/upstream/workflows.md +289 -0
- package/extensions/dev-team/index.ts +539 -0
- package/extensions/dev-team/lib/agents.ts +272 -0
- package/extensions/dev-team/lib/ai-credits.ts +92 -0
- package/extensions/dev-team/lib/autocompact.ts +81 -0
- package/extensions/dev-team/lib/child-run.ts +102 -0
- package/extensions/dev-team/lib/config.ts +236 -0
- package/extensions/dev-team/lib/gh-command.ts +103 -0
- package/extensions/dev-team/lib/github-style.ts +307 -0
- package/extensions/dev-team/lib/hooks.ts +350 -0
- package/extensions/dev-team/lib/metrics.ts +115 -0
- package/extensions/dev-team/lib/safe-read.ts +49 -0
- package/extensions/dev-team/lib/session-files.ts +57 -0
- package/extensions/dev-team/lib/session-spend.ts +123 -0
- package/extensions/dev-team/lib/shell-scan.ts +205 -0
- package/extensions/dev-team/lib/skills.ts +213 -0
- package/extensions/dev-team/lib/subagent-render.ts +245 -0
- package/extensions/dev-team/lib/subagent-types.ts +164 -0
- package/extensions/dev-team/lib/subagent.ts +596 -0
- package/extensions/dev-team/lib/terminal-text.ts +54 -0
- package/extensions/dev-team/lib/tools-misc.ts +152 -0
- package/extensions/dev-team/lib/transcript.ts +110 -0
- package/extensions/dev-team/lib/trust.ts +52 -0
- package/extensions/dev-team/lib/usage-breakdown.ts +176 -0
- package/extensions/dev-team/lib/usage-chart.ts +153 -0
- package/extensions/dev-team/lib/usage-command.ts +107 -0
- package/extensions/dev-team/lib/usage-history.ts +203 -0
- package/extensions/dev-team/lib/usage-render.ts +225 -0
- package/extensions/dev-team/lib/usage-split-bar.ts +127 -0
- package/extensions/dev-team/lib/usage-state.ts +116 -0
- package/extensions/dev-team/lib/usage-text.ts +159 -0
- package/extensions/dev-team/lib/usage-view.ts +109 -0
- package/hooks/__pycache__/refactor_test_freeze_guard.cpython-314.pyc +0 -0
- package/hooks/agent_dispatch_ledger.py +190 -0
- package/hooks/autocompact_setup_nudge.py +99 -0
- package/hooks/bash_retry_guard.py +228 -0
- package/hooks/boundary_events_write_guard.py +352 -0
- package/hooks/code_intelligence_nudge.py +293 -0
- package/hooks/code_intelligence_turn_mark.py +317 -0
- package/hooks/codegraph_bootstrap.py +139 -0
- package/hooks/contract_version_guard.py +362 -0
- package/hooks/cost_meter.py +106 -0
- package/hooks/destructive-commands.json +62 -0
- package/hooks/destructive_guard.py +477 -0
- package/hooks/eval_compliance_check.py +440 -0
- package/hooks/guards.json +17 -0
- package/hooks/hooks.json +323 -0
- package/hooks/internal_double_gate.py +296 -0
- package/hooks/js_fp_review.py +212 -0
- package/hooks/knowledge_index.py +119 -0
- package/hooks/lib/__pycache__/artifact_paths.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/atomic_state.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/autocompact_config.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/boundary_events.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/doc_classification.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/gh_pr_create_detect.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/git_safe_diff.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/instrument_log.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/metrics_query.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/plugin_version.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/pre_commit_doc_classifier.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/review_agent_registry.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/review_gate_corroboration.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/review_gate_hash.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/review_verdicts.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/stdin_json.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/stryker_invocation.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/telemetry_consent.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/test_file_classify.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/token_efficiency_limits.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/verify_guard_state.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/xunit_v3_operator_gate.cpython-314.pyc +0 -0
- package/hooks/lib/agent_skill_hints.py +74 -0
- package/hooks/lib/artifact_paths.py +263 -0
- package/hooks/lib/atomic_state.py +557 -0
- package/hooks/lib/autocompact_config.py +103 -0
- package/hooks/lib/autoship_log.py +106 -0
- package/hooks/lib/banned_scripts_policy.py +51 -0
- package/hooks/lib/boundary_events.py +436 -0
- package/hooks/lib/build_knowledge_index.py +504 -0
- package/hooks/lib/build_skills_index.py +361 -0
- package/hooks/lib/build_state.py +116 -0
- package/hooks/lib/classify_ship_outcome.py +126 -0
- package/hooks/lib/config_changelog_schema.py +115 -0
- package/hooks/lib/cost_meter.py +955 -0
- package/hooks/lib/doc_classification.py +116 -0
- package/hooks/lib/gh_pr_create_detect.py +136 -0
- package/hooks/lib/git_safe_diff.py +123 -0
- package/hooks/lib/instrument_log.py +66 -0
- package/hooks/lib/iteration_journal_gate.py +197 -0
- package/hooks/lib/knowledge_index_paths.py +88 -0
- package/hooks/lib/mcp_json_repowise.py +177 -0
- package/hooks/lib/metrics_query.py +202 -0
- package/hooks/lib/minimal_yaml.py +434 -0
- package/hooks/lib/plugin_version.py +142 -0
- package/hooks/lib/pre_commit_detect.py +537 -0
- package/hooks/lib/pre_commit_doc_classifier.py +126 -0
- package/hooks/lib/pricing.py +118 -0
- package/hooks/lib/report_pdf.py +371 -0
- package/hooks/lib/review_agent_registry.py +142 -0
- package/hooks/lib/review_dispatch_ledger.py +101 -0
- package/hooks/lib/review_gate_corroboration.py +521 -0
- package/hooks/lib/review_gate_hash.py +252 -0
- package/hooks/lib/review_gate_normalized_hash.py +1115 -0
- package/hooks/lib/review_verdicts.py +301 -0
- package/hooks/lib/run_report.py +160 -0
- package/hooks/lib/skill_categories.yaml +125 -0
- package/hooks/lib/stdin_json.py +57 -0
- package/hooks/lib/stryker_invocation.py +102 -0
- package/hooks/lib/telemetry_consent.py +41 -0
- package/hooks/lib/telemetry_report.py +108 -0
- package/hooks/lib/test_file_classify.py +160 -0
- package/hooks/lib/token_efficiency_limits.py +51 -0
- package/hooks/lib/turn_identity.py +77 -0
- package/hooks/lib/verify_guard_state.py +110 -0
- package/hooks/lib/workflow_state.py +206 -0
- package/hooks/lib/xunit_v3_operator_gate.py +596 -0
- package/hooks/mcp_json_repowise_nudge.py +74 -0
- package/hooks/mutation_adapters/__init__.py +7 -0
- package/hooks/mutation_adapters/__pycache__/__init__.cpython-314.pyc +0 -0
- package/hooks/mutation_adapters/__pycache__/lib.cpython-314.pyc +0 -0
- package/hooks/mutation_adapters/__pycache__/mutmut.cpython-314.pyc +0 -0
- package/hooks/mutation_adapters/__pycache__/pitest.cpython-314.pyc +0 -0
- package/hooks/mutation_adapters/__pycache__/stryker.cpython-314.pyc +0 -0
- package/hooks/mutation_adapters/__pycache__/stryker_net.cpython-314.pyc +0 -0
- package/hooks/mutation_adapters/lib.py +478 -0
- package/hooks/mutation_adapters/mutmut.py +188 -0
- package/hooks/mutation_adapters/pitest.py +266 -0
- package/hooks/mutation_adapters/stryker.py +157 -0
- package/hooks/mutation_adapters/stryker_net.py +264 -0
- package/hooks/mutation_gate.py +193 -0
- package/hooks/mutation_testing_smoke_gate.py +371 -0
- package/hooks/pending_review_notify.py +121 -0
- package/hooks/phase_marker.py +138 -0
- package/hooks/post_compact_state_reinject.py +180 -0
- package/hooks/post_format.py +115 -0
- package/hooks/pre_commit_knowledge_index.py +128 -0
- package/hooks/pre_commit_review.py +66 -0
- package/hooks/pre_pr_review.py +694 -0
- package/hooks/pre_tool_guard.py +405 -0
- package/hooks/py.sh +73 -0
- package/hooks/refactor-bash-write-patterns.json +29 -0
- package/hooks/refactor_test_bash_guard.py +253 -0
- package/hooks/refactor_test_freeze_guard.py +139 -0
- package/hooks/refactor_test_revert_guard.py +186 -0
- package/hooks/repo_review_nudge.py +287 -0
- package/hooks/review_verdict_recorder.py +464 -0
- package/hooks/scan_bash_command_for_banned_scripts.py +428 -0
- package/hooks/scan_worktree_for_banned_scripts.py +238 -0
- package/hooks/session_learning_trigger.py +248 -0
- package/hooks/skills_index.py +126 -0
- package/hooks/stryker_xunit_shim_guard.py +571 -0
- package/hooks/subagent_completion_guard.py +309 -0
- package/hooks/subagent_skill_context.py +139 -0
- package/hooks/task_completion_metrics.py +216 -0
- package/hooks/tdd_guard.py +229 -0
- package/hooks/telemetry.py +341 -0
- package/hooks/token_efficiency_review.py +194 -0
- package/hooks/verify_guard.py +183 -0
- package/hooks/verify_guard_edit_marker.py +73 -0
- package/hooks/version_check.py +173 -0
- package/knowledge/accepted-risks-schema.md +98 -0
- package/knowledge/adr-decision-criteria.md +64 -0
- package/knowledge/adversarial-review-protocol.md +139 -0
- package/knowledge/agent-registry.md +228 -0
- package/knowledge/agent-review-methodology.md +80 -0
- package/knowledge/ai-friendly-repo-guidelines.md +67 -0
- package/knowledge/architecture-assessment.md +96 -0
- package/knowledge/artifact-lifecycle.md +57 -0
- package/knowledge/cd-maturity-model.md +82 -0
- package/knowledge/cd-test-architecture.md +190 -0
- package/knowledge/ci-cd-file-scope.md +24 -0
- package/knowledge/codegraph-vs-graphify.md +192 -0
- package/knowledge/component-test-patterns.md +139 -0
- package/knowledge/database-change-management.md +80 -0
- package/knowledge/database-test-patterns.md +79 -0
- package/knowledge/decision-defaults.md +88 -0
- package/knowledge/dependency-breaking-techniques.md +116 -0
- package/knowledge/deployment-pipeline.md +86 -0
- package/knowledge/design-smells.md +122 -0
- package/knowledge/directory-enumeration.md +38 -0
- package/knowledge/domain-modeling.md +123 -0
- package/knowledge/evidence-bundle.md +90 -0
- package/knowledge/exploratory-testing-field-guide.md +122 -0
- package/knowledge/failure-routing.md +28 -0
- package/knowledge/fixture-construction.md +56 -0
- package/knowledge/frontend-component-architecture.md +139 -0
- package/knowledge/gherkin-quality-review-dispatch.md +135 -0
- package/knowledge/index.json +6766 -0
- package/knowledge/internal-collaborator-doubling.md +101 -0
- package/knowledge/legacy-test-strategy.md +71 -0
- package/knowledge/long-run-waiting.md +66 -0
- package/knowledge/microservice-testing.md +71 -0
- package/knowledge/model-pricing.json +23 -0
- package/knowledge/mutation-score-formulas.md +60 -0
- package/knowledge/object-calisthenics.md +147 -0
- package/knowledge/oracle-provenance.md +94 -0
- package/knowledge/orchestrator-script-implementation.md +185 -0
- package/knowledge/owasp-detection.md +148 -0
- package/knowledge/plan-review-rubric.md +56 -0
- package/knowledge/proxy-connectivity.md +62 -0
- package/knowledge/reactive-effect-patterns.md +73 -0
- package/knowledge/recon-inventory-excludes.txt +32 -0
- package/knowledge/references/bdd-value-guide.md +61 -0
- package/knowledge/references/csharp-http-client-testing.md +264 -0
- package/knowledge/release-strategies.md +74 -0
- package/knowledge/report-output-location.md +117 -0
- package/knowledge/report-pdf-integration.md +63 -0
- package/knowledge/report-print.css +129 -0
- package/knowledge/report-template.md +114 -0
- package/knowledge/report-to-pdf.md +69 -0
- package/knowledge/request-processing-flow.md +63 -0
- package/knowledge/result-verification.md +52 -0
- package/knowledge/review-agent-output-contract.md +121 -0
- package/knowledge/review-lens-classification.md +113 -0
- package/knowledge/review-rubric.md +62 -0
- package/knowledge/review-template.md +104 -0
- package/knowledge/rule-fixtures/A02.insecure-random-js/negative.js +1 -0
- package/knowledge/rule-fixtures/A02.insecure-random-js/positive.js +1 -0
- package/knowledge/rule-fixtures/A02.weak-hashing-md5/negative.py +1 -0
- package/knowledge/rule-fixtures/A02.weak-hashing-md5/positive.py +1 -0
- package/knowledge/rule-fixtures/A03.command-injection/negative.js +1 -0
- package/knowledge/rule-fixtures/A03.command-injection/positive.js +1 -0
- package/knowledge/rule-fixtures/A03.sql-injection/negative.js +1 -0
- package/knowledge/rule-fixtures/A03.sql-injection/positive.js +1 -0
- package/knowledge/rule-fixtures/A03.xss-innerhtml/negative.js +1 -0
- package/knowledge/rule-fixtures/A03.xss-innerhtml/positive.js +1 -0
- package/knowledge/rule-fixtures/A05.cors-wildcard/negative.js +1 -0
- package/knowledge/rule-fixtures/A05.cors-wildcard/positive.js +1 -0
- package/knowledge/rule-fixtures/A05.default-credentials/negative.js +1 -0
- package/knowledge/rule-fixtures/A05.default-credentials/positive.js +1 -0
- package/knowledge/rule-fixtures/A07.jwt-alg-none/negative.js +1 -0
- package/knowledge/rule-fixtures/A07.jwt-alg-none/positive.js +1 -0
- package/knowledge/rule-fixtures/A08.binary-formatter/negative.cs +1 -0
- package/knowledge/rule-fixtures/A08.binary-formatter/positive.cs +1 -0
- package/knowledge/rule-fixtures/A08.js-eval/negative.js +1 -0
- package/knowledge/rule-fixtures/A08.js-eval/positive.js +1 -0
- package/knowledge/rule-fixtures/A08.object-input-stream/negative.java +1 -0
- package/knowledge/rule-fixtures/A08.object-input-stream/positive.java +1 -0
- package/knowledge/schemas/disposition-register-v1.json +65 -0
- package/knowledge/schemas/recon-envelope-v1.json +198 -0
- package/knowledge/schemas/unified-finding-v1.json +72 -0
- package/knowledge/security-primitives-contract.md +301 -0
- package/knowledge/security-review-rule-map.yaml +107 -0
- package/knowledge/skills-registry.md +72 -0
- package/knowledge/task-size-classifier.md +103 -0
- package/knowledge/telemetry-schema.md +881 -0
- package/knowledge/test-automation-maturity.md +56 -0
- package/knowledge/test-automation-principles.md +71 -0
- package/knowledge/test-cadence-tradeoffs.md +68 -0
- package/knowledge/test-doubles.md +105 -0
- package/knowledge/test-file-indicators.md +22 -0
- package/knowledge/test-layer-gates.md +35 -0
- package/knowledge/test-matrix-examples/django-batch.md +24 -0
- package/knowledge/test-matrix-examples/dotnet-grpc-fronting-api.md +90 -0
- package/knowledge/test-matrix-examples/dotnet-http-consumer.md +131 -0
- package/knowledge/test-matrix-examples/react-node-spa.md +24 -0
- package/knowledge/test-matrix-examples/spring-boot-service.md +25 -0
- package/knowledge/test-matrix-examples/ssr-htmx.md +24 -0
- package/knowledge/test-organization.md +70 -0
- package/knowledge/test-pyramid.md +84 -0
- package/knowledge/test-refactoring.md +67 -0
- package/knowledge/test-review-division-of-labor.md +85 -0
- package/knowledge/test-smells.md +80 -0
- package/knowledge/test-stack-profiles/bdd-frameworks.md +235 -0
- package/knowledge/test-stack-profiles/django.md +13 -0
- package/knowledge/test-stack-profiles/dotnet.md +18 -0
- package/knowledge/test-stack-profiles/go.md +16 -0
- package/knowledge/test-stack-profiles/node.md +16 -0
- package/knowledge/test-stack-profiles/react.md +12 -0
- package/knowledge/test-stack-profiles/spring-boot.md +16 -0
- package/knowledge/test-stack-profiles/ssr-htmx.md +14 -0
- package/knowledge/test-stack-profiles/vue.md +12 -0
- package/knowledge/test-strategy.md +70 -0
- package/knowledge/testability-patterns.md +240 -0
- package/knowledge/testing-quadrants.md +44 -0
- package/knowledge/testing-techniques/approval.md +15 -0
- package/knowledge/testing-techniques/chaos.md +17 -0
- package/knowledge/testing-techniques/fuzz.md +15 -0
- package/knowledge/testing-techniques/property-based.md +15 -0
- package/knowledge/testing-techniques/schema-validation.md +15 -0
- package/knowledge/testing-techniques/screenshot.md +15 -0
- package/knowledge/three-phase-workflow.md +198 -0
- package/knowledge/value-patterns.md +55 -0
- package/knowledge/verification-mode.md +116 -0
- package/knowledge/virtual-service-libraries.md +75 -0
- package/knowledge/wave-consolidation-guidance.md +21 -0
- package/overrides/agents/Explore.md +15 -0
- package/overrides/agents/general-purpose.md +10 -0
- package/overrides/notes/autoship.md +6 -0
- package/overrides/notes/issues-from-assessment.md +3 -0
- package/overrides/notes/issues-from-plan.md +3 -0
- package/overrides/notes/mutation-night-watch.md +3 -0
- package/overrides/notes/mutation-testing.md +3 -0
- package/overrides/notes/pr.md +7 -0
- package/overrides/notes/project-init.md +6 -0
- package/overrides/notes/setup.md +13 -0
- package/overrides/notes/specs.md +3 -0
- package/overrides/skills/headless-run/SKILL.md +45 -0
- package/overrides/skills/upgrade/SKILL.md +30 -0
- package/overrides/skills/version/SKILL.md +25 -0
- package/package.json +36 -0
- package/scripts/authoring_digest.py +93 -0
- package/scripts/autoship_discover.py +121 -0
- package/scripts/autoship_group.py +409 -0
- package/scripts/autoship_proposals.py +494 -0
- package/scripts/autoship_queue.py +291 -0
- package/scripts/autoship_reclaim.py +495 -0
- package/scripts/build_jobs.py +108 -0
- package/scripts/build_rollback_point.py +240 -0
- package/scripts/build_slice_scope.py +157 -0
- package/scripts/build_wave.py +109 -0
- package/scripts/build_wave_reconcile.py +252 -0
- package/scripts/build_worktree_baseref.py +113 -0
- package/scripts/check_agent_scope.py +117 -0
- package/scripts/check_agent_tool_mapping.py +213 -0
- package/scripts/check_review_agent_mcp_tools.py +317 -0
- package/scripts/check_security_assessment_mcp_tools.py +165 -0
- package/scripts/checkpoint_abort.py +502 -0
- package/scripts/claude_setup_review.py +438 -0
- package/scripts/codebase_recon.py +556 -0
- package/scripts/coverage_config.py +623 -0
- package/scripts/coverage_delta_steering.py +330 -0
- package/scripts/coverage_discovery_dotnet.py +315 -0
- package/scripts/coverage_discovery_java.py +742 -0
- package/scripts/coverage_discovery_js.py +546 -0
- package/scripts/coverage_gap_ranking.py +556 -0
- package/scripts/coverage_readiness.py +455 -0
- package/scripts/coverage_report_parse.py +521 -0
- package/scripts/detect_bdd_convention.py +252 -0
- package/scripts/eval_ablation.py +376 -0
- package/scripts/gherkin_analysis_coverage_gate.py +306 -0
- package/scripts/gherkin_cross_feature_duplicate_titles_gate.py +173 -0
- package/scripts/gherkin_effectiveness_rollup.py +238 -0
- package/scripts/gherkin_failure_path_gate.py +206 -0
- package/scripts/gherkin_feature_merge.py +720 -0
- package/scripts/gherkin_stub_gate.py +163 -0
- package/scripts/gherkin_stub_merge.py +479 -0
- package/scripts/git_origin_host.py +88 -0
- package/scripts/install-java-static-analysis.py +110 -0
- package/scripts/issue_deps.py +74 -0
- package/scripts/lib/_bdd_markers.py +28 -0
- package/scripts/lib/_gherkin_text.py +93 -0
- package/scripts/lib/_vendored_tree.py +70 -0
- package/scripts/lib/autoship_state.py +397 -0
- package/scripts/lib/claude_md_guard.py +226 -0
- package/scripts/lib/deterministic_recon.py +446 -0
- package/scripts/lib/mcp_tool_grants.py +211 -0
- package/scripts/lib/plan_parse.py +386 -0
- package/scripts/lib/review_result.py +84 -0
- package/scripts/lib/review_roster.py +86 -0
- package/scripts/lib/session_log/__init__.py +34 -0
- package/scripts/lib/session_log/__pycache__/__init__.cpython-314.pyc +0 -0
- package/scripts/lib/session_log/__pycache__/records.cpython-314.pyc +0 -0
- package/scripts/lib/session_log/classify.py +231 -0
- package/scripts/lib/session_log/corrections.py +194 -0
- package/scripts/lib/session_log/discovery.py +108 -0
- package/scripts/lib/session_log/records.py +218 -0
- package/scripts/lib/session_log/redact.py +76 -0
- package/scripts/lib/session_log/signals.py +373 -0
- package/scripts/lib/session_report_downstream.py +614 -0
- package/scripts/lib/session_report_maintainer.py +1273 -0
- package/scripts/lib/session_report_shared.py +262 -0
- package/scripts/lib/settings_hook_guard.py +157 -0
- package/scripts/lib/slug.py +33 -0
- package/scripts/lib/stub_extractors/__init__.py +82 -0
- package/scripts/lib/stub_extractors/_common.py +328 -0
- package/scripts/lib/stub_extractors/csharp.py +19 -0
- package/scripts/lib/stub_extractors/go.py +173 -0
- package/scripts/lib/stub_extractors/java.py +18 -0
- package/scripts/lib/stub_extractors/jsts.py +126 -0
- package/scripts/mutation_stack_sections.py +149 -0
- package/scripts/mutation_yield_steering.py +345 -0
- package/scripts/orchestrator.py +895 -0
- package/scripts/plan_gherkin_export.py +227 -0
- package/scripts/plan_waves.py +208 -0
- package/scripts/pr_close_keyword_lint.py +108 -0
- package/scripts/progress_guardian.py +888 -0
- package/scripts/recon_inventory.py +273 -0
- package/scripts/review_findings_log.py +93 -0
- package/scripts/run_invariants.py +124 -0
- package/scripts/select_lenses.py +640 -0
- package/scripts/session_report.py +486 -0
- package/scripts/set_autocompact_env.py +221 -0
- package/scripts/ship_resume_guard.py +135 -0
- package/scripts/ship_review_gate.py +63 -0
- package/scripts/specs_convention_marker.py +103 -0
- package/scripts/test_improve_resume.py +277 -0
- package/scripts/test_review_mechanics.py +958 -0
- package/scripts/token_efficiency_review.py +322 -0
- package/scripts/verdict_scope.py +285 -0
- package/scripts/verify_gherkin_quality_critic_isolation.py +296 -0
- package/scripts/verify_tier.py +157 -0
- package/skills/adr-tools/SKILL.md +118 -0
- package/skills/agent-readiness/SKILL.md +105 -0
- package/skills/agent-readiness/ai_friendly_analyzers.py +326 -0
- package/skills/agent-readiness/scanner.py +441 -0
- package/skills/agent-readiness/scorecard.yaml +88 -0
- package/skills/api-design/SKILL.md +115 -0
- package/skills/apply-fixes/SKILL.md +171 -0
- package/skills/apply-test-doubles/SKILL.md +321 -0
- package/skills/artifact-lifecycle/SKILL.md +127 -0
- package/skills/autoship/SKILL.md +1124 -0
- package/skills/benchmark/SKILL.md +105 -0
- package/skills/branch-workflow/SKILL.md +89 -0
- package/skills/browse/SKILL.md +184 -0
- package/skills/browser-testing/SKILL.md +62 -0
- package/skills/browser-testing/references/playwright-patterns.md +216 -0
- package/skills/build/SKILL.md +422 -0
- package/skills/build/references/static-self-heal.md +245 -0
- package/skills/careful/SKILL.md +72 -0
- package/skills/cd-test-architecture/SKILL.md +371 -0
- package/skills/ci-debugging/SKILL.md +105 -0
- package/skills/co-evolution-audit/SKILL.md +269 -0
- package/skills/code-review/SKILL.md +1015 -0
- package/skills/code-review/examples/aggregated-sample.json +56 -0
- package/skills/code-review/examples/sample-report.md +41 -0
- package/skills/code-review/output-format.md +478 -0
- package/skills/code-review/scripts/activation.py +86 -0
- package/skills/code-review/scripts/change_impact.py +357 -0
- package/skills/code-review/scripts/change_shape.py +372 -0
- package/skills/code-review/scripts/change_size.py +212 -0
- package/skills/code-review/scripts/changed_file_list.py +141 -0
- package/skills/code-review/scripts/closing_pass.py +187 -0
- package/skills/code-review/scripts/consolidate.py +277 -0
- package/skills/code-review/scripts/contract_failure_report.py +185 -0
- package/skills/code-review/scripts/dispatch_reconcile.py +66 -0
- package/skills/code-review/scripts/dispatch_waves.py +164 -0
- package/skills/code-review/scripts/finding_signature.py +446 -0
- package/skills/code-review/scripts/ledger.py +283 -0
- package/skills/code-review/scripts/partition.py +169 -0
- package/skills/code-review/scripts/render_tiered_findings.py +274 -0
- package/skills/code-review/scripts/repo_invariants.py +1066 -0
- package/skills/code-review/scripts/review_context_pack.py +306 -0
- package/skills/code-review/scripts/review_round_log.py +345 -0
- package/skills/code-review/scripts/review_value_coverage.py +297 -0
- package/skills/code-review/scripts/validate_review_output.py +467 -0
- package/skills/code-review/sliced-mode.md +205 -0
- package/skills/competitive-analysis/SKILL.md +191 -0
- package/skills/context-loading-protocol/SKILL.md +157 -0
- package/skills/continue/SKILL.md +90 -0
- package/skills/cost-report/SKILL.md +178 -0
- package/skills/coverage-baseline/SKILL.md +335 -0
- package/skills/coverage-baseline/references/multi-project-discovery.md +202 -0
- package/skills/coverage-delta/SKILL.md +181 -0
- package/skills/coverage-delta/references/mutation-gate.md +70 -0
- package/skills/design-doc/SKILL.md +95 -0
- package/skills/design-interrogation/SKILL.md +89 -0
- package/skills/design-it-twice/SKILL.md +91 -0
- package/skills/docker-image-audit/SKILL.md +108 -0
- package/skills/docker-image-audit/references/install-guide.md +64 -0
- package/skills/docker-image-audit/references/report-template.md +73 -0
- package/skills/docker-image-create/SKILL.md +185 -0
- package/skills/domain-analysis/SKILL.md +183 -0
- package/skills/domain-driven-design/SKILL.md +194 -0
- package/skills/exploratory-testing/SKILL.md +108 -0
- package/skills/explore/SKILL.md +51 -0
- package/skills/farley-score/SKILL.md +165 -0
- package/skills/feature-file-validation/SKILL.md +78 -0
- package/skills/feature-file-validation/references/validation-rules.md +115 -0
- package/skills/feedback-learning/SKILL.md +414 -0
- package/skills/fix/SKILL.md +450 -0
- package/skills/freeze/SKILL.md +68 -0
- package/skills/frontend-architecture/SKILL.md +113 -0
- package/skills/gherkin-derive/SKILL.md +630 -0
- package/skills/gherkin-public/SKILL.md +266 -0
- package/skills/governance-compliance/SKILL.md +150 -0
- package/skills/guard/SKILL.md +75 -0
- package/skills/handoff/SKILL.md +139 -0
- package/skills/handoff/references/summary-templates.md +242 -0
- package/skills/harness-audit/SKILL.md +751 -0
- package/skills/harness-audit/scripts/lesson_validate.py +386 -0
- package/skills/harness-audit/scripts/redundancy_criterion.py +188 -0
- package/skills/headless-run/SKILL.md +45 -0
- package/skills/headless-run/scripts/isolated_dispatch.py +381 -0
- package/skills/help/SKILL.md +72 -0
- package/skills/hexagonal-architecture/SKILL.md +85 -0
- package/skills/human-oversight-protocol/SKILL.md +224 -0
- package/skills/issues-from-assessment/SKILL.md +223 -0
- package/skills/issues-from-plan/SKILL.md +133 -0
- package/skills/legacy-code/SKILL.md +132 -0
- package/skills/mermaid-diagramming/SKILL.md +120 -0
- package/skills/mutation-night-watch/SKILL.md +154 -0
- package/skills/mutation-night-watch/references/scheduling.md +135 -0
- package/skills/mutation-testing/SKILL.md +396 -0
- package/skills/mutation-testing/references/languages/csharp-stryker-net.md +676 -0
- package/skills/mutation-testing/references/languages/go-go-mutesting.md +95 -0
- package/skills/mutation-testing/references/languages/java-pitest.md +77 -0
- package/skills/mutation-testing/references/languages/javascript-stryker.md +188 -0
- package/skills/mutation-testing/references/languages/python-mutmut.md +97 -0
- package/skills/mutation-testing/references/time-estimation.md +34 -0
- package/skills/mutation-testing/references/tool-detection.md +15 -0
- package/skills/mutation-testing/references/workflow-callers.md +23 -0
- package/skills/mutation-testing/scripts/__pycache__/xunit_v3_feature_detector.cpython-314.pyc +0 -0
- package/skills/mutation-testing/scripts/csharp_stryker_net_slice_runner.py +635 -0
- package/skills/mutation-testing/scripts/csharp_stryker_net_status_loop.py +525 -0
- package/skills/mutation-testing/scripts/csharp_stryker_net_wrapper.py +681 -0
- package/skills/mutation-testing/scripts/mutation_baseline_reuse.py +292 -0
- package/skills/mutation-testing/scripts/mutation_exclude_policy.py +268 -0
- package/skills/mutation-testing/scripts/mutation_feasibility_gate.py +463 -0
- package/skills/mutation-testing/scripts/mutation_kill_headless.py +331 -0
- package/skills/mutation-testing/scripts/mutation_kill_insert.py +199 -0
- package/skills/mutation-testing/scripts/mutation_kill_insert_python.py +150 -0
- package/skills/mutation-testing/scripts/mutation_kill_loop.py +869 -0
- package/skills/mutation-testing/scripts/mutation_kill_loop_python.py +949 -0
- package/skills/mutation-testing/scripts/mutation_kill_retry.py +592 -0
- package/skills/mutation-testing/scripts/mutation_kill_shared.py +620 -0
- package/skills/mutation-testing/scripts/mutation_nightwatch.py +462 -0
- package/skills/mutation-testing/scripts/mutation_nightwatch_stacks.py +425 -0
- package/skills/mutation-testing/scripts/mutation_report.py +743 -0
- package/skills/mutation-testing/scripts/mutation_report_cli.py +175 -0
- package/skills/mutation-testing/scripts/mutation_safety_gate.py +69 -0
- package/skills/mutation-testing/scripts/stryker_shard_pipeline.py +847 -0
- package/skills/mutation-testing/scripts/stryker_shard_setup.py +440 -0
- package/skills/mutation-testing/scripts/stryker_timeout_retry.py +142 -0
- package/skills/mutation-testing/scripts/xunit_v3_feature_detector.py +341 -0
- package/skills/performance-benchmark/SKILL.md +174 -0
- package/skills/performance-benchmark/examples/report-format.md +43 -0
- package/skills/performance-benchmark/references/benchmark-script.md +169 -0
- package/skills/performance-metrics/SKILL.md +265 -0
- package/skills/plan/SKILL.md +199 -0
- package/skills/plan/references/gherkin-persistence.md +43 -0
- package/skills/plan/references/plan-template.md +182 -0
- package/skills/pr/SKILL.md +289 -0
- package/skills/pr/scripts/gate_retry_state.py +368 -0
- package/skills/project-init/README.md +141 -0
- package/skills/project-init/SKILL.md +1197 -0
- package/skills/project-init/evals/evals.json +200 -0
- package/skills/project-init/references/capability-tools.md +55 -0
- package/skills/project-init/references/configs.md +221 -0
- package/skills/property-based-testing/SKILL.md +121 -0
- package/skills/property-based-testing/fixtures/invariant_fixture.py +15 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/README.md +42 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/LICENSE +21 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/README.md +263 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/lib/cjs/fast-check.d.ts +5165 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/lib/cjs/fast-check.js +12147 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/lib/cjs/package.json +3 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/lib/cjs/types57/fast-check.d.ts +5165 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/lib/fast-check.d.ts +5165 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/lib/fast-check.js +12011 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/lib/rolldown-runtime-D7D4PA-g.js +13 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/lib/types57/fast-check.d.ts +5165 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/package.json +94 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/LICENSE +21 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/README.md +168 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/RandomGenerator-DcXj09Ch.d.ts +14 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/distribution/uniformBigInt.d.ts +15 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/distribution/uniformBigInt.js +38 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/distribution/uniformFloat32.d.ts +15 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/distribution/uniformFloat32.js +18 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/distribution/uniformFloat64.d.ts +15 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/distribution/uniformFloat64.js +22 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/distribution/uniformInt.d.ts +15 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/distribution/uniformInt.js +134 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/RandomGenerator-DcXj09Ch.d.ts +14 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/distribution/uniformBigInt.d.ts +15 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/distribution/uniformBigInt.js +37 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/distribution/uniformFloat32.d.ts +15 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/distribution/uniformFloat32.js +17 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/distribution/uniformFloat64.d.ts +15 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/distribution/uniformFloat64.js +21 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/distribution/uniformInt.d.ts +15 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/distribution/uniformInt.js +133 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/generator/congruential32.d.ts +7 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/generator/congruential32.js +44 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/generator/mersenne.d.ts +7 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/generator/mersenne.js +90 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/generator/xoroshiro128plus.d.ts +7 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/generator/xoroshiro128plus.js +80 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/generator/xorshift128plus.d.ts +7 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/generator/xorshift128plus.js +78 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/package.json +3 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/types/JumpableRandomGenerator.d.ts +16 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/types/JumpableRandomGenerator.js +0 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/types/RandomGenerator.d.ts +2 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/types/RandomGenerator.js +0 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/utils/generateN.d.ts +6 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/utils/generateN.js +8 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/utils/purify.d.ts +12 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/utils/purify.js +9 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/utils/skipN.d.ts +6 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/utils/skipN.js +6 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/generator/congruential32.d.ts +7 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/generator/congruential32.js +46 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/generator/mersenne.d.ts +7 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/generator/mersenne.js +92 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/generator/xoroshiro128plus.d.ts +7 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/generator/xoroshiro128plus.js +82 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/generator/xorshift128plus.d.ts +7 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/generator/xorshift128plus.js +80 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/types/JumpableRandomGenerator.d.ts +16 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/types/JumpableRandomGenerator.js +0 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/types/RandomGenerator.d.ts +2 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/types/RandomGenerator.js +0 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/utils/generateN.d.ts +6 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/utils/generateN.js +9 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/utils/purify.d.ts +12 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/utils/purify.js +10 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/utils/skipN.d.ts +6 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/utils/skipN.js +7 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/package.json +133 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/package-lock.json +1179 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/package.json +14 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/roundtrip.js +29 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/roundtrip.properties.test.js +16 -0
- package/skills/property-based-testing/fixtures/no_property_fixture.py +10 -0
- package/skills/property-based-testing/fixtures/roundtrip_fixture.py +16 -0
- package/skills/property-based-testing/references/languages/javascript.md +54 -0
- package/skills/property-based-testing/scripts/detect_and_dispatch.py +80 -0
- package/skills/property-based-testing/scripts/hypothesis_scaffold.py +276 -0
- package/skills/proxy-resilience/SKILL.md +84 -0
- package/skills/quality-gate-pipeline/SKILL.md +184 -0
- package/skills/quality-targets-converge/SKILL.md +254 -0
- package/skills/repo-review/SKILL.md +159 -0
- package/skills/report-pdf/SKILL.md +66 -0
- package/skills/review/SKILL.md +47 -0
- package/skills/review-agent/SKILL.md +152 -0
- package/skills/review-summary/SKILL.md +73 -0
- package/skills/run-report/SKILL.md +70 -0
- package/skills/semantic-duplication-scan/SKILL.md +337 -0
- package/skills/semantic-scan/SKILL.md +53 -0
- package/skills/semgrep-analyze/SKILL.md +139 -0
- package/skills/setup/SKILL.md +1122 -0
- package/skills/ship/SKILL.md +240 -0
- package/skills/source-verification/SKILL.md +210 -0
- package/skills/source-verification/scripts/claim_extractor.py +155 -0
- package/skills/specs/.size-baseline.json +4 -0
- package/skills/specs/SKILL.md +243 -0
- package/skills/specs/references/completeness-checklist.md +83 -0
- package/skills/specs/references/extraction.md +58 -0
- package/skills/specs/references/glossary.md +59 -0
- package/skills/specs/references/persistence.md +115 -0
- package/skills/specs/references/predictability-check.md +77 -0
- package/skills/static-analysis-integration/SKILL.md +235 -0
- package/skills/static-analysis-integration/adapters/_envelope.py +26 -0
- package/skills/static-analysis-integration/adapters/jscpd-adapter.py +66 -0
- package/skills/static-analysis-integration/adapters/lizard-adapter.py +81 -0
- package/skills/static-analysis-integration/adapters/mypy-adapter.py +50 -0
- package/skills/static-analysis-integration/adapters/mypy-src-layout.py +93 -0
- package/skills/static-analysis-integration/adapters/security-review-adapter.py +212 -0
- package/skills/static-analysis-integration/maintenance.md +23 -0
- package/skills/static-analysis-integration/references/language-setup.md +228 -0
- package/skills/static-analysis-integration/references/sarif-parser.md +124 -0
- package/skills/static-analysis-integration/references/security-review-adapter.md +118 -0
- package/skills/static-analysis-integration/references/tool-configs.md +617 -0
- package/skills/static-analysis-integration/rulesets/pmd-quickstart.xml +24 -0
- package/skills/stryker-xunit-v2-shim/SKILL.md +274 -0
- package/skills/stryker-xunit-v2-shim/references/shim-howto.md +256 -0
- package/skills/stryker-xunit-v2-shim/scripts/generate_shim.py +143 -0
- package/skills/systematic-debugging/SKILL.md +130 -0
- package/skills/telemetry/SKILL.md +75 -0
- package/skills/test-audit-disable/SKILL.md +129 -0
- package/skills/test-design/SKILL.md +177 -0
- package/skills/test-design/scripts/__pycache__/internal_double_detector.cpython-314.pyc +0 -0
- package/skills/test-design/scripts/internal_double_detector.py +631 -0
- package/skills/test-design-advisor/SKILL.md +166 -0
- package/skills/test-driven-development/SKILL.md +169 -0
- package/skills/test-health/SKILL.md +262 -0
- package/skills/test-improve/SKILL.md +239 -0
- package/skills/test-improve/references/phase-0-approach-contract.md +228 -0
- package/skills/test-improve/references/phase-1-analyze.md +131 -0
- package/skills/test-improve/references/phase-2-baseline.md +121 -0
- package/skills/test-improve/references/phase-3-derive-gherkin.md +53 -0
- package/skills/test-improve/references/phase-4-plan-fixes.md +34 -0
- package/skills/test-improve/references/phase-5-improve.md +215 -0
- package/skills/test-improve/references/phase-6-refactor-decision.md +45 -0
- package/skills/test-improve/references/phase-7-refactor.md +44 -0
- package/skills/test-improve/references/phase-8-validate.md +66 -0
- package/skills/test-improve/references/phase-9-close-out-prompt.md +11 -0
- package/skills/test-improve/references/phase-9-report.md +62 -0
- package/skills/test-improve/references/review-loop.md +92 -0
- package/skills/test-improve/templates/executive-summary.md +123 -0
- package/skills/threat-modeling/SKILL.md +108 -0
- package/skills/triage/SKILL.md +211 -0
- package/skills/ubiquitous-language/SKILL.md +192 -0
- package/skills/ubiquitous-language/scripts/collect_domain_signals.py +300 -0
- package/skills/unfreeze/SKILL.md +37 -0
- package/skills/upgrade/SKILL.md +31 -0
- package/skills/upgrade/scripts/check_version_drift.py +113 -0
- package/skills/upgrade/scripts/enable_autoupdate.py +149 -0
- package/skills/version/SKILL.md +25 -0
- package/sync/__pycache__/sync_upstream.cpython-314.pyc +0 -0
- package/sync/sync_upstream.py +293 -0
- package/templates/ACCEPTED-RISKS.md.tmpl +46 -0
- package/templates/agents/agent-template.md +151 -0
- package/templates/agents/angular-testing.md +66 -0
- package/templates/agents/csharp-quality.md +63 -0
- package/templates/agents/esm-enforcer.md +52 -0
- package/templates/agents/front-end-testing.md +65 -0
- package/templates/agents/go-quality.md +65 -0
- package/templates/agents/python-quality.md +62 -0
- package/templates/agents/react-testing.md +61 -0
- package/templates/agents/ts-enforcer.md +60 -0
- package/templates/agents/twelve-factor-audit.md +49 -0
- package/tools/entropy-check.py +250 -0
- package/tools/model-hash-verify.py +213 -0
|
@@ -0,0 +1,495 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Reclaim issues orphaned by a crashed/interrupted /dev-team:autoship round (#989).
|
|
3
|
+
|
|
4
|
+
Relabels a stale `autoship:in-progress` issue back to `autoship:blocked` with
|
|
5
|
+
an explanatory comment, so a crashed or interrupted autoship round doesn't
|
|
6
|
+
leave an issue permanently stuck "in progress". Deterministic, testable
|
|
7
|
+
Python — no model judgment, per the epic's architecture rationale (see plan
|
|
8
|
+
`plans/issue-989-autoship-discovery-reclaim.md`, Slice 3).
|
|
9
|
+
|
|
10
|
+
Stdlib-only.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import argparse
|
|
16
|
+
import json
|
|
17
|
+
import subprocess
|
|
18
|
+
import sys
|
|
19
|
+
from datetime import datetime, timezone
|
|
20
|
+
from pathlib import Path
|
|
21
|
+
|
|
22
|
+
sys.path.insert(0, str(Path(__file__).resolve().parent / "lib"))
|
|
23
|
+
|
|
24
|
+
import autoship_state
|
|
25
|
+
|
|
26
|
+
IN_PROGRESS_LABEL = autoship_state.IN_PROGRESS_LABEL
|
|
27
|
+
BLOCKED_LABEL = autoship_state.BLOCKED_LABEL
|
|
28
|
+
|
|
29
|
+
# Stripped alongside IN_PROGRESS_LABEL on every reclaim relabel — a crashed
|
|
30
|
+
# batch round can leave a member `in-progress` + `batch-confirmed`; without
|
|
31
|
+
# also removing this label here, reclaim would produce `blocked` +
|
|
32
|
+
# `batch-confirmed` still co-present, violating the "autoship:blocked is
|
|
33
|
+
# mutually exclusive with the other two states" invariant
|
|
34
|
+
# (`skills/autoship/SKILL.md`) and letting a later human relabel back to
|
|
35
|
+
# `ready` silently re-trigger `has_batch_confirmed_override` on a stale,
|
|
36
|
+
# no-longer-reconfirmed marker. Defined once in `autoship_state` alongside
|
|
37
|
+
# the other `autoship:*` label constants; `autoship_group.py` imports the
|
|
38
|
+
# same shared constant.
|
|
39
|
+
BATCH_CONFIRMED_LABEL = autoship_state.BATCH_CONFIRMED_LABEL
|
|
40
|
+
|
|
41
|
+
# gh subprocess calls get a hard timeout so a hung/stalled network call never
|
|
42
|
+
# blocks this script indefinitely.
|
|
43
|
+
_GH_TIMEOUT_SECONDS = 30
|
|
44
|
+
|
|
45
|
+
# Required per-issue fields for --input-file, mirroring autoship_discover's
|
|
46
|
+
# REQUIRED_ISSUE_FIELDS/validate_issues contract so a malformed local fixture
|
|
47
|
+
# fails loud with a clear message instead of an uncaught AttributeError deep
|
|
48
|
+
# inside select_orphaned.
|
|
49
|
+
REQUIRED_ISSUE_FIELDS = ("number", "title", "state", "labels")
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class ReclaimError(Exception):
|
|
53
|
+
"""A reclaim-input or `gh` fetch problem that must surface as a clear
|
|
54
|
+
CLI error message, not an uncaught exception/traceback."""
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def select_orphaned(issues: list, stale_after_hours: float, now: datetime) -> list:
|
|
58
|
+
"""Return the subset of `issues` that are orphaned in-progress issues.
|
|
59
|
+
|
|
60
|
+
An issue qualifies when it is open, carries `autoship:in-progress`, and
|
|
61
|
+
its `labeled_at` (falling back to `updatedAt` when `labeled_at` is
|
|
62
|
+
absent) is stale per `autoship_state.is_stale` (inclusive boundary). The
|
|
63
|
+
live-fetch path (`_fetch_in_progress_issues`/`_labeled_at_for`) always
|
|
64
|
+
populates `labeled_at` before this function runs, falling back to
|
|
65
|
+
`updatedAt` itself when the real timeline event can't be found.
|
|
66
|
+
"""
|
|
67
|
+
orphaned = []
|
|
68
|
+
for issue in issues:
|
|
69
|
+
if issue.get("state") != "OPEN":
|
|
70
|
+
continue
|
|
71
|
+
labels = issue.get("labels") or []
|
|
72
|
+
label_names = {
|
|
73
|
+
label["name"] if isinstance(label, dict) else label for label in labels
|
|
74
|
+
}
|
|
75
|
+
if IN_PROGRESS_LABEL not in label_names:
|
|
76
|
+
continue
|
|
77
|
+
timestamp_raw = issue.get("labeled_at") or issue.get("updatedAt")
|
|
78
|
+
if timestamp_raw is None:
|
|
79
|
+
continue
|
|
80
|
+
labeled_at = _parse_timestamp(timestamp_raw)
|
|
81
|
+
if autoship_state.is_stale(labeled_at, stale_after_hours, now):
|
|
82
|
+
orphaned.append(issue)
|
|
83
|
+
return orphaned
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def _parse_timestamp(raw) -> datetime:
|
|
87
|
+
"""Parse a `labeled_at`/`updatedAt` value into a `datetime`.
|
|
88
|
+
|
|
89
|
+
Accepts either an already-parsed `datetime` (as tests may supply) or an
|
|
90
|
+
ISO-8601 string (as `--input-file` JSON and the live `gh` fetch supply),
|
|
91
|
+
tolerating a trailing `Z` suffix.
|
|
92
|
+
"""
|
|
93
|
+
if isinstance(raw, datetime):
|
|
94
|
+
return raw
|
|
95
|
+
return datetime.fromisoformat(raw.rstrip("Z"))
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def _build_parser() -> argparse.ArgumentParser:
|
|
99
|
+
"""Build this CLI's `argparse.ArgumentParser`, isolated from `main()` so
|
|
100
|
+
tests can assert defaults/overrides via `_build_parser().parse_args([...])`."""
|
|
101
|
+
parser = argparse.ArgumentParser(description=__doc__)
|
|
102
|
+
parser.add_argument(
|
|
103
|
+
"--stale-after-hours",
|
|
104
|
+
type=autoship_state.positive_float_validator("--stale-after-hours"),
|
|
105
|
+
default=24,
|
|
106
|
+
help=(
|
|
107
|
+
"Hours an issue may stay autoship:in-progress before it is "
|
|
108
|
+
"considered orphaned (default 24)."
|
|
109
|
+
),
|
|
110
|
+
)
|
|
111
|
+
parser.add_argument(
|
|
112
|
+
"--dry-run",
|
|
113
|
+
action="store_true",
|
|
114
|
+
help="Preview reclaims without commenting or relabeling (no gh calls).",
|
|
115
|
+
)
|
|
116
|
+
parser.add_argument(
|
|
117
|
+
"--emit-actions-only",
|
|
118
|
+
action="store_true",
|
|
119
|
+
help=(
|
|
120
|
+
"Commit to reclaiming each orphaned issue, but never call gh — "
|
|
121
|
+
"print one JSON action per line to stdout instead, for a caller "
|
|
122
|
+
"without a gh CLI (e.g. a cloud session) to execute via another "
|
|
123
|
+
"mechanism (issue #1700). Ignored when --dry-run is also given: "
|
|
124
|
+
"dry-run's 'nothing happens yet' semantics take priority."
|
|
125
|
+
),
|
|
126
|
+
)
|
|
127
|
+
autoship_state.add_input_seam_args(parser)
|
|
128
|
+
return parser
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def _fetch_in_progress_issues() -> list:
|
|
132
|
+
"""Fetch open `autoship:in-progress` issues via `gh issue list`, enriched
|
|
133
|
+
with each one's real `labeled_at` timestamp from its GitHub timeline.
|
|
134
|
+
|
|
135
|
+
`labels` and `state` are requested even though the live fetch is already
|
|
136
|
+
server-filtered to open + `autoship:in-progress`, so the fetched shape
|
|
137
|
+
matches exactly what `select_orphaned` checks — same reasoning as
|
|
138
|
+
discovery's live-fetch step. `--limit 500` overrides `gh issue list`'s
|
|
139
|
+
default result cap (typically 30) so a repo with more than a page of
|
|
140
|
+
stale in-progress issues doesn't silently reclaim only part of them. A
|
|
141
|
+
failure fetching the issue list itself
|
|
142
|
+
(missing `gh` binary, non-zero exit, timeout, or malformed JSON) is
|
|
143
|
+
unrecoverable and propagates to the caller, which translates it to a
|
|
144
|
+
clear stderr message. A failure looking up one issue's timeline is NOT
|
|
145
|
+
fatal — it falls back to that issue's own `updatedAt` (see
|
|
146
|
+
`_labeled_at_for`), so one issue's timeline hiccup never aborts the
|
|
147
|
+
whole run.
|
|
148
|
+
"""
|
|
149
|
+
try:
|
|
150
|
+
result = subprocess.run(
|
|
151
|
+
[
|
|
152
|
+
"gh",
|
|
153
|
+
"issue",
|
|
154
|
+
"list",
|
|
155
|
+
"--state",
|
|
156
|
+
"open",
|
|
157
|
+
"--label",
|
|
158
|
+
IN_PROGRESS_LABEL,
|
|
159
|
+
"--limit",
|
|
160
|
+
autoship_state.GH_LIST_LIMIT,
|
|
161
|
+
"--json",
|
|
162
|
+
"number,title,state,labels,updatedAt",
|
|
163
|
+
],
|
|
164
|
+
capture_output=True,
|
|
165
|
+
text=True,
|
|
166
|
+
check=True,
|
|
167
|
+
timeout=_GH_TIMEOUT_SECONDS,
|
|
168
|
+
)
|
|
169
|
+
except FileNotFoundError as exc:
|
|
170
|
+
raise ReclaimError(f"gh CLI not found: {exc}") from exc
|
|
171
|
+
issues = json.loads(result.stdout)
|
|
172
|
+
try:
|
|
173
|
+
repo = _current_repo()
|
|
174
|
+
except (
|
|
175
|
+
subprocess.CalledProcessError,
|
|
176
|
+
subprocess.TimeoutExpired,
|
|
177
|
+
FileNotFoundError,
|
|
178
|
+
json.JSONDecodeError,
|
|
179
|
+
):
|
|
180
|
+
# Repo resolution failing is one more "timeline lookup hiccup" —
|
|
181
|
+
# every issue falls back to its own `updatedAt` rather than
|
|
182
|
+
# aborting the whole run.
|
|
183
|
+
repo = None
|
|
184
|
+
for issue in issues:
|
|
185
|
+
issue["labeled_at"] = _labeled_at_for(issue, repo)
|
|
186
|
+
return issues
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def _labeled_at_for(issue: dict, repo: str | None) -> str:
|
|
190
|
+
"""Return the best `labeled_at` timestamp for `issue` in `repo`.
|
|
191
|
+
|
|
192
|
+
Prefers the most recent `labeled` timeline event naming
|
|
193
|
+
`autoship:in-progress`; falls back to the issue's own `updatedAt` when
|
|
194
|
+
`repo` is unresolved, the timeline fetch fails, or no matching event is
|
|
195
|
+
found. `repo` is resolved once by the caller and threaded through —
|
|
196
|
+
resolving it per issue would cost one redundant `gh repo view`
|
|
197
|
+
subprocess call per orphan candidate.
|
|
198
|
+
"""
|
|
199
|
+
if repo is None:
|
|
200
|
+
return issue["updatedAt"]
|
|
201
|
+
try:
|
|
202
|
+
timeline = _fetch_timeline(issue["number"], repo)
|
|
203
|
+
except (
|
|
204
|
+
subprocess.CalledProcessError,
|
|
205
|
+
subprocess.TimeoutExpired,
|
|
206
|
+
FileNotFoundError,
|
|
207
|
+
json.JSONDecodeError,
|
|
208
|
+
):
|
|
209
|
+
return issue["updatedAt"]
|
|
210
|
+
|
|
211
|
+
labeled_events = [
|
|
212
|
+
event
|
|
213
|
+
for event in timeline
|
|
214
|
+
if event.get("event") == "labeled"
|
|
215
|
+
and event.get("label", {}).get("name") == IN_PROGRESS_LABEL
|
|
216
|
+
]
|
|
217
|
+
if not labeled_events:
|
|
218
|
+
return issue["updatedAt"]
|
|
219
|
+
|
|
220
|
+
return labeled_events[-1]["created_at"]
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
def _fetch_timeline(number: int, repo: str) -> list:
|
|
224
|
+
"""Fetch the full timeline for `issue`, following pagination.
|
|
225
|
+
|
|
226
|
+
`--paginate --slurp` is required here: the timeline endpoint returns
|
|
227
|
+
events oldest-first, and `_labeled_at_for` reads the *most recent*
|
|
228
|
+
matching `labeled` event (`labeled_events[-1]`) — on a busy issue with
|
|
229
|
+
more activity than one page, an unpaginated fetch would silently return
|
|
230
|
+
only the first page and miss the real most-recent event, understating
|
|
231
|
+
staleness rather than failing loudly. `--slurp` wraps the pages into a
|
|
232
|
+
JSON array-of-arrays (one array per page), which this flattens back
|
|
233
|
+
into a single flat list of events.
|
|
234
|
+
"""
|
|
235
|
+
result = subprocess.run(
|
|
236
|
+
[
|
|
237
|
+
"gh",
|
|
238
|
+
"api",
|
|
239
|
+
"--paginate",
|
|
240
|
+
"--slurp",
|
|
241
|
+
f"repos/{repo}/issues/{number}/timeline",
|
|
242
|
+
],
|
|
243
|
+
capture_output=True,
|
|
244
|
+
text=True,
|
|
245
|
+
check=True,
|
|
246
|
+
timeout=_GH_TIMEOUT_SECONDS,
|
|
247
|
+
)
|
|
248
|
+
pages = json.loads(result.stdout)
|
|
249
|
+
return [event for page in pages for event in page]
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
def _current_repo() -> str:
|
|
253
|
+
"""Resolve `OWNER/REPO` for the current cwd via `gh repo view` (cwd-based
|
|
254
|
+
repo auto-detection — see the plan's Decision-defaults stance)."""
|
|
255
|
+
result = subprocess.run(
|
|
256
|
+
["gh", "repo", "view", "--json", "nameWithOwner", "--jq", ".nameWithOwner"],
|
|
257
|
+
capture_output=True,
|
|
258
|
+
text=True,
|
|
259
|
+
check=True,
|
|
260
|
+
timeout=_GH_TIMEOUT_SECONDS,
|
|
261
|
+
)
|
|
262
|
+
return result.stdout.strip()
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
def validate_issues(issues) -> None:
|
|
266
|
+
"""Validate `issues` is a JSON array of objects each carrying every
|
|
267
|
+
`REQUIRED_ISSUE_FIELDS` entry.
|
|
268
|
+
|
|
269
|
+
Raises `ReclaimError` naming the malformed entry (by issue number if
|
|
270
|
+
present, by index otherwise) rather than letting an uncaught
|
|
271
|
+
`AttributeError`/`KeyError` propagate out of `select_orphaned`.
|
|
272
|
+
"""
|
|
273
|
+
if not isinstance(issues, list):
|
|
274
|
+
raise ReclaimError(
|
|
275
|
+
"--input-file must contain a JSON array of issue objects, got "
|
|
276
|
+
f"{type(issues).__name__}"
|
|
277
|
+
)
|
|
278
|
+
for idx, issue in enumerate(issues):
|
|
279
|
+
if not isinstance(issue, dict):
|
|
280
|
+
raise ReclaimError(
|
|
281
|
+
f"malformed --input-file entry at index {idx}: not a JSON object"
|
|
282
|
+
)
|
|
283
|
+
missing = [field for field in REQUIRED_ISSUE_FIELDS if field not in issue]
|
|
284
|
+
if missing:
|
|
285
|
+
identifier = f"#{issue['number']}" if "number" in issue else f"index {idx}"
|
|
286
|
+
raise ReclaimError(
|
|
287
|
+
f"malformed --input-file entry ({identifier}): missing required "
|
|
288
|
+
f"field(s) {', '.join(missing)}"
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
def _load_issues(args: argparse.Namespace) -> list:
|
|
293
|
+
"""Load the issue list from `--input-file` when given, else the live
|
|
294
|
+
`gh` fetch. Both paths converge on the same field set (`number`,
|
|
295
|
+
`title`, `state`, `labels`, plus `labeled_at`/`updatedAt`) before
|
|
296
|
+
`select_orphaned` runs.
|
|
297
|
+
|
|
298
|
+
Raises `ReclaimError` on a `--input-file` read/parse/schema failure or a
|
|
299
|
+
`gh`-fetch failure (missing binary, non-zero exit, timeout) — always
|
|
300
|
+
with a message naming which source failed, never an uncaught traceback.
|
|
301
|
+
"""
|
|
302
|
+
if args.input_file:
|
|
303
|
+
try:
|
|
304
|
+
with open(args.input_file, encoding="utf-8") as fh:
|
|
305
|
+
issues = json.load(fh)
|
|
306
|
+
except json.JSONDecodeError as exc:
|
|
307
|
+
raise ReclaimError(
|
|
308
|
+
f"--input-file {args.input_file!r} is not valid JSON: {exc}"
|
|
309
|
+
) from exc
|
|
310
|
+
except OSError as exc:
|
|
311
|
+
raise ReclaimError(
|
|
312
|
+
f"--input-file {args.input_file!r} could not be read: {exc}"
|
|
313
|
+
) from exc
|
|
314
|
+
validate_issues(issues)
|
|
315
|
+
return issues
|
|
316
|
+
try:
|
|
317
|
+
return _fetch_in_progress_issues()
|
|
318
|
+
except (
|
|
319
|
+
subprocess.CalledProcessError,
|
|
320
|
+
subprocess.TimeoutExpired,
|
|
321
|
+
json.JSONDecodeError,
|
|
322
|
+
OSError,
|
|
323
|
+
) as exc:
|
|
324
|
+
raise ReclaimError(f"failed to fetch in-progress issues via gh: {exc}") from exc
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
def _explanatory_comment(issue: dict, stale_after_hours: float, now: datetime) -> str:
|
|
328
|
+
"""Build the comment posted on a reclaimed issue, naming the stale
|
|
329
|
+
threshold and the `labeled_at`/`updatedAt` timestamp used to judge it."""
|
|
330
|
+
timestamp_raw = issue.get("labeled_at") or issue.get("updatedAt")
|
|
331
|
+
return (
|
|
332
|
+
f"Reclaiming this issue: it has carried `{IN_PROGRESS_LABEL}` for at "
|
|
333
|
+
f"least {stale_after_hours} hour(s) (since {timestamp_raw}), past the "
|
|
334
|
+
f"stale threshold as of {autoship_state.format_round_timestamp(now)}. "
|
|
335
|
+
f"Relabeling to `{BLOCKED_LABEL}` so it can be triaged by a human."
|
|
336
|
+
)
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
def _post_comment(number: int, body: str) -> None:
|
|
340
|
+
subprocess.run(
|
|
341
|
+
["gh", "issue", "comment", str(number), "--body", body],
|
|
342
|
+
capture_output=True,
|
|
343
|
+
text=True,
|
|
344
|
+
check=True,
|
|
345
|
+
timeout=_GH_TIMEOUT_SECONDS,
|
|
346
|
+
)
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
def _relabel(number: int) -> None:
|
|
350
|
+
"""Relabel `number` from `IN_PROGRESS_LABEL` to `BLOCKED_LABEL`, also
|
|
351
|
+
stripping `BATCH_CONFIRMED_LABEL` in the same operation (a no-op via
|
|
352
|
+
`gh issue edit` when the label isn't present) — see `BATCH_CONFIRMED_LABEL`
|
|
353
|
+
for why this must never be a bare `IN_PROGRESS_LABEL` -> `BLOCKED_LABEL`
|
|
354
|
+
swap."""
|
|
355
|
+
subprocess.run(
|
|
356
|
+
[
|
|
357
|
+
"gh",
|
|
358
|
+
"issue",
|
|
359
|
+
"edit",
|
|
360
|
+
str(number),
|
|
361
|
+
"--remove-label",
|
|
362
|
+
IN_PROGRESS_LABEL,
|
|
363
|
+
"--remove-label",
|
|
364
|
+
BATCH_CONFIRMED_LABEL,
|
|
365
|
+
"--add-label",
|
|
366
|
+
BLOCKED_LABEL,
|
|
367
|
+
],
|
|
368
|
+
capture_output=True,
|
|
369
|
+
text=True,
|
|
370
|
+
check=True,
|
|
371
|
+
timeout=_GH_TIMEOUT_SECONDS,
|
|
372
|
+
)
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
def _reclaim_issue(
|
|
376
|
+
issue: dict,
|
|
377
|
+
stale_after_hours: float,
|
|
378
|
+
now: datetime,
|
|
379
|
+
dry_run: bool,
|
|
380
|
+
emit_actions_only: bool = False,
|
|
381
|
+
) -> int:
|
|
382
|
+
"""Reclaim a single orphaned `issue`: comment first, then relabel.
|
|
383
|
+
|
|
384
|
+
This order is deliberate — if the comment call fails, the issue is left
|
|
385
|
+
exactly as it was (still `autoship:in-progress`, no misleading partial
|
|
386
|
+
comment), so a later reclaim run naturally re-selects and retries it via
|
|
387
|
+
`select_orphaned` with no special-cased recovery path. If the comment
|
|
388
|
+
succeeds but the relabel then fails, the issue also stays
|
|
389
|
+
`autoship:in-progress` and is retried the same way. Returns 0 on
|
|
390
|
+
success, 1 if either sub-operation fails (after printing a stderr
|
|
391
|
+
message naming the issue and the failing sub-operation).
|
|
392
|
+
"""
|
|
393
|
+
number = issue["number"]
|
|
394
|
+
comment = _explanatory_comment(issue, stale_after_hours, now)
|
|
395
|
+
|
|
396
|
+
if dry_run:
|
|
397
|
+
print(
|
|
398
|
+
f"would-reclaim #{number}: {IN_PROGRESS_LABEL} -> {BLOCKED_LABEL} "
|
|
399
|
+
f"(comment: {comment!r})"
|
|
400
|
+
)
|
|
401
|
+
return 0
|
|
402
|
+
|
|
403
|
+
if emit_actions_only:
|
|
404
|
+
# No gh call at all — the caller (e.g. a cloud session with no gh
|
|
405
|
+
# binary, per issue #1700) is committing to actually reclaim this
|
|
406
|
+
# issue and executes the action itself via another mechanism (GitHub
|
|
407
|
+
# MCP tools). One compact JSON object per line, so a caller can
|
|
408
|
+
# stream-process without buffering the whole run's output.
|
|
409
|
+
# `relabel_remove`/`relabel_add` are lists (not a single
|
|
410
|
+
# `relabel_from`/`relabel_to` pair) because a reclaimed issue may
|
|
411
|
+
# need more than one label stripped — see `_relabel`'s
|
|
412
|
+
# `BATCH_CONFIRMED_LABEL` handling for why.
|
|
413
|
+
print(
|
|
414
|
+
json.dumps(
|
|
415
|
+
{
|
|
416
|
+
"number": number,
|
|
417
|
+
"comment": comment,
|
|
418
|
+
"relabel_remove": [IN_PROGRESS_LABEL, BATCH_CONFIRMED_LABEL],
|
|
419
|
+
"relabel_add": [BLOCKED_LABEL],
|
|
420
|
+
}
|
|
421
|
+
)
|
|
422
|
+
)
|
|
423
|
+
return 0
|
|
424
|
+
|
|
425
|
+
try:
|
|
426
|
+
_post_comment(number, comment)
|
|
427
|
+
except (
|
|
428
|
+
subprocess.CalledProcessError,
|
|
429
|
+
subprocess.TimeoutExpired,
|
|
430
|
+
FileNotFoundError,
|
|
431
|
+
) as exc:
|
|
432
|
+
print(f"failed #{number}: comment ({exc})", file=sys.stderr)
|
|
433
|
+
return 1
|
|
434
|
+
|
|
435
|
+
try:
|
|
436
|
+
_relabel(number)
|
|
437
|
+
except (
|
|
438
|
+
subprocess.CalledProcessError,
|
|
439
|
+
subprocess.TimeoutExpired,
|
|
440
|
+
FileNotFoundError,
|
|
441
|
+
) as exc:
|
|
442
|
+
print(f"failed #{number}: relabel ({exc})", file=sys.stderr)
|
|
443
|
+
return 1
|
|
444
|
+
|
|
445
|
+
print(f"reclaimed #{number}")
|
|
446
|
+
return 0
|
|
447
|
+
|
|
448
|
+
|
|
449
|
+
def main(argv=None) -> int:
|
|
450
|
+
parser = _build_parser()
|
|
451
|
+
args = parser.parse_args(argv)
|
|
452
|
+
if args.emit_actions_only and not args.input_file:
|
|
453
|
+
# --emit-actions-only's whole contract is "never call gh" (issue
|
|
454
|
+
# #1700's cloud-session caller has none available). Without
|
|
455
|
+
# --input-file, _load_issues falls through to the live gh fetch on
|
|
456
|
+
# the READ side — --emit-actions-only only ever suppressed the WRITE
|
|
457
|
+
# side. Fail loudly here rather than silently degrading the promise.
|
|
458
|
+
parser.error("--emit-actions-only requires --input-file (it never calls gh)")
|
|
459
|
+
now = args.now_override or datetime.now(timezone.utc).replace(tzinfo=None)
|
|
460
|
+
|
|
461
|
+
try:
|
|
462
|
+
issues = _load_issues(args)
|
|
463
|
+
except ReclaimError as exc:
|
|
464
|
+
print(f"autoship_reclaim: {exc}", file=sys.stderr)
|
|
465
|
+
return 1
|
|
466
|
+
|
|
467
|
+
orphaned = select_orphaned(issues, args.stale_after_hours, now)
|
|
468
|
+
|
|
469
|
+
if not orphaned:
|
|
470
|
+
# Under --emit-actions-only, stdout is a one-JSON-action-per-line
|
|
471
|
+
# machine contract (see _reclaim_issue) — this notice goes to stderr
|
|
472
|
+
# so a caller parsing stdout line-by-line never hits a non-JSON line
|
|
473
|
+
# on the empty-round path, the most common one. --dry-run still
|
|
474
|
+
# takes precedence (matching _reclaim_issue's own dry-run-wins rule):
|
|
475
|
+
# its "would-reclaim" preview lines print to stdout for a non-empty
|
|
476
|
+
# round, so this notice must too for an empty one, on the same
|
|
477
|
+
# --dry-run --emit-actions-only combination the SKILL.md documents.
|
|
478
|
+
emitting = args.emit_actions_only and not args.dry_run
|
|
479
|
+
stream = sys.stderr if emitting else sys.stdout
|
|
480
|
+
print("No orphaned autoship:in-progress issues found.", file=stream)
|
|
481
|
+
return 0
|
|
482
|
+
|
|
483
|
+
exit_code = 0
|
|
484
|
+
for issue in orphaned:
|
|
485
|
+
rc = _reclaim_issue(
|
|
486
|
+
issue, args.stale_after_hours, now, args.dry_run, args.emit_actions_only
|
|
487
|
+
)
|
|
488
|
+
if rc != 0:
|
|
489
|
+
exit_code = rc
|
|
490
|
+
|
|
491
|
+
return exit_code
|
|
492
|
+
|
|
493
|
+
|
|
494
|
+
if __name__ == "__main__":
|
|
495
|
+
raise SystemExit(main(sys.argv[1:]))
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Python port of scripts/build-jobs.sh (#610 / #572 Phase 3).
|
|
3
|
+
|
|
4
|
+
Resolve the effective build concurrency for a wave:
|
|
5
|
+
|
|
6
|
+
effective = min(requested --jobs, DEV_TEAM_MAX_PARALLEL_BUILDS, wave width)
|
|
7
|
+
|
|
8
|
+
A requested value or max that is zero, negative, or non-integer clamps to 1
|
|
9
|
+
(deterministic, never an error). Parallel fan-out is opt-in: when neither
|
|
10
|
+
`--jobs` nor `DEV_TEAM_MAX_PARALLEL_BUILDS` is set, the default is sequential
|
|
11
|
+
(effective 1) — fan-out never *saves* tokens, it trades them for wall-clock, so
|
|
12
|
+
it is never the silent default (#1515). An explicit `--jobs N` opts in, bounded
|
|
13
|
+
only by wave width; an explicit `DEV_TEAM_MAX_PARALLEL_BUILDS` opts in and is
|
|
14
|
+
honored verbatim (never re-capped by any per-host ceiling), with an unset
|
|
15
|
+
`--jobs` then fanning out to that env max. `--jobs 1` resolves to 1 — the
|
|
16
|
+
sequential decision. Prints the effective integer on stdout and a human-readable
|
|
17
|
+
resolution line on stderr.
|
|
18
|
+
|
|
19
|
+
Usage: build_jobs.py --wave-width W [--jobs N]
|
|
20
|
+
|
|
21
|
+
Stdlib-only. See docs/python-hook-contract.md.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
from __future__ import annotations
|
|
25
|
+
|
|
26
|
+
import os
|
|
27
|
+
import sys
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _norm(value: str) -> int:
|
|
31
|
+
"""A positive integer stays; anything else (empty, 0, negative, non-numeric)
|
|
32
|
+
clamps to 1 — matches the .sh's `norm()` function exactly, deterministic and
|
|
33
|
+
never raising."""
|
|
34
|
+
if not value:
|
|
35
|
+
return 1
|
|
36
|
+
# Require ASCII decimals. `str.isdigit()` alone is True for non-decimal
|
|
37
|
+
# Unicode digits (e.g. superscript "²") that `int()` then rejects with
|
|
38
|
+
# ValueError — the `isascii()` guard keeps the "never an error" contract.
|
|
39
|
+
# Bash's `case '$1' in ''|*[!0-9]*) echo 1` likewise treats "-2" as
|
|
40
|
+
# non-numeric (the leading dash is a non-digit character).
|
|
41
|
+
if not (value.isascii() and value.isdigit()):
|
|
42
|
+
return 1
|
|
43
|
+
n = int(value)
|
|
44
|
+
return max(n, 1)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _parse_argv(argv: list[str]) -> tuple:
|
|
48
|
+
"""Return (jobs_str, width_str). Bash's arg loop: unknown flags → usage
|
|
49
|
+
error + exit 2. Missing arg to a known flag reads empty (bash `${2:-}`)."""
|
|
50
|
+
jobs = ""
|
|
51
|
+
width = ""
|
|
52
|
+
i = 0
|
|
53
|
+
while i < len(argv):
|
|
54
|
+
tok = argv[i]
|
|
55
|
+
if tok == "--jobs":
|
|
56
|
+
jobs = argv[i + 1] if i + 1 < len(argv) else ""
|
|
57
|
+
i += 2
|
|
58
|
+
elif tok == "--wave-width":
|
|
59
|
+
width = argv[i + 1] if i + 1 < len(argv) else ""
|
|
60
|
+
i += 2
|
|
61
|
+
else:
|
|
62
|
+
print("usage: build-jobs.sh --wave-width W [--jobs N]", file=sys.stderr)
|
|
63
|
+
sys.exit(2)
|
|
64
|
+
return jobs, width
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def _resolve_max(width: int, max_env: str | None) -> tuple:
|
|
68
|
+
"""Resolve the concurrency ceiling and report whether the env opted in. The
|
|
69
|
+
env var's presence is the opt-in-to-parallel signal: set → honored verbatim
|
|
70
|
+
(even above any old per-host ceiling); unset → no independent ceiling, so
|
|
71
|
+
wave width alone bounds an explicit --jobs (#1515). Returns (max_, env_set)."""
|
|
72
|
+
env_set = bool(max_env)
|
|
73
|
+
return (_norm(max_env) if env_set else width), env_set
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def _resolve_jobs(jobs_raw: str, env_set: bool, max_: int) -> int:
|
|
77
|
+
"""Resolve the requested job count. Default is sequential (#1515): with
|
|
78
|
+
neither --jobs nor the env var set, nothing opts into fan-out, so jobs is 1.
|
|
79
|
+
An explicit env with no --jobs fans to that env max; an explicit --jobs is
|
|
80
|
+
honored as requested."""
|
|
81
|
+
if jobs_raw:
|
|
82
|
+
return _norm(jobs_raw)
|
|
83
|
+
if env_set:
|
|
84
|
+
return max_
|
|
85
|
+
return 1
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def main(argv: list[str]) -> int:
|
|
89
|
+
jobs_raw, width_raw = _parse_argv(argv)
|
|
90
|
+
|
|
91
|
+
width = _norm(width_raw if width_raw else "1")
|
|
92
|
+
max_, env_set = _resolve_max(width, os.environ.get("DEV_TEAM_MAX_PARALLEL_BUILDS"))
|
|
93
|
+
jobs = _resolve_jobs(jobs_raw, env_set, max_)
|
|
94
|
+
eff = min(jobs, max_, width)
|
|
95
|
+
|
|
96
|
+
# Bash: requested=${JOBS:-(unset)} — literal "(unset)" when empty.
|
|
97
|
+
requested = jobs_raw if jobs_raw else "(unset)"
|
|
98
|
+
print(
|
|
99
|
+
f"build-jobs: requested={requested} max={max_} wave_width={width} "
|
|
100
|
+
f"-> effective={eff}",
|
|
101
|
+
file=sys.stderr,
|
|
102
|
+
)
|
|
103
|
+
print(eff)
|
|
104
|
+
return 0
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
if __name__ == "__main__":
|
|
108
|
+
raise SystemExit(main(sys.argv[1:]))
|