gsd-pi 2.74.0-dev.14c45ac → 2.74.0-dev.20f79a8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (254) hide show
  1. package/dist/resources/extensions/gsd/auto-post-unit.js +7 -3
  2. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +10 -1
  3. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +45 -4
  4. package/dist/resources/extensions/gsd/ecosystem/gsd-extension-api.js +144 -0
  5. package/dist/resources/extensions/gsd/ecosystem/loader.js +145 -0
  6. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  7. package/dist/web/standalone/.next/BUILD_ID +1 -1
  8. package/dist/web/standalone/.next/app-path-routes-manifest.json +16 -16
  9. package/dist/web/standalone/.next/build-manifest.json +2 -2
  10. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  11. package/dist/web/standalone/.next/required-server-files.json +1 -1
  12. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  13. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  14. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  15. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  16. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  17. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  18. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  19. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  20. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  21. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  22. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  23. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  24. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  25. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  26. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  27. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  28. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  29. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +1 -1
  30. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +1 -1
  31. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +1 -1
  32. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +1 -1
  33. package/dist/web/standalone/.next/server/app/index.html +1 -1
  34. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  35. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  36. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  37. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  38. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  39. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  40. package/dist/web/standalone/.next/server/app-paths-manifest.json +16 -16
  41. package/dist/web/standalone/.next/server/chunks/6897.js +3 -3
  42. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  43. package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
  44. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  45. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  46. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  47. package/dist/web/standalone/server.js +1 -1
  48. package/package.json +1 -1
  49. package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
  50. package/packages/pi-ai/dist/index.d.ts +1 -9
  51. package/packages/pi-ai/dist/index.d.ts.map +1 -1
  52. package/packages/pi-ai/dist/index.js +1 -9
  53. package/packages/pi-ai/dist/index.js.map +1 -1
  54. package/packages/pi-ai/dist/models/capability-patches.d.ts +19 -0
  55. package/packages/pi-ai/dist/models/capability-patches.d.ts.map +1 -0
  56. package/packages/pi-ai/dist/models/capability-patches.js +36 -0
  57. package/packages/pi-ai/dist/models/capability-patches.js.map +1 -0
  58. package/packages/pi-ai/dist/{models.custom.d.ts → models/custom.d.ts} +1 -1
  59. package/packages/pi-ai/dist/models/custom.d.ts.map +1 -0
  60. package/packages/pi-ai/dist/{models.custom.js → models/custom.js} +4 -4
  61. package/packages/pi-ai/dist/models/custom.js.map +1 -0
  62. package/packages/pi-ai/dist/models/generated/amazon-bedrock.d.ts +1482 -0
  63. package/packages/pi-ai/dist/models/generated/amazon-bedrock.d.ts.map +1 -0
  64. package/packages/pi-ai/dist/models/generated/amazon-bedrock.js +1484 -0
  65. package/packages/pi-ai/dist/models/generated/amazon-bedrock.js.map +1 -0
  66. package/packages/pi-ai/dist/models/generated/anthropic.d.ts +377 -0
  67. package/packages/pi-ai/dist/models/generated/anthropic.d.ts.map +1 -0
  68. package/packages/pi-ai/dist/models/generated/anthropic.js +379 -0
  69. package/packages/pi-ai/dist/models/generated/anthropic.js.map +1 -0
  70. package/packages/pi-ai/dist/models/generated/azure-openai-responses.d.ts +700 -0
  71. package/packages/pi-ai/dist/models/generated/azure-openai-responses.d.ts.map +1 -0
  72. package/packages/pi-ai/dist/models/generated/azure-openai-responses.js +702 -0
  73. package/packages/pi-ai/dist/models/generated/azure-openai-responses.js.map +1 -0
  74. package/packages/pi-ai/dist/models/generated/cerebras.d.ts +71 -0
  75. package/packages/pi-ai/dist/models/generated/cerebras.d.ts.map +1 -0
  76. package/packages/pi-ai/dist/models/generated/cerebras.js +73 -0
  77. package/packages/pi-ai/dist/models/generated/cerebras.js.map +1 -0
  78. package/packages/pi-ai/dist/models/generated/github-copilot.d.ts +590 -0
  79. package/packages/pi-ai/dist/models/generated/github-copilot.d.ts.map +1 -0
  80. package/packages/pi-ai/dist/models/generated/github-copilot.js +444 -0
  81. package/packages/pi-ai/dist/models/generated/github-copilot.js.map +1 -0
  82. package/packages/pi-ai/dist/models/generated/google-antigravity.d.ts +156 -0
  83. package/packages/pi-ai/dist/models/generated/google-antigravity.d.ts.map +1 -0
  84. package/packages/pi-ai/dist/models/generated/google-antigravity.js +158 -0
  85. package/packages/pi-ai/dist/models/generated/google-antigravity.js.map +1 -0
  86. package/packages/pi-ai/dist/models/generated/google-gemini-cli.d.ts +105 -0
  87. package/packages/pi-ai/dist/models/generated/google-gemini-cli.d.ts.map +1 -0
  88. package/packages/pi-ai/dist/models/generated/google-gemini-cli.js +107 -0
  89. package/packages/pi-ai/dist/models/generated/google-gemini-cli.js.map +1 -0
  90. package/packages/pi-ai/dist/models/generated/google-vertex.d.ts +207 -0
  91. package/packages/pi-ai/dist/models/generated/google-vertex.d.ts.map +1 -0
  92. package/packages/pi-ai/dist/models/generated/google-vertex.js +209 -0
  93. package/packages/pi-ai/dist/models/generated/google-vertex.js.map +1 -0
  94. package/packages/pi-ai/dist/models/generated/google.d.ts +462 -0
  95. package/packages/pi-ai/dist/models/generated/google.d.ts.map +1 -0
  96. package/packages/pi-ai/dist/models/generated/google.js +464 -0
  97. package/packages/pi-ai/dist/models/generated/google.js.map +1 -0
  98. package/packages/pi-ai/dist/models/generated/groq.d.ts +309 -0
  99. package/packages/pi-ai/dist/models/generated/groq.d.ts.map +1 -0
  100. package/packages/pi-ai/dist/models/generated/groq.js +311 -0
  101. package/packages/pi-ai/dist/models/generated/groq.js.map +1 -0
  102. package/packages/pi-ai/dist/models/generated/huggingface.d.ts +383 -0
  103. package/packages/pi-ai/dist/models/generated/huggingface.d.ts.map +1 -0
  104. package/packages/pi-ai/dist/models/generated/huggingface.js +347 -0
  105. package/packages/pi-ai/dist/models/generated/huggingface.js.map +1 -0
  106. package/packages/pi-ai/dist/{models.generated.d.ts → models/generated/index.d.ts} +1 -1
  107. package/packages/pi-ai/dist/{models.generated.d.ts.map → models/generated/index.d.ts.map} +1 -1
  108. package/packages/pi-ai/dist/models/generated/index.js +51 -0
  109. package/packages/pi-ai/dist/models/generated/index.js.map +1 -0
  110. package/packages/pi-ai/dist/models/generated/kimi-coding.d.ts +37 -0
  111. package/packages/pi-ai/dist/models/generated/kimi-coding.d.ts.map +1 -0
  112. package/packages/pi-ai/dist/models/generated/kimi-coding.js +39 -0
  113. package/packages/pi-ai/dist/models/generated/kimi-coding.js.map +1 -0
  114. package/packages/pi-ai/dist/models/generated/minimax-cn.d.ts +105 -0
  115. package/packages/pi-ai/dist/models/generated/minimax-cn.d.ts.map +1 -0
  116. package/packages/pi-ai/dist/models/generated/minimax-cn.js +107 -0
  117. package/packages/pi-ai/dist/models/generated/minimax-cn.js.map +1 -0
  118. package/packages/pi-ai/dist/models/generated/minimax.d.ts +105 -0
  119. package/packages/pi-ai/dist/models/generated/minimax.d.ts.map +1 -0
  120. package/packages/pi-ai/dist/models/generated/minimax.js +107 -0
  121. package/packages/pi-ai/dist/models/generated/minimax.js.map +1 -0
  122. package/packages/pi-ai/dist/models/generated/mistral.d.ts +445 -0
  123. package/packages/pi-ai/dist/models/generated/mistral.d.ts.map +1 -0
  124. package/packages/pi-ai/dist/models/generated/mistral.js +447 -0
  125. package/packages/pi-ai/dist/models/generated/mistral.js.map +1 -0
  126. package/packages/pi-ai/dist/models/generated/openai-codex.d.ts +139 -0
  127. package/packages/pi-ai/dist/models/generated/openai-codex.d.ts.map +1 -0
  128. package/packages/pi-ai/dist/models/generated/openai-codex.js +141 -0
  129. package/packages/pi-ai/dist/models/generated/openai-codex.js.map +1 -0
  130. package/packages/pi-ai/dist/models/generated/openai.d.ts +700 -0
  131. package/packages/pi-ai/dist/models/generated/openai.d.ts.map +1 -0
  132. package/packages/pi-ai/dist/models/generated/openai.js +702 -0
  133. package/packages/pi-ai/dist/models/generated/openai.js.map +1 -0
  134. package/packages/pi-ai/dist/models/generated/opencode-go.d.ts +122 -0
  135. package/packages/pi-ai/dist/models/generated/opencode-go.d.ts.map +1 -0
  136. package/packages/pi-ai/dist/models/generated/opencode-go.js +124 -0
  137. package/packages/pi-ai/dist/models/generated/opencode-go.js.map +1 -0
  138. package/packages/pi-ai/dist/models/generated/opencode.d.ts +530 -0
  139. package/packages/pi-ai/dist/models/generated/opencode.d.ts.map +1 -0
  140. package/packages/pi-ai/dist/models/generated/opencode.js +532 -0
  141. package/packages/pi-ai/dist/models/generated/opencode.js.map +1 -0
  142. package/packages/pi-ai/dist/models/generated/openrouter.d.ts +4270 -0
  143. package/packages/pi-ai/dist/models/generated/openrouter.d.ts.map +1 -0
  144. package/packages/pi-ai/dist/models/generated/openrouter.js +4272 -0
  145. package/packages/pi-ai/dist/models/generated/openrouter.js.map +1 -0
  146. package/packages/pi-ai/dist/models/generated/vercel-ai-gateway.d.ts +2604 -0
  147. package/packages/pi-ai/dist/models/generated/vercel-ai-gateway.d.ts.map +1 -0
  148. package/packages/pi-ai/dist/models/generated/vercel-ai-gateway.js +2606 -0
  149. package/packages/pi-ai/dist/models/generated/vercel-ai-gateway.js.map +1 -0
  150. package/packages/pi-ai/dist/models/generated/xai.d.ts +411 -0
  151. package/packages/pi-ai/dist/models/generated/xai.d.ts.map +1 -0
  152. package/packages/pi-ai/dist/models/generated/xai.js +413 -0
  153. package/packages/pi-ai/dist/models/generated/xai.js.map +1 -0
  154. package/packages/pi-ai/dist/models/generated/zai.d.ts +276 -0
  155. package/packages/pi-ai/dist/models/generated/zai.d.ts.map +1 -0
  156. package/packages/pi-ai/dist/models/generated/zai.js +239 -0
  157. package/packages/pi-ai/dist/models/generated/zai.js.map +1 -0
  158. package/packages/pi-ai/dist/models/index.d.ts +27 -0
  159. package/packages/pi-ai/dist/models/index.d.ts.map +1 -0
  160. package/packages/pi-ai/dist/models/index.js +80 -0
  161. package/packages/pi-ai/dist/models/index.js.map +1 -0
  162. package/packages/pi-ai/dist/models.d.ts +1 -36
  163. package/packages/pi-ai/dist/models.d.ts.map +1 -1
  164. package/packages/pi-ai/dist/models.generated.test.js +1 -2
  165. package/packages/pi-ai/dist/models.generated.test.js.map +1 -1
  166. package/packages/pi-ai/dist/models.js +3 -112
  167. package/packages/pi-ai/dist/models.js.map +1 -1
  168. package/packages/pi-ai/dist/models.test.js +6 -5
  169. package/packages/pi-ai/dist/models.test.js.map +1 -1
  170. package/packages/pi-ai/scripts/generate-models.ts +74 -40
  171. package/packages/pi-ai/src/index.ts +1 -9
  172. package/packages/pi-ai/src/models/capability-patches.ts +40 -0
  173. package/packages/pi-ai/src/{models.custom.ts → models/custom.ts} +4 -4
  174. package/packages/pi-ai/src/models/generated/amazon-bedrock.ts +1486 -0
  175. package/packages/pi-ai/src/models/generated/anthropic.ts +381 -0
  176. package/packages/pi-ai/src/models/generated/azure-openai-responses.ts +704 -0
  177. package/packages/pi-ai/src/models/generated/cerebras.ts +75 -0
  178. package/packages/pi-ai/src/models/generated/github-copilot.ts +446 -0
  179. package/packages/pi-ai/src/models/generated/google-antigravity.ts +160 -0
  180. package/packages/pi-ai/src/models/generated/google-gemini-cli.ts +109 -0
  181. package/packages/pi-ai/src/models/generated/google-vertex.ts +211 -0
  182. package/packages/pi-ai/src/models/generated/google.ts +466 -0
  183. package/packages/pi-ai/src/models/generated/groq.ts +313 -0
  184. package/packages/pi-ai/src/models/generated/huggingface.ts +349 -0
  185. package/packages/pi-ai/src/models/generated/index.ts +52 -0
  186. package/packages/pi-ai/src/models/generated/kimi-coding.ts +41 -0
  187. package/packages/pi-ai/src/models/generated/minimax-cn.ts +109 -0
  188. package/packages/pi-ai/src/models/generated/minimax.ts +109 -0
  189. package/packages/pi-ai/src/models/generated/mistral.ts +449 -0
  190. package/packages/pi-ai/src/models/generated/openai-codex.ts +143 -0
  191. package/packages/pi-ai/src/models/generated/openai.ts +704 -0
  192. package/packages/pi-ai/src/models/generated/opencode-go.ts +126 -0
  193. package/packages/pi-ai/src/models/generated/opencode.ts +534 -0
  194. package/packages/pi-ai/src/models/generated/openrouter.ts +4274 -0
  195. package/packages/pi-ai/src/models/generated/vercel-ai-gateway.ts +2608 -0
  196. package/packages/pi-ai/src/models/generated/xai.ts +415 -0
  197. package/packages/pi-ai/src/models/generated/zai.ts +241 -0
  198. package/packages/pi-ai/src/models/index.ts +106 -0
  199. package/packages/pi-ai/src/models.generated.test.ts +1 -2
  200. package/packages/pi-ai/src/models.test.ts +6 -5
  201. package/packages/pi-ai/src/models.ts +3 -153
  202. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  203. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  204. package/packages/pi-coding-agent/dist/core/agent-session.js +8 -2
  205. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  206. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +284 -10
  207. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
  208. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts +1 -0
  209. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  210. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js +23 -9
  211. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
  212. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts +11 -0
  213. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts.map +1 -0
  214. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js +47 -0
  215. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js.map +1 -0
  216. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  217. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js +22 -22
  218. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js.map +1 -1
  219. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  220. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +171 -24
  221. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  222. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-ordering.test.d.ts +2 -0
  223. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-ordering.test.d.ts.map +1 -0
  224. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-ordering.test.js +38 -0
  225. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-ordering.test.js.map +1 -0
  226. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +13 -0
  227. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  228. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +53 -6
  229. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  230. package/packages/pi-coding-agent/src/core/agent-session.ts +12 -6
  231. package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +357 -10
  232. package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +25 -10
  233. package/packages/pi-coding-agent/src/modes/interactive/components/chat-frame.ts +67 -0
  234. package/packages/pi-coding-agent/src/modes/interactive/components/user-message.ts +23 -26
  235. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +232 -47
  236. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-ordering.test.ts +44 -0
  237. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +73 -6
  238. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  239. package/src/resources/extensions/gsd/auto-post-unit.ts +7 -3
  240. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +15 -1
  241. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +56 -3
  242. package/src/resources/extensions/gsd/ecosystem/gsd-extension-api.ts +228 -0
  243. package/src/resources/extensions/gsd/ecosystem/loader.ts +201 -0
  244. package/src/resources/extensions/gsd/tests/health-widget.test.ts +1 -1
  245. package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +1 -1
  246. package/src/resources/extensions/gsd/types.ts +13 -0
  247. package/src/resources/extensions/gsd/workflow-logger.ts +2 -1
  248. package/packages/pi-ai/dist/models.custom.d.ts.map +0 -1
  249. package/packages/pi-ai/dist/models.custom.js.map +0 -1
  250. package/packages/pi-ai/dist/models.generated.js +0 -14343
  251. package/packages/pi-ai/dist/models.generated.js.map +0 -1
  252. package/packages/pi-ai/src/models.generated.ts +0 -14345
  253. /package/dist/web/standalone/.next/static/{ZMKM0OI0CrTgzKWbgfPOg → ZDXqgjuglsRoazETSKw1J}/_buildManifest.js +0 -0
  254. /package/dist/web/standalone/.next/static/{ZMKM0OI0CrTgzKWbgfPOg → ZDXqgjuglsRoazETSKw1J}/_ssgManifest.js +0 -0
@@ -0,0 +1,11 @@
1
+ import { type TimestampFormat } from "./timestamp.js";
2
+ type FrameTone = "assistant" | "user";
3
+ export declare function renderChatFrame(contentLines: string[], width: number, opts: {
4
+ label: string;
5
+ tone: FrameTone;
6
+ timestamp?: number;
7
+ timestampFormat: TimestampFormat;
8
+ showTimestamp?: boolean;
9
+ }): string[];
10
+ export {};
11
+ //# sourceMappingURL=chat-frame.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat-frame.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/chat-frame.ts"],"names":[],"mappings":"AAEA,OAAO,EAAmB,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEvE,KAAK,SAAS,GAAG,WAAW,GAAG,MAAM,CAAC;AAUtC,wBAAgB,eAAe,CAC9B,YAAY,EAAE,MAAM,EAAE,EACtB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE;IACL,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,SAAS,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,eAAe,CAAC;IACjC,aAAa,CAAC,EAAE,OAAO,CAAC;CACxB,GACC,MAAM,EAAE,CA0CV"}
@@ -0,0 +1,47 @@
1
+ import { truncateToWidth, visibleWidth } from "@gsd/pi-tui";
2
+ import { theme } from "../theme/theme.js";
3
+ import { formatTimestamp } from "./timestamp.js";
4
+ function trimOuterBlankLines(lines) {
5
+ let start = 0;
6
+ let end = lines.length;
7
+ while (start < end && lines[start].trim().length === 0)
8
+ start++;
9
+ while (end > start && lines[end - 1].trim().length === 0)
10
+ end--;
11
+ return lines.slice(start, end);
12
+ }
13
+ export function renderChatFrame(contentLines, width, opts) {
14
+ const outerWidth = Math.max(20, width);
15
+ const contentWidth = Math.max(1, outerWidth - 2); // "│ " + content
16
+ const borderColor = opts.tone === "user" ? "borderAccent" : "border";
17
+ const borderMuted = opts.tone === "user" ? "borderMuted" : "borderMuted";
18
+ const border = (s) => theme.fg(borderColor, s);
19
+ const leftRaw = `• ${opts.label}`;
20
+ const rightRaw = opts.showTimestamp === false || !opts.timestamp
21
+ ? ""
22
+ : formatTimestamp(opts.timestamp, opts.timestampFormat);
23
+ const leftBudget = rightRaw
24
+ ? Math.max(1, outerWidth - visibleWidth(rightRaw) - 1)
25
+ : outerWidth;
26
+ const left = truncateToWidth(leftRaw, leftBudget, "");
27
+ const leftStyled = opts.tone === "user"
28
+ ? theme.fg("accent", theme.bold(left))
29
+ : theme.fg("muted", theme.bold(left));
30
+ const rightStyled = rightRaw ? theme.fg("dim", rightRaw) : "";
31
+ const gap = rightRaw.length > 0
32
+ ? Math.max(1, outerWidth - visibleWidth(leftStyled) - visibleWidth(rightStyled))
33
+ : Math.max(0, outerWidth - visibleWidth(leftStyled));
34
+ const headerRow = `${leftStyled}${" ".repeat(gap)}${rightStyled}`;
35
+ const headerPad = Math.max(0, outerWidth - visibleWidth(headerRow));
36
+ const sourceLines = trimOuterBlankLines(contentLines);
37
+ const bodyLines = (sourceLines.length > 0 ? sourceLines : [""]).map((line) => {
38
+ const clipped = truncateToWidth(line, contentWidth, "");
39
+ return border("│ ") + clipped;
40
+ });
41
+ return [
42
+ theme.fg(borderMuted, "─".repeat(outerWidth)),
43
+ headerRow + " ".repeat(headerPad),
44
+ ...bodyLines,
45
+ ];
46
+ }
47
+ //# sourceMappingURL=chat-frame.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat-frame.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/chat-frame.ts"],"names":[],"mappings":"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","sourcesContent":["import { truncateToWidth, visibleWidth } from \"@gsd/pi-tui\";\nimport { theme } from \"../theme/theme.js\";\nimport { formatTimestamp, type TimestampFormat } from \"./timestamp.js\";\n\ntype FrameTone = \"assistant\" | \"user\";\n\nfunction trimOuterBlankLines(lines: string[]): string[] {\n\tlet start = 0;\n\tlet end = lines.length;\n\twhile (start < end && lines[start].trim().length === 0) start++;\n\twhile (end > start && lines[end - 1].trim().length === 0) end--;\n\treturn lines.slice(start, end);\n}\n\nexport function renderChatFrame(\n\tcontentLines: string[],\n\twidth: number,\n\topts: {\n\t\tlabel: string;\n\t\ttone: FrameTone;\n\t\ttimestamp?: number;\n\t\ttimestampFormat: TimestampFormat;\n\t\tshowTimestamp?: boolean;\n\t},\n): string[] {\n\tconst outerWidth = Math.max(20, width);\n\tconst contentWidth = Math.max(1, outerWidth - 2); // \"│ \" + content\n\tconst borderColor = opts.tone === \"user\" ? \"borderAccent\" : \"border\";\n\tconst borderMuted = opts.tone === \"user\" ? \"borderMuted\" : \"borderMuted\";\n\tconst border = (s: string) => theme.fg(borderColor, s);\n\tconst leftRaw = `• ${opts.label}`;\n\tconst rightRaw =\n\t\topts.showTimestamp === false || !opts.timestamp\n\t\t\t? \"\"\n\t\t\t: formatTimestamp(opts.timestamp, opts.timestampFormat);\n\n\tconst leftBudget = rightRaw\n\t\t? Math.max(1, outerWidth - visibleWidth(rightRaw) - 1)\n\t\t: outerWidth;\n\tconst left = truncateToWidth(leftRaw, leftBudget, \"\");\n\tconst leftStyled =\n\t\topts.tone === \"user\"\n\t\t\t? theme.fg(\"accent\", theme.bold(left))\n\t\t\t: theme.fg(\"muted\", theme.bold(left));\n\tconst rightStyled = rightRaw ? theme.fg(\"dim\", rightRaw) : \"\";\n\tconst gap =\n\t\trightRaw.length > 0\n\t\t\t? Math.max(\n\t\t\t\t\t1,\n\t\t\t\t\touterWidth - visibleWidth(leftStyled) - visibleWidth(rightStyled),\n\t\t\t\t)\n\t\t\t: Math.max(0, outerWidth - visibleWidth(leftStyled));\n\tconst headerRow = `${leftStyled}${\" \".repeat(gap)}${rightStyled}`;\n\tconst headerPad = Math.max(0, outerWidth - visibleWidth(headerRow));\n\n\tconst sourceLines = trimOuterBlankLines(contentLines);\n\tconst bodyLines = (sourceLines.length > 0 ? sourceLines : [\"\"]).map((line) => {\n\t\tconst clipped = truncateToWidth(line, contentWidth, \"\");\n\t\treturn border(\"│ \") + clipped;\n\t});\n\n\treturn [\n\t\ttheme.fg(borderMuted, \"─\".repeat(outerWidth)),\n\t\theaderRow + \" \".repeat(headerPad),\n\t\t...bodyLines,\n\t];\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"user-message.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/user-message.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAY,KAAK,aAAa,EAAgB,MAAM,aAAa,CAAC;AAEpF,OAAO,EAAmB,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAKvE;;GAEG;AACH,qBAAa,oBAAqB,SAAQ,SAAS;IAClD,OAAO,CAAC,SAAS,CAAqB;IACtC,OAAO,CAAC,eAAe,CAAkB;gBAE7B,IAAI,EAAE,MAAM,EAAE,aAAa,GAAE,aAAkC,EAAE,SAAS,CAAC,EAAE,MAAM,EAAE,eAAe,GAAE,eAAiC;IAa1I,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE;CAmBxC"}
1
+ {"version":3,"file":"user-message.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/user-message.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAY,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAEtE,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAMtD;;GAEG;AACH,qBAAa,oBAAqB,SAAQ,SAAS;IAClD,OAAO,CAAC,SAAS,CAAqB;IACtC,OAAO,CAAC,eAAe,CAAkB;gBAE7B,IAAI,EAAE,MAAM,EAAE,aAAa,GAAE,aAAkC,EAAE,SAAS,CAAC,EAAE,MAAM,EAAE,eAAe,GAAE,eAAiC;IAO1I,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE;CAqBxC"}
@@ -1,6 +1,6 @@
1
- import { Container, Markdown, Spacer } from "@gsd/pi-tui";
2
- import { getMarkdownTheme, theme } from "../theme/theme.js";
3
- import { formatTimestamp } from "./timestamp.js";
1
+ import { Container, Markdown } from "@gsd/pi-tui";
2
+ import { getMarkdownTheme } from "../theme/theme.js";
3
+ import { renderChatFrame } from "./chat-frame.js";
4
4
  const OSC133_ZONE_START = "\x1b]133;A\x07";
5
5
  const OSC133_ZONE_END = "\x1b]133;B\x07";
6
6
  /**
@@ -11,28 +11,28 @@ export class UserMessageComponent extends Container {
11
11
  super();
12
12
  this.timestamp = timestamp;
13
13
  this.timestampFormat = timestampFormat;
14
- this.addChild(new Spacer(1));
15
- this.addChild(new Markdown(text, 1, 1, markdownTheme, {
16
- bgColor: (text) => theme.bg("userMessageBg", text),
17
- color: (text) => theme.fg("userMessageText", text),
18
- }));
14
+ this.addChild(new Markdown(text, 0, 0, markdownTheme));
19
15
  }
20
16
  render(width) {
21
- const lines = super.render(width);
22
- if (lines.length === 0) {
23
- return lines;
17
+ const frameWidth = Math.max(20, width);
18
+ const contentWidth = Math.max(1, frameWidth - 4);
19
+ const lines = super.render(contentWidth);
20
+ const framed = renderChatFrame(lines, frameWidth, {
21
+ label: "You",
22
+ tone: "user",
23
+ timestamp: this.timestamp,
24
+ timestampFormat: this.timestampFormat,
25
+ showTimestamp: true,
26
+ });
27
+ if (framed.length === 0) {
28
+ return framed;
24
29
  }
25
- // Insert right-aligned timestamp above the message content
26
- if (this.timestamp) {
27
- const timeStr = formatTimestamp(this.timestamp, this.timestampFormat);
28
- const label = theme.fg("dim", timeStr);
29
- const padding = Math.max(0, width - timeStr.length - 1);
30
- const timestampLine = " ".repeat(padding) + label;
31
- lines.splice(0, 0, timestampLine);
32
- }
33
- lines[0] = OSC133_ZONE_START + lines[0];
34
- lines[lines.length - 1] = lines[lines.length - 1] + OSC133_ZONE_END;
35
- return lines;
30
+ const out = ["", ...framed];
31
+ const firstFrameLine = 1;
32
+ const lastFrameLine = out.length - 1;
33
+ out[firstFrameLine] = OSC133_ZONE_START + out[firstFrameLine];
34
+ out[lastFrameLine] = out[lastFrameLine] + OSC133_ZONE_END;
35
+ return out;
36
36
  }
37
37
  }
38
38
  //# sourceMappingURL=user-message.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"user-message.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/user-message.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAsB,MAAM,EAAQ,MAAM,aAAa,CAAC;AACpF,OAAO,EAAE,gBAAgB,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAwB,MAAM,gBAAgB,CAAC;AAEvE,MAAM,iBAAiB,GAAG,gBAAgB,CAAC;AAC3C,MAAM,eAAe,GAAG,gBAAgB,CAAC;AAEzC;;GAEG;AACH,MAAM,OAAO,oBAAqB,SAAQ,SAAS;IAIlD,YAAY,IAAY,EAAE,gBAA+B,gBAAgB,EAAE,EAAE,SAAkB,EAAE,kBAAmC,eAAe;QAClJ,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,eAAe,GAAG,eAAe,CAAC;QACvC,IAAI,CAAC,QAAQ,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QAC7B,IAAI,CAAC,QAAQ,CACZ,IAAI,QAAQ,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,EAAE,aAAa,EAAE;YACvC,OAAO,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,eAAe,EAAE,IAAI,CAAC;YAC1D,KAAK,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,iBAAiB,EAAE,IAAI,CAAC;SAC1D,CAAC,CACF,CAAC;IACH,CAAC;IAEQ,MAAM,CAAC,KAAa;QAC5B,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAClC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxB,OAAO,KAAK,CAAC;QACd,CAAC;QAED,2DAA2D;QAC3D,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACpB,MAAM,OAAO,GAAG,eAAe,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,eAAe,CAAC,CAAC;YACtE,MAAM,KAAK,GAAG,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;YACvC,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;YACxD,MAAM,aAAa,GAAG,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,KAAK,CAAC;YAClD,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,aAAa,CAAC,CAAC;QACnC,CAAC;QAED,KAAK,CAAC,CAAC,CAAC,GAAG,iBAAiB,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACxC,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,eAAe,CAAC;QACpE,OAAO,KAAK,CAAC;IACd,CAAC;CACD","sourcesContent":["import { Container, Markdown, type MarkdownTheme, Spacer, Text } from \"@gsd/pi-tui\";\nimport { getMarkdownTheme, theme } from \"../theme/theme.js\";\nimport { formatTimestamp, type TimestampFormat } from \"./timestamp.js\";\n\nconst OSC133_ZONE_START = \"\\x1b]133;A\\x07\";\nconst OSC133_ZONE_END = \"\\x1b]133;B\\x07\";\n\n/**\n * Component that renders a user message with a right-aligned timestamp.\n */\nexport class UserMessageComponent extends Container {\n\tprivate timestamp: number | undefined;\n\tprivate timestampFormat: TimestampFormat;\n\n\tconstructor(text: string, markdownTheme: MarkdownTheme = getMarkdownTheme(), timestamp?: number, timestampFormat: TimestampFormat = \"date-time-iso\") {\n\t\tsuper();\n\t\tthis.timestamp = timestamp;\n\t\tthis.timestampFormat = timestampFormat;\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(\n\t\t\tnew Markdown(text, 1, 1, markdownTheme, {\n\t\t\t\tbgColor: (text: string) => theme.bg(\"userMessageBg\", text),\n\t\t\t\tcolor: (text: string) => theme.fg(\"userMessageText\", text),\n\t\t\t}),\n\t\t);\n\t}\n\n\toverride render(width: number): string[] {\n\t\tconst lines = super.render(width);\n\t\tif (lines.length === 0) {\n\t\t\treturn lines;\n\t\t}\n\n\t\t// Insert right-aligned timestamp above the message content\n\t\tif (this.timestamp) {\n\t\t\tconst timeStr = formatTimestamp(this.timestamp, this.timestampFormat);\n\t\t\tconst label = theme.fg(\"dim\", timeStr);\n\t\t\tconst padding = Math.max(0, width - timeStr.length - 1);\n\t\t\tconst timestampLine = \" \".repeat(padding) + label;\n\t\t\tlines.splice(0, 0, timestampLine);\n\t\t}\n\n\t\tlines[0] = OSC133_ZONE_START + lines[0];\n\t\tlines[lines.length - 1] = lines[lines.length - 1] + OSC133_ZONE_END;\n\t\treturn lines;\n\t}\n}\n"]}
1
+ {"version":3,"file":"user-message.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/user-message.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAsB,MAAM,aAAa,CAAC;AACtE,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAErD,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAElD,MAAM,iBAAiB,GAAG,gBAAgB,CAAC;AAC3C,MAAM,eAAe,GAAG,gBAAgB,CAAC;AAEzC;;GAEG;AACH,MAAM,OAAO,oBAAqB,SAAQ,SAAS;IAIlD,YAAY,IAAY,EAAE,gBAA+B,gBAAgB,EAAE,EAAE,SAAkB,EAAE,kBAAmC,eAAe;QAClJ,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,eAAe,GAAG,eAAe,CAAC;QACvC,IAAI,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,EAAE,aAAa,CAAC,CAAC,CAAC;IACxD,CAAC;IAEQ,MAAM,CAAC,KAAa;QAC5B,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;QACvC,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,UAAU,GAAG,CAAC,CAAC,CAAC;QACjD,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;QACzC,MAAM,MAAM,GAAG,eAAe,CAAC,KAAK,EAAE,UAAU,EAAE;YACjD,KAAK,EAAE,KAAK;YACZ,IAAI,EAAE,MAAM;YACZ,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,eAAe,EAAE,IAAI,CAAC,eAAe;YACrC,aAAa,EAAE,IAAI;SACnB,CAAC,CAAC;QACH,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,OAAO,MAAM,CAAC;QACf,CAAC;QACD,MAAM,GAAG,GAAG,CAAC,EAAE,EAAE,GAAG,MAAM,CAAC,CAAC;QAC5B,MAAM,cAAc,GAAG,CAAC,CAAC;QACzB,MAAM,aAAa,GAAG,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC;QACrC,GAAG,CAAC,cAAc,CAAC,GAAG,iBAAiB,GAAG,GAAG,CAAC,cAAc,CAAC,CAAC;QAC9D,GAAG,CAAC,aAAa,CAAC,GAAG,GAAG,CAAC,aAAa,CAAC,GAAG,eAAe,CAAC;QAC1D,OAAO,GAAG,CAAC;IACZ,CAAC;CACD","sourcesContent":["import { Container, Markdown, type MarkdownTheme } from \"@gsd/pi-tui\";\nimport { getMarkdownTheme } from \"../theme/theme.js\";\nimport { type TimestampFormat } from \"./timestamp.js\";\nimport { renderChatFrame } from \"./chat-frame.js\";\n\nconst OSC133_ZONE_START = \"\\x1b]133;A\\x07\";\nconst OSC133_ZONE_END = \"\\x1b]133;B\\x07\";\n\n/**\n * Component that renders a user message with a right-aligned timestamp.\n */\nexport class UserMessageComponent extends Container {\n\tprivate timestamp: number | undefined;\n\tprivate timestampFormat: TimestampFormat;\n\n\tconstructor(text: string, markdownTheme: MarkdownTheme = getMarkdownTheme(), timestamp?: number, timestampFormat: TimestampFormat = \"date-time-iso\") {\n\t\tsuper();\n\t\tthis.timestamp = timestamp;\n\t\tthis.timestampFormat = timestampFormat;\n\t\tthis.addChild(new Markdown(text, 0, 0, markdownTheme));\n\t}\n\n\toverride render(width: number): string[] {\n\t\tconst frameWidth = Math.max(20, width);\n\t\tconst contentWidth = Math.max(1, frameWidth - 4);\n\t\tconst lines = super.render(contentWidth);\n\t\tconst framed = renderChatFrame(lines, frameWidth, {\n\t\t\tlabel: \"You\",\n\t\t\ttone: \"user\",\n\t\t\ttimestamp: this.timestamp,\n\t\t\ttimestampFormat: this.timestampFormat,\n\t\t\tshowTimestamp: true,\n\t\t});\n\t\tif (framed.length === 0) {\n\t\t\treturn framed;\n\t\t}\n\t\tconst out = [\"\", ...framed];\n\t\tconst firstFrameLine = 1;\n\t\tconst lastFrameLine = out.length - 1;\n\t\tout[firstFrameLine] = OSC133_ZONE_START + out[firstFrameLine];\n\t\tout[lastFrameLine] = out[lastFrameLine] + OSC133_ZONE_END;\n\t\treturn out;\n\t}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"chat-controller.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/controllers/chat-controller.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,oBAAoB,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AAyCnG,wBAAgB,sBAAsB,CAAC,aAAa,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,MAAM,CAgBxE;AAWD,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,wBAAwB,GAAG;IACvE,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,4BAA4B,EAAE,MAAM,GAAG,CAAC;IACxC,gBAAgB,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,GAAG,KAAK,IAAI,CAAC;IACxD,qBAAqB,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,MAAM,CAAC;IACpD,2BAA2B,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,GAAG,CAAC;IACvD,sBAAsB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C,uBAAuB,EAAE,MAAM,IAAI,CAAC;IACpC,oBAAoB,EAAE,CAAC,OAAO,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3E,UAAU,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,SAAS,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,4BAA4B,EAAE,MAAM,IAAI,CAAC;IACzC,mBAAmB,EAAE,MAAM,IAAI,CAAC;IAChC,uBAAuB,EAAE,MAAM,IAAI,CAAC;IACpC,wBAAwB,EAAE;QAAE,KAAK,EAAE,MAAM,IAAI,CAAA;KAAE,CAAC;CAChD,EAAE,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CA2oB7C"}
1
+ {"version":3,"file":"chat-controller.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/controllers/chat-controller.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,oBAAoB,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AA+CnG,wBAAgB,sBAAsB,CAAC,aAAa,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,MAAM,CAgBxE;AAWD,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,wBAAwB,GAAG;IACvE,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,4BAA4B,EAAE,MAAM,GAAG,CAAC;IACxC,gBAAgB,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,GAAG,KAAK,IAAI,CAAC;IACxD,qBAAqB,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,MAAM,CAAC;IACpD,2BAA2B,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,GAAG,CAAC;IACvD,sBAAsB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C,uBAAuB,EAAE,MAAM,IAAI,CAAC;IACpC,oBAAoB,EAAE,CAAC,OAAO,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3E,UAAU,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,SAAS,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,4BAA4B,EAAE,MAAM,IAAI,CAAC;IACzC,mBAAmB,EAAE,MAAM,IAAI,CAAC;IAChC,uBAAuB,EAAE,MAAM,IAAI,CAAC;IACpC,wBAAwB,EAAE;QAAE,KAAK,EAAE,MAAM,IAAI,CAAA;KAAE,CAAC;CAChD,EAAE,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CA8zB7C"}
@@ -55,6 +55,7 @@ export async function handleAgentEvent(host, event) {
55
55
  await host.init();
56
56
  }
57
57
  host.footer.invalidate();
58
+ const timestampFormat = host.settingsManager.getTimestampFormat();
58
59
  // Reset content index tracker and pinned state when a new assistant message starts
59
60
  if (event.type === "message_start" && event.message.role === "assistant") {
60
61
  lastProcessedContentIndex = 0;
@@ -190,7 +191,10 @@ export async function handleAgentEvent(host, event) {
190
191
  // content (#4144 regression). Prior sub-turn children stay in
191
192
  // chatContainer as frozen history; new segments append after them.
192
193
  if (contentBlocks.length < lastContentLength) {
193
- orphanedSegments = [...renderedSegments];
194
+ // Accumulate across successive shrinks — overwriting would drop
195
+ // segments displaced by an earlier shrink, leaving them stranded
196
+ // in chatContainer once the prune pass finally runs.
197
+ orphanedSegments = [...orphanedSegments, ...renderedSegments];
194
198
  renderedSegments = [];
195
199
  lastPinnedText = "";
196
200
  lastProcessedContentIndex = 0;
@@ -268,42 +272,76 @@ export async function handleAgentEvent(host, event) {
268
272
  }
269
273
  return false;
270
274
  });
271
- const shouldDropPreToolText = isClaudeCodeProvider && hasMcpToolBlock;
272
275
  const firstToolIdx = blocks.findIndex((b) => b.type === "toolCall" || b.type === "serverToolUse");
276
+ const hasPostToolText = firstToolIdx >= 0
277
+ && blocks.some((b, idx) => (idx > firstToolIdx
278
+ && b?.type === "text"
279
+ && typeof b?.text === "string"
280
+ && b.text.trim().length > 0));
281
+ // Only prune provisional pre-tool prose after post-tool prose exists,
282
+ // so MCP tool-only windows do not blank the assistant content.
283
+ const shouldDropPreToolProse = isClaudeCodeProvider && hasMcpToolBlock && hasPostToolText;
273
284
  const desired = [];
274
285
  let runStart = -1;
286
+ let runEnd = -1;
287
+ let runType;
288
+ const closeRun = () => {
289
+ if (runStart !== -1 && runType) {
290
+ desired.push({ kind: "text-run", startIndex: runStart, endIndex: runEnd, contentType: runType });
291
+ runStart = -1;
292
+ runEnd = -1;
293
+ runType = undefined;
294
+ }
295
+ };
275
296
  for (let i = 0; i < blocks.length; i++) {
276
297
  const b = blocks[i];
277
- const isText = b.type === "text" || b.type === "thinking";
298
+ const blockType = b.type === "text" || b.type === "thinking" ? b.type : undefined;
299
+ const isTextLike = blockType === "text" || blockType === "thinking";
278
300
  const isTool = b.type === "toolCall" || b.type === "serverToolUse";
279
- if (isText) {
280
- if (shouldDropPreToolText && firstToolIdx >= 0 && i < firstToolIdx) {
281
- continue;
301
+ // For Claude Code MCP turns, prune only pre-tool prose, never thinking.
302
+ const textValue = blockType === "text" && typeof b?.text === "string" ? b.text : "";
303
+ const isLikelyQuestion = blockType === "text" && typeof textValue === "string" && /\?\s*$/.test(textValue.trim());
304
+ const shouldSkipProse = shouldDropPreToolProse
305
+ && firstToolIdx >= 0
306
+ && i < firstToolIdx
307
+ && blockType === "text"
308
+ && !isLikelyQuestion;
309
+ if (shouldSkipProse) {
310
+ closeRun();
311
+ continue;
312
+ }
313
+ if (isTextLike) {
314
+ if (runStart === -1) {
315
+ runStart = i;
316
+ runEnd = i;
317
+ runType = blockType;
282
318
  }
283
- if (runStart === -1)
319
+ else if (runType !== blockType) {
320
+ closeRun();
284
321
  runStart = i;
322
+ runEnd = i;
323
+ runType = blockType;
324
+ }
325
+ else {
326
+ runEnd = i;
327
+ }
285
328
  }
286
329
  else {
287
- if (runStart !== -1) {
288
- desired.push({ kind: "text-run", startIndex: runStart, endIndex: i - 1 });
289
- runStart = -1;
290
- }
330
+ closeRun();
291
331
  if (isTool) {
292
332
  desired.push({ kind: "tool", contentIndex: i, toolId: b.id });
293
333
  }
294
334
  }
295
335
  }
296
- if (runStart !== -1) {
297
- desired.push({ kind: "text-run", startIndex: runStart, endIndex: blocks.length - 1 });
298
- }
336
+ closeRun();
299
337
  // Claude Code MCP can emit provisional pre-tool prose that gets
300
338
  // superseded by post-tool output. Prune stale text-run segments so
301
339
  // the final assistant output remains below tool output.
302
- if (shouldDropPreToolText && firstToolIdx >= 0) {
340
+ if (shouldDropPreToolProse && firstToolIdx >= 0) {
303
341
  if (orphanedSegments.length > 0) {
304
342
  const remainingOrphans = [];
305
343
  for (const orphan of orphanedSegments) {
306
- if (orphan.kind === "text-run") {
344
+ if (orphan.kind === "text-run" && orphan.contentType === "text") {
307
345
  host.chatContainer.removeChild(orphan.component);
308
346
  if (host.streamingComponent === orphan.component) {
309
347
  host.streamingComponent = undefined;
@@ -314,15 +352,17 @@ export async function handleAgentEvent(host, event) {
314
352
  }
315
353
  orphanedSegments = remainingOrphans;
316
354
  }
317
- const desiredTextStarts = new Set(desired
355
+ const desiredTextKeys = new Set(desired
318
356
  .filter((seg) => seg.kind === "text-run")
319
- .map((seg) => seg.startIndex));
357
+ .map((seg) => `${seg.contentType}:${seg.startIndex}`));
320
358
  const desiredToolIndices = new Set(desired
321
359
  .filter((seg) => seg.kind === "tool")
322
360
  .map((seg) => seg.contentIndex));
323
361
  const nextRendered = [];
324
362
  for (const seg of renderedSegments) {
325
- if (seg.kind === "text-run" && !desiredTextStarts.has(seg.startIndex)) {
363
+ if (seg.kind === "text-run"
364
+ && seg.contentType === "text"
365
+ && !desiredTextKeys.has(`${seg.contentType}:${seg.startIndex}`)) {
326
366
  host.chatContainer.removeChild(seg.component);
327
367
  if (host.streamingComponent === seg.component) {
328
368
  host.streamingComponent = undefined;
@@ -351,11 +391,17 @@ export async function handleAgentEvent(host, event) {
351
391
  }
352
392
  else {
353
393
  // text-run segment
354
- const existing = renderedSegments.find((s) => s.kind === "text-run" && s.startIndex === seg.startIndex);
394
+ const existing = renderedSegments.find((s) => s.kind === "text-run" && s.startIndex === seg.startIndex && s.contentType === seg.contentType);
355
395
  if (!existing) {
356
- const comp = new AssistantMessageComponent(undefined, host.hideThinkingBlock, host.getMarkdownThemeWithSettings(), host.settingsManager.getTimestampFormat(), { startIndex: seg.startIndex, endIndex: seg.endIndex });
396
+ const comp = new AssistantMessageComponent(undefined, host.hideThinkingBlock, host.getMarkdownThemeWithSettings(), timestampFormat, { startIndex: seg.startIndex, endIndex: seg.endIndex });
357
397
  host.chatContainer.addChild(comp);
358
- renderedSegments.push({ kind: "text-run", startIndex: seg.startIndex, endIndex: seg.endIndex, component: comp });
398
+ renderedSegments.push({
399
+ kind: "text-run",
400
+ startIndex: seg.startIndex,
401
+ endIndex: seg.endIndex,
402
+ contentType: seg.contentType,
403
+ component: comp,
404
+ });
359
405
  host.streamingComponent = comp;
360
406
  }
361
407
  }
@@ -365,7 +411,7 @@ export async function handleAgentEvent(host, event) {
365
411
  for (const seg of renderedSegments) {
366
412
  if (seg.kind === "text-run") {
367
413
  // Find corresponding desired segment to get current endIndex
368
- const d = desired.find((ds) => ds.kind === "text-run" && ds.startIndex === seg.startIndex);
414
+ const d = desired.find((ds) => ds.kind === "text-run" && ds.startIndex === seg.startIndex && ds.contentType === seg.contentType);
369
415
  if (d && d.kind === "text-run" && d.endIndex !== seg.endIndex) {
370
416
  seg.endIndex = d.endIndex;
371
417
  seg.component.setRange({ startIndex: seg.startIndex, endIndex: seg.endIndex });
@@ -441,8 +487,109 @@ export async function handleAgentEvent(host, event) {
441
487
  const shouldRenderAssistant = hasVisibleAssistantContent(host.streamingMessage)
442
488
  || ((host.streamingMessage.stopReason === "aborted" || host.streamingMessage.stopReason === "error")
443
489
  && !hasAssistantToolBlocks(host.streamingMessage));
490
+ // The final message_end payload can contain additional text/thinking
491
+ // blocks that never arrived via message_update (e.g. SDK result
492
+ // aggregation). Rebuild this in-flight turn from final content so
493
+ // ranges/components don't keep stale partial indices.
494
+ if (renderedSegments.length > 0) {
495
+ const finalBlocks = host.streamingMessage.content;
496
+ const desired = [];
497
+ let runStart = -1;
498
+ let runEnd = -1;
499
+ let runType;
500
+ const closeRun = () => {
501
+ if (runStart !== -1 && runType) {
502
+ desired.push({ kind: "text-run", startIndex: runStart, endIndex: runEnd, contentType: runType });
503
+ runStart = -1;
504
+ runEnd = -1;
505
+ runType = undefined;
506
+ }
507
+ };
508
+ for (let i = 0; i < finalBlocks.length; i++) {
509
+ const block = finalBlocks[i];
510
+ const blockType = block?.type === "text" || block?.type === "thinking" ? block.type : undefined;
511
+ const isTextLike = blockType === "text" || blockType === "thinking";
512
+ const isTool = block?.type === "toolCall" || block?.type === "serverToolUse";
513
+ if (isTextLike) {
514
+ if (runStart === -1) {
515
+ runStart = i;
516
+ runEnd = i;
517
+ runType = blockType;
518
+ }
519
+ else if (runType !== blockType) {
520
+ closeRun();
521
+ runStart = i;
522
+ runEnd = i;
523
+ runType = blockType;
524
+ }
525
+ else {
526
+ runEnd = i;
527
+ }
528
+ }
529
+ else {
530
+ closeRun();
531
+ if (isTool) {
532
+ desired.push({ kind: "tool", contentIndex: i, toolId: block.id });
533
+ }
534
+ }
535
+ }
536
+ closeRun();
537
+ const toolComponentsById = new Map();
538
+ for (const [toolId, component] of host.pendingTools.entries()) {
539
+ toolComponentsById.set(toolId, component);
540
+ }
541
+ for (const seg of renderedSegments) {
542
+ host.chatContainer.removeChild(seg.component);
543
+ if (seg.kind === "tool") {
544
+ const priorBlocks = host.streamingMessage.content;
545
+ const priorBlock = priorBlocks[seg.contentIndex];
546
+ if (priorBlock?.id && !toolComponentsById.has(priorBlock.id)) {
547
+ toolComponentsById.set(priorBlock.id, seg.component);
548
+ }
549
+ }
550
+ }
551
+ renderedSegments = [];
552
+ host.streamingComponent = undefined;
553
+ for (const seg of desired) {
554
+ if (seg.kind === "tool") {
555
+ const finalBlock = finalBlocks[seg.contentIndex];
556
+ let component = toolComponentsById.get(seg.toolId);
557
+ if (!component && finalBlock?.id) {
558
+ component = host.pendingTools.get(finalBlock.id);
559
+ }
560
+ if (!component && finalBlock?.type === "toolCall") {
561
+ component = new ToolExecutionComponent(finalBlock.name, finalBlock.arguments, { showImages: host.settingsManager.getShowImages() }, host.getRegisteredToolDefinition(finalBlock.name), host.ui);
562
+ component.setExpanded(host.toolOutputExpanded);
563
+ host.pendingTools.set(finalBlock.id, component);
564
+ toolComponentsById.set(finalBlock.id, component);
565
+ }
566
+ else if (!component && finalBlock?.type === "serverToolUse") {
567
+ component = new ToolExecutionComponent(finalBlock.name, finalBlock.input ?? {}, { showImages: host.settingsManager.getShowImages() }, undefined, host.ui);
568
+ component.setExpanded(host.toolOutputExpanded);
569
+ host.pendingTools.set(finalBlock.id, component);
570
+ toolComponentsById.set(finalBlock.id, component);
571
+ }
572
+ if (component) {
573
+ host.chatContainer.addChild(component);
574
+ renderedSegments.push({ kind: "tool", contentIndex: seg.contentIndex, component });
575
+ }
576
+ continue;
577
+ }
578
+ const comp = new AssistantMessageComponent(undefined, host.hideThinkingBlock, host.getMarkdownThemeWithSettings(), timestampFormat, { startIndex: seg.startIndex, endIndex: seg.endIndex });
579
+ comp.updateContent(host.streamingMessage);
580
+ host.chatContainer.addChild(comp);
581
+ renderedSegments.push({
582
+ kind: "text-run",
583
+ startIndex: seg.startIndex,
584
+ endIndex: seg.endIndex,
585
+ contentType: seg.contentType,
586
+ component: comp,
587
+ });
588
+ host.streamingComponent = comp;
589
+ }
590
+ }
444
591
  if (!host.streamingComponent && shouldRenderAssistant) {
445
- host.streamingComponent = new AssistantMessageComponent(undefined, host.hideThinkingBlock, host.getMarkdownThemeWithSettings(), host.settingsManager.getTimestampFormat());
592
+ host.streamingComponent = new AssistantMessageComponent(undefined, host.hideThinkingBlock, host.getMarkdownThemeWithSettings(), timestampFormat);
446
593
  host.chatContainer.addChild(host.streamingComponent);
447
594
  }
448
595
  if (host.streamingComponent) {