@opengsd/gsd-pi 1.2.0-dev.844675c9 → 1.2.0-dev.b1abb545

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 (375) 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/resources/.managed-resources-content-hash +1 -1
  5. package/dist/resources/extensions/ask-user-questions.js +78 -23
  6. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +84 -228
  7. package/dist/resources/extensions/claude-code-cli/turn-assembler.js +224 -0
  8. package/dist/resources/extensions/github-sync/templates.js +3 -3
  9. package/dist/resources/extensions/gsd/artifact-projection.js +14 -0
  10. package/dist/resources/extensions/gsd/auto/loop.js +74 -56
  11. package/dist/resources/extensions/gsd/auto/orchestrator.js +109 -11
  12. package/dist/resources/extensions/gsd/auto/phases.js +28 -3
  13. package/dist/resources/extensions/gsd/auto/run-unit.js +2 -1
  14. package/dist/resources/extensions/gsd/auto/session.js +3 -0
  15. package/dist/resources/extensions/gsd/auto-dashboard.js +16 -4
  16. package/dist/resources/extensions/gsd/auto-dispatch.js +6 -5
  17. package/dist/resources/extensions/gsd/auto-model-selection.js +8 -0
  18. package/dist/resources/extensions/gsd/auto-post-unit.js +4 -3
  19. package/dist/resources/extensions/gsd/auto-prompts.js +81 -8
  20. package/dist/resources/extensions/gsd/auto-recovery.js +48 -49
  21. package/dist/resources/extensions/gsd/auto-runtime-state.js +14 -0
  22. package/dist/resources/extensions/gsd/auto-start.js +12 -23
  23. package/dist/resources/extensions/gsd/auto-timers.js +16 -2
  24. package/dist/resources/extensions/gsd/auto-tool-tracking.js +32 -0
  25. package/dist/resources/extensions/gsd/auto-unit-tool-scope.js +4 -29
  26. package/dist/resources/extensions/gsd/auto-verification.js +7 -7
  27. package/dist/resources/extensions/gsd/auto-worktree.js +21 -19
  28. package/dist/resources/extensions/gsd/auto.js +11 -7
  29. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +28 -37
  30. package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +11 -37
  31. package/dist/resources/extensions/gsd/bootstrap/query-tools.js +2 -2
  32. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +100 -138
  33. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +63 -4
  34. package/dist/resources/extensions/gsd/closeout-consistency-gate.js +21 -4
  35. package/dist/resources/extensions/gsd/codebase-generator.js +8 -4
  36. package/dist/resources/extensions/gsd/commands/handlers/auto.js +3 -0
  37. package/dist/resources/extensions/gsd/commands-handlers.js +20 -0
  38. package/dist/resources/extensions/gsd/commands-inspect.js +4 -8
  39. package/dist/resources/extensions/gsd/commands-maintenance.js +61 -41
  40. package/dist/resources/extensions/gsd/commands-ship.js +2 -2
  41. package/dist/resources/extensions/gsd/commands-verdict.js +12 -2
  42. package/dist/resources/extensions/gsd/db-workspace.js +103 -0
  43. package/dist/resources/extensions/gsd/delegation-policy.js +2 -10
  44. package/dist/resources/extensions/gsd/discussion-handoff.js +218 -0
  45. package/dist/resources/extensions/gsd/docs/preferences-reference.md +9 -0
  46. package/dist/resources/extensions/gsd/doctor.js +16 -9
  47. package/dist/resources/extensions/gsd/error-classifier.js +1 -1
  48. package/dist/resources/extensions/gsd/git-conflict-state.js +16 -1
  49. package/dist/resources/extensions/gsd/gsd-db.js +12 -0
  50. package/dist/resources/extensions/gsd/guided-flow.js +34 -468
  51. package/dist/resources/extensions/gsd/guided-unit-completion.js +225 -0
  52. package/dist/resources/extensions/gsd/markdown-renderer.js +2 -1
  53. package/dist/resources/extensions/gsd/mcp-filter.js +2 -1
  54. package/dist/resources/extensions/gsd/mcp-tool-name.js +26 -0
  55. package/dist/resources/extensions/gsd/md-importer.js +4 -3
  56. package/dist/resources/extensions/gsd/migrate/safety.js +2 -2
  57. package/dist/resources/extensions/gsd/migration-auto-check.js +3 -2
  58. package/dist/resources/extensions/gsd/milestone-closeout-proof.js +72 -0
  59. package/dist/resources/extensions/gsd/milestone-closeout.js +12 -4
  60. package/dist/resources/extensions/gsd/milestone-merge-transaction.js +10 -0
  61. package/dist/resources/extensions/gsd/milestone-planning-persistence.js +156 -0
  62. package/dist/resources/extensions/gsd/milestone-readiness.js +77 -0
  63. package/dist/resources/extensions/gsd/milestone-settlement.js +50 -0
  64. package/dist/resources/extensions/gsd/milestone-validation-evidence.js +73 -0
  65. package/dist/resources/extensions/gsd/milestone-validation-verdict.js +57 -0
  66. package/dist/resources/extensions/gsd/parallel-eligibility.js +3 -6
  67. package/dist/resources/extensions/gsd/parallel-orchestrator.js +3 -2
  68. package/dist/resources/extensions/gsd/preferences-diagnostics.js +67 -0
  69. package/dist/resources/extensions/gsd/preferences.js +147 -29
  70. package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -0
  71. package/dist/resources/extensions/gsd/prompts/execute-task.md +2 -0
  72. package/dist/resources/extensions/gsd/prompts/guided-discuss-project.md +3 -1
  73. package/dist/resources/extensions/gsd/prompts/plan-milestone.md +2 -0
  74. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -0
  75. package/dist/resources/extensions/gsd/prompts/refine-slice.md +1 -0
  76. package/dist/resources/extensions/gsd/prompts/system.md +1 -1
  77. package/dist/resources/extensions/gsd/provider-payload-policy.js +83 -0
  78. package/dist/resources/extensions/gsd/pull-request-process.js +13 -0
  79. package/dist/resources/extensions/gsd/quality-gate-closure.js +109 -0
  80. package/dist/resources/extensions/gsd/question-transport.js +86 -0
  81. package/dist/resources/extensions/gsd/roadmap-slices.js +8 -2
  82. package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +3 -2
  83. package/dist/resources/extensions/gsd/state.js +13 -5
  84. package/dist/resources/extensions/gsd/templates/plan.md +7 -0
  85. package/dist/resources/extensions/gsd/templates/project.md +1 -0
  86. package/dist/resources/extensions/gsd/templates/roadmap.md +1 -1
  87. package/dist/resources/extensions/gsd/templates/uat.md +5 -1
  88. package/dist/resources/extensions/gsd/tool-contract.js +52 -8
  89. package/dist/resources/extensions/gsd/tool-presentation-plan.js +15 -34
  90. package/dist/resources/extensions/gsd/tool-surface-snapshot.js +17 -0
  91. package/dist/resources/extensions/gsd/tools/plan-milestone.js +15 -143
  92. package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +39 -0
  93. package/dist/resources/extensions/gsd/tools/validate-milestone.js +15 -78
  94. package/dist/resources/extensions/gsd/uat-policy.js +16 -10
  95. package/dist/resources/extensions/gsd/uat-run.js +9 -14
  96. package/dist/resources/extensions/gsd/unit-context-composer.js +40 -20
  97. package/dist/resources/extensions/gsd/unit-runtime.js +3 -2
  98. package/dist/resources/extensions/gsd/unit-tool-contracts.js +2 -1
  99. package/dist/resources/extensions/gsd/user-input-boundary.js +23 -0
  100. package/dist/resources/extensions/gsd/validation-block-guard.js +2 -0
  101. package/dist/resources/extensions/gsd/web-app-uat.js +80 -0
  102. package/dist/resources/extensions/gsd/workflow-mcp.js +15 -102
  103. package/dist/resources/extensions/gsd/workflow-reconcile.js +4 -3
  104. package/dist/resources/extensions/gsd/workflow-tool-surface.js +46 -0
  105. package/dist/resources/extensions/gsd/workspace-git-guard.js +2 -0
  106. package/dist/resources/extensions/gsd/worktree-state-projection.js +33 -4
  107. package/dist/resources/extensions/gsd/worktree-telemetry.js +12 -0
  108. package/dist/resources/extensions/shared/interview-ui.js +2 -2
  109. package/dist/resources/shared/claude-runtime-floor.js +182 -0
  110. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  111. package/dist/update-cmd.js +20 -0
  112. package/dist/web/standalone/.next/BUILD_ID +1 -1
  113. package/dist/web/standalone/.next/app-path-routes-manifest.json +7 -7
  114. package/dist/web/standalone/.next/build-manifest.json +3 -3
  115. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  116. package/dist/web/standalone/.next/react-loadable-manifest.json +8 -8
  117. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  118. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  119. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  120. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  121. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  122. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  123. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  124. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  125. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  126. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  127. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  128. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  129. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  130. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  131. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  132. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  133. package/dist/web/standalone/.next/server/app/index.html +1 -1
  134. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  135. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  136. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  137. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  138. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  139. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  140. package/dist/web/standalone/.next/server/app-paths-manifest.json +7 -7
  141. package/dist/web/standalone/.next/server/chunks/8357.js +1 -1
  142. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  143. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  144. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  145. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  146. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  147. package/dist/web/standalone/.next/static/chunks/2659.b7b129ee6a769448.js +1 -0
  148. package/dist/web/standalone/.next/static/chunks/2772.bfa657f49f955239.js +1 -0
  149. package/dist/web/standalone/.next/static/chunks/{3616.4113d484a994e411.js → 3616.3c60753b8ffcbd2e.js} +1 -1
  150. package/dist/web/standalone/.next/static/chunks/4283.e4873b058df143a1.js +2 -0
  151. package/dist/web/standalone/.next/static/chunks/5826.a46ecdd1cfe8dabc.js +1 -0
  152. package/dist/web/standalone/.next/static/chunks/796.cf859a427a2cb2ac.js +10 -0
  153. package/dist/web/standalone/.next/static/chunks/8785.2e5a118797fb2dd2.js +1 -0
  154. package/dist/web/standalone/.next/static/chunks/{webpack-dda80a1ef5587410.js → webpack-fbea77b5f9953368.js} +1 -1
  155. package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
  156. package/dist/web-mode.d.ts +2 -0
  157. package/dist/web-mode.js +20 -8
  158. package/package.json +2 -1
  159. package/packages/cloud-mcp-gateway/package.json +2 -2
  160. package/packages/contracts/package.json +1 -1
  161. package/packages/daemon/package.json +4 -4
  162. package/packages/gsd-agent-core/dist/session/agent-session-extensions.d.ts +2 -0
  163. package/packages/gsd-agent-core/dist/session/agent-session-extensions.d.ts.map +1 -1
  164. package/packages/gsd-agent-core/dist/session/agent-session-extensions.js +14 -0
  165. package/packages/gsd-agent-core/dist/session/agent-session-extensions.js.map +1 -1
  166. package/packages/gsd-agent-core/package.json +5 -5
  167. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  168. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +106 -40
  169. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  170. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-widgets.d.ts.map +1 -1
  171. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-widgets.js +6 -0
  172. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-widgets.js.map +1 -1
  173. package/packages/gsd-agent-modes/package.json +7 -7
  174. package/packages/mcp-server/dist/server.d.ts +10 -0
  175. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  176. package/packages/mcp-server/dist/server.js +8 -0
  177. package/packages/mcp-server/dist/server.js.map +1 -1
  178. package/packages/mcp-server/dist/workflow-tools.d.ts +41 -0
  179. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  180. package/packages/mcp-server/dist/workflow-tools.js +2 -1
  181. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  182. package/packages/mcp-server/package.json +3 -3
  183. package/packages/native/package.json +1 -1
  184. package/packages/pi-agent-core/package.json +1 -1
  185. package/packages/pi-ai/dist/models.generated.d.ts +8 -93
  186. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  187. package/packages/pi-ai/dist/models.generated.js +35 -120
  188. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  189. package/packages/pi-ai/package.json +1 -1
  190. package/packages/pi-coding-agent/package.json +7 -7
  191. package/packages/pi-tui/dist/components/input.js +1 -1
  192. package/packages/pi-tui/dist/components/input.js.map +1 -1
  193. package/packages/pi-tui/dist/keys.d.ts.map +1 -1
  194. package/packages/pi-tui/dist/keys.js +39 -30
  195. package/packages/pi-tui/dist/keys.js.map +1 -1
  196. package/packages/pi-tui/dist/stdin-buffer.d.ts.map +1 -1
  197. package/packages/pi-tui/dist/stdin-buffer.js +22 -0
  198. package/packages/pi-tui/dist/stdin-buffer.js.map +1 -1
  199. package/packages/pi-tui/package.json +2 -2
  200. package/packages/rpc-client/package.json +2 -2
  201. package/pkg/package.json +1 -1
  202. package/src/resources/extensions/ask-user-questions.ts +87 -24
  203. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +108 -281
  204. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +240 -0
  205. package/src/resources/extensions/claude-code-cli/turn-assembler.ts +287 -0
  206. package/src/resources/extensions/github-sync/templates.ts +3 -3
  207. package/src/resources/extensions/github-sync/tests/templates.test.ts +2 -2
  208. package/src/resources/extensions/gsd/artifact-projection.ts +31 -0
  209. package/src/resources/extensions/gsd/auto/contracts.ts +32 -2
  210. package/src/resources/extensions/gsd/auto/loop-deps.ts +2 -0
  211. package/src/resources/extensions/gsd/auto/loop.ts +83 -61
  212. package/src/resources/extensions/gsd/auto/orchestrator.ts +125 -12
  213. package/src/resources/extensions/gsd/auto/phases.ts +35 -3
  214. package/src/resources/extensions/gsd/auto/run-unit.ts +2 -1
  215. package/src/resources/extensions/gsd/auto/session.ts +4 -0
  216. package/src/resources/extensions/gsd/auto-dashboard.ts +18 -4
  217. package/src/resources/extensions/gsd/auto-dispatch.ts +20 -7
  218. package/src/resources/extensions/gsd/auto-model-selection.ts +8 -0
  219. package/src/resources/extensions/gsd/auto-post-unit.ts +4 -3
  220. package/src/resources/extensions/gsd/auto-prompts.ts +107 -9
  221. package/src/resources/extensions/gsd/auto-recovery.ts +50 -50
  222. package/src/resources/extensions/gsd/auto-runtime-state.ts +26 -0
  223. package/src/resources/extensions/gsd/auto-start.ts +17 -20
  224. package/src/resources/extensions/gsd/auto-timers.ts +16 -2
  225. package/src/resources/extensions/gsd/auto-tool-tracking.ts +35 -0
  226. package/src/resources/extensions/gsd/auto-unit-tool-scope.ts +9 -30
  227. package/src/resources/extensions/gsd/auto-verification.ts +7 -8
  228. package/src/resources/extensions/gsd/auto-worktree.ts +33 -26
  229. package/src/resources/extensions/gsd/auto.ts +15 -8
  230. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +29 -37
  231. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +10 -37
  232. package/src/resources/extensions/gsd/bootstrap/query-tools.ts +2 -2
  233. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +116 -151
  234. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +107 -3
  235. package/src/resources/extensions/gsd/closeout-consistency-gate.ts +27 -5
  236. package/src/resources/extensions/gsd/codebase-generator.ts +9 -5
  237. package/src/resources/extensions/gsd/commands/handlers/auto.ts +3 -0
  238. package/src/resources/extensions/gsd/commands-handlers.ts +18 -0
  239. package/src/resources/extensions/gsd/commands-inspect.ts +7 -8
  240. package/src/resources/extensions/gsd/commands-maintenance.ts +74 -40
  241. package/src/resources/extensions/gsd/commands-ship.ts +2 -2
  242. package/src/resources/extensions/gsd/commands-verdict.ts +19 -2
  243. package/src/resources/extensions/gsd/db-workspace.ts +170 -0
  244. package/src/resources/extensions/gsd/delegation-policy.ts +3 -11
  245. package/src/resources/extensions/gsd/discussion-handoff.ts +276 -0
  246. package/src/resources/extensions/gsd/docs/preferences-reference.md +9 -0
  247. package/src/resources/extensions/gsd/doctor.ts +15 -5
  248. package/src/resources/extensions/gsd/error-classifier.ts +1 -1
  249. package/src/resources/extensions/gsd/git-conflict-state.ts +17 -1
  250. package/src/resources/extensions/gsd/gsd-db.ts +12 -0
  251. package/src/resources/extensions/gsd/guided-flow.ts +47 -558
  252. package/src/resources/extensions/gsd/guided-unit-completion.ts +275 -0
  253. package/src/resources/extensions/gsd/markdown-renderer.ts +2 -1
  254. package/src/resources/extensions/gsd/mcp-filter.ts +2 -1
  255. package/src/resources/extensions/gsd/mcp-tool-name.ts +35 -0
  256. package/src/resources/extensions/gsd/md-importer.ts +3 -3
  257. package/src/resources/extensions/gsd/migrate/safety.ts +2 -2
  258. package/src/resources/extensions/gsd/migration-auto-check.ts +2 -2
  259. package/src/resources/extensions/gsd/milestone-closeout-proof.ts +131 -0
  260. package/src/resources/extensions/gsd/milestone-closeout.ts +12 -4
  261. package/src/resources/extensions/gsd/milestone-merge-transaction.ts +47 -0
  262. package/src/resources/extensions/gsd/milestone-planning-persistence.ts +224 -0
  263. package/src/resources/extensions/gsd/milestone-readiness.ts +125 -0
  264. package/src/resources/extensions/gsd/milestone-settlement.ts +81 -0
  265. package/src/resources/extensions/gsd/milestone-validation-evidence.ts +95 -0
  266. package/src/resources/extensions/gsd/milestone-validation-verdict.ts +80 -0
  267. package/src/resources/extensions/gsd/parallel-eligibility.ts +4 -5
  268. package/src/resources/extensions/gsd/parallel-orchestrator.ts +6 -2
  269. package/src/resources/extensions/gsd/preferences-diagnostics.ts +98 -0
  270. package/src/resources/extensions/gsd/preferences-types.ts +16 -0
  271. package/src/resources/extensions/gsd/preferences.ts +173 -28
  272. package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -0
  273. package/src/resources/extensions/gsd/prompts/execute-task.md +2 -0
  274. package/src/resources/extensions/gsd/prompts/guided-discuss-project.md +3 -1
  275. package/src/resources/extensions/gsd/prompts/plan-milestone.md +2 -0
  276. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -0
  277. package/src/resources/extensions/gsd/prompts/refine-slice.md +1 -0
  278. package/src/resources/extensions/gsd/prompts/system.md +1 -1
  279. package/src/resources/extensions/gsd/provider-payload-policy.ts +140 -0
  280. package/src/resources/extensions/gsd/pull-request-process.ts +41 -0
  281. package/src/resources/extensions/gsd/quality-gate-closure.ts +140 -0
  282. package/src/resources/extensions/gsd/question-transport.ts +138 -0
  283. package/src/resources/extensions/gsd/roadmap-slices.ts +8 -2
  284. package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +6 -2
  285. package/src/resources/extensions/gsd/state.ts +15 -5
  286. package/src/resources/extensions/gsd/templates/plan.md +7 -0
  287. package/src/resources/extensions/gsd/templates/project.md +1 -0
  288. package/src/resources/extensions/gsd/templates/roadmap.md +1 -1
  289. package/src/resources/extensions/gsd/templates/uat.md +5 -1
  290. package/src/resources/extensions/gsd/tests/ask-user-questions-render.test.ts +92 -0
  291. package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +29 -1
  292. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +321 -5
  293. package/src/resources/extensions/gsd/tests/auto-milestone-target.test.ts +23 -0
  294. package/src/resources/extensions/gsd/tests/auto-model-selection-tool-poisoning.test.ts +18 -0
  295. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +133 -4
  296. package/src/resources/extensions/gsd/tests/auto-runtime-state.test.ts +34 -0
  297. package/src/resources/extensions/gsd/tests/canonical-milestone-root.test.ts +20 -0
  298. package/src/resources/extensions/gsd/tests/codebase-generator.test.ts +22 -0
  299. package/src/resources/extensions/gsd/tests/commands-dispatcher-workspace-git.test.ts +11 -0
  300. package/src/resources/extensions/gsd/tests/commands-verdict.test.ts +38 -1
  301. package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +34 -3
  302. package/src/resources/extensions/gsd/tests/dispatch-run-uat-browser-tools.test.ts +88 -0
  303. package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +18 -0
  304. package/src/resources/extensions/gsd/tests/execute-task-rendering.test.ts +1 -0
  305. package/src/resources/extensions/gsd/tests/fixtures/pr-body/swarm-lane-no-blockers.md +1 -5
  306. package/src/resources/extensions/gsd/tests/fixtures/pr-body/swarm-lane-with-blockers.md +1 -5
  307. package/src/resources/extensions/gsd/tests/gate-state-canonicalization.test.ts +48 -1
  308. package/src/resources/extensions/gsd/tests/mcp-tool-name.test.ts +34 -0
  309. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +58 -0
  310. package/src/resources/extensions/gsd/tests/milestone-closeout-proof.test.ts +99 -0
  311. package/src/resources/extensions/gsd/tests/milestone-closeout.test.ts +25 -0
  312. package/src/resources/extensions/gsd/tests/milestone-merge-transaction.test.ts +46 -0
  313. package/src/resources/extensions/gsd/tests/milestone-readiness.test.ts +65 -0
  314. package/src/resources/extensions/gsd/tests/milestone-validation-evidence.test.ts +41 -0
  315. package/src/resources/extensions/gsd/tests/milestone-validation-verdict.test.ts +55 -0
  316. package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +45 -0
  317. package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +2 -0
  318. package/src/resources/extensions/gsd/tests/planning-crossval.test.ts +45 -0
  319. package/src/resources/extensions/gsd/tests/preferences-diagnostics.test.ts +67 -0
  320. package/src/resources/extensions/gsd/tests/preferences.test.ts +183 -0
  321. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +46 -0
  322. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +9 -0
  323. package/src/resources/extensions/gsd/tests/provider-payload-policy.test.ts +165 -0
  324. package/src/resources/extensions/gsd/tests/pull-request-process.test.ts +47 -0
  325. package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +94 -0
  326. package/src/resources/extensions/gsd/tests/roadmap-parse-regression.test.ts +40 -0
  327. package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +25 -1
  328. package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +80 -0
  329. package/src/resources/extensions/gsd/tests/single-writer-invariant.test.ts +101 -1
  330. package/src/resources/extensions/gsd/tests/stale-queued-milestone.test.ts +27 -0
  331. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +2 -1
  332. package/src/resources/extensions/gsd/tests/tool-availability-audit.test.ts +35 -0
  333. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +35 -42
  334. package/src/resources/extensions/gsd/tests/uat-policy.test.ts +23 -0
  335. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +47 -0
  336. package/src/resources/extensions/gsd/tests/user-input-boundary.test.ts +86 -1
  337. package/src/resources/extensions/gsd/tests/validate-milestone-stuck-guard.test.ts +39 -0
  338. package/src/resources/extensions/gsd/tests/web-app-uat.test.ts +150 -0
  339. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +126 -9
  340. package/src/resources/extensions/gsd/tests/workspace-git-preflight.test.ts +15 -0
  341. package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +21 -0
  342. package/src/resources/extensions/gsd/tests/worktree-projection-writers.test.ts +1 -1
  343. package/src/resources/extensions/gsd/tests/worktree-telemetry.test.ts +22 -0
  344. package/src/resources/extensions/gsd/tests/write-gate.test.ts +79 -0
  345. package/src/resources/extensions/gsd/tool-contract.ts +86 -8
  346. package/src/resources/extensions/gsd/tool-presentation-plan.ts +16 -33
  347. package/src/resources/extensions/gsd/tool-surface-snapshot.ts +47 -0
  348. package/src/resources/extensions/gsd/tools/plan-milestone.ts +19 -160
  349. package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +43 -0
  350. package/src/resources/extensions/gsd/tools/validate-milestone.ts +25 -84
  351. package/src/resources/extensions/gsd/uat-policy.ts +19 -10
  352. package/src/resources/extensions/gsd/uat-run.ts +10 -14
  353. package/src/resources/extensions/gsd/unit-context-composer.ts +85 -20
  354. package/src/resources/extensions/gsd/unit-runtime.ts +3 -2
  355. package/src/resources/extensions/gsd/unit-tool-contracts.ts +2 -1
  356. package/src/resources/extensions/gsd/user-input-boundary.ts +18 -0
  357. package/src/resources/extensions/gsd/validation-block-guard.ts +2 -0
  358. package/src/resources/extensions/gsd/web-app-uat.ts +101 -0
  359. package/src/resources/extensions/gsd/workflow-mcp.ts +22 -110
  360. package/src/resources/extensions/gsd/workflow-reconcile.ts +3 -3
  361. package/src/resources/extensions/gsd/workflow-tool-surface.ts +73 -0
  362. package/src/resources/extensions/gsd/workspace-git-guard.ts +1 -0
  363. package/src/resources/extensions/gsd/worktree-lifecycle.ts +7 -16
  364. package/src/resources/extensions/gsd/worktree-state-projection.ts +55 -7
  365. package/src/resources/extensions/gsd/worktree-telemetry.ts +16 -0
  366. package/src/resources/extensions/shared/interview-ui.ts +15 -2
  367. package/src/resources/shared/claude-runtime-floor.ts +248 -0
  368. package/dist/web/standalone/.next/static/chunks/2659.feb6499ca863ebfc.js +0 -1
  369. package/dist/web/standalone/.next/static/chunks/2772.151789db0edea835.js +0 -1
  370. package/dist/web/standalone/.next/static/chunks/4283.10a065467b5340d8.js +0 -2
  371. package/dist/web/standalone/.next/static/chunks/5826.960dc4634cc9b0d3.js +0 -1
  372. package/dist/web/standalone/.next/static/chunks/796.46f811c0fac23aab.js +0 -10
  373. package/dist/web/standalone/.next/static/chunks/8785.d32f7a61f55c1600.js +0 -1
  374. /package/dist/web/standalone/.next/static/{Qbr81pQ-pbQXP4bq2VXLv → 3PtrU9qGPEXwNLWkIyiqk}/_buildManifest.js +0 -0
  375. /package/dist/web/standalone/.next/static/{Qbr81pQ-pbQXP4bq2VXLv → 3PtrU9qGPEXwNLWkIyiqk}/_ssgManifest.js +0 -0
@@ -27,13 +27,29 @@ import { homedir } from "node:os";
27
27
  import { createRequire } from "node:module";
28
28
  import { dirname, join } from "node:path";
29
29
  import { PartialMessageBuilder, ZERO_USAGE, mapUsage } from "./partial-builder.js";
30
+ import {
31
+ attachExternalResultsToToolBlocks,
32
+ buildFinalAssistantContent,
33
+ extractToolResultsFromSdkUserMessage,
34
+ handleClaudeCodePartialStreamEvent,
35
+ } from "./turn-assembler.js";
36
+ import type {
37
+ ExternalToolResultPayload,
38
+ ToolCallWithExternalResult,
39
+ } from "./turn-assembler.js";
30
40
  import {
31
41
  buildWorkflowMcpServers,
32
42
  getRequiredWorkflowToolsForAutoUnit,
33
43
  resolveWorkflowMcpProjectRoot,
34
44
  } from "../gsd/workflow-mcp.js";
45
+ import { resolveWorkflowQuestionToolSurface } from "../gsd/question-transport.js";
35
46
  import { buildProjectGsdMcpServers, ensureProjectWorkflowMcpConfig } from "../gsd/mcp-project-config.js";
36
47
  import { loadProjectGSDPreferences } from "../gsd/preferences.js";
48
+ import { markToolStart, markToolEnd } from "../gsd/auto.js";
49
+ import {
50
+ markInteractiveElicitationStart,
51
+ markInteractiveElicitationEnd,
52
+ } from "../gsd/auto-tool-tracking.js";
37
53
  import {
38
54
  discoverBrowserMcpServerName,
39
55
  discoverMcpServers,
@@ -45,7 +61,6 @@ import {
45
61
  import { RUN_UAT_CLAUDE_NATIVE_TOOL_NAMES, RUN_UAT_FORBIDDEN_TOOL_NAMES, RUN_UAT_WORKFLOW_TOOL_NAMES, resolveToolPresentationPlan } from "../gsd/tool-presentation-plan.js";
46
62
  import { showInterviewRound, type Question, type RoundResult } from "../shared/tui.js";
47
63
  import type {
48
- BetaRawMessageStreamEvent,
49
64
  SDKAssistantMessage,
50
65
  SDKMessage,
51
66
  SDKPartialAssistantMessage,
@@ -53,25 +68,17 @@ import type {
53
68
  SDKUserMessage,
54
69
  } from "./sdk-types.js";
55
70
 
56
- /** A single content block returned by an external (SDK-executed) tool call. */
57
- export interface ExternalToolResultContentBlock {
58
- type: string;
59
- text?: string;
60
- data?: string;
61
- mimeType?: string;
62
- }
63
-
64
- /** The full result payload returned by an external tool, including content blocks and error status. */
65
- export interface ExternalToolResultPayload {
66
- content: ExternalToolResultContentBlock[];
67
- details?: Record<string, unknown>;
68
- isError: boolean;
69
- }
70
-
71
- /** A `ToolCall` block augmented with the external result attached by the SDK synthetic user message. */
72
- type ToolCallWithExternalResult = ToolCall & {
73
- externalResult?: ExternalToolResultPayload;
74
- };
71
+ export {
72
+ buildFinalAssistantContent,
73
+ extractToolResultsFromSdkUserMessage,
74
+ handleClaudeCodePartialStreamEvent,
75
+ mergePendingToolCalls,
76
+ } from "./turn-assembler.js";
77
+ export type {
78
+ ExternalToolResultContentBlock,
79
+ ExternalToolResultPayload,
80
+ ToolCallWithExternalResult,
81
+ } from "./turn-assembler.js";
75
82
 
76
83
  interface PromptToolContextOptions {
77
84
  workflowMcpServerName?: string | null;
@@ -1359,7 +1366,27 @@ export function createClaudeCodeCanUseToolHandler(
1359
1366
  // Elicitation handler
1360
1367
  // ---------------------------------------------------------------------------
1361
1368
 
1362
- /** Create an SDK elicitation handler that routes requests through the extension UI dialogs, or undefined if no UI is available. */
1369
+ /**
1370
+ * Create an SDK elicitation handler that routes requests through the extension UI dialogs, or undefined if no UI is available.
1371
+ *
1372
+ * For structured (AskUserQuestion) elicitations, the interview round's result
1373
+ * disambiguates two cases that must not be conflated: an `undefined` result
1374
+ * means the custom UI is unavailable, so we fall back to the simpler `select`
1375
+ * dialogs; an empty-answers result means the user dismissed the question, which
1376
+ * is treated as a clean cancel. Falling back to dialogs on dismissal would
1377
+ * re-ask the same questions (the duplicate-question bug).
1378
+ */
1379
+ /**
1380
+ * Monotonic counter so concurrent/sequential elicitations resolved within the
1381
+ * same millisecond get distinct synthetic in-flight-tool ids (the `cc-elicit-*`
1382
+ * namespace never collides with real MCP toolCallIds).
1383
+ */
1384
+ let _elicitationSeq = 0;
1385
+ function nextElicitationSeq(): number {
1386
+ _elicitationSeq = (_elicitationSeq + 1) % Number.MAX_SAFE_INTEGER;
1387
+ return _elicitationSeq;
1388
+ }
1389
+
1363
1390
  export function createClaudeCodeElicitationHandler(
1364
1391
  ui: ExtensionUIContext | undefined,
1365
1392
  ): ((request: SdkElicitationRequest, options: { signal: AbortSignal }) => Promise<SdkElicitationResult>) | undefined {
@@ -1375,20 +1402,67 @@ export function createClaudeCodeElicitationHandler(
1375
1402
  const headlessAnswer = answerElicitationFromHeadlessAnswers(questions, loadHeadlessAnswers());
1376
1403
  if (headlessAnswer) return headlessAnswer;
1377
1404
 
1378
- const interviewResult = await showInterviewRound(questions, { signal }, { ui } as any).catch(() => undefined);
1379
- if (interviewResult && Object.keys(interviewResult.answers).length > 0) {
1405
+ // The SDK elicitation blocks waiting for human input, but it is not an
1406
+ // MCP tool dispatch, so markToolStart/markToolEnd are never called for
1407
+ // it. Without this the soft/context/idle/hard watchdogs see zero
1408
+ // in-flight tools and re-dispatch (and ultimately abort) the agent
1409
+ // turn hosting this elicitation, tearing the question down (#2676 /
1410
+ // claude-code-cli self-cancel loop). Bracketing the human wait with
1411
+ // the s.active-gated interactive-tool guard makes it visible to
1412
+ // hasInteractiveToolInFlight()/getInFlightToolCount() so those
1413
+ // watchdogs exempt it. No-op outside auto-mode (wrapper self-gates).
1414
+ //
1415
+ // markInteractiveElicitationStart/End is a SEPARATE, ungated signal that
1416
+ // is observable in FOREGROUND (where the s.active-gated markToolStart is a
1417
+ // no-op). The foreground approval-gate pause path (register-hooks
1418
+ // message_update) consults isInteractiveElicitationInFlight() and bails so
1419
+ // it does not tear down the very elicitation that IS the human boundary
1420
+ // (#cc-elicitation-self-cancel). It clears in the finally on every exit.
1421
+ const elicId = "cc-elicit-" + ((request as { id?: string | number }).id ?? `${Date.now()}-${nextElicitationSeq()}`);
1422
+ markInteractiveElicitationStart();
1423
+ markToolStart(elicId, "ask_user_questions");
1424
+ try {
1425
+ const interviewResult = await showInterviewRound(
1426
+ questions,
1427
+ { signal, overlay: true },
1428
+ { ui } as any,
1429
+ ).catch(() => undefined);
1430
+ if (interviewResult === undefined) {
1431
+ // `await` so the dialog human-wait stays inside try/finally and the
1432
+ // in-flight guard is held until the dialog resolves. Without it,
1433
+ // `finally` runs the moment the promise is created and the fallback
1434
+ // wait runs with zero in-flight tools — reintroducing the
1435
+ // self-cancel on this path (Bugbot #1c00624d).
1436
+ return await promptElicitationWithDialogs(request, questions, ui, signal);
1437
+ }
1438
+ if (Object.keys(interviewResult.answers).length === 0) {
1439
+ // A system/host teardown (compaction, session_switch, true
1440
+ // interrupt) that aborted the signal mid-wait sets `interrupted`.
1441
+ // Surface that as a non-affirmative `decline` so it is not
1442
+ // laundered into a clean user-declined `cancel` the model re-asks
1443
+ // against. A genuine user dismissal leaves `interrupted` falsy and
1444
+ // keeps the prior `cancel` semantics.
1445
+ return interviewResult.interrupted ? { action: "decline" } : { action: "cancel" };
1446
+ }
1380
1447
  return {
1381
1448
  action: "accept",
1382
1449
  content: roundResultToElicitationContent(questions, interviewResult),
1383
1450
  };
1451
+ } finally {
1452
+ markToolEnd(elicId);
1453
+ markInteractiveElicitationEnd();
1384
1454
  }
1385
-
1386
- return promptElicitationWithDialogs(request, questions, ui, signal);
1387
1455
  }
1388
1456
 
1389
1457
  const textFields = parseTextInputElicitation(request);
1390
1458
  if (textFields) {
1391
- return promptTextInputElicitation(request, textFields, ui, signal);
1459
+ const elicId = "cc-elicit-" + ((request as { id?: string | number }).id ?? `${Date.now()}-${nextElicitationSeq()}`);
1460
+ markToolStart(elicId, "secure_env_collect");
1461
+ try {
1462
+ return await promptTextInputElicitation(request, textFields, ui, signal);
1463
+ } finally {
1464
+ markToolEnd(elicId);
1465
+ }
1392
1466
  }
1393
1467
 
1394
1468
  return { action: "decline" };
@@ -1743,6 +1817,13 @@ export function buildSdkOptions(
1743
1817
  workflowServerName,
1744
1818
  workflowExplicitlyBlocked,
1745
1819
  );
1820
+ const questionToolSurface = resolveWorkflowQuestionToolSurface({
1821
+ workflowServerName,
1822
+ workflowExplicitlyBlocked,
1823
+ workflowMcpTools,
1824
+ exactWorkflowMcpTools,
1825
+ env: process.env,
1826
+ });
1746
1827
  const runUatDisallowedTools = gsdPhase === "run-uat" && workflowServerName
1747
1828
  ? [
1748
1829
  ...RUN_UAT_FORBIDDEN_TOOL_NAMES.filter((toolName) => !toolName.startsWith("mcp__")),
@@ -1756,6 +1837,7 @@ export function buildSdkOptions(
1756
1837
  const disallowedTools: string[] = [...new Set([
1757
1838
  "ToolSearch",
1758
1839
  ...(workflowMcpTools.length > 0 || exactWorkflowMcpTools.length > 0 ? ["AskUserQuestion"] : []),
1840
+ ...questionToolSurface.disallowedTools,
1759
1841
  ...runUatDisallowedTools,
1760
1842
  ...extraDisallowedTools,
1761
1843
  ])];
@@ -1824,261 +1906,6 @@ export function buildSdkOptions(
1824
1906
  };
1825
1907
  }
1826
1908
 
1827
- /** Normalise heterogeneous SDK tool-result content (string, array, or object) into a uniform `ExternalToolResultContentBlock[]`. */
1828
- function normalizeToolResultContent(content: unknown): ExternalToolResultContentBlock[] {
1829
- if (typeof content === "string") {
1830
- return [{ type: "text", text: content }];
1831
- }
1832
-
1833
- if (!Array.isArray(content)) {
1834
- if (content == null) return [{ type: "text", text: "" }];
1835
- return [{ type: "text", text: JSON.stringify(content) }];
1836
- }
1837
-
1838
- const blocks: ExternalToolResultContentBlock[] = [];
1839
-
1840
- for (const item of content) {
1841
- if (typeof item === "string") {
1842
- blocks.push({ type: "text", text: item });
1843
- continue;
1844
- }
1845
- if (!item || typeof item !== "object") {
1846
- blocks.push({ type: "text", text: String(item) });
1847
- continue;
1848
- }
1849
-
1850
- const block = item as Record<string, unknown>;
1851
- if (block.type === "text") {
1852
- blocks.push({ type: "text", text: typeof block.text === "string" ? block.text : "" });
1853
- continue;
1854
- }
1855
- if (
1856
- block.type === "image"
1857
- && typeof block.data === "string"
1858
- && typeof block.mimeType === "string"
1859
- ) {
1860
- blocks.push({ type: "image", data: block.data, mimeType: block.mimeType });
1861
- continue;
1862
- }
1863
-
1864
- blocks.push({ type: "text", text: JSON.stringify(block) });
1865
- }
1866
-
1867
- return blocks.length > 0 ? blocks : [{ type: "text", text: "" }];
1868
- }
1869
-
1870
- /**
1871
- * Extract a `details` payload from an MCP tool-result block.
1872
- *
1873
- * MCP's `CallToolResult` carries structured data in `structuredContent` — the
1874
- * protocol's supported channel for non-text payloads. Claude Code's synthetic
1875
- * user message may surface that field in one of two shapes depending on SDK
1876
- * version: as a sibling on the `mcp_tool_result` block itself, or as a
1877
- * dedicated content sub-block with `type: "structuredContent"`. Snake-case
1878
- * (`structured_content`) is accepted defensively in case a transport hop
1879
- * rewrites casing. All other shapes fall back to an empty object so callers
1880
- * can rely on `details` being present.
1881
- */
1882
- function extractStructuredDetailsFromBlock(block: Record<string, unknown>): Record<string, unknown> | undefined {
1883
- const sibling = block.structuredContent ?? (block as Record<string, unknown>).structured_content;
1884
- if (sibling && typeof sibling === "object" && !Array.isArray(sibling)) {
1885
- return sibling as Record<string, unknown>;
1886
- }
1887
-
1888
- if (Array.isArray(block.content)) {
1889
- for (const item of block.content) {
1890
- if (!item || typeof item !== "object") continue;
1891
- const sub = item as Record<string, unknown>;
1892
- if (sub.type !== "structuredContent" && sub.type !== "structured_content") continue;
1893
- const payload = sub.structuredContent ?? sub.structured_content ?? sub.data ?? sub.value;
1894
- if (payload && typeof payload === "object" && !Array.isArray(payload)) {
1895
- return payload as Record<string, unknown>;
1896
- }
1897
- }
1898
- }
1899
-
1900
- // Return undefined (not {}) when no structured payload is present, matching
1901
- // the pre-#4477 contract where `details` was nullable. An empty-object
1902
- // sentinel is truthy and breaks downstream consumers that gate on
1903
- // `if (details)`. `undefined` matches the type of the field these results
1904
- // flow into (`Record<string, unknown> | undefined`).
1905
- return undefined;
1906
- }
1907
-
1908
- /**
1909
- * True for items that are MCP `structuredContent` pseudo-blocks living inside
1910
- * a tool-result `content[]` array. These blocks carry the structured payload
1911
- * (extracted separately by `extractStructuredDetailsFromBlock`) and must NOT
1912
- * leak into the visible content rendered to the user — otherwise the renderer
1913
- * stringifies the JSON pseudo-block and shows it next to the actual tool
1914
- * output. See PR #4477 review (post-fix-round).
1915
- */
1916
- function isStructuredContentPseudoBlock(item: unknown): boolean {
1917
- if (!item || typeof item !== "object") return false;
1918
- const type = (item as Record<string, unknown>).type;
1919
- return type === "structuredContent" || type === "structured_content";
1920
- }
1921
-
1922
- /**
1923
- * Strip `structuredContent` pseudo-blocks from a tool-result content array
1924
- * before normalization. The structured payload is extracted via the sibling
1925
- * `structuredContent` field (or a dedicated extractor pass on the raw block);
1926
- * the visible content path must not include the pseudo-block itself.
1927
- */
1928
- function stripStructuredContentPseudoBlocks(content: unknown): unknown {
1929
- if (!Array.isArray(content)) return content;
1930
- return content.filter((item) => !isStructuredContentPseudoBlock(item));
1931
- }
1932
-
1933
- /** Extract tool result payloads from an SDK synthetic user message, keyed by tool-use ID. */
1934
- export function extractToolResultsFromSdkUserMessage(message: SDKUserMessage): Array<{
1935
- toolUseId: string;
1936
- result: ExternalToolResultPayload;
1937
- }> {
1938
- const extracted: Array<{ toolUseId: string; result: ExternalToolResultPayload }> = [];
1939
- const seen = new Set<string>();
1940
- const rawMessage = message.message as Record<string, unknown> | null | undefined;
1941
- const content = Array.isArray(rawMessage?.content) ? rawMessage.content : [];
1942
-
1943
- for (const item of content) {
1944
- if (!item || typeof item !== "object") continue;
1945
- const block = item as Record<string, unknown>;
1946
- const type = typeof block.type === "string" ? block.type : "";
1947
- if (type !== "tool_result" && type !== "mcp_tool_result") continue;
1948
-
1949
- const toolUseId = typeof block.tool_use_id === "string" ? block.tool_use_id : "";
1950
- if (!toolUseId || seen.has(toolUseId)) continue;
1951
- seen.add(toolUseId);
1952
-
1953
- extracted.push({
1954
- toolUseId,
1955
- result: {
1956
- content: normalizeToolResultContent(stripStructuredContentPseudoBlocks(block.content)),
1957
- details: extractStructuredDetailsFromBlock(block),
1958
- isError: block.is_error === true,
1959
- },
1960
- });
1961
- }
1962
-
1963
- if (extracted.length === 0) {
1964
- const fallback = message.tool_use_result;
1965
- if (fallback && typeof fallback === "object") {
1966
- const toolResult = fallback as Record<string, unknown>;
1967
- const toolUseId = typeof toolResult.tool_use_id === "string" ? toolResult.tool_use_id : "";
1968
- if (toolUseId) {
1969
- extracted.push({
1970
- toolUseId,
1971
- result: {
1972
- content: normalizeToolResultContent(stripStructuredContentPseudoBlocks(toolResult.content)),
1973
- details: extractStructuredDetailsFromBlock(toolResult),
1974
- isError: toolResult.is_error === true,
1975
- },
1976
- });
1977
- }
1978
- }
1979
- }
1980
-
1981
- return extracted;
1982
- }
1983
-
1984
- /** Attach external tool results from the SDK synthetic user message to their corresponding tool-call blocks by ID. */
1985
- function attachExternalResultsToToolBlocks(
1986
- toolBlocks: AssistantMessage["content"],
1987
- toolResultsById: ReadonlyMap<string, ExternalToolResultPayload>,
1988
- ): void {
1989
- for (const block of toolBlocks) {
1990
- if (block.type !== "toolCall" && block.type !== "serverToolUse") continue;
1991
- const externalResult = toolResultsById.get(block.id);
1992
- if (!externalResult) continue;
1993
- (block as ToolCallWithExternalResult & { id: string }).externalResult = externalResult;
1994
- }
1995
- }
1996
-
1997
- /**
1998
- * Build the final assistant content that Agent Core consumes in
1999
- * `externalToolExecution` mode. This preserves tool-call blocks, attaches any
2000
- * SDK-produced external results by tool-call id, and then appends the final
2001
- * text/thinking blocks for the completed turn.
2002
- */
2003
- export function buildFinalAssistantContent(params: {
2004
- intermediateToolBlocks: AssistantMessage["content"];
2005
- pendingContent?: AssistantMessage["content"];
2006
- toolResultsById: ReadonlyMap<string, ExternalToolResultPayload>;
2007
- lastThinkingContent?: string;
2008
- lastTextContent?: string;
2009
- fallbackResultText?: string;
2010
- }): AssistantMessage["content"] {
2011
- const mergedToolBlocks = [...params.intermediateToolBlocks];
2012
- if (params.pendingContent) {
2013
- mergePendingToolCalls(mergedToolBlocks, params.pendingContent);
2014
- }
2015
- attachExternalResultsToToolBlocks(mergedToolBlocks, params.toolResultsById);
2016
-
2017
- const finalContent: AssistantMessage["content"] = [...mergedToolBlocks];
2018
- if (params.pendingContent && params.pendingContent.length > 0) {
2019
- for (const block of params.pendingContent) {
2020
- if (block.type === "text" || block.type === "thinking") {
2021
- finalContent.push(block);
2022
- }
2023
- }
2024
- } else {
2025
- if (params.lastThinkingContent) {
2026
- finalContent.push({ type: "thinking", thinking: params.lastThinkingContent });
2027
- }
2028
- if (params.lastTextContent) {
2029
- finalContent.push({ type: "text", text: params.lastTextContent });
2030
- }
2031
- }
2032
-
2033
- if (finalContent.length === 0 && params.fallbackResultText) {
2034
- finalContent.push({ type: "text", text: params.fallbackResultText });
2035
- }
2036
-
2037
- return finalContent;
2038
- }
2039
-
2040
- /**
2041
- * Merge tool-call blocks from the active partial-message builder into the
2042
- * running list of intermediate tool calls, preserving order and de-duping
2043
- * by tool-call id. Exposed for testing the F3 fix (final-turn tool calls
2044
- * dropped when `result` arrives without a preceding synthetic `user`).
2045
- */
2046
- export function mergePendingToolCalls(
2047
- intermediate: AssistantMessage["content"],
2048
- pending: AssistantMessage["content"],
2049
- ): AssistantMessage["content"] {
2050
- const alreadyIncluded = new Set<string>();
2051
- for (const block of intermediate) {
2052
- if (block.type === "toolCall") alreadyIncluded.add(block.id);
2053
- }
2054
- for (const block of pending) {
2055
- if (block.type !== "toolCall") continue;
2056
- if (alreadyIncluded.has(block.id)) continue;
2057
- alreadyIncluded.add(block.id);
2058
- intermediate.push(block);
2059
- }
2060
- return intermediate;
2061
- }
2062
-
2063
- export function handleClaudeCodePartialStreamEvent(
2064
- builder: PartialMessageBuilder | null,
2065
- event: BetaRawMessageStreamEvent,
2066
- modelId: string,
2067
- ): { builder: PartialMessageBuilder | null; assistantEvent: AssistantMessageEvent | null } {
2068
- if (event.type === "message_start") {
2069
- // Claude Code can emit repeated SDK message_start events inside one
2070
- // logical assistant response. Keep appending until a synthetic user
2071
- // tool-result boundary explicitly clears the builder.
2072
- return {
2073
- builder: builder ?? new PartialMessageBuilder((event as any).message?.model ?? modelId),
2074
- assistantEvent: null,
2075
- };
2076
- }
2077
-
2078
- if (!builder) return { builder, assistantEvent: null };
2079
- return { builder, assistantEvent: builder.handleEvent(event) };
2080
- }
2081
-
2082
1909
  // ---------------------------------------------------------------------------
2083
1910
  // streamSimple implementation
2084
1911
  // ---------------------------------------------------------------------------