@pareto4/pp-core 1.5.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 (618) hide show
  1. package/.claude-plugin/plugin.json +23 -0
  2. package/GEMINI.md +53 -0
  3. package/LICENSE +22 -0
  4. package/README.md +100 -0
  5. package/agents/pp-advisor-researcher.md +108 -0
  6. package/agents/pp-ai-researcher.md +114 -0
  7. package/agents/pp-assumptions-analyzer.md +105 -0
  8. package/agents/pp-code-fixer.md +669 -0
  9. package/agents/pp-code-reviewer.md +387 -0
  10. package/agents/pp-codebase-mapper.md +853 -0
  11. package/agents/pp-debug-session-manager.md +315 -0
  12. package/agents/pp-debugger.md +1453 -0
  13. package/agents/pp-doc-classifier.md +168 -0
  14. package/agents/pp-doc-synthesizer.md +204 -0
  15. package/agents/pp-doc-verifier.md +217 -0
  16. package/agents/pp-doc-writer.md +616 -0
  17. package/agents/pp-domain-researcher.md +147 -0
  18. package/agents/pp-eval-auditor.md +191 -0
  19. package/agents/pp-eval-planner.md +154 -0
  20. package/agents/pp-executor.md +808 -0
  21. package/agents/pp-framework-selector.md +160 -0
  22. package/agents/pp-integration-checker.md +470 -0
  23. package/agents/pp-intel-updater.md +339 -0
  24. package/agents/pp-mempalace-curator.md +47 -0
  25. package/agents/pp-nyquist-auditor.md +204 -0
  26. package/agents/pp-pattern-mapper.md +335 -0
  27. package/agents/pp-phase-researcher.md +867 -0
  28. package/agents/pp-plan-checker.md +988 -0
  29. package/agents/pp-planner.md +1052 -0
  30. package/agents/pp-project-researcher.md +612 -0
  31. package/agents/pp-research-synthesizer.md +260 -0
  32. package/agents/pp-roadmapper.md +741 -0
  33. package/agents/pp-security-auditor.md +156 -0
  34. package/agents/pp-ui-auditor.md +495 -0
  35. package/agents/pp-ui-checker.md +309 -0
  36. package/agents/pp-ui-researcher.md +375 -0
  37. package/agents/pp-user-profiler.md +171 -0
  38. package/agents/pp-verifier.md +967 -0
  39. package/assets/gsd-logo-2000-transparent.png +0 -0
  40. package/assets/gsd-logo-2000-transparent.svg +17 -0
  41. package/assets/gsd-logo-2000.png +0 -0
  42. package/assets/gsd-logo-2000.svg +21 -0
  43. package/assets/terminal.svg +68 -0
  44. package/bin/install.js +12370 -0
  45. package/bin/lib/ui-safety-gate.cjs +107 -0
  46. package/commands/pp-add-tests.md +42 -0
  47. package/commands/pp-ai-integration-phase.md +37 -0
  48. package/commands/pp-audit-fix.md +34 -0
  49. package/commands/pp-audit-milestone.md +37 -0
  50. package/commands/pp-audit-uat.md +24 -0
  51. package/commands/pp-autonomous.md +51 -0
  52. package/commands/pp-capture.md +62 -0
  53. package/commands/pp-cleanup.md +24 -0
  54. package/commands/pp-code-review.md +59 -0
  55. package/commands/pp-complete-milestone.md +143 -0
  56. package/commands/pp-config.md +56 -0
  57. package/commands/pp-debug.md +52 -0
  58. package/commands/pp-discovery.md +34 -0
  59. package/commands/pp-discuss-phase.md +77 -0
  60. package/commands/pp-docs-update.md +49 -0
  61. package/commands/pp-eval-review.md +33 -0
  62. package/commands/pp-execute-phase.md +65 -0
  63. package/commands/pp-explore.md +27 -0
  64. package/commands/pp-extract-learnings.md +23 -0
  65. package/commands/pp-fast.md +31 -0
  66. package/commands/pp-forensics.md +57 -0
  67. package/commands/pp-graphify.md +204 -0
  68. package/commands/pp-health.md +31 -0
  69. package/commands/pp-help.md +28 -0
  70. package/commands/pp-import.md +45 -0
  71. package/commands/pp-inbox.md +39 -0
  72. package/commands/pp-ingest-docs.md +42 -0
  73. package/commands/pp-manager.md +45 -0
  74. package/commands/pp-map-codebase.md +83 -0
  75. package/commands/pp-mempalace-capture.md +71 -0
  76. package/commands/pp-mempalace-recall.md +102 -0
  77. package/commands/pp-milestone-summary.md +51 -0
  78. package/commands/pp-mvp-phase.md +45 -0
  79. package/commands/pp-new-milestone.md +45 -0
  80. package/commands/pp-new-project.md +47 -0
  81. package/commands/pp-ns-context.md +25 -0
  82. package/commands/pp-ns-ideate.md +24 -0
  83. package/commands/pp-ns-manage.md +36 -0
  84. package/commands/pp-ns-project.md +27 -0
  85. package/commands/pp-ns-review.md +29 -0
  86. package/commands/pp-ns-workflow.md +35 -0
  87. package/commands/pp-pause-work.md +43 -0
  88. package/commands/pp-phase.md +56 -0
  89. package/commands/pp-plan-phase.md +63 -0
  90. package/commands/pp-plan-review-convergence.md +60 -0
  91. package/commands/pp-pr-branch.md +26 -0
  92. package/commands/pp-profile-user.md +46 -0
  93. package/commands/pp-progress.md +49 -0
  94. package/commands/pp-quick.md +174 -0
  95. package/commands/pp-resume-work.md +30 -0
  96. package/commands/pp-review-backlog.md +63 -0
  97. package/commands/pp-review.md +42 -0
  98. package/commands/pp-secure-phase.md +36 -0
  99. package/commands/pp-settings.md +29 -0
  100. package/commands/pp-ship.md +24 -0
  101. package/commands/pp-sketch.md +60 -0
  102. package/commands/pp-spec-phase.md +63 -0
  103. package/commands/pp-spike.md +57 -0
  104. package/commands/pp-stats.md +20 -0
  105. package/commands/pp-surface.md +162 -0
  106. package/commands/pp-thread.md +24 -0
  107. package/commands/pp-ui-phase.md +35 -0
  108. package/commands/pp-ui-review.md +33 -0
  109. package/commands/pp-ultraplan-phase.md +34 -0
  110. package/commands/pp-undo.md +35 -0
  111. package/commands/pp-update.md +49 -0
  112. package/commands/pp-validate-phase.md +36 -0
  113. package/commands/pp-verify-work.md +39 -0
  114. package/commands/pp-workspace.md +52 -0
  115. package/commands/pp-workstreams.md +70 -0
  116. package/gemini-extension.json +6 -0
  117. package/hooks/dist/lib/git-cmd.js +150 -0
  118. package/hooks/dist/lib/pp-graphify-rebuild.sh +65 -0
  119. package/hooks/dist/managed-hooks-registry.cjs +39 -0
  120. package/hooks/dist/pp-check-update-worker.js +108 -0
  121. package/hooks/dist/pp-check-update.js +66 -0
  122. package/hooks/dist/pp-config-reload.js +133 -0
  123. package/hooks/dist/pp-context-monitor.js +196 -0
  124. package/hooks/dist/pp-cursor-post-tool.js +75 -0
  125. package/hooks/dist/pp-cursor-session-start.js +52 -0
  126. package/hooks/dist/pp-ensure-canonical-path.js +305 -0
  127. package/hooks/dist/pp-graphify-update.sh +158 -0
  128. package/hooks/dist/pp-phase-boundary.sh +47 -0
  129. package/hooks/dist/pp-prompt-guard.js +97 -0
  130. package/hooks/dist/pp-read-guard.js +101 -0
  131. package/hooks/dist/pp-read-injection-scanner.js +203 -0
  132. package/hooks/dist/pp-session-state.sh +59 -0
  133. package/hooks/dist/pp-statusline.js +566 -0
  134. package/hooks/dist/pp-update-banner.js +138 -0
  135. package/hooks/dist/pp-validate-commit.sh +57 -0
  136. package/hooks/dist/pp-workflow-guard.js +167 -0
  137. package/hooks/dist/pp-worktree-path-guard.js +185 -0
  138. package/hooks/hooks.json +70 -0
  139. package/hooks/lib/git-cmd.js +150 -0
  140. package/hooks/lib/pp-graphify-rebuild.sh +65 -0
  141. package/hooks/managed-hooks-registry.cjs +39 -0
  142. package/hooks/pp-check-update-worker.js +108 -0
  143. package/hooks/pp-check-update.js +66 -0
  144. package/hooks/pp-config-reload.js +133 -0
  145. package/hooks/pp-context-monitor.js +196 -0
  146. package/hooks/pp-cursor-post-tool.js +75 -0
  147. package/hooks/pp-cursor-session-start.js +52 -0
  148. package/hooks/pp-ensure-canonical-path.js +305 -0
  149. package/hooks/pp-graphify-update.sh +158 -0
  150. package/hooks/pp-phase-boundary.sh +47 -0
  151. package/hooks/pp-prompt-guard.js +97 -0
  152. package/hooks/pp-read-guard.js +101 -0
  153. package/hooks/pp-read-injection-scanner.js +203 -0
  154. package/hooks/pp-session-state.sh +59 -0
  155. package/hooks/pp-statusline.js +566 -0
  156. package/hooks/pp-update-banner.js +138 -0
  157. package/hooks/pp-validate-commit.sh +57 -0
  158. package/hooks/pp-workflow-guard.js +167 -0
  159. package/hooks/pp-worktree-path-guard.js +185 -0
  160. package/package.json +125 -0
  161. package/pp-core/bin/check-latest-version.cjs +161 -0
  162. package/pp-core/bin/lib/active-workstream-store.cjs +297 -0
  163. package/pp-core/bin/lib/adr-parser.cjs +399 -0
  164. package/pp-core/bin/lib/agent-command-router.cjs +68 -0
  165. package/pp-core/bin/lib/agent-install-check.cjs +143 -0
  166. package/pp-core/bin/lib/artifacts.cjs +51 -0
  167. package/pp-core/bin/lib/audit-command-router.cjs +61 -0
  168. package/pp-core/bin/lib/audit.cjs +743 -0
  169. package/pp-core/bin/lib/capability-activation.cjs +113 -0
  170. package/pp-core/bin/lib/capability-registry.cjs +3727 -0
  171. package/pp-core/bin/lib/capability-state.cjs +497 -0
  172. package/pp-core/bin/lib/capability-writer.cjs +355 -0
  173. package/pp-core/bin/lib/check-command-router.cjs +800 -0
  174. package/pp-core/bin/lib/cjs-command-router-adapter.cjs +81 -0
  175. package/pp-core/bin/lib/cli-exit.cjs +61 -0
  176. package/pp-core/bin/lib/clock.cjs +95 -0
  177. package/pp-core/bin/lib/clusters.cjs +131 -0
  178. package/pp-core/bin/lib/code-review-flags.cjs +59 -0
  179. package/pp-core/bin/lib/command-aliases.cjs +809 -0
  180. package/pp-core/bin/lib/command-arg-projection.cjs +55 -0
  181. package/pp-core/bin/lib/command-roster.cjs +19 -0
  182. package/pp-core/bin/lib/command-routing-hub.cjs +300 -0
  183. package/pp-core/bin/lib/commands.cjs +1244 -0
  184. package/pp-core/bin/lib/config-loader.cjs +714 -0
  185. package/pp-core/bin/lib/config-schema.cjs +58 -0
  186. package/pp-core/bin/lib/config-types.cjs +20 -0
  187. package/pp-core/bin/lib/config.cjs +796 -0
  188. package/pp-core/bin/lib/configuration.cjs +209 -0
  189. package/pp-core/bin/lib/context-utilization.cjs +48 -0
  190. package/pp-core/bin/lib/core-utils.cjs +198 -0
  191. package/pp-core/bin/lib/decisions.cjs +136 -0
  192. package/pp-core/bin/lib/docs.cjs +264 -0
  193. package/pp-core/bin/lib/drift.cjs +364 -0
  194. package/pp-core/bin/lib/edge-probe.cjs +196 -0
  195. package/pp-core/bin/lib/fallow-runner.cjs +153 -0
  196. package/pp-core/bin/lib/federated-config.cjs +182 -0
  197. package/pp-core/bin/lib/frontmatter.cjs +494 -0
  198. package/pp-core/bin/lib/gap-checker.cjs +260 -0
  199. package/pp-core/bin/lib/git-base-branch.cjs +220 -0
  200. package/pp-core/bin/lib/graphify-command-router.cjs +72 -0
  201. package/pp-core/bin/lib/graphify.cjs +472 -0
  202. package/pp-core/bin/lib/gsd2-import.cjs +456 -0
  203. package/pp-core/bin/lib/init-command-router.cjs +62 -0
  204. package/pp-core/bin/lib/init.cjs +1912 -0
  205. package/pp-core/bin/lib/install-profiles.cjs +814 -0
  206. package/pp-core/bin/lib/installer-migration-authoring.cjs +122 -0
  207. package/pp-core/bin/lib/installer-migration-report.cjs +351 -0
  208. package/pp-core/bin/lib/installer-migrations/000-first-time-baseline.cjs +225 -0
  209. package/pp-core/bin/lib/installer-migrations/001-legacy-orphan-files.cjs +48 -0
  210. package/pp-core/bin/lib/installer-migrations/002-codex-legacy-hooks-json.cjs +94 -0
  211. package/pp-core/bin/lib/installer-migrations/003-rename-get-shit-done-to-gsd-core.cjs +108 -0
  212. package/pp-core/bin/lib/installer-migrations/004-prune-stale-pristine-snapshots.cjs +123 -0
  213. package/pp-core/bin/lib/installer-migrations/005-rename-gsd-core-to-pp-core.cjs +109 -0
  214. package/pp-core/bin/lib/installer-migrations/006-rename-gsd-command-namespace.cjs +135 -0
  215. package/pp-core/bin/lib/installer-migrations.cjs +823 -0
  216. package/pp-core/bin/lib/intel-command-router.cjs +119 -0
  217. package/pp-core/bin/lib/intel.cjs +584 -0
  218. package/pp-core/bin/lib/io.cjs +220 -0
  219. package/pp-core/bin/lib/learnings.cjs +270 -0
  220. package/pp-core/bin/lib/legacy-cleanup.cjs +253 -0
  221. package/pp-core/bin/lib/loop-host-contract.cjs +105 -0
  222. package/pp-core/bin/lib/loop-resolver.cjs +479 -0
  223. package/pp-core/bin/lib/milestone.cjs +381 -0
  224. package/pp-core/bin/lib/model-catalog.cjs +154 -0
  225. package/pp-core/bin/lib/model-profiles.cjs +24 -0
  226. package/pp-core/bin/lib/model-resolver.cjs +467 -0
  227. package/pp-core/bin/lib/observability/event.cjs +51 -0
  228. package/pp-core/bin/lib/observability/logger.cjs +146 -0
  229. package/pp-core/bin/lib/observability/redaction.cjs +48 -0
  230. package/pp-core/bin/lib/package-identity.cjs +35 -0
  231. package/pp-core/bin/lib/package-legitimacy.cjs +368 -0
  232. package/pp-core/bin/lib/phase-command-router.cjs +209 -0
  233. package/pp-core/bin/lib/phase-id.cjs +213 -0
  234. package/pp-core/bin/lib/phase-lifecycle.cjs +74 -0
  235. package/pp-core/bin/lib/phase-locator.cjs +145 -0
  236. package/pp-core/bin/lib/phase.cjs +1446 -0
  237. package/pp-core/bin/lib/phases-command-router.cjs +43 -0
  238. package/pp-core/bin/lib/plan-drift-guard.cjs +117 -0
  239. package/pp-core/bin/lib/plan-scan.cjs +91 -0
  240. package/pp-core/bin/lib/planning-workspace.cjs +245 -0
  241. package/pp-core/bin/lib/probe-core.cjs +402 -0
  242. package/pp-core/bin/lib/profile-output.cjs +1164 -0
  243. package/pp-core/bin/lib/profile-pipeline-command-router.cjs +138 -0
  244. package/pp-core/bin/lib/profile-pipeline.cjs +519 -0
  245. package/pp-core/bin/lib/prohibition-enforcement.cjs +660 -0
  246. package/pp-core/bin/lib/project-root.cjs +119 -0
  247. package/pp-core/bin/lib/prompt-budget.cjs +305 -0
  248. package/pp-core/bin/lib/research-provider.cjs +137 -0
  249. package/pp-core/bin/lib/research-store.cjs +167 -0
  250. package/pp-core/bin/lib/review-reviewer-selection.cjs +121 -0
  251. package/pp-core/bin/lib/roadmap-command-router.cjs +166 -0
  252. package/pp-core/bin/lib/roadmap-parser.cjs +456 -0
  253. package/pp-core/bin/lib/roadmap-upgrade.cjs +476 -0
  254. package/pp-core/bin/lib/roadmap.cjs +738 -0
  255. package/pp-core/bin/lib/runtime-artifact-conversion.cjs +1966 -0
  256. package/pp-core/bin/lib/runtime-artifact-layout.cjs +342 -0
  257. package/pp-core/bin/lib/runtime-config-adapter-registry.cjs +103 -0
  258. package/pp-core/bin/lib/runtime-homes.cjs +272 -0
  259. package/pp-core/bin/lib/runtime-hooks-surface.cjs +1460 -0
  260. package/pp-core/bin/lib/runtime-name-policy.cjs +97 -0
  261. package/pp-core/bin/lib/runtime-slash.cjs +137 -0
  262. package/pp-core/bin/lib/schema-detect.cjs +159 -0
  263. package/pp-core/bin/lib/secrets.cjs +34 -0
  264. package/pp-core/bin/lib/security.cjs +480 -0
  265. package/pp-core/bin/lib/semver-compare.cjs +42 -0
  266. package/pp-core/bin/lib/shell-command-projection.cjs +550 -0
  267. package/pp-core/bin/lib/state-command-router.cjs +172 -0
  268. package/pp-core/bin/lib/state-document.cjs +312 -0
  269. package/pp-core/bin/lib/state.cjs +2587 -0
  270. package/pp-core/bin/lib/surface.cjs +505 -0
  271. package/pp-core/bin/lib/task-command-router.cjs +85 -0
  272. package/pp-core/bin/lib/teams-status.cjs +74 -0
  273. package/pp-core/bin/lib/template.cjs +246 -0
  274. package/pp-core/bin/lib/uat-predicate.cjs +329 -0
  275. package/pp-core/bin/lib/uat.cjs +359 -0
  276. package/pp-core/bin/lib/ui-safety-gate.cjs +98 -0
  277. package/pp-core/bin/lib/update-context.cjs +221 -0
  278. package/pp-core/bin/lib/validate-command-router.cjs +91 -0
  279. package/pp-core/bin/lib/validate.cjs +122 -0
  280. package/pp-core/bin/lib/verification-command-router.cjs +31 -0
  281. package/pp-core/bin/lib/verification.cjs +196 -0
  282. package/pp-core/bin/lib/verify-command-router.cjs +44 -0
  283. package/pp-core/bin/lib/verify.cjs +1932 -0
  284. package/pp-core/bin/lib/workstream-inventory-builder.cjs +81 -0
  285. package/pp-core/bin/lib/workstream-inventory.cjs +147 -0
  286. package/pp-core/bin/lib/workstream-name-policy.cjs +91 -0
  287. package/pp-core/bin/lib/workstream.cjs +386 -0
  288. package/pp-core/bin/lib/worktree-base-ref.cjs +350 -0
  289. package/pp-core/bin/lib/worktree-safety.cjs +985 -0
  290. package/pp-core/bin/pp-tools.cjs +2239 -0
  291. package/pp-core/bin/pp_run +20 -0
  292. package/pp-core/bin/shared/config-defaults.manifest.json +97 -0
  293. package/pp-core/bin/shared/config-schema.manifest.json +176 -0
  294. package/pp-core/bin/shared/model-catalog.json +160 -0
  295. package/pp-core/bin/shared/runtime-aliases.manifest.json +79 -0
  296. package/pp-core/bin/verify-reapply-patches.cjs +400 -0
  297. package/pp-core/contexts/dev.md +21 -0
  298. package/pp-core/contexts/research.md +22 -0
  299. package/pp-core/contexts/review.md +23 -0
  300. package/pp-core/references/agent-contracts.md +79 -0
  301. package/pp-core/references/ai-evals.md +156 -0
  302. package/pp-core/references/ai-frameworks.md +186 -0
  303. package/pp-core/references/artifact-types.md +131 -0
  304. package/pp-core/references/autonomous-smart-discuss.md +277 -0
  305. package/pp-core/references/checkpoints.md +814 -0
  306. package/pp-core/references/common-bug-patterns.md +114 -0
  307. package/pp-core/references/context-budget.md +85 -0
  308. package/pp-core/references/continuation-format.md +253 -0
  309. package/pp-core/references/debugger-philosophy.md +76 -0
  310. package/pp-core/references/decimal-phase-calculation.md +64 -0
  311. package/pp-core/references/doc-conflict-engine.md +91 -0
  312. package/pp-core/references/domain-probes.md +125 -0
  313. package/pp-core/references/edge-probe-fixtures/01-round-half-even/expected-coverage.json +7 -0
  314. package/pp-core/references/edge-probe-fixtures/01-round-half-even/requirements.json +1 -0
  315. package/pp-core/references/edge-probe-fixtures/02-merge-intervals/expected-coverage.json +8 -0
  316. package/pp-core/references/edge-probe-fixtures/02-merge-intervals/requirements.json +1 -0
  317. package/pp-core/references/edge-probe-fixtures/03-truncate-graphemes/expected-coverage.json +7 -0
  318. package/pp-core/references/edge-probe-fixtures/03-truncate-graphemes/requirements.json +1 -0
  319. package/pp-core/references/edge-probe-fixtures/04-money-rounding/expected-coverage.json +7 -0
  320. package/pp-core/references/edge-probe-fixtures/04-money-rounding/requirements.json +1 -0
  321. package/pp-core/references/edge-probe-fixtures/05-list-dedupe/expected-coverage.json +8 -0
  322. package/pp-core/references/edge-probe-fixtures/05-list-dedupe/requirements.json +1 -0
  323. package/pp-core/references/edge-probe-fixtures/06-resolved-mixed/expected-coverage.json +8 -0
  324. package/pp-core/references/edge-probe-fixtures/06-resolved-mixed/requirements.json +1 -0
  325. package/pp-core/references/edge-probe-fixtures/06-resolved-mixed/resolutions.json +4 -0
  326. package/pp-core/references/edge-probe.md +272 -0
  327. package/pp-core/references/execute-mvp-tdd.md +81 -0
  328. package/pp-core/references/executor-examples.md +110 -0
  329. package/pp-core/references/few-shot-examples/plan-checker.md +73 -0
  330. package/pp-core/references/few-shot-examples/verifier.md +109 -0
  331. package/pp-core/references/gate-prompts.md +100 -0
  332. package/pp-core/references/gates.md +70 -0
  333. package/pp-core/references/git-integration.md +298 -0
  334. package/pp-core/references/git-planning-commit.md +40 -0
  335. package/pp-core/references/ios-scaffold.md +123 -0
  336. package/pp-core/references/loop-hook-dispatch.md +61 -0
  337. package/pp-core/references/mandatory-initial-read.md +2 -0
  338. package/pp-core/references/model-profile-resolution.md +38 -0
  339. package/pp-core/references/model-profiles.md +245 -0
  340. package/pp-core/references/mvp-concepts.md +49 -0
  341. package/pp-core/references/phase-argument-parsing.md +61 -0
  342. package/pp-core/references/planner-antipatterns.md +176 -0
  343. package/pp-core/references/planner-chunked.md +49 -0
  344. package/pp-core/references/planner-gap-closure.md +62 -0
  345. package/pp-core/references/planner-graphify-auto-update.md +67 -0
  346. package/pp-core/references/planner-guidance.md +186 -0
  347. package/pp-core/references/planner-human-verify-mode.md +57 -0
  348. package/pp-core/references/planner-interface-context.md +62 -0
  349. package/pp-core/references/planner-load-graph-context.md +36 -0
  350. package/pp-core/references/planner-mvp-mode.md +53 -0
  351. package/pp-core/references/planner-reviews.md +42 -0
  352. package/pp-core/references/planner-revision.md +87 -0
  353. package/pp-core/references/planner-source-audit.md +73 -0
  354. package/pp-core/references/planning-config.md +477 -0
  355. package/pp-core/references/prohibition-probe-fixtures/01-streak-reminder/expected.json +14 -0
  356. package/pp-core/references/prohibition-probe-fixtures/02-clean-utility/expected.json +4 -0
  357. package/pp-core/references/prohibition-probe-fixtures/03-multi-prohibition/expected.json +32 -0
  358. package/pp-core/references/prohibition-probe.md +326 -0
  359. package/pp-core/references/project-skills-discovery.md +19 -0
  360. package/pp-core/references/questioning.md +162 -0
  361. package/pp-core/references/research-documentation-lookup.md +29 -0
  362. package/pp-core/references/research-philosophy.md +29 -0
  363. package/pp-core/references/research-verification-protocol.md +27 -0
  364. package/pp-core/references/revision-loop.md +97 -0
  365. package/pp-core/references/scout-codebase.md +51 -0
  366. package/pp-core/references/skeleton-template.md +48 -0
  367. package/pp-core/references/sketch-interactivity.md +41 -0
  368. package/pp-core/references/sketch-theme-system.md +94 -0
  369. package/pp-core/references/sketch-tooling.md +45 -0
  370. package/pp-core/references/sketch-variant-patterns.md +81 -0
  371. package/pp-core/references/spidr-splitting.md +69 -0
  372. package/pp-core/references/tdd.md +330 -0
  373. package/pp-core/references/thinking-models-debug.md +44 -0
  374. package/pp-core/references/thinking-models-execution.md +50 -0
  375. package/pp-core/references/thinking-models-planning.md +62 -0
  376. package/pp-core/references/thinking-models-research.md +50 -0
  377. package/pp-core/references/thinking-models-verification.md +55 -0
  378. package/pp-core/references/thinking-partner.md +96 -0
  379. package/pp-core/references/ui-brand.md +162 -0
  380. package/pp-core/references/universal-anti-patterns.md +63 -0
  381. package/pp-core/references/user-profiling.md +681 -0
  382. package/pp-core/references/user-story-template.md +58 -0
  383. package/pp-core/references/verification-overrides.md +227 -0
  384. package/pp-core/references/verification-patterns.md +612 -0
  385. package/pp-core/references/verify-mvp-mode.md +85 -0
  386. package/pp-core/references/workstream-flag.md +111 -0
  387. package/pp-core/references/worktree-branch-check.md +44 -0
  388. package/pp-core/references/worktree-path-safety.md +67 -0
  389. package/pp-core/templates/AI-SPEC.md +246 -0
  390. package/pp-core/templates/DEBUG.md +169 -0
  391. package/pp-core/templates/README.md +77 -0
  392. package/pp-core/templates/SECURITY.md +61 -0
  393. package/pp-core/templates/UAT.md +265 -0
  394. package/pp-core/templates/UI-SPEC.md +100 -0
  395. package/pp-core/templates/VALIDATION.md +76 -0
  396. package/pp-core/templates/claude-md.md +145 -0
  397. package/pp-core/templates/codebase/architecture.md +255 -0
  398. package/pp-core/templates/codebase/concerns.md +310 -0
  399. package/pp-core/templates/codebase/conventions.md +307 -0
  400. package/pp-core/templates/codebase/integrations.md +280 -0
  401. package/pp-core/templates/codebase/stack.md +186 -0
  402. package/pp-core/templates/codebase/structure.md +285 -0
  403. package/pp-core/templates/codebase/testing.md +480 -0
  404. package/pp-core/templates/config.json +62 -0
  405. package/pp-core/templates/context.md +352 -0
  406. package/pp-core/templates/continue-here.md +78 -0
  407. package/pp-core/templates/copilot-instructions.md +7 -0
  408. package/pp-core/templates/debug-subagent-prompt.md +91 -0
  409. package/pp-core/templates/dev-preferences.md +21 -0
  410. package/pp-core/templates/discovery.md +146 -0
  411. package/pp-core/templates/discussion-log.md +63 -0
  412. package/pp-core/templates/milestone-archive.md +123 -0
  413. package/pp-core/templates/milestone.md +115 -0
  414. package/pp-core/templates/phase-prompt.md +610 -0
  415. package/pp-core/templates/planner-subagent-prompt.md +117 -0
  416. package/pp-core/templates/project.md +203 -0
  417. package/pp-core/templates/requirements.md +231 -0
  418. package/pp-core/templates/research-project/ARCHITECTURE.md +204 -0
  419. package/pp-core/templates/research-project/FEATURES.md +147 -0
  420. package/pp-core/templates/research-project/PITFALLS.md +200 -0
  421. package/pp-core/templates/research-project/STACK.md +120 -0
  422. package/pp-core/templates/research-project/SUMMARY.md +170 -0
  423. package/pp-core/templates/research.md +592 -0
  424. package/pp-core/templates/retrospective.md +54 -0
  425. package/pp-core/templates/roadmap.md +202 -0
  426. package/pp-core/templates/spec.md +333 -0
  427. package/pp-core/templates/state.md +195 -0
  428. package/pp-core/templates/summary-complex.md +60 -0
  429. package/pp-core/templates/summary-minimal.md +42 -0
  430. package/pp-core/templates/summary-standard.md +49 -0
  431. package/pp-core/templates/summary.md +249 -0
  432. package/pp-core/templates/user-profile.md +146 -0
  433. package/pp-core/templates/user-setup.md +311 -0
  434. package/pp-core/templates/verification-report.md +335 -0
  435. package/pp-core/workflows/_runtime-launcher.snippet.sh +1 -0
  436. package/pp-core/workflows/add-backlog.md +91 -0
  437. package/pp-core/workflows/add-phase.md +113 -0
  438. package/pp-core/workflows/add-tests.md +355 -0
  439. package/pp-core/workflows/add-todo.md +161 -0
  440. package/pp-core/workflows/ai-integration-phase.md +295 -0
  441. package/pp-core/workflows/analyze-dependencies.md +96 -0
  442. package/pp-core/workflows/audit-fix.md +178 -0
  443. package/pp-core/workflows/audit-milestone.md +362 -0
  444. package/pp-core/workflows/audit-uat.md +110 -0
  445. package/pp-core/workflows/autonomous.md +886 -0
  446. package/pp-core/workflows/check-todos.md +180 -0
  447. package/pp-core/workflows/cleanup.md +195 -0
  448. package/pp-core/workflows/code-review-fix.md +506 -0
  449. package/pp-core/workflows/code-review.md +696 -0
  450. package/pp-core/workflows/complete-milestone.md +857 -0
  451. package/pp-core/workflows/debug.md +237 -0
  452. package/pp-core/workflows/diagnose-issues.md +245 -0
  453. package/pp-core/workflows/discovery-phase.md +291 -0
  454. package/pp-core/workflows/discovery-sprint.md +1546 -0
  455. package/pp-core/workflows/discuss-phase/modes/advisor.md +176 -0
  456. package/pp-core/workflows/discuss-phase/modes/all.md +28 -0
  457. package/pp-core/workflows/discuss-phase/modes/analyze.md +44 -0
  458. package/pp-core/workflows/discuss-phase/modes/auto.md +57 -0
  459. package/pp-core/workflows/discuss-phase/modes/batch.md +52 -0
  460. package/pp-core/workflows/discuss-phase/modes/chain.md +98 -0
  461. package/pp-core/workflows/discuss-phase/modes/default.md +141 -0
  462. package/pp-core/workflows/discuss-phase/modes/power.md +44 -0
  463. package/pp-core/workflows/discuss-phase/modes/text.md +55 -0
  464. package/pp-core/workflows/discuss-phase/templates/checkpoint.json +18 -0
  465. package/pp-core/workflows/discuss-phase/templates/context.md +136 -0
  466. package/pp-core/workflows/discuss-phase/templates/discussion-log.md +50 -0
  467. package/pp-core/workflows/discuss-phase-assumptions.md +675 -0
  468. package/pp-core/workflows/discuss-phase-power.md +291 -0
  469. package/pp-core/workflows/discuss-phase.md +520 -0
  470. package/pp-core/workflows/do.md +111 -0
  471. package/pp-core/workflows/docs-update.md +1168 -0
  472. package/pp-core/workflows/edit-phase.md +295 -0
  473. package/pp-core/workflows/eval-review.md +159 -0
  474. package/pp-core/workflows/execute-phase/steps/codebase-drift-gate.md +95 -0
  475. package/pp-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +94 -0
  476. package/pp-core/workflows/execute-phase/steps/post-merge-gate.md +117 -0
  477. package/pp-core/workflows/execute-phase/steps/worktree-recovery-policy.md +9 -0
  478. package/pp-core/workflows/execute-phase.md +1707 -0
  479. package/pp-core/workflows/execute-plan.md +541 -0
  480. package/pp-core/workflows/explore.md +146 -0
  481. package/pp-core/workflows/extract-learnings.md +243 -0
  482. package/pp-core/workflows/fast.md +124 -0
  483. package/pp-core/workflows/forensics.md +279 -0
  484. package/pp-core/workflows/graduation.md +196 -0
  485. package/pp-core/workflows/health.md +224 -0
  486. package/pp-core/workflows/help/modes/brief.md +22 -0
  487. package/pp-core/workflows/help/modes/default.md +50 -0
  488. package/pp-core/workflows/help/modes/full.md +791 -0
  489. package/pp-core/workflows/help/modes/topic.md +74 -0
  490. package/pp-core/workflows/help.md +24 -0
  491. package/pp-core/workflows/import.md +256 -0
  492. package/pp-core/workflows/inbox.md +387 -0
  493. package/pp-core/workflows/ingest-docs.md +340 -0
  494. package/pp-core/workflows/insert-phase.md +152 -0
  495. package/pp-core/workflows/list-phase-assumptions.md +178 -0
  496. package/pp-core/workflows/list-workspaces.md +57 -0
  497. package/pp-core/workflows/manager.md +435 -0
  498. package/pp-core/workflows/map-codebase.md +444 -0
  499. package/pp-core/workflows/milestone-summary.md +224 -0
  500. package/pp-core/workflows/mvp-phase.md +222 -0
  501. package/pp-core/workflows/new-milestone.md +643 -0
  502. package/pp-core/workflows/new-project.md +1563 -0
  503. package/pp-core/workflows/new-workspace.md +240 -0
  504. package/pp-core/workflows/next.md +347 -0
  505. package/pp-core/workflows/node-repair.md +92 -0
  506. package/pp-core/workflows/note.md +158 -0
  507. package/pp-core/workflows/pause-work.md +250 -0
  508. package/pp-core/workflows/plan-milestone-gaps.md +281 -0
  509. package/pp-core/workflows/plan-phase.md +1755 -0
  510. package/pp-core/workflows/plan-review-convergence.md +369 -0
  511. package/pp-core/workflows/plant-seed.md +230 -0
  512. package/pp-core/workflows/pr-branch.md +159 -0
  513. package/pp-core/workflows/profile-user.md +455 -0
  514. package/pp-core/workflows/progress.md +756 -0
  515. package/pp-core/workflows/quick.md +1045 -0
  516. package/pp-core/workflows/reapply-patches.md +443 -0
  517. package/pp-core/workflows/remove-phase.md +156 -0
  518. package/pp-core/workflows/remove-workspace.md +108 -0
  519. package/pp-core/workflows/resume-project.md +348 -0
  520. package/pp-core/workflows/review.md +765 -0
  521. package/pp-core/workflows/scan.md +107 -0
  522. package/pp-core/workflows/secure-phase.md +184 -0
  523. package/pp-core/workflows/session-report.md +146 -0
  524. package/pp-core/workflows/settings-advanced.md +816 -0
  525. package/pp-core/workflows/settings-integrations.md +312 -0
  526. package/pp-core/workflows/settings.md +592 -0
  527. package/pp-core/workflows/ship.md +465 -0
  528. package/pp-core/workflows/sketch-wrap-up.md +286 -0
  529. package/pp-core/workflows/sketch.md +361 -0
  530. package/pp-core/workflows/spec-phase.md +495 -0
  531. package/pp-core/workflows/spike-wrap-up.md +307 -0
  532. package/pp-core/workflows/spike.md +453 -0
  533. package/pp-core/workflows/stats.md +80 -0
  534. package/pp-core/workflows/sync-skills.md +182 -0
  535. package/pp-core/workflows/thread.md +222 -0
  536. package/pp-core/workflows/transition.md +694 -0
  537. package/pp-core/workflows/ui-phase.md +328 -0
  538. package/pp-core/workflows/ui-review.md +193 -0
  539. package/pp-core/workflows/ultraplan-phase.md +199 -0
  540. package/pp-core/workflows/undo.md +314 -0
  541. package/pp-core/workflows/update.md +501 -0
  542. package/pp-core/workflows/validate-phase.md +183 -0
  543. package/pp-core/workflows/verify-phase.md +569 -0
  544. package/pp-core/workflows/verify-work.md +804 -0
  545. package/scripts/affected-tests-lib.cjs +554 -0
  546. package/scripts/audit-workflow-script-paths.cjs +73 -0
  547. package/scripts/base64-scan.sh +351 -0
  548. package/scripts/build-hooks.js +254 -0
  549. package/scripts/changeset/README.md +129 -0
  550. package/scripts/changeset/cli.cjs +597 -0
  551. package/scripts/changeset/github-release-notes.cjs +199 -0
  552. package/scripts/changeset/lint.cjs +147 -0
  553. package/scripts/changeset/new.cjs +151 -0
  554. package/scripts/changeset/parse.cjs +114 -0
  555. package/scripts/changeset/render.cjs +34 -0
  556. package/scripts/changeset/serialize.cjs +130 -0
  557. package/scripts/check-alias-drift.cjs +114 -0
  558. package/scripts/check-env.cjs +312 -0
  559. package/scripts/check-npm-integrity.cjs +215 -0
  560. package/scripts/ci-guard-runner.cjs +22 -0
  561. package/scripts/ci-prepare-test-scope.cjs +93 -0
  562. package/scripts/ci-rebase-check.cjs +86 -0
  563. package/scripts/ci-test-scope.cjs +441 -0
  564. package/scripts/command-contract-helpers.cjs +64 -0
  565. package/scripts/diff-touches-shipped-paths.cjs +149 -0
  566. package/scripts/fix-slash-commands.cjs +161 -0
  567. package/scripts/gen-capability-registry.cjs +2646 -0
  568. package/scripts/gen-commands-reference.cjs +139 -0
  569. package/scripts/gen-inventory-manifest.cjs +114 -0
  570. package/scripts/gen-loop-host-contract.cjs +526 -0
  571. package/scripts/gen-research-agents.cjs +276 -0
  572. package/scripts/generate-package-identity.cjs +134 -0
  573. package/scripts/issue-dedupe.cjs +278 -0
  574. package/scripts/issue-version-gate.cjs +140 -0
  575. package/scripts/lib/allowlist-ratchet.cjs +236 -0
  576. package/scripts/lib/cli-exit.cjs +56 -0
  577. package/scripts/lint-allow-test-rule-refs.allowlist.json +328 -0
  578. package/scripts/lint-allow-test-rule-refs.cjs +162 -0
  579. package/scripts/lint-command-contract.cjs +118 -0
  580. package/scripts/lint-descriptions.cjs +87 -0
  581. package/scripts/lint-docs-required.cjs +222 -0
  582. package/scripts/lint-legacy-dir-name.cjs +166 -0
  583. package/scripts/lint-package-identity-drift.cjs +141 -0
  584. package/scripts/lint-pr-check-project-dir.cjs +99 -0
  585. package/scripts/lint-regression-test-names.allowlist.json +269 -0
  586. package/scripts/lint-regression-test-names.cjs +117 -0
  587. package/scripts/lint-shell-command-projection-drift.cjs +62 -0
  588. package/scripts/lint-skill-deps.cjs +185 -0
  589. package/scripts/lint-test-file-count.allowlist.json +181 -0
  590. package/scripts/lint-test-file-count.cjs +246 -0
  591. package/scripts/lint-windows-test-portability.cjs +178 -0
  592. package/scripts/mutation-matrix.cjs +323 -0
  593. package/scripts/pr-target-policy.cjs +63 -0
  594. package/scripts/pr-template-policy.cjs +268 -0
  595. package/scripts/prompt-injection-scan.sh +207 -0
  596. package/scripts/registry-smoke.cjs +337 -0
  597. package/scripts/release-notes/discord-release-summary.cjs +373 -0
  598. package/scripts/release-notes/format-github-release-notes.cjs +261 -0
  599. package/scripts/release-tarball-smoke.cjs +763 -0
  600. package/scripts/research-profiles.cjs +149 -0
  601. package/scripts/run-affected-tests.cjs +7 -0
  602. package/scripts/run-tests.cjs +589 -0
  603. package/scripts/secret-scan-lint.sh +231 -0
  604. package/scripts/secret-scan.sh +358 -0
  605. package/scripts/setup-branch-protection.sh +234 -0
  606. package/scripts/strip-prose-atrefs.cjs +106 -0
  607. package/scripts/sync-manifest-versions.cjs +119 -0
  608. package/scripts/sync-next-version.cjs +133 -0
  609. package/scripts/sync-rulesets.sh +34 -0
  610. package/scripts/sync-runtime-launcher.cjs +425 -0
  611. package/scripts/test-failure-reasons.cjs +34 -0
  612. package/scripts/update-size-baseline.cjs +68 -0
  613. package/scripts/verify-npm-publish.cjs +240 -0
  614. package/scripts/verify-opengsd-sweep.cjs +288 -0
  615. package/scripts/verify-phase-02-rename.sh +258 -0
  616. package/scripts/verify-phase-03-rename.sh +376 -0
  617. package/scripts/workflow-policy.cjs +483 -0
  618. package/scripts/workflow-size.cjs +90 -0
@@ -0,0 +1,800 @@
1
+ "use strict";
2
+ /**
3
+ * Check subcommand router — auto-mode, decision-coverage-plan, decision-coverage-verify.
4
+ *
5
+ * ADR-457 build-at-publish: the hand-written bin/lib/check-command-router.cjs collapsed
6
+ * to a TypeScript source of truth. Behaviour is preserved byte-for-behaviour
7
+ * from the prior hand-written .cjs; only strict types are added.
8
+ */
9
+ var __importDefault = (this && this.__importDefault) || function (mod) {
10
+ return (mod && mod.__esModule) ? mod : { "default": mod };
11
+ };
12
+ const node_fs_1 = __importDefault(require("node:fs"));
13
+ const node_path_1 = __importDefault(require("node:path"));
14
+ const node_child_process_1 = require("node:child_process");
15
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
16
+ const io = require("./io.cjs");
17
+ const { output, error, ERROR_REASON } = io;
18
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
19
+ const planningWorkspaceMod = require("./planning-workspace.cjs");
20
+ const { planningDir } = planningWorkspaceMod;
21
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
22
+ const phaseLocatorMod = require("./phase-locator.cjs");
23
+ const { findPhaseInternal } = phaseLocatorMod;
24
+ const decisions_cjs_1 = require("./decisions.cjs");
25
+ const ui_safety_gate_cjs_1 = require("./ui-safety-gate.cjs");
26
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
27
+ const verifyModule = require("./verify.cjs");
28
+ const { cmdVerifySchemaDrift, cmdVerifyCodebaseDrift } = verifyModule;
29
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
30
+ const roadmapModule = require("./roadmap.cjs");
31
+ const { getRoadmapPhaseWithFallback } = roadmapModule;
32
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
33
+ const gapCheckerModule = require("./gap-checker.cjs");
34
+ const { runGapAnalysis } = gapCheckerModule;
35
+ const prohibition_enforcement_cjs_1 = require("./prohibition-enforcement.cjs");
36
+ // ─── Helpers ──────────────────────────────────────────────────────────────────
37
+ function normalizePhrase(text) {
38
+ // eslint-disable-next-line @typescript-eslint/no-base-to-string
39
+ return String(text || '')
40
+ .toLowerCase()
41
+ .replace(/[^a-z0-9\s]/g, ' ')
42
+ .replace(/\s+/g, ' ')
43
+ .trim();
44
+ }
45
+ const SOFT_PHRASE_MIN_WORDS = 6;
46
+ function softPhrase(text) {
47
+ const words = normalizePhrase(text).split(' ').filter(Boolean);
48
+ if (words.length < SOFT_PHRASE_MIN_WORDS)
49
+ return '';
50
+ return words.slice(0, SOFT_PHRASE_MIN_WORDS).join(' ');
51
+ }
52
+ function decisionMentioned(haystack, decision) {
53
+ if (!haystack)
54
+ return false;
55
+ if (new RegExp(`\\b${decision.id}\\b`).test(haystack))
56
+ return true;
57
+ const phrase = softPhrase(decision.text);
58
+ return phrase ? normalizePhrase(haystack).includes(phrase) : false;
59
+ }
60
+ function readIfExists(filePath) {
61
+ try {
62
+ return node_fs_1.default.readFileSync(filePath, 'utf-8');
63
+ }
64
+ catch {
65
+ return '';
66
+ }
67
+ }
68
+ function resolvePath(inputPath, projectDir) {
69
+ return node_path_1.default.isAbsolute(inputPath) ? inputPath : node_path_1.default.join(projectDir, inputPath);
70
+ }
71
+ function readWorkflowConfig(projectDir) {
72
+ const configPath = node_path_1.default.join(projectDir, '.planning', 'config.json');
73
+ try {
74
+ const parsed = JSON.parse(node_fs_1.default.readFileSync(configPath, 'utf-8'));
75
+ const wf = parsed['workflow'] || {};
76
+ return {
77
+ ...wf,
78
+ auto_advance: (wf['auto_advance'] ?? parsed['auto_advance']),
79
+ _auto_chain_active: (wf['_auto_chain_active'] ?? parsed['_auto_chain_active']),
80
+ context_coverage_gate: (wf['context_coverage_gate'] ?? parsed['context_coverage_gate']),
81
+ };
82
+ }
83
+ catch {
84
+ return {};
85
+ }
86
+ }
87
+ function cmdAutoMode(projectDir, raw) {
88
+ const workflow = readWorkflowConfig(projectDir);
89
+ const autoAdvance = Boolean(workflow.auto_advance ?? false);
90
+ const autoChainActive = Boolean(workflow._auto_chain_active ?? false);
91
+ let source = 'none';
92
+ if (autoChainActive && autoAdvance)
93
+ source = 'both';
94
+ else if (autoChainActive)
95
+ source = 'auto_chain';
96
+ else if (autoAdvance)
97
+ source = 'auto_advance';
98
+ output({
99
+ active: autoChainActive || autoAdvance,
100
+ source,
101
+ auto_chain_active: autoChainActive,
102
+ auto_advance: autoAdvance,
103
+ }, raw, undefined);
104
+ }
105
+ function gateEnabled(projectDir) {
106
+ const value = readWorkflowConfig(projectDir).context_coverage_gate;
107
+ if (typeof value === 'boolean')
108
+ return value;
109
+ if (typeof value === 'string') {
110
+ const lower = value.toLowerCase();
111
+ if (lower === 'false' || lower === 'true')
112
+ return lower !== 'false';
113
+ }
114
+ return true;
115
+ }
116
+ function loadPlanContents(phaseDir) {
117
+ if (!node_fs_1.default.existsSync(phaseDir))
118
+ return [];
119
+ try {
120
+ return node_fs_1.default.readdirSync(phaseDir)
121
+ .filter((entry) => /-PLAN\.md$/.test(entry))
122
+ .map((entry) => readIfExists(node_path_1.default.join(phaseDir, entry)));
123
+ }
124
+ catch {
125
+ return [];
126
+ }
127
+ }
128
+ const DESIGNATED_HEADINGS_RE = /^#{1,6}\s+(?:must[_ ]haves?|truths?|tasks?|objective)\b/i;
129
+ const XML_DECISION_TAGS_RE = /<(?:objective|tasks?|action)(?:\s[^>]*)?>([\s\S]*?)<\/(?:objective|tasks?|action)>/gi;
130
+ function stripCommentsAndFences(text) {
131
+ return text
132
+ .replace(/<!--[\s\S]*?-->/g, ' ')
133
+ .replace(/```[\s\S]*?```/g, ' ')
134
+ .replace(/~~~[\s\S]*?~~~/g, ' ');
135
+ }
136
+ function extractYamlBlock(frontmatter, key) {
137
+ const match = frontmatter.match(new RegExp(`^${key}\\s*:(.*)$`, 'm'));
138
+ if (!match)
139
+ return '';
140
+ const startIdx = (match.index || 0) + match[0].length;
141
+ const rest = frontmatter.slice(startIdx + 1).split(/\r?\n/);
142
+ const block = [match[1] || ''];
143
+ for (const line of rest) {
144
+ if (line === '' || /^\s/.test(line))
145
+ block.push(line);
146
+ else
147
+ break;
148
+ }
149
+ return block.join('\n');
150
+ }
151
+ function extractXmlTagBodies(text) {
152
+ const parts = [];
153
+ for (const match of text.matchAll(XML_DECISION_TAGS_RE)) {
154
+ if (match[1])
155
+ parts.push(match[1]);
156
+ }
157
+ return parts.join('\n');
158
+ }
159
+ function extractPlanDesignatedSections(planContent) {
160
+ if (!planContent)
161
+ return '';
162
+ const cleaned = stripCommentsAndFences(planContent);
163
+ const fmMatch = cleaned.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/);
164
+ const frontmatter = fmMatch ? fmMatch[1] : '';
165
+ const body = fmMatch ? fmMatch[2] : cleaned;
166
+ const parts = [];
167
+ for (const key of ['must_haves', 'truths', 'objective']) {
168
+ const block = extractYamlBlock(frontmatter, key);
169
+ if (block)
170
+ parts.push(block);
171
+ }
172
+ const bodyParts = [];
173
+ let inDesignated = false;
174
+ for (const line of body.split(/\r?\n/)) {
175
+ const heading = /^#{1,6}\s+/.test(line);
176
+ if (heading) {
177
+ inDesignated = DESIGNATED_HEADINGS_RE.test(line);
178
+ if (inDesignated)
179
+ bodyParts.push(line);
180
+ continue;
181
+ }
182
+ if (inDesignated)
183
+ bodyParts.push(line);
184
+ }
185
+ parts.push(bodyParts.join('\n'));
186
+ parts.push(extractXmlTagBodies(cleaned));
187
+ return parts.join('\n\n');
188
+ }
189
+ function buildPlanMessage(uncovered) {
190
+ if (uncovered.length === 0)
191
+ return 'All trackable CONTEXT.md decisions are covered by plans.';
192
+ return [
193
+ '## Decision Coverage Gap',
194
+ '',
195
+ `${uncovered.length} CONTEXT.md decision(s) are not covered by any plan:`,
196
+ '',
197
+ ...uncovered.map((item) => `- **${item.id}** (${item.category || 'uncategorized'}): ${item.text}`),
198
+ '',
199
+ 'Resolve by citing `D-NN:` in a relevant plan\'s `must_haves`/`truths` (or body),',
200
+ 'OR move the decision to `### Claude\'s Discretion` / tag it `[informational]` if it should not be tracked.',
201
+ ].join('\n');
202
+ }
203
+ function buildVerifyMessage(notHonored) {
204
+ if (notHonored.length === 0)
205
+ return 'All trackable CONTEXT.md decisions are honored by shipped artifacts.';
206
+ return [
207
+ '### Decision Coverage (warning)',
208
+ '',
209
+ `${notHonored.length} decision(s) not found in shipped artifacts:`,
210
+ '',
211
+ ...notHonored.map((item) => `- **${item.id}** (${item.category || 'uncategorized'}): ${item.text}`),
212
+ '',
213
+ 'This is a soft warning - verification status is unchanged.',
214
+ ].join('\n');
215
+ }
216
+ function loadTrackableDecisions(contextPath) {
217
+ return (0, decisions_cjs_1.parseDecisions)(readIfExists(contextPath)).filter((decision) => decision.trackable);
218
+ }
219
+ function cmdDecisionCoveragePlan(projectDir, args, raw) {
220
+ const phaseDir = args[2] ? resolvePath(args[2], projectDir) : '';
221
+ const contextPath = args[3] ? resolvePath(args[3], projectDir) : '';
222
+ if (!gateEnabled(projectDir)) {
223
+ output({ passed: true, skipped: true, reason: 'workflow.context_coverage_gate is false', total: 0, covered: 0, uncovered: [], message: 'Decision coverage gate disabled by config.' }, raw, undefined);
224
+ return;
225
+ }
226
+ if (!contextPath || !node_fs_1.default.existsSync(contextPath)) {
227
+ output({ passed: true, skipped: true, reason: 'CONTEXT.md missing', total: 0, covered: 0, uncovered: [], message: 'No CONTEXT.md - nothing to check.' }, raw, undefined);
228
+ return;
229
+ }
230
+ const decisions = loadTrackableDecisions(contextPath);
231
+ if (decisions.length === 0) {
232
+ output({ passed: true, skipped: true, reason: 'no trackable decisions', total: 0, covered: 0, uncovered: [], message: 'No trackable decisions in CONTEXT.md.' }, raw, undefined);
233
+ return;
234
+ }
235
+ const sections = loadPlanContents(phaseDir).map(extractPlanDesignatedSections);
236
+ const uncovered = [];
237
+ let covered = 0;
238
+ for (const decision of decisions) {
239
+ if (sections.some((section) => decisionMentioned(section, decision)))
240
+ covered++;
241
+ else
242
+ uncovered.push({ id: decision.id, text: decision.text, category: decision.category });
243
+ }
244
+ output({
245
+ passed: uncovered.length === 0,
246
+ skipped: false,
247
+ total: decisions.length,
248
+ covered,
249
+ uncovered,
250
+ message: buildPlanMessage(uncovered),
251
+ }, raw, undefined);
252
+ }
253
+ function recentCommitMessages(projectDir) {
254
+ try {
255
+ return (0, node_child_process_1.execFileSync)('git', ['log', '-n', '200', '--pretty=%s%n%b'], {
256
+ cwd: projectDir,
257
+ encoding: 'utf-8',
258
+ maxBuffer: 4 * 1024 * 1024,
259
+ windowsHide: true,
260
+ });
261
+ }
262
+ catch {
263
+ return '';
264
+ }
265
+ }
266
+ function isInsideRoot(candidatePath, rootDir) {
267
+ const root = node_path_1.default.resolve(rootDir);
268
+ const target = node_path_1.default.resolve(root, candidatePath);
269
+ return target === root || target.startsWith(`${root}${node_path_1.default.sep}`);
270
+ }
271
+ function readModifiedFilesContent(projectDir, summaries) {
272
+ const out = [];
273
+ let total = 0;
274
+ for (const summary of summaries) {
275
+ if (!summary)
276
+ continue;
277
+ for (const blockMatch of summary.matchAll(/files_modified:\s*\n((?:[ \t]*-\s+.+\n?)+)/g)) {
278
+ const files = [...(blockMatch[1] || '').matchAll(/-\s+(.+)/g)]
279
+ .map((match) => match[1].trim().replace(/^["']|["']$/g, ''));
280
+ for (const file of files) {
281
+ if (total >= 50)
282
+ break;
283
+ if (!file || !isInsideRoot(file, projectDir))
284
+ continue;
285
+ const raw = readIfExists(resolvePath(file, projectDir));
286
+ out.push(raw.length > 256 * 1024 ? raw.slice(0, 256 * 1024) : raw);
287
+ total++;
288
+ }
289
+ if (total >= 50)
290
+ break;
291
+ }
292
+ if (total >= 50)
293
+ break;
294
+ }
295
+ return out.join('\n\n');
296
+ }
297
+ function cmdDecisionCoverageVerify(projectDir, args, raw) {
298
+ const phaseDir = args[2] ? resolvePath(args[2], projectDir) : '';
299
+ const contextPath = args[3] ? resolvePath(args[3], projectDir) : '';
300
+ if (!gateEnabled(projectDir)) {
301
+ output({ skipped: true, blocking: false, reason: 'workflow.context_coverage_gate is false', total: 0, honored: 0, not_honored: [], message: 'Decision coverage gate disabled by config.' }, raw, undefined);
302
+ return;
303
+ }
304
+ if (!contextPath || !node_fs_1.default.existsSync(contextPath)) {
305
+ output({ skipped: true, blocking: false, reason: 'CONTEXT.md missing', total: 0, honored: 0, not_honored: [], message: 'No CONTEXT.md - nothing to check.' }, raw, undefined);
306
+ return;
307
+ }
308
+ const decisions = loadTrackableDecisions(contextPath);
309
+ if (decisions.length === 0) {
310
+ output({ skipped: true, blocking: false, reason: 'no trackable decisions', total: 0, honored: 0, not_honored: [], message: 'No trackable decisions in CONTEXT.md.' }, raw, undefined);
311
+ return;
312
+ }
313
+ const planContents = loadPlanContents(phaseDir);
314
+ const summaryParts = node_fs_1.default.existsSync(phaseDir)
315
+ ? node_fs_1.default.readdirSync(phaseDir).filter((entry) => /-SUMMARY\.md$/.test(entry)).map((entry) => readIfExists(node_path_1.default.join(phaseDir, entry)))
316
+ : [];
317
+ const haystack = [
318
+ planContents.join('\n\n'),
319
+ summaryParts.join('\n\n'),
320
+ readModifiedFilesContent(projectDir, summaryParts),
321
+ recentCommitMessages(projectDir),
322
+ ].join('\n\n');
323
+ const notHonored = [];
324
+ let honored = 0;
325
+ for (const decision of decisions) {
326
+ if (decisionMentioned(haystack, decision))
327
+ honored++;
328
+ else
329
+ notHonored.push({ id: decision.id, text: decision.text, category: decision.category });
330
+ }
331
+ output({
332
+ skipped: false,
333
+ blocking: false,
334
+ total: decisions.length,
335
+ honored,
336
+ not_honored: notHonored,
337
+ message: buildVerifyMessage(notHonored),
338
+ }, raw, undefined);
339
+ }
340
+ // ─── ui-plan-gate ─────────────────────────────────────────────────────────────
341
+ /**
342
+ * ui-plan-gate: given a phase number, checks whether the phase has frontend
343
+ * indicators and whether a *-UI-SPEC.md already exists in the phase directory.
344
+ *
345
+ * Returns JSON: { frontend: boolean, hasUiSpec: boolean, block: boolean }
346
+ * block = frontend && !hasUiSpec (gate fires when UI work is detected but no spec exists)
347
+ *
348
+ * Invocable as: gsd_run check ui-plan-gate <phase>
349
+ *
350
+ * Uses checkUiPresence from ui-safety-gate.cjs — does NOT reimplement frontend detection.
351
+ * Uses getRoadmapPhaseWithFallback + findPhaseInternal from leaf modules for phase data.
352
+ */
353
+ function findUiSpecInDir(phaseDir) {
354
+ if (!phaseDir || !node_fs_1.default.existsSync(phaseDir))
355
+ return '';
356
+ try {
357
+ const files = node_fs_1.default.readdirSync(phaseDir);
358
+ const found = files.find((f) => /-UI-SPEC\.md$/.test(f));
359
+ return found ? node_path_1.default.join(phaseDir, found) : '';
360
+ }
361
+ catch {
362
+ return '';
363
+ }
364
+ }
365
+ /**
366
+ * Pure logic for ui-plan-gate — exposed for direct behavioral testing.
367
+ *
368
+ * Given a projectDir and phase number:
369
+ * (a) Reads the phase section from ROADMAP.md via getRoadmapPhaseWithFallback —
370
+ * same two-pass lookup (current milestone → full roadmap) as `roadmap.get-phase`
371
+ * (cmdRoadmapGetPhase). Cross-milestone / older frontend phases resolve correctly.
372
+ * If ROADMAP.md is missing, phaseSection is '' (ROADMAP.md not present = project
373
+ * has no roadmap = cannot be frontend). If the phase truly can't be found after
374
+ * both passes, phaseSection is '' and phaseLookupFailed is set so callers can
375
+ * surface the miss — we do NOT silently degrade to frontend:false if the roadmap
376
+ * exists but the phase header is absent.
377
+ * (b) Runs checkUiPresence (frontend detection) — no reimplementation.
378
+ * (c) Resolves the phase directory via findPhaseInternal (phase-locator.cjs); checks for *-UI-SPEC.md.
379
+ *
380
+ * Returns: { frontend, hasUiSpec, block, uiSpecPath, phaseLookupFailed }
381
+ * block = frontend && !hasUiSpec
382
+ * phaseLookupFailed = ROADMAP.md present but phase header not found (surfaced for
383
+ * onError:halt gates so a missing phase doesn't silently bypass)
384
+ */
385
+ function computeUiPlanGate(projectDir, phase) {
386
+ // (a) Read the phase section text using the same two-pass lookup as roadmap.get-phase.
387
+ // getRoadmapPhaseWithFallback: current-milestone first, then stripShippedMilestones
388
+ // fallback — mirrors cmdRoadmapGetPhase exactly.
389
+ let phaseSection = '';
390
+ let phaseLookupFailed;
391
+ try {
392
+ const section = getRoadmapPhaseWithFallback(projectDir, phase);
393
+ if (section === null) {
394
+ // Distinguish: ROADMAP.md missing (no-roadmap project) vs phase not found in ROADMAP.
395
+ // planningDir(cwd) resolves the .planning/ root for workstream-aware paths.
396
+ const planDir = planningDir(projectDir);
397
+ const roadmapPath = node_path_1.default.join(planDir, 'ROADMAP.md');
398
+ if (node_fs_1.default.existsSync(roadmapPath)) {
399
+ // ROADMAP.md exists but phase was not found → surface the miss
400
+ phaseLookupFailed = true;
401
+ }
402
+ // phaseSection stays ''
403
+ }
404
+ else {
405
+ phaseSection = section;
406
+ }
407
+ }
408
+ catch { /* roadmap read failure → treat as empty (non-frontend) */ }
409
+ // (b) Run checkUiPresence (frontend detection) — reuse existing helper; no reimplementation
410
+ const presenceResult = (0, ui_safety_gate_cjs_1.checkUiPresence)(phaseSection);
411
+ const frontend = presenceResult.hasUI;
412
+ // (c) Resolve phase directory via findPhaseInternal and check for *-UI-SPEC.md
413
+ let phaseDir = '';
414
+ try {
415
+ const result = findPhaseInternal(projectDir, phase);
416
+ if (result && typeof result === 'object') {
417
+ // findPhaseInternal returns { directory: '<relative-posix-path>', ... }
418
+ // directory is relative to cwd — resolve it to absolute.
419
+ const relDir = typeof result['directory'] === 'string' ? result['directory'] : '';
420
+ if (relDir) {
421
+ phaseDir = node_path_1.default.resolve(projectDir, relDir);
422
+ }
423
+ }
424
+ else if (typeof result === 'string') {
425
+ phaseDir = result;
426
+ }
427
+ }
428
+ catch { /* phase dir lookup failure → hasUiSpec=false */ }
429
+ const uiSpecPath = findUiSpecInDir(phaseDir);
430
+ const hasUiSpec = uiSpecPath !== '';
431
+ // block = frontend phase with no UI-SPEC
432
+ const block = frontend && !hasUiSpec;
433
+ const result = {
434
+ frontend, hasUiSpec, block, uiSpecPath: hasUiSpec ? uiSpecPath : null,
435
+ };
436
+ if (phaseLookupFailed)
437
+ result.phaseLookupFailed = true;
438
+ return result;
439
+ }
440
+ function cmdUiPlanGate(projectDir, args, raw) {
441
+ // args[0] = 'check', args[1] = 'ui-plan-gate', args[2] = phase
442
+ const phase = args[2] || '';
443
+ if (!phase) {
444
+ error('ui-plan-gate requires a phase argument: check ui-plan-gate <phase>', ERROR_REASON.SDK_MISSING_ARG);
445
+ return;
446
+ }
447
+ output(computeUiPlanGate(projectDir, phase), raw, undefined);
448
+ }
449
+ // ─── ui-safety-gate ───────────────────────────────────────────────────────────
450
+ /**
451
+ * ui-safety-gate: post-wave check that verifies UI-changed files conform to
452
+ * the active UI-SPEC for the phase. Called after each wave by execute:wave:post.
453
+ *
454
+ * Returns JSON: { frontend: boolean, hasUiFiles: boolean, hasUiSpec: boolean, block: boolean, message?: string }
455
+ * block = frontend && hasUiFiles && !hasUiSpec
456
+ *
457
+ * Args: check ui-safety-gate <phase>
458
+ * Invocable as: gsd_run check ui-safety-gate <phase>
459
+ * or gsd_run check ui.safety-gate <phase> (dots normalized to hyphens)
460
+ *
461
+ * Uses checkUiPresence from ui-safety-gate.cjs — does NOT reimplement frontend detection.
462
+ * Checks whether any files changed in recent git history match frontend file patterns.
463
+ * Also checks whether a *-UI-SPEC.md exists in the phase directory (same as ui-plan-gate).
464
+ *
465
+ * Limitation: uses git diff HEAD~1..HEAD which covers only the last commit; in a
466
+ * multi-plan wave the wave-start commit would be more accurate but is not yet stored
467
+ * in the wave manifest. This is tracked as a known limitation.
468
+ */
469
+ const UI_FILE_EXTENSIONS_RE = /\.(tsx|jsx|css|scss|sass|less|vue|svelte|html)$/i;
470
+ const UI_PATH_PATTERNS_RE = /\/(components|pages|views|screens|layouts|ui|frontend)\//i;
471
+ /**
472
+ * Pure logic for ui-safety-gate — exposed for direct behavioral testing.
473
+ *
474
+ * Given a projectDir and phase number:
475
+ * (a) Reads the phase section from ROADMAP.md via getRoadmapPhaseWithFallback —
476
+ * same lookup as computeUiPlanGate — to determine if this is a frontend phase.
477
+ * (b) Runs checkUiPresence (frontend detection) — no reimplementation.
478
+ * (c) Checks git diff HEAD~1..HEAD for UI file changes in the current worktree.
479
+ * (d) Resolves the phase directory via findPhaseInternal (phase-locator.cjs); checks for *-UI-SPEC.md.
480
+ *
481
+ * Returns: { frontend, hasUiFiles, hasUiSpec, block, message?, phaseLookupFailed? }
482
+ * block = frontend && hasUiFiles && !hasUiSpec
483
+ * phaseLookupFailed = ROADMAP.md present but phase header not found
484
+ */
485
+ function computeUiSafetyGate(projectDir, phase) {
486
+ // (a) Read the phase section text (same two-pass lookup as computeUiPlanGate)
487
+ let phaseSection = '';
488
+ let phaseLookupFailed;
489
+ try {
490
+ const section = getRoadmapPhaseWithFallback(projectDir, phase);
491
+ if (section === null) {
492
+ const planDir = planningDir(projectDir);
493
+ const roadmapPath = node_path_1.default.join(planDir, 'ROADMAP.md');
494
+ if (node_fs_1.default.existsSync(roadmapPath)) {
495
+ phaseLookupFailed = true;
496
+ }
497
+ }
498
+ else {
499
+ phaseSection = section;
500
+ }
501
+ }
502
+ catch { /* roadmap read failure → treat as empty (non-frontend) */ }
503
+ // (b) Run checkUiPresence (frontend detection) — reuse existing helper; no reimplementation
504
+ const presenceResult = (0, ui_safety_gate_cjs_1.checkUiPresence)(phaseSection);
505
+ const frontend = presenceResult.hasUI;
506
+ // (c) Check whether any UI files were changed in recent git commits
507
+ // Uses git diff HEAD~1..HEAD to detect frontend file changes since last commit.
508
+ // Known limitation: multi-plan waves may need the wave-start commit for full coverage.
509
+ let hasUiFiles = false;
510
+ try {
511
+ const changed = (0, node_child_process_1.execFileSync)('git', ['diff', '--name-only', 'HEAD~1', 'HEAD'], {
512
+ cwd: projectDir,
513
+ encoding: 'utf-8',
514
+ maxBuffer: 2 * 1024 * 1024,
515
+ windowsHide: true,
516
+ });
517
+ hasUiFiles = changed.split('\n').some((f) => f.trim() && (UI_FILE_EXTENSIONS_RE.test(f) || UI_PATH_PATTERNS_RE.test(f)));
518
+ }
519
+ catch { /* git unavailable or no prior commit — treat as no UI files changed */ }
520
+ // (d) Resolve phase directory and check for *-UI-SPEC.md (same as computeUiPlanGate)
521
+ let phaseDir = '';
522
+ try {
523
+ const result = findPhaseInternal(projectDir, phase);
524
+ if (result && typeof result === 'object') {
525
+ const relDir = typeof result['directory'] === 'string' ? result['directory'] : '';
526
+ if (relDir) {
527
+ phaseDir = node_path_1.default.resolve(projectDir, relDir);
528
+ }
529
+ }
530
+ else if (typeof result === 'string') {
531
+ phaseDir = result;
532
+ }
533
+ }
534
+ catch { /* phase dir lookup failure → hasUiSpec=false */ }
535
+ const uiSpecPath = findUiSpecInDir(phaseDir);
536
+ const hasUiSpec = uiSpecPath !== '';
537
+ // block only when: this is a frontend phase AND UI files were changed AND no UI-SPEC exists
538
+ const block = frontend && hasUiFiles && !hasUiSpec;
539
+ const result = { frontend, hasUiFiles, hasUiSpec, block };
540
+ if (block) {
541
+ result.message = `UI files changed in this wave but no UI-SPEC.md exists for Phase ${phase}. ` +
542
+ `Run /gsd:ui-phase ${phase} to generate the design contract before continuing.`;
543
+ }
544
+ if (phaseLookupFailed)
545
+ result.phaseLookupFailed = true;
546
+ return result;
547
+ }
548
+ function cmdUiSafetyGate(projectDir, args, raw) {
549
+ // args[0] = 'check', args[1] = 'ui-safety-gate', args[2] = phase
550
+ const phase = args[2] || '';
551
+ if (!phase) {
552
+ error('ui-safety-gate requires a phase argument: check ui-safety-gate <phase>', ERROR_REASON.SDK_MISSING_ARG);
553
+ return;
554
+ }
555
+ output(computeUiSafetyGate(projectDir, phase), raw, undefined);
556
+ }
557
+ function cmdTddReviewCheckpoint(projectDir, args, raw) {
558
+ // args[0] = 'check', args[1] = 'tdd-review-checkpoint' (normalized), args[2] = phase
559
+ const phase = args[2] || '';
560
+ if (!phase) {
561
+ error('tdd.review-checkpoint requires a phase argument: check tdd.review-checkpoint <phase>', ERROR_REASON.SDK_MISSING_ARG);
562
+ return;
563
+ }
564
+ // Resolve phase directory
565
+ let phaseDir = '';
566
+ try {
567
+ const result = findPhaseInternal(projectDir, phase);
568
+ if (result && typeof result === 'object') {
569
+ const relDir = typeof result['directory'] === 'string' ? result['directory'] : '';
570
+ if (relDir)
571
+ phaseDir = node_path_1.default.resolve(projectDir, relDir);
572
+ }
573
+ else if (typeof result === 'string') {
574
+ phaseDir = result;
575
+ }
576
+ }
577
+ catch { /* phase dir lookup failure */ }
578
+ // Find all PLAN.md files with type: tdd in frontmatter
579
+ const tddPlanFiles = [];
580
+ if (phaseDir) {
581
+ try {
582
+ const files = node_fs_1.default.readdirSync(phaseDir).filter(f => f.endsWith('-PLAN.md'));
583
+ for (const file of files) {
584
+ const planPath = node_path_1.default.join(phaseDir, file);
585
+ const content = readIfExists(planPath);
586
+ // Check frontmatter for type: tdd
587
+ const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
588
+ if (frontmatterMatch) {
589
+ const fm = frontmatterMatch[1];
590
+ if (/^type:\s*tdd\s*$/m.test(fm)) {
591
+ tddPlanFiles.push(planPath);
592
+ }
593
+ }
594
+ }
595
+ }
596
+ catch { /* directory read failure */ }
597
+ }
598
+ if (tddPlanFiles.length === 0) {
599
+ const result = {
600
+ // Uniform gate contract: block = violations > 0 (advisory; never truly blocks).
601
+ block: false,
602
+ passed: true,
603
+ tddPlans: 0,
604
+ violations: 0,
605
+ table: '',
606
+ rows: [],
607
+ message: `No type:tdd plans found in phase ${phase}. TDD review skipped.`,
608
+ };
609
+ // Pass undefined as rawValue so --raw emits JSON (not plain text).
610
+ // The human-readable report is carried in `result.message` for the
611
+ // dispatch's advisory branch to surface.
612
+ output(result, raw, undefined);
613
+ return;
614
+ }
615
+ // For each TDD plan, extract the plan ID (padded plan number) and check git log
616
+ const rows = [];
617
+ for (const planPath of tddPlanFiles) {
618
+ // Extract plan ID from filename (e.g. "01-02-PLAN.md" → "01-02", or "03-PLAN.md" → "03")
619
+ const basename = node_path_1.default.basename(planPath, '-PLAN.md');
620
+ // planId for commit grep: phase-plan format, e.g. "01-02"
621
+ const planId = basename;
622
+ // Check for RED gate commit: test({planId}):
623
+ let red = false;
624
+ let green = false;
625
+ let refactor = false;
626
+ try {
627
+ const redCommit = (0, node_child_process_1.execFileSync)('git', ['log', '--oneline', `--grep=^test(${planId}):`, '--', '.'], { cwd: projectDir, encoding: 'utf-8', maxBuffer: 1024 * 1024, windowsHide: true });
628
+ red = redCommit.trim().length > 0;
629
+ }
630
+ catch { /* git unavailable or no match */ }
631
+ try {
632
+ const greenCommit = (0, node_child_process_1.execFileSync)('git', ['log', '--oneline', `--grep=^feat(${planId}):`, '--', '.'], { cwd: projectDir, encoding: 'utf-8', maxBuffer: 1024 * 1024, windowsHide: true });
633
+ green = greenCommit.trim().length > 0;
634
+ }
635
+ catch { /* git unavailable or no match */ }
636
+ try {
637
+ const refactorCommit = (0, node_child_process_1.execFileSync)('git', ['log', '--oneline', `--grep=^refactor(${planId}):`, '--', '.'], { cwd: projectDir, encoding: 'utf-8', maxBuffer: 1024 * 1024, windowsHide: true });
638
+ refactor = refactorCommit.trim().length > 0;
639
+ }
640
+ catch { /* git unavailable or no match */ }
641
+ const missing = [];
642
+ if (!red)
643
+ missing.push('RED');
644
+ if (!green)
645
+ missing.push('GREEN');
646
+ const status = missing.length === 0 ? 'Pass' : 'FAIL';
647
+ rows.push({ planId, red, green, refactor, status, missing });
648
+ }
649
+ const violations = rows.filter(r => r.status === 'FAIL').length;
650
+ // Build review table
651
+ const sep = '━'.repeat(53);
652
+ const tableHeader = '| Plan | RED | GREEN | REFACTOR | Status |';
653
+ const tableDivider = '|------|-----|-------|----------|--------|';
654
+ const tableRows = rows.map(r => `| ${r.planId.padEnd(4)} | ${r.red ? ' ✓ ' : ' ✗ '} | ${r.green ? ' ✓ ' : ' ✗ '} | ${r.refactor ? ' ✓ ' : ' — '} | ${r.status.padEnd(6)} |`);
655
+ let table = [
656
+ sep,
657
+ ` TDD REVIEW — Phase ${phase}`,
658
+ sep,
659
+ '',
660
+ `TDD Plans: ${tddPlanFiles.length} | Gate violations: ${violations}`,
661
+ '',
662
+ tableHeader,
663
+ tableDivider,
664
+ ...tableRows,
665
+ ].join('\n');
666
+ if (violations > 0) {
667
+ table += '\n\n⚠ Gate violations are advisory — review before advancing.';
668
+ for (const r of rows.filter(row => row.status === 'FAIL')) {
669
+ table += `\n Plan ${r.planId} missing: ${r.missing.join(', ')} gate commit(s).`;
670
+ table += `\n Expected commit pattern: test(${r.planId}): ... → feat(${r.planId}): ...`;
671
+ }
672
+ }
673
+ const result = {
674
+ // Uniform gate contract: block = violations > 0.
675
+ // This gate is advisory (blocking: false in capability.json) so block:true
676
+ // only surfaces as a warning, never halts. Kept here so the host-loop
677
+ // dispatch can read a single consistent `block` field.
678
+ block: violations > 0,
679
+ passed: true,
680
+ tddPlans: tddPlanFiles.length,
681
+ violations,
682
+ table,
683
+ rows,
684
+ // Human-readable report in `message` so the dispatch's advisory branch
685
+ // can surface it. --raw emits JSON (rawValue=undefined), not plain text.
686
+ message: table,
687
+ };
688
+ // Pass undefined as rawValue so --raw emits JSON (not the raw table text).
689
+ // The review table is carried in `result.message` and `result.table` so
690
+ // the host-loop dispatch's advisory branch can surface it.
691
+ output(result, raw, undefined);
692
+ }
693
+ // ─── gap-analysis-plan-post ───────────────────────────────────────────────────
694
+ /**
695
+ * gap-analysis-plan-post: non-blocking advisory check that runs the post-planning
696
+ * gap analysis after all PLAN.md files are generated for a phase.
697
+ *
698
+ * Cross-references every REQ-ID and D-ID from REQUIREMENTS.md and CONTEXT.md
699
+ * against the concatenated text of all *-PLAN.md files, emitting a coverage table.
700
+ *
701
+ * This gate is always advisory (passed: true) — it never blocks phase advancement.
702
+ *
703
+ * Args: check gap-analysis.plan-post <phase-dir> [phase-req-ids]
704
+ * Invocable as: gsd_run check gap-analysis.plan-post <phase-dir> [phase-req-ids]
705
+ */
706
+ function cmdGapAnalysisPlanPost(projectDir, args, raw) {
707
+ // args[0] = 'check', args[1] = 'gap-analysis-plan-post' (normalized), args[2] = phaseDir, args[3] = phaseReqIds
708
+ const phaseDir = args[2] || '';
709
+ if (!phaseDir) {
710
+ error('gap-analysis.plan-post requires a phase-dir argument: check gap-analysis.plan-post <phase-dir> [phase-req-ids]', ERROR_REASON.SDK_MISSING_ARG);
711
+ return;
712
+ }
713
+ const phaseReqIds = args[3] ?? undefined;
714
+ const result = runGapAnalysis(projectDir, phaseDir, { phaseReqIds });
715
+ // Uniform gate contract: block = false (gap-analysis is always advisory, never blocks).
716
+ // `message` carries the human-readable gap analysis report so the dispatch's
717
+ // advisory branch can surface it. --raw emits JSON (rawValue=undefined), not
718
+ // plain markdown text.
719
+ output({
720
+ block: false,
721
+ passed: true,
722
+ enabled: result.enabled,
723
+ table: result.table,
724
+ summary: result.summary,
725
+ counts: result.counts,
726
+ // Human-readable report in `message` for the host-loop advisory branch.
727
+ message: result.table || result.summary || '',
728
+ }, raw, undefined);
729
+ }
730
+ function routeCheckCommand({ args, cwd, raw }) {
731
+ // Normalize dots to hyphens in the subcommand so both forms are accepted.
732
+ // This makes `check.query = "ui.plan-gate"` (dotted form in capability.json gates)
733
+ // directly runnable as `gsd_run check ui.plan-gate` — the dot is normalized to
734
+ // `ui-plan-gate` before routing. The generic gate-dispatch in §5.6 reads
735
+ // `check.query` from the active gate hook and runs `gsd_run check ${hook.check.query}`,
736
+ // so the declared query must be dispatchable exactly as declared.
737
+ const rawSubcommand = args[1];
738
+ const subcommand = typeof rawSubcommand === 'string' ? rawSubcommand.replace(/\./g, '-') : rawSubcommand;
739
+ if (subcommand === 'auto-mode') {
740
+ cmdAutoMode(cwd, raw);
741
+ return;
742
+ }
743
+ if (subcommand === 'decision-coverage-plan') {
744
+ cmdDecisionCoveragePlan(cwd, args, raw);
745
+ return;
746
+ }
747
+ if (subcommand === 'decision-coverage-verify') {
748
+ cmdDecisionCoverageVerify(cwd, args, raw);
749
+ return;
750
+ }
751
+ if (subcommand === 'ui-plan-gate') {
752
+ cmdUiPlanGate(cwd, args, raw);
753
+ return;
754
+ }
755
+ if (subcommand === 'gap-analysis-plan-post') {
756
+ cmdGapAnalysisPlanPost(cwd, args, raw);
757
+ return;
758
+ }
759
+ if (subcommand === 'tdd-review-checkpoint') {
760
+ cmdTddReviewCheckpoint(cwd, args, raw);
761
+ return;
762
+ }
763
+ if (subcommand === 'ui-safety-gate') {
764
+ cmdUiSafetyGate(cwd, args, raw);
765
+ return;
766
+ }
767
+ if (subcommand === 'verify-schema-drift') {
768
+ // Delegates to verify.schema-drift — drift capability gate at execute:wave:post (blocking).
769
+ // Dot-to-hyphen normalization means query "verify.schema-drift" routes here.
770
+ // Honor GSD_SKIP_SCHEMA_CHECK=true to bypass the gate (preserves the original inline gate behavior).
771
+ const phaseArg = typeof args[2] === 'string' ? args[2] : '';
772
+ const skipSchemaCheck = process.env['GSD_SKIP_SCHEMA_CHECK'] === 'true';
773
+ cmdVerifySchemaDrift(cwd, phaseArg, skipSchemaCheck, raw);
774
+ return;
775
+ }
776
+ if (subcommand === 'verify-codebase-drift') {
777
+ // Delegates to verify.codebase-drift — drift capability gate at execute:wave:post (non-blocking).
778
+ // Dot-to-hyphen normalization means query "verify.codebase-drift" routes here.
779
+ cmdVerifyCodebaseDrift(cwd, raw);
780
+ return;
781
+ }
782
+ if (subcommand === 'prohibition-enforcement') {
783
+ // The deterministic test-tier prohibition PRODUCER/gate (#1259, ADR-550 D5d). Locates the
784
+ // wired mechanical check (node-test or lint-rule), confirms fail-first, runs it, builds
785
+ // enforcementEvidence, and emits the dispositionForProhibition verdict. Invocable as
786
+ // `gsd_run check prohibition-enforcement <request.json>`.
787
+ (0, prohibition_enforcement_cjs_1.routeProhibitionEnforcement)(args, raw);
788
+ return;
789
+ }
790
+ error('Unknown check subcommand. Available: auto-mode, decision-coverage-plan, decision-coverage-verify, gap-analysis-plan-post, prohibition-enforcement, tdd-review-checkpoint, ui-plan-gate, ui-safety-gate, verify-schema-drift, verify-codebase-drift', ERROR_REASON.SDK_UNKNOWN_COMMAND);
791
+ }
792
+ module.exports = {
793
+ routeCheckCommand,
794
+ decisionMentioned,
795
+ extractPlanDesignatedSections,
796
+ computeUiPlanGate,
797
+ computeUiSafetyGate,
798
+ cmdGapAnalysisPlanPost,
799
+ cmdTddReviewCheckpoint,
800
+ };