@zenbu-labs/pixel 0.0.0 → 0.0.13
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/bin.d.ts +2 -0
- package/dist/bin.js +161 -0
- package/dist/bootstrap.d.ts +1 -0
- package/dist/bootstrap.js +75 -0
- package/dist/context-menu.d.ts +20 -0
- package/dist/context-menu.js +57 -0
- package/dist/debug.d.ts +1 -0
- package/dist/debug.js +9 -0
- package/dist/devtools-layout.d.ts +21 -0
- package/dist/devtools-layout.js +45 -0
- package/dist/devtools.d.ts +33 -0
- package/dist/devtools.js +125 -0
- package/dist/electron/index.d.ts +3 -0
- package/dist/electron/index.js +4 -0
- package/dist/host/guest.d.ts +5 -0
- package/dist/host/guest.js +178 -0
- package/dist/host/server.d.ts +91 -0
- package/dist/host/server.js +296 -0
- package/dist/host/shell.d.ts +35 -0
- package/dist/host/shell.js +113 -0
- package/dist/host/strip.d.ts +6 -0
- package/dist/host/strip.js +63 -0
- package/dist/icons.d.ts +30 -0
- package/dist/icons.js +58 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +39 -0
- package/dist/instances.d.ts +30 -0
- package/dist/instances.js +177 -0
- package/dist/layout.d.ts +5 -0
- package/dist/layout.js +34 -0
- package/dist/popup.d.ts +21 -0
- package/dist/popup.js +47 -0
- package/dist/preload/index.d.ts +15 -0
- package/dist/preload/index.js +3 -0
- package/dist/react/colors.d.ts +3 -0
- package/dist/react/colors.js +25 -0
- package/dist/react/components.d.ts +21 -0
- package/dist/react/components.js +45 -0
- package/dist/react/devtools/app.d.ts +3 -0
- package/dist/react/devtools/app.js +89 -0
- package/dist/react/devtools/console-capture.d.ts +1 -0
- package/dist/react/devtools/console-capture.js +41 -0
- package/dist/react/devtools/controller.d.ts +45 -0
- package/dist/react/devtools/controller.js +252 -0
- package/dist/react/devtools/elements.d.ts +4 -0
- package/dist/react/devtools/elements.js +152 -0
- package/dist/react/devtools/export-profile.d.ts +2 -0
- package/dist/react/devtools/export-profile.js +225 -0
- package/dist/react/devtools/fiber-hook.d.ts +1 -0
- package/dist/react/devtools/fiber-hook.js +89 -0
- package/dist/react/devtools/log-panel.d.ts +4 -0
- package/dist/react/devtools/log-panel.js +113 -0
- package/dist/react/devtools/profiler.d.ts +11 -0
- package/dist/react/devtools/profiler.js +374 -0
- package/dist/react/devtools/store.d.ts +27 -0
- package/dist/react/devtools/store.js +61 -0
- package/dist/react/devtools/stores.d.ts +92 -0
- package/dist/react/devtools/stores.js +41 -0
- package/dist/react/devtools/theme.d.ts +35 -0
- package/dist/react/devtools/theme.js +77 -0
- package/dist/react/devtools/ui.d.ts +24 -0
- package/dist/react/devtools/ui.js +59 -0
- package/dist/react/index.d.ts +110 -0
- package/dist/react/index.js +538 -0
- package/dist/react/markdown.d.ts +25 -0
- package/dist/react/markdown.js +270 -0
- package/dist/react/native.d.ts +116 -0
- package/dist/react/native.js +56 -0
- package/dist/react/reconciler-config.d.ts +241 -0
- package/dist/react/reconciler-config.js +412 -0
- package/dist/react/styles.d.ts +88 -0
- package/dist/react/styles.js +85 -0
- package/dist/react/surface.d.ts +55 -0
- package/dist/react/surface.js +74 -0
- package/dist/registry.d.ts +53 -0
- package/dist/registry.js +193 -0
- package/dist/root.d.ts +19 -0
- package/dist/root.js +342 -0
- package/dist/sandbox.d.ts +4 -0
- package/dist/sandbox.js +84 -0
- package/dist/scale.d.ts +7 -0
- package/dist/scale.js +31 -0
- package/dist/ssh/index.d.ts +58 -0
- package/dist/ssh/index.js +445 -0
- package/dist/terminal/applescript.d.ts +2 -0
- package/dist/terminal/applescript.js +20 -0
- package/dist/terminal/detect.d.ts +10 -0
- package/dist/terminal/detect.js +34 -0
- package/dist/terminal/graphics.d.ts +9 -0
- package/dist/terminal/graphics.js +142 -0
- package/dist/terminal/index.d.ts +12 -0
- package/dist/terminal/index.js +23 -0
- package/dist/terminal/run.d.ts +2 -0
- package/dist/terminal/run.js +15 -0
- package/dist/terminal/shared.d.ts +20 -0
- package/dist/terminal/shared.js +88 -0
- package/dist/terminal/terminal.d.ts +66 -0
- package/dist/terminal/terminal.js +6 -0
- package/dist/terminal/terminals/cmux.d.ts +2 -0
- package/dist/terminal/terminals/cmux.js +98 -0
- package/dist/terminal/terminals/ghostty-script.d.ts +1 -0
- package/dist/terminal/terminals/ghostty-script.js +179 -0
- package/dist/terminal/terminals/ghostty.d.ts +2 -0
- package/dist/terminal/terminals/ghostty.js +336 -0
- package/dist/terminal/terminals/herdr.d.ts +2 -0
- package/dist/terminal/terminals/herdr.js +141 -0
- package/dist/terminal/terminals/index.d.ts +5 -0
- package/dist/terminal/terminals/index.js +26 -0
- package/dist/terminal/terminals/kitty.d.ts +2 -0
- package/dist/terminal/terminals/kitty.js +209 -0
- package/dist/terminal/terminals/supacode.d.ts +2 -0
- package/dist/terminal/terminals/supacode.js +79 -0
- package/dist/terminal/terminals/tmux.d.ts +2 -0
- package/dist/terminal/terminals/tmux.js +132 -0
- package/dist/terminal/terminals/tty7.d.ts +2 -0
- package/dist/terminal/terminals/tty7.js +58 -0
- package/dist/terminal/terminals/vscode.d.ts +2 -0
- package/dist/terminal/terminals/vscode.js +13 -0
- package/dist/terminal/terminals/wezterm.d.ts +2 -0
- package/dist/terminal/terminals/wezterm.js +59 -0
- package/dist/theme.d.ts +22 -0
- package/dist/theme.js +40 -0
- package/dist/web/browser-session.d.ts +13 -0
- package/dist/web/browser-session.js +186 -0
- package/dist/web/cursor.d.ts +1 -0
- package/dist/web/cursor.js +24 -0
- package/dist/web/devtools.d.ts +39 -0
- package/dist/web/devtools.js +300 -0
- package/dist/web/favicon.d.ts +7 -0
- package/dist/web/favicon.js +73 -0
- package/dist/web/frame-rate.d.ts +1 -0
- package/dist/web/frame-rate.js +12 -0
- package/dist/web/host.d.ts +123 -0
- package/dist/web/host.js +573 -0
- package/dist/web/input.d.ts +49 -0
- package/dist/web/input.js +468 -0
- package/dist/web/offscreen.d.ts +2 -0
- package/dist/web/offscreen.js +23 -0
- package/dist/web/paint.d.ts +11 -0
- package/dist/web/paint.js +128 -0
- package/dist/web/popup.d.ts +40 -0
- package/dist/web/popup.js +144 -0
- package/dist/web/session.d.ts +20 -0
- package/dist/web/session.js +110 -0
- package/dist/web/types.d.ts +38 -0
- package/dist/web/types.js +39 -0
- package/dist/web/zoom.d.ts +5 -0
- package/dist/web/zoom.js +36 -0
- package/dist/webview.d.ts +55 -0
- package/dist/webview.js +481 -0
- package/package.json +69 -3
- package/scripts/apparmor.sh +71 -0
- package/scripts/postinstall.mjs +150 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TERMINALS = void 0;
|
|
4
|
+
const cmux_1 = require("./cmux");
|
|
5
|
+
const ghostty_1 = require("./ghostty");
|
|
6
|
+
const herdr_1 = require("./herdr");
|
|
7
|
+
const kitty_1 = require("./kitty");
|
|
8
|
+
const supacode_1 = require("./supacode");
|
|
9
|
+
const tmux_1 = require("./tmux");
|
|
10
|
+
const tty7_1 = require("./tty7");
|
|
11
|
+
const vscode_1 = require("./vscode");
|
|
12
|
+
const wezterm_1 = require("./wezterm");
|
|
13
|
+
/**
|
|
14
|
+
* not fantastic, but ordering does matter
|
|
15
|
+
*/
|
|
16
|
+
exports.TERMINALS = [
|
|
17
|
+
herdr_1.herdr,
|
|
18
|
+
tmux_1.tmux,
|
|
19
|
+
tty7_1.tty7,
|
|
20
|
+
wezterm_1.wezterm,
|
|
21
|
+
kitty_1.kitty,
|
|
22
|
+
cmux_1.cmux,
|
|
23
|
+
supacode_1.supacode,
|
|
24
|
+
ghostty_1.ghostty,
|
|
25
|
+
vscode_1.vscode,
|
|
26
|
+
];
|
|
@@ -0,0 +1,209 @@
|
|
|
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.kitty = void 0;
|
|
7
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
const shared_1 = require("../shared");
|
|
10
|
+
// todo: do this automatically
|
|
11
|
+
const SETUP_HINT = [
|
|
12
|
+
"kitty has remote control switched off, which is required for this feature",
|
|
13
|
+
"Add these two lines to kitty.conf (usually ~/.config/kitty/kitty.conf), then fully quit and reopen kitty:",
|
|
14
|
+
" allow_remote_control socket-only",
|
|
15
|
+
" listen_on unix:/tmp/kitty",
|
|
16
|
+
].join("\n");
|
|
17
|
+
const GRID = 10000;
|
|
18
|
+
function pairRects(tab) {
|
|
19
|
+
const pairs = tab.layout_state?.pairs;
|
|
20
|
+
if (tab.layout !== "splits" || !pairs)
|
|
21
|
+
return [];
|
|
22
|
+
const groups = new Map((tab.groups ?? []).map((group) => [group.id, group.windows[0]]));
|
|
23
|
+
const windowIds = new Set(tab.windows.map((window) => window.id));
|
|
24
|
+
const rects = [];
|
|
25
|
+
const walk = (node, left, top, width, height) => {
|
|
26
|
+
if (node === undefined)
|
|
27
|
+
return;
|
|
28
|
+
if (typeof node === "number") {
|
|
29
|
+
const id = windowIds.has(node) ? node : groups.get(node);
|
|
30
|
+
if (id !== undefined)
|
|
31
|
+
rects.push({ id: String(id), left, top, right: left + width - 1, bottom: top + height - 1 });
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
const bias = node.bias ?? 0.5;
|
|
35
|
+
if (node.one === undefined || node.two === undefined) {
|
|
36
|
+
walk(node.one ?? node.two, left, top, width, height);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
if (node.horizontal ?? true) {
|
|
40
|
+
const first = Math.round(width * bias);
|
|
41
|
+
walk(node.one, left, top, first, height);
|
|
42
|
+
walk(node.two, left + first, top, width - first, height);
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
const first = Math.round(height * bias);
|
|
46
|
+
walk(node.one, left, top, width, first);
|
|
47
|
+
walk(node.two, left, top + first, width, height - first);
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
walk(pairs, 0, 0, GRID, GRID);
|
|
51
|
+
return rects;
|
|
52
|
+
}
|
|
53
|
+
function findKitten(env) {
|
|
54
|
+
const pathDirs = (env.PATH ?? "").split(node_path_1.default.delimiter).filter(Boolean);
|
|
55
|
+
const appBundles = process.platform === "darwin"
|
|
56
|
+
? [
|
|
57
|
+
"/Applications/kitty.app/Contents/MacOS/kitten",
|
|
58
|
+
node_path_1.default.join(env.HOME ?? "/", "Applications/kitty.app/Contents/MacOS/kitten"),
|
|
59
|
+
]
|
|
60
|
+
: [];
|
|
61
|
+
const candidates = [
|
|
62
|
+
...pathDirs.map((dir) => node_path_1.default.join(dir, "kitten")),
|
|
63
|
+
...appBundles,
|
|
64
|
+
...pathDirs.map((dir) => node_path_1.default.join(dir, "kitty")),
|
|
65
|
+
];
|
|
66
|
+
return (candidates.find((candidate) => {
|
|
67
|
+
try {
|
|
68
|
+
node_fs_1.default.accessSync(candidate, node_fs_1.default.constants.X_OK);
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
}) ?? null);
|
|
75
|
+
}
|
|
76
|
+
const kitty = (env, run) => {
|
|
77
|
+
const looksLikeKitty = (env.TERM ?? "").includes("kitty") || env.KITTY_WINDOW_ID || env.KITTY_PID;
|
|
78
|
+
if (!looksLikeKitty)
|
|
79
|
+
return null;
|
|
80
|
+
let cachedBin;
|
|
81
|
+
async function kitten(args, input) {
|
|
82
|
+
if (cachedBin === undefined)
|
|
83
|
+
cachedBin = findKitten(env);
|
|
84
|
+
if (!cachedBin) {
|
|
85
|
+
throw new Error("kitty's `kitten` command was not found — install kitty, or add kitten to PATH");
|
|
86
|
+
}
|
|
87
|
+
const listenOn = env.KITTY_LISTEN_ON && !env.KITTY_LISTEN_ON.startsWith("fd:") ? env.KITTY_LISTEN_ON : null;
|
|
88
|
+
const to = listenOn ? ["--to", listenOn] : [];
|
|
89
|
+
try {
|
|
90
|
+
return await run(cachedBin, ["@", ...to, ...args], input);
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
const stderr = String(error.stderr ?? "");
|
|
94
|
+
if (stderr.includes("Remote control is disabled"))
|
|
95
|
+
throw new Error(SETUP_HINT);
|
|
96
|
+
throw error;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
const osWindows = async () => JSON.parse(await kitten(["ls"]));
|
|
100
|
+
async function panes() {
|
|
101
|
+
const panes = [];
|
|
102
|
+
for (const osWindow of await osWindows()) {
|
|
103
|
+
for (const tab of osWindow.tabs) {
|
|
104
|
+
for (const window of tab.windows) {
|
|
105
|
+
panes.push({
|
|
106
|
+
id: String(window.id),
|
|
107
|
+
tab: `${osWindow.id}:${tab.id}`,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return panes;
|
|
113
|
+
}
|
|
114
|
+
async function listPanes() {
|
|
115
|
+
const listed = [];
|
|
116
|
+
for (const osWindow of await osWindows()) {
|
|
117
|
+
for (const tab of osWindow.tabs) {
|
|
118
|
+
for (const window of tab.windows) {
|
|
119
|
+
const pid = window.pid ?? window.foreground_processes?.[0]?.pid ?? null;
|
|
120
|
+
listed.push({
|
|
121
|
+
pid,
|
|
122
|
+
pane: {
|
|
123
|
+
id: String(window.id),
|
|
124
|
+
tab: `${osWindow.id}:${tab.id}`,
|
|
125
|
+
tty: null,
|
|
126
|
+
command: (window.foreground_processes ?? [])
|
|
127
|
+
.map((process) => (process.cmdline ?? []).join(" "))
|
|
128
|
+
.join("\n") || null,
|
|
129
|
+
},
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
const pids = listed.map((entry) => entry.pid).filter((pid) => pid != null);
|
|
135
|
+
if (pids.length > 0) {
|
|
136
|
+
const byPid = new Map();
|
|
137
|
+
const out = await run("ps", ["-o", "pid=,tty=", "-p", pids.join(",")]).catch(() => "");
|
|
138
|
+
for (const line of out.split("\n")) {
|
|
139
|
+
const [pid, tty] = line.trim().split(/\s+/);
|
|
140
|
+
if (pid && tty && tty !== "??")
|
|
141
|
+
byPid.set(Number(pid), `/dev/${tty}`);
|
|
142
|
+
}
|
|
143
|
+
for (const entry of listed) {
|
|
144
|
+
if (entry.pid != null)
|
|
145
|
+
entry.pane.tty = byPid.get(entry.pid) ?? null;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return listed.map((entry) => entry.pane);
|
|
149
|
+
}
|
|
150
|
+
/** kitty can only place splits in a layout that has them. */
|
|
151
|
+
async function ensureSplitsLayout(paneId) {
|
|
152
|
+
const self = Number(paneId);
|
|
153
|
+
const tabs = (await osWindows()).flatMap((osWindow) => osWindow.tabs);
|
|
154
|
+
const tab = tabs.find((candidate) => candidate.windows.some((window) => window.id === self)) ??
|
|
155
|
+
tabs.find((candidate) => candidate.is_active);
|
|
156
|
+
if (!tab || tab.layout === "splits")
|
|
157
|
+
return;
|
|
158
|
+
const hasSplits = tab.enabled_layouts.some((layout) => layout === "splits" || layout.startsWith("splits:"));
|
|
159
|
+
if (!hasSplits)
|
|
160
|
+
return;
|
|
161
|
+
const match = self > 0 ? ["--match", `id:${self}`] : [];
|
|
162
|
+
await kitten(["goto-layout", ...match, "splits"]);
|
|
163
|
+
}
|
|
164
|
+
async function neighbor(from, direction) {
|
|
165
|
+
const self = Number(from.id);
|
|
166
|
+
const tab = (await osWindows())
|
|
167
|
+
.flatMap((osWindow) => osWindow.tabs)
|
|
168
|
+
.find((candidate) => candidate.windows.some((window) => window.id === self));
|
|
169
|
+
if (!tab)
|
|
170
|
+
return null;
|
|
171
|
+
const rects = pairRects(tab);
|
|
172
|
+
const own = rects.find((rect) => rect.id === from.id);
|
|
173
|
+
if (!own)
|
|
174
|
+
return null;
|
|
175
|
+
const found = (0, shared_1.adjacentPane)(own, rects, direction, 1);
|
|
176
|
+
return found ? { id: found.id, tab: from.tab } : null;
|
|
177
|
+
}
|
|
178
|
+
return {
|
|
179
|
+
name: "kitty",
|
|
180
|
+
getCurrentPane: () => (0, shared_1.paneById)(panes, env.KITTY_WINDOW_ID),
|
|
181
|
+
listPanes,
|
|
182
|
+
neighbor,
|
|
183
|
+
async sendText(pane, text) {
|
|
184
|
+
const target = ["send-text", "--match", `id:${pane}`, "--stdin"];
|
|
185
|
+
try {
|
|
186
|
+
await kitten([...target, "--bracketed-paste", "auto"], text);
|
|
187
|
+
}
|
|
188
|
+
catch (error) {
|
|
189
|
+
const stderr = String(error.stderr ?? "");
|
|
190
|
+
if (!/bracketed-paste/.test(stderr))
|
|
191
|
+
throw error;
|
|
192
|
+
await kitten(target, text);
|
|
193
|
+
}
|
|
194
|
+
},
|
|
195
|
+
async focusPane(pane) {
|
|
196
|
+
await kitten(["focus-window", "--match", `id:${pane}`]);
|
|
197
|
+
},
|
|
198
|
+
async split({ from, direction, command, size }) {
|
|
199
|
+
await ensureSplitsLayout(from.id);
|
|
200
|
+
const location = direction === "right" || direction === "left" ? "vsplit" : "hsplit";
|
|
201
|
+
const bias = size ? [`--bias=${Math.round(size * 100)}`] : [];
|
|
202
|
+
await kitten(["launch", `--location=${location}`, ...bias, "--", ...command]);
|
|
203
|
+
if (direction === "left" || direction === "up") {
|
|
204
|
+
await kitten(["action", "move_window", direction]);
|
|
205
|
+
}
|
|
206
|
+
},
|
|
207
|
+
};
|
|
208
|
+
};
|
|
209
|
+
exports.kitty = kitty;
|
|
@@ -0,0 +1,79 @@
|
|
|
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.supacode = void 0;
|
|
7
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
|
+
const shared_1 = require("../shared");
|
|
9
|
+
const BUNDLED_CLI = "/Applications/supacode.app/Contents/Resources/bin/supacode";
|
|
10
|
+
const supacode = (env, run) => {
|
|
11
|
+
if (!env.SUPACODE_SURFACE_ID && env.TERM_PROGRAM !== "supacode")
|
|
12
|
+
return null;
|
|
13
|
+
const binary = node_fs_1.default.existsSync(BUNDLED_CLI) && !env.SUPACODE_SURFACE_ID ? BUNDLED_CLI : "supacode";
|
|
14
|
+
const supacode = (args) => run(binary, args);
|
|
15
|
+
const lines = async (args) => (await supacode(args))
|
|
16
|
+
.split("\n")
|
|
17
|
+
.map((line) => line.trim())
|
|
18
|
+
.filter((line) => line !== "");
|
|
19
|
+
async function panes() {
|
|
20
|
+
const found = [];
|
|
21
|
+
for (const tab of await lines(["tab", "list"])) {
|
|
22
|
+
for (const surface of await lines(["surface", "list", "--tab", tab])) {
|
|
23
|
+
found.push({ id: surface, tab });
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return found;
|
|
27
|
+
}
|
|
28
|
+
const homes = new Map();
|
|
29
|
+
async function listPanes() {
|
|
30
|
+
const worktrees = env.SUPACODE_WORKTREE_ID ? [env.SUPACODE_WORKTREE_ID] : await lines(["worktree", "list"]);
|
|
31
|
+
const found = [];
|
|
32
|
+
for (const worktree of worktrees) {
|
|
33
|
+
for (const tab of await lines(["tab", "list", "-w", worktree])) {
|
|
34
|
+
for (const surface of await lines(["surface", "list", "-w", worktree, "-t", tab])) {
|
|
35
|
+
homes.set(surface, { worktree, tab });
|
|
36
|
+
found.push({ id: surface, tab, tty: null, command: null });
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return found;
|
|
41
|
+
}
|
|
42
|
+
async function home(surface) {
|
|
43
|
+
if (!homes.has(surface))
|
|
44
|
+
await listPanes();
|
|
45
|
+
const found = homes.get(surface);
|
|
46
|
+
if (!found)
|
|
47
|
+
throw new Error(`supacode has no surface ${surface}`);
|
|
48
|
+
return found;
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
name: "supacode",
|
|
52
|
+
getCurrentPane: () => (0, shared_1.paneById)(panes, env.SUPACODE_SURFACE_ID),
|
|
53
|
+
listPanes,
|
|
54
|
+
async sendText(pane, text) {
|
|
55
|
+
const { worktree, tab } = await home(pane);
|
|
56
|
+
await supacode(["surface", "focus", "-w", worktree, "-t", tab, "-s", pane, "--input", text, "--timeout", "5"]);
|
|
57
|
+
},
|
|
58
|
+
async focusPane(pane) {
|
|
59
|
+
const { worktree, tab } = await home(pane);
|
|
60
|
+
await supacode(["surface", "focus", "-w", worktree, "-t", tab, "-s", pane, "--timeout", "5"]);
|
|
61
|
+
},
|
|
62
|
+
async split({ from, direction, command }) {
|
|
63
|
+
if (direction !== "right" && direction !== "down") {
|
|
64
|
+
throw new Error("supacode only splits right and down");
|
|
65
|
+
}
|
|
66
|
+
await supacode([
|
|
67
|
+
"surface",
|
|
68
|
+
"split",
|
|
69
|
+
"--surface",
|
|
70
|
+
from.id,
|
|
71
|
+
"--direction",
|
|
72
|
+
direction === "right" ? "horizontal" : "vertical",
|
|
73
|
+
"--input",
|
|
74
|
+
(0, shared_1.shellQuote)(command),
|
|
75
|
+
]);
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
};
|
|
79
|
+
exports.supacode = supacode;
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.tmux = void 0;
|
|
4
|
+
const node_child_process_1 = require("node:child_process");
|
|
5
|
+
const shared_1 = require("../shared");
|
|
6
|
+
const SPLIT_FLAG = { right: "-h", left: "-h", down: "-v", up: "-v" };
|
|
7
|
+
const tmux = (env, run) => {
|
|
8
|
+
if (!env.TMUX)
|
|
9
|
+
return null;
|
|
10
|
+
const tmux = (args) => run("tmux", args);
|
|
11
|
+
async function panes() {
|
|
12
|
+
const listing = await tmux([
|
|
13
|
+
"list-panes",
|
|
14
|
+
"-a",
|
|
15
|
+
"-F",
|
|
16
|
+
"#{session_name}\t#{window_id}\t#{pane_id}\t#{pane_title}",
|
|
17
|
+
]);
|
|
18
|
+
const panes = [];
|
|
19
|
+
for (const line of listing.split("\n")) {
|
|
20
|
+
if (!line.trim())
|
|
21
|
+
continue;
|
|
22
|
+
const [session, window, pane, ...title] = line.split("\t");
|
|
23
|
+
panes.push({ id: pane, tab: `${session}:${window}` });
|
|
24
|
+
}
|
|
25
|
+
return panes;
|
|
26
|
+
}
|
|
27
|
+
async function listPanes() {
|
|
28
|
+
const listing = await tmux([
|
|
29
|
+
"list-panes",
|
|
30
|
+
"-a",
|
|
31
|
+
"-F",
|
|
32
|
+
"#{session_name}\t#{window_id}\t#{pane_id}\t#{pane_tty}",
|
|
33
|
+
]);
|
|
34
|
+
const panes = [];
|
|
35
|
+
for (const line of listing.split("\n")) {
|
|
36
|
+
if (!line.trim())
|
|
37
|
+
continue;
|
|
38
|
+
const [session, window, pane, tty] = line.split("\t");
|
|
39
|
+
panes.push({ id: pane, tab: `${session}:${window}`, tty: tty || null, command: null });
|
|
40
|
+
}
|
|
41
|
+
return panes;
|
|
42
|
+
}
|
|
43
|
+
async function userClient() {
|
|
44
|
+
const listing = await tmux(["list-clients", "-F", "#{client_tty}\t#{client_flags}\t#{client_activity}"]);
|
|
45
|
+
let best = null;
|
|
46
|
+
for (const line of listing.split("\n")) {
|
|
47
|
+
if (!line.trim())
|
|
48
|
+
continue;
|
|
49
|
+
const [tty, flags, activity] = line.split("\t");
|
|
50
|
+
const client = { tty, focused: (flags ?? "").split(",").includes("focused"), activity: Number(activity) || 0 };
|
|
51
|
+
if (!best || (client.focused && !best.focused) || (client.focused === best.focused && client.activity > best.activity)) {
|
|
52
|
+
best = client;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return best?.tty ?? null;
|
|
56
|
+
}
|
|
57
|
+
async function neighbor(from, direction) {
|
|
58
|
+
const listing = await tmux([
|
|
59
|
+
"list-panes",
|
|
60
|
+
"-t",
|
|
61
|
+
from.id,
|
|
62
|
+
"-F",
|
|
63
|
+
"#{pane_id}\t#{pane_left}\t#{pane_top}\t#{pane_right}\t#{pane_bottom}",
|
|
64
|
+
]);
|
|
65
|
+
const rects = [];
|
|
66
|
+
for (const line of listing.split("\n")) {
|
|
67
|
+
if (!line.trim())
|
|
68
|
+
continue;
|
|
69
|
+
const [id, left, top, right, bottom] = line.split("\t");
|
|
70
|
+
rects.push({ id, left: Number(left), top: Number(top), right: Number(right), bottom: Number(bottom) });
|
|
71
|
+
}
|
|
72
|
+
const self = rects.find((rect) => rect.id === from.id);
|
|
73
|
+
if (!self)
|
|
74
|
+
return null;
|
|
75
|
+
const found = (0, shared_1.adjacentPane)(self, rects, direction);
|
|
76
|
+
return found ? { id: found.id, tab: from.tab } : null;
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
name: "tmux",
|
|
80
|
+
wrapper: "tmux",
|
|
81
|
+
prepare: () => prepareTmux(env),
|
|
82
|
+
getCurrentPane: () => (0, shared_1.paneById)(panes, env.TMUX_PANE),
|
|
83
|
+
listPanes,
|
|
84
|
+
neighbor,
|
|
85
|
+
async sendText(pane, text) {
|
|
86
|
+
if (text === "")
|
|
87
|
+
return;
|
|
88
|
+
await run("tmux", ["load-buffer", "-b", "pixel-send", "-"], text);
|
|
89
|
+
await tmux(["paste-buffer", "-p", "-d", "-b", "pixel-send", "-t", pane]);
|
|
90
|
+
},
|
|
91
|
+
async focusPane(pane) {
|
|
92
|
+
const client = await userClient();
|
|
93
|
+
if (client) {
|
|
94
|
+
await tmux(["switch-client", "-c", client, "-t", pane]);
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
await tmux(["select-window", "-t", pane]);
|
|
98
|
+
await tmux(["select-pane", "-t", pane]);
|
|
99
|
+
},
|
|
100
|
+
async split({ from, direction, command, size }) {
|
|
101
|
+
const before = direction === "left" || direction === "up" ? ["-b"] : [];
|
|
102
|
+
const length = size ? ["-l", `${Math.round(size * 100)}%`] : [];
|
|
103
|
+
await tmux([
|
|
104
|
+
"split-window",
|
|
105
|
+
SPLIT_FLAG[direction],
|
|
106
|
+
...before,
|
|
107
|
+
...length,
|
|
108
|
+
"-t",
|
|
109
|
+
from.id,
|
|
110
|
+
(0, shared_1.shellQuote)(command),
|
|
111
|
+
]);
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
};
|
|
115
|
+
exports.tmux = tmux;
|
|
116
|
+
function prepareTmux(env) {
|
|
117
|
+
const tmux = (args) => {
|
|
118
|
+
try {
|
|
119
|
+
return (0, node_child_process_1.execFileSync)("tmux", args, { env, encoding: "utf8", timeout: 5000 }).trim();
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
tmux(["set", "-p", "allow-passthrough", "on"]);
|
|
126
|
+
tmux(["set", "-s", "focus-events", "on"]);
|
|
127
|
+
tmux(["set", "-s", "extended-keys", "on"]);
|
|
128
|
+
tmux(["set", "-s", "extended-keys-format", "csi-u"]);
|
|
129
|
+
const termname = tmux(["display", "-p", "#{client_termname}"]);
|
|
130
|
+
if (termname)
|
|
131
|
+
tmux(["set", "-as", "terminal-features", `${termname}:extkeys`]);
|
|
132
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.tty7 = void 0;
|
|
4
|
+
const shared_1 = require("../shared");
|
|
5
|
+
const tty7 = (env, run) => {
|
|
6
|
+
if (!env.TTY7_PANE && env.TERM_PROGRAM !== "tty7")
|
|
7
|
+
return null;
|
|
8
|
+
const tty7 = (args) => run("tty7", args);
|
|
9
|
+
const list = async (args) => JSON.parse(await tty7(args)).panes;
|
|
10
|
+
const selfId = () => (env.TTY7_PANE ?? "").replace(/^%/, "") || null;
|
|
11
|
+
async function panes() {
|
|
12
|
+
const [placed, running] = await Promise.all([
|
|
13
|
+
list(["pane", "ls", "--json"]),
|
|
14
|
+
list(["pane", "ls", "--all", "--json"]),
|
|
15
|
+
]);
|
|
16
|
+
const live = new Set(running.map((pane) => pane.pane));
|
|
17
|
+
return placed
|
|
18
|
+
.filter((pane) => live.has(pane.pane))
|
|
19
|
+
.map((pane) => ({
|
|
20
|
+
id: String(pane.pane),
|
|
21
|
+
tab: `${pane.workspace ?? ""}:${pane.tab ?? ""}`,
|
|
22
|
+
}));
|
|
23
|
+
}
|
|
24
|
+
async function listPanes() {
|
|
25
|
+
const [placed, running] = await Promise.all([
|
|
26
|
+
list(["pane", "ls", "--json"]),
|
|
27
|
+
list(["pane", "ls", "--all", "--json"]),
|
|
28
|
+
]);
|
|
29
|
+
// tty7 reports the foreground process name as the pane title
|
|
30
|
+
const commands = new Map(running.filter((pane) => pane.live).map((pane) => [pane.pane, pane.title]));
|
|
31
|
+
return placed
|
|
32
|
+
.filter((pane) => commands.has(pane.pane))
|
|
33
|
+
.map((pane) => ({
|
|
34
|
+
id: String(pane.pane),
|
|
35
|
+
tab: `${pane.workspace ?? ""}:${pane.tab ?? ""}`,
|
|
36
|
+
tty: null,
|
|
37
|
+
command: commands.get(pane.pane) || null,
|
|
38
|
+
}));
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
name: "tty7",
|
|
42
|
+
getCurrentPane: () => (0, shared_1.paneById)(panes, selfId()),
|
|
43
|
+
listPanes,
|
|
44
|
+
async sendText(pane, text) {
|
|
45
|
+
await tty7(["send", `%${pane}`, (0, shared_1.bracketedPaste)(text)]);
|
|
46
|
+
},
|
|
47
|
+
async split({ from, direction, command, size }) {
|
|
48
|
+
if (direction !== "right" && direction !== "down") {
|
|
49
|
+
throw new Error("tty7 only splits right and down");
|
|
50
|
+
}
|
|
51
|
+
const axis = direction === "right" ? "--horizontal" : "--vertical";
|
|
52
|
+
const ratio = size ? ["--ratio", String(1 - size)] : [];
|
|
53
|
+
const created = JSON.parse(await tty7(["split", `%${from.id}`, axis, ...ratio, "--json"]));
|
|
54
|
+
await tty7(["send", `%${created.pane}`, (0, shared_1.shellQuote)(command), "--enter"]);
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
};
|
|
58
|
+
exports.tty7 = tty7;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.vscode = void 0;
|
|
4
|
+
// we could implement the full api with a vscode extension
|
|
5
|
+
const vscode = (env) => {
|
|
6
|
+
if (env.TERM_PROGRAM !== "vscode" && !env.VSCODE_INJECTION)
|
|
7
|
+
return null;
|
|
8
|
+
return {
|
|
9
|
+
name: "vscode",
|
|
10
|
+
reportsCssPixels: true,
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
exports.vscode = vscode;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.wezterm = void 0;
|
|
4
|
+
const shared_1 = require("../shared");
|
|
5
|
+
const SPLIT_FLAG = { right: "--right", left: "--left", down: "--bottom", up: "--top" };
|
|
6
|
+
const wezterm = (env, run) => {
|
|
7
|
+
if (env.TERM_PROGRAM !== "WezTerm" && !env.WEZTERM_PANE)
|
|
8
|
+
return null;
|
|
9
|
+
const wezterm = (args, input) => run("wezterm", args, input);
|
|
10
|
+
async function panes() {
|
|
11
|
+
const list = JSON.parse(await wezterm(["cli", "list", "--format", "json"]));
|
|
12
|
+
return list.map((pane) => ({
|
|
13
|
+
id: String(pane.pane_id),
|
|
14
|
+
tab: `${pane.window_id}:${pane.tab_id}`,
|
|
15
|
+
}));
|
|
16
|
+
}
|
|
17
|
+
async function listPanes() {
|
|
18
|
+
const list = JSON.parse(await wezterm(["cli", "list", "--format", "json"]));
|
|
19
|
+
return list.map((pane) => ({
|
|
20
|
+
id: String(pane.pane_id),
|
|
21
|
+
tab: `${pane.window_id}:${pane.tab_id}`,
|
|
22
|
+
tty: pane.tty_name || null,
|
|
23
|
+
command: null,
|
|
24
|
+
}));
|
|
25
|
+
}
|
|
26
|
+
async function neighbor(from, direction) {
|
|
27
|
+
const list = JSON.parse(await wezterm(["cli", "list", "--format", "json"]));
|
|
28
|
+
const rects = list
|
|
29
|
+
.filter((pane) => `${pane.window_id}:${pane.tab_id}` === from.tab && pane.size && pane.left_col != null && pane.top_row != null)
|
|
30
|
+
.map((pane) => ({
|
|
31
|
+
id: String(pane.pane_id),
|
|
32
|
+
left: pane.left_col,
|
|
33
|
+
top: pane.top_row,
|
|
34
|
+
right: pane.left_col + pane.size.cols - 1,
|
|
35
|
+
bottom: pane.top_row + pane.size.rows - 1,
|
|
36
|
+
}));
|
|
37
|
+
const self = rects.find((rect) => rect.id === from.id);
|
|
38
|
+
if (!self)
|
|
39
|
+
return null;
|
|
40
|
+
const found = (0, shared_1.adjacentPane)(self, rects, direction);
|
|
41
|
+
return found ? { id: found.id, tab: from.tab } : null;
|
|
42
|
+
}
|
|
43
|
+
return {
|
|
44
|
+
name: "wezterm",
|
|
45
|
+
getCurrentPane: () => (0, shared_1.paneById)(panes, env.WEZTERM_PANE),
|
|
46
|
+
listPanes,
|
|
47
|
+
neighbor,
|
|
48
|
+
async sendText(pane, text) {
|
|
49
|
+
await wezterm(["cli", "send-text", "--pane-id", pane], text);
|
|
50
|
+
},
|
|
51
|
+
async focusPane(pane) {
|
|
52
|
+
await wezterm(["cli", "activate-pane", "--pane-id", pane]);
|
|
53
|
+
},
|
|
54
|
+
async split({ direction, command }) {
|
|
55
|
+
await wezterm(["cli", "split-pane", SPLIT_FLAG[direction], "--", ...command]);
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
};
|
|
59
|
+
exports.wezterm = wezterm;
|
package/dist/theme.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { EngineInfo, Rgba } from "./react";
|
|
2
|
+
export interface Theme {
|
|
3
|
+
bg: Rgba;
|
|
4
|
+
fg: Rgba;
|
|
5
|
+
muted: Rgba;
|
|
6
|
+
disabled: Rgba;
|
|
7
|
+
accent: Rgba;
|
|
8
|
+
field: Rgba;
|
|
9
|
+
fieldBorder: Rgba;
|
|
10
|
+
hover: Rgba;
|
|
11
|
+
hoverStrong: Rgba;
|
|
12
|
+
hairline: Rgba;
|
|
13
|
+
selection: Rgba;
|
|
14
|
+
red: Rgba;
|
|
15
|
+
green: Rgba;
|
|
16
|
+
yellow: Rgba;
|
|
17
|
+
magenta: Rgba;
|
|
18
|
+
cyan: Rgba;
|
|
19
|
+
}
|
|
20
|
+
export declare function withAlpha(color: Rgba, alpha: number): Rgba;
|
|
21
|
+
export declare function mix(base: Rgba, toward: Rgba, t: number): Rgba;
|
|
22
|
+
export declare function makeTheme(colors: EngineInfo["colors"]): Theme;
|
package/dist/theme.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.withAlpha = withAlpha;
|
|
4
|
+
exports.mix = mix;
|
|
5
|
+
exports.makeTheme = makeTheme;
|
|
6
|
+
function withAlpha(color, alpha) {
|
|
7
|
+
return [color[0], color[1], color[2], alpha];
|
|
8
|
+
}
|
|
9
|
+
function mix(base, toward, t) {
|
|
10
|
+
const channel = (b, w) => Math.round(b + (w - b) * t);
|
|
11
|
+
return [
|
|
12
|
+
channel(base[0], toward[0]),
|
|
13
|
+
channel(base[1], toward[1]),
|
|
14
|
+
channel(base[2], toward[2]),
|
|
15
|
+
255,
|
|
16
|
+
];
|
|
17
|
+
}
|
|
18
|
+
function makeTheme(colors) {
|
|
19
|
+
const bg = colors.background ?? [30, 32, 38, 255];
|
|
20
|
+
const fg = colors.foreground ?? [235, 237, 242, 255];
|
|
21
|
+
const accent = colors.palette[12] ?? colors.palette[4] ?? [93, 156, 255, 255];
|
|
22
|
+
return {
|
|
23
|
+
bg,
|
|
24
|
+
fg,
|
|
25
|
+
accent,
|
|
26
|
+
muted: mix(fg, bg, 0.35),
|
|
27
|
+
disabled: mix(fg, bg, 0.7),
|
|
28
|
+
field: mix(bg, fg, 0.06),
|
|
29
|
+
fieldBorder: mix(bg, fg, 0.16),
|
|
30
|
+
hover: mix(bg, fg, 0.12),
|
|
31
|
+
hoverStrong: mix(bg, fg, 0.26),
|
|
32
|
+
hairline: mix(bg, fg, 0.12),
|
|
33
|
+
selection: mix(bg, accent, 0.35),
|
|
34
|
+
red: colors.palette[9] ?? colors.palette[1] ?? [229, 72, 77, 255],
|
|
35
|
+
green: colors.palette[10] ?? colors.palette[2] ?? [48, 164, 108, 255],
|
|
36
|
+
yellow: colors.palette[11] ?? colors.palette[3] ?? [245, 165, 36, 255],
|
|
37
|
+
magenta: colors.palette[13] ?? colors.palette[5] ?? [186, 148, 255, 255],
|
|
38
|
+
cyan: colors.palette[14] ?? colors.palette[6] ?? [94, 201, 227, 255],
|
|
39
|
+
};
|
|
40
|
+
}
|