gsd-pi 2.74.0-dev.b741afb → 2.74.0-dev.ffbcc03

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 (403) hide show
  1. package/dist/resources/extensions/gsd/activity-log.js +16 -0
  2. package/dist/resources/extensions/gsd/auto/loop.js +147 -10
  3. package/dist/resources/extensions/gsd/auto/phases.js +113 -3
  4. package/dist/resources/extensions/gsd/auto/session.js +10 -0
  5. package/dist/resources/extensions/gsd/auto-dispatch.js +11 -1
  6. package/dist/resources/extensions/gsd/auto-model-selection.js +51 -5
  7. package/dist/resources/extensions/gsd/auto-post-unit.js +215 -8
  8. package/dist/resources/extensions/gsd/auto-recovery.js +24 -10
  9. package/dist/resources/extensions/gsd/auto-unit-closeout.js +18 -0
  10. package/dist/resources/extensions/gsd/auto-verification.js +100 -2
  11. package/dist/resources/extensions/gsd/auto.js +28 -2
  12. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +10 -1
  13. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +61 -9
  14. package/dist/resources/extensions/gsd/cache.js +16 -5
  15. package/dist/resources/extensions/gsd/commands/handlers/ops.js +5 -0
  16. package/dist/resources/extensions/gsd/commands-extract-learnings.js +225 -0
  17. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +1 -1
  18. package/dist/resources/extensions/gsd/docs/preferences-reference.md +14 -1
  19. package/dist/resources/extensions/gsd/ecosystem/gsd-extension-api.js +144 -0
  20. package/dist/resources/extensions/gsd/ecosystem/loader.js +145 -0
  21. package/dist/resources/extensions/gsd/git-service.js +49 -1
  22. package/dist/resources/extensions/gsd/graph-context.js +98 -7
  23. package/dist/resources/extensions/gsd/gsd-db.js +260 -2
  24. package/dist/resources/extensions/gsd/guided-flow.js +24 -1
  25. package/dist/resources/extensions/gsd/init-wizard.js +1 -0
  26. package/dist/resources/extensions/gsd/journal.js +27 -0
  27. package/dist/resources/extensions/gsd/metrics.js +19 -0
  28. package/dist/resources/extensions/gsd/parallel-orchestrator.js +33 -1
  29. package/dist/resources/extensions/gsd/preferences-models.js +20 -3
  30. package/dist/resources/extensions/gsd/preferences-types.js +1 -0
  31. package/dist/resources/extensions/gsd/preferences-validation.js +108 -2
  32. package/dist/resources/extensions/gsd/preferences.js +26 -0
  33. package/dist/resources/extensions/gsd/safety/evidence-collector.js +15 -30
  34. package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +12 -2
  35. package/dist/resources/extensions/gsd/templates/PREFERENCES.md +18 -0
  36. package/dist/resources/extensions/gsd/tools/complete-slice.js +5 -0
  37. package/dist/resources/extensions/gsd/tools/validate-milestone.js +39 -4
  38. package/dist/resources/extensions/gsd/unit-ownership.js +1 -1
  39. package/dist/resources/extensions/gsd/uok/audit-toggle.js +7 -0
  40. package/dist/resources/extensions/gsd/uok/audit.js +40 -0
  41. package/dist/resources/extensions/gsd/uok/contracts.js +1 -0
  42. package/dist/resources/extensions/gsd/uok/execution-graph.js +179 -0
  43. package/dist/resources/extensions/gsd/uok/flags.js +29 -0
  44. package/dist/resources/extensions/gsd/uok/gate-runner.js +109 -0
  45. package/dist/resources/extensions/gsd/uok/gitops.js +53 -0
  46. package/dist/resources/extensions/gsd/uok/kernel.js +80 -0
  47. package/dist/resources/extensions/gsd/uok/loop-adapter.js +133 -0
  48. package/dist/resources/extensions/gsd/uok/model-policy.js +66 -0
  49. package/dist/resources/extensions/gsd/uok/plan-v2.js +132 -0
  50. package/dist/resources/extensions/gsd/workflow-logger.js +22 -0
  51. package/dist/resources/extensions/ttsr/ttsr-manager.js +3 -1
  52. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  53. package/dist/web/standalone/.next/BUILD_ID +1 -1
  54. package/dist/web/standalone/.next/app-path-routes-manifest.json +9 -9
  55. package/dist/web/standalone/.next/build-manifest.json +2 -2
  56. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  57. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  58. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  59. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  60. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  61. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  62. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  63. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  64. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  65. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  66. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  67. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  68. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  69. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  70. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  71. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  72. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  73. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  74. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +1 -1
  75. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +1 -1
  76. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +1 -1
  77. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +1 -1
  78. package/dist/web/standalone/.next/server/app/index.html +1 -1
  79. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  80. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  81. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  82. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  83. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  84. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  85. package/dist/web/standalone/.next/server/app-paths-manifest.json +9 -9
  86. package/dist/web/standalone/.next/server/chunks/6897.js +3 -3
  87. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  88. package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
  89. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  90. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  91. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  92. package/package.json +1 -1
  93. package/packages/mcp-server/dist/readers/graph.d.ts +1 -1
  94. package/packages/mcp-server/dist/readers/graph.d.ts.map +1 -1
  95. package/packages/mcp-server/dist/readers/graph.js +107 -0
  96. package/packages/mcp-server/dist/readers/graph.js.map +1 -1
  97. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  98. package/packages/mcp-server/dist/workflow-tools.js +88 -6
  99. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  100. package/packages/mcp-server/src/readers/graph.test.ts +178 -0
  101. package/packages/mcp-server/src/readers/graph.ts +148 -1
  102. package/packages/mcp-server/src/workflow-tools.ts +95 -10
  103. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
  104. package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
  105. package/packages/pi-ai/dist/index.d.ts +1 -9
  106. package/packages/pi-ai/dist/index.d.ts.map +1 -1
  107. package/packages/pi-ai/dist/index.js +1 -9
  108. package/packages/pi-ai/dist/index.js.map +1 -1
  109. package/packages/pi-ai/dist/models/capability-patches.d.ts +19 -0
  110. package/packages/pi-ai/dist/models/capability-patches.d.ts.map +1 -0
  111. package/packages/pi-ai/dist/models/capability-patches.js +36 -0
  112. package/packages/pi-ai/dist/models/capability-patches.js.map +1 -0
  113. package/packages/pi-ai/dist/{models.custom.d.ts → models/custom.d.ts} +1 -1
  114. package/packages/pi-ai/dist/models/custom.d.ts.map +1 -0
  115. package/packages/pi-ai/dist/{models.custom.js → models/custom.js} +4 -4
  116. package/packages/pi-ai/dist/models/custom.js.map +1 -0
  117. package/packages/pi-ai/dist/models/generated/amazon-bedrock.d.ts +1482 -0
  118. package/packages/pi-ai/dist/models/generated/amazon-bedrock.d.ts.map +1 -0
  119. package/packages/pi-ai/dist/models/generated/amazon-bedrock.js +1484 -0
  120. package/packages/pi-ai/dist/models/generated/amazon-bedrock.js.map +1 -0
  121. package/packages/pi-ai/dist/models/generated/anthropic.d.ts +377 -0
  122. package/packages/pi-ai/dist/models/generated/anthropic.d.ts.map +1 -0
  123. package/packages/pi-ai/dist/models/generated/anthropic.js +379 -0
  124. package/packages/pi-ai/dist/models/generated/anthropic.js.map +1 -0
  125. package/packages/pi-ai/dist/models/generated/azure-openai-responses.d.ts +700 -0
  126. package/packages/pi-ai/dist/models/generated/azure-openai-responses.d.ts.map +1 -0
  127. package/packages/pi-ai/dist/models/generated/azure-openai-responses.js +702 -0
  128. package/packages/pi-ai/dist/models/generated/azure-openai-responses.js.map +1 -0
  129. package/packages/pi-ai/dist/models/generated/cerebras.d.ts +71 -0
  130. package/packages/pi-ai/dist/models/generated/cerebras.d.ts.map +1 -0
  131. package/packages/pi-ai/dist/models/generated/cerebras.js +73 -0
  132. package/packages/pi-ai/dist/models/generated/cerebras.js.map +1 -0
  133. package/packages/pi-ai/dist/models/generated/github-copilot.d.ts +590 -0
  134. package/packages/pi-ai/dist/models/generated/github-copilot.d.ts.map +1 -0
  135. package/packages/pi-ai/dist/models/generated/github-copilot.js +444 -0
  136. package/packages/pi-ai/dist/models/generated/github-copilot.js.map +1 -0
  137. package/packages/pi-ai/dist/models/generated/google-antigravity.d.ts +156 -0
  138. package/packages/pi-ai/dist/models/generated/google-antigravity.d.ts.map +1 -0
  139. package/packages/pi-ai/dist/models/generated/google-antigravity.js +158 -0
  140. package/packages/pi-ai/dist/models/generated/google-antigravity.js.map +1 -0
  141. package/packages/pi-ai/dist/models/generated/google-gemini-cli.d.ts +105 -0
  142. package/packages/pi-ai/dist/models/generated/google-gemini-cli.d.ts.map +1 -0
  143. package/packages/pi-ai/dist/models/generated/google-gemini-cli.js +107 -0
  144. package/packages/pi-ai/dist/models/generated/google-gemini-cli.js.map +1 -0
  145. package/packages/pi-ai/dist/models/generated/google-vertex.d.ts +207 -0
  146. package/packages/pi-ai/dist/models/generated/google-vertex.d.ts.map +1 -0
  147. package/packages/pi-ai/dist/models/generated/google-vertex.js +209 -0
  148. package/packages/pi-ai/dist/models/generated/google-vertex.js.map +1 -0
  149. package/packages/pi-ai/dist/models/generated/google.d.ts +462 -0
  150. package/packages/pi-ai/dist/models/generated/google.d.ts.map +1 -0
  151. package/packages/pi-ai/dist/models/generated/google.js +464 -0
  152. package/packages/pi-ai/dist/models/generated/google.js.map +1 -0
  153. package/packages/pi-ai/dist/models/generated/groq.d.ts +309 -0
  154. package/packages/pi-ai/dist/models/generated/groq.d.ts.map +1 -0
  155. package/packages/pi-ai/dist/models/generated/groq.js +311 -0
  156. package/packages/pi-ai/dist/models/generated/groq.js.map +1 -0
  157. package/packages/pi-ai/dist/models/generated/huggingface.d.ts +383 -0
  158. package/packages/pi-ai/dist/models/generated/huggingface.d.ts.map +1 -0
  159. package/packages/pi-ai/dist/models/generated/huggingface.js +347 -0
  160. package/packages/pi-ai/dist/models/generated/huggingface.js.map +1 -0
  161. package/packages/pi-ai/dist/{models.generated.d.ts → models/generated/index.d.ts} +1 -1
  162. package/packages/pi-ai/dist/{models.generated.d.ts.map → models/generated/index.d.ts.map} +1 -1
  163. package/packages/pi-ai/dist/models/generated/index.js +51 -0
  164. package/packages/pi-ai/dist/models/generated/index.js.map +1 -0
  165. package/packages/pi-ai/dist/models/generated/kimi-coding.d.ts +37 -0
  166. package/packages/pi-ai/dist/models/generated/kimi-coding.d.ts.map +1 -0
  167. package/packages/pi-ai/dist/models/generated/kimi-coding.js +39 -0
  168. package/packages/pi-ai/dist/models/generated/kimi-coding.js.map +1 -0
  169. package/packages/pi-ai/dist/models/generated/minimax-cn.d.ts +105 -0
  170. package/packages/pi-ai/dist/models/generated/minimax-cn.d.ts.map +1 -0
  171. package/packages/pi-ai/dist/models/generated/minimax-cn.js +107 -0
  172. package/packages/pi-ai/dist/models/generated/minimax-cn.js.map +1 -0
  173. package/packages/pi-ai/dist/models/generated/minimax.d.ts +105 -0
  174. package/packages/pi-ai/dist/models/generated/minimax.d.ts.map +1 -0
  175. package/packages/pi-ai/dist/models/generated/minimax.js +107 -0
  176. package/packages/pi-ai/dist/models/generated/minimax.js.map +1 -0
  177. package/packages/pi-ai/dist/models/generated/mistral.d.ts +445 -0
  178. package/packages/pi-ai/dist/models/generated/mistral.d.ts.map +1 -0
  179. package/packages/pi-ai/dist/models/generated/mistral.js +447 -0
  180. package/packages/pi-ai/dist/models/generated/mistral.js.map +1 -0
  181. package/packages/pi-ai/dist/models/generated/openai-codex.d.ts +139 -0
  182. package/packages/pi-ai/dist/models/generated/openai-codex.d.ts.map +1 -0
  183. package/packages/pi-ai/dist/models/generated/openai-codex.js +141 -0
  184. package/packages/pi-ai/dist/models/generated/openai-codex.js.map +1 -0
  185. package/packages/pi-ai/dist/models/generated/openai.d.ts +700 -0
  186. package/packages/pi-ai/dist/models/generated/openai.d.ts.map +1 -0
  187. package/packages/pi-ai/dist/models/generated/openai.js +702 -0
  188. package/packages/pi-ai/dist/models/generated/openai.js.map +1 -0
  189. package/packages/pi-ai/dist/models/generated/opencode-go.d.ts +122 -0
  190. package/packages/pi-ai/dist/models/generated/opencode-go.d.ts.map +1 -0
  191. package/packages/pi-ai/dist/models/generated/opencode-go.js +124 -0
  192. package/packages/pi-ai/dist/models/generated/opencode-go.js.map +1 -0
  193. package/packages/pi-ai/dist/models/generated/opencode.d.ts +530 -0
  194. package/packages/pi-ai/dist/models/generated/opencode.d.ts.map +1 -0
  195. package/packages/pi-ai/dist/models/generated/opencode.js +532 -0
  196. package/packages/pi-ai/dist/models/generated/opencode.js.map +1 -0
  197. package/packages/pi-ai/dist/models/generated/openrouter.d.ts +4270 -0
  198. package/packages/pi-ai/dist/models/generated/openrouter.d.ts.map +1 -0
  199. package/packages/pi-ai/dist/models/generated/openrouter.js +4272 -0
  200. package/packages/pi-ai/dist/models/generated/openrouter.js.map +1 -0
  201. package/packages/pi-ai/dist/models/generated/vercel-ai-gateway.d.ts +2604 -0
  202. package/packages/pi-ai/dist/models/generated/vercel-ai-gateway.d.ts.map +1 -0
  203. package/packages/pi-ai/dist/models/generated/vercel-ai-gateway.js +2606 -0
  204. package/packages/pi-ai/dist/models/generated/vercel-ai-gateway.js.map +1 -0
  205. package/packages/pi-ai/dist/models/generated/xai.d.ts +411 -0
  206. package/packages/pi-ai/dist/models/generated/xai.d.ts.map +1 -0
  207. package/packages/pi-ai/dist/models/generated/xai.js +413 -0
  208. package/packages/pi-ai/dist/models/generated/xai.js.map +1 -0
  209. package/packages/pi-ai/dist/models/generated/zai.d.ts +276 -0
  210. package/packages/pi-ai/dist/models/generated/zai.d.ts.map +1 -0
  211. package/packages/pi-ai/dist/models/generated/zai.js +239 -0
  212. package/packages/pi-ai/dist/models/generated/zai.js.map +1 -0
  213. package/packages/pi-ai/dist/models/index.d.ts +27 -0
  214. package/packages/pi-ai/dist/models/index.d.ts.map +1 -0
  215. package/packages/pi-ai/dist/models/index.js +80 -0
  216. package/packages/pi-ai/dist/models/index.js.map +1 -0
  217. package/packages/pi-ai/dist/models.d.ts +1 -36
  218. package/packages/pi-ai/dist/models.d.ts.map +1 -1
  219. package/packages/pi-ai/dist/models.generated.test.js +1 -2
  220. package/packages/pi-ai/dist/models.generated.test.js.map +1 -1
  221. package/packages/pi-ai/dist/models.js +3 -112
  222. package/packages/pi-ai/dist/models.js.map +1 -1
  223. package/packages/pi-ai/dist/models.test.js +6 -5
  224. package/packages/pi-ai/dist/models.test.js.map +1 -1
  225. package/packages/pi-ai/scripts/generate-models.ts +74 -40
  226. package/packages/pi-ai/src/index.ts +1 -9
  227. package/packages/pi-ai/src/models/capability-patches.ts +40 -0
  228. package/packages/pi-ai/src/{models.custom.ts → models/custom.ts} +4 -4
  229. package/packages/pi-ai/src/models/generated/amazon-bedrock.ts +1486 -0
  230. package/packages/pi-ai/src/models/generated/anthropic.ts +381 -0
  231. package/packages/pi-ai/src/models/generated/azure-openai-responses.ts +704 -0
  232. package/packages/pi-ai/src/models/generated/cerebras.ts +75 -0
  233. package/packages/pi-ai/src/models/generated/github-copilot.ts +446 -0
  234. package/packages/pi-ai/src/models/generated/google-antigravity.ts +160 -0
  235. package/packages/pi-ai/src/models/generated/google-gemini-cli.ts +109 -0
  236. package/packages/pi-ai/src/models/generated/google-vertex.ts +211 -0
  237. package/packages/pi-ai/src/models/generated/google.ts +466 -0
  238. package/packages/pi-ai/src/models/generated/groq.ts +313 -0
  239. package/packages/pi-ai/src/models/generated/huggingface.ts +349 -0
  240. package/packages/pi-ai/src/models/generated/index.ts +52 -0
  241. package/packages/pi-ai/src/models/generated/kimi-coding.ts +41 -0
  242. package/packages/pi-ai/src/models/generated/minimax-cn.ts +109 -0
  243. package/packages/pi-ai/src/models/generated/minimax.ts +109 -0
  244. package/packages/pi-ai/src/models/generated/mistral.ts +449 -0
  245. package/packages/pi-ai/src/models/generated/openai-codex.ts +143 -0
  246. package/packages/pi-ai/src/models/generated/openai.ts +704 -0
  247. package/packages/pi-ai/src/models/generated/opencode-go.ts +126 -0
  248. package/packages/pi-ai/src/models/generated/opencode.ts +534 -0
  249. package/packages/pi-ai/src/models/generated/openrouter.ts +4274 -0
  250. package/packages/pi-ai/src/models/generated/vercel-ai-gateway.ts +2608 -0
  251. package/packages/pi-ai/src/models/generated/xai.ts +415 -0
  252. package/packages/pi-ai/src/models/generated/zai.ts +241 -0
  253. package/packages/pi-ai/src/models/index.ts +106 -0
  254. package/packages/pi-ai/src/models.generated.test.ts +1 -2
  255. package/packages/pi-ai/src/models.test.ts +6 -5
  256. package/packages/pi-ai/src/models.ts +3 -153
  257. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  258. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  259. package/packages/pi-coding-agent/dist/core/agent-session.js +8 -2
  260. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  261. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +472 -0
  262. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
  263. package/packages/pi-coding-agent/dist/core/model-registry-env-fallback.test.d.ts +2 -0
  264. package/packages/pi-coding-agent/dist/core/model-registry-env-fallback.test.d.ts.map +1 -0
  265. package/packages/pi-coding-agent/dist/core/model-registry-env-fallback.test.js +52 -0
  266. package/packages/pi-coding-agent/dist/core/model-registry-env-fallback.test.js.map +1 -0
  267. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  268. package/packages/pi-coding-agent/dist/core/model-registry.js +2 -2
  269. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  270. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +11 -0
  271. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -1
  272. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts +1 -0
  273. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  274. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js +23 -9
  275. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
  276. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts +11 -0
  277. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts.map +1 -0
  278. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js +47 -0
  279. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js.map +1 -0
  280. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +8 -0
  281. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  282. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +68 -8
  283. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  284. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  285. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js +22 -22
  286. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js.map +1 -1
  287. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  288. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +232 -18
  289. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  290. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-ordering.test.d.ts +2 -0
  291. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-ordering.test.d.ts.map +1 -0
  292. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-ordering.test.js +38 -0
  293. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-ordering.test.js.map +1 -0
  294. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +14 -0
  295. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  296. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +70 -6
  297. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  298. package/packages/pi-coding-agent/src/core/agent-session.ts +12 -6
  299. package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +612 -0
  300. package/packages/pi-coding-agent/src/core/model-registry-env-fallback.test.ts +59 -0
  301. package/packages/pi-coding-agent/src/core/model-registry.ts +2 -1
  302. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +19 -0
  303. package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +25 -10
  304. package/packages/pi-coding-agent/src/modes/interactive/components/chat-frame.ts +67 -0
  305. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +83 -7
  306. package/packages/pi-coding-agent/src/modes/interactive/components/user-message.ts +23 -26
  307. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +298 -41
  308. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-ordering.test.ts +44 -0
  309. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +92 -6
  310. package/packages/pi-coding-agent/src/types/ambient-modules.d.ts +69 -0
  311. package/packages/pi-coding-agent/tsconfig.json +2 -2
  312. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  313. package/src/resources/extensions/gsd/activity-log.ts +21 -0
  314. package/src/resources/extensions/gsd/auto/loop-deps.ts +4 -0
  315. package/src/resources/extensions/gsd/auto/loop.ts +159 -10
  316. package/src/resources/extensions/gsd/auto/phases.ts +123 -3
  317. package/src/resources/extensions/gsd/auto/session.ts +10 -0
  318. package/src/resources/extensions/gsd/auto-dispatch.ts +16 -6
  319. package/src/resources/extensions/gsd/auto-model-selection.ts +66 -5
  320. package/src/resources/extensions/gsd/auto-post-unit.ts +226 -9
  321. package/src/resources/extensions/gsd/auto-recovery.ts +29 -9
  322. package/src/resources/extensions/gsd/auto-unit-closeout.ts +25 -1
  323. package/src/resources/extensions/gsd/auto-verification.ts +129 -2
  324. package/src/resources/extensions/gsd/auto.ts +34 -2
  325. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +15 -1
  326. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +72 -8
  327. package/src/resources/extensions/gsd/cache.ts +16 -5
  328. package/src/resources/extensions/gsd/commands/handlers/ops.ts +5 -0
  329. package/src/resources/extensions/gsd/commands-extract-learnings.ts +304 -0
  330. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +1 -1
  331. package/src/resources/extensions/gsd/docs/preferences-reference.md +14 -1
  332. package/src/resources/extensions/gsd/ecosystem/gsd-extension-api.ts +228 -0
  333. package/src/resources/extensions/gsd/ecosystem/loader.ts +201 -0
  334. package/src/resources/extensions/gsd/git-service.ts +68 -0
  335. package/src/resources/extensions/gsd/graph-context.ts +139 -12
  336. package/src/resources/extensions/gsd/gsd-db.ts +321 -3
  337. package/src/resources/extensions/gsd/guided-flow.ts +33 -1
  338. package/src/resources/extensions/gsd/init-wizard.ts +3 -2
  339. package/src/resources/extensions/gsd/journal.ts +30 -0
  340. package/src/resources/extensions/gsd/metrics.ts +26 -0
  341. package/src/resources/extensions/gsd/parallel-orchestrator.ts +40 -1
  342. package/src/resources/extensions/gsd/preferences-models.ts +20 -3
  343. package/src/resources/extensions/gsd/preferences-types.ts +32 -0
  344. package/src/resources/extensions/gsd/preferences-validation.ts +107 -2
  345. package/src/resources/extensions/gsd/preferences.ts +28 -0
  346. package/src/resources/extensions/gsd/safety/evidence-collector.ts +15 -31
  347. package/src/resources/extensions/gsd/session-lock.ts +14 -2
  348. package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +20 -1
  349. package/src/resources/extensions/gsd/templates/PREFERENCES.md +18 -0
  350. package/src/resources/extensions/gsd/tests/artifacts-table-preserved-on-cache-invalidate.test.ts +177 -0
  351. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +7 -3
  352. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +20 -0
  353. package/src/resources/extensions/gsd/tests/auto-project-root-env.test.ts +7 -3
  354. package/src/resources/extensions/gsd/tests/auto-retry-mcp-churn-fixes.test.ts +272 -0
  355. package/src/resources/extensions/gsd/tests/cold-resume-db-reopen.test.ts +6 -2
  356. package/src/resources/extensions/gsd/tests/commands-extract-learnings.test.ts +340 -0
  357. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +2 -2
  358. package/src/resources/extensions/gsd/tests/complete-task.test.ts +2 -2
  359. package/src/resources/extensions/gsd/tests/finalize-timeout-guard.test.ts +10 -7
  360. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +1 -1
  361. package/src/resources/extensions/gsd/tests/health-widget.test.ts +1 -1
  362. package/src/resources/extensions/gsd/tests/md-importer.test.ts +1 -2
  363. package/src/resources/extensions/gsd/tests/memory-store.test.ts +2 -3
  364. package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +79 -1
  365. package/src/resources/extensions/gsd/tests/post-unit-state-rebuild.test.ts +2 -1
  366. package/src/resources/extensions/gsd/tests/pre-execution-pause-wiring.test.ts +40 -1
  367. package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +1 -1
  368. package/src/resources/extensions/gsd/tests/token-profile.test.ts +8 -5
  369. package/src/resources/extensions/gsd/tests/uok-audit-unified.test.ts +101 -0
  370. package/src/resources/extensions/gsd/tests/uok-contracts.test.ts +85 -0
  371. package/src/resources/extensions/gsd/tests/uok-execution-graph.test.ts +69 -0
  372. package/src/resources/extensions/gsd/tests/uok-flags.test.ts +39 -0
  373. package/src/resources/extensions/gsd/tests/uok-gate-runner.test.ts +70 -0
  374. package/src/resources/extensions/gsd/tests/uok-gitops-turn-action.test.ts +85 -0
  375. package/src/resources/extensions/gsd/tests/uok-gitops-wiring.test.ts +35 -0
  376. package/src/resources/extensions/gsd/tests/uok-model-policy.test.ts +89 -0
  377. package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +167 -0
  378. package/src/resources/extensions/gsd/tests/uok-preferences.test.ts +42 -0
  379. package/src/resources/extensions/gsd/tests/validate-milestone-write-order.test.ts +39 -0
  380. package/src/resources/extensions/gsd/tools/complete-slice.ts +9 -2
  381. package/src/resources/extensions/gsd/tools/validate-milestone.ts +48 -3
  382. package/src/resources/extensions/gsd/types.ts +14 -1
  383. package/src/resources/extensions/gsd/unit-ownership.ts +2 -2
  384. package/src/resources/extensions/gsd/uok/audit-toggle.ts +9 -0
  385. package/src/resources/extensions/gsd/uok/audit.ts +51 -0
  386. package/src/resources/extensions/gsd/uok/contracts.ts +135 -0
  387. package/src/resources/extensions/gsd/uok/execution-graph.ts +241 -0
  388. package/src/resources/extensions/gsd/uok/flags.ts +45 -0
  389. package/src/resources/extensions/gsd/uok/gate-runner.ts +146 -0
  390. package/src/resources/extensions/gsd/uok/gitops.ts +75 -0
  391. package/src/resources/extensions/gsd/uok/kernel.ts +105 -0
  392. package/src/resources/extensions/gsd/uok/loop-adapter.ts +162 -0
  393. package/src/resources/extensions/gsd/uok/model-policy.ts +112 -0
  394. package/src/resources/extensions/gsd/uok/plan-v2.ts +156 -0
  395. package/src/resources/extensions/gsd/workflow-logger.ts +27 -1
  396. package/src/resources/extensions/ttsr/ttsr-manager.ts +10 -5
  397. package/packages/pi-ai/dist/models.custom.d.ts.map +0 -1
  398. package/packages/pi-ai/dist/models.custom.js.map +0 -1
  399. package/packages/pi-ai/dist/models.generated.js +0 -14343
  400. package/packages/pi-ai/dist/models.generated.js.map +0 -1
  401. package/packages/pi-ai/src/models.generated.ts +0 -14345
  402. /package/dist/web/standalone/.next/static/{XnHY5eXUsTCFmNodWHetD → kn6xzWKYnogsxp2b6RpDD}/_buildManifest.js +0 -0
  403. /package/dist/web/standalone/.next/static/{XnHY5eXUsTCFmNodWHetD → kn6xzWKYnogsxp2b6RpDD}/_ssgManifest.js +0 -0
@@ -199,6 +199,427 @@ test("chat-controller renders serverToolUse before trailing text matching conten
199
199
  assert.equal(host.chatContainer.children[0]?.constructor?.name, "ToolExecutionComponent");
200
200
  assert.equal(host.chatContainer.children[1]?.constructor?.name, "AssistantMessageComponent");
201
201
  });
202
+ test("chat-controller replays final message_end content when result adds unstreamed trailing text", async () => {
203
+ globalThis[Symbol.for("@gsd/pi-coding-agent:theme")] = {
204
+ fg: (_key, text) => text,
205
+ bg: (_key, text) => text,
206
+ bold: (text) => text,
207
+ italic: (text) => text,
208
+ truncate: (text) => text,
209
+ };
210
+ const host = createHost();
211
+ host.getMarkdownThemeWithSettings = () => ({});
212
+ const tool = {
213
+ type: "toolCall",
214
+ id: "mcp-end-replay-1",
215
+ name: "read",
216
+ mcpServer: "filesystem",
217
+ arguments: { filePath: "/tmp/demo.txt" },
218
+ };
219
+ await handleAgentEvent(host, { type: "message_start", message: makeAssistant([]) });
220
+ const streamedContent = [
221
+ tool,
222
+ { type: "thinking", thinking: "I am analyzing tool output..." },
223
+ ];
224
+ await handleAgentEvent(host, {
225
+ type: "message_update",
226
+ message: makeAssistant(streamedContent),
227
+ assistantMessageEvent: {
228
+ type: "thinking_delta",
229
+ contentIndex: 1,
230
+ delta: "I am analyzing tool output...",
231
+ partial: makeAssistant(streamedContent),
232
+ },
233
+ });
234
+ assert.equal(host.chatContainer.children.length, 2, "streaming shows tool + thinking only");
235
+ assert.equal(host.chatContainer.children[0]?.constructor?.name, "ToolExecutionComponent");
236
+ assert.equal(host.chatContainer.children[1]?.constructor?.name, "AssistantMessageComponent");
237
+ // Final payload includes trailing text that never arrived as message_update.
238
+ const finalContent = [
239
+ tool,
240
+ { type: "thinking", thinking: "I am analyzing tool output..." },
241
+ { type: "text", text: "Correct anything important I missed?" },
242
+ ];
243
+ await handleAgentEvent(host, { type: "message_end", message: makeAssistant(finalContent) });
244
+ assert.equal(host.chatContainer.children.length, 3, "message_end should replay and include trailing text segment");
245
+ assert.equal(host.chatContainer.children[0]?.constructor?.name, "ToolExecutionComponent");
246
+ assert.equal(host.chatContainer.children[1]?.constructor?.name, "AssistantMessageComponent");
247
+ assert.equal(host.chatContainer.children[2]?.constructor?.name, "AssistantMessageComponent");
248
+ });
249
+ test("chat-controller keeps pre-tool prose visible until post-tool prose arrives, then prunes it", async () => {
250
+ globalThis[Symbol.for("@gsd/pi-coding-agent:theme")] = {
251
+ fg: (_key, text) => text,
252
+ bg: (_key, text) => text,
253
+ bold: (text) => text,
254
+ italic: (text) => text,
255
+ truncate: (text) => text,
256
+ };
257
+ const host = createHost();
258
+ host.getMarkdownThemeWithSettings = () => ({});
259
+ const mcpTool = {
260
+ type: "toolCall",
261
+ id: "mcp-tool-1",
262
+ name: "read",
263
+ mcpServer: "filesystem",
264
+ arguments: { filePath: "/tmp/demo.txt" },
265
+ };
266
+ await handleAgentEvent(host, { type: "message_start", message: makeAssistant([]) });
267
+ // Provisional assistant text arrives first.
268
+ await handleAgentEvent(host, {
269
+ type: "message_update",
270
+ message: makeAssistant([{ type: "text", text: "Let me inspect the workspace first." }]),
271
+ assistantMessageEvent: {
272
+ type: "text_delta",
273
+ contentIndex: 0,
274
+ delta: "Let me inspect the workspace first.",
275
+ partial: makeAssistant([{ type: "text", text: "Let me inspect the workspace first." }]),
276
+ },
277
+ });
278
+ assert.equal(host.chatContainer.children.length, 1);
279
+ assert.equal(host.chatContainer.children[0]?.constructor?.name, "AssistantMessageComponent");
280
+ // MCP tool appears; provisional text should remain visible until post-tool prose exists.
281
+ await handleAgentEvent(host, {
282
+ type: "message_update",
283
+ message: makeAssistant([{ type: "text", text: "Let me inspect the workspace first." }, mcpTool]),
284
+ assistantMessageEvent: {
285
+ type: "toolcall_end",
286
+ contentIndex: 1,
287
+ toolCall: {
288
+ ...mcpTool,
289
+ externalResult: {
290
+ content: [{ type: "text", text: "file preview" }],
291
+ details: {},
292
+ isError: false,
293
+ },
294
+ },
295
+ partial: makeAssistant([{ type: "text", text: "Let me inspect the workspace first." }, mcpTool]),
296
+ },
297
+ });
298
+ assert.equal(host.chatContainer.children.length, 2, "pre-tool prose should remain during tool-only window");
299
+ assert.equal(host.chatContainer.children[0]?.constructor?.name, "AssistantMessageComponent");
300
+ assert.equal(host.chatContainer.children[1]?.constructor?.name, "ToolExecutionComponent");
301
+ // Post-tool prose arrives: pre-tool prose should now be pruned.
302
+ const finalContent = [
303
+ { type: "text", text: "Let me inspect the workspace first." },
304
+ mcpTool,
305
+ { type: "text", text: "Which missing feature matters most to you?" },
306
+ ];
307
+ await handleAgentEvent(host, {
308
+ type: "message_update",
309
+ message: makeAssistant(finalContent),
310
+ assistantMessageEvent: {
311
+ type: "text_delta",
312
+ contentIndex: 2,
313
+ delta: "Which missing feature matters most to you?",
314
+ partial: makeAssistant(finalContent),
315
+ },
316
+ });
317
+ assert.equal(host.chatContainer.children.length, 2);
318
+ assert.equal(host.chatContainer.children[0]?.constructor?.name, "ToolExecutionComponent");
319
+ assert.equal(host.chatContainer.children[1]?.constructor?.name, "AssistantMessageComponent");
320
+ // Finalize to tear down any pinned spinner state.
321
+ await handleAgentEvent(host, { type: "message_end", message: makeAssistant(finalContent) });
322
+ });
323
+ test("chat-controller keeps pre-tool thinking visible for claude-code MCP turns without post-tool prose", async () => {
324
+ globalThis[Symbol.for("@gsd/pi-coding-agent:theme")] = {
325
+ fg: (_key, text) => text,
326
+ bg: (_key, text) => text,
327
+ bold: (text) => text,
328
+ italic: (text) => text,
329
+ truncate: (text) => text,
330
+ };
331
+ const host = createHost();
332
+ host.getMarkdownThemeWithSettings = () => ({});
333
+ const mcpTool = {
334
+ type: "toolCall",
335
+ id: "mcp-tool-thinking-1",
336
+ name: "read",
337
+ mcpServer: "filesystem",
338
+ arguments: { filePath: "/tmp/demo.txt" },
339
+ };
340
+ await handleAgentEvent(host, { type: "message_start", message: makeAssistant([]) });
341
+ const thinkingOnly = [{ type: "thinking", thinking: "I should inspect the workspace." }];
342
+ await handleAgentEvent(host, {
343
+ type: "message_update",
344
+ message: makeAssistant(thinkingOnly),
345
+ assistantMessageEvent: {
346
+ type: "thinking_delta",
347
+ contentIndex: 0,
348
+ delta: "I should inspect the workspace.",
349
+ partial: makeAssistant(thinkingOnly),
350
+ },
351
+ });
352
+ assert.equal(host.chatContainer.children.length, 1);
353
+ assert.equal(host.chatContainer.children[0]?.constructor?.name, "AssistantMessageComponent");
354
+ await handleAgentEvent(host, {
355
+ type: "message_update",
356
+ message: makeAssistant([thinkingOnly[0], mcpTool]),
357
+ assistantMessageEvent: {
358
+ type: "toolcall_end",
359
+ contentIndex: 1,
360
+ toolCall: {
361
+ ...mcpTool,
362
+ externalResult: {
363
+ content: [{ type: "text", text: "file preview" }],
364
+ details: {},
365
+ isError: false,
366
+ },
367
+ },
368
+ partial: makeAssistant([thinkingOnly[0], mcpTool]),
369
+ },
370
+ });
371
+ assert.equal(host.chatContainer.children.length, 2, "thinking should remain visible while only tool output is present");
372
+ assert.equal(host.chatContainer.children[0]?.constructor?.name, "AssistantMessageComponent");
373
+ assert.equal(host.chatContainer.children[1]?.constructor?.name, "ToolExecutionComponent");
374
+ await handleAgentEvent(host, { type: "message_end", message: makeAssistant([thinkingOnly[0], mcpTool]) });
375
+ });
376
+ test("chat-controller keeps pre-tool question text for claude-code MCP when post-tool prose exists", async () => {
377
+ globalThis[Symbol.for("@gsd/pi-coding-agent:theme")] = {
378
+ fg: (_key, text) => text,
379
+ bg: (_key, text) => text,
380
+ bold: (text) => text,
381
+ italic: (text) => text,
382
+ truncate: (text) => text,
383
+ };
384
+ const host = createHost();
385
+ host.getMarkdownThemeWithSettings = () => ({});
386
+ const mcpTool = {
387
+ type: "toolCall",
388
+ id: "mcp-tool-question-1",
389
+ name: "glob",
390
+ mcpServer: "filesystem",
391
+ arguments: { pattern: "**/*" },
392
+ };
393
+ await handleAgentEvent(host, { type: "message_start", message: makeAssistant([]) });
394
+ const questionText = { type: "text", text: "Which file should I inspect?" };
395
+ await handleAgentEvent(host, {
396
+ type: "message_update",
397
+ message: makeAssistant([questionText]),
398
+ assistantMessageEvent: {
399
+ type: "text_delta",
400
+ contentIndex: 0,
401
+ delta: questionText.text,
402
+ partial: makeAssistant([questionText]),
403
+ },
404
+ });
405
+ await handleAgentEvent(host, {
406
+ type: "message_update",
407
+ message: makeAssistant([questionText, mcpTool]),
408
+ assistantMessageEvent: {
409
+ type: "toolcall_end",
410
+ contentIndex: 1,
411
+ toolCall: {
412
+ ...mcpTool,
413
+ externalResult: {
414
+ content: [{ type: "text", text: "glob output" }],
415
+ details: {},
416
+ isError: false,
417
+ },
418
+ },
419
+ partial: makeAssistant([questionText, mcpTool]),
420
+ },
421
+ });
422
+ const postTool = { type: "text", text: "I'll review that next." };
423
+ const finalContent = [questionText, mcpTool, postTool];
424
+ await handleAgentEvent(host, {
425
+ type: "message_update",
426
+ message: makeAssistant(finalContent),
427
+ assistantMessageEvent: {
428
+ type: "text_delta",
429
+ contentIndex: 2,
430
+ delta: postTool.text,
431
+ partial: makeAssistant(finalContent),
432
+ },
433
+ });
434
+ assert.equal(host.chatContainer.children.length, 3, "question text should remain alongside MCP tool and post-tool prose");
435
+ assert.equal(host.chatContainer.children[0]?.constructor?.name, "AssistantMessageComponent", "pre-tool question stays visible");
436
+ assert.equal(host.chatContainer.children[1]?.constructor?.name, "ToolExecutionComponent", "tool renders in the middle");
437
+ assert.equal(host.chatContainer.children[2]?.constructor?.name, "AssistantMessageComponent", "post-tool prose renders last");
438
+ await handleAgentEvent(host, { type: "message_end", message: makeAssistant(finalContent) });
439
+ });
440
+ test("chat-controller prunes orphaned provisional text after claude-code sub-turn shrink when MCP tools appear", async () => {
441
+ globalThis[Symbol.for("@gsd/pi-coding-agent:theme")] = {
442
+ fg: (_key, text) => text,
443
+ bg: (_key, text) => text,
444
+ bold: (text) => text,
445
+ italic: (text) => text,
446
+ truncate: (text) => text,
447
+ };
448
+ const host = createHost();
449
+ host.getMarkdownThemeWithSettings = () => ({});
450
+ const mcpTool = {
451
+ type: "toolCall",
452
+ id: "mcp-tool-shrink-1",
453
+ name: "glob",
454
+ mcpServer: "filesystem",
455
+ arguments: { pattern: "**/*" },
456
+ };
457
+ await handleAgentEvent(host, { type: "message_start", message: makeAssistant([]) });
458
+ // Sub-turn 1: generate longer provisional text content.
459
+ await handleAgentEvent(host, {
460
+ type: "message_update",
461
+ message: makeAssistant([{ type: "text", text: "Old provisional preface." }, { type: "text", text: "More old text." }]),
462
+ assistantMessageEvent: {
463
+ type: "text_delta",
464
+ contentIndex: 1,
465
+ delta: "More old text.",
466
+ partial: makeAssistant([{ type: "text", text: "Old provisional preface." }, { type: "text", text: "More old text." }]),
467
+ },
468
+ });
469
+ assert.equal(host.chatContainer.children.length, 1, "first sub-turn text run should render");
470
+ // Sub-turn 2 starts (content shrink): old component is orphaned by design.
471
+ await handleAgentEvent(host, {
472
+ type: "message_update",
473
+ message: makeAssistant([{ type: "text", text: "New provisional text before tool." }]),
474
+ assistantMessageEvent: {
475
+ type: "text_delta",
476
+ contentIndex: 0,
477
+ delta: "New provisional text before tool.",
478
+ partial: makeAssistant([{ type: "text", text: "New provisional text before tool." }]),
479
+ },
480
+ });
481
+ assert.equal(host.chatContainer.children.length, 2, "shrink keeps prior text until MCP tool context appears");
482
+ // MCP tool appears in sub-turn 2: tool-only windows keep provisional prose visible.
483
+ await handleAgentEvent(host, {
484
+ type: "message_update",
485
+ message: makeAssistant([{ type: "text", text: "New provisional text before tool." }, mcpTool]),
486
+ assistantMessageEvent: {
487
+ type: "toolcall_end",
488
+ contentIndex: 1,
489
+ toolCall: {
490
+ ...mcpTool,
491
+ externalResult: {
492
+ content: [{ type: "text", text: "glob output" }],
493
+ details: {},
494
+ isError: false,
495
+ },
496
+ },
497
+ partial: makeAssistant([{ type: "text", text: "New provisional text before tool." }, mcpTool]),
498
+ },
499
+ });
500
+ assert.equal(host.chatContainer.children.length, 3, "stale text runs are deferred until post-tool prose arrives");
501
+ assert.equal(host.chatContainer.children[0]?.constructor?.name, "AssistantMessageComponent");
502
+ assert.equal(host.chatContainer.children[1]?.constructor?.name, "AssistantMessageComponent");
503
+ assert.equal(host.chatContainer.children[2]?.constructor?.name, "ToolExecutionComponent");
504
+ const finalContent = [mcpTool, { type: "text", text: "Final visible question?" }];
505
+ await handleAgentEvent(host, {
506
+ type: "message_update",
507
+ message: makeAssistant(finalContent),
508
+ assistantMessageEvent: {
509
+ type: "text_delta",
510
+ contentIndex: 1,
511
+ delta: "Final visible question?",
512
+ partial: makeAssistant(finalContent),
513
+ },
514
+ });
515
+ assert.equal(host.chatContainer.children.length, 2);
516
+ assert.equal(host.chatContainer.children[0]?.constructor?.name, "ToolExecutionComponent");
517
+ assert.equal(host.chatContainer.children[1]?.constructor?.name, "AssistantMessageComponent");
518
+ await handleAgentEvent(host, { type: "message_end", message: makeAssistant(finalContent) });
519
+ });
520
+ test("chat-controller prunes orphans from multiple sub-turn shrinks before MCP post-tool prose", async () => {
521
+ globalThis[Symbol.for("@gsd/pi-coding-agent:theme")] = {
522
+ fg: (_key, text) => text,
523
+ bg: (_key, text) => text,
524
+ bold: (text) => text,
525
+ italic: (text) => text,
526
+ truncate: (text) => text,
527
+ };
528
+ const host = createHost();
529
+ host.getMarkdownThemeWithSettings = () => ({});
530
+ const mcpTool = {
531
+ type: "toolCall",
532
+ id: "mcp-tool-multi-shrink-1",
533
+ name: "glob",
534
+ mcpServer: "filesystem",
535
+ arguments: { pattern: "**/*" },
536
+ };
537
+ await handleAgentEvent(host, { type: "message_start", message: makeAssistant([]) });
538
+ // Sub-turn 1: 3 text blocks (merged into one text-run).
539
+ const subTurn1 = [
540
+ { type: "text", text: "First provisional A." },
541
+ { type: "text", text: "First provisional B." },
542
+ { type: "text", text: "First provisional C." },
543
+ ];
544
+ await handleAgentEvent(host, {
545
+ type: "message_update",
546
+ message: makeAssistant(subTurn1),
547
+ assistantMessageEvent: {
548
+ type: "text_delta",
549
+ contentIndex: 2,
550
+ delta: "First provisional C.",
551
+ partial: makeAssistant(subTurn1),
552
+ },
553
+ });
554
+ assert.equal(host.chatContainer.children.length, 1, "first sub-turn renders 1 text-run");
555
+ // Sub-turn 2 (first shrink 3 → 2 blocks).
556
+ const subTurn2 = [
557
+ { type: "text", text: "Second provisional A." },
558
+ { type: "text", text: "Second provisional B." },
559
+ ];
560
+ await handleAgentEvent(host, {
561
+ type: "message_update",
562
+ message: makeAssistant(subTurn2),
563
+ assistantMessageEvent: {
564
+ type: "text_delta",
565
+ contentIndex: 1,
566
+ delta: "Second provisional B.",
567
+ partial: makeAssistant(subTurn2),
568
+ },
569
+ });
570
+ assert.equal(host.chatContainer.children.length, 2, "first shrink appends, keeps prior text as frozen history");
571
+ // Sub-turn 3 (second shrink 2 → 1 block). This is the critical step —
572
+ // without orphan accumulation, sub-turn 1's orphaned segment would be
573
+ // dropped from tracking here and later strand in the container.
574
+ const subTurn3 = [{ type: "text", text: "Third provisional." }];
575
+ await handleAgentEvent(host, {
576
+ type: "message_update",
577
+ message: makeAssistant(subTurn3),
578
+ assistantMessageEvent: {
579
+ type: "text_delta",
580
+ contentIndex: 0,
581
+ delta: "Third provisional.",
582
+ partial: makeAssistant(subTurn3),
583
+ },
584
+ });
585
+ assert.equal(host.chatContainer.children.length, 3, "second shrink appends again, still no prune (no post-tool text)");
586
+ // MCP tool appears — tool-only window still keeps provisional prose visible.
587
+ await handleAgentEvent(host, {
588
+ type: "message_update",
589
+ message: makeAssistant([{ type: "text", text: "Third provisional." }, mcpTool]),
590
+ assistantMessageEvent: {
591
+ type: "toolcall_end",
592
+ contentIndex: 1,
593
+ toolCall: {
594
+ ...mcpTool,
595
+ externalResult: {
596
+ content: [{ type: "text", text: "glob output" }],
597
+ details: {},
598
+ isError: false,
599
+ },
600
+ },
601
+ partial: makeAssistant([{ type: "text", text: "Third provisional." }, mcpTool]),
602
+ },
603
+ });
604
+ assert.equal(host.chatContainer.children.length, 4, "tool-only window keeps all three provisional text-runs");
605
+ // Final post-tool text arrives — prune must drop ALL three pre-tool
606
+ // provisional text-runs across both shrinks, leaving only tool + final text.
607
+ const finalContent = [mcpTool, { type: "text", text: "Final answer." }];
608
+ await handleAgentEvent(host, {
609
+ type: "message_update",
610
+ message: makeAssistant(finalContent),
611
+ assistantMessageEvent: {
612
+ type: "text_delta",
613
+ contentIndex: 1,
614
+ delta: "Final answer.",
615
+ partial: makeAssistant(finalContent),
616
+ },
617
+ });
618
+ assert.equal(host.chatContainer.children.length, 2, "all pre-tool provisional segments from every shrink must be pruned once post-tool prose arrives");
619
+ assert.equal(host.chatContainer.children[0]?.constructor?.name, "ToolExecutionComponent");
620
+ assert.equal(host.chatContainer.children[1]?.constructor?.name, "AssistantMessageComponent");
621
+ await handleAgentEvent(host, { type: "message_end", message: makeAssistant(finalContent) });
622
+ });
202
623
  test("chat-controller pins latest assistant text above editor when tool calls are present", async () => {
203
624
  globalThis[Symbol.for("@gsd/pi-coding-agent:theme")] = {
204
625
  fg: (_key, text) => text,
@@ -690,4 +1111,55 @@ test("chat-controller updates pinned zone after sub-turn shrink", async () => {
690
1111
  // Finalize so the module-level pinned spinner (setInterval) is torn down and the test process can exit.
691
1112
  await handleAgentEvent(host, { type: "message_end", message: makeAssistant([{ type: "text", text: "second" }, t2]) });
692
1113
  });
1114
+ test("chat-controller: agent_end without message_end must not remove streaming component from DOM (regression #4197)", async () => {
1115
+ const host = createHost();
1116
+ await handleAgentEvent(host, {
1117
+ type: "message_start",
1118
+ message: makeAssistant([]),
1119
+ });
1120
+ // Simulate partial streaming that creates an AssistantMessageComponent
1121
+ await handleAgentEvent(host, {
1122
+ type: "message_update",
1123
+ message: makeAssistant([{ type: "text", text: "partial answer" }]),
1124
+ assistantMessageEvent: {
1125
+ type: "text_delta",
1126
+ contentIndex: 0,
1127
+ delta: "partial answer",
1128
+ partial: makeAssistant([{ type: "text", text: "partial answer" }]),
1129
+ },
1130
+ });
1131
+ // Precondition: component is in DOM
1132
+ assert.equal(host.chatContainer.children.length, 1, "streaming component must be in DOM after message_update");
1133
+ const comp = host.chatContainer.children[0];
1134
+ // Simulate abort: agent_end fires WITHOUT message_end
1135
+ await handleAgentEvent(host, { type: "agent_end" });
1136
+ assert.equal(host.chatContainer.children.length, 1, "agent_end must NOT remove the streaming component from the DOM (issue #4197)");
1137
+ assert.equal(host.chatContainer.children[0], comp, "the same component instance must remain in the DOM after agent_end");
1138
+ });
1139
+ test("chat-controller: agent_end after message_end must not alter DOM", async () => {
1140
+ const host = createHost();
1141
+ const content = [{ type: "text", text: "complete answer" }];
1142
+ await handleAgentEvent(host, {
1143
+ type: "message_start",
1144
+ message: makeAssistant([]),
1145
+ });
1146
+ await handleAgentEvent(host, {
1147
+ type: "message_update",
1148
+ message: makeAssistant(content),
1149
+ assistantMessageEvent: {
1150
+ type: "text_delta",
1151
+ contentIndex: 0,
1152
+ delta: "complete answer",
1153
+ partial: makeAssistant(content),
1154
+ },
1155
+ });
1156
+ await handleAgentEvent(host, {
1157
+ type: "message_end",
1158
+ message: makeAssistant(content),
1159
+ });
1160
+ const countAfterMessageEnd = host.chatContainer.children.length;
1161
+ assert.ok(countAfterMessageEnd > 0, "component must be present after message_end");
1162
+ await handleAgentEvent(host, { type: "agent_end" });
1163
+ assert.equal(host.chatContainer.children.length, countAfterMessageEnd, "agent_end after message_end must not add or remove DOM nodes");
1164
+ });
693
1165
  //# sourceMappingURL=chat-controller-ordering.test.js.map