@sayknow-cli/tui 0.3.13 → 0.3.15
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.
- package/dist/types/animation-scheduler.d.ts +13 -0
- package/dist/types/autocomplete.d.ts +83 -0
- package/dist/types/bracketed-paste.d.ts +26 -0
- package/dist/types/components/box.d.ts +20 -0
- package/dist/types/components/cancellable-loader.d.ts +21 -0
- package/dist/types/components/editor.d.ts +126 -0
- package/dist/types/components/image.d.ts +18 -0
- package/dist/types/components/input.d.ts +16 -0
- package/dist/types/components/loader.d.ts +23 -0
- package/dist/types/components/markdown.d.ts +87 -0
- package/dist/types/components/sayknow-pet.d.ts +128 -0
- package/dist/types/components/select-list.d.ts +46 -0
- package/dist/types/components/settings-list.d.ts +39 -0
- package/dist/types/components/spacer.d.ts +11 -0
- package/dist/types/components/tab-bar.d.ts +56 -0
- package/dist/types/components/text.d.ts +22 -0
- package/dist/types/components/truncated-text.d.ts +10 -0
- package/dist/types/editor-component.d.ts +36 -0
- package/dist/types/fuzzy.d.ts +15 -0
- package/dist/types/index.d.ts +28 -0
- package/dist/types/keybindings.d.ts +201 -0
- package/dist/types/keys.d.ts +208 -0
- package/dist/types/kill-ring.d.ts +27 -0
- package/dist/types/metrics.d.ts +85 -0
- package/dist/types/stdin-buffer.d.ts +50 -0
- package/dist/types/symbols.d.ts +23 -0
- package/dist/types/terminal-capabilities.d.ts +187 -0
- package/dist/types/terminal.d.ts +90 -0
- package/dist/types/ttyid.d.ts +9 -0
- package/dist/types/tui.d.ts +269 -0
- package/dist/types/utils.d.ts +110 -0
- package/package.json +9 -8
- package/src/terminal-capabilities.ts +77 -4
- package/src/tui.ts +50 -21
package/src/tui.ts
CHANGED
|
@@ -9,7 +9,14 @@ import { getKeybindings } from "./keybindings";
|
|
|
9
9
|
import { isKeyRelease } from "./keys";
|
|
10
10
|
import { renderMetrics } from "./metrics";
|
|
11
11
|
import type { Terminal } from "./terminal";
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
ImageProtocol,
|
|
14
|
+
isImageProtocolForced,
|
|
15
|
+
isUnderTerminalMultiplexer,
|
|
16
|
+
setCellDimensions,
|
|
17
|
+
setTerminalImageProtocol,
|
|
18
|
+
TERMINAL,
|
|
19
|
+
} from "./terminal-capabilities";
|
|
13
20
|
import {
|
|
14
21
|
Ellipsis,
|
|
15
22
|
extractSegments,
|
|
@@ -217,7 +224,6 @@ function isTermuxSession(env: Record<string, string | undefined> = Bun.env): boo
|
|
|
217
224
|
return Boolean(env.TERMUX_VERSION);
|
|
218
225
|
}
|
|
219
226
|
|
|
220
|
-
const SKC_TMUX_LAUNCHED_ENV = "SKC_TMUX_LAUNCHED";
|
|
221
227
|
const DISABLED_ENV_VALUES = new Set(["0", "false", "off", "no"]);
|
|
222
228
|
const TRUTHY_ENV_VALUES = new Set(["1", "true", "yes", "on", "y"]);
|
|
223
229
|
|
|
@@ -231,25 +237,38 @@ function envFlagEnabled(value: string | undefined): boolean {
|
|
|
231
237
|
return normalized !== undefined && TRUTHY_ENV_VALUES.has(normalized);
|
|
232
238
|
}
|
|
233
239
|
|
|
234
|
-
function termLooksMultiplexed(value: string | undefined): boolean {
|
|
235
|
-
const term = value?.trim().toLowerCase() ?? "";
|
|
236
|
-
return term.startsWith("tmux") || term.startsWith("screen");
|
|
237
|
-
}
|
|
238
|
-
|
|
239
240
|
function isWindowsTerminalSession(env: Record<string, string | undefined> = Bun.env): boolean {
|
|
240
241
|
return envIsEnabled(env.WT_SESSION) || env.TERM_PROGRAM === "Windows_Terminal";
|
|
241
242
|
}
|
|
242
243
|
|
|
243
|
-
/**
|
|
244
|
+
/**
|
|
245
|
+
* Detect terminal multiplexers where scrollback clearing and height-change
|
|
246
|
+
* redraws are hostile. Delegates to the shared capability predicate so the
|
|
247
|
+
* renderer and graphics-protocol selection agree on what counts as a
|
|
248
|
+
* multiplexed host.
|
|
249
|
+
*/
|
|
244
250
|
function isMultiplexerSession(env: Record<string, string | undefined> = Bun.env): boolean {
|
|
245
|
-
return
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
251
|
+
return isUnderTerminalMultiplexer(env as NodeJS.ProcessEnv);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Startup sixel capability probe policy (pure; exported for tests):
|
|
256
|
+
* - Never probe when PI_FORCE_IMAGE_PROTOCOL is set — an explicit
|
|
257
|
+
* configuration (including "off") is authoritative.
|
|
258
|
+
* - Never probe inside a terminal multiplexer: tmux advertises DA1 ";4"
|
|
259
|
+
* whenever it was compiled with sixel support, regardless of whether the
|
|
260
|
+
* attached client terminal can render sixel, so a positive reply is not
|
|
261
|
+
* end-to-end evidence. Graphics under a multiplexer are strictly opt-in
|
|
262
|
+
* via PI_FORCE_IMAGE_PROTOCOL=sixel.
|
|
263
|
+
* - Probe Windows Terminal (>=1.22 renders sixel but exposes no env marker).
|
|
264
|
+
*/
|
|
265
|
+
export function shouldProbeSixelCapability(
|
|
266
|
+
env: NodeJS.ProcessEnv = Bun.env,
|
|
267
|
+
platform: NodeJS.Platform = process.platform,
|
|
268
|
+
): boolean {
|
|
269
|
+
if (isImageProtocolForced()) return false;
|
|
270
|
+
if (isUnderTerminalMultiplexer(env)) return false;
|
|
271
|
+
return platform === "win32" && Boolean(env.WT_SESSION?.trim());
|
|
253
272
|
}
|
|
254
273
|
|
|
255
274
|
function useLegacyMultiplexerFullRender(env: Record<string, string | undefined> = Bun.env): boolean {
|
|
@@ -1008,8 +1027,7 @@ export class TUI extends Container {
|
|
|
1008
1027
|
|
|
1009
1028
|
#querySixelSupport(): void {
|
|
1010
1029
|
if (TERMINAL.imageProtocol) return;
|
|
1011
|
-
if (
|
|
1012
|
-
if (!Bun.env.WT_SESSION) return;
|
|
1030
|
+
if (!this.#isSixelProbeCandidate()) return;
|
|
1013
1031
|
if (!process.stdin.isTTY || !process.stdout.isTTY) return;
|
|
1014
1032
|
|
|
1015
1033
|
this.#clearSixelProbeState();
|
|
@@ -1023,6 +1041,10 @@ export class TUI extends Container {
|
|
|
1023
1041
|
}, 250);
|
|
1024
1042
|
}
|
|
1025
1043
|
|
|
1044
|
+
#isSixelProbeCandidate(): boolean {
|
|
1045
|
+
return shouldProbeSixelCapability();
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1026
1048
|
#handleSixelProbeInput(data: string): InputListenerResult {
|
|
1027
1049
|
if (!this.#sixelProbePendingDa && !this.#sixelProbePendingGraphics) {
|
|
1028
1050
|
return undefined;
|
|
@@ -1049,11 +1071,15 @@ export class TUI extends Container {
|
|
|
1049
1071
|
|
|
1050
1072
|
if (useDa && this.#sixelProbePendingDa) {
|
|
1051
1073
|
this.#sixelProbePendingDa = false;
|
|
1052
|
-
const
|
|
1074
|
+
const params = (match[1] ?? "")
|
|
1053
1075
|
.split(";")
|
|
1054
1076
|
.map(value => Number.parseInt(value, 10))
|
|
1055
1077
|
.filter(value => Number.isFinite(value));
|
|
1056
|
-
|
|
1078
|
+
// The first DA1 parameter is the device/operating class (e.g. 1,
|
|
1079
|
+
// 62, 64), not an extension attribute: `CSI ?4;6c` identifies a
|
|
1080
|
+
// VT132, it does not advertise sixel. Only the parameters after
|
|
1081
|
+
// the class carry attributes like 4 (sixel graphics).
|
|
1082
|
+
const hasSixelAttribute = params.slice(1).includes(4);
|
|
1057
1083
|
if (hasSixelAttribute) {
|
|
1058
1084
|
this.#sixelProbePendingGraphics = false;
|
|
1059
1085
|
probeOutcome = true;
|
|
@@ -1062,8 +1088,11 @@ export class TUI extends Container {
|
|
|
1062
1088
|
}
|
|
1063
1089
|
} else if (!useDa && this.#sixelProbePendingGraphics) {
|
|
1064
1090
|
this.#sixelProbePendingGraphics = false;
|
|
1091
|
+
// XTSMGRAPHICS reply is `CSI ? 2 ; Ps ; ... S` where Ps=0 means
|
|
1092
|
+
// success and 1/2/3 are errors (tmux answers our unsupported
|
|
1093
|
+
// read with `CSI ?2;3;0S`). Only a success reply proves sixel.
|
|
1065
1094
|
const status = Number.parseInt(match[1] ?? "", 10);
|
|
1066
|
-
const supportsSixel =
|
|
1095
|
+
const supportsSixel = status === 0;
|
|
1067
1096
|
if (supportsSixel) {
|
|
1068
1097
|
this.#sixelProbePendingDa = false;
|
|
1069
1098
|
probeOutcome = true;
|