@adhdev/session-host-core 0.9.76 → 0.9.78

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.js CHANGED
@@ -145,9 +145,6 @@ var SessionRingBuffer = class {
145
145
  }
146
146
  };
147
147
 
148
- // src/registry.ts
149
- var import_crypto = require("crypto");
150
-
151
148
  // src/defaults.ts
152
149
  var DEFAULT_SESSION_HOST_COLS = 80;
153
150
  var DEFAULT_SESSION_HOST_ROWS = 32;
@@ -278,10 +275,20 @@ function formatRuntimeOwner(record) {
278
275
  }
279
276
 
280
277
  // src/registry.ts
278
+ function generateUUID() {
279
+ if (typeof crypto !== "undefined" && crypto.randomUUID) {
280
+ return crypto.randomUUID();
281
+ }
282
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
283
+ const r = Math.random() * 16 | 0;
284
+ const v = c === "x" ? r : r & 3 | 8;
285
+ return v.toString(16);
286
+ });
287
+ }
281
288
  var SessionHostRegistry = class {
282
289
  sessions = /* @__PURE__ */ new Map();
283
290
  createSession(payload) {
284
- const sessionId = payload.sessionId || (0, import_crypto.randomUUID)();
291
+ const sessionId = payload.sessionId || generateUUID();
285
292
  if (this.sessions.has(sessionId)) {
286
293
  throw new Error(`Session already exists: ${sessionId}`);
287
294
  }
@@ -498,7 +505,16 @@ var SessionHostRegistry = class {
498
505
  var os = __toESM(require("os"));
499
506
  var path2 = __toESM(require("path"));
500
507
  var net = __toESM(require("net"));
501
- var import_crypto2 = require("crypto");
508
+ function generateUUID2() {
509
+ if (typeof crypto !== "undefined" && crypto.randomUUID) {
510
+ return crypto.randomUUID();
511
+ }
512
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
513
+ const r = Math.random() * 16 | 0;
514
+ const v = c === "x" ? r : r & 3 | 8;
515
+ return v.toString(16);
516
+ });
517
+ }
502
518
  function getDefaultSessionHostEndpoint(appName = "adhdev") {
503
519
  if (process.platform === "win32") {
504
520
  return {
@@ -589,7 +605,7 @@ var SessionHostClient = class {
589
605
  async request(request) {
590
606
  await this.connect();
591
607
  if (!this.socket) throw new Error("Session host socket unavailable");
592
- const requestId = (0, import_crypto2.randomUUID)();
608
+ const requestId = generateUUID2();
593
609
  const envelope = {
594
610
  kind: "request",
595
611
  requestId,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/types.ts","../src/buffer.ts","../src/registry.ts","../src/defaults.ts","../src/runtime-labels.ts","../src/ipc.ts","../src/spawn-env.ts"],"sourcesContent":["export type {\n AcquireWritePayload,\n AttachSessionPayload,\n ClearSessionBufferPayload,\n CreateSessionPayload,\n DetachSessionPayload,\n ForceDetachClientPayload,\n GetHostDiagnosticsPayload,\n GetSnapshotPayload,\n PruneDuplicateSessionsPayload,\n ReleaseWritePayload,\n ResumeSessionPayload,\n RestartSessionPayload,\n ResizeSessionPayload,\n SendSignalPayload,\n SendInputPayload,\n UpdateSessionMetaPayload,\n SessionAttachedClient,\n SessionBufferSnapshot,\n SessionClientType,\n SessionHostDiagnostics,\n SessionHostDuplicateSessionGroup,\n SessionHostCategory,\n SessionHostSurfaceKind,\n SessionHostEvent,\n SessionHostEventEnvelope,\n SessionHostLogEntry,\n SessionHostPruneDuplicatesResult,\n SessionHostRecord,\n SessionHostRequest,\n SessionHostRequestEnvelope,\n SessionHostRequestTrace,\n SessionHostRequestType,\n SessionHostResponse,\n SessionHostResponseEnvelope,\n SessionHostRuntimeTransition,\n SessionLaunchCommand,\n SessionLifecycle,\n SessionOwnerType,\n SessionTransport,\n SessionHostWireEnvelope,\n SessionWriteOwner,\n StopSessionPayload,\n} from './types.js';\n\nexport { SESSION_HOST_SUPPORTED_REQUEST_TYPES } from './types.js';\n\nexport { DEFAULT_SESSION_RING_BUFFER_MAX_BYTES, SessionRingBuffer } from './buffer.js';\nexport type { SessionRingBufferOptions } from './buffer.js';\nexport { SessionHostRegistry } from './registry.js';\nexport {\n buildRuntimeDisplayName,\n buildRuntimeKey,\n formatRuntimeOwner,\n getSessionHostRecoveryLabel,\n getSessionHostSurfaceKind,\n getWorkspaceLabel,\n isSessionHostLiveRuntime,\n isSessionHostRecoverySnapshot,\n resolveAttachableRuntimeRecord,\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';\nexport {\n DEFAULT_SESSION_HOST_COLS,\n DEFAULT_SESSION_HOST_ROWS,\n resolveSessionHostCols,\n resolveSessionHostRows,\n} from './defaults.js';\nexport {\n sanitizeSpawnEnv,\n applyTerminalColorEnv,\n ensureNodePtySpawnHelperPermissions,\n} from './spawn-env.js';\n","export type SessionTransport = 'pty';\n\nexport type SessionHostCategory = 'cli' | 'acp' | 'shell';\n\nexport type SessionLifecycle = 'starting' | 'running' | 'stopping' | 'stopped' | 'failed' | 'interrupted';\n\nexport type SessionClientType = 'daemon' | 'web' | 'local-terminal';\n\nexport type SessionOwnerType = 'agent' | 'user';\n\nexport interface SessionLaunchCommand {\n command: string;\n args: string[];\n env?: Record<string, string>;\n}\n\nexport interface SessionWriteOwner {\n clientId: string;\n ownerType: SessionOwnerType;\n acquiredAt: number;\n}\n\nexport interface SessionAttachedClient {\n clientId: string;\n type: SessionClientType;\n readOnly: boolean;\n attachedAt: number;\n lastSeenAt: number;\n}\n\nexport interface SessionBufferSnapshot {\n seq: number;\n text: string;\n truncated: boolean;\n cols?: number;\n rows?: number;\n}\n\nexport interface SessionBufferState {\n scrollbackBytes: number;\n snapshotSeq: number;\n}\n\nexport type SessionHostSurfaceKind = 'live_runtime' | 'recovery_snapshot' | 'inactive_record';\n\nexport interface SessionHostRecord {\n sessionId: string;\n runtimeKey: string;\n displayName: string;\n workspaceLabel: string;\n transport: SessionTransport;\n providerType: string;\n category: SessionHostCategory;\n workspace: string;\n launchCommand: SessionLaunchCommand;\n osPid?: number;\n createdAt: number;\n startedAt?: number;\n lastActivityAt: number;\n lifecycle: SessionLifecycle;\n surfaceKind?: SessionHostSurfaceKind;\n writeOwner: SessionWriteOwner | null;\n attachedClients: SessionAttachedClient[];\n buffer: SessionBufferState;\n meta: Record<string, unknown>;\n}\n\nexport interface CreateSessionPayload {\n sessionId?: string;\n runtimeKey?: string;\n displayName?: string;\n providerType: string;\n category: SessionHostCategory;\n workspace: string;\n launchCommand: SessionLaunchCommand;\n cols?: number;\n rows?: number;\n clientId?: string;\n clientType?: SessionClientType;\n meta?: Record<string, unknown>;\n}\n\nexport interface AttachSessionPayload {\n sessionId: string;\n clientId: string;\n clientType: SessionClientType;\n readOnly?: boolean;\n}\n\nexport interface DetachSessionPayload {\n sessionId: string;\n clientId: string;\n}\n\nexport interface SendInputPayload {\n sessionId: string;\n clientId: string;\n data: string;\n}\n\nexport interface ResizeSessionPayload {\n sessionId: string;\n cols: number;\n rows: number;\n}\n\nexport interface StopSessionPayload {\n sessionId: string;\n}\n\nexport interface DeleteSessionPayload {\n sessionId: string;\n /** Stop a live runtime before deleting the persisted record. */\n force?: boolean;\n}\n\nexport interface ResumeSessionPayload {\n sessionId: string;\n}\n\nexport interface AcquireWritePayload {\n sessionId: string;\n clientId: string;\n ownerType: SessionOwnerType;\n force?: boolean;\n}\n\nexport interface ReleaseWritePayload {\n sessionId: string;\n clientId: string;\n}\n\nexport interface GetSnapshotPayload {\n sessionId: string;\n sinceSeq?: number;\n}\n\nexport interface ClearSessionBufferPayload {\n sessionId: string;\n}\n\nexport interface UpdateSessionMetaPayload {\n sessionId: string;\n meta: Record<string, unknown>;\n replace?: boolean;\n}\n\nexport interface GetHostDiagnosticsPayload {\n includeSessions?: boolean;\n limit?: number;\n}\n\nexport interface ForceDetachClientPayload {\n sessionId: string;\n clientId: string;\n}\n\nexport interface SendSignalPayload {\n sessionId: string;\n signal: string;\n}\n\nexport interface RestartSessionPayload {\n sessionId: string;\n}\n\nexport interface PruneDuplicateSessionsPayload {\n providerType?: string;\n workspace?: string;\n dryRun?: boolean;\n}\n\nexport interface SessionHostDuplicateSessionGroup {\n bindingKey: string;\n providerType: string;\n workspace: string;\n providerSessionId: string;\n keptSessionId: string;\n prunedSessionIds: string[];\n}\n\nexport interface SessionHostPruneDuplicatesResult {\n duplicateGroupCount: number;\n keptSessionIds: string[];\n prunedSessionIds: string[];\n groups: SessionHostDuplicateSessionGroup[];\n}\n\nexport interface SessionHostLogEntry {\n timestamp: number;\n level: 'debug' | 'info' | 'warn' | 'error';\n message: string;\n sessionId?: string;\n data?: Record<string, unknown>;\n}\n\nexport interface SessionHostRequestTrace {\n timestamp: number;\n requestId: string;\n type: SessionHostRequest['type'];\n sessionId?: string;\n clientId?: string;\n success: boolean;\n durationMs: number;\n error?: string;\n}\n\nexport interface SessionHostRuntimeTransition {\n timestamp: number;\n sessionId: string;\n action: string;\n lifecycle?: SessionLifecycle;\n detail?: string;\n success?: boolean;\n error?: string;\n}\n\nexport interface SessionHostDiagnostics {\n hostStartedAt: number;\n endpoint: string;\n runtimeCount: number;\n supportedRequestTypes?: SessionHostRequestType[];\n sessions?: SessionHostRecord[];\n liveRuntimes?: SessionHostRecord[];\n recoverySnapshots?: SessionHostRecord[];\n inactiveRecords?: SessionHostRecord[];\n recentLogs: SessionHostLogEntry[];\n recentRequests: SessionHostRequestTrace[];\n recentTransitions: SessionHostRuntimeTransition[];\n}\n\nexport type SessionHostRequest =\n | { type: 'create_session'; payload: CreateSessionPayload }\n | { type: 'attach_session'; payload: AttachSessionPayload }\n | { type: 'detach_session'; payload: DetachSessionPayload }\n | { type: 'send_input'; payload: SendInputPayload }\n | { type: 'resize_session'; payload: ResizeSessionPayload }\n | { type: 'stop_session'; payload: StopSessionPayload }\n | { type: 'delete_session'; payload: DeleteSessionPayload }\n | { type: 'resume_session'; payload: ResumeSessionPayload }\n | { type: 'acquire_write'; payload: AcquireWritePayload }\n | { type: 'release_write'; payload: ReleaseWritePayload }\n | { type: 'get_snapshot'; payload: GetSnapshotPayload }\n | { type: 'clear_session_buffer'; payload: ClearSessionBufferPayload }\n | { type: 'update_session_meta'; payload: UpdateSessionMetaPayload }\n | { type: 'get_host_diagnostics'; payload?: GetHostDiagnosticsPayload }\n | { type: 'force_detach_client'; payload: ForceDetachClientPayload }\n | { type: 'send_signal'; payload: SendSignalPayload }\n | { type: 'restart_session'; payload: RestartSessionPayload }\n | { type: 'prune_duplicate_sessions'; payload?: PruneDuplicateSessionsPayload }\n | { type: 'list_sessions'; payload?: {} };\n\nexport type SessionHostRequestType = SessionHostRequest['type'];\n\nexport const SESSION_HOST_SUPPORTED_REQUEST_TYPES: readonly SessionHostRequestType[] = [\n 'create_session',\n 'attach_session',\n 'detach_session',\n 'send_input',\n 'resize_session',\n 'stop_session',\n 'delete_session',\n 'resume_session',\n 'acquire_write',\n 'release_write',\n 'get_snapshot',\n 'clear_session_buffer',\n 'update_session_meta',\n 'get_host_diagnostics',\n 'force_detach_client',\n 'send_signal',\n 'restart_session',\n 'prune_duplicate_sessions',\n 'list_sessions',\n];\n\nexport interface SessionHostResponse<T = unknown> {\n success: boolean;\n result?: T;\n error?: string;\n}\n\nexport type SessionHostEvent =\n | { type: 'session_created'; sessionId: string; record: SessionHostRecord }\n | { type: 'session_started'; sessionId: string; pid?: number }\n | { type: 'session_resumed'; sessionId: string; pid?: number }\n | { type: 'session_output'; sessionId: string; seq: number; data: string }\n | { type: 'session_cleared'; sessionId: string }\n | { type: 'session_exit'; sessionId: string; exitCode: number | null }\n | { type: 'session_stopped'; sessionId: string }\n | { type: 'session_deleted'; sessionId: string }\n | { type: 'session_resized'; sessionId: string; cols: number; rows: number }\n | { type: 'write_owner_changed'; sessionId: string; owner: SessionWriteOwner | null }\n | { type: 'client_attached'; sessionId: string; client: SessionAttachedClient }\n | { type: 'client_detached'; sessionId: string; clientId: string }\n | { type: 'host_log'; entry: SessionHostLogEntry }\n | { type: 'request_trace'; trace: SessionHostRequestTrace }\n | { type: 'runtime_transition'; transition: SessionHostRuntimeTransition };\n\nexport interface SessionHostRequestEnvelope {\n kind: 'request';\n requestId: string;\n request: SessionHostRequest;\n}\n\nexport interface SessionHostResponseEnvelope {\n kind: 'response';\n requestId: string;\n response: SessionHostResponse;\n}\n\nexport interface SessionHostEventEnvelope {\n kind: 'event';\n event: SessionHostEvent;\n}\n\nexport type SessionHostWireEnvelope =\n | SessionHostRequestEnvelope\n | SessionHostResponseEnvelope\n | SessionHostEventEnvelope;\n","import type { SessionBufferSnapshot } from './types.js';\n\nexport interface SessionRingBufferOptions {\n maxBytes?: number;\n}\n\n// Manual \"Load older terminal output\" replays this raw ring buffer into the\n// browser terminal. 512KiB was too small for long Claude/Codex conversations:\n// by the time the user scrolled to the top and clicked the loader, the output\n// they were trying to recover was often already trimmed.\nexport const DEFAULT_SESSION_RING_BUFFER_MAX_BYTES = 4 * 1024 * 1024;\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 ?? DEFAULT_SESSION_RING_BUFFER_MAX_BYTES;\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 { resolveSessionHostCols, resolveSessionHostRows } from './defaults.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: resolveSessionHostCols(payload.cols),\n sessionHostRows: resolveSessionHostRows(payload.rows),\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 updateSessionMeta(sessionId: string, meta: Record<string, unknown>, replace = false): SessionHostRecord {\n const state = this.requireSession(sessionId);\n state.record.meta = replace\n ? { ...meta }\n : {\n ...(state.record.meta || {}),\n ...meta,\n };\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 deleteSession(sessionId: string): boolean {\n return this.sessions.delete(sessionId);\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","export const DEFAULT_SESSION_HOST_COLS = 80;\nexport const DEFAULT_SESSION_HOST_ROWS = 32;\n\nfunction normalizeSessionHostDimension(value: number | undefined, fallback: number): number {\n if (typeof value !== 'number' || !Number.isFinite(value)) return fallback;\n const rounded = Math.floor(value);\n return rounded > 0 ? rounded : fallback;\n}\n\nexport function resolveSessionHostCols(value: number | undefined): number {\n return normalizeSessionHostDimension(value, DEFAULT_SESSION_HOST_COLS);\n}\n\nexport function resolveSessionHostRows(value: number | undefined): number {\n return normalizeSessionHostDimension(value, DEFAULT_SESSION_HOST_ROWS);\n}\n","import * as path from 'path';\nimport type { CreateSessionPayload, SessionHostRecord, SessionHostSurfaceKind } 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\nexport interface SessionHostSurfaceRecordLike {\n lifecycle?: string | null;\n surfaceKind?: SessionHostSurfaceKind | null;\n meta?: Record<string, unknown> | null;\n}\n\nconst LIVE_LIFECYCLES = new Set(['starting', 'running', 'stopping', 'interrupted']);\n\nexport function isSessionHostLiveRuntime(record: SessionHostSurfaceRecordLike | null | undefined): boolean {\n if (!record) return false;\n if (record.surfaceKind === 'live_runtime') return true;\n if (record.surfaceKind === 'recovery_snapshot' || record.surfaceKind === 'inactive_record') return false;\n const lifecycle = String(record.lifecycle || '').trim();\n return LIVE_LIFECYCLES.has(lifecycle);\n}\n\nexport function getSessionHostRecoveryLabel(meta: Record<string, unknown> | null | undefined): string | null {\n const recoveryState = typeof meta?.runtimeRecoveryState === 'string'\n ? String(meta.runtimeRecoveryState).trim()\n : '';\n if (!recoveryState) return null;\n if (recoveryState === 'auto_resumed') return 'restored after restart';\n if (recoveryState === 'resume_failed') return 'restore failed';\n if (recoveryState === 'host_restart_interrupted') return 'host restart interrupted';\n if (recoveryState === 'orphan_snapshot') return 'snapshot recovered';\n return recoveryState.replace(/_/g, ' ');\n}\n\nexport function isSessionHostRecoverySnapshot(record: SessionHostSurfaceRecordLike | null | undefined): boolean {\n if (!record) return false;\n if (record.surfaceKind === 'recovery_snapshot') return true;\n if (record.surfaceKind === 'live_runtime' || record.surfaceKind === 'inactive_record') return false;\n if (isSessionHostLiveRuntime(record)) return false;\n\n const lifecycle = String(record.lifecycle || '').trim();\n if (lifecycle && lifecycle !== 'stopped' && lifecycle !== 'failed') {\n return false;\n }\n\n const meta = record.meta || undefined;\n if (meta?.restoredFromStorage === true) return true;\n return getSessionHostRecoveryLabel(meta) !== null;\n}\n\nexport function getSessionHostSurfaceKind(record: SessionHostSurfaceRecordLike | null | undefined): SessionHostSurfaceKind {\n if (record?.surfaceKind === 'live_runtime' || record?.surfaceKind === 'recovery_snapshot' || record?.surfaceKind === 'inactive_record') {\n return record.surfaceKind;\n }\n if (isSessionHostLiveRuntime(record)) return 'live_runtime';\n if (isSessionHostRecoverySnapshot(record)) return 'recovery_snapshot';\n return 'inactive_record';\n}\n\nexport function resolveAttachableRuntimeRecord(records: SessionHostRecord[], identifier: string): SessionHostRecord {\n const record = resolveRuntimeRecord(records, identifier);\n const surfaceKind = getSessionHostSurfaceKind(record);\n if (surfaceKind === 'live_runtime') {\n return record;\n }\n if (surfaceKind === 'recovery_snapshot') {\n throw new Error(`Runtime ${record.runtimeKey} is a recovery snapshot, not a live attach target. Resume or recover it first.`);\n }\n throw new Error(`Runtime ${record.runtimeKey} is ${record.lifecycle}, not a live attach target.`);\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 // Cleanup stale socket reference left after error/disconnect\n if (this.socket) {\n try { this.socket.destroy(); } catch { /* noop */ }\n this.socket = null;\n }\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 // Clear the dead socket reference so the next connect() creates a fresh connection\n // instead of skipping reconnection on the `!this.socket.destroyed` guard.\n if (this.socket === socket) {\n this.socket = null;\n }\n try { socket.destroy(); } catch { /* noop */ }\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 const timeout = setTimeout(() => {\n this.requestWaiters.delete(requestId);\n reject(new Error(`Session host request timed out after 30s (${request.type})`));\n }, 30_000);\n this.requestWaiters.set(requestId, {\n resolve: (value) => { clearTimeout(timeout); resolve(value); },\n reject: (error) => { clearTimeout(timeout); reject(error); },\n });\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","/**\n * Shared PTY spawn environment utilities.\n *\n * Centralises npm/pnpm/yarn env variable stripping, terminal colour env\n * injection, and node-pty spawn-helper permission fixing.\n *\n * Used by daemon-core (provider-cli-adapter), session-host-daemon (runtime),\n * and daemon-cloud (session-host).\n */\n\nimport * as os from 'os';\nimport * as path from 'path';\n\n/**\n * Strip package-manager injected environment variables that can interfere\n * with child CLI processes and apply terminal colour defaults.\n */\nexport function sanitizeSpawnEnv(\n baseEnv: NodeJS.ProcessEnv,\n overrides?: Record<string, string>,\n): Record<string, string> {\n const env: Record<string, string> = {};\n const source = { ...baseEnv, ...(overrides || {}) } as NodeJS.ProcessEnv;\n\n for (const [key, value] of Object.entries(source)) {\n if (typeof value !== 'string') continue;\n env[key] = value;\n }\n\n for (const key of Object.keys(env)) {\n if (\n key === 'INIT_CWD'\n || key === 'npm_command'\n || key === 'npm_execpath'\n || key === 'npm_node_execpath'\n || key.startsWith('npm_')\n || key.startsWith('npm_config_')\n || key.startsWith('npm_package_')\n || key.startsWith('npm_lifecycle_')\n || key.startsWith('PNPM_')\n || key.startsWith('YARN_')\n || key.startsWith('BUN_')\n || key.startsWith('VSCODE_')\n || key.startsWith('ELECTRON_')\n ) {\n delete env[key];\n }\n }\n\n // Do not leak the parent Codex app/extension thread identity into child CLIs.\n // Those variables cause codex-cli to attach to the current IDE thread instead\n // of creating or resuming its own standalone CLI thread, which breaks\n // providerSessionId discovery and reconnect semantics.\n delete env.CODEX_THREAD_ID;\n delete env.CODEX_INTERNAL_ORIGINATOR_OVERRIDE;\n\n applyTerminalColorEnv(env);\n return env;\n}\n\n/**\n * Apply preferred terminal colour environment variables.\n * Ensures TERM is set to xterm-256color and enables colour on Windows.\n */\nexport function applyTerminalColorEnv(env: Record<string, string>): void {\n if (env.NO_COLOR) return;\n\n if (!env.TERM || env.TERM === 'xterm-color') {\n env.TERM = 'xterm-256color';\n }\n if (!env.COLORTERM) env.COLORTERM = 'truecolor';\n\n if (process.platform === 'win32') {\n if (!env.FORCE_COLOR) env.FORCE_COLOR = '1';\n if (!env.CLICOLOR) env.CLICOLOR = '1';\n }\n}\n\n/**\n * Ensure node-pty's spawn-helper binary has execute permissions.\n *\n * npm's default umask can strip +x from the prebuilt spawn-helper on macOS/Linux,\n * causing EACCES when node-pty tries to fork. Best-effort fix.\n *\n * @param logFn Optional log callback for reporting the fix.\n */\nexport function ensureNodePtySpawnHelperPermissions(\n logFn?: (msg: string) => void,\n): void {\n if (os.platform() === 'win32') return;\n try {\n const fs = require('fs');\n const ptyDir = path.resolve(path.dirname(require.resolve('node-pty')), '..');\n const platformArch = `${os.platform()}-${os.arch()}`;\n const helper = path.join(ptyDir, 'prebuilds', platformArch, 'spawn-helper');\n if (fs.existsSync(helper)) {\n const stat = fs.statSync(helper);\n if (!(stat.mode & 0o111)) {\n fs.chmodSync(helper, stat.mode | 0o755);\n logFn?.(`Fixed spawn-helper permissions: ${helper}`);\n }\n }\n } catch {\n // best-effort: node-pty still works on most installs without this\n }\n}\n"],"mappings":"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","names":["path","import_crypto","resolve","os","path"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/types.ts","../src/buffer.ts","../src/defaults.ts","../src/runtime-labels.ts","../src/registry.ts","../src/ipc.ts","../src/spawn-env.ts"],"sourcesContent":["export type {\n AcquireWritePayload,\n AttachSessionPayload,\n ClearSessionBufferPayload,\n CreateSessionPayload,\n DetachSessionPayload,\n ForceDetachClientPayload,\n GetHostDiagnosticsPayload,\n GetSnapshotPayload,\n PruneDuplicateSessionsPayload,\n ReleaseWritePayload,\n ResumeSessionPayload,\n RestartSessionPayload,\n ResizeSessionPayload,\n SendSignalPayload,\n SendInputPayload,\n UpdateSessionMetaPayload,\n SessionAttachedClient,\n SessionBufferSnapshot,\n SessionClientType,\n SessionHostDiagnostics,\n SessionHostDuplicateSessionGroup,\n SessionHostCategory,\n SessionHostSurfaceKind,\n SessionHostEvent,\n SessionHostEventEnvelope,\n SessionHostLogEntry,\n SessionHostPruneDuplicatesResult,\n SessionHostRecord,\n SessionHostRequest,\n SessionHostRequestEnvelope,\n SessionHostRequestTrace,\n SessionHostRequestType,\n SessionHostResponse,\n SessionHostResponseEnvelope,\n SessionHostRuntimeTransition,\n SessionLaunchCommand,\n SessionLifecycle,\n SessionOwnerType,\n SessionTransport,\n SessionHostWireEnvelope,\n SessionWriteOwner,\n StopSessionPayload,\n} from './types.js';\n\nexport { SESSION_HOST_SUPPORTED_REQUEST_TYPES } from './types.js';\n\nexport { DEFAULT_SESSION_RING_BUFFER_MAX_BYTES, SessionRingBuffer } from './buffer.js';\nexport type { SessionRingBufferOptions } from './buffer.js';\nexport { SessionHostRegistry } from './registry.js';\nexport {\n buildRuntimeDisplayName,\n buildRuntimeKey,\n formatRuntimeOwner,\n getSessionHostRecoveryLabel,\n getSessionHostSurfaceKind,\n getWorkspaceLabel,\n isSessionHostLiveRuntime,\n isSessionHostRecoverySnapshot,\n resolveAttachableRuntimeRecord,\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';\nexport {\n DEFAULT_SESSION_HOST_COLS,\n DEFAULT_SESSION_HOST_ROWS,\n resolveSessionHostCols,\n resolveSessionHostRows,\n} from './defaults.js';\nexport {\n sanitizeSpawnEnv,\n applyTerminalColorEnv,\n ensureNodePtySpawnHelperPermissions,\n} from './spawn-env.js';\n","export type SessionTransport = 'pty';\n\nexport type SessionHostCategory = 'cli' | 'acp' | 'shell';\n\nexport type SessionLifecycle = 'starting' | 'running' | 'stopping' | 'stopped' | 'failed' | 'interrupted';\n\nexport type SessionClientType = 'daemon' | 'web' | 'local-terminal';\n\nexport type SessionOwnerType = 'agent' | 'user';\n\nexport interface SessionLaunchCommand {\n command: string;\n args: string[];\n env?: Record<string, string>;\n}\n\nexport interface SessionWriteOwner {\n clientId: string;\n ownerType: SessionOwnerType;\n acquiredAt: number;\n}\n\nexport interface SessionAttachedClient {\n clientId: string;\n type: SessionClientType;\n readOnly: boolean;\n attachedAt: number;\n lastSeenAt: number;\n}\n\nexport interface SessionBufferSnapshot {\n seq: number;\n text: string;\n truncated: boolean;\n cols?: number;\n rows?: number;\n}\n\nexport interface SessionBufferState {\n scrollbackBytes: number;\n snapshotSeq: number;\n}\n\nexport type SessionHostSurfaceKind = 'live_runtime' | 'recovery_snapshot' | 'inactive_record';\n\nexport interface SessionHostRecord {\n sessionId: string;\n runtimeKey: string;\n displayName: string;\n workspaceLabel: string;\n transport: SessionTransport;\n providerType: string;\n category: SessionHostCategory;\n workspace: string;\n launchCommand: SessionLaunchCommand;\n osPid?: number;\n createdAt: number;\n startedAt?: number;\n lastActivityAt: number;\n lifecycle: SessionLifecycle;\n surfaceKind?: SessionHostSurfaceKind;\n writeOwner: SessionWriteOwner | null;\n attachedClients: SessionAttachedClient[];\n buffer: SessionBufferState;\n meta: Record<string, unknown>;\n}\n\nexport interface CreateSessionPayload {\n sessionId?: string;\n runtimeKey?: string;\n displayName?: string;\n providerType: string;\n category: SessionHostCategory;\n workspace: string;\n launchCommand: SessionLaunchCommand;\n cols?: number;\n rows?: number;\n clientId?: string;\n clientType?: SessionClientType;\n meta?: Record<string, unknown>;\n}\n\nexport interface AttachSessionPayload {\n sessionId: string;\n clientId: string;\n clientType: SessionClientType;\n readOnly?: boolean;\n}\n\nexport interface DetachSessionPayload {\n sessionId: string;\n clientId: string;\n}\n\nexport interface SendInputPayload {\n sessionId: string;\n clientId: string;\n data: string;\n}\n\nexport interface ResizeSessionPayload {\n sessionId: string;\n cols: number;\n rows: number;\n}\n\nexport interface StopSessionPayload {\n sessionId: string;\n}\n\nexport interface DeleteSessionPayload {\n sessionId: string;\n /** Stop a live runtime before deleting the persisted record. */\n force?: boolean;\n}\n\nexport interface ResumeSessionPayload {\n sessionId: string;\n}\n\nexport interface AcquireWritePayload {\n sessionId: string;\n clientId: string;\n ownerType: SessionOwnerType;\n force?: boolean;\n}\n\nexport interface ReleaseWritePayload {\n sessionId: string;\n clientId: string;\n}\n\nexport interface GetSnapshotPayload {\n sessionId: string;\n sinceSeq?: number;\n}\n\nexport interface ClearSessionBufferPayload {\n sessionId: string;\n}\n\nexport interface UpdateSessionMetaPayload {\n sessionId: string;\n meta: Record<string, unknown>;\n replace?: boolean;\n}\n\nexport interface GetHostDiagnosticsPayload {\n includeSessions?: boolean;\n limit?: number;\n}\n\nexport interface ForceDetachClientPayload {\n sessionId: string;\n clientId: string;\n}\n\nexport interface SendSignalPayload {\n sessionId: string;\n signal: string;\n}\n\nexport interface RestartSessionPayload {\n sessionId: string;\n}\n\nexport interface PruneDuplicateSessionsPayload {\n providerType?: string;\n workspace?: string;\n dryRun?: boolean;\n}\n\nexport interface SessionHostDuplicateSessionGroup {\n bindingKey: string;\n providerType: string;\n workspace: string;\n providerSessionId: string;\n keptSessionId: string;\n prunedSessionIds: string[];\n}\n\nexport interface SessionHostPruneDuplicatesResult {\n duplicateGroupCount: number;\n keptSessionIds: string[];\n prunedSessionIds: string[];\n groups: SessionHostDuplicateSessionGroup[];\n}\n\nexport interface SessionHostLogEntry {\n timestamp: number;\n level: 'debug' | 'info' | 'warn' | 'error';\n message: string;\n sessionId?: string;\n data?: Record<string, unknown>;\n}\n\nexport interface SessionHostRequestTrace {\n timestamp: number;\n requestId: string;\n type: SessionHostRequest['type'];\n sessionId?: string;\n clientId?: string;\n success: boolean;\n durationMs: number;\n error?: string;\n}\n\nexport interface SessionHostRuntimeTransition {\n timestamp: number;\n sessionId: string;\n action: string;\n lifecycle?: SessionLifecycle;\n detail?: string;\n success?: boolean;\n error?: string;\n}\n\nexport interface SessionHostDiagnostics {\n hostStartedAt: number;\n endpoint: string;\n runtimeCount: number;\n supportedRequestTypes?: SessionHostRequestType[];\n sessions?: SessionHostRecord[];\n liveRuntimes?: SessionHostRecord[];\n recoverySnapshots?: SessionHostRecord[];\n inactiveRecords?: SessionHostRecord[];\n recentLogs: SessionHostLogEntry[];\n recentRequests: SessionHostRequestTrace[];\n recentTransitions: SessionHostRuntimeTransition[];\n}\n\nexport type SessionHostRequest =\n | { type: 'create_session'; payload: CreateSessionPayload }\n | { type: 'attach_session'; payload: AttachSessionPayload }\n | { type: 'detach_session'; payload: DetachSessionPayload }\n | { type: 'send_input'; payload: SendInputPayload }\n | { type: 'resize_session'; payload: ResizeSessionPayload }\n | { type: 'stop_session'; payload: StopSessionPayload }\n | { type: 'delete_session'; payload: DeleteSessionPayload }\n | { type: 'resume_session'; payload: ResumeSessionPayload }\n | { type: 'acquire_write'; payload: AcquireWritePayload }\n | { type: 'release_write'; payload: ReleaseWritePayload }\n | { type: 'get_snapshot'; payload: GetSnapshotPayload }\n | { type: 'clear_session_buffer'; payload: ClearSessionBufferPayload }\n | { type: 'update_session_meta'; payload: UpdateSessionMetaPayload }\n | { type: 'get_host_diagnostics'; payload?: GetHostDiagnosticsPayload }\n | { type: 'force_detach_client'; payload: ForceDetachClientPayload }\n | { type: 'send_signal'; payload: SendSignalPayload }\n | { type: 'restart_session'; payload: RestartSessionPayload }\n | { type: 'prune_duplicate_sessions'; payload?: PruneDuplicateSessionsPayload }\n | { type: 'list_sessions'; payload?: {} };\n\nexport type SessionHostRequestType = SessionHostRequest['type'];\n\nexport const SESSION_HOST_SUPPORTED_REQUEST_TYPES: readonly SessionHostRequestType[] = [\n 'create_session',\n 'attach_session',\n 'detach_session',\n 'send_input',\n 'resize_session',\n 'stop_session',\n 'delete_session',\n 'resume_session',\n 'acquire_write',\n 'release_write',\n 'get_snapshot',\n 'clear_session_buffer',\n 'update_session_meta',\n 'get_host_diagnostics',\n 'force_detach_client',\n 'send_signal',\n 'restart_session',\n 'prune_duplicate_sessions',\n 'list_sessions',\n];\n\nexport interface SessionHostResponse<T = unknown> {\n success: boolean;\n result?: T;\n error?: string;\n}\n\nexport type SessionHostEvent =\n | { type: 'session_created'; sessionId: string; record: SessionHostRecord }\n | { type: 'session_started'; sessionId: string; pid?: number }\n | { type: 'session_resumed'; sessionId: string; pid?: number }\n | { type: 'session_output'; sessionId: string; seq: number; data: string }\n | { type: 'session_cleared'; sessionId: string }\n | { type: 'session_exit'; sessionId: string; exitCode: number | null }\n | { type: 'session_stopped'; sessionId: string }\n | { type: 'session_deleted'; sessionId: string }\n | { type: 'session_resized'; sessionId: string; cols: number; rows: number }\n | { type: 'write_owner_changed'; sessionId: string; owner: SessionWriteOwner | null }\n | { type: 'client_attached'; sessionId: string; client: SessionAttachedClient }\n | { type: 'client_detached'; sessionId: string; clientId: string }\n | { type: 'host_log'; entry: SessionHostLogEntry }\n | { type: 'request_trace'; trace: SessionHostRequestTrace }\n | { type: 'runtime_transition'; transition: SessionHostRuntimeTransition };\n\nexport interface SessionHostRequestEnvelope {\n kind: 'request';\n requestId: string;\n request: SessionHostRequest;\n}\n\nexport interface SessionHostResponseEnvelope {\n kind: 'response';\n requestId: string;\n response: SessionHostResponse;\n}\n\nexport interface SessionHostEventEnvelope {\n kind: 'event';\n event: SessionHostEvent;\n}\n\nexport type SessionHostWireEnvelope =\n | SessionHostRequestEnvelope\n | SessionHostResponseEnvelope\n | SessionHostEventEnvelope;\n","import type { SessionBufferSnapshot } from './types.js';\n\nexport interface SessionRingBufferOptions {\n maxBytes?: number;\n}\n\n// Manual \"Load older terminal output\" replays this raw ring buffer into the\n// browser terminal. 512KiB was too small for long Claude/Codex conversations:\n// by the time the user scrolled to the top and clicked the loader, the output\n// they were trying to recover was often already trimmed.\nexport const DEFAULT_SESSION_RING_BUFFER_MAX_BYTES = 4 * 1024 * 1024;\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 ?? DEFAULT_SESSION_RING_BUFFER_MAX_BYTES;\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","export const DEFAULT_SESSION_HOST_COLS = 80;\nexport const DEFAULT_SESSION_HOST_ROWS = 32;\n\nfunction normalizeSessionHostDimension(value: number | undefined, fallback: number): number {\n if (typeof value !== 'number' || !Number.isFinite(value)) return fallback;\n const rounded = Math.floor(value);\n return rounded > 0 ? rounded : fallback;\n}\n\nexport function resolveSessionHostCols(value: number | undefined): number {\n return normalizeSessionHostDimension(value, DEFAULT_SESSION_HOST_COLS);\n}\n\nexport function resolveSessionHostRows(value: number | undefined): number {\n return normalizeSessionHostDimension(value, DEFAULT_SESSION_HOST_ROWS);\n}\n","import * as path from 'path';\nimport type { CreateSessionPayload, SessionHostRecord, SessionHostSurfaceKind } 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\nexport interface SessionHostSurfaceRecordLike {\n lifecycle?: string | null;\n surfaceKind?: SessionHostSurfaceKind | null;\n meta?: Record<string, unknown> | null;\n}\n\nconst LIVE_LIFECYCLES = new Set(['starting', 'running', 'stopping', 'interrupted']);\n\nexport function isSessionHostLiveRuntime(record: SessionHostSurfaceRecordLike | null | undefined): boolean {\n if (!record) return false;\n if (record.surfaceKind === 'live_runtime') return true;\n if (record.surfaceKind === 'recovery_snapshot' || record.surfaceKind === 'inactive_record') return false;\n const lifecycle = String(record.lifecycle || '').trim();\n return LIVE_LIFECYCLES.has(lifecycle);\n}\n\nexport function getSessionHostRecoveryLabel(meta: Record<string, unknown> | null | undefined): string | null {\n const recoveryState = typeof meta?.runtimeRecoveryState === 'string'\n ? String(meta.runtimeRecoveryState).trim()\n : '';\n if (!recoveryState) return null;\n if (recoveryState === 'auto_resumed') return 'restored after restart';\n if (recoveryState === 'resume_failed') return 'restore failed';\n if (recoveryState === 'host_restart_interrupted') return 'host restart interrupted';\n if (recoveryState === 'orphan_snapshot') return 'snapshot recovered';\n return recoveryState.replace(/_/g, ' ');\n}\n\nexport function isSessionHostRecoverySnapshot(record: SessionHostSurfaceRecordLike | null | undefined): boolean {\n if (!record) return false;\n if (record.surfaceKind === 'recovery_snapshot') return true;\n if (record.surfaceKind === 'live_runtime' || record.surfaceKind === 'inactive_record') return false;\n if (isSessionHostLiveRuntime(record)) return false;\n\n const lifecycle = String(record.lifecycle || '').trim();\n if (lifecycle && lifecycle !== 'stopped' && lifecycle !== 'failed') {\n return false;\n }\n\n const meta = record.meta || undefined;\n if (meta?.restoredFromStorage === true) return true;\n return getSessionHostRecoveryLabel(meta) !== null;\n}\n\nexport function getSessionHostSurfaceKind(record: SessionHostSurfaceRecordLike | null | undefined): SessionHostSurfaceKind {\n if (record?.surfaceKind === 'live_runtime' || record?.surfaceKind === 'recovery_snapshot' || record?.surfaceKind === 'inactive_record') {\n return record.surfaceKind;\n }\n if (isSessionHostLiveRuntime(record)) return 'live_runtime';\n if (isSessionHostRecoverySnapshot(record)) return 'recovery_snapshot';\n return 'inactive_record';\n}\n\nexport function resolveAttachableRuntimeRecord(records: SessionHostRecord[], identifier: string): SessionHostRecord {\n const record = resolveRuntimeRecord(records, identifier);\n const surfaceKind = getSessionHostSurfaceKind(record);\n if (surfaceKind === 'live_runtime') {\n return record;\n }\n if (surfaceKind === 'recovery_snapshot') {\n throw new Error(`Runtime ${record.runtimeKey} is a recovery snapshot, not a live attach target. Resume or recover it first.`);\n }\n throw new Error(`Runtime ${record.runtimeKey} is ${record.lifecycle}, not a live attach target.`);\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","function generateUUID(): string {\n if (typeof crypto !== 'undefined' && crypto.randomUUID) {\n return crypto.randomUUID();\n }\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {\n const r = Math.random() * 16 | 0;\n const v = c === 'x' ? r : (r & 0x3 | 0x8);\n return v.toString(16);\n });\n}\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 { resolveSessionHostCols, resolveSessionHostRows } from './defaults.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 || generateUUID();\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: resolveSessionHostCols(payload.cols),\n sessionHostRows: resolveSessionHostRows(payload.rows),\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 updateSessionMeta(sessionId: string, meta: Record<string, unknown>, replace = false): SessionHostRecord {\n const state = this.requireSession(sessionId);\n state.record.meta = replace\n ? { ...meta }\n : {\n ...(state.record.meta || {}),\n ...meta,\n };\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 deleteSession(sessionId: string): boolean {\n return this.sessions.delete(sessionId);\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 os from 'os';\nimport * as path from 'path';\nimport * as net from 'net';\nimport type {\n SessionHostEvent,\n SessionHostRequest,\n SessionHostRequestEnvelope,\n SessionHostResponse,\n SessionHostResponseEnvelope,\n SessionHostWireEnvelope,\n} from './types.js';\n\nfunction generateUUID(): string {\n if (typeof crypto !== 'undefined' && crypto.randomUUID) {\n return crypto.randomUUID();\n }\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {\n const r = Math.random() * 16 | 0;\n const v = c === 'x' ? r : (r & 0x3 | 0x8);\n return v.toString(16);\n });\n}\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 // Cleanup stale socket reference left after error/disconnect\n if (this.socket) {\n try { this.socket.destroy(); } catch { /* noop */ }\n this.socket = null;\n }\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 // Clear the dead socket reference so the next connect() creates a fresh connection\n // instead of skipping reconnection on the `!this.socket.destroyed` guard.\n if (this.socket === socket) {\n this.socket = null;\n }\n try { socket.destroy(); } catch { /* noop */ }\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 = generateUUID();\n const envelope: SessionHostRequestEnvelope = {\n kind: 'request',\n requestId,\n request,\n };\n\n const response = await new Promise<SessionHostResponse>((resolve, reject) => {\n const timeout = setTimeout(() => {\n this.requestWaiters.delete(requestId);\n reject(new Error(`Session host request timed out after 30s (${request.type})`));\n }, 30_000);\n this.requestWaiters.set(requestId, {\n resolve: (value) => { clearTimeout(timeout); resolve(value); },\n reject: (error) => { clearTimeout(timeout); reject(error); },\n });\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","/**\n * Shared PTY spawn environment utilities.\n *\n * Centralises npm/pnpm/yarn env variable stripping, terminal colour env\n * injection, and node-pty spawn-helper permission fixing.\n *\n * Used by daemon-core (provider-cli-adapter), session-host-daemon (runtime),\n * and daemon-cloud (session-host).\n */\n\nimport * as os from 'os';\nimport * as path from 'path';\n\n/**\n * Strip package-manager injected environment variables that can interfere\n * with child CLI processes and apply terminal colour defaults.\n */\nexport function sanitizeSpawnEnv(\n baseEnv: NodeJS.ProcessEnv,\n overrides?: Record<string, string>,\n): Record<string, string> {\n const env: Record<string, string> = {};\n const source = { ...baseEnv, ...(overrides || {}) } as NodeJS.ProcessEnv;\n\n for (const [key, value] of Object.entries(source)) {\n if (typeof value !== 'string') continue;\n env[key] = value;\n }\n\n for (const key of Object.keys(env)) {\n if (\n key === 'INIT_CWD'\n || key === 'npm_command'\n || key === 'npm_execpath'\n || key === 'npm_node_execpath'\n || key.startsWith('npm_')\n || key.startsWith('npm_config_')\n || key.startsWith('npm_package_')\n || key.startsWith('npm_lifecycle_')\n || key.startsWith('PNPM_')\n || key.startsWith('YARN_')\n || key.startsWith('BUN_')\n || key.startsWith('VSCODE_')\n || key.startsWith('ELECTRON_')\n ) {\n delete env[key];\n }\n }\n\n // Do not leak the parent Codex app/extension thread identity into child CLIs.\n // Those variables cause codex-cli to attach to the current IDE thread instead\n // of creating or resuming its own standalone CLI thread, which breaks\n // providerSessionId discovery and reconnect semantics.\n delete env.CODEX_THREAD_ID;\n delete env.CODEX_INTERNAL_ORIGINATOR_OVERRIDE;\n\n applyTerminalColorEnv(env);\n return env;\n}\n\n/**\n * Apply preferred terminal colour environment variables.\n * Ensures TERM is set to xterm-256color and enables colour on Windows.\n */\nexport function applyTerminalColorEnv(env: Record<string, string>): void {\n if (env.NO_COLOR) return;\n\n if (!env.TERM || env.TERM === 'xterm-color') {\n env.TERM = 'xterm-256color';\n }\n if (!env.COLORTERM) env.COLORTERM = 'truecolor';\n\n if (process.platform === 'win32') {\n if (!env.FORCE_COLOR) env.FORCE_COLOR = '1';\n if (!env.CLICOLOR) env.CLICOLOR = '1';\n }\n}\n\n/**\n * Ensure node-pty's spawn-helper binary has execute permissions.\n *\n * npm's default umask can strip +x from the prebuilt spawn-helper on macOS/Linux,\n * causing EACCES when node-pty tries to fork. Best-effort fix.\n *\n * @param logFn Optional log callback for reporting the fix.\n */\nexport function ensureNodePtySpawnHelperPermissions(\n logFn?: (msg: string) => void,\n): void {\n if (os.platform() === 'win32') return;\n try {\n const fs = require('fs');\n const ptyDir = path.resolve(path.dirname(require.resolve('node-pty')), '..');\n const platformArch = `${os.platform()}-${os.arch()}`;\n const helper = path.join(ptyDir, 'prebuilds', platformArch, 'spawn-helper');\n if (fs.existsSync(helper)) {\n const stat = fs.statSync(helper);\n if (!(stat.mode & 0o111)) {\n fs.chmodSync(helper, stat.mode | 0o755);\n logFn?.(`Fixed spawn-helper permissions: ${helper}`);\n }\n }\n } catch {\n // best-effort: node-pty still works on most installs without this\n }\n}\n"],"mappings":"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","names":["path","generateUUID","resolve","os","path"]}
package/dist/index.mjs CHANGED
@@ -91,9 +91,6 @@ var SessionRingBuffer = class {
91
91
  }
92
92
  };
93
93
 
94
- // src/registry.ts
95
- import { randomUUID } from "crypto";
96
-
97
94
  // src/defaults.ts
98
95
  var DEFAULT_SESSION_HOST_COLS = 80;
99
96
  var DEFAULT_SESSION_HOST_ROWS = 32;
@@ -224,10 +221,20 @@ function formatRuntimeOwner(record) {
224
221
  }
225
222
 
226
223
  // src/registry.ts
224
+ function generateUUID() {
225
+ if (typeof crypto !== "undefined" && crypto.randomUUID) {
226
+ return crypto.randomUUID();
227
+ }
228
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
229
+ const r = Math.random() * 16 | 0;
230
+ const v = c === "x" ? r : r & 3 | 8;
231
+ return v.toString(16);
232
+ });
233
+ }
227
234
  var SessionHostRegistry = class {
228
235
  sessions = /* @__PURE__ */ new Map();
229
236
  createSession(payload) {
230
- const sessionId = payload.sessionId || randomUUID();
237
+ const sessionId = payload.sessionId || generateUUID();
231
238
  if (this.sessions.has(sessionId)) {
232
239
  throw new Error(`Session already exists: ${sessionId}`);
233
240
  }
@@ -444,7 +451,16 @@ var SessionHostRegistry = class {
444
451
  import * as os from "os";
445
452
  import * as path2 from "path";
446
453
  import * as net from "net";
447
- import { randomUUID as randomUUID2 } from "crypto";
454
+ function generateUUID2() {
455
+ if (typeof crypto !== "undefined" && crypto.randomUUID) {
456
+ return crypto.randomUUID();
457
+ }
458
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
459
+ const r = Math.random() * 16 | 0;
460
+ const v = c === "x" ? r : r & 3 | 8;
461
+ return v.toString(16);
462
+ });
463
+ }
448
464
  function getDefaultSessionHostEndpoint(appName = "adhdev") {
449
465
  if (process.platform === "win32") {
450
466
  return {
@@ -535,7 +551,7 @@ var SessionHostClient = class {
535
551
  async request(request) {
536
552
  await this.connect();
537
553
  if (!this.socket) throw new Error("Session host socket unavailable");
538
- const requestId = randomUUID2();
554
+ const requestId = generateUUID2();
539
555
  const envelope = {
540
556
  kind: "request",
541
557
  requestId,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/types.ts","../src/buffer.ts","../src/registry.ts","../src/defaults.ts","../src/runtime-labels.ts","../src/ipc.ts","../src/spawn-env.ts"],"sourcesContent":["export type SessionTransport = 'pty';\n\nexport type SessionHostCategory = 'cli' | 'acp' | 'shell';\n\nexport type SessionLifecycle = 'starting' | 'running' | 'stopping' | 'stopped' | 'failed' | 'interrupted';\n\nexport type SessionClientType = 'daemon' | 'web' | 'local-terminal';\n\nexport type SessionOwnerType = 'agent' | 'user';\n\nexport interface SessionLaunchCommand {\n command: string;\n args: string[];\n env?: Record<string, string>;\n}\n\nexport interface SessionWriteOwner {\n clientId: string;\n ownerType: SessionOwnerType;\n acquiredAt: number;\n}\n\nexport interface SessionAttachedClient {\n clientId: string;\n type: SessionClientType;\n readOnly: boolean;\n attachedAt: number;\n lastSeenAt: number;\n}\n\nexport interface SessionBufferSnapshot {\n seq: number;\n text: string;\n truncated: boolean;\n cols?: number;\n rows?: number;\n}\n\nexport interface SessionBufferState {\n scrollbackBytes: number;\n snapshotSeq: number;\n}\n\nexport type SessionHostSurfaceKind = 'live_runtime' | 'recovery_snapshot' | 'inactive_record';\n\nexport interface SessionHostRecord {\n sessionId: string;\n runtimeKey: string;\n displayName: string;\n workspaceLabel: string;\n transport: SessionTransport;\n providerType: string;\n category: SessionHostCategory;\n workspace: string;\n launchCommand: SessionLaunchCommand;\n osPid?: number;\n createdAt: number;\n startedAt?: number;\n lastActivityAt: number;\n lifecycle: SessionLifecycle;\n surfaceKind?: SessionHostSurfaceKind;\n writeOwner: SessionWriteOwner | null;\n attachedClients: SessionAttachedClient[];\n buffer: SessionBufferState;\n meta: Record<string, unknown>;\n}\n\nexport interface CreateSessionPayload {\n sessionId?: string;\n runtimeKey?: string;\n displayName?: string;\n providerType: string;\n category: SessionHostCategory;\n workspace: string;\n launchCommand: SessionLaunchCommand;\n cols?: number;\n rows?: number;\n clientId?: string;\n clientType?: SessionClientType;\n meta?: Record<string, unknown>;\n}\n\nexport interface AttachSessionPayload {\n sessionId: string;\n clientId: string;\n clientType: SessionClientType;\n readOnly?: boolean;\n}\n\nexport interface DetachSessionPayload {\n sessionId: string;\n clientId: string;\n}\n\nexport interface SendInputPayload {\n sessionId: string;\n clientId: string;\n data: string;\n}\n\nexport interface ResizeSessionPayload {\n sessionId: string;\n cols: number;\n rows: number;\n}\n\nexport interface StopSessionPayload {\n sessionId: string;\n}\n\nexport interface DeleteSessionPayload {\n sessionId: string;\n /** Stop a live runtime before deleting the persisted record. */\n force?: boolean;\n}\n\nexport interface ResumeSessionPayload {\n sessionId: string;\n}\n\nexport interface AcquireWritePayload {\n sessionId: string;\n clientId: string;\n ownerType: SessionOwnerType;\n force?: boolean;\n}\n\nexport interface ReleaseWritePayload {\n sessionId: string;\n clientId: string;\n}\n\nexport interface GetSnapshotPayload {\n sessionId: string;\n sinceSeq?: number;\n}\n\nexport interface ClearSessionBufferPayload {\n sessionId: string;\n}\n\nexport interface UpdateSessionMetaPayload {\n sessionId: string;\n meta: Record<string, unknown>;\n replace?: boolean;\n}\n\nexport interface GetHostDiagnosticsPayload {\n includeSessions?: boolean;\n limit?: number;\n}\n\nexport interface ForceDetachClientPayload {\n sessionId: string;\n clientId: string;\n}\n\nexport interface SendSignalPayload {\n sessionId: string;\n signal: string;\n}\n\nexport interface RestartSessionPayload {\n sessionId: string;\n}\n\nexport interface PruneDuplicateSessionsPayload {\n providerType?: string;\n workspace?: string;\n dryRun?: boolean;\n}\n\nexport interface SessionHostDuplicateSessionGroup {\n bindingKey: string;\n providerType: string;\n workspace: string;\n providerSessionId: string;\n keptSessionId: string;\n prunedSessionIds: string[];\n}\n\nexport interface SessionHostPruneDuplicatesResult {\n duplicateGroupCount: number;\n keptSessionIds: string[];\n prunedSessionIds: string[];\n groups: SessionHostDuplicateSessionGroup[];\n}\n\nexport interface SessionHostLogEntry {\n timestamp: number;\n level: 'debug' | 'info' | 'warn' | 'error';\n message: string;\n sessionId?: string;\n data?: Record<string, unknown>;\n}\n\nexport interface SessionHostRequestTrace {\n timestamp: number;\n requestId: string;\n type: SessionHostRequest['type'];\n sessionId?: string;\n clientId?: string;\n success: boolean;\n durationMs: number;\n error?: string;\n}\n\nexport interface SessionHostRuntimeTransition {\n timestamp: number;\n sessionId: string;\n action: string;\n lifecycle?: SessionLifecycle;\n detail?: string;\n success?: boolean;\n error?: string;\n}\n\nexport interface SessionHostDiagnostics {\n hostStartedAt: number;\n endpoint: string;\n runtimeCount: number;\n supportedRequestTypes?: SessionHostRequestType[];\n sessions?: SessionHostRecord[];\n liveRuntimes?: SessionHostRecord[];\n recoverySnapshots?: SessionHostRecord[];\n inactiveRecords?: SessionHostRecord[];\n recentLogs: SessionHostLogEntry[];\n recentRequests: SessionHostRequestTrace[];\n recentTransitions: SessionHostRuntimeTransition[];\n}\n\nexport type SessionHostRequest =\n | { type: 'create_session'; payload: CreateSessionPayload }\n | { type: 'attach_session'; payload: AttachSessionPayload }\n | { type: 'detach_session'; payload: DetachSessionPayload }\n | { type: 'send_input'; payload: SendInputPayload }\n | { type: 'resize_session'; payload: ResizeSessionPayload }\n | { type: 'stop_session'; payload: StopSessionPayload }\n | { type: 'delete_session'; payload: DeleteSessionPayload }\n | { type: 'resume_session'; payload: ResumeSessionPayload }\n | { type: 'acquire_write'; payload: AcquireWritePayload }\n | { type: 'release_write'; payload: ReleaseWritePayload }\n | { type: 'get_snapshot'; payload: GetSnapshotPayload }\n | { type: 'clear_session_buffer'; payload: ClearSessionBufferPayload }\n | { type: 'update_session_meta'; payload: UpdateSessionMetaPayload }\n | { type: 'get_host_diagnostics'; payload?: GetHostDiagnosticsPayload }\n | { type: 'force_detach_client'; payload: ForceDetachClientPayload }\n | { type: 'send_signal'; payload: SendSignalPayload }\n | { type: 'restart_session'; payload: RestartSessionPayload }\n | { type: 'prune_duplicate_sessions'; payload?: PruneDuplicateSessionsPayload }\n | { type: 'list_sessions'; payload?: {} };\n\nexport type SessionHostRequestType = SessionHostRequest['type'];\n\nexport const SESSION_HOST_SUPPORTED_REQUEST_TYPES: readonly SessionHostRequestType[] = [\n 'create_session',\n 'attach_session',\n 'detach_session',\n 'send_input',\n 'resize_session',\n 'stop_session',\n 'delete_session',\n 'resume_session',\n 'acquire_write',\n 'release_write',\n 'get_snapshot',\n 'clear_session_buffer',\n 'update_session_meta',\n 'get_host_diagnostics',\n 'force_detach_client',\n 'send_signal',\n 'restart_session',\n 'prune_duplicate_sessions',\n 'list_sessions',\n];\n\nexport interface SessionHostResponse<T = unknown> {\n success: boolean;\n result?: T;\n error?: string;\n}\n\nexport type SessionHostEvent =\n | { type: 'session_created'; sessionId: string; record: SessionHostRecord }\n | { type: 'session_started'; sessionId: string; pid?: number }\n | { type: 'session_resumed'; sessionId: string; pid?: number }\n | { type: 'session_output'; sessionId: string; seq: number; data: string }\n | { type: 'session_cleared'; sessionId: string }\n | { type: 'session_exit'; sessionId: string; exitCode: number | null }\n | { type: 'session_stopped'; sessionId: string }\n | { type: 'session_deleted'; sessionId: string }\n | { type: 'session_resized'; sessionId: string; cols: number; rows: number }\n | { type: 'write_owner_changed'; sessionId: string; owner: SessionWriteOwner | null }\n | { type: 'client_attached'; sessionId: string; client: SessionAttachedClient }\n | { type: 'client_detached'; sessionId: string; clientId: string }\n | { type: 'host_log'; entry: SessionHostLogEntry }\n | { type: 'request_trace'; trace: SessionHostRequestTrace }\n | { type: 'runtime_transition'; transition: SessionHostRuntimeTransition };\n\nexport interface SessionHostRequestEnvelope {\n kind: 'request';\n requestId: string;\n request: SessionHostRequest;\n}\n\nexport interface SessionHostResponseEnvelope {\n kind: 'response';\n requestId: string;\n response: SessionHostResponse;\n}\n\nexport interface SessionHostEventEnvelope {\n kind: 'event';\n event: SessionHostEvent;\n}\n\nexport type SessionHostWireEnvelope =\n | SessionHostRequestEnvelope\n | SessionHostResponseEnvelope\n | SessionHostEventEnvelope;\n","import type { SessionBufferSnapshot } from './types.js';\n\nexport interface SessionRingBufferOptions {\n maxBytes?: number;\n}\n\n// Manual \"Load older terminal output\" replays this raw ring buffer into the\n// browser terminal. 512KiB was too small for long Claude/Codex conversations:\n// by the time the user scrolled to the top and clicked the loader, the output\n// they were trying to recover was often already trimmed.\nexport const DEFAULT_SESSION_RING_BUFFER_MAX_BYTES = 4 * 1024 * 1024;\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 ?? DEFAULT_SESSION_RING_BUFFER_MAX_BYTES;\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 { resolveSessionHostCols, resolveSessionHostRows } from './defaults.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: resolveSessionHostCols(payload.cols),\n sessionHostRows: resolveSessionHostRows(payload.rows),\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 updateSessionMeta(sessionId: string, meta: Record<string, unknown>, replace = false): SessionHostRecord {\n const state = this.requireSession(sessionId);\n state.record.meta = replace\n ? { ...meta }\n : {\n ...(state.record.meta || {}),\n ...meta,\n };\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 deleteSession(sessionId: string): boolean {\n return this.sessions.delete(sessionId);\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","export const DEFAULT_SESSION_HOST_COLS = 80;\nexport const DEFAULT_SESSION_HOST_ROWS = 32;\n\nfunction normalizeSessionHostDimension(value: number | undefined, fallback: number): number {\n if (typeof value !== 'number' || !Number.isFinite(value)) return fallback;\n const rounded = Math.floor(value);\n return rounded > 0 ? rounded : fallback;\n}\n\nexport function resolveSessionHostCols(value: number | undefined): number {\n return normalizeSessionHostDimension(value, DEFAULT_SESSION_HOST_COLS);\n}\n\nexport function resolveSessionHostRows(value: number | undefined): number {\n return normalizeSessionHostDimension(value, DEFAULT_SESSION_HOST_ROWS);\n}\n","import * as path from 'path';\nimport type { CreateSessionPayload, SessionHostRecord, SessionHostSurfaceKind } 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\nexport interface SessionHostSurfaceRecordLike {\n lifecycle?: string | null;\n surfaceKind?: SessionHostSurfaceKind | null;\n meta?: Record<string, unknown> | null;\n}\n\nconst LIVE_LIFECYCLES = new Set(['starting', 'running', 'stopping', 'interrupted']);\n\nexport function isSessionHostLiveRuntime(record: SessionHostSurfaceRecordLike | null | undefined): boolean {\n if (!record) return false;\n if (record.surfaceKind === 'live_runtime') return true;\n if (record.surfaceKind === 'recovery_snapshot' || record.surfaceKind === 'inactive_record') return false;\n const lifecycle = String(record.lifecycle || '').trim();\n return LIVE_LIFECYCLES.has(lifecycle);\n}\n\nexport function getSessionHostRecoveryLabel(meta: Record<string, unknown> | null | undefined): string | null {\n const recoveryState = typeof meta?.runtimeRecoveryState === 'string'\n ? String(meta.runtimeRecoveryState).trim()\n : '';\n if (!recoveryState) return null;\n if (recoveryState === 'auto_resumed') return 'restored after restart';\n if (recoveryState === 'resume_failed') return 'restore failed';\n if (recoveryState === 'host_restart_interrupted') return 'host restart interrupted';\n if (recoveryState === 'orphan_snapshot') return 'snapshot recovered';\n return recoveryState.replace(/_/g, ' ');\n}\n\nexport function isSessionHostRecoverySnapshot(record: SessionHostSurfaceRecordLike | null | undefined): boolean {\n if (!record) return false;\n if (record.surfaceKind === 'recovery_snapshot') return true;\n if (record.surfaceKind === 'live_runtime' || record.surfaceKind === 'inactive_record') return false;\n if (isSessionHostLiveRuntime(record)) return false;\n\n const lifecycle = String(record.lifecycle || '').trim();\n if (lifecycle && lifecycle !== 'stopped' && lifecycle !== 'failed') {\n return false;\n }\n\n const meta = record.meta || undefined;\n if (meta?.restoredFromStorage === true) return true;\n return getSessionHostRecoveryLabel(meta) !== null;\n}\n\nexport function getSessionHostSurfaceKind(record: SessionHostSurfaceRecordLike | null | undefined): SessionHostSurfaceKind {\n if (record?.surfaceKind === 'live_runtime' || record?.surfaceKind === 'recovery_snapshot' || record?.surfaceKind === 'inactive_record') {\n return record.surfaceKind;\n }\n if (isSessionHostLiveRuntime(record)) return 'live_runtime';\n if (isSessionHostRecoverySnapshot(record)) return 'recovery_snapshot';\n return 'inactive_record';\n}\n\nexport function resolveAttachableRuntimeRecord(records: SessionHostRecord[], identifier: string): SessionHostRecord {\n const record = resolveRuntimeRecord(records, identifier);\n const surfaceKind = getSessionHostSurfaceKind(record);\n if (surfaceKind === 'live_runtime') {\n return record;\n }\n if (surfaceKind === 'recovery_snapshot') {\n throw new Error(`Runtime ${record.runtimeKey} is a recovery snapshot, not a live attach target. Resume or recover it first.`);\n }\n throw new Error(`Runtime ${record.runtimeKey} is ${record.lifecycle}, not a live attach target.`);\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 // Cleanup stale socket reference left after error/disconnect\n if (this.socket) {\n try { this.socket.destroy(); } catch { /* noop */ }\n this.socket = null;\n }\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 // Clear the dead socket reference so the next connect() creates a fresh connection\n // instead of skipping reconnection on the `!this.socket.destroyed` guard.\n if (this.socket === socket) {\n this.socket = null;\n }\n try { socket.destroy(); } catch { /* noop */ }\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 const timeout = setTimeout(() => {\n this.requestWaiters.delete(requestId);\n reject(new Error(`Session host request timed out after 30s (${request.type})`));\n }, 30_000);\n this.requestWaiters.set(requestId, {\n resolve: (value) => { clearTimeout(timeout); resolve(value); },\n reject: (error) => { clearTimeout(timeout); reject(error); },\n });\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","/**\n * Shared PTY spawn environment utilities.\n *\n * Centralises npm/pnpm/yarn env variable stripping, terminal colour env\n * injection, and node-pty spawn-helper permission fixing.\n *\n * Used by daemon-core (provider-cli-adapter), session-host-daemon (runtime),\n * and daemon-cloud (session-host).\n */\n\nimport * as os from 'os';\nimport * as path from 'path';\n\n/**\n * Strip package-manager injected environment variables that can interfere\n * with child CLI processes and apply terminal colour defaults.\n */\nexport function sanitizeSpawnEnv(\n baseEnv: NodeJS.ProcessEnv,\n overrides?: Record<string, string>,\n): Record<string, string> {\n const env: Record<string, string> = {};\n const source = { ...baseEnv, ...(overrides || {}) } as NodeJS.ProcessEnv;\n\n for (const [key, value] of Object.entries(source)) {\n if (typeof value !== 'string') continue;\n env[key] = value;\n }\n\n for (const key of Object.keys(env)) {\n if (\n key === 'INIT_CWD'\n || key === 'npm_command'\n || key === 'npm_execpath'\n || key === 'npm_node_execpath'\n || key.startsWith('npm_')\n || key.startsWith('npm_config_')\n || key.startsWith('npm_package_')\n || key.startsWith('npm_lifecycle_')\n || key.startsWith('PNPM_')\n || key.startsWith('YARN_')\n || key.startsWith('BUN_')\n || key.startsWith('VSCODE_')\n || key.startsWith('ELECTRON_')\n ) {\n delete env[key];\n }\n }\n\n // Do not leak the parent Codex app/extension thread identity into child CLIs.\n // Those variables cause codex-cli to attach to the current IDE thread instead\n // of creating or resuming its own standalone CLI thread, which breaks\n // providerSessionId discovery and reconnect semantics.\n delete env.CODEX_THREAD_ID;\n delete env.CODEX_INTERNAL_ORIGINATOR_OVERRIDE;\n\n applyTerminalColorEnv(env);\n return env;\n}\n\n/**\n * Apply preferred terminal colour environment variables.\n * Ensures TERM is set to xterm-256color and enables colour on Windows.\n */\nexport function applyTerminalColorEnv(env: Record<string, string>): void {\n if (env.NO_COLOR) return;\n\n if (!env.TERM || env.TERM === 'xterm-color') {\n env.TERM = 'xterm-256color';\n }\n if (!env.COLORTERM) env.COLORTERM = 'truecolor';\n\n if (process.platform === 'win32') {\n if (!env.FORCE_COLOR) env.FORCE_COLOR = '1';\n if (!env.CLICOLOR) env.CLICOLOR = '1';\n }\n}\n\n/**\n * Ensure node-pty's spawn-helper binary has execute permissions.\n *\n * npm's default umask can strip +x from the prebuilt spawn-helper on macOS/Linux,\n * causing EACCES when node-pty tries to fork. Best-effort fix.\n *\n * @param logFn Optional log callback for reporting the fix.\n */\nexport function ensureNodePtySpawnHelperPermissions(\n logFn?: (msg: string) => void,\n): void {\n if (os.platform() === 'win32') return;\n try {\n const fs = require('fs');\n const ptyDir = path.resolve(path.dirname(require.resolve('node-pty')), '..');\n const platformArch = `${os.platform()}-${os.arch()}`;\n const helper = path.join(ptyDir, 'prebuilds', platformArch, 'spawn-helper');\n if (fs.existsSync(helper)) {\n const stat = fs.statSync(helper);\n if (!(stat.mode & 0o111)) {\n fs.chmodSync(helper, stat.mode | 0o755);\n logFn?.(`Fixed spawn-helper permissions: ${helper}`);\n }\n }\n } catch {\n // best-effort: node-pty still works on most installs without this\n }\n}\n"],"mappings":"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","names":["path","randomUUID","resolve","os","path"]}
1
+ {"version":3,"sources":["../src/types.ts","../src/buffer.ts","../src/defaults.ts","../src/runtime-labels.ts","../src/registry.ts","../src/ipc.ts","../src/spawn-env.ts"],"sourcesContent":["export type SessionTransport = 'pty';\n\nexport type SessionHostCategory = 'cli' | 'acp' | 'shell';\n\nexport type SessionLifecycle = 'starting' | 'running' | 'stopping' | 'stopped' | 'failed' | 'interrupted';\n\nexport type SessionClientType = 'daemon' | 'web' | 'local-terminal';\n\nexport type SessionOwnerType = 'agent' | 'user';\n\nexport interface SessionLaunchCommand {\n command: string;\n args: string[];\n env?: Record<string, string>;\n}\n\nexport interface SessionWriteOwner {\n clientId: string;\n ownerType: SessionOwnerType;\n acquiredAt: number;\n}\n\nexport interface SessionAttachedClient {\n clientId: string;\n type: SessionClientType;\n readOnly: boolean;\n attachedAt: number;\n lastSeenAt: number;\n}\n\nexport interface SessionBufferSnapshot {\n seq: number;\n text: string;\n truncated: boolean;\n cols?: number;\n rows?: number;\n}\n\nexport interface SessionBufferState {\n scrollbackBytes: number;\n snapshotSeq: number;\n}\n\nexport type SessionHostSurfaceKind = 'live_runtime' | 'recovery_snapshot' | 'inactive_record';\n\nexport interface SessionHostRecord {\n sessionId: string;\n runtimeKey: string;\n displayName: string;\n workspaceLabel: string;\n transport: SessionTransport;\n providerType: string;\n category: SessionHostCategory;\n workspace: string;\n launchCommand: SessionLaunchCommand;\n osPid?: number;\n createdAt: number;\n startedAt?: number;\n lastActivityAt: number;\n lifecycle: SessionLifecycle;\n surfaceKind?: SessionHostSurfaceKind;\n writeOwner: SessionWriteOwner | null;\n attachedClients: SessionAttachedClient[];\n buffer: SessionBufferState;\n meta: Record<string, unknown>;\n}\n\nexport interface CreateSessionPayload {\n sessionId?: string;\n runtimeKey?: string;\n displayName?: string;\n providerType: string;\n category: SessionHostCategory;\n workspace: string;\n launchCommand: SessionLaunchCommand;\n cols?: number;\n rows?: number;\n clientId?: string;\n clientType?: SessionClientType;\n meta?: Record<string, unknown>;\n}\n\nexport interface AttachSessionPayload {\n sessionId: string;\n clientId: string;\n clientType: SessionClientType;\n readOnly?: boolean;\n}\n\nexport interface DetachSessionPayload {\n sessionId: string;\n clientId: string;\n}\n\nexport interface SendInputPayload {\n sessionId: string;\n clientId: string;\n data: string;\n}\n\nexport interface ResizeSessionPayload {\n sessionId: string;\n cols: number;\n rows: number;\n}\n\nexport interface StopSessionPayload {\n sessionId: string;\n}\n\nexport interface DeleteSessionPayload {\n sessionId: string;\n /** Stop a live runtime before deleting the persisted record. */\n force?: boolean;\n}\n\nexport interface ResumeSessionPayload {\n sessionId: string;\n}\n\nexport interface AcquireWritePayload {\n sessionId: string;\n clientId: string;\n ownerType: SessionOwnerType;\n force?: boolean;\n}\n\nexport interface ReleaseWritePayload {\n sessionId: string;\n clientId: string;\n}\n\nexport interface GetSnapshotPayload {\n sessionId: string;\n sinceSeq?: number;\n}\n\nexport interface ClearSessionBufferPayload {\n sessionId: string;\n}\n\nexport interface UpdateSessionMetaPayload {\n sessionId: string;\n meta: Record<string, unknown>;\n replace?: boolean;\n}\n\nexport interface GetHostDiagnosticsPayload {\n includeSessions?: boolean;\n limit?: number;\n}\n\nexport interface ForceDetachClientPayload {\n sessionId: string;\n clientId: string;\n}\n\nexport interface SendSignalPayload {\n sessionId: string;\n signal: string;\n}\n\nexport interface RestartSessionPayload {\n sessionId: string;\n}\n\nexport interface PruneDuplicateSessionsPayload {\n providerType?: string;\n workspace?: string;\n dryRun?: boolean;\n}\n\nexport interface SessionHostDuplicateSessionGroup {\n bindingKey: string;\n providerType: string;\n workspace: string;\n providerSessionId: string;\n keptSessionId: string;\n prunedSessionIds: string[];\n}\n\nexport interface SessionHostPruneDuplicatesResult {\n duplicateGroupCount: number;\n keptSessionIds: string[];\n prunedSessionIds: string[];\n groups: SessionHostDuplicateSessionGroup[];\n}\n\nexport interface SessionHostLogEntry {\n timestamp: number;\n level: 'debug' | 'info' | 'warn' | 'error';\n message: string;\n sessionId?: string;\n data?: Record<string, unknown>;\n}\n\nexport interface SessionHostRequestTrace {\n timestamp: number;\n requestId: string;\n type: SessionHostRequest['type'];\n sessionId?: string;\n clientId?: string;\n success: boolean;\n durationMs: number;\n error?: string;\n}\n\nexport interface SessionHostRuntimeTransition {\n timestamp: number;\n sessionId: string;\n action: string;\n lifecycle?: SessionLifecycle;\n detail?: string;\n success?: boolean;\n error?: string;\n}\n\nexport interface SessionHostDiagnostics {\n hostStartedAt: number;\n endpoint: string;\n runtimeCount: number;\n supportedRequestTypes?: SessionHostRequestType[];\n sessions?: SessionHostRecord[];\n liveRuntimes?: SessionHostRecord[];\n recoverySnapshots?: SessionHostRecord[];\n inactiveRecords?: SessionHostRecord[];\n recentLogs: SessionHostLogEntry[];\n recentRequests: SessionHostRequestTrace[];\n recentTransitions: SessionHostRuntimeTransition[];\n}\n\nexport type SessionHostRequest =\n | { type: 'create_session'; payload: CreateSessionPayload }\n | { type: 'attach_session'; payload: AttachSessionPayload }\n | { type: 'detach_session'; payload: DetachSessionPayload }\n | { type: 'send_input'; payload: SendInputPayload }\n | { type: 'resize_session'; payload: ResizeSessionPayload }\n | { type: 'stop_session'; payload: StopSessionPayload }\n | { type: 'delete_session'; payload: DeleteSessionPayload }\n | { type: 'resume_session'; payload: ResumeSessionPayload }\n | { type: 'acquire_write'; payload: AcquireWritePayload }\n | { type: 'release_write'; payload: ReleaseWritePayload }\n | { type: 'get_snapshot'; payload: GetSnapshotPayload }\n | { type: 'clear_session_buffer'; payload: ClearSessionBufferPayload }\n | { type: 'update_session_meta'; payload: UpdateSessionMetaPayload }\n | { type: 'get_host_diagnostics'; payload?: GetHostDiagnosticsPayload }\n | { type: 'force_detach_client'; payload: ForceDetachClientPayload }\n | { type: 'send_signal'; payload: SendSignalPayload }\n | { type: 'restart_session'; payload: RestartSessionPayload }\n | { type: 'prune_duplicate_sessions'; payload?: PruneDuplicateSessionsPayload }\n | { type: 'list_sessions'; payload?: {} };\n\nexport type SessionHostRequestType = SessionHostRequest['type'];\n\nexport const SESSION_HOST_SUPPORTED_REQUEST_TYPES: readonly SessionHostRequestType[] = [\n 'create_session',\n 'attach_session',\n 'detach_session',\n 'send_input',\n 'resize_session',\n 'stop_session',\n 'delete_session',\n 'resume_session',\n 'acquire_write',\n 'release_write',\n 'get_snapshot',\n 'clear_session_buffer',\n 'update_session_meta',\n 'get_host_diagnostics',\n 'force_detach_client',\n 'send_signal',\n 'restart_session',\n 'prune_duplicate_sessions',\n 'list_sessions',\n];\n\nexport interface SessionHostResponse<T = unknown> {\n success: boolean;\n result?: T;\n error?: string;\n}\n\nexport type SessionHostEvent =\n | { type: 'session_created'; sessionId: string; record: SessionHostRecord }\n | { type: 'session_started'; sessionId: string; pid?: number }\n | { type: 'session_resumed'; sessionId: string; pid?: number }\n | { type: 'session_output'; sessionId: string; seq: number; data: string }\n | { type: 'session_cleared'; sessionId: string }\n | { type: 'session_exit'; sessionId: string; exitCode: number | null }\n | { type: 'session_stopped'; sessionId: string }\n | { type: 'session_deleted'; sessionId: string }\n | { type: 'session_resized'; sessionId: string; cols: number; rows: number }\n | { type: 'write_owner_changed'; sessionId: string; owner: SessionWriteOwner | null }\n | { type: 'client_attached'; sessionId: string; client: SessionAttachedClient }\n | { type: 'client_detached'; sessionId: string; clientId: string }\n | { type: 'host_log'; entry: SessionHostLogEntry }\n | { type: 'request_trace'; trace: SessionHostRequestTrace }\n | { type: 'runtime_transition'; transition: SessionHostRuntimeTransition };\n\nexport interface SessionHostRequestEnvelope {\n kind: 'request';\n requestId: string;\n request: SessionHostRequest;\n}\n\nexport interface SessionHostResponseEnvelope {\n kind: 'response';\n requestId: string;\n response: SessionHostResponse;\n}\n\nexport interface SessionHostEventEnvelope {\n kind: 'event';\n event: SessionHostEvent;\n}\n\nexport type SessionHostWireEnvelope =\n | SessionHostRequestEnvelope\n | SessionHostResponseEnvelope\n | SessionHostEventEnvelope;\n","import type { SessionBufferSnapshot } from './types.js';\n\nexport interface SessionRingBufferOptions {\n maxBytes?: number;\n}\n\n// Manual \"Load older terminal output\" replays this raw ring buffer into the\n// browser terminal. 512KiB was too small for long Claude/Codex conversations:\n// by the time the user scrolled to the top and clicked the loader, the output\n// they were trying to recover was often already trimmed.\nexport const DEFAULT_SESSION_RING_BUFFER_MAX_BYTES = 4 * 1024 * 1024;\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 ?? DEFAULT_SESSION_RING_BUFFER_MAX_BYTES;\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","export const DEFAULT_SESSION_HOST_COLS = 80;\nexport const DEFAULT_SESSION_HOST_ROWS = 32;\n\nfunction normalizeSessionHostDimension(value: number | undefined, fallback: number): number {\n if (typeof value !== 'number' || !Number.isFinite(value)) return fallback;\n const rounded = Math.floor(value);\n return rounded > 0 ? rounded : fallback;\n}\n\nexport function resolveSessionHostCols(value: number | undefined): number {\n return normalizeSessionHostDimension(value, DEFAULT_SESSION_HOST_COLS);\n}\n\nexport function resolveSessionHostRows(value: number | undefined): number {\n return normalizeSessionHostDimension(value, DEFAULT_SESSION_HOST_ROWS);\n}\n","import * as path from 'path';\nimport type { CreateSessionPayload, SessionHostRecord, SessionHostSurfaceKind } 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\nexport interface SessionHostSurfaceRecordLike {\n lifecycle?: string | null;\n surfaceKind?: SessionHostSurfaceKind | null;\n meta?: Record<string, unknown> | null;\n}\n\nconst LIVE_LIFECYCLES = new Set(['starting', 'running', 'stopping', 'interrupted']);\n\nexport function isSessionHostLiveRuntime(record: SessionHostSurfaceRecordLike | null | undefined): boolean {\n if (!record) return false;\n if (record.surfaceKind === 'live_runtime') return true;\n if (record.surfaceKind === 'recovery_snapshot' || record.surfaceKind === 'inactive_record') return false;\n const lifecycle = String(record.lifecycle || '').trim();\n return LIVE_LIFECYCLES.has(lifecycle);\n}\n\nexport function getSessionHostRecoveryLabel(meta: Record<string, unknown> | null | undefined): string | null {\n const recoveryState = typeof meta?.runtimeRecoveryState === 'string'\n ? String(meta.runtimeRecoveryState).trim()\n : '';\n if (!recoveryState) return null;\n if (recoveryState === 'auto_resumed') return 'restored after restart';\n if (recoveryState === 'resume_failed') return 'restore failed';\n if (recoveryState === 'host_restart_interrupted') return 'host restart interrupted';\n if (recoveryState === 'orphan_snapshot') return 'snapshot recovered';\n return recoveryState.replace(/_/g, ' ');\n}\n\nexport function isSessionHostRecoverySnapshot(record: SessionHostSurfaceRecordLike | null | undefined): boolean {\n if (!record) return false;\n if (record.surfaceKind === 'recovery_snapshot') return true;\n if (record.surfaceKind === 'live_runtime' || record.surfaceKind === 'inactive_record') return false;\n if (isSessionHostLiveRuntime(record)) return false;\n\n const lifecycle = String(record.lifecycle || '').trim();\n if (lifecycle && lifecycle !== 'stopped' && lifecycle !== 'failed') {\n return false;\n }\n\n const meta = record.meta || undefined;\n if (meta?.restoredFromStorage === true) return true;\n return getSessionHostRecoveryLabel(meta) !== null;\n}\n\nexport function getSessionHostSurfaceKind(record: SessionHostSurfaceRecordLike | null | undefined): SessionHostSurfaceKind {\n if (record?.surfaceKind === 'live_runtime' || record?.surfaceKind === 'recovery_snapshot' || record?.surfaceKind === 'inactive_record') {\n return record.surfaceKind;\n }\n if (isSessionHostLiveRuntime(record)) return 'live_runtime';\n if (isSessionHostRecoverySnapshot(record)) return 'recovery_snapshot';\n return 'inactive_record';\n}\n\nexport function resolveAttachableRuntimeRecord(records: SessionHostRecord[], identifier: string): SessionHostRecord {\n const record = resolveRuntimeRecord(records, identifier);\n const surfaceKind = getSessionHostSurfaceKind(record);\n if (surfaceKind === 'live_runtime') {\n return record;\n }\n if (surfaceKind === 'recovery_snapshot') {\n throw new Error(`Runtime ${record.runtimeKey} is a recovery snapshot, not a live attach target. Resume or recover it first.`);\n }\n throw new Error(`Runtime ${record.runtimeKey} is ${record.lifecycle}, not a live attach target.`);\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","function generateUUID(): string {\n if (typeof crypto !== 'undefined' && crypto.randomUUID) {\n return crypto.randomUUID();\n }\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {\n const r = Math.random() * 16 | 0;\n const v = c === 'x' ? r : (r & 0x3 | 0x8);\n return v.toString(16);\n });\n}\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 { resolveSessionHostCols, resolveSessionHostRows } from './defaults.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 || generateUUID();\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: resolveSessionHostCols(payload.cols),\n sessionHostRows: resolveSessionHostRows(payload.rows),\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 updateSessionMeta(sessionId: string, meta: Record<string, unknown>, replace = false): SessionHostRecord {\n const state = this.requireSession(sessionId);\n state.record.meta = replace\n ? { ...meta }\n : {\n ...(state.record.meta || {}),\n ...meta,\n };\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 deleteSession(sessionId: string): boolean {\n return this.sessions.delete(sessionId);\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 os from 'os';\nimport * as path from 'path';\nimport * as net from 'net';\nimport type {\n SessionHostEvent,\n SessionHostRequest,\n SessionHostRequestEnvelope,\n SessionHostResponse,\n SessionHostResponseEnvelope,\n SessionHostWireEnvelope,\n} from './types.js';\n\nfunction generateUUID(): string {\n if (typeof crypto !== 'undefined' && crypto.randomUUID) {\n return crypto.randomUUID();\n }\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {\n const r = Math.random() * 16 | 0;\n const v = c === 'x' ? r : (r & 0x3 | 0x8);\n return v.toString(16);\n });\n}\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 // Cleanup stale socket reference left after error/disconnect\n if (this.socket) {\n try { this.socket.destroy(); } catch { /* noop */ }\n this.socket = null;\n }\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 // Clear the dead socket reference so the next connect() creates a fresh connection\n // instead of skipping reconnection on the `!this.socket.destroyed` guard.\n if (this.socket === socket) {\n this.socket = null;\n }\n try { socket.destroy(); } catch { /* noop */ }\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 = generateUUID();\n const envelope: SessionHostRequestEnvelope = {\n kind: 'request',\n requestId,\n request,\n };\n\n const response = await new Promise<SessionHostResponse>((resolve, reject) => {\n const timeout = setTimeout(() => {\n this.requestWaiters.delete(requestId);\n reject(new Error(`Session host request timed out after 30s (${request.type})`));\n }, 30_000);\n this.requestWaiters.set(requestId, {\n resolve: (value) => { clearTimeout(timeout); resolve(value); },\n reject: (error) => { clearTimeout(timeout); reject(error); },\n });\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","/**\n * Shared PTY spawn environment utilities.\n *\n * Centralises npm/pnpm/yarn env variable stripping, terminal colour env\n * injection, and node-pty spawn-helper permission fixing.\n *\n * Used by daemon-core (provider-cli-adapter), session-host-daemon (runtime),\n * and daemon-cloud (session-host).\n */\n\nimport * as os from 'os';\nimport * as path from 'path';\n\n/**\n * Strip package-manager injected environment variables that can interfere\n * with child CLI processes and apply terminal colour defaults.\n */\nexport function sanitizeSpawnEnv(\n baseEnv: NodeJS.ProcessEnv,\n overrides?: Record<string, string>,\n): Record<string, string> {\n const env: Record<string, string> = {};\n const source = { ...baseEnv, ...(overrides || {}) } as NodeJS.ProcessEnv;\n\n for (const [key, value] of Object.entries(source)) {\n if (typeof value !== 'string') continue;\n env[key] = value;\n }\n\n for (const key of Object.keys(env)) {\n if (\n key === 'INIT_CWD'\n || key === 'npm_command'\n || key === 'npm_execpath'\n || key === 'npm_node_execpath'\n || key.startsWith('npm_')\n || key.startsWith('npm_config_')\n || key.startsWith('npm_package_')\n || key.startsWith('npm_lifecycle_')\n || key.startsWith('PNPM_')\n || key.startsWith('YARN_')\n || key.startsWith('BUN_')\n || key.startsWith('VSCODE_')\n || key.startsWith('ELECTRON_')\n ) {\n delete env[key];\n }\n }\n\n // Do not leak the parent Codex app/extension thread identity into child CLIs.\n // Those variables cause codex-cli to attach to the current IDE thread instead\n // of creating or resuming its own standalone CLI thread, which breaks\n // providerSessionId discovery and reconnect semantics.\n delete env.CODEX_THREAD_ID;\n delete env.CODEX_INTERNAL_ORIGINATOR_OVERRIDE;\n\n applyTerminalColorEnv(env);\n return env;\n}\n\n/**\n * Apply preferred terminal colour environment variables.\n * Ensures TERM is set to xterm-256color and enables colour on Windows.\n */\nexport function applyTerminalColorEnv(env: Record<string, string>): void {\n if (env.NO_COLOR) return;\n\n if (!env.TERM || env.TERM === 'xterm-color') {\n env.TERM = 'xterm-256color';\n }\n if (!env.COLORTERM) env.COLORTERM = 'truecolor';\n\n if (process.platform === 'win32') {\n if (!env.FORCE_COLOR) env.FORCE_COLOR = '1';\n if (!env.CLICOLOR) env.CLICOLOR = '1';\n }\n}\n\n/**\n * Ensure node-pty's spawn-helper binary has execute permissions.\n *\n * npm's default umask can strip +x from the prebuilt spawn-helper on macOS/Linux,\n * causing EACCES when node-pty tries to fork. Best-effort fix.\n *\n * @param logFn Optional log callback for reporting the fix.\n */\nexport function ensureNodePtySpawnHelperPermissions(\n logFn?: (msg: string) => void,\n): void {\n if (os.platform() === 'win32') return;\n try {\n const fs = require('fs');\n const ptyDir = path.resolve(path.dirname(require.resolve('node-pty')), '..');\n const platformArch = `${os.platform()}-${os.arch()}`;\n const helper = path.join(ptyDir, 'prebuilds', platformArch, 'spawn-helper');\n if (fs.existsSync(helper)) {\n const stat = fs.statSync(helper);\n if (!(stat.mode & 0o111)) {\n fs.chmodSync(helper, stat.mode | 0o755);\n logFn?.(`Fixed spawn-helper permissions: ${helper}`);\n }\n }\n } catch {\n // best-effort: node-pty still works on most installs without this\n }\n}\n"],"mappings":"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","names":["path","generateUUID","resolve","os","path"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adhdev/session-host-core",
3
- "version": "0.9.76",
3
+ "version": "0.9.78",
4
4
  "description": "ADHDev local session host core \u2014 session registry, protocol, buffers",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/src/ipc.ts CHANGED
@@ -1,7 +1,6 @@
1
1
  import * as os from 'os';
2
2
  import * as path from 'path';
3
3
  import * as net from 'net';
4
- import { randomUUID } from 'crypto';
5
4
  import type {
6
5
  SessionHostEvent,
7
6
  SessionHostRequest,
@@ -11,6 +10,17 @@ import type {
11
10
  SessionHostWireEnvelope,
12
11
  } from './types.js';
13
12
 
13
+ function generateUUID(): string {
14
+ if (typeof crypto !== 'undefined' && crypto.randomUUID) {
15
+ return crypto.randomUUID();
16
+ }
17
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
18
+ const r = Math.random() * 16 | 0;
19
+ const v = c === 'x' ? r : (r & 0x3 | 0x8);
20
+ return v.toString(16);
21
+ });
22
+ }
23
+
14
24
  export interface SessionHostEndpoint {
15
25
  kind: 'unix' | 'pipe';
16
26
  path: string;
@@ -122,7 +132,7 @@ export class SessionHostClient {
122
132
  await this.connect();
123
133
  if (!this.socket) throw new Error('Session host socket unavailable');
124
134
 
125
- const requestId = randomUUID();
135
+ const requestId = generateUUID();
126
136
  const envelope: SessionHostRequestEnvelope = {
127
137
  kind: 'request',
128
138
  requestId,
package/src/registry.ts CHANGED
@@ -1,4 +1,13 @@
1
- import { randomUUID } from 'crypto';
1
+ function generateUUID(): string {
2
+ if (typeof crypto !== 'undefined' && crypto.randomUUID) {
3
+ return crypto.randomUUID();
4
+ }
5
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
6
+ const r = Math.random() * 16 | 0;
7
+ const v = c === 'x' ? r : (r & 0x3 | 0x8);
8
+ return v.toString(16);
9
+ });
10
+ }
2
11
  import type {
3
12
  AcquireWritePayload,
4
13
  AttachSessionPayload,
@@ -21,7 +30,7 @@ export class SessionHostRegistry {
21
30
  private sessions = new Map<string, SessionRuntimeState>();
22
31
 
23
32
  createSession(payload: CreateSessionPayload): SessionHostRecord {
24
- const sessionId = payload.sessionId || randomUUID();
33
+ const sessionId = payload.sessionId || generateUUID();
25
34
  if (this.sessions.has(sessionId)) {
26
35
  throw new Error(`Session already exists: ${sessionId}`);
27
36
  }