gsd-pi 2.70.0 → 2.70.1-dev.3e19108

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 (254) hide show
  1. package/dist/loader.js +4 -0
  2. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +152 -2
  3. package/dist/resources/extensions/gsd/auto-model-selection.js +33 -19
  4. package/dist/resources/extensions/gsd/auto-prompts.js +7 -3
  5. package/dist/resources/extensions/gsd/auto-start.js +28 -12
  6. package/dist/resources/extensions/gsd/auto.js +12 -8
  7. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +4 -0
  8. package/dist/resources/extensions/gsd/commands-handlers.js +22 -8
  9. package/dist/resources/extensions/gsd/doctor-engine-checks.js +12 -0
  10. package/dist/resources/extensions/gsd/doctor-format.js +2 -0
  11. package/dist/resources/extensions/gsd/guided-flow.js +33 -20
  12. package/dist/resources/extensions/gsd/init-wizard.js +3 -11
  13. package/dist/resources/extensions/gsd/pre-execution-checks.js +5 -3
  14. package/dist/resources/extensions/gsd/prompts/discuss.md +31 -13
  15. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +34 -0
  16. package/dist/resources/extensions/gsd/validate-directory.js +30 -12
  17. package/dist/resources/extensions/gsd/workflow-mcp-auto-prep.js +56 -0
  18. package/dist/resources/extensions/gsd/workflow-mcp.js +12 -1
  19. package/dist/resources/extensions/slash-commands/audit.js +2 -1
  20. package/dist/resources/extensions/subagent/isolation.js +4 -2
  21. package/dist/update-check.d.ts +1 -0
  22. package/dist/update-check.js +30 -27
  23. package/dist/update-cmd.js +3 -11
  24. package/dist/web/standalone/.next/BUILD_ID +1 -1
  25. package/dist/web/standalone/.next/app-path-routes-manifest.json +15 -15
  26. package/dist/web/standalone/.next/build-manifest.json +4 -4
  27. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  28. package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
  29. package/dist/web/standalone/.next/required-server-files.json +3 -3
  30. package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
  31. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  32. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  33. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  34. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  35. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  36. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  37. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  38. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  39. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  40. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  41. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  42. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  43. package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
  44. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
  45. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  46. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
  47. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  48. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  49. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  50. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  51. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  52. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  53. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  54. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  55. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  56. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
  57. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  58. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  59. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  60. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  61. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  62. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  63. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  64. package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
  65. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  66. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  67. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  68. package/dist/web/standalone/.next/server/app/api/experimental/route.js +2 -2
  69. package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
  70. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  71. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  72. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  73. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  74. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  75. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  76. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  77. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  78. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  79. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  80. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  81. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  82. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  83. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  84. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  85. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  86. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  87. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  88. package/dist/web/standalone/.next/server/app/api/notifications/route.js +2 -2
  89. package/dist/web/standalone/.next/server/app/api/notifications/route_client-reference-manifest.js +1 -1
  90. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  91. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  92. package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
  93. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  94. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  95. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  96. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  97. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  98. package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +2 -2
  99. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  100. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  101. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  102. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  103. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  104. package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
  105. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  106. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  107. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  108. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  109. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  110. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  111. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  112. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  113. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  114. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  115. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  116. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
  117. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
  118. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +1 -1
  119. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  120. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
  121. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  122. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +1 -1
  123. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  124. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +2 -2
  125. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  126. package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
  127. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  128. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  129. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  130. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  131. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  132. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  133. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  134. package/dist/web/standalone/.next/server/app/index.html +1 -1
  135. package/dist/web/standalone/.next/server/app/index.rsc +4 -4
  136. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  137. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
  138. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  139. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +3 -3
  140. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  141. package/dist/web/standalone/.next/server/app/page.js +2 -2
  142. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  143. package/dist/web/standalone/.next/server/app-paths-manifest.json +15 -15
  144. package/dist/web/standalone/.next/server/chunks/63.js +3 -3
  145. package/dist/web/standalone/.next/server/chunks/6897.js +1 -1
  146. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  147. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  148. package/dist/web/standalone/.next/server/middleware.js +2 -2
  149. package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
  150. package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
  151. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  152. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  153. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  154. package/dist/web/standalone/.next/static/chunks/2826.dd3dc8bbd3025fa5.js +9 -0
  155. package/dist/web/standalone/.next/static/chunks/app/_not-found/{page-2f24283c162b6ab3.js → page-f2a7482d42a5614b.js} +1 -1
  156. package/dist/web/standalone/.next/static/chunks/app/{layout-9ecfd95f343793f0.js → layout-a16c7a7ecdf0c2cf.js} +1 -1
  157. package/dist/web/standalone/.next/static/chunks/app/page-f1e30ab6bb269149.js +1 -0
  158. package/dist/web/standalone/.next/static/chunks/main-app-fdab67f7802d7832.js +1 -0
  159. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +1 -0
  160. package/dist/web/standalone/.next/static/chunks/{webpack-6e4d7e9a4f57bed4.js → webpack-b868033a5834586d.js} +1 -1
  161. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  162. package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
  163. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  164. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
  165. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
  166. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
  167. package/dist/web/standalone/server.js +1 -1
  168. package/dist/web-mode.js +4 -0
  169. package/package.json +11 -11
  170. package/packages/mcp-server/dist/env-writer.d.ts +39 -0
  171. package/packages/mcp-server/dist/env-writer.d.ts.map +1 -0
  172. package/packages/mcp-server/dist/env-writer.js +158 -0
  173. package/packages/mcp-server/dist/env-writer.js.map +1 -0
  174. package/packages/mcp-server/dist/server.d.ts +11 -2
  175. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  176. package/packages/mcp-server/dist/server.js +102 -2
  177. package/packages/mcp-server/dist/server.js.map +1 -1
  178. package/packages/mcp-server/dist/workflow-tools.d.ts +2 -0
  179. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  180. package/packages/mcp-server/dist/workflow-tools.js +35 -3
  181. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  182. package/packages/mcp-server/src/env-writer.test.ts +280 -0
  183. package/packages/mcp-server/src/env-writer.ts +183 -0
  184. package/packages/mcp-server/src/import-candidates.test.ts +48 -0
  185. package/packages/mcp-server/src/secure-env-collect.test.ts +265 -0
  186. package/packages/mcp-server/src/server.ts +137 -3
  187. package/packages/mcp-server/src/workflow-tools.ts +34 -1
  188. package/packages/pi-agent-core/dist/agent.d.ts +8 -0
  189. package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
  190. package/packages/pi-agent-core/dist/agent.js +3 -0
  191. package/packages/pi-agent-core/dist/agent.js.map +1 -1
  192. package/packages/pi-agent-core/src/agent.test.ts +82 -0
  193. package/packages/pi-agent-core/src/agent.ts +12 -0
  194. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.d.ts +2 -0
  195. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.d.ts.map +1 -0
  196. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +133 -0
  197. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -0
  198. package/packages/pi-coding-agent/dist/core/lsp/config.d.ts +1 -0
  199. package/packages/pi-coding-agent/dist/core/lsp/config.d.ts.map +1 -1
  200. package/packages/pi-coding-agent/dist/core/lsp/config.js +38 -15
  201. package/packages/pi-coding-agent/dist/core/lsp/config.js.map +1 -1
  202. package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
  203. package/packages/pi-coding-agent/dist/core/sdk.js +10 -0
  204. package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
  205. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  206. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +58 -21
  207. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  208. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.d.ts.map +1 -1
  209. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.js +3 -1
  210. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.js.map +1 -1
  211. package/packages/pi-coding-agent/package.json +1 -1
  212. package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +152 -0
  213. package/packages/pi-coding-agent/src/core/lsp/config.ts +43 -17
  214. package/packages/pi-coding-agent/src/core/sdk.ts +8 -0
  215. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +83 -27
  216. package/packages/pi-coding-agent/src/modes/interactive/slash-command-handlers.ts +7 -5
  217. package/pkg/package.json +1 -1
  218. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +229 -2
  219. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +205 -0
  220. package/src/resources/extensions/gsd/auto-model-selection.ts +39 -25
  221. package/src/resources/extensions/gsd/auto-prompts.ts +7 -3
  222. package/src/resources/extensions/gsd/auto-start.ts +37 -14
  223. package/src/resources/extensions/gsd/auto.ts +12 -8
  224. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +4 -0
  225. package/src/resources/extensions/gsd/commands-handlers.ts +22 -7
  226. package/src/resources/extensions/gsd/doctor-engine-checks.ts +14 -0
  227. package/src/resources/extensions/gsd/doctor-format.ts +1 -0
  228. package/src/resources/extensions/gsd/doctor-types.ts +1 -0
  229. package/src/resources/extensions/gsd/guided-flow.ts +36 -17
  230. package/src/resources/extensions/gsd/init-wizard.ts +3 -13
  231. package/src/resources/extensions/gsd/pre-execution-checks.ts +6 -3
  232. package/src/resources/extensions/gsd/prompts/discuss.md +31 -13
  233. package/src/resources/extensions/gsd/tests/discuss-incremental-persistence.test.ts +9 -0
  234. package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +43 -0
  235. package/src/resources/extensions/gsd/tests/interactive-routing-bypass.test.ts +207 -0
  236. package/src/resources/extensions/gsd/tests/pre-exec-backtick-strip.test.ts +48 -1
  237. package/src/resources/extensions/gsd/tests/resource-loader-import-path.test.ts +8 -7
  238. package/src/resources/extensions/gsd/tests/validate-directory.test.ts +33 -1
  239. package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +87 -1
  240. package/src/resources/extensions/gsd/tests/workflow-mcp-auto-prep.test.ts +76 -0
  241. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +180 -1
  242. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +22 -0
  243. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +60 -25
  244. package/src/resources/extensions/gsd/validate-directory.ts +33 -11
  245. package/src/resources/extensions/gsd/workflow-mcp-auto-prep.ts +76 -0
  246. package/src/resources/extensions/gsd/workflow-mcp.ts +16 -1
  247. package/src/resources/extensions/slash-commands/audit.ts +2 -1
  248. package/src/resources/extensions/subagent/isolation.ts +4 -3
  249. package/dist/web/standalone/.next/static/chunks/2826.821e01b07d92e948.js +0 -9
  250. package/dist/web/standalone/.next/static/chunks/app/page-7115e62689b5fd84.js +0 -1
  251. package/dist/web/standalone/.next/static/chunks/main-app-d3d4c336195465f9.js +0 -1
  252. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ab5a8926e07ec673.js +0 -1
  253. /package/dist/web/standalone/.next/static/{Nl6lg7zP5dNgNBV1107v1 → cHCEWiRJM5bXJa9HkP1QU}/_buildManifest.js +0 -0
  254. /package/dist/web/standalone/.next/static/{Nl6lg7zP5dNgNBV1107v1 → cHCEWiRJM5bXJa9HkP1QU}/_ssgManifest.js +0 -0
@@ -35,7 +35,7 @@ import { findMilestoneIds, nextMilestoneId, reserveMilestoneId, getReservedMiles
35
35
  import { parkMilestone, discardMilestone } from "./milestone-actions.js";
36
36
  import { selectAndApplyModel } from "./auto-model-selection.js";
37
37
  import { DISCUSS_TOOLS_ALLOWLIST } from "./constants.js";
38
- import { getWorkflowTransportSupportError, getRequiredWorkflowToolsForGuidedUnit, } from "./workflow-mcp.js";
38
+ import { getWorkflowTransportSupportError, getRequiredWorkflowToolsForGuidedUnit, supportsStructuredQuestions, } from "./workflow-mcp.js";
39
39
  import { runPreparation, formatCodebaseBrief, formatPriorContextBrief, } from "./preparation.js";
40
40
  // ─── Re-exports (preserve public API for existing importers) ────────────────
41
41
  export { MILESTONE_ID_RE, generateMilestoneSuffix, nextMilestoneId, extractMilestoneSeq, parseMilestoneId, milestoneIdSort, maxMilestoneNum, findMilestoneIds, reserveMilestoneId, claimReservedId, getReservedMilestoneIds, clearReservedMilestoneIds, } from "./milestone-ids.js";
@@ -236,7 +236,8 @@ async function dispatchWorkflow(pi, note, customType = "gsd-run", ctx, unitType)
236
236
  // tier downgrade, fallback chains) — same path as auto-mode dispatches (#2958).
237
237
  if (ctx && unitType) {
238
238
  const prefs = loadEffectiveGSDPreferences()?.preferences;
239
- const result = await selectAndApplyModel(ctx, pi, unitType, /* unitId */ "", /* basePath */ process.cwd(), prefs, /* verbose */ false, /* autoModeStartModel */ null);
239
+ const result = await selectAndApplyModel(ctx, pi, unitType, /* unitId */ "", /* basePath */ process.cwd(), prefs, /* verbose */ false, /* autoModeStartModel */ null,
240
+ /* retryContext */ undefined, /* isAutoMode */ false);
240
241
  if (result.appliedModel) {
241
242
  debugLog("guided-flow-model-applied", {
242
243
  unitType,
@@ -294,6 +295,16 @@ async function dispatchWorkflow(pi, note, customType = "gsd-run", ctx, unitType)
294
295
  pi.setActiveTools(savedTools);
295
296
  }
296
297
  }
298
+ function getStructuredQuestionsAvailability(pi, ctx) {
299
+ if (!ctx)
300
+ return "false";
301
+ const provider = ctx.model?.provider;
302
+ const authMode = provider ? ctx.modelRegistry.getProviderAuthMode(provider) : undefined;
303
+ return supportsStructuredQuestions(pi.getActiveTools(), {
304
+ authMode,
305
+ baseUrl: ctx.model?.baseUrl,
306
+ }) ? "true" : "false";
307
+ }
297
308
  /**
298
309
  * Resolve a model ID string to a model object from available models.
299
310
  * Handles "provider/model" and bare ID formats.
@@ -323,8 +334,9 @@ function resolveAvailableModel(modelId, availableModels, currentProvider) {
323
334
  * Build the discuss-and-plan prompt for a new milestone.
324
335
  * Used by all three "new milestone" paths (first ever, no active, all complete).
325
336
  */
326
- function buildDiscussPrompt(nextId, preamble, _basePath, preparationContext) {
337
+ function buildDiscussPrompt(nextId, preamble, _basePath, pi, ctx, preparationContext) {
327
338
  const milestoneRel = `.gsd/milestones/${nextId}`;
339
+ const structuredQuestionsAvailable = getStructuredQuestionsAvailability(pi, ctx);
328
340
  const inlinedTemplates = [
329
341
  inlineTemplate("project", "Project"),
330
342
  inlineTemplate("requirements", "Requirements"),
@@ -336,6 +348,7 @@ function buildDiscussPrompt(nextId, preamble, _basePath, preparationContext) {
336
348
  milestoneId: nextId,
337
349
  preamble,
338
350
  preparationContext: preparationContext ?? "",
351
+ structuredQuestionsAvailable,
339
352
  contextPath: `${milestoneRel}/${nextId}-CONTEXT.md`,
340
353
  roadmapPath: `${milestoneRel}/${nextId}-ROADMAP.md`,
341
354
  inlinedTemplates,
@@ -379,7 +392,7 @@ function buildHeadlessDiscussPrompt(nextId, seedContext, _basePath) {
379
392
  * @param basePath - Root directory of the project
380
393
  * @returns The discuss prompt string
381
394
  */
382
- async function prepareAndBuildDiscussPrompt(ctx, nextId, preamble, basePath) {
395
+ async function prepareAndBuildDiscussPrompt(ctx, pi, nextId, preamble, basePath) {
383
396
  const prefs = loadEffectiveGSDPreferences()?.preferences ?? {};
384
397
  // Run preparation if enabled (default: true) — results are injected as
385
398
  // supplementary context into the standard discuss prompt, NOT as a
@@ -410,7 +423,7 @@ async function prepareAndBuildDiscussPrompt(ctx, nextId, preamble, basePath) {
410
423
  logWarning("guided", `preparation failed, proceeding without context: ${err.message}`);
411
424
  }
412
425
  }
413
- return buildDiscussPrompt(nextId, preamble, basePath, preparationContext);
426
+ return buildDiscussPrompt(nextId, preamble, basePath, pi, ctx, preparationContext);
414
427
  }
415
428
  /**
416
429
  * Bootstrap a .gsd/ project from scratch for headless use.
@@ -600,7 +613,7 @@ export async function showDiscuss(ctx, pi, basePath) {
600
613
  });
601
614
  if (choice === "discuss_draft") {
602
615
  const discussMilestoneTemplates = inlineTemplate("context", "Context");
603
- const structuredQuestionsAvailable = pi.getActiveTools().includes("ask_user_questions") ? "true" : "false";
616
+ const structuredQuestionsAvailable = getStructuredQuestionsAvailability(pi, ctx);
604
617
  const basePrompt = loadPrompt("guided-discuss-milestone", {
605
618
  milestoneId: mid, milestoneTitle, inlinedTemplates: discussMilestoneTemplates, structuredQuestionsAvailable,
606
619
  commitInstruction: buildDocsCommitInstruction(`docs(${mid}): milestone context from discuss`),
@@ -614,7 +627,7 @@ export async function showDiscuss(ctx, pi, basePath) {
614
627
  }
615
628
  else if (choice === "discuss_fresh") {
616
629
  const discussMilestoneTemplates = inlineTemplate("context", "Context");
617
- const structuredQuestionsAvailable = pi.getActiveTools().includes("ask_user_questions") ? "true" : "false";
630
+ const structuredQuestionsAvailable = getStructuredQuestionsAvailability(pi, ctx);
618
631
  pendingAutoStartMap.set(basePath, { ctx, pi, basePath, milestoneId: mid, step: false, createdAt: Date.now() });
619
632
  await dispatchWorkflow(pi, loadPrompt("guided-discuss-milestone", {
620
633
  milestoneId: mid, milestoneTitle, inlinedTemplates: discussMilestoneTemplates, structuredQuestionsAvailable,
@@ -627,7 +640,7 @@ export async function showDiscuss(ctx, pi, basePath) {
627
640
  const uniqueMilestoneIds = !!loadEffectiveGSDPreferences()?.preferences?.unique_milestone_ids;
628
641
  const nextId = nextMilestoneIdReserved(milestoneIds, uniqueMilestoneIds);
629
642
  pendingAutoStartMap.set(basePath, { ctx, pi, basePath, milestoneId: nextId, step: false, createdAt: Date.now() });
630
- await dispatchWorkflow(pi, await prepareAndBuildDiscussPrompt(ctx, nextId, `New milestone ${nextId}.`, basePath), "gsd-run", ctx, "discuss-milestone");
643
+ await dispatchWorkflow(pi, await prepareAndBuildDiscussPrompt(ctx, pi, nextId, `New milestone ${nextId}.`, basePath), "gsd-run", ctx, "discuss-milestone");
631
644
  }
632
645
  return;
633
646
  }
@@ -757,7 +770,7 @@ export async function showDiscuss(ctx, pi, basePath) {
757
770
  if (confirm !== "rediscuss")
758
771
  continue;
759
772
  }
760
- const sqAvail = pi.getActiveTools().includes("ask_user_questions") ? "true" : "false";
773
+ const sqAvail = getStructuredQuestionsAvailability(pi, ctx);
761
774
  const prompt = await buildDiscussSlicePrompt(mid, chosen.id, chosen.title, basePath, { rediscuss: isRediscuss, structuredQuestionsAvailable: sqAvail });
762
775
  await dispatchWorkflow(pi, prompt, "gsd-discuss", ctx, "discuss-slice");
763
776
  // Wait for the discuss session to finish, then loop back to the picker
@@ -848,7 +861,7 @@ async function dispatchDiscussForMilestone(ctx, pi, basePath, mid, milestoneTitl
848
861
  ].join("\n")
849
862
  : "";
850
863
  const discussMilestoneTemplates = inlineTemplate("context", "Context");
851
- const structuredQuestionsAvailable = pi.getActiveTools().includes("ask_user_questions") ? "true" : "false";
864
+ const structuredQuestionsAvailable = getStructuredQuestionsAvailability(pi, ctx);
852
865
  const basePrompt = loadPrompt("guided-discuss-milestone", {
853
866
  milestoneId: mid,
854
867
  milestoneTitle,
@@ -983,7 +996,7 @@ async function handleMilestoneActions(ctx, pi, basePath, milestoneId, milestoneT
983
996
  const uniqueMilestoneIds = !!loadEffectiveGSDPreferences()?.preferences?.unique_milestone_ids;
984
997
  const nextId = nextMilestoneIdReserved(milestoneIds, uniqueMilestoneIds);
985
998
  pendingAutoStartMap.set(basePath, { ctx, pi, basePath, milestoneId: nextId, step: stepMode, createdAt: Date.now() });
986
- await dispatchWorkflow(pi, await prepareAndBuildDiscussPrompt(ctx, nextId, `New milestone ${nextId}.`, basePath), "gsd-run", ctx, "discuss-milestone");
999
+ await dispatchWorkflow(pi, await prepareAndBuildDiscussPrompt(ctx, pi, nextId, `New milestone ${nextId}.`, basePath), "gsd-run", ctx, "discuss-milestone");
987
1000
  return true;
988
1001
  }
989
1002
  // "back" or null
@@ -1150,7 +1163,7 @@ export async function showSmartEntry(ctx, pi, basePath, options) {
1150
1163
  if (isFirst) {
1151
1164
  // First ever — skip wizard, just ask directly
1152
1165
  pendingAutoStartMap.set(basePath, { ctx, pi, basePath, milestoneId: nextId, step: stepMode, createdAt: Date.now() });
1153
- await dispatchWorkflow(pi, await prepareAndBuildDiscussPrompt(ctx, nextId, `New project, milestone ${nextId}. Do NOT read or explore .gsd/ — it's empty scaffolding.`, basePath), "gsd-run", ctx, "discuss-milestone");
1166
+ await dispatchWorkflow(pi, await prepareAndBuildDiscussPrompt(ctx, pi, nextId, `New project, milestone ${nextId}. Do NOT read or explore .gsd/ — it's empty scaffolding.`, basePath), "gsd-run", ctx, "discuss-milestone");
1154
1167
  }
1155
1168
  else {
1156
1169
  const choice = await showNextAction(ctx, {
@@ -1168,7 +1181,7 @@ export async function showSmartEntry(ctx, pi, basePath, options) {
1168
1181
  });
1169
1182
  if (choice === "new_milestone") {
1170
1183
  pendingAutoStartMap.set(basePath, { ctx, pi, basePath, milestoneId: nextId, step: stepMode, createdAt: Date.now() });
1171
- await dispatchWorkflow(pi, await prepareAndBuildDiscussPrompt(ctx, nextId, `New milestone ${nextId}.`, basePath), "gsd-run", ctx, "discuss-milestone");
1184
+ await dispatchWorkflow(pi, await prepareAndBuildDiscussPrompt(ctx, pi, nextId, `New milestone ${nextId}.`, basePath), "gsd-run", ctx, "discuss-milestone");
1172
1185
  }
1173
1186
  }
1174
1187
  return;
@@ -1200,7 +1213,7 @@ export async function showSmartEntry(ctx, pi, basePath, options) {
1200
1213
  const uniqueMilestoneIds = !!loadEffectiveGSDPreferences()?.preferences?.unique_milestone_ids;
1201
1214
  const nextId = nextMilestoneIdReserved(milestoneIds, uniqueMilestoneIds);
1202
1215
  pendingAutoStartMap.set(basePath, { ctx, pi, basePath, milestoneId: nextId, step: stepMode, createdAt: Date.now() });
1203
- await dispatchWorkflow(pi, await prepareAndBuildDiscussPrompt(ctx, nextId, `New milestone ${nextId}.`, basePath), "gsd-run", ctx, "discuss-milestone");
1216
+ await dispatchWorkflow(pi, await prepareAndBuildDiscussPrompt(ctx, pi, nextId, `New milestone ${nextId}.`, basePath), "gsd-run", ctx, "discuss-milestone");
1204
1217
  }
1205
1218
  else if (choice === "status") {
1206
1219
  const { fireStatusViaCommand } = await import("./commands.js");
@@ -1237,7 +1250,7 @@ export async function showSmartEntry(ctx, pi, basePath, options) {
1237
1250
  });
1238
1251
  if (choice === "discuss_draft") {
1239
1252
  const discussMilestoneTemplates = inlineTemplate("context", "Context");
1240
- const structuredQuestionsAvailable = pi.getActiveTools().includes("ask_user_questions") ? "true" : "false";
1253
+ const structuredQuestionsAvailable = getStructuredQuestionsAvailability(pi, ctx);
1241
1254
  const basePrompt = loadPrompt("guided-discuss-milestone", {
1242
1255
  milestoneId, milestoneTitle, inlinedTemplates: discussMilestoneTemplates, structuredQuestionsAvailable,
1243
1256
  commitInstruction: buildDocsCommitInstruction(`docs(${milestoneId}): milestone context from discuss`),
@@ -1251,7 +1264,7 @@ export async function showSmartEntry(ctx, pi, basePath, options) {
1251
1264
  }
1252
1265
  else if (choice === "discuss_fresh") {
1253
1266
  const discussMilestoneTemplates = inlineTemplate("context", "Context");
1254
- const structuredQuestionsAvailable = pi.getActiveTools().includes("ask_user_questions") ? "true" : "false";
1267
+ const structuredQuestionsAvailable = getStructuredQuestionsAvailability(pi, ctx);
1255
1268
  pendingAutoStartMap.set(basePath, { ctx, pi, basePath, milestoneId, step: stepMode, createdAt: Date.now() });
1256
1269
  await dispatchWorkflow(pi, loadPrompt("guided-discuss-milestone", {
1257
1270
  milestoneId, milestoneTitle, inlinedTemplates: discussMilestoneTemplates, structuredQuestionsAvailable,
@@ -1264,7 +1277,7 @@ export async function showSmartEntry(ctx, pi, basePath, options) {
1264
1277
  const uniqueMilestoneIds = !!loadEffectiveGSDPreferences()?.preferences?.unique_milestone_ids;
1265
1278
  const nextId = nextMilestoneIdReserved(milestoneIds, uniqueMilestoneIds);
1266
1279
  pendingAutoStartMap.set(basePath, { ctx, pi, basePath, milestoneId: nextId, step: stepMode, createdAt: Date.now() });
1267
- await dispatchWorkflow(pi, await prepareAndBuildDiscussPrompt(ctx, nextId, `New milestone ${nextId}.`, basePath), "gsd-run", ctx, "discuss-milestone");
1280
+ await dispatchWorkflow(pi, await prepareAndBuildDiscussPrompt(ctx, pi, nextId, `New milestone ${nextId}.`, basePath), "gsd-run", ctx, "discuss-milestone");
1268
1281
  }
1269
1282
  return;
1270
1283
  }
@@ -1342,7 +1355,7 @@ export async function showSmartEntry(ctx, pi, basePath, options) {
1342
1355
  }
1343
1356
  else if (choice === "discuss") {
1344
1357
  const discussMilestoneTemplates = inlineTemplate("context", "Context");
1345
- const structuredQuestionsAvailable = pi.getActiveTools().includes("ask_user_questions") ? "true" : "false";
1358
+ const structuredQuestionsAvailable = getStructuredQuestionsAvailability(pi, ctx);
1346
1359
  await dispatchWorkflow(pi, loadPrompt("guided-discuss-milestone", {
1347
1360
  milestoneId, milestoneTitle, inlinedTemplates: discussMilestoneTemplates, structuredQuestionsAvailable,
1348
1361
  commitInstruction: buildDocsCommitInstruction(`docs(${milestoneId}): milestone context from discuss`),
@@ -1354,7 +1367,7 @@ export async function showSmartEntry(ctx, pi, basePath, options) {
1354
1367
  const uniqueMilestoneIds = !!loadEffectiveGSDPreferences()?.preferences?.unique_milestone_ids;
1355
1368
  const nextId = nextMilestoneIdReserved(milestoneIds, uniqueMilestoneIds);
1356
1369
  pendingAutoStartMap.set(basePath, { ctx, pi, basePath, milestoneId: nextId, step: stepMode, createdAt: Date.now() });
1357
- await dispatchWorkflow(pi, await prepareAndBuildDiscussPrompt(ctx, nextId, `New milestone ${nextId}.`, basePath), "gsd-run", ctx, "discuss-milestone");
1370
+ await dispatchWorkflow(pi, await prepareAndBuildDiscussPrompt(ctx, pi, nextId, `New milestone ${nextId}.`, basePath), "gsd-run", ctx, "discuss-milestone");
1358
1371
  }
1359
1372
  else if (choice === "discard_milestone") {
1360
1373
  const confirmed = await showConfirm(ctx, {
@@ -1480,7 +1493,7 @@ export async function showSmartEntry(ctx, pi, basePath, options) {
1480
1493
  }), "gsd-run", ctx, "plan-slice");
1481
1494
  }
1482
1495
  else if (choice === "discuss") {
1483
- const sqAvail = pi.getActiveTools().includes("ask_user_questions") ? "true" : "false";
1496
+ const sqAvail = getStructuredQuestionsAvailability(pi, ctx);
1484
1497
  await dispatchWorkflow(pi, await buildDiscussSlicePrompt(milestoneId, sliceId, sliceTitle, basePath, { rediscuss: hasContext, structuredQuestionsAvailable: sqAvail }), "gsd-run", ctx, "discuss-slice");
1485
1498
  }
1486
1499
  else if (choice === "research") {
@@ -225,17 +225,9 @@ export async function showProjectInit(ctx, pi, basePath, detection) {
225
225
  catch {
226
226
  // Non-fatal — STATE.md will be regenerated on next /gsd invocation
227
227
  }
228
- if (ctx.model?.provider === "claude-code") {
229
- try {
230
- const { ensureProjectWorkflowMcpConfig } = await import("./mcp-project-config.js");
231
- const result = ensureProjectWorkflowMcpConfig(basePath);
232
- if (result.status !== "unchanged") {
233
- ctx.ui.notify(`Claude Code MCP prepared at ${result.configPath}`, "info");
234
- }
235
- }
236
- catch (err) {
237
- ctx.ui.notify(`Claude Code MCP prep failed: ${err instanceof Error ? err.message : String(err)}`, "warning");
238
- }
228
+ {
229
+ const { prepareWorkflowMcpForProject } = await import("./workflow-mcp-auto-prep.js");
230
+ prepareWorkflowMcpForProject(ctx, basePath);
239
231
  }
240
232
  ctx.ui.notify("GSD initialized. Starting your first milestone...", "info");
241
233
  return { completed: true, bootstrapped: true };
@@ -16,6 +16,7 @@
16
16
  import { existsSync } from "node:fs";
17
17
  import { spawn } from "node:child_process";
18
18
  import { resolve } from "node:path";
19
+ const NPM_COMMAND = process.platform === "win32" ? "npm.cmd" : "npm";
19
20
  // ─── Package Existence Check ─────────────────────────────────────────────────
20
21
  /**
21
22
  * Extract npm package names from task descriptions.
@@ -98,9 +99,10 @@ function normalizePackageName(raw) {
98
99
  */
99
100
  async function checkPackageOnNpm(packageName, timeoutMs = 5000) {
100
101
  return new Promise((resolve) => {
101
- const child = spawn("npm", ["view", packageName, "name"], {
102
+ const child = spawn(NPM_COMMAND, ["view", packageName, "name"], {
102
103
  stdio: ["ignore", "pipe", "pipe"],
103
104
  timeout: timeoutMs,
105
+ shell: process.platform === "win32",
104
106
  });
105
107
  let stdout = "";
106
108
  let stderr = "";
@@ -216,9 +218,9 @@ function extractPathFromAnnotation(raw) {
216
218
  const trimmed = raw.trim();
217
219
  if (!trimmed)
218
220
  return trimmed;
219
- const backtickMatch = trimmed.match(/^`([^`]+)`(?:\s+[—–-]\s+.*)?$/);
221
+ const backtickMatch = trimmed.match(/^(`+)([^`]+)\1(?:(?:\s+[—–-]\s+.+)|(?:\s+\([^()]+\)))?$/);
220
222
  if (backtickMatch) {
221
- return backtickMatch[1].trim();
223
+ return backtickMatch[2].trim();
222
224
  }
223
225
  const annotatedMatch = trimmed.match(/^(.+?)\s+[—–-]\s+.+$/);
224
226
  if (annotatedMatch) {
@@ -49,6 +49,26 @@ This happens ONCE, before the first round. The goal: your first questions should
49
49
 
50
50
  For subsequent rounds, continue investigating between rounds — check docs, search, or scout as needed to make each round's questions smarter. But the first-round investigation is mandatory and explicit. Distribute searches across turns rather than clustering them in one turn.
51
51
 
52
+ ## Question Rounds
53
+
54
+ Ask **1–3 questions per round**. Keep each round tightly focused on one or two of the depth checklist dimensions — do not try to cover all six in one round.
55
+
56
+ **If `{{structuredQuestionsAvailable}}` is `true`:** use `ask_user_questions` for each round. 1–3 questions per call, each as a separate question object. Keep option labels short (3–5 words). Always include a freeform "Other / let me explain" option. When the user picks that option or writes a long freeform answer, switch to plain text follow-up for that thread before resuming structured questions. **IMPORTANT: Call `ask_user_questions` exactly once per turn. Never make multiple calls with the same or overlapping questions — wait for the user's response before asking the next round.**
57
+
58
+ **If `{{structuredQuestionsAvailable}}` is `false`:** ask questions in plain text. Keep each round to 1–3 focused questions. Wait for answers before asking the next round.
59
+
60
+ After each answer set, investigate further if any answer opens a new unknown, then ask the next round.
61
+
62
+ ### Round cadence
63
+
64
+ After each round of answers, decide whether you already have enough depth to write strong output.
65
+
66
+ - **Incremental persistence:** After every 2 question rounds, silently save a `{{milestoneId}}-CONTEXT-DRAFT.md` using `gsd_summary_save` with `artifact_type: "CONTEXT-DRAFT"` and `milestone_id: "{{milestoneId}}"`. This protects confirmed work against session crashes. Do NOT mention this save to the user.
67
+ - If not ready, continue to the next round immediately. Do **not** ask a meta "ready to wrap up?" question after every round.
68
+ - **Depth-matching rule:** Simple, well-defined work needs fewer rounds — maybe 1–2. Large, ambiguous visions need more — maybe 4+. Do not pad rounds to hit a number. Stop when the Depth Enforcement checklist below is fully satisfied.
69
+ - Do not count the reflection step as a question round. Rounds start after reflection is confirmed.
70
+ - When you genuinely believe the depth checklist is satisfied, move to the Depth Verification step below. Do not ask a separate "ready to wrap up?" gate — the depth verification IS the gate.
71
+
52
72
  ## Questioning Philosophy
53
73
 
54
74
  You are a thinking partner, not an interviewer.
@@ -94,29 +114,27 @@ Do NOT offer to proceed until ALL of the following are satisfied. Track these in
94
114
 
95
115
  Before offering to proceed, demonstrate absorption: reference specific things the user emphasized, specific terminology they used, specific nuance they sharpened — and show how those shaped your understanding. Synthesize, don't recite. "Your emphasis on X led me to prioritize Y over Z" is good. "You said X, you said Y, you said Z" is not. The user should feel heard in the specifics, not just acknowledged in the abstract.
96
116
 
97
- **Questioning depth should match scope.** Simple, well-defined work needs fewer rounds — maybe 1-2. Large, ambiguous visions need more — maybe 4+. Don't pad rounds to hit a number. Stop when the depth checklist is satisfied and you genuinely understand the work.
98
-
99
- Do not count the reflection step as a question round. Rounds start after reflection is confirmed.
100
-
101
117
  ## Depth Verification
102
118
 
103
119
  Before moving to the wrap-up gate, present a structured depth summary as a checkpoint.
104
120
 
105
121
  **Print the summary as normal chat text first** — this is where the formatting renders properly. Structure the summary across the depth checklist dimensions using the user's own terminology and framing. Cover: what you understood them to be building, what shaped your understanding most (their emphasis, constraints, concerns), and any areas where you're least confident in your understanding.
106
122
 
107
- **Then** use `ask_user_questions` with a short confirmation question — NOT the summary itself. The question field is designed for single sentences, not multi-paragraph summaries.
123
+ **Then confirm:**
108
124
 
109
- **Convention:** The question ID must contain `depth_verification` (e.g., `depth_verification_confirm`). This naming convention enables downstream mechanical detection of this step.
125
+ **If `{{structuredQuestionsAvailable}}` is `true`:** use `ask_user_questions` with:
126
+ - header: "Depth Check"
127
+ - question: "Did I capture the depth right?"
128
+ - options: "Yes, you got it (Recommended)", "Not quite — let me clarify"
129
+ - **The question ID must contain `depth_verification`** (e.g., `depth_verification_confirm`) — this naming convention enables downstream mechanical detection and the write-gate.
110
130
 
111
- Example flow:
112
- 1. Print in chat: the full depth summary with markdown formatting (headers, bold, bullets)
113
- 2. Call `ask_user_questions` with: header "Depth Check", question "Did I capture the depth right?", options "Yes, you got it (Recommended)" and "Not quite — let me clarify"
131
+ **If `{{structuredQuestionsAvailable}}` is `false`:** ask in plain text: "Did I capture that correctly? If not, tell me what I missed." Wait for explicit confirmation before proceeding. **The same non-bypassable gate applies to the plain-text path** — if the user does not respond, gives an ambiguous answer, or does not explicitly confirm, you MUST re-ask. Never rationalize past a missing confirmation.
114
132
 
115
133
  If they clarify, absorb the correction and re-verify.
116
134
 
117
135
  The depth verification is the required write-gate. Do **not** add another meta "ready to proceed?" checkpoint immediately after it unless there is still material ambiguity.
118
136
 
119
- **CRITICAL — Non-bypassable gate:** The system mechanically blocks CONTEXT.md writes until the user selects the "(Recommended)" option. If the user declines, cancels, or the tool fails, you MUST re-ask — never rationalize past the block ("tool not responding, I'll proceed" is forbidden). The gate exists to protect the user's work; treat a block as an instruction, not an obstacle to work around.
137
+ **CRITICAL — Non-bypassable gate:** The system mechanically blocks CONTEXT.md writes until the user selects the "(Recommended)" option (structured path) or explicitly confirms (plain-text path). If the user declines, cancels, does not respond, or the tool fails, you MUST re-ask — never rationalize past the block ("tool not responding, I'll proceed" is forbidden). The gate exists to protect the user's work; treat a block as an instruction, not an obstacle to work around.
120
138
 
121
139
  ## Wrap-up Gate
122
140
 
@@ -244,7 +262,7 @@ If a milestone has no dependencies, omit the frontmatter. The dependency chain f
244
262
 
245
263
  #### Phase 3: Sequential readiness gate for remaining milestones
246
264
 
247
- For each remaining milestone **one at a time, in sequence**, decide the most likely readiness mode from the evidence you already have, then use `ask_user_questions` to let the user correct that recommendation. **Non-bypassable:** If `ask_user_questions` fails, errors, returns no response, or the user's response does not match a provided option, you MUST re-ask — never rationalize past the block or auto-select a readiness mode. Present three options:
265
+ For each remaining milestone **one at a time, in sequence**, decide the most likely readiness mode from the evidence you already have, then present the three options below to the user. **If `{{structuredQuestionsAvailable}}` is `true`:** use `ask_user_questions`. **If `{{structuredQuestionsAvailable}}` is `false`:** present the options as a plain-text numbered list and ask the user to type their choice. **Non-bypassable:** If the user does not respond, gives an ambiguous answer, or the tool fails, you MUST re-ask — never rationalize past the block or auto-select a readiness mode. Present three options:
248
266
 
249
267
  - **"Discuss now"** — The user wants to conduct a focused discussion for this milestone in the current session, while the context from the broader discussion is still fresh. Proceed with a focused discussion for this milestone (reflection → investigation → questioning → depth verification). When the discussion concludes, write a full `CONTEXT.md`. Then move to the gate for the next milestone.
250
268
  - **"Write draft for later"** — This milestone has seed material from the current conversation but needs its own dedicated discussion in a future session. Write a `CONTEXT-DRAFT.md` capturing the seed material (what was discussed, key ideas, provisional scope, open questions). Mark it clearly as a draft, not a finalized context. **What happens downstream:** When auto-mode reaches this milestone, it pauses and notifies the user: "M00x has draft context — needs discussion. Run /gsd." The `/gsd` wizard shows a "Discuss from draft" option that seeds the new discussion with this draft, so nothing from the current conversation is lost. After the dedicated discussion produces a full CONTEXT.md, the draft file is automatically deleted.
@@ -256,9 +274,9 @@ Before writing each milestone's CONTEXT.md (whether primary or secondary), you M
256
274
 
257
275
  1. **Read the actual code** for every file or module you reference. Confirm APIs exist, check what functions actually do, identify phantom capabilities (code that exists but isn't wired up).
258
276
  2. **Check for stale assumptions** — the codebase changes. Verify referenced modules still work as described.
259
- 3. **Present findings** — use `ask_user_questions` with a question ID containing BOTH `depth_verification` AND the milestone ID (e.g., `depth_verification_M002`). Present: what you're about to write, key technical findings from investigation, risks the code review surfaced.
277
+ 3. **Present findings** — **If `{{structuredQuestionsAvailable}}` is `true`:** use `ask_user_questions` with a question ID containing BOTH `depth_verification` AND the milestone ID (e.g., `depth_verification_M002`). Present: what you're about to write, key technical findings from investigation, risks the code review surfaced. **If `{{structuredQuestionsAvailable}}` is `false`:** present the same findings in plain text and ask for explicit confirmation before proceeding.
260
278
 
261
- **The system mechanically blocks CONTEXT.md writes until the per-milestone depth verification passes.** Each milestone needs its own verification — one global verification does not unlock all milestones.
279
+ **The system mechanically blocks CONTEXT.md writes until the per-milestone depth verification passes** (structured path: user selects "(Recommended)" option; plain-text path: user explicitly confirms). Each milestone needs its own verification — one global verification does not unlock all milestones.
262
280
 
263
281
  **Why sequential, not batch:** After writing the primary milestone's context and roadmap, the agent still has context window capacity. Asking one milestone at a time lets the user decide per-milestone whether to invest that remaining capacity in a focused discussion now, or defer to a future session. A batch question ("Ready/Draft/Queue for M002, M003, M004?") forces the user to decide everything upfront without knowing how much session capacity remains.
264
282
 
@@ -23,12 +23,14 @@ export async function executeSummarySave(params, basePath = process.cwd()) {
23
23
  return {
24
24
  content: [{ type: "text", text: "Error: GSD database is not available. Cannot save artifact." }],
25
25
  details: { operation: "save_summary", error: "db_unavailable" },
26
+ isError: true,
26
27
  };
27
28
  }
28
29
  if (!isSupportedSummaryArtifactType(params.artifact_type)) {
29
30
  return {
30
31
  content: [{ type: "text", text: `Error: Invalid artifact_type "${params.artifact_type}". Must be one of: ${SUPPORTED_SUMMARY_ARTIFACT_TYPES.join(", ")}` }],
31
32
  details: { operation: "save_summary", error: "invalid_artifact_type" },
33
+ isError: true,
32
34
  };
33
35
  }
34
36
  const contextGuard = shouldBlockContextArtifactSaveInSnapshot(loadWriteGateSnapshot(basePath), params.artifact_type, params.milestone_id ?? null, params.slice_id ?? null);
@@ -36,6 +38,7 @@ export async function executeSummarySave(params, basePath = process.cwd()) {
36
38
  return {
37
39
  content: [{ type: "text", text: `Error saving artifact: ${contextGuard.reason ?? "context write blocked"}` }],
38
40
  details: { operation: "save_summary", error: "context_write_blocked" },
41
+ isError: true,
39
42
  };
40
43
  }
41
44
  try {
@@ -68,6 +71,7 @@ export async function executeSummarySave(params, basePath = process.cwd()) {
68
71
  return {
69
72
  content: [{ type: "text", text: `Error saving artifact: ${msg}` }],
70
73
  details: { operation: "save_summary", error: msg },
74
+ isError: true,
71
75
  };
72
76
  }
73
77
  }
@@ -77,6 +81,7 @@ export async function executeTaskComplete(params, basePath = process.cwd()) {
77
81
  return {
78
82
  content: [{ type: "text", text: "Error: GSD database is not available. Cannot complete task." }],
79
83
  details: { operation: "complete_task", error: "db_unavailable" },
84
+ isError: true,
80
85
  };
81
86
  }
82
87
  try {
@@ -87,6 +92,7 @@ export async function executeTaskComplete(params, basePath = process.cwd()) {
87
92
  return {
88
93
  content: [{ type: "text", text: `Error completing task: ${result.error}` }],
89
94
  details: { operation: "complete_task", error: result.error },
95
+ isError: true,
90
96
  };
91
97
  }
92
98
  return {
@@ -106,6 +112,7 @@ export async function executeTaskComplete(params, basePath = process.cwd()) {
106
112
  return {
107
113
  content: [{ type: "text", text: `Error completing task: ${msg}` }],
108
114
  details: { operation: "complete_task", error: msg },
115
+ isError: true,
109
116
  };
110
117
  }
111
118
  }
@@ -115,6 +122,7 @@ export async function executeSliceComplete(params, basePath = process.cwd()) {
115
122
  return {
116
123
  content: [{ type: "text", text: "Error: GSD database is not available. Cannot complete slice." }],
117
124
  details: { operation: "complete_slice", error: "db_unavailable" },
125
+ isError: true,
118
126
  };
119
127
  }
120
128
  try {
@@ -167,6 +175,7 @@ export async function executeSliceComplete(params, basePath = process.cwd()) {
167
175
  return {
168
176
  content: [{ type: "text", text: `Error completing slice: ${result.error}` }],
169
177
  details: { operation: "complete_slice", error: result.error },
178
+ isError: true,
170
179
  };
171
180
  }
172
181
  return {
@@ -186,6 +195,7 @@ export async function executeSliceComplete(params, basePath = process.cwd()) {
186
195
  return {
187
196
  content: [{ type: "text", text: `Error completing slice: ${msg}` }],
188
197
  details: { operation: "complete_slice", error: msg },
198
+ isError: true,
189
199
  };
190
200
  }
191
201
  }
@@ -195,6 +205,7 @@ export async function executeCompleteMilestone(params, basePath = process.cwd())
195
205
  return {
196
206
  content: [{ type: "text", text: "Error: GSD database is not available. Cannot complete milestone." }],
197
207
  details: { operation: "complete_milestone", error: "db_unavailable" },
208
+ isError: true,
198
209
  };
199
210
  }
200
211
  try {
@@ -204,6 +215,7 @@ export async function executeCompleteMilestone(params, basePath = process.cwd())
204
215
  return {
205
216
  content: [{ type: "text", text: `Error completing milestone: ${result.error}` }],
206
217
  details: { operation: "complete_milestone", error: result.error },
218
+ isError: true,
207
219
  };
208
220
  }
209
221
  return {
@@ -221,6 +233,7 @@ export async function executeCompleteMilestone(params, basePath = process.cwd())
221
233
  return {
222
234
  content: [{ type: "text", text: `Error completing milestone: ${msg}` }],
223
235
  details: { operation: "complete_milestone", error: msg },
236
+ isError: true,
224
237
  };
225
238
  }
226
239
  }
@@ -230,6 +243,7 @@ export async function executeValidateMilestone(params, basePath = process.cwd())
230
243
  return {
231
244
  content: [{ type: "text", text: "Error: GSD database is not available. Cannot validate milestone." }],
232
245
  details: { operation: "validate_milestone", error: "db_unavailable" },
246
+ isError: true,
233
247
  };
234
248
  }
235
249
  try {
@@ -238,6 +252,7 @@ export async function executeValidateMilestone(params, basePath = process.cwd())
238
252
  return {
239
253
  content: [{ type: "text", text: `Error validating milestone: ${result.error}` }],
240
254
  details: { operation: "validate_milestone", error: result.error },
255
+ isError: true,
241
256
  };
242
257
  }
243
258
  return {
@@ -256,6 +271,7 @@ export async function executeValidateMilestone(params, basePath = process.cwd())
256
271
  return {
257
272
  content: [{ type: "text", text: `Error validating milestone: ${msg}` }],
258
273
  details: { operation: "validate_milestone", error: msg },
274
+ isError: true,
259
275
  };
260
276
  }
261
277
  }
@@ -265,6 +281,7 @@ export async function executeReassessRoadmap(params, basePath = process.cwd()) {
265
281
  return {
266
282
  content: [{ type: "text", text: "Error: GSD database is not available. Cannot reassess roadmap." }],
267
283
  details: { operation: "reassess_roadmap", error: "db_unavailable" },
284
+ isError: true,
268
285
  };
269
286
  }
270
287
  try {
@@ -273,6 +290,7 @@ export async function executeReassessRoadmap(params, basePath = process.cwd()) {
273
290
  return {
274
291
  content: [{ type: "text", text: `Error reassessing roadmap: ${result.error}` }],
275
292
  details: { operation: "reassess_roadmap", error: result.error },
293
+ isError: true,
276
294
  };
277
295
  }
278
296
  return {
@@ -292,6 +310,7 @@ export async function executeReassessRoadmap(params, basePath = process.cwd()) {
292
310
  return {
293
311
  content: [{ type: "text", text: `Error reassessing roadmap: ${msg}` }],
294
312
  details: { operation: "reassess_roadmap", error: msg },
313
+ isError: true,
295
314
  };
296
315
  }
297
316
  }
@@ -301,6 +320,7 @@ export async function executeSaveGateResult(params, basePath = process.cwd()) {
301
320
  return {
302
321
  content: [{ type: "text", text: "Error: GSD database is not available." }],
303
322
  details: { operation: "save_gate_result", error: "db_unavailable" },
323
+ isError: true,
304
324
  };
305
325
  }
306
326
  const validGates = ["Q3", "Q4", "Q5", "Q6", "Q7", "Q8"];
@@ -308,6 +328,7 @@ export async function executeSaveGateResult(params, basePath = process.cwd()) {
308
328
  return {
309
329
  content: [{ type: "text", text: `Error: Invalid gateId "${params.gateId}". Must be one of: ${validGates.join(", ")}` }],
310
330
  details: { operation: "save_gate_result", error: "invalid_gate_id" },
331
+ isError: true,
311
332
  };
312
333
  }
313
334
  const validVerdicts = ["pass", "flag", "omitted"];
@@ -315,6 +336,7 @@ export async function executeSaveGateResult(params, basePath = process.cwd()) {
315
336
  return {
316
337
  content: [{ type: "text", text: `Error: Invalid verdict "${params.verdict}". Must be one of: ${validVerdicts.join(", ")}` }],
317
338
  details: { operation: "save_gate_result", error: "invalid_verdict" },
339
+ isError: true,
318
340
  };
319
341
  }
320
342
  try {
@@ -339,6 +361,7 @@ export async function executeSaveGateResult(params, basePath = process.cwd()) {
339
361
  return {
340
362
  content: [{ type: "text", text: `Error saving gate result: ${msg}` }],
341
363
  details: { operation: "save_gate_result", error: msg },
364
+ isError: true,
342
365
  };
343
366
  }
344
367
  }
@@ -348,6 +371,7 @@ export async function executePlanMilestone(params, basePath = process.cwd()) {
348
371
  return {
349
372
  content: [{ type: "text", text: "Error: GSD database is not available. Cannot plan milestone." }],
350
373
  details: { operation: "plan_milestone", error: "db_unavailable" },
374
+ isError: true,
351
375
  };
352
376
  }
353
377
  try {
@@ -356,6 +380,7 @@ export async function executePlanMilestone(params, basePath = process.cwd()) {
356
380
  return {
357
381
  content: [{ type: "text", text: `Error planning milestone: ${result.error}` }],
358
382
  details: { operation: "plan_milestone", error: result.error },
383
+ isError: true,
359
384
  };
360
385
  }
361
386
  return {
@@ -373,6 +398,7 @@ export async function executePlanMilestone(params, basePath = process.cwd()) {
373
398
  return {
374
399
  content: [{ type: "text", text: `Error planning milestone: ${msg}` }],
375
400
  details: { operation: "plan_milestone", error: msg },
401
+ isError: true,
376
402
  };
377
403
  }
378
404
  }
@@ -382,6 +408,7 @@ export async function executePlanSlice(params, basePath = process.cwd()) {
382
408
  return {
383
409
  content: [{ type: "text", text: "Error: GSD database is not available. Cannot plan slice." }],
384
410
  details: { operation: "plan_slice", error: "db_unavailable" },
411
+ isError: true,
385
412
  };
386
413
  }
387
414
  try {
@@ -390,6 +417,7 @@ export async function executePlanSlice(params, basePath = process.cwd()) {
390
417
  return {
391
418
  content: [{ type: "text", text: `Error planning slice: ${result.error}` }],
392
419
  details: { operation: "plan_slice", error: result.error },
420
+ isError: true,
393
421
  };
394
422
  }
395
423
  return {
@@ -409,6 +437,7 @@ export async function executePlanSlice(params, basePath = process.cwd()) {
409
437
  return {
410
438
  content: [{ type: "text", text: `Error planning slice: ${msg}` }],
411
439
  details: { operation: "plan_slice", error: msg },
440
+ isError: true,
412
441
  };
413
442
  }
414
443
  }
@@ -418,6 +447,7 @@ export async function executeReplanSlice(params, basePath = process.cwd()) {
418
447
  return {
419
448
  content: [{ type: "text", text: "Error: GSD database is not available. Cannot replan slice." }],
420
449
  details: { operation: "replan_slice", error: "db_unavailable" },
450
+ isError: true,
421
451
  };
422
452
  }
423
453
  try {
@@ -426,6 +456,7 @@ export async function executeReplanSlice(params, basePath = process.cwd()) {
426
456
  return {
427
457
  content: [{ type: "text", text: `Error replanning slice: ${result.error}` }],
428
458
  details: { operation: "replan_slice", error: result.error },
459
+ isError: true,
429
460
  };
430
461
  }
431
462
  return {
@@ -445,6 +476,7 @@ export async function executeReplanSlice(params, basePath = process.cwd()) {
445
476
  return {
446
477
  content: [{ type: "text", text: `Error replanning slice: ${msg}` }],
447
478
  details: { operation: "replan_slice", error: msg },
479
+ isError: true,
448
480
  };
449
481
  }
450
482
  }
@@ -455,6 +487,7 @@ export async function executeMilestoneStatus(params, basePath = process.cwd()) {
455
487
  return {
456
488
  content: [{ type: "text", text: "Error: GSD database is not available." }],
457
489
  details: { operation: "milestone_status", error: "db_unavailable" },
490
+ isError: true,
458
491
  };
459
492
  }
460
493
  const adapter = _getAdapter();
@@ -503,6 +536,7 @@ export async function executeMilestoneStatus(params, basePath = process.cwd()) {
503
536
  return {
504
537
  content: [{ type: "text", text: `Error querying milestone status: ${msg}` }],
505
538
  details: { operation: "milestone_status", error: msg },
539
+ isError: true,
506
540
  };
507
541
  }
508
542
  }