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,228 @@
1
+ #!/usr/bin/env python3
2
+ """bash_retry_guard — Claude Code PreToolUse hook (Python port of bash-retry-guard.sh).
3
+
4
+ Detects repeated identical Bash commands within a session. After THRESHOLD
5
+ consecutive identical commands, nudges the agent to vary its approach
6
+ rather than re-running the same failing command.
7
+
8
+ Contract (docs/python-hook-contract.md):
9
+ Input : PreToolUse JSON on stdin
10
+ Output: advisory nudge on stdout when threshold reached
11
+ Exit : always 0 (advisory — never blocks)
12
+ Env : DEV_TEAM_BASH_RETRY_THRESHOLD (default 3; 0 disables)
13
+
14
+ State is persisted per-session under $TMPDIR/dev-team-bash-retry/<key>.json
15
+ where <key> is the session_id when present, else a cksum of $cwd. Files
16
+ are tiny and short-lived — no cleanup story needed beyond the OS's tmp
17
+ sweeping.
18
+
19
+ Stdlib-only. See #591 / #572 Phase 3.
20
+ """
21
+
22
+ from __future__ import annotations
23
+
24
+ import json
25
+ import os
26
+ import re
27
+ import sys
28
+ import tempfile
29
+ import time
30
+ import zlib
31
+ from pathlib import Path
32
+ from typing import Any
33
+
34
+ _HOOK_DIR = Path(__file__).resolve().parent
35
+ _LIB_DIR = _HOOK_DIR / "lib"
36
+
37
+ sys.path.insert(0, str(_LIB_DIR))
38
+ try:
39
+ from atomic_state import ( # type: ignore[import-not-found]
40
+ atomic_write,
41
+ locked_state,
42
+ race_window_delay,
43
+ )
44
+ from boundary_events import ( # type: ignore[import-not-found]
45
+ emit_boundary_event as _emit_boundary_event,
46
+ )
47
+ from stdin_json import read_stdin_json # type: ignore[import-not-found]
48
+ except ImportError: # pragma: no cover
49
+ import contextlib as _contextlib
50
+
51
+ def read_stdin_json() -> dict | None: # type: ignore[misc]
52
+ return None
53
+
54
+ def _emit_boundary_event(*_args, **_kwargs) -> None: # type: ignore[misc]
55
+ return None
56
+
57
+ def atomic_write(path: Path, text: str) -> None: # type: ignore[misc]
58
+ try:
59
+ path.write_text(text, encoding="utf-8")
60
+ except OSError:
61
+ pass
62
+
63
+ @_contextlib.contextmanager
64
+ def locked_state(_path: Path): # type: ignore[misc]
65
+ yield
66
+
67
+ def race_window_delay(_env_var: str) -> None: # type: ignore[misc]
68
+ return None
69
+
70
+
71
+ def emit_boundary_event(*args, **kwargs) -> None:
72
+ """Local safety net (#859): even a misbehaving helper must never affect
73
+ this hook's exit code, stdout, or stderr."""
74
+ try:
75
+ _emit_boundary_event(*args, **kwargs)
76
+ except Exception: # noqa: BLE001, S110 - fail-open by design
77
+ pass
78
+
79
+
80
+ # Verify-family commands — the verify-guard hook handles retry-nudging for
81
+ # these; this hook must not double-warn. The pattern MUST match the .sh's
82
+ # ERE byte-for-byte.
83
+ _VERIFY_RE = re.compile(
84
+ r"\b(npm (run )?(test|lint|build)|pytest|bats|eslint|tsc|"
85
+ r"go test|cargo (test|build)|mvn|gradle|make( |$)|vitest|"
86
+ r"jest|ruff|mypy|shellcheck)\b"
87
+ )
88
+
89
+ # Trivially short / read-only commands that retry harmlessly. Matches the
90
+ # `case` list in the .sh.
91
+ _READ_ONLY_FIRST_TOKENS = {"ls", "pwd", "echo", "cat", "head", "tail", "grep"}
92
+
93
+ _STATE_DIRNAME = "dev-team-bash-retry"
94
+
95
+ # Same TTL-purge-on-write pattern as tdd_guard.py / mutation_adapters/lib.py
96
+ # (#732) — one state file is written per session with no expiry otherwise,
97
+ # so long-lived hosts accumulate a file per session forever.
98
+ _STATE_TTL_SECONDS = 14400 # 4 hours
99
+
100
+
101
+ def _cksum(text: str) -> str:
102
+ """POSIX cksum-compatible hash for state-key/hash purposes.
103
+
104
+ The .sh uses `cksum` (POSIX CRC + length). We use zlib.crc32 as a
105
+ stable stdlib hash — byte-parity with the .sh is NOT required here
106
+ because the state file is a private per-session artifact never
107
+ surfaced to the user or committed to the repo. Determinism within
108
+ the Python port is sufficient.
109
+ """
110
+ return str(zlib.crc32(text.encode("utf-8")) & 0xFFFFFFFF)
111
+
112
+
113
+ def _normalize(cmd: str) -> str:
114
+ """Collapse runs of whitespace to a single space and trim ends."""
115
+ return re.sub(r"\s+", " ", cmd).strip()
116
+
117
+
118
+ def _first_token(cmd: str) -> str:
119
+ trimmed = _normalize(cmd)
120
+ if not trimmed:
121
+ return ""
122
+ return trimmed.split(" ", 1)[0]
123
+
124
+
125
+ def _should_skip(cmd: str) -> bool:
126
+ """True when this command class is out of scope (verify family or read-only)."""
127
+ if _VERIFY_RE.search(cmd):
128
+ return True
129
+ return _first_token(cmd) in _READ_ONLY_FIRST_TOKENS
130
+
131
+
132
+ def _state_key(session_id: str, cwd: str) -> str:
133
+ if session_id:
134
+ return session_id
135
+ return _cksum(cwd or os.getcwd())
136
+
137
+
138
+ def _purge_stale(state_dir: Path) -> None:
139
+ if not state_dir.is_dir():
140
+ return
141
+ now = time.time()
142
+ for path in state_dir.glob("*.json"):
143
+ try:
144
+ if now - path.stat().st_mtime > _STATE_TTL_SECONDS:
145
+ path.unlink()
146
+ except OSError:
147
+ pass
148
+
149
+
150
+ def _state_file(state_key: str) -> Path:
151
+ tmp = Path(os.environ.get("TMPDIR", tempfile.gettempdir()))
152
+ state_dir = tmp / _STATE_DIRNAME
153
+ state_dir.mkdir(parents=True, exist_ok=True)
154
+ _purge_stale(state_dir)
155
+ return state_dir / f"{state_key}.json"
156
+
157
+
158
+ def _read_state(path: Path) -> dict[str, Any]:
159
+ if not path.is_file():
160
+ return {"hash": "", "count": 0}
161
+ try:
162
+ data = json.loads(path.read_text(encoding="utf-8"))
163
+ except (OSError, json.JSONDecodeError):
164
+ return {"hash": "", "count": 0}
165
+ return {
166
+ "hash": str(data.get("hash", "") or ""),
167
+ "count": int(data.get("count", 0) or 0),
168
+ }
169
+
170
+
171
+ def _write_state(path: Path, state: dict[str, Any]) -> None:
172
+ # Atomic (tempfile + rename) so a concurrent reader never sees a torn
173
+ # file. The read-increment-write cycle is additionally serialized under
174
+ # locked_state() in main() (#1501). Best-effort — advisory hook.
175
+ atomic_write(path, json.dumps(state, separators=(",", ":")))
176
+
177
+
178
+ def main() -> int:
179
+ payload = read_stdin_json()
180
+ if payload is None:
181
+ return 0
182
+
183
+ tool_input = payload.get("tool_input") or {}
184
+ command = str(tool_input.get("command") or "")
185
+ if not command:
186
+ return 0
187
+
188
+ if _should_skip(command):
189
+ return 0
190
+
191
+ threshold = int(os.environ.get("DEV_TEAM_BASH_RETRY_THRESHOLD", "3") or "3")
192
+ if threshold <= 0:
193
+ # 0 disables the nudge entirely. Skip state accounting so a later
194
+ # non-zero threshold doesn't fire on stale state.
195
+ return 0
196
+
197
+ session_id = str(payload.get("session_id") or "")
198
+ cwd = str(payload.get("cwd") or "")
199
+ state_key = _state_key(session_id, cwd)
200
+ state_path = _state_file(state_key)
201
+
202
+ normalized = _normalize(command)
203
+ cur_hash = _cksum(normalized)
204
+
205
+ # Serialize the read-increment-write so two concurrent invocations of the
206
+ # same command (e.g. a shared-cwd state key across two sessions) each add
207
+ # exactly one to the consecutive-run count instead of racing and losing an
208
+ # increment (#1501). Fail-open: an unlockable environment runs unlocked.
209
+ with locked_state(state_path):
210
+ prev = _read_state(state_path)
211
+ if cur_hash == prev["hash"]:
212
+ count = prev["count"] + 1
213
+ else:
214
+ count = 1
215
+ race_window_delay("DEV_TEAM_BASH_RETRY_TEST_DELAY_MS")
216
+ _write_state(state_path, {"hash": cur_hash, "count": count})
217
+
218
+ if count >= threshold:
219
+ print(f"bash-retry-guard: This command has run {count} consecutive times.")
220
+ print(" If it keeps failing, investigate the root cause rather than retrying.")
221
+ print(" Set DEV_TEAM_BASH_RETRY_THRESHOLD=0 to disable this warning.")
222
+ emit_boundary_event(cwd, "bash_retry_guard", "Bash", "warn", "bash-retry-threshold", session_id)
223
+
224
+ return 0
225
+
226
+
227
+ if __name__ == "__main__":
228
+ sys.exit(main())
@@ -0,0 +1,352 @@
1
+ #!/usr/bin/env python3
2
+ """boundary_events_write_guard.py — Claude Code PreToolUse hook (#2171).
3
+
4
+ `.claude/metrics/boundary-events.jsonl` is the plugin's boundary-level
5
+ accountability ledger (`hooks/lib/boundary_events.py`, #859) — every guard
6
+ hook's block/warn/bypass decision is recorded there, and that module's own
7
+ docstring states rows must never carry free text (command text, prompt
8
+ text, file paths, reasons), only rule IDs from closed vocabularies. A
9
+ direct `Write` or `Edit` tool call targeting that file bypasses
10
+ `emit_boundary_event()` entirely and could forge or corrupt that record
11
+ from inside the session — this hook raises the cost of that forgery the
12
+ same way `pre_tool_guard.py` raises it for other sensitive paths, by
13
+ blocking a Write/Edit whose `file_path`/`path` resolves to the ledger.
14
+
15
+ Step 1.1 of plans/2164-verdict-ledger-writer.md added the Write/Edit
16
+ path-match guard. Step 1.2 extends this same module to also inspect Bash
17
+ `tool_input.command` text for write-shaped commands (redirect, `tee`,
18
+ `sed -i`, `cp`/`mv`/`rm`/`truncate`/`dd`, or a write/append/exclusive-mode
19
+ Python `open()`) that target the ledger by filename, in any path form —
20
+ see `bash_command_writes_to_ledger()` and `_BASH_WRITE_SHAPE_PATTERNS`
21
+ below. The hook is registered in `settings.json`'s existing `Write|Edit`
22
+ and `Bash` `PreToolUse` matcher groups.
23
+
24
+ Contract (docs/python-hook-contract.md):
25
+ Input : PreToolUse JSON on stdin — for Write/Edit, `tool_input.file_path`
26
+ or `tool_input.path`, resolved relative to `cwd` when not
27
+ absolute; for Bash, `tool_input.command`
28
+ Output: block message on stdout. The Write/Edit-path message names
29
+ `emit_boundary_event()` (`hooks/lib/boundary_events.py`) as the
30
+ remedy — a Python-only function unreachable from a shell
31
+ command. The Bash-path message instead names the
32
+ `hooks/lib/boundary_events.py` CLI's actual invocable shape
33
+ (`python3 plugins/dev-team/hooks/lib/boundary_events.py --event
34
+ <event> --subject-hash <hash> ...`, #1461) — the message
35
+ interpolates the live `<event>` choice set from
36
+ `boundary_events.cli_event_names()` rather than restating it
37
+ here, so this docstring never drifts the way the message
38
+ itself used to (review finding, #2171). `--event` is a flag
39
+ drawn from a closed `choices` set, not a positional, and most
40
+ events require `--subject-hash`; the CLI cannot construct an
41
+ arbitrary row by design — a genuinely custom row still needs
42
+ `emit_boundary_event()` called from a hook (plan-review-ux
43
+ finding, Step 1.2, corrected by review).
44
+ Exit : 2 to block, 0 to allow. Fail-open on any exception (malformed
45
+ payload, unreadable cwd, unresolvable repo root) — never raises.
46
+
47
+ Path matching is lexical only (`os.path.abspath` — `.`/`..` collapsing, no
48
+ symlink following): a symlink-escape sandbox is explicitly out of scope
49
+ (plan Step 1.1 TEST note) — this guard raises the cost of forgery, it does
50
+ not sandbox the filesystem. One narrow exception: `targets_ledger()`
51
+ resolves the `cwd` anchor itself via `os.path.realpath` before joining a
52
+ relative `file_path` against it (review finding — see `targets_ledger()`'s
53
+ own docstring) so that anchor stays symmetric with the ledger side, which
54
+ already passes through `git rev-parse --show-toplevel`'s own symlink
55
+ resolution via `artifact_paths.resolve_file()`/`project_root()`. Everything
56
+ beyond that single anchor — the rest of the joined path, and all Bash
57
+ command-text matching below — stays purely lexical, no further symlink
58
+ following.
59
+
60
+ Stdlib-only. See ADR 0014.
61
+ """
62
+
63
+ from __future__ import annotations
64
+
65
+ import os
66
+ import re
67
+ import sys
68
+ from pathlib import Path
69
+
70
+ _HOOK_DIR = Path(__file__).resolve().parent
71
+ _LIB_DIR = _HOOK_DIR / "lib"
72
+ if str(_LIB_DIR) not in sys.path:
73
+ sys.path.insert(0, str(_LIB_DIR))
74
+
75
+ import artifact_paths
76
+ from boundary_events import LOG_NAME as _LEDGER_NAME
77
+ from boundary_events import cli_event_names as _cli_event_names
78
+ from boundary_events import emit_boundary_event as _emit_boundary_event
79
+ from stdin_json import read_stdin_json # type: ignore[import-not-found]
80
+
81
+
82
+ def emit_boundary_event(*args, **kwargs) -> None:
83
+ """Local safety net (#859): even a misbehaving helper must never affect
84
+ this hook's exit code, stdout, or stderr."""
85
+ try:
86
+ _emit_boundary_event(*args, **kwargs)
87
+ except Exception: # noqa: BLE001, S110 - fail-open by design
88
+ pass
89
+
90
+
91
+ def _extract_file_path(tool_input: object) -> str:
92
+ """Return `tool_input.file_path`, `tool_input.path`, or empty string —
93
+ mirrors `pre_tool_guard._extract_file_path`'s field-preference order."""
94
+ if not isinstance(tool_input, dict):
95
+ return ""
96
+ file_path = tool_input.get("file_path")
97
+ if isinstance(file_path, str) and file_path:
98
+ return file_path
99
+ path = tool_input.get("path")
100
+ if isinstance(path, str) and path:
101
+ return path
102
+ return ""
103
+
104
+
105
+ def targets_ledger(file_path: str, cwd: str) -> bool:
106
+ """True when `file_path` (joined against `cwd` if not absolute) names
107
+ the same on-disk path `emit_boundary_event()` itself resolves and
108
+ writes to — `artifact_paths.resolve_file("metrics", ...)` under the
109
+ repo root, not a bare `.claude/metrics/` prefix match (so
110
+ `review-verdicts.jsonl`, Slice 2's own store, is unaffected) — OR the
111
+ pre-migration legacy path `<project-root>/metrics/boundary-events.jsonl`
112
+ (review finding, #2171): `resolve_file(..., migrate=True)`, the default
113
+ every `emit_boundary_event()` call uses, `shutil.move`s an untracked
114
+ file at that legacy path into the ledger the *next* time anything
115
+ emits, whenever the new-location file does not yet exist. Matching
116
+ only the new-location path would let a Write/Edit plant a forged file
117
+ at the legacy path — invisible to this guard — that a later, entirely
118
+ legitimate `emit_boundary_event()` call then silently promotes into
119
+ ledger history. Both candidates must be blocked for the guard's
120
+ forgery-cost claim to hold.
121
+
122
+ The `cwd` anchor is realpath'd before the join (review finding): the
123
+ ledger side already resolves symlinks transparently, because
124
+ `artifact_paths.resolve_file()` -> `project_root()` finds the repo root
125
+ via `git rev-parse --show-toplevel`, and git itself resolves a
126
+ symlinked `cwd` to its real location. Joining `file_path` against the
127
+ *unresolved* `cwd` string, then comparing both sides with only
128
+ `os.path.abspath` (no symlink resolution), left the two sides
129
+ comparing a symlinked-form candidate against a resolved-form ledger —
130
+ a real, if narrow, false negative on a symlinked `cwd`. Resolving only
131
+ the `cwd` anchor keeps this guard's `os.path.abspath` comparison the
132
+ same symmetric idiom `pre_tool_guard.py` uses elsewhere, without
133
+ resolving symlinks anywhere else in the path (module docstring)."""
134
+ if not file_path:
135
+ return False
136
+ base = Path(os.path.realpath(cwd)) if cwd else Path.cwd()
137
+ candidate = Path(file_path)
138
+ if not candidate.is_absolute():
139
+ candidate = base / candidate
140
+ candidate_norm = os.path.abspath(str(candidate))
141
+
142
+ # Cheap lexical pre-check (performance review finding, #2171): every
143
+ # candidate this function can match ends in `_LEDGER_NAME` — skip the
144
+ # `git rev-parse` subprocess `resolve_stream()`/`project_root()` incur
145
+ # for the overwhelming majority of Write/Edit calls that plainly don't.
146
+ if os.path.basename(candidate_norm) != _LEDGER_NAME:
147
+ return False
148
+
149
+ ledger = artifact_paths.resolve_file(
150
+ "metrics", _LEDGER_NAME, Path(cwd) if cwd else Path.cwd(), migrate=False
151
+ )
152
+ ledger_norm = os.path.abspath(str(ledger))
153
+ if candidate_norm == ledger_norm:
154
+ return True
155
+
156
+ legacy_ledger = artifact_paths.project_root(start=cwd) / "metrics" / _LEDGER_NAME
157
+ legacy_norm = os.path.abspath(str(legacy_ledger))
158
+
159
+ return candidate_norm == legacy_norm
160
+
161
+
162
+ def _extract_command(tool_input: object) -> str:
163
+ """Return `tool_input.command`, or empty string — mirrors
164
+ `destructive_guard._extract_command`'s field access."""
165
+ if not isinstance(tool_input, dict):
166
+ return ""
167
+ command = tool_input.get("command")
168
+ return command if isinstance(command, str) else ""
169
+
170
+
171
+ # Any prefix of path characters ending in the ledger's literal filename.
172
+ # Matches the filename in every ordinary path form the plan requires
173
+ # (relative, absolute, "./"-prefixed, bare after a `cd .claude/metrics`
174
+ # prefix, `~/`-prefixed, `$VAR`/`${VAR}`-expanded, or a quoted path
175
+ # containing a space), since all of those literally end in this substring.
176
+ # Widening this class is not an attempt at obfuscation-grade path matching
177
+ # (shell escapes, `$(...)` substitution, base64-encoded paths, etc. remain
178
+ # out of scope — see the module docstring's "heuristic, not a sandbox"
179
+ # note); it only covers path forms a real command would ordinarily write.
180
+ _LEDGER_PATH_SUFFIX = r"[\w./~${} -]*" + re.escape(_LEDGER_NAME)
181
+
182
+ # Bash write-shaped patterns targeting the ledger (Step 1.2, #2171). Each
183
+ # pattern embeds `_LEDGER_PATH_SUFFIX` directly, so a match always means the
184
+ # command's write operation targets the ledger specifically — not merely
185
+ # that the ledger's filename appears somewhere unrelated in the command
186
+ # (e.g. `cat boundary-events.jsonl | tee /tmp/copy.txt` reads the ledger and
187
+ # writes elsewhere; it does not match the `tee` pattern below because
188
+ # `tee`'s own argument is `/tmp/copy.txt`, not the ledger). Heuristic, not a
189
+ # sandbox — see the plan's Risks note ("raises the cost of forgery," per
190
+ # #2171's Out of Scope). Mirrors destructive_guard.py's own pattern-table
191
+ # idiom (a module-level constant, one comment per pattern).
192
+ _BASH_WRITE_SHAPE_PATTERNS: tuple[re.Pattern, ...] = (
193
+ # `>`/`>>` redirect whose target is the ledger. Also catches a
194
+ # heredoc's trailing redirect operator (`cat <<'EOF' >> ...`) — the
195
+ # heredoc `<<` marker itself is never parsed or matched (plan Decision
196
+ # note); detection is via this same trailing operator, like any other
197
+ # write-shaped command.
198
+ re.compile(rf">{{1,2}}\s*['\"]?{_LEDGER_PATH_SUFFIX}"),
199
+ # `tee` writing to the ledger, within the same shell statement (same
200
+ # same-statement scoping as the cp/mv/rm pattern below) — the ledger
201
+ # can be any of tee's operands (`tee /tmp/log boundary-events.jsonl`),
202
+ # not just its first.
203
+ re.compile(rf"\btee\b[^;|&\n]*['\"]?{_LEDGER_PATH_SUFFIX}"),
204
+ # `sed -i`/`sed --in-place` (in-place edit) targeting the ledger, within
205
+ # the same shell statement (stops at `;`/`|`/`&` so an unrelated later
206
+ # statement that happens to also mention the ledger doesn't
207
+ # false-positive).
208
+ re.compile(
209
+ rf"\bsed\b[^;|&\n]*(?:-i\b|--in-place\b)[^;|&\n]*['\"]?{_LEDGER_PATH_SUFFIX}"
210
+ ),
211
+ # cp/mv/rm/truncate/dd targeting the ledger, within the same shell
212
+ # statement (same same-statement scoping as the sed pattern above).
213
+ re.compile(rf"\b(?:cp|mv|rm|truncate|dd)\b[^;|&\n]*{_LEDGER_PATH_SUFFIX}"),
214
+ # A Python `open(...)` call on the ledger using any mode that permits
215
+ # writing: "w"/"a"/"x" (optionally suffixed, e.g. "wb"/"a+"/"x+"), or a
216
+ # "+" read-write mode such as "r+"/"rb+"/"r+b" — any mode string
217
+ # containing w/a/x/+ can write. The mode may be positional or the
218
+ # keyword form (`mode='a'`). "Allowed" means read-ONLY: a mode-omitted
219
+ # (default "r") or explicit pure-"r" `open()` never matches this
220
+ # pattern — not "read-mode" generically, since "r+" is a read-*and*-
221
+ # write mode despite starting with "r".
222
+ re.compile(
223
+ rf"open\(\s*['\"]{_LEDGER_PATH_SUFFIX}['\"]\s*,\s*"
224
+ r"(?:mode\s*=\s*)?['\"][^'\"]*[wax+][^'\"]*['\"]"
225
+ ),
226
+ )
227
+
228
+
229
+ def bash_command_writes_to_ledger(command: str) -> bool:
230
+ """True when `command` is write-shaped AND targets the ledger by
231
+ filename, in any path form — see `_BASH_WRITE_SHAPE_PATTERNS`. A
232
+ read-shaped command referencing the same filename (`cat`, `grep`,
233
+ `tail`, `head`, a read-mode `open()`) never matches any pattern here,
234
+ so it is allowed without a separate read-allowlist check.
235
+
236
+ O(n) fast path first (security review finding, #2171): every pattern in
237
+ `_BASH_WRITE_SHAPE_PATTERNS` requires the literal `_LEDGER_NAME`
238
+ substring, so a command that lacks it cannot match any of them — this
239
+ is semantically equivalent to running the patterns, not a heuristic
240
+ shortcut. Skipping straight to `False` on a long non-matching command
241
+ (e.g. a `rm` of padding data) avoids the patterns' overlapping
242
+ `[^;|&\\n]*`/path-suffix character classes backtracking quadratically
243
+ on input that was never going to match."""
244
+ if not command or _LEDGER_NAME not in command:
245
+ return False
246
+ return any(pattern.search(command) for pattern in _BASH_WRITE_SHAPE_PATTERNS)
247
+
248
+
249
+ def _block(
250
+ cwd: str,
251
+ tool: str,
252
+ session_id: str | None,
253
+ blocked_message: str,
254
+ remedy_message: str,
255
+ ) -> int:
256
+ """Shared block sequence for both `main()` branches: record the guard's
257
+ own decision (every sibling guard does — see the module docstring),
258
+ print the block explanation, and return the block exit code.
259
+
260
+ Mirrors every line to stderr in addition to stdout (docs/python-hook-
261
+ contract.md § stderr, "Exception — exit-2 (block) messages"): some
262
+ Claude Code hook-error wrappers surface only stderr on a nonzero hook
263
+ exit, so a stdout-only block message can go unseen there. Stdout stays
264
+ the canonical channel; stderr is additive duplication for this exit-2
265
+ path only — this is a new hook, so it converges to the documented
266
+ standard from the start rather than joining the stdout-only legacy list."""
267
+ emit_boundary_event(
268
+ cwd, "boundary_events_write_guard", tool, "block", "ledger-write-blocked", session_id
269
+ )
270
+ lines = (
271
+ blocked_message,
272
+ (
273
+ "This file is the boundary-events accountability ledger (#859) — "
274
+ "it is append-only from the session's perspective."
275
+ ),
276
+ remedy_message,
277
+ )
278
+ for line in lines:
279
+ print(line)
280
+ for line in lines:
281
+ print(line, file=sys.stderr)
282
+ return 2
283
+
284
+
285
+ def _handle_bash_tool(payload: dict, cwd: str, session_id: str | None) -> int:
286
+ command = _extract_command(payload.get("tool_input"))
287
+ if not bash_command_writes_to_ledger(command):
288
+ return 0
289
+
290
+ events = "|".join(_cli_event_names())
291
+ return _block(
292
+ cwd,
293
+ "Bash",
294
+ session_id,
295
+ f"BLOCKED: This Bash command writes to '.claude/metrics/{_LEDGER_NAME}', "
296
+ "which is not allowed.",
297
+ "Use 'python3 plugins/dev-team/hooks/lib/boundary_events.py "
298
+ f"--event <{events}> "
299
+ "--subject-hash <hash> ...' instead of writing to it from Bash — "
300
+ "an arbitrary row isn't CLI-constructible by design (that CLI only "
301
+ "accepts a closed --event vocabulary); this exact row needs a "
302
+ "Python-side hook change instead.",
303
+ )
304
+
305
+
306
+ def _handle_write_edit_tool(
307
+ payload: dict, cwd: str, tool: str, session_id: str | None
308
+ ) -> int:
309
+ file_path = _extract_file_path(payload.get("tool_input"))
310
+ if not file_path:
311
+ return 0
312
+
313
+ if not targets_ledger(file_path, cwd):
314
+ return 0
315
+
316
+ return _block(
317
+ cwd,
318
+ tool,
319
+ session_id,
320
+ f"BLOCKED: Direct write to '{file_path}' is not allowed.",
321
+ "Use emit_boundary_event() in plugins/dev-team/hooks/lib/boundary_events.py "
322
+ "instead of writing to it directly.",
323
+ )
324
+
325
+
326
+ def main() -> int:
327
+ try:
328
+ payload = read_stdin_json()
329
+ if payload is None:
330
+ return 0
331
+
332
+ raw_cwd = payload.get("cwd")
333
+ cwd = (
334
+ raw_cwd
335
+ if isinstance(raw_cwd, str) and raw_cwd and "\0" not in raw_cwd
336
+ else "."
337
+ )
338
+ raw_tool = payload.get("tool_name")
339
+ tool = raw_tool if isinstance(raw_tool, str) and raw_tool else "Write"
340
+ raw_session_id = payload.get("session_id")
341
+ session_id = raw_session_id if isinstance(raw_session_id, str) else None
342
+
343
+ if tool == "Bash":
344
+ return _handle_bash_tool(payload, cwd, session_id)
345
+
346
+ return _handle_write_edit_tool(payload, cwd, tool, session_id)
347
+ except Exception: # noqa: BLE001 - fail-open by design, see module docstring
348
+ return 0
349
+
350
+
351
+ if __name__ == "__main__": # pragma: no cover
352
+ sys.exit(main())