@opengsd/gsd-core 1.10.0 → 1.12.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 (544) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/agents/gsd-code-fixer.md +1 -1
  4. package/agents/gsd-debug-session-manager.md +12 -1
  5. package/agents/gsd-debugger.md +1 -1
  6. package/agents/gsd-doc-synthesizer.md +2 -4
  7. package/agents/gsd-dom-verifier.md +169 -0
  8. package/agents/gsd-eval-auditor.md +1 -1
  9. package/agents/gsd-executor.md +22 -14
  10. package/agents/gsd-framework-selector.md +1 -3
  11. package/agents/gsd-intel-updater.md +1 -1
  12. package/agents/gsd-mempalace-curator.md +5 -3
  13. package/agents/gsd-pattern-mapper.md +11 -0
  14. package/agents/gsd-phase-researcher.md +23 -2
  15. package/agents/gsd-plan-checker.md +50 -53
  16. package/agents/gsd-planner.md +50 -50
  17. package/agents/gsd-project-researcher.md +1 -1
  18. package/agents/gsd-research-synthesizer.md +2 -2
  19. package/agents/gsd-roadmapper.md +15 -11
  20. package/agents/gsd-ui-checker.md +63 -4
  21. package/agents/gsd-ui-researcher.md +41 -3
  22. package/agents/gsd-user-profiler.md +3 -0
  23. package/agents/gsd-verifier.md +13 -4
  24. package/bin/install.js +1448 -1103
  25. package/commands/gsd/code-review.md +1 -1
  26. package/commands/gsd/discuss-phase.md +1 -1
  27. package/commands/gsd/execute-phase.md +1 -1
  28. package/commands/gsd/import.md +1 -1
  29. package/commands/gsd/map-codebase.md +1 -1
  30. package/commands/gsd/mempalace-capture.md +1 -1
  31. package/commands/gsd/mempalace-recall.md +1 -1
  32. package/commands/gsd/new-milestone.md +1 -1
  33. package/commands/gsd/quick.md +9 -5
  34. package/commands/gsd/review-backlog.md +2 -1
  35. package/commands/gsd/verify-work.md +1 -1
  36. package/gsd-core/bin/gsd-tools.cjs +1035 -138
  37. package/gsd-core/bin/lib/active-workstream-store.cjs +146 -22
  38. package/gsd-core/bin/lib/adr-parser.cjs +13 -7
  39. package/gsd-core/bin/lib/agent-install-check.cjs +392 -32
  40. package/gsd-core/bin/lib/api-coverage.cjs +33 -14
  41. package/gsd-core/bin/lib/artifacts.cjs +5 -0
  42. package/gsd-core/bin/lib/assumption-delta.cjs +32 -15
  43. package/gsd-core/bin/lib/audit-command-router.cjs +9 -2
  44. package/gsd-core/bin/lib/audit.cjs +1026 -268
  45. package/gsd-core/bin/lib/broken-windows.cjs +306 -28
  46. package/gsd-core/bin/lib/capability-consent.cjs +149 -15
  47. package/gsd-core/bin/lib/capability-lifecycle.cjs +45 -0
  48. package/gsd-core/bin/lib/capability-lock.cjs +10 -4
  49. package/gsd-core/bin/lib/capability-registry.cjs +845 -130
  50. package/gsd-core/bin/lib/capability-source.cjs +92 -0
  51. package/gsd-core/bin/lib/capability-state.cjs +18 -3
  52. package/gsd-core/bin/lib/capability-trust.cjs +444 -25
  53. package/gsd-core/bin/lib/capability-validator.cjs +700 -40
  54. package/gsd-core/bin/lib/capability-writer.cjs +3 -2
  55. package/gsd-core/bin/lib/check-command-router.cjs +216 -42
  56. package/gsd-core/bin/lib/claude-orchestration.cjs +56 -3
  57. package/gsd-core/bin/lib/cli-exit.cjs +496 -10
  58. package/gsd-core/bin/lib/code-review-depth.cjs +288 -0
  59. package/gsd-core/bin/lib/codex-agent-toml.cjs +735 -0
  60. package/gsd-core/bin/lib/command-aliases.cjs +22 -0
  61. package/gsd-core/bin/lib/command-arg-projection.cjs +144 -14
  62. package/gsd-core/bin/lib/command-roster.cjs +44 -1
  63. package/gsd-core/bin/lib/command-routing-hub.cjs +31 -2
  64. package/gsd-core/bin/lib/commands.cjs +1172 -108
  65. package/gsd-core/bin/lib/commonjs-marker.cjs +12 -6
  66. package/gsd-core/bin/lib/complexity-trigger.cjs +1192 -0
  67. package/gsd-core/bin/lib/config-loader.cjs +187 -23
  68. package/gsd-core/bin/lib/config.cjs +102 -3
  69. package/gsd-core/bin/lib/configuration.cjs +129 -37
  70. package/gsd-core/bin/lib/core-utils.cjs +208 -33
  71. package/gsd-core/bin/lib/decisions.cjs +23 -0
  72. package/gsd-core/bin/lib/edge-probe.cjs +9 -1
  73. package/gsd-core/bin/lib/estimate-cli.cjs +55 -11
  74. package/gsd-core/bin/lib/exit-code-registry.cjs +98 -0
  75. package/gsd-core/bin/lib/fallow-runner.cjs +20 -44
  76. package/gsd-core/bin/lib/frontmatter.cjs +899 -229
  77. package/gsd-core/bin/lib/gap-checker.cjs +95 -10
  78. package/gsd-core/bin/lib/git-base-branch.cjs +276 -39
  79. package/gsd-core/bin/lib/gsd2-import.cjs +10 -1
  80. package/gsd-core/bin/lib/health-diagnostic-rules/agent-install.cjs +101 -0
  81. package/gsd-core/bin/lib/health-diagnostic-rules/config-validation.cjs +348 -0
  82. package/gsd-core/bin/lib/health-diagnostic-rules/consistency.cjs +149 -0
  83. package/gsd-core/bin/lib/health-diagnostic-rules/install-surface-shadowing.cjs +98 -0
  84. package/gsd-core/bin/lib/health-diagnostic-rules/milestone-archive-hygiene.cjs +100 -0
  85. package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +222 -0
  86. package/gsd-core/bin/lib/health-diagnostic-rules/roadmap-disk-consistency.cjs +268 -0
  87. package/gsd-core/bin/lib/health-diagnostic-rules/root-existence.cjs +161 -0
  88. package/gsd-core/bin/lib/health-diagnostic-rules/state-consistency.cjs +303 -0
  89. package/gsd-core/bin/lib/health-diagnostic-rules/worktree-health.cjs +187 -0
  90. package/gsd-core/bin/lib/health-diagnostic-types.cjs +68 -0
  91. package/gsd-core/bin/lib/health-diagnostic.cjs +451 -0
  92. package/gsd-core/bin/lib/host-integration.cjs +39 -6
  93. package/gsd-core/bin/lib/host-runtime-detection.cjs +134 -0
  94. package/gsd-core/bin/lib/init-command-router.cjs +118 -21
  95. package/gsd-core/bin/lib/init.cjs +439 -168
  96. package/gsd-core/bin/lib/install-effort-resolver.cjs +73 -30
  97. package/gsd-core/bin/lib/install-engine.cjs +811 -259
  98. package/gsd-core/bin/lib/install-fs-adapter.cjs +262 -0
  99. package/gsd-core/bin/lib/install-model-override-resolver.cjs +235 -0
  100. package/gsd-core/bin/lib/install-profiles.cjs +212 -61
  101. package/gsd-core/bin/lib/install-scope.cjs +270 -0
  102. package/gsd-core/bin/lib/install-shadow-report.cjs +385 -0
  103. package/gsd-core/bin/lib/installed-surface-resolver.cjs +381 -0
  104. package/gsd-core/bin/lib/installer-migration-report.cjs +3 -0
  105. package/gsd-core/bin/lib/installer-migrations/010-antigravity-retire-confighome-artifacts.cjs +169 -0
  106. package/gsd-core/bin/lib/installer-migrations.cjs +148 -38
  107. package/gsd-core/bin/lib/intel.cjs +101 -26
  108. package/gsd-core/bin/lib/io.cjs +170 -15
  109. package/gsd-core/bin/lib/learnings.cjs +85 -14
  110. package/gsd-core/bin/lib/legacy-cleanup.cjs +8 -2
  111. package/gsd-core/bin/lib/markdown-sectionizer.cjs +2 -1
  112. package/gsd-core/bin/lib/markdown-table.cjs +183 -22
  113. package/gsd-core/bin/lib/milestone-lock.cjs +248 -0
  114. package/gsd-core/bin/lib/milestone.cjs +842 -73
  115. package/gsd-core/bin/lib/model-catalog.cjs +232 -16
  116. package/gsd-core/bin/lib/model-resolver.cjs +193 -68
  117. package/gsd-core/bin/lib/normalize-test-command.cjs +1 -1
  118. package/gsd-core/bin/lib/onboard-projection.cjs +5 -1
  119. package/gsd-core/bin/lib/pattern.cjs +122 -0
  120. package/gsd-core/bin/lib/phase-estimation.cjs +18 -9
  121. package/gsd-core/bin/lib/phase-id.cjs +514 -40
  122. package/gsd-core/bin/lib/phase-lifecycle.cjs +52 -19
  123. package/gsd-core/bin/lib/phase-locator.cjs +262 -34
  124. package/gsd-core/bin/lib/phase.cjs +1038 -214
  125. package/gsd-core/bin/lib/plan-dependency-graph.cjs +72 -1
  126. package/gsd-core/bin/lib/plan-document.cjs +263 -0
  127. package/gsd-core/bin/lib/plan-drift-guard.cjs +120 -0
  128. package/gsd-core/bin/lib/plan-scan.cjs +98 -3
  129. package/gsd-core/bin/lib/planning-command-router.cjs +61 -0
  130. package/gsd-core/bin/lib/planning-inspect.cjs +1168 -0
  131. package/gsd-core/bin/lib/planning-scope.cjs +31 -0
  132. package/gsd-core/bin/lib/planning-snapshot.cjs +894 -0
  133. package/gsd-core/bin/lib/planning-workspace.cjs +112 -6
  134. package/gsd-core/bin/lib/probe-core.cjs +5 -2
  135. package/gsd-core/bin/lib/profile-output.cjs +1 -1
  136. package/gsd-core/bin/lib/profile-pipeline-command-router.cjs +50 -7
  137. package/gsd-core/bin/lib/profile-pipeline.cjs +6 -3
  138. package/gsd-core/bin/lib/real-home-guard.cjs +419 -0
  139. package/gsd-core/bin/lib/refactor-trigger-command-router.cjs +766 -0
  140. package/gsd-core/bin/lib/retired-artifact-cleanup.cjs +11 -6
  141. package/gsd-core/bin/lib/review-lane-descriptor.cjs +22 -13
  142. package/gsd-core/bin/lib/review-lane-invocation.cjs +30 -0
  143. package/gsd-core/bin/lib/review-lane-runner.cjs +421 -66
  144. package/gsd-core/bin/lib/review-reviewer-selection.cjs +13 -18
  145. package/gsd-core/bin/lib/roadmap-command-router.cjs +59 -11
  146. package/gsd-core/bin/lib/roadmap-parser.cjs +1006 -184
  147. package/gsd-core/bin/lib/roadmap-upgrade.cjs +37 -10
  148. package/gsd-core/bin/lib/roadmap.cjs +442 -96
  149. package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +702 -52
  150. package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +14 -2
  151. package/gsd-core/bin/lib/runtime-artifact-layout.cjs +459 -55
  152. package/gsd-core/bin/lib/runtime-config-adapter-registry.cjs +3 -2
  153. package/gsd-core/bin/lib/runtime-homes.cjs +69 -3
  154. package/gsd-core/bin/lib/runtime-hooks-surface.cjs +402 -58
  155. package/gsd-core/bin/lib/runtime-identity.cjs +234 -0
  156. package/gsd-core/bin/lib/runtime-name-policy.cjs +3 -1
  157. package/gsd-core/bin/lib/runtime-slash.cjs +96 -8
  158. package/gsd-core/bin/lib/security.cjs +104 -5
  159. package/gsd-core/bin/lib/shell-command-projection.cjs +342 -7
  160. package/gsd-core/bin/lib/smart-entry.cjs +133 -23
  161. package/gsd-core/bin/lib/spec-section.cjs +12 -7
  162. package/gsd-core/bin/lib/state-command-router.cjs +52 -19
  163. package/gsd-core/bin/lib/state-contract.cjs +359 -0
  164. package/gsd-core/bin/lib/state-document.cjs +338 -8
  165. package/gsd-core/bin/lib/state-md-schema.cjs +221 -0
  166. package/gsd-core/bin/lib/state-transition.cjs +846 -176
  167. package/gsd-core/bin/lib/state.cjs +2589 -369
  168. package/gsd-core/bin/lib/surface.cjs +33 -11
  169. package/gsd-core/bin/lib/task-command-router.cjs +111 -1
  170. package/gsd-core/bin/lib/task-content-resolution.cjs +368 -0
  171. package/gsd-core/bin/lib/teams-status.cjs +4 -1
  172. package/gsd-core/bin/lib/text-lines.cjs +80 -0
  173. package/gsd-core/bin/lib/token-scanner.cjs +76 -0
  174. package/gsd-core/bin/lib/uat-predicate.cjs +67 -23
  175. package/gsd-core/bin/lib/uat.cjs +1761 -167
  176. package/gsd-core/bin/lib/ui-consideration-probe.cjs +9 -1
  177. package/gsd-core/bin/lib/ui-frontend-evidence.cjs +157 -0
  178. package/gsd-core/bin/lib/ui-safety-gate.cjs +51 -12
  179. package/gsd-core/bin/lib/unusable-input.cjs +37 -0
  180. package/gsd-core/bin/lib/update-context.cjs +8 -2
  181. package/gsd-core/bin/lib/user-artifact-staging.cjs +705 -0
  182. package/gsd-core/bin/lib/validate-command-router.cjs +2 -2
  183. package/gsd-core/bin/lib/validate.cjs +20 -6
  184. package/gsd-core/bin/lib/vendor/README.md +75 -0
  185. package/gsd-core/bin/lib/vendor/js-yaml.cjs +3014 -0
  186. package/gsd-core/bin/lib/vendor/re2js.cjs +6480 -0
  187. package/gsd-core/bin/lib/vendor/re2js.d.cts +938 -0
  188. package/gsd-core/bin/lib/verification-command-router.cjs +2 -1
  189. package/gsd-core/bin/lib/verification.cjs +272 -9
  190. package/gsd-core/bin/lib/verify-command-grounding.cjs +846 -0
  191. package/gsd-core/bin/lib/verify.cjs +453 -918
  192. package/gsd-core/bin/lib/workstream-inventory-builder.cjs +53 -32
  193. package/gsd-core/bin/lib/workstream-inventory.cjs +63 -10
  194. package/gsd-core/bin/lib/workstream-name-policy.cjs +25 -4
  195. package/gsd-core/bin/lib/workstream.cjs +2 -2
  196. package/gsd-core/bin/lib/worktree-base-ref.cjs +66 -12
  197. package/gsd-core/bin/lib/worktree-safety.cjs +341 -18
  198. package/gsd-core/bin/shared/config-defaults.manifest.json +8 -1
  199. package/gsd-core/bin/shared/config-schema.manifest.json +12 -1
  200. package/gsd-core/bin/shared/exit-codes.json +8 -0
  201. package/gsd-core/bin/shared/exit-codes.sh +20 -0
  202. package/gsd-core/bin/shared/model-catalog.json +8 -1
  203. package/gsd-core/references/agent-contracts.md +44 -26
  204. package/gsd-core/references/api-coverage.md +24 -2
  205. package/gsd-core/references/autonomous-smart-discuss.md +3 -3
  206. package/gsd-core/references/checkpoints.md +39 -21
  207. package/gsd-core/references/context-budget.md +1 -1
  208. package/gsd-core/references/decimal-phase-calculation.md +5 -5
  209. package/gsd-core/references/dispatch-isolation-gate.md +138 -0
  210. package/gsd-core/references/doc-conflict-engine.md +1 -1
  211. package/gsd-core/references/edge-probe.md +8 -0
  212. package/gsd-core/references/execute-mvp-tdd.md +4 -6
  213. package/gsd-core/references/execute-phase-between-wave-reset.md +15 -14
  214. package/gsd-core/references/execute-phase-context-guard.md +1 -1
  215. package/gsd-core/references/execute-phase-response-language.md +1 -1
  216. package/gsd-core/references/execute-phase-wave-guard.md +17 -11
  217. package/gsd-core/references/failing-direction.md +78 -0
  218. package/gsd-core/references/gate-prompts.md +1 -1
  219. package/gsd-core/references/git-integration.md +5 -5
  220. package/gsd-core/references/git-planning-commit.md +5 -4
  221. package/gsd-core/references/gsd-run-resolver.md +1 -1
  222. package/gsd-core/references/loop-hook-dispatch.md +61 -2
  223. package/gsd-core/references/model-profiles.md +12 -4
  224. package/gsd-core/references/mvp-concepts.md +9 -9
  225. package/gsd-core/references/nyquist-compliance.md +74 -0
  226. package/gsd-core/references/offer-next.md +3 -5
  227. package/gsd-core/references/phase-argument-parsing.md +3 -3
  228. package/gsd-core/references/planner-failing-direction.md +53 -0
  229. package/gsd-core/references/planner-guidance.md +3 -9
  230. package/gsd-core/references/planner-human-verify-mode.md +15 -1
  231. package/gsd-core/references/planner-preconditions.md +1 -1
  232. package/gsd-core/references/planner-reviews.md +1 -1
  233. package/gsd-core/references/planner-revision.md +1 -1
  234. package/gsd-core/references/planner-verify-command-grounding.md +17 -0
  235. package/gsd-core/references/planning-config.md +44 -13
  236. package/gsd-core/references/reviewer-instances.md +31 -0
  237. package/gsd-core/references/revision-loop.md +1 -1
  238. package/gsd-core/references/runtime-aware-dispatch.md +1 -1
  239. package/gsd-core/references/specless-probe-fallback.md +1 -1
  240. package/gsd-core/references/tdd.md +1 -3
  241. package/gsd-core/references/ui-brand.md +65 -21
  242. package/gsd-core/references/ui-consideration-probe.md +1 -1
  243. package/gsd-core/references/universal-anti-patterns.md +5 -5
  244. package/gsd-core/references/verifier-phase-gates.md +192 -0
  245. package/gsd-core/references/verify-command-path-resolvability.md +42 -0
  246. package/gsd-core/references/verify-mvp-mode.md +2 -2
  247. package/gsd-core/references/workstream-flag.md +33 -17
  248. package/gsd-core/templates/README.md +1 -1
  249. package/gsd-core/templates/SECURITY.md +3 -3
  250. package/gsd-core/templates/UI-SPEC.md +25 -3
  251. package/gsd-core/templates/VALIDATION.md +3 -3
  252. package/gsd-core/templates/discussion-log.md +1 -1
  253. package/gsd-core/templates/phase-prompt.md +5 -4
  254. package/gsd-core/templates/state.md +11 -4
  255. package/gsd-core/templates/verification-report.md +9 -1
  256. package/gsd-core/workflows/_runtime-launcher.snippet.sh +1 -1
  257. package/gsd-core/workflows/add-backlog.md +1 -1
  258. package/gsd-core/workflows/add-phase.md +3 -3
  259. package/gsd-core/workflows/add-tests.md +3 -8
  260. package/gsd-core/workflows/add-todo.md +1 -1
  261. package/gsd-core/workflows/ai-integration-phase.md +13 -20
  262. package/gsd-core/workflows/audit-fix.md +12 -3
  263. package/gsd-core/workflows/audit-milestone.md +9 -9
  264. package/gsd-core/workflows/audit-uat.md +17 -2
  265. package/gsd-core/workflows/autonomous/steps/converge-fail-fast.md +2 -2
  266. package/gsd-core/workflows/autonomous.md +11 -27
  267. package/gsd-core/workflows/check-todos.md +1 -1
  268. package/gsd-core/workflows/cleanup.md +64 -5
  269. package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +14 -4
  270. package/gsd-core/workflows/code-review-fix.md +38 -11
  271. package/gsd-core/workflows/code-review.md +159 -52
  272. package/gsd-core/workflows/complete-milestone.md +151 -23
  273. package/gsd-core/workflows/debug.md +12 -8
  274. package/gsd-core/workflows/diagnose-issues.md +47 -15
  275. package/gsd-core/workflows/discuss-phase/modes/advisor.md +1 -1
  276. package/gsd-core/workflows/discuss-phase/modes/chain.md +5 -8
  277. package/gsd-core/workflows/discuss-phase/modes/default.md +1 -1
  278. package/gsd-core/workflows/discuss-phase/modes/text.md +1 -1
  279. package/gsd-core/workflows/discuss-phase-assumptions/steps/auto-advance-dispatch.md +1 -3
  280. package/gsd-core/workflows/discuss-phase-assumptions.md +4 -3
  281. package/gsd-core/workflows/discuss-phase.md +1 -1
  282. package/gsd-core/workflows/do.md +3 -6
  283. package/gsd-core/workflows/docs-update.md +5 -4
  284. package/gsd-core/workflows/edit-phase.md +27 -2
  285. package/gsd-core/workflows/eval-review.md +7 -14
  286. package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +1 -1
  287. package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +142 -15
  288. package/gsd-core/workflows/execute-phase/steps/gap-closure-artifacts.md +1 -1
  289. package/gsd-core/workflows/execute-phase/steps/partial-wave.md +1 -1
  290. package/gsd-core/workflows/execute-phase/steps/per-plan-executor-routing.md +77 -0
  291. package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +24 -4
  292. package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +2 -2
  293. package/gsd-core/workflows/execute-phase/steps/protected-branch.md +21 -0
  294. package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +2 -2
  295. package/gsd-core/workflows/execute-phase/steps/wave-post-gate-hooks.md +39 -0
  296. package/gsd-core/workflows/execute-phase.md +72 -100
  297. package/gsd-core/workflows/execute-plan.md +52 -15
  298. package/gsd-core/workflows/explore.md +131 -4
  299. package/gsd-core/workflows/extract-learnings.md +1 -1
  300. package/gsd-core/workflows/fast.md +10 -2
  301. package/gsd-core/workflows/forensics.md +1 -1
  302. package/gsd-core/workflows/graduation.md +5 -5
  303. package/gsd-core/workflows/health.md +76 -10
  304. package/gsd-core/workflows/import.md +18 -15
  305. package/gsd-core/workflows/inbox.md +4 -5
  306. package/gsd-core/workflows/ingest-docs.md +49 -16
  307. package/gsd-core/workflows/insert-phase.md +5 -5
  308. package/gsd-core/workflows/list-seeds.md +5 -3
  309. package/gsd-core/workflows/list-workspaces.md +1 -1
  310. package/gsd-core/workflows/manager.md +12 -23
  311. package/gsd-core/workflows/map-codebase.md +1 -1
  312. package/gsd-core/workflows/milestone-summary.md +1 -1
  313. package/gsd-core/workflows/mvp-phase.md +8 -5
  314. package/gsd-core/workflows/new-milestone.md +22 -29
  315. package/gsd-core/workflows/new-project/steps/auto-mode-config.md +1 -1
  316. package/gsd-core/workflows/new-project.md +26 -40
  317. package/gsd-core/workflows/new-workspace.md +1 -1
  318. package/gsd-core/workflows/next.md +14 -2
  319. package/gsd-core/workflows/pause-work.md +1 -1
  320. package/gsd-core/workflows/plan-phase/steps/adr-ingest-express-path.md +1 -1
  321. package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +1 -1
  322. package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +2 -4
  323. package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +3 -3
  324. package/gsd-core/workflows/plan-phase.md +162 -59
  325. package/gsd-core/workflows/plan-review-convergence.md +96 -11
  326. package/gsd-core/workflows/plant-seed.md +2 -2
  327. package/gsd-core/workflows/pr-branch.md +187 -51
  328. package/gsd-core/workflows/profile-user.md +16 -14
  329. package/gsd-core/workflows/progress.md +61 -18
  330. package/gsd-core/workflows/quick/steps/discussion-phase.md +1 -3
  331. package/gsd-core/workflows/quick/steps/plan-checker-loop.md +5 -7
  332. package/gsd-core/workflows/quick/steps/quick-verification.md +28 -9
  333. package/gsd-core/workflows/quick/steps/research-phase.md +4 -6
  334. package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +3 -3
  335. package/gsd-core/workflows/quick.md +55 -44
  336. package/gsd-core/workflows/remove-phase.md +4 -4
  337. package/gsd-core/workflows/remove-workspace.md +2 -2
  338. package/gsd-core/workflows/resume-project.md +8 -12
  339. package/gsd-core/workflows/review.md +219 -20
  340. package/gsd-core/workflows/scan.md +1 -1
  341. package/gsd-core/workflows/secure-phase.md +3 -3
  342. package/gsd-core/workflows/session-report.md +2 -1
  343. package/gsd-core/workflows/settings-advanced.md +7 -9
  344. package/gsd-core/workflows/settings-integrations.md +64 -31
  345. package/gsd-core/workflows/settings.md +69 -7
  346. package/gsd-core/workflows/ship.md +116 -50
  347. package/gsd-core/workflows/sketch-wrap-up.md +11 -17
  348. package/gsd-core/workflows/sketch.md +12 -18
  349. package/gsd-core/workflows/smart-entry.md +3 -5
  350. package/gsd-core/workflows/spec-phase.md +53 -13
  351. package/gsd-core/workflows/spike-wrap-up.md +7 -11
  352. package/gsd-core/workflows/spike.md +20 -31
  353. package/gsd-core/workflows/stats.md +2 -2
  354. package/gsd-core/workflows/sync-skills.md +64 -9
  355. package/gsd-core/workflows/thread.md +11 -7
  356. package/gsd-core/workflows/transition.md +49 -14
  357. package/gsd-core/workflows/ui-phase.md +15 -21
  358. package/gsd-core/workflows/ui-review.md +8 -12
  359. package/gsd-core/workflows/ultraplan-phase.md +5 -13
  360. package/gsd-core/workflows/undo.md +8 -16
  361. package/gsd-core/workflows/update.md +7 -11
  362. package/gsd-core/workflows/validate-phase.md +3 -3
  363. package/gsd-core/workflows/verify-work/steps/automated-ui-verification.md +25 -1
  364. package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +1 -1
  365. package/gsd-core/workflows/verify-work.md +66 -25
  366. package/hooks/dist/gsd-agent-isolation-guard.js +158 -30
  367. package/hooks/dist/gsd-check-update-worker.js +56 -13
  368. package/hooks/dist/gsd-check-update.js +19 -1
  369. package/hooks/dist/gsd-config-reload.js +18 -12
  370. package/hooks/dist/gsd-context-monitor.js +19 -10
  371. package/hooks/dist/gsd-cursor-post-tool.js +3 -1
  372. package/hooks/dist/gsd-cursor-pre-tool.js +2 -3
  373. package/hooks/dist/gsd-cursor-session-start.js +2 -1
  374. package/hooks/dist/gsd-cursor-stop.js +2 -1
  375. package/hooks/dist/gsd-cursor-subagent-start.js +83 -3
  376. package/hooks/dist/gsd-cursor-subagent-stop.js +6 -3
  377. package/hooks/dist/gsd-ensure-canonical-path.js +2 -1
  378. package/hooks/dist/gsd-graphify-update.sh +22 -18
  379. package/hooks/dist/gsd-node-runner.sh +76 -0
  380. package/hooks/dist/gsd-phase-boundary.sh +1 -0
  381. package/hooks/dist/gsd-prompt-guard.js +37 -27
  382. package/hooks/dist/gsd-read-guard.js +16 -7
  383. package/hooks/dist/gsd-read-injection-scanner.js +55 -32
  384. package/hooks/dist/gsd-session-state.sh +1 -0
  385. package/hooks/dist/gsd-statusline.js +231 -24
  386. package/hooks/dist/gsd-update-banner.js +22 -1
  387. package/hooks/dist/gsd-validate-commit.sh +80 -6
  388. package/hooks/dist/gsd-windsurf-pre-command.js +16 -11
  389. package/hooks/dist/gsd-windsurf-pre-write.js +22 -13
  390. package/hooks/dist/gsd-workflow-guard.js +162 -46
  391. package/hooks/dist/gsd-worktree-path-guard.js +36 -21
  392. package/hooks/dist/gsd-write-guard.js +35 -25
  393. package/hooks/dist/lib/cli-exit.js +560 -0
  394. package/hooks/dist/lib/exit-code-registry.js +98 -0
  395. package/hooks/dist/lib/git-cmd.js +92 -59
  396. package/hooks/dist/lib/git-probe.js +84 -0
  397. package/hooks/dist/lib/hook-exit.js +81 -0
  398. package/hooks/dist/lib/injection-patterns.js +45 -0
  399. package/hooks/dist/lib/isolation-deny-reason.js +39 -0
  400. package/hooks/dist/lib/isolation-sentinel.js +9 -0
  401. package/hooks/dist/managed-hooks-registry.cjs +3 -0
  402. package/hooks/gsd-agent-isolation-guard.js +158 -30
  403. package/hooks/gsd-check-update-worker.js +56 -13
  404. package/hooks/gsd-check-update.js +19 -1
  405. package/hooks/gsd-config-reload.js +18 -12
  406. package/hooks/gsd-context-monitor.js +19 -10
  407. package/hooks/gsd-cursor-post-tool.js +3 -1
  408. package/hooks/gsd-cursor-pre-tool.js +2 -3
  409. package/hooks/gsd-cursor-session-start.js +2 -1
  410. package/hooks/gsd-cursor-stop.js +2 -1
  411. package/hooks/gsd-cursor-subagent-start.js +83 -3
  412. package/hooks/gsd-cursor-subagent-stop.js +6 -3
  413. package/hooks/gsd-ensure-canonical-path.js +2 -1
  414. package/hooks/gsd-graphify-update.sh +22 -18
  415. package/hooks/gsd-node-runner.sh +76 -0
  416. package/hooks/gsd-phase-boundary.sh +1 -0
  417. package/hooks/gsd-prompt-guard.js +37 -27
  418. package/hooks/gsd-read-guard.js +16 -7
  419. package/hooks/gsd-read-injection-scanner.js +55 -32
  420. package/hooks/gsd-session-state.sh +1 -0
  421. package/hooks/gsd-statusline.js +231 -24
  422. package/hooks/gsd-update-banner.js +22 -1
  423. package/hooks/gsd-validate-commit.sh +80 -6
  424. package/hooks/gsd-windsurf-pre-command.js +16 -11
  425. package/hooks/gsd-windsurf-pre-write.js +22 -13
  426. package/hooks/gsd-workflow-guard.js +162 -46
  427. package/hooks/gsd-worktree-path-guard.js +36 -21
  428. package/hooks/gsd-write-guard.js +35 -25
  429. package/hooks/lib/cli-exit.js +560 -0
  430. package/hooks/lib/exit-code-registry.js +98 -0
  431. package/hooks/lib/git-cmd.js +92 -59
  432. package/hooks/lib/git-probe.js +84 -0
  433. package/hooks/lib/hook-exit.js +81 -0
  434. package/hooks/lib/injection-patterns.js +45 -0
  435. package/hooks/lib/isolation-deny-reason.js +39 -0
  436. package/hooks/lib/isolation-sentinel.js +9 -0
  437. package/hooks/managed-hooks-registry.cjs +3 -0
  438. package/package.json +28 -11
  439. package/pi/gsd.cjs +19 -5
  440. package/scripts/base64-scan.sh +74 -12
  441. package/scripts/baselines/planning-prompt-drift-baseline.json +4 -0
  442. package/scripts/baselines/planning-snapshot-bypass-baseline.json +12 -0
  443. package/scripts/baselines/unreachable-guard-drift-baseline.json +4 -0
  444. package/scripts/build-hooks.js +5 -0
  445. package/scripts/changeset/lint.cjs +60 -5
  446. package/scripts/check-alias-drift.cjs +7 -43
  447. package/scripts/check-contract-drift.cjs +297 -0
  448. package/scripts/check-glossary-refs.cjs +77 -15
  449. package/scripts/check-mutation-score-ratchet.cjs +156 -0
  450. package/scripts/ci-check-job-near-cap.cjs +49 -0
  451. package/scripts/ci-pr-mergeability.cjs +262 -0
  452. package/scripts/ci-test-scope.cjs +64 -14
  453. package/scripts/ci-timeout-report.cjs +230 -0
  454. package/scripts/command-contract-helpers.cjs +903 -1
  455. package/scripts/docs-guard-registry.cjs +396 -0
  456. package/scripts/gen-adr-index.cjs +728 -38
  457. package/scripts/gen-capability-registry.cjs +11 -21
  458. package/scripts/gen-context-index.cjs +2 -11
  459. package/scripts/gen-exit-code-docs.cjs +318 -0
  460. package/scripts/gen-exit-code-registry.cjs +891 -0
  461. package/scripts/gen-features.cjs +836 -0
  462. package/scripts/gen-health-docs.cjs +390 -0
  463. package/scripts/gen-hooks-cli-exit.cjs +239 -0
  464. package/scripts/gen-install-tree-fixtures.cjs +2 -2
  465. package/scripts/gen-inventory-manifest.cjs +50 -4
  466. package/scripts/gen-loop-host-contract.cjs +138 -25
  467. package/scripts/gen-registry.cjs +3 -14
  468. package/scripts/gen-scripts-cli-exit.cjs +185 -0
  469. package/scripts/gen-state-md-docs.cjs +727 -0
  470. package/scripts/{test-failure-reasons.cjs → gsd-test-gate-reasons.cjs} +6 -0
  471. package/scripts/lib/alias-drift-families.cjs +46 -0
  472. package/scripts/lib/ci-job-timing.cjs +72 -0
  473. package/scripts/lib/cli-exit.cjs +546 -44
  474. package/scripts/lib/drift-scan.cjs +308 -0
  475. package/scripts/lib/exit-code-registry.cjs +98 -0
  476. package/scripts/lib/ndjson-reporter.cjs +119 -0
  477. package/scripts/lint-allow-test-rule-refs.allowlist.json +1 -26
  478. package/scripts/lint-allow-test-rule-refs.effective-ceiling.json +4 -0
  479. package/scripts/lint-allow-test-rule-refs.unverified-ceiling.json +3 -0
  480. package/scripts/lint-canary-version-leak.cjs +73 -0
  481. package/scripts/lint-command-contract.cjs +96 -13
  482. package/scripts/lint-completion-predicate-drift.cjs +933 -0
  483. package/scripts/lint-completion-ratio-drift.cjs +214 -0
  484. package/scripts/lint-default-flip-documentation.cjs +193 -0
  485. package/scripts/lint-docs-guard-registration.cjs +495 -0
  486. package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +193 -0
  487. package/scripts/lint-eslint-glob-coverage.allowlist.json +38 -0
  488. package/scripts/lint-eslint-glob-coverage.cjs +340 -0
  489. package/scripts/{lint-fix-has-regression-test.cjs → lint-fix-has-regression-tests.cjs} +12 -6
  490. package/scripts/lint-frontmatter-scalar-broad-grep.cjs +237 -0
  491. package/scripts/lint-health-diagnostic-rule-table.cjs +461 -0
  492. package/scripts/lint-hooks-runtime-build-seam.cjs +262 -0
  493. package/scripts/lint-milestone-window-drift.cjs +468 -0
  494. package/scripts/lint-mutation-test-derivation-drift.cjs +86 -0
  495. package/scripts/lint-phase-enumeration-drift.cjs +492 -0
  496. package/scripts/lint-plan-count-drift.cjs +318 -0
  497. package/scripts/lint-planning-artifact-writer-drift.cjs +398 -0
  498. package/scripts/lint-planning-prompt-drift.cjs +471 -0
  499. package/scripts/lint-planning-snapshot-bypass-drift.cjs +544 -0
  500. package/scripts/lint-regression-test-names.cjs +15 -13
  501. package/scripts/lint-removed-but-needed.cjs +488 -0
  502. package/scripts/lint-seam-enforcement.cjs +182 -0
  503. package/scripts/lint-slug-derivation-drift.cjs +921 -0
  504. package/scripts/lint-source-test-name-collision.cjs +241 -0
  505. package/scripts/lint-state-field-drift.cjs +805 -0
  506. package/scripts/lint-state-write-path-drift.cjs +950 -0
  507. package/scripts/lint-test-file-count.allowlist.json +137 -8
  508. package/scripts/lint-test-file-count.cjs +25 -3
  509. package/scripts/lint-unreachable-guard-drift.cjs +830 -0
  510. package/scripts/lint-vendored-deps.cjs +297 -0
  511. package/scripts/mutation-matrix.cjs +599 -50
  512. package/scripts/pr-changed-files.cjs +63 -0
  513. package/scripts/pr-template-policy.cjs +14 -4
  514. package/scripts/prompt-injection-scan.sh +100 -14
  515. package/scripts/require-issue-link-policy.cjs +192 -0
  516. package/scripts/secret-scan.sh +75 -13
  517. package/scripts/select-docs-guards.cjs +56 -0
  518. package/scripts/sync-runtime-launcher.cjs +24 -7
  519. package/skills/gsd-autonomous/SKILL.md +0 -1
  520. package/skills/gsd-code-review/SKILL.md +1 -1
  521. package/skills/gsd-discuss-phase/SKILL.md +1 -1
  522. package/skills/gsd-execute-phase/SKILL.md +1 -2
  523. package/skills/gsd-import/SKILL.md +1 -1
  524. package/skills/gsd-map-codebase/SKILL.md +1 -1
  525. package/skills/gsd-mempalace-capture/SKILL.md +1 -1
  526. package/skills/gsd-mempalace-recall/SKILL.md +1 -1
  527. package/skills/gsd-new-milestone/SKILL.md +1 -1
  528. package/skills/gsd-next/SKILL.md +0 -1
  529. package/skills/gsd-plan-phase/SKILL.md +0 -1
  530. package/skills/gsd-progress/SKILL.md +0 -1
  531. package/skills/gsd-quick/SKILL.md +9 -5
  532. package/skills/gsd-review-backlog/SKILL.md +2 -1
  533. package/skills/gsd-stats/SKILL.md +0 -1
  534. package/skills/gsd-verify-work/SKILL.md +1 -1
  535. package/vscode/package.json +1 -1
  536. package/bin/lib/ui-safety-gate.cjs +0 -107
  537. package/gsd-core/workflows/discovery-phase.md +0 -298
  538. package/gsd-core/workflows/plan-milestone-gaps.md +0 -281
  539. package/gsd-core/workflows/verify-phase.md +0 -574
  540. package/scripts/affected-tests-lib.cjs +0 -554
  541. package/scripts/lint-allow-test-rule-refs.cjs +0 -162
  542. package/scripts/lint-emitted-drift-ack.cjs +0 -344
  543. package/scripts/run-affected-tests.cjs +0 -7
  544. package/scripts/run-tests.cjs +0 -1051
@@ -15,6 +15,9 @@ const node_fs_1 = __importDefault(require("node:fs"));
15
15
  const node_os_1 = __importDefault(require("node:os"));
16
16
  const node_path_1 = __importDefault(require("node:path"));
17
17
  const shell_command_projection_cjs_1 = require("./shell-command-projection.cjs");
18
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
19
+ const cliExitModule = require("./cli-exit.cjs");
20
+ const { setJsonErrorMode, getJsonErrorMode, EXIT_ENVELOPE_REASON, ExitError, setPendingOutcome, projectOutcome, getContractVersion, } = cliExitModule;
18
21
  // ─── Temp-file helpers (needed by output()) ──────────────────────────────────
19
22
  /**
20
23
  * Dedicated GSD temp directory: path.join(os.tmpdir(), 'gsd').
@@ -134,7 +137,48 @@ function writeAllSync(fd, data) {
134
137
  function serializeForOutput(result) {
135
138
  return JSON.stringify(result, null, 2);
136
139
  }
140
+ /**
141
+ * A payload-carried error, per ADR-2980's own definition (#3912, ADR-3889
142
+ * §4): `result` is an object carrying a SERIALIZABLE `error` property, in
143
+ * ANY key order — `{ found: false, error }` counts exactly the same as
144
+ * `{ error, found: false }`. The discriminator is a serializable error
145
+ * value, NOT mere key presence: `result.error`'s own truthiness is
146
+ * irrelevant (falsy `0`/`null`/`''` all count), and neither is `result`'s
147
+ * prototype (a plain object literal is all any call site here ever
148
+ * passes) — but `error: undefined` does NOT count, because
149
+ * `JSON.stringify` (the exact serializer `serializeForOutput` uses to
150
+ * build the payload the caller actually receives) drops an object
151
+ * property whose value is `undefined` entirely. A payload built as
152
+ * `{ found: false, error: undefined }` therefore reaches the wire as
153
+ * `{"found":false}` — no error at all — and recording DEGRADED for it
154
+ * would be a false verdict: exit 80 under v2 for output the user sees as
155
+ * clean. `hasOwnProperty` alone is not enough to answer "does this payload
156
+ * declare an error"; it must also survive `JSON.stringify`.
157
+ */
158
+ function isPayloadCarriedError(result) {
159
+ return typeof result === 'object' && result !== null
160
+ && Object.prototype.hasOwnProperty.call(result, 'error')
161
+ && result.error !== undefined;
162
+ }
137
163
  function output(result, raw, rawValue) {
164
+ // #3912 (ADR-3889 §4): a payload-carried error declares DEGRADED into the
165
+ // pending-outcome cell runMain reads. This is the ONLY new thing output()
166
+ // does — it still just writes fd 1 and returns; the exit code stays
167
+ // whatever it already was under v1 (DEGRADED projects to 0), and nothing
168
+ // here touches process.exitCode directly.
169
+ //
170
+ // LAST-WRITE-WINS (review fix): a clean (non-error-shaped) payload CLEARS
171
+ // the cell rather than leaving a prior degraded declaration in place. A
172
+ // handler that calls output() more than once per invocation — a
173
+ // diagnostic error payload followed by a clean final payload — must have
174
+ // its LATEST declaration win, not its first: the cell reflects "is a
175
+ // degraded outcome pending right now", not "was one ever declared".
176
+ if (isPayloadCarriedError(result)) {
177
+ setPendingOutcome('DEGRADED');
178
+ }
179
+ else {
180
+ setPendingOutcome(undefined);
181
+ }
138
182
  let data;
139
183
  if (raw && rawValue !== undefined) {
140
184
  // eslint-disable-next-line @typescript-eslint/no-base-to-string
@@ -178,7 +222,7 @@ const ERROR_REASON = Object.freeze({
178
222
  CONFIG_PARSE_FAILED: 'config_parse_failed',
179
223
  CONFIG_INVALID_KEY: 'config_invalid_key',
180
224
  // SDK / gsd-tools dispatch
181
- SDK_FAIL_FAST: 'sdk_fail_fast',
225
+ SDK_FAIL_FAST: EXIT_ENVELOPE_REASON,
182
226
  SDK_UNKNOWN_COMMAND: 'sdk_unknown_command',
183
227
  SDK_MISSING_ARG: 'sdk_missing_arg',
184
228
  // workflow / phase
@@ -186,29 +230,38 @@ const ERROR_REASON = Object.freeze({
186
230
  PHASE_VERIFICATION_INCOMPLETE: 'phase_verification_incomplete',
187
231
  PHASE_PLAN_COVERAGE_INCOMPLETE: 'phase_plan_coverage_incomplete',
188
232
  SUMMARY_NO_PLANNING: 'summary_no_planning',
233
+ // #3579: workstream-mode fail-safe guards (init.progress, phase.complete) —
234
+ // distinguishes "no marker/pointer anywhere" from "a marker exists but
235
+ // didn't resolve" so a JSON-error-mode caller can branch on `reason`
236
+ // instead of regexing the human message.
237
+ WORKSTREAM_MODE_NONE_ACTIVE: 'workstream_mode_none_active',
238
+ WORKSTREAM_MODE_MARKER_UNRESOLVED: 'workstream_mode_marker_unresolved',
189
239
  // graphify
190
240
  GRAPHIFY_NO_GRAPH: 'graphify_no_graph',
191
241
  GRAPHIFY_INVALID_QUERY: 'graphify_invalid_query',
242
+ // estimate-calibrate (#3882, ADR-3473 §8.2): the phases directory exists
243
+ // but could not be read — a NON-answer, distinct from a project that
244
+ // genuinely has zero completed phases yet.
245
+ ESTIMATE_PHASES_UNREADABLE: 'estimate_phases_unreadable',
192
246
  // hooks
193
247
  HOOKS_OPT_OUT: 'hooks_opt_out',
248
+ // commit-docs-guard (#3588)
249
+ COMMIT_DOCS_GUARD_NOT_A_REPO: 'commit_docs_guard_not_a_repo',
250
+ COMMIT_DOCS_GUARD_FOREIGN_HOOK: 'commit_docs_guard_foreign_hook',
251
+ COMMIT_DOCS_GUARD_HOOKS_PATH_SET: 'commit_docs_guard_hooks_path_set',
194
252
  // security-scan
195
253
  SECURITY_SCAN_FAILED: 'security_scan_failed',
254
+ // --pick (#3365 / #3358, ADR-3473 §8.4): an absent field or non-JSON
255
+ // command output is a failure, never a demotion to an empty answer at
256
+ // exit 0. See .gsd/phase/feat-3884-failure-is-a-value/40-design.md.
257
+ PICK_FIELD_ABSENT: 'pick_field_absent',
258
+ PICK_OUTPUT_NOT_JSON: 'pick_output_not_json',
196
259
  // generic
197
260
  USAGE: 'usage',
198
261
  UNKNOWN: 'unknown',
199
262
  });
200
- /**
201
- * Process-level flag: when true, error() emits structured JSON to stderr
202
- * instead of plain "Error: <message>" text. Set by gsd-tools.cjs when the
203
- * CLI is invoked with `--json-errors`. Tests opt in to typed-IR error
204
- * assertions by passing that flag and parsing the JSON.
205
- *
206
- * Default off so existing callers and human operators keep their plain-text
207
- * diagnostics. The structured form is opt-in for tooling and tests (#2974).
208
- */
209
- let _jsonErrorMode = false;
210
- function setJsonErrorMode(v) { _jsonErrorMode = !!v; }
211
- function getJsonErrorMode() { return _jsonErrorMode; }
263
+ // setJsonErrorMode / getJsonErrorMode now live in cli-exit.cts (imported above)
264
+ // and are re-exported here for the callers that already import them from io.
212
265
  /**
213
266
  * Emit an error and exit. When the second argument is provided it must be
214
267
  * a value from ERROR_REASON; tests can assert on `result.reason`. When the
@@ -223,15 +276,116 @@ function getJsonErrorMode() { return _jsonErrorMode; }
223
276
  * human-readable text. Ignored entirely in plain-text mode — the human
224
277
  * message is the only thing an operator sees there.
225
278
  */
279
+ /**
280
+ * Render an UNTRUSTED string for embedding inside a human-readable,
281
+ * plain-text diagnostic (the `'Error: ' + message` line `error()` writes in
282
+ * non-JSON mode).
283
+ *
284
+ * WHY THIS EXISTS AND WHY `error()` DOES NOT DO IT ITSELF: `error()`
285
+ * deliberately writes its `message` argument verbatim — several callers in
286
+ * this repo intentionally emit multi-line diagnostics (e.g. the phase-gate
287
+ * messages), and `error()` has no way to distinguish a legitimate multi-line
288
+ * message from a hostile one, so it must not mangle newlines generically.
289
+ * That means any UNTRUSTED substring a caller interpolates into `message`
290
+ * (an argv token, a JSON key/value read back from a command's own output,
291
+ * etc.) can smuggle its own `\n` and forge a second `Error: ` line on
292
+ * stderr — a caller that parses stderr line-by-line would then see a second,
293
+ * attacker-authored error. Every call site that interpolates untrusted data
294
+ * into a diagnostic MUST pass that substring through this function first;
295
+ * `error()` itself stays a dumb, faithful writer.
296
+ *
297
+ * `JSON.stringify` is the primitive: it wraps the value in quotes and
298
+ * escapes control characters (`\n`, `\r`, `\t`, and the rest of the C0
299
+ * range, plus the quote character itself), so the result can never span
300
+ * more than one line or introduce an unescaped `"`. Callers embedding the
301
+ * result MUST NOT add their own surrounding quotes — that would
302
+ * double-quote it.
303
+ */
304
+ function formatDiagnosticToken(value) {
305
+ return JSON.stringify(value);
306
+ }
307
+ /**
308
+ * Map an ERROR_REASON wire value onto a declared outcome name (#3912,
309
+ * ADR-3889 §4). Closed over the 25-member enum: every reason gets an
310
+ * explicit entry below, so a 26th member added without a mapping falls
311
+ * through to the `?? 'FAIL'` default rather than silently mis-projecting —
312
+ * and tests/A1 iterates `Object.values(ERROR_REASON)`, so that default is
313
+ * exactly what makes an unmapped addition visible instead of invisible.
314
+ *
315
+ * This function's result is ONLY consulted under v2 (see `error()` below) —
316
+ * it is deliberately never routed through `projectOutcome` under v1, which
317
+ * is what keeps the v1 pin intact (`projectOutcome` treats registered names
318
+ * as version-invariant, so e.g. USAGE would otherwise become 64 today).
319
+ *
320
+ * Each non-FAIL choice below is justified inline; `UNKNOWN` and anything
321
+ * with no clearly better fit stays `FAIL` — the honest default the design
322
+ * calls for, not a guess dressed up as a specific outcome.
323
+ */
324
+ const REASON_TO_OUTCOME = Object.freeze({
325
+ // Bad argv/subcommand/argument — the caller, not the run, is at fault.
326
+ [ERROR_REASON.CONFIG_INVALID_KEY]: 'USAGE',
327
+ [ERROR_REASON.SDK_UNKNOWN_COMMAND]: 'USAGE',
328
+ [ERROR_REASON.SDK_MISSING_ARG]: 'USAGE',
329
+ [ERROR_REASON.GRAPHIFY_INVALID_QUERY]: 'USAGE',
330
+ [ERROR_REASON.USAGE]: 'USAGE',
331
+ // A specific, named thing does not exist / nothing was there to find —
332
+ // genuine, known emptiness rather than a broken prerequisite.
333
+ [ERROR_REASON.CONFIG_KEY_NOT_FOUND]: 'NO_INPUT',
334
+ [ERROR_REASON.SUMMARY_NO_PLANNING]: 'NO_INPUT',
335
+ [ERROR_REASON.WORKSTREAM_MODE_NONE_ACTIVE]: 'NO_INPUT',
336
+ // A prerequisite is absent, unreadable, or otherwise not in a state the
337
+ // run could proceed from — distinct from NO_INPUT's genuine emptiness.
338
+ [ERROR_REASON.CONFIG_NO_FILE]: 'UNAVAILABLE',
339
+ [ERROR_REASON.CONFIG_PARSE_FAILED]: 'UNAVAILABLE',
340
+ [ERROR_REASON.PHASE_NOT_FOUND]: 'UNAVAILABLE',
341
+ [ERROR_REASON.PHASE_VERIFICATION_INCOMPLETE]: 'UNAVAILABLE',
342
+ [ERROR_REASON.PHASE_PLAN_COVERAGE_INCOMPLETE]: 'UNAVAILABLE',
343
+ // Its own docstring: "a marker exists but didn't resolve" — a broken
344
+ // prerequisite, not the "no marker anywhere" emptiness NONE_ACTIVE covers.
345
+ [ERROR_REASON.WORKSTREAM_MODE_MARKER_UNRESOLVED]: 'UNAVAILABLE',
346
+ [ERROR_REASON.GRAPHIFY_NO_GRAPH]: 'UNAVAILABLE',
347
+ // Its own docstring: "a NON-answer, distinct from a project that
348
+ // genuinely has zero completed phases yet" — UNAVAILABLE, not NO_INPUT.
349
+ [ERROR_REASON.ESTIMATE_PHASES_UNREADABLE]: 'UNAVAILABLE',
350
+ [ERROR_REASON.COMMIT_DOCS_GUARD_NOT_A_REPO]: 'UNAVAILABLE',
351
+ [ERROR_REASON.COMMIT_DOCS_GUARD_FOREIGN_HOOK]: 'UNAVAILABLE',
352
+ [ERROR_REASON.COMMIT_DOCS_GUARD_HOOKS_PATH_SET]: 'UNAVAILABLE',
353
+ // Its own docstring: "an absent field or non-JSON command output is a
354
+ // failure, never a demotion to an empty answer" — the field/output was
355
+ // supposed to be there and was not; a prerequisite of the query failed.
356
+ [ERROR_REASON.PICK_FIELD_ABSENT]: 'UNAVAILABLE',
357
+ [ERROR_REASON.PICK_OUTPUT_NOT_JSON]: 'UNAVAILABLE',
358
+ // Self-failure: the run itself broke, not its inputs.
359
+ [ERROR_REASON.SDK_FAIL_FAST]: 'INTERNAL',
360
+ [ERROR_REASON.SECURITY_SCAN_FAILED]: 'INTERNAL',
361
+ // No clearly better fit — the honest default, per design.
362
+ [ERROR_REASON.HOOKS_OPT_OUT]: 'FAIL',
363
+ [ERROR_REASON.UNKNOWN]: 'FAIL',
364
+ });
365
+ function outcomeForReason(reason) {
366
+ return REASON_TO_OUTCOME[reason] ?? 'FAIL';
367
+ }
226
368
  function error(message, reason = ERROR_REASON.UNKNOWN, extra) {
227
- if (_jsonErrorMode) {
369
+ if (getJsonErrorMode()) {
228
370
  const payload = JSON.stringify({ ok: false, reason, message, ...(extra || {}) }) + '\n';
229
371
  writeAllSync(2, payload);
230
372
  }
231
373
  else {
232
374
  writeAllSync(2, 'Error: ' + message + '\n');
233
375
  }
234
- process.exit(1);
376
+ // #3912 (ADR-3889 §4): the declaration is version-gated HERE, not inside
377
+ // projectOutcome — registered names are version-invariant there, so
378
+ // routing every reason through it unconditionally would change v1 exit
379
+ // codes today (e.g. USAGE -> 64) and break the pin. Under v1 the exit
380
+ // stays ExitError(1) unconditionally, byte-identical to every prior
381
+ // release; only v2 projects the declared outcome through the registry.
382
+ if (getContractVersion() === 'v2') {
383
+ throw new ExitError(projectOutcome(outcomeForReason(reason), 'v2'));
384
+ }
385
+ // No message passed to ExitError: the stderr write above is already done,
386
+ // byte-identical to the prior process.exit(1) behavior, and ExitError with
387
+ // no message means runMain's catch adds nothing further to stderr.
388
+ throw new ExitError(1);
235
389
  }
236
390
  module.exports = {
237
391
  GSD_TEMP_DIR,
@@ -243,4 +397,5 @@ module.exports = {
243
397
  setJsonErrorMode,
244
398
  getJsonErrorMode,
245
399
  error,
400
+ formatDiagnosticToken,
246
401
  };
@@ -21,6 +21,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
21
21
  const node_fs_1 = __importDefault(require("node:fs"));
22
22
  const node_path_1 = __importDefault(require("node:path"));
23
23
  const node_crypto_1 = __importDefault(require("node:crypto"));
24
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
25
+ const phaseLocator = require("./phase-locator.cjs");
24
26
  const node_os_1 = __importDefault(require("node:os"));
25
27
  // eslint-disable-next-line @typescript-eslint/no-require-imports
26
28
  const ioMod = require("./io.cjs");
@@ -145,9 +147,55 @@ function learningsDelete(id, opts) {
145
147
  node_fs_1.default.unlinkSync(filePath);
146
148
  return true;
147
149
  }
150
+ /**
151
+ * #3683 — resolve which learnings artifact a copy reads. The extractor writes
152
+ * phase-scoped `{PHASE_DIR}/{PADDED}-LEARNINGS.md`; the legacy shape is a
153
+ * project-root `LEARNINGS.md`. The MOST RECENT phase-scoped artifact wins (a
154
+ * gated completion copies the phase it just wrote); the project-root file is
155
+ * the fallback when no phase artifact exists. Returns null when neither shape
156
+ * is present.
157
+ */
158
+ function resolveLearningsSource(planningDir) {
159
+ let best = null;
160
+ const phasesDir = node_path_1.default.join(planningDir, 'phases');
161
+ // Phase enumeration routes through the sanctioned seam (the #3185 drift
162
+ // guard rejects ad-hoc re-derivations): no cwd → every phase dir in the
163
+ // tree, sentinel dirs excluded, unreadable phases dir already degraded to
164
+ // an empty list by the locator itself.
165
+ const { value: phaseDirNames } = phaseLocator.listMilestonePhaseDirs(phasesDir);
166
+ for (const entry of phaseDirNames) {
167
+ const phaseDir = node_path_1.default.join(phasesDir, entry);
168
+ let files;
169
+ try {
170
+ files = node_fs_1.default.readdirSync(phaseDir);
171
+ }
172
+ catch {
173
+ // An unreadable phase dir (ACL, removal race) must not crash the copy —
174
+ // skip it and keep scanning.
175
+ continue;
176
+ }
177
+ for (const f of files) {
178
+ if (!/-LEARNINGS\.md$/i.test(f))
179
+ continue;
180
+ const p = node_path_1.default.join(phaseDir, f);
181
+ try {
182
+ const m = node_fs_1.default.statSync(p).mtimeMs;
183
+ if (best === null || m > best.m)
184
+ best = { p, m };
185
+ }
186
+ catch {
187
+ continue;
188
+ }
189
+ }
190
+ }
191
+ if (best !== null)
192
+ return best.p;
193
+ const rootPath = node_path_1.default.join(planningDir, 'LEARNINGS.md');
194
+ return node_fs_1.default.existsSync(rootPath) ? rootPath : null;
195
+ }
148
196
  function learningsCopyFromProject(planningDir, opts) {
149
- const learningsPath = node_path_1.default.join(planningDir, 'LEARNINGS.md');
150
- if (!node_fs_1.default.existsSync(learningsPath)) {
197
+ const learningsPath = resolveLearningsSource(planningDir);
198
+ if (learningsPath === null) {
151
199
  return { total: 0, created: 0, skipped: 0 };
152
200
  }
153
201
  const content = node_fs_1.default.readFileSync(learningsPath, 'utf-8');
@@ -167,29 +215,52 @@ function learningsCopyFromProject(planningDir, opts) {
167
215
  dedupeIndex.set(existing.content_hash, existing.id);
168
216
  }
169
217
  }
170
- // Parse markdown: split on ## headings
218
+ // Parse markdown: split on ## category headings.
219
+ // #3683: the real producer (extract-learnings.md write_learnings) writes ##
220
+ // categories containing ### item headings — each item is ONE learning (the
221
+ // store's relevance contract caps injection by count, so category-sized
222
+ // blobs defeat it). A bare ## section with no ### items keeps the legacy
223
+ // single-learning shape.
171
224
  const sections = content.split(/^## /m).slice(1); // skip preamble before first ##
172
225
  let created = 0;
173
226
  let skipped = 0;
174
- for (const section of sections) {
175
- const lines = section.trim().split('\n');
176
- const title = lines[0].trim();
177
- const body = lines.slice(1).join('\n').trim();
178
- if (!body)
179
- continue;
180
- // Extract tags from title (simple: use words as tags)
181
- const tags = title.toLowerCase().split(/\s+/).filter(w => w.length > 2);
227
+ const writeOne = (title, body, extraTags) => {
228
+ const tags = Array.from(new Set([
229
+ ...extraTags,
230
+ ...title.toLowerCase().split(/\s+/).filter(w => w.length > 2),
231
+ ]));
182
232
  const result = learningsWrite({
183
233
  source_project: sourceProject,
184
234
  learning: body,
185
235
  context: title,
186
236
  tags,
187
237
  }, { ...opts, dedupeIndex });
188
- if (result.created) {
238
+ if (result.created)
189
239
  created++;
190
- }
191
- else {
240
+ else
192
241
  skipped++;
242
+ };
243
+ for (const section of sections) {
244
+ const lines = section.trim().split('\n');
245
+ const category = lines[0].trim();
246
+ const body = lines.slice(1).join('\n').trim();
247
+ if (!body)
248
+ continue;
249
+ const categoryTag = category.toLowerCase().split(/\s+/)[0] || '';
250
+ // Split into ### items when present; otherwise one learning per section.
251
+ const items = body.split(/^### /m).map(s => s.trim()).filter(s => s.length > 0);
252
+ const hasItemHeadings = /^### /m.test(body);
253
+ if (!hasItemHeadings) {
254
+ writeOne(category, body, categoryTag ? [categoryTag] : []);
255
+ continue;
256
+ }
257
+ for (const item of items) {
258
+ const itemLines = item.split('\n');
259
+ const title = itemLines[0].trim();
260
+ const itemBody = itemLines.slice(1).join('\n').trim();
261
+ if (!itemBody && !title)
262
+ continue;
263
+ writeOne(title, itemBody || title, categoryTag ? [categoryTag] : []);
193
264
  }
194
265
  }
195
266
  return { total: created + skipped, created, skipped };
@@ -262,8 +262,14 @@ function planLegacyCleanup(configDirs, opts = {}) {
262
262
  }
263
263
  }
264
264
 
265
- // Legacy shared cache (fixed name from the old package)
266
- const legacyCachePath = path.join(homeDir, '.cache', 'gsd', 'gsd-update-check.json');
265
+ // Legacy shared cache (fixed name from the old package). #3799: under an
266
+ // explicit configDirs override the cache lives under the SCOPE root(s), not
267
+ // the default home — the override means "clean only what this redirected
268
+ // install owns", and the default home's cache belongs to the live install.
269
+ const cacheRoot = (Array.isArray(opts.configDirs) && opts.configDirs.length > 0)
270
+ ? opts.configDirs[0]
271
+ : homeDir;
272
+ const legacyCachePath = path.join(cacheRoot, '.cache', 'gsd', 'gsd-update-check.json');
267
273
  try {
268
274
  const stat = fsMod.statSync(legacyCachePath);
269
275
  if (stat.isFile()) {
@@ -26,6 +26,7 @@ exports.stripTaggedBlocks = stripTaggedBlocks;
26
26
  exports.replaceSection = replaceSection;
27
27
  exports.withSection = withSection;
28
28
  exports.deleteSection = deleteSection;
29
+ const pattern_cjs_1 = require("./pattern.cjs");
29
30
  // ─── stripFencedCode ──────────────────────────────────────────────────────────
30
31
  /**
31
32
  * CommonMark-correct fenced-code-block stripper.
@@ -792,7 +793,7 @@ function extractTaggedBlocks(content, tagName, allowAttributes = false) {
792
793
  * open>` marks the ACTIVE milestone and must be preserved, not stripped (#557).
793
794
  */
794
795
  function taggedBlockPattern(tagName, flags, allowAttributes) {
795
- const esc = tagName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
796
+ const esc = (0, pattern_cjs_1.escapeRegex)(tagName);
796
797
  const open = allowAttributes ? `<${esc}(?:\\s[^>]{0,1000})?>` : `<${esc}>`;
797
798
  const boundary = allowAttributes ? `<${esc}[\\s>]` : `<${esc}>`;
798
799
  return new RegExp(`${open}((?:(?!${boundary})[\\s\\S])*?)</${esc}>`, flags);