@thenewlabs/entangle-serve 2.2.1 → 2.4.0

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.
@@ -0,0 +1,128 @@
1
+ import { OutputHandler } from '@thenewlabs/entangle-utils';
2
+ import type { WindowStateBody } from '@thenewlabs/entangle-protocol';
3
+ /**
4
+ * A client's viewport onto the shared workspace.
5
+ *
6
+ * Each client keeps ONE pty stream (the sid from STREAM_OPEN); the workspace
7
+ * multiplexes the ACTIVE window's output onto it via {@link onData}, repaints it
8
+ * on a window switch (also via {@link onData}: a clear + the new window's
9
+ * replay), and pushes the current {@link WindowStateBody} to it via
10
+ * {@link onWindowState} on every change. `onExit` fires only when the workspace
11
+ * as a whole ends (its last window exits) — closing a non-last window just
12
+ * repaints, it does not end the viewport.
13
+ */
14
+ export interface Viewport {
15
+ sid: string;
16
+ onData: (chunk: Uint8Array) => void;
17
+ onExit: (code: number | null, signal: string | null) => void;
18
+ onWindowState: (state: WindowStateBody) => void;
19
+ }
20
+ /**
21
+ * A shared, tmux-style workspace of windows synced across every attached client.
22
+ *
23
+ * The workspace holds N windows, each its own {@link SharedSession} PTY; every
24
+ * window keeps running in the background but only the ONE global active window's
25
+ * output is streamed to clients' viewports and to the host terminal. Client
26
+ * keystrokes go to the active window; the host terminal size is authoritative
27
+ * and every window is sized to it.
28
+ *
29
+ * The host terminal binds to a workspace exactly as it used to bind to a single
30
+ * SharedSession — {@link onHostData}, {@link onViewersChange}, {@link onExit},
31
+ * {@link resize}, {@link write}, {@link getReplay}, {@link viewerCount} — so a
32
+ * single-window workspace behaves identically to the old shared terminal.
33
+ */
34
+ export declare class SharedWorkspace {
35
+ private output;
36
+ private windows;
37
+ private activeIndex;
38
+ private viewports;
39
+ private exited;
40
+ private readonly cwd?;
41
+ private readonly maxReplayBytes?;
42
+ private readonly maxWindows;
43
+ private hostDataCb?;
44
+ private exitCb?;
45
+ private viewersChangedCb?;
46
+ private hostWindowStateCb?;
47
+ cols: number;
48
+ rows: number;
49
+ constructor(output: OutputHandler, opts: {
50
+ cols: number;
51
+ rows: number;
52
+ cwd?: string;
53
+ maxReplayBytes?: number;
54
+ maxWindows?: number;
55
+ });
56
+ /** Register the host's local rendering callback for the active window. */
57
+ onHostData(cb: (chunk: Buffer) => void): void;
58
+ /** Register a callback fired once when the workspace ends (last window exits). */
59
+ onExit(cb: (code: number | null, signal: string | null) => void): void;
60
+ /** Register a callback fired whenever the attached-viewport count changes. */
61
+ onViewersChange(cb: (count: number) => void): void;
62
+ /**
63
+ * Register a host callback fired whenever the window set changes — create,
64
+ * close, switch, or rename. Lets the host render its own tab bar in-process
65
+ * (the analogue of the {@link Viewport.onWindowState} push sent to clients).
66
+ * Fires with the current {@link windowState}.
67
+ */
68
+ onWindowState(cb: (state: WindowStateBody) => void): void;
69
+ get hasExited(): boolean;
70
+ /** Merge input (from the host) into the ACTIVE window. */
71
+ write(data: Uint8Array | string): void;
72
+ /** Resize the workspace (host is authoritative) — every window is sized to it. */
73
+ resize(cols: number, rows: number): void;
74
+ /** Recent-output snapshot of the ACTIVE window (host's initial paint). */
75
+ getReplay(): Uint8Array;
76
+ /** Number of attached client viewports. */
77
+ viewerCount(): number;
78
+ /** Kill every window (which drives the workspace to exit). */
79
+ kill(): void;
80
+ /**
81
+ * Attach a client viewport. Returns the current active-window replay so the
82
+ * caller can send it as the viewport's initial output. The caller should then
83
+ * send the current {@link windowState} so the client's tab bar populates.
84
+ */
85
+ attachViewport(v: Viewport): {
86
+ replay: Uint8Array;
87
+ };
88
+ /** Detach a client viewport (disconnect / stream close). */
89
+ detachViewport(sid: string): void;
90
+ /** Route a viewport's keystrokes to the ACTIVE window. */
91
+ writeFromViewport(sid: string, data: Uint8Array | string): void;
92
+ /** Create a new window and switch to it. */
93
+ newWindow(): void;
94
+ /** Switch the global active window to `index` (no-op if out of range/current). */
95
+ selectWindow(index: number): void;
96
+ /** Switch to the next window (wraps). */
97
+ nextWindow(): void;
98
+ /** Switch to the previous window (wraps). */
99
+ prevWindow(): void;
100
+ /**
101
+ * Close the window at `index`. Killing its PTY drives the shared exit path,
102
+ * which removes the window, re-homes the active index, and broadcasts. Closing
103
+ * the last window ends the whole workspace.
104
+ */
105
+ closeWindow(index: number): void;
106
+ /** Rename the window at `index` and broadcast the change. */
107
+ renameWindow(index: number, title: string): void;
108
+ /** Current window state (the `msg` body of a window-state frame). */
109
+ windowState(): WindowStateBody;
110
+ private spawnWindow;
111
+ /**
112
+ * Tap the active window's output and fan it out to the host + every viewport.
113
+ * Only the active window is tapped; background windows keep running silently.
114
+ */
115
+ private bindActiveOutput;
116
+ /**
117
+ * Switch the active window: detach the old window's output tap, tap the new
118
+ * one, and repaint the host + every viewport (clear + new window's replay).
119
+ * Does NOT broadcast window-state — callers pair this with broadcastWindowState.
120
+ */
121
+ private setActive;
122
+ /** Repaint the host + every viewport with a clear + the active window's replay. */
123
+ private repaintAll;
124
+ /** Notify the host + every attached client of the current window-state. */
125
+ broadcastWindowState(): void;
126
+ private handleWindowExit;
127
+ }
128
+ //# sourceMappingURL=shared-workspace.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared-workspace.d.ts","sourceRoot":"","sources":["../src/shared-workspace.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,295 @@
1
+ import { SharedSession } from './shared-session.js';
2
+ /** Screen clear + home used to repaint a viewport/host on a window switch. */
3
+ const CLEAR = Buffer.from('\x1b[2J\x1b[3J\x1b[H', 'utf8');
4
+ /** Hard cap on concurrent windows so a client can't spawn unbounded shells. */
5
+ const DEFAULT_MAX_WINDOWS = 16;
6
+ /**
7
+ * A shared, tmux-style workspace of windows synced across every attached client.
8
+ *
9
+ * The workspace holds N windows, each its own {@link SharedSession} PTY; every
10
+ * window keeps running in the background but only the ONE global active window's
11
+ * output is streamed to clients' viewports and to the host terminal. Client
12
+ * keystrokes go to the active window; the host terminal size is authoritative
13
+ * and every window is sized to it.
14
+ *
15
+ * The host terminal binds to a workspace exactly as it used to bind to a single
16
+ * SharedSession — {@link onHostData}, {@link onViewersChange}, {@link onExit},
17
+ * {@link resize}, {@link write}, {@link getReplay}, {@link viewerCount} — so a
18
+ * single-window workspace behaves identically to the old shared terminal.
19
+ */
20
+ export class SharedWorkspace {
21
+ output;
22
+ windows = [];
23
+ activeIndex = 0;
24
+ viewports = new Map();
25
+ exited = false;
26
+ cwd;
27
+ maxReplayBytes;
28
+ maxWindows;
29
+ hostDataCb;
30
+ exitCb;
31
+ viewersChangedCb;
32
+ hostWindowStateCb;
33
+ cols;
34
+ rows;
35
+ constructor(output, opts) {
36
+ this.output = output;
37
+ this.cols = Math.max(1, opts.cols);
38
+ this.rows = Math.max(1, opts.rows);
39
+ if (opts.cwd !== undefined)
40
+ this.cwd = opts.cwd;
41
+ if (opts.maxReplayBytes !== undefined)
42
+ this.maxReplayBytes = opts.maxReplayBytes;
43
+ this.maxWindows = opts.maxWindows ?? DEFAULT_MAX_WINDOWS;
44
+ // Start with a single window so the existing single-shell behavior is
45
+ // preserved when nobody ever creates a second one.
46
+ const first = this.spawnWindow();
47
+ this.windows.push(first);
48
+ this.activeIndex = 0;
49
+ this.bindActiveOutput();
50
+ this.output.info(`Shared workspace started: 1 window, cols=${this.cols}, rows=${this.rows}`);
51
+ }
52
+ // --- host-facing API (mirrors the old SharedSession surface) -------------
53
+ /** Register the host's local rendering callback for the active window. */
54
+ onHostData(cb) { this.hostDataCb = cb; }
55
+ /** Register a callback fired once when the workspace ends (last window exits). */
56
+ onExit(cb) { this.exitCb = cb; }
57
+ /** Register a callback fired whenever the attached-viewport count changes. */
58
+ onViewersChange(cb) { this.viewersChangedCb = cb; }
59
+ /**
60
+ * Register a host callback fired whenever the window set changes — create,
61
+ * close, switch, or rename. Lets the host render its own tab bar in-process
62
+ * (the analogue of the {@link Viewport.onWindowState} push sent to clients).
63
+ * Fires with the current {@link windowState}.
64
+ */
65
+ onWindowState(cb) { this.hostWindowStateCb = cb; }
66
+ get hasExited() { return this.exited; }
67
+ /** Merge input (from the host) into the ACTIVE window. */
68
+ write(data) {
69
+ if (this.exited)
70
+ return;
71
+ this.windows[this.activeIndex]?.write(data);
72
+ }
73
+ /** Resize the workspace (host is authoritative) — every window is sized to it. */
74
+ resize(cols, rows) {
75
+ if (this.exited || cols < 1 || rows < 1)
76
+ return;
77
+ this.cols = cols;
78
+ this.rows = rows;
79
+ for (const w of this.windows)
80
+ w.resize(cols, rows);
81
+ }
82
+ /** Recent-output snapshot of the ACTIVE window (host's initial paint). */
83
+ getReplay() {
84
+ return this.windows[this.activeIndex]?.getReplay() ?? new Uint8Array(0);
85
+ }
86
+ /** Number of attached client viewports. */
87
+ viewerCount() { return this.viewports.size; }
88
+ /** Kill every window (which drives the workspace to exit). */
89
+ kill() {
90
+ for (const w of this.windows) {
91
+ try {
92
+ w.kill();
93
+ }
94
+ catch { }
95
+ }
96
+ }
97
+ // --- viewport-facing API (clients) ---------------------------------------
98
+ /**
99
+ * Attach a client viewport. Returns the current active-window replay so the
100
+ * caller can send it as the viewport's initial output. The caller should then
101
+ * send the current {@link windowState} so the client's tab bar populates.
102
+ */
103
+ attachViewport(v) {
104
+ this.viewports.set(v.sid, v);
105
+ this.output.info(`Viewport attached: ${v.sid} (${this.viewports.size} total)`);
106
+ this.viewersChangedCb?.(this.viewports.size);
107
+ return { replay: this.getReplay() };
108
+ }
109
+ /** Detach a client viewport (disconnect / stream close). */
110
+ detachViewport(sid) {
111
+ if (this.viewports.delete(sid)) {
112
+ this.output.info(`Viewport detached: ${sid} (${this.viewports.size} remaining)`);
113
+ this.viewersChangedCb?.(this.viewports.size);
114
+ }
115
+ }
116
+ /** Route a viewport's keystrokes to the ACTIVE window. */
117
+ writeFromViewport(sid, data) {
118
+ if (this.exited || !this.viewports.has(sid))
119
+ return;
120
+ this.windows[this.activeIndex]?.write(data);
121
+ }
122
+ // --- window operations (WINDOW_CTL client->server) -----------------------
123
+ /** Create a new window and switch to it. */
124
+ newWindow() {
125
+ if (this.exited)
126
+ return;
127
+ if (this.windows.length >= this.maxWindows) {
128
+ this.output.warn(`Window cap reached (${this.maxWindows}); ignoring new-window`);
129
+ return;
130
+ }
131
+ const win = this.spawnWindow();
132
+ this.windows.push(win);
133
+ this.setActive(this.windows.length - 1);
134
+ this.broadcastWindowState();
135
+ }
136
+ /** Switch the global active window to `index` (no-op if out of range/current). */
137
+ selectWindow(index) {
138
+ if (this.exited)
139
+ return;
140
+ if (index < 0 || index >= this.windows.length || index === this.activeIndex)
141
+ return;
142
+ this.setActive(index);
143
+ this.broadcastWindowState();
144
+ }
145
+ /** Switch to the next window (wraps). */
146
+ nextWindow() {
147
+ if (this.windows.length < 2)
148
+ return;
149
+ this.selectWindow((this.activeIndex + 1) % this.windows.length);
150
+ }
151
+ /** Switch to the previous window (wraps). */
152
+ prevWindow() {
153
+ if (this.windows.length < 2)
154
+ return;
155
+ this.selectWindow((this.activeIndex - 1 + this.windows.length) % this.windows.length);
156
+ }
157
+ /**
158
+ * Close the window at `index`. Killing its PTY drives the shared exit path,
159
+ * which removes the window, re-homes the active index, and broadcasts. Closing
160
+ * the last window ends the whole workspace.
161
+ */
162
+ closeWindow(index) {
163
+ if (this.exited)
164
+ return;
165
+ if (index < 0 || index >= this.windows.length)
166
+ return;
167
+ try {
168
+ this.windows[index].kill();
169
+ }
170
+ catch { }
171
+ }
172
+ /** Rename the window at `index` and broadcast the change. */
173
+ renameWindow(index, title) {
174
+ if (this.exited)
175
+ return;
176
+ const win = this.windows[index];
177
+ if (!win)
178
+ return;
179
+ win.title = title;
180
+ this.broadcastWindowState();
181
+ }
182
+ /** Current window state (the `msg` body of a window-state frame). */
183
+ windowState() {
184
+ const windows = this.windows.map((w) => ({ id: w.id, title: w.title }));
185
+ return { v: 1, kind: 'window-state', windows, activeIndex: this.activeIndex };
186
+ }
187
+ // --- internals -----------------------------------------------------------
188
+ spawnWindow() {
189
+ const win = new SharedSession(this.output, {
190
+ cols: this.cols,
191
+ rows: this.rows,
192
+ ...(this.cwd !== undefined ? { cwd: this.cwd } : {}),
193
+ ...(this.maxReplayBytes !== undefined ? { maxReplayBytes: this.maxReplayBytes } : {}),
194
+ });
195
+ win.onExit((code, signal) => this.handleWindowExit(win, code, signal));
196
+ return win;
197
+ }
198
+ /**
199
+ * Tap the active window's output and fan it out to the host + every viewport.
200
+ * Only the active window is tapped; background windows keep running silently.
201
+ */
202
+ bindActiveOutput() {
203
+ const active = this.windows[this.activeIndex];
204
+ if (!active)
205
+ return;
206
+ active.onHostData((chunk) => {
207
+ this.hostDataCb?.(chunk);
208
+ if (this.viewports.size === 0)
209
+ return;
210
+ const bytes = new Uint8Array(chunk);
211
+ for (const v of this.viewports.values()) {
212
+ try {
213
+ v.onData(bytes);
214
+ }
215
+ catch { }
216
+ }
217
+ });
218
+ }
219
+ /**
220
+ * Switch the active window: detach the old window's output tap, tap the new
221
+ * one, and repaint the host + every viewport (clear + new window's replay).
222
+ * Does NOT broadcast window-state — callers pair this with broadcastWindowState.
223
+ */
224
+ setActive(index) {
225
+ const prev = this.windows[this.activeIndex];
226
+ if (prev)
227
+ prev.onHostData(() => { }); // stop tapping the now-background window
228
+ this.activeIndex = index;
229
+ this.bindActiveOutput();
230
+ this.repaintAll();
231
+ }
232
+ /** Repaint the host + every viewport with a clear + the active window's replay. */
233
+ repaintAll() {
234
+ const active = this.windows[this.activeIndex];
235
+ if (!active)
236
+ return;
237
+ const payload = Buffer.concat([CLEAR, Buffer.from(active.getReplay())]);
238
+ this.hostDataCb?.(payload);
239
+ if (this.viewports.size > 0) {
240
+ const bytes = new Uint8Array(payload);
241
+ for (const v of this.viewports.values()) {
242
+ try {
243
+ v.onData(bytes);
244
+ }
245
+ catch { }
246
+ }
247
+ }
248
+ }
249
+ /** Notify the host + every attached client of the current window-state. */
250
+ broadcastWindowState() {
251
+ const state = this.windowState();
252
+ this.hostWindowStateCb?.(state);
253
+ if (this.viewports.size === 0)
254
+ return;
255
+ for (const v of this.viewports.values()) {
256
+ try {
257
+ v.onWindowState(state);
258
+ }
259
+ catch { }
260
+ }
261
+ }
262
+ handleWindowExit(win, code, signal) {
263
+ const idx = this.windows.indexOf(win);
264
+ if (idx === -1)
265
+ return;
266
+ const wasActive = idx === this.activeIndex;
267
+ this.windows.splice(idx, 1);
268
+ // Last window gone: the whole workspace ends. Tell every viewport and the
269
+ // host so the client streams and host process wind down.
270
+ if (this.windows.length === 0) {
271
+ this.exited = true;
272
+ for (const v of this.viewports.values()) {
273
+ try {
274
+ v.onExit(code, signal);
275
+ }
276
+ catch { }
277
+ }
278
+ this.viewports.clear();
279
+ this.exitCb?.(code, signal);
280
+ return;
281
+ }
282
+ if (wasActive) {
283
+ // Re-home the active index onto a surviving neighbor and repaint everyone.
284
+ this.activeIndex = Math.min(idx, this.windows.length - 1);
285
+ this.bindActiveOutput();
286
+ this.repaintAll();
287
+ }
288
+ else if (idx < this.activeIndex) {
289
+ // A window before the active one vanished; keep pointing at the same window.
290
+ this.activeIndex -= 1;
291
+ }
292
+ this.broadcastWindowState();
293
+ }
294
+ }
295
+ //# sourceMappingURL=shared-workspace.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared-workspace.js","sourceRoot":"","sources":["../src/shared-workspace.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ export declare class VtGrid {
2
+ cols: number;
3
+ rows: number;
4
+ cursorX: number;
5
+ cursorY: number;
6
+ private grid;
7
+ private sgr;
8
+ private savedX;
9
+ private savedY;
10
+ private pending;
11
+ constructor(cols: number, rows: number);
12
+ private blankGrid;
13
+ /** Resize, preserving as much top-left content as fits. */
14
+ resize(cols: number, rows: number): void;
15
+ write(data: string): void;
16
+ private handleEscape;
17
+ private handleCsi;
18
+ private applySgr;
19
+ private handleControlOrPrintable;
20
+ private lineFeed;
21
+ private reverseLineFeed;
22
+ private scrollUp;
23
+ private scrollDown;
24
+ private insertLines;
25
+ private deleteLines;
26
+ private deleteChars;
27
+ private insertBlanks;
28
+ private eraseDisplay;
29
+ private eraseLine;
30
+ private clampX;
31
+ private clampY;
32
+ /**
33
+ * Render each row as a styled string exactly `cols` wide, with SGR runs
34
+ * reconstructed and a reset at both ends so a row never bleeds style into the
35
+ * box frame.
36
+ */
37
+ renderRows(): string[];
38
+ /** Plain-text rows (no SGR) — handy for assertions/tests. */
39
+ renderPlainRows(): string[];
40
+ }
41
+ //# sourceMappingURL=vt-grid.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vt-grid.d.ts","sourceRoot":"","sources":["../src/vt-grid.ts"],"names":[],"mappings":"AAmBA,qBAAa,MAAM;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,SAAK;IACZ,OAAO,SAAK;IACZ,OAAO,CAAC,IAAI,CAAW;IACvB,OAAO,CAAC,GAAG,CAAM;IACjB,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,OAAO,CAAM;gBAET,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;IAMtC,OAAO,CAAC,SAAS;IAMjB,2DAA2D;IAC3D,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAgBxC,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAqBzB,OAAO,CAAC,YAAY;IAqCpB,OAAO,CAAC,SAAS;IAiCjB,OAAO,CAAC,QAAQ;IAQhB,OAAO,CAAC,wBAAwB;IAiBhC,OAAO,CAAC,QAAQ;IAKhB,OAAO,CAAC,eAAe;IAKvB,OAAO,CAAC,QAAQ;IAKhB,OAAO,CAAC,UAAU;IAKlB,OAAO,CAAC,WAAW;IAOnB,OAAO,CAAC,WAAW;IAOnB,OAAO,CAAC,WAAW;IAMnB,OAAO,CAAC,YAAY;IAMpB,OAAO,CAAC,YAAY;IAcpB,OAAO,CAAC,SAAS;IAOjB,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,MAAM;IAEd;;;;OAIG;IACH,UAAU,IAAI,MAAM,EAAE;IAgBtB,6DAA6D;IAC7D,eAAe,IAAI,MAAM,EAAE;CAG5B"}