gsd-pi 2.64.0-dev.f8aad9b → 2.65.0-dev.16e10d7

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 (473) hide show
  1. package/dist/headless.js +3 -1
  2. package/dist/mcp-server.js +6 -2
  3. package/dist/resources/extensions/bg-shell/bg-shell-lifecycle.js +22 -7
  4. package/dist/resources/extensions/bg-shell/process-manager.js +6 -1
  5. package/dist/resources/extensions/browser-tools/capture.js +20 -1
  6. package/dist/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +93 -0
  7. package/dist/resources/extensions/gsd/auto/run-unit.js +13 -2
  8. package/dist/resources/extensions/gsd/auto-dispatch.js +94 -8
  9. package/dist/resources/extensions/gsd/auto-model-selection.js +7 -5
  10. package/dist/resources/extensions/gsd/auto-post-unit.js +115 -7
  11. package/dist/resources/extensions/gsd/auto-prompts.js +24 -0
  12. package/dist/resources/extensions/gsd/auto-recovery.js +12 -8
  13. package/dist/resources/extensions/gsd/auto-start.js +35 -1
  14. package/dist/resources/extensions/gsd/auto-tool-tracking.js +10 -0
  15. package/dist/resources/extensions/gsd/auto-verification.js +138 -1
  16. package/dist/resources/extensions/gsd/auto-worktree.js +29 -7
  17. package/dist/resources/extensions/gsd/auto.js +2 -2
  18. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +17 -4
  19. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +34 -13
  20. package/dist/resources/extensions/gsd/bootstrap/notify-interceptor.js +28 -0
  21. package/dist/resources/extensions/gsd/bootstrap/query-tools.js +6 -4
  22. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +5 -1
  23. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +12 -1
  24. package/dist/resources/extensions/gsd/bootstrap/register-shortcuts.js +16 -0
  25. package/dist/resources/extensions/gsd/bootstrap/system-context.js +20 -0
  26. package/dist/resources/extensions/gsd/commands/catalog.js +7 -1
  27. package/dist/resources/extensions/gsd/commands/context.js +8 -1
  28. package/dist/resources/extensions/gsd/commands/handlers/core.js +21 -0
  29. package/dist/resources/extensions/gsd/commands/handlers/notifications-handler.js +104 -0
  30. package/dist/resources/extensions/gsd/commands/handlers/ops.js +5 -0
  31. package/dist/resources/extensions/gsd/commands-extensions.js +1 -1
  32. package/dist/resources/extensions/gsd/config-overlay.js +312 -0
  33. package/dist/resources/extensions/gsd/detection.js +1 -1
  34. package/dist/resources/extensions/gsd/dispatch-guard.js +2 -1
  35. package/dist/resources/extensions/gsd/docs/preferences-reference.md +1 -0
  36. package/dist/resources/extensions/gsd/doctor.js +2 -1
  37. package/dist/resources/extensions/gsd/gitignore.js +1 -0
  38. package/dist/resources/extensions/gsd/gsd-db.js +11 -2
  39. package/dist/resources/extensions/gsd/guided-flow.js +220 -29
  40. package/dist/resources/extensions/gsd/md-importer.js +14 -7
  41. package/dist/resources/extensions/gsd/notification-overlay.js +256 -0
  42. package/dist/resources/extensions/gsd/notification-store.js +273 -0
  43. package/dist/resources/extensions/gsd/notification-widget.js +56 -0
  44. package/dist/resources/extensions/gsd/parallel-orchestrator.js +17 -11
  45. package/dist/resources/extensions/gsd/post-execution-checks.js +407 -0
  46. package/dist/resources/extensions/gsd/pre-execution-checks.js +471 -0
  47. package/dist/resources/extensions/gsd/preferences-types.js +7 -0
  48. package/dist/resources/extensions/gsd/preferences-validation.js +78 -1
  49. package/dist/resources/extensions/gsd/preferences.js +13 -2
  50. package/dist/resources/extensions/gsd/preparation.js +1092 -0
  51. package/dist/resources/extensions/gsd/prompt-validation.js +67 -0
  52. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +3 -3
  53. package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  54. package/dist/resources/extensions/gsd/prompts/discuss-prepared.md +424 -0
  55. package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +4 -1
  56. package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +5 -4
  57. package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +23 -0
  58. package/dist/resources/extensions/gsd/prompts/rethink.md +2 -1
  59. package/dist/resources/extensions/gsd/prompts/validate-milestone.md +56 -23
  60. package/dist/resources/extensions/gsd/quick.js +19 -15
  61. package/dist/resources/extensions/gsd/reactive-graph.js +12 -0
  62. package/dist/resources/extensions/gsd/roadmap-slices.js +24 -5
  63. package/dist/resources/extensions/gsd/safety/content-validator.js +3 -3
  64. package/dist/resources/extensions/gsd/session-lock.js +23 -1
  65. package/dist/resources/extensions/gsd/state.js +100 -12
  66. package/dist/resources/extensions/gsd/templates/context-enhanced.md +138 -0
  67. package/dist/resources/extensions/gsd/tools/complete-slice.js +12 -3
  68. package/dist/resources/extensions/gsd/tools/complete-task.js +16 -4
  69. package/dist/resources/extensions/gsd/tools/plan-milestone.js +7 -5
  70. package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +5 -2
  71. package/dist/resources/extensions/gsd/tools/reopen-milestone.js +119 -0
  72. package/dist/resources/extensions/gsd/tools/reopen-slice.js +30 -0
  73. package/dist/resources/extensions/gsd/tools/reopen-task.js +18 -0
  74. package/dist/resources/extensions/gsd/triage-resolution.js +25 -9
  75. package/dist/resources/extensions/gsd/verification-evidence.js +18 -0
  76. package/dist/resources/extensions/gsd/workflow-logger.js +8 -0
  77. package/dist/resources/extensions/gsd/workflow-projections.js +4 -7
  78. package/dist/resources/extensions/gsd/workflow-reconcile.js +2 -4
  79. package/dist/resources/extensions/gsd/workflow-templates.js +11 -2
  80. package/dist/resources/extensions/gsd/worktree-manager.js +5 -2
  81. package/dist/resources/extensions/gsd/worktree.js +9 -0
  82. package/dist/resources/extensions/shared/interview-ui.js +1 -1
  83. package/dist/web/standalone/.next/BUILD_ID +1 -1
  84. package/dist/web/standalone/.next/app-path-routes-manifest.json +18 -17
  85. package/dist/web/standalone/.next/build-manifest.json +3 -3
  86. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  87. package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
  88. package/dist/web/standalone/.next/routes-manifest.json +6 -0
  89. package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
  90. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  91. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  92. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  93. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  94. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  95. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  96. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  97. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  98. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  99. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  100. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  101. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  102. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  103. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  104. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  105. package/dist/web/standalone/.next/server/app/api/notifications/route.js +3 -0
  106. package/dist/web/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -0
  107. package/dist/web/standalone/.next/server/app/api/notifications/route_client-reference-manifest.js +1 -0
  108. package/dist/web/standalone/.next/server/app/index.html +1 -1
  109. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  110. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  111. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  112. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  113. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  114. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  115. package/dist/web/standalone/.next/server/app-paths-manifest.json +18 -17
  116. package/dist/web/standalone/.next/server/functions-config-manifest.json +1 -0
  117. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  118. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  119. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  120. package/dist/web/standalone/.next/server/pages/500.html +2 -2
  121. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  122. package/dist/web/standalone/.next/static/Z3TgDP0c7kG9j8CVQVGcl/_buildManifest.js +1 -0
  123. package/dist/web/standalone/.next/static/chunks/6502.8874bcae249c02e1.js +9 -0
  124. package/dist/web/standalone/.next/static/chunks/app/_global-error/page-8805a20e15762c3c.js +1 -0
  125. package/dist/web/standalone/.next/static/chunks/app/api/boot/route-8805a20e15762c3c.js +1 -0
  126. package/dist/web/standalone/.next/static/chunks/app/api/bridge-terminal/input/route-8805a20e15762c3c.js +1 -0
  127. package/dist/web/standalone/.next/static/chunks/app/api/bridge-terminal/resize/route-8805a20e15762c3c.js +1 -0
  128. package/dist/web/standalone/.next/static/chunks/app/api/bridge-terminal/stream/route-8805a20e15762c3c.js +1 -0
  129. package/dist/web/standalone/.next/static/chunks/app/api/browse-directories/route-8805a20e15762c3c.js +1 -0
  130. package/dist/web/standalone/.next/static/chunks/app/api/captures/route-8805a20e15762c3c.js +1 -0
  131. package/dist/web/standalone/.next/static/chunks/app/api/cleanup/route-8805a20e15762c3c.js +1 -0
  132. package/dist/web/standalone/.next/static/chunks/app/api/dev-mode/route-8805a20e15762c3c.js +1 -0
  133. package/dist/web/standalone/.next/static/chunks/app/api/doctor/route-8805a20e15762c3c.js +1 -0
  134. package/dist/web/standalone/.next/static/chunks/app/api/experimental/route-8805a20e15762c3c.js +1 -0
  135. package/dist/web/standalone/.next/static/chunks/app/api/export-data/route-8805a20e15762c3c.js +1 -0
  136. package/dist/web/standalone/.next/static/chunks/app/api/files/route-8805a20e15762c3c.js +1 -0
  137. package/dist/web/standalone/.next/static/chunks/app/api/forensics/route-8805a20e15762c3c.js +1 -0
  138. package/dist/web/standalone/.next/static/chunks/app/api/git/route-8805a20e15762c3c.js +1 -0
  139. package/dist/web/standalone/.next/static/chunks/app/api/history/route-8805a20e15762c3c.js +1 -0
  140. package/dist/web/standalone/.next/static/chunks/app/api/hooks/route-8805a20e15762c3c.js +1 -0
  141. package/dist/web/standalone/.next/static/chunks/app/api/inspect/route-8805a20e15762c3c.js +1 -0
  142. package/dist/web/standalone/.next/static/chunks/app/api/knowledge/route-8805a20e15762c3c.js +1 -0
  143. package/dist/web/standalone/.next/static/chunks/app/api/live-state/route-8805a20e15762c3c.js +1 -0
  144. package/dist/web/standalone/.next/static/chunks/app/api/notifications/route-8805a20e15762c3c.js +1 -0
  145. package/dist/web/standalone/.next/static/chunks/app/api/onboarding/route-8805a20e15762c3c.js +1 -0
  146. package/dist/web/standalone/.next/static/chunks/app/api/preferences/route-8805a20e15762c3c.js +1 -0
  147. package/dist/web/standalone/.next/static/chunks/app/api/projects/route-8805a20e15762c3c.js +1 -0
  148. package/dist/web/standalone/.next/static/chunks/app/api/recovery/route-8805a20e15762c3c.js +1 -0
  149. package/dist/web/standalone/.next/static/chunks/app/api/remote-questions/route-8805a20e15762c3c.js +1 -0
  150. package/dist/web/standalone/.next/static/chunks/app/api/session/browser/route-8805a20e15762c3c.js +1 -0
  151. package/dist/web/standalone/.next/static/chunks/app/api/session/command/route-8805a20e15762c3c.js +1 -0
  152. package/dist/web/standalone/.next/static/chunks/app/api/session/events/route-8805a20e15762c3c.js +1 -0
  153. package/dist/web/standalone/.next/static/chunks/app/api/session/manage/route-8805a20e15762c3c.js +1 -0
  154. package/dist/web/standalone/.next/static/chunks/app/api/settings-data/route-8805a20e15762c3c.js +1 -0
  155. package/dist/web/standalone/.next/static/chunks/app/api/shutdown/route-8805a20e15762c3c.js +1 -0
  156. package/dist/web/standalone/.next/static/chunks/app/api/skill-health/route-8805a20e15762c3c.js +1 -0
  157. package/dist/web/standalone/.next/static/chunks/app/api/steer/route-8805a20e15762c3c.js +1 -0
  158. package/dist/web/standalone/.next/static/chunks/app/api/switch-root/route-8805a20e15762c3c.js +1 -0
  159. package/dist/web/standalone/.next/static/chunks/app/api/terminal/input/route-8805a20e15762c3c.js +1 -0
  160. package/dist/web/standalone/.next/static/chunks/app/api/terminal/resize/route-8805a20e15762c3c.js +1 -0
  161. package/dist/web/standalone/.next/static/chunks/app/api/terminal/sessions/route-8805a20e15762c3c.js +1 -0
  162. package/dist/web/standalone/.next/static/chunks/app/api/terminal/stream/route-8805a20e15762c3c.js +1 -0
  163. package/dist/web/standalone/.next/static/chunks/app/api/terminal/upload/route-8805a20e15762c3c.js +1 -0
  164. package/dist/web/standalone/.next/static/chunks/app/api/undo/route-8805a20e15762c3c.js +1 -0
  165. package/dist/web/standalone/.next/static/chunks/app/api/update/route-8805a20e15762c3c.js +1 -0
  166. package/dist/web/standalone/.next/static/chunks/app/api/visualizer/route-8805a20e15762c3c.js +1 -0
  167. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/app-error-8805a20e15762c3c.js +1 -0
  168. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/forbidden-8805a20e15762c3c.js +1 -0
  169. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/not-found-8805a20e15762c3c.js +1 -0
  170. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/unauthorized-8805a20e15762c3c.js +1 -0
  171. package/dist/web/standalone/.next/static/chunks/{webpack-a1c1e452c6b32d04.js → webpack-9fed74684e1c5bb1.js} +1 -1
  172. package/package.json +1 -1
  173. package/packages/pi-agent-core/dist/agent-loop.js +26 -9
  174. package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
  175. package/packages/pi-agent-core/src/agent-loop.test.ts +100 -4
  176. package/packages/pi-agent-core/src/agent-loop.ts +43 -12
  177. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.d.ts +2 -0
  178. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.d.ts.map +1 -0
  179. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js +38 -0
  180. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js.map +1 -0
  181. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  182. package/packages/pi-coding-agent/dist/core/agent-session.js +11 -0
  183. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  184. package/packages/pi-coding-agent/dist/core/resource-loader-cache-reset.test.d.ts +2 -0
  185. package/packages/pi-coding-agent/dist/core/resource-loader-cache-reset.test.d.ts.map +1 -0
  186. package/packages/pi-coding-agent/dist/core/resource-loader-cache-reset.test.js +24 -0
  187. package/packages/pi-coding-agent/dist/core/resource-loader-cache-reset.test.js.map +1 -0
  188. package/packages/pi-coding-agent/dist/core/resource-loader.d.ts.map +1 -1
  189. package/packages/pi-coding-agent/dist/core/resource-loader.js +4 -1
  190. package/packages/pi-coding-agent/dist/core/resource-loader.js.map +1 -1
  191. package/packages/pi-coding-agent/dist/core/retry-handler.d.ts.map +1 -1
  192. package/packages/pi-coding-agent/dist/core/retry-handler.js +30 -19
  193. package/packages/pi-coding-agent/dist/core/retry-handler.js.map +1 -1
  194. package/packages/pi-coding-agent/dist/core/retry-handler.test.js +51 -0
  195. package/packages/pi-coding-agent/dist/core/retry-handler.test.js.map +1 -1
  196. package/packages/pi-coding-agent/dist/core/sdk.js +9 -9
  197. package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
  198. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.d.ts +2 -1
  199. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.d.ts.map +1 -1
  200. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js +10 -1
  201. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js.map +1 -1
  202. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +2 -0
  203. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  204. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +28 -5
  205. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  206. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js +15 -1
  207. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js.map +1 -1
  208. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js +18 -0
  209. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js.map +1 -1
  210. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +6 -0
  211. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  212. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +40 -0
  213. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  214. package/packages/pi-coding-agent/package.json +1 -1
  215. package/packages/pi-coding-agent/src/core/agent-session-tool-refresh.test.ts +64 -0
  216. package/packages/pi-coding-agent/src/core/agent-session.ts +10 -0
  217. package/packages/pi-coding-agent/src/core/resource-loader-cache-reset.test.ts +42 -0
  218. package/packages/pi-coding-agent/src/core/resource-loader.ts +5 -1
  219. package/packages/pi-coding-agent/src/core/retry-handler.test.ts +80 -0
  220. package/packages/pi-coding-agent/src/core/retry-handler.ts +37 -25
  221. package/packages/pi-coding-agent/src/core/sdk.ts +9 -9
  222. package/packages/pi-coding-agent/src/modes/interactive/components/provider-manager.ts +10 -0
  223. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +29 -4
  224. package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.test.ts +27 -0
  225. package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.ts +16 -1
  226. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +38 -0
  227. package/packages/pi-tui/dist/__tests__/overlay-layout.test.d.ts +2 -0
  228. package/packages/pi-tui/dist/__tests__/overlay-layout.test.d.ts.map +1 -0
  229. package/packages/pi-tui/dist/__tests__/overlay-layout.test.js +66 -0
  230. package/packages/pi-tui/dist/__tests__/overlay-layout.test.js.map +1 -0
  231. package/packages/pi-tui/dist/components/image.d.ts +2 -0
  232. package/packages/pi-tui/dist/components/image.d.ts.map +1 -1
  233. package/packages/pi-tui/dist/components/image.js +4 -0
  234. package/packages/pi-tui/dist/components/image.js.map +1 -1
  235. package/packages/pi-tui/dist/components/image.test.d.ts +6 -0
  236. package/packages/pi-tui/dist/components/image.test.d.ts.map +1 -0
  237. package/packages/pi-tui/dist/components/image.test.js +32 -0
  238. package/packages/pi-tui/dist/components/image.test.js.map +1 -0
  239. package/packages/pi-tui/dist/components/loader.d.ts +4 -2
  240. package/packages/pi-tui/dist/components/loader.d.ts.map +1 -1
  241. package/packages/pi-tui/dist/components/loader.js +27 -9
  242. package/packages/pi-tui/dist/components/loader.js.map +1 -1
  243. package/packages/pi-tui/dist/components/text.d.ts.map +1 -1
  244. package/packages/pi-tui/dist/components/text.js +2 -0
  245. package/packages/pi-tui/dist/components/text.js.map +1 -1
  246. package/packages/pi-tui/dist/overlay-layout.d.ts.map +1 -1
  247. package/packages/pi-tui/dist/overlay-layout.js +12 -1
  248. package/packages/pi-tui/dist/overlay-layout.js.map +1 -1
  249. package/packages/pi-tui/dist/tui.d.ts +4 -0
  250. package/packages/pi-tui/dist/tui.d.ts.map +1 -1
  251. package/packages/pi-tui/dist/tui.js +35 -0
  252. package/packages/pi-tui/dist/tui.js.map +1 -1
  253. package/packages/pi-tui/src/__tests__/overlay-layout.test.ts +82 -0
  254. package/packages/pi-tui/src/components/image.test.ts +36 -0
  255. package/packages/pi-tui/src/components/image.ts +5 -0
  256. package/packages/pi-tui/src/components/loader.ts +27 -10
  257. package/packages/pi-tui/src/components/text.ts +1 -0
  258. package/packages/pi-tui/src/overlay-layout.ts +13 -1
  259. package/packages/pi-tui/src/tui.ts +34 -0
  260. package/pkg/package.json +1 -1
  261. package/src/resources/extensions/bg-shell/bg-shell-lifecycle.ts +19 -7
  262. package/src/resources/extensions/bg-shell/process-manager.ts +8 -2
  263. package/src/resources/extensions/browser-tools/capture.ts +19 -1
  264. package/src/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +93 -0
  265. package/src/resources/extensions/gsd/auto/run-unit.ts +12 -2
  266. package/src/resources/extensions/gsd/auto-dispatch.ts +105 -8
  267. package/src/resources/extensions/gsd/auto-model-selection.ts +7 -5
  268. package/src/resources/extensions/gsd/auto-post-unit.ts +138 -6
  269. package/src/resources/extensions/gsd/auto-prompts.ts +31 -0
  270. package/src/resources/extensions/gsd/auto-recovery.ts +10 -8
  271. package/src/resources/extensions/gsd/auto-start.ts +38 -0
  272. package/src/resources/extensions/gsd/auto-tool-tracking.ts +10 -0
  273. package/src/resources/extensions/gsd/auto-verification.ts +190 -2
  274. package/src/resources/extensions/gsd/auto-worktree.ts +28 -7
  275. package/src/resources/extensions/gsd/auto.ts +2 -1
  276. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +16 -4
  277. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +35 -13
  278. package/src/resources/extensions/gsd/bootstrap/notify-interceptor.ts +34 -0
  279. package/src/resources/extensions/gsd/bootstrap/query-tools.ts +5 -4
  280. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +4 -1
  281. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +12 -1
  282. package/src/resources/extensions/gsd/bootstrap/register-shortcuts.ts +20 -0
  283. package/src/resources/extensions/gsd/bootstrap/system-context.ts +28 -0
  284. package/src/resources/extensions/gsd/commands/catalog.ts +7 -1
  285. package/src/resources/extensions/gsd/commands/context.ts +7 -1
  286. package/src/resources/extensions/gsd/commands/handlers/core.ts +24 -0
  287. package/src/resources/extensions/gsd/commands/handlers/notifications-handler.ts +140 -0
  288. package/src/resources/extensions/gsd/commands/handlers/ops.ts +5 -0
  289. package/src/resources/extensions/gsd/commands-extensions.ts +1 -1
  290. package/src/resources/extensions/gsd/config-overlay.ts +331 -0
  291. package/src/resources/extensions/gsd/detection.ts +1 -1
  292. package/src/resources/extensions/gsd/dispatch-guard.ts +2 -1
  293. package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -0
  294. package/src/resources/extensions/gsd/doctor.ts +2 -1
  295. package/src/resources/extensions/gsd/gitignore.ts +1 -0
  296. package/src/resources/extensions/gsd/gsd-db.ts +13 -2
  297. package/src/resources/extensions/gsd/guided-flow.ts +254 -30
  298. package/src/resources/extensions/gsd/md-importer.ts +13 -6
  299. package/src/resources/extensions/gsd/notification-overlay.ts +295 -0
  300. package/src/resources/extensions/gsd/notification-store.ts +293 -0
  301. package/src/resources/extensions/gsd/notification-widget.ts +68 -0
  302. package/src/resources/extensions/gsd/parallel-orchestrator.ts +19 -11
  303. package/src/resources/extensions/gsd/post-execution-checks.ts +539 -0
  304. package/src/resources/extensions/gsd/pre-execution-checks.ts +581 -0
  305. package/src/resources/extensions/gsd/preferences-types.ts +53 -0
  306. package/src/resources/extensions/gsd/preferences-validation.ts +78 -1
  307. package/src/resources/extensions/gsd/preferences.ts +13 -2
  308. package/src/resources/extensions/gsd/preparation.ts +1419 -0
  309. package/src/resources/extensions/gsd/prompt-validation.ts +88 -0
  310. package/src/resources/extensions/gsd/prompts/complete-milestone.md +3 -3
  311. package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  312. package/src/resources/extensions/gsd/prompts/discuss-prepared.md +424 -0
  313. package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +4 -1
  314. package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +5 -4
  315. package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +23 -0
  316. package/src/resources/extensions/gsd/prompts/rethink.md +2 -1
  317. package/src/resources/extensions/gsd/prompts/validate-milestone.md +56 -23
  318. package/src/resources/extensions/gsd/quick.ts +20 -15
  319. package/src/resources/extensions/gsd/reactive-graph.ts +18 -0
  320. package/src/resources/extensions/gsd/roadmap-slices.ts +21 -5
  321. package/src/resources/extensions/gsd/safety/content-validator.ts +3 -3
  322. package/src/resources/extensions/gsd/session-lock.ts +17 -1
  323. package/src/resources/extensions/gsd/state.ts +101 -11
  324. package/src/resources/extensions/gsd/templates/context-enhanced.md +138 -0
  325. package/src/resources/extensions/gsd/tests/adversarial-review-fixes.test.ts +223 -0
  326. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +33 -2
  327. package/src/resources/extensions/gsd/tests/auto-remediate-slice-status.test.ts +56 -0
  328. package/src/resources/extensions/gsd/tests/clear-stale-autostart.test.ts +41 -0
  329. package/src/resources/extensions/gsd/tests/complete-slice-string-coercion.test.ts +36 -0
  330. package/src/resources/extensions/gsd/tests/complete-slice-verification-gate.test.ts +72 -0
  331. package/src/resources/extensions/gsd/tests/complete-task-normalize-lists.test.ts +54 -0
  332. package/src/resources/extensions/gsd/tests/defer-milestone-stamp.test.ts +30 -0
  333. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +4 -3
  334. package/src/resources/extensions/gsd/tests/discuss-incremental-persistence.test.ts +36 -0
  335. package/src/resources/extensions/gsd/tests/discuss-slice-structured-questions.test.ts +46 -0
  336. package/src/resources/extensions/gsd/tests/discuss-tool-scope-leak.test.ts +76 -0
  337. package/src/resources/extensions/gsd/tests/dispatch-guard-closed-status.test.ts +33 -0
  338. package/src/resources/extensions/gsd/tests/dispatcher-stuck-planning.test.ts +37 -0
  339. package/src/resources/extensions/gsd/tests/enhanced-verification-integration.test.ts +526 -0
  340. package/src/resources/extensions/gsd/tests/error-success-mask.test.ts +37 -0
  341. package/src/resources/extensions/gsd/tests/find-missing-summaries-closed.test.ts +48 -0
  342. package/src/resources/extensions/gsd/tests/frontmatter-parse-noise.test.ts +42 -0
  343. package/src/resources/extensions/gsd/tests/gitignore-bg-shell.test.ts +38 -0
  344. package/src/resources/extensions/gsd/tests/guided-flow-state-rebuild.test.ts +103 -0
  345. package/src/resources/extensions/gsd/tests/import-done-milestones.test.ts +42 -0
  346. package/src/resources/extensions/gsd/tests/integration/auto-recovery.test.ts +5 -3
  347. package/src/resources/extensions/gsd/tests/integration/state-machine-edge-cases.test.ts +4 -2
  348. package/src/resources/extensions/gsd/tests/integration/state-machine-live-validation.test.ts +28 -30
  349. package/src/resources/extensions/gsd/tests/integration/test-isolation.ts +53 -0
  350. package/src/resources/extensions/gsd/tests/integration-prepared-discussion.test.ts +525 -0
  351. package/src/resources/extensions/gsd/tests/isolation-none-branch-guard.test.ts +62 -0
  352. package/src/resources/extensions/gsd/tests/needs-remediation-revalidation.test.ts +48 -0
  353. package/src/resources/extensions/gsd/tests/note-captures-executed.test.ts +46 -0
  354. package/src/resources/extensions/gsd/tests/notification-overlay.test.ts +73 -0
  355. package/src/resources/extensions/gsd/tests/notification-store.test.ts +282 -0
  356. package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +77 -0
  357. package/src/resources/extensions/gsd/tests/phantom-ghost-detection.test.ts +55 -0
  358. package/src/resources/extensions/gsd/tests/phantom-milestone-default-queued.test.ts +39 -0
  359. package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +312 -0
  360. package/src/resources/extensions/gsd/tests/post-execution-checks.test.ts +813 -0
  361. package/src/resources/extensions/gsd/tests/pre-exec-backtick-strip.test.ts +68 -0
  362. package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +1197 -0
  363. package/src/resources/extensions/gsd/tests/pre-execution-fail-closed.test.ts +266 -0
  364. package/src/resources/extensions/gsd/tests/pre-execution-pause-wiring.test.ts +457 -0
  365. package/src/resources/extensions/gsd/tests/preparation.test.ts +1211 -0
  366. package/src/resources/extensions/gsd/tests/project-root-cwd-crash.test.ts +53 -0
  367. package/src/resources/extensions/gsd/tests/projection-no-plan-overwrite.test.ts +83 -0
  368. package/src/resources/extensions/gsd/tests/prompt-builder.test.ts +669 -0
  369. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +7 -4
  370. package/src/resources/extensions/gsd/tests/prompt-step-ordering.test.ts +85 -0
  371. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +2 -1
  372. package/src/resources/extensions/gsd/tests/query-tools-db-open.test.ts +47 -0
  373. package/src/resources/extensions/gsd/tests/queued-discuss-fast-path.test.ts +107 -0
  374. package/src/resources/extensions/gsd/tests/reactive-graph.test.ts +45 -0
  375. package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +63 -0
  376. package/src/resources/extensions/gsd/tests/rogue-file-detection.test.ts +4 -5
  377. package/src/resources/extensions/gsd/tests/run-uat-replay-cap.test.ts +51 -0
  378. package/src/resources/extensions/gsd/tests/show-config-command.test.ts +56 -0
  379. package/src/resources/extensions/gsd/tests/skip-slice-state-rebuild.test.ts +31 -0
  380. package/src/resources/extensions/gsd/tests/skipped-validation-completion.test.ts +39 -0
  381. package/src/resources/extensions/gsd/tests/slice-sequence-insert.test.ts +51 -0
  382. package/src/resources/extensions/gsd/tests/smart-entry-complete.test.ts +1 -1
  383. package/src/resources/extensions/gsd/tests/stale-lockfile-recovery.test.ts +36 -0
  384. package/src/resources/extensions/gsd/tests/stale-queued-milestone.test.ts +147 -0
  385. package/src/resources/extensions/gsd/tests/stale-worktree-cwd.test.ts +13 -0
  386. package/src/resources/extensions/gsd/tests/stash-pop-gsd-conflict.test.ts +21 -0
  387. package/src/resources/extensions/gsd/tests/stash-queued-context-files.test.ts +21 -0
  388. package/src/resources/extensions/gsd/tests/state-machine-full-walkthrough.test.ts +6 -7
  389. package/src/resources/extensions/gsd/tests/status-db-open.test.ts +47 -0
  390. package/src/resources/extensions/gsd/tests/stuck-detection-coverage.test.ts +1 -0
  391. package/src/resources/extensions/gsd/tests/symlink-extension-discovery.test.ts +125 -0
  392. package/src/resources/extensions/gsd/tests/sync-worktree-skip-current.test.ts +65 -0
  393. package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +29 -1
  394. package/src/resources/extensions/gsd/tests/triage-resolution.test.ts +2 -1
  395. package/src/resources/extensions/gsd/tests/unstructured-continue-context-injection.test.ts +163 -0
  396. package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +3 -4
  397. package/src/resources/extensions/gsd/tests/verification-operational-gate.test.ts +15 -0
  398. package/src/resources/extensions/gsd/tests/verify-artifact-tightened.test.ts +89 -0
  399. package/src/resources/extensions/gsd/tests/worker-model-override.test.ts +48 -0
  400. package/src/resources/extensions/gsd/tests/worktree-expected-warnings.test.ts +38 -0
  401. package/src/resources/extensions/gsd/tests/worktree-integration.test.ts +16 -0
  402. package/src/resources/extensions/gsd/tests/worktree-main-branch.test.ts +20 -0
  403. package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +16 -17
  404. package/src/resources/extensions/gsd/tests/worktree-sync-tasks.test.ts +13 -9
  405. package/src/resources/extensions/gsd/tests/worktree.test.ts +26 -9
  406. package/src/resources/extensions/gsd/tests/zero-slice-roadmap-guided.test.ts +19 -0
  407. package/src/resources/extensions/gsd/tools/complete-slice.ts +13 -3
  408. package/src/resources/extensions/gsd/tools/complete-task.ts +16 -4
  409. package/src/resources/extensions/gsd/tools/plan-milestone.ts +11 -9
  410. package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +5 -2
  411. package/src/resources/extensions/gsd/tools/reopen-milestone.ts +152 -0
  412. package/src/resources/extensions/gsd/tools/reopen-slice.ts +27 -0
  413. package/src/resources/extensions/gsd/tools/reopen-task.ts +17 -0
  414. package/src/resources/extensions/gsd/triage-resolution.ts +29 -10
  415. package/src/resources/extensions/gsd/types.ts +4 -0
  416. package/src/resources/extensions/gsd/verification-evidence.ts +68 -0
  417. package/src/resources/extensions/gsd/workflow-logger.ts +13 -0
  418. package/src/resources/extensions/gsd/workflow-projections.ts +4 -6
  419. package/src/resources/extensions/gsd/workflow-reconcile.ts +2 -3
  420. package/src/resources/extensions/gsd/workflow-templates.ts +11 -2
  421. package/src/resources/extensions/gsd/worktree-manager.ts +4 -2
  422. package/src/resources/extensions/gsd/worktree.ts +10 -0
  423. package/src/resources/extensions/shared/interview-ui.ts +1 -1
  424. package/src/resources/extensions/shared/tests/interview-notes-loop.test.ts +8 -10
  425. package/dist/web/standalone/.next/static/F1mOwzgCW9R8N3Pt1Et87/_buildManifest.js +0 -1
  426. package/dist/web/standalone/.next/static/chunks/6502.7593d7797a4b3999.js +0 -9
  427. package/dist/web/standalone/.next/static/chunks/app/_global-error/page-c4cc189e7b117ea2.js +0 -1
  428. package/dist/web/standalone/.next/static/chunks/app/api/boot/route-c4cc189e7b117ea2.js +0 -1
  429. package/dist/web/standalone/.next/static/chunks/app/api/bridge-terminal/input/route-c4cc189e7b117ea2.js +0 -1
  430. package/dist/web/standalone/.next/static/chunks/app/api/bridge-terminal/resize/route-c4cc189e7b117ea2.js +0 -1
  431. package/dist/web/standalone/.next/static/chunks/app/api/bridge-terminal/stream/route-c4cc189e7b117ea2.js +0 -1
  432. package/dist/web/standalone/.next/static/chunks/app/api/browse-directories/route-c4cc189e7b117ea2.js +0 -1
  433. package/dist/web/standalone/.next/static/chunks/app/api/captures/route-c4cc189e7b117ea2.js +0 -1
  434. package/dist/web/standalone/.next/static/chunks/app/api/cleanup/route-c4cc189e7b117ea2.js +0 -1
  435. package/dist/web/standalone/.next/static/chunks/app/api/dev-mode/route-c4cc189e7b117ea2.js +0 -1
  436. package/dist/web/standalone/.next/static/chunks/app/api/doctor/route-c4cc189e7b117ea2.js +0 -1
  437. package/dist/web/standalone/.next/static/chunks/app/api/experimental/route-c4cc189e7b117ea2.js +0 -1
  438. package/dist/web/standalone/.next/static/chunks/app/api/export-data/route-c4cc189e7b117ea2.js +0 -1
  439. package/dist/web/standalone/.next/static/chunks/app/api/files/route-c4cc189e7b117ea2.js +0 -1
  440. package/dist/web/standalone/.next/static/chunks/app/api/forensics/route-c4cc189e7b117ea2.js +0 -1
  441. package/dist/web/standalone/.next/static/chunks/app/api/git/route-c4cc189e7b117ea2.js +0 -1
  442. package/dist/web/standalone/.next/static/chunks/app/api/history/route-c4cc189e7b117ea2.js +0 -1
  443. package/dist/web/standalone/.next/static/chunks/app/api/hooks/route-c4cc189e7b117ea2.js +0 -1
  444. package/dist/web/standalone/.next/static/chunks/app/api/inspect/route-c4cc189e7b117ea2.js +0 -1
  445. package/dist/web/standalone/.next/static/chunks/app/api/knowledge/route-c4cc189e7b117ea2.js +0 -1
  446. package/dist/web/standalone/.next/static/chunks/app/api/live-state/route-c4cc189e7b117ea2.js +0 -1
  447. package/dist/web/standalone/.next/static/chunks/app/api/onboarding/route-c4cc189e7b117ea2.js +0 -1
  448. package/dist/web/standalone/.next/static/chunks/app/api/preferences/route-c4cc189e7b117ea2.js +0 -1
  449. package/dist/web/standalone/.next/static/chunks/app/api/projects/route-c4cc189e7b117ea2.js +0 -1
  450. package/dist/web/standalone/.next/static/chunks/app/api/recovery/route-c4cc189e7b117ea2.js +0 -1
  451. package/dist/web/standalone/.next/static/chunks/app/api/remote-questions/route-c4cc189e7b117ea2.js +0 -1
  452. package/dist/web/standalone/.next/static/chunks/app/api/session/browser/route-c4cc189e7b117ea2.js +0 -1
  453. package/dist/web/standalone/.next/static/chunks/app/api/session/command/route-c4cc189e7b117ea2.js +0 -1
  454. package/dist/web/standalone/.next/static/chunks/app/api/session/events/route-c4cc189e7b117ea2.js +0 -1
  455. package/dist/web/standalone/.next/static/chunks/app/api/session/manage/route-c4cc189e7b117ea2.js +0 -1
  456. package/dist/web/standalone/.next/static/chunks/app/api/settings-data/route-c4cc189e7b117ea2.js +0 -1
  457. package/dist/web/standalone/.next/static/chunks/app/api/shutdown/route-c4cc189e7b117ea2.js +0 -1
  458. package/dist/web/standalone/.next/static/chunks/app/api/skill-health/route-c4cc189e7b117ea2.js +0 -1
  459. package/dist/web/standalone/.next/static/chunks/app/api/steer/route-c4cc189e7b117ea2.js +0 -1
  460. package/dist/web/standalone/.next/static/chunks/app/api/switch-root/route-c4cc189e7b117ea2.js +0 -1
  461. package/dist/web/standalone/.next/static/chunks/app/api/terminal/input/route-c4cc189e7b117ea2.js +0 -1
  462. package/dist/web/standalone/.next/static/chunks/app/api/terminal/resize/route-c4cc189e7b117ea2.js +0 -1
  463. package/dist/web/standalone/.next/static/chunks/app/api/terminal/sessions/route-c4cc189e7b117ea2.js +0 -1
  464. package/dist/web/standalone/.next/static/chunks/app/api/terminal/stream/route-c4cc189e7b117ea2.js +0 -1
  465. package/dist/web/standalone/.next/static/chunks/app/api/terminal/upload/route-c4cc189e7b117ea2.js +0 -1
  466. package/dist/web/standalone/.next/static/chunks/app/api/undo/route-c4cc189e7b117ea2.js +0 -1
  467. package/dist/web/standalone/.next/static/chunks/app/api/update/route-c4cc189e7b117ea2.js +0 -1
  468. package/dist/web/standalone/.next/static/chunks/app/api/visualizer/route-c4cc189e7b117ea2.js +0 -1
  469. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/app-error-c4cc189e7b117ea2.js +0 -1
  470. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/forbidden-c4cc189e7b117ea2.js +0 -1
  471. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/not-found-c4cc189e7b117ea2.js +0 -1
  472. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/unauthorized-c4cc189e7b117ea2.js +0 -1
  473. /package/dist/web/standalone/.next/static/{F1mOwzgCW9R8N3Pt1Et87 → Z3TgDP0c7kG9j8CVQVGcl}/_ssgManifest.js +0 -0
@@ -754,6 +754,7 @@ export async function buildDiscussMilestonePrompt(mid, midTitle, base) {
754
754
  inlinedTemplates: discussTemplates,
755
755
  structuredQuestionsAvailable: "true",
756
756
  commitInstruction: "Do not commit planning artifacts — .gsd/ is managed externally.",
757
+ fastPathInstruction: "",
757
758
  });
758
759
  // If a CONTEXT-DRAFT.md exists, append it as seed material
759
760
  const draftPath = resolveMilestoneFile(base, mid, "CONTEXT-DRAFT");
@@ -1607,6 +1608,29 @@ const GATE_QUESTIONS = {
1607
1608
  ].join("\n"),
1608
1609
  },
1609
1610
  };
1611
+ export async function buildParallelResearchSlicesPrompt(mid, midTitle, slices, basePath) {
1612
+ // Build individual research-slice prompts for each slice
1613
+ const subagentSections = [];
1614
+ for (const slice of slices) {
1615
+ const slicePrompt = await buildResearchSlicePrompt(mid, midTitle, slice.id, slice.title, basePath);
1616
+ subagentSections.push([
1617
+ `### ${slice.id}: ${slice.title}`,
1618
+ "",
1619
+ "Use this as the prompt for a `subagent` call (agent: `gsd-executor` or the default agent):",
1620
+ "",
1621
+ "```",
1622
+ slicePrompt,
1623
+ "```",
1624
+ ].join("\n"));
1625
+ }
1626
+ return loadPrompt("parallel-research-slices", {
1627
+ mid,
1628
+ midTitle,
1629
+ sliceCount: String(slices.length),
1630
+ sliceList: slices.map((s) => `- **${s.id}**: ${s.title}`).join("\n"),
1631
+ subagentPrompts: subagentSections.join("\n\n---\n\n"),
1632
+ });
1633
+ }
1610
1634
  export async function buildGateEvaluatePrompt(mid, midTitle, sid, sTitle, base) {
1611
1635
  const pending = getPendingGates(mid, sid, "slice");
1612
1636
  // Load the slice plan for context
@@ -238,7 +238,7 @@ export function verifyExpectedArtifact(unitType, unitId, base) {
238
238
  if (!hasCheckboxTask && !hasHeadingTask)
239
239
  return false;
240
240
  }
241
- // execute-task: DB status is authoritative. Fall back to heading-style plan
241
+ // execute-task: DB status is authoritative. Fall back to checked-checkbox
242
242
  // detection when the DB is unavailable (unmigrated projects).
243
243
  if (unitType === "execute-task") {
244
244
  const { milestone: mid, slice: sid, task: tid } = parseUnitId(unitId);
@@ -251,21 +251,25 @@ export function verifyExpectedArtifact(unitType, unitId, base) {
251
251
  }
252
252
  else if (!isDbAvailable()) {
253
253
  // LEGACY: Pre-migration fallback for projects without DB.
254
- // Fall back to plan heading check (format detection, not reconciliation).
255
- // Heading-style entries (### T01 --) count as verified because the
256
- // summary file existence (checked above) is the real signal.
254
+ // Require a CHECKED checkbox a bare heading or unchecked checkbox
255
+ // does not prove gsd_complete_task ran. Summary file on disk alone
256
+ // is not sufficient evidence (could be a rogue write) (#3607).
257
257
  const planAbs = resolveSliceFile(base, mid, sid, "PLAN");
258
258
  if (planAbs && existsSync(planAbs)) {
259
259
  const planContent = readFileSync(planAbs, "utf-8");
260
260
  const escapedTid = tid.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
261
- const hdRe = new RegExp(`^#{2,4}\\s+${escapedTid}\\s*(?:--|—|:)`, "m");
262
261
  const cbRe = new RegExp(`^- \\[[xX]\\] \\*\\*${escapedTid}:`, "m");
263
- if (!hdRe.test(planContent) && !cbRe.test(planContent))
262
+ if (!cbRe.test(planContent))
264
263
  return false;
265
264
  }
265
+ else {
266
+ return false; // no plan file → cannot verify
267
+ }
268
+ }
269
+ else {
270
+ // DB available but task row not found — completion tool never ran (#3607)
271
+ return false;
266
272
  }
267
- // else: DB available but task not found — summary file exists (checked above),
268
- // so treat as verified (task may not be imported yet)
269
273
  }
270
274
  }
271
275
  // plan-slice must also produce individual task plan files for every task listed
@@ -20,7 +20,7 @@ import { synthesizeCrashRecovery } from "./session-forensics.js";
20
20
  import { writeLock, clearLock, readCrashLock, formatCrashInfo, isLockProcessAlive, } from "./crash-recovery.js";
21
21
  import { acquireSessionLock, releaseSessionLock, updateSessionLock, } from "./session-lock.js";
22
22
  import { ensureGitignore, untrackRuntimeFiles } from "./gitignore.js";
23
- import { nativeInit, nativeAddAll, nativeCommit, } from "./native-git-bridge.js";
23
+ import { nativeIsRepo, nativeInit, nativeAddAll, nativeCommit, nativeGetCurrentBranch, nativeDetectMainBranch, nativeCheckoutBranch, } from "./native-git-bridge.js";
24
24
  import { GitServiceImpl } from "./git-service.js";
25
25
  import { captureIntegrationBranch, detectWorktreeName, setActiveMilestoneId, } from "./worktree.js";
26
26
  import { getAutoWorktreePath } from "./auto-worktree.js";
@@ -373,6 +373,22 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
373
373
  }
374
374
  setActiveMilestoneId(base, s.currentMilestoneId);
375
375
  }
376
+ // Guard against stale milestone branch when isolation:none (#3613).
377
+ // A prior session with isolation:branch/worktree may have left HEAD on
378
+ // milestone/<MID>. Auto-checkout back to the integration branch.
379
+ if (getIsolationMode() === "none" && nativeIsRepo(base)) {
380
+ try {
381
+ const currentBranch = nativeGetCurrentBranch(base);
382
+ if (currentBranch.startsWith("milestone/")) {
383
+ const integrationBranch = nativeDetectMainBranch(base);
384
+ nativeCheckoutBranch(base, integrationBranch);
385
+ logWarning("bootstrap", `Returned to "${integrationBranch}" — HEAD was on stale milestone branch "${currentBranch}" (isolation: none does not use milestone branches).`);
386
+ }
387
+ }
388
+ catch (err) {
389
+ logWarning("bootstrap", `Could not auto-checkout from stale milestone branch: ${err instanceof Error ? err.message : String(err)}`);
390
+ }
391
+ }
376
392
  // ── Auto-worktree setup ──
377
393
  s.originalBasePath = base;
378
394
  const isUnderGsdWorktrees = (p) => {
@@ -448,6 +464,24 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
448
464
  id: startModelSnapshot.id,
449
465
  };
450
466
  }
467
+ // Apply worker model override from parallel orchestrator (#worker-model).
468
+ // GSD_WORKER_MODEL is injected by the coordinator when parallel.worker_model
469
+ // is configured, so parallel milestone workers use a cheaper model than the
470
+ // coordinator session (e.g. Haiku for execution, Sonnet for planning).
471
+ const workerModelOverride = process.env.GSD_WORKER_MODEL;
472
+ if (workerModelOverride && process.env.GSD_PARALLEL_WORKER === "1") {
473
+ const availableModels = ctx.modelRegistry.getAvailable();
474
+ const { resolveModelId } = await import("./auto-model-selection.js");
475
+ const overrideModel = resolveModelId(workerModelOverride, availableModels, ctx.model?.provider);
476
+ if (overrideModel) {
477
+ const ok = await pi.setModel(overrideModel, { persist: false });
478
+ if (ok) {
479
+ // Update start model so all subsequent units use this as the baseline
480
+ s.autoModeStartModel = { provider: overrideModel.provider, id: overrideModel.id };
481
+ ctx.ui.notify(`Worker model override: ${overrideModel.provider}/${overrideModel.id}`, "info");
482
+ }
483
+ }
484
+ }
451
485
  // Snapshot installed skills
452
486
  if (resolveSkillDiscoveryMode() !== "off") {
453
487
  snapshotSkills();
@@ -92,3 +92,13 @@ export function isToolInvocationError(errorMsg) {
92
92
  return false;
93
93
  return TOOL_INVOCATION_ERROR_RE.test(errorMsg);
94
94
  }
95
+ /**
96
+ * Returns true if the error message indicates the tool was skipped because
97
+ * a queued user message interrupted the turn (#3595). Retrying will produce
98
+ * the same skip, so the unit should be paused rather than retried.
99
+ */
100
+ export function isQueuedUserMessageSkip(errorMsg) {
101
+ if (!errorMsg)
102
+ return false;
103
+ return /^Skipped due to queued user message\.?$/i.test(errorMsg.trim());
104
+ }
@@ -9,13 +9,15 @@
9
9
  * value instead of calling return/pauseAuto directly — the caller
10
10
  * checks the result and handles control flow.
11
11
  */
12
+ import { mkdirSync, writeFileSync } from "node:fs";
12
13
  import { resolveSlicePath } from "./paths.js";
13
14
  import { parseUnitId } from "./unit-id.js";
14
- import { isDbAvailable, getTask } from "./gsd-db.js";
15
+ import { isDbAvailable, getTask, getSliceTasks } from "./gsd-db.js";
15
16
  import { loadEffectiveGSDPreferences } from "./preferences.js";
16
17
  import { runVerificationGate, formatFailureContext, captureRuntimeErrors, runDependencyAudit, } from "./verification-gate.js";
17
18
  import { writeVerificationJSON } from "./verification-evidence.js";
18
19
  import { logWarning } from "./workflow-logger.js";
20
+ import { runPostExecutionChecks } from "./post-execution-checks.js";
19
21
  import { join } from "node:path";
20
22
  function isInfraVerificationFailure(stderr) {
21
23
  return /\b(ENOENT|ENOTFOUND|ETIMEDOUT|ECONNRESET|EAI_AGAIN|spawn\s+\S+\s+ENOENT|command not found)\b/i.test(stderr);
@@ -128,12 +130,104 @@ export async function runPostUnitVerification(vctx, pauseAuto) {
128
130
  : "Verification failed due to infrastructure/runtime environment issues — treating as advisory.", "warning");
129
131
  return "continue";
130
132
  }
133
+ // ── Post-execution checks (run after main verification passes for execute-task units) ──
134
+ let postExecChecks;
135
+ let postExecBlockingFailure = false;
136
+ if (result.passed && mid && sid && tid) {
137
+ // Check preferences — respect enhanced_verification and enhanced_verification_post
138
+ const enhancedEnabled = prefs?.enhanced_verification !== false; // default true
139
+ const postEnabled = prefs?.enhanced_verification_post !== false; // default true
140
+ if (enhancedEnabled && postEnabled && isDbAvailable()) {
141
+ try {
142
+ // Get the completed task from DB
143
+ const taskRow = getTask(mid, sid, tid);
144
+ if (taskRow && taskRow.key_files && taskRow.key_files.length > 0) {
145
+ // Get all tasks in the slice
146
+ const allTasks = getSliceTasks(mid, sid);
147
+ // Filter to prior completed tasks (status = 'complete' or 'done', before current task)
148
+ const priorTasks = allTasks.filter((t) => (t.status === "complete" || t.status === "done") &&
149
+ t.id !== tid &&
150
+ t.sequence < taskRow.sequence);
151
+ // Run post-execution checks
152
+ const postExecResult = runPostExecutionChecks(taskRow, priorTasks, s.basePath);
153
+ // Store checks for evidence JSON
154
+ postExecChecks = postExecResult.checks;
155
+ // Log summary to stderr with gsd-post-exec: prefix
156
+ const emoji = postExecResult.status === "pass"
157
+ ? "✅"
158
+ : postExecResult.status === "warn"
159
+ ? "⚠️"
160
+ : "❌";
161
+ process.stderr.write(`gsd-post-exec: ${emoji} Post-execution checks ${postExecResult.status} for ${mid}/${sid}/${tid} (${postExecResult.durationMs}ms)\n`);
162
+ // Log individual check results
163
+ for (const check of postExecResult.checks) {
164
+ const checkEmoji = check.passed
165
+ ? "✓"
166
+ : check.blocking
167
+ ? "✗"
168
+ : "⚠";
169
+ process.stderr.write(`gsd-post-exec: ${checkEmoji} [${check.category}] ${check.target}: ${check.message}\n`);
170
+ }
171
+ // Check for blocking failures
172
+ if (postExecResult.status === "fail") {
173
+ postExecBlockingFailure = true;
174
+ const blockingCount = postExecResult.checks.filter((c) => !c.passed && c.blocking).length;
175
+ ctx.ui.notify(`Post-execution checks failed: ${blockingCount} blocking issue${blockingCount === 1 ? "" : "s"} found`, "error");
176
+ }
177
+ else if (postExecResult.status === "warn") {
178
+ ctx.ui.notify(`Post-execution checks passed with warnings`, "warning");
179
+ // Strict mode: treat warnings as blocking
180
+ if (prefs?.enhanced_verification_strict === true) {
181
+ postExecBlockingFailure = true;
182
+ }
183
+ }
184
+ }
185
+ }
186
+ catch (postExecErr) {
187
+ // Post-execution check errors are non-fatal — log and continue
188
+ logWarning("engine", `gsd-post-exec: error — ${postExecErr.message}`);
189
+ }
190
+ }
191
+ }
192
+ // Re-write verification evidence JSON with post-execution checks
193
+ if (postExecChecks && postExecChecks.length > 0 && mid && sid && tid) {
194
+ try {
195
+ const sDir = resolveSlicePath(s.basePath, mid, sid);
196
+ if (sDir) {
197
+ const tasksDir = join(sDir, "tasks");
198
+ // Add postExecutionChecks to the result for the JSON write
199
+ const resultWithPostExec = {
200
+ ...result,
201
+ // Mark as failed if there was a blocking post-exec failure
202
+ passed: result.passed && !postExecBlockingFailure,
203
+ };
204
+ // Manually write with postExecutionChecks field
205
+ writeVerificationJSONWithPostExec(resultWithPostExec, tasksDir, tid, s.currentUnit.id, postExecChecks, postExecBlockingFailure ? attempt + 1 : undefined, postExecBlockingFailure ? maxRetries : undefined);
206
+ }
207
+ }
208
+ catch (evidenceErr) {
209
+ logWarning("engine", `verification-evidence: post-exec write error — ${evidenceErr.message}`);
210
+ }
211
+ }
212
+ // Update result.passed based on post-execution checks
213
+ if (postExecBlockingFailure) {
214
+ result.passed = false;
215
+ }
131
216
  // ── Auto-fix retry logic ──
132
217
  if (result.passed) {
133
218
  s.verificationRetryCount.delete(s.currentUnit.id);
134
219
  s.pendingVerificationRetry = null;
135
220
  return "continue";
136
221
  }
222
+ else if (postExecBlockingFailure) {
223
+ // Post-execution failures are cross-task consistency issues — retrying the same task won't fix them.
224
+ // Skip retry and pause immediately for human review.
225
+ s.verificationRetryCount.delete(s.currentUnit.id);
226
+ s.pendingVerificationRetry = null;
227
+ ctx.ui.notify(`Post-execution checks failed — cross-task consistency issue detected, pausing for human review`, "error");
228
+ await pauseAuto(ctx, pi);
229
+ return "pause";
230
+ }
137
231
  else if (autoFixEnabled && attempt + 1 <= maxRetries) {
138
232
  const nextAttempt = attempt + 1;
139
233
  s.verificationRetryCount.set(s.currentUnit.id, nextAttempt);
@@ -173,3 +267,46 @@ export async function runPostUnitVerification(vctx, pauseAuto) {
173
267
  return "continue";
174
268
  }
175
269
  }
270
+ /**
271
+ * Write verification evidence JSON with post-execution checks included.
272
+ * This is a variant of writeVerificationJSON that adds the postExecutionChecks field.
273
+ */
274
+ function writeVerificationJSONWithPostExec(result, tasksDir, taskId, unitId, postExecutionChecks, retryAttempt, maxRetries) {
275
+ mkdirSync(tasksDir, { recursive: true });
276
+ const evidence = {
277
+ schemaVersion: 1,
278
+ taskId,
279
+ unitId: unitId ?? taskId,
280
+ timestamp: result.timestamp,
281
+ passed: result.passed,
282
+ discoverySource: result.discoverySource,
283
+ checks: result.checks.map((check) => ({
284
+ command: check.command,
285
+ exitCode: check.exitCode,
286
+ durationMs: check.durationMs,
287
+ verdict: check.exitCode === 0 ? "pass" : "fail",
288
+ })),
289
+ ...(retryAttempt !== undefined ? { retryAttempt } : {}),
290
+ ...(maxRetries !== undefined ? { maxRetries } : {}),
291
+ postExecutionChecks,
292
+ };
293
+ if (result.runtimeErrors && result.runtimeErrors.length > 0) {
294
+ evidence.runtimeErrors = result.runtimeErrors.map(e => ({
295
+ source: e.source,
296
+ severity: e.severity,
297
+ message: e.message,
298
+ blocking: e.blocking,
299
+ }));
300
+ }
301
+ if (result.auditWarnings && result.auditWarnings.length > 0) {
302
+ evidence.auditWarnings = result.auditWarnings.map(w => ({
303
+ name: w.name,
304
+ severity: w.severity,
305
+ title: w.title,
306
+ url: w.url,
307
+ fixAvailable: w.fixAvailable,
308
+ }));
309
+ }
310
+ const filePath = join(tasksDir, `${taskId}-VERIFY.json`);
311
+ writeFileSync(filePath, JSON.stringify(evidence, null, 2) + "\n", "utf-8");
312
+ }
@@ -135,8 +135,10 @@ function clearProjectRootStateFiles(basePath, milestoneId) {
135
135
  unlinkSync(file);
136
136
  }
137
137
  catch (err) {
138
- /* non-fatal — file may not exist */
139
- logWarning("worktree", `file unlink failed: ${err instanceof Error ? err.message : String(err)}`);
138
+ // ENOENT is expected — file may not exist (#3597)
139
+ if (err.code !== "ENOENT") {
140
+ logWarning("worktree", `file unlink failed: ${err instanceof Error ? err.message : String(err)}`);
141
+ }
140
142
  }
141
143
  }
142
144
  // Clean up entire synced milestone directory and runtime/units.
@@ -160,8 +162,11 @@ function clearProjectRootStateFiles(basePath, milestoneId) {
160
162
  unlinkSync(join(basePath, f));
161
163
  }
162
164
  catch (err) {
163
- /* non-fatal */
164
- logWarning("worktree", `untracked file unlink failed: ${err instanceof Error ? err.message : String(err)}`);
165
+ // ENOENT/EISDIR are expected for already-removed or directory entries (#3597)
166
+ const code = err.code;
167
+ if (code !== "ENOENT" && code !== "EISDIR") {
168
+ logWarning("worktree", `untracked file unlink failed: ${err instanceof Error ? err.message : String(err)}`);
169
+ }
165
170
  }
166
171
  }
167
172
  }
@@ -656,6 +661,10 @@ export function syncWorktreeStateBack(mainBasePath, worktreePath, milestoneId) {
656
661
  .filter((d) => d.isDirectory())
657
662
  .map((d) => d.name);
658
663
  for (const mid of wtMilestones) {
664
+ // Skip the current milestone being merged — its files are already in the
665
+ // milestone branch and would conflict with the squash merge (#3641).
666
+ if (mid === milestoneId)
667
+ continue;
659
668
  syncMilestoneDir(wtGsd, mainGsd, mid, synced);
660
669
  }
661
670
  }
@@ -901,11 +910,19 @@ export function createAutoWorktree(basePath, milestoneId) {
901
910
  });
902
911
  }
903
912
  else {
904
- // Fresh start — create branch from integration branch
913
+ // Fresh start — create branch from integration branch.
914
+ // Use the same 3-tier fallback as mergeMilestoneToMain (#3461):
915
+ // 1. META.json integration branch (explicit per-milestone override)
916
+ // 2. git.main_branch preference (user's configured working branch)
917
+ // 3. nativeDetectMainBranch (origin/HEAD auto-detection)
918
+ // Without tier 2, projects with main_branch=dev but origin/HEAD→master
919
+ // would fork worktrees from the wrong (stale) branch.
905
920
  const integrationBranch = readIntegrationBranch(basePath, milestoneId) ?? undefined;
921
+ const gitPrefs = loadEffectiveGSDPreferences()?.preferences?.git;
922
+ const startPoint = integrationBranch ?? gitPrefs?.main_branch ?? undefined;
906
923
  info = createWorktree(basePath, milestoneId, {
907
924
  branch,
908
- startPoint: integrationBranch,
925
+ startPoint,
909
926
  });
910
927
  }
911
928
  // Copy .gsd/ planning artifacts from the source repo into the new worktree.
@@ -1235,7 +1252,12 @@ export function mergeMilestoneToMain(originalBasePath_, milestoneId, roadmapCont
1235
1252
  // checkout and leave the user with a broken merge state (#1668).
1236
1253
  const prefs = loadEffectiveGSDPreferences()?.preferences?.git ?? {};
1237
1254
  const integrationBranch = readIntegrationBranch(originalBasePath_, milestoneId);
1238
- const mainBranch = integrationBranch ?? prefs.main_branch ?? nativeDetectMainBranch(originalBasePath_);
1255
+ // Validate prefs.main_branch exists before using it — a stale preference
1256
+ // (e.g. "master" when repo uses "main") causes merge failure (#3589).
1257
+ const validatedPrefBranch = prefs.main_branch && nativeBranchExists(originalBasePath_, prefs.main_branch)
1258
+ ? prefs.main_branch
1259
+ : undefined;
1260
+ const mainBranch = integrationBranch ?? validatedPrefBranch ?? nativeDetectMainBranch(originalBasePath_);
1239
1261
  // Remove transient project-root state files before any branch or merge
1240
1262
  // operation. Untracked milestone metadata can otherwise block squash merges.
1241
1263
  clearProjectRootStateFiles(originalBasePath_, milestoneId);
@@ -23,7 +23,7 @@ import { acquireSessionLock, getSessionLockStatus, releaseSessionLock, updateSes
23
23
  import { resolveAutoSupervisorConfig, loadEffectiveGSDPreferences, getIsolationMode, } from "./preferences.js";
24
24
  import { sendDesktopNotification } from "./notifications.js";
25
25
  import { getBudgetAlertLevel, getNewBudgetAlertLevel, getBudgetEnforcementAction, } from "./auto-budget.js";
26
- import { markToolStart as _markToolStart, markToolEnd as _markToolEnd, getOldestInFlightToolAgeMs as _getOldestInFlightToolAgeMs, clearInFlightTools, isToolInvocationError, } from "./auto-tool-tracking.js";
26
+ import { markToolStart as _markToolStart, markToolEnd as _markToolEnd, getOldestInFlightToolAgeMs as _getOldestInFlightToolAgeMs, clearInFlightTools, isToolInvocationError, isQueuedUserMessageSkip, } from "./auto-tool-tracking.js";
27
27
  import { closeoutUnit } from "./auto-unit-closeout.js";
28
28
  import { selectAndApplyModel, resolveModelId } from "./auto-model-selection.js";
29
29
  import { resetRoutingHistory, recordOutcome } from "./routing-history.js";
@@ -201,7 +201,7 @@ export function markToolEnd(toolCallId) {
201
201
  export function recordToolInvocationError(toolName, errorMsg) {
202
202
  if (!s.active)
203
203
  return;
204
- if (isToolInvocationError(errorMsg)) {
204
+ if (isToolInvocationError(errorMsg) || isQueuedUserMessageSkip(errorMsg)) {
205
205
  s.lastToolInvocationError = `${toolName}: ${errorMsg}`;
206
206
  }
207
207
  }
@@ -79,11 +79,24 @@ export async function handleAgentEnd(pi, event, ctx) {
79
79
  return;
80
80
  }
81
81
  if (lastMsg && "stopReason" in lastMsg && lastMsg.stopReason === "error") {
82
- const errorDetail = "errorMessage" in lastMsg && lastMsg.errorMessage ? `: ${lastMsg.errorMessage}` : "";
83
- const errorMsg = ("errorMessage" in lastMsg && lastMsg.errorMessage) ? String(lastMsg.errorMessage) : "";
82
+ // #3588: errorMessage can be useless (e.g. "success") while the real error
83
+ // is in the assistant message text content. Fall back to content when
84
+ // errorMessage looks uninformative.
85
+ const rawErrorMsg = ("errorMessage" in lastMsg && lastMsg.errorMessage) ? String(lastMsg.errorMessage) : "";
86
+ const isUseless = !rawErrorMsg || /^(success|ok|true|error|unknown)$/i.test(rawErrorMsg.trim());
87
+ // #3588: When errorMessage is uninformative, extract the real error from
88
+ // the assistant message text content for display purposes only.
89
+ // Classification still uses rawErrorMsg to avoid false positives from prose.
90
+ let displayMsg = rawErrorMsg;
91
+ if (isUseless && "content" in lastMsg && Array.isArray(lastMsg.content)) {
92
+ const textBlock = lastMsg.content.find((b) => b.type === "text" && b.text);
93
+ if (textBlock)
94
+ displayMsg = textBlock.text.slice(0, 300);
95
+ }
96
+ const errorDetail = displayMsg ? `: ${displayMsg}` : "";
84
97
  const explicitRetryAfterMs = ("retryAfterMs" in lastMsg && typeof lastMsg.retryAfterMs === "number") ? lastMsg.retryAfterMs : undefined;
85
- // ── 1. Classify ──────────────────────────────────────────────────────
86
- const cls = classifyError(errorMsg, explicitRetryAfterMs);
98
+ // ── 1. Classify using rawErrorMsg to avoid prose false-positives ────
99
+ const cls = classifyError(rawErrorMsg, explicitRetryAfterMs);
87
100
  // Cap rate-limit backoff for CLI-style providers (openai-codex, google-gemini-cli)
88
101
  // which use per-user quotas with shorter windows (#2922).
89
102
  if (cls.kind === "rate-limit") {
@@ -768,31 +768,42 @@ export function registerDbTools(pi) {
768
768
  return m ? [m[1].trim(), m[2].trim()] : [s.trim(), ""];
769
769
  };
770
770
  const coerced = { ...params };
771
- coerced.filesModified = (params.filesModified ?? []).map((f) => {
771
+ // Coerce simple string-array fields: LLMs sometimes pass a plain string
772
+ // instead of a single-element array (#3585).
773
+ const wrapArray = (v) => v == null ? [] : Array.isArray(v) ? v : [v];
774
+ coerced.provides = wrapArray(params.provides);
775
+ coerced.keyFiles = wrapArray(params.keyFiles);
776
+ coerced.keyDecisions = wrapArray(params.keyDecisions);
777
+ coerced.patternsEstablished = wrapArray(params.patternsEstablished);
778
+ coerced.observabilitySurfaces = wrapArray(params.observabilitySurfaces);
779
+ coerced.requirementsSurfaced = wrapArray(params.requirementsSurfaced);
780
+ coerced.drillDownPaths = wrapArray(params.drillDownPaths);
781
+ coerced.affects = wrapArray(params.affects);
782
+ coerced.filesModified = wrapArray(params.filesModified).map((f) => {
772
783
  if (typeof f !== "string")
773
784
  return f;
774
785
  const [path, description] = splitPair(f);
775
786
  return { path, description };
776
787
  });
777
- coerced.requires = (params.requires ?? []).map((r) => {
788
+ coerced.requires = wrapArray(params.requires).map((r) => {
778
789
  if (typeof r !== "string")
779
790
  return r;
780
791
  const [slice, provides] = splitPair(r);
781
792
  return { slice, provides };
782
793
  });
783
- coerced.requirementsAdvanced = (params.requirementsAdvanced ?? []).map((r) => {
794
+ coerced.requirementsAdvanced = wrapArray(params.requirementsAdvanced).map((r) => {
784
795
  if (typeof r !== "string")
785
796
  return r;
786
797
  const [id, how] = splitPair(r);
787
798
  return { id, how };
788
799
  });
789
- coerced.requirementsValidated = (params.requirementsValidated ?? []).map((r) => {
800
+ coerced.requirementsValidated = wrapArray(params.requirementsValidated).map((r) => {
790
801
  if (typeof r !== "string")
791
802
  return r;
792
803
  const [id, proof] = splitPair(r);
793
804
  return { id, proof };
794
805
  });
795
- coerced.requirementsInvalidated = (params.requirementsInvalidated ?? []).map((r) => {
806
+ coerced.requirementsInvalidated = wrapArray(params.requirementsInvalidated).map((r) => {
796
807
  if (typeof r !== "string")
797
808
  return r;
798
809
  const [id, what] = splitPair(r);
@@ -851,14 +862,14 @@ export function registerDbTools(pi) {
851
862
  deviations: Type.Optional(Type.String({ description: "Deviations from the slice plan, or 'None.'" })),
852
863
  knownLimitations: Type.Optional(Type.String({ description: "Known limitations or gaps, or 'None.'" })),
853
864
  followUps: Type.Optional(Type.String({ description: "Follow-up work discovered during execution, or 'None.'" })),
854
- keyFiles: Type.Optional(Type.Array(Type.String(), { description: "Key files created or modified" })),
855
- keyDecisions: Type.Optional(Type.Array(Type.String(), { description: "Key decisions made during this slice" })),
856
- patternsEstablished: Type.Optional(Type.Array(Type.String(), { description: "Patterns established by this slice" })),
857
- observabilitySurfaces: Type.Optional(Type.Array(Type.String(), { description: "Observability surfaces added" })),
858
- provides: Type.Optional(Type.Array(Type.String(), { description: "What this slice provides to downstream slices" })),
859
- requirementsSurfaced: Type.Optional(Type.Array(Type.String(), { description: "New requirements surfaced" })),
860
- drillDownPaths: Type.Optional(Type.Array(Type.String(), { description: "Paths to task summaries for drill-down" })),
861
- affects: Type.Optional(Type.Array(Type.String(), { description: "Downstream slices affected" })),
865
+ keyFiles: Type.Optional(Type.Union([Type.Array(Type.String()), Type.String()], { description: "Key files created or modified" })),
866
+ keyDecisions: Type.Optional(Type.Union([Type.Array(Type.String()), Type.String()], { description: "Key decisions made during this slice" })),
867
+ patternsEstablished: Type.Optional(Type.Union([Type.Array(Type.String()), Type.String()], { description: "Patterns established by this slice" })),
868
+ observabilitySurfaces: Type.Optional(Type.Union([Type.Array(Type.String()), Type.String()], { description: "Observability surfaces added" })),
869
+ provides: Type.Optional(Type.Union([Type.Array(Type.String()), Type.String()], { description: "What this slice provides to downstream slices" })),
870
+ requirementsSurfaced: Type.Optional(Type.Union([Type.Array(Type.String()), Type.String()], { description: "New requirements surfaced" })),
871
+ drillDownPaths: Type.Optional(Type.Union([Type.Array(Type.String()), Type.String()], { description: "Paths to task summaries for drill-down" })),
872
+ affects: Type.Optional(Type.Union([Type.Array(Type.String()), Type.String()], { description: "Downstream slices affected" })),
862
873
  requirementsAdvanced: Type.Optional(Type.Array(Type.Union([
863
874
  Type.Object({
864
875
  id: Type.String({ description: "Requirement ID" }),
@@ -932,6 +943,16 @@ export function registerDbTools(pi) {
932
943
  }
933
944
  updateSliceStatus(params.milestoneId, params.sliceId, "skipped");
934
945
  invalidateStateCache();
946
+ // Rebuild STATE.md so it reflects the skip immediately (#3477).
947
+ // Without this, /gsd auto reads stale STATE.md and resumes the skipped slice.
948
+ try {
949
+ const basePath = process.cwd();
950
+ const { rebuildState } = await import("../doctor.js");
951
+ await rebuildState(basePath);
952
+ }
953
+ catch (err) {
954
+ logError("tool", `skip_slice rebuildState failed: ${err.message}`, { tool: "gsd_skip_slice" });
955
+ }
935
956
  return {
936
957
  content: [{ type: "text", text: `Skipped slice ${params.sliceId} (${params.milestoneId}). Reason: ${params.reason ?? "User-directed skip"}. Auto-mode will advance past this slice.` }],
937
958
  details: {
@@ -0,0 +1,28 @@
1
+ // GSD Extension — Notify Interceptor
2
+ // Wraps ctx.ui.notify() in-place to persist every notification through the
3
+ // notification store. Uses a WeakSet to prevent double-wrapping and handle
4
+ // UI context replacement on /reload gracefully.
5
+ import { appendNotification } from "../notification-store.js";
6
+ // Track which ui context objects have been wrapped to prevent double-install.
7
+ // WeakSet allows GC to collect replaced uiContext instances after /reload.
8
+ const _wrappedContexts = new WeakSet();
9
+ /**
10
+ * Install the notify interceptor on a context's UI object.
11
+ * Mutates ctx.ui.notify in place — the original is called after persistence.
12
+ * Safe to call multiple times; no-ops if already installed on the same ui object.
13
+ */
14
+ export function installNotifyInterceptor(ctx) {
15
+ if (_wrappedContexts.has(ctx.ui))
16
+ return;
17
+ const originalNotify = ctx.ui.notify.bind(ctx.ui);
18
+ ctx.ui.notify = (message, type) => {
19
+ try {
20
+ appendNotification(message, (type ?? "info"), "notify");
21
+ }
22
+ catch {
23
+ // Non-fatal — never let persistence break the UI
24
+ }
25
+ originalNotify(message, type);
26
+ };
27
+ _wrappedContexts.add(ctx.ui);
28
+ }
@@ -17,10 +17,12 @@ export function registerQueryTools(pi) {
17
17
  }),
18
18
  async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
19
19
  try {
20
- // Strictly read-only: only use an already-open DB connection.
21
- // Do NOT call ensureDbOpen() it can create/migrate the DB as a side effect.
22
- const { isDbAvailable, getMilestone, getSliceStatusSummary, getSliceTaskCounts, _getAdapter, } = await import("../gsd-db.js");
23
- if (!isDbAvailable()) {
20
+ // Open the DB if not already open safe for read-only use since
21
+ // ensureDbOpen() only creates/migrates when .gsd/ has content (#3644).
22
+ const { ensureDbOpen } = await import("./dynamic-tools.js");
23
+ const dbAvailable = await ensureDbOpen();
24
+ const { getMilestone, getSliceStatusSummary, getSliceTaskCounts, _getAdapter, } = await import("../gsd-db.js");
25
+ if (!dbAvailable) {
24
26
  return {
25
27
  content: [{ type: "text", text: "Error: GSD database is not available." }],
26
28
  details: { operation: "milestone_status", error: "db_unavailable" },
@@ -31,7 +31,11 @@ function installEpipeGuard() {
31
31
  if (handleRecoverableExtensionProcessError(err)) {
32
32
  return;
33
33
  }
34
- throw err;
34
+ // Log unhandled errors instead of re-throwing — throwing inside an
35
+ // uncaughtException handler is a fatal double-fault in Node.js (#3163).
36
+ process.stderr.write(`[gsd] uncaught extension error (non-fatal): ${err.message}\n`);
37
+ if (err.stack)
38
+ process.stderr.write(`${err.stack}\n`);
35
39
  };
36
40
  process.on("uncaughtException", _gsdEpipeGuard);
37
41
  }
@@ -18,6 +18,9 @@ import { resetAskUserQuestionsCache } from "../../ask-user-questions.js";
18
18
  import { recordToolCall as safetyRecordToolCall, recordToolResult as safetyRecordToolResult } from "../safety/evidence-collector.js";
19
19
  import { classifyCommand } from "../safety/destructive-guard.js";
20
20
  import { logWarning as safetyLogWarning } from "../workflow-logger.js";
21
+ import { installNotifyInterceptor } from "./notify-interceptor.js";
22
+ import { initNotificationStore } from "../notification-store.js";
23
+ import { initNotificationWidget } from "../notification-widget.js";
21
24
  // Skip the welcome screen on the very first session_start — cli.ts already
22
25
  // printed it before the TUI launched. Only re-print on /clear (subsequent sessions).
23
26
  let isFirstSession = true;
@@ -27,6 +30,9 @@ async function syncServiceTierStatus(ctx) {
27
30
  }
28
31
  export function registerHooks(pi) {
29
32
  pi.on("session_start", async (_event, ctx) => {
33
+ initNotificationStore(process.cwd());
34
+ installNotifyInterceptor(ctx);
35
+ initNotificationWidget(ctx);
30
36
  resetWriteGateState();
31
37
  resetToolCallLoopGuard();
32
38
  resetAskUserQuestionsCache();
@@ -63,6 +69,8 @@ export function registerHooks(pi) {
63
69
  loadToolApiKeys();
64
70
  });
65
71
  pi.on("session_switch", async (_event, ctx) => {
72
+ initNotificationStore(process.cwd());
73
+ installNotifyInterceptor(ctx);
66
74
  resetWriteGateState();
67
75
  resetToolCallLoopGuard();
68
76
  resetAskUserQuestionsCache();
@@ -90,7 +98,10 @@ export function registerHooks(pi) {
90
98
  }
91
99
  });
92
100
  pi.on("session_before_compact", async () => {
93
- if (isAutoActive() || isAutoPaused()) {
101
+ // Only cancel compaction while auto-mode is actively running.
102
+ // Paused auto-mode should allow compaction — the user may be doing
103
+ // interactive work (#3165).
104
+ if (isAutoActive()) {
94
105
  return { cancel: true };
95
106
  }
96
107
  const basePath = process.cwd();