@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
@@ -11,7 +11,7 @@
11
11
  * {ok,data|kind}; the two never mix (different modules).
12
12
  */
13
13
  Object.defineProperty(exports, "__esModule", { value: true });
14
- exports.TABLE_SCHEMAS = void 0;
14
+ exports.QUICK_TASKS_SECTION_ABSENT = exports.TABLE_SCHEMAS = void 0;
15
15
  exports.matchTableSchema = matchTableSchema;
16
16
  exports.splitTableRow = splitTableRow;
17
17
  exports.isDelimiterRow = isDelimiterRow;
@@ -23,6 +23,7 @@ exports.findTableBySchema = findTableBySchema;
23
23
  exports.findTableWithColumns = findTableWithColumns;
24
24
  exports.escapeCell = escapeCell;
25
25
  exports.appendQuickTaskRow = appendQuickTaskRow;
26
+ exports.resetQuickTaskRows = resetQuickTaskRows;
26
27
  const markdown_sectionizer_cjs_1 = require("./markdown-sectionizer.cjs");
27
28
  // ─── Schema registry ──────────────────────────────────────────────────────────
28
29
  /**
@@ -280,32 +281,54 @@ function unescapeCellText(raw) {
280
281
  */
281
282
  function updateTableCell(tableText, match, column, newValue) {
282
283
  const lines = splitLinesWithOffsets(tableText);
284
+ // #3255: pick the first VALID table whose columns include `column`. The prior
285
+ // code bound to the FIRST table of any shape and returned 'unknown column' if
286
+ // that one lacked the column — so a section holding a summary table above the
287
+ // target (e.g. ## Traceability: a phase-summary table, then the requirement
288
+ // rows) never reached the target table. Scan for the first valid table that
289
+ // carries the column; if none does but a valid table exists, still return
290
+ // 'unknown column' (single-table behaviour unchanged). Track the first
291
+ // malformation reason so a lone malformed table keeps its specific error.
283
292
  let headerIdx = -1;
293
+ let columns = [];
294
+ let firstValidIdx = -1;
295
+ let firstMalformedReason = null;
296
+ const recordMalformed = (reason) => {
297
+ if (firstMalformedReason === null && firstValidIdx === -1)
298
+ firstMalformedReason = reason;
299
+ };
284
300
  for (let i = 0; i < lines.length; i++) {
285
301
  const trimmed = lines[i].line.trim();
286
- if (trimmed.startsWith('|') && trimmed.indexOf('|', 1) !== -1) {
302
+ if (!trimmed.startsWith('|') || trimmed.indexOf('|', 1) === -1)
303
+ continue;
304
+ const delimiterLine = lines[i + 1]?.line;
305
+ if (delimiterLine === undefined || !delimiterLine.trim().startsWith('|')) {
306
+ recordMalformed('missing delimiter row');
307
+ continue;
308
+ }
309
+ const candidateRanges = splitTableRowRanges(lines[i].line, lines[i].start);
310
+ const candidateColumns = candidateRanges.map((r) => unescapeCellText(tableText.slice(r.start, r.end)));
311
+ const delimiterCells = splitTableRow(delimiterLine);
312
+ if (!isDelimiterRow(delimiterCells)) {
313
+ recordMalformed('missing delimiter row');
314
+ continue;
315
+ }
316
+ if (delimiterCells.length !== candidateColumns.length) {
317
+ recordMalformed('delimiter/header column count mismatch');
318
+ continue;
319
+ }
320
+ if (firstValidIdx === -1)
321
+ firstValidIdx = i;
322
+ if (candidateColumns.includes(column)) {
287
323
  headerIdx = i;
324
+ columns = candidateColumns;
288
325
  break;
289
326
  }
290
327
  }
291
328
  if (headerIdx === -1) {
292
- return { ok: false, reason: 'no table found' };
293
- }
294
- const delimiterLine = lines[headerIdx + 1]?.line;
295
- if (delimiterLine === undefined || !delimiterLine.trim().startsWith('|')) {
296
- return { ok: false, reason: 'missing delimiter row' };
297
- }
298
- const headerRanges = splitTableRowRanges(lines[headerIdx].line, lines[headerIdx].start);
299
- const columns = headerRanges.map((r) => unescapeCellText(tableText.slice(r.start, r.end)));
300
- const delimiterCells = splitTableRow(delimiterLine);
301
- if (!isDelimiterRow(delimiterCells)) {
302
- return { ok: false, reason: 'missing delimiter row' };
303
- }
304
- if (delimiterCells.length !== columns.length) {
305
- return { ok: false, reason: 'delimiter/header column count mismatch' };
306
- }
307
- if (!columns.includes(column)) {
308
- return { ok: false, reason: `unknown column: ${column}` };
329
+ if (firstValidIdx !== -1)
330
+ return { ok: false, reason: `unknown column: ${column}` };
331
+ return { ok: false, reason: firstMalformedReason ?? 'no table found' };
309
332
  }
310
333
  const targetColIdx = columns.indexOf(column);
311
334
  let selectedRange;
@@ -623,6 +646,65 @@ function escapeCell(value) {
623
646
  .replace(/\|/g, '\\|')
624
647
  .trim();
625
648
  }
649
+ /**
650
+ * Shared sentinel `reason` returned by both `appendQuickTaskRow` and
651
+ * `resetQuickTaskRows` when the "Quick Tasks Completed" heading is absent
652
+ * from `stateContent` (#2142). The section is created lazily by
653
+ * `gsd-core/workflows/quick.md` Step 7b and is absent from
654
+ * `gsd-core/templates/state.md`, so an absent section is the common case,
655
+ * not an anomaly — callers compare against this constant rather than
656
+ * matching on the free-form reason string (CONTRIBUTING.md "Prohibited:
657
+ * Raw Text Matching").
658
+ */
659
+ exports.QUICK_TASKS_SECTION_ABSENT = 'no Quick Tasks Completed section';
660
+ /**
661
+ * #3860: heading predicate for STATE.md's Quick Tasks Completed section(s).
662
+ * The heading is a section LABEL, not data — milestone-scoped files
663
+ * legitimately carry suffixed headings (`### Quick Tasks Completed (v1.1+)`
664
+ * beside an archived `(v1.0)`), so the match is prefix-anchored with a word
665
+ * boundary, never exact: `Quick Tasks Completedness` must NOT match. Hoisted
666
+ * beside QUICK_TASKS_SECTION_ABSENT so `appendQuickTaskRow` and
667
+ * `resetQuickTaskRows` cannot drift apart again.
668
+ */
669
+ const isQuickTasksHeading = (h) => /^quick tasks completed\b/i.test(h.text.trim());
670
+ /**
671
+ * #3860: among ALL heading-matching sections, pick the first whose body is a
672
+ * table with a recognized Quick Tasks schema — a legacy/unparseable table
673
+ * first in document order no longer shadows a usable one further down. When
674
+ * NO section is usable, return the FIRST match so the caller's downstream
675
+ * error describes the real problem (unparseable/legacy table) instead of a
676
+ * false QUICK_TASKS_SECTION_ABSENT.
677
+ *
678
+ * Bounding: `collectSections` ends a candidate's body only at the NEXT
679
+ * matching heading — far too wide for splicing (it would swallow an
680
+ * intervening `## Deferred Items` table into the Quick Tasks body, and
681
+ * `appendQuickTaskRow`'s last-table-line scan would then splice the new row
682
+ * into that WRONG table). Each candidate is therefore re-collected through
683
+ * `collectSection` with an offset-precise predicate, whose default
684
+ * level-bounded stop (next heading of the same or higher level) is exactly
685
+ * the semantics the pre-#3860 single-section lookup had.
686
+ *
687
+ * Convention: "first" is document order — the newest-on-top layout the issue
688
+ * itself demonstrates (`(v1.1+)` above an archived `(v1.0)`). When several
689
+ * suffixed sections all carry recognized schemas, this layer has no signal
690
+ * for which milestone is active, so document order is the pinned tie-break.
691
+ */
692
+ function selectQuickTasksSection(stateContent) {
693
+ const candidates = (0, markdown_sectionizer_cjs_1.collectSections)(stateContent, isQuickTasksHeading);
694
+ if (candidates.length === 0)
695
+ return null;
696
+ const boundedOf = (cand) => (0, markdown_sectionizer_cjs_1.collectSection)(stateContent, (h) => h.offset === cand.heading.offset);
697
+ const firstBounded = boundedOf(candidates[0]);
698
+ for (const cand of candidates) {
699
+ const bounded = boundedOf(cand);
700
+ if (!bounded)
701
+ continue;
702
+ const parsed = parseMarkdownTable(bounded.body);
703
+ if (parsed.ok && matchTableSchema(parsed.value.columns)?.id === 'QuickTasks')
704
+ return bounded;
705
+ }
706
+ return firstBounded;
707
+ }
626
708
  /**
627
709
  * Append one row to STATE.md's "Quick Tasks Completed" table.
628
710
  *
@@ -643,9 +725,9 @@ function escapeCell(value) {
643
725
  * rows), preserving any surrounding blank lines/trailing content in the section.
644
726
  */
645
727
  function appendQuickTaskRow(stateContent, fields) {
646
- const section = (0, markdown_sectionizer_cjs_1.collectSection)(stateContent, (h) => /^quick tasks completed$/i.test(h.text.trim()));
728
+ const section = selectQuickTasksSection(stateContent);
647
729
  if (!section) {
648
- return { ok: false, reason: 'no Quick Tasks Completed section' };
730
+ return { ok: false, reason: exports.QUICK_TASKS_SECTION_ABSENT };
649
731
  }
650
732
  const parsed = parseMarkdownTable(section.body);
651
733
  if (!parsed.ok) {
@@ -663,7 +745,7 @@ function appendQuickTaskRow(stateContent, fields) {
663
745
  const rowNumber = parsed.value.rows.length + 1;
664
746
  const cellFor = (col) => {
665
747
  switch (col) {
666
- case '#': return escapeCell(String(rowNumber));
748
+ case '#': return escapeCell(fields.quickId ?? String(rowNumber));
667
749
  case 'Description': return escapeCell(fields.description);
668
750
  case 'Date': return escapeCell(fields.date);
669
751
  case 'Commit': return escapeCell(fields.commit);
@@ -694,5 +776,84 @@ function appendQuickTaskRow(stateContent, fields) {
694
776
  const content = (0, markdown_sectionizer_cjs_1.replaceSection)(stateContent, section, newBody);
695
777
  return { ok: true, value: { content, row, variant: match.label } };
696
778
  }
779
+ // ─── resetQuickTaskRows (#2142) ────────────────────────────────────────────
780
+ /**
781
+ * Clear every DATA row from STATE.md's "Quick Tasks Completed" table, leaving
782
+ * the header + delimiter lines byte-identical, for use at milestone close when
783
+ * `--archive-quick` has actually moved the underlying `.planning/quick/*`
784
+ * directories out from under the table (see `src/milestone.cts`'s
785
+ * `archiveQuickTaskDirectories` / `cmdMilestoneComplete` wiring).
786
+ *
787
+ * Mirrors `appendQuickTaskRow`'s exact contract (same `selectQuickTasksSection` ->
788
+ * `parseMarkdownTable` -> `matchTableSchema` pipeline, same fail-loud posture,
789
+ * same EOL-detect-before-split handling) rather than inventing a second one:
790
+ * - no "Quick Tasks Completed" heading -> `{ok:false, reason:
791
+ * QUICK_TASKS_SECTION_ABSENT}` (no-op; a STATE.md without the section has
792
+ * nothing to reset — per #2142 design doc §40, behavior table row 5, the
793
+ * section is created lazily by quick.md Step 7b and is absent from
794
+ * templates/state.md, so absence is the common path, not an anomaly.
795
+ * Callers MUST treat this sentinel as silent — never surface it as a
796
+ * `preservation_warnings` entry).
797
+ * - the section body doesn't parse as a GFM table -> `{ok:false, reason}`.
798
+ * - the table's header doesn't match a known `TABLE_SCHEMAS.QuickTasks`
799
+ * variant -> `{ok:false, reason}` and — CRITICAL — no modification at
800
+ * all. A user-added column means the data can't be safely addressed by
801
+ * name, so clearing it would destroy rows under a schema we don't
802
+ * understand (Postel's Law: liberal in accepting known shapes,
803
+ * conservative about destroying what we don't).
804
+ */
805
+ function resetQuickTaskRows(stateContent) {
806
+ if (typeof stateContent !== 'string' || stateContent.trim() === '') {
807
+ return { ok: false, reason: 'empty or non-string input' };
808
+ }
809
+ const section = selectQuickTasksSection(stateContent);
810
+ if (!section) {
811
+ return { ok: false, reason: exports.QUICK_TASKS_SECTION_ABSENT };
812
+ }
813
+ const parsed = parseMarkdownTable(section.body);
814
+ if (!parsed.ok) {
815
+ return { ok: false, reason: `quick-tasks table: ${parsed.reason}` };
816
+ }
817
+ const match = matchTableSchema(parsed.value.columns);
818
+ if (!match || match.id !== 'QuickTasks') {
819
+ // Refuse the reset — keep every row, caller-owned content is untouched.
820
+ return {
821
+ ok: false,
822
+ reason: `unrecognized Quick Tasks schema (columns: ${parsed.value.columns.join(' | ')})`,
823
+ };
824
+ }
825
+ const cleared = parsed.value.rows.length;
826
+ // Detect the section's EOL BEFORE splitting on /\r?\n/ (which discards it) —
827
+ // exactly `appendQuickTaskRow`'s convention — so a CRLF document is not
828
+ // downgraded to mixed EOL by the rejoin below.
829
+ const eol = /\r\n/.test(section.body) ? '\r\n' : '\n';
830
+ const lines = section.body.split(/\r?\n/);
831
+ let headerIdx = -1;
832
+ for (let i = 0; i < lines.length; i++) {
833
+ if (lines[i].trim().startsWith('|')) {
834
+ headerIdx = i;
835
+ break;
836
+ }
837
+ }
838
+ // headerIdx is always found here — parseMarkdownTable already confirmed a
839
+ // header + delimiter row exist in this same `section.body`.
840
+ let lastTableLineIdx = headerIdx + 1; // delimiter row, when there are zero data rows
841
+ for (let i = headerIdx + 2; i < lines.length; i++) {
842
+ if (!lines[i].trim().startsWith('|'))
843
+ break;
844
+ lastTableLineIdx = i;
845
+ }
846
+ // Keep the header + delimiter lines [0 .. headerIdx+1] plus everything
847
+ // after the contiguous run of `|`-prefixed data rows — dropping only the
848
+ // data rows themselves. Non-table content before/after the table inside
849
+ // the section is preserved untouched.
850
+ const newLines = [
851
+ ...lines.slice(0, headerIdx + 2),
852
+ ...lines.slice(lastTableLineIdx + 1),
853
+ ];
854
+ const newBody = newLines.join(eol);
855
+ const content = (0, markdown_sectionizer_cjs_1.replaceSection)(stateContent, section, newBody);
856
+ return { ok: true, value: { content, cleared, variant: match.label } };
857
+ }
697
858
  // Consumers: require('../gsd-core/bin/lib/markdown-table.cjs')
698
859
  // Named CJS exports are the canonical surface (ADR-457 .cts → .cjs build-at-publish).
@@ -0,0 +1,248 @@
1
+ "use strict";
2
+ /**
3
+ * Milestone Lock — advisory (phase, session) claim over the single Current
4
+ * Position slot in STATE.md (#3311).
5
+ *
6
+ * Problem it solves: two sessions running DIFFERENT phases in the same working
7
+ * tree both read-modify-write `## Current Position`. The byte-level STATE.md
8
+ * lock (#464) already serializes those writes, so no write is lost — but the
9
+ * SEMANTIC clobber is silent: `state.advance-plan` takes no phase argument and
10
+ * advances whatever plan the (possibly just clobbered) Current Position names,
11
+ * and nothing ever surfaces that two sessions claimed two different phases
12
+ * against the one single-slot field.
13
+ *
14
+ * This module is the maintainer-chosen fix (issue #3311 comment): a milestone
15
+ * lock keyed by phase + session id, with a second session WARNED instead of
16
+ * silently overwriting. It is an advisory claim file, not a mutex:
17
+ *
18
+ * - `.planning/milestone.lock` (workstream-scoped via planningDir) holds
19
+ * `{ phase, session, pid, updated_at }`.
20
+ * - Session identity reuses `getWorkstreamSessionKey()`
21
+ * (active-workstream-store.cjs): env-first (GSD_SESSION_KEY,
22
+ * CLAUDE_SESSION_ID, CODEX_THREAD_ID, …), then the controlling TTY. Two
23
+ * agent sessions in different terminals/runtimes resolve different keys;
24
+ * headless runs resolve to null.
25
+ * - Liveness is age-based only: a claim is live while
26
+ * `now - updated_at < MILESTONE_LOCK_TTL_MS`. There is deliberately NO
27
+ * pid-liveness gate — CLI invocations are short-lived, so the recorded pid
28
+ * is dead by the next invocation regardless of whether the agent SESSION is
29
+ * still active; pid-death would make every claim instantly stale. Active
30
+ * sessions heartbeat their claim (advance-plan on a matching position
31
+ * refreshes updated_at); an abandoned claim self-expires after the TTL.
32
+ * - Conflict rule: a live claim for a DIFFERENT phase held by a DIFFERENT
33
+ * session. Same phase never conflicts (the lock is keyed by phase — two
34
+ * sessions on one phase are doing the same work). A non-null session key
35
+ * equal to the caller's never conflicts (one orchestrating session may
36
+ * re-target its own claim). A null session key never counts as "same" as
37
+ * anything, so headless parallel phases are still detected. The one
38
+ * exception is advance-plan (checkMilestonePosition), which reports ANY
39
+ * live claim/position phase mismatch regardless of session — a session's
40
+ * own legitimate re-targeting goes through begin-phase, which keeps the
41
+ * claim in sync, so a same-session mismatch is just as anomalous.
42
+ * - On conflict the existing claim is LEFT INTACT (not stolen): as long as two
43
+ * phases are concurrently active, every Current Position mutation keeps
44
+ * reporting the conflict. The conflicting command still proceeds (warn, not
45
+ * block — a stale-but-live claim must not brick later sessions).
46
+ */
47
+ var __importDefault = (this && this.__importDefault) || function (mod) {
48
+ return (mod && mod.__esModule) ? mod : { "default": mod };
49
+ };
50
+ Object.defineProperty(exports, "__esModule", { value: true });
51
+ exports.MILESTONE_LOCK_TTL_MS = exports.MILESTONE_LOCK_FILENAME = void 0;
52
+ exports.warnMilestoneConflict = warnMilestoneConflict;
53
+ exports.claimMilestonePhase = claimMilestonePhase;
54
+ exports.checkMilestonePosition = checkMilestonePosition;
55
+ exports.checkMilestoneConflictForPhase = checkMilestoneConflictForPhase;
56
+ exports.releaseMilestonePhase = releaseMilestonePhase;
57
+ const node_fs_1 = __importDefault(require("node:fs"));
58
+ const node_path_1 = __importDefault(require("node:path"));
59
+ const clock_cjs_1 = require("./clock.cjs");
60
+ // eslint-disable-next-line @typescript-eslint/no-require-imports -- planning-workspace.cjs is an export= CommonJS module
61
+ const planningWorkspace = require("./planning-workspace.cjs");
62
+ // eslint-disable-next-line @typescript-eslint/no-require-imports -- active-workstream-store.cjs is an export= CommonJS module
63
+ const activeWorkstreamStore = require("./active-workstream-store.cjs");
64
+ exports.MILESTONE_LOCK_FILENAME = 'milestone.lock';
65
+ /**
66
+ * How long a claim stays live without a heartbeat. Active sessions heartbeat
67
+ * on every advance-plan against their claimed phase; a phase's planning stage
68
+ * (begin-phase → first completed plan) can legitimately run for hours, so the
69
+ * floor must comfortably exceed the longest expected gap between heartbeats
70
+ * while still expiring an abandoned claim within a working day.
71
+ */
72
+ exports.MILESTONE_LOCK_TTL_MS = 4 * 60 * 60 * 1000;
73
+ function milestoneLockPath(cwd) {
74
+ return node_path_1.default.join(planningWorkspace.planningDir(cwd), exports.MILESTONE_LOCK_FILENAME);
75
+ }
76
+ /**
77
+ * Normalize a phase token for claim comparison: trim, and collapse an integer
78
+ * spelling to its canonical form so "01", "1" and " 1 " compare equal while
79
+ * decimals ("2.5") compare by their trimmed text.
80
+ */
81
+ function normalizePhaseToken(value) {
82
+ const trimmed = String(value).trim();
83
+ if (/^\d+$/.test(trimmed))
84
+ return String(parseInt(trimmed, 10));
85
+ return trimmed;
86
+ }
87
+ function sameSession(a, b) {
88
+ // A null key is "unknown", not "equal" — two headless sessions must still
89
+ // conflict across phases (the CI/cron shape of #3311).
90
+ if (a === null || b === null)
91
+ return false;
92
+ return a === b;
93
+ }
94
+ function parseClaim(raw) {
95
+ if (!raw)
96
+ return null;
97
+ try {
98
+ const parsed = JSON.parse(raw);
99
+ if (typeof parsed.phase !== 'string' || !parsed.phase.trim())
100
+ return null;
101
+ return {
102
+ phase: parsed.phase,
103
+ session: typeof parsed.session === 'string' ? parsed.session : null,
104
+ pid: typeof parsed.pid === 'number' ? parsed.pid : 0,
105
+ updated_at: typeof parsed.updated_at === 'number' ? parsed.updated_at : 0,
106
+ };
107
+ }
108
+ catch {
109
+ // Corrupt body (concurrent partial write, hand edit) — treat as no claim.
110
+ // The next writer replaces the file; never crash a state command over an
111
+ // advisory sidecar.
112
+ return null;
113
+ }
114
+ }
115
+ function readClaim(cwd) {
116
+ try {
117
+ return parseClaim(node_fs_1.default.readFileSync(milestoneLockPath(cwd), 'utf-8'));
118
+ }
119
+ catch {
120
+ return null; // absent or unreadable — same posture as parseClaim
121
+ }
122
+ }
123
+ function writeClaim(cwd, claim) {
124
+ ensureClaimDir(cwd);
125
+ node_fs_1.default.writeFileSync(milestoneLockPath(cwd), JSON.stringify(claim, null, 2) + '\n');
126
+ }
127
+ // planningWorkspace.planningDir targets .planning (or the workstream-scoped
128
+ // variant); the parent is created by every GSD command that gets this far, but
129
+ // the claim write must not throw if it is somehow missing.
130
+ function ensureClaimDir(cwd) {
131
+ try {
132
+ node_fs_1.default.mkdirSync(node_path_1.default.dirname(milestoneLockPath(cwd)), { recursive: true });
133
+ }
134
+ catch {
135
+ /* best-effort — see writeClaim callers' advisory posture */
136
+ }
137
+ }
138
+ function isClaimLive(claim, nowMs) {
139
+ return nowMs - claim.updated_at < exports.MILESTONE_LOCK_TTL_MS;
140
+ }
141
+ function currentSessionKey() {
142
+ return activeWorkstreamStore.getWorkstreamSessionKey();
143
+ }
144
+ function toConflict(claim, phase, session) {
145
+ return {
146
+ locked_phase: claim.phase,
147
+ locked_session: claim.session,
148
+ phase,
149
+ session,
150
+ };
151
+ }
152
+ /**
153
+ * Human-visible warning for a conflict. Emitted on stderr unconditionally —
154
+ * visibility is the entire point of this lock (#3311's "silent last-write-wins").
155
+ */
156
+ function warnMilestoneConflict(conflict, action) {
157
+ const holder = conflict.locked_session ?? 'an unknown (headless) session';
158
+ const actor = conflict.session ?? 'an unknown (headless) session';
159
+ process.stderr.write(`[gsd-tools] WARNING: milestone lock conflict (#3311): ${holder} holds the milestone claim for phase ` +
160
+ `${conflict.locked_phase}, but ${actor} is running ${action} for phase ${conflict.phase}. ` +
161
+ `STATE.md's ## Current Position is a single slot — concurrent phases overwrite each other's ` +
162
+ `position. Verify Current Position before trusting it.\n`);
163
+ }
164
+ /**
165
+ * begin-phase entry point: claim `phase` for this session.
166
+ *
167
+ * Returns a conflict descriptor (and leaves the existing claim intact) when a
168
+ * live claim for a DIFFERENT phase is held by a DIFFERENT session; otherwise
169
+ * takes/refreshes the claim and returns null.
170
+ */
171
+ function claimMilestonePhase(cwd, phase, nowMs) {
172
+ const now = nowMs ?? clock_cjs_1.realClock.now();
173
+ const session = currentSessionKey();
174
+ const existing = readClaim(cwd);
175
+ if (existing !== null &&
176
+ isClaimLive(existing, now) &&
177
+ normalizePhaseToken(existing.phase) !== normalizePhaseToken(phase) &&
178
+ !sameSession(existing.session, session)) {
179
+ return toConflict(existing, phase, session);
180
+ }
181
+ writeClaim(cwd, { phase: String(phase).trim(), session, pid: process.pid, updated_at: now });
182
+ return null;
183
+ }
184
+ /**
185
+ * advance-plan entry point: `positionPhase` is the phase STATE.md's Current
186
+ * Position currently names.
187
+ *
188
+ * A live claim naming a DIFFERENT phase means the position was moved away from
189
+ * the claimed phase without a matching begin-phase — the #3311 flip — and is
190
+ * returned as a conflict REGARDLESS of session: this session's own legitimate
191
+ * re-targeting goes through begin-phase, which keeps the claim in sync, so a
192
+ * same-session mismatch is exactly as anomalous as a cross-session one. A live
193
+ * claim matching the position phase is heartbeat-refreshed (this session is
194
+ * actively working that phase, so the claim stays live). No claim is ever
195
+ * created here: advance-plan has no phase argument of its own, so it can only
196
+ * corroborate or contradict an existing claim, not originate one.
197
+ */
198
+ function checkMilestonePosition(cwd, positionPhase, nowMs) {
199
+ const now = nowMs ?? clock_cjs_1.realClock.now();
200
+ const existing = readClaim(cwd);
201
+ if (existing === null || !isClaimLive(existing, now))
202
+ return null;
203
+ const session = currentSessionKey();
204
+ if (normalizePhaseToken(existing.phase) === normalizePhaseToken(positionPhase)) {
205
+ // Heartbeat — keep the claim's liveness anchored to actual activity.
206
+ writeClaim(cwd, { phase: existing.phase, session: existing.session, pid: process.pid, updated_at: now });
207
+ return null;
208
+ }
209
+ return toConflict(existing, positionPhase, session);
210
+ }
211
+ /**
212
+ * phase.complete entry point (read-only check): a live claim for a DIFFERENT
213
+ * phase held by a DIFFERENT session is a conflict. phase.complete never claims
214
+ * — it ends work on a phase rather than starting it.
215
+ */
216
+ function checkMilestoneConflictForPhase(cwd, phase, nowMs) {
217
+ const now = nowMs ?? clock_cjs_1.realClock.now();
218
+ const existing = readClaim(cwd);
219
+ if (existing === null || !isClaimLive(existing, now))
220
+ return null;
221
+ if (normalizePhaseToken(existing.phase) === normalizePhaseToken(phase))
222
+ return null;
223
+ const session = currentSessionKey();
224
+ if (!sameSession(existing.session, session)) {
225
+ return toConflict(existing, phase, session);
226
+ }
227
+ return null;
228
+ }
229
+ /**
230
+ * Release the claim when the phase it names completes — regardless of which
231
+ * session completes it (an orchestrator cleaning up after a dead session must
232
+ * not be blocked by the dead session's own claim). Returns whether a matching
233
+ * claim was removed.
234
+ */
235
+ function releaseMilestonePhase(cwd, phase) {
236
+ const existing = readClaim(cwd);
237
+ if (existing === null)
238
+ return false;
239
+ if (normalizePhaseToken(existing.phase) !== normalizePhaseToken(phase))
240
+ return false;
241
+ try {
242
+ node_fs_1.default.unlinkSync(milestoneLockPath(cwd));
243
+ return true;
244
+ }
245
+ catch {
246
+ return false; // already gone — same outcome for the caller
247
+ }
248
+ }