@code-yeongyu/senpi-tui 2026.7.26 → 2026.7.28
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/components/editor.d.ts +16 -6
- package/dist/components/editor.d.ts.map +1 -1
- package/dist/components/editor.js +56 -120
- package/dist/components/editor.js.map +1 -1
- package/dist/components/image.d.ts.map +1 -1
- package/dist/components/image.js +7 -1
- package/dist/components/image.js.map +1 -1
- package/dist/editor-component.d.ts +18 -0
- package/dist/editor-component.d.ts.map +1 -1
- package/dist/editor-component.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/paste-markers.d.ts +29 -0
- package/dist/paste-markers.d.ts.map +1 -0
- package/dist/paste-markers.js +185 -0
- package/dist/paste-markers.js.map +1 -0
- package/dist/terminal-capabilities.d.ts +18 -0
- package/dist/terminal-capabilities.d.ts.map +1 -0
- package/dist/terminal-capabilities.js +62 -0
- package/dist/terminal-capabilities.js.map +1 -0
- package/dist/terminal-image.d.ts +31 -6
- package/dist/terminal-image.d.ts.map +1 -1
- package/dist/terminal-image.js +137 -92
- package/dist/terminal-image.js.map +1 -1
- package/dist/tmux-focus.d.ts +8 -0
- package/dist/tmux-focus.d.ts.map +1 -0
- package/dist/tmux-focus.js +14 -0
- package/dist/tmux-focus.js.map +1 -0
- package/dist/tmux-image-capability.d.ts +17 -0
- package/dist/tmux-image-capability.d.ts.map +1 -0
- package/dist/tmux-image-capability.js +61 -0
- package/dist/tmux-image-capability.js.map +1 -0
- package/dist/tmux-image-probe.d.ts +39 -0
- package/dist/tmux-image-probe.d.ts.map +1 -0
- package/dist/tmux-image-probe.js +121 -0
- package/dist/tmux-image-probe.js.map +1 -0
- package/dist/tui.d.ts +3 -0
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +63 -33
- package/dist/tui.js.map +1 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +19 -0
- package/dist/utils.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
export function parseTmuxKittyTerminalOverride(raw) {
|
|
2
|
+
return raw === "kitty" || raw === "ghostty" || raw === "warp" ? raw : undefined;
|
|
3
|
+
}
|
|
4
|
+
function identityForTerminal(terminal) {
|
|
5
|
+
return {
|
|
6
|
+
terminal,
|
|
7
|
+
placement: terminal === "warp" ? "direct" : "placeholder",
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
function identifyTmuxKittyClient(clientTermname, override) {
|
|
11
|
+
if (override)
|
|
12
|
+
return identityForTerminal(override);
|
|
13
|
+
const term = clientTermname.trim().toLowerCase();
|
|
14
|
+
if (term.includes("kitty"))
|
|
15
|
+
return identityForTerminal("kitty");
|
|
16
|
+
if (term.includes("ghostty"))
|
|
17
|
+
return identityForTerminal("ghostty");
|
|
18
|
+
if (term.includes("warp"))
|
|
19
|
+
return identityForTerminal("warp");
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
function topologyReason(state) {
|
|
23
|
+
if (state.supportTier === "unsupported")
|
|
24
|
+
return "unsupported-version";
|
|
25
|
+
if (state.nested)
|
|
26
|
+
return "nested";
|
|
27
|
+
if (state.clientCount !== 1)
|
|
28
|
+
return "multiple-clients";
|
|
29
|
+
if (!state.focusEvents)
|
|
30
|
+
return "focus-events-off";
|
|
31
|
+
if (state.allowPassthrough === "off")
|
|
32
|
+
return "passthrough-off";
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
export function canTrackTmuxImageFocus(state, override) {
|
|
36
|
+
if (state.kind !== "tmux" || topologyReason(state))
|
|
37
|
+
return false;
|
|
38
|
+
const identity = identifyTmuxKittyClient(state.clientTermname, override);
|
|
39
|
+
if (!identity)
|
|
40
|
+
return false;
|
|
41
|
+
return identity.placement !== "direct" || state.allowPassthrough === "on";
|
|
42
|
+
}
|
|
43
|
+
export function decideTmuxImageCapability(state, override) {
|
|
44
|
+
if (state.kind === "outside")
|
|
45
|
+
return { enabled: false, reason: "outside-tmux" };
|
|
46
|
+
if (state.kind === "unavailable")
|
|
47
|
+
return { enabled: false, reason: "probe-unavailable" };
|
|
48
|
+
const topology = topologyReason(state);
|
|
49
|
+
if (topology)
|
|
50
|
+
return { enabled: false, reason: topology };
|
|
51
|
+
if (!state.visible)
|
|
52
|
+
return { enabled: false, reason: "hidden" };
|
|
53
|
+
const identity = identifyTmuxKittyClient(state.clientTermname, override);
|
|
54
|
+
if (!identity)
|
|
55
|
+
return { enabled: false, reason: "unknown-client" };
|
|
56
|
+
if (identity.placement === "direct" && state.allowPassthrough !== "on") {
|
|
57
|
+
return { enabled: false, reason: "unsafe-direct-placement" };
|
|
58
|
+
}
|
|
59
|
+
return { enabled: true, placement: identity.placement, terminal: identity.terminal };
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=tmux-image-capability.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tmux-image-capability.js","sourceRoot":"","sources":["../src/tmux-image-capability.ts"],"names":[],"mappings":"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","sourcesContent":["import type { TmuxDetectedState, TmuxImageState } from \"./tmux-image-probe.ts\";\n\nexport type TmuxKittyTerminal = \"kitty\" | \"ghostty\" | \"warp\";\nexport type TmuxKittyPlacement = \"placeholder\" | \"direct\";\nexport type TmuxKittyTerminalOverride = TmuxKittyTerminal | undefined;\n\nexport type TmuxImageDisabledReason =\n\t| \"outside-tmux\"\n\t| \"probe-unavailable\"\n\t| \"unsupported-version\"\n\t| \"passthrough-off\"\n\t| \"focus-events-off\"\n\t| \"multiple-clients\"\n\t| \"nested\"\n\t| \"hidden\"\n\t| \"unknown-client\"\n\t| \"unsafe-direct-placement\";\n\nexport type TmuxImageDecision =\n\t| {\n\t\t\treadonly enabled: true;\n\t\t\treadonly placement: TmuxKittyPlacement;\n\t\t\treadonly terminal: TmuxKittyTerminal;\n\t }\n\t| { readonly enabled: false; readonly reason: TmuxImageDisabledReason };\n\ninterface TmuxKittyIdentity {\n\treadonly placement: TmuxKittyPlacement;\n\treadonly terminal: TmuxKittyTerminal;\n}\n\nexport function parseTmuxKittyTerminalOverride(raw: string | undefined): TmuxKittyTerminalOverride {\n\treturn raw === \"kitty\" || raw === \"ghostty\" || raw === \"warp\" ? raw : undefined;\n}\n\nfunction identityForTerminal(terminal: TmuxKittyTerminal): TmuxKittyIdentity {\n\treturn {\n\t\tterminal,\n\t\tplacement: terminal === \"warp\" ? \"direct\" : \"placeholder\",\n\t};\n}\n\nfunction identifyTmuxKittyClient(\n\tclientTermname: string,\n\toverride: TmuxKittyTerminalOverride,\n): TmuxKittyIdentity | null {\n\tif (override) return identityForTerminal(override);\n\tconst term = clientTermname.trim().toLowerCase();\n\tif (term.includes(\"kitty\")) return identityForTerminal(\"kitty\");\n\tif (term.includes(\"ghostty\")) return identityForTerminal(\"ghostty\");\n\tif (term.includes(\"warp\")) return identityForTerminal(\"warp\");\n\treturn null;\n}\n\nfunction topologyReason(state: TmuxDetectedState): TmuxImageDisabledReason | null {\n\tif (state.supportTier === \"unsupported\") return \"unsupported-version\";\n\tif (state.nested) return \"nested\";\n\tif (state.clientCount !== 1) return \"multiple-clients\";\n\tif (!state.focusEvents) return \"focus-events-off\";\n\tif (state.allowPassthrough === \"off\") return \"passthrough-off\";\n\treturn null;\n}\n\nexport function canTrackTmuxImageFocus(state: TmuxImageState, override: TmuxKittyTerminalOverride): boolean {\n\tif (state.kind !== \"tmux\" || topologyReason(state)) return false;\n\tconst identity = identifyTmuxKittyClient(state.clientTermname, override);\n\tif (!identity) return false;\n\treturn identity.placement !== \"direct\" || state.allowPassthrough === \"on\";\n}\n\nexport function decideTmuxImageCapability(\n\tstate: TmuxImageState,\n\toverride: TmuxKittyTerminalOverride,\n): TmuxImageDecision {\n\tif (state.kind === \"outside\") return { enabled: false, reason: \"outside-tmux\" };\n\tif (state.kind === \"unavailable\") return { enabled: false, reason: \"probe-unavailable\" };\n\n\tconst topology = topologyReason(state);\n\tif (topology) return { enabled: false, reason: topology };\n\tif (!state.visible) return { enabled: false, reason: \"hidden\" };\n\n\tconst identity = identifyTmuxKittyClient(state.clientTermname, override);\n\tif (!identity) return { enabled: false, reason: \"unknown-client\" };\n\tif (identity.placement === \"direct\" && state.allowPassthrough !== \"on\") {\n\t\treturn { enabled: false, reason: \"unsafe-direct-placement\" };\n\t}\n\treturn { enabled: true, placement: identity.placement, terminal: identity.terminal };\n}\n"]}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
interface CellDimensions {
|
|
2
|
+
widthPx: number;
|
|
3
|
+
heightPx: number;
|
|
4
|
+
}
|
|
5
|
+
export type TmuxSupportTier = "unsupported" | "on-only" | "on-and-all";
|
|
6
|
+
export type TmuxAllowPassthrough = "off" | "on" | "all";
|
|
7
|
+
export type TmuxExecFile = (file: string, args: readonly string[]) => string;
|
|
8
|
+
interface TmuxBaseState {
|
|
9
|
+
readonly supportTier: TmuxSupportTier;
|
|
10
|
+
readonly allowPassthrough: TmuxAllowPassthrough;
|
|
11
|
+
readonly focusEvents: boolean;
|
|
12
|
+
readonly paneActive: boolean;
|
|
13
|
+
readonly windowActive: boolean;
|
|
14
|
+
readonly visible: boolean;
|
|
15
|
+
readonly clientCount: number;
|
|
16
|
+
readonly clientTermname: string;
|
|
17
|
+
readonly nested: boolean;
|
|
18
|
+
readonly hyperlinks: boolean;
|
|
19
|
+
readonly cellDimensions?: CellDimensions;
|
|
20
|
+
}
|
|
21
|
+
export interface TmuxOutsideState extends TmuxBaseState {
|
|
22
|
+
readonly kind: "outside";
|
|
23
|
+
}
|
|
24
|
+
export interface TmuxUnavailableState extends TmuxBaseState {
|
|
25
|
+
readonly kind: "unavailable";
|
|
26
|
+
readonly reason: "probe-failed" | "malformed-output";
|
|
27
|
+
}
|
|
28
|
+
export interface TmuxDetectedState extends TmuxBaseState {
|
|
29
|
+
readonly kind: "tmux";
|
|
30
|
+
readonly version: string;
|
|
31
|
+
}
|
|
32
|
+
export type TmuxImageState = TmuxOutsideState | TmuxUnavailableState | TmuxDetectedState;
|
|
33
|
+
export declare const TMUX_IMAGE_FORMAT = "#{version}|#{allow-passthrough}|#{focus-events}|#{pane_active}|#{window_active}|#{session_attached}|#{client_termname}|#{client_cell_width}|#{client_cell_height}|#{client_termfeatures}";
|
|
34
|
+
export declare function tmuxSupportTier(version: string): TmuxSupportTier;
|
|
35
|
+
export declare function normalizeTmuxAllowPassthrough(raw: string, supportTier: TmuxSupportTier): TmuxAllowPassthrough;
|
|
36
|
+
export declare function parseTmuxImageState(output: string): TmuxImageState;
|
|
37
|
+
export declare function probeTmuxImageState(env?: Readonly<Record<string, string | undefined>>, execFile?: TmuxExecFile): TmuxImageState;
|
|
38
|
+
export {};
|
|
39
|
+
//# sourceMappingURL=tmux-image-probe.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tmux-image-probe.d.ts","sourceRoot":"","sources":["../src/tmux-image-probe.ts"],"names":[],"mappings":"AAEA,UAAU,cAAc;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,eAAe,GAAG,aAAa,GAAG,SAAS,GAAG,YAAY,CAAC;AACvE,MAAM,MAAM,oBAAoB,GAAG,KAAK,GAAG,IAAI,GAAG,KAAK,CAAC;AAExD,MAAM,MAAM,YAAY,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,MAAM,EAAE,KAAK,MAAM,CAAC;AAE7E,UAAU,aAAa;IACtB,QAAQ,CAAC,WAAW,EAAE,eAAe,CAAC;IACtC,QAAQ,CAAC,gBAAgB,EAAE,oBAAoB,CAAC;IAChD,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;IAC9B,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,cAAc,CAAC,EAAE,cAAc,CAAC;CACzC;AAED,MAAM,WAAW,gBAAiB,SAAQ,aAAa;IACtD,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;CACzB;AAED,MAAM,WAAW,oBAAqB,SAAQ,aAAa;IAC1D,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,cAAc,GAAG,kBAAkB,CAAC;CACrD;AAED,MAAM,WAAW,iBAAkB,SAAQ,aAAa;IACvD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,MAAM,cAAc,GAAG,gBAAgB,GAAG,oBAAoB,GAAG,iBAAiB,CAAC;AAEzF,eAAO,MAAM,iBAAiB,6LAC6J,CAAC;AA+B5L,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,eAAe,CAOhE;AAED,wBAAgB,6BAA6B,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,eAAe,GAAG,oBAAoB,CAM7G;AAuBD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,CA6ClE;AAED,wBAAgB,mBAAmB,CAClC,GAAG,GAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAe,EAC/D,QAAQ,GAAE,YAA8B,GACtC,cAAc,CAkBhB"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { execFileSync } from "node:child_process";
|
|
2
|
+
export const TMUX_IMAGE_FORMAT = "#{version}|#{allow-passthrough}|#{focus-events}|#{pane_active}|#{window_active}|#{session_attached}|#{client_termname}|#{client_cell_width}|#{client_cell_height}|#{client_termfeatures}";
|
|
3
|
+
const DISABLED_STATE = {
|
|
4
|
+
supportTier: "unsupported",
|
|
5
|
+
allowPassthrough: "off",
|
|
6
|
+
focusEvents: false,
|
|
7
|
+
paneActive: false,
|
|
8
|
+
windowActive: false,
|
|
9
|
+
visible: false,
|
|
10
|
+
clientCount: 0,
|
|
11
|
+
clientTermname: "",
|
|
12
|
+
nested: false,
|
|
13
|
+
hyperlinks: false,
|
|
14
|
+
};
|
|
15
|
+
function defaultExecFile(file, args) {
|
|
16
|
+
return execFileSync(file, [...args], {
|
|
17
|
+
encoding: "utf8",
|
|
18
|
+
timeout: 250,
|
|
19
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
function parseTmuxVersion(version) {
|
|
23
|
+
const match = /^(?:next-)?(\d+)\.(\d+)/.exec(version.trim());
|
|
24
|
+
if (!match)
|
|
25
|
+
return null;
|
|
26
|
+
const major = Number.parseInt(match[1] ?? "", 10);
|
|
27
|
+
const minor = Number.parseInt(match[2] ?? "", 10);
|
|
28
|
+
return Number.isFinite(major) && Number.isFinite(minor) ? [major, minor] : null;
|
|
29
|
+
}
|
|
30
|
+
export function tmuxSupportTier(version) {
|
|
31
|
+
const parsed = parseTmuxVersion(version);
|
|
32
|
+
if (!parsed)
|
|
33
|
+
return "unsupported";
|
|
34
|
+
const [major, minor] = parsed;
|
|
35
|
+
if (major > 3 || (major === 3 && minor >= 4))
|
|
36
|
+
return "on-and-all";
|
|
37
|
+
if (major === 3 && minor === 3)
|
|
38
|
+
return "on-only";
|
|
39
|
+
return "unsupported";
|
|
40
|
+
}
|
|
41
|
+
export function normalizeTmuxAllowPassthrough(raw, supportTier) {
|
|
42
|
+
if (supportTier === "unsupported")
|
|
43
|
+
return "off";
|
|
44
|
+
const value = raw.trim().toLowerCase();
|
|
45
|
+
if (value === "1" || value === "on")
|
|
46
|
+
return "on";
|
|
47
|
+
if (value === "all" && supportTier === "on-and-all")
|
|
48
|
+
return "all";
|
|
49
|
+
return "off";
|
|
50
|
+
}
|
|
51
|
+
function parseBoolean(raw) {
|
|
52
|
+
const value = raw.trim().toLowerCase();
|
|
53
|
+
return value === "1" || value === "on";
|
|
54
|
+
}
|
|
55
|
+
function parsePositiveInteger(raw) {
|
|
56
|
+
if (!/^\d+$/.test(raw))
|
|
57
|
+
return undefined;
|
|
58
|
+
const value = Number.parseInt(raw, 10);
|
|
59
|
+
return value > 0 ? value : undefined;
|
|
60
|
+
}
|
|
61
|
+
function parseClientCount(raw) {
|
|
62
|
+
if (!/^\d+$/.test(raw))
|
|
63
|
+
return 0;
|
|
64
|
+
return Number.parseInt(raw, 10);
|
|
65
|
+
}
|
|
66
|
+
function isNestedClient(clientTermname) {
|
|
67
|
+
const term = clientTermname.trim().toLowerCase();
|
|
68
|
+
return term.startsWith("tmux") || term.startsWith("screen");
|
|
69
|
+
}
|
|
70
|
+
export function parseTmuxImageState(output) {
|
|
71
|
+
const fields = output.trim().split("|");
|
|
72
|
+
if (fields.length !== 10) {
|
|
73
|
+
return { kind: "unavailable", reason: "malformed-output", ...DISABLED_STATE };
|
|
74
|
+
}
|
|
75
|
+
const [version = "", rawAllow = "", rawFocusEvents = "", rawPaneActive = "", rawWindowActive = "", rawClientCount = "", rawClientTermname = "", rawCellWidth = "", rawCellHeight = "", rawTermfeatures = "",] = fields;
|
|
76
|
+
const supportTier = tmuxSupportTier(version);
|
|
77
|
+
const clientCount = parseClientCount(rawClientCount);
|
|
78
|
+
const paneActive = parseBoolean(rawPaneActive);
|
|
79
|
+
const windowActive = parseBoolean(rawWindowActive);
|
|
80
|
+
const clientTermname = rawClientTermname.trim();
|
|
81
|
+
const widthPx = parsePositiveInteger(rawCellWidth);
|
|
82
|
+
const heightPx = parsePositiveInteger(rawCellHeight);
|
|
83
|
+
const cellDimensions = widthPx && heightPx ? { widthPx, heightPx } : undefined;
|
|
84
|
+
return {
|
|
85
|
+
kind: "tmux",
|
|
86
|
+
version: version.trim(),
|
|
87
|
+
supportTier,
|
|
88
|
+
allowPassthrough: normalizeTmuxAllowPassthrough(rawAllow, supportTier),
|
|
89
|
+
focusEvents: parseBoolean(rawFocusEvents),
|
|
90
|
+
paneActive,
|
|
91
|
+
windowActive,
|
|
92
|
+
visible: paneActive && windowActive && clientCount === 1,
|
|
93
|
+
clientCount,
|
|
94
|
+
clientTermname,
|
|
95
|
+
nested: isNestedClient(clientTermname),
|
|
96
|
+
hyperlinks: rawTermfeatures
|
|
97
|
+
.split(",")
|
|
98
|
+
.map((feature) => feature.trim())
|
|
99
|
+
.includes("hyperlinks"),
|
|
100
|
+
...(cellDimensions ? { cellDimensions } : {}),
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
export function probeTmuxImageState(env = process.env, execFile = defaultExecFile) {
|
|
104
|
+
const term = env.TERM?.toLowerCase() ?? "";
|
|
105
|
+
if (!env.TMUX && !term.startsWith("tmux")) {
|
|
106
|
+
return { kind: "outside", ...DISABLED_STATE };
|
|
107
|
+
}
|
|
108
|
+
const pane = env.TMUX_PANE;
|
|
109
|
+
const args = ["display-message", "-p"];
|
|
110
|
+
if (pane && /^%\d+$/.test(pane)) {
|
|
111
|
+
args.push("-t", pane);
|
|
112
|
+
}
|
|
113
|
+
args.push(TMUX_IMAGE_FORMAT);
|
|
114
|
+
try {
|
|
115
|
+
return parseTmuxImageState(execFile("tmux", args));
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
return { kind: "unavailable", reason: "probe-failed", ...DISABLED_STATE };
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=tmux-image-probe.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tmux-image-probe.js","sourceRoot":"","sources":["../src/tmux-image-probe.ts"],"names":[],"mappings":"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","sourcesContent":["import { execFileSync } from \"node:child_process\";\n\ninterface CellDimensions {\n\twidthPx: number;\n\theightPx: number;\n}\n\nexport type TmuxSupportTier = \"unsupported\" | \"on-only\" | \"on-and-all\";\nexport type TmuxAllowPassthrough = \"off\" | \"on\" | \"all\";\n\nexport type TmuxExecFile = (file: string, args: readonly string[]) => string;\n\ninterface TmuxBaseState {\n\treadonly supportTier: TmuxSupportTier;\n\treadonly allowPassthrough: TmuxAllowPassthrough;\n\treadonly focusEvents: boolean;\n\treadonly paneActive: boolean;\n\treadonly windowActive: boolean;\n\treadonly visible: boolean;\n\treadonly clientCount: number;\n\treadonly clientTermname: string;\n\treadonly nested: boolean;\n\treadonly hyperlinks: boolean;\n\treadonly cellDimensions?: CellDimensions;\n}\n\nexport interface TmuxOutsideState extends TmuxBaseState {\n\treadonly kind: \"outside\";\n}\n\nexport interface TmuxUnavailableState extends TmuxBaseState {\n\treadonly kind: \"unavailable\";\n\treadonly reason: \"probe-failed\" | \"malformed-output\";\n}\n\nexport interface TmuxDetectedState extends TmuxBaseState {\n\treadonly kind: \"tmux\";\n\treadonly version: string;\n}\n\nexport type TmuxImageState = TmuxOutsideState | TmuxUnavailableState | TmuxDetectedState;\n\nexport const TMUX_IMAGE_FORMAT =\n\t\"#{version}|#{allow-passthrough}|#{focus-events}|#{pane_active}|#{window_active}|#{session_attached}|#{client_termname}|#{client_cell_width}|#{client_cell_height}|#{client_termfeatures}\";\n\nconst DISABLED_STATE = {\n\tsupportTier: \"unsupported\",\n\tallowPassthrough: \"off\",\n\tfocusEvents: false,\n\tpaneActive: false,\n\twindowActive: false,\n\tvisible: false,\n\tclientCount: 0,\n\tclientTermname: \"\",\n\tnested: false,\n\thyperlinks: false,\n} as const;\n\nfunction defaultExecFile(file: string, args: readonly string[]): string {\n\treturn execFileSync(file, [...args], {\n\t\tencoding: \"utf8\",\n\t\ttimeout: 250,\n\t\tstdio: [\"ignore\", \"pipe\", \"ignore\"],\n\t});\n}\n\nfunction parseTmuxVersion(version: string): readonly [major: number, minor: number] | null {\n\tconst match = /^(?:next-)?(\\d+)\\.(\\d+)/.exec(version.trim());\n\tif (!match) return null;\n\tconst major = Number.parseInt(match[1] ?? \"\", 10);\n\tconst minor = Number.parseInt(match[2] ?? \"\", 10);\n\treturn Number.isFinite(major) && Number.isFinite(minor) ? [major, minor] : null;\n}\n\nexport function tmuxSupportTier(version: string): TmuxSupportTier {\n\tconst parsed = parseTmuxVersion(version);\n\tif (!parsed) return \"unsupported\";\n\tconst [major, minor] = parsed;\n\tif (major > 3 || (major === 3 && minor >= 4)) return \"on-and-all\";\n\tif (major === 3 && minor === 3) return \"on-only\";\n\treturn \"unsupported\";\n}\n\nexport function normalizeTmuxAllowPassthrough(raw: string, supportTier: TmuxSupportTier): TmuxAllowPassthrough {\n\tif (supportTier === \"unsupported\") return \"off\";\n\tconst value = raw.trim().toLowerCase();\n\tif (value === \"1\" || value === \"on\") return \"on\";\n\tif (value === \"all\" && supportTier === \"on-and-all\") return \"all\";\n\treturn \"off\";\n}\n\nfunction parseBoolean(raw: string): boolean {\n\tconst value = raw.trim().toLowerCase();\n\treturn value === \"1\" || value === \"on\";\n}\n\nfunction parsePositiveInteger(raw: string): number | undefined {\n\tif (!/^\\d+$/.test(raw)) return undefined;\n\tconst value = Number.parseInt(raw, 10);\n\treturn value > 0 ? value : undefined;\n}\n\nfunction parseClientCount(raw: string): number {\n\tif (!/^\\d+$/.test(raw)) return 0;\n\treturn Number.parseInt(raw, 10);\n}\n\nfunction isNestedClient(clientTermname: string): boolean {\n\tconst term = clientTermname.trim().toLowerCase();\n\treturn term.startsWith(\"tmux\") || term.startsWith(\"screen\");\n}\n\nexport function parseTmuxImageState(output: string): TmuxImageState {\n\tconst fields = output.trim().split(\"|\");\n\tif (fields.length !== 10) {\n\t\treturn { kind: \"unavailable\", reason: \"malformed-output\", ...DISABLED_STATE };\n\t}\n\n\tconst [\n\t\tversion = \"\",\n\t\trawAllow = \"\",\n\t\trawFocusEvents = \"\",\n\t\trawPaneActive = \"\",\n\t\trawWindowActive = \"\",\n\t\trawClientCount = \"\",\n\t\trawClientTermname = \"\",\n\t\trawCellWidth = \"\",\n\t\trawCellHeight = \"\",\n\t\trawTermfeatures = \"\",\n\t] = fields;\n\tconst supportTier = tmuxSupportTier(version);\n\tconst clientCount = parseClientCount(rawClientCount);\n\tconst paneActive = parseBoolean(rawPaneActive);\n\tconst windowActive = parseBoolean(rawWindowActive);\n\tconst clientTermname = rawClientTermname.trim();\n\tconst widthPx = parsePositiveInteger(rawCellWidth);\n\tconst heightPx = parsePositiveInteger(rawCellHeight);\n\tconst cellDimensions = widthPx && heightPx ? { widthPx, heightPx } : undefined;\n\n\treturn {\n\t\tkind: \"tmux\",\n\t\tversion: version.trim(),\n\t\tsupportTier,\n\t\tallowPassthrough: normalizeTmuxAllowPassthrough(rawAllow, supportTier),\n\t\tfocusEvents: parseBoolean(rawFocusEvents),\n\t\tpaneActive,\n\t\twindowActive,\n\t\tvisible: paneActive && windowActive && clientCount === 1,\n\t\tclientCount,\n\t\tclientTermname,\n\t\tnested: isNestedClient(clientTermname),\n\t\thyperlinks: rawTermfeatures\n\t\t\t.split(\",\")\n\t\t\t.map((feature) => feature.trim())\n\t\t\t.includes(\"hyperlinks\"),\n\t\t...(cellDimensions ? { cellDimensions } : {}),\n\t};\n}\n\nexport function probeTmuxImageState(\n\tenv: Readonly<Record<string, string | undefined>> = process.env,\n\texecFile: TmuxExecFile = defaultExecFile,\n): TmuxImageState {\n\tconst term = env.TERM?.toLowerCase() ?? \"\";\n\tif (!env.TMUX && !term.startsWith(\"tmux\")) {\n\t\treturn { kind: \"outside\", ...DISABLED_STATE };\n\t}\n\n\tconst pane = env.TMUX_PANE;\n\tconst args = [\"display-message\", \"-p\"];\n\tif (pane && /^%\\d+$/.test(pane)) {\n\t\targs.push(\"-t\", pane);\n\t}\n\targs.push(TMUX_IMAGE_FORMAT);\n\n\ttry {\n\t\treturn parseTmuxImageState(execFile(\"tmux\", args));\n\t} catch {\n\t\treturn { kind: \"unavailable\", reason: \"probe-failed\", ...DISABLED_STATE };\n\t}\n}\n"]}
|
package/dist/tui.d.ts
CHANGED
|
@@ -67,6 +67,9 @@ export { visibleWidth };
|
|
|
67
67
|
export declare function __renderErrorLogStats(): {
|
|
68
68
|
writes: number;
|
|
69
69
|
} | undefined;
|
|
70
|
+
export declare function __renderDiagnosticStats(): {
|
|
71
|
+
linesScanned: number;
|
|
72
|
+
} | undefined;
|
|
70
73
|
export declare function __viewportRenderStats(): ViewportRenderStats | undefined;
|
|
71
74
|
/**
|
|
72
75
|
* Anchor position for overlays
|
package/dist/tui.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tui.d.ts","sourceRoot":"","sources":["../src/tui.ts"],"names":[],"mappings":"AAAA;;GAEG;AAQH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAIN,KAAK,QAAQ,EACb,KAAK,mBAAmB,EACxB,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"tui.d.ts","sourceRoot":"","sources":["../src/tui.ts"],"names":[],"mappings":"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"}
|
package/dist/tui.js
CHANGED
|
@@ -8,7 +8,8 @@ import { performance } from "node:perf_hooks";
|
|
|
8
8
|
import { isKeyRelease, matchesKey } from "./keys.js";
|
|
9
9
|
import { isMultiplexerSession, useLegacyMuxRender, viewportRenderEnabled } from "./mux.js";
|
|
10
10
|
import { isOsc11BackgroundColorResponse, parseOsc11BackgroundColor, parseTerminalColorSchemeReport, } from "./terminal-colors.js";
|
|
11
|
-
import { deleteKittyImage, getCapabilities, isImageLine, setCellDimensions } from "./terminal-image.js";
|
|
11
|
+
import { deleteKittyImage, getCapabilities, isImageLine, resetCapabilitiesCache, setCellDimensions, } from "./terminal-image.js";
|
|
12
|
+
import { consumeTmuxFocusEvent, DISABLE_FOCUS_REPORTING, ENABLE_FOCUS_REPORTING } from "./tmux-focus.js";
|
|
12
13
|
import { extractSegments, normalizeTerminalOutput, sliceByColumn, sliceWithWidth, visibleWidth } from "./utils.js";
|
|
13
14
|
const KITTY_SEQUENCE_PREFIX = "\x1b_G";
|
|
14
15
|
function parseKittyImageHeader(line) {
|
|
@@ -58,6 +59,7 @@ export const CURSOR_MARKER = "\x1b_pi:c\x07";
|
|
|
58
59
|
export { visibleWidth };
|
|
59
60
|
const renderErrorLoggedClasses = new Set();
|
|
60
61
|
let renderErrorLogWrites = 0;
|
|
62
|
+
let renderDiagnosticLineScans = 0;
|
|
61
63
|
const DIAGNOSTIC_LOG_MODE = 0o600;
|
|
62
64
|
const VIEWPORT_RENDER_OVERSCAN = 16;
|
|
63
65
|
// Keep scroll-region wins cheap when a few visible rows mutate during append streaming.
|
|
@@ -77,6 +79,12 @@ export function __renderErrorLogStats() {
|
|
|
77
79
|
}
|
|
78
80
|
return { writes: renderErrorLogWrites };
|
|
79
81
|
}
|
|
82
|
+
export function __renderDiagnosticStats() {
|
|
83
|
+
if (process.env.PI_TUI_TEST_SEAMS !== "1") {
|
|
84
|
+
return undefined;
|
|
85
|
+
}
|
|
86
|
+
return { linesScanned: renderDiagnosticLineScans };
|
|
87
|
+
}
|
|
80
88
|
export function __viewportRenderStats() {
|
|
81
89
|
if (process.env.PI_TUI_TEST_SEAMS !== "1") {
|
|
82
90
|
return undefined;
|
|
@@ -142,6 +150,18 @@ function writeRenderDiagnosticBestEffort(logPath, data) {
|
|
|
142
150
|
throw error;
|
|
143
151
|
}
|
|
144
152
|
}
|
|
153
|
+
function formatOverWideRenderDiagnostic(lines, terminalWidth, lineIndex, lineWidth) {
|
|
154
|
+
renderDiagnosticLineScans += lines.length;
|
|
155
|
+
return [
|
|
156
|
+
`Crash at ${new Date().toISOString()}`,
|
|
157
|
+
`Terminal width: ${terminalWidth}`,
|
|
158
|
+
`Line ${lineIndex} visible width: ${lineWidth}`,
|
|
159
|
+
"",
|
|
160
|
+
"=== All rendered lines ===",
|
|
161
|
+
...lines.map((line, index) => `[${index}] (w=${visibleWidth(line)}) ${line}`),
|
|
162
|
+
"",
|
|
163
|
+
].join("\n");
|
|
164
|
+
}
|
|
145
165
|
function chmodDiagnosticLogBestEffort(logPath) {
|
|
146
166
|
try {
|
|
147
167
|
fs.chmodSync(logPath, DIAGNOSTIC_LOG_MODE);
|
|
@@ -576,6 +596,8 @@ export class TUI extends Container {
|
|
|
576
596
|
this.inputRenderPending = false;
|
|
577
597
|
this.#lastCursorVisibility = undefined;
|
|
578
598
|
this.terminal.start((data) => this.handleInput(data), () => this.requestRender());
|
|
599
|
+
if (process.env.TMUX)
|
|
600
|
+
this.terminal.write(ENABLE_FOCUS_REPORTING);
|
|
579
601
|
this.#setCursorVisibility(false);
|
|
580
602
|
if (this.terminalColorSchemeNotificationsEnabled) {
|
|
581
603
|
this.terminal.write("\x1b[?2031h");
|
|
@@ -643,6 +665,8 @@ export class TUI extends Container {
|
|
|
643
665
|
}
|
|
644
666
|
this.#lastCursorVisibility = undefined;
|
|
645
667
|
this.#setCursorVisibility(true);
|
|
668
|
+
if (process.env.TMUX)
|
|
669
|
+
this.terminal.write(DISABLE_FOCUS_REPORTING);
|
|
646
670
|
this.terminal.stop();
|
|
647
671
|
this.#lastCursorVisibility = undefined;
|
|
648
672
|
this.previousLines = [];
|
|
@@ -749,6 +773,15 @@ export class TUI extends Container {
|
|
|
749
773
|
this.doRender();
|
|
750
774
|
}
|
|
751
775
|
handleInput(data) {
|
|
776
|
+
const focus = consumeTmuxFocusEvent(data);
|
|
777
|
+
if (focus.event !== null) {
|
|
778
|
+
resetCapabilitiesCache();
|
|
779
|
+
this.invalidate();
|
|
780
|
+
this.requestRender(true);
|
|
781
|
+
if (focus.data.length === 0)
|
|
782
|
+
return;
|
|
783
|
+
data = focus.data;
|
|
784
|
+
}
|
|
752
785
|
if (this.consumeOsc11BackgroundResponse(data)) {
|
|
753
786
|
return;
|
|
754
787
|
}
|
|
@@ -1350,8 +1383,11 @@ export class TUI extends Container {
|
|
|
1350
1383
|
}
|
|
1351
1384
|
/** Splice overlay content into a base line at a specific column. Single-pass optimized. */
|
|
1352
1385
|
compositeLineAt(baseLine, overlayLine, startCol, overlayWidth, totalWidth) {
|
|
1353
|
-
if (isImageLine(baseLine))
|
|
1386
|
+
if (isImageLine(baseLine) && visibleWidth(baseLine) === 0)
|
|
1354
1387
|
return baseLine;
|
|
1388
|
+
const placeholderIndex = baseLine.indexOf("\u{10eeee}");
|
|
1389
|
+
const protocolEnd = placeholderIndex === -1 ? -1 : baseLine.lastIndexOf("\x1b\\", placeholderIndex);
|
|
1390
|
+
const protocolPrefix = protocolEnd === -1 ? "" : baseLine.slice(0, protocolEnd + 2);
|
|
1355
1391
|
// Single pass through baseLine extracts both before and after segments
|
|
1356
1392
|
const afterStart = startCol + overlayWidth;
|
|
1357
1393
|
const base = extractSegments(baseLine, startCol, afterStart, totalWidth - afterStart, true);
|
|
@@ -1382,10 +1418,10 @@ export class TUI extends Container {
|
|
|
1382
1418
|
// - Edge cases in segment extraction
|
|
1383
1419
|
const resultWidth = visibleWidth(result);
|
|
1384
1420
|
if (resultWidth <= totalWidth) {
|
|
1385
|
-
return result;
|
|
1421
|
+
return protocolPrefix + result;
|
|
1386
1422
|
}
|
|
1387
1423
|
// Truncate with strict=true to ensure we don't exceed totalWidth
|
|
1388
|
-
return sliceByColumn(result, 0, totalWidth, true);
|
|
1424
|
+
return protocolPrefix + sliceByColumn(result, 0, totalWidth, true);
|
|
1389
1425
|
}
|
|
1390
1426
|
/**
|
|
1391
1427
|
* Find and extract cursor position from rendered lines.
|
|
@@ -1758,36 +1794,30 @@ export class TUI extends Container {
|
|
|
1758
1794
|
buffer += `\x1b[2K${TUI.SEGMENT_RESET}`; // Clear current line
|
|
1759
1795
|
const lineWidth = visibleWidth(line);
|
|
1760
1796
|
if (!isImage && lineWidth > width) {
|
|
1761
|
-
// Log all lines to crash file for debugging
|
|
1762
1797
|
const crashLogPath = path.join(os.homedir(), ".senpi", "agent", "senpi-crash.log");
|
|
1763
|
-
const
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
throw new Error(errorMsg);
|
|
1787
|
-
}
|
|
1788
|
-
if (!this.overWideCrashDumpWritten) {
|
|
1789
|
-
writeRenderDiagnosticBestEffort(crashLogPath, crashData);
|
|
1790
|
-
this.overWideCrashDumpWritten = true;
|
|
1798
|
+
const strictRender = process.env.PI_TUI_STRICT_RENDER === "1";
|
|
1799
|
+
if (strictRender || !this.overWideCrashDumpWritten) {
|
|
1800
|
+
const crashData = formatOverWideRenderDiagnostic(newLines, width, i, lineWidth);
|
|
1801
|
+
if (!strictRender) {
|
|
1802
|
+
writeRenderDiagnosticBestEffort(crashLogPath, crashData);
|
|
1803
|
+
this.overWideCrashDumpWritten = true;
|
|
1804
|
+
}
|
|
1805
|
+
else {
|
|
1806
|
+
const crashDumpWritten = writeRenderDiagnosticBestEffort(crashLogPath, crashData);
|
|
1807
|
+
// Clean up terminal state before throwing
|
|
1808
|
+
this.stop();
|
|
1809
|
+
const errorMsg = [
|
|
1810
|
+
`Rendered line ${i} exceeds terminal width (${lineWidth} > ${width}).`,
|
|
1811
|
+
"",
|
|
1812
|
+
"This is likely caused by a custom TUI component not truncating its output.",
|
|
1813
|
+
"Use visibleWidth() to measure and truncateToWidth() to truncate lines.",
|
|
1814
|
+
"",
|
|
1815
|
+
crashDumpWritten
|
|
1816
|
+
? `Debug log written to: ${crashLogPath}`
|
|
1817
|
+
: `Debug log could not be written to: ${crashLogPath}`,
|
|
1818
|
+
].join("\n");
|
|
1819
|
+
throw new Error(errorMsg);
|
|
1820
|
+
}
|
|
1791
1821
|
}
|
|
1792
1822
|
const truncatedLine = sliceByColumn(line, 0, width, true) + TUI.SEGMENT_RESET;
|
|
1793
1823
|
newLines[i] = truncatedLine;
|