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,293 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""code_intelligence_nudge — Claude Code PreToolUse hook.
|
|
3
|
+
|
|
4
|
+
Renamed/generalized from codegraph_nudge.py (#593 / #572 Phase 3, #1368)
|
|
5
|
+
now that this hook nudges agents toward whichever of CodeGraph, Repowise,
|
|
6
|
+
and Graphify are indexed in the project, not CodeGraph alone.
|
|
7
|
+
`_detect_present_tools()` reports which of the three are present;
|
|
8
|
+
`_compose_message()` composes a single-tool or precedence-ordered
|
|
9
|
+
combined message for whichever of those are not already used this turn.
|
|
10
|
+
|
|
11
|
+
Runs before Read, Grep, Glob tool calls. Single-file Read calls, Grep with
|
|
12
|
+
a file `path`, and Glob with a literal `pattern` pass silently.
|
|
13
|
+
|
|
14
|
+
Contract (docs/python-hook-contract.md):
|
|
15
|
+
Input : PreToolUse JSON on stdin
|
|
16
|
+
Output: warning on stderr when exploration is detected
|
|
17
|
+
Exit : 0 = allow (silent or warn). 2 = block (careful mode only).
|
|
18
|
+
|
|
19
|
+
Posture: fail-open. Any internal error → exit 0. The hook is a nudge,
|
|
20
|
+
never a gate.
|
|
21
|
+
|
|
22
|
+
Stdlib-only.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
from __future__ import annotations
|
|
26
|
+
|
|
27
|
+
import json
|
|
28
|
+
import sys
|
|
29
|
+
from pathlib import Path
|
|
30
|
+
|
|
31
|
+
_HOOK_DIR = Path(__file__).resolve().parent
|
|
32
|
+
_LIB_DIR = _HOOK_DIR / "lib"
|
|
33
|
+
|
|
34
|
+
sys.path.insert(0, str(_LIB_DIR))
|
|
35
|
+
|
|
36
|
+
import artifact_paths # type: ignore[import-not-found]
|
|
37
|
+
|
|
38
|
+
try:
|
|
39
|
+
from stdin_json import read_stdin_json # type: ignore[import-not-found]
|
|
40
|
+
except ImportError: # pragma: no cover
|
|
41
|
+
|
|
42
|
+
def read_stdin_json() -> dict | None: # type: ignore[misc]
|
|
43
|
+
return None
|
|
44
|
+
|
|
45
|
+
try:
|
|
46
|
+
from turn_identity import ( # type: ignore[import-not-found]
|
|
47
|
+
SENTINEL_RELATIVE_PATH,
|
|
48
|
+
count_user_lines,
|
|
49
|
+
matches_current_turn,
|
|
50
|
+
transcript_id,
|
|
51
|
+
)
|
|
52
|
+
except ImportError: # pragma: no cover
|
|
53
|
+
|
|
54
|
+
SENTINEL_RELATIVE_PATH = Path(".claude") / "code-intelligence-turn-state.json" # type: ignore[misc]
|
|
55
|
+
|
|
56
|
+
def transcript_id(path: str) -> str: # type: ignore[misc]
|
|
57
|
+
return Path(path).stem
|
|
58
|
+
|
|
59
|
+
def count_user_lines(transcript_path: Path) -> int: # type: ignore[misc]
|
|
60
|
+
return 0
|
|
61
|
+
|
|
62
|
+
def matches_current_turn(sentinel: dict, tid: str, tc: int) -> bool: # type: ignore[misc]
|
|
63
|
+
sentinel_tid = str(sentinel.get("transcript_id") or "")
|
|
64
|
+
if sentinel_tid != tid:
|
|
65
|
+
return False
|
|
66
|
+
try:
|
|
67
|
+
return int(sentinel.get("turn_counter")) == tc
|
|
68
|
+
except (TypeError, ValueError):
|
|
69
|
+
return False
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
_CUES = {
|
|
73
|
+
"graphify": (
|
|
74
|
+
'graphify query "<question>" — cross-artifact: code + docs + schemas + '
|
|
75
|
+
"infra (non-code content; not a faster CodeGraph/Repowise)"
|
|
76
|
+
),
|
|
77
|
+
"repowise": (
|
|
78
|
+
"repowise get_context / get_risk / get_why — risk, rationale, code "
|
|
79
|
+
"health, dead code (not raw call-graph structure)"
|
|
80
|
+
),
|
|
81
|
+
"codegraph": (
|
|
82
|
+
"codegraph_explore — structure, call graph, blast radius (not risk, "
|
|
83
|
+
"rationale, or non-code content)"
|
|
84
|
+
),
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
_LABELS = {"graphify": "Graphify", "repowise": "Repowise", "codegraph": "CodeGraph"}
|
|
88
|
+
|
|
89
|
+
# Fixed message order — never the filesystem/detection order the caller passes in.
|
|
90
|
+
# This specific order (graphify, repowise, codegraph) was chosen during plan
|
|
91
|
+
# review to remove the CodeGraph-first primacy bias that motivated this whole
|
|
92
|
+
# generalization (#1368): CodeGraph used to be the only tool this hook named,
|
|
93
|
+
# so listing it first here would silently re-establish it as the "default,
|
|
94
|
+
# most-likely-tried" tool. Graphify and Repowise get equal billing ahead of
|
|
95
|
+
# it instead.
|
|
96
|
+
_PRECEDENCE = ["graphify", "repowise", "codegraph"]
|
|
97
|
+
|
|
98
|
+
_CLOSING_LINE = "Grep/Glob/Read for confirming a specific detail."
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def _cue_line(tool: str, *, bulleted: bool) -> str:
|
|
102
|
+
"""Format one tool's cue — bulleted for the combined message, bare for
|
|
103
|
+
the single-tool message. Shared by both `_compose_message` branches so
|
|
104
|
+
the underlying cue text can't drift between the two message shapes."""
|
|
105
|
+
return f"- {_CUES[tool]}" if bulleted else _CUES[tool]
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def _compose_message(qualifying: list) -> str | None:
|
|
109
|
+
"""Compose the nudge message for the given qualifying tools.
|
|
110
|
+
|
|
111
|
+
`qualifying` is reordered by `_PRECEDENCE` before composing — the
|
|
112
|
+
message's tool order never varies with filesystem/detection order.
|
|
113
|
+
Zero qualifying tools → None (full suppression).
|
|
114
|
+
"""
|
|
115
|
+
ordered = [tool for tool in _PRECEDENCE if tool in qualifying]
|
|
116
|
+
if not ordered:
|
|
117
|
+
return None
|
|
118
|
+
|
|
119
|
+
if len(ordered) == 1:
|
|
120
|
+
tool = ordered[0]
|
|
121
|
+
return (
|
|
122
|
+
f"[code-intelligence-nudge] {_LABELS[tool]} is initialized in this "
|
|
123
|
+
f"project. Prefer {_cue_line(tool, bulleted=False)} for multi-file "
|
|
124
|
+
f"exploration; {_CLOSING_LINE}"
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
bullets = "\n".join(_cue_line(tool, bulleted=True) for tool in ordered)
|
|
128
|
+
return (
|
|
129
|
+
"[code-intelligence-nudge] Multiple code-intelligence indexes found. "
|
|
130
|
+
f"Pick whichever matches your question:\n{bullets}\n{_CLOSING_LINE}"
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def _tools_used_this_turn(cwd: Path, transcript_path: str) -> list:
|
|
135
|
+
"""Which tool families ran earlier in the current turn, per the
|
|
136
|
+
accumulating sentinel `code_intelligence_turn_mark.py` writes at
|
|
137
|
+
`$cwd/.claude/code-intelligence-turn-state.json`.
|
|
138
|
+
|
|
139
|
+
Cross-checks the sentinel's `transcript_id`/`turn_counter` against the
|
|
140
|
+
freshly computed values (same turn-identity computation the write side
|
|
141
|
+
uses, via turn_identity.py) — a mismatch means a new turn/transcript, so
|
|
142
|
+
the sentinel doesn't apply. A missing file, an unparseable/non-dict
|
|
143
|
+
payload, a mismatched identity, or a `tools_used` field that's missing
|
|
144
|
+
or not a list (legacy pre-Slice-2 schema, or corrupt) all resolve to
|
|
145
|
+
`[]` — fail-open, never a crash.
|
|
146
|
+
"""
|
|
147
|
+
sentinel = cwd / SENTINEL_RELATIVE_PATH
|
|
148
|
+
if not sentinel.is_file():
|
|
149
|
+
return []
|
|
150
|
+
if not transcript_path:
|
|
151
|
+
return []
|
|
152
|
+
tx = Path(transcript_path)
|
|
153
|
+
if not tx.is_file():
|
|
154
|
+
return []
|
|
155
|
+
try:
|
|
156
|
+
sentinel_data = json.loads(sentinel.read_text(encoding="utf-8"))
|
|
157
|
+
except (OSError, json.JSONDecodeError):
|
|
158
|
+
return []
|
|
159
|
+
if not isinstance(sentinel_data, dict):
|
|
160
|
+
return []
|
|
161
|
+
|
|
162
|
+
current_tid = transcript_id(transcript_path)
|
|
163
|
+
current_tc = count_user_lines(tx)
|
|
164
|
+
if not matches_current_turn(sentinel_data, current_tid, current_tc):
|
|
165
|
+
return []
|
|
166
|
+
|
|
167
|
+
tools_used = sentinel_data.get("tools_used")
|
|
168
|
+
if not isinstance(tools_used, list):
|
|
169
|
+
return []
|
|
170
|
+
return tools_used
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def _is_multi_grep(tool_input: dict) -> bool:
|
|
174
|
+
"""Grep is multi-file unless `path` is set AND points at a regular file."""
|
|
175
|
+
path = str(tool_input.get("path") or "")
|
|
176
|
+
if not path:
|
|
177
|
+
return True
|
|
178
|
+
return not Path(path).is_file()
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def _is_multi_glob(tool_input: dict) -> bool:
|
|
182
|
+
"""Glob is multi when the pattern contains a glob metacharacter."""
|
|
183
|
+
pattern = str(tool_input.get("pattern") or "")
|
|
184
|
+
return any(c in pattern for c in ("*", "?", "["))
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def _detect_present_tools(cwd: Path) -> list:
|
|
188
|
+
"""Return which of codegraph/repowise/graphify are indexed in `cwd`.
|
|
189
|
+
|
|
190
|
+
codegraph: `.codegraph/` directory. repowise: `.repowise/` directory.
|
|
191
|
+
graphify: `graphify-out/graph.json` regular file. Each check is wrapped
|
|
192
|
+
so any OSError (wrong type — e.g. a file where a dir is expected, or a
|
|
193
|
+
permission error) is treated as "not present," never raised — this
|
|
194
|
+
hook is a nudge, never a gate.
|
|
195
|
+
"""
|
|
196
|
+
present = []
|
|
197
|
+
try:
|
|
198
|
+
if (cwd / ".codegraph").is_dir():
|
|
199
|
+
present.append("codegraph")
|
|
200
|
+
except OSError:
|
|
201
|
+
pass
|
|
202
|
+
try:
|
|
203
|
+
if (cwd / ".repowise").is_dir():
|
|
204
|
+
present.append("repowise")
|
|
205
|
+
except OSError:
|
|
206
|
+
pass
|
|
207
|
+
try:
|
|
208
|
+
if (cwd / "graphify-out" / "graph.json").is_file():
|
|
209
|
+
present.append("graphify")
|
|
210
|
+
except OSError:
|
|
211
|
+
pass
|
|
212
|
+
return present
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def _careful_active(careful_path: Path) -> bool:
|
|
216
|
+
"""Read careful-state.json's `active` field; True iff it is `True`.
|
|
217
|
+
|
|
218
|
+
`careful_path` is resolved by the caller via
|
|
219
|
+
`artifact_paths.resolve_file()`, keyed off the payload's own `cwd`
|
|
220
|
+
(#1900 follow-up in this file — the identical bug class already fixed
|
|
221
|
+
in `destructive_guard.py`: `/careful`/`/guard` only ever write the
|
|
222
|
+
per-repo `<repo-root>/.claude/hooks/careful-state.json`, never a path
|
|
223
|
+
relative to this hook's own script directory, which in a real
|
|
224
|
+
installed session is the shared plugin-cache directory — one location
|
|
225
|
+
shared by every concurrently-running session, worktree, and project on
|
|
226
|
+
the machine).
|
|
227
|
+
"""
|
|
228
|
+
if not careful_path.is_file():
|
|
229
|
+
return False
|
|
230
|
+
try:
|
|
231
|
+
data = json.loads(careful_path.read_text(encoding="utf-8"))
|
|
232
|
+
except (OSError, json.JSONDecodeError):
|
|
233
|
+
return False
|
|
234
|
+
return data.get("active") is True
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
def main() -> int:
|
|
238
|
+
payload = read_stdin_json()
|
|
239
|
+
if payload is None:
|
|
240
|
+
return 0
|
|
241
|
+
|
|
242
|
+
cwd_str = str(payload.get("cwd") or "").strip()
|
|
243
|
+
cwd = Path(cwd_str) if cwd_str else Path.cwd()
|
|
244
|
+
|
|
245
|
+
tool_name = str(payload.get("tool_name") or "")
|
|
246
|
+
|
|
247
|
+
# Read always targets exactly one file_path — never exploration.
|
|
248
|
+
if tool_name == "Read":
|
|
249
|
+
return 0
|
|
250
|
+
|
|
251
|
+
tool_input = payload.get("tool_input") or {}
|
|
252
|
+
if not isinstance(tool_input, dict):
|
|
253
|
+
return 0
|
|
254
|
+
|
|
255
|
+
if tool_name == "Grep":
|
|
256
|
+
is_multi = _is_multi_grep(tool_input)
|
|
257
|
+
elif tool_name == "Glob":
|
|
258
|
+
is_multi = _is_multi_glob(tool_input)
|
|
259
|
+
else:
|
|
260
|
+
# Other tools — defensive default, pass silently.
|
|
261
|
+
return 0
|
|
262
|
+
|
|
263
|
+
if not is_multi:
|
|
264
|
+
return 0
|
|
265
|
+
|
|
266
|
+
qualifying = _detect_present_tools(cwd)
|
|
267
|
+
if not qualifying:
|
|
268
|
+
return 0
|
|
269
|
+
|
|
270
|
+
transcript_path = str(payload.get("transcript_path") or "")
|
|
271
|
+
used_this_turn = set(_tools_used_this_turn(cwd, transcript_path))
|
|
272
|
+
qualifying = [tool for tool in qualifying if tool not in used_this_turn]
|
|
273
|
+
|
|
274
|
+
message = _compose_message(qualifying)
|
|
275
|
+
if message is None:
|
|
276
|
+
return 0
|
|
277
|
+
|
|
278
|
+
careful_path = artifact_paths.resolve_file(
|
|
279
|
+
"hooks", "careful-state.json", root=cwd, migrate=False
|
|
280
|
+
)
|
|
281
|
+
if _careful_active(careful_path):
|
|
282
|
+
print(f"{message} [blocked by /careful]", file=sys.stderr)
|
|
283
|
+
return 2
|
|
284
|
+
|
|
285
|
+
print(message, file=sys.stderr)
|
|
286
|
+
return 0
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
if __name__ == "__main__":
|
|
290
|
+
try:
|
|
291
|
+
sys.exit(main())
|
|
292
|
+
except Exception: # noqa: BLE001 -- fail-open on any unexpected error; the hook is a nudge, never a gate
|
|
293
|
+
sys.exit(0)
|
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Renamed/generalized from codegraph_turn_mark.py (#594 / #572 Phase 3, #1368).
|
|
3
|
+
|
|
4
|
+
Claude Code PostToolUse hook. Fires after a tool call completes and
|
|
5
|
+
`_tool_family()` recognizes its name as belonging to a supported
|
|
6
|
+
code-intelligence tool family — currently `mcp__codegraph__*` ("codegraph")
|
|
7
|
+
and `mcp__plugin_repowise_repowise__*` ("repowise"). Writes a sentinel at
|
|
8
|
+
`${CLAUDE_PROJECT_DIR:-$PWD}/.claude/code-intelligence-turn-state.json` that
|
|
9
|
+
the nudge hook (`code_intelligence_nudge.py`) will consult (Step 2.3) to
|
|
10
|
+
suppress its warning for whichever tool family was used during the rest of
|
|
11
|
+
the current turn.
|
|
12
|
+
|
|
13
|
+
`transcript_id`/`count_user_lines` are imported from the shared
|
|
14
|
+
`hooks/lib/turn_identity.py` module (falling back to local reimplementations
|
|
15
|
+
only if that import fails) so this hook and the nudge hook can never drift
|
|
16
|
+
apart on how a "turn" is identified. The same module's `matches_current_turn`
|
|
17
|
+
owns the identity-match predicate for both this hook's read-modify-write
|
|
18
|
+
merge and the nudge hook's read-side suppression check.
|
|
19
|
+
|
|
20
|
+
Sentinel schema (Step 2.2 — accumulating `tools_used` list, written to
|
|
21
|
+
`.claude/code-intelligence-turn-state.json`):
|
|
22
|
+
{ "transcript_id": <string>, "turn_counter": <int>, "tools_used": [<string>, ...] }
|
|
23
|
+
- transcript_id: basename of transcript_path with extension stripped
|
|
24
|
+
- turn_counter: count of `"type":"user"` lines in the transcript file,
|
|
25
|
+
scanning only the last 1 MiB so a monotonically growing
|
|
26
|
+
transcript stays O(1) per fire (same cap the nudge hook
|
|
27
|
+
applies on its side).
|
|
28
|
+
- tools_used: families (e.g. "codegraph", "repowise") recognized so
|
|
29
|
+
far this turn, in first-used order, deduplicated.
|
|
30
|
+
|
|
31
|
+
Before writing, any existing sentinel is read back. When its transcript_id
|
|
32
|
+
and turn_counter match the freshly computed values (same turn), the newly
|
|
33
|
+
recognized family is merged into the existing `tools_used` list (deduped,
|
|
34
|
+
order preserved); otherwise — new turn, new transcript, or a
|
|
35
|
+
missing/legacy/corrupt sentinel — the sentinel is rewritten from scratch
|
|
36
|
+
with only the new family. A `tools_used` field that exists but isn't a
|
|
37
|
+
list, or a sentinel that fails to parse at all, is treated as an empty list
|
|
38
|
+
rather than raised (fail-open on the write side, mirroring the nudge hook's
|
|
39
|
+
read-side handling of the same shapes).
|
|
40
|
+
|
|
41
|
+
Both `transcript_id`/`turn_counter` are computed the same way the nudge hook
|
|
42
|
+
recomputes them at PreToolUse time, so a same-turn match accumulates and a
|
|
43
|
+
next-turn mismatch (new user message → counter bumps) resets it.
|
|
44
|
+
|
|
45
|
+
Contract (docs/python-hook-contract.md):
|
|
46
|
+
Input : PostToolUse JSON on stdin
|
|
47
|
+
Output: writes sentinel file; no stdout. Exit 0.
|
|
48
|
+
Posture: fail-open. Any internal error → exit 0; sentinel may not be
|
|
49
|
+
written, the nudge hook will simply emit its (advisory) warning.
|
|
50
|
+
|
|
51
|
+
Stdlib-only (json/os/pathlib/sys/tempfile). See ADR 0014.
|
|
52
|
+
|
|
53
|
+
Refs: #572 (bash → Python migration epic), #1368 (multi-tool nudge).
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
from __future__ import annotations
|
|
57
|
+
|
|
58
|
+
import contextlib
|
|
59
|
+
import json
|
|
60
|
+
import os
|
|
61
|
+
import sys
|
|
62
|
+
import tempfile
|
|
63
|
+
import time
|
|
64
|
+
from pathlib import Path
|
|
65
|
+
|
|
66
|
+
try:
|
|
67
|
+
import fcntl # type: ignore[import-not-found]
|
|
68
|
+
except ImportError: # pragma: no cover — Windows has no fcntl
|
|
69
|
+
fcntl = None # type: ignore[assignment]
|
|
70
|
+
|
|
71
|
+
try:
|
|
72
|
+
import msvcrt # type: ignore[import-not-found]
|
|
73
|
+
except ImportError: # pragma: no cover — POSIX has no msvcrt
|
|
74
|
+
msvcrt = None # type: ignore[assignment]
|
|
75
|
+
|
|
76
|
+
_HOOK_DIR = Path(__file__).resolve().parent
|
|
77
|
+
_LIB_DIR = _HOOK_DIR / "lib"
|
|
78
|
+
|
|
79
|
+
sys.path.insert(0, str(_LIB_DIR))
|
|
80
|
+
try:
|
|
81
|
+
from turn_identity import ( # type: ignore[import-not-found]
|
|
82
|
+
SENTINEL_RELATIVE_PATH,
|
|
83
|
+
count_user_lines,
|
|
84
|
+
matches_current_turn,
|
|
85
|
+
transcript_id,
|
|
86
|
+
)
|
|
87
|
+
except ImportError: # pragma: no cover
|
|
88
|
+
|
|
89
|
+
SENTINEL_RELATIVE_PATH = Path(".claude") / "code-intelligence-turn-state.json" # type: ignore[misc]
|
|
90
|
+
|
|
91
|
+
def transcript_id(path: str) -> str: # type: ignore[misc]
|
|
92
|
+
return Path(path).stem
|
|
93
|
+
|
|
94
|
+
def count_user_lines(transcript_path: Path) -> int: # type: ignore[misc]
|
|
95
|
+
return 0
|
|
96
|
+
|
|
97
|
+
def matches_current_turn(sentinel: dict, tid: str, tc: int) -> bool: # type: ignore[misc]
|
|
98
|
+
sentinel_tid = str(sentinel.get("transcript_id") or "")
|
|
99
|
+
if sentinel_tid != tid:
|
|
100
|
+
return False
|
|
101
|
+
try:
|
|
102
|
+
return int(sentinel.get("turn_counter")) == tc
|
|
103
|
+
except (TypeError, ValueError):
|
|
104
|
+
return False
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
from stdin_json import read_stdin_json # type: ignore[import-not-found]
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def _tool_family(name: str) -> str | None:
|
|
111
|
+
"""Classify a tool name into the family whose usage this hook marks.
|
|
112
|
+
|
|
113
|
+
Same prefix filter the .sh applied via
|
|
114
|
+
`case "$TOOL_NAME" in mcp__codegraph__*)`, generalized to also recognize
|
|
115
|
+
Repowise's MCP server prefix. Any other tool name (or a name matching
|
|
116
|
+
neither prefix) returns None.
|
|
117
|
+
"""
|
|
118
|
+
if name.startswith("mcp__codegraph__"):
|
|
119
|
+
return "codegraph"
|
|
120
|
+
if name.startswith("mcp__plugin_repowise_repowise__"):
|
|
121
|
+
return "repowise"
|
|
122
|
+
return None
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def _existing_tools_used(sentinel: Path, tid: str, tc: int) -> list:
|
|
126
|
+
"""Read back any prior sentinel's `tools_used` for the current turn.
|
|
127
|
+
|
|
128
|
+
Fail-open on every corrupt/legacy shape — an unreadable file, invalid
|
|
129
|
+
JSON, a non-dict payload, a mismatched transcript/turn (new turn), a
|
|
130
|
+
missing `tools_used` field (legacy pre-Slice-2 schema), or a
|
|
131
|
+
`tools_used` present but not a list — all resolve to "start fresh",
|
|
132
|
+
i.e. an empty list, never a raised exception. The same-turn check
|
|
133
|
+
itself is `turn_identity.matches_current_turn` — the single predicate
|
|
134
|
+
shared with the nudge hook's read side, so the two sides of the
|
|
135
|
+
sentinel contract can't drift on turn-counter coercion.
|
|
136
|
+
"""
|
|
137
|
+
if not sentinel.is_file():
|
|
138
|
+
return []
|
|
139
|
+
try:
|
|
140
|
+
existing = json.loads(sentinel.read_text(encoding="utf-8"))
|
|
141
|
+
except (OSError, json.JSONDecodeError, ValueError):
|
|
142
|
+
return []
|
|
143
|
+
if not isinstance(existing, dict):
|
|
144
|
+
return []
|
|
145
|
+
if not matches_current_turn(existing, tid, tc):
|
|
146
|
+
return []
|
|
147
|
+
tools_used = existing.get("tools_used")
|
|
148
|
+
if not isinstance(tools_used, list):
|
|
149
|
+
return []
|
|
150
|
+
return tools_used
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def _merge_tools_used(existing: list, family: str) -> list:
|
|
154
|
+
"""Append `family` to `existing`, deduped, preserving first-seen order."""
|
|
155
|
+
if family in existing:
|
|
156
|
+
return list(existing)
|
|
157
|
+
return list(existing) + [family]
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def _test_delay() -> None:
|
|
161
|
+
"""Test-only injection point: sleep inside the locked read-merge-write
|
|
162
|
+
section when `CODE_INTELLIGENCE_TURN_MARK_TEST_DELAY_MS` is set,
|
|
163
|
+
widening the race window so a concurrency test can deterministically
|
|
164
|
+
force two hook invocations to overlap on the same sentinel rather than
|
|
165
|
+
relying on real-world timing luck. Unset in production; a bad/missing
|
|
166
|
+
value is a no-op (fail-open)."""
|
|
167
|
+
delay_ms = os.environ.get("CODE_INTELLIGENCE_TURN_MARK_TEST_DELAY_MS")
|
|
168
|
+
if not delay_ms:
|
|
169
|
+
return
|
|
170
|
+
try:
|
|
171
|
+
time.sleep(int(delay_ms) / 1000)
|
|
172
|
+
except (ValueError, OSError):
|
|
173
|
+
pass
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
@contextlib.contextmanager
|
|
177
|
+
def _sentinel_lock(sentinel: Path):
|
|
178
|
+
"""Exclusive advisory lock held for the full read-merge-write cycle.
|
|
179
|
+
|
|
180
|
+
Prevents the lost-update race where two concurrent PostToolUse
|
|
181
|
+
invocations (e.g. two MCP tool calls firing in quick succession) both
|
|
182
|
+
read the same stale `tools_used` list, merge in different families, and
|
|
183
|
+
one write clobbers the other's update. `fcntl.flock` on POSIX,
|
|
184
|
+
`msvcrt.locking` on Windows (this repo's hooks target both — see the
|
|
185
|
+
Windows note on `_write_sentinel_atomic`'s tempfile+rename above).
|
|
186
|
+
|
|
187
|
+
Fail-open: any failure to open/lock the lock file — missing `fcntl` and
|
|
188
|
+
`msvcrt` both, or an `OSError` opening it — falls through to running the
|
|
189
|
+
critical section unlocked rather than raising. A lost-update race under
|
|
190
|
+
that fallback is strictly worse than today's behavior (already racy)
|
|
191
|
+
but a crash is not; this hook is a nudge dependency, never a gate.
|
|
192
|
+
"""
|
|
193
|
+
lock_path = sentinel.parent / (sentinel.name + ".lock")
|
|
194
|
+
try:
|
|
195
|
+
lock_path.parent.mkdir(parents=True, exist_ok=True)
|
|
196
|
+
except OSError:
|
|
197
|
+
yield
|
|
198
|
+
return
|
|
199
|
+
|
|
200
|
+
# The `open()` failure case (fail-open: fall through to an unlocked
|
|
201
|
+
# critical section) has to share this try/except with the whole
|
|
202
|
+
# `with` body rather than wrapping only the open() call, since ruff's
|
|
203
|
+
# SIM115 requires `open()` to appear directly in a `with` statement.
|
|
204
|
+
# Every helper invoked between here and the `yield` already catches
|
|
205
|
+
# its own OSErrors (see _existing_tools_used/_write_sentinel_atomic),
|
|
206
|
+
# so this outer except only ever fires for the open() call itself.
|
|
207
|
+
try:
|
|
208
|
+
with open(lock_path, "a+") as fh:
|
|
209
|
+
locked = False
|
|
210
|
+
try:
|
|
211
|
+
try:
|
|
212
|
+
if fcntl is not None:
|
|
213
|
+
fcntl.flock(fh.fileno(), fcntl.LOCK_EX)
|
|
214
|
+
locked = True
|
|
215
|
+
elif msvcrt is not None:
|
|
216
|
+
fh.seek(0)
|
|
217
|
+
msvcrt.locking(fh.fileno(), msvcrt.LK_LOCK, 1)
|
|
218
|
+
locked = True
|
|
219
|
+
except OSError:
|
|
220
|
+
locked = False
|
|
221
|
+
yield
|
|
222
|
+
finally:
|
|
223
|
+
if locked:
|
|
224
|
+
try:
|
|
225
|
+
if fcntl is not None:
|
|
226
|
+
fcntl.flock(fh.fileno(), fcntl.LOCK_UN)
|
|
227
|
+
elif msvcrt is not None:
|
|
228
|
+
fh.seek(0)
|
|
229
|
+
msvcrt.locking(fh.fileno(), msvcrt.LK_UNLCK, 1)
|
|
230
|
+
except OSError:
|
|
231
|
+
pass
|
|
232
|
+
return
|
|
233
|
+
except OSError:
|
|
234
|
+
pass
|
|
235
|
+
yield
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
def _write_sentinel_atomic(sentinel: Path, payload: dict) -> None:
|
|
239
|
+
"""Atomic write via a tempfile in the same directory + rename.
|
|
240
|
+
|
|
241
|
+
Mirrors the .sh's `mktemp` + `mv -f` pattern so the nudge hook never sees
|
|
242
|
+
a partial JSON. Any failure short-circuits to a silent exit 0.
|
|
243
|
+
"""
|
|
244
|
+
parent = sentinel.parent
|
|
245
|
+
try:
|
|
246
|
+
parent.mkdir(parents=True, exist_ok=True)
|
|
247
|
+
except OSError:
|
|
248
|
+
return
|
|
249
|
+
|
|
250
|
+
# NamedTemporaryFile with delete=False + explicit rename gives us the
|
|
251
|
+
# same atomic-mv semantic on macOS + Linux + Windows Git Bash.
|
|
252
|
+
try:
|
|
253
|
+
fd, tmp_path = tempfile.mkstemp(
|
|
254
|
+
prefix=".code-intelligence-turn-state.",
|
|
255
|
+
dir=str(parent),
|
|
256
|
+
)
|
|
257
|
+
except OSError:
|
|
258
|
+
return
|
|
259
|
+
tmp = Path(tmp_path)
|
|
260
|
+
try:
|
|
261
|
+
# jq -n produces two-space-indented pretty JSON with a trailing
|
|
262
|
+
# newline. Match that byte-for-byte: `json.dumps(..., indent=2)` uses
|
|
263
|
+
# ": " (space after colon) and "," between items — the exact shape jq
|
|
264
|
+
# emits — and we append the trailing `\n` jq always writes.
|
|
265
|
+
body = json.dumps(payload, indent=2)
|
|
266
|
+
with os.fdopen(fd, "w", encoding="utf-8") as fh:
|
|
267
|
+
fh.write(body)
|
|
268
|
+
fh.write("\n")
|
|
269
|
+
os.replace(tmp, sentinel)
|
|
270
|
+
except OSError:
|
|
271
|
+
try:
|
|
272
|
+
tmp.unlink()
|
|
273
|
+
except OSError:
|
|
274
|
+
pass
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
def main() -> int:
|
|
278
|
+
payload = read_stdin_json() or {}
|
|
279
|
+
if not payload:
|
|
280
|
+
return 0
|
|
281
|
+
|
|
282
|
+
tool_name = payload.get("tool_name") or ""
|
|
283
|
+
family = _tool_family(tool_name) if isinstance(tool_name, str) else None
|
|
284
|
+
if family is None:
|
|
285
|
+
return 0
|
|
286
|
+
|
|
287
|
+
transcript_path_str = payload.get("transcript_path") or ""
|
|
288
|
+
if not isinstance(transcript_path_str, str) or not transcript_path_str:
|
|
289
|
+
return 0
|
|
290
|
+
transcript_path = Path(transcript_path_str)
|
|
291
|
+
if not transcript_path.is_file():
|
|
292
|
+
return 0
|
|
293
|
+
|
|
294
|
+
project_dir = Path(os.environ.get("CLAUDE_PROJECT_DIR") or os.getcwd())
|
|
295
|
+
sentinel = project_dir / SENTINEL_RELATIVE_PATH
|
|
296
|
+
|
|
297
|
+
tid = transcript_id(transcript_path_str)
|
|
298
|
+
tc = count_user_lines(transcript_path)
|
|
299
|
+
|
|
300
|
+
with _sentinel_lock(sentinel):
|
|
301
|
+
tools_used = _merge_tools_used(_existing_tools_used(sentinel, tid, tc), family)
|
|
302
|
+
_test_delay()
|
|
303
|
+
_write_sentinel_atomic(
|
|
304
|
+
sentinel,
|
|
305
|
+
{"transcript_id": tid, "turn_counter": tc, "tools_used": tools_used},
|
|
306
|
+
)
|
|
307
|
+
return 0
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
if __name__ == "__main__":
|
|
311
|
+
try:
|
|
312
|
+
sys.exit(main())
|
|
313
|
+
except Exception: # noqa: BLE001 - fail-open by design; this hook is a
|
|
314
|
+
# nudge, never a gate. Matches the module docstring's posture
|
|
315
|
+
# ("Any internal error -> exit 0") and the sibling nudge hook's
|
|
316
|
+
# identical guard.
|
|
317
|
+
sys.exit(0)
|