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,405 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""pre_tool_guard.py — Claude Code PreToolUse hook (Python port of pre-tool-guard.sh).
|
|
3
|
+
|
|
4
|
+
Runs before Write and Edit tool calls. Blocks writes to sensitive paths
|
|
5
|
+
(credentials, secrets, keys). Warns on writes to protected config files.
|
|
6
|
+
Enforces freeze-mode's scope lock when a freeze-state file is active.
|
|
7
|
+
|
|
8
|
+
Input : JSON on stdin with `tool_input.file_path` or `tool_input.path`.
|
|
9
|
+
Output: message on stdout; exit 2 to block, exit 0 to allow.
|
|
10
|
+
Config: `hooks/guards.json` (same directory as the hook itself — shared
|
|
11
|
+
across sessions deliberately; sensitive-path patterns are global, not
|
|
12
|
+
per-repo).
|
|
13
|
+
|
|
14
|
+
Freeze state (issue #1890) is resolved per invoking repo, NOT relative to
|
|
15
|
+
this hook's own `script_dir`. In a real installed session `script_dir` is
|
|
16
|
+
the shared plugin cache (`~/.claude/plugins/cache/bfinster/dev-team/<ver>/
|
|
17
|
+
hooks/`) — one location shared by every concurrently-running session,
|
|
18
|
+
worktree, and project on the machine. Resolving freeze state there let one
|
|
19
|
+
session's `/freeze` scope-lock every other, unrelated session's Write/Edit
|
|
20
|
+
calls. `main()` instead resolves it via `hooks/lib/artifact_paths.py`'s
|
|
21
|
+
`resolve_file()`, keyed off the tool call's own `cwd` — landing at
|
|
22
|
+
`<repo-root>/.claude/hooks/freeze-state.json`, the same per-repo `.claude/`
|
|
23
|
+
convention `.review-passed` and other runtime state already use.
|
|
24
|
+
|
|
25
|
+
Two follow-up fixes (issue #1904 items 7, 11, 14):
|
|
26
|
+
|
|
27
|
+
- (#1904 item 11) `main()` no longer calls the `git rev-parse`-based
|
|
28
|
+
`project_root()` unconditionally on every Write/Edit. `_cheap_freeze_inactive()`
|
|
29
|
+
proves freeze is inactive with a plain filesystem stat when `cwd` is
|
|
30
|
+
unambiguously the repo root itself (a `.git` entry exists directly under
|
|
31
|
+
it); only when that check is inconclusive does `main()` fall through to
|
|
32
|
+
the git-based resolution — mirroring the cheap-stat fast path #1861 added
|
|
33
|
+
for the higher-frequency PostToolUse `*` matcher.
|
|
34
|
+
- (#1904 items 7, 14) `evaluate()`'s freeze-mode allowlist match now
|
|
35
|
+
relativizes `tool_input.file_path` against the freeze-scoped repo root
|
|
36
|
+
before matching — a real session reports an ABSOLUTE `file_path`, which
|
|
37
|
+
can never match a repo-relative glob like `.claude/plans/*.md` (item 14).
|
|
38
|
+
Doing so safely requires knowing whether `file_path` even resolves inside
|
|
39
|
+
the SAME repo `cwd` resolved to: `evaluate()` treats a `file_path` that
|
|
40
|
+
resolves to a different repo root entirely as outside freeze's scope —
|
|
41
|
+
neither blocked nor exempted by that repo's allowlist — rather than
|
|
42
|
+
matching a relativized path fragment against an unrelated repo (item 7).
|
|
43
|
+
|
|
44
|
+
A third follow-up (post-#1904 review): a candidate whose resolved form
|
|
45
|
+
lands outside `repo_root` even though its UNRESOLVED, cwd-joined form was
|
|
46
|
+
inside it is a symlink escape (e.g. a `tests/` directory symlinked
|
|
47
|
+
elsewhere) — `_freeze_verdict()` blocks that case rather than falling
|
|
48
|
+
through to the ordinary sensitive-path/warn checks, since a scope lock
|
|
49
|
+
crossing a symlink must never be silently permitted.
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
from __future__ import annotations
|
|
53
|
+
|
|
54
|
+
import fnmatch
|
|
55
|
+
import json
|
|
56
|
+
import os
|
|
57
|
+
import sys
|
|
58
|
+
from pathlib import Path
|
|
59
|
+
from typing import NamedTuple
|
|
60
|
+
|
|
61
|
+
_LIB_DIR = Path(__file__).resolve().parent / "lib"
|
|
62
|
+
if str(_LIB_DIR) not in sys.path:
|
|
63
|
+
sys.path.insert(0, str(_LIB_DIR))
|
|
64
|
+
|
|
65
|
+
import artifact_paths
|
|
66
|
+
from boundary_events import emit_boundary_event as _emit_boundary_event
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def emit_boundary_event(*args, **kwargs) -> None:
|
|
70
|
+
"""Local safety net (#859): even a misbehaving helper must never affect
|
|
71
|
+
this hook's exit code, stdout, or stderr."""
|
|
72
|
+
try:
|
|
73
|
+
_emit_boundary_event(*args, **kwargs)
|
|
74
|
+
except Exception: # noqa: BLE001, S110 - fail-open by design
|
|
75
|
+
pass
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
_DEFAULT_BLOCKED = [
|
|
79
|
+
".env",
|
|
80
|
+
".env.*",
|
|
81
|
+
"*.pem",
|
|
82
|
+
"*.key",
|
|
83
|
+
"*.p12",
|
|
84
|
+
"*.pfx",
|
|
85
|
+
"*credential*",
|
|
86
|
+
"*secret*",
|
|
87
|
+
"*.token",
|
|
88
|
+
]
|
|
89
|
+
_DEFAULT_WARN = [
|
|
90
|
+
".claude/settings.json",
|
|
91
|
+
".claude/claude.md",
|
|
92
|
+
]
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
# ---------------------------------------------------------------------------
|
|
96
|
+
# stdin → file path
|
|
97
|
+
# ---------------------------------------------------------------------------
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def _extract_file_path(raw: str) -> str:
|
|
101
|
+
"""Return `tool_input.file_path`, `tool_input.path`, or empty string.
|
|
102
|
+
|
|
103
|
+
Mirrors the bash `jq -r '.tool_input.file_path // .tool_input.path // empty'`.
|
|
104
|
+
"""
|
|
105
|
+
try:
|
|
106
|
+
payload = json.loads(raw)
|
|
107
|
+
except (TypeError, ValueError):
|
|
108
|
+
return ""
|
|
109
|
+
if not isinstance(payload, dict):
|
|
110
|
+
return ""
|
|
111
|
+
tool_input = payload.get("tool_input")
|
|
112
|
+
if not isinstance(tool_input, dict):
|
|
113
|
+
return ""
|
|
114
|
+
file_path = tool_input.get("file_path")
|
|
115
|
+
if isinstance(file_path, str) and file_path:
|
|
116
|
+
return file_path
|
|
117
|
+
other = tool_input.get("path")
|
|
118
|
+
if isinstance(other, str) and other:
|
|
119
|
+
return other
|
|
120
|
+
return ""
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
# ---------------------------------------------------------------------------
|
|
124
|
+
# Glob matching — the bash uses `case ... esac`, we use fnmatch.fnmatchcase
|
|
125
|
+
# with matching semantics (no case folding — we lowercase subjects ourselves).
|
|
126
|
+
# ---------------------------------------------------------------------------
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def _matches_any(subject: str, patterns: list[str]) -> bool:
|
|
130
|
+
return any(
|
|
131
|
+
pattern and fnmatch.fnmatchcase(subject, pattern) for pattern in patterns
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def _relative_to_repo_root(
|
|
136
|
+
file_path: str, cwd: str, repo_root: Path | None
|
|
137
|
+
) -> tuple[str | None, bool]:
|
|
138
|
+
"""Resolve `file_path` relative to `repo_root`, and whether it lies
|
|
139
|
+
within `repo_root` at all (#1904 items 7 and 14).
|
|
140
|
+
|
|
141
|
+
A relative `file_path` is joined against `cwd` first — a tool reports
|
|
142
|
+
`file_path` relative to its own invocation `cwd`, never to some other
|
|
143
|
+
root. Returns `(None, False)` when `repo_root` is unknown (the caller
|
|
144
|
+
didn't resolve one, e.g. freeze is provably inactive), when `file_path`
|
|
145
|
+
cannot be resolved, or when it resolves OUTSIDE `repo_root` entirely —
|
|
146
|
+
freeze's `allowed_patterns` are defined relative to that one repo, so
|
|
147
|
+
they never govern a write that lands in a different repo (item 7),
|
|
148
|
+
even one with the identical relative shape.
|
|
149
|
+
"""
|
|
150
|
+
if repo_root is None:
|
|
151
|
+
return None, False
|
|
152
|
+
base = Path(cwd) if cwd else Path.cwd()
|
|
153
|
+
candidate = Path(file_path)
|
|
154
|
+
if not candidate.is_absolute():
|
|
155
|
+
candidate = base / candidate
|
|
156
|
+
try:
|
|
157
|
+
resolved = candidate.resolve()
|
|
158
|
+
resolved_root = repo_root.resolve()
|
|
159
|
+
except (OSError, RuntimeError):
|
|
160
|
+
return None, False
|
|
161
|
+
if not resolved.is_relative_to(resolved_root):
|
|
162
|
+
return None, False
|
|
163
|
+
return str(resolved.relative_to(resolved_root)), True
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def _unresolved_within_repo_root(file_path: str, cwd: str, repo_root: Path) -> bool:
|
|
167
|
+
"""True when `file_path`'s cwd-joined form is LEXICALLY inside
|
|
168
|
+
`repo_root` — normalized via `os.path.abspath` (`..`/`.` collapsing
|
|
169
|
+
only, no filesystem access, no symlink following).
|
|
170
|
+
|
|
171
|
+
Used to detect a symlink escape: `file_path` is nominally in scope AS
|
|
172
|
+
WRITTEN, but `_relative_to_repo_root`'s symlink-following `.resolve()`
|
|
173
|
+
lands it outside `repo_root`. Without this check, `evaluate()` would
|
|
174
|
+
fall through to the ordinary sensitive-path/warn checks and silently
|
|
175
|
+
allow a write that crosses a symlink out of a frozen repo.
|
|
176
|
+
"""
|
|
177
|
+
base = Path(cwd) if cwd else Path.cwd()
|
|
178
|
+
candidate = Path(file_path)
|
|
179
|
+
if not candidate.is_absolute():
|
|
180
|
+
candidate = base / candidate
|
|
181
|
+
lexical = os.path.abspath(str(candidate))
|
|
182
|
+
root_lexical = os.path.abspath(str(repo_root))
|
|
183
|
+
return lexical == root_lexical or lexical.startswith(root_lexical + os.sep)
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
# ---------------------------------------------------------------------------
|
|
187
|
+
# Config loading — guards.json + freeze-state.json
|
|
188
|
+
# ---------------------------------------------------------------------------
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def _load_guards(guards_path: Path) -> tuple:
|
|
192
|
+
"""Return (blocked_patterns, warn_patterns) from guards.json or defaults."""
|
|
193
|
+
if not guards_path.is_file():
|
|
194
|
+
return list(_DEFAULT_BLOCKED), list(_DEFAULT_WARN)
|
|
195
|
+
try:
|
|
196
|
+
data = json.loads(guards_path.read_text())
|
|
197
|
+
except (OSError, ValueError):
|
|
198
|
+
return list(_DEFAULT_BLOCKED), list(_DEFAULT_WARN)
|
|
199
|
+
if not isinstance(data, dict):
|
|
200
|
+
return list(_DEFAULT_BLOCKED), list(_DEFAULT_WARN)
|
|
201
|
+
raw_blocked = data.get("blocked_paths")
|
|
202
|
+
raw_warn = data.get("warn_paths")
|
|
203
|
+
blocked = [p for p in (raw_blocked if isinstance(raw_blocked, list) else []) if isinstance(p, str) and p]
|
|
204
|
+
warn = [p for p in (raw_warn if isinstance(raw_warn, list) else []) if isinstance(p, str) and p]
|
|
205
|
+
if not blocked:
|
|
206
|
+
blocked = list(_DEFAULT_BLOCKED)
|
|
207
|
+
if not warn:
|
|
208
|
+
warn = list(_DEFAULT_WARN)
|
|
209
|
+
return blocked, warn
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
def _load_freeze(freeze_path: Path) -> list[str] | None:
|
|
213
|
+
"""Return the freeze `allowed_patterns` when freeze is active, else None."""
|
|
214
|
+
if not freeze_path.is_file():
|
|
215
|
+
return None
|
|
216
|
+
try:
|
|
217
|
+
data = json.loads(freeze_path.read_text())
|
|
218
|
+
except (OSError, ValueError):
|
|
219
|
+
return None
|
|
220
|
+
if not isinstance(data, dict):
|
|
221
|
+
return None
|
|
222
|
+
if data.get("active") is not True and data.get("active") != "true":
|
|
223
|
+
return None
|
|
224
|
+
raw_allowed = data.get("allowed_patterns")
|
|
225
|
+
allowed = [
|
|
226
|
+
p for p in (raw_allowed if isinstance(raw_allowed, list) else []) if isinstance(p, str) and p
|
|
227
|
+
]
|
|
228
|
+
return allowed
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
# ---------------------------------------------------------------------------
|
|
232
|
+
# Guard evaluation
|
|
233
|
+
# ---------------------------------------------------------------------------
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
class GuardPaths(NamedTuple):
|
|
237
|
+
"""The "where do we look" state `main()` resolves once per invocation
|
|
238
|
+
— bundled so `evaluate()` takes one param instead of three."""
|
|
239
|
+
|
|
240
|
+
guards_path: Path
|
|
241
|
+
freeze_path: Path
|
|
242
|
+
repo_root: Path | None = None
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
def _freeze_block(file_path: str, allowed: list[str], cwd: str, session_id: str | None) -> tuple:
|
|
246
|
+
allowed_display = "\n".join(allowed)
|
|
247
|
+
emit_boundary_event(cwd, "pre_tool_guard", "Write", "block", "freeze-scope-lock", session_id)
|
|
248
|
+
return 2, [
|
|
249
|
+
"BLOCKED: Freeze mode is active. Only files matching the allowed patterns can be edited.",
|
|
250
|
+
f"File: {file_path}",
|
|
251
|
+
f"Allowed: {allowed_display}",
|
|
252
|
+
"Use /unfreeze to lift the scope lock.",
|
|
253
|
+
]
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
def _freeze_verdict(
|
|
257
|
+
file_path: str,
|
|
258
|
+
lower_path: str,
|
|
259
|
+
freeze_path: Path,
|
|
260
|
+
cwd: str,
|
|
261
|
+
repo_root: Path | None,
|
|
262
|
+
session_id: str | None,
|
|
263
|
+
) -> tuple | None:
|
|
264
|
+
"""Freeze-mode lens, mirroring `pre_pr_review.py`'s named-verdict-lens
|
|
265
|
+
pipeline shape: a decisive BLOCK `(exit_code, lines)` tuple when freeze
|
|
266
|
+
is active and `file_path` is in scope but not allow-listed (or is a
|
|
267
|
+
symlink escape out of scope — see below); `None` otherwise, meaning
|
|
268
|
+
"continue to the sensitive-path/warn checks".
|
|
269
|
+
|
|
270
|
+
A candidate whose UNRESOLVED, cwd-joined form is inside `repo_root`
|
|
271
|
+
but whose `.resolve()`d form (following symlinks) lands outside it is
|
|
272
|
+
a symlink escape and is BLOCKED, not treated as merely out of scope —
|
|
273
|
+
a scope lock crossing a symlink must never be silently permitted.
|
|
274
|
+
"""
|
|
275
|
+
allowed = _load_freeze(freeze_path)
|
|
276
|
+
if allowed is None:
|
|
277
|
+
return None
|
|
278
|
+
|
|
279
|
+
rel_path, in_scope = _relative_to_repo_root(file_path, cwd, repo_root)
|
|
280
|
+
if repo_root is not None and not in_scope:
|
|
281
|
+
if _unresolved_within_repo_root(file_path, cwd, repo_root):
|
|
282
|
+
return _freeze_block(file_path, allowed, cwd, session_id)
|
|
283
|
+
return None
|
|
284
|
+
|
|
285
|
+
subjects = [file_path, lower_path]
|
|
286
|
+
if rel_path is not None:
|
|
287
|
+
subjects.extend((rel_path, rel_path.lower()))
|
|
288
|
+
matched = any(
|
|
289
|
+
fnmatch.fnmatchcase(subject, pat) for subject in subjects for pat in allowed
|
|
290
|
+
)
|
|
291
|
+
if matched:
|
|
292
|
+
return None
|
|
293
|
+
return _freeze_block(file_path, allowed, cwd, session_id)
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
def evaluate(
|
|
297
|
+
file_path: str,
|
|
298
|
+
cwd: str = ".",
|
|
299
|
+
session_id: str | None = None,
|
|
300
|
+
*,
|
|
301
|
+
paths: GuardPaths,
|
|
302
|
+
) -> tuple:
|
|
303
|
+
"""Return (exit_code, [stdout_lines]) for a single file_path decision.
|
|
304
|
+
|
|
305
|
+
- exit_code 0 with `[warning]` lines means "allow with warning".
|
|
306
|
+
- exit_code 0 with `[]` means "silent pass".
|
|
307
|
+
- exit_code 2 with `[block message]` means "block".
|
|
308
|
+
|
|
309
|
+
`paths.repo_root` is the repo `cwd` resolved to (see `main()`) — used
|
|
310
|
+
only to relativize `file_path` against it for the freeze-mode allowlist
|
|
311
|
+
match (#1904 items 7, 14). Leave it `None` to match `file_path` as-is,
|
|
312
|
+
e.g. when the caller already knows it's repo-relative.
|
|
313
|
+
|
|
314
|
+
Emits a boundary event (#859) for every warn/block decision.
|
|
315
|
+
"""
|
|
316
|
+
if not file_path:
|
|
317
|
+
return 0, []
|
|
318
|
+
|
|
319
|
+
filename = os.path.basename(file_path)
|
|
320
|
+
lower_filename = filename.lower()
|
|
321
|
+
lower_path = file_path.lower()
|
|
322
|
+
|
|
323
|
+
# Freeze mode first — scope lock trumps allow list.
|
|
324
|
+
verdict = _freeze_verdict(
|
|
325
|
+
file_path, lower_path, paths.freeze_path, cwd, paths.repo_root, session_id
|
|
326
|
+
)
|
|
327
|
+
if verdict is not None:
|
|
328
|
+
return verdict
|
|
329
|
+
|
|
330
|
+
blocked_patterns, warn_patterns = _load_guards(paths.guards_path)
|
|
331
|
+
|
|
332
|
+
if _matches_any(lower_filename, blocked_patterns) or _matches_any(
|
|
333
|
+
lower_path, blocked_patterns
|
|
334
|
+
):
|
|
335
|
+
emit_boundary_event(cwd, "pre_tool_guard", "Write", "block", "sensitive-path", session_id)
|
|
336
|
+
return 2, [
|
|
337
|
+
f"BLOCKED: Write to '{file_path}' is not allowed.",
|
|
338
|
+
"This path matches a sensitive-file pattern in .claude/hooks/guards.json.",
|
|
339
|
+
"If this write is intentional, confirm with the user before proceeding.",
|
|
340
|
+
]
|
|
341
|
+
|
|
342
|
+
if _matches_any(lower_path, warn_patterns):
|
|
343
|
+
emit_boundary_event(cwd, "pre_tool_guard", "Write", "warn", "protected-config", session_id)
|
|
344
|
+
return 0, [
|
|
345
|
+
f"WARNING: '{file_path}' is a protected configuration file.",
|
|
346
|
+
"Verify this change is intentional before writing.",
|
|
347
|
+
]
|
|
348
|
+
|
|
349
|
+
return 0, []
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
def _cheap_freeze_inactive(cwd: str) -> bool:
|
|
353
|
+
"""Cheap, non-git proof that freeze mode is inactive for `cwd` (#1904
|
|
354
|
+
item 11) — mirrors #1861's `looks_like_monorepo_checkout` cheap-stat
|
|
355
|
+
pattern, added there for the higher-frequency PostToolUse `*` matcher.
|
|
356
|
+
|
|
357
|
+
Only returns True when `cwd` is unambiguously the repo root itself (a
|
|
358
|
+
`.git` entry exists directly under it — a plain stat, no `git`
|
|
359
|
+
subprocess needed to confirm this) AND no `.claude/hooks/
|
|
360
|
+
freeze-state.json` exists there. Any other shape — `cwd` is a
|
|
361
|
+
subdirectory of the repo (the file could exist at an ancestor this
|
|
362
|
+
check never looks at), or the file exists right here — is ambiguous;
|
|
363
|
+
the caller must fall through to the git-rev-parse-based resolution.
|
|
364
|
+
"""
|
|
365
|
+
try:
|
|
366
|
+
base = Path(cwd)
|
|
367
|
+
if not (base / ".git").exists():
|
|
368
|
+
return False
|
|
369
|
+
return not (base / ".claude" / "hooks" / "freeze-state.json").exists()
|
|
370
|
+
except OSError:
|
|
371
|
+
return False
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
def main() -> int:
|
|
375
|
+
raw = sys.stdin.read()
|
|
376
|
+
file_path = _extract_file_path(raw)
|
|
377
|
+
if not file_path:
|
|
378
|
+
return 0
|
|
379
|
+
try:
|
|
380
|
+
payload = json.loads(raw)
|
|
381
|
+
except (TypeError, ValueError):
|
|
382
|
+
payload = {}
|
|
383
|
+
raw_cwd = payload.get("cwd") if isinstance(payload, dict) else None
|
|
384
|
+
cwd = raw_cwd if isinstance(raw_cwd, str) and raw_cwd and "\0" not in raw_cwd else "."
|
|
385
|
+
raw_session_id = payload.get("session_id") if isinstance(payload, dict) else None
|
|
386
|
+
session_id = raw_session_id if isinstance(raw_session_id, str) else None
|
|
387
|
+
script_dir = Path(__file__).resolve().parent
|
|
388
|
+
|
|
389
|
+
repo_root: Path | None
|
|
390
|
+
if _cheap_freeze_inactive(cwd):
|
|
391
|
+
freeze_path = Path(cwd) / ".claude" / "hooks" / "freeze-state.json"
|
|
392
|
+
repo_root = None
|
|
393
|
+
else:
|
|
394
|
+
repo_root = artifact_paths.project_root(start=cwd)
|
|
395
|
+
freeze_path = repo_root / ".claude" / "hooks" / "freeze-state.json"
|
|
396
|
+
|
|
397
|
+
paths = GuardPaths(script_dir / "guards.json", freeze_path, repo_root)
|
|
398
|
+
exit_code, lines = evaluate(file_path, cwd, session_id, paths=paths)
|
|
399
|
+
for line in lines:
|
|
400
|
+
print(line)
|
|
401
|
+
return exit_code
|
|
402
|
+
|
|
403
|
+
|
|
404
|
+
if __name__ == "__main__": # pragma: no cover
|
|
405
|
+
sys.exit(main())
|
package/hooks/py.sh
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# py.sh — resolve a working Python 3 interpreter and exec it with the given args.
|
|
3
|
+
#
|
|
4
|
+
# Ships as .sh (not .py) by necessity: it runs BEFORE a Python interpreter is
|
|
5
|
+
# guaranteed on PATH, so it cannot itself be Python. This is the same
|
|
6
|
+
# pre-Python bootstrap carve-out ADR 0015 grants install.sh — not a regression
|
|
7
|
+
# on the "shipped scripts are Python" rule.
|
|
8
|
+
#
|
|
9
|
+
# Why it exists: every hook command in settings.json and the /version skill
|
|
10
|
+
# route their Python invocations through this shim so the plugin works on
|
|
11
|
+
# machines where Python 3 exists under a name other than `python3`. Notably
|
|
12
|
+
# Windows, where python.org installs `python.exe`/`py.exe` but NOT
|
|
13
|
+
# `python3.exe`, and the only `python3` on PATH is the WindowsApps
|
|
14
|
+
# app-execution-alias stub that refuses to run non-interactively. Many
|
|
15
|
+
# locked-down corporate users cannot install packages to fix this themselves
|
|
16
|
+
# but do have Python 3 as `python`/`py`.
|
|
17
|
+
#
|
|
18
|
+
# Resolution order: $DEV_TEAM_PYTHON override, then python3, py -3, python.
|
|
19
|
+
# Each candidate is *executed* (not just located with `command -v`) so the
|
|
20
|
+
# Store stub and Python 2 are rejected on behavior, not name. The winner is
|
|
21
|
+
# cached for the session so only the first call pays the probe cost.
|
|
22
|
+
#
|
|
23
|
+
# Usage: sh hooks/py.sh <script.py> [args...]
|
|
24
|
+
# Exit 2 (environment error) when no Python 3 is found — matches the hook
|
|
25
|
+
# contract's exit-2 semantics.
|
|
26
|
+
|
|
27
|
+
set -u
|
|
28
|
+
|
|
29
|
+
# Match version_check.py's cache convention: a bare /tmp literal is portable to
|
|
30
|
+
# Windows Git Bash (MSYS mounts it), so no ${TMPDIR:-/tmp} dance is needed.
|
|
31
|
+
# $DEV_TEAM_PY_CACHE overrides the path (used by tests for isolation).
|
|
32
|
+
CACHE="${DEV_TEAM_PY_CACHE:-/tmp/.dev-team-python}"
|
|
33
|
+
|
|
34
|
+
# A candidate is valid only if it runs AND reports major version >= 3. All
|
|
35
|
+
# output is discarded so the Store stub's "not found" banner never surfaces and
|
|
36
|
+
# a candidate that prints nothing is judged purely on exit status.
|
|
37
|
+
valid() {
|
|
38
|
+
command -v "$1" >/dev/null 2>&1 || return 1
|
|
39
|
+
"$@" -c 'import sys; raise SystemExit(0 if sys.version_info[0] >= 3 else 1)' \
|
|
40
|
+
>/dev/null 2>&1
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
# Fast path: trust a cached interpreter if its first token still resolves.
|
|
44
|
+
# Skipped when DEV_TEAM_PYTHON is set so an explicit override always wins over a
|
|
45
|
+
# stale cache.
|
|
46
|
+
if [ -z "${DEV_TEAM_PYTHON:-}" ] && [ -f "$CACHE" ]; then
|
|
47
|
+
read -r PY <"$CACHE" 2>/dev/null || PY=""
|
|
48
|
+
if [ -n "$PY" ] && command -v "${PY%% *}" >/dev/null 2>&1; then
|
|
49
|
+
exec $PY "$@"
|
|
50
|
+
fi
|
|
51
|
+
fi
|
|
52
|
+
|
|
53
|
+
PY=""
|
|
54
|
+
# Intentional word-split: DEV_TEAM_PYTHON may be a multi-word command like "py -3".
|
|
55
|
+
# shellcheck disable=SC2086
|
|
56
|
+
if [ -n "${DEV_TEAM_PYTHON:-}" ] && valid ${DEV_TEAM_PYTHON}; then
|
|
57
|
+
PY="${DEV_TEAM_PYTHON}"
|
|
58
|
+
elif valid python3; then
|
|
59
|
+
PY="python3"
|
|
60
|
+
elif valid py -3; then
|
|
61
|
+
PY="py -3"
|
|
62
|
+
elif valid python; then
|
|
63
|
+
PY="python"
|
|
64
|
+
else
|
|
65
|
+
echo "dev-team: no Python 3 interpreter found (tried \$DEV_TEAM_PYTHON, python3, py -3, python)." >&2
|
|
66
|
+
echo "dev-team: install Python 3.8+ or set DEV_TEAM_PYTHON to a working interpreter." >&2
|
|
67
|
+
exit 2
|
|
68
|
+
fi
|
|
69
|
+
|
|
70
|
+
# Best-effort cache; a read-only /tmp is non-fatal.
|
|
71
|
+
printf '%s\n' "$PY" >"$CACHE" 2>/dev/null || true
|
|
72
|
+
|
|
73
|
+
exec $PY "$@"
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_comment": "Regex library for refactor_test_bash_guard.py (#906). Each entry recognizes one Bash file-modifying shape and extracts the apparent write target via a named 'target' capture group. Every occurrence of every entry is evaluated independently against the full command (#914) - a command blocks if ANY occurrence's target resolves to a frozen test file, so an earlier benign match (e.g. 'redirect' onto a scratch file, or an earlier 'mv-cp' onto a non-test file) in a compound command can never mask a later, genuinely dangerous match (same entry or a different one) elsewhere in the same string. Ambiguous/unparseable commands (no entry matches) are never blocked - false-negative-favoring by design, see the issue's Non-goals.",
|
|
3
|
+
"patterns": [
|
|
4
|
+
{
|
|
5
|
+
"id": "sed-i",
|
|
6
|
+
"regex": "\\bsed\\s+-i(?:\\.\\S+)?\\s+(?:-e\\s+)?(?:'[^']*'|\"[^\"]*\")\\s+(?P<target>[^\\s;&|]+)"
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
"id": "perl-i",
|
|
10
|
+
"regex": "\\bperl\\s+-i(?:\\.\\S+)?\\s+(?:-[a-zA-Z]+\\s+)*(?:'[^']*'|\"[^\"]*\")\\s+(?P<target>[^\\s;&|]+)"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"id": "tee",
|
|
14
|
+
"regex": "\\btee\\s+(?:-a\\s+)?(?P<target>[^\\s;&|]+)"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"id": "redirect",
|
|
18
|
+
"regex": "(?<![\\w&])>{1,2}(?!\\S*&)\\s*(?P<target>[^\\s;&|>]+)"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"id": "mv-cp",
|
|
22
|
+
"regex": "\\b(?:mv|cp)\\s+(?:-\\S+\\s+)*(?P<src>[^\\s;&|]+)\\s+(?P<target>[^\\s;&|]+)\\s*(?:[;&|]|$)"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"id": "python-open-write",
|
|
26
|
+
"regex": "open\\(\\s*['\"](?P<target>[^'\"]+)['\"]\\s*,\\s*['\"](?:w|a|wb|ab|w\\+|a\\+)['\"]"
|
|
27
|
+
}
|
|
28
|
+
]
|
|
29
|
+
}
|