pty-manager 1.10.2 → 1.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +39 -0
- package/dist/index.d.ts +39 -0
- package/dist/index.js +62 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +62 -0
- package/dist/index.mjs.map +1 -1
- package/dist/pty-worker.js +48 -0
- package/package.json +1 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/adapters/adapter-factory.ts","../src/adapters/adapter-registry.ts","../src/adapters/base-adapter.ts","../src/adapters/shell-adapter.ts","../src/bun-compat.ts","../src/ensure-pty.ts","../src/pty-manager.ts","../src/logger.ts","../src/pty-session.ts","../src/task-completion-trace.ts"],"sourcesContent":["/**\n * pty-manager\n *\n * PTY session manager with lifecycle management,\n * pluggable adapters, and blocking prompt detection.\n */\n\nexport type { CLIAdapter, ShellAdapterOptions } from './adapters';\n// Adapter system\nexport {\n AdapterRegistry,\n BaseCLIAdapter,\n createAdapter,\n ShellAdapter,\n} from './adapters';\nexport type {\n BunPTYManagerOptions,\n WorkerSessionHandle,\n} from './bun-compat';\n// Bun compatibility layer\nexport {\n BunCompatiblePTYManager,\n createPTYManager,\n isBun,\n} from './bun-compat';\n// PTY preflight check\nexport { ensurePty } from './ensure-pty';\n// Event types\nexport type { PTYManagerEvents } from './pty-manager';\n// Core classes\nexport { PTYManager } from './pty-manager';\nexport type { PTYSessionEvents } from './pty-session';\nexport { PTYSession, SPECIAL_KEYS } from './pty-session';\nexport type {\n BuildTimelineOptions,\n TaskCompletionTimelineResult,\n TaskCompletionTimelineStep,\n TaskCompletionTraceRecord,\n TaskCompletionTurnTimeline,\n} from './task-completion-trace';\nexport {\n buildTaskCompletionTimeline,\n extractTaskCompletionTraceRecords,\n} from './task-completion-trace';\n// Types\nexport type {\n // Factory types\n AdapterFactoryConfig,\n AuthRequiredInfo,\n AuthRequiredMethod,\n AutoResponseRule,\n BlockingPromptDetection,\n BlockingPromptInfo,\n BlockingPromptType,\n // Manager types\n Logger,\n LoginDetection,\n LogOptions,\n MessageType,\n // Adapter types\n ParsedOutput,\n PTYManagerConfig,\n SessionFilter,\n SessionHandle,\n SessionMessage,\n // Session types\n SessionStatus,\n SpawnConfig,\n // Stall detection types\n StallClassification,\n StopOptions,\n TerminalAttachment,\n // Tool running detection\n ToolRunningInfo,\n} from './types';\n","/**\n * Adapter Factory — re-exported from adapter-types\n */\nexport { createAdapter } from 'adapter-types';\n","/**\n * Adapter Registry — re-exported from adapter-types\n */\nexport { AdapterRegistry } from 'adapter-types';\n","/**\n * Base CLI Adapter — re-exported from adapter-types\n */\nexport { BaseCLIAdapter } from 'adapter-types';\n","/**\n * Shell Adapter\n *\n * Built-in adapter for bash/zsh shell sessions.\n */\n\nimport type {\n AutoResponseRule,\n BlockingPromptDetection,\n LoginDetection,\n ParsedOutput,\n SpawnConfig,\n} from '../types';\nimport type { CLIAdapter } from './adapter-interface';\n\n/**\n * Options for the shell adapter\n */\nexport interface ShellAdapterOptions {\n /** Shell to use (default: $SHELL or /bin/bash) */\n shell?: string;\n\n /** Custom prompt string (default: 'pty> ') */\n prompt?: string;\n}\n\n/**\n * Built-in adapter for shell sessions (bash/zsh)\n */\nexport class ShellAdapter implements CLIAdapter {\n readonly adapterType = 'shell';\n readonly displayName = 'Shell';\n readonly autoResponseRules: AutoResponseRule[] = [];\n\n private shell: string;\n private promptStr: string;\n\n constructor(options: ShellAdapterOptions = {}) {\n this.shell = options.shell || process.env.SHELL || '/bin/bash';\n this.promptStr = options.prompt || 'pty> ';\n }\n\n getCommand(): string {\n return this.shell;\n }\n\n getArgs(_config: SpawnConfig): string[] {\n return [];\n }\n\n getEnv(_config: SpawnConfig): Record<string, string> {\n return {\n PS1: this.promptStr,\n };\n }\n\n detectLogin(_output: string): LoginDetection {\n // Shell doesn't need login\n return { required: false };\n }\n\n detectBlockingPrompt(_output: string): BlockingPromptDetection {\n // Shell typically doesn't have blocking prompts\n return { detected: false };\n }\n\n detectReady(output: string): boolean {\n // Reject continuation prompts — the shell is waiting for a closing\n // quote/heredoc/backtick, NOT at a real prompt.\n if (this.isContinuationPrompt(output)) {\n return false;\n }\n\n // Check for our custom prompt string (PS1) or standard shell prompt at end of line\n return this.getPromptPattern().test(this.stripAnsi(output));\n }\n\n /**\n * Detect shell continuation prompts that indicate the shell is NOT ready\n * for a new command (e.g., unclosed quote, heredoc, backtick).\n */\n private isContinuationPrompt(output: string): boolean {\n const stripped = this.stripAnsi(output);\n // Match common continuation prompts at the end of output\n return (\n /(?:quote|dquote|heredoc|bquote|cmdsubst|pipe|then|else|do|loop)>\\s*$/.test(\n stripped\n ) ||\n // Also match bare > that's preceded by one of these words on the same line\n /(?:quote|dquote|heredoc|bquote)>\\s*$/m.test(stripped)\n );\n }\n\n detectExit(output: string): {\n exited: boolean;\n code?: number;\n error?: string;\n } {\n if (output.includes('exit')) {\n return { exited: true, code: 0 };\n }\n return { exited: false };\n }\n\n parseOutput(output: string): ParsedOutput | null {\n const cleaned = this.stripAnsi(output).trim();\n if (!cleaned) return null;\n\n return {\n type: 'response',\n content: cleaned,\n isComplete: true,\n isQuestion: false,\n };\n }\n\n formatInput(message: string): string {\n return message;\n }\n\n getPromptPattern(): RegExp {\n // Match our custom prompt or standard shell prompts ($ or #).\n // Does NOT match bare > because that collides with continuation prompts\n // (quote>, dquote>, heredoc>, etc.).\n const escaped = this.promptStr.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n return new RegExp(`(?:${escaped}|\\\\$|#)\\\\s*$`, 'm');\n }\n\n async validateInstallation(): Promise<{\n installed: boolean;\n version?: string;\n error?: string;\n }> {\n // Shell is always installed\n return { installed: true };\n }\n\n private stripAnsi(str: string): string {\n // eslint-disable-next-line no-control-regex\n return str.replace(/\\x1B(?:[@-Z\\\\-_]|\\[[0-?]*[ -/]*[@-~])/g, '');\n }\n}\n","/**\n * Bun-Compatible PTY Manager\n *\n * A wrapper that spawns a Node.js worker process to handle PTY operations,\n * allowing pty-manager to work from Bun or other non-Node runtimes.\n */\n\nimport { type ChildProcess, spawn } from 'node:child_process';\nimport { EventEmitter } from 'node:events';\nimport * as path from 'node:path';\nimport * as readline from 'node:readline';\nimport type {\n AuthRequiredInfo,\n AutoResponseRule,\n BlockingPromptType,\n SessionStatus,\n SpawnConfig,\n StallClassification,\n ToolRunningInfo,\n} from './types';\n\n/**\n * Serialized auto-response rule for IPC (pattern as string instead of RegExp)\n */\nexport interface SerializedRule {\n pattern: string;\n flags?: string;\n type: BlockingPromptType;\n response: string;\n responseType?: 'text' | 'keys';\n keys?: string[];\n description: string;\n safe?: boolean;\n once?: boolean;\n}\n\nexport interface WorkerSessionHandle {\n id: string;\n name: string;\n type: string;\n status: SessionStatus;\n pid: number | undefined;\n cols: number;\n rows: number;\n startedAt?: Date;\n lastActivityAt?: Date;\n error?: string;\n exitCode?: number;\n}\n\nexport interface BunPTYManagerOptions {\n /** Path to node executable (default: 'node') */\n nodePath?: string;\n /** Path to worker script (default: auto-detected) */\n workerPath?: string;\n /** Environment variables for worker process */\n env?: Record<string, string>;\n /**\n * Adapter modules to load in the worker process.\n * Each module should export a `createAllAdapters()` function that returns an array of adapters.\n * Example: ['coding-agent-adapters']\n */\n adapterModules?: string[];\n\n /** Enable stall detection (default: false) */\n stallDetectionEnabled?: boolean;\n /** Default stall timeout in ms (default: 8000) */\n stallTimeoutMs?: number;\n /**\n * External classification callback invoked when a stall is detected.\n * The worker emits stall_detected; this callback runs on the parent side.\n */\n onStallClassify?: (\n sessionId: string,\n recentOutput: string,\n stallDurationMs: number\n ) => Promise<StallClassification | null>;\n}\n\ninterface PendingOperation {\n resolve: (value: unknown) => void;\n reject: (error: Error) => void;\n timeout: NodeJS.Timeout;\n}\n\n/**\n * PTY Manager that works with Bun and other non-Node runtimes\n * by spawning a Node.js worker process.\n */\nexport class BunCompatiblePTYManager extends EventEmitter {\n private worker: ChildProcess | null = null;\n private sessions: Map<string, WorkerSessionHandle> = new Map();\n private pending: Map<string, PendingOperation> = new Map();\n private ready = false;\n private readyPromise: Promise<void>;\n private readyResolve!: () => void;\n private nodePath: string;\n private workerPath: string;\n private env: Record<string, string>;\n private adapterModules: string[];\n private _stallDetectionEnabled: boolean;\n private _stallTimeoutMs: number;\n private _onStallClassify?: (\n sessionId: string,\n recentOutput: string,\n stallDurationMs: number\n ) => Promise<StallClassification | null>;\n\n constructor(options: BunPTYManagerOptions = {}) {\n super();\n\n this.nodePath = options.nodePath || 'node';\n this.workerPath = options.workerPath || this.findWorkerPath();\n this.env = options.env || {};\n this.adapterModules = options.adapterModules || [];\n this._stallDetectionEnabled = options.stallDetectionEnabled ?? false;\n this._stallTimeoutMs = options.stallTimeoutMs ?? 8000;\n this._onStallClassify = options.onStallClassify;\n\n this.readyPromise = new Promise((resolve) => {\n this.readyResolve = resolve;\n });\n\n this.startWorker();\n }\n\n private findWorkerPath(): string {\n // Try to find the worker script relative to this module\n const possiblePaths = [\n path.join(__dirname, 'pty-worker.js'),\n path.join(__dirname, '..', 'dist', 'pty-worker.js'),\n path.join(__dirname, '..', 'src', 'pty-worker.js'),\n ];\n\n // Return first path (we'll rely on Node to throw if it doesn't exist)\n return possiblePaths[0];\n }\n\n private startWorker(): void {\n this.worker = spawn(this.nodePath, [this.workerPath], {\n stdio: ['pipe', 'pipe', 'pipe'],\n env: { ...process.env, ...this.env },\n });\n\n if (!this.worker.stdout || !this.worker.stdin) {\n throw new Error('Failed to create worker process pipes');\n }\n\n const rl = readline.createInterface({\n input: this.worker.stdout,\n terminal: false,\n });\n\n rl.on('line', (line) => this.handleWorkerMessage(line));\n\n this.worker.stderr?.on('data', (data) => {\n this.emit('worker_error', data.toString());\n });\n\n this.worker.on('exit', (code, signal) => {\n this.ready = false;\n this.worker = null;\n this.emit('worker_exit', { code, signal });\n\n // Reject all pending operations\n for (const [key, op] of this.pending) {\n clearTimeout(op.timeout);\n op.reject(new Error('Worker process exited'));\n this.pending.delete(key);\n }\n\n // Mark all sessions as stopped\n for (const session of this.sessions.values()) {\n session.status = 'stopped';\n }\n });\n\n this.worker.on('error', (err) => {\n this.emit('worker_error', err);\n });\n }\n\n private handleWorkerMessage(line: string): void {\n let event: Record<string, unknown>;\n\n try {\n event = JSON.parse(line);\n } catch {\n this.emit('worker_error', `Invalid JSON from worker: ${line}`);\n return;\n }\n\n const eventType = event.event as string;\n const id = event.id as string | undefined;\n\n switch (eventType) {\n case 'worker_ready':\n // Send stall detection config to worker (fire-and-forget, no ack needed before ready)\n if (this._stallDetectionEnabled) {\n this.sendCommand({\n cmd: 'configureStallDetection',\n enabled: true,\n timeoutMs: this._stallTimeoutMs,\n });\n }\n // Register adapter modules and wait for ack before marking as ready.\n // Without this, spawn() can race ahead using the default shell adapter.\n if (this.adapterModules.length > 0) {\n this.sendCommand({\n cmd: 'registerAdapters',\n modules: this.adapterModules,\n });\n this.createPending('registerAdapters')\n .then(() => {\n this.ready = true;\n this.readyResolve();\n this.emit('ready');\n })\n .catch((err) => {\n this.emit('worker_error', `Failed to register adapters: ${err}`);\n // Still resolve so callers aren't stuck forever — they'll get shell adapter\n this.ready = true;\n this.readyResolve();\n this.emit('ready');\n });\n } else {\n this.ready = true;\n this.readyResolve();\n this.emit('ready');\n }\n break;\n\n case 'spawned': {\n // Get config from event (worker sends it back)\n const session: WorkerSessionHandle = {\n id: id!,\n name: (event.name as string) || id!,\n type: (event.type as string) || 'shell',\n status: 'starting',\n pid: event.pid as number,\n cols: (event.cols as number) || 80,\n rows: (event.rows as number) || 24,\n startedAt: new Date(),\n };\n this.sessions.set(id!, session);\n this.emit('session_started', session);\n break;\n }\n\n case 'output': {\n const session = this.sessions.get(id!);\n if (session) {\n session.lastActivityAt = new Date();\n }\n this.emit('data', { id, data: event.data });\n this.emit(`data:${id}`, event.data);\n break;\n }\n\n case 'ready': {\n const session = this.sessions.get(id!);\n if (session) {\n session.status = 'ready';\n session.lastActivityAt = new Date();\n this.emit('session_ready', session);\n }\n break;\n }\n\n case 'exit': {\n const session = this.sessions.get(id!);\n if (session) {\n session.status = 'stopped';\n session.exitCode = event.code as number;\n session.lastActivityAt = new Date();\n this.emit('session_stopped', session, event.code, event.signal);\n this.sessions.delete(id!);\n }\n break;\n }\n\n case 'error':\n if (id) {\n const session = this.sessions.get(id);\n if (session) {\n session.status = 'error';\n session.error = event.message as string;\n session.lastActivityAt = new Date();\n }\n this.emit('session_error', { id, error: event.message });\n } else {\n this.emit('worker_error', event.message);\n }\n break;\n\n case 'blocking_prompt': {\n const session = this.sessions.get(id!);\n if (session) {\n this.emit(\n 'blocking_prompt',\n session,\n event.promptInfo,\n event.autoResponded\n );\n }\n break;\n }\n\n case 'login_required': {\n const session = this.sessions.get(id!);\n if (session) {\n session.status = 'authenticating';\n this.emit('login_required', session, event.instructions, event.url);\n }\n break;\n }\n\n case 'auth_required': {\n const session = this.sessions.get(id!);\n if (session) {\n session.status = 'authenticating';\n this.emit('auth_required', session, event.info as AuthRequiredInfo);\n }\n break;\n }\n\n case 'message': {\n const msg = event.message as Record<string, unknown>;\n // Convert timestamp back to Date\n this.emit('message', {\n ...msg,\n timestamp: new Date(msg.timestamp as string),\n });\n break;\n }\n\n case 'question': {\n const session = this.sessions.get(id!);\n if (session) {\n this.emit('question', session, event.question);\n }\n break;\n }\n\n case 'status_changed': {\n const session = this.sessions.get(id!);\n if (session) {\n session.status = event.status as SessionStatus;\n session.lastActivityAt = new Date();\n this.emit('session_status_changed', session);\n }\n break;\n }\n\n case 'task_complete': {\n const session = this.sessions.get(id!);\n if (session) {\n session.status = 'ready';\n session.lastActivityAt = new Date();\n this.emit('task_complete', session);\n }\n break;\n }\n\n case 'tool_running': {\n const session = this.sessions.get(id!);\n if (session) {\n this.emit('tool_running', session, event.info as ToolRunningInfo);\n }\n break;\n }\n\n case 'stall_detected': {\n const session = this.sessions.get(id!);\n if (session) {\n const recentOutput = event.recentOutput as string;\n const stallDurationMs = event.stallDurationMs as number;\n this.emit('stall_detected', session, recentOutput, stallDurationMs);\n\n // Call external classifier on parent side, send result back to worker\n if (this._onStallClassify) {\n this._onStallClassify(id!, recentOutput, stallDurationMs)\n .then((classification) => {\n this.sendCommand({\n cmd: 'classifyStallResult',\n id: id!,\n classification,\n });\n })\n .catch(() => {\n // On error, send null to reset the timer\n this.sendCommand({\n cmd: 'classifyStallResult',\n id: id!,\n classification: null,\n });\n });\n }\n }\n break;\n }\n\n case 'list': {\n // Convert date strings back to Date objects\n const sessions = (event.sessions as Record<string, unknown>[]).map(\n (s) => ({\n ...s,\n startedAt: s.startedAt\n ? new Date(s.startedAt as string)\n : undefined,\n lastActivityAt: s.lastActivityAt\n ? new Date(s.lastActivityAt as string)\n : undefined,\n })\n ) as WorkerSessionHandle[];\n this.resolvePending('list', sessions);\n break;\n }\n\n case 'rules': {\n // Convert serialized rules back to AutoResponseRule objects\n const serializedRules = event.rules as SerializedRule[];\n const rules = serializedRules.map((r) => ({\n pattern: new RegExp(r.pattern, r.flags || ''),\n type: r.type,\n response: r.response,\n responseType: r.responseType,\n keys: r.keys,\n description: r.description,\n safe: r.safe,\n once: r.once,\n })) as AutoResponseRule[];\n this.resolvePending(`getRules:${id}`, rules);\n break;\n }\n\n case 'ack': {\n const cmd = event.cmd as string;\n const success = event.success as boolean;\n const pendingKey = id ? `${cmd}:${id}` : cmd;\n const pending = this.pending.get(pendingKey);\n\n if (pending) {\n clearTimeout(pending.timeout);\n this.pending.delete(pendingKey);\n\n if (success) {\n pending.resolve(true);\n } else {\n pending.reject(new Error(event.error as string));\n }\n }\n break;\n }\n }\n }\n\n private sendCommand(cmd: Record<string, unknown>): void {\n if (!this.worker?.stdin) {\n throw new Error('Worker not available');\n }\n\n this.worker.stdin.write(`${JSON.stringify(cmd)}\\n`);\n }\n\n private createPending(key: string, timeoutMs = 30000): Promise<unknown> {\n return new Promise((resolve, reject) => {\n const timeout = setTimeout(() => {\n this.pending.delete(key);\n reject(new Error(`Operation ${key} timed out`));\n }, timeoutMs);\n\n this.pending.set(key, { resolve, reject, timeout });\n });\n }\n\n private resolvePending(key: string, value: unknown): void {\n const pending = this.pending.get(key);\n if (pending) {\n clearTimeout(pending.timeout);\n this.pending.delete(key);\n pending.resolve(value);\n }\n }\n\n /**\n * Wait for the worker to be ready\n */\n async waitForReady(): Promise<void> {\n return this.readyPromise;\n }\n\n /**\n * Check if worker is ready\n */\n isReady(): boolean {\n return this.ready;\n }\n\n /**\n * Spawn a new PTY session\n */\n async spawn(\n config: SpawnConfig & { id: string }\n ): Promise<WorkerSessionHandle> {\n await this.waitForReady();\n\n const { id } = config;\n\n this.sendCommand({ cmd: 'spawn', id, config });\n\n await this.createPending(`spawn:${id}`);\n\n return this.sessions.get(id)!;\n }\n\n /**\n * Send data to a session\n */\n async send(id: string, data: string): Promise<void> {\n await this.waitForReady();\n\n this.sendCommand({ cmd: 'send', id, data });\n\n await this.createPending(`send:${id}`);\n }\n\n /**\n * Send special keys to a session\n */\n async sendKeys(id: string, keys: string | string[]): Promise<void> {\n await this.waitForReady();\n\n this.sendCommand({ cmd: 'sendKeys', id, keys });\n\n await this.createPending(`sendKeys:${id}`);\n }\n\n /**\n * Notify a session of an external hook event (resets stall timer, updates status).\n */\n async notifyHookEvent(id: string, hookEvent: string): Promise<void> {\n await this.waitForReady();\n this.sendCommand({ cmd: 'notifyHookEvent', id, hookEvent });\n await this.createPending(`notifyHookEvent:${id}`);\n }\n\n /**\n * Write raw data to a session (bypasses adapter formatting)\n */\n async writeRaw(id: string, data: string): Promise<void> {\n await this.waitForReady();\n this.sendCommand({ cmd: 'writeRaw', id, data });\n // Fire-and-forget — writeRaw pushes bytes to the terminal and\n // doesn't need an ACK. Awaiting createPending caused timeouts\n // when overlapping calls for the same session collided on the\n // pending key (`writeRaw:${id}`), since the worker ACK only\n // carries cmd+id with no sequence number.\n }\n\n /**\n * Paste text to a session\n */\n async paste(id: string, text: string, bracketed = true): Promise<void> {\n await this.waitForReady();\n\n this.sendCommand({ cmd: 'paste', id, text, bracketed });\n\n await this.createPending(`paste:${id}`);\n }\n\n /**\n * Resize a session\n */\n async resize(id: string, cols: number, rows: number): Promise<void> {\n await this.waitForReady();\n this.sendCommand({ cmd: 'resize', id, cols, rows });\n const session = this.sessions.get(id);\n if (session) {\n session.cols = cols;\n session.rows = rows;\n }\n // Fire-and-forget — rapid resize events from the UI collide on\n // the pending key (`resize:${id}`) causing spurious timeouts.\n }\n\n /**\n * Kill a session\n */\n async kill(id: string, signal?: string): Promise<void> {\n await this.waitForReady();\n\n this.sendCommand({ cmd: 'kill', id, signal });\n\n await this.createPending(`kill:${id}`);\n }\n\n /**\n * Get a session by ID\n */\n get(id: string): WorkerSessionHandle | undefined {\n return this.sessions.get(id);\n }\n\n /**\n * List all sessions\n */\n async list(): Promise<WorkerSessionHandle[]> {\n await this.waitForReady();\n\n this.sendCommand({ cmd: 'list' });\n\n const sessions = (await this.createPending(\n 'list'\n )) as WorkerSessionHandle[];\n return sessions;\n }\n\n /**\n * Check if a session exists\n */\n has(id: string): boolean {\n return this.sessions.has(id);\n }\n\n /**\n * Subscribe to output from a specific session\n */\n onSessionData(id: string, callback: (data: string) => void): () => void {\n const handler = (data: string) => callback(data);\n this.on(`data:${id}`, handler);\n return () => this.off(`data:${id}`, handler);\n }\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Runtime Auto-Response Rules API\n // ─────────────────────────────────────────────────────────────────────────────\n\n private serializeRule(rule: AutoResponseRule): SerializedRule {\n return {\n pattern: rule.pattern.source,\n flags: rule.pattern.flags || undefined,\n type: rule.type,\n response: rule.response,\n responseType: rule.responseType,\n keys: rule.keys,\n description: rule.description,\n safe: rule.safe,\n once: rule.once,\n };\n }\n\n /**\n * Add an auto-response rule to a session.\n * Session rules are checked before adapter rules.\n */\n async addAutoResponseRule(\n sessionId: string,\n rule: AutoResponseRule\n ): Promise<void> {\n await this.waitForReady();\n\n const serialized = this.serializeRule(rule);\n this.sendCommand({ cmd: 'addRule', id: sessionId, rule: serialized });\n\n await this.createPending(`addRule:${sessionId}`);\n }\n\n /**\n * Remove an auto-response rule from a session by pattern.\n * Returns true if a rule was removed.\n */\n async removeAutoResponseRule(\n sessionId: string,\n pattern: RegExp\n ): Promise<boolean> {\n await this.waitForReady();\n\n this.sendCommand({\n cmd: 'removeRule',\n id: sessionId,\n pattern: pattern.source,\n flags: pattern.flags || undefined,\n });\n\n try {\n await this.createPending(`removeRule:${sessionId}`);\n return true;\n } catch {\n return false;\n }\n }\n\n /**\n * Set all auto-response rules for a session, replacing existing ones.\n */\n async setAutoResponseRules(\n sessionId: string,\n rules: AutoResponseRule[]\n ): Promise<void> {\n await this.waitForReady();\n\n const serialized = rules.map((r) => this.serializeRule(r));\n this.sendCommand({ cmd: 'setRules', id: sessionId, rules: serialized });\n\n await this.createPending(`setRules:${sessionId}`);\n }\n\n /**\n * Get all auto-response rules for a session.\n */\n async getAutoResponseRules(sessionId: string): Promise<AutoResponseRule[]> {\n await this.waitForReady();\n\n this.sendCommand({ cmd: 'getRules', id: sessionId });\n\n const rules = (await this.createPending(\n `getRules:${sessionId}`\n )) as AutoResponseRule[];\n return rules;\n }\n\n /**\n * Select a TUI menu option by index (0-based) in a session.\n */\n async selectMenuOption(id: string, optionIndex: number): Promise<void> {\n await this.waitForReady();\n\n this.sendCommand({ cmd: 'selectMenuOption', id, optionIndex });\n\n await this.createPending(`selectMenuOption:${id}`);\n }\n\n /**\n * Clear all auto-response rules for a session.\n */\n async clearAutoResponseRules(sessionId: string): Promise<void> {\n await this.waitForReady();\n\n this.sendCommand({ cmd: 'clearRules', id: sessionId });\n\n await this.createPending(`clearRules:${sessionId}`);\n }\n\n /**\n * Shutdown the worker and all sessions\n */\n async shutdown(): Promise<void> {\n if (!this.worker) return;\n\n this.sendCommand({ cmd: 'shutdown' });\n\n await this.createPending('shutdown', 10000).catch(() => {\n // Force kill if shutdown times out\n this.worker?.kill('SIGKILL');\n });\n }\n\n /**\n * Restart the worker process\n */\n async restart(): Promise<void> {\n await this.shutdown();\n\n this.sessions.clear();\n this.ready = false;\n this.readyPromise = new Promise((resolve) => {\n this.readyResolve = resolve;\n });\n\n this.startWorker();\n await this.waitForReady();\n }\n}\n\n/**\n * Detect if running in Bun\n */\nexport function isBun(): boolean {\n // Bun 1.1.24+ sets process.versions.bun (lowercase)\n return typeof process !== 'undefined' && 'bun' in process.versions;\n}\n\n/**\n * Create the appropriate PTY manager based on runtime\n */\nexport function createPTYManager(\n options?: BunPTYManagerOptions\n): BunCompatiblePTYManager {\n return new BunCompatiblePTYManager(options);\n}\n","/**\n * Lazy runtime check for node-pty native addon.\n *\n * Called once before the first PTY spawn. Ensures the native binary is\n * loadable and spawn-helper permissions are correct.\n *\n * 1. Finds the binary — checks for prebuilt pty.node under\n * prebuilds/<platform>-<arch>/ (node-pty >=1.0), then falls back to\n * checking for a node-gyp compiled build/Release/pty.node\n * 2. Fixes spawn-helper permissions — bun install can strip execute\n * bits from the spawn-helper Mach-O binary, causing posix_spawnp\n * failed at runtime. The script chmod 755s all spawn-helpers under\n * prebuilds/\n * 3. Rebuilds if missing — if no binary is found at all, runs\n * node-gyp rebuild as a last resort (with a 2-minute timeout)\n */\n\nimport { execSync } from 'node:child_process';\nimport { chmodSync, existsSync, readdirSync, statSync } from 'node:fs';\nimport { dirname, join, relative } from 'node:path';\n\nconst TAG = '[pty-preflight]';\nconst platformArch = `${process.platform}-${process.arch}`;\n\nlet checked = false;\n\n// ─── Locate node-pty ─────────────────────────────────────────────────────────\n\nfunction findNodePtyRoots(): string[] {\n const roots: string[] = [];\n\n // Try to resolve node-pty through the standard require resolution\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const nodePtyMain = require.resolve('node-pty');\n const nodePtyRoot = dirname(dirname(nodePtyMain));\n if (existsSync(join(nodePtyRoot, 'package.json'))) {\n roots.push(nodePtyRoot);\n }\n } catch {\n // not resolvable directly — try known paths\n }\n\n // Also check common nested locations relative to this package\n const packageRoot = join(__dirname, '..');\n const candidates = [\n join(packageRoot, 'node_modules', 'node-pty'),\n // Monorepo hoisted\n join(packageRoot, '..', 'node-pty'),\n join(packageRoot, '..', '..', 'node-pty'),\n ];\n\n for (const candidate of candidates) {\n if (\n existsSync(join(candidate, 'package.json')) &&\n !roots.includes(candidate)\n ) {\n roots.push(candidate);\n }\n }\n\n return roots;\n}\n\n// ─── Find native binary ─────────────────────────────────────────────────────\n\nfunction findNativeBinary(\n nodePtyRoot: string\n): { type: string; path: string } | null {\n // Prebuilt (node-pty >= 1.0)\n const prebuildPath = join(nodePtyRoot, 'prebuilds', platformArch, 'pty.node');\n if (existsSync(prebuildPath)) {\n return { type: 'prebuild', path: prebuildPath };\n }\n\n // node-gyp compiled\n const gypPath = join(nodePtyRoot, 'build', 'Release', 'pty.node');\n if (existsSync(gypPath)) {\n return { type: 'gyp', path: gypPath };\n }\n\n return null;\n}\n\n// ─── Fix spawn-helper permissions ────────────────────────────────────────────\n\nfunction fixSpawnHelpers(\n nodePtyRoot: string,\n log: (msg: string) => void\n): void {\n if (process.platform === 'win32') return;\n\n const prebuildsDir = join(nodePtyRoot, 'prebuilds');\n if (!existsSync(prebuildsDir)) return;\n\n try {\n for (const entry of readdirSync(prebuildsDir)) {\n const helperPath = join(prebuildsDir, entry, 'spawn-helper');\n if (existsSync(helperPath)) {\n try {\n const stat = statSync(helperPath);\n if ((stat.mode & 0o111) === 0) {\n chmodSync(helperPath, 0o755);\n log(\n `${TAG} Fixed spawn-helper permissions: ${relative(nodePtyRoot, helperPath)}`\n );\n }\n } catch {\n // Permission denied — not fatal\n }\n }\n }\n } catch {\n // prebuilds dir not readable\n }\n}\n\n// ─── Rebuild if missing ──────────────────────────────────────────────────────\n\nfunction rebuildNodePty(\n nodePtyRoot: string,\n log: (msg: string) => void\n): boolean {\n log(`${TAG} No native binary found — attempting node-gyp rebuild...`);\n try {\n execSync('node-gyp rebuild', {\n cwd: nodePtyRoot,\n stdio: 'pipe',\n timeout: 120_000,\n });\n log(`${TAG} node-gyp rebuild succeeded`);\n return true;\n } catch (err) {\n log(\n `${TAG} node-gyp rebuild failed: ${err instanceof Error ? err.message : err}`\n );\n return false;\n }\n}\n\n// ─── Public API ──────────────────────────────────────────────────────────────\n\n/**\n * Ensure node-pty is usable. Called once before first spawn.\n * Idempotent — subsequent calls are no-ops.\n *\n * @param log - logger function (defaults to console.log)\n * @throws Error if no native binary can be found or built\n */\nexport function ensurePty(log: (msg: string) => void = console.log): void {\n if (checked) return;\n checked = true;\n\n const roots = findNodePtyRoots();\n\n if (roots.length === 0) {\n throw new Error(\n `${TAG} node-pty not found. Install it with: npm install node-pty`\n );\n }\n\n let anyBinaryFound = false;\n\n for (const root of roots) {\n const binary = findNativeBinary(root);\n\n if (binary) {\n log(`${TAG} Found ${binary.type} binary for ${platformArch}`);\n anyBinaryFound = true;\n }\n\n // Always fix spawn-helper permissions\n fixSpawnHelpers(root, log);\n\n // Rebuild if no binary at this location\n if (!binary) {\n if (rebuildNodePty(root, log)) {\n if (findNativeBinary(root)) {\n anyBinaryFound = true;\n }\n }\n }\n\n // Stop after first location with a working binary\n if (anyBinaryFound) break;\n }\n\n if (!anyBinaryFound) {\n throw new Error(\n `${TAG} No node-pty native binary available for ${platformArch}. ` +\n `Try: cd node_modules/node-pty && node-gyp rebuild`\n );\n }\n}\n","/**\n * PTY Manager\n *\n * Manages multiple PTY sessions for CLI tools.\n */\n\nimport { EventEmitter } from 'node:events';\nimport type { CLIAdapter } from './adapters/adapter-interface';\nimport { AdapterRegistry } from './adapters/adapter-registry';\nimport { consoleLogger } from './logger';\nimport { PTYSession } from './pty-session';\nimport type {\n AuthRequiredInfo,\n AutoResponseRule,\n BlockingPromptInfo,\n Logger,\n LogOptions,\n PTYManagerConfig,\n SessionFilter,\n SessionHandle,\n SessionMessage,\n SessionStatus,\n SpawnConfig,\n StallClassification,\n StopOptions,\n TerminalAttachment,\n ToolRunningInfo,\n} from './types';\n\nexport interface PTYManagerEvents {\n session_started: (session: SessionHandle) => void;\n session_ready: (session: SessionHandle) => void;\n session_stopped: (session: SessionHandle, reason: string) => void;\n session_error: (session: SessionHandle, error: string) => void;\n login_required: (\n session: SessionHandle,\n instructions?: string,\n url?: string\n ) => void;\n auth_required: (session: SessionHandle, info: AuthRequiredInfo) => void;\n blocking_prompt: (\n session: SessionHandle,\n promptInfo: BlockingPromptInfo,\n autoResponded: boolean\n ) => void;\n message: (message: SessionMessage) => void;\n question: (session: SessionHandle, question: string) => void;\n stall_detected: (\n session: SessionHandle,\n recentOutput: string,\n stallDurationMs: number\n ) => void;\n session_status_changed: (session: SessionHandle) => void;\n task_complete: (session: SessionHandle) => void;\n tool_running: (session: SessionHandle, info: ToolRunningInfo) => void;\n}\n\nexport class PTYManager extends EventEmitter {\n private sessions: Map<string, PTYSession> = new Map();\n private outputLogs: Map<string, string[]> = new Map();\n private maxLogLines: number;\n private logger: Logger;\n public readonly adapters: AdapterRegistry;\n\n // Stall detection config\n private _stallDetectionEnabled: boolean;\n private _stallTimeoutMs: number;\n private _onStallClassify?: (\n sessionId: string,\n recentOutput: string,\n stallDurationMs: number\n ) => Promise<StallClassification | null>;\n\n constructor(config: PTYManagerConfig = {}) {\n super();\n this.adapters = new AdapterRegistry();\n this.logger = config.logger || consoleLogger;\n this.maxLogLines = config.maxLogLines || 1000;\n this._stallDetectionEnabled = config.stallDetectionEnabled ?? false;\n this._stallTimeoutMs = config.stallTimeoutMs ?? 8000;\n this._onStallClassify = config.onStallClassify;\n }\n\n /**\n * Register a CLI adapter\n */\n registerAdapter(adapter: CLIAdapter): void {\n this.adapters.register(adapter);\n }\n\n /**\n * Spawn a new PTY session\n */\n async spawn(config: SpawnConfig): Promise<SessionHandle> {\n // Get adapter for this type\n const adapter = this.adapters.get(config.type);\n if (!adapter) {\n throw new Error(\n `No adapter found for type: ${config.type}. Registered adapters: ${this.adapters.list().join(', ') || 'none'}`\n );\n }\n\n // Check if ID already exists\n if (config.id && this.sessions.has(config.id)) {\n throw new Error(`Session with ID ${config.id} already exists`);\n }\n\n this.logger.info(\n { type: config.type, name: config.name },\n 'Spawning session'\n );\n\n // Create session\n const session = new PTYSession(\n adapter,\n config,\n this.logger,\n this._stallDetectionEnabled,\n this._stallTimeoutMs\n );\n\n // Set up event forwarding\n this.setupSessionEvents(session);\n\n // Store session\n this.sessions.set(session.id, session);\n this.outputLogs.set(session.id, []);\n\n // Start the session\n await session.start();\n\n const handle = session.toHandle();\n this.emit('session_started', handle);\n\n return handle;\n }\n\n /**\n * Set up event handlers for a session\n */\n private setupSessionEvents(session: PTYSession): void {\n session.on('output', (data: string) => {\n // Store in log buffer\n const logs = this.outputLogs.get(session.id) || [];\n const lines = data.split('\\n');\n logs.push(...lines);\n\n // Trim to max lines\n while (logs.length > this.maxLogLines) {\n logs.shift();\n }\n this.outputLogs.set(session.id, logs);\n });\n\n session.on('ready', () => {\n this.emit('session_ready', session.toHandle());\n });\n\n session.on('login_required', (instructions?: string, url?: string) => {\n this.emit('login_required', session.toHandle(), instructions, url);\n });\n\n session.on('auth_required', (info: AuthRequiredInfo) => {\n this.emit('auth_required', session.toHandle(), info);\n });\n\n session.on(\n 'blocking_prompt',\n (promptInfo: BlockingPromptInfo, autoResponded: boolean) => {\n this.emit(\n 'blocking_prompt',\n session.toHandle(),\n promptInfo,\n autoResponded\n );\n }\n );\n\n session.on('message', (message: SessionMessage) => {\n this.emit('message', message);\n });\n\n session.on('question', (question: string) => {\n this.emit('question', session.toHandle(), question);\n });\n\n session.on('exit', (code: number) => {\n const reason = code === 0 ? 'normal exit' : `exit code ${code}`;\n this.emit('session_stopped', session.toHandle(), reason);\n });\n\n session.on('error', (error: Error) => {\n this.emit('session_error', session.toHandle(), error.message);\n });\n\n session.on('status_changed', () => {\n // Refresh the handle so the parent sees the updated status\n this.emit('session_status_changed', session.toHandle());\n });\n\n session.on('task_complete', () => {\n this.emit('task_complete', session.toHandle());\n });\n\n session.on('tool_running', (info: ToolRunningInfo) => {\n this.emit('tool_running', session.toHandle(), info);\n });\n\n session.on(\n 'stall_detected',\n (recentOutput: string, stallDurationMs: number) => {\n const handle = session.toHandle();\n this.emit('stall_detected', handle, recentOutput, stallDurationMs);\n\n // Call external classifier if configured\n if (this._onStallClassify) {\n // Sanitize output before passing to LLM classifier to mitigate prompt injection.\n // Truncate to 1500 chars and strip sequences that could be used to manipulate the classifier.\n const sanitized = recentOutput\n .slice(-1500)\n .replace(\n /\\b(ignore|disregard|forget)\\s+(all\\s+)?(previous|above|prior)\\s+(instructions?|prompts?|rules?)\\b/gi,\n '[REDACTED]'\n )\n .replace(\n /\\b(you\\s+are|act\\s+as|pretend\\s+to\\s+be|you\\s+must|system\\s*:)\\b/gi,\n '[REDACTED]'\n );\n this._onStallClassify(session.id, sanitized, stallDurationMs)\n .then((classification) => {\n session.handleStallClassification(classification);\n })\n .catch((err) => {\n this.logger.error(\n { sessionId: session.id, error: err },\n 'Stall classification callback failed'\n );\n // Reset timer so detection continues\n session.handleStallClassification(null);\n });\n }\n }\n );\n }\n\n /**\n * Stop a session\n */\n async stop(sessionId: string, options?: StopOptions): Promise<void> {\n const session = this.sessions.get(sessionId);\n if (!session) {\n throw new Error(`Session not found: ${sessionId}`);\n }\n\n this.logger.info({ sessionId, force: options?.force }, 'Stopping session');\n\n const timeout = options?.timeout || 5000;\n\n return new Promise((resolve) => {\n const timer = setTimeout(() => {\n // Force kill if graceful shutdown times out\n session.kill('SIGKILL');\n resolve();\n }, timeout);\n\n session.once('exit', () => {\n clearTimeout(timer);\n session.removeAllListeners();\n this.sessions.delete(sessionId);\n this.outputLogs.delete(sessionId);\n resolve();\n });\n\n // Send graceful signal\n session.kill(options?.force ? 'SIGKILL' : 'SIGTERM');\n });\n }\n\n /**\n * Stop all sessions\n */\n async stopAll(options?: StopOptions): Promise<void> {\n const stopPromises = Array.from(this.sessions.keys()).map((id) =>\n this.stop(id, options).catch((err) => {\n this.logger.warn(\n { sessionId: id, error: err },\n 'Error stopping session'\n );\n })\n );\n\n await Promise.all(stopPromises);\n }\n\n /**\n * Get a session by ID\n */\n get(sessionId: string): SessionHandle | null {\n const session = this.sessions.get(sessionId);\n return session ? session.toHandle() : null;\n }\n\n /**\n * List all sessions\n */\n list(filter?: SessionFilter): SessionHandle[] {\n const handles: SessionHandle[] = [];\n\n for (const session of this.sessions.values()) {\n const handle = session.toHandle();\n\n // Apply filters\n if (filter) {\n if (filter.status) {\n const statuses = Array.isArray(filter.status)\n ? filter.status\n : [filter.status];\n if (!statuses.includes(handle.status)) continue;\n }\n\n if (filter.type) {\n const types = Array.isArray(filter.type)\n ? filter.type\n : [filter.type];\n if (!types.includes(handle.type)) continue;\n }\n }\n\n handles.push(handle);\n }\n\n return handles;\n }\n\n /**\n * Send a message to a session\n */\n send(sessionId: string, message: string): SessionMessage {\n const session = this.sessions.get(sessionId);\n if (!session) {\n throw new Error(`Session not found: ${sessionId}`);\n }\n\n return session.send(message);\n }\n\n /**\n * Get logs for a session\n */\n async *logs(sessionId: string, options?: LogOptions): AsyncIterable<string> {\n const logBuffer = this.outputLogs.get(sessionId);\n if (!logBuffer) {\n throw new Error(`Session not found: ${sessionId}`);\n }\n\n const lines = options?.tail ? logBuffer.slice(-options.tail) : logBuffer;\n\n for (const line of lines) {\n yield line;\n }\n }\n\n /**\n * Get metrics for a session\n */\n metrics(\n sessionId: string\n ): { uptime?: number; messageCount?: number } | null {\n const session = this.sessions.get(sessionId);\n if (!session) {\n return null;\n }\n\n const handle = session.toHandle();\n const uptime = handle.startedAt\n ? Math.floor((Date.now() - handle.startedAt.getTime()) / 1000)\n : undefined;\n\n return { uptime };\n }\n\n /**\n * Shutdown manager and stop all sessions\n */\n async shutdown(): Promise<void> {\n this.logger.info(\n { count: this.sessions.size },\n 'Shutting down all sessions'\n );\n\n await this.stopAll({ timeout: 3000 });\n\n this.sessions.clear();\n this.outputLogs.clear();\n }\n\n /**\n * Get count of sessions by status\n */\n getStatusCounts(): Record<SessionStatus, number> {\n const counts: Record<SessionStatus, number> = {\n pending: 0,\n starting: 0,\n authenticating: 0,\n ready: 0,\n busy: 0,\n stopping: 0,\n stopped: 0,\n error: 0,\n };\n\n for (const session of this.sessions.values()) {\n counts[session.status]++;\n }\n\n return counts;\n }\n\n /**\n * Attach to a session's terminal for raw I/O streaming\n */\n attachTerminal(sessionId: string): TerminalAttachment | null {\n const session = this.sessions.get(sessionId);\n if (!session) {\n return null;\n }\n\n return {\n /**\n * Subscribe to raw terminal output\n * Returns an unsubscribe function\n */\n onData: (callback: (data: string) => void) => {\n session.on('output', callback);\n return () => session.off('output', callback);\n },\n\n /**\n * Write raw data to terminal (no formatting applied)\n */\n write: (data: string) => {\n session.writeRaw(data);\n },\n\n /**\n * Resize the terminal\n */\n resize: (cols: number, rows: number) => {\n session.resize(cols, rows);\n },\n };\n }\n\n /**\n * Check if a session exists\n */\n has(sessionId: string): boolean {\n return this.sessions.has(sessionId);\n }\n\n /**\n * Get the underlying PTYSession (for advanced use)\n */\n getSession(sessionId: string): PTYSession | undefined {\n return this.sessions.get(sessionId);\n }\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Stall Detection Configuration\n // ─────────────────────────────────────────────────────────────────────────────\n\n /**\n * Configure stall detection at runtime.\n * Affects newly spawned sessions only — existing sessions keep their config.\n */\n configureStallDetection(\n enabled: boolean,\n timeoutMs?: number,\n classify?: (\n sessionId: string,\n recentOutput: string,\n stallDurationMs: number\n ) => Promise<StallClassification | null>\n ): void {\n this._stallDetectionEnabled = enabled;\n if (timeoutMs !== undefined) {\n this._stallTimeoutMs = timeoutMs;\n }\n if (classify !== undefined) {\n this._onStallClassify = classify;\n }\n }\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Runtime Auto-Response Rules API\n // ─────────────────────────────────────────────────────────────────────────────\n\n /**\n * Add an auto-response rule to a session.\n * Session rules are checked before adapter rules.\n */\n addAutoResponseRule(sessionId: string, rule: AutoResponseRule): void {\n const session = this.sessions.get(sessionId);\n if (!session) {\n throw new Error(`Session not found: ${sessionId}`);\n }\n session.addAutoResponseRule(rule);\n }\n\n /**\n * Remove an auto-response rule from a session by pattern.\n * Returns true if a rule was removed.\n */\n removeAutoResponseRule(sessionId: string, pattern: RegExp): boolean {\n const session = this.sessions.get(sessionId);\n if (!session) {\n throw new Error(`Session not found: ${sessionId}`);\n }\n return session.removeAutoResponseRule(pattern);\n }\n\n /**\n * Set all auto-response rules for a session, replacing existing ones.\n */\n setAutoResponseRules(sessionId: string, rules: AutoResponseRule[]): void {\n const session = this.sessions.get(sessionId);\n if (!session) {\n throw new Error(`Session not found: ${sessionId}`);\n }\n session.setAutoResponseRules(rules);\n }\n\n /**\n * Get all auto-response rules for a session.\n */\n getAutoResponseRules(sessionId: string): AutoResponseRule[] {\n const session = this.sessions.get(sessionId);\n if (!session) {\n throw new Error(`Session not found: ${sessionId}`);\n }\n return session.getAutoResponseRules();\n }\n\n /**\n * Clear all auto-response rules for a session.\n */\n clearAutoResponseRules(sessionId: string): void {\n const session = this.sessions.get(sessionId);\n if (!session) {\n throw new Error(`Session not found: ${sessionId}`);\n }\n session.clearAutoResponseRules();\n }\n}\n","/**\n * Console-based logger fallback.\n *\n * Shared between PTYManager and PTYSession to avoid duplication.\n * Supports both pino-style (context, message) and printf-style (message, context) calls.\n */\n\nimport type { Logger } from './types';\n\nexport const consoleLogger: Logger = {\n debug: (...args: unknown[]) => {\n if (typeof args[0] === 'string') {\n console.debug(args[0], args[1]);\n } else {\n console.debug(args[1], args[0]);\n }\n },\n info: (...args: unknown[]) => {\n if (typeof args[0] === 'string') {\n console.info(args[0], args[1]);\n } else {\n console.info(args[1], args[0]);\n }\n },\n warn: (...args: unknown[]) => {\n if (typeof args[0] === 'string') {\n console.warn(args[0], args[1]);\n } else {\n console.warn(args[1], args[0]);\n }\n },\n error: (...args: unknown[]) => {\n if (typeof args[0] === 'string') {\n console.error(args[0], args[1]);\n } else {\n console.error(args[1], args[0]);\n }\n },\n};\n","/**\n * PTY Session\n *\n * Manages a single pseudo-terminal session for a CLI tool.\n */\n\nimport { randomUUID } from 'node:crypto';\nimport { EventEmitter } from 'node:events';\nimport type * as ptyModule from 'node-pty';\nimport type { CLIAdapter } from './adapters/adapter-interface';\nimport { ensurePty } from './ensure-pty';\nimport { consoleLogger } from './logger';\nimport type {\n AuthRequiredInfo,\n AutoResponseRule,\n BlockingPromptInfo,\n Logger,\n LoginDetection,\n SessionHandle,\n SessionMessage,\n SessionStatus,\n SpawnConfig,\n StallClassification,\n ToolRunningInfo,\n} from './types';\n\n// Lazy-load node-pty to avoid issues in environments where it's not installed\nlet ptyCache: typeof ptyModule | null = null;\nfunction loadPty(): typeof ptyModule {\n if (!ptyCache) {\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n ptyCache = require('node-pty') as typeof ptyModule;\n } catch {\n throw new Error(\n 'node-pty is required but not installed. Run: npm install node-pty'\n );\n }\n }\n return ptyCache!;\n}\n\nexport interface PTYSessionEvents {\n output: (data: string) => void;\n ready: () => void;\n login_required: (instructions?: string, url?: string) => void;\n auth_required: (info: AuthRequiredInfo) => void;\n blocking_prompt: (prompt: BlockingPromptInfo, autoResponded: boolean) => void;\n message: (message: SessionMessage) => void;\n question: (question: string) => void;\n exit: (code: number) => void;\n error: (error: Error) => void;\n stall_detected: (recentOutput: string, stallDurationMs: number) => void;\n status_changed: (status: SessionStatus) => void;\n task_complete: () => void;\n tool_running: (info: ToolRunningInfo) => void;\n}\n\n/**\n * Generate a unique ID\n */\nfunction generateId(): string {\n return `pty-${Date.now()}-${randomUUID().slice(0, 8)}`;\n}\n\n/**\n * Special key mappings to escape sequences\n *\n * Modifier codes for arrows/function keys:\n * 2 = Shift, 3 = Alt, 4 = Shift+Alt, 5 = Ctrl, 6 = Ctrl+Shift, 7 = Ctrl+Alt, 8 = Ctrl+Alt+Shift\n */\nexport const SPECIAL_KEYS: Record<string, string> = {\n // Control keys (Ctrl+letter = ASCII control code)\n 'ctrl+a': '\\x01',\n 'ctrl+b': '\\x02',\n 'ctrl+c': '\\x03',\n 'ctrl+d': '\\x04',\n 'ctrl+e': '\\x05',\n 'ctrl+f': '\\x06',\n 'ctrl+g': '\\x07',\n 'ctrl+h': '\\x08',\n 'ctrl+i': '\\x09',\n 'ctrl+j': '\\x0a',\n 'ctrl+k': '\\x0b',\n 'ctrl+l': '\\x0c',\n 'ctrl+m': '\\x0d',\n 'ctrl+n': '\\x0e',\n 'ctrl+o': '\\x0f',\n 'ctrl+p': '\\x10',\n 'ctrl+q': '\\x11',\n 'ctrl+r': '\\x12',\n 'ctrl+s': '\\x13',\n 'ctrl+t': '\\x14',\n 'ctrl+u': '\\x15',\n 'ctrl+v': '\\x16',\n 'ctrl+w': '\\x17',\n 'ctrl+x': '\\x18',\n 'ctrl+y': '\\x19',\n 'ctrl+z': '\\x1a',\n 'ctrl+[': '\\x1b',\n 'ctrl+\\\\': '\\x1c',\n 'ctrl+]': '\\x1d',\n 'ctrl+^': '\\x1e',\n 'ctrl+_': '\\x1f',\n\n // Alt+letter (Meta key = ESC + letter)\n 'alt+a': '\\x1ba',\n 'alt+b': '\\x1bb',\n 'alt+c': '\\x1bc',\n 'alt+d': '\\x1bd',\n 'alt+e': '\\x1be',\n 'alt+f': '\\x1bf',\n 'alt+g': '\\x1bg',\n 'alt+h': '\\x1bh',\n 'alt+i': '\\x1bi',\n 'alt+j': '\\x1bj',\n 'alt+k': '\\x1bk',\n 'alt+l': '\\x1bl',\n 'alt+m': '\\x1bm',\n 'alt+n': '\\x1bn',\n 'alt+o': '\\x1bo',\n 'alt+p': '\\x1bp',\n 'alt+q': '\\x1bq',\n 'alt+r': '\\x1br',\n 'alt+s': '\\x1bs',\n 'alt+t': '\\x1bt',\n 'alt+u': '\\x1bu',\n 'alt+v': '\\x1bv',\n 'alt+w': '\\x1bw',\n 'alt+x': '\\x1bx',\n 'alt+y': '\\x1by',\n 'alt+z': '\\x1bz',\n 'alt+backspace': '\\x1b\\x7f', // Delete word backward\n\n // Navigation - plain\n up: '\\x1b[A',\n down: '\\x1b[B',\n right: '\\x1b[C',\n left: '\\x1b[D',\n home: '\\x1b[H',\n end: '\\x1b[F',\n pageup: '\\x1b[5~',\n pagedown: '\\x1b[6~',\n\n // Navigation - with Shift (modifier 2)\n 'shift+up': '\\x1b[1;2A',\n 'shift+down': '\\x1b[1;2B',\n 'shift+right': '\\x1b[1;2C',\n 'shift+left': '\\x1b[1;2D',\n 'shift+home': '\\x1b[1;2H',\n 'shift+end': '\\x1b[1;2F',\n 'shift+pageup': '\\x1b[5;2~',\n 'shift+pagedown': '\\x1b[6;2~',\n\n // Navigation - with Alt (modifier 3)\n 'alt+up': '\\x1b[1;3A',\n 'alt+down': '\\x1b[1;3B',\n 'alt+right': '\\x1b[1;3C', // Forward word\n 'alt+left': '\\x1b[1;3D', // Backward word\n\n // Navigation - with Ctrl (modifier 5)\n 'ctrl+up': '\\x1b[1;5A',\n 'ctrl+down': '\\x1b[1;5B',\n 'ctrl+right': '\\x1b[1;5C', // Forward word\n 'ctrl+left': '\\x1b[1;5D', // Backward word\n 'ctrl+home': '\\x1b[1;5H',\n 'ctrl+end': '\\x1b[1;5F',\n\n // Navigation - with Ctrl+Shift (modifier 6) - select word\n 'ctrl+shift+up': '\\x1b[1;6A',\n 'ctrl+shift+down': '\\x1b[1;6B',\n 'ctrl+shift+right': '\\x1b[1;6C',\n 'ctrl+shift+left': '\\x1b[1;6D',\n 'ctrl+shift+home': '\\x1b[1;6H',\n 'ctrl+shift+end': '\\x1b[1;6F',\n\n // Navigation - with Shift+Alt (modifier 4)\n 'shift+alt+up': '\\x1b[1;4A',\n 'shift+alt+down': '\\x1b[1;4B',\n 'shift+alt+right': '\\x1b[1;4C',\n 'shift+alt+left': '\\x1b[1;4D',\n\n // Editing\n enter: '\\r',\n return: '\\r',\n tab: '\\t',\n 'shift+tab': '\\x1b[Z', // Reverse tab\n backspace: '\\x7f',\n delete: '\\x1b[3~',\n 'shift+delete': '\\x1b[3;2~',\n 'ctrl+delete': '\\x1b[3;5~', // Delete word forward\n insert: '\\x1b[2~',\n escape: '\\x1b',\n esc: '\\x1b',\n space: ' ',\n\n // Function keys - plain\n f1: '\\x1bOP',\n f2: '\\x1bOQ',\n f3: '\\x1bOR',\n f4: '\\x1bOS',\n f5: '\\x1b[15~',\n f6: '\\x1b[17~',\n f7: '\\x1b[18~',\n f8: '\\x1b[19~',\n f9: '\\x1b[20~',\n f10: '\\x1b[21~',\n f11: '\\x1b[23~',\n f12: '\\x1b[24~',\n\n // Function keys - with Shift (modifier 2)\n 'shift+f1': '\\x1b[1;2P',\n 'shift+f2': '\\x1b[1;2Q',\n 'shift+f3': '\\x1b[1;2R',\n 'shift+f4': '\\x1b[1;2S',\n 'shift+f5': '\\x1b[15;2~',\n 'shift+f6': '\\x1b[17;2~',\n 'shift+f7': '\\x1b[18;2~',\n 'shift+f8': '\\x1b[19;2~',\n 'shift+f9': '\\x1b[20;2~',\n 'shift+f10': '\\x1b[21;2~',\n 'shift+f11': '\\x1b[23;2~',\n 'shift+f12': '\\x1b[24;2~',\n\n // Function keys - with Ctrl (modifier 5)\n 'ctrl+f1': '\\x1b[1;5P',\n 'ctrl+f2': '\\x1b[1;5Q',\n 'ctrl+f3': '\\x1b[1;5R',\n 'ctrl+f4': '\\x1b[1;5S',\n 'ctrl+f5': '\\x1b[15;5~',\n 'ctrl+f6': '\\x1b[17;5~',\n 'ctrl+f7': '\\x1b[18;5~',\n 'ctrl+f8': '\\x1b[19;5~',\n 'ctrl+f9': '\\x1b[20;5~',\n 'ctrl+f10': '\\x1b[21;5~',\n 'ctrl+f11': '\\x1b[23;5~',\n 'ctrl+f12': '\\x1b[24;5~',\n};\n\n/**\n * Bracketed paste mode escape sequences\n */\nconst BRACKETED_PASTE_START = '\\x1b[200~';\nconst BRACKETED_PASTE_END = '\\x1b[201~';\n\nexport class PTYSession extends EventEmitter {\n private ptyProcess: ptyModule.IPty | null = null;\n private outputBuffer: string = '';\n private _status: SessionStatus = 'pending';\n private _startedAt: Date | null = null;\n private _lastActivityAt: Date | null = null;\n private messageCounter: number = 0;\n private logger: Logger;\n private sessionRules: AutoResponseRule[] = [];\n private _firedOnceRules: Set<string> = new Set();\n private _lastBlockingPromptHash: string | null = null;\n private _lastBlockingPromptEmitAt = 0;\n private static readonly BLOCKING_PROMPT_DEBOUNCE_MS = 250;\n private _ruleOverrides: Map<string, Partial<AutoResponseRule>> = new Map();\n private _disabledRulePatterns: Set<string> = new Set();\n\n // Stall detection\n private _stallTimer: ReturnType<typeof setTimeout> | null = null;\n private _stallTimeoutMs: number;\n private _stallDetectionEnabled: boolean;\n private _lastStallHash: string | null = null;\n private _stallStartedAt: number | null = null;\n private _lastContentHash: string | null = null;\n private _stallBackoffMs: number = 0; // Initialized in constructor from _stallTimeoutMs\n private static readonly MAX_STALL_BACKOFF_MS = 30_000;\n private _stallEmissionCount: number = 0;\n private static readonly MAX_STALL_EMISSIONS = 5;\n\n // Task completion detection (idle detection when busy)\n private _taskCompleteTimer: ReturnType<typeof setTimeout> | null = null;\n private _taskCompletePending = false;\n private static readonly TASK_COMPLETE_DEBOUNCE_MS = 1500;\n\n // Ready detection settle delay — defers session_ready until output goes quiet\n private _readySettleTimer: ReturnType<typeof setTimeout> | null = null;\n private _readySettlePending = false;\n\n // Tool running deduplication — only emit when tool changes\n private _lastToolRunningName: string | null = null;\n\n // Deferred output processing — prevents node-pty's synchronous data\n // delivery from starving the event loop (timers, I/O callbacks, etc.)\n private _processScheduled = false;\n\n // Output buffer cap — prevents unbounded growth during long tasks\n private static readonly MAX_OUTPUT_BUFFER = 100_000; // 100 KB\n\n public readonly id: string;\n public readonly config: SpawnConfig;\n\n constructor(\n private adapter: CLIAdapter,\n config: SpawnConfig,\n logger?: Logger,\n stallDetectionEnabled?: boolean,\n defaultStallTimeoutMs?: number\n ) {\n super();\n this.id = config.id || generateId();\n this.config = { ...config, id: this.id };\n this.logger = logger || consoleLogger;\n this._stallDetectionEnabled = stallDetectionEnabled ?? false;\n this._stallTimeoutMs =\n config.stallTimeoutMs ?? defaultStallTimeoutMs ?? 8000;\n this._stallBackoffMs = this._stallTimeoutMs;\n\n // Process rule overrides from spawn config\n if (config.ruleOverrides) {\n for (const [key, value] of Object.entries(config.ruleOverrides)) {\n if (value === null) {\n this._disabledRulePatterns.add(key);\n } else {\n this._ruleOverrides.set(key, value);\n }\n }\n }\n }\n\n get status(): SessionStatus {\n return this._status;\n }\n\n get pid(): number | undefined {\n return this.ptyProcess?.pid;\n }\n\n get startedAt(): Date | undefined {\n return this._startedAt ?? undefined;\n }\n\n get lastActivityAt(): Date | undefined {\n return this._lastActivityAt ?? undefined;\n }\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Runtime Auto-Response Rules API\n // ─────────────────────────────────────────────────────────────────────────────\n\n /**\n * Add an auto-response rule to this session.\n * Session rules are checked before adapter rules.\n */\n addAutoResponseRule(rule: AutoResponseRule): void {\n // Check for duplicate pattern\n const existingIndex = this.sessionRules.findIndex(\n (r) =>\n r.pattern.source === rule.pattern.source &&\n r.pattern.flags === rule.pattern.flags\n );\n\n if (existingIndex >= 0) {\n // Replace existing rule with same pattern\n this.sessionRules[existingIndex] = rule;\n this.logger.debug(\n { sessionId: this.id, pattern: rule.pattern.source, type: rule.type },\n 'Replaced existing auto-response rule'\n );\n } else {\n this.sessionRules.push(rule);\n this.logger.debug(\n { sessionId: this.id, pattern: rule.pattern.source, type: rule.type },\n 'Added auto-response rule'\n );\n }\n }\n\n /**\n * Remove an auto-response rule by pattern.\n * Returns true if a rule was removed.\n */\n removeAutoResponseRule(pattern: RegExp): boolean {\n const initialLength = this.sessionRules.length;\n this.sessionRules = this.sessionRules.filter(\n (r) =>\n !(\n r.pattern.source === pattern.source &&\n r.pattern.flags === pattern.flags\n )\n );\n\n const removed = this.sessionRules.length < initialLength;\n if (removed) {\n this.logger.debug(\n { sessionId: this.id, pattern: pattern.source },\n 'Removed auto-response rule'\n );\n }\n return removed;\n }\n\n /**\n * Set all session auto-response rules, replacing existing ones.\n */\n setAutoResponseRules(rules: AutoResponseRule[]): void {\n this.sessionRules = [...rules];\n this.logger.debug(\n { sessionId: this.id, count: rules.length },\n 'Set auto-response rules'\n );\n }\n\n /**\n * Get all session auto-response rules.\n */\n getAutoResponseRules(): AutoResponseRule[] {\n return [...this.sessionRules];\n }\n\n /**\n * Clear all session auto-response rules.\n */\n clearAutoResponseRules(): void {\n this.sessionRules = [];\n this.logger.debug({ sessionId: this.id }, 'Cleared auto-response rules');\n }\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Stall Detection\n // ─────────────────────────────────────────────────────────────────────────────\n\n /**\n * Start or reset the stall detection timer.\n * Active when status is \"busy\" or \"authenticating\" and stall detection is enabled.\n *\n * Content-based: hashes the ANSI-stripped buffer tail and only resets the\n * timer when visible content actually changes. This prevents TUI spinners\n * (which produce new ANSI sequences but no new visible text) from endlessly\n * resetting the timer.\n */\n private resetStallTimer(): void {\n if (\n !this._stallDetectionEnabled ||\n (this._status !== 'busy' && this._status !== 'authenticating')\n ) {\n this.clearStallTimer();\n return;\n }\n\n // Strip the full buffer FIRST, then slice the tail of the normalized text.\n // Stripping before slicing ensures the 500-char window covers the same\n // visible content regardless of how many raw escape sequences surround it.\n // (Slicing raw first caused different cursor-positioning codes at the\n // truncation boundary to produce different stripped text each TUI redraw.)\n const stripped = this.stripAnsiForStall(this.outputBuffer).trim();\n const visible = this.stripAnsiForClassifier(this.outputBuffer).trim();\n const tail = stripped.slice(-500);\n const fallbackTail = visible.slice(-500);\n const hash = this.simpleHash(tail || fallbackTail);\n\n if (hash === this._lastContentHash) {\n // Content unchanged (e.g., spinner animation) — don't reset the timer\n return;\n }\n this._lastContentHash = hash;\n this._stallEmissionCount = 0;\n\n // Content changed — clear and restart the timer, reset backoff\n if (this._stallTimer) {\n clearTimeout(this._stallTimer);\n this._stallTimer = null;\n }\n this._stallStartedAt = Date.now();\n this._lastStallHash = null; // New content, reset dedup hash for emissions\n this._stallBackoffMs = this._stallTimeoutMs; // Reset backoff on new real content\n\n this._stallTimer = setTimeout(() => {\n this.onStallTimerFired();\n }, this._stallTimeoutMs);\n }\n\n /**\n * Clear the stall detection timer.\n */\n private clearStallTimer(): void {\n if (this._stallTimer) {\n clearTimeout(this._stallTimer);\n this._stallTimer = null;\n }\n this._stallStartedAt = null;\n this._lastContentHash = null;\n this._stallBackoffMs = this._stallTimeoutMs;\n this._stallEmissionCount = 0;\n }\n\n /**\n * Called when the stall timer fires (no output for stallTimeoutMs).\n */\n private onStallTimerFired(): void {\n if (this._status !== 'busy' && this._status !== 'authenticating') {\n return; // Status changed while timer was running\n }\n\n // Fast path: try adapter-level task completion detection first.\n // This must run BEFORE detectLoading because the buffer may contain\n // both stale loading patterns (e.g. \"esc to interrupt\" from the spinner)\n // and a completion signal (e.g. \"Baked for 2s\" + prompt). Task completion\n // is the more specific/certain signal and should take priority.\n if (\n this._status === 'busy' &&\n this.adapter.detectTaskComplete?.(this.outputBuffer)\n ) {\n this._status = 'ready';\n this._lastBlockingPromptHash = null;\n this._lastBlockingPromptEmitAt = 0;\n this.outputBuffer = '';\n this.clearStallTimer();\n this.emit('status_changed', 'ready');\n this.emit('task_complete');\n this.logger.info(\n { sessionId: this.id },\n 'Task complete (adapter fast-path) — agent returned to idle prompt'\n );\n return;\n }\n\n // Loading suppression: if the adapter detects an active loading indicator\n // (thinking spinner, \"esc to interrupt\", \"Reading N files\", etc.),\n // the agent is provably working — suppress stall detection and reschedule.\n if (this.adapter.detectLoading?.(this.outputBuffer)) {\n this.logger.debug(\n { sessionId: this.id },\n 'Loading pattern detected — suppressing stall emission'\n );\n this._stallTimer = setTimeout(\n () => this.onStallTimerFired(),\n this._stallBackoffMs\n );\n return;\n }\n\n // Tool running suppression: if the adapter detects an external tool/process\n // (browser, bash, node, python, etc.), the agent is working through that tool.\n // Suppress stall detection and emit tool_running event for the UI.\n const toolInfo = this.adapter.detectToolRunning?.(this.outputBuffer);\n if (toolInfo) {\n if (toolInfo.toolName !== this._lastToolRunningName) {\n this._lastToolRunningName = toolInfo.toolName;\n this.emit('tool_running', toolInfo);\n }\n this.logger.debug(\n { sessionId: this.id, tool: toolInfo.toolName },\n 'Tool running — suppressing stall emission'\n );\n this._stallTimer = setTimeout(\n () => this.onStallTimerFired(),\n this._stallBackoffMs\n );\n return;\n }\n // Clear tool running state when no tool detected\n if (this._lastToolRunningName) {\n this._lastToolRunningName = null;\n }\n\n // Compute dedup hash from last 500 chars of outputBuffer\n const tail = this.outputBuffer.slice(-500);\n const hash = this.simpleHash(tail);\n\n if (hash === this._lastStallHash) {\n // Buffer tail unchanged since last stall emission — don't re-emit.\n // Schedule another check with current backoff.\n this._stallTimer = setTimeout(\n () => this.onStallTimerFired(),\n this._stallBackoffMs\n );\n return;\n }\n this._lastStallHash = hash;\n\n this._stallEmissionCount++;\n if (this._stallEmissionCount > PTYSession.MAX_STALL_EMISSIONS) {\n this.logger.warn(\n { sessionId: this.id, count: this._stallEmissionCount },\n 'Max stall emissions reached — suspending stall detection for this task'\n );\n this.clearStallTimer();\n return;\n }\n\n // Compute recent output for classifier: last 2000 chars, ANSI-stripped\n // while preserving visible symbols/text used by TUI CLIs.\n const recentRaw = this.outputBuffer.slice(-2000);\n const recentOutput = this.stripAnsiForClassifier(recentRaw).trim();\n\n const stallDurationMs = this._stallStartedAt\n ? Date.now() - this._stallStartedAt\n : this._stallTimeoutMs;\n\n this.logger.debug(\n {\n sessionId: this.id,\n stallDurationMs,\n bufferTailLength: tail.length,\n recentOutputLength: recentOutput.length,\n recentOutputHash: this.simpleHash(recentOutput.slice(-500)),\n },\n 'Stall detected'\n );\n\n this.emit('stall_detected', recentOutput, stallDurationMs);\n\n // Schedule next check with current backoff\n this._stallTimer = setTimeout(\n () => this.onStallTimerFired(),\n this._stallBackoffMs\n );\n }\n\n /**\n * Promise-based delay helper.\n */\n private delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n\n /**\n * Simple string hash for deduplication.\n */\n private simpleHash(str: string): string {\n let hash = 0;\n for (let i = 0; i < str.length; i++) {\n const char = str.charCodeAt(i);\n hash = (hash << 5) - hash + char;\n hash |= 0;\n }\n return hash.toString(36);\n }\n\n private mapLoginTypeToAuthMethod(\n type: LoginDetection['type'] | undefined\n ): AuthRequiredInfo['method'] {\n switch (type) {\n case 'api_key':\n return 'api_key';\n case 'cli_auth':\n return 'cli_auth';\n case 'device_code':\n return 'device_code';\n case 'oauth':\n case 'browser':\n return 'oauth_browser';\n default:\n return 'unknown';\n }\n }\n\n private extractDeviceCode(text: string): string | undefined {\n const stripped = this.stripAnsiForClassifier(text);\n const explicitMatch = stripped.match(\n /(?:one-time|one time|device)?\\s*code[:\\s]+([A-Z0-9]{3,}(?:-[A-Z0-9]{3,})+)/i\n );\n if (explicitMatch?.[1]) {\n return explicitMatch[1].toUpperCase();\n }\n\n if (!/code/i.test(stripped)) {\n return undefined;\n }\n const fallbackMatch = stripped.match(\n /\\b([A-Z0-9]{3,}(?:-[A-Z0-9]{3,})+)\\b/\n );\n return fallbackMatch?.[1]?.toUpperCase();\n }\n\n private getPromptSnippet(maxChars = 280): string | undefined {\n const normalized = this.stripAnsiForClassifier(this.outputBuffer)\n .replace(/\\s+/g, ' ')\n .trim();\n if (!normalized) {\n return undefined;\n }\n return normalized.length <= maxChars\n ? normalized\n : normalized.slice(-maxChars);\n }\n\n private emitAuthRequired(details: {\n type?: LoginDetection['type'];\n url?: string;\n deviceCode?: string;\n instructions?: string;\n }): void {\n const info: AuthRequiredInfo = {\n method: this.mapLoginTypeToAuthMethod(details.type),\n url: details.url,\n deviceCode:\n details.deviceCode ?? this.extractDeviceCode(this.outputBuffer),\n instructions: details.instructions,\n promptSnippet: this.getPromptSnippet(),\n };\n\n this.emit('auth_required', info);\n this.emit('login_required', info.instructions, info.url);\n }\n\n /**\n * Strip ANSI codes, cursor movement, box-drawing, and spinner characters.\n * Used for stall detection hashing and auto-response pattern matching.\n *\n * Cursor movement codes are replaced with spaces (not removed) to preserve\n * word boundaries — e.g. \"Do\\x1b[5Cyou\" becomes \"Do you\", not \"Doyou\".\n */\n private stripAnsiForStall(str: string): string {\n // Replace ALL cursor movement/positioning codes with a space to preserve word boundaries:\n // \\x1b[nC (forward), \\x1b[nD (back), \\x1b[nA (up), \\x1b[nB (down), \\x1b[nG (column)\n // \\x1b[n;mH and \\x1b[n;mf (absolute positioning)\n // \\x1b[nJ (erase display), \\x1b[nK (erase line) — also space to keep words apart\n // \\x1b[nd (vertical position), \\x1b[nE/nF (cursor next/prev line)\n let result = str.replace(/\\x1b\\[\\d*[CDABGdEF]/g, ' ');\n result = result.replace(/\\x1b\\[\\d*(?:;\\d+)?[Hf]/g, ' ');\n result = result.replace(/\\x1b\\[\\d*[JK]/g, ' ');\n\n // Strip OSC sequences (Operating System Command): \\x1b] ... BEL or \\x1b] ... ST\n // Used for hyperlinks, window titles, Kitty graphics. Payload text would pollute output.\n result = result.replace(\n /\\x1b\\](?:[^\\x07\\x1b]|\\x1b[^\\\\])*(?:\\x07|\\x1b\\\\)/g,\n ''\n );\n\n // Strip DCS sequences (Device Control String): \\x1bP ... ST\n result = result.replace(/\\x1bP(?:[^\\x1b]|\\x1b[^\\\\])*\\x1b\\\\/g, '');\n\n // Strip remaining ANSI escape sequences (SGR, cursor show/hide, etc.)\n // eslint-disable-next-line no-control-regex\n result = result.replace(/\\x1B(?:[@-Z\\\\-_]|\\[[0-?]*[ -/]*[@-~])/g, '');\n\n // Strip bare control characters (backspace, bell, carriage return, etc.)\n // Preserves only \\x09 (tab) and \\x0a (newline).\n // eslint-disable-next-line no-control-regex\n result = result.replace(/[\\x00-\\x08\\x0b-\\x1f\\x7f]/g, '');\n\n // Normalize non-breaking spaces (NBSP \\xa0) to regular spaces\n result = result.replace(/\\xa0/g, ' ');\n\n // Strip TUI box-drawing, spinner, and decorative Unicode characters\n result = result.replace(\n /[│╭╰╮╯─═╌║╔╗╚╝╠╣╦╩╬┌┐└┘├┤┬┴┼●○❯❮▶◀⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏⣾⣽⣻⢿⡿⣟⣯⣷✻✶✳✢⏺←→↑↓⬆⬇◆◇▪▫■□▲△▼▽◈⟨⟩⌘⏎⏏⌫⌦⇧⇪⌥]/g,\n ' '\n );\n\n // Normalize countdown/duration text (e.g., \"8m 17s\" → \"0s\") to prevent\n // TUI countdown timers from resetting the stall timer every second.\n result = result.replace(/\\d+[hms](?:\\s+\\d+[hms])*/g, '0s');\n\n // Collapse multiple spaces\n result = result.replace(/ {2,}/g, ' ');\n\n return result;\n }\n\n /**\n * Less-aggressive ANSI stripping for classifier context.\n * Preserves visible TUI symbols (e.g. ❯, ✻) and durations while removing\n * escape/control sequences so the classifier keeps useful evidence.\n */\n private stripAnsiForClassifier(str: string): string {\n let result = str.replace(/\\x1b\\[\\d*[CDABGdEF]/g, ' ');\n result = result.replace(/\\x1b\\[\\d*(?:;\\d+)?[Hf]/g, ' ');\n result = result.replace(/\\x1b\\[\\d*[JK]/g, ' ');\n\n // Strip OSC and DCS payloads\n result = result.replace(\n /\\x1b\\](?:[^\\x07\\x1b]|\\x1b[^\\\\])*(?:\\x07|\\x1b\\\\)/g,\n ''\n );\n result = result.replace(/\\x1bP(?:[^\\x1b]|\\x1b[^\\\\])*\\x1b\\\\/g, '');\n\n // Strip remaining ANSI escape sequences\n // eslint-disable-next-line no-control-regex\n result = result.replace(/\\x1B(?:[@-Z\\\\-_]|\\[[0-?]*[ -/]*[@-~])/g, '');\n\n // Strip bare control chars except tab/newline\n // eslint-disable-next-line no-control-regex\n result = result.replace(/[\\x00-\\x08\\x0b-\\x1f\\x7f]/g, '');\n\n // Normalize NBSP and collapse spaces\n result = result.replace(/\\xa0/g, ' ');\n result = result.replace(/ {2,}/g, ' ');\n return result;\n }\n\n /**\n * Handle external stall classification result.\n * Called by the manager after onStallClassify resolves.\n */\n handleStallClassification(classification: StallClassification | null): void {\n // Guard against async race — session may no longer be busy/authenticating\n if (this._status !== 'busy' && this._status !== 'authenticating') {\n return;\n }\n\n if (!classification || classification.state === 'still_working') {\n // Exponential backoff — double the check interval (capped at 30s).\n // This avoids hammering the LLM classifier every few seconds when\n // the agent is legitimately working on a long task.\n this._stallBackoffMs = Math.min(\n this._stallBackoffMs * 2,\n PTYSession.MAX_STALL_BACKOFF_MS\n );\n this.logger.debug(\n { sessionId: this.id, nextCheckMs: this._stallBackoffMs },\n 'Still working — backing off stall check interval'\n );\n\n // Force timer restart with backed-off interval, even if buffer\n // content hasn't changed.\n this._lastContentHash = null;\n this._lastStallHash = null; // Reset dedup hash so next fire can re-emit\n if (this._stallTimer) {\n clearTimeout(this._stallTimer);\n this._stallTimer = null;\n }\n this._stallTimer = setTimeout(\n () => this.onStallTimerFired(),\n this._stallBackoffMs\n );\n return;\n }\n\n switch (classification.state) {\n case 'waiting_for_input': {\n const promptInfo: BlockingPromptInfo = {\n type: 'stall_classified',\n prompt: classification.prompt,\n canAutoRespond: !!classification.suggestedResponse,\n };\n\n if (classification.suggestedResponse) {\n this.logger.info(\n { sessionId: this.id, response: classification.suggestedResponse },\n 'Auto-responding to stall-classified prompt'\n );\n const resp = classification.suggestedResponse;\n if (resp.startsWith('keys:')) {\n const keys = resp\n .slice(5)\n .split(',')\n .map((k) => k.trim());\n this.sendKeySequence(keys);\n } else {\n this.writeRaw(`${resp}\\r`);\n }\n this.emit('blocking_prompt', promptInfo, true);\n this.outputBuffer = ''; // Prevent stale text from triggering false detections\n } else {\n this.emit('blocking_prompt', promptInfo, false);\n }\n break;\n }\n\n case 'task_complete':\n this._status = 'ready';\n this._lastBlockingPromptHash = null;\n this._lastBlockingPromptEmitAt = 0;\n this.outputBuffer = '';\n this.clearStallTimer();\n this.emit('ready');\n this.logger.info(\n { sessionId: this.id },\n 'Stall classified as task_complete, transitioning to ready'\n );\n break;\n\n case 'error':\n this.clearStallTimer();\n this.emit(\n 'error',\n new Error(classification.prompt || 'Stall classified as error')\n );\n break;\n }\n }\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Task Completion Detection\n // ─────────────────────────────────────────────────────────────────────────────\n\n /**\n * Schedule a task_complete transition after a debounce period.\n * Uses a settle pattern: each call resets the debounce timer instead of\n * being a no-op when already scheduled. This allows TUI agents that\n * continue rendering decorative output (status bar, update notices) after\n * the prompt to eventually settle, rather than having the timer cancelled\n * by every new data chunk. The callback re-verifies the task-complete\n * signal before transitioning, so stale triggers are safe.\n */\n private scheduleTaskComplete(): void {\n const wasPending = this._taskCompletePending;\n this.traceTaskCompletion('debounce_schedule', {\n wasPending,\n debounceMs: PTYSession.TASK_COMPLETE_DEBOUNCE_MS,\n });\n\n if (this._taskCompleteTimer) {\n clearTimeout(this._taskCompleteTimer);\n }\n this._taskCompletePending = true;\n\n this._taskCompleteTimer = setTimeout(() => {\n this._taskCompleteTimer = null;\n this._taskCompletePending = false;\n\n const signal = this.isTaskCompleteSignal(this.outputBuffer);\n this.traceTaskCompletion('debounce_fire', { signal });\n\n // Re-check: still busy and task-complete signal still present?\n if (this._status !== 'busy') {\n this.traceTaskCompletion('debounce_reject_status', { signal });\n return;\n }\n if (!signal) {\n this.traceTaskCompletion('debounce_reject_signal', { signal });\n return;\n }\n\n this._status = 'ready';\n this._lastBlockingPromptHash = null;\n this._lastBlockingPromptEmitAt = 0;\n this.outputBuffer = '';\n this.clearStallTimer();\n this.emit('status_changed', 'ready');\n this.emit('task_complete');\n this.traceTaskCompletion('transition_ready', { signal: true });\n this.logger.info(\n { sessionId: this.id },\n 'Task complete — agent returned to idle prompt'\n );\n }, PTYSession.TASK_COMPLETE_DEBOUNCE_MS);\n }\n\n /**\n * Adapter-level task completion check with compatibility fallback.\n * Prefer detectTaskComplete() because detectReady() may be broad for TUIs.\n */\n private isTaskCompleteSignal(output: string): boolean {\n if (this.adapter.detectTaskComplete) {\n return this.adapter.detectTaskComplete(output);\n }\n return this.adapter.detectReady(output);\n }\n\n /**\n * Claude-oriented task completion traces for PTY debugging.\n * Disabled by default; enable via config.traceTaskCompletion.\n */\n private traceTaskCompletion(\n event: string,\n ctx: Partial<{\n signal: boolean;\n wasPending: boolean;\n debounceMs: number;\n }> = {}\n ): void {\n if (!this.shouldTraceTaskCompletion()) return;\n\n const output = this.outputBuffer;\n const detectTaskComplete = this.adapter.detectTaskComplete\n ? this.adapter.detectTaskComplete(output)\n : undefined;\n const detectReady = this.adapter.detectReady(output);\n const detectLoading = this.adapter.detectLoading\n ? this.adapter.detectLoading(output)\n : undefined;\n const normalizedTail = this.stripAnsiForStall(output.slice(-280));\n\n this.logger.debug(\n {\n sessionId: this.id,\n adapterType: this.adapter.adapterType,\n event,\n status: this._status,\n taskCompletePending: this._taskCompletePending,\n signal: ctx.signal,\n wasPending: ctx.wasPending,\n debounceMs: ctx.debounceMs,\n detectTaskComplete,\n detectReady,\n detectLoading,\n tailHash: this.simpleHash(normalizedTail),\n tailSnippet: normalizedTail.slice(-140),\n },\n 'Task completion trace'\n );\n }\n\n private shouldTraceTaskCompletion(): boolean {\n return this.config.traceTaskCompletion === true;\n }\n\n /**\n * Cancel a pending task_complete timer (new output arrived that\n * doesn't match the idle prompt, so the agent is still working).\n */\n private cancelTaskComplete(): void {\n if (this._taskCompleteTimer) {\n clearTimeout(this._taskCompleteTimer);\n this._taskCompleteTimer = null;\n }\n this._taskCompletePending = false;\n }\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Ready Detection Settle Delay\n // ─────────────────────────────────────────────────────────────────────────────\n\n /**\n * Schedule or reset the ready-settle timer.\n * Defers emitting session_ready until output goes quiet for readySettleMs\n * after detectReady first matches. This prevents sending input while\n * TUI agents are still rendering (status bar, shortcuts, update notices).\n */\n private scheduleReadySettle(): void {\n this._readySettlePending = true;\n if (this._readySettleTimer) {\n clearTimeout(this._readySettleTimer);\n }\n const settleMs =\n this.config.readySettleMs ?? this.adapter.readySettleMs ?? 100;\n this._readySettleTimer = setTimeout(() => {\n this._readySettleTimer = null;\n this._readySettlePending = false;\n // Re-verify state and ready indicator\n if (this._status !== 'starting' && this._status !== 'authenticating')\n return;\n if (!this.adapter.detectReady(this.outputBuffer)) return;\n this._status = 'ready';\n this._lastBlockingPromptHash = null;\n this._lastBlockingPromptEmitAt = 0;\n this.outputBuffer = '';\n this.clearStallTimer();\n this.emit('ready');\n this.logger.info({ sessionId: this.id }, 'Session ready (after settle)');\n }, settleMs);\n }\n\n /**\n * Cancel a pending ready-settle timer (ready indicator disappeared\n * or session status changed).\n */\n private cancelReadySettle(): void {\n if (this._readySettleTimer) {\n clearTimeout(this._readySettleTimer);\n this._readySettleTimer = null;\n }\n this._readySettlePending = false;\n }\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Lifecycle\n // ─────────────────────────────────────────────────────────────────────────────\n\n /**\n * Start the PTY session\n */\n async start(): Promise<void> {\n if (this.ptyProcess) {\n throw new Error('Session already started');\n }\n\n // Ensure node-pty native addon is usable before first spawn\n ensurePty((msg) => this.logger.info({ sessionId: this.id }, msg));\n\n const nodePty = loadPty();\n\n this._status = 'starting';\n this._startedAt = new Date();\n\n const command = this.adapter.getCommand();\n const args = this.adapter.getArgs(this.config);\n const adapterEnv = this.adapter.getEnv(this.config);\n\n const env = PTYSession.buildSpawnEnv(this.config, adapterEnv);\n\n this.logger.info(\n { sessionId: this.id, command, args: args.join(' ') },\n 'Starting PTY session'\n );\n\n try {\n this.ptyProcess = nodePty.spawn(command, args, {\n name: 'xterm-256color',\n cols: this.config.cols || 120,\n rows: this.config.rows || 40,\n cwd: this.config.workdir || process.cwd(),\n env: env as Record<string, string>,\n });\n\n this.setupEventHandlers();\n\n this.logger.info(\n { sessionId: this.id, pid: this.ptyProcess.pid },\n 'PTY session started'\n );\n } catch (error) {\n this._status = 'error';\n this.logger.error(\n { sessionId: this.id, error },\n 'Failed to start PTY session'\n );\n throw error;\n }\n }\n\n /**\n * Set up event handlers for the PTY\n */\n private setupEventHandlers(): void {\n if (!this.ptyProcess) return;\n\n this.ptyProcess.onData((data) => {\n this._lastActivityAt = new Date();\n this.outputBuffer += data;\n\n // Cap the buffer to prevent unbounded growth during long tasks.\n // Detection only ever inspects the tail, so trimming is safe.\n if (this.outputBuffer.length > PTYSession.MAX_OUTPUT_BUFFER) {\n this.outputBuffer = this.outputBuffer.slice(\n -PTYSession.MAX_OUTPUT_BUFFER\n );\n }\n\n // Emit raw output immediately (callers may need it for real-time display)\n this.emit('output', data);\n\n // Defer all heavy detection work to the next event-loop tick.\n // node-pty delivers data synchronously from its native read loop;\n // running regex-heavy detection inline can starve the event loop\n // and prevent timers (stall detection, task_complete debounce)\n // from firing — especially on macOS ARM64 where the PTY read can\n // hold the libuv poll phase.\n if (!this._processScheduled) {\n this._processScheduled = true;\n setImmediate(() => {\n this._processScheduled = false;\n this.processOutputBuffer();\n });\n }\n });\n\n this.ptyProcess.onExit(({ exitCode, signal }) => {\n this._status = 'stopped';\n this.clearStallTimer();\n this.logger.info(\n { sessionId: this.id, exitCode, signal },\n 'PTY session exited'\n );\n this.emit('exit', exitCode);\n });\n }\n\n /**\n * Process the accumulated output buffer.\n * Called via setImmediate() from the onData handler so that heavy regex\n * work runs in its own event-loop tick, not inside node-pty's native callback.\n */\n private processOutputBuffer(): void {\n // Reset stall timer on any new output while busy or authenticating\n if (this._status === 'busy' || this._status === 'authenticating') {\n this.resetStallTimer();\n }\n\n // If a ready-settle is pending, reset the timer on new data instead of\n // re-running all detection. If the ready indicator disappears, cancel.\n if (this._readySettlePending) {\n if (\n (this._status === 'starting' || this._status === 'authenticating') &&\n this.adapter.detectReady(this.outputBuffer)\n ) {\n this.scheduleReadySettle();\n } else {\n this.cancelReadySettle();\n }\n return;\n }\n\n // Ready detection — check FIRST, before blocking prompt detection.\n // After an auto-response (e.g. trust prompt), the buffer may contain\n // leftover prompt text that would falsely trigger detectBlockingPrompt\n // and block detectReady from ever running. Adapter detectReady\n // implementations have negative guards for trust/auth prompts, so\n // this is safe — it won't prematurely mark the session as ready.\n if (\n (this._status === 'starting' || this._status === 'authenticating') &&\n this.adapter.detectReady(this.outputBuffer)\n ) {\n this.scheduleReadySettle();\n return;\n }\n\n // Tool running detection — emit event promptly when busy so UI updates\n if (this._status === 'busy') {\n const toolInfo = this.adapter.detectToolRunning?.(this.outputBuffer);\n if (toolInfo) {\n if (toolInfo.toolName !== this._lastToolRunningName) {\n this._lastToolRunningName = toolInfo.toolName;\n this.emit('tool_running', toolInfo);\n }\n } else if (this._lastToolRunningName) {\n this._lastToolRunningName = null;\n }\n }\n\n // Task completion detection — when busy and the agent returns to idle.\n // Uses a settle pattern: once triggered, the debounce timer resets on each\n // new data chunk instead of being cancelled. The callback re-verifies\n // the task-complete signal before transitioning, so stale triggers are safe.\n if (this._status === 'busy') {\n const signal = this.isTaskCompleteSignal(this.outputBuffer);\n if (this._taskCompletePending || signal) {\n this.traceTaskCompletion('busy_signal', { signal });\n this.scheduleTaskComplete();\n }\n // No else/cancel — timer self-validates on fire\n }\n\n // Auto-response / blocking prompt detection — runs after detectReady.\n // Handles trust confirmations, permission prompts, apply changes, etc.\n // Skip when stopping/stopped to prevent blocking_prompt spam between\n // stopSession() and PTY exit.\n if (this._status !== 'stopping' && this._status !== 'stopped') {\n const blockingPrompt = this.detectAndHandleBlockingPrompt();\n if (blockingPrompt) {\n return;\n }\n }\n\n // Login detection — only during startup/auth (not after ready/busy)\n if (this._status !== 'ready' && this._status !== 'busy') {\n const loginDetection = this.adapter.detectLogin(this.outputBuffer);\n if (loginDetection.required && this._status !== 'authenticating') {\n this._status = 'authenticating';\n this.clearStallTimer();\n this.emitAuthRequired({\n type: loginDetection.type,\n url: loginDetection.url,\n deviceCode: loginDetection.deviceCode,\n instructions: loginDetection.instructions,\n });\n this.logger.warn(\n { sessionId: this.id, loginType: loginDetection.type },\n 'Login required'\n );\n return;\n }\n }\n\n // Check for exit\n const exitDetection = this.adapter.detectExit(this.outputBuffer);\n if (exitDetection.exited) {\n this._status = 'stopped';\n this.clearStallTimer();\n this.emit('exit', exitDetection.code || 0);\n }\n\n // Try to parse output into structured message only when ready.\n // Parsing clears outputBuffer; doing this while busy can starve task-complete\n // and stall detection of evidence during heavy TUI rendering.\n if (this._status === 'ready') {\n this.tryParseOutput();\n }\n }\n\n /**\n * Detect blocking prompts and handle them with auto-responses or user notification.\n * Deduplicates emissions - won't re-emit the same blocking prompt repeatedly.\n */\n private detectAndHandleBlockingPrompt(): boolean {\n // First, check adapter's auto-response rules\n const autoHandled = this.tryAutoResponse();\n if (autoHandled) {\n return true;\n }\n\n // Then check the adapter's detectBlockingPrompt method\n if (this.adapter.detectBlockingPrompt) {\n const detection = this.adapter.detectBlockingPrompt(this.outputBuffer);\n\n if (detection.detected) {\n // Deduplicate: don't re-emit the same blocking prompt.\n // Normalize the prompt text for hashing — strip whitespace variations,\n // line numbers, and cursor artifacts that change on every TUI re-render\n // (e.g. pager prompts, permission dialogs with changing line counts).\n const normalizedPrompt = (detection.prompt || '')\n .replace(/\\s+/g, ' ') // collapse whitespace\n .replace(/\\d+/g, '#') // normalize numbers (line counts, etc.)\n .trim()\n .slice(0, 100); // cap length for consistent hashing\n const promptHash = `${detection.type}:${normalizedPrompt}`;\n if (promptHash === this._lastBlockingPromptHash) {\n // Still blocked by same prompt, but don't spam events\n return true;\n }\n // Time-based debounce: suppress rapid re-emissions within 250ms.\n // Spinner fragments produce slightly different hashes on each frame.\n const now = Date.now();\n if (now - this._lastBlockingPromptEmitAt < PTYSession.BLOCKING_PROMPT_DEBOUNCE_MS) {\n return true;\n }\n this._lastBlockingPromptHash = promptHash;\n this._lastBlockingPromptEmitAt = now;\n\n const promptInfo: BlockingPromptInfo = {\n type: detection.type || 'unknown',\n prompt: detection.prompt,\n options: detection.options,\n canAutoRespond: detection.canAutoRespond || false,\n instructions: detection.instructions,\n url: detection.url,\n };\n\n // If we can auto-respond and have a suggested response, do it\n if (\n detection.canAutoRespond &&\n detection.suggestedResponse &&\n !this.config.skipAdapterAutoResponse\n ) {\n this.logger.info(\n {\n sessionId: this.id,\n promptType: detection.type,\n response: detection.suggestedResponse,\n },\n 'Auto-responding to blocking prompt'\n );\n\n const resp = detection.suggestedResponse;\n if (resp.startsWith('keys:')) {\n const keys = resp\n .slice(5)\n .split(',')\n .map((k) => k.trim());\n this.sendKeySequence(keys);\n } else {\n this.writeRaw(`${resp}\\r`);\n }\n // Keep the hash so TUI re-renders of the same prompt are deduped.\n // Clear the buffer to prevent stale text from triggering false detections.\n this.outputBuffer = '';\n this.emit('blocking_prompt', promptInfo, true);\n return true;\n }\n\n // Otherwise, notify that user intervention is needed\n if (detection.type === 'login') {\n this._status = 'authenticating';\n // Surface login prompts through the dedicated auth event so callers\n // can open OAuth/device-code URLs without parsing blocking_prompt.\n const inferred = this.adapter.detectLogin(this.outputBuffer);\n this.emitAuthRequired({\n type: inferred.required ? inferred.type : undefined,\n url: detection.url ?? inferred.url,\n deviceCode: inferred.required ? inferred.deviceCode : undefined,\n instructions: detection.instructions ?? inferred.instructions,\n });\n }\n\n this.logger.warn(\n {\n sessionId: this.id,\n promptType: detection.type,\n prompt: detection.prompt,\n },\n 'Blocking prompt requires user intervention'\n );\n\n this.emit('blocking_prompt', promptInfo, false);\n return true;\n } else {\n // No blocking prompt detected - clear the hash\n this._lastBlockingPromptHash = null;\n this._lastBlockingPromptEmitAt = 0;\n }\n }\n\n return false;\n }\n\n /**\n * Try to match and apply auto-response rules.\n * Session rules are checked first, then adapter rules.\n */\n private tryAutoResponse(): boolean {\n // Combine session rules (higher priority) with adapter rules (filtered/merged by overrides)\n const adapterRules = (this.adapter.autoResponseRules || [])\n .filter((r) => !this._disabledRulePatterns.has(r.pattern.source))\n .map((r) => {\n const override = this._ruleOverrides.get(r.pattern.source);\n return override ? { ...r, ...override } : r;\n });\n const allRules = [...this.sessionRules, ...adapterRules];\n\n if (allRules.length === 0) {\n return false;\n }\n\n // Strip ANSI codes, cursor movement, box-drawing, and spinner chars\n // so regex patterns match the visible text, not raw terminal sequences.\n const stripped = this.stripAnsiForStall(this.outputBuffer);\n\n for (const rule of allRules) {\n // Skip once-rules that have already fired\n if (rule.once) {\n const ruleKey = `${rule.pattern.source}:${rule.pattern.flags}`;\n if (this._firedOnceRules.has(ruleKey)) {\n continue;\n }\n }\n\n if (rule.pattern.test(stripped)) {\n // Check if it's safe to auto-respond (default: true)\n const safe = rule.safe !== false;\n const isSessionRule = this.sessionRules.includes(rule);\n\n if (safe) {\n this.logger.info(\n {\n sessionId: this.id,\n promptType: rule.type,\n description: rule.description,\n response: rule.response,\n source: isSessionRule ? 'session' : 'adapter',\n },\n 'Applying auto-response rule'\n );\n\n // Determine how to send the response\n const useKeys = rule.keys && rule.keys.length > 0;\n const isTuiDefault =\n !rule.responseType && !rule.keys && this.adapter.usesTuiMenus;\n\n if (useKeys) {\n // Explicit key sequence\n this.sendKeySequence(rule.keys!);\n } else if (isTuiDefault) {\n // TUI adapter with no explicit responseType — default to Enter\n this.sendKeys('enter');\n } else {\n // Text response (backward compat)\n this.writeRaw(`${rule.response}\\r`);\n }\n\n // Track once-rules so they don't fire again on TUI re-renders\n if (rule.once) {\n const ruleKey = `${rule.pattern.source}:${rule.pattern.flags}`;\n this._firedOnceRules.add(ruleKey);\n }\n\n // Clear the entire buffer — the prompt has been handled and leftover\n // text (e.g. \"Press enter to continue\") would block detectReady().\n this.outputBuffer = '';\n\n const promptInfo: BlockingPromptInfo = {\n type: rule.type,\n prompt: rule.description,\n canAutoRespond: true,\n };\n\n this.emit('blocking_prompt', promptInfo, true);\n return true;\n } else {\n // Not safe to auto-respond, emit for user intervention\n const promptInfo: BlockingPromptInfo = {\n type: rule.type,\n prompt: rule.description,\n canAutoRespond: false,\n instructions: `Prompt matched but requires user confirmation: ${rule.description}`,\n };\n\n this.emit('blocking_prompt', promptInfo, false);\n return true;\n }\n }\n }\n\n return false;\n }\n\n /**\n * Try to parse the output buffer into structured messages\n */\n private tryParseOutput(): void {\n const parsed = this.adapter.parseOutput(this.outputBuffer);\n\n if (parsed?.isComplete) {\n // Clear the buffer for the parsed content\n this.outputBuffer = '';\n\n const message: SessionMessage = {\n id: `${this.id}-msg-${++this.messageCounter}`,\n sessionId: this.id,\n direction: 'outbound',\n type: parsed.type,\n content: parsed.content,\n metadata: parsed.metadata,\n timestamp: new Date(),\n };\n\n this.emit('message', message);\n\n // Also emit specific event for questions\n if (parsed.isQuestion) {\n this.emit('question', parsed.content);\n }\n }\n }\n\n /**\n * Write data to the PTY (formatted by adapter)\n */\n write(data: string): void {\n if (!this.ptyProcess) {\n throw new Error('Session not started');\n }\n\n this._lastActivityAt = new Date();\n const formatted = this.adapter.formatInput(data);\n this.ptyProcess.write(`${formatted}\\r`);\n\n this.logger.debug(\n { sessionId: this.id, input: data },\n 'Sent input to session'\n );\n }\n\n /**\n * Write raw data directly to the PTY (no formatting)\n */\n writeRaw(data: string): void {\n if (!this.ptyProcess) {\n throw new Error('Session not started');\n }\n\n this._lastActivityAt = new Date();\n this.ptyProcess.write(data);\n }\n\n /**\n * Send a task/message to the session\n *\n * Text and Enter are sent as separate writes with a small delay.\n * This is required for TUI-based CLIs (Gemini CLI, ink/React-based tools)\n * which drop the trailing \\r if it arrives in the same write buffer\n * during a render cycle.\n */\n send(message: string): SessionMessage {\n this._status = 'busy';\n this.outputBuffer = ''; // Clear stale startup/previous-task text so detectReady guards don't false-negative\n this.emit('status_changed', 'busy');\n this._stallEmissionCount = 0;\n this.resetStallTimer();\n\n const msg: SessionMessage = {\n id: `${this.id}-msg-${++this.messageCounter}`,\n sessionId: this.id,\n direction: 'inbound',\n type: 'task',\n content: message,\n timestamp: new Date(),\n };\n\n // Write formatted text without Enter\n const formatted = this.adapter.formatInput(message);\n this.writeRaw(formatted);\n\n // Send Enter separately after a brief delay\n // TUI-based CLIs need this as a discrete event to register the submission\n setTimeout(() => this.sendKeys('enter'), 50);\n\n this.logger.debug(\n { sessionId: this.id, input: message },\n 'Sent input to session'\n );\n\n return msg;\n }\n\n /**\n * Resize the PTY terminal\n */\n resize(cols: number, rows: number): void {\n this.ptyProcess?.resize(cols, rows);\n }\n\n /**\n * Send special keys to the PTY\n *\n * Supported keys:\n * - Control: ctrl+c, ctrl+d, ctrl+z, ctrl+l, ctrl+a, ctrl+e, ctrl+k, ctrl+u, ctrl+w, ctrl+r\n * - Navigation: up, down, left, right, home, end, pageup, pagedown\n * - Editing: enter, tab, backspace, delete, insert, escape\n * - Function: f1-f12\n *\n * @param keys - Key name(s) to send, e.g. \"ctrl+c\" or [\"up\", \"up\", \"enter\"]\n */\n sendKeys(keys: string | string[]): void {\n if (!this.ptyProcess) {\n throw new Error('Session not started');\n }\n\n const keyList = Array.isArray(keys) ? keys : [keys];\n const normalized = PTYSession.normalizeKeyList(keyList);\n this._stallEmissionCount = 0;\n this._lastBlockingPromptHash = null;\n this._lastBlockingPromptEmitAt = 0;\n this.outputBuffer = '';\n this.resetStallTimer();\n\n for (const key of normalized) {\n const sequence = SPECIAL_KEYS[key];\n\n if (sequence) {\n this._lastActivityAt = new Date();\n this.ptyProcess.write(sequence);\n this.logger.debug({ sessionId: this.id, key }, 'Sent special key');\n } else {\n this.logger.warn(\n { sessionId: this.id, key },\n 'Unknown special key, sending as literal'\n );\n this.ptyProcess.write(key);\n }\n }\n }\n\n /**\n * Build the environment object for spawning a PTY process.\n * Merges base env (process.env unless opted out), adapter env, and config env,\n * with TERM/COLORTERM always forced.\n */\n static buildSpawnEnv(\n config: SpawnConfig,\n adapterEnv: Record<string, string>\n ): Record<string, string> {\n const baseEnv = config.inheritProcessEnv !== false ? process.env : {};\n return {\n ...baseEnv,\n ...adapterEnv,\n ...config.env,\n TERM: 'xterm-256color',\n COLORTERM: 'truecolor',\n } as Record<string, string>;\n }\n\n /**\n * Normalize a list of key names for SPECIAL_KEYS lookup.\n *\n * Handles two problems:\n * 1. Modifier aliases: \"control\" → \"ctrl\", \"command\" → \"meta\", \"option\" → \"alt\"\n * 2. Comma-separated compound keys from stall classifier: [\"control\", \"c\"] → [\"ctrl+c\"]\n * A bare modifier followed by a single char/key is joined with \"+\".\n */\n static normalizeKeyList(keys: string[]): string[] {\n const MODIFIER_MAP: Record<string, string> = {\n control: 'ctrl',\n command: 'meta',\n cmd: 'meta',\n option: 'alt',\n opt: 'alt',\n };\n\n const MODIFIER_NAMES = new Set([\n 'ctrl',\n 'alt',\n 'shift',\n 'meta',\n // Also match the aliases so we can detect them before remapping\n ...Object.keys(MODIFIER_MAP),\n ]);\n\n const result: string[] = [];\n let i = 0;\n\n while (i < keys.length) {\n let key = keys[i].toLowerCase().trim();\n\n // Remap modifier aliases\n if (MODIFIER_MAP[key]) {\n key = MODIFIER_MAP[key];\n }\n\n // If this is a bare modifier and the next element is a non-modifier key,\n // join them as \"modifier+key\" (e.g. [\"ctrl\", \"c\"] → \"ctrl+c\")\n if (MODIFIER_NAMES.has(key) && i + 1 < keys.length) {\n let nextKey = keys[i + 1].toLowerCase().trim();\n if (MODIFIER_MAP[nextKey]) {\n nextKey = MODIFIER_MAP[nextKey];\n }\n // Only join if next is NOT a bare modifier (avoid collapsing [\"ctrl\", \"shift\", \"c\"])\n if (!MODIFIER_NAMES.has(nextKey)) {\n result.push(`${key}+${nextKey}`);\n i += 2;\n continue;\n }\n }\n\n result.push(key);\n i++;\n }\n\n return result;\n }\n\n /**\n * Select a TUI menu option by index (0-based).\n * Sends Down arrow `optionIndex` times, then Enter, with 50ms delays.\n */\n async selectMenuOption(optionIndex: number): Promise<void> {\n for (let i = 0; i < optionIndex; i++) {\n this.sendKeys('down');\n await this.delay(50);\n }\n this.sendKeys('enter');\n }\n\n /**\n * Send a sequence of keys with staggered timing.\n * Each key is sent 50ms apart using setTimeout to keep the caller synchronous.\n */\n private sendKeySequence(keys: string[]): void {\n keys.forEach((key, i) => {\n setTimeout(() => this.sendKeys(key), i * 50);\n });\n }\n\n /**\n * Paste text using bracketed paste mode\n *\n * Bracketed paste mode wraps the pasted text in escape sequences\n * that tell the terminal this is pasted content, not typed input.\n * This prevents issues with pasting text that contains special characters\n * or looks like commands.\n *\n * @param text - Text to paste\n * @param useBracketedPaste - Whether to use bracketed paste mode (default: true)\n */\n paste(text: string, useBracketedPaste: boolean = true): void {\n if (!this.ptyProcess) {\n throw new Error('Session not started');\n }\n\n this._lastActivityAt = new Date();\n\n if (useBracketedPaste) {\n this.ptyProcess.write(BRACKETED_PASTE_START + text + BRACKETED_PASTE_END);\n this.logger.debug(\n { sessionId: this.id, length: text.length },\n 'Pasted text with bracketed paste mode'\n );\n } else {\n this.ptyProcess.write(text);\n this.logger.debug(\n { sessionId: this.id, length: text.length },\n 'Pasted text without bracketed paste'\n );\n }\n }\n\n /**\n * Kill the PTY process\n */\n /**\n * Notify the session of an external hook event (e.g. from Claude Code HTTP hooks).\n * Resets the stall timer so hook-managed sessions don't get false stall escalations.\n * For \"task_complete\" events, transitions the session to ready.\n */\n notifyHookEvent(event: string): void {\n switch (event) {\n case 'tool_running':\n // Hook confirms a tool is running — reset stall timer to avoid false escalation.\n this._lastActivityAt = new Date();\n this.resetStallTimer();\n // Intentionally silent — fires on every tool use and is too noisy even at debug level.\n break;\n case 'task_complete':\n // Hook says the agent finished — transition to ready.\n this._status = 'ready';\n this._lastBlockingPromptHash = null;\n this._lastBlockingPromptEmitAt = 0;\n this.outputBuffer = '';\n this.clearStallTimer();\n this.emit('status_changed', 'ready');\n this.emit('task_complete');\n this.logger.info(\n { sessionId: this.id, event },\n 'Hook event: task_complete → ready'\n );\n break;\n case 'permission_approved':\n // Permission handled by hook — reset stall timer and clear the output\n // buffer so stale prompt text doesn't re-trigger detection. Keep the\n // hash intact: TUI re-renders may briefly show the same prompt text\n // before the agent processes the approval. With the hash preserved,\n // detectBlockingPrompt deduplicates those re-renders instead of\n // emitting a flood of duplicate blocking_prompt events.\n this._lastActivityAt = new Date();\n this.outputBuffer = '';\n this.resetStallTimer();\n break;\n default:\n // Generic activity signal — just reset stall timer.\n this._lastActivityAt = new Date();\n this.resetStallTimer();\n break;\n }\n }\n\n kill(signal?: string): void {\n if (this.ptyProcess) {\n this._status = 'stopping';\n this.clearStallTimer();\n this.cancelTaskComplete();\n this.cancelReadySettle();\n this.ptyProcess.kill(signal);\n this.logger.info({ sessionId: this.id, signal }, 'Killing PTY session');\n }\n }\n\n /**\n * Get current output buffer\n */\n getOutputBuffer(): string {\n return this.outputBuffer;\n }\n\n /**\n * Clear output buffer\n */\n clearOutputBuffer(): void {\n this.outputBuffer = '';\n }\n\n /**\n * Convert to SessionHandle\n */\n toHandle(): SessionHandle {\n return {\n id: this.id,\n name: this.config.name,\n type: this.config.type,\n status: this._status,\n pid: this.pid,\n startedAt: this._startedAt ?? undefined,\n lastActivityAt: this._lastActivityAt ?? undefined,\n };\n }\n}\n","/**\n * Task completion trace analysis helpers.\n *\n * Parses structured \"Task completion trace\" logs and builds a compact\n * per-turn confidence timeline useful for debugging idle/completion detection.\n */\n\nexport interface TaskCompletionTraceRecord {\n sessionId?: string;\n adapterType?: string;\n event: string;\n status?: string;\n taskCompletePending?: boolean;\n signal?: boolean;\n wasPending?: boolean;\n debounceMs?: number;\n detectTaskComplete?: boolean;\n detectReady?: boolean;\n detectLoading?: boolean;\n tailHash?: string;\n tailSnippet?: string;\n timestamp?: string | number | Date;\n}\n\nexport interface TaskCompletionTimelineStep {\n event: string;\n atIndex: number;\n status:\n | 'active'\n | 'active_loading'\n | 'likely_complete'\n | 'completed'\n | 'rejected';\n confidence: number;\n signal?: boolean;\n detectTaskComplete?: boolean;\n detectReady?: boolean;\n detectLoading?: boolean;\n}\n\nexport interface TaskCompletionTurnTimeline {\n turn: number;\n startIndex: number;\n endIndex: number;\n completed: boolean;\n maxConfidence: number;\n finalConfidence: number;\n events: TaskCompletionTimelineStep[];\n}\n\nexport interface TaskCompletionTimelineResult {\n turns: TaskCompletionTurnTimeline[];\n totalRecords: number;\n ignoredRecords: number;\n}\n\nexport interface BuildTimelineOptions {\n adapterType?: string;\n}\n\n/**\n * Extract trace records from mixed log inputs.\n * Accepts structured objects and JSON lines.\n */\nexport function extractTaskCompletionTraceRecords(\n entries: Array<string | Record<string, unknown>>\n): TaskCompletionTraceRecord[] {\n const out: TaskCompletionTraceRecord[] = [];\n\n for (const entry of entries) {\n let obj: Record<string, unknown> | null = null;\n\n if (typeof entry === 'string') {\n const line = entry.trim();\n if (!line.startsWith('{') || !line.endsWith('}')) continue;\n try {\n obj = JSON.parse(line) as Record<string, unknown>;\n } catch {\n continue;\n }\n } else if (entry && typeof entry === 'object') {\n obj = entry;\n }\n\n if (!obj) continue;\n if (obj.msg !== 'Task completion trace') continue;\n if (typeof obj.event !== 'string') continue;\n\n out.push({\n sessionId: asString(obj.sessionId),\n adapterType: asString(obj.adapterType),\n event: obj.event,\n status: asString(obj.status),\n taskCompletePending: asBool(obj.taskCompletePending),\n signal: asBool(obj.signal),\n wasPending: asBool(obj.wasPending),\n debounceMs: asNumber(obj.debounceMs),\n detectTaskComplete: asBool(obj.detectTaskComplete),\n detectReady: asBool(obj.detectReady),\n detectLoading: asBool(obj.detectLoading),\n tailHash: asString(obj.tailHash),\n tailSnippet: asString(obj.tailSnippet),\n timestamp: asTimestamp(obj.time) ?? asTimestamp(obj.timestamp),\n });\n }\n\n return out;\n}\n\n/**\n * Build a per-turn confidence timeline from task-completion traces.\n */\nexport function buildTaskCompletionTimeline(\n records: TaskCompletionTraceRecord[],\n options: BuildTimelineOptions = {}\n): TaskCompletionTimelineResult {\n const filtered = records.filter((r) => {\n if (!options.adapterType) return true;\n return r.adapterType === options.adapterType;\n });\n\n const turns: TaskCompletionTurnTimeline[] = [];\n let current: TaskCompletionTurnTimeline | null = null;\n let ignored = 0;\n\n filtered.forEach((record, index) => {\n if (record.event === 'busy_signal' && current && current.completed) {\n current = null;\n }\n\n if (!current) {\n current = {\n turn: turns.length + 1,\n startIndex: index,\n endIndex: index,\n completed: false,\n maxConfidence: 0,\n finalConfidence: 0,\n events: [],\n };\n turns.push(current);\n }\n\n const step = toStep(record, index);\n if (!step) {\n ignored++;\n return;\n }\n\n current.events.push(step);\n current.endIndex = index;\n current.maxConfidence = Math.max(current.maxConfidence, step.confidence);\n current.finalConfidence = step.confidence;\n\n if (step.status === 'completed') {\n current.completed = true;\n }\n });\n\n return {\n turns,\n totalRecords: filtered.length,\n ignoredRecords: ignored,\n };\n}\n\nfunction toStep(\n record: TaskCompletionTraceRecord,\n atIndex: number\n): TaskCompletionTimelineStep | null {\n const event = record.event;\n const confidence = scoreConfidence(record);\n\n if (event === 'transition_ready') {\n return withCommon(record, {\n event,\n atIndex,\n status: 'completed',\n confidence: 100,\n });\n }\n\n if (\n event === 'debounce_reject_signal' ||\n event === 'debounce_reject_status'\n ) {\n return withCommon(record, {\n event,\n atIndex,\n status: 'rejected',\n confidence,\n });\n }\n\n if (record.detectLoading) {\n return withCommon(record, {\n event,\n atIndex,\n status: 'active_loading',\n confidence,\n });\n }\n\n if (event === 'debounce_fire' && record.signal) {\n return withCommon(record, {\n event,\n atIndex,\n status: 'likely_complete',\n confidence,\n });\n }\n\n if (\n event === 'busy_signal' ||\n event === 'debounce_schedule' ||\n event === 'debounce_fire'\n ) {\n return withCommon(record, {\n event,\n atIndex,\n status: 'active',\n confidence,\n });\n }\n\n return null;\n}\n\nfunction scoreConfidence(record: TaskCompletionTraceRecord): number {\n let score = 10;\n\n if (record.detectLoading) score -= 40;\n if (record.detectReady) score += 20;\n if (record.detectTaskComplete) score += 45;\n if (record.signal) score += 20;\n if (\n record.event === 'debounce_reject_signal' ||\n record.event === 'debounce_reject_status'\n ) {\n score -= 30;\n }\n if (record.event === 'transition_ready') score = 100;\n\n if (score < 0) return 0;\n if (score > 100) return 100;\n return score;\n}\n\nfunction withCommon(\n record: TaskCompletionTraceRecord,\n step: Omit<\n TaskCompletionTimelineStep,\n 'signal' | 'detectTaskComplete' | 'detectReady' | 'detectLoading'\n >\n): TaskCompletionTimelineStep {\n return {\n ...step,\n signal: record.signal,\n detectTaskComplete: record.detectTaskComplete,\n detectReady: record.detectReady,\n detectLoading: record.detectLoading,\n };\n}\n\nfunction asString(value: unknown): string | undefined {\n return typeof value === 'string' ? value : undefined;\n}\n\nfunction asBool(value: unknown): boolean | undefined {\n return typeof value === 'boolean' ? value : undefined;\n}\n\nfunction asNumber(value: unknown): number | undefined {\n return typeof value === 'number' ? value : undefined;\n}\n\nfunction asTimestamp(value: unknown): string | number | Date | undefined {\n if (\n typeof value === 'string' ||\n typeof value === 'number' ||\n value instanceof Date\n ) {\n return value;\n }\n return undefined;\n}\n"],"mappings":"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","names":["import_adapter_types","import_adapter_types","import_node_child_process","import_node_events","import_node_events"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/adapters/adapter-factory.ts","../src/adapters/adapter-registry.ts","../src/adapters/base-adapter.ts","../src/adapters/shell-adapter.ts","../src/bun-compat.ts","../src/ensure-pty.ts","../src/pty-manager.ts","../src/logger.ts","../src/pty-session.ts","../src/task-completion-trace.ts"],"sourcesContent":["/**\n * pty-manager\n *\n * PTY session manager with lifecycle management,\n * pluggable adapters, and blocking prompt detection.\n */\n\nexport type { CLIAdapter, ShellAdapterOptions } from './adapters';\n// Adapter system\nexport {\n AdapterRegistry,\n BaseCLIAdapter,\n createAdapter,\n ShellAdapter,\n} from './adapters';\nexport type {\n BunPTYManagerOptions,\n WorkerSessionHandle,\n} from './bun-compat';\n// Bun compatibility layer\nexport {\n BunCompatiblePTYManager,\n createPTYManager,\n isBun,\n} from './bun-compat';\n// PTY preflight check\nexport { ensurePty } from './ensure-pty';\n// Event types\nexport type { PTYManagerEvents } from './pty-manager';\n// Core classes\nexport { PTYManager } from './pty-manager';\nexport type { PTYSessionEvents } from './pty-session';\nexport { PTYSession, SPECIAL_KEYS } from './pty-session';\nexport type {\n BuildTimelineOptions,\n TaskCompletionTimelineResult,\n TaskCompletionTimelineStep,\n TaskCompletionTraceRecord,\n TaskCompletionTurnTimeline,\n} from './task-completion-trace';\nexport {\n buildTaskCompletionTimeline,\n extractTaskCompletionTraceRecords,\n} from './task-completion-trace';\n// Types\nexport type {\n // Factory types\n AdapterFactoryConfig,\n AuthRequiredInfo,\n AuthRequiredMethod,\n AutoResponseRule,\n BlockingPromptDetection,\n BlockingPromptInfo,\n BlockingPromptType,\n // Manager types\n Logger,\n LoginDetection,\n LogOptions,\n MessageType,\n // Adapter types\n ParsedOutput,\n PTYManagerConfig,\n SessionFilter,\n SessionHandle,\n SessionMessage,\n // Session types\n SessionStatus,\n SpawnConfig,\n // Stall detection types\n StallClassification,\n StopOptions,\n TerminalAttachment,\n // Tool running detection\n ToolRunningInfo,\n} from './types';\n","/**\n * Adapter Factory — re-exported from adapter-types\n */\nexport { createAdapter } from 'adapter-types';\n","/**\n * Adapter Registry — re-exported from adapter-types\n */\nexport { AdapterRegistry } from 'adapter-types';\n","/**\n * Base CLI Adapter — re-exported from adapter-types\n */\nexport { BaseCLIAdapter } from 'adapter-types';\n","/**\n * Shell Adapter\n *\n * Built-in adapter for bash/zsh shell sessions.\n */\n\nimport type {\n AutoResponseRule,\n BlockingPromptDetection,\n LoginDetection,\n ParsedOutput,\n SpawnConfig,\n} from '../types';\nimport type { CLIAdapter } from './adapter-interface';\n\n/**\n * Options for the shell adapter\n */\nexport interface ShellAdapterOptions {\n /** Shell to use (default: $SHELL or /bin/bash) */\n shell?: string;\n\n /** Custom prompt string (default: 'pty> ') */\n prompt?: string;\n}\n\n/**\n * Built-in adapter for shell sessions (bash/zsh)\n */\nexport class ShellAdapter implements CLIAdapter {\n readonly adapterType = 'shell';\n readonly displayName = 'Shell';\n readonly autoResponseRules: AutoResponseRule[] = [];\n\n private shell: string;\n private promptStr: string;\n\n constructor(options: ShellAdapterOptions = {}) {\n this.shell = options.shell || process.env.SHELL || '/bin/bash';\n this.promptStr = options.prompt || 'pty> ';\n }\n\n getCommand(): string {\n return this.shell;\n }\n\n getArgs(_config: SpawnConfig): string[] {\n return [];\n }\n\n getEnv(_config: SpawnConfig): Record<string, string> {\n return {\n PS1: this.promptStr,\n };\n }\n\n detectLogin(_output: string): LoginDetection {\n // Shell doesn't need login\n return { required: false };\n }\n\n detectBlockingPrompt(_output: string): BlockingPromptDetection {\n // Shell typically doesn't have blocking prompts\n return { detected: false };\n }\n\n detectReady(output: string): boolean {\n // Reject continuation prompts — the shell is waiting for a closing\n // quote/heredoc/backtick, NOT at a real prompt.\n if (this.isContinuationPrompt(output)) {\n return false;\n }\n\n // Check for our custom prompt string (PS1) or standard shell prompt at end of line\n return this.getPromptPattern().test(this.stripAnsi(output));\n }\n\n /**\n * Detect shell continuation prompts that indicate the shell is NOT ready\n * for a new command (e.g., unclosed quote, heredoc, backtick).\n */\n private isContinuationPrompt(output: string): boolean {\n const stripped = this.stripAnsi(output);\n // Match common continuation prompts at the end of output\n return (\n /(?:quote|dquote|heredoc|bquote|cmdsubst|pipe|then|else|do|loop)>\\s*$/.test(\n stripped\n ) ||\n // Also match bare > that's preceded by one of these words on the same line\n /(?:quote|dquote|heredoc|bquote)>\\s*$/m.test(stripped)\n );\n }\n\n detectExit(output: string): {\n exited: boolean;\n code?: number;\n error?: string;\n } {\n if (output.includes('exit')) {\n return { exited: true, code: 0 };\n }\n return { exited: false };\n }\n\n parseOutput(output: string): ParsedOutput | null {\n const cleaned = this.stripAnsi(output).trim();\n if (!cleaned) return null;\n\n return {\n type: 'response',\n content: cleaned,\n isComplete: true,\n isQuestion: false,\n };\n }\n\n formatInput(message: string): string {\n return message;\n }\n\n getPromptPattern(): RegExp {\n // Match our custom prompt or standard shell prompts ($ or #).\n // Does NOT match bare > because that collides with continuation prompts\n // (quote>, dquote>, heredoc>, etc.).\n const escaped = this.promptStr.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n return new RegExp(`(?:${escaped}|\\\\$|#)\\\\s*$`, 'm');\n }\n\n async validateInstallation(): Promise<{\n installed: boolean;\n version?: string;\n error?: string;\n }> {\n // Shell is always installed\n return { installed: true };\n }\n\n private stripAnsi(str: string): string {\n // eslint-disable-next-line no-control-regex\n return str.replace(/\\x1B(?:[@-Z\\\\-_]|\\[[0-?]*[ -/]*[@-~])/g, '');\n }\n}\n","/**\n * Bun-Compatible PTY Manager\n *\n * A wrapper that spawns a Node.js worker process to handle PTY operations,\n * allowing pty-manager to work from Bun or other non-Node runtimes.\n */\n\nimport { type ChildProcess, spawn } from 'node:child_process';\nimport { EventEmitter } from 'node:events';\nimport * as path from 'node:path';\nimport * as readline from 'node:readline';\nimport type {\n AuthRequiredInfo,\n AutoResponseRule,\n BlockingPromptType,\n SessionStatus,\n SpawnConfig,\n StallClassification,\n ToolRunningInfo,\n} from './types';\n\n/**\n * Serialized auto-response rule for IPC (pattern as string instead of RegExp)\n */\nexport interface SerializedRule {\n pattern: string;\n flags?: string;\n type: BlockingPromptType;\n response: string;\n responseType?: 'text' | 'keys';\n keys?: string[];\n description: string;\n safe?: boolean;\n once?: boolean;\n}\n\nexport interface WorkerSessionHandle {\n id: string;\n name: string;\n type: string;\n status: SessionStatus;\n pid: number | undefined;\n cols: number;\n rows: number;\n startedAt?: Date;\n lastActivityAt?: Date;\n error?: string;\n exitCode?: number;\n}\n\nexport interface BunPTYManagerOptions {\n /** Path to node executable (default: 'node') */\n nodePath?: string;\n /** Path to worker script (default: auto-detected) */\n workerPath?: string;\n /** Environment variables for worker process */\n env?: Record<string, string>;\n /**\n * Adapter modules to load in the worker process.\n * Each module should export a `createAllAdapters()` function that returns an array of adapters.\n * Example: ['coding-agent-adapters']\n */\n adapterModules?: string[];\n\n /** Enable stall detection (default: false) */\n stallDetectionEnabled?: boolean;\n /** Default stall timeout in ms (default: 8000) */\n stallTimeoutMs?: number;\n /**\n * External classification callback invoked when a stall is detected.\n * The worker emits stall_detected; this callback runs on the parent side.\n */\n onStallClassify?: (\n sessionId: string,\n recentOutput: string,\n stallDurationMs: number\n ) => Promise<StallClassification | null>;\n}\n\ninterface PendingOperation {\n resolve: (value: unknown) => void;\n reject: (error: Error) => void;\n timeout: NodeJS.Timeout;\n}\n\n/**\n * PTY Manager that works with Bun and other non-Node runtimes\n * by spawning a Node.js worker process.\n */\nexport class BunCompatiblePTYManager extends EventEmitter {\n private worker: ChildProcess | null = null;\n private sessions: Map<string, WorkerSessionHandle> = new Map();\n private pending: Map<string, PendingOperation> = new Map();\n private ready = false;\n private readyPromise: Promise<void>;\n private readyResolve!: () => void;\n private nodePath: string;\n private workerPath: string;\n private env: Record<string, string>;\n private adapterModules: string[];\n private _stallDetectionEnabled: boolean;\n private _stallTimeoutMs: number;\n private _onStallClassify?: (\n sessionId: string,\n recentOutput: string,\n stallDurationMs: number\n ) => Promise<StallClassification | null>;\n\n constructor(options: BunPTYManagerOptions = {}) {\n super();\n\n this.nodePath = options.nodePath || 'node';\n this.workerPath = options.workerPath || this.findWorkerPath();\n this.env = options.env || {};\n this.adapterModules = options.adapterModules || [];\n this._stallDetectionEnabled = options.stallDetectionEnabled ?? false;\n this._stallTimeoutMs = options.stallTimeoutMs ?? 8000;\n this._onStallClassify = options.onStallClassify;\n\n this.readyPromise = new Promise((resolve) => {\n this.readyResolve = resolve;\n });\n\n this.startWorker();\n }\n\n private findWorkerPath(): string {\n // Try to find the worker script relative to this module\n const possiblePaths = [\n path.join(__dirname, 'pty-worker.js'),\n path.join(__dirname, '..', 'dist', 'pty-worker.js'),\n path.join(__dirname, '..', 'src', 'pty-worker.js'),\n ];\n\n // Return first path (we'll rely on Node to throw if it doesn't exist)\n return possiblePaths[0];\n }\n\n private startWorker(): void {\n this.worker = spawn(this.nodePath, [this.workerPath], {\n stdio: ['pipe', 'pipe', 'pipe'],\n env: { ...process.env, ...this.env },\n });\n\n if (!this.worker.stdout || !this.worker.stdin) {\n throw new Error('Failed to create worker process pipes');\n }\n\n const rl = readline.createInterface({\n input: this.worker.stdout,\n terminal: false,\n });\n\n rl.on('line', (line) => this.handleWorkerMessage(line));\n\n this.worker.stderr?.on('data', (data) => {\n this.emit('worker_error', data.toString());\n });\n\n this.worker.on('exit', (code, signal) => {\n this.ready = false;\n this.worker = null;\n this.emit('worker_exit', { code, signal });\n\n // Reject all pending operations\n for (const [key, op] of this.pending) {\n clearTimeout(op.timeout);\n op.reject(new Error('Worker process exited'));\n this.pending.delete(key);\n }\n\n // Mark all sessions as stopped\n for (const session of this.sessions.values()) {\n session.status = 'stopped';\n }\n });\n\n this.worker.on('error', (err) => {\n this.emit('worker_error', err);\n });\n }\n\n private handleWorkerMessage(line: string): void {\n let event: Record<string, unknown>;\n\n try {\n event = JSON.parse(line);\n } catch {\n this.emit('worker_error', `Invalid JSON from worker: ${line}`);\n return;\n }\n\n const eventType = event.event as string;\n const id = event.id as string | undefined;\n\n switch (eventType) {\n case 'worker_ready':\n // Send stall detection config to worker (fire-and-forget, no ack needed before ready)\n if (this._stallDetectionEnabled) {\n this.sendCommand({\n cmd: 'configureStallDetection',\n enabled: true,\n timeoutMs: this._stallTimeoutMs,\n });\n }\n // Register adapter modules and wait for ack before marking as ready.\n // Without this, spawn() can race ahead using the default shell adapter.\n if (this.adapterModules.length > 0) {\n this.sendCommand({\n cmd: 'registerAdapters',\n modules: this.adapterModules,\n });\n this.createPending('registerAdapters')\n .then(() => {\n this.ready = true;\n this.readyResolve();\n this.emit('ready');\n })\n .catch((err) => {\n this.emit('worker_error', `Failed to register adapters: ${err}`);\n // Still resolve so callers aren't stuck forever — they'll get shell adapter\n this.ready = true;\n this.readyResolve();\n this.emit('ready');\n });\n } else {\n this.ready = true;\n this.readyResolve();\n this.emit('ready');\n }\n break;\n\n case 'spawned': {\n // Get config from event (worker sends it back)\n const session: WorkerSessionHandle = {\n id: id!,\n name: (event.name as string) || id!,\n type: (event.type as string) || 'shell',\n status: 'starting',\n pid: event.pid as number,\n cols: (event.cols as number) || 80,\n rows: (event.rows as number) || 24,\n startedAt: new Date(),\n };\n this.sessions.set(id!, session);\n this.emit('session_started', session);\n break;\n }\n\n case 'output': {\n const session = this.sessions.get(id!);\n if (session) {\n session.lastActivityAt = new Date();\n }\n this.emit('data', { id, data: event.data });\n this.emit(`data:${id}`, event.data);\n break;\n }\n\n case 'ready': {\n const session = this.sessions.get(id!);\n if (session) {\n session.status = 'ready';\n session.lastActivityAt = new Date();\n this.emit('session_ready', session);\n }\n break;\n }\n\n case 'exit': {\n const session = this.sessions.get(id!);\n if (session) {\n session.status = 'stopped';\n session.exitCode = event.code as number;\n session.lastActivityAt = new Date();\n this.emit('session_stopped', session, event.code, event.signal);\n this.sessions.delete(id!);\n }\n break;\n }\n\n case 'error':\n if (id) {\n const session = this.sessions.get(id);\n if (session) {\n session.status = 'error';\n session.error = event.message as string;\n session.lastActivityAt = new Date();\n }\n this.emit('session_error', { id, error: event.message });\n } else {\n this.emit('worker_error', event.message);\n }\n break;\n\n case 'blocking_prompt': {\n const session = this.sessions.get(id!);\n if (session) {\n this.emit(\n 'blocking_prompt',\n session,\n event.promptInfo,\n event.autoResponded\n );\n }\n break;\n }\n\n case 'login_required': {\n const session = this.sessions.get(id!);\n if (session) {\n session.status = 'authenticating';\n this.emit('login_required', session, event.instructions, event.url);\n }\n break;\n }\n\n case 'auth_required': {\n const session = this.sessions.get(id!);\n if (session) {\n session.status = 'authenticating';\n this.emit('auth_required', session, event.info as AuthRequiredInfo);\n }\n break;\n }\n\n case 'message': {\n const msg = event.message as Record<string, unknown>;\n // Convert timestamp back to Date\n this.emit('message', {\n ...msg,\n timestamp: new Date(msg.timestamp as string),\n });\n break;\n }\n\n case 'question': {\n const session = this.sessions.get(id!);\n if (session) {\n this.emit('question', session, event.question);\n }\n break;\n }\n\n case 'status_changed': {\n const session = this.sessions.get(id!);\n if (session) {\n session.status = event.status as SessionStatus;\n session.lastActivityAt = new Date();\n this.emit('session_status_changed', session);\n }\n break;\n }\n\n case 'task_complete': {\n const session = this.sessions.get(id!);\n if (session) {\n session.status = 'ready';\n session.lastActivityAt = new Date();\n this.emit('task_complete', session);\n }\n break;\n }\n\n case 'tool_running': {\n const session = this.sessions.get(id!);\n if (session) {\n this.emit('tool_running', session, event.info as ToolRunningInfo);\n }\n break;\n }\n\n case 'stall_detected': {\n const session = this.sessions.get(id!);\n if (session) {\n const recentOutput = event.recentOutput as string;\n const stallDurationMs = event.stallDurationMs as number;\n this.emit('stall_detected', session, recentOutput, stallDurationMs);\n\n // Call external classifier on parent side, send result back to worker\n if (this._onStallClassify) {\n this._onStallClassify(id!, recentOutput, stallDurationMs)\n .then((classification) => {\n this.sendCommand({\n cmd: 'classifyStallResult',\n id: id!,\n classification,\n });\n })\n .catch(() => {\n // On error, send null to reset the timer\n this.sendCommand({\n cmd: 'classifyStallResult',\n id: id!,\n classification: null,\n });\n });\n }\n }\n break;\n }\n\n case 'list': {\n // Convert date strings back to Date objects\n const sessions = (event.sessions as Record<string, unknown>[]).map(\n (s) => ({\n ...s,\n startedAt: s.startedAt\n ? new Date(s.startedAt as string)\n : undefined,\n lastActivityAt: s.lastActivityAt\n ? new Date(s.lastActivityAt as string)\n : undefined,\n })\n ) as WorkerSessionHandle[];\n this.resolvePending('list', sessions);\n break;\n }\n\n case 'isSessionLoading': {\n this.resolvePending(\n `isSessionLoading:${id}`,\n Boolean(event.loading),\n );\n break;\n }\n\n case 'rules': {\n // Convert serialized rules back to AutoResponseRule objects\n const serializedRules = event.rules as SerializedRule[];\n const rules = serializedRules.map((r) => ({\n pattern: new RegExp(r.pattern, r.flags || ''),\n type: r.type,\n response: r.response,\n responseType: r.responseType,\n keys: r.keys,\n description: r.description,\n safe: r.safe,\n once: r.once,\n })) as AutoResponseRule[];\n this.resolvePending(`getRules:${id}`, rules);\n break;\n }\n\n case 'ack': {\n const cmd = event.cmd as string;\n const success = event.success as boolean;\n const pendingKey = id ? `${cmd}:${id}` : cmd;\n const pending = this.pending.get(pendingKey);\n\n if (pending) {\n clearTimeout(pending.timeout);\n this.pending.delete(pendingKey);\n\n if (success) {\n pending.resolve(true);\n } else {\n pending.reject(new Error(event.error as string));\n }\n }\n break;\n }\n }\n }\n\n private sendCommand(cmd: Record<string, unknown>): void {\n if (!this.worker?.stdin) {\n throw new Error('Worker not available');\n }\n\n this.worker.stdin.write(`${JSON.stringify(cmd)}\\n`);\n }\n\n private createPending(key: string, timeoutMs = 30000): Promise<unknown> {\n return new Promise((resolve, reject) => {\n const timeout = setTimeout(() => {\n this.pending.delete(key);\n reject(new Error(`Operation ${key} timed out`));\n }, timeoutMs);\n\n this.pending.set(key, { resolve, reject, timeout });\n });\n }\n\n private resolvePending(key: string, value: unknown): void {\n const pending = this.pending.get(key);\n if (pending) {\n clearTimeout(pending.timeout);\n this.pending.delete(key);\n pending.resolve(value);\n }\n }\n\n /**\n * Wait for the worker to be ready\n */\n async waitForReady(): Promise<void> {\n return this.readyPromise;\n }\n\n /**\n * Check if worker is ready\n */\n isReady(): boolean {\n return this.ready;\n }\n\n /**\n * Spawn a new PTY session\n */\n async spawn(\n config: SpawnConfig & { id: string }\n ): Promise<WorkerSessionHandle> {\n await this.waitForReady();\n\n const { id } = config;\n\n this.sendCommand({ cmd: 'spawn', id, config });\n\n await this.createPending(`spawn:${id}`);\n\n return this.sessions.get(id)!;\n }\n\n /**\n * Send data to a session\n */\n async send(id: string, data: string): Promise<void> {\n await this.waitForReady();\n\n this.sendCommand({ cmd: 'send', id, data });\n\n await this.createPending(`send:${id}`);\n }\n\n /**\n * Send special keys to a session\n */\n async sendKeys(id: string, keys: string | string[]): Promise<void> {\n await this.waitForReady();\n\n this.sendCommand({ cmd: 'sendKeys', id, keys });\n\n await this.createPending(`sendKeys:${id}`);\n }\n\n /**\n * Notify a session of an external hook event (resets stall timer, updates status).\n */\n async notifyHookEvent(id: string, hookEvent: string): Promise<void> {\n await this.waitForReady();\n this.sendCommand({ cmd: 'notifyHookEvent', id, hookEvent });\n await this.createPending(`notifyHookEvent:${id}`);\n }\n\n /**\n * Write raw data to a session (bypasses adapter formatting)\n */\n async writeRaw(id: string, data: string): Promise<void> {\n await this.waitForReady();\n this.sendCommand({ cmd: 'writeRaw', id, data });\n // Fire-and-forget — writeRaw pushes bytes to the terminal and\n // doesn't need an ACK. Awaiting createPending caused timeouts\n // when overlapping calls for the same session collided on the\n // pending key (`writeRaw:${id}`), since the worker ACK only\n // carries cmd+id with no sequence number.\n }\n\n /**\n * Paste text to a session\n */\n async paste(id: string, text: string, bracketed = true): Promise<void> {\n await this.waitForReady();\n\n this.sendCommand({ cmd: 'paste', id, text, bracketed });\n\n await this.createPending(`paste:${id}`);\n }\n\n /**\n * Resize a session\n */\n async resize(id: string, cols: number, rows: number): Promise<void> {\n await this.waitForReady();\n this.sendCommand({ cmd: 'resize', id, cols, rows });\n const session = this.sessions.get(id);\n if (session) {\n session.cols = cols;\n session.rows = rows;\n }\n // Fire-and-forget — rapid resize events from the UI collide on\n // the pending key (`resize:${id}`) causing spurious timeouts.\n }\n\n /**\n * Kill a session\n */\n async kill(id: string, signal?: string): Promise<void> {\n await this.waitForReady();\n\n this.sendCommand({ cmd: 'kill', id, signal });\n\n await this.createPending(`kill:${id}`);\n }\n\n /**\n * Get a session by ID\n */\n get(id: string): WorkerSessionHandle | undefined {\n return this.sessions.get(id);\n }\n\n /**\n * List all sessions\n */\n async list(): Promise<WorkerSessionHandle[]> {\n await this.waitForReady();\n\n this.sendCommand({ cmd: 'list' });\n\n const sessions = (await this.createPending(\n 'list'\n )) as WorkerSessionHandle[];\n return sessions;\n }\n\n /**\n * Check if a session exists\n */\n has(id: string): boolean {\n return this.sessions.has(id);\n }\n\n /**\n * Whether the adapter currently classifies the session as actively\n * processing work.\n *\n * This round-trips to the worker since the adapter lives in the\n * worker process. Orchestrators (like milady's swarm idle watchdog)\n * should consult this before assuming a session is idle based on\n * output byte diffs — TUIs that redraw their status row in place\n * (Codex's \"Working… esc to interrupt\") can fool a raw text diff\n * even while the model is actively reasoning.\n *\n * Returns `false` for unknown sessions, adapters that don't\n * implement `detectLoading`, or on IPC errors.\n */\n async isSessionLoading(id: string): Promise<boolean> {\n if (!this.sessions.has(id)) return false;\n await this.waitForReady();\n this.sendCommand({ cmd: 'isSessionLoading', id });\n try {\n const result = (await this.createPending(\n `isSessionLoading:${id}`,\n )) as boolean;\n return Boolean(result);\n } catch {\n return false;\n }\n }\n\n /**\n * Subscribe to output from a specific session\n */\n onSessionData(id: string, callback: (data: string) => void): () => void {\n const handler = (data: string) => callback(data);\n this.on(`data:${id}`, handler);\n return () => this.off(`data:${id}`, handler);\n }\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Runtime Auto-Response Rules API\n // ─────────────────────────────────────────────────────────────────────────────\n\n private serializeRule(rule: AutoResponseRule): SerializedRule {\n return {\n pattern: rule.pattern.source,\n flags: rule.pattern.flags || undefined,\n type: rule.type,\n response: rule.response,\n responseType: rule.responseType,\n keys: rule.keys,\n description: rule.description,\n safe: rule.safe,\n once: rule.once,\n };\n }\n\n /**\n * Add an auto-response rule to a session.\n * Session rules are checked before adapter rules.\n */\n async addAutoResponseRule(\n sessionId: string,\n rule: AutoResponseRule\n ): Promise<void> {\n await this.waitForReady();\n\n const serialized = this.serializeRule(rule);\n this.sendCommand({ cmd: 'addRule', id: sessionId, rule: serialized });\n\n await this.createPending(`addRule:${sessionId}`);\n }\n\n /**\n * Remove an auto-response rule from a session by pattern.\n * Returns true if a rule was removed.\n */\n async removeAutoResponseRule(\n sessionId: string,\n pattern: RegExp\n ): Promise<boolean> {\n await this.waitForReady();\n\n this.sendCommand({\n cmd: 'removeRule',\n id: sessionId,\n pattern: pattern.source,\n flags: pattern.flags || undefined,\n });\n\n try {\n await this.createPending(`removeRule:${sessionId}`);\n return true;\n } catch {\n return false;\n }\n }\n\n /**\n * Set all auto-response rules for a session, replacing existing ones.\n */\n async setAutoResponseRules(\n sessionId: string,\n rules: AutoResponseRule[]\n ): Promise<void> {\n await this.waitForReady();\n\n const serialized = rules.map((r) => this.serializeRule(r));\n this.sendCommand({ cmd: 'setRules', id: sessionId, rules: serialized });\n\n await this.createPending(`setRules:${sessionId}`);\n }\n\n /**\n * Get all auto-response rules for a session.\n */\n async getAutoResponseRules(sessionId: string): Promise<AutoResponseRule[]> {\n await this.waitForReady();\n\n this.sendCommand({ cmd: 'getRules', id: sessionId });\n\n const rules = (await this.createPending(\n `getRules:${sessionId}`\n )) as AutoResponseRule[];\n return rules;\n }\n\n /**\n * Select a TUI menu option by index (0-based) in a session.\n */\n async selectMenuOption(id: string, optionIndex: number): Promise<void> {\n await this.waitForReady();\n\n this.sendCommand({ cmd: 'selectMenuOption', id, optionIndex });\n\n await this.createPending(`selectMenuOption:${id}`);\n }\n\n /**\n * Clear all auto-response rules for a session.\n */\n async clearAutoResponseRules(sessionId: string): Promise<void> {\n await this.waitForReady();\n\n this.sendCommand({ cmd: 'clearRules', id: sessionId });\n\n await this.createPending(`clearRules:${sessionId}`);\n }\n\n /**\n * Shutdown the worker and all sessions\n */\n async shutdown(): Promise<void> {\n if (!this.worker) return;\n\n this.sendCommand({ cmd: 'shutdown' });\n\n await this.createPending('shutdown', 10000).catch(() => {\n // Force kill if shutdown times out\n this.worker?.kill('SIGKILL');\n });\n }\n\n /**\n * Restart the worker process\n */\n async restart(): Promise<void> {\n await this.shutdown();\n\n this.sessions.clear();\n this.ready = false;\n this.readyPromise = new Promise((resolve) => {\n this.readyResolve = resolve;\n });\n\n this.startWorker();\n await this.waitForReady();\n }\n}\n\n/**\n * Detect if running in Bun\n */\nexport function isBun(): boolean {\n // Bun 1.1.24+ sets process.versions.bun (lowercase)\n return typeof process !== 'undefined' && 'bun' in process.versions;\n}\n\n/**\n * Create the appropriate PTY manager based on runtime\n */\nexport function createPTYManager(\n options?: BunPTYManagerOptions\n): BunCompatiblePTYManager {\n return new BunCompatiblePTYManager(options);\n}\n","/**\n * Lazy runtime check for node-pty native addon.\n *\n * Called once before the first PTY spawn. Ensures the native binary is\n * loadable and spawn-helper permissions are correct.\n *\n * 1. Finds the binary — checks for prebuilt pty.node under\n * prebuilds/<platform>-<arch>/ (node-pty >=1.0), then falls back to\n * checking for a node-gyp compiled build/Release/pty.node\n * 2. Fixes spawn-helper permissions — bun install can strip execute\n * bits from the spawn-helper Mach-O binary, causing posix_spawnp\n * failed at runtime. The script chmod 755s all spawn-helpers under\n * prebuilds/\n * 3. Rebuilds if missing — if no binary is found at all, runs\n * node-gyp rebuild as a last resort (with a 2-minute timeout)\n */\n\nimport { execSync } from 'node:child_process';\nimport { chmodSync, existsSync, readdirSync, statSync } from 'node:fs';\nimport { dirname, join, relative } from 'node:path';\n\nconst TAG = '[pty-preflight]';\nconst platformArch = `${process.platform}-${process.arch}`;\n\nlet checked = false;\n\n// ─── Locate node-pty ─────────────────────────────────────────────────────────\n\nfunction findNodePtyRoots(): string[] {\n const roots: string[] = [];\n\n // Try to resolve node-pty through the standard require resolution\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const nodePtyMain = require.resolve('node-pty');\n const nodePtyRoot = dirname(dirname(nodePtyMain));\n if (existsSync(join(nodePtyRoot, 'package.json'))) {\n roots.push(nodePtyRoot);\n }\n } catch {\n // not resolvable directly — try known paths\n }\n\n // Also check common nested locations relative to this package\n const packageRoot = join(__dirname, '..');\n const candidates = [\n join(packageRoot, 'node_modules', 'node-pty'),\n // Monorepo hoisted\n join(packageRoot, '..', 'node-pty'),\n join(packageRoot, '..', '..', 'node-pty'),\n ];\n\n for (const candidate of candidates) {\n if (\n existsSync(join(candidate, 'package.json')) &&\n !roots.includes(candidate)\n ) {\n roots.push(candidate);\n }\n }\n\n return roots;\n}\n\n// ─── Find native binary ─────────────────────────────────────────────────────\n\nfunction findNativeBinary(\n nodePtyRoot: string\n): { type: string; path: string } | null {\n // Prebuilt (node-pty >= 1.0)\n const prebuildPath = join(nodePtyRoot, 'prebuilds', platformArch, 'pty.node');\n if (existsSync(prebuildPath)) {\n return { type: 'prebuild', path: prebuildPath };\n }\n\n // node-gyp compiled\n const gypPath = join(nodePtyRoot, 'build', 'Release', 'pty.node');\n if (existsSync(gypPath)) {\n return { type: 'gyp', path: gypPath };\n }\n\n return null;\n}\n\n// ─── Fix spawn-helper permissions ────────────────────────────────────────────\n\nfunction fixSpawnHelpers(\n nodePtyRoot: string,\n log: (msg: string) => void\n): void {\n if (process.platform === 'win32') return;\n\n const prebuildsDir = join(nodePtyRoot, 'prebuilds');\n if (!existsSync(prebuildsDir)) return;\n\n try {\n for (const entry of readdirSync(prebuildsDir)) {\n const helperPath = join(prebuildsDir, entry, 'spawn-helper');\n if (existsSync(helperPath)) {\n try {\n const stat = statSync(helperPath);\n if ((stat.mode & 0o111) === 0) {\n chmodSync(helperPath, 0o755);\n log(\n `${TAG} Fixed spawn-helper permissions: ${relative(nodePtyRoot, helperPath)}`\n );\n }\n } catch {\n // Permission denied — not fatal\n }\n }\n }\n } catch {\n // prebuilds dir not readable\n }\n}\n\n// ─── Rebuild if missing ──────────────────────────────────────────────────────\n\nfunction rebuildNodePty(\n nodePtyRoot: string,\n log: (msg: string) => void\n): boolean {\n log(`${TAG} No native binary found — attempting node-gyp rebuild...`);\n try {\n execSync('node-gyp rebuild', {\n cwd: nodePtyRoot,\n stdio: 'pipe',\n timeout: 120_000,\n });\n log(`${TAG} node-gyp rebuild succeeded`);\n return true;\n } catch (err) {\n log(\n `${TAG} node-gyp rebuild failed: ${err instanceof Error ? err.message : err}`\n );\n return false;\n }\n}\n\n// ─── Public API ──────────────────────────────────────────────────────────────\n\n/**\n * Ensure node-pty is usable. Called once before first spawn.\n * Idempotent — subsequent calls are no-ops.\n *\n * @param log - logger function (defaults to console.log)\n * @throws Error if no native binary can be found or built\n */\nexport function ensurePty(log: (msg: string) => void = console.log): void {\n if (checked) return;\n checked = true;\n\n const roots = findNodePtyRoots();\n\n if (roots.length === 0) {\n throw new Error(\n `${TAG} node-pty not found. Install it with: npm install node-pty`\n );\n }\n\n let anyBinaryFound = false;\n\n for (const root of roots) {\n const binary = findNativeBinary(root);\n\n if (binary) {\n log(`${TAG} Found ${binary.type} binary for ${platformArch}`);\n anyBinaryFound = true;\n }\n\n // Always fix spawn-helper permissions\n fixSpawnHelpers(root, log);\n\n // Rebuild if no binary at this location\n if (!binary) {\n if (rebuildNodePty(root, log)) {\n if (findNativeBinary(root)) {\n anyBinaryFound = true;\n }\n }\n }\n\n // Stop after first location with a working binary\n if (anyBinaryFound) break;\n }\n\n if (!anyBinaryFound) {\n throw new Error(\n `${TAG} No node-pty native binary available for ${platformArch}. ` +\n `Try: cd node_modules/node-pty && node-gyp rebuild`\n );\n }\n}\n","/**\n * PTY Manager\n *\n * Manages multiple PTY sessions for CLI tools.\n */\n\nimport { EventEmitter } from 'node:events';\nimport type { CLIAdapter } from './adapters/adapter-interface';\nimport { AdapterRegistry } from './adapters/adapter-registry';\nimport { consoleLogger } from './logger';\nimport { PTYSession } from './pty-session';\nimport type {\n AuthRequiredInfo,\n AutoResponseRule,\n BlockingPromptInfo,\n Logger,\n LogOptions,\n PTYManagerConfig,\n SessionFilter,\n SessionHandle,\n SessionMessage,\n SessionStatus,\n SpawnConfig,\n StallClassification,\n StopOptions,\n TerminalAttachment,\n ToolRunningInfo,\n} from './types';\n\nexport interface PTYManagerEvents {\n session_started: (session: SessionHandle) => void;\n session_ready: (session: SessionHandle) => void;\n session_stopped: (session: SessionHandle, reason: string) => void;\n session_error: (session: SessionHandle, error: string) => void;\n login_required: (\n session: SessionHandle,\n instructions?: string,\n url?: string\n ) => void;\n auth_required: (session: SessionHandle, info: AuthRequiredInfo) => void;\n blocking_prompt: (\n session: SessionHandle,\n promptInfo: BlockingPromptInfo,\n autoResponded: boolean\n ) => void;\n message: (message: SessionMessage) => void;\n question: (session: SessionHandle, question: string) => void;\n stall_detected: (\n session: SessionHandle,\n recentOutput: string,\n stallDurationMs: number\n ) => void;\n session_status_changed: (session: SessionHandle) => void;\n task_complete: (session: SessionHandle) => void;\n tool_running: (session: SessionHandle, info: ToolRunningInfo) => void;\n}\n\nexport class PTYManager extends EventEmitter {\n private sessions: Map<string, PTYSession> = new Map();\n private outputLogs: Map<string, string[]> = new Map();\n private maxLogLines: number;\n private logger: Logger;\n public readonly adapters: AdapterRegistry;\n\n // Stall detection config\n private _stallDetectionEnabled: boolean;\n private _stallTimeoutMs: number;\n private _onStallClassify?: (\n sessionId: string,\n recentOutput: string,\n stallDurationMs: number\n ) => Promise<StallClassification | null>;\n\n constructor(config: PTYManagerConfig = {}) {\n super();\n this.adapters = new AdapterRegistry();\n this.logger = config.logger || consoleLogger;\n this.maxLogLines = config.maxLogLines || 1000;\n this._stallDetectionEnabled = config.stallDetectionEnabled ?? false;\n this._stallTimeoutMs = config.stallTimeoutMs ?? 8000;\n this._onStallClassify = config.onStallClassify;\n }\n\n /**\n * Register a CLI adapter\n */\n registerAdapter(adapter: CLIAdapter): void {\n this.adapters.register(adapter);\n }\n\n /**\n * Spawn a new PTY session\n */\n async spawn(config: SpawnConfig): Promise<SessionHandle> {\n // Get adapter for this type\n const adapter = this.adapters.get(config.type);\n if (!adapter) {\n throw new Error(\n `No adapter found for type: ${config.type}. Registered adapters: ${this.adapters.list().join(', ') || 'none'}`\n );\n }\n\n // Check if ID already exists\n if (config.id && this.sessions.has(config.id)) {\n throw new Error(`Session with ID ${config.id} already exists`);\n }\n\n this.logger.info(\n { type: config.type, name: config.name },\n 'Spawning session'\n );\n\n // Create session\n const session = new PTYSession(\n adapter,\n config,\n this.logger,\n this._stallDetectionEnabled,\n this._stallTimeoutMs\n );\n\n // Set up event forwarding\n this.setupSessionEvents(session);\n\n // Store session\n this.sessions.set(session.id, session);\n this.outputLogs.set(session.id, []);\n\n // Start the session\n await session.start();\n\n const handle = session.toHandle();\n this.emit('session_started', handle);\n\n return handle;\n }\n\n /**\n * Set up event handlers for a session\n */\n private setupSessionEvents(session: PTYSession): void {\n session.on('output', (data: string) => {\n // Store in log buffer\n const logs = this.outputLogs.get(session.id) || [];\n const lines = data.split('\\n');\n logs.push(...lines);\n\n // Trim to max lines\n while (logs.length > this.maxLogLines) {\n logs.shift();\n }\n this.outputLogs.set(session.id, logs);\n });\n\n session.on('ready', () => {\n this.emit('session_ready', session.toHandle());\n });\n\n session.on('login_required', (instructions?: string, url?: string) => {\n this.emit('login_required', session.toHandle(), instructions, url);\n });\n\n session.on('auth_required', (info: AuthRequiredInfo) => {\n this.emit('auth_required', session.toHandle(), info);\n });\n\n session.on(\n 'blocking_prompt',\n (promptInfo: BlockingPromptInfo, autoResponded: boolean) => {\n this.emit(\n 'blocking_prompt',\n session.toHandle(),\n promptInfo,\n autoResponded\n );\n }\n );\n\n session.on('message', (message: SessionMessage) => {\n this.emit('message', message);\n });\n\n session.on('question', (question: string) => {\n this.emit('question', session.toHandle(), question);\n });\n\n session.on('exit', (code: number) => {\n const reason = code === 0 ? 'normal exit' : `exit code ${code}`;\n this.emit('session_stopped', session.toHandle(), reason);\n });\n\n session.on('error', (error: Error) => {\n this.emit('session_error', session.toHandle(), error.message);\n });\n\n session.on('status_changed', () => {\n // Refresh the handle so the parent sees the updated status\n this.emit('session_status_changed', session.toHandle());\n });\n\n session.on('task_complete', () => {\n this.emit('task_complete', session.toHandle());\n });\n\n session.on('tool_running', (info: ToolRunningInfo) => {\n this.emit('tool_running', session.toHandle(), info);\n });\n\n session.on(\n 'stall_detected',\n (recentOutput: string, stallDurationMs: number) => {\n const handle = session.toHandle();\n this.emit('stall_detected', handle, recentOutput, stallDurationMs);\n\n // Call external classifier if configured\n if (this._onStallClassify) {\n // Sanitize output before passing to LLM classifier to mitigate prompt injection.\n // Truncate to 1500 chars and strip sequences that could be used to manipulate the classifier.\n const sanitized = recentOutput\n .slice(-1500)\n .replace(\n /\\b(ignore|disregard|forget)\\s+(all\\s+)?(previous|above|prior)\\s+(instructions?|prompts?|rules?)\\b/gi,\n '[REDACTED]'\n )\n .replace(\n /\\b(you\\s+are|act\\s+as|pretend\\s+to\\s+be|you\\s+must|system\\s*:)\\b/gi,\n '[REDACTED]'\n );\n this._onStallClassify(session.id, sanitized, stallDurationMs)\n .then((classification) => {\n session.handleStallClassification(classification);\n })\n .catch((err) => {\n this.logger.error(\n { sessionId: session.id, error: err },\n 'Stall classification callback failed'\n );\n // Reset timer so detection continues\n session.handleStallClassification(null);\n });\n }\n }\n );\n }\n\n /**\n * Stop a session\n */\n async stop(sessionId: string, options?: StopOptions): Promise<void> {\n const session = this.sessions.get(sessionId);\n if (!session) {\n throw new Error(`Session not found: ${sessionId}`);\n }\n\n this.logger.info({ sessionId, force: options?.force }, 'Stopping session');\n\n const timeout = options?.timeout || 5000;\n\n return new Promise((resolve) => {\n const timer = setTimeout(() => {\n // Force kill if graceful shutdown times out\n session.kill('SIGKILL');\n resolve();\n }, timeout);\n\n session.once('exit', () => {\n clearTimeout(timer);\n session.removeAllListeners();\n this.sessions.delete(sessionId);\n this.outputLogs.delete(sessionId);\n resolve();\n });\n\n // Send graceful signal\n session.kill(options?.force ? 'SIGKILL' : 'SIGTERM');\n });\n }\n\n /**\n * Stop all sessions\n */\n async stopAll(options?: StopOptions): Promise<void> {\n const stopPromises = Array.from(this.sessions.keys()).map((id) =>\n this.stop(id, options).catch((err) => {\n this.logger.warn(\n { sessionId: id, error: err },\n 'Error stopping session'\n );\n })\n );\n\n await Promise.all(stopPromises);\n }\n\n /**\n * Get a session by ID\n */\n get(sessionId: string): SessionHandle | null {\n const session = this.sessions.get(sessionId);\n return session ? session.toHandle() : null;\n }\n\n /**\n * List all sessions\n */\n list(filter?: SessionFilter): SessionHandle[] {\n const handles: SessionHandle[] = [];\n\n for (const session of this.sessions.values()) {\n const handle = session.toHandle();\n\n // Apply filters\n if (filter) {\n if (filter.status) {\n const statuses = Array.isArray(filter.status)\n ? filter.status\n : [filter.status];\n if (!statuses.includes(handle.status)) continue;\n }\n\n if (filter.type) {\n const types = Array.isArray(filter.type)\n ? filter.type\n : [filter.type];\n if (!types.includes(handle.type)) continue;\n }\n }\n\n handles.push(handle);\n }\n\n return handles;\n }\n\n /**\n * Send a message to a session\n */\n send(sessionId: string, message: string): SessionMessage {\n const session = this.sessions.get(sessionId);\n if (!session) {\n throw new Error(`Session not found: ${sessionId}`);\n }\n\n return session.send(message);\n }\n\n /**\n * Get logs for a session\n */\n async *logs(sessionId: string, options?: LogOptions): AsyncIterable<string> {\n const logBuffer = this.outputLogs.get(sessionId);\n if (!logBuffer) {\n throw new Error(`Session not found: ${sessionId}`);\n }\n\n const lines = options?.tail ? logBuffer.slice(-options.tail) : logBuffer;\n\n for (const line of lines) {\n yield line;\n }\n }\n\n /**\n * Get metrics for a session\n */\n metrics(\n sessionId: string\n ): { uptime?: number; messageCount?: number } | null {\n const session = this.sessions.get(sessionId);\n if (!session) {\n return null;\n }\n\n const handle = session.toHandle();\n const uptime = handle.startedAt\n ? Math.floor((Date.now() - handle.startedAt.getTime()) / 1000)\n : undefined;\n\n return { uptime };\n }\n\n /**\n * Shutdown manager and stop all sessions\n */\n async shutdown(): Promise<void> {\n this.logger.info(\n { count: this.sessions.size },\n 'Shutting down all sessions'\n );\n\n await this.stopAll({ timeout: 3000 });\n\n this.sessions.clear();\n this.outputLogs.clear();\n }\n\n /**\n * Get count of sessions by status\n */\n getStatusCounts(): Record<SessionStatus, number> {\n const counts: Record<SessionStatus, number> = {\n pending: 0,\n starting: 0,\n authenticating: 0,\n ready: 0,\n busy: 0,\n stopping: 0,\n stopped: 0,\n error: 0,\n };\n\n for (const session of this.sessions.values()) {\n counts[session.status]++;\n }\n\n return counts;\n }\n\n /**\n * Attach to a session's terminal for raw I/O streaming\n */\n attachTerminal(sessionId: string): TerminalAttachment | null {\n const session = this.sessions.get(sessionId);\n if (!session) {\n return null;\n }\n\n return {\n /**\n * Subscribe to raw terminal output\n * Returns an unsubscribe function\n */\n onData: (callback: (data: string) => void) => {\n session.on('output', callback);\n return () => session.off('output', callback);\n },\n\n /**\n * Write raw data to terminal (no formatting applied)\n */\n write: (data: string) => {\n session.writeRaw(data);\n },\n\n /**\n * Resize the terminal\n */\n resize: (cols: number, rows: number) => {\n session.resize(cols, rows);\n },\n };\n }\n\n /**\n * Check if a session exists\n */\n has(sessionId: string): boolean {\n return this.sessions.has(sessionId);\n }\n\n /**\n * Get the underlying PTYSession (for advanced use)\n */\n getSession(sessionId: string): PTYSession | undefined {\n return this.sessions.get(sessionId);\n }\n\n /**\n * Whether the adapter currently classifies the session as actively\n * processing work (e.g. Codex's \"esc to interrupt\" status row).\n *\n * Orchestrators (like milady's swarm idle watchdog) should consult\n * this before assuming a session is idle based on output byte diffs,\n * which are fooled by TUIs that redraw the same status row in place.\n *\n * Returns `false` for unknown sessions or adapters that don't\n * implement `detectLoading`.\n */\n isSessionLoading(sessionId: string): boolean {\n return this.sessions.get(sessionId)?.isLoading() ?? false;\n }\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Stall Detection Configuration\n // ─────────────────────────────────────────────────────────────────────────────\n\n /**\n * Configure stall detection at runtime.\n * Affects newly spawned sessions only — existing sessions keep their config.\n */\n configureStallDetection(\n enabled: boolean,\n timeoutMs?: number,\n classify?: (\n sessionId: string,\n recentOutput: string,\n stallDurationMs: number\n ) => Promise<StallClassification | null>\n ): void {\n this._stallDetectionEnabled = enabled;\n if (timeoutMs !== undefined) {\n this._stallTimeoutMs = timeoutMs;\n }\n if (classify !== undefined) {\n this._onStallClassify = classify;\n }\n }\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Runtime Auto-Response Rules API\n // ─────────────────────────────────────────────────────────────────────────────\n\n /**\n * Add an auto-response rule to a session.\n * Session rules are checked before adapter rules.\n */\n addAutoResponseRule(sessionId: string, rule: AutoResponseRule): void {\n const session = this.sessions.get(sessionId);\n if (!session) {\n throw new Error(`Session not found: ${sessionId}`);\n }\n session.addAutoResponseRule(rule);\n }\n\n /**\n * Remove an auto-response rule from a session by pattern.\n * Returns true if a rule was removed.\n */\n removeAutoResponseRule(sessionId: string, pattern: RegExp): boolean {\n const session = this.sessions.get(sessionId);\n if (!session) {\n throw new Error(`Session not found: ${sessionId}`);\n }\n return session.removeAutoResponseRule(pattern);\n }\n\n /**\n * Set all auto-response rules for a session, replacing existing ones.\n */\n setAutoResponseRules(sessionId: string, rules: AutoResponseRule[]): void {\n const session = this.sessions.get(sessionId);\n if (!session) {\n throw new Error(`Session not found: ${sessionId}`);\n }\n session.setAutoResponseRules(rules);\n }\n\n /**\n * Get all auto-response rules for a session.\n */\n getAutoResponseRules(sessionId: string): AutoResponseRule[] {\n const session = this.sessions.get(sessionId);\n if (!session) {\n throw new Error(`Session not found: ${sessionId}`);\n }\n return session.getAutoResponseRules();\n }\n\n /**\n * Clear all auto-response rules for a session.\n */\n clearAutoResponseRules(sessionId: string): void {\n const session = this.sessions.get(sessionId);\n if (!session) {\n throw new Error(`Session not found: ${sessionId}`);\n }\n session.clearAutoResponseRules();\n }\n}\n","/**\n * Console-based logger fallback.\n *\n * Shared between PTYManager and PTYSession to avoid duplication.\n * Supports both pino-style (context, message) and printf-style (message, context) calls.\n */\n\nimport type { Logger } from './types';\n\nexport const consoleLogger: Logger = {\n debug: (...args: unknown[]) => {\n if (typeof args[0] === 'string') {\n console.debug(args[0], args[1]);\n } else {\n console.debug(args[1], args[0]);\n }\n },\n info: (...args: unknown[]) => {\n if (typeof args[0] === 'string') {\n console.info(args[0], args[1]);\n } else {\n console.info(args[1], args[0]);\n }\n },\n warn: (...args: unknown[]) => {\n if (typeof args[0] === 'string') {\n console.warn(args[0], args[1]);\n } else {\n console.warn(args[1], args[0]);\n }\n },\n error: (...args: unknown[]) => {\n if (typeof args[0] === 'string') {\n console.error(args[0], args[1]);\n } else {\n console.error(args[1], args[0]);\n }\n },\n};\n","/**\n * PTY Session\n *\n * Manages a single pseudo-terminal session for a CLI tool.\n */\n\nimport { randomUUID } from 'node:crypto';\nimport { EventEmitter } from 'node:events';\nimport type * as ptyModule from 'node-pty';\nimport type { CLIAdapter } from './adapters/adapter-interface';\nimport { ensurePty } from './ensure-pty';\nimport { consoleLogger } from './logger';\nimport type {\n AuthRequiredInfo,\n AutoResponseRule,\n BlockingPromptInfo,\n Logger,\n LoginDetection,\n SessionHandle,\n SessionMessage,\n SessionStatus,\n SpawnConfig,\n StallClassification,\n ToolRunningInfo,\n} from './types';\n\n// Lazy-load node-pty to avoid issues in environments where it's not installed\nlet ptyCache: typeof ptyModule | null = null;\nfunction loadPty(): typeof ptyModule {\n if (!ptyCache) {\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n ptyCache = require('node-pty') as typeof ptyModule;\n } catch {\n throw new Error(\n 'node-pty is required but not installed. Run: npm install node-pty'\n );\n }\n }\n return ptyCache!;\n}\n\nexport interface PTYSessionEvents {\n output: (data: string) => void;\n ready: () => void;\n login_required: (instructions?: string, url?: string) => void;\n auth_required: (info: AuthRequiredInfo) => void;\n blocking_prompt: (prompt: BlockingPromptInfo, autoResponded: boolean) => void;\n message: (message: SessionMessage) => void;\n question: (question: string) => void;\n exit: (code: number) => void;\n error: (error: Error) => void;\n stall_detected: (recentOutput: string, stallDurationMs: number) => void;\n status_changed: (status: SessionStatus) => void;\n task_complete: () => void;\n tool_running: (info: ToolRunningInfo) => void;\n}\n\n/**\n * Generate a unique ID\n */\nfunction generateId(): string {\n return `pty-${Date.now()}-${randomUUID().slice(0, 8)}`;\n}\n\n/**\n * Special key mappings to escape sequences\n *\n * Modifier codes for arrows/function keys:\n * 2 = Shift, 3 = Alt, 4 = Shift+Alt, 5 = Ctrl, 6 = Ctrl+Shift, 7 = Ctrl+Alt, 8 = Ctrl+Alt+Shift\n */\nexport const SPECIAL_KEYS: Record<string, string> = {\n // Control keys (Ctrl+letter = ASCII control code)\n 'ctrl+a': '\\x01',\n 'ctrl+b': '\\x02',\n 'ctrl+c': '\\x03',\n 'ctrl+d': '\\x04',\n 'ctrl+e': '\\x05',\n 'ctrl+f': '\\x06',\n 'ctrl+g': '\\x07',\n 'ctrl+h': '\\x08',\n 'ctrl+i': '\\x09',\n 'ctrl+j': '\\x0a',\n 'ctrl+k': '\\x0b',\n 'ctrl+l': '\\x0c',\n 'ctrl+m': '\\x0d',\n 'ctrl+n': '\\x0e',\n 'ctrl+o': '\\x0f',\n 'ctrl+p': '\\x10',\n 'ctrl+q': '\\x11',\n 'ctrl+r': '\\x12',\n 'ctrl+s': '\\x13',\n 'ctrl+t': '\\x14',\n 'ctrl+u': '\\x15',\n 'ctrl+v': '\\x16',\n 'ctrl+w': '\\x17',\n 'ctrl+x': '\\x18',\n 'ctrl+y': '\\x19',\n 'ctrl+z': '\\x1a',\n 'ctrl+[': '\\x1b',\n 'ctrl+\\\\': '\\x1c',\n 'ctrl+]': '\\x1d',\n 'ctrl+^': '\\x1e',\n 'ctrl+_': '\\x1f',\n\n // Alt+letter (Meta key = ESC + letter)\n 'alt+a': '\\x1ba',\n 'alt+b': '\\x1bb',\n 'alt+c': '\\x1bc',\n 'alt+d': '\\x1bd',\n 'alt+e': '\\x1be',\n 'alt+f': '\\x1bf',\n 'alt+g': '\\x1bg',\n 'alt+h': '\\x1bh',\n 'alt+i': '\\x1bi',\n 'alt+j': '\\x1bj',\n 'alt+k': '\\x1bk',\n 'alt+l': '\\x1bl',\n 'alt+m': '\\x1bm',\n 'alt+n': '\\x1bn',\n 'alt+o': '\\x1bo',\n 'alt+p': '\\x1bp',\n 'alt+q': '\\x1bq',\n 'alt+r': '\\x1br',\n 'alt+s': '\\x1bs',\n 'alt+t': '\\x1bt',\n 'alt+u': '\\x1bu',\n 'alt+v': '\\x1bv',\n 'alt+w': '\\x1bw',\n 'alt+x': '\\x1bx',\n 'alt+y': '\\x1by',\n 'alt+z': '\\x1bz',\n 'alt+backspace': '\\x1b\\x7f', // Delete word backward\n\n // Navigation - plain\n up: '\\x1b[A',\n down: '\\x1b[B',\n right: '\\x1b[C',\n left: '\\x1b[D',\n home: '\\x1b[H',\n end: '\\x1b[F',\n pageup: '\\x1b[5~',\n pagedown: '\\x1b[6~',\n\n // Navigation - with Shift (modifier 2)\n 'shift+up': '\\x1b[1;2A',\n 'shift+down': '\\x1b[1;2B',\n 'shift+right': '\\x1b[1;2C',\n 'shift+left': '\\x1b[1;2D',\n 'shift+home': '\\x1b[1;2H',\n 'shift+end': '\\x1b[1;2F',\n 'shift+pageup': '\\x1b[5;2~',\n 'shift+pagedown': '\\x1b[6;2~',\n\n // Navigation - with Alt (modifier 3)\n 'alt+up': '\\x1b[1;3A',\n 'alt+down': '\\x1b[1;3B',\n 'alt+right': '\\x1b[1;3C', // Forward word\n 'alt+left': '\\x1b[1;3D', // Backward word\n\n // Navigation - with Ctrl (modifier 5)\n 'ctrl+up': '\\x1b[1;5A',\n 'ctrl+down': '\\x1b[1;5B',\n 'ctrl+right': '\\x1b[1;5C', // Forward word\n 'ctrl+left': '\\x1b[1;5D', // Backward word\n 'ctrl+home': '\\x1b[1;5H',\n 'ctrl+end': '\\x1b[1;5F',\n\n // Navigation - with Ctrl+Shift (modifier 6) - select word\n 'ctrl+shift+up': '\\x1b[1;6A',\n 'ctrl+shift+down': '\\x1b[1;6B',\n 'ctrl+shift+right': '\\x1b[1;6C',\n 'ctrl+shift+left': '\\x1b[1;6D',\n 'ctrl+shift+home': '\\x1b[1;6H',\n 'ctrl+shift+end': '\\x1b[1;6F',\n\n // Navigation - with Shift+Alt (modifier 4)\n 'shift+alt+up': '\\x1b[1;4A',\n 'shift+alt+down': '\\x1b[1;4B',\n 'shift+alt+right': '\\x1b[1;4C',\n 'shift+alt+left': '\\x1b[1;4D',\n\n // Editing\n enter: '\\r',\n return: '\\r',\n tab: '\\t',\n 'shift+tab': '\\x1b[Z', // Reverse tab\n backspace: '\\x7f',\n delete: '\\x1b[3~',\n 'shift+delete': '\\x1b[3;2~',\n 'ctrl+delete': '\\x1b[3;5~', // Delete word forward\n insert: '\\x1b[2~',\n escape: '\\x1b',\n esc: '\\x1b',\n space: ' ',\n\n // Function keys - plain\n f1: '\\x1bOP',\n f2: '\\x1bOQ',\n f3: '\\x1bOR',\n f4: '\\x1bOS',\n f5: '\\x1b[15~',\n f6: '\\x1b[17~',\n f7: '\\x1b[18~',\n f8: '\\x1b[19~',\n f9: '\\x1b[20~',\n f10: '\\x1b[21~',\n f11: '\\x1b[23~',\n f12: '\\x1b[24~',\n\n // Function keys - with Shift (modifier 2)\n 'shift+f1': '\\x1b[1;2P',\n 'shift+f2': '\\x1b[1;2Q',\n 'shift+f3': '\\x1b[1;2R',\n 'shift+f4': '\\x1b[1;2S',\n 'shift+f5': '\\x1b[15;2~',\n 'shift+f6': '\\x1b[17;2~',\n 'shift+f7': '\\x1b[18;2~',\n 'shift+f8': '\\x1b[19;2~',\n 'shift+f9': '\\x1b[20;2~',\n 'shift+f10': '\\x1b[21;2~',\n 'shift+f11': '\\x1b[23;2~',\n 'shift+f12': '\\x1b[24;2~',\n\n // Function keys - with Ctrl (modifier 5)\n 'ctrl+f1': '\\x1b[1;5P',\n 'ctrl+f2': '\\x1b[1;5Q',\n 'ctrl+f3': '\\x1b[1;5R',\n 'ctrl+f4': '\\x1b[1;5S',\n 'ctrl+f5': '\\x1b[15;5~',\n 'ctrl+f6': '\\x1b[17;5~',\n 'ctrl+f7': '\\x1b[18;5~',\n 'ctrl+f8': '\\x1b[19;5~',\n 'ctrl+f9': '\\x1b[20;5~',\n 'ctrl+f10': '\\x1b[21;5~',\n 'ctrl+f11': '\\x1b[23;5~',\n 'ctrl+f12': '\\x1b[24;5~',\n};\n\n/**\n * Bracketed paste mode escape sequences\n */\nconst BRACKETED_PASTE_START = '\\x1b[200~';\nconst BRACKETED_PASTE_END = '\\x1b[201~';\n\nexport class PTYSession extends EventEmitter {\n private ptyProcess: ptyModule.IPty | null = null;\n private outputBuffer: string = '';\n private _status: SessionStatus = 'pending';\n private _startedAt: Date | null = null;\n private _lastActivityAt: Date | null = null;\n private messageCounter: number = 0;\n private logger: Logger;\n private sessionRules: AutoResponseRule[] = [];\n private _firedOnceRules: Set<string> = new Set();\n private _lastBlockingPromptHash: string | null = null;\n private _lastBlockingPromptEmitAt = 0;\n private static readonly BLOCKING_PROMPT_DEBOUNCE_MS = 250;\n private _ruleOverrides: Map<string, Partial<AutoResponseRule>> = new Map();\n private _disabledRulePatterns: Set<string> = new Set();\n\n // Stall detection\n private _stallTimer: ReturnType<typeof setTimeout> | null = null;\n private _stallTimeoutMs: number;\n private _stallDetectionEnabled: boolean;\n private _lastStallHash: string | null = null;\n private _stallStartedAt: number | null = null;\n private _lastContentHash: string | null = null;\n private _stallBackoffMs: number = 0; // Initialized in constructor from _stallTimeoutMs\n private static readonly MAX_STALL_BACKOFF_MS = 30_000;\n private _stallEmissionCount: number = 0;\n private static readonly MAX_STALL_EMISSIONS = 5;\n\n // Task completion detection (idle detection when busy)\n private _taskCompleteTimer: ReturnType<typeof setTimeout> | null = null;\n private _taskCompletePending = false;\n private static readonly TASK_COMPLETE_DEBOUNCE_MS = 1500;\n\n // Ready detection settle delay — defers session_ready until output goes quiet\n private _readySettleTimer: ReturnType<typeof setTimeout> | null = null;\n private _readySettlePending = false;\n\n // Tool running deduplication — only emit when tool changes\n private _lastToolRunningName: string | null = null;\n\n // Deferred output processing — prevents node-pty's synchronous data\n // delivery from starving the event loop (timers, I/O callbacks, etc.)\n private _processScheduled = false;\n\n // Output buffer cap — prevents unbounded growth during long tasks\n private static readonly MAX_OUTPUT_BUFFER = 100_000; // 100 KB\n\n public readonly id: string;\n public readonly config: SpawnConfig;\n\n constructor(\n private adapter: CLIAdapter,\n config: SpawnConfig,\n logger?: Logger,\n stallDetectionEnabled?: boolean,\n defaultStallTimeoutMs?: number\n ) {\n super();\n this.id = config.id || generateId();\n this.config = { ...config, id: this.id };\n this.logger = logger || consoleLogger;\n this._stallDetectionEnabled = stallDetectionEnabled ?? false;\n this._stallTimeoutMs =\n config.stallTimeoutMs ?? defaultStallTimeoutMs ?? 8000;\n this._stallBackoffMs = this._stallTimeoutMs;\n\n // Process rule overrides from spawn config\n if (config.ruleOverrides) {\n for (const [key, value] of Object.entries(config.ruleOverrides)) {\n if (value === null) {\n this._disabledRulePatterns.add(key);\n } else {\n this._ruleOverrides.set(key, value);\n }\n }\n }\n }\n\n get status(): SessionStatus {\n return this._status;\n }\n\n get pid(): number | undefined {\n return this.ptyProcess?.pid;\n }\n\n get startedAt(): Date | undefined {\n return this._startedAt ?? undefined;\n }\n\n get lastActivityAt(): Date | undefined {\n return this._lastActivityAt ?? undefined;\n }\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Runtime Auto-Response Rules API\n // ─────────────────────────────────────────────────────────────────────────────\n\n /**\n * Add an auto-response rule to this session.\n * Session rules are checked before adapter rules.\n */\n addAutoResponseRule(rule: AutoResponseRule): void {\n // Check for duplicate pattern\n const existingIndex = this.sessionRules.findIndex(\n (r) =>\n r.pattern.source === rule.pattern.source &&\n r.pattern.flags === rule.pattern.flags\n );\n\n if (existingIndex >= 0) {\n // Replace existing rule with same pattern\n this.sessionRules[existingIndex] = rule;\n this.logger.debug(\n { sessionId: this.id, pattern: rule.pattern.source, type: rule.type },\n 'Replaced existing auto-response rule'\n );\n } else {\n this.sessionRules.push(rule);\n this.logger.debug(\n { sessionId: this.id, pattern: rule.pattern.source, type: rule.type },\n 'Added auto-response rule'\n );\n }\n }\n\n /**\n * Remove an auto-response rule by pattern.\n * Returns true if a rule was removed.\n */\n removeAutoResponseRule(pattern: RegExp): boolean {\n const initialLength = this.sessionRules.length;\n this.sessionRules = this.sessionRules.filter(\n (r) =>\n !(\n r.pattern.source === pattern.source &&\n r.pattern.flags === pattern.flags\n )\n );\n\n const removed = this.sessionRules.length < initialLength;\n if (removed) {\n this.logger.debug(\n { sessionId: this.id, pattern: pattern.source },\n 'Removed auto-response rule'\n );\n }\n return removed;\n }\n\n /**\n * Set all session auto-response rules, replacing existing ones.\n */\n setAutoResponseRules(rules: AutoResponseRule[]): void {\n this.sessionRules = [...rules];\n this.logger.debug(\n { sessionId: this.id, count: rules.length },\n 'Set auto-response rules'\n );\n }\n\n /**\n * Get all session auto-response rules.\n */\n getAutoResponseRules(): AutoResponseRule[] {\n return [...this.sessionRules];\n }\n\n /**\n * Clear all session auto-response rules.\n */\n clearAutoResponseRules(): void {\n this.sessionRules = [];\n this.logger.debug({ sessionId: this.id }, 'Cleared auto-response rules');\n }\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Stall Detection\n // ─────────────────────────────────────────────────────────────────────────────\n\n /**\n * Start or reset the stall detection timer.\n * Active when status is \"busy\" or \"authenticating\" and stall detection is enabled.\n *\n * Content-based: hashes the ANSI-stripped buffer tail and only resets the\n * timer when visible content actually changes. This prevents TUI spinners\n * (which produce new ANSI sequences but no new visible text) from endlessly\n * resetting the timer.\n */\n private resetStallTimer(): void {\n if (\n !this._stallDetectionEnabled ||\n (this._status !== 'busy' && this._status !== 'authenticating')\n ) {\n this.clearStallTimer();\n return;\n }\n\n // Strip the full buffer FIRST, then slice the tail of the normalized text.\n // Stripping before slicing ensures the 500-char window covers the same\n // visible content regardless of how many raw escape sequences surround it.\n // (Slicing raw first caused different cursor-positioning codes at the\n // truncation boundary to produce different stripped text each TUI redraw.)\n const stripped = this.stripAnsiForStall(this.outputBuffer).trim();\n const visible = this.stripAnsiForClassifier(this.outputBuffer).trim();\n const tail = stripped.slice(-500);\n const fallbackTail = visible.slice(-500);\n const hash = this.simpleHash(tail || fallbackTail);\n\n if (hash === this._lastContentHash) {\n // Content unchanged (e.g., spinner animation) — don't reset the timer\n return;\n }\n this._lastContentHash = hash;\n this._stallEmissionCount = 0;\n\n // Content changed — clear and restart the timer, reset backoff\n if (this._stallTimer) {\n clearTimeout(this._stallTimer);\n this._stallTimer = null;\n }\n this._stallStartedAt = Date.now();\n this._lastStallHash = null; // New content, reset dedup hash for emissions\n this._stallBackoffMs = this._stallTimeoutMs; // Reset backoff on new real content\n\n this._stallTimer = setTimeout(() => {\n this.onStallTimerFired();\n }, this._stallTimeoutMs);\n }\n\n /**\n * Clear the stall detection timer.\n */\n private clearStallTimer(): void {\n if (this._stallTimer) {\n clearTimeout(this._stallTimer);\n this._stallTimer = null;\n }\n this._stallStartedAt = null;\n this._lastContentHash = null;\n this._stallBackoffMs = this._stallTimeoutMs;\n this._stallEmissionCount = 0;\n }\n\n /**\n * Called when the stall timer fires (no output for stallTimeoutMs).\n */\n private onStallTimerFired(): void {\n if (this._status !== 'busy' && this._status !== 'authenticating') {\n return; // Status changed while timer was running\n }\n\n // Fast path: try adapter-level task completion detection first.\n // This must run BEFORE detectLoading because the buffer may contain\n // both stale loading patterns (e.g. \"esc to interrupt\" from the spinner)\n // and a completion signal (e.g. \"Baked for 2s\" + prompt). Task completion\n // is the more specific/certain signal and should take priority.\n if (\n this._status === 'busy' &&\n this.adapter.detectTaskComplete?.(this.outputBuffer)\n ) {\n this._status = 'ready';\n this._lastBlockingPromptHash = null;\n this._lastBlockingPromptEmitAt = 0;\n this.outputBuffer = '';\n this.clearStallTimer();\n this.emit('status_changed', 'ready');\n this.emit('task_complete');\n this.logger.info(\n { sessionId: this.id },\n 'Task complete (adapter fast-path) — agent returned to idle prompt'\n );\n return;\n }\n\n // Loading suppression: if the adapter detects an active loading indicator\n // (thinking spinner, \"esc to interrupt\", \"Reading N files\", etc.),\n // the agent is provably working — suppress stall detection and reschedule.\n if (this.adapter.detectLoading?.(this.outputBuffer)) {\n this.logger.debug(\n { sessionId: this.id },\n 'Loading pattern detected — suppressing stall emission'\n );\n this._stallTimer = setTimeout(\n () => this.onStallTimerFired(),\n this._stallBackoffMs\n );\n return;\n }\n\n // Tool running suppression: if the adapter detects an external tool/process\n // (browser, bash, node, python, etc.), the agent is working through that tool.\n // Suppress stall detection and emit tool_running event for the UI.\n const toolInfo = this.adapter.detectToolRunning?.(this.outputBuffer);\n if (toolInfo) {\n if (toolInfo.toolName !== this._lastToolRunningName) {\n this._lastToolRunningName = toolInfo.toolName;\n this.emit('tool_running', toolInfo);\n }\n this.logger.debug(\n { sessionId: this.id, tool: toolInfo.toolName },\n 'Tool running — suppressing stall emission'\n );\n this._stallTimer = setTimeout(\n () => this.onStallTimerFired(),\n this._stallBackoffMs\n );\n return;\n }\n // Clear tool running state when no tool detected\n if (this._lastToolRunningName) {\n this._lastToolRunningName = null;\n }\n\n // Compute dedup hash from last 500 chars of outputBuffer\n const tail = this.outputBuffer.slice(-500);\n const hash = this.simpleHash(tail);\n\n if (hash === this._lastStallHash) {\n // Buffer tail unchanged since last stall emission — don't re-emit.\n // Schedule another check with current backoff.\n this._stallTimer = setTimeout(\n () => this.onStallTimerFired(),\n this._stallBackoffMs\n );\n return;\n }\n this._lastStallHash = hash;\n\n this._stallEmissionCount++;\n if (this._stallEmissionCount > PTYSession.MAX_STALL_EMISSIONS) {\n this.logger.warn(\n { sessionId: this.id, count: this._stallEmissionCount },\n 'Max stall emissions reached — suspending stall detection for this task'\n );\n this.clearStallTimer();\n return;\n }\n\n // Compute recent output for classifier: last 2000 chars, ANSI-stripped\n // while preserving visible symbols/text used by TUI CLIs.\n const recentRaw = this.outputBuffer.slice(-2000);\n const recentOutput = this.stripAnsiForClassifier(recentRaw).trim();\n\n const stallDurationMs = this._stallStartedAt\n ? Date.now() - this._stallStartedAt\n : this._stallTimeoutMs;\n\n this.logger.debug(\n {\n sessionId: this.id,\n stallDurationMs,\n bufferTailLength: tail.length,\n recentOutputLength: recentOutput.length,\n recentOutputHash: this.simpleHash(recentOutput.slice(-500)),\n },\n 'Stall detected'\n );\n\n this.emit('stall_detected', recentOutput, stallDurationMs);\n\n // Schedule next check with current backoff\n this._stallTimer = setTimeout(\n () => this.onStallTimerFired(),\n this._stallBackoffMs\n );\n }\n\n /**\n * Promise-based delay helper.\n */\n private delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n\n /**\n * Simple string hash for deduplication.\n */\n private simpleHash(str: string): string {\n let hash = 0;\n for (let i = 0; i < str.length; i++) {\n const char = str.charCodeAt(i);\n hash = (hash << 5) - hash + char;\n hash |= 0;\n }\n return hash.toString(36);\n }\n\n private mapLoginTypeToAuthMethod(\n type: LoginDetection['type'] | undefined\n ): AuthRequiredInfo['method'] {\n switch (type) {\n case 'api_key':\n return 'api_key';\n case 'cli_auth':\n return 'cli_auth';\n case 'device_code':\n return 'device_code';\n case 'oauth':\n case 'browser':\n return 'oauth_browser';\n default:\n return 'unknown';\n }\n }\n\n private extractDeviceCode(text: string): string | undefined {\n const stripped = this.stripAnsiForClassifier(text);\n const explicitMatch = stripped.match(\n /(?:one-time|one time|device)?\\s*code[:\\s]+([A-Z0-9]{3,}(?:-[A-Z0-9]{3,})+)/i\n );\n if (explicitMatch?.[1]) {\n return explicitMatch[1].toUpperCase();\n }\n\n if (!/code/i.test(stripped)) {\n return undefined;\n }\n const fallbackMatch = stripped.match(\n /\\b([A-Z0-9]{3,}(?:-[A-Z0-9]{3,})+)\\b/\n );\n return fallbackMatch?.[1]?.toUpperCase();\n }\n\n private getPromptSnippet(maxChars = 280): string | undefined {\n const normalized = this.stripAnsiForClassifier(this.outputBuffer)\n .replace(/\\s+/g, ' ')\n .trim();\n if (!normalized) {\n return undefined;\n }\n return normalized.length <= maxChars\n ? normalized\n : normalized.slice(-maxChars);\n }\n\n private emitAuthRequired(details: {\n type?: LoginDetection['type'];\n url?: string;\n deviceCode?: string;\n instructions?: string;\n }): void {\n const info: AuthRequiredInfo = {\n method: this.mapLoginTypeToAuthMethod(details.type),\n url: details.url,\n deviceCode:\n details.deviceCode ?? this.extractDeviceCode(this.outputBuffer),\n instructions: details.instructions,\n promptSnippet: this.getPromptSnippet(),\n };\n\n this.emit('auth_required', info);\n this.emit('login_required', info.instructions, info.url);\n }\n\n /**\n * Strip ANSI codes, cursor movement, box-drawing, and spinner characters.\n * Used for stall detection hashing and auto-response pattern matching.\n *\n * Cursor movement codes are replaced with spaces (not removed) to preserve\n * word boundaries — e.g. \"Do\\x1b[5Cyou\" becomes \"Do you\", not \"Doyou\".\n */\n private stripAnsiForStall(str: string): string {\n // Replace ALL cursor movement/positioning codes with a space to preserve word boundaries:\n // \\x1b[nC (forward), \\x1b[nD (back), \\x1b[nA (up), \\x1b[nB (down), \\x1b[nG (column)\n // \\x1b[n;mH and \\x1b[n;mf (absolute positioning)\n // \\x1b[nJ (erase display), \\x1b[nK (erase line) — also space to keep words apart\n // \\x1b[nd (vertical position), \\x1b[nE/nF (cursor next/prev line)\n let result = str.replace(/\\x1b\\[\\d*[CDABGdEF]/g, ' ');\n result = result.replace(/\\x1b\\[\\d*(?:;\\d+)?[Hf]/g, ' ');\n result = result.replace(/\\x1b\\[\\d*[JK]/g, ' ');\n\n // Strip OSC sequences (Operating System Command): \\x1b] ... BEL or \\x1b] ... ST\n // Used for hyperlinks, window titles, Kitty graphics. Payload text would pollute output.\n result = result.replace(\n /\\x1b\\](?:[^\\x07\\x1b]|\\x1b[^\\\\])*(?:\\x07|\\x1b\\\\)/g,\n ''\n );\n\n // Strip DCS sequences (Device Control String): \\x1bP ... ST\n result = result.replace(/\\x1bP(?:[^\\x1b]|\\x1b[^\\\\])*\\x1b\\\\/g, '');\n\n // Strip remaining ANSI escape sequences (SGR, cursor show/hide, etc.)\n // eslint-disable-next-line no-control-regex\n result = result.replace(/\\x1B(?:[@-Z\\\\-_]|\\[[0-?]*[ -/]*[@-~])/g, '');\n\n // Strip bare control characters (backspace, bell, carriage return, etc.)\n // Preserves only \\x09 (tab) and \\x0a (newline).\n // eslint-disable-next-line no-control-regex\n result = result.replace(/[\\x00-\\x08\\x0b-\\x1f\\x7f]/g, '');\n\n // Normalize non-breaking spaces (NBSP \\xa0) to regular spaces\n result = result.replace(/\\xa0/g, ' ');\n\n // Strip TUI box-drawing, spinner, and decorative Unicode characters\n result = result.replace(\n /[│╭╰╮╯─═╌║╔╗╚╝╠╣╦╩╬┌┐└┘├┤┬┴┼●○❯❮▶◀⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏⣾⣽⣻⢿⡿⣟⣯⣷✻✶✳✢⏺←→↑↓⬆⬇◆◇▪▫■□▲△▼▽◈⟨⟩⌘⏎⏏⌫⌦⇧⇪⌥]/g,\n ' '\n );\n\n // Normalize countdown/duration text (e.g., \"8m 17s\" → \"0s\") to prevent\n // TUI countdown timers from resetting the stall timer every second.\n result = result.replace(/\\d+[hms](?:\\s+\\d+[hms])*/g, '0s');\n\n // Collapse multiple spaces\n result = result.replace(/ {2,}/g, ' ');\n\n return result;\n }\n\n /**\n * Less-aggressive ANSI stripping for classifier context.\n * Preserves visible TUI symbols (e.g. ❯, ✻) and durations while removing\n * escape/control sequences so the classifier keeps useful evidence.\n */\n private stripAnsiForClassifier(str: string): string {\n let result = str.replace(/\\x1b\\[\\d*[CDABGdEF]/g, ' ');\n result = result.replace(/\\x1b\\[\\d*(?:;\\d+)?[Hf]/g, ' ');\n result = result.replace(/\\x1b\\[\\d*[JK]/g, ' ');\n\n // Strip OSC and DCS payloads\n result = result.replace(\n /\\x1b\\](?:[^\\x07\\x1b]|\\x1b[^\\\\])*(?:\\x07|\\x1b\\\\)/g,\n ''\n );\n result = result.replace(/\\x1bP(?:[^\\x1b]|\\x1b[^\\\\])*\\x1b\\\\/g, '');\n\n // Strip remaining ANSI escape sequences\n // eslint-disable-next-line no-control-regex\n result = result.replace(/\\x1B(?:[@-Z\\\\-_]|\\[[0-?]*[ -/]*[@-~])/g, '');\n\n // Strip bare control chars except tab/newline\n // eslint-disable-next-line no-control-regex\n result = result.replace(/[\\x00-\\x08\\x0b-\\x1f\\x7f]/g, '');\n\n // Normalize NBSP and collapse spaces\n result = result.replace(/\\xa0/g, ' ');\n result = result.replace(/ {2,}/g, ' ');\n return result;\n }\n\n /**\n * Handle external stall classification result.\n * Called by the manager after onStallClassify resolves.\n */\n handleStallClassification(classification: StallClassification | null): void {\n // Guard against async race — session may no longer be busy/authenticating\n if (this._status !== 'busy' && this._status !== 'authenticating') {\n return;\n }\n\n if (!classification || classification.state === 'still_working') {\n // Exponential backoff — double the check interval (capped at 30s).\n // This avoids hammering the LLM classifier every few seconds when\n // the agent is legitimately working on a long task.\n this._stallBackoffMs = Math.min(\n this._stallBackoffMs * 2,\n PTYSession.MAX_STALL_BACKOFF_MS\n );\n this.logger.debug(\n { sessionId: this.id, nextCheckMs: this._stallBackoffMs },\n 'Still working — backing off stall check interval'\n );\n\n // Force timer restart with backed-off interval, even if buffer\n // content hasn't changed.\n this._lastContentHash = null;\n this._lastStallHash = null; // Reset dedup hash so next fire can re-emit\n if (this._stallTimer) {\n clearTimeout(this._stallTimer);\n this._stallTimer = null;\n }\n this._stallTimer = setTimeout(\n () => this.onStallTimerFired(),\n this._stallBackoffMs\n );\n return;\n }\n\n switch (classification.state) {\n case 'waiting_for_input': {\n const promptInfo: BlockingPromptInfo = {\n type: 'stall_classified',\n prompt: classification.prompt,\n canAutoRespond: !!classification.suggestedResponse,\n };\n\n if (classification.suggestedResponse) {\n this.logger.info(\n { sessionId: this.id, response: classification.suggestedResponse },\n 'Auto-responding to stall-classified prompt'\n );\n const resp = classification.suggestedResponse;\n if (resp.startsWith('keys:')) {\n const keys = resp\n .slice(5)\n .split(',')\n .map((k) => k.trim());\n this.sendKeySequence(keys);\n } else {\n this.writeRaw(`${resp}\\r`);\n }\n this.emit('blocking_prompt', promptInfo, true);\n this.outputBuffer = ''; // Prevent stale text from triggering false detections\n } else {\n this.emit('blocking_prompt', promptInfo, false);\n }\n break;\n }\n\n case 'task_complete':\n this._status = 'ready';\n this._lastBlockingPromptHash = null;\n this._lastBlockingPromptEmitAt = 0;\n this.outputBuffer = '';\n this.clearStallTimer();\n this.emit('ready');\n this.logger.info(\n { sessionId: this.id },\n 'Stall classified as task_complete, transitioning to ready'\n );\n break;\n\n case 'error':\n this.clearStallTimer();\n this.emit(\n 'error',\n new Error(classification.prompt || 'Stall classified as error')\n );\n break;\n }\n }\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Task Completion Detection\n // ─────────────────────────────────────────────────────────────────────────────\n\n /**\n * Schedule a task_complete transition after a debounce period.\n * Uses a settle pattern: each call resets the debounce timer instead of\n * being a no-op when already scheduled. This allows TUI agents that\n * continue rendering decorative output (status bar, update notices) after\n * the prompt to eventually settle, rather than having the timer cancelled\n * by every new data chunk. The callback re-verifies the task-complete\n * signal before transitioning, so stale triggers are safe.\n */\n private scheduleTaskComplete(): void {\n const wasPending = this._taskCompletePending;\n this.traceTaskCompletion('debounce_schedule', {\n wasPending,\n debounceMs: PTYSession.TASK_COMPLETE_DEBOUNCE_MS,\n });\n\n if (this._taskCompleteTimer) {\n clearTimeout(this._taskCompleteTimer);\n }\n this._taskCompletePending = true;\n\n this._taskCompleteTimer = setTimeout(() => {\n this._taskCompleteTimer = null;\n this._taskCompletePending = false;\n\n const signal = this.isTaskCompleteSignal(this.outputBuffer);\n this.traceTaskCompletion('debounce_fire', { signal });\n\n // Re-check: still busy and task-complete signal still present?\n if (this._status !== 'busy') {\n this.traceTaskCompletion('debounce_reject_status', { signal });\n return;\n }\n if (!signal) {\n this.traceTaskCompletion('debounce_reject_signal', { signal });\n return;\n }\n\n this._status = 'ready';\n this._lastBlockingPromptHash = null;\n this._lastBlockingPromptEmitAt = 0;\n this.outputBuffer = '';\n this.clearStallTimer();\n this.emit('status_changed', 'ready');\n this.emit('task_complete');\n this.traceTaskCompletion('transition_ready', { signal: true });\n this.logger.info(\n { sessionId: this.id },\n 'Task complete — agent returned to idle prompt'\n );\n }, PTYSession.TASK_COMPLETE_DEBOUNCE_MS);\n }\n\n /**\n * Whether the adapter's `detectLoading()` currently classifies the\n * session as actively processing work.\n *\n * This wraps `adapter.detectLoading(outputBuffer)` for consumers outside\n * the PTY layer (e.g. milady's swarm idle watchdog) that need a\n * reliable \"is the agent busy right now?\" signal without reimplementing\n * heuristics over raw terminal output.\n *\n * Returns `false` if the adapter does not implement `detectLoading`.\n */\n public isLoading(): boolean {\n return this.adapter.detectLoading?.(this.outputBuffer) ?? false;\n }\n\n /**\n * Adapter-level task completion check with compatibility fallback.\n * Prefer detectTaskComplete() because detectReady() may be broad for TUIs.\n */\n private isTaskCompleteSignal(output: string): boolean {\n if (this.adapter.detectTaskComplete) {\n return this.adapter.detectTaskComplete(output);\n }\n return this.adapter.detectReady(output);\n }\n\n /**\n * Claude-oriented task completion traces for PTY debugging.\n * Disabled by default; enable via config.traceTaskCompletion.\n */\n private traceTaskCompletion(\n event: string,\n ctx: Partial<{\n signal: boolean;\n wasPending: boolean;\n debounceMs: number;\n }> = {}\n ): void {\n if (!this.shouldTraceTaskCompletion()) return;\n\n const output = this.outputBuffer;\n const detectTaskComplete = this.adapter.detectTaskComplete\n ? this.adapter.detectTaskComplete(output)\n : undefined;\n const detectReady = this.adapter.detectReady(output);\n const detectLoading = this.adapter.detectLoading\n ? this.adapter.detectLoading(output)\n : undefined;\n const normalizedTail = this.stripAnsiForStall(output.slice(-280));\n\n this.logger.debug(\n {\n sessionId: this.id,\n adapterType: this.adapter.adapterType,\n event,\n status: this._status,\n taskCompletePending: this._taskCompletePending,\n signal: ctx.signal,\n wasPending: ctx.wasPending,\n debounceMs: ctx.debounceMs,\n detectTaskComplete,\n detectReady,\n detectLoading,\n tailHash: this.simpleHash(normalizedTail),\n tailSnippet: normalizedTail.slice(-140),\n },\n 'Task completion trace'\n );\n }\n\n private shouldTraceTaskCompletion(): boolean {\n return this.config.traceTaskCompletion === true;\n }\n\n /**\n * Cancel a pending task_complete timer (new output arrived that\n * doesn't match the idle prompt, so the agent is still working).\n */\n private cancelTaskComplete(): void {\n if (this._taskCompleteTimer) {\n clearTimeout(this._taskCompleteTimer);\n this._taskCompleteTimer = null;\n }\n this._taskCompletePending = false;\n }\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Ready Detection Settle Delay\n // ─────────────────────────────────────────────────────────────────────────────\n\n /**\n * Schedule or reset the ready-settle timer.\n * Defers emitting session_ready until output goes quiet for readySettleMs\n * after detectReady first matches. This prevents sending input while\n * TUI agents are still rendering (status bar, shortcuts, update notices).\n */\n private scheduleReadySettle(): void {\n this._readySettlePending = true;\n if (this._readySettleTimer) {\n clearTimeout(this._readySettleTimer);\n }\n const settleMs =\n this.config.readySettleMs ?? this.adapter.readySettleMs ?? 100;\n this._readySettleTimer = setTimeout(() => {\n this._readySettleTimer = null;\n this._readySettlePending = false;\n // Re-verify state and ready indicator\n if (this._status !== 'starting' && this._status !== 'authenticating')\n return;\n if (!this.adapter.detectReady(this.outputBuffer)) return;\n this._status = 'ready';\n this._lastBlockingPromptHash = null;\n this._lastBlockingPromptEmitAt = 0;\n this.outputBuffer = '';\n this.clearStallTimer();\n this.emit('ready');\n this.logger.info({ sessionId: this.id }, 'Session ready (after settle)');\n }, settleMs);\n }\n\n /**\n * Cancel a pending ready-settle timer (ready indicator disappeared\n * or session status changed).\n */\n private cancelReadySettle(): void {\n if (this._readySettleTimer) {\n clearTimeout(this._readySettleTimer);\n this._readySettleTimer = null;\n }\n this._readySettlePending = false;\n }\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Lifecycle\n // ─────────────────────────────────────────────────────────────────────────────\n\n /**\n * Start the PTY session\n */\n async start(): Promise<void> {\n if (this.ptyProcess) {\n throw new Error('Session already started');\n }\n\n // Ensure node-pty native addon is usable before first spawn\n ensurePty((msg) => this.logger.info({ sessionId: this.id }, msg));\n\n const nodePty = loadPty();\n\n this._status = 'starting';\n this._startedAt = new Date();\n\n const command = this.adapter.getCommand();\n const args = this.adapter.getArgs(this.config);\n const adapterEnv = this.adapter.getEnv(this.config);\n\n const env = PTYSession.buildSpawnEnv(this.config, adapterEnv);\n\n this.logger.info(\n { sessionId: this.id, command, args: args.join(' ') },\n 'Starting PTY session'\n );\n\n try {\n this.ptyProcess = nodePty.spawn(command, args, {\n name: 'xterm-256color',\n cols: this.config.cols || 120,\n rows: this.config.rows || 40,\n cwd: this.config.workdir || process.cwd(),\n env: env as Record<string, string>,\n });\n\n this.setupEventHandlers();\n\n this.logger.info(\n { sessionId: this.id, pid: this.ptyProcess.pid },\n 'PTY session started'\n );\n } catch (error) {\n this._status = 'error';\n this.logger.error(\n { sessionId: this.id, error },\n 'Failed to start PTY session'\n );\n throw error;\n }\n }\n\n /**\n * Set up event handlers for the PTY\n */\n private setupEventHandlers(): void {\n if (!this.ptyProcess) return;\n\n this.ptyProcess.onData((data) => {\n this._lastActivityAt = new Date();\n this.outputBuffer += data;\n\n // Cap the buffer to prevent unbounded growth during long tasks.\n // Detection only ever inspects the tail, so trimming is safe.\n if (this.outputBuffer.length > PTYSession.MAX_OUTPUT_BUFFER) {\n this.outputBuffer = this.outputBuffer.slice(\n -PTYSession.MAX_OUTPUT_BUFFER\n );\n }\n\n // Emit raw output immediately (callers may need it for real-time display)\n this.emit('output', data);\n\n // Defer all heavy detection work to the next event-loop tick.\n // node-pty delivers data synchronously from its native read loop;\n // running regex-heavy detection inline can starve the event loop\n // and prevent timers (stall detection, task_complete debounce)\n // from firing — especially on macOS ARM64 where the PTY read can\n // hold the libuv poll phase.\n if (!this._processScheduled) {\n this._processScheduled = true;\n setImmediate(() => {\n this._processScheduled = false;\n this.processOutputBuffer();\n });\n }\n });\n\n this.ptyProcess.onExit(({ exitCode, signal }) => {\n this._status = 'stopped';\n this.clearStallTimer();\n this.logger.info(\n { sessionId: this.id, exitCode, signal },\n 'PTY session exited'\n );\n this.emit('exit', exitCode);\n });\n }\n\n /**\n * Process the accumulated output buffer.\n * Called via setImmediate() from the onData handler so that heavy regex\n * work runs in its own event-loop tick, not inside node-pty's native callback.\n */\n private processOutputBuffer(): void {\n // Reset stall timer on any new output while busy or authenticating\n if (this._status === 'busy' || this._status === 'authenticating') {\n this.resetStallTimer();\n }\n\n // If a ready-settle is pending, reset the timer on new data instead of\n // re-running all detection. If the ready indicator disappears, cancel.\n if (this._readySettlePending) {\n if (\n (this._status === 'starting' || this._status === 'authenticating') &&\n this.adapter.detectReady(this.outputBuffer)\n ) {\n this.scheduleReadySettle();\n } else {\n this.cancelReadySettle();\n }\n return;\n }\n\n // Ready detection — check FIRST, before blocking prompt detection.\n // After an auto-response (e.g. trust prompt), the buffer may contain\n // leftover prompt text that would falsely trigger detectBlockingPrompt\n // and block detectReady from ever running. Adapter detectReady\n // implementations have negative guards for trust/auth prompts, so\n // this is safe — it won't prematurely mark the session as ready.\n if (\n (this._status === 'starting' || this._status === 'authenticating') &&\n this.adapter.detectReady(this.outputBuffer)\n ) {\n this.scheduleReadySettle();\n return;\n }\n\n // Tool running detection — emit event promptly when busy so UI updates\n if (this._status === 'busy') {\n const toolInfo = this.adapter.detectToolRunning?.(this.outputBuffer);\n if (toolInfo) {\n if (toolInfo.toolName !== this._lastToolRunningName) {\n this._lastToolRunningName = toolInfo.toolName;\n this.emit('tool_running', toolInfo);\n }\n } else if (this._lastToolRunningName) {\n this._lastToolRunningName = null;\n }\n }\n\n // Task completion detection — when busy and the agent returns to idle.\n // Uses a settle pattern: once triggered, the debounce timer resets on each\n // new data chunk instead of being cancelled. The callback re-verifies\n // the task-complete signal before transitioning, so stale triggers are safe.\n if (this._status === 'busy') {\n const signal = this.isTaskCompleteSignal(this.outputBuffer);\n if (this._taskCompletePending || signal) {\n this.traceTaskCompletion('busy_signal', { signal });\n this.scheduleTaskComplete();\n }\n // No else/cancel — timer self-validates on fire\n }\n\n // Auto-response / blocking prompt detection — runs after detectReady.\n // Handles trust confirmations, permission prompts, apply changes, etc.\n // Skip when stopping/stopped to prevent blocking_prompt spam between\n // stopSession() and PTY exit.\n if (this._status !== 'stopping' && this._status !== 'stopped') {\n const blockingPrompt = this.detectAndHandleBlockingPrompt();\n if (blockingPrompt) {\n return;\n }\n }\n\n // Login detection — only during startup/auth (not after ready/busy)\n if (this._status !== 'ready' && this._status !== 'busy') {\n const loginDetection = this.adapter.detectLogin(this.outputBuffer);\n if (loginDetection.required && this._status !== 'authenticating') {\n this._status = 'authenticating';\n this.clearStallTimer();\n this.emitAuthRequired({\n type: loginDetection.type,\n url: loginDetection.url,\n deviceCode: loginDetection.deviceCode,\n instructions: loginDetection.instructions,\n });\n this.logger.warn(\n { sessionId: this.id, loginType: loginDetection.type },\n 'Login required'\n );\n return;\n }\n }\n\n // Check for exit\n const exitDetection = this.adapter.detectExit(this.outputBuffer);\n if (exitDetection.exited) {\n this._status = 'stopped';\n this.clearStallTimer();\n this.emit('exit', exitDetection.code || 0);\n }\n\n // Try to parse output into structured message only when ready.\n // Parsing clears outputBuffer; doing this while busy can starve task-complete\n // and stall detection of evidence during heavy TUI rendering.\n if (this._status === 'ready') {\n this.tryParseOutput();\n }\n }\n\n /**\n * Detect blocking prompts and handle them with auto-responses or user notification.\n * Deduplicates emissions - won't re-emit the same blocking prompt repeatedly.\n */\n private detectAndHandleBlockingPrompt(): boolean {\n // First, check adapter's auto-response rules\n const autoHandled = this.tryAutoResponse();\n if (autoHandled) {\n return true;\n }\n\n // Then check the adapter's detectBlockingPrompt method\n if (this.adapter.detectBlockingPrompt) {\n const detection = this.adapter.detectBlockingPrompt(this.outputBuffer);\n\n if (detection.detected) {\n // Deduplicate: don't re-emit the same blocking prompt.\n // Normalize the prompt text for hashing — strip whitespace variations,\n // line numbers, and cursor artifacts that change on every TUI re-render\n // (e.g. pager prompts, permission dialogs with changing line counts).\n const normalizedPrompt = (detection.prompt || '')\n .replace(/\\s+/g, ' ') // collapse whitespace\n .replace(/\\d+/g, '#') // normalize numbers (line counts, etc.)\n .trim()\n .slice(0, 100); // cap length for consistent hashing\n const promptHash = `${detection.type}:${normalizedPrompt}`;\n if (promptHash === this._lastBlockingPromptHash) {\n // Still blocked by same prompt, but don't spam events\n return true;\n }\n // Time-based debounce: suppress rapid re-emissions within 250ms.\n // Spinner fragments produce slightly different hashes on each frame.\n const now = Date.now();\n if (now - this._lastBlockingPromptEmitAt < PTYSession.BLOCKING_PROMPT_DEBOUNCE_MS) {\n return true;\n }\n this._lastBlockingPromptHash = promptHash;\n this._lastBlockingPromptEmitAt = now;\n\n const promptInfo: BlockingPromptInfo = {\n type: detection.type || 'unknown',\n prompt: detection.prompt,\n options: detection.options,\n canAutoRespond: detection.canAutoRespond || false,\n instructions: detection.instructions,\n url: detection.url,\n };\n\n // If we can auto-respond and have a suggested response, do it\n if (\n detection.canAutoRespond &&\n detection.suggestedResponse &&\n !this.config.skipAdapterAutoResponse\n ) {\n this.logger.info(\n {\n sessionId: this.id,\n promptType: detection.type,\n response: detection.suggestedResponse,\n },\n 'Auto-responding to blocking prompt'\n );\n\n const resp = detection.suggestedResponse;\n if (resp.startsWith('keys:')) {\n const keys = resp\n .slice(5)\n .split(',')\n .map((k) => k.trim());\n this.sendKeySequence(keys);\n } else {\n this.writeRaw(`${resp}\\r`);\n }\n // Keep the hash so TUI re-renders of the same prompt are deduped.\n // Clear the buffer to prevent stale text from triggering false detections.\n this.outputBuffer = '';\n this.emit('blocking_prompt', promptInfo, true);\n return true;\n }\n\n // Otherwise, notify that user intervention is needed\n if (detection.type === 'login') {\n this._status = 'authenticating';\n // Surface login prompts through the dedicated auth event so callers\n // can open OAuth/device-code URLs without parsing blocking_prompt.\n const inferred = this.adapter.detectLogin(this.outputBuffer);\n this.emitAuthRequired({\n type: inferred.required ? inferred.type : undefined,\n url: detection.url ?? inferred.url,\n deviceCode: inferred.required ? inferred.deviceCode : undefined,\n instructions: detection.instructions ?? inferred.instructions,\n });\n }\n\n this.logger.warn(\n {\n sessionId: this.id,\n promptType: detection.type,\n prompt: detection.prompt,\n },\n 'Blocking prompt requires user intervention'\n );\n\n this.emit('blocking_prompt', promptInfo, false);\n return true;\n } else {\n // No blocking prompt detected - clear the hash\n this._lastBlockingPromptHash = null;\n this._lastBlockingPromptEmitAt = 0;\n }\n }\n\n return false;\n }\n\n /**\n * Try to match and apply auto-response rules.\n * Session rules are checked first, then adapter rules.\n */\n private tryAutoResponse(): boolean {\n // Combine session rules (higher priority) with adapter rules (filtered/merged by overrides)\n const adapterRules = (this.adapter.autoResponseRules || [])\n .filter((r) => !this._disabledRulePatterns.has(r.pattern.source))\n .map((r) => {\n const override = this._ruleOverrides.get(r.pattern.source);\n return override ? { ...r, ...override } : r;\n });\n const allRules = [...this.sessionRules, ...adapterRules];\n\n if (allRules.length === 0) {\n return false;\n }\n\n // Strip ANSI codes, cursor movement, box-drawing, and spinner chars\n // so regex patterns match the visible text, not raw terminal sequences.\n const stripped = this.stripAnsiForStall(this.outputBuffer);\n\n for (const rule of allRules) {\n // Skip once-rules that have already fired\n if (rule.once) {\n const ruleKey = `${rule.pattern.source}:${rule.pattern.flags}`;\n if (this._firedOnceRules.has(ruleKey)) {\n continue;\n }\n }\n\n if (rule.pattern.test(stripped)) {\n // Check if it's safe to auto-respond (default: true)\n const safe = rule.safe !== false;\n const isSessionRule = this.sessionRules.includes(rule);\n\n if (safe) {\n this.logger.info(\n {\n sessionId: this.id,\n promptType: rule.type,\n description: rule.description,\n response: rule.response,\n source: isSessionRule ? 'session' : 'adapter',\n },\n 'Applying auto-response rule'\n );\n\n // Determine how to send the response\n const useKeys = rule.keys && rule.keys.length > 0;\n const isTuiDefault =\n !rule.responseType && !rule.keys && this.adapter.usesTuiMenus;\n\n if (useKeys) {\n // Explicit key sequence\n this.sendKeySequence(rule.keys!);\n } else if (isTuiDefault) {\n // TUI adapter with no explicit responseType — default to Enter\n this.sendKeys('enter');\n } else {\n // Text response (backward compat)\n this.writeRaw(`${rule.response}\\r`);\n }\n\n // Track once-rules so they don't fire again on TUI re-renders\n if (rule.once) {\n const ruleKey = `${rule.pattern.source}:${rule.pattern.flags}`;\n this._firedOnceRules.add(ruleKey);\n }\n\n // Clear the entire buffer — the prompt has been handled and leftover\n // text (e.g. \"Press enter to continue\") would block detectReady().\n this.outputBuffer = '';\n\n const promptInfo: BlockingPromptInfo = {\n type: rule.type,\n prompt: rule.description,\n canAutoRespond: true,\n };\n\n this.emit('blocking_prompt', promptInfo, true);\n return true;\n } else {\n // Not safe to auto-respond, emit for user intervention\n const promptInfo: BlockingPromptInfo = {\n type: rule.type,\n prompt: rule.description,\n canAutoRespond: false,\n instructions: `Prompt matched but requires user confirmation: ${rule.description}`,\n };\n\n this.emit('blocking_prompt', promptInfo, false);\n return true;\n }\n }\n }\n\n return false;\n }\n\n /**\n * Try to parse the output buffer into structured messages\n */\n private tryParseOutput(): void {\n const parsed = this.adapter.parseOutput(this.outputBuffer);\n\n if (parsed?.isComplete) {\n // Clear the buffer for the parsed content\n this.outputBuffer = '';\n\n const message: SessionMessage = {\n id: `${this.id}-msg-${++this.messageCounter}`,\n sessionId: this.id,\n direction: 'outbound',\n type: parsed.type,\n content: parsed.content,\n metadata: parsed.metadata,\n timestamp: new Date(),\n };\n\n this.emit('message', message);\n\n // Also emit specific event for questions\n if (parsed.isQuestion) {\n this.emit('question', parsed.content);\n }\n }\n }\n\n /**\n * Write data to the PTY (formatted by adapter)\n */\n write(data: string): void {\n if (!this.ptyProcess) {\n throw new Error('Session not started');\n }\n\n this._lastActivityAt = new Date();\n const formatted = this.adapter.formatInput(data);\n this.ptyProcess.write(`${formatted}\\r`);\n\n this.logger.debug(\n { sessionId: this.id, input: data },\n 'Sent input to session'\n );\n }\n\n /**\n * Write raw data directly to the PTY (no formatting)\n */\n writeRaw(data: string): void {\n if (!this.ptyProcess) {\n throw new Error('Session not started');\n }\n\n this._lastActivityAt = new Date();\n this.ptyProcess.write(data);\n }\n\n /**\n * Send a task/message to the session\n *\n * Text and Enter are sent as separate writes with a small delay.\n * This is required for TUI-based CLIs (Gemini CLI, ink/React-based tools)\n * which drop the trailing \\r if it arrives in the same write buffer\n * during a render cycle.\n */\n send(message: string): SessionMessage {\n this._status = 'busy';\n this.outputBuffer = ''; // Clear stale startup/previous-task text so detectReady guards don't false-negative\n this.emit('status_changed', 'busy');\n this._stallEmissionCount = 0;\n this.resetStallTimer();\n\n const msg: SessionMessage = {\n id: `${this.id}-msg-${++this.messageCounter}`,\n sessionId: this.id,\n direction: 'inbound',\n type: 'task',\n content: message,\n timestamp: new Date(),\n };\n\n // Write formatted text without Enter\n const formatted = this.adapter.formatInput(message);\n this.writeRaw(formatted);\n\n // Send Enter separately after a brief delay\n // TUI-based CLIs need this as a discrete event to register the submission\n setTimeout(() => this.sendKeys('enter'), 50);\n\n this.logger.debug(\n { sessionId: this.id, input: message },\n 'Sent input to session'\n );\n\n return msg;\n }\n\n /**\n * Resize the PTY terminal\n */\n resize(cols: number, rows: number): void {\n this.ptyProcess?.resize(cols, rows);\n }\n\n /**\n * Send special keys to the PTY\n *\n * Supported keys:\n * - Control: ctrl+c, ctrl+d, ctrl+z, ctrl+l, ctrl+a, ctrl+e, ctrl+k, ctrl+u, ctrl+w, ctrl+r\n * - Navigation: up, down, left, right, home, end, pageup, pagedown\n * - Editing: enter, tab, backspace, delete, insert, escape\n * - Function: f1-f12\n *\n * @param keys - Key name(s) to send, e.g. \"ctrl+c\" or [\"up\", \"up\", \"enter\"]\n */\n sendKeys(keys: string | string[]): void {\n if (!this.ptyProcess) {\n throw new Error('Session not started');\n }\n\n const keyList = Array.isArray(keys) ? keys : [keys];\n const normalized = PTYSession.normalizeKeyList(keyList);\n this._stallEmissionCount = 0;\n this._lastBlockingPromptHash = null;\n this._lastBlockingPromptEmitAt = 0;\n this.outputBuffer = '';\n this.resetStallTimer();\n\n for (const key of normalized) {\n const sequence = SPECIAL_KEYS[key];\n\n if (sequence) {\n this._lastActivityAt = new Date();\n this.ptyProcess.write(sequence);\n this.logger.debug({ sessionId: this.id, key }, 'Sent special key');\n } else {\n this.logger.warn(\n { sessionId: this.id, key },\n 'Unknown special key, sending as literal'\n );\n this.ptyProcess.write(key);\n }\n }\n }\n\n /**\n * Build the environment object for spawning a PTY process.\n * Merges base env (process.env unless opted out), adapter env, and config env,\n * with TERM/COLORTERM always forced.\n */\n static buildSpawnEnv(\n config: SpawnConfig,\n adapterEnv: Record<string, string>\n ): Record<string, string> {\n const baseEnv = config.inheritProcessEnv !== false ? process.env : {};\n return {\n ...baseEnv,\n ...adapterEnv,\n ...config.env,\n TERM: 'xterm-256color',\n COLORTERM: 'truecolor',\n } as Record<string, string>;\n }\n\n /**\n * Normalize a list of key names for SPECIAL_KEYS lookup.\n *\n * Handles two problems:\n * 1. Modifier aliases: \"control\" → \"ctrl\", \"command\" → \"meta\", \"option\" → \"alt\"\n * 2. Comma-separated compound keys from stall classifier: [\"control\", \"c\"] → [\"ctrl+c\"]\n * A bare modifier followed by a single char/key is joined with \"+\".\n */\n static normalizeKeyList(keys: string[]): string[] {\n const MODIFIER_MAP: Record<string, string> = {\n control: 'ctrl',\n command: 'meta',\n cmd: 'meta',\n option: 'alt',\n opt: 'alt',\n };\n\n const MODIFIER_NAMES = new Set([\n 'ctrl',\n 'alt',\n 'shift',\n 'meta',\n // Also match the aliases so we can detect them before remapping\n ...Object.keys(MODIFIER_MAP),\n ]);\n\n const result: string[] = [];\n let i = 0;\n\n while (i < keys.length) {\n let key = keys[i].toLowerCase().trim();\n\n // Remap modifier aliases\n if (MODIFIER_MAP[key]) {\n key = MODIFIER_MAP[key];\n }\n\n // If this is a bare modifier and the next element is a non-modifier key,\n // join them as \"modifier+key\" (e.g. [\"ctrl\", \"c\"] → \"ctrl+c\")\n if (MODIFIER_NAMES.has(key) && i + 1 < keys.length) {\n let nextKey = keys[i + 1].toLowerCase().trim();\n if (MODIFIER_MAP[nextKey]) {\n nextKey = MODIFIER_MAP[nextKey];\n }\n // Only join if next is NOT a bare modifier (avoid collapsing [\"ctrl\", \"shift\", \"c\"])\n if (!MODIFIER_NAMES.has(nextKey)) {\n result.push(`${key}+${nextKey}`);\n i += 2;\n continue;\n }\n }\n\n result.push(key);\n i++;\n }\n\n return result;\n }\n\n /**\n * Select a TUI menu option by index (0-based).\n * Sends Down arrow `optionIndex` times, then Enter, with 50ms delays.\n */\n async selectMenuOption(optionIndex: number): Promise<void> {\n for (let i = 0; i < optionIndex; i++) {\n this.sendKeys('down');\n await this.delay(50);\n }\n this.sendKeys('enter');\n }\n\n /**\n * Send a sequence of keys with staggered timing.\n * Each key is sent 50ms apart using setTimeout to keep the caller synchronous.\n */\n private sendKeySequence(keys: string[]): void {\n keys.forEach((key, i) => {\n setTimeout(() => this.sendKeys(key), i * 50);\n });\n }\n\n /**\n * Paste text using bracketed paste mode\n *\n * Bracketed paste mode wraps the pasted text in escape sequences\n * that tell the terminal this is pasted content, not typed input.\n * This prevents issues with pasting text that contains special characters\n * or looks like commands.\n *\n * @param text - Text to paste\n * @param useBracketedPaste - Whether to use bracketed paste mode (default: true)\n */\n paste(text: string, useBracketedPaste: boolean = true): void {\n if (!this.ptyProcess) {\n throw new Error('Session not started');\n }\n\n this._lastActivityAt = new Date();\n\n if (useBracketedPaste) {\n this.ptyProcess.write(BRACKETED_PASTE_START + text + BRACKETED_PASTE_END);\n this.logger.debug(\n { sessionId: this.id, length: text.length },\n 'Pasted text with bracketed paste mode'\n );\n } else {\n this.ptyProcess.write(text);\n this.logger.debug(\n { sessionId: this.id, length: text.length },\n 'Pasted text without bracketed paste'\n );\n }\n }\n\n /**\n * Kill the PTY process\n */\n /**\n * Notify the session of an external hook event (e.g. from Claude Code HTTP hooks).\n * Resets the stall timer so hook-managed sessions don't get false stall escalations.\n * For \"task_complete\" events, transitions the session to ready.\n */\n notifyHookEvent(event: string): void {\n switch (event) {\n case 'tool_running':\n // Hook confirms a tool is running — reset stall timer to avoid false escalation.\n this._lastActivityAt = new Date();\n this.resetStallTimer();\n // Intentionally silent — fires on every tool use and is too noisy even at debug level.\n break;\n case 'task_complete':\n // Hook says the agent finished — transition to ready.\n this._status = 'ready';\n this._lastBlockingPromptHash = null;\n this._lastBlockingPromptEmitAt = 0;\n this.outputBuffer = '';\n this.clearStallTimer();\n this.emit('status_changed', 'ready');\n this.emit('task_complete');\n this.logger.info(\n { sessionId: this.id, event },\n 'Hook event: task_complete → ready'\n );\n break;\n case 'permission_approved':\n // Permission handled by hook — reset stall timer and clear the output\n // buffer so stale prompt text doesn't re-trigger detection. Keep the\n // hash intact: TUI re-renders may briefly show the same prompt text\n // before the agent processes the approval. With the hash preserved,\n // detectBlockingPrompt deduplicates those re-renders instead of\n // emitting a flood of duplicate blocking_prompt events.\n this._lastActivityAt = new Date();\n this.outputBuffer = '';\n this.resetStallTimer();\n break;\n default:\n // Generic activity signal — just reset stall timer.\n this._lastActivityAt = new Date();\n this.resetStallTimer();\n break;\n }\n }\n\n kill(signal?: string): void {\n if (this.ptyProcess) {\n this._status = 'stopping';\n this.clearStallTimer();\n this.cancelTaskComplete();\n this.cancelReadySettle();\n this.ptyProcess.kill(signal);\n this.logger.info({ sessionId: this.id, signal }, 'Killing PTY session');\n }\n }\n\n /**\n * Get current output buffer\n */\n getOutputBuffer(): string {\n return this.outputBuffer;\n }\n\n /**\n * Clear output buffer\n */\n clearOutputBuffer(): void {\n this.outputBuffer = '';\n }\n\n /**\n * Convert to SessionHandle\n */\n toHandle(): SessionHandle {\n return {\n id: this.id,\n name: this.config.name,\n type: this.config.type,\n status: this._status,\n pid: this.pid,\n startedAt: this._startedAt ?? undefined,\n lastActivityAt: this._lastActivityAt ?? undefined,\n };\n }\n}\n","/**\n * Task completion trace analysis helpers.\n *\n * Parses structured \"Task completion trace\" logs and builds a compact\n * per-turn confidence timeline useful for debugging idle/completion detection.\n */\n\nexport interface TaskCompletionTraceRecord {\n sessionId?: string;\n adapterType?: string;\n event: string;\n status?: string;\n taskCompletePending?: boolean;\n signal?: boolean;\n wasPending?: boolean;\n debounceMs?: number;\n detectTaskComplete?: boolean;\n detectReady?: boolean;\n detectLoading?: boolean;\n tailHash?: string;\n tailSnippet?: string;\n timestamp?: string | number | Date;\n}\n\nexport interface TaskCompletionTimelineStep {\n event: string;\n atIndex: number;\n status:\n | 'active'\n | 'active_loading'\n | 'likely_complete'\n | 'completed'\n | 'rejected';\n confidence: number;\n signal?: boolean;\n detectTaskComplete?: boolean;\n detectReady?: boolean;\n detectLoading?: boolean;\n}\n\nexport interface TaskCompletionTurnTimeline {\n turn: number;\n startIndex: number;\n endIndex: number;\n completed: boolean;\n maxConfidence: number;\n finalConfidence: number;\n events: TaskCompletionTimelineStep[];\n}\n\nexport interface TaskCompletionTimelineResult {\n turns: TaskCompletionTurnTimeline[];\n totalRecords: number;\n ignoredRecords: number;\n}\n\nexport interface BuildTimelineOptions {\n adapterType?: string;\n}\n\n/**\n * Extract trace records from mixed log inputs.\n * Accepts structured objects and JSON lines.\n */\nexport function extractTaskCompletionTraceRecords(\n entries: Array<string | Record<string, unknown>>\n): TaskCompletionTraceRecord[] {\n const out: TaskCompletionTraceRecord[] = [];\n\n for (const entry of entries) {\n let obj: Record<string, unknown> | null = null;\n\n if (typeof entry === 'string') {\n const line = entry.trim();\n if (!line.startsWith('{') || !line.endsWith('}')) continue;\n try {\n obj = JSON.parse(line) as Record<string, unknown>;\n } catch {\n continue;\n }\n } else if (entry && typeof entry === 'object') {\n obj = entry;\n }\n\n if (!obj) continue;\n if (obj.msg !== 'Task completion trace') continue;\n if (typeof obj.event !== 'string') continue;\n\n out.push({\n sessionId: asString(obj.sessionId),\n adapterType: asString(obj.adapterType),\n event: obj.event,\n status: asString(obj.status),\n taskCompletePending: asBool(obj.taskCompletePending),\n signal: asBool(obj.signal),\n wasPending: asBool(obj.wasPending),\n debounceMs: asNumber(obj.debounceMs),\n detectTaskComplete: asBool(obj.detectTaskComplete),\n detectReady: asBool(obj.detectReady),\n detectLoading: asBool(obj.detectLoading),\n tailHash: asString(obj.tailHash),\n tailSnippet: asString(obj.tailSnippet),\n timestamp: asTimestamp(obj.time) ?? asTimestamp(obj.timestamp),\n });\n }\n\n return out;\n}\n\n/**\n * Build a per-turn confidence timeline from task-completion traces.\n */\nexport function buildTaskCompletionTimeline(\n records: TaskCompletionTraceRecord[],\n options: BuildTimelineOptions = {}\n): TaskCompletionTimelineResult {\n const filtered = records.filter((r) => {\n if (!options.adapterType) return true;\n return r.adapterType === options.adapterType;\n });\n\n const turns: TaskCompletionTurnTimeline[] = [];\n let current: TaskCompletionTurnTimeline | null = null;\n let ignored = 0;\n\n filtered.forEach((record, index) => {\n if (record.event === 'busy_signal' && current && current.completed) {\n current = null;\n }\n\n if (!current) {\n current = {\n turn: turns.length + 1,\n startIndex: index,\n endIndex: index,\n completed: false,\n maxConfidence: 0,\n finalConfidence: 0,\n events: [],\n };\n turns.push(current);\n }\n\n const step = toStep(record, index);\n if (!step) {\n ignored++;\n return;\n }\n\n current.events.push(step);\n current.endIndex = index;\n current.maxConfidence = Math.max(current.maxConfidence, step.confidence);\n current.finalConfidence = step.confidence;\n\n if (step.status === 'completed') {\n current.completed = true;\n }\n });\n\n return {\n turns,\n totalRecords: filtered.length,\n ignoredRecords: ignored,\n };\n}\n\nfunction toStep(\n record: TaskCompletionTraceRecord,\n atIndex: number\n): TaskCompletionTimelineStep | null {\n const event = record.event;\n const confidence = scoreConfidence(record);\n\n if (event === 'transition_ready') {\n return withCommon(record, {\n event,\n atIndex,\n status: 'completed',\n confidence: 100,\n });\n }\n\n if (\n event === 'debounce_reject_signal' ||\n event === 'debounce_reject_status'\n ) {\n return withCommon(record, {\n event,\n atIndex,\n status: 'rejected',\n confidence,\n });\n }\n\n if (record.detectLoading) {\n return withCommon(record, {\n event,\n atIndex,\n status: 'active_loading',\n confidence,\n });\n }\n\n if (event === 'debounce_fire' && record.signal) {\n return withCommon(record, {\n event,\n atIndex,\n status: 'likely_complete',\n confidence,\n });\n }\n\n if (\n event === 'busy_signal' ||\n event === 'debounce_schedule' ||\n event === 'debounce_fire'\n ) {\n return withCommon(record, {\n event,\n atIndex,\n status: 'active',\n confidence,\n });\n }\n\n return null;\n}\n\nfunction scoreConfidence(record: TaskCompletionTraceRecord): number {\n let score = 10;\n\n if (record.detectLoading) score -= 40;\n if (record.detectReady) score += 20;\n if (record.detectTaskComplete) score += 45;\n if (record.signal) score += 20;\n if (\n record.event === 'debounce_reject_signal' ||\n record.event === 'debounce_reject_status'\n ) {\n score -= 30;\n }\n if (record.event === 'transition_ready') score = 100;\n\n if (score < 0) return 0;\n if (score > 100) return 100;\n return score;\n}\n\nfunction withCommon(\n record: TaskCompletionTraceRecord,\n step: Omit<\n TaskCompletionTimelineStep,\n 'signal' | 'detectTaskComplete' | 'detectReady' | 'detectLoading'\n >\n): TaskCompletionTimelineStep {\n return {\n ...step,\n signal: record.signal,\n detectTaskComplete: record.detectTaskComplete,\n detectReady: record.detectReady,\n detectLoading: record.detectLoading,\n };\n}\n\nfunction asString(value: unknown): string | undefined {\n return typeof value === 'string' ? value : undefined;\n}\n\nfunction asBool(value: unknown): boolean | undefined {\n return typeof value === 'boolean' ? value : undefined;\n}\n\nfunction asNumber(value: unknown): number | undefined {\n return typeof value === 'number' ? value : undefined;\n}\n\nfunction asTimestamp(value: unknown): string | number | Date | undefined {\n if (\n typeof value === 'string' ||\n typeof value === 'number' ||\n value instanceof Date\n ) {\n return value;\n }\n return undefined;\n}\n"],"mappings":"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","names":["import_adapter_types","import_adapter_types","import_node_child_process","import_node_events","import_node_events"]}
|