gsd-pi 2.70.1 → 2.71.0-dev.06b86c6

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 (335) hide show
  1. package/README.md +24 -17
  2. package/dist/cli.js +12 -3
  3. package/dist/mcp-server.js +6 -6
  4. package/dist/provider-migrations.d.ts +10 -0
  5. package/dist/provider-migrations.js +12 -0
  6. package/dist/resource-loader.js +136 -13
  7. package/dist/resources/GSD-WORKFLOW.md +1 -1
  8. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +129 -30
  9. package/dist/resources/extensions/get-secrets-from-user.js +17 -1
  10. package/dist/resources/extensions/gsd/auto-start.js +4 -12
  11. package/dist/resources/extensions/gsd/auto-tool-tracking.js +1 -1
  12. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +6 -0
  13. package/dist/resources/extensions/gsd/bootstrap/system-context.js +6 -0
  14. package/dist/resources/extensions/gsd/commands/context.js +15 -6
  15. package/dist/resources/extensions/gsd/commands/dispatcher.js +12 -2
  16. package/dist/resources/extensions/gsd/custom-workflow-engine.js +16 -12
  17. package/dist/resources/extensions/gsd/dispatch-guard.js +18 -1
  18. package/dist/resources/extensions/gsd/error-classifier.js +1 -1
  19. package/dist/resources/extensions/gsd/file-lock.js +60 -0
  20. package/dist/resources/extensions/gsd/guided-flow.js +12 -10
  21. package/dist/resources/extensions/gsd/init-wizard.js +3 -11
  22. package/dist/resources/extensions/gsd/notification-store.js +21 -1
  23. package/dist/resources/extensions/gsd/notification-widget.js +1 -1
  24. package/dist/resources/extensions/gsd/pre-execution-checks.js +35 -2
  25. package/dist/resources/extensions/gsd/prompts/complete-slice.md +2 -2
  26. package/dist/resources/extensions/gsd/prompts/discuss.md +33 -13
  27. package/dist/resources/extensions/gsd/prompts/execute-task.md +20 -19
  28. package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +2 -0
  29. package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +2 -0
  30. package/dist/resources/extensions/gsd/prompts/guided-resume-task.md +1 -1
  31. package/dist/resources/extensions/gsd/prompts/queue.md +3 -2
  32. package/dist/resources/extensions/gsd/prompts/system.md +1 -0
  33. package/dist/resources/extensions/gsd/prompts/validate-milestone.md +2 -1
  34. package/dist/resources/extensions/gsd/state.js +234 -332
  35. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +34 -0
  36. package/dist/resources/extensions/gsd/workflow-events.js +25 -13
  37. package/dist/resources/extensions/gsd/workflow-mcp-auto-prep.js +56 -0
  38. package/dist/resources/extensions/gsd/workflow-mcp.js +1 -1
  39. package/dist/resources/skills/create-skill/SKILL.md +2 -0
  40. package/dist/web/standalone/.next/BUILD_ID +1 -1
  41. package/dist/web/standalone/.next/app-path-routes-manifest.json +15 -15
  42. package/dist/web/standalone/.next/build-manifest.json +4 -4
  43. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  44. package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
  45. package/dist/web/standalone/.next/required-server-files.json +3 -3
  46. package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
  47. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  48. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  49. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  50. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  51. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  52. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  53. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  54. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  55. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  56. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  57. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  58. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  59. package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
  60. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
  61. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  62. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
  63. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  64. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  65. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  66. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  67. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  68. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  69. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  70. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  71. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  72. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
  73. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  74. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  75. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  76. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  77. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  78. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  79. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  80. package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
  81. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  82. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  83. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  84. package/dist/web/standalone/.next/server/app/api/experimental/route.js +2 -2
  85. package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
  86. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  87. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  88. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  89. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  90. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  91. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  92. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  93. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  94. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  95. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  96. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  97. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  98. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  99. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  100. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  101. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  102. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  103. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  104. package/dist/web/standalone/.next/server/app/api/notifications/route.js +2 -2
  105. package/dist/web/standalone/.next/server/app/api/notifications/route_client-reference-manifest.js +1 -1
  106. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  107. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  108. package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
  109. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  110. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  111. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  112. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  113. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  114. package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +2 -2
  115. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  116. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  117. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  118. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  119. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  120. package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
  121. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  122. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  123. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  124. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  125. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  126. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  127. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  128. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  129. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  130. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  131. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  132. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
  133. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
  134. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +1 -1
  135. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  136. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
  137. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  138. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +1 -1
  139. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  140. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +2 -2
  141. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  142. package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
  143. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  144. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  145. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  146. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  147. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  148. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  149. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  150. package/dist/web/standalone/.next/server/app/index.html +1 -1
  151. package/dist/web/standalone/.next/server/app/index.rsc +4 -4
  152. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  153. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
  154. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  155. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +3 -3
  156. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  157. package/dist/web/standalone/.next/server/app/page.js +2 -2
  158. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  159. package/dist/web/standalone/.next/server/app-paths-manifest.json +15 -15
  160. package/dist/web/standalone/.next/server/chunks/63.js +3 -3
  161. package/dist/web/standalone/.next/server/chunks/6897.js +1 -1
  162. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  163. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  164. package/dist/web/standalone/.next/server/middleware.js +2 -2
  165. package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
  166. package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
  167. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  168. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  169. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  170. package/dist/web/standalone/.next/static/chunks/2826.dd3dc8bbd3025fa5.js +9 -0
  171. package/dist/web/standalone/.next/static/chunks/app/_not-found/{page-2f24283c162b6ab3.js → page-f2a7482d42a5614b.js} +1 -1
  172. package/dist/web/standalone/.next/static/chunks/app/{layout-9ecfd95f343793f0.js → layout-a16c7a7ecdf0c2cf.js} +1 -1
  173. package/dist/web/standalone/.next/static/chunks/app/page-f1e30ab6bb269149.js +1 -0
  174. package/dist/web/standalone/.next/static/chunks/main-app-fdab67f7802d7832.js +1 -0
  175. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +1 -0
  176. package/dist/web/standalone/.next/static/chunks/{webpack-6e4d7e9a4f57bed4.js → webpack-b868033a5834586d.js} +1 -1
  177. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  178. package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
  179. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  180. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
  181. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
  182. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
  183. package/dist/web/standalone/server.js +1 -1
  184. package/package.json +1 -1
  185. package/packages/mcp-server/dist/env-writer.d.ts +39 -0
  186. package/packages/mcp-server/dist/env-writer.d.ts.map +1 -0
  187. package/packages/mcp-server/dist/env-writer.js +158 -0
  188. package/packages/mcp-server/dist/env-writer.js.map +1 -0
  189. package/packages/mcp-server/dist/server.d.ts +11 -2
  190. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  191. package/packages/mcp-server/dist/server.js +102 -2
  192. package/packages/mcp-server/dist/server.js.map +1 -1
  193. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  194. package/packages/mcp-server/dist/workflow-tools.js +21 -11
  195. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  196. package/packages/mcp-server/src/env-writer.test.ts +280 -0
  197. package/packages/mcp-server/src/env-writer.ts +183 -0
  198. package/packages/mcp-server/src/secure-env-collect.test.ts +265 -0
  199. package/packages/mcp-server/src/server.ts +137 -3
  200. package/packages/mcp-server/src/workflow-tools.test.ts +110 -0
  201. package/packages/mcp-server/src/workflow-tools.ts +31 -11
  202. package/packages/pi-ai/dist/providers/amazon-bedrock.js +11 -2
  203. package/packages/pi-ai/dist/providers/amazon-bedrock.js.map +1 -1
  204. package/packages/pi-ai/dist/providers/anthropic-shared.d.ts +4 -1
  205. package/packages/pi-ai/dist/providers/anthropic-shared.d.ts.map +1 -1
  206. package/packages/pi-ai/dist/providers/anthropic-shared.js +8 -3
  207. package/packages/pi-ai/dist/providers/anthropic-shared.js.map +1 -1
  208. package/packages/pi-ai/dist/providers/anthropic-shared.test.js +44 -1
  209. package/packages/pi-ai/dist/providers/anthropic-shared.test.js.map +1 -1
  210. package/packages/pi-ai/dist/providers/openai-completions.d.ts.map +1 -1
  211. package/packages/pi-ai/dist/providers/openai-completions.js +11 -0
  212. package/packages/pi-ai/dist/providers/openai-completions.js.map +1 -1
  213. package/packages/pi-ai/src/providers/amazon-bedrock.ts +13 -1
  214. package/packages/pi-ai/src/providers/anthropic-shared.test.ts +55 -1
  215. package/packages/pi-ai/src/providers/anthropic-shared.ts +14 -3
  216. package/packages/pi-ai/src/providers/openai-completions.ts +14 -0
  217. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.d.ts +2 -0
  218. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.d.ts.map +1 -0
  219. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +388 -0
  220. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -0
  221. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +2 -0
  222. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  223. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  224. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.d.ts +19 -2
  225. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -1
  226. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.js +50 -1
  227. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.js.map +1 -1
  228. package/packages/pi-coding-agent/dist/modes/interactive/components/extension-input.d.ts +1 -0
  229. package/packages/pi-coding-agent/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
  230. package/packages/pi-coding-agent/dist/modes/interactive/components/extension-input.js +1 -0
  231. package/packages/pi-coding-agent/dist/modes/interactive/components/extension-input.js.map +1 -1
  232. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  233. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +168 -23
  234. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  235. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts +1 -0
  236. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -1
  237. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js.map +1 -1
  238. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +6 -0
  239. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  240. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +58 -2
  241. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  242. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js +1 -1
  243. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js.map +1 -1
  244. package/packages/pi-coding-agent/dist/modes/rpc/rpc-types.d.ts +1 -0
  245. package/packages/pi-coding-agent/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  246. package/packages/pi-coding-agent/dist/modes/rpc/rpc-types.js.map +1 -1
  247. package/packages/pi-coding-agent/package.json +1 -1
  248. package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +468 -0
  249. package/packages/pi-coding-agent/src/core/extensions/types.ts +2 -0
  250. package/packages/pi-coding-agent/src/modes/interactive/components/dynamic-border.ts +58 -2
  251. package/packages/pi-coding-agent/src/modes/interactive/components/extension-input.ts +2 -0
  252. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +198 -29
  253. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-state.ts +1 -0
  254. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +66 -2
  255. package/packages/pi-coding-agent/src/modes/rpc/rpc-mode.ts +1 -1
  256. package/packages/pi-coding-agent/src/modes/rpc/rpc-types.ts +1 -0
  257. package/packages/pi-tui/dist/components/__tests__/input.test.js +9 -0
  258. package/packages/pi-tui/dist/components/__tests__/input.test.js.map +1 -1
  259. package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.d.ts +2 -0
  260. package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.d.ts.map +1 -0
  261. package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.js +66 -0
  262. package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.js.map +1 -0
  263. package/packages/pi-tui/dist/components/input.d.ts +2 -0
  264. package/packages/pi-tui/dist/components/input.d.ts.map +1 -1
  265. package/packages/pi-tui/dist/components/input.js +7 -4
  266. package/packages/pi-tui/dist/components/input.js.map +1 -1
  267. package/packages/pi-tui/dist/components/markdown.d.ts +3 -0
  268. package/packages/pi-tui/dist/components/markdown.d.ts.map +1 -1
  269. package/packages/pi-tui/dist/components/markdown.js +17 -1
  270. package/packages/pi-tui/dist/components/markdown.js.map +1 -1
  271. package/packages/pi-tui/src/components/__tests__/input.test.ts +11 -0
  272. package/packages/pi-tui/src/components/__tests__/markdown-maxlines.test.ts +75 -0
  273. package/packages/pi-tui/src/components/input.ts +7 -4
  274. package/packages/pi-tui/src/components/markdown.ts +22 -1
  275. package/pkg/package.json +1 -1
  276. package/src/resources/GSD-WORKFLOW.md +1 -1
  277. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +166 -31
  278. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +145 -0
  279. package/src/resources/extensions/get-secrets-from-user.ts +24 -1
  280. package/src/resources/extensions/gsd/auto-start.ts +4 -14
  281. package/src/resources/extensions/gsd/auto-tool-tracking.ts +1 -1
  282. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +6 -0
  283. package/src/resources/extensions/gsd/bootstrap/system-context.ts +7 -0
  284. package/src/resources/extensions/gsd/commands/context.ts +16 -5
  285. package/src/resources/extensions/gsd/commands/dispatcher.ts +14 -2
  286. package/src/resources/extensions/gsd/custom-workflow-engine.ts +19 -14
  287. package/src/resources/extensions/gsd/dispatch-guard.ts +18 -1
  288. package/src/resources/extensions/gsd/error-classifier.ts +1 -1
  289. package/src/resources/extensions/gsd/file-lock.ts +59 -0
  290. package/src/resources/extensions/gsd/guided-flow.ts +12 -9
  291. package/src/resources/extensions/gsd/init-wizard.ts +3 -13
  292. package/src/resources/extensions/gsd/notification-store.ts +19 -1
  293. package/src/resources/extensions/gsd/notification-widget.ts +1 -1
  294. package/src/resources/extensions/gsd/pre-execution-checks.ts +39 -2
  295. package/src/resources/extensions/gsd/prompts/complete-slice.md +2 -2
  296. package/src/resources/extensions/gsd/prompts/discuss.md +33 -13
  297. package/src/resources/extensions/gsd/prompts/execute-task.md +20 -19
  298. package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +2 -0
  299. package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +2 -0
  300. package/src/resources/extensions/gsd/prompts/guided-resume-task.md +1 -1
  301. package/src/resources/extensions/gsd/prompts/queue.md +3 -2
  302. package/src/resources/extensions/gsd/prompts/system.md +1 -0
  303. package/src/resources/extensions/gsd/prompts/validate-milestone.md +2 -1
  304. package/src/resources/extensions/gsd/state.ts +274 -344
  305. package/src/resources/extensions/gsd/tests/auto-start-worktree-db-path.test.ts +28 -0
  306. package/src/resources/extensions/gsd/tests/bootstrap-derive-state-db-open.test.ts +39 -0
  307. package/src/resources/extensions/gsd/tests/complete-slice-prompt-task-summary-layout.test.ts +18 -0
  308. package/src/resources/extensions/gsd/tests/derive-state-helpers.test.ts +436 -0
  309. package/src/resources/extensions/gsd/tests/discuss-incremental-persistence.test.ts +9 -0
  310. package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +27 -0
  311. package/src/resources/extensions/gsd/tests/execute-task-prompt-existing-artifact-guard.test.ts +33 -0
  312. package/src/resources/extensions/gsd/tests/file-lock.test.ts +103 -0
  313. package/src/resources/extensions/gsd/tests/gsd-no-project-error.test.ts +73 -0
  314. package/src/resources/extensions/gsd/tests/notification-store.test.ts +17 -0
  315. package/src/resources/extensions/gsd/tests/notification-widget.test.ts +25 -0
  316. package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +49 -0
  317. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +19 -0
  318. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +7 -0
  319. package/src/resources/extensions/gsd/tests/secure-env-collect.test.ts +45 -0
  320. package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +7 -0
  321. package/src/resources/extensions/gsd/tests/validate-milestone-prompt-verification-classes.test.ts +18 -0
  322. package/src/resources/extensions/gsd/tests/workflow-mcp-auto-prep.test.ts +76 -0
  323. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +155 -1
  324. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +22 -0
  325. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +60 -25
  326. package/src/resources/extensions/gsd/workflow-events.ts +34 -25
  327. package/src/resources/extensions/gsd/workflow-mcp-auto-prep.ts +76 -0
  328. package/src/resources/extensions/gsd/workflow-mcp.ts +1 -1
  329. package/src/resources/skills/create-skill/SKILL.md +2 -0
  330. package/dist/web/standalone/.next/static/chunks/2826.821e01b07d92e948.js +0 -9
  331. package/dist/web/standalone/.next/static/chunks/app/page-7115e62689b5fd84.js +0 -1
  332. package/dist/web/standalone/.next/static/chunks/main-app-d3d4c336195465f9.js +0 -1
  333. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ab5a8926e07ec673.js +0 -1
  334. /package/dist/web/standalone/.next/static/{9pw9EXtXjdM7EFrCXUEPf → dYVdRaunb2ZSEA8fjkT-V}/_buildManifest.js +0 -0
  335. /package/dist/web/standalone/.next/static/{9pw9EXtXjdM7EFrCXUEPf → dYVdRaunb2ZSEA8fjkT-V}/_ssgManifest.js +0 -0
@@ -0,0 +1,75 @@
1
+ import assert from "node:assert/strict";
2
+ import { test } from "node:test";
3
+
4
+ import { Markdown, type MarkdownTheme } from "../markdown.js";
5
+
6
+ function noopTheme(): MarkdownTheme {
7
+ const identity = (text: string) => text;
8
+ return {
9
+ heading: identity,
10
+ link: identity,
11
+ linkUrl: identity,
12
+ code: identity,
13
+ codeBlock: identity,
14
+ codeBlockBorder: identity,
15
+ quote: identity,
16
+ quoteBorder: identity,
17
+ hr: identity,
18
+ listBullet: identity,
19
+ bold: identity,
20
+ italic: identity,
21
+ strikethrough: identity,
22
+ underline: identity,
23
+ };
24
+ }
25
+
26
+ test("Markdown renders all lines when maxLines is not set", () => {
27
+ const text = "Line 1\n\nLine 2\n\nLine 3\n\nLine 4\n\nLine 5";
28
+ const md = new Markdown(text, 0, 0, noopTheme());
29
+ const lines = md.render(80);
30
+ // Each paragraph produces a line + an inter-paragraph blank line
31
+ const contentLines = lines.filter((l) => l.trim().length > 0);
32
+ assert.ok(contentLines.length >= 5, `expected at least 5 content lines, got ${contentLines.length}`);
33
+ });
34
+
35
+ test("Markdown truncates from the top when maxLines is exceeded", () => {
36
+ const text = "Line 1\n\nLine 2\n\nLine 3\n\nLine 4\n\nLine 5";
37
+ const md = new Markdown(text, 0, 0, noopTheme());
38
+ md.maxLines = 3;
39
+ const lines = md.render(80);
40
+ assert.ok(lines.length <= 3, `expected at most 3 lines, got ${lines.length}`);
41
+ // First line should be the ellipsis indicator
42
+ assert.ok(lines[0].includes("…"), "first line should contain ellipsis indicator");
43
+ assert.ok(lines[0].includes("above"), "first line should mention lines above");
44
+ });
45
+
46
+ test("Markdown preserves most recent content when truncating", () => {
47
+ const text = "First paragraph\n\nSecond paragraph\n\nThird paragraph\n\nFourth paragraph\n\nFifth paragraph";
48
+ const md = new Markdown(text, 0, 0, noopTheme());
49
+ md.maxLines = 3;
50
+ const lines = md.render(80);
51
+ // The last rendered line should contain "Fifth paragraph" (the most recent content)
52
+ const lastContentLine = lines.filter((l) => !l.includes("…")).pop() ?? "";
53
+ assert.ok(
54
+ lastContentLine.includes("Fifth paragraph"),
55
+ `expected last content line to contain "Fifth paragraph", got "${lastContentLine}"`,
56
+ );
57
+ });
58
+
59
+ test("Markdown does not truncate when content fits within maxLines", () => {
60
+ const text = "Short text";
61
+ const md = new Markdown(text, 0, 0, noopTheme());
62
+ md.maxLines = 10;
63
+ const lines = md.render(80);
64
+ assert.ok(!lines.some((l) => l.includes("…")), "should not contain ellipsis when content fits");
65
+ assert.ok(lines.some((l) => l.includes("Short text")), "should contain the original text");
66
+ });
67
+
68
+ test("Markdown trims trailing empty lines", () => {
69
+ const text = "Some text\n\n";
70
+ const md = new Markdown(text, 0, 0, noopTheme());
71
+ const lines = md.render(80);
72
+ // Last line should not be empty (trailing empties are trimmed)
73
+ const lastLine = lines[lines.length - 1];
74
+ assert.ok(lastLine.trim().length > 0 || lines.length === 1, "trailing empty lines should be trimmed");
75
+ });
@@ -21,6 +21,8 @@ export class Input implements Component, Focusable {
21
21
  public onSubmit?: (value: string) => void;
22
22
  public onEscape?: () => void;
23
23
  public placeholder: string = "";
24
+ /** When true, render obscured characters instead of the actual value. */
25
+ public secure: boolean = false;
24
26
 
25
27
  /** Focusable interface - set by TUI when focus changes */
26
28
  private _focused: boolean = false;
@@ -446,6 +448,7 @@ export class Input implements Component, Focusable {
446
448
  // Calculate visible window
447
449
  const prompt = "> ";
448
450
  const availableWidth = width - prompt.length;
451
+ const renderValue = this.secure ? "*".repeat(this.value.length) : this.value;
449
452
 
450
453
  if (availableWidth <= 0) {
451
454
  return [prompt];
@@ -466,7 +469,7 @@ export class Input implements Component, Focusable {
466
469
 
467
470
  if (this.value.length < availableWidth) {
468
471
  // Everything fits (leave room for cursor at end)
469
- visibleText = this.value;
472
+ visibleText = renderValue;
470
473
  } else {
471
474
  // Need horizontal scrolling
472
475
  // Reserve one character for cursor if it's at the end
@@ -501,17 +504,17 @@ export class Input implements Component, Focusable {
501
504
 
502
505
  if (this.cursor < halfWidth) {
503
506
  // Cursor near start
504
- visibleText = this.value.slice(0, findValidEnd(scrollWidth));
507
+ visibleText = renderValue.slice(0, findValidEnd(scrollWidth));
505
508
  cursorDisplay = this.cursor;
506
509
  } else if (this.cursor > this.value.length - halfWidth) {
507
510
  // Cursor near end
508
511
  const start = findValidStart(this.value.length - scrollWidth);
509
- visibleText = this.value.slice(start);
512
+ visibleText = renderValue.slice(start);
510
513
  cursorDisplay = this.cursor - start;
511
514
  } else {
512
515
  // Cursor in middle
513
516
  const start = findValidStart(this.cursor - halfWidth);
514
- visibleText = this.value.slice(start, findValidEnd(start + scrollWidth));
517
+ visibleText = renderValue.slice(start, findValidEnd(start + scrollWidth));
515
518
  cursorDisplay = halfWidth;
516
519
  }
517
520
  }
@@ -58,10 +58,13 @@ export class Markdown implements Component {
58
58
  private defaultTextStyle?: DefaultTextStyle;
59
59
  private theme: MarkdownTheme;
60
60
  private defaultStylePrefix?: string;
61
+ /** Maximum rendered lines (excluding padding). When set, content is truncated from the top with an ellipsis indicator so the most recent output remains visible. */
62
+ maxLines?: number;
61
63
 
62
64
  // Cache for rendered output
63
65
  private cachedText?: string;
64
66
  private cachedWidth?: number;
67
+ private cachedMaxLines?: number;
65
68
  private cachedLines?: string[];
66
69
 
67
70
  constructor(
@@ -86,12 +89,13 @@ export class Markdown implements Component {
86
89
  invalidate(): void {
87
90
  this.cachedText = undefined;
88
91
  this.cachedWidth = undefined;
92
+ this.cachedMaxLines = undefined;
89
93
  this.cachedLines = undefined;
90
94
  }
91
95
 
92
96
  render(width: number): string[] {
93
97
  // Check cache
94
- if (this.cachedLines && this.cachedText === this.text && this.cachedWidth === width) {
98
+ if (this.cachedLines && this.cachedText === this.text && this.cachedWidth === width && this.cachedMaxLines === this.maxLines) {
95
99
  return this.cachedLines;
96
100
  }
97
101
 
@@ -104,6 +108,7 @@ export class Markdown implements Component {
104
108
  // Update cache
105
109
  this.cachedText = this.text;
106
110
  this.cachedWidth = width;
111
+ this.cachedMaxLines = this.maxLines;
107
112
  this.cachedLines = result;
108
113
  return result;
109
114
  }
@@ -124,6 +129,12 @@ export class Markdown implements Component {
124
129
  for (let j = 0; j < tokenLines.length; j++) renderedLines.push(tokenLines[j]);
125
130
  }
126
131
 
132
+ // Trim trailing empty lines — inter-block spacing at the end just adds
133
+ // unwanted whitespace before whatever follows (e.g. pinned output border).
134
+ while (renderedLines.length > 0 && renderedLines[renderedLines.length - 1] === "") {
135
+ renderedLines.pop();
136
+ }
137
+
127
138
  // Wrap lines (NO padding, NO background yet)
128
139
  const wrappedLines: string[] = [];
129
140
  for (const line of renderedLines) {
@@ -143,6 +154,15 @@ export class Markdown implements Component {
143
154
  }
144
155
  }
145
156
 
157
+ // Truncate from the top when maxLines is set so the most recent content
158
+ // stays visible. This prevents the pinned output zone from exceeding the
159
+ // terminal height and causing render flashing.
160
+ if (this.maxLines !== undefined && wrappedLines.length > this.maxLines) {
161
+ const keep = Math.max(1, this.maxLines - 1); // Reserve one line for the ellipsis indicator
162
+ const truncated = wrappedLines.length - keep;
163
+ wrappedLines.splice(0, truncated, `… ${truncated} line${truncated !== 1 ? "s" : ""} above`);
164
+ }
165
+
146
166
  // Add margins and background to each wrapped line
147
167
  const leftMargin = " ".repeat(this.paddingX);
148
168
  const rightMargin = " ".repeat(this.paddingX);
@@ -181,6 +201,7 @@ export class Markdown implements Component {
181
201
  // Update cache
182
202
  this.cachedText = this.text;
183
203
  this.cachedWidth = width;
204
+ this.cachedMaxLines = this.maxLines;
184
205
  this.cachedLines = result;
185
206
 
186
207
  return result.length > 0 ? result : [""];
package/pkg/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@glittercowboy/gsd",
3
- "version": "2.70.1",
3
+ "version": "2.71.0",
4
4
  "piConfig": {
5
5
  "name": "gsd",
6
6
  "configDir": ".gsd"
@@ -275,7 +275,7 @@ Work flows through these phases. Each phase produces a file.
275
275
  **How to do it manually:**
276
276
  1. Read the roadmap to understand the scope.
277
277
  2. Identify 3-5 gray areas — implementation decisions the user cares about.
278
- 3. Use `ask_user_questions` to discuss each area.
278
+ 3. Use `ask_user_questions` to discuss each area, one round at a time. Never fabricate user input; wait for the user's actual response before the next round.
279
279
  4. Write decisions to the appropriate context file (`M###-CONTEXT.md` or `S##-CONTEXT.md`).
280
280
  5. Do NOT discuss how to implement — only what the user wants.
281
281
 
@@ -60,6 +60,8 @@ interface SdkElicitationFieldSchema {
60
60
  type?: string;
61
61
  title?: string;
62
62
  description?: string;
63
+ format?: string;
64
+ writeOnly?: boolean;
63
65
  oneOf?: SdkElicitationRequestOption[];
64
66
  items?: {
65
67
  anyOf?: SdkElicitationRequestOption[];
@@ -73,6 +75,7 @@ interface SdkElicitationRequest {
73
75
  requestedSchema?: {
74
76
  type?: string;
75
77
  properties?: Record<string, SdkElicitationFieldSchema>;
78
+ required?: string[];
76
79
  };
77
80
  }
78
81
 
@@ -85,7 +88,16 @@ interface ParsedElicitationQuestion extends Question {
85
88
  noteFieldId?: string;
86
89
  }
87
90
 
91
+ interface ParsedTextInputField {
92
+ id: string;
93
+ title: string;
94
+ description: string;
95
+ required: boolean;
96
+ secure: boolean;
97
+ }
98
+
88
99
  const OTHER_OPTION_LABEL = "None of the above";
100
+ const SENSITIVE_FIELD_PATTERN = /(password|passphrase|secret|token|api[_\s-]*key|private[_\s-]*key|credential)/i;
89
101
 
90
102
  // ---------------------------------------------------------------------------
91
103
  // Stream factory
@@ -274,6 +286,67 @@ export function parseAskUserQuestionsElicitation(
274
286
  return questions.length > 0 ? questions : null;
275
287
  }
276
288
 
289
+ function isSecureElicitationField(
290
+ requestMessage: string,
291
+ fieldId: string,
292
+ field: SdkElicitationFieldSchema,
293
+ ): boolean {
294
+ if (field.format === "password") return true;
295
+ if (field.writeOnly === true) return true;
296
+
297
+ const rawField = field as Record<string, unknown>;
298
+ if (rawField.sensitive === true || rawField["x-sensitive"] === true) return true;
299
+
300
+ const haystack = [
301
+ requestMessage,
302
+ fieldId.replace(/[_-]+/g, " "),
303
+ typeof field.title === "string" ? field.title : "",
304
+ typeof field.description === "string" ? field.description : "",
305
+ ]
306
+ .join(" ")
307
+ .toLowerCase();
308
+
309
+ return SENSITIVE_FIELD_PATTERN.test(haystack);
310
+ }
311
+
312
+ export function parseTextInputElicitation(
313
+ request: Pick<SdkElicitationRequest, "message" | "mode" | "requestedSchema">,
314
+ ): ParsedTextInputField[] | null {
315
+ if (request.mode && request.mode !== "form") return null;
316
+ const schema = request.requestedSchema as
317
+ | ({ properties?: Record<string, SdkElicitationFieldSchema>; keys?: Record<string, SdkElicitationFieldSchema> } & Record<string, unknown>)
318
+ | undefined;
319
+ const fieldsSource = schema?.properties && typeof schema.properties === "object"
320
+ ? schema.properties
321
+ : schema?.keys && typeof schema.keys === "object"
322
+ ? schema.keys
323
+ : undefined;
324
+ if (!fieldsSource) return null;
325
+
326
+ const requiredSet = new Set(
327
+ Array.isArray(request.requestedSchema?.required)
328
+ ? request.requestedSchema.required.filter((value): value is string => typeof value === "string")
329
+ : [],
330
+ );
331
+
332
+ const fields: ParsedTextInputField[] = [];
333
+ for (const [fieldId, field] of Object.entries(fieldsSource)) {
334
+ if (!field || typeof field !== "object") continue;
335
+ if (field.type !== "string") continue;
336
+ if (Array.isArray(field.oneOf) && field.oneOf.length > 0) continue;
337
+
338
+ fields.push({
339
+ id: fieldId,
340
+ title: typeof field.title === "string" && field.title.length > 0 ? field.title : fieldId,
341
+ description: typeof field.description === "string" ? field.description : "",
342
+ required: requiredSet.has(fieldId),
343
+ secure: isSecureElicitationField(request.message, fieldId, field),
344
+ });
345
+ }
346
+
347
+ return fields.length > 0 ? fields : null;
348
+ }
349
+
277
350
  export function roundResultToElicitationContent(
278
351
  questions: ParsedElicitationQuestion[],
279
352
  result: RoundResult,
@@ -355,6 +428,52 @@ async function promptElicitationWithDialogs(
355
428
  return { action: "accept", content };
356
429
  }
357
430
 
431
+ function buildTextInputPromptTitle(request: SdkElicitationRequest, field: ParsedTextInputField): string {
432
+ const parts = [
433
+ request.serverName ? `[${request.serverName}]` : "",
434
+ field.title,
435
+ field.description,
436
+ ].filter((part) => typeof part === "string" && part.trim().length > 0);
437
+ return parts.join("\n\n");
438
+ }
439
+
440
+ function buildTextInputPlaceholder(field: ParsedTextInputField): string | undefined {
441
+ const desc = field.description.trim();
442
+ if (!desc) return field.required ? "Required" : "Leave empty to skip";
443
+
444
+ const formatLine = desc
445
+ .split(/\r?\n/)
446
+ .map((line) => line.trim())
447
+ .find((line) => /^format:/i.test(line));
448
+
449
+ if (!formatLine) return field.required ? "Required" : "Leave empty to skip";
450
+ const hint = formatLine.replace(/^format:\s*/i, "").trim();
451
+ return hint.length > 0 ? hint : field.required ? "Required" : "Leave empty to skip";
452
+ }
453
+
454
+ async function promptTextInputElicitation(
455
+ request: SdkElicitationRequest,
456
+ fields: ParsedTextInputField[],
457
+ ui: ExtensionUIContext,
458
+ signal: AbortSignal,
459
+ ): Promise<SdkElicitationResult> {
460
+ const content: Record<string, string | string[]> = {};
461
+
462
+ for (const field of fields) {
463
+ const value = await ui.input(
464
+ buildTextInputPromptTitle(request, field),
465
+ buildTextInputPlaceholder(field),
466
+ { signal, ...(field.secure ? { secure: true } : {}) },
467
+ );
468
+ if (value === undefined) {
469
+ return { action: "cancel" };
470
+ }
471
+ content[field.id] = value;
472
+ }
473
+
474
+ return { action: "accept", content };
475
+ }
476
+
358
477
  export function createClaudeCodeElicitationHandler(
359
478
  ui: ExtensionUIContext | undefined,
360
479
  ): ((request: SdkElicitationRequest, options: { signal: AbortSignal }) => Promise<SdkElicitationResult>) | undefined {
@@ -366,19 +485,24 @@ export function createClaudeCodeElicitationHandler(
366
485
  }
367
486
 
368
487
  const questions = parseAskUserQuestionsElicitation(request);
369
- if (!questions) {
370
- return { action: "decline" };
488
+ if (questions) {
489
+ const interviewResult = await showInterviewRound(questions, { signal }, { ui } as any).catch(() => undefined);
490
+ if (interviewResult && Object.keys(interviewResult.answers).length > 0) {
491
+ return {
492
+ action: "accept",
493
+ content: roundResultToElicitationContent(questions, interviewResult),
494
+ };
495
+ }
496
+
497
+ return promptElicitationWithDialogs(request, questions, ui, signal);
371
498
  }
372
499
 
373
- const interviewResult = await showInterviewRound(questions, { signal }, { ui } as any).catch(() => undefined);
374
- if (interviewResult && Object.keys(interviewResult.answers).length > 0) {
375
- return {
376
- action: "accept",
377
- content: roundResultToElicitationContent(questions, interviewResult),
378
- };
500
+ const textFields = parseTextInputElicitation(request);
501
+ if (textFields) {
502
+ return promptTextInputElicitation(request, textFields, ui, signal);
379
503
  }
380
504
 
381
- return promptElicitationWithDialogs(request, questions, ui, signal);
505
+ return { action: "decline" };
382
506
  };
383
507
  }
384
508
 
@@ -398,6 +522,7 @@ export function buildSdkOptions(
398
522
  extraOptions: Record<string, unknown> = {},
399
523
  ): Record<string, unknown> {
400
524
  const mcpServers = buildWorkflowMcpServers();
525
+ const disallowedTools = ["AskUserQuestion"];
401
526
  return {
402
527
  pathToClaudeCodeExecutable: getClaudePath(),
403
528
  model: modelId,
@@ -408,6 +533,7 @@ export function buildSdkOptions(
408
533
  allowDangerouslySkipPermissions: true,
409
534
  settingSources: ["project"],
410
535
  systemPrompt: { type: "preset", preset: "claude_code" },
536
+ disallowedTools,
411
537
  ...(mcpServers ? { mcpServers } : {}),
412
538
  betas: modelId.includes("sonnet") ? ["context-1m-2025-08-07"] : [],
413
539
  ...extraOptions,
@@ -506,15 +632,15 @@ export function extractToolResultsFromSdkUserMessage(message: SDKUserMessage): A
506
632
  return extracted;
507
633
  }
508
634
 
509
- function attachExternalResultsToToolCalls(
510
- toolCalls: AssistantMessage["content"],
635
+ function attachExternalResultsToToolBlocks(
636
+ toolBlocks: AssistantMessage["content"],
511
637
  toolResultsById: ReadonlyMap<string, ExternalToolResultPayload>,
512
638
  ): void {
513
- for (const block of toolCalls) {
514
- if (block.type !== "toolCall") continue;
639
+ for (const block of toolBlocks) {
640
+ if (block.type !== "toolCall" && block.type !== "serverToolUse") continue;
515
641
  const externalResult = toolResultsById.get(block.id);
516
642
  if (!externalResult) continue;
517
- (block as ToolCallWithExternalResult).externalResult = externalResult;
643
+ (block as ToolCallWithExternalResult & { id: string }).externalResult = externalResult;
518
644
  }
519
645
  }
520
646
 
@@ -552,8 +678,8 @@ async function pumpSdkMessages(
552
678
  /** Track the last text content seen across all assistant turns for the final message. */
553
679
  let lastTextContent = "";
554
680
  let lastThinkingContent = "";
555
- /** Collect tool calls from intermediate SDK turns for tool_execution events. */
556
- const intermediateToolCalls: AssistantMessage["content"] = [];
681
+ /** Collect tool blocks from intermediate SDK turns for tool execution rendering. */
682
+ const intermediateToolBlocks: AssistantMessage["content"] = [];
557
683
  /** Preserve real external tool results from Claude Code's synthetic user messages. */
558
684
  const toolResultsById = new Map<string, ExternalToolResultPayload>();
559
685
 
@@ -664,9 +790,9 @@ async function pumpSdkMessages(
664
790
  lastTextContent = block.text;
665
791
  } else if (block.type === "thinking" && block.thinking) {
666
792
  lastThinkingContent = block.thinking;
667
- } else if (block.type === "toolCall") {
668
- // Collect tool calls for externalToolExecution rendering
669
- intermediateToolCalls.push(block);
793
+ } else if (block.type === "toolCall" || block.type === "serverToolUse") {
794
+ // Collect tool blocks for externalToolExecution rendering
795
+ intermediateToolBlocks.push(block);
670
796
  }
671
797
  }
672
798
  }
@@ -676,24 +802,33 @@ async function pumpSdkMessages(
676
802
  for (const { toolUseId, result } of extractToolResultsFromSdkUserMessage(msg as SDKUserMessage)) {
677
803
  toolResultsById.set(toolUseId, result);
678
804
  }
679
- attachExternalResultsToToolCalls(intermediateToolCalls, toolResultsById);
805
+ attachExternalResultsToToolBlocks(intermediateToolBlocks, toolResultsById);
680
806
 
681
807
  // Push a synthetic toolcall_end for each tool call from this turn
682
808
  // so the TUI can render tool results in real-time during the SDK
683
809
  // session instead of waiting until the entire session completes.
684
810
  if (builder) {
685
811
  for (const block of builder.message.content) {
686
- if (block.type !== "toolCall") continue;
687
812
  const extResult = (block as ToolCallWithExternalResult).externalResult;
688
813
  if (!extResult) continue;
689
- // Push a toolcall_end with result attached so the chat-controller
690
- // can call updateResult on the pending ToolExecutionComponent.
691
- stream.push({
692
- type: "toolcall_end",
693
- contentIndex: builder.message.content.indexOf(block),
694
- toolCall: block,
695
- partial: builder.message,
696
- });
814
+ const contentIndex = builder.message.content.indexOf(block);
815
+ if (contentIndex < 0) continue;
816
+ // Push synthetic completion events with result attached so the
817
+ // chat-controller can update pending ToolExecutionComponents.
818
+ if (block.type === "toolCall") {
819
+ stream.push({
820
+ type: "toolcall_end",
821
+ contentIndex,
822
+ toolCall: block,
823
+ partial: builder.message,
824
+ });
825
+ } else if (block.type === "serverToolUse") {
826
+ stream.push({
827
+ type: "server_tool_use",
828
+ contentIndex,
829
+ partial: builder.message,
830
+ });
831
+ }
697
832
  }
698
833
  }
699
834
 
@@ -711,8 +846,8 @@ async function pumpSdkMessages(
711
846
  const finalContent: AssistantMessage["content"] = [];
712
847
 
713
848
  // Add tool calls from intermediate turns first (renders above text)
714
- attachExternalResultsToToolCalls(intermediateToolCalls, toolResultsById);
715
- finalContent.push(...intermediateToolCalls);
849
+ attachExternalResultsToToolBlocks(intermediateToolBlocks, toolResultsById);
850
+ finalContent.push(...intermediateToolBlocks);
716
851
 
717
852
  // Add text/thinking from the last turn
718
853
  if (builder && builder.message.content.length > 0) {