@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.
Files changed (153) hide show
  1. package/dist/bin.d.ts +2 -0
  2. package/dist/bin.js +161 -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,74 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SurfaceCapture = exports.Surface = void 0;
4
+ exports.surfaceId = surfaceId;
5
+ class Surface {
6
+ id;
7
+ engine;
8
+ closed = false;
9
+ constructor(engine, id) {
10
+ this.engine = engine;
11
+ this.id = id;
12
+ }
13
+ present(frame) {
14
+ if (this.closed) {
15
+ if ("shm" in frame)
16
+ frame.released?.();
17
+ return;
18
+ }
19
+ if ("ioSurface" in frame) {
20
+ const submit = this.engine.updateSurfaceTexture;
21
+ if (!submit)
22
+ throw new Error("IOSurface frames are not supported on this platform");
23
+ submit.call(this.engine, this.id, frame.ioSurface, frame.damage);
24
+ }
25
+ else if ("shm" in frame) {
26
+ const submit = this.engine.updateSurfaceShm;
27
+ if (!submit)
28
+ throw new Error("shared memory frames are not supported on this platform");
29
+ submit.call(this.engine, this.id, frame.shm, frame.damage, frame.released);
30
+ }
31
+ else {
32
+ this.engine.updateSurface(this.id, frame.bgra, frame.width, frame.height, frame.damage);
33
+ }
34
+ }
35
+ clear() {
36
+ if (this.closed)
37
+ return;
38
+ this.engine.removeSurface(this.id);
39
+ }
40
+ startCapture(dir) {
41
+ return new SurfaceCapture(this.engine, this.engine.startSurfaceCapture(this.id, dir));
42
+ }
43
+ close() {
44
+ if (this.closed)
45
+ return;
46
+ this.closed = true;
47
+ this.engine.removeSurface(this.id);
48
+ }
49
+ }
50
+ exports.Surface = Surface;
51
+ class SurfaceCapture {
52
+ engine;
53
+ id;
54
+ constructor(engine, id) {
55
+ this.engine = engine;
56
+ this.id = id;
57
+ }
58
+ stop() {
59
+ return JSON.parse(this.engine.stopSurfaceCapture(this.id));
60
+ }
61
+ index() {
62
+ return JSON.parse(this.engine.captureIndex(this.id));
63
+ }
64
+ frame(index) {
65
+ return this.engine.captureFrame(this.id, index);
66
+ }
67
+ release() {
68
+ this.engine.releaseCapture(this.id);
69
+ }
70
+ }
71
+ exports.SurfaceCapture = SurfaceCapture;
72
+ function surfaceId(surface) {
73
+ return surface.id;
74
+ }
@@ -0,0 +1,53 @@
1
+ import type { EngineKeyEvent, LayoutSnapshot, PastedImage, PixelRoot, TerminalColors } from "./react";
2
+ import type { Store } from "./react/devtools/store";
3
+ import type { PageHost } from "./web/host";
4
+ import type { TerminalTheme } from "./web/session";
5
+ export interface ViewEntry {
6
+ host: PageHost | null;
7
+ handle: object | null;
8
+ devtoolsEnabled: boolean;
9
+ externalDevtools: boolean;
10
+ externalDevtoolsAction: ((action: "close" | "dock-bottom" | "dock-right") => void) | null;
11
+ toggleDevtools(): void;
12
+ handleKey(event: EngineKeyEvent): boolean;
13
+ paste?(text: string): void;
14
+ setActive?(focused: boolean): void;
15
+ }
16
+ export interface RegistryHooks {
17
+ quit(entry: ViewEntry | null): void;
18
+ }
19
+ export declare class ViewRegistry {
20
+ readonly root: PixelRoot;
21
+ readonly displayScale: number;
22
+ private readonly noSuper;
23
+ private readonly hooks;
24
+ readonly views: Set<ViewEntry>;
25
+ focused: ViewEntry | null;
26
+ readonly resizeListeners: Set<() => void>;
27
+ readonly layout: Store<LayoutSnapshot>;
28
+ readonly colors: Store<TerminalColors>;
29
+ private sentCursor;
30
+ constructor(root: PixelRoot, displayScale: number, noSuper: boolean, hooks: RegistryHooks);
31
+ register(entry: ViewEntry): void;
32
+ unregister(entry: ViewEntry): void;
33
+ hosts(): Iterable<PageHost>;
34
+ focus(entry: ViewEntry, target?: "page" | "devtools" | "popup"): void;
35
+ blur(entry: ViewEntry): void;
36
+ private setActive;
37
+ quit(entry: ViewEntry | null): void;
38
+ setPointerShape(shape: string): void;
39
+ queryLayout(): void;
40
+ background(): string;
41
+ theme(): TerminalTheme | null;
42
+ handleKey(event: EngineKeyEvent): void;
43
+ handlePaste(text: string): void;
44
+ handlePasteImage(image: PastedImage): void;
45
+ handleTerminalFocus(focused: boolean): void;
46
+ private clipboardKeys;
47
+ private cmdHeld;
48
+ private clipboardHeld;
49
+ private isDevtoolsKey;
50
+ }
51
+ export declare const RootContext: import("react").Context<ViewRegistry | null>;
52
+ export declare function useRegistryColors(registry: ViewRegistry): TerminalColors;
53
+ export declare const handleEntries: WeakMap<object, ViewEntry>;
@@ -0,0 +1,193 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handleEntries = exports.RootContext = exports.ViewRegistry = void 0;
4
+ exports.useRegistryColors = useRegistryColors;
5
+ const react_1 = require("react");
6
+ const store_1 = require("./react/devtools/store");
7
+ class ViewRegistry {
8
+ root;
9
+ displayScale;
10
+ noSuper;
11
+ hooks;
12
+ views = new Set();
13
+ focused = null;
14
+ resizeListeners = new Set();
15
+ layout = (0, store_1.createStore)({
16
+ rects: new Map(),
17
+ stats: { frameMs: 0, fps: 0 },
18
+ width: 0,
19
+ height: 0,
20
+ at: 0,
21
+ });
22
+ colors;
23
+ sentCursor = null;
24
+ constructor(root, displayScale, noSuper, hooks) {
25
+ this.root = root;
26
+ this.displayScale = displayScale;
27
+ this.noSuper = noSuper;
28
+ this.hooks = hooks;
29
+ this.colors = (0, store_1.createStore)(root.info.colors);
30
+ }
31
+ register(entry) {
32
+ this.views.add(entry);
33
+ }
34
+ unregister(entry) {
35
+ this.views.delete(entry);
36
+ if (this.focused === entry)
37
+ this.focused = null;
38
+ }
39
+ *hosts() {
40
+ for (const view of this.views)
41
+ if (view.host)
42
+ yield view.host;
43
+ }
44
+ focus(entry, target = "page") {
45
+ if (this.focused !== entry) {
46
+ this.setActive(this.focused, false);
47
+ this.focused = entry;
48
+ if (!entry.host)
49
+ entry.setActive?.(true);
50
+ }
51
+ const host = entry.host;
52
+ if (!host)
53
+ return;
54
+ if (target === "devtools")
55
+ host.focusDevtools();
56
+ else if (target === "page")
57
+ host.focusContent();
58
+ }
59
+ blur(entry) {
60
+ if (this.focused !== entry)
61
+ return;
62
+ this.setActive(entry, false);
63
+ this.focused = null;
64
+ }
65
+ setActive(entry, active) {
66
+ if (!entry)
67
+ return;
68
+ if (entry.host)
69
+ entry.host.setActive(active);
70
+ else
71
+ entry.setActive?.(active);
72
+ }
73
+ quit(entry) {
74
+ this.hooks.quit(entry);
75
+ }
76
+ setPointerShape(shape) {
77
+ if (shape === this.sentCursor)
78
+ return;
79
+ this.sentCursor = shape;
80
+ this.root.setPointerShape(shape);
81
+ }
82
+ queryLayout() {
83
+ this.root.queryLayout();
84
+ }
85
+ background() {
86
+ const bg = this.root.info.colors.background ?? [30, 32, 38, 255];
87
+ return `#${bg.slice(0, 3).map((c) => c.toString(16).padStart(2, "0")).join("")}`;
88
+ }
89
+ theme() {
90
+ const colors = this.root.info.colors;
91
+ if (!colors.background || !colors.foreground)
92
+ return null;
93
+ const rgb = (channelled) => channelled ? [channelled[0], channelled[1], channelled[2]] : null;
94
+ return {
95
+ background: rgb(colors.background),
96
+ foreground: rgb(colors.foreground),
97
+ ansi: Array.from({ length: 16 }, (_, at) => rgb(colors.palette[at] ?? null)),
98
+ };
99
+ }
100
+ handleKey(event) {
101
+ const view = this.focused;
102
+ if (!view)
103
+ return;
104
+ if (view.handleKey(event))
105
+ return;
106
+ const host = view.host;
107
+ if (!host)
108
+ return;
109
+ if (host.popup) {
110
+ if (event.kind !== "release" && event.key === "escape") {
111
+ host.popup.close();
112
+ return;
113
+ }
114
+ this.clipboardKeys(event, host.popup.input);
115
+ host.popup.input.key(event);
116
+ return;
117
+ }
118
+ if (event.kind !== "release" && view.devtoolsEnabled && this.isDevtoolsKey(event)) {
119
+ view.toggleDevtools();
120
+ return;
121
+ }
122
+ if (host.devtoolsFocused && host.devtools) {
123
+ this.clipboardKeys(event, host.devtools.input);
124
+ host.devtools.input.key(event);
125
+ return;
126
+ }
127
+ this.clipboardKeys(event, host);
128
+ host.key(event);
129
+ }
130
+ handlePaste(text) {
131
+ const host = this.focused?.host;
132
+ if (!host) {
133
+ this.focused?.paste?.(text);
134
+ return;
135
+ }
136
+ if (host.popup)
137
+ host.popup.input.paste(text);
138
+ else if (host.devtoolsFocused && host.devtools)
139
+ host.devtools.input.paste(text);
140
+ else
141
+ host.paste(text);
142
+ }
143
+ handlePasteImage(image) {
144
+ const host = this.focused?.host;
145
+ if (!host)
146
+ return;
147
+ if (host.popup)
148
+ host.popup.input.pasteImage(image);
149
+ else if (host.devtoolsFocused && host.devtools)
150
+ host.devtools.input.pasteImage(image);
151
+ else
152
+ host.pasteImage(image);
153
+ }
154
+ handleTerminalFocus(focused) {
155
+ this.setActive(this.focused, focused);
156
+ }
157
+ clipboardKeys(event, target) {
158
+ if (event.kind !== "press")
159
+ return;
160
+ if (this.clipboardHeld(event) && event.key === "v")
161
+ this.root.requestClipboardImage();
162
+ if (this.clipboardHeld(event) && (event.key === "c" || event.key === "x")) {
163
+ void target.selectionText().then((text) => {
164
+ if (text)
165
+ this.root.setClipboard(text);
166
+ });
167
+ }
168
+ }
169
+ cmdHeld(event) {
170
+ return event.mods.super || (this.noSuper && event.mods.alt);
171
+ }
172
+ clipboardHeld(event) {
173
+ if (this.cmdHeld(event))
174
+ return true;
175
+ return (process.platform === "linux" && event.mods.ctrl && !event.mods.shift && !event.mods.alt);
176
+ }
177
+ isDevtoolsKey(event) {
178
+ const { key, mods } = event;
179
+ if (key === "f12" && !mods.super && !mods.ctrl && !mods.alt && !mods.shift)
180
+ return true;
181
+ if (key === "i" && mods.ctrl && mods.shift && !mods.alt && !mods.super)
182
+ return true;
183
+ if (process.platform === "darwin" && key === "i" && this.cmdHeld(event) && mods.alt)
184
+ return true;
185
+ return false;
186
+ }
187
+ }
188
+ exports.ViewRegistry = ViewRegistry;
189
+ exports.RootContext = (0, react_1.createContext)(null);
190
+ function useRegistryColors(registry) {
191
+ return (0, react_1.useSyncExternalStore)(registry.colors.subscribe, registry.colors.get, registry.colors.get);
192
+ }
193
+ exports.handleEntries = new WeakMap();
package/dist/root.d.ts ADDED
@@ -0,0 +1,19 @@
1
+ import type { ReactNode } from "react";
2
+ import type { EngineKeyEvent, PixelRoot, RootOptions as EngineRootOptions } from "./react";
3
+ import type { WebViewHandle, WebViewProps } from "./webview";
4
+ export interface RootOptions extends Omit<EngineRootOptions, "keyEventTypes" | "onKey" | "onEngineExit" | "onLayout" | "host" | "onHostClosed" | "onHandoff"> {
5
+ name?: string;
6
+ onKey?: (event: EngineKeyEvent) => boolean | void;
7
+ onQuit?: (view: WebViewHandle | null) => void;
8
+ onExit?: (code: number) => void;
9
+ }
10
+ export type LoadOptions = Omit<WebViewProps, "src" | "style" | "hidden" | "autoFocus">;
11
+ export interface Root extends Omit<PixelRoot, "render" | "flushSync" | "stop" | "retarget"> {
12
+ readonly displayScale: number;
13
+ readonly hosted: boolean;
14
+ render(element: ReactNode): void;
15
+ loadURL(url: string, options?: LoadOptions): WebViewHandle;
16
+ loadFile(file: string, options?: LoadOptions): WebViewHandle;
17
+ stop(code?: number): void;
18
+ }
19
+ export declare function createRoot(options?: RootOptions): Root;
package/dist/root.js ADDED
@@ -0,0 +1,342 @@
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.createRoot = createRoot;
7
+ const jsx_runtime_1 = require("react/jsx-runtime");
8
+ const node_child_process_1 = require("node:child_process");
9
+ const node_crypto_1 = require("node:crypto");
10
+ const node_fs_1 = __importDefault(require("node:fs"));
11
+ const node_path_1 = __importDefault(require("node:path"));
12
+ const node_url_1 = require("node:url");
13
+ const react_1 = require("react");
14
+ const electron_1 = require("electron");
15
+ const debug_1 = require("./debug");
16
+ const shell_1 = require("./host/shell");
17
+ const server_1 = require("./host/server");
18
+ const strip_1 = require("./host/strip");
19
+ const instances_1 = require("./instances");
20
+ const react_2 = require("./react");
21
+ const registry_1 = require("./registry");
22
+ const webview_1 = require("./webview");
23
+ const scale_1 = require("./scale");
24
+ const terminal_1 = require("./terminal");
25
+ const offscreen_1 = require("./web/offscreen");
26
+ const session_1 = require("./web/session");
27
+ function ownTty() {
28
+ try {
29
+ const out = (0, node_child_process_1.execFileSync)("tty", { stdio: ["inherit", "pipe", "ignore"], encoding: "utf8" }).trim();
30
+ return out.startsWith("/dev/") ? out : undefined;
31
+ }
32
+ catch {
33
+ return undefined;
34
+ }
35
+ }
36
+ const liveRoots = new Set();
37
+ let signalsInstalled = false;
38
+ function installSignals() {
39
+ if (signalsInstalled)
40
+ return;
41
+ signalsInstalled = true;
42
+ const stopAll = (code) => () => {
43
+ for (const root of [...liveRoots])
44
+ root.stop(code);
45
+ };
46
+ process.on("SIGTERM", stopAll(143));
47
+ process.on("SIGHUP", stopAll(129));
48
+ }
49
+ const REJOIN_WAIT_MS = 5000;
50
+ function waitForSocket(socket) {
51
+ return new Promise((resolve, reject) => {
52
+ const deadline = Date.now() + REJOIN_WAIT_MS;
53
+ const check = () => {
54
+ if (node_fs_1.default.existsSync(socket))
55
+ return resolve();
56
+ if (Date.now() > deadline)
57
+ return reject(new Error(`no owner appeared at ${socket}`));
58
+ setTimeout(check, 25);
59
+ };
60
+ check();
61
+ });
62
+ }
63
+ function createRoot(options = {}) {
64
+ if (!electron_1.app.isReady()) {
65
+ throw new Error("[placeholder copy: createRoot() needs electron to be ready. Run your entry with `pixel .`, which waits for app.whenReady() before loading it.]");
66
+ }
67
+ const env = options.sessionEnv ?? process.env;
68
+ const terminal = (0, terminal_1.detect)(env);
69
+ const tty = options.tty ?? env.PIXEL_TTY ?? ownTty();
70
+ const embed = env.PIXEL_EMBED ?? null;
71
+ let owner = tty && !embed ? (0, instances_1.findOwner)(tty) : null;
72
+ const name = options.name ?? electron_1.app.getName();
73
+ const cellZoom = new scale_1.CellZoomFollower();
74
+ const shell = new shell_1.Shell(() => name);
75
+ let registry = null;
76
+ let embedder = null;
77
+ let server = null;
78
+ let record = null;
79
+ let handoff = null;
80
+ let stopping = false;
81
+ const shutdown = (code, then = () => finish(code)) => {
82
+ if (stopping)
83
+ return;
84
+ stopping = true;
85
+ (0, debug_1.debug)("shutdown", { code, hosted: owner != null });
86
+ liveRoots.delete(root);
87
+ if (embedder)
88
+ (0, session_1.uninstallEmbedderApi)(embedder);
89
+ if (registry) {
90
+ for (const host of [...registry.hosts()]) {
91
+ try {
92
+ host.stop();
93
+ }
94
+ catch { }
95
+ }
96
+ }
97
+ (0, session_1.flushSessions)();
98
+ try {
99
+ // wait whats going on here
100
+ engineRoot.setPointerShape("text");
101
+ }
102
+ catch { }
103
+ try {
104
+ engineRoot.stop();
105
+ }
106
+ catch { }
107
+ record?.withdraw();
108
+ server?.stop();
109
+ then();
110
+ };
111
+ const finish = (code) => {
112
+ if (tty)
113
+ (0, instances_1.clearHandoff)(tty, env);
114
+ if (options.onExit)
115
+ options.onExit(code);
116
+ else
117
+ electron_1.app.exit(code);
118
+ };
119
+ const finishAfterSuccessor = (code) => {
120
+ if (!tty)
121
+ return finish(code);
122
+ const deadline = Date.now() + 15000;
123
+ const check = () => {
124
+ if ((0, instances_1.findOwner)(tty, env) || Date.now() > deadline)
125
+ return finish(code);
126
+ setTimeout(check, 25);
127
+ };
128
+ check();
129
+ };
130
+ const socketPath = tty ? node_path_1.default.join((0, instances_1.instancesDir)(env), `${(0, instances_1.instanceKey)(tty)}.sock`) : null;
131
+ const engineRoot = (0, react_2.createRoot)({
132
+ ...options,
133
+ tty: owner || embed ? undefined : tty,
134
+ host: owner
135
+ ? {
136
+ socket: owner.socket,
137
+ pane: env.PIXEL_PANE ?? (0, node_crypto_1.randomBytes)(8).toString("hex"),
138
+ name,
139
+ }
140
+ : embed && tty
141
+ ? { socket: embed, pane: (0, node_crypto_1.randomBytes)(8).toString("hex"), name, tty }
142
+ : undefined,
143
+ wrapper: options.wrapper ?? (owner || embed ? undefined : terminal?.wrapper),
144
+ keyEventTypes: true,
145
+ devtools: options.devtools ?? process.env.NODE_ENV !== "production",
146
+ onKey: (event) => {
147
+ if (shell.handleKey(event))
148
+ return;
149
+ if (!shell.guestActive() && options.onKey?.(event) === true)
150
+ return;
151
+ registry?.handleKey(event);
152
+ },
153
+ onPaste: (text) => {
154
+ if (!shell.guestActive())
155
+ options.onPaste?.(text);
156
+ registry?.handlePaste(text);
157
+ },
158
+ onPasteImage: (image) => {
159
+ if (!shell.guestActive())
160
+ options.onPasteImage?.(image);
161
+ registry?.handlePasteImage(image);
162
+ },
163
+ onFocus: (focused) => {
164
+ options.onFocus?.(focused);
165
+ registry?.handleTerminalFocus(focused);
166
+ },
167
+ onResize: (size) => {
168
+ const ratio = cellZoom.ratio(engineRoot.info);
169
+ if (registry) {
170
+ if (ratio != null) {
171
+ for (const host of registry.hosts()) {
172
+ host.scaleZoom(ratio);
173
+ host.popup?.scaleZoom(ratio);
174
+ }
175
+ }
176
+ for (const listener of registry.resizeListeners)
177
+ listener();
178
+ }
179
+ options.onResize?.(size);
180
+ },
181
+ onColors: (colors) => {
182
+ (0, debug_1.debug)("colors", { background: colors.background });
183
+ if (registry) {
184
+ registry.colors.set(colors);
185
+ const background = registry.background();
186
+ for (const host of registry.hosts())
187
+ void host.setBackground(background);
188
+ if (embedder)
189
+ (0, session_1.broadcastTheme)(embedder, registry.theme());
190
+ }
191
+ options.onColors?.(colors);
192
+ },
193
+ onLayout: (snapshot) => registry?.layout.set(snapshot),
194
+ onHandoff: (next) => {
195
+ handoff = next;
196
+ },
197
+ onHostClosed: () => void ownerLeft(),
198
+ onEngineExit: (error) => {
199
+ if (error)
200
+ process.stderr.write(`pixel engine: ${error}\n`);
201
+ shutdown(error ? 1 : 0);
202
+ },
203
+ });
204
+ (0, offscreen_1.initOffscreenMode)(engineRoot.sharedTextures);
205
+ cellZoom.ratio(engineRoot.info);
206
+ const quit = (entry) => {
207
+ if (options.onQuit)
208
+ options.onQuit(entry?.handle ?? null);
209
+ else
210
+ shutdown(0);
211
+ };
212
+ registry = new registry_1.ViewRegistry(engineRoot, (0, scale_1.hostDisplayScale)(terminal, env), !engineRoot.info.kittyKeyboard, { quit: (entry) => quit(entry) });
213
+ const views = registry;
214
+ embedder = {
215
+ hosts: () => views.hosts(),
216
+ theme: () => views.theme(),
217
+ quit: (host) => quit([...views.views].find((view) => view.host === host) ?? null),
218
+ };
219
+ (0, session_1.installEmbedderApi)(embedder);
220
+ const becomeOwner = () => {
221
+ if (!tty || !socketPath)
222
+ return;
223
+ owner = null;
224
+ server = new server_1.OwnerServer(socketPath, () => ({
225
+ width: engineRoot.info.cellWidth,
226
+ height: engineRoot.info.cellHeight,
227
+ }));
228
+ server.onJoin = (guest) => {
229
+ const focused = views.focused;
230
+ shell.rememberFocus(() => {
231
+ if (focused && views.views.has(focused))
232
+ views.focus(focused);
233
+ });
234
+ guest.onClose = () => shell.remove(guest);
235
+ shell.add(guest);
236
+ };
237
+ record = new instances_1.InstanceRecord({
238
+ tty,
239
+ pid: process.pid,
240
+ socket: socketPath,
241
+ protocol: instances_1.PROTOCOL,
242
+ name,
243
+ title: currentTitle,
244
+ cwd: options.cwd ?? process.cwd(),
245
+ startedAt: Date.now(),
246
+ }, env);
247
+ };
248
+ const ownerLeft = async () => {
249
+ if (stopping)
250
+ return;
251
+ const next = embed ? null : handoff;
252
+ handoff = null;
253
+ try {
254
+ if (next?.tty && socketPath) {
255
+ (0, debug_1.debug)("adopting tty", { tty: next.tty });
256
+ await engineRoot.retarget({ tty: next.tty, wrapper: terminal?.wrapper });
257
+ becomeOwner();
258
+ engineRoot.nudgeResize();
259
+ return;
260
+ }
261
+ if (next?.socket) {
262
+ (0, debug_1.debug)("rejoining", { socket: next.socket });
263
+ await waitForSocket(next.socket);
264
+ await engineRoot.retarget({
265
+ host: { socket: next.socket, pane: (0, node_crypto_1.randomBytes)(8).toString("hex"), name },
266
+ });
267
+ return;
268
+ }
269
+ shutdown(0);
270
+ }
271
+ catch (error) {
272
+ process.stderr.write(`pixel: ${error instanceof Error ? error.message : String(error)}\n`);
273
+ shutdown(1);
274
+ }
275
+ };
276
+ shell.onCloseOwner = () => {
277
+ const successor = shell.successor();
278
+ if (!successor || !tty || !socketPath) {
279
+ quit(null);
280
+ return;
281
+ }
282
+ (0, instances_1.markHandoff)(tty, env);
283
+ successor.send({ type: "adopt", tty });
284
+ for (const other of shell.others(successor))
285
+ other.send({ type: "rejoin", socket: socketPath });
286
+ shutdown(0, () => finishAfterSuccessor(0));
287
+ };
288
+ let currentTitle = null;
289
+ if (owner) {
290
+ (0, debug_1.debug)("joined owner", { tty, owner: owner.name, pid: owner.pid });
291
+ }
292
+ else {
293
+ becomeOwner();
294
+ }
295
+ if (tty && !embed) {
296
+ process.on("SIGWINCH", () => {
297
+ if (!stopping && !owner)
298
+ engineRoot.nudgeResize();
299
+ });
300
+ }
301
+ installSignals();
302
+ const pageRef = (0, react_1.createRef)();
303
+ const loadURL = (url, options = {}) => {
304
+ if (pageRef.current) {
305
+ pageRef.current.loadURL(url);
306
+ return pageRef.current;
307
+ }
308
+ engineRoot.flushSync(() => {
309
+ root.render((0, jsx_runtime_1.jsx)(webview_1.WebView, { ref: pageRef, src: url, style: { width: "100%", height: "100%" }, ...options }));
310
+ });
311
+ if (!pageRef.current)
312
+ throw new Error("[placeholder copy: the page did not mount]");
313
+ return pageRef.current;
314
+ };
315
+ const root = {
316
+ ...engineRoot,
317
+ displayScale: views.displayScale,
318
+ get hosted() {
319
+ return owner != null || embed != null;
320
+ },
321
+ get info() {
322
+ return engineRoot.info;
323
+ },
324
+ render(element) {
325
+ (0, debug_1.debug)("render", { width: engineRoot.info.width, height: engineRoot.info.height });
326
+ engineRoot.render((0, jsx_runtime_1.jsx)(registry_1.RootContext.Provider, { value: views, children: (0, jsx_runtime_1.jsx)(strip_1.PaneShell, { shell: shell, children: element }) }));
327
+ },
328
+ loadURL,
329
+ loadFile: (file, options) => loadURL((0, node_url_1.pathToFileURL)(node_path_1.default.resolve(file)).href, options),
330
+ setTitle(text) {
331
+ currentTitle = text || null;
332
+ engineRoot.setTitle(text);
333
+ record?.setTitle(currentTitle);
334
+ shell.changed();
335
+ },
336
+ stop(code = 0) {
337
+ shutdown(code);
338
+ },
339
+ };
340
+ liveRoots.add(root);
341
+ return root;
342
+ }
@@ -0,0 +1,4 @@
1
+ export declare function sandboxRefusal(): string | null;
2
+ export declare function deniedRefusal(): string | null;
3
+ export declare function linuxSandboxError(electronBinary: string): string | null;
4
+ export declare function apparmorSetup(electronBinary: string): number;