gsd-pi 2.66.1-dev.ed243f2 → 2.67.0-dev.43b0159

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 (287) hide show
  1. package/dist/claude-cli-check.d.ts +8 -0
  2. package/dist/claude-cli-check.js +36 -0
  3. package/dist/cli.js +40 -0
  4. package/dist/onboarding.js +19 -2
  5. package/dist/resources/extensions/ask-user-questions.js +79 -11
  6. package/dist/resources/extensions/claude-code-cli/partial-builder.js +4 -3
  7. package/dist/resources/extensions/claude-code-cli/readiness.js +63 -12
  8. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +10 -3
  9. package/dist/resources/extensions/gsd/auto/loop.js +13 -1
  10. package/dist/resources/extensions/gsd/auto/phases.js +22 -3
  11. package/dist/resources/extensions/gsd/auto/run-unit.js +10 -2
  12. package/dist/resources/extensions/gsd/auto/session.js +1 -1
  13. package/dist/resources/extensions/gsd/auto-dashboard.js +65 -15
  14. package/dist/resources/extensions/gsd/auto-dispatch.js +30 -28
  15. package/dist/resources/extensions/gsd/auto-model-selection.js +12 -3
  16. package/dist/resources/extensions/gsd/auto-prompts.js +173 -25
  17. package/dist/resources/extensions/gsd/auto-recovery.js +11 -12
  18. package/dist/resources/extensions/gsd/auto.js +13 -1
  19. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +32 -1
  20. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +18 -6
  21. package/dist/resources/extensions/gsd/bootstrap/provider-error-resume.js +5 -0
  22. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +59 -5
  23. package/dist/resources/extensions/gsd/bootstrap/register-shortcuts.js +8 -5
  24. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +186 -14
  25. package/dist/resources/extensions/gsd/codebase-generator.js +4 -0
  26. package/dist/resources/extensions/gsd/commands/catalog.js +2 -1
  27. package/dist/resources/extensions/gsd/commands/dispatcher.js +1 -1
  28. package/dist/resources/extensions/gsd/commands/handlers/core.js +94 -4
  29. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +49 -9
  30. package/dist/resources/extensions/gsd/context-store.js +134 -2
  31. package/dist/resources/extensions/gsd/custom-workflow-engine.js +3 -1
  32. package/dist/resources/extensions/gsd/detection.js +6 -0
  33. package/dist/resources/extensions/gsd/files.js +19 -2
  34. package/dist/resources/extensions/gsd/guided-flow.js +12 -8
  35. package/dist/resources/extensions/gsd/index.js +1 -1
  36. package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +2 -0
  37. package/dist/resources/extensions/gsd/parsers-legacy.js +3 -1
  38. package/dist/resources/extensions/gsd/preferences.js +6 -1
  39. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
  40. package/dist/resources/extensions/gsd/prompts/complete-slice.md +3 -3
  41. package/dist/resources/extensions/gsd/prompts/discuss-prepared.md +7 -7
  42. package/dist/resources/extensions/gsd/prompts/discuss.md +3 -3
  43. package/dist/resources/extensions/gsd/prompts/execute-task.md +3 -3
  44. package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +3 -3
  45. package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +3 -1
  46. package/dist/resources/extensions/gsd/prompts/rethink.md +6 -2
  47. package/dist/resources/extensions/gsd/prompts/system.md +1 -1
  48. package/dist/resources/extensions/gsd/prompts/triage-captures.md +1 -1
  49. package/dist/resources/extensions/gsd/prompts/validate-milestone.md +11 -9
  50. package/dist/resources/extensions/gsd/prompts/worktree-merge.md +3 -1
  51. package/dist/resources/extensions/gsd/safety/file-change-validator.js +2 -1
  52. package/dist/resources/extensions/gsd/state.js +2 -1
  53. package/dist/resources/extensions/gsd/visualizer-overlay.js +27 -26
  54. package/dist/resources/extensions/gsd/workflow-reconcile.js +46 -7
  55. package/dist/resources/extensions/remote-questions/manager.js +8 -0
  56. package/dist/resources/extensions/shared/interview-ui.js +10 -0
  57. package/dist/web/standalone/.next/BUILD_ID +1 -1
  58. package/dist/web/standalone/.next/app-path-routes-manifest.json +17 -17
  59. package/dist/web/standalone/.next/build-manifest.json +3 -3
  60. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  61. package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
  62. package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
  63. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  64. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  65. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  66. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  67. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  68. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  69. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  70. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  71. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  72. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  73. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  74. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  75. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  76. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  77. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  78. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  79. package/dist/web/standalone/.next/server/app/index.html +1 -1
  80. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  81. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  82. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  83. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  84. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  85. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  86. package/dist/web/standalone/.next/server/app-paths-manifest.json +17 -17
  87. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  88. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  89. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  90. package/dist/web/standalone/.next/server/pages/500.html +2 -2
  91. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  92. package/dist/web/standalone/.next/static/chunks/{6502.8874bcae249c02e1.js → 6502.b804e48b7919f55e.js} +3 -3
  93. package/dist/web/standalone/.next/static/chunks/{webpack-9fed74684e1c5bb1.js → webpack-65f0501b197d1c49.js} +1 -1
  94. package/package.json +1 -1
  95. package/packages/pi-ai/dist/providers/anthropic-shared.d.ts.map +1 -1
  96. package/packages/pi-ai/dist/providers/anthropic-shared.js +4 -3
  97. package/packages/pi-ai/dist/providers/anthropic-shared.js.map +1 -1
  98. package/packages/pi-ai/dist/utils/json-parse.d.ts.map +1 -1
  99. package/packages/pi-ai/dist/utils/json-parse.js +11 -1
  100. package/packages/pi-ai/dist/utils/json-parse.js.map +1 -1
  101. package/packages/pi-ai/dist/utils/repair-tool-json.d.ts.map +1 -1
  102. package/packages/pi-ai/dist/utils/repair-tool-json.js +60 -1
  103. package/packages/pi-ai/dist/utils/repair-tool-json.js.map +1 -1
  104. package/packages/pi-ai/dist/utils/tests/json-parse.test.d.ts +2 -0
  105. package/packages/pi-ai/dist/utils/tests/json-parse.test.d.ts.map +1 -0
  106. package/packages/pi-ai/dist/utils/tests/json-parse.test.js +14 -0
  107. package/packages/pi-ai/dist/utils/tests/json-parse.test.js.map +1 -0
  108. package/packages/pi-ai/dist/utils/tests/repair-tool-json.test.js +10 -0
  109. package/packages/pi-ai/dist/utils/tests/repair-tool-json.test.js.map +1 -1
  110. package/packages/pi-ai/src/providers/anthropic-shared.ts +4 -3
  111. package/packages/pi-ai/src/utils/json-parse.ts +11 -1
  112. package/packages/pi-ai/src/utils/repair-tool-json.ts +69 -1
  113. package/packages/pi-ai/src/utils/tests/json-parse.test.ts +17 -0
  114. package/packages/pi-ai/src/utils/tests/repair-tool-json.test.ts +13 -0
  115. package/packages/pi-coding-agent/dist/core/agent-session.d.ts +3 -0
  116. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  117. package/packages/pi-coding-agent/dist/core/agent-session.js +1 -0
  118. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  119. package/packages/pi-coding-agent/dist/core/retry-handler.d.ts +16 -0
  120. package/packages/pi-coding-agent/dist/core/retry-handler.d.ts.map +1 -1
  121. package/packages/pi-coding-agent/dist/core/retry-handler.js +58 -1
  122. package/packages/pi-coding-agent/dist/core/retry-handler.js.map +1 -1
  123. package/packages/pi-coding-agent/dist/core/retry-handler.test.js +58 -0
  124. package/packages/pi-coding-agent/dist/core/retry-handler.test.js.map +1 -1
  125. package/packages/pi-coding-agent/dist/core/sdk.d.ts +3 -0
  126. package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
  127. package/packages/pi-coding-agent/dist/core/sdk.js +1 -0
  128. package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
  129. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/provider-display-name.test.d.ts +2 -0
  130. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/provider-display-name.test.d.ts.map +1 -0
  131. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/provider-display-name.test.js +17 -0
  132. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/provider-display-name.test.js.map +1 -0
  133. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
  134. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +2 -1
  135. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
  136. package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.d.ts +1 -0
  137. package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  138. package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.js +9 -2
  139. package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.js.map +1 -1
  140. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.d.ts.map +1 -1
  141. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js +2 -1
  142. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js.map +1 -1
  143. package/packages/pi-coding-agent/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
  144. package/packages/pi-coding-agent/dist/modes/interactive/components/scoped-models-selector.js +2 -1
  145. package/packages/pi-coding-agent/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  146. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +2 -2
  147. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  148. package/packages/pi-coding-agent/package.json +1 -1
  149. package/packages/pi-coding-agent/src/core/agent-session.ts +4 -0
  150. package/packages/pi-coding-agent/src/core/retry-handler.test.ts +69 -0
  151. package/packages/pi-coding-agent/src/core/retry-handler.ts +66 -1
  152. package/packages/pi-coding-agent/src/core/sdk.ts +5 -0
  153. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/provider-display-name.test.ts +18 -0
  154. package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +2 -1
  155. package/packages/pi-coding-agent/src/modes/interactive/components/model-selector.ts +11 -2
  156. package/packages/pi-coding-agent/src/modes/interactive/components/provider-manager.ts +2 -1
  157. package/packages/pi-coding-agent/src/modes/interactive/components/scoped-models-selector.ts +2 -1
  158. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +2 -2
  159. package/packages/pi-tui/dist/__tests__/autocomplete.test.js +13 -0
  160. package/packages/pi-tui/dist/__tests__/autocomplete.test.js.map +1 -1
  161. package/packages/pi-tui/dist/__tests__/stdin-buffer.test.d.ts +2 -0
  162. package/packages/pi-tui/dist/__tests__/stdin-buffer.test.d.ts.map +1 -0
  163. package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js +35 -0
  164. package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js.map +1 -0
  165. package/packages/pi-tui/dist/__tests__/tui.test.d.ts +2 -0
  166. package/packages/pi-tui/dist/__tests__/tui.test.d.ts.map +1 -0
  167. package/packages/pi-tui/dist/__tests__/tui.test.js +43 -0
  168. package/packages/pi-tui/dist/__tests__/tui.test.js.map +1 -0
  169. package/packages/pi-tui/dist/autocomplete.d.ts.map +1 -1
  170. package/packages/pi-tui/dist/autocomplete.js +9 -7
  171. package/packages/pi-tui/dist/autocomplete.js.map +1 -1
  172. package/packages/pi-tui/dist/components/__tests__/editor.test.d.ts +2 -0
  173. package/packages/pi-tui/dist/components/__tests__/editor.test.d.ts.map +1 -0
  174. package/packages/pi-tui/dist/components/__tests__/editor.test.js +54 -0
  175. package/packages/pi-tui/dist/components/__tests__/editor.test.js.map +1 -0
  176. package/packages/pi-tui/dist/components/editor.d.ts +3 -1
  177. package/packages/pi-tui/dist/components/editor.d.ts.map +1 -1
  178. package/packages/pi-tui/dist/components/editor.js +14 -3
  179. package/packages/pi-tui/dist/components/editor.js.map +1 -1
  180. package/packages/pi-tui/dist/stdin-buffer.d.ts.map +1 -1
  181. package/packages/pi-tui/dist/stdin-buffer.js +6 -0
  182. package/packages/pi-tui/dist/stdin-buffer.js.map +1 -1
  183. package/packages/pi-tui/dist/tui.d.ts.map +1 -1
  184. package/packages/pi-tui/dist/tui.js +8 -0
  185. package/packages/pi-tui/dist/tui.js.map +1 -1
  186. package/packages/pi-tui/src/__tests__/autocomplete.test.ts +15 -0
  187. package/packages/pi-tui/src/__tests__/stdin-buffer.test.ts +43 -0
  188. package/packages/pi-tui/src/__tests__/tui.test.ts +50 -0
  189. package/packages/pi-tui/src/autocomplete.ts +9 -7
  190. package/packages/pi-tui/src/components/__tests__/editor.test.ts +64 -0
  191. package/packages/pi-tui/src/components/editor.ts +14 -3
  192. package/packages/pi-tui/src/stdin-buffer.ts +7 -0
  193. package/packages/pi-tui/src/tui.ts +9 -0
  194. package/pkg/package.json +1 -1
  195. package/src/resources/extensions/ask-user-questions.ts +103 -11
  196. package/src/resources/extensions/claude-code-cli/partial-builder.ts +4 -3
  197. package/src/resources/extensions/claude-code-cli/readiness.ts +67 -12
  198. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +12 -3
  199. package/src/resources/extensions/claude-code-cli/tests/partial-builder.test.ts +17 -0
  200. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +18 -0
  201. package/src/resources/extensions/gsd/auto/loop-deps.ts +2 -1
  202. package/src/resources/extensions/gsd/auto/loop.ts +14 -1
  203. package/src/resources/extensions/gsd/auto/phases.ts +27 -4
  204. package/src/resources/extensions/gsd/auto/run-unit.ts +14 -2
  205. package/src/resources/extensions/gsd/auto/session.ts +1 -1
  206. package/src/resources/extensions/gsd/auto-dashboard.ts +76 -16
  207. package/src/resources/extensions/gsd/auto-dispatch.ts +36 -35
  208. package/src/resources/extensions/gsd/auto-model-selection.ts +12 -3
  209. package/src/resources/extensions/gsd/auto-prompts.ts +195 -25
  210. package/src/resources/extensions/gsd/auto-recovery.ts +15 -15
  211. package/src/resources/extensions/gsd/auto.ts +12 -1
  212. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +34 -1
  213. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +27 -6
  214. package/src/resources/extensions/gsd/bootstrap/provider-error-resume.ts +6 -0
  215. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +67 -6
  216. package/src/resources/extensions/gsd/bootstrap/register-shortcuts.ts +11 -8
  217. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +209 -16
  218. package/src/resources/extensions/gsd/codebase-generator.ts +4 -0
  219. package/src/resources/extensions/gsd/commands/catalog.ts +2 -1
  220. package/src/resources/extensions/gsd/commands/dispatcher.ts +1 -2
  221. package/src/resources/extensions/gsd/commands/handlers/core.ts +113 -8
  222. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +49 -11
  223. package/src/resources/extensions/gsd/context-store.ts +167 -2
  224. package/src/resources/extensions/gsd/custom-workflow-engine.ts +3 -1
  225. package/src/resources/extensions/gsd/detection.ts +6 -0
  226. package/src/resources/extensions/gsd/files.ts +21 -2
  227. package/src/resources/extensions/gsd/guided-flow.ts +15 -8
  228. package/src/resources/extensions/gsd/index.ts +6 -0
  229. package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +2 -0
  230. package/src/resources/extensions/gsd/parsers-legacy.ts +3 -1
  231. package/src/resources/extensions/gsd/preferences.ts +6 -1
  232. package/src/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
  233. package/src/resources/extensions/gsd/prompts/complete-slice.md +3 -3
  234. package/src/resources/extensions/gsd/prompts/discuss-prepared.md +7 -7
  235. package/src/resources/extensions/gsd/prompts/discuss.md +3 -3
  236. package/src/resources/extensions/gsd/prompts/execute-task.md +3 -3
  237. package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +3 -3
  238. package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +3 -1
  239. package/src/resources/extensions/gsd/prompts/rethink.md +6 -2
  240. package/src/resources/extensions/gsd/prompts/system.md +1 -1
  241. package/src/resources/extensions/gsd/prompts/triage-captures.md +1 -1
  242. package/src/resources/extensions/gsd/prompts/validate-milestone.md +11 -9
  243. package/src/resources/extensions/gsd/prompts/worktree-merge.md +3 -1
  244. package/src/resources/extensions/gsd/safety/file-change-validator.ts +4 -1
  245. package/src/resources/extensions/gsd/state.ts +2 -1
  246. package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +52 -1
  247. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +50 -2
  248. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +21 -7
  249. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +48 -0
  250. package/src/resources/extensions/gsd/tests/codebase-generator.test.ts +22 -0
  251. package/src/resources/extensions/gsd/tests/commands-workflow-custom.test.ts +12 -0
  252. package/src/resources/extensions/gsd/tests/context-store.test.ts +176 -0
  253. package/src/resources/extensions/gsd/tests/core-overlay-fallback.test.ts +76 -0
  254. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +7 -1
  255. package/src/resources/extensions/gsd/tests/custom-workflow-engine.test.ts +31 -0
  256. package/src/resources/extensions/gsd/tests/decision-scope-cascade.test.ts +370 -0
  257. package/src/resources/extensions/gsd/tests/detection.test.ts +37 -0
  258. package/src/resources/extensions/gsd/tests/file-change-validator.test.ts +50 -0
  259. package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +35 -0
  260. package/src/resources/extensions/gsd/tests/guided-flow-session-isolation.test.ts +34 -0
  261. package/src/resources/extensions/gsd/tests/health-widget.test.ts +45 -0
  262. package/src/resources/extensions/gsd/tests/integration/auto-recovery.test.ts +53 -13
  263. package/src/resources/extensions/gsd/tests/integration/state-machine-runtime-failures.test.ts +2 -2
  264. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +3 -3
  265. package/src/resources/extensions/gsd/tests/measurement.test.ts +531 -0
  266. package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +3 -4
  267. package/src/resources/extensions/gsd/tests/parallel-monitor-overlay.test.ts +21 -0
  268. package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +71 -2
  269. package/src/resources/extensions/gsd/tests/parsers.test.ts +25 -0
  270. package/src/resources/extensions/gsd/tests/preferences.test.ts +37 -0
  271. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +26 -4
  272. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +60 -0
  273. package/src/resources/extensions/gsd/tests/queue-execution-guard.test.ts +9 -0
  274. package/src/resources/extensions/gsd/tests/reactive-graph.test.ts +19 -0
  275. package/src/resources/extensions/gsd/tests/register-shortcuts.test.ts +73 -0
  276. package/src/resources/extensions/gsd/tests/remote-questions.test.ts +98 -0
  277. package/src/resources/extensions/gsd/tests/smart-entry-complete.test.ts +2 -2
  278. package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +26 -0
  279. package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +59 -0
  280. package/src/resources/extensions/gsd/tests/workflow-reconcile.test.ts +91 -0
  281. package/src/resources/extensions/gsd/tests/write-gate.test.ts +210 -35
  282. package/src/resources/extensions/gsd/visualizer-overlay.ts +31 -27
  283. package/src/resources/extensions/gsd/workflow-reconcile.ts +59 -8
  284. package/src/resources/extensions/remote-questions/manager.ts +9 -0
  285. package/src/resources/extensions/shared/interview-ui.ts +13 -0
  286. /package/dist/web/standalone/.next/static/{HAq0VE4k68rhRvJbQL1VW → CrKrzIIxk55witDF1eS0L}/_buildManifest.js +0 -0
  287. /package/dist/web/standalone/.next/static/{HAq0VE4k68rhRvJbQL1VW → CrKrzIIxk55witDF1eS0L}/_ssgManifest.js +0 -0
@@ -13,7 +13,7 @@ import { appendEvent } from "./workflow-events.js";
13
13
  import { atomicWriteSync } from "./atomic-write.js";
14
14
  import { clearParseCache } from "./files.js";
15
15
  import { parseRoadmap as parseLegacyRoadmap, parsePlan as parseLegacyPlan } from "./parsers-legacy.js";
16
- import { isDbAvailable, getTask, getSlice, getSliceTasks, updateTaskStatus, updateSliceStatus } from "./gsd-db.js";
16
+ import { isDbAvailable, getTask, getSlice, getSliceTasks, getPendingGates, updateTaskStatus, updateSliceStatus } from "./gsd-db.js";
17
17
  import { isValidationTerminal } from "./state.js";
18
18
  import { getErrorMessage } from "./error-utils.js";
19
19
  import { logWarning, logError } from "./workflow-logger.js";
@@ -248,8 +248,7 @@ export function verifyExpectedArtifact(
248
248
  if (gateIds.length === 0) return true;
249
249
 
250
250
  try {
251
- const { getPendingGates: getPending } = require("./gsd-db.js");
252
- const pending = getPending(mid, sid, "slice");
251
+ const pending = getPendingGates(mid, sid, "slice");
253
252
  const pendingIds = new Set(pending.map((g: any) => g.gate_id));
254
253
  // All dispatched gates must no longer be pending
255
254
  for (const gid of gateIds) {
@@ -480,22 +479,23 @@ function abortAndResetMerge(
480
479
  }
481
480
  }
482
481
 
482
+ export type MergeReconcileResult = "clean" | "reconciled" | "blocked";
483
+
483
484
  /**
484
485
  * Detect leftover merge state from a prior session and reconcile it.
485
486
  * If MERGE_HEAD or SQUASH_MSG exists, check whether conflicts are resolved.
486
- * If resolved: finalize the commit. If still conflicted: abort and reset.
487
- *
488
- * Returns true if state was dirty and re-derivation is needed.
487
+ * If resolved: finalize the commit. If only .gsd conflicts remain: auto-resolve.
488
+ * If code conflicts remain: fail safe without modifying the worktree.
489
489
  */
490
490
  export function reconcileMergeState(
491
491
  basePath: string,
492
492
  ctx: ExtensionContext,
493
- ): boolean {
493
+ ): MergeReconcileResult {
494
494
  const mergeHeadPath = join(basePath, ".git", "MERGE_HEAD");
495
495
  const squashMsgPath = join(basePath, ".git", "SQUASH_MSG");
496
496
  const hasMergeHead = existsSync(mergeHeadPath);
497
497
  const hasSquashMsg = existsSync(squashMsgPath);
498
- if (!hasMergeHead && !hasSquashMsg) return false;
498
+ if (!hasMergeHead && !hasSquashMsg) return "clean";
499
499
 
500
500
  const conflictedFiles = nativeConflictFiles(basePath);
501
501
  if (conflictedFiles.length === 0) {
@@ -511,7 +511,7 @@ export function reconcileMergeState(
511
511
  } catch (err) {
512
512
  const errorMessage = getErrorMessage(err);
513
513
  ctx.ui.notify(`Failed to finalize leftover merge/squash commit: ${errorMessage}`, "error");
514
- return false;
514
+ return "blocked";
515
515
  }
516
516
  } else {
517
517
  // Still conflicted — try auto-resolving .gsd/ state file conflicts (#530)
@@ -551,15 +551,16 @@ export function reconcileMergeState(
551
551
  );
552
552
  }
553
553
  } else {
554
- // Code conflicts present — abort and reset
555
- abortAndResetMerge(basePath, hasMergeHead, squashMsgPath);
554
+ // Code conflicts present — fail safe and preserve any manual resolution
555
+ // work instead of discarding it with merge --abort/reset --hard.
556
556
  ctx.ui.notify(
557
- "Detected leftover merge state with unresolved conflicts cleaned up. Re-deriving state.",
558
- "warning",
557
+ "Detected leftover merge state with unresolved code conflicts. Auto-mode will pause without modifying the worktree so manual conflict resolution is preserved.",
558
+ "error",
559
559
  );
560
+ return "blocked";
560
561
  }
561
562
  }
562
- return true;
563
+ return "reconciled";
563
564
  }
564
565
 
565
566
  // ─── Loop Remediation ─────────────────────────────────────────────────────────
@@ -618,4 +619,3 @@ export function buildLoopRemediationSteps(
618
619
  }
619
620
  return null;
620
621
  }
621
-
@@ -1205,7 +1205,18 @@ export async function startAuto(
1205
1205
  s.active = true;
1206
1206
  s.verbose = verboseMode;
1207
1207
  s.stepMode = requestedStepMode;
1208
- s.cmdCtx = ctx;
1208
+ // Preserve the original cmdCtx (ExtensionCommandContext with newSession)
1209
+ // when resuming from a provider-error pause. The resume callback receives
1210
+ // an ExtensionContext (from the agent_end hook) which lacks newSession —
1211
+ // using it would crash runUnit with "newSession is not a function".
1212
+ // Only override if the new ctx actually has newSession (user-initiated resume).
1213
+ if ("newSession" in ctx && typeof (ctx as any).newSession === "function") {
1214
+ s.cmdCtx = ctx;
1215
+ } else if (!s.cmdCtx) {
1216
+ // No saved cmdCtx — this shouldn't happen, but handle gracefully
1217
+ s.cmdCtx = ctx as ExtensionCommandContext;
1218
+ }
1219
+ // else: keep existing s.cmdCtx which has the real newSession
1209
1220
  s.basePath = base;
1210
1221
  setLogBasePath(base);
1211
1222
  if (!s.autoStartTime || s.autoStartTime <= 0) s.autoStartTime = Date.now();
@@ -19,7 +19,17 @@ import {
19
19
 
20
20
  const retryState = createRetryState();
21
21
  const MAX_NETWORK_RETRIES = 2;
22
- const MAX_TRANSIENT_AUTO_RESUMES = 3;
22
+ const MAX_TRANSIENT_AUTO_RESUMES = 8;
23
+
24
+ /**
25
+ * Reset the module-level retry state so a resumed auto-session starts fresh.
26
+ * Called by provider-error-resume.ts before startAuto() — without this, the
27
+ * consecutiveTransientCount accumulates across pause/resume cycles and locks
28
+ * out auto-resume after MAX_TRANSIENT_AUTO_RESUMES total (not consecutive) errors.
29
+ */
30
+ export function resetTransientRetryState(): void {
31
+ resetRetryState(retryState);
32
+ }
23
33
 
24
34
  async function pauseTransientWithBackoff(
25
35
  cls: ErrorClass,
@@ -114,6 +124,29 @@ export async function handleAgentEnd(
114
124
  // ── 1. Classify using rawErrorMsg to avoid prose false-positives ────
115
125
  const cls = classifyError(rawErrorMsg, explicitRetryAfterMs);
116
126
 
127
+ // ── 1b. Defer to Core RetryHandler for transient errors ─────────────
128
+ // The Core RetryHandler (agent-session.ts) processes retryable errors
129
+ // AFTER this extension handler, in the same _processAgentEvent() call.
130
+ // For transient errors (overloaded, rate limit, server), the Core will
131
+ // retry in-context — same session, same conversation — which is strictly
132
+ // better than our Layer 2 pause+resume (which creates a new session).
133
+ //
134
+ // If we react here AND the Core also retries, we race: pauseAuto tears
135
+ // down the session while agent.continue() starts a new turn.
136
+ //
137
+ // Solution: Do nothing for transient errors. The Core RetryHandler
138
+ // runs next in _processAgentEvent and will either:
139
+ // a) Retry successfully → new agent_end (success) → we see it next time
140
+ // b) Exhaust retries → the agent stays idle, autoLoop's unit timeout
141
+ // or stuck detection handles it
142
+ //
143
+ // We do NOT call resolveAgentEnd here — that would unblock autoLoop
144
+ // prematurely while the Core is still retrying in the same session.
145
+ // We do NOT call pauseAuto — that would tear down the session.
146
+ if (isTransient(cls)) {
147
+ return;
148
+ }
149
+
117
150
  // Cap rate-limit backoff for CLI-style providers (openai-codex, google-gemini-cli)
118
151
  // which use per-user quotas with shorter windows (#2922).
119
152
  if (cls.kind === "rate-limit") {
@@ -7,6 +7,16 @@ import { loadEffectiveGSDPreferences } from "../preferences.js";
7
7
  import { ensureDbOpen } from "./dynamic-tools.js";
8
8
  import { StringEnum } from "@gsd/pi-ai";
9
9
  import { logError } from "../workflow-logger.js";
10
+ import { getErrorMessage } from "../error-utils.js";
11
+ import { shouldBlockContextArtifactSave } from "./write-gate.js";
12
+
13
+ const SUPPORTED_SUMMARY_ARTIFACT_TYPES = ["SUMMARY", "RESEARCH", "CONTEXT", "ASSESSMENT", "CONTEXT-DRAFT"] as const;
14
+
15
+ export function isSupportedSummaryArtifactType(
16
+ artifactType: string,
17
+ ): artifactType is (typeof SUPPORTED_SUMMARY_ARTIFACT_TYPES)[number] {
18
+ return (SUPPORTED_SUMMARY_ARTIFACT_TYPES as readonly string[]).includes(artifactType);
19
+ }
10
20
 
11
21
  /**
12
22
  * Register an alias tool that shares the same execute function as its canonical counterpart.
@@ -283,13 +293,23 @@ export function registerDbTools(pi: ExtensionAPI): void {
283
293
  details: { operation: "save_summary", error: "db_unavailable" } as any,
284
294
  };
285
295
  }
286
- const validTypes = ["SUMMARY", "RESEARCH", "CONTEXT", "ASSESSMENT"];
287
- if (!validTypes.includes(params.artifact_type)) {
296
+ if (!isSupportedSummaryArtifactType(params.artifact_type)) {
288
297
  return {
289
- content: [{ type: "text" as const, text: `Error: Invalid artifact_type "${params.artifact_type}". Must be one of: ${validTypes.join(", ")}` }],
298
+ content: [{ type: "text" as const, text: `Error: Invalid artifact_type "${params.artifact_type}". Must be one of: ${SUPPORTED_SUMMARY_ARTIFACT_TYPES.join(", ")}` }],
290
299
  details: { operation: "save_summary", error: "invalid_artifact_type" } as any,
291
300
  };
292
301
  }
302
+ const contextGuard = shouldBlockContextArtifactSave(
303
+ params.artifact_type,
304
+ params.milestone_id ?? null,
305
+ params.slice_id ?? null,
306
+ );
307
+ if (contextGuard.block) {
308
+ return {
309
+ content: [{ type: "text" as const, text: `Error saving artifact: ${contextGuard.reason ?? "context write blocked"}` }],
310
+ details: { operation: "save_summary", error: "context_write_blocked" } as any,
311
+ };
312
+ }
293
313
  try {
294
314
  let relativePath: string;
295
315
  if (params.task_id && params.slice_id) {
@@ -333,16 +353,17 @@ export function registerDbTools(pi: ExtensionAPI): void {
333
353
  "Computes the file path from milestone/slice/task IDs automatically.",
334
354
  promptSnippet: "Save a GSD artifact (summary/research/context/assessment) to DB and disk",
335
355
  promptGuidelines: [
336
- "Use gsd_summary_save to persist structured artifacts (SUMMARY, RESEARCH, CONTEXT, ASSESSMENT).",
356
+ "Use gsd_summary_save to persist structured artifacts (SUMMARY, RESEARCH, CONTEXT, ASSESSMENT, CONTEXT-DRAFT).",
337
357
  "milestone_id is required. slice_id and task_id are optional — they determine the file path.",
338
358
  "The tool computes the relative path automatically: milestones/M001/M001-SUMMARY.md, milestones/M001/slices/S01/S01-SUMMARY.md, etc.",
339
- "artifact_type must be one of: SUMMARY, RESEARCH, CONTEXT, ASSESSMENT.",
359
+ "artifact_type must be one of: SUMMARY, RESEARCH, CONTEXT, ASSESSMENT, CONTEXT-DRAFT.",
360
+ "Use CONTEXT-DRAFT for incremental draft persistence; use CONTEXT for the final milestone context after depth verification.",
340
361
  ],
341
362
  parameters: Type.Object({
342
363
  milestone_id: Type.String({ description: "Milestone ID (e.g. M001)" }),
343
364
  slice_id: Type.Optional(Type.String({ description: "Slice ID (e.g. S01)" })),
344
365
  task_id: Type.Optional(Type.String({ description: "Task ID (e.g. T01)" })),
345
- artifact_type: Type.String({ description: "One of: SUMMARY, RESEARCH, CONTEXT, ASSESSMENT" }),
366
+ artifact_type: Type.String({ description: "One of: SUMMARY, RESEARCH, CONTEXT, ASSESSMENT, CONTEXT-DRAFT" }),
346
367
  content: Type.String({ description: "The full markdown content of the artifact" }),
347
368
  }),
348
369
  execute: summarySaveExecute,
@@ -5,6 +5,7 @@ import type {
5
5
  } from "@gsd/pi-coding-agent";
6
6
 
7
7
  import { getAutoDashboardData, startAuto, type AutoDashboardData } from "../auto.js";
8
+ import { resetTransientRetryState } from "./agent-end-recovery.js";
8
9
 
9
10
  type AutoResumeSnapshot = Pick<AutoDashboardData, "active" | "paused" | "stepMode" | "basePath">;
10
11
 
@@ -42,6 +43,11 @@ export async function resumeAutoAfterProviderDelay(
42
43
  return "missing-base";
43
44
  }
44
45
 
46
+ // Reset the transient retry counter before restarting — without this,
47
+ // consecutiveTransientCount accumulates across pause/resume cycles and
48
+ // permanently locks out auto-resume after MAX_TRANSIENT_AUTO_RESUMES errors.
49
+ resetTransientRetryState();
50
+
45
51
  await deps.startAuto(
46
52
  ctx as ExtensionCommandContext,
47
53
  pi,
@@ -6,7 +6,7 @@ import { isToolCallEventType } from "@gsd/pi-coding-agent";
6
6
  import { buildMilestoneFileName, resolveMilestonePath, resolveSliceFile, resolveSlicePath } from "../paths.js";
7
7
  import { buildBeforeAgentStartResult } from "./system-context.js";
8
8
  import { handleAgentEnd } from "./agent-end-recovery.js";
9
- import { clearDiscussionFlowState, isDepthVerified, isDepthConfirmationAnswer, isQueuePhaseActive, markDepthVerified, resetWriteGateState, shouldBlockContextWrite, shouldBlockQueueExecution } from "./write-gate.js";
9
+ import { clearDiscussionFlowState, isDepthConfirmationAnswer, isQueuePhaseActive, markDepthVerified, resetWriteGateState, shouldBlockContextWrite, shouldBlockQueueExecution, isGateQuestionId, setPendingGate, clearPendingGate, getPendingGate, shouldBlockPendingGate, shouldBlockPendingGateBash, extractDepthVerificationMilestoneId } from "./write-gate.js";
10
10
  import { isBlockedStateFile, isBashWriteToStateFile, BLOCKED_WRITE_ERROR } from "../write-intercept.js";
11
11
  import { cleanupQuickBranch } from "../quick.js";
12
12
  import { getDiscussionMilestoneId } from "../guided-flow.js";
@@ -24,6 +24,7 @@ import { logWarning as safetyLogWarning } from "../workflow-logger.js";
24
24
  import { installNotifyInterceptor } from "./notify-interceptor.js";
25
25
  import { initNotificationStore } from "../notification-store.js";
26
26
  import { initNotificationWidget } from "../notification-widget.js";
27
+ import { initHealthWidget } from "../health-widget.js";
27
28
 
28
29
  // Skip the welcome screen on the very first session_start — cli.ts already
29
30
  // printed it before the TUI launched. Only re-print on /clear (subsequent sessions).
@@ -39,6 +40,7 @@ export function registerHooks(pi: ExtensionAPI): void {
39
40
  initNotificationStore(process.cwd());
40
41
  installNotifyInterceptor(ctx);
41
42
  initNotificationWidget(ctx);
43
+ initHealthWidget(ctx);
42
44
  resetWriteGateState();
43
45
  resetToolCallLoopGuard();
44
46
  resetAskUserQuestionsCache();
@@ -162,12 +164,50 @@ export function registerHooks(pi: ExtensionAPI): void {
162
164
  });
163
165
 
164
166
  pi.on("tool_call", async (event) => {
167
+ const discussionBasePath = process.cwd();
165
168
  // ── Loop guard: block repeated identical tool calls ──
166
169
  const loopCheck = checkToolCallLoop(event.toolName, event.input as Record<string, unknown>);
167
170
  if (loopCheck.block) {
168
171
  return { block: true, reason: loopCheck.reason };
169
172
  }
170
173
 
174
+ // ── Discussion gate enforcement: track pending gate questions ─────────
175
+ // Only gate-shaped ask_user_questions calls should block execution.
176
+ // The gate stays pending until the user selects the approval option.
177
+ if (event.toolName === "ask_user_questions") {
178
+ const milestoneId = getDiscussionMilestoneId(discussionBasePath);
179
+ const inDiscussion = milestoneId !== null || isQueuePhaseActive();
180
+ if (inDiscussion) {
181
+ const questions: any[] = (event.input as any)?.questions ?? [];
182
+ const questionId = questions.find((question) => typeof question?.id === "string" && isGateQuestionId(question.id))?.id;
183
+ if (typeof questionId === "string") {
184
+ setPendingGate(questionId);
185
+ }
186
+ }
187
+ }
188
+
189
+ // ── Discussion gate enforcement: block tool calls while gate is pending ──
190
+ // If ask_user_questions was called with a gate ID but hasn't been confirmed,
191
+ // block all non-read-only tool calls to prevent the model from skipping gates.
192
+ if (getPendingGate()) {
193
+ const milestoneId = getDiscussionMilestoneId(discussionBasePath);
194
+ if (isToolCallEventType("bash", event)) {
195
+ const bashGuard = shouldBlockPendingGateBash(
196
+ event.input.command,
197
+ milestoneId,
198
+ isQueuePhaseActive(),
199
+ );
200
+ if (bashGuard.block) return bashGuard;
201
+ } else {
202
+ const gateGuard = shouldBlockPendingGate(
203
+ event.toolName,
204
+ milestoneId,
205
+ isQueuePhaseActive(),
206
+ );
207
+ if (gateGuard.block) return gateGuard;
208
+ }
209
+ }
210
+
171
211
  // ── Queue-mode execution guard (#2545): block source-code mutations ──
172
212
  // When /gsd queue is active, the agent should only create milestones,
173
213
  // not execute work. Block write/edit to non-.gsd/ paths and bash commands
@@ -210,8 +250,7 @@ export function registerHooks(pi: ExtensionAPI): void {
210
250
  const result = shouldBlockContextWrite(
211
251
  event.toolName,
212
252
  event.input.path,
213
- getDiscussionMilestoneId(),
214
- isDepthVerified(),
253
+ getDiscussionMilestoneId(discussionBasePath),
215
254
  isQueuePhaseActive(),
216
255
  );
217
256
  if (result.block) return result;
@@ -239,21 +278,43 @@ export function registerHooks(pi: ExtensionAPI): void {
239
278
 
240
279
  pi.on("tool_result", async (event) => {
241
280
  if (event.toolName !== "ask_user_questions") return;
242
- const milestoneId = getDiscussionMilestoneId();
281
+ const milestoneId = getDiscussionMilestoneId(process.cwd());
243
282
  const queueActive = isQueuePhaseActive();
244
283
  if (!milestoneId && !queueActive) return;
245
284
 
246
285
  const details = event.details as any;
247
- if (details?.cancelled || !details?.response) return;
248
286
 
287
+ // ── Discussion gate enforcement: handle gate question responses ──
288
+ // If the result is cancelled or has no response, the pending gate stays active
289
+ // so the model is blocked from non-read-only tools until it re-asks.
290
+ // If the user responded at all (even "needs adjustment"), clear the pending gate
291
+ // because the user engaged — the prompt handles the re-ask-after-adjustment flow.
249
292
  const questions: any[] = (event.input as any)?.questions ?? [];
293
+ const currentPendingGate = getPendingGate();
294
+ if (currentPendingGate) {
295
+ if (details?.cancelled || !details?.response) {
296
+ // Gate stays pending — model will be blocked from non-read-only tools
297
+ // until it re-asks and gets a valid response
298
+ } else {
299
+ const pendingQuestion = questions.find((question) => question?.id === currentPendingGate);
300
+ if (pendingQuestion) {
301
+ const answer = details.response?.answers?.[currentPendingGate];
302
+ if (isDepthConfirmationAnswer(answer?.selected, pendingQuestion.options)) {
303
+ clearPendingGate();
304
+ }
305
+ }
306
+ }
307
+ }
308
+
309
+ if (details?.cancelled || !details?.response) return;
310
+
250
311
  for (const question of questions) {
251
312
  if (typeof question.id === "string" && question.id.includes("depth_verification")) {
252
313
  // Only unlock the gate if the user selected the first option (confirmation).
253
314
  // Cross-references against the question's defined options to reject free-form "Other" text.
254
315
  const answer = details.response?.answers?.[question.id];
255
316
  if (isDepthConfirmationAnswer(answer?.selected, question.options)) {
256
- markDepthVerified();
317
+ markDepthVerified(extractDepthVerificationMilestoneId(question.id) ?? milestoneId);
257
318
  }
258
319
  break;
259
320
  }
@@ -7,18 +7,20 @@ import { Key } from "@gsd/pi-tui";
7
7
  import { GSDDashboardOverlay } from "../dashboard-overlay.js";
8
8
  import { GSDNotificationOverlay } from "../notification-overlay.js";
9
9
  import { ParallelMonitorOverlay } from "../parallel-monitor-overlay.js";
10
+ import { projectRoot } from "../commands/context.js";
10
11
  import { shortcutDesc } from "../../shared/mod.js";
11
12
 
12
13
  export function registerShortcuts(pi: ExtensionAPI): void {
13
14
  pi.registerShortcut(Key.ctrlAlt("g"), {
14
15
  description: shortcutDesc("Open GSD dashboard", "/gsd status"),
15
16
  handler: async (ctx) => {
16
- if (!existsSync(join(process.cwd(), ".gsd"))) {
17
+ const basePath = projectRoot();
18
+ if (!existsSync(join(basePath, ".gsd"))) {
17
19
  ctx.ui.notify("No .gsd/ directory found. Run /gsd to start.", "info");
18
20
  return;
19
21
  }
20
- await ctx.ui.custom<void>(
21
- (tui, theme, _kb, done) => new GSDDashboardOverlay(tui, theme, () => done()),
22
+ await ctx.ui.custom<boolean>(
23
+ (tui, theme, _kb, done) => new GSDDashboardOverlay(tui, theme, () => done(true)),
22
24
  {
23
25
  overlay: true,
24
26
  overlayOptions: {
@@ -35,8 +37,8 @@ export function registerShortcuts(pi: ExtensionAPI): void {
35
37
  pi.registerShortcut(Key.ctrlAlt("n"), {
36
38
  description: shortcutDesc("Open notification history", "/gsd notifications"),
37
39
  handler: async (ctx) => {
38
- await ctx.ui.custom<void>(
39
- (tui, theme, _kb, done) => new GSDNotificationOverlay(tui, theme, () => done()),
40
+ await ctx.ui.custom<boolean>(
41
+ (tui, theme, _kb, done) => new GSDNotificationOverlay(tui, theme, () => done(true)),
40
42
  {
41
43
  overlay: true,
42
44
  overlayOptions: {
@@ -54,13 +56,14 @@ export function registerShortcuts(pi: ExtensionAPI): void {
54
56
  pi.registerShortcut(Key.ctrlAlt("p"), {
55
57
  description: shortcutDesc("Open parallel worker monitor", "/gsd parallel watch"),
56
58
  handler: async (ctx) => {
57
- const parallelDir = join(process.cwd(), ".gsd", "parallel");
59
+ const basePath = projectRoot();
60
+ const parallelDir = join(basePath, ".gsd", "parallel");
58
61
  if (!existsSync(parallelDir)) {
59
62
  ctx.ui.notify("No parallel workers found. Run /gsd parallel start first.", "info");
60
63
  return;
61
64
  }
62
- await ctx.ui.custom<void>(
63
- (tui, theme, _kb, done) => new ParallelMonitorOverlay(tui, theme, () => done()),
65
+ await ctx.ui.custom<boolean>(
66
+ (tui, theme, _kb, done) => new ParallelMonitorOverlay(tui, theme, () => done(true)),
64
67
  {
65
68
  overlay: true,
66
69
  overlayOptions: {