@delt/claude-alarm 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -10
- package/dist/channel/server.js.map +1 -1
- package/dist/cli.js +906 -67
- package/dist/cli.js.map +1 -1
- package/dist/codex/main.js +380 -63
- package/dist/codex/main.js.map +1 -1
- package/dist/dashboard/index.html +179 -2
- package/dist/hub/server.js +165 -8
- package/dist/hub/server.js.map +1 -1
- package/dist/index.d.ts +60 -2
- package/dist/index.js +166 -8
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/dashboard/index.html +179 -2
package/dist/codex/main.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/codex/main.ts","../../src/shared/config.ts","../../src/shared/constants.ts","../../src/shared/crash-guard.ts","../../src/shared/logger.ts","../../src/codex/adapter.ts","../../src/channel/hub-client.ts","../../src/codex/transport.ts","../../src/codex/rpc.ts","../../src/codex/approvals.ts","../../src/codex/mapping.ts"],"sourcesContent":["import fs from 'node:fs';\r\nimport { loadConfig } from '../shared/config.js';\r\nimport { CODEX_PID_FILE, DEFAULT_HUB_HOST } 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\n\r\nfunction isRunning(pid: number): boolean {\r\n try {\r\n process.kill(pid, 0);\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n}\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\n\r\nconst existing = fs.existsSync(CODEX_PID_FILE) ? parseInt(fs.readFileSync(CODEX_PID_FILE, 'utf-8').trim(), 10) : NaN;\r\nif (!Number.isNaN(existing) && existing !== process.pid && isRunning(existing)) {\r\n logger.info(`Codex adapter already running (PID: ${existing})`);\r\n process.exit(0);\r\n}\r\nfs.writeFileSync(CODEX_PID_FILE, String(process.pid), 'utf-8');\r\nlogStartup('Codex adapter');\r\n\r\nconst host = process.env.CLAUDE_ALARM_HUB_HOST ?? (config.hub.host === '0.0.0.0' ? DEFAULT_HUB_HOST : config.hub.host);\r\nconst port = process.env.CLAUDE_ALARM_HUB_PORT ? parseInt(process.env.CLAUDE_ALARM_HUB_PORT, 10) : config.hub.port;\r\nconst token = process.env.CLAUDE_ALARM_HUB_TOKEN ?? config.hub.token;\r\n\r\nconst adapter = new CodexAdapter({ command: config.codex?.command ?? 'codex', hub: { host, port, token } });\r\nadapter.start();\r\n\r\nlet exiting = false;\r\nconst shutdown = () => {\r\n if (exiting) return;\r\n exiting = true;\r\n adapter.stop();\r\n try {\r\n if (fs.readFileSync(CODEX_PID_FILE, 'utf-8').trim() === String(process.pid)) fs.unlinkSync(CODEX_PID_FILE);\r\n } catch {}\r\n process.exit(0);\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 (process.argv.includes('--watch-stdin')) {\r\n process.stdin.on('end', shutdown);\r\n process.stdin.on('close', shutdown);\r\n process.stdin.resume();\r\n}\r\n","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\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 { 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, MessageSource, NotifyLevel, SessionInfo } from '../shared/types.js';\r\nimport { connectProxy, type ProxyConnection, type SpawnFn } from './transport.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 codexSessionId,\r\n finalAnswer,\r\n hubStatus,\r\n isTrackable,\r\n threadTitle,\r\n withSourcePrefix,\r\n type AgentMessage,\r\n type CodexThread,\r\n type CodexThreadStatus,\r\n} from './mapping.js';\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}\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 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\r\n constructor(private opts: CodexAdapterOptions) {\r\n this.delay = opts.reconnectMinMs ?? 2000;\r\n }\r\n\r\n start(): void {\r\n this.stopped = false;\r\n void this.connect();\r\n }\r\n\r\n stop(): void {\r\n this.stopped = true;\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);\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 await this.discover();\r\n this.delay = this.opts.reconnectMinMs ?? 2000;\r\n } catch (err) {\r\n logger.warn(`Codex daemon connection failed: ${(err as Error).message}`);\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.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 async discover(): Promise<void> {\r\n const ids: string[] = [];\r\n let cursor: string | null | undefined;\r\n do {\r\n const page = await this.rpc!.request<{ data: string[]; nextCursor?: string | null }>(\r\n 'thread/loaded/list',\r\n cursor ? { cursor } : {},\r\n );\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 }\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 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) };\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;\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 }\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 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.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.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 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 void this.sendTurn(threadId, msg.content, msg.source);\r\n } else if (msg.type === 'image_to_session') {\r\n this.notify(threadId, 'Not delivered', 'Codex sessions do not accept images yet.', 'warning');\r\n } else if (msg.type === 'permission_response') {\r\n this.answer(threadId, msg.requestId, msg.choiceId);\r\n }\r\n }\r\n\r\n private async sendTurn(threadId: string, content: string, source?: MessageSource): Promise<void> {\r\n const t = this.threads.get(threadId);\r\n if (!t) return;\r\n if (t.thread.status.type !== 'idle' || t.pendingTurn) {\r\n this.notify(threadId, 'Not delivered', 'Codex is busy, so the message was not delivered. Send it again when the task finishes.', 'warning');\r\n return;\r\n }\r\n t.pendingTurn = true;\r\n try {\r\n if (!this.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 t.unrelayed = !t.subscribed;\r\n await this.rpc.request('turn/start', { threadId, input: [{ type: 'text', text: withSourcePrefix(content, source) }] });\r\n } catch (err) {\r\n t.pendingTurn = false;\r\n t.unrelayed = false;\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 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.notify(t.thread.id, 'Codex is waiting', 'Codex asked for input that claude-alarm cannot relay. Handle it in Codex.', 'warning');\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 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 }\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 { 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' || /[\\\\/]/.test(command) || path.extname(command)) return { file: command, shell: false };\r\n const file = findOnPath(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\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 function connectProxy(command: string, spawnFn: SpawnFn = defaultSpawn): 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 fail = (err: Error) => {\r\n if (settled) return;\r\n settled = true;\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 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 { 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): 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 = setTimeout(() => {\r\n this.pending.delete(id);\r\n reject(new Error(`${method} timed out`));\r\n }, this.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 { 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\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();\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"],"mappings":"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","names":["fs","path","config","config","fs","fs","randomUUID","token","fs","path","WebSocket","path","fs","WebSocket","existing","host","port","token","randomUUID","fs"]}
|
|
1
|
+
{"version":3,"sources":["../../src/codex/main.ts","../../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"],"sourcesContent":["import fs from 'node:fs';\r\nimport { loadConfig } from '../shared/config.js';\r\nimport { CODEX_PID_FILE } 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\n\r\nfunction isRunning(pid: number): boolean {\r\n try {\r\n process.kill(pid, 0);\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n}\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\n\r\nconst existing = fs.existsSync(CODEX_PID_FILE) ? parseInt(fs.readFileSync(CODEX_PID_FILE, 'utf-8').trim(), 10) : NaN;\r\nif (!Number.isNaN(existing) && existing !== process.pid && isRunning(existing)) {\r\n logger.info(`Codex adapter already running (PID: ${existing})`);\r\n process.exit(0);\r\n}\r\nfs.writeFileSync(CODEX_PID_FILE, String(process.pid), 'utf-8');\r\nlogStartup('Codex adapter');\r\n\r\nconst { host, port, token } = resolveAdapterHub(config);\r\n\r\nconst adapter = new CodexAdapter({\r\n command: config.codex?.command ?? 'codex',\r\n hub: { host, port, token },\r\n onFirstConnect: (outcome) => {\r\n if (!process.send || !process.connected) return;\r\n // With a callback, a channel that closes between the check and the send reports here instead of throwing.\r\n process.send({ type: 'codex-first-connect', ...outcome }, undefined, undefined, (err: Error | null) => {\r\n if (err) logger.debug(`First-connect report not delivered: ${err.message}`);\r\n });\r\n },\r\n});\r\nadapter.start();\r\n\r\nlet exiting = false;\r\nconst shutdown = () => {\r\n if (exiting) return;\r\n exiting = true;\r\n adapter.stop();\r\n try {\r\n if (fs.readFileSync(CODEX_PID_FILE, 'utf-8').trim() === String(process.pid)) fs.unlinkSync(CODEX_PID_FILE);\r\n } catch {}\r\n process.exit(0);\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 (process.argv.includes('--watch-stdin')) {\r\n process.stdin.on('end', shutdown);\r\n process.stdin.on('close', shutdown);\r\n process.stdin.resume();\r\n}\r\n","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 }\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.notify(t.thread.id, 'Codex is waiting', 'Codex asked for input that claude-alarm cannot relay. Handle it in Codex.', 'warning');\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 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 }\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' || /[\\\\/]/.test(command) || path.extname(command)) return { file: command, shell: false };\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 function connectProxy(command: string, spawnFn: SpawnFn = defaultSpawn): 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 fail = (err: Error) => {\r\n if (settled) return;\r\n settled = true;\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 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"],"mappings":"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","names":["fs","path","config","config","fs","fs","fs","os","path","randomUUID","WebSocket","token","WebSocket","fs","path","WebSocket","path","fs","WebSocket","fs","fs","os","randomUUID","host","port","token","path","fs","existing","host","config","fs"]}
|