gsd-pi 2.81.0 → 2.82.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 (290) hide show
  1. package/README.md +36 -24
  2. package/dist/resources/.managed-resources-content-hash +1 -1
  3. package/dist/resources/extensions/gsd/auto/loop.js +111 -8
  4. package/dist/resources/extensions/gsd/auto/phases.js +190 -97
  5. package/dist/resources/extensions/gsd/auto/run-unit.js +66 -3
  6. package/dist/resources/extensions/gsd/auto/session.js +9 -0
  7. package/dist/resources/extensions/gsd/auto/verification-retry-policy.js +43 -0
  8. package/dist/resources/extensions/gsd/auto-dashboard.js +182 -178
  9. package/dist/resources/extensions/gsd/auto-dispatch.js +14 -11
  10. package/dist/resources/extensions/gsd/auto-post-unit.js +7 -1
  11. package/dist/resources/extensions/gsd/auto-recovery.js +6 -181
  12. package/dist/resources/extensions/gsd/auto-runtime-state.js +5 -0
  13. package/dist/resources/extensions/gsd/auto-start.js +20 -23
  14. package/dist/resources/extensions/gsd/auto-unit-closeout.js +33 -5
  15. package/dist/resources/extensions/gsd/auto-verification.js +12 -6
  16. package/dist/resources/extensions/gsd/auto-worktree.js +8 -0
  17. package/dist/resources/extensions/gsd/auto.js +265 -76
  18. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +13 -6
  19. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +8 -2
  20. package/dist/resources/extensions/gsd/bootstrap/register-shortcuts.js +4 -8
  21. package/dist/resources/extensions/gsd/commands/handlers/notifications-handler.js +4 -10
  22. package/dist/resources/extensions/gsd/commands/handlers/parallel.js +9 -0
  23. package/dist/resources/extensions/gsd/git-service.js +2 -1
  24. package/dist/resources/extensions/gsd/gsd-db.js +7 -23
  25. package/dist/resources/extensions/gsd/health-widget-core.js +1 -1
  26. package/dist/resources/extensions/gsd/health-widget.js +4 -10
  27. package/dist/resources/extensions/gsd/markdown-renderer.js +0 -95
  28. package/dist/resources/extensions/gsd/native-git-bridge.js +14 -14
  29. package/dist/resources/extensions/gsd/notification-overlay.js +35 -40
  30. package/dist/resources/extensions/gsd/parallel-merge.js +53 -30
  31. package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +25 -33
  32. package/dist/resources/extensions/gsd/prompts/complete-slice.md +14 -12
  33. package/dist/resources/extensions/gsd/prompts/discuss-headless.md +20 -2
  34. package/dist/resources/extensions/gsd/prompts/discuss.md +20 -2
  35. package/dist/resources/extensions/gsd/recovery-classification.js +15 -1
  36. package/dist/resources/extensions/gsd/session-lock.js +40 -0
  37. package/dist/resources/extensions/gsd/state-reconciliation/drift/completion.js +131 -0
  38. package/dist/resources/extensions/gsd/state-reconciliation/drift/merge-state.js +247 -0
  39. package/dist/resources/extensions/gsd/state-reconciliation/drift/project-md.js +50 -0
  40. package/dist/resources/extensions/gsd/state-reconciliation/drift/roadmap.js +87 -0
  41. package/dist/resources/extensions/gsd/state-reconciliation/drift/sketch-flag.js +50 -0
  42. package/dist/resources/extensions/gsd/state-reconciliation/drift/stale-render.js +124 -0
  43. package/dist/resources/extensions/gsd/state-reconciliation/drift/stale-worker.js +32 -0
  44. package/dist/resources/extensions/gsd/state-reconciliation/errors.js +41 -0
  45. package/dist/resources/extensions/gsd/state-reconciliation/index.js +99 -0
  46. package/dist/resources/extensions/gsd/state-reconciliation/registry.js +24 -0
  47. package/dist/resources/extensions/gsd/state-reconciliation/spawn-gate.js +43 -0
  48. package/dist/resources/extensions/gsd/state-reconciliation/types.js +3 -0
  49. package/dist/resources/extensions/gsd/state-reconciliation.js +5 -26
  50. package/dist/resources/extensions/gsd/tui/render-kit.js +74 -0
  51. package/dist/resources/extensions/gsd/watch/header-renderer.js +92 -69
  52. package/dist/resources/extensions/gsd/watch/splash-palette.js +10 -0
  53. package/dist/resources/extensions/gsd/workflow-mcp.js +2 -2
  54. package/dist/resources/extensions/gsd/worktree-lifecycle.js +722 -316
  55. package/dist/resources/extensions/gsd/worktree-telemetry.js +3 -1
  56. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  57. package/dist/web/standalone/.next/BUILD_ID +1 -1
  58. package/dist/web/standalone/.next/app-path-routes-manifest.json +9 -9
  59. package/dist/web/standalone/.next/build-manifest.json +2 -2
  60. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  61. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  62. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  63. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  64. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  65. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  66. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  67. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  68. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  69. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  70. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  71. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  72. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  73. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  74. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  75. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  76. package/dist/web/standalone/.next/server/app/index.html +1 -1
  77. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  78. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  79. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  80. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  81. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  82. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  83. package/dist/web/standalone/.next/server/app-paths-manifest.json +9 -9
  84. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  85. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  86. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  87. package/dist/welcome-screen.d.ts +0 -7
  88. package/dist/welcome-screen.js +60 -69
  89. package/package.json +1 -1
  90. package/packages/daemon/package.json +2 -2
  91. package/packages/mcp-server/package.json +2 -2
  92. package/packages/native/package.json +1 -1
  93. package/packages/pi-agent-core/package.json +1 -1
  94. package/packages/pi-ai/package.json +1 -1
  95. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.d.ts +2 -0
  96. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.d.ts.map +1 -0
  97. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.js +47 -0
  98. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.js.map +1 -0
  99. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +76 -9
  100. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -1
  101. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.d.ts +2 -0
  102. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.d.ts.map +1 -0
  103. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.js +40 -0
  104. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.js.map +1 -0
  105. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.d.ts +0 -1
  106. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.d.ts.map +1 -1
  107. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.js +30 -29
  108. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.js.map +1 -1
  109. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.js +10 -3
  110. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.js.map +1 -1
  111. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  112. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js +13 -13
  113. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
  114. package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.d.ts +1 -3
  115. package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  116. package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.js +58 -3
  117. package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.js.map +1 -1
  118. package/packages/pi-coding-agent/dist/modes/interactive/components/diff.d.ts +2 -2
  119. package/packages/pi-coding-agent/dist/modes/interactive/components/diff.d.ts.map +1 -1
  120. package/packages/pi-coding-agent/dist/modes/interactive/components/diff.js +12 -6
  121. package/packages/pi-coding-agent/dist/modes/interactive/components/diff.js.map +1 -1
  122. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
  123. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +14 -41
  124. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
  125. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +0 -1
  126. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  127. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +86 -82
  128. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  129. package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.d.ts +35 -0
  130. package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.d.ts.map +1 -0
  131. package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.js +152 -0
  132. package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.js.map +1 -0
  133. package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.d.ts +16 -0
  134. package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.d.ts.map +1 -0
  135. package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.js +73 -0
  136. package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.js.map +1 -0
  137. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts +1 -1
  138. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  139. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js +12 -8
  140. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js.map +1 -1
  141. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.d.ts +2 -0
  142. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.d.ts.map +1 -0
  143. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.js +17 -0
  144. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.js.map +1 -0
  145. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  146. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js +105 -1
  147. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js.map +1 -1
  148. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.d.ts.map +1 -1
  149. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js +27 -26
  150. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js.map +1 -1
  151. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.js +9 -6
  152. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.js.map +1 -1
  153. package/packages/pi-coding-agent/package.json +1 -1
  154. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/assistant-message-design.test.ts +56 -0
  155. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +113 -9
  156. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/user-message-design.test.ts +48 -0
  157. package/packages/pi-coding-agent/src/modes/interactive/components/adaptive-layout.test.ts +10 -3
  158. package/packages/pi-coding-agent/src/modes/interactive/components/adaptive-layout.ts +43 -42
  159. package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +14 -14
  160. package/packages/pi-coding-agent/src/modes/interactive/components/bash-execution.ts +64 -3
  161. package/packages/pi-coding-agent/src/modes/interactive/components/diff.ts +13 -7
  162. package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +15 -42
  163. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +84 -104
  164. package/packages/pi-coding-agent/src/modes/interactive/components/transcript-design.ts +196 -0
  165. package/packages/pi-coding-agent/src/modes/interactive/components/tui-style-kit.ts +94 -0
  166. package/packages/pi-coding-agent/src/modes/interactive/components/user-message.ts +14 -9
  167. package/packages/pi-coding-agent/src/modes/interactive/theme/theme-highlight.test.ts +23 -0
  168. package/packages/pi-coding-agent/src/modes/interactive/theme/theme.ts +106 -1
  169. package/packages/pi-coding-agent/src/modes/interactive/theme/themes.ts +27 -26
  170. package/packages/pi-coding-agent/src/modes/interactive/tui-mode.test.ts +9 -6
  171. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  172. package/packages/pi-tui/dist/__tests__/overlay-layout.test.js +14 -1
  173. package/packages/pi-tui/dist/__tests__/overlay-layout.test.js.map +1 -1
  174. package/packages/pi-tui/dist/overlay-layout.d.ts.map +1 -1
  175. package/packages/pi-tui/dist/overlay-layout.js +9 -6
  176. package/packages/pi-tui/dist/overlay-layout.js.map +1 -1
  177. package/packages/pi-tui/package.json +1 -1
  178. package/packages/pi-tui/src/__tests__/overlay-layout.test.ts +20 -1
  179. package/packages/pi-tui/src/overlay-layout.ts +10 -7
  180. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  181. package/packages/rpc-client/package.json +1 -1
  182. package/pkg/dist/modes/interactive/theme/theme-highlight.test.d.ts +2 -0
  183. package/pkg/dist/modes/interactive/theme/theme-highlight.test.d.ts.map +1 -0
  184. package/pkg/dist/modes/interactive/theme/theme-highlight.test.js +17 -0
  185. package/pkg/dist/modes/interactive/theme/theme-highlight.test.js.map +1 -0
  186. package/pkg/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  187. package/pkg/dist/modes/interactive/theme/theme.js +105 -1
  188. package/pkg/dist/modes/interactive/theme/theme.js.map +1 -1
  189. package/pkg/dist/modes/interactive/theme/themes.d.ts.map +1 -1
  190. package/pkg/dist/modes/interactive/theme/themes.js +27 -26
  191. package/pkg/dist/modes/interactive/theme/themes.js.map +1 -1
  192. package/pkg/package.json +1 -1
  193. package/src/resources/extensions/gsd/auto/loop-deps.ts +9 -5
  194. package/src/resources/extensions/gsd/auto/loop.ts +113 -9
  195. package/src/resources/extensions/gsd/auto/phases.ts +144 -19
  196. package/src/resources/extensions/gsd/auto/run-unit.ts +69 -4
  197. package/src/resources/extensions/gsd/auto/session.ts +10 -0
  198. package/src/resources/extensions/gsd/auto/verification-retry-policy.ts +82 -0
  199. package/src/resources/extensions/gsd/auto-dashboard.ts +230 -183
  200. package/src/resources/extensions/gsd/auto-dispatch.ts +15 -1
  201. package/src/resources/extensions/gsd/auto-post-unit.ts +7 -1
  202. package/src/resources/extensions/gsd/auto-recovery.ts +7 -209
  203. package/src/resources/extensions/gsd/auto-runtime-state.ts +5 -0
  204. package/src/resources/extensions/gsd/auto-start.ts +22 -22
  205. package/src/resources/extensions/gsd/auto-unit-closeout.ts +51 -0
  206. package/src/resources/extensions/gsd/auto-verification.ts +12 -6
  207. package/src/resources/extensions/gsd/auto-worktree.ts +8 -0
  208. package/src/resources/extensions/gsd/auto.ts +295 -75
  209. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +21 -6
  210. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +6 -2
  211. package/src/resources/extensions/gsd/bootstrap/register-shortcuts.ts +5 -8
  212. package/src/resources/extensions/gsd/commands/handlers/notifications-handler.ts +4 -10
  213. package/src/resources/extensions/gsd/commands/handlers/parallel.ts +12 -0
  214. package/src/resources/extensions/gsd/git-service.ts +2 -0
  215. package/src/resources/extensions/gsd/gsd-db.ts +7 -23
  216. package/src/resources/extensions/gsd/health-widget-core.ts +1 -1
  217. package/src/resources/extensions/gsd/health-widget.ts +6 -10
  218. package/src/resources/extensions/gsd/journal.ts +2 -0
  219. package/src/resources/extensions/gsd/markdown-renderer.ts +4 -95
  220. package/src/resources/extensions/gsd/native-git-bridge.ts +14 -13
  221. package/src/resources/extensions/gsd/notification-overlay.ts +50 -46
  222. package/src/resources/extensions/gsd/parallel-merge.ts +61 -34
  223. package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +33 -35
  224. package/src/resources/extensions/gsd/prompts/complete-slice.md +14 -12
  225. package/src/resources/extensions/gsd/prompts/discuss-headless.md +20 -2
  226. package/src/resources/extensions/gsd/prompts/discuss.md +20 -2
  227. package/src/resources/extensions/gsd/recovery-classification.ts +18 -1
  228. package/src/resources/extensions/gsd/session-lock.ts +41 -0
  229. package/src/resources/extensions/gsd/state-reconciliation/drift/completion.ts +172 -0
  230. package/src/resources/extensions/gsd/state-reconciliation/drift/merge-state.ts +337 -0
  231. package/src/resources/extensions/gsd/state-reconciliation/drift/project-md.ts +69 -0
  232. package/src/resources/extensions/gsd/state-reconciliation/drift/roadmap.ts +109 -0
  233. package/src/resources/extensions/gsd/state-reconciliation/drift/sketch-flag.ts +68 -0
  234. package/src/resources/extensions/gsd/state-reconciliation/drift/stale-render.ts +185 -0
  235. package/src/resources/extensions/gsd/state-reconciliation/drift/stale-worker.ts +46 -0
  236. package/src/resources/extensions/gsd/state-reconciliation/errors.ts +67 -0
  237. package/src/resources/extensions/gsd/state-reconciliation/index.ts +142 -0
  238. package/src/resources/extensions/gsd/state-reconciliation/registry.ts +27 -0
  239. package/src/resources/extensions/gsd/state-reconciliation/spawn-gate.ts +60 -0
  240. package/src/resources/extensions/gsd/state-reconciliation/types.ts +83 -0
  241. package/src/resources/extensions/gsd/state-reconciliation.ts +21 -53
  242. package/src/resources/extensions/gsd/tests/artifact-retry-cap.test.ts +1 -1
  243. package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +99 -0
  244. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +654 -176
  245. package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +291 -4
  246. package/src/resources/extensions/gsd/tests/auto-runtime-state.test.ts +16 -1
  247. package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +18 -0
  248. package/src/resources/extensions/gsd/tests/auto-unit-closeout.test.ts +68 -0
  249. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +28 -1
  250. package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +20 -2
  251. package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +44 -0
  252. package/src/resources/extensions/gsd/tests/header-renderer.test.ts +40 -0
  253. package/src/resources/extensions/gsd/tests/headless-milestone-parity.test.ts +10 -0
  254. package/src/resources/extensions/gsd/tests/health-widget.test.ts +14 -4
  255. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +26 -0
  256. package/src/resources/extensions/gsd/tests/integration/integration-proof.test.ts +1 -1
  257. package/src/resources/extensions/gsd/tests/integration/parallel-merge.test.ts +116 -24
  258. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +0 -1
  259. package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +1 -1
  260. package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +46 -11
  261. package/src/resources/extensions/gsd/tests/notification-overlay.test.ts +78 -41
  262. package/src/resources/extensions/gsd/tests/notifications-handler.test.ts +44 -0
  263. package/src/resources/extensions/gsd/tests/originalbase-path-comparison.test.ts +12 -217
  264. package/src/resources/extensions/gsd/tests/parallel-monitor-overlay.test.ts +38 -6
  265. package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +2 -2
  266. package/src/resources/extensions/gsd/tests/progressive-planning.test.ts +1 -1
  267. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +24 -1
  268. package/src/resources/extensions/gsd/tests/resume-dispatch-worktree.test.ts +7 -3
  269. package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +6 -3
  270. package/src/resources/extensions/gsd/tests/session-switch-abort-misclassification.test.ts +24 -0
  271. package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +65 -58
  272. package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +952 -0
  273. package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +4 -0
  274. package/src/resources/extensions/gsd/tests/tui-header-lifecycle.test.ts +121 -1
  275. package/src/resources/extensions/gsd/tests/tui-render-kit.test.ts +66 -0
  276. package/src/resources/extensions/gsd/tests/verification-retry-policy.test.ts +83 -0
  277. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +6 -0
  278. package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +158 -58
  279. package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +572 -118
  280. package/src/resources/extensions/gsd/tests/worktree-telemetry.test.ts +59 -2
  281. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +18 -0
  282. package/src/resources/extensions/gsd/tui/render-kit.ts +109 -0
  283. package/src/resources/extensions/gsd/watch/header-renderer.ts +121 -79
  284. package/src/resources/extensions/gsd/watch/splash-palette.ts +11 -0
  285. package/src/resources/extensions/gsd/workflow-mcp.ts +2 -2
  286. package/src/resources/extensions/gsd/worktree-lifecycle.ts +1151 -524
  287. package/src/resources/extensions/gsd/worktree-telemetry.ts +7 -2
  288. package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +0 -1544
  289. /package/dist/web/standalone/.next/static/{drLMkgfHQ8lzS229_HWYR → S44UQTFCUdA44dkjfYt6S}/_buildManifest.js +0 -0
  290. /package/dist/web/standalone/.next/static/{drLMkgfHQ8lzS229_HWYR → S44UQTFCUdA44dkjfYt6S}/_ssgManifest.js +0 -0
@@ -8,9 +8,13 @@
8
8
  import { existsSync, readdirSync } from "node:fs";
9
9
  import { join } from "node:path";
10
10
  import { spawnSync } from "node:child_process";
11
- import { loadFile } from "./files.js";
12
- import { resolveGsdPathContract, resolveMilestoneFile } from "./paths.js";
13
- import { mergeMilestoneToMain } from "./auto-worktree.js";
11
+ import { resolveGsdPathContract } from "./paths.js";
12
+ import { getAutoWorktreePath } from "./auto-worktree.js";
13
+ import { buildWorktreeLifecycleDeps } from "./auto.js";
14
+ import {
15
+ mergeMilestoneStandalone,
16
+ type MergeStandaloneResult,
17
+ } from "./worktree-lifecycle.js";
14
18
  import { MergeConflictError } from "./git-service.js";
15
19
  import { removeSessionStatus } from "./session-status-io.js";
16
20
  import type { WorkerInfo } from "./parallel-orchestrator.js";
@@ -136,44 +140,46 @@ export function determineMergeOrder(
136
140
 
137
141
  /**
138
142
  * Attempt to merge a single milestone's worktree back to main.
139
- * Wraps mergeMilestoneToMain with error handling for parallel context.
143
+ *
144
+ * Routes through `WorktreeLifecycle.mergeMilestoneStandalone` so parallel
145
+ * callers get the same projection-finalize / roadmap-fallback / secondary-
146
+ * teardown invariants as the single-loop path. Closes the parallel-merge
147
+ * bypass that ADR-016 names (issue #5618).
140
148
  */
141
149
  export async function mergeCompletedMilestone(
142
150
  basePath: string,
143
151
  milestoneId: string,
144
152
  ): Promise<MergeResult> {
145
- try {
146
- // Load the roadmap content (needed by mergeMilestoneToMain)
147
- const roadmapPath = resolveMilestoneFile(basePath, milestoneId, "ROADMAP");
148
- if (!roadmapPath) {
149
- return {
150
- milestoneId,
151
- success: false,
152
- error: `No roadmap found for ${milestoneId}`,
153
- };
154
- }
155
-
156
- const roadmapContent = await loadFile(roadmapPath);
157
- if (!roadmapContent) {
158
- return {
159
- milestoneId,
160
- success: false,
161
- error: `Could not read roadmap for ${milestoneId}`,
162
- };
163
- }
153
+ // Resolve the worktree path explicitly; parallel-merge has no AutoSession
154
+ // to read it from. Only use the worktree path when git actually knows
155
+ // about it (`getAutoWorktreePath` returns non-null). When the directory
156
+ // exists on disk but isn't a registered git worktree (e.g. a stale
157
+ // session-status marker dir), fall back to the project root and let the
158
+ // standalone's mode detection pick branch-mode or skipped — using the
159
+ // un-registered dir as `worktreeBasePath` would cause `getCurrentBranch`
160
+ // to fail with a "Worktree HEAD diverged" error.
161
+ const registeredWtPath = getAutoWorktreePath(basePath, milestoneId);
162
+ const worktreeBasePath = registeredWtPath ?? basePath;
164
163
 
165
- // Attempt the merge
166
- const result = mergeMilestoneToMain(basePath, milestoneId, roadmapContent);
167
-
168
- // Clean up parallel session status
169
- removeSessionStatus(basePath, milestoneId);
170
-
171
- return {
164
+ let result: MergeStandaloneResult;
165
+ try {
166
+ result = mergeMilestoneStandalone(buildWorktreeLifecycleDeps(), {
167
+ originalBasePath: basePath,
168
+ worktreeBasePath,
172
169
  milestoneId,
173
- success: true,
174
- commitMessage: result.commitMessage,
175
- pushed: result.pushed,
176
- };
170
+ // Parallel context never runs with degraded isolation — workers only
171
+ // exist when isolation succeeded. Pass `false` explicitly so the
172
+ // standalone's degraded-skip branch is not reached.
173
+ isolationDegraded: false,
174
+ notify: (msg, level) => {
175
+ // Surface user-visible messages from the standalone through the
176
+ // workflow logger so the parallel merge's progress is visible in
177
+ // the same channel as the rest of the parallel orchestration.
178
+ if (level === "error" || level === "warning") {
179
+ logWarning("parallel", `${milestoneId}: ${msg}`);
180
+ }
181
+ },
182
+ });
177
183
  } catch (err) {
178
184
  if (err instanceof MergeConflictError) {
179
185
  return {
@@ -189,6 +195,27 @@ export async function mergeCompletedMilestone(
189
195
  error: getErrorMessage(err),
190
196
  };
191
197
  }
198
+
199
+ if (!result.merged) {
200
+ return {
201
+ milestoneId,
202
+ success: false,
203
+ error:
204
+ result.mode === "skipped"
205
+ ? `Merge skipped for ${milestoneId} (mode=none or isolation degraded).`
206
+ : `No roadmap for ${milestoneId} — milestone branch preserved for manual merge.`,
207
+ };
208
+ }
209
+
210
+ // Clean up parallel session status — only on a real merge.
211
+ removeSessionStatus(basePath, milestoneId);
212
+
213
+ return {
214
+ milestoneId,
215
+ success: true,
216
+ commitMessage: result.commitMessage,
217
+ pushed: result.pushed,
218
+ };
192
219
  }
193
220
 
194
221
  /**
@@ -1,23 +1,23 @@
1
- /**
2
- * GSD Parallel Monitor Overlay
3
- *
4
- * Full-screen TUI overlay showing real-time parallel worker progress.
5
- * Opened via `/gsd parallel watch`, Ctrl+Alt+P (⌃⌥P on macOS),
6
- * or Ctrl+Shift+P fallback.
7
- * Reads the same data sources as `scripts/parallel-monitor.mjs` but
8
- * renders as a native pi-tui overlay with theme integration.
9
- */
1
+ // Project/App: GSD-2
2
+ // File Purpose: Parallel worker monitor overlay with width-safe operations-console rendering.
10
3
 
11
4
  import { existsSync, statSync, readFileSync, openSync, readSync, closeSync, readdirSync } from "node:fs";
12
5
  import { join } from "node:path";
13
6
  import { spawnSync } from "node:child_process";
14
7
 
15
8
  import type { Theme } from "@gsd/pi-coding-agent";
16
- import { truncateToWidth, visibleWidth, matchesKey, Key } from "@gsd/pi-tui";
9
+ import { matchesKey, Key } from "@gsd/pi-tui";
17
10
 
18
- import { formatDuration, STATUS_GLYPH, STATUS_COLOR } from "../shared/mod.js";
11
+ import { formatDuration } from "../shared/mod.js";
19
12
  import { formattedShortcutPair } from "./shortcut-defs.js";
20
13
  import { resolveGsdPathContract } from "./paths.js";
14
+ import {
15
+ renderBar,
16
+ renderKeyHints,
17
+ renderProgressBar,
18
+ safeLine,
19
+ statusGlyph,
20
+ } from "./tui/render-kit.js";
21
21
 
22
22
  // ─── Types ────────────────────────────────────────────────────────────────
23
23
 
@@ -277,17 +277,6 @@ function unitTypeLabel(unitType: string | null): string {
277
277
  return labels[unitType || ""] || (unitType || "---").toUpperCase().slice(0, 5);
278
278
  }
279
279
 
280
- function progressBar(done: number, total: number, width: number): string {
281
- if (total === 0) return "░".repeat(width);
282
- const filled = Math.round((done / total) * width);
283
- return "█".repeat(filled) + "░".repeat(width - filled);
284
- }
285
-
286
- function healthGlyph(alive: boolean, heartbeatAge: number): string {
287
- if (!alive) return "○";
288
- return "●";
289
- }
290
-
291
280
  // ─── Overlay Class ────────────────────────────────────────────────────────
292
281
 
293
282
  export class ParallelMonitorOverlay {
@@ -299,6 +288,7 @@ export class ParallelMonitorOverlay {
299
288
  private workers: WorkerView[] = [];
300
289
  private events: string[] = [];
301
290
  private cachedLines?: string[];
291
+ private cachedWidth?: number;
302
292
  private scrollOffset = 0;
303
293
  private disposed = false;
304
294
  private resizeHandler: (() => void) | null = null;
@@ -339,6 +329,7 @@ export class ParallelMonitorOverlay {
339
329
  this.events = this.events.slice(-10);
340
330
 
341
331
  this.cachedLines = undefined;
332
+ this.cachedWidth = undefined;
342
333
  this.tui.requestRender();
343
334
  }
344
335
 
@@ -378,14 +369,15 @@ export class ParallelMonitorOverlay {
378
369
 
379
370
  invalidate(): void {
380
371
  this.cachedLines = undefined;
372
+ this.cachedWidth = undefined;
381
373
  }
382
374
 
383
375
  render(width: number): string[] {
384
- if (this.cachedLines) return this.cachedLines;
376
+ if (this.cachedLines && this.cachedWidth === width) return this.cachedLines;
385
377
 
386
378
  const t = this.theme;
387
379
  const lines: string[] = [];
388
- const w = Math.max(width, 60);
380
+ const w = Math.max(1, width);
389
381
 
390
382
  // Header
391
383
  const totalCost = this.workers.reduce((s, wk) => s + wk.cost, 0);
@@ -398,7 +390,7 @@ export class ParallelMonitorOverlay {
398
390
  t.bold(`$${totalCost.toFixed(2)}`) +
399
391
  t.fg("muted", " │ 5s refresh"),
400
392
  );
401
- lines.push(t.fg("muted", "─".repeat(w)));
393
+ lines.push(renderBar(t, w));
402
394
 
403
395
  if (this.workers.length === 0) {
404
396
  lines.push("");
@@ -410,7 +402,7 @@ export class ParallelMonitorOverlay {
410
402
 
411
403
  // Health + ID + state
412
404
  const healthColor = wk.alive ? "success" : "error";
413
- const glyph = healthGlyph(wk.alive, wk.heartbeatAge);
405
+ const glyph = statusGlyph(t, wk.alive ? "active" : "idle");
414
406
  const stateText = wk.alive
415
407
  ? t.fg("success", "RUNNING")
416
408
  : t.fg("error", t.bold("DEAD"));
@@ -452,25 +444,29 @@ export class ParallelMonitorOverlay {
452
444
  lines.push(` ${t.fg("muted", "slices")} ${chips.join(" ")}`);
453
445
 
454
446
  // Task progress bar
455
- const bar = progressBar(wk.doneTasks, wk.totalTasks, 25);
447
+ const barWidth = Math.max(6, Math.min(25, w - 32));
448
+ const bar = renderProgressBar(t, wk.doneTasks, wk.totalTasks, barWidth, {
449
+ filledChar: "█",
450
+ emptyChar: "░",
451
+ emptyColor: "dim",
452
+ });
456
453
  const pct = wk.totalTasks > 0 ? Math.round((wk.doneTasks / wk.totalTasks) * 100) : 0;
457
454
  lines.push(
458
- ` ${t.fg("muted", "tasks")} ${t.fg("success", bar)} ${wk.doneTasks}/${wk.totalTasks} ` +
455
+ ` ${t.fg("muted", "tasks")} ${bar} ${wk.doneTasks}/${wk.totalTasks} ` +
459
456
  t.fg("muted", `(${pct}%) │ slices done ${wk.doneSlices}/${wk.totalSlices}`),
460
457
  );
461
458
  }
462
459
 
463
460
  // Errors
464
461
  for (const err of wk.errors.slice(-2)) {
465
- const truncated = err.length > w - 10 ? err.slice(0, w - 11) + "…" : err;
466
- lines.push(` ${t.fg("error", "⚠ " + truncated)}`);
462
+ lines.push(` ${t.fg("error", "! " + err)}`);
467
463
  }
468
464
  }
469
465
  }
470
466
 
471
467
  // Event feed
472
468
  lines.push("");
473
- lines.push(t.fg("muted", "─".repeat(w)));
469
+ lines.push(renderBar(t, w));
474
470
  lines.push(` ${t.bold("Recent Events")}`);
475
471
 
476
472
  if (this.events.length === 0) {
@@ -478,8 +474,7 @@ export class ParallelMonitorOverlay {
478
474
  } else {
479
475
  for (const evt of this.events.slice(-8)) {
480
476
  const mid = evt.match(/^✓ (M\d+)\//)?.[1] || "";
481
- const truncated = evt.length > w - 10 ? evt.slice(0, w - 11) + "" : evt;
482
- lines.push(` ${t.fg("muted", "│")} ${t.fg("accent", mid)} ${truncated.replace(/^✓ M\d+\//, "")}`);
477
+ lines.push(` ${t.fg("muted", "│")} ${t.fg("accent", mid)} ${evt.replace(/^✓ M\d+\//, "")}`);
483
478
  }
484
479
  }
485
480
 
@@ -496,14 +491,17 @@ export class ParallelMonitorOverlay {
496
491
  }
497
492
  lines.push(` ${t.bold("Total: $" + this.workers.reduce((s, wk) => s + wk.cost, 0).toFixed(2))}`);
498
493
  }
499
- lines.push(t.fg("muted", ` ESC/q/${formattedShortcutPair("parallel")} close↑↓ scroll`));
494
+ lines.push(renderKeyHints(t, [`ESC/q/${formattedShortcutPair("parallel")} close`, "↑↓ scroll"], w));
500
495
 
501
496
  // Apply scroll — use terminal rows as height estimate
502
497
  const termHeight = process.stdout.rows || 40;
503
498
  const maxScroll = Math.max(0, lines.length - termHeight);
504
499
  this.scrollOffset = Math.min(Math.max(this.scrollOffset, 0), maxScroll);
505
- const visible = lines.slice(this.scrollOffset, this.scrollOffset + termHeight);
500
+ const visible = lines
501
+ .slice(this.scrollOffset, this.scrollOffset + termHeight)
502
+ .map((line) => safeLine(line, w));
506
503
  this.cachedLines = visible;
504
+ this.cachedWidth = width;
507
505
  return visible;
508
506
  }
509
507
  }
@@ -22,22 +22,24 @@ Use `subagent` only for fresh-context review when useful: reviewer for cross-cut
22
22
 
23
23
  1. Use the inlined Slice Summary and UAT templates.
24
24
  2. {{skillActivation}}
25
- 3. Run all slice-level verification checks from the slice plan. Fix failures before marking done; refresh current state if needed.
26
- 4. Task summaries use a flat file layout under `tasks/` such as `T01-SUMMARY.md`, not inside per-task subdirectories like `tasks/T01/SUMMARY.md`. Never use `tasks/*/SUMMARY.md`.
27
- 5. If observability/diagnostics were planned, verify them unless the slice is simple.
28
- 6. Address every gate in Gates to Close. Q8 maps to **Operational Readiness**: health signal, failure signal, recovery procedure, monitoring gaps. Empty sections are recorded as omitted.
29
- 7. If requirement status changed, call `gsd_requirement_update`; do not write `.gsd/REQUIREMENTS.md` directly.
30
- 8. Prepare `gsd_slice_complete` content with camelCase fields `milestoneId`, `sliceId`, `sliceTitle`, `oneLiner`, `narrative`, `verification`, and `uatContent`.
31
- 9. Draft concrete UAT with preconditions, numbered steps, expected outcomes, edge cases, UAT Type, and Not Proven By This UAT.
32
- 10. Review the inlined task-summary excerpts for DECISIONS.md and KNOWLEDGE.md-worthy decisions, patterns, and gotchas. Read full `*-SUMMARY.md` files only when an excerpt is absent, truncated, or lacks the specific evidence needed for the slice narrative. Capture significant items with `capture_thought`; do not append knowledge files directly.
33
- 11. Call `gsd_slice_complete`. The DB-backed tool is the canonical write path. Do **not** manually write `{{sliceSummaryPath}}`. Do **not** manually write `{{sliceUatPath}}`. Do not edit roadmap checkboxes; the tool renders files and updates projections.
34
- 12. Do not run git commands.
35
- 13. Update `.gsd/PROJECT.md` with a full `write` only if the current project state needs refresh.
25
+ 3. Run all slice-level verification checks from the slice plan through the closeout-safe verification surface (`gsd_exec` / Context Mode verification evidence); refresh current state if needed. Do not use direct `bash` for verification commands.
26
+ 4. Complete the slice only when every required verification check passes. If verification fails or the fix requires source changes, do **not** edit source files in this unit and do **not** call `gsd_slice_complete`.
27
+ 5. For task-specific failures, call `gsd_task_reopen` with the failing completed task and a concrete reason so execution can redo the work. For plan-invalidating failures, call `gsd_replan_slice` with the blocker and updated execution tasks. Then stop with: "Slice {{sliceId}} needs execution follow-up."
28
+ 6. Task summaries use a flat file layout under `tasks/` such as `T01-SUMMARY.md`, not inside per-task subdirectories like `tasks/T01/SUMMARY.md`. Never use `tasks/*/SUMMARY.md`.
29
+ 7. If observability/diagnostics were planned, verify them unless the slice is simple.
30
+ 8. Address every gate in Gates to Close. Q8 maps to **Operational Readiness**: health signal, failure signal, recovery procedure, monitoring gaps. Empty sections are recorded as omitted.
31
+ 9. If requirement status changed, call `gsd_requirement_update`; do not write `.gsd/REQUIREMENTS.md` directly.
32
+ 10. Prepare `gsd_slice_complete` content with camelCase fields `milestoneId`, `sliceId`, `sliceTitle`, `oneLiner`, `narrative`, `verification`, and `uatContent`.
33
+ 11. Draft concrete UAT with preconditions, numbered steps, expected outcomes, edge cases, UAT Type, and Not Proven By This UAT.
34
+ 12. Review the inlined task-summary excerpts for DECISIONS.md and KNOWLEDGE.md-worthy decisions, patterns, and gotchas. Read full `*-SUMMARY.md` files only when an excerpt is absent, truncated, or lacks the specific evidence needed for the slice narrative. Capture significant items with `capture_thought`; do not append knowledge files directly.
35
+ 13. When verification passes, call `gsd_slice_complete`. The DB-backed tool is the canonical write path. Do **not** manually write `{{sliceSummaryPath}}`. Do **not** manually write `{{sliceUatPath}}`. Do not edit roadmap checkboxes; the tool renders files and updates projections.
36
+ 14. Do not run git commands.
37
+ 15. Update `.gsd/PROJECT.md` with a full `write` only if the current project state needs refresh.
36
38
 
37
39
  **Autonomous execution:** no human is available. Do not call `ask_user_questions` or `secure_env_collect`; make reasonable assumptions and document them.
38
40
 
39
41
  **File system safety:** if re-reading task summaries, use `find .gsd/milestones/{{milestoneId}}/slices/{{sliceId}}/tasks -name "*-SUMMARY.md"` or `ls .gsd/milestones/{{milestoneId}}/slices/{{sliceId}}/tasks/*-SUMMARY.md`. Never pass `{{slicePath}}` or any directory path directly to the `read` tool.
40
42
 
41
- **You MUST call `gsd_slice_complete` with summary and UAT content before finishing.**
43
+ **You MUST call `gsd_slice_complete` with summary and UAT content before finishing only after verification passes.**
42
44
 
43
45
  When done, say: "Slice {{sliceId}} complete."
@@ -129,7 +129,16 @@ If ANY box is unchecked, **STOP**. Do NOT emit the ready phrase. Emit the missin
129
129
 
130
130
  Do not announce the ready phrase as something you are "about to" do. The ready phrase is a post-write signal, not an intent signal.
131
131
 
132
- After completing steps 1–7 above, say exactly: "Milestone {{milestoneId}} ready." — nothing else. Auto-mode will start automatically.
132
+ After completing steps 1–7 above, end with this concise user-facing handoff:
133
+
134
+ ```
135
+ Milestone {{milestoneId}} ready.
136
+
137
+ Next steps:
138
+ - Run `/gsd auto` to start execution if it does not begin automatically.
139
+ - Use `/gsd status` or `/gsd visualize` to inspect the roadmap.
140
+ - Use `/gsd notifications` to review or configure delivery alerts.
141
+ ```
133
142
 
134
143
  ### Multi-Milestone
135
144
 
@@ -215,7 +224,16 @@ If ANY box is unchecked, **STOP**. Do NOT emit the ready phrase. Emit the missin
215
224
 
216
225
  Do not announce the ready phrase as something you are "about to" do. The ready phrase is a post-write signal, not an intent signal.
217
226
 
218
- After completing every step above, say exactly: "Milestone {{milestoneId}} ready." — nothing else. Auto-mode will start automatically.
227
+ After completing every step above, end with this concise user-facing handoff:
228
+
229
+ ```
230
+ Milestone {{milestoneId}} ready.
231
+
232
+ Next steps:
233
+ - Run `/gsd auto` to start execution if it does not begin automatically.
234
+ - Use `/gsd status` or `/gsd visualize` to inspect the roadmap.
235
+ - Use `/gsd notifications` to review or configure delivery alerts.
236
+ ```
219
237
 
220
238
  ## Critical Rules
221
239
 
@@ -252,7 +252,16 @@ If ANY box is unchecked, **STOP**. Do NOT emit the ready phrase. Emit the missin
252
252
 
253
253
  Do not announce the ready phrase as something you are "about to" do. It is a post-write signal, not intent.
254
254
 
255
- After completing steps 1–7 above, say exactly: "Milestone {{milestoneId}} ready." — nothing else. Auto-mode will start automatically.
255
+ After completing steps 1–7 above, end with this concise user-facing handoff:
256
+
257
+ ```
258
+ Milestone {{milestoneId}} ready.
259
+
260
+ Next steps:
261
+ - Run `/gsd auto` to start execution if it does not begin automatically.
262
+ - Use `/gsd status` or `/gsd visualize` to inspect the roadmap.
263
+ - Use `/gsd notifications` to review or configure delivery alerts.
264
+ ```
256
265
 
257
266
  ### Multi-Milestone
258
267
 
@@ -345,6 +354,15 @@ If ANY box is unchecked, **STOP**. Do NOT emit the ready phrase. Emit the missin
345
354
 
346
355
  Do not announce the ready phrase as something you are "about to" do. It is a post-write signal, not intent.
347
356
 
348
- After completing all phases above, say exactly: "Milestone M001 ready." — nothing else. Auto-mode will start automatically.
357
+ After completing all phases above, end with this concise user-facing handoff:
358
+
359
+ ```
360
+ Milestone M001 ready.
361
+
362
+ Next steps:
363
+ - Run `/gsd auto` to start execution if it does not begin automatically.
364
+ - Use `/gsd status` or `/gsd visualize` to inspect the roadmap.
365
+ - Use `/gsd notifications` to review or configure delivery alerts.
366
+ ```
349
367
 
350
368
  {{inlinedTemplates}}
@@ -2,6 +2,7 @@
2
2
  // File Purpose: ADR-015 Recovery Classification module for runtime failure taxonomy.
3
3
 
4
4
  import { classifyError, isTransient, type ErrorClass } from "./error-classifier.js";
5
+ import { ReconciliationFailedError } from "./state-reconciliation.js";
5
6
 
6
7
  export type RecoveryFailureKind =
7
8
  | "tool-schema"
@@ -9,6 +10,7 @@ export type RecoveryFailureKind =
9
10
  | "stale-worker"
10
11
  | "worktree-invalid"
11
12
  | "verification-drift"
13
+ | "reconciliation-drift"
12
14
  | "provider"
13
15
  | "runtime-unknown";
14
16
 
@@ -33,7 +35,13 @@ export interface RecoveryClassification {
33
35
 
34
36
  export function classifyFailure(input: RecoveryClassificationInput): RecoveryClassification {
35
37
  const message = errorMessage(input.error);
36
- const failureKind = input.failureKind ?? inferFailureKind(message);
38
+ // ADR-017: ReconciliationFailedError is a typed throw from the State
39
+ // Reconciliation Module. Recognize it by class regardless of caller-supplied
40
+ // failureKind so the taxonomy stays consistent.
41
+ const failureKind =
42
+ input.error instanceof ReconciliationFailedError
43
+ ? "reconciliation-drift"
44
+ : input.failureKind ?? inferFailureKind(message);
37
45
 
38
46
  switch (failureKind) {
39
47
  case "tool-schema":
@@ -76,6 +84,15 @@ export function classifyFailure(input: RecoveryClassificationInput): RecoveryCla
76
84
  exitReason: "verification-drift",
77
85
  remediation: "Inspect the verification artifact and reconcile the state snapshot before resuming.",
78
86
  };
87
+ case "reconciliation-drift":
88
+ return {
89
+ failureKind,
90
+ action: "escalate",
91
+ reason: `Reconciliation drift${unitSuffix(input)}: ${message}`,
92
+ exitReason: "reconciliation-drift",
93
+ remediation:
94
+ "Inspect the persistent or repair-failed drift kinds reported by the State Reconciliation Module before resuming.",
95
+ };
79
96
  case "provider": {
80
97
  const providerClass = classifyError(message, input.retryAfterMs);
81
98
  return {
@@ -597,6 +597,47 @@ export function isSessionLockProcessAlive(data: SessionLockData): boolean {
597
597
  return isPidAlive(data.pid);
598
598
  }
599
599
 
600
+ /**
601
+ * ADR-017 raw primitive: remove orphaned lock artifacts (lock dir + lock file)
602
+ * when the recorded PID is dead or no metadata is present. Mirrors the
603
+ * pre-flight cleanup logic in acquireSessionLock so the stale-worker drift
604
+ * handler can clear the orphan proactively without going through the full
605
+ * acquire path. No-op when the lock is held by an alive process.
606
+ *
607
+ * Returns true when artifacts were removed (drift was present).
608
+ */
609
+ export function removeStaleSessionLock(basePath: string): boolean {
610
+ const lp = lockPath(basePath);
611
+ const gsdDir = gsdRoot(basePath);
612
+ const lockTarget = effectiveLockTarget(gsdDir);
613
+ const lockDir = lockTarget + ".lock";
614
+
615
+ const existingData = readExistingLockData(lp);
616
+ const isOrphan =
617
+ !existingData ||
618
+ (typeof existingData.pid === "number" && !isPidAlive(existingData.pid));
619
+ if (!isOrphan) return false;
620
+
621
+ let removed = false;
622
+ if (existsSync(lockDir)) {
623
+ try {
624
+ rmSync(lockDir, { recursive: true, force: true });
625
+ removed = true;
626
+ } catch {
627
+ /* best-effort */
628
+ }
629
+ }
630
+ if (existsSync(lp)) {
631
+ try {
632
+ unlinkSync(lp);
633
+ removed = true;
634
+ } catch {
635
+ /* best-effort */
636
+ }
637
+ }
638
+ return removed;
639
+ }
640
+
600
641
  /**
601
642
  * Returns true if we currently hold a session lock for the given path.
602
643
  */