@thenewlabs/entangle-serve 2.12.2 → 2.14.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/daemon-client.d.ts +30 -0
- package/dist/daemon-client.d.ts.map +1 -0
- package/dist/daemon-client.js +76 -0
- package/dist/daemon-client.js.map +1 -0
- package/dist/daemon-server.d.ts +57 -0
- package/dist/daemon-server.d.ts.map +1 -0
- package/dist/daemon-server.js +258 -0
- package/dist/daemon-server.js.map +1 -0
- package/dist/daemon.d.ts +6 -6
- package/dist/daemon.d.ts.map +1 -1
- package/dist/daemon.js +15 -230
- package/dist/daemon.js.map +1 -1
- package/dist/host-session.d.ts +14 -0
- package/dist/host-session.d.ts.map +1 -1
- package/dist/host-session.js +2 -1
- package/dist/host-session.js.map +1 -1
- package/dist/host-terminal.js +86 -6
- package/dist/host-terminal.js.map +1 -1
- package/dist/index.js +44 -67
- package/dist/index.js.map +1 -1
- package/dist/ipc.d.ts +8 -0
- package/dist/ipc.d.ts.map +1 -1
- package/dist/ipc.js.map +1 -1
- package/dist/remote-host-session.d.ts +6 -0
- package/dist/remote-host-session.d.ts.map +1 -1
- package/dist/remote-host-session.js +8 -0
- package/dist/remote-host-session.js.map +1 -1
- package/dist/session-registry.d.ts +22 -0
- package/dist/session-registry.d.ts.map +1 -1
- package/dist/session-registry.js +38 -1
- package/dist/session-registry.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import * as net from 'net';
|
|
2
|
+
import type { OutputHandler } from '@thenewlabs/entangle-utils';
|
|
3
|
+
/** Connect to a unix socket, rejecting on connection error. */
|
|
4
|
+
export declare function connectSocket(path: string): Promise<net.Socket>;
|
|
5
|
+
/**
|
|
6
|
+
* Poll a socket path until it accepts a connection, resolving the connected
|
|
7
|
+
* socket. Rejects with a pointer to `logFile` if it never comes up in time. The
|
|
8
|
+
* socket is left flowing-paused (no 'data' listener) so no daemon frames are
|
|
9
|
+
* lost before the RemoteHostSession attaches its reader.
|
|
10
|
+
*/
|
|
11
|
+
export declare function pollSocket(path: string, logFile: string): Promise<net.Socket>;
|
|
12
|
+
/**
|
|
13
|
+
* Spawn a detached daemon process whose stdout/stderr append to `logFile` and
|
|
14
|
+
* whose config rides entirely in `env`. Returns immediately (the child is
|
|
15
|
+
* unref'd); pair with {@link pollSocket} to wait for its socket.
|
|
16
|
+
*/
|
|
17
|
+
export declare function spawnDetached(opts: {
|
|
18
|
+
entry: string;
|
|
19
|
+
args: string[];
|
|
20
|
+
env: NodeJS.ProcessEnv;
|
|
21
|
+
logFile: string;
|
|
22
|
+
}): void;
|
|
23
|
+
/**
|
|
24
|
+
* Attach this terminal to a daemon over its (already connected) socket: wrap it
|
|
25
|
+
* in a RemoteHostSession sized to the current terminal and hand it to the host
|
|
26
|
+
* UI. host-terminal keeps the process alive and calls process.exit on the
|
|
27
|
+
* session's exit/detach path.
|
|
28
|
+
*/
|
|
29
|
+
export declare function attachToSocket(socket: net.Socket, output: OutputHandler): void;
|
|
30
|
+
//# sourceMappingURL=daemon-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon-client.d.ts","sourceRoot":"","sources":["../src/daemon-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,KAAK,CAAC;AAG3B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAoBhE,+DAA+D;AAC/D,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAO/D;AAED;;;;;GAKG;AACH,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAcnF;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;CACjB,GAAG,IAAI,CASP;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,aAAa,GAAG,IAAI,CAM9E"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import * as net from 'net';
|
|
2
|
+
import * as fs from 'fs';
|
|
3
|
+
import { spawn } from 'child_process';
|
|
4
|
+
import { attachHostTerminal } from './host-terminal.js';
|
|
5
|
+
import { RemoteHostSession } from './remote-host-session.js';
|
|
6
|
+
/**
|
|
7
|
+
* The CLIENT half of the tmux-style detach/reattach split: helpers for spawning
|
|
8
|
+
* a detached session daemon and attaching the current terminal to its unix
|
|
9
|
+
* socket. Extracted from the serve CLI wiring so embedders (Locus's CLI) can
|
|
10
|
+
* compose the same spawn/poll/attach flow around their own daemon entry.
|
|
11
|
+
*/
|
|
12
|
+
/** How long to wait for a freshly spawned daemon's socket to become connectable. */
|
|
13
|
+
const SOCKET_POLL_INTERVAL_MS = 100;
|
|
14
|
+
const SOCKET_POLL_TIMEOUT_MS = 8000;
|
|
15
|
+
/** Resolve after `ms`. */
|
|
16
|
+
function delay(ms) {
|
|
17
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
18
|
+
}
|
|
19
|
+
/** Connect to a unix socket, rejecting on connection error. */
|
|
20
|
+
export function connectSocket(path) {
|
|
21
|
+
return new Promise((resolve, reject) => {
|
|
22
|
+
const socket = net.connect(path);
|
|
23
|
+
const onError = (err) => reject(err);
|
|
24
|
+
socket.once('error', onError);
|
|
25
|
+
socket.once('connect', () => { socket.removeListener('error', onError); resolve(socket); });
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Poll a socket path until it accepts a connection, resolving the connected
|
|
30
|
+
* socket. Rejects with a pointer to `logFile` if it never comes up in time. The
|
|
31
|
+
* socket is left flowing-paused (no 'data' listener) so no daemon frames are
|
|
32
|
+
* lost before the RemoteHostSession attaches its reader.
|
|
33
|
+
*/
|
|
34
|
+
export async function pollSocket(path, logFile) {
|
|
35
|
+
const deadline = Date.now() + SOCKET_POLL_TIMEOUT_MS;
|
|
36
|
+
for (;;) {
|
|
37
|
+
try {
|
|
38
|
+
return await connectSocket(path);
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
if (Date.now() >= deadline) {
|
|
42
|
+
throw new Error(`Session daemon did not come up within ${SOCKET_POLL_TIMEOUT_MS / 1000}s (socket ${path}); see log: ${logFile}`);
|
|
43
|
+
}
|
|
44
|
+
await delay(SOCKET_POLL_INTERVAL_MS);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Spawn a detached daemon process whose stdout/stderr append to `logFile` and
|
|
50
|
+
* whose config rides entirely in `env`. Returns immediately (the child is
|
|
51
|
+
* unref'd); pair with {@link pollSocket} to wait for its socket.
|
|
52
|
+
*/
|
|
53
|
+
export function spawnDetached(opts) {
|
|
54
|
+
const logFd = fs.openSync(opts.logFile, 'a');
|
|
55
|
+
const child = spawn(process.execPath, [opts.entry, ...opts.args], {
|
|
56
|
+
detached: true,
|
|
57
|
+
stdio: ['ignore', logFd, logFd],
|
|
58
|
+
env: opts.env,
|
|
59
|
+
});
|
|
60
|
+
child.unref();
|
|
61
|
+
fs.closeSync(logFd); // the child holds its own fd
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Attach this terminal to a daemon over its (already connected) socket: wrap it
|
|
65
|
+
* in a RemoteHostSession sized to the current terminal and hand it to the host
|
|
66
|
+
* UI. host-terminal keeps the process alive and calls process.exit on the
|
|
67
|
+
* session's exit/detach path.
|
|
68
|
+
*/
|
|
69
|
+
export function attachToSocket(socket, output) {
|
|
70
|
+
const session = new RemoteHostSession(socket, {
|
|
71
|
+
cols: process.stdout.columns || 80,
|
|
72
|
+
rows: process.stdout.rows || 24,
|
|
73
|
+
});
|
|
74
|
+
attachHostTerminal(session, output);
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=daemon-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon-client.js","sourceRoot":"","sources":["../src/daemon-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { OutputHandler } from '@thenewlabs/entangle-utils';
|
|
2
|
+
import type { SharedWorkspace } from './shared-workspace.js';
|
|
3
|
+
import type { LocalHostSession } from './host-session.js';
|
|
4
|
+
/**
|
|
5
|
+
* The reusable socket-server half of a detachable session daemon: everything a
|
|
6
|
+
* daemon does BETWEEN owning a workspace and connecting it to a relay.
|
|
7
|
+
*
|
|
8
|
+
* Extracted from daemon.ts so embedders (Locus's `locus __daemon`) can compose
|
|
9
|
+
* the same detach/reattach machinery around their own boot sequence: it listens
|
|
10
|
+
* on a unix socket where zero or more terminal CLIENTS (RemoteHostSession)
|
|
11
|
+
* attach, fans the session's events out to every attached client, applies each
|
|
12
|
+
* client's input/resize/window ops to the one shared workspace, and keeps the
|
|
13
|
+
* session registry entry current. Detaching a client leaves the daemon (and
|
|
14
|
+
* the session) running.
|
|
15
|
+
*
|
|
16
|
+
* The caller stays responsible for constructing the SharedWorkspace +
|
|
17
|
+
* LocalHostSession, starting the relay agent, and reporting the session URL
|
|
18
|
+
* via {@link DaemonServer.setUrl} once the relay announces it.
|
|
19
|
+
*/
|
|
20
|
+
export interface DaemonServerOptions {
|
|
21
|
+
/** Session name — the registry key and the log/socket basename. */
|
|
22
|
+
name: string;
|
|
23
|
+
/** Absolute path of the unix socket to listen on. */
|
|
24
|
+
socketPath: string;
|
|
25
|
+
workspace: SharedWorkspace;
|
|
26
|
+
session: LocalHostSession;
|
|
27
|
+
output: OutputHandler;
|
|
28
|
+
/** What the registry entry records about this session. */
|
|
29
|
+
registry: {
|
|
30
|
+
capId: string;
|
|
31
|
+
kind: 'entangle' | 'locus';
|
|
32
|
+
workspaceRoot?: string;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Extra async teardown run during shutdown, after the workspace and clients
|
|
36
|
+
* are torn down but before the process exits (Locus: close locusd + remove
|
|
37
|
+
* its pipe sockets). Best-effort: a throw here never blocks the exit.
|
|
38
|
+
*/
|
|
39
|
+
beforeExit?: () => Promise<void> | void;
|
|
40
|
+
/** Install SIGTERM/SIGINT → shutdown handlers (default true; off for tests). */
|
|
41
|
+
installSignalHandlers?: boolean;
|
|
42
|
+
/** Process exit hook (default process.exit; replaced by tests). */
|
|
43
|
+
exit?: (code: number) => void;
|
|
44
|
+
}
|
|
45
|
+
export interface DaemonServer {
|
|
46
|
+
/** Record the session URL: pushes it to attached clients and the registry. */
|
|
47
|
+
setUrl(url: string): void;
|
|
48
|
+
/** Tear the daemon down (idempotent): broadcast exit, deregister, exit(0). */
|
|
49
|
+
shutdown(code: number | null): void;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Listen on `socketPath`, register the session, and serve attach/detach
|
|
53
|
+
* clients over the IPC protocol (ipc.ts). Resolves once the socket is
|
|
54
|
+
* listening and the registry entry is written (url filled in via setUrl).
|
|
55
|
+
*/
|
|
56
|
+
export declare function createDaemonServer(opts: DaemonServerOptions): Promise<DaemonServer>;
|
|
57
|
+
//# sourceMappingURL=daemon-server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon-server.d.ts","sourceRoot":"","sources":["../src/daemon-server.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAW1D;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,mBAAmB;IAClC,mEAAmE;IACnE,IAAI,EAAE,MAAM,CAAC;IACb,qDAAqD;IACrD,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,eAAe,CAAC;IAC3B,OAAO,EAAE,gBAAgB,CAAC;IAC1B,MAAM,EAAE,aAAa,CAAC;IACtB,0DAA0D;IAC1D,QAAQ,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC;QAAC,aAAa,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAChF;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACxC,gFAAgF;IAChF,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,mEAAmE;IACnE,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAC/B;AAED,MAAM,WAAW,YAAY;IAC3B,8EAA8E;IAC9E,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,8EAA8E;IAC9E,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC;CACrC;AAED;;;;GAIG;AACH,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAAC,YAAY,CAAC,CAiNzF"}
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
import * as net from 'net';
|
|
2
|
+
import * as fs from 'fs';
|
|
3
|
+
import { addSession, assertSocketPathUsable, logPath, removeSession } from './session-registry.js';
|
|
4
|
+
import { createMessageReader, decodeChunk, encodeChunk, writeMessage, } from './ipc.js';
|
|
5
|
+
/**
|
|
6
|
+
* Listen on `socketPath`, register the session, and serve attach/detach
|
|
7
|
+
* clients over the IPC protocol (ipc.ts). Resolves once the socket is
|
|
8
|
+
* listening and the registry entry is written (url filled in via setUrl).
|
|
9
|
+
*/
|
|
10
|
+
export async function createDaemonServer(opts) {
|
|
11
|
+
const { name, socketPath: socketPathValue, workspace, session: localSession, output } = opts;
|
|
12
|
+
// Refuse a path bind() would silently truncate — a truncated socket looks
|
|
13
|
+
// dead to every liveness check that stats the full path.
|
|
14
|
+
assertSocketPathUsable(socketPathValue);
|
|
15
|
+
const exit = opts.exit ?? ((code) => process.exit(code));
|
|
16
|
+
const createdAt = Date.now();
|
|
17
|
+
const register = (url) => {
|
|
18
|
+
const info = {
|
|
19
|
+
name,
|
|
20
|
+
socket: socketPathValue,
|
|
21
|
+
logFile: logPath(name),
|
|
22
|
+
pid: process.pid,
|
|
23
|
+
capId: opts.registry.capId,
|
|
24
|
+
url,
|
|
25
|
+
createdAt,
|
|
26
|
+
kind: opts.registry.kind,
|
|
27
|
+
...(opts.registry.workspaceRoot ? { workspaceRoot: opts.registry.workspaceRoot } : {}),
|
|
28
|
+
};
|
|
29
|
+
addSession(info);
|
|
30
|
+
};
|
|
31
|
+
// --- client set + fan-out -------------------------------------------------
|
|
32
|
+
const clients = new Set();
|
|
33
|
+
const broadcast = (msg) => {
|
|
34
|
+
for (const socket of clients) {
|
|
35
|
+
try {
|
|
36
|
+
writeMessage(socket, msg);
|
|
37
|
+
}
|
|
38
|
+
catch { /* dropped client; its close handler cleans up */ }
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
// --- lifecycle / cleanup (idempotent) ------------------------------------
|
|
42
|
+
let server;
|
|
43
|
+
let shuttingDown = false;
|
|
44
|
+
const shutdown = (code) => {
|
|
45
|
+
if (shuttingDown)
|
|
46
|
+
return;
|
|
47
|
+
shuttingDown = true;
|
|
48
|
+
broadcast({ t: 'exit', code });
|
|
49
|
+
try {
|
|
50
|
+
localSession.dispose();
|
|
51
|
+
}
|
|
52
|
+
catch { /* best-effort */ }
|
|
53
|
+
try {
|
|
54
|
+
workspace.kill();
|
|
55
|
+
}
|
|
56
|
+
catch { /* best-effort */ }
|
|
57
|
+
for (const socket of clients) {
|
|
58
|
+
try {
|
|
59
|
+
socket.end();
|
|
60
|
+
}
|
|
61
|
+
catch { /* already gone */ }
|
|
62
|
+
}
|
|
63
|
+
clients.clear();
|
|
64
|
+
try {
|
|
65
|
+
server?.close();
|
|
66
|
+
}
|
|
67
|
+
catch { /* not listening */ }
|
|
68
|
+
removeSession(name);
|
|
69
|
+
try {
|
|
70
|
+
fs.unlinkSync(socketPathValue);
|
|
71
|
+
}
|
|
72
|
+
catch { /* already gone */ }
|
|
73
|
+
// The embedder's teardown may be async (Locus closes locusd); exit after it
|
|
74
|
+
// either way. With no beforeExit this is an immediate exit, as before.
|
|
75
|
+
void (async () => {
|
|
76
|
+
try {
|
|
77
|
+
await opts.beforeExit?.();
|
|
78
|
+
}
|
|
79
|
+
catch { /* best-effort */ }
|
|
80
|
+
exit(0);
|
|
81
|
+
})();
|
|
82
|
+
};
|
|
83
|
+
if (opts.installSignalHandlers !== false) {
|
|
84
|
+
process.on('SIGTERM', () => shutdown(0));
|
|
85
|
+
process.on('SIGINT', () => shutdown(0));
|
|
86
|
+
}
|
|
87
|
+
// Subscribe ONCE to the SESSION-GLOBAL streams and fan each out to every
|
|
88
|
+
// client. Terminal output and window-state are NOT global anymore: each client
|
|
89
|
+
// gets its own workspace viewport (see onConnection) so it can sit on its own
|
|
90
|
+
// active window, so we deliberately do NOT broadcast onHostData/onWindowState.
|
|
91
|
+
localSession.onViewersChange((n) => broadcast({ t: 'viewers', n }));
|
|
92
|
+
localSession.onLog((line) => broadcast({ t: 'log', line }));
|
|
93
|
+
localSession.onUrl((url) => broadcast({ t: 'url', url }));
|
|
94
|
+
// Workspace ended (last window's shell exited) → tear the daemon down.
|
|
95
|
+
localSession.onExit((code) => shutdown(code));
|
|
96
|
+
// --- inbound client handling ---------------------------------------------
|
|
97
|
+
// A client's messages drive ITS OWN workspace viewport (keyed by `vpId`), so
|
|
98
|
+
// input/window ops only move that client's active window. Sizing stays global
|
|
99
|
+
// (the host/workspace size is authoritative), so hello/resize resize the whole
|
|
100
|
+
// workspace as before.
|
|
101
|
+
const handleClientMessage = (msg, socket, vpId) => {
|
|
102
|
+
switch (msg.t) {
|
|
103
|
+
case 'hello':
|
|
104
|
+
workspace.resize(msg.cols, msg.rows);
|
|
105
|
+
break;
|
|
106
|
+
case 'input':
|
|
107
|
+
workspace.writeFromViewport(vpId, decodeChunk(msg.data));
|
|
108
|
+
break;
|
|
109
|
+
case 'resize':
|
|
110
|
+
workspace.resize(msg.cols, msg.rows);
|
|
111
|
+
break;
|
|
112
|
+
case 'win':
|
|
113
|
+
switch (msg.op) {
|
|
114
|
+
case 'new':
|
|
115
|
+
workspace.newWindowForViewport(vpId);
|
|
116
|
+
break;
|
|
117
|
+
case 'next':
|
|
118
|
+
workspace.nextWindowForViewport(vpId);
|
|
119
|
+
break;
|
|
120
|
+
case 'prev':
|
|
121
|
+
workspace.prevWindowForViewport(vpId);
|
|
122
|
+
break;
|
|
123
|
+
case 'select':
|
|
124
|
+
if (msg.index !== undefined)
|
|
125
|
+
workspace.selectWindowForViewport(vpId, msg.index);
|
|
126
|
+
break;
|
|
127
|
+
case 'close':
|
|
128
|
+
if (msg.index !== undefined)
|
|
129
|
+
workspace.closeWindowFromViewport(vpId, msg.index);
|
|
130
|
+
break;
|
|
131
|
+
}
|
|
132
|
+
break;
|
|
133
|
+
case 'refresh':
|
|
134
|
+
// Serialize the viewport's active window NOW and send it back as a
|
|
135
|
+
// `replay` frame (getReplay()'s source client-side). Because this is a
|
|
136
|
+
// full IPC round-trip after the client's own bytes were fed to the
|
|
137
|
+
// emulator, the serialize reflects the window's live screen — this is
|
|
138
|
+
// what lets a host repaint (e.g. after a full-screen app quits) paint
|
|
139
|
+
// the CURRENT primary instead of the stale attach-time cache.
|
|
140
|
+
try {
|
|
141
|
+
const frame = workspace.snapshotForViewport(vpId, msg.scrollback !== undefined ? { scrollback: msg.scrollback } : undefined);
|
|
142
|
+
writeMessage(socket, { t: 'replay', chunk: encodeChunk(frame) });
|
|
143
|
+
}
|
|
144
|
+
catch { /* dropped client; its close handler cleans up */ }
|
|
145
|
+
break;
|
|
146
|
+
case 'scrollback':
|
|
147
|
+
// Serialize the viewport's active window buffer to plain-text lines NOW
|
|
148
|
+
// and send them back for the client's copy-mode pager.
|
|
149
|
+
try {
|
|
150
|
+
writeMessage(socket, { t: 'scrollback', lines: workspace.scrollbackLinesForViewport(vpId) });
|
|
151
|
+
}
|
|
152
|
+
catch { /* dropped client; its close handler cleans up */ }
|
|
153
|
+
break;
|
|
154
|
+
case 'detach':
|
|
155
|
+
// Drop just this client's viewport; the daemon (and session) keep running.
|
|
156
|
+
clients.delete(socket);
|
|
157
|
+
workspace.detachViewport(vpId);
|
|
158
|
+
try {
|
|
159
|
+
socket.end();
|
|
160
|
+
}
|
|
161
|
+
catch { /* already ending */ }
|
|
162
|
+
break;
|
|
163
|
+
case 'kill':
|
|
164
|
+
// End the whole session on a client's request (host UI Ctrl-B q): the
|
|
165
|
+
// exit broadcast inside shutdown() tells every attached client first.
|
|
166
|
+
shutdown(0);
|
|
167
|
+
break;
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
let nextVpId = 0;
|
|
171
|
+
const onConnection = (socket) => {
|
|
172
|
+
// Each connection is its own workspace viewport with an independent active
|
|
173
|
+
// window; reuse the connection counter as the viewport key.
|
|
174
|
+
const vpId = `client-${nextVpId++}`;
|
|
175
|
+
clients.add(socket);
|
|
176
|
+
const remove = () => {
|
|
177
|
+
clients.delete(socket);
|
|
178
|
+
workspace.detachViewport(vpId);
|
|
179
|
+
};
|
|
180
|
+
socket.on('close', remove);
|
|
181
|
+
socket.on('error', remove);
|
|
182
|
+
// Attach this client's viewport: the workspace multiplexes ITS active
|
|
183
|
+
// window's output onto this socket and pushes ITS own window-state.
|
|
184
|
+
const { replay } = workspace.attachViewport({
|
|
185
|
+
sid: vpId,
|
|
186
|
+
onData: (chunk) => { try {
|
|
187
|
+
writeMessage(socket, { t: 'data', chunk: encodeChunk(chunk) });
|
|
188
|
+
}
|
|
189
|
+
catch { /* dropped */ } },
|
|
190
|
+
onWindowState: (state) => { try {
|
|
191
|
+
writeMessage(socket, { t: 'window-state', state });
|
|
192
|
+
}
|
|
193
|
+
catch { /* dropped */ } },
|
|
194
|
+
onExit: (code) => { try {
|
|
195
|
+
writeMessage(socket, { t: 'exit', code });
|
|
196
|
+
}
|
|
197
|
+
catch { /* dropped */ } },
|
|
198
|
+
});
|
|
199
|
+
createMessageReader(socket, (msg) => {
|
|
200
|
+
// Only ClientToDaemon frames are expected inbound; a single bad message
|
|
201
|
+
// must not take down the daemon.
|
|
202
|
+
try {
|
|
203
|
+
handleClientMessage(msg, socket, vpId);
|
|
204
|
+
}
|
|
205
|
+
catch (err) {
|
|
206
|
+
output.warn('Client message failed', err instanceof Error ? err.message : String(err));
|
|
207
|
+
}
|
|
208
|
+
}, () => { remove(); try {
|
|
209
|
+
socket.destroy();
|
|
210
|
+
}
|
|
211
|
+
catch { /* already gone */ } });
|
|
212
|
+
// Push this viewport's current state immediately so the client's UI
|
|
213
|
+
// populates fast. Sent synchronously (no await) right after attach, so live
|
|
214
|
+
// onData frames can't slip in before the replay.
|
|
215
|
+
try {
|
|
216
|
+
const url = localSession.getUrl();
|
|
217
|
+
if (url)
|
|
218
|
+
writeMessage(socket, { t: 'url', url });
|
|
219
|
+
writeMessage(socket, { t: 'window-state', state: workspace.windowStateForViewport(vpId) });
|
|
220
|
+
writeMessage(socket, { t: 'viewers', n: workspace.viewerCount() });
|
|
221
|
+
for (const line of localSession.getLogBuffer())
|
|
222
|
+
writeMessage(socket, { t: 'log', line });
|
|
223
|
+
writeMessage(socket, { t: 'replay', chunk: encodeChunk(replay) });
|
|
224
|
+
}
|
|
225
|
+
catch {
|
|
226
|
+
remove();
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
// --- listen ---------------------------------------------------------------
|
|
230
|
+
try {
|
|
231
|
+
fs.unlinkSync(socketPathValue);
|
|
232
|
+
}
|
|
233
|
+
catch { /* no stale socket to remove */ }
|
|
234
|
+
server = net.createServer(onConnection);
|
|
235
|
+
server.on('error', (err) => output.error('Daemon socket server error', err.message));
|
|
236
|
+
await new Promise((resolve, reject) => {
|
|
237
|
+
const onError = (err) => reject(err);
|
|
238
|
+
server.once('error', onError);
|
|
239
|
+
server.listen(socketPathValue, () => {
|
|
240
|
+
server.off('error', onError);
|
|
241
|
+
resolve();
|
|
242
|
+
});
|
|
243
|
+
});
|
|
244
|
+
try {
|
|
245
|
+
fs.chmodSync(socketPathValue, 0o600);
|
|
246
|
+
}
|
|
247
|
+
catch { /* best-effort tightening */ }
|
|
248
|
+
// Register now (url filled in via setUrl once the relay assigns it).
|
|
249
|
+
register('');
|
|
250
|
+
return {
|
|
251
|
+
setUrl(url) {
|
|
252
|
+
localSession.setUrl(url);
|
|
253
|
+
register(url);
|
|
254
|
+
},
|
|
255
|
+
shutdown,
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
//# sourceMappingURL=daemon-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon-server.js","sourceRoot":"","sources":["../src/daemon-server.ts"],"names":[],"mappings":"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"}
|
package/dist/daemon.d.ts
CHANGED
|
@@ -3,12 +3,12 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Runs headless (no TTY): it owns a {@link SharedWorkspace} + {@link LocalHostSession}
|
|
5
5
|
* and connects to the relay via {@link startAgent}, serving the pinned capability
|
|
6
|
-
* handed to it.
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* running; the daemon exits only when the workspace's last
|
|
11
|
-
* signalled.
|
|
6
|
+
* handed to it. The socket server that terminal CLIENTS ({@link RemoteHostSession})
|
|
7
|
+
* attach to — fan-out, per-client viewports, registry bookkeeping, shutdown — lives
|
|
8
|
+
* in daemon-server.ts (shared with embedders like Locus); this file is just the
|
|
9
|
+
* entangle-specific composition around it. Detaching a client leaves the daemon
|
|
10
|
+
* (and the session) running; the daemon exits only when the workspace's last
|
|
11
|
+
* shell exits or it is signalled.
|
|
12
12
|
*
|
|
13
13
|
* Config comes entirely from the environment (set by the index wiring that spawns
|
|
14
14
|
* the daemon):
|
package/dist/daemon.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../src/daemon.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../src/daemon.ts"],"names":[],"mappings":"AAOA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CAkC/C"}
|