@opengsd/gsd-core 1.9.1 → 1.11.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 (426) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +2 -3
  3. package/.opencode/plugins/gsd-core.js +8 -1
  4. package/agents/gsd-code-fixer.md +27 -3
  5. package/agents/gsd-debug-session-manager.md +11 -0
  6. package/agents/gsd-debugger.md +12 -246
  7. package/agents/gsd-doc-synthesizer.md +2 -4
  8. package/agents/gsd-executor.md +12 -10
  9. package/agents/gsd-integration-checker.md +3 -0
  10. package/agents/gsd-mempalace-curator.md +5 -2
  11. package/agents/gsd-phase-researcher.md +20 -1
  12. package/agents/gsd-plan-checker.md +46 -0
  13. package/agents/gsd-planner.md +49 -54
  14. package/agents/gsd-roadmapper.md +21 -3
  15. package/agents/gsd-user-profiler.md +3 -0
  16. package/agents/gsd-verifier.md +26 -73
  17. package/bin/install.js +1272 -1238
  18. package/bin/lib/ui-safety-gate.cjs +2 -0
  19. package/commands/gsd/code-review.md +1 -1
  20. package/commands/gsd/execute-phase.md +1 -1
  21. package/commands/gsd/map-codebase.md +1 -1
  22. package/commands/gsd/mempalace-capture.md +2 -2
  23. package/commands/gsd/mempalace-recall.md +1 -1
  24. package/commands/gsd/new-milestone.md +2 -2
  25. package/commands/gsd/plan-phase.md +1 -1
  26. package/commands/gsd/quick.md +1 -1
  27. package/commands/gsd/review-backlog.md +2 -1
  28. package/commands/gsd/verify-work.md +1 -1
  29. package/gsd-core/bin/gsd-tools.cjs +1009 -115
  30. package/gsd-core/bin/lib/active-workstream-store.cjs +153 -12
  31. package/gsd-core/bin/lib/agent-install-check.cjs +268 -38
  32. package/gsd-core/bin/lib/api-coverage.cjs +123 -5
  33. package/gsd-core/bin/lib/artifacts.cjs +3 -0
  34. package/gsd-core/bin/lib/assumption-delta.cjs +2 -4
  35. package/gsd-core/bin/lib/audit-command-router.cjs +9 -2
  36. package/gsd-core/bin/lib/audit.cjs +926 -202
  37. package/gsd-core/bin/lib/broken-windows.cjs +36 -6
  38. package/gsd-core/bin/lib/capability-consent.cjs +149 -15
  39. package/gsd-core/bin/lib/capability-lifecycle.cjs +45 -0
  40. package/gsd-core/bin/lib/capability-registry.cjs +608 -148
  41. package/gsd-core/bin/lib/capability-source.cjs +92 -0
  42. package/gsd-core/bin/lib/capability-trust.cjs +444 -25
  43. package/gsd-core/bin/lib/capability-validator.cjs +507 -24
  44. package/gsd-core/bin/lib/capability-writer.cjs +3 -2
  45. package/gsd-core/bin/lib/check-command-router.cjs +114 -38
  46. package/gsd-core/bin/lib/claude-orchestration.cjs +56 -3
  47. package/gsd-core/bin/lib/codex-agent-toml.cjs +329 -0
  48. package/gsd-core/bin/lib/command-aliases.cjs +94 -0
  49. package/gsd-core/bin/lib/command-roster.cjs +44 -1
  50. package/gsd-core/bin/lib/commands.cjs +665 -99
  51. package/gsd-core/bin/lib/commonjs-marker.cjs +142 -0
  52. package/gsd-core/bin/lib/complexity-trigger.cjs +1172 -0
  53. package/gsd-core/bin/lib/config-loader.cjs +76 -0
  54. package/gsd-core/bin/lib/config.cjs +22 -2
  55. package/gsd-core/bin/lib/context-composer.cjs +278 -0
  56. package/gsd-core/bin/lib/context-predicates.cjs +506 -0
  57. package/gsd-core/bin/lib/core-utils.cjs +217 -40
  58. package/gsd-core/bin/lib/decisions.cjs +23 -0
  59. package/gsd-core/bin/lib/docs.cjs +3 -2
  60. package/gsd-core/bin/lib/external-job.cjs +19 -4
  61. package/gsd-core/bin/lib/fallow-runner.cjs +20 -44
  62. package/gsd-core/bin/lib/frontmatter.cjs +239 -32
  63. package/gsd-core/bin/lib/gap-checker.cjs +68 -7
  64. package/gsd-core/bin/lib/gate-predicate-evaluator.cjs +57 -6
  65. package/gsd-core/bin/lib/git-base-branch.cjs +160 -15
  66. package/gsd-core/bin/lib/graphify.cjs +142 -27
  67. package/gsd-core/bin/lib/gsd2-import.cjs +37 -5
  68. package/gsd-core/bin/lib/health-diagnostic-rules/agent-install.cjs +101 -0
  69. package/gsd-core/bin/lib/health-diagnostic-rules/config-validation.cjs +348 -0
  70. package/gsd-core/bin/lib/health-diagnostic-rules/consistency.cjs +145 -0
  71. package/gsd-core/bin/lib/health-diagnostic-rules/install-surface-shadowing.cjs +98 -0
  72. package/gsd-core/bin/lib/health-diagnostic-rules/milestone-archive-hygiene.cjs +100 -0
  73. package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +222 -0
  74. package/gsd-core/bin/lib/health-diagnostic-rules/roadmap-disk-consistency.cjs +265 -0
  75. package/gsd-core/bin/lib/health-diagnostic-rules/root-existence.cjs +161 -0
  76. package/gsd-core/bin/lib/health-diagnostic-rules/state-consistency.cjs +303 -0
  77. package/gsd-core/bin/lib/health-diagnostic-rules/worktree-health.cjs +173 -0
  78. package/gsd-core/bin/lib/health-diagnostic-types.cjs +68 -0
  79. package/gsd-core/bin/lib/health-diagnostic.cjs +431 -0
  80. package/gsd-core/bin/lib/host-integration.cjs +13 -1
  81. package/gsd-core/bin/lib/host-runtime-detection.cjs +134 -0
  82. package/gsd-core/bin/lib/init-command-router.cjs +83 -8
  83. package/gsd-core/bin/lib/init.cjs +1325 -169
  84. package/gsd-core/bin/lib/install-effort-resolver.cjs +73 -30
  85. package/gsd-core/bin/lib/install-engine.cjs +805 -264
  86. package/gsd-core/bin/lib/install-fs-adapter.cjs +262 -0
  87. package/gsd-core/bin/lib/install-model-override-resolver.cjs +203 -0
  88. package/gsd-core/bin/lib/install-profiles.cjs +160 -57
  89. package/gsd-core/bin/lib/install-scope.cjs +270 -0
  90. package/gsd-core/bin/lib/install-shadow-report.cjs +385 -0
  91. package/gsd-core/bin/lib/installed-surface-resolver.cjs +381 -0
  92. package/gsd-core/bin/lib/installer-migration-authoring.cjs +3 -1
  93. package/gsd-core/bin/lib/installer-migration-report.cjs +4 -0
  94. package/gsd-core/bin/lib/installer-migrations/007-retire-config-root-commonjs-marker.cjs +149 -0
  95. package/gsd-core/bin/lib/installer-migrations/008-cursor-retire-commands-surface.cjs +55 -0
  96. package/gsd-core/bin/lib/installer-migrations/009-pi-retire-reserved-hooks-dir.cjs +199 -0
  97. package/gsd-core/bin/lib/installer-migrations.cjs +206 -13
  98. package/gsd-core/bin/lib/io.cjs +38 -3
  99. package/gsd-core/bin/lib/markdown-sectionizer.cjs +8 -1
  100. package/gsd-core/bin/lib/markdown-table.cjs +133 -20
  101. package/gsd-core/bin/lib/mcp-catalog.cjs +518 -0
  102. package/gsd-core/bin/lib/mcp-server.cjs +135 -3
  103. package/gsd-core/bin/lib/milestone-lock.cjs +248 -0
  104. package/gsd-core/bin/lib/milestone.cjs +821 -109
  105. package/gsd-core/bin/lib/model-catalog.cjs +59 -1
  106. package/gsd-core/bin/lib/model-resolver.cjs +183 -40
  107. package/gsd-core/bin/lib/normalize-test-command.cjs +1 -1
  108. package/gsd-core/bin/lib/pattern.cjs +122 -0
  109. package/gsd-core/bin/lib/phase-estimation.cjs +1 -1
  110. package/gsd-core/bin/lib/phase-id.cjs +507 -36
  111. package/gsd-core/bin/lib/phase-lifecycle.cjs +28 -3
  112. package/gsd-core/bin/lib/phase-locator.cjs +258 -58
  113. package/gsd-core/bin/lib/phase.cjs +891 -156
  114. package/gsd-core/bin/lib/plan-dependency-graph.cjs +303 -0
  115. package/gsd-core/bin/lib/plan-drift-guard.cjs +120 -0
  116. package/gsd-core/bin/lib/plan-scan.cjs +86 -2
  117. package/gsd-core/bin/lib/planning-scope.cjs +31 -0
  118. package/gsd-core/bin/lib/planning-snapshot.cjs +890 -0
  119. package/gsd-core/bin/lib/planning-workspace.cjs +60 -6
  120. package/gsd-core/bin/lib/probe-core.cjs +1 -1
  121. package/gsd-core/bin/lib/profile-output.cjs +1 -1
  122. package/gsd-core/bin/lib/prompt-budget.cjs +128 -165
  123. package/gsd-core/bin/lib/refactor-trigger-command-router.cjs +740 -0
  124. package/gsd-core/bin/lib/retired-artifact-cleanup.cjs +85 -0
  125. package/gsd-core/bin/lib/review-lane-descriptor.cjs +108 -0
  126. package/gsd-core/bin/lib/review-lane-invocation.cjs +30 -0
  127. package/gsd-core/bin/lib/review-lane-runner.cjs +447 -68
  128. package/gsd-core/bin/lib/review-reviewer-selection.cjs +13 -18
  129. package/gsd-core/bin/lib/roadmap-command-router.cjs +76 -9
  130. package/gsd-core/bin/lib/roadmap-parser.cjs +1035 -194
  131. package/gsd-core/bin/lib/roadmap-upgrade.cjs +37 -10
  132. package/gsd-core/bin/lib/roadmap.cjs +405 -84
  133. package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +795 -100
  134. package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +14 -2
  135. package/gsd-core/bin/lib/runtime-artifact-layout.cjs +440 -57
  136. package/gsd-core/bin/lib/runtime-config-adapter-registry.cjs +3 -2
  137. package/gsd-core/bin/lib/runtime-homes.cjs +220 -41
  138. package/gsd-core/bin/lib/runtime-hooks-surface.cjs +220 -44
  139. package/gsd-core/bin/lib/runtime-name-policy.cjs +3 -1
  140. package/gsd-core/bin/lib/runtime-slash.cjs +27 -9
  141. package/gsd-core/bin/lib/section-manifest.cjs +209 -0
  142. package/gsd-core/bin/lib/security.cjs +104 -5
  143. package/gsd-core/bin/lib/shell-command-projection.cjs +388 -30
  144. package/gsd-core/bin/lib/smart-entry.cjs +154 -22
  145. package/gsd-core/bin/lib/state-command-router.cjs +5 -1
  146. package/gsd-core/bin/lib/state-document.cjs +152 -8
  147. package/gsd-core/bin/lib/state-transition.cjs +424 -105
  148. package/gsd-core/bin/lib/state.cjs +1927 -401
  149. package/gsd-core/bin/lib/surface.cjs +35 -10
  150. package/gsd-core/bin/lib/text-lines.cjs +80 -0
  151. package/gsd-core/bin/lib/token-scanner.cjs +76 -0
  152. package/gsd-core/bin/lib/uat-predicate.cjs +20 -4
  153. package/gsd-core/bin/lib/uat.cjs +706 -64
  154. package/gsd-core/bin/lib/ui-frontend-evidence.cjs +157 -0
  155. package/gsd-core/bin/lib/ui-safety-gate.cjs +14 -5
  156. package/gsd-core/bin/lib/unusable-input.cjs +33 -0
  157. package/gsd-core/bin/lib/update-context.cjs +8 -2
  158. package/gsd-core/bin/lib/user-artifact-staging.cjs +705 -0
  159. package/gsd-core/bin/lib/validate.cjs +20 -6
  160. package/gsd-core/bin/lib/vendor/README.md +37 -0
  161. package/gsd-core/bin/lib/vendor/re2js.cjs +6480 -0
  162. package/gsd-core/bin/lib/vendor/re2js.d.cts +938 -0
  163. package/gsd-core/bin/lib/verification-command-router.cjs +2 -1
  164. package/gsd-core/bin/lib/verification.cjs +287 -20
  165. package/gsd-core/bin/lib/verify.cjs +368 -880
  166. package/gsd-core/bin/lib/workflow-fragments.cjs +557 -0
  167. package/gsd-core/bin/lib/workstream-inventory-builder.cjs +203 -19
  168. package/gsd-core/bin/lib/workstream-inventory.cjs +576 -31
  169. package/gsd-core/bin/lib/workstream.cjs +8 -2
  170. package/gsd-core/bin/lib/worktree-base-ref.cjs +50 -6
  171. package/gsd-core/bin/lib/worktree-safety.cjs +450 -125
  172. package/gsd-core/bin/shared/config-defaults.manifest.json +1 -0
  173. package/gsd-core/bin/shared/config-schema.manifest.json +9 -1
  174. package/gsd-core/references/agent-contracts.md +43 -26
  175. package/gsd-core/references/artifact-types.md +10 -3
  176. package/gsd-core/references/autonomous-ui-design-contract.md +42 -0
  177. package/gsd-core/references/checkpoints.md +2 -2
  178. package/gsd-core/references/context-budget.md +1 -1
  179. package/gsd-core/references/debugger-techniques.md +255 -0
  180. package/gsd-core/references/dispatch-isolation-gate.md +138 -0
  181. package/gsd-core/references/doc-conflict-engine.md +1 -1
  182. package/gsd-core/references/execute-mvp-tdd.md +3 -3
  183. package/gsd-core/references/execute-phase-between-wave-reset.md +6 -2
  184. package/gsd-core/references/execute-phase-context-guard.md +1 -1
  185. package/gsd-core/references/execute-phase-response-language.md +1 -1
  186. package/gsd-core/references/execute-phase-wave-guard.md +6 -2
  187. package/gsd-core/references/gate-prompts.md +1 -1
  188. package/gsd-core/references/git-planning-commit.md +2 -1
  189. package/gsd-core/references/loop-hook-dispatch.md +39 -2
  190. package/gsd-core/references/model-profiles.md +12 -4
  191. package/gsd-core/references/mvp-concepts.md +9 -9
  192. package/gsd-core/references/planner-guidance.md +3 -9
  193. package/gsd-core/references/planner-preconditions.md +1 -1
  194. package/gsd-core/references/planner-reviews.md +1 -1
  195. package/gsd-core/references/planning-config.md +8 -6
  196. package/gsd-core/references/research-documentation-lookup.md +5 -3
  197. package/gsd-core/references/revision-loop.md +1 -1
  198. package/gsd-core/references/specless-probe-fallback.md +8 -7
  199. package/gsd-core/references/universal-anti-patterns.md +3 -3
  200. package/gsd-core/references/verifier-phase-gates.md +192 -0
  201. package/gsd-core/references/verifier-wiring-patterns.md +100 -0
  202. package/gsd-core/references/verify-mvp-mode.md +1 -1
  203. package/gsd-core/references/workstream-flag.md +22 -6
  204. package/gsd-core/references/worktree-branch-check.md +2 -2
  205. package/gsd-core/templates/discussion-log.md +1 -1
  206. package/gsd-core/templates/phase-prompt.md +2 -4
  207. package/gsd-core/templates/state.md +4 -4
  208. package/gsd-core/templates/summary-complex.md +2 -0
  209. package/gsd-core/templates/summary-minimal.md +2 -0
  210. package/gsd-core/templates/summary-standard.md +2 -0
  211. package/gsd-core/templates/summary.md +2 -0
  212. package/gsd-core/templates/verification-report.md +9 -1
  213. package/gsd-core/workflows/ai-integration-phase.md +9 -11
  214. package/gsd-core/workflows/audit-milestone.md +3 -0
  215. package/gsd-core/workflows/autonomous/steps/converge-banner.md +1 -0
  216. package/gsd-core/workflows/autonomous/steps/converge-dispatch-bg.md +11 -0
  217. package/gsd-core/workflows/autonomous/steps/converge-dispatch-inline.md +7 -0
  218. package/gsd-core/workflows/autonomous/steps/converge-fail-fast.md +21 -0
  219. package/gsd-core/workflows/autonomous/steps/converge-loop.md +7 -0
  220. package/gsd-core/workflows/autonomous.md +33 -70
  221. package/gsd-core/workflows/cleanup.md +62 -3
  222. package/gsd-core/workflows/code-review/steps/dispatch-fix.md +39 -0
  223. package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +93 -0
  224. package/gsd-core/workflows/code-review-fix.md +37 -10
  225. package/gsd-core/workflows/code-review.md +74 -166
  226. package/gsd-core/workflows/complete-milestone/steps/git-tag.md +29 -0
  227. package/gsd-core/workflows/complete-milestone.md +160 -95
  228. package/gsd-core/workflows/debug.md +16 -17
  229. package/gsd-core/workflows/diagnose-issues.md +56 -8
  230. package/gsd-core/workflows/discuss-phase/modes/chain.md +2 -1
  231. package/gsd-core/workflows/discuss-phase/modes/default.md +1 -1
  232. package/gsd-core/workflows/discuss-phase-assumptions/steps/auto-advance-dispatch.md +15 -0
  233. package/gsd-core/workflows/discuss-phase-assumptions.md +7 -17
  234. package/gsd-core/workflows/docs-update/steps/dispatch-monorepo-packages.md +51 -0
  235. package/gsd-core/workflows/docs-update.md +8 -51
  236. package/gsd-core/workflows/edit-phase.md +26 -1
  237. package/gsd-core/workflows/eval-review.md +3 -5
  238. package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +64 -7
  239. package/gsd-core/workflows/execute-phase/steps/gap-closure-artifacts.md +50 -0
  240. package/gsd-core/workflows/execute-phase/steps/partial-wave.md +31 -0
  241. package/gsd-core/workflows/execute-phase/steps/per-plan-executor-routing.md +77 -0
  242. package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +21 -0
  243. package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +42 -0
  244. package/gsd-core/workflows/execute-phase/steps/regression-gate.md +43 -37
  245. package/gsd-core/workflows/execute-phase.md +103 -187
  246. package/gsd-core/workflows/execute-plan.md +36 -4
  247. package/gsd-core/workflows/explore.md +131 -4
  248. package/gsd-core/workflows/fast.md +10 -2
  249. package/gsd-core/workflows/health.md +73 -4
  250. package/gsd-core/workflows/help/modes/full.md +6 -1
  251. package/gsd-core/workflows/import.md +4 -4
  252. package/gsd-core/workflows/ingest-docs.md +7 -6
  253. package/gsd-core/workflows/mvp-phase.md +6 -3
  254. package/gsd-core/workflows/new-milestone/steps/project-md-milestone-write.md +16 -0
  255. package/gsd-core/workflows/new-milestone/steps/reset-phase-safety.md +19 -0
  256. package/gsd-core/workflows/new-milestone.md +35 -47
  257. package/gsd-core/workflows/new-project/steps/auto-mode-config.md +176 -0
  258. package/gsd-core/workflows/new-project/steps/auto-mode-detection.md +32 -0
  259. package/gsd-core/workflows/new-project/steps/codebase-map-offer.md +18 -0
  260. package/gsd-core/workflows/new-project.md +27 -240
  261. package/gsd-core/workflows/next.md +12 -0
  262. package/gsd-core/workflows/plan-phase/steps/adr-ingest-express-path.md +15 -0
  263. package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +110 -0
  264. package/gsd-core/workflows/plan-phase/steps/prd-express-gate.md +8 -0
  265. package/gsd-core/workflows/plan-phase/steps/research-only-early-exit.md +17 -0
  266. package/gsd-core/workflows/plan-phase/steps/research-only-modifiers.md +16 -0
  267. package/gsd-core/workflows/plan-phase/steps/reviews-prerequisite.md +17 -0
  268. package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +149 -0
  269. package/gsd-core/workflows/plan-phase.md +89 -209
  270. package/gsd-core/workflows/plan-review-convergence.md +50 -2
  271. package/gsd-core/workflows/progress/steps/forensic-audit.md +125 -0
  272. package/gsd-core/workflows/progress/steps/mvp-display.md +18 -0
  273. package/gsd-core/workflows/progress.md +45 -159
  274. package/gsd-core/workflows/quick/steps/discussion-phase.md +124 -0
  275. package/gsd-core/workflows/quick/steps/plan-checker-loop.md +111 -0
  276. package/gsd-core/workflows/quick/steps/quick-verification.md +67 -0
  277. package/gsd-core/workflows/quick/steps/research-phase.md +72 -0
  278. package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +37 -0
  279. package/gsd-core/workflows/quick.md +55 -405
  280. package/gsd-core/workflows/resume-project.md +3 -0
  281. package/gsd-core/workflows/review/steps/reviewer-instances-note-1.md +4 -0
  282. package/gsd-core/workflows/review/steps/reviewer-instances-note-2.md +3 -0
  283. package/gsd-core/workflows/review.md +41 -13
  284. package/gsd-core/workflows/section-manifest.json +219 -0
  285. package/gsd-core/workflows/secure-phase.md +1 -1
  286. package/gsd-core/workflows/session-report.md +2 -1
  287. package/gsd-core/workflows/settings.md +66 -2
  288. package/gsd-core/workflows/ship.md +104 -44
  289. package/gsd-core/workflows/sketch.md +1 -1
  290. package/gsd-core/workflows/spec-phase.md +41 -20
  291. package/gsd-core/workflows/spike-wrap-up.md +20 -5
  292. package/gsd-core/workflows/spike.md +50 -16
  293. package/gsd-core/workflows/sync-skills.md +106 -13
  294. package/gsd-core/workflows/transition/steps/workstream-collision-check.md +17 -0
  295. package/gsd-core/workflows/transition.md +53 -31
  296. package/gsd-core/workflows/ui-phase.md +13 -12
  297. package/gsd-core/workflows/ui-review.md +2 -2
  298. package/gsd-core/workflows/update/steps/channel-banner.md +7 -0
  299. package/gsd-core/workflows/update.md +19 -8
  300. package/gsd-core/workflows/validate-phase.md +1 -1
  301. package/gsd-core/workflows/verify-work/steps/automated-ui-verification.md +36 -0
  302. package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +21 -0
  303. package/gsd-core/workflows/verify-work.md +17 -65
  304. package/hooks/dist/gsd-agent-isolation-guard.js +517 -0
  305. package/hooks/dist/gsd-check-update-worker.js +64 -12
  306. package/hooks/dist/gsd-check-update.js +19 -1
  307. package/hooks/dist/gsd-cursor-pre-tool.js +0 -3
  308. package/hooks/dist/gsd-cursor-subagent-start.js +607 -26
  309. package/hooks/dist/gsd-cursor-subagent-stop.js +3 -2
  310. package/hooks/dist/gsd-prompt-guard.js +21 -20
  311. package/hooks/dist/gsd-read-injection-scanner.js +45 -24
  312. package/hooks/dist/gsd-statusline.js +90 -6
  313. package/hooks/dist/gsd-update-banner.js +22 -1
  314. package/hooks/dist/gsd-workflow-guard.js +134 -36
  315. package/hooks/dist/gsd-worktree-path-guard.js +2 -1
  316. package/hooks/dist/gsd-write-guard.js +359 -0
  317. package/hooks/dist/lib/git-cmd.js +92 -59
  318. package/hooks/dist/lib/injection-patterns.js +45 -0
  319. package/hooks/dist/lib/isolation-deny-reason.js +39 -0
  320. package/hooks/dist/lib/isolation-sentinel.js +277 -0
  321. package/hooks/dist/managed-hooks-registry.cjs +2 -0
  322. package/hooks/gsd-agent-isolation-guard.js +517 -0
  323. package/hooks/gsd-check-update-worker.js +64 -12
  324. package/hooks/gsd-check-update.js +19 -1
  325. package/hooks/gsd-cursor-pre-tool.js +0 -3
  326. package/hooks/gsd-cursor-subagent-start.js +607 -26
  327. package/hooks/gsd-cursor-subagent-stop.js +3 -2
  328. package/hooks/gsd-prompt-guard.js +21 -20
  329. package/hooks/gsd-read-injection-scanner.js +45 -24
  330. package/hooks/gsd-statusline.js +90 -6
  331. package/hooks/gsd-update-banner.js +22 -1
  332. package/hooks/gsd-workflow-guard.js +134 -36
  333. package/hooks/gsd-worktree-path-guard.js +2 -1
  334. package/hooks/gsd-write-guard.js +359 -0
  335. package/hooks/hooks.json +12 -0
  336. package/hooks/lib/git-cmd.js +92 -59
  337. package/hooks/lib/injection-patterns.js +45 -0
  338. package/hooks/lib/isolation-deny-reason.js +39 -0
  339. package/hooks/lib/isolation-sentinel.js +277 -0
  340. package/hooks/managed-hooks-registry.cjs +2 -0
  341. package/package.json +31 -10
  342. package/pi/gsd.cjs +71 -12
  343. package/scripts/baselines/planning-prompt-drift-baseline.json +4 -0
  344. package/scripts/baselines/planning-snapshot-bypass-baseline.json +12 -0
  345. package/scripts/baselines/unreachable-guard-drift-baseline.json +4 -0
  346. package/scripts/build-hooks.js +9 -0
  347. package/scripts/changeset/lint.cjs +68 -6
  348. package/scripts/changeset/serialize.cjs +5 -1
  349. package/scripts/check-alias-drift.cjs +7 -43
  350. package/scripts/check-contract-drift.cjs +297 -0
  351. package/scripts/ci-test-scope.cjs +19 -2
  352. package/scripts/command-contract-helpers.cjs +903 -1
  353. package/scripts/gen-adr-index.cjs +728 -38
  354. package/scripts/gen-capability-matrix.cjs +1 -1
  355. package/scripts/gen-capability-registry.cjs +3 -15
  356. package/scripts/gen-context-index.cjs +439 -0
  357. package/scripts/gen-health-docs.cjs +390 -0
  358. package/scripts/gen-inventory-manifest.cjs +150 -4
  359. package/scripts/gen-loop-host-contract.cjs +4 -24
  360. package/scripts/gen-prompt-budget-parity-corpus.cjs +645 -0
  361. package/scripts/gen-registry.cjs +3 -14
  362. package/scripts/gen-section-manifest.cjs +638 -0
  363. package/scripts/generate-package-identity.cjs +4 -2
  364. package/scripts/lib/alias-drift-families.cjs +46 -0
  365. package/scripts/lib/drift-scan.cjs +278 -0
  366. package/scripts/lint-allow-test-rule-refs.allowlist.json +15 -54
  367. package/scripts/lint-allow-test-rule-refs.effective-ceiling.json +4 -0
  368. package/scripts/lint-allow-test-rule-refs.unverified-ceiling.json +3 -0
  369. package/scripts/lint-canary-version-leak.cjs +73 -0
  370. package/scripts/lint-command-contract.cjs +96 -13
  371. package/scripts/lint-compiled-artifact-sync.cjs +6 -1
  372. package/scripts/lint-completion-predicate-drift.cjs +933 -0
  373. package/scripts/lint-completion-ratio-drift.cjs +214 -0
  374. package/scripts/lint-default-flip-documentation.cjs +193 -0
  375. package/scripts/lint-docs-command-form.cjs +195 -0
  376. package/scripts/lint-docs-required.cjs +9 -1
  377. package/scripts/lint-emitted-drift-ack.cjs +215 -20
  378. package/scripts/lint-eslint-glob-coverage.allowlist.json +34 -0
  379. package/scripts/lint-eslint-glob-coverage.cjs +340 -0
  380. package/scripts/lint-example-parser-parity.cjs +395 -0
  381. package/scripts/lint-frontmatter-scalar-broad-grep.cjs +237 -0
  382. package/scripts/lint-health-diagnostic-rule-table.cjs +404 -0
  383. package/scripts/lint-hooks-runtime-build-seam.cjs +262 -0
  384. package/scripts/lint-milestone-window-drift.cjs +468 -0
  385. package/scripts/lint-phase-enumeration-drift.cjs +479 -0
  386. package/scripts/lint-plan-count-drift.cjs +318 -0
  387. package/scripts/lint-planning-artifact-writer-drift.cjs +398 -0
  388. package/scripts/lint-planning-prompt-drift.cjs +434 -0
  389. package/scripts/lint-planning-snapshot-bypass-drift.cjs +544 -0
  390. package/scripts/lint-regression-test-names.cjs +15 -13
  391. package/scripts/lint-removed-but-needed.cjs +320 -0
  392. package/scripts/lint-state-field-drift.cjs +805 -0
  393. package/scripts/lint-state-write-path-drift.cjs +1045 -0
  394. package/scripts/lint-test-file-count.allowlist.json +40 -3
  395. package/scripts/lint-unreachable-guard-drift.cjs +843 -0
  396. package/scripts/lint-vendored-deps.cjs +124 -0
  397. package/scripts/mutation-matrix.cjs +13 -0
  398. package/scripts/pr-changed-files.cjs +63 -0
  399. package/scripts/pr-template-policy.cjs +14 -4
  400. package/scripts/prompt-injection-scan.sh +52 -6
  401. package/scripts/require-issue-link-policy.cjs +192 -0
  402. package/scripts/state-write-path-drift-baseline.json +19 -0
  403. package/scripts/sync-runtime-launcher.cjs +2 -4
  404. package/skills/gsd-autonomous/SKILL.md +0 -1
  405. package/skills/gsd-code-review/SKILL.md +1 -1
  406. package/skills/gsd-execute-phase/SKILL.md +1 -2
  407. package/skills/gsd-map-codebase/SKILL.md +1 -1
  408. package/skills/gsd-mempalace-capture/SKILL.md +2 -2
  409. package/skills/gsd-mempalace-recall/SKILL.md +1 -1
  410. package/skills/gsd-new-milestone/SKILL.md +2 -2
  411. package/skills/gsd-next/SKILL.md +0 -1
  412. package/skills/gsd-plan-phase/SKILL.md +1 -2
  413. package/skills/gsd-progress/SKILL.md +0 -1
  414. package/skills/gsd-quick/SKILL.md +1 -1
  415. package/skills/gsd-review-backlog/SKILL.md +2 -1
  416. package/skills/gsd-stats/SKILL.md +0 -1
  417. package/skills/gsd-verify-work/SKILL.md +1 -1
  418. package/vscode/package.json +1 -1
  419. package/gsd-core/workflows/discovery-phase.md +0 -298
  420. package/gsd-core/workflows/plan-milestone-gaps.md +0 -281
  421. package/gsd-core/workflows/verify-phase.md +0 -577
  422. package/scripts/affected-tests-lib.cjs +0 -554
  423. package/scripts/gen-emitted-baseline.cjs +0 -145
  424. package/scripts/lint-allow-test-rule-refs.cjs +0 -162
  425. package/scripts/run-affected-tests.cjs +0 -7
  426. package/scripts/run-tests.cjs +0 -1050
@@ -27,6 +27,9 @@
27
27
  * the additive, importable server surface a host (or the bin shim) drives.
28
28
  */
29
29
  'use strict';
30
+ var __importDefault = (this && this.__importDefault) || function (mod) {
31
+ return (mod && mod.__esModule) ? mod : { "default": mod };
32
+ };
30
33
  Object.defineProperty(exports, "__esModule", { value: true });
31
34
  exports.SERVER_NAME = exports.PROTOCOL_VERSION = void 0;
32
35
  exports.handleMessage = handleMessage;
@@ -36,9 +39,62 @@ const stateIo = require("./state-io.cjs");
36
39
  // eslint-disable-next-line @typescript-eslint/no-require-imports
37
40
  const shellCommandProjection = require("./shell-command-projection.cjs");
38
41
  const { dispatchGsdCommand } = shellCommandProjection;
42
+ const node_fs_1 = __importDefault(require("node:fs"));
43
+ const node_path_1 = __importDefault(require("node:path"));
44
+ const mcp_catalog_cjs_1 = require("./mcp-catalog.cjs");
39
45
  exports.PROTOCOL_VERSION = '2024-11-05';
40
46
  exports.SERVER_NAME = 'gsd-core';
41
- const SERVER_VERSION = '1.7.0';
47
+ // #3072: resolve SERVER_VERSION from package.json (source tree) or the
48
+ // installed gsd-core/VERSION marker, WITHOUT a top-level `require(...)` —
49
+ // mirrors the established, already-precedented resolver in
50
+ // `runtime-artifact-conversion.cts`'s `gsdVersion()` (#1383): a top-level
51
+ // require would throw on any runtime whose root has no package.json/VERSION,
52
+ // and `scripts/sync-manifest-versions.cjs` is not a fit here — its
53
+ // `VERSIONED_MANIFESTS` list stamps a `version` FIELD into hand-authored JSON
54
+ // manifests (plugin.json, marketplace.json, vscode/package.json); a `.cts`
55
+ // source constant is not a JSON document that script can round-trip through
56
+ // `readJson`/`setByPath`, and teaching it to text-edit TypeScript source
57
+ // would be a much larger footprint than this lazy, cached, defensive read.
58
+ // Resolved once per process (never per-request) and cached; a failed lookup
59
+ // degrades to '0.0.0' (never `undefined`, never a crash) rather than making
60
+ // `initialize`'s `serverInfo.version` field absent or malformed.
61
+ const SEMVER_PREFIX = /^\d+\.\d+\.\d+/;
62
+ let cachedServerVersion;
63
+ function resolveServerVersion() {
64
+ if (cachedServerVersion !== undefined)
65
+ return cachedServerVersion;
66
+ let version = '0.0.0';
67
+ try {
68
+ const v = node_fs_1.default.readFileSync(node_path_1.default.join(__dirname, '..', '..', 'VERSION'), 'utf8').trim();
69
+ if (SEMVER_PREFIX.test(v))
70
+ version = v;
71
+ }
72
+ catch {
73
+ /* not an installed tree (no gsd-core/VERSION) */
74
+ }
75
+ if (version === '0.0.0') {
76
+ try {
77
+ // eslint-disable-next-line @typescript-eslint/no-require-imports -- lazy, defensive: a top-level require would throw on a runtime root with no package.json.
78
+ const pkg = require(node_path_1.default.join(__dirname, '..', '..', '..', 'package.json'));
79
+ if (pkg && typeof pkg.version === 'string' && SEMVER_PREFIX.test(pkg.version))
80
+ version = pkg.version;
81
+ }
82
+ catch {
83
+ /* runtime root has no package.json */
84
+ }
85
+ }
86
+ cachedServerVersion = version;
87
+ return version;
88
+ }
89
+ // Catalog is built once per process, lazily, and cached (design "Shape" /
90
+ // Gall's Law — no watching, no invalidation; Known limits: the package is
91
+ // immutable in every install mode we ship).
92
+ let cachedCatalog;
93
+ function getCatalog() {
94
+ if (cachedCatalog === undefined)
95
+ cachedCatalog = (0, mcp_catalog_cjs_1.buildCatalog)();
96
+ return cachedCatalog;
97
+ }
42
98
  // JSON-RPC 2.0 error codes.
43
99
  const PARSE_ERROR = -32700;
44
100
  const INVALID_REQUEST = -32600;
@@ -93,6 +149,32 @@ function okResponse(id, result) {
93
149
  function asString(v) {
94
150
  return typeof v === 'string' ? v : null;
95
151
  }
152
+ /** Extract the {@link REASON} carried by a `CatalogError`, if any (see `mcp-catalog.cts`). */
153
+ function catalogErrorReason(err) {
154
+ const reason = err && typeof err === 'object' ? err.reason : undefined;
155
+ return typeof reason === 'string' ? reason : undefined;
156
+ }
157
+ function catalogErrorMessage(err) {
158
+ return err instanceof Error ? err.message : String(err);
159
+ }
160
+ /**
161
+ * Map a `mcp-catalog.cts` `CatalogError.reason` to a JSON-RPC error code.
162
+ * `READ_FAILED` is a server-side IO/compose failure (`INTERNAL_ERROR`);
163
+ * every other reason (unknown uri/prompt/cursor/root, malformed/traversal
164
+ * uri, wrong-typed param) is a client-supplied-value problem (`INVALID_PARAMS`)
165
+ * — deliberately never `METHOD_NOT_FOUND`, so a refusal is never
166
+ * indistinguishable from the method simply not existing (test-matrix rows
167
+ * 33/35).
168
+ */
169
+ function catalogErrorCode(err) {
170
+ return catalogErrorReason(err) === mcp_catalog_cjs_1.REASON.READ_FAILED ? INTERNAL_ERROR : INVALID_PARAMS;
171
+ }
172
+ function wireResource(entry) {
173
+ return { uri: entry.uri, name: entry.name, title: entry.title, description: entry.description, mimeType: entry.mimeType };
174
+ }
175
+ function wirePrompt(entry) {
176
+ return { name: entry.name, title: entry.title, description: entry.description };
177
+ }
96
178
  function callTool(name, args, ctx) {
97
179
  const a = (args && typeof args === 'object' ? args : {});
98
180
  const cwd = asString(ctx.cwd) || process.cwd();
@@ -148,8 +230,12 @@ function handleMessage(request, ctx = {}) {
148
230
  case 'initialize':
149
231
  result = {
150
232
  protocolVersion: exports.PROTOCOL_VERSION,
151
- capabilities: { tools: {} },
152
- serverInfo: { name: exports.SERVER_NAME, version: SERVER_VERSION },
233
+ // #3072: resources/prompts declared alongside tools. Deliberately NO
234
+ // subscribe/listChanged — nothing ever sends those notifications
235
+ // (design row 2 / Hyrum's Law: advertising an unimplemented
236
+ // notification is a lie a host would act on).
237
+ capabilities: { tools: {}, resources: {}, prompts: {} },
238
+ serverInfo: { name: exports.SERVER_NAME, version: resolveServerVersion() },
153
239
  };
154
240
  break;
155
241
  case 'tools/list':
@@ -163,6 +249,52 @@ function handleMessage(request, ctx = {}) {
163
249
  result = callTool(toolName, params.arguments, ctx);
164
250
  break;
165
251
  }
252
+ case 'resources/list': {
253
+ const params = (request.params && typeof request.params === 'object' ? request.params : {});
254
+ try {
255
+ const cursor = typeof params.cursor === 'string' ? params.cursor : undefined;
256
+ const pageSize = typeof params.pageSize === 'number' ? params.pageSize : undefined;
257
+ const page = (0, mcp_catalog_cjs_1.listResources)(getCatalog(), { cursor, pageSize });
258
+ result = page.nextCursor === undefined
259
+ ? { resources: page.resources.map(wireResource) }
260
+ : { resources: page.resources.map(wireResource), nextCursor: page.nextCursor };
261
+ }
262
+ catch (e) {
263
+ return errorResponse(id, catalogErrorCode(e), catalogErrorMessage(e));
264
+ }
265
+ break;
266
+ }
267
+ case 'resources/read': {
268
+ const params = (request.params && typeof request.params === 'object' ? request.params : {});
269
+ try {
270
+ const read = (0, mcp_catalog_cjs_1.readResource)(getCatalog(), params.uri);
271
+ result = { contents: [{ uri: read.uri, mimeType: read.mimeType, text: read.text }] };
272
+ }
273
+ catch (e) {
274
+ return errorResponse(id, catalogErrorCode(e), catalogErrorMessage(e));
275
+ }
276
+ break;
277
+ }
278
+ case 'prompts/list':
279
+ result = {
280
+ prompts: [...getCatalog().prompts.values()]
281
+ .map(wirePrompt)
282
+ .sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0)),
283
+ };
284
+ break;
285
+ case 'prompts/get': {
286
+ const params = (request.params && typeof request.params === 'object' ? request.params : {});
287
+ const name = asString(params.name);
288
+ if (!name)
289
+ return errorResponse(id, INVALID_PARAMS, 'prompts/get requires string "name".');
290
+ try {
291
+ result = (0, mcp_catalog_cjs_1.getPrompt)(getCatalog(), name, params.arguments);
292
+ }
293
+ catch (e) {
294
+ return errorResponse(id, catalogErrorCode(e), catalogErrorMessage(e));
295
+ }
296
+ break;
297
+ }
166
298
  default:
167
299
  if (isNotification)
168
300
  return null;
@@ -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
+ }