adhdev 0.8.50 → 0.8.52

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 (41) hide show
  1. package/dist/cli/index.js +30 -5
  2. package/dist/cli/index.js.map +1 -1
  3. package/dist/index.js +30 -5
  4. package/dist/index.js.map +1 -1
  5. package/package.json +3 -2
  6. package/vendor/terminal-mux-cli/index.d.mts +1 -0
  7. package/vendor/terminal-mux-cli/index.d.ts +1 -0
  8. package/vendor/terminal-mux-cli/index.js +2056 -0
  9. package/vendor/terminal-mux-cli/index.mjs +2048 -0
  10. package/vendor/terminal-mux-cli/node_modules/@adhdev/session-host-core/index.d.mts +427 -0
  11. package/vendor/terminal-mux-cli/node_modules/@adhdev/session-host-core/index.d.ts +427 -0
  12. package/vendor/terminal-mux-cli/node_modules/@adhdev/session-host-core/index.js +617 -0
  13. package/vendor/terminal-mux-cli/node_modules/@adhdev/session-host-core/index.js.map +1 -0
  14. package/vendor/terminal-mux-cli/node_modules/@adhdev/session-host-core/index.mjs +573 -0
  15. package/vendor/terminal-mux-cli/node_modules/@adhdev/session-host-core/index.mjs.map +1 -0
  16. package/vendor/terminal-mux-cli/node_modules/@adhdev/session-host-core/package.json +7 -0
  17. package/vendor/terminal-mux-cli/node_modules/@adhdev/terminal-mux-control/api.d.mts +16 -0
  18. package/vendor/terminal-mux-cli/node_modules/@adhdev/terminal-mux-control/api.d.ts +16 -0
  19. package/vendor/terminal-mux-cli/node_modules/@adhdev/terminal-mux-control/api.js +206 -0
  20. package/vendor/terminal-mux-cli/node_modules/@adhdev/terminal-mux-control/api.mjs +17 -0
  21. package/vendor/terminal-mux-cli/node_modules/@adhdev/terminal-mux-control/chunk-7RNMRPVZ.mjs +183 -0
  22. package/vendor/terminal-mux-cli/node_modules/@adhdev/terminal-mux-control/chunk-R4EFW6W3.mjs +46 -0
  23. package/vendor/terminal-mux-cli/node_modules/@adhdev/terminal-mux-control/chunk-XZWWVN5W.mjs +164 -0
  24. package/vendor/terminal-mux-cli/node_modules/@adhdev/terminal-mux-control/control-socket.d.mts +35 -0
  25. package/vendor/terminal-mux-cli/node_modules/@adhdev/terminal-mux-control/control-socket.d.ts +35 -0
  26. package/vendor/terminal-mux-cli/node_modules/@adhdev/terminal-mux-control/control-socket.js +219 -0
  27. package/vendor/terminal-mux-cli/node_modules/@adhdev/terminal-mux-control/control-socket.mjs +13 -0
  28. package/vendor/terminal-mux-cli/node_modules/@adhdev/terminal-mux-control/index.d.mts +5 -0
  29. package/vendor/terminal-mux-cli/node_modules/@adhdev/terminal-mux-control/index.d.ts +5 -0
  30. package/vendor/terminal-mux-cli/node_modules/@adhdev/terminal-mux-control/index.js +427 -0
  31. package/vendor/terminal-mux-cli/node_modules/@adhdev/terminal-mux-control/index.mjs +34 -0
  32. package/vendor/terminal-mux-cli/node_modules/@adhdev/terminal-mux-control/package.json +33 -0
  33. package/vendor/terminal-mux-cli/node_modules/@adhdev/terminal-mux-control/storage.d.mts +49 -0
  34. package/vendor/terminal-mux-cli/node_modules/@adhdev/terminal-mux-control/storage.d.ts +49 -0
  35. package/vendor/terminal-mux-cli/node_modules/@adhdev/terminal-mux-control/storage.js +222 -0
  36. package/vendor/terminal-mux-cli/node_modules/@adhdev/terminal-mux-control/storage.mjs +16 -0
  37. package/vendor/terminal-mux-cli/node_modules/@adhdev/terminal-mux-core/index.d.mts +162 -0
  38. package/vendor/terminal-mux-cli/node_modules/@adhdev/terminal-mux-core/index.d.ts +162 -0
  39. package/vendor/terminal-mux-cli/node_modules/@adhdev/terminal-mux-core/index.js +985 -0
  40. package/vendor/terminal-mux-cli/node_modules/@adhdev/terminal-mux-core/index.mjs +948 -0
  41. package/vendor/terminal-mux-cli/node_modules/@adhdev/terminal-mux-core/package.json +7 -0
@@ -0,0 +1,617 @@
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
+ applyTerminalColorEnv: () => applyTerminalColorEnv,
37
+ buildRuntimeDisplayName: () => buildRuntimeDisplayName,
38
+ buildRuntimeKey: () => buildRuntimeKey,
39
+ createLineParser: () => createLineParser,
40
+ createResponseEnvelope: () => createResponseEnvelope,
41
+ ensureNodePtySpawnHelperPermissions: () => ensureNodePtySpawnHelperPermissions,
42
+ formatRuntimeOwner: () => formatRuntimeOwner,
43
+ getDefaultSessionHostEndpoint: () => getDefaultSessionHostEndpoint,
44
+ getWorkspaceLabel: () => getWorkspaceLabel,
45
+ resolveRuntimeRecord: () => resolveRuntimeRecord,
46
+ sanitizeSpawnEnv: () => sanitizeSpawnEnv,
47
+ writeEnvelope: () => writeEnvelope
48
+ });
49
+ module.exports = __toCommonJS(index_exports);
50
+
51
+ // src/buffer.ts
52
+ var SessionRingBuffer = class {
53
+ maxBytes;
54
+ chunks = [];
55
+ nextSeq = 1;
56
+ totalBytes = 0;
57
+ constructor(options = {}) {
58
+ this.maxBytes = options.maxBytes ?? 512 * 1024;
59
+ }
60
+ append(data) {
61
+ const normalized = typeof data === "string" ? data : String(data ?? "");
62
+ const bytes = Buffer.byteLength(normalized, "utf8");
63
+ const seq = this.nextSeq++;
64
+ this.chunks.push({ seq, data: normalized, bytes });
65
+ this.totalBytes += bytes;
66
+ this.trim();
67
+ return seq;
68
+ }
69
+ snapshot(sinceSeq) {
70
+ const relevant = typeof sinceSeq === "number" ? this.chunks.filter((chunk) => chunk.seq > sinceSeq) : this.chunks;
71
+ const text = relevant.map((chunk) => chunk.data).join("");
72
+ const truncated = !!this.chunks[0] && typeof sinceSeq === "number" && sinceSeq < this.chunks[0].seq - 1;
73
+ return {
74
+ seq: this.nextSeq - 1,
75
+ text,
76
+ truncated
77
+ };
78
+ }
79
+ getState() {
80
+ return {
81
+ scrollbackBytes: this.totalBytes,
82
+ snapshotSeq: this.nextSeq - 1
83
+ };
84
+ }
85
+ clear() {
86
+ this.chunks = [];
87
+ this.totalBytes = 0;
88
+ this.nextSeq = 1;
89
+ }
90
+ restore(snapshot) {
91
+ this.clear();
92
+ const text = String(snapshot.text || "");
93
+ if (!text) {
94
+ this.nextSeq = Math.max(1, Number(snapshot.seq || 0) + 1);
95
+ return;
96
+ }
97
+ const bytes = Buffer.byteLength(text, "utf8");
98
+ const seq = Math.max(1, Number(snapshot.seq || 1));
99
+ this.chunks = [{ seq, data: text, bytes }];
100
+ this.totalBytes = bytes;
101
+ this.nextSeq = seq + 1;
102
+ this.trim();
103
+ }
104
+ trim() {
105
+ while (this.totalBytes > this.maxBytes && this.chunks.length > 1) {
106
+ const removed = this.chunks.shift();
107
+ if (!removed) break;
108
+ this.totalBytes -= removed.bytes;
109
+ }
110
+ }
111
+ };
112
+
113
+ // src/registry.ts
114
+ var import_crypto = require("crypto");
115
+
116
+ // src/runtime-labels.ts
117
+ var path = __toESM(require("path"));
118
+ function normalizeSlug(input) {
119
+ return input.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48);
120
+ }
121
+ function normalizeValue(input) {
122
+ return input.trim().toLowerCase();
123
+ }
124
+ function getWorkspaceLabel(workspace) {
125
+ const trimmed = workspace.trim();
126
+ if (!trimmed) return "workspace";
127
+ const normalized = trimmed.replace(/[\\/]+$/, "");
128
+ const base = path.basename(normalized);
129
+ return base || normalized;
130
+ }
131
+ function buildRuntimeDisplayName(payload) {
132
+ const explicit = payload.displayName?.trim();
133
+ if (explicit) return explicit;
134
+ const workspaceLabel = getWorkspaceLabel(payload.workspace);
135
+ const providerLabel = payload.providerType.trim() || "runtime";
136
+ return `${providerLabel} @ ${workspaceLabel}`;
137
+ }
138
+ function buildRuntimeKey(payload, existingKeys) {
139
+ const requested = payload.runtimeKey?.trim();
140
+ const existing = new Set(Array.from(existingKeys, (key) => key.toLowerCase()));
141
+ const displayName = buildRuntimeDisplayName(payload);
142
+ const baseKey = normalizeSlug(requested || displayName || getWorkspaceLabel(payload.workspace) || payload.providerType || "runtime") || "runtime";
143
+ if (!existing.has(baseKey)) return baseKey;
144
+ let suffix = 2;
145
+ let candidate = `${baseKey}-${suffix}`;
146
+ while (existing.has(candidate)) {
147
+ suffix += 1;
148
+ candidate = `${baseKey}-${suffix}`;
149
+ }
150
+ return candidate;
151
+ }
152
+ function uniqueMatch(records, predicate) {
153
+ const matches = records.filter(predicate);
154
+ if (matches.length === 1) return matches[0] || null;
155
+ if (matches.length === 0) return null;
156
+ const labels = matches.map((record) => `${record.runtimeKey} (${record.sessionId})`).join(", ");
157
+ throw new Error(`Ambiguous runtime target. Matches: ${labels}`);
158
+ }
159
+ function resolveRuntimeRecord(records, identifier) {
160
+ const target = identifier.trim();
161
+ if (!target) {
162
+ throw new Error("Runtime target is required");
163
+ }
164
+ const exact = uniqueMatch(
165
+ records,
166
+ (record) => record.sessionId === target || normalizeValue(record.runtimeKey) === normalizeValue(target) || normalizeValue(record.displayName) === normalizeValue(target)
167
+ );
168
+ if (exact) return exact;
169
+ const prefix = uniqueMatch(
170
+ records,
171
+ (record) => record.sessionId.startsWith(target) || normalizeValue(record.runtimeKey).startsWith(normalizeValue(target))
172
+ );
173
+ if (prefix) return prefix;
174
+ throw new Error(`Unknown runtime target: ${target}`);
175
+ }
176
+ function formatRuntimeOwner(record) {
177
+ if (!record.writeOwner) return "none";
178
+ return `${record.writeOwner.ownerType}:${record.writeOwner.clientId}`;
179
+ }
180
+
181
+ // src/registry.ts
182
+ var SessionHostRegistry = class {
183
+ sessions = /* @__PURE__ */ new Map();
184
+ createSession(payload) {
185
+ const sessionId = payload.sessionId || (0, import_crypto.randomUUID)();
186
+ if (this.sessions.has(sessionId)) {
187
+ throw new Error(`Session already exists: ${sessionId}`);
188
+ }
189
+ const now = Date.now();
190
+ const initialClient = payload.clientId ? [{
191
+ clientId: payload.clientId,
192
+ type: payload.clientType || "daemon",
193
+ readOnly: false,
194
+ attachedAt: now,
195
+ lastSeenAt: now
196
+ }] : [];
197
+ const record = {
198
+ sessionId,
199
+ runtimeKey: buildRuntimeKey(
200
+ payload,
201
+ Array.from(this.sessions.values(), (state) => state.record.runtimeKey)
202
+ ),
203
+ displayName: buildRuntimeDisplayName(payload),
204
+ workspaceLabel: getWorkspaceLabel(payload.workspace),
205
+ transport: "pty",
206
+ providerType: payload.providerType,
207
+ category: payload.category,
208
+ workspace: payload.workspace,
209
+ launchCommand: payload.launchCommand,
210
+ createdAt: now,
211
+ lastActivityAt: now,
212
+ lifecycle: "starting",
213
+ writeOwner: null,
214
+ attachedClients: initialClient,
215
+ buffer: {
216
+ scrollbackBytes: 0,
217
+ snapshotSeq: 0
218
+ },
219
+ meta: payload.meta || {}
220
+ };
221
+ record.meta = {
222
+ sessionHostCols: payload.cols || 80,
223
+ sessionHostRows: payload.rows || 24,
224
+ ...record.meta
225
+ };
226
+ this.sessions.set(sessionId, {
227
+ record,
228
+ buffer: new SessionRingBuffer()
229
+ });
230
+ return this.cloneRecord(record);
231
+ }
232
+ restoreSession(record, snapshot) {
233
+ const cloned = this.cloneRecord(record);
234
+ this.sessions.set(cloned.sessionId, {
235
+ record: cloned,
236
+ buffer: (() => {
237
+ const buffer = new SessionRingBuffer();
238
+ if (snapshot) buffer.restore(snapshot);
239
+ return buffer;
240
+ })()
241
+ });
242
+ return this.cloneRecord(cloned);
243
+ }
244
+ listSessions() {
245
+ return Array.from(this.sessions.values()).map((state) => this.cloneRecord(state.record)).sort((a, b) => b.lastActivityAt - a.lastActivityAt);
246
+ }
247
+ getSession(sessionId) {
248
+ const state = this.sessions.get(sessionId);
249
+ return state ? this.cloneRecord(state.record) : null;
250
+ }
251
+ attachClient(payload) {
252
+ const state = this.requireSession(payload.sessionId);
253
+ const now = Date.now();
254
+ let removedDaemonOwner = false;
255
+ if (payload.clientType === "daemon") {
256
+ const staleDaemonClientIds = state.record.attachedClients.filter((client) => client.type === "daemon" && client.clientId !== payload.clientId).map((client) => client.clientId);
257
+ if (staleDaemonClientIds.length > 0) {
258
+ state.record.attachedClients = state.record.attachedClients.filter(
259
+ (client) => !(client.type === "daemon" && client.clientId !== payload.clientId)
260
+ );
261
+ if (state.record.writeOwner && staleDaemonClientIds.includes(state.record.writeOwner.clientId)) {
262
+ removedDaemonOwner = true;
263
+ }
264
+ }
265
+ }
266
+ const existing = state.record.attachedClients.find((client) => client.clientId === payload.clientId);
267
+ if (existing) {
268
+ existing.type = payload.clientType;
269
+ existing.readOnly = !!payload.readOnly;
270
+ existing.lastSeenAt = now;
271
+ } else {
272
+ state.record.attachedClients.push({
273
+ clientId: payload.clientId,
274
+ type: payload.clientType,
275
+ readOnly: !!payload.readOnly,
276
+ attachedAt: now,
277
+ lastSeenAt: now
278
+ });
279
+ }
280
+ if (removedDaemonOwner) {
281
+ state.record.writeOwner = null;
282
+ }
283
+ state.record.lastActivityAt = now;
284
+ return this.cloneRecord(state.record);
285
+ }
286
+ detachClient(payload) {
287
+ const state = this.requireSession(payload.sessionId);
288
+ state.record.attachedClients = state.record.attachedClients.filter((client) => client.clientId !== payload.clientId);
289
+ if (state.record.writeOwner?.clientId === payload.clientId) {
290
+ state.record.writeOwner = null;
291
+ }
292
+ state.record.lastActivityAt = Date.now();
293
+ return this.cloneRecord(state.record);
294
+ }
295
+ acquireWrite(payload) {
296
+ const state = this.requireSession(payload.sessionId);
297
+ if (state.record.writeOwner && state.record.writeOwner.clientId !== payload.clientId && !payload.force) {
298
+ throw new Error(`Write owned by ${state.record.writeOwner.clientId}`);
299
+ }
300
+ const attachedClient = state.record.attachedClients.find((client) => client.clientId === payload.clientId);
301
+ if (attachedClient) {
302
+ attachedClient.readOnly = false;
303
+ attachedClient.lastSeenAt = Date.now();
304
+ }
305
+ state.record.writeOwner = {
306
+ clientId: payload.clientId,
307
+ ownerType: payload.ownerType,
308
+ acquiredAt: Date.now()
309
+ };
310
+ state.record.lastActivityAt = Date.now();
311
+ return this.cloneRecord(state.record);
312
+ }
313
+ releaseWrite(payload) {
314
+ const state = this.requireSession(payload.sessionId);
315
+ const attachedClient = state.record.attachedClients.find((client) => client.clientId === payload.clientId);
316
+ if (attachedClient) {
317
+ attachedClient.readOnly = false;
318
+ attachedClient.lastSeenAt = Date.now();
319
+ }
320
+ if (state.record.writeOwner?.clientId === payload.clientId) {
321
+ state.record.writeOwner = null;
322
+ }
323
+ state.record.lastActivityAt = Date.now();
324
+ return this.cloneRecord(state.record);
325
+ }
326
+ appendOutput(sessionId, data) {
327
+ const state = this.requireSession(sessionId);
328
+ const seq = state.buffer.append(data);
329
+ state.record.buffer = state.buffer.getState();
330
+ state.record.lastActivityAt = Date.now();
331
+ return { record: this.cloneRecord(state.record), seq };
332
+ }
333
+ getSnapshot(sessionId, sinceSeq) {
334
+ const state = this.requireSession(sessionId);
335
+ state.record.buffer = state.buffer.getState();
336
+ return state.buffer.snapshot(sinceSeq);
337
+ }
338
+ clearBuffer(sessionId) {
339
+ const state = this.requireSession(sessionId);
340
+ state.buffer.clear();
341
+ state.record.buffer = state.buffer.getState();
342
+ state.record.lastActivityAt = Date.now();
343
+ return this.cloneRecord(state.record);
344
+ }
345
+ updateSessionMeta(sessionId, meta, replace = false) {
346
+ const state = this.requireSession(sessionId);
347
+ state.record.meta = replace ? { ...meta } : {
348
+ ...state.record.meta || {},
349
+ ...meta
350
+ };
351
+ state.record.lastActivityAt = Date.now();
352
+ return this.cloneRecord(state.record);
353
+ }
354
+ markStarted(sessionId, pid) {
355
+ const state = this.requireSession(sessionId);
356
+ state.record.lifecycle = "running";
357
+ state.record.startedAt = state.record.startedAt || Date.now();
358
+ if (typeof pid === "number") state.record.osPid = pid;
359
+ state.record.lastActivityAt = Date.now();
360
+ return this.cloneRecord(state.record);
361
+ }
362
+ markStopped(sessionId, lifecycle = "stopped") {
363
+ const state = this.requireSession(sessionId);
364
+ state.record.lifecycle = lifecycle;
365
+ state.record.lastActivityAt = Date.now();
366
+ return this.cloneRecord(state.record);
367
+ }
368
+ setLifecycle(sessionId, lifecycle) {
369
+ const state = this.requireSession(sessionId);
370
+ state.record.lifecycle = lifecycle;
371
+ state.record.lastActivityAt = Date.now();
372
+ return this.cloneRecord(state.record);
373
+ }
374
+ deleteSession(sessionId) {
375
+ return this.sessions.delete(sessionId);
376
+ }
377
+ requireSession(sessionId) {
378
+ const state = this.sessions.get(sessionId);
379
+ if (!state) throw new Error(`Unknown session: ${sessionId}`);
380
+ return state;
381
+ }
382
+ cloneRecord(record) {
383
+ return {
384
+ ...record,
385
+ launchCommand: {
386
+ ...record.launchCommand,
387
+ args: [...record.launchCommand.args],
388
+ env: record.launchCommand.env ? { ...record.launchCommand.env } : void 0
389
+ },
390
+ writeOwner: record.writeOwner ? { ...record.writeOwner } : null,
391
+ attachedClients: record.attachedClients.map((client) => ({ ...client })),
392
+ buffer: { ...record.buffer },
393
+ meta: { ...record.meta }
394
+ };
395
+ }
396
+ };
397
+
398
+ // src/ipc.ts
399
+ var os = __toESM(require("os"));
400
+ var path2 = __toESM(require("path"));
401
+ var net = __toESM(require("net"));
402
+ var import_crypto2 = require("crypto");
403
+ function getDefaultSessionHostEndpoint(appName = "adhdev") {
404
+ if (process.platform === "win32") {
405
+ return {
406
+ kind: "pipe",
407
+ path: `\\\\.\\pipe\\${appName}-session-host`
408
+ };
409
+ }
410
+ return {
411
+ kind: "unix",
412
+ path: path2.join(os.tmpdir(), `${appName}-session-host.sock`)
413
+ };
414
+ }
415
+ function serializeEnvelope(envelope) {
416
+ return `${JSON.stringify(envelope)}
417
+ `;
418
+ }
419
+ function createLineParser(onEnvelope) {
420
+ let buffer = "";
421
+ return (chunk) => {
422
+ buffer += chunk.toString();
423
+ let newlineIndex = buffer.indexOf("\n");
424
+ while (newlineIndex >= 0) {
425
+ const rawLine = buffer.slice(0, newlineIndex).trim();
426
+ buffer = buffer.slice(newlineIndex + 1);
427
+ if (rawLine) {
428
+ onEnvelope(JSON.parse(rawLine));
429
+ }
430
+ newlineIndex = buffer.indexOf("\n");
431
+ }
432
+ };
433
+ }
434
+ var SessionHostClient = class {
435
+ endpoint;
436
+ socket = null;
437
+ requestWaiters = /* @__PURE__ */ new Map();
438
+ eventListeners = /* @__PURE__ */ new Set();
439
+ constructor(options = {}) {
440
+ this.endpoint = options.endpoint || getDefaultSessionHostEndpoint(options.appName || "adhdev");
441
+ }
442
+ async connect() {
443
+ if (this.socket && !this.socket.destroyed) return;
444
+ if (this.socket) {
445
+ try {
446
+ this.socket.destroy();
447
+ } catch {
448
+ }
449
+ this.socket = null;
450
+ }
451
+ const socket = net.createConnection(this.endpoint.path);
452
+ this.socket = socket;
453
+ socket.on("data", createLineParser((envelope) => {
454
+ if (envelope.kind === "response") {
455
+ const waiter = this.requestWaiters.get(envelope.requestId);
456
+ if (waiter) {
457
+ this.requestWaiters.delete(envelope.requestId);
458
+ waiter.resolve(envelope.response);
459
+ }
460
+ return;
461
+ }
462
+ if (envelope.kind === "event") {
463
+ for (const listener of this.eventListeners) listener(envelope.event);
464
+ }
465
+ }));
466
+ socket.on("error", (error) => {
467
+ for (const waiter of this.requestWaiters.values()) {
468
+ waiter.reject(error);
469
+ }
470
+ this.requestWaiters.clear();
471
+ if (this.socket === socket) {
472
+ this.socket = null;
473
+ }
474
+ try {
475
+ socket.destroy();
476
+ } catch {
477
+ }
478
+ });
479
+ await new Promise((resolve2, reject) => {
480
+ socket.once("connect", () => resolve2());
481
+ socket.once("error", reject);
482
+ });
483
+ }
484
+ onEvent(listener) {
485
+ this.eventListeners.add(listener);
486
+ return () => {
487
+ this.eventListeners.delete(listener);
488
+ };
489
+ }
490
+ async request(request) {
491
+ await this.connect();
492
+ if (!this.socket) throw new Error("Session host socket unavailable");
493
+ const requestId = (0, import_crypto2.randomUUID)();
494
+ const envelope = {
495
+ kind: "request",
496
+ requestId,
497
+ request
498
+ };
499
+ const response = await new Promise((resolve2, reject) => {
500
+ const timeout = setTimeout(() => {
501
+ this.requestWaiters.delete(requestId);
502
+ reject(new Error(`Session host request timed out after 30s (${request.type})`));
503
+ }, 3e4);
504
+ this.requestWaiters.set(requestId, {
505
+ resolve: (value) => {
506
+ clearTimeout(timeout);
507
+ resolve2(value);
508
+ },
509
+ reject: (error) => {
510
+ clearTimeout(timeout);
511
+ reject(error);
512
+ }
513
+ });
514
+ this.socket?.write(serializeEnvelope(envelope));
515
+ });
516
+ return response;
517
+ }
518
+ async close() {
519
+ if (!this.socket) return;
520
+ const socket = this.socket;
521
+ this.socket = null;
522
+ for (const waiter of this.requestWaiters.values()) {
523
+ waiter.reject(new Error("Session host client closed"));
524
+ }
525
+ this.requestWaiters.clear();
526
+ await new Promise((resolve2) => {
527
+ let settled = false;
528
+ const done = () => {
529
+ if (settled) return;
530
+ settled = true;
531
+ resolve2();
532
+ };
533
+ socket.once("close", done);
534
+ socket.end();
535
+ socket.destroy();
536
+ setTimeout(done, 50);
537
+ });
538
+ }
539
+ };
540
+ function createResponseEnvelope(requestId, response) {
541
+ return {
542
+ kind: "response",
543
+ requestId,
544
+ response
545
+ };
546
+ }
547
+ function writeEnvelope(socket, envelope) {
548
+ socket.write(serializeEnvelope(envelope));
549
+ }
550
+
551
+ // src/spawn-env.ts
552
+ var os2 = __toESM(require("os"));
553
+ var path3 = __toESM(require("path"));
554
+ function sanitizeSpawnEnv(baseEnv, overrides) {
555
+ const env = {};
556
+ const source = { ...baseEnv, ...overrides || {} };
557
+ for (const [key, value] of Object.entries(source)) {
558
+ if (typeof value !== "string") continue;
559
+ env[key] = value;
560
+ }
561
+ for (const key of Object.keys(env)) {
562
+ if (key === "INIT_CWD" || key === "npm_command" || key === "npm_execpath" || key === "npm_node_execpath" || key.startsWith("npm_") || key.startsWith("npm_config_") || key.startsWith("npm_package_") || key.startsWith("npm_lifecycle_") || key.startsWith("PNPM_") || key.startsWith("YARN_") || key.startsWith("BUN_") || key.startsWith("VSCODE_") || key.startsWith("ELECTRON_")) {
563
+ delete env[key];
564
+ }
565
+ }
566
+ delete env.CODEX_THREAD_ID;
567
+ delete env.CODEX_INTERNAL_ORIGINATOR_OVERRIDE;
568
+ applyTerminalColorEnv(env);
569
+ return env;
570
+ }
571
+ function applyTerminalColorEnv(env) {
572
+ if (env.NO_COLOR) return;
573
+ if (!env.TERM || env.TERM === "xterm-color") {
574
+ env.TERM = "xterm-256color";
575
+ }
576
+ if (!env.COLORTERM) env.COLORTERM = "truecolor";
577
+ if (process.platform === "win32") {
578
+ if (!env.FORCE_COLOR) env.FORCE_COLOR = "1";
579
+ if (!env.CLICOLOR) env.CLICOLOR = "1";
580
+ }
581
+ }
582
+ function ensureNodePtySpawnHelperPermissions(logFn) {
583
+ if (os2.platform() === "win32") return;
584
+ try {
585
+ const fs = require("fs");
586
+ const ptyDir = path3.resolve(path3.dirname(require.resolve("node-pty")), "..");
587
+ const platformArch = `${os2.platform()}-${os2.arch()}`;
588
+ const helper = path3.join(ptyDir, "prebuilds", platformArch, "spawn-helper");
589
+ if (fs.existsSync(helper)) {
590
+ const stat = fs.statSync(helper);
591
+ if (!(stat.mode & 73)) {
592
+ fs.chmodSync(helper, stat.mode | 493);
593
+ logFn?.(`Fixed spawn-helper permissions: ${helper}`);
594
+ }
595
+ }
596
+ } catch {
597
+ }
598
+ }
599
+ // Annotate the CommonJS export names for ESM import in node:
600
+ 0 && (module.exports = {
601
+ SessionHostClient,
602
+ SessionHostRegistry,
603
+ SessionRingBuffer,
604
+ applyTerminalColorEnv,
605
+ buildRuntimeDisplayName,
606
+ buildRuntimeKey,
607
+ createLineParser,
608
+ createResponseEnvelope,
609
+ ensureNodePtySpawnHelperPermissions,
610
+ formatRuntimeOwner,
611
+ getDefaultSessionHostEndpoint,
612
+ getWorkspaceLabel,
613
+ resolveRuntimeRecord,
614
+ sanitizeSpawnEnv,
615
+ writeEnvelope
616
+ });
617
+ //# sourceMappingURL=index.js.map