@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.
- package/dist/agent.d.ts +7 -0
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +9 -1
- package/dist/agent.js.map +1 -1
- package/dist/box-renderer.d.ts +52 -0
- package/dist/box-renderer.d.ts.map +1 -0
- package/dist/box-renderer.js +138 -0
- package/dist/box-renderer.js.map +1 -0
- package/dist/host-terminal.d.ts +23 -0
- package/dist/host-terminal.d.ts.map +1 -0
- package/dist/host-terminal.js +217 -0
- package/dist/host-terminal.js.map +1 -0
- package/dist/index.js +31 -0
- package/dist/index.js.map +1 -1
- package/dist/multi-session.d.ts +3 -0
- package/dist/multi-session.d.ts.map +1 -1
- package/dist/multi-session.js +143 -1
- package/dist/multi-session.js.map +1 -1
- package/dist/session.d.ts +3 -1
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +6 -1
- package/dist/session.js.map +1 -1
- package/dist/shared-session.d.ts +78 -0
- package/dist/shared-session.d.ts.map +1 -0
- package/dist/shared-session.js +146 -0
- package/dist/shared-session.js.map +1 -0
- package/dist/shared-workspace.d.ts +128 -0
- package/dist/shared-workspace.d.ts.map +1 -0
- package/dist/shared-workspace.js +295 -0
- package/dist/shared-workspace.js.map +1 -0
- package/dist/vt-grid.d.ts +41 -0
- package/dist/vt-grid.d.ts.map +1 -0
- package/dist/vt-grid.js +311 -0
- package/dist/vt-grid.js.map +1 -0
- package/package.json +4 -4
|
@@ -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":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAC3D,OAAO,KAAK,EAAc,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAGjF;;;;;;;;;;GAUG;AACH,MAAM,WAAW,QAAQ;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;IACpC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IAC7D,aAAa,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,CAAC;CACjD;AAQD;;;;;;;;;;;;;GAaG;AACH,qBAAa,eAAe;IAmBxB,OAAO,CAAC,MAAM;IAlBhB,OAAO,CAAC,OAAO,CAAuB;IACtC,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,SAAS,CAA+B;IAChD,OAAO,CAAC,MAAM,CAAS;IAEvB,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IAEpC,OAAO,CAAC,UAAU,CAAC,CAA0B;IAC7C,OAAO,CAAC,MAAM,CAAC,CAAuD;IACtE,OAAO,CAAC,gBAAgB,CAAC,CAA0B;IACnD,OAAO,CAAC,iBAAiB,CAAC,CAAmC;IAEtD,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;gBAGV,MAAM,EAAE,aAAa,EAC7B,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE;IAoBlG,0EAA0E;IAC1E,UAAU,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI;IAE7C,kFAAkF;IAClF,MAAM,CAAC,EAAE,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,GAAG,IAAI;IAEtE,8EAA8E;IAC9E,eAAe,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI;IAElD;;;;;OAKG;IACH,aAAa,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,GAAG,IAAI;IAEzD,IAAI,SAAS,IAAI,OAAO,CAAwB;IAEhD,0DAA0D;IAC1D,KAAK,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,GAAG,IAAI;IAKtC,kFAAkF;IAClF,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAOxC,0EAA0E;IAC1E,SAAS,IAAI,UAAU;IAIvB,2CAA2C;IAC3C,WAAW,IAAI,MAAM;IAErB,8DAA8D;IAC9D,IAAI,IAAI,IAAI;IAQZ;;;;OAIG;IACH,cAAc,CAAC,CAAC,EAAE,QAAQ,GAAG;QAAE,MAAM,EAAE,UAAU,CAAA;KAAE;IAOnD,4DAA4D;IAC5D,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAOjC,0DAA0D;IAC1D,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,MAAM,GAAG,IAAI;IAO/D,4CAA4C;IAC5C,SAAS,IAAI,IAAI;IAYjB,kFAAkF;IAClF,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAOjC,yCAAyC;IACzC,UAAU,IAAI,IAAI;IAKlB,6CAA6C;IAC7C,UAAU,IAAI,IAAI;IAKlB;;;;OAIG;IACH,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAMhC,6DAA6D;IAC7D,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAQhD,qEAAqE;IACrE,WAAW,IAAI,eAAe;IAO9B,OAAO,CAAC,WAAW;IAWnB;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IAaxB;;;;OAIG;IACH,OAAO,CAAC,SAAS;IAQjB,mFAAmF;IACnF,OAAO,CAAC,UAAU;IAalB,2EAA2E;IAC3E,oBAAoB,IAAI,IAAI;IAS5B,OAAO,CAAC,gBAAgB;CA6BzB"}
|
|
@@ -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"}
|