gsd-pi 2.74.0-dev.16f2f3b → 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 (246) 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 +13 -13
  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/server/app/_global-error.html +1 -1
  12. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  13. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  14. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  15. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  16. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  17. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  18. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  19. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  20. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  21. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  22. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  23. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  24. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  25. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  26. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  27. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  28. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +1 -1
  29. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +1 -1
  30. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +1 -1
  31. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +1 -1
  32. package/dist/web/standalone/.next/server/app/index.html +1 -1
  33. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  34. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  35. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  36. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  37. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  38. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  39. package/dist/web/standalone/.next/server/app-paths-manifest.json +13 -13
  40. package/dist/web/standalone/.next/server/chunks/6897.js +3 -3
  41. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  42. package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
  43. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  44. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  45. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  46. package/package.json +1 -1
  47. package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
  48. package/packages/pi-ai/dist/index.d.ts +1 -9
  49. package/packages/pi-ai/dist/index.d.ts.map +1 -1
  50. package/packages/pi-ai/dist/index.js +1 -9
  51. package/packages/pi-ai/dist/index.js.map +1 -1
  52. package/packages/pi-ai/dist/models/capability-patches.d.ts +19 -0
  53. package/packages/pi-ai/dist/models/capability-patches.d.ts.map +1 -0
  54. package/packages/pi-ai/dist/models/capability-patches.js +36 -0
  55. package/packages/pi-ai/dist/models/capability-patches.js.map +1 -0
  56. package/packages/pi-ai/dist/{models.custom.d.ts → models/custom.d.ts} +1 -1
  57. package/packages/pi-ai/dist/models/custom.d.ts.map +1 -0
  58. package/packages/pi-ai/dist/{models.custom.js → models/custom.js} +4 -4
  59. package/packages/pi-ai/dist/models/custom.js.map +1 -0
  60. package/packages/pi-ai/dist/models/generated/amazon-bedrock.d.ts +1482 -0
  61. package/packages/pi-ai/dist/models/generated/amazon-bedrock.d.ts.map +1 -0
  62. package/packages/pi-ai/dist/models/generated/amazon-bedrock.js +1484 -0
  63. package/packages/pi-ai/dist/models/generated/amazon-bedrock.js.map +1 -0
  64. package/packages/pi-ai/dist/models/generated/anthropic.d.ts +377 -0
  65. package/packages/pi-ai/dist/models/generated/anthropic.d.ts.map +1 -0
  66. package/packages/pi-ai/dist/models/generated/anthropic.js +379 -0
  67. package/packages/pi-ai/dist/models/generated/anthropic.js.map +1 -0
  68. package/packages/pi-ai/dist/models/generated/azure-openai-responses.d.ts +700 -0
  69. package/packages/pi-ai/dist/models/generated/azure-openai-responses.d.ts.map +1 -0
  70. package/packages/pi-ai/dist/models/generated/azure-openai-responses.js +702 -0
  71. package/packages/pi-ai/dist/models/generated/azure-openai-responses.js.map +1 -0
  72. package/packages/pi-ai/dist/models/generated/cerebras.d.ts +71 -0
  73. package/packages/pi-ai/dist/models/generated/cerebras.d.ts.map +1 -0
  74. package/packages/pi-ai/dist/models/generated/cerebras.js +73 -0
  75. package/packages/pi-ai/dist/models/generated/cerebras.js.map +1 -0
  76. package/packages/pi-ai/dist/models/generated/github-copilot.d.ts +590 -0
  77. package/packages/pi-ai/dist/models/generated/github-copilot.d.ts.map +1 -0
  78. package/packages/pi-ai/dist/models/generated/github-copilot.js +444 -0
  79. package/packages/pi-ai/dist/models/generated/github-copilot.js.map +1 -0
  80. package/packages/pi-ai/dist/models/generated/google-antigravity.d.ts +156 -0
  81. package/packages/pi-ai/dist/models/generated/google-antigravity.d.ts.map +1 -0
  82. package/packages/pi-ai/dist/models/generated/google-antigravity.js +158 -0
  83. package/packages/pi-ai/dist/models/generated/google-antigravity.js.map +1 -0
  84. package/packages/pi-ai/dist/models/generated/google-gemini-cli.d.ts +105 -0
  85. package/packages/pi-ai/dist/models/generated/google-gemini-cli.d.ts.map +1 -0
  86. package/packages/pi-ai/dist/models/generated/google-gemini-cli.js +107 -0
  87. package/packages/pi-ai/dist/models/generated/google-gemini-cli.js.map +1 -0
  88. package/packages/pi-ai/dist/models/generated/google-vertex.d.ts +207 -0
  89. package/packages/pi-ai/dist/models/generated/google-vertex.d.ts.map +1 -0
  90. package/packages/pi-ai/dist/models/generated/google-vertex.js +209 -0
  91. package/packages/pi-ai/dist/models/generated/google-vertex.js.map +1 -0
  92. package/packages/pi-ai/dist/models/generated/google.d.ts +462 -0
  93. package/packages/pi-ai/dist/models/generated/google.d.ts.map +1 -0
  94. package/packages/pi-ai/dist/models/generated/google.js +464 -0
  95. package/packages/pi-ai/dist/models/generated/google.js.map +1 -0
  96. package/packages/pi-ai/dist/models/generated/groq.d.ts +309 -0
  97. package/packages/pi-ai/dist/models/generated/groq.d.ts.map +1 -0
  98. package/packages/pi-ai/dist/models/generated/groq.js +311 -0
  99. package/packages/pi-ai/dist/models/generated/groq.js.map +1 -0
  100. package/packages/pi-ai/dist/models/generated/huggingface.d.ts +383 -0
  101. package/packages/pi-ai/dist/models/generated/huggingface.d.ts.map +1 -0
  102. package/packages/pi-ai/dist/models/generated/huggingface.js +347 -0
  103. package/packages/pi-ai/dist/models/generated/huggingface.js.map +1 -0
  104. package/packages/pi-ai/dist/{models.generated.d.ts → models/generated/index.d.ts} +1 -1
  105. package/packages/pi-ai/dist/{models.generated.d.ts.map → models/generated/index.d.ts.map} +1 -1
  106. package/packages/pi-ai/dist/models/generated/index.js +51 -0
  107. package/packages/pi-ai/dist/models/generated/index.js.map +1 -0
  108. package/packages/pi-ai/dist/models/generated/kimi-coding.d.ts +37 -0
  109. package/packages/pi-ai/dist/models/generated/kimi-coding.d.ts.map +1 -0
  110. package/packages/pi-ai/dist/models/generated/kimi-coding.js +39 -0
  111. package/packages/pi-ai/dist/models/generated/kimi-coding.js.map +1 -0
  112. package/packages/pi-ai/dist/models/generated/minimax-cn.d.ts +105 -0
  113. package/packages/pi-ai/dist/models/generated/minimax-cn.d.ts.map +1 -0
  114. package/packages/pi-ai/dist/models/generated/minimax-cn.js +107 -0
  115. package/packages/pi-ai/dist/models/generated/minimax-cn.js.map +1 -0
  116. package/packages/pi-ai/dist/models/generated/minimax.d.ts +105 -0
  117. package/packages/pi-ai/dist/models/generated/minimax.d.ts.map +1 -0
  118. package/packages/pi-ai/dist/models/generated/minimax.js +107 -0
  119. package/packages/pi-ai/dist/models/generated/minimax.js.map +1 -0
  120. package/packages/pi-ai/dist/models/generated/mistral.d.ts +445 -0
  121. package/packages/pi-ai/dist/models/generated/mistral.d.ts.map +1 -0
  122. package/packages/pi-ai/dist/models/generated/mistral.js +447 -0
  123. package/packages/pi-ai/dist/models/generated/mistral.js.map +1 -0
  124. package/packages/pi-ai/dist/models/generated/openai-codex.d.ts +139 -0
  125. package/packages/pi-ai/dist/models/generated/openai-codex.d.ts.map +1 -0
  126. package/packages/pi-ai/dist/models/generated/openai-codex.js +141 -0
  127. package/packages/pi-ai/dist/models/generated/openai-codex.js.map +1 -0
  128. package/packages/pi-ai/dist/models/generated/openai.d.ts +700 -0
  129. package/packages/pi-ai/dist/models/generated/openai.d.ts.map +1 -0
  130. package/packages/pi-ai/dist/models/generated/openai.js +702 -0
  131. package/packages/pi-ai/dist/models/generated/openai.js.map +1 -0
  132. package/packages/pi-ai/dist/models/generated/opencode-go.d.ts +122 -0
  133. package/packages/pi-ai/dist/models/generated/opencode-go.d.ts.map +1 -0
  134. package/packages/pi-ai/dist/models/generated/opencode-go.js +124 -0
  135. package/packages/pi-ai/dist/models/generated/opencode-go.js.map +1 -0
  136. package/packages/pi-ai/dist/models/generated/opencode.d.ts +530 -0
  137. package/packages/pi-ai/dist/models/generated/opencode.d.ts.map +1 -0
  138. package/packages/pi-ai/dist/models/generated/opencode.js +532 -0
  139. package/packages/pi-ai/dist/models/generated/opencode.js.map +1 -0
  140. package/packages/pi-ai/dist/models/generated/openrouter.d.ts +4270 -0
  141. package/packages/pi-ai/dist/models/generated/openrouter.d.ts.map +1 -0
  142. package/packages/pi-ai/dist/models/generated/openrouter.js +4272 -0
  143. package/packages/pi-ai/dist/models/generated/openrouter.js.map +1 -0
  144. package/packages/pi-ai/dist/models/generated/vercel-ai-gateway.d.ts +2604 -0
  145. package/packages/pi-ai/dist/models/generated/vercel-ai-gateway.d.ts.map +1 -0
  146. package/packages/pi-ai/dist/models/generated/vercel-ai-gateway.js +2606 -0
  147. package/packages/pi-ai/dist/models/generated/vercel-ai-gateway.js.map +1 -0
  148. package/packages/pi-ai/dist/models/generated/xai.d.ts +411 -0
  149. package/packages/pi-ai/dist/models/generated/xai.d.ts.map +1 -0
  150. package/packages/pi-ai/dist/models/generated/xai.js +413 -0
  151. package/packages/pi-ai/dist/models/generated/xai.js.map +1 -0
  152. package/packages/pi-ai/dist/models/generated/zai.d.ts +276 -0
  153. package/packages/pi-ai/dist/models/generated/zai.d.ts.map +1 -0
  154. package/packages/pi-ai/dist/models/generated/zai.js +239 -0
  155. package/packages/pi-ai/dist/models/generated/zai.js.map +1 -0
  156. package/packages/pi-ai/dist/models/index.d.ts +27 -0
  157. package/packages/pi-ai/dist/models/index.d.ts.map +1 -0
  158. package/packages/pi-ai/dist/models/index.js +80 -0
  159. package/packages/pi-ai/dist/models/index.js.map +1 -0
  160. package/packages/pi-ai/dist/models.d.ts +1 -36
  161. package/packages/pi-ai/dist/models.d.ts.map +1 -1
  162. package/packages/pi-ai/dist/models.generated.test.js +1 -2
  163. package/packages/pi-ai/dist/models.generated.test.js.map +1 -1
  164. package/packages/pi-ai/dist/models.js +3 -112
  165. package/packages/pi-ai/dist/models.js.map +1 -1
  166. package/packages/pi-ai/dist/models.test.js +6 -5
  167. package/packages/pi-ai/dist/models.test.js.map +1 -1
  168. package/packages/pi-ai/scripts/generate-models.ts +74 -40
  169. package/packages/pi-ai/src/index.ts +1 -9
  170. package/packages/pi-ai/src/models/capability-patches.ts +40 -0
  171. package/packages/pi-ai/src/{models.custom.ts → models/custom.ts} +4 -4
  172. package/packages/pi-ai/src/models/generated/amazon-bedrock.ts +1486 -0
  173. package/packages/pi-ai/src/models/generated/anthropic.ts +381 -0
  174. package/packages/pi-ai/src/models/generated/azure-openai-responses.ts +704 -0
  175. package/packages/pi-ai/src/models/generated/cerebras.ts +75 -0
  176. package/packages/pi-ai/src/models/generated/github-copilot.ts +446 -0
  177. package/packages/pi-ai/src/models/generated/google-antigravity.ts +160 -0
  178. package/packages/pi-ai/src/models/generated/google-gemini-cli.ts +109 -0
  179. package/packages/pi-ai/src/models/generated/google-vertex.ts +211 -0
  180. package/packages/pi-ai/src/models/generated/google.ts +466 -0
  181. package/packages/pi-ai/src/models/generated/groq.ts +313 -0
  182. package/packages/pi-ai/src/models/generated/huggingface.ts +349 -0
  183. package/packages/pi-ai/src/models/generated/index.ts +52 -0
  184. package/packages/pi-ai/src/models/generated/kimi-coding.ts +41 -0
  185. package/packages/pi-ai/src/models/generated/minimax-cn.ts +109 -0
  186. package/packages/pi-ai/src/models/generated/minimax.ts +109 -0
  187. package/packages/pi-ai/src/models/generated/mistral.ts +449 -0
  188. package/packages/pi-ai/src/models/generated/openai-codex.ts +143 -0
  189. package/packages/pi-ai/src/models/generated/openai.ts +704 -0
  190. package/packages/pi-ai/src/models/generated/opencode-go.ts +126 -0
  191. package/packages/pi-ai/src/models/generated/opencode.ts +534 -0
  192. package/packages/pi-ai/src/models/generated/openrouter.ts +4274 -0
  193. package/packages/pi-ai/src/models/generated/vercel-ai-gateway.ts +2608 -0
  194. package/packages/pi-ai/src/models/generated/xai.ts +415 -0
  195. package/packages/pi-ai/src/models/generated/zai.ts +241 -0
  196. package/packages/pi-ai/src/models/index.ts +106 -0
  197. package/packages/pi-ai/src/models.generated.test.ts +1 -2
  198. package/packages/pi-ai/src/models.test.ts +6 -5
  199. package/packages/pi-ai/src/models.ts +3 -153
  200. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  201. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  202. package/packages/pi-coding-agent/dist/core/agent-session.js +8 -2
  203. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  204. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +214 -0
  205. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
  206. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts +1 -0
  207. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  208. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js +18 -8
  209. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
  210. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts +11 -0
  211. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts.map +1 -0
  212. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js +47 -0
  213. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js.map +1 -0
  214. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  215. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js +22 -22
  216. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js.map +1 -1
  217. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  218. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +115 -4
  219. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  220. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  221. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +6 -4
  222. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  223. package/packages/pi-coding-agent/src/core/agent-session.ts +12 -6
  224. package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +273 -0
  225. package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +20 -9
  226. package/packages/pi-coding-agent/src/modes/interactive/components/chat-frame.ts +67 -0
  227. package/packages/pi-coding-agent/src/modes/interactive/components/user-message.ts +23 -26
  228. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +176 -40
  229. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +6 -4
  230. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  231. package/src/resources/extensions/gsd/auto-post-unit.ts +7 -3
  232. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +15 -1
  233. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +56 -3
  234. package/src/resources/extensions/gsd/ecosystem/gsd-extension-api.ts +228 -0
  235. package/src/resources/extensions/gsd/ecosystem/loader.ts +201 -0
  236. package/src/resources/extensions/gsd/tests/health-widget.test.ts +1 -1
  237. package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +1 -1
  238. package/src/resources/extensions/gsd/types.ts +13 -0
  239. package/src/resources/extensions/gsd/workflow-logger.ts +2 -1
  240. package/packages/pi-ai/dist/models.custom.d.ts.map +0 -1
  241. package/packages/pi-ai/dist/models.custom.js.map +0 -1
  242. package/packages/pi-ai/dist/models.generated.js +0 -14343
  243. package/packages/pi-ai/dist/models.generated.js.map +0 -1
  244. package/packages/pi-ai/src/models.generated.ts +0 -14345
  245. /package/dist/web/standalone/.next/static/{C7qugsXHwdw4-b4ROHvOE → ZDXqgjuglsRoazETSKw1J}/_buildManifest.js +0 -0
  246. /package/dist/web/standalone/.next/static/{C7qugsXHwdw4-b4ROHvOE → 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;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,CAsrB7C"}
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;
@@ -295,7 +299,13 @@ export async function handleAgentEvent(host, event) {
295
299
  const isTextLike = blockType === "text" || blockType === "thinking";
296
300
  const isTool = b.type === "toolCall" || b.type === "serverToolUse";
297
301
  // For Claude Code MCP turns, prune only pre-tool prose, never thinking.
298
- const shouldSkipProse = shouldDropPreToolProse && firstToolIdx >= 0 && i < firstToolIdx && blockType === "text";
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;
299
309
  if (shouldSkipProse) {
300
310
  closeRun();
301
311
  continue;
@@ -383,7 +393,7 @@ export async function handleAgentEvent(host, event) {
383
393
  // text-run segment
384
394
  const existing = renderedSegments.find((s) => s.kind === "text-run" && s.startIndex === seg.startIndex && s.contentType === seg.contentType);
385
395
  if (!existing) {
386
- 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 });
387
397
  host.chatContainer.addChild(comp);
388
398
  renderedSegments.push({
389
399
  kind: "text-run",
@@ -477,8 +487,109 @@ export async function handleAgentEvent(host, event) {
477
487
  const shouldRenderAssistant = hasVisibleAssistantContent(host.streamingMessage)
478
488
  || ((host.streamingMessage.stopReason === "aborted" || host.streamingMessage.stopReason === "error")
479
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
+ }
480
591
  if (!host.streamingComponent && shouldRenderAssistant) {
481
- host.streamingComponent = new AssistantMessageComponent(undefined, host.hideThinkingBlock, host.getMarkdownThemeWithSettings(), host.settingsManager.getTimestampFormat());
592
+ host.streamingComponent = new AssistantMessageComponent(undefined, host.hideThinkingBlock, host.getMarkdownThemeWithSettings(), timestampFormat);
482
593
  host.chatContainer.addChild(host.streamingComponent);
483
594
  }
484
595
  if (host.streamingComponent) {