@bytespell/amux 0.0.4 → 0.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/dist/chunk-C73RKCTS.js +36 -0
  2. package/dist/chunk-C73RKCTS.js.map +1 -0
  3. package/dist/chunk-HJCRMFTD.js +771 -0
  4. package/dist/chunk-HJCRMFTD.js.map +1 -0
  5. package/dist/lib/logger.d.ts +24 -0
  6. package/dist/{src/lib → lib}/logger.js +1 -2
  7. package/dist/lib/mentions.d.ts +14 -0
  8. package/dist/lib/mentions.js +7 -0
  9. package/dist/streams/backends/index.d.ts +88 -0
  10. package/dist/streams/backends/index.js +13 -0
  11. package/dist/streams/manager.d.ts +49 -0
  12. package/dist/streams/manager.js +237 -0
  13. package/dist/streams/manager.js.map +1 -0
  14. package/dist/types-DoG5bt6C.d.ts +153 -0
  15. package/dist/types.d.ts +2 -0
  16. package/dist/{chunk-226DBKL3.js → types.js} +7 -8
  17. package/dist/types.js.map +1 -0
  18. package/package.json +10 -37
  19. package/scripts/fix-pty.cjs +21 -0
  20. package/dist/bin/cli.js +0 -28
  21. package/dist/bin/cli.js.map +0 -1
  22. package/dist/chunk-226DBKL3.js.map +0 -1
  23. package/dist/chunk-2NON2HR2.js +0 -1602
  24. package/dist/chunk-2NON2HR2.js.map +0 -1
  25. package/dist/chunk-L4DBPVMA.js +0 -122
  26. package/dist/chunk-L4DBPVMA.js.map +0 -1
  27. package/dist/chunk-OQ5K5ON2.js +0 -319
  28. package/dist/chunk-OQ5K5ON2.js.map +0 -1
  29. package/dist/chunk-PZ5AY32C.js +0 -10
  30. package/dist/chunk-SX7NC3ZM.js +0 -65
  31. package/dist/chunk-SX7NC3ZM.js.map +0 -1
  32. package/dist/chunk-YYN3GXYP.js +0 -333
  33. package/dist/chunk-YYN3GXYP.js.map +0 -1
  34. package/dist/src/agents/eventStore.js +0 -22
  35. package/dist/src/agents/eventStore.js.map +0 -1
  36. package/dist/src/agents/manager.js +0 -12
  37. package/dist/src/agents/manager.js.map +0 -1
  38. package/dist/src/db/index.js +0 -10
  39. package/dist/src/server.js +0 -16
  40. package/dist/src/server.js.map +0 -1
  41. package/dist/src/trpc/files.js +0 -11
  42. package/dist/src/trpc/files.js.map +0 -1
  43. package/dist/src/types.js +0 -12
  44. package/dist/src/types.js.map +0 -1
  45. /package/dist/{src/lib → lib}/logger.js.map +0 -0
  46. /package/dist/{chunk-PZ5AY32C.js.map → lib/mentions.js.map} +0 -0
  47. /package/dist/{src/db → streams/backends}/index.js.map +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/streams/backends/acp.ts","../src/streams/process.ts","../src/streams/backends/mock.ts","../src/streams/backends/shell.ts"],"sourcesContent":["import { randomUUID } from 'crypto';\nimport { spawn as nodeSpawn, type ChildProcess } from 'child_process';\nimport { Readable, Writable } from 'stream';\nimport * as fs from 'fs/promises';\nimport * as fsSync from 'fs';\nimport * as path from 'path';\nimport {\n ClientSideConnection,\n ndJsonStream,\n Client,\n RequestPermissionRequest,\n RequestPermissionResponse,\n SessionNotification,\n ReadTextFileRequest,\n ReadTextFileResponse,\n WriteTextFileRequest,\n WriteTextFileResponse,\n CreateTerminalRequest,\n CreateTerminalResponse,\n TerminalOutputRequest,\n TerminalOutputResponse,\n WaitForTerminalExitRequest,\n WaitForTerminalExitResponse,\n KillTerminalCommandRequest,\n KillTerminalCommandResponse,\n ReleaseTerminalRequest,\n ReleaseTerminalResponse,\n} from '@agentclientprotocol/sdk';\nimport type { StreamDriver, StreamConfig, Stream, EmitFn } from './types.js';\nimport type { PendingPermission, StreamPayload } from '../../types.js';\nimport { spawn, type ManagedProcess } from '../process.js';\nimport { debug } from '../../lib/logger.js';\nimport { parseMessageToContentBlocks } from '../../lib/mentions.js';\n\nconst INIT_TIMEOUT_MS = 90000; // 90s to allow npx download on first run\n\n/** ACP backend state for persistence */\nexport interface AcpBackendState {\n acpSessionId: string;\n}\n\n/**\n * Normalize ACP session updates.\n *\n * Amux passes through events as-is, but normalizes quirks from specific agents:\n * - Claude sends Edit/Write diffs as {newText, oldText, path} instead of unified diff\n * - We convert these to standard unified diff format so the UI doesn't need agent-specific logic\n */\nfunction normalizeSessionUpdate(update: Record<string, unknown>): Record<string, unknown> {\n // Only process tool_call and tool_call_update events with content arrays\n if (update.sessionUpdate !== 'tool_call' && update.sessionUpdate !== 'tool_call_update') {\n return update;\n }\n\n const content = update.content as Array<Record<string, unknown>> | undefined;\n if (!content || !Array.isArray(content)) {\n return update;\n }\n\n // Check for diff items that need normalization\n const normalizedContent = content.map(item => {\n if (item.type !== 'diff') return item;\n\n // Already a string diff - pass through\n if (typeof item.content === 'string') return item;\n\n // Claude-style diff: {type: 'diff', newText, oldText, path}\n // Convert to unified diff format\n const newText = item.newText as string | undefined;\n const oldText = item.oldText as string | null | undefined;\n const path = item.path as string | undefined;\n\n if (newText === undefined) return item;\n\n // Generate unified diff\n const filePath = path ?? 'file';\n const oldLines = oldText ? oldText.split('\\n') : [];\n const newLines = newText.split('\\n');\n\n let unifiedDiff = `Index: ${filePath}\\n`;\n unifiedDiff += '===================================================================\\n';\n unifiedDiff += `--- ${filePath}\\n`;\n unifiedDiff += `+++ ${filePath}\\n`;\n unifiedDiff += `@@ -${oldLines.length > 0 ? 1 : 0},${oldLines.length} +1,${newLines.length} @@\\n`;\n\n for (const line of oldLines) {\n unifiedDiff += `-${line}\\n`;\n }\n for (const line of newLines) {\n unifiedDiff += `+${line}\\n`;\n }\n\n // Return normalized diff item\n return {\n type: 'diff',\n content: unifiedDiff,\n };\n });\n\n return {\n ...update,\n content: normalizedContent,\n };\n}\n\nfunction withTimeout<T>(promise: Promise<T>, ms: number, operation: string): Promise<T> {\n return Promise.race([\n promise,\n new Promise<T>((_, reject) =>\n setTimeout(() => reject(new Error(`${operation} timed out after ${ms}ms`)), ms)\n ),\n ]);\n}\n\ninterface Terminal {\n process: ChildProcess;\n output: string;\n exitCode: number | null;\n signal: string | null;\n truncated: boolean;\n outputByteLimit: number;\n}\n\ninterface AcpInstance {\n process: ManagedProcess;\n connection: ClientSideConnection;\n acpSessionId: string; // The ACP protocol session ID\n pendingPermission: PendingPermission | null;\n permissionCallbacks: Map<string, {\n resolve: (optionId: string) => void;\n reject: (err: Error) => void;\n }>;\n emit: EmitFn;\n terminals: Map<string, Terminal>;\n storageDir: string;\n}\n\nexport class AcpDriver implements StreamDriver {\n readonly type = 'acp';\n readonly streamType = 'acp' as const;\n private instances = new Map<string, AcpInstance>();\n\n private getHistoryPath(storageDir: string): string {\n return path.join(storageDir, 'history.json');\n }\n\n private storeEvent(storageDir: string, update: StreamPayload): void {\n // Only store SessionUpdate events and turn markers\n const isSessionUpdate = typeof update === 'object' && update !== null && 'sessionUpdate' in update;\n const isAmuxEvent = typeof update === 'object' && update !== null && 'amuxEvent' in update;\n const isTurnMarker = isAmuxEvent && ((update as any).amuxEvent === 'turn_start' || (update as any).amuxEvent === 'turn_end');\n\n if (!isSessionUpdate && !isTurnMarker) {\n return;\n }\n\n // Ensure directory exists\n if (!fsSync.existsSync(storageDir)) {\n fsSync.mkdirSync(storageDir, { recursive: true });\n }\n\n const historyPath = this.getHistoryPath(storageDir);\n let events: StreamPayload[] = [];\n\n try {\n if (fsSync.existsSync(historyPath)) {\n const data = fsSync.readFileSync(historyPath, 'utf-8');\n events = JSON.parse(data);\n }\n } catch {\n events = [];\n }\n\n events.push(update);\n fsSync.writeFileSync(historyPath, JSON.stringify(events));\n }\n\n async start(\n streamId: string,\n config: StreamConfig,\n cwd: string,\n backendState: unknown | null,\n emit: EmitFn,\n storageDir: string\n ): Promise<Stream> {\n // Extract existing ACP session ID from backend state if resuming\n const existingState = backendState as AcpBackendState | null;\n const existingAcpSessionId = existingState?.acpSessionId ?? null;\n\n // Kill existing instance if any\n if (this.instances.has(streamId)) {\n await this.stop(streamId);\n }\n\n const args = config.args ?? [];\n const env = config.env ?? {};\n\n debug('acp',` Spawning: ${config.command} ${args.join(' ')} in ${cwd}`);\n\n const proc = spawn({\n command: config.command,\n args,\n cwd,\n env,\n });\n\n // Log stderr for debugging startup issues\n proc.stderr.on('data', (data: Buffer) => {\n debug('acp', `[stderr] ${data.toString().trim()}`);\n });\n\n // Wrap emit to store events\n const storingEmit: EmitFn = (update) => {\n this.storeEvent(storageDir, update);\n emit(update);\n };\n\n const instance: AcpInstance = {\n process: proc,\n connection: null!,\n acpSessionId: '',\n pendingPermission: null,\n permissionCallbacks: new Map(),\n emit: storingEmit,\n terminals: new Map(),\n storageDir,\n };\n\n // Handle unexpected exit\n proc.wait().then(({ exitCode }) => {\n if (this.instances.has(streamId)) {\n emit({ amuxEvent: 'error', message: `Agent process exited with code ${exitCode}` });\n this.instances.delete(streamId);\n }\n });\n\n try {\n const input = Writable.toWeb(proc.stdin) as WritableStream<Uint8Array>;\n const output = Readable.toWeb(proc.stdout) as ReadableStream<Uint8Array>;\n const stream = ndJsonStream(input, output);\n\n const client = this.createClient(streamId, instance);\n instance.connection = new ClientSideConnection(() => client, stream);\n\n const initResult = await withTimeout(\n instance.connection.initialize({\n protocolVersion: 1,\n clientCapabilities: {\n fs: { readTextFile: true, writeTextFile: true },\n terminal: true,\n },\n }),\n INIT_TIMEOUT_MS,\n 'Agent initialization'\n );\n\n debug('acp',` Initialized agent: ${initResult.agentInfo?.name} v${initResult.agentInfo?.version}`);\n\n const canResume = initResult.agentCapabilities?.sessionCapabilities?.resume !== undefined;\n let acpSessionId: string;\n let sessionResult: any;\n\n if (existingAcpSessionId && canResume) {\n let resumeSucceeded = false;\n try {\n debug('acp',` Resuming ACP session ${existingAcpSessionId}...`);\n sessionResult = await withTimeout(\n (instance.connection as any).unstable_resumeSession({\n sessionId: existingAcpSessionId,\n cwd,\n mcpServers: [],\n }),\n INIT_TIMEOUT_MS,\n 'Session resume'\n );\n\n await new Promise(resolve => setTimeout(resolve, 100));\n acpSessionId = existingAcpSessionId;\n debug('acp',` ACP session resumed successfully`);\n resumeSucceeded = true;\n } catch (resumeErr) {\n debug('acp', ` Resume failed, creating new session: ${resumeErr}`);\n }\n\n if (!resumeSucceeded) {\n sessionResult = await withTimeout(\n instance.connection.newSession({ cwd, mcpServers: [] }),\n INIT_TIMEOUT_MS,\n 'New session creation'\n );\n acpSessionId = sessionResult.sessionId;\n debug('acp',` New ACP session created: ${acpSessionId}`);\n }\n } else {\n debug('acp',` Creating new ACP session in ${cwd}...`);\n sessionResult = await withTimeout(\n instance.connection.newSession({ cwd, mcpServers: [] }),\n INIT_TIMEOUT_MS,\n 'New session creation'\n );\n acpSessionId = sessionResult.sessionId!;\n debug('acp',` ACP session created: ${acpSessionId}`);\n }\n\n instance.acpSessionId = acpSessionId!;\n this.instances.set(streamId, instance);\n\n const models = sessionResult?.models?.availableModels;\n const modes = sessionResult?.modes?.availableModes;\n\n if (sessionResult?.modes) {\n emit({\n sessionUpdate: 'current_mode_update',\n currentModeId: sessionResult.modes.currentModeId,\n });\n }\n\n return {\n acpSessionId: acpSessionId!,\n models,\n modes,\n };\n } catch (err) {\n console.error(`[acp] Error starting agent for stream ${streamId}:`, err);\n await proc.kill();\n throw err;\n }\n }\n\n private createClient(_streamId: string, instance: AcpInstance): Client {\n return {\n async requestPermission(params: RequestPermissionRequest): Promise<RequestPermissionResponse> {\n const requestId = randomUUID();\n\n const permission = {\n requestId,\n toolCallId: params.toolCall.toolCallId,\n title: params.toolCall.title ?? 'Permission Required',\n options: params.options.map(o => ({\n optionId: o.optionId,\n name: o.name,\n kind: o.kind,\n })),\n };\n instance.pendingPermission = permission;\n instance.emit({ amuxEvent: 'permission_request', permission });\n\n return new Promise((resolve, reject) => {\n instance.permissionCallbacks.set(requestId, {\n resolve: (optionId) => {\n instance.pendingPermission = null;\n instance.emit({ amuxEvent: 'permission_cleared' });\n resolve({ outcome: { outcome: 'selected', optionId } });\n },\n reject,\n });\n });\n },\n\n async sessionUpdate(params: SessionNotification): Promise<void> {\n debug('acp', ` sessionUpdate received: ${JSON.stringify(params)}`);\n // Normalize the update before emitting (ACP normalization layer)\n const normalized = normalizeSessionUpdate(params.update) as StreamPayload;\n instance.emit(normalized);\n },\n\n async readTextFile(params: ReadTextFileRequest): Promise<ReadTextFileResponse> {\n const content = await fs.readFile(params.path, 'utf-8');\n return { content };\n },\n\n async writeTextFile(params: WriteTextFileRequest): Promise<WriteTextFileResponse> {\n await fs.writeFile(params.path, params.content);\n return {};\n },\n\n async createTerminal(params: CreateTerminalRequest): Promise<CreateTerminalResponse> {\n debug('acp', ` createTerminal request: ${JSON.stringify(params)}`);\n const terminalId = randomUUID();\n const outputByteLimit = params.outputByteLimit ?? 1024 * 1024; // Default 1MB\n\n const termProc = nodeSpawn(params.command, params.args ?? [], {\n cwd: params.cwd ?? undefined,\n env: params.env\n ? { ...process.env, ...Object.fromEntries(params.env.map(e => [e.name, e.value])) }\n : process.env,\n shell: true,\n stdio: ['ignore', 'pipe', 'pipe'],\n });\n\n const terminal: Terminal = {\n process: termProc,\n output: '',\n exitCode: null,\n signal: null,\n truncated: false,\n outputByteLimit,\n };\n\n const appendOutput = (data: Buffer) => {\n terminal.output += data.toString();\n // Truncate from beginning if over limit\n if (terminal.output.length > terminal.outputByteLimit) {\n terminal.output = terminal.output.slice(-terminal.outputByteLimit);\n terminal.truncated = true;\n }\n };\n\n termProc.stdout?.on('data', appendOutput);\n termProc.stderr?.on('data', appendOutput);\n\n termProc.on('exit', (code, signal) => {\n debug('acp',` Terminal ${terminalId} exited with code ${code}, signal ${signal}`);\n terminal.exitCode = code ?? null;\n terminal.signal = signal ?? null;\n });\n\n termProc.on('error', (err) => {\n console.error(`[acp] Terminal ${terminalId} error:`, err.message);\n terminal.output += `\\nError: ${err.message}`;\n terminal.exitCode = -1;\n });\n\n instance.terminals.set(terminalId, terminal);\n debug('acp',` Created terminal ${terminalId} for command: ${params.command}`);\n\n return { terminalId };\n },\n\n async terminalOutput(params: TerminalOutputRequest): Promise<TerminalOutputResponse> {\n debug('acp',` terminalOutput request for terminal ${params.terminalId}`);\n const terminal = instance.terminals.get(params.terminalId);\n if (!terminal) {\n throw new Error(`Terminal ${params.terminalId} not found`);\n }\n return {\n output: terminal.output,\n truncated: terminal.truncated,\n exitStatus: terminal.exitCode !== null || terminal.signal !== null ? {\n exitCode: terminal.exitCode,\n signal: terminal.signal,\n } : undefined,\n };\n },\n\n async waitForTerminalExit(params: WaitForTerminalExitRequest): Promise<WaitForTerminalExitResponse> {\n debug('acp',` waitForTerminalExit request for terminal ${params.terminalId}`);\n const terminal = instance.terminals.get(params.terminalId);\n if (!terminal) {\n throw new Error(`Terminal ${params.terminalId} not found`);\n }\n\n // If already exited, return immediately\n if (terminal.exitCode !== null || terminal.signal !== null) {\n return {\n exitCode: terminal.exitCode,\n signal: terminal.signal,\n };\n }\n\n // Wait for exit\n return new Promise((resolve) => {\n terminal.process.on('exit', (code, signal) => {\n resolve({\n exitCode: code ?? null,\n signal: signal ?? null,\n });\n });\n });\n },\n\n // Note: killTerminalCommand not in SDK Client interface yet, but we implement handlers\n // for completeness when the SDK adds support\n async killTerminal(params: KillTerminalCommandRequest): Promise<KillTerminalCommandResponse> {\n debug('acp',` killTerminal request for terminal ${params.terminalId}`);\n const terminal = instance.terminals.get(params.terminalId);\n if (!terminal) {\n throw new Error(`Terminal ${params.terminalId} not found`);\n }\n terminal.process.kill('SIGTERM');\n return {};\n },\n\n async releaseTerminal(params: ReleaseTerminalRequest): Promise<ReleaseTerminalResponse> {\n debug('acp',` releaseTerminal request for terminal ${params.terminalId}`);\n const terminal = instance.terminals.get(params.terminalId);\n if (terminal) {\n if (terminal.exitCode === null) {\n terminal.process.kill('SIGKILL');\n }\n instance.terminals.delete(params.terminalId);\n }\n return {};\n },\n };\n }\n\n async input(streamId: string, raw: string, cwd: string, _emit: EmitFn): Promise<void> {\n const instance = this.instances.get(streamId);\n if (!instance) throw new Error(`No ACP instance for stream ${streamId}`);\n\n // Store user message for replay\n this.storeEvent(instance.storageDir, {\n sessionUpdate: 'user_message_chunk',\n content: { type: 'text', text: raw },\n } as StreamPayload);\n\n // Parse @mentions into ContentBlocks\n const content = parseMessageToContentBlocks(raw, cwd);\n\n debug('acp',` Sending input to session ${instance.acpSessionId} with ${content.length} content block(s)...`);\n const result = await instance.connection.prompt({\n sessionId: instance.acpSessionId,\n prompt: content,\n });\n debug('acp',` Input complete, stopReason: ${result.stopReason}`);\n }\n\n async stop(streamId: string): Promise<void> {\n const instance = this.instances.get(streamId);\n if (!instance) return;\n\n // Reject pending permission callbacks\n for (const [, callback] of instance.permissionCallbacks) {\n callback.reject(new Error('Agent stopped'));\n }\n instance.permissionCallbacks.clear();\n instance.pendingPermission = null;\n\n // Remove from instances first to prevent exit handler re-entry\n this.instances.delete(streamId);\n\n // Kill the process tree\n await instance.process.kill();\n }\n\n async stopAll(): Promise<void> {\n const streamIds = [...this.instances.keys()];\n await Promise.all(streamIds.map((id) => this.stop(id)));\n }\n\n isRunning(streamId: string): boolean {\n return this.instances.has(streamId);\n }\n\n /** Get backend state for persistence (ACP session ID for resumption) */\n getState(streamId: string): AcpBackendState | undefined {\n const instance = this.instances.get(streamId);\n if (!instance) return undefined;\n return { acpSessionId: instance.acpSessionId };\n }\n\n /** Get stored events for replay on reconnect */\n getReplayData(streamId: string): StreamPayload[] | undefined {\n const instance = this.instances.get(streamId);\n if (!instance) return undefined;\n\n const historyPath = this.getHistoryPath(instance.storageDir);\n try {\n if (fsSync.existsSync(historyPath)) {\n const data = fsSync.readFileSync(historyPath, 'utf-8');\n return JSON.parse(data);\n }\n } catch {\n // Return empty if file is corrupted\n }\n return [];\n }\n\n /** Clear stored events for a stream */\n clearHistory(streamId: string): void {\n const instance = this.instances.get(streamId);\n if (!instance) return;\n\n const historyPath = this.getHistoryPath(instance.storageDir);\n try {\n if (fsSync.existsSync(historyPath)) {\n fsSync.unlinkSync(historyPath);\n }\n } catch {\n // Ignore errors\n }\n }\n\n respondToPermission(streamId: string, requestId: string, optionId: string): void {\n const instance = this.instances.get(streamId);\n const callback = instance?.permissionCallbacks.get(requestId);\n if (!callback) {\n throw new Error(`No pending permission request ${requestId}`);\n }\n callback.resolve(optionId);\n instance!.permissionCallbacks.delete(requestId);\n }\n\n getPendingPermission(streamId: string): PendingPermission | null {\n const instance = this.instances.get(streamId);\n return instance?.pendingPermission ?? null;\n }\n\n async cancel(streamId: string): Promise<void> {\n const instance = this.instances.get(streamId);\n if (!instance) return;\n\n await instance.connection.cancel({ sessionId: instance.acpSessionId });\n }\n\n async setMode(streamId: string, modeId: string): Promise<void> {\n const instance = this.instances.get(streamId);\n if (!instance) throw new Error(`No ACP instance for stream ${streamId}`);\n\n await instance.connection.setSessionMode({\n sessionId: instance.acpSessionId,\n modeId,\n });\n }\n\n async setModel(streamId: string, modelId: string): Promise<void> {\n const instance = this.instances.get(streamId);\n if (!instance) throw new Error(`No ACP instance for stream ${streamId}`);\n\n await (instance.connection as any).unstable_setSessionModel({\n sessionId: instance.acpSessionId,\n modelId,\n });\n }\n}\n","/**\n * Managed process wrapper with automatic tree cleanup.\n * Uses execa for process spawning and tree-kill for cleanup.\n */\n\nimport { execa } from 'execa';\nimport treeKill from 'tree-kill';\nimport type { Writable, Readable } from 'stream';\n\nexport interface ManagedProcess {\n pid: number;\n stdin: Writable;\n stdout: Readable;\n stderr: Readable;\n kill: (signal?: string) => Promise<void>;\n wait: () => Promise<{ exitCode: number | null }>;\n}\n\nexport interface SpawnOptions {\n command: string;\n args?: string[];\n cwd?: string;\n env?: Record<string, string>;\n timeoutMs?: number;\n}\n\n/**\n * Spawns a managed process with automatic tree cleanup.\n *\n * - Cross-platform process tree killing via tree-kill\n * - Automatic cleanup on parent exit\n * - Promise-based wait/kill\n */\nexport function spawn(options: SpawnOptions): ManagedProcess {\n const { command, args = [], cwd, env, timeoutMs } = options;\n\n const subprocess = execa(command, args, {\n cwd,\n env: { ...process.env, ...env },\n stdin: 'pipe',\n stdout: 'pipe',\n stderr: 'pipe',\n timeout: timeoutMs,\n cleanup: true, // Kill on parent exit\n windowsHide: true, // Hide console window on Windows\n });\n\n const pid = subprocess.pid;\n if (!pid) {\n throw new Error(`Failed to spawn process: ${command}`);\n }\n\n return {\n pid,\n stdin: subprocess.stdin!,\n stdout: subprocess.stdout!,\n stderr: subprocess.stderr!,\n\n kill: (signal = 'SIGTERM') => killTree(pid, signal),\n\n wait: async () => {\n try {\n const result = await subprocess;\n return { exitCode: result.exitCode };\n } catch (err: any) {\n return { exitCode: err.exitCode ?? 1 };\n }\n },\n };\n}\n\nfunction killTree(pid: number, signal: string): Promise<void> {\n return new Promise((resolve) => {\n treeKill(pid, signal, (err?: Error) => {\n if (err && !err.message.includes('No such process')) {\n console.error(`[process] kill error pid=${pid}:`, err.message);\n }\n resolve();\n });\n });\n}\n","import { randomUUID } from 'crypto';\nimport type { StreamDriver, StreamConfig, Stream, EmitFn } from './types.js';\nimport { debug } from '../../lib/logger.js';\n\nfunction delay(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n}\n\nexport class MockDriver implements StreamDriver {\n readonly type = 'mock';\n readonly streamType = 'acp' as const;\n private running = new Set<string>();\n\n async start(\n streamId: string,\n _config: StreamConfig,\n _cwd: string,\n _backendState: unknown | null,\n emit: EmitFn,\n _storageDir: string\n ): Promise<Stream> {\n debug('mock',` Starting mock agent for stream ${streamId}`);\n\n emit({\n sessionUpdate: 'current_mode_update',\n currentModeId: 'mock',\n });\n\n debug('mock',` Mock agent ready for stream ${streamId}`);\n this.running.add(streamId);\n\n return {\n acpSessionId: randomUUID(),\n models: [{ modelId: 'mock-model', name: 'Mock Model' }],\n modes: [{ id: 'mock', name: 'Mock Mode' }],\n };\n }\n\n async input(streamId: string, raw: string, _cwd: string, emit: EmitFn): Promise<void> {\n debug('mock',` Mock input for stream ${streamId}: \"${raw.slice(0, 50)}...\"`);\n\n const words = [\n 'This', 'is', 'a', 'mock', 'response', 'from', 'the', 'mock', 'agent.',\n 'It', 'simulates', 'streaming', 'text', 'chunks', 'for', 'performance', 'testing.',\n 'The', 'response', 'arrives', 'in', 'small', 'pieces', 'to', 'test', 'UI', 'rendering.',\n ];\n\n for (let i = 0; i < words.length; i += 3) {\n const chunk = words.slice(i, i + 3).join(' ') + ' ';\n emit({\n sessionUpdate: 'agent_message_chunk',\n content: { type: 'text', text: chunk },\n });\n await delay(50);\n }\n }\n\n async stop(streamId: string): Promise<void> {\n debug('mock',` Stopping mock agent for stream ${streamId}`);\n this.running.delete(streamId);\n }\n\n async stopAll(): Promise<void> {\n const streamIds = [...this.running];\n await Promise.all(streamIds.map((id) => this.stop(id)));\n }\n\n isRunning(streamId: string): boolean {\n return this.running.has(streamId);\n }\n}\n","import type { IPty } from 'node-pty';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport type { StreamDriver, StreamConfig, Stream, EmitFn } from './types.js';\nimport { debug, warn } from '../../lib/logger.js';\n\n// Dynamic import for node-pty (native module)\nlet pty: typeof import('node-pty') | null = null;\n\nasync function getPty() {\n if (!pty) {\n pty = await import('node-pty');\n }\n return pty;\n}\n\nconst MAX_SCROLLBACK = 100_000; // ~100KB of terminal output\nconst SAVE_DEBOUNCE_MS = 1000; // Debounce scrollback saves\n\ninterface ShellInstance {\n pty: IPty;\n scrollback: string;\n cwd: string;\n emit: EmitFn;\n storageDir: string;\n saveTimeout: ReturnType<typeof setTimeout> | null;\n}\n\n/**\n * PtyDriver - Interactive terminal driver using node-pty.\n *\n * Unlike conversational agents (AcpDriver), this provides a raw PTY\n * for interactive shell access. Key differences:\n * - input() writes text to terminal (also exposes terminalWrite() for raw access)\n * - Emits terminal_output events instead of message chunks\n * - Maintains scrollback buffer for reconnection replay\n */\nexport class PtyDriver implements StreamDriver {\n readonly type = 'pty';\n readonly streamType = 'pty' as const;\n readonly isInteractive = true;\n\n private instances = new Map<string, ShellInstance>();\n\n private getScrollbackPath(storageDir: string): string {\n return path.join(storageDir, 'scrollback.txt');\n }\n\n private saveScrollback(instance: ShellInstance): void {\n // Ensure directory exists\n if (!fs.existsSync(instance.storageDir)) {\n fs.mkdirSync(instance.storageDir, { recursive: true });\n }\n fs.writeFileSync(this.getScrollbackPath(instance.storageDir), instance.scrollback);\n }\n\n private loadScrollback(storageDir: string): string {\n const scrollbackPath = this.getScrollbackPath(storageDir);\n try {\n if (fs.existsSync(scrollbackPath)) {\n return fs.readFileSync(scrollbackPath, 'utf-8');\n }\n } catch {\n // Ignore read errors\n }\n return '';\n }\n\n private debouncedSave(instance: ShellInstance): void {\n if (instance.saveTimeout) {\n clearTimeout(instance.saveTimeout);\n }\n instance.saveTimeout = setTimeout(() => {\n this.saveScrollback(instance);\n instance.saveTimeout = null;\n }, SAVE_DEBOUNCE_MS);\n }\n\n async start(\n streamId: string,\n _config: StreamConfig,\n cwd: string,\n _backendState: unknown | null,\n emit: EmitFn,\n storageDir: string\n ): Promise<Stream> {\n // Check if already running (reconnect case)\n const existing = this.instances.get(streamId);\n if (existing) {\n debug('shell', `Stream ${streamId} already running, reusing`);\n // Update emit function for new subscriber\n existing.emit = emit;\n return {};\n }\n\n // Load persisted scrollback (for after server restart)\n const restoredScrollback = this.loadScrollback(storageDir);\n if (restoredScrollback) {\n debug('shell', `Restored ${restoredScrollback.length} bytes of scrollback for ${streamId}`);\n }\n\n const nodePty = await getPty();\n const shell = process.env.SHELL || '/bin/bash';\n\n debug('shell', `Spawning ${shell} in ${cwd}`);\n\n let p: IPty;\n try {\n p = nodePty.spawn(shell, [], {\n name: 'xterm-256color',\n cols: 80,\n rows: 24,\n cwd,\n env: process.env as Record<string, string>,\n });\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n\n if (message.includes('posix_spawnp failed') && process.platform === 'darwin') {\n throw new Error(\n `Failed to spawn shell on macOS: ${message}. ` +\n `This may be caused by macOS quarantine. Try: ` +\n `1) Install globally: npm install -g @bytespell/shella && shella, or ` +\n `2) Clear quarantine: xattr -dr com.apple.quarantine ~/.npm/_npx`\n );\n }\n throw error;\n }\n\n const instance: ShellInstance = {\n pty: p,\n scrollback: restoredScrollback,\n cwd,\n emit,\n storageDir,\n saveTimeout: null,\n };\n\n p.onData((data: string) => {\n // Accumulate scrollback\n instance.scrollback += data;\n if (instance.scrollback.length > MAX_SCROLLBACK) {\n instance.scrollback = instance.scrollback.slice(-MAX_SCROLLBACK);\n }\n\n // Persist scrollback (debounced)\n this.debouncedSave(instance);\n\n // Emit for live subscribers\n instance.emit({ amuxEvent: 'terminal_output', data });\n });\n\n p.onExit(({ exitCode, signal }) => {\n debug('shell', `PTY exited: code=${exitCode}, signal=${signal}`);\n // Save scrollback immediately on exit\n if (instance.saveTimeout) {\n clearTimeout(instance.saveTimeout);\n }\n this.saveScrollback(instance);\n instance.emit({\n amuxEvent: 'terminal_exit',\n exitCode: exitCode ?? null,\n signal: signal !== undefined ? String(signal) : null,\n });\n this.instances.delete(streamId);\n });\n\n this.instances.set(streamId, instance);\n debug('shell', `Stream ${streamId} started`);\n\n return {};\n }\n\n /**\n * Get accumulated scrollback for replay on reconnect.\n */\n getScrollback(streamId: string): string | undefined {\n return this.instances.get(streamId)?.scrollback;\n }\n\n /**\n * Get replay data (scrollback) for reconnecting clients.\n */\n getReplayData(streamId: string): string | undefined {\n return this.getScrollback(streamId);\n }\n\n /**\n * Write raw input to terminal (keystrokes from client).\n */\n terminalWrite(streamId: string, data: string): void {\n const instance = this.instances.get(streamId);\n if (!instance) {\n warn('shell', `terminalWrite: stream ${streamId} not found`);\n return;\n }\n instance.pty.write(data);\n }\n\n /**\n * Resize terminal dimensions.\n */\n terminalResize(streamId: string, cols: number, rows: number): void {\n const instance = this.instances.get(streamId);\n if (!instance) {\n warn('shell', `terminalResize: stream ${streamId} not found`);\n return;\n }\n instance.pty.resize(cols, rows);\n }\n\n /**\n * Handle user input - writes raw text to terminal.\n */\n async input(streamId: string, raw: string, _cwd: string, _emit: EmitFn): Promise<void> {\n if (raw) {\n this.terminalWrite(streamId, raw);\n }\n }\n\n async stop(streamId: string): Promise<void> {\n const instance = this.instances.get(streamId);\n if (!instance) return;\n\n debug('shell', `Stopping stream ${streamId}`);\n\n // Cancel pending save and save immediately\n if (instance.saveTimeout) {\n clearTimeout(instance.saveTimeout);\n }\n this.saveScrollback(instance);\n\n instance.pty.kill();\n this.instances.delete(streamId);\n }\n\n async stopAll(): Promise<void> {\n debug('shell', `Stopping all streams (${this.instances.size})`);\n for (const streamId of this.instances.keys()) {\n await this.stop(streamId);\n }\n }\n\n isRunning(streamId: string): boolean {\n return this.instances.has(streamId);\n }\n}\n"],"mappings":"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","names":["path","randomUUID","randomUUID","fs","path"]}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Simple logger with verbose mode toggle.
3
+ * In production, debug logs are suppressed unless verbose mode is enabled.
4
+ */
5
+ declare function setVerbose(v: boolean): void;
6
+ declare function isVerbose(): boolean;
7
+ /**
8
+ * Log a debug message. Only shown when verbose mode is enabled.
9
+ */
10
+ declare function debug(tag: string, message: string): void;
11
+ /**
12
+ * Log an info message. Always shown.
13
+ */
14
+ declare function info(tag: string, message: string): void;
15
+ /**
16
+ * Log a warning. Always shown.
17
+ */
18
+ declare function warn(tag: string, message: string): void;
19
+ /**
20
+ * Log an error. Always shown.
21
+ */
22
+ declare function error(tag: string, message: string): void;
23
+
24
+ export { debug, error, info, isVerbose, setVerbose, warn };
@@ -5,8 +5,7 @@ import {
5
5
  isVerbose,
6
6
  setVerbose,
7
7
  warn
8
- } from "../../chunk-5IPYOXBE.js";
9
- import "../../chunk-PZ5AY32C.js";
8
+ } from "../chunk-5IPYOXBE.js";
10
9
  export {
11
10
  debug,
12
11
  error,
@@ -0,0 +1,14 @@
1
+ import { ContentBlock } from '@agentclientprotocol/sdk';
2
+
3
+ /**
4
+ * Parse message text with @mentions into ContentBlock array.
5
+ * @mentions become resource_link blocks, other text becomes text blocks.
6
+ *
7
+ * Examples:
8
+ * - "hello world" → [{ type: 'text', text: 'hello world' }]
9
+ * - "@src/foo.ts" → [{ type: 'resource_link', uri: 'file://...', name: 'src/foo.ts' }]
10
+ * - "check @src/foo.ts for bugs" → text + resource_link + text
11
+ */
12
+ declare function parseMessageToContentBlocks(message: string, workingDir: string): ContentBlock[];
13
+
14
+ export { parseMessageToContentBlocks };
@@ -0,0 +1,7 @@
1
+ import {
2
+ parseMessageToContentBlocks
3
+ } from "../chunk-C73RKCTS.js";
4
+ export {
5
+ parseMessageToContentBlocks
6
+ };
7
+ //# sourceMappingURL=mentions.js.map
@@ -0,0 +1,88 @@
1
+ import { c as StreamDriver, e as StreamConfig, f as EmitFn, d as Stream, b as StreamPayload, P as PendingPermission } from '../../types-DoG5bt6C.js';
2
+ import '@agentclientprotocol/sdk';
3
+
4
+ /** ACP backend state for persistence */
5
+ interface AcpBackendState {
6
+ acpSessionId: string;
7
+ }
8
+ declare class AcpDriver implements StreamDriver {
9
+ readonly type = "acp";
10
+ readonly streamType: "acp";
11
+ private instances;
12
+ private getHistoryPath;
13
+ private storeEvent;
14
+ start(streamId: string, config: StreamConfig, cwd: string, backendState: unknown | null, emit: EmitFn, storageDir: string): Promise<Stream>;
15
+ private createClient;
16
+ input(streamId: string, raw: string, cwd: string, _emit: EmitFn): Promise<void>;
17
+ stop(streamId: string): Promise<void>;
18
+ stopAll(): Promise<void>;
19
+ isRunning(streamId: string): boolean;
20
+ /** Get backend state for persistence (ACP session ID for resumption) */
21
+ getState(streamId: string): AcpBackendState | undefined;
22
+ /** Get stored events for replay on reconnect */
23
+ getReplayData(streamId: string): StreamPayload[] | undefined;
24
+ /** Clear stored events for a stream */
25
+ clearHistory(streamId: string): void;
26
+ respondToPermission(streamId: string, requestId: string, optionId: string): void;
27
+ getPendingPermission(streamId: string): PendingPermission | null;
28
+ cancel(streamId: string): Promise<void>;
29
+ setMode(streamId: string, modeId: string): Promise<void>;
30
+ setModel(streamId: string, modelId: string): Promise<void>;
31
+ }
32
+
33
+ declare class MockDriver implements StreamDriver {
34
+ readonly type = "mock";
35
+ readonly streamType: "acp";
36
+ private running;
37
+ start(streamId: string, _config: StreamConfig, _cwd: string, _backendState: unknown | null, emit: EmitFn, _storageDir: string): Promise<Stream>;
38
+ input(streamId: string, raw: string, _cwd: string, emit: EmitFn): Promise<void>;
39
+ stop(streamId: string): Promise<void>;
40
+ stopAll(): Promise<void>;
41
+ isRunning(streamId: string): boolean;
42
+ }
43
+
44
+ /**
45
+ * PtyDriver - Interactive terminal driver using node-pty.
46
+ *
47
+ * Unlike conversational agents (AcpDriver), this provides a raw PTY
48
+ * for interactive shell access. Key differences:
49
+ * - input() writes text to terminal (also exposes terminalWrite() for raw access)
50
+ * - Emits terminal_output events instead of message chunks
51
+ * - Maintains scrollback buffer for reconnection replay
52
+ */
53
+ declare class PtyDriver implements StreamDriver {
54
+ readonly type = "pty";
55
+ readonly streamType: "pty";
56
+ readonly isInteractive = true;
57
+ private instances;
58
+ private getScrollbackPath;
59
+ private saveScrollback;
60
+ private loadScrollback;
61
+ private debouncedSave;
62
+ start(streamId: string, _config: StreamConfig, cwd: string, _backendState: unknown | null, emit: EmitFn, storageDir: string): Promise<Stream>;
63
+ /**
64
+ * Get accumulated scrollback for replay on reconnect.
65
+ */
66
+ getScrollback(streamId: string): string | undefined;
67
+ /**
68
+ * Get replay data (scrollback) for reconnecting clients.
69
+ */
70
+ getReplayData(streamId: string): string | undefined;
71
+ /**
72
+ * Write raw input to terminal (keystrokes from client).
73
+ */
74
+ terminalWrite(streamId: string, data: string): void;
75
+ /**
76
+ * Resize terminal dimensions.
77
+ */
78
+ terminalResize(streamId: string, cols: number, rows: number): void;
79
+ /**
80
+ * Handle user input - writes raw text to terminal.
81
+ */
82
+ input(streamId: string, raw: string, _cwd: string, _emit: EmitFn): Promise<void>;
83
+ stop(streamId: string): Promise<void>;
84
+ stopAll(): Promise<void>;
85
+ isRunning(streamId: string): boolean;
86
+ }
87
+
88
+ export { AcpDriver, EmitFn, MockDriver, PtyDriver, Stream, StreamConfig, StreamDriver };
@@ -0,0 +1,13 @@
1
+ import {
2
+ AcpDriver,
3
+ MockDriver,
4
+ PtyDriver
5
+ } from "../../chunk-HJCRMFTD.js";
6
+ import "../../chunk-5IPYOXBE.js";
7
+ import "../../chunk-C73RKCTS.js";
8
+ export {
9
+ AcpDriver,
10
+ MockDriver,
11
+ PtyDriver
12
+ };
13
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,49 @@
1
+ import { S as StartStreamArgs, a as StreamHandle, b as StreamPayload, c as StreamDriver, d as Stream, E as Emit, P as PendingPermission } from '../types-DoG5bt6C.js';
2
+ import { EventEmitter } from 'events';
3
+ import '@agentclientprotocol/sdk';
4
+
5
+ interface StreamEntry {
6
+ driver: StreamDriver;
7
+ stream: Stream;
8
+ emit: Emit;
9
+ cwd: string;
10
+ storageDir: string;
11
+ status: 'starting' | 'ready' | 'dead';
12
+ }
13
+ declare class MuxManager extends EventEmitter {
14
+ private drivers;
15
+ private streamEntries;
16
+ constructor();
17
+ private getDriver;
18
+ private emitUpdate;
19
+ /**
20
+ * Start a stream with the given configuration.
21
+ * The caller provides config, cwd, storageDir, and an emit callback for receiving events.
22
+ */
23
+ startStream(args: StartStreamArgs): Promise<StreamHandle>;
24
+ input(streamId: string, message: string): Promise<void>;
25
+ setMode(streamId: string, modeId: string): Promise<void>;
26
+ setModel(streamId: string, modelId: string): Promise<void>;
27
+ cancel(streamId: string): Promise<void>;
28
+ terminalWrite(streamId: string, data: string): void;
29
+ terminalResize(streamId: string, cols: number, rows: number): void;
30
+ getTerminalScrollback(streamId: string): string | undefined;
31
+ /**
32
+ * Get replay data from the driver (events for ACP, scrollback for PTY).
33
+ */
34
+ getReplayData(streamId: string): StreamPayload[] | string | undefined;
35
+ isTerminalStream(streamId: string): boolean;
36
+ respondPermission(streamId: string, requestId: string, optionId: string): void;
37
+ /**
38
+ * Get the driver state for a stream (for persistence before stopping).
39
+ */
40
+ getDriverState(streamId: string): unknown | undefined;
41
+ stopForStream(streamId: string): Promise<void>;
42
+ stopAll(): Promise<void>;
43
+ getForStream(streamId: string): StreamEntry | undefined;
44
+ getPendingPermission(streamId: string): PendingPermission | null;
45
+ registerDriver(driver: StreamDriver): void;
46
+ }
47
+ declare const muxManager: MuxManager;
48
+
49
+ export { MuxManager, muxManager };
@@ -0,0 +1,237 @@
1
+ import {
2
+ AcpDriver,
3
+ MockDriver,
4
+ PtyDriver
5
+ } from "../chunk-HJCRMFTD.js";
6
+ import {
7
+ debug
8
+ } from "../chunk-5IPYOXBE.js";
9
+ import "../chunk-C73RKCTS.js";
10
+
11
+ // src/streams/manager.ts
12
+ import { EventEmitter } from "events";
13
+ var MuxManager = class extends EventEmitter {
14
+ drivers;
15
+ streamEntries = /* @__PURE__ */ new Map();
16
+ constructor() {
17
+ super();
18
+ this.drivers = [
19
+ new AcpDriver(),
20
+ new PtyDriver(),
21
+ new MockDriver()
22
+ ];
23
+ }
24
+ getDriver(type) {
25
+ const driver = this.drivers.find((d) => d.type === type);
26
+ if (!driver) {
27
+ throw new Error(`No driver registered for type: ${type}`);
28
+ }
29
+ return driver;
30
+ }
31
+ emitUpdate(streamId, payload) {
32
+ const entry = this.streamEntries.get(streamId);
33
+ if (!entry) return;
34
+ const event = {
35
+ ...payload,
36
+ streamId,
37
+ timestamp: Date.now()
38
+ };
39
+ entry.emit(event);
40
+ this.emit("update", event);
41
+ }
42
+ /**
43
+ * Start a stream with the given configuration.
44
+ * The caller provides config, cwd, storageDir, and an emit callback for receiving events.
45
+ */
46
+ async startStream(args) {
47
+ const { streamId, driverType, config, cwd, restoredState, emit, storageDir } = args;
48
+ const existing = this.streamEntries.get(streamId);
49
+ if (existing?.status === "ready") {
50
+ return {
51
+ streamId,
52
+ stream: existing.stream,
53
+ driverType: existing.driver.type
54
+ };
55
+ }
56
+ if (existing?.status === "starting") {
57
+ return new Promise((resolve, reject) => {
58
+ const checkReady = () => {
59
+ const entry = this.streamEntries.get(streamId);
60
+ if (entry?.status === "ready") {
61
+ resolve({
62
+ streamId,
63
+ stream: entry.stream,
64
+ driverType: entry.driver.type
65
+ });
66
+ } else if (entry?.status === "dead") {
67
+ reject(new Error("Stream failed to start"));
68
+ } else {
69
+ setTimeout(checkReady, 100);
70
+ }
71
+ };
72
+ checkReady();
73
+ });
74
+ }
75
+ const driver = this.getDriver(driverType);
76
+ const driverEmit = (payload) => this.emitUpdate(streamId, payload);
77
+ this.streamEntries.set(streamId, {
78
+ driver,
79
+ stream: {},
80
+ emit,
81
+ cwd,
82
+ storageDir,
83
+ status: "starting"
84
+ });
85
+ try {
86
+ const stream = await driver.start(streamId, config, cwd, restoredState ?? null, driverEmit, storageDir);
87
+ this.streamEntries.set(streamId, {
88
+ driver,
89
+ stream,
90
+ emit,
91
+ cwd,
92
+ storageDir,
93
+ status: "ready"
94
+ });
95
+ debug("streams", `Stream ready for ${streamId}`);
96
+ return {
97
+ streamId,
98
+ stream,
99
+ driverType: driver.type
100
+ };
101
+ } catch (err) {
102
+ this.streamEntries.set(streamId, {
103
+ driver,
104
+ stream: {},
105
+ emit,
106
+ cwd,
107
+ storageDir,
108
+ status: "dead"
109
+ });
110
+ throw err;
111
+ }
112
+ }
113
+ async input(streamId, message) {
114
+ debug("streams", `input() called for stream ${streamId}: "${message.slice(0, 50)}..."`);
115
+ const entry = this.streamEntries.get(streamId);
116
+ if (!entry || entry.status !== "ready") {
117
+ throw new Error(`Stream not ready for ${streamId}`);
118
+ }
119
+ this.emitUpdate(streamId, { amuxEvent: "turn_start" });
120
+ const driverEmit = (payload) => this.emitUpdate(streamId, payload);
121
+ try {
122
+ await entry.driver.input(streamId, message, entry.cwd, driverEmit);
123
+ } finally {
124
+ this.emitUpdate(streamId, { amuxEvent: "turn_end" });
125
+ }
126
+ }
127
+ async setMode(streamId, modeId) {
128
+ const entry = this.streamEntries.get(streamId);
129
+ if (!entry || entry.status !== "ready") {
130
+ throw new Error(`Stream not ready for ${streamId}`);
131
+ }
132
+ if (!entry.driver.setMode) {
133
+ throw new Error(`Driver ${entry.driver.type} does not support setMode`);
134
+ }
135
+ await entry.driver.setMode(streamId, modeId);
136
+ }
137
+ async setModel(streamId, modelId) {
138
+ const entry = this.streamEntries.get(streamId);
139
+ if (!entry || entry.status !== "ready") {
140
+ throw new Error(`Stream not ready for ${streamId}`);
141
+ }
142
+ if (!entry.driver.setModel) {
143
+ throw new Error(`Driver ${entry.driver.type} does not support setModel`);
144
+ }
145
+ await entry.driver.setModel(streamId, modelId);
146
+ }
147
+ async cancel(streamId) {
148
+ const entry = this.streamEntries.get(streamId);
149
+ if (!entry?.driver.cancel) return;
150
+ await entry.driver.cancel(streamId);
151
+ }
152
+ // Terminal-specific methods (for PtyDriver)
153
+ terminalWrite(streamId, data) {
154
+ const entry = this.streamEntries.get(streamId);
155
+ if (!entry) {
156
+ throw new Error(`No stream running for ${streamId}`);
157
+ }
158
+ if (!entry.driver.terminalWrite) {
159
+ throw new Error(`Driver ${entry.driver.type} does not support terminal input`);
160
+ }
161
+ entry.driver.terminalWrite(streamId, data);
162
+ }
163
+ terminalResize(streamId, cols, rows) {
164
+ const entry = this.streamEntries.get(streamId);
165
+ if (!entry) {
166
+ throw new Error(`No stream running for ${streamId}`);
167
+ }
168
+ if (!entry.driver.terminalResize) {
169
+ throw new Error(`Driver ${entry.driver.type} does not support terminal resize`);
170
+ }
171
+ entry.driver.terminalResize(streamId, cols, rows);
172
+ }
173
+ getTerminalScrollback(streamId) {
174
+ const entry = this.streamEntries.get(streamId);
175
+ if (!entry?.driver.getScrollback) return void 0;
176
+ return entry.driver.getScrollback(streamId);
177
+ }
178
+ /**
179
+ * Get replay data from the driver (events for ACP, scrollback for PTY).
180
+ */
181
+ getReplayData(streamId) {
182
+ const entry = this.streamEntries.get(streamId);
183
+ if (!entry?.driver.getReplayData) return void 0;
184
+ return entry.driver.getReplayData(streamId);
185
+ }
186
+ isTerminalStream(streamId) {
187
+ const entry = this.streamEntries.get(streamId);
188
+ return entry?.driver.isInteractive ?? false;
189
+ }
190
+ respondPermission(streamId, requestId, optionId) {
191
+ const entry = this.streamEntries.get(streamId);
192
+ if (!entry) {
193
+ console.warn(`[MuxManager] No stream running for ${streamId}, ignoring permission response`);
194
+ return;
195
+ }
196
+ if (!entry.driver.respondToPermission) {
197
+ throw new Error(`Driver ${entry.driver.type} does not support permissions`);
198
+ }
199
+ entry.driver.respondToPermission(streamId, requestId, optionId);
200
+ }
201
+ /**
202
+ * Get the driver state for a stream (for persistence before stopping).
203
+ */
204
+ getDriverState(streamId) {
205
+ const entry = this.streamEntries.get(streamId);
206
+ if (!entry?.driver.getState) return void 0;
207
+ return entry.driver.getState(streamId);
208
+ }
209
+ async stopForStream(streamId) {
210
+ const entry = this.streamEntries.get(streamId);
211
+ if (entry) {
212
+ await entry.driver.stop(streamId);
213
+ }
214
+ this.streamEntries.delete(streamId);
215
+ }
216
+ async stopAll() {
217
+ const streamIds = Array.from(this.streamEntries.keys());
218
+ await Promise.all(streamIds.map((id) => this.stopForStream(id)));
219
+ }
220
+ getForStream(streamId) {
221
+ return this.streamEntries.get(streamId);
222
+ }
223
+ getPendingPermission(streamId) {
224
+ const entry = this.streamEntries.get(streamId);
225
+ if (!entry?.driver.getPendingPermission) return null;
226
+ return entry.driver.getPendingPermission(streamId);
227
+ }
228
+ registerDriver(driver) {
229
+ this.drivers.unshift(driver);
230
+ }
231
+ };
232
+ var muxManager = new MuxManager();
233
+ export {
234
+ MuxManager,
235
+ muxManager
236
+ };
237
+ //# sourceMappingURL=manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/streams/manager.ts"],"sourcesContent":["import { EventEmitter } from 'events';\nimport type { StreamPayload, StreamEvent, Emit, StreamHandle, StartStreamArgs } from '../types.js';\nimport { AcpDriver, MockDriver, PtyDriver } from './backends/index.js';\nimport type { StreamDriver, Stream } from './backends/index.js';\nimport { debug } from '../lib/logger.js';\n\ninterface StreamEntry {\n driver: StreamDriver;\n stream: Stream;\n emit: Emit;\n cwd: string;\n storageDir: string;\n status: 'starting' | 'ready' | 'dead';\n}\n\nclass MuxManager extends EventEmitter {\n private drivers: StreamDriver[];\n private streamEntries = new Map<string, StreamEntry>();\n\n constructor() {\n super();\n this.drivers = [\n new AcpDriver(),\n new PtyDriver(),\n new MockDriver(),\n ];\n }\n\n private getDriver(type: string): StreamDriver {\n const driver = this.drivers.find(d => d.type === type);\n if (!driver) {\n throw new Error(`No driver registered for type: ${type}`);\n }\n return driver;\n }\n\n private emitUpdate(streamId: string, payload: StreamPayload): void {\n const entry = this.streamEntries.get(streamId);\n if (!entry) return;\n\n const event: StreamEvent = {\n ...payload,\n streamId,\n timestamp: Date.now(),\n };\n\n // Call the stream's emit callback (for the consumer to persist/handle)\n entry.emit(event);\n\n // Also emit on EventEmitter for internal subscribers\n this.emit('update', event);\n }\n\n /**\n * Start a stream with the given configuration.\n * The caller provides config, cwd, storageDir, and an emit callback for receiving events.\n */\n async startStream(args: StartStreamArgs): Promise<StreamHandle> {\n const { streamId, driverType, config, cwd, restoredState, emit, storageDir } = args;\n\n const existing = this.streamEntries.get(streamId);\n\n if (existing?.status === 'ready') {\n // Already ready - return the existing handle\n return {\n streamId,\n stream: existing.stream,\n driverType: existing.driver.type,\n };\n }\n\n if (existing?.status === 'starting') {\n // Wait for the stream to be ready\n return new Promise((resolve, reject) => {\n const checkReady = () => {\n const entry = this.streamEntries.get(streamId);\n if (entry?.status === 'ready') {\n resolve({\n streamId,\n stream: entry.stream,\n driverType: entry.driver.type,\n });\n } else if (entry?.status === 'dead') {\n reject(new Error('Stream failed to start'));\n } else {\n setTimeout(checkReady, 100);\n }\n };\n checkReady();\n });\n }\n\n const driver = this.getDriver(driverType);\n const driverEmit = (payload: StreamPayload) => this.emitUpdate(streamId, payload);\n\n this.streamEntries.set(streamId, {\n driver,\n stream: {},\n emit,\n cwd,\n storageDir,\n status: 'starting',\n });\n\n try {\n const stream = await driver.start(streamId, config, cwd, restoredState ?? null, driverEmit, storageDir);\n\n this.streamEntries.set(streamId, {\n driver,\n stream,\n emit,\n cwd,\n storageDir,\n status: 'ready',\n });\n\n debug('streams', `Stream ready for ${streamId}`);\n\n return {\n streamId,\n stream,\n driverType: driver.type,\n };\n } catch (err) {\n this.streamEntries.set(streamId, {\n driver,\n stream: {},\n emit,\n cwd,\n storageDir,\n status: 'dead',\n });\n throw err;\n }\n }\n\n async input(streamId: string, message: string): Promise<void> {\n debug('streams', `input() called for stream ${streamId}: \"${message.slice(0, 50)}...\"`);\n\n const entry = this.streamEntries.get(streamId);\n if (!entry || entry.status !== 'ready') {\n throw new Error(`Stream not ready for ${streamId}`);\n }\n\n // Signal turn start for streaming state\n this.emitUpdate(streamId, { amuxEvent: 'turn_start' });\n\n const driverEmit = (payload: StreamPayload) => this.emitUpdate(streamId, payload);\n\n try {\n await entry.driver.input(streamId, message, entry.cwd, driverEmit);\n } finally {\n this.emitUpdate(streamId, { amuxEvent: 'turn_end' });\n }\n }\n\n async setMode(streamId: string, modeId: string): Promise<void> {\n const entry = this.streamEntries.get(streamId);\n if (!entry || entry.status !== 'ready') {\n throw new Error(`Stream not ready for ${streamId}`);\n }\n if (!entry.driver.setMode) {\n throw new Error(`Driver ${entry.driver.type} does not support setMode`);\n }\n await entry.driver.setMode(streamId, modeId);\n }\n\n async setModel(streamId: string, modelId: string): Promise<void> {\n const entry = this.streamEntries.get(streamId);\n if (!entry || entry.status !== 'ready') {\n throw new Error(`Stream not ready for ${streamId}`);\n }\n if (!entry.driver.setModel) {\n throw new Error(`Driver ${entry.driver.type} does not support setModel`);\n }\n await entry.driver.setModel(streamId, modelId);\n }\n\n async cancel(streamId: string): Promise<void> {\n const entry = this.streamEntries.get(streamId);\n if (!entry?.driver.cancel) return;\n await entry.driver.cancel(streamId);\n }\n\n // Terminal-specific methods (for PtyDriver)\n\n terminalWrite(streamId: string, data: string): void {\n const entry = this.streamEntries.get(streamId);\n if (!entry) {\n throw new Error(`No stream running for ${streamId}`);\n }\n if (!entry.driver.terminalWrite) {\n throw new Error(`Driver ${entry.driver.type} does not support terminal input`);\n }\n entry.driver.terminalWrite(streamId, data);\n }\n\n terminalResize(streamId: string, cols: number, rows: number): void {\n const entry = this.streamEntries.get(streamId);\n if (!entry) {\n throw new Error(`No stream running for ${streamId}`);\n }\n if (!entry.driver.terminalResize) {\n throw new Error(`Driver ${entry.driver.type} does not support terminal resize`);\n }\n entry.driver.terminalResize(streamId, cols, rows);\n }\n\n getTerminalScrollback(streamId: string): string | undefined {\n const entry = this.streamEntries.get(streamId);\n if (!entry?.driver.getScrollback) return undefined;\n return entry.driver.getScrollback(streamId);\n }\n\n /**\n * Get replay data from the driver (events for ACP, scrollback for PTY).\n */\n getReplayData(streamId: string): StreamPayload[] | string | undefined {\n const entry = this.streamEntries.get(streamId);\n if (!entry?.driver.getReplayData) return undefined;\n return entry.driver.getReplayData(streamId);\n }\n\n isTerminalStream(streamId: string): boolean {\n const entry = this.streamEntries.get(streamId);\n return entry?.driver.isInteractive ?? false;\n }\n\n respondPermission(streamId: string, requestId: string, optionId: string): void {\n const entry = this.streamEntries.get(streamId);\n if (!entry) {\n // Stream may have stopped - silently ignore stale permission responses\n console.warn(`[MuxManager] No stream running for ${streamId}, ignoring permission response`);\n return;\n }\n if (!entry.driver.respondToPermission) {\n throw new Error(`Driver ${entry.driver.type} does not support permissions`);\n }\n entry.driver.respondToPermission(streamId, requestId, optionId);\n }\n\n /**\n * Get the driver state for a stream (for persistence before stopping).\n */\n getDriverState(streamId: string): unknown | undefined {\n const entry = this.streamEntries.get(streamId);\n if (!entry?.driver.getState) return undefined;\n return entry.driver.getState(streamId);\n }\n\n async stopForStream(streamId: string): Promise<void> {\n const entry = this.streamEntries.get(streamId);\n if (entry) {\n await entry.driver.stop(streamId);\n }\n this.streamEntries.delete(streamId);\n }\n\n async stopAll(): Promise<void> {\n const streamIds = Array.from(this.streamEntries.keys());\n await Promise.all(streamIds.map(id => this.stopForStream(id)));\n }\n\n getForStream(streamId: string): StreamEntry | undefined {\n return this.streamEntries.get(streamId);\n }\n\n getPendingPermission(streamId: string): import('../types.js').PendingPermission | null {\n const entry = this.streamEntries.get(streamId);\n if (!entry?.driver.getPendingPermission) return null;\n return entry.driver.getPendingPermission(streamId);\n }\n\n registerDriver(driver: StreamDriver): void {\n this.drivers.unshift(driver);\n }\n}\n\nexport const muxManager = new MuxManager();\nexport { MuxManager };\n"],"mappings":";;;;;;;;;;;AAAA,SAAS,oBAAoB;AAe7B,IAAM,aAAN,cAAyB,aAAa;AAAA,EAC5B;AAAA,EACA,gBAAgB,oBAAI,IAAyB;AAAA,EAErD,cAAc;AACZ,UAAM;AACN,SAAK,UAAU;AAAA,MACb,IAAI,UAAU;AAAA,MACd,IAAI,UAAU;AAAA,MACd,IAAI,WAAW;AAAA,IACjB;AAAA,EACF;AAAA,EAEQ,UAAU,MAA4B;AAC5C,UAAM,SAAS,KAAK,QAAQ,KAAK,OAAK,EAAE,SAAS,IAAI;AACrD,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI,MAAM,kCAAkC,IAAI,EAAE;AAAA,IAC1D;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,WAAW,UAAkB,SAA8B;AACjE,UAAM,QAAQ,KAAK,cAAc,IAAI,QAAQ;AAC7C,QAAI,CAAC,MAAO;AAEZ,UAAM,QAAqB;AAAA,MACzB,GAAG;AAAA,MACH;AAAA,MACA,WAAW,KAAK,IAAI;AAAA,IACtB;AAGA,UAAM,KAAK,KAAK;AAGhB,SAAK,KAAK,UAAU,KAAK;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,YAAY,MAA8C;AAC9D,UAAM,EAAE,UAAU,YAAY,QAAQ,KAAK,eAAe,MAAM,WAAW,IAAI;AAE/E,UAAM,WAAW,KAAK,cAAc,IAAI,QAAQ;AAEhD,QAAI,UAAU,WAAW,SAAS;AAEhC,aAAO;AAAA,QACL;AAAA,QACA,QAAQ,SAAS;AAAA,QACjB,YAAY,SAAS,OAAO;AAAA,MAC9B;AAAA,IACF;AAEA,QAAI,UAAU,WAAW,YAAY;AAEnC,aAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,cAAM,aAAa,MAAM;AACvB,gBAAM,QAAQ,KAAK,cAAc,IAAI,QAAQ;AAC7C,cAAI,OAAO,WAAW,SAAS;AAC7B,oBAAQ;AAAA,cACN;AAAA,cACA,QAAQ,MAAM;AAAA,cACd,YAAY,MAAM,OAAO;AAAA,YAC3B,CAAC;AAAA,UACH,WAAW,OAAO,WAAW,QAAQ;AACnC,mBAAO,IAAI,MAAM,wBAAwB,CAAC;AAAA,UAC5C,OAAO;AACL,uBAAW,YAAY,GAAG;AAAA,UAC5B;AAAA,QACF;AACA,mBAAW;AAAA,MACb,CAAC;AAAA,IACH;AAEA,UAAM,SAAS,KAAK,UAAU,UAAU;AACxC,UAAM,aAAa,CAAC,YAA2B,KAAK,WAAW,UAAU,OAAO;AAEhF,SAAK,cAAc,IAAI,UAAU;AAAA,MAC/B;AAAA,MACA,QAAQ,CAAC;AAAA,MACT;AAAA,MACA;AAAA,MACA;AAAA,MACA,QAAQ;AAAA,IACV,CAAC;AAED,QAAI;AACF,YAAM,SAAS,MAAM,OAAO,MAAM,UAAU,QAAQ,KAAK,iBAAiB,MAAM,YAAY,UAAU;AAEtG,WAAK,cAAc,IAAI,UAAU;AAAA,QAC/B;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,QAAQ;AAAA,MACV,CAAC;AAED,YAAM,WAAW,oBAAoB,QAAQ,EAAE;AAE/C,aAAO;AAAA,QACL;AAAA,QACA;AAAA,QACA,YAAY,OAAO;AAAA,MACrB;AAAA,IACF,SAAS,KAAK;AACZ,WAAK,cAAc,IAAI,UAAU;AAAA,QAC/B;AAAA,QACA,QAAQ,CAAC;AAAA,QACT;AAAA,QACA;AAAA,QACA;AAAA,QACA,QAAQ;AAAA,MACV,CAAC;AACD,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEA,MAAM,MAAM,UAAkB,SAAgC;AAC5D,UAAM,WAAW,6BAA6B,QAAQ,MAAM,QAAQ,MAAM,GAAG,EAAE,CAAC,MAAM;AAEtF,UAAM,QAAQ,KAAK,cAAc,IAAI,QAAQ;AAC7C,QAAI,CAAC,SAAS,MAAM,WAAW,SAAS;AACtC,YAAM,IAAI,MAAM,wBAAwB,QAAQ,EAAE;AAAA,IACpD;AAGA,SAAK,WAAW,UAAU,EAAE,WAAW,aAAa,CAAC;AAErD,UAAM,aAAa,CAAC,YAA2B,KAAK,WAAW,UAAU,OAAO;AAEhF,QAAI;AACF,YAAM,MAAM,OAAO,MAAM,UAAU,SAAS,MAAM,KAAK,UAAU;AAAA,IACnE,UAAE;AACA,WAAK,WAAW,UAAU,EAAE,WAAW,WAAW,CAAC;AAAA,IACrD;AAAA,EACF;AAAA,EAEA,MAAM,QAAQ,UAAkB,QAA+B;AAC7D,UAAM,QAAQ,KAAK,cAAc,IAAI,QAAQ;AAC7C,QAAI,CAAC,SAAS,MAAM,WAAW,SAAS;AACtC,YAAM,IAAI,MAAM,wBAAwB,QAAQ,EAAE;AAAA,IACpD;AACA,QAAI,CAAC,MAAM,OAAO,SAAS;AACzB,YAAM,IAAI,MAAM,UAAU,MAAM,OAAO,IAAI,2BAA2B;AAAA,IACxE;AACA,UAAM,MAAM,OAAO,QAAQ,UAAU,MAAM;AAAA,EAC7C;AAAA,EAEA,MAAM,SAAS,UAAkB,SAAgC;AAC/D,UAAM,QAAQ,KAAK,cAAc,IAAI,QAAQ;AAC7C,QAAI,CAAC,SAAS,MAAM,WAAW,SAAS;AACtC,YAAM,IAAI,MAAM,wBAAwB,QAAQ,EAAE;AAAA,IACpD;AACA,QAAI,CAAC,MAAM,OAAO,UAAU;AAC1B,YAAM,IAAI,MAAM,UAAU,MAAM,OAAO,IAAI,4BAA4B;AAAA,IACzE;AACA,UAAM,MAAM,OAAO,SAAS,UAAU,OAAO;AAAA,EAC/C;AAAA,EAEA,MAAM,OAAO,UAAiC;AAC5C,UAAM,QAAQ,KAAK,cAAc,IAAI,QAAQ;AAC7C,QAAI,CAAC,OAAO,OAAO,OAAQ;AAC3B,UAAM,MAAM,OAAO,OAAO,QAAQ;AAAA,EACpC;AAAA;AAAA,EAIA,cAAc,UAAkB,MAAoB;AAClD,UAAM,QAAQ,KAAK,cAAc,IAAI,QAAQ;AAC7C,QAAI,CAAC,OAAO;AACV,YAAM,IAAI,MAAM,yBAAyB,QAAQ,EAAE;AAAA,IACrD;AACA,QAAI,CAAC,MAAM,OAAO,eAAe;AAC/B,YAAM,IAAI,MAAM,UAAU,MAAM,OAAO,IAAI,kCAAkC;AAAA,IAC/E;AACA,UAAM,OAAO,cAAc,UAAU,IAAI;AAAA,EAC3C;AAAA,EAEA,eAAe,UAAkB,MAAc,MAAoB;AACjE,UAAM,QAAQ,KAAK,cAAc,IAAI,QAAQ;AAC7C,QAAI,CAAC,OAAO;AACV,YAAM,IAAI,MAAM,yBAAyB,QAAQ,EAAE;AAAA,IACrD;AACA,QAAI,CAAC,MAAM,OAAO,gBAAgB;AAChC,YAAM,IAAI,MAAM,UAAU,MAAM,OAAO,IAAI,mCAAmC;AAAA,IAChF;AACA,UAAM,OAAO,eAAe,UAAU,MAAM,IAAI;AAAA,EAClD;AAAA,EAEA,sBAAsB,UAAsC;AAC1D,UAAM,QAAQ,KAAK,cAAc,IAAI,QAAQ;AAC7C,QAAI,CAAC,OAAO,OAAO,cAAe,QAAO;AACzC,WAAO,MAAM,OAAO,cAAc,QAAQ;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA,EAKA,cAAc,UAAwD;AACpE,UAAM,QAAQ,KAAK,cAAc,IAAI,QAAQ;AAC7C,QAAI,CAAC,OAAO,OAAO,cAAe,QAAO;AACzC,WAAO,MAAM,OAAO,cAAc,QAAQ;AAAA,EAC5C;AAAA,EAEA,iBAAiB,UAA2B;AAC1C,UAAM,QAAQ,KAAK,cAAc,IAAI,QAAQ;AAC7C,WAAO,OAAO,OAAO,iBAAiB;AAAA,EACxC;AAAA,EAEA,kBAAkB,UAAkB,WAAmB,UAAwB;AAC7E,UAAM,QAAQ,KAAK,cAAc,IAAI,QAAQ;AAC7C,QAAI,CAAC,OAAO;AAEV,cAAQ,KAAK,sCAAsC,QAAQ,gCAAgC;AAC3F;AAAA,IACF;AACA,QAAI,CAAC,MAAM,OAAO,qBAAqB;AACrC,YAAM,IAAI,MAAM,UAAU,MAAM,OAAO,IAAI,+BAA+B;AAAA,IAC5E;AACA,UAAM,OAAO,oBAAoB,UAAU,WAAW,QAAQ;AAAA,EAChE;AAAA;AAAA;AAAA;AAAA,EAKA,eAAe,UAAuC;AACpD,UAAM,QAAQ,KAAK,cAAc,IAAI,QAAQ;AAC7C,QAAI,CAAC,OAAO,OAAO,SAAU,QAAO;AACpC,WAAO,MAAM,OAAO,SAAS,QAAQ;AAAA,EACvC;AAAA,EAEA,MAAM,cAAc,UAAiC;AACnD,UAAM,QAAQ,KAAK,cAAc,IAAI,QAAQ;AAC7C,QAAI,OAAO;AACT,YAAM,MAAM,OAAO,KAAK,QAAQ;AAAA,IAClC;AACA,SAAK,cAAc,OAAO,QAAQ;AAAA,EACpC;AAAA,EAEA,MAAM,UAAyB;AAC7B,UAAM,YAAY,MAAM,KAAK,KAAK,cAAc,KAAK,CAAC;AACtD,UAAM,QAAQ,IAAI,UAAU,IAAI,QAAM,KAAK,cAAc,EAAE,CAAC,CAAC;AAAA,EAC/D;AAAA,EAEA,aAAa,UAA2C;AACtD,WAAO,KAAK,cAAc,IAAI,QAAQ;AAAA,EACxC;AAAA,EAEA,qBAAqB,UAAkE;AACrF,UAAM,QAAQ,KAAK,cAAc,IAAI,QAAQ;AAC7C,QAAI,CAAC,OAAO,OAAO,qBAAsB,QAAO;AAChD,WAAO,MAAM,OAAO,qBAAqB,QAAQ;AAAA,EACnD;AAAA,EAEA,eAAe,QAA4B;AACzC,SAAK,QAAQ,QAAQ,MAAM;AAAA,EAC7B;AACF;AAEO,IAAM,aAAa,IAAI,WAAW;","names":[]}