@opengsd/gsd-pi 1.1.1-dev.b2556262 → 1.2.0-dev.4813ead6

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 (500) hide show
  1. package/dist/cli-web-branch.d.ts +2 -0
  2. package/dist/cli-web-branch.js +9 -2
  3. package/dist/help-text.js +5 -0
  4. package/dist/project-sessions.js +4 -2
  5. package/dist/resources/.managed-resources-content-hash +1 -1
  6. package/dist/resources/extensions/ask-user-questions.js +78 -23
  7. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +101 -237
  8. package/dist/resources/extensions/claude-code-cli/turn-assembler.js +224 -0
  9. package/dist/resources/extensions/github-sync/templates.js +3 -3
  10. package/dist/resources/extensions/gsd/artifact-projection.js +14 -0
  11. package/dist/resources/extensions/gsd/auto/contracts.js +8 -1
  12. package/dist/resources/extensions/gsd/auto/loop.js +74 -56
  13. package/dist/resources/extensions/gsd/auto/orchestrator.js +763 -63
  14. package/dist/resources/extensions/gsd/auto/phases.js +28 -3
  15. package/dist/resources/extensions/gsd/auto/run-unit.js +2 -1
  16. package/dist/resources/extensions/gsd/auto/session.js +3 -0
  17. package/dist/resources/extensions/gsd/auto-dashboard.js +16 -4
  18. package/dist/resources/extensions/gsd/auto-dispatch.js +6 -5
  19. package/dist/resources/extensions/gsd/auto-model-selection.js +8 -0
  20. package/dist/resources/extensions/gsd/auto-post-unit.js +4 -3
  21. package/dist/resources/extensions/gsd/auto-prompts.js +191 -9
  22. package/dist/resources/extensions/gsd/auto-recovery.js +48 -49
  23. package/dist/resources/extensions/gsd/auto-runtime-state.js +17 -0
  24. package/dist/resources/extensions/gsd/auto-start.js +12 -23
  25. package/dist/resources/extensions/gsd/auto-timers.js +16 -2
  26. package/dist/resources/extensions/gsd/auto-tool-tracking.js +37 -0
  27. package/dist/resources/extensions/gsd/auto-unit-tool-scope.js +33 -29
  28. package/dist/resources/extensions/gsd/auto-verification.js +7 -7
  29. package/dist/resources/extensions/gsd/auto-worktree.js +45 -36
  30. package/dist/resources/extensions/gsd/auto.js +73 -471
  31. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +28 -37
  32. package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +11 -37
  33. package/dist/resources/extensions/gsd/bootstrap/query-tools.js +2 -2
  34. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +103 -138
  35. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +63 -4
  36. package/dist/resources/extensions/gsd/closeout-consistency-gate.js +21 -4
  37. package/dist/resources/extensions/gsd/codebase-generator.js +8 -4
  38. package/dist/resources/extensions/gsd/commands/handlers/auto.js +3 -0
  39. package/dist/resources/extensions/gsd/commands-handlers.js +20 -0
  40. package/dist/resources/extensions/gsd/commands-inspect.js +4 -8
  41. package/dist/resources/extensions/gsd/commands-maintenance.js +61 -41
  42. package/dist/resources/extensions/gsd/commands-ship.js +2 -2
  43. package/dist/resources/extensions/gsd/commands-verdict.js +12 -2
  44. package/dist/resources/extensions/gsd/db-workspace.js +103 -0
  45. package/dist/resources/extensions/gsd/debug-logger.js +10 -0
  46. package/dist/resources/extensions/gsd/delegation-policy.js +2 -10
  47. package/dist/resources/extensions/gsd/discussion-handoff.js +218 -0
  48. package/dist/resources/extensions/gsd/docs/preferences-reference.md +9 -0
  49. package/dist/resources/extensions/gsd/doctor-proactive.js +7 -2
  50. package/dist/resources/extensions/gsd/doctor.js +16 -9
  51. package/dist/resources/extensions/gsd/error-classifier.js +1 -1
  52. package/dist/resources/extensions/gsd/git-conflict-state.js +16 -1
  53. package/dist/resources/extensions/gsd/gsd-db.js +12 -0
  54. package/dist/resources/extensions/gsd/guided-flow.js +36 -470
  55. package/dist/resources/extensions/gsd/guided-unit-completion.js +225 -0
  56. package/dist/resources/extensions/gsd/markdown-renderer.js +33 -33
  57. package/dist/resources/extensions/gsd/mcp-filter.js +8 -1
  58. package/dist/resources/extensions/gsd/mcp-tool-name.js +26 -0
  59. package/dist/resources/extensions/gsd/md-importer.js +4 -3
  60. package/dist/resources/extensions/gsd/migrate/safety.js +2 -2
  61. package/dist/resources/extensions/gsd/migration-auto-check.js +3 -2
  62. package/dist/resources/extensions/gsd/milestone-closeout-proof.js +72 -0
  63. package/dist/resources/extensions/gsd/milestone-closeout.js +12 -4
  64. package/dist/resources/extensions/gsd/milestone-merge-transaction.js +10 -0
  65. package/dist/resources/extensions/gsd/milestone-planning-persistence.js +156 -0
  66. package/dist/resources/extensions/gsd/milestone-readiness.js +77 -0
  67. package/dist/resources/extensions/gsd/milestone-settlement.js +50 -0
  68. package/dist/resources/extensions/gsd/milestone-validation-evidence.js +73 -0
  69. package/dist/resources/extensions/gsd/milestone-validation-verdict.js +57 -0
  70. package/dist/resources/extensions/gsd/native-git-bridge.js +45 -0
  71. package/dist/resources/extensions/gsd/parallel-eligibility.js +3 -6
  72. package/dist/resources/extensions/gsd/parallel-orchestrator.js +3 -2
  73. package/dist/resources/extensions/gsd/preferences-diagnostics.js +67 -0
  74. package/dist/resources/extensions/gsd/preferences.js +147 -29
  75. package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -0
  76. package/dist/resources/extensions/gsd/prompts/discuss.md +6 -7
  77. package/dist/resources/extensions/gsd/prompts/execute-task.md +2 -0
  78. package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +5 -7
  79. package/dist/resources/extensions/gsd/prompts/guided-discuss-project.md +6 -6
  80. package/dist/resources/extensions/gsd/prompts/guided-discuss-requirements.md +1 -2
  81. package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +5 -6
  82. package/dist/resources/extensions/gsd/prompts/plan-milestone.md +2 -0
  83. package/dist/resources/extensions/gsd/prompts/plan-slice.md +2 -1
  84. package/dist/resources/extensions/gsd/prompts/refine-slice.md +1 -0
  85. package/dist/resources/extensions/gsd/prompts/research-milestone.md +2 -2
  86. package/dist/resources/extensions/gsd/prompts/system.md +1 -1
  87. package/dist/resources/extensions/gsd/prompts/validate-milestone.md +5 -3
  88. package/dist/resources/extensions/gsd/provider-payload-policy.js +83 -0
  89. package/dist/resources/extensions/gsd/pull-request-process.js +13 -0
  90. package/dist/resources/extensions/gsd/quality-gate-closure.js +109 -0
  91. package/dist/resources/extensions/gsd/question-transport.js +86 -0
  92. package/dist/resources/extensions/gsd/roadmap-slices.js +8 -2
  93. package/dist/resources/extensions/gsd/schemas/parsers.js +6 -1
  94. package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +3 -2
  95. package/dist/resources/extensions/gsd/state-reconciliation/drift/artifact-db.js +21 -1
  96. package/dist/resources/extensions/gsd/state.js +13 -5
  97. package/dist/resources/extensions/gsd/templates/plan.md +7 -0
  98. package/dist/resources/extensions/gsd/templates/project.md +1 -0
  99. package/dist/resources/extensions/gsd/templates/roadmap.md +1 -1
  100. package/dist/resources/extensions/gsd/templates/uat.md +5 -1
  101. package/dist/resources/extensions/gsd/tool-contract.js +52 -8
  102. package/dist/resources/extensions/gsd/tool-presentation-plan.js +15 -34
  103. package/dist/resources/extensions/gsd/tool-surface-snapshot.js +17 -0
  104. package/dist/resources/extensions/gsd/tools/plan-milestone.js +15 -143
  105. package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +39 -0
  106. package/dist/resources/extensions/gsd/tools/validate-milestone.js +15 -78
  107. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +169 -20
  108. package/dist/resources/extensions/gsd/uat-policy.js +16 -10
  109. package/dist/resources/extensions/gsd/uat-run.js +9 -14
  110. package/dist/resources/extensions/gsd/unit-context-composer.js +40 -20
  111. package/dist/resources/extensions/gsd/unit-runtime.js +3 -2
  112. package/dist/resources/extensions/gsd/unit-tool-contracts.js +2 -1
  113. package/dist/resources/extensions/gsd/user-input-boundary.js +65 -4
  114. package/dist/resources/extensions/gsd/validation-block-guard.js +2 -0
  115. package/dist/resources/extensions/gsd/web-app-uat.js +80 -0
  116. package/dist/resources/extensions/gsd/workflow-mcp.js +15 -102
  117. package/dist/resources/extensions/gsd/workflow-reconcile.js +4 -3
  118. package/dist/resources/extensions/gsd/workflow-tool-surface.js +46 -0
  119. package/dist/resources/extensions/gsd/workspace-git-guard.js +2 -0
  120. package/dist/resources/extensions/gsd/worktree-state-projection.js +33 -4
  121. package/dist/resources/extensions/gsd/worktree-telemetry.js +12 -0
  122. package/dist/resources/extensions/shared/interview-ui.js +2 -2
  123. package/dist/resources/shared/claude-runtime-floor.js +182 -0
  124. package/dist/tsconfig.extensions.tsbuildinfo +1 -0
  125. package/dist/update-cmd.js +20 -0
  126. package/dist/web/standalone/.next/BUILD_ID +1 -1
  127. package/dist/web/standalone/.next/app-path-routes-manifest.json +5 -5
  128. package/dist/web/standalone/.next/build-manifest.json +3 -3
  129. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  130. package/dist/web/standalone/.next/react-loadable-manifest.json +8 -8
  131. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  132. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  133. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  134. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  135. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  136. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  137. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  138. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  139. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  140. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  141. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  142. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  143. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  144. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  145. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  146. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  147. package/dist/web/standalone/.next/server/app/api/boot/route.js.nft.json +1 -1
  148. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js.nft.json +1 -1
  149. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js.nft.json +1 -1
  150. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js.nft.json +1 -1
  151. package/dist/web/standalone/.next/server/app/api/captures/route.js.nft.json +1 -1
  152. package/dist/web/standalone/.next/server/app/api/cleanup/route.js.nft.json +1 -1
  153. package/dist/web/standalone/.next/server/app/api/doctor/route.js.nft.json +1 -1
  154. package/dist/web/standalone/.next/server/app/api/export-data/route.js.nft.json +1 -1
  155. package/dist/web/standalone/.next/server/app/api/files/route.js.nft.json +1 -1
  156. package/dist/web/standalone/.next/server/app/api/forensics/route.js.nft.json +1 -1
  157. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  158. package/dist/web/standalone/.next/server/app/api/git/route.js.nft.json +1 -1
  159. package/dist/web/standalone/.next/server/app/api/history/route.js.nft.json +1 -1
  160. package/dist/web/standalone/.next/server/app/api/hooks/route.js.nft.json +1 -1
  161. package/dist/web/standalone/.next/server/app/api/inspect/route.js.nft.json +1 -1
  162. package/dist/web/standalone/.next/server/app/api/knowledge/route.js.nft.json +1 -1
  163. package/dist/web/standalone/.next/server/app/api/live-state/route.js.nft.json +1 -1
  164. package/dist/web/standalone/.next/server/app/api/mcp-connections/route.js.nft.json +1 -1
  165. package/dist/web/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
  166. package/dist/web/standalone/.next/server/app/api/onboarding/route.js.nft.json +1 -1
  167. package/dist/web/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
  168. package/dist/web/standalone/.next/server/app/api/recovery/route.js.nft.json +1 -1
  169. package/dist/web/standalone/.next/server/app/api/session/browser/route.js.nft.json +1 -1
  170. package/dist/web/standalone/.next/server/app/api/session/command/route.js.nft.json +1 -1
  171. package/dist/web/standalone/.next/server/app/api/session/events/route.js.nft.json +1 -1
  172. package/dist/web/standalone/.next/server/app/api/session/manage/route.js.nft.json +1 -1
  173. package/dist/web/standalone/.next/server/app/api/settings-data/route.js.nft.json +1 -1
  174. package/dist/web/standalone/.next/server/app/api/shutdown/route.js.nft.json +1 -1
  175. package/dist/web/standalone/.next/server/app/api/skill-health/route.js.nft.json +1 -1
  176. package/dist/web/standalone/.next/server/app/api/steer/route.js.nft.json +1 -1
  177. package/dist/web/standalone/.next/server/app/api/switch-root/route.js.nft.json +1 -1
  178. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js.nft.json +1 -1
  179. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js.nft.json +1 -1
  180. package/dist/web/standalone/.next/server/app/api/undo/route.js.nft.json +1 -1
  181. package/dist/web/standalone/.next/server/app/api/visualizer/route.js.nft.json +1 -1
  182. package/dist/web/standalone/.next/server/app/index.html +1 -1
  183. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  184. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  185. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  186. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  187. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  188. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  189. package/dist/web/standalone/.next/server/app-paths-manifest.json +5 -5
  190. package/dist/web/standalone/.next/server/chunks/5047.js +2 -0
  191. package/dist/web/standalone/.next/server/chunks/5124.js +1 -0
  192. package/dist/web/standalone/.next/server/chunks/8357.js +2 -2
  193. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  194. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  195. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  196. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  197. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  198. package/dist/web/standalone/.next/static/chunks/2659.b7b129ee6a769448.js +1 -0
  199. package/dist/web/standalone/.next/static/chunks/2772.bfa657f49f955239.js +1 -0
  200. package/dist/web/standalone/.next/static/chunks/{3616.4113d484a994e411.js → 3616.3c60753b8ffcbd2e.js} +1 -1
  201. package/dist/web/standalone/.next/static/chunks/4283.e4873b058df143a1.js +2 -0
  202. package/dist/web/standalone/.next/static/chunks/5826.a46ecdd1cfe8dabc.js +1 -0
  203. package/dist/web/standalone/.next/static/chunks/796.cf859a427a2cb2ac.js +10 -0
  204. package/dist/web/standalone/.next/static/chunks/8785.2e5a118797fb2dd2.js +1 -0
  205. package/dist/web/standalone/.next/static/chunks/{webpack-dda80a1ef5587410.js → webpack-fbea77b5f9953368.js} +1 -1
  206. package/dist/web/standalone/node_modules/@gsd/native/package.json +1 -1
  207. package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
  208. package/dist/web/standalone/node_modules/postcss/lib/container.js +26 -18
  209. package/dist/web/standalone/node_modules/postcss/lib/css-syntax-error.js +47 -14
  210. package/dist/web/standalone/node_modules/postcss/lib/declaration.js +4 -4
  211. package/dist/web/standalone/node_modules/postcss/lib/fromJSON.js +3 -3
  212. package/dist/web/standalone/node_modules/postcss/lib/input.js +54 -29
  213. package/dist/web/standalone/node_modules/postcss/lib/lazy-result.js +47 -37
  214. package/dist/web/standalone/node_modules/postcss/lib/map-generator.js +26 -9
  215. package/dist/web/standalone/node_modules/postcss/lib/no-work-result.js +57 -55
  216. package/dist/web/standalone/node_modules/postcss/lib/node.js +99 -31
  217. package/dist/web/standalone/node_modules/postcss/lib/parse.js +1 -1
  218. package/dist/web/standalone/node_modules/postcss/lib/parser.js +10 -9
  219. package/dist/web/standalone/node_modules/postcss/lib/postcss.js +12 -12
  220. package/dist/web/standalone/node_modules/postcss/lib/previous-map.js +30 -11
  221. package/dist/web/standalone/node_modules/postcss/lib/processor.js +7 -7
  222. package/dist/web/standalone/node_modules/postcss/lib/result.js +5 -5
  223. package/dist/web/standalone/node_modules/postcss/lib/rule.js +6 -6
  224. package/dist/web/standalone/node_modules/postcss/lib/stringifier.js +69 -28
  225. package/dist/web/standalone/node_modules/postcss/lib/tokenize.js +6 -2
  226. package/dist/web/standalone/node_modules/postcss/package.json +48 -48
  227. package/dist/web-mode.d.ts +2 -0
  228. package/dist/web-mode.js +20 -8
  229. package/package.json +17 -11
  230. package/packages/cloud-mcp-gateway/package.json +2 -2
  231. package/packages/contracts/package.json +1 -1
  232. package/packages/daemon/package.json +4 -4
  233. package/packages/gsd-agent-core/dist/session/agent-session-extensions.d.ts +2 -0
  234. package/packages/gsd-agent-core/dist/session/agent-session-extensions.d.ts.map +1 -1
  235. package/packages/gsd-agent-core/dist/session/agent-session-extensions.js +14 -0
  236. package/packages/gsd-agent-core/dist/session/agent-session-extensions.js.map +1 -1
  237. package/packages/gsd-agent-core/package.json +5 -5
  238. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  239. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js +3 -0
  240. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js.map +1 -1
  241. package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js +1 -1
  242. package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js.map +1 -1
  243. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  244. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +106 -40
  245. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  246. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-widgets.d.ts.map +1 -1
  247. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-widgets.js +6 -0
  248. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-widgets.js.map +1 -1
  249. package/packages/gsd-agent-modes/package.json +7 -7
  250. package/packages/mcp-server/dist/server.d.ts +10 -0
  251. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  252. package/packages/mcp-server/dist/server.js +8 -0
  253. package/packages/mcp-server/dist/server.js.map +1 -1
  254. package/packages/mcp-server/dist/workflow-tools.d.ts +41 -0
  255. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  256. package/packages/mcp-server/dist/workflow-tools.js +2 -1
  257. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  258. package/packages/mcp-server/package.json +3 -3
  259. package/packages/native/package.json +1 -1
  260. package/packages/pi-agent-core/package.json +1 -1
  261. package/packages/pi-ai/dist/image-models.generated.d.ts +30 -0
  262. package/packages/pi-ai/dist/image-models.generated.d.ts.map +1 -1
  263. package/packages/pi-ai/dist/image-models.generated.js +30 -0
  264. package/packages/pi-ai/dist/image-models.generated.js.map +1 -1
  265. package/packages/pi-ai/dist/models.generated.d.ts +8 -127
  266. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  267. package/packages/pi-ai/dist/models.generated.js +47 -166
  268. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  269. package/packages/pi-ai/package.json +1 -1
  270. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts.map +1 -1
  271. package/packages/pi-coding-agent/dist/core/auth-storage.js +11 -3
  272. package/packages/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
  273. package/packages/pi-coding-agent/package.json +7 -7
  274. package/packages/pi-tui/dist/components/input.js +1 -1
  275. package/packages/pi-tui/dist/components/input.js.map +1 -1
  276. package/packages/pi-tui/dist/keys.d.ts.map +1 -1
  277. package/packages/pi-tui/dist/keys.js +39 -30
  278. package/packages/pi-tui/dist/keys.js.map +1 -1
  279. package/packages/pi-tui/dist/stdin-buffer.d.ts.map +1 -1
  280. package/packages/pi-tui/dist/stdin-buffer.js +22 -0
  281. package/packages/pi-tui/dist/stdin-buffer.js.map +1 -1
  282. package/packages/pi-tui/package.json +2 -2
  283. package/packages/rpc-client/package.json +2 -2
  284. package/pkg/package.json +1 -1
  285. package/scripts/install/deps.js +10 -0
  286. package/scripts/link-workspace-packages.cjs +7 -40
  287. package/src/resources/extensions/ask-user-questions.ts +87 -24
  288. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +126 -289
  289. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +242 -2
  290. package/src/resources/extensions/claude-code-cli/turn-assembler.ts +287 -0
  291. package/src/resources/extensions/github-sync/templates.ts +3 -3
  292. package/src/resources/extensions/github-sync/tests/templates.test.ts +2 -2
  293. package/src/resources/extensions/gsd/artifact-projection.ts +31 -0
  294. package/src/resources/extensions/gsd/auto/contracts.ts +40 -121
  295. package/src/resources/extensions/gsd/auto/loop-deps.ts +2 -0
  296. package/src/resources/extensions/gsd/auto/loop.ts +83 -61
  297. package/src/resources/extensions/gsd/auto/orchestrator.ts +913 -64
  298. package/src/resources/extensions/gsd/auto/phases.ts +35 -3
  299. package/src/resources/extensions/gsd/auto/run-unit.ts +2 -1
  300. package/src/resources/extensions/gsd/auto/session.ts +4 -0
  301. package/src/resources/extensions/gsd/auto-dashboard.ts +18 -4
  302. package/src/resources/extensions/gsd/auto-dispatch.ts +20 -7
  303. package/src/resources/extensions/gsd/auto-model-selection.ts +8 -0
  304. package/src/resources/extensions/gsd/auto-post-unit.ts +4 -3
  305. package/src/resources/extensions/gsd/auto-prompts.ts +220 -9
  306. package/src/resources/extensions/gsd/auto-recovery.ts +50 -50
  307. package/src/resources/extensions/gsd/auto-runtime-state.ts +30 -0
  308. package/src/resources/extensions/gsd/auto-start.ts +17 -20
  309. package/src/resources/extensions/gsd/auto-timers.ts +16 -2
  310. package/src/resources/extensions/gsd/auto-tool-tracking.ts +40 -0
  311. package/src/resources/extensions/gsd/auto-unit-tool-scope.ts +42 -30
  312. package/src/resources/extensions/gsd/auto-verification.ts +7 -8
  313. package/src/resources/extensions/gsd/auto-worktree.ts +57 -42
  314. package/src/resources/extensions/gsd/auto.ts +96 -508
  315. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +29 -37
  316. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +10 -37
  317. package/src/resources/extensions/gsd/bootstrap/query-tools.ts +2 -2
  318. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +120 -151
  319. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +107 -3
  320. package/src/resources/extensions/gsd/closeout-consistency-gate.ts +27 -5
  321. package/src/resources/extensions/gsd/codebase-generator.ts +9 -5
  322. package/src/resources/extensions/gsd/commands/handlers/auto.ts +3 -0
  323. package/src/resources/extensions/gsd/commands-handlers.ts +18 -0
  324. package/src/resources/extensions/gsd/commands-inspect.ts +7 -8
  325. package/src/resources/extensions/gsd/commands-maintenance.ts +74 -40
  326. package/src/resources/extensions/gsd/commands-ship.ts +2 -2
  327. package/src/resources/extensions/gsd/commands-verdict.ts +19 -2
  328. package/src/resources/extensions/gsd/db-workspace.ts +170 -0
  329. package/src/resources/extensions/gsd/debug-logger.ts +11 -0
  330. package/src/resources/extensions/gsd/delegation-policy.ts +3 -11
  331. package/src/resources/extensions/gsd/discussion-handoff.ts +276 -0
  332. package/src/resources/extensions/gsd/docs/preferences-reference.md +9 -0
  333. package/src/resources/extensions/gsd/doctor-proactive.ts +8 -2
  334. package/src/resources/extensions/gsd/doctor.ts +15 -5
  335. package/src/resources/extensions/gsd/error-classifier.ts +1 -1
  336. package/src/resources/extensions/gsd/git-conflict-state.ts +17 -1
  337. package/src/resources/extensions/gsd/gsd-db.ts +12 -0
  338. package/src/resources/extensions/gsd/guided-flow.ts +49 -560
  339. package/src/resources/extensions/gsd/guided-unit-completion.ts +275 -0
  340. package/src/resources/extensions/gsd/markdown-renderer.ts +40 -20
  341. package/src/resources/extensions/gsd/mcp-filter.ts +9 -1
  342. package/src/resources/extensions/gsd/mcp-tool-name.ts +35 -0
  343. package/src/resources/extensions/gsd/md-importer.ts +3 -3
  344. package/src/resources/extensions/gsd/migrate/safety.ts +2 -2
  345. package/src/resources/extensions/gsd/migration-auto-check.ts +2 -2
  346. package/src/resources/extensions/gsd/milestone-closeout-proof.ts +131 -0
  347. package/src/resources/extensions/gsd/milestone-closeout.ts +12 -4
  348. package/src/resources/extensions/gsd/milestone-merge-transaction.ts +47 -0
  349. package/src/resources/extensions/gsd/milestone-planning-persistence.ts +224 -0
  350. package/src/resources/extensions/gsd/milestone-readiness.ts +125 -0
  351. package/src/resources/extensions/gsd/milestone-settlement.ts +81 -0
  352. package/src/resources/extensions/gsd/milestone-validation-evidence.ts +95 -0
  353. package/src/resources/extensions/gsd/milestone-validation-verdict.ts +80 -0
  354. package/src/resources/extensions/gsd/native-git-bridge.ts +48 -0
  355. package/src/resources/extensions/gsd/parallel-eligibility.ts +4 -5
  356. package/src/resources/extensions/gsd/parallel-orchestrator.ts +6 -2
  357. package/src/resources/extensions/gsd/preferences-diagnostics.ts +98 -0
  358. package/src/resources/extensions/gsd/preferences-types.ts +16 -0
  359. package/src/resources/extensions/gsd/preferences.ts +173 -28
  360. package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -0
  361. package/src/resources/extensions/gsd/prompts/discuss.md +6 -7
  362. package/src/resources/extensions/gsd/prompts/execute-task.md +2 -0
  363. package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +5 -7
  364. package/src/resources/extensions/gsd/prompts/guided-discuss-project.md +6 -6
  365. package/src/resources/extensions/gsd/prompts/guided-discuss-requirements.md +1 -2
  366. package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +5 -6
  367. package/src/resources/extensions/gsd/prompts/plan-milestone.md +2 -0
  368. package/src/resources/extensions/gsd/prompts/plan-slice.md +2 -1
  369. package/src/resources/extensions/gsd/prompts/refine-slice.md +1 -0
  370. package/src/resources/extensions/gsd/prompts/research-milestone.md +2 -2
  371. package/src/resources/extensions/gsd/prompts/system.md +1 -1
  372. package/src/resources/extensions/gsd/prompts/validate-milestone.md +5 -3
  373. package/src/resources/extensions/gsd/provider-payload-policy.ts +140 -0
  374. package/src/resources/extensions/gsd/pull-request-process.ts +41 -0
  375. package/src/resources/extensions/gsd/quality-gate-closure.ts +140 -0
  376. package/src/resources/extensions/gsd/question-transport.ts +138 -0
  377. package/src/resources/extensions/gsd/roadmap-slices.ts +8 -2
  378. package/src/resources/extensions/gsd/schemas/parsers.ts +6 -1
  379. package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +6 -2
  380. package/src/resources/extensions/gsd/state-reconciliation/drift/artifact-db.ts +31 -10
  381. package/src/resources/extensions/gsd/state.ts +15 -5
  382. package/src/resources/extensions/gsd/templates/plan.md +7 -0
  383. package/src/resources/extensions/gsd/templates/project.md +1 -0
  384. package/src/resources/extensions/gsd/templates/roadmap.md +1 -1
  385. package/src/resources/extensions/gsd/templates/uat.md +5 -1
  386. package/src/resources/extensions/gsd/tests/artifact-db-drift-memo.test.ts +66 -0
  387. package/src/resources/extensions/gsd/tests/ask-user-questions-render.test.ts +92 -0
  388. package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +29 -1
  389. package/src/resources/extensions/gsd/tests/auto-dispatch-baseline-harness.test.ts +53 -0
  390. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +321 -5
  391. package/src/resources/extensions/gsd/tests/auto-milestone-target.test.ts +23 -0
  392. package/src/resources/extensions/gsd/tests/auto-model-selection-tool-poisoning.test.ts +18 -0
  393. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +709 -845
  394. package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +38 -10
  395. package/src/resources/extensions/gsd/tests/auto-runtime-state.test.ts +34 -0
  396. package/src/resources/extensions/gsd/tests/canonical-milestone-root.test.ts +20 -0
  397. package/src/resources/extensions/gsd/tests/codebase-generator.test.ts +22 -0
  398. package/src/resources/extensions/gsd/tests/commands-dispatcher-workspace-git.test.ts +11 -0
  399. package/src/resources/extensions/gsd/tests/commands-verdict.test.ts +38 -1
  400. package/src/resources/extensions/gsd/tests/debug-logger.test.ts +15 -0
  401. package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +34 -3
  402. package/src/resources/extensions/gsd/tests/dispatch-run-uat-browser-tools.test.ts +88 -0
  403. package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +18 -0
  404. package/src/resources/extensions/gsd/tests/execute-summary-save-empty-project.test.ts +64 -1
  405. package/src/resources/extensions/gsd/tests/execute-task-rendering.test.ts +1 -0
  406. package/src/resources/extensions/gsd/tests/fixtures/pr-body/swarm-lane-no-blockers.md +1 -5
  407. package/src/resources/extensions/gsd/tests/fixtures/pr-body/swarm-lane-with-blockers.md +1 -5
  408. package/src/resources/extensions/gsd/tests/gate-state-canonicalization.test.ts +48 -1
  409. package/src/resources/extensions/gsd/tests/integration/merge-strategy-regular.test.ts +157 -0
  410. package/src/resources/extensions/gsd/tests/markdown-renderer-parse-cache.test.ts +75 -0
  411. package/src/resources/extensions/gsd/tests/mcp-tool-name.test.ts +34 -0
  412. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +58 -0
  413. package/src/resources/extensions/gsd/tests/milestone-closeout-proof.test.ts +99 -0
  414. package/src/resources/extensions/gsd/tests/milestone-closeout.test.ts +25 -0
  415. package/src/resources/extensions/gsd/tests/milestone-merge-transaction.test.ts +46 -0
  416. package/src/resources/extensions/gsd/tests/milestone-readiness.test.ts +65 -0
  417. package/src/resources/extensions/gsd/tests/milestone-validation-evidence.test.ts +41 -0
  418. package/src/resources/extensions/gsd/tests/milestone-validation-verdict.test.ts +55 -0
  419. package/src/resources/extensions/gsd/tests/native-merge-regular.test.ts +139 -0
  420. package/src/resources/extensions/gsd/tests/orchestrator-legacy-parity.test.ts +127 -0
  421. package/src/resources/extensions/gsd/tests/parse-project-milestone-bridge.test.ts +77 -0
  422. package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +45 -0
  423. package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +6 -2
  424. package/src/resources/extensions/gsd/tests/planning-crossval.test.ts +45 -0
  425. package/src/resources/extensions/gsd/tests/preferences-diagnostics.test.ts +67 -0
  426. package/src/resources/extensions/gsd/tests/preferences.test.ts +183 -0
  427. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +75 -2
  428. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +9 -0
  429. package/src/resources/extensions/gsd/tests/provider-payload-policy.test.ts +165 -0
  430. package/src/resources/extensions/gsd/tests/pull-request-process.test.ts +47 -0
  431. package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +94 -0
  432. package/src/resources/extensions/gsd/tests/research-milestone-composer.test.ts +65 -0
  433. package/src/resources/extensions/gsd/tests/roadmap-parse-regression.test.ts +40 -0
  434. package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +25 -1
  435. package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +80 -0
  436. package/src/resources/extensions/gsd/tests/single-writer-invariant.test.ts +101 -1
  437. package/src/resources/extensions/gsd/tests/stale-queued-milestone.test.ts +27 -0
  438. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +21 -6
  439. package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +38 -0
  440. package/src/resources/extensions/gsd/tests/tool-availability-audit.test.ts +35 -0
  441. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +35 -42
  442. package/src/resources/extensions/gsd/tests/uat-policy.test.ts +23 -0
  443. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +47 -0
  444. package/src/resources/extensions/gsd/tests/user-input-boundary.test.ts +147 -0
  445. package/src/resources/extensions/gsd/tests/validate-milestone-stuck-guard.test.ts +39 -0
  446. package/src/resources/extensions/gsd/tests/web-app-uat.test.ts +150 -0
  447. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +126 -9
  448. package/src/resources/extensions/gsd/tests/workspace-git-preflight.test.ts +15 -0
  449. package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +21 -0
  450. package/src/resources/extensions/gsd/tests/worktree-projection-writers.test.ts +1 -1
  451. package/src/resources/extensions/gsd/tests/worktree-safety.test.ts +24 -0
  452. package/src/resources/extensions/gsd/tests/worktree-telemetry.test.ts +22 -0
  453. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +15 -3
  454. package/src/resources/extensions/gsd/tests/write-gate.test.ts +79 -0
  455. package/src/resources/extensions/gsd/tool-contract.ts +86 -8
  456. package/src/resources/extensions/gsd/tool-presentation-plan.ts +16 -33
  457. package/src/resources/extensions/gsd/tool-surface-snapshot.ts +47 -0
  458. package/src/resources/extensions/gsd/tools/plan-milestone.ts +19 -160
  459. package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +43 -0
  460. package/src/resources/extensions/gsd/tools/validate-milestone.ts +25 -84
  461. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +183 -21
  462. package/src/resources/extensions/gsd/uat-policy.ts +19 -10
  463. package/src/resources/extensions/gsd/uat-run.ts +10 -14
  464. package/src/resources/extensions/gsd/unit-context-composer.ts +85 -20
  465. package/src/resources/extensions/gsd/unit-runtime.ts +3 -2
  466. package/src/resources/extensions/gsd/unit-tool-contracts.ts +2 -1
  467. package/src/resources/extensions/gsd/user-input-boundary.ts +55 -5
  468. package/src/resources/extensions/gsd/validation-block-guard.ts +2 -0
  469. package/src/resources/extensions/gsd/web-app-uat.ts +101 -0
  470. package/src/resources/extensions/gsd/workflow-mcp.ts +22 -110
  471. package/src/resources/extensions/gsd/workflow-reconcile.ts +3 -3
  472. package/src/resources/extensions/gsd/workflow-tool-surface.ts +73 -0
  473. package/src/resources/extensions/gsd/workspace-git-guard.ts +1 -0
  474. package/src/resources/extensions/gsd/worktree-lifecycle.ts +7 -16
  475. package/src/resources/extensions/gsd/worktree-state-projection.ts +55 -7
  476. package/src/resources/extensions/gsd/worktree-telemetry.ts +16 -0
  477. package/src/resources/extensions/shared/interview-ui.ts +15 -2
  478. package/src/resources/shared/claude-runtime-floor.ts +248 -0
  479. package/dist/web/standalone/.next/server/chunks/678.js +0 -2
  480. package/dist/web/standalone/.next/static/chunks/2659.feb6499ca863ebfc.js +0 -1
  481. package/dist/web/standalone/.next/static/chunks/2772.151789db0edea835.js +0 -1
  482. package/dist/web/standalone/.next/static/chunks/4283.10a065467b5340d8.js +0 -2
  483. package/dist/web/standalone/.next/static/chunks/5826.960dc4634cc9b0d3.js +0 -1
  484. package/dist/web/standalone/.next/static/chunks/796.46f811c0fac23aab.js +0 -10
  485. package/dist/web/standalone/.next/static/chunks/8785.d32f7a61f55c1600.js +0 -1
  486. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.d.ts +0 -21
  487. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.d.ts.map +0 -1
  488. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.js +0 -213
  489. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.js.map +0 -1
  490. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/transcript-density-prototype.d.ts +0 -28
  491. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/transcript-density-prototype.d.ts.map +0 -1
  492. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/transcript-density-prototype.js +0 -249
  493. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/transcript-density-prototype.js.map +0 -1
  494. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/transcript-design-prototype.d.ts +0 -19
  495. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/transcript-design-prototype.d.ts.map +0 -1
  496. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/transcript-design-prototype.js +0 -797
  497. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/transcript-design-prototype.js.map +0 -1
  498. package/scripts/ensure-workspace-builds.cjs +0 -129
  499. /package/dist/web/standalone/.next/static/{tJOKQbQRO-9MiFDO8DIDS → tkLHUSzPA2kMmWz4DmGwI}/_buildManifest.js +0 -0
  500. /package/dist/web/standalone/.next/static/{tJOKQbQRO-9MiFDO8DIDS → tkLHUSzPA2kMmWz4DmGwI}/_ssgManifest.js +0 -0
@@ -20,6 +20,8 @@ export interface CliFlags {
20
20
  webPort?: number;
21
21
  /** Additional allowed origins for CORS: `--allowed-origins http://192.168.1.10:8080` */
22
22
  webAllowedOrigins?: string[];
23
+ /** Disable the web launcher's bearer token gate: `--no-auth` */
24
+ webNoAuth?: boolean;
23
25
  /** Set by `gsd sessions` when the user picks a specific session to resume */
24
26
  _selectedSessionPath?: string;
25
27
  }
@@ -52,6 +52,9 @@ export function parseCliArgs(argv) {
52
52
  const origins = args[++i].split(',').map(o => o.trim()).filter(Boolean);
53
53
  flags.webAllowedOrigins = (flags.webAllowedOrigins ?? []).concat(origins);
54
54
  }
55
+ else if (arg === '--no-auth') {
56
+ flags.webNoAuth = true;
57
+ }
55
58
  else if (arg === '--model' && i + 1 < args.length) {
56
59
  flags.model = args[++i];
57
60
  }
@@ -232,14 +235,18 @@ export async function runWebCliBranch(flags, deps = {}) {
232
235
  const agentDir = deps.agentDir ?? defaultAgentDir;
233
236
  const projectSessionsDir = getProjectSessionsDir(currentCwd, baseSessionsDir);
234
237
  migrateLegacyFlatSessions(baseSessionsDir, projectSessionsDir);
235
- const status = await (deps.runWebMode ?? launchWebMode)({
238
+ const launchOptions = {
236
239
  cwd: currentCwd,
237
240
  projectSessionsDir,
238
241
  agentDir,
239
242
  host: flags.webHost,
240
243
  port: flags.webPort,
241
244
  allowedOrigins: flags.webAllowedOrigins,
242
- });
245
+ };
246
+ if (flags.webNoAuth !== undefined) {
247
+ launchOptions.noAuth = flags.webNoAuth;
248
+ }
249
+ const status = await (deps.runWebMode ?? launchWebMode)(launchOptions);
243
250
  if (!status.ok) {
244
251
  emitWebModeFailure(stderr, status);
245
252
  }
package/dist/help-text.js CHANGED
@@ -189,6 +189,11 @@ export function printHelp(version) {
189
189
  process.stdout.write(' --worktree, -w [name] Start in an isolated worktree (auto-named if omitted)\n');
190
190
  process.stdout.write(' --model <id> Override model (e.g. provider/model-id)\n');
191
191
  process.stdout.write(' --no-session Disable session persistence\n');
192
+ process.stdout.write(' --web [path] Start browser-only web mode\n');
193
+ process.stdout.write(' --host <host> Web mode bind address\n');
194
+ process.stdout.write(' --port <port> Web mode port\n');
195
+ process.stdout.write(' --allowed-origins <csv> Additional allowed web origins\n');
196
+ process.stdout.write(' --no-auth Disable web token auth; requires external access control\n');
192
197
  process.stdout.write(' --extension <path> Load additional extension\n');
193
198
  process.stdout.write(' --tools <a,b,c> Restrict available tools\n');
194
199
  process.stdout.write(' --list-models [search] List available models and exit\n');
@@ -1,6 +1,8 @@
1
- import { join } from "node:path";
1
+ import { join, normalize } from "node:path";
2
2
  import { sessionsDir as defaultSessionsDir } from "./app-paths.js";
3
3
  export function getProjectSessionsDir(cwd, baseSessionsDir = defaultSessionsDir) {
4
- const safePath = `--${cwd.replace(/^[/\\]/, "").replace(/[/\\:]/g, "-")}--`;
4
+ // Normalize the cwd path to prevent directory traversal
5
+ const normalizedCwd = normalize(cwd).replace(/^[/\\]/, "").replace(/[/\\:]/g, "-");
6
+ const safePath = `--${normalizedCwd}--`;
5
7
  return join(baseSessionsDir, safePath);
6
8
  }
@@ -1 +1 @@
1
- fc4ebdcd3723ade9
1
+ 9a23824a70bd2722
@@ -114,6 +114,61 @@ function errorResult(message, questions = [], options) {
114
114
  details: { questions, response: null, cancelled: true, interrupted: options?.interrupted === true },
115
115
  };
116
116
  }
117
+ /** Parse the LLM-facing JSON payload back into a RoundResult for TUI rendering. */
118
+ function parseLlmAnswersContent(text) {
119
+ try {
120
+ const parsed = JSON.parse(text);
121
+ if (!parsed?.answers || typeof parsed.answers !== "object")
122
+ return null;
123
+ const answers = {};
124
+ for (const [id, entry] of Object.entries(parsed.answers)) {
125
+ const list = Array.isArray(entry?.answers) ? [...entry.answers] : [];
126
+ let notes = "";
127
+ const noteIdx = list.findIndex((item) => typeof item === "string" && item.startsWith("user_note:"));
128
+ if (noteIdx >= 0) {
129
+ notes = list.splice(noteIdx, 1)[0].replace(/^user_note:\s*/, "");
130
+ }
131
+ if (list.length === 0)
132
+ continue;
133
+ answers[id] = {
134
+ selected: list.length === 1 ? list[0] : list,
135
+ notes,
136
+ };
137
+ }
138
+ if (Object.keys(answers).length === 0)
139
+ return null;
140
+ return { endInterview: false, answers };
141
+ }
142
+ catch {
143
+ return null;
144
+ }
145
+ }
146
+ function isCancelledResultContent(text) {
147
+ return /\bwas cancelled before receiving a response\b/i.test(text)
148
+ || /\bwas interrupted before receiving a response\b/i.test(text);
149
+ }
150
+ function renderAnswerLines(questions, response, theme) {
151
+ const lines = [];
152
+ for (const q of questions) {
153
+ const answer = response.answers[q.id];
154
+ if (!answer) {
155
+ lines.push(`${theme.fg("accent", q.header)}: ${theme.fg("dim", "(no answer)")}`);
156
+ continue;
157
+ }
158
+ const selected = answer.selected;
159
+ const notes = answer.notes;
160
+ const multiSel = !!q.allowMultiple;
161
+ const answerText = multiSel && Array.isArray(selected)
162
+ ? selected.join(", ")
163
+ : (Array.isArray(selected) ? selected[0] : selected) ?? "(no answer)";
164
+ let line = `${theme.fg("success", "✓ ")}${theme.fg("accent", q.header)}: ${answerText}`;
165
+ if (notes) {
166
+ line += ` ${theme.fg("muted", `[note: ${notes}]`)}`;
167
+ }
168
+ lines.push(line);
169
+ }
170
+ return new Text(lines.join("\n"), 0, 0);
171
+ }
117
172
  /** Convert the shared RoundResult into the JSON the LLM expects. */
118
173
  function formatForLLM(result) {
119
174
  const answers = {};
@@ -318,11 +373,17 @@ export default function AskUserQuestions(pi) {
318
373
  }
319
374
  return new Text(text, 0, 0);
320
375
  },
321
- renderResult(result, _options, theme) {
376
+ renderResult(result, _options, theme, context) {
322
377
  const details = result.details;
378
+ const contentText = result.content[0]?.type === "text" ? result.content[0].text : "";
379
+ const questionsFromArgs = context?.args?.questions;
380
+ const parsedResponse = contentText ? parseLlmAnswersContent(contentText) : null;
323
381
  if (!details) {
324
- const text = result.content[0];
325
- return new Text(text?.type === "text" ? text.text : "", 0, 0);
382
+ const questions = questionsFromArgs;
383
+ if (questions?.length && parsedResponse) {
384
+ return renderAnswerLines(questions, parsedResponse, theme);
385
+ }
386
+ return new Text(contentText, 0, 0);
326
387
  }
327
388
  // Remote channel result (discriminated on details.remote === true)
328
389
  if (details.remote) {
@@ -352,30 +413,24 @@ export default function AskUserQuestions(pi) {
352
413
  }
353
414
  return new Text(lines.join("\n"), 0, 0);
354
415
  }
355
- if (details.cancelled || !details.response) {
416
+ const questions = details.questions ?? questionsFromArgs;
417
+ const response = details.response ?? parsedResponse;
418
+ const explicitCancel = details.cancelled === true || isCancelledResultContent(contentText);
419
+ if (explicitCancel && !response) {
356
420
  const interrupted = "interrupted" in details && details.interrupted === true;
357
421
  return new Text(theme.fg("warning", interrupted ? "Interrupted" : "Cancelled"), 0, 0);
358
422
  }
359
- const lines = [];
360
- for (const q of details.questions) {
361
- const answer = details.response.answers[q.id];
362
- if (!answer) {
363
- lines.push(`${theme.fg("accent", q.header)}: ${theme.fg("dim", "(no answer)")}`);
364
- continue;
365
- }
366
- const selected = answer.selected;
367
- const notes = answer.notes;
368
- const multiSel = !!q.allowMultiple;
369
- const answerText = multiSel && Array.isArray(selected)
370
- ? selected.join(", ")
371
- : (Array.isArray(selected) ? selected[0] : selected) ?? "(no answer)";
372
- let line = `${theme.fg("success", "✓ ")}${theme.fg("accent", q.header)}: ${answerText}`;
373
- if (notes) {
374
- line += ` ${theme.fg("muted", `[note: ${notes}]`)}`;
375
- }
376
- lines.push(line);
423
+ if (questions?.length && response) {
424
+ return renderAnswerLines(questions, response, theme);
425
+ }
426
+ if (contentText) {
427
+ return new Text(contentText, 0, 0);
428
+ }
429
+ if (details.cancelled || !details.response) {
430
+ const interrupted = "interrupted" in details && details.interrupted === true;
431
+ return new Text(theme.fg("warning", interrupted ? "Interrupted" : "Cancelled"), 0, 0);
377
432
  }
378
- return new Text(lines.join("\n"), 0, 0);
433
+ return new Text("", 0, 0);
379
434
  },
380
435
  });
381
436
  }
@@ -14,13 +14,18 @@ import { existsSync, readFileSync } from "node:fs";
14
14
  import { homedir } from "node:os";
15
15
  import { createRequire } from "node:module";
16
16
  import { dirname, join } from "node:path";
17
- import { PartialMessageBuilder, ZERO_USAGE, mapUsage } from "./partial-builder.js";
17
+ import { ZERO_USAGE, mapUsage } from "./partial-builder.js";
18
+ import { attachExternalResultsToToolBlocks, buildFinalAssistantContent, extractToolResultsFromSdkUserMessage, handleClaudeCodePartialStreamEvent, } from "./turn-assembler.js";
18
19
  import { buildWorkflowMcpServers, getRequiredWorkflowToolsForAutoUnit, resolveWorkflowMcpProjectRoot, } from "../gsd/workflow-mcp.js";
20
+ import { resolveWorkflowQuestionToolSurface } from "../gsd/question-transport.js";
19
21
  import { buildProjectGsdMcpServers, ensureProjectWorkflowMcpConfig } from "../gsd/mcp-project-config.js";
20
22
  import { loadProjectGSDPreferences } from "../gsd/preferences.js";
21
- import { discoverBrowserMcpServerName, discoverMcpServers, discoverMcpServerNames, discoverWorkflowMcpServerName, computeMcpDisallowedTools, } from "../gsd/mcp-filter.js";
23
+ import { markToolStart, markToolEnd } from "../gsd/auto.js";
24
+ import { markInteractiveElicitationStart, markInteractiveElicitationEnd, } from "../gsd/auto-tool-tracking.js";
25
+ import { discoverBrowserMcpServerName, discoverMcpServers, discoverMcpServerNames, discoverUserMcpServerNames, discoverWorkflowMcpServerName, computeMcpDisallowedTools, } from "../gsd/mcp-filter.js";
22
26
  import { RUN_UAT_CLAUDE_NATIVE_TOOL_NAMES, RUN_UAT_FORBIDDEN_TOOL_NAMES, RUN_UAT_WORKFLOW_TOOL_NAMES, resolveToolPresentationPlan } from "../gsd/tool-presentation-plan.js";
23
27
  import { showInterviewRound } from "../shared/tui.js";
28
+ export { buildFinalAssistantContent, extractToolResultsFromSdkUserMessage, handleClaudeCodePartialStreamEvent, mergePendingToolCalls, } from "./turn-assembler.js";
24
29
  export function serverToolUseToToolCallLike(block) {
25
30
  const argumentsValue = block.input && typeof block.input === "object" && !Array.isArray(block.input)
26
31
  ? block.input
@@ -1078,7 +1083,26 @@ export function createClaudeCodeCanUseToolHandler(ui) {
1078
1083
  // ---------------------------------------------------------------------------
1079
1084
  // Elicitation handler
1080
1085
  // ---------------------------------------------------------------------------
1081
- /** Create an SDK elicitation handler that routes requests through the extension UI dialogs, or undefined if no UI is available. */
1086
+ /**
1087
+ * Create an SDK elicitation handler that routes requests through the extension UI dialogs, or undefined if no UI is available.
1088
+ *
1089
+ * For structured (AskUserQuestion) elicitations, the interview round's result
1090
+ * disambiguates two cases that must not be conflated: an `undefined` result
1091
+ * means the custom UI is unavailable, so we fall back to the simpler `select`
1092
+ * dialogs; an empty-answers result means the user dismissed the question, which
1093
+ * is treated as a clean cancel. Falling back to dialogs on dismissal would
1094
+ * re-ask the same questions (the duplicate-question bug).
1095
+ */
1096
+ /**
1097
+ * Monotonic counter so concurrent/sequential elicitations resolved within the
1098
+ * same millisecond get distinct synthetic in-flight-tool ids (the `cc-elicit-*`
1099
+ * namespace never collides with real MCP toolCallIds).
1100
+ */
1101
+ let _elicitationSeq = 0;
1102
+ function nextElicitationSeq() {
1103
+ _elicitationSeq = (_elicitationSeq + 1) % Number.MAX_SAFE_INTEGER;
1104
+ return _elicitationSeq;
1105
+ }
1082
1106
  export function createClaudeCodeElicitationHandler(ui) {
1083
1107
  if (!ui)
1084
1108
  return undefined;
@@ -1091,18 +1115,64 @@ export function createClaudeCodeElicitationHandler(ui) {
1091
1115
  const headlessAnswer = answerElicitationFromHeadlessAnswers(questions, loadHeadlessAnswers());
1092
1116
  if (headlessAnswer)
1093
1117
  return headlessAnswer;
1094
- const interviewResult = await showInterviewRound(questions, { signal }, { ui }).catch(() => undefined);
1095
- if (interviewResult && Object.keys(interviewResult.answers).length > 0) {
1118
+ // The SDK elicitation blocks waiting for human input, but it is not an
1119
+ // MCP tool dispatch, so markToolStart/markToolEnd are never called for
1120
+ // it. Without this the soft/context/idle/hard watchdogs see zero
1121
+ // in-flight tools and re-dispatch (and ultimately abort) the agent
1122
+ // turn hosting this elicitation, tearing the question down (#2676 /
1123
+ // claude-code-cli self-cancel loop). Bracketing the human wait with
1124
+ // the s.active-gated interactive-tool guard makes it visible to
1125
+ // hasInteractiveToolInFlight()/getInFlightToolCount() so those
1126
+ // watchdogs exempt it. No-op outside auto-mode (wrapper self-gates).
1127
+ //
1128
+ // markInteractiveElicitationStart/End is a SEPARATE, ungated signal that
1129
+ // is observable in FOREGROUND (where the s.active-gated markToolStart is a
1130
+ // no-op). The foreground approval-gate pause path (register-hooks
1131
+ // message_update) consults isInteractiveElicitationInFlight() and bails so
1132
+ // it does not tear down the very elicitation that IS the human boundary
1133
+ // (#cc-elicitation-self-cancel). It clears in the finally on every exit.
1134
+ const elicId = "cc-elicit-" + (request.id ?? `${Date.now()}-${nextElicitationSeq()}`);
1135
+ markInteractiveElicitationStart();
1136
+ markToolStart(elicId, "ask_user_questions");
1137
+ try {
1138
+ const interviewResult = await showInterviewRound(questions, { signal, overlay: true }, { ui }).catch(() => undefined);
1139
+ if (interviewResult === undefined) {
1140
+ // `await` so the dialog human-wait stays inside try/finally and the
1141
+ // in-flight guard is held until the dialog resolves. Without it,
1142
+ // `finally` runs the moment the promise is created and the fallback
1143
+ // wait runs with zero in-flight tools — reintroducing the
1144
+ // self-cancel on this path (Bugbot #1c00624d).
1145
+ return await promptElicitationWithDialogs(request, questions, ui, signal);
1146
+ }
1147
+ if (Object.keys(interviewResult.answers).length === 0) {
1148
+ // A system/host teardown (compaction, session_switch, true
1149
+ // interrupt) that aborted the signal mid-wait sets `interrupted`.
1150
+ // Surface that as a non-affirmative `decline` so it is not
1151
+ // laundered into a clean user-declined `cancel` the model re-asks
1152
+ // against. A genuine user dismissal leaves `interrupted` falsy and
1153
+ // keeps the prior `cancel` semantics.
1154
+ return interviewResult.interrupted ? { action: "decline" } : { action: "cancel" };
1155
+ }
1096
1156
  return {
1097
1157
  action: "accept",
1098
1158
  content: roundResultToElicitationContent(questions, interviewResult),
1099
1159
  };
1100
1160
  }
1101
- return promptElicitationWithDialogs(request, questions, ui, signal);
1161
+ finally {
1162
+ markToolEnd(elicId);
1163
+ markInteractiveElicitationEnd();
1164
+ }
1102
1165
  }
1103
1166
  const textFields = parseTextInputElicitation(request);
1104
1167
  if (textFields) {
1105
- return promptTextInputElicitation(request, textFields, ui, signal);
1168
+ const elicId = "cc-elicit-" + (request.id ?? `${Date.now()}-${nextElicitationSeq()}`);
1169
+ markToolStart(elicId, "secure_env_collect");
1170
+ try {
1171
+ return await promptTextInputElicitation(request, textFields, ui, signal);
1172
+ }
1173
+ finally {
1174
+ markToolEnd(elicId);
1175
+ }
1106
1176
  }
1107
1177
  return { action: "decline" };
1108
1178
  };
@@ -1341,14 +1411,22 @@ export function buildSdkOptions(modelId, prompt, overrides, extraOptions = {}) {
1341
1411
  const projectBrowserServerName = discoverBrowserMcpServerName(projectRoot);
1342
1412
  const workflowServerName = projectWorkflowServerName ?? injectedWorkflowServerName;
1343
1413
  const browserServerName = projectBrowserServerName ?? injectedBrowserServerName;
1344
- // If a default GSD MCP server is already declared in the project's .mcp.json
1345
- // or .claude/settings.json, do not inject it again via mcpServers. Passing the
1346
- // same server name from two sources causes a duplicate registration conflict
1347
- // that prevents the MCP server from loading (tools become unavailable).
1414
+ // Non-strict (non-phase) sessions load ~/.claude/settings.json via settingSources
1415
+ // including "user". If the user declared the same server names there, injecting them
1416
+ // again via mcpServers causes duplicate registration and leaves MCP tools unavailable.
1417
+ // Strict (gsdPhase) sessions set settingSources=[] so user settings are not loaded.
1418
+ const userDiscovered = !gsdPhase ? discoverUserMcpServerNames() : [];
1419
+ const allDiscovered = discovered.length > 0 || userDiscovered.length > 0
1420
+ ? [...discovered, ...userDiscovered]
1421
+ : discovered;
1422
+ // If a default GSD MCP server is already declared in project config or in the user's
1423
+ // ~/.claude/settings.json (when that file will be loaded), do not inject it again via
1424
+ // mcpServers. Passing the same server name from two sources causes a duplicate
1425
+ // registration conflict that prevents the MCP server from loading (tools become unavailable).
1348
1426
  const workflowAlreadyInProject = projectWorkflowServerName !== undefined
1349
- || (injectedWorkflowServerName !== undefined && discovered.includes(injectedWorkflowServerName));
1427
+ || (injectedWorkflowServerName !== undefined && allDiscovered.includes(injectedWorkflowServerName));
1350
1428
  const browserAlreadyInProject = projectBrowserServerName !== undefined
1351
- || (injectedBrowserServerName !== undefined && discovered.includes(injectedBrowserServerName));
1429
+ || (injectedBrowserServerName !== undefined && allDiscovered.includes(injectedBrowserServerName));
1352
1430
  const mcpServersToInject = { ...defaultMcpServers.servers };
1353
1431
  if (workflowAlreadyInProject && injectedWorkflowServerName)
1354
1432
  delete mcpServersToInject[injectedWorkflowServerName];
@@ -1405,10 +1483,17 @@ export function buildSdkOptions(modelId, prompt, overrides, extraOptions = {}) {
1405
1483
  const sdkMcpServers = inlinePhaseMcpServers ?? filteredMcpServers;
1406
1484
  const strictMcpConfig = !!inlinePhaseMcpServers;
1407
1485
  // Strict phase configs inline the exact MCP servers GSD needs. Loading
1408
- // project/local settings at the same time can duplicate those servers and
1486
+ // Claude Code settings at the same time can duplicate those servers and
1409
1487
  // leave allowed mcp__... tools with no registered backing tool.
1410
- const settingSources = strictMcpConfig ? [] : ["project", "local"];
1488
+ const settingSources = strictMcpConfig ? [] : ["user", "project", "local"];
1411
1489
  const exactWorkflowMcpTools = resolveExactWorkflowMcpToolsForPhase(gsdPhase, workflowServerName, workflowExplicitlyBlocked);
1490
+ const questionToolSurface = resolveWorkflowQuestionToolSurface({
1491
+ workflowServerName,
1492
+ workflowExplicitlyBlocked,
1493
+ workflowMcpTools,
1494
+ exactWorkflowMcpTools,
1495
+ env: process.env,
1496
+ });
1412
1497
  const runUatDisallowedTools = gsdPhase === "run-uat" && workflowServerName
1413
1498
  ? [
1414
1499
  ...RUN_UAT_FORBIDDEN_TOOL_NAMES.filter((toolName) => !toolName.startsWith("mcp__")),
@@ -1422,6 +1507,7 @@ export function buildSdkOptions(modelId, prompt, overrides, extraOptions = {}) {
1422
1507
  const disallowedTools = [...new Set([
1423
1508
  "ToolSearch",
1424
1509
  ...(workflowMcpTools.length > 0 || exactWorkflowMcpTools.length > 0 ? ["AskUserQuestion"] : []),
1510
+ ...questionToolSurface.disallowedTools,
1425
1511
  ...runUatDisallowedTools,
1426
1512
  ...extraDisallowedTools,
1427
1513
  ])];
@@ -1484,228 +1570,6 @@ export function buildSdkOptions(modelId, prompt, overrides, extraOptions = {}) {
1484
1570
  ...sdkExtraOptions,
1485
1571
  };
1486
1572
  }
1487
- /** Normalise heterogeneous SDK tool-result content (string, array, or object) into a uniform `ExternalToolResultContentBlock[]`. */
1488
- function normalizeToolResultContent(content) {
1489
- if (typeof content === "string") {
1490
- return [{ type: "text", text: content }];
1491
- }
1492
- if (!Array.isArray(content)) {
1493
- if (content == null)
1494
- return [{ type: "text", text: "" }];
1495
- return [{ type: "text", text: JSON.stringify(content) }];
1496
- }
1497
- const blocks = [];
1498
- for (const item of content) {
1499
- if (typeof item === "string") {
1500
- blocks.push({ type: "text", text: item });
1501
- continue;
1502
- }
1503
- if (!item || typeof item !== "object") {
1504
- blocks.push({ type: "text", text: String(item) });
1505
- continue;
1506
- }
1507
- const block = item;
1508
- if (block.type === "text") {
1509
- blocks.push({ type: "text", text: typeof block.text === "string" ? block.text : "" });
1510
- continue;
1511
- }
1512
- if (block.type === "image"
1513
- && typeof block.data === "string"
1514
- && typeof block.mimeType === "string") {
1515
- blocks.push({ type: "image", data: block.data, mimeType: block.mimeType });
1516
- continue;
1517
- }
1518
- blocks.push({ type: "text", text: JSON.stringify(block) });
1519
- }
1520
- return blocks.length > 0 ? blocks : [{ type: "text", text: "" }];
1521
- }
1522
- /**
1523
- * Extract a `details` payload from an MCP tool-result block.
1524
- *
1525
- * MCP's `CallToolResult` carries structured data in `structuredContent` — the
1526
- * protocol's supported channel for non-text payloads. Claude Code's synthetic
1527
- * user message may surface that field in one of two shapes depending on SDK
1528
- * version: as a sibling on the `mcp_tool_result` block itself, or as a
1529
- * dedicated content sub-block with `type: "structuredContent"`. Snake-case
1530
- * (`structured_content`) is accepted defensively in case a transport hop
1531
- * rewrites casing. All other shapes fall back to an empty object so callers
1532
- * can rely on `details` being present.
1533
- */
1534
- function extractStructuredDetailsFromBlock(block) {
1535
- const sibling = block.structuredContent ?? block.structured_content;
1536
- if (sibling && typeof sibling === "object" && !Array.isArray(sibling)) {
1537
- return sibling;
1538
- }
1539
- if (Array.isArray(block.content)) {
1540
- for (const item of block.content) {
1541
- if (!item || typeof item !== "object")
1542
- continue;
1543
- const sub = item;
1544
- if (sub.type !== "structuredContent" && sub.type !== "structured_content")
1545
- continue;
1546
- const payload = sub.structuredContent ?? sub.structured_content ?? sub.data ?? sub.value;
1547
- if (payload && typeof payload === "object" && !Array.isArray(payload)) {
1548
- return payload;
1549
- }
1550
- }
1551
- }
1552
- // Return undefined (not {}) when no structured payload is present, matching
1553
- // the pre-#4477 contract where `details` was nullable. An empty-object
1554
- // sentinel is truthy and breaks downstream consumers that gate on
1555
- // `if (details)`. `undefined` matches the type of the field these results
1556
- // flow into (`Record<string, unknown> | undefined`).
1557
- return undefined;
1558
- }
1559
- /**
1560
- * True for items that are MCP `structuredContent` pseudo-blocks living inside
1561
- * a tool-result `content[]` array. These blocks carry the structured payload
1562
- * (extracted separately by `extractStructuredDetailsFromBlock`) and must NOT
1563
- * leak into the visible content rendered to the user — otherwise the renderer
1564
- * stringifies the JSON pseudo-block and shows it next to the actual tool
1565
- * output. See PR #4477 review (post-fix-round).
1566
- */
1567
- function isStructuredContentPseudoBlock(item) {
1568
- if (!item || typeof item !== "object")
1569
- return false;
1570
- const type = item.type;
1571
- return type === "structuredContent" || type === "structured_content";
1572
- }
1573
- /**
1574
- * Strip `structuredContent` pseudo-blocks from a tool-result content array
1575
- * before normalization. The structured payload is extracted via the sibling
1576
- * `structuredContent` field (or a dedicated extractor pass on the raw block);
1577
- * the visible content path must not include the pseudo-block itself.
1578
- */
1579
- function stripStructuredContentPseudoBlocks(content) {
1580
- if (!Array.isArray(content))
1581
- return content;
1582
- return content.filter((item) => !isStructuredContentPseudoBlock(item));
1583
- }
1584
- /** Extract tool result payloads from an SDK synthetic user message, keyed by tool-use ID. */
1585
- export function extractToolResultsFromSdkUserMessage(message) {
1586
- const extracted = [];
1587
- const seen = new Set();
1588
- const rawMessage = message.message;
1589
- const content = Array.isArray(rawMessage?.content) ? rawMessage.content : [];
1590
- for (const item of content) {
1591
- if (!item || typeof item !== "object")
1592
- continue;
1593
- const block = item;
1594
- const type = typeof block.type === "string" ? block.type : "";
1595
- if (type !== "tool_result" && type !== "mcp_tool_result")
1596
- continue;
1597
- const toolUseId = typeof block.tool_use_id === "string" ? block.tool_use_id : "";
1598
- if (!toolUseId || seen.has(toolUseId))
1599
- continue;
1600
- seen.add(toolUseId);
1601
- extracted.push({
1602
- toolUseId,
1603
- result: {
1604
- content: normalizeToolResultContent(stripStructuredContentPseudoBlocks(block.content)),
1605
- details: extractStructuredDetailsFromBlock(block),
1606
- isError: block.is_error === true,
1607
- },
1608
- });
1609
- }
1610
- if (extracted.length === 0) {
1611
- const fallback = message.tool_use_result;
1612
- if (fallback && typeof fallback === "object") {
1613
- const toolResult = fallback;
1614
- const toolUseId = typeof toolResult.tool_use_id === "string" ? toolResult.tool_use_id : "";
1615
- if (toolUseId) {
1616
- extracted.push({
1617
- toolUseId,
1618
- result: {
1619
- content: normalizeToolResultContent(stripStructuredContentPseudoBlocks(toolResult.content)),
1620
- details: extractStructuredDetailsFromBlock(toolResult),
1621
- isError: toolResult.is_error === true,
1622
- },
1623
- });
1624
- }
1625
- }
1626
- }
1627
- return extracted;
1628
- }
1629
- /** Attach external tool results from the SDK synthetic user message to their corresponding tool-call blocks by ID. */
1630
- function attachExternalResultsToToolBlocks(toolBlocks, toolResultsById) {
1631
- for (const block of toolBlocks) {
1632
- if (block.type !== "toolCall" && block.type !== "serverToolUse")
1633
- continue;
1634
- const externalResult = toolResultsById.get(block.id);
1635
- if (!externalResult)
1636
- continue;
1637
- block.externalResult = externalResult;
1638
- }
1639
- }
1640
- /**
1641
- * Build the final assistant content that Agent Core consumes in
1642
- * `externalToolExecution` mode. This preserves tool-call blocks, attaches any
1643
- * SDK-produced external results by tool-call id, and then appends the final
1644
- * text/thinking blocks for the completed turn.
1645
- */
1646
- export function buildFinalAssistantContent(params) {
1647
- const mergedToolBlocks = [...params.intermediateToolBlocks];
1648
- if (params.pendingContent) {
1649
- mergePendingToolCalls(mergedToolBlocks, params.pendingContent);
1650
- }
1651
- attachExternalResultsToToolBlocks(mergedToolBlocks, params.toolResultsById);
1652
- const finalContent = [...mergedToolBlocks];
1653
- if (params.pendingContent && params.pendingContent.length > 0) {
1654
- for (const block of params.pendingContent) {
1655
- if (block.type === "text" || block.type === "thinking") {
1656
- finalContent.push(block);
1657
- }
1658
- }
1659
- }
1660
- else {
1661
- if (params.lastThinkingContent) {
1662
- finalContent.push({ type: "thinking", thinking: params.lastThinkingContent });
1663
- }
1664
- if (params.lastTextContent) {
1665
- finalContent.push({ type: "text", text: params.lastTextContent });
1666
- }
1667
- }
1668
- if (finalContent.length === 0 && params.fallbackResultText) {
1669
- finalContent.push({ type: "text", text: params.fallbackResultText });
1670
- }
1671
- return finalContent;
1672
- }
1673
- /**
1674
- * Merge tool-call blocks from the active partial-message builder into the
1675
- * running list of intermediate tool calls, preserving order and de-duping
1676
- * by tool-call id. Exposed for testing the F3 fix (final-turn tool calls
1677
- * dropped when `result` arrives without a preceding synthetic `user`).
1678
- */
1679
- export function mergePendingToolCalls(intermediate, pending) {
1680
- const alreadyIncluded = new Set();
1681
- for (const block of intermediate) {
1682
- if (block.type === "toolCall")
1683
- alreadyIncluded.add(block.id);
1684
- }
1685
- for (const block of pending) {
1686
- if (block.type !== "toolCall")
1687
- continue;
1688
- if (alreadyIncluded.has(block.id))
1689
- continue;
1690
- alreadyIncluded.add(block.id);
1691
- intermediate.push(block);
1692
- }
1693
- return intermediate;
1694
- }
1695
- export function handleClaudeCodePartialStreamEvent(builder, event, modelId) {
1696
- if (event.type === "message_start") {
1697
- // Claude Code can emit repeated SDK message_start events inside one
1698
- // logical assistant response. Keep appending until a synthetic user
1699
- // tool-result boundary explicitly clears the builder.
1700
- return {
1701
- builder: builder ?? new PartialMessageBuilder(event.message?.model ?? modelId),
1702
- assistantEvent: null,
1703
- };
1704
- }
1705
- if (!builder)
1706
- return { builder, assistantEvent: null };
1707
- return { builder, assistantEvent: builder.handleEvent(event) };
1708
- }
1709
1573
  // ---------------------------------------------------------------------------
1710
1574
  // streamSimple implementation
1711
1575
  // ---------------------------------------------------------------------------