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,102 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Shared predicate: does a shell command actually RUN Stryker.NET? (#2185)
|
|
3
|
+
|
|
4
|
+
Both C# mutation PreToolUse gates (`mutation_testing_smoke_gate.py` and
|
|
5
|
+
`stryker_xunit_shim_guard.py`) used to decide "is this a Stryker run?" with a
|
|
6
|
+
bare `re.search` over the entire command string — no notion of argument
|
|
7
|
+
position, quoting, or comments. Any command that merely *mentioned* the tool
|
|
8
|
+
name in prose (a `gh issue create --body "..."`, a `grep`, an `echo`, a
|
|
9
|
+
Python comment) was treated as an invocation and blocked.
|
|
10
|
+
|
|
11
|
+
This module parses the command instead of scanning it: tokenize with
|
|
12
|
+
`shlex.shlex(..., punctuation_chars=True)` (posix quoting rules, `&&`/`||`/
|
|
13
|
+
`;`/`|` recognised as their own tokens), split the token stream into
|
|
14
|
+
per-operator segments, and match the tool only in **program position** of a
|
|
15
|
+
segment — `dotnet` with `stryker` as its very next token, a bare
|
|
16
|
+
`dotnet-stryker` token, or the wrapper script (however it's invoked: directly,
|
|
17
|
+
or via an interpreter like `bash <path>` — matched by exact basename, not
|
|
18
|
+
substring, so a quoted prose mention that happens to contain the wrapper's
|
|
19
|
+
name cannot collide with a real path token).
|
|
20
|
+
|
|
21
|
+
Heredoc bodies are stripped before tokenizing (`<<EOF ... EOF` /
|
|
22
|
+
`<<'EOF' ... EOF` / `<<-EOF ... EOF`) — a command that pipes documentation
|
|
23
|
+
prose through a heredoc is the same false-positive shape as a quoted
|
|
24
|
+
argument, just harder for `shlex` to see through structurally.
|
|
25
|
+
|
|
26
|
+
Fails closed: if `shlex` raises (unbalanced quotes it cannot tokenize), fall
|
|
27
|
+
back to the old permissive regex over the raw command rather than silently
|
|
28
|
+
returning False — a malformed command still gets caught rather than sliding
|
|
29
|
+
through unblocked.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
from __future__ import annotations
|
|
33
|
+
|
|
34
|
+
import re
|
|
35
|
+
import shlex
|
|
36
|
+
from pathlib import Path
|
|
37
|
+
|
|
38
|
+
#: Matches only when shlex tokenization itself fails — the pre-#2185
|
|
39
|
+
#: permissive scan, kept as the fail-closed fallback for unparseable input.
|
|
40
|
+
_FALLBACK_TRIGGER = re.compile(
|
|
41
|
+
r"(?:^|[^a-zA-Z0-9])dotnet[ \t-]+stryker(?:\b|$)|csharp[_-]stryker[_-]net[_-]wrapper"
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
#: Shell operators that separate one command segment from the next. `>`/`<`
|
|
45
|
+
#: (redirects) deliberately excluded — they don't start a new program.
|
|
46
|
+
_SEGMENT_OPERATORS = {"&&", "||", ";", "|"}
|
|
47
|
+
|
|
48
|
+
#: A `<<[-]DELIM ... DELIM` heredoc body, DELIM optionally quoted.
|
|
49
|
+
_HEREDOC_RE = re.compile(r"<<-?\s*['\"]?(\w+)['\"]?\n.*?\n\1\b", re.DOTALL)
|
|
50
|
+
|
|
51
|
+
#: The plugin's Stryker.NET wrapper script, matched against a token's
|
|
52
|
+
#: basename — with or without hyphen/underscore separators, with or without
|
|
53
|
+
#: the `.sh` extension (mirrors the two gates' previously-divergent forms).
|
|
54
|
+
_WRAPPER_NAME_RE = re.compile(r"^csharp[_-]stryker[_-]net[_-]wrapper(\.sh)?$")
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def _strip_heredocs(command: str) -> str:
|
|
58
|
+
return _HEREDOC_RE.sub("", command)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _segments(tokens: list[str]) -> list[list[str]]:
|
|
62
|
+
segments: list[list[str]] = [[]]
|
|
63
|
+
for tok in tokens:
|
|
64
|
+
if tok in _SEGMENT_OPERATORS:
|
|
65
|
+
segments.append([])
|
|
66
|
+
else:
|
|
67
|
+
segments[-1].append(tok)
|
|
68
|
+
return [seg for seg in segments if seg]
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def _segment_is_stryker(segment: list[str]) -> bool:
|
|
72
|
+
if not segment:
|
|
73
|
+
return False
|
|
74
|
+
first = segment[0]
|
|
75
|
+
if first == "dotnet" and len(segment) > 1 and segment[1] == "stryker":
|
|
76
|
+
return True
|
|
77
|
+
if first == "dotnet-stryker":
|
|
78
|
+
return True
|
|
79
|
+
# The wrapper, invoked directly or via an interpreter (`bash <path>`,
|
|
80
|
+
# `sh <path>`) — only the program and its immediate first argument can
|
|
81
|
+
# be the wrapper path, so later arguments are never checked.
|
|
82
|
+
for tok in segment[:2]:
|
|
83
|
+
if _WRAPPER_NAME_RE.match(Path(tok).name):
|
|
84
|
+
return True
|
|
85
|
+
return False
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def is_stryker_invocation(command: str) -> bool:
|
|
89
|
+
"""True only when `command` actually runs Stryker.NET — `dotnet stryker`,
|
|
90
|
+
`dotnet-stryker`, or the plugin's wrapper script, in program position of
|
|
91
|
+
one of the command's operator-separated segments. A mention of the tool
|
|
92
|
+
name in a --body/grep/echo/comment argument does not count."""
|
|
93
|
+
if not command:
|
|
94
|
+
return False
|
|
95
|
+
stripped = _strip_heredocs(command)
|
|
96
|
+
try:
|
|
97
|
+
lexer = shlex.shlex(stripped, posix=True, punctuation_chars=True)
|
|
98
|
+
lexer.whitespace_split = True
|
|
99
|
+
tokens = list(lexer)
|
|
100
|
+
except ValueError:
|
|
101
|
+
return bool(_FALLBACK_TRIGGER.search(command))
|
|
102
|
+
return any(_segment_is_stryker(seg) for seg in _segments(tokens))
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"""telemetry_consent.py — shared, home-scoped telemetry consent check (#1405).
|
|
2
|
+
|
|
3
|
+
Single source of truth for whether the user has opted in to the plugin's
|
|
4
|
+
local telemetry writers. Reads **only** `~/.claude/telemetry.json` —
|
|
5
|
+
deliberately no environment-variable branch and no project-scoped
|
|
6
|
+
(`<cwd>/.claude/telemetry.json`) fallback. Consent is a user-level decision,
|
|
7
|
+
not a per-project or per-invocation one.
|
|
8
|
+
|
|
9
|
+
Fail-open: a missing file, a malformed file, or any read error is treated as
|
|
10
|
+
"not enabled" — never raises, never blocks the calling hook.
|
|
11
|
+
|
|
12
|
+
Stdlib only. See ADR 0014 / ADR 0015.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import json
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _consent_path() -> Path:
|
|
22
|
+
return Path.home() / ".claude" / "telemetry.json"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def is_enabled() -> bool:
|
|
26
|
+
"""Return True only when `~/.claude/telemetry.json` contains
|
|
27
|
+
`{"enabled": true}`. Any other state — file absent, malformed JSON,
|
|
28
|
+
`"enabled"` false or missing, or a read error — returns False."""
|
|
29
|
+
config = _consent_path()
|
|
30
|
+
try:
|
|
31
|
+
if not config.is_file():
|
|
32
|
+
return False
|
|
33
|
+
data = json.loads(config.read_text(encoding="utf-8"))
|
|
34
|
+
except (OSError, ValueError):
|
|
35
|
+
return False
|
|
36
|
+
if not isinstance(data, dict):
|
|
37
|
+
return False
|
|
38
|
+
# Deliberate strict identity check (`is True`, not truthiness): a
|
|
39
|
+
# non-bool value such as `"true"` or `1` must NOT imply consent — only
|
|
40
|
+
# the literal JSON boolean `true` does.
|
|
41
|
+
return data.get("enabled") is True
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Telemetry report (issues #106, #135).
|
|
3
|
+
|
|
4
|
+
Aggregates the opt-in, privacy-clean event log written by hooks/telemetry.py
|
|
5
|
+
(~/.claude/metrics/telemetry.jsonl, home-scoped per #1405/#1406 Slice 1) into:
|
|
6
|
+
command usage counts, skill usage counts (including agent-/auto-invoked
|
|
7
|
+
skills, counted distinctly from user-typed commands — #135), and the
|
|
8
|
+
pre-commit review gate's bypass rate (bypassed / (fired + bypassed)). With
|
|
9
|
+
telemetry disabled the log doesn't exist and this reports that nothing was
|
|
10
|
+
collected — satisfying "with it disabled, nothing leaves the machine."
|
|
11
|
+
|
|
12
|
+
Usage: telemetry_report.py [--log ~/.claude/metrics/telemetry.jsonl] [--json]
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import argparse
|
|
18
|
+
import json
|
|
19
|
+
import sys
|
|
20
|
+
from collections import Counter
|
|
21
|
+
from pathlib import Path
|
|
22
|
+
|
|
23
|
+
_DEFAULT_LOG = Path.home() / ".claude" / "metrics" / "telemetry.jsonl"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def aggregate(log: Path) -> dict:
|
|
27
|
+
commands: Counter = Counter()
|
|
28
|
+
skills: Counter = Counter()
|
|
29
|
+
gate_by_name: dict[str, Counter] = {}
|
|
30
|
+
total_events = 0
|
|
31
|
+
for line in log.read_text().splitlines():
|
|
32
|
+
line = line.strip()
|
|
33
|
+
if not line:
|
|
34
|
+
continue
|
|
35
|
+
try:
|
|
36
|
+
e = json.loads(line)
|
|
37
|
+
except json.JSONDecodeError:
|
|
38
|
+
continue
|
|
39
|
+
total_events += 1
|
|
40
|
+
if e.get("event") == "command":
|
|
41
|
+
commands[e.get("name", "?")] += 1
|
|
42
|
+
elif e.get("event") == "skill":
|
|
43
|
+
skills[e.get("name", "?")] += 1
|
|
44
|
+
elif e.get("event") == "gate":
|
|
45
|
+
name = e.get("name", "?")
|
|
46
|
+
gate_by_name.setdefault(name, Counter())[e.get("outcome", "?")] += 1
|
|
47
|
+
|
|
48
|
+
gate_summary = {}
|
|
49
|
+
for name, oc in gate_by_name.items():
|
|
50
|
+
fired = oc.get("fired", 0)
|
|
51
|
+
bypassed = oc.get("bypassed", 0)
|
|
52
|
+
denom = fired + bypassed
|
|
53
|
+
gate_summary[name] = {
|
|
54
|
+
"fired": fired,
|
|
55
|
+
"bypassed": bypassed,
|
|
56
|
+
"bypass_rate": round(bypassed / denom, 4) if denom else 0.0,
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
"total_events": total_events,
|
|
60
|
+
"command_usage": dict(commands.most_common()),
|
|
61
|
+
"skill_usage": dict(skills.most_common()),
|
|
62
|
+
"gates": gate_summary,
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def main(argv: list[str]) -> int:
|
|
67
|
+
ap = argparse.ArgumentParser(description=__doc__)
|
|
68
|
+
ap.add_argument("--log", default=str(_DEFAULT_LOG))
|
|
69
|
+
ap.add_argument("--json", action="store_true")
|
|
70
|
+
args = ap.parse_args(argv)
|
|
71
|
+
|
|
72
|
+
log = Path(args.log)
|
|
73
|
+
if not log.is_file():
|
|
74
|
+
print("Telemetry is off (or no events recorded): "
|
|
75
|
+
f"{log} does not exist. Nothing has left the machine.")
|
|
76
|
+
return 0
|
|
77
|
+
|
|
78
|
+
summary = aggregate(log)
|
|
79
|
+
if args.json:
|
|
80
|
+
print(json.dumps(summary, indent=2))
|
|
81
|
+
return 0
|
|
82
|
+
|
|
83
|
+
print(f"# Telemetry report — {summary['total_events']} event(s)\n")
|
|
84
|
+
print("## Command usage (user-typed slash commands)")
|
|
85
|
+
if summary["command_usage"]:
|
|
86
|
+
for name, n in summary["command_usage"].items():
|
|
87
|
+
print(f" /{name}: {n}")
|
|
88
|
+
else:
|
|
89
|
+
print(" (none)")
|
|
90
|
+
print("\n## Skill usage (incl. agent-/auto-invoked)")
|
|
91
|
+
if summary["skill_usage"]:
|
|
92
|
+
for name, n in summary["skill_usage"].items():
|
|
93
|
+
print(f" {name}: {n}")
|
|
94
|
+
else:
|
|
95
|
+
print(" (none)")
|
|
96
|
+
print("\n## Gate bypass rates")
|
|
97
|
+
if summary["gates"]:
|
|
98
|
+
for name, g in summary["gates"].items():
|
|
99
|
+
print(f" {name}: {g['bypassed']} bypassed / "
|
|
100
|
+
f"{g['fired'] + g['bypassed']} attempts "
|
|
101
|
+
f"({g['bypass_rate'] * 100:.1f}% bypassed)")
|
|
102
|
+
else:
|
|
103
|
+
print(" (none)")
|
|
104
|
+
return 0
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
if __name__ == "__main__":
|
|
108
|
+
raise SystemExit(main(sys.argv[1:]))
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
"""test_file_classify — shared test-file classifier + build-phase reader.
|
|
2
|
+
|
|
3
|
+
Single encoding of `knowledge/test-file-indicators.md` for hooks that need to
|
|
4
|
+
decide "is this a test file?" (the refactor test-freeze guards), plus the
|
|
5
|
+
reader for the build-phase state `/build` records at each step-phase
|
|
6
|
+
transition (`.claude/memory/build-phase.json`).
|
|
7
|
+
|
|
8
|
+
Stdlib-only. See docs/python-hook-contract.md.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import json
|
|
14
|
+
import re
|
|
15
|
+
import sys
|
|
16
|
+
import time
|
|
17
|
+
from datetime import datetime, timezone
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
|
|
20
|
+
_LIB_DIR = Path(__file__).resolve().parent
|
|
21
|
+
if str(_LIB_DIR) not in sys.path:
|
|
22
|
+
sys.path.insert(0, str(_LIB_DIR))
|
|
23
|
+
|
|
24
|
+
import artifact_paths
|
|
25
|
+
|
|
26
|
+
#: memory/build-phase.json older than this is treated as absent — a crashed
|
|
27
|
+
#: build must not freeze tests forever.
|
|
28
|
+
STALE_AFTER_SECONDS = 4 * 60 * 60
|
|
29
|
+
|
|
30
|
+
_JS_TS_NAME_RE = re.compile(r"\.(test|spec)\.[^./]+$", re.IGNORECASE)
|
|
31
|
+
_STEP_DEF_RE = re.compile(r"(\.steps\.[^./]+$|StepDefinitions\.[^./]+$|Steps\.[^./]+$)")
|
|
32
|
+
_CSHARP_MARKER_RE = re.compile(r"\[(Fact|Theory|Test|TestCase|TestMethod|TestClass)\]")
|
|
33
|
+
_JAVA_MARKER_RE = re.compile(r"@(Test|ParameterizedTest|TestFactory)\b")
|
|
34
|
+
_JAVA_CLASS_SUFFIXES = ("Test", "Tests", "TestCase", "Spec")
|
|
35
|
+
_PYTHON_NAME_RE = re.compile(r"^(test_.+|.+_test)\.py$", re.IGNORECASE)
|
|
36
|
+
|
|
37
|
+
#: How much of a file to read when a content probe is needed.
|
|
38
|
+
_CONTENT_PROBE_BYTES = 256 * 1024
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _read_probe(path: Path) -> str:
|
|
42
|
+
try:
|
|
43
|
+
with open(path, "r", encoding="utf-8", errors="replace") as handle:
|
|
44
|
+
return handle.read(_CONTENT_PROBE_BYTES)
|
|
45
|
+
except OSError:
|
|
46
|
+
return ""
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def is_test_file(path: str, content: str | None = None) -> bool:
|
|
50
|
+
"""True when `path` is a test file per knowledge/test-file-indicators.md.
|
|
51
|
+
|
|
52
|
+
`content` overrides the on-disk read for the languages whose indicator is
|
|
53
|
+
content-based (C#, Java) — pass it in tests or when the file is not on
|
|
54
|
+
disk yet (a PreToolUse Write).
|
|
55
|
+
"""
|
|
56
|
+
if not path:
|
|
57
|
+
return False
|
|
58
|
+
p = Path(path)
|
|
59
|
+
name = p.name
|
|
60
|
+
posix = p.as_posix()
|
|
61
|
+
|
|
62
|
+
# BDD/Gherkin — a .feature file always counts as a test file.
|
|
63
|
+
if name.lower().endswith(".feature"):
|
|
64
|
+
return True
|
|
65
|
+
if _STEP_DEF_RE.search(name):
|
|
66
|
+
return True
|
|
67
|
+
|
|
68
|
+
# JS/TS — *.test.*, *.spec.*, or inside __tests__/
|
|
69
|
+
if _JS_TS_NAME_RE.search(name):
|
|
70
|
+
return True
|
|
71
|
+
if "/__tests__/" in posix or posix.startswith("__tests__/"):
|
|
72
|
+
return True
|
|
73
|
+
|
|
74
|
+
# Python — test_*.py or *_test.py (pytest/unittest convention).
|
|
75
|
+
if _PYTHON_NAME_RE.match(name):
|
|
76
|
+
return True
|
|
77
|
+
|
|
78
|
+
suffix = p.suffix.lower()
|
|
79
|
+
if suffix == ".cs":
|
|
80
|
+
probe = content if content is not None else _read_probe(p)
|
|
81
|
+
return bool(_CSHARP_MARKER_RE.search(probe))
|
|
82
|
+
|
|
83
|
+
if suffix == ".java":
|
|
84
|
+
if p.stem.endswith(_JAVA_CLASS_SUFFIXES):
|
|
85
|
+
return True
|
|
86
|
+
probe = content if content is not None else _read_probe(p)
|
|
87
|
+
return bool(_JAVA_MARKER_RE.search(probe))
|
|
88
|
+
|
|
89
|
+
return False
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def _parse_written_at(value: str) -> float | None:
|
|
93
|
+
"""ISO-8601 → epoch seconds, tolerant of a trailing 'Z'. None when unparseable."""
|
|
94
|
+
if not isinstance(value, str) or not value:
|
|
95
|
+
return None
|
|
96
|
+
candidate = value.strip()
|
|
97
|
+
if candidate.endswith("Z"):
|
|
98
|
+
candidate = candidate[:-1] + "+00:00"
|
|
99
|
+
try:
|
|
100
|
+
parsed = datetime.fromisoformat(candidate)
|
|
101
|
+
except ValueError:
|
|
102
|
+
return None
|
|
103
|
+
if parsed.tzinfo is None:
|
|
104
|
+
parsed = parsed.replace(tzinfo=timezone.utc)
|
|
105
|
+
return parsed.timestamp()
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def build_phase_path(project_dir: Path) -> Path:
|
|
109
|
+
# Read-only: no Python writer of build-phase.json exists anywhere in
|
|
110
|
+
# hooks/ — it is agent-instruction-written (build/SKILL.md). migrate=False
|
|
111
|
+
# so this read never migrates a legacy file or creates .claude/memory/ as
|
|
112
|
+
# a side effect.
|
|
113
|
+
return artifact_paths.resolve_file(
|
|
114
|
+
"memory", "build-phase.json", project_dir, migrate=False
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def read_build_phase(
|
|
119
|
+
project_dir: Path, now: float | None = None
|
|
120
|
+
) -> tuple[dict | None, str | None]:
|
|
121
|
+
"""Read `memory/build-phase.json`. Returns `(state, error)`.
|
|
122
|
+
|
|
123
|
+
- `(None, None)` — no state recorded, or the state is stale
|
|
124
|
+
(> STALE_AFTER_SECONDS old): guards treat both as "no phase".
|
|
125
|
+
- `(None, <why>)` — the file exists but is unreadable or malformed:
|
|
126
|
+
guards fail OPEN and record the reason in the audit log.
|
|
127
|
+
- `(state, None)` — an active, fresh phase record. `state["phase"]` is a
|
|
128
|
+
string; `state["test_files_staged"]` is always a list of strings.
|
|
129
|
+
|
|
130
|
+
`now` is the injectable clock (epoch seconds) for staleness tests.
|
|
131
|
+
"""
|
|
132
|
+
path = build_phase_path(project_dir)
|
|
133
|
+
if not path.is_file():
|
|
134
|
+
return None, None
|
|
135
|
+
try:
|
|
136
|
+
raw = path.read_text(encoding="utf-8")
|
|
137
|
+
except OSError as exc:
|
|
138
|
+
return None, f"unreadable build-phase state: {exc}"
|
|
139
|
+
try:
|
|
140
|
+
data = json.loads(raw)
|
|
141
|
+
except ValueError:
|
|
142
|
+
return None, "malformed build-phase state: invalid JSON"
|
|
143
|
+
if not isinstance(data, dict):
|
|
144
|
+
return None, "malformed build-phase state: not an object"
|
|
145
|
+
phase = data.get("phase")
|
|
146
|
+
if not isinstance(phase, str) or not phase:
|
|
147
|
+
return None, "malformed build-phase state: missing phase"
|
|
148
|
+
written_at = _parse_written_at(data.get("written_at", ""))
|
|
149
|
+
if written_at is None:
|
|
150
|
+
return None, "malformed build-phase state: missing/unparseable written_at"
|
|
151
|
+
current = time.time() if now is None else now
|
|
152
|
+
if current - written_at > STALE_AFTER_SECONDS:
|
|
153
|
+
return None, None
|
|
154
|
+
staged = data.get("test_files_staged", [])
|
|
155
|
+
if not isinstance(staged, list):
|
|
156
|
+
return None, "malformed build-phase state: test_files_staged not a list"
|
|
157
|
+
files: list[str] = [f for f in staged if isinstance(f, str) and f]
|
|
158
|
+
state = dict(data)
|
|
159
|
+
state["test_files_staged"] = files
|
|
160
|
+
return state, None
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""token_efficiency_limits — shared thresholds for token-efficiency checks.
|
|
3
|
+
|
|
4
|
+
Single source of truth for the limits enforced by both
|
|
5
|
+
`hooks/token_efficiency_review.py` (the shipped PostToolUse hook) and
|
|
6
|
+
`plugins/dev-team/scripts/token_efficiency_review.py` (the review-agent CI runner). Both
|
|
7
|
+
previously hardcoded their own copy of these numbers.
|
|
8
|
+
|
|
9
|
+
It is also the single source of truth for two small pieces of *logic* that
|
|
10
|
+
drifted between those same two callers: which filename counts as "CLAUDE.md"
|
|
11
|
+
and how "character count" is measured. The hook used to match only the exact
|
|
12
|
+
case `CLAUDE.md` and count bytes; the CI runner matched case-insensitively
|
|
13
|
+
and counted decoded characters — so the same file could report two different
|
|
14
|
+
counts, or be checked in one caller and silently skipped in the other,
|
|
15
|
+
depending on nothing but its name's casing.
|
|
16
|
+
|
|
17
|
+
Stdlib-only. See docs/python-hook-contract.md.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
from pathlib import Path
|
|
23
|
+
|
|
24
|
+
# CLAUDE.md character-count limit (advisory in the hook, hard error in CI).
|
|
25
|
+
CLAUDE_MD_CHAR_LIMIT: int = 5000
|
|
26
|
+
|
|
27
|
+
# Any tracked source/CLAUDE.md file's line-count limit.
|
|
28
|
+
FILE_LINE_LIMIT: int = 500
|
|
29
|
+
|
|
30
|
+
# CLAUDE.md rule-count limit. Lives here rather than as a local literal in the
|
|
31
|
+
# CI runner (#1651) so this module's "single source of truth" claim above is
|
|
32
|
+
# true of every limit, not just the two that happened to be duplicated when it
|
|
33
|
+
# was written. Only the CI runner reads it today — the shipped hook does not
|
|
34
|
+
# count rules — but a second reader is exactly how the other two limits drifted
|
|
35
|
+
# into needing this module in the first place.
|
|
36
|
+
CLAUDE_MD_RULE_LIMIT: int = 200
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def is_claude_md_file(path: Path) -> bool:
|
|
40
|
+
"""Return True when `path`'s filename is CLAUDE.md, case-insensitively."""
|
|
41
|
+
return path.name.lower() == "claude.md"
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def char_count(path: Path) -> int:
|
|
45
|
+
"""Return the decoded character count of `path`.
|
|
46
|
+
|
|
47
|
+
Character count, not byte count: `CLAUDE_MD_CHAR_LIMIT` is a token-budget
|
|
48
|
+
proxy, and decoded characters track token count far more closely than
|
|
49
|
+
bytes do for any file containing multi-byte UTF-8 sequences.
|
|
50
|
+
"""
|
|
51
|
+
return len(path.read_text(encoding="utf-8", errors="replace"))
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"""turn_identity — shared transcript/turn identity helpers.
|
|
2
|
+
|
|
3
|
+
Extracted from the tail-window logic that used to live independently in
|
|
4
|
+
both `codegraph_nudge.py` (read side) and `codegraph_turn_mark.py` (write
|
|
5
|
+
side) — the latter's own docstring already flagged this exact duplication
|
|
6
|
+
as intended for a "future PR." Both hooks now import from here so the
|
|
7
|
+
transcript_id/turn_counter computation can't drift between the two sides
|
|
8
|
+
of the sentinel contract.
|
|
9
|
+
|
|
10
|
+
Stdlib-only.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import os
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
|
|
18
|
+
# Same 1 MiB tail window both hooks applied independently before this
|
|
19
|
+
# extraction — a monotonically growing transcript stays O(1) per read.
|
|
20
|
+
_TAIL_WINDOW_BYTES = 1_048_576
|
|
21
|
+
|
|
22
|
+
_USER_LINE_MARKER = b'"type":"user"'
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def transcript_id(path: str) -> str:
|
|
26
|
+
"""basename(path) with the last extension stripped.
|
|
27
|
+
|
|
28
|
+
`Path.stem` matches the shapes the harness emits (`.jsonl`, `.json`,
|
|
29
|
+
no extension).
|
|
30
|
+
"""
|
|
31
|
+
return Path(path).stem
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def count_user_lines(transcript_path: Path) -> int:
|
|
35
|
+
"""Count `"type":"user"` occurrences in the last 1 MiB of the transcript.
|
|
36
|
+
|
|
37
|
+
Errors -> 0 (fail-open). Reads a bounded tail so growing transcripts
|
|
38
|
+
don't turn every call into a full-file scan.
|
|
39
|
+
"""
|
|
40
|
+
try:
|
|
41
|
+
with transcript_path.open("rb") as fh:
|
|
42
|
+
fh.seek(0, os.SEEK_END)
|
|
43
|
+
size = fh.tell()
|
|
44
|
+
offset = max(0, size - _TAIL_WINDOW_BYTES)
|
|
45
|
+
fh.seek(offset, os.SEEK_SET)
|
|
46
|
+
tail = fh.read()
|
|
47
|
+
except OSError:
|
|
48
|
+
return 0
|
|
49
|
+
return tail.count(_USER_LINE_MARKER)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
# Single source of truth for the sentinel's location relative to the
|
|
53
|
+
# project dir — both code_intelligence_nudge.py (read side) and
|
|
54
|
+
# code_intelligence_turn_mark.py (write side) used to hardcode this
|
|
55
|
+
# path independently.
|
|
56
|
+
SENTINEL_RELATIVE_PATH = Path(".claude") / "code-intelligence-turn-state.json"
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def matches_current_turn(sentinel: dict, tid: str, tc: int) -> bool:
|
|
60
|
+
"""True when `sentinel`'s identity fields match the freshly computed
|
|
61
|
+
transcript_id/turn_counter for the current call — i.e. the sentinel was
|
|
62
|
+
written earlier in the *same* turn.
|
|
63
|
+
|
|
64
|
+
Owns the type coercion once for both sides of the sentinel contract:
|
|
65
|
+
`transcript_id` is compared as a string (coercing a missing/`None`
|
|
66
|
+
value to `""`), and `turn_counter` is compared via `int()` wrapped in a
|
|
67
|
+
try/except — a non-numeric or otherwise uncoercible value (corrupt
|
|
68
|
+
sentinel) resolves to `False` rather than raising, matching this
|
|
69
|
+
module's fail-open posture.
|
|
70
|
+
"""
|
|
71
|
+
sentinel_tid = str(sentinel.get("transcript_id") or "")
|
|
72
|
+
if sentinel_tid != tid:
|
|
73
|
+
return False
|
|
74
|
+
try:
|
|
75
|
+
return int(sentinel.get("turn_counter")) == tc
|
|
76
|
+
except (TypeError, ValueError):
|
|
77
|
+
return False
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
"""Shared per-session state helpers for verify_guard.py and
|
|
2
|
+
verify_guard_edit_marker.py (#708).
|
|
3
|
+
|
|
4
|
+
verify_guard.py (PreToolUse `Bash`) needs to tell a genuinely stuck loop
|
|
5
|
+
(the same verify command run over and over with zero intervening code
|
|
6
|
+
changes) apart from ordinary TDD re-verification (RED, GREEN, REFACTOR
|
|
7
|
+
each legitimately re-run the same command, but each preceded by a real
|
|
8
|
+
edit). The two hooks communicate that signal through one JSON state file
|
|
9
|
+
per session, keyed identically by both hooks — so this module exists to
|
|
10
|
+
make sure "identically" is actually true, rather than two independently
|
|
11
|
+
maintained copies of the same hashing/keying logic drifting apart.
|
|
12
|
+
|
|
13
|
+
State shape (JSON object): ``{"hash": str, "count": int, "edited": bool}``.
|
|
14
|
+
``hash`` and ``count`` are verify_guard.py's consecutive-identical-command
|
|
15
|
+
counter; ``edited`` is set true by verify_guard_edit_marker.py whenever an
|
|
16
|
+
Edit/Write/NotebookEdit tool call is observed, and consumed (reset to
|
|
17
|
+
false) by verify_guard.py on its next run.
|
|
18
|
+
|
|
19
|
+
Stdlib-only. See docs/python-hook-contract.md.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
from __future__ import annotations
|
|
23
|
+
|
|
24
|
+
import json
|
|
25
|
+
import os
|
|
26
|
+
import tempfile
|
|
27
|
+
import time
|
|
28
|
+
import zlib
|
|
29
|
+
from pathlib import Path
|
|
30
|
+
|
|
31
|
+
_STATE_DIRNAME = "dev-team-verify-guard"
|
|
32
|
+
|
|
33
|
+
# Same TTL-purge-on-write pattern as tdd_guard.py / mutation_adapters/lib.py
|
|
34
|
+
# (#732) — one state file is written per session with no expiry otherwise,
|
|
35
|
+
# so long-lived hosts accumulate a file per session forever.
|
|
36
|
+
_STATE_TTL_SECONDS = 14400 # 4 hours
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def cksum(text: str) -> str:
|
|
40
|
+
"""In-process, deterministic hash used for state-key/hash purposes.
|
|
41
|
+
|
|
42
|
+
The bash-parity `cksum` shell-out this used to require is gone (the
|
|
43
|
+
.sh implementations were removed — ADR 0015 / epic #572); only that
|
|
44
|
+
both hooks hash the same way matters, so the state key/hash they
|
|
45
|
+
compute for the same session agrees — hence the shared helper rather
|
|
46
|
+
than two copies. Uses zlib.crc32, matching bash_retry_guard.py's own
|
|
47
|
+
`_cksum` exactly so checksums stay comparable if anything ever
|
|
48
|
+
persists/compares both.
|
|
49
|
+
"""
|
|
50
|
+
return str(zlib.crc32(text.encode("utf-8")) & 0xFFFFFFFF)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def tmpdir() -> Path:
|
|
54
|
+
return Path(os.environ.get("TMPDIR") or tempfile.gettempdir() or "/tmp")
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def state_dir() -> Path:
|
|
58
|
+
return tmpdir() / _STATE_DIRNAME
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def state_key(session_id: str, cwd: str) -> str:
|
|
62
|
+
"""Prefer session_id, fall back to cksum of cwd (or $PWD when both empty)."""
|
|
63
|
+
if session_id:
|
|
64
|
+
return session_id
|
|
65
|
+
return cksum(cwd or os.getcwd())
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def state_file(key: str) -> Path:
|
|
69
|
+
return state_dir() / f"{key}.json"
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def read_state(path: Path) -> dict:
|
|
73
|
+
if not path.is_file():
|
|
74
|
+
return {}
|
|
75
|
+
try:
|
|
76
|
+
data = json.loads(path.read_text())
|
|
77
|
+
except (OSError, json.JSONDecodeError, ValueError):
|
|
78
|
+
return {}
|
|
79
|
+
return data if isinstance(data, dict) else {}
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def purge_stale(directory: Path) -> None:
|
|
83
|
+
"""Delete `*.json` state files in `directory` untouched past the TTL.
|
|
84
|
+
|
|
85
|
+
Both verify_guard.py and verify_guard_edit_marker.py write through
|
|
86
|
+
`write_state`, so calling this there is the single choke point that
|
|
87
|
+
keeps the shared state dir from accumulating one file per session
|
|
88
|
+
forever (#732).
|
|
89
|
+
"""
|
|
90
|
+
if not directory.is_dir():
|
|
91
|
+
return
|
|
92
|
+
now = time.time()
|
|
93
|
+
for path in directory.glob("*.json"):
|
|
94
|
+
try:
|
|
95
|
+
if now - path.stat().st_mtime > _STATE_TTL_SECONDS:
|
|
96
|
+
path.unlink()
|
|
97
|
+
except OSError:
|
|
98
|
+
pass
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def write_state(path: Path, data: dict) -> None:
|
|
102
|
+
try:
|
|
103
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
104
|
+
except OSError:
|
|
105
|
+
return
|
|
106
|
+
purge_stale(path.parent)
|
|
107
|
+
try:
|
|
108
|
+
path.write_text(json.dumps(data, separators=(",", ":")) + "\n")
|
|
109
|
+
except OSError:
|
|
110
|
+
pass
|