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
@@ -1,3 +1,6 @@
1
+ // Project/App: GSD-2
2
+ // File Purpose: Tests for /gsd notifications command handling and overlay launch behavior.
3
+
1
4
  import test from "node:test";
2
5
  import assert from "node:assert/strict";
3
6
  import { join } from "node:path";
@@ -58,6 +61,47 @@ test("notifications command falls back to text output when overlay returns undef
58
61
  assert.match(notices[0].message, /Recent notifications:/);
59
62
  });
60
63
 
64
+ test("notifications command opens a compact bounded overlay", async (t) => {
65
+ const base = makeTempDir("overlay-options");
66
+ initNotificationStore(base);
67
+ appendNotification("Build complete", "success");
68
+
69
+ t.after(() => {
70
+ _resetNotificationStore();
71
+ cleanup(base);
72
+ });
73
+
74
+ const notices: Array<{ message: string; level?: string }> = [];
75
+ let capturedOptions: any;
76
+ await handleNotificationsCommand(
77
+ "",
78
+ {
79
+ hasUI: true,
80
+ ui: {
81
+ custom: async (_factory: any, options: any) => {
82
+ capturedOptions = options;
83
+ return true;
84
+ },
85
+ notify: (message: string, level?: string) => {
86
+ notices.push({ message, level });
87
+ },
88
+ },
89
+ } as any,
90
+ {} as any,
91
+ );
92
+
93
+ assert.deepEqual(capturedOptions?.overlayOptions, {
94
+ width: "58%",
95
+ minWidth: 68,
96
+ maxHeight: "52%",
97
+ anchor: "top-center",
98
+ row: "24%",
99
+ margin: { top: 2, right: 2, bottom: 6, left: 2 },
100
+ backdrop: true,
101
+ });
102
+ assert.equal(notices.length, 0, "successful overlay should not emit text fallback");
103
+ });
104
+
61
105
  test("notifications tail caps inline output and hints to open overlay", async (t) => {
62
106
  const base = makeTempDir("tail-cap");
63
107
  initNotificationStore(base);
@@ -33,43 +33,6 @@ import {
33
33
  teardownAutoWorktree,
34
34
  } from "../auto-worktree.ts";
35
35
  import { normalizeWorktreePathForCompare } from "../worktree-root.ts";
36
- import {
37
- WorktreeLifecycle,
38
- type WorktreeLifecycleDeps,
39
- type NotifyCtx,
40
- } from "../worktree-lifecycle.ts";
41
- import { WorktreeStateProjection } from "../worktree-state-projection.ts";
42
- import { resolveWorktreeProjectRoot } from "../worktree-root.ts";
43
- import { AutoSession } from "../auto/session.ts";
44
-
45
- // Test-local: LegacyTestDeps had three fields Lifecycle does not need
46
- // (shouldUseWorktreeIsolation, syncWorktreeStateBack, captureIntegrationBranch).
47
- // Permit them in test fixtures so existing override patterns keep working —
48
- // Lifecycle ignores the extras via structural typing.
49
- type LegacyTestDeps = WorktreeLifecycleDeps & {
50
- shouldUseWorktreeIsolation?: () => boolean;
51
- syncWorktreeStateBack?: (
52
- mainBasePath: string,
53
- worktreePath: string,
54
- milestoneId: string,
55
- ) => { synced: string[] };
56
- captureIntegrationBranch?: (basePath: string, mid: string | undefined) => void;
57
- };
58
-
59
- /** Shim factory preserving the legacy WorktreeResolver throw shape for tests. */
60
- function makeResolver(s: AutoSession, deps: LegacyTestDeps) {
61
- const lifecycle = new WorktreeLifecycle(s, deps);
62
- return {
63
- get workPath(): string { return s.basePath; },
64
- get projectRoot(): string {
65
- return resolveWorktreeProjectRoot(s.basePath, s.originalBasePath);
66
- },
67
- mergeAndExit: (mid: string, ctx: NotifyCtx) => {
68
- const r = lifecycle.exitMilestone(mid, { merge: true }, ctx);
69
- if (!r.ok && r.cause instanceof Error) throw r.cause;
70
- },
71
- };
72
- }
73
36
 
74
37
  // ─── Helpers ──────────────────────────────────────────────────────────────────
75
38
 
@@ -91,97 +54,6 @@ function createTempRepo(t: { after: (fn: () => void) => void }): string {
91
54
  return dir;
92
55
  }
93
56
 
94
- function makeSession(overrides?: Partial<{ basePath: string; originalBasePath: string }>): AutoSession {
95
- const s = new AutoSession();
96
- s.basePath = overrides?.basePath ?? "/project";
97
- s.originalBasePath = overrides?.originalBasePath ?? "/project";
98
- return s;
99
- }
100
-
101
- interface CallLog { fn: string; args: unknown[] }
102
-
103
- function makeDeps(overrides?: Partial<LegacyTestDeps>): LegacyTestDeps & { calls: CallLog[] } {
104
- const calls: CallLog[] = [];
105
-
106
- const deps: LegacyTestDeps & { calls: CallLog[] } = {
107
- calls,
108
- isInAutoWorktree: (basePath: string) => {
109
- calls.push({ fn: "isInAutoWorktree", args: [basePath] });
110
- return basePath.includes("worktrees");
111
- },
112
- shouldUseWorktreeIsolation: () => true,
113
- getIsolationMode: () => "worktree",
114
- mergeMilestoneToMain: (basePath: string, milestoneId: string, roadmapContent: string) => {
115
- calls.push({ fn: "mergeMilestoneToMain", args: [basePath, milestoneId, roadmapContent] });
116
- return { pushed: false, codeFilesChanged: true };
117
- },
118
- syncWorktreeStateBack: (mainBasePath: string, worktreePath: string, milestoneId: string) => {
119
- calls.push({ fn: "syncWorktreeStateBack", args: [mainBasePath, worktreePath, milestoneId] });
120
- return { synced: [] };
121
- },
122
- teardownAutoWorktree: (basePath: string, milestoneId: string, opts?: { preserveBranch?: boolean }) => {
123
- calls.push({ fn: "teardownAutoWorktree", args: [basePath, milestoneId, opts] });
124
- },
125
- createAutoWorktree: (basePath: string, milestoneId: string) => {
126
- calls.push({ fn: "createAutoWorktree", args: [basePath, milestoneId] });
127
- return `${basePath}/.gsd/worktrees/${milestoneId}`;
128
- },
129
- enterAutoWorktree: (basePath: string, milestoneId: string) => {
130
- calls.push({ fn: "enterAutoWorktree", args: [basePath, milestoneId] });
131
- return `${basePath}/.gsd/worktrees/${milestoneId}`;
132
- },
133
- getAutoWorktreePath: (basePath: string, milestoneId: string) => {
134
- calls.push({ fn: "getAutoWorktreePath", args: [basePath, milestoneId] });
135
- return null;
136
- },
137
- autoCommitCurrentBranch: (basePath: string, reason: string, milestoneId: string) => {
138
- calls.push({ fn: "autoCommitCurrentBranch", args: [basePath, reason, milestoneId] });
139
- },
140
- getCurrentBranch: (basePath: string) => {
141
- calls.push({ fn: "getCurrentBranch", args: [basePath] });
142
- return "main";
143
- },
144
- checkoutBranch: (basePath: string, branch: string) => {
145
- calls.push({ fn: "checkoutBranch", args: [basePath, branch] });
146
- },
147
- autoWorktreeBranch: (milestoneId: string) => `milestone/${milestoneId}`,
148
- resolveMilestoneFile: (basePath: string, milestoneId: string, fileType: string) => {
149
- calls.push({ fn: "resolveMilestoneFile", args: [basePath, milestoneId, fileType] });
150
- return null;
151
- },
152
- readFileSync: (path: string, _enc: string) => {
153
- calls.push({ fn: "readFileSync", args: [path] });
154
- return "# Roadmap\n";
155
- },
156
- GitServiceImpl: class {
157
- constructor(_basePath: string, _gitConfig: unknown) {}
158
- } as unknown as LegacyTestDeps["GitServiceImpl"],
159
- loadEffectiveGSDPreferences: () => ({ preferences: { git: {} } }),
160
- invalidateAllCaches: () => { calls.push({ fn: "invalidateAllCaches", args: [] }); },
161
- captureIntegrationBranch: (_basePath: string, _mid: string | undefined) => {},
162
- enterBranchModeForMilestone: (_basePath: string, _milestoneId: string) => {},
163
- worktreeProjection: new WorktreeStateProjection(),
164
- ...overrides,
165
- };
166
-
167
- if (overrides) {
168
- for (const [key, val] of Object.entries(overrides)) {
169
- if (key !== "calls") (deps as unknown as Record<string, unknown>)[key] = val;
170
- }
171
- }
172
- return deps;
173
- }
174
-
175
- function makeNotifyCtx(): NotifyCtx & { messages: Array<{ msg: string; level?: string }> } {
176
- const messages: Array<{ msg: string; level?: string }> = [];
177
- return {
178
- messages,
179
- notify: (msg: string, level?: "info" | "warning" | "error" | "success") => {
180
- messages.push({ msg, level });
181
- },
182
- };
183
- }
184
-
185
57
  // ─── Suite 1: getAutoWorktreeOriginalBase() returns realpath-canonical path ──
186
58
 
187
59
  describe("getAutoWorktreeOriginalBase() is realpath-normalised", () => {
@@ -273,92 +145,15 @@ describe("normalizeWorktreePathForCompare equalises canonical vs non-canonical f
273
145
  // resolveMilestoneFile call against the "worktree" path that is actually the
274
146
  // same directory). The new code correctly skips the fallback.
275
147
 
276
- describe("WorktreeResolver: roadmap-fallback skipped when basePath is same physical path as originalBase", () => {
277
- test("with trailing-slash basePath equal to originalBase: resolveMilestoneFile called once", () => {
278
- // originalBase is canonical (as returned by workspace registry)
279
- const canonicalBase = "/tmp/m5-test-project";
280
- // s.basePath has a trailing slash same physical dir, non-canonical string
281
- const trailingSlashBase = canonicalBase + "/";
282
-
283
- const s = makeSession({
284
- basePath: trailingSlashBase,
285
- originalBasePath: canonicalBase,
286
- });
287
-
288
- const calls: CallLog[] = [];
289
- const deps = makeDeps({
290
- // isInAutoWorktree: basePath has trailing slash but is NOT a worktree
291
- isInAutoWorktree: (basePath: string) => {
292
- calls.push({ fn: "isInAutoWorktree", args: [basePath] });
293
- return false;
294
- },
295
- // resolveMilestoneFile always returns null (no roadmap found)
296
- resolveMilestoneFile: (basePath: string, milestoneId: string, fileType: string) => {
297
- calls.push({ fn: "resolveMilestoneFile", args: [basePath, milestoneId, fileType] });
298
- return null;
299
- },
300
- teardownAutoWorktree: (basePath: string, milestoneId: string, opts?: { preserveBranch?: boolean }) => {
301
- calls.push({ fn: "teardownAutoWorktree", args: [basePath, milestoneId, opts] });
302
- },
303
- });
304
-
305
- // Override calls ref so we can inspect it directly
306
- (deps as unknown as { calls: CallLog[] }).calls = calls;
307
-
308
- const resolver = makeResolver(s, deps);
309
- const ctx = makeNotifyCtx();
310
-
311
- // mergeAndExit → _mergeWorktreeMode
312
- // originalBase = s.originalBasePath = canonicalBase
313
- // s.basePath = trailingSlashBase — physically same as canonicalBase
314
- // Post-fix: isSamePath(trailingSlashBase, canonicalBase) is true
315
- // → roadmap fallback branch is skipped (resolveMilestoneFile called once)
316
- // Pre-fix (bug): trailingSlashBase !== canonicalBase → fallback entered
317
- // → resolveMilestoneFile called twice
318
-
319
- resolver.mergeAndExit("M001", ctx);
320
-
321
- const rmfCalls = calls.filter(c => c.fn === "resolveMilestoneFile");
322
- assert.strictEqual(rmfCalls.length, 1,
323
- "resolveMilestoneFile must be called exactly once — fallback should be skipped when " +
324
- "s.basePath is the same physical path as originalBase (isSamePath fix)");
325
- });
326
-
327
- test("with genuinely different basePath (inside worktree): resolveMilestoneFile called twice", () => {
328
- // originalBase is the project root
329
- const projectRoot = "/tmp/m5-test-project";
330
- // s.basePath is inside a worktree — a physically different path
331
- const worktreePath = projectRoot + "/.gsd/worktrees/M002";
332
-
333
- const s = makeSession({
334
- basePath: worktreePath,
335
- originalBasePath: projectRoot,
336
- });
337
-
338
- const calls: CallLog[] = [];
339
- const deps = makeDeps({
340
- isInAutoWorktree: (basePath: string) => {
341
- calls.push({ fn: "isInAutoWorktree", args: [basePath] });
342
- return basePath.includes("worktrees");
343
- },
344
- resolveMilestoneFile: (basePath: string, milestoneId: string, fileType: string) => {
345
- calls.push({ fn: "resolveMilestoneFile", args: [basePath, milestoneId, fileType] });
346
- return null; // no roadmap in either location
347
- },
348
- teardownAutoWorktree: (basePath: string, milestoneId: string, opts?: { preserveBranch?: boolean }) => {
349
- calls.push({ fn: "teardownAutoWorktree", args: [basePath, milestoneId, opts] });
350
- },
351
- });
352
- (deps as unknown as { calls: CallLog[] }).calls = calls;
353
-
354
- const resolver = makeResolver(s, deps);
355
- const ctx = makeNotifyCtx();
356
-
357
- resolver.mergeAndExit("M002", ctx);
358
-
359
- const rmfCalls = calls.filter(c => c.fn === "resolveMilestoneFile");
360
- assert.strictEqual(rmfCalls.length, 2,
361
- "resolveMilestoneFile must be called twice when basePath is a genuine worktree path " +
362
- "(fallback should run for different physical paths)");
363
- });
364
- });
148
+ // ADR-016 phase 2 / C2 + C3 (#5625, #5626): the prior two tests in this
149
+ // suite asserted call counts on `deps.resolveMilestoneFile` /
150
+ // `deps.isInAutoWorktree` / `deps.teardownAutoWorktree` to verify that the
151
+ // roadmap-fallback branch was skipped when basePath was a non-canonical
152
+ // form of originalBase (trailing slash). After C2/C3 those fields are
153
+ // inlined into worktree-lifecycle.ts as direct imports — the mocks no
154
+ // longer fire and the call-count assertions test nothing meaningful. The
155
+ // underlying invariant (isSamePathPhysical normalises trailing slashes,
156
+ // canonical/non-canonical pairs, and case differences) is preserved
157
+ // inside worktree-lifecycle.ts and covered indirectly by the merge-area
158
+ // integration tests, which exercise real worktree merges where the
159
+ // fallback choice matters.
@@ -1,11 +1,19 @@
1
+ // Project/App: GSD-2
2
+ // File Purpose: Regression tests for parallel monitor overlay rendering and input handling.
3
+
1
4
  import { describe, it } from "node:test";
2
- import assert from "node:assert";
5
+ import assert from "node:assert/strict";
6
+
7
+ import { visibleWidth } from "@gsd/pi-tui";
3
8
 
4
- /**
5
- * Basic tests for the parallel monitor overlay data helpers.
6
- * The overlay is primarily a rendering component that reads existing
7
- * status files — these tests verify the helper logic in isolation.
8
- */
9
+ function assertLinesFit(lines: string[], width: number): void {
10
+ for (const line of lines) {
11
+ assert.ok(
12
+ visibleWidth(line) <= width,
13
+ `line exceeds width ${width}: ${visibleWidth(line)} "${line}"`,
14
+ );
15
+ }
16
+ }
9
17
 
10
18
  describe("parallel-monitor-overlay", () => {
11
19
  it("progressBar generates correct width", async () => {
@@ -37,6 +45,7 @@ describe("parallel-monitor-overlay", () => {
37
45
  const lines = overlay.render(80);
38
46
  assert.ok(Array.isArray(lines), "render should return an array");
39
47
  assert.ok(lines.length > 0, "render should return at least one line");
48
+ assertLinesFit(lines, 80);
40
49
 
41
50
  // Should contain header text
42
51
  const joined = lines.join("\n");
@@ -79,4 +88,27 @@ describe("parallel-monitor-overlay", () => {
79
88
  assert.equal((overlay as any).scrollOffset, 0, "empty overlays clamp scroll to zero");
80
89
  overlay.dispose();
81
90
  });
91
+
92
+ it("ParallelMonitorOverlay empty state fits narrow and wide widths", async () => {
93
+ const mod = await import("../parallel-monitor-overlay.js");
94
+
95
+ const mockTui = { requestRender: () => {} };
96
+ const mockTheme = {
97
+ fg: (_color: string, text: string) => text,
98
+ bold: (text: string) => text,
99
+ };
100
+ const overlay = new mod.ParallelMonitorOverlay(
101
+ mockTui,
102
+ mockTheme as any,
103
+ () => {},
104
+ "/nonexistent/path",
105
+ );
106
+
107
+ for (const width of [40, 80, 120]) {
108
+ assertLinesFit(overlay.render(width), width);
109
+ overlay.invalidate();
110
+ }
111
+
112
+ overlay.dispose();
113
+ });
82
114
  });
@@ -250,14 +250,14 @@ describe("Post-execution blocking failure retry bypass", () => {
250
250
  const s = makeMockSession(tempDir, { type: "execute-task", id: "M001/S01/T01" });
251
251
 
252
252
  // Pre-set some retry state
253
- s.verificationRetryCount.set("M001/S01/T01", 2);
253
+ s.verificationRetryCount.set("execute-task:M001/S01/T01", 2);
254
254
 
255
255
  const vctx: VerificationContext = { s, ctx, pi };
256
256
  const result = await runPostUnitVerification(vctx, pauseAutoMock);
257
257
 
258
258
  // On success, retry count should be cleared
259
259
  assert.equal(result, "continue");
260
- assert.equal(s.verificationRetryCount.has("M001/S01/T01"), false);
260
+ assert.equal(s.verificationRetryCount.has("execute-task:M001/S01/T01"), false);
261
261
  });
262
262
 
263
263
  test("post-exec failure notification mentions cross-task consistency", async () => {
@@ -14,9 +14,9 @@ import {
14
14
  insertMilestone,
15
15
  insertSlice,
16
16
  setSliceSketchFlag,
17
- autoHealSketchFlags,
18
17
  getSlice,
19
18
  } from "../gsd-db.ts";
19
+ import { autoHealSketchFlags } from "../state-reconciliation/drift/sketch-flag.ts";
20
20
  import { deriveStateFromDb } from "../state.ts";
21
21
  import { resolveDispatch } from "../auto-dispatch.ts";
22
22
  import type { DispatchContext } from "../auto-dispatch.ts";
@@ -64,6 +64,16 @@ test("discuss prompt allows implementation questions when they materially matter
64
64
  assert.doesNotMatch(prompt, /Questions must be about the experience, not the implementation/i);
65
65
  });
66
66
 
67
+ test("discuss prompt ends milestone planning with next-step handoff", () => {
68
+ const prompt = readPrompt("discuss");
69
+ assert.match(prompt, /Next steps:/);
70
+ assert.match(prompt, /\/gsd auto/);
71
+ assert.match(prompt, /\/gsd status/);
72
+ assert.match(prompt, /\/gsd visualize/);
73
+ assert.match(prompt, /\/gsd notifications/);
74
+ assert.doesNotMatch(prompt, /nothing else\. Auto-mode will start automatically/);
75
+ });
76
+
67
77
  test("guided discussion prompts avoid wrap-up prompts after every round", () => {
68
78
  const milestonePrompt = readPrompt("guided-discuss-milestone");
69
79
  const slicePrompt = readPrompt("guided-discuss-slice");
@@ -217,6 +227,17 @@ test("complete-slice prompt does not instruct LLM to toggle checkboxes manually"
217
227
  assert.doesNotMatch(prompt, /change \[ \] to \[x\]/);
218
228
  });
219
229
 
230
+ test("complete-slice prompt keeps source fixes in execution units", () => {
231
+ const prompt = readPrompt("complete-slice");
232
+ assert.match(prompt, /Do not use direct `bash` for verification commands/i);
233
+ assert.match(prompt, /do \*\*not\*\* edit source files in this unit/i);
234
+ assert.match(prompt, /do \*\*not\*\* call `gsd_slice_complete`/i);
235
+ assert.match(prompt, /gsd_task_reopen/);
236
+ assert.match(prompt, /gsd_replan_slice/);
237
+ assert.match(prompt, /needs execution follow-up/i);
238
+ assert.doesNotMatch(prompt, /Fix failures before marking done/i);
239
+ });
240
+
220
241
  test("complete-slice prompt instructs writing summary and UAT files before tool call", () => {
221
242
  const prompt = readPrompt("complete-slice");
222
243
  assert.match(prompt, /\{\{sliceSummaryPath\}\}/);
@@ -363,7 +384,9 @@ test("execute-task prompt uses camelCase parameter names matching TypeBox schema
363
384
  test("complete-slice prompt uses camelCase parameter names matching TypeBox schema", () => {
364
385
  const prompt = readPrompt("complete-slice");
365
386
  // The gsd_complete_slice tool schema uses camelCase: milestoneId, sliceId
366
- const toolCallLine = prompt.split("\n").find((l) => /gsd_complete_slice/.test(l) || /gsd_slice_complete/.test(l));
387
+ const toolCallLine = prompt.split("\n").find((l) =>
388
+ (/gsd_complete_slice/.test(l) || /gsd_slice_complete/.test(l)) && /milestoneId/.test(l) && /sliceId/.test(l)
389
+ );
367
390
  assert.ok(toolCallLine, "prompt must contain a gsd_complete_slice or gsd_slice_complete tool call line");
368
391
  assert.doesNotMatch(toolCallLine!, /milestone_id/, "must use milestoneId, not milestone_id");
369
392
  assert.doesNotMatch(toolCallLine!, /slice_id/, "must use sliceId, not slice_id");
@@ -10,7 +10,11 @@ import { join } from "node:path";
10
10
  import { tmpdir } from "node:os";
11
11
  import { randomUUID } from "node:crypto";
12
12
 
13
- import { _resolvePausedResumeBasePathForTest } from "../auto.ts";
13
+ // ADR-016 phase 2 / B3 (#5621): the legacy `resolvePausedResumeBasePath`
14
+ // helper was retired and folded into `WorktreeLifecycle.resumeFromPausedSession`.
15
+ // The pure path-resolution function lives in `worktree-lifecycle.ts` for tests
16
+ // that exercise the path-resolution invariant without constructing a session.
17
+ import { resolvePausedResumeBasePath } from "../worktree-lifecycle.ts";
14
18
 
15
19
  function makeTmpBase(): string {
16
20
  const base = join(tmpdir(), `gsd-resume-wt-${randomUUID()}`);
@@ -59,7 +63,7 @@ test("resume base path uses paused-session worktreePath when the worktree exists
59
63
  try {
60
64
  setupWorktreeOnDisk(wt);
61
65
  assert.equal(
62
- _resolvePausedResumeBasePathForTest(base, wt),
66
+ resolvePausedResumeBasePath(base, wt),
63
67
  wt,
64
68
  );
65
69
  } finally {
@@ -72,7 +76,7 @@ test("resume base path falls back to project root when paused worktree is missin
72
76
  const wt = makeWorktreePath(base, "M001-test");
73
77
  try {
74
78
  assert.equal(
75
- _resolvePausedResumeBasePathForTest(base, wt),
79
+ resolvePausedResumeBasePath(base, wt),
76
80
  base,
77
81
  );
78
82
  } finally {
@@ -42,16 +42,19 @@ test("State Reconciliation invalidates cache and returns reconciled state", asyn
42
42
  assert.equal(result.ok && result.stateSnapshot, state);
43
43
  });
44
44
 
45
- test("State Reconciliation blocks when derived state carries blockers", async () => {
45
+ test("State Reconciliation surfaces terminal blockers in result (ADR-017)", async () => {
46
+ // Under ADR-017, blockers are terminal but do not throw — they ride along
47
+ // in the result so the orchestrator adapter can map them to ok=false.
46
48
  const result = await reconcileBeforeDispatch("/project", {
47
49
  invalidateStateCache() {},
48
50
  async deriveState() {
49
51
  return makeState({ phase: "blocked", blockers: ["slice lock missing"] });
50
52
  },
53
+ registry: [],
51
54
  });
52
55
 
53
- assert.equal(result.ok, false);
54
- assert.equal(!result.ok && result.reason, "slice lock missing");
56
+ assert.equal(result.ok, true);
57
+ assert.deepEqual(result.blockers, ["slice lock missing"]);
55
58
  });
56
59
 
57
60
  test("Tool Contract compiles known Unit prompt and tool policy", () => {
@@ -188,6 +188,30 @@ test("empty-content aborted during session-switch is silently ignored", () => {
188
188
  assert.equal(cancelledWith, null);
189
189
  });
190
190
 
191
+ test("completed assistant content with aborted stopReason during session-switch is ignored", () => {
192
+ // newSession() can abort the just-finished provider stream while the last
193
+ // assistant message still carries the completed unit summary. That is a
194
+ // session-transition artifact, not a cancellation for the next unit.
195
+ let cancelledWith: unknown = null;
196
+ const resolveCancelled = (ctx: ErrorContext) => {
197
+ cancelledWith = ctx;
198
+ return true;
199
+ };
200
+
201
+ _handleSessionSwitchAgentEnd(
202
+ {
203
+ stopReason: "aborted",
204
+ content: [{
205
+ type: "text",
206
+ text: "Implemented T01 and verified the slice task is complete.",
207
+ }],
208
+ },
209
+ resolveCancelled,
210
+ );
211
+
212
+ assert.equal(cancelledWith, null);
213
+ });
214
+
191
215
  test("non-abort errors during session-switch are not propagated through this helper", () => {
192
216
  // Real provider errors (rate-limit, network, unsupported-model) are handled
193
217
  // by the post-switch retry pipeline — not by the in-flight switch handler.