@zenbu-labs/pixel 0.0.0 → 0.0.12

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 (153) hide show
  1. package/dist/bin.d.ts +2 -0
  2. package/dist/bin.js +166 -0
  3. package/dist/bootstrap.d.ts +1 -0
  4. package/dist/bootstrap.js +75 -0
  5. package/dist/context-menu.d.ts +20 -0
  6. package/dist/context-menu.js +57 -0
  7. package/dist/debug.d.ts +1 -0
  8. package/dist/debug.js +9 -0
  9. package/dist/devtools-layout.d.ts +21 -0
  10. package/dist/devtools-layout.js +45 -0
  11. package/dist/devtools.d.ts +33 -0
  12. package/dist/devtools.js +125 -0
  13. package/dist/electron/index.d.ts +3 -0
  14. package/dist/electron/index.js +4 -0
  15. package/dist/host/guest.d.ts +5 -0
  16. package/dist/host/guest.js +178 -0
  17. package/dist/host/server.d.ts +91 -0
  18. package/dist/host/server.js +296 -0
  19. package/dist/host/shell.d.ts +35 -0
  20. package/dist/host/shell.js +113 -0
  21. package/dist/host/strip.d.ts +6 -0
  22. package/dist/host/strip.js +63 -0
  23. package/dist/icons.d.ts +30 -0
  24. package/dist/icons.js +58 -0
  25. package/dist/index.d.ts +17 -0
  26. package/dist/index.js +39 -0
  27. package/dist/instances.d.ts +30 -0
  28. package/dist/instances.js +177 -0
  29. package/dist/layout.d.ts +5 -0
  30. package/dist/layout.js +34 -0
  31. package/dist/popup.d.ts +21 -0
  32. package/dist/popup.js +47 -0
  33. package/dist/preload/index.d.ts +15 -0
  34. package/dist/preload/index.js +3 -0
  35. package/dist/react/colors.d.ts +3 -0
  36. package/dist/react/colors.js +25 -0
  37. package/dist/react/components.d.ts +21 -0
  38. package/dist/react/components.js +45 -0
  39. package/dist/react/devtools/app.d.ts +3 -0
  40. package/dist/react/devtools/app.js +89 -0
  41. package/dist/react/devtools/console-capture.d.ts +1 -0
  42. package/dist/react/devtools/console-capture.js +41 -0
  43. package/dist/react/devtools/controller.d.ts +45 -0
  44. package/dist/react/devtools/controller.js +252 -0
  45. package/dist/react/devtools/elements.d.ts +4 -0
  46. package/dist/react/devtools/elements.js +152 -0
  47. package/dist/react/devtools/export-profile.d.ts +2 -0
  48. package/dist/react/devtools/export-profile.js +225 -0
  49. package/dist/react/devtools/fiber-hook.d.ts +1 -0
  50. package/dist/react/devtools/fiber-hook.js +89 -0
  51. package/dist/react/devtools/log-panel.d.ts +4 -0
  52. package/dist/react/devtools/log-panel.js +113 -0
  53. package/dist/react/devtools/profiler.d.ts +11 -0
  54. package/dist/react/devtools/profiler.js +374 -0
  55. package/dist/react/devtools/store.d.ts +27 -0
  56. package/dist/react/devtools/store.js +61 -0
  57. package/dist/react/devtools/stores.d.ts +92 -0
  58. package/dist/react/devtools/stores.js +41 -0
  59. package/dist/react/devtools/theme.d.ts +35 -0
  60. package/dist/react/devtools/theme.js +77 -0
  61. package/dist/react/devtools/ui.d.ts +24 -0
  62. package/dist/react/devtools/ui.js +59 -0
  63. package/dist/react/index.d.ts +110 -0
  64. package/dist/react/index.js +538 -0
  65. package/dist/react/markdown.d.ts +25 -0
  66. package/dist/react/markdown.js +270 -0
  67. package/dist/react/native.d.ts +116 -0
  68. package/dist/react/native.js +56 -0
  69. package/dist/react/reconciler-config.d.ts +241 -0
  70. package/dist/react/reconciler-config.js +412 -0
  71. package/dist/react/styles.d.ts +88 -0
  72. package/dist/react/styles.js +85 -0
  73. package/dist/react/surface.d.ts +55 -0
  74. package/dist/react/surface.js +74 -0
  75. package/dist/registry.d.ts +53 -0
  76. package/dist/registry.js +193 -0
  77. package/dist/root.d.ts +19 -0
  78. package/dist/root.js +342 -0
  79. package/dist/sandbox.d.ts +4 -0
  80. package/dist/sandbox.js +84 -0
  81. package/dist/scale.d.ts +7 -0
  82. package/dist/scale.js +31 -0
  83. package/dist/ssh/index.d.ts +58 -0
  84. package/dist/ssh/index.js +445 -0
  85. package/dist/terminal/applescript.d.ts +2 -0
  86. package/dist/terminal/applescript.js +20 -0
  87. package/dist/terminal/detect.d.ts +10 -0
  88. package/dist/terminal/detect.js +34 -0
  89. package/dist/terminal/graphics.d.ts +9 -0
  90. package/dist/terminal/graphics.js +142 -0
  91. package/dist/terminal/index.d.ts +12 -0
  92. package/dist/terminal/index.js +23 -0
  93. package/dist/terminal/run.d.ts +2 -0
  94. package/dist/terminal/run.js +15 -0
  95. package/dist/terminal/shared.d.ts +20 -0
  96. package/dist/terminal/shared.js +88 -0
  97. package/dist/terminal/terminal.d.ts +66 -0
  98. package/dist/terminal/terminal.js +6 -0
  99. package/dist/terminal/terminals/cmux.d.ts +2 -0
  100. package/dist/terminal/terminals/cmux.js +98 -0
  101. package/dist/terminal/terminals/ghostty-script.d.ts +1 -0
  102. package/dist/terminal/terminals/ghostty-script.js +179 -0
  103. package/dist/terminal/terminals/ghostty.d.ts +2 -0
  104. package/dist/terminal/terminals/ghostty.js +336 -0
  105. package/dist/terminal/terminals/herdr.d.ts +2 -0
  106. package/dist/terminal/terminals/herdr.js +141 -0
  107. package/dist/terminal/terminals/index.d.ts +5 -0
  108. package/dist/terminal/terminals/index.js +26 -0
  109. package/dist/terminal/terminals/kitty.d.ts +2 -0
  110. package/dist/terminal/terminals/kitty.js +209 -0
  111. package/dist/terminal/terminals/supacode.d.ts +2 -0
  112. package/dist/terminal/terminals/supacode.js +79 -0
  113. package/dist/terminal/terminals/tmux.d.ts +2 -0
  114. package/dist/terminal/terminals/tmux.js +132 -0
  115. package/dist/terminal/terminals/tty7.d.ts +2 -0
  116. package/dist/terminal/terminals/tty7.js +58 -0
  117. package/dist/terminal/terminals/vscode.d.ts +2 -0
  118. package/dist/terminal/terminals/vscode.js +13 -0
  119. package/dist/terminal/terminals/wezterm.d.ts +2 -0
  120. package/dist/terminal/terminals/wezterm.js +59 -0
  121. package/dist/theme.d.ts +22 -0
  122. package/dist/theme.js +40 -0
  123. package/dist/web/browser-session.d.ts +13 -0
  124. package/dist/web/browser-session.js +186 -0
  125. package/dist/web/cursor.d.ts +1 -0
  126. package/dist/web/cursor.js +24 -0
  127. package/dist/web/devtools.d.ts +39 -0
  128. package/dist/web/devtools.js +300 -0
  129. package/dist/web/favicon.d.ts +7 -0
  130. package/dist/web/favicon.js +73 -0
  131. package/dist/web/frame-rate.d.ts +1 -0
  132. package/dist/web/frame-rate.js +12 -0
  133. package/dist/web/host.d.ts +123 -0
  134. package/dist/web/host.js +573 -0
  135. package/dist/web/input.d.ts +49 -0
  136. package/dist/web/input.js +468 -0
  137. package/dist/web/offscreen.d.ts +2 -0
  138. package/dist/web/offscreen.js +23 -0
  139. package/dist/web/paint.d.ts +11 -0
  140. package/dist/web/paint.js +128 -0
  141. package/dist/web/popup.d.ts +40 -0
  142. package/dist/web/popup.js +144 -0
  143. package/dist/web/session.d.ts +20 -0
  144. package/dist/web/session.js +110 -0
  145. package/dist/web/types.d.ts +38 -0
  146. package/dist/web/types.js +39 -0
  147. package/dist/web/zoom.d.ts +5 -0
  148. package/dist/web/zoom.js +36 -0
  149. package/dist/webview.d.ts +55 -0
  150. package/dist/webview.js +481 -0
  151. package/package.json +69 -3
  152. package/scripts/apparmor.sh +71 -0
  153. package/scripts/postinstall.mjs +150 -0
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.detect = detect;
4
+ exports.checkTerminal = checkTerminal;
5
+ exports.cannotOpenPanes = cannotOpenPanes;
6
+ const graphics_1 = require("./graphics");
7
+ const run_1 = require("./run");
8
+ const terminals_1 = require("./terminals");
9
+ function detect(env = process.env, run) {
10
+ const runIn = run ?? (0, run_1.shellIn)(env);
11
+ for (const recognise of terminals_1.TERMINALS) {
12
+ const terminal = recognise(env, runIn);
13
+ if (terminal)
14
+ return terminal;
15
+ }
16
+ return null;
17
+ }
18
+ async function checkTerminal(terminal, env = process.env) {
19
+ await terminal?.prepare?.();
20
+ if (env[graphics_1.SKIP_ENV])
21
+ return { terminal, graphics: "supported" };
22
+ const probed = await (0, graphics_1.probeGraphics)(terminal);
23
+ const graphics = probed === "unknown" ? (terminal ? "supported" : "unsupported") : probed;
24
+ return { terminal, graphics };
25
+ }
26
+ function cannotOpenPanes(terminal) {
27
+ const who = terminal
28
+ ? `${terminal.name} cannot open panes from a command`
29
+ : "unrecogonized terminal";
30
+ const recommendation = process.platform === "darwin"
31
+ ? "We recommend Ghostty (https://ghostty.org/download)."
32
+ : "We recommend Kitty (https://sw.kovidgoyal.net/kitty/binary)";
33
+ return `${who}. ${recommendation}`;
34
+ }
@@ -0,0 +1,9 @@
1
+ import type { Terminal } from "./terminal";
2
+ export type GraphicsSupport = "supported" | "unsupported" | "unknown";
3
+ export declare const SKIP_ENV = "PIXEL_SKIP_GRAPHICS_CHECK";
4
+ export declare function probeGraphics(terminal: Terminal | null): Promise<GraphicsSupport>;
5
+ export declare function panePixels(): Promise<{
6
+ width: number;
7
+ height: number;
8
+ } | null>;
9
+ export declare function unsupportedGraphicsMessage(color?: boolean): string;
@@ -0,0 +1,142 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.SKIP_ENV = void 0;
7
+ exports.probeGraphics = probeGraphics;
8
+ exports.panePixels = panePixels;
9
+ exports.unsupportedGraphicsMessage = unsupportedGraphicsMessage;
10
+ const node_fs_1 = __importDefault(require("node:fs"));
11
+ exports.SKIP_ENV = "PIXEL_SKIP_GRAPHICS_CHECK";
12
+ const PROBE_ID = 4207;
13
+ const PROBE_TIMEOUT_MS = 500;
14
+ function passthrough(seq) {
15
+ return `\x1bPtmux;${seq.replaceAll("\x1b", "\x1b\x1b")}\x1b\\`;
16
+ }
17
+ function probeSequence(wrap) {
18
+ const query = `\x1b_Gi=${PROBE_ID},a=q,t=d,f=24,s=1,v=1;AAAA\x1b\\`;
19
+ return `${wrap ? passthrough(query) : query}\x1b[c`;
20
+ }
21
+ function graphicsReply(buffer) {
22
+ const needle = `Gi=${PROBE_ID};`;
23
+ const at = buffer.indexOf(needle);
24
+ if (at < 0)
25
+ return null;
26
+ const rest = buffer.slice(at + needle.length);
27
+ if (rest.length < 2)
28
+ return null;
29
+ return rest.startsWith("OK");
30
+ }
31
+ function probeGraphics(terminal) {
32
+ const stdin = process.stdin;
33
+ if (!stdin.isTTY || !process.stdout.isTTY || !stdin.setRawMode) {
34
+ return Promise.resolve("unknown");
35
+ }
36
+ const wasRaw = stdin.isRaw;
37
+ return new Promise((resolve) => {
38
+ let buffer = "";
39
+ let timer = null;
40
+ let done = false;
41
+ const finish = (graphics) => {
42
+ if (done)
43
+ return;
44
+ done = true;
45
+ if (timer)
46
+ clearTimeout(timer);
47
+ stdin.off("data", onData);
48
+ try {
49
+ if (!wasRaw)
50
+ stdin.setRawMode?.(false);
51
+ }
52
+ catch { }
53
+ if (!stdin.isPaused())
54
+ stdin.pause();
55
+ resolve(graphics);
56
+ };
57
+ const onData = (chunk) => {
58
+ buffer += chunk.toString("binary");
59
+ const reply = graphicsReply(buffer);
60
+ if (reply !== null)
61
+ return finish(reply ? "supported" : "unsupported");
62
+ if (buffer.length > 1024)
63
+ finish("unknown");
64
+ };
65
+ try {
66
+ stdin.setRawMode(true);
67
+ }
68
+ catch {
69
+ return finish("unknown");
70
+ }
71
+ stdin.resume();
72
+ stdin.on("data", onData);
73
+ timer = setTimeout(() => finish("unknown"), PROBE_TIMEOUT_MS);
74
+ try {
75
+ node_fs_1.default.writeSync(1, probeSequence(terminal?.wrapper === "tmux"));
76
+ }
77
+ catch {
78
+ finish("unknown");
79
+ }
80
+ });
81
+ }
82
+ function panePixels() {
83
+ const stdin = process.stdin;
84
+ if (!stdin.isTTY || !process.stdout.isTTY || !stdin.setRawMode)
85
+ return Promise.resolve(null);
86
+ const wasRaw = stdin.isRaw;
87
+ return new Promise((resolve) => {
88
+ let buffer = "";
89
+ let timer = null;
90
+ let done = false;
91
+ const finish = (value) => {
92
+ if (done)
93
+ return;
94
+ done = true;
95
+ if (timer)
96
+ clearTimeout(timer);
97
+ stdin.off("data", onData);
98
+ try {
99
+ if (!wasRaw)
100
+ stdin.setRawMode?.(false);
101
+ }
102
+ catch { }
103
+ if (!stdin.isPaused())
104
+ stdin.pause();
105
+ resolve(value);
106
+ };
107
+ const onData = (chunk) => {
108
+ buffer += chunk.toString("binary");
109
+ const reply = /\x1b\[4;(\d+);(\d+)t/.exec(buffer);
110
+ if (reply)
111
+ finish({ width: Number(reply[2]), height: Number(reply[1]) });
112
+ };
113
+ try {
114
+ stdin.setRawMode(true);
115
+ }
116
+ catch {
117
+ return finish(null);
118
+ }
119
+ stdin.resume();
120
+ stdin.on("data", onData);
121
+ timer = setTimeout(() => finish(null), PROBE_TIMEOUT_MS);
122
+ try {
123
+ node_fs_1.default.writeSync(1, "\x1b[14t");
124
+ }
125
+ catch {
126
+ finish(null);
127
+ }
128
+ });
129
+ }
130
+ function unsupportedGraphicsMessage(color = false) {
131
+ const sgr = (code, text) => (color ? `\x1b[${code}m${text}\x1b[0m` : text);
132
+ return [
133
+ "",
134
+ ` ${sgr("1", "Unsupported terminal: this terminal cannot display graphics")}`,
135
+ "",
136
+ ` ${sgr("2", "We recommend Ghostty:")}`,
137
+ ` ${sgr("4", "https://ghostty.org/download")}`,
138
+ "",
139
+ ` ${sgr("2", "Note: any terminal that supports the kitty graphics protocol is supported")}`,
140
+ "",
141
+ ].join("\n");
142
+ }
@@ -0,0 +1,12 @@
1
+ /// <reference path="../../electron/electron.d.ts" preserve="true" />
2
+ export type { Detect, Direction, ListPanesOptions, Pane, PaneContext, PaneDetails, SplitRequest, Terminal } from "./terminal";
3
+ export { canSplit } from "./terminal";
4
+ export type { Run } from "./run";
5
+ export { shellIn } from "./run";
6
+ export { bracketedPaste, callerTty, shellLiteral } from "./shared";
7
+ export type { TerminalCheck } from "./detect";
8
+ export { cannotOpenPanes, checkTerminal, detect } from "./detect";
9
+ export type { GraphicsSupport } from "./graphics";
10
+ export type { Instance } from "../instances";
11
+ export { findOwner, listInstances, PROTOCOL as EMBED_PROTOCOL } from "../instances";
12
+ export { probeGraphics, unsupportedGraphicsMessage, SKIP_ENV as GRAPHICS_SKIP_ENV } from "./graphics";
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GRAPHICS_SKIP_ENV = exports.unsupportedGraphicsMessage = exports.probeGraphics = exports.EMBED_PROTOCOL = exports.listInstances = exports.findOwner = exports.detect = exports.checkTerminal = exports.cannotOpenPanes = exports.shellLiteral = exports.callerTty = exports.bracketedPaste = exports.shellIn = exports.canSplit = void 0;
4
+ var terminal_1 = require("./terminal");
5
+ Object.defineProperty(exports, "canSplit", { enumerable: true, get: function () { return terminal_1.canSplit; } });
6
+ var run_1 = require("./run");
7
+ Object.defineProperty(exports, "shellIn", { enumerable: true, get: function () { return run_1.shellIn; } });
8
+ var shared_1 = require("./shared");
9
+ Object.defineProperty(exports, "bracketedPaste", { enumerable: true, get: function () { return shared_1.bracketedPaste; } });
10
+ Object.defineProperty(exports, "callerTty", { enumerable: true, get: function () { return shared_1.callerTty; } });
11
+ Object.defineProperty(exports, "shellLiteral", { enumerable: true, get: function () { return shared_1.shellLiteral; } });
12
+ var detect_1 = require("./detect");
13
+ Object.defineProperty(exports, "cannotOpenPanes", { enumerable: true, get: function () { return detect_1.cannotOpenPanes; } });
14
+ Object.defineProperty(exports, "checkTerminal", { enumerable: true, get: function () { return detect_1.checkTerminal; } });
15
+ Object.defineProperty(exports, "detect", { enumerable: true, get: function () { return detect_1.detect; } });
16
+ var instances_1 = require("../instances");
17
+ Object.defineProperty(exports, "findOwner", { enumerable: true, get: function () { return instances_1.findOwner; } });
18
+ Object.defineProperty(exports, "listInstances", { enumerable: true, get: function () { return instances_1.listInstances; } });
19
+ Object.defineProperty(exports, "EMBED_PROTOCOL", { enumerable: true, get: function () { return instances_1.PROTOCOL; } });
20
+ var graphics_1 = require("./graphics");
21
+ Object.defineProperty(exports, "probeGraphics", { enumerable: true, get: function () { return graphics_1.probeGraphics; } });
22
+ Object.defineProperty(exports, "unsupportedGraphicsMessage", { enumerable: true, get: function () { return graphics_1.unsupportedGraphicsMessage; } });
23
+ Object.defineProperty(exports, "GRAPHICS_SKIP_ENV", { enumerable: true, get: function () { return graphics_1.SKIP_ENV; } });
@@ -0,0 +1,2 @@
1
+ export type Run = (bin: string, args: string[], input?: string) => Promise<string>;
2
+ export declare function shellIn(env: NodeJS.ProcessEnv): Run;
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.shellIn = shellIn;
4
+ const node_child_process_1 = require("node:child_process");
5
+ const node_util_1 = require("node:util");
6
+ const exec = (0, node_util_1.promisify)(node_child_process_1.execFile);
7
+ function shellIn(env) {
8
+ return async (bin, args, input) => {
9
+ const running = exec(bin, args, { env, maxBuffer: 4 * 1024 * 1024, timeout: 8000 });
10
+ if (input !== undefined)
11
+ running.child.stdin?.end(input);
12
+ const { stdout } = await running;
13
+ return stdout;
14
+ };
15
+ }
@@ -0,0 +1,20 @@
1
+ import type { Pane } from "./terminal";
2
+ export interface CallerTty {
3
+ path: string | null;
4
+ denied: boolean;
5
+ }
6
+ export interface PaneRect {
7
+ id: string;
8
+ left: number;
9
+ top: number;
10
+ right: number;
11
+ bottom: number;
12
+ }
13
+ export declare function adjacentPane(from: PaneRect, candidates: PaneRect[], direction: "right" | "left" | "down" | "up", gap?: number): PaneRect | null;
14
+ export declare function callerTty(): CallerTty;
15
+ export declare function setPaneWorkingDirectory(tty: string, directory: string): void;
16
+ export declare function paneById(panes: () => Promise<Pane[]>, id: string | null | undefined): Promise<Pane | null>;
17
+ export declare function shellQuote(argv: string[]): string;
18
+ export declare const sleep: (ms: number) => Promise<unknown>;
19
+ export declare function shellLiteral(text: string): string;
20
+ export declare function bracketedPaste(text: string): string;
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.sleep = void 0;
7
+ exports.adjacentPane = adjacentPane;
8
+ exports.callerTty = callerTty;
9
+ exports.setPaneWorkingDirectory = setPaneWorkingDirectory;
10
+ exports.paneById = paneById;
11
+ exports.shellQuote = shellQuote;
12
+ exports.shellLiteral = shellLiteral;
13
+ exports.bracketedPaste = bracketedPaste;
14
+ const node_child_process_1 = require("node:child_process");
15
+ const node_fs_1 = __importDefault(require("node:fs"));
16
+ const node_os_1 = __importDefault(require("node:os"));
17
+ function adjacentPane(from, candidates, direction, gap = 2) {
18
+ const touches = (candidate) => {
19
+ switch (direction) {
20
+ case "right":
21
+ return candidate.left > from.right && candidate.left <= from.right + gap;
22
+ case "left":
23
+ return candidate.right < from.left && candidate.right >= from.left - gap;
24
+ case "down":
25
+ return candidate.top > from.bottom && candidate.top <= from.bottom + gap;
26
+ case "up":
27
+ return candidate.bottom < from.top && candidate.bottom >= from.top - gap;
28
+ }
29
+ };
30
+ const overlap = (candidate) => direction === "right" || direction === "left"
31
+ ? Math.min(candidate.bottom, from.bottom) - Math.max(candidate.top, from.top)
32
+ : Math.min(candidate.right, from.right) - Math.max(candidate.left, from.left);
33
+ let best = null;
34
+ for (const candidate of candidates) {
35
+ if (candidate.id === from.id || !touches(candidate) || overlap(candidate) < 0)
36
+ continue;
37
+ if (!best || overlap(candidate) > overlap(best))
38
+ best = candidate;
39
+ }
40
+ return best;
41
+ }
42
+ function callerTty() {
43
+ let pid = process.pid;
44
+ for (let hops = 0; hops < 30 && pid > 1; hops++) {
45
+ let out;
46
+ try {
47
+ out = (0, node_child_process_1.execFileSync)("ps", ["-o", "ppid=,tty=", "-p", String(pid)], {
48
+ encoding: "utf8",
49
+ }).trim();
50
+ }
51
+ catch {
52
+ return { path: null, denied: hops === 0 };
53
+ }
54
+ if (!out)
55
+ return { path: null, denied: hops === 0 };
56
+ const [ppid, tty] = out.split(/\s+/);
57
+ if (tty && tty !== "??" && tty !== "?")
58
+ return { path: `/dev/${tty}`, denied: false };
59
+ pid = Number(ppid);
60
+ if (!Number.isFinite(pid))
61
+ return { path: null, denied: false };
62
+ }
63
+ return { path: null, denied: false };
64
+ }
65
+ function setPaneWorkingDirectory(tty, directory) {
66
+ const encoded = directory.split("/").map(encodeURIComponent).join("/");
67
+ node_fs_1.default.writeFileSync(tty, `\x1b]7;file://${node_os_1.default.hostname()}${encoded}\x07`);
68
+ }
69
+ async function paneById(panes, id) {
70
+ if (!id)
71
+ return null;
72
+ return (await panes()).find((pane) => pane.id === id) ?? null;
73
+ }
74
+ function shellQuote(argv) {
75
+ return argv
76
+ .map((arg) => arg !== "" && /^[\w\-./:=+@%,]+$/.test(arg) ? arg : `'${arg.replaceAll("'", `'\\''`)}'`)
77
+ .join(" ");
78
+ }
79
+ const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
80
+ exports.sleep = sleep;
81
+ function shellLiteral(text) {
82
+ return `'${text.replace(/['\\]/g, (char) => (char === "'" ? "'\\''" : "'\\\\'"))}'`;
83
+ }
84
+ function bracketedPaste(text) {
85
+ if (!text.includes("\n"))
86
+ return text;
87
+ return `\x1b[200~${text.replaceAll("\x1b[201~", "")}\x1b[201~`;
88
+ }
@@ -0,0 +1,66 @@
1
+ import type { Run } from "./run";
2
+ export type Direction = "right" | "left" | "down" | "up";
3
+ export interface Pane {
4
+ id: string;
5
+ tab: string;
6
+ }
7
+ export interface PaneDetails extends Pane {
8
+ tty: string | null;
9
+ command: string | null;
10
+ }
11
+ export interface PaneContext {
12
+ tty: string | null;
13
+ cwd: string;
14
+ }
15
+ export interface ListPanesOptions {
16
+ commands?: (command: string) => boolean;
17
+ tty?: string | null;
18
+ }
19
+ export interface SplitRequest {
20
+ from: Pane;
21
+ direction: Direction;
22
+ command: string[];
23
+ size: number | null;
24
+ tty: string | null;
25
+ }
26
+ export interface Terminal {
27
+ readonly name: string;
28
+ /**
29
+ * When terminal-browser tries to write to the TTY to render graphics using the
30
+ * kitty graphics protocol, tmux will by default not forward those escape
31
+ * codes to the outer TTY. But, tmux supports a passthrough mode if the content
32
+ * is wrapped in tmux specific escape codes. We implement this "wrapping" functionality
33
+ * internally, and allow a backend to configure what kind of wrapping should be applied (if any)
34
+ */
35
+ readonly wrapper?: "tmux";
36
+ /**
37
+ * When terminal-browser is rendered, it is scaled by the DPI of the display
38
+ * Terminals that report css based pixels when queried already perform that normalization, so we need an explicit flag to avoid rescaling
39
+ */
40
+ readonly reportsCssPixels?: boolean;
41
+ /**
42
+ * Allows code to be ran at startup, useful for preparing the terminal environment for terminal-browser
43
+ */
44
+ prepare?(): void | Promise<void>;
45
+ /**
46
+ * Allows terminal-browser to know which pane its being called from inside the terminal.
47
+ * This gives terminal-browser the ability to know if a terminal-browser instance
48
+ * is open inside the terminal-pane, and powers features such as:
49
+ * - terminal-browser ls lists the browers inside the current terminal tab
50
+ * - terminal-browser new-tab [url] will open in the browser inside the current terminal tab by default
51
+ */
52
+ getCurrentPane?(context: PaneContext): Promise<Pane | null>;
53
+ /**
54
+ * This powers terminal-browser's --split argument. This is useful when using terminal-browser w/ coding agents
55
+ * since it allows agents to open a browser next to their TUI without having to know how to
56
+ * script the current terminal they are running in
57
+ *
58
+ */
59
+ split?(request: SplitRequest): Promise<void>;
60
+ listPanes?(options?: ListPanesOptions): Promise<PaneDetails[]>;
61
+ neighbor?(from: Pane, direction: Direction): Promise<Pane | null>;
62
+ sendText?(pane: string, text: string): Promise<void>;
63
+ focusPane?(pane: string): Promise<void>;
64
+ }
65
+ export type Detect = (env: NodeJS.ProcessEnv, run: Run) => Terminal | null;
66
+ export declare function canSplit(terminal: Terminal | null): boolean;
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.canSplit = canSplit;
4
+ function canSplit(terminal) {
5
+ return Boolean(terminal?.split);
6
+ }
@@ -0,0 +1,2 @@
1
+ import type { Detect } from "../terminal";
2
+ export declare const cmux: Detect;
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.cmux = void 0;
4
+ const shared_1 = require("../shared");
5
+ const cmux = (env, run) => {
6
+ if (!env.CMUX_SURFACE_ID)
7
+ return null;
8
+ const binary = env.CMUX_BUNDLED_CLI_PATH ?? "cmux";
9
+ const cmux = (args) => run(binary, args);
10
+ const asked = async (args) => JSON.parse(await cmux([...args, "--json", "--id-format", "both"]));
11
+ async function panes() {
12
+ const listed = (await asked(["list-panes"])).panes ?? [];
13
+ const found = [];
14
+ for (const pane of listed) {
15
+ const paneId = pane.id ?? pane.ref;
16
+ if (!paneId)
17
+ continue;
18
+ const surfaces = (await asked(["list-pane-surfaces", "--pane", paneId]))
19
+ .surfaces ?? [];
20
+ for (const surface of surfaces) {
21
+ if (!surface.id)
22
+ continue;
23
+ found.push({ id: surface.id, tab: env.CMUX_WORKSPACE_ID ?? "" });
24
+ }
25
+ }
26
+ return found;
27
+ }
28
+ async function listPanes() {
29
+ const tree = (await asked(["tree", "--all"]));
30
+ const found = [];
31
+ for (const window of tree.windows ?? []) {
32
+ for (const workspace of window.workspaces ?? []) {
33
+ for (const pane of workspace.panes ?? []) {
34
+ for (const surface of pane.surfaces ?? []) {
35
+ if (surface.type !== undefined && surface.type !== "terminal")
36
+ continue;
37
+ found.push({
38
+ id: surface.id,
39
+ tab: workspace.id,
40
+ tty: surface.tty || null,
41
+ command: null,
42
+ });
43
+ }
44
+ }
45
+ }
46
+ }
47
+ return found;
48
+ }
49
+ async function neighbor(from, direction) {
50
+ const workspace = from.tab || env.CMUX_WORKSPACE_ID;
51
+ const rows = (await asked(["rpc", "pane.list", JSON.stringify(workspace ? { workspace_id: workspace } : {})])).panes ?? [];
52
+ const rects = [];
53
+ const surfacesOf = new Map();
54
+ for (const row of rows) {
55
+ const id = row.id ?? row.ref;
56
+ const frame = row.pixel_frame ?? row.frame;
57
+ if (!id || !frame || frame.x == null || frame.y == null || frame.width == null || frame.height == null)
58
+ continue;
59
+ rects.push({
60
+ id,
61
+ left: Math.round(frame.x),
62
+ top: Math.round(frame.y),
63
+ right: Math.round(frame.x + frame.width) - 1,
64
+ bottom: Math.round(frame.y + frame.height) - 1,
65
+ });
66
+ surfacesOf.set(id, (await asked(["list-pane-surfaces", "--pane", id])).surfaces ?? []);
67
+ }
68
+ const own = rects.find((rect) => (surfacesOf.get(rect.id) ?? []).some((surface) => surface.id === from.id));
69
+ if (!own)
70
+ return null;
71
+ const found = (0, shared_1.adjacentPane)(own, rects, direction, 16);
72
+ if (!found)
73
+ return null;
74
+ const surfaces = surfacesOf.get(found.id) ?? [];
75
+ const shown = surfaces.find((surface) => surface.focused || surface.selected) ?? surfaces[0];
76
+ return shown?.id ? { id: shown.id, tab: from.tab } : null;
77
+ }
78
+ return {
79
+ name: "cmux",
80
+ getCurrentPane: () => (0, shared_1.paneById)(panes, env.CMUX_SURFACE_ID),
81
+ listPanes,
82
+ neighbor,
83
+ async sendText(pane, text) {
84
+ await cmux(["rpc", "terminal.paste", JSON.stringify({ text, surface_id: pane, submit_key: "none" })]);
85
+ },
86
+ async focusPane(pane) {
87
+ await cmux(["focus-panel", "--panel", pane]);
88
+ },
89
+ async split({ from, direction, command }) {
90
+ const created = await asked(["new-split", direction, "--surface", from.id, "--focus", "true"]);
91
+ const opened = created.surface_id ?? created.surface_ref;
92
+ if (!opened)
93
+ throw new Error("cmux opened a split but did not say which surface it is");
94
+ await cmux(["send", "--surface", opened, "--", `${(0, shared_1.shellQuote)(command)}\\n`]);
95
+ },
96
+ };
97
+ };
98
+ exports.cmux = cmux;
@@ -0,0 +1 @@
1
+ export declare const GHOSTTY_SCRIPT: string;