@adhdev/session-host-core 0.7.12
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/index.d.mts +293 -0
- package/dist/index.d.ts +293 -0
- package/dist/index.js +523 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +475 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +43 -0
- package/src/buffer.ts +78 -0
- package/src/index.ts +49 -0
- package/src/ipc.ts +164 -0
- package/src/registry.ts +252 -0
- package/src/runtime-labels.ts +85 -0
- package/src/types.ts +184 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,523 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
|
+
SessionHostClient: () => SessionHostClient,
|
|
34
|
+
SessionHostRegistry: () => SessionHostRegistry,
|
|
35
|
+
SessionRingBuffer: () => SessionRingBuffer,
|
|
36
|
+
buildRuntimeDisplayName: () => buildRuntimeDisplayName,
|
|
37
|
+
buildRuntimeKey: () => buildRuntimeKey,
|
|
38
|
+
createLineParser: () => createLineParser,
|
|
39
|
+
createResponseEnvelope: () => createResponseEnvelope,
|
|
40
|
+
formatRuntimeOwner: () => formatRuntimeOwner,
|
|
41
|
+
getDefaultSessionHostEndpoint: () => getDefaultSessionHostEndpoint,
|
|
42
|
+
getWorkspaceLabel: () => getWorkspaceLabel,
|
|
43
|
+
resolveRuntimeRecord: () => resolveRuntimeRecord,
|
|
44
|
+
writeEnvelope: () => writeEnvelope
|
|
45
|
+
});
|
|
46
|
+
module.exports = __toCommonJS(index_exports);
|
|
47
|
+
|
|
48
|
+
// src/buffer.ts
|
|
49
|
+
var SessionRingBuffer = class {
|
|
50
|
+
maxBytes;
|
|
51
|
+
chunks = [];
|
|
52
|
+
nextSeq = 1;
|
|
53
|
+
totalBytes = 0;
|
|
54
|
+
constructor(options = {}) {
|
|
55
|
+
this.maxBytes = options.maxBytes ?? 512 * 1024;
|
|
56
|
+
}
|
|
57
|
+
append(data) {
|
|
58
|
+
const normalized = typeof data === "string" ? data : String(data ?? "");
|
|
59
|
+
const bytes = Buffer.byteLength(normalized, "utf8");
|
|
60
|
+
const seq = this.nextSeq++;
|
|
61
|
+
this.chunks.push({ seq, data: normalized, bytes });
|
|
62
|
+
this.totalBytes += bytes;
|
|
63
|
+
this.trim();
|
|
64
|
+
return seq;
|
|
65
|
+
}
|
|
66
|
+
snapshot(sinceSeq) {
|
|
67
|
+
const relevant = typeof sinceSeq === "number" ? this.chunks.filter((chunk) => chunk.seq > sinceSeq) : this.chunks;
|
|
68
|
+
const text = relevant.map((chunk) => chunk.data).join("");
|
|
69
|
+
const truncated = !!this.chunks[0] && typeof sinceSeq === "number" && sinceSeq < this.chunks[0].seq - 1;
|
|
70
|
+
return {
|
|
71
|
+
seq: this.nextSeq - 1,
|
|
72
|
+
text,
|
|
73
|
+
truncated
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
getState() {
|
|
77
|
+
return {
|
|
78
|
+
scrollbackBytes: this.totalBytes,
|
|
79
|
+
snapshotSeq: this.nextSeq - 1
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
clear() {
|
|
83
|
+
this.chunks = [];
|
|
84
|
+
this.totalBytes = 0;
|
|
85
|
+
this.nextSeq = 1;
|
|
86
|
+
}
|
|
87
|
+
restore(snapshot) {
|
|
88
|
+
this.clear();
|
|
89
|
+
const text = String(snapshot.text || "");
|
|
90
|
+
if (!text) {
|
|
91
|
+
this.nextSeq = Math.max(1, Number(snapshot.seq || 0) + 1);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
const bytes = Buffer.byteLength(text, "utf8");
|
|
95
|
+
const seq = Math.max(1, Number(snapshot.seq || 1));
|
|
96
|
+
this.chunks = [{ seq, data: text, bytes }];
|
|
97
|
+
this.totalBytes = bytes;
|
|
98
|
+
this.nextSeq = seq + 1;
|
|
99
|
+
this.trim();
|
|
100
|
+
}
|
|
101
|
+
trim() {
|
|
102
|
+
while (this.totalBytes > this.maxBytes && this.chunks.length > 1) {
|
|
103
|
+
const removed = this.chunks.shift();
|
|
104
|
+
if (!removed) break;
|
|
105
|
+
this.totalBytes -= removed.bytes;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
// src/registry.ts
|
|
111
|
+
var import_crypto = require("crypto");
|
|
112
|
+
|
|
113
|
+
// src/runtime-labels.ts
|
|
114
|
+
var path = __toESM(require("path"));
|
|
115
|
+
function normalizeSlug(input) {
|
|
116
|
+
return input.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48);
|
|
117
|
+
}
|
|
118
|
+
function normalizeValue(input) {
|
|
119
|
+
return input.trim().toLowerCase();
|
|
120
|
+
}
|
|
121
|
+
function getWorkspaceLabel(workspace) {
|
|
122
|
+
const trimmed = workspace.trim();
|
|
123
|
+
if (!trimmed) return "workspace";
|
|
124
|
+
const normalized = trimmed.replace(/[\\/]+$/, "");
|
|
125
|
+
const base = path.basename(normalized);
|
|
126
|
+
return base || normalized;
|
|
127
|
+
}
|
|
128
|
+
function buildRuntimeDisplayName(payload) {
|
|
129
|
+
const explicit = payload.displayName?.trim();
|
|
130
|
+
if (explicit) return explicit;
|
|
131
|
+
const workspaceLabel = getWorkspaceLabel(payload.workspace);
|
|
132
|
+
const providerLabel = payload.providerType.trim() || "runtime";
|
|
133
|
+
return `${providerLabel} @ ${workspaceLabel}`;
|
|
134
|
+
}
|
|
135
|
+
function buildRuntimeKey(payload, existingKeys) {
|
|
136
|
+
const requested = payload.runtimeKey?.trim();
|
|
137
|
+
const existing = new Set(Array.from(existingKeys, (key) => key.toLowerCase()));
|
|
138
|
+
const displayName = buildRuntimeDisplayName(payload);
|
|
139
|
+
const baseKey = normalizeSlug(requested || displayName || getWorkspaceLabel(payload.workspace) || payload.providerType || "runtime") || "runtime";
|
|
140
|
+
if (!existing.has(baseKey)) return baseKey;
|
|
141
|
+
let suffix = 2;
|
|
142
|
+
let candidate = `${baseKey}-${suffix}`;
|
|
143
|
+
while (existing.has(candidate)) {
|
|
144
|
+
suffix += 1;
|
|
145
|
+
candidate = `${baseKey}-${suffix}`;
|
|
146
|
+
}
|
|
147
|
+
return candidate;
|
|
148
|
+
}
|
|
149
|
+
function uniqueMatch(records, predicate) {
|
|
150
|
+
const matches = records.filter(predicate);
|
|
151
|
+
if (matches.length === 1) return matches[0] || null;
|
|
152
|
+
if (matches.length === 0) return null;
|
|
153
|
+
const labels = matches.map((record) => `${record.runtimeKey} (${record.sessionId})`).join(", ");
|
|
154
|
+
throw new Error(`Ambiguous runtime target. Matches: ${labels}`);
|
|
155
|
+
}
|
|
156
|
+
function resolveRuntimeRecord(records, identifier) {
|
|
157
|
+
const target = identifier.trim();
|
|
158
|
+
if (!target) {
|
|
159
|
+
throw new Error("Runtime target is required");
|
|
160
|
+
}
|
|
161
|
+
const exact = uniqueMatch(
|
|
162
|
+
records,
|
|
163
|
+
(record) => record.sessionId === target || normalizeValue(record.runtimeKey) === normalizeValue(target) || normalizeValue(record.displayName) === normalizeValue(target)
|
|
164
|
+
);
|
|
165
|
+
if (exact) return exact;
|
|
166
|
+
const prefix = uniqueMatch(
|
|
167
|
+
records,
|
|
168
|
+
(record) => record.sessionId.startsWith(target) || normalizeValue(record.runtimeKey).startsWith(normalizeValue(target))
|
|
169
|
+
);
|
|
170
|
+
if (prefix) return prefix;
|
|
171
|
+
throw new Error(`Unknown runtime target: ${target}`);
|
|
172
|
+
}
|
|
173
|
+
function formatRuntimeOwner(record) {
|
|
174
|
+
if (!record.writeOwner) return "none";
|
|
175
|
+
return `${record.writeOwner.ownerType}:${record.writeOwner.clientId}`;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// src/registry.ts
|
|
179
|
+
var SessionHostRegistry = class {
|
|
180
|
+
sessions = /* @__PURE__ */ new Map();
|
|
181
|
+
createSession(payload) {
|
|
182
|
+
const sessionId = payload.sessionId || (0, import_crypto.randomUUID)();
|
|
183
|
+
if (this.sessions.has(sessionId)) {
|
|
184
|
+
throw new Error(`Session already exists: ${sessionId}`);
|
|
185
|
+
}
|
|
186
|
+
const now = Date.now();
|
|
187
|
+
const initialClient = payload.clientId ? [{
|
|
188
|
+
clientId: payload.clientId,
|
|
189
|
+
type: payload.clientType || "daemon",
|
|
190
|
+
readOnly: false,
|
|
191
|
+
attachedAt: now,
|
|
192
|
+
lastSeenAt: now
|
|
193
|
+
}] : [];
|
|
194
|
+
const record = {
|
|
195
|
+
sessionId,
|
|
196
|
+
runtimeKey: buildRuntimeKey(
|
|
197
|
+
payload,
|
|
198
|
+
Array.from(this.sessions.values(), (state) => state.record.runtimeKey)
|
|
199
|
+
),
|
|
200
|
+
displayName: buildRuntimeDisplayName(payload),
|
|
201
|
+
workspaceLabel: getWorkspaceLabel(payload.workspace),
|
|
202
|
+
transport: "pty",
|
|
203
|
+
providerType: payload.providerType,
|
|
204
|
+
category: payload.category,
|
|
205
|
+
workspace: payload.workspace,
|
|
206
|
+
launchCommand: payload.launchCommand,
|
|
207
|
+
createdAt: now,
|
|
208
|
+
lastActivityAt: now,
|
|
209
|
+
lifecycle: "starting",
|
|
210
|
+
writeOwner: null,
|
|
211
|
+
attachedClients: initialClient,
|
|
212
|
+
buffer: {
|
|
213
|
+
scrollbackBytes: 0,
|
|
214
|
+
snapshotSeq: 0
|
|
215
|
+
},
|
|
216
|
+
meta: payload.meta || {}
|
|
217
|
+
};
|
|
218
|
+
record.meta = {
|
|
219
|
+
sessionHostCols: payload.cols || 120,
|
|
220
|
+
sessionHostRows: payload.rows || 40,
|
|
221
|
+
...record.meta
|
|
222
|
+
};
|
|
223
|
+
this.sessions.set(sessionId, {
|
|
224
|
+
record,
|
|
225
|
+
buffer: new SessionRingBuffer()
|
|
226
|
+
});
|
|
227
|
+
return this.cloneRecord(record);
|
|
228
|
+
}
|
|
229
|
+
restoreSession(record, snapshot) {
|
|
230
|
+
const cloned = this.cloneRecord(record);
|
|
231
|
+
this.sessions.set(cloned.sessionId, {
|
|
232
|
+
record: cloned,
|
|
233
|
+
buffer: (() => {
|
|
234
|
+
const buffer = new SessionRingBuffer();
|
|
235
|
+
if (snapshot) buffer.restore(snapshot);
|
|
236
|
+
return buffer;
|
|
237
|
+
})()
|
|
238
|
+
});
|
|
239
|
+
return this.cloneRecord(cloned);
|
|
240
|
+
}
|
|
241
|
+
listSessions() {
|
|
242
|
+
return Array.from(this.sessions.values()).map((state) => this.cloneRecord(state.record)).sort((a, b) => b.lastActivityAt - a.lastActivityAt);
|
|
243
|
+
}
|
|
244
|
+
getSession(sessionId) {
|
|
245
|
+
const state = this.sessions.get(sessionId);
|
|
246
|
+
return state ? this.cloneRecord(state.record) : null;
|
|
247
|
+
}
|
|
248
|
+
attachClient(payload) {
|
|
249
|
+
const state = this.requireSession(payload.sessionId);
|
|
250
|
+
const now = Date.now();
|
|
251
|
+
let removedDaemonOwner = false;
|
|
252
|
+
if (payload.clientType === "daemon") {
|
|
253
|
+
const staleDaemonClientIds = state.record.attachedClients.filter((client) => client.type === "daemon" && client.clientId !== payload.clientId).map((client) => client.clientId);
|
|
254
|
+
if (staleDaemonClientIds.length > 0) {
|
|
255
|
+
state.record.attachedClients = state.record.attachedClients.filter(
|
|
256
|
+
(client) => !(client.type === "daemon" && client.clientId !== payload.clientId)
|
|
257
|
+
);
|
|
258
|
+
if (state.record.writeOwner && staleDaemonClientIds.includes(state.record.writeOwner.clientId)) {
|
|
259
|
+
removedDaemonOwner = true;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
const existing = state.record.attachedClients.find((client) => client.clientId === payload.clientId);
|
|
264
|
+
if (existing) {
|
|
265
|
+
existing.type = payload.clientType;
|
|
266
|
+
existing.readOnly = !!payload.readOnly;
|
|
267
|
+
existing.lastSeenAt = now;
|
|
268
|
+
} else {
|
|
269
|
+
state.record.attachedClients.push({
|
|
270
|
+
clientId: payload.clientId,
|
|
271
|
+
type: payload.clientType,
|
|
272
|
+
readOnly: !!payload.readOnly,
|
|
273
|
+
attachedAt: now,
|
|
274
|
+
lastSeenAt: now
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
if (removedDaemonOwner) {
|
|
278
|
+
state.record.writeOwner = null;
|
|
279
|
+
}
|
|
280
|
+
state.record.lastActivityAt = now;
|
|
281
|
+
return this.cloneRecord(state.record);
|
|
282
|
+
}
|
|
283
|
+
detachClient(payload) {
|
|
284
|
+
const state = this.requireSession(payload.sessionId);
|
|
285
|
+
state.record.attachedClients = state.record.attachedClients.filter((client) => client.clientId !== payload.clientId);
|
|
286
|
+
if (state.record.writeOwner?.clientId === payload.clientId) {
|
|
287
|
+
state.record.writeOwner = null;
|
|
288
|
+
}
|
|
289
|
+
state.record.lastActivityAt = Date.now();
|
|
290
|
+
return this.cloneRecord(state.record);
|
|
291
|
+
}
|
|
292
|
+
acquireWrite(payload) {
|
|
293
|
+
const state = this.requireSession(payload.sessionId);
|
|
294
|
+
if (state.record.writeOwner && state.record.writeOwner.clientId !== payload.clientId && !payload.force) {
|
|
295
|
+
throw new Error(`Write owned by ${state.record.writeOwner.clientId}`);
|
|
296
|
+
}
|
|
297
|
+
const attachedClient = state.record.attachedClients.find((client) => client.clientId === payload.clientId);
|
|
298
|
+
if (attachedClient) {
|
|
299
|
+
attachedClient.readOnly = false;
|
|
300
|
+
attachedClient.lastSeenAt = Date.now();
|
|
301
|
+
}
|
|
302
|
+
state.record.writeOwner = {
|
|
303
|
+
clientId: payload.clientId,
|
|
304
|
+
ownerType: payload.ownerType,
|
|
305
|
+
acquiredAt: Date.now()
|
|
306
|
+
};
|
|
307
|
+
state.record.lastActivityAt = Date.now();
|
|
308
|
+
return this.cloneRecord(state.record);
|
|
309
|
+
}
|
|
310
|
+
releaseWrite(payload) {
|
|
311
|
+
const state = this.requireSession(payload.sessionId);
|
|
312
|
+
const attachedClient = state.record.attachedClients.find((client) => client.clientId === payload.clientId);
|
|
313
|
+
if (attachedClient) {
|
|
314
|
+
attachedClient.readOnly = false;
|
|
315
|
+
attachedClient.lastSeenAt = Date.now();
|
|
316
|
+
}
|
|
317
|
+
if (state.record.writeOwner?.clientId === payload.clientId) {
|
|
318
|
+
state.record.writeOwner = null;
|
|
319
|
+
}
|
|
320
|
+
state.record.lastActivityAt = Date.now();
|
|
321
|
+
return this.cloneRecord(state.record);
|
|
322
|
+
}
|
|
323
|
+
appendOutput(sessionId, data) {
|
|
324
|
+
const state = this.requireSession(sessionId);
|
|
325
|
+
const seq = state.buffer.append(data);
|
|
326
|
+
state.record.buffer = state.buffer.getState();
|
|
327
|
+
state.record.lastActivityAt = Date.now();
|
|
328
|
+
return { record: this.cloneRecord(state.record), seq };
|
|
329
|
+
}
|
|
330
|
+
getSnapshot(sessionId, sinceSeq) {
|
|
331
|
+
const state = this.requireSession(sessionId);
|
|
332
|
+
state.record.buffer = state.buffer.getState();
|
|
333
|
+
return state.buffer.snapshot(sinceSeq);
|
|
334
|
+
}
|
|
335
|
+
clearBuffer(sessionId) {
|
|
336
|
+
const state = this.requireSession(sessionId);
|
|
337
|
+
state.buffer.clear();
|
|
338
|
+
state.record.buffer = state.buffer.getState();
|
|
339
|
+
state.record.lastActivityAt = Date.now();
|
|
340
|
+
return this.cloneRecord(state.record);
|
|
341
|
+
}
|
|
342
|
+
markStarted(sessionId, pid) {
|
|
343
|
+
const state = this.requireSession(sessionId);
|
|
344
|
+
state.record.lifecycle = "running";
|
|
345
|
+
state.record.startedAt = state.record.startedAt || Date.now();
|
|
346
|
+
if (typeof pid === "number") state.record.osPid = pid;
|
|
347
|
+
state.record.lastActivityAt = Date.now();
|
|
348
|
+
return this.cloneRecord(state.record);
|
|
349
|
+
}
|
|
350
|
+
markStopped(sessionId, lifecycle = "stopped") {
|
|
351
|
+
const state = this.requireSession(sessionId);
|
|
352
|
+
state.record.lifecycle = lifecycle;
|
|
353
|
+
state.record.lastActivityAt = Date.now();
|
|
354
|
+
return this.cloneRecord(state.record);
|
|
355
|
+
}
|
|
356
|
+
setLifecycle(sessionId, lifecycle) {
|
|
357
|
+
const state = this.requireSession(sessionId);
|
|
358
|
+
state.record.lifecycle = lifecycle;
|
|
359
|
+
state.record.lastActivityAt = Date.now();
|
|
360
|
+
return this.cloneRecord(state.record);
|
|
361
|
+
}
|
|
362
|
+
requireSession(sessionId) {
|
|
363
|
+
const state = this.sessions.get(sessionId);
|
|
364
|
+
if (!state) throw new Error(`Unknown session: ${sessionId}`);
|
|
365
|
+
return state;
|
|
366
|
+
}
|
|
367
|
+
cloneRecord(record) {
|
|
368
|
+
return {
|
|
369
|
+
...record,
|
|
370
|
+
launchCommand: {
|
|
371
|
+
...record.launchCommand,
|
|
372
|
+
args: [...record.launchCommand.args],
|
|
373
|
+
env: record.launchCommand.env ? { ...record.launchCommand.env } : void 0
|
|
374
|
+
},
|
|
375
|
+
writeOwner: record.writeOwner ? { ...record.writeOwner } : null,
|
|
376
|
+
attachedClients: record.attachedClients.map((client) => ({ ...client })),
|
|
377
|
+
buffer: { ...record.buffer },
|
|
378
|
+
meta: { ...record.meta }
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
};
|
|
382
|
+
|
|
383
|
+
// src/ipc.ts
|
|
384
|
+
var os = __toESM(require("os"));
|
|
385
|
+
var path2 = __toESM(require("path"));
|
|
386
|
+
var net = __toESM(require("net"));
|
|
387
|
+
var import_crypto2 = require("crypto");
|
|
388
|
+
function getDefaultSessionHostEndpoint(appName = "adhdev") {
|
|
389
|
+
if (process.platform === "win32") {
|
|
390
|
+
return {
|
|
391
|
+
kind: "pipe",
|
|
392
|
+
path: `\\\\.\\pipe\\${appName}-session-host`
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
return {
|
|
396
|
+
kind: "unix",
|
|
397
|
+
path: path2.join(os.tmpdir(), `${appName}-session-host.sock`)
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
function serializeEnvelope(envelope) {
|
|
401
|
+
return `${JSON.stringify(envelope)}
|
|
402
|
+
`;
|
|
403
|
+
}
|
|
404
|
+
function createLineParser(onEnvelope) {
|
|
405
|
+
let buffer = "";
|
|
406
|
+
return (chunk) => {
|
|
407
|
+
buffer += chunk.toString();
|
|
408
|
+
let newlineIndex = buffer.indexOf("\n");
|
|
409
|
+
while (newlineIndex >= 0) {
|
|
410
|
+
const rawLine = buffer.slice(0, newlineIndex).trim();
|
|
411
|
+
buffer = buffer.slice(newlineIndex + 1);
|
|
412
|
+
if (rawLine) {
|
|
413
|
+
onEnvelope(JSON.parse(rawLine));
|
|
414
|
+
}
|
|
415
|
+
newlineIndex = buffer.indexOf("\n");
|
|
416
|
+
}
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
var SessionHostClient = class {
|
|
420
|
+
endpoint;
|
|
421
|
+
socket = null;
|
|
422
|
+
requestWaiters = /* @__PURE__ */ new Map();
|
|
423
|
+
eventListeners = /* @__PURE__ */ new Set();
|
|
424
|
+
constructor(options = {}) {
|
|
425
|
+
this.endpoint = options.endpoint || getDefaultSessionHostEndpoint(options.appName || "adhdev");
|
|
426
|
+
}
|
|
427
|
+
async connect() {
|
|
428
|
+
if (this.socket && !this.socket.destroyed) return;
|
|
429
|
+
const socket = net.createConnection(this.endpoint.path);
|
|
430
|
+
this.socket = socket;
|
|
431
|
+
socket.on("data", createLineParser((envelope) => {
|
|
432
|
+
if (envelope.kind === "response") {
|
|
433
|
+
const waiter = this.requestWaiters.get(envelope.requestId);
|
|
434
|
+
if (waiter) {
|
|
435
|
+
this.requestWaiters.delete(envelope.requestId);
|
|
436
|
+
waiter.resolve(envelope.response);
|
|
437
|
+
}
|
|
438
|
+
return;
|
|
439
|
+
}
|
|
440
|
+
if (envelope.kind === "event") {
|
|
441
|
+
for (const listener of this.eventListeners) listener(envelope.event);
|
|
442
|
+
}
|
|
443
|
+
}));
|
|
444
|
+
socket.on("error", (error) => {
|
|
445
|
+
for (const waiter of this.requestWaiters.values()) {
|
|
446
|
+
waiter.reject(error);
|
|
447
|
+
}
|
|
448
|
+
this.requestWaiters.clear();
|
|
449
|
+
});
|
|
450
|
+
await new Promise((resolve, reject) => {
|
|
451
|
+
socket.once("connect", () => resolve());
|
|
452
|
+
socket.once("error", reject);
|
|
453
|
+
});
|
|
454
|
+
}
|
|
455
|
+
onEvent(listener) {
|
|
456
|
+
this.eventListeners.add(listener);
|
|
457
|
+
return () => {
|
|
458
|
+
this.eventListeners.delete(listener);
|
|
459
|
+
};
|
|
460
|
+
}
|
|
461
|
+
async request(request) {
|
|
462
|
+
await this.connect();
|
|
463
|
+
if (!this.socket) throw new Error("Session host socket unavailable");
|
|
464
|
+
const requestId = (0, import_crypto2.randomUUID)();
|
|
465
|
+
const envelope = {
|
|
466
|
+
kind: "request",
|
|
467
|
+
requestId,
|
|
468
|
+
request
|
|
469
|
+
};
|
|
470
|
+
const response = await new Promise((resolve, reject) => {
|
|
471
|
+
this.requestWaiters.set(requestId, { resolve, reject });
|
|
472
|
+
this.socket?.write(serializeEnvelope(envelope));
|
|
473
|
+
});
|
|
474
|
+
return response;
|
|
475
|
+
}
|
|
476
|
+
async close() {
|
|
477
|
+
if (!this.socket) return;
|
|
478
|
+
const socket = this.socket;
|
|
479
|
+
this.socket = null;
|
|
480
|
+
for (const waiter of this.requestWaiters.values()) {
|
|
481
|
+
waiter.reject(new Error("Session host client closed"));
|
|
482
|
+
}
|
|
483
|
+
this.requestWaiters.clear();
|
|
484
|
+
await new Promise((resolve) => {
|
|
485
|
+
let settled = false;
|
|
486
|
+
const done = () => {
|
|
487
|
+
if (settled) return;
|
|
488
|
+
settled = true;
|
|
489
|
+
resolve();
|
|
490
|
+
};
|
|
491
|
+
socket.once("close", done);
|
|
492
|
+
socket.end();
|
|
493
|
+
socket.destroy();
|
|
494
|
+
setTimeout(done, 50);
|
|
495
|
+
});
|
|
496
|
+
}
|
|
497
|
+
};
|
|
498
|
+
function createResponseEnvelope(requestId, response) {
|
|
499
|
+
return {
|
|
500
|
+
kind: "response",
|
|
501
|
+
requestId,
|
|
502
|
+
response
|
|
503
|
+
};
|
|
504
|
+
}
|
|
505
|
+
function writeEnvelope(socket, envelope) {
|
|
506
|
+
socket.write(serializeEnvelope(envelope));
|
|
507
|
+
}
|
|
508
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
509
|
+
0 && (module.exports = {
|
|
510
|
+
SessionHostClient,
|
|
511
|
+
SessionHostRegistry,
|
|
512
|
+
SessionRingBuffer,
|
|
513
|
+
buildRuntimeDisplayName,
|
|
514
|
+
buildRuntimeKey,
|
|
515
|
+
createLineParser,
|
|
516
|
+
createResponseEnvelope,
|
|
517
|
+
formatRuntimeOwner,
|
|
518
|
+
getDefaultSessionHostEndpoint,
|
|
519
|
+
getWorkspaceLabel,
|
|
520
|
+
resolveRuntimeRecord,
|
|
521
|
+
writeEnvelope
|
|
522
|
+
});
|
|
523
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/buffer.ts","../src/registry.ts","../src/runtime-labels.ts","../src/ipc.ts"],"sourcesContent":["export type {\n AcquireWritePayload,\n AttachSessionPayload,\n ClearSessionBufferPayload,\n CreateSessionPayload,\n DetachSessionPayload,\n GetSnapshotPayload,\n ReleaseWritePayload,\n ResumeSessionPayload,\n ResizeSessionPayload,\n SendInputPayload,\n SessionAttachedClient,\n SessionBufferSnapshot,\n SessionClientType,\n SessionHostCategory,\n SessionHostEvent,\n SessionHostEventEnvelope,\n SessionHostRecord,\n SessionHostRequest,\n SessionHostRequestEnvelope,\n SessionHostResponse,\n SessionHostResponseEnvelope,\n SessionLaunchCommand,\n SessionLifecycle,\n SessionOwnerType,\n SessionTransport,\n SessionHostWireEnvelope,\n SessionWriteOwner,\n StopSessionPayload,\n} from './types.js';\n\nexport { SessionRingBuffer } from './buffer.js';\nexport type { SessionRingBufferOptions } from './buffer.js';\nexport { SessionHostRegistry } from './registry.js';\nexport {\n buildRuntimeDisplayName,\n buildRuntimeKey,\n formatRuntimeOwner,\n getWorkspaceLabel,\n resolveRuntimeRecord,\n} from './runtime-labels.js';\nexport {\n SessionHostClient,\n createLineParser,\n createResponseEnvelope,\n getDefaultSessionHostEndpoint,\n writeEnvelope,\n} from './ipc.js';\nexport type { SessionHostClientOptions, SessionHostEndpoint } from './ipc.js';\n","import type { SessionBufferSnapshot } from './types.js';\n\nexport interface SessionRingBufferOptions {\n maxBytes?: number;\n}\n\nexport class SessionRingBuffer {\n private maxBytes: number;\n private chunks: { seq: number; data: string; bytes: number }[] = [];\n private nextSeq = 1;\n private totalBytes = 0;\n\n constructor(options: SessionRingBufferOptions = {}) {\n this.maxBytes = options.maxBytes ?? 512 * 1024;\n }\n\n append(data: string): number {\n const normalized = typeof data === 'string' ? data : String(data ?? '');\n const bytes = Buffer.byteLength(normalized, 'utf8');\n const seq = this.nextSeq++;\n\n this.chunks.push({ seq, data: normalized, bytes });\n this.totalBytes += bytes;\n this.trim();\n return seq;\n }\n\n snapshot(sinceSeq?: number): SessionBufferSnapshot {\n const relevant = typeof sinceSeq === 'number'\n ? this.chunks.filter(chunk => chunk.seq > sinceSeq)\n : this.chunks;\n\n const text = relevant.map(chunk => chunk.data).join('');\n const truncated = !!this.chunks[0] && typeof sinceSeq === 'number' && sinceSeq < this.chunks[0].seq - 1;\n\n return {\n seq: this.nextSeq - 1,\n text,\n truncated,\n };\n }\n\n getState(): { scrollbackBytes: number; snapshotSeq: number } {\n return {\n scrollbackBytes: this.totalBytes,\n snapshotSeq: this.nextSeq - 1,\n };\n }\n\n clear(): void {\n this.chunks = [];\n this.totalBytes = 0;\n this.nextSeq = 1;\n }\n\n restore(snapshot: { seq: number; text: string }): void {\n this.clear();\n const text = String(snapshot.text || '');\n if (!text) {\n this.nextSeq = Math.max(1, Number(snapshot.seq || 0) + 1);\n return;\n }\n const bytes = Buffer.byteLength(text, 'utf8');\n const seq = Math.max(1, Number(snapshot.seq || 1));\n this.chunks = [{ seq, data: text, bytes }];\n this.totalBytes = bytes;\n this.nextSeq = seq + 1;\n this.trim();\n }\n\n private trim(): void {\n while (this.totalBytes > this.maxBytes && this.chunks.length > 1) {\n const removed = this.chunks.shift();\n if (!removed) break;\n this.totalBytes -= removed.bytes;\n }\n }\n}\n","import { randomUUID } from 'crypto';\nimport type {\n AcquireWritePayload,\n AttachSessionPayload,\n CreateSessionPayload,\n DetachSessionPayload,\n ReleaseWritePayload,\n SessionAttachedClient,\n SessionHostRecord,\n} from './types.js';\nimport { SessionRingBuffer } from './buffer.js';\nimport { buildRuntimeDisplayName, buildRuntimeKey, getWorkspaceLabel } from './runtime-labels.js';\n\ninterface SessionRuntimeState {\n record: SessionHostRecord;\n buffer: SessionRingBuffer;\n}\n\nexport class SessionHostRegistry {\n private sessions = new Map<string, SessionRuntimeState>();\n\n createSession(payload: CreateSessionPayload): SessionHostRecord {\n const sessionId = payload.sessionId || randomUUID();\n if (this.sessions.has(sessionId)) {\n throw new Error(`Session already exists: ${sessionId}`);\n }\n const now = Date.now();\n const initialClient = payload.clientId\n ? [{\n clientId: payload.clientId,\n type: payload.clientType || 'daemon',\n readOnly: false,\n attachedAt: now,\n lastSeenAt: now,\n } satisfies SessionAttachedClient]\n : [];\n\n const record: SessionHostRecord = {\n sessionId,\n runtimeKey: buildRuntimeKey(\n payload,\n Array.from(this.sessions.values(), (state) => state.record.runtimeKey),\n ),\n displayName: buildRuntimeDisplayName(payload),\n workspaceLabel: getWorkspaceLabel(payload.workspace),\n transport: 'pty',\n providerType: payload.providerType,\n category: payload.category,\n workspace: payload.workspace,\n launchCommand: payload.launchCommand,\n createdAt: now,\n lastActivityAt: now,\n lifecycle: 'starting',\n writeOwner: null,\n attachedClients: initialClient,\n buffer: {\n scrollbackBytes: 0,\n snapshotSeq: 0,\n },\n meta: payload.meta || {},\n };\n\n record.meta = {\n sessionHostCols: payload.cols || 120,\n sessionHostRows: payload.rows || 40,\n ...record.meta,\n };\n\n this.sessions.set(sessionId, {\n record,\n buffer: new SessionRingBuffer(),\n });\n\n return this.cloneRecord(record);\n }\n\n restoreSession(record: SessionHostRecord, snapshot?: { seq: number; text: string } | null): SessionHostRecord {\n const cloned = this.cloneRecord(record);\n this.sessions.set(cloned.sessionId, {\n record: cloned,\n buffer: (() => {\n const buffer = new SessionRingBuffer();\n if (snapshot) buffer.restore(snapshot);\n return buffer;\n })(),\n });\n return this.cloneRecord(cloned);\n }\n\n listSessions(): SessionHostRecord[] {\n return Array.from(this.sessions.values())\n .map(state => this.cloneRecord(state.record))\n .sort((a, b) => b.lastActivityAt - a.lastActivityAt);\n }\n\n getSession(sessionId: string): SessionHostRecord | null {\n const state = this.sessions.get(sessionId);\n return state ? this.cloneRecord(state.record) : null;\n }\n\n attachClient(payload: AttachSessionPayload): SessionHostRecord {\n const state = this.requireSession(payload.sessionId);\n const now = Date.now();\n let removedDaemonOwner = false;\n\n if (payload.clientType === 'daemon') {\n const staleDaemonClientIds = state.record.attachedClients\n .filter(client => client.type === 'daemon' && client.clientId !== payload.clientId)\n .map(client => client.clientId);\n if (staleDaemonClientIds.length > 0) {\n state.record.attachedClients = state.record.attachedClients.filter(\n client => !(client.type === 'daemon' && client.clientId !== payload.clientId),\n );\n if (state.record.writeOwner && staleDaemonClientIds.includes(state.record.writeOwner.clientId)) {\n removedDaemonOwner = true;\n }\n }\n }\n\n const existing = state.record.attachedClients.find(client => client.clientId === payload.clientId);\n\n if (existing) {\n existing.type = payload.clientType;\n existing.readOnly = !!payload.readOnly;\n existing.lastSeenAt = now;\n } else {\n state.record.attachedClients.push({\n clientId: payload.clientId,\n type: payload.clientType,\n readOnly: !!payload.readOnly,\n attachedAt: now,\n lastSeenAt: now,\n });\n }\n\n if (removedDaemonOwner) {\n state.record.writeOwner = null;\n }\n\n state.record.lastActivityAt = now;\n return this.cloneRecord(state.record);\n }\n\n detachClient(payload: DetachSessionPayload): SessionHostRecord {\n const state = this.requireSession(payload.sessionId);\n state.record.attachedClients = state.record.attachedClients.filter(client => client.clientId !== payload.clientId);\n if (state.record.writeOwner?.clientId === payload.clientId) {\n state.record.writeOwner = null;\n }\n state.record.lastActivityAt = Date.now();\n return this.cloneRecord(state.record);\n }\n\n acquireWrite(payload: AcquireWritePayload): SessionHostRecord {\n const state = this.requireSession(payload.sessionId);\n if (state.record.writeOwner && state.record.writeOwner.clientId !== payload.clientId && !payload.force) {\n throw new Error(`Write owned by ${state.record.writeOwner.clientId}`);\n }\n const attachedClient = state.record.attachedClients.find(client => client.clientId === payload.clientId);\n if (attachedClient) {\n attachedClient.readOnly = false;\n attachedClient.lastSeenAt = Date.now();\n }\n state.record.writeOwner = {\n clientId: payload.clientId,\n ownerType: payload.ownerType,\n acquiredAt: Date.now(),\n };\n state.record.lastActivityAt = Date.now();\n return this.cloneRecord(state.record);\n }\n\n releaseWrite(payload: ReleaseWritePayload): SessionHostRecord {\n const state = this.requireSession(payload.sessionId);\n const attachedClient = state.record.attachedClients.find(client => client.clientId === payload.clientId);\n if (attachedClient) {\n attachedClient.readOnly = false;\n attachedClient.lastSeenAt = Date.now();\n }\n if (state.record.writeOwner?.clientId === payload.clientId) {\n state.record.writeOwner = null;\n }\n state.record.lastActivityAt = Date.now();\n return this.cloneRecord(state.record);\n }\n\n appendOutput(sessionId: string, data: string): { record: SessionHostRecord; seq: number } {\n const state = this.requireSession(sessionId);\n const seq = state.buffer.append(data);\n state.record.buffer = state.buffer.getState();\n state.record.lastActivityAt = Date.now();\n return { record: this.cloneRecord(state.record), seq };\n }\n\n getSnapshot(sessionId: string, sinceSeq?: number) {\n const state = this.requireSession(sessionId);\n state.record.buffer = state.buffer.getState();\n return state.buffer.snapshot(sinceSeq);\n }\n\n clearBuffer(sessionId: string): SessionHostRecord {\n const state = this.requireSession(sessionId);\n state.buffer.clear();\n state.record.buffer = state.buffer.getState();\n state.record.lastActivityAt = Date.now();\n return this.cloneRecord(state.record);\n }\n\n markStarted(sessionId: string, pid?: number): SessionHostRecord {\n const state = this.requireSession(sessionId);\n state.record.lifecycle = 'running';\n state.record.startedAt = state.record.startedAt || Date.now();\n if (typeof pid === 'number') state.record.osPid = pid;\n state.record.lastActivityAt = Date.now();\n return this.cloneRecord(state.record);\n }\n\n markStopped(sessionId: string, lifecycle: 'stopped' | 'failed' = 'stopped'): SessionHostRecord {\n const state = this.requireSession(sessionId);\n state.record.lifecycle = lifecycle;\n state.record.lastActivityAt = Date.now();\n return this.cloneRecord(state.record);\n }\n\n setLifecycle(sessionId: string, lifecycle: 'starting' | 'running' | 'stopping' | 'stopped' | 'failed' | 'interrupted'): SessionHostRecord {\n const state = this.requireSession(sessionId);\n state.record.lifecycle = lifecycle;\n state.record.lastActivityAt = Date.now();\n return this.cloneRecord(state.record);\n }\n\n private requireSession(sessionId: string): SessionRuntimeState {\n const state = this.sessions.get(sessionId);\n if (!state) throw new Error(`Unknown session: ${sessionId}`);\n return state;\n }\n\n private cloneRecord(record: SessionHostRecord): SessionHostRecord {\n return {\n ...record,\n launchCommand: {\n ...record.launchCommand,\n args: [...record.launchCommand.args],\n env: record.launchCommand.env ? { ...record.launchCommand.env } : undefined,\n },\n writeOwner: record.writeOwner ? { ...record.writeOwner } : null,\n attachedClients: record.attachedClients.map(client => ({ ...client })),\n buffer: { ...record.buffer },\n meta: { ...record.meta },\n };\n }\n}\n","import * as path from 'path';\nimport type { CreateSessionPayload, SessionHostRecord } from './types.js';\n\nfunction normalizeSlug(input: string): string {\n return input\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n .slice(0, 48);\n}\n\nfunction normalizeValue(input: string): string {\n return input.trim().toLowerCase();\n}\n\nexport function getWorkspaceLabel(workspace: string): string {\n const trimmed = workspace.trim();\n if (!trimmed) return 'workspace';\n const normalized = trimmed.replace(/[\\\\/]+$/, '');\n const base = path.basename(normalized);\n return base || normalized;\n}\n\nexport function buildRuntimeDisplayName(payload: Pick<CreateSessionPayload, 'displayName' | 'providerType' | 'workspace'>): string {\n const explicit = payload.displayName?.trim();\n if (explicit) return explicit;\n const workspaceLabel = getWorkspaceLabel(payload.workspace);\n const providerLabel = payload.providerType.trim() || 'runtime';\n return `${providerLabel} @ ${workspaceLabel}`;\n}\n\nexport function buildRuntimeKey(\n payload: Pick<CreateSessionPayload, 'runtimeKey' | 'displayName' | 'providerType' | 'workspace'>,\n existingKeys: Iterable<string>,\n): string {\n const requested = payload.runtimeKey?.trim();\n const existing = new Set(Array.from(existingKeys, (key) => key.toLowerCase()));\n const displayName = buildRuntimeDisplayName(payload);\n const baseKey = normalizeSlug(requested || displayName || getWorkspaceLabel(payload.workspace) || payload.providerType || 'runtime') || 'runtime';\n if (!existing.has(baseKey)) return baseKey;\n\n let suffix = 2;\n let candidate = `${baseKey}-${suffix}`;\n while (existing.has(candidate)) {\n suffix += 1;\n candidate = `${baseKey}-${suffix}`;\n }\n return candidate;\n}\n\nfunction uniqueMatch(records: SessionHostRecord[], predicate: (record: SessionHostRecord) => boolean): SessionHostRecord | null {\n const matches = records.filter(predicate);\n if (matches.length === 1) return matches[0] || null;\n if (matches.length === 0) return null;\n const labels = matches.map((record) => `${record.runtimeKey} (${record.sessionId})`).join(', ');\n throw new Error(`Ambiguous runtime target. Matches: ${labels}`);\n}\n\nexport function resolveRuntimeRecord(records: SessionHostRecord[], identifier: string): SessionHostRecord {\n const target = identifier.trim();\n if (!target) {\n throw new Error('Runtime target is required');\n }\n\n const exact = uniqueMatch(records, (record) =>\n record.sessionId === target ||\n normalizeValue(record.runtimeKey) === normalizeValue(target) ||\n normalizeValue(record.displayName) === normalizeValue(target),\n );\n if (exact) return exact;\n\n const prefix = uniqueMatch(records, (record) =>\n record.sessionId.startsWith(target) ||\n normalizeValue(record.runtimeKey).startsWith(normalizeValue(target)),\n );\n if (prefix) return prefix;\n\n throw new Error(`Unknown runtime target: ${target}`);\n}\n\nexport function formatRuntimeOwner(record: Pick<SessionHostRecord, 'writeOwner'>): string {\n if (!record.writeOwner) return 'none';\n return `${record.writeOwner.ownerType}:${record.writeOwner.clientId}`;\n}\n","import * as os from 'os';\nimport * as path from 'path';\nimport * as net from 'net';\nimport { randomUUID } from 'crypto';\nimport type {\n SessionHostEvent,\n SessionHostRequest,\n SessionHostRequestEnvelope,\n SessionHostResponse,\n SessionHostResponseEnvelope,\n SessionHostWireEnvelope,\n} from './types.js';\n\nexport interface SessionHostEndpoint {\n kind: 'unix' | 'pipe';\n path: string;\n}\n\nexport function getDefaultSessionHostEndpoint(appName = 'adhdev'): SessionHostEndpoint {\n if (process.platform === 'win32') {\n return {\n kind: 'pipe',\n path: `\\\\\\\\.\\\\pipe\\\\${appName}-session-host`,\n };\n }\n\n return {\n kind: 'unix',\n path: path.join(os.tmpdir(), `${appName}-session-host.sock`),\n };\n}\n\nfunction serializeEnvelope(envelope: SessionHostWireEnvelope): string {\n return `${JSON.stringify(envelope)}\\n`;\n}\n\nfunction createLineParser(onEnvelope: (envelope: SessionHostWireEnvelope) => void) {\n let buffer = '';\n return (chunk: Buffer | string) => {\n buffer += chunk.toString();\n let newlineIndex = buffer.indexOf('\\n');\n while (newlineIndex >= 0) {\n const rawLine = buffer.slice(0, newlineIndex).trim();\n buffer = buffer.slice(newlineIndex + 1);\n if (rawLine) {\n onEnvelope(JSON.parse(rawLine) as SessionHostWireEnvelope);\n }\n newlineIndex = buffer.indexOf('\\n');\n }\n };\n}\n\nexport interface SessionHostClientOptions {\n endpoint?: SessionHostEndpoint;\n appName?: string;\n}\n\nexport class SessionHostClient {\n readonly endpoint: SessionHostEndpoint;\n\n private socket: net.Socket | null = null;\n private requestWaiters = new Map<string, { resolve: (value: SessionHostResponse) => void; reject: (error: Error) => void }>();\n private eventListeners = new Set<(event: SessionHostEvent) => void>();\n\n constructor(options: SessionHostClientOptions = {}) {\n this.endpoint = options.endpoint || getDefaultSessionHostEndpoint(options.appName || 'adhdev');\n }\n\n async connect(): Promise<void> {\n if (this.socket && !this.socket.destroyed) return;\n\n const socket = net.createConnection(this.endpoint.path);\n this.socket = socket;\n\n socket.on('data', createLineParser((envelope) => {\n if (envelope.kind === 'response') {\n const waiter = this.requestWaiters.get(envelope.requestId);\n if (waiter) {\n this.requestWaiters.delete(envelope.requestId);\n waiter.resolve(envelope.response);\n }\n return;\n }\n\n if (envelope.kind === 'event') {\n for (const listener of this.eventListeners) listener(envelope.event);\n }\n }));\n\n socket.on('error', (error) => {\n for (const waiter of this.requestWaiters.values()) {\n waiter.reject(error);\n }\n this.requestWaiters.clear();\n });\n\n await new Promise<void>((resolve, reject) => {\n socket.once('connect', () => resolve());\n socket.once('error', reject);\n });\n }\n\n onEvent(listener: (event: SessionHostEvent) => void): () => void {\n this.eventListeners.add(listener);\n return () => {\n this.eventListeners.delete(listener);\n };\n }\n\n async request<T = unknown>(request: SessionHostRequest): Promise<SessionHostResponse<T>> {\n await this.connect();\n if (!this.socket) throw new Error('Session host socket unavailable');\n\n const requestId = randomUUID();\n const envelope: SessionHostRequestEnvelope = {\n kind: 'request',\n requestId,\n request,\n };\n\n const response = await new Promise<SessionHostResponse>((resolve, reject) => {\n this.requestWaiters.set(requestId, { resolve, reject });\n this.socket?.write(serializeEnvelope(envelope));\n });\n\n return response as SessionHostResponse<T>;\n }\n\n async close(): Promise<void> {\n if (!this.socket) return;\n const socket = this.socket;\n this.socket = null;\n for (const waiter of this.requestWaiters.values()) {\n waiter.reject(new Error('Session host client closed'));\n }\n this.requestWaiters.clear();\n await new Promise<void>((resolve) => {\n let settled = false;\n const done = () => {\n if (settled) return;\n settled = true;\n resolve();\n };\n socket.once('close', done);\n socket.end();\n socket.destroy();\n setTimeout(done, 50);\n });\n }\n}\n\nexport function createResponseEnvelope(requestId: string, response: SessionHostResponse): SessionHostResponseEnvelope {\n return {\n kind: 'response',\n requestId,\n response,\n };\n}\n\nexport function writeEnvelope(socket: Pick<net.Socket, 'write'>, envelope: SessionHostWireEnvelope): void {\n socket.write(serializeEnvelope(envelope));\n}\n\nexport { createLineParser };\n"],"mappings":"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","names":["path","import_crypto"]}
|