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,888 @@
1
+ """progress_guardian.py — Python plan validator for the progress-guardian agent.
2
+
3
+ Validates plan step completion, commit discipline, and scope creep.
4
+
5
+ Exit codes:
6
+ 0 = pass (all checks clean)
7
+ 1 = fail (hard errors: missing commits, uncommitted work, incomplete steps)
8
+ 2 = warn (warnings only or LLM check skipped)
9
+
10
+ Usage:
11
+ python3 ${CLAUDE_PLUGIN_ROOT}/scripts/progress_guardian.py --plan <path> [--pre-pr] [--skip-llm]
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ import argparse
17
+ import fnmatch
18
+ import json
19
+ import re
20
+ import subprocess
21
+ import sys
22
+ from dataclasses import dataclass
23
+ from pathlib import Path
24
+
25
+ sys.path.insert(0, str(Path(__file__).parent))
26
+ from lib.review_result import build_result, main_exit, make_issue, skipped_llm_warning
27
+
28
+ # ---------------------------------------------------------------------------
29
+ # Module constants (REFACTOR: extracted for easy maintenance)
30
+ # ---------------------------------------------------------------------------
31
+
32
+ # Matches: - [x] Step 1.1: Header text OR - [ ] Just a header
33
+ STEP_PATTERN = re.compile(r"^-\s+\[( |x|X)\]\s+(?:Step\s+[\d.]+:\s+)?(.+)$")
34
+
35
+ # Matches backtick-quoted paths in plan text (declared file references)
36
+ BACKTICK_PATH_RE = re.compile(r"`([^`\s]+\.[a-zA-Z0-9_]+)`")
37
+
38
+ # Matches backtick-quoted directory declarations (trailing '/'), e.g.
39
+ # `plugins/dev-team/skills/new-feature/`. Kept separate from
40
+ # BACKTICK_PATH_RE so extension-less, non-path backtick tokens (e.g.
41
+ # `runHook()`, `SomeClass`) are never mistaken for declared paths — see
42
+ # issue #713.
43
+ BACKTICK_DIR_RE = re.compile(r"`([^`\s]+/)`")
44
+
45
+ # Matches a slice's `**Files:** ...` declaration line. Captures the
46
+ # remainder of the line so BACKTICK_PATH_RE/BACKTICK_DIR_RE can extract
47
+ # the paths from it.
48
+ SLICE_FILES_RE = re.compile(r"^\*\*Files:\*\*\s*(.+)$")
49
+
50
+
51
+ def _extract_declared_paths(text: str) -> list[str]:
52
+ """Return backtick-quoted file paths and directory paths declared in
53
+ text: exact file paths (ending in a dot-extension) plus directory
54
+ declarations (ending in '/'). A directory declaration means "this
55
+ slice touches things under here" — matched with startswith, not
56
+ equality, by callers. Bare backtick-quoted tokens with no extension
57
+ and no trailing slash (e.g. `` `runHook()` ``) are not paths and are
58
+ intentionally excluded (see issue #713).
59
+ """
60
+ return BACKTICK_PATH_RE.findall(text) + BACKTICK_DIR_RE.findall(text)
61
+
62
+
63
+ def _is_path_declared(file_path: str, declared_paths) -> bool:
64
+ """True if file_path exactly matches a declared file, falls under
65
+ a declared directory (trailing '/') prefix, or matches a declared glob
66
+ pattern (fnmatch, stdlib — issue #865 AC9, e.g. `src/auth/**`). Single
67
+ source of truth shared by check_commit_discipline, check_scope, and
68
+ check_declared_scope_adherence so these checks cannot drift on what
69
+ counts as "declared" (see issue #525/#713/#865).
70
+ """
71
+ for declared in declared_paths:
72
+ if declared.endswith("/"):
73
+ if file_path.startswith(declared):
74
+ return True
75
+ elif file_path == declared or any(ch in declared for ch in "*?[") and fnmatch.fnmatch(
76
+ file_path, declared
77
+ ):
78
+ return True
79
+ return False
80
+
81
+
82
+ # ---------------------------------------------------------------------------
83
+ # Data model
84
+ # ---------------------------------------------------------------------------
85
+
86
+
87
+ @dataclass
88
+ class Step:
89
+ done: bool
90
+ header: str
91
+
92
+
93
+ # ---------------------------------------------------------------------------
94
+ # Helpers
95
+ # ---------------------------------------------------------------------------
96
+
97
+
98
+ def run_git(args: list[str], cwd: str) -> str:
99
+ """Run a git command in cwd, return stdout. Returns '' on failure."""
100
+ try:
101
+ result = subprocess.run(
102
+ ["git"] + args,
103
+ capture_output=True,
104
+ text=True,
105
+ cwd=cwd,
106
+ check=False,
107
+ )
108
+ return result.stdout
109
+ except (FileNotFoundError, OSError):
110
+ return ""
111
+
112
+
113
+ # ---------------------------------------------------------------------------
114
+ # Core checks
115
+ # ---------------------------------------------------------------------------
116
+
117
+
118
+ def parse_plan(path: Path) -> tuple[list[Step], list[dict]]:
119
+ """Parse plan file and return (steps, errors).
120
+
121
+ Scopes checkbox parsing with two flags when a Build Progress section
122
+ exists (issue #525):
123
+
124
+ - `in_build_progress` (outer scope) — when the plan contains a
125
+ `## Build Progress` heading, only lines between that heading and the
126
+ next `## ` H2 are eligible for step parsing. This prevents the
127
+ top-level `## Acceptance Criteria` section's checkboxes from being
128
+ treated as Build Progress steps.
129
+ - `in_acceptance` (inner skip) — within the Build Progress section,
130
+ the `/plan` skill renders a documentation mirror of the top-level
131
+ AC list under a `### Acceptance Criteria` H3 sub-heading. Those
132
+ mirror items lack work-tracking semantics (no `### Slice` heading,
133
+ no `**Files:**` line, no commit subject anchor). They are skipped
134
+ so the pre-PR gate doesn't demand a commit for each one. The
135
+ structural problem behind the workaround is tracked in #526.
136
+
137
+ When no `## Build Progress` heading is present (legacy/minimal plans),
138
+ falls back to whole-file scanning — preserves backward compatibility
139
+ with the pre-existing bats fixtures that construct minimal plans.
140
+
141
+ Returns an error finding (naming the file) if no checkboxes found.
142
+ """
143
+ text = path.read_text(encoding="utf-8")
144
+
145
+ # First, see whether the plan has a `## Build Progress` heading. If it
146
+ # does, narrow the scan to that section only. Otherwise, scan the whole
147
+ # file (preserves backward compatibility with plans that don't carry
148
+ # the section structure).
149
+ lines = text.splitlines()
150
+ has_build_progress = any(
151
+ line.rstrip().startswith("## Build Progress") for line in lines
152
+ )
153
+
154
+ steps: list[Step] = []
155
+ in_build_progress = not has_build_progress # legacy plans: scan everything
156
+ in_acceptance = False
157
+ for raw in lines:
158
+ line = raw.rstrip()
159
+ if has_build_progress:
160
+ if line.startswith("## Build Progress"):
161
+ in_build_progress = True
162
+ in_acceptance = False
163
+ continue
164
+ # Any other H2 closes the section.
165
+ if in_build_progress and line.startswith("## "):
166
+ in_build_progress = False
167
+ continue
168
+ # The `### Acceptance Criteria` subheading inside Build Progress
169
+ # is a documentation mirror — the same items appear in the
170
+ # top-level `## Acceptance Criteria`. Skip its checkboxes so
171
+ # they don't demand commits of their own. The structural
172
+ # redesign of where ACs live is tracked in #526; this PR
173
+ # ships the workaround so the gate stops false-positiving.
174
+ if in_build_progress and line.startswith("### Acceptance Criteria"):
175
+ in_acceptance = True
176
+ continue
177
+ # Any other H3 within Build Progress exits the AC subsection.
178
+ if in_acceptance and line.startswith("### "):
179
+ in_acceptance = False
180
+ if not in_build_progress or in_acceptance:
181
+ continue
182
+ m = STEP_PATTERN.match(line)
183
+ if m:
184
+ flag, header = m.group(1), m.group(2).strip()
185
+ steps.append(Step(done=(flag.lower() == "x"), header=header))
186
+
187
+ if not steps:
188
+ return [], [
189
+ make_issue(
190
+ "error",
191
+ message=f"No checkbox steps found in plan file: {path.name}",
192
+ file=str(path),
193
+ suggested_fix="Add steps with '- [ ] Step N.M: description' format.",
194
+ )
195
+ ]
196
+ return steps, []
197
+
198
+
199
+ def _parse_slice_files(plan_text: str, slice_header: str) -> list[str]:
200
+ """Return backtick-quoted paths from the `**Files:**` line declared
201
+ under the slice identified by `slice_header`. Empty list when not found.
202
+
203
+ Two layouts are supported:
204
+ 1. **Heading-anchored** (the /plan skill convention): the slice is
205
+ declared with `### Slice N: title` and `**Files:** ...` lives in
206
+ that section's body. Build Progress checkboxes mirror the heading
207
+ text — we match the heading and scan forward.
208
+ 2. **Inline** (minimal plans): `- [x] Slice N: title` followed by a
209
+ `**Files:** ...` line in the same checkbox block. Scan forward
210
+ from the checkbox until another checkbox or a heading.
211
+
212
+ Heading-anchored is tried first because real plans always use it. The
213
+ inline form preserves a smaller fixture surface for tests and the
214
+ minimal plans the existing bats fixtures construct.
215
+ """
216
+ lines = plan_text.splitlines()
217
+
218
+ # Try heading-anchored layout first.
219
+ in_block = False
220
+ for raw in lines:
221
+ line = raw.rstrip()
222
+ if line.startswith("### ") and line[4:].strip() == slice_header:
223
+ in_block = True
224
+ continue
225
+ if not in_block:
226
+ continue
227
+ if line.startswith(("## ", "### ")):
228
+ break
229
+ fm = SLICE_FILES_RE.match(line)
230
+ if fm:
231
+ return _extract_declared_paths(fm.group(1))
232
+
233
+ # Fall back to inline layout: `**Files:**` line near a `- [x] <header>`.
234
+ in_block = False
235
+ for raw in lines:
236
+ line = raw.rstrip()
237
+ m = STEP_PATTERN.match(line)
238
+ if m:
239
+ header = m.group(2).strip()
240
+ if header == slice_header:
241
+ in_block = True
242
+ continue
243
+ if in_block:
244
+ # A different checkbox closes the block.
245
+ break
246
+ if not in_block:
247
+ continue
248
+ if line.startswith(("## ", "### ")):
249
+ break
250
+ fm = SLICE_FILES_RE.match(line)
251
+ if fm:
252
+ return _extract_declared_paths(fm.group(1))
253
+ return []
254
+
255
+
256
+ def _branch_base_sha(repo_root: str) -> str | None:
257
+ """Resolve the branch base SHA (the merge-base with trunk).
258
+
259
+ Prefers remote tracking refs over local refs — local main lags
260
+ origin/main the moment any work begins. Returns None when no
261
+ trunk-like ref resolves to a divergence point; callers should
262
+ treat None as "no meaningful branch base — use whole history."
263
+ See issue #525.
264
+ """
265
+ head_sha = run_git(["rev-parse", "HEAD"], repo_root).strip()
266
+ for branch in ("origin/main", "origin/master", "main", "master"):
267
+ out = run_git(["merge-base", "HEAD", branch], repo_root).strip()
268
+ if out and out != head_sha:
269
+ return out
270
+ return None
271
+
272
+
273
+ def check_commit_discipline(
274
+ steps: list[Step], repo_root: str, plan_text: str = ""
275
+ ) -> list[dict]:
276
+ """For each done step, verify a matching commit exists on this branch.
277
+
278
+ Two strategies, tried in order per step:
279
+ 1. **File-path match (preferred).** When the slice declares
280
+ `**Files:** ...`, pass when any commit since the branch base
281
+ touched one of the declared files. This decouples the gate
282
+ from commit-subject wording so Conventional Commits work.
283
+ 2. **Substring fallback.** When the slice has no `**Files:**`
284
+ line (legacy plans), pass when any commit subject since the
285
+ branch base contains the slice header. Same matcher as before,
286
+ but scoped to `<base>..HEAD` so both strategies see the same
287
+ commit range (cannot diverge — see issue #525).
288
+
289
+ Returns error findings for any done step with no matching commit.
290
+ """
291
+ done_steps = [s for s in steps if s.done]
292
+ if not done_steps:
293
+ return []
294
+
295
+ base_sha = _branch_base_sha(repo_root)
296
+
297
+ # Build the commit range. When no base resolves (orphan HEAD), fall
298
+ # back to whole-history matching so legacy behavior is preserved.
299
+ if base_sha:
300
+ range_arg = f"{base_sha}..HEAD"
301
+ log_subjects_out = run_git(
302
+ ["log", "--no-merges", "--format=%s", range_arg], repo_root
303
+ )
304
+ else:
305
+ range_arg = "HEAD"
306
+ log_subjects_out = run_git(
307
+ ["log", "--no-merges", "--format=%s", "HEAD"], repo_root
308
+ )
309
+ if not log_subjects_out.strip():
310
+ # Zero commits on this branch — emit a warning, not a hard error.
311
+ return [
312
+ make_issue(
313
+ "warning",
314
+ message="No commits found on this branch — cannot verify commit discipline.",
315
+ suggested_fix="Commit work before marking steps done.",
316
+ )
317
+ ]
318
+ commit_subjects = [
319
+ s.lower() for s in log_subjects_out.strip().splitlines() if s.strip()
320
+ ]
321
+
322
+ # Collect file paths touched by commits in the range (file-path path).
323
+ if base_sha:
324
+ diff_out = run_git(["diff", "--name-only", range_arg], repo_root)
325
+ else:
326
+ diff_out = run_git(
327
+ ["log", "--name-only", "--pretty=format:", "HEAD"], repo_root
328
+ )
329
+ branch_files = {p for p in diff_out.strip().splitlines() if p.strip()}
330
+
331
+ errors: list[dict] = []
332
+ for step in done_steps:
333
+ declared = _parse_slice_files(plan_text, step.header) if plan_text else []
334
+ if declared:
335
+ # File-path path: pass when any declared file was touched on
336
+ # this branch, or any branch file falls under a declared
337
+ # directory (see issue #713).
338
+ if any(_is_path_declared(bf, declared) for bf in branch_files):
339
+ continue
340
+ errors.append(
341
+ make_issue(
342
+ "error",
343
+ message=(
344
+ f"Done step '{step.header}' has no matching commit in git log. "
345
+ f"Expected a commit on this branch that touched one of: "
346
+ f"{', '.join(declared)}"
347
+ ),
348
+ suggested_fix=(
349
+ f"Commit your work touching one of the declared files "
350
+ f"({', '.join(declared)}) before marking '{step.header}' done."
351
+ ),
352
+ )
353
+ )
354
+ continue
355
+ # Substring fallback: no `**Files:**` declared.
356
+ header_lower = step.header.lower()
357
+ if not any(header_lower in subject for subject in commit_subjects):
358
+ errors.append(
359
+ make_issue(
360
+ "error",
361
+ message=(
362
+ f"Done step '{step.header}' has no matching commit in git log. "
363
+ f"Expected a commit whose subject contains: '{step.header}'"
364
+ ),
365
+ suggested_fix=(
366
+ f"Commit your work with a message containing '{step.header}' "
367
+ f"before marking this step done."
368
+ ),
369
+ )
370
+ )
371
+ return errors
372
+
373
+
374
+ def check_uncommitted(
375
+ repo_root: str, exclude_paths: list[str] | None = None
376
+ ) -> list[dict]:
377
+ """Check for staged or unstaged changes. Returns an error if any exist.
378
+
379
+ exclude_paths: relative or absolute paths to ignore (e.g. the plan file itself).
380
+ """
381
+ status_output = run_git(["status", "--porcelain"], repo_root)
382
+ if not status_output.strip():
383
+ return []
384
+
385
+ # Filter out excluded paths
386
+ excluded = set(exclude_paths or [])
387
+ non_excluded_lines = []
388
+ for line in status_output.strip().splitlines():
389
+ if not line.strip():
390
+ continue
391
+ parts = line.strip().split(None, 1)
392
+ file_path = parts[1].strip() if len(parts) == 2 else ""
393
+ # Normalize: check both basename and full relative path
394
+ if file_path and file_path not in excluded:
395
+ import os
396
+
397
+ basename = os.path.basename(file_path)
398
+ if basename not in excluded:
399
+ non_excluded_lines.append(line)
400
+
401
+ if non_excluded_lines:
402
+ return [
403
+ make_issue(
404
+ "error",
405
+ message=(
406
+ "Uncommitted changes detected. All work must be committed "
407
+ "before plan steps can be considered complete."
408
+ ),
409
+ suggested_fix="Run 'git add' and 'git commit' to commit outstanding work.",
410
+ )
411
+ ]
412
+ return []
413
+
414
+
415
+ def check_pre_pr(steps: list[Step]) -> list[dict]:
416
+ """Assert all steps are done (checked). Returns error for each undone step."""
417
+ errors: list[dict] = []
418
+ for step in steps:
419
+ if not step.done:
420
+ errors.append(
421
+ make_issue(
422
+ "error",
423
+ message=(
424
+ f"Pre-PR gate: step '{step.header}' is not done ([ ] unchecked). "
425
+ f"All plan steps must be complete before opening a PR."
426
+ ),
427
+ suggested_fix=f"Complete and commit work for '{step.header}', then mark it [x].",
428
+ )
429
+ )
430
+ return errors
431
+
432
+
433
+ VERIFY_LOG_PATH = "metrics/verify-log.jsonl"
434
+
435
+ # Test-file indicators — kept in sync with knowledge/test-file-indicators.md
436
+ # so this Python check and the /build skill's prose classification agree on
437
+ # what counts as "a test" (see issue #727).
438
+ _TEST_NAME_RE = re.compile(r"\.(test|spec)\.[^./]+$")
439
+ _TEST_DIR_FRAGMENTS = ("__tests__/",)
440
+ _STEP_DEFINITION_RE = re.compile(
441
+ r"(\.steps\.[^./]+$|StepDefinitions\.[^./]+$|Steps\.[^./]+$)", re.IGNORECASE
442
+ )
443
+ _TEST_CLASS_NAME_RE = re.compile(r"(Test|Tests|TestCase|Spec)\.java$")
444
+ _TEST_ATTRIBUTE_RE = re.compile(
445
+ r"\[Fact\]|\[Theory\]|\[TestCase\]|\[TestMethod\]|\[TestClass\]|"
446
+ r"(?<!Parameterized)(?<!Factory)\[Test\]|@Test\b|@ParameterizedTest|@TestFactory"
447
+ )
448
+
449
+ # Docs/config files never carry a runtime surface — no source ever executes
450
+ # from them, so a diff touching only these (plus tests) has nothing for
451
+ # /verify to drive.
452
+ _DOC_CONFIG_SUFFIXES = {
453
+ ".md",
454
+ ".mdx",
455
+ ".txt",
456
+ ".rst",
457
+ ".adoc",
458
+ ".yml",
459
+ ".yaml",
460
+ ".toml",
461
+ ".ini",
462
+ ".cfg",
463
+ ".editorconfig",
464
+ }
465
+ _DOC_CONFIG_BASENAMES = {
466
+ "LICENSE",
467
+ "LICENSE.txt",
468
+ ".gitignore",
469
+ ".gitattributes",
470
+ "CODEOWNERS",
471
+ }
472
+
473
+
474
+ def _is_test_file(path: str, repo_root: str) -> bool:
475
+ """True when `path` looks like a test per knowledge/test-file-indicators.md."""
476
+ if path.endswith(".feature"):
477
+ return True
478
+ if _TEST_NAME_RE.search(path):
479
+ return True
480
+ if any(frag in path for frag in _TEST_DIR_FRAGMENTS):
481
+ return True
482
+ if _STEP_DEFINITION_RE.search(path):
483
+ return True
484
+ if _TEST_CLASS_NAME_RE.search(path):
485
+ return True
486
+ suffix = Path(path).suffix.lower()
487
+ if suffix in (".cs", ".java"):
488
+ # Attribute-based test detection needs the file's content — best
489
+ # effort only, and only when the file still exists on disk.
490
+ try:
491
+ content = (Path(repo_root) / path).read_text(
492
+ encoding="utf-8", errors="replace"
493
+ )
494
+ except OSError:
495
+ return False
496
+ if _TEST_ATTRIBUTE_RE.search(content):
497
+ return True
498
+ return False
499
+
500
+
501
+ def _is_doc_or_config_file(path: str) -> bool:
502
+ if path.startswith("metrics/") and path.endswith(".jsonl"):
503
+ return True
504
+ if Path(path).name in _DOC_CONFIG_BASENAMES:
505
+ return True
506
+ return Path(path).suffix.lower() in _DOC_CONFIG_SUFFIXES
507
+
508
+
509
+ def has_runtime_surface(changed_files: list[str], repo_root: str) -> bool:
510
+ """True when at least one changed file is neither a test file nor a
511
+ docs/config file — i.e. there is something for /verify to exercise.
512
+ """
513
+ return any(
514
+ not _is_test_file(f, repo_root) and not _is_doc_or_config_file(f)
515
+ for f in changed_files
516
+ )
517
+
518
+
519
+ def _collect_branch_changed_files(repo_root: str) -> list[str]:
520
+ """All files changed on this branch: the committed diff since the
521
+ branch base, plus any currently uncommitted (staged/unstaged) files.
522
+ Mirrors check_scope's branch-scope resolution (issue #727).
523
+ """
524
+ base_ref = _branch_base_sha(repo_root)
525
+ if not base_ref:
526
+ base_ref = run_git(["rev-list", "--max-parents=0", "HEAD"], repo_root).strip()
527
+
528
+ diff_output = (
529
+ run_git(["diff", "--name-only", base_ref + "..HEAD"], repo_root)
530
+ if base_ref
531
+ else ""
532
+ )
533
+ changed_files = (
534
+ set(diff_output.strip().splitlines()) if diff_output.strip() else set()
535
+ )
536
+
537
+ status_output = run_git(["status", "--porcelain"], repo_root)
538
+ for line in status_output.strip().splitlines():
539
+ if line.strip():
540
+ parts = line.strip().split(None, 1)
541
+ if len(parts) == 2:
542
+ changed_files.add(parts[1].strip())
543
+
544
+ return sorted(changed_files)
545
+
546
+
547
+ def check_verify_log(repo_root: str, changed_files: list[str]) -> list[dict]:
548
+ """Pre-PR gate (issue #727): if the branch touches any runtime-surface
549
+ file (not exclusively tests/docs/config), require at least one entry
550
+ in metrics/verify-log.jsonl for the current branch — evidence that
551
+ `/verify` ran (or was explicitly skipped with a reason) before the
552
+ slice was marked done. Fails closed, the same way an incomplete step
553
+ or a missing commit does.
554
+ """
555
+ if not changed_files or not has_runtime_surface(changed_files, repo_root):
556
+ return []
557
+
558
+ branch = run_git(["rev-parse", "--abbrev-ref", "HEAD"], repo_root).strip()
559
+ log_path = Path(repo_root) / VERIFY_LOG_PATH
560
+
561
+ entries: list[dict] = []
562
+ if log_path.exists():
563
+ for raw_line in log_path.read_text(encoding="utf-8").splitlines():
564
+ raw_line = raw_line.strip()
565
+ if not raw_line:
566
+ continue
567
+ try:
568
+ entries.append(json.loads(raw_line))
569
+ except ValueError:
570
+ continue
571
+
572
+ if any(entry.get("branch") == branch for entry in entries):
573
+ return []
574
+
575
+ return [
576
+ make_issue(
577
+ "error",
578
+ message=(
579
+ "Pre-PR gate: this branch touches runtime-surface file(s) but no "
580
+ f"entry in {VERIFY_LOG_PATH} matches branch '{branch}'. `/verify` "
581
+ "(or an explicit skip-with-reason) is required before a PR can be "
582
+ "opened."
583
+ ),
584
+ suggested_fix=(
585
+ "Run /verify against the branch's changed runtime files (or record "
586
+ "a skipped:<reason> entry if the diff genuinely has no runtime "
587
+ f"surface to drive), then append the outcome to {VERIFY_LOG_PATH}."
588
+ ),
589
+ )
590
+ ]
591
+
592
+
593
+ def _all_slice_headers(steps: list[Step]) -> list[str]:
594
+ """Return the subset of Build Progress checkbox headers that are slice
595
+ headers (`"Slice N: <title>"`), not step headers — the shape
596
+ `_parse_slice_files` expects (issue #865 AC8)."""
597
+ return [s.header for s in steps if s.header.startswith("Slice ")]
598
+
599
+
600
+ def check_declared_scope_adherence(
601
+ steps: list[Step], plan_path: Path, repo_root: str, plan_text: str
602
+ ) -> list[dict]:
603
+ """Issue #865 AC8: compare the branch diff against the union of every
604
+ slice's declared `**Files:**` scope (fnmatch-aware, glob-capable).
605
+
606
+ This is a **named WARNING only** — never a pre-PR gate failure. When a
607
+ plan opts into `Scope enforcement: freeze` (see `build_slice_scope.py`),
608
+ freeze itself is the real enforcement mechanism (a blocked Write/Edit);
609
+ this check exists for the *unfrozen* case, where out-of-scope edits are
610
+ otherwise invisible until `/code-review` or a human catches them.
611
+
612
+ Deterministic — no LLM call, unlike `check_scope` (which reasons about
613
+ *all* backtick-quoted paths in the plan prose). A plan with no slice
614
+ declaring `**Files:**` has nothing to compare against and returns `[]`.
615
+ """
616
+ declared: list[str] = []
617
+ for header in _all_slice_headers(steps):
618
+ declared.extend(_parse_slice_files(plan_text, header))
619
+ if not declared:
620
+ return []
621
+
622
+ changed_files = _collect_branch_changed_files(repo_root)
623
+ plan_name = plan_path.name
624
+ changed_files = [
625
+ f
626
+ for f in changed_files
627
+ if f != plan_name
628
+ and not f.endswith(plan_name)
629
+ and not (f.startswith("metrics/") and f.endswith(".jsonl"))
630
+ and not f.startswith("memory/")
631
+ ]
632
+ if not changed_files:
633
+ return []
634
+
635
+ out_of_scope = sorted(f for f in changed_files if not _is_path_declared(f, declared))
636
+ if not out_of_scope:
637
+ return []
638
+
639
+ return [
640
+ make_issue(
641
+ "warning",
642
+ message=(
643
+ "Scope adherence: out-of-scope edit(s) without freeze: "
644
+ f"{', '.join(out_of_scope)} not covered by any slice's declared "
645
+ f"Files ({', '.join(sorted(set(declared)))})."
646
+ ),
647
+ suggested_fix=(
648
+ "Reconcile the plan's Files declarations, or engage scope "
649
+ "enforcement (`**Scope enforcement:** freeze`) so out-of-scope "
650
+ "writes are blocked rather than merely warned about."
651
+ ),
652
+ rule_id="declared-scope-warning",
653
+ )
654
+ ]
655
+
656
+
657
+ def check_scope(plan_path: Path, repo_root: str, skip_llm: bool) -> list[dict]:
658
+ """Detect files in the branch diff that aren't declared in the plan.
659
+
660
+ Declared paths are backtick-quoted filenames in the plan text.
661
+ Compares all files touched in commits since the branch diverged from its
662
+ base (merge-base with HEAD~N or the root commit) plus any uncommitted files.
663
+
664
+ With --skip-llm: adds llm-skipped warning instead of calling LLM.
665
+ LLM unavailability always produces a warning, never an error.
666
+ """
667
+ text = plan_path.read_text(encoding="utf-8")
668
+ declared_paths = set(_extract_declared_paths(text))
669
+
670
+ # Single source of truth for base-ref resolution — shared with
671
+ # check_commit_discipline so the two checks cannot drift on what
672
+ # counts as "trunk" (see issue #525). When no meaningful divergence
673
+ # point exists (no remote, no local trunk), fall back to the root
674
+ # commit so check_scope can still flag every file touched in the repo.
675
+ base_ref = _branch_base_sha(repo_root)
676
+ if not base_ref:
677
+ base_ref = run_git(["rev-list", "--max-parents=0", "HEAD"], repo_root).strip()
678
+
679
+ # Collect files changed in commits since base_ref
680
+ if base_ref:
681
+ diff_output = run_git(["diff", "--name-only", base_ref + "..HEAD"], repo_root)
682
+ else:
683
+ diff_output = ""
684
+ changed_files = (
685
+ set(diff_output.strip().splitlines()) if diff_output.strip() else set()
686
+ )
687
+
688
+ # Also collect uncommitted files from status
689
+ status_output = run_git(["status", "--porcelain"], repo_root)
690
+ for line in status_output.strip().splitlines():
691
+ if line.strip():
692
+ # porcelain format: XY <path>
693
+ parts = line.strip().split(None, 1)
694
+ if len(parts) == 2:
695
+ changed_files.add(parts[1].strip())
696
+
697
+ # Exclude the plan file itself from scope check, along with append-only
698
+ # metrics artifacts (e.g. review-value.jsonl, verify-log.jsonl) — these
699
+ # are pipeline instrumentation the plan never declares by name, not
700
+ # plan-scoped work product (issue #727).
701
+ plan_name = plan_path.name
702
+ plan_rel = str(plan_path)
703
+ changed_files = {
704
+ f
705
+ for f in changed_files
706
+ if f != plan_name
707
+ and f != plan_rel
708
+ and not f.endswith(plan_name)
709
+ and not (f.startswith("metrics/") and f.endswith(".jsonl"))
710
+ }
711
+
712
+ if not changed_files:
713
+ return []
714
+
715
+ # If no declared paths, any changed file is potentially out-of-plan.
716
+ # Otherwise a file is "declared" (not out-of-plan) if it exactly
717
+ # matches a declared file or falls under a declared directory prefix
718
+ # (see issue #713).
719
+ out_of_plan = (
720
+ changed_files
721
+ if not declared_paths
722
+ else {f for f in changed_files if not _is_path_declared(f, declared_paths)}
723
+ )
724
+
725
+ if not out_of_plan:
726
+ return []
727
+
728
+ # We have out-of-plan files — check with LLM or emit skipped warning
729
+ if skip_llm:
730
+ return [
731
+ skipped_llm_warning(
732
+ message=(
733
+ f"LLM check skipped (--skip-llm): {len(out_of_plan)} file(s) not declared "
734
+ f"in plan may represent scope creep — manual review required."
735
+ )
736
+ )
737
+ ]
738
+
739
+ # Call LLM for scope assessment
740
+ file_list = ", ".join(sorted(out_of_plan))
741
+ prompt = (
742
+ f"These files were changed but are not declared in the plan '{plan_path.name}': "
743
+ f"{file_list}. "
744
+ f"Is this likely scope creep or acceptable collateral changes? "
745
+ f'Reply with a brief JSON assessment: {{"scope_creep": true/false, "reason": "..."}}.'
746
+ )
747
+ try:
748
+ result = subprocess.run(
749
+ ["claude", "-p", prompt],
750
+ capture_output=True,
751
+ text=True,
752
+ timeout=60,
753
+ check=False,
754
+ )
755
+ if result.returncode != 0 or not result.stdout.strip():
756
+ return [
757
+ make_issue(
758
+ "warning",
759
+ message=(
760
+ f"LLM scope check unavailable: {len(out_of_plan)} file(s) not in plan "
761
+ f"({file_list}) — manual scope review recommended."
762
+ ),
763
+ )
764
+ ]
765
+ return [
766
+ make_issue(
767
+ "warning",
768
+ message=(
769
+ f"Scope check (LLM): {len(out_of_plan)} out-of-plan file(s): "
770
+ f"{file_list}. LLM assessment: {result.stdout.strip()[:300]}"
771
+ ),
772
+ )
773
+ ]
774
+ except (FileNotFoundError, subprocess.TimeoutExpired, OSError):
775
+ return [
776
+ make_issue(
777
+ "warning",
778
+ message=(
779
+ f"LLM scope check unavailable (claude not on PATH or timed out): "
780
+ f"{len(out_of_plan)} file(s) not declared in plan — manual review needed."
781
+ ),
782
+ )
783
+ ]
784
+
785
+
786
+ # ---------------------------------------------------------------------------
787
+ # Main
788
+ # ---------------------------------------------------------------------------
789
+
790
+
791
+ def main(argv: list[str] | None = None) -> int:
792
+ parser = argparse.ArgumentParser(
793
+ description="Validate plan step completion and commit discipline."
794
+ )
795
+ parser.add_argument("--plan", required=True, help="Path to the plan markdown file.")
796
+ parser.add_argument(
797
+ "--pre-pr",
798
+ action="store_true",
799
+ help="Assert all plan steps are complete (pre-PR gate).",
800
+ )
801
+ parser.add_argument(
802
+ "--skip-llm",
803
+ action="store_true",
804
+ help="Skip LLM scope check and emit a warning finding instead.",
805
+ )
806
+ args = parser.parse_args(argv)
807
+
808
+ plan_path = Path(args.plan).resolve()
809
+ if not plan_path.exists():
810
+ result = build_result(
811
+ errors=[
812
+ make_issue(
813
+ "error",
814
+ message=f"Plan file not found: {args.plan}",
815
+ file=args.plan,
816
+ )
817
+ ],
818
+ warnings=[],
819
+ )
820
+ return main_exit(result)
821
+
822
+ # Resolve the git repo root from the plan file's directory.
823
+ # Falls back to the plan file's parent if not in a git repo.
824
+ repo_root_output = run_git(
825
+ ["rev-parse", "--show-toplevel"], str(plan_path.parent)
826
+ ).strip()
827
+ repo_root = repo_root_output if repo_root_output else str(plan_path.parent)
828
+
829
+ errors: list[dict] = []
830
+ warnings: list[dict] = []
831
+
832
+ # 1. Parse plan checkboxes
833
+ steps, parse_errors = parse_plan(plan_path)
834
+ errors.extend(parse_errors)
835
+
836
+ # Pre-read the plan text once so check_commit_discipline can locate
837
+ # per-slice `**Files:**` declarations (file-path matcher path).
838
+ plan_text = plan_path.read_text(encoding="utf-8")
839
+ if not parse_errors:
840
+ # 2. Uncommitted change check (always runs; ignore the plan file itself)
841
+ uncommitted_issues = check_uncommitted(
842
+ repo_root, exclude_paths=[plan_path.name]
843
+ )
844
+ errors.extend(uncommitted_issues)
845
+
846
+ # 3. Commit discipline (runs regardless of uncommitted state — both issues matter)
847
+ commit_issues = check_commit_discipline(steps, repo_root, plan_text)
848
+ for issue in commit_issues:
849
+ if issue["severity"] == "error":
850
+ errors.append(issue)
851
+ else:
852
+ warnings.append(issue)
853
+
854
+ # 4. Scope creep check (only when tree is clean — avoids double-counting uncommitted)
855
+ if not uncommitted_issues:
856
+ scope_issues = check_scope(plan_path, repo_root, args.skip_llm)
857
+ for issue in scope_issues:
858
+ if issue["severity"] == "error":
859
+ errors.append(issue)
860
+ else:
861
+ warnings.append(issue)
862
+
863
+ # 5. Pre-PR gate (runs regardless of uncommitted state)
864
+ if args.pre_pr:
865
+ pre_pr_issues = check_pre_pr(steps)
866
+ errors.extend(pre_pr_issues)
867
+
868
+ # 6. Verify-log gate (issue #727): runtime-surface changes need
869
+ # evidence /verify ran before the PR can be opened.
870
+ verify_changed_files = _collect_branch_changed_files(repo_root)
871
+ verify_issues = check_verify_log(repo_root, verify_changed_files)
872
+ errors.extend(verify_issues)
873
+
874
+ # 7. Declared-scope adherence (issue #865 AC8): named warning
875
+ # only, never a gate failure — freeze (when engaged) is the
876
+ # real enforcement mechanism.
877
+ warnings.extend(
878
+ check_declared_scope_adherence(
879
+ steps, plan_path, repo_root, plan_text
880
+ )
881
+ )
882
+
883
+ result = build_result(errors, warnings)
884
+ return main_exit(result)
885
+
886
+
887
+ if __name__ == "__main__":
888
+ sys.exit(main())