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,193 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""mutation_gate.py — PostToolUse hook (Python port of mutation-gate.sh).
|
|
3
|
+
|
|
4
|
+
After each RED-to-GREEN test transition, runs mutation testing scoped to
|
|
5
|
+
the affected test file and blocks tests that kill zero mutants.
|
|
6
|
+
|
|
7
|
+
Output protocol (PostToolUse):
|
|
8
|
+
Blocking : `emit_block` JSON on stdout, exit 0.
|
|
9
|
+
Advisory : `emit_advisory` JSON on stdout, exit 0.
|
|
10
|
+
Silent : no stdout, exit 0.
|
|
11
|
+
|
|
12
|
+
Delegates to `hooks.mutation_adapters` for detection, dispatch, and per-
|
|
13
|
+
adapter execution — the same Python library shipped in #572.D0.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
import json
|
|
19
|
+
import os
|
|
20
|
+
import shutil
|
|
21
|
+
import sys
|
|
22
|
+
from pathlib import Path
|
|
23
|
+
|
|
24
|
+
_HOOK_DIR = Path(__file__).resolve().parent
|
|
25
|
+
# Add the plugin hooks dir to sys.path so the mutation_adapters package resolves.
|
|
26
|
+
sys.path.insert(0, str(_HOOK_DIR))
|
|
27
|
+
sys.path.insert(0, str(_HOOK_DIR / "lib"))
|
|
28
|
+
|
|
29
|
+
from boundary_events import emit_boundary_event as _emit_boundary_event
|
|
30
|
+
from mutation_adapters import lib as adapter_lib
|
|
31
|
+
from mutation_adapters import mutmut, pitest, stryker, stryker_net
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def emit_boundary_event(*args, **kwargs) -> None:
|
|
35
|
+
"""Local safety net (#859): even a misbehaving helper must never affect
|
|
36
|
+
this hook's exit code, stdout, or stderr."""
|
|
37
|
+
try:
|
|
38
|
+
_emit_boundary_event(*args, **kwargs)
|
|
39
|
+
except Exception: # noqa: BLE001, S110 - fail-open by design
|
|
40
|
+
pass
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
_JQ_MISSING_MESSAGE = (
|
|
44
|
+
"MUTATION GATE ADVISORY: jq is required but not installed. Run "
|
|
45
|
+
"/setup to install it, or: brew install jq (macOS) / apt install jq "
|
|
46
|
+
"(Linux) / winget install jqlang.jq (Windows)."
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _emit_advisory_pretty(message: str) -> None:
|
|
51
|
+
"""Emit an advisory in bash `jq -n`'s pretty format (2-space indent + \\n).
|
|
52
|
+
|
|
53
|
+
`mutation-gate.sh` prints its advisories with `jq -n` so downstream Claude
|
|
54
|
+
Code output stays visually indented. This matches that shape byte-for-byte
|
|
55
|
+
for the paths the mutation-gate hook itself dispatches; the adapters still
|
|
56
|
+
print compact JSON (their internal `emit_advisory` returns compact),
|
|
57
|
+
tracked for the next release cycle when the settings-toggle flips
|
|
58
|
+
default to `.py`.
|
|
59
|
+
"""
|
|
60
|
+
print(
|
|
61
|
+
json.dumps(
|
|
62
|
+
{
|
|
63
|
+
"hookSpecificOutput": {
|
|
64
|
+
"hookEventName": "PostToolUse",
|
|
65
|
+
"additionalContext": message,
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
indent=2,
|
|
69
|
+
)
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def _emit_block_pretty(reason: str) -> None:
|
|
74
|
+
print(json.dumps({"decision": "block", "reason": reason}, indent=2))
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def main() -> int:
|
|
78
|
+
# Hard dependency guards — mirror the bash order.
|
|
79
|
+
if shutil.which("jq") is None:
|
|
80
|
+
_emit_advisory_pretty(_JQ_MISSING_MESSAGE)
|
|
81
|
+
return 0
|
|
82
|
+
# python3 is by definition available here (we are python3), but if the
|
|
83
|
+
# bash sibling migrates a caller through the settings-toggle env var, the
|
|
84
|
+
# advisory would already have fired. Keep the branch for parity of the
|
|
85
|
+
# shape, harmlessly no-op.
|
|
86
|
+
|
|
87
|
+
if os.environ.get("MUTATION_GATE_SKIP") == "1":
|
|
88
|
+
return 0
|
|
89
|
+
|
|
90
|
+
raw = sys.stdin.read()
|
|
91
|
+
try:
|
|
92
|
+
payload = json.loads(raw)
|
|
93
|
+
except (TypeError, ValueError):
|
|
94
|
+
return 0
|
|
95
|
+
if not isinstance(payload, dict):
|
|
96
|
+
return 0
|
|
97
|
+
|
|
98
|
+
command = ""
|
|
99
|
+
tool_input = payload.get("tool_input") or {}
|
|
100
|
+
if isinstance(tool_input, dict):
|
|
101
|
+
candidate = tool_input.get("command")
|
|
102
|
+
if isinstance(candidate, str):
|
|
103
|
+
command = candidate
|
|
104
|
+
if not command:
|
|
105
|
+
return 0
|
|
106
|
+
|
|
107
|
+
if not adapter_lib.is_test_command(command):
|
|
108
|
+
return 0
|
|
109
|
+
|
|
110
|
+
event_json = raw
|
|
111
|
+
current_result = adapter_lib.detect_result(event_json)
|
|
112
|
+
|
|
113
|
+
prev_state = adapter_lib.read_state()
|
|
114
|
+
prev_result = "none"
|
|
115
|
+
if prev_state:
|
|
116
|
+
try:
|
|
117
|
+
prev_result = json.loads(prev_state).get("result") or "none"
|
|
118
|
+
except (TypeError, ValueError):
|
|
119
|
+
prev_result = "none"
|
|
120
|
+
|
|
121
|
+
adapter_lib.write_state(current_result, event_json)
|
|
122
|
+
|
|
123
|
+
if not adapter_lib.is_red_to_green(prev_result, current_result):
|
|
124
|
+
return 0
|
|
125
|
+
|
|
126
|
+
adapter = adapter_lib.detect_adapter(command)
|
|
127
|
+
if adapter == "none":
|
|
128
|
+
_emit_advisory_pretty(
|
|
129
|
+
"MUTATION GATE ADVISORY: no mutation testing adapter for this "
|
|
130
|
+
"language. Run /setup to install one (supports JS/TS via "
|
|
131
|
+
"Stryker, Java via pitest, C# via Stryker.NET)."
|
|
132
|
+
)
|
|
133
|
+
return 0
|
|
134
|
+
|
|
135
|
+
zero_kills_dir = Path(os.environ.get("TMPDIR", "/tmp")) / "mutation-gate"
|
|
136
|
+
zero_kills_file = zero_kills_dir / "zero-kills.json"
|
|
137
|
+
zero_kills_dir.mkdir(parents=True, exist_ok=True)
|
|
138
|
+
|
|
139
|
+
os.environ["ADAPTER_TIMEOUT"] = os.environ.get("MUTATION_GATE_TIMEOUT", "60")
|
|
140
|
+
os.environ["ADAPTER_COMMAND"] = command
|
|
141
|
+
|
|
142
|
+
runner_stdout = ""
|
|
143
|
+
if prev_state:
|
|
144
|
+
try:
|
|
145
|
+
runner_stdout = json.loads(prev_state).get("runner_stdout") or ""
|
|
146
|
+
except (TypeError, ValueError):
|
|
147
|
+
runner_stdout = ""
|
|
148
|
+
os.environ["ADAPTER_RUNNER_STDOUT"] = runner_stdout
|
|
149
|
+
|
|
150
|
+
if adapter == "stryker":
|
|
151
|
+
if not stryker.stryker_detect():
|
|
152
|
+
return 0
|
|
153
|
+
# bash derives ADAPTER_SOURCE_FILE from the last word of the command.
|
|
154
|
+
last_arg = command.rsplit(" ", 1)[-1] if command else ""
|
|
155
|
+
source_file = stryker.derive_source_file(last_arg) if last_arg else ""
|
|
156
|
+
os.environ["ADAPTER_SOURCE_FILE"] = source_file
|
|
157
|
+
stryker.stryker_run(zero_kills_file)
|
|
158
|
+
elif adapter == "pitest":
|
|
159
|
+
if not pitest.pitest_detect():
|
|
160
|
+
return 0
|
|
161
|
+
pitest.pitest_run(zero_kills_file)
|
|
162
|
+
elif adapter == "stryker-net":
|
|
163
|
+
if not stryker_net.stryker_net_detect():
|
|
164
|
+
return 0
|
|
165
|
+
stryker_net.stryker_net_run(zero_kills_file)
|
|
166
|
+
elif adapter == "mutmut":
|
|
167
|
+
if not mutmut.mutmut_detect():
|
|
168
|
+
return 0
|
|
169
|
+
mutmut.mutmut_run(zero_kills_file)
|
|
170
|
+
|
|
171
|
+
# Emit block if zero-kill tests found.
|
|
172
|
+
if zero_kills_file.is_file():
|
|
173
|
+
try:
|
|
174
|
+
data = json.loads(zero_kills_file.read_text())
|
|
175
|
+
except (OSError, ValueError):
|
|
176
|
+
data = []
|
|
177
|
+
if isinstance(data, list) and data:
|
|
178
|
+
reason = adapter_lib.format_blocking_reason(zero_kills_file, command)
|
|
179
|
+
_emit_block_pretty(reason)
|
|
180
|
+
emit_boundary_event(
|
|
181
|
+
payload.get("cwd") or ".",
|
|
182
|
+
"mutation_gate",
|
|
183
|
+
"Bash",
|
|
184
|
+
"block",
|
|
185
|
+
"mutation-gate-zero-kills",
|
|
186
|
+
payload.get("session_id"),
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
return 0
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
if __name__ == "__main__": # pragma: no cover
|
|
193
|
+
sys.exit(main())
|
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Mutation-testing smoke gate — PreToolUse hook (#565; python port per #574 / #572).
|
|
3
|
+
|
|
4
|
+
Byte-compatible port of the Claude Code PreToolUse hook that enforces the
|
|
5
|
+
SKILL.md § Step 1c smoke gate. Blocks whole-scope Stryker.NET invocations
|
|
6
|
+
until a single-file smoke probe has landed a mutation-report.json under
|
|
7
|
+
StrykerOutput/smoke/reports/ with at least one Killed mutant.
|
|
8
|
+
|
|
9
|
+
Contract (docs/python-hook-contract.md):
|
|
10
|
+
Input : PreToolUse JSON on stdin
|
|
11
|
+
Output: exit 2 + message on stdout to BLOCK
|
|
12
|
+
exit 0 + no stdout for SILENT-PASS
|
|
13
|
+
exit 0 + ADVISORY-prefixed stdout for missing-dep / malformed / drift
|
|
14
|
+
Env : MUTATION_SMOKE_GATE_SKIP=1 → silent bypass + audit-log line
|
|
15
|
+
|
|
16
|
+
Stdlib-only. See docs/python-hook-contract.md.
|
|
17
|
+
|
|
18
|
+
Refs: #565 (the .sh predecessor), #554, #557 (the failure modes it guards).
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
from __future__ import annotations
|
|
22
|
+
|
|
23
|
+
import hashlib
|
|
24
|
+
import json
|
|
25
|
+
import os
|
|
26
|
+
import re
|
|
27
|
+
import shlex
|
|
28
|
+
import shutil
|
|
29
|
+
import sys
|
|
30
|
+
from datetime import datetime, timezone
|
|
31
|
+
from pathlib import Path
|
|
32
|
+
|
|
33
|
+
_HOOK_DIR = Path(__file__).resolve().parent
|
|
34
|
+
_LIB_DIR = _HOOK_DIR / "lib"
|
|
35
|
+
|
|
36
|
+
sys.path.insert(0, str(_LIB_DIR))
|
|
37
|
+
import artifact_paths # type: ignore[import-not-found]
|
|
38
|
+
|
|
39
|
+
try:
|
|
40
|
+
from atomic_state import ( # type: ignore[import-not-found]
|
|
41
|
+
append_line_locked,
|
|
42
|
+
)
|
|
43
|
+
from boundary_events import ( # type: ignore[import-not-found]
|
|
44
|
+
emit_boundary_event as _emit_boundary_event,
|
|
45
|
+
)
|
|
46
|
+
from stdin_json import read_stdin_json # type: ignore[import-not-found]
|
|
47
|
+
except ImportError: # pragma: no cover
|
|
48
|
+
|
|
49
|
+
def read_stdin_json() -> dict | None: # type: ignore[misc]
|
|
50
|
+
return None
|
|
51
|
+
|
|
52
|
+
def _emit_boundary_event(*_args, **_kwargs) -> None: # type: ignore[misc]
|
|
53
|
+
return None
|
|
54
|
+
|
|
55
|
+
def append_line_locked( # type: ignore[misc]
|
|
56
|
+
path: Path, line: str, *, delay_env_var=None, fail_open: bool = True
|
|
57
|
+
) -> None:
|
|
58
|
+
# Degraded-import fallback: atomic_state itself couldn't be
|
|
59
|
+
# imported, so no hardened (locked, O_NOFOLLOW) append is available.
|
|
60
|
+
# #1904 item 5: this used to fall back to a plain unlocked
|
|
61
|
+
# `open(path, "a")` — the exact O_NOFOLLOW-hardening gap that
|
|
62
|
+
# issue disclosed for this and `pre_commit_review.py`'s equivalent
|
|
63
|
+
# shim. A failed audit write is already fail-open by design (the
|
|
64
|
+
# bypass this line records proceeds either way), so degrading
|
|
65
|
+
# further to "don't write at all" costs nothing beyond the audit
|
|
66
|
+
# trail entry itself, and avoids reintroducing the symlink-redirect
|
|
67
|
+
# gap the shared helper exists to close.
|
|
68
|
+
if not fail_open:
|
|
69
|
+
raise OSError("atomic_state unavailable (degraded import)")
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def emit_boundary_event(*args, **kwargs) -> None:
|
|
73
|
+
"""Local safety net (#859): even a misbehaving helper must never affect
|
|
74
|
+
this hook's exit code, stdout, or stderr."""
|
|
75
|
+
try:
|
|
76
|
+
_emit_boundary_event(*args, **kwargs)
|
|
77
|
+
except Exception: # noqa: BLE001, S110 - fail-open by design
|
|
78
|
+
pass
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
# ---------------------------------------------------------------------------
|
|
82
|
+
# Trigger detection
|
|
83
|
+
# ---------------------------------------------------------------------------
|
|
84
|
+
|
|
85
|
+
try:
|
|
86
|
+
from stryker_invocation import ( # type: ignore[import-not-found]
|
|
87
|
+
is_stryker_invocation as _is_stryker_invocation,
|
|
88
|
+
)
|
|
89
|
+
except ImportError: # pragma: no cover - degraded fallback, hooks/lib unreachable
|
|
90
|
+
_STRYKER_TRIGGER_FALLBACK = re.compile(
|
|
91
|
+
r"(?:^|[^a-zA-Z0-9])dotnet[ \t]+stryker(?:\b|$)|csharp-stryker-net-wrapper\.sh"
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
def _is_stryker_invocation(cmd: str) -> bool: # type: ignore[misc]
|
|
95
|
+
return bool(cmd) and bool(_STRYKER_TRIGGER_FALLBACK.search(cmd))
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def is_stryker_command(cmd: str) -> bool:
|
|
99
|
+
"""True when `cmd` invokes dotnet stryker OR the wrapper script.
|
|
100
|
+
|
|
101
|
+
Delegates to the shared `hooks/lib/stryker_invocation` predicate (#2185):
|
|
102
|
+
parsed via `shlex` in program position, not scanned with a bare regex —
|
|
103
|
+
so a mention of the tool name in a --body/grep/echo/comment argument is
|
|
104
|
+
never mistaken for a real invocation.
|
|
105
|
+
"""
|
|
106
|
+
if not cmd:
|
|
107
|
+
return False
|
|
108
|
+
return _is_stryker_invocation(cmd)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def extract_mutate_value(cmd: str) -> str:
|
|
112
|
+
"""Return the --mutate value (handles --mutate=X, --mutate X, -m X).
|
|
113
|
+
|
|
114
|
+
Respects shell quoting via shlex so `--mutate 'src/Foo.cs'` and
|
|
115
|
+
`--mutate "src/Foo.cs"` both yield the unquoted path. Malformed shell
|
|
116
|
+
input yields "" (silent, matching the .sh's behavior).
|
|
117
|
+
"""
|
|
118
|
+
try:
|
|
119
|
+
tokens = shlex.split(cmd)
|
|
120
|
+
except ValueError:
|
|
121
|
+
return ""
|
|
122
|
+
for i, tok in enumerate(tokens):
|
|
123
|
+
if tok.startswith("--mutate="):
|
|
124
|
+
return tok.split("=", 1)[1]
|
|
125
|
+
if tok in ("--mutate", "-m"):
|
|
126
|
+
if i + 1 < len(tokens):
|
|
127
|
+
return tokens[i + 1]
|
|
128
|
+
return ""
|
|
129
|
+
return ""
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def is_single_file_mutate(value: str) -> bool:
|
|
133
|
+
"""A --mutate value is single-file only when it has no glob metacharacters
|
|
134
|
+
(*, ?, [) AND no semicolon (Stryker.NET's multi-file separator)."""
|
|
135
|
+
if not value:
|
|
136
|
+
return False
|
|
137
|
+
return not any(c in value for c in ("*", "?", "[", ";"))
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
# ---------------------------------------------------------------------------
|
|
141
|
+
# Audit-log helpers
|
|
142
|
+
# ---------------------------------------------------------------------------
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def sha256_first_16(text: str) -> str:
|
|
146
|
+
"""First 16 hex chars of sha256(text). Matches the .sh's cross-platform
|
|
147
|
+
shasum/sha256sum fallback chain output."""
|
|
148
|
+
return hashlib.sha256(text.encode("utf-8")).hexdigest()[:16]
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def iso_utc_timestamp() -> str:
|
|
152
|
+
"""ISO-8601 UTC timestamp with 'Z' suffix. Matches the .sh helper."""
|
|
153
|
+
return datetime.now(timezone.utc).isoformat().replace("+00:00", "Z")
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def log_bypass_audit(raw_command: str, payload_cwd: str) -> None:
|
|
157
|
+
"""Append one JSONL line to <payload_cwd>/.claude/metrics/gate-bypass.jsonl.
|
|
158
|
+
|
|
159
|
+
Writes timestamp + hook name + command_hash (sha256 first 16) + cwd.
|
|
160
|
+
The raw command is NEVER written — only its hash — matching the .sh's
|
|
161
|
+
privacy boundary. Filesystem errors write to stderr and return
|
|
162
|
+
silently so the bypass still succeeds.
|
|
163
|
+
"""
|
|
164
|
+
audit_file = artifact_paths.resolve_file(
|
|
165
|
+
"metrics", "gate-bypass.jsonl", payload_cwd
|
|
166
|
+
)
|
|
167
|
+
audit_dir = audit_file.parent
|
|
168
|
+
try:
|
|
169
|
+
audit_dir.mkdir(parents=True, exist_ok=True)
|
|
170
|
+
except OSError:
|
|
171
|
+
print(
|
|
172
|
+
f"mutation-testing-smoke-gate: cannot create {audit_dir} "
|
|
173
|
+
"(bypass still succeeds)",
|
|
174
|
+
file=sys.stderr,
|
|
175
|
+
)
|
|
176
|
+
return
|
|
177
|
+
record = {
|
|
178
|
+
"timestamp": iso_utc_timestamp(),
|
|
179
|
+
"hook": "mutation-testing-smoke-gate",
|
|
180
|
+
"command_hash": sha256_first_16(raw_command),
|
|
181
|
+
"cwd": payload_cwd,
|
|
182
|
+
}
|
|
183
|
+
try:
|
|
184
|
+
# Match jq -c compact output: no spaces after ',' or ':'.
|
|
185
|
+
append_line_locked(
|
|
186
|
+
audit_file, json.dumps(record, separators=(",", ":")) + "\n", fail_open=False
|
|
187
|
+
)
|
|
188
|
+
except OSError:
|
|
189
|
+
print(
|
|
190
|
+
f"mutation-testing-smoke-gate: cannot write to {audit_file} "
|
|
191
|
+
"(bypass still succeeds)",
|
|
192
|
+
file=sys.stderr,
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
# ---------------------------------------------------------------------------
|
|
197
|
+
# Block message
|
|
198
|
+
# ---------------------------------------------------------------------------
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
_BLOCK_TEMPLATE = """[BLOCK] mutation-testing-smoke-gate: whole-scope Stryker.NET run detected
|
|
202
|
+
|
|
203
|
+
{diagnostic}
|
|
204
|
+
|
|
205
|
+
The Step 1c smoke gate (see SKILL.md § Step 1c) requires a single-file
|
|
206
|
+
mutation probe with Killed > 0 before authorizing a full run. This
|
|
207
|
+
prevents the silent 0.00 % failure mode (see #554, #557).
|
|
208
|
+
|
|
209
|
+
To run the smoke probe:
|
|
210
|
+
|
|
211
|
+
dotnet stryker --config-file stryker-config.json \\
|
|
212
|
+
--mutate 'path/to/one/covered/file.cs' \\
|
|
213
|
+
-O StrykerOutput/smoke
|
|
214
|
+
|
|
215
|
+
Then re-run this command. To bypass this gate for a legitimate exception,
|
|
216
|
+
set MUTATION_SMOKE_GATE_SKIP=1 in the environment (audit-logged)."""
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
def print_block_message(diagnostic: str) -> None:
|
|
220
|
+
"""Write the shared block-message body with the caller's diagnostic."""
|
|
221
|
+
print(_BLOCK_TEMPLATE.format(diagnostic=diagnostic))
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
# ---------------------------------------------------------------------------
|
|
225
|
+
# Report parsing
|
|
226
|
+
# ---------------------------------------------------------------------------
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def count_mutants_by_status(report: dict, status: str) -> int:
|
|
230
|
+
"""Count entries in report['mutants'] with the given status field."""
|
|
231
|
+
mutants = report.get("mutants") or []
|
|
232
|
+
return sum(1 for m in mutants if isinstance(m, dict) and m.get("status") == status)
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
# ---------------------------------------------------------------------------
|
|
236
|
+
# main()
|
|
237
|
+
# ---------------------------------------------------------------------------
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
def main() -> int:
|
|
241
|
+
# -------------------------------------------------------------------
|
|
242
|
+
# Dependency guards — a missing dep must NOT become a de facto gate.
|
|
243
|
+
# -------------------------------------------------------------------
|
|
244
|
+
if shutil.which("jq") is None:
|
|
245
|
+
# Preserve parity with the .sh, which uses jq for JSON parsing.
|
|
246
|
+
# The Python port does not itself use jq, but flags the missing
|
|
247
|
+
# dep to keep the failure mode identical across ports.
|
|
248
|
+
print(
|
|
249
|
+
"ADVISORY: mutation-testing-smoke-gate: jq is required but not installed; gate not enforced"
|
|
250
|
+
)
|
|
251
|
+
return 0
|
|
252
|
+
# python3 is always present by construction in a .py hook; the .sh's
|
|
253
|
+
# python3 dep check is a no-op here.
|
|
254
|
+
|
|
255
|
+
# -------------------------------------------------------------------
|
|
256
|
+
# Parse PreToolUse payload
|
|
257
|
+
# -------------------------------------------------------------------
|
|
258
|
+
payload = read_stdin_json()
|
|
259
|
+
if payload is None:
|
|
260
|
+
# Empty or malformed stdin — nothing to check, silent-pass.
|
|
261
|
+
return 0
|
|
262
|
+
|
|
263
|
+
command = str(payload.get("tool_input", {}).get("command", "") or "")
|
|
264
|
+
if not command:
|
|
265
|
+
return 0
|
|
266
|
+
|
|
267
|
+
# cwd from payload, fall back to $PWD (matches .sh's `${PAYLOAD_CWD:=$PWD}`).
|
|
268
|
+
# Prefer the shell-provided $PWD over os.getcwd() so macOS's /var → /private/var
|
|
269
|
+
# symlink resolution does not diverge from the .sh.
|
|
270
|
+
payload_cwd = str(payload.get("cwd") or os.environ.get("PWD") or os.getcwd())
|
|
271
|
+
|
|
272
|
+
# -------------------------------------------------------------------
|
|
273
|
+
# Trigger detection
|
|
274
|
+
# -------------------------------------------------------------------
|
|
275
|
+
if not is_stryker_command(command):
|
|
276
|
+
return 0
|
|
277
|
+
|
|
278
|
+
mutate_value = extract_mutate_value(command)
|
|
279
|
+
if is_single_file_mutate(mutate_value):
|
|
280
|
+
# This IS the smoke probe; do not block it.
|
|
281
|
+
return 0
|
|
282
|
+
|
|
283
|
+
# -------------------------------------------------------------------
|
|
284
|
+
# Escape hatch — must run BEFORE report check so bypass works even
|
|
285
|
+
# without a report. Matches .sh ordering.
|
|
286
|
+
# -------------------------------------------------------------------
|
|
287
|
+
if os.environ.get("MUTATION_SMOKE_GATE_SKIP", "0") == "1":
|
|
288
|
+
log_bypass_audit(command, payload_cwd)
|
|
289
|
+
return 0
|
|
290
|
+
|
|
291
|
+
# -------------------------------------------------------------------
|
|
292
|
+
# Whole-scope run detected — check the smoke report.
|
|
293
|
+
# -------------------------------------------------------------------
|
|
294
|
+
report_path = (
|
|
295
|
+
Path(payload_cwd)
|
|
296
|
+
/ "StrykerOutput"
|
|
297
|
+
/ "smoke"
|
|
298
|
+
/ "reports"
|
|
299
|
+
/ "mutation-report.json"
|
|
300
|
+
)
|
|
301
|
+
|
|
302
|
+
session_id = payload.get("session_id")
|
|
303
|
+
|
|
304
|
+
if not report_path.is_file():
|
|
305
|
+
print_block_message(f"no smoke report at {report_path}")
|
|
306
|
+
emit_boundary_event(
|
|
307
|
+
payload_cwd, "mutation_testing_smoke_gate", "Bash", "block",
|
|
308
|
+
"mutation-smoke-report-missing", session_id,
|
|
309
|
+
)
|
|
310
|
+
return 2
|
|
311
|
+
|
|
312
|
+
try:
|
|
313
|
+
report_text = report_path.read_text(encoding="utf-8")
|
|
314
|
+
except OSError:
|
|
315
|
+
print_block_message(f"no smoke report at {report_path}")
|
|
316
|
+
emit_boundary_event(
|
|
317
|
+
payload_cwd, "mutation_testing_smoke_gate", "Bash", "block",
|
|
318
|
+
"mutation-smoke-report-missing", session_id,
|
|
319
|
+
)
|
|
320
|
+
return 2
|
|
321
|
+
|
|
322
|
+
try:
|
|
323
|
+
report = json.loads(report_text)
|
|
324
|
+
except json.JSONDecodeError:
|
|
325
|
+
# Malformed JSON — advisory (not block, not silent-pass). Matches .sh.
|
|
326
|
+
print(
|
|
327
|
+
f"ADVISORY: mutation-testing-smoke-gate: report at {report_path} is not valid JSON — cannot enforce gate; command not blocked"
|
|
328
|
+
)
|
|
329
|
+
return 0
|
|
330
|
+
|
|
331
|
+
# Schema drift — valid JSON without mutants[]. Advisory. ORDERING NOTE
|
|
332
|
+
# (from .sh): schema-drift advisory MUST run before counting logic;
|
|
333
|
+
# otherwise a schema-drift report incorrectly reports "no scored mutants".
|
|
334
|
+
if not isinstance(report, dict) or "mutants" not in report:
|
|
335
|
+
print(
|
|
336
|
+
f"ADVISORY: mutation-testing-smoke-gate: report at {report_path} lacks the mutants[] key — not the mutation-testing-elements shape; cannot enforce gate"
|
|
337
|
+
)
|
|
338
|
+
return 0
|
|
339
|
+
|
|
340
|
+
killed = count_mutants_by_status(report, "Killed")
|
|
341
|
+
survived = count_mutants_by_status(report, "Survived")
|
|
342
|
+
|
|
343
|
+
# At least one Killed → gate passes silently.
|
|
344
|
+
if killed > 0:
|
|
345
|
+
return 0
|
|
346
|
+
|
|
347
|
+
# Killed==0 && Survived>0 → mutation-switch not observing mutations.
|
|
348
|
+
if survived > 0:
|
|
349
|
+
print_block_message(
|
|
350
|
+
f"killed=0 survived={survived} — mutation-switch not observing mutations at runtime "
|
|
351
|
+
"(see #554, #557 and SKILL.md Step 1c diagnostic checklist)"
|
|
352
|
+
)
|
|
353
|
+
emit_boundary_event(
|
|
354
|
+
payload_cwd, "mutation_testing_smoke_gate", "Bash", "block",
|
|
355
|
+
"mutation-smoke-switch-not-observed", session_id,
|
|
356
|
+
)
|
|
357
|
+
return 2
|
|
358
|
+
|
|
359
|
+
# Killed==0 && Survived==0 → empty mutants[] or only NoCoverage/CompileError.
|
|
360
|
+
print_block_message(
|
|
361
|
+
"no scored mutants in smoke report — pick a different probe file with real test coverage"
|
|
362
|
+
)
|
|
363
|
+
emit_boundary_event(
|
|
364
|
+
payload_cwd, "mutation_testing_smoke_gate", "Bash", "block",
|
|
365
|
+
"mutation-smoke-no-scored-mutants", session_id,
|
|
366
|
+
)
|
|
367
|
+
return 2
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
if __name__ == "__main__":
|
|
371
|
+
sys.exit(main())
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""SessionStart hook: notify when the pending-review queue has entries.
|
|
3
|
+
|
|
4
|
+
Emits a one-line notification when .claude/metrics/pending-review.jsonl has
|
|
5
|
+
unreviewed entries. Split off (#1284/#1288) from the retired
|
|
6
|
+
session_model_banner.py, whose other two responsibilities (persisting the
|
|
7
|
+
session model to `.claude/session-model` and announcing the effort-band
|
|
8
|
+
routing table) belonged to the band-to-model resolver system ADR 0026
|
|
9
|
+
retired — the harness now resolves `model:`/`effort:` natively, with no
|
|
10
|
+
plugin-side banner to keep in sync.
|
|
11
|
+
|
|
12
|
+
Env seams (TEST-ONLY):
|
|
13
|
+
PENDING_REVIEW_FILE defaults to <cwd>/.claude/metrics/pending-review.jsonl
|
|
14
|
+
|
|
15
|
+
Contract (docs/python-hook-contract.md):
|
|
16
|
+
Input : SessionStart JSON on stdin (hook_event_name, cwd, model, ...).
|
|
17
|
+
Output: notification text on stdout. Exit 0 always.
|
|
18
|
+
Posture: fail-open — a buggy notifier must never block a session.
|
|
19
|
+
|
|
20
|
+
Stdlib-only (json/os/pathlib/sys).
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
from __future__ import annotations
|
|
24
|
+
|
|
25
|
+
import json
|
|
26
|
+
import os
|
|
27
|
+
import sys
|
|
28
|
+
from pathlib import Path
|
|
29
|
+
|
|
30
|
+
_HOOK_DIR = Path(__file__).resolve().parent
|
|
31
|
+
_LIB_DIR = _HOOK_DIR / "lib"
|
|
32
|
+
if str(_LIB_DIR) not in sys.path:
|
|
33
|
+
sys.path.insert(0, str(_LIB_DIR))
|
|
34
|
+
|
|
35
|
+
import artifact_paths
|
|
36
|
+
from stdin_json import read_stdin_json, resolve_cwd # type: ignore[import-not-found]
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _notify_pending_findings(cwd: str) -> str | None:
|
|
40
|
+
"""Count still-pending entries in the pending-review queue, rotating out
|
|
41
|
+
disposed ones so the file stays bounded (#732).
|
|
42
|
+
|
|
43
|
+
A finding gains exactly one disposition (`reviewed_at` on approval,
|
|
44
|
+
`rejected_at` on rejection — see feedback-learning/SKILL.md); once either
|
|
45
|
+
is present, its audit trail lives in .claude/metrics/config-changelog.jsonl
|
|
46
|
+
(on approval) and the entry itself has no further use here. Rewriting the
|
|
47
|
+
queue to drop disposed entries every SessionStart keeps it bounded to the
|
|
48
|
+
outstanding backlog instead of growing without limit across the life of
|
|
49
|
+
a project. Lines that fail to parse can't be classified either way, so
|
|
50
|
+
they are left untouched — /session-review handles malformed-line
|
|
51
|
+
reporting on its own.
|
|
52
|
+
"""
|
|
53
|
+
queue_env = os.environ.get("PENDING_REVIEW_FILE")
|
|
54
|
+
queue = (
|
|
55
|
+
Path(queue_env)
|
|
56
|
+
if queue_env
|
|
57
|
+
else artifact_paths.resolve_file("metrics", "pending-review.jsonl", cwd)
|
|
58
|
+
)
|
|
59
|
+
if not queue.is_file():
|
|
60
|
+
return None
|
|
61
|
+
try:
|
|
62
|
+
with queue.open("r", encoding="utf-8", errors="replace") as fh:
|
|
63
|
+
lines = fh.readlines()
|
|
64
|
+
except OSError:
|
|
65
|
+
return None
|
|
66
|
+
|
|
67
|
+
kept_lines: list[str] = []
|
|
68
|
+
dropped_any = False
|
|
69
|
+
count = 0
|
|
70
|
+
for raw_line in lines:
|
|
71
|
+
line = raw_line.strip()
|
|
72
|
+
if not line:
|
|
73
|
+
dropped_any = True
|
|
74
|
+
continue
|
|
75
|
+
try:
|
|
76
|
+
entry = json.loads(line)
|
|
77
|
+
except (json.JSONDecodeError, ValueError):
|
|
78
|
+
# Can't classify — keep it as-is rather than silently losing it.
|
|
79
|
+
kept_lines.append(line)
|
|
80
|
+
continue
|
|
81
|
+
if isinstance(entry, dict) and (
|
|
82
|
+
"reviewed_at" in entry or "rejected_at" in entry
|
|
83
|
+
):
|
|
84
|
+
# Disposed — rotate it out of the queue.
|
|
85
|
+
dropped_any = True
|
|
86
|
+
continue
|
|
87
|
+
if isinstance(entry, dict):
|
|
88
|
+
count += 1
|
|
89
|
+
kept_lines.append(line)
|
|
90
|
+
|
|
91
|
+
if dropped_any:
|
|
92
|
+
try:
|
|
93
|
+
queue.write_text(
|
|
94
|
+
"".join(f"{line}\n" for line in kept_lines), encoding="utf-8"
|
|
95
|
+
)
|
|
96
|
+
except OSError:
|
|
97
|
+
pass
|
|
98
|
+
|
|
99
|
+
if count <= 0:
|
|
100
|
+
return None
|
|
101
|
+
return (
|
|
102
|
+
f"📋 {count} queued finding(s) from background analysis — "
|
|
103
|
+
"run /session-review to review\n"
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def main() -> int:
|
|
108
|
+
payload = read_stdin_json()
|
|
109
|
+
if payload is None:
|
|
110
|
+
return 0
|
|
111
|
+
cwd = resolve_cwd(payload)
|
|
112
|
+
|
|
113
|
+
notice = _notify_pending_findings(cwd)
|
|
114
|
+
if notice is not None:
|
|
115
|
+
sys.stdout.write(notice)
|
|
116
|
+
|
|
117
|
+
return 0
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
if __name__ == "__main__": # pragma: no cover
|
|
121
|
+
sys.exit(main())
|