@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.
Files changed (139) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +288 -0
  3. package/dist/agents/env.d.ts +36 -0
  4. package/dist/agents/env.d.ts.map +1 -0
  5. package/dist/agents/env.js +61 -0
  6. package/dist/agents/env.js.map +1 -0
  7. package/dist/agents/profiles.d.ts +45 -0
  8. package/dist/agents/profiles.d.ts.map +1 -0
  9. package/dist/agents/profiles.js +123 -0
  10. package/dist/agents/profiles.js.map +1 -0
  11. package/dist/agents/resolve.d.ts +16 -0
  12. package/dist/agents/resolve.d.ts.map +1 -0
  13. package/dist/agents/resolve.js +71 -0
  14. package/dist/agents/resolve.js.map +1 -0
  15. package/dist/agents/router.d.ts +29 -0
  16. package/dist/agents/router.d.ts.map +1 -0
  17. package/dist/agents/router.js +83 -0
  18. package/dist/agents/router.js.map +1 -0
  19. package/dist/agents/tokens.d.ts +21 -0
  20. package/dist/agents/tokens.d.ts.map +1 -0
  21. package/dist/agents/tokens.js +39 -0
  22. package/dist/agents/tokens.js.map +1 -0
  23. package/dist/agents/wiring.d.ts +30 -0
  24. package/dist/agents/wiring.d.ts.map +1 -0
  25. package/dist/agents/wiring.js +110 -0
  26. package/dist/agents/wiring.js.map +1 -0
  27. package/dist/browser.d.ts +13 -0
  28. package/dist/browser.d.ts.map +1 -0
  29. package/dist/browser.js +34 -0
  30. package/dist/browser.js.map +1 -0
  31. package/dist/cli.d.ts +3 -0
  32. package/dist/cli.d.ts.map +1 -0
  33. package/dist/cli.js +200 -0
  34. package/dist/cli.js.map +1 -0
  35. package/dist/db/index.d.ts +14 -0
  36. package/dist/db/index.d.ts.map +1 -0
  37. package/dist/db/index.js +24 -0
  38. package/dist/db/index.js.map +1 -0
  39. package/dist/db/migrations.d.ts +15 -0
  40. package/dist/db/migrations.d.ts.map +1 -0
  41. package/dist/db/migrations.js +176 -0
  42. package/dist/db/migrations.js.map +1 -0
  43. package/dist/db/store.d.ts +71 -0
  44. package/dist/db/store.d.ts.map +1 -0
  45. package/dist/db/store.js +341 -0
  46. package/dist/db/store.js.map +1 -0
  47. package/dist/hub.d.ts +188 -0
  48. package/dist/hub.d.ts.map +1 -0
  49. package/dist/hub.js +636 -0
  50. package/dist/hub.js.map +1 -0
  51. package/dist/hub.tgz +0 -0
  52. package/dist/mcp/server.d.ts +31 -0
  53. package/dist/mcp/server.d.ts.map +1 -0
  54. package/dist/mcp/server.js +66 -0
  55. package/dist/mcp/server.js.map +1 -0
  56. package/dist/paths.d.ts +27 -0
  57. package/dist/paths.d.ts.map +1 -0
  58. package/dist/paths.js +31 -0
  59. package/dist/paths.js.map +1 -0
  60. package/dist/protocol/address.d.ts +15 -0
  61. package/dist/protocol/address.d.ts.map +1 -0
  62. package/dist/protocol/address.js +39 -0
  63. package/dist/protocol/address.js.map +1 -0
  64. package/dist/protocol/domain.d.ts +151 -0
  65. package/dist/protocol/domain.d.ts.map +1 -0
  66. package/dist/protocol/domain.js +104 -0
  67. package/dist/protocol/domain.js.map +1 -0
  68. package/dist/protocol/index.d.ts +7 -0
  69. package/dist/protocol/index.d.ts.map +1 -0
  70. package/dist/protocol/index.js +7 -0
  71. package/dist/protocol/index.js.map +1 -0
  72. package/dist/protocol/inject.d.ts +29 -0
  73. package/dist/protocol/inject.d.ts.map +1 -0
  74. package/dist/protocol/inject.js +40 -0
  75. package/dist/protocol/inject.js.map +1 -0
  76. package/dist/protocol/mcp-tools.d.ts +45 -0
  77. package/dist/protocol/mcp-tools.d.ts.map +1 -0
  78. package/dist/protocol/mcp-tools.js +46 -0
  79. package/dist/protocol/mcp-tools.js.map +1 -0
  80. package/dist/protocol/peer.d.ts +304 -0
  81. package/dist/protocol/peer.d.ts.map +1 -0
  82. package/dist/protocol/peer.js +183 -0
  83. package/dist/protocol/peer.js.map +1 -0
  84. package/dist/protocol/ws.d.ts +416 -0
  85. package/dist/protocol/ws.d.ts.map +1 -0
  86. package/dist/protocol/ws.js +119 -0
  87. package/dist/protocol/ws.js.map +1 -0
  88. package/dist/remote/deployer.d.ts +78 -0
  89. package/dist/remote/deployer.d.ts.map +1 -0
  90. package/dist/remote/deployer.js +216 -0
  91. package/dist/remote/deployer.js.map +1 -0
  92. package/dist/remote/enroll.d.ts +14 -0
  93. package/dist/remote/enroll.d.ts.map +1 -0
  94. package/dist/remote/enroll.js +244 -0
  95. package/dist/remote/enroll.js.map +1 -0
  96. package/dist/remote/join-script.d.ts +29 -0
  97. package/dist/remote/join-script.d.ts.map +1 -0
  98. package/dist/remote/join-script.js +709 -0
  99. package/dist/remote/join-script.js.map +1 -0
  100. package/dist/remote/join.d.ts +19 -0
  101. package/dist/remote/join.d.ts.map +1 -0
  102. package/dist/remote/join.js +195 -0
  103. package/dist/remote/join.js.map +1 -0
  104. package/dist/remote/lan.d.ts +45 -0
  105. package/dist/remote/lan.d.ts.map +1 -0
  106. package/dist/remote/lan.js +105 -0
  107. package/dist/remote/lan.js.map +1 -0
  108. package/dist/remote/peer-serve.d.ts +27 -0
  109. package/dist/remote/peer-serve.d.ts.map +1 -0
  110. package/dist/remote/peer-serve.js +274 -0
  111. package/dist/remote/peer-serve.js.map +1 -0
  112. package/dist/remote/peer.d.ts +62 -0
  113. package/dist/remote/peer.d.ts.map +1 -0
  114. package/dist/remote/peer.js +250 -0
  115. package/dist/remote/peer.js.map +1 -0
  116. package/dist/remote/registry.d.ts +104 -0
  117. package/dist/remote/registry.d.ts.map +1 -0
  118. package/dist/remote/registry.js +359 -0
  119. package/dist/remote/registry.js.map +1 -0
  120. package/dist/remote/tarball.d.ts +9 -0
  121. package/dist/remote/tarball.d.ts.map +1 -0
  122. package/dist/remote/tarball.js +22 -0
  123. package/dist/remote/tarball.js.map +1 -0
  124. package/dist/server.d.ts +54 -0
  125. package/dist/server.d.ts.map +1 -0
  126. package/dist/server.js +438 -0
  127. package/dist/server.js.map +1 -0
  128. package/dist/session/manager.d.ts +104 -0
  129. package/dist/session/manager.d.ts.map +1 -0
  130. package/dist/session/manager.js +421 -0
  131. package/dist/session/manager.js.map +1 -0
  132. package/dist/session/pty.d.ts +114 -0
  133. package/dist/session/pty.d.ts.map +1 -0
  134. package/dist/session/pty.js +300 -0
  135. package/dist/session/pty.js.map +1 -0
  136. package/package.json +49 -0
  137. package/web/assets/index-B2JtCtHa.css +1 -0
  138. package/web/assets/index-BOqZOoep.js +107 -0
  139. package/web/index.html +13 -0
@@ -0,0 +1,421 @@
1
+ import { EventEmitter } from 'node:events';
2
+ import { randomUUID } from 'node:crypto';
3
+ import { existsSync } from 'node:fs';
4
+ import { makeAddress, uniqueName, } from '../protocol/index.js';
5
+ import { DEFAULT_WINDOW } from '../db/store.js';
6
+ import { template, templateAll } from '../agents/profiles.js';
7
+ import { resolveCommand } from '../agents/resolve.js';
8
+ import { writeWiring } from '../agents/wiring.js';
9
+ import { PtySession } from './pty.js';
10
+ /** Debounce for persisting the serialized screen of an active session. */
11
+ const SNAPSHOT_DEBOUNCE_MS = 5_000;
12
+ /**
13
+ * How long titles are pooled before one write and one broadcast. An agent
14
+ * rewrites its terminal title as it works, and every change would otherwise be
15
+ * a row update and a frame to every browser.
16
+ */
17
+ const TITLE_COALESCE_MS = 250;
18
+ /** Debounce for persisting window geometry while a window is being dragged. */
19
+ export const LAYOUT_DEBOUNCE_MS = 250;
20
+ /**
21
+ * Owns every PTY on this hub, plus the persistence of their state.
22
+ *
23
+ * The invariant worth stating: SQLite always holds enough to redraw the canvas
24
+ * and relaunch each agent. Live objects here are a cache over that, never the
25
+ * other way round.
26
+ */
27
+ export class SessionManager extends EventEmitter {
28
+ store;
29
+ profiles;
30
+ tokens;
31
+ hubOrigin;
32
+ live = new Map();
33
+ snapshotTimers = new Map();
34
+ layoutTimers = new Map();
35
+ /** Latest title per session, waiting for the coalescing window to close. */
36
+ pendingTitles = new Map();
37
+ titleTimer = null;
38
+ constructor(store, profiles, tokens, hubOrigin) {
39
+ super();
40
+ this.store = store;
41
+ this.profiles = profiles;
42
+ this.tokens = tokens;
43
+ this.hubOrigin = hubOrigin;
44
+ }
45
+ setHubOrigin(origin) {
46
+ this.hubOrigin = origin;
47
+ }
48
+ /* ----------------------------------------------------------- accessors */
49
+ isResumable = (profile) => this.profiles.isResumable(profile);
50
+ list() {
51
+ return this.store.listSessions(this.isResumable).map((s) => this.decorate(s));
52
+ }
53
+ get(id) {
54
+ const s = this.store.getSession(id, this.isResumable);
55
+ return s ? this.decorate(s) : null;
56
+ }
57
+ getByAddress(address) {
58
+ return this.list().find((s) => s.address === address) ?? null;
59
+ }
60
+ /** Overlay live runtime status onto the persisted row. */
61
+ decorate(s) {
62
+ const p = this.live.get(s.id);
63
+ if (!p)
64
+ return s;
65
+ return { ...s, status: p.status, pid: p.pid, cols: p.cols, rows: p.rows };
66
+ }
67
+ pty(id) {
68
+ return this.live.get(id) ?? null;
69
+ }
70
+ /* -------------------------------------------------------------- launch */
71
+ /** Build the resolved argv/env for a launch. `resume` swaps in --resume. */
72
+ buildSpec(session, workspaceName, profile, peers, resume) {
73
+ const token = this.tokens.mint(session.id);
74
+ let vars = {
75
+ address: session.address,
76
+ workspace: workspaceName,
77
+ cwd: session.cwd,
78
+ session_uuid: session.agentSessionUuid ?? '',
79
+ default_shell: profile.command,
80
+ };
81
+ if (profile.mcp) {
82
+ const w = writeWiring({
83
+ sessionId: session.id,
84
+ address: session.address,
85
+ workspace: workspaceName,
86
+ cwd: session.cwd,
87
+ profile,
88
+ token,
89
+ hubOrigin: this.hubOrigin,
90
+ peers,
91
+ });
92
+ vars = {
93
+ ...vars,
94
+ mcp_config_path: w.mcpConfigPath,
95
+ settings_path: w.settingsPath,
96
+ brief_path: w.briefPath,
97
+ };
98
+ }
99
+ const argTemplate = resume && profile.resumeArgs ? profile.resumeArgs : profile.args;
100
+ // Resolve to an absolute path here rather than at spawn time, so the
101
+ // stored argv is exactly what will be run and a missing CLI is reported
102
+ // as a clear error instead of node-pty's bare "File not found:".
103
+ const { argv } = resolveCommand(template(profile.command, vars), templateAll(argTemplate, vars));
104
+ return {
105
+ argv,
106
+ env: Object.fromEntries(Object.entries(profile.env).map(([k, v]) => [k, templateAll([v], vars)[0]])),
107
+ };
108
+ }
109
+ peersOf(workspaceId, exceptId) {
110
+ return this.list()
111
+ .filter((s) => s.workspaceId === workspaceId && s.id !== exceptId)
112
+ .map((s) => s.address);
113
+ }
114
+ async start(opts) {
115
+ const ws = this.store.getWorkspace(opts.workspaceId);
116
+ if (!ws)
117
+ throw new Error(`unknown workspace ${opts.workspaceId}`);
118
+ const profile = this.profiles.require(opts.profileId);
119
+ const name = uniqueName(opts.name ?? opts.profileId, this.store.namesInWorkspace(ws.id));
120
+ const id = randomUUID();
121
+ const cwd = opts.cwd ?? ws.rootPath;
122
+ if (!existsSync(cwd))
123
+ throw new Error(`working directory does not exist: ${cwd}`);
124
+ const now = Date.now();
125
+ const session = {
126
+ id,
127
+ workspaceId: ws.id,
128
+ name,
129
+ address: makeAddress(ws.name, name),
130
+ profile: profile.id,
131
+ cwd,
132
+ // Claude Code keys its conversation store by cwd + this uuid; holding on
133
+ // to it is what makes --resume possible after a restart.
134
+ agentSessionUuid: profile.resumeArgs ? randomUUID() : null,
135
+ spawnedBy: opts.spawnedBy ?? null,
136
+ state: 'starting',
137
+ status: 'unknown',
138
+ statusText: null,
139
+ title: null,
140
+ pid: null,
141
+ exitCode: null,
142
+ cols: opts.cols ?? 100,
143
+ rows: opts.rows ?? 30,
144
+ resumable: !!profile.resumeArgs,
145
+ createdAt: now,
146
+ exitedAt: null,
147
+ lastActiveAt: now,
148
+ window: opts.window ?? this.placeWindow(ws.id, opts.spawnedBy ?? null),
149
+ };
150
+ const spec = this.buildSpec(session, ws.name, profile, this.peersOf(ws.id), false);
151
+ this.store.insertSession(session, spec);
152
+ this.spawn(session, spec, profile);
153
+ return this.get(id);
154
+ }
155
+ /** Bring a stopped session back, reusing its recorded argv and cwd. */
156
+ async resume(sessionId) {
157
+ const s = this.store.getSession(sessionId, this.isResumable);
158
+ if (!s)
159
+ throw new Error(`unknown session ${sessionId}`);
160
+ if (this.live.get(sessionId)?.running)
161
+ return this.get(sessionId);
162
+ const ws = this.store.getWorkspace(s.workspaceId);
163
+ if (!ws)
164
+ throw new Error(`unknown workspace ${s.workspaceId}`);
165
+ const profile = this.profiles.require(s.profile);
166
+ // Rebuild rather than replay the stored argv verbatim: the token must be
167
+ // fresh and the wiring files must be rewritten for this run.
168
+ const spec = this.buildSpec(s, ws.name, profile, this.peersOf(ws.id, s.id), !!profile.resumeArgs && !!s.agentSessionUuid);
169
+ this.store.setLaunchSpec(s.id, spec);
170
+ this.spawn(s, spec, profile);
171
+ return this.get(sessionId);
172
+ }
173
+ spawn(session, spec, profile) {
174
+ const existing = this.live.get(session.id);
175
+ if (existing)
176
+ existing.dispose();
177
+ const p = new PtySession(session.id, session.cols, session.rows, profile.readyHint ? new RegExp(profile.readyHint) : null, profile.status);
178
+ this.live.set(session.id, p);
179
+ // Restoring the persisted screen first means a resumed window shows its
180
+ // prior content immediately rather than flashing empty.
181
+ const snap = this.store.getSnapshot(session.id);
182
+ if (snap)
183
+ p.restore(snap.serialized);
184
+ p.on('data', (chunk) => {
185
+ this.emit('data', session.id, chunk);
186
+ this.scheduleSnapshot(session.id);
187
+ });
188
+ p.on('status', () => this.emitSession(session.id));
189
+ p.on('title', (title) => this.noteTitle(session.id, title));
190
+ p.on('exit', ({ exitCode }) => {
191
+ this.persistSnapshot(session.id);
192
+ this.tokens.revoke(session.id);
193
+ this.store.updateSession(session.id, {
194
+ state: 'exited',
195
+ pid: null,
196
+ exitCode,
197
+ exitedAt: Date.now(),
198
+ });
199
+ this.emit('exit', session.id, exitCode);
200
+ this.emitSession(session.id);
201
+ });
202
+ try {
203
+ p.start({
204
+ argv: spec.argv,
205
+ env: spec.env,
206
+ cwd: session.cwd,
207
+ cols: session.cols,
208
+ rows: session.rows,
209
+ });
210
+ this.store.updateSession(session.id, {
211
+ state: 'running',
212
+ pid: p.pid,
213
+ exitCode: null,
214
+ exitedAt: null,
215
+ lastActiveAt: Date.now(),
216
+ });
217
+ }
218
+ catch (err) {
219
+ this.store.updateSession(session.id, {
220
+ state: 'failed',
221
+ pid: null,
222
+ exitedAt: Date.now(),
223
+ });
224
+ this.emitSession(session.id);
225
+ throw err;
226
+ }
227
+ this.emitSession(session.id);
228
+ }
229
+ /* --------------------------------------------------------------- input */
230
+ write(sessionId, data) {
231
+ const p = this.live.get(sessionId);
232
+ if (!p?.running)
233
+ throw new Error(`session ${sessionId} is not running`);
234
+ p.write(data);
235
+ this.store.updateSession(sessionId, { lastActiveAt: Date.now() });
236
+ }
237
+ resize(sessionId, cols, rows) {
238
+ const p = this.live.get(sessionId);
239
+ p?.resize(cols, rows);
240
+ this.store.updateSession(sessionId, { cols, rows });
241
+ }
242
+ setStatusText(sessionId, text) {
243
+ this.store.updateSession(sessionId, { statusText: text });
244
+ this.emitSession(sessionId);
245
+ }
246
+ /**
247
+ * A title the program in the PTY set for itself.
248
+ *
249
+ * An agent rewrites this as it works, several times a second, so the write
250
+ * and the broadcast are held to the last value in a window rather than one
251
+ * apiece. Unrefed: a pending title is never a reason to keep the process up.
252
+ */
253
+ noteTitle(sessionId, title) {
254
+ this.pendingTitles.set(sessionId, title);
255
+ if (this.titleTimer)
256
+ return;
257
+ this.titleTimer = setTimeout(() => {
258
+ this.titleTimer = null;
259
+ const batch = [...this.pendingTitles];
260
+ this.pendingTitles.clear();
261
+ for (const [id, t] of batch) {
262
+ this.store.updateSession(id, { title: t });
263
+ this.emitSession(id);
264
+ }
265
+ }, TITLE_COALESCE_MS);
266
+ this.titleTimer.unref?.();
267
+ }
268
+ /** Called by the hooks endpoint: exact turn boundaries from the agent CLI. */
269
+ setStatusFromHook(sessionId, status) {
270
+ this.live.get(sessionId)?.noteHook(status);
271
+ this.emitSession(sessionId);
272
+ }
273
+ stop(sessionId) {
274
+ const p = this.live.get(sessionId);
275
+ if (!p)
276
+ return;
277
+ this.persistSnapshot(sessionId);
278
+ p.kill();
279
+ this.tokens.revoke(sessionId);
280
+ this.store.updateSession(sessionId, { state: 'stopped', pid: null });
281
+ this.emitSession(sessionId);
282
+ }
283
+ remove(sessionId) {
284
+ // Capture the address before the row goes: peers address sessions by
285
+ // name, and after the delete there is nothing left to look it up from.
286
+ const address = this.get(sessionId)?.address ?? null;
287
+ this.live.get(sessionId)?.dispose();
288
+ this.live.delete(sessionId);
289
+ this.clearTimer(this.snapshotTimers, sessionId);
290
+ this.clearTimer(this.layoutTimers, sessionId);
291
+ this.tokens.revoke(sessionId);
292
+ this.store.removeSession(sessionId);
293
+ this.emit('removed', sessionId, address);
294
+ }
295
+ /* ------------------------------------------------------------ snapshots */
296
+ scheduleSnapshot(sessionId) {
297
+ if (this.snapshotTimers.has(sessionId))
298
+ return;
299
+ const t = setTimeout(() => {
300
+ this.snapshotTimers.delete(sessionId);
301
+ this.persistSnapshot(sessionId);
302
+ }, SNAPSHOT_DEBOUNCE_MS);
303
+ // Never let a pending snapshot hold the process open at shutdown.
304
+ t.unref?.();
305
+ this.snapshotTimers.set(sessionId, t);
306
+ }
307
+ /** Screen only — the deliberate cost of the snapshot-only design. */
308
+ persistSnapshot(sessionId) {
309
+ const p = this.live.get(sessionId);
310
+ if (!p)
311
+ return;
312
+ try {
313
+ this.store.saveSnapshot(sessionId, p.serializeForPersist(), p.cols, p.rows);
314
+ }
315
+ catch (err) {
316
+ console.error(`[snapshot] ${sessionId}: ${err.message}`);
317
+ }
318
+ }
319
+ persistAllSnapshots() {
320
+ for (const id of this.live.keys())
321
+ this.persistSnapshot(id);
322
+ }
323
+ snapshotForAttach(sessionId) {
324
+ const p = this.live.get(sessionId);
325
+ if (p)
326
+ return { serialized: p.serializeForAttach(), cols: p.cols, rows: p.rows };
327
+ // Not running: fall back to whatever the last persisted screen was.
328
+ return this.store.getSnapshot(sessionId);
329
+ }
330
+ /* --------------------------------------------------------------- layout */
331
+ moveWindow(sessionId, rect) {
332
+ this.clearTimer(this.layoutTimers, sessionId);
333
+ const t = setTimeout(() => {
334
+ this.layoutTimers.delete(sessionId);
335
+ this.store.saveWindow(sessionId, rect);
336
+ }, LAYOUT_DEBOUNCE_MS);
337
+ t.unref?.();
338
+ this.layoutTimers.set(sessionId, t);
339
+ }
340
+ /**
341
+ * Place a new window: tucked below-right of its parent when spawned by
342
+ * another agent, otherwise in the next free slot of a simple grid.
343
+ */
344
+ placeWindow(workspaceId, parentId) {
345
+ const siblings = this.list().filter((s) => s.workspaceId === workspaceId);
346
+ if (parentId) {
347
+ const parent = this.get(parentId);
348
+ if (parent) {
349
+ return {
350
+ ...DEFAULT_WINDOW,
351
+ x: parent.window.x + 60,
352
+ y: parent.window.y + parent.window.h + 40,
353
+ z: parent.window.z + 1,
354
+ };
355
+ }
356
+ }
357
+ const all = this.list();
358
+ const col = siblings.length % 3;
359
+ const row = Math.floor(siblings.length / 3);
360
+ const originX = all.length === siblings.length ? 0 : this.workspaceOriginX(workspaceId);
361
+ return {
362
+ ...DEFAULT_WINDOW,
363
+ x: originX + col * (DEFAULT_WINDOW.w + 40),
364
+ y: row * (DEFAULT_WINDOW.h + 40),
365
+ z: siblings.length,
366
+ };
367
+ }
368
+ /** Workspaces are laid out left to right so their groups do not overlap. */
369
+ workspaceOriginX(workspaceId) {
370
+ const order = this.store.listWorkspaces().findIndex((w) => w.id === workspaceId);
371
+ return Math.max(0, order) * (DEFAULT_WINDOW.w + 40) * 3.5;
372
+ }
373
+ /* -------------------------------------------------------------- helpers */
374
+ clearTimer(map, key) {
375
+ const t = map.get(key);
376
+ if (t) {
377
+ clearTimeout(t);
378
+ map.delete(key);
379
+ }
380
+ }
381
+ emitSession(sessionId) {
382
+ const s = this.get(sessionId);
383
+ if (s)
384
+ this.emit('session', s);
385
+ }
386
+ /**
387
+ * Startup reconciliation. Sessions cannot outlive the hub, so anything the
388
+ * DB still calls running is stale and is marked stopped, ready to resume.
389
+ */
390
+ reconcileOnBoot() {
391
+ for (const s of this.store.listSessions(this.isResumable)) {
392
+ if (s.state === 'running' || s.state === 'starting') {
393
+ this.store.updateSession(s.id, { state: 'stopped', pid: null });
394
+ }
395
+ }
396
+ }
397
+ shutdown() {
398
+ this.persistAllSnapshots();
399
+ for (const [id, p] of this.live) {
400
+ p.dispose();
401
+ this.store.updateSession(id, { state: 'stopped', pid: null });
402
+ }
403
+ this.live.clear();
404
+ for (const t of this.snapshotTimers.values())
405
+ clearTimeout(t);
406
+ for (const t of this.layoutTimers.values())
407
+ clearTimeout(t);
408
+ this.snapshotTimers.clear();
409
+ this.layoutTimers.clear();
410
+ // The title timer is a single shared timeout rather than one per session,
411
+ // which is exactly why it was missed here: it holds a write that would
412
+ // land after the caller closes the database, and better-sqlite3 throws
413
+ // rather than ignoring it. Unref keeps it from holding the process open;
414
+ // it does not stop it firing while the process is still coming down.
415
+ if (this.titleTimer)
416
+ clearTimeout(this.titleTimer);
417
+ this.titleTimer = null;
418
+ this.pendingTitles.clear();
419
+ }
420
+ }
421
+ //# sourceMappingURL=manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/session/manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,114 @@
1
+ import { EventEmitter } from 'node:events';
2
+ import type { AgentStatus } from '../protocol/index.js';
3
+ export interface PtyStartOptions {
4
+ argv: string[];
5
+ env: Record<string, string>;
6
+ cwd: string;
7
+ cols: number;
8
+ rows: number;
9
+ }
10
+ export interface PtyExit {
11
+ exitCode: number;
12
+ signal?: number;
13
+ }
14
+ /**
15
+ * One PTY plus a headless xterm that mirrors it.
16
+ *
17
+ * The headless terminal earns its keep twice: it produces the serialized
18
+ * screen we persist to SQLite, and it is the in-memory scrollback that backs
19
+ * LOD detach/reattach. Feeding one parser instead of keeping a separate raw
20
+ * ring buffer means the replayed screen is always consistent with what the
21
+ * program actually drew, escape sequences and all.
22
+ */
23
+ export declare class PtySession extends EventEmitter {
24
+ readonly id: string;
25
+ cols: number;
26
+ rows: number;
27
+ private readonly readyHint;
28
+ private readonly statusMode;
29
+ private proc;
30
+ private readonly term;
31
+ private readonly serializer;
32
+ private lastOutputAt;
33
+ private idleTimer;
34
+ private _status;
35
+ /**
36
+ * Whether this session has ever reported a turn boundary itself. Until it
37
+ * has, a `hooks` profile is indistinguishable from one whose hooks cannot
38
+ * run at all, and the dot has to come from somewhere.
39
+ */
40
+ private hooksSeen;
41
+ /** Last title this program set, to keep repeats off the wire. */
42
+ private lastTitle;
43
+ /** argv[0], to recognise the one title the program did not choose. */
44
+ private launchedFile;
45
+ private disposed;
46
+ constructor(id: string, cols: number, rows: number, readyHint: RegExp | null, statusMode: 'hooks' | 'heuristic');
47
+ /**
48
+ * ConPTY announces the child's image path as the terminal title the moment
49
+ * it starts, before the program has said anything at all. That is Windows
50
+ * talking, not the agent, and `C:...node.exe` in a window header is worse
51
+ * than the canvas address it would replace.
52
+ */
53
+ private isLaunchNoise;
54
+ get status(): AgentStatus;
55
+ get running(): boolean;
56
+ get pid(): number | null;
57
+ start(opts: PtyStartOptions): void;
58
+ /** Feed output to subscribers and to the mirror terminal. */
59
+ private ingest;
60
+ /**
61
+ * Idle detection from output alone. Drives the status chip only — never
62
+ * gates delivery, because delivery is immediate by design.
63
+ *
64
+ * Two callers, with different standards of proof. A `heuristic` profile has
65
+ * a prompt pattern, so a short quiet spell plus a matching last line is
66
+ * enough. A `hooks` profile only reaches here while its hooks have never
67
+ * arrived, and has nothing to match against, so it waits out a longer
68
+ * silence and takes that as the answer.
69
+ */
70
+ private scheduleIdleCheck;
71
+ private clearIdleTimer;
72
+ markBusy(): void;
73
+ /**
74
+ * A turn boundary the agent reported itself. Exact, where reading the output
75
+ * is a guess — so the first one to arrive retires the fallback for good and
76
+ * this session's status is whatever its hooks say from then on.
77
+ */
78
+ noteHook(s: AgentStatus): void;
79
+ setStatus(s: AgentStatus): void;
80
+ write(data: string): void;
81
+ resize(cols: number, rows: number): void;
82
+ /** Full-ish history, for a browser that just attached to this window. */
83
+ serializeForAttach(): string;
84
+ /**
85
+ * Screen only. This is what goes in SQLite: a restart preserves the last
86
+ * screenful, deliberately not the scrollback above it.
87
+ */
88
+ serializeForPersist(): string;
89
+ /**
90
+ * The last line the program actually drew, wherever it is on the screen.
91
+ *
92
+ * Not the bottom row: a CLI sitting at its prompt after printing one banner
93
+ * has its prompt at the top and twenty-three blank rows under it, and
94
+ * testing the bottom row against a prompt pattern matched nothing, ever.
95
+ * That is what kept a freshly started window amber for the life of the
96
+ * process.
97
+ */
98
+ private lastNonEmptyLine;
99
+ /**
100
+ * Trailing rendered lines, for the read_screen MCP tool.
101
+ *
102
+ * Rows the terminal wrapped are rejoined. A wrap is a property of how
103
+ * wide the window happens to be, not of the text, so breaking a line
104
+ * there hands the reader a word split down the middle at a column that
105
+ * depends on someone else's terminal size - and the reader here is an
106
+ * agent trying to make sense of what another agent is doing.
107
+ */
108
+ tailLines(n: number): string;
109
+ /** Restore a persisted screen into the mirror so reattach shows it. */
110
+ restore(serialized: string): void;
111
+ kill(): void;
112
+ dispose(): void;
113
+ }
114
+ //# sourceMappingURL=pty.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pty.d.ts","sourceRoot":"","sources":["../../src/session/pty.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAI3C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAqBvD,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,OAAO;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAqBD;;;;;;;;GAQG;AACH,qBAAa,UAAW,SAAQ,YAAY;IAoBxC,QAAQ,CAAC,EAAE,EAAE,MAAM;IACZ,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE,MAAM;IACnB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,UAAU;IAvB7B,OAAO,CAAC,IAAI,CAAqB;IACjC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAQ;IAC7B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAkB;IAC7C,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,SAAS,CAA+B;IAChD,OAAO,CAAC,OAAO,CAA0B;IACzC;;;;OAIG;IACH,OAAO,CAAC,SAAS,CAAS;IAC1B,iEAAiE;IACjE,OAAO,CAAC,SAAS,CAAuB;IACxC,sEAAsE;IACtE,OAAO,CAAC,YAAY,CAAM;IAC1B,OAAO,CAAC,QAAQ,CAAS;gBAGd,EAAE,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACF,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,UAAU,EAAE,OAAO,GAAG,WAAW;IAwBpD;;;;;OAKG;IACH,OAAO,CAAC,aAAa;IASrB,IAAI,MAAM,IAAI,WAAW,CAExB;IAED,IAAI,OAAO,IAAI,OAAO,CAErB;IAED,IAAI,GAAG,IAAI,MAAM,GAAG,IAAI,CAEvB;IAED,KAAK,CAAC,IAAI,EAAE,eAAe,GAAG,IAAI;IAkClC,6DAA6D;IAC7D,OAAO,CAAC,MAAM;IAWd;;;;;;;;;OASG;IACH,OAAO,CAAC,iBAAiB;IAkBzB,OAAO,CAAC,cAAc;IAOtB,QAAQ,IAAI,IAAI;IAIhB;;;;OAIG;IACH,QAAQ,CAAC,CAAC,EAAE,WAAW,GAAG,IAAI;IAM9B,SAAS,CAAC,CAAC,EAAE,WAAW,GAAG,IAAI;IAM/B,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAKzB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IASxC,yEAAyE;IACzE,kBAAkB,IAAI,MAAM;IAI5B;;;OAGG;IACH,mBAAmB,IAAI,MAAM;IAI7B;;;;;;;;OAQG;IACH,OAAO,CAAC,gBAAgB;IAKxB;;;;;;;;OAQG;IACH,SAAS,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM;IAe5B,uEAAuE;IACvE,OAAO,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAIjC,IAAI,IAAI,IAAI;IAWZ,OAAO,IAAI,IAAI;CAMhB"}