@delt/claude-alarm 1.3.0 → 1.4.1

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/shared/config.ts","../../src/shared/constants.ts","../../src/shared/crash-guard.ts","../../src/shared/logger.ts","../../src/codex/adapter.ts","../../src/codex/hub-link.ts","../../src/channel/hub-client.ts","../../src/codex/transport.ts","../../src/codex/inputs.ts","../../src/codex/mapping.ts","../../src/codex/rpc.ts","../../src/codex/approvals.ts","../../src/shared/hub-url.ts","../../src/codex/hub-target.ts","../../src/codex/instance-lock.ts","../../src/codex/main.ts"],"sourcesContent":["import fs from 'node:fs';\r\nimport path from 'node:path';\r\nimport { randomUUID } from 'node:crypto';\r\nimport { CONFIG_DIR, CONFIG_FILE, DEFAULT_HUB_HOST, DEFAULT_HUB_PORT } from './constants.js';\r\nimport type { AppConfig } from './types.js';\r\n\r\nconst DEFAULT_CONFIG: AppConfig = {\r\n hub: {\r\n host: DEFAULT_HUB_HOST,\r\n port: DEFAULT_HUB_PORT,\r\n },\r\n notifications: {\r\n desktop: true,\r\n sound: true,\r\n },\r\n webhooks: [],\r\n};\r\n\r\nexport function ensureConfigDir(): void {\r\n if (!fs.existsSync(CONFIG_DIR)) {\r\n fs.mkdirSync(CONFIG_DIR, { recursive: true });\r\n }\r\n}\r\n\r\nexport function loadConfig(): AppConfig {\r\n ensureConfigDir();\r\n let config: AppConfig;\r\n if (!fs.existsSync(CONFIG_FILE)) {\r\n config = { ...DEFAULT_CONFIG, hub: { ...DEFAULT_CONFIG.hub } };\r\n } else {\r\n try {\r\n const raw = fs.readFileSync(CONFIG_FILE, 'utf-8');\r\n const parsed = JSON.parse(raw);\r\n config = { ...DEFAULT_CONFIG, ...parsed, hub: { ...DEFAULT_CONFIG.hub, ...parsed.hub }, ...(parsed.telegram ? { telegram: parsed.telegram } : {}) };\r\n } catch {\r\n config = { ...DEFAULT_CONFIG, hub: { ...DEFAULT_CONFIG.hub } };\r\n }\r\n }\r\n\r\n // Auto-generate token if missing\r\n if (!config.hub.token) {\r\n config.hub.token = randomUUID();\r\n saveConfig(config);\r\n }\r\n\r\n return config;\r\n}\r\n\r\n/** Get the current token, generating one if needed */\r\nexport function getOrCreateToken(): string {\r\n const config = loadConfig();\r\n return config.hub.token!;\r\n}\r\n\r\nexport function saveConfig(config: AppConfig): void {\r\n ensureConfigDir();\r\n fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), { encoding: 'utf-8', mode: 0o600 });\r\n}\r\n\r\nexport function setCodexEnabled(enabled: boolean): AppConfig {\r\n const config = loadConfig();\r\n config.codex = { ...config.codex, enabled };\r\n saveConfig(config);\r\n return config;\r\n}\r\n\r\nexport function shouldOfferCodex(config: AppConfig, installed: boolean): boolean {\r\n return installed && config.codex === undefined;\r\n}\r\n\r\n/**\r\n * Add claude-alarm as an MCP channel server to .mcp.json\r\n */\r\nexport function setupMcpConfig(targetDir?: string): string {\r\n const dir = targetDir ?? process.cwd();\r\n const mcpPath = path.join(dir, '.mcp.json');\r\n\r\n let mcpConfig: Record<string, any> = {};\r\n if (fs.existsSync(mcpPath)) {\r\n try {\r\n mcpConfig = JSON.parse(fs.readFileSync(mcpPath, 'utf-8'));\r\n } catch {\r\n mcpConfig = {};\r\n }\r\n }\r\n\r\n if (!mcpConfig.mcpServers) {\r\n mcpConfig.mcpServers = {};\r\n }\r\n\r\n mcpConfig.mcpServers['claude-alarm'] = {\r\n command: 'npx',\r\n args: ['-y', '@delt/claude-alarm', 'serve'],\r\n env: {\r\n CLAUDE_ALARM_SESSION_NAME: path.basename(dir),\r\n },\r\n };\r\n\r\n fs.writeFileSync(mcpPath, JSON.stringify(mcpConfig, null, 2), 'utf-8');\r\n return mcpPath;\r\n}\r\n","import path from 'node:path';\r\nimport os from 'node:os';\r\n\r\nexport const DEFAULT_HUB_HOST = '127.0.0.1';\r\nexport const DEFAULT_HUB_PORT = 7900;\r\n\r\nexport const CONFIG_DIR = path.join(os.homedir(), '.claude-alarm');\r\nexport const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');\r\nexport const PID_FILE = path.join(CONFIG_DIR, 'hub.pid');\r\nexport const LOG_FILE = path.join(CONFIG_DIR, 'hub.log');\r\nexport const UPLOADS_DIR = path.join(CONFIG_DIR, 'uploads');\r\nexport const CODEX_PID_FILE = path.join(CONFIG_DIR, 'codex.pid');\r\nexport const CODEX_LOG_FILE = path.join(CONFIG_DIR, 'codex.log');\r\n\r\nexport const WS_PATH_CHANNEL = '/ws/channel';\r\nexport const WS_PATH_DASHBOARD = '/ws/dashboard';\r\nexport const WS_PATH_CODEX = '/ws/codex';\r\n\r\nexport const CHANNEL_SERVER_NAME = 'claude-alarm';\r\nexport const CHANNEL_SERVER_VERSION = '0.1.0';\r\n","import fs from 'node:fs';\nimport { CONFIG_DIR, LOG_FILE } from './constants.js';\nimport { logger } from './logger.js';\n\nconst BURST_WINDOW_MS = 60_000;\nconst BURST_LIMIT = 10;\n\nfunction appendToLog(text: string): void {\n try {\n fs.mkdirSync(CONFIG_DIR, { recursive: true });\n fs.appendFileSync(LOG_FILE, text, 'utf-8');\n } catch {}\n}\n\nfunction describe(err: unknown): string {\n if (err instanceof Error) return err.stack ?? `${err.name}: ${err.message}`;\n try {\n return JSON.stringify(err);\n } catch {\n return String(err);\n }\n}\n\n/**\n * Last-resort net for exceptions no local handler caught.\n *\n * The hub keeps running afterwards: a notification relay that dies silently is\n * worse than one running on possibly-degraded state, and in foreground mode the\n * stack trace would otherwise vanish with the console window. A repeated burst\n * still exits, so a self-feeding error loop cannot spin forever.\n */\nexport function installCrashGuard(context: string): void {\n let recent: number[] = [];\n\n const handle = (kind: string, err: unknown): void => {\n const stack = describe(err);\n appendToLog(`\\n[${new Date().toISOString()}] ${kind} (${context})\\n${stack}\\n`);\n logger.error(`${kind} caught by crash guard: ${stack}`);\n\n const now = Date.now();\n recent = recent.filter((t) => now - t < BURST_WINDOW_MS);\n recent.push(now);\n\n if (recent.length > BURST_LIMIT) {\n const msg = `${recent.length} unhandled errors within ${BURST_WINDOW_MS / 1000}s — exiting`;\n appendToLog(`[${new Date().toISOString()}] ${msg}\\n`);\n logger.error(msg);\n process.exit(1);\n }\n };\n\n process.on('uncaughtException', (err) => handle('uncaughtException', err));\n process.on('unhandledRejection', (reason) => handle('unhandledRejection', reason));\n}\n\nexport function logStartup(context: string): void {\n appendToLog(`\\n[${new Date().toISOString()}] ${context} started (pid ${process.pid})\\n`);\n}\n","/**\r\n * Logger that writes to stderr only.\r\n * CRITICAL: In MCP channel servers, stdout is used for the stdio protocol.\r\n * Any console.log() would corrupt the protocol. Always use this logger.\r\n */\r\nexport const logger = {\r\n info(msg: string, ...args: unknown[]) {\r\n console.error(`[claude-alarm] ${msg}`, ...args);\r\n },\r\n warn(msg: string, ...args: unknown[]) {\r\n console.error(`[claude-alarm WARN] ${msg}`, ...args);\r\n },\r\n error(msg: string, ...args: unknown[]) {\r\n console.error(`[claude-alarm ERROR] ${msg}`, ...args);\r\n },\r\n debug(msg: string, ...args: unknown[]) {\r\n if (process.env.CLAUDE_ALARM_DEBUG) {\r\n console.error(`[claude-alarm DEBUG] ${msg}`, ...args);\r\n }\r\n },\r\n};\r\n","import fs from 'node:fs';\r\nimport os from 'node:os';\r\nimport path from 'node:path';\r\nimport { CodexHubLink } from './hub-link.js';\r\nimport { randomUUID } from 'node:crypto';\r\nimport { HubClient } from '../channel/hub-client.js';\r\nimport { CHANNEL_SERVER_VERSION } from '../shared/constants.js';\r\nimport { logger } from '../shared/logger.js';\r\nimport type { ChannelMessage, CodexCall, NotifyLevel, SessionInfo } from '../shared/types.js';\r\nimport { connectProxy, type ProxyConnection, type SpawnFn } from './transport.js';\r\nimport { imageInput, textInput, type UserInput } from './inputs.js';\r\nimport { RpcClient, type RpcId } from './rpc.js';\r\nimport { approvalView, fileChanges, type ApprovalChoice, type ApprovalView, type FileChange } from './approvals.js';\r\nimport {\r\n cleanFolder,\r\n codexSessionId,\r\n finalAnswer,\r\n hubStatus,\r\n isTrackable,\r\n threadTitle,\r\n type AgentMessage,\r\n type CodexThread,\r\n type CodexThreadStatus,\r\n} from './mapping.js';\r\n\r\nexport type FirstConnect =\r\n | { connected: true; userAgent?: string }\r\n | { connected: false; error: string; notFound: boolean };\r\n\r\nexport interface CodexAdapterOptions {\r\n command: string;\r\n hub: { host: string; port: number; token?: string };\r\n spawnFn?: SpawnFn;\r\n reconnectMinMs?: number;\r\n reconnectMaxMs?: number;\r\n idleReleaseMs?: number;\r\n noticeTimeoutMs?: number;\r\n hostName?: string;\r\n linkReconnectMs?: number;\r\n rpcTimeoutMs?: number;\r\n onFirstConnect?: (outcome: FirstConnect) => void;\r\n}\r\n\r\ninterface Tracked {\r\n thread: CodexThread;\r\n hub: HubClient;\r\n subscribed: boolean;\r\n wantSubscribed: boolean;\r\n sync: Promise<void>;\r\n pendingTurn: boolean;\r\n sending: Promise<void>;\r\n turns: Map<string, AgentMessage[]>;\r\n releaseTimer?: ReturnType<typeof setTimeout>;\r\n unrelayed: boolean;\r\n files: Map<string, FileChange[]>;\r\n}\r\n\r\n// Requests a person must answer that claude-alarm cannot relay; the user is pointed back to Codex.\r\nconst USER_REQUESTS = new Set(['item/tool/requestUserInput', 'item/permissions/requestApproval', 'mcpServer/elicitation/request']);\r\n\r\ninterface PendingApproval {\r\n threadId: string;\r\n rpcId: RpcId;\r\n turnId?: string;\r\n choices: ApprovalChoice[];\r\n answered: boolean;\r\n}\r\n\r\nexport class CodexAdapter {\r\n private conn?: ProxyConnection;\r\n private rpc?: RpcClient;\r\n private threads = new Map<string, Tracked>();\r\n private approvals = new Map<string, PendingApproval>();\r\n private stopped = false;\r\n private retryTimer?: ReturnType<typeof setTimeout>;\r\n private delay: number;\r\n private notFoundNotice: 'unsent' | 'sending' | 'sent' = 'unsent';\r\n private firstConnectReported = false;\r\n\r\n private pins = new Set<string>();\r\n private ready = false;\r\n private readonly hostName: string;\r\n private readonly link: CodexHubLink;\r\n\r\n constructor(private opts: CodexAdapterOptions) {\r\n this.delay = opts.reconnectMinMs ?? 2000;\r\n this.hostName = opts.hostName ?? os.hostname();\r\n this.link = new CodexHubLink(opts.hub, { id: randomUUID(), host: this.hostName }, (call) => this.onCall(call), opts.linkReconnectMs);\r\n }\r\n\r\n start(): void {\r\n this.stopped = false;\r\n this.link.connect();\r\n void this.connect();\r\n }\r\n\r\n stop(): void {\r\n this.stopped = true;\r\n this.link.disconnect();\r\n if (this.retryTimer) clearTimeout(this.retryTimer);\r\n this.retryTimer = undefined;\r\n for (const id of [...this.threads.keys()]) this.drop(id);\r\n this.conn?.close();\r\n }\r\n\r\n private async connect(): Promise<void> {\r\n let rpc: RpcClient | undefined;\r\n try {\r\n const conn = await connectProxy(this.opts.command, this.opts.spawnFn);\r\n if (this.stopped) {\r\n conn.close();\r\n return;\r\n }\r\n const live = new RpcClient(conn.ws, this.opts.rpcTimeoutMs);\r\n rpc = live;\r\n live.on('notification', (method: string, params: any) => this.onNotification(method, params));\r\n live.on('request', (id: RpcId, method: string, params: any) => this.onServerRequest(id, method, params));\r\n live.on('close', () => {\r\n if (this.rpc === live) this.onDaemonLost();\r\n });\r\n this.conn = conn;\r\n this.rpc = live;\r\n const init = await live.request<{ userAgent?: string }>('initialize', {\r\n clientInfo: { name: 'claude-alarm', version: CHANNEL_SERVER_VERSION },\r\n });\r\n live.notify('initialized');\r\n logger.info(`Connected to Codex daemon (${init.userAgent ?? 'unknown version'})`);\r\n this.reportFirstConnect({ connected: true, ...(init.userAgent ? { userAgent: init.userAgent } : {}) });\r\n await this.discover();\r\n if (this.rpc === live) this.setReady(true);\r\n this.delay = this.opts.reconnectMinMs ?? 2000;\r\n } catch (err) {\r\n this.setReady(false);\r\n logger.warn(`Codex daemon connection failed: ${(err as Error).message}`);\r\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') this.noticeNotFound();\r\n this.reportFirstConnect({\r\n connected: false,\r\n error: (err as Error).message,\r\n notFound: (err as NodeJS.ErrnoException).code === 'ENOENT',\r\n });\r\n if (rpc && this.rpc === rpc) {\r\n this.rpc = undefined;\r\n this.conn?.close();\r\n this.conn = undefined;\r\n }\r\n for (const id of [...this.threads.keys()]) this.drop(id);\r\n this.scheduleRetry();\r\n }\r\n }\r\n\r\n private onDaemonLost(): void {\r\n this.setReady(false);\r\n this.rpc = undefined;\r\n this.conn?.close();\r\n this.conn = undefined;\r\n for (const id of [...this.threads.keys()]) this.drop(id);\r\n if (!this.stopped) logger.warn('Codex daemon connection lost');\r\n this.scheduleRetry();\r\n }\r\n\r\n private scheduleRetry(): void {\r\n if (this.stopped || this.retryTimer) return;\r\n this.retryTimer = setTimeout(() => {\r\n this.retryTimer = undefined;\r\n void this.connect();\r\n }, this.delay);\r\n this.delay = Math.min(this.delay * 2, this.opts.reconnectMaxMs ?? 60_000);\r\n }\r\n\r\n private reportFirstConnect(outcome: FirstConnect): void {\r\n if (this.firstConnectReported || this.stopped) return;\r\n this.firstConnectReported = true;\r\n try {\r\n this.opts.onFirstConnect?.(outcome);\r\n } catch (err) {\r\n // Inside connect(), a throw here would be taken for a daemon failure and drop a healthy connection.\r\n logger.debug(`First-connect observer failed: ${(err as Error).message}`);\r\n }\r\n }\r\n\r\n private noticeNotFound(): void {\r\n if (this.notFoundNotice !== 'unsent') return;\r\n this.notFoundNotice = 'sending';\r\n const { host, port, token } = this.opts.hub;\r\n fetch(`http://${host}:${port}/api/notify`, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json', ...(token ? { Authorization: `Bearer ${token}` } : {}) },\r\n body: JSON.stringify({\r\n title: 'Codex not found',\r\n message: `The Codex adapter cannot find \"${this.opts.command}\". Open a new terminal and restart the hub, or set \"codex.command\" in ~/.claude-alarm/config.json.`,\r\n level: 'warning',\r\n }),\r\n signal: AbortSignal.timeout(this.opts.noticeTimeoutMs ?? 5000),\r\n })\r\n .then((res) => {\r\n this.notFoundNotice = res.ok ? 'sent' : 'unsent';\r\n if (!res.ok) logger.debug(`Codex not-found notice was refused (${res.status})`);\r\n })\r\n .catch((err) => {\r\n // The hub replies only after its desktop notification closes, which can outlast the timeout, so a timeout still means it arrived.\r\n this.notFoundNotice = (err as Error).name === 'TimeoutError' ? 'sent' : 'unsent';\r\n logger.debug(`Codex not-found notice failed: ${(err as Error).message}`);\r\n });\r\n }\r\n\r\n private setReady(ready: boolean): void {\r\n this.ready = ready;\r\n this.link.setReady(ready);\r\n }\r\n\r\n private requireDaemon(): RpcClient {\r\n if (!this.ready || !this.rpc) throw new Error(`Codex is not connected on ${this.hostName}.`);\r\n return this.rpc;\r\n }\r\n\r\n private async onCall(call: CodexCall): Promise<unknown> {\r\n if (call.kind === 'folders') return { folders: await this.folders() };\r\n return { sessionId: await this.create(call.cwd) };\r\n }\r\n\r\n private async folders(): Promise<string[]> {\r\n const page = await this.requireDaemon().request<{ data: CodexThread[] }>('thread/list', { limit: 50, sortKey: 'updated_at' });\r\n return [...new Set(page.data.map((t) => t.cwd).filter(Boolean))].slice(0, 10);\r\n }\r\n\r\n private async create(input: string): Promise<string> {\r\n const rpc = this.requireDaemon();\r\n const cwd = cleanFolder(input);\r\n const isDir = path.isAbsolute(cwd) && (await fs.promises.stat(cwd).then((s) => s.isDirectory(), () => false));\r\n if (!isDir) throw new Error(`Folder not found on ${this.hostName}: ${cwd}`);\r\n let thread: CodexThread;\r\n try {\r\n // No RPC timeout: an answer dropped after a timeout would leave a conversation this connection holds but never pins.\r\n ({ thread } = await rpc.request<{ thread: CodexThread }>('thread/start', { cwd, sandbox: 'danger-full-access', approvalPolicy: 'never' }, null));\r\n } catch (err) {\r\n throw new Error(`Codex could not start the conversation: ${(err as Error).message}`);\r\n }\r\n this.pins.add(thread.id);\r\n this.upsert(thread);\r\n const t = this.threads.get(thread.id);\r\n if (!t) {\r\n this.pins.delete(thread.id);\r\n throw new Error('Codex started a conversation claude-alarm cannot follow.');\r\n }\r\n // The starting connection is already subscribed; marking it before upsert's queued sync runs avoids a resume that fails before the first turn.\r\n t.subscribed = true;\r\n return codexSessionId(thread.id);\r\n }\r\n\r\n private async discover(): Promise<void> {\r\n const rpc = this.rpc!;\r\n const pinned = [...this.pins];\r\n const ids: string[] = [];\r\n let cursor: string | null | undefined;\r\n do {\r\n const page = await rpc.request<{ data: string[]; nextCursor?: string | null }>('thread/loaded/list', cursor ? { cursor } : {});\r\n ids.push(...page.data);\r\n cursor = page.nextCursor;\r\n } while (cursor);\r\n for (const id of ids) await this.refresh(id);\r\n // A list read on a connection that has since been replaced says nothing about what the daemon holds now.\r\n if (this.rpc !== rpc) return;\r\n for (const id of pinned) if (!ids.includes(id)) this.pins.delete(id);\r\n }\r\n\r\n private async refresh(threadId: string): Promise<void> {\r\n try {\r\n const { thread } = await this.rpc!.request<{ thread: CodexThread }>('thread/read', { threadId, includeTurns: false });\r\n this.upsert(thread);\r\n } catch (err) {\r\n logger.debug(`thread/read ${threadId} failed: ${(err as Error).message}`);\r\n }\r\n }\r\n\r\n private upsert(thread: CodexThread): void {\r\n if (!isTrackable(thread)) {\r\n this.drop(thread.id);\r\n return;\r\n }\r\n const existing = this.threads.get(thread.id);\r\n if (existing) {\r\n existing.thread = thread;\r\n existing.hub.reregister();\r\n } else {\r\n const { host, port, token } = this.opts.hub;\r\n const hub = new HubClient(codexSessionId(thread.id), threadTitle(thread), host, port, token, () => undefined, () =>\r\n this.registration(thread.id),\r\n );\r\n this.threads.set(thread.id, {\r\n thread,\r\n hub,\r\n subscribed: false,\r\n wantSubscribed: false,\r\n sync: Promise.resolve(),\r\n pendingTurn: false,\r\n sending: Promise.resolve(),\r\n turns: new Map(),\r\n unrelayed: false,\r\n files: new Map(),\r\n });\r\n hub.onMessage((msg) => this.onHubMessage(thread.id, msg));\r\n hub.connect();\r\n }\r\n void this.want(thread.id, thread.status.type === 'active');\r\n }\r\n\r\n private registration(threadId: string): Partial<SessionInfo> {\r\n const t = this.threads.get(threadId);\r\n if (!t) return {};\r\n const title = threadTitle(t.thread);\r\n return { name: title, title, cwd: t.thread.cwd, agentKind: 'codex', status: hubStatus(t.thread.status), closable: this.pins.has(threadId) };\r\n }\r\n\r\n private want(threadId: string, subscribed: boolean): Promise<void> {\r\n const t = this.threads.get(threadId);\r\n if (!t) return Promise.resolve();\r\n t.wantSubscribed = subscribed || this.pins.has(threadId);\r\n t.sync = t.sync.then(() => this.syncSubscription(t));\r\n return t.sync;\r\n }\r\n\r\n private async syncSubscription(t: Tracked): Promise<void> {\r\n const threadId = t.thread.id;\r\n if (!this.rpc || this.threads.get(threadId) !== t || t.subscribed === t.wantSubscribed) return;\r\n try {\r\n if (t.wantSubscribed) {\r\n // Only these two fields: any other resume field overrides the user's own thread settings.\r\n await this.rpc.request('thread/resume', { threadId, excludeTurns: true });\r\n t.subscribed = true;\r\n t.unrelayed = false;\r\n } else {\r\n // The daemon unloads a conversation 60 s after its last subscriber leaves; staying subscribed would keep closed Codex windows alive.\r\n await this.rpc.request('thread/unsubscribe', { threadId });\r\n t.subscribed = false;\r\n }\r\n } catch (err) {\r\n logger.debug(`subscription sync for ${threadId} deferred: ${(err as Error).message}`);\r\n // A turn started in the Codex window has no other way to reach claude-alarm, so its reply is lost unless a later resume succeeds.\r\n if (t.wantSubscribed && !t.subscribed && t.thread.status.type === 'active') t.unrelayed = true;\r\n }\r\n }\r\n\r\n private releaseLater(t: Tracked): void {\r\n clearTimeout(t.releaseTimer);\r\n t.releaseTimer = setTimeout(() => {\r\n t.releaseTimer = undefined;\r\n if (this.threads.get(t.thread.id) === t && t.thread.status.type !== 'active' && !t.pendingTurn) {\r\n void this.want(t.thread.id, false);\r\n }\r\n }, this.opts.idleReleaseMs ?? 1000);\r\n }\r\n\r\n private drop(threadId: string): void {\r\n const t = this.threads.get(threadId);\r\n if (!t) return;\r\n for (const [requestId, a] of this.approvals) {\r\n if (a.threadId === threadId) this.finishApproval(requestId, 'expired');\r\n }\r\n this.threads.delete(threadId);\r\n clearTimeout(t.releaseTimer);\r\n t.releaseTimer = undefined;\r\n t.hub.disconnect();\r\n }\r\n\r\n private busy(t: Tracked): boolean {\r\n return t.thread.status.type === 'active' || t.pendingTurn;\r\n }\r\n\r\n private async close(threadId: string): Promise<void> {\r\n const t = this.threads.get(threadId);\r\n if (!t || !this.pins.delete(threadId)) return;\r\n t.hub.reregister();\r\n if (this.busy(t)) return;\r\n // drop() before the unsubscribe finishes would skip it: syncSubscription stops once the thread is untracked.\r\n await this.want(threadId, false);\r\n // A message or an active broadcast may arrive while unsubscribing; the conversation then ends like a close during work.\r\n if (this.threads.get(threadId) !== t || this.busy(t) || t.wantSubscribed) return;\r\n if (!t.subscribed) {\r\n this.drop(threadId);\r\n return;\r\n }\r\n // syncSubscription swallows unsubscribe errors, so a still-set flag is the only sign it failed.\r\n this.pins.add(threadId);\r\n t.hub.reregister();\r\n void this.want(threadId, true);\r\n this.notify(threadId, 'Not closed', 'Codex did not release the conversation. Try closing it again.', 'warning');\r\n }\r\n\r\n private onNotification(method: string, params: any): void {\r\n switch (method) {\r\n case 'thread/started':\r\n this.upsert(params.thread);\r\n break;\r\n case 'thread/status/changed':\r\n this.onStatus(params.threadId, params.status);\r\n break;\r\n case 'thread/name/updated': {\r\n const t = this.threads.get(params.threadId);\r\n if (t) {\r\n t.thread.name = params.threadName;\r\n t.hub.reregister();\r\n }\r\n break;\r\n }\r\n case 'thread/closed':\r\n case 'thread/archived':\r\n case 'thread/deleted':\r\n this.pins.delete(params.threadId);\r\n this.drop(params.threadId);\r\n break;\r\n case 'item/started':\r\n if (params.item?.type === 'fileChange') this.threads.get(params.threadId)?.files.set(params.item.id, fileChanges(params.item));\r\n break;\r\n case 'item/completed':\r\n if (params.item?.type === 'agentMessage') this.collect(params.threadId, params.turnId, params.item);\r\n if (params.item?.type === 'fileChange') this.threads.get(params.threadId)?.files.delete(params.item.id);\r\n break;\r\n case 'serverRequest/resolved':\r\n this.onResolved(params.threadId, params.requestId);\r\n break;\r\n case 'turn/completed':\r\n this.onTurnCompleted(params.threadId, params.turn);\r\n break;\r\n }\r\n }\r\n\r\n private onStatus(threadId: string, status: CodexThreadStatus): void {\r\n const t = this.threads.get(threadId);\r\n if (!t) {\r\n if (status.type !== 'notLoaded') void this.refresh(threadId);\r\n return;\r\n }\r\n if (status.type === 'notLoaded') {\r\n this.pins.delete(threadId);\r\n this.drop(threadId);\r\n return;\r\n }\r\n t.thread.status = status;\r\n t.pendingTurn = false;\r\n t.hub.send({ type: 'status', sessionId: codexSessionId(threadId), status: hubStatus(status) });\r\n if (status.type === 'systemError') this.notify(threadId, 'Codex error', 'The Codex conversation hit a system error.', 'error');\r\n if (status.type === 'active') {\r\n void this.want(threadId, true);\r\n return;\r\n }\r\n if (t.unrelayed) {\r\n t.unrelayed = false;\r\n this.notify(threadId, 'Reply not relayed', 'Codex finished, but its reply could not be relayed here. Check the Codex window.', 'warning');\r\n }\r\n // The daemon emits idle just before turn/completed; unsubscribing at once could cut off the reply.\r\n this.releaseLater(t);\r\n }\r\n\r\n private collect(threadId: string, turnId: string, item: AgentMessage): void {\r\n const t = this.threads.get(threadId);\r\n if (!t) return;\r\n const list = t.turns.get(turnId) ?? [];\r\n list.push({ text: item.text, phase: item.phase });\r\n t.turns.set(turnId, list);\r\n }\r\n\r\n private onTurnCompleted(\r\n threadId: string,\r\n turn: { id: string; status: string; error?: { message: string } | null; items?: Array<{ type: string } & AgentMessage> },\r\n ): void {\r\n for (const [requestId, a] of this.approvals) {\r\n if (a.threadId === threadId && a.turnId === turn.id) this.finishApproval(requestId, 'resolved');\r\n }\r\n const t = this.threads.get(threadId);\r\n if (!t) return;\r\n const collected = t.turns.get(turn.id) ?? [];\r\n t.turns.delete(turn.id);\r\n t.files.clear();\r\n // The daemon announces name changes but not preview changes, so a title taken from the folder is re-read once text exists.\r\n if (!t.thread.name?.trim() && !t.thread.preview?.trim()) void this.refresh(threadId);\r\n if (t.thread.status.type !== 'active') void this.want(threadId, false);\r\n if (turn.status === 'failed' || turn.error) {\r\n this.notify(threadId, 'Codex task failed', turn.error?.message ?? 'The task ended with an error.', 'error');\r\n return;\r\n }\r\n if (turn.status === 'interrupted') {\r\n this.notify(threadId, 'Codex task stopped', 'The task was interrupted.', 'info');\r\n return;\r\n }\r\n // turn/completed may carry only a summary of the items, so prefer what was collected live.\r\n const fromTurn = (turn.items ?? []).filter((i) => i.type === 'agentMessage');\r\n const text = finalAnswer(collected.length ? collected : fromTurn);\r\n if (text) t.hub.send({ type: 'reply', sessionId: codexSessionId(threadId), content: text });\r\n }\r\n\r\n private onHubMessage(threadId: string, msg: ChannelMessage): void {\r\n if (msg.type === 'message_to_session') {\r\n this.enqueue(threadId, async () => textInput(msg.content, msg.source));\r\n } else if (msg.type === 'image_to_session') {\r\n this.enqueue(threadId, () => imageInput(msg.imagePath, msg.mimeType, msg.content, msg.source));\r\n } else if (msg.type === 'permission_response') {\r\n this.answer(threadId, msg.requestId, msg.choiceId);\r\n } else if (msg.type === 'codex_close') {\r\n void this.close(threadId);\r\n }\r\n }\r\n\r\n // One message at a time per conversation, so a message right behind another sees the turn the first one started.\r\n private enqueue(threadId: string, build: () => Promise<UserInput[]>): void {\r\n const t = this.threads.get(threadId);\r\n if (!t) return;\r\n t.sending = t.sending\r\n .then(() => this.deliver(t, build))\r\n .catch((err) => logger.warn(`Codex delivery for ${threadId} failed: ${(err as Error).message}`));\r\n }\r\n\r\n private async deliver(t: Tracked, build: () => Promise<UserInput[]>): Promise<void> {\r\n const threadId = t.thread.id;\r\n if (this.threads.get(threadId) !== t) return;\r\n // A steer is accepted while an approval is pending but read only after it is answered, which reads like an answer.\r\n if (hubStatus(t.thread.status) === 'waiting_input') {\r\n this.notify(threadId, 'Not delivered', 'Codex is waiting for an approval or input. Answer it first, then send the message again.', 'warning');\r\n return;\r\n }\r\n let input: UserInput[];\r\n try {\r\n input = await build();\r\n } catch (err) {\r\n logger.debug(`Codex input for ${threadId} could not be built: ${(err as Error).message}`);\r\n this.notify(threadId, 'Not delivered', 'The image could not be read here, so it was not delivered. Codex may be running on another PC.', 'warning');\r\n return;\r\n }\r\n if (this.threads.get(threadId) !== t) return;\r\n t.pendingTurn = true;\r\n const wasUnrelayed = t.unrelayed;\r\n try {\r\n const rpc = this.rpc;\r\n if (!rpc) throw new Error('not connected to the Codex daemon');\r\n await this.want(threadId, true);\r\n // A new conversation cannot be subscribed before its first turn (no rollout found); the active broadcast retries it.\r\n const unsubscribed = !t.subscribed;\r\n const running = await this.runningTurn(rpc, threadId);\r\n if (this.threads.get(threadId) !== t) return;\r\n if (unsubscribed) t.unrelayed = true;\r\n if (running) {\r\n await rpc.request('turn/steer', { threadId, expectedTurnId: running, input });\r\n this.notify(threadId, 'Queued', 'Queued: Codex will read it after its current step.', 'info');\r\n return;\r\n }\r\n await rpc.request('turn/start', { threadId, input });\r\n } catch (err) {\r\n t.pendingTurn = false;\r\n t.unrelayed = wasUnrelayed;\r\n this.releaseLater(t);\r\n this.notify(threadId, 'Not delivered', `Codex rejected the message: ${(err as Error).message}`, 'warning');\r\n }\r\n }\r\n\r\n // The list is unavailable before a new conversation's first turn; starting a turn is safe then, since turn/start steers a running turn.\r\n private async runningTurn(rpc: RpcClient, threadId: string): Promise<string | undefined> {\r\n try {\r\n const page = await rpc.request<{ data: Array<{ id: string; status: string }> }>('thread/turns/list', {\r\n threadId,\r\n limit: 1,\r\n sortDirection: 'desc',\r\n });\r\n const turn = page.data?.[0];\r\n return turn?.status === 'inProgress' ? turn.id : undefined;\r\n } catch (err) {\r\n logger.debug(`thread/turns/list ${threadId} failed: ${(err as Error).message}`);\r\n return undefined;\r\n }\r\n }\r\n\r\n private onServerRequest(rpcId: RpcId, method: string, params: any): void {\r\n const t = params?.threadId ? this.threads.get(params.threadId) : undefined;\r\n let view: ApprovalView | null = null;\r\n let broken = false;\r\n if (t) {\r\n try {\r\n view = approvalView(method, params, t.files.get(params.itemId));\r\n } catch (err) {\r\n broken = true;\r\n logger.warn(`Codex ${method} could not be shown: ${(err as Error).message}`);\r\n }\r\n }\r\n if (!t || !view) {\r\n if (t && (broken || USER_REQUESTS.has(method))) {\r\n this.waitingInCodex(t.thread.id);\r\n } else {\r\n logger.debug(`Ignoring Codex server request ${method}`);\r\n }\r\n return;\r\n }\r\n // The daemon re-sends a pending request to every new subscriber, so a resubscribe can deliver it twice.\r\n for (const a of this.approvals.values()) {\r\n if (a.threadId === t.thread.id && a.rpcId === rpcId) return;\r\n }\r\n const requestId = randomUUID();\r\n try {\r\n this.approvals.set(requestId, { threadId: t.thread.id, rpcId, turnId: params.turnId, choices: view.choices, answered: false });\r\n t.hub.send({\r\n type: 'permission_request',\r\n sessionId: codexSessionId(t.thread.id),\r\n requestId,\r\n toolName: view.toolName,\r\n description: view.description,\r\n inputPreview: view.inputPreview,\r\n timestamp: Date.now(),\r\n choices: view.choices.map((c, i) => ({ id: String(i), label: c.label })),\r\n });\r\n } catch (err) {\r\n this.approvals.delete(requestId);\r\n logger.warn(`Codex ${method} could not be relayed: ${(err as Error).message}`);\r\n // No reply to the daemon: the same request is open in the Codex window, and an error reply could cancel it there.\r\n this.waitingInCodex(t.thread.id);\r\n }\r\n }\r\n\r\n private waitingInCodex(threadId: string): void {\r\n this.notify(threadId, 'Codex is waiting', 'Codex asked for input that claude-alarm cannot relay. Handle it in Codex.', 'warning');\r\n }\r\n\r\n private answer(threadId: string, requestId: string, choiceId?: string): void {\r\n const a = this.approvals.get(requestId);\r\n if (!a || a.threadId !== threadId || a.answered || !this.rpc || !choiceId || !/^\\d+$/.test(choiceId)) return;\r\n const choice = a.choices[Number(choiceId)];\r\n if (!choice) return;\r\n a.answered = true;\r\n this.rpc.respond(a.rpcId, choice.response);\r\n }\r\n\r\n private onResolved(threadId: string, rpcId: RpcId): void {\r\n for (const [requestId, a] of this.approvals) {\r\n if (a.threadId === threadId && a.rpcId === rpcId) this.finishApproval(requestId, 'resolved');\r\n }\r\n }\r\n\r\n private finishApproval(requestId: string, state: 'resolved' | 'expired'): void {\r\n const a = this.approvals.get(requestId);\r\n if (!a) return;\r\n this.approvals.delete(requestId);\r\n this.threads.get(a.threadId)?.hub.send({ type: 'permission_resolved', sessionId: codexSessionId(a.threadId), requestId, state });\r\n }\r\n\r\n private notify(threadId: string, title: string, message: string, level: NotifyLevel): void {\r\n this.threads.get(threadId)?.hub.send({ type: 'notify', sessionId: codexSessionId(threadId), title, message, level });\r\n }\r\n}\r\n","import WebSocket from 'ws';\r\nimport { WS_PATH_CODEX } from '../shared/constants.js';\r\nimport { logger } from '../shared/logger.js';\r\nimport type { CodexCall, CodexLinkMessage } from '../shared/types.js';\r\n\r\nexport class CodexHubLink {\r\n private ws: WebSocket | null = null;\r\n private retryTimer: ReturnType<typeof setTimeout> | null = null;\r\n private pingTimer: ReturnType<typeof setTimeout> | null = null;\r\n private closed = true;\r\n private ready = false;\r\n\r\n constructor(\r\n private hub: { host: string; port: number; token?: string },\r\n private identity: { id: string; host: string },\r\n private onCall: (call: CodexCall) => Promise<unknown>,\r\n private reconnectMs = 5000,\r\n private pingTimeoutMs = 75_000,\r\n ) {}\r\n\r\n connect(): void {\r\n this.closed = false;\r\n const query = this.hub.token ? `?token=${encodeURIComponent(this.hub.token)}` : '';\r\n let ws: WebSocket;\r\n try {\r\n ws = new WebSocket(`ws://${this.hub.host}:${this.hub.port}${WS_PATH_CODEX}${query}`);\r\n } catch (err) {\r\n logger.debug(`Codex hub link failed: ${(err as Error).message}`);\r\n this.scheduleReconnect();\r\n return;\r\n }\r\n this.ws = ws;\r\n ws.on('open', () => {\r\n if (this.ws !== ws) return;\r\n this.armWatchdog(ws);\r\n this.hello();\r\n });\r\n ws.on('ping', () => this.armWatchdog(ws));\r\n ws.on('message', (data) => {\r\n if (this.ws === ws) this.onMessage(String(data));\r\n });\r\n ws.on('close', () => {\r\n if (this.ws !== ws) return;\r\n this.clearWatchdog();\r\n this.ws = null;\r\n this.scheduleReconnect();\r\n });\r\n ws.on('error', (err) => logger.debug(`Codex hub link error: ${err.message}`));\r\n }\r\n\r\n setReady(ready: boolean): void {\r\n if (this.ready === ready) return;\r\n this.ready = ready;\r\n this.hello();\r\n }\r\n\r\n disconnect(): void {\r\n this.closed = true;\r\n this.clearWatchdog();\r\n if (this.retryTimer) clearTimeout(this.retryTimer);\r\n this.retryTimer = null;\r\n const ws = this.ws;\r\n this.ws = null;\r\n ws?.close();\r\n }\r\n\r\n private hello(): void {\r\n this.send({ type: 'adapter_hello', adapter: { ...this.identity, ready: this.ready } });\r\n }\r\n\r\n private send(msg: CodexLinkMessage): void {\r\n if (this.ws?.readyState === WebSocket.OPEN) this.ws.send(JSON.stringify(msg));\r\n }\r\n\r\n private onMessage(text: string): void {\r\n let msg: CodexLinkMessage;\r\n try {\r\n msg = JSON.parse(text) as CodexLinkMessage;\r\n } catch {\r\n return;\r\n }\r\n if (!msg || typeof msg !== 'object') return;\r\n if (msg.type !== 'adapter_call') return;\r\n const { requestId, call } = msg;\r\n this.onCall(call).then(\r\n (data) => this.send({ type: 'adapter_result', requestId, ok: true, data }),\r\n (err) => this.send({ type: 'adapter_result', requestId, ok: false, error: (err as Error).message }),\r\n );\r\n }\r\n\r\n private clearWatchdog(): void {\r\n if (this.pingTimer) clearTimeout(this.pingTimer);\r\n this.pingTimer = null;\r\n }\r\n\r\n private armWatchdog(ws: WebSocket): void {\r\n if (this.ws !== ws) return;\r\n this.clearWatchdog();\r\n // The hub pings every 30 s, so two missed pings mean it already dropped this socket.\r\n this.pingTimer = setTimeout(() => {\r\n if (this.ws === ws) ws.terminate();\r\n }, this.pingTimeoutMs);\r\n }\r\n\r\n private scheduleReconnect(): void {\r\n if (this.closed || this.retryTimer) return;\r\n this.retryTimer = setTimeout(() => {\r\n this.retryTimer = null;\r\n this.connect();\r\n }, this.reconnectMs);\r\n }\r\n}\r\n","import WebSocket from 'ws';\r\nimport { logger } from '../shared/logger.js';\r\nimport { DEFAULT_HUB_HOST, DEFAULT_HUB_PORT, WS_PATH_CHANNEL } from '../shared/constants.js';\r\nimport type { ChannelMessage, SessionInfo } from '../shared/types.js';\r\n\r\nexport class HubClient {\r\n private ws: WebSocket | null = null;\r\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\r\n private messageHandlers: Array<(msg: ChannelMessage) => void> = [];\r\n private queue: ChannelMessage[] = [];\r\n private connected = false;\r\n private closed = false;\r\n\r\n constructor(\r\n private sessionId: string,\r\n private sessionName: string,\r\n private hubHost = DEFAULT_HUB_HOST,\r\n private hubPort = DEFAULT_HUB_PORT,\r\n private token?: string,\r\n private getPeerName: () => string | undefined = () => undefined,\r\n private getRegistration: () => Partial<SessionInfo> = () => ({}),\r\n ) {}\r\n\r\n connect(): void {\r\n this.closed = false;\r\n const tokenQuery = this.token ? `?token=${encodeURIComponent(this.token)}` : '';\r\n const url = `ws://${this.hubHost}:${this.hubPort}${WS_PATH_CHANNEL}${tokenQuery}`;\r\n logger.debug(`Connecting to hub at ${url}`);\r\n\r\n try {\r\n const ws = new WebSocket(url);\r\n this.ws = ws;\r\n\r\n ws.on('open', () => {\r\n if (this.ws !== ws) return;\r\n logger.info('Connected to hub');\r\n this.connected = true;\r\n\r\n this.ws!.send(JSON.stringify(this.registration()));\r\n\r\n // Flush queued messages\r\n for (const msg of this.queue) {\r\n this.ws!.send(JSON.stringify(msg));\r\n }\r\n this.queue = [];\r\n });\r\n\r\n ws.on('message', (data) => {\r\n if (this.ws !== ws) return;\r\n try {\r\n const msg = JSON.parse(data.toString()) as ChannelMessage;\r\n for (const handler of this.messageHandlers) {\r\n handler(msg);\r\n }\r\n } catch (err) {\r\n logger.warn('Failed to parse hub message:', err);\r\n }\r\n });\r\n\r\n ws.on('close', () => {\r\n if (this.ws !== ws) return;\r\n logger.info('Disconnected from hub');\r\n this.connected = false;\r\n if (!this.closed) this.scheduleReconnect();\r\n });\r\n\r\n ws.on('error', (err) => {\r\n if (this.ws !== ws) return;\r\n logger.debug(`Hub connection error: ${err.message}`);\r\n this.connected = false;\r\n });\r\n } catch {\r\n logger.debug('Failed to connect to hub, will retry');\r\n this.scheduleReconnect();\r\n }\r\n }\r\n\r\n send(msg: ChannelMessage): void {\r\n if (this.connected && this.ws?.readyState === WebSocket.OPEN) {\r\n this.ws.send(JSON.stringify(msg));\r\n } else {\r\n if (this.queue.length < 100) {\r\n this.queue.push(msg);\r\n }\r\n logger.debug('Hub not connected, message queued');\r\n }\r\n }\r\n\r\n onMessage(handler: (msg: ChannelMessage) => void): void {\r\n this.messageHandlers.push(handler);\r\n }\r\n\r\n disconnect(): void {\r\n this.closed = true;\r\n if (this.reconnectTimer) {\r\n clearTimeout(this.reconnectTimer);\r\n this.reconnectTimer = null;\r\n }\r\n if (this.ws) {\r\n this.ws.close();\r\n this.ws = null;\r\n }\r\n this.connected = false;\r\n }\r\n\r\n reregister(): void {\r\n if (this.connected && this.ws?.readyState === WebSocket.OPEN) {\r\n this.ws.send(JSON.stringify(this.registration()));\r\n }\r\n }\r\n\r\n private registration(): ChannelMessage {\r\n return {\r\n type: 'register',\r\n session: {\r\n id: this.sessionId,\r\n name: this.sessionName,\r\n status: 'idle',\r\n connectedAt: Date.now(),\r\n lastActivity: Date.now(),\r\n cwd: process.cwd(),\r\n channelEnabled: true,\r\n peerName: this.getPeerName(),\r\n ...this.getRegistration(),\r\n },\r\n };\r\n }\r\n\r\n private scheduleReconnect(): void {\r\n if (this.reconnectTimer || this.closed) return;\r\n this.reconnectTimer = setTimeout(() => {\r\n this.reconnectTimer = null;\r\n this.connect();\r\n }, 5000);\r\n }\r\n}\r\n","import { spawn, type ChildProcess } from 'node:child_process';\r\nimport fs from 'node:fs';\r\nimport path from 'node:path';\r\nimport { Duplex } from 'node:stream';\r\nimport WebSocket, { type ClientOptions } from 'ws';\r\nimport { logger } from '../shared/logger.js';\r\n\r\nexport type SpawnFn = (command: string, args: string[]) => ChildProcess;\r\n\r\nexport interface ProxyConnection {\r\n ws: WebSocket;\r\n close(): void;\r\n}\r\n\r\n// npm installs Codex on Windows as a codex.cmd shim, which only runs through a shell.\r\nexport function resolveCommand(\r\n command: string,\r\n platform: NodeJS.Platform = process.platform,\r\n env: NodeJS.ProcessEnv = process.env,\r\n): { file: string; shell: boolean } {\r\n if (platform !== 'win32') return { file: command, shell: false };\r\n if (/[\\\\/]/.test(command) || path.extname(command)) return { file: command, shell: /\\.(cmd|bat)$/i.test(command) };\r\n const file = findCodex(command, platform, env);\r\n return file ? { file, shell: file.endsWith('.cmd') } : { file: command, shell: false };\r\n}\r\n\r\nexport function findOnPath(\r\n command: string,\r\n platform: NodeJS.Platform = process.platform,\r\n env: NodeJS.ProcessEnv = process.env,\r\n): string | undefined {\r\n const dirs = (env.PATH ?? env.Path ?? '').split(path.delimiter).filter(Boolean);\r\n for (const ext of platform === 'win32' ? ['.exe', '.cmd'] : ['']) {\r\n for (const dir of dirs) {\r\n const file = path.join(dir, command + ext);\r\n if (fs.existsSync(file)) return file;\r\n }\r\n }\r\n return undefined;\r\n}\r\n\r\n// A terminal opened before Codex was installed keeps its old PATH, so also look where the installers put codex.\r\nexport function findCodex(\r\n command: string,\r\n platform: NodeJS.Platform = process.platform,\r\n env: NodeJS.ProcessEnv = process.env,\r\n): string | undefined {\r\n const onPath = findOnPath(command, platform, env);\r\n if (onPath || platform !== 'win32') return onPath;\r\n const candidates = [\r\n env.LOCALAPPDATA && path.join(env.LOCALAPPDATA, 'Programs', 'OpenAI', 'Codex', 'bin', `${command}.exe`),\r\n env.APPDATA && path.join(env.APPDATA, 'npm', `${command}.cmd`),\r\n ];\r\n return candidates.find((file): file is string => !!file && fs.existsSync(file));\r\n}\r\n\r\nexport const defaultSpawn: SpawnFn = (command, args) => {\r\n const { file, shell } = resolveCommand(command);\r\n if (shell) return spawn(`\"${file}\" ${args.join(' ')}`, { stdio: 'pipe', windowsHide: true, shell: true });\r\n return spawn(file, args, { stdio: 'pipe', windowsHide: true });\r\n};\r\n\r\n// The daemon control socket speaks WebSocket, not JSONL: `codex app-server proxy` only relays bytes.\r\nexport const HANDSHAKE_TIMEOUT_MS = 10_000;\r\n\r\nexport function connectProxy(command: string, spawnFn: SpawnFn = defaultSpawn, timeoutMs = HANDSHAKE_TIMEOUT_MS): Promise<ProxyConnection> {\r\n const child = spawnFn(command, ['app-server', 'proxy']);\r\n child.stdin?.on('error', () => {});\r\n child.stderr?.on('data', (d) => logger.debug(`codex proxy: ${String(d).trim()}`));\r\n\r\n const stream = new Duplex({\r\n read() {},\r\n write(chunk, _encoding, callback) {\r\n if (child.stdin?.writable) child.stdin.write(chunk, callback);\r\n else callback();\r\n },\r\n final(callback) {\r\n child.stdin?.end();\r\n callback();\r\n },\r\n });\r\n child.stdout?.on('data', (d) => stream.push(d));\r\n child.stdout?.on('end', () => stream.push(null));\r\n Object.assign(stream, { setNoDelay() {}, setTimeout() {}, setKeepAlive() {}, ref() {}, unref() {} });\r\n\r\n const ws = new WebSocket('ws://localhost/', {\r\n createConnection: (() => stream) as unknown as ClientOptions['createConnection'],\r\n });\r\n const close = () => {\r\n ws.terminate();\r\n child.kill();\r\n };\r\n\r\n return new Promise((resolve, reject) => {\r\n let settled = false;\r\n const timer = setTimeout(() => fail(new Error(`codex daemon did not answer within ${timeoutMs / 1000}s`)), timeoutMs);\r\n const fail = (err: Error) => {\r\n if (settled) return;\r\n settled = true;\r\n clearTimeout(timer);\r\n close();\r\n reject(err);\r\n };\r\n child.on('error', fail);\r\n child.once('exit', (code) => fail(new Error(`codex proxy exited (code ${code})`)));\r\n ws.on('error', fail);\r\n ws.once('open', () => {\r\n if (settled) return;\r\n settled = true;\r\n clearTimeout(timer);\r\n child.on('error', (err) => logger.warn(`codex proxy error: ${err.message}`));\r\n ws.on('error', (err) => logger.warn(`codex daemon socket error: ${err.message}`));\r\n resolve({ ws, close });\r\n });\r\n });\r\n}\r\n","import fs from 'node:fs/promises';\r\nimport type { MessageSource } from '../shared/types.js';\r\nimport { withSourcePrefix } from './mapping.js';\r\n\r\nexport type UserInput = { type: 'text'; text: string } | { type: 'image'; url: string };\r\n\r\nconst IMAGE_TYPES = new Set(['image/png', 'image/jpeg', 'image/gif', 'image/webp']);\r\n\r\nexport function textInput(content: string, source?: MessageSource): UserInput[] {\r\n return [{ type: 'text', text: withSourcePrefix(content, source) }];\r\n}\r\n\r\n// Codex reads a localImage path only when it builds the model request, and the hub deletes uploads after 5 minutes, so the bytes go inline.\r\nexport async function imageInput(imagePath: string, mimeType: string, caption: string | undefined, source?: MessageSource): Promise<UserInput[]> {\r\n if (!IMAGE_TYPES.has(mimeType)) throw new Error(`unsupported image type ${mimeType}`);\r\n const data = await fs.readFile(imagePath);\r\n return [\r\n { type: 'text', text: withSourcePrefix(caption?.trim() || '(image)', source) },\r\n { type: 'image', url: `data:${mimeType};base64,${data.toString('base64')}` },\r\n ];\r\n}\r\n","import type { MessageSource, SessionStatus } from '../shared/types.js';\r\n\r\nexport type CodexThreadStatus =\r\n | { type: 'notLoaded' | 'idle' | 'systemError' }\r\n | { type: 'active'; activeFlags: string[] };\r\n\r\nexport interface CodexThread {\r\n id: string;\r\n name?: string | null;\r\n preview?: string;\r\n cwd: string;\r\n status: CodexThreadStatus;\r\n parentThreadId?: string | null;\r\n ephemeral?: boolean;\r\n}\r\n\r\nexport interface AgentMessage {\r\n text: string;\r\n phase?: string | null;\r\n}\r\n\r\nconst TITLE_MAX = 30;\r\nconst SOURCE_LABEL: Record<MessageSource, string> = { dashboard: 'Dashboard', telegram: 'Telegram', api: 'API' };\r\n\r\nconst SOURCE_PREFIX = new RegExp(`^\\\\[claude-alarm(?: · (?:${Object.values(SOURCE_LABEL).join('|')}))?\\\\] ?`);\r\n\r\nexport function codexSessionId(threadId: string): string {\r\n return `codex:${threadId}`;\r\n}\r\n\r\nexport function isTrackable(thread: CodexThread): boolean {\r\n return !thread.parentThreadId && !thread.ephemeral && thread.status.type !== 'notLoaded';\r\n}\r\n\r\nexport function threadTitle(thread: CodexThread): string {\r\n const name = thread.name?.trim();\r\n if (name) return name;\r\n const preview = (thread.preview ?? '').replace(/\\s+/g, ' ').trim().replace(SOURCE_PREFIX, '').trim();\r\n if (preview) return preview.length > TITLE_MAX ? `${preview.slice(0, TITLE_MAX)}…` : preview;\r\n return thread.cwd.replace(/^.*[/\\\\]/, '') || thread.id.slice(0, 8);\r\n}\r\n\r\nexport function hubStatus(status: CodexThreadStatus): SessionStatus {\r\n if (status.type !== 'active') return 'idle';\r\n return status.activeFlags.some((f) => f === 'waitingOnApproval' || f === 'waitingOnUserInput') ? 'waiting_input' : 'working';\r\n}\r\n\r\nexport function withSourcePrefix(content: string, source?: MessageSource): string {\r\n return source ? `[claude-alarm · ${SOURCE_LABEL[source]}] ${content}` : `[claude-alarm] ${content}`;\r\n}\r\n\r\nexport function finalAnswer(messages: AgentMessage[]): string | null {\r\n const finals = messages.filter((m) => m.phase === 'final_answer').map((m) => m.text);\r\n if (finals.length) return finals.join('\\n\\n');\r\n return messages.at(-1)?.text ?? null;\r\n}\r\n\r\n// Explorer's \"Copy as path\" wraps the path in double quotes.\r\nexport function cleanFolder(input: string): string {\r\n const s = input.trim();\r\n return s.length >= 2 && s.startsWith('\"') && s.endsWith('\"') ? s.slice(1, -1).trim() : s;\r\n}\r\n","import { EventEmitter } from 'node:events';\r\nimport type WebSocket from 'ws';\r\nimport { logger } from '../shared/logger.js';\r\n\r\nexport type RpcId = number | string;\r\n\r\nexport class RpcError extends Error {\r\n constructor(public readonly code: number, message: string) {\r\n super(message);\r\n }\r\n}\r\n\r\ninterface Pending {\r\n resolve: (value: any) => void;\r\n reject: (err: Error) => void;\r\n timer?: ReturnType<typeof setTimeout>;\r\n}\r\n\r\nexport class RpcClient extends EventEmitter {\r\n private nextId = 1;\r\n private pending = new Map<RpcId, Pending>();\r\n\r\n constructor(private ws: WebSocket, private timeoutMs = 30_000) {\r\n super();\r\n ws.on('message', (data) => this.onMessage(String(data)));\r\n ws.on('close', () => {\r\n for (const p of this.pending.values()) {\r\n clearTimeout(p.timer);\r\n p.reject(new Error('connection closed'));\r\n }\r\n this.pending.clear();\r\n this.emit('close');\r\n });\r\n }\r\n\r\n request<T = any>(method: string, params?: unknown, timeoutMs: number | null = this.timeoutMs): Promise<T> {\r\n if (this.ws.readyState !== this.ws.OPEN) return Promise.reject(new Error('connection closed'));\r\n const id = this.nextId++;\r\n return new Promise<T>((resolve, reject) => {\r\n const timer =\r\n timeoutMs === null\r\n ? undefined\r\n : setTimeout(() => {\r\n this.pending.delete(id);\r\n reject(new Error(`${method} timed out`));\r\n }, timeoutMs);\r\n this.pending.set(id, { resolve, reject, timer });\r\n this.ws.send(JSON.stringify(params === undefined ? { id, method } : { id, method, params }));\r\n });\r\n }\r\n\r\n notify(method: string, params?: unknown): void {\r\n if (this.ws.readyState !== this.ws.OPEN) return;\r\n this.ws.send(JSON.stringify(params === undefined ? { method } : { method, params }));\r\n }\r\n\r\n respond(id: RpcId, result: unknown): void {\r\n if (this.ws.readyState !== this.ws.OPEN) return;\r\n this.ws.send(JSON.stringify({ id, result }));\r\n }\r\n\r\n // ws stops reading the socket for good if a 'message' listener throws.\r\n private guarded(method: string, fn: () => void): void {\r\n try {\r\n fn();\r\n } catch (err) {\r\n logger.warn(`Codex ${method} handling failed: ${(err as Error).message}`);\r\n }\r\n }\r\n\r\n private onMessage(text: string): void {\r\n let msg: any;\r\n try {\r\n msg = JSON.parse(text);\r\n } catch {\r\n return;\r\n }\r\n if (!msg || typeof msg !== 'object') return;\r\n if (msg.method === undefined && msg.id !== undefined) {\r\n const p = this.pending.get(msg.id);\r\n if (!p) return;\r\n this.pending.delete(msg.id);\r\n clearTimeout(p.timer);\r\n if (msg.error) p.reject(new RpcError(msg.error.code, msg.error.message));\r\n else p.resolve(msg.result);\r\n } else if (msg.method !== undefined && msg.id !== undefined) {\r\n this.guarded(msg.method, () => this.emit('request', msg.id, msg.method, msg.params));\r\n } else if (msg.method !== undefined) {\r\n this.guarded(msg.method, () => this.emit('notification', msg.method, msg.params));\r\n }\r\n }\r\n}\r\n","export interface ApprovalChoice {\r\n label: string;\r\n response: unknown;\r\n}\r\n\r\nexport interface ApprovalView {\r\n toolName: string;\r\n description: string;\r\n inputPreview: string;\r\n choices: ApprovalChoice[];\r\n}\r\n\r\nexport interface FileChange {\r\n path: string;\r\n diff: string;\r\n}\r\n\r\nconst MAX_DESCRIPTION = 500;\r\nconst MAX_PREVIEW = 50_000;\r\n\r\nfunction clip(text: string, max: number): string {\r\n return text.length > max ? `${text.slice(0, max)}…(truncated)` : text;\r\n}\r\n\r\nconst DECISION_LABELS: Record<string, string> = {\r\n accept: 'Allow once',\r\n acceptForSession: 'Allow for this session',\r\n acceptWithExecpolicyAmendment: 'Always allow this command',\r\n decline: 'Decline',\r\n cancel: 'Cancel task',\r\n};\r\n\r\nexport function decisionLabel(decision: unknown): string {\r\n if (typeof decision === 'string') return DECISION_LABELS[decision] ?? decision;\r\n const [key, value] = Object.entries(decision ?? {})[0] ?? [];\r\n if (key === 'applyNetworkPolicyAmendment') {\r\n const rule = (value as { network_policy_amendment?: { host?: string; action?: string } } | undefined)?.network_policy_amendment;\r\n return `Network rule: ${rule?.host ?? 'unknown host'} ${rule?.action ?? ''}`.trim();\r\n }\r\n return key ? (DECISION_LABELS[key] ?? key) : 'Unknown';\r\n}\r\n\r\nfunction decisions(offered: unknown[]): ApprovalChoice[] {\r\n return offered.map((decision) => ({ label: decisionLabel(decision), response: { decision } }));\r\n}\r\n\r\nexport function fileChanges(item: { changes?: Array<{ path?: string; diff?: string }> }): FileChange[] {\r\n return (item.changes ?? []).map((c) => ({ path: String(c.path ?? ''), diff: String(c.diff ?? '') }));\r\n}\r\n\r\nexport function approvalView(method: string, params: any, files: FileChange[] = []): ApprovalView | null {\r\n switch (method) {\r\n case 'item/commandExecution/requestApproval': {\r\n // availableDecisions is sent by Codex 0.159.3 but absent from its generated schema.\r\n const offered: unknown[] =\r\n Array.isArray(params.availableDecisions) && params.availableDecisions.length\r\n ? params.availableDecisions\r\n : ['accept', 'decline', 'cancel'];\r\n const command = params.command ?? (params.commandActions ?? []).map((a: { command: string }) => a.command).join('\\n');\r\n return {\r\n toolName: 'Command',\r\n description: clip(params.reason || 'Codex wants to run a command.', MAX_DESCRIPTION),\r\n inputPreview: JSON.stringify({ command: clip(String(command), MAX_PREVIEW) }),\r\n choices: decisions(offered),\r\n };\r\n }\r\n case 'item/fileChange/requestApproval': {\r\n // The request names only the item; the file list arrives earlier in item/started.\r\n const content = files.length\r\n ? files.map((f) => (f.diff ? `${f.path}\\n${f.diff}` : f.path)).join('\\n\\n')\r\n : 'The file list is not available here. Check the Codex window.';\r\n return {\r\n toolName: 'File change',\r\n description: clip(params.reason || 'Codex wants to change files.', MAX_DESCRIPTION),\r\n inputPreview: JSON.stringify({ content: clip(content, MAX_PREVIEW) }),\r\n choices: decisions(['accept', 'acceptForSession', 'decline', 'cancel']),\r\n };\r\n }\r\n case 'mcpServer/elicitation/request':\r\n if (params._meta?.codex_approval_kind !== 'mcp_tool_call') return null;\r\n return {\r\n toolName: 'MCP tool',\r\n description: clip(`MCP server: ${params.serverName ?? 'unknown'}`, MAX_DESCRIPTION),\r\n inputPreview: JSON.stringify({ content: clip(String(params.message ?? ''), MAX_PREVIEW) }),\r\n choices: [\r\n { label: 'Allow', response: { action: 'accept', content: {} } },\r\n { label: 'Decline', response: { action: 'decline' } },\r\n { label: 'Cancel', response: { action: 'cancel' } },\r\n ],\r\n };\r\n default:\r\n return null;\r\n }\r\n}\r\n","import net from 'node:net';\r\n\r\nexport function hubUrlHost(host: string): string {\r\n if (host === '' || host === '0.0.0.0') return '127.0.0.1';\r\n if (host === '::') return '[::1]';\r\n return net.isIPv6(host) ? `[${host}]` : host;\r\n}\r\n","import { hubUrlHost } from '../shared/hub-url.js';\r\nimport type { AppConfig } from '../shared/types.js';\r\n\r\nexport interface AdapterHub {\r\n host: string;\r\n port: number;\r\n token?: string;\r\n fromEnv: { host: boolean; port: boolean; token: boolean };\r\n}\r\n\r\nexport function resolveAdapterHub(config: AppConfig, env: NodeJS.ProcessEnv = process.env): AdapterHub {\r\n const envHost = env.CLAUDE_ALARM_HUB_HOST;\r\n const envPort = env.CLAUDE_ALARM_HUB_PORT;\r\n const envToken = env.CLAUDE_ALARM_HUB_TOKEN;\r\n return {\r\n host: hubUrlHost(envHost ?? config.hub.host),\r\n port: envPort ? parseInt(envPort, 10) : config.hub.port,\r\n token: envToken ?? config.hub.token,\r\n fromEnv: { host: envHost !== undefined, port: !!envPort, token: envToken !== undefined },\r\n };\r\n}\r\n","import crypto from 'node:crypto';\r\nimport fs from 'node:fs';\r\nimport net from 'node:net';\r\nimport path from 'node:path';\r\n\r\nexport const CONTROL_PROTOCOL = 1;\r\nexport const STALE_GUARD_MS = 10_000;\r\nexport const STOP_PROOF_LABEL = 'claude-alarm codex stop';\r\nconst MAX_LINE_BYTES = 4096;\r\nconst REQUEST_IDLE_MS = 2000;\r\nconst MAX_SOCKET_PATH_BYTES = 103;\r\n\r\nexport function stopProof(token: string): string {\r\n return crypto.createHmac('sha256', token).update(STOP_PROOF_LABEL).digest('hex');\r\n}\r\n\r\nexport type OwnerState =\r\n | { state: 'running'; pid: number }\r\n | { state: 'absent' }\r\n | { state: 'unknown'; error: string };\r\n\r\nexport type StopResult =\r\n | { state: 'stopping'; pid: number }\r\n | { state: 'unauthorized' }\r\n | { state: 'absent' }\r\n | { state: 'unknown'; error: string };\r\n\r\nexport type Acquired =\r\n | { kind: 'owner'; close: () => Promise<void> }\r\n | { kind: 'held'; pid: number }\r\n | { kind: 'unknown'; error: string };\r\n\r\nexport type Attempt = Acquired | { kind: 'busy' };\r\n\r\nexport interface LockOwner {\r\n pid: number;\r\n token: string;\r\n onStop: () => void;\r\n}\r\n\r\ntype LockFs = Pick<typeof fs, 'mkdirSync' | 'rmdirSync' | 'statSync' | 'unlinkSync'>;\r\n\r\nexport interface LockDeps {\r\n platform?: NodeJS.Platform;\r\n listen?: (endpoint: string, owner: LockOwner) => Promise<Attempt>;\r\n queryOwner?: (endpoint: string) => Promise<OwnerState>;\r\n fs?: LockFs;\r\n now?: () => number;\r\n}\r\n\r\nexport function controlEndpoint(configDir: string, platform: NodeJS.Platform = process.platform): string {\r\n if (platform !== 'win32') return path.posix.join(configDir, 'codex.sock');\r\n let dir: string;\r\n try {\r\n dir = fs.realpathSync.native(configDir);\r\n } catch {\r\n dir = path.win32.resolve(configDir);\r\n }\r\n const hash = crypto.createHash('sha256').update(dir.toLowerCase()).digest('hex').slice(0, 16);\r\n return `\\\\\\\\.\\\\pipe\\\\claude-alarm-codex-${hash}`;\r\n}\r\n\r\ntype Answer = { reply: unknown } | { state: 'absent' } | { state: 'unknown'; error: string };\r\n\r\nfunction ask(endpoint: string, request: object, timeoutMs: number): Promise<Answer> {\r\n return new Promise((resolve) => {\r\n let buffer = '';\r\n let settled = false;\r\n const socket = net.connect(endpoint);\r\n const finish = (answer: Answer) => {\r\n if (settled) return;\r\n settled = true;\r\n clearTimeout(timer);\r\n socket.destroy();\r\n resolve(answer);\r\n };\r\n const timer = setTimeout(() => finish({ state: 'unknown', error: `no answer within ${timeoutMs}ms` }), timeoutMs);\r\n socket.setEncoding('utf8');\r\n socket.on('connect', () => socket.write(`${JSON.stringify(request)}\\n`));\r\n socket.on('data', (chunk: string) => {\r\n buffer += chunk;\r\n const end = buffer.indexOf('\\n');\r\n if (end < 0) {\r\n if (Buffer.byteLength(buffer) > MAX_LINE_BYTES) finish({ state: 'unknown', error: 'reply too long' });\r\n return;\r\n }\r\n try {\r\n finish({ reply: JSON.parse(buffer.slice(0, end)) });\r\n } catch {\r\n finish({ state: 'unknown', error: 'unreadable reply' });\r\n }\r\n });\r\n socket.on('end', () => finish({ state: 'unknown', error: 'closed without a reply' }));\r\n socket.on('error', (err: NodeJS.ErrnoException) => {\r\n if (err.code === 'ENOENT' || err.code === 'ECONNREFUSED') finish({ state: 'absent' });\r\n else finish({ state: 'unknown', error: err.code ?? err.message });\r\n });\r\n });\r\n}\r\n\r\nexport async function queryOwner(endpoint: string, timeoutMs = 1000): Promise<OwnerState> {\r\n const answer = await ask(endpoint, { type: 'status' }, timeoutMs);\r\n if (!('reply' in answer)) return answer;\r\n const reply = answer.reply as { type?: unknown; protocol?: unknown; pid?: unknown } | null;\r\n if (reply?.type === 'status' && reply.protocol === CONTROL_PROTOCOL && Number.isInteger(reply.pid)) {\r\n return { state: 'running', pid: reply.pid as number };\r\n }\r\n return { state: 'unknown', error: 'unexpected reply' };\r\n}\r\n\r\nexport async function requestStop(endpoint: string, token: string, timeoutMs = 1000): Promise<StopResult> {\r\n const answer = await ask(endpoint, { type: 'stop', proof: stopProof(token) }, timeoutMs);\r\n if (!('reply' in answer)) return answer;\r\n const reply = answer.reply as { type?: unknown; pid?: unknown; error?: unknown } | null;\r\n if (reply?.type === 'stopping' && Number.isInteger(reply.pid)) return { state: 'stopping', pid: reply.pid as number };\r\n if (reply?.type === 'error' && reply.error === 'unauthorized') return { state: 'unauthorized' };\r\n return { state: 'unknown', error: 'unexpected reply' };\r\n}\r\n\r\nconst line = (message: object) => `${JSON.stringify(message)}\\n`;\r\n\r\nfunction controlServer(owner: LockOwner): net.Server {\r\n const expectedProof = Buffer.from(stopProof(owner.token));\r\n return net.createServer((socket) => {\r\n let buffer = '';\r\n socket.setEncoding('utf8');\r\n socket.on('error', () => {});\r\n const idle = setTimeout(() => socket.destroy(), REQUEST_IDLE_MS);\r\n socket.on('close', () => clearTimeout(idle));\r\n const onData = (chunk: string) => {\r\n buffer += chunk;\r\n const end = buffer.indexOf('\\n');\r\n if (end < 0) {\r\n if (Buffer.byteLength(buffer) > MAX_LINE_BYTES) socket.destroy();\r\n return;\r\n }\r\n socket.off('data', onData);\r\n clearTimeout(idle);\r\n let request: { type?: unknown; proof?: unknown } | null = null;\r\n try {\r\n request = JSON.parse(buffer.slice(0, end));\r\n } catch {}\r\n if (request?.type === 'status') {\r\n socket.end(line({ type: 'status', protocol: CONTROL_PROTOCOL, pid: owner.pid }));\r\n } else if (request?.type === 'stop') {\r\n const proof = typeof request.proof === 'string' ? Buffer.from(request.proof) : undefined;\r\n if (owner.token !== '' && proof && proof.length === expectedProof.length && crypto.timingSafeEqual(proof, expectedProof)) {\r\n socket.end(line({ type: 'stopping', pid: owner.pid }), () => owner.onStop());\r\n } else {\r\n socket.end(line({ type: 'error', error: 'unauthorized' }));\r\n }\r\n } else {\r\n socket.end(line({ type: 'error', error: 'unknown request' }));\r\n }\r\n };\r\n socket.on('data', onData);\r\n });\r\n}\r\n\r\nexport function listenControl(endpoint: string, owner: LockOwner): Promise<Attempt> {\r\n const server = controlServer(owner);\r\n return new Promise((resolve) => {\r\n const onError = (err: NodeJS.ErrnoException) => {\r\n resolve(err.code === 'EADDRINUSE' ? { kind: 'busy' } : { kind: 'unknown', error: err.code ?? err.message });\r\n };\r\n server.once('error', onError);\r\n server.listen(endpoint, () => {\r\n server.off('error', onError);\r\n server.on('error', () => {});\r\n resolve({ kind: 'owner', close: () => new Promise<void>((done) => server.close(() => done())) });\r\n });\r\n });\r\n}\r\n\r\nfunction settle(attempt: Attempt, busy: string): Acquired {\r\n return attempt.kind === 'busy' ? { kind: 'unknown', error: busy } : attempt;\r\n}\r\n\r\nexport async function acquireLock(endpoint: string, owner: LockOwner, deps: LockDeps = {}): Promise<Acquired> {\r\n const platform = deps.platform ?? process.platform;\r\n const listen = deps.listen ?? listenControl;\r\n const query = deps.queryOwner ?? ((e: string) => queryOwner(e));\r\n if (platform !== 'win32' && Buffer.byteLength(endpoint) > MAX_SOCKET_PATH_BYTES) {\r\n return { kind: 'unknown', error: `control socket path is too long: ${endpoint}` };\r\n }\r\n const first = await listen(endpoint, owner);\r\n if (first.kind !== 'busy') return first;\r\n const state = await query(endpoint);\r\n if (state.state === 'running') return { kind: 'held', pid: state.pid };\r\n if (state.state === 'unknown') return { kind: 'unknown', error: state.error };\r\n if (platform === 'win32') return settle(await listen(endpoint, owner), 'the control pipe is in use but does not answer');\r\n return recoverSocket(endpoint, owner, listen, query, deps.fs ?? fs, deps.now ?? Date.now);\r\n}\r\n\r\n// Two starters that both find a dead socket file would each unlink it, and the second unlink would remove the first one's live socket.\r\nasync function recoverSocket(\r\n endpoint: string,\r\n owner: LockOwner,\r\n listen: (endpoint: string, owner: LockOwner) => Promise<Attempt>,\r\n query: (endpoint: string) => Promise<OwnerState>,\r\n f: LockFs,\r\n now: () => number,\r\n): Promise<Acquired> {\r\n const guard = `${endpoint}.lock`;\r\n const blocked = takeGuard(guard, f, now);\r\n if (blocked) return { kind: 'unknown', error: blocked };\r\n try {\r\n const state = await query(endpoint);\r\n if (state.state === 'running') return { kind: 'held', pid: state.pid };\r\n if (state.state === 'unknown') return { kind: 'unknown', error: state.error };\r\n try {\r\n f.unlinkSync(endpoint);\r\n } catch (err) {\r\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') return { kind: 'unknown', error: (err as Error).message };\r\n }\r\n return settle(await listen(endpoint, owner), 'the control socket is in use but does not answer');\r\n } finally {\r\n try {\r\n f.rmdirSync(guard);\r\n } catch {}\r\n }\r\n}\r\n\r\nfunction takeGuard(guard: string, f: LockFs, now: () => number): string | undefined {\r\n for (let attempt = 0; attempt < 2; attempt++) {\r\n try {\r\n f.mkdirSync(guard);\r\n return undefined;\r\n } catch (err) {\r\n if ((err as NodeJS.ErrnoException).code !== 'EEXIST') return (err as Error).message;\r\n }\r\n let age: number;\r\n try {\r\n age = now() - f.statSync(guard).mtimeMs;\r\n } catch {\r\n continue;\r\n }\r\n if (age <= STALE_GUARD_MS) return 'another Codex adapter is starting';\r\n try {\r\n f.rmdirSync(guard);\r\n } catch {}\r\n }\r\n return 'another Codex adapter is starting';\r\n}\r\n","import { loadConfig } from '../shared/config.js';\r\nimport { CONFIG_DIR } from '../shared/constants.js';\r\nimport { installCrashGuard, logStartup } from '../shared/crash-guard.js';\r\nimport { logger } from '../shared/logger.js';\r\nimport { CodexAdapter } from './adapter.js';\r\nimport { resolveAdapterHub } from './hub-target.js';\r\nimport { acquireLock, controlEndpoint } from './instance-lock.js';\r\n\r\nconst WAIT_MIN_MS = 2000;\r\nconst WAIT_MAX_MS = 30_000;\r\n\r\ninstallCrashGuard('codex adapter');\r\n// Once the hub is gone its pipes break; without listeners every log line would become an uncaught EPIPE.\r\nprocess.stdout.on('error', () => {});\r\nprocess.stderr.on('error', () => {});\r\nconst config = loadConfig();\r\nconst supervised = process.argv.includes('--watch-stdin');\r\nconst endpoint = controlEndpoint(CONFIG_DIR);\r\n\r\nlet adapter: CodexAdapter | undefined;\r\nlet release: (() => Promise<void>) | undefined;\r\nlet exiting = false;\r\nconst shutdown = () => {\r\n if (exiting) return;\r\n exiting = true;\r\n adapter?.stop();\r\n const exit = () => process.exit(0);\r\n // server.close() waits for open control connections; a client that never finishes must not keep a stopped adapter alive.\r\n setTimeout(exit, 3000).unref();\r\n if (release) release().then(exit, exit);\r\n else exit();\r\n};\r\nprocess.on('SIGINT', shutdown);\r\nprocess.on('SIGTERM', shutdown);\r\n\r\n// On Windows `hub stop` kills the hub without running its exit handlers, so stdin EOF is the only sign the parent is gone.\r\nif (supervised) {\r\n process.stdin.on('end', shutdown);\r\n process.stdin.on('close', shutdown);\r\n process.stdin.resume();\r\n}\r\n\r\nfunction send(message: object, then?: () => void): void {\r\n if (!process.send || !process.connected) {\r\n then?.();\r\n return;\r\n }\r\n // With a callback, a channel that closes between the check and the send reports here instead of throwing.\r\n process.send(message, undefined, undefined, (err: Error | null) => {\r\n if (err) logger.debug(`Report to the parent not delivered: ${err.message}`);\r\n then?.();\r\n });\r\n}\r\n\r\nconst sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));\r\n\r\nasync function takeLock(): Promise<boolean> {\r\n let delay = WAIT_MIN_MS;\r\n let waitReason: string | undefined;\r\n for (;;) {\r\n const lock = await acquireLock(endpoint, {\r\n pid: process.pid,\r\n token: config.hub.token ?? '',\r\n onStop: () => {\r\n if (supervised) logger.warn('Stopped by claude-alarm codex stop; the hub will not start the Codex adapter again until the hub restarts');\r\n shutdown();\r\n },\r\n });\r\n if (lock.kind === 'owner') {\r\n release = lock.close;\r\n if (waitReason !== undefined) logger.info('Codex adapter took over: the other adapter has stopped');\r\n return true;\r\n }\r\n if (!supervised) {\r\n if (lock.kind === 'held') {\r\n logger.info(`Codex adapter already running (PID: ${lock.pid})`);\r\n send({ type: 'codex-already-running', pid: lock.pid }, () => process.exit(0));\r\n } else {\r\n logger.error(`Codex adapter cannot start: ${lock.error}`);\r\n send({ type: 'codex-lock-failed', error: lock.error }, () => process.exit(1));\r\n }\r\n return false;\r\n }\r\n const reason = lock.kind === 'held' ? `held:${lock.pid}` : `unknown:${lock.error}`;\r\n if (reason !== waitReason) {\r\n waitReason = reason;\r\n if (lock.kind === 'held') logger.info(`Another Codex adapter is running (PID: ${lock.pid}); this one takes over when it stops`);\r\n else logger.warn(`Codex adapter control endpoint is unavailable (${lock.error}); retrying`);\r\n }\r\n await sleep(delay);\r\n delay = Math.min(delay * 2, WAIT_MAX_MS);\r\n }\r\n}\r\n\r\nvoid takeLock().then((owned) => {\r\n if (!owned) return;\r\n logStartup('Codex adapter');\r\n const { host, port, token } = resolveAdapterHub(config);\r\n adapter = new CodexAdapter({\r\n command: config.codex?.command ?? 'codex',\r\n hub: { host, port, token },\r\n onFirstConnect: (outcome) => send({ type: 'codex-first-connect', ...outcome }),\r\n });\r\n adapter.start();\r\n});\r\n"],"mappings":"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","names":["path","config","config","fs","fs","fs","os","path","randomUUID","WebSocket","WebSocket","fs","path","WebSocket","path","fs","WebSocket","fs","fs","os","randomUUID","path","fs","config","fs","net","path","endpoint","net","endpoint","fs"]}
1
+ {"version":3,"sources":["../../src/shared/config.ts","../../src/shared/constants.ts","../../src/shared/crash-guard.ts","../../src/shared/logger.ts","../../src/codex/adapter.ts","../../src/codex/hub-link.ts","../../src/channel/hub-client.ts","../../src/codex/transport.ts","../../src/codex/inputs.ts","../../src/codex/mapping.ts","../../src/codex/rpc.ts","../../src/codex/approvals.ts","../../src/codex/shutdown.ts","../../src/shared/hub-url.ts","../../src/codex/hub-target.ts","../../src/codex/instance-lock.ts","../../src/codex/main.ts"],"sourcesContent":["import fs from 'node:fs';\r\nimport path from 'node:path';\r\nimport { randomUUID } from 'node:crypto';\r\nimport { CONFIG_DIR, CONFIG_FILE, DEFAULT_HUB_HOST, DEFAULT_HUB_PORT } from './constants.js';\r\nimport type { AppConfig } from './types.js';\r\n\r\nconst DEFAULT_CONFIG: AppConfig = {\r\n hub: {\r\n host: DEFAULT_HUB_HOST,\r\n port: DEFAULT_HUB_PORT,\r\n },\r\n notifications: {\r\n desktop: true,\r\n sound: true,\r\n },\r\n webhooks: [],\r\n};\r\n\r\nexport function ensureConfigDir(): void {\r\n if (!fs.existsSync(CONFIG_DIR)) {\r\n fs.mkdirSync(CONFIG_DIR, { recursive: true });\r\n }\r\n}\r\n\r\nexport function loadConfig(): AppConfig {\r\n ensureConfigDir();\r\n let config: AppConfig;\r\n if (!fs.existsSync(CONFIG_FILE)) {\r\n config = { ...DEFAULT_CONFIG, hub: { ...DEFAULT_CONFIG.hub } };\r\n } else {\r\n try {\r\n const raw = fs.readFileSync(CONFIG_FILE, 'utf-8');\r\n const parsed = JSON.parse(raw);\r\n config = { ...DEFAULT_CONFIG, ...parsed, hub: { ...DEFAULT_CONFIG.hub, ...parsed.hub }, ...(parsed.telegram ? { telegram: parsed.telegram } : {}) };\r\n } catch {\r\n config = { ...DEFAULT_CONFIG, hub: { ...DEFAULT_CONFIG.hub } };\r\n }\r\n }\r\n\r\n // Auto-generate token if missing\r\n if (!config.hub.token) {\r\n config.hub.token = randomUUID();\r\n saveConfig(config);\r\n }\r\n\r\n return config;\r\n}\r\n\r\n/** Get the current token, generating one if needed */\r\nexport function getOrCreateToken(): string {\r\n const config = loadConfig();\r\n return config.hub.token!;\r\n}\r\n\r\nexport function saveConfig(config: AppConfig): void {\r\n ensureConfigDir();\r\n fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), { encoding: 'utf-8', mode: 0o600 });\r\n}\r\n\r\nexport function setCodexEnabled(enabled: boolean): AppConfig {\r\n const config = loadConfig();\r\n config.codex = { ...config.codex, enabled };\r\n saveConfig(config);\r\n return config;\r\n}\r\n\r\nexport function shouldOfferCodex(config: AppConfig, installed: boolean): boolean {\r\n return installed && config.codex === undefined;\r\n}\r\n\r\n/**\r\n * Add claude-alarm as an MCP channel server to .mcp.json\r\n */\r\nexport function setupMcpConfig(targetDir?: string): string {\r\n const dir = targetDir ?? process.cwd();\r\n const mcpPath = path.join(dir, '.mcp.json');\r\n\r\n let mcpConfig: Record<string, any> = {};\r\n if (fs.existsSync(mcpPath)) {\r\n try {\r\n mcpConfig = JSON.parse(fs.readFileSync(mcpPath, 'utf-8'));\r\n } catch {\r\n mcpConfig = {};\r\n }\r\n }\r\n\r\n if (!mcpConfig.mcpServers) {\r\n mcpConfig.mcpServers = {};\r\n }\r\n\r\n mcpConfig.mcpServers['claude-alarm'] = {\r\n command: 'npx',\r\n args: ['-y', '@delt/claude-alarm', 'serve'],\r\n env: {\r\n CLAUDE_ALARM_SESSION_NAME: path.basename(dir),\r\n },\r\n };\r\n\r\n fs.writeFileSync(mcpPath, JSON.stringify(mcpConfig, null, 2), 'utf-8');\r\n return mcpPath;\r\n}\r\n","import path from 'node:path';\r\nimport os from 'node:os';\r\n\r\nexport const DEFAULT_HUB_HOST = '127.0.0.1';\r\nexport const DEFAULT_HUB_PORT = 7900;\r\n\r\nexport const CONFIG_DIR = path.join(os.homedir(), '.claude-alarm');\r\nexport const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');\r\nexport const PID_FILE = path.join(CONFIG_DIR, 'hub.pid');\r\nexport const LOG_FILE = path.join(CONFIG_DIR, 'hub.log');\r\nexport const UPLOADS_DIR = path.join(CONFIG_DIR, 'uploads');\r\nexport const CODEX_PID_FILE = path.join(CONFIG_DIR, 'codex.pid');\r\nexport const CODEX_LOG_FILE = path.join(CONFIG_DIR, 'codex.log');\r\n\r\nexport const WS_PATH_CHANNEL = '/ws/channel';\r\nexport const WS_PATH_DASHBOARD = '/ws/dashboard';\r\nexport const WS_PATH_CODEX = '/ws/codex';\r\n\r\nexport const CHANNEL_SERVER_NAME = 'claude-alarm';\r\nexport const CHANNEL_SERVER_VERSION = '0.1.0';\r\n","import fs from 'node:fs';\nimport { CONFIG_DIR, LOG_FILE } from './constants.js';\nimport { logger } from './logger.js';\n\nconst BURST_WINDOW_MS = 60_000;\nconst BURST_LIMIT = 10;\n\nfunction appendToLog(text: string): void {\n try {\n fs.mkdirSync(CONFIG_DIR, { recursive: true });\n fs.appendFileSync(LOG_FILE, text, 'utf-8');\n } catch {}\n}\n\nfunction describe(err: unknown): string {\n if (err instanceof Error) return err.stack ?? `${err.name}: ${err.message}`;\n try {\n return JSON.stringify(err);\n } catch {\n return String(err);\n }\n}\n\n/**\n * Last-resort net for exceptions no local handler caught.\n *\n * The hub keeps running afterwards: a notification relay that dies silently is\n * worse than one running on possibly-degraded state, and in foreground mode the\n * stack trace would otherwise vanish with the console window. A repeated burst\n * still exits, so a self-feeding error loop cannot spin forever.\n */\nexport function installCrashGuard(context: string): void {\n let recent: number[] = [];\n\n const handle = (kind: string, err: unknown): void => {\n const stack = describe(err);\n appendToLog(`\\n[${new Date().toISOString()}] ${kind} (${context})\\n${stack}\\n`);\n logger.error(`${kind} caught by crash guard: ${stack}`);\n\n const now = Date.now();\n recent = recent.filter((t) => now - t < BURST_WINDOW_MS);\n recent.push(now);\n\n if (recent.length > BURST_LIMIT) {\n const msg = `${recent.length} unhandled errors within ${BURST_WINDOW_MS / 1000}s — exiting`;\n appendToLog(`[${new Date().toISOString()}] ${msg}\\n`);\n logger.error(msg);\n process.exit(1);\n }\n };\n\n process.on('uncaughtException', (err) => handle('uncaughtException', err));\n process.on('unhandledRejection', (reason) => handle('unhandledRejection', reason));\n}\n\nexport function logStartup(context: string): void {\n appendToLog(`\\n[${new Date().toISOString()}] ${context} started (pid ${process.pid})\\n`);\n}\n","/**\r\n * Logger that writes to stderr only.\r\n * CRITICAL: In MCP channel servers, stdout is used for the stdio protocol.\r\n * Any console.log() would corrupt the protocol. Always use this logger.\r\n */\r\nexport const logger = {\r\n info(msg: string, ...args: unknown[]) {\r\n console.error(`[claude-alarm] ${msg}`, ...args);\r\n },\r\n warn(msg: string, ...args: unknown[]) {\r\n console.error(`[claude-alarm WARN] ${msg}`, ...args);\r\n },\r\n error(msg: string, ...args: unknown[]) {\r\n console.error(`[claude-alarm ERROR] ${msg}`, ...args);\r\n },\r\n debug(msg: string, ...args: unknown[]) {\r\n if (process.env.CLAUDE_ALARM_DEBUG) {\r\n console.error(`[claude-alarm DEBUG] ${msg}`, ...args);\r\n }\r\n },\r\n};\r\n","import fs from 'node:fs';\r\nimport os from 'node:os';\r\nimport path from 'node:path';\r\nimport { CodexHubLink } from './hub-link.js';\r\nimport { randomUUID } from 'node:crypto';\r\nimport { HubClient } from '../channel/hub-client.js';\r\nimport { CHANNEL_SERVER_VERSION } from '../shared/constants.js';\r\nimport { logger } from '../shared/logger.js';\r\nimport type { ChannelMessage, CodexCall, MessageSource, NotifyLevel, SessionInfo } from '../shared/types.js';\r\nimport { connectProxy, type ProxyConnection, type SpawnFn } from './transport.js';\r\nimport { imageInput, textInput, type UserInput } from './inputs.js';\r\nimport { RpcClient, type RpcId } from './rpc.js';\r\nimport { approvalView, fileChanges, type ApprovalChoice, type ApprovalView, type FileChange } from './approvals.js';\r\nimport {\r\n cleanFolder,\r\n codexSessionId,\r\n finalAnswer,\r\n hubStatus,\r\n isTrackable,\r\n threadTitle,\r\n type AgentMessage,\r\n type CodexThread,\r\n type CodexThreadStatus,\r\n} from './mapping.js';\r\n\r\nexport type FirstConnect =\r\n | { connected: true; userAgent?: string }\r\n | { connected: false; error: string; notFound: boolean };\r\n\r\nexport interface CodexAdapterOptions {\r\n command: string;\r\n hub: { host: string; port: number; token?: string };\r\n spawnFn?: SpawnFn;\r\n reconnectMinMs?: number;\r\n reconnectMaxMs?: number;\r\n idleReleaseMs?: number;\r\n noticeTimeoutMs?: number;\r\n hostName?: string;\r\n linkReconnectMs?: number;\r\n rpcTimeoutMs?: number;\r\n onFirstConnect?: (outcome: FirstConnect) => void;\r\n}\r\n\r\ninterface Tracked {\r\n thread: CodexThread;\r\n hub: HubClient;\r\n subscribed: boolean;\r\n wantSubscribed: boolean;\r\n sync: Promise<void>;\r\n pendingTurn: boolean;\r\n sending: Promise<void>;\r\n turns: Map<string, AgentMessage[]>;\r\n releaseTimer?: ReturnType<typeof setTimeout>;\r\n unrelayed: boolean;\r\n files: Map<string, FileChange[]>;\r\n}\r\n\r\n// Requests a person must answer that claude-alarm cannot relay; the user is pointed back to Codex.\r\nconst USER_REQUESTS = new Set(['item/tool/requestUserInput', 'item/permissions/requestApproval', 'mcpServer/elicitation/request']);\r\n\r\ninterface PendingApproval {\r\n threadId: string;\r\n rpcId: RpcId;\r\n turnId?: string;\r\n choices: ApprovalChoice[];\r\n answered: boolean;\r\n}\r\n\r\nexport class CodexAdapter {\r\n private conn?: ProxyConnection;\r\n private connecting?: Promise<void>;\r\n private closing = new Set<Promise<void>>();\r\n private rpc?: RpcClient;\r\n private threads = new Map<string, Tracked>();\r\n private approvals = new Map<string, PendingApproval>();\r\n private stopped = false;\r\n private retryTimer?: ReturnType<typeof setTimeout>;\r\n private delay: number;\r\n private notFoundNotice: 'unsent' | 'sending' | 'sent' = 'unsent';\r\n private firstConnectReported = false;\r\n\r\n private pins = new Set<string>();\r\n private ready = false;\r\n private readonly hostName: string;\r\n private readonly link: CodexHubLink;\r\n\r\n constructor(private opts: CodexAdapterOptions) {\r\n this.delay = opts.reconnectMinMs ?? 2000;\r\n this.hostName = opts.hostName ?? os.hostname();\r\n this.link = new CodexHubLink(opts.hub, { id: randomUUID(), host: this.hostName }, (call) => this.onCall(call), opts.linkReconnectMs);\r\n }\r\n\r\n start(): void {\r\n this.stopped = false;\r\n this.link.connect();\r\n this.connecting = this.connect();\r\n }\r\n\r\n async stop(): Promise<void> {\r\n this.stopped = true;\r\n this.link.disconnect();\r\n if (this.retryTimer) clearTimeout(this.retryTimer);\r\n this.retryTimer = undefined;\r\n for (const id of [...this.threads.keys()]) this.drop(id);\r\n this.closeConn(this.conn);\r\n await this.connecting;\r\n await Promise.all(this.closing);\r\n }\r\n\r\n private closeConn(conn: ProxyConnection | undefined): void {\r\n if (!conn) return;\r\n const closing: Promise<void> = conn.close().finally(() => this.closing.delete(closing));\r\n this.closing.add(closing);\r\n }\r\n\r\n private async connect(): Promise<void> {\r\n let rpc: RpcClient | undefined;\r\n try {\r\n const conn = await connectProxy(this.opts.command, this.opts.spawnFn);\r\n if (this.stopped) {\r\n this.closeConn(conn);\r\n return;\r\n }\r\n const live = new RpcClient(conn.ws, this.opts.rpcTimeoutMs);\r\n rpc = live;\r\n live.on('notification', (method: string, params: any) => this.onNotification(method, params));\r\n live.on('request', (id: RpcId, method: string, params: any) => this.onServerRequest(id, method, params));\r\n live.on('close', () => {\r\n if (this.rpc === live) this.onDaemonLost();\r\n });\r\n this.conn = conn;\r\n this.rpc = live;\r\n const init = await live.request<{ userAgent?: string }>('initialize', {\r\n clientInfo: { name: 'claude-alarm', version: CHANNEL_SERVER_VERSION },\r\n });\r\n live.notify('initialized');\r\n logger.info(`Connected to Codex daemon (${init.userAgent ?? 'unknown version'})`);\r\n this.reportFirstConnect({ connected: true, ...(init.userAgent ? { userAgent: init.userAgent } : {}) });\r\n await this.discover();\r\n if (this.rpc === live) this.setReady(true);\r\n this.delay = this.opts.reconnectMinMs ?? 2000;\r\n } catch (err) {\r\n this.setReady(false);\r\n logger.warn(`Codex daemon connection failed: ${(err as Error).message}`);\r\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') this.noticeNotFound();\r\n this.reportFirstConnect({\r\n connected: false,\r\n error: (err as Error).message,\r\n notFound: (err as NodeJS.ErrnoException).code === 'ENOENT',\r\n });\r\n if (rpc && this.rpc === rpc) {\r\n this.rpc = undefined;\r\n this.closeConn(this.conn);\r\n this.conn = undefined;\r\n }\r\n for (const id of [...this.threads.keys()]) this.drop(id);\r\n this.scheduleRetry();\r\n }\r\n }\r\n\r\n private onDaemonLost(): void {\r\n this.setReady(false);\r\n this.rpc = undefined;\r\n this.closeConn(this.conn);\r\n this.conn = undefined;\r\n for (const id of [...this.threads.keys()]) this.drop(id);\r\n if (!this.stopped) logger.warn('Codex daemon connection lost');\r\n this.scheduleRetry();\r\n }\r\n\r\n private scheduleRetry(): void {\r\n if (this.stopped || this.retryTimer) return;\r\n this.retryTimer = setTimeout(() => {\r\n this.retryTimer = undefined;\r\n this.connecting = this.connect();\r\n }, this.delay);\r\n this.delay = Math.min(this.delay * 2, this.opts.reconnectMaxMs ?? 60_000);\r\n }\r\n\r\n private reportFirstConnect(outcome: FirstConnect): void {\r\n if (this.firstConnectReported || this.stopped) return;\r\n this.firstConnectReported = true;\r\n try {\r\n this.opts.onFirstConnect?.(outcome);\r\n } catch (err) {\r\n // Inside connect(), a throw here would be taken for a daemon failure and drop a healthy connection.\r\n logger.debug(`First-connect observer failed: ${(err as Error).message}`);\r\n }\r\n }\r\n\r\n private noticeNotFound(): void {\r\n if (this.notFoundNotice !== 'unsent') return;\r\n this.notFoundNotice = 'sending';\r\n const { host, port, token } = this.opts.hub;\r\n fetch(`http://${host}:${port}/api/notify`, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json', ...(token ? { Authorization: `Bearer ${token}` } : {}) },\r\n body: JSON.stringify({\r\n title: 'Codex not found',\r\n message: `The Codex adapter cannot find \"${this.opts.command}\". Open a new terminal and restart the hub, or set \"codex.command\" in ~/.claude-alarm/config.json.`,\r\n level: 'warning',\r\n }),\r\n signal: AbortSignal.timeout(this.opts.noticeTimeoutMs ?? 5000),\r\n })\r\n .then((res) => {\r\n this.notFoundNotice = res.ok ? 'sent' : 'unsent';\r\n if (!res.ok) logger.debug(`Codex not-found notice was refused (${res.status})`);\r\n })\r\n .catch((err) => {\r\n // The hub replies only after its desktop notification closes, which can outlast the timeout, so a timeout still means it arrived.\r\n this.notFoundNotice = (err as Error).name === 'TimeoutError' ? 'sent' : 'unsent';\r\n logger.debug(`Codex not-found notice failed: ${(err as Error).message}`);\r\n });\r\n }\r\n\r\n private setReady(ready: boolean): void {\r\n this.ready = ready;\r\n this.link.setReady(ready);\r\n }\r\n\r\n private requireDaemon(): RpcClient {\r\n if (!this.ready || !this.rpc) throw new Error(`Codex is not connected on ${this.hostName}.`);\r\n return this.rpc;\r\n }\r\n\r\n private async onCall(call: CodexCall): Promise<unknown> {\r\n if (call.kind === 'folders') return { folders: await this.folders() };\r\n return { sessionId: await this.create(call.cwd) };\r\n }\r\n\r\n private async folders(): Promise<string[]> {\r\n const page = await this.requireDaemon().request<{ data: CodexThread[] }>('thread/list', { limit: 50, sortKey: 'updated_at' });\r\n return [...new Set(page.data.map((t) => t.cwd).filter(Boolean))].slice(0, 10);\r\n }\r\n\r\n private async create(input: string): Promise<string> {\r\n const rpc = this.requireDaemon();\r\n const cwd = cleanFolder(input);\r\n const isDir = path.isAbsolute(cwd) && (await fs.promises.stat(cwd).then((s) => s.isDirectory(), () => false));\r\n if (!isDir) throw new Error(`Folder not found on ${this.hostName}: ${cwd}`);\r\n let thread: CodexThread;\r\n try {\r\n // No RPC timeout: an answer dropped after a timeout would leave a conversation this connection holds but never pins.\r\n ({ thread } = await rpc.request<{ thread: CodexThread }>('thread/start', { cwd, sandbox: 'danger-full-access', approvalPolicy: 'never' }, null));\r\n } catch (err) {\r\n throw new Error(`Codex could not start the conversation: ${(err as Error).message}`);\r\n }\r\n this.pins.add(thread.id);\r\n this.upsert(thread);\r\n const t = this.threads.get(thread.id);\r\n if (!t) {\r\n this.pins.delete(thread.id);\r\n throw new Error('Codex started a conversation claude-alarm cannot follow.');\r\n }\r\n // The starting connection is already subscribed; marking it before upsert's queued sync runs avoids a resume that fails before the first turn.\r\n t.subscribed = true;\r\n return codexSessionId(thread.id);\r\n }\r\n\r\n private async discover(): Promise<void> {\r\n const rpc = this.rpc!;\r\n const pinned = [...this.pins];\r\n const ids: string[] = [];\r\n let cursor: string | null | undefined;\r\n do {\r\n const page = await rpc.request<{ data: string[]; nextCursor?: string | null }>('thread/loaded/list', cursor ? { cursor } : {});\r\n ids.push(...page.data);\r\n cursor = page.nextCursor;\r\n } while (cursor);\r\n for (const id of ids) await this.refresh(id);\r\n // A list read on a connection that has since been replaced says nothing about what the daemon holds now.\r\n if (this.rpc !== rpc) return;\r\n for (const id of pinned) if (!ids.includes(id)) this.pins.delete(id);\r\n }\r\n\r\n private async refresh(threadId: string): Promise<void> {\r\n try {\r\n const { thread } = await this.rpc!.request<{ thread: CodexThread }>('thread/read', { threadId, includeTurns: false });\r\n this.upsert(thread);\r\n } catch (err) {\r\n logger.debug(`thread/read ${threadId} failed: ${(err as Error).message}`);\r\n }\r\n }\r\n\r\n private upsert(thread: CodexThread): void {\r\n if (!isTrackable(thread)) {\r\n this.drop(thread.id);\r\n return;\r\n }\r\n const existing = this.threads.get(thread.id);\r\n if (existing) {\r\n existing.thread = thread;\r\n existing.hub.reregister();\r\n } else {\r\n const { host, port, token } = this.opts.hub;\r\n const hub = new HubClient(codexSessionId(thread.id), threadTitle(thread), host, port, token, () => undefined, () =>\r\n this.registration(thread.id),\r\n );\r\n this.threads.set(thread.id, {\r\n thread,\r\n hub,\r\n subscribed: false,\r\n wantSubscribed: false,\r\n sync: Promise.resolve(),\r\n pendingTurn: false,\r\n sending: Promise.resolve(),\r\n turns: new Map(),\r\n unrelayed: false,\r\n files: new Map(),\r\n });\r\n hub.onMessage((msg) => this.onHubMessage(thread.id, msg));\r\n hub.connect();\r\n }\r\n void this.want(thread.id, thread.status.type === 'active');\r\n }\r\n\r\n private registration(threadId: string): Partial<SessionInfo> {\r\n const t = this.threads.get(threadId);\r\n if (!t) return {};\r\n const title = threadTitle(t.thread);\r\n return { name: title, title, cwd: t.thread.cwd, agentKind: 'codex', status: hubStatus(t.thread.status), closable: this.pins.has(threadId) };\r\n }\r\n\r\n private want(threadId: string, subscribed: boolean): Promise<void> {\r\n const t = this.threads.get(threadId);\r\n if (!t) return Promise.resolve();\r\n t.wantSubscribed = subscribed || this.pins.has(threadId);\r\n t.sync = t.sync.then(() => this.syncSubscription(t));\r\n return t.sync;\r\n }\r\n\r\n private async syncSubscription(t: Tracked): Promise<void> {\r\n const threadId = t.thread.id;\r\n if (!this.rpc || this.threads.get(threadId) !== t || t.subscribed === t.wantSubscribed) return;\r\n try {\r\n if (t.wantSubscribed) {\r\n // Only these two fields: any other resume field overrides the user's own thread settings.\r\n await this.rpc.request('thread/resume', { threadId, excludeTurns: true });\r\n t.subscribed = true;\r\n t.unrelayed = false;\r\n } else {\r\n // The daemon unloads a conversation 60 s after its last subscriber leaves; staying subscribed would keep closed Codex windows alive.\r\n await this.rpc.request('thread/unsubscribe', { threadId });\r\n t.subscribed = false;\r\n }\r\n } catch (err) {\r\n logger.debug(`subscription sync for ${threadId} deferred: ${(err as Error).message}`);\r\n // A turn started in the Codex window has no other way to reach claude-alarm, so its reply is lost unless a later resume succeeds.\r\n if (t.wantSubscribed && !t.subscribed && t.thread.status.type === 'active') t.unrelayed = true;\r\n }\r\n }\r\n\r\n private releaseLater(t: Tracked): void {\r\n clearTimeout(t.releaseTimer);\r\n t.releaseTimer = setTimeout(() => {\r\n t.releaseTimer = undefined;\r\n if (this.threads.get(t.thread.id) === t && t.thread.status.type !== 'active' && !t.pendingTurn) {\r\n void this.want(t.thread.id, false);\r\n }\r\n }, this.opts.idleReleaseMs ?? 1000);\r\n }\r\n\r\n private drop(threadId: string): void {\r\n const t = this.threads.get(threadId);\r\n if (!t) return;\r\n for (const [requestId, a] of this.approvals) {\r\n if (a.threadId === threadId) this.finishApproval(requestId, 'expired');\r\n }\r\n this.threads.delete(threadId);\r\n clearTimeout(t.releaseTimer);\r\n t.releaseTimer = undefined;\r\n t.hub.disconnect();\r\n }\r\n\r\n private busy(t: Tracked): boolean {\r\n return t.thread.status.type === 'active' || t.pendingTurn;\r\n }\r\n\r\n private async close(threadId: string): Promise<void> {\r\n const t = this.threads.get(threadId);\r\n if (!t || !this.pins.delete(threadId)) return;\r\n t.hub.reregister();\r\n if (this.busy(t)) return;\r\n // drop() before the unsubscribe finishes would skip it: syncSubscription stops once the thread is untracked.\r\n await this.want(threadId, false);\r\n // A message or an active broadcast may arrive while unsubscribing; the conversation then ends like a close during work.\r\n if (this.threads.get(threadId) !== t || this.busy(t) || t.wantSubscribed) return;\r\n if (!t.subscribed) {\r\n this.drop(threadId);\r\n return;\r\n }\r\n // syncSubscription swallows unsubscribe errors, so a still-set flag is the only sign it failed.\r\n this.pins.add(threadId);\r\n t.hub.reregister();\r\n void this.want(threadId, true);\r\n this.notify(threadId, 'Not closed', 'Codex did not release the conversation. Try closing it again.', 'warning');\r\n }\r\n\r\n private onNotification(method: string, params: any): void {\r\n switch (method) {\r\n case 'thread/started':\r\n this.upsert(params.thread);\r\n break;\r\n case 'thread/status/changed':\r\n this.onStatus(params.threadId, params.status);\r\n break;\r\n case 'thread/name/updated': {\r\n const t = this.threads.get(params.threadId);\r\n if (t) {\r\n t.thread.name = params.threadName;\r\n t.hub.reregister();\r\n }\r\n break;\r\n }\r\n case 'thread/closed':\r\n case 'thread/archived':\r\n case 'thread/deleted':\r\n this.pins.delete(params.threadId);\r\n this.drop(params.threadId);\r\n break;\r\n case 'item/started':\r\n if (params.item?.type === 'fileChange') this.threads.get(params.threadId)?.files.set(params.item.id, fileChanges(params.item));\r\n break;\r\n case 'item/completed':\r\n if (params.item?.type === 'agentMessage') this.collect(params.threadId, params.turnId, params.item);\r\n if (params.item?.type === 'fileChange') this.threads.get(params.threadId)?.files.delete(params.item.id);\r\n break;\r\n case 'serverRequest/resolved':\r\n this.onResolved(params.threadId, params.requestId);\r\n break;\r\n case 'turn/completed':\r\n this.onTurnCompleted(params.threadId, params.turn);\r\n break;\r\n }\r\n }\r\n\r\n private onStatus(threadId: string, status: CodexThreadStatus): void {\r\n const t = this.threads.get(threadId);\r\n if (!t) {\r\n if (status.type !== 'notLoaded') void this.refresh(threadId);\r\n return;\r\n }\r\n if (status.type === 'notLoaded') {\r\n this.pins.delete(threadId);\r\n this.drop(threadId);\r\n return;\r\n }\r\n t.thread.status = status;\r\n t.pendingTurn = false;\r\n t.hub.send({ type: 'status', sessionId: codexSessionId(threadId), status: hubStatus(status) });\r\n if (status.type === 'systemError') this.notify(threadId, 'Codex error', 'The Codex conversation hit a system error.', 'error');\r\n if (status.type === 'active') {\r\n void this.want(threadId, true);\r\n return;\r\n }\r\n if (t.unrelayed) {\r\n t.unrelayed = false;\r\n this.notify(threadId, 'Reply not relayed', 'Codex finished, but its reply could not be relayed here. Check the Codex window.', 'warning');\r\n }\r\n // The daemon emits idle just before turn/completed; unsubscribing at once could cut off the reply.\r\n this.releaseLater(t);\r\n }\r\n\r\n private collect(threadId: string, turnId: string, item: AgentMessage): void {\r\n const t = this.threads.get(threadId);\r\n if (!t) return;\r\n const list = t.turns.get(turnId) ?? [];\r\n list.push({ text: item.text, phase: item.phase });\r\n t.turns.set(turnId, list);\r\n }\r\n\r\n private onTurnCompleted(\r\n threadId: string,\r\n turn: { id: string; status: string; error?: { message: string } | null; items?: Array<{ type: string } & AgentMessage> },\r\n ): void {\r\n for (const [requestId, a] of this.approvals) {\r\n if (a.threadId === threadId && a.turnId === turn.id) this.finishApproval(requestId, 'resolved');\r\n }\r\n const t = this.threads.get(threadId);\r\n if (!t) return;\r\n const collected = t.turns.get(turn.id) ?? [];\r\n t.turns.delete(turn.id);\r\n t.files.clear();\r\n // The daemon announces name changes but not preview changes, so a title taken from the folder is re-read once text exists.\r\n if (!t.thread.name?.trim() && !t.thread.preview?.trim()) void this.refresh(threadId);\r\n if (t.thread.status.type !== 'active') void this.want(threadId, false);\r\n if (turn.status === 'failed' || turn.error) {\r\n this.notify(threadId, 'Codex task failed', turn.error?.message ?? 'The task ended with an error.', 'error');\r\n return;\r\n }\r\n if (turn.status === 'interrupted') {\r\n this.notify(threadId, 'Codex task stopped', 'The task was interrupted.', 'info');\r\n return;\r\n }\r\n // turn/completed may carry only a summary of the items, so prefer what was collected live.\r\n const fromTurn = (turn.items ?? []).filter((i) => i.type === 'agentMessage');\r\n const text = finalAnswer(collected.length ? collected : fromTurn);\r\n if (text) t.hub.send({ type: 'reply', sessionId: codexSessionId(threadId), content: text });\r\n }\r\n\r\n private onHubMessage(threadId: string, msg: ChannelMessage): void {\r\n if (msg.type === 'message_to_session') {\r\n this.enqueue(threadId, async () => textInput(msg.content, msg.source), msg.source);\r\n } else if (msg.type === 'image_to_session') {\r\n this.enqueue(threadId, () => imageInput(msg.imagePath, msg.mimeType, msg.content, msg.source), msg.source);\r\n } else if (msg.type === 'permission_response') {\r\n this.answer(threadId, msg.requestId, msg.choiceId);\r\n } else if (msg.type === 'codex_close') {\r\n void this.close(threadId);\r\n }\r\n }\r\n\r\n // One message at a time per conversation, so a message right behind another sees the turn the first one started.\r\n private enqueue(threadId: string, build: () => Promise<UserInput[]>, source?: MessageSource): void {\r\n const t = this.threads.get(threadId);\r\n if (!t) return;\r\n t.sending = t.sending\r\n .then(() => this.deliver(t, build, source))\r\n .catch((err) => logger.warn(`Codex delivery for ${threadId} failed: ${(err as Error).message}`));\r\n }\r\n\r\n private async deliver(t: Tracked, build: () => Promise<UserInput[]>, source?: MessageSource): Promise<void> {\r\n const threadId = t.thread.id;\r\n if (this.threads.get(threadId) !== t) return;\r\n // A steer is accepted while an approval is pending but read only after it is answered, which reads like an answer.\r\n if (this.waitingForAnswer(t)) {\r\n this.refuseWhileWaiting(threadId);\r\n return;\r\n }\r\n let input: UserInput[];\r\n try {\r\n input = await build();\r\n } catch (err) {\r\n logger.debug(`Codex input for ${threadId} could not be built: ${(err as Error).message}`);\r\n this.notify(threadId, 'Not delivered', 'The image could not be read here, so it was not delivered. Codex may be running on another PC.', 'warning');\r\n return;\r\n }\r\n if (this.threads.get(threadId) !== t) return;\r\n t.pendingTurn = true;\r\n const wasUnrelayed = t.unrelayed;\r\n try {\r\n const rpc = this.rpc;\r\n if (!rpc) throw new Error('not connected to the Codex daemon');\r\n await this.want(threadId, true);\r\n // A new conversation cannot be subscribed before its first turn (no rollout found); the active broadcast retries it.\r\n const unsubscribed = !t.subscribed;\r\n const running = await this.runningTurn(rpc, threadId);\r\n if (this.threads.get(threadId) !== t) return;\r\n // An approval can start while the input is built and the turn looked up; the check at the top cannot see it.\r\n if (this.waitingForAnswer(t)) {\r\n this.abandonDelivery(t, wasUnrelayed);\r\n this.refuseWhileWaiting(threadId);\r\n return;\r\n }\r\n if (unsubscribed) t.unrelayed = true;\r\n if (running) {\r\n await rpc.request('turn/steer', { threadId, expectedTurnId: running, input });\r\n this.notify(threadId, 'Queued', 'Queued: Codex will read it after its current step.', 'info', source);\r\n return;\r\n }\r\n await rpc.request('turn/start', { threadId, input });\r\n } catch (err) {\r\n this.abandonDelivery(t, wasUnrelayed);\r\n this.notify(threadId, 'Not delivered', `Codex rejected the message: ${(err as Error).message}`, 'warning');\r\n }\r\n }\r\n\r\n private abandonDelivery(t: Tracked, wasUnrelayed: boolean): void {\r\n t.pendingTurn = false;\r\n t.unrelayed = wasUnrelayed;\r\n this.releaseLater(t);\r\n }\r\n\r\n // The approval request itself can arrive before the status broadcast that marks the thread as waiting.\r\n private waitingForAnswer(t: Tracked): boolean {\r\n if (hubStatus(t.thread.status) === 'waiting_input') return true;\r\n for (const a of this.approvals.values()) if (a.threadId === t.thread.id && !a.answered) return true;\r\n return false;\r\n }\r\n\r\n private refuseWhileWaiting(threadId: string): void {\r\n this.notify(threadId, 'Not delivered', 'Codex is waiting for an approval or input. Answer it first, then send the message again.', 'warning');\r\n }\r\n\r\n // The list is unavailable before a new conversation's first turn; starting a turn is safe then, since turn/start steers a running turn.\r\n private async runningTurn(rpc: RpcClient, threadId: string): Promise<string | undefined> {\r\n try {\r\n const page = await rpc.request<{ data: Array<{ id: string; status: string }> }>('thread/turns/list', {\r\n threadId,\r\n limit: 1,\r\n sortDirection: 'desc',\r\n });\r\n const turn = page.data?.[0];\r\n return turn?.status === 'inProgress' ? turn.id : undefined;\r\n } catch (err) {\r\n logger.debug(`thread/turns/list ${threadId} failed: ${(err as Error).message}`);\r\n return undefined;\r\n }\r\n }\r\n\r\n private onServerRequest(rpcId: RpcId, method: string, params: any): void {\r\n const t = params?.threadId ? this.threads.get(params.threadId) : undefined;\r\n let view: ApprovalView | null = null;\r\n let broken = false;\r\n if (t) {\r\n try {\r\n view = approvalView(method, params, t.files.get(params.itemId));\r\n } catch (err) {\r\n broken = true;\r\n logger.warn(`Codex ${method} could not be shown: ${(err as Error).message}`);\r\n }\r\n }\r\n if (!t || !view) {\r\n if (t && (broken || USER_REQUESTS.has(method))) {\r\n this.waitingInCodex(t.thread.id);\r\n } else {\r\n logger.debug(`Ignoring Codex server request ${method}`);\r\n }\r\n return;\r\n }\r\n // The daemon re-sends a pending request to every new subscriber, so a resubscribe can deliver it twice.\r\n for (const a of this.approvals.values()) {\r\n if (a.threadId === t.thread.id && a.rpcId === rpcId) return;\r\n }\r\n const requestId = randomUUID();\r\n try {\r\n this.approvals.set(requestId, { threadId: t.thread.id, rpcId, turnId: params.turnId, choices: view.choices, answered: false });\r\n t.hub.send({\r\n type: 'permission_request',\r\n sessionId: codexSessionId(t.thread.id),\r\n requestId,\r\n toolName: view.toolName,\r\n description: view.description,\r\n inputPreview: view.inputPreview,\r\n timestamp: Date.now(),\r\n choices: view.choices.map((c, i) => ({ id: String(i), label: c.label })),\r\n });\r\n } catch (err) {\r\n this.approvals.delete(requestId);\r\n logger.warn(`Codex ${method} could not be relayed: ${(err as Error).message}`);\r\n // No reply to the daemon: the same request is open in the Codex window, and an error reply could cancel it there.\r\n this.waitingInCodex(t.thread.id);\r\n }\r\n }\r\n\r\n private waitingInCodex(threadId: string): void {\r\n this.notify(threadId, 'Codex is waiting', 'Codex asked for input that claude-alarm cannot relay. Handle it in Codex.', 'warning');\r\n }\r\n\r\n private answer(threadId: string, requestId: string, choiceId?: string): void {\r\n const a = this.approvals.get(requestId);\r\n if (!a || a.threadId !== threadId || a.answered || !this.rpc || !choiceId || !/^\\d+$/.test(choiceId)) return;\r\n const choice = a.choices[Number(choiceId)];\r\n if (!choice) return;\r\n a.answered = true;\r\n this.rpc.respond(a.rpcId, choice.response);\r\n }\r\n\r\n private onResolved(threadId: string, rpcId: RpcId): void {\r\n for (const [requestId, a] of this.approvals) {\r\n if (a.threadId === threadId && a.rpcId === rpcId) this.finishApproval(requestId, 'resolved');\r\n }\r\n }\r\n\r\n private finishApproval(requestId: string, state: 'resolved' | 'expired'): void {\r\n const a = this.approvals.get(requestId);\r\n if (!a) return;\r\n this.approvals.delete(requestId);\r\n this.threads.get(a.threadId)?.hub.send({ type: 'permission_resolved', sessionId: codexSessionId(a.threadId), requestId, state });\r\n }\r\n\r\n private notify(threadId: string, title: string, message: string, level: NotifyLevel, to?: MessageSource): void {\r\n this.threads.get(threadId)?.hub.send({ type: 'notify', sessionId: codexSessionId(threadId), title, message, level, ...(to ? { to } : {}) });\r\n }\r\n}\r\n","import WebSocket from 'ws';\r\nimport { WS_PATH_CODEX } from '../shared/constants.js';\r\nimport { logger } from '../shared/logger.js';\r\nimport type { CodexCall, CodexLinkMessage } from '../shared/types.js';\r\n\r\nexport class CodexHubLink {\r\n private ws: WebSocket | null = null;\r\n private retryTimer: ReturnType<typeof setTimeout> | null = null;\r\n private pingTimer: ReturnType<typeof setTimeout> | null = null;\r\n private closed = true;\r\n private ready = false;\r\n\r\n constructor(\r\n private hub: { host: string; port: number; token?: string },\r\n private identity: { id: string; host: string },\r\n private onCall: (call: CodexCall) => Promise<unknown>,\r\n private reconnectMs = 5000,\r\n private pingTimeoutMs = 75_000,\r\n ) {}\r\n\r\n connect(): void {\r\n this.closed = false;\r\n const query = this.hub.token ? `?token=${encodeURIComponent(this.hub.token)}` : '';\r\n let ws: WebSocket;\r\n try {\r\n ws = new WebSocket(`ws://${this.hub.host}:${this.hub.port}${WS_PATH_CODEX}${query}`);\r\n } catch (err) {\r\n logger.debug(`Codex hub link failed: ${(err as Error).message}`);\r\n this.scheduleReconnect();\r\n return;\r\n }\r\n this.ws = ws;\r\n ws.on('open', () => {\r\n if (this.ws !== ws) return;\r\n this.armWatchdog(ws);\r\n this.hello();\r\n });\r\n ws.on('ping', () => this.armWatchdog(ws));\r\n ws.on('message', (data) => {\r\n if (this.ws === ws) this.onMessage(String(data));\r\n });\r\n ws.on('close', () => {\r\n if (this.ws !== ws) return;\r\n this.clearWatchdog();\r\n this.ws = null;\r\n this.scheduleReconnect();\r\n });\r\n ws.on('error', (err) => logger.debug(`Codex hub link error: ${err.message}`));\r\n }\r\n\r\n setReady(ready: boolean): void {\r\n if (this.ready === ready) return;\r\n this.ready = ready;\r\n this.hello();\r\n }\r\n\r\n disconnect(): void {\r\n this.closed = true;\r\n this.clearWatchdog();\r\n if (this.retryTimer) clearTimeout(this.retryTimer);\r\n this.retryTimer = null;\r\n const ws = this.ws;\r\n this.ws = null;\r\n ws?.close();\r\n }\r\n\r\n private hello(): void {\r\n this.send({ type: 'adapter_hello', adapter: { ...this.identity, ready: this.ready } });\r\n }\r\n\r\n private send(msg: CodexLinkMessage): void {\r\n if (this.ws?.readyState === WebSocket.OPEN) this.ws.send(JSON.stringify(msg));\r\n }\r\n\r\n private onMessage(text: string): void {\r\n let msg: CodexLinkMessage;\r\n try {\r\n msg = JSON.parse(text) as CodexLinkMessage;\r\n } catch {\r\n return;\r\n }\r\n if (!msg || typeof msg !== 'object') return;\r\n if (msg.type !== 'adapter_call') return;\r\n const { requestId, call } = msg;\r\n this.onCall(call).then(\r\n (data) => this.send({ type: 'adapter_result', requestId, ok: true, data }),\r\n (err) => this.send({ type: 'adapter_result', requestId, ok: false, error: (err as Error).message }),\r\n );\r\n }\r\n\r\n private clearWatchdog(): void {\r\n if (this.pingTimer) clearTimeout(this.pingTimer);\r\n this.pingTimer = null;\r\n }\r\n\r\n private armWatchdog(ws: WebSocket): void {\r\n if (this.ws !== ws) return;\r\n this.clearWatchdog();\r\n // The hub pings every 30 s, so two missed pings mean it already dropped this socket.\r\n this.pingTimer = setTimeout(() => {\r\n if (this.ws === ws) ws.terminate();\r\n }, this.pingTimeoutMs);\r\n }\r\n\r\n private scheduleReconnect(): void {\r\n if (this.closed || this.retryTimer) return;\r\n this.retryTimer = setTimeout(() => {\r\n this.retryTimer = null;\r\n this.connect();\r\n }, this.reconnectMs);\r\n }\r\n}\r\n","import WebSocket from 'ws';\r\nimport { logger } from '../shared/logger.js';\r\nimport { DEFAULT_HUB_HOST, DEFAULT_HUB_PORT, WS_PATH_CHANNEL } from '../shared/constants.js';\r\nimport type { ChannelMessage, SessionInfo } from '../shared/types.js';\r\n\r\nexport class HubClient {\r\n private ws: WebSocket | null = null;\r\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\r\n private messageHandlers: Array<(msg: ChannelMessage) => void> = [];\r\n private queue: ChannelMessage[] = [];\r\n private connected = false;\r\n private closed = false;\r\n\r\n constructor(\r\n private sessionId: string,\r\n private sessionName: string,\r\n private hubHost = DEFAULT_HUB_HOST,\r\n private hubPort = DEFAULT_HUB_PORT,\r\n private token?: string,\r\n private getPeerName: () => string | undefined = () => undefined,\r\n private getRegistration: () => Partial<SessionInfo> = () => ({}),\r\n ) {}\r\n\r\n connect(): void {\r\n this.closed = false;\r\n const tokenQuery = this.token ? `?token=${encodeURIComponent(this.token)}` : '';\r\n const url = `ws://${this.hubHost}:${this.hubPort}${WS_PATH_CHANNEL}${tokenQuery}`;\r\n logger.debug(`Connecting to hub at ${url}`);\r\n\r\n try {\r\n const ws = new WebSocket(url);\r\n this.ws = ws;\r\n\r\n ws.on('open', () => {\r\n if (this.ws !== ws) return;\r\n logger.info('Connected to hub');\r\n this.connected = true;\r\n\r\n this.ws!.send(JSON.stringify(this.registration()));\r\n\r\n // Flush queued messages\r\n for (const msg of this.queue) {\r\n this.ws!.send(JSON.stringify(msg));\r\n }\r\n this.queue = [];\r\n });\r\n\r\n ws.on('message', (data) => {\r\n if (this.ws !== ws) return;\r\n try {\r\n const msg = JSON.parse(data.toString()) as ChannelMessage;\r\n for (const handler of this.messageHandlers) {\r\n handler(msg);\r\n }\r\n } catch (err) {\r\n logger.warn('Failed to parse hub message:', err);\r\n }\r\n });\r\n\r\n ws.on('close', () => {\r\n if (this.ws !== ws) return;\r\n logger.info('Disconnected from hub');\r\n this.connected = false;\r\n if (!this.closed) this.scheduleReconnect();\r\n });\r\n\r\n ws.on('error', (err) => {\r\n if (this.ws !== ws) return;\r\n logger.debug(`Hub connection error: ${err.message}`);\r\n this.connected = false;\r\n });\r\n } catch {\r\n logger.debug('Failed to connect to hub, will retry');\r\n this.scheduleReconnect();\r\n }\r\n }\r\n\r\n send(msg: ChannelMessage): void {\r\n if (this.connected && this.ws?.readyState === WebSocket.OPEN) {\r\n this.ws.send(JSON.stringify(msg));\r\n } else {\r\n if (this.queue.length < 100) {\r\n this.queue.push(msg);\r\n }\r\n logger.debug('Hub not connected, message queued');\r\n }\r\n }\r\n\r\n onMessage(handler: (msg: ChannelMessage) => void): void {\r\n this.messageHandlers.push(handler);\r\n }\r\n\r\n disconnect(): void {\r\n this.closed = true;\r\n if (this.reconnectTimer) {\r\n clearTimeout(this.reconnectTimer);\r\n this.reconnectTimer = null;\r\n }\r\n if (this.ws) {\r\n this.ws.close();\r\n this.ws = null;\r\n }\r\n this.connected = false;\r\n }\r\n\r\n reregister(): void {\r\n if (this.connected && this.ws?.readyState === WebSocket.OPEN) {\r\n this.ws.send(JSON.stringify(this.registration()));\r\n }\r\n }\r\n\r\n private registration(): ChannelMessage {\r\n return {\r\n type: 'register',\r\n session: {\r\n id: this.sessionId,\r\n name: this.sessionName,\r\n status: 'idle',\r\n connectedAt: Date.now(),\r\n lastActivity: Date.now(),\r\n cwd: process.cwd(),\r\n channelEnabled: true,\r\n peerName: this.getPeerName(),\r\n ...this.getRegistration(),\r\n },\r\n };\r\n }\r\n\r\n private scheduleReconnect(): void {\r\n if (this.reconnectTimer || this.closed) return;\r\n this.reconnectTimer = setTimeout(() => {\r\n this.reconnectTimer = null;\r\n this.connect();\r\n }, 5000);\r\n }\r\n}\r\n","import { execFile, spawn, type ChildProcess } from 'node:child_process';\r\nimport fs from 'node:fs';\r\nimport path from 'node:path';\r\nimport { Duplex } from 'node:stream';\r\nimport WebSocket, { type ClientOptions } from 'ws';\r\nimport { logger } from '../shared/logger.js';\r\n\r\nexport type SpawnFn = (command: string, args: string[]) => ChildProcess;\r\n\r\nexport interface ProxyConnection {\r\n ws: WebSocket;\r\n close(): Promise<void>;\r\n}\r\n\r\n// npm installs Codex on Windows as a codex.cmd shim, which only runs through a shell.\r\nexport function resolveCommand(\r\n command: string,\r\n platform: NodeJS.Platform = process.platform,\r\n env: NodeJS.ProcessEnv = process.env,\r\n): { file: string; shell: boolean } {\r\n if (platform !== 'win32') return { file: command, shell: false };\r\n if (/[\\\\/]/.test(command) || path.extname(command)) return { file: command, shell: /\\.(cmd|bat)$/i.test(command) };\r\n const file = findCodex(command, platform, env);\r\n return file ? { file, shell: file.endsWith('.cmd') } : { file: command, shell: false };\r\n}\r\n\r\nexport function findOnPath(\r\n command: string,\r\n platform: NodeJS.Platform = process.platform,\r\n env: NodeJS.ProcessEnv = process.env,\r\n): string | undefined {\r\n const dirs = (env.PATH ?? env.Path ?? '').split(path.delimiter).filter(Boolean);\r\n for (const ext of platform === 'win32' ? ['.exe', '.cmd'] : ['']) {\r\n for (const dir of dirs) {\r\n const file = path.join(dir, command + ext);\r\n if (fs.existsSync(file)) return file;\r\n }\r\n }\r\n return undefined;\r\n}\r\n\r\n// A terminal opened before Codex was installed keeps its old PATH, so also look where the installers put codex.\r\nexport function findCodex(\r\n command: string,\r\n platform: NodeJS.Platform = process.platform,\r\n env: NodeJS.ProcessEnv = process.env,\r\n): string | undefined {\r\n const onPath = findOnPath(command, platform, env);\r\n if (onPath || platform !== 'win32') return onPath;\r\n const candidates = [\r\n env.LOCALAPPDATA && path.join(env.LOCALAPPDATA, 'Programs', 'OpenAI', 'Codex', 'bin', `${command}.exe`),\r\n env.APPDATA && path.join(env.APPDATA, 'npm', `${command}.cmd`),\r\n ];\r\n return candidates.find((file): file is string => !!file && fs.existsSync(file));\r\n}\r\n\r\nconst shellSpawns = new WeakSet<ChildProcess>();\r\n\r\nexport const spawnedThroughShell = (child: ChildProcess): boolean => shellSpawns.has(child);\r\n\r\nexport const defaultSpawn: SpawnFn = (command, args) => {\r\n const { file, shell } = resolveCommand(command);\r\n if (!shell) return spawn(file, args, { stdio: 'pipe', windowsHide: true });\r\n const child = spawn(`\"${file}\" ${args.join(' ')}`, { stdio: 'pipe', windowsHide: true, shell: true });\r\n shellSpawns.add(child);\r\n return child;\r\n};\r\n\r\nexport type KillTreeFn = ((child: ChildProcess) => Promise<void>) & { track?: (child: ChildProcess) => Promise<void> };\r\nexport interface ProcessIdentity { pid: number; parentPid: number; creationTime: string }\r\nexport type ProcessQueryFn = () => Promise<ProcessIdentity[]>;\r\nexport type ProcessEndFn = (targets: ProcessIdentity[]) => Promise<void>;\r\ntype Descendant = ProcessIdentity & { depth: number };\r\n\r\nconst POWERSHELL_TIMEOUT_MS = 5000;\r\n\r\nconst powershell = (script: string, env?: NodeJS.ProcessEnv) => new Promise<string>((resolve, reject) => {\r\n execFile('powershell.exe', ['-NoProfile', '-NonInteractive', '-Command', script], { windowsHide: true, timeout: POWERSHELL_TIMEOUT_MS, maxBuffer: 4 * 1024 * 1024, env }, (err, stdout) => {\r\n if (err) reject(err);\r\n else resolve(stdout);\r\n });\r\n});\r\n\r\n// Select-Object rather than a [pscustomobject] cast, which Constrained Language Mode (AppLocker/WDAC) refuses.\r\nconst QUERY_SCRIPT = \"@(Get-CimInstance Win32_Process | Where-Object CreationDate | Select-Object @{ n = 'pid'; e = { [int]$_.ProcessId } }, @{ n = 'parentPid'; e = { [int]$_.ParentProcessId } }, @{ n = 'creationTime'; e = { $_.CreationDate.ToUniversalTime().ToString('o') } }) | ConvertTo-Json -Compress\";\r\n\r\n// A prelude runs first in the same PowerShell session; tests use it to switch the language mode or stand in for a cmdlet.\r\nexport const processQuery = (prelude = ''): ProcessQueryFn => async () => {\r\n const rows: unknown = JSON.parse(await powershell(prelude + QUERY_SCRIPT));\r\n if (!Array.isArray(rows) || rows.some(row => !Number.isInteger(row.pid) || !Number.isInteger(row.parentPid) || typeof row.creationTime !== 'string')) {\r\n throw new Error('invalid process snapshot');\r\n }\r\n return rows;\r\n};\r\n\r\nexport const queryProcesses: ProcessQueryFn = processQuery();\r\n\r\n// One handle per target both proves its creation time and ends it, so a PID handed to another process meanwhile is never ended.\r\n// Only property reads and cmdlets touch the process: Constrained Language Mode refuses method calls on it.\r\nconst END_SCRIPT = [\r\n 'foreach ($t in ($env:CLAUDE_ALARM_END_TARGETS | ConvertFrom-Json)) {',\r\n ' $p = Get-Process -Id $t.pid -ErrorAction SilentlyContinue',\r\n // Reading Handle opens the process once, and StartTime, Stop-Process and Wait-Process then use that handle; a getter that throws reads as $null.\r\n ' if ($null -eq $p -or $null -eq $p.Handle) { \"$($t.pid) is gone or cannot be opened\"; continue }',\r\n ' $start = $p.StartTime',\r\n ' if ($null -eq $start) { \"$($t.pid) has no readable creation time\"; continue }',\r\n ' $start = $start.ToUniversalTime()',\r\n // Win32_Process creation dates stop at microseconds.\r\n \" if ($start.AddTicks(-($start.Ticks % 10)).ToString('o') -ne $t.creationTime) { \\\"$($t.pid) now belongs to another process\\\"; continue }\",\r\n ' try { Stop-Process -InputObject $p -Force -ErrorAction Stop } catch { \"$($t.pid) not ended: $($_.FullyQualifiedErrorId)\" }',\r\n // A refused termination usually means the process is already exiting, so it is waited for all the same.\r\n ' try { Wait-Process -InputObject $p -Timeout 1 -ErrorAction Stop } catch { \"$($t.pid) has not exited yet\" }',\r\n '}',\r\n].join('\\n');\r\n\r\n// Each target gets its own PowerShell and time limit, run side by side, so one that runs long cannot use up the others' turn.\r\nexport const processEnder = (prelude = ''): ProcessEndFn => async (targets) => {\r\n await Promise.all(targets.map(async (target) => {\r\n try {\r\n const notes = await powershell(prelude + END_SCRIPT, { ...process.env, CLAUDE_ALARM_END_TARGETS: JSON.stringify([target]) });\r\n for (const note of notes.split(/\\r?\\n/)) if (note) logger.debug(`codex process ${note}`);\r\n } catch (err) {\r\n logger.debug(`ending codex process ${target.pid} failed: ${(err as { killed?: boolean }).killed ? 'timed out' : String(err)}`);\r\n }\r\n }));\r\n};\r\n\r\nexport const endProcesses: ProcessEndFn = processEnder();\r\n\r\nfunction descendantsOf(rootPid: number, rows: ProcessIdentity[]): Descendant[] | undefined {\r\n const root = rows.find(row => row.pid === rootPid);\r\n if (!root) return undefined;\r\n const found: Descendant[] = [];\r\n const seen = new Set([root.pid]);\r\n let level: ProcessIdentity[] = [root];\r\n for (let depth = 1; level.length; depth++) {\r\n const next: ProcessIdentity[] = [];\r\n for (const parent of level) {\r\n for (const row of rows) {\r\n // Windows keeps a dead parent's PID in its children, so a process older than the PID's current owner is not its child.\r\n if (row.parentPid !== parent.pid || seen.has(row.pid) || row.creationTime < parent.creationTime) continue;\r\n seen.add(row.pid);\r\n next.push(row);\r\n found.push({ ...row, depth });\r\n }\r\n }\r\n level = next;\r\n }\r\n return found;\r\n}\r\n\r\nconst exited = (child: ChildProcess) => child.exitCode !== null || child.signalCode !== null;\r\n\r\nconst SHELL_EXIT_WAIT_MS = 1000;\r\nexport const PROXY_TREE_CLOSE_BUDGET_MS = 2 * POWERSHELL_TIMEOUT_MS + SHELL_EXIT_WAIT_MS;\r\n\r\nconst exitOf = (child: ChildProcess) => new Promise<void>((resolve) => {\r\n if (exited(child)) { resolve(); return; }\r\n const timer = setTimeout(() => {\r\n logger.debug(`codex proxy shell ${child.pid} has not exited yet`);\r\n resolve();\r\n }, SHELL_EXIT_WAIT_MS);\r\n child.once('exit', () => {\r\n clearTimeout(timer);\r\n resolve();\r\n });\r\n});\r\n\r\nconst merged = (before: Descendant[], found: Descendant[]) =>\r\n [...before, ...found.filter(d => !before.some(b => b.pid === d.pid && b.creationTime === d.creationTime))];\r\n\r\nexport function treeKiller(\r\n platform: NodeJS.Platform = process.platform,\r\n end: ProcessEndFn = endProcesses,\r\n query: ProcessQueryFn = queryProcesses,\r\n throughShell: (child: ChildProcess) => boolean = spawnedThroughShell,\r\n): KillTreeFn {\r\n const recorded = new WeakMap<ChildProcess, Promise<Descendant[]>>();\r\n // No taskkill: it ends whatever holds a PID by then, and its /T builds trees from ParentProcessId alone.\r\n const endByIdentity = async (descendants: Descendant[]) => {\r\n if (!descendants.length) return;\r\n // The default ender ends all targets at once, so this order is not kept; that is safe because each target's identity is checked as it is ended.\r\n try { await end([...descendants].sort((a, b) => b.depth - a.depth).map(({ depth, ...identity }) => identity)); }\r\n catch (err) { logger.debug(`ending codex processes failed: ${String(err)}`); }\r\n };\r\n const snapshot = async () => {\r\n try { return await query(); }\r\n catch (err) { logger.debug(`codex process query failed: ${String(err)}`); return undefined; }\r\n };\r\n const isShellTree = (child: ChildProcess) => platform === 'win32' && child.pid !== undefined && throughShell(child);\r\n const killer: KillTreeFn = async (child) => {\r\n if (!isShellTree(child)) {\r\n if (!exited(child)) child.kill();\r\n return;\r\n }\r\n // An npm codex.cmd runs the proxy under cmd.exe, and child.kill() would end only cmd.exe.\r\n const [rows, before] = await Promise.all([exited(child) ? undefined : snapshot(), recorded.get(child)]);\r\n // Until Node sees the shell exit it holds the shell's handle, so the shell's PID cannot have been reused during the snapshot.\r\n const found = rows && !exited(child) ? descendantsOf(child.pid!, rows) ?? [] : [];\r\n await endByIdentity(merged(before ?? [], found));\r\n if (exited(child)) return;\r\n child.kill();\r\n await exitOf(child);\r\n };\r\n killer.track = async (child) => {\r\n if (!isShellTree(child) || exited(child)) return;\r\n const earlier = recorded.get(child);\r\n const latest = (async () => {\r\n const rows = await snapshot();\r\n // A snapshot that ends after the shell exited may show another process under the shell's reused PID.\r\n const found = rows && !exited(child) ? descendantsOf(child.pid!, rows) ?? [] : [];\r\n return merged((await earlier) ?? [], found);\r\n })();\r\n recorded.set(child, latest);\r\n await latest;\r\n };\r\n return killer;\r\n}\r\n\r\nexport const killTree: KillTreeFn = treeKiller();\r\n\r\n// The daemon control socket speaks WebSocket, not JSONL: `codex app-server proxy` only relays bytes.\r\nexport const HANDSHAKE_TIMEOUT_MS = 10_000;\r\n\r\nexport function connectProxy(\r\n command: string,\r\n spawnFn: SpawnFn = defaultSpawn,\r\n timeoutMs = HANDSHAKE_TIMEOUT_MS,\r\n killTreeFn: KillTreeFn = killTree,\r\n): Promise<ProxyConnection> {\r\n const child = spawnFn(command, ['app-server', 'proxy']);\r\n void killTreeFn.track?.(child);\r\n child.stdin?.on('error', () => {});\r\n child.stderr?.on('data', (d) => logger.debug(`codex proxy: ${String(d).trim()}`));\r\n\r\n const stream = new Duplex({\r\n read() {},\r\n write(chunk, _encoding, callback) {\r\n if (child.stdin?.writable) child.stdin.write(chunk, callback);\r\n else callback();\r\n },\r\n final(callback) {\r\n child.stdin?.end();\r\n callback();\r\n },\r\n });\r\n child.stdout?.on('data', (d) => stream.push(d));\r\n child.stdout?.on('end', () => stream.push(null));\r\n Object.assign(stream, { setNoDelay() {}, setTimeout() {}, setKeepAlive() {}, ref() {}, unref() {} });\r\n\r\n const ws = new WebSocket('ws://localhost/', {\r\n createConnection: (() => stream) as unknown as ClientOptions['createConnection'],\r\n });\r\n let closing: Promise<void> | undefined;\r\n const close = () => closing ??= (async () => {\r\n ws.terminate();\r\n child.stdin?.end();\r\n await killTreeFn(child);\r\n })();\r\n\r\n return new Promise((resolve, reject) => {\r\n let settled = false;\r\n const timer = setTimeout(() => fail(new Error(`codex daemon did not answer within ${timeoutMs / 1000}s`)), timeoutMs);\r\n const fail = (err: Error) => {\r\n if (settled) return;\r\n settled = true;\r\n clearTimeout(timer);\r\n void close().then(() => reject(err), () => reject(err));\r\n };\r\n child.on('error', fail);\r\n child.once('exit', (code) => fail(new Error(`codex proxy exited (code ${code})`)));\r\n ws.on('error', fail);\r\n ws.once('open', () => {\r\n if (settled) return;\r\n settled = true;\r\n clearTimeout(timer);\r\n child.on('error', (err) => logger.warn(`codex proxy error: ${err.message}`));\r\n ws.on('error', (err) => logger.warn(`codex daemon socket error: ${err.message}`));\r\n // The snapshot taken at spawn can predate the proxy that codex.cmd starts, so record the tree again now that it answers.\r\n void killTreeFn.track?.(child);\r\n resolve({ ws, close });\r\n });\r\n });\r\n}\r\n","import fs from 'node:fs/promises';\r\nimport type { MessageSource } from '../shared/types.js';\r\nimport { withSourcePrefix } from './mapping.js';\r\n\r\nexport type UserInput = { type: 'text'; text: string } | { type: 'image'; url: string };\r\n\r\nconst IMAGE_TYPES = new Set(['image/png', 'image/jpeg', 'image/gif', 'image/webp']);\r\n\r\nexport function textInput(content: string, source?: MessageSource): UserInput[] {\r\n return [{ type: 'text', text: withSourcePrefix(content, source) }];\r\n}\r\n\r\n// Codex reads a localImage path only when it builds the model request, and the hub deletes uploads after 5 minutes, so the bytes go inline.\r\nexport async function imageInput(imagePath: string, mimeType: string, caption: string | undefined, source?: MessageSource): Promise<UserInput[]> {\r\n if (!IMAGE_TYPES.has(mimeType)) throw new Error(`unsupported image type ${mimeType}`);\r\n const data = await fs.readFile(imagePath);\r\n return [\r\n { type: 'text', text: withSourcePrefix(caption?.trim() || '(image)', source) },\r\n { type: 'image', url: `data:${mimeType};base64,${data.toString('base64')}` },\r\n ];\r\n}\r\n","import type { MessageSource, SessionStatus } from '../shared/types.js';\r\n\r\nexport type CodexThreadStatus =\r\n | { type: 'notLoaded' | 'idle' | 'systemError' }\r\n | { type: 'active'; activeFlags: string[] };\r\n\r\nexport interface CodexThread {\r\n id: string;\r\n name?: string | null;\r\n preview?: string;\r\n cwd: string;\r\n status: CodexThreadStatus;\r\n parentThreadId?: string | null;\r\n ephemeral?: boolean;\r\n}\r\n\r\nexport interface AgentMessage {\r\n text: string;\r\n phase?: string | null;\r\n}\r\n\r\nconst TITLE_MAX = 30;\r\nconst SOURCE_LABEL: Record<MessageSource, string> = { dashboard: 'Dashboard', telegram: 'Telegram', api: 'API' };\r\n\r\nconst SOURCE_PREFIX = new RegExp(`^\\\\[claude-alarm(?: · (?:${Object.values(SOURCE_LABEL).join('|')}))?\\\\] ?`);\r\n\r\nexport function codexSessionId(threadId: string): string {\r\n return `codex:${threadId}`;\r\n}\r\n\r\nexport function isTrackable(thread: CodexThread): boolean {\r\n return !thread.parentThreadId && !thread.ephemeral && thread.status.type !== 'notLoaded';\r\n}\r\n\r\nexport function threadTitle(thread: CodexThread): string {\r\n const name = thread.name?.trim();\r\n if (name) return name;\r\n const preview = (thread.preview ?? '').replace(/\\s+/g, ' ').trim().replace(SOURCE_PREFIX, '').trim();\r\n if (preview) return preview.length > TITLE_MAX ? `${preview.slice(0, TITLE_MAX)}…` : preview;\r\n return thread.cwd.replace(/^.*[/\\\\]/, '') || thread.id.slice(0, 8);\r\n}\r\n\r\nexport function hubStatus(status: CodexThreadStatus): SessionStatus {\r\n if (status.type !== 'active') return 'idle';\r\n return status.activeFlags.some((f) => f === 'waitingOnApproval' || f === 'waitingOnUserInput') ? 'waiting_input' : 'working';\r\n}\r\n\r\nexport function withSourcePrefix(content: string, source?: MessageSource): string {\r\n return source ? `[claude-alarm · ${SOURCE_LABEL[source]}] ${content}` : `[claude-alarm] ${content}`;\r\n}\r\n\r\nexport function finalAnswer(messages: AgentMessage[]): string | null {\r\n const finals = messages.filter((m) => m.phase === 'final_answer').map((m) => m.text);\r\n if (finals.length) return finals.join('\\n\\n');\r\n return messages.at(-1)?.text ?? null;\r\n}\r\n\r\n// Explorer's \"Copy as path\" wraps the path in double quotes.\r\nexport function cleanFolder(input: string): string {\r\n const s = input.trim();\r\n return s.length >= 2 && s.startsWith('\"') && s.endsWith('\"') ? s.slice(1, -1).trim() : s;\r\n}\r\n","import { EventEmitter } from 'node:events';\r\nimport type WebSocket from 'ws';\r\nimport { logger } from '../shared/logger.js';\r\n\r\nexport type RpcId = number | string;\r\n\r\nexport class RpcError extends Error {\r\n constructor(public readonly code: number, message: string) {\r\n super(message);\r\n }\r\n}\r\n\r\ninterface Pending {\r\n resolve: (value: any) => void;\r\n reject: (err: Error) => void;\r\n timer?: ReturnType<typeof setTimeout>;\r\n}\r\n\r\nexport class RpcClient extends EventEmitter {\r\n private nextId = 1;\r\n private pending = new Map<RpcId, Pending>();\r\n\r\n constructor(private ws: WebSocket, private timeoutMs = 30_000) {\r\n super();\r\n ws.on('message', (data) => this.onMessage(String(data)));\r\n ws.on('close', () => {\r\n for (const p of this.pending.values()) {\r\n clearTimeout(p.timer);\r\n p.reject(new Error('connection closed'));\r\n }\r\n this.pending.clear();\r\n this.emit('close');\r\n });\r\n }\r\n\r\n request<T = any>(method: string, params?: unknown, timeoutMs: number | null = this.timeoutMs): Promise<T> {\r\n if (this.ws.readyState !== this.ws.OPEN) return Promise.reject(new Error('connection closed'));\r\n const id = this.nextId++;\r\n return new Promise<T>((resolve, reject) => {\r\n const timer =\r\n timeoutMs === null\r\n ? undefined\r\n : setTimeout(() => {\r\n this.pending.delete(id);\r\n reject(new Error(`${method} timed out`));\r\n }, timeoutMs);\r\n this.pending.set(id, { resolve, reject, timer });\r\n this.ws.send(JSON.stringify(params === undefined ? { id, method } : { id, method, params }));\r\n });\r\n }\r\n\r\n notify(method: string, params?: unknown): void {\r\n if (this.ws.readyState !== this.ws.OPEN) return;\r\n this.ws.send(JSON.stringify(params === undefined ? { method } : { method, params }));\r\n }\r\n\r\n respond(id: RpcId, result: unknown): void {\r\n if (this.ws.readyState !== this.ws.OPEN) return;\r\n this.ws.send(JSON.stringify({ id, result }));\r\n }\r\n\r\n // ws stops reading the socket for good if a 'message' listener throws.\r\n private guarded(method: string, fn: () => void): void {\r\n try {\r\n fn();\r\n } catch (err) {\r\n logger.warn(`Codex ${method} handling failed: ${(err as Error).message}`);\r\n }\r\n }\r\n\r\n private onMessage(text: string): void {\r\n let msg: any;\r\n try {\r\n msg = JSON.parse(text);\r\n } catch {\r\n return;\r\n }\r\n if (!msg || typeof msg !== 'object') return;\r\n if (msg.method === undefined && msg.id !== undefined) {\r\n const p = this.pending.get(msg.id);\r\n if (!p) return;\r\n this.pending.delete(msg.id);\r\n clearTimeout(p.timer);\r\n if (msg.error) p.reject(new RpcError(msg.error.code, msg.error.message));\r\n else p.resolve(msg.result);\r\n } else if (msg.method !== undefined && msg.id !== undefined) {\r\n this.guarded(msg.method, () => this.emit('request', msg.id, msg.method, msg.params));\r\n } else if (msg.method !== undefined) {\r\n this.guarded(msg.method, () => this.emit('notification', msg.method, msg.params));\r\n }\r\n }\r\n}\r\n","export interface ApprovalChoice {\r\n label: string;\r\n response: unknown;\r\n}\r\n\r\nexport interface ApprovalView {\r\n toolName: string;\r\n description: string;\r\n inputPreview: string;\r\n choices: ApprovalChoice[];\r\n}\r\n\r\nexport interface FileChange {\r\n path: string;\r\n diff: string;\r\n}\r\n\r\nconst MAX_DESCRIPTION = 500;\r\nconst MAX_PREVIEW = 50_000;\r\n\r\nfunction clip(text: string, max: number): string {\r\n return text.length > max ? `${text.slice(0, max)}…(truncated)` : text;\r\n}\r\n\r\nconst DECISION_LABELS: Record<string, string> = {\r\n accept: 'Allow once',\r\n acceptForSession: 'Allow for this session',\r\n acceptWithExecpolicyAmendment: 'Always allow this command',\r\n decline: 'Decline',\r\n cancel: 'Cancel task',\r\n};\r\n\r\nexport function decisionLabel(decision: unknown): string {\r\n if (typeof decision === 'string') return DECISION_LABELS[decision] ?? decision;\r\n const [key, value] = Object.entries(decision ?? {})[0] ?? [];\r\n if (key === 'applyNetworkPolicyAmendment') {\r\n const rule = (value as { network_policy_amendment?: { host?: string; action?: string } } | undefined)?.network_policy_amendment;\r\n return `Network rule: ${rule?.host ?? 'unknown host'} ${rule?.action ?? ''}`.trim();\r\n }\r\n return key ? (DECISION_LABELS[key] ?? key) : 'Unknown';\r\n}\r\n\r\nfunction decisions(offered: unknown[]): ApprovalChoice[] {\r\n return offered.map((decision) => ({ label: decisionLabel(decision), response: { decision } }));\r\n}\r\n\r\nexport function fileChanges(item: { changes?: Array<{ path?: string; diff?: string }> }): FileChange[] {\r\n return (item.changes ?? []).map((c) => ({ path: String(c.path ?? ''), diff: String(c.diff ?? '') }));\r\n}\r\n\r\nexport function approvalView(method: string, params: any, files: FileChange[] = []): ApprovalView | null {\r\n switch (method) {\r\n case 'item/commandExecution/requestApproval': {\r\n // availableDecisions is sent by Codex 0.159.3 but absent from its generated schema.\r\n const offered: unknown[] =\r\n Array.isArray(params.availableDecisions) && params.availableDecisions.length\r\n ? params.availableDecisions\r\n : ['accept', 'decline', 'cancel'];\r\n const command = params.command ?? (params.commandActions ?? []).map((a: { command: string }) => a.command).join('\\n');\r\n return {\r\n toolName: 'Command',\r\n description: clip(params.reason || 'Codex wants to run a command.', MAX_DESCRIPTION),\r\n inputPreview: JSON.stringify({ command: clip(String(command), MAX_PREVIEW) }),\r\n choices: decisions(offered),\r\n };\r\n }\r\n case 'item/fileChange/requestApproval': {\r\n // The request names only the item; the file list arrives earlier in item/started.\r\n const content = files.length\r\n ? files.map((f) => (f.diff ? `${f.path}\\n${f.diff}` : f.path)).join('\\n\\n')\r\n : 'The file list is not available here. Check the Codex window.';\r\n return {\r\n toolName: 'File change',\r\n description: clip(params.reason || 'Codex wants to change files.', MAX_DESCRIPTION),\r\n inputPreview: JSON.stringify({ content: clip(content, MAX_PREVIEW) }),\r\n choices: decisions(['accept', 'acceptForSession', 'decline', 'cancel']),\r\n };\r\n }\r\n case 'mcpServer/elicitation/request':\r\n if (params._meta?.codex_approval_kind !== 'mcp_tool_call') return null;\r\n return {\r\n toolName: 'MCP tool',\r\n description: clip(`MCP server: ${params.serverName ?? 'unknown'}`, MAX_DESCRIPTION),\r\n inputPreview: JSON.stringify({ content: clip(String(params.message ?? ''), MAX_PREVIEW) }),\r\n choices: [\r\n { label: 'Allow', response: { action: 'accept', content: {} } },\r\n { label: 'Decline', response: { action: 'decline' } },\r\n { label: 'Cancel', response: { action: 'cancel' } },\r\n ],\r\n };\r\n default:\r\n return null;\r\n }\r\n}\r\n","import type { EventEmitter } from 'node:events';\r\nimport type { Writable } from 'node:stream';\r\nimport { logger } from '../shared/logger.js';\r\n\r\n// Adapter stop may await the 10s handshake before the 11s tree cleanup; leave scheduling headroom.\r\nexport const ADAPTER_SHUTDOWN_MS = 25_000;\r\nexport const RUN_CLOSE_MS = 15_000;\r\nexport const SUPERVISOR_STOP_GRACE_MS = 30_000;\r\nexport const CLI_EXIT_FLUSH_MS = 1000;\r\n\r\ninterface ShutdownOptions {\r\n signals: EventEmitter;\r\n stdin?: EventEmitter;\r\n stop(): Promise<void> | undefined;\r\n release(): Promise<void> | undefined;\r\n exit(): void;\r\n}\r\n\r\nexport function createAdapterShutdown(opts: ShutdownOptions): () => void {\r\n let exiting = false;\r\n const shutdown = () => {\r\n if (exiting) return;\r\n exiting = true;\r\n // A codex.cmd proxy runs outside the job that ends this process's children on exit, so its kill must finish first.\r\n const timer = setTimeout(() => {\r\n logger.warn(`Codex adapter shutdown did not finish within ${ADAPTER_SHUTDOWN_MS}ms; exiting`);\r\n opts.exit();\r\n }, ADAPTER_SHUTDOWN_MS);\r\n const stopped = Promise.resolve().then(opts.stop);\r\n const released = Promise.resolve().then(opts.release);\r\n void Promise.allSettled([stopped, released]).then(() => {\r\n clearTimeout(timer);\r\n opts.exit();\r\n });\r\n };\r\n opts.signals.on('SIGINT', shutdown);\r\n opts.signals.on('SIGTERM', shutdown);\r\n opts.stdin?.on('end', shutdown);\r\n opts.stdin?.on('close', shutdown);\r\n return shutdown;\r\n}\r\n\r\nexport async function closeWithinLimit(close: () => Promise<void>): Promise<void> {\r\n let timer: ReturnType<typeof setTimeout> | undefined;\r\n try {\r\n await Promise.race([\r\n Promise.resolve().then(close),\r\n new Promise<never>((_resolve, reject) => {\r\n timer = setTimeout(() => reject(new Error('Codex proxy cleanup timed out')), RUN_CLOSE_MS);\r\n }),\r\n ]);\r\n } finally {\r\n clearTimeout(timer);\r\n }\r\n}\r\n\r\nexport function exitAfterFlush(code: number, stdout: Pick<Writable, 'write'>, stderr: Pick<Writable, 'write'>, exit: (code: number) => void = process.exit): void {\r\n let exited = false;\r\n let remaining = 2;\r\n const finish = () => {\r\n if (exited) return;\r\n exited = true;\r\n clearTimeout(timer);\r\n exit(code);\r\n };\r\n const timer = setTimeout(finish, CLI_EXIT_FLUSH_MS);\r\n const flushed = () => { if (--remaining === 0) finish(); };\r\n for (const stream of [stdout, stderr]) {\r\n try { stream.write('', flushed); }\r\n catch { flushed(); }\r\n }\r\n}\r\n","import net from 'node:net';\r\n\r\nexport function hubUrlHost(host: string): string {\r\n if (host === '' || host === '0.0.0.0') return '127.0.0.1';\r\n if (host === '::') return '[::1]';\r\n return net.isIPv6(host) ? `[${host}]` : host;\r\n}\r\n","import { hubUrlHost } from '../shared/hub-url.js';\r\nimport type { AppConfig } from '../shared/types.js';\r\n\r\nexport interface AdapterHub {\r\n host: string;\r\n port: number;\r\n token?: string;\r\n fromEnv: { host: boolean; port: boolean; token: boolean };\r\n}\r\n\r\nexport function resolveAdapterHub(config: AppConfig, env: NodeJS.ProcessEnv = process.env): AdapterHub {\r\n const envHost = env.CLAUDE_ALARM_HUB_HOST;\r\n const envPort = env.CLAUDE_ALARM_HUB_PORT;\r\n const envToken = env.CLAUDE_ALARM_HUB_TOKEN;\r\n return {\r\n host: hubUrlHost(envHost ?? config.hub.host),\r\n port: envPort ? parseInt(envPort, 10) : config.hub.port,\r\n token: envToken ?? config.hub.token,\r\n fromEnv: { host: envHost !== undefined, port: !!envPort, token: envToken !== undefined },\r\n };\r\n}\r\n","import crypto from 'node:crypto';\r\nimport fs from 'node:fs';\r\nimport net from 'node:net';\r\nimport path from 'node:path';\r\n\r\nexport const CONTROL_PROTOCOL = 1;\r\nexport const STALE_GUARD_MS = 10_000;\r\nexport const STOP_PROOF_LABEL = 'claude-alarm codex stop';\r\nconst MAX_LINE_BYTES = 4096;\r\nconst REQUEST_IDLE_MS = 2000;\r\nconst MAX_SOCKET_PATH_BYTES = 103;\r\n\r\nexport function stopProof(token: string): string {\r\n return crypto.createHmac('sha256', token).update(STOP_PROOF_LABEL).digest('hex');\r\n}\r\n\r\nexport type OwnerState =\r\n | { state: 'running'; pid: number }\r\n | { state: 'absent' }\r\n | { state: 'unknown'; error: string };\r\n\r\nexport type StopResult =\r\n | { state: 'stopping'; pid: number }\r\n | { state: 'unauthorized' }\r\n | { state: 'absent' }\r\n | { state: 'unknown'; error: string };\r\n\r\nexport type Acquired =\r\n | { kind: 'owner'; close: () => Promise<void> }\r\n | { kind: 'held'; pid: number }\r\n | { kind: 'unknown'; error: string };\r\n\r\nexport type Attempt = Acquired | { kind: 'busy' };\r\n\r\nexport interface LockOwner {\r\n pid: number;\r\n token: string;\r\n onStop: () => void;\r\n}\r\n\r\ntype LockFs = Pick<typeof fs, 'mkdirSync' | 'rmdirSync' | 'statSync' | 'unlinkSync'>;\r\n\r\nexport interface LockDeps {\r\n platform?: NodeJS.Platform;\r\n listen?: (endpoint: string, owner: LockOwner) => Promise<Attempt>;\r\n queryOwner?: (endpoint: string) => Promise<OwnerState>;\r\n fs?: LockFs;\r\n now?: () => number;\r\n}\r\n\r\nexport function controlEndpoint(configDir: string, platform: NodeJS.Platform = process.platform): string {\r\n if (platform !== 'win32') return path.posix.join(configDir, 'codex.sock');\r\n let dir: string;\r\n try {\r\n dir = fs.realpathSync.native(configDir);\r\n } catch {\r\n dir = path.win32.resolve(configDir);\r\n }\r\n const hash = crypto.createHash('sha256').update(dir.toLowerCase()).digest('hex').slice(0, 16);\r\n return `\\\\\\\\.\\\\pipe\\\\claude-alarm-codex-${hash}`;\r\n}\r\n\r\ntype Answer = { reply: unknown } | { state: 'absent' } | { state: 'unknown'; error: string };\r\n\r\nfunction ask(endpoint: string, request: object, timeoutMs: number): Promise<Answer> {\r\n return new Promise((resolve) => {\r\n let buffer = '';\r\n let settled = false;\r\n const socket = net.connect(endpoint);\r\n const finish = (answer: Answer) => {\r\n if (settled) return;\r\n settled = true;\r\n clearTimeout(timer);\r\n socket.destroy();\r\n resolve(answer);\r\n };\r\n const timer = setTimeout(() => finish({ state: 'unknown', error: `no answer within ${timeoutMs}ms` }), timeoutMs);\r\n socket.setEncoding('utf8');\r\n socket.on('connect', () => socket.write(`${JSON.stringify(request)}\\n`));\r\n socket.on('data', (chunk: string) => {\r\n buffer += chunk;\r\n const end = buffer.indexOf('\\n');\r\n if (end < 0) {\r\n if (Buffer.byteLength(buffer) > MAX_LINE_BYTES) finish({ state: 'unknown', error: 'reply too long' });\r\n return;\r\n }\r\n try {\r\n finish({ reply: JSON.parse(buffer.slice(0, end)) });\r\n } catch {\r\n finish({ state: 'unknown', error: 'unreadable reply' });\r\n }\r\n });\r\n socket.on('end', () => finish({ state: 'unknown', error: 'closed without a reply' }));\r\n socket.on('error', (err: NodeJS.ErrnoException) => {\r\n if (err.code === 'ENOENT' || err.code === 'ECONNREFUSED') finish({ state: 'absent' });\r\n else finish({ state: 'unknown', error: err.code ?? err.message });\r\n });\r\n });\r\n}\r\n\r\nexport async function queryOwner(endpoint: string, timeoutMs = 1000): Promise<OwnerState> {\r\n const answer = await ask(endpoint, { type: 'status' }, timeoutMs);\r\n if (!('reply' in answer)) return answer;\r\n const reply = answer.reply as { type?: unknown; protocol?: unknown; pid?: unknown } | null;\r\n if (reply?.type === 'status' && reply.protocol === CONTROL_PROTOCOL && Number.isInteger(reply.pid)) {\r\n return { state: 'running', pid: reply.pid as number };\r\n }\r\n return { state: 'unknown', error: 'unexpected reply' };\r\n}\r\n\r\nexport async function requestStop(endpoint: string, token: string, timeoutMs = 1000): Promise<StopResult> {\r\n const answer = await ask(endpoint, { type: 'stop', proof: stopProof(token) }, timeoutMs);\r\n if (!('reply' in answer)) return answer;\r\n const reply = answer.reply as { type?: unknown; pid?: unknown; error?: unknown } | null;\r\n if (reply?.type === 'stopping' && Number.isInteger(reply.pid)) return { state: 'stopping', pid: reply.pid as number };\r\n if (reply?.type === 'error' && reply.error === 'unauthorized') return { state: 'unauthorized' };\r\n return { state: 'unknown', error: 'unexpected reply' };\r\n}\r\n\r\nconst line = (message: object) => `${JSON.stringify(message)}\\n`;\r\n\r\nfunction controlServer(owner: LockOwner): net.Server {\r\n const expectedProof = Buffer.from(stopProof(owner.token));\r\n return net.createServer((socket) => {\r\n let buffer = '';\r\n socket.setEncoding('utf8');\r\n socket.on('error', () => {});\r\n const idle = setTimeout(() => socket.destroy(), REQUEST_IDLE_MS);\r\n socket.on('close', () => clearTimeout(idle));\r\n const onData = (chunk: string) => {\r\n buffer += chunk;\r\n const end = buffer.indexOf('\\n');\r\n if (end < 0) {\r\n if (Buffer.byteLength(buffer) > MAX_LINE_BYTES) socket.destroy();\r\n return;\r\n }\r\n socket.off('data', onData);\r\n clearTimeout(idle);\r\n let request: { type?: unknown; proof?: unknown } | null = null;\r\n try {\r\n request = JSON.parse(buffer.slice(0, end));\r\n } catch {}\r\n if (request?.type === 'status') {\r\n socket.end(line({ type: 'status', protocol: CONTROL_PROTOCOL, pid: owner.pid }));\r\n } else if (request?.type === 'stop') {\r\n const proof = typeof request.proof === 'string' ? Buffer.from(request.proof) : undefined;\r\n if (owner.token !== '' && proof && proof.length === expectedProof.length && crypto.timingSafeEqual(proof, expectedProof)) {\r\n socket.end(line({ type: 'stopping', pid: owner.pid }), () => owner.onStop());\r\n } else {\r\n socket.end(line({ type: 'error', error: 'unauthorized' }));\r\n }\r\n } else {\r\n socket.end(line({ type: 'error', error: 'unknown request' }));\r\n }\r\n };\r\n socket.on('data', onData);\r\n });\r\n}\r\n\r\nexport function listenControl(endpoint: string, owner: LockOwner): Promise<Attempt> {\r\n const server = controlServer(owner);\r\n return new Promise((resolve) => {\r\n const onError = (err: NodeJS.ErrnoException) => {\r\n resolve(err.code === 'EADDRINUSE' ? { kind: 'busy' } : { kind: 'unknown', error: err.code ?? err.message });\r\n };\r\n server.once('error', onError);\r\n server.listen(endpoint, () => {\r\n server.off('error', onError);\r\n server.on('error', () => {});\r\n resolve({ kind: 'owner', close: () => new Promise<void>((done) => server.close(() => done())) });\r\n });\r\n });\r\n}\r\n\r\nfunction settle(attempt: Attempt, busy: string): Acquired {\r\n return attempt.kind === 'busy' ? { kind: 'unknown', error: busy } : attempt;\r\n}\r\n\r\nexport async function acquireLock(endpoint: string, owner: LockOwner, deps: LockDeps = {}): Promise<Acquired> {\r\n const platform = deps.platform ?? process.platform;\r\n const listen = deps.listen ?? listenControl;\r\n const query = deps.queryOwner ?? ((e: string) => queryOwner(e));\r\n if (platform !== 'win32' && Buffer.byteLength(endpoint) > MAX_SOCKET_PATH_BYTES) {\r\n return { kind: 'unknown', error: `control socket path is too long: ${endpoint}` };\r\n }\r\n const first = await listen(endpoint, owner);\r\n if (first.kind !== 'busy') return first;\r\n const state = await query(endpoint);\r\n if (state.state === 'running') return { kind: 'held', pid: state.pid };\r\n if (state.state === 'unknown') return { kind: 'unknown', error: state.error };\r\n if (platform === 'win32') return settle(await listen(endpoint, owner), 'the control pipe is in use but does not answer');\r\n return recoverSocket(endpoint, owner, listen, query, deps.fs ?? fs, deps.now ?? Date.now);\r\n}\r\n\r\n// Two starters that both find a dead socket file would each unlink it, and the second unlink would remove the first one's live socket.\r\nasync function recoverSocket(\r\n endpoint: string,\r\n owner: LockOwner,\r\n listen: (endpoint: string, owner: LockOwner) => Promise<Attempt>,\r\n query: (endpoint: string) => Promise<OwnerState>,\r\n f: LockFs,\r\n now: () => number,\r\n): Promise<Acquired> {\r\n const guard = `${endpoint}.lock`;\r\n const blocked = takeGuard(guard, f, now);\r\n if (blocked) return { kind: 'unknown', error: blocked };\r\n try {\r\n const state = await query(endpoint);\r\n if (state.state === 'running') return { kind: 'held', pid: state.pid };\r\n if (state.state === 'unknown') return { kind: 'unknown', error: state.error };\r\n try {\r\n f.unlinkSync(endpoint);\r\n } catch (err) {\r\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') return { kind: 'unknown', error: (err as Error).message };\r\n }\r\n return settle(await listen(endpoint, owner), 'the control socket is in use but does not answer');\r\n } finally {\r\n try {\r\n f.rmdirSync(guard);\r\n } catch {}\r\n }\r\n}\r\n\r\nfunction takeGuard(guard: string, f: LockFs, now: () => number): string | undefined {\r\n for (let attempt = 0; attempt < 2; attempt++) {\r\n try {\r\n f.mkdirSync(guard);\r\n return undefined;\r\n } catch (err) {\r\n if ((err as NodeJS.ErrnoException).code !== 'EEXIST') return (err as Error).message;\r\n }\r\n let age: number;\r\n try {\r\n age = now() - f.statSync(guard).mtimeMs;\r\n } catch {\r\n continue;\r\n }\r\n if (age <= STALE_GUARD_MS) return 'another Codex adapter is starting';\r\n try {\r\n f.rmdirSync(guard);\r\n } catch {}\r\n }\r\n return 'another Codex adapter is starting';\r\n}\r\n","import { loadConfig } from '../shared/config.js';\r\nimport { CONFIG_DIR } from '../shared/constants.js';\r\nimport { installCrashGuard, logStartup } from '../shared/crash-guard.js';\r\nimport { logger } from '../shared/logger.js';\r\nimport { CodexAdapter } from './adapter.js';\r\nimport { createAdapterShutdown } from './shutdown.js';\r\nimport { resolveAdapterHub } from './hub-target.js';\r\nimport { acquireLock, controlEndpoint } from './instance-lock.js';\r\n\r\nconst WAIT_MIN_MS = 2000;\r\nconst WAIT_MAX_MS = 30_000;\r\n\r\ninstallCrashGuard('codex adapter');\r\n// Once the hub is gone its pipes break; without listeners every log line would become an uncaught EPIPE.\r\nprocess.stdout.on('error', () => {});\r\nprocess.stderr.on('error', () => {});\r\nconst config = loadConfig();\r\nconst supervised = process.argv.includes('--watch-stdin');\r\nconst endpoint = controlEndpoint(CONFIG_DIR);\r\n\r\nlet adapter: CodexAdapter | undefined;\r\nlet release: (() => Promise<void>) | undefined;\r\nconst shutdown = createAdapterShutdown({\r\n signals: process,\r\n stdin: supervised ? process.stdin : undefined,\r\n stop: () => adapter?.stop(),\r\n release: () => release?.(),\r\n exit: () => process.exit(0),\r\n});\r\n\r\n// On Windows `hub stop` kills the hub without running its exit handlers, so stdin EOF is the only sign the parent is gone.\r\nif (supervised) process.stdin.resume();\r\n\r\nfunction send(message: object, then?: () => void): void {\r\n if (!process.send || !process.connected) {\r\n then?.();\r\n return;\r\n }\r\n // With a callback, a channel that closes between the check and the send reports here instead of throwing.\r\n process.send(message, undefined, undefined, (err: Error | null) => {\r\n if (err) logger.debug(`Report to the parent not delivered: ${err.message}`);\r\n then?.();\r\n });\r\n}\r\n\r\nconst sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));\r\n\r\nasync function takeLock(): Promise<boolean> {\r\n let delay = WAIT_MIN_MS;\r\n let waitReason: string | undefined;\r\n for (;;) {\r\n const lock = await acquireLock(endpoint, {\r\n pid: process.pid,\r\n token: config.hub.token ?? '',\r\n onStop: () => {\r\n if (supervised) logger.warn('Stopped by claude-alarm codex stop; the hub will not start the Codex adapter again until the hub restarts');\r\n shutdown();\r\n },\r\n });\r\n if (lock.kind === 'owner') {\r\n release = lock.close;\r\n if (waitReason !== undefined) logger.info('Codex adapter took over: the other adapter has stopped');\r\n return true;\r\n }\r\n if (!supervised) {\r\n if (lock.kind === 'held') {\r\n logger.info(`Codex adapter already running (PID: ${lock.pid})`);\r\n send({ type: 'codex-already-running', pid: lock.pid }, () => process.exit(0));\r\n } else {\r\n logger.error(`Codex adapter cannot start: ${lock.error}`);\r\n send({ type: 'codex-lock-failed', error: lock.error }, () => process.exit(1));\r\n }\r\n return false;\r\n }\r\n const reason = lock.kind === 'held' ? `held:${lock.pid}` : `unknown:${lock.error}`;\r\n if (reason !== waitReason) {\r\n waitReason = reason;\r\n if (lock.kind === 'held') logger.info(`Another Codex adapter is running (PID: ${lock.pid}); this one takes over when it stops`);\r\n else logger.warn(`Codex adapter control endpoint is unavailable (${lock.error}); retrying`);\r\n }\r\n await sleep(delay);\r\n delay = Math.min(delay * 2, WAIT_MAX_MS);\r\n }\r\n}\r\n\r\nvoid takeLock().then((owned) => {\r\n if (!owned) return;\r\n logStartup('Codex adapter');\r\n const { host, port, token } = resolveAdapterHub(config);\r\n adapter = new CodexAdapter({\r\n command: config.codex?.command ?? 'codex',\r\n hub: { host, port, token },\r\n onFirstConnect: (outcome) => send({ type: 'codex-first-connect', ...outcome }),\r\n });\r\n adapter.start();\r\n});\r\n"],"mappings":"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","names":["path","config","config","fs","fs","fs","os","path","randomUUID","WebSocket","WebSocket","fs","path","WebSocket","path","fs","WebSocket","fs","fs","os","randomUUID","path","fs","shutdown","config","fs","net","path","endpoint","net","endpoint","fs"]}