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.
Files changed (780) hide show
  1. package/LICENSE +21 -0
  2. package/PORTING.md +134 -0
  3. package/README.md +207 -0
  4. package/UPSTREAM.json +64 -0
  5. package/agents/Explore.md +15 -0
  6. package/agents/a11y-review.md +118 -0
  7. package/agents/adr-author.md +70 -0
  8. package/agents/ai-provenance-review.md +120 -0
  9. package/agents/angular-reactivity-review.md +95 -0
  10. package/agents/arch-review.md +135 -0
  11. package/agents/architect.md +78 -0
  12. package/agents/autoship-batch-proposer.md +69 -0
  13. package/agents/claude-setup-review.md +136 -0
  14. package/agents/codebase-recon.md +184 -0
  15. package/agents/component-architecture-review.md +119 -0
  16. package/agents/concurrency-review.md +109 -0
  17. package/agents/correctness-review.md +290 -0
  18. package/agents/data-flow-tracer.md +120 -0
  19. package/agents/doc-review.md +165 -0
  20. package/agents/domain-review.md +136 -0
  21. package/agents/general-purpose.md +10 -0
  22. package/agents/gherkin-quality-critic.md +113 -0
  23. package/agents/js-fp-review.md +114 -0
  24. package/agents/mutation-kill.md +684 -0
  25. package/agents/naming-review.md +142 -0
  26. package/agents/orchestrator.md +339 -0
  27. package/agents/performance-review.md +105 -0
  28. package/agents/plan-review-acceptance.md +115 -0
  29. package/agents/plan-review-design.md +90 -0
  30. package/agents/plan-review-parallelization.md +84 -0
  31. package/agents/plan-review-strategic.md +96 -0
  32. package/agents/plan-review-ux.md +110 -0
  33. package/agents/platform-engineer.md +64 -0
  34. package/agents/product-manager.md +68 -0
  35. package/agents/progress-guardian.md +79 -0
  36. package/agents/qa-engineer.md +289 -0
  37. package/agents/quality-reviewer.md +132 -0
  38. package/agents/react-reactivity-review.md +102 -0
  39. package/agents/refactor-opportunity-review.md +128 -0
  40. package/agents/security-engineer.md +60 -0
  41. package/agents/security-review.md +218 -0
  42. package/agents/session-analysis.md +95 -0
  43. package/agents/software-engineer.md +105 -0
  44. package/agents/spec-compliance-review.md +100 -0
  45. package/agents/spec-reviewer.md +114 -0
  46. package/agents/structure-review.md +146 -0
  47. package/agents/tech-writer.md +84 -0
  48. package/agents/test-review.md +246 -0
  49. package/agents/test-smell-review.md +188 -0
  50. package/agents/token-efficiency-review.md +139 -0
  51. package/agents/ui-ux-designer.md +54 -0
  52. package/agents/vue-reactivity-review.md +95 -0
  53. package/bin/__pycache__/claudecpython-314.pyc +0 -0
  54. package/bin/claude +258 -0
  55. package/docs/upstream/.pages +1 -0
  56. package/docs/upstream/CHANGELOG.md +2586 -0
  57. package/docs/upstream/README.md +155 -0
  58. package/docs/upstream/agent-architecture.md +214 -0
  59. package/docs/upstream/agent_info.md +187 -0
  60. package/docs/upstream/artifact-migration.md +124 -0
  61. package/docs/upstream/code-intelligence-nudge.md +149 -0
  62. package/docs/upstream/code-review-process.md +294 -0
  63. package/docs/upstream/concurrent-use.md +73 -0
  64. package/docs/upstream/context-management.md +111 -0
  65. package/docs/upstream/developer-notes.md +280 -0
  66. package/docs/upstream/diagrams/architecture-overview.svg +101 -0
  67. package/docs/upstream/diagrams/review-dispatch.svg +139 -0
  68. package/docs/upstream/diagrams/team-agents.svg +128 -0
  69. package/docs/upstream/diagrams/test-improve-flow.svg +166 -0
  70. package/docs/upstream/diagrams/workflow-linear.svg +66 -0
  71. package/docs/upstream/diagrams/workflow-three-phase.svg +200 -0
  72. package/docs/upstream/eval-maintenance.md +95 -0
  73. package/docs/upstream/eval-running-guide.md +147 -0
  74. package/docs/upstream/eval-system.md +291 -0
  75. package/docs/upstream/session-review-oss-complements.md +75 -0
  76. package/docs/upstream/session-review.md +212 -0
  77. package/docs/upstream/skills.md +188 -0
  78. package/docs/upstream/team-structure.md +21 -0
  79. package/docs/upstream/telemetry-ci-access.md +129 -0
  80. package/docs/upstream/telemetry-repo-security.md +120 -0
  81. package/docs/upstream/test-evaluation.md +277 -0
  82. package/docs/upstream/test-improve.md +154 -0
  83. package/docs/upstream/triage-workflow.md +282 -0
  84. package/docs/upstream/workflows.md +289 -0
  85. package/extensions/dev-team/index.ts +539 -0
  86. package/extensions/dev-team/lib/agents.ts +272 -0
  87. package/extensions/dev-team/lib/ai-credits.ts +92 -0
  88. package/extensions/dev-team/lib/autocompact.ts +81 -0
  89. package/extensions/dev-team/lib/child-run.ts +102 -0
  90. package/extensions/dev-team/lib/config.ts +236 -0
  91. package/extensions/dev-team/lib/gh-command.ts +103 -0
  92. package/extensions/dev-team/lib/github-style.ts +307 -0
  93. package/extensions/dev-team/lib/hooks.ts +350 -0
  94. package/extensions/dev-team/lib/metrics.ts +115 -0
  95. package/extensions/dev-team/lib/safe-read.ts +49 -0
  96. package/extensions/dev-team/lib/session-files.ts +57 -0
  97. package/extensions/dev-team/lib/session-spend.ts +123 -0
  98. package/extensions/dev-team/lib/shell-scan.ts +205 -0
  99. package/extensions/dev-team/lib/skills.ts +213 -0
  100. package/extensions/dev-team/lib/subagent-render.ts +245 -0
  101. package/extensions/dev-team/lib/subagent-types.ts +164 -0
  102. package/extensions/dev-team/lib/subagent.ts +596 -0
  103. package/extensions/dev-team/lib/terminal-text.ts +54 -0
  104. package/extensions/dev-team/lib/tools-misc.ts +152 -0
  105. package/extensions/dev-team/lib/transcript.ts +110 -0
  106. package/extensions/dev-team/lib/trust.ts +52 -0
  107. package/extensions/dev-team/lib/usage-breakdown.ts +176 -0
  108. package/extensions/dev-team/lib/usage-chart.ts +153 -0
  109. package/extensions/dev-team/lib/usage-command.ts +107 -0
  110. package/extensions/dev-team/lib/usage-history.ts +203 -0
  111. package/extensions/dev-team/lib/usage-render.ts +225 -0
  112. package/extensions/dev-team/lib/usage-split-bar.ts +127 -0
  113. package/extensions/dev-team/lib/usage-state.ts +116 -0
  114. package/extensions/dev-team/lib/usage-text.ts +159 -0
  115. package/extensions/dev-team/lib/usage-view.ts +109 -0
  116. package/hooks/__pycache__/refactor_test_freeze_guard.cpython-314.pyc +0 -0
  117. package/hooks/agent_dispatch_ledger.py +190 -0
  118. package/hooks/autocompact_setup_nudge.py +99 -0
  119. package/hooks/bash_retry_guard.py +228 -0
  120. package/hooks/boundary_events_write_guard.py +352 -0
  121. package/hooks/code_intelligence_nudge.py +293 -0
  122. package/hooks/code_intelligence_turn_mark.py +317 -0
  123. package/hooks/codegraph_bootstrap.py +139 -0
  124. package/hooks/contract_version_guard.py +362 -0
  125. package/hooks/cost_meter.py +106 -0
  126. package/hooks/destructive-commands.json +62 -0
  127. package/hooks/destructive_guard.py +477 -0
  128. package/hooks/eval_compliance_check.py +440 -0
  129. package/hooks/guards.json +17 -0
  130. package/hooks/hooks.json +323 -0
  131. package/hooks/internal_double_gate.py +296 -0
  132. package/hooks/js_fp_review.py +212 -0
  133. package/hooks/knowledge_index.py +119 -0
  134. package/hooks/lib/__pycache__/artifact_paths.cpython-314.pyc +0 -0
  135. package/hooks/lib/__pycache__/atomic_state.cpython-314.pyc +0 -0
  136. package/hooks/lib/__pycache__/autocompact_config.cpython-314.pyc +0 -0
  137. package/hooks/lib/__pycache__/boundary_events.cpython-314.pyc +0 -0
  138. package/hooks/lib/__pycache__/doc_classification.cpython-314.pyc +0 -0
  139. package/hooks/lib/__pycache__/gh_pr_create_detect.cpython-314.pyc +0 -0
  140. package/hooks/lib/__pycache__/git_safe_diff.cpython-314.pyc +0 -0
  141. package/hooks/lib/__pycache__/instrument_log.cpython-314.pyc +0 -0
  142. package/hooks/lib/__pycache__/metrics_query.cpython-314.pyc +0 -0
  143. package/hooks/lib/__pycache__/plugin_version.cpython-314.pyc +0 -0
  144. package/hooks/lib/__pycache__/pre_commit_doc_classifier.cpython-314.pyc +0 -0
  145. package/hooks/lib/__pycache__/review_agent_registry.cpython-314.pyc +0 -0
  146. package/hooks/lib/__pycache__/review_gate_corroboration.cpython-314.pyc +0 -0
  147. package/hooks/lib/__pycache__/review_gate_hash.cpython-314.pyc +0 -0
  148. package/hooks/lib/__pycache__/review_verdicts.cpython-314.pyc +0 -0
  149. package/hooks/lib/__pycache__/stdin_json.cpython-314.pyc +0 -0
  150. package/hooks/lib/__pycache__/stryker_invocation.cpython-314.pyc +0 -0
  151. package/hooks/lib/__pycache__/telemetry_consent.cpython-314.pyc +0 -0
  152. package/hooks/lib/__pycache__/test_file_classify.cpython-314.pyc +0 -0
  153. package/hooks/lib/__pycache__/token_efficiency_limits.cpython-314.pyc +0 -0
  154. package/hooks/lib/__pycache__/verify_guard_state.cpython-314.pyc +0 -0
  155. package/hooks/lib/__pycache__/xunit_v3_operator_gate.cpython-314.pyc +0 -0
  156. package/hooks/lib/agent_skill_hints.py +74 -0
  157. package/hooks/lib/artifact_paths.py +263 -0
  158. package/hooks/lib/atomic_state.py +557 -0
  159. package/hooks/lib/autocompact_config.py +103 -0
  160. package/hooks/lib/autoship_log.py +106 -0
  161. package/hooks/lib/banned_scripts_policy.py +51 -0
  162. package/hooks/lib/boundary_events.py +436 -0
  163. package/hooks/lib/build_knowledge_index.py +504 -0
  164. package/hooks/lib/build_skills_index.py +361 -0
  165. package/hooks/lib/build_state.py +116 -0
  166. package/hooks/lib/classify_ship_outcome.py +126 -0
  167. package/hooks/lib/config_changelog_schema.py +115 -0
  168. package/hooks/lib/cost_meter.py +955 -0
  169. package/hooks/lib/doc_classification.py +116 -0
  170. package/hooks/lib/gh_pr_create_detect.py +136 -0
  171. package/hooks/lib/git_safe_diff.py +123 -0
  172. package/hooks/lib/instrument_log.py +66 -0
  173. package/hooks/lib/iteration_journal_gate.py +197 -0
  174. package/hooks/lib/knowledge_index_paths.py +88 -0
  175. package/hooks/lib/mcp_json_repowise.py +177 -0
  176. package/hooks/lib/metrics_query.py +202 -0
  177. package/hooks/lib/minimal_yaml.py +434 -0
  178. package/hooks/lib/plugin_version.py +142 -0
  179. package/hooks/lib/pre_commit_detect.py +537 -0
  180. package/hooks/lib/pre_commit_doc_classifier.py +126 -0
  181. package/hooks/lib/pricing.py +118 -0
  182. package/hooks/lib/report_pdf.py +371 -0
  183. package/hooks/lib/review_agent_registry.py +142 -0
  184. package/hooks/lib/review_dispatch_ledger.py +101 -0
  185. package/hooks/lib/review_gate_corroboration.py +521 -0
  186. package/hooks/lib/review_gate_hash.py +252 -0
  187. package/hooks/lib/review_gate_normalized_hash.py +1115 -0
  188. package/hooks/lib/review_verdicts.py +301 -0
  189. package/hooks/lib/run_report.py +160 -0
  190. package/hooks/lib/skill_categories.yaml +125 -0
  191. package/hooks/lib/stdin_json.py +57 -0
  192. package/hooks/lib/stryker_invocation.py +102 -0
  193. package/hooks/lib/telemetry_consent.py +41 -0
  194. package/hooks/lib/telemetry_report.py +108 -0
  195. package/hooks/lib/test_file_classify.py +160 -0
  196. package/hooks/lib/token_efficiency_limits.py +51 -0
  197. package/hooks/lib/turn_identity.py +77 -0
  198. package/hooks/lib/verify_guard_state.py +110 -0
  199. package/hooks/lib/workflow_state.py +206 -0
  200. package/hooks/lib/xunit_v3_operator_gate.py +596 -0
  201. package/hooks/mcp_json_repowise_nudge.py +74 -0
  202. package/hooks/mutation_adapters/__init__.py +7 -0
  203. package/hooks/mutation_adapters/__pycache__/__init__.cpython-314.pyc +0 -0
  204. package/hooks/mutation_adapters/__pycache__/lib.cpython-314.pyc +0 -0
  205. package/hooks/mutation_adapters/__pycache__/mutmut.cpython-314.pyc +0 -0
  206. package/hooks/mutation_adapters/__pycache__/pitest.cpython-314.pyc +0 -0
  207. package/hooks/mutation_adapters/__pycache__/stryker.cpython-314.pyc +0 -0
  208. package/hooks/mutation_adapters/__pycache__/stryker_net.cpython-314.pyc +0 -0
  209. package/hooks/mutation_adapters/lib.py +478 -0
  210. package/hooks/mutation_adapters/mutmut.py +188 -0
  211. package/hooks/mutation_adapters/pitest.py +266 -0
  212. package/hooks/mutation_adapters/stryker.py +157 -0
  213. package/hooks/mutation_adapters/stryker_net.py +264 -0
  214. package/hooks/mutation_gate.py +193 -0
  215. package/hooks/mutation_testing_smoke_gate.py +371 -0
  216. package/hooks/pending_review_notify.py +121 -0
  217. package/hooks/phase_marker.py +138 -0
  218. package/hooks/post_compact_state_reinject.py +180 -0
  219. package/hooks/post_format.py +115 -0
  220. package/hooks/pre_commit_knowledge_index.py +128 -0
  221. package/hooks/pre_commit_review.py +66 -0
  222. package/hooks/pre_pr_review.py +694 -0
  223. package/hooks/pre_tool_guard.py +405 -0
  224. package/hooks/py.sh +73 -0
  225. package/hooks/refactor-bash-write-patterns.json +29 -0
  226. package/hooks/refactor_test_bash_guard.py +253 -0
  227. package/hooks/refactor_test_freeze_guard.py +139 -0
  228. package/hooks/refactor_test_revert_guard.py +186 -0
  229. package/hooks/repo_review_nudge.py +287 -0
  230. package/hooks/review_verdict_recorder.py +464 -0
  231. package/hooks/scan_bash_command_for_banned_scripts.py +428 -0
  232. package/hooks/scan_worktree_for_banned_scripts.py +238 -0
  233. package/hooks/session_learning_trigger.py +248 -0
  234. package/hooks/skills_index.py +126 -0
  235. package/hooks/stryker_xunit_shim_guard.py +571 -0
  236. package/hooks/subagent_completion_guard.py +309 -0
  237. package/hooks/subagent_skill_context.py +139 -0
  238. package/hooks/task_completion_metrics.py +216 -0
  239. package/hooks/tdd_guard.py +229 -0
  240. package/hooks/telemetry.py +341 -0
  241. package/hooks/token_efficiency_review.py +194 -0
  242. package/hooks/verify_guard.py +183 -0
  243. package/hooks/verify_guard_edit_marker.py +73 -0
  244. package/hooks/version_check.py +173 -0
  245. package/knowledge/accepted-risks-schema.md +98 -0
  246. package/knowledge/adr-decision-criteria.md +64 -0
  247. package/knowledge/adversarial-review-protocol.md +139 -0
  248. package/knowledge/agent-registry.md +228 -0
  249. package/knowledge/agent-review-methodology.md +80 -0
  250. package/knowledge/ai-friendly-repo-guidelines.md +67 -0
  251. package/knowledge/architecture-assessment.md +96 -0
  252. package/knowledge/artifact-lifecycle.md +57 -0
  253. package/knowledge/cd-maturity-model.md +82 -0
  254. package/knowledge/cd-test-architecture.md +190 -0
  255. package/knowledge/ci-cd-file-scope.md +24 -0
  256. package/knowledge/codegraph-vs-graphify.md +192 -0
  257. package/knowledge/component-test-patterns.md +139 -0
  258. package/knowledge/database-change-management.md +80 -0
  259. package/knowledge/database-test-patterns.md +79 -0
  260. package/knowledge/decision-defaults.md +88 -0
  261. package/knowledge/dependency-breaking-techniques.md +116 -0
  262. package/knowledge/deployment-pipeline.md +86 -0
  263. package/knowledge/design-smells.md +122 -0
  264. package/knowledge/directory-enumeration.md +38 -0
  265. package/knowledge/domain-modeling.md +123 -0
  266. package/knowledge/evidence-bundle.md +90 -0
  267. package/knowledge/exploratory-testing-field-guide.md +122 -0
  268. package/knowledge/failure-routing.md +28 -0
  269. package/knowledge/fixture-construction.md +56 -0
  270. package/knowledge/frontend-component-architecture.md +139 -0
  271. package/knowledge/gherkin-quality-review-dispatch.md +135 -0
  272. package/knowledge/index.json +6766 -0
  273. package/knowledge/internal-collaborator-doubling.md +101 -0
  274. package/knowledge/legacy-test-strategy.md +71 -0
  275. package/knowledge/long-run-waiting.md +66 -0
  276. package/knowledge/microservice-testing.md +71 -0
  277. package/knowledge/model-pricing.json +23 -0
  278. package/knowledge/mutation-score-formulas.md +60 -0
  279. package/knowledge/object-calisthenics.md +147 -0
  280. package/knowledge/oracle-provenance.md +94 -0
  281. package/knowledge/orchestrator-script-implementation.md +185 -0
  282. package/knowledge/owasp-detection.md +148 -0
  283. package/knowledge/plan-review-rubric.md +56 -0
  284. package/knowledge/proxy-connectivity.md +62 -0
  285. package/knowledge/reactive-effect-patterns.md +73 -0
  286. package/knowledge/recon-inventory-excludes.txt +32 -0
  287. package/knowledge/references/bdd-value-guide.md +61 -0
  288. package/knowledge/references/csharp-http-client-testing.md +264 -0
  289. package/knowledge/release-strategies.md +74 -0
  290. package/knowledge/report-output-location.md +117 -0
  291. package/knowledge/report-pdf-integration.md +63 -0
  292. package/knowledge/report-print.css +129 -0
  293. package/knowledge/report-template.md +114 -0
  294. package/knowledge/report-to-pdf.md +69 -0
  295. package/knowledge/request-processing-flow.md +63 -0
  296. package/knowledge/result-verification.md +52 -0
  297. package/knowledge/review-agent-output-contract.md +121 -0
  298. package/knowledge/review-lens-classification.md +113 -0
  299. package/knowledge/review-rubric.md +62 -0
  300. package/knowledge/review-template.md +104 -0
  301. package/knowledge/rule-fixtures/A02.insecure-random-js/negative.js +1 -0
  302. package/knowledge/rule-fixtures/A02.insecure-random-js/positive.js +1 -0
  303. package/knowledge/rule-fixtures/A02.weak-hashing-md5/negative.py +1 -0
  304. package/knowledge/rule-fixtures/A02.weak-hashing-md5/positive.py +1 -0
  305. package/knowledge/rule-fixtures/A03.command-injection/negative.js +1 -0
  306. package/knowledge/rule-fixtures/A03.command-injection/positive.js +1 -0
  307. package/knowledge/rule-fixtures/A03.sql-injection/negative.js +1 -0
  308. package/knowledge/rule-fixtures/A03.sql-injection/positive.js +1 -0
  309. package/knowledge/rule-fixtures/A03.xss-innerhtml/negative.js +1 -0
  310. package/knowledge/rule-fixtures/A03.xss-innerhtml/positive.js +1 -0
  311. package/knowledge/rule-fixtures/A05.cors-wildcard/negative.js +1 -0
  312. package/knowledge/rule-fixtures/A05.cors-wildcard/positive.js +1 -0
  313. package/knowledge/rule-fixtures/A05.default-credentials/negative.js +1 -0
  314. package/knowledge/rule-fixtures/A05.default-credentials/positive.js +1 -0
  315. package/knowledge/rule-fixtures/A07.jwt-alg-none/negative.js +1 -0
  316. package/knowledge/rule-fixtures/A07.jwt-alg-none/positive.js +1 -0
  317. package/knowledge/rule-fixtures/A08.binary-formatter/negative.cs +1 -0
  318. package/knowledge/rule-fixtures/A08.binary-formatter/positive.cs +1 -0
  319. package/knowledge/rule-fixtures/A08.js-eval/negative.js +1 -0
  320. package/knowledge/rule-fixtures/A08.js-eval/positive.js +1 -0
  321. package/knowledge/rule-fixtures/A08.object-input-stream/negative.java +1 -0
  322. package/knowledge/rule-fixtures/A08.object-input-stream/positive.java +1 -0
  323. package/knowledge/schemas/disposition-register-v1.json +65 -0
  324. package/knowledge/schemas/recon-envelope-v1.json +198 -0
  325. package/knowledge/schemas/unified-finding-v1.json +72 -0
  326. package/knowledge/security-primitives-contract.md +301 -0
  327. package/knowledge/security-review-rule-map.yaml +107 -0
  328. package/knowledge/skills-registry.md +72 -0
  329. package/knowledge/task-size-classifier.md +103 -0
  330. package/knowledge/telemetry-schema.md +881 -0
  331. package/knowledge/test-automation-maturity.md +56 -0
  332. package/knowledge/test-automation-principles.md +71 -0
  333. package/knowledge/test-cadence-tradeoffs.md +68 -0
  334. package/knowledge/test-doubles.md +105 -0
  335. package/knowledge/test-file-indicators.md +22 -0
  336. package/knowledge/test-layer-gates.md +35 -0
  337. package/knowledge/test-matrix-examples/django-batch.md +24 -0
  338. package/knowledge/test-matrix-examples/dotnet-grpc-fronting-api.md +90 -0
  339. package/knowledge/test-matrix-examples/dotnet-http-consumer.md +131 -0
  340. package/knowledge/test-matrix-examples/react-node-spa.md +24 -0
  341. package/knowledge/test-matrix-examples/spring-boot-service.md +25 -0
  342. package/knowledge/test-matrix-examples/ssr-htmx.md +24 -0
  343. package/knowledge/test-organization.md +70 -0
  344. package/knowledge/test-pyramid.md +84 -0
  345. package/knowledge/test-refactoring.md +67 -0
  346. package/knowledge/test-review-division-of-labor.md +85 -0
  347. package/knowledge/test-smells.md +80 -0
  348. package/knowledge/test-stack-profiles/bdd-frameworks.md +235 -0
  349. package/knowledge/test-stack-profiles/django.md +13 -0
  350. package/knowledge/test-stack-profiles/dotnet.md +18 -0
  351. package/knowledge/test-stack-profiles/go.md +16 -0
  352. package/knowledge/test-stack-profiles/node.md +16 -0
  353. package/knowledge/test-stack-profiles/react.md +12 -0
  354. package/knowledge/test-stack-profiles/spring-boot.md +16 -0
  355. package/knowledge/test-stack-profiles/ssr-htmx.md +14 -0
  356. package/knowledge/test-stack-profiles/vue.md +12 -0
  357. package/knowledge/test-strategy.md +70 -0
  358. package/knowledge/testability-patterns.md +240 -0
  359. package/knowledge/testing-quadrants.md +44 -0
  360. package/knowledge/testing-techniques/approval.md +15 -0
  361. package/knowledge/testing-techniques/chaos.md +17 -0
  362. package/knowledge/testing-techniques/fuzz.md +15 -0
  363. package/knowledge/testing-techniques/property-based.md +15 -0
  364. package/knowledge/testing-techniques/schema-validation.md +15 -0
  365. package/knowledge/testing-techniques/screenshot.md +15 -0
  366. package/knowledge/three-phase-workflow.md +198 -0
  367. package/knowledge/value-patterns.md +55 -0
  368. package/knowledge/verification-mode.md +116 -0
  369. package/knowledge/virtual-service-libraries.md +75 -0
  370. package/knowledge/wave-consolidation-guidance.md +21 -0
  371. package/overrides/agents/Explore.md +15 -0
  372. package/overrides/agents/general-purpose.md +10 -0
  373. package/overrides/notes/autoship.md +6 -0
  374. package/overrides/notes/issues-from-assessment.md +3 -0
  375. package/overrides/notes/issues-from-plan.md +3 -0
  376. package/overrides/notes/mutation-night-watch.md +3 -0
  377. package/overrides/notes/mutation-testing.md +3 -0
  378. package/overrides/notes/pr.md +7 -0
  379. package/overrides/notes/project-init.md +6 -0
  380. package/overrides/notes/setup.md +13 -0
  381. package/overrides/notes/specs.md +3 -0
  382. package/overrides/skills/headless-run/SKILL.md +45 -0
  383. package/overrides/skills/upgrade/SKILL.md +30 -0
  384. package/overrides/skills/version/SKILL.md +25 -0
  385. package/package.json +36 -0
  386. package/scripts/authoring_digest.py +93 -0
  387. package/scripts/autoship_discover.py +121 -0
  388. package/scripts/autoship_group.py +409 -0
  389. package/scripts/autoship_proposals.py +494 -0
  390. package/scripts/autoship_queue.py +291 -0
  391. package/scripts/autoship_reclaim.py +495 -0
  392. package/scripts/build_jobs.py +108 -0
  393. package/scripts/build_rollback_point.py +240 -0
  394. package/scripts/build_slice_scope.py +157 -0
  395. package/scripts/build_wave.py +109 -0
  396. package/scripts/build_wave_reconcile.py +252 -0
  397. package/scripts/build_worktree_baseref.py +113 -0
  398. package/scripts/check_agent_scope.py +117 -0
  399. package/scripts/check_agent_tool_mapping.py +213 -0
  400. package/scripts/check_review_agent_mcp_tools.py +317 -0
  401. package/scripts/check_security_assessment_mcp_tools.py +165 -0
  402. package/scripts/checkpoint_abort.py +502 -0
  403. package/scripts/claude_setup_review.py +438 -0
  404. package/scripts/codebase_recon.py +556 -0
  405. package/scripts/coverage_config.py +623 -0
  406. package/scripts/coverage_delta_steering.py +330 -0
  407. package/scripts/coverage_discovery_dotnet.py +315 -0
  408. package/scripts/coverage_discovery_java.py +742 -0
  409. package/scripts/coverage_discovery_js.py +546 -0
  410. package/scripts/coverage_gap_ranking.py +556 -0
  411. package/scripts/coverage_readiness.py +455 -0
  412. package/scripts/coverage_report_parse.py +521 -0
  413. package/scripts/detect_bdd_convention.py +252 -0
  414. package/scripts/eval_ablation.py +376 -0
  415. package/scripts/gherkin_analysis_coverage_gate.py +306 -0
  416. package/scripts/gherkin_cross_feature_duplicate_titles_gate.py +173 -0
  417. package/scripts/gherkin_effectiveness_rollup.py +238 -0
  418. package/scripts/gherkin_failure_path_gate.py +206 -0
  419. package/scripts/gherkin_feature_merge.py +720 -0
  420. package/scripts/gherkin_stub_gate.py +163 -0
  421. package/scripts/gherkin_stub_merge.py +479 -0
  422. package/scripts/git_origin_host.py +88 -0
  423. package/scripts/install-java-static-analysis.py +110 -0
  424. package/scripts/issue_deps.py +74 -0
  425. package/scripts/lib/_bdd_markers.py +28 -0
  426. package/scripts/lib/_gherkin_text.py +93 -0
  427. package/scripts/lib/_vendored_tree.py +70 -0
  428. package/scripts/lib/autoship_state.py +397 -0
  429. package/scripts/lib/claude_md_guard.py +226 -0
  430. package/scripts/lib/deterministic_recon.py +446 -0
  431. package/scripts/lib/mcp_tool_grants.py +211 -0
  432. package/scripts/lib/plan_parse.py +386 -0
  433. package/scripts/lib/review_result.py +84 -0
  434. package/scripts/lib/review_roster.py +86 -0
  435. package/scripts/lib/session_log/__init__.py +34 -0
  436. package/scripts/lib/session_log/__pycache__/__init__.cpython-314.pyc +0 -0
  437. package/scripts/lib/session_log/__pycache__/records.cpython-314.pyc +0 -0
  438. package/scripts/lib/session_log/classify.py +231 -0
  439. package/scripts/lib/session_log/corrections.py +194 -0
  440. package/scripts/lib/session_log/discovery.py +108 -0
  441. package/scripts/lib/session_log/records.py +218 -0
  442. package/scripts/lib/session_log/redact.py +76 -0
  443. package/scripts/lib/session_log/signals.py +373 -0
  444. package/scripts/lib/session_report_downstream.py +614 -0
  445. package/scripts/lib/session_report_maintainer.py +1273 -0
  446. package/scripts/lib/session_report_shared.py +262 -0
  447. package/scripts/lib/settings_hook_guard.py +157 -0
  448. package/scripts/lib/slug.py +33 -0
  449. package/scripts/lib/stub_extractors/__init__.py +82 -0
  450. package/scripts/lib/stub_extractors/_common.py +328 -0
  451. package/scripts/lib/stub_extractors/csharp.py +19 -0
  452. package/scripts/lib/stub_extractors/go.py +173 -0
  453. package/scripts/lib/stub_extractors/java.py +18 -0
  454. package/scripts/lib/stub_extractors/jsts.py +126 -0
  455. package/scripts/mutation_stack_sections.py +149 -0
  456. package/scripts/mutation_yield_steering.py +345 -0
  457. package/scripts/orchestrator.py +895 -0
  458. package/scripts/plan_gherkin_export.py +227 -0
  459. package/scripts/plan_waves.py +208 -0
  460. package/scripts/pr_close_keyword_lint.py +108 -0
  461. package/scripts/progress_guardian.py +888 -0
  462. package/scripts/recon_inventory.py +273 -0
  463. package/scripts/review_findings_log.py +93 -0
  464. package/scripts/run_invariants.py +124 -0
  465. package/scripts/select_lenses.py +640 -0
  466. package/scripts/session_report.py +486 -0
  467. package/scripts/set_autocompact_env.py +221 -0
  468. package/scripts/ship_resume_guard.py +135 -0
  469. package/scripts/ship_review_gate.py +63 -0
  470. package/scripts/specs_convention_marker.py +103 -0
  471. package/scripts/test_improve_resume.py +277 -0
  472. package/scripts/test_review_mechanics.py +958 -0
  473. package/scripts/token_efficiency_review.py +322 -0
  474. package/scripts/verdict_scope.py +285 -0
  475. package/scripts/verify_gherkin_quality_critic_isolation.py +296 -0
  476. package/scripts/verify_tier.py +157 -0
  477. package/skills/adr-tools/SKILL.md +118 -0
  478. package/skills/agent-readiness/SKILL.md +105 -0
  479. package/skills/agent-readiness/ai_friendly_analyzers.py +326 -0
  480. package/skills/agent-readiness/scanner.py +441 -0
  481. package/skills/agent-readiness/scorecard.yaml +88 -0
  482. package/skills/api-design/SKILL.md +115 -0
  483. package/skills/apply-fixes/SKILL.md +171 -0
  484. package/skills/apply-test-doubles/SKILL.md +321 -0
  485. package/skills/artifact-lifecycle/SKILL.md +127 -0
  486. package/skills/autoship/SKILL.md +1124 -0
  487. package/skills/benchmark/SKILL.md +105 -0
  488. package/skills/branch-workflow/SKILL.md +89 -0
  489. package/skills/browse/SKILL.md +184 -0
  490. package/skills/browser-testing/SKILL.md +62 -0
  491. package/skills/browser-testing/references/playwright-patterns.md +216 -0
  492. package/skills/build/SKILL.md +422 -0
  493. package/skills/build/references/static-self-heal.md +245 -0
  494. package/skills/careful/SKILL.md +72 -0
  495. package/skills/cd-test-architecture/SKILL.md +371 -0
  496. package/skills/ci-debugging/SKILL.md +105 -0
  497. package/skills/co-evolution-audit/SKILL.md +269 -0
  498. package/skills/code-review/SKILL.md +1015 -0
  499. package/skills/code-review/examples/aggregated-sample.json +56 -0
  500. package/skills/code-review/examples/sample-report.md +41 -0
  501. package/skills/code-review/output-format.md +478 -0
  502. package/skills/code-review/scripts/activation.py +86 -0
  503. package/skills/code-review/scripts/change_impact.py +357 -0
  504. package/skills/code-review/scripts/change_shape.py +372 -0
  505. package/skills/code-review/scripts/change_size.py +212 -0
  506. package/skills/code-review/scripts/changed_file_list.py +141 -0
  507. package/skills/code-review/scripts/closing_pass.py +187 -0
  508. package/skills/code-review/scripts/consolidate.py +277 -0
  509. package/skills/code-review/scripts/contract_failure_report.py +185 -0
  510. package/skills/code-review/scripts/dispatch_reconcile.py +66 -0
  511. package/skills/code-review/scripts/dispatch_waves.py +164 -0
  512. package/skills/code-review/scripts/finding_signature.py +446 -0
  513. package/skills/code-review/scripts/ledger.py +283 -0
  514. package/skills/code-review/scripts/partition.py +169 -0
  515. package/skills/code-review/scripts/render_tiered_findings.py +274 -0
  516. package/skills/code-review/scripts/repo_invariants.py +1066 -0
  517. package/skills/code-review/scripts/review_context_pack.py +306 -0
  518. package/skills/code-review/scripts/review_round_log.py +345 -0
  519. package/skills/code-review/scripts/review_value_coverage.py +297 -0
  520. package/skills/code-review/scripts/validate_review_output.py +467 -0
  521. package/skills/code-review/sliced-mode.md +205 -0
  522. package/skills/competitive-analysis/SKILL.md +191 -0
  523. package/skills/context-loading-protocol/SKILL.md +157 -0
  524. package/skills/continue/SKILL.md +90 -0
  525. package/skills/cost-report/SKILL.md +178 -0
  526. package/skills/coverage-baseline/SKILL.md +335 -0
  527. package/skills/coverage-baseline/references/multi-project-discovery.md +202 -0
  528. package/skills/coverage-delta/SKILL.md +181 -0
  529. package/skills/coverage-delta/references/mutation-gate.md +70 -0
  530. package/skills/design-doc/SKILL.md +95 -0
  531. package/skills/design-interrogation/SKILL.md +89 -0
  532. package/skills/design-it-twice/SKILL.md +91 -0
  533. package/skills/docker-image-audit/SKILL.md +108 -0
  534. package/skills/docker-image-audit/references/install-guide.md +64 -0
  535. package/skills/docker-image-audit/references/report-template.md +73 -0
  536. package/skills/docker-image-create/SKILL.md +185 -0
  537. package/skills/domain-analysis/SKILL.md +183 -0
  538. package/skills/domain-driven-design/SKILL.md +194 -0
  539. package/skills/exploratory-testing/SKILL.md +108 -0
  540. package/skills/explore/SKILL.md +51 -0
  541. package/skills/farley-score/SKILL.md +165 -0
  542. package/skills/feature-file-validation/SKILL.md +78 -0
  543. package/skills/feature-file-validation/references/validation-rules.md +115 -0
  544. package/skills/feedback-learning/SKILL.md +414 -0
  545. package/skills/fix/SKILL.md +450 -0
  546. package/skills/freeze/SKILL.md +68 -0
  547. package/skills/frontend-architecture/SKILL.md +113 -0
  548. package/skills/gherkin-derive/SKILL.md +630 -0
  549. package/skills/gherkin-public/SKILL.md +266 -0
  550. package/skills/governance-compliance/SKILL.md +150 -0
  551. package/skills/guard/SKILL.md +75 -0
  552. package/skills/handoff/SKILL.md +139 -0
  553. package/skills/handoff/references/summary-templates.md +242 -0
  554. package/skills/harness-audit/SKILL.md +751 -0
  555. package/skills/harness-audit/scripts/lesson_validate.py +386 -0
  556. package/skills/harness-audit/scripts/redundancy_criterion.py +188 -0
  557. package/skills/headless-run/SKILL.md +45 -0
  558. package/skills/headless-run/scripts/isolated_dispatch.py +381 -0
  559. package/skills/help/SKILL.md +72 -0
  560. package/skills/hexagonal-architecture/SKILL.md +85 -0
  561. package/skills/human-oversight-protocol/SKILL.md +224 -0
  562. package/skills/issues-from-assessment/SKILL.md +223 -0
  563. package/skills/issues-from-plan/SKILL.md +133 -0
  564. package/skills/legacy-code/SKILL.md +132 -0
  565. package/skills/mermaid-diagramming/SKILL.md +120 -0
  566. package/skills/mutation-night-watch/SKILL.md +154 -0
  567. package/skills/mutation-night-watch/references/scheduling.md +135 -0
  568. package/skills/mutation-testing/SKILL.md +396 -0
  569. package/skills/mutation-testing/references/languages/csharp-stryker-net.md +676 -0
  570. package/skills/mutation-testing/references/languages/go-go-mutesting.md +95 -0
  571. package/skills/mutation-testing/references/languages/java-pitest.md +77 -0
  572. package/skills/mutation-testing/references/languages/javascript-stryker.md +188 -0
  573. package/skills/mutation-testing/references/languages/python-mutmut.md +97 -0
  574. package/skills/mutation-testing/references/time-estimation.md +34 -0
  575. package/skills/mutation-testing/references/tool-detection.md +15 -0
  576. package/skills/mutation-testing/references/workflow-callers.md +23 -0
  577. package/skills/mutation-testing/scripts/__pycache__/xunit_v3_feature_detector.cpython-314.pyc +0 -0
  578. package/skills/mutation-testing/scripts/csharp_stryker_net_slice_runner.py +635 -0
  579. package/skills/mutation-testing/scripts/csharp_stryker_net_status_loop.py +525 -0
  580. package/skills/mutation-testing/scripts/csharp_stryker_net_wrapper.py +681 -0
  581. package/skills/mutation-testing/scripts/mutation_baseline_reuse.py +292 -0
  582. package/skills/mutation-testing/scripts/mutation_exclude_policy.py +268 -0
  583. package/skills/mutation-testing/scripts/mutation_feasibility_gate.py +463 -0
  584. package/skills/mutation-testing/scripts/mutation_kill_headless.py +331 -0
  585. package/skills/mutation-testing/scripts/mutation_kill_insert.py +199 -0
  586. package/skills/mutation-testing/scripts/mutation_kill_insert_python.py +150 -0
  587. package/skills/mutation-testing/scripts/mutation_kill_loop.py +869 -0
  588. package/skills/mutation-testing/scripts/mutation_kill_loop_python.py +949 -0
  589. package/skills/mutation-testing/scripts/mutation_kill_retry.py +592 -0
  590. package/skills/mutation-testing/scripts/mutation_kill_shared.py +620 -0
  591. package/skills/mutation-testing/scripts/mutation_nightwatch.py +462 -0
  592. package/skills/mutation-testing/scripts/mutation_nightwatch_stacks.py +425 -0
  593. package/skills/mutation-testing/scripts/mutation_report.py +743 -0
  594. package/skills/mutation-testing/scripts/mutation_report_cli.py +175 -0
  595. package/skills/mutation-testing/scripts/mutation_safety_gate.py +69 -0
  596. package/skills/mutation-testing/scripts/stryker_shard_pipeline.py +847 -0
  597. package/skills/mutation-testing/scripts/stryker_shard_setup.py +440 -0
  598. package/skills/mutation-testing/scripts/stryker_timeout_retry.py +142 -0
  599. package/skills/mutation-testing/scripts/xunit_v3_feature_detector.py +341 -0
  600. package/skills/performance-benchmark/SKILL.md +174 -0
  601. package/skills/performance-benchmark/examples/report-format.md +43 -0
  602. package/skills/performance-benchmark/references/benchmark-script.md +169 -0
  603. package/skills/performance-metrics/SKILL.md +265 -0
  604. package/skills/plan/SKILL.md +199 -0
  605. package/skills/plan/references/gherkin-persistence.md +43 -0
  606. package/skills/plan/references/plan-template.md +182 -0
  607. package/skills/pr/SKILL.md +289 -0
  608. package/skills/pr/scripts/gate_retry_state.py +368 -0
  609. package/skills/project-init/README.md +141 -0
  610. package/skills/project-init/SKILL.md +1197 -0
  611. package/skills/project-init/evals/evals.json +200 -0
  612. package/skills/project-init/references/capability-tools.md +55 -0
  613. package/skills/project-init/references/configs.md +221 -0
  614. package/skills/property-based-testing/SKILL.md +121 -0
  615. package/skills/property-based-testing/fixtures/invariant_fixture.py +15 -0
  616. package/skills/property-based-testing/fixtures/js-roundtrip/README.md +42 -0
  617. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/LICENSE +21 -0
  618. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/README.md +263 -0
  619. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/lib/cjs/fast-check.d.ts +5165 -0
  620. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/lib/cjs/fast-check.js +12147 -0
  621. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/lib/cjs/package.json +3 -0
  622. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/lib/cjs/types57/fast-check.d.ts +5165 -0
  623. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/lib/fast-check.d.ts +5165 -0
  624. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/lib/fast-check.js +12011 -0
  625. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/lib/rolldown-runtime-D7D4PA-g.js +13 -0
  626. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/lib/types57/fast-check.d.ts +5165 -0
  627. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/package.json +94 -0
  628. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/LICENSE +21 -0
  629. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/README.md +168 -0
  630. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/RandomGenerator-DcXj09Ch.d.ts +14 -0
  631. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/distribution/uniformBigInt.d.ts +15 -0
  632. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/distribution/uniformBigInt.js +38 -0
  633. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/distribution/uniformFloat32.d.ts +15 -0
  634. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/distribution/uniformFloat32.js +18 -0
  635. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/distribution/uniformFloat64.d.ts +15 -0
  636. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/distribution/uniformFloat64.js +22 -0
  637. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/distribution/uniformInt.d.ts +15 -0
  638. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/distribution/uniformInt.js +134 -0
  639. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/RandomGenerator-DcXj09Ch.d.ts +14 -0
  640. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/distribution/uniformBigInt.d.ts +15 -0
  641. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/distribution/uniformBigInt.js +37 -0
  642. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/distribution/uniformFloat32.d.ts +15 -0
  643. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/distribution/uniformFloat32.js +17 -0
  644. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/distribution/uniformFloat64.d.ts +15 -0
  645. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/distribution/uniformFloat64.js +21 -0
  646. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/distribution/uniformInt.d.ts +15 -0
  647. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/distribution/uniformInt.js +133 -0
  648. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/generator/congruential32.d.ts +7 -0
  649. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/generator/congruential32.js +44 -0
  650. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/generator/mersenne.d.ts +7 -0
  651. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/generator/mersenne.js +90 -0
  652. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/generator/xoroshiro128plus.d.ts +7 -0
  653. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/generator/xoroshiro128plus.js +80 -0
  654. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/generator/xorshift128plus.d.ts +7 -0
  655. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/generator/xorshift128plus.js +78 -0
  656. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/package.json +3 -0
  657. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/types/JumpableRandomGenerator.d.ts +16 -0
  658. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/types/JumpableRandomGenerator.js +0 -0
  659. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/types/RandomGenerator.d.ts +2 -0
  660. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/types/RandomGenerator.js +0 -0
  661. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/utils/generateN.d.ts +6 -0
  662. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/utils/generateN.js +8 -0
  663. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/utils/purify.d.ts +12 -0
  664. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/utils/purify.js +9 -0
  665. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/utils/skipN.d.ts +6 -0
  666. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/utils/skipN.js +6 -0
  667. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/generator/congruential32.d.ts +7 -0
  668. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/generator/congruential32.js +46 -0
  669. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/generator/mersenne.d.ts +7 -0
  670. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/generator/mersenne.js +92 -0
  671. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/generator/xoroshiro128plus.d.ts +7 -0
  672. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/generator/xoroshiro128plus.js +82 -0
  673. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/generator/xorshift128plus.d.ts +7 -0
  674. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/generator/xorshift128plus.js +80 -0
  675. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/types/JumpableRandomGenerator.d.ts +16 -0
  676. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/types/JumpableRandomGenerator.js +0 -0
  677. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/types/RandomGenerator.d.ts +2 -0
  678. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/types/RandomGenerator.js +0 -0
  679. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/utils/generateN.d.ts +6 -0
  680. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/utils/generateN.js +9 -0
  681. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/utils/purify.d.ts +12 -0
  682. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/utils/purify.js +10 -0
  683. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/utils/skipN.d.ts +6 -0
  684. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/utils/skipN.js +7 -0
  685. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/package.json +133 -0
  686. package/skills/property-based-testing/fixtures/js-roundtrip/package-lock.json +1179 -0
  687. package/skills/property-based-testing/fixtures/js-roundtrip/package.json +14 -0
  688. package/skills/property-based-testing/fixtures/js-roundtrip/roundtrip.js +29 -0
  689. package/skills/property-based-testing/fixtures/js-roundtrip/roundtrip.properties.test.js +16 -0
  690. package/skills/property-based-testing/fixtures/no_property_fixture.py +10 -0
  691. package/skills/property-based-testing/fixtures/roundtrip_fixture.py +16 -0
  692. package/skills/property-based-testing/references/languages/javascript.md +54 -0
  693. package/skills/property-based-testing/scripts/detect_and_dispatch.py +80 -0
  694. package/skills/property-based-testing/scripts/hypothesis_scaffold.py +276 -0
  695. package/skills/proxy-resilience/SKILL.md +84 -0
  696. package/skills/quality-gate-pipeline/SKILL.md +184 -0
  697. package/skills/quality-targets-converge/SKILL.md +254 -0
  698. package/skills/repo-review/SKILL.md +159 -0
  699. package/skills/report-pdf/SKILL.md +66 -0
  700. package/skills/review/SKILL.md +47 -0
  701. package/skills/review-agent/SKILL.md +152 -0
  702. package/skills/review-summary/SKILL.md +73 -0
  703. package/skills/run-report/SKILL.md +70 -0
  704. package/skills/semantic-duplication-scan/SKILL.md +337 -0
  705. package/skills/semantic-scan/SKILL.md +53 -0
  706. package/skills/semgrep-analyze/SKILL.md +139 -0
  707. package/skills/setup/SKILL.md +1122 -0
  708. package/skills/ship/SKILL.md +240 -0
  709. package/skills/source-verification/SKILL.md +210 -0
  710. package/skills/source-verification/scripts/claim_extractor.py +155 -0
  711. package/skills/specs/.size-baseline.json +4 -0
  712. package/skills/specs/SKILL.md +243 -0
  713. package/skills/specs/references/completeness-checklist.md +83 -0
  714. package/skills/specs/references/extraction.md +58 -0
  715. package/skills/specs/references/glossary.md +59 -0
  716. package/skills/specs/references/persistence.md +115 -0
  717. package/skills/specs/references/predictability-check.md +77 -0
  718. package/skills/static-analysis-integration/SKILL.md +235 -0
  719. package/skills/static-analysis-integration/adapters/_envelope.py +26 -0
  720. package/skills/static-analysis-integration/adapters/jscpd-adapter.py +66 -0
  721. package/skills/static-analysis-integration/adapters/lizard-adapter.py +81 -0
  722. package/skills/static-analysis-integration/adapters/mypy-adapter.py +50 -0
  723. package/skills/static-analysis-integration/adapters/mypy-src-layout.py +93 -0
  724. package/skills/static-analysis-integration/adapters/security-review-adapter.py +212 -0
  725. package/skills/static-analysis-integration/maintenance.md +23 -0
  726. package/skills/static-analysis-integration/references/language-setup.md +228 -0
  727. package/skills/static-analysis-integration/references/sarif-parser.md +124 -0
  728. package/skills/static-analysis-integration/references/security-review-adapter.md +118 -0
  729. package/skills/static-analysis-integration/references/tool-configs.md +617 -0
  730. package/skills/static-analysis-integration/rulesets/pmd-quickstart.xml +24 -0
  731. package/skills/stryker-xunit-v2-shim/SKILL.md +274 -0
  732. package/skills/stryker-xunit-v2-shim/references/shim-howto.md +256 -0
  733. package/skills/stryker-xunit-v2-shim/scripts/generate_shim.py +143 -0
  734. package/skills/systematic-debugging/SKILL.md +130 -0
  735. package/skills/telemetry/SKILL.md +75 -0
  736. package/skills/test-audit-disable/SKILL.md +129 -0
  737. package/skills/test-design/SKILL.md +177 -0
  738. package/skills/test-design/scripts/__pycache__/internal_double_detector.cpython-314.pyc +0 -0
  739. package/skills/test-design/scripts/internal_double_detector.py +631 -0
  740. package/skills/test-design-advisor/SKILL.md +166 -0
  741. package/skills/test-driven-development/SKILL.md +169 -0
  742. package/skills/test-health/SKILL.md +262 -0
  743. package/skills/test-improve/SKILL.md +239 -0
  744. package/skills/test-improve/references/phase-0-approach-contract.md +228 -0
  745. package/skills/test-improve/references/phase-1-analyze.md +131 -0
  746. package/skills/test-improve/references/phase-2-baseline.md +121 -0
  747. package/skills/test-improve/references/phase-3-derive-gherkin.md +53 -0
  748. package/skills/test-improve/references/phase-4-plan-fixes.md +34 -0
  749. package/skills/test-improve/references/phase-5-improve.md +215 -0
  750. package/skills/test-improve/references/phase-6-refactor-decision.md +45 -0
  751. package/skills/test-improve/references/phase-7-refactor.md +44 -0
  752. package/skills/test-improve/references/phase-8-validate.md +66 -0
  753. package/skills/test-improve/references/phase-9-close-out-prompt.md +11 -0
  754. package/skills/test-improve/references/phase-9-report.md +62 -0
  755. package/skills/test-improve/references/review-loop.md +92 -0
  756. package/skills/test-improve/templates/executive-summary.md +123 -0
  757. package/skills/threat-modeling/SKILL.md +108 -0
  758. package/skills/triage/SKILL.md +211 -0
  759. package/skills/ubiquitous-language/SKILL.md +192 -0
  760. package/skills/ubiquitous-language/scripts/collect_domain_signals.py +300 -0
  761. package/skills/unfreeze/SKILL.md +37 -0
  762. package/skills/upgrade/SKILL.md +31 -0
  763. package/skills/upgrade/scripts/check_version_drift.py +113 -0
  764. package/skills/upgrade/scripts/enable_autoupdate.py +149 -0
  765. package/skills/version/SKILL.md +25 -0
  766. package/sync/__pycache__/sync_upstream.cpython-314.pyc +0 -0
  767. package/sync/sync_upstream.py +293 -0
  768. package/templates/ACCEPTED-RISKS.md.tmpl +46 -0
  769. package/templates/agents/agent-template.md +151 -0
  770. package/templates/agents/angular-testing.md +66 -0
  771. package/templates/agents/csharp-quality.md +63 -0
  772. package/templates/agents/esm-enforcer.md +52 -0
  773. package/templates/agents/front-end-testing.md +65 -0
  774. package/templates/agents/go-quality.md +65 -0
  775. package/templates/agents/python-quality.md +62 -0
  776. package/templates/agents/react-testing.md +61 -0
  777. package/templates/agents/ts-enforcer.md +60 -0
  778. package/templates/agents/twelve-factor-audit.md +49 -0
  779. package/tools/entropy-check.py +250 -0
  780. package/tools/model-hash-verify.py +213 -0
@@ -0,0 +1,694 @@
1
+ #!/usr/bin/env python3
2
+ """pre_pr_review — Claude Code PreToolUse:Bash hook (#1886).
3
+
4
+ Successor to `hooks/pre_commit_review.py`'s review-corroboration gate.
5
+ Design decision (issue #1886, resolved): the gate moves from `git commit` to
6
+ `gh pr create` — a branch is now free to accumulate any number of local
7
+ commits without paying the review-panel cost at each one; the hard block
8
+ fires once, against the branch's FULL diff vs. its base, at PR-creation
9
+ time.
10
+
11
+ WHY A NEW MODULE RATHER THAN REPURPOSING `pre_commit_review.py` IN PLACE
12
+ (documenting the choice the issue explicitly left open): `pre_commit_review.py`
13
+ grew, across #1461/#1476/#1627/#1763/#1801 and further re-reviews, an enormous
14
+ amount of machinery specific to `git commit`'s command shape — per-target
15
+ `-C`/`--git-dir`/`--work-tree` resolution, `-a`/pathspec-form-commit detection,
16
+ cosmetic-delta carry-forward across re-stages, and a `--no-verify`/`-n`
17
+ flag-based bypass. None of that transfers to `gh pr create`, which has no `-C`
18
+ equivalent, no pathspec-commit-shaped ambiguity, and no native
19
+ `--no-verify`-shaped flag to key a bypass off. Reusing that file's own
20
+ git-commit-specific detector/hash pair in place would have meant either
21
+ carrying dead complexity forward or performing a much larger, riskier
22
+ in-place rewrite than standing up a new, deliberately leaner module that
23
+ reuses the SHARED library pieces (`review_gate_hash.py`,
24
+ `review_gate_corroboration.py`, `boundary_events.py`, `atomic_state.py`,
25
+ `artifact_paths.py`) both hooks depend on. `pre_commit_review.py` itself is
26
+ now a documented no-op (see its own module docstring) rather than deleted,
27
+ since deleting it would strand the many docs/tests/skills that still name it
28
+ in prose describing this exact migration.
29
+
30
+ WHAT CHANGED, MECHANICALLY, FROM THE COMMIT-TIME GATE:
31
+
32
+ - **Trigger**: `gh pr create` (`hooks/lib/gh_pr_create_detect.py`) instead of
33
+ `git commit`. Any other Bash command passes through immediately (exit 0).
34
+ - **Hash**: `hooks/lib/review_gate_hash.py`'s `branch_diff_gate_hash(base_ref,
35
+ cwd)` — `git diff <base>...HEAD`, the WHOLE branch diff against its
36
+ merge-base with the resolved default branch (`default_base_ref()`) —
37
+ instead of `git diff --cached` (one commit's staged patch).
38
+ - **Recency window anchor**: `before_ts` is the CURRENT time at
39
+ `gh pr create` invocation, not a gate file's own mtime (design decision,
40
+ #1886: "anchor to before PR creation"). A multi-commit branch may have been
41
+ reviewed well before its final commit; anchoring on "now" rather than on
42
+ when some earlier `/code-review` run happened to write the gate file means
43
+ the window's only real question is "did genuine, distinct review-agent
44
+ dispatches occur recently, for THIS exact branch-diff content" — not "did
45
+ they happen within `WINDOW_SECONDS` of an arbitrary earlier file write".
46
+ - **Gate file**: `.claude/memory/.pr-review-passed` (new; distinct from
47
+ `.claude/memory/.review-passed`, whose only remaining writer/reader is now
48
+ historical prose — see `pre_commit_review.py`'s docstring).
49
+ - **Bypass**: `PR_GATE_BYPASS_REASON` (an env var, not a `--no-verify`/`-n`
50
+ command-line flag — `gh pr create` has no such native flag to key off).
51
+ Mirrors #709's pattern for the ORIGINAL commit-time gate: when set to a
52
+ non-empty value, the PR is allowed and the bypass is durably logged to
53
+ `.claude/metrics/gate-bypass-audit.jsonl` (the SAME stream, distinguished
54
+ by `triggeredBy: "PR_GATE_BYPASS_REASON"`); when unset, the ordinary gate
55
+ evaluation applies — there is no separate "you tried to bypass but forgot
56
+ the reason" message, because there is no separate flag to detect trying
57
+ without one.
58
+
59
+ WHAT DID NOT CHANGE: the underlying corroboration architecture is reused
60
+ as-is from `hooks/lib/review_gate_corroboration.py` — >= 1 distinct,
61
+ registered review-agent dispatch (or a sanctioned doc-only/single-agent
62
+ exemption) recorded in the recency window, live-registry re-validated, with
63
+ the same #1763 dispatch-failure veto taking priority over every exemption.
64
+ See that module's own docstring for the full account of why this raises the
65
+ bar without cryptographically closing #1461's self-certification gap.
66
+
67
+ `_MIN_DISTINCT_DISPATCHES` was lowered from 2 to 1 (#2147): a single
68
+ `/code-review` invocation already dispatches a full multi-agent panel
69
+ internally, so requiring a SECOND, separate top-level dispatch on top of
70
+ that bought no additional corroboration — it only produced false blocks on
71
+ a legitimately-reviewed branch (e.g. a single `--agent <name>` review, or a
72
+ session whose panel dispatch shape records fewer ledger rows than a prior
73
+ plugin version did). The single-agent exemption event
74
+ (`single-agent-review-exempt`) is consequently now redundant with the
75
+ ordinary count check for the case it was built for — kept anyway, since it
76
+ is a harmless, already-audited alternate path, not because anything still
77
+ requires it.
78
+
79
+ DELIBERATELY DROPPED, not carried forward from `pre_commit_review.py`
80
+ (explicit scope decisions, not oversights):
81
+
82
+ 1. **Cosmetic-delta carry-forward** (#1627): existed to stop a whitespace-only
83
+ re-stage from forcing a fresh review-agent dispatch before the NEXT commit.
84
+ That friction was a direct consequence of gating every commit; since this
85
+ gate fires once, at PR-creation time, against the branch's cumulative
86
+ diff, the scenario it existed to relieve no longer arises here.
87
+ 2. **Multi-target `-C`/`--git-dir`/`--work-tree` resolution** (#1801): a
88
+ `git commit` can retarget which repository it commits to; `gh pr create`
89
+ has no equivalent multi-repository ambiguity — it always targets the
90
+ current repository's configured remote.
91
+ 3. **`-a`/pathspec-form-commit detection** (#1476): specific to `git commit`
92
+ committing tracked-file changes that were never `git add`-ed; has no
93
+ `gh pr create` analogue (a PR is always opened against whatever is
94
+ already committed to the branch).
95
+
96
+ CLOSED (#1886 follow-up, extended by #1904 Bug 2b): `skills/code-review/SKILL.md`
97
+ step 9 WRITES `.claude/memory/.pr-review-passed` with a hash bound to the
98
+ branch diff (`branch_diff_gate_hash(default_base_ref(cwd), cwd)`, via this
99
+ module's own `review_gate_hash.py --branch-diff` CLI mode), for an
100
+ auto-scoped uncommitted-changes review OR a `--since <base>`-scoped one
101
+ that passed — the latter is the shape `/pr`'s own `/code-review --since
102
+ "$BASE" --json` call actually takes, the only real path to `gh pr create`.
103
+ `review_gate_hash.py`'s sibling `review_gate_hash()` (the staged-diff hash)
104
+ is no longer written to any gate file at all — `.review-passed` is retired.
105
+ `hooks/agent_dispatch_ledger.py` now stamps a dispatch's `subject_hash` with
106
+ this same branch-diff hash whenever nothing is staged (the routine state
107
+ during a `--since <base>`-scoped review, since `/pr`'s step 1 requires a
108
+ clean working tree first) — closing the mismatch for that shape completely,
109
+ since every dispatch during it and step 9's own write agree on one content
110
+ domain.
111
+
112
+ KNOWN RESIDUAL GAP, disclosed rather than silently accepted (narrower than
113
+ before #1904, still out of this fix's own scope): for an **auto-scoped
114
+ uncommitted-changes** review, `agent_dispatch_ledger.py` still stamps the
115
+ staged-diff hash (something IS staged in that mode), which is mathematically
116
+ identical to step 9's branch-diff write only in the common
117
+ single-commit-then-PR shape (a branch cut from its base, reviewed once while
118
+ staged, committed, then a PR opened immediately). On a branch with multiple
119
+ separate review-and-commit cycles in THAT mode, the branch-diff hash written
120
+ at step 9 won't match an earlier cycle's dispatch `subject_hash`, and this
121
+ gate correctly falls through to the "no dispatch found" block on a real
122
+ `gh pr create`, requiring a fresh `/code-review` run — a `--since <base>`
123
+ re-review now closes cleanly per the paragraph above, or the audited
124
+ `PR_GATE_BYPASS_REASON` escape hatch remains available — before it opens.
125
+
126
+ `gh_pr_create_detect.is_gh_pr_create_command`'s own docstring discloses its
127
+ detection gap (no `<shell> -c` unwrapping, no command-substitution
128
+ unwrapping, ...) — a much lighter heuristic than
129
+ `pre_commit_detect.is_git_commit_command`'s five-round-hardened one; see
130
+ that module's own docstring for why that difference is a deliberate,
131
+ disclosed scope decision, not an oversight.
132
+
133
+ Contract (docs/python-hook-contract.md):
134
+ Input : JSON on stdin (Claude Code PreToolUse:Bash payload)
135
+ Exit 0: allow the tool call
136
+ Exit 2: block the tool call (feedback returned to Claude on stdout,
137
+ mirrored to stderr — see `_emit_block`)
138
+
139
+ Stdlib-only.
140
+ """
141
+
142
+ from __future__ import annotations
143
+
144
+ import hashlib
145
+ import json
146
+ import os
147
+ import subprocess
148
+ import sys
149
+ from datetime import datetime, timezone
150
+ from pathlib import Path
151
+
152
+ # The digest `sha256(b"")` produces — never treated as a valid subject-hash
153
+ # match here (issue #1904 Bug 1). Computed locally via hashlib rather than
154
+ # imported from `review_gate_hash.EMPTY_DIGEST` so this constant is available
155
+ # even on the degraded-import fallback path below.
156
+ _EMPTY_DIGEST = hashlib.sha256(b"").hexdigest()
157
+
158
+ _HOOK_DIR = Path(__file__).resolve().parent
159
+ _LIB_DIR = _HOOK_DIR / "lib"
160
+
161
+ sys.path.insert(0, str(_LIB_DIR))
162
+ try:
163
+ from artifact_paths import (
164
+ resolve_file as _resolve_file, # type: ignore[import-not-found]
165
+ )
166
+ from atomic_state import ( # type: ignore[import-not-found]
167
+ append_line_locked as _append_line_locked,
168
+ )
169
+ from boundary_events import ( # type: ignore[import-not-found]
170
+ emit_boundary_event as _emit_boundary_event,
171
+ )
172
+ from gh_pr_create_detect import ( # type: ignore[import-not-found]
173
+ is_gh_pr_create_command,
174
+ )
175
+ from git_safe_diff import run_safe_git_diff # type: ignore[import-not-found]
176
+ from pre_commit_doc_classifier import ( # type: ignore[import-not-found]
177
+ is_doc_only_changeset as _is_doc_only_changeset,
178
+ )
179
+ from review_gate_corroboration import ( # type: ignore[import-not-found]
180
+ evaluate as _evaluate_ledger,
181
+ )
182
+ from review_gate_corroboration import ( # type: ignore[import-not-found]
183
+ has_doc_only_exemption as _has_doc_only_exemption,
184
+ )
185
+ from review_gate_corroboration import ( # type: ignore[import-not-found]
186
+ has_single_agent_exemption as _has_single_agent_exemption,
187
+ )
188
+ from review_gate_hash import ( # type: ignore[import-not-found]
189
+ branch_diff_gate_hash,
190
+ default_base_ref,
191
+ )
192
+ from stdin_json import read_stdin_json # type: ignore[import-not-found]
193
+ except ImportError: # pragma: no cover - degraded-import fallback
194
+
195
+ def read_stdin_json() -> dict | None: # type: ignore[misc]
196
+ return None
197
+
198
+ def is_gh_pr_create_command(_command: str) -> bool: # type: ignore[misc]
199
+ return False
200
+
201
+ def _resolve_file( # type: ignore[misc]
202
+ category: str, filename: str, root=None, migrate: bool = True
203
+ ) -> Path:
204
+ repo_root = Path(__file__).resolve().parents[3]
205
+ return repo_root / ".claude" / category / filename
206
+
207
+ def _emit_boundary_event(*_args, **_kwargs) -> None: # type: ignore[misc]
208
+ return None
209
+
210
+ def _append_line_locked( # type: ignore[misc]
211
+ path: Path, line: str, *, delay_env_var=None, fail_open: bool = True
212
+ ) -> None:
213
+ # Degraded-import fallback: atomic_state itself couldn't be
214
+ # imported, so no hardened append is available. Unlike the OLD
215
+ # pre_commit_review.py fallback this replaces, this does NOT fall
216
+ # back to a plain unlocked `open(path, "a")` (#1904 item 5's own
217
+ # disclosed gap for that pattern) — a failed audit write is already
218
+ # fail-open by design (a bypass proceeds either way), so degrading
219
+ # further to "don't write at all" costs nothing beyond the audit
220
+ # trail entry itself, and avoids reintroducing the O_NOFOLLOW gap
221
+ # the shared helper exists to close.
222
+ if not fail_open:
223
+ raise OSError("atomic_state unavailable (degraded import)")
224
+
225
+ def run_safe_git_diff(extra_flags, cwd=None, text=False, target=None): # type: ignore[misc]
226
+ raise OSError("git_safe_diff unavailable (degraded import)")
227
+
228
+ def _is_doc_only_changeset(files: list[str]) -> bool: # type: ignore[misc]
229
+ return False
230
+
231
+ def branch_diff_gate_hash(base_ref: str, cwd=None) -> str: # type: ignore[misc]
232
+ return ""
233
+
234
+ def default_base_ref(cwd=None) -> str: # type: ignore[misc]
235
+ return "HEAD"
236
+
237
+ class _DegradedLedgerEvidence: # type: ignore[misc]
238
+ agents_in_window: frozenset = frozenset()
239
+ any_dispatch_ever = False
240
+ same_subject_dispatch_ever = False
241
+ read_failure_reason = "unreadable"
242
+ dispatch_failure_agents: frozenset | None = None
243
+
244
+ def _evaluate_ledger(cwd, before_ts, window_seconds, subject_hash): # type: ignore[misc]
245
+ return _DegradedLedgerEvidence()
246
+
247
+ def _has_doc_only_exemption( # type: ignore[misc]
248
+ cwd, before_ts, window_seconds, subject_hash
249
+ ) -> bool:
250
+ return False
251
+
252
+ def _has_single_agent_exemption( # type: ignore[misc]
253
+ cwd, before_ts, window_seconds, subject_hash
254
+ ) -> bool:
255
+ return False
256
+
257
+
258
+ def emit_boundary_event(*args, **kwargs) -> None:
259
+ """Local safety net (#859): even a misbehaving helper must never affect
260
+ this hook's exit code, stdout, or stderr."""
261
+ try:
262
+ _emit_boundary_event(*args, **kwargs)
263
+ except Exception: # noqa: BLE001, S110 - fail-open by design
264
+ pass
265
+
266
+
267
+ _GATE_FILE_NAME = ".pr-review-passed"
268
+
269
+ # The env var must be set in a process environment this hook's own process
270
+ # actually inherits — e.g. `export PR_GATE_BYPASS_REASON=<reason>` in your
271
+ # shell profile, or a session-level persistent env config. An inline
272
+ # `PR_GATE_BYPASS_REASON=<reason> gh pr create ...` prefix on the SAME
273
+ # command line does NOT work (#2147): that assignment is scoped to the
274
+ # subshell that runs `gh`, which this PreToolUse hook — a separate process
275
+ # that runs BEFORE that subshell exists — never sees. Confirmed directly
276
+ # against this hook's own architecture (a PreToolUse hook reads
277
+ # `tool_input.command` as text; it does not execute it, and inline shell
278
+ # assignments are never reflected into a sibling process's `os.environ`).
279
+ _BYPASS_HINT = (
280
+ "To bypass: set PR_GATE_BYPASS_REASON as a real, inherited environment "
281
+ "variable before this command runs (e.g. `export "
282
+ "PR_GATE_BYPASS_REASON=<reason>`) — NOT as an inline "
283
+ "`PR_GATE_BYPASS_REASON=<reason> gh pr create ...` prefix on the same "
284
+ "line, which this hook cannot see and will not honor.\n"
285
+ )
286
+
287
+ _BLOCK_MESSAGE = (
288
+ "BLOCKED: Code review required before opening a PR.\n"
289
+ "\n"
290
+ "Run /code-review scoped to this branch's diff vs. its base, then\n"
291
+ "retry `gh pr create` — the PR will be allowed once review passes.\n"
292
+ "\n" + _BYPASS_HINT
293
+ )
294
+
295
+ # Recency window (#1886, mirrors #1461's WINDOW_SECONDS): how far back before
296
+ # `gh pr create`'s own invocation time a genuine review-agent dispatch still
297
+ # counts as corroborating evidence. Anchored on NOW (see module docstring's
298
+ # "Recency window anchor" bullet), not a gate file's mtime.
299
+ WINDOW_SECONDS = 1800
300
+
301
+ # #2147: lowered from 2 to 1 — a single `/code-review` invocation already
302
+ # dispatches a full multi-agent panel internally, so a second, separate
303
+ # top-level dispatch was never additional corroboration. See the module
304
+ # docstring's "`_MIN_DISTINCT_DISPATCHES` was lowered..." paragraph.
305
+ _MIN_DISTINCT_DISPATCHES = 1
306
+
307
+ _NO_DISPATCH_MESSAGE = (
308
+ f"BLOCKED: No genuine review-agent dispatch found in the last "
309
+ f"{WINDOW_SECONDS}s — run /code-review (scoped to this branch's diff "
310
+ f"vs. its base) before opening a PR.\n"
311
+ "\n" + _BYPASS_HINT
312
+ )
313
+
314
+ _STALE_MESSAGE = (
315
+ f"BLOCKED: Review-agent dispatch evidence found but outside the "
316
+ f"{WINDOW_SECONDS}s window — run /code-review again before opening a "
317
+ "PR.\n"
318
+ "\n" + _BYPASS_HINT
319
+ )
320
+
321
+ _DIFFERENT_CONTENT_MESSAGE = (
322
+ "BLOCKED: Review-agent dispatch evidence found, but for different "
323
+ "branch-diff content (the branch changed since that review) — run "
324
+ "/code-review again before opening a PR.\n"
325
+ "\n" + _BYPASS_HINT
326
+ )
327
+
328
+ _READ_FAILURE_MESSAGE = (
329
+ "BLOCKED: Could not read the dispatch ledger "
330
+ "(.claude/metrics/boundary-events.jsonl) — check hook registration; "
331
+ "this is an infra problem, not evidence that no review happened.\n"
332
+ "\n" + _BYPASS_HINT
333
+ )
334
+
335
+ _GATE_SETUP_FAILURE_MESSAGE = (
336
+ "BLOCKED: Could not determine the review-gate's own state (the branch "
337
+ "diff or the .claude/memory/.pr-review-passed path) — check that "
338
+ ".claude/memory is a writable directory and the git repository is "
339
+ "healthy; this is an infra problem, not evidence that no review "
340
+ "happened.\n"
341
+ "\n" + _BYPASS_HINT
342
+ )
343
+
344
+ _REGISTRY_READ_FAILURE_MESSAGE = (
345
+ "BLOCKED: Could not read the registered review-agent set — cannot "
346
+ "prove no dispatch failure exists for this content; this is an infra "
347
+ "problem, not evidence that no review happened.\n"
348
+ "\n" + _BYPASS_HINT
349
+ )
350
+
351
+
352
+ def _insufficient_message(n: int) -> str:
353
+ return (
354
+ f"BLOCKED: Only {n} distinct review agent(s) dispatched (need >= "
355
+ f"{_MIN_DISTINCT_DISPATCHES}) — run /code-review before opening a "
356
+ "PR.\n"
357
+ "\n" + _BYPASS_HINT
358
+ )
359
+
360
+
361
+ def _dispatch_failure_message(agents: frozenset) -> str:
362
+ names = ", ".join(sorted(agents)) or "an unnamed review agent"
363
+ return (
364
+ f"BLOCKED: Dispatch failure recorded for {names} — this is a "
365
+ "dispatch/infra failure, not a code-review finding.\n"
366
+ "\n"
367
+ "Run /code-review again against this same, unchanged branch diff — "
368
+ "a clean rerun clears this block.\n"
369
+ "\n" + _BYPASS_HINT
370
+ )
371
+
372
+
373
+ def _emit_block(message: str) -> None:
374
+ sys.stdout.write(message)
375
+ sys.stderr.write(message)
376
+
377
+
378
+ def _branch_diff_names(base_ref: str, cwd: str | None) -> list[str] | None:
379
+ """Return the branch-diff file list (`git diff <base>...HEAD
380
+ --name-only`), or `None` when git could not be asked at all — same
381
+ `None`-means-"couldn't determine" contract `pre_commit_review.py`'s own
382
+ `_staged_names()` established."""
383
+ try:
384
+ completed = run_safe_git_diff(
385
+ ["--name-only"], cwd=(cwd or None), text=True, target=f"{base_ref}...HEAD"
386
+ )
387
+ except Exception: # noqa: BLE001 - "couldn't determine", not "nothing changed"
388
+ return None
389
+ if completed.returncode != 0:
390
+ return None
391
+ return [line for line in completed.stdout.splitlines() if line]
392
+
393
+
394
+ def _current_branch(cwd: str | None = None) -> str:
395
+ try:
396
+ completed = subprocess.run(
397
+ ["git", "branch", "--show-current"],
398
+ cwd=cwd or None,
399
+ capture_output=True,
400
+ check=False,
401
+ text=True,
402
+ )
403
+ except (FileNotFoundError, OSError):
404
+ return ""
405
+ if completed.returncode != 0:
406
+ return ""
407
+ return completed.stdout.strip()
408
+
409
+
410
+ def _plugin_version() -> str:
411
+ manifest = _HOOK_DIR / ".." / ".claude-plugin" / "plugin.json"
412
+ try:
413
+ data = json.loads(manifest.read_text())
414
+ version = data.get("version")
415
+ if isinstance(version, str) and version:
416
+ return version
417
+ except (OSError, ValueError):
418
+ pass
419
+ return "unknown"
420
+
421
+
422
+ def _record_bypass_audit(reason: str, file_count: int, cwd: str) -> None:
423
+ """Append one accountability line to
424
+ <project-root>/.claude/metrics/gate-bypass-audit.jsonl — the SAME
425
+ stream `pre_commit_review.py`'s `--no-verify` bypass used, distinguished
426
+ by `triggeredBy`. Fail-open: any failure to resolve the path, create the
427
+ directory, or write the line logs a diagnostic to stderr and never
428
+ blocks the PR."""
429
+ entry = {
430
+ "timestamp": datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"),
431
+ "branch": _current_branch(cwd),
432
+ "triggeredBy": "PR_GATE_BYPASS_REASON",
433
+ "reason": reason,
434
+ "stagedFileCount": file_count,
435
+ "pluginVersion": _plugin_version(),
436
+ }
437
+ try:
438
+ audit_log_path = _resolve_file("metrics", "gate-bypass-audit.jsonl", cwd)
439
+ audit_log_path.parent.mkdir(parents=True, exist_ok=True)
440
+ _append_line_locked(
441
+ audit_log_path,
442
+ json.dumps(entry, separators=(",", ":")) + "\n",
443
+ fail_open=False,
444
+ )
445
+ except OSError as exc:
446
+ sys.stderr.write(f"[pre_pr_review] failed to record bypass audit: {exc}\n")
447
+
448
+
449
+ class GateVerdict:
450
+ __slots__ = ("matched_rule", "message", "passed")
451
+
452
+ def __init__(self, passed: bool, message: str = "", matched_rule: str = "") -> None:
453
+ self.passed = passed
454
+ self.message = message
455
+ self.matched_rule = matched_rule
456
+
457
+
458
+ def _stored_gate_hash(gate_file: Path) -> str:
459
+ """Read `.pr-review-passed`'s single line: the raw branch-diff hash.
460
+
461
+ Fails CLOSED on ANY read/decode error (mirrors `pre_commit_review.py`'s
462
+ own `_stored_gate_hashes()` — an unreadable gate file is not a pass).
463
+ """
464
+ try:
465
+ lines = gate_file.read_text(errors="replace").strip().splitlines()
466
+ except Exception: # noqa: BLE001 - fail CLOSED
467
+ return ""
468
+ return lines[0].strip() if lines else ""
469
+
470
+
471
+ def _hash_verdict(gate_file: Path, current_hash: str) -> GateVerdict | None:
472
+ """Lens: the hash-match check, evaluated first — a mismatch (or a
473
+ missing/unreadable gate file) always rejects with `_BLOCK_MESSAGE`,
474
+ regardless of how much genuine dispatch evidence exists.
475
+
476
+ `current_hash == _EMPTY_DIGEST` is rejected with `_GATE_SETUP_FAILURE_MESSAGE`
477
+ rather than treated as an ordinary mismatch (issue #1904 Bug 1) — defense
478
+ in depth alongside `_prepare_gate()`'s own guard, which already refuses to
479
+ hand out an empty-digest `current_hash` in the first place, so this branch
480
+ is not expected to fire via `main()`'s normal call path; it exists so a
481
+ future caller of this function directly can't reintroduce the constant-hash
482
+ collapse by skipping `_prepare_gate()`.
483
+
484
+ Returns a rejecting `GateVerdict` when the hash doesn't match; `None`
485
+ when it matches, meaning "continue to the dispatch-ledger corroboration
486
+ lenses".
487
+ """
488
+ if current_hash == _EMPTY_DIGEST:
489
+ return GateVerdict(False, _GATE_SETUP_FAILURE_MESSAGE, "gate-setup-failure-empty-digest")
490
+ if not gate_file.is_file():
491
+ return GateVerdict(False, _BLOCK_MESSAGE, "pre-pr-review")
492
+ stored = _stored_gate_hash(gate_file)
493
+ if not stored or stored != current_hash:
494
+ return GateVerdict(False, _BLOCK_MESSAGE, "pre-pr-review")
495
+ return None
496
+
497
+
498
+ def _dispatch_failure_verdict(evidence) -> GateVerdict | None:
499
+ """Lens (#1763, reused as-is): the mechanical dispatch-failure veto.
500
+ Takes priority over every exemption AND the terminal distinct-dispatch
501
+ count."""
502
+ if evidence.dispatch_failure_agents is None:
503
+ return GateVerdict(False, _REGISTRY_READ_FAILURE_MESSAGE, "registry-read-failure")
504
+ if evidence.dispatch_failure_agents:
505
+ return GateVerdict(
506
+ False,
507
+ _dispatch_failure_message(evidence.dispatch_failure_agents),
508
+ "dispatch-failure-veto",
509
+ )
510
+ return None
511
+
512
+
513
+ def _doc_only_exemption_verdict(
514
+ cwd: str, before_ts: str, subject_hash: str, files: list[str]
515
+ ) -> GateVerdict | None:
516
+ if _has_doc_only_exemption(
517
+ cwd, before_ts, WINDOW_SECONDS, subject_hash
518
+ ) and _is_doc_only_changeset(files):
519
+ return GateVerdict(True)
520
+ return None
521
+
522
+
523
+ def _single_agent_exemption_verdict(
524
+ cwd: str, before_ts: str, subject_hash: str, n: int
525
+ ) -> GateVerdict | None:
526
+ if n >= 1 and _has_single_agent_exemption(cwd, before_ts, WINDOW_SECONDS, subject_hash):
527
+ return GateVerdict(True)
528
+ return None
529
+
530
+
531
+ def _dispatch_count_verdict(evidence, n: int) -> GateVerdict:
532
+ if n >= _MIN_DISTINCT_DISPATCHES:
533
+ return GateVerdict(True)
534
+ if n >= 1:
535
+ return GateVerdict(False, _insufficient_message(n), "dispatch-evidence-insufficient")
536
+ if evidence.same_subject_dispatch_ever:
537
+ return GateVerdict(False, _STALE_MESSAGE, "dispatch-evidence-stale")
538
+ if evidence.any_dispatch_ever:
539
+ return GateVerdict(
540
+ False, _DIFFERENT_CONTENT_MESSAGE, "dispatch-evidence-different-content"
541
+ )
542
+ return GateVerdict(False, _NO_DISPATCH_MESSAGE, "dispatch-evidence-missing")
543
+
544
+
545
+ def _evaluate_gate(
546
+ gate_file: Path, current_hash: str, cwd: str, files: list[str]
547
+ ) -> GateVerdict:
548
+ """Decide whether `.pr-review-passed` corroborates a genuine, recent,
549
+ multi-agent review of the branch's full diff vs. its base (#1886).
550
+
551
+ A short pipeline over named decision lenses, mirroring
552
+ `pre_commit_review.py`'s own (now-retired) pipeline shape: `_hash_verdict`
553
+ first (always decisive on mismatch), then — only once the hash matches
554
+ and the ledger read succeeds — `_dispatch_failure_verdict`,
555
+ `_doc_only_exemption_verdict`, `_single_agent_exemption_verdict`, and
556
+ finally `_dispatch_count_verdict` as the terminal fallback.
557
+ """
558
+ verdict = _hash_verdict(gate_file, current_hash)
559
+ if verdict is not None:
560
+ return verdict
561
+
562
+ try:
563
+ before_ts = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
564
+
565
+ evidence = _evaluate_ledger(cwd, before_ts, WINDOW_SECONDS, current_hash)
566
+ if evidence.read_failure_reason is not None:
567
+ return GateVerdict(False, _READ_FAILURE_MESSAGE, "dispatch-ledger-read-failure")
568
+
569
+ verdict = _dispatch_failure_verdict(evidence)
570
+ if verdict is not None:
571
+ return verdict
572
+
573
+ n = len(evidence.agents_in_window)
574
+
575
+ verdict = _doc_only_exemption_verdict(cwd, before_ts, current_hash, files)
576
+ if verdict is not None:
577
+ return verdict
578
+
579
+ verdict = _single_agent_exemption_verdict(cwd, before_ts, current_hash, n)
580
+ if verdict is not None:
581
+ return verdict
582
+
583
+ return _dispatch_count_verdict(evidence, n)
584
+ except Exception: # noqa: BLE001 - fail CLOSED: an unexpected error is not a pass
585
+ return GateVerdict(False, _READ_FAILURE_MESSAGE, "dispatch-ledger-read-failure")
586
+
587
+
588
+ def _handle_bypass(cwd: str, file_count: int, session_id) -> int | None:
589
+ """`main()` lens: the `PR_GATE_BYPASS_REASON` bypass. Returns 0 when a
590
+ non-empty reason is set (allowing and auditing the bypass); `None`
591
+ otherwise (not applicable — `main()` continues to the normal gate
592
+ evaluation). There is no separate flag to detect "tried to bypass
593
+ without a reason" (see module docstring) — an unset/empty env var simply
594
+ means the ordinary gate applies."""
595
+ reason = os.environ.get("PR_GATE_BYPASS_REASON", "").strip()
596
+ if not reason:
597
+ return None
598
+ _record_bypass_audit(reason, file_count, cwd)
599
+ emit_boundary_event(cwd, "pre_pr_review", "Bash", "bypass", "PR_GATE_BYPASS_REASON", session_id)
600
+ return 0
601
+
602
+
603
+ def _prepare_gate(cwd: str) -> tuple[str, list[str], Path] | None:
604
+ """`main()` lens: resolve the branch's base ref, the current branch-diff
605
+ hash, its file list, and the `.pr-review-passed` gate-file path,
606
+ creating its parent directory. Returns `(current_hash, files, gate_file)`
607
+ on success; `None` on failure (message/event already emitted).
608
+
609
+ Two additional failure modes, both issue #1904 Bug 1:
610
+
611
+ - `default_base_ref()` returning `None` (the base ref could not be
612
+ resolved at all — a routine state in a shallow/single-branch clone) is
613
+ a hard setup failure, not a reason to fall back to `"HEAD"` and
614
+ evaluate `git diff HEAD...HEAD`, which would succeed with an
615
+ empty-input digest and silently pass the gate.
616
+ - `current_hash == _EMPTY_DIGEST` — whether from the `None`-base-ref
617
+ case above, a genuinely empty branch diff, or any other git failure
618
+ `branch_diff_gate_hash()` fails closed to — is refused outright rather
619
+ than handed to `_hash_verdict()` as an ordinary hash to compare: the
620
+ empty digest is a CONSTANT, and treating it as comparable evidence
621
+ would let one dispatch recorded while nothing was staged corroborate
622
+ any later PR whose gate hash also happens to be empty.
623
+ """
624
+ try:
625
+ base_ref = default_base_ref(cwd)
626
+ if base_ref is None:
627
+ raise OSError("could not resolve the branch's base ref")
628
+ current_hash = branch_diff_gate_hash(base_ref, cwd)
629
+ if current_hash == _EMPTY_DIGEST:
630
+ raise OSError("branch diff hashed to the empty-input digest")
631
+ files = _branch_diff_names(base_ref, cwd)
632
+ if files is None:
633
+ raise OSError("could not determine the branch diff's file list")
634
+ gate_file = _resolve_file("memory", _GATE_FILE_NAME, cwd)
635
+ gate_file.parent.mkdir(parents=True, exist_ok=True)
636
+ return current_hash, files, gate_file
637
+ except Exception: # noqa: BLE001 - fail CLOSED: setup failure is not a pass
638
+ return None
639
+
640
+
641
+ def main() -> int:
642
+ payload = read_stdin_json()
643
+ if payload is None:
644
+ return 0
645
+
646
+ tool_input = payload.get("tool_input") or {}
647
+ if not isinstance(tool_input, dict):
648
+ return 0
649
+ command = str(tool_input.get("command") or "")
650
+
651
+ if not is_gh_pr_create_command(command):
652
+ return 0
653
+
654
+ cwd = payload.get("cwd") or "."
655
+ session_id = payload.get("session_id")
656
+
657
+ prepared = _prepare_gate(cwd)
658
+
659
+ # Bug 2a (#1904): check the bypass BEFORE a gate-setup failure returns —
660
+ # `_GATE_SETUP_FAILURE_MESSAGE` itself documents `PR_GATE_BYPASS_REASON`
661
+ # as the way out, but that was previously unreachable on this path since
662
+ # `_prepare_gate()`'s failure short-circuited before `_handle_bypass()`
663
+ # ever ran. `-1` (module docstring: "branch diff unavailable") is the
664
+ # sentinel file count for the audit record when setup itself failed —
665
+ # there is no real file list to report a count for.
666
+ file_count = len(prepared[1]) if prepared is not None else -1
667
+ bypass_exit_code = _handle_bypass(cwd, file_count, session_id)
668
+ if bypass_exit_code is not None:
669
+ return bypass_exit_code
670
+
671
+ if prepared is None:
672
+ _emit_block(_GATE_SETUP_FAILURE_MESSAGE)
673
+ emit_boundary_event(cwd, "pre_pr_review", "Bash", "block", "gate-setup-failure", session_id)
674
+ return 2
675
+ current_hash, files, gate_file = prepared
676
+
677
+ verdict = _evaluate_gate(gate_file, current_hash, cwd, files)
678
+ if verdict.passed:
679
+ try:
680
+ gate_file.unlink()
681
+ except OSError:
682
+ pass
683
+ return 0
684
+
685
+ _emit_block(verdict.message)
686
+ emit_boundary_event(cwd, "pre_pr_review", "Bash", "block", verdict.matched_rule, session_id)
687
+ return 2
688
+
689
+
690
+ if __name__ == "__main__":
691
+ try:
692
+ sys.exit(main())
693
+ except Exception: # noqa: BLE001 - fail-open: a hook bug must never block a PR
694
+ sys.exit(0)