@linxiraos/pi-tui 1.2.1 → 1.3.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 (280) hide show
  1. package/CHANGELOG.md +245 -224
  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/status-notice.d.ts +2 -0
  21. package/dist/types/chrome/transcript-container.d.ts +2 -0
  22. package/dist/types/components/image.d.ts +2 -0
  23. package/dist/types/components/markdown.d.ts +49 -3
  24. package/dist/types/components/text.d.ts +2 -0
  25. package/dist/types/debug-server.d.ts +2 -0
  26. package/dist/types/keybinding-matchers.d.ts +6 -0
  27. package/dist/types/multiplexers/tmux.d.ts +1 -0
  28. package/dist/types/multiplexers/types.d.ts +6 -0
  29. package/dist/types/native/backend.d.ts +5 -4
  30. package/dist/types/native/blobs.d.ts +24 -12
  31. package/dist/types/overlays/agent-hub-projection.d.ts +10 -5
  32. package/dist/types/overlays/annotation-overlay.d.ts +19 -0
  33. package/dist/types/overlays/approval-dialog.d.ts +79 -0
  34. package/dist/types/overlays/ask-dialog.d.ts +11 -6
  35. package/dist/types/overlays/btw-history-panel.d.ts +2 -6
  36. package/dist/types/overlays/hook-editor.d.ts +7 -2
  37. package/dist/types/overlays/hook-input.d.ts +12 -4
  38. package/dist/types/overlays/job-tree.d.ts +50 -0
  39. package/dist/types/overlays/jobs-panel.d.ts +25 -11
  40. package/dist/types/overlays/login-dialog.d.ts +8 -3
  41. package/dist/types/overlays/mcp-add-wizard.d.ts +9 -1
  42. package/dist/types/overlays/model-browser.d.ts +6 -1
  43. package/dist/types/overlays/model-picker.d.ts +2 -0
  44. package/dist/types/overlays/pause-screen.d.ts +5 -0
  45. package/dist/types/overlays/plan-review-overlay.d.ts +4 -0
  46. package/dist/types/overlays/report-panel.d.ts +5 -1
  47. package/dist/types/overlays/reset-usage-selector.d.ts +7 -5
  48. package/dist/types/overlays/session-account-selector.d.ts +4 -0
  49. package/dist/types/overlays/session-info-overlay.d.ts +7 -3
  50. package/dist/types/overlays/session-selector.d.ts +3 -1
  51. package/dist/types/overlays/usage-dashboard.d.ts +6 -6
  52. package/dist/types/prompt/composer.d.ts +23 -20
  53. package/dist/types/prompt/custom-editor.d.ts +20 -10
  54. package/dist/types/prompt/image-references.d.ts +22 -0
  55. package/dist/types/prompt/internal-url-autocomplete.d.ts +1 -0
  56. package/dist/types/prompt/macos-spelling.d.ts +2 -1
  57. package/dist/types/prompt/prose-gate.d.ts +3 -0
  58. package/dist/types/prompt/queued-messages.d.ts +1 -1
  59. package/dist/types/prompt/typing-word.d.ts +25 -0
  60. package/dist/types/prompt/welcome.d.ts +26 -6
  61. package/dist/types/render/hanging-wrap.d.ts +7 -0
  62. package/dist/types/render/hyperlink.d.ts +2 -0
  63. package/dist/types/render/render-utils.d.ts +9 -1
  64. package/dist/types/render/utils.d.ts +1 -1
  65. package/dist/types/setup/scenes/splash.d.ts +6 -5
  66. package/dist/types/status-line/context-usage.d.ts +4 -1
  67. package/dist/types/status-line/host.d.ts +6 -4
  68. package/dist/types/status-line/startup.d.ts +6 -6
  69. package/dist/types/status-line/types.d.ts +3 -0
  70. package/dist/types/stdin-buffer.d.ts +7 -0
  71. package/dist/types/terminal-capabilities.d.ts +16 -1
  72. package/dist/types/terminal-multiplexer.d.ts +7 -0
  73. package/dist/types/terminal.d.ts +8 -4
  74. package/dist/types/theme/symbols.d.ts +1 -1
  75. package/dist/types/theme/theme.d.ts +11 -0
  76. package/dist/types/thinking.d.ts +5 -0
  77. package/dist/types/tmux.d.ts +39 -4
  78. package/dist/types/tools/ast-edit.d.ts +2 -2
  79. package/dist/types/tools/ast-grep.d.ts +2 -2
  80. package/dist/types/tools/bash.d.ts +6 -1
  81. package/dist/types/tools/edit.d.ts +2 -0
  82. package/dist/types/tools/eval.d.ts +53 -4
  83. package/dist/types/tools/find.d.ts +14 -4
  84. package/dist/types/tools/glob.d.ts +3 -3
  85. package/dist/types/tools/grep.d.ts +2 -2
  86. package/dist/types/tools/grouped-file-output.d.ts +9 -4
  87. package/dist/types/tools/native-view.d.ts +1 -1
  88. package/dist/types/tools/read.d.ts +32 -10
  89. package/dist/types/tools/renderer.d.ts +2 -0
  90. package/dist/types/tools/task.d.ts +31 -0
  91. package/dist/types/tools/web-search-types.d.ts +1 -0
  92. package/dist/types/tools/write.d.ts +2 -0
  93. package/dist/types/tui.d.ts +20 -3
  94. package/package.json +10 -10
  95. package/src/app-keybindings.d.ts +18 -8
  96. package/src/app-keybindings.ts +20 -8
  97. package/src/apps/autoresearch-dashboard.ts +444 -27
  98. package/src/apps/debug/raw-sse.ts +2 -2
  99. package/src/apps/git/diff-pane.ts +39 -41
  100. package/src/apps/git/git-tui.ts +80 -14
  101. package/src/apps/git/sidebar.ts +10 -1
  102. package/src/apps/git/state.ts +12 -0
  103. package/src/autocomplete.d.ts +2 -0
  104. package/src/autocomplete.ts +21 -19
  105. package/src/bracketed-paste.ts +9 -2
  106. package/src/charts/chart-svg.d.ts +7 -13
  107. package/src/charts/chart-svg.ts +19 -22
  108. package/src/charts/table-data.ts +17 -6
  109. package/src/chat/advisor-message.d.ts +4 -1
  110. package/src/chat/advisor-message.ts +77 -24
  111. package/src/chat/assistant-message.d.ts +9 -4
  112. package/src/chat/assistant-message.ts +127 -31
  113. package/src/chat/bash-execution.ts +7 -2
  114. package/src/chat/figure-markdown.d.ts +7 -2
  115. package/src/chat/figure-markdown.ts +10 -3
  116. package/src/chat/image-loading.ts +9 -6
  117. package/src/chat/messages.d.ts +3 -1
  118. package/src/chat/messages.ts +4 -1
  119. package/src/chat/read-tool-group.d.ts +2 -2
  120. package/src/chat/read-tool-group.ts +97 -42
  121. package/src/chat/svg-figure.ts +3 -1
  122. package/src/chat/svg-source.ts +6 -3
  123. package/src/chat/table-chart.d.ts +11 -15
  124. package/src/chat/table-chart.ts +24 -57
  125. package/src/chat/tool-execution.d.ts +32 -20
  126. package/src/chat/tool-execution.ts +103 -36
  127. package/src/chat/user-message.d.ts +3 -2
  128. package/src/chat/user-message.ts +54 -34
  129. package/src/chrome/countdown-timer.ts +3 -3
  130. package/src/chrome/diff.d.ts +2 -3
  131. package/src/chrome/diff.ts +4 -9
  132. package/src/chrome/status-notice.ts +5 -0
  133. package/src/chrome/transcript-container.d.ts +2 -0
  134. package/src/chrome/transcript-container.ts +212 -28
  135. package/src/components/editor.ts +12 -12
  136. package/src/components/image.d.ts +2 -0
  137. package/src/components/image.ts +54 -20
  138. package/src/components/markdown.d.ts +49 -3
  139. package/src/components/markdown.ts +482 -12
  140. package/src/components/settings-list.ts +2 -4
  141. package/src/components/text.d.ts +2 -0
  142. package/src/components/text.ts +11 -1
  143. package/src/debug-server.d.ts +2 -0
  144. package/src/debug-server.ts +51 -69
  145. package/src/hotkeys-markdown.ts +2 -0
  146. package/src/keybinding-matchers.d.ts +6 -0
  147. package/src/keybinding-matchers.ts +19 -0
  148. package/src/multiplexers/tmux.d.ts +1 -0
  149. package/src/multiplexers/tmux.ts +3 -0
  150. package/src/multiplexers/types.d.ts +6 -0
  151. package/src/multiplexers/types.ts +6 -0
  152. package/src/native/backend.d.ts +5 -4
  153. package/src/native/backend.ts +13 -5
  154. package/src/native/blobs.d.ts +24 -12
  155. package/src/native/blobs.ts +56 -7
  156. package/src/native/reconcile.ts +43 -21
  157. package/src/overlays/advisor-config.ts +259 -8
  158. package/src/overlays/agent-hub-projection.d.ts +10 -5
  159. package/src/overlays/agent-hub-projection.ts +63 -12
  160. package/src/overlays/annotation-overlay.ts +422 -168
  161. package/src/overlays/approval-dialog.ts +389 -0
  162. package/src/overlays/ask-dialog.ts +244 -105
  163. package/src/overlays/btw-history-panel.ts +208 -147
  164. package/src/overlays/extensions/extension-list.ts +4 -6
  165. package/src/overlays/hook-editor.ts +90 -32
  166. package/src/overlays/hook-input.ts +105 -19
  167. package/src/overlays/job-tree.ts +177 -0
  168. package/src/overlays/jobs-panel.ts +222 -142
  169. package/src/overlays/login-dialog.ts +201 -91
  170. package/src/overlays/mcp-add-wizard.ts +562 -279
  171. package/src/overlays/model-browser.ts +32 -7
  172. package/src/overlays/model-hub.ts +4 -10
  173. package/src/overlays/model-picker.ts +58 -21
  174. package/src/overlays/pause-screen.ts +81 -23
  175. package/src/overlays/plan-review-overlay.ts +16 -0
  176. package/src/overlays/plugin-selector.ts +17 -1
  177. package/src/overlays/queue-mode-selector.ts +10 -0
  178. package/src/overlays/report-panel.ts +6 -2
  179. package/src/overlays/reset-usage-selector.ts +130 -21
  180. package/src/overlays/session-account-selector.ts +36 -0
  181. package/src/overlays/session-info-overlay.ts +199 -76
  182. package/src/overlays/session-selector.ts +15 -10
  183. package/src/overlays/settings-selector.ts +3 -0
  184. package/src/overlays/show-images-selector.ts +1 -0
  185. package/src/overlays/snapcompact-shape-preview.ts +13 -6
  186. package/src/overlays/theme-selector.ts +6 -1
  187. package/src/overlays/thinking-selector.ts +8 -4
  188. package/src/overlays/tree-selector.ts +117 -2
  189. package/src/overlays/usage-dashboard.ts +498 -144
  190. package/src/prompt/composer-cache.ts +4 -1
  191. package/src/prompt/composer.ts +200 -74
  192. package/src/prompt/custom-editor.ts +168 -65
  193. package/src/prompt/image-references.d.ts +22 -0
  194. package/src/prompt/image-references.ts +79 -2
  195. package/src/prompt/internal-url-autocomplete.ts +1 -0
  196. package/src/prompt/macos-spelling.ts +28 -5
  197. package/src/prompt/prose-gate.ts +3 -0
  198. package/src/prompt/queued-messages.ts +9 -2
  199. package/src/prompt/tips.txt +1 -2
  200. package/src/prompt/typing-word.ts +59 -0
  201. package/src/prompt/welcome.ts +97 -45
  202. package/src/render/code-cell.ts +18 -5
  203. package/src/render/hanging-wrap.d.ts +7 -0
  204. package/src/render/hanging-wrap.ts +58 -0
  205. package/src/render/hyperlink.d.ts +2 -0
  206. package/src/render/hyperlink.ts +5 -0
  207. package/src/render/render-utils.d.ts +9 -1
  208. package/src/render/render-utils.ts +16 -2
  209. package/src/render/utils.d.ts +1 -1
  210. package/src/render/utils.ts +1 -1
  211. package/src/render/width-aware-text.ts +6 -5
  212. package/src/setup/scenes/splash.ts +22 -8
  213. package/src/status-line/component.ts +79 -11
  214. package/src/status-line/context-usage.ts +176 -73
  215. package/src/status-line/footer.ts +18 -35
  216. package/src/status-line/host.ts +6 -1
  217. package/src/status-line/segments.ts +16 -5
  218. package/src/status-line/startup.ts +6 -6
  219. package/src/status-line/types.ts +1 -0
  220. package/src/stdin-buffer.d.ts +7 -0
  221. package/src/stdin-buffer.ts +300 -62
  222. package/src/terminal-capabilities.d.ts +16 -1
  223. package/src/terminal-capabilities.ts +66 -28
  224. package/src/terminal-multiplexer.d.ts +7 -0
  225. package/src/terminal-multiplexer.ts +14 -0
  226. package/src/terminal.d.ts +8 -4
  227. package/src/terminal.ts +190 -63
  228. package/src/theme/symbols.d.ts +1 -1
  229. package/src/theme/symbols.ts +1 -0
  230. package/src/theme/theme-class.ts +1 -0
  231. package/src/theme/theme.d.ts +11 -0
  232. package/src/theme/theme.ts +46 -14
  233. package/src/thinking.d.ts +5 -0
  234. package/src/thinking.ts +9 -1
  235. package/src/tmux.d.ts +39 -4
  236. package/src/tmux.ts +110 -16
  237. package/src/tools/ask.ts +20 -9
  238. package/src/tools/ast-edit.d.ts +2 -2
  239. package/src/tools/ast-edit.ts +30 -7
  240. package/src/tools/ast-grep.d.ts +2 -2
  241. package/src/tools/ast-grep.ts +39 -35
  242. package/src/tools/bash.d.ts +6 -1
  243. package/src/tools/bash.ts +15 -9
  244. package/src/tools/debug.ts +2 -1
  245. package/src/tools/default-renderer.ts +3 -2
  246. package/src/tools/edit.d.ts +2 -0
  247. package/src/tools/edit.ts +100 -21
  248. package/src/tools/eval.d.ts +53 -4
  249. package/src/tools/eval.ts +173 -137
  250. package/src/tools/find.d.ts +14 -4
  251. package/src/tools/find.ts +71 -18
  252. package/src/tools/glob.d.ts +3 -3
  253. package/src/tools/glob.ts +51 -17
  254. package/src/tools/grep.d.ts +2 -2
  255. package/src/tools/grep.ts +99 -22
  256. package/src/tools/grouped-file-output.d.ts +9 -4
  257. package/src/tools/grouped-file-output.ts +21 -6
  258. package/src/tools/lsp.ts +30 -18
  259. package/src/tools/mcp.ts +2 -2
  260. package/src/tools/native-view.d.ts +1 -1
  261. package/src/tools/native-view.ts +2 -2
  262. package/src/tools/read.d.ts +32 -10
  263. package/src/tools/read.ts +89 -43
  264. package/src/tools/renderer.d.ts +2 -0
  265. package/src/tools/renderer.ts +2 -0
  266. package/src/tools/task.d.ts +31 -0
  267. package/src/tools/task.ts +40 -7
  268. package/src/tools/todo.ts +3 -2
  269. package/src/tools/wait.ts +16 -30
  270. package/src/tools/web-search-types.d.ts +1 -0
  271. package/src/tools/web-search-types.ts +1 -0
  272. package/src/tools/web-search.ts +2 -1
  273. package/src/tools/write.d.ts +2 -0
  274. package/src/tools/write.ts +36 -12
  275. package/src/tools/yield.ts +2 -2
  276. package/src/tui.d.ts +20 -3
  277. package/src/tui.ts +160 -43
  278. package/src/utils.ts +5 -3
  279. package/dist/types/tools/eval-format/code-mode-declarations.d.ts +0 -5
  280. package/src/tools/eval-format/code-mode-declarations.ts +0 -61
@@ -12,16 +12,35 @@ import {
12
12
  } from "./kitty-graphics";
13
13
  import {
14
14
  isInsideTerminalMultiplexer,
15
+ isTerminalBackgroundQueryTrusted,
15
16
  routeTerminalMultiplexerNotification,
16
17
  terminalMultiplexerForTerm,
17
18
  terminalMultiplexerSessions,
18
19
  } from "./terminal-multiplexer";
19
- import { resolveTmuxClientTerminalName, wrapTmuxPassthroughIfNeeded } from "./tmux";
20
+ import { resolveTmuxClientTerminalNames, tmuxPaneAllowsPassthrough, wrapTmuxPassthroughIfNeeded } from "./tmux";
21
+ import { detectTerminalBackground } from "./theme/theme";
20
22
  import type { HangulCompatibilityJamoWidth } from "./utils";
21
23
 
22
24
  export * from "./terminal-multiplexer";
23
25
  export { wrapTmuxPassthrough } from "./tmux";
24
26
 
27
+ /** Last valid OSC 11 background, packed as 0xRRGGBB. */
28
+ let terminalBackgroundColor: number | undefined;
29
+
30
+ /**
31
+ * Trusted terminal background when reported; otherwise black for detected dark
32
+ * appearance or white for detected light appearance, using theme auto-detection.
33
+ */
34
+ export function getTerminalBackgroundColor(): number {
35
+ if (isTerminalBackgroundQueryTrusted() && terminalBackgroundColor !== undefined) return terminalBackgroundColor;
36
+ return detectTerminalBackground() === "light" ? 0xffffff : 0x000000;
37
+ }
38
+
39
+ /** Store an OSC 11 background, or reset to appearance detection (also for tests). */
40
+ export function setTerminalBackgroundColor(color: number | undefined): void {
41
+ terminalBackgroundColor = color;
42
+ }
43
+
25
44
  export enum ImageProtocol {
26
45
  Kitty = "\x1b_G",
27
46
  Iterm2 = "\x1b]1337;File=",
@@ -486,9 +505,10 @@ function getFallbackImageProtocol(
486
505
  if (!isTTY) return null;
487
506
  if (terminalId === "vscode" || terminalId === "alacritty") return null;
488
507
  const term = env.TERM?.toLowerCase() ?? "";
489
- if (term.includes("screen") || term.includes("tmux") || term.includes("ghostty")) {
490
- return ImageProtocol.Kitty;
491
- }
508
+ // tmux TERM names the pane, not the attached client's graphics support.
509
+ // Leave unknown clients unselected so the runtime SIXEL probe can run.
510
+ if (env.TMUX || term.includes("tmux")) return null;
511
+ if (term.includes("screen") || term.includes("ghostty")) return ImageProtocol.Kitty;
492
512
  return null;
493
513
  }
494
514
  /**
@@ -557,6 +577,12 @@ export function resolveImageProtocol(
557
577
  ) {
558
578
  return null;
559
579
  }
580
+ // Kitty graphics reach a tmux client only through the DCS passthrough
581
+ // envelope, which tmux drops unless `allow-passthrough` is enabled. A Kitty
582
+ // client identity alone would otherwise send images into the void.
583
+ if (imageProtocol === ImageProtocol.Kitty && env.TMUX && !tmuxPaneAllowsPassthrough(env)) {
584
+ return null;
585
+ }
560
586
  return imageProtocol;
561
587
  }
562
588
 
@@ -678,9 +704,11 @@ export function detectTerminalId(env: NodeJS.ProcessEnv = Bun.env): TerminalId {
678
704
  if (programId) return programId;
679
705
 
680
706
  // tmux >= 3.2 replaces the pane's identity with `TERM_PROGRAM=tmux`.
681
- // Its server still holds the attached client's terminal-type reply.
682
- const clientProgramId = fromProgram(resolveTmuxClientTerminalName(env) ?? undefined);
683
- if (clientProgramId) return clientProgramId;
707
+ // Its server still holds the attached client's terminal-type reply and TERM.
708
+ for (const clientProgram of resolveTmuxClientTerminalNames(env)) {
709
+ const clientProgramId = fromProgram(clientProgram);
710
+ if (clientProgramId) return clientProgramId;
711
+ }
684
712
 
685
713
  if (TERM?.toLowerCase().includes("ghostty")) return "ghostty";
686
714
  if (TERM && caseEq(TERM, "monstar")) return "monstar";
@@ -971,6 +999,21 @@ export function parseKittyDirectPlacementLine(line: string): ParsedKittyPlacemen
971
999
  };
972
1000
  }
973
1001
 
1002
+ /** `ESC 7` + `CUU(n)` lead-in of an {@link Image} direct-placement line. */
1003
+ const DIRECT_PLACEMENT_LIFT = /^\x1b7\x1b\[(\d+)A/;
1004
+
1005
+ /**
1006
+ * Rows above its own line that an {@link Image} direct-placement line paints
1007
+ * over: the `CUU(rows-1)` of its lead-in, or 0 for any other line. The renderer
1008
+ * erases those rows before a SIXEL/iTerm2 block is written again, because
1009
+ * those protocols have no delete command and the block's reserved rows are
1010
+ * byte-identical between frames, so the diff never rewrites them.
1011
+ */
1012
+ export function directPlacementLift(line: string): number {
1013
+ const m = DIRECT_PLACEMENT_LIFT.exec(line);
1014
+ return m ? Number(m[1]) : 0;
1015
+ }
1016
+
974
1017
  /**
975
1018
  * Rebuild an {@link Image} direct-placement line for the viewport row it is
976
1019
  * written at. The component-rendered line encodes `CUU(rows-1)`, which clamps
@@ -1248,9 +1291,14 @@ export function getImageDimensions(base64Data: string, mimeType: string): ImageD
1248
1291
  * thread; `null` when the encode fails. For output that cannot wait for an
1249
1292
  * off-thread encode.
1250
1293
  */
1251
- export function encodeSixelNow(base64Data: string, widthPx: number, heightPx: number): string | null {
1294
+ export function encodeSixelNow(
1295
+ base64Data: string,
1296
+ widthPx: number,
1297
+ heightPx: number,
1298
+ backgroundRgb = getTerminalBackgroundColor(),
1299
+ ): string | null {
1252
1300
  try {
1253
- return encodeSixel(new Uint8Array(Buffer.from(base64Data, "base64")), widthPx, heightPx);
1301
+ return encodeSixel(new Uint8Array(Buffer.from(base64Data, "base64")), widthPx, heightPx, backgroundRgb);
1254
1302
  } catch {
1255
1303
  return null;
1256
1304
  }
@@ -1309,25 +1357,15 @@ export function renderImage(
1309
1357
  }
1310
1358
 
1311
1359
  if (TERMINAL.imageProtocol === ImageProtocol.Sixel) {
1312
- // SIXEL encodes in 6-pixel vertical bands. A height that is not a
1313
- // multiple of 6 is padded with transparent rows, but the terminal
1314
- // still allocates cell rows for the padded height. When the padded
1315
- // height crosses a cell boundary the terminal uses one more row
1316
- // than fit.rows, so the next line of content overwrites the bottom
1317
- // of the image — a visible slice stripped from the image. Round the
1318
- // encode height DOWN to the largest multiple of 6 that fits within
1319
- // the requested row budget, so the band boundary aligns without
1320
- // padding and the reserved row count never exceeds fit.rows. Scale
1321
- // the width by the same ratio so resize_exact preserves the aspect
1322
- // ratio instead of squashing the image vertically.
1323
- const rawHeightPx = Math.max(1, fit.rows * cellDims.heightPx);
1324
- const targetHeightPx = Math.max(6, Math.floor(rawHeightPx / 6) * 6);
1325
- const heightScale = targetHeightPx / rawHeightPx;
1326
- const targetWidthPx = Math.max(1, Math.round(fit.columns * cellDims.widthPx * heightScale));
1327
- const rows = Math.max(1, Math.ceil(targetHeightPx / cellDims.heightPx));
1328
- const sequence = options.sixel
1329
- ? options.sixel(targetWidthPx, targetHeightPx)
1330
- : encodeSixelNow(base64Data, targetWidthPx, targetHeightPx);
1360
+ // Encode the cell box itself, so a raster drawn at the cell size
1361
+ // (SvgFigure) is placed 1:1 instead of resampled. The encoder drops a
1362
+ // partial last 6px band rather than letting the terminal pad it into
1363
+ // the next row; only a box under one band (sub-6px cells) still takes
1364
+ // the rows of a whole one.
1365
+ const heightPx = fit.rows * cellDims.heightPx;
1366
+ const widthPx = fit.columns * cellDims.widthPx;
1367
+ const rows = heightPx < 6 ? Math.ceil(6 / cellDims.heightPx) : fit.rows;
1368
+ const sequence = options.sixel ? options.sixel(widthPx, heightPx) : encodeSixelNow(base64Data, widthPx, heightPx);
1331
1369
  if (sequence === null) return null;
1332
1370
  // Undefined while the provider's encode is pending: the rows stay reserved.
1333
1371
  return { sequence, rows };
@@ -38,6 +38,7 @@ declare const registry: readonly [{
38
38
  readonly passthrough: typeof import("./tmux").wrapTmuxPassthrough;
39
39
  readonly settleMs: 100;
40
40
  };
41
+ readonly gatesBracketedPaste: true;
41
42
  readonly expandsRepPadding: true;
42
43
  readonly expiresSynchronizedOutput: true;
43
44
  readonly altRestoreEndsSynchronizedOutput: true;
@@ -100,6 +101,12 @@ export declare function hasTerminalMultiplexerSession(multiplexer: TerminalMulti
100
101
  * order. Nested sessions all appear; TERM is not consulted.
101
102
  */
102
103
  export declare function terminalMultiplexerSessions(env?: NodeJS.ProcessEnv): TerminalMultiplexerModule<TerminalMultiplexer>[];
104
+ /**
105
+ * Whether OSC 11 background replies are trusted on this platform. Any active
106
+ * session with `backgroundQueryBrokenOn` matching the platform makes the entire
107
+ * path untrusted; TERM-only classification does not identify an active session.
108
+ */
109
+ export declare function isTerminalBackgroundQueryTrusted(env?: NodeJS.ProcessEnv, platform?: NodeJS.Platform): boolean;
103
110
  /**
104
111
  * The multiplexer TERM names, whether or not its session markers survived.
105
112
  * This is classification's TERM fallback; session markers are not consulted.
@@ -67,6 +67,20 @@ export function terminalMultiplexerSessions(
67
67
  return TERMINAL_MULTIPLEXERS.filter(multiplexer => multiplexer.isInside(env));
68
68
  }
69
69
 
70
+ /**
71
+ * Whether OSC 11 background replies are trusted on this platform. Any active
72
+ * session with `backgroundQueryBrokenOn` matching the platform makes the entire
73
+ * path untrusted; TERM-only classification does not identify an active session.
74
+ */
75
+ export function isTerminalBackgroundQueryTrusted(
76
+ env: NodeJS.ProcessEnv = Bun.env,
77
+ platform: NodeJS.Platform = process.platform,
78
+ ): boolean {
79
+ return !TERMINAL_MULTIPLEXERS.some(
80
+ multiplexer => multiplexer.isInside(env) && multiplexer.backgroundQueryBrokenOn?.includes(platform),
81
+ );
82
+ }
83
+
70
84
  /**
71
85
  * The multiplexer TERM names, whether or not its session markers survived.
72
86
  * This is classification's TERM fallback; session markers are not consulted.
package/src/terminal.d.ts CHANGED
@@ -117,7 +117,7 @@ export type GlyphProtocolReportHandler = (supported: boolean) => void;
117
117
  /**
118
118
  * Outcome of the Tern Surface Protocol `hello` probe: the terminal's reply,
119
119
  * or null when it answered the DA1 sentinel first (no TSP) or the probe was
120
- * skipped (`PI_TUI_NATIVE=0`, multiplexers).
120
+ * skipped (`PI_TUI_NATIVE=0`, multiplexers, devenv's reloading shell).
121
121
  */
122
122
  export type TspHelloHandler = (hello: TspHello | null) => void;
123
123
  /**
@@ -181,6 +181,7 @@ export interface Terminal {
181
181
  get kittyEnableSequence(): string | null;
182
182
  readonly keyboardEnhancementEnterSequence?: string | null;
183
183
  readonly keyboardEnhancementExitSequence?: string | null;
184
+ readonly keyboardEnhancementRestoreSequence?: string | null;
184
185
  moveBy(lines: number): void;
185
186
  hideCursor(force?: boolean): void;
186
187
  showCursor(force?: boolean): void;
@@ -283,9 +284,11 @@ export interface ProcessTerminalOptions {
283
284
  conpty?: boolean;
284
285
  /**
285
286
  * Whether stdin is a native Windows console handle (win32, not WSL), whose
286
- * console host answers `CSI ? 9001 h` with win32-input-mode key records.
287
- * Defaults to `process.platform === "win32"`; only consulted when `conpty`
288
- * is also true.
287
+ * console host is certain to answer `CSI ? 9001 h` with win32-input-mode key
288
+ * records. When false (WSL), the keyboard fallback requests modifyOtherKeys
289
+ * alongside win32-input-mode, since a WSL pty may not be relayed by a console
290
+ * host. Defaults to `process.platform === "win32"`; only consulted when
291
+ * `conpty` is also true.
289
292
  */
290
293
  nativeWindowsConsole?: boolean;
291
294
  }
@@ -298,6 +301,7 @@ export declare class ProcessTerminal implements Terminal {
298
301
  get kittyProtocolActive(): boolean;
299
302
  get kittyEnableSequence(): string | null;
300
303
  get keyboardEnhancementEnterSequence(): string | null;
304
+ get keyboardEnhancementRestoreSequence(): string | null;
301
305
  get keyboardEnhancementExitSequence(): string | null;
302
306
  get appearance(): TerminalAppearance | undefined;
303
307
  onAppearanceChange(callback: (appearance: TerminalAppearance, requestToken?: TerminalAppearanceRequestToken) => void): void;