@opengsd/gsd-core 1.15.0 → 1.16.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 (487) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.opencode/plugins/gsd-core.js +85 -5
  4. package/agents/gsd-code-fixer.compact.md +1 -1
  5. package/agents/gsd-code-fixer.md +1 -1
  6. package/agents/gsd-code-reviewer.compact.md +5 -3
  7. package/agents/gsd-code-reviewer.md +8 -6
  8. package/agents/gsd-debug-session-manager.compact.md +1 -1
  9. package/agents/gsd-debug-session-manager.md +1 -1
  10. package/agents/gsd-debugger.md +2 -2
  11. package/agents/gsd-eval-auditor.compact.md +1 -1
  12. package/agents/gsd-eval-auditor.md +1 -1
  13. package/agents/gsd-executor.md +4 -4
  14. package/agents/gsd-intel-updater.compact.md +1 -1
  15. package/agents/gsd-intel-updater.md +1 -1
  16. package/agents/gsd-mempalace-curator.md +2 -2
  17. package/agents/gsd-phase-researcher.md +1 -1
  18. package/agents/gsd-plan-checker.md +7 -2
  19. package/agents/gsd-planner.md +3 -3
  20. package/agents/gsd-project-researcher.compact.md +1 -1
  21. package/agents/gsd-project-researcher.md +1 -1
  22. package/agents/gsd-research-synthesizer.compact.md +1 -1
  23. package/agents/gsd-research-synthesizer.md +1 -1
  24. package/agents/gsd-ui-auditor.compact.md +21 -30
  25. package/agents/gsd-ui-auditor.md +42 -51
  26. package/agents/gsd-ui-researcher.compact.md +1 -1
  27. package/agents/gsd-ui-researcher.md +1 -1
  28. package/agents/gsd-verifier.md +31 -9
  29. package/bin/install.js +126 -196
  30. package/commands/gsd/add-tests.md +6 -1
  31. package/commands/gsd/ai-integration-phase.md +6 -1
  32. package/commands/gsd/audit-fix.md +5 -0
  33. package/commands/gsd/audit-milestone.md +6 -1
  34. package/commands/gsd/autonomous.md +5 -0
  35. package/commands/gsd/capture.md +8 -4
  36. package/commands/gsd/code-review.md +7 -2
  37. package/commands/gsd/complete-milestone.md +4 -0
  38. package/commands/gsd/config.md +7 -3
  39. package/commands/gsd/debug.md +11 -7
  40. package/commands/gsd/discuss-phase.md +7 -3
  41. package/commands/gsd/docs-update.md +12 -7
  42. package/commands/gsd/eval-review.md +6 -1
  43. package/commands/gsd/execute-phase.md +12 -7
  44. package/commands/gsd/extract-learnings.md +5 -0
  45. package/commands/gsd/fast.md +4 -0
  46. package/commands/gsd/forensics.md +5 -1
  47. package/commands/gsd/graphify.md +10 -6
  48. package/commands/gsd/health.md +5 -0
  49. package/commands/gsd/help.md +7 -2
  50. package/commands/gsd/import.md +7 -3
  51. package/commands/gsd/inbox.md +5 -0
  52. package/commands/gsd/ingest-docs.md +5 -1
  53. package/commands/gsd/manager.md +6 -1
  54. package/commands/gsd/map-codebase.md +7 -3
  55. package/commands/gsd/mempalace-capture.md +5 -1
  56. package/commands/gsd/mempalace-recall.md +5 -1
  57. package/commands/gsd/milestone-summary.md +5 -1
  58. package/commands/gsd/mvp-phase.md +8 -3
  59. package/commands/gsd/new-milestone.md +6 -1
  60. package/commands/gsd/new-project.md +5 -0
  61. package/commands/gsd/next.md +6 -1
  62. package/commands/gsd/ns-context.md +4 -0
  63. package/commands/gsd/ns-ideate.md +4 -0
  64. package/commands/gsd/ns-manage.md +4 -0
  65. package/commands/gsd/ns-project.md +4 -0
  66. package/commands/gsd/ns-review.md +4 -0
  67. package/commands/gsd/ns-workflow.md +4 -0
  68. package/commands/gsd/onboard.md +6 -1
  69. package/commands/gsd/pause-work.md +5 -1
  70. package/commands/gsd/phase.md +8 -4
  71. package/commands/gsd/plan-phase.md +6 -1
  72. package/commands/gsd/plan-review-convergence.md +5 -1
  73. package/commands/gsd/pr-branch.md +4 -0
  74. package/commands/gsd/profile-user.md +5 -1
  75. package/commands/gsd/progress.md +6 -1
  76. package/commands/gsd/quick-batch.md +20 -8
  77. package/commands/gsd/quick.md +12 -7
  78. package/commands/gsd/review.md +5 -1
  79. package/commands/gsd/secure-phase.md +6 -1
  80. package/commands/gsd/ship.md +5 -0
  81. package/commands/gsd/sketch.md +7 -2
  82. package/commands/gsd/spec-phase.md +5 -1
  83. package/commands/gsd/spike.md +8 -3
  84. package/commands/gsd/surface.md +5 -1
  85. package/commands/gsd/thread.md +4 -0
  86. package/commands/gsd/ui-phase.md +6 -1
  87. package/commands/gsd/ui-review.md +6 -1
  88. package/commands/gsd/ultraplan-phase.md +5 -1
  89. package/commands/gsd/undo.md +5 -1
  90. package/commands/gsd/update.md +6 -2
  91. package/commands/gsd/validate-phase.md +6 -1
  92. package/commands/gsd/verify-work.md +6 -1
  93. package/commands/gsd/workspace.md +7 -3
  94. package/gsd-core/bin/gsd-tools.cjs +142 -56
  95. package/gsd-core/bin/lib/active-workstream-store.cjs +15 -0
  96. package/gsd-core/bin/lib/agent-install-check.cjs +4 -1
  97. package/gsd-core/bin/lib/audit.cjs +78 -44
  98. package/gsd-core/bin/lib/broken-windows.cjs +13 -13
  99. package/gsd-core/bin/lib/capability-activation.cjs +9 -4
  100. package/gsd-core/bin/lib/capability-registry.cjs +183 -103
  101. package/gsd-core/bin/lib/capability-validator.cjs +16 -0
  102. package/gsd-core/bin/lib/check-auto-mode.cjs +35 -0
  103. package/gsd-core/bin/lib/check-command-router.cjs +164 -1712
  104. package/gsd-core/bin/lib/cjs-command-router-adapter.cjs +13 -2
  105. package/gsd-core/bin/lib/cli-exit.cjs +12 -0
  106. package/gsd-core/bin/lib/codex-agent-toml.cjs +11 -8
  107. package/gsd-core/bin/lib/command-aliases.cjs +7 -0
  108. package/gsd-core/bin/lib/command-routing-hub.cjs +48 -1
  109. package/gsd-core/bin/lib/commands.cjs +173 -170
  110. package/gsd-core/bin/lib/complexity-trigger.cjs +8 -7
  111. package/gsd-core/bin/lib/config.cjs +43 -12
  112. package/gsd-core/bin/lib/core-utils.cjs +6 -1
  113. package/gsd-core/bin/lib/coverage.cjs +4 -8
  114. package/gsd-core/bin/lib/decision-coverage-support.cjs +259 -0
  115. package/gsd-core/bin/lib/drift.cjs +177 -42
  116. package/gsd-core/bin/lib/frontmatter-fence.cjs +90 -0
  117. package/gsd-core/bin/lib/frontmatter-splice.cjs +494 -0
  118. package/gsd-core/bin/lib/frontmatter.cjs +413 -234
  119. package/gsd-core/bin/lib/gap-checker.cjs +72 -29
  120. package/gsd-core/bin/lib/gate-api-coverage-verify-pre.cjs +381 -0
  121. package/gsd-core/bin/lib/gate-args.cjs +53 -0
  122. package/gsd-core/bin/lib/gate-codebase-drift.cjs +285 -0
  123. package/gsd-core/bin/lib/gate-config.cjs +46 -0
  124. package/gsd-core/bin/lib/gate-context-drift.cjs +141 -0
  125. package/gsd-core/bin/lib/gate-decision-coverage-plan.cjs +169 -0
  126. package/gsd-core/bin/lib/gate-decision-coverage-verify.cjs +126 -0
  127. package/gsd-core/bin/lib/gate-evaluation-scope.cjs +555 -0
  128. package/gsd-core/bin/lib/gate-evidence.cjs +138 -0
  129. package/gsd-core/bin/lib/gate-exit.cjs +27 -0
  130. package/gsd-core/bin/lib/gate-gap-analysis-plan-post.cjs +61 -0
  131. package/gsd-core/bin/lib/gate-phase-context.cjs +170 -0
  132. package/gsd-core/bin/lib/gate-predicate-evaluator.cjs +1 -1
  133. package/gsd-core/bin/lib/gate-predicate.cjs +165 -0
  134. package/gsd-core/bin/lib/gate-prohibition-enforcement.cjs +94 -0
  135. package/gsd-core/bin/lib/gate-schema-drift.cjs +165 -0
  136. package/gsd-core/bin/lib/gate-tdd-red-evidence.cjs +100 -0
  137. package/gsd-core/bin/lib/gate-tdd-review-checkpoint.cjs +182 -0
  138. package/gsd-core/bin/lib/gate-ui-plan.cjs +86 -0
  139. package/gsd-core/bin/lib/gate-ui-safety.cjs +80 -0
  140. package/gsd-core/bin/lib/gate-verdict.cjs +64 -0
  141. package/gsd-core/bin/lib/gate-verify-command-paths.cjs +78 -0
  142. package/gsd-core/bin/lib/gate-verify-failure-directions.cjs +41 -0
  143. package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +43 -47
  144. package/gsd-core/bin/lib/health-diagnostic.cjs +45 -8
  145. package/gsd-core/bin/lib/init.cjs +162 -96
  146. package/gsd-core/bin/lib/install-engine.cjs +19 -35
  147. package/gsd-core/bin/lib/install-profiles.cjs +7 -4
  148. package/gsd-core/bin/lib/io.cjs +122 -3
  149. package/gsd-core/bin/lib/loop-resolver.cjs +95 -0
  150. package/gsd-core/bin/lib/markdown-sectionizer.cjs +75 -1
  151. package/gsd-core/bin/lib/milestone.cjs +19 -1
  152. package/gsd-core/bin/lib/model-resolver.cjs +18 -18
  153. package/gsd-core/bin/lib/observability/event.cjs +1 -1
  154. package/gsd-core/bin/lib/observability/logger.cjs +46 -1
  155. package/gsd-core/bin/lib/pattern.cjs +10 -0
  156. package/gsd-core/bin/lib/phase-command-router.cjs +11 -4
  157. package/gsd-core/bin/lib/phase-estimation.cjs +5 -4
  158. package/gsd-core/bin/lib/phase-id.cjs +1 -1
  159. package/gsd-core/bin/lib/phase-lifecycle.cjs +9 -2
  160. package/gsd-core/bin/lib/phase-status.cjs +360 -0
  161. package/gsd-core/bin/lib/phase.cjs +280 -80
  162. package/gsd-core/bin/lib/plan-document.cjs +93 -19
  163. package/gsd-core/bin/lib/plan-drift-guard.cjs +5 -0
  164. package/gsd-core/bin/lib/planning-document.cjs +273 -40
  165. package/gsd-core/bin/lib/planning-inspect.cjs +42 -8
  166. package/gsd-core/bin/lib/planning-snapshot.cjs +18 -0
  167. package/gsd-core/bin/lib/planning-workspace.cjs +76 -53
  168. package/gsd-core/bin/lib/pristine-baseline.cjs +10 -0
  169. package/gsd-core/bin/lib/profile-output.cjs +6 -3
  170. package/gsd-core/bin/lib/prohibition-enforcement.cjs +0 -55
  171. package/gsd-core/bin/lib/quick-batch-command-router.cjs +35 -9
  172. package/gsd-core/bin/lib/quick-batch-dispatch.cjs +11 -8
  173. package/gsd-core/bin/lib/real-home-guard.cjs +9 -1
  174. package/gsd-core/bin/lib/report-parser.cjs +269 -0
  175. package/gsd-core/bin/lib/roadmap-command-router.cjs +13 -15
  176. package/gsd-core/bin/lib/roadmap-parser.cjs +82 -15
  177. package/gsd-core/bin/lib/roadmap-upgrade.cjs +127 -65
  178. package/gsd-core/bin/lib/roadmap.cjs +169 -72
  179. package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +91 -157
  180. package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +2 -1
  181. package/gsd-core/bin/lib/runtime-artifact-layout.cjs +57 -1
  182. package/gsd-core/bin/lib/runtime-homes.cjs +13 -10
  183. package/gsd-core/bin/lib/runtime-hooks-surface.cjs +307 -591
  184. package/gsd-core/bin/lib/runtime-name-policy.cjs +142 -27
  185. package/gsd-core/bin/lib/runtime-slash.cjs +47 -30
  186. package/gsd-core/bin/lib/shell-command-projection.cjs +37 -2
  187. package/gsd-core/bin/lib/smart-entry.cjs +19 -3
  188. package/gsd-core/bin/lib/stale-bake-guard.cjs +32 -48
  189. package/gsd-core/bin/lib/state-contract.cjs +15 -18
  190. package/gsd-core/bin/lib/state-document.cjs +100 -22
  191. package/gsd-core/bin/lib/state.cjs +214 -105
  192. package/gsd-core/bin/lib/surface.cjs +2 -1
  193. package/gsd-core/bin/lib/tdd-red-evidence.cjs +48 -152
  194. package/gsd-core/bin/lib/uat-predicate.cjs +313 -35
  195. package/gsd-core/bin/lib/uat.cjs +424 -7
  196. package/gsd-core/bin/lib/ui-frontend-evidence.cjs +94 -58
  197. package/gsd-core/bin/lib/vendor/README.md +31 -9
  198. package/gsd-core/bin/lib/vendor/saxes.cjs +1934 -0
  199. package/gsd-core/bin/lib/vendor/saxes.cjs.LICENSE.txt +92 -0
  200. package/gsd-core/bin/lib/vendor/tap-parser.cjs +8927 -0
  201. package/gsd-core/bin/lib/vendor/tap-parser.cjs.LICENSE.txt +152 -0
  202. package/gsd-core/bin/lib/verification-command-router.cjs +2 -1
  203. package/gsd-core/bin/lib/verification.cjs +1165 -314
  204. package/gsd-core/bin/lib/verify-command-router.cjs +18 -7
  205. package/gsd-core/bin/lib/verify.cjs +286 -567
  206. package/gsd-core/bin/lib/workstream-inventory-builder.cjs +14 -6
  207. package/gsd-core/bin/lib/workstream-inventory.cjs +31 -21
  208. package/gsd-core/bin/lib/workstream-name-policy.cjs +31 -1
  209. package/gsd-core/bin/lib/workstream.cjs +11 -2
  210. package/gsd-core/bin/shared/config-defaults.manifest.json +5 -0
  211. package/gsd-core/bin/shared/config-schema.manifest.json +4 -0
  212. package/gsd-core/references/autonomous-smart-discuss.md +2 -1
  213. package/gsd-core/references/autonomous-ui-design-contract.md +3 -3
  214. package/gsd-core/references/execute-mvp-tdd.md +5 -10
  215. package/gsd-core/references/execute-phase-between-wave-reset.md +3 -0
  216. package/gsd-core/references/execute-phase-response-language.md +1 -1
  217. package/gsd-core/references/gsd-run-resolver.md +1 -1
  218. package/gsd-core/references/loop-hook-dispatch.md +7 -1
  219. package/gsd-core/references/offer-next.md +1 -1
  220. package/gsd-core/references/planning-config.md +1 -1
  221. package/gsd-core/references/spidr-splitting.md +1 -1
  222. package/gsd-core/references/tdd.md +10 -4
  223. package/gsd-core/references/verifier-phase-gates.md +5 -2
  224. package/gsd-core/references/verify-mvp-mode.md +2 -2
  225. package/gsd-core/references/workstream-flag.md +33 -3
  226. package/gsd-core/templates/README.md +1 -1
  227. package/gsd-core/templates/UAT.md +17 -1
  228. package/gsd-core/templates/config.json +2 -11
  229. package/gsd-core/templates/verification-report.md +1 -1
  230. package/gsd-core/workflows/_runtime-launcher.snippet.sh +1 -1
  231. package/gsd-core/workflows/add-backlog.md +1 -1
  232. package/gsd-core/workflows/add-phase.md +8 -7
  233. package/gsd-core/workflows/add-tests.md +3 -2
  234. package/gsd-core/workflows/add-todo.md +4 -3
  235. package/gsd-core/workflows/ai-integration-phase.md +3 -2
  236. package/gsd-core/workflows/audit-fix.md +1 -1
  237. package/gsd-core/workflows/audit-milestone.md +4 -3
  238. package/gsd-core/workflows/audit-uat.md +1 -1
  239. package/gsd-core/workflows/autonomous.md +28 -18
  240. package/gsd-core/workflows/check-todos.md +6 -5
  241. package/gsd-core/workflows/cleanup.md +1 -1
  242. package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +20 -13
  243. package/gsd-core/workflows/code-review-fix.md +5 -4
  244. package/gsd-core/workflows/code-review.md +84 -90
  245. package/gsd-core/workflows/complete-milestone/detail/elaboration.md +4 -3
  246. package/gsd-core/workflows/complete-milestone.md +12 -7
  247. package/gsd-core/workflows/debug.md +30 -5
  248. package/gsd-core/workflows/diagnose-issues.md +3 -2
  249. package/gsd-core/workflows/discuss-phase/modes/advisor.md +1 -1
  250. package/gsd-core/workflows/discuss-phase/modes/chain.md +1 -1
  251. package/gsd-core/workflows/discuss-phase-assumptions.md +4 -3
  252. package/gsd-core/workflows/discuss-phase.md +4 -3
  253. package/gsd-core/workflows/do.md +1 -1
  254. package/gsd-core/workflows/docs-update.md +4 -3
  255. package/gsd-core/workflows/edit-phase.md +4 -3
  256. package/gsd-core/workflows/eval-review.md +5 -3
  257. package/gsd-core/workflows/execute-phase/detail/elaboration.md +1 -1
  258. package/gsd-core/workflows/execute-phase/steps/code-review-disposition.md +4 -2
  259. package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +15 -4
  260. package/gsd-core/workflows/execute-phase/steps/completion-reconciliation.md +10 -7
  261. package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +1 -1
  262. package/gsd-core/workflows/execute-phase/steps/gap-closure-artifacts.md +3 -1
  263. package/gsd-core/workflows/execute-phase/steps/partial-wave.md +2 -2
  264. package/gsd-core/workflows/execute-phase/steps/per-plan-executor-routing.md +1 -1
  265. package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +1 -1
  266. package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +1 -1
  267. package/gsd-core/workflows/execute-phase/steps/protected-branch.md +1 -1
  268. package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +1 -1
  269. package/gsd-core/workflows/execute-phase/steps/regression-gate.md +2 -0
  270. package/gsd-core/workflows/execute-phase/steps/tdd-applicability-resolution.md +1 -1
  271. package/gsd-core/workflows/execute-phase/steps/verify-phase-goal.md +187 -0
  272. package/gsd-core/workflows/execute-phase/steps/wave-post-gate-hooks.md +2 -3
  273. package/gsd-core/workflows/execute-phase.md +78 -170
  274. package/gsd-core/workflows/execute-plan.md +13 -19
  275. package/gsd-core/workflows/explore.md +2 -2
  276. package/gsd-core/workflows/extract-learnings.md +3 -2
  277. package/gsd-core/workflows/fast.md +1 -1
  278. package/gsd-core/workflows/forensics.md +1 -1
  279. package/gsd-core/workflows/graduation.md +1 -1
  280. package/gsd-core/workflows/health.md +2 -1
  281. package/gsd-core/workflows/import.md +3 -2
  282. package/gsd-core/workflows/inbox.md +1 -1
  283. package/gsd-core/workflows/ingest-docs.md +1 -1
  284. package/gsd-core/workflows/insert-phase.md +4 -3
  285. package/gsd-core/workflows/list-seeds.md +1 -1
  286. package/gsd-core/workflows/list-workspaces.md +1 -1
  287. package/gsd-core/workflows/manager.md +5 -3
  288. package/gsd-core/workflows/map-codebase.md +4 -3
  289. package/gsd-core/workflows/milestone-summary.md +3 -2
  290. package/gsd-core/workflows/mvp-phase.md +14 -14
  291. package/gsd-core/workflows/new-milestone.md +10 -10
  292. package/gsd-core/workflows/new-project/steps/auto-mode-config.md +1 -1
  293. package/gsd-core/workflows/new-project.md +1 -1
  294. package/gsd-core/workflows/new-workspace.md +1 -1
  295. package/gsd-core/workflows/next.md +1 -1
  296. package/gsd-core/workflows/pause-work.md +2 -2
  297. package/gsd-core/workflows/plan-phase/detail/elaboration.md +1 -1
  298. package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +1 -1
  299. package/gsd-core/workflows/plan-phase/steps/closed-phase-gate.md +1 -1
  300. package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +1 -1
  301. package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +1 -1
  302. package/gsd-core/workflows/plan-phase.md +27 -18
  303. package/gsd-core/workflows/plan-review-convergence.md +1 -1
  304. package/gsd-core/workflows/plant-seed.md +1 -1
  305. package/gsd-core/workflows/pr-branch.md +1 -1
  306. package/gsd-core/workflows/profile-user.md +1 -1
  307. package/gsd-core/workflows/progress.md +19 -49
  308. package/gsd-core/workflows/quick/steps/plan-checker-loop.md +4 -2
  309. package/gsd-core/workflows/quick/steps/quick-verification.md +4 -4
  310. package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +30 -11
  311. package/gsd-core/workflows/quick-batch/steps/batch-init.md +1 -1
  312. package/gsd-core/workflows/quick-batch/steps/completion.md +1 -1
  313. package/gsd-core/workflows/quick-batch/steps/merge-wave.md +1 -1
  314. package/gsd-core/workflows/quick-batch/steps/planner-wave.md +1 -1
  315. package/gsd-core/workflows/quick-batch/steps/research-phase.md +1 -1
  316. package/gsd-core/workflows/quick-batch/steps/resume-mode.md +1 -1
  317. package/gsd-core/workflows/quick-batch/steps/verification-wave.md +9 -3
  318. package/gsd-core/workflows/quick-batch/steps/worktree-dispatch.md +1 -1
  319. package/gsd-core/workflows/quick-batch.md +15 -10
  320. package/gsd-core/workflows/quick.md +42 -31
  321. package/gsd-core/workflows/remove-phase.md +3 -2
  322. package/gsd-core/workflows/remove-workspace.md +1 -1
  323. package/gsd-core/workflows/resume-project.md +3 -2
  324. package/gsd-core/workflows/review.md +3 -2
  325. package/gsd-core/workflows/scan.md +3 -2
  326. package/gsd-core/workflows/secure-phase.md +11 -12
  327. package/gsd-core/workflows/settings-advanced.md +1 -1
  328. package/gsd-core/workflows/settings-integrations.md +1 -1
  329. package/gsd-core/workflows/settings.md +1 -1
  330. package/gsd-core/workflows/ship.md +12 -12
  331. package/gsd-core/workflows/sketch-wrap-up.md +1 -1
  332. package/gsd-core/workflows/sketch.md +1 -1
  333. package/gsd-core/workflows/smart-entry.md +1 -1
  334. package/gsd-core/workflows/spec-phase.md +1 -1
  335. package/gsd-core/workflows/spike-wrap-up.md +1 -1
  336. package/gsd-core/workflows/spike.md +1 -1
  337. package/gsd-core/workflows/stats.md +1 -1
  338. package/gsd-core/workflows/sync-skills.md +1 -1
  339. package/gsd-core/workflows/thread.md +2 -2
  340. package/gsd-core/workflows/transition.md +13 -23
  341. package/gsd-core/workflows/ui-phase.md +5 -4
  342. package/gsd-core/workflows/ui-review.md +4 -3
  343. package/gsd-core/workflows/ultraplan-phase.md +3 -2
  344. package/gsd-core/workflows/undo.md +1 -1
  345. package/gsd-core/workflows/validate-phase.md +10 -12
  346. package/gsd-core/workflows/verify-work/detail/elaboration.md +43 -3
  347. package/gsd-core/workflows/verify-work/steps/automated-ui-verification.md +1 -1
  348. package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +5 -3
  349. package/gsd-core/workflows/verify-work.md +68 -59
  350. package/hooks/dist/gsd-agent-isolation-guard.js +8 -0
  351. package/hooks/dist/gsd-check-update-worker.js +8 -0
  352. package/hooks/dist/gsd-check-update.js +8 -0
  353. package/hooks/dist/gsd-context-monitor.js +31 -8
  354. package/hooks/dist/gsd-cursor-subagent-start.js +8 -0
  355. package/hooks/dist/gsd-secret-read-guard.js +147 -16
  356. package/hooks/dist/gsd-statusline.js +15 -7
  357. package/hooks/dist/gsd-update-banner.js +8 -0
  358. package/hooks/dist/gsd-windsurf-pre-write.js +11 -2
  359. package/hooks/dist/gsd-workflow-guard.js +5 -4
  360. package/hooks/dist/gsd-worktree-path-guard.js +6 -2
  361. package/hooks/dist/lib/cli-exit.js +12 -0
  362. package/hooks/dist/lib/git-probe.js +17 -1
  363. package/hooks/dist/lib/isolation-sentinel.js +2 -2
  364. package/hooks/gsd-agent-isolation-guard.js +8 -0
  365. package/hooks/gsd-check-update-worker.js +8 -0
  366. package/hooks/gsd-check-update.js +8 -0
  367. package/hooks/gsd-context-monitor.js +31 -8
  368. package/hooks/gsd-cursor-subagent-start.js +8 -0
  369. package/hooks/gsd-secret-read-guard.js +147 -16
  370. package/hooks/gsd-statusline.js +15 -7
  371. package/hooks/gsd-update-banner.js +8 -0
  372. package/hooks/gsd-windsurf-pre-write.js +11 -2
  373. package/hooks/gsd-workflow-guard.js +5 -4
  374. package/hooks/gsd-worktree-path-guard.js +6 -2
  375. package/hooks/hooks.json +5 -5
  376. package/hooks/lib/cli-exit.js +12 -0
  377. package/hooks/lib/git-probe.js +17 -1
  378. package/hooks/lib/isolation-sentinel.js +2 -2
  379. package/package.json +21 -4
  380. package/scripts/changeset/parse.cjs +52 -4
  381. package/scripts/ci-timeout-report.cjs +770 -4
  382. package/scripts/command-contract-helpers.cjs +12 -8
  383. package/scripts/docs-guard-registry.cjs +6 -0
  384. package/scripts/gen-features.cjs +13 -8
  385. package/scripts/gen-hooks-cli-exit.cjs +12 -28
  386. package/scripts/gen-loop-host-contract.cjs +10 -1
  387. package/scripts/gen-platform-conformance-tier.cjs +187 -1
  388. package/scripts/gen-plugin-skills.cjs +87 -1
  389. package/scripts/gen-research-agents.cjs +24 -31
  390. package/scripts/gen-scripts-cli-exit.cjs +30 -3
  391. package/scripts/gen-test-timings.cjs +32 -7
  392. package/scripts/lib/cli-exit.cjs +12 -0
  393. package/scripts/lib/macos-conformance-tier.generated.cjs +20 -2
  394. package/scripts/lib/ndjson-reporter.cjs +28 -3
  395. package/scripts/lib/platform-conformance-tier.generated.cjs +34 -5
  396. package/scripts/lib/registration-ledger-preload.cjs +155 -0
  397. package/scripts/lib/vendor-bundle.cjs +59 -0
  398. package/scripts/lib/vendor-licenses/saxes-6.0.0.txt +64 -0
  399. package/scripts/lint-allow-test-rule-refs.effective-ceiling.json +1 -1
  400. package/scripts/lint-allow-test-rule-refs.unverified-ceiling.json +1 -1
  401. package/scripts/lint-completion-predicate-drift.cjs +18 -19
  402. package/scripts/lint-descriptions.cjs +7 -3
  403. package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +10 -0
  404. package/scripts/lint-eslint-glob-coverage.allowlist.json +20 -0
  405. package/scripts/lint-frontmatter-fence-drift.cjs +313 -0
  406. package/scripts/lint-frontmatter-scalar-broad-grep.cjs +122 -16
  407. package/scripts/lint-phase-enumeration-drift.cjs +12 -8
  408. package/scripts/lint-phase-id-drift.cjs +29 -0
  409. package/scripts/lint-planning-document-positive-control.cjs +329 -0
  410. package/scripts/lint-response-language-coverage.cjs +3 -0
  411. package/scripts/lint-skill-deps.cjs +7 -3
  412. package/scripts/lint-test-file-count.allowlist.json +11 -1
  413. package/scripts/lint-test-file-count.cjs +34 -1
  414. package/scripts/lint-vendored-deps.cjs +41 -5
  415. package/scripts/lint-workflow-shellcheck-baseline.json +10 -10
  416. package/scripts/mutation-matrix.cjs +50 -5
  417. package/scripts/require-issue-link-policy.cjs +6 -2
  418. package/scripts/sync-runtime-launcher.cjs +184 -2
  419. package/scripts/verify-npm-publish.cjs +76 -20
  420. package/skills/gsd-add-tests/SKILL.md +6 -1
  421. package/skills/gsd-ai-integration-phase/SKILL.md +6 -1
  422. package/skills/gsd-audit-fix/SKILL.md +5 -0
  423. package/skills/gsd-audit-milestone/SKILL.md +6 -1
  424. package/skills/gsd-autonomous/SKILL.md +5 -0
  425. package/skills/gsd-capture/SKILL.md +8 -4
  426. package/skills/gsd-code-review/SKILL.md +7 -2
  427. package/skills/gsd-complete-milestone/SKILL.md +4 -0
  428. package/skills/gsd-config/SKILL.md +8 -4
  429. package/skills/gsd-debug/SKILL.md +11 -7
  430. package/skills/gsd-discuss-phase/SKILL.md +7 -3
  431. package/skills/gsd-docs-update/SKILL.md +12 -7
  432. package/skills/gsd-eval-review/SKILL.md +6 -1
  433. package/skills/gsd-execute-phase/SKILL.md +12 -7
  434. package/skills/gsd-extract-learnings/SKILL.md +5 -0
  435. package/skills/gsd-fast/SKILL.md +4 -0
  436. package/skills/gsd-forensics/SKILL.md +5 -1
  437. package/skills/gsd-graphify/SKILL.md +10 -6
  438. package/skills/gsd-health/SKILL.md +5 -0
  439. package/skills/gsd-help/SKILL.md +7 -2
  440. package/skills/gsd-import/SKILL.md +7 -3
  441. package/skills/gsd-inbox/SKILL.md +5 -0
  442. package/skills/gsd-ingest-docs/SKILL.md +5 -1
  443. package/skills/gsd-manager/SKILL.md +6 -1
  444. package/skills/gsd-map-codebase/SKILL.md +7 -3
  445. package/skills/gsd-mempalace-capture/SKILL.md +5 -1
  446. package/skills/gsd-mempalace-recall/SKILL.md +5 -1
  447. package/skills/gsd-milestone-summary/SKILL.md +5 -1
  448. package/skills/gsd-mvp-phase/SKILL.md +8 -3
  449. package/skills/gsd-new-milestone/SKILL.md +6 -1
  450. package/skills/gsd-new-project/SKILL.md +5 -0
  451. package/skills/gsd-next/SKILL.md +6 -1
  452. package/skills/gsd-ns-context/SKILL.md +4 -0
  453. package/skills/gsd-ns-ideate/SKILL.md +4 -0
  454. package/skills/gsd-ns-manage/SKILL.md +4 -0
  455. package/skills/gsd-ns-project/SKILL.md +4 -0
  456. package/skills/gsd-ns-review/SKILL.md +4 -0
  457. package/skills/gsd-ns-workflow/SKILL.md +4 -0
  458. package/skills/gsd-onboard/SKILL.md +6 -1
  459. package/skills/gsd-pause-work/SKILL.md +5 -1
  460. package/skills/gsd-phase/SKILL.md +8 -4
  461. package/skills/gsd-plan-phase/SKILL.md +6 -1
  462. package/skills/gsd-plan-review-convergence/SKILL.md +5 -1
  463. package/skills/gsd-pr-branch/SKILL.md +4 -0
  464. package/skills/gsd-profile-user/SKILL.md +5 -1
  465. package/skills/gsd-progress/SKILL.md +6 -1
  466. package/skills/gsd-quick/SKILL.md +16 -10
  467. package/skills/gsd-quick-batch/SKILL.md +20 -8
  468. package/skills/gsd-review/SKILL.md +5 -1
  469. package/skills/gsd-review-backlog/SKILL.md +3 -2
  470. package/skills/gsd-secure-phase/SKILL.md +6 -1
  471. package/skills/gsd-ship/SKILL.md +5 -0
  472. package/skills/gsd-sketch/SKILL.md +7 -2
  473. package/skills/gsd-spec-phase/SKILL.md +5 -1
  474. package/skills/gsd-spike/SKILL.md +8 -3
  475. package/skills/gsd-surface/SKILL.md +5 -1
  476. package/skills/gsd-thread/SKILL.md +4 -0
  477. package/skills/gsd-ui-phase/SKILL.md +6 -1
  478. package/skills/gsd-ui-review/SKILL.md +6 -1
  479. package/skills/gsd-ultraplan-phase/SKILL.md +5 -1
  480. package/skills/gsd-undo/SKILL.md +5 -1
  481. package/skills/gsd-update/SKILL.md +6 -2
  482. package/skills/gsd-validate-phase/SKILL.md +6 -1
  483. package/skills/gsd-verify-work/SKILL.md +6 -1
  484. package/skills/gsd-workspace/SKILL.md +7 -3
  485. package/skills/gsd-workstreams/SKILL.md +6 -6
  486. package/vscode/package.json +1 -1
  487. package/gsd-core/workflows/execute-phase/steps/stale-reverification.md +0 -24
@@ -0,0 +1,59 @@
1
+ 'use strict';
2
+
3
+ const fs = require('node:fs');
4
+ const path = require('node:path');
5
+ const { isBuiltin } = require('node:module');
6
+ const { buildSync } = require('esbuild');
7
+
8
+ /** Rebuild locked upstream code without edits; installed trees need no node_modules. */
9
+ function buildVendorBundle(root, entry) {
10
+ const result = buildSync({
11
+ absWorkingDir: root,
12
+ entryPoints: [entry],
13
+ bundle: true,
14
+ platform: 'node',
15
+ format: 'cjs',
16
+ target: 'node24',
17
+ write: false,
18
+ metafile: true,
19
+ legalComments: 'inline',
20
+ banner: { js: '// Generated from locked npm dependencies by lint-vendored-deps.cjs --fix. Do not edit.' },
21
+ });
22
+ for (const output of Object.values(result.metafile.outputs)) {
23
+ for (const imported of output.imports) {
24
+ if (imported.external && !isBuiltin(imported.path)) {
25
+ throw new Error(`Vendor bundle has an external dependency: ${imported.path}`);
26
+ }
27
+ }
28
+ }
29
+ const packages = new Map();
30
+ for (const input of Object.keys(result.metafile.inputs)) {
31
+ let dir = path.dirname(path.resolve(root, input));
32
+ while (dir !== root && dir !== path.dirname(dir)) {
33
+ const manifest = path.join(dir, 'package.json');
34
+ if (fs.existsSync(manifest)) {
35
+ const pkg = JSON.parse(fs.readFileSync(manifest, 'utf8'));
36
+ if (pkg.name && pkg.version) {
37
+ const licenses = fs.readdirSync(dir).filter((name) => /^(licen[sc]e|copying|notice)(\.|$)/i.test(name)).sort();
38
+ // saxes 6.0.0 omits its LICENSE from npm; preserve the exact tagged
39
+ // upstream file (https://github.com/lddubeau/saxes/blob/v6.0.0/LICENSE).
40
+ const supplemental = path.join(__dirname, 'vendor-licenses', `${pkg.name}-${pkg.version}.txt`);
41
+ if (licenses.length === 0 && !fs.existsSync(supplemental)) throw new Error(`Missing upstream license: ${pkg.name}`);
42
+ packages.set(`${pkg.name}@${pkg.version}`, [
43
+ `${pkg.name}@${pkg.version} (package metadata: ${pkg.license})`,
44
+ ...licenses.map((name) => `${name}:\n${fs.readFileSync(path.join(dir, name), 'utf8')}`),
45
+ ...(licenses.length === 0 ? [fs.readFileSync(supplemental, 'utf8')] : []),
46
+ ].join('\n\n'));
47
+ break;
48
+ }
49
+ }
50
+ dir = path.dirname(dir);
51
+ }
52
+ }
53
+ return {
54
+ code: result.outputFiles[0].contents,
55
+ notices: Buffer.from([...packages.keys()].sort().map((name) => packages.get(name)).join('\n\n---\n\n') + '\n'),
56
+ };
57
+ }
58
+
59
+ module.exports = { buildVendorBundle };
@@ -0,0 +1,64 @@
1
+ The ISC License
2
+
3
+ Copyright (c) Contributors
4
+
5
+ Permission to use, copy, modify, and/or distribute this software for any
6
+ purpose with or without fee is hereby granted, provided that the above
7
+ copyright notice and this permission notice appear in all copies.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
15
+ IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
+
17
+ ====
18
+
19
+ The following license is the one that governed sax, from which saxes
20
+ was forked. Isaac Schlueter is not *directly* involved with saxes so
21
+ don't go bugging him for saxes issues.
22
+
23
+ The ISC License
24
+
25
+ Copyright (c) Isaac Z. Schlueter and Contributors
26
+
27
+ Permission to use, copy, modify, and/or distribute this software for any
28
+ purpose with or without fee is hereby granted, provided that the above
29
+ copyright notice and this permission notice appear in all copies.
30
+
31
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
32
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
33
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
34
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
35
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
36
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
37
+ IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
38
+
39
+ ====
40
+
41
+ `String.fromCodePoint` by Mathias Bynens is no longer used, but it can
42
+ still be found in old commits. It was once used according to terms of
43
+ MIT License, as follows:
44
+
45
+ Copyright Mathias Bynens <https://mathiasbynens.be/>
46
+
47
+ Permission is hereby granted, free of charge, to any person obtaining
48
+ a copy of this software and associated documentation files (the
49
+ "Software"), to deal in the Software without restriction, including
50
+ without limitation the rights to use, copy, modify, merge, publish,
51
+ distribute, sublicense, and/or sell copies of the Software, and to
52
+ permit persons to whom the Software is furnished to do so, subject to
53
+ the following conditions:
54
+
55
+ The above copyright notice and this permission notice shall be
56
+ included in all copies or substantial portions of the Software.
57
+
58
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
59
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
60
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
61
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
62
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
63
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
64
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -1,4 +1,4 @@
1
1
  {
2
- "maxSites": 84,
2
+ "maxSites": 64,
3
3
  "grace": 2
4
4
  }
@@ -1,3 +1,3 @@
1
1
  {
2
- "maxFiles": 283
2
+ "maxFiles": 284
3
3
  }
@@ -805,17 +805,17 @@ const OWNER_FILE = path.join('src', 'verification.cts');
805
805
  // one (the owner consumes plan counts, never the reverse). Left as its
806
806
  // own, differently-scoped answer, per design's "Rejected" list item 1.
807
807
  //
808
- // - `buildWorkstreamInventory` (src/workstream-inventory-builder.cts) — a
809
- // PURE, I/O-free projection (see the module's own header) over
810
- // PRE-COLLECTED `planCount`/`summaryCount`/`verificationStatus` inputs.
811
- // `summariesMeetPlans = summaryCount >= planCount && planCount > 0`
812
- // answers "are all plans summarized?" (combined with the caller-supplied
813
- // verification verdict for its own `status` projection) — it cannot call
808
+ // - `buildWorkstreamInventory` (src/workstream-inventory-builder.cts) —
809
+ // formerly exempted here (a PURE, I/O-free projection that hand-rolled
810
+ // `summaryCount >= planCount && planCount > 0` locally, unable to call
814
811
  // the I/O-bound `isPhaseComplete` without breaking its "No I/O. No
815
- // async." contract, and re-plumbing its callers to pass a pre-computed
816
- // `complete` boolean instead of raw counts is a larger architectural
817
- // change than this phase's declared 6 call sites. Declared deviation —
818
- // see the Phase 4 migration PR for the full reasoning.
812
+ // async." contract). #5060 (Phase Status Module, epic #5056) gave this
813
+ // exact "pure function over pre-collected facts" shape a real owner —
814
+ // `phaseStatusFromFacts` (`src/phase-status.cts`) — which is itself
815
+ // import-free at load time and does no I/O, so this function now calls
816
+ // it instead of re-deriving the comparison locally. The local textual
817
+ // shapes this guard matches are gone; the exemption entry was removed
818
+ // rather than left dead.
819
819
  //
820
820
  // - `buildPhaseCompletionProjection` (src/init.cts) — MIGRATED onto
821
821
  // `isPhaseComplete` for `phase_complete`/`verification_status` (shape
@@ -832,17 +832,17 @@ const OWNER_FILE = path.join('src', 'verification.cts');
832
832
  //
833
833
  // SHAPE (d) reuses this exact map (`findScanPhasePlansCompletedReadDrift`
834
834
  // takes the same `exemptFunctions` set every other shape's finder does). The
835
- // four entries above were entered for shapes (a)/(b)/(c); of them, only
835
+ // entries above were entered for shapes (a)/(b)/(c); of them, only
836
836
  // `scanPhasePlans` (src/plan-scan.cts) also legitimately reads its OWN
837
837
  // `completed` field for shape (d)'s purposes (building the return value it
838
838
  // itself defines — not a call-then-read of another `scanPhasePlans(`
839
- // invocation). `isPhaseComplete`, `buildWorkstreamInventory`, and
840
- // `buildPhaseCompletionProjection` do not read `.completed` off a
841
- // `scanPhasePlans(` call result at all (verified by direct inspection of
842
- // each function's body as of this guard's shape-(d) addition — they consume
843
- // `planCount`/`summaryCount`/`summaryFiles`, never `.completed`), so their
844
- // presence in this map exempts nothing NEW for shape (d); they are listed
845
- // here only because the map is shared. As of this addition, a whole-repo
839
+ // invocation). `isPhaseComplete` and `buildPhaseCompletionProjection` do not
840
+ // read `.completed` off a `scanPhasePlans(` call result at all (verified by
841
+ // direct inspection of each function's body as of this guard's shape-(d)
842
+ // addition — they consume `planCount`/`summaryCount`/`summaryFiles`, never
843
+ // `.completed`), so their presence in this map exempts nothing NEW for shape
844
+ // (d); they are listed here only because the map is shared. As of this
845
+ // addition, a whole-repo
846
846
  // scan found ZERO live shape-(d) sites needing a fresh exemption entry — the
847
847
  // one real instance this shape exists to catch (`cmdStateSync`,
848
848
  // src/state.cts) was fixed by routing through `isPhaseComplete` rather than
@@ -852,7 +852,6 @@ const OWNER_FILE = path.join('src', 'verification.cts');
852
852
  const FUNCTION_SCOPED_EXEMPTIONS = new Map([
853
853
  [OWNER_FILE, new Set(['isPhaseComplete'])],
854
854
  [path.join('src', 'plan-scan.cts'), new Set(['scanPhasePlans'])],
855
- [path.join('src', 'workstream-inventory-builder.cts'), new Set(['buildWorkstreamInventory'])],
856
855
  [path.join('src', 'init.cts'), new Set(['buildPhaseCompletionProjection'])],
857
856
  ]);
858
857
 
@@ -16,6 +16,9 @@
16
16
  const fs = require('fs');
17
17
  const path = require('path');
18
18
  const { ExitError, runMain } = require('./lib/cli-exit.cjs');
19
+ // The one frontmatter fence owner (src/frontmatter-fence.cts, built by build:lib).
20
+ // This dev-time script runs after the build (`npm run lint:descriptions`, the tests).
21
+ const { locateFrontmatterFence } = require('../gsd-core/bin/lib/frontmatter-fence.cjs');
19
22
 
20
23
  const MAX_LENGTH = 100;
21
24
  const COMMANDS_DIR = path.join(__dirname, '..', 'commands', 'gsd');
@@ -25,9 +28,10 @@ const COMMANDS_DIR = path.join(__dirname, '..', 'commands', 'gsd');
25
28
  * Returns null if no description is found.
26
29
  */
27
30
  function parseDescription(content) {
28
- const fmMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
29
- if (!fmMatch) return null;
30
- const fm = fmMatch[1];
31
+ // The block is the one the one fence owner finds (found while implementing #5105).
32
+ const fence = locateFrontmatterFence(content);
33
+ if (!fence || !fence.closed) return null;
34
+ const fm = content.slice(fence.openEnd, fence.bodyEnd);
31
35
 
32
36
  const quoted = fm.match(/^description:\s+"((?:[^"\\]|\\.)*)"\s*$/m);
33
37
  if (quoted) return quoted[1];
@@ -88,6 +88,7 @@ const DOCS_GUARD_EXEMPT_BASELINE = [
88
88
  'security-prompt-injection.security.test.cjs',
89
89
  'shipped-reference-cites.test.cjs',
90
90
  'state.test.cjs',
91
+ 'verification-status.test.cjs',
91
92
  'worktree-safety.test.cjs',
92
93
  ];
93
94
 
@@ -236,6 +237,15 @@ const DOCS_GUARD_EXEMPT_DOCS_PATHS = {
236
237
  // #4186: the record-session usage-contract test cites the documented
237
238
  // signature in docs/CLI-TOOLS.md in its explanatory comment.
238
239
  'state.test.cjs': ['docs/CLI-TOOLS.md', 'docs/CONFIGURATION.md', 'docs/reference/state-md.md'],
240
+ // #5095: 'docs/VERIFICATION.md' is a tmpdir fixture basename (proving the
241
+ // report-shaped filter matches basename, not full path); 'docs/planning'
242
+ // and its two nested PLAN/SUMMARY children are an in-repo `.planning ->
243
+ // docs/planning` symlink-alias fixture. All are WRITTEN into a throwaway
244
+ // mkdtemp/createTempGitProject tree; none reads real shipped docs/ content.
245
+ 'verification-status.test.cjs': [
246
+ 'docs/VERIFICATION.md', 'docs/planning', 'docs/planning/phases',
247
+ 'docs/planning/phases/01-foo/01-01-PLAN.md', 'docs/planning/phases/01-foo/01-01-SUMMARY.md',
248
+ ],
239
249
  'worktree-safety.test.cjs': ['docs/SUMMARY.md'],
240
250
  };
241
251
 
@@ -11,6 +11,14 @@
11
11
  "path": "src/vendor/js-yaml.d.cts",
12
12
  "reason": "Vendored third-party type declaration (ADR-3473 §8.1, #3881): a .d.cts carries no executable code, so no ESLint rule is meaningful; the vendored js-yaml .cjs it describes is globally ignored as verbatim upstream output (gsd-core/bin/lib/vendor/**). Freshness is enforced by scripts/lint-vendored-deps.cjs, not by lint rules — same precedent as src/vendor/re2js.d.cts above."
13
13
  },
14
+ {
15
+ "path": "src/vendor/saxes.d.cts",
16
+ "reason": "Upstream type forwarding for the vendored saxes bundle (#4692): declaration-only export with no executable code. scripts/lint-vendored-deps.cjs enforces the exact forwarding declaration; TypeScript checks consumers against upstream types."
17
+ },
18
+ {
19
+ "path": "src/vendor/tap-parser.d.cts",
20
+ "reason": "Upstream type forwarding for the vendored tap-parser bundle (#4692): declaration-only export with no executable code. scripts/lint-vendored-deps.cjs enforces the exact forwarding declaration; TypeScript checks consumers against upstream types."
21
+ },
14
22
  {
15
23
  "path": "tests/fixtures/brand-typing/bad-calibrated-as-sample-basis.cts",
16
24
  "reason": "Deliberate MUST-NOT-COMPILE type-error fixture (#3059): type-aware linting would fail by design; it exists to prove the compiler rejects it."
@@ -34,5 +42,17 @@
34
42
  {
35
43
  "path": "tests/fixtures/brand-typing/ok-correct-composition.cts",
36
44
  "reason": "Positive-control counterpart to the bad-* must-not-compile fixtures (#3059); kept in the same exemption so the pair stays together."
45
+ },
46
+ {
47
+ "path": "tests/fixtures/gate-evidence-typing/bad-pass-from-unreadable.cts",
48
+ "reason": "Deliberate MUST-NOT-COMPILE type-error fixture (#5170): the unreadable-evidence branding makes a passing outcome from unreadable evidence a compile error, and tests/gate-evidence.test.cjs asserts tsc rejects it; type-aware linting would fail by design."
49
+ },
50
+ {
51
+ "path": "tests/fixtures/gate-evidence-typing/bad-unbranded-unreadable.cts",
52
+ "reason": "Deliberate MUST-NOT-COMPILE type-error fixture (#5170): the unreadable-evidence branding makes a passing outcome from unreadable evidence a compile error, and tests/gate-evidence.test.cjs asserts tsc rejects it; type-aware linting would fail by design."
53
+ },
54
+ {
55
+ "path": "tests/fixtures/gate-evidence-typing/ok-unreadable-arm.cts",
56
+ "reason": "Positive-control counterpart to the gate-evidence-typing bad-* must-not-compile fixtures (#5170): tsc compiles it clean; kept in the same exemption so the pair stays together."
37
57
  }
38
58
  ]
@@ -0,0 +1,313 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /**
5
+ * Anti-divergence drift guard for the FRONTMATTER FENCE seam (found while
6
+ * implementing #5105; ADR-5057 one-owner rule).
7
+ *
8
+ * `src/frontmatter-fence.cts`'s `locateFrontmatterFence` is the SINGLE owner of
9
+ * "where does a document's frontmatter block start and stop" — the BOM, the
10
+ * byte-0 opening fence, the whole-line closing fence, an adjacent empty block,
11
+ * the lenient `----` closer. Before it existed that answer was re-derived in
12
+ * some thirty places across `src/` (regexes like `/^---\r?\n([\s\S]*?)\r?\n---/`,
13
+ * `indexOf('\n---', 4)`, `lines[0].trim() === '---'`), and the copies disagreed
14
+ * on a BOM, CRLF, an adjacent empty block, `----`, `--- x`, a `---` inside a
15
+ * value and leading whitespace. This guard keeps a new copy from appearing.
16
+ *
17
+ * Mechanism: the shared `scripts/lib/drift-scan.cjs` tree walk and regex-literal
18
+ * tokenizer (ADR-3180 Decision 4), scanning the WHOLE `src/` and `hooks/` trees
19
+ * (the hooks load the built `bin/lib` behind `ensureRuntimeBuild`), the dev-time
20
+ * `scripts/` and `eslint-rules/` trees (every one of them that runs after
21
+ * `build:lib` requires the owner from `gsd-core/bin/lib/frontmatter-fence.cjs`),
22
+ * the two hand-written entry points that load `bin/lib` (`bin/install.js`,
23
+ * `gsd-core/bin/gsd-tools.cjs`), and the two native plugin adapters
24
+ * (`.opencode/plugins/gsd-core.js`, `.kilo/plugins/gsd-core.js`), with
25
+ * FUNCTION-SCOPED exemptions carrying a written reason — never a bare file
26
+ * allowlist — exactly as `lint-milestone-window-drift.cjs` does.
27
+ *
28
+ * KEPT COPIES (found while implementing #5105). A file that must run where the
29
+ * built owner may not exist keeps a self-contained copy of `locateFrontmatterFence`,
30
+ * and only that one function is allowlisted: `scripts/changeset/parse.cjs` (the
31
+ * `changeset-lint` CI job runs it with no `npm ci` and no build) and the two plugin
32
+ * adapters (a package/git-spec tree may carry no built `bin/lib`). Each copy is
33
+ * pinned to the owner by tests/frontmatter-fence.test.cjs ("kept frontmatter fence
34
+ * copies agree with the owner") over a fixture corpus and a property test.
35
+ *
36
+ * DETECTORS. Three files carry a regex that recognizes a fence idiom in OTHER
37
+ * text — this guard itself, `lint-frontmatter-scalar-broad-grep.cjs` (workflow
38
+ * shell snippets) and the `no-crlf-fragile-split` ESLint rule (regex literals in
39
+ * source). None of them locates a frontmatter block; each is exempt only for its
40
+ * exact fragment (`DETECTOR_EXEMPTIONS`), so any other fence code in the same
41
+ * file is still flagged.
42
+ *
43
+ * A line (comment text stripped) is a fence re-derivation when it carries:
44
+ * (a) a regex literal whose text contains `---` (`/^---/`, `/\n---/`,
45
+ * `/(\r?\n)---$/`), or
46
+ * (b) `new RegExp(` together with a string/template literal containing `---`, or
47
+ * (c) a fence-shaped string literal — `'---'`, `'\n---'`, `'---\n'`,
48
+ * `'---\r\n'`, `'\r\n---'` — that is the direct argument of
49
+ * `.startsWith(`/`.endsWith(`/`.indexOf(`/`.lastIndexOf(`/`.split(`, or an
50
+ * operand of `===`/`!==`/`==`/`!=`, or (only when it carries a line
51
+ * ending) the argument of `.includes(`.
52
+ * A template literal that BUILDS a block (`` `---\n${yaml}\n---` ``) or an array
53
+ * of fence lines to join is a writer emitting a fence, not a reader locating
54
+ * one, and is not flagged.
55
+ *
56
+ * KNOWN, ACCEPTED limits of a per-line textual scan (the sibling guards'
57
+ * tradeoff): a derivation split across lines, or routed through a variable
58
+ * holding the `---` literal, is left to code review and to the consumer-parity
59
+ * tests in `tests/frontmatter-fence.test.cjs`.
60
+ */
61
+
62
+ const fs = require('node:fs');
63
+ const path = require('node:path');
64
+ const driftScan = require('./lib/drift-scan.cjs');
65
+ const { readRegexLiteralAt, MAX_REGEX_LITERAL_LEN, sanitizeForReport, scanTree } = driftScan;
66
+
67
+ // Authored TypeScript source (the generated bin/lib/*.cjs mirror it) and the runtime hooks
68
+ // (`hooks/dist`, their build output, is skipped by the shared walker), plus the two hand-written
69
+ // entry points that load bin/lib and so can — and must — read the owner too.
70
+ const SCAN_TREES = [
71
+ { dirs: ['src'], ext: new Set(['.cts', '.ts', '.mts']) },
72
+ { dirs: ['hooks'], ext: new Set(['.js', '.cjs']) },
73
+ { dirs: ['scripts', 'eslint-rules'], ext: new Set(['.js', '.cjs', '.mjs']) },
74
+ ];
75
+ const SCAN_FILES = [
76
+ path.join('bin', 'install.js'),
77
+ path.join('gsd-core', 'bin', 'gsd-tools.cjs'),
78
+ path.join('.opencode', 'plugins', 'gsd-core.js'),
79
+ path.join('.kilo', 'plugins', 'gsd-core.js'),
80
+ ];
81
+
82
+ const OWNER_FILE = path.join('src', 'frontmatter-fence.cts');
83
+
84
+ // Code outside any top-level function (a module-scope constant) is keyed as this.
85
+ const TOP_LEVEL = '<top-level>';
86
+
87
+ // FUNCTION-SCOPED exemptions, each with its reason:
88
+ // - frontmatter-fence.cts `locateFrontmatterFence`: this IS the owner. Its
89
+ // module-scope fence constants (`CLOSING_FENCE_LINE`, `LENIENT_CLOSING_FENCE_LINE`)
90
+ // sit OUTSIDE this function, at TOP_LEVEL, and are exempted by exact fragment
91
+ // in DETECTOR_EXEMPTIONS below instead — a blanket TOP_LEVEL pass here would
92
+ // let any new top-level helper in this file go unscanned (#5105 fix).
93
+ // - phase.cts `phaseEntryInsertOffset`: its `lastIndexOf('\n---')` finds the
94
+ // ROADMAP's trailing section SEPARATOR (a thematic break closing the phase
95
+ // list) so a new phase entry is appended before it — it never asks where a
96
+ // frontmatter block is.
97
+ // - shell-command-projection.cts `_normalizeMd`: `prevTrimmed !== '---'` is
98
+ // the Markdown normalizer's "no blank line after a thematic break" rule,
99
+ // applied line by line to BODY text; that normalizer's frontmatter skip
100
+ // (`leadingFrontmatterLineCount`) reads the owner.
101
+ // - scripts/changeset/parse.cjs `locateFrontmatterFence`: a kept copy of the
102
+ // owner (#5105) — the `changeset-lint` job in changeset-required.yml runs it
103
+ // with no `npm ci` and no `build:lib`. Pinned to the owner by the parity test
104
+ // tests/frontmatter-fence.test.cjs "kept frontmatter fence copies agree with the owner".
105
+ // - .opencode/plugins/gsd-core.js and .kilo/plugins/gsd-core.js
106
+ // `locateFrontmatterFence`: kept copies of the owner (#5105) — the plugin loads
107
+ // from a package/git-spec tree that may carry no built bin/lib. Pinned to the
108
+ // owner by the same parity test.
109
+ const FUNCTION_SCOPED_EXEMPTIONS = new Map([
110
+ [OWNER_FILE, new Set(['locateFrontmatterFence'])],
111
+ [path.join('src', 'phase.cts'), new Set(['phaseEntryInsertOffset'])],
112
+ [path.join('src', 'shell-command-projection.cts'), new Set(['_normalizeMd'])],
113
+ [path.join('scripts', 'changeset', 'parse.cjs'), new Set(['locateFrontmatterFence'])],
114
+ [path.join('.opencode', 'plugins', 'gsd-core.js'), new Set(['locateFrontmatterFence'])],
115
+ [path.join('.kilo', 'plugins', 'gsd-core.js'), new Set(['locateFrontmatterFence'])],
116
+ ]);
117
+
118
+ // FRAGMENT-SCOPED exemptions for DETECTORS (#5105), each pinned to the exact
119
+ // reported fragment (the literal's source text) — a regex that recognizes a fence
120
+ // idiom in other text, never one that locates a frontmatter block:
121
+ // - this guard's own fence-literal matcher (`FENCE_LITERAL_CONTENT_RE`);
122
+ // - lint-frontmatter-scalar-broad-grep.cjs `FRONTMATTER_SCOPE_RE`, which finds a
123
+ // `^---`-scoped extraction in a workflow's shell snippet;
124
+ // - the no-crlf-fragile-split ESLint rule's `^---` probe, which classifies a
125
+ // regex literal in linted source as frontmatter-shaped.
126
+ const DETECTOR_EXEMPTIONS = new Map([
127
+ [path.join('scripts', 'lint-frontmatter-fence-drift.cjs'), new Set(['/^(?:\\\\r)?(?:\\\\n)?---(?:\\\\r)?(?:\\\\n)?$/'])],
128
+ [path.join('scripts', 'lint-frontmatter-scalar-broad-grep.cjs'), new Set(['/\\^---[\\s\\S]{0,300}?---/'])],
129
+ [path.join('eslint-rules', 'no-crlf-fragile-split.cjs'), new Set(['/\\^---/'])],
130
+ // The owner's own module-scope fence-literal constants (#5105 fix): these ARE
131
+ // the canonical closing-fence patterns, not a re-derivation — exempted by their
132
+ // exact fragment rather than by a blanket TOP_LEVEL pass, so a NEW top-level
133
+ // helper in this file (one that merely happens to sit outside a function) is
134
+ // still caught.
135
+ [OWNER_FILE, new Set(['/^---[ \\t]*$/', '/^-{4,}[ \\t]*$/'])],
136
+ ]);
137
+
138
+ // Only a column-0 top-level `function` declaration updates the current-function
139
+ // tracker (mirrors lint-milestone-window-drift.cjs); ANY OTHER non-blank,
140
+ // non-`}` column-0 line — a `const`, a `module.exports =`, an `export const`
141
+ // arrow, anything — resets it to TOP_LEVEL. (#5105 fix: the previous version
142
+ // only reset on a fixed keyword list, so a top-level statement it didn't
143
+ // recognize — e.g. `module.exports = { ... }` — silently inherited the LAST
144
+ // exempted function's name and went unscanned.)
145
+ const TOP_LEVEL_FUNCTION_RE = /^(?:export\s+)?(?:async\s+)?function\s+([A-Za-z0-9_$]+)\s*\(/;
146
+ const COLUMN_ZERO_RESET_RE = /^[^\s}]/;
147
+
148
+ const NEW_REGEXP_RE = /new\s+RegExp\s*\(/;
149
+
150
+ // A fence-shaped string literal's CONTENT (source text between the quotes):
151
+ // `---`, optionally preceded by `\n`/`\r\n` and optionally followed by `\n`/`\r\n`.
152
+ const FENCE_LITERAL_CONTENT_RE = /^(?:\\r)?(?:\\n)?---(?:\\r)?(?:\\n)?$/;
153
+
154
+ const SEARCH_CALL_BEFORE_RE = /\.(startsWith|endsWith|indexOf|lastIndexOf|split|includes)\(\s*$/;
155
+ const COMPARE_BEFORE_RE = /[!=]==?\s*$/;
156
+ const COMPARE_AFTER_RE = /^\s*[!=]==?/;
157
+
158
+ /**
159
+ * Read the quoted or backtick-delimited string literal starting at `line[start]`.
160
+ * Returns `{ text, end }` (delimiters included) or null. Same single-pass,
161
+ * escape-aware, bounded style as the shared `readRegexLiteralAt`.
162
+ */
163
+ function readStringLiteralAt(line, start) {
164
+ const quote = line[start];
165
+ if (quote !== "'" && quote !== '"' && quote !== '`') return null;
166
+ const limit = Math.min(line.length, start + MAX_REGEX_LITERAL_LEN);
167
+ for (let i = start + 1; i < limit; i++) {
168
+ const ch = line[i];
169
+ if (ch === '\\') {
170
+ i++;
171
+ continue;
172
+ }
173
+ if (ch === '\r' || ch === '\n') return null;
174
+ if (ch === quote) return { text: line.slice(start, i + 1), end: i + 1 };
175
+ }
176
+ return null;
177
+ }
178
+
179
+ /**
180
+ * Strip comment text from a line (whole-line `*`, `/*`, `//`, and a trailing
181
+ * `//`), as the sibling guards do — prose about a fence is not a fence.
182
+ */
183
+ function stripComments(line) {
184
+ const trimmed = line.trim();
185
+ if (trimmed.startsWith('*') || trimmed.startsWith('/*') || trimmed.startsWith('//')) return '';
186
+ const idx = line.indexOf('//');
187
+ return idx === -1 ? line : line.slice(0, idx);
188
+ }
189
+
190
+ /** Every regex and string literal on `code`, in order, with its kind and span. */
191
+ function literalsOf(code) {
192
+ const out = [];
193
+ for (let i = 0; i < code.length; i++) {
194
+ const ch = code[i];
195
+ let literal = null;
196
+ let kind = null;
197
+ if (ch === '/' && code[i + 1] !== '/' && code[i + 1] !== '*') {
198
+ literal = readRegexLiteralAt(code, i);
199
+ kind = 'regex';
200
+ } else if (ch === "'" || ch === '"' || ch === '`') {
201
+ literal = readStringLiteralAt(code, i);
202
+ kind = 'string';
203
+ }
204
+ if (!literal) continue;
205
+ out.push({ kind, text: literal.text, start: i, end: literal.end });
206
+ i = literal.end - 1;
207
+ }
208
+ return out;
209
+ }
210
+
211
+ /** The fence re-derivation fragment on a comment-stripped line, or null. */
212
+ function fenceFragment(code) {
213
+ const literals = literalsOf(code);
214
+ const hasNewRegExp = NEW_REGEXP_RE.test(code);
215
+ for (const lit of literals) {
216
+ if (lit.kind === 'regex') {
217
+ if (lit.text.includes('---')) return lit.text;
218
+ continue;
219
+ }
220
+ const content = lit.text.slice(1, -1);
221
+ if (hasNewRegExp && content.includes('---')) return lit.text;
222
+ if (!FENCE_LITERAL_CONTENT_RE.test(content)) continue;
223
+ const before = code.slice(0, lit.start);
224
+ const after = code.slice(lit.end);
225
+ const call = SEARCH_CALL_BEFORE_RE.exec(before);
226
+ if (call && (call[1] !== 'includes' || content.includes('\\n'))) return lit.text;
227
+ if (COMPARE_BEFORE_RE.test(before) || COMPARE_AFTER_RE.test(after)) return lit.text;
228
+ }
229
+ return null;
230
+ }
231
+
232
+ /**
233
+ * Pure: every unsanctioned frontmatter-fence re-derivation in `text`.
234
+ * `relPath` is the repo-relative path, for reporting and the exemptions.
235
+ * Returns [{ line, fn, found }].
236
+ */
237
+ function findFrontmatterFenceDrift(text, relPath) {
238
+ const out = [];
239
+ const lines = text.split('\n');
240
+ const exemptFunctions = FUNCTION_SCOPED_EXEMPTIONS.get(relPath) || null;
241
+ const exemptFragments = DETECTOR_EXEMPTIONS.get(relPath) || null;
242
+ let currentFunction = TOP_LEVEL;
243
+ for (let i = 0; i < lines.length; i++) {
244
+ const line = lines[i];
245
+ const fnMatch = TOP_LEVEL_FUNCTION_RE.exec(line);
246
+ if (fnMatch) currentFunction = fnMatch[1];
247
+ else if (COLUMN_ZERO_RESET_RE.test(line)) currentFunction = TOP_LEVEL;
248
+
249
+ const code = stripComments(line);
250
+ if (!code.includes('---')) continue;
251
+ const found = fenceFragment(code);
252
+ if (found === null) continue;
253
+ if (exemptFunctions && exemptFunctions.has(currentFunction)) continue;
254
+ if (exemptFragments && exemptFragments.has(found)) continue;
255
+ out.push({ line: i + 1, fn: currentFunction, found });
256
+ }
257
+ return out;
258
+ }
259
+
260
+ /** Scan the authored source tree and entry points; every violation carries its repo-relative file. */
261
+ function scanRepo(root) {
262
+ const violations = [];
263
+ for (const { dirs, ext } of SCAN_TREES) {
264
+ violations.push(...scanTree({
265
+ root,
266
+ scanDirs: dirs,
267
+ scanExt: ext,
268
+ onFile(rel, text) {
269
+ return findFrontmatterFenceDrift(text, rel).map((d) => ({ file: rel, ...d }));
270
+ },
271
+ }));
272
+ }
273
+ for (const rel of SCAN_FILES) {
274
+ let text;
275
+ try {
276
+ text = fs.readFileSync(path.join(root, rel), 'utf8');
277
+ } catch {
278
+ continue; // absent in a fixture tree
279
+ }
280
+ violations.push(...findFrontmatterFenceDrift(text, rel).map((d) => ({ file: rel, ...d })));
281
+ }
282
+ return violations;
283
+ }
284
+
285
+ function main() {
286
+ const root = path.join(__dirname, '..');
287
+ const violations = scanRepo(root);
288
+ if (violations.length === 0) {
289
+ process.stdout.write('ok frontmatter-fence-drift: no frontmatter fence re-derivations outside frontmatter-fence.cts\n');
290
+ return;
291
+ }
292
+ process.stderr.write('frontmatter-fence-drift: independent re-derivation(s) of the frontmatter fence found.\n');
293
+ process.stderr.write('Use `locateFrontmatterFence` (src/frontmatter-fence.cts) for offsets, or `frontmatterBlock` /\n');
294
+ process.stderr.write('`frontmatterRegion` / `extractFrontmatter` / `stripFrontmatter` (src/frontmatter.cts) for content:\n');
295
+ for (const d of violations) {
296
+ process.stderr.write(` ${sanitizeForReport(d.file)}:${d.line} (${sanitizeForReport(d.fn)}) ${sanitizeForReport(d.found)}\n`);
297
+ }
298
+ process.exitCode = 1;
299
+ }
300
+
301
+ if (require.main === module) main();
302
+
303
+ module.exports = {
304
+ findFrontmatterFenceDrift,
305
+ scanRepo,
306
+ fenceFragment,
307
+ stripComments,
308
+ readStringLiteralAt,
309
+ OWNER_FILE,
310
+ TOP_LEVEL,
311
+ FUNCTION_SCOPED_EXEMPTIONS,
312
+ DETECTOR_EXEMPTIONS,
313
+ };