pi-namespace-patch 0.85.1 → 0.86.0-namespace.1

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 (317) hide show
  1. package/CHANGELOG.md +86 -0
  2. package/README.md +26 -705
  3. package/dist/bundle/chunks/anthropic-messages-MYU5ZMRF.js +6 -0
  4. package/dist/bundle/chunks/azure-openai-responses-HUSQ3GP2.js +2 -0
  5. package/dist/bundle/chunks/bedrock-converse-stream.js +47 -38
  6. package/dist/bundle/chunks/chunk-A3JYRWB6.js +2 -0
  7. package/dist/bundle/chunks/chunk-DTD7JQ7Y.js +42 -0
  8. package/dist/bundle/chunks/chunk-FUXEF6JQ.js +44 -0
  9. package/dist/bundle/chunks/chunk-IS2VY2NY.js +1561 -0
  10. package/dist/bundle/chunks/{chunk-IDDQWTHI.js → chunk-RCZIEVGO.js} +10 -1
  11. package/dist/bundle/chunks/chunk-S7SZN6Z3.js +2 -0
  12. package/dist/bundle/chunks/chunk-SXW7XMQG.js +2 -0
  13. package/dist/bundle/chunks/chunk-WIUZI2CJ.js +11 -0
  14. package/dist/bundle/chunks/github-copilot.js +1 -1
  15. package/dist/bundle/chunks/google-generative-ai-IMS5EK2Y.js +2 -0
  16. package/dist/bundle/chunks/google-vertex-O4YJEQUW.js +2 -0
  17. package/dist/bundle/chunks/jiti-loader-C3NU2SDH.js +21 -0
  18. package/dist/bundle/chunks/jiti-static-loader-E6ANQD5T.js +2 -0
  19. package/dist/bundle/chunks/mistral-conversations-NOSQHBEY.js +5 -0
  20. package/dist/bundle/chunks/{node-KG362ECQ.js → node-O3RIBJRH.js} +1 -1
  21. package/dist/bundle/chunks/openai-codex-responses-QDSOTBBO.js +10 -0
  22. package/dist/bundle/chunks/openai-completions-KQPOPEVM.js +7 -0
  23. package/dist/bundle/chunks/openai-responses-HWEUZ6WZ.js +2 -0
  24. package/dist/bundle/chunks/{pi-messages-PML4SPVJ.js → pi-messages-GFKBWJHZ.js} +1 -1
  25. package/dist/bundle/chunks/virtual-modules-UQVS3IVK.js +2 -0
  26. package/dist/bundle/cli.js +1 -1
  27. package/dist/bundle/index.js +1 -1
  28. package/dist/bundle/rpc-entry.js +1 -1
  29. package/dist/cli/session-picker.d.ts +1 -1
  30. package/dist/cli/session-picker.d.ts.map +1 -1
  31. package/dist/cli/session-picker.js.map +1 -1
  32. package/dist/config.d.ts.map +1 -1
  33. package/dist/config.js +1 -1
  34. package/dist/config.js.map +1 -1
  35. package/dist/core/agent-session.d.ts +56 -6
  36. package/dist/core/agent-session.d.ts.map +1 -1
  37. package/dist/core/agent-session.js +294 -157
  38. package/dist/core/agent-session.js.map +1 -1
  39. package/dist/core/bug-report-upload.d.ts +12 -0
  40. package/dist/core/bug-report-upload.d.ts.map +1 -0
  41. package/dist/core/bug-report-upload.js +22 -0
  42. package/dist/core/bug-report-upload.js.map +1 -0
  43. package/dist/core/bug-report.d.ts +176 -0
  44. package/dist/core/bug-report.d.ts.map +1 -0
  45. package/dist/core/bug-report.js +292 -0
  46. package/dist/core/bug-report.js.map +1 -0
  47. package/dist/core/cache-stats.d.ts.map +1 -1
  48. package/dist/core/cache-stats.js +12 -1
  49. package/dist/core/cache-stats.js.map +1 -1
  50. package/dist/core/cache-warmer.d.ts +102 -0
  51. package/dist/core/cache-warmer.d.ts.map +1 -0
  52. package/dist/core/cache-warmer.js +342 -0
  53. package/dist/core/cache-warmer.js.map +1 -0
  54. package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  55. package/dist/core/compaction/branch-summarization.js +2 -2
  56. package/dist/core/compaction/branch-summarization.js.map +1 -1
  57. package/dist/core/compaction/compaction.d.ts +2 -2
  58. package/dist/core/compaction/compaction.d.ts.map +1 -1
  59. package/dist/core/compaction/compaction.js +11 -12
  60. package/dist/core/compaction/compaction.js.map +1 -1
  61. package/dist/core/crash-log.d.ts +22 -0
  62. package/dist/core/crash-log.d.ts.map +1 -0
  63. package/dist/core/crash-log.js +71 -0
  64. package/dist/core/crash-log.js.map +1 -0
  65. package/dist/core/experimental.d.ts +0 -4
  66. package/dist/core/experimental.d.ts.map +1 -1
  67. package/dist/core/experimental.js +0 -4
  68. package/dist/core/experimental.js.map +1 -1
  69. package/dist/core/extensions/index.d.ts +1 -1
  70. package/dist/core/extensions/index.d.ts.map +1 -1
  71. package/dist/core/extensions/index.js.map +1 -1
  72. package/dist/core/extensions/jiti-loader.d.ts +2 -0
  73. package/dist/core/extensions/jiti-loader.d.ts.map +1 -0
  74. package/dist/core/extensions/jiti-loader.js +4 -0
  75. package/dist/core/extensions/jiti-loader.js.map +1 -0
  76. package/dist/core/extensions/jiti-static-loader.d.ts +2 -0
  77. package/dist/core/extensions/jiti-static-loader.d.ts.map +1 -0
  78. package/dist/core/extensions/jiti-static-loader.js +4 -0
  79. package/dist/core/extensions/jiti-static-loader.js.map +1 -0
  80. package/dist/core/extensions/loader.d.ts.map +1 -1
  81. package/dist/core/extensions/loader.js +38 -51
  82. package/dist/core/extensions/loader.js.map +1 -1
  83. package/dist/core/extensions/runner.d.ts +10 -7
  84. package/dist/core/extensions/runner.d.ts.map +1 -1
  85. package/dist/core/extensions/runner.js +85 -67
  86. package/dist/core/extensions/runner.js.map +1 -1
  87. package/dist/core/extensions/types.d.ts +60 -50
  88. package/dist/core/extensions/types.d.ts.map +1 -1
  89. package/dist/core/extensions/types.js.map +1 -1
  90. package/dist/core/extensions/virtual-modules.d.ts +3 -0
  91. package/dist/core/extensions/virtual-modules.d.ts.map +1 -0
  92. package/dist/core/extensions/virtual-modules.js +38 -0
  93. package/dist/core/extensions/virtual-modules.js.map +1 -0
  94. package/dist/core/extensions/wrapper.d.ts.map +1 -1
  95. package/dist/core/extensions/wrapper.js +1 -20
  96. package/dist/core/extensions/wrapper.js.map +1 -1
  97. package/dist/core/index.d.ts +2 -1
  98. package/dist/core/index.d.ts.map +1 -1
  99. package/dist/core/index.js.map +1 -1
  100. package/dist/core/keybindings.d.ts +1 -1
  101. package/dist/core/keybindings.d.ts.map +1 -1
  102. package/dist/core/keybindings.js +1 -1
  103. package/dist/core/keybindings.js.map +1 -1
  104. package/dist/core/messages.d.ts.map +1 -1
  105. package/dist/core/messages.js +1 -0
  106. package/dist/core/messages.js.map +1 -1
  107. package/dist/core/model-config.d.ts +101 -20
  108. package/dist/core/model-config.d.ts.map +1 -1
  109. package/dist/core/model-config.js +25 -18
  110. package/dist/core/model-config.js.map +1 -1
  111. package/dist/core/model-registry.d.ts +5 -1
  112. package/dist/core/model-registry.d.ts.map +1 -1
  113. package/dist/core/model-registry.js +8 -0
  114. package/dist/core/model-registry.js.map +1 -1
  115. package/dist/core/model-resolver.d.ts.map +1 -1
  116. package/dist/core/model-resolver.js +1 -1
  117. package/dist/core/model-resolver.js.map +1 -1
  118. package/dist/core/model-runtime.d.ts.map +1 -1
  119. package/dist/core/model-runtime.js +5 -3
  120. package/dist/core/model-runtime.js.map +1 -1
  121. package/dist/core/provider-composer.d.ts +3 -2
  122. package/dist/core/provider-composer.d.ts.map +1 -1
  123. package/dist/core/provider-composer.js +2 -0
  124. package/dist/core/provider-composer.js.map +1 -1
  125. package/dist/core/radius.d.ts +3 -0
  126. package/dist/core/radius.d.ts.map +1 -1
  127. package/dist/core/radius.js +6 -0
  128. package/dist/core/radius.js.map +1 -1
  129. package/dist/core/sdk.d.ts.map +1 -1
  130. package/dist/core/sdk.js +60 -38
  131. package/dist/core/sdk.js.map +1 -1
  132. package/dist/core/session-export.d.ts +6 -2
  133. package/dist/core/session-export.d.ts.map +1 -1
  134. package/dist/core/session-export.js +14 -13
  135. package/dist/core/session-export.js.map +1 -1
  136. package/dist/core/session-manager.d.ts +29 -6
  137. package/dist/core/session-manager.d.ts.map +1 -1
  138. package/dist/core/session-manager.js +159 -96
  139. package/dist/core/session-manager.js.map +1 -1
  140. package/dist/core/settings-manager.d.ts +20 -4
  141. package/dist/core/settings-manager.d.ts.map +1 -1
  142. package/dist/core/settings-manager.js +43 -7
  143. package/dist/core/settings-manager.js.map +1 -1
  144. package/dist/core/slash-commands.d.ts.map +1 -1
  145. package/dist/core/slash-commands.js +1 -0
  146. package/dist/core/slash-commands.js.map +1 -1
  147. package/dist/core/system-prompt.d.ts +49 -6
  148. package/dist/core/system-prompt.d.ts.map +1 -1
  149. package/dist/core/system-prompt.js +121 -92
  150. package/dist/core/system-prompt.js.map +1 -1
  151. package/dist/core/tools/bash.d.ts +2 -1
  152. package/dist/core/tools/bash.d.ts.map +1 -1
  153. package/dist/core/tools/bash.js +10 -4
  154. package/dist/core/tools/bash.js.map +1 -1
  155. package/dist/core/tools/edit.d.ts.map +1 -1
  156. package/dist/core/tools/edit.js +1 -2
  157. package/dist/core/tools/edit.js.map +1 -1
  158. package/dist/core/tools/read.d.ts.map +1 -1
  159. package/dist/core/tools/read.js +1 -2
  160. package/dist/core/tools/read.js.map +1 -1
  161. package/dist/core/tools/renderers/bash.d.ts.map +1 -1
  162. package/dist/core/tools/renderers/bash.js +9 -1
  163. package/dist/core/tools/renderers/bash.js.map +1 -1
  164. package/dist/core/tools/write.d.ts.map +1 -1
  165. package/dist/core/tools/write.js +1 -2
  166. package/dist/core/tools/write.js.map +1 -1
  167. package/dist/core/usage-totals.d.ts +1 -1
  168. package/dist/core/usage-totals.d.ts.map +1 -1
  169. package/dist/core/usage-totals.js +5 -1
  170. package/dist/core/usage-totals.js.map +1 -1
  171. package/dist/extensions/llama/client.d.ts +2 -0
  172. package/dist/extensions/llama/client.d.ts.map +1 -1
  173. package/dist/extensions/llama/client.js +7 -3
  174. package/dist/extensions/llama/client.js.map +1 -1
  175. package/dist/extensions/llama/provider.d.ts.map +1 -1
  176. package/dist/extensions/llama/provider.js +20 -5
  177. package/dist/extensions/llama/provider.js.map +1 -1
  178. package/dist/index.d.ts +3 -2
  179. package/dist/index.d.ts.map +1 -1
  180. package/dist/index.js.map +1 -1
  181. package/dist/main.d.ts.map +1 -1
  182. package/dist/main.js +13 -9
  183. package/dist/main.js.map +1 -1
  184. package/dist/migrations.d.ts.map +1 -1
  185. package/dist/migrations.js +2 -2
  186. package/dist/migrations.js.map +1 -1
  187. package/dist/modes/interactive/bug-report.d.ts +14 -0
  188. package/dist/modes/interactive/bug-report.d.ts.map +1 -0
  189. package/dist/modes/interactive/bug-report.js +209 -0
  190. package/dist/modes/interactive/bug-report.js.map +1 -0
  191. package/dist/modes/interactive/chat-viewport.d.ts.map +1 -1
  192. package/dist/modes/interactive/chat-viewport.js +1 -1
  193. package/dist/modes/interactive/chat-viewport.js.map +1 -1
  194. package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
  195. package/dist/modes/interactive/components/branch-summary-message.js +12 -5
  196. package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
  197. package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
  198. package/dist/modes/interactive/components/compaction-summary-message.js +12 -5
  199. package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
  200. package/dist/modes/interactive/components/custom-editor.d.ts +3 -3
  201. package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
  202. package/dist/modes/interactive/components/custom-editor.js.map +1 -1
  203. package/dist/modes/interactive/components/extension-input.d.ts +2 -0
  204. package/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
  205. package/dist/modes/interactive/components/extension-input.js +6 -0
  206. package/dist/modes/interactive/components/extension-input.js.map +1 -1
  207. package/dist/modes/interactive/components/extension-selector.d.ts +1 -0
  208. package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
  209. package/dist/modes/interactive/components/extension-selector.js +4 -0
  210. package/dist/modes/interactive/components/extension-selector.js.map +1 -1
  211. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  212. package/dist/modes/interactive/components/footer.js +4 -1
  213. package/dist/modes/interactive/components/footer.js.map +1 -1
  214. package/dist/modes/interactive/components/session-selector.d.ts +5 -5
  215. package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
  216. package/dist/modes/interactive/components/session-selector.js +74 -48
  217. package/dist/modes/interactive/components/session-selector.js.map +1 -1
  218. package/dist/modes/interactive/components/settings-selector.d.ts +3 -1
  219. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  220. package/dist/modes/interactive/components/settings-selector.js +11 -0
  221. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  222. package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
  223. package/dist/modes/interactive/components/skill-invocation-message.js +11 -4
  224. package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
  225. package/dist/modes/interactive/components/status-indicator.d.ts +2 -2
  226. package/dist/modes/interactive/components/status-indicator.d.ts.map +1 -1
  227. package/dist/modes/interactive/components/status-indicator.js +7 -7
  228. package/dist/modes/interactive/components/status-indicator.js.map +1 -1
  229. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  230. package/dist/modes/interactive/components/tool-execution.js +18 -9
  231. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  232. package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
  233. package/dist/modes/interactive/components/tree-selector.js +2 -0
  234. package/dist/modes/interactive/components/tree-selector.js.map +1 -1
  235. package/dist/modes/interactive/interactive-mode.d.ts +13 -1
  236. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  237. package/dist/modes/interactive/interactive-mode.js +220 -84
  238. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  239. package/dist/modes/interactive/session-share.d.ts +2 -0
  240. package/dist/modes/interactive/session-share.d.ts.map +1 -1
  241. package/dist/modes/interactive/session-share.js +8 -4
  242. package/dist/modes/interactive/session-share.js.map +1 -1
  243. package/dist/modes/interactive/tui-renderer.d.ts.map +1 -1
  244. package/dist/modes/interactive/tui-renderer.js +2 -2
  245. package/dist/modes/interactive/tui-renderer.js.map +1 -1
  246. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  247. package/dist/modes/rpc/rpc-mode.js +2 -2
  248. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  249. package/dist/utils/clipboard-command.d.ts +7 -0
  250. package/dist/utils/clipboard-command.d.ts.map +1 -0
  251. package/dist/utils/clipboard-command.js +45 -0
  252. package/dist/utils/clipboard-command.js.map +1 -0
  253. package/dist/utils/clipboard-image.d.ts.map +1 -1
  254. package/dist/utils/clipboard-image.js +52 -69
  255. package/dist/utils/clipboard-image.js.map +1 -1
  256. package/dist/utils/clipboard.d.ts.map +1 -1
  257. package/dist/utils/clipboard.js +61 -125
  258. package/dist/utils/clipboard.js.map +1 -1
  259. package/dist/utils/version-check.d.ts.map +1 -1
  260. package/dist/utils/version-check.js +11 -4
  261. package/dist/utils/version-check.js.map +1 -1
  262. package/dist/utils/zip.d.ts +7 -0
  263. package/dist/utils/zip.d.ts.map +1 -0
  264. package/dist/utils/zip.js +60 -0
  265. package/dist/utils/zip.js.map +1 -0
  266. package/docs/compaction.md +39 -13
  267. package/docs/custom-provider.md +22 -13
  268. package/docs/development.md +4 -4
  269. package/docs/docs.json +4 -0
  270. package/docs/environment-variables.md +1 -0
  271. package/docs/extensions.md +57 -43
  272. package/docs/json.md +4 -4
  273. package/docs/models.md +33 -2
  274. package/docs/providers.md +2 -2
  275. package/docs/sdk.md +4 -2
  276. package/docs/security.md +1 -1
  277. package/docs/session-format.md +82 -40
  278. package/docs/sessions.md +27 -0
  279. package/docs/settings.md +60 -1
  280. package/docs/termux.md +0 -1
  281. package/docs/tui.md +2 -2
  282. package/docs/usage.md +1 -0
  283. package/examples/extensions/README.md +0 -1
  284. package/examples/extensions/custom-provider-anthropic/index.ts +18 -12
  285. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  286. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  287. package/examples/extensions/custom-provider-gitlab-duo/index.ts +2 -2
  288. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  289. package/examples/extensions/gondolin/package-lock.json +2 -2
  290. package/examples/extensions/gondolin/package.json +1 -1
  291. package/examples/extensions/prompt-customizer.ts +19 -67
  292. package/examples/extensions/sandbox/package-lock.json +2 -2
  293. package/examples/extensions/sandbox/package.json +1 -1
  294. package/examples/extensions/with-deps/package-lock.json +2 -2
  295. package/examples/extensions/with-deps/package.json +1 -1
  296. package/npm-shrinkwrap.json +435 -762
  297. package/package.json +17 -23
  298. package/dist/bundle/chunks/anthropic-messages-VWZZOSJQ.js +0 -6
  299. package/dist/bundle/chunks/azure-openai-responses-BJLAM6CD.js +0 -2
  300. package/dist/bundle/chunks/chunk-AXIIZGTV.js +0 -2
  301. package/dist/bundle/chunks/chunk-CLNPYIDP.js +0 -42
  302. package/dist/bundle/chunks/chunk-GMWCTUPB.js +0 -2
  303. package/dist/bundle/chunks/chunk-JJ2YFCJF.js +0 -1547
  304. package/dist/bundle/chunks/chunk-OUXLLA64.js +0 -11
  305. package/dist/bundle/chunks/chunk-U6ZMQKGD.js +0 -50
  306. package/dist/bundle/chunks/chunk-UAQELI3K.js +0 -2
  307. package/dist/bundle/chunks/google-generative-ai-Q2K7FBDI.js +0 -2
  308. package/dist/bundle/chunks/google-vertex-7UJBF4S7.js +0 -2
  309. package/dist/bundle/chunks/mistral-conversations-4M6BZBX6.js +0 -5
  310. package/dist/bundle/chunks/openai-codex-responses-R6VYZTVY.js +0 -10
  311. package/dist/bundle/chunks/openai-completions-EKZT2IH2.js +0 -7
  312. package/dist/bundle/chunks/openai-responses-TFDINO6W.js +0 -2
  313. package/dist/utils/clipboard-native.d.ts +0 -11
  314. package/dist/utils/clipboard-native.d.ts.map +0 -1
  315. package/dist/utils/clipboard-native.js +0 -20
  316. package/dist/utils/clipboard-native.js.map +0 -1
  317. package/examples/extensions/kimi-deferred-tools.ts +0 -61
@@ -0,0 +1,209 @@
1
+ import * as path from "node:path";
2
+ import { getAuthCredential } from "../../cli/auth-command.js";
3
+ import { BUG_REPORT_CUSTOM_ENTRY_TYPE, bugReportArchiveFileName, collectBugReportDiagnostics, collectBugReportMetadata, writeBugReportArchive, } from "../../core/bug-report.js";
4
+ import { uploadBugReport } from "../../core/bug-report-upload.js";
5
+ import { clearCrashLog, readCrashLog } from "../../core/crash-log.js";
6
+ import { getRadiusGatewayUrl, RADIUS_PROVIDER_ID } from "../../core/radius.js";
7
+ import { serializeSessionBranch } from "../../core/session-export.js";
8
+ import { BorderedLoader } from "./components/bordered-loader.js";
9
+ import { ExtensionInputComponent } from "./components/extension-input.js";
10
+ import { ExtensionSelectorComponent } from "./components/extension-selector.js";
11
+ import { createShareTrailingEntries } from "./session-share.js";
12
+ import { theme } from "./theme/theme.js";
13
+ const DISCLAIMER = "This report goes to the Pi developers (Earendil) and is not shared publicly. It includes your pi version, operating system, the current model and provider configuration (without API keys), loaded extensions, settings, and provider error diagnostics from this session.";
14
+ const TRANSCRIPT_NOTE = "The transcript contains your messages, model output, tool calls and their results, including file contents and command output read during this session.";
15
+ /** Run the `/bug` flow: consent, optional summary, then upload or export. */
16
+ export async function reportBug(context, initialHint) {
17
+ const options = await promptForOptions(context, initialHint);
18
+ if (!options) {
19
+ context.showStatus("Bug report cancelled");
20
+ return;
21
+ }
22
+ let summary;
23
+ if (options.includeSummary) {
24
+ const loader = showLoader(context, `Writing summary with ${context.session.model?.name ?? "the current model"}...`);
25
+ try {
26
+ summary = await context.session.summarizeForBugReport({ hint: options.hint, signal: loader.signal });
27
+ }
28
+ catch (error) {
29
+ restoreEditor(context, loader);
30
+ if (loader.signal.aborted)
31
+ context.showStatus("Bug report cancelled");
32
+ else
33
+ context.showError(`Failed to write bug report summary: ${errorMessage(error)}`);
34
+ return;
35
+ }
36
+ restoreEditor(context, loader);
37
+ if (loader.signal.aborted) {
38
+ context.showStatus("Bug report cancelled");
39
+ return;
40
+ }
41
+ }
42
+ let bundle;
43
+ try {
44
+ bundle = buildBundle(context.session, options, summary);
45
+ }
46
+ catch (error) {
47
+ context.showError(`Failed to build bug report: ${errorMessage(error)}`);
48
+ return;
49
+ }
50
+ if (options.delivery === "upload") {
51
+ const failure = await upload(context, bundle);
52
+ if (failure === undefined)
53
+ return;
54
+ const fallback = await choose(context, "Upload failed", ["Export as Zip", "Cancel"], `${failure}\n\nExport the report as a zip archive instead?`);
55
+ if (fallback !== "Export as Zip") {
56
+ context.showStatus("Bug report cancelled");
57
+ return;
58
+ }
59
+ }
60
+ await exportZip(context, bundle);
61
+ }
62
+ async function promptForOptions(context, initialHint) {
63
+ const hint = await input(context, "Report a bug", `${DISCLAIMER}\n\nWhat went wrong? (optional)`, initialHint);
64
+ if (hint === null)
65
+ return undefined;
66
+ const transcript = await choose(context, "Include the session transcript?", ["Yes, include the transcript", "No"], TRANSCRIPT_NOTE);
67
+ if (!transcript)
68
+ return undefined;
69
+ const includeSession = transcript !== "No";
70
+ let includeSummary = false;
71
+ if (!includeSession) {
72
+ const model = context.session.model;
73
+ const summary = await choose(context, `Attach a summary written by ${model?.name ?? "the current model"} instead?`, ["Yes, generate a summary", "No"], `The transcript is sent to ${model?.provider ?? "your provider"} with your credentials and tokens. Only the generated summary is attached; the transcript stays on your machine.`);
74
+ if (!summary)
75
+ return undefined;
76
+ includeSummary = summary !== "No";
77
+ }
78
+ const description = hint.trim();
79
+ const delivery = await choose(context, "Bug report", ["Upload Report", "Export as Zip", "Cancel"], `Description: ${description || "none"}\nTranscript: ${includeSession ? "included" : "not included"}\nSummary: ${includeSummary ? `written by ${context.session.model?.name ?? "the current model"}` : "none"}\n\nUpload sends the report to ${new URL(getRadiusGatewayUrl()).host}. Export writes a zip archive to the current directory instead.`);
80
+ if (!delivery || delivery === "Cancel")
81
+ return undefined;
82
+ return {
83
+ hint: description || undefined,
84
+ includeSession,
85
+ includeSummary,
86
+ delivery: delivery === "Upload Report" ? "upload" : "zip",
87
+ };
88
+ }
89
+ function buildBundle(session, options, summary) {
90
+ const extensions = session.resourceLoader.getExtensions();
91
+ return {
92
+ metadata: collectBugReportMetadata({
93
+ hint: options.hint,
94
+ sessionId: session.sessionId,
95
+ cwd: session.sessionManager.getCwd(),
96
+ includeSession: options.includeSession,
97
+ includeSummary: summary !== undefined,
98
+ messageCount: session.messages.length,
99
+ model: session.model,
100
+ modelRuntime: session.modelRuntime,
101
+ thinkingLevel: session.thinkingLevel,
102
+ extensions: extensions.extensions,
103
+ extensionErrors: extensions.errors,
104
+ globalSettings: session.settingsManager.getGlobalSettings(),
105
+ projectSettings: session.settingsManager.getProjectSettings(),
106
+ }),
107
+ diagnostics: collectBugReportDiagnostics(session.sessionManager, readCrashLog()),
108
+ summary,
109
+ sessionJsonl: options.includeSession
110
+ ? serializeSessionBranch(session.sessionManager, (parentId, timestamp) => createShareTrailingEntries(session, parentId, timestamp))
111
+ : undefined,
112
+ };
113
+ }
114
+ async function upload(context, bundle) {
115
+ const loader = showLoader(context, "Uploading bug report...");
116
+ try {
117
+ const provider = context.session.modelRuntime.getProvider(RADIUS_PROVIDER_ID);
118
+ const token = provider
119
+ ? getAuthCredential(await context.session.modelRuntime.getAuth(RADIUS_PROVIDER_ID, { minOAuthValidityMs: 5 * 60_000 }))
120
+ : undefined;
121
+ const result = await uploadBugReport(bundle, { token, signal: loader.signal });
122
+ restoreEditor(context, loader);
123
+ recordInSession(context.session, bundle, { delivery: "upload" });
124
+ context.showStatus(`Bug report uploaded. Report ID: ${result.id}`);
125
+ return undefined;
126
+ }
127
+ catch (error) {
128
+ restoreEditor(context, loader);
129
+ if (loader.signal.aborted) {
130
+ context.showStatus("Bug report cancelled");
131
+ return undefined;
132
+ }
133
+ return errorMessage(error);
134
+ }
135
+ }
136
+ async function exportZip(context, bundle) {
137
+ const archivePath = path.join(process.cwd(), bugReportArchiveFileName(bundle.metadata.id));
138
+ try {
139
+ await writeBugReportArchive(bundle, archivePath);
140
+ }
141
+ catch (error) {
142
+ context.showError(`Failed to write bug report: ${errorMessage(error)}`);
143
+ return;
144
+ }
145
+ recordInSession(context.session, bundle, { delivery: "zip", path: archivePath });
146
+ context.showStatus(`Bug report exported to: ${archivePath}\nReport ID: ${bundle.metadata.id}`);
147
+ }
148
+ function recordInSession(session, bundle, delivery) {
149
+ session.sessionManager.appendCustomEntry(BUG_REPORT_CUSTOM_ENTRY_TYPE, {
150
+ id: bundle.metadata.id,
151
+ createdAt: bundle.metadata.createdAt,
152
+ hint: bundle.metadata.hint,
153
+ sessionIncluded: bundle.metadata.session.included,
154
+ summaryIncluded: bundle.metadata.session.summaryIncluded,
155
+ ...delivery,
156
+ });
157
+ if (bundle.diagnostics.crashes.length > 0)
158
+ clearCrashLog();
159
+ }
160
+ function input(context, title, description, initialValue) {
161
+ return new Promise((resolve) => {
162
+ let component;
163
+ const finish = (value) => {
164
+ restoreEditor(context, component);
165
+ resolve(value);
166
+ };
167
+ component = new ExtensionInputComponent(title, undefined, (value) => finish(value), () => finish(null), {
168
+ initialValue,
169
+ description,
170
+ });
171
+ showOverlay(context, component);
172
+ });
173
+ }
174
+ function choose(context, title, options, description) {
175
+ return new Promise((resolve) => {
176
+ let component;
177
+ const finish = (value) => {
178
+ restoreEditor(context, component);
179
+ resolve(value);
180
+ };
181
+ component = new ExtensionSelectorComponent(title, options, finish, () => finish(), {
182
+ tui: context.ui,
183
+ description,
184
+ });
185
+ showOverlay(context, component);
186
+ });
187
+ }
188
+ function showLoader(context, message) {
189
+ const loader = new BorderedLoader(context.ui, theme, message);
190
+ showOverlay(context, loader);
191
+ return loader;
192
+ }
193
+ function showOverlay(context, component) {
194
+ context.editorContainer.clear();
195
+ context.editorContainer.addChild(component);
196
+ context.ui.setFocus(component);
197
+ context.ui.requestRender();
198
+ }
199
+ function restoreEditor(context, component) {
200
+ component.dispose?.();
201
+ context.editorContainer.clear();
202
+ context.editorContainer.addChild(context.editor);
203
+ context.ui.setFocus(context.editor);
204
+ context.ui.requestRender();
205
+ }
206
+ function errorMessage(error) {
207
+ return error instanceof Error ? error.message : "Unknown error";
208
+ }
209
+ //# sourceMappingURL=bug-report.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bug-report.js","sourceRoot":"","sources":["../../../src/modes/interactive/bug-report.ts"],"names":[],"mappings":"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","sourcesContent":["import * as path from \"node:path\";\nimport type { Container, EditorComponent, TUI } from \"@earendil-works/pi-tui\";\nimport { getAuthCredential } from \"../../cli/auth-command.ts\";\nimport type { AgentSession } from \"../../core/agent-session.ts\";\nimport {\n\tBUG_REPORT_CUSTOM_ENTRY_TYPE,\n\ttype BugReportBundle,\n\ttype BugReportSessionEntryData,\n\tbugReportArchiveFileName,\n\tcollectBugReportDiagnostics,\n\tcollectBugReportMetadata,\n\twriteBugReportArchive,\n} from \"../../core/bug-report.ts\";\nimport { uploadBugReport } from \"../../core/bug-report-upload.ts\";\nimport { clearCrashLog, readCrashLog } from \"../../core/crash-log.ts\";\nimport { getRadiusGatewayUrl, RADIUS_PROVIDER_ID } from \"../../core/radius.ts\";\nimport { serializeSessionBranch } from \"../../core/session-export.ts\";\nimport { BorderedLoader } from \"./components/bordered-loader.ts\";\nimport { ExtensionInputComponent } from \"./components/extension-input.ts\";\nimport { ExtensionSelectorComponent } from \"./components/extension-selector.ts\";\nimport { createShareTrailingEntries } from \"./session-share.ts\";\nimport { theme } from \"./theme/theme.ts\";\n\ninterface BugReportContext {\n\tsession: AgentSession;\n\tui: TUI;\n\teditorContainer: Container;\n\teditor: EditorComponent;\n\tshowStatus: (message: string) => void;\n\tshowError: (message: string) => void;\n}\n\ninterface BugReportOptions {\n\thint?: string;\n\tincludeSession: boolean;\n\tincludeSummary: boolean;\n\tdelivery: \"upload\" | \"zip\";\n}\n\ntype Overlay = Container & { dispose?: () => void };\n\nconst DISCLAIMER =\n\t\"This report goes to the Pi developers (Earendil) and is not shared publicly. It includes your pi version, operating system, the current model and provider configuration (without API keys), loaded extensions, settings, and provider error diagnostics from this session.\";\nconst TRANSCRIPT_NOTE =\n\t\"The transcript contains your messages, model output, tool calls and their results, including file contents and command output read during this session.\";\n\n/** Run the `/bug` flow: consent, optional summary, then upload or export. */\nexport async function reportBug(context: BugReportContext, initialHint?: string): Promise<void> {\n\tconst options = await promptForOptions(context, initialHint);\n\tif (!options) {\n\t\tcontext.showStatus(\"Bug report cancelled\");\n\t\treturn;\n\t}\n\n\tlet summary: string | undefined;\n\tif (options.includeSummary) {\n\t\tconst loader = showLoader(\n\t\t\tcontext,\n\t\t\t`Writing summary with ${context.session.model?.name ?? \"the current model\"}...`,\n\t\t);\n\t\ttry {\n\t\t\tsummary = await context.session.summarizeForBugReport({ hint: options.hint, signal: loader.signal });\n\t\t} catch (error: unknown) {\n\t\t\trestoreEditor(context, loader);\n\t\t\tif (loader.signal.aborted) context.showStatus(\"Bug report cancelled\");\n\t\t\telse context.showError(`Failed to write bug report summary: ${errorMessage(error)}`);\n\t\t\treturn;\n\t\t}\n\t\trestoreEditor(context, loader);\n\t\tif (loader.signal.aborted) {\n\t\t\tcontext.showStatus(\"Bug report cancelled\");\n\t\t\treturn;\n\t\t}\n\t}\n\n\tlet bundle: BugReportBundle;\n\ttry {\n\t\tbundle = buildBundle(context.session, options, summary);\n\t} catch (error: unknown) {\n\t\tcontext.showError(`Failed to build bug report: ${errorMessage(error)}`);\n\t\treturn;\n\t}\n\n\tif (options.delivery === \"upload\") {\n\t\tconst failure = await upload(context, bundle);\n\t\tif (failure === undefined) return;\n\t\tconst fallback = await choose(\n\t\t\tcontext,\n\t\t\t\"Upload failed\",\n\t\t\t[\"Export as Zip\", \"Cancel\"],\n\t\t\t`${failure}\\n\\nExport the report as a zip archive instead?`,\n\t\t);\n\t\tif (fallback !== \"Export as Zip\") {\n\t\t\tcontext.showStatus(\"Bug report cancelled\");\n\t\t\treturn;\n\t\t}\n\t}\n\tawait exportZip(context, bundle);\n}\n\nasync function promptForOptions(\n\tcontext: BugReportContext,\n\tinitialHint: string | undefined,\n): Promise<BugReportOptions | undefined> {\n\tconst hint = await input(context, \"Report a bug\", `${DISCLAIMER}\\n\\nWhat went wrong? (optional)`, initialHint);\n\tif (hint === null) return undefined;\n\tconst transcript = await choose(\n\t\tcontext,\n\t\t\"Include the session transcript?\",\n\t\t[\"Yes, include the transcript\", \"No\"],\n\t\tTRANSCRIPT_NOTE,\n\t);\n\tif (!transcript) return undefined;\n\tconst includeSession = transcript !== \"No\";\n\tlet includeSummary = false;\n\tif (!includeSession) {\n\t\tconst model = context.session.model;\n\t\tconst summary = await choose(\n\t\t\tcontext,\n\t\t\t`Attach a summary written by ${model?.name ?? \"the current model\"} instead?`,\n\t\t\t[\"Yes, generate a summary\", \"No\"],\n\t\t\t`The transcript is sent to ${model?.provider ?? \"your provider\"} with your credentials and tokens. Only the generated summary is attached; the transcript stays on your machine.`,\n\t\t);\n\t\tif (!summary) return undefined;\n\t\tincludeSummary = summary !== \"No\";\n\t}\n\tconst description = hint.trim();\n\tconst delivery = await choose(\n\t\tcontext,\n\t\t\"Bug report\",\n\t\t[\"Upload Report\", \"Export as Zip\", \"Cancel\"],\n\t\t`Description: ${description || \"none\"}\\nTranscript: ${includeSession ? \"included\" : \"not included\"}\\nSummary: ${includeSummary ? `written by ${context.session.model?.name ?? \"the current model\"}` : \"none\"}\\n\\nUpload sends the report to ${new URL(getRadiusGatewayUrl()).host}. Export writes a zip archive to the current directory instead.`,\n\t);\n\tif (!delivery || delivery === \"Cancel\") return undefined;\n\treturn {\n\t\thint: description || undefined,\n\t\tincludeSession,\n\t\tincludeSummary,\n\t\tdelivery: delivery === \"Upload Report\" ? \"upload\" : \"zip\",\n\t};\n}\n\nfunction buildBundle(session: AgentSession, options: BugReportOptions, summary: string | undefined): BugReportBundle {\n\tconst extensions = session.resourceLoader.getExtensions();\n\treturn {\n\t\tmetadata: collectBugReportMetadata({\n\t\t\thint: options.hint,\n\t\t\tsessionId: session.sessionId,\n\t\t\tcwd: session.sessionManager.getCwd(),\n\t\t\tincludeSession: options.includeSession,\n\t\t\tincludeSummary: summary !== undefined,\n\t\t\tmessageCount: session.messages.length,\n\t\t\tmodel: session.model,\n\t\t\tmodelRuntime: session.modelRuntime,\n\t\t\tthinkingLevel: session.thinkingLevel,\n\t\t\textensions: extensions.extensions,\n\t\t\textensionErrors: extensions.errors,\n\t\t\tglobalSettings: session.settingsManager.getGlobalSettings(),\n\t\t\tprojectSettings: session.settingsManager.getProjectSettings(),\n\t\t}),\n\t\tdiagnostics: collectBugReportDiagnostics(session.sessionManager, readCrashLog()),\n\t\tsummary,\n\t\tsessionJsonl: options.includeSession\n\t\t\t? serializeSessionBranch(session.sessionManager, (parentId, timestamp) =>\n\t\t\t\t\tcreateShareTrailingEntries(session, parentId, timestamp),\n\t\t\t\t)\n\t\t\t: undefined,\n\t};\n}\n\nasync function upload(context: BugReportContext, bundle: BugReportBundle): Promise<string | undefined> {\n\tconst loader = showLoader(context, \"Uploading bug report...\");\n\ttry {\n\t\tconst provider = context.session.modelRuntime.getProvider(RADIUS_PROVIDER_ID);\n\t\tconst token = provider\n\t\t\t? getAuthCredential(\n\t\t\t\t\tawait context.session.modelRuntime.getAuth(RADIUS_PROVIDER_ID, { minOAuthValidityMs: 5 * 60_000 }),\n\t\t\t\t)\n\t\t\t: undefined;\n\t\tconst result = await uploadBugReport(bundle, { token, signal: loader.signal });\n\t\trestoreEditor(context, loader);\n\t\trecordInSession(context.session, bundle, { delivery: \"upload\" });\n\t\tcontext.showStatus(`Bug report uploaded. Report ID: ${result.id}`);\n\t\treturn undefined;\n\t} catch (error: unknown) {\n\t\trestoreEditor(context, loader);\n\t\tif (loader.signal.aborted) {\n\t\t\tcontext.showStatus(\"Bug report cancelled\");\n\t\t\treturn undefined;\n\t\t}\n\t\treturn errorMessage(error);\n\t}\n}\n\nasync function exportZip(context: BugReportContext, bundle: BugReportBundle): Promise<void> {\n\tconst archivePath = path.join(process.cwd(), bugReportArchiveFileName(bundle.metadata.id));\n\ttry {\n\t\tawait writeBugReportArchive(bundle, archivePath);\n\t} catch (error: unknown) {\n\t\tcontext.showError(`Failed to write bug report: ${errorMessage(error)}`);\n\t\treturn;\n\t}\n\trecordInSession(context.session, bundle, { delivery: \"zip\", path: archivePath });\n\tcontext.showStatus(`Bug report exported to: ${archivePath}\\nReport ID: ${bundle.metadata.id}`);\n}\n\nfunction recordInSession(\n\tsession: AgentSession,\n\tbundle: BugReportBundle,\n\tdelivery: Pick<BugReportSessionEntryData, \"delivery\" | \"path\">,\n): void {\n\tsession.sessionManager.appendCustomEntry(BUG_REPORT_CUSTOM_ENTRY_TYPE, {\n\t\tid: bundle.metadata.id,\n\t\tcreatedAt: bundle.metadata.createdAt,\n\t\thint: bundle.metadata.hint,\n\t\tsessionIncluded: bundle.metadata.session.included,\n\t\tsummaryIncluded: bundle.metadata.session.summaryIncluded,\n\t\t...delivery,\n\t} satisfies BugReportSessionEntryData);\n\tif (bundle.diagnostics.crashes.length > 0) clearCrashLog();\n}\n\nfunction input(\n\tcontext: BugReportContext,\n\ttitle: string,\n\tdescription: string,\n\tinitialValue?: string,\n): Promise<string | null> {\n\treturn new Promise((resolve) => {\n\t\tlet component: ExtensionInputComponent;\n\t\tconst finish = (value: string | null) => {\n\t\t\trestoreEditor(context, component);\n\t\t\tresolve(value);\n\t\t};\n\t\tcomponent = new ExtensionInputComponent(\n\t\t\ttitle,\n\t\t\tundefined,\n\t\t\t(value) => finish(value),\n\t\t\t() => finish(null),\n\t\t\t{\n\t\t\t\tinitialValue,\n\t\t\t\tdescription,\n\t\t\t},\n\t\t);\n\t\tshowOverlay(context, component);\n\t});\n}\n\nfunction choose(\n\tcontext: BugReportContext,\n\ttitle: string,\n\toptions: string[],\n\tdescription?: string,\n): Promise<string | undefined> {\n\treturn new Promise((resolve) => {\n\t\tlet component: ExtensionSelectorComponent;\n\t\tconst finish = (value?: string) => {\n\t\t\trestoreEditor(context, component);\n\t\t\tresolve(value);\n\t\t};\n\t\tcomponent = new ExtensionSelectorComponent(title, options, finish, () => finish(), {\n\t\t\ttui: context.ui,\n\t\t\tdescription,\n\t\t});\n\t\tshowOverlay(context, component);\n\t});\n}\n\nfunction showLoader(context: BugReportContext, message: string): BorderedLoader {\n\tconst loader = new BorderedLoader(context.ui, theme, message);\n\tshowOverlay(context, loader);\n\treturn loader;\n}\n\nfunction showOverlay(context: BugReportContext, component: Overlay): void {\n\tcontext.editorContainer.clear();\n\tcontext.editorContainer.addChild(component);\n\tcontext.ui.setFocus(component);\n\tcontext.ui.requestRender();\n}\n\nfunction restoreEditor(context: BugReportContext, component: Overlay): void {\n\tcomponent.dispose?.();\n\tcontext.editorContainer.clear();\n\tcontext.editorContainer.addChild(context.editor);\n\tcontext.ui.setFocus(context.editor);\n\tcontext.ui.requestRender();\n}\n\nfunction errorMessage(error: unknown): string {\n\treturn error instanceof Error ? error.message : \"Unknown error\";\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"chat-viewport.d.ts","sourceRoot":"","sources":["../../../src/modes/interactive/chat-viewport.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,UAAU,EAAE,KAAK,mBAAmB,EAAU,MAAM,wBAAwB,CAAC;AAEtG,MAAM,WAAW,mBAAmB;IACnC,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC;IAC7B,QAAQ,CAAC,eAAe,EAAE,SAAS,CAAC;IACpC,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,QAAQ,CAAC,YAAY,CAAC,EAAE,SAAS,CAAC;IAClC,QAAQ,CAAC,YAAY,CAAC,EAAE,SAAS,CAAC;IAClC,QAAQ,CAAC,SAAS,CAAC,EAAE,mBAAmB,CAAC;IACzC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IACxD,QAAQ,CAAC,mBAAmB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;CACxD;AAED,MAAM,WAAW,YAAY;IAC5B,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;CAChC;AAED,gEAAgE;AAChE,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,mBAAmB,GAAG,YAAY,CAwB7E","sourcesContent":["import { type Component, ScrollView, type ScrollViewScrollbar, VStack } from \"@earendil-works/pi-tui\";\n\nexport interface ChatViewportOptions {\n\treadonly document: Component;\n\treadonly pendingMessages: Component;\n\treadonly status: Component;\n\treadonly editor: Component;\n\treadonly footer: Component;\n\treadonly widgetsAbove?: Component;\n\treadonly widgetsBelow?: Component;\n\treadonly scrollbar?: ScrollViewScrollbar;\n\treadonly scrollbarTrackStyle?: (text: string) => string;\n\treadonly scrollbarThumbStyle?: (text: string) => string;\n}\n\nexport interface ChatViewport {\n\treadonly root: Component;\n\treadonly transcript: ScrollView;\n}\n\n/** Shared fullscreen transcript and fixed input-dock layout. */\nexport function createChatViewport(options: ChatViewportOptions): ChatViewport {\n\tconst transcript = new ScrollView(options.document, {\n\t\tfollow: \"end\",\n\t\tprimary: true,\n\t\toverscroll: \"chain\",\n\t\tscrollbar: options.scrollbar ?? \"auto\",\n\t\t...(options.scrollbarTrackStyle === undefined ? {} : { scrollbarTrackStyle: options.scrollbarTrackStyle }),\n\t\t...(options.scrollbarThumbStyle === undefined ? {} : { scrollbarThumbStyle: options.scrollbarThumbStyle }),\n\t});\n\tconst dock = new VStack([\n\t\t{ component: options.pendingMessages, shrink: 1, minSize: 0 },\n\t\t{ component: options.status, shrink: 1, minSize: 0 },\n\t\t...(options.widgetsAbove === undefined ? [] : [{ component: options.widgetsAbove, shrink: 1, minSize: 0 }]),\n\t\t{ component: options.editor, shrink: 1, minSize: 3 },\n\t\t...(options.widgetsBelow === undefined ? [] : [{ component: options.widgetsBelow, shrink: 1, minSize: 0 }]),\n\t\t{ component: options.footer, shrink: 1, minSize: 1 },\n\t]);\n\treturn {\n\t\ttranscript,\n\t\troot: new VStack([\n\t\t\t{ component: transcript, basis: 0, grow: 1, shrink: 1, minSize: 1 },\n\t\t\t{ component: dock, basis: \"auto\", grow: 0, shrink: 1, minSize: 1 },\n\t\t]),\n\t};\n}\n"]}
1
+ {"version":3,"file":"chat-viewport.d.ts","sourceRoot":"","sources":["../../../src/modes/interactive/chat-viewport.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,UAAU,EAAE,KAAK,mBAAmB,EAAU,MAAM,wBAAwB,CAAC;AAEtG,MAAM,WAAW,mBAAmB;IACnC,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC;IAC7B,QAAQ,CAAC,eAAe,EAAE,SAAS,CAAC;IACpC,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,QAAQ,CAAC,YAAY,CAAC,EAAE,SAAS,CAAC;IAClC,QAAQ,CAAC,YAAY,CAAC,EAAE,SAAS,CAAC;IAClC,QAAQ,CAAC,SAAS,CAAC,EAAE,mBAAmB,CAAC;IACzC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IACxD,QAAQ,CAAC,mBAAmB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;CACxD;AAED,MAAM,WAAW,YAAY;IAC5B,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;CAChC;AAED,gEAAgE;AAChE,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,mBAAmB,GAAG,YAAY,CAwB7E","sourcesContent":["import { type Component, ScrollView, type ScrollViewScrollbar, VStack } from \"@earendil-works/pi-tui\";\n\nexport interface ChatViewportOptions {\n\treadonly document: Component;\n\treadonly pendingMessages: Component;\n\treadonly status: Component;\n\treadonly editor: Component;\n\treadonly footer: Component;\n\treadonly widgetsAbove?: Component;\n\treadonly widgetsBelow?: Component;\n\treadonly scrollbar?: ScrollViewScrollbar;\n\treadonly scrollbarTrackStyle?: (text: string) => string;\n\treadonly scrollbarThumbStyle?: (text: string) => string;\n}\n\nexport interface ChatViewport {\n\treadonly root: Component;\n\treadonly transcript: ScrollView;\n}\n\n/** Shared fullscreen transcript and fixed input-dock layout. */\nexport function createChatViewport(options: ChatViewportOptions): ChatViewport {\n\tconst transcript = new ScrollView(options.document, {\n\t\tfollow: \"end\",\n\t\tprimary: true,\n\t\toverscroll: \"chain\",\n\t\tscrollbar: options.scrollbar ?? \"auto\",\n\t\t...(options.scrollbarTrackStyle === undefined ? {} : { scrollbarTrackStyle: options.scrollbarTrackStyle }),\n\t\t...(options.scrollbarThumbStyle === undefined ? {} : { scrollbarThumbStyle: options.scrollbarThumbStyle }),\n\t});\n\tconst dock = new VStack([\n\t\t{ component: options.pendingMessages, shrink: 1, minSize: 0 },\n\t\t{ component: options.status, shrink: 1, minSize: 0 },\n\t\t...(options.widgetsAbove === undefined ? [] : [{ component: options.widgetsAbove, shrink: 1, minSize: 0 }]),\n\t\t{ component: options.editor, shrink: 1, minSize: 3 },\n\t\t...(options.widgetsBelow === undefined ? [] : [{ component: options.widgetsBelow, shrink: 1, minSize: 0 }]),\n\t\t{ component: options.footer, shrink: 1, minSize: 0 },\n\t]);\n\treturn {\n\t\ttranscript,\n\t\troot: new VStack([\n\t\t\t{ component: transcript, basis: 0, grow: 1, shrink: 1, minSize: 1 },\n\t\t\t{ component: dock, basis: \"auto\", grow: 0, shrink: 1, minSize: 1 },\n\t\t]),\n\t};\n}\n"]}
@@ -15,7 +15,7 @@ export function createChatViewport(options) {
15
15
  ...(options.widgetsAbove === undefined ? [] : [{ component: options.widgetsAbove, shrink: 1, minSize: 0 }]),
16
16
  { component: options.editor, shrink: 1, minSize: 3 },
17
17
  ...(options.widgetsBelow === undefined ? [] : [{ component: options.widgetsBelow, shrink: 1, minSize: 0 }]),
18
- { component: options.footer, shrink: 1, minSize: 1 },
18
+ { component: options.footer, shrink: 1, minSize: 0 },
19
19
  ]);
20
20
  return {
21
21
  transcript,
@@ -1 +1 @@
1
- {"version":3,"file":"chat-viewport.js","sourceRoot":"","sources":["../../../src/modes/interactive/chat-viewport.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,UAAU,EAA4B,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAoBtG,gEAAgE;AAChE,MAAM,UAAU,kBAAkB,CAAC,OAA4B,EAAgB;IAC9E,MAAM,UAAU,GAAG,IAAI,UAAU,CAAC,OAAO,CAAC,QAAQ,EAAE;QACnD,MAAM,EAAE,KAAK;QACb,OAAO,EAAE,IAAI;QACb,UAAU,EAAE,OAAO;QACnB,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,MAAM;QACtC,GAAG,CAAC,OAAO,CAAC,mBAAmB,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,mBAAmB,EAAE,OAAO,CAAC,mBAAmB,EAAE,CAAC;QAC1G,GAAG,CAAC,OAAO,CAAC,mBAAmB,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,mBAAmB,EAAE,OAAO,CAAC,mBAAmB,EAAE,CAAC;KAC1G,CAAC,CAAC;IACH,MAAM,IAAI,GAAG,IAAI,MAAM,CAAC;QACvB,EAAE,SAAS,EAAE,OAAO,CAAC,eAAe,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE;QAC7D,EAAE,SAAS,EAAE,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE;QACpD,GAAG,CAAC,OAAO,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,YAAY,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;QAC3G,EAAE,SAAS,EAAE,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE;QACpD,GAAG,CAAC,OAAO,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,YAAY,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;QAC3G,EAAE,SAAS,EAAE,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE;KACpD,CAAC,CAAC;IACH,OAAO;QACN,UAAU;QACV,IAAI,EAAE,IAAI,MAAM,CAAC;YAChB,EAAE,SAAS,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE;YACnE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE;SAClE,CAAC;KACF,CAAC;AAAA,CACF","sourcesContent":["import { type Component, ScrollView, type ScrollViewScrollbar, VStack } from \"@earendil-works/pi-tui\";\n\nexport interface ChatViewportOptions {\n\treadonly document: Component;\n\treadonly pendingMessages: Component;\n\treadonly status: Component;\n\treadonly editor: Component;\n\treadonly footer: Component;\n\treadonly widgetsAbove?: Component;\n\treadonly widgetsBelow?: Component;\n\treadonly scrollbar?: ScrollViewScrollbar;\n\treadonly scrollbarTrackStyle?: (text: string) => string;\n\treadonly scrollbarThumbStyle?: (text: string) => string;\n}\n\nexport interface ChatViewport {\n\treadonly root: Component;\n\treadonly transcript: ScrollView;\n}\n\n/** Shared fullscreen transcript and fixed input-dock layout. */\nexport function createChatViewport(options: ChatViewportOptions): ChatViewport {\n\tconst transcript = new ScrollView(options.document, {\n\t\tfollow: \"end\",\n\t\tprimary: true,\n\t\toverscroll: \"chain\",\n\t\tscrollbar: options.scrollbar ?? \"auto\",\n\t\t...(options.scrollbarTrackStyle === undefined ? {} : { scrollbarTrackStyle: options.scrollbarTrackStyle }),\n\t\t...(options.scrollbarThumbStyle === undefined ? {} : { scrollbarThumbStyle: options.scrollbarThumbStyle }),\n\t});\n\tconst dock = new VStack([\n\t\t{ component: options.pendingMessages, shrink: 1, minSize: 0 },\n\t\t{ component: options.status, shrink: 1, minSize: 0 },\n\t\t...(options.widgetsAbove === undefined ? [] : [{ component: options.widgetsAbove, shrink: 1, minSize: 0 }]),\n\t\t{ component: options.editor, shrink: 1, minSize: 3 },\n\t\t...(options.widgetsBelow === undefined ? [] : [{ component: options.widgetsBelow, shrink: 1, minSize: 0 }]),\n\t\t{ component: options.footer, shrink: 1, minSize: 1 },\n\t]);\n\treturn {\n\t\ttranscript,\n\t\troot: new VStack([\n\t\t\t{ component: transcript, basis: 0, grow: 1, shrink: 1, minSize: 1 },\n\t\t\t{ component: dock, basis: \"auto\", grow: 0, shrink: 1, minSize: 1 },\n\t\t]),\n\t};\n}\n"]}
1
+ {"version":3,"file":"chat-viewport.js","sourceRoot":"","sources":["../../../src/modes/interactive/chat-viewport.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,UAAU,EAA4B,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAoBtG,gEAAgE;AAChE,MAAM,UAAU,kBAAkB,CAAC,OAA4B,EAAgB;IAC9E,MAAM,UAAU,GAAG,IAAI,UAAU,CAAC,OAAO,CAAC,QAAQ,EAAE;QACnD,MAAM,EAAE,KAAK;QACb,OAAO,EAAE,IAAI;QACb,UAAU,EAAE,OAAO;QACnB,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,MAAM;QACtC,GAAG,CAAC,OAAO,CAAC,mBAAmB,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,mBAAmB,EAAE,OAAO,CAAC,mBAAmB,EAAE,CAAC;QAC1G,GAAG,CAAC,OAAO,CAAC,mBAAmB,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,mBAAmB,EAAE,OAAO,CAAC,mBAAmB,EAAE,CAAC;KAC1G,CAAC,CAAC;IACH,MAAM,IAAI,GAAG,IAAI,MAAM,CAAC;QACvB,EAAE,SAAS,EAAE,OAAO,CAAC,eAAe,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE;QAC7D,EAAE,SAAS,EAAE,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE;QACpD,GAAG,CAAC,OAAO,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,YAAY,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;QAC3G,EAAE,SAAS,EAAE,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE;QACpD,GAAG,CAAC,OAAO,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,YAAY,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;QAC3G,EAAE,SAAS,EAAE,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE;KACpD,CAAC,CAAC;IACH,OAAO;QACN,UAAU;QACV,IAAI,EAAE,IAAI,MAAM,CAAC;YAChB,EAAE,SAAS,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE;YACnE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE;SAClE,CAAC;KACF,CAAC;AAAA,CACF","sourcesContent":["import { type Component, ScrollView, type ScrollViewScrollbar, VStack } from \"@earendil-works/pi-tui\";\n\nexport interface ChatViewportOptions {\n\treadonly document: Component;\n\treadonly pendingMessages: Component;\n\treadonly status: Component;\n\treadonly editor: Component;\n\treadonly footer: Component;\n\treadonly widgetsAbove?: Component;\n\treadonly widgetsBelow?: Component;\n\treadonly scrollbar?: ScrollViewScrollbar;\n\treadonly scrollbarTrackStyle?: (text: string) => string;\n\treadonly scrollbarThumbStyle?: (text: string) => string;\n}\n\nexport interface ChatViewport {\n\treadonly root: Component;\n\treadonly transcript: ScrollView;\n}\n\n/** Shared fullscreen transcript and fixed input-dock layout. */\nexport function createChatViewport(options: ChatViewportOptions): ChatViewport {\n\tconst transcript = new ScrollView(options.document, {\n\t\tfollow: \"end\",\n\t\tprimary: true,\n\t\toverscroll: \"chain\",\n\t\tscrollbar: options.scrollbar ?? \"auto\",\n\t\t...(options.scrollbarTrackStyle === undefined ? {} : { scrollbarTrackStyle: options.scrollbarTrackStyle }),\n\t\t...(options.scrollbarThumbStyle === undefined ? {} : { scrollbarThumbStyle: options.scrollbarThumbStyle }),\n\t});\n\tconst dock = new VStack([\n\t\t{ component: options.pendingMessages, shrink: 1, minSize: 0 },\n\t\t{ component: options.status, shrink: 1, minSize: 0 },\n\t\t...(options.widgetsAbove === undefined ? [] : [{ component: options.widgetsAbove, shrink: 1, minSize: 0 }]),\n\t\t{ component: options.editor, shrink: 1, minSize: 3 },\n\t\t...(options.widgetsBelow === undefined ? [] : [{ component: options.widgetsBelow, shrink: 1, minSize: 0 }]),\n\t\t{ component: options.footer, shrink: 1, minSize: 0 },\n\t]);\n\treturn {\n\t\ttranscript,\n\t\troot: new VStack([\n\t\t\t{ component: transcript, basis: 0, grow: 1, shrink: 1, minSize: 1 },\n\t\t\t{ component: dock, basis: \"auto\", grow: 0, shrink: 1, minSize: 1 },\n\t\t]),\n\t};\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"branch-summary-message.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/branch-summary-message.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAY,KAAK,aAAa,EAAgB,MAAM,wBAAwB,CAAC;AACzF,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAItE;;;GAGG;AACH,qBAAa,6BAA8B,SAAQ,GAAG;IACrD,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,OAAO,CAAuB;IACtC,OAAO,CAAC,aAAa,CAAgB;IAErC,YAAY,OAAO,EAAE,oBAAoB,EAAE,aAAa,GAAE,aAAkC,EAK3F;IAED,WAAW,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAGnC;IAEQ,UAAU,IAAI,IAAI,CAG1B;IAED,OAAO,CAAC,aAAa;CA0BrB","sourcesContent":["import { Box, Markdown, type MarkdownTheme, Spacer, Text } from \"@earendil-works/pi-tui\";\nimport type { BranchSummaryMessage } from \"../../../core/messages.ts\";\nimport { getMarkdownTheme, theme } from \"../theme/theme.ts\";\nimport { keyText } from \"./keybinding-hints.ts\";\n\n/**\n * Component that renders a branch summary message with collapsed/expanded state.\n * Uses same background color as custom messages for visual consistency.\n */\nexport class BranchSummaryMessageComponent extends Box {\n\tprivate expanded = false;\n\tprivate message: BranchSummaryMessage;\n\tprivate markdownTheme: MarkdownTheme;\n\n\tconstructor(message: BranchSummaryMessage, markdownTheme: MarkdownTheme = getMarkdownTheme()) {\n\t\tsuper(1, 1, (t) => theme.bg(\"customMessageBg\", t));\n\t\tthis.message = message;\n\t\tthis.markdownTheme = markdownTheme;\n\t\tthis.updateDisplay();\n\t}\n\n\tsetExpanded(expanded: boolean): void {\n\t\tthis.expanded = expanded;\n\t\tthis.updateDisplay();\n\t}\n\n\toverride invalidate(): void {\n\t\tsuper.invalidate();\n\t\tthis.updateDisplay();\n\t}\n\n\tprivate updateDisplay(): void {\n\t\tthis.clear();\n\n\t\tconst label = theme.fg(\"customMessageLabel\", `\\x1b[1m[branch]\\x1b[22m`);\n\t\tthis.addChild(new Text(label, 0, 0));\n\t\tthis.addChild(new Spacer(1));\n\n\t\tif (this.expanded) {\n\t\t\tconst header = \"**Branch Summary**\\n\\n\";\n\t\t\tthis.addChild(\n\t\t\t\tnew Markdown(header + this.message.summary, 0, 0, this.markdownTheme, {\n\t\t\t\t\tcolor: (text: string) => theme.fg(\"customMessageText\", text),\n\t\t\t\t}),\n\t\t\t);\n\t\t} else {\n\t\t\tthis.addChild(\n\t\t\t\tnew Text(\n\t\t\t\t\ttheme.fg(\"customMessageText\", \"Branch summary (\") +\n\t\t\t\t\t\ttheme.fg(\"dim\", keyText(\"app.tools.expand\")) +\n\t\t\t\t\t\ttheme.fg(\"customMessageText\", \" to expand)\"),\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t}\n}\n"]}
1
+ {"version":3,"file":"branch-summary-message.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/branch-summary-message.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAuB,KAAK,aAAa,EAA6B,MAAM,wBAAwB,CAAC;AACjH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAItE;;;GAGG;AACH,qBAAa,6BAA8B,SAAQ,GAAG;IACrD,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,OAAO,CAAuB;IACtC,OAAO,CAAC,aAAa,CAAgB;IAErC,YAAY,OAAO,EAAE,oBAAoB,EAAE,aAAa,GAAE,aAAkC,EAK3F;IAED,WAAW,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAGnC;IAEQ,UAAU,IAAI,IAAI,CAG1B;IAED,OAAO,CAAC,aAAa;CAmCrB","sourcesContent":["import { Box, Container, Markdown, type MarkdownTheme, MouseRegion, Spacer, Text } from \"@earendil-works/pi-tui\";\nimport type { BranchSummaryMessage } from \"../../../core/messages.ts\";\nimport { getMarkdownTheme, theme } from \"../theme/theme.ts\";\nimport { keyText } from \"./keybinding-hints.ts\";\n\n/**\n * Component that renders a branch summary message with collapsed/expanded state.\n * Uses same background color as custom messages for visual consistency.\n */\nexport class BranchSummaryMessageComponent extends Box {\n\tprivate expanded = false;\n\tprivate message: BranchSummaryMessage;\n\tprivate markdownTheme: MarkdownTheme;\n\n\tconstructor(message: BranchSummaryMessage, markdownTheme: MarkdownTheme = getMarkdownTheme()) {\n\t\tsuper(1, 1, (t) => theme.bg(\"customMessageBg\", t));\n\t\tthis.message = message;\n\t\tthis.markdownTheme = markdownTheme;\n\t\tthis.updateDisplay();\n\t}\n\n\tsetExpanded(expanded: boolean): void {\n\t\tthis.expanded = expanded;\n\t\tthis.updateDisplay();\n\t}\n\n\toverride invalidate(): void {\n\t\tsuper.invalidate();\n\t\tthis.updateDisplay();\n\t}\n\n\tprivate updateDisplay(): void {\n\t\tthis.clear();\n\t\tconst content = new Container();\n\n\t\tconst label = theme.fg(\"customMessageLabel\", `\\x1b[1m[branch]\\x1b[22m`);\n\t\tcontent.addChild(new Text(label, 0, 0));\n\t\tcontent.addChild(new Spacer(1));\n\n\t\tif (this.expanded) {\n\t\t\tconst header = \"**Branch Summary**\\n\\n\";\n\t\t\tcontent.addChild(\n\t\t\t\tnew Markdown(header + this.message.summary, 0, 0, this.markdownTheme, {\n\t\t\t\t\tcolor: (text: string) => theme.fg(\"customMessageText\", text),\n\t\t\t\t}),\n\t\t\t);\n\t\t} else {\n\t\t\tcontent.addChild(\n\t\t\t\tnew Text(\n\t\t\t\t\ttheme.fg(\"customMessageText\", \"Branch summary (\") +\n\t\t\t\t\t\ttheme.fg(\"dim\", keyText(\"app.tools.expand\")) +\n\t\t\t\t\t\ttheme.fg(\"customMessageText\", \" to expand)\"),\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\n\t\tthis.addChild(\n\t\t\tnew MouseRegion(content, (event) => {\n\t\t\t\tif (event.type !== \"click\" || event.button !== \"left\") return undefined;\n\t\t\t\tthis.setExpanded(!this.expanded);\n\t\t\t\treturn { handled: true };\n\t\t\t}),\n\t\t);\n\t}\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { Box, Markdown, Spacer, Text } from "@earendil-works/pi-tui";
1
+ import { Box, Container, Markdown, MouseRegion, Spacer, Text } from "@earendil-works/pi-tui";
2
2
  import { getMarkdownTheme, theme } from "../theme/theme.js";
3
3
  import { keyText } from "./keybinding-hints.js";
4
4
  /**
@@ -25,20 +25,27 @@ export class BranchSummaryMessageComponent extends Box {
25
25
  }
26
26
  updateDisplay() {
27
27
  this.clear();
28
+ const content = new Container();
28
29
  const label = theme.fg("customMessageLabel", `\x1b[1m[branch]\x1b[22m`);
29
- this.addChild(new Text(label, 0, 0));
30
- this.addChild(new Spacer(1));
30
+ content.addChild(new Text(label, 0, 0));
31
+ content.addChild(new Spacer(1));
31
32
  if (this.expanded) {
32
33
  const header = "**Branch Summary**\n\n";
33
- this.addChild(new Markdown(header + this.message.summary, 0, 0, this.markdownTheme, {
34
+ content.addChild(new Markdown(header + this.message.summary, 0, 0, this.markdownTheme, {
34
35
  color: (text) => theme.fg("customMessageText", text),
35
36
  }));
36
37
  }
37
38
  else {
38
- this.addChild(new Text(theme.fg("customMessageText", "Branch summary (") +
39
+ content.addChild(new Text(theme.fg("customMessageText", "Branch summary (") +
39
40
  theme.fg("dim", keyText("app.tools.expand")) +
40
41
  theme.fg("customMessageText", " to expand)"), 0, 0));
41
42
  }
43
+ this.addChild(new MouseRegion(content, (event) => {
44
+ if (event.type !== "click" || event.button !== "left")
45
+ return undefined;
46
+ this.setExpanded(!this.expanded);
47
+ return { handled: true };
48
+ }));
42
49
  }
43
50
  }
44
51
  //# sourceMappingURL=branch-summary-message.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"branch-summary-message.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/branch-summary-message.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAsB,MAAM,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAEzF,OAAO,EAAE,gBAAgB,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAEhD;;;GAGG;AACH,MAAM,OAAO,6BAA8B,SAAQ,GAAG;IAC7C,QAAQ,GAAG,KAAK,CAAC;IACjB,OAAO,CAAuB;IAC9B,aAAa,CAAgB;IAErC,YAAY,OAA6B,EAAE,aAAa,GAAkB,gBAAgB,EAAE,EAAE;QAC7F,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAC,CAAC;QACnD,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,aAAa,GAAG,aAAa,CAAC;QACnC,IAAI,CAAC,aAAa,EAAE,CAAC;IAAA,CACrB;IAED,WAAW,CAAC,QAAiB,EAAQ;QACpC,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,aAAa,EAAE,CAAC;IAAA,CACrB;IAEQ,UAAU,GAAS;QAC3B,KAAK,CAAC,UAAU,EAAE,CAAC;QACnB,IAAI,CAAC,aAAa,EAAE,CAAC;IAAA,CACrB;IAEO,aAAa,GAAS;QAC7B,IAAI,CAAC,KAAK,EAAE,CAAC;QAEb,MAAM,KAAK,GAAG,KAAK,CAAC,EAAE,CAAC,oBAAoB,EAAE,yBAAyB,CAAC,CAAC;QACxE,IAAI,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACrC,IAAI,CAAC,QAAQ,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QAE7B,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YACnB,MAAM,MAAM,GAAG,wBAAwB,CAAC;YACxC,IAAI,CAAC,QAAQ,CACZ,IAAI,QAAQ,CAAC,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,aAAa,EAAE;gBACrE,KAAK,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,mBAAmB,EAAE,IAAI,CAAC;aAC5D,CAAC,CACF,CAAC;QACH,CAAC;aAAM,CAAC;YACP,IAAI,CAAC,QAAQ,CACZ,IAAI,IAAI,CACP,KAAK,CAAC,EAAE,CAAC,mBAAmB,EAAE,kBAAkB,CAAC;gBAChD,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,kBAAkB,CAAC,CAAC;gBAC5C,KAAK,CAAC,EAAE,CAAC,mBAAmB,EAAE,aAAa,CAAC,EAC7C,CAAC,EACD,CAAC,CACD,CACD,CAAC;QACH,CAAC;IAAA,CACD;CACD","sourcesContent":["import { Box, Markdown, type MarkdownTheme, Spacer, Text } from \"@earendil-works/pi-tui\";\nimport type { BranchSummaryMessage } from \"../../../core/messages.ts\";\nimport { getMarkdownTheme, theme } from \"../theme/theme.ts\";\nimport { keyText } from \"./keybinding-hints.ts\";\n\n/**\n * Component that renders a branch summary message with collapsed/expanded state.\n * Uses same background color as custom messages for visual consistency.\n */\nexport class BranchSummaryMessageComponent extends Box {\n\tprivate expanded = false;\n\tprivate message: BranchSummaryMessage;\n\tprivate markdownTheme: MarkdownTheme;\n\n\tconstructor(message: BranchSummaryMessage, markdownTheme: MarkdownTheme = getMarkdownTheme()) {\n\t\tsuper(1, 1, (t) => theme.bg(\"customMessageBg\", t));\n\t\tthis.message = message;\n\t\tthis.markdownTheme = markdownTheme;\n\t\tthis.updateDisplay();\n\t}\n\n\tsetExpanded(expanded: boolean): void {\n\t\tthis.expanded = expanded;\n\t\tthis.updateDisplay();\n\t}\n\n\toverride invalidate(): void {\n\t\tsuper.invalidate();\n\t\tthis.updateDisplay();\n\t}\n\n\tprivate updateDisplay(): void {\n\t\tthis.clear();\n\n\t\tconst label = theme.fg(\"customMessageLabel\", `\\x1b[1m[branch]\\x1b[22m`);\n\t\tthis.addChild(new Text(label, 0, 0));\n\t\tthis.addChild(new Spacer(1));\n\n\t\tif (this.expanded) {\n\t\t\tconst header = \"**Branch Summary**\\n\\n\";\n\t\t\tthis.addChild(\n\t\t\t\tnew Markdown(header + this.message.summary, 0, 0, this.markdownTheme, {\n\t\t\t\t\tcolor: (text: string) => theme.fg(\"customMessageText\", text),\n\t\t\t\t}),\n\t\t\t);\n\t\t} else {\n\t\t\tthis.addChild(\n\t\t\t\tnew Text(\n\t\t\t\t\ttheme.fg(\"customMessageText\", \"Branch summary (\") +\n\t\t\t\t\t\ttheme.fg(\"dim\", keyText(\"app.tools.expand\")) +\n\t\t\t\t\t\ttheme.fg(\"customMessageText\", \" to expand)\"),\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t}\n}\n"]}
1
+ {"version":3,"file":"branch-summary-message.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/branch-summary-message.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,QAAQ,EAAsB,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAEjH,OAAO,EAAE,gBAAgB,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAEhD;;;GAGG;AACH,MAAM,OAAO,6BAA8B,SAAQ,GAAG;IAC7C,QAAQ,GAAG,KAAK,CAAC;IACjB,OAAO,CAAuB;IAC9B,aAAa,CAAgB;IAErC,YAAY,OAA6B,EAAE,aAAa,GAAkB,gBAAgB,EAAE,EAAE;QAC7F,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAC,CAAC;QACnD,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,aAAa,GAAG,aAAa,CAAC;QACnC,IAAI,CAAC,aAAa,EAAE,CAAC;IAAA,CACrB;IAED,WAAW,CAAC,QAAiB,EAAQ;QACpC,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,aAAa,EAAE,CAAC;IAAA,CACrB;IAEQ,UAAU,GAAS;QAC3B,KAAK,CAAC,UAAU,EAAE,CAAC;QACnB,IAAI,CAAC,aAAa,EAAE,CAAC;IAAA,CACrB;IAEO,aAAa,GAAS;QAC7B,IAAI,CAAC,KAAK,EAAE,CAAC;QACb,MAAM,OAAO,GAAG,IAAI,SAAS,EAAE,CAAC;QAEhC,MAAM,KAAK,GAAG,KAAK,CAAC,EAAE,CAAC,oBAAoB,EAAE,yBAAyB,CAAC,CAAC;QACxE,OAAO,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACxC,OAAO,CAAC,QAAQ,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QAEhC,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YACnB,MAAM,MAAM,GAAG,wBAAwB,CAAC;YACxC,OAAO,CAAC,QAAQ,CACf,IAAI,QAAQ,CAAC,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,aAAa,EAAE;gBACrE,KAAK,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,mBAAmB,EAAE,IAAI,CAAC;aAC5D,CAAC,CACF,CAAC;QACH,CAAC;aAAM,CAAC;YACP,OAAO,CAAC,QAAQ,CACf,IAAI,IAAI,CACP,KAAK,CAAC,EAAE,CAAC,mBAAmB,EAAE,kBAAkB,CAAC;gBAChD,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,kBAAkB,CAAC,CAAC;gBAC5C,KAAK,CAAC,EAAE,CAAC,mBAAmB,EAAE,aAAa,CAAC,EAC7C,CAAC,EACD,CAAC,CACD,CACD,CAAC;QACH,CAAC;QAED,IAAI,CAAC,QAAQ,CACZ,IAAI,WAAW,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC;YACnC,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,IAAI,KAAK,CAAC,MAAM,KAAK,MAAM;gBAAE,OAAO,SAAS,CAAC;YACxE,IAAI,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACjC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QAAA,CACzB,CAAC,CACF,CAAC;IAAA,CACF;CACD","sourcesContent":["import { Box, Container, Markdown, type MarkdownTheme, MouseRegion, Spacer, Text } from \"@earendil-works/pi-tui\";\nimport type { BranchSummaryMessage } from \"../../../core/messages.ts\";\nimport { getMarkdownTheme, theme } from \"../theme/theme.ts\";\nimport { keyText } from \"./keybinding-hints.ts\";\n\n/**\n * Component that renders a branch summary message with collapsed/expanded state.\n * Uses same background color as custom messages for visual consistency.\n */\nexport class BranchSummaryMessageComponent extends Box {\n\tprivate expanded = false;\n\tprivate message: BranchSummaryMessage;\n\tprivate markdownTheme: MarkdownTheme;\n\n\tconstructor(message: BranchSummaryMessage, markdownTheme: MarkdownTheme = getMarkdownTheme()) {\n\t\tsuper(1, 1, (t) => theme.bg(\"customMessageBg\", t));\n\t\tthis.message = message;\n\t\tthis.markdownTheme = markdownTheme;\n\t\tthis.updateDisplay();\n\t}\n\n\tsetExpanded(expanded: boolean): void {\n\t\tthis.expanded = expanded;\n\t\tthis.updateDisplay();\n\t}\n\n\toverride invalidate(): void {\n\t\tsuper.invalidate();\n\t\tthis.updateDisplay();\n\t}\n\n\tprivate updateDisplay(): void {\n\t\tthis.clear();\n\t\tconst content = new Container();\n\n\t\tconst label = theme.fg(\"customMessageLabel\", `\\x1b[1m[branch]\\x1b[22m`);\n\t\tcontent.addChild(new Text(label, 0, 0));\n\t\tcontent.addChild(new Spacer(1));\n\n\t\tif (this.expanded) {\n\t\t\tconst header = \"**Branch Summary**\\n\\n\";\n\t\t\tcontent.addChild(\n\t\t\t\tnew Markdown(header + this.message.summary, 0, 0, this.markdownTheme, {\n\t\t\t\t\tcolor: (text: string) => theme.fg(\"customMessageText\", text),\n\t\t\t\t}),\n\t\t\t);\n\t\t} else {\n\t\t\tcontent.addChild(\n\t\t\t\tnew Text(\n\t\t\t\t\ttheme.fg(\"customMessageText\", \"Branch summary (\") +\n\t\t\t\t\t\ttheme.fg(\"dim\", keyText(\"app.tools.expand\")) +\n\t\t\t\t\t\ttheme.fg(\"customMessageText\", \" to expand)\"),\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\n\t\tthis.addChild(\n\t\t\tnew MouseRegion(content, (event) => {\n\t\t\t\tif (event.type !== \"click\" || event.button !== \"left\") return undefined;\n\t\t\t\tthis.setExpanded(!this.expanded);\n\t\t\t\treturn { handled: true };\n\t\t\t}),\n\t\t);\n\t}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"compaction-summary-message.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/compaction-summary-message.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAY,KAAK,aAAa,EAAgB,MAAM,wBAAwB,CAAC;AACzF,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AAI1E;;;GAGG;AACH,qBAAa,iCAAkC,SAAQ,GAAG;IACzD,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,OAAO,CAA2B;IAC1C,OAAO,CAAC,aAAa,CAAgB;IAErC,YAAY,OAAO,EAAE,wBAAwB,EAAE,aAAa,GAAE,aAAkC,EAK/F;IAED,WAAW,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAGnC;IAEQ,UAAU,IAAI,IAAI,CAG1B;IAED,OAAO,CAAC,aAAa;CA2BrB","sourcesContent":["import { Box, Markdown, type MarkdownTheme, Spacer, Text } from \"@earendil-works/pi-tui\";\nimport type { CompactionSummaryMessage } from \"../../../core/messages.ts\";\nimport { getMarkdownTheme, theme } from \"../theme/theme.ts\";\nimport { keyText } from \"./keybinding-hints.ts\";\n\n/**\n * Component that renders a compaction message with collapsed/expanded state.\n * Uses same background color as custom messages for visual consistency.\n */\nexport class CompactionSummaryMessageComponent extends Box {\n\tprivate expanded = false;\n\tprivate message: CompactionSummaryMessage;\n\tprivate markdownTheme: MarkdownTheme;\n\n\tconstructor(message: CompactionSummaryMessage, markdownTheme: MarkdownTheme = getMarkdownTheme()) {\n\t\tsuper(1, 1, (t) => theme.bg(\"customMessageBg\", t));\n\t\tthis.message = message;\n\t\tthis.markdownTheme = markdownTheme;\n\t\tthis.updateDisplay();\n\t}\n\n\tsetExpanded(expanded: boolean): void {\n\t\tthis.expanded = expanded;\n\t\tthis.updateDisplay();\n\t}\n\n\toverride invalidate(): void {\n\t\tsuper.invalidate();\n\t\tthis.updateDisplay();\n\t}\n\n\tprivate updateDisplay(): void {\n\t\tthis.clear();\n\n\t\tconst tokenStr = this.message.tokensBefore.toLocaleString();\n\t\tconst label = theme.fg(\"customMessageLabel\", `\\x1b[1m[compaction]\\x1b[22m`);\n\t\tthis.addChild(new Text(label, 0, 0));\n\t\tthis.addChild(new Spacer(1));\n\n\t\tif (this.expanded) {\n\t\t\tconst header = `**Compacted from ${tokenStr} tokens**\\n\\n`;\n\t\t\tthis.addChild(\n\t\t\t\tnew Markdown(header + this.message.summary, 0, 0, this.markdownTheme, {\n\t\t\t\t\tcolor: (text: string) => theme.fg(\"customMessageText\", text),\n\t\t\t\t}),\n\t\t\t);\n\t\t} else {\n\t\t\tthis.addChild(\n\t\t\t\tnew Text(\n\t\t\t\t\ttheme.fg(\"customMessageText\", `Compacted from ${tokenStr} tokens (`) +\n\t\t\t\t\t\ttheme.fg(\"dim\", keyText(\"app.tools.expand\")) +\n\t\t\t\t\t\ttheme.fg(\"customMessageText\", \" to expand)\"),\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t}\n}\n"]}
1
+ {"version":3,"file":"compaction-summary-message.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/compaction-summary-message.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAuB,KAAK,aAAa,EAA6B,MAAM,wBAAwB,CAAC;AACjH,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AAI1E;;;GAGG;AACH,qBAAa,iCAAkC,SAAQ,GAAG;IACzD,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,OAAO,CAA2B;IAC1C,OAAO,CAAC,aAAa,CAAgB;IAErC,YAAY,OAAO,EAAE,wBAAwB,EAAE,aAAa,GAAE,aAAkC,EAK/F;IAED,WAAW,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAGnC;IAEQ,UAAU,IAAI,IAAI,CAG1B;IAED,OAAO,CAAC,aAAa;CAoCrB","sourcesContent":["import { Box, Container, Markdown, type MarkdownTheme, MouseRegion, Spacer, Text } from \"@earendil-works/pi-tui\";\nimport type { CompactionSummaryMessage } from \"../../../core/messages.ts\";\nimport { getMarkdownTheme, theme } from \"../theme/theme.ts\";\nimport { keyText } from \"./keybinding-hints.ts\";\n\n/**\n * Component that renders a compaction message with collapsed/expanded state.\n * Uses same background color as custom messages for visual consistency.\n */\nexport class CompactionSummaryMessageComponent extends Box {\n\tprivate expanded = false;\n\tprivate message: CompactionSummaryMessage;\n\tprivate markdownTheme: MarkdownTheme;\n\n\tconstructor(message: CompactionSummaryMessage, markdownTheme: MarkdownTheme = getMarkdownTheme()) {\n\t\tsuper(1, 1, (t) => theme.bg(\"customMessageBg\", t));\n\t\tthis.message = message;\n\t\tthis.markdownTheme = markdownTheme;\n\t\tthis.updateDisplay();\n\t}\n\n\tsetExpanded(expanded: boolean): void {\n\t\tthis.expanded = expanded;\n\t\tthis.updateDisplay();\n\t}\n\n\toverride invalidate(): void {\n\t\tsuper.invalidate();\n\t\tthis.updateDisplay();\n\t}\n\n\tprivate updateDisplay(): void {\n\t\tthis.clear();\n\t\tconst content = new Container();\n\n\t\tconst tokenStr = this.message.tokensBefore.toLocaleString();\n\t\tconst label = theme.fg(\"customMessageLabel\", `\\x1b[1m[compaction]\\x1b[22m`);\n\t\tcontent.addChild(new Text(label, 0, 0));\n\t\tcontent.addChild(new Spacer(1));\n\n\t\tif (this.expanded) {\n\t\t\tconst header = `**Compacted from ${tokenStr} tokens**\\n\\n`;\n\t\t\tcontent.addChild(\n\t\t\t\tnew Markdown(header + this.message.summary, 0, 0, this.markdownTheme, {\n\t\t\t\t\tcolor: (text: string) => theme.fg(\"customMessageText\", text),\n\t\t\t\t}),\n\t\t\t);\n\t\t} else {\n\t\t\tcontent.addChild(\n\t\t\t\tnew Text(\n\t\t\t\t\ttheme.fg(\"customMessageText\", `Compacted from ${tokenStr} tokens (`) +\n\t\t\t\t\t\ttheme.fg(\"dim\", keyText(\"app.tools.expand\")) +\n\t\t\t\t\t\ttheme.fg(\"customMessageText\", \" to expand)\"),\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\n\t\tthis.addChild(\n\t\t\tnew MouseRegion(content, (event) => {\n\t\t\t\tif (event.type !== \"click\" || event.button !== \"left\") return undefined;\n\t\t\t\tthis.setExpanded(!this.expanded);\n\t\t\t\treturn { handled: true };\n\t\t\t}),\n\t\t);\n\t}\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { Box, Markdown, Spacer, Text } from "@earendil-works/pi-tui";
1
+ import { Box, Container, Markdown, MouseRegion, Spacer, Text } from "@earendil-works/pi-tui";
2
2
  import { getMarkdownTheme, theme } from "../theme/theme.js";
3
3
  import { keyText } from "./keybinding-hints.js";
4
4
  /**
@@ -25,21 +25,28 @@ export class CompactionSummaryMessageComponent extends Box {
25
25
  }
26
26
  updateDisplay() {
27
27
  this.clear();
28
+ const content = new Container();
28
29
  const tokenStr = this.message.tokensBefore.toLocaleString();
29
30
  const label = theme.fg("customMessageLabel", `\x1b[1m[compaction]\x1b[22m`);
30
- this.addChild(new Text(label, 0, 0));
31
- this.addChild(new Spacer(1));
31
+ content.addChild(new Text(label, 0, 0));
32
+ content.addChild(new Spacer(1));
32
33
  if (this.expanded) {
33
34
  const header = `**Compacted from ${tokenStr} tokens**\n\n`;
34
- this.addChild(new Markdown(header + this.message.summary, 0, 0, this.markdownTheme, {
35
+ content.addChild(new Markdown(header + this.message.summary, 0, 0, this.markdownTheme, {
35
36
  color: (text) => theme.fg("customMessageText", text),
36
37
  }));
37
38
  }
38
39
  else {
39
- this.addChild(new Text(theme.fg("customMessageText", `Compacted from ${tokenStr} tokens (`) +
40
+ content.addChild(new Text(theme.fg("customMessageText", `Compacted from ${tokenStr} tokens (`) +
40
41
  theme.fg("dim", keyText("app.tools.expand")) +
41
42
  theme.fg("customMessageText", " to expand)"), 0, 0));
42
43
  }
44
+ this.addChild(new MouseRegion(content, (event) => {
45
+ if (event.type !== "click" || event.button !== "left")
46
+ return undefined;
47
+ this.setExpanded(!this.expanded);
48
+ return { handled: true };
49
+ }));
43
50
  }
44
51
  }
45
52
  //# sourceMappingURL=compaction-summary-message.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"compaction-summary-message.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/compaction-summary-message.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAsB,MAAM,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAEzF,OAAO,EAAE,gBAAgB,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAEhD;;;GAGG;AACH,MAAM,OAAO,iCAAkC,SAAQ,GAAG;IACjD,QAAQ,GAAG,KAAK,CAAC;IACjB,OAAO,CAA2B;IAClC,aAAa,CAAgB;IAErC,YAAY,OAAiC,EAAE,aAAa,GAAkB,gBAAgB,EAAE,EAAE;QACjG,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAC,CAAC;QACnD,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,aAAa,GAAG,aAAa,CAAC;QACnC,IAAI,CAAC,aAAa,EAAE,CAAC;IAAA,CACrB;IAED,WAAW,CAAC,QAAiB,EAAQ;QACpC,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,aAAa,EAAE,CAAC;IAAA,CACrB;IAEQ,UAAU,GAAS;QAC3B,KAAK,CAAC,UAAU,EAAE,CAAC;QACnB,IAAI,CAAC,aAAa,EAAE,CAAC;IAAA,CACrB;IAEO,aAAa,GAAS;QAC7B,IAAI,CAAC,KAAK,EAAE,CAAC;QAEb,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,cAAc,EAAE,CAAC;QAC5D,MAAM,KAAK,GAAG,KAAK,CAAC,EAAE,CAAC,oBAAoB,EAAE,6BAA6B,CAAC,CAAC;QAC5E,IAAI,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACrC,IAAI,CAAC,QAAQ,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QAE7B,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YACnB,MAAM,MAAM,GAAG,oBAAoB,QAAQ,eAAe,CAAC;YAC3D,IAAI,CAAC,QAAQ,CACZ,IAAI,QAAQ,CAAC,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,aAAa,EAAE;gBACrE,KAAK,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,mBAAmB,EAAE,IAAI,CAAC;aAC5D,CAAC,CACF,CAAC;QACH,CAAC;aAAM,CAAC;YACP,IAAI,CAAC,QAAQ,CACZ,IAAI,IAAI,CACP,KAAK,CAAC,EAAE,CAAC,mBAAmB,EAAE,kBAAkB,QAAQ,WAAW,CAAC;gBACnE,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,kBAAkB,CAAC,CAAC;gBAC5C,KAAK,CAAC,EAAE,CAAC,mBAAmB,EAAE,aAAa,CAAC,EAC7C,CAAC,EACD,CAAC,CACD,CACD,CAAC;QACH,CAAC;IAAA,CACD;CACD","sourcesContent":["import { Box, Markdown, type MarkdownTheme, Spacer, Text } from \"@earendil-works/pi-tui\";\nimport type { CompactionSummaryMessage } from \"../../../core/messages.ts\";\nimport { getMarkdownTheme, theme } from \"../theme/theme.ts\";\nimport { keyText } from \"./keybinding-hints.ts\";\n\n/**\n * Component that renders a compaction message with collapsed/expanded state.\n * Uses same background color as custom messages for visual consistency.\n */\nexport class CompactionSummaryMessageComponent extends Box {\n\tprivate expanded = false;\n\tprivate message: CompactionSummaryMessage;\n\tprivate markdownTheme: MarkdownTheme;\n\n\tconstructor(message: CompactionSummaryMessage, markdownTheme: MarkdownTheme = getMarkdownTheme()) {\n\t\tsuper(1, 1, (t) => theme.bg(\"customMessageBg\", t));\n\t\tthis.message = message;\n\t\tthis.markdownTheme = markdownTheme;\n\t\tthis.updateDisplay();\n\t}\n\n\tsetExpanded(expanded: boolean): void {\n\t\tthis.expanded = expanded;\n\t\tthis.updateDisplay();\n\t}\n\n\toverride invalidate(): void {\n\t\tsuper.invalidate();\n\t\tthis.updateDisplay();\n\t}\n\n\tprivate updateDisplay(): void {\n\t\tthis.clear();\n\n\t\tconst tokenStr = this.message.tokensBefore.toLocaleString();\n\t\tconst label = theme.fg(\"customMessageLabel\", `\\x1b[1m[compaction]\\x1b[22m`);\n\t\tthis.addChild(new Text(label, 0, 0));\n\t\tthis.addChild(new Spacer(1));\n\n\t\tif (this.expanded) {\n\t\t\tconst header = `**Compacted from ${tokenStr} tokens**\\n\\n`;\n\t\t\tthis.addChild(\n\t\t\t\tnew Markdown(header + this.message.summary, 0, 0, this.markdownTheme, {\n\t\t\t\t\tcolor: (text: string) => theme.fg(\"customMessageText\", text),\n\t\t\t\t}),\n\t\t\t);\n\t\t} else {\n\t\t\tthis.addChild(\n\t\t\t\tnew Text(\n\t\t\t\t\ttheme.fg(\"customMessageText\", `Compacted from ${tokenStr} tokens (`) +\n\t\t\t\t\t\ttheme.fg(\"dim\", keyText(\"app.tools.expand\")) +\n\t\t\t\t\t\ttheme.fg(\"customMessageText\", \" to expand)\"),\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t}\n}\n"]}
1
+ {"version":3,"file":"compaction-summary-message.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/compaction-summary-message.ts"],"names":[],"mappings":"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","sourcesContent":["import { Box, Container, Markdown, type MarkdownTheme, MouseRegion, Spacer, Text } from \"@earendil-works/pi-tui\";\nimport type { CompactionSummaryMessage } from \"../../../core/messages.ts\";\nimport { getMarkdownTheme, theme } from \"../theme/theme.ts\";\nimport { keyText } from \"./keybinding-hints.ts\";\n\n/**\n * Component that renders a compaction message with collapsed/expanded state.\n * Uses same background color as custom messages for visual consistency.\n */\nexport class CompactionSummaryMessageComponent extends Box {\n\tprivate expanded = false;\n\tprivate message: CompactionSummaryMessage;\n\tprivate markdownTheme: MarkdownTheme;\n\n\tconstructor(message: CompactionSummaryMessage, markdownTheme: MarkdownTheme = getMarkdownTheme()) {\n\t\tsuper(1, 1, (t) => theme.bg(\"customMessageBg\", t));\n\t\tthis.message = message;\n\t\tthis.markdownTheme = markdownTheme;\n\t\tthis.updateDisplay();\n\t}\n\n\tsetExpanded(expanded: boolean): void {\n\t\tthis.expanded = expanded;\n\t\tthis.updateDisplay();\n\t}\n\n\toverride invalidate(): void {\n\t\tsuper.invalidate();\n\t\tthis.updateDisplay();\n\t}\n\n\tprivate updateDisplay(): void {\n\t\tthis.clear();\n\t\tconst content = new Container();\n\n\t\tconst tokenStr = this.message.tokensBefore.toLocaleString();\n\t\tconst label = theme.fg(\"customMessageLabel\", `\\x1b[1m[compaction]\\x1b[22m`);\n\t\tcontent.addChild(new Text(label, 0, 0));\n\t\tcontent.addChild(new Spacer(1));\n\n\t\tif (this.expanded) {\n\t\t\tconst header = `**Compacted from ${tokenStr} tokens**\\n\\n`;\n\t\t\tcontent.addChild(\n\t\t\t\tnew Markdown(header + this.message.summary, 0, 0, this.markdownTheme, {\n\t\t\t\t\tcolor: (text: string) => theme.fg(\"customMessageText\", text),\n\t\t\t\t}),\n\t\t\t);\n\t\t} else {\n\t\t\tcontent.addChild(\n\t\t\t\tnew Text(\n\t\t\t\t\ttheme.fg(\"customMessageText\", `Compacted from ${tokenStr} tokens (`) +\n\t\t\t\t\t\ttheme.fg(\"dim\", keyText(\"app.tools.expand\")) +\n\t\t\t\t\t\ttheme.fg(\"customMessageText\", \" to expand)\"),\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\n\t\tthis.addChild(\n\t\t\tnew MouseRegion(content, (event) => {\n\t\t\t\tif (event.type !== \"click\" || event.button !== \"left\") return undefined;\n\t\t\t\tthis.setExpanded(!this.expanded);\n\t\t\t\treturn { handled: true };\n\t\t\t}),\n\t\t);\n\t}\n}\n"]}
@@ -1,8 +1,8 @@
1
1
  import { Editor, type EditorOptions, type EditorTheme, type TUI } from "@earendil-works/pi-tui";
2
2
  import type { AppKeybinding, KeybindingsManager } from "../../../core/keybindings.ts";
3
- import type { WorkingStatusIndicator } from "./status-indicator.ts";
3
+ import type { StatusIndicator } from "./status-indicator.ts";
4
4
  export type CustomEditorOptions = EditorOptions & {
5
- /** Render the streaming working status in the editor's top border. */
5
+ /** Render working, compaction, summarization, and retry status in the editor's top border. */
6
6
  embedWorkingStatus?: boolean;
7
7
  };
8
8
  /**
@@ -19,7 +19,7 @@ export declare class CustomEditor extends Editor {
19
19
  /** Handler for extension-registered shortcuts. Returns true if handled. */
20
20
  onExtensionShortcut?: (data: string) => boolean;
21
21
  constructor(tui: TUI, theme: EditorTheme, keybindings: KeybindingsManager, options?: CustomEditorOptions);
22
- setWorkingStatusIndicator(indicator: WorkingStatusIndicator | undefined): void;
22
+ setWorkingStatusIndicator(indicator: StatusIndicator | undefined): void;
23
23
  protected renderTopBorder(width: number, hiddenLineCount: number): string;
24
24
  /**
25
25
  * Register a handler for an app action.
@@ -1 +1 @@
1
- {"version":3,"file":"custom-editor.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/custom-editor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,KAAK,aAAa,EAAE,KAAK,WAAW,EAAE,KAAK,GAAG,EAAgB,MAAM,wBAAwB,CAAC;AAC9G,OAAO,KAAK,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AACtF,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAEpE,MAAM,MAAM,mBAAmB,GAAG,aAAa,GAAG;IACjD,sEAAsE;IACtE,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC7B,CAAC;AAEF;;GAEG;AACH,qBAAa,YAAa,SAAQ,MAAM;IACvC,OAAO,CAAC,WAAW,CAAqB;IACxC,OAAO,CAAC,sBAAsB,CAAqC;IACnE,SAAgB,kBAAkB,EAAE,OAAO,CAAC;IACrC,cAAc,EAAE,GAAG,CAAC,aAAa,EAAE,MAAM,IAAI,CAAC,CAAa;IAG3D,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IACjC,2EAA2E;IACpE,mBAAmB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;IAEvD,YAAY,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,kBAAkB,EAAE,OAAO,CAAC,EAAE,mBAAmB,EAIvG;IAED,yBAAyB,CAAC,SAAS,EAAE,sBAAsB,GAAG,SAAS,GAAG,IAAI,CAE7E;IAED,UAAmB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,MAAM,CA2CjF;IAED;;OAEG;IACH,QAAQ,CAAC,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,IAAI,GAAG,IAAI,CAEzD;IAED,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CA2D9B;CACD","sourcesContent":["import { Editor, type EditorOptions, type EditorTheme, type TUI, visibleWidth } from \"@earendil-works/pi-tui\";\nimport type { AppKeybinding, KeybindingsManager } from \"../../../core/keybindings.ts\";\nimport type { WorkingStatusIndicator } from \"./status-indicator.ts\";\n\nexport type CustomEditorOptions = EditorOptions & {\n\t/** Render the streaming working status in the editor's top border. */\n\tembedWorkingStatus?: boolean;\n};\n\n/**\n * Custom editor that handles app-level keybindings for coding-agent.\n */\nexport class CustomEditor extends Editor {\n\tprivate keybindings: KeybindingsManager;\n\tprivate workingStatusIndicator: WorkingStatusIndicator | undefined;\n\tpublic readonly embedWorkingStatus: boolean;\n\tpublic actionHandlers: Map<AppKeybinding, () => void> = new Map();\n\n\t// Special handlers that can be dynamically replaced\n\tpublic onEscape?: () => void;\n\tpublic onCtrlD?: () => void;\n\tpublic onPasteImage?: () => void;\n\t/** Handler for extension-registered shortcuts. Returns true if handled. */\n\tpublic onExtensionShortcut?: (data: string) => boolean;\n\n\tconstructor(tui: TUI, theme: EditorTheme, keybindings: KeybindingsManager, options?: CustomEditorOptions) {\n\t\tsuper(tui, theme, options);\n\t\tthis.keybindings = keybindings;\n\t\tthis.embedWorkingStatus = options?.embedWorkingStatus ?? false;\n\t}\n\n\tsetWorkingStatusIndicator(indicator: WorkingStatusIndicator | undefined): void {\n\t\tthis.workingStatusIndicator = indicator;\n\t}\n\n\tprotected override renderTopBorder(width: number, hiddenLineCount: number): string {\n\t\tif (!this.embedWorkingStatus || !this.workingStatusIndicator || width <= 0) {\n\t\t\treturn super.renderTopBorder(width, hiddenLineCount);\n\t\t}\n\n\t\tlet status = this.workingStatusIndicator.renderInBorder(Math.max(1, width - 5));\n\t\tlet statusWidth = visibleWidth(status);\n\t\tif (statusWidth === 0) return super.renderTopBorder(width, hiddenLineCount);\n\n\t\tconst overflowLabel = hiddenLineCount > 0 ? ` ↑ ${hiddenLineCount} more ` : undefined;\n\t\tconst overflowLabelWidth = overflowLabel ? visibleWidth(overflowLabel) : 0;\n\t\tconst overflowStart = Math.floor((width - overflowLabelWidth) / 2);\n\t\tconst canFitOverflow = () =>\n\t\t\toverflowLabel !== undefined && overflowLabelWidth + 2 <= width && overflowStart - (3 + statusWidth + 1) >= 1;\n\n\t\tif (overflowLabel && !canFitOverflow()) {\n\t\t\tstatus = this.workingStatusIndicator.renderSpinnerInBorder(width);\n\t\t\tstatusWidth = visibleWidth(status);\n\t\t}\n\n\t\tif (canFitOverflow()) {\n\t\t\tconst leftBlockWidth = 3 + statusWidth + 1;\n\t\t\treturn (\n\t\t\t\tthis.borderColor(\"── \") +\n\t\t\t\tstatus +\n\t\t\t\tthis.borderColor(\n\t\t\t\t\t` ${\"─\".repeat(overflowStart - leftBlockWidth)}${overflowLabel}${\"─\".repeat(width - overflowStart - overflowLabelWidth)}`,\n\t\t\t\t)\n\t\t\t);\n\t\t}\n\n\t\tif (width >= statusWidth + 5) {\n\t\t\treturn this.borderColor(\"── \") + status + this.borderColor(` ${\"─\".repeat(width - statusWidth - 4)}`);\n\t\t}\n\n\t\tstatus = this.workingStatusIndicator.renderSpinnerInBorder(width);\n\t\tstatusWidth = visibleWidth(status);\n\t\tconst prefixWidth = Math.min(3, Math.max(0, width - statusWidth));\n\t\treturn (\n\t\t\tthis.borderColor(\"─\".repeat(prefixWidth)) +\n\t\t\tstatus +\n\t\t\tthis.borderColor(\"─\".repeat(Math.max(0, width - prefixWidth - statusWidth)))\n\t\t);\n\t}\n\n\t/**\n\t * Register a handler for an app action.\n\t */\n\tonAction(action: AppKeybinding, handler: () => void): void {\n\t\tthis.actionHandlers.set(action, handler);\n\t}\n\n\thandleInput(data: string): void {\n\t\t// Check extension-registered shortcuts first\n\t\tif (this.onExtensionShortcut?.(data)) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Check for clipboard paste keybinding\n\t\tif (this.keybindings.matches(data, \"app.clipboard.pasteImage\")) {\n\t\t\tthis.onPasteImage?.();\n\t\t\treturn;\n\t\t}\n\n\t\t// Check app keybindings first\n\n\t\t// Escape/interrupt - only if autocomplete is NOT active\n\t\tif (this.keybindings.matches(data, \"app.interrupt\")) {\n\t\t\tif (!this.isShowingAutocomplete()) {\n\t\t\t\t// Use dynamic onEscape if set, otherwise registered handler\n\t\t\t\tconst handler = this.onEscape ?? this.actionHandlers.get(\"app.interrupt\");\n\t\t\t\tif (handler) {\n\t\t\t\t\thandler();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Let parent handle escape for autocomplete cancellation\n\t\t\tsuper.handleInput(data);\n\t\t\treturn;\n\t\t}\n\n\t\t// Exit (Ctrl+D) - only when editor is empty\n\t\tif (this.keybindings.matches(data, \"app.exit\")) {\n\t\t\tif (this.getText().length === 0) {\n\t\t\t\tconst handler = this.onCtrlD ?? this.actionHandlers.get(\"app.exit\");\n\t\t\t\tif (handler) handler();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// Fall through to editor handling for delete-char-forward when not empty\n\t\t}\n\n\t\t// Explicit history bindings take precedence over app actions while the editor is focused.\n\t\t// This lets users bind Ctrl+P even though it cycles models by default.\n\t\tif (\n\t\t\tthis.keybindings.matches(data, \"tui.editor.historyPrevious\") ||\n\t\t\tthis.keybindings.matches(data, \"tui.editor.historyNext\")\n\t\t) {\n\t\t\tsuper.handleInput(data);\n\t\t\treturn;\n\t\t}\n\n\t\t// Check all other app actions\n\t\tfor (const [action, handler] of this.actionHandlers) {\n\t\t\tif (action !== \"app.interrupt\" && action !== \"app.exit\" && this.keybindings.matches(data, action)) {\n\t\t\t\thandler();\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\t// Pass to parent for editor handling\n\t\tsuper.handleInput(data);\n\t}\n}\n"]}
1
+ {"version":3,"file":"custom-editor.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/custom-editor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,KAAK,aAAa,EAAE,KAAK,WAAW,EAAE,KAAK,GAAG,EAAgB,MAAM,wBAAwB,CAAC;AAC9G,OAAO,KAAK,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AACtF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAE7D,MAAM,MAAM,mBAAmB,GAAG,aAAa,GAAG;IACjD,8FAA8F;IAC9F,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC7B,CAAC;AAEF;;GAEG;AACH,qBAAa,YAAa,SAAQ,MAAM;IACvC,OAAO,CAAC,WAAW,CAAqB;IACxC,OAAO,CAAC,sBAAsB,CAA8B;IAC5D,SAAgB,kBAAkB,EAAE,OAAO,CAAC;IACrC,cAAc,EAAE,GAAG,CAAC,aAAa,EAAE,MAAM,IAAI,CAAC,CAAa;IAG3D,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IACjC,2EAA2E;IACpE,mBAAmB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;IAEvD,YAAY,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,kBAAkB,EAAE,OAAO,CAAC,EAAE,mBAAmB,EAIvG;IAED,yBAAyB,CAAC,SAAS,EAAE,eAAe,GAAG,SAAS,GAAG,IAAI,CAEtE;IAED,UAAmB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,MAAM,CA2CjF;IAED;;OAEG;IACH,QAAQ,CAAC,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,IAAI,GAAG,IAAI,CAEzD;IAED,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CA2D9B;CACD","sourcesContent":["import { Editor, type EditorOptions, type EditorTheme, type TUI, visibleWidth } from \"@earendil-works/pi-tui\";\nimport type { AppKeybinding, KeybindingsManager } from \"../../../core/keybindings.ts\";\nimport type { StatusIndicator } from \"./status-indicator.ts\";\n\nexport type CustomEditorOptions = EditorOptions & {\n\t/** Render working, compaction, summarization, and retry status in the editor's top border. */\n\tembedWorkingStatus?: boolean;\n};\n\n/**\n * Custom editor that handles app-level keybindings for coding-agent.\n */\nexport class CustomEditor extends Editor {\n\tprivate keybindings: KeybindingsManager;\n\tprivate workingStatusIndicator: StatusIndicator | undefined;\n\tpublic readonly embedWorkingStatus: boolean;\n\tpublic actionHandlers: Map<AppKeybinding, () => void> = new Map();\n\n\t// Special handlers that can be dynamically replaced\n\tpublic onEscape?: () => void;\n\tpublic onCtrlD?: () => void;\n\tpublic onPasteImage?: () => void;\n\t/** Handler for extension-registered shortcuts. Returns true if handled. */\n\tpublic onExtensionShortcut?: (data: string) => boolean;\n\n\tconstructor(tui: TUI, theme: EditorTheme, keybindings: KeybindingsManager, options?: CustomEditorOptions) {\n\t\tsuper(tui, theme, options);\n\t\tthis.keybindings = keybindings;\n\t\tthis.embedWorkingStatus = options?.embedWorkingStatus ?? false;\n\t}\n\n\tsetWorkingStatusIndicator(indicator: StatusIndicator | undefined): void {\n\t\tthis.workingStatusIndicator = indicator;\n\t}\n\n\tprotected override renderTopBorder(width: number, hiddenLineCount: number): string {\n\t\tif (!this.embedWorkingStatus || !this.workingStatusIndicator || width <= 0) {\n\t\t\treturn super.renderTopBorder(width, hiddenLineCount);\n\t\t}\n\n\t\tlet status = this.workingStatusIndicator.renderInBorder(Math.max(1, width - 5));\n\t\tlet statusWidth = visibleWidth(status);\n\t\tif (statusWidth === 0) return super.renderTopBorder(width, hiddenLineCount);\n\n\t\tconst overflowLabel = hiddenLineCount > 0 ? ` ↑ ${hiddenLineCount} more ` : undefined;\n\t\tconst overflowLabelWidth = overflowLabel ? visibleWidth(overflowLabel) : 0;\n\t\tconst overflowStart = Math.floor((width - overflowLabelWidth) / 2);\n\t\tconst canFitOverflow = () =>\n\t\t\toverflowLabel !== undefined && overflowLabelWidth + 2 <= width && overflowStart - (3 + statusWidth + 1) >= 1;\n\n\t\tif (overflowLabel && !canFitOverflow()) {\n\t\t\tstatus = this.workingStatusIndicator.renderSpinnerInBorder(width);\n\t\t\tstatusWidth = visibleWidth(status);\n\t\t}\n\n\t\tif (canFitOverflow()) {\n\t\t\tconst leftBlockWidth = 3 + statusWidth + 1;\n\t\t\treturn (\n\t\t\t\tthis.borderColor(\"── \") +\n\t\t\t\tstatus +\n\t\t\t\tthis.borderColor(\n\t\t\t\t\t` ${\"─\".repeat(overflowStart - leftBlockWidth)}${overflowLabel}${\"─\".repeat(width - overflowStart - overflowLabelWidth)}`,\n\t\t\t\t)\n\t\t\t);\n\t\t}\n\n\t\tif (width >= statusWidth + 5) {\n\t\t\treturn this.borderColor(\"── \") + status + this.borderColor(` ${\"─\".repeat(width - statusWidth - 4)}`);\n\t\t}\n\n\t\tstatus = this.workingStatusIndicator.renderSpinnerInBorder(width);\n\t\tstatusWidth = visibleWidth(status);\n\t\tconst prefixWidth = Math.min(3, Math.max(0, width - statusWidth));\n\t\treturn (\n\t\t\tthis.borderColor(\"─\".repeat(prefixWidth)) +\n\t\t\tstatus +\n\t\t\tthis.borderColor(\"─\".repeat(Math.max(0, width - prefixWidth - statusWidth)))\n\t\t);\n\t}\n\n\t/**\n\t * Register a handler for an app action.\n\t */\n\tonAction(action: AppKeybinding, handler: () => void): void {\n\t\tthis.actionHandlers.set(action, handler);\n\t}\n\n\thandleInput(data: string): void {\n\t\t// Check extension-registered shortcuts first\n\t\tif (this.onExtensionShortcut?.(data)) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Check for clipboard paste keybinding\n\t\tif (this.keybindings.matches(data, \"app.clipboard.pasteImage\")) {\n\t\t\tthis.onPasteImage?.();\n\t\t\treturn;\n\t\t}\n\n\t\t// Check app keybindings first\n\n\t\t// Escape/interrupt - only if autocomplete is NOT active\n\t\tif (this.keybindings.matches(data, \"app.interrupt\")) {\n\t\t\tif (!this.isShowingAutocomplete()) {\n\t\t\t\t// Use dynamic onEscape if set, otherwise registered handler\n\t\t\t\tconst handler = this.onEscape ?? this.actionHandlers.get(\"app.interrupt\");\n\t\t\t\tif (handler) {\n\t\t\t\t\thandler();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Let parent handle escape for autocomplete cancellation\n\t\t\tsuper.handleInput(data);\n\t\t\treturn;\n\t\t}\n\n\t\t// Exit (Ctrl+D) - only when editor is empty\n\t\tif (this.keybindings.matches(data, \"app.exit\")) {\n\t\t\tif (this.getText().length === 0) {\n\t\t\t\tconst handler = this.onCtrlD ?? this.actionHandlers.get(\"app.exit\");\n\t\t\t\tif (handler) handler();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// Fall through to editor handling for delete-char-forward when not empty\n\t\t}\n\n\t\t// Explicit history bindings take precedence over app actions while the editor is focused.\n\t\t// This lets users bind Ctrl+P even though it cycles models by default.\n\t\tif (\n\t\t\tthis.keybindings.matches(data, \"tui.editor.historyPrevious\") ||\n\t\t\tthis.keybindings.matches(data, \"tui.editor.historyNext\")\n\t\t) {\n\t\t\tsuper.handleInput(data);\n\t\t\treturn;\n\t\t}\n\n\t\t// Check all other app actions\n\t\tfor (const [action, handler] of this.actionHandlers) {\n\t\t\tif (action !== \"app.interrupt\" && action !== \"app.exit\" && this.keybindings.matches(data, action)) {\n\t\t\t\thandler();\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\t// Pass to parent for editor handling\n\t\tsuper.handleInput(data);\n\t}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"custom-editor.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/custom-editor.ts"],"names":[],"mappings":"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","sourcesContent":["import { Editor, type EditorOptions, type EditorTheme, type TUI, visibleWidth } from \"@earendil-works/pi-tui\";\nimport type { AppKeybinding, KeybindingsManager } from \"../../../core/keybindings.ts\";\nimport type { WorkingStatusIndicator } from \"./status-indicator.ts\";\n\nexport type CustomEditorOptions = EditorOptions & {\n\t/** Render the streaming working status in the editor's top border. */\n\tembedWorkingStatus?: boolean;\n};\n\n/**\n * Custom editor that handles app-level keybindings for coding-agent.\n */\nexport class CustomEditor extends Editor {\n\tprivate keybindings: KeybindingsManager;\n\tprivate workingStatusIndicator: WorkingStatusIndicator | undefined;\n\tpublic readonly embedWorkingStatus: boolean;\n\tpublic actionHandlers: Map<AppKeybinding, () => void> = new Map();\n\n\t// Special handlers that can be dynamically replaced\n\tpublic onEscape?: () => void;\n\tpublic onCtrlD?: () => void;\n\tpublic onPasteImage?: () => void;\n\t/** Handler for extension-registered shortcuts. Returns true if handled. */\n\tpublic onExtensionShortcut?: (data: string) => boolean;\n\n\tconstructor(tui: TUI, theme: EditorTheme, keybindings: KeybindingsManager, options?: CustomEditorOptions) {\n\t\tsuper(tui, theme, options);\n\t\tthis.keybindings = keybindings;\n\t\tthis.embedWorkingStatus = options?.embedWorkingStatus ?? false;\n\t}\n\n\tsetWorkingStatusIndicator(indicator: WorkingStatusIndicator | undefined): void {\n\t\tthis.workingStatusIndicator = indicator;\n\t}\n\n\tprotected override renderTopBorder(width: number, hiddenLineCount: number): string {\n\t\tif (!this.embedWorkingStatus || !this.workingStatusIndicator || width <= 0) {\n\t\t\treturn super.renderTopBorder(width, hiddenLineCount);\n\t\t}\n\n\t\tlet status = this.workingStatusIndicator.renderInBorder(Math.max(1, width - 5));\n\t\tlet statusWidth = visibleWidth(status);\n\t\tif (statusWidth === 0) return super.renderTopBorder(width, hiddenLineCount);\n\n\t\tconst overflowLabel = hiddenLineCount > 0 ? ` ↑ ${hiddenLineCount} more ` : undefined;\n\t\tconst overflowLabelWidth = overflowLabel ? visibleWidth(overflowLabel) : 0;\n\t\tconst overflowStart = Math.floor((width - overflowLabelWidth) / 2);\n\t\tconst canFitOverflow = () =>\n\t\t\toverflowLabel !== undefined && overflowLabelWidth + 2 <= width && overflowStart - (3 + statusWidth + 1) >= 1;\n\n\t\tif (overflowLabel && !canFitOverflow()) {\n\t\t\tstatus = this.workingStatusIndicator.renderSpinnerInBorder(width);\n\t\t\tstatusWidth = visibleWidth(status);\n\t\t}\n\n\t\tif (canFitOverflow()) {\n\t\t\tconst leftBlockWidth = 3 + statusWidth + 1;\n\t\t\treturn (\n\t\t\t\tthis.borderColor(\"── \") +\n\t\t\t\tstatus +\n\t\t\t\tthis.borderColor(\n\t\t\t\t\t` ${\"─\".repeat(overflowStart - leftBlockWidth)}${overflowLabel}${\"─\".repeat(width - overflowStart - overflowLabelWidth)}`,\n\t\t\t\t)\n\t\t\t);\n\t\t}\n\n\t\tif (width >= statusWidth + 5) {\n\t\t\treturn this.borderColor(\"── \") + status + this.borderColor(` ${\"─\".repeat(width - statusWidth - 4)}`);\n\t\t}\n\n\t\tstatus = this.workingStatusIndicator.renderSpinnerInBorder(width);\n\t\tstatusWidth = visibleWidth(status);\n\t\tconst prefixWidth = Math.min(3, Math.max(0, width - statusWidth));\n\t\treturn (\n\t\t\tthis.borderColor(\"─\".repeat(prefixWidth)) +\n\t\t\tstatus +\n\t\t\tthis.borderColor(\"─\".repeat(Math.max(0, width - prefixWidth - statusWidth)))\n\t\t);\n\t}\n\n\t/**\n\t * Register a handler for an app action.\n\t */\n\tonAction(action: AppKeybinding, handler: () => void): void {\n\t\tthis.actionHandlers.set(action, handler);\n\t}\n\n\thandleInput(data: string): void {\n\t\t// Check extension-registered shortcuts first\n\t\tif (this.onExtensionShortcut?.(data)) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Check for clipboard paste keybinding\n\t\tif (this.keybindings.matches(data, \"app.clipboard.pasteImage\")) {\n\t\t\tthis.onPasteImage?.();\n\t\t\treturn;\n\t\t}\n\n\t\t// Check app keybindings first\n\n\t\t// Escape/interrupt - only if autocomplete is NOT active\n\t\tif (this.keybindings.matches(data, \"app.interrupt\")) {\n\t\t\tif (!this.isShowingAutocomplete()) {\n\t\t\t\t// Use dynamic onEscape if set, otherwise registered handler\n\t\t\t\tconst handler = this.onEscape ?? this.actionHandlers.get(\"app.interrupt\");\n\t\t\t\tif (handler) {\n\t\t\t\t\thandler();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Let parent handle escape for autocomplete cancellation\n\t\t\tsuper.handleInput(data);\n\t\t\treturn;\n\t\t}\n\n\t\t// Exit (Ctrl+D) - only when editor is empty\n\t\tif (this.keybindings.matches(data, \"app.exit\")) {\n\t\t\tif (this.getText().length === 0) {\n\t\t\t\tconst handler = this.onCtrlD ?? this.actionHandlers.get(\"app.exit\");\n\t\t\t\tif (handler) handler();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// Fall through to editor handling for delete-char-forward when not empty\n\t\t}\n\n\t\t// Explicit history bindings take precedence over app actions while the editor is focused.\n\t\t// This lets users bind Ctrl+P even though it cycles models by default.\n\t\tif (\n\t\t\tthis.keybindings.matches(data, \"tui.editor.historyPrevious\") ||\n\t\t\tthis.keybindings.matches(data, \"tui.editor.historyNext\")\n\t\t) {\n\t\t\tsuper.handleInput(data);\n\t\t\treturn;\n\t\t}\n\n\t\t// Check all other app actions\n\t\tfor (const [action, handler] of this.actionHandlers) {\n\t\t\tif (action !== \"app.interrupt\" && action !== \"app.exit\" && this.keybindings.matches(data, action)) {\n\t\t\t\thandler();\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\t// Pass to parent for editor handling\n\t\tsuper.handleInput(data);\n\t}\n}\n"]}
1
+ {"version":3,"file":"custom-editor.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/custom-editor.ts"],"names":[],"mappings":"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","sourcesContent":["import { Editor, type EditorOptions, type EditorTheme, type TUI, visibleWidth } from \"@earendil-works/pi-tui\";\nimport type { AppKeybinding, KeybindingsManager } from \"../../../core/keybindings.ts\";\nimport type { StatusIndicator } from \"./status-indicator.ts\";\n\nexport type CustomEditorOptions = EditorOptions & {\n\t/** Render working, compaction, summarization, and retry status in the editor's top border. */\n\tembedWorkingStatus?: boolean;\n};\n\n/**\n * Custom editor that handles app-level keybindings for coding-agent.\n */\nexport class CustomEditor extends Editor {\n\tprivate keybindings: KeybindingsManager;\n\tprivate workingStatusIndicator: StatusIndicator | undefined;\n\tpublic readonly embedWorkingStatus: boolean;\n\tpublic actionHandlers: Map<AppKeybinding, () => void> = new Map();\n\n\t// Special handlers that can be dynamically replaced\n\tpublic onEscape?: () => void;\n\tpublic onCtrlD?: () => void;\n\tpublic onPasteImage?: () => void;\n\t/** Handler for extension-registered shortcuts. Returns true if handled. */\n\tpublic onExtensionShortcut?: (data: string) => boolean;\n\n\tconstructor(tui: TUI, theme: EditorTheme, keybindings: KeybindingsManager, options?: CustomEditorOptions) {\n\t\tsuper(tui, theme, options);\n\t\tthis.keybindings = keybindings;\n\t\tthis.embedWorkingStatus = options?.embedWorkingStatus ?? false;\n\t}\n\n\tsetWorkingStatusIndicator(indicator: StatusIndicator | undefined): void {\n\t\tthis.workingStatusIndicator = indicator;\n\t}\n\n\tprotected override renderTopBorder(width: number, hiddenLineCount: number): string {\n\t\tif (!this.embedWorkingStatus || !this.workingStatusIndicator || width <= 0) {\n\t\t\treturn super.renderTopBorder(width, hiddenLineCount);\n\t\t}\n\n\t\tlet status = this.workingStatusIndicator.renderInBorder(Math.max(1, width - 5));\n\t\tlet statusWidth = visibleWidth(status);\n\t\tif (statusWidth === 0) return super.renderTopBorder(width, hiddenLineCount);\n\n\t\tconst overflowLabel = hiddenLineCount > 0 ? ` ↑ ${hiddenLineCount} more ` : undefined;\n\t\tconst overflowLabelWidth = overflowLabel ? visibleWidth(overflowLabel) : 0;\n\t\tconst overflowStart = Math.floor((width - overflowLabelWidth) / 2);\n\t\tconst canFitOverflow = () =>\n\t\t\toverflowLabel !== undefined && overflowLabelWidth + 2 <= width && overflowStart - (3 + statusWidth + 1) >= 1;\n\n\t\tif (overflowLabel && !canFitOverflow()) {\n\t\t\tstatus = this.workingStatusIndicator.renderSpinnerInBorder(width);\n\t\t\tstatusWidth = visibleWidth(status);\n\t\t}\n\n\t\tif (canFitOverflow()) {\n\t\t\tconst leftBlockWidth = 3 + statusWidth + 1;\n\t\t\treturn (\n\t\t\t\tthis.borderColor(\"── \") +\n\t\t\t\tstatus +\n\t\t\t\tthis.borderColor(\n\t\t\t\t\t` ${\"─\".repeat(overflowStart - leftBlockWidth)}${overflowLabel}${\"─\".repeat(width - overflowStart - overflowLabelWidth)}`,\n\t\t\t\t)\n\t\t\t);\n\t\t}\n\n\t\tif (width >= statusWidth + 5) {\n\t\t\treturn this.borderColor(\"── \") + status + this.borderColor(` ${\"─\".repeat(width - statusWidth - 4)}`);\n\t\t}\n\n\t\tstatus = this.workingStatusIndicator.renderSpinnerInBorder(width);\n\t\tstatusWidth = visibleWidth(status);\n\t\tconst prefixWidth = Math.min(3, Math.max(0, width - statusWidth));\n\t\treturn (\n\t\t\tthis.borderColor(\"─\".repeat(prefixWidth)) +\n\t\t\tstatus +\n\t\t\tthis.borderColor(\"─\".repeat(Math.max(0, width - prefixWidth - statusWidth)))\n\t\t);\n\t}\n\n\t/**\n\t * Register a handler for an app action.\n\t */\n\tonAction(action: AppKeybinding, handler: () => void): void {\n\t\tthis.actionHandlers.set(action, handler);\n\t}\n\n\thandleInput(data: string): void {\n\t\t// Check extension-registered shortcuts first\n\t\tif (this.onExtensionShortcut?.(data)) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Check for clipboard paste keybinding\n\t\tif (this.keybindings.matches(data, \"app.clipboard.pasteImage\")) {\n\t\t\tthis.onPasteImage?.();\n\t\t\treturn;\n\t\t}\n\n\t\t// Check app keybindings first\n\n\t\t// Escape/interrupt - only if autocomplete is NOT active\n\t\tif (this.keybindings.matches(data, \"app.interrupt\")) {\n\t\t\tif (!this.isShowingAutocomplete()) {\n\t\t\t\t// Use dynamic onEscape if set, otherwise registered handler\n\t\t\t\tconst handler = this.onEscape ?? this.actionHandlers.get(\"app.interrupt\");\n\t\t\t\tif (handler) {\n\t\t\t\t\thandler();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Let parent handle escape for autocomplete cancellation\n\t\t\tsuper.handleInput(data);\n\t\t\treturn;\n\t\t}\n\n\t\t// Exit (Ctrl+D) - only when editor is empty\n\t\tif (this.keybindings.matches(data, \"app.exit\")) {\n\t\t\tif (this.getText().length === 0) {\n\t\t\t\tconst handler = this.onCtrlD ?? this.actionHandlers.get(\"app.exit\");\n\t\t\t\tif (handler) handler();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// Fall through to editor handling for delete-char-forward when not empty\n\t\t}\n\n\t\t// Explicit history bindings take precedence over app actions while the editor is focused.\n\t\t// This lets users bind Ctrl+P even though it cycles models by default.\n\t\tif (\n\t\t\tthis.keybindings.matches(data, \"tui.editor.historyPrevious\") ||\n\t\t\tthis.keybindings.matches(data, \"tui.editor.historyNext\")\n\t\t) {\n\t\t\tsuper.handleInput(data);\n\t\t\treturn;\n\t\t}\n\n\t\t// Check all other app actions\n\t\tfor (const [action, handler] of this.actionHandlers) {\n\t\t\tif (action !== \"app.interrupt\" && action !== \"app.exit\" && this.keybindings.matches(data, action)) {\n\t\t\t\thandler();\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\t// Pass to parent for editor handling\n\t\tsuper.handleInput(data);\n\t}\n}\n"]}
@@ -5,6 +5,8 @@ import { Container, type Focusable, type TUI } from "@earendil-works/pi-tui";
5
5
  export interface ExtensionInputOptions {
6
6
  tui?: TUI;
7
7
  timeout?: number;
8
+ initialValue?: string;
9
+ description?: string;
8
10
  }
9
11
  export declare class ExtensionInputComponent extends Container implements Focusable {
10
12
  private input;
@@ -1 +1 @@
1
- {"version":3,"file":"extension-input.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/extension-input.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,SAAS,EAAE,KAAK,SAAS,EAAuC,KAAK,GAAG,EAAE,MAAM,wBAAwB,CAAC;AAMlH,MAAM,WAAW,qBAAqB;IACrC,GAAG,CAAC,EAAE,GAAG,CAAC;IACV,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,uBAAwB,SAAQ,SAAU,YAAW,SAAS;IAC1E,OAAO,CAAC,KAAK,CAAQ;IACrB,OAAO,CAAC,gBAAgB,CAA0B;IAClD,OAAO,CAAC,gBAAgB,CAAa;IACrC,OAAO,CAAC,SAAS,CAAO;IACxB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,SAAS,CAA6B;IAG9C,OAAO,CAAC,QAAQ,CAAS;IACzB,IAAI,OAAO,IAAI,OAAO,CAErB;IACD,IAAI,OAAO,CAAC,KAAK,EAAE,OAAO,EAGzB;IAED,YACC,KAAK,EAAE,MAAM,EACb,YAAY,EAAE,MAAM,GAAG,SAAS,EAChC,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,EACjC,QAAQ,EAAE,MAAM,IAAI,EACpB,IAAI,CAAC,EAAE,qBAAqB,EAgC5B;IAED,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CASjC;IAED,OAAO,IAAI,IAAI,CAEd;CACD","sourcesContent":["/**\n * Simple text input component for extensions.\n */\n\nimport { Container, type Focusable, getKeybindings, Input, Spacer, Text, type TUI } from \"@earendil-works/pi-tui\";\nimport { theme } from \"../theme/theme.ts\";\nimport { CountdownTimer } from \"./countdown-timer.ts\";\nimport { DynamicBorder } from \"./dynamic-border.ts\";\nimport { keyHint } from \"./keybinding-hints.ts\";\n\nexport interface ExtensionInputOptions {\n\ttui?: TUI;\n\ttimeout?: number;\n}\n\nexport class ExtensionInputComponent extends Container implements Focusable {\n\tprivate input: Input;\n\tprivate onSubmitCallback: (value: string) => void;\n\tprivate onCancelCallback: () => void;\n\tprivate titleText: Text;\n\tprivate baseTitle: string;\n\tprivate countdown: CountdownTimer | undefined;\n\n\t// Focusable implementation - propagate to input for IME cursor positioning\n\tprivate _focused = false;\n\tget focused(): boolean {\n\t\treturn this._focused;\n\t}\n\tset focused(value: boolean) {\n\t\tthis._focused = value;\n\t\tthis.input.focused = value;\n\t}\n\n\tconstructor(\n\t\ttitle: string,\n\t\t_placeholder: string | undefined,\n\t\tonSubmit: (value: string) => void,\n\t\tonCancel: () => void,\n\t\topts?: ExtensionInputOptions,\n\t) {\n\t\tsuper();\n\n\t\tthis.onSubmitCallback = onSubmit;\n\t\tthis.onCancelCallback = onCancel;\n\t\tthis.baseTitle = title;\n\n\t\tthis.addChild(new DynamicBorder());\n\t\tthis.addChild(new Spacer(1));\n\n\t\tthis.titleText = new Text(theme.fg(\"accent\", title), 1, 0);\n\t\tthis.addChild(this.titleText);\n\t\tthis.addChild(new Spacer(1));\n\n\t\tif (opts?.timeout && opts.timeout > 0 && opts.tui) {\n\t\t\tthis.countdown = new CountdownTimer(\n\t\t\t\topts.timeout,\n\t\t\t\topts.tui,\n\t\t\t\t(s) => this.titleText.setText(theme.fg(\"accent\", `${this.baseTitle} (${s}s)`)),\n\t\t\t\t() => this.onCancelCallback(),\n\t\t\t);\n\t\t}\n\n\t\tthis.input = new Input();\n\t\tthis.addChild(this.input);\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(\n\t\t\tnew Text(`${keyHint(\"tui.select.confirm\", \"submit\")} ${keyHint(\"tui.select.cancel\", \"cancel\")}`, 1, 0),\n\t\t);\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(new DynamicBorder());\n\t}\n\n\thandleInput(keyData: string): void {\n\t\tconst kb = getKeybindings();\n\t\tif (kb.matches(keyData, \"tui.select.confirm\") || keyData === \"\\n\") {\n\t\t\tthis.onSubmitCallback(this.input.getValue());\n\t\t} else if (kb.matches(keyData, \"tui.select.cancel\")) {\n\t\t\tthis.onCancelCallback();\n\t\t} else {\n\t\t\tthis.input.handleInput(keyData);\n\t\t}\n\t}\n\n\tdispose(): void {\n\t\tthis.countdown?.dispose();\n\t}\n}\n"]}
1
+ {"version":3,"file":"extension-input.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/extension-input.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,SAAS,EAAE,KAAK,SAAS,EAAuC,KAAK,GAAG,EAAE,MAAM,wBAAwB,CAAC;AAMlH,MAAM,WAAW,qBAAqB;IACrC,GAAG,CAAC,EAAE,GAAG,CAAC;IACV,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,qBAAa,uBAAwB,SAAQ,SAAU,YAAW,SAAS;IAC1E,OAAO,CAAC,KAAK,CAAQ;IACrB,OAAO,CAAC,gBAAgB,CAA0B;IAClD,OAAO,CAAC,gBAAgB,CAAa;IACrC,OAAO,CAAC,SAAS,CAAO;IACxB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,SAAS,CAA6B;IAG9C,OAAO,CAAC,QAAQ,CAAS;IACzB,IAAI,OAAO,IAAI,OAAO,CAErB;IACD,IAAI,OAAO,CAAC,KAAK,EAAE,OAAO,EAGzB;IAED,YACC,KAAK,EAAE,MAAM,EACb,YAAY,EAAE,MAAM,GAAG,SAAS,EAChC,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,EACjC,QAAQ,EAAE,MAAM,IAAI,EACpB,IAAI,CAAC,EAAE,qBAAqB,EAqC5B;IAED,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CASjC;IAED,OAAO,IAAI,IAAI,CAEd;CACD","sourcesContent":["/**\n * Simple text input component for extensions.\n */\n\nimport { Container, type Focusable, getKeybindings, Input, Spacer, Text, type TUI } from \"@earendil-works/pi-tui\";\nimport { theme } from \"../theme/theme.ts\";\nimport { CountdownTimer } from \"./countdown-timer.ts\";\nimport { DynamicBorder } from \"./dynamic-border.ts\";\nimport { keyHint } from \"./keybinding-hints.ts\";\n\nexport interface ExtensionInputOptions {\n\ttui?: TUI;\n\ttimeout?: number;\n\tinitialValue?: string;\n\tdescription?: string;\n}\n\nexport class ExtensionInputComponent extends Container implements Focusable {\n\tprivate input: Input;\n\tprivate onSubmitCallback: (value: string) => void;\n\tprivate onCancelCallback: () => void;\n\tprivate titleText: Text;\n\tprivate baseTitle: string;\n\tprivate countdown: CountdownTimer | undefined;\n\n\t// Focusable implementation - propagate to input for IME cursor positioning\n\tprivate _focused = false;\n\tget focused(): boolean {\n\t\treturn this._focused;\n\t}\n\tset focused(value: boolean) {\n\t\tthis._focused = value;\n\t\tthis.input.focused = value;\n\t}\n\n\tconstructor(\n\t\ttitle: string,\n\t\t_placeholder: string | undefined,\n\t\tonSubmit: (value: string) => void,\n\t\tonCancel: () => void,\n\t\topts?: ExtensionInputOptions,\n\t) {\n\t\tsuper();\n\n\t\tthis.onSubmitCallback = onSubmit;\n\t\tthis.onCancelCallback = onCancel;\n\t\tthis.baseTitle = title;\n\n\t\tthis.addChild(new DynamicBorder());\n\t\tthis.addChild(new Spacer(1));\n\n\t\tthis.titleText = new Text(theme.fg(\"accent\", title), 1, 0);\n\t\tthis.addChild(this.titleText);\n\t\tif (opts?.description) {\n\t\t\tthis.addChild(new Spacer(1));\n\t\t\tthis.addChild(new Text(theme.fg(\"text\", opts.description), 1, 0));\n\t\t}\n\t\tthis.addChild(new Spacer(1));\n\n\t\tif (opts?.timeout && opts.timeout > 0 && opts.tui) {\n\t\t\tthis.countdown = new CountdownTimer(\n\t\t\t\topts.timeout,\n\t\t\t\topts.tui,\n\t\t\t\t(s) => this.titleText.setText(theme.fg(\"accent\", `${this.baseTitle} (${s}s)`)),\n\t\t\t\t() => this.onCancelCallback(),\n\t\t\t);\n\t\t}\n\n\t\tthis.input = new Input();\n\t\tif (opts?.initialValue) this.input.setValue(opts.initialValue);\n\t\tthis.addChild(this.input);\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(\n\t\t\tnew Text(`${keyHint(\"tui.select.confirm\", \"submit\")} ${keyHint(\"tui.select.cancel\", \"cancel\")}`, 1, 0),\n\t\t);\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(new DynamicBorder());\n\t}\n\n\thandleInput(keyData: string): void {\n\t\tconst kb = getKeybindings();\n\t\tif (kb.matches(keyData, \"tui.select.confirm\") || keyData === \"\\n\") {\n\t\t\tthis.onSubmitCallback(this.input.getValue());\n\t\t} else if (kb.matches(keyData, \"tui.select.cancel\")) {\n\t\t\tthis.onCancelCallback();\n\t\t} else {\n\t\t\tthis.input.handleInput(keyData);\n\t\t}\n\t}\n\n\tdispose(): void {\n\t\tthis.countdown?.dispose();\n\t}\n}\n"]}