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,306 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""One shared context pack for a review panel (#2006). OPT-IN, off by default.
|
|
3
|
+
|
|
4
|
+
**This is not the default dispatch path.** `code-review/SKILL.md` step 4 uses
|
|
5
|
+
the per-agent context payload unless the caller sets
|
|
6
|
+
`DEV_TEAM_REVIEW_CONTEXT_PACK=on`. ADR 0034 declined a shared-context pre-pass
|
|
7
|
+
after measuring duplicate full-file reads at 0.38%-4.86% of a round's total
|
|
8
|
+
input spend (median 0.8%); a later re-measurement with the same tool put it at
|
|
9
|
+
0.22%. The 4.31x multiplier quoted for this problem is a read-volume ratio, a
|
|
10
|
+
different denominator from the one that decision turns on. #2024 tracks
|
|
11
|
+
measuring panels of >= 8 agents, the shape that could change the answer.
|
|
12
|
+
|
|
13
|
+
The pack ships complete file bodies, not the structural skeleton ADR 0034
|
|
14
|
+
warned would starve line-level lenses, so it carries no known quality risk —
|
|
15
|
+
it simply has not been shown to pay for its complexity.
|
|
16
|
+
|
|
17
|
+
Every lens in a `/code-review` panel is handed the same changed files and then
|
|
18
|
+
reads them itself. Measured across 148 panels of >= 8 agents: **180 MB of Read
|
|
19
|
+
volume covering 41.8 MB of unique content — a 4.31x re-read multiplier**, with
|
|
20
|
+
one file opened by 38 agents in the worst case. Those panels are 73% of all
|
|
21
|
+
review spend.
|
|
22
|
+
|
|
23
|
+
The multiplier is not only cross-agent duplication. A lens that opens a file,
|
|
24
|
+
greps around it, and opens it again pays for it each time, and the panel pays
|
|
25
|
+
that per lens. What removes it is giving every lens the same prepared bytes
|
|
26
|
+
once, so reading is a single addressed fetch instead of an exploration.
|
|
27
|
+
|
|
28
|
+
## Why one pack serves nearly the whole panel
|
|
29
|
+
|
|
30
|
+
Of the 18 review lenses that declare a `Context needs` value, **17 need the
|
|
31
|
+
full bodies of the changed files** (13 `full-file`, 4 `project-structure`);
|
|
32
|
+
one needs the diff alone. So the union of what the panel needs is: the changed
|
|
33
|
+
file list, the diff, and the full bodies — which is exactly this pack. Each
|
|
34
|
+
lens reads the section its declaration calls for.
|
|
35
|
+
|
|
36
|
+
## What this deliberately does NOT do
|
|
37
|
+
|
|
38
|
+
It does not stop a lens from reading anything else. A lens tracing a caller
|
|
39
|
+
into an unchanged file still should, and still can. The pack removes the
|
|
40
|
+
*repeated* read of the *same* changed files, which is the measured cost; it is
|
|
41
|
+
not a sandbox.
|
|
42
|
+
|
|
43
|
+
## Truncation is always visible
|
|
44
|
+
|
|
45
|
+
A pack over its byte cap omits **whole files**, names every one of them in the
|
|
46
|
+
pack body and in the manifest, and tells the reader to open those directly.
|
|
47
|
+
Silently truncating would hand a lens a file that looks complete and is not —
|
|
48
|
+
a finding-shaped hole that reads as "reviewed". Per this repo's rule, a bound
|
|
49
|
+
that drops coverage says so out loud.
|
|
50
|
+
|
|
51
|
+
Stdlib-only. See docs/python-hook-contract.md.
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
from __future__ import annotations
|
|
55
|
+
|
|
56
|
+
import argparse
|
|
57
|
+
import hashlib
|
|
58
|
+
import json
|
|
59
|
+
import subprocess
|
|
60
|
+
import sys
|
|
61
|
+
from pathlib import Path
|
|
62
|
+
|
|
63
|
+
_PLUGIN_ROOT = Path(__file__).resolve().parents[3]
|
|
64
|
+
_HOOKS_LIB_DIR = _PLUGIN_ROOT / "hooks" / "lib"
|
|
65
|
+
if str(_HOOKS_LIB_DIR) not in sys.path:
|
|
66
|
+
sys.path.insert(0, str(_HOOKS_LIB_DIR))
|
|
67
|
+
|
|
68
|
+
try:
|
|
69
|
+
import artifact_paths # type: ignore[import-not-found]
|
|
70
|
+
except ImportError: # pragma: no cover - degraded fallback, hooks/lib unreachable
|
|
71
|
+
# Same guarded-import shape as the sibling scripts in this directory, which
|
|
72
|
+
# is not in ruff.toml's E402 per-file-ignore list.
|
|
73
|
+
artifact_paths = None
|
|
74
|
+
|
|
75
|
+
#: Default ceiling on the pack body. A pack is read by every lens in the panel,
|
|
76
|
+
#: so bytes here are multiplied by the roster size — the cap is what keeps a
|
|
77
|
+
#: large diff from costing more shared than it saved duplicated.
|
|
78
|
+
DEFAULT_MAX_BYTES = 400_000
|
|
79
|
+
|
|
80
|
+
#: Files above this size are omitted individually rather than crowding out the
|
|
81
|
+
#: rest of the pack. A single generated or vendored file can exceed the whole
|
|
82
|
+
#: budget on its own.
|
|
83
|
+
DEFAULT_MAX_FILE_BYTES = 60_000
|
|
84
|
+
|
|
85
|
+
_CATEGORY = "review-context"
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def _git(args, cwd: Path) -> str:
|
|
89
|
+
try:
|
|
90
|
+
result = subprocess.run(
|
|
91
|
+
["git", "-c", "core.quotePath=false", *args],
|
|
92
|
+
cwd=str(cwd), capture_output=True, text=True, timeout=60, check=False,
|
|
93
|
+
)
|
|
94
|
+
except (OSError, subprocess.SubprocessError):
|
|
95
|
+
return ""
|
|
96
|
+
return result.stdout if result.returncode == 0 else ""
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def read_file_text(path: Path) -> tuple[str | None, str]:
|
|
100
|
+
"""Return (text, reason). `text` is None when the body cannot be included."""
|
|
101
|
+
try:
|
|
102
|
+
if not path.exists():
|
|
103
|
+
return None, "not present in the working tree (deleted or renamed)"
|
|
104
|
+
if path.is_dir():
|
|
105
|
+
return None, "directory"
|
|
106
|
+
raw = path.read_bytes()
|
|
107
|
+
except OSError as exc:
|
|
108
|
+
return None, f"unreadable ({exc.__class__.__name__})"
|
|
109
|
+
if b"\x00" in raw[:8192]:
|
|
110
|
+
return None, "binary"
|
|
111
|
+
try:
|
|
112
|
+
return raw.decode("utf-8"), ""
|
|
113
|
+
except UnicodeDecodeError:
|
|
114
|
+
return None, "not valid UTF-8"
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def number_lines(text: str) -> str:
|
|
118
|
+
"""Line-numbered body, matching how the Read tool presents a file so a lens
|
|
119
|
+
can cite `file:line` from the pack without re-opening the file to count."""
|
|
120
|
+
lines = text.splitlines()
|
|
121
|
+
width = len(str(len(lines))) if lines else 1
|
|
122
|
+
return "\n".join(f"{str(i).rjust(width)}\t{line}" for i, line in enumerate(lines, 1))
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def select_bodies(files, cwd: Path, max_bytes: int, max_file_bytes: int):
|
|
126
|
+
"""Include file bodies in the given order until the budget is spent.
|
|
127
|
+
|
|
128
|
+
Returns (included, omitted) where each entry is a dict. Selection walks the
|
|
129
|
+
caller's order and skips anything that does not fit, rather than stopping
|
|
130
|
+
at the first oversized file — one huge file must not hide every smaller one
|
|
131
|
+
behind it.
|
|
132
|
+
"""
|
|
133
|
+
included, omitted = [], []
|
|
134
|
+
used = 0
|
|
135
|
+
for rel in files:
|
|
136
|
+
text, reason = read_file_text(cwd / rel)
|
|
137
|
+
if text is None:
|
|
138
|
+
omitted.append({"file": rel, "reason": reason})
|
|
139
|
+
continue
|
|
140
|
+
body = number_lines(text)
|
|
141
|
+
size = len(body.encode("utf-8"))
|
|
142
|
+
if size > max_file_bytes:
|
|
143
|
+
omitted.append({"file": rel, "reason": f"exceeds per-file cap ({size} bytes)"})
|
|
144
|
+
continue
|
|
145
|
+
if used + size > max_bytes:
|
|
146
|
+
omitted.append({"file": rel, "reason": "pack byte budget exhausted"})
|
|
147
|
+
continue
|
|
148
|
+
included.append({"file": rel, "body": body, "bytes": size})
|
|
149
|
+
used += size
|
|
150
|
+
return included, omitted
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def render_pack(*, changed, diff_text, included, omitted, base_ref) -> str:
|
|
154
|
+
parts = [
|
|
155
|
+
"# Review context pack",
|
|
156
|
+
"",
|
|
157
|
+
(
|
|
158
|
+
"Prepared once for this panel. Read the section your `Context needs` "
|
|
159
|
+
"declaration calls for instead of opening these files individually — "
|
|
160
|
+
"the bodies below are complete and line-numbered, so `file:line` "
|
|
161
|
+
"citations from this pack are accurate."
|
|
162
|
+
),
|
|
163
|
+
"",
|
|
164
|
+
(
|
|
165
|
+
"You may still open anything NOT listed here (a caller in an unchanged "
|
|
166
|
+
"file, a sibling module). This pack removes the repeated read of the "
|
|
167
|
+
"changed set; it does not limit what you may consult."
|
|
168
|
+
),
|
|
169
|
+
"",
|
|
170
|
+
"## Changed files",
|
|
171
|
+
"",
|
|
172
|
+
]
|
|
173
|
+
if changed:
|
|
174
|
+
# A status is optional: the caller may know the paths without knowing
|
|
175
|
+
# how each changed. Claiming "full-repository scope" in that case (the
|
|
176
|
+
# original behavior) tells a lens the diff is empty when it is not.
|
|
177
|
+
parts += [
|
|
178
|
+
f"- `{status}` {path}" if status else f"- {path}"
|
|
179
|
+
for path, status in changed
|
|
180
|
+
]
|
|
181
|
+
else:
|
|
182
|
+
parts.append("_(no change list — full-repository scope)_")
|
|
183
|
+
parts += ["", "## Diff", ""]
|
|
184
|
+
parts += [f"_(vs `{base_ref}`)_", "", "```diff", diff_text.rstrip("\n") or "(empty)", "```"] \
|
|
185
|
+
if diff_text.strip() else ["_(no diff — full-repository scope)_"]
|
|
186
|
+
|
|
187
|
+
parts += ["", "## File bodies", ""]
|
|
188
|
+
if not included:
|
|
189
|
+
parts.append("_(none included — see omissions below)_")
|
|
190
|
+
for entry in included:
|
|
191
|
+
parts += [f"### {entry['file']}", "", "```", entry["body"], "```", ""]
|
|
192
|
+
|
|
193
|
+
if omitted:
|
|
194
|
+
parts += [
|
|
195
|
+
"## NOT included in this pack",
|
|
196
|
+
"",
|
|
197
|
+
(
|
|
198
|
+
"These files are part of the change but their bodies are not "
|
|
199
|
+
"above. **Open them directly** — do not treat their absence as "
|
|
200
|
+
"'nothing to review here'."
|
|
201
|
+
),
|
|
202
|
+
"",
|
|
203
|
+
]
|
|
204
|
+
parts += [f"- {o['file']} — {o['reason']}" for o in omitted]
|
|
205
|
+
parts.append("")
|
|
206
|
+
return "\n".join(parts) + "\n"
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def _pack_dir(cwd: Path) -> Path:
|
|
210
|
+
if artifact_paths is not None:
|
|
211
|
+
return artifact_paths.category_dir(_CATEGORY, cwd)
|
|
212
|
+
return cwd / ".claude" / _CATEGORY
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def build(
|
|
216
|
+
*, files, cwd: Path, base_ref: str, max_bytes: int, max_file_bytes: int,
|
|
217
|
+
diff_text: str | None = None, changed=None,
|
|
218
|
+
) -> dict:
|
|
219
|
+
ordered = sorted(dict.fromkeys(files))
|
|
220
|
+
if changed is None:
|
|
221
|
+
changed = [(path, "") for path in ordered]
|
|
222
|
+
if diff_text is None:
|
|
223
|
+
diff_text = _git(["-c", "diff.relative=false", "diff", base_ref, "--", *ordered], cwd) \
|
|
224
|
+
if ordered else ""
|
|
225
|
+
included, omitted = select_bodies(ordered, cwd, max_bytes, max_file_bytes)
|
|
226
|
+
text = render_pack(
|
|
227
|
+
changed=changed or [], diff_text=diff_text, included=included,
|
|
228
|
+
omitted=omitted, base_ref=base_ref,
|
|
229
|
+
)
|
|
230
|
+
digest = hashlib.sha256(text.encode("utf-8")).hexdigest()[:16]
|
|
231
|
+
out_dir = _pack_dir(cwd)
|
|
232
|
+
out_dir.mkdir(parents=True, exist_ok=True)
|
|
233
|
+
out_path = out_dir / f"pack-{digest}.md"
|
|
234
|
+
out_path.write_text(text, encoding="utf-8")
|
|
235
|
+
|
|
236
|
+
unique_bytes = sum(e["bytes"] for e in included)
|
|
237
|
+
return {
|
|
238
|
+
"path": str(out_path),
|
|
239
|
+
"pack_bytes": len(text.encode("utf-8")),
|
|
240
|
+
"unique_body_bytes": unique_bytes,
|
|
241
|
+
"files_requested": len(ordered),
|
|
242
|
+
"files_included": [e["file"] for e in included],
|
|
243
|
+
"files_omitted": omitted,
|
|
244
|
+
"complete": not omitted,
|
|
245
|
+
"base_ref": base_ref,
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
def parse_name_status(lines) -> list[tuple[str, str]]:
|
|
250
|
+
"""Parse `git diff --name-status` rows into (path, status) pairs.
|
|
251
|
+
|
|
252
|
+
Rename and copy rows carry two paths (`R100\told\tnew`); the NEW path is
|
|
253
|
+
the one that exists on disk and the one findings are cited against, so it
|
|
254
|
+
is the one kept.
|
|
255
|
+
"""
|
|
256
|
+
out: list[tuple[str, str]] = []
|
|
257
|
+
for line in lines:
|
|
258
|
+
parts = line.split("\t")
|
|
259
|
+
if len(parts) < 2 or not parts[0].strip():
|
|
260
|
+
continue
|
|
261
|
+
status = parts[0].strip()[0].upper()
|
|
262
|
+
path = parts[-1].strip() if status in {"R", "C"} else parts[1].strip()
|
|
263
|
+
if path:
|
|
264
|
+
out.append((path, status))
|
|
265
|
+
return out
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
def _read_file_list(source: str | None) -> list[str]:
|
|
269
|
+
if not source:
|
|
270
|
+
return []
|
|
271
|
+
text = sys.stdin.read() if source == "-" else Path(source).read_text(encoding="utf-8")
|
|
272
|
+
return [line.strip() for line in text.splitlines() if line.strip()]
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
def main(argv=None) -> int:
|
|
276
|
+
parser = argparse.ArgumentParser(
|
|
277
|
+
description="Build one shared context pack for a review panel (#2006)."
|
|
278
|
+
)
|
|
279
|
+
parser.add_argument("--files-from", default="-",
|
|
280
|
+
help="file with one changed path per line, or '-' for stdin")
|
|
281
|
+
parser.add_argument("--name-status-from", default=None,
|
|
282
|
+
help="file of `git diff --name-status` lines (or '-'), "
|
|
283
|
+
"so the pack can label each path A/M/D/R/C")
|
|
284
|
+
parser.add_argument("--base", default="HEAD", dest="base_ref")
|
|
285
|
+
parser.add_argument("--cwd", default=None)
|
|
286
|
+
parser.add_argument("--max-bytes", type=int, default=DEFAULT_MAX_BYTES)
|
|
287
|
+
parser.add_argument("--max-file-bytes", type=int, default=DEFAULT_MAX_FILE_BYTES)
|
|
288
|
+
args = parser.parse_args(argv)
|
|
289
|
+
|
|
290
|
+
cwd = Path(args.cwd) if args.cwd else Path.cwd()
|
|
291
|
+
changed = parse_name_status(_read_file_list(args.name_status_from)) \
|
|
292
|
+
if args.name_status_from else None
|
|
293
|
+
files = [p for p, _ in changed] if changed else _read_file_list(args.files_from)
|
|
294
|
+
if not files:
|
|
295
|
+
print(json.dumps({"error": "no files given", "path": None}))
|
|
296
|
+
return 1
|
|
297
|
+
manifest = build(
|
|
298
|
+
files=files, cwd=cwd, base_ref=args.base_ref, changed=changed,
|
|
299
|
+
max_bytes=args.max_bytes, max_file_bytes=args.max_file_bytes,
|
|
300
|
+
)
|
|
301
|
+
print(json.dumps(manifest, indent=2, sort_keys=True))
|
|
302
|
+
return 0
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
if __name__ == "__main__":
|
|
306
|
+
sys.exit(main())
|
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Round-level review-value instrumentation for `/code-review` (#1624).
|
|
3
|
+
|
|
4
|
+
`metrics/review-value.jsonl` today is written only by `/build`'s inline
|
|
5
|
+
checkpoints (#348) and records nothing about `/code-review`'s OWN fix-loop
|
|
6
|
+
rounds. That gap is why #1623's central question — is `correctness-review`'s
|
|
7
|
+
24-dispatch frequency delivering proportional value, or is it churn? — is
|
|
8
|
+
unanswerable, and why no churn-reduction mechanism can prove it worked.
|
|
9
|
+
|
|
10
|
+
This module writes one row per `/code-review` round to the same stream, with
|
|
11
|
+
`source: "code-review"` (the value `/harness-audit` Step 4 already knows to
|
|
12
|
+
exclude from fix-rate drop-candidate logic — see `knowledge/telemetry-schema.md`).
|
|
13
|
+
|
|
14
|
+
## The one judgment-free signal: fix provenance
|
|
15
|
+
|
|
16
|
+
`fix_provenance_new` counts how many of a round's NEW findings land inside
|
|
17
|
+
the line ranges the PREVIOUS round's fix actually touched. That is the
|
|
18
|
+
"the fix introduced it" signal, and it is computed by interval math over a
|
|
19
|
+
unified diff — no LLM judgment, no heuristics about finding text. A round
|
|
20
|
+
whose new error/warning findings ALL carry fix provenance is churn by
|
|
21
|
+
construction: every problem it found was created by the round before it.
|
|
22
|
+
|
|
23
|
+
Intervals are taken from the diff's **new side** (the `+` file's line
|
|
24
|
+
numbers), because that is the coordinate system findings are reported in:
|
|
25
|
+
an agent re-reading the post-fix file reports `file:line` against the
|
|
26
|
+
content that now exists on disk.
|
|
27
|
+
|
|
28
|
+
## Location & gating (issue #1624 design item 2)
|
|
29
|
+
|
|
30
|
+
Writes to `.claude/metrics/` **unconditionally**, matching
|
|
31
|
+
`boundary-events.jsonl` rather than `/build`'s consent-gated
|
|
32
|
+
`~/.claude/telemetry.json` path. Rationale, as recorded on the issue: this
|
|
33
|
+
is the same class of local, counts-only operational stream the commit gate
|
|
34
|
+
itself already depends on, and gating it behind consent would make the
|
|
35
|
+
epic's success criteria depend on consent being enabled on dev machines.
|
|
36
|
+
Rows carry counts, agent names, and enum values only — never code, file
|
|
37
|
+
content, or message text.
|
|
38
|
+
|
|
39
|
+
Stdlib-only. See docs/python-hook-contract.md.
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
from __future__ import annotations
|
|
43
|
+
|
|
44
|
+
import argparse
|
|
45
|
+
import json
|
|
46
|
+
import re
|
|
47
|
+
import sys
|
|
48
|
+
from datetime import datetime, timezone
|
|
49
|
+
from pathlib import Path
|
|
50
|
+
|
|
51
|
+
# skills/code-review/scripts -> skills/code-review -> skills -> plugin root
|
|
52
|
+
_PLUGIN_ROOT = Path(__file__).resolve().parents[3]
|
|
53
|
+
_HOOKS_LIB_DIR = _PLUGIN_ROOT / "hooks" / "lib"
|
|
54
|
+
if str(_HOOKS_LIB_DIR) not in sys.path:
|
|
55
|
+
sys.path.insert(0, str(_HOOKS_LIB_DIR))
|
|
56
|
+
|
|
57
|
+
try:
|
|
58
|
+
import artifact_paths # type: ignore[import-not-found]
|
|
59
|
+
except ImportError: # pragma: no cover - degraded fallback, hooks/lib unreachable
|
|
60
|
+
# Guarded-import form matching `change_shape.py`'s sibling pattern: this
|
|
61
|
+
# directory is not in `ruff.toml`'s E402 per-file-ignore list, and the
|
|
62
|
+
# import genuinely cannot precede the `sys.path` setup above. The fallback
|
|
63
|
+
# resolves the same default location `artifact_paths.resolve_file` would,
|
|
64
|
+
# minus the legacy-path migration — enough for an append-only metrics
|
|
65
|
+
# writer that is already fail-open.
|
|
66
|
+
artifact_paths = None
|
|
67
|
+
|
|
68
|
+
_STREAM_NAME = "review-value.jsonl"
|
|
69
|
+
_SOURCE = "code-review"
|
|
70
|
+
|
|
71
|
+
#: `dispatch_purpose` values. `discovery` = a panel looking for new problems
|
|
72
|
+
#: (round 1, and any full re-panel); `verification` = a re-dispatch confirming
|
|
73
|
+
#: a specific fix (#1628); `closing` = the scoped gate-closing pass (#1626).
|
|
74
|
+
DISPATCH_PURPOSES = ("discovery", "verification", "closing")
|
|
75
|
+
|
|
76
|
+
#: `outcome` values — the same closed enum `/build`'s rows already use, so the
|
|
77
|
+
#: two `source` values stay aggregatable in one query.
|
|
78
|
+
OUTCOMES = ("fixed", "no-op", "escalated")
|
|
79
|
+
|
|
80
|
+
#: `@@ -old,oldcount +new,newcount @@` — the counts are optional (git omits
|
|
81
|
+
#: `,1`), and anything may follow the closing `@@` (the hunk-header context).
|
|
82
|
+
_HUNK_RE = re.compile(r"^@@ -\d+(?:,\d+)? \+(\d+)(?:,(\d+))? @@")
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def _now_iso() -> str:
|
|
86
|
+
return datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def changed_line_intervals(diff_text: str) -> dict:
|
|
90
|
+
"""Parse a unified diff into `{path: [(start, end), ...]}` — inclusive
|
|
91
|
+
NEW-side line ranges that the diff added or modified.
|
|
92
|
+
|
|
93
|
+
Only `+` lines (and their positions) count as changed. A hunk that is
|
|
94
|
+
pure deletion contributes no interval: there is no post-fix line for a
|
|
95
|
+
finding to be reported against, so a deletion can never be the *site* of
|
|
96
|
+
a new finding. Context lines advance the new-side counter without
|
|
97
|
+
producing an interval.
|
|
98
|
+
|
|
99
|
+
Paths come from the `+++ b/<path>` header with the `b/` prefix stripped;
|
|
100
|
+
`/dev/null` (a pure delete) is skipped. Consecutive added lines collapse
|
|
101
|
+
into one interval so the returned list stays small on large diffs.
|
|
102
|
+
|
|
103
|
+
Malformed input degrades to fewer intervals, never to an exception — a
|
|
104
|
+
caller that can't parse the diff simply gets no provenance credit, which
|
|
105
|
+
is the conservative direction (it under-reports churn rather than
|
|
106
|
+
inventing it).
|
|
107
|
+
"""
|
|
108
|
+
intervals: dict = {}
|
|
109
|
+
path: str | None = None
|
|
110
|
+
new_line = 0
|
|
111
|
+
run_start: int | None = None
|
|
112
|
+
run_end: int | None = None
|
|
113
|
+
|
|
114
|
+
def flush() -> None:
|
|
115
|
+
nonlocal run_start, run_end
|
|
116
|
+
if path is not None and run_start is not None and run_end is not None:
|
|
117
|
+
intervals.setdefault(path, []).append((run_start, run_end))
|
|
118
|
+
run_start = None
|
|
119
|
+
run_end = None
|
|
120
|
+
|
|
121
|
+
for raw in diff_text.splitlines():
|
|
122
|
+
if raw.startswith("+++ "):
|
|
123
|
+
flush()
|
|
124
|
+
target = raw[4:].strip()
|
|
125
|
+
# Strip git's `b/` prefix; tolerate `--src-prefix`-less diffs.
|
|
126
|
+
if target == "/dev/null":
|
|
127
|
+
path = None
|
|
128
|
+
else:
|
|
129
|
+
path = target.removeprefix("b/")
|
|
130
|
+
new_line = 0
|
|
131
|
+
continue
|
|
132
|
+
if raw.startswith(("--- ", "diff --git ")):
|
|
133
|
+
flush()
|
|
134
|
+
continue
|
|
135
|
+
match = _HUNK_RE.match(raw)
|
|
136
|
+
if match:
|
|
137
|
+
flush()
|
|
138
|
+
new_line = int(match.group(1))
|
|
139
|
+
continue
|
|
140
|
+
if path is None:
|
|
141
|
+
continue
|
|
142
|
+
if raw.startswith("+"):
|
|
143
|
+
if run_start is None:
|
|
144
|
+
run_start = new_line
|
|
145
|
+
run_end = new_line
|
|
146
|
+
new_line += 1
|
|
147
|
+
elif raw.startswith("-"):
|
|
148
|
+
# Deletion: consumes an old-side line only. Does not advance the
|
|
149
|
+
# new-side counter and never opens an interval.
|
|
150
|
+
continue
|
|
151
|
+
elif raw.startswith("\\"):
|
|
152
|
+
# "" — belongs to whichever side
|
|
153
|
+
# preceded it and moves no counter.
|
|
154
|
+
continue
|
|
155
|
+
else:
|
|
156
|
+
# Context line (leading space) or a stray blank line git emits
|
|
157
|
+
# for an empty context line.
|
|
158
|
+
flush()
|
|
159
|
+
new_line += 1
|
|
160
|
+
|
|
161
|
+
flush()
|
|
162
|
+
return intervals
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def _normalize_path(value: str) -> str:
|
|
166
|
+
"""Compare paths by their POSIX form without a leading `./`, so a finding
|
|
167
|
+
reported as `./src/a.js` matches a diff header's `src/a.js`."""
|
|
168
|
+
text = str(value).replace("\\", "/")
|
|
169
|
+
while text.startswith("./"):
|
|
170
|
+
text = text[2:]
|
|
171
|
+
return text
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def finding_has_fix_provenance(finding: dict, intervals: dict) -> bool:
|
|
175
|
+
"""True when this finding's `file:line` falls inside a line range the
|
|
176
|
+
previous round's fix touched — i.e. the fix is where this finding lives.
|
|
177
|
+
|
|
178
|
+
A finding with no usable `line` (missing, non-integer, or <= 0) is NOT
|
|
179
|
+
credited: "somewhere in a file the fix touched" is too weak a claim to
|
|
180
|
+
call churn on. Same conservative direction as `changed_line_intervals`.
|
|
181
|
+
"""
|
|
182
|
+
path = finding.get("file")
|
|
183
|
+
if not isinstance(path, str) or not path:
|
|
184
|
+
return False
|
|
185
|
+
line = finding.get("line")
|
|
186
|
+
if isinstance(line, bool) or not isinstance(line, int) or line <= 0:
|
|
187
|
+
return False
|
|
188
|
+
key = _normalize_path(path)
|
|
189
|
+
for candidate, ranges in intervals.items():
|
|
190
|
+
if _normalize_path(candidate) != key:
|
|
191
|
+
continue
|
|
192
|
+
if any(start <= line <= end for start, end in ranges):
|
|
193
|
+
return True
|
|
194
|
+
return False
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def count_fix_provenance(findings, intervals: dict) -> int:
|
|
198
|
+
"""How many of `findings` land inside the previous round's fix delta."""
|
|
199
|
+
return sum(1 for f in findings if isinstance(f, dict) and finding_has_fix_provenance(f, intervals))
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def severity_breakdown(findings) -> dict:
|
|
203
|
+
"""`{errors, warnings, suggestions}` counts over a finding list — the
|
|
204
|
+
same three-bucket shape `/build`'s rows already carry, so both `source`
|
|
205
|
+
values aggregate in one query. Unrecognized severities are dropped
|
|
206
|
+
rather than bucketed, keeping the three keys' sum meaningful."""
|
|
207
|
+
counts = {"errors": 0, "warnings": 0, "suggestions": 0}
|
|
208
|
+
bucket = {"error": "errors", "warning": "warnings", "suggestion": "suggestions"}
|
|
209
|
+
for finding in findings:
|
|
210
|
+
if not isinstance(finding, dict):
|
|
211
|
+
continue
|
|
212
|
+
key = bucket.get(str(finding.get("severity", "")).lower())
|
|
213
|
+
if key:
|
|
214
|
+
counts[key] += 1
|
|
215
|
+
return counts
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
def build_round_entry(
|
|
219
|
+
*,
|
|
220
|
+
round_number: int,
|
|
221
|
+
agents_run,
|
|
222
|
+
findings_new,
|
|
223
|
+
findings_carried: int,
|
|
224
|
+
dispatch_purpose: str,
|
|
225
|
+
outcome: str,
|
|
226
|
+
fix_diff: str = "",
|
|
227
|
+
timestamp: str | None = None,
|
|
228
|
+
) -> dict:
|
|
229
|
+
"""Assemble one `review-value.jsonl` row for a `/code-review` round.
|
|
230
|
+
|
|
231
|
+
`findings_new` is this round's NEW findings (carried-over signatures are
|
|
232
|
+
counted separately via `findings_carried` — see #1625's round ledger,
|
|
233
|
+
which owns signature identity). `fix_diff` is the unified diff of the
|
|
234
|
+
PREVIOUS round's fix; empty for round 1, which by definition has no
|
|
235
|
+
preceding fix and therefore always reports `fix_provenance_new: 0`.
|
|
236
|
+
"""
|
|
237
|
+
if dispatch_purpose not in DISPATCH_PURPOSES:
|
|
238
|
+
raise ValueError(f"dispatch_purpose must be one of {DISPATCH_PURPOSES}")
|
|
239
|
+
if outcome not in OUTCOMES:
|
|
240
|
+
raise ValueError(f"outcome must be one of {OUTCOMES}")
|
|
241
|
+
|
|
242
|
+
findings = [f for f in findings_new if isinstance(f, dict)]
|
|
243
|
+
intervals = changed_line_intervals(fix_diff) if fix_diff else {}
|
|
244
|
+
return {
|
|
245
|
+
"timestamp": timestamp or _now_iso(),
|
|
246
|
+
"source": _SOURCE,
|
|
247
|
+
"round": int(round_number),
|
|
248
|
+
"agents_run": sorted({str(a) for a in agents_run}),
|
|
249
|
+
"findings_new": len(findings),
|
|
250
|
+
"findings_carried": int(findings_carried),
|
|
251
|
+
"severity_breakdown": severity_breakdown(findings),
|
|
252
|
+
"fix_provenance_new": count_fix_provenance(findings, intervals),
|
|
253
|
+
"dispatch_purpose": dispatch_purpose,
|
|
254
|
+
"outcome": outcome,
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
def append_round(entry: dict, cwd=None) -> Path | None:
|
|
259
|
+
"""Append one row to `.claude/metrics/review-value.jsonl`.
|
|
260
|
+
|
|
261
|
+
Fail-open on the write, matching every other metrics emitter in this
|
|
262
|
+
plugin: a full disk or read-only metrics directory must never fail a
|
|
263
|
+
review. Returns the path written, or `None` when the write failed.
|
|
264
|
+
"""
|
|
265
|
+
try:
|
|
266
|
+
base = Path(cwd) if cwd else Path.cwd()
|
|
267
|
+
log = (
|
|
268
|
+
artifact_paths.resolve_file("metrics", _STREAM_NAME, base)
|
|
269
|
+
if artifact_paths is not None
|
|
270
|
+
else base / ".claude" / "metrics" / _STREAM_NAME
|
|
271
|
+
)
|
|
272
|
+
log.parent.mkdir(parents=True, exist_ok=True)
|
|
273
|
+
with open(log, "a", encoding="utf-8") as handle:
|
|
274
|
+
handle.write(json.dumps(entry, separators=(",", ":"), sort_keys=True) + "\n")
|
|
275
|
+
return log
|
|
276
|
+
except Exception: # noqa: BLE001 - fail-open: telemetry never blocks a review
|
|
277
|
+
return None
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
def _load_findings(path: str | None):
|
|
281
|
+
if not path:
|
|
282
|
+
return []
|
|
283
|
+
text = sys.stdin.read() if path == "-" else Path(path).read_text(encoding="utf-8")
|
|
284
|
+
if not text.strip():
|
|
285
|
+
return []
|
|
286
|
+
data = json.loads(text)
|
|
287
|
+
if isinstance(data, dict):
|
|
288
|
+
data = data.get("findings", [])
|
|
289
|
+
return data if isinstance(data, list) else []
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
def main(argv=None) -> int:
|
|
293
|
+
parser = argparse.ArgumentParser(description="Append one /code-review round to review-value.jsonl")
|
|
294
|
+
parser.add_argument("--round", type=int, required=True, dest="round_number")
|
|
295
|
+
parser.add_argument(
|
|
296
|
+
"--agents", default="", help="Comma-separated agent names dispatched this round"
|
|
297
|
+
)
|
|
298
|
+
parser.add_argument(
|
|
299
|
+
"--findings",
|
|
300
|
+
default=None,
|
|
301
|
+
help="Path to this round's NEW findings JSON (a list, or {findings: [...]}); '-' for stdin",
|
|
302
|
+
)
|
|
303
|
+
parser.add_argument("--carried", type=int, default=0, dest="findings_carried")
|
|
304
|
+
parser.add_argument("--purpose", required=True, choices=list(DISPATCH_PURPOSES))
|
|
305
|
+
parser.add_argument("--outcome", required=True, choices=list(OUTCOMES))
|
|
306
|
+
parser.add_argument(
|
|
307
|
+
"--fix-diff",
|
|
308
|
+
default=None,
|
|
309
|
+
dest="fix_diff",
|
|
310
|
+
help="Path to the PREVIOUS round's fix diff (unified); '-' for stdin. Omit for round 1.",
|
|
311
|
+
)
|
|
312
|
+
parser.add_argument("--cwd", default=None)
|
|
313
|
+
parser.add_argument(
|
|
314
|
+
"--dry-run",
|
|
315
|
+
action="store_true",
|
|
316
|
+
help="Print the row that would be appended without writing it",
|
|
317
|
+
)
|
|
318
|
+
args = parser.parse_args(argv)
|
|
319
|
+
|
|
320
|
+
findings = _load_findings(args.findings)
|
|
321
|
+
fix_diff = ""
|
|
322
|
+
if args.fix_diff:
|
|
323
|
+
fix_diff = (
|
|
324
|
+
sys.stdin.read()
|
|
325
|
+
if args.fix_diff == "-"
|
|
326
|
+
else Path(args.fix_diff).read_text(encoding="utf-8")
|
|
327
|
+
)
|
|
328
|
+
|
|
329
|
+
entry = build_round_entry(
|
|
330
|
+
round_number=args.round_number,
|
|
331
|
+
agents_run=[a.strip() for a in args.agents.split(",") if a.strip()],
|
|
332
|
+
findings_new=findings,
|
|
333
|
+
findings_carried=args.findings_carried,
|
|
334
|
+
dispatch_purpose=args.purpose,
|
|
335
|
+
outcome=args.outcome,
|
|
336
|
+
fix_diff=fix_diff,
|
|
337
|
+
)
|
|
338
|
+
if not args.dry_run:
|
|
339
|
+
append_round(entry, args.cwd)
|
|
340
|
+
print(json.dumps(entry, sort_keys=True))
|
|
341
|
+
return 0
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
if __name__ == "__main__":
|
|
345
|
+
raise SystemExit(main(sys.argv[1:]))
|