@linxiraos/pi-tui 1.2.0 → 1.3.0

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 (276) hide show
  1. package/CHANGELOG.md +188 -120
  2. package/README.md +36 -0
  3. package/THIRD-PARTY-NOTICES.txt +55 -5
  4. package/dist/types/app-keybindings.d.ts +18 -8
  5. package/dist/types/apps/git/diff-pane.d.ts +5 -0
  6. package/dist/types/apps/git/git-tui.d.ts +16 -2
  7. package/dist/types/apps/git/state.d.ts +11 -0
  8. package/dist/types/autocomplete.d.ts +2 -0
  9. package/dist/types/charts/chart-svg.d.ts +7 -13
  10. package/dist/types/chat/advisor-message.d.ts +4 -1
  11. package/dist/types/chat/assistant-message.d.ts +9 -4
  12. package/dist/types/chat/figure-markdown.d.ts +7 -2
  13. package/dist/types/chat/messages.d.ts +3 -1
  14. package/dist/types/chat/read-tool-group.d.ts +2 -2
  15. package/dist/types/chat/table-chart.d.ts +11 -15
  16. package/dist/types/chat/tool-execution.d.ts +32 -20
  17. package/dist/types/chat/user-message.d.ts +3 -2
  18. package/dist/types/chrome/countdown-timer.d.ts +3 -2
  19. package/dist/types/chrome/diff.d.ts +2 -3
  20. package/dist/types/chrome/transcript-container.d.ts +2 -0
  21. package/dist/types/components/image.d.ts +2 -0
  22. package/dist/types/components/markdown.d.ts +49 -3
  23. package/dist/types/components/text.d.ts +2 -0
  24. package/dist/types/debug-server.d.ts +2 -0
  25. package/dist/types/keybinding-matchers.d.ts +6 -0
  26. package/dist/types/multiplexers/tmux.d.ts +1 -0
  27. package/dist/types/multiplexers/types.d.ts +6 -0
  28. package/dist/types/native/backend.d.ts +5 -4
  29. package/dist/types/native/blobs.d.ts +24 -12
  30. package/dist/types/overlays/agent-hub-projection.d.ts +10 -5
  31. package/dist/types/overlays/annotation-overlay.d.ts +19 -0
  32. package/dist/types/overlays/approval-dialog.d.ts +79 -0
  33. package/dist/types/overlays/ask-dialog.d.ts +11 -6
  34. package/dist/types/overlays/btw-history-panel.d.ts +2 -6
  35. package/dist/types/overlays/hook-editor.d.ts +7 -2
  36. package/dist/types/overlays/hook-input.d.ts +12 -4
  37. package/dist/types/overlays/job-tree.d.ts +50 -0
  38. package/dist/types/overlays/jobs-panel.d.ts +25 -11
  39. package/dist/types/overlays/login-dialog.d.ts +8 -3
  40. package/dist/types/overlays/mcp-add-wizard.d.ts +9 -1
  41. package/dist/types/overlays/model-browser.d.ts +6 -1
  42. package/dist/types/overlays/model-picker.d.ts +2 -0
  43. package/dist/types/overlays/pause-screen.d.ts +5 -0
  44. package/dist/types/overlays/plan-review-overlay.d.ts +4 -0
  45. package/dist/types/overlays/report-panel.d.ts +5 -1
  46. package/dist/types/overlays/reset-usage-selector.d.ts +7 -5
  47. package/dist/types/overlays/session-account-selector.d.ts +4 -0
  48. package/dist/types/overlays/session-info-overlay.d.ts +7 -3
  49. package/dist/types/overlays/session-selector.d.ts +3 -1
  50. package/dist/types/overlays/usage-dashboard.d.ts +6 -6
  51. package/dist/types/prompt/composer.d.ts +22 -26
  52. package/dist/types/prompt/custom-editor.d.ts +20 -10
  53. package/dist/types/prompt/image-references.d.ts +22 -0
  54. package/dist/types/prompt/internal-url-autocomplete.d.ts +1 -0
  55. package/dist/types/prompt/macos-spelling.d.ts +2 -1
  56. package/dist/types/prompt/prose-gate.d.ts +3 -0
  57. package/dist/types/prompt/queued-messages.d.ts +1 -1
  58. package/dist/types/prompt/typing-word.d.ts +25 -0
  59. package/dist/types/prompt/welcome.d.ts +35 -43
  60. package/dist/types/render/hanging-wrap.d.ts +7 -0
  61. package/dist/types/render/hyperlink.d.ts +2 -0
  62. package/dist/types/render/render-utils.d.ts +9 -1
  63. package/dist/types/render/utils.d.ts +1 -1
  64. package/dist/types/setup/scenes/splash.d.ts +6 -5
  65. package/dist/types/status-line/context-usage.d.ts +4 -1
  66. package/dist/types/status-line/host.d.ts +6 -4
  67. package/dist/types/status-line/startup.d.ts +6 -6
  68. package/dist/types/status-line/types.d.ts +3 -0
  69. package/dist/types/stdin-buffer.d.ts +7 -0
  70. package/dist/types/terminal-capabilities.d.ts +16 -1
  71. package/dist/types/terminal-multiplexer.d.ts +7 -0
  72. package/dist/types/terminal.d.ts +8 -4
  73. package/dist/types/theme/symbols.d.ts +1 -1
  74. package/dist/types/theme/theme.d.ts +11 -0
  75. package/dist/types/thinking.d.ts +5 -0
  76. package/dist/types/tmux.d.ts +39 -4
  77. package/dist/types/tools/ast-edit.d.ts +2 -2
  78. package/dist/types/tools/ast-grep.d.ts +2 -2
  79. package/dist/types/tools/bash.d.ts +6 -1
  80. package/dist/types/tools/edit.d.ts +2 -0
  81. package/dist/types/tools/eval.d.ts +53 -4
  82. package/dist/types/tools/find.d.ts +14 -4
  83. package/dist/types/tools/glob.d.ts +3 -3
  84. package/dist/types/tools/grep.d.ts +2 -2
  85. package/dist/types/tools/grouped-file-output.d.ts +9 -4
  86. package/dist/types/tools/native-view.d.ts +1 -1
  87. package/dist/types/tools/read.d.ts +32 -10
  88. package/dist/types/tools/renderer.d.ts +2 -0
  89. package/dist/types/tools/task.d.ts +31 -0
  90. package/dist/types/tools/write.d.ts +2 -0
  91. package/dist/types/tui.d.ts +20 -3
  92. package/package.json +10 -10
  93. package/src/app-keybindings.d.ts +18 -8
  94. package/src/app-keybindings.ts +20 -8
  95. package/src/apps/autoresearch-dashboard.ts +444 -27
  96. package/src/apps/debug/raw-sse.ts +2 -2
  97. package/src/apps/git/diff-pane.ts +39 -41
  98. package/src/apps/git/git-tui.ts +80 -14
  99. package/src/apps/git/sidebar.ts +10 -1
  100. package/src/apps/git/state.ts +12 -0
  101. package/src/autocomplete.d.ts +2 -0
  102. package/src/autocomplete.ts +21 -19
  103. package/src/bracketed-paste.ts +9 -2
  104. package/src/charts/chart-svg.d.ts +7 -13
  105. package/src/charts/chart-svg.ts +19 -22
  106. package/src/chat/advisor-message.d.ts +4 -1
  107. package/src/chat/advisor-message.ts +77 -24
  108. package/src/chat/assistant-message.d.ts +9 -4
  109. package/src/chat/assistant-message.ts +127 -31
  110. package/src/chat/bash-execution.ts +7 -2
  111. package/src/chat/figure-markdown.d.ts +7 -2
  112. package/src/chat/figure-markdown.ts +10 -3
  113. package/src/chat/image-loading.ts +9 -6
  114. package/src/chat/messages.d.ts +3 -1
  115. package/src/chat/messages.ts +4 -1
  116. package/src/chat/read-tool-group.d.ts +2 -2
  117. package/src/chat/read-tool-group.ts +97 -42
  118. package/src/chat/svg-figure.ts +3 -1
  119. package/src/chat/svg-source.ts +6 -3
  120. package/src/chat/table-chart.d.ts +11 -15
  121. package/src/chat/table-chart.ts +24 -57
  122. package/src/chat/tool-execution.d.ts +32 -20
  123. package/src/chat/tool-execution.ts +103 -36
  124. package/src/chat/user-message.d.ts +3 -2
  125. package/src/chat/user-message.ts +54 -34
  126. package/src/chrome/countdown-timer.ts +3 -3
  127. package/src/chrome/diff.d.ts +2 -3
  128. package/src/chrome/diff.ts +4 -9
  129. package/src/chrome/transcript-container.d.ts +2 -0
  130. package/src/chrome/transcript-container.ts +212 -28
  131. package/src/components/editor.ts +12 -12
  132. package/src/components/image.d.ts +2 -0
  133. package/src/components/image.ts +54 -20
  134. package/src/components/markdown.d.ts +49 -3
  135. package/src/components/markdown.ts +461 -11
  136. package/src/components/settings-list.ts +2 -4
  137. package/src/components/text.d.ts +2 -0
  138. package/src/components/text.ts +11 -1
  139. package/src/debug-server.d.ts +2 -0
  140. package/src/debug-server.ts +51 -69
  141. package/src/hotkeys-markdown.ts +2 -0
  142. package/src/keybinding-matchers.d.ts +6 -0
  143. package/src/keybinding-matchers.ts +19 -0
  144. package/src/multiplexers/tmux.d.ts +1 -0
  145. package/src/multiplexers/tmux.ts +3 -0
  146. package/src/multiplexers/types.d.ts +6 -0
  147. package/src/multiplexers/types.ts +6 -0
  148. package/src/native/backend.d.ts +5 -4
  149. package/src/native/backend.ts +13 -5
  150. package/src/native/blobs.d.ts +24 -12
  151. package/src/native/blobs.ts +56 -7
  152. package/src/native/reconcile.ts +43 -21
  153. package/src/overlays/advisor-config.ts +259 -8
  154. package/src/overlays/agent-hub-projection.d.ts +10 -5
  155. package/src/overlays/agent-hub-projection.ts +63 -12
  156. package/src/overlays/agent-hub.ts +2 -2
  157. package/src/overlays/annotation-overlay.ts +422 -168
  158. package/src/overlays/approval-dialog.ts +389 -0
  159. package/src/overlays/ask-dialog.ts +244 -105
  160. package/src/overlays/btw-history-panel.ts +208 -147
  161. package/src/overlays/extensions/extension-list.ts +4 -6
  162. package/src/overlays/hook-editor.ts +90 -32
  163. package/src/overlays/hook-input.ts +105 -19
  164. package/src/overlays/job-tree.ts +177 -0
  165. package/src/overlays/jobs-panel.ts +222 -142
  166. package/src/overlays/login-dialog.ts +201 -91
  167. package/src/overlays/mcp-add-wizard.ts +562 -279
  168. package/src/overlays/model-browser.ts +32 -7
  169. package/src/overlays/model-hub.ts +4 -10
  170. package/src/overlays/model-picker.ts +58 -21
  171. package/src/overlays/pause-screen.ts +81 -23
  172. package/src/overlays/plan-review-overlay.ts +16 -0
  173. package/src/overlays/plugin-selector.ts +17 -1
  174. package/src/overlays/plugin-settings.ts +8 -2
  175. package/src/overlays/queue-mode-selector.ts +10 -0
  176. package/src/overlays/report-panel.ts +6 -2
  177. package/src/overlays/reset-usage-selector.ts +130 -21
  178. package/src/overlays/session-account-selector.ts +36 -0
  179. package/src/overlays/session-info-overlay.ts +199 -76
  180. package/src/overlays/session-selector.ts +15 -10
  181. package/src/overlays/settings-selector.ts +3 -0
  182. package/src/overlays/show-images-selector.ts +1 -0
  183. package/src/overlays/snapcompact-shape-preview.ts +13 -6
  184. package/src/overlays/theme-selector.ts +6 -1
  185. package/src/overlays/thinking-selector.ts +8 -4
  186. package/src/overlays/tree-selector.ts +117 -2
  187. package/src/overlays/usage-dashboard.ts +498 -144
  188. package/src/prompt/composer-cache.ts +4 -6
  189. package/src/prompt/composer.ts +196 -96
  190. package/src/prompt/custom-editor.ts +168 -65
  191. package/src/prompt/image-references.d.ts +22 -0
  192. package/src/prompt/image-references.ts +79 -2
  193. package/src/prompt/internal-url-autocomplete.ts +1 -0
  194. package/src/prompt/macos-spelling.ts +28 -5
  195. package/src/prompt/prose-gate.ts +3 -0
  196. package/src/prompt/queued-messages.ts +9 -2
  197. package/src/prompt/tips.txt +1 -2
  198. package/src/prompt/typing-word.ts +59 -0
  199. package/src/prompt/welcome.ts +256 -423
  200. package/src/render/code-cell.ts +18 -5
  201. package/src/render/hanging-wrap.d.ts +7 -0
  202. package/src/render/hanging-wrap.ts +58 -0
  203. package/src/render/hyperlink.d.ts +2 -0
  204. package/src/render/hyperlink.ts +5 -0
  205. package/src/render/render-utils.d.ts +9 -1
  206. package/src/render/render-utils.ts +16 -2
  207. package/src/render/utils.d.ts +1 -1
  208. package/src/render/utils.ts +1 -1
  209. package/src/render/width-aware-text.ts +6 -5
  210. package/src/setup/scenes/splash.ts +137 -60
  211. package/src/status-line/component.ts +23 -10
  212. package/src/status-line/context-usage.ts +176 -73
  213. package/src/status-line/footer.ts +18 -35
  214. package/src/status-line/host.ts +6 -1
  215. package/src/status-line/segments.ts +16 -5
  216. package/src/status-line/startup.ts +6 -6
  217. package/src/status-line/types.ts +1 -0
  218. package/src/stdin-buffer.d.ts +7 -0
  219. package/src/stdin-buffer.ts +11 -1
  220. package/src/terminal-capabilities.d.ts +16 -1
  221. package/src/terminal-capabilities.ts +66 -28
  222. package/src/terminal-multiplexer.d.ts +7 -0
  223. package/src/terminal-multiplexer.ts +14 -0
  224. package/src/terminal.d.ts +8 -4
  225. package/src/terminal.ts +160 -46
  226. package/src/theme/symbols.d.ts +1 -1
  227. package/src/theme/symbols.ts +1 -0
  228. package/src/theme/theme-class.ts +1 -0
  229. package/src/theme/theme.d.ts +11 -0
  230. package/src/theme/theme.ts +46 -14
  231. package/src/thinking.d.ts +5 -0
  232. package/src/thinking.ts +9 -1
  233. package/src/tmux.d.ts +39 -4
  234. package/src/tmux.ts +110 -16
  235. package/src/tools/ask.ts +20 -9
  236. package/src/tools/ast-edit.d.ts +2 -2
  237. package/src/tools/ast-edit.ts +30 -7
  238. package/src/tools/ast-grep.d.ts +2 -2
  239. package/src/tools/ast-grep.ts +39 -35
  240. package/src/tools/bash.d.ts +6 -1
  241. package/src/tools/bash.ts +15 -9
  242. package/src/tools/debug.ts +2 -1
  243. package/src/tools/default-renderer.ts +3 -2
  244. package/src/tools/edit.d.ts +2 -0
  245. package/src/tools/edit.ts +100 -21
  246. package/src/tools/eval.d.ts +53 -4
  247. package/src/tools/eval.ts +173 -137
  248. package/src/tools/find.d.ts +14 -4
  249. package/src/tools/find.ts +71 -18
  250. package/src/tools/glob.d.ts +3 -3
  251. package/src/tools/glob.ts +51 -17
  252. package/src/tools/grep.d.ts +2 -2
  253. package/src/tools/grep.ts +99 -22
  254. package/src/tools/grouped-file-output.d.ts +9 -4
  255. package/src/tools/grouped-file-output.ts +21 -6
  256. package/src/tools/lsp.ts +30 -18
  257. package/src/tools/mcp.ts +2 -2
  258. package/src/tools/native-view.d.ts +1 -1
  259. package/src/tools/native-view.ts +2 -2
  260. package/src/tools/read.d.ts +32 -10
  261. package/src/tools/read.ts +89 -43
  262. package/src/tools/renderer.d.ts +2 -0
  263. package/src/tools/renderer.ts +2 -0
  264. package/src/tools/task.d.ts +31 -0
  265. package/src/tools/task.ts +40 -7
  266. package/src/tools/todo.ts +3 -2
  267. package/src/tools/wait.ts +16 -30
  268. package/src/tools/web-search.ts +2 -1
  269. package/src/tools/write.d.ts +2 -0
  270. package/src/tools/write.ts +36 -12
  271. package/src/tools/yield.ts +2 -2
  272. package/src/tui.d.ts +20 -3
  273. package/src/tui.ts +140 -36
  274. package/src/utils.ts +5 -3
  275. package/dist/types/tools/eval-format/code-mode-declarations.d.ts +0 -5
  276. package/src/tools/eval-format/code-mode-declarations.ts +0 -61
@@ -4,13 +4,15 @@ import {
4
4
  encodeSixelNow,
5
5
  getCellDimensions,
6
6
  getImageDimensions,
7
+ getTerminalBackgroundColor,
7
8
  type ImageDimensions,
8
9
  ImageProtocol,
9
10
  imageFallback,
10
11
  renderImage,
11
12
  TERMINAL,
12
13
  } from "../terminal-capabilities";
13
- import { nativeImageNode } from "../native/blobs";
14
+ import { nativeImageNode, openableImageProps } from "../native/blobs";
15
+ import { imageLinksEnabled, linkedImageText, transcriptImageLink } from "../prompt/image-references";
14
16
  import type { DescribeContext, NativeNode } from "../native/node";
15
17
  import type { Component } from "../tui";
16
18
 
@@ -22,6 +24,8 @@ export interface ImageOptions {
22
24
  maxWidthCells?: number;
23
25
  maxHeightCells?: number;
24
26
  filename?: string;
27
+ /** File the image was read from; its link target. Images without one link to a blob copy of their bytes. */
28
+ sourcePath?: string;
25
29
  /** Shared budget that caps how many inline images render as live graphics. */
26
30
  budget?: ImageBudget;
27
31
  /**
@@ -38,6 +42,13 @@ export interface ImageOptions {
38
42
  requestRender?: () => void;
39
43
  }
40
44
 
45
+ interface SixelEncode {
46
+ widthPx: number;
47
+ heightPx: number;
48
+ backgroundRgb: number;
49
+ sequence?: string | null;
50
+ }
51
+
41
52
  /** Renders in progress whose rows are bound for native scrollback. */
42
53
  let scrollbackRenderDepth = 0;
43
54
 
@@ -652,14 +663,17 @@ export class Image implements Component {
652
663
  #cachedImageProtocol: typeof TERMINAL.imageProtocol = null;
653
664
  #cachedCellWidthPx = 0;
654
665
  #cachedCellHeightPx = 0;
666
+ #cachedSixelBackground: number | undefined;
655
667
  #cachedKittyUnicodePlaceholders = false;
668
+ #cachedLinked = false;
656
669
  // Tallest graphic placement this image has rendered. The text fallback
657
670
  // pads itself to this height so a budget demotion never shrinks the block
658
671
  // (its rows may already be committed to native scrollback).
659
672
  #renderedGraphicRows = 0;
660
- #native?: NativeNode;
661
- /** Newest SIXEL encode: its target size and, once settled, the sequence (`null` on failure). */
662
- #sixel?: { widthPx: number; heightPx: number; sequence?: string | null };
673
+ /** Described node and the link policy it was built under (an `off` switch drops its `href`). */
674
+ #native?: { linked: boolean; node: NativeNode };
675
+ /** Newest SIXEL encode: target size, compositing background, and settled sequence. */
676
+ #sixel?: SixelEncode;
663
677
 
664
678
  constructor(
665
679
  base64Data: string,
@@ -699,33 +713,38 @@ export class Image implements Component {
699
713
  }
700
714
 
701
715
  /**
702
- * SIXEL sequence for a target size. A new size starts the encode off the JS
716
+ * SIXEL sequence for a target size and background. A change starts the encode off the JS
703
717
  * thread and answers `undefined` until it settles; the settled encode
704
718
  * invalidates the cached lines and requests a repaint. A render bound for
705
719
  * scrollback cannot wait, so it encodes synchronously.
706
720
  */
707
- #sixelSequence(widthPx: number, heightPx: number): string | null | undefined {
721
+ #sixelSequence(widthPx: number, heightPx: number, backgroundRgb: number): string | null | undefined {
708
722
  const current = this.#sixel;
709
- const sameSize = current !== undefined && current.widthPx === widthPx && current.heightPx === heightPx;
710
- if (sameSize && current.sequence !== undefined) return current.sequence;
723
+ const sameInput =
724
+ current !== undefined &&
725
+ current.widthPx === widthPx &&
726
+ current.heightPx === heightPx &&
727
+ current.backgroundRgb === backgroundRgb;
728
+ if (sameInput && current.sequence !== undefined) return current.sequence;
711
729
  if (scrollbackRenderDepth > 0) {
712
730
  // Replacing the entry makes a still-pending async encode settle as stale.
713
- const sequence = encodeSixelNow(this.#base64Data, widthPx, heightPx);
714
- this.#sixel = { widthPx, heightPx, sequence };
731
+ const sequence = encodeSixelNow(this.#base64Data, widthPx, heightPx, backgroundRgb);
732
+ this.#sixel = { widthPx, heightPx, backgroundRgb, sequence };
715
733
  return sequence;
716
734
  }
717
- if (sameSize) return undefined;
718
- const request: { widthPx: number; heightPx: number; sequence?: string | null } = { widthPx, heightPx };
735
+ if (sameInput) return undefined;
736
+ const request: SixelEncode = { widthPx, heightPx, backgroundRgb };
719
737
  this.#sixel = request;
720
738
  const settle = (sequence: string | null): void => {
721
739
  request.sequence = sequence;
722
- if (this.#sixel !== request) return;
740
+ if (this.#sixel !== request || getTerminalBackgroundColor() !== backgroundRgb) return;
723
741
  this.invalidate();
724
742
  if (this.#options.requestRender) this.#options.requestRender();
725
743
  else this.#budget?.requestRender();
726
744
  };
727
- encodeSixelAsync(new Uint8Array(Buffer.from(this.#base64Data, "base64")), widthPx, heightPx).then(settle, () =>
728
- settle(null),
745
+ encodeSixelAsync(new Uint8Array(Buffer.from(this.#base64Data, "base64")), widthPx, heightPx, backgroundRgb).then(
746
+ settle,
747
+ () => settle(null),
729
748
  );
730
749
  return undefined;
731
750
  }
@@ -736,10 +755,12 @@ export class Image implements Component {
736
755
  * graphics protocols do not apply.
737
756
  */
738
757
  describe(_cx: DescribeContext): NativeNode {
739
- if (this.#native) return this.#native;
758
+ const linked = imageLinksEnabled();
759
+ if (this.#native?.linked === linked) return this.#native.node;
740
760
  const maxW = this.#options.maxWidthCells;
741
761
  const maxH = this.#options.maxHeightCells;
742
- this.#native = nativeImageNode(Buffer.from(this.#base64Data, "base64"), this.#mimeType, {
762
+ const href = transcriptImageLink({ data: this.#base64Data, mimeType: this.#mimeType }, this.#options.sourcePath);
763
+ const node = nativeImageNode(Buffer.from(this.#base64Data, "base64"), this.#mimeType, {
743
764
  alt: imageFallback(this.#mimeType, this.#dimensions, this.#options.filename),
744
765
  w: this.#dimensions.widthPx,
745
766
  h: this.#dimensions.heightPx,
@@ -750,8 +771,10 @@ export class Image implements Component {
750
771
  h: maxH && maxH > 0 ? `${maxH}lines` : undefined,
751
772
  }
752
773
  : undefined,
774
+ ...openableImageProps(href),
753
775
  });
754
- return this.#native;
776
+ this.#native = { linked, node };
777
+ return node;
755
778
  }
756
779
 
757
780
  render(width: number): readonly string[] {
@@ -759,6 +782,7 @@ export class Image implements Component {
759
782
  const hasProtocol = imageProtocol != null;
760
783
  const cellDimensions = getCellDimensions();
761
784
  const kittyUnicodePlaceholders = getKittyGraphics().unicodePlaceholders;
785
+ const sixelBackground = imageProtocol === ImageProtocol.Sixel ? getTerminalBackgroundColor() : undefined;
762
786
  // observe() must run on every pass — even a cache hit — so the image keeps
763
787
  // its display-order slot in the budget. Only graphics-capable frames count
764
788
  // toward (and are demoted by) the budget; without a protocol every image is
@@ -771,6 +795,7 @@ export class Image implements Component {
771
795
  // re-encode the full image on every render pass.
772
796
  const imageId = this.#imageId;
773
797
  const transmitsSeparately = imageProtocol === ImageProtocol.Kitty && imageId != null;
798
+ const linked = imageLinksEnabled();
774
799
 
775
800
  if (
776
801
  this.#cachedLines &&
@@ -779,7 +804,10 @@ export class Image implements Component {
779
804
  this.#cachedImageProtocol === imageProtocol &&
780
805
  this.#cachedCellWidthPx === cellDimensions.widthPx &&
781
806
  this.#cachedCellHeightPx === cellDimensions.heightPx &&
807
+ this.#cachedSixelBackground === sixelBackground &&
782
808
  this.#cachedKittyUnicodePlaceholders === kittyUnicodePlaceholders &&
809
+ // The text fallback embeds a link only under an enabled hyperlink policy.
810
+ this.#cachedLinked === linked &&
783
811
  (!transmitsSeparately || this.#budget?.shouldTransmit(imageId) !== true) &&
784
812
  // Cached rows reserved for a pending SIXEL encode must not reach scrollback.
785
813
  !(scrollbackRenderDepth > 0 && this.#sixel !== undefined && this.#sixel.sequence === undefined)
@@ -801,7 +829,7 @@ export class Image implements Component {
801
829
  maxHeightCells: this.#options.maxHeightCells,
802
830
  imageId: this.#imageId,
803
831
  includeTransmit: needsTransmit,
804
- sixel: (widthPx, heightPx) => this.#sixelSequence(widthPx, heightPx),
832
+ sixel: (widthPx, heightPx) => this.#sixelSequence(widthPx, heightPx, sixelBackground!),
805
833
  });
806
834
 
807
835
  if (result?.transmit && this.#imageId != null && this.#budget !== undefined) {
@@ -849,7 +877,9 @@ export class Image implements Component {
849
877
  this.#cachedImageProtocol = imageProtocol;
850
878
  this.#cachedCellWidthPx = cellDimensions.widthPx;
851
879
  this.#cachedCellHeightPx = cellDimensions.heightPx;
880
+ this.#cachedSixelBackground = sixelBackground;
852
881
  this.#cachedKittyUnicodePlaceholders = kittyUnicodePlaceholders;
882
+ this.#cachedLinked = linked;
853
883
 
854
884
  return lines;
855
885
  }
@@ -864,7 +894,11 @@ export class Image implements Component {
864
894
  */
865
895
  #fallbackLines(): string[] {
866
896
  const fallback = this.#theme.fallbackColor(
867
- imageFallback(this.#mimeType, this.#dimensions, this.#options.filename),
897
+ linkedImageText(
898
+ imageFallback(this.#mimeType, this.#dimensions, this.#options.filename),
899
+ { data: this.#base64Data, mimeType: this.#mimeType },
900
+ this.#options.sourcePath,
901
+ ),
868
902
  );
869
903
  if (this.#renderedGraphicRows <= 1) return [fallback];
870
904
  const lines: string[] = [];
@@ -2,6 +2,51 @@ import { type TokensList } from "@linxiraos/pi-utils/marked";
2
2
  import type { DescribeContext, NativeNode } from "../native/node";
3
3
  import type { SymbolTheme } from "../symbols";
4
4
  import type { Component } from "../tui";
5
+ /**
6
+ * `text` as the streaming renderer lexes it: OSC 8 terminators unified and
7
+ * tabs expanded. {@link Markdown.getLastRenderStableText} is a prefix of this
8
+ * form, not of the raw source, so append-only publishers that mix settled
9
+ * prefixes with whole blocks must compare both in this form. Rendering it is
10
+ * byte-identical to rendering `text`.
11
+ */
12
+ export declare function streamingMarkdownSource(text: string): string;
13
+ /**
14
+ * Streaming `md` source for a native terminal, minus a still-growing table row:
15
+ * the unterminated last line when a GFM table (a run of pipe lines holding a
16
+ * header and its delimiter row, outer pipes optional) sits right above it,
17
+ * outside any open code fence. GFM continues a table on any non-blank line, so
18
+ * that line is a row whatever it holds so far. The terminal sizes columns by
19
+ * every row it gets, so a half-streamed row (an unclosed link shows its whole
20
+ * URL) would rewrap the table each frame, and TSP cannot ask it to skip one.
21
+ * The result keeps the newline before the held line, so it is a prefix of
22
+ * `text` and of the result for every append to it: streaming stays
23
+ * append-only. Pass untrimmed source: trimming first drops the newline that
24
+ * marks the last row finished, so that row would be held too.
25
+ */
26
+ export declare function holdPartialTableRow(text: string): string;
27
+ /**
28
+ * `text`, one inline run whose end is still streaming, with a trailing open
29
+ * link or math span closed the way the finished text most likely closes it,
30
+ * or `undefined` when nothing at its end is open. A link gains its missing
31
+ * `)` (one per open parenthesis in its destination), so it renders as the
32
+ * link it becomes instead of literal brackets and URL. A math body is cut back
33
+ * to its last valid form (a half-typed command, dangling `^`/`_`, or the first
34
+ * `$` of a `$$` closer dropped, open braces closed) and closed, so the
35
+ * rendered math grows in place instead of raw LaTeX turning into symbols at
36
+ * the closer. A `$` body needs a LaTeX character, so a price (`$5 per`) is
37
+ * never speculated. Only prose is: escaped openers and anything inside a code
38
+ * span, closed or still being written, stay literal.
39
+ */
40
+ export declare function speculativeInlineClose(text: string): string | undefined;
41
+ /**
42
+ * Streaming `md` source for a native terminal with the open link or math span
43
+ * at its end speculatively closed ({@link speculativeInlineClose}), as the TUI
44
+ * renders it. Only the last block is read (a span cannot cross a blank line),
45
+ * and source inside an open code fence is left as it is. Each frame rewrites
46
+ * only the guessed closers at the end, which the reconciler sends as a small
47
+ * `splice`.
48
+ */
49
+ export declare function speculativeStreamingSource(text: string): string;
5
50
  /** @internal exported for tests — the grown-line block-kind gate. */
6
51
  export declare function fastLineStartHazard(grownLine: string): boolean;
7
52
  /**
@@ -140,9 +185,10 @@ export declare class Markdown implements Component {
140
185
  */
141
186
  describe(_cx: DescribeContext): NativeNode;
142
187
  /**
143
- * Width-independent source prefix of the last render ending at a frozen
144
- * Markdown block boundary that no append can move: it stops in front of a
145
- * display-math opener whose block an append could still close. Only
188
+ * Width-independent source prefix of the last render that no append can
189
+ * change: up to a frozen Markdown block boundary, stopping in front of a
190
+ * display-math opener whose block an append could still close, or, while a
191
+ * list streams as the last block, up to its newest top-level item. Only
146
192
  * meaningful while streaming (transient render cache on); grows
147
193
  * monotonically under append-only `setText`.
148
194
  */