@kdonev/termscape 0.1.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/LICENSE +21 -0
- package/README.md +288 -0
- package/dist/agents/env.d.ts +36 -0
- package/dist/agents/env.d.ts.map +1 -0
- package/dist/agents/env.js +61 -0
- package/dist/agents/env.js.map +1 -0
- package/dist/agents/profiles.d.ts +45 -0
- package/dist/agents/profiles.d.ts.map +1 -0
- package/dist/agents/profiles.js +123 -0
- package/dist/agents/profiles.js.map +1 -0
- package/dist/agents/resolve.d.ts +16 -0
- package/dist/agents/resolve.d.ts.map +1 -0
- package/dist/agents/resolve.js +71 -0
- package/dist/agents/resolve.js.map +1 -0
- package/dist/agents/router.d.ts +29 -0
- package/dist/agents/router.d.ts.map +1 -0
- package/dist/agents/router.js +83 -0
- package/dist/agents/router.js.map +1 -0
- package/dist/agents/tokens.d.ts +21 -0
- package/dist/agents/tokens.d.ts.map +1 -0
- package/dist/agents/tokens.js +39 -0
- package/dist/agents/tokens.js.map +1 -0
- package/dist/agents/wiring.d.ts +30 -0
- package/dist/agents/wiring.d.ts.map +1 -0
- package/dist/agents/wiring.js +110 -0
- package/dist/agents/wiring.js.map +1 -0
- package/dist/browser.d.ts +13 -0
- package/dist/browser.d.ts.map +1 -0
- package/dist/browser.js +34 -0
- package/dist/browser.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +200 -0
- package/dist/cli.js.map +1 -0
- package/dist/db/index.d.ts +14 -0
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +24 -0
- package/dist/db/index.js.map +1 -0
- package/dist/db/migrations.d.ts +15 -0
- package/dist/db/migrations.d.ts.map +1 -0
- package/dist/db/migrations.js +176 -0
- package/dist/db/migrations.js.map +1 -0
- package/dist/db/store.d.ts +71 -0
- package/dist/db/store.d.ts.map +1 -0
- package/dist/db/store.js +341 -0
- package/dist/db/store.js.map +1 -0
- package/dist/hub.d.ts +188 -0
- package/dist/hub.d.ts.map +1 -0
- package/dist/hub.js +636 -0
- package/dist/hub.js.map +1 -0
- package/dist/hub.tgz +0 -0
- package/dist/mcp/server.d.ts +31 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +66 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/paths.d.ts +27 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +31 -0
- package/dist/paths.js.map +1 -0
- package/dist/protocol/address.d.ts +15 -0
- package/dist/protocol/address.d.ts.map +1 -0
- package/dist/protocol/address.js +39 -0
- package/dist/protocol/address.js.map +1 -0
- package/dist/protocol/domain.d.ts +151 -0
- package/dist/protocol/domain.d.ts.map +1 -0
- package/dist/protocol/domain.js +104 -0
- package/dist/protocol/domain.js.map +1 -0
- package/dist/protocol/index.d.ts +7 -0
- package/dist/protocol/index.d.ts.map +1 -0
- package/dist/protocol/index.js +7 -0
- package/dist/protocol/index.js.map +1 -0
- package/dist/protocol/inject.d.ts +29 -0
- package/dist/protocol/inject.d.ts.map +1 -0
- package/dist/protocol/inject.js +40 -0
- package/dist/protocol/inject.js.map +1 -0
- package/dist/protocol/mcp-tools.d.ts +45 -0
- package/dist/protocol/mcp-tools.d.ts.map +1 -0
- package/dist/protocol/mcp-tools.js +46 -0
- package/dist/protocol/mcp-tools.js.map +1 -0
- package/dist/protocol/peer.d.ts +304 -0
- package/dist/protocol/peer.d.ts.map +1 -0
- package/dist/protocol/peer.js +183 -0
- package/dist/protocol/peer.js.map +1 -0
- package/dist/protocol/ws.d.ts +416 -0
- package/dist/protocol/ws.d.ts.map +1 -0
- package/dist/protocol/ws.js +119 -0
- package/dist/protocol/ws.js.map +1 -0
- package/dist/remote/deployer.d.ts +78 -0
- package/dist/remote/deployer.d.ts.map +1 -0
- package/dist/remote/deployer.js +216 -0
- package/dist/remote/deployer.js.map +1 -0
- package/dist/remote/enroll.d.ts +14 -0
- package/dist/remote/enroll.d.ts.map +1 -0
- package/dist/remote/enroll.js +244 -0
- package/dist/remote/enroll.js.map +1 -0
- package/dist/remote/join-script.d.ts +29 -0
- package/dist/remote/join-script.d.ts.map +1 -0
- package/dist/remote/join-script.js +709 -0
- package/dist/remote/join-script.js.map +1 -0
- package/dist/remote/join.d.ts +19 -0
- package/dist/remote/join.d.ts.map +1 -0
- package/dist/remote/join.js +195 -0
- package/dist/remote/join.js.map +1 -0
- package/dist/remote/lan.d.ts +45 -0
- package/dist/remote/lan.d.ts.map +1 -0
- package/dist/remote/lan.js +105 -0
- package/dist/remote/lan.js.map +1 -0
- package/dist/remote/peer-serve.d.ts +27 -0
- package/dist/remote/peer-serve.d.ts.map +1 -0
- package/dist/remote/peer-serve.js +274 -0
- package/dist/remote/peer-serve.js.map +1 -0
- package/dist/remote/peer.d.ts +62 -0
- package/dist/remote/peer.d.ts.map +1 -0
- package/dist/remote/peer.js +250 -0
- package/dist/remote/peer.js.map +1 -0
- package/dist/remote/registry.d.ts +104 -0
- package/dist/remote/registry.d.ts.map +1 -0
- package/dist/remote/registry.js +359 -0
- package/dist/remote/registry.js.map +1 -0
- package/dist/remote/tarball.d.ts +9 -0
- package/dist/remote/tarball.d.ts.map +1 -0
- package/dist/remote/tarball.js +22 -0
- package/dist/remote/tarball.js.map +1 -0
- package/dist/server.d.ts +54 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +438 -0
- package/dist/server.js.map +1 -0
- package/dist/session/manager.d.ts +104 -0
- package/dist/session/manager.d.ts.map +1 -0
- package/dist/session/manager.js +421 -0
- package/dist/session/manager.js.map +1 -0
- package/dist/session/pty.d.ts +114 -0
- package/dist/session/pty.d.ts.map +1 -0
- package/dist/session/pty.js +300 -0
- package/dist/session/pty.js.map +1 -0
- package/package.json +49 -0
- package/web/assets/index-B2JtCtHa.css +1 -0
- package/web/assets/index-BOqZOoep.js +107 -0
- package/web/index.html +13 -0
package/dist/server.js
ADDED
|
@@ -0,0 +1,438 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
|
+
import { dirname, join, sep } from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import Fastify from 'fastify';
|
|
6
|
+
import websocket from '@fastify/websocket';
|
|
7
|
+
import fastifyStatic from '@fastify/static';
|
|
8
|
+
import { ClientMsg, BinaryFrameKind, decodeBinaryFrame, encodeBinaryFrame, } from './protocol/index.js';
|
|
9
|
+
import { HUB_VERSION } from './hub.js';
|
|
10
|
+
import { createPeerServer } from './remote/peer-serve.js';
|
|
11
|
+
import { registerEnrollment } from './remote/enroll.js';
|
|
12
|
+
import { advertisedHost, coversLoopback, preferredHostname, urlHost, } from './remote/lan.js';
|
|
13
|
+
import { buildMcpServer, buildMcpTransport } from './mcp/server.js';
|
|
14
|
+
/**
|
|
15
|
+
* Ports to try before falling back to whatever the OS hands out.
|
|
16
|
+
*
|
|
17
|
+
* The join page is the one URL someone has to type by hand, on a different
|
|
18
|
+
* machine, from memory — it carries no token precisely so it can be typed. A
|
|
19
|
+
* five-digit ephemeral port makes that miserable, so prefer something a person
|
|
20
|
+
* can hold in their head.
|
|
21
|
+
*
|
|
22
|
+
* Ordered by memorability, skipping ports that common dev tooling squats on:
|
|
23
|
+
* 3000/8000/8080 (everything), 5555 (adb), 8888 (Jupyter), 2222 (alt ssh).
|
|
24
|
+
*/
|
|
25
|
+
export const MEMORABLE_PORTS = [7777, 4242, 7333, 3333, 9999, 7070, 4040, 1212];
|
|
26
|
+
/**
|
|
27
|
+
* Locate the built web assets relative to this file, if they exist.
|
|
28
|
+
*
|
|
29
|
+
* Two layouts have to work. In the monorepo the hub runs from
|
|
30
|
+
* `packages/hub/dist/` and the UI is its sibling at `packages/web/dist`. In the
|
|
31
|
+
* published package there are no siblings: the UI is copied to `web/` beside
|
|
32
|
+
* `dist/`, because npm ships one package and a relative walk out of it would
|
|
33
|
+
* land in whatever the user happens to have installed next door.
|
|
34
|
+
*/
|
|
35
|
+
function webRoot() {
|
|
36
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
37
|
+
const candidates = [
|
|
38
|
+
// Published layout: <pkg>/dist/server.js -> <pkg>/web
|
|
39
|
+
join(here, '..', 'web'),
|
|
40
|
+
join(here, '..', '..', 'web', 'dist'),
|
|
41
|
+
join(here, '..', '..', '..', 'web', 'dist'),
|
|
42
|
+
];
|
|
43
|
+
return candidates.find((p) => existsSync(p)) ?? null;
|
|
44
|
+
}
|
|
45
|
+
export async function serve(opts) {
|
|
46
|
+
const { hub, clientToken } = opts;
|
|
47
|
+
const app = Fastify({ logger: false });
|
|
48
|
+
await app.register(websocket, {
|
|
49
|
+
options: { maxPayload: 8 * 1024 * 1024 },
|
|
50
|
+
});
|
|
51
|
+
/* ------------------------------------------------------------- health */
|
|
52
|
+
app.get('/health', async () => ({
|
|
53
|
+
ok: true,
|
|
54
|
+
hubVersion: HUB_VERSION,
|
|
55
|
+
pid: process.pid,
|
|
56
|
+
}));
|
|
57
|
+
/* -------------------------------------------------------------- hooks */
|
|
58
|
+
/**
|
|
59
|
+
* Agent CLIs POST here at turn boundaries. The path carries the agent's own
|
|
60
|
+
* bearer token, which is also how we know which window changed state.
|
|
61
|
+
*/
|
|
62
|
+
app.post('/hook/:token', async (req, reply) => {
|
|
63
|
+
const sessionId = hub.tokens.resolve(req.params.token);
|
|
64
|
+
if (!sessionId)
|
|
65
|
+
return reply.code(404).send({ ok: false });
|
|
66
|
+
const event = req.query.event === 'idle' ? 'idle' : 'busy';
|
|
67
|
+
hub.sessions.setStatusFromHook(sessionId, event);
|
|
68
|
+
return { ok: true };
|
|
69
|
+
});
|
|
70
|
+
/* ---------------------------------------------------------------- MCP */
|
|
71
|
+
app.all('/mcp', async (req, reply) => {
|
|
72
|
+
const auth = req.headers.authorization ?? '';
|
|
73
|
+
const token = auth.startsWith('Bearer ') ? auth.slice(7) : '';
|
|
74
|
+
const sessionId = token ? hub.tokens.resolve(token) : null;
|
|
75
|
+
if (!sessionId) {
|
|
76
|
+
return reply.code(401).send({
|
|
77
|
+
jsonrpc: '2.0',
|
|
78
|
+
error: { code: -32001, message: 'unauthorized' },
|
|
79
|
+
id: null,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
// Stateless: a fresh server + transport per request, bound to this caller.
|
|
83
|
+
const server = buildMcpServer(sessionId, hub);
|
|
84
|
+
const transport = buildMcpTransport();
|
|
85
|
+
reply.raw.on('close', () => {
|
|
86
|
+
void transport.close();
|
|
87
|
+
void server.close();
|
|
88
|
+
});
|
|
89
|
+
await server.connect(transport);
|
|
90
|
+
await transport.handleRequest(req.raw, reply.raw, req.body);
|
|
91
|
+
return reply;
|
|
92
|
+
});
|
|
93
|
+
/* --------------------------------------------------------- peer (hub↔hub) */
|
|
94
|
+
/**
|
|
95
|
+
* The answering half of the hub-to-hub link. A hub deployed over SSH serves
|
|
96
|
+
* this and the canvas-owning hub dials it through the tunnel, so on that
|
|
97
|
+
* path the endpoint is only ever reachable over loopback on the remote
|
|
98
|
+
* machine. The logic lives in peer-serve.ts because a hub that enrolled
|
|
99
|
+
* itself runs the identical thing over a socket it dialled out instead.
|
|
100
|
+
*/
|
|
101
|
+
const peerServer = createPeerServer(hub, clientToken);
|
|
102
|
+
// It is also this hub's link back to whatever canvas it was attached to.
|
|
103
|
+
// On a hub that owns its own canvas nothing ever attaches, and the uplink
|
|
104
|
+
// reports itself as detached forever.
|
|
105
|
+
hub.setUplink(peerServer);
|
|
106
|
+
app.get('/peer', { websocket: true }, (socket) => {
|
|
107
|
+
peerServer.serve(socket);
|
|
108
|
+
});
|
|
109
|
+
/* --------------------------------------------------------------- join */
|
|
110
|
+
// The bind address is not known until listen() resolves, so the enroll
|
|
111
|
+
// routes read it through a closure rather than a captured value.
|
|
112
|
+
let enrollOrigin = null;
|
|
113
|
+
let enrollAltOrigin = null;
|
|
114
|
+
const enrollment = registerEnrollment(app, { hub, enrollOrigin: () => enrollOrigin });
|
|
115
|
+
/* ---------------------------------------------------------- WebSocket */
|
|
116
|
+
const clients = new Set();
|
|
117
|
+
const send = (ws, msg) => {
|
|
118
|
+
if (ws.readyState === ws.OPEN)
|
|
119
|
+
ws.send(JSON.stringify(msg));
|
|
120
|
+
};
|
|
121
|
+
const broadcast = (msg) => {
|
|
122
|
+
for (const ws of clients)
|
|
123
|
+
send(ws, msg);
|
|
124
|
+
};
|
|
125
|
+
const snapshotState = () => ({
|
|
126
|
+
hubVersion: HUB_VERSION,
|
|
127
|
+
enrollUrl: enrollOrigin ? `${enrollOrigin}/join` : null,
|
|
128
|
+
enrollAltUrl: enrollAltOrigin ? `${enrollAltOrigin}/join` : null,
|
|
129
|
+
hosts: hub.store.listHosts(),
|
|
130
|
+
workspaces: hub.store.listWorkspaces(),
|
|
131
|
+
sessions: hub.allSessions(),
|
|
132
|
+
messages: hub.messages(),
|
|
133
|
+
viewport: hub.store.getViewport(),
|
|
134
|
+
profiles: hub.profiles.list().map((p) => ({
|
|
135
|
+
id: p.id,
|
|
136
|
+
description: p.description,
|
|
137
|
+
mcp: p.mcp,
|
|
138
|
+
resumable: !!p.resumeArgs,
|
|
139
|
+
})),
|
|
140
|
+
});
|
|
141
|
+
hub.on('session', (s) => broadcast({ t: 'sessionUpserted', session: s }));
|
|
142
|
+
hub.on('removed', (id) => broadcast({ t: 'sessionRemoved', sessionId: id }));
|
|
143
|
+
hub.on('workspace', (w) => broadcast({ t: 'workspaceUpserted', workspace: w }));
|
|
144
|
+
hub.on('workspaceRemoved', (id) => broadcast({ t: 'workspaceRemoved', workspaceId: id }));
|
|
145
|
+
hub.on('message', (m) => broadcast({ t: 'messageSent', message: m }));
|
|
146
|
+
hub.on('host', (h) => broadcast({ t: 'hostUpserted', host: h }));
|
|
147
|
+
hub.on('hostRemoved', (id) => broadcast({ t: 'hostRemoved', hostId: id }));
|
|
148
|
+
// Deploy progress. Installing on a remote can take minutes; the panel shows
|
|
149
|
+
// these lines so it is not a frozen button.
|
|
150
|
+
hub.on('hostLog', (hostId, line) => broadcast({ t: 'hostLog', hostId, line }));
|
|
151
|
+
// A peer connecting, dropping, or resyncing changes many sessions at
|
|
152
|
+
// once, so push the whole list rather than diffing it here.
|
|
153
|
+
hub.on('peersChanged', () => {
|
|
154
|
+
for (const s of hub.peers.sessions())
|
|
155
|
+
broadcast({ t: 'sessionUpserted', session: s });
|
|
156
|
+
});
|
|
157
|
+
// Terminal output goes only to clients that have attached to that window,
|
|
158
|
+
// so a canvas showing 20 terminals zoomed out is not paying for 20 streams.
|
|
159
|
+
const attached = new Map();
|
|
160
|
+
hub.on('data', (sessionId, chunk) => {
|
|
161
|
+
const frame = encodeBinaryFrame(BinaryFrameKind.PtyOutput, sessionId, Buffer.from(chunk, 'utf8'));
|
|
162
|
+
for (const ws of clients) {
|
|
163
|
+
if (attached.get(ws)?.has(sessionId) && ws.readyState === ws.OPEN)
|
|
164
|
+
ws.send(frame);
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
app.get('/ws', { websocket: true }, (socket) => {
|
|
168
|
+
let authed = false;
|
|
169
|
+
clients.add(socket);
|
|
170
|
+
attached.set(socket, new Set());
|
|
171
|
+
socket.on('message', (raw, isBinary) => {
|
|
172
|
+
try {
|
|
173
|
+
if (isBinary) {
|
|
174
|
+
if (!authed)
|
|
175
|
+
return;
|
|
176
|
+
const f = decodeBinaryFrame(new Uint8Array(raw));
|
|
177
|
+
if (f.kind === BinaryFrameKind.PtyInput) {
|
|
178
|
+
const data = Buffer.from(f.payload).toString('utf8');
|
|
179
|
+
const remote = hub.peers.find(f.sessionId);
|
|
180
|
+
if (remote) {
|
|
181
|
+
// Typing into a remote terminal whose PTY has since exited is
|
|
182
|
+
// ordinary, and the peer says so by rejecting. Unhandled, that
|
|
183
|
+
// rejection reaches the process and takes the whole canvas with
|
|
184
|
+
// it — so it is reported to this browser and goes no further.
|
|
185
|
+
void remote.peer
|
|
186
|
+
.request({ t: 'input', id: randomUUID(), address: f.sessionId, data })
|
|
187
|
+
.catch((e) => send(socket, { t: 'error', message: e.message, sessionId: f.sessionId }));
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
hub.sessions.write(f.sessionId, data);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
const parsed = ClientMsg.safeParse(JSON.parse(raw.toString('utf8')));
|
|
196
|
+
if (!parsed.success) {
|
|
197
|
+
send(socket, { t: 'error', message: 'malformed message' });
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
const msg = parsed.data;
|
|
201
|
+
if (!authed) {
|
|
202
|
+
if (msg.t !== 'hello' || msg.token !== clientToken) {
|
|
203
|
+
send(socket, { t: 'error', message: 'unauthorized' });
|
|
204
|
+
socket.close();
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
authed = true;
|
|
208
|
+
send(socket, { t: 'ready', state: snapshotState() });
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
void handleClientMsg(socket, msg);
|
|
212
|
+
}
|
|
213
|
+
catch (err) {
|
|
214
|
+
send(socket, { t: 'error', message: err.message });
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
socket.on('close', () => {
|
|
218
|
+
clients.delete(socket);
|
|
219
|
+
attached.delete(socket);
|
|
220
|
+
});
|
|
221
|
+
});
|
|
222
|
+
async function handleClientMsg(socket, msg) {
|
|
223
|
+
try {
|
|
224
|
+
switch (msg.t) {
|
|
225
|
+
case 'hello':
|
|
226
|
+
return;
|
|
227
|
+
// Remote sessions are keyed by their address, so a single lookup
|
|
228
|
+
// decides whether a request is served locally or forwarded to a peer.
|
|
229
|
+
case 'attach': {
|
|
230
|
+
attached.get(socket)?.add(msg.sessionId);
|
|
231
|
+
const remote = hub.peers.find(msg.sessionId);
|
|
232
|
+
if (remote) {
|
|
233
|
+
await remote.peer.attach(msg.sessionId);
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
const snap = hub.sessions.snapshotForAttach(msg.sessionId);
|
|
237
|
+
if (snap) {
|
|
238
|
+
send(socket, {
|
|
239
|
+
t: 'snapshot',
|
|
240
|
+
sessionId: msg.sessionId,
|
|
241
|
+
serialized: snap.serialized,
|
|
242
|
+
cols: snap.cols,
|
|
243
|
+
rows: snap.rows,
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
case 'detach': {
|
|
249
|
+
attached.get(socket)?.delete(msg.sessionId);
|
|
250
|
+
const remote = hub.peers.find(msg.sessionId);
|
|
251
|
+
if (remote)
|
|
252
|
+
await remote.peer.detach(msg.sessionId);
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
case 'resize': {
|
|
256
|
+
const remote = hub.peers.find(msg.sessionId);
|
|
257
|
+
if (remote) {
|
|
258
|
+
await remote.peer.request({
|
|
259
|
+
t: 'resize',
|
|
260
|
+
id: randomUUID(),
|
|
261
|
+
address: msg.sessionId,
|
|
262
|
+
cols: msg.cols,
|
|
263
|
+
rows: msg.rows,
|
|
264
|
+
});
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
hub.sessions.resize(msg.sessionId, msg.cols, msg.rows);
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
case 'createWorkspace':
|
|
271
|
+
hub.createWorkspace(msg.name, msg.rootPath, msg.hostId ?? null);
|
|
272
|
+
return;
|
|
273
|
+
case 'removeWorkspace':
|
|
274
|
+
await hub.removeWorkspace(msg.workspaceId);
|
|
275
|
+
return;
|
|
276
|
+
case 'startSession':
|
|
277
|
+
await hub.startSession({
|
|
278
|
+
workspaceId: msg.workspaceId,
|
|
279
|
+
profile: msg.profile,
|
|
280
|
+
name: msg.name,
|
|
281
|
+
cwd: msg.cwd,
|
|
282
|
+
});
|
|
283
|
+
return;
|
|
284
|
+
case 'stopSession': {
|
|
285
|
+
const remote = hub.peers.find(msg.sessionId);
|
|
286
|
+
if (remote) {
|
|
287
|
+
await remote.peer.request({ t: 'stopSession', id: randomUUID(), address: msg.sessionId });
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
hub.sessions.stop(msg.sessionId);
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
case 'removeSession':
|
|
294
|
+
// A remote window's session belongs to its peer. Removing it here
|
|
295
|
+
// would delete nothing and merely hide the window until that peer
|
|
296
|
+
// reported it again.
|
|
297
|
+
if (await hub.peers.removeSession(msg.sessionId))
|
|
298
|
+
return;
|
|
299
|
+
hub.sessions.remove(msg.sessionId);
|
|
300
|
+
return;
|
|
301
|
+
case 'resumeSession': {
|
|
302
|
+
const remote = hub.peers.find(msg.sessionId);
|
|
303
|
+
if (remote) {
|
|
304
|
+
await remote.peer.request({ t: 'resumeSession', id: randomUUID(), address: msg.sessionId });
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
await hub.sessions.resume(msg.sessionId);
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
case 'resumeWorkspace':
|
|
311
|
+
await hub.resumeWorkspace(msg.workspaceId);
|
|
312
|
+
return;
|
|
313
|
+
case 'moveWindow':
|
|
314
|
+
// Layout is always local, even for a peer's session.
|
|
315
|
+
if (!hub.peers.saveLayout(msg.sessionId, msg.rect)) {
|
|
316
|
+
hub.moveWindow(msg.sessionId, msg.rect);
|
|
317
|
+
}
|
|
318
|
+
return;
|
|
319
|
+
case 'setViewport':
|
|
320
|
+
hub.setViewport(msg.viewport);
|
|
321
|
+
return;
|
|
322
|
+
case 'addHost': {
|
|
323
|
+
const host = hub.addHost(msg);
|
|
324
|
+
// Connect immediately: adding a host the user then has to connect
|
|
325
|
+
// by hand is a pointless second step.
|
|
326
|
+
void hub.connectHost(host.id).catch((e) => send(socket, { t: 'error', message: `connect ${host.label}: ${e.message}` }));
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
case 'removeHost':
|
|
330
|
+
await hub.removeHost(msg.hostId);
|
|
331
|
+
return;
|
|
332
|
+
case 'connectHost':
|
|
333
|
+
await hub.connectHost(msg.hostId);
|
|
334
|
+
return;
|
|
335
|
+
default:
|
|
336
|
+
send(socket, { t: 'error', message: `unhandled: ${msg.t}` });
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
catch (err) {
|
|
340
|
+
send(socket, { t: 'error', message: err.message });
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
/* ------------------------------------------------------------- static */
|
|
344
|
+
if (!opts.headless) {
|
|
345
|
+
const root = webRoot();
|
|
346
|
+
if (root) {
|
|
347
|
+
await app.register(fastifyStatic, {
|
|
348
|
+
root,
|
|
349
|
+
wildcard: false,
|
|
350
|
+
// Asset filenames are content-hashed by vite, so they may be cached
|
|
351
|
+
// forever. index.html must NOT be: a cached copy points at the
|
|
352
|
+
// previous build's hashed bundle, which now 404s, leaving a blank
|
|
353
|
+
// page that only a manual hard-reload fixes.
|
|
354
|
+
setHeaders: (res, filePath) => {
|
|
355
|
+
const immutable = filePath.includes(`${sep}assets${sep}`);
|
|
356
|
+
res.header('cache-control', immutable ? 'public, max-age=31536000, immutable' : 'no-cache');
|
|
357
|
+
},
|
|
358
|
+
});
|
|
359
|
+
// SPA fallback, but only for navigations. Serving index.html for a
|
|
360
|
+
// missing /assets/*.js turns a cache-stale asset into a confusing MIME
|
|
361
|
+
// type error instead of an honest 404, so anything that looks like a
|
|
362
|
+
// file must 404 as a file.
|
|
363
|
+
app.setNotFoundHandler((req, reply) => {
|
|
364
|
+
const url = (req.raw.url ?? '/').split('?')[0];
|
|
365
|
+
const looksLikeFile = /\.[a-z0-9]+$/i.test(url);
|
|
366
|
+
const isApi = url.startsWith('/mcp') || url.startsWith('/hook') || url.startsWith('/ws');
|
|
367
|
+
if (looksLikeFile || isApi) {
|
|
368
|
+
return reply.code(404).send({ error: 'not found', path: url });
|
|
369
|
+
}
|
|
370
|
+
return reply.sendFile('index.html');
|
|
371
|
+
});
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
/* ----------------------------------------------------------- shutdown */
|
|
375
|
+
/**
|
|
376
|
+
* Fastify's close() waits for open connections to drain, and a WebSocket
|
|
377
|
+
* never drains on its own — an idle browser tab or a connected peer would
|
|
378
|
+
* hang shutdown indefinitely. Terminate them explicitly instead.
|
|
379
|
+
*/
|
|
380
|
+
app.addHook('onClose', async () => {
|
|
381
|
+
for (const ws of clients) {
|
|
382
|
+
try {
|
|
383
|
+
ws.terminate();
|
|
384
|
+
}
|
|
385
|
+
catch {
|
|
386
|
+
// Already gone.
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
peerServer.closeAll();
|
|
390
|
+
clients.clear();
|
|
391
|
+
attached.clear();
|
|
392
|
+
});
|
|
393
|
+
/* --------------------------------------------------------------- bind */
|
|
394
|
+
// Loopback unless the operator asked otherwise. An SSH-deployed hub is
|
|
395
|
+
// always reached through its tunnel and never binds wider; `--listen` exists
|
|
396
|
+
// so a machine can fetch the join page and enroll itself.
|
|
397
|
+
const host = opts.host ?? '127.0.0.1';
|
|
398
|
+
const address = await listenOnFirstFree(app, host, opts.port ?? 0);
|
|
399
|
+
const port = app.server.address().port;
|
|
400
|
+
// Agents' MCP endpoint stays on loopback whenever the bind answers there,
|
|
401
|
+
// which for `--listen lan` it does: that binds the wildcard precisely so
|
|
402
|
+
// this stays true.
|
|
403
|
+
const origin = `http://${coversLoopback(host) ? '127.0.0.1' : urlHost(host)}:${port}`;
|
|
404
|
+
hub.setOrigin(origin);
|
|
405
|
+
const advertised = advertisedHost(host);
|
|
406
|
+
if (advertised) {
|
|
407
|
+
// Prefer this machine's name: it is the URL someone has to carry to
|
|
408
|
+
// another machine and type in. The IP stays available underneath.
|
|
409
|
+
const name = await preferredHostname(advertised);
|
|
410
|
+
enrollOrigin = `http://${name ?? advertised}:${port}`;
|
|
411
|
+
enrollAltOrigin = name ? `http://${advertised}:${port}` : null;
|
|
412
|
+
}
|
|
413
|
+
void address;
|
|
414
|
+
return { app, origin, enrollOrigin, enrollAltOrigin, port, peerServer, enrollment };
|
|
415
|
+
}
|
|
416
|
+
/**
|
|
417
|
+
* Bind the first candidate that is free.
|
|
418
|
+
*
|
|
419
|
+
* A probe-then-bind would race, so this just tries to bind for real and moves
|
|
420
|
+
* on when the port is taken. The last resort is `0` — an unmemorable port
|
|
421
|
+
* still beats refusing to start.
|
|
422
|
+
*/
|
|
423
|
+
async function listenOnFirstFree(app, host, port) {
|
|
424
|
+
const candidates = Array.isArray(port) ? [...port, 0] : [port];
|
|
425
|
+
for (let i = 0; i < candidates.length; i++) {
|
|
426
|
+
try {
|
|
427
|
+
return await app.listen({ host, port: candidates[i] });
|
|
428
|
+
}
|
|
429
|
+
catch (err) {
|
|
430
|
+
const code = err.code;
|
|
431
|
+
const inUse = code === 'EADDRINUSE' || code === 'EACCES';
|
|
432
|
+
if (!inUse || i === candidates.length - 1)
|
|
433
|
+
throw err;
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
throw new Error('no port available');
|
|
437
|
+
}
|
|
438
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { EventEmitter } from 'node:events';
|
|
2
|
+
import { type Session, type WindowRect } from '../protocol/index.js';
|
|
3
|
+
import { Store } from '../db/store.js';
|
|
4
|
+
import { ProfileRegistry } from '../agents/profiles.js';
|
|
5
|
+
import { TokenRegistry } from '../agents/tokens.js';
|
|
6
|
+
import { PtySession } from './pty.js';
|
|
7
|
+
/** Debounce for persisting window geometry while a window is being dragged. */
|
|
8
|
+
export declare const LAYOUT_DEBOUNCE_MS = 250;
|
|
9
|
+
export interface StartOptions {
|
|
10
|
+
workspaceId: string;
|
|
11
|
+
profileId: string;
|
|
12
|
+
name?: string;
|
|
13
|
+
cwd?: string;
|
|
14
|
+
spawnedBy?: string | null;
|
|
15
|
+
cols?: number;
|
|
16
|
+
rows?: number;
|
|
17
|
+
window?: WindowRect;
|
|
18
|
+
}
|
|
19
|
+
export interface ManagerEvents {
|
|
20
|
+
session: (s: Session) => void;
|
|
21
|
+
/**
|
|
22
|
+
* The address travels with the id: after the delete there is nothing left
|
|
23
|
+
* to look it up from, and peers address sessions by name.
|
|
24
|
+
*/
|
|
25
|
+
removed: (sessionId: string, address: string | null) => void;
|
|
26
|
+
data: (sessionId: string, chunk: string) => void;
|
|
27
|
+
exit: (sessionId: string, code: number) => void;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Owns every PTY on this hub, plus the persistence of their state.
|
|
31
|
+
*
|
|
32
|
+
* The invariant worth stating: SQLite always holds enough to redraw the canvas
|
|
33
|
+
* and relaunch each agent. Live objects here are a cache over that, never the
|
|
34
|
+
* other way round.
|
|
35
|
+
*/
|
|
36
|
+
export declare class SessionManager extends EventEmitter {
|
|
37
|
+
private readonly store;
|
|
38
|
+
private readonly profiles;
|
|
39
|
+
readonly tokens: TokenRegistry;
|
|
40
|
+
private hubOrigin;
|
|
41
|
+
private readonly live;
|
|
42
|
+
private readonly snapshotTimers;
|
|
43
|
+
private readonly layoutTimers;
|
|
44
|
+
/** Latest title per session, waiting for the coalescing window to close. */
|
|
45
|
+
private readonly pendingTitles;
|
|
46
|
+
private titleTimer;
|
|
47
|
+
constructor(store: Store, profiles: ProfileRegistry, tokens: TokenRegistry, hubOrigin: string);
|
|
48
|
+
setHubOrigin(origin: string): void;
|
|
49
|
+
private isResumable;
|
|
50
|
+
list(): Session[];
|
|
51
|
+
get(id: string): Session | null;
|
|
52
|
+
getByAddress(address: string): Session | null;
|
|
53
|
+
/** Overlay live runtime status onto the persisted row. */
|
|
54
|
+
private decorate;
|
|
55
|
+
pty(id: string): PtySession | null;
|
|
56
|
+
/** Build the resolved argv/env for a launch. `resume` swaps in --resume. */
|
|
57
|
+
private buildSpec;
|
|
58
|
+
private peersOf;
|
|
59
|
+
start(opts: StartOptions): Promise<Session>;
|
|
60
|
+
/** Bring a stopped session back, reusing its recorded argv and cwd. */
|
|
61
|
+
resume(sessionId: string): Promise<Session>;
|
|
62
|
+
private spawn;
|
|
63
|
+
write(sessionId: string, data: string): void;
|
|
64
|
+
resize(sessionId: string, cols: number, rows: number): void;
|
|
65
|
+
setStatusText(sessionId: string, text: string): void;
|
|
66
|
+
/**
|
|
67
|
+
* A title the program in the PTY set for itself.
|
|
68
|
+
*
|
|
69
|
+
* An agent rewrites this as it works, several times a second, so the write
|
|
70
|
+
* and the broadcast are held to the last value in a window rather than one
|
|
71
|
+
* apiece. Unrefed: a pending title is never a reason to keep the process up.
|
|
72
|
+
*/
|
|
73
|
+
private noteTitle;
|
|
74
|
+
/** Called by the hooks endpoint: exact turn boundaries from the agent CLI. */
|
|
75
|
+
setStatusFromHook(sessionId: string, status: 'busy' | 'idle'): void;
|
|
76
|
+
stop(sessionId: string): void;
|
|
77
|
+
remove(sessionId: string): void;
|
|
78
|
+
private scheduleSnapshot;
|
|
79
|
+
/** Screen only — the deliberate cost of the snapshot-only design. */
|
|
80
|
+
persistSnapshot(sessionId: string): void;
|
|
81
|
+
persistAllSnapshots(): void;
|
|
82
|
+
snapshotForAttach(sessionId: string): {
|
|
83
|
+
serialized: string;
|
|
84
|
+
cols: number;
|
|
85
|
+
rows: number;
|
|
86
|
+
} | null;
|
|
87
|
+
moveWindow(sessionId: string, rect: WindowRect): void;
|
|
88
|
+
/**
|
|
89
|
+
* Place a new window: tucked below-right of its parent when spawned by
|
|
90
|
+
* another agent, otherwise in the next free slot of a simple grid.
|
|
91
|
+
*/
|
|
92
|
+
private placeWindow;
|
|
93
|
+
/** Workspaces are laid out left to right so their groups do not overlap. */
|
|
94
|
+
private workspaceOriginX;
|
|
95
|
+
private clearTimer;
|
|
96
|
+
private emitSession;
|
|
97
|
+
/**
|
|
98
|
+
* Startup reconciliation. Sessions cannot outlive the hub, so anything the
|
|
99
|
+
* DB still calls running is stale and is marked stopped, ready to resume.
|
|
100
|
+
*/
|
|
101
|
+
reconcileOnBoot(): void;
|
|
102
|
+
shutdown(): void;
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/session/manager.ts"],"names":[],"mappings":"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"}
|