@mobvibe/cli 0.1.6 → 0.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1,25 @@
1
- {"version":3,"sources":["../src/index.ts","../src/auth/login.ts","../src/lib/logger.ts","../src/auth/credentials.ts","../src/config.ts","../src/config-loader.ts","../src/daemon/daemon.ts","../src/acp/session-manager.ts","../../../packages/shared/dist/types/errors.js","../src/acp/acp-connection.ts","../src/daemon/socket-client.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { login, loginStatus, logout } from \"./auth/login.js\";\nimport { getCliConfig } from \"./config.js\";\nimport { DaemonManager } from \"./daemon/daemon.js\";\nimport { logger } from \"./lib/logger.js\";\n\nconst program = new Command();\n\nprogram\n\t.name(\"mobvibe\")\n\t.description(\"Mobvibe CLI - Connect local ACP backends to the gateway\")\n\t.version(\"0.0.0\");\n\nprogram\n\t.command(\"start\")\n\t.description(\"Start the mobvibe daemon\")\n\t.option(\"--gateway <url>\", \"Gateway URL\", process.env.MOBVIBE_GATEWAY_URL)\n\t.option(\"--foreground\", \"Run in foreground instead of detaching\")\n\t.action(async (options) => {\n\t\tif (options.gateway) {\n\t\t\tprocess.env.MOBVIBE_GATEWAY_URL = options.gateway;\n\t\t}\n\t\tconst config = await getCliConfig();\n\t\tconst daemon = new DaemonManager(config);\n\t\tawait daemon.start({ foreground: options.foreground });\n\t});\n\nprogram\n\t.command(\"stop\")\n\t.description(\"Stop the mobvibe daemon\")\n\t.action(async () => {\n\t\tconst config = await getCliConfig();\n\t\tconst daemon = new DaemonManager(config);\n\t\tawait daemon.stop();\n\t});\n\nprogram\n\t.command(\"status\")\n\t.description(\"Show daemon status\")\n\t.action(async () => {\n\t\tconst config = await getCliConfig();\n\t\tconst daemon = new DaemonManager(config);\n\t\tconst status = await daemon.status();\n\t\tif (status.running) {\n\t\t\tlogger.info({ pid: status.pid }, \"daemon_status_running\");\n\t\t\tconsole.log(`Daemon is running (PID ${status.pid})`);\n\t\t\tif (status.connected !== undefined) {\n\t\t\t\tconsole.log(`Connected to gateway: ${status.connected ? \"yes\" : \"no\"}`);\n\t\t\t}\n\t\t\tif (status.sessionCount !== undefined) {\n\t\t\t\tconsole.log(`Active sessions: ${status.sessionCount}`);\n\t\t\t}\n\t\t} else {\n\t\t\tlogger.info(\"daemon_status_not_running\");\n\t\t\tconsole.log(\"Daemon is not running\");\n\t\t}\n\t});\n\nprogram\n\t.command(\"logs\")\n\t.description(\"Show daemon logs\")\n\t.option(\"-f, --follow\", \"Follow log output\")\n\t.option(\"-n, --lines <number>\", \"Number of lines to show\", \"50\")\n\t.action(async (options) => {\n\t\tconst config = await getCliConfig();\n\t\tconst daemon = new DaemonManager(config);\n\t\tawait daemon.logs({\n\t\t\tfollow: options.follow,\n\t\t\tlines: Number.parseInt(options.lines, 10),\n\t\t});\n\t});\n\nprogram\n\t.command(\"login\")\n\t.description(\"Authenticate with an API key from the WebUI\")\n\t.action(async () => {\n\t\tconst result = await login();\n\t\tif (!result.success) {\n\t\t\tlogger.error({ err: result.error }, \"login_failed\");\n\t\t\tconsole.error(`Login failed: ${result.error}`);\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram\n\t.command(\"logout\")\n\t.description(\"Remove stored credentials\")\n\t.action(async () => {\n\t\tawait logout();\n\t});\n\nprogram\n\t.command(\"auth-status\")\n\t.description(\"Show authentication status\")\n\t.action(async () => {\n\t\tawait loginStatus();\n\t});\n\nexport async function run() {\n\tawait program.parseAsync(process.argv);\n}\n\nrun().catch((error) => {\n\tlogger.error({ err: error }, \"cli_run_error\");\n\tconsole.error(\"Error:\", error.message);\n\tprocess.exit(1);\n});\n","/**\n * Login command for CLI authentication.\n * Prompts user to paste an API key generated from the WebUI.\n */\n\nimport * as readline from \"node:readline/promises\";\nimport { logger } from \"../lib/logger.js\";\nimport {\n\ttype Credentials,\n\tdeleteCredentials,\n\tloadCredentials,\n\tsaveCredentials,\n} from \"./credentials.js\";\n\nexport interface LoginResult {\n\tsuccess: boolean;\n\terror?: string;\n}\n\n/**\n * Start the login flow.\n * Prompts user to paste an API key from the WebUI.\n */\nexport async function login(): Promise<LoginResult> {\n\tlogger.info(\"login_prompt_start\");\n\tconsole.log(\"To get an API key:\");\n\tconsole.log(\" 1. Open the Mobvibe WebUI in your browser\");\n\tconsole.log(\" 2. Go to Settings (gear icon) -> API Keys\");\n\tconsole.log(\" 3. Click 'Create API Key' and copy it\");\n\tconsole.log(\" 4. Paste the API key below\\n\");\n\n\tconst rl = readline.createInterface({\n\t\tinput: process.stdin,\n\t\toutput: process.stdout,\n\t});\n\n\ttry {\n\t\tconst apiKey = await rl.question(\"Paste your API key: \");\n\n\t\tif (!apiKey.trim()) {\n\t\t\tlogger.warn(\"login_missing_api_key\");\n\t\t\treturn { success: false, error: \"No API key provided\" };\n\t\t}\n\n\t\t// Basic format check\n\t\tif (!apiKey.trim().startsWith(\"mbk_\")) {\n\t\t\tlogger.warn(\"login_invalid_api_key_format\");\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: \"Invalid API key format (should start with mbk_)\",\n\t\t\t};\n\t\t}\n\n\t\t// Store credentials - gateway validates on connection\n\t\tconst credentials: Credentials = {\n\t\t\tapiKey: apiKey.trim(),\n\t\t\tcreatedAt: Date.now(),\n\t\t};\n\t\tawait saveCredentials(credentials);\n\t\tlogger.info(\"login_credentials_saved\");\n\n\t\tconsole.log(\"\\nAPI key saved!\");\n\t\tconsole.log(\"Run 'mobvibe start' to connect to the gateway.\");\n\n\t\treturn { success: true };\n\t} finally {\n\t\trl.close();\n\t}\n}\n\n/**\n * Logout - delete stored credentials.\n */\nexport async function logout(): Promise<void> {\n\tawait deleteCredentials();\n\tlogger.info(\"logout_complete\");\n\tconsole.log(\"Logged out successfully. Credentials deleted.\");\n}\n\n/**\n * Show current login status.\n */\nexport async function loginStatus(): Promise<void> {\n\tconst credentials = await loadCredentials();\n\tif (credentials) {\n\t\tlogger.info(\"login_status_logged_in\");\n\t\tconsole.log(\"Status: Logged in\");\n\t\tconsole.log(`API key: ${credentials.apiKey.slice(0, 12)}...`);\n\t\tconsole.log(`Saved: ${new Date(credentials.createdAt).toLocaleString()}`);\n\t} else {\n\t\tlogger.info(\"login_status_logged_out\");\n\t\tconsole.log(\"Status: Not logged in\");\n\t\tconsole.log(\"Run 'mobvibe login' to authenticate.\");\n\t}\n}\n","import pino from \"pino\";\n\nconst LOG_LEVEL = process.env.LOG_LEVEL ?? \"info\";\nconst isPretty = process.env.NODE_ENV !== \"production\";\n\nconst redact = {\n\tpaths: [\n\t\t\"req.headers.authorization\",\n\t\t\"req.headers.cookie\",\n\t\t\"req.headers['x-api-key']\",\n\t\t\"headers.authorization\",\n\t\t\"headers.cookie\",\n\t\t\"headers['x-api-key']\",\n\t\t\"apiKey\",\n\t\t\"token\",\n\t],\n\tcensor: \"[redacted]\",\n};\n\nconst transport = isPretty\n\t? {\n\t\t\ttarget: \"pino-pretty\",\n\t\t\toptions: {\n\t\t\t\tcolorize: true,\n\t\t\t\ttranslateTime: \"SYS:standard\",\n\t\t\t\tignore: \"pid,hostname\",\n\t\t\t},\n\t\t}\n\t: undefined;\n\nexport const logger = pino(\n\t{\n\t\tlevel: LOG_LEVEL,\n\t\tredact,\n\t\tbase: { service: \"mobvibe-cli\" },\n\t\tserializers: {\n\t\t\terr: pino.stdSerializers.err,\n\t\t\terror: pino.stdSerializers.err,\n\t\t},\n\t},\n\ttransport ? pino.transport(transport) : undefined,\n);\n","/**\n * Credentials management for CLI authentication.\n * Stores API key in ~/.mobvibe/credentials.json\n */\n\nimport fs from \"node:fs/promises\";\nimport os from \"node:os\";\nimport path from \"node:path\";\n\nexport interface Credentials {\n\t/** API key for gateway authentication */\n\tapiKey: string;\n\t/** When the credentials were created */\n\tcreatedAt: number;\n\t/** Optional: custom gateway URL (user can manually set this) */\n\tgatewayUrl?: string;\n}\n\nconst MOBVIBE_DIR =\n\tprocess.env.MOBVIBE_HOME ?? path.join(os.homedir(), \".mobvibe\");\nconst CREDENTIALS_FILE = path.join(MOBVIBE_DIR, \"credentials.json\");\n\n/**\n * Ensure the mobvibe directory exists.\n */\nasync function ensureMobvibeDir(): Promise<void> {\n\tawait fs.mkdir(MOBVIBE_DIR, { recursive: true });\n}\n\n/**\n * Load credentials from the credentials file.\n * Returns null if no credentials exist.\n */\nexport async function loadCredentials(): Promise<Credentials | null> {\n\ttry {\n\t\tconst data = await fs.readFile(CREDENTIALS_FILE, \"utf8\");\n\t\tconst credentials = JSON.parse(data) as Credentials;\n\n\t\t// Validate required fields\n\t\tif (!credentials.apiKey) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn credentials;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n/**\n * Save credentials to the credentials file.\n */\nexport async function saveCredentials(credentials: Credentials): Promise<void> {\n\tawait ensureMobvibeDir();\n\tawait fs.writeFile(\n\t\tCREDENTIALS_FILE,\n\t\tJSON.stringify(credentials, null, 2),\n\t\t{ mode: 0o600 }, // Read/write only for owner\n\t);\n}\n\n/**\n * Delete the credentials file.\n */\nexport async function deleteCredentials(): Promise<void> {\n\ttry {\n\t\tawait fs.unlink(CREDENTIALS_FILE);\n\t} catch {\n\t\t// Ignore if file doesn't exist\n\t}\n}\n\n/**\n * Check if credentials exist.\n */\nexport async function hasCredentials(): Promise<boolean> {\n\tconst credentials = await loadCredentials();\n\treturn credentials !== null;\n}\n\n/**\n * Get the API key from credentials.\n * Also checks MOBVIBE_API_KEY env var as override.\n */\nexport async function getApiKey(): Promise<string | undefined> {\n\t// Environment variable takes precedence\n\tif (process.env.MOBVIBE_API_KEY) {\n\t\treturn process.env.MOBVIBE_API_KEY;\n\t}\n\n\tconst credentials = await loadCredentials();\n\treturn credentials?.apiKey;\n}\n\n/** Default production gateway URL */\nconst DEFAULT_GATEWAY_URL = \"https://mobvibe.zeabur.app\";\n\n/**\n * Get the gateway URL with the following priority:\n * 1. MOBVIBE_GATEWAY_URL env var\n * 2. gatewayUrl in credentials file\n * 3. Default production URL\n */\nexport async function getGatewayUrl(): Promise<string> {\n\t// Environment variable takes precedence\n\tif (process.env.MOBVIBE_GATEWAY_URL) {\n\t\treturn process.env.MOBVIBE_GATEWAY_URL;\n\t}\n\n\t// Check credentials file for custom gateway URL\n\tconst credentials = await loadCredentials();\n\tif (credentials?.gatewayUrl) {\n\t\treturn credentials.gatewayUrl;\n\t}\n\n\t// Default to production\n\treturn DEFAULT_GATEWAY_URL;\n}\n","import os from \"node:os\";\nimport path from \"node:path\";\nimport type { AcpBackendId, UserAgentConfig } from \"@mobvibe/shared\";\nimport { getGatewayUrl } from \"./auth/credentials.js\";\nimport { loadUserConfig } from \"./config-loader.js\";\nimport { logger } from \"./lib/logger.js\";\n\nexport type AcpBackendConfig = {\n\tid: AcpBackendId;\n\tlabel: string;\n\tcommand: string;\n\targs: string[];\n\tenvOverrides?: Record<string, string>;\n};\n\nexport type CliConfig = {\n\tgatewayUrl: string;\n\tacpBackends: AcpBackendConfig[];\n\tdefaultAcpBackendId: AcpBackendId;\n\tclientName: string;\n\tclientVersion: string;\n\thomePath: string;\n\tlogPath: string;\n\tpidFile: string;\n\tmachineId: string;\n\thostname: string;\n\tplatform: string;\n\tuserConfigPath?: string;\n\tuserConfigErrors?: string[];\n};\n\n// Default opencode backend\nconst DEFAULT_OPENCODE_BACKEND: AcpBackendConfig = {\n\tid: \"opencode\",\n\tlabel: \"opencode\",\n\tcommand: \"opencode\",\n\targs: [\"acp\"],\n};\n\nconst generateMachineId = (): string => {\n\tconst hostname = os.hostname();\n\tconst platform = os.platform();\n\tconst arch = os.arch();\n\tconst username = os.userInfo().username;\n\treturn `${hostname}-${platform}-${arch}-${username}`;\n};\n\nconst userAgentToBackendConfig = (\n\tagent: UserAgentConfig,\n): AcpBackendConfig => ({\n\tid: agent.id,\n\tlabel: agent.label ?? agent.id,\n\tcommand: agent.command,\n\targs: agent.args ?? [],\n\tenvOverrides: agent.env,\n});\n\nconst mergeBackends = (\n\tdefaultBackend: AcpBackendConfig,\n\tuserAgents: UserAgentConfig[] | undefined,\n): { backends: AcpBackendConfig[]; defaultId: AcpBackendId } => {\n\t// No user agents: use default opencode only\n\tif (!userAgents || userAgents.length === 0) {\n\t\treturn { backends: [defaultBackend], defaultId: defaultBackend.id };\n\t}\n\n\t// Check if user defined opencode (override case)\n\tconst userOpencode = userAgents.find((a) => a.id === \"opencode\");\n\n\tif (userOpencode) {\n\t\t// User overrides opencode - use only user-defined agents\n\t\treturn {\n\t\t\tbackends: userAgents.map(userAgentToBackendConfig),\n\t\t\tdefaultId: userAgents[0].id,\n\t\t};\n\t}\n\n\t// User didn't define opencode - prepend default opencode to user agents\n\treturn {\n\t\tbackends: [defaultBackend, ...userAgents.map(userAgentToBackendConfig)],\n\t\tdefaultId: defaultBackend.id,\n\t};\n};\n\nexport const getCliConfig = async (): Promise<CliConfig> => {\n\tconst env = process.env;\n\tconst homePath = env.MOBVIBE_HOME ?? path.join(os.homedir(), \".mobvibe\");\n\n\t// Load user configuration\n\tconst userConfigResult = await loadUserConfig(homePath);\n\n\t// Log any config errors as warnings\n\tif (userConfigResult.errors.length > 0) {\n\t\tfor (const error of userConfigResult.errors) {\n\t\t\tlogger.warn({ configPath: userConfigResult.path, error }, \"config_error\");\n\t\t}\n\t}\n\n\t// Merge backends\n\tconst { backends, defaultId } = mergeBackends(\n\t\tDEFAULT_OPENCODE_BACKEND,\n\t\tuserConfigResult.config?.agents,\n\t);\n\n\t// Override default if user specified one\n\tconst resolvedDefaultId =\n\t\tuserConfigResult.config?.defaultAgentId &&\n\t\tbackends.some((b) => b.id === userConfigResult.config?.defaultAgentId)\n\t\t\t? userConfigResult.config.defaultAgentId\n\t\t\t: defaultId;\n\n\t// Get gateway URL (env var > credentials file > default production URL)\n\tconst gatewayUrl = await getGatewayUrl();\n\n\treturn {\n\t\tgatewayUrl,\n\t\tacpBackends: backends,\n\t\tdefaultAcpBackendId: resolvedDefaultId,\n\t\tclientName: env.MOBVIBE_ACP_CLIENT_NAME ?? \"mobvibe-cli\",\n\t\tclientVersion: env.MOBVIBE_ACP_CLIENT_VERSION ?? \"0.0.0\",\n\t\thomePath,\n\t\tlogPath: path.join(homePath, \"logs\"),\n\t\tpidFile: path.join(homePath, \"daemon.pid\"),\n\t\tmachineId: env.MOBVIBE_MACHINE_ID ?? generateMachineId(),\n\t\thostname: os.hostname(),\n\t\tplatform: os.platform(),\n\t\tuserConfigPath: userConfigResult.path,\n\t\tuserConfigErrors:\n\t\t\tuserConfigResult.errors.length > 0 ? userConfigResult.errors : undefined,\n\t};\n};\n","import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { MobvibeUserConfig, UserAgentConfig } from \"@mobvibe/shared\";\n\nexport type ConfigLoadResult = {\n\tconfig: MobvibeUserConfig | null;\n\terrors: string[];\n\tpath: string;\n};\n\nconst CONFIG_FILENAME = \".config.json\";\n\nconst validateAgentConfig = (\n\tagent: unknown,\n\tindex: number,\n): { valid: UserAgentConfig | null; errors: string[] } => {\n\tconst errors: string[] = [];\n\tconst prefix = `agents[${index}]`;\n\n\tif (typeof agent !== \"object\" || agent === null) {\n\t\terrors.push(`${prefix}: must be an object`);\n\t\treturn { valid: null, errors };\n\t}\n\n\tconst record = agent as Record<string, unknown>;\n\n\t// Validate id (required)\n\tif (typeof record.id !== \"string\" || record.id.trim().length === 0) {\n\t\terrors.push(`${prefix}.id: must be a non-empty string`);\n\t\treturn { valid: null, errors };\n\t}\n\n\t// Validate command (required)\n\tif (\n\t\ttypeof record.command !== \"string\" ||\n\t\trecord.command.trim().length === 0\n\t) {\n\t\terrors.push(`${prefix}.command: must be a non-empty string`);\n\t\treturn { valid: null, errors };\n\t}\n\n\tconst validated: UserAgentConfig = {\n\t\tid: record.id.trim(),\n\t\tcommand: record.command.trim(),\n\t};\n\n\t// Validate label (optional string)\n\tif (record.label !== undefined) {\n\t\tif (typeof record.label !== \"string\") {\n\t\t\terrors.push(`${prefix}.label: must be a string`);\n\t\t} else if (record.label.trim().length > 0) {\n\t\t\tvalidated.label = record.label.trim();\n\t\t}\n\t}\n\n\t// Validate args (optional string array)\n\tif (record.args !== undefined) {\n\t\tif (!Array.isArray(record.args)) {\n\t\t\terrors.push(`${prefix}.args: must be an array of strings`);\n\t\t} else {\n\t\t\tconst validArgs = record.args.filter((arg): arg is string => {\n\t\t\t\tif (typeof arg !== \"string\") {\n\t\t\t\t\terrors.push(`${prefix}.args: all elements must be strings`);\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t});\n\t\t\tif (validArgs.length > 0) {\n\t\t\t\tvalidated.args = validArgs;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Validate env (optional object with string values)\n\tif (record.env !== undefined) {\n\t\tif (typeof record.env !== \"object\" || record.env === null) {\n\t\t\terrors.push(`${prefix}.env: must be an object`);\n\t\t} else {\n\t\t\tconst envRecord = record.env as Record<string, unknown>;\n\t\t\tconst validEnv: Record<string, string> = {};\n\t\t\tlet hasEnv = false;\n\t\t\tfor (const [key, value] of Object.entries(envRecord)) {\n\t\t\t\tif (typeof value !== \"string\") {\n\t\t\t\t\terrors.push(`${prefix}.env.${key}: must be a string`);\n\t\t\t\t} else {\n\t\t\t\t\tvalidEnv[key] = value;\n\t\t\t\t\thasEnv = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (hasEnv) {\n\t\t\t\tvalidated.env = validEnv;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Return null if there were any errors after id/command validation\n\tif (errors.length > 0) {\n\t\treturn { valid: null, errors };\n\t}\n\n\treturn { valid: validated, errors: [] };\n};\n\nconst validateUserConfig = (\n\tdata: unknown,\n): { config: MobvibeUserConfig | null; errors: string[] } => {\n\tconst errors: string[] = [];\n\n\tif (typeof data !== \"object\" || data === null) {\n\t\terrors.push(\"config: must be an object\");\n\t\treturn { config: null, errors };\n\t}\n\n\tconst record = data as Record<string, unknown>;\n\tconst config: MobvibeUserConfig = {};\n\n\t// Validate agents array\n\tif (record.agents !== undefined) {\n\t\tif (!Array.isArray(record.agents)) {\n\t\t\terrors.push(\"agents: must be an array\");\n\t\t} else {\n\t\t\tconst validAgents: UserAgentConfig[] = [];\n\t\t\tconst seenIds = new Set<string>();\n\n\t\t\tfor (let i = 0; i < record.agents.length; i++) {\n\t\t\t\tconst result = validateAgentConfig(record.agents[i], i);\n\t\t\t\terrors.push(...result.errors);\n\n\t\t\t\tif (result.valid) {\n\t\t\t\t\tif (seenIds.has(result.valid.id)) {\n\t\t\t\t\t\terrors.push(`agents[${i}].id: duplicate id \"${result.valid.id}\"`);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tseenIds.add(result.valid.id);\n\t\t\t\t\t\tvalidAgents.push(result.valid);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (validAgents.length > 0) {\n\t\t\t\tconfig.agents = validAgents;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Validate defaultAgentId\n\tif (record.defaultAgentId !== undefined) {\n\t\tif (typeof record.defaultAgentId !== \"string\") {\n\t\t\terrors.push(\"defaultAgentId: must be a string\");\n\t\t} else if (record.defaultAgentId.trim().length > 0) {\n\t\t\tconfig.defaultAgentId = record.defaultAgentId.trim();\n\t\t}\n\t}\n\n\tif (errors.length > 0) {\n\t\treturn { config: null, errors };\n\t}\n\n\treturn { config, errors: [] };\n};\n\nexport const loadUserConfig = async (\n\thomePath: string,\n): Promise<ConfigLoadResult> => {\n\tconst configPath = path.join(homePath, CONFIG_FILENAME);\n\tconsole.log(`[config] Loading config from: ${configPath}`);\n\n\ttry {\n\t\tconst content = await fs.readFile(configPath, \"utf-8\");\n\t\tlet parsed: unknown;\n\n\t\ttry {\n\t\t\tparsed = JSON.parse(content);\n\t\t} catch {\n\t\t\tconsole.log(`[config] Invalid JSON in config file: ${configPath}`);\n\t\t\treturn {\n\t\t\t\tconfig: null,\n\t\t\t\terrors: [\"Invalid JSON in config file\"],\n\t\t\t\tpath: configPath,\n\t\t\t};\n\t\t}\n\n\t\tconst { config, errors } = validateUserConfig(parsed);\n\n\t\tif (errors.length > 0) {\n\t\t\tconsole.log(\"[config] Validation errors:\", errors);\n\t\t}\n\n\t\tif (config) {\n\t\t\tconsole.log(\"[config] Loaded config:\", JSON.stringify(config, null, 2));\n\t\t}\n\n\t\treturn { config, errors, path: configPath };\n\t} catch (error) {\n\t\t// File not found is not an error, just return null config\n\t\tif (error instanceof Error && \"code\" in error && error.code === \"ENOENT\") {\n\t\t\tconsole.log(`[config] No config file found at: ${configPath}`);\n\t\t\treturn { config: null, errors: [], path: configPath };\n\t\t}\n\n\t\t// Other errors (permissions, etc.)\n\t\tconst message =\n\t\t\terror instanceof Error ? error.message : \"Unknown error reading config\";\n\t\tconsole.log(`[config] Error reading config: ${message}`);\n\t\treturn { config: null, errors: [message], path: configPath };\n\t}\n};\n","import { spawn } from \"node:child_process\";\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { SessionManager } from \"../acp/session-manager.js\";\nimport { getApiKey } from \"../auth/credentials.js\";\nimport type { CliConfig } from \"../config.js\";\nimport { logger } from \"../lib/logger.js\";\nimport { SocketClient } from \"./socket-client.js\";\n\ntype DaemonStatus = {\n\trunning: boolean;\n\tpid?: number;\n\tconnected?: boolean;\n\tsessionCount?: number;\n};\n\nexport class DaemonManager {\n\tconstructor(private readonly config: CliConfig) {}\n\n\tasync ensureHomeDirectory(): Promise<void> {\n\t\tawait fs.mkdir(this.config.homePath, { recursive: true });\n\t\tawait fs.mkdir(this.config.logPath, { recursive: true });\n\t}\n\n\tasync getPid(): Promise<number | null> {\n\t\ttry {\n\t\t\tconst content = await fs.readFile(this.config.pidFile, \"utf8\");\n\t\t\tconst pid = Number.parseInt(content.trim(), 10);\n\t\t\tif (Number.isNaN(pid)) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\t// Check if process is running\n\t\t\ttry {\n\t\t\t\tprocess.kill(pid, 0);\n\t\t\t\treturn pid;\n\t\t\t} catch {\n\t\t\t\t// Process not running, clean up stale PID file\n\t\t\t\tawait this.removePidFile();\n\t\t\t\treturn null;\n\t\t\t}\n\t\t} catch {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tasync writePidFile(pid: number): Promise<void> {\n\t\tawait fs.writeFile(this.config.pidFile, String(pid), \"utf8\");\n\t}\n\n\tasync removePidFile(): Promise<void> {\n\t\ttry {\n\t\t\tawait fs.unlink(this.config.pidFile);\n\t\t} catch {\n\t\t\t// Ignore errors\n\t\t}\n\t}\n\n\tasync status(): Promise<DaemonStatus> {\n\t\tconst pid = await this.getPid();\n\t\tif (!pid) {\n\t\t\treturn { running: false };\n\t\t}\n\t\treturn { running: true, pid };\n\t}\n\n\tasync start(options?: { foreground?: boolean }): Promise<void> {\n\t\tconst existingPid = await this.getPid();\n\t\tif (existingPid) {\n\t\t\tlogger.info({ pid: existingPid }, \"daemon_already_running\");\n\t\t\treturn;\n\t\t}\n\n\t\tawait this.ensureHomeDirectory();\n\n\t\tif (options?.foreground) {\n\t\t\tawait this.runForeground();\n\t\t} else {\n\t\t\tawait this.spawnBackground();\n\t\t}\n\t}\n\n\tasync stop(): Promise<void> {\n\t\tconst pid = await this.getPid();\n\t\tif (!pid) {\n\t\t\tlogger.info(\"daemon_not_running\");\n\t\t\treturn;\n\t\t}\n\n\t\t// Check if process actually exists\n\t\ttry {\n\t\t\tprocess.kill(pid, 0);\n\t\t} catch {\n\t\t\tlogger.warn(\"daemon_pid_missing_cleanup\");\n\t\t\tawait this.removePidFile();\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tlogger.info({ pid }, \"daemon_stop_sigterm\");\n\t\t\tprocess.kill(pid, \"SIGTERM\");\n\n\t\t\t// Wait for process to exit (up to 5 seconds)\n\t\t\tconst startTime = Date.now();\n\t\t\tconst timeout = 5000;\n\n\t\t\twhile (Date.now() - startTime < timeout) {\n\t\t\t\tawait new Promise((resolve) => setTimeout(resolve, 100));\n\t\t\t\ttry {\n\t\t\t\t\tprocess.kill(pid, 0);\n\t\t\t\t\t// Process still running\n\t\t\t\t} catch {\n\t\t\t\t\t// Process exited\n\t\t\t\t\tlogger.info({ pid }, \"daemon_stopped_gracefully\");\n\t\t\t\t\tawait this.removePidFile();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Process didn't exit gracefully, force kill\n\t\t\tlogger.warn({ pid }, \"daemon_force_kill_start\");\n\t\t\ttry {\n\t\t\t\tprocess.kill(pid, \"SIGKILL\");\n\t\t\t\t// Wait a bit for SIGKILL to take effect\n\t\t\t\tawait new Promise((resolve) => setTimeout(resolve, 500));\n\t\t\t\tlogger.warn({ pid }, \"daemon_force_kill_complete\");\n\t\t\t} catch {\n\t\t\t\t// Already dead\n\t\t\t\tlogger.info({ pid }, \"daemon_already_stopped\");\n\t\t\t}\n\t\t\tawait this.removePidFile();\n\t\t} catch (error) {\n\t\t\tlogger.error({ err: error }, \"daemon_stop_error\");\n\t\t\tawait this.removePidFile();\n\t\t}\n\t}\n\n\tprivate async spawnBackground(): Promise<void> {\n\t\tconst logFile = path.join(\n\t\t\tthis.config.logPath,\n\t\t\t`${new Date().toISOString().replace(/[:.]/g, \"-\")}-daemon.log`,\n\t\t);\n\n\t\t// Filter out --foreground if already present, then add it\n\t\tconst args = process.argv\n\t\t\t.slice(1)\n\t\t\t.filter((arg) => arg !== \"--foreground\" && arg !== \"-f\");\n\t\targs.push(\"--foreground\");\n\n\t\tconst child = spawn(process.argv[0], args, {\n\t\t\tdetached: true,\n\t\t\tstdio: [\"ignore\", \"pipe\", \"pipe\"],\n\t\t\tenv: {\n\t\t\t\t...process.env,\n\t\t\t\tMOBVIBE_GATEWAY_URL: this.config.gatewayUrl,\n\t\t\t},\n\t\t});\n\n\t\tif (!child.pid) {\n\t\t\tlogger.error(\"daemon_spawn_failed\");\n\t\t\tthrow new Error(\"Failed to spawn daemon process\");\n\t\t}\n\n\t\t// Create log file stream before writing PID\n\t\tconst logStream = await fs.open(logFile, \"a\");\n\t\tconst fileHandle = logStream;\n\n\t\tchild.stdout?.on(\"data\", (data: Buffer) => {\n\t\t\tfileHandle.write(`[stdout] ${data.toString()}`).catch(() => {});\n\t\t});\n\n\t\tchild.stderr?.on(\"data\", (data: Buffer) => {\n\t\t\tfileHandle.write(`[stderr] ${data.toString()}`).catch(() => {});\n\t\t});\n\n\t\t// Handle child exit to clean up\n\t\tchild.on(\"exit\", (code, signal) => {\n\t\t\tfileHandle\n\t\t\t\t.write(`[exit] Process exited with code ${code}, signal ${signal}\\n`)\n\t\t\t\t.catch(() => {});\n\t\t\tfileHandle.close().catch(() => {});\n\t\t});\n\n\t\t// Detach from parent\n\t\t// Note: The child process writes its own PID file in runForeground()\n\t\tchild.unref();\n\n\t\tlogger.info({ pid: child.pid }, \"daemon_started\");\n\t\tconsole.log(`Logs: ${logFile}`);\n\t\tlogger.info({ logFile }, \"daemon_log_path\");\n\t}\n\n\tasync runForeground(): Promise<void> {\n\t\tconst pid = process.pid;\n\t\tawait this.writePidFile(pid);\n\n\t\tlogger.info({ pid }, \"daemon_starting\");\n\t\tlogger.info({ gatewayUrl: this.config.gatewayUrl }, \"daemon_gateway_url\");\n\t\tlogger.info({ machineId: this.config.machineId }, \"daemon_machine_id\");\n\n\t\t// Load API key for authentication\n\t\tconst apiKey = await getApiKey();\n\t\tif (!apiKey) {\n\t\t\tlogger.error(\"daemon_api_key_missing\");\n\t\t\tconsole.error(\n\t\t\t\t`[mobvibe-cli] No API key found. Run 'mobvibe login' to authenticate.`,\n\t\t\t);\n\t\t\tlogger.warn(\"daemon_exit_missing_api_key\");\n\t\t\tprocess.exit(1);\n\t\t}\n\t\tlogger.info(\"daemon_api_key_loaded\");\n\n\t\tconst sessionManager = new SessionManager(this.config);\n\t\tconst socketClient = new SocketClient({\n\t\t\tconfig: this.config,\n\t\t\tsessionManager,\n\t\t\tapiKey,\n\t\t});\n\n\t\tlet shuttingDown = false;\n\n\t\tconst shutdown = async (signal: string) => {\n\t\t\tif (shuttingDown) {\n\t\t\t\tlogger.warn({ signal }, \"daemon_shutdown_already_running\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tshuttingDown = true;\n\n\t\t\tlogger.info({ signal }, \"daemon_shutdown_start\");\n\n\t\t\ttry {\n\t\t\t\tsocketClient.disconnect();\n\t\t\t\tawait sessionManager.closeAll();\n\t\t\t\tawait this.removePidFile();\n\t\t\t\tlogger.info({ signal }, \"daemon_shutdown_complete\");\n\t\t\t} catch (error) {\n\t\t\t\tlogger.error({ err: error, signal }, \"daemon_shutdown_error\");\n\t\t\t}\n\t\t};\n\n\t\tprocess.on(\"SIGINT\", () => {\n\t\t\tshutdown(\"SIGINT\").catch((error) => {\n\t\t\t\tlogger.error({ err: error }, \"daemon_shutdown_sigint_error\");\n\t\t\t});\n\t\t});\n\t\tprocess.on(\"SIGTERM\", () => {\n\t\t\tshutdown(\"SIGTERM\").catch((error) => {\n\t\t\t\tlogger.error({ err: error }, \"daemon_shutdown_sigterm_error\");\n\t\t\t});\n\t\t});\n\n\t\tsocketClient.connect();\n\n\t\t// Keep process alive\n\t\tawait new Promise(() => {});\n\t}\n\n\tasync logs(options?: { follow?: boolean; lines?: number }): Promise<void> {\n\t\tconst files = await fs.readdir(this.config.logPath);\n\t\tconst logFiles = files\n\t\t\t.filter((f) => f.endsWith(\"-daemon.log\"))\n\t\t\t.sort()\n\t\t\t.reverse();\n\n\t\tif (logFiles.length === 0) {\n\t\t\tlogger.warn(\"daemon_logs_empty\");\n\t\t\tconsole.log(\"No log files found\");\n\t\t\treturn;\n\t\t}\n\n\t\tconst latestLog = path.join(this.config.logPath, logFiles[0]);\n\t\tlogger.info({ logFile: latestLog }, \"daemon_logs_latest\");\n\t\tconsole.log(`Log file: ${latestLog}\\n`);\n\n\t\tif (options?.follow) {\n\t\t\t// Use tail -f\n\t\t\tconst tail = spawn(\"tail\", [\"-f\", latestLog], {\n\t\t\t\tstdio: \"inherit\",\n\t\t\t});\n\t\t\tawait new Promise<void>((resolve) => {\n\t\t\t\ttail.on(\"close\", () => resolve());\n\t\t\t});\n\t\t} else {\n\t\t\tconst content = await fs.readFile(latestLog, \"utf8\");\n\t\t\tconst lines = content.split(\"\\n\");\n\t\t\tconst count = options?.lines ?? 50;\n\t\t\tconsole.log(lines.slice(-count).join(\"\\n\"));\n\t\t}\n\t}\n}\n","import { randomUUID } from \"node:crypto\";\nimport { EventEmitter } from \"node:events\";\nimport fs from \"node:fs/promises\";\nimport type {\n\tAvailableCommand,\n\tRequestPermissionRequest,\n\tRequestPermissionResponse,\n\tSessionModelState,\n\tSessionModeState,\n\tSessionNotification,\n} from \"@agentclientprotocol/sdk\";\nimport {\n\ttype AcpSessionInfo,\n\tAppError,\n\tcreateErrorDetail,\n\ttype DiscoverSessionsRpcResult,\n\ttype ErrorDetail,\n\ttype PermissionDecisionPayload,\n\ttype PermissionRequestPayload,\n\ttype SessionSummary,\n\ttype SessionsChangedPayload,\n\ttype TerminalOutputEvent,\n} from \"@mobvibe/shared\";\nimport type { AcpBackendConfig, CliConfig } from \"../config.js\";\nimport { logger } from \"../lib/logger.js\";\nimport { AcpConnection } from \"./acp-connection.js\";\n\ntype SessionRecord = {\n\tsessionId: string;\n\ttitle: string;\n\tbackendId: string;\n\tbackendLabel: string;\n\tconnection: AcpConnection;\n\tcreatedAt: Date;\n\tupdatedAt: Date;\n\tcwd?: string;\n\tagentName?: string;\n\tmodelId?: string;\n\tmodelName?: string;\n\tmodeId?: string;\n\tmodeName?: string;\n\tavailableModes?: Array<{ id: string; name: string }>;\n\tavailableModels?: Array<{\n\t\tid: string;\n\t\tname: string;\n\t\tdescription?: string | null;\n\t}>;\n\tavailableCommands?: AvailableCommand[];\n\tunsubscribe?: () => void;\n\tunsubscribeTerminal?: () => void;\n\tisAttached?: boolean;\n\tattachedAt?: Date;\n};\n\ntype PermissionRequestRecord = {\n\tsessionId: string;\n\trequestId: string;\n\tparams: RequestPermissionRequest;\n\tpromise: Promise<RequestPermissionResponse>;\n\tresolve: (response: RequestPermissionResponse) => void;\n};\n\nconst buildPermissionKey = (sessionId: string, requestId: string) =>\n\t`${sessionId}:${requestId}`;\n\nconst resolveModelState = (models?: SessionModelState | null) => {\n\tif (!models) {\n\t\treturn {\n\t\t\tmodelId: undefined,\n\t\t\tmodelName: undefined,\n\t\t\tavailableModels: undefined,\n\t\t};\n\t}\n\tconst availableModels = models.availableModels?.map((model) => ({\n\t\tid: model.modelId,\n\t\tname: model.name,\n\t\tdescription: model.description ?? undefined,\n\t}));\n\tconst modelId = models.currentModelId ?? undefined;\n\tconst modelName = availableModels?.find(\n\t\t(model) => model.id === modelId,\n\t)?.name;\n\treturn { modelId, modelName, availableModels };\n};\n\nconst resolveModeState = (modes?: SessionModeState | null) => {\n\tif (!modes) {\n\t\treturn {\n\t\t\tmodeId: undefined,\n\t\t\tmodeName: undefined,\n\t\t\tavailableModes: undefined,\n\t\t};\n\t}\n\tconst modeId = modes.currentModeId ?? undefined;\n\tconst modeName = modes.availableModes?.find(\n\t\t(mode) => mode.id === modeId,\n\t)?.name;\n\treturn {\n\t\tmodeId,\n\t\tmodeName,\n\t\tavailableModes: modes.availableModes?.map((mode) => ({\n\t\t\tid: mode.id,\n\t\t\tname: mode.name,\n\t\t})),\n\t};\n};\n\nconst createCapabilityNotSupportedError = (message: string) =>\n\tnew AppError(\n\t\tcreateErrorDetail({\n\t\t\tcode: \"CAPABILITY_NOT_SUPPORTED\",\n\t\t\tmessage,\n\t\t\tretryable: false,\n\t\t\tscope: \"session\",\n\t\t}),\n\t\t409,\n\t);\n\nconst isValidWorkspacePath = async (cwd: string): Promise<boolean> => {\n\ttry {\n\t\tconst stats = await fs.stat(cwd);\n\t\treturn stats.isDirectory();\n\t} catch {\n\t\treturn false;\n\t}\n};\n\nexport class SessionManager {\n\tprivate sessions = new Map<string, SessionRecord>();\n\tprivate discoveredSessions = new Map<string, AcpSessionInfo>();\n\tprivate backendById: Map<string, AcpBackendConfig>;\n\tprivate defaultBackendId: string;\n\tprivate permissionRequests = new Map<string, PermissionRequestRecord>();\n\tprivate readonly sessionUpdateEmitter = new EventEmitter();\n\tprivate readonly sessionErrorEmitter = new EventEmitter();\n\tprivate readonly permissionRequestEmitter = new EventEmitter();\n\tprivate readonly permissionResultEmitter = new EventEmitter();\n\tprivate readonly terminalOutputEmitter = new EventEmitter();\n\tprivate readonly sessionsChangedEmitter = new EventEmitter();\n\tprivate readonly sessionAttachedEmitter = new EventEmitter();\n\tprivate readonly sessionDetachedEmitter = new EventEmitter();\n\n\tconstructor(private readonly config: CliConfig) {\n\t\tthis.backendById = new Map(\n\t\t\tconfig.acpBackends.map((backend) => [backend.id, backend]),\n\t\t);\n\t\tthis.defaultBackendId = config.defaultAcpBackendId;\n\t}\n\n\tlistSessions(): SessionSummary[] {\n\t\treturn Array.from(this.sessions.values()).map((record) =>\n\t\t\tthis.buildSummary(record),\n\t\t);\n\t}\n\n\tgetSession(sessionId: string): SessionRecord | undefined {\n\t\treturn this.sessions.get(sessionId);\n\t}\n\n\tonSessionUpdate(listener: (notification: SessionNotification) => void) {\n\t\tthis.sessionUpdateEmitter.on(\"update\", listener);\n\t\treturn () => {\n\t\t\tthis.sessionUpdateEmitter.off(\"update\", listener);\n\t\t};\n\t}\n\n\tonSessionError(\n\t\tlistener: (payload: { sessionId: string; error: ErrorDetail }) => void,\n\t) {\n\t\tthis.sessionErrorEmitter.on(\"error\", listener);\n\t\treturn () => {\n\t\t\tthis.sessionErrorEmitter.off(\"error\", listener);\n\t\t};\n\t}\n\n\tonPermissionRequest(listener: (payload: PermissionRequestPayload) => void) {\n\t\tthis.permissionRequestEmitter.on(\"request\", listener);\n\t\treturn () => {\n\t\t\tthis.permissionRequestEmitter.off(\"request\", listener);\n\t\t};\n\t}\n\n\tonPermissionResult(listener: (payload: PermissionDecisionPayload) => void) {\n\t\tthis.permissionResultEmitter.on(\"result\", listener);\n\t\treturn () => {\n\t\t\tthis.permissionResultEmitter.off(\"result\", listener);\n\t\t};\n\t}\n\n\tonTerminalOutput(listener: (event: TerminalOutputEvent) => void) {\n\t\tthis.terminalOutputEmitter.on(\"output\", listener);\n\t\treturn () => {\n\t\t\tthis.terminalOutputEmitter.off(\"output\", listener);\n\t\t};\n\t}\n\n\tonSessionsChanged(listener: (payload: SessionsChangedPayload) => void) {\n\t\tthis.sessionsChangedEmitter.on(\"changed\", listener);\n\t\treturn () => {\n\t\t\tthis.sessionsChangedEmitter.off(\"changed\", listener);\n\t\t};\n\t}\n\n\tonSessionAttached(\n\t\tlistener: (payload: {\n\t\t\tsessionId: string;\n\t\t\tmachineId: string;\n\t\t\tattachedAt: string;\n\t\t}) => void,\n\t) {\n\t\tthis.sessionAttachedEmitter.on(\"attached\", listener);\n\t\treturn () => {\n\t\t\tthis.sessionAttachedEmitter.off(\"attached\", listener);\n\t\t};\n\t}\n\n\tonSessionDetached(\n\t\tlistener: (payload: {\n\t\t\tsessionId: string;\n\t\t\tmachineId: string;\n\t\t\tdetachedAt: string;\n\t\t\treason:\n\t\t\t\t| \"agent_exit\"\n\t\t\t\t| \"cli_disconnect\"\n\t\t\t\t| \"gateway_disconnect\"\n\t\t\t\t| \"unknown\";\n\t\t}) => void,\n\t) {\n\t\tthis.sessionDetachedEmitter.on(\"detached\", listener);\n\t\treturn () => {\n\t\t\tthis.sessionDetachedEmitter.off(\"detached\", listener);\n\t\t};\n\t}\n\n\tprivate emitSessionsChanged(payload: SessionsChangedPayload) {\n\t\tthis.sessionsChangedEmitter.emit(\"changed\", payload);\n\t}\n\n\tprivate emitSessionAttached(sessionId: string) {\n\t\tconst record = this.sessions.get(sessionId);\n\t\tif (!record) {\n\t\t\treturn;\n\t\t}\n\t\tif (record.isAttached) {\n\t\t\treturn;\n\t\t}\n\t\tconst attachedAt = new Date();\n\t\trecord.isAttached = true;\n\t\trecord.attachedAt = attachedAt;\n\t\tthis.sessionAttachedEmitter.emit(\"attached\", {\n\t\t\tsessionId,\n\t\t\tmachineId: this.config.machineId,\n\t\t\tattachedAt: attachedAt.toISOString(),\n\t\t});\n\t}\n\n\tprivate emitSessionDetached(\n\t\tsessionId: string,\n\t\treason: \"agent_exit\" | \"cli_disconnect\" | \"gateway_disconnect\" | \"unknown\",\n\t) {\n\t\tconst record = this.sessions.get(sessionId);\n\t\tif (!record) {\n\t\t\treturn;\n\t\t}\n\t\tif (!record.isAttached) {\n\t\t\treturn;\n\t\t}\n\t\trecord.isAttached = false;\n\t\tthis.sessionDetachedEmitter.emit(\"detached\", {\n\t\t\tsessionId,\n\t\t\tmachineId: this.config.machineId,\n\t\t\tdetachedAt: new Date().toISOString(),\n\t\t\treason,\n\t\t});\n\t}\n\n\tlistPendingPermissions(sessionId: string): PermissionRequestPayload[] {\n\t\treturn Array.from(this.permissionRequests.values())\n\t\t\t.filter((record) => record.sessionId === sessionId)\n\t\t\t.map((record) => this.buildPermissionRequestPayload(record));\n\t}\n\n\tresolvePermissionRequest(\n\t\tsessionId: string,\n\t\trequestId: string,\n\t\toutcome: RequestPermissionResponse[\"outcome\"],\n\t): PermissionDecisionPayload {\n\t\tconst key = buildPermissionKey(sessionId, requestId);\n\t\tconst record = this.permissionRequests.get(key);\n\t\tif (!record) {\n\t\t\tthrow new AppError(\n\t\t\t\tcreateErrorDetail({\n\t\t\t\t\tcode: \"REQUEST_VALIDATION_FAILED\",\n\t\t\t\t\tmessage: \"Permission request not found\",\n\t\t\t\t\tretryable: false,\n\t\t\t\t\tscope: \"request\",\n\t\t\t\t}),\n\t\t\t\t404,\n\t\t\t);\n\t\t}\n\t\tconst response: RequestPermissionResponse = { outcome };\n\t\trecord.resolve(response);\n\t\tthis.permissionRequests.delete(key);\n\t\tconst payload: PermissionDecisionPayload = {\n\t\t\tsessionId,\n\t\t\trequestId,\n\t\t\toutcome,\n\t\t};\n\t\tthis.permissionResultEmitter.emit(\"result\", payload);\n\t\treturn payload;\n\t}\n\n\tprivate resolveBackend(backendId?: string) {\n\t\tconst normalized = backendId?.trim();\n\t\tconst resolvedId =\n\t\t\tnormalized && normalized.length > 0 ? normalized : this.defaultBackendId;\n\t\tconst backend = this.backendById.get(resolvedId);\n\t\tif (!backend) {\n\t\t\tthrow new AppError(\n\t\t\t\tcreateErrorDetail({\n\t\t\t\t\tcode: \"REQUEST_VALIDATION_FAILED\",\n\t\t\t\t\tmessage: \"Invalid backend ID\",\n\t\t\t\t\tretryable: false,\n\t\t\t\t\tscope: \"request\",\n\t\t\t\t}),\n\t\t\t\t400,\n\t\t\t);\n\t\t}\n\t\treturn backend;\n\t}\n\n\tasync createSession(options?: {\n\t\tcwd?: string;\n\t\ttitle?: string;\n\t\tbackendId?: string;\n\t}): Promise<SessionSummary> {\n\t\tconst backend = this.resolveBackend(options?.backendId);\n\t\tconst connection = new AcpConnection({\n\t\t\tbackend,\n\t\t\tclient: {\n\t\t\t\tname: this.config.clientName,\n\t\t\t\tversion: this.config.clientVersion,\n\t\t\t},\n\t\t});\n\t\ttry {\n\t\t\tawait connection.connect();\n\t\t\tconst session = await connection.createSession({ cwd: options?.cwd });\n\t\t\tconnection.setPermissionHandler((params) =>\n\t\t\t\tthis.handlePermissionRequest(session.sessionId, params),\n\t\t\t);\n\t\t\tconst now = new Date();\n\t\t\tconst agentInfo = connection.getAgentInfo();\n\t\t\tconst { modelId, modelName, availableModels } = resolveModelState(\n\t\t\t\tsession.models,\n\t\t\t);\n\t\t\tconst { modeId, modeName, availableModes } = resolveModeState(\n\t\t\t\tsession.modes,\n\t\t\t);\n\t\t\tconst record: SessionRecord = {\n\t\t\t\tsessionId: session.sessionId,\n\t\t\t\ttitle: options?.title ?? `Session ${this.sessions.size + 1}`,\n\t\t\t\tbackendId: backend.id,\n\t\t\t\tbackendLabel: backend.label,\n\t\t\t\tconnection,\n\t\t\t\tcreatedAt: now,\n\t\t\t\tupdatedAt: now,\n\t\t\t\tcwd: options?.cwd,\n\t\t\t\tagentName: agentInfo?.title ?? agentInfo?.name,\n\t\t\t\tmodelId,\n\t\t\t\tmodelName,\n\t\t\t\tmodeId,\n\t\t\t\tmodeName,\n\t\t\t\tavailableModes,\n\t\t\t\tavailableModels,\n\t\t\t\tavailableCommands: undefined,\n\t\t\t};\n\t\t\trecord.unsubscribe = connection.onSessionUpdate(\n\t\t\t\t(notification: SessionNotification) => {\n\t\t\t\t\trecord.updatedAt = new Date();\n\t\t\t\t\tthis.sessionUpdateEmitter.emit(\"update\", notification);\n\t\t\t\t\tthis.applySessionUpdateToRecord(record, notification);\n\t\t\t\t},\n\t\t\t);\n\t\t\trecord.unsubscribeTerminal = connection.onTerminalOutput((event) => {\n\t\t\t\tthis.terminalOutputEmitter.emit(\"output\", event);\n\t\t\t});\n\t\t\tconnection.onStatusChange((status) => {\n\t\t\t\tif (status.error) {\n\t\t\t\t\tthis.sessionErrorEmitter.emit(\"error\", {\n\t\t\t\t\t\tsessionId: session.sessionId,\n\t\t\t\t\t\terror: status.error,\n\t\t\t\t\t});\n\t\t\t\t\tthis.emitSessionDetached(session.sessionId, \"agent_exit\");\n\t\t\t\t}\n\t\t\t});\n\t\t\tthis.sessions.set(session.sessionId, record);\n\t\t\tconst summary = this.buildSummary(record);\n\t\t\tthis.emitSessionsChanged({\n\t\t\t\tadded: [summary],\n\t\t\t\tupdated: [],\n\t\t\t\tremoved: [],\n\t\t\t});\n\t\t\tthis.emitSessionAttached(session.sessionId);\n\t\t\treturn summary;\n\t\t} catch (error) {\n\t\t\tconst status = connection.getStatus();\n\t\t\tawait connection.disconnect();\n\t\t\tif (status.error) {\n\t\t\t\tthrow new AppError(status.error, 500);\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tprivate buildPermissionRequestPayload(\n\t\trecord: PermissionRequestRecord,\n\t): PermissionRequestPayload {\n\t\tconst toolCall = record.params.toolCall;\n\t\treturn {\n\t\t\tsessionId: record.sessionId,\n\t\t\trequestId: record.requestId,\n\t\t\toptions: record.params.options.map((option) => ({\n\t\t\t\toptionId: option.optionId,\n\t\t\t\t// SDK uses 'name', our shared type uses 'label'\n\t\t\t\tlabel: option.name,\n\t\t\t\tdescription: (option._meta?.description as string) ?? null,\n\t\t\t})),\n\t\t\ttoolCall: {\n\t\t\t\ttoolCallId: toolCall.toolCallId,\n\t\t\t\tname: (toolCall._meta?.name as string) ?? null,\n\t\t\t\ttitle: toolCall.title,\n\t\t\t\tcommand: (toolCall._meta?.command as string) ?? null,\n\t\t\t\targs: (toolCall._meta?.args as string[]) ?? null,\n\t\t\t},\n\t\t};\n\t}\n\n\tprivate handlePermissionRequest(\n\t\tsessionId: string,\n\t\tparams: RequestPermissionRequest,\n\t): Promise<RequestPermissionResponse> {\n\t\tconst requestId = params.toolCall?.toolCallId ?? randomUUID();\n\t\tconst key = buildPermissionKey(sessionId, requestId);\n\t\tconst existing = this.permissionRequests.get(key);\n\t\tif (existing) {\n\t\t\treturn existing.promise;\n\t\t}\n\t\tlet resolver: (response: RequestPermissionResponse) => void = () => {};\n\t\tconst promise = new Promise<RequestPermissionResponse>((resolve) => {\n\t\t\tresolver = resolve;\n\t\t});\n\t\tconst record: PermissionRequestRecord = {\n\t\t\tsessionId,\n\t\t\trequestId,\n\t\t\tparams,\n\t\t\tpromise,\n\t\t\tresolve: resolver,\n\t\t};\n\t\tthis.permissionRequests.set(key, record);\n\t\tthis.permissionRequestEmitter.emit(\n\t\t\t\"request\",\n\t\t\tthis.buildPermissionRequestPayload(record),\n\t\t);\n\t\treturn promise;\n\t}\n\n\tprivate cancelPermissionRequests(sessionId: string) {\n\t\tconst cancelledOutcome: RequestPermissionResponse[\"outcome\"] = {\n\t\t\toutcome: \"cancelled\",\n\t\t};\n\t\tfor (const [key, record] of this.permissionRequests.entries()) {\n\t\t\tif (record.sessionId !== sessionId) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\trecord.resolve({ outcome: cancelledOutcome });\n\t\t\tthis.permissionRequests.delete(key);\n\t\t\tthis.permissionResultEmitter.emit(\"result\", {\n\t\t\t\tsessionId,\n\t\t\t\trequestId: record.requestId,\n\t\t\t\toutcome: cancelledOutcome,\n\t\t\t});\n\t\t}\n\t}\n\n\tupdateTitle(sessionId: string, title: string): SessionSummary {\n\t\tconst record = this.sessions.get(sessionId);\n\t\tif (!record) {\n\t\t\tthrow new AppError(\n\t\t\t\tcreateErrorDetail({\n\t\t\t\t\tcode: \"SESSION_NOT_FOUND\",\n\t\t\t\t\tmessage: \"Session not found\",\n\t\t\t\t\tretryable: false,\n\t\t\t\t\tscope: \"session\",\n\t\t\t\t}),\n\t\t\t\t404,\n\t\t\t);\n\t\t}\n\t\trecord.title = title;\n\t\trecord.updatedAt = new Date();\n\t\tconst summary = this.buildSummary(record);\n\t\tthis.emitSessionsChanged({\n\t\t\tadded: [],\n\t\t\tupdated: [summary],\n\t\t\tremoved: [],\n\t\t});\n\t\treturn summary;\n\t}\n\n\ttouchSession(sessionId: string) {\n\t\tconst record = this.sessions.get(sessionId);\n\t\tif (!record) {\n\t\t\treturn;\n\t\t}\n\t\trecord.updatedAt = new Date();\n\t}\n\n\tasync setSessionMode(\n\t\tsessionId: string,\n\t\tmodeId: string,\n\t): Promise<SessionSummary> {\n\t\tconst record = this.sessions.get(sessionId);\n\t\tif (!record) {\n\t\t\tthrow new AppError(\n\t\t\t\tcreateErrorDetail({\n\t\t\t\t\tcode: \"SESSION_NOT_FOUND\",\n\t\t\t\t\tmessage: \"Session not found\",\n\t\t\t\t\tretryable: false,\n\t\t\t\t\tscope: \"session\",\n\t\t\t\t}),\n\t\t\t\t404,\n\t\t\t);\n\t\t}\n\t\tif (!record.availableModes || record.availableModes.length === 0) {\n\t\t\tthrow createCapabilityNotSupportedError(\n\t\t\t\t\"Current agent does not support mode switching\",\n\t\t\t);\n\t\t}\n\t\tconst selected = record.availableModes.find((mode) => mode.id === modeId);\n\t\tif (!selected) {\n\t\t\tthrow new AppError(\n\t\t\t\tcreateErrorDetail({\n\t\t\t\t\tcode: \"REQUEST_VALIDATION_FAILED\",\n\t\t\t\t\tmessage: \"Invalid mode ID\",\n\t\t\t\t\tretryable: false,\n\t\t\t\t\tscope: \"request\",\n\t\t\t\t}),\n\t\t\t\t400,\n\t\t\t);\n\t\t}\n\t\tawait record.connection.setSessionMode(sessionId, modeId);\n\t\trecord.modeId = selected.id;\n\t\trecord.modeName = selected.name;\n\t\trecord.updatedAt = new Date();\n\t\tconst summary = this.buildSummary(record);\n\t\tthis.emitSessionsChanged({\n\t\t\tadded: [],\n\t\t\tupdated: [summary],\n\t\t\tremoved: [],\n\t\t});\n\t\treturn summary;\n\t}\n\n\tasync setSessionModel(\n\t\tsessionId: string,\n\t\tmodelId: string,\n\t): Promise<SessionSummary> {\n\t\tconst record = this.sessions.get(sessionId);\n\t\tif (!record) {\n\t\t\tthrow new AppError(\n\t\t\t\tcreateErrorDetail({\n\t\t\t\t\tcode: \"SESSION_NOT_FOUND\",\n\t\t\t\t\tmessage: \"Session not found\",\n\t\t\t\t\tretryable: false,\n\t\t\t\t\tscope: \"session\",\n\t\t\t\t}),\n\t\t\t\t404,\n\t\t\t);\n\t\t}\n\t\tif (!record.availableModels || record.availableModels.length === 0) {\n\t\t\tthrow createCapabilityNotSupportedError(\n\t\t\t\t\"Current agent does not support model switching\",\n\t\t\t);\n\t\t}\n\t\tconst selected = record.availableModels.find(\n\t\t\t(model) => model.id === modelId,\n\t\t);\n\t\tif (!selected) {\n\t\t\tthrow new AppError(\n\t\t\t\tcreateErrorDetail({\n\t\t\t\t\tcode: \"REQUEST_VALIDATION_FAILED\",\n\t\t\t\t\tmessage: \"Invalid model ID\",\n\t\t\t\t\tretryable: false,\n\t\t\t\t\tscope: \"request\",\n\t\t\t\t}),\n\t\t\t\t400,\n\t\t\t);\n\t\t}\n\t\tawait record.connection.setSessionModel(sessionId, modelId);\n\t\trecord.modelId = selected.id;\n\t\trecord.modelName = selected.name;\n\t\trecord.updatedAt = new Date();\n\t\tconst summary = this.buildSummary(record);\n\t\tthis.emitSessionsChanged({\n\t\t\tadded: [],\n\t\t\tupdated: [summary],\n\t\t\tremoved: [],\n\t\t});\n\t\treturn summary;\n\t}\n\n\tasync cancelSession(sessionId: string): Promise<boolean> {\n\t\tconst record = this.sessions.get(sessionId);\n\t\tif (!record) {\n\t\t\treturn false;\n\t\t}\n\t\tthis.cancelPermissionRequests(sessionId);\n\t\tawait record.connection.cancel(sessionId);\n\t\tthis.touchSession(sessionId);\n\t\treturn true;\n\t}\n\n\tasync closeSession(sessionId: string): Promise<boolean> {\n\t\tconst record = this.sessions.get(sessionId);\n\t\tif (!record) {\n\t\t\treturn false;\n\t\t}\n\t\ttry {\n\t\t\trecord.unsubscribe?.();\n\t\t\trecord.unsubscribeTerminal?.();\n\t\t} catch (error) {\n\t\t\tlogger.error({ err: error, sessionId }, \"session_unsubscribe_failed\");\n\t\t}\n\t\tthis.cancelPermissionRequests(sessionId);\n\t\ttry {\n\t\t\tawait record.connection.disconnect();\n\t\t} catch (error) {\n\t\t\tlogger.error({ err: error, sessionId }, \"session_disconnect_failed\");\n\t\t}\n\t\tthis.emitSessionDetached(sessionId, \"unknown\");\n\t\tthis.sessions.delete(sessionId);\n\t\tthis.emitSessionsChanged({\n\t\t\tadded: [],\n\t\t\tupdated: [],\n\t\t\tremoved: [sessionId],\n\t\t});\n\t\treturn true;\n\t}\n\n\tasync closeAll(): Promise<void> {\n\t\tconst sessionIds = Array.from(this.sessions.keys());\n\t\tawait Promise.all(\n\t\t\tsessionIds.map((sessionId) => this.closeSession(sessionId)),\n\t\t);\n\t}\n\n\t/**\n\t * Discover sessions persisted by the ACP agent.\n\t * Creates a temporary connection to query sessions.\n\t * @param options Optional parameters for discovery\n\t * @returns List of discovered sessions and agent capabilities\n\t */\n\tasync discoverSessions(options?: {\n\t\tcwd?: string;\n\t\tbackendId?: string;\n\t\tcursor?: string;\n\t}): Promise<DiscoverSessionsRpcResult> {\n\t\tconst backend = this.resolveBackend(options?.backendId);\n\t\tconst connection = new AcpConnection({\n\t\t\tbackend,\n\t\t\tclient: {\n\t\t\t\tname: this.config.clientName,\n\t\t\t\tversion: this.config.clientVersion,\n\t\t\t},\n\t\t});\n\n\t\ttry {\n\t\t\tawait connection.connect();\n\t\t\tconst capabilities = connection.getSessionCapabilities();\n\t\t\tconst sessions: AcpSessionInfo[] = [];\n\t\t\tlet nextCursor: string | undefined;\n\n\t\t\tif (capabilities.list) {\n\t\t\t\tconst response = await connection.listSessions({\n\t\t\t\t\tcwd: options?.cwd,\n\t\t\t\t\tcursor: options?.cursor,\n\t\t\t\t});\n\t\t\t\tnextCursor = response.nextCursor;\n\t\t\t\tconst validity = await Promise.all(\n\t\t\t\t\tresponse.sessions.map(async (session) => ({\n\t\t\t\t\t\tsession,\n\t\t\t\t\t\tisValid: session.cwd\n\t\t\t\t\t\t\t? await isValidWorkspacePath(session.cwd)\n\t\t\t\t\t\t\t: false,\n\t\t\t\t\t})),\n\t\t\t\t);\n\t\t\t\tfor (const { session, isValid } of validity) {\n\t\t\t\t\tif (!isValid) {\n\t\t\t\t\t\tthis.discoveredSessions.delete(session.sessionId);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tthis.discoveredSessions.set(session.sessionId, {\n\t\t\t\t\t\tsessionId: session.sessionId,\n\t\t\t\t\t\tcwd: session.cwd,\n\t\t\t\t\t\ttitle: session.title ?? undefined,\n\t\t\t\t\t\tupdatedAt: session.updatedAt ?? undefined,\n\t\t\t\t\t});\n\t\t\t\t\tsessions.push({\n\t\t\t\t\t\tsessionId: session.sessionId,\n\t\t\t\t\t\tcwd: session.cwd,\n\t\t\t\t\t\ttitle: session.title ?? undefined,\n\t\t\t\t\t\tupdatedAt: session.updatedAt ?? undefined,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlogger.info(\n\t\t\t\t{\n\t\t\t\t\tbackendId: backend.id,\n\t\t\t\t\tsessionCount: sessions.length,\n\t\t\t\t\tcapabilities,\n\t\t\t\t},\n\t\t\t\t\"sessions_discovered\",\n\t\t\t);\n\n\t\t\treturn { sessions, capabilities, nextCursor };\n\t\t} finally {\n\t\t\tawait connection.disconnect();\n\t\t}\n\t}\n\n\t/**\n\t * Load a historical session from the ACP agent.\n\t * This will replay the session's message history.\n\t * @param sessionId The session ID to load\n\t * @param cwd The working directory\n\t * @param backendId Optional backend ID\n\t * @returns The loaded session summary\n\t */\n\tasync loadSession(\n\t\tsessionId: string,\n\t\tcwd: string,\n\t\tbackendId?: string,\n\t): Promise<SessionSummary> {\n\t\t// Check if session is already loaded\n\t\tconst existing = this.sessions.get(sessionId);\n\t\tif (existing) {\n\t\t\tthis.emitSessionAttached(sessionId);\n\t\t\treturn this.buildSummary(existing);\n\t\t}\n\n\t\tconst backend = this.resolveBackend(backendId);\n\t\tconst connection = new AcpConnection({\n\t\t\tbackend,\n\t\t\tclient: {\n\t\t\t\tname: this.config.clientName,\n\t\t\t\tversion: this.config.clientVersion,\n\t\t\t},\n\t\t});\n\n\t\ttry {\n\t\t\tawait connection.connect();\n\n\t\t\tif (!connection.supportsSessionLoad()) {\n\t\t\t\tthrow createCapabilityNotSupportedError(\n\t\t\t\t\t\"Agent does not support session loading\",\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst bufferedUpdates: SessionNotification[] = [];\n\t\t\tlet recordRef: SessionRecord | undefined;\n\t\t\tconst unsubscribe = connection.onSessionUpdate(\n\t\t\t\t(notification: SessionNotification) => {\n\t\t\t\t\tthis.sessionUpdateEmitter.emit(\"update\", notification);\n\t\t\t\t\tif (recordRef) {\n\t\t\t\t\t\trecordRef.updatedAt = new Date();\n\t\t\t\t\t\tthis.applySessionUpdateToRecord(recordRef, notification);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tbufferedUpdates.push(notification);\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t);\n\n\t\t\tconst response = await connection.loadSession(sessionId, cwd);\n\t\t\tconnection.setPermissionHandler((params) =>\n\t\t\t\tthis.handlePermissionRequest(sessionId, params),\n\t\t\t);\n\n\t\t\tconst now = new Date();\n\t\t\tconst agentInfo = connection.getAgentInfo();\n\t\t\tconst { modelId, modelName, availableModels } = resolveModelState(\n\t\t\t\tresponse.models,\n\t\t\t);\n\t\t\tconst { modeId, modeName, availableModes } = resolveModeState(\n\t\t\t\tresponse.modes,\n\t\t\t);\n\t\t\tconst discovered = this.discoveredSessions.get(sessionId);\n\n\t\t\tconst record: SessionRecord = {\n\t\t\t\tsessionId,\n\t\t\t\ttitle: discovered?.title ?? sessionId,\n\t\t\t\tbackendId: backend.id,\n\t\t\t\tbackendLabel: backend.label,\n\t\t\t\tconnection,\n\t\t\t\tcreatedAt: now,\n\t\t\t\tupdatedAt: now,\n\t\t\t\tcwd,\n\t\t\t\tagentName: agentInfo?.title ?? agentInfo?.name,\n\t\t\t\tmodelId,\n\t\t\t\tmodelName,\n\t\t\t\tmodeId,\n\t\t\t\tmodeName,\n\t\t\t\tavailableModes,\n\t\t\t\tavailableModels,\n\t\t\t\tavailableCommands: undefined,\n\t\t\t};\n\n\t\t\trecordRef = record;\n\t\t\trecord.unsubscribe = unsubscribe;\n\t\t\tfor (const notification of bufferedUpdates) {\n\t\t\t\tthis.applySessionUpdateToRecord(record, notification);\n\t\t\t}\n\n\t\t\tthis.setupSessionSubscriptions(record, { skipSessionUpdates: true });\n\t\t\tthis.sessions.set(sessionId, record);\n\n\t\t\tconst summary = this.buildSummary(record);\n\t\t\tthis.emitSessionsChanged({\n\t\t\t\tadded: [summary],\n\t\t\t\tupdated: [],\n\t\t\t\tremoved: [],\n\t\t\t});\n\t\t\tthis.emitSessionAttached(sessionId);\n\n\t\t\tlogger.info({ sessionId, backendId: backend.id }, \"session_loaded\");\n\n\t\t\treturn summary;\n\t\t} catch (error) {\n\t\t\tawait connection.disconnect();\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tprivate applySessionUpdateToRecord(\n\t\trecord: SessionRecord,\n\t\tnotification: SessionNotification,\n\t) {\n\t\tconst update = notification.update;\n\t\tif (update.sessionUpdate === \"current_mode_update\") {\n\t\t\trecord.modeId = update.currentModeId;\n\t\t\trecord.modeName =\n\t\t\t\trecord.availableModes?.find((mode) => mode.id === update.currentModeId)\n\t\t\t\t\t?.name ?? record.modeName;\n\t\t\treturn;\n\t\t}\n\t\tif (update.sessionUpdate === \"session_info_update\") {\n\t\t\tif (typeof update.title === \"string\") {\n\t\t\t\trecord.title = update.title;\n\t\t\t}\n\t\t\tif (typeof update.updatedAt === \"string\") {\n\t\t\t\trecord.updatedAt = new Date(update.updatedAt);\n\t\t\t}\n\t\t}\n\t\tif (update.sessionUpdate === \"available_commands_update\") {\n\t\t\tif (update.availableCommands) {\n\t\t\t\trecord.availableCommands = update.availableCommands;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Set up event subscriptions for a session record.\n\t */\n\tprivate setupSessionSubscriptions(\n\t\trecord: SessionRecord,\n\t\toptions?: { skipSessionUpdates?: boolean },\n\t): void {\n\t\tconst { sessionId, connection } = record;\n\n\t\tif (!options?.skipSessionUpdates) {\n\t\t\trecord.unsubscribe = connection.onSessionUpdate(\n\t\t\t\t(notification: SessionNotification) => {\n\t\t\t\t\trecord.updatedAt = new Date();\n\t\t\t\t\tthis.sessionUpdateEmitter.emit(\"update\", notification);\n\t\t\t\t\tthis.applySessionUpdateToRecord(record, notification);\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\n\t\trecord.unsubscribeTerminal = connection.onTerminalOutput((event) => {\n\t\t\tthis.terminalOutputEmitter.emit(\"output\", event);\n\t\t});\n\n\t\tconnection.onStatusChange((status) => {\n\t\t\tif (status.error) {\n\t\t\t\tthis.sessionErrorEmitter.emit(\"error\", {\n\t\t\t\t\tsessionId,\n\t\t\t\t\terror: status.error,\n\t\t\t\t});\n\t\t\t\tthis.emitSessionDetached(sessionId, \"agent_exit\");\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate buildSummary(record: SessionRecord): SessionSummary {\n\t\tconst status = record.connection.getStatus();\n\t\treturn {\n\t\t\tsessionId: record.sessionId,\n\t\t\ttitle: record.title,\n\t\t\tbackendId: record.backendId,\n\t\t\tbackendLabel: record.backendLabel,\n\t\t\terror: status.error,\n\t\t\tpid: status.pid,\n\t\t\tcreatedAt: record.createdAt.toISOString(),\n\t\t\tupdatedAt: record.updatedAt.toISOString(),\n\t\t\tcwd: record.cwd,\n\t\t\tagentName: record.agentName,\n\t\t\tmodelId: record.modelId,\n\t\t\tmodelName: record.modelName,\n\t\t\tmodeId: record.modeId,\n\t\t\tmodeName: record.modeName,\n\t\t\tavailableModes: record.availableModes,\n\t\t\tavailableModels: record.availableModels,\n\t\t\tavailableCommands: record.availableCommands,\n\t\t};\n\t}\n}\n","export const createErrorDetail = (input) => ({\n ...input,\n});\nexport const withScope = (detail, scope) => createErrorDetail({\n ...detail,\n scope,\n});\nexport const createInternalError = (scope, detail) => createErrorDetail({\n code: \"INTERNAL_ERROR\",\n message: \"Internal server error\",\n retryable: true,\n scope,\n detail,\n});\nexport const isProtocolMismatch = (error) => {\n if (error instanceof Error) {\n return /protocol/i.test(error.message);\n }\n return false;\n};\nexport class AppError extends Error {\n detail;\n status;\n constructor(detail, status = 500) {\n super(detail.message);\n this.detail = detail;\n this.status = status;\n }\n}\nexport const isErrorDetail = (payload) => {\n if (!payload || typeof payload !== \"object\") {\n return false;\n }\n const detail = payload;\n return (typeof detail.code === \"string\" &&\n typeof detail.message === \"string\" &&\n typeof detail.retryable === \"boolean\" &&\n typeof detail.scope === \"string\");\n};\n","import { type ChildProcessWithoutNullStreams, spawn } from \"node:child_process\";\nimport { randomUUID } from \"node:crypto\";\nimport { EventEmitter } from \"node:events\";\nimport { Readable, Writable } from \"node:stream\";\nimport {\n\ttype AgentCapabilities,\n\ttype Client,\n\tClientSideConnection,\n\ttype ContentBlock,\n\ttype CreateTerminalRequest,\n\ttype CreateTerminalResponse,\n\ttype Implementation,\n\ttype KillTerminalCommandRequest,\n\ttype KillTerminalCommandResponse,\n\ttype ListSessionsResponse,\n\ttype LoadSessionResponse,\n\ttype NewSessionResponse,\n\tndJsonStream,\n\tPROTOCOL_VERSION,\n\ttype PromptResponse,\n\ttype ReleaseTerminalRequest,\n\ttype ReleaseTerminalResponse,\n\ttype RequestPermissionRequest,\n\ttype RequestPermissionResponse,\n\ttype SessionInfo,\n\ttype SessionNotification,\n\ttype TerminalExitStatus,\n\ttype TerminalOutputRequest,\n\ttype TerminalOutputResponse,\n\ttype WaitForTerminalExitRequest,\n\ttype WaitForTerminalExitResponse,\n} from \"@agentclientprotocol/sdk\";\nimport {\n\ttype AcpConnectionState,\n\ttype AgentSessionCapabilities,\n\tcreateErrorDetail,\n\ttype ErrorDetail,\n\tisProtocolMismatch,\n\ttype TerminalOutputEvent,\n} from \"@mobvibe/shared\";\nimport type { AcpBackendConfig } from \"../config.js\";\n\ntype ClientInfo = {\n\tname: string;\n\tversion: string;\n};\n\nexport type AcpBackendStatus = {\n\tbackendId: string;\n\tbackendLabel: string;\n\tstate: AcpConnectionState;\n\tcommand: string;\n\targs: string[];\n\tconnectedAt?: string;\n\terror?: ErrorDetail;\n\tsessionId?: string;\n\tpid?: number;\n};\n\nconst getErrorMessage = (error: unknown) => {\n\tif (error instanceof Error) {\n\t\treturn error.message;\n\t}\n\treturn String(error);\n};\n\ntype SessionUpdateListener = (notification: SessionNotification) => void;\n\ntype TerminalOutputSnapshot = {\n\toutput: string;\n\ttruncated: boolean;\n\texitStatus?: TerminalExitStatus | null;\n};\n\ntype TerminalRecord = {\n\tsessionId: string;\n\tcommand: string;\n\targs: string[];\n\toutputByteLimit: number;\n\toutput: TerminalOutputSnapshot;\n\tprocess?: ChildProcessWithoutNullStreams;\n\tonExit?: Promise<WaitForTerminalExitResponse>;\n\tresolveExit?: (response: WaitForTerminalExitResponse) => void;\n};\n\ntype ClientHandlers = {\n\tonSessionUpdate: (notification: SessionNotification) => void;\n\tonRequestPermission?: (\n\t\tparams: RequestPermissionRequest,\n\t) => Promise<RequestPermissionResponse>;\n\tonCreateTerminal?: (\n\t\tparams: CreateTerminalRequest,\n\t) => Promise<CreateTerminalResponse>;\n\tonTerminalOutput?: (\n\t\tparams: TerminalOutputRequest,\n\t) => Promise<TerminalOutputResponse>;\n\tonWaitForTerminalExit?: (\n\t\tparams: WaitForTerminalExitRequest,\n\t) => Promise<WaitForTerminalExitResponse>;\n\tonKillTerminal?: (\n\t\tparams: KillTerminalCommandRequest,\n\t) => Promise<KillTerminalCommandResponse>;\n\tonReleaseTerminal?: (\n\t\tparams: ReleaseTerminalRequest,\n\t) => Promise<ReleaseTerminalResponse>;\n};\n\nconst buildClient = (handlers: ClientHandlers): Client => ({\n\tasync requestPermission(params: RequestPermissionRequest) {\n\t\tif (handlers.onRequestPermission) {\n\t\t\treturn handlers.onRequestPermission(params);\n\t\t}\n\t\treturn { outcome: { outcome: \"cancelled\" } };\n\t},\n\tasync sessionUpdate(params: SessionNotification) {\n\t\thandlers.onSessionUpdate(params);\n\t},\n\tasync createTerminal(params: CreateTerminalRequest) {\n\t\tif (!handlers.onCreateTerminal) {\n\t\t\tthrow new Error(\"Terminal create handler not configured\");\n\t\t}\n\t\treturn handlers.onCreateTerminal(params);\n\t},\n\tasync terminalOutput(params: TerminalOutputRequest) {\n\t\tif (!handlers.onTerminalOutput) {\n\t\t\treturn { output: \"\", truncated: false };\n\t\t}\n\t\treturn handlers.onTerminalOutput(params);\n\t},\n\tasync waitForTerminalExit(params: WaitForTerminalExitRequest) {\n\t\tif (!handlers.onWaitForTerminalExit) {\n\t\t\treturn { exitCode: null, signal: null };\n\t\t}\n\t\treturn handlers.onWaitForTerminalExit(params);\n\t},\n\tasync killTerminal(params: KillTerminalCommandRequest) {\n\t\tif (!handlers.onKillTerminal) {\n\t\t\treturn {};\n\t\t}\n\t\treturn handlers.onKillTerminal(params);\n\t},\n\tasync releaseTerminal(params: ReleaseTerminalRequest) {\n\t\tif (!handlers.onReleaseTerminal) {\n\t\t\treturn {};\n\t\t}\n\t\treturn handlers.onReleaseTerminal(params);\n\t},\n});\n\nconst formatExitMessage = (\n\tcode: number | null,\n\tsignal: NodeJS.Signals | null,\n) => {\n\tif (signal) {\n\t\treturn `ACP process received signal ${signal}`;\n\t}\n\tif (code !== null) {\n\t\treturn `ACP process exited with code ${code}`;\n\t}\n\treturn \"ACP process exited\";\n};\n\nconst buildConnectError = (error: unknown): ErrorDetail => {\n\tconst detail = getErrorMessage(error);\n\tif (isProtocolMismatch(error)) {\n\t\treturn createErrorDetail({\n\t\t\tcode: \"ACP_PROTOCOL_MISMATCH\",\n\t\t\tmessage: \"ACP protocol version mismatch\",\n\t\t\tretryable: false,\n\t\t\tscope: \"service\",\n\t\t\tdetail,\n\t\t});\n\t}\n\treturn createErrorDetail({\n\t\tcode: \"ACP_CONNECT_FAILED\",\n\t\tmessage: \"Failed to connect to ACP backend process\",\n\t\tretryable: true,\n\t\tscope: \"service\",\n\t\tdetail,\n\t});\n};\n\nconst buildProcessExitError = (detail: string): ErrorDetail =>\n\tcreateErrorDetail({\n\t\tcode: \"ACP_PROCESS_EXITED\",\n\t\tmessage: \"ACP backend process exited unexpectedly\",\n\t\tretryable: true,\n\t\tscope: \"service\",\n\t\tdetail,\n\t});\n\nconst buildConnectionClosedError = (detail: string): ErrorDetail =>\n\tcreateErrorDetail({\n\t\tcode: \"ACP_CONNECTION_CLOSED\",\n\t\tmessage: \"ACP connection closed\",\n\t\tretryable: true,\n\t\tscope: \"service\",\n\t\tdetail,\n\t});\n\nconst normalizeOutputText = (value: string) => value.normalize(\"NFC\");\n\nconst isOutputOverLimit = (value: string, limit: number) =>\n\tBuffer.byteLength(value, \"utf8\") > limit;\n\nconst sliceOutputToLimit = (value: string, limit: number) => {\n\tconst buffer = Buffer.from(value, \"utf8\");\n\tif (buffer.byteLength <= limit) {\n\t\treturn value;\n\t}\n\tconst sliced = buffer.subarray(buffer.byteLength - limit);\n\tlet start = 0;\n\twhile (start < sliced.length && (sliced[start] & 0b11000000) === 0b10000000) {\n\t\tstart += 1;\n\t}\n\treturn sliced.subarray(start).toString(\"utf8\");\n};\n\nexport class AcpConnection {\n\tprivate connection?: ClientSideConnection;\n\tprivate process?: ChildProcessWithoutNullStreams;\n\tprivate closedPromise?: Promise<void>;\n\tprivate state: AcpConnectionState = \"idle\";\n\tprivate connectedAt?: Date;\n\tprivate error?: ErrorDetail;\n\tprivate sessionId?: string;\n\tprivate agentInfo?: Implementation;\n\tprivate agentCapabilities?: AgentCapabilities;\n\tprivate readonly sessionUpdateEmitter = new EventEmitter();\n\tprivate readonly statusEmitter = new EventEmitter();\n\tprivate readonly terminalOutputEmitter = new EventEmitter();\n\tprivate permissionHandler?: (\n\t\tparams: RequestPermissionRequest,\n\t) => Promise<RequestPermissionResponse>;\n\tprivate terminals = new Map<string, TerminalRecord>();\n\n\tconstructor(\n\t\tprivate readonly options: {\n\t\t\tbackend: AcpBackendConfig;\n\t\t\tclient: ClientInfo;\n\t\t},\n\t) {}\n\n\tgetStatus(): AcpBackendStatus {\n\t\treturn {\n\t\t\tbackendId: this.options.backend.id,\n\t\t\tbackendLabel: this.options.backend.label,\n\t\t\tstate: this.state,\n\t\t\tcommand: this.options.backend.command,\n\t\t\targs: [...this.options.backend.args],\n\t\t\tconnectedAt: this.connectedAt?.toISOString(),\n\t\t\terror: this.error,\n\t\t\tsessionId: this.sessionId,\n\t\t\tpid: this.process?.pid,\n\t\t};\n\t}\n\n\tgetAgentInfo(): Implementation | undefined {\n\t\treturn this.agentInfo;\n\t}\n\n\t/**\n\t * Get the agent's session capabilities.\n\t */\n\tgetSessionCapabilities(): AgentSessionCapabilities {\n\t\treturn {\n\t\t\tlist: this.agentCapabilities?.sessionCapabilities?.list != null,\n\t\t\tload: this.agentCapabilities?.loadSession === true,\n\t\t};\n\t}\n\n\t/**\n\t * Check if the agent supports session/list.\n\t */\n\tsupportsSessionList(): boolean {\n\t\treturn this.agentCapabilities?.sessionCapabilities?.list != null;\n\t}\n\n\t/**\n\t * Check if the agent supports session/load.\n\t */\n\tsupportsSessionLoad(): boolean {\n\t\treturn this.agentCapabilities?.loadSession === true;\n\t}\n\n\t/**\n\t * List sessions from the agent (session/list).\n\t * @param params Optional filter parameters\n\t * @returns List of session info from the agent\n\t */\n\tasync listSessions(params?: {\n\t\tcursor?: string;\n\t\tcwd?: string;\n\t}): Promise<{ sessions: SessionInfo[]; nextCursor?: string }> {\n\t\tif (!this.supportsSessionList()) {\n\t\t\treturn { sessions: [] };\n\t\t}\n\t\tconst connection = await this.ensureReady();\n\t\tconst response: ListSessionsResponse =\n\t\t\tawait connection.unstable_listSessions({\n\t\t\t\tcursor: params?.cursor ?? undefined,\n\t\t\t\tcwd: params?.cwd ?? undefined,\n\t\t\t});\n\t\treturn {\n\t\t\tsessions: response.sessions,\n\t\t\tnextCursor: response.nextCursor ?? undefined,\n\t\t};\n\t}\n\n\t/**\n\t * Load a historical session with message history replay (session/load).\n\t * @param sessionId The session ID to load\n\t * @param cwd The working directory\n\t * @returns Load session response with modes/models state\n\t */\n\tasync loadSession(\n\t\tsessionId: string,\n\t\tcwd: string,\n\t): Promise<LoadSessionResponse> {\n\t\tif (!this.supportsSessionLoad()) {\n\t\t\tthrow new Error(\"Agent does not support session/load capability\");\n\t\t}\n\t\tconst connection = await this.ensureReady();\n\t\tconst response = await connection.loadSession({\n\t\t\tsessionId,\n\t\t\tcwd,\n\t\t\tmcpServers: [],\n\t\t});\n\t\tthis.sessionId = sessionId;\n\t\treturn response;\n\t}\n\n\tsetPermissionHandler(\n\t\thandler?: (\n\t\t\tparams: RequestPermissionRequest,\n\t\t) => Promise<RequestPermissionResponse>,\n\t) {\n\t\tthis.permissionHandler = handler;\n\t}\n\n\tonTerminalOutput(listener: (payload: TerminalOutputEvent) => void) {\n\t\tthis.terminalOutputEmitter.on(\"output\", listener);\n\t\treturn () => {\n\t\t\tthis.terminalOutputEmitter.off(\"output\", listener);\n\t\t};\n\t}\n\n\tonSessionUpdate(listener: SessionUpdateListener) {\n\t\tthis.sessionUpdateEmitter.on(\"update\", listener);\n\t\treturn () => {\n\t\t\tthis.sessionUpdateEmitter.off(\"update\", listener);\n\t\t};\n\t}\n\n\tonStatusChange(listener: (status: AcpBackendStatus) => void) {\n\t\tthis.statusEmitter.on(\"status\", listener);\n\t\treturn () => {\n\t\t\tthis.statusEmitter.off(\"status\", listener);\n\t\t};\n\t}\n\n\tprivate updateStatus(state: AcpConnectionState, error?: ErrorDetail) {\n\t\tthis.state = state;\n\t\tthis.error = error;\n\t\tthis.statusEmitter.emit(\"status\", this.getStatus());\n\t}\n\n\tasync connect(): Promise<void> {\n\t\tif (this.state === \"connecting\" || this.state === \"ready\") {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.updateStatus(\"connecting\");\n\t\tthis.agentInfo = undefined;\n\n\t\ttry {\n\t\t\tconst env = this.options.backend.envOverrides\n\t\t\t\t? { ...process.env, ...this.options.backend.envOverrides }\n\t\t\t\t: process.env;\n\t\t\tconst child = spawn(\n\t\t\t\tthis.options.backend.command,\n\t\t\t\tthis.options.backend.args,\n\t\t\t\t{\n\t\t\t\t\tstdio: [\"pipe\", \"pipe\", \"pipe\"],\n\t\t\t\t\tenv,\n\t\t\t\t},\n\t\t\t);\n\t\t\tthis.process = child;\n\t\t\tthis.sessionId = undefined;\n\t\t\tchild.stderr.pipe(process.stderr);\n\n\t\t\tconst input = Writable.toWeb(child.stdin) as WritableStream<Uint8Array>;\n\t\t\tconst output = Readable.toWeb(child.stdout) as ReadableStream<Uint8Array>;\n\t\t\tconst stream = ndJsonStream(input, output);\n\t\t\tconst connection = new ClientSideConnection(\n\t\t\t\t() =>\n\t\t\t\t\tbuildClient({\n\t\t\t\t\t\tonSessionUpdate: (notification) =>\n\t\t\t\t\t\t\tthis.emitSessionUpdate(notification),\n\t\t\t\t\t\tonRequestPermission: (params) =>\n\t\t\t\t\t\t\tthis.handlePermissionRequest(params),\n\t\t\t\t\t\tonCreateTerminal: (params) => this.createTerminal(params),\n\t\t\t\t\t\tonTerminalOutput: (params) => this.getTerminalOutput(params),\n\t\t\t\t\t\tonWaitForTerminalExit: (params) => this.waitForTerminalExit(params),\n\t\t\t\t\t\tonKillTerminal: (params) => this.killTerminal(params),\n\t\t\t\t\t\tonReleaseTerminal: (params) => this.releaseTerminal(params),\n\t\t\t\t\t}),\n\t\t\t\tstream,\n\t\t\t);\n\t\t\tthis.connection = connection;\n\n\t\t\tchild.once(\"error\", (error) => {\n\t\t\t\tif (this.state === \"stopped\") {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tthis.updateStatus(\"error\", buildConnectError(error));\n\t\t\t});\n\n\t\t\tchild.once(\"exit\", (code, signal) => {\n\t\t\t\tif (this.state === \"stopped\") {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tthis.updateStatus(\n\t\t\t\t\t\"error\",\n\t\t\t\t\tbuildProcessExitError(formatExitMessage(code, signal)),\n\t\t\t\t);\n\t\t\t});\n\n\t\t\tthis.closedPromise = connection.closed.catch((error) => {\n\t\t\t\tthis.updateStatus(\n\t\t\t\t\t\"error\",\n\t\t\t\t\tbuildConnectionClosedError(getErrorMessage(error)),\n\t\t\t\t);\n\t\t\t});\n\n\t\t\tconst initializeResponse = await connection.initialize({\n\t\t\t\tprotocolVersion: PROTOCOL_VERSION,\n\t\t\t\tclientInfo: {\n\t\t\t\t\tname: this.options.client.name,\n\t\t\t\t\tversion: this.options.client.version,\n\t\t\t\t},\n\t\t\t\tclientCapabilities: { terminal: true },\n\t\t\t});\n\n\t\t\tthis.agentInfo = initializeResponse.agentInfo ?? undefined;\n\t\t\tthis.agentCapabilities =\n\t\t\t\tinitializeResponse.agentCapabilities ?? undefined;\n\t\t\tthis.connectedAt = new Date();\n\t\t\tthis.updateStatus(\"ready\");\n\t\t} catch (error) {\n\t\t\tthis.updateStatus(\"error\", buildConnectError(error));\n\t\t\tawait this.stopProcess();\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tasync createSession(options?: { cwd?: string }): Promise<NewSessionResponse> {\n\t\tconst connection = await this.ensureReady();\n\t\tconst response = await this.createSessionInternal(\n\t\t\tconnection,\n\t\t\toptions?.cwd ?? process.cwd(),\n\t\t);\n\t\tthis.sessionId = response.sessionId;\n\t\treturn response;\n\t}\n\n\tasync prompt(\n\t\tsessionId: string,\n\t\tprompt: ContentBlock[],\n\t): Promise<PromptResponse> {\n\t\tconst connection = await this.ensureReady();\n\t\treturn connection.prompt({ sessionId, prompt });\n\t}\n\n\tasync cancel(sessionId: string): Promise<void> {\n\t\tconst connection = await this.ensureReady();\n\t\tawait connection.cancel({ sessionId });\n\t}\n\n\tasync setSessionMode(sessionId: string, modeId: string): Promise<void> {\n\t\tconst connection = await this.ensureReady();\n\t\tawait connection.setSessionMode({ sessionId, modeId });\n\t}\n\n\tasync setSessionModel(sessionId: string, modelId: string): Promise<void> {\n\t\tconst connection = await this.ensureReady();\n\t\tawait connection.unstable_setSessionModel({ sessionId, modelId });\n\t}\n\n\tasync createTerminal(\n\t\tparams: CreateTerminalRequest,\n\t): Promise<CreateTerminalResponse> {\n\t\tconst outputLimit =\n\t\t\ttypeof params.outputByteLimit === \"number\" && params.outputByteLimit > 0\n\t\t\t\t? Math.floor(params.outputByteLimit)\n\t\t\t\t: 1024 * 1024;\n\t\tconst resolvedEnv = params.env\n\t\t\t? Object.fromEntries(\n\t\t\t\t\tparams.env.map((envVar) => [envVar.name, envVar.value]),\n\t\t\t\t)\n\t\t\t: undefined;\n\t\tconst terminalId = randomUUID();\n\t\tconst record: TerminalRecord = {\n\t\t\tsessionId: params.sessionId,\n\t\t\tcommand: params.command,\n\t\t\targs: params.args ?? [],\n\t\t\toutputByteLimit: outputLimit,\n\t\t\toutput: {\n\t\t\t\toutput: \"\",\n\t\t\t\ttruncated: false,\n\t\t\t\texitStatus: null,\n\t\t\t},\n\t\t};\n\t\tthis.terminals.set(terminalId, record);\n\n\t\tconst child = spawn(params.command, params.args ?? [], {\n\t\t\tcwd: params.cwd ?? undefined,\n\t\t\tenv: resolvedEnv ? { ...process.env, ...resolvedEnv } : process.env,\n\t\t});\n\t\tchild.once(\"error\", (error) => {\n\t\t\trecord.output.exitStatus = {\n\t\t\t\texitCode: null,\n\t\t\t\tsignal: null,\n\t\t\t};\n\t\t\trecord.resolveExit?.({ exitCode: null, signal: null });\n\t\t\tthis.terminalOutputEmitter.emit(\"output\", {\n\t\t\t\tsessionId: record.sessionId,\n\t\t\t\tterminalId,\n\t\t\t\tdelta: `\\n[terminal error] ${String(error)}`,\n\t\t\t\ttruncated: record.output.truncated,\n\t\t\t\toutput: record.output.output,\n\t\t\t\texitStatus: record.output.exitStatus,\n\t\t\t} satisfies TerminalOutputEvent);\n\t\t});\n\t\trecord.process = child;\n\t\tlet resolveExit: (response: WaitForTerminalExitResponse) => void = () => {};\n\t\trecord.onExit = new Promise<WaitForTerminalExitResponse>((resolve) => {\n\t\t\tresolveExit = resolve;\n\t\t});\n\t\trecord.resolveExit = resolveExit;\n\n\t\tconst handleChunk = (chunk: Buffer) => {\n\t\t\tconst delta = normalizeOutputText(chunk.toString(\"utf8\"));\n\t\t\tif (!delta) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst combinedOutput = record.output.output + delta;\n\t\t\trecord.output.truncated = isOutputOverLimit(\n\t\t\t\tcombinedOutput,\n\t\t\t\trecord.outputByteLimit,\n\t\t\t);\n\t\t\trecord.output.output = sliceOutputToLimit(\n\t\t\t\tcombinedOutput,\n\t\t\t\trecord.outputByteLimit,\n\t\t\t);\n\n\t\t\tthis.terminalOutputEmitter.emit(\"output\", {\n\t\t\t\tsessionId: record.sessionId,\n\t\t\t\tterminalId,\n\t\t\t\tdelta,\n\t\t\t\ttruncated: record.output.truncated,\n\t\t\t\toutput: record.output.truncated ? record.output.output : undefined,\n\t\t\t\texitStatus: record.output.exitStatus,\n\t\t\t} satisfies TerminalOutputEvent);\n\t\t};\n\n\t\tchild.stdout?.on(\"data\", handleChunk);\n\t\tchild.stderr?.on(\"data\", handleChunk);\n\t\tchild.on(\"exit\", (code, signal) => {\n\t\t\trecord.output.exitStatus = {\n\t\t\t\texitCode: code ?? null,\n\t\t\t\tsignal: signal ?? null,\n\t\t\t};\n\t\t\trecord.resolveExit?.({\n\t\t\t\texitCode: code ?? null,\n\t\t\t\tsignal: signal ?? null,\n\t\t\t});\n\t\t\tthis.terminalOutputEmitter.emit(\"output\", {\n\t\t\t\tsessionId: record.sessionId,\n\t\t\t\tterminalId,\n\t\t\t\tdelta: \"\",\n\t\t\t\ttruncated: record.output.truncated,\n\t\t\t\toutput: record.output.output,\n\t\t\t\texitStatus: record.output.exitStatus,\n\t\t\t} satisfies TerminalOutputEvent);\n\t\t});\n\n\t\treturn { terminalId };\n\t}\n\n\tasync getTerminalOutput(\n\t\tparams: TerminalOutputRequest,\n\t): Promise<TerminalOutputResponse> {\n\t\tconst record = this.terminals.get(params.terminalId);\n\t\tif (!record || record.sessionId !== params.sessionId) {\n\t\t\treturn { output: \"\", truncated: false };\n\t\t}\n\t\treturn record.output;\n\t}\n\n\tasync waitForTerminalExit(\n\t\tparams: WaitForTerminalExitRequest,\n\t): Promise<WaitForTerminalExitResponse> {\n\t\tconst record = this.terminals.get(params.terminalId);\n\t\tif (!record || record.sessionId !== params.sessionId) {\n\t\t\treturn Promise.resolve({ exitCode: null, signal: null });\n\t\t}\n\t\treturn record.onExit ?? Promise.resolve({ exitCode: null, signal: null });\n\t}\n\n\tasync killTerminal(\n\t\tparams: KillTerminalCommandRequest,\n\t): Promise<KillTerminalCommandResponse> {\n\t\tconst record = this.terminals.get(params.terminalId);\n\t\tif (!record || record.sessionId !== params.sessionId) {\n\t\t\treturn {};\n\t\t}\n\t\trecord.process?.kill(\"SIGTERM\");\n\t\treturn {};\n\t}\n\n\tasync releaseTerminal(\n\t\tparams: ReleaseTerminalRequest,\n\t): Promise<ReleaseTerminalResponse> {\n\t\tconst record = this.terminals.get(params.terminalId);\n\t\tif (record?.process && record.process.exitCode === null) {\n\t\t\trecord.process.kill(\"SIGTERM\");\n\t\t}\n\t\tthis.terminals.delete(params.terminalId);\n\t\treturn {};\n\t}\n\n\tasync disconnect(): Promise<void> {\n\t\tif (this.state === \"stopped\") {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.updateStatus(\"stopped\");\n\t\tthis.sessionId = undefined;\n\t\tthis.agentInfo = undefined;\n\t\tawait this.stopProcess();\n\t\tawait this.closedPromise;\n\t\tthis.connection = undefined;\n\t}\n\n\tprivate async ensureReady(): Promise<ClientSideConnection> {\n\t\tif (this.state !== \"ready\" || !this.connection) {\n\t\t\tawait this.connect();\n\t\t}\n\n\t\tif (!this.connection || this.state !== \"ready\") {\n\t\t\tthrow new Error(\"ACP connection not available\");\n\t\t}\n\n\t\treturn this.connection;\n\t}\n\n\tprivate async createSessionInternal(\n\t\tconnection: ClientSideConnection,\n\t\tcwd: string,\n\t): Promise<NewSessionResponse> {\n\t\tconst session = await connection.newSession({\n\t\t\tcwd,\n\t\t\tmcpServers: [],\n\t\t});\n\t\treturn session;\n\t}\n\n\tprivate emitSessionUpdate(notification: SessionNotification) {\n\t\tthis.sessionUpdateEmitter.emit(\"update\", notification);\n\t}\n\n\tprivate async handlePermissionRequest(\n\t\tparams: RequestPermissionRequest,\n\t): Promise<RequestPermissionResponse> {\n\t\tif (this.permissionHandler) {\n\t\t\treturn this.permissionHandler(params);\n\t\t}\n\t\treturn { outcome: { outcome: \"cancelled\" } };\n\t}\n\n\tprivate async stopProcess(): Promise<void> {\n\t\tconst child = this.process;\n\t\tif (!child) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.process = undefined;\n\t\tif (child.exitCode === null && !child.killed) {\n\t\t\tchild.kill(\"SIGTERM\");\n\t\t}\n\t}\n}\n","import { EventEmitter } from \"node:events\";\nimport fs from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport path from \"node:path\";\nimport type {\n\tCliToGatewayEvents,\n\tFsEntry,\n\tFsRoot,\n\tGatewayToCliEvents,\n\tHostFsRootsResponse,\n\tRpcResponse,\n\tSessionFsFilePreview,\n\tSessionFsResourceEntry,\n\tStopReason,\n} from \"@mobvibe/shared\";\nimport ignore, { type Ignore } from \"ignore\";\nimport { io, type Socket } from \"socket.io-client\";\nimport type { SessionManager } from \"../acp/session-manager.js\";\nimport type { CliConfig } from \"../config.js\";\nimport { logger } from \"../lib/logger.js\";\n\ntype SocketClientOptions = {\n\tconfig: CliConfig;\n\tsessionManager: SessionManager;\n\t/** API key for authentication (loaded from credentials) */\n\tapiKey: string;\n};\n\nconst SESSION_ROOT_NAME = \"Working Directory\";\nconst MAX_RESOURCE_FILES = 2000;\nconst DEFAULT_IGNORES = [\n\t\"node_modules\",\n\t\".git\",\n\t\"dist\",\n\t\"build\",\n\t\".next\",\n\t\".nuxt\",\n\t\".output\",\n\t\".cache\",\n\t\"__pycache__\",\n\t\".venv\",\n\t\"venv\",\n\t\"target\",\n];\n\nconst loadGitignore = async (rootPath: string): Promise<Ignore> => {\n\tconst ig = ignore().add(DEFAULT_IGNORES);\n\ttry {\n\t\tconst gitignorePath = path.join(rootPath, \".gitignore\");\n\t\tconst content = await fs.readFile(gitignorePath, \"utf8\");\n\t\tig.add(content);\n\t} catch {\n\t\t// No .gitignore file, use defaults only\n\t}\n\treturn ig;\n};\n\nconst resolveImageMimeType = (filePath: string) => {\n\tconst extension = path.extname(filePath).toLowerCase();\n\tswitch (extension) {\n\t\tcase \".apng\":\n\t\t\treturn \"image/apng\";\n\t\tcase \".avif\":\n\t\t\treturn \"image/avif\";\n\t\tcase \".gif\":\n\t\t\treturn \"image/gif\";\n\t\tcase \".jpeg\":\n\t\t\treturn \"image/jpeg\";\n\t\tcase \".jpg\":\n\t\t\treturn \"image/jpeg\";\n\t\tcase \".png\":\n\t\t\treturn \"image/png\";\n\t\tcase \".svg\":\n\t\t\treturn \"image/svg+xml\";\n\t\tcase \".webp\":\n\t\t\treturn \"image/webp\";\n\t\tdefault:\n\t\t\treturn undefined;\n\t}\n};\n\nconst readDirectoryEntries = async (dirPath: string): Promise<FsEntry[]> => {\n\tconst entries = await fs.readdir(dirPath, { withFileTypes: true });\n\tconst resolvedEntries = await Promise.all(\n\t\tentries.map(async (entry) => {\n\t\t\tconst entryPath = path.join(dirPath, entry.name);\n\t\t\tlet isDirectory = entry.isDirectory();\n\t\t\tif (!isDirectory && entry.isSymbolicLink()) {\n\t\t\t\ttry {\n\t\t\t\t\tconst stats = await fs.stat(entryPath);\n\t\t\t\t\tisDirectory = stats.isDirectory();\n\t\t\t\t} catch {\n\t\t\t\t\t// ignore broken symlink\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst entryType: FsEntry[\"type\"] = isDirectory ? \"directory\" : \"file\";\n\t\t\treturn {\n\t\t\t\tname: entry.name,\n\t\t\t\tpath: entryPath,\n\t\t\t\ttype: entryType,\n\t\t\t\thidden: entry.name.startsWith(\".\"),\n\t\t\t};\n\t\t}),\n\t);\n\treturn resolvedEntries.sort((left, right) => {\n\t\tif (left.type !== right.type) {\n\t\t\treturn left.type === \"directory\" ? -1 : 1;\n\t\t}\n\t\treturn left.name.localeCompare(right.name);\n\t});\n};\n\nconst filterVisibleEntries = (entries: FsEntry[]) =>\n\tentries.filter((entry) => !entry.hidden);\n\nconst buildHostFsRoots = async (): Promise<HostFsRootsResponse> => {\n\tconst homePath = homedir();\n\treturn {\n\t\thomePath,\n\t\troots: [{ name: \"Home\", path: homePath }],\n\t};\n};\n\nexport class SocketClient extends EventEmitter {\n\tprivate socket: Socket<GatewayToCliEvents, CliToGatewayEvents>;\n\tprivate connected = false;\n\tprivate reconnectAttempts = 0;\n\tprivate heartbeatInterval?: NodeJS.Timeout;\n\n\tconstructor(private readonly options: SocketClientOptions) {\n\t\tsuper();\n\t\tthis.socket = io(`${options.config.gatewayUrl}/cli`, {\n\t\t\tpath: \"/socket.io\",\n\t\t\treconnection: true,\n\t\t\treconnectionAttempts: Number.POSITIVE_INFINITY,\n\t\t\treconnectionDelay: 1000,\n\t\t\treconnectionDelayMax: 30000,\n\t\t\ttransports: [\"websocket\"],\n\t\t\tautoConnect: false,\n\t\t\textraHeaders: {\n\t\t\t\t\"x-api-key\": options.apiKey,\n\t\t\t},\n\t\t});\n\t\tthis.setupEventHandlers();\n\t\tthis.setupRpcHandlers();\n\t\tthis.setupSessionManagerListeners();\n\t}\n\n\tprivate setupEventHandlers() {\n\t\tthis.socket.on(\"connect\", () => {\n\t\t\tlogger.info(\n\t\t\t\t{ gatewayUrl: this.options.config.gatewayUrl },\n\t\t\t\t\"gateway_connected\",\n\t\t\t);\n\t\t\tthis.connected = true;\n\t\t\tthis.reconnectAttempts = 0;\n\t\t\tlogger.info(\"gateway_register_start\");\n\t\t\tthis.register();\n\t\t\tthis.startHeartbeat();\n\t\t\tthis.emit(\"connected\");\n\t\t});\n\n\t\tthis.socket.on(\"disconnect\", (reason) => {\n\t\t\tlogger.warn({ reason }, \"gateway_disconnected\");\n\t\t\tthis.connected = false;\n\t\t\tthis.stopHeartbeat();\n\t\t\tthis.emit(\"disconnected\", reason);\n\t\t});\n\n\t\tthis.socket.on(\"connect_error\", (error) => {\n\t\t\tthis.reconnectAttempts++;\n\t\t\tif (this.reconnectAttempts <= 3 || this.reconnectAttempts % 10 === 0) {\n\t\t\t\tlogger.error(\n\t\t\t\t\t{ attempt: this.reconnectAttempts, err: error },\n\t\t\t\t\t\"gateway_connect_error\",\n\t\t\t\t);\n\t\t\t}\n\t\t});\n\n\t\tthis.socket.on(\"cli:registered\", async (info) => {\n\t\t\tlogger.info({ machineId: info.machineId }, \"gateway_registered\");\n\n\t\t\t// Auto-discover historical sessions from ACP agent\n\t\t\ttry {\n\t\t\t\tlet cursor: string | undefined;\n\t\t\t\tlet page = 0;\n\t\t\t\tdo {\n\t\t\t\t\tconst { sessions, capabilities, nextCursor } =\n\t\t\t\t\t\tawait this.options.sessionManager.discoverSessions({ cursor });\n\t\t\t\t\tcursor = nextCursor;\n\t\t\t\t\tif (sessions.length > 0) {\n\t\t\t\t\t\tthis.socket.emit(\"sessions:discovered\", {\n\t\t\t\t\t\t\tsessions,\n\t\t\t\t\t\t\tcapabilities,\n\t\t\t\t\t\t\tnextCursor,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tlogger.info(\n\t\t\t\t\t\t\t{ count: sessions.length, capabilities, page },\n\t\t\t\t\t\t\t\"historical_sessions_discovered\",\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tpage += 1;\n\t\t\t\t} while (cursor);\n\t\t\t} catch (error) {\n\t\t\t\tlogger.warn({ err: error }, \"session_discovery_failed\");\n\t\t\t}\n\t\t});\n\n\t\t// Handle authentication errors\n\t\tthis.socket.on(\"cli:error\", (error) => {\n\t\t\tlogger.error({ err: error }, \"gateway_auth_error\");\n\t\t\tthis.emit(\"auth_error\", error);\n\t\t});\n\t}\n\n\tprivate setupRpcHandlers() {\n\t\tconst { sessionManager } = this.options;\n\n\t\t// Session create\n\t\tthis.socket.on(\"rpc:session:create\", async (request) => {\n\t\t\ttry {\n\t\t\t\tlogger.info({ requestId: request.requestId }, \"rpc_session_create\");\n\t\t\t\tconst session = await sessionManager.createSession(request.params);\n\t\t\t\tthis.sendRpcResponse(request.requestId, session);\n\t\t\t} catch (error) {\n\t\t\t\tlogger.error(\n\t\t\t\t\t{ err: error, requestId: request.requestId },\n\t\t\t\t\t\"rpc_session_create_error\",\n\t\t\t\t);\n\t\t\t\tthis.sendRpcError(request.requestId, error);\n\t\t\t}\n\t\t});\n\n\t\t// Session close\n\t\tthis.socket.on(\"rpc:session:close\", async (request) => {\n\t\t\ttry {\n\t\t\t\tlogger.info(\n\t\t\t\t\t{ requestId: request.requestId, sessionId: request.params.sessionId },\n\t\t\t\t\t\"rpc_session_close\",\n\t\t\t\t);\n\t\t\t\tawait sessionManager.closeSession(request.params.sessionId);\n\t\t\t\tthis.sendRpcResponse(request.requestId, { ok: true });\n\t\t\t} catch (error) {\n\t\t\t\tlogger.error(\n\t\t\t\t\t{\n\t\t\t\t\t\terr: error,\n\t\t\t\t\t\trequestId: request.requestId,\n\t\t\t\t\t\tsessionId: request.params.sessionId,\n\t\t\t\t\t},\n\t\t\t\t\t\"rpc_session_close_error\",\n\t\t\t\t);\n\t\t\t\tthis.sendRpcError(request.requestId, error);\n\t\t\t}\n\t\t});\n\n\t\t// Session cancel\n\t\tthis.socket.on(\"rpc:session:cancel\", async (request) => {\n\t\t\ttry {\n\t\t\t\tlogger.info(\n\t\t\t\t\t{ requestId: request.requestId, sessionId: request.params.sessionId },\n\t\t\t\t\t\"rpc_session_cancel\",\n\t\t\t\t);\n\t\t\t\tawait sessionManager.cancelSession(request.params.sessionId);\n\t\t\t\tthis.sendRpcResponse(request.requestId, { ok: true });\n\t\t\t} catch (error) {\n\t\t\t\tlogger.error(\n\t\t\t\t\t{\n\t\t\t\t\t\terr: error,\n\t\t\t\t\t\trequestId: request.requestId,\n\t\t\t\t\t\tsessionId: request.params.sessionId,\n\t\t\t\t\t},\n\t\t\t\t\t\"rpc_session_cancel_error\",\n\t\t\t\t);\n\t\t\t\tthis.sendRpcError(request.requestId, error);\n\t\t\t}\n\t\t});\n\n\t\t// Session mode\n\t\tthis.socket.on(\"rpc:session:mode\", async (request) => {\n\t\t\ttry {\n\t\t\t\tlogger.info(\n\t\t\t\t\t{\n\t\t\t\t\t\trequestId: request.requestId,\n\t\t\t\t\t\tsessionId: request.params.sessionId,\n\t\t\t\t\t\tmodeId: request.params.modeId,\n\t\t\t\t\t},\n\t\t\t\t\t\"rpc_session_mode\",\n\t\t\t\t);\n\t\t\t\tconst session = await sessionManager.setSessionMode(\n\t\t\t\t\trequest.params.sessionId,\n\t\t\t\t\trequest.params.modeId,\n\t\t\t\t);\n\t\t\t\tthis.sendRpcResponse(request.requestId, session);\n\t\t\t} catch (error) {\n\t\t\t\tlogger.error(\n\t\t\t\t\t{\n\t\t\t\t\t\terr: error,\n\t\t\t\t\t\trequestId: request.requestId,\n\t\t\t\t\t\tsessionId: request.params.sessionId,\n\t\t\t\t\t\tmodeId: request.params.modeId,\n\t\t\t\t\t},\n\t\t\t\t\t\"rpc_session_mode_error\",\n\t\t\t\t);\n\t\t\t\tthis.sendRpcError(request.requestId, error);\n\t\t\t}\n\t\t});\n\n\t\t// Session model\n\t\tthis.socket.on(\"rpc:session:model\", async (request) => {\n\t\t\ttry {\n\t\t\t\tlogger.info(\n\t\t\t\t\t{\n\t\t\t\t\t\trequestId: request.requestId,\n\t\t\t\t\t\tsessionId: request.params.sessionId,\n\t\t\t\t\t\tmodelId: request.params.modelId,\n\t\t\t\t\t},\n\t\t\t\t\t\"rpc_session_model\",\n\t\t\t\t);\n\t\t\t\tconst session = await sessionManager.setSessionModel(\n\t\t\t\t\trequest.params.sessionId,\n\t\t\t\t\trequest.params.modelId,\n\t\t\t\t);\n\t\t\t\tthis.sendRpcResponse(request.requestId, session);\n\t\t\t} catch (error) {\n\t\t\t\tlogger.error(\n\t\t\t\t\t{\n\t\t\t\t\t\terr: error,\n\t\t\t\t\t\trequestId: request.requestId,\n\t\t\t\t\t\tsessionId: request.params.sessionId,\n\t\t\t\t\t\tmodelId: request.params.modelId,\n\t\t\t\t\t},\n\t\t\t\t\t\"rpc_session_model_error\",\n\t\t\t\t);\n\t\t\t\tthis.sendRpcError(request.requestId, error);\n\t\t\t}\n\t\t});\n\n\t\t// Send message\n\t\tthis.socket.on(\"rpc:message:send\", async (request) => {\n\t\t\tconst requestStart = process.hrtime.bigint();\n\t\t\ttry {\n\t\t\t\tconst { sessionId, prompt } = request.params;\n\t\t\t\tlogger.info(\n\t\t\t\t\t{\n\t\t\t\t\t\trequestId: request.requestId,\n\t\t\t\t\t\tsessionId,\n\t\t\t\t\t\tpromptBlocks: prompt.length,\n\t\t\t\t\t},\n\t\t\t\t\t\"rpc_message_send\",\n\t\t\t\t);\n\t\t\t\tlogger.debug(\n\t\t\t\t\t{\n\t\t\t\t\t\trequestId: request.requestId,\n\t\t\t\t\t\tsessionId,\n\t\t\t\t\t\tpromptBlocks: prompt.length,\n\t\t\t\t\t},\n\t\t\t\t\t\"rpc_message_send_start\",\n\t\t\t\t);\n\t\t\t\tconst record = sessionManager.getSession(sessionId);\n\t\t\t\tif (!record) {\n\t\t\t\t\tthrow new Error(\"Session not found\");\n\t\t\t\t}\n\t\t\t\tsessionManager.touchSession(sessionId);\n\t\t\t\t// Cast through unknown since SDK and shared ContentBlock types are structurally compatible\n\t\t\t\tconst result = await record.connection.prompt(\n\t\t\t\t\tsessionId,\n\t\t\t\t\tprompt as unknown as import(\"@agentclientprotocol/sdk\").ContentBlock[],\n\t\t\t\t);\n\t\t\t\tsessionManager.touchSession(sessionId);\n\t\t\t\tthis.sendRpcResponse<{ stopReason: StopReason }>(request.requestId, {\n\t\t\t\t\tstopReason: result.stopReason as StopReason,\n\t\t\t\t});\n\t\t\t\tconst durationMs =\n\t\t\t\t\tNumber(process.hrtime.bigint() - requestStart) / 1_000_000;\n\t\t\t\tlogger.info(\n\t\t\t\t\t{\n\t\t\t\t\t\trequestId: request.requestId,\n\t\t\t\t\t\tsessionId,\n\t\t\t\t\t\tstopReason: result.stopReason,\n\t\t\t\t\t\tdurationMs,\n\t\t\t\t\t},\n\t\t\t\t\t\"rpc_message_send_complete\",\n\t\t\t\t);\n\t\t\t\tlogger.debug(\n\t\t\t\t\t{\n\t\t\t\t\t\trequestId: request.requestId,\n\t\t\t\t\t\tsessionId,\n\t\t\t\t\t\tdurationMs,\n\t\t\t\t\t},\n\t\t\t\t\t\"rpc_message_send_finish\",\n\t\t\t\t);\n\t\t\t} catch (error) {\n\t\t\t\tconst durationMs =\n\t\t\t\t\tNumber(process.hrtime.bigint() - requestStart) / 1_000_000;\n\t\t\t\tlogger.error(\n\t\t\t\t\t{\n\t\t\t\t\t\terr: error,\n\t\t\t\t\t\trequestId: request.requestId,\n\t\t\t\t\t\tsessionId: request.params.sessionId,\n\t\t\t\t\t\tpromptBlocks: request.params.prompt.length,\n\t\t\t\t\t\tdurationMs,\n\t\t\t\t\t},\n\t\t\t\t\t\"rpc_message_send_error\",\n\t\t\t\t);\n\t\t\t\tthis.sendRpcError(request.requestId, error);\n\t\t\t}\n\t\t});\n\n\t\t// Permission decision\n\t\tthis.socket.on(\"rpc:permission:decision\", async (request) => {\n\t\t\ttry {\n\t\t\t\tconst { sessionId, requestId, outcome } = request.params;\n\t\t\t\tlogger.info(\n\t\t\t\t\t{ requestId: request.requestId, sessionId, outcome },\n\t\t\t\t\t\"rpc_permission_decision\",\n\t\t\t\t);\n\t\t\t\tsessionManager.resolvePermissionRequest(sessionId, requestId, outcome);\n\t\t\t\tthis.sendRpcResponse(request.requestId, { ok: true });\n\t\t\t} catch (error) {\n\t\t\t\tlogger.error(\n\t\t\t\t\t{\n\t\t\t\t\t\terr: error,\n\t\t\t\t\t\trequestId: request.requestId,\n\t\t\t\t\t\tsessionId: request.params.sessionId,\n\t\t\t\t\t\tpermissionRequestId: request.params.requestId,\n\t\t\t\t\t\toutcome: request.params.outcome,\n\t\t\t\t\t},\n\t\t\t\t\t\"rpc_permission_decision_error\",\n\t\t\t\t);\n\t\t\t\tthis.sendRpcError(request.requestId, error);\n\t\t\t}\n\t\t});\n\n\t\t// File system handlers\n\t\tthis.socket.on(\"rpc:fs:roots\", async (request) => {\n\t\t\ttry {\n\t\t\t\tlogger.debug(\n\t\t\t\t\t{ requestId: request.requestId, sessionId: request.params.sessionId },\n\t\t\t\t\t\"rpc_fs_roots\",\n\t\t\t\t);\n\t\t\t\tconst record = sessionManager.getSession(request.params.sessionId);\n\t\t\t\tif (!record || !record.cwd) {\n\t\t\t\t\tthrow new Error(\"Session not found or no working directory\");\n\t\t\t\t}\n\t\t\t\tconst root: FsRoot = {\n\t\t\t\t\tname: SESSION_ROOT_NAME,\n\t\t\t\t\tpath: record.cwd,\n\t\t\t\t};\n\t\t\t\tthis.sendRpcResponse(request.requestId, { root });\n\t\t\t} catch (error) {\n\t\t\t\tlogger.error(\n\t\t\t\t\t{\n\t\t\t\t\t\terr: error,\n\t\t\t\t\t\trequestId: request.requestId,\n\t\t\t\t\t\tsessionId: request.params.sessionId,\n\t\t\t\t\t},\n\t\t\t\t\t\"rpc_fs_roots_error\",\n\t\t\t\t);\n\t\t\t\tthis.sendRpcError(request.requestId, error);\n\t\t\t}\n\t\t});\n\n\t\tthis.socket.on(\"rpc:hostfs:roots\", async (request) => {\n\t\t\ttry {\n\t\t\t\tlogger.debug(\n\t\t\t\t\t{\n\t\t\t\t\t\trequestId: request.requestId,\n\t\t\t\t\t\tmachineId: request.params.machineId,\n\t\t\t\t\t},\n\t\t\t\t\t\"rpc_hostfs_roots\",\n\t\t\t\t);\n\t\t\t\tconst result = await buildHostFsRoots();\n\t\t\t\tthis.sendRpcResponse(request.requestId, result);\n\t\t\t} catch (error) {\n\t\t\t\tlogger.error(\n\t\t\t\t\t{\n\t\t\t\t\t\terr: error,\n\t\t\t\t\t\trequestId: request.requestId,\n\t\t\t\t\t\tmachineId: request.params.machineId,\n\t\t\t\t\t},\n\t\t\t\t\t\"rpc_hostfs_roots_error\",\n\t\t\t\t);\n\t\t\t\tthis.sendRpcError(request.requestId, error);\n\t\t\t}\n\t\t});\n\n\t\tthis.socket.on(\"rpc:hostfs:entries\", async (request) => {\n\t\t\ttry {\n\t\t\t\tconst { path: requestPath, machineId } = request.params;\n\t\t\t\tlogger.debug(\n\t\t\t\t\t{ requestId: request.requestId, machineId, path: requestPath },\n\t\t\t\t\t\"rpc_hostfs_entries\",\n\t\t\t\t);\n\t\t\t\tconst entries = await readDirectoryEntries(requestPath);\n\t\t\t\tthis.sendRpcResponse(request.requestId, {\n\t\t\t\t\tpath: requestPath,\n\t\t\t\t\tentries: filterVisibleEntries(entries),\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tlogger.error(\n\t\t\t\t\t{\n\t\t\t\t\t\terr: error,\n\t\t\t\t\t\trequestId: request.requestId,\n\t\t\t\t\t\tmachineId: request.params.machineId,\n\t\t\t\t\t},\n\t\t\t\t\t\"rpc_hostfs_entries_error\",\n\t\t\t\t);\n\t\t\t\tthis.sendRpcError(request.requestId, error);\n\t\t\t}\n\t\t});\n\n\t\tthis.socket.on(\"rpc:fs:entries\", async (request) => {\n\t\t\ttry {\n\t\t\t\tconst { sessionId, path: requestPath } = request.params;\n\t\t\t\tlogger.debug(\n\t\t\t\t\t{ requestId: request.requestId, sessionId, path: requestPath },\n\t\t\t\t\t\"rpc_fs_entries\",\n\t\t\t\t);\n\t\t\t\tconst record = sessionManager.getSession(sessionId);\n\t\t\t\tif (!record || !record.cwd) {\n\t\t\t\t\tthrow new Error(\"Session not found or no working directory\");\n\t\t\t\t}\n\t\t\t\tconst resolved = requestPath\n\t\t\t\t\t? path.isAbsolute(requestPath)\n\t\t\t\t\t\t? requestPath\n\t\t\t\t\t\t: path.join(record.cwd, requestPath)\n\t\t\t\t\t: record.cwd;\n\t\t\t\tconst entries = await readDirectoryEntries(resolved);\n\t\t\t\tthis.sendRpcResponse(request.requestId, { path: resolved, entries });\n\t\t\t} catch (error) {\n\t\t\t\tlogger.error(\n\t\t\t\t\t{\n\t\t\t\t\t\terr: error,\n\t\t\t\t\t\trequestId: request.requestId,\n\t\t\t\t\t\tsessionId: request.params.sessionId,\n\t\t\t\t\t},\n\t\t\t\t\t\"rpc_fs_entries_error\",\n\t\t\t\t);\n\t\t\t\tthis.sendRpcError(request.requestId, error);\n\t\t\t}\n\t\t});\n\n\t\tthis.socket.on(\"rpc:fs:file\", async (request) => {\n\t\t\ttry {\n\t\t\t\tconst { sessionId, path: requestPath } = request.params;\n\t\t\t\tlogger.debug(\n\t\t\t\t\t{ requestId: request.requestId, sessionId, path: requestPath },\n\t\t\t\t\t\"rpc_fs_file\",\n\t\t\t\t);\n\t\t\t\tconst record = sessionManager.getSession(sessionId);\n\t\t\t\tif (!record || !record.cwd) {\n\t\t\t\t\tthrow new Error(\"Session not found or no working directory\");\n\t\t\t\t}\n\t\t\t\tconst resolved = path.isAbsolute(requestPath)\n\t\t\t\t\t? requestPath\n\t\t\t\t\t: path.join(record.cwd, requestPath);\n\t\t\t\tconst mimeType = resolveImageMimeType(resolved);\n\t\t\t\tif (mimeType) {\n\t\t\t\t\tconst buffer = await fs.readFile(resolved);\n\t\t\t\t\tconst preview: SessionFsFilePreview = {\n\t\t\t\t\t\tpath: resolved,\n\t\t\t\t\t\tpreviewType: \"image\",\n\t\t\t\t\t\tcontent: `data:${mimeType};base64,${buffer.toString(\"base64\")}`,\n\t\t\t\t\t\tmimeType,\n\t\t\t\t\t};\n\t\t\t\t\tthis.sendRpcResponse(request.requestId, preview);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst content = await fs.readFile(resolved, \"utf8\");\n\t\t\t\tconst preview: SessionFsFilePreview = {\n\t\t\t\t\tpath: resolved,\n\t\t\t\t\tpreviewType: \"code\",\n\t\t\t\t\tcontent,\n\t\t\t\t};\n\t\t\t\tthis.sendRpcResponse(request.requestId, preview);\n\t\t\t} catch (error) {\n\t\t\t\tlogger.error(\n\t\t\t\t\t{\n\t\t\t\t\t\terr: error,\n\t\t\t\t\t\trequestId: request.requestId,\n\t\t\t\t\t\tsessionId: request.params.sessionId,\n\t\t\t\t\t},\n\t\t\t\t\t\"rpc_fs_file_error\",\n\t\t\t\t);\n\t\t\t\tthis.sendRpcError(request.requestId, error);\n\t\t\t}\n\t\t});\n\n\t\tthis.socket.on(\"rpc:fs:resources\", async (request) => {\n\t\t\ttry {\n\t\t\t\tconst { sessionId } = request.params;\n\t\t\t\tlogger.debug(\n\t\t\t\t\t{ requestId: request.requestId, sessionId },\n\t\t\t\t\t\"rpc_fs_resources\",\n\t\t\t\t);\n\t\t\t\tconst record = sessionManager.getSession(sessionId);\n\t\t\t\tif (!record || !record.cwd) {\n\t\t\t\t\tthrow new Error(\"Session not found or no working directory\");\n\t\t\t\t}\n\t\t\t\tconst entries = await this.listSessionResources(record.cwd);\n\t\t\t\tthis.sendRpcResponse(request.requestId, {\n\t\t\t\t\trootPath: record.cwd,\n\t\t\t\t\tentries,\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tlogger.error(\n\t\t\t\t\t{\n\t\t\t\t\t\terr: error,\n\t\t\t\t\t\trequestId: request.requestId,\n\t\t\t\t\t\tsessionId: request.params.sessionId,\n\t\t\t\t\t},\n\t\t\t\t\t\"rpc_fs_resources_error\",\n\t\t\t\t);\n\t\t\t\tthis.sendRpcError(request.requestId, error);\n\t\t\t}\n\t\t});\n\n\t\t// Session discovery - list sessions from ACP agent\n\t\tthis.socket.on(\"rpc:sessions:discover\", async (request) => {\n\t\t\ttry {\n\t\t\t\tconst { cwd, backendId, cursor } = request.params;\n\t\t\t\tlogger.info(\n\t\t\t\t\t{ requestId: request.requestId, cwd, backendId, cursor },\n\t\t\t\t\t\"rpc_sessions_discover\",\n\t\t\t\t);\n\t\t\t\tconst result = await sessionManager.discoverSessions({\n\t\t\t\t\tcwd,\n\t\t\t\t\tbackendId,\n\t\t\t\t\tcursor,\n\t\t\t\t});\n\t\t\t\tthis.sendRpcResponse(request.requestId, result);\n\t\t\t} catch (error) {\n\t\t\t\tlogger.error(\n\t\t\t\t\t{\n\t\t\t\t\t\terr: error,\n\t\t\t\t\t\trequestId: request.requestId,\n\t\t\t\t\t},\n\t\t\t\t\t\"rpc_sessions_discover_error\",\n\t\t\t\t);\n\t\t\t\tthis.sendRpcError(request.requestId, error);\n\t\t\t}\n\t\t});\n\n\t\t// Load historical session from ACP agent\n\t\tthis.socket.on(\"rpc:session:load\", async (request) => {\n\t\t\ttry {\n\t\t\t\tconst { sessionId, cwd } = request.params;\n\t\t\t\tlogger.info(\n\t\t\t\t\t{ requestId: request.requestId, sessionId, cwd },\n\t\t\t\t\t\"rpc_session_load\",\n\t\t\t\t);\n\t\t\t\tconst session = await sessionManager.loadSession(sessionId, cwd);\n\t\t\t\tthis.sendRpcResponse(request.requestId, session);\n\t\t\t} catch (error) {\n\t\t\t\tlogger.error(\n\t\t\t\t\t{\n\t\t\t\t\t\terr: error,\n\t\t\t\t\t\trequestId: request.requestId,\n\t\t\t\t\t\tsessionId: request.params.sessionId,\n\t\t\t\t\t},\n\t\t\t\t\t\"rpc_session_load_error\",\n\t\t\t\t);\n\t\t\t\tthis.sendRpcError(request.requestId, error);\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate setupSessionManagerListeners() {\n\t\tconst { sessionManager } = this.options;\n\n\t\tsessionManager.onSessionUpdate((notification) => {\n\t\t\tif (this.connected) {\n\t\t\t\t// Cast through unknown since SDK and shared SessionNotification types are structurally compatible\n\t\t\t\tthis.socket.emit(\n\t\t\t\t\t\"session:update\",\n\t\t\t\t\tnotification as unknown as import(\"@mobvibe/shared\").SessionNotification,\n\t\t\t\t);\n\t\t\t}\n\t\t});\n\n\t\tsessionManager.onSessionError((payload) => {\n\t\t\tif (this.connected) {\n\t\t\t\tthis.socket.emit(\"session:error\", payload);\n\t\t\t}\n\t\t});\n\n\t\tsessionManager.onPermissionRequest((payload) => {\n\t\t\tif (this.connected) {\n\t\t\t\tthis.socket.emit(\"permission:request\", payload);\n\t\t\t}\n\t\t});\n\n\t\tsessionManager.onPermissionResult((payload) => {\n\t\t\tif (this.connected) {\n\t\t\t\tthis.socket.emit(\"permission:result\", payload);\n\t\t\t}\n\t\t});\n\n\t\tsessionManager.onTerminalOutput((event) => {\n\t\t\tif (this.connected) {\n\t\t\t\tthis.socket.emit(\"terminal:output\", event);\n\t\t\t}\n\t\t});\n\n\t\tsessionManager.onSessionsChanged((payload) => {\n\t\t\tif (this.connected) {\n\t\t\t\tlogger.info(\n\t\t\t\t\t{\n\t\t\t\t\t\tadded: payload.added.length,\n\t\t\t\t\t\tupdated: payload.updated.length,\n\t\t\t\t\t\tremoved: payload.removed.length,\n\t\t\t\t\t},\n\t\t\t\t\t\"sessions_changed_emit\",\n\t\t\t\t);\n\t\t\t\tthis.socket.emit(\"sessions:changed\", payload);\n\t\t\t}\n\t\t});\n\n\t\tsessionManager.onSessionAttached((payload) => {\n\t\t\tif (this.connected) {\n\t\t\t\tthis.socket.emit(\"session:attached\", payload);\n\t\t\t}\n\t\t});\n\n\t\tsessionManager.onSessionDetached((payload) => {\n\t\t\tif (this.connected) {\n\t\t\t\tthis.socket.emit(\"session:detached\", payload);\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate async listSessionResources(\n\t\trootPath: string,\n\t): Promise<SessionFsResourceEntry[]> {\n\t\tconst ig = await loadGitignore(rootPath);\n\t\tconst allFiles = await this.listAllFiles(rootPath, ig, rootPath, []);\n\t\treturn allFiles.map((filePath) => ({\n\t\t\tname: path.basename(filePath),\n\t\t\trelativePath: path.relative(rootPath, filePath),\n\t\t\tpath: filePath,\n\t\t}));\n\t}\n\n\tprivate async listAllFiles(\n\t\trootPath: string,\n\t\tig: Ignore,\n\t\tbaseDir: string,\n\t\tcollected: string[] = [],\n\t): Promise<string[]> {\n\t\tif (collected.length >= MAX_RESOURCE_FILES) {\n\t\t\treturn collected;\n\t\t}\n\t\tconst entries = await fs.readdir(rootPath, { withFileTypes: true });\n\t\tfor (const entry of entries) {\n\t\t\tif (collected.length >= MAX_RESOURCE_FILES) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tconst entryPath = path.join(rootPath, entry.name);\n\t\t\tconst relativePath = path.relative(baseDir, entryPath);\n\n\t\t\t// Check gitignore (add trailing slash for directories)\n\t\t\tconst checkPath = entry.isDirectory() ? `${relativePath}/` : relativePath;\n\t\t\tif (ig.ignores(checkPath)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (entry.isDirectory()) {\n\t\t\t\tawait this.listAllFiles(entryPath, ig, baseDir, collected);\n\t\t\t} else if (entry.isFile()) {\n\t\t\t\tcollected.push(entryPath);\n\t\t\t}\n\t\t}\n\t\treturn collected;\n\t}\n\n\tprivate sendRpcResponse<T>(requestId: string, result: T) {\n\t\tconst response: RpcResponse<T> = { requestId, result };\n\t\tthis.socket.emit(\"rpc:response\", response);\n\t\tlogger.debug({ requestId }, \"rpc_response_sent\");\n\t}\n\n\tprivate sendRpcError(requestId: string, error: unknown) {\n\t\tconst message = error instanceof Error ? error.message : \"Unknown error\";\n\t\tconst detail = error instanceof Error ? error.stack : undefined;\n\t\tlogger.error(\n\t\t\t{\n\t\t\t\trequestId,\n\t\t\t\terr: error,\n\t\t\t\tmessage,\n\t\t\t\tdetail,\n\t\t\t},\n\t\t\t\"rpc_response_error_sent\",\n\t\t);\n\t\tconst response: RpcResponse<unknown> = {\n\t\t\trequestId,\n\t\t\terror: {\n\t\t\t\tcode: \"INTERNAL_ERROR\",\n\t\t\t\tmessage,\n\t\t\t\tretryable: true,\n\t\t\t\tscope: \"request\",\n\t\t\t\tdetail,\n\t\t\t},\n\t\t};\n\t\tthis.socket.emit(\"rpc:response\", response);\n\t}\n\n\tprivate register() {\n\t\tconst { config, sessionManager } = this.options;\n\t\tlogger.info({ machineId: config.machineId }, \"cli_register_emit\");\n\t\tthis.socket.emit(\"cli:register\", {\n\t\t\tmachineId: config.machineId,\n\t\t\thostname: config.hostname,\n\t\t\tversion: config.clientVersion,\n\t\t\tbackends: config.acpBackends.map((backend) => ({\n\t\t\t\tbackendId: backend.id,\n\t\t\t\tbackendLabel: backend.label,\n\t\t\t})),\n\t\t\tdefaultBackendId: config.defaultAcpBackendId,\n\t\t});\n\t\tlogger.info({ machineId: config.machineId }, \"cli_register_sessions_list\");\n\t\t// Send current sessions list\n\t\tthis.socket.emit(\"sessions:list\", sessionManager.listSessions());\n\t}\n\n\tprivate startHeartbeat() {\n\t\tthis.stopHeartbeat();\n\t\tthis.heartbeatInterval = setInterval(() => {\n\t\t\tif (this.connected) {\n\t\t\t\tthis.socket.emit(\"cli:heartbeat\");\n\t\t\t\tthis.socket.emit(\n\t\t\t\t\t\"sessions:list\",\n\t\t\t\t\tthis.options.sessionManager.listSessions(),\n\t\t\t\t);\n\t\t\t}\n\t\t}, 30000);\n\t}\n\n\tprivate stopHeartbeat() {\n\t\tif (this.heartbeatInterval) {\n\t\t\tclearInterval(this.heartbeatInterval);\n\t\t\tthis.heartbeatInterval = undefined;\n\t\t}\n\t}\n\n\tconnect() {\n\t\tthis.socket.connect();\n\t}\n\n\tdisconnect() {\n\t\tthis.stopHeartbeat();\n\t\tthis.socket.disconnect();\n\t}\n\n\tisConnected() {\n\t\treturn this.connected;\n\t}\n}\n"],"mappings":"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","names":["os","path","fs","path","os","path","spawn","fs","path","randomUUID","EventEmitter","fs","fs","EventEmitter","randomUUID","EventEmitter","fs","path","path","fs","EventEmitter","preview","fs","path","spawn"]}
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/index.ts", "../src/auth/credentials.ts", "../src/auth/login.ts", "../src/lib/logger.ts", "../src/config.ts", "../src/config-loader.ts", "../src/daemon/daemon.ts", "../src/acp/session-manager.ts", "../src/wal/compactor.ts", "../src/wal/migrations.ts", "../src/wal/seq-generator.ts", "../src/wal/wal-store.ts", "../src/acp/acp-connection.ts", "../src/e2ee/crypto-service.ts", "../src/daemon/socket-client.ts", "../src/lib/git-utils.ts"],
4
+ "sourcesContent": [
5
+ "import { Database } from \"bun:sqlite\";\nimport { Command } from \"commander\";\nimport { loadCredentials } from \"./auth/credentials.js\";\nimport { login, loginStatus, logout } from \"./auth/login.js\";\nimport { getCliConfig } from \"./config.js\";\nimport { DaemonManager } from \"./daemon/daemon.js\";\nimport { logger } from \"./lib/logger.js\";\nimport { WalCompactor, WalStore } from \"./wal/index.js\";\n\nconst program = new Command();\n\nprogram\n\t.name(\"mobvibe\")\n\t.description(\"Mobvibe CLI - Connect local ACP backends to the gateway\")\n\t.version(\"0.0.0\");\n\nprogram\n\t.command(\"start\")\n\t.description(\"Start the mobvibe daemon\")\n\t.option(\"--gateway <url>\", \"Gateway URL\", process.env.MOBVIBE_GATEWAY_URL)\n\t.option(\"--foreground\", \"Run in foreground instead of detaching\")\n\t.action(async (options) => {\n\t\tif (options.gateway) {\n\t\t\tprocess.env.MOBVIBE_GATEWAY_URL = options.gateway;\n\t\t}\n\t\tconst config = await getCliConfig();\n\t\tconst daemon = new DaemonManager(config);\n\t\tawait daemon.start({ foreground: options.foreground });\n\t});\n\nprogram\n\t.command(\"stop\")\n\t.description(\"Stop the mobvibe daemon\")\n\t.action(async () => {\n\t\tconst config = await getCliConfig();\n\t\tconst daemon = new DaemonManager(config);\n\t\tawait daemon.stop();\n\t});\n\nprogram\n\t.command(\"status\")\n\t.description(\"Show daemon status\")\n\t.action(async () => {\n\t\tconst config = await getCliConfig();\n\t\tconst daemon = new DaemonManager(config);\n\t\tconst status = await daemon.status();\n\t\tif (status.running) {\n\t\t\tlogger.info({ pid: status.pid }, \"daemon_status_running\");\n\t\t\tconsole.log(`Daemon is running (PID ${status.pid})`);\n\t\t\tif (status.connected !== undefined) {\n\t\t\t\tconsole.log(`Connected to gateway: ${status.connected ? \"yes\" : \"no\"}`);\n\t\t\t}\n\t\t\tif (status.sessionCount !== undefined) {\n\t\t\t\tconsole.log(`Active sessions: ${status.sessionCount}`);\n\t\t\t}\n\t\t} else {\n\t\t\tlogger.info(\"daemon_status_not_running\");\n\t\t\tconsole.log(\"Daemon is not running\");\n\t\t}\n\t});\n\nprogram\n\t.command(\"logs\")\n\t.description(\"Show daemon logs\")\n\t.option(\"-f, --follow\", \"Follow log output\")\n\t.option(\"-n, --lines <number>\", \"Number of lines to show\", \"50\")\n\t.action(async (options) => {\n\t\tconst config = await getCliConfig();\n\t\tconst daemon = new DaemonManager(config);\n\t\tawait daemon.logs({\n\t\t\tfollow: options.follow,\n\t\t\tlines: Number.parseInt(options.lines, 10),\n\t\t});\n\t});\n\nprogram\n\t.command(\"login\")\n\t.description(\"Authenticate with an API key from the WebUI\")\n\t.action(async () => {\n\t\tconst result = await login();\n\t\tif (!result.success) {\n\t\t\tlogger.error({ err: result.error }, \"login_failed\");\n\t\t\tconsole.error(`Login failed: ${result.error}`);\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram\n\t.command(\"logout\")\n\t.description(\"Remove stored credentials\")\n\t.action(async () => {\n\t\tawait logout();\n\t});\n\nprogram\n\t.command(\"auth-status\")\n\t.description(\"Show authentication status\")\n\t.action(async () => {\n\t\tawait loginStatus();\n\t});\n\nconst e2eeCmd = program.command(\"e2ee\").description(\"E2EE key management\");\n\ne2eeCmd\n\t.command(\"show\")\n\t.description(\"Display the master secret for pairing other devices\")\n\t.action(async () => {\n\t\tconst credentials = await loadCredentials();\n\t\tif (!credentials) {\n\t\t\tconsole.error(\"Not logged in. Run 'mobvibe login' first.\");\n\t\t\tprocess.exit(1);\n\t\t}\n\n\t\t// Convert standard base64 to base64url for URL safety\n\t\tconst base64url = credentials.masterSecret\n\t\t\t.replace(/\\+/g, \"-\")\n\t\t\t.replace(/\\//g, \"_\")\n\t\t\t.replace(/=+$/, \"\");\n\t\tconst pairingUrl = `mobvibe://pair?secret=${base64url}`;\n\n\t\t// Display QR code for mobile scanning\n\t\tconst QRCode = await import(\"qrcode\");\n\t\tconst qrText = await QRCode.toString(pairingUrl, {\n\t\t\ttype: \"terminal\",\n\t\t\tsmall: true,\n\t\t});\n\t\tconsole.log(qrText);\n\n\t\tconsole.log(\"Master secret (for pairing WebUI/Tauri devices):\");\n\t\tconsole.log(` ${credentials.masterSecret}`);\n\t\tconsole.log(\n\t\t\t\"\\nScan the QR code with your phone, or paste the secret into WebUI Settings > E2EE > Pair.\",\n\t\t);\n\t});\n\ne2eeCmd\n\t.command(\"status\")\n\t.description(\"Show E2EE key status\")\n\t.action(async () => {\n\t\tconst { initCrypto, deriveAuthKeyPair, deriveContentKeyPair, getSodium } =\n\t\t\tawait import(\"@mobvibe/shared\");\n\t\tconst credentials = await loadCredentials();\n\t\tif (!credentials) {\n\t\t\tconsole.log(\"Status: Not logged in\");\n\t\t\tconsole.log(\"Run 'mobvibe login' to authenticate.\");\n\t\t\treturn;\n\t\t}\n\t\tawait initCrypto();\n\t\tconst sodium = getSodium();\n\t\tconst masterSecret = sodium.from_base64(\n\t\t\tcredentials.masterSecret,\n\t\t\tsodium.base64_variants.ORIGINAL,\n\t\t);\n\t\tconst authKp = deriveAuthKeyPair(masterSecret);\n\t\tconst contentKp = deriveContentKeyPair(masterSecret);\n\t\tconst authPub = sodium.to_base64(\n\t\t\tauthKp.publicKey,\n\t\t\tsodium.base64_variants.ORIGINAL,\n\t\t);\n\t\tconst contentPub = sodium.to_base64(\n\t\t\tcontentKp.publicKey,\n\t\t\tsodium.base64_variants.ORIGINAL,\n\t\t);\n\t\tconsole.log(\"Status: E2EE enabled\");\n\t\tconsole.log(`Auth public key: ${authPub.slice(0, 16)}...`);\n\t\tconsole.log(`Content public key: ${contentPub.slice(0, 16)}...`);\n\t\tconsole.log(`Saved: ${new Date(credentials.createdAt).toLocaleString()}`);\n\t});\n\nprogram\n\t.command(\"compact\")\n\t.description(\"Compact the WAL database to reclaim space\")\n\t.option(\"--session <id>\", \"Compact a specific session only\")\n\t.option(\"--dry-run\", \"Show what would be deleted without actually deleting\")\n\t.option(\"-v, --verbose\", \"Show detailed output\")\n\t.action(async (options) => {\n\t\tconst config = await getCliConfig();\n\n\t\tif (!config.compaction.enabled && !options.dryRun) {\n\t\t\tconsole.log(\"Compaction is disabled in configuration.\");\n\t\t\tconsole.log(\"Set MOBVIBE_COMPACTION_ENABLED=true to enable.\");\n\t\t\treturn;\n\t\t}\n\n\t\tconst walStore = new WalStore(config.walDbPath);\n\t\tconst db = new Database(config.walDbPath);\n\t\tconst compactor = new WalCompactor(walStore, config.compaction, db);\n\n\t\tconsole.log(\n\t\t\toptions.dryRun\n\t\t\t\t? \"Dry run - no changes will be made\"\n\t\t\t\t: \"Starting compaction...\",\n\t\t);\n\n\t\ttry {\n\t\t\tif (options.session) {\n\t\t\t\tconst stats = await compactor.compactSession(options.session, {\n\t\t\t\t\tdryRun: options.dryRun,\n\t\t\t\t});\n\t\t\t\tconsole.log(`Session ${options.session}:`);\n\t\t\t\tconsole.log(` Acked events deleted: ${stats.ackedEventsDeleted}`);\n\t\t\t\tconsole.log(` Old revisions deleted: ${stats.oldRevisionsDeleted}`);\n\t\t\t\tconsole.log(` Duration: ${stats.durationMs.toFixed(2)}ms`);\n\t\t\t} else {\n\t\t\t\tconst result = await compactor.compactAll({\n\t\t\t\t\tdryRun: options.dryRun,\n\t\t\t\t});\n\n\t\t\t\tif (options.verbose) {\n\t\t\t\t\tfor (const stats of result.stats) {\n\t\t\t\t\t\tif (stats.ackedEventsDeleted > 0 || stats.oldRevisionsDeleted > 0) {\n\t\t\t\t\t\t\tconsole.log(`\\nSession ${stats.sessionId}:`);\n\t\t\t\t\t\t\tconsole.log(\n\t\t\t\t\t\t\t\t` Acked events deleted: ${stats.ackedEventsDeleted}`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tconsole.log(\n\t\t\t\t\t\t\t\t` Old revisions deleted: ${stats.oldRevisionsDeleted}`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif (result.skipped.length > 0) {\n\t\t\t\t\t\tconsole.log(\n\t\t\t\t\t\t\t`\\nSkipped (active sessions): ${result.skipped.join(\", \")}`,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst totalDeleted = result.stats.reduce(\n\t\t\t\t\t(sum, s) => sum + s.ackedEventsDeleted + s.oldRevisionsDeleted,\n\t\t\t\t\t0,\n\t\t\t\t);\n\n\t\t\t\tconsole.log(`\\nSummary:`);\n\t\t\t\tconsole.log(` Sessions processed: ${result.stats.length}`);\n\t\t\t\tconsole.log(` Sessions skipped: ${result.skipped.length}`);\n\t\t\t\tconsole.log(\n\t\t\t\t\t` Total events ${options.dryRun ? \"to delete\" : \"deleted\"}: ${totalDeleted}`,\n\t\t\t\t);\n\t\t\t\tconsole.log(` Duration: ${result.totalDurationMs.toFixed(2)}ms`);\n\t\t\t}\n\t\t} finally {\n\t\t\twalStore.close();\n\t\t\tdb.close();\n\t\t}\n\t});\n\nexport async function run() {\n\tawait program.parseAsync(process.argv);\n}\n\nrun().catch((error) => {\n\tlogger.error({ err: error }, \"cli_run_error\");\n\tconsole.error(\"Error:\", error.message);\n\tprocess.exit(1);\n});\n",
6
+ "/**\n * Credentials management for CLI authentication.\n * Stores API key in ~/.mobvibe/credentials.json\n */\n\nimport fs from \"node:fs/promises\";\nimport os from \"node:os\";\nimport path from \"node:path\";\n\nexport interface Credentials {\n\t/** Base64-encoded master secret (32 bytes) — the single root credential */\n\tmasterSecret: string;\n\t/** When the credentials were created */\n\tcreatedAt: number;\n\t/** Optional: custom gateway URL (user can manually set this) */\n\tgatewayUrl?: string;\n}\n\nconst MOBVIBE_DIR =\n\tprocess.env.MOBVIBE_HOME ?? path.join(os.homedir(), \".mobvibe\");\nconst CREDENTIALS_FILE = path.join(MOBVIBE_DIR, \"credentials.json\");\n\n/**\n * Ensure the mobvibe directory exists.\n */\nasync function ensureMobvibeDir(): Promise<void> {\n\tawait fs.mkdir(MOBVIBE_DIR, { recursive: true });\n}\n\n/**\n * Load credentials from the credentials file.\n * Returns null if no credentials exist.\n */\nexport async function loadCredentials(): Promise<Credentials | null> {\n\ttry {\n\t\tconst data = await fs.readFile(CREDENTIALS_FILE, \"utf8\");\n\t\tconst credentials = JSON.parse(data) as Credentials;\n\n\t\t// Validate required fields\n\t\tif (!credentials.masterSecret) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn credentials;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n/**\n * Save credentials to the credentials file.\n */\nexport async function saveCredentials(credentials: Credentials): Promise<void> {\n\tawait ensureMobvibeDir();\n\tawait fs.writeFile(\n\t\tCREDENTIALS_FILE,\n\t\tJSON.stringify(credentials, null, 2),\n\t\t{ mode: 0o600 }, // Read/write only for owner\n\t);\n}\n\n/**\n * Delete the credentials file.\n */\nexport async function deleteCredentials(): Promise<void> {\n\ttry {\n\t\tawait fs.unlink(CREDENTIALS_FILE);\n\t} catch {\n\t\t// Ignore if file doesn't exist\n\t}\n}\n\n/**\n * Check if credentials exist.\n */\nexport async function hasCredentials(): Promise<boolean> {\n\tconst credentials = await loadCredentials();\n\treturn credentials !== null;\n}\n\n/**\n * Get the master secret from credentials.\n * Also checks MOBVIBE_MASTER_SECRET env var as override.\n * Returns base64-encoded string.\n */\nexport async function getMasterSecret(): Promise<string | undefined> {\n\t// Environment variable takes precedence\n\tif (process.env.MOBVIBE_MASTER_SECRET) {\n\t\treturn process.env.MOBVIBE_MASTER_SECRET;\n\t}\n\n\tconst credentials = await loadCredentials();\n\treturn credentials?.masterSecret;\n}\n\n/** Default production gateway URL */\nconst DEFAULT_GATEWAY_URL = \"https://mobvibe.zeabur.app\";\n\n/**\n * Get the gateway URL with the following priority:\n * 1. MOBVIBE_GATEWAY_URL env var\n * 2. gatewayUrl in credentials file\n * 3. Default production URL\n */\nexport async function getGatewayUrl(): Promise<string> {\n\t// Environment variable takes precedence\n\tif (process.env.MOBVIBE_GATEWAY_URL) {\n\t\treturn process.env.MOBVIBE_GATEWAY_URL;\n\t}\n\n\t// Check credentials file for custom gateway URL\n\tconst credentials = await loadCredentials();\n\tif (credentials?.gatewayUrl) {\n\t\treturn credentials.gatewayUrl;\n\t}\n\n\t// Default to production\n\treturn DEFAULT_GATEWAY_URL;\n}\n",
7
+ "/**\n * Login command for CLI authentication.\n * Generates a master secret, authenticates via email/password,\n * and registers the device public key with the gateway.\n */\n\nimport os from \"node:os\";\nimport * as readline from \"node:readline/promises\";\nimport { Writable } from \"node:stream\";\nimport {\n\tderiveAuthKeyPair,\n\tgenerateMasterSecret,\n\tgetSodium,\n\tinitCrypto,\n} from \"@mobvibe/shared\";\nimport { logger } from \"../lib/logger.js\";\nimport {\n\ttype Credentials,\n\tdeleteCredentials,\n\tgetGatewayUrl,\n\tloadCredentials,\n\tsaveCredentials,\n} from \"./credentials.js\";\n\nexport interface LoginResult {\n\tsuccess: boolean;\n\terror?: string;\n}\n\n/**\n * Read a password from stdin without echoing characters.\n * Prints '*' for each character typed.\n */\nfunction readPassword(prompt: string): Promise<string> {\n\treturn new Promise((resolve, reject) => {\n\t\tprocess.stdout.write(prompt);\n\t\tconst chars: string[] = [];\n\n\t\tif (!process.stdin.isTTY) {\n\t\t\t// Non-interactive: fall back to readline\n\t\t\tconst rl = readline.createInterface({\n\t\t\t\tinput: process.stdin,\n\t\t\t\toutput: new Writable({ write: (_c, _e, cb) => cb() }),\n\t\t\t});\n\t\t\trl.question(\"\").then((answer) => {\n\t\t\t\trl.close();\n\t\t\t\tprocess.stdout.write(\"\\n\");\n\t\t\t\tresolve(answer);\n\t\t\t}, reject);\n\t\t\treturn;\n\t\t}\n\n\t\tprocess.stdin.setRawMode(true);\n\t\tprocess.stdin.resume();\n\t\tprocess.stdin.setEncoding(\"utf8\");\n\n\t\tconst onData = (key: string) => {\n\t\t\tfor (const ch of key) {\n\t\t\t\tconst code = ch.charCodeAt(0);\n\t\t\t\tif (ch === \"\\r\" || ch === \"\\n\") {\n\t\t\t\t\t// Enter\n\t\t\t\t\tprocess.stdin.setRawMode(false);\n\t\t\t\t\tprocess.stdin.pause();\n\t\t\t\t\tprocess.stdin.removeListener(\"data\", onData);\n\t\t\t\t\tprocess.stdout.write(\"\\n\");\n\t\t\t\t\tresolve(chars.join(\"\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (code === 3) {\n\t\t\t\t\t// Ctrl-C\n\t\t\t\t\tprocess.stdin.setRawMode(false);\n\t\t\t\t\tprocess.stdin.pause();\n\t\t\t\t\tprocess.stdin.removeListener(\"data\", onData);\n\t\t\t\t\tprocess.stdout.write(\"\\n\");\n\t\t\t\t\treject(new Error(\"User cancelled\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (code === 127 || code === 8) {\n\t\t\t\t\t// Backspace\n\t\t\t\t\tif (chars.length > 0) {\n\t\t\t\t\t\tchars.pop();\n\t\t\t\t\t\tprocess.stdout.write(\"\\b \\b\");\n\t\t\t\t\t}\n\t\t\t\t} else if (code >= 32) {\n\t\t\t\t\tchars.push(ch);\n\t\t\t\t\tprocess.stdout.write(\"*\");\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\tprocess.stdin.on(\"data\", onData);\n\t});\n}\n\nexport async function login(): Promise<LoginResult> {\n\tawait initCrypto();\n\tconst sodium = getSodium();\n\n\tlogger.info(\"login_prompt_start\");\n\tconsole.log(\"Mobvibe E2EE Login\\n\");\n\n\tconst rl = readline.createInterface({\n\t\tinput: process.stdin,\n\t\toutput: process.stdout,\n\t});\n\n\ttry {\n\t\tconst email = await rl.question(\"Email: \");\n\t\tif (!email.trim()) {\n\t\t\treturn { success: false, error: \"No email provided\" };\n\t\t}\n\n\t\trl.close();\n\t\tconst password = await readPassword(\"Password: \");\n\t\tif (!password.trim()) {\n\t\t\treturn { success: false, error: \"No password provided\" };\n\t\t}\n\n\t\tconst gatewayUrl = await getGatewayUrl();\n\n\t\t// Step 1: Sign in via Better Auth\n\t\tconsole.log(\"\\nSigning in...\");\n\t\tconst signInResponse = await fetch(`${gatewayUrl}/api/auth/sign-in/email`, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: { \"Content-Type\": \"application/json\" },\n\t\t\tbody: JSON.stringify({\n\t\t\t\temail: email.trim(),\n\t\t\t\tpassword: password.trim(),\n\t\t\t}),\n\t\t});\n\n\t\tif (!signInResponse.ok) {\n\t\t\tconst body = await signInResponse.text();\n\t\t\tlogger.warn(\n\t\t\t\t{ status: signInResponse.status, body },\n\t\t\t\t\"login_sign_in_failed\",\n\t\t\t);\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: `Sign-in failed (${signInResponse.status}): ${body}`,\n\t\t\t};\n\t\t}\n\n\t\t// Extract session cookie from response\n\t\tconst setCookieHeaders = signInResponse.headers.getSetCookie?.() ?? [];\n\t\tconst cookieHeader = setCookieHeaders\n\t\t\t.map((c: string) => c.split(\";\")[0])\n\t\t\t.join(\"; \");\n\n\t\tif (!cookieHeader) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: \"No session cookie received from sign-in\",\n\t\t\t};\n\t\t}\n\n\t\t// Step 2: Generate master secret and derive public key\n\t\tconst masterSecret = generateMasterSecret();\n\t\tconst authKeyPair = deriveAuthKeyPair(masterSecret);\n\t\tconst publicKeyBase64 = sodium.to_base64(\n\t\t\tauthKeyPair.publicKey,\n\t\t\tsodium.base64_variants.ORIGINAL,\n\t\t);\n\n\t\t// Step 3: Register device public key\n\t\tconsole.log(\"Registering device...\");\n\t\tconst registerResponse = await fetch(`${gatewayUrl}/auth/device/register`, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\tCookie: cookieHeader,\n\t\t\t},\n\t\t\tbody: JSON.stringify({\n\t\t\t\tpublicKey: publicKeyBase64,\n\t\t\t\tdeviceName: os.hostname(),\n\t\t\t}),\n\t\t});\n\n\t\tif (!registerResponse.ok) {\n\t\t\tconst body = await registerResponse.text();\n\t\t\tlogger.warn(\n\t\t\t\t{ status: registerResponse.status, body },\n\t\t\t\t\"login_device_register_failed\",\n\t\t\t);\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: `Device registration failed (${registerResponse.status}): ${body}`,\n\t\t\t};\n\t\t}\n\n\t\t// Step 4: Store master secret\n\t\tconst masterSecretBase64 = sodium.to_base64(\n\t\t\tmasterSecret,\n\t\t\tsodium.base64_variants.ORIGINAL,\n\t\t);\n\t\tconst credentials: Credentials = {\n\t\t\tmasterSecret: masterSecretBase64,\n\t\t\tcreatedAt: Date.now(),\n\t\t};\n\t\tawait saveCredentials(credentials);\n\t\tlogger.info(\"login_credentials_saved\");\n\n\t\tconsole.log(\"\\nLogin successful!\");\n\t\tconsole.log(\n\t\t\t\"\\nWARNING: The master secret below will appear in your terminal history.\",\n\t\t);\n\t\tconsole.log(\n\t\t\t\" Clear your terminal after copying it, or use 'mobvibe e2ee show' later.\",\n\t\t);\n\t\tconsole.log(\"\\nYour master secret (for pairing WebUI/Tauri devices):\");\n\t\tconsole.log(` ${masterSecretBase64}`);\n\t\tconsole.log(\n\t\t\t\"\\nKeep this secret safe. You can view it again with 'mobvibe e2ee show'.\",\n\t\t);\n\t\tconsole.log(\"Run 'mobvibe start' to connect to the gateway.\");\n\n\t\treturn { success: true };\n\t} finally {\n\t\trl.close();\n\t}\n}\n\n/**\n * Logout - delete stored credentials.\n */\nexport async function logout(): Promise<void> {\n\tawait deleteCredentials();\n\tlogger.info(\"logout_complete\");\n\tconsole.log(\"Logged out successfully. Credentials deleted.\");\n}\n\n/**\n * Show current login status.\n */\nexport async function loginStatus(): Promise<void> {\n\tconst credentials = await loadCredentials();\n\tif (credentials) {\n\t\tawait initCrypto();\n\t\tconst sodium = getSodium();\n\t\tconst masterSecret = sodium.from_base64(\n\t\t\tcredentials.masterSecret,\n\t\t\tsodium.base64_variants.ORIGINAL,\n\t\t);\n\t\tconst authKeyPair = deriveAuthKeyPair(masterSecret);\n\t\tconst pubKeyBase64 = sodium.to_base64(\n\t\t\tauthKeyPair.publicKey,\n\t\t\tsodium.base64_variants.ORIGINAL,\n\t\t);\n\n\t\tlogger.info(\"login_status_logged_in\");\n\t\tconsole.log(\"Status: Logged in (E2EE)\");\n\t\tconsole.log(`Auth public key: ${pubKeyBase64.slice(0, 16)}...`);\n\t\tconsole.log(`Saved: ${new Date(credentials.createdAt).toLocaleString()}`);\n\t} else {\n\t\tlogger.info(\"login_status_logged_out\");\n\t\tconsole.log(\"Status: Not logged in\");\n\t\tconsole.log(\"Run 'mobvibe login' to authenticate.\");\n\t}\n}\n",
8
+ "import pino from \"pino\";\n\nconst LOG_LEVEL = process.env.LOG_LEVEL ?? \"info\";\nconst isPretty = process.env.NODE_ENV !== \"production\";\n\nconst redact = {\n\tpaths: [\n\t\t\"req.headers.authorization\",\n\t\t\"req.headers.cookie\",\n\t\t\"req.headers['x-api-key']\",\n\t\t\"headers.authorization\",\n\t\t\"headers.cookie\",\n\t\t\"headers['x-api-key']\",\n\t\t\"apiKey\",\n\t\t\"token\",\n\t],\n\tcensor: \"[redacted]\",\n};\n\nconst transport = isPretty\n\t? {\n\t\t\ttarget: \"pino-pretty\",\n\t\t\toptions: {\n\t\t\t\tcolorize: true,\n\t\t\t\ttranslateTime: \"SYS:standard\",\n\t\t\t\tignore: \"pid,hostname\",\n\t\t\t},\n\t\t}\n\t: undefined;\n\nexport const logger = pino(\n\t{\n\t\tlevel: LOG_LEVEL,\n\t\tredact,\n\t\tbase: { service: \"mobvibe-cli\" },\n\t\tserializers: {\n\t\t\terr: pino.stdSerializers.err,\n\t\t\terror: pino.stdSerializers.err,\n\t\t},\n\t},\n\ttransport ? pino.transport(transport) : undefined,\n);\n",
9
+ "import os from \"node:os\";\nimport path from \"node:path\";\nimport type { AcpBackendId, UserAgentConfig } from \"@mobvibe/shared\";\nimport { getGatewayUrl } from \"./auth/credentials.js\";\nimport { loadUserConfig } from \"./config-loader.js\";\nimport { logger } from \"./lib/logger.js\";\n\nexport type AcpBackendConfig = {\n\tid: AcpBackendId;\n\tlabel: string;\n\tcommand: string;\n\targs: string[];\n\tenvOverrides?: Record<string, string>;\n};\n\nexport type CompactionConfig = {\n\t/** Enable automatic compaction */\n\tenabled: boolean;\n\t/** Keep acked events for this many days (default: 7) */\n\tackedEventRetentionDays: number;\n\t/** Always keep this many latest revisions (default: 2) */\n\tkeepLatestRevisionsCount: number;\n\t/** Run compaction on daemon startup (default: false) */\n\trunOnStartup: boolean;\n\t/** Run compaction every N hours (default: 24) */\n\trunIntervalHours: number;\n\t/** Safety: minimum events to keep per session (default: 1000) */\n\tminEventsToKeep: number;\n\t// P1-3: Removed unused config items:\n\t// - consolidateChunksAfterSec: chunk consolidation not implemented\n\t// - keepOldRevisionsDays: only keepLatestRevisionsCount is used\n};\n\nexport const DEFAULT_COMPACTION_CONFIG: CompactionConfig = {\n\tenabled: false, // P0-8: Disabled by default - compaction deletes acked events which are the only history source\n\tackedEventRetentionDays: 7,\n\tkeepLatestRevisionsCount: 2,\n\trunOnStartup: false, // P0-8: Disabled - only run via explicit `mobvibe compact` command\n\trunIntervalHours: 24,\n\tminEventsToKeep: 1000,\n};\n\nexport type CliConfig = {\n\tgatewayUrl: string;\n\tacpBackends: AcpBackendConfig[];\n\tclientName: string;\n\tclientVersion: string;\n\thomePath: string;\n\tlogPath: string;\n\tpidFile: string;\n\twalDbPath: string;\n\tmachineId: string;\n\thostname: string;\n\tplatform: string;\n\tuserConfigPath?: string;\n\tuserConfigErrors?: string[];\n\tcompaction: CompactionConfig;\n};\n\n// Default opencode backend\nconst DEFAULT_OPENCODE_BACKEND: AcpBackendConfig = {\n\tid: \"opencode\",\n\tlabel: \"opencode\",\n\tcommand: \"opencode\",\n\targs: [\"acp\"],\n};\n\nconst generateMachineId = (): string => {\n\tconst hostname = os.hostname();\n\tconst platform = os.platform();\n\tconst arch = os.arch();\n\tconst username = os.userInfo().username;\n\treturn `${hostname}-${platform}-${arch}-${username}`;\n};\n\nconst userAgentToBackendConfig = (\n\tagent: UserAgentConfig,\n): AcpBackendConfig => ({\n\tid: agent.id,\n\tlabel: agent.label ?? agent.id,\n\tcommand: agent.command,\n\targs: agent.args ?? [],\n\tenvOverrides: agent.env,\n});\n\nconst mergeBackends = (\n\tdefaultBackend: AcpBackendConfig,\n\tuserAgents: UserAgentConfig[] | undefined,\n): AcpBackendConfig[] => {\n\t// No user agents: use default opencode only\n\tif (!userAgents || userAgents.length === 0) {\n\t\treturn [defaultBackend];\n\t}\n\n\t// Check if user defined opencode (override case)\n\tconst userOpencode = userAgents.find((a) => a.id === \"opencode\");\n\n\tif (userOpencode) {\n\t\t// User overrides opencode - use only user-defined agents\n\t\treturn userAgents.map(userAgentToBackendConfig);\n\t}\n\n\t// User didn't define opencode - prepend default opencode to user agents\n\treturn [defaultBackend, ...userAgents.map(userAgentToBackendConfig)];\n};\n\nexport const getCliConfig = async (): Promise<CliConfig> => {\n\tconst env = process.env;\n\tconst homePath = env.MOBVIBE_HOME ?? path.join(os.homedir(), \".mobvibe\");\n\n\t// Load user configuration\n\tconst userConfigResult = await loadUserConfig(homePath);\n\n\t// Log any config errors as warnings\n\tif (userConfigResult.errors.length > 0) {\n\t\tfor (const error of userConfigResult.errors) {\n\t\t\tlogger.warn({ configPath: userConfigResult.path, error }, \"config_error\");\n\t\t}\n\t}\n\n\t// Merge backends\n\tconst backends = mergeBackends(\n\t\tDEFAULT_OPENCODE_BACKEND,\n\t\tuserConfigResult.config?.agents,\n\t);\n\n\t// Get gateway URL (env var > credentials file > default production URL)\n\tconst gatewayUrl = await getGatewayUrl();\n\n\treturn {\n\t\tgatewayUrl,\n\t\tacpBackends: backends,\n\t\tclientName: env.MOBVIBE_ACP_CLIENT_NAME ?? \"mobvibe-cli\",\n\t\tclientVersion: env.MOBVIBE_ACP_CLIENT_VERSION ?? \"0.0.0\",\n\t\thomePath,\n\t\tlogPath: path.join(homePath, \"logs\"),\n\t\tpidFile: path.join(homePath, \"daemon.pid\"),\n\t\twalDbPath: path.join(homePath, \"events.db\"),\n\t\tmachineId: env.MOBVIBE_MACHINE_ID ?? generateMachineId(),\n\t\thostname: os.hostname(),\n\t\tplatform: os.platform(),\n\t\tuserConfigPath: userConfigResult.path,\n\t\tuserConfigErrors:\n\t\t\tuserConfigResult.errors.length > 0 ? userConfigResult.errors : undefined,\n\t\tcompaction: {\n\t\t\t...DEFAULT_COMPACTION_CONFIG,\n\t\t\t// Allow enabling via env var\n\t\t\tenabled: env.MOBVIBE_COMPACTION_ENABLED === \"true\",\n\t\t},\n\t};\n};\n",
10
+ "import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { MobvibeUserConfig, UserAgentConfig } from \"@mobvibe/shared\";\n\nexport type ConfigLoadResult = {\n\tconfig: MobvibeUserConfig | null;\n\terrors: string[];\n\tpath: string;\n};\n\nconst CONFIG_FILENAME = \".config.json\";\n\nconst validateAgentConfig = (\n\tagent: unknown,\n\tindex: number,\n): { valid: UserAgentConfig | null; errors: string[] } => {\n\tconst errors: string[] = [];\n\tconst prefix = `agents[${index}]`;\n\n\tif (typeof agent !== \"object\" || agent === null) {\n\t\terrors.push(`${prefix}: must be an object`);\n\t\treturn { valid: null, errors };\n\t}\n\n\tconst record = agent as Record<string, unknown>;\n\n\t// Validate id (required)\n\tif (typeof record.id !== \"string\" || record.id.trim().length === 0) {\n\t\terrors.push(`${prefix}.id: must be a non-empty string`);\n\t\treturn { valid: null, errors };\n\t}\n\n\t// Validate command (required)\n\tif (\n\t\ttypeof record.command !== \"string\" ||\n\t\trecord.command.trim().length === 0\n\t) {\n\t\terrors.push(`${prefix}.command: must be a non-empty string`);\n\t\treturn { valid: null, errors };\n\t}\n\n\tconst validated: UserAgentConfig = {\n\t\tid: record.id.trim(),\n\t\tcommand: record.command.trim(),\n\t};\n\n\t// Validate label (optional string)\n\tif (record.label !== undefined) {\n\t\tif (typeof record.label !== \"string\") {\n\t\t\terrors.push(`${prefix}.label: must be a string`);\n\t\t} else if (record.label.trim().length > 0) {\n\t\t\tvalidated.label = record.label.trim();\n\t\t}\n\t}\n\n\t// Validate args (optional string array)\n\tif (record.args !== undefined) {\n\t\tif (!Array.isArray(record.args)) {\n\t\t\terrors.push(`${prefix}.args: must be an array of strings`);\n\t\t} else {\n\t\t\tconst validArgs = record.args.filter((arg): arg is string => {\n\t\t\t\tif (typeof arg !== \"string\") {\n\t\t\t\t\terrors.push(`${prefix}.args: all elements must be strings`);\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t});\n\t\t\tif (validArgs.length > 0) {\n\t\t\t\tvalidated.args = validArgs;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Validate env (optional object with string values)\n\tif (record.env !== undefined) {\n\t\tif (typeof record.env !== \"object\" || record.env === null) {\n\t\t\terrors.push(`${prefix}.env: must be an object`);\n\t\t} else {\n\t\t\tconst envRecord = record.env as Record<string, unknown>;\n\t\t\tconst validEnv: Record<string, string> = {};\n\t\t\tlet hasEnv = false;\n\t\t\tfor (const [key, value] of Object.entries(envRecord)) {\n\t\t\t\tif (typeof value !== \"string\") {\n\t\t\t\t\terrors.push(`${prefix}.env.${key}: must be a string`);\n\t\t\t\t} else {\n\t\t\t\t\tvalidEnv[key] = value;\n\t\t\t\t\thasEnv = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (hasEnv) {\n\t\t\t\tvalidated.env = validEnv;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Return null if there were any errors after id/command validation\n\tif (errors.length > 0) {\n\t\treturn { valid: null, errors };\n\t}\n\n\treturn { valid: validated, errors: [] };\n};\n\nconst validateUserConfig = (\n\tdata: unknown,\n): { config: MobvibeUserConfig | null; errors: string[] } => {\n\tconst errors: string[] = [];\n\n\tif (typeof data !== \"object\" || data === null) {\n\t\terrors.push(\"config: must be an object\");\n\t\treturn { config: null, errors };\n\t}\n\n\tconst record = data as Record<string, unknown>;\n\tconst config: MobvibeUserConfig = {};\n\n\t// Validate agents array\n\tif (record.agents !== undefined) {\n\t\tif (!Array.isArray(record.agents)) {\n\t\t\terrors.push(\"agents: must be an array\");\n\t\t} else {\n\t\t\tconst validAgents: UserAgentConfig[] = [];\n\t\t\tconst seenIds = new Set<string>();\n\n\t\t\tfor (let i = 0; i < record.agents.length; i++) {\n\t\t\t\tconst result = validateAgentConfig(record.agents[i], i);\n\t\t\t\terrors.push(...result.errors);\n\n\t\t\t\tif (result.valid) {\n\t\t\t\t\tif (seenIds.has(result.valid.id)) {\n\t\t\t\t\t\terrors.push(`agents[${i}].id: duplicate id \"${result.valid.id}\"`);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tseenIds.add(result.valid.id);\n\t\t\t\t\t\tvalidAgents.push(result.valid);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (validAgents.length > 0) {\n\t\t\t\tconfig.agents = validAgents;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Validate defaultAgentId\n\tif (record.defaultAgentId !== undefined) {\n\t\tif (typeof record.defaultAgentId !== \"string\") {\n\t\t\terrors.push(\"defaultAgentId: must be a string\");\n\t\t} else if (record.defaultAgentId.trim().length > 0) {\n\t\t\tconfig.defaultAgentId = record.defaultAgentId.trim();\n\t\t}\n\t}\n\n\tif (errors.length > 0) {\n\t\treturn { config: null, errors };\n\t}\n\n\treturn { config, errors: [] };\n};\n\nexport const loadUserConfig = async (\n\thomePath: string,\n): Promise<ConfigLoadResult> => {\n\tconst configPath = path.join(homePath, CONFIG_FILENAME);\n\tconsole.log(`[config] Loading config from: ${configPath}`);\n\n\ttry {\n\t\tconst content = await fs.readFile(configPath, \"utf-8\");\n\t\tlet parsed: unknown;\n\n\t\ttry {\n\t\t\tparsed = JSON.parse(content);\n\t\t} catch {\n\t\t\tconsole.log(`[config] Invalid JSON in config file: ${configPath}`);\n\t\t\treturn {\n\t\t\t\tconfig: null,\n\t\t\t\terrors: [\"Invalid JSON in config file\"],\n\t\t\t\tpath: configPath,\n\t\t\t};\n\t\t}\n\n\t\tconst { config, errors } = validateUserConfig(parsed);\n\n\t\tif (errors.length > 0) {\n\t\t\tconsole.log(\"[config] Validation errors:\", errors);\n\t\t}\n\n\t\tif (config) {\n\t\t\tconsole.log(\"[config] Loaded config:\", JSON.stringify(config, null, 2));\n\t\t}\n\n\t\treturn { config, errors, path: configPath };\n\t} catch (error) {\n\t\t// File not found is not an error, just return null config\n\t\tif (error instanceof Error && \"code\" in error && error.code === \"ENOENT\") {\n\t\t\tconsole.log(`[config] No config file found at: ${configPath}`);\n\t\t\treturn { config: null, errors: [], path: configPath };\n\t\t}\n\n\t\t// Other errors (permissions, etc.)\n\t\tconst message =\n\t\t\terror instanceof Error ? error.message : \"Unknown error reading config\";\n\t\tconsole.log(`[config] Error reading config: ${message}`);\n\t\treturn { config: null, errors: [message], path: configPath };\n\t}\n};\n",
11
+ "import { Database } from \"bun:sqlite\";\nimport { spawn } from \"node:child_process\";\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { getSodium, initCrypto } from \"@mobvibe/shared\";\nimport { SessionManager } from \"../acp/session-manager.js\";\nimport { getMasterSecret } from \"../auth/credentials.js\";\nimport type { CliConfig } from \"../config.js\";\nimport { CliCryptoService } from \"../e2ee/crypto-service.js\";\nimport { logger } from \"../lib/logger.js\";\nimport { WalCompactor, WalStore } from \"../wal/index.js\";\nimport { SocketClient } from \"./socket-client.js\";\n\ntype DaemonStatus = {\n\trunning: boolean;\n\tpid?: number;\n\tconnected?: boolean;\n\tsessionCount?: number;\n};\n\nexport class DaemonManager {\n\tconstructor(private readonly config: CliConfig) {}\n\n\tasync ensureHomeDirectory(): Promise<void> {\n\t\tawait fs.mkdir(this.config.homePath, { recursive: true });\n\t\tawait fs.mkdir(this.config.logPath, { recursive: true });\n\t}\n\n\tasync getPid(): Promise<number | null> {\n\t\ttry {\n\t\t\tconst content = await fs.readFile(this.config.pidFile, \"utf8\");\n\t\t\tconst pid = Number.parseInt(content.trim(), 10);\n\t\t\tif (Number.isNaN(pid)) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\t// Check if process is running\n\t\t\ttry {\n\t\t\t\tprocess.kill(pid, 0);\n\t\t\t\treturn pid;\n\t\t\t} catch {\n\t\t\t\t// Process not running, clean up stale PID file\n\t\t\t\tawait this.removePidFile();\n\t\t\t\treturn null;\n\t\t\t}\n\t\t} catch {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tasync writePidFile(pid: number): Promise<void> {\n\t\tawait fs.writeFile(this.config.pidFile, String(pid), \"utf8\");\n\t}\n\n\tasync removePidFile(): Promise<void> {\n\t\ttry {\n\t\t\tawait fs.unlink(this.config.pidFile);\n\t\t} catch {\n\t\t\t// Ignore errors\n\t\t}\n\t}\n\n\tasync status(): Promise<DaemonStatus> {\n\t\tconst pid = await this.getPid();\n\t\tif (!pid) {\n\t\t\treturn { running: false };\n\t\t}\n\t\treturn { running: true, pid };\n\t}\n\n\tasync start(options?: { foreground?: boolean }): Promise<void> {\n\t\tconst existingPid = await this.getPid();\n\t\tif (existingPid) {\n\t\t\tlogger.info({ pid: existingPid }, \"daemon_already_running\");\n\t\t\treturn;\n\t\t}\n\n\t\tawait this.ensureHomeDirectory();\n\n\t\tif (options?.foreground) {\n\t\t\tawait this.runForeground();\n\t\t} else {\n\t\t\tawait this.spawnBackground();\n\t\t}\n\t}\n\n\tasync stop(): Promise<void> {\n\t\tconst pid = await this.getPid();\n\t\tif (!pid) {\n\t\t\tlogger.info(\"daemon_not_running\");\n\t\t\treturn;\n\t\t}\n\n\t\t// Check if process actually exists\n\t\ttry {\n\t\t\tprocess.kill(pid, 0);\n\t\t} catch {\n\t\t\tlogger.warn(\"daemon_pid_missing_cleanup\");\n\t\t\tawait this.removePidFile();\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tlogger.info({ pid }, \"daemon_stop_sigterm\");\n\t\t\tprocess.kill(pid, \"SIGTERM\");\n\n\t\t\t// Wait for process to exit (up to 5 seconds)\n\t\t\tconst startTime = Date.now();\n\t\t\tconst timeout = 5000;\n\n\t\t\twhile (Date.now() - startTime < timeout) {\n\t\t\t\tawait new Promise((resolve) => setTimeout(resolve, 100));\n\t\t\t\ttry {\n\t\t\t\t\tprocess.kill(pid, 0);\n\t\t\t\t\t// Process still running\n\t\t\t\t} catch {\n\t\t\t\t\t// Process exited\n\t\t\t\t\tlogger.info({ pid }, \"daemon_stopped_gracefully\");\n\t\t\t\t\tawait this.removePidFile();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Process didn't exit gracefully, force kill\n\t\t\tlogger.warn({ pid }, \"daemon_force_kill_start\");\n\t\t\ttry {\n\t\t\t\tprocess.kill(pid, \"SIGKILL\");\n\t\t\t\t// Wait a bit for SIGKILL to take effect\n\t\t\t\tawait new Promise((resolve) => setTimeout(resolve, 500));\n\t\t\t\tlogger.warn({ pid }, \"daemon_force_kill_complete\");\n\t\t\t} catch {\n\t\t\t\t// Already dead\n\t\t\t\tlogger.info({ pid }, \"daemon_already_stopped\");\n\t\t\t}\n\t\t\tawait this.removePidFile();\n\t\t} catch (error) {\n\t\t\tlogger.error({ err: error }, \"daemon_stop_error\");\n\t\t\tawait this.removePidFile();\n\t\t}\n\t}\n\n\tprivate async spawnBackground(): Promise<void> {\n\t\tconst logFile = path.join(\n\t\t\tthis.config.logPath,\n\t\t\t`${new Date().toISOString().replace(/[:.]/g, \"-\")}-daemon.log`,\n\t\t);\n\n\t\t// Filter out --foreground if already present, then add it\n\t\tconst args = process.argv\n\t\t\t.slice(1)\n\t\t\t.filter((arg) => arg !== \"--foreground\" && arg !== \"-f\");\n\t\targs.push(\"--foreground\");\n\n\t\tconst child = spawn(process.argv[0], args, {\n\t\t\tdetached: true,\n\t\t\tstdio: [\"ignore\", \"pipe\", \"pipe\"],\n\t\t\tenv: {\n\t\t\t\t...process.env,\n\t\t\t\tMOBVIBE_GATEWAY_URL: this.config.gatewayUrl,\n\t\t\t},\n\t\t});\n\n\t\tif (!child.pid) {\n\t\t\tlogger.error(\"daemon_spawn_failed\");\n\t\t\tthrow new Error(\"Failed to spawn daemon process\");\n\t\t}\n\n\t\t// Create log file stream before writing PID\n\t\tconst logStream = await fs.open(logFile, \"a\");\n\t\tconst fileHandle = logStream;\n\n\t\tchild.stdout?.on(\"data\", (data: Buffer) => {\n\t\t\tfileHandle.write(`[stdout] ${data.toString()}`).catch(() => {});\n\t\t});\n\n\t\tchild.stderr?.on(\"data\", (data: Buffer) => {\n\t\t\tfileHandle.write(`[stderr] ${data.toString()}`).catch(() => {});\n\t\t});\n\n\t\t// Handle child exit to clean up\n\t\tchild.on(\"exit\", (code, signal) => {\n\t\t\tfileHandle\n\t\t\t\t.write(`[exit] Process exited with code ${code}, signal ${signal}\\n`)\n\t\t\t\t.catch(() => {});\n\t\t\tfileHandle.close().catch(() => {});\n\t\t});\n\n\t\t// Detach from parent\n\t\t// Note: The child process writes its own PID file in runForeground()\n\t\tchild.unref();\n\n\t\tlogger.info({ pid: child.pid }, \"daemon_started\");\n\t\tconsole.log(`Logs: ${logFile}`);\n\t\tlogger.info({ logFile }, \"daemon_log_path\");\n\t}\n\n\tasync runForeground(): Promise<void> {\n\t\tconst pid = process.pid;\n\t\tawait this.writePidFile(pid);\n\n\t\tlogger.info({ pid }, \"daemon_starting\");\n\t\tlogger.info({ gatewayUrl: this.config.gatewayUrl }, \"daemon_gateway_url\");\n\t\tlogger.info({ machineId: this.config.machineId }, \"daemon_machine_id\");\n\n\t\t// Initialize crypto and load master secret\n\t\tawait initCrypto();\n\t\tconst masterSecretBase64 = await getMasterSecret();\n\t\tif (!masterSecretBase64) {\n\t\t\tlogger.error(\"daemon_master_secret_missing\");\n\t\t\tconsole.error(\n\t\t\t\t`[mobvibe-cli] No credentials found. Run 'mobvibe login' to authenticate.`,\n\t\t\t);\n\t\t\tlogger.warn(\"daemon_exit_missing_master_secret\");\n\t\t\tprocess.exit(1);\n\t\t}\n\t\tconst sodium = getSodium();\n\t\tconst masterSecret = sodium.from_base64(\n\t\t\tmasterSecretBase64,\n\t\t\tsodium.base64_variants.ORIGINAL,\n\t\t);\n\t\tconst cryptoService = new CliCryptoService(masterSecret);\n\t\tlogger.info(\"daemon_crypto_initialized\");\n\n\t\tconst sessionManager = new SessionManager(this.config, cryptoService);\n\t\tconst socketClient = new SocketClient({\n\t\t\tconfig: this.config,\n\t\t\tsessionManager,\n\t\t\tcryptoService,\n\t\t});\n\n\t\t// Initialize compactor if enabled\n\t\tlet compactor: WalCompactor | undefined;\n\t\tlet compactionInterval: NodeJS.Timeout | undefined;\n\t\t// P1-2: Track compactor resources for cleanup on shutdown\n\t\tlet compactorWalStore: WalStore | undefined;\n\t\tlet compactorDb: Database | undefined;\n\n\t\tif (this.config.compaction.enabled) {\n\t\t\tcompactorWalStore = new WalStore(this.config.walDbPath);\n\t\t\tcompactorDb = new Database(this.config.walDbPath);\n\t\t\tcompactor = new WalCompactor(\n\t\t\t\tcompactorWalStore,\n\t\t\t\tthis.config.compaction,\n\t\t\t\tcompactorDb,\n\t\t\t);\n\n\t\t\t// Run compaction on startup\n\t\t\tif (this.config.compaction.runOnStartup) {\n\t\t\t\tlogger.info(\"compaction_startup_start\");\n\t\t\t\tcompactor.compactAll().catch((error) => {\n\t\t\t\t\tlogger.error({ err: error }, \"compaction_startup_error\");\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// Schedule periodic compaction\n\t\t\tconst intervalMs =\n\t\t\t\tthis.config.compaction.runIntervalHours * 60 * 60 * 1000;\n\t\t\tcompactionInterval = setInterval(() => {\n\t\t\t\tlogger.info(\"compaction_scheduled_start\");\n\t\t\t\tcompactor?.compactAll().catch((error) => {\n\t\t\t\t\tlogger.error({ err: error }, \"compaction_scheduled_error\");\n\t\t\t\t});\n\t\t\t}, intervalMs);\n\n\t\t\tlogger.info(\n\t\t\t\t{ intervalHours: this.config.compaction.runIntervalHours },\n\t\t\t\t\"compaction_scheduled\",\n\t\t\t);\n\t\t}\n\n\t\tlet shuttingDown = false;\n\n\t\tconst shutdown = async (signal: string) => {\n\t\t\tif (shuttingDown) {\n\t\t\t\tlogger.warn({ signal }, \"daemon_shutdown_already_running\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tshuttingDown = true;\n\n\t\t\tlogger.info({ signal }, \"daemon_shutdown_start\");\n\n\t\t\ttry {\n\t\t\t\t// Stop compaction interval\n\t\t\t\tif (compactionInterval) {\n\t\t\t\t\tclearInterval(compactionInterval);\n\t\t\t\t}\n\n\t\t\t\t// P1-2: Close compactor resources to prevent connection leak\n\t\t\t\tif (compactorWalStore) {\n\t\t\t\t\tcompactorWalStore.close();\n\t\t\t\t}\n\t\t\t\tif (compactorDb) {\n\t\t\t\t\tcompactorDb.close();\n\t\t\t\t}\n\n\t\t\t\tsocketClient.disconnect();\n\t\t\t\tawait sessionManager.shutdown();\n\t\t\t\tawait this.removePidFile();\n\t\t\t\tlogger.info({ signal }, \"daemon_shutdown_complete\");\n\t\t\t} catch (error) {\n\t\t\t\tlogger.error({ err: error, signal }, \"daemon_shutdown_error\");\n\t\t\t}\n\t\t};\n\n\t\tprocess.on(\"SIGINT\", () => {\n\t\t\tshutdown(\"SIGINT\").catch((error) => {\n\t\t\t\tlogger.error({ err: error }, \"daemon_shutdown_sigint_error\");\n\t\t\t});\n\t\t});\n\t\tprocess.on(\"SIGTERM\", () => {\n\t\t\tshutdown(\"SIGTERM\").catch((error) => {\n\t\t\t\tlogger.error({ err: error }, \"daemon_shutdown_sigterm_error\");\n\t\t\t});\n\t\t});\n\n\t\tsocketClient.connect();\n\n\t\t// Keep process alive\n\t\tawait new Promise(() => {});\n\t}\n\n\tasync logs(options?: { follow?: boolean; lines?: number }): Promise<void> {\n\t\tconst files = await fs.readdir(this.config.logPath);\n\t\tconst logFiles = files\n\t\t\t.filter((f) => f.endsWith(\"-daemon.log\"))\n\t\t\t.sort()\n\t\t\t.reverse();\n\n\t\tif (logFiles.length === 0) {\n\t\t\tlogger.warn(\"daemon_logs_empty\");\n\t\t\tconsole.log(\"No log files found\");\n\t\t\treturn;\n\t\t}\n\n\t\tconst latestLog = path.join(this.config.logPath, logFiles[0]);\n\t\tlogger.info({ logFile: latestLog }, \"daemon_logs_latest\");\n\t\tconsole.log(`Log file: ${latestLog}\\n`);\n\n\t\tif (options?.follow) {\n\t\t\t// Use tail -f\n\t\t\tconst tail = spawn(\"tail\", [\"-f\", latestLog], {\n\t\t\t\tstdio: \"inherit\",\n\t\t\t});\n\t\t\tawait new Promise<void>((resolve) => {\n\t\t\t\ttail.on(\"close\", () => resolve());\n\t\t\t});\n\t\t} else {\n\t\t\tconst content = await fs.readFile(latestLog, \"utf8\");\n\t\t\tconst lines = content.split(\"\\n\");\n\t\t\tconst count = options?.lines ?? 50;\n\t\t\tconsole.log(lines.slice(-count).join(\"\\n\"));\n\t\t}\n\t}\n}\n",
12
+ "import { randomUUID } from \"node:crypto\";\nimport { EventEmitter } from \"node:events\";\nimport fs from \"node:fs/promises\";\nimport type {\n\tAvailableCommand,\n\tRequestPermissionRequest,\n\tRequestPermissionResponse,\n\tSessionModelState,\n\tSessionModeState,\n\tSessionNotification,\n} from \"@agentclientprotocol/sdk\";\nimport {\n\ttype AcpSessionInfo,\n\tAppError,\n\tcreateErrorDetail,\n\ttype DiscoverSessionsRpcResult,\n\ttype PermissionDecisionPayload,\n\ttype PermissionRequestPayload,\n\ttype SessionEvent,\n\ttype SessionEventKind,\n\ttype SessionEventsParams,\n\ttype SessionEventsResponse,\n\ttype SessionSummary,\n\ttype SessionsChangedPayload,\n\ttype StopReason,\n} from \"@mobvibe/shared\";\nimport type { AcpBackendConfig, CliConfig } from \"../config.js\";\nimport type { CliCryptoService } from \"../e2ee/crypto-service.js\";\nimport { logger } from \"../lib/logger.js\";\nimport { WalStore } from \"../wal/index.js\";\nimport { AcpConnection } from \"./acp-connection.js\";\n\ntype SessionRecord = {\n\tsessionId: string;\n\ttitle: string;\n\tbackendId: string;\n\tbackendLabel: string;\n\tconnection: AcpConnection;\n\tcreatedAt: Date;\n\tupdatedAt: Date;\n\tcwd?: string;\n\tagentName?: string;\n\tmodelId?: string;\n\tmodelName?: string;\n\tmodeId?: string;\n\tmodeName?: string;\n\tavailableModes?: Array<{ id: string; name: string }>;\n\tavailableModels?: Array<{\n\t\tid: string;\n\t\tname: string;\n\t\tdescription?: string | null;\n\t}>;\n\tavailableCommands?: AvailableCommand[];\n\tunsubscribe?: () => void;\n\tunsubscribeTerminal?: () => void;\n\tisAttached?: boolean;\n\tattachedAt?: Date;\n\t/** Current WAL revision for this session */\n\trevision: number;\n};\n\ntype PermissionRequestRecord = {\n\tsessionId: string;\n\trequestId: string;\n\tparams: RequestPermissionRequest;\n\tpromise: Promise<RequestPermissionResponse>;\n\tresolve: (response: RequestPermissionResponse) => void;\n};\n\nconst buildPermissionKey = (sessionId: string, requestId: string) =>\n\t`${sessionId}:${requestId}`;\n\nconst resolveModelState = (models?: SessionModelState | null) => {\n\tif (!models) {\n\t\treturn {\n\t\t\tmodelId: undefined,\n\t\t\tmodelName: undefined,\n\t\t\tavailableModels: undefined,\n\t\t};\n\t}\n\tconst availableModels = models.availableModels?.map((model) => ({\n\t\tid: model.modelId,\n\t\tname: model.name,\n\t\tdescription: model.description ?? undefined,\n\t}));\n\tconst modelId = models.currentModelId ?? undefined;\n\tconst modelName = availableModels?.find(\n\t\t(model) => model.id === modelId,\n\t)?.name;\n\treturn { modelId, modelName, availableModels };\n};\n\nconst resolveModeState = (modes?: SessionModeState | null) => {\n\tif (!modes) {\n\t\treturn {\n\t\t\tmodeId: undefined,\n\t\t\tmodeName: undefined,\n\t\t\tavailableModes: undefined,\n\t\t};\n\t}\n\tconst modeId = modes.currentModeId ?? undefined;\n\tconst modeName = modes.availableModes?.find(\n\t\t(mode) => mode.id === modeId,\n\t)?.name;\n\treturn {\n\t\tmodeId,\n\t\tmodeName,\n\t\tavailableModes: modes.availableModes?.map((mode) => ({\n\t\t\tid: mode.id,\n\t\t\tname: mode.name,\n\t\t})),\n\t};\n};\n\nconst createCapabilityNotSupportedError = (message: string) =>\n\tnew AppError(\n\t\tcreateErrorDetail({\n\t\t\tcode: \"CAPABILITY_NOT_SUPPORTED\",\n\t\t\tmessage,\n\t\t\tretryable: false,\n\t\t\tscope: \"session\",\n\t\t}),\n\t\t409,\n\t);\n\nconst isValidWorkspacePath = async (cwd: string): Promise<boolean> => {\n\ttry {\n\t\tconst stats = await fs.stat(cwd);\n\t\treturn stats.isDirectory();\n\t} catch {\n\t\treturn false;\n\t}\n};\n\nexport class SessionManager {\n\tprivate sessions = new Map<string, SessionRecord>();\n\tprivate discoveredSessions = new Map<string, AcpSessionInfo>();\n\tprivate backendById: Map<string, AcpBackendConfig>;\n\tprivate permissionRequests = new Map<string, PermissionRequestRecord>();\n\tprivate readonly permissionRequestEmitter = new EventEmitter();\n\tprivate readonly permissionResultEmitter = new EventEmitter();\n\tprivate readonly sessionsChangedEmitter = new EventEmitter();\n\tprivate readonly sessionAttachedEmitter = new EventEmitter();\n\tprivate readonly sessionDetachedEmitter = new EventEmitter();\n\tprivate readonly sessionEventEmitter = new EventEmitter();\n\tprivate readonly walStore: WalStore;\n\tprivate readonly cryptoService?: CliCryptoService;\n\n\tconstructor(\n\t\tprivate readonly config: CliConfig,\n\t\tcryptoService?: CliCryptoService,\n\t) {\n\t\tthis.backendById = new Map(\n\t\t\tconfig.acpBackends.map((backend) => [backend.id, backend]),\n\t\t);\n\t\tthis.walStore = new WalStore(config.walDbPath);\n\t\tthis.cryptoService = cryptoService;\n\t}\n\n\tcreateConnection(backend: AcpBackendConfig): AcpConnection {\n\t\treturn new AcpConnection({\n\t\t\tbackend,\n\t\t\tclient: {\n\t\t\t\tname: this.config.clientName,\n\t\t\t\tversion: this.config.clientVersion,\n\t\t\t},\n\t\t});\n\t}\n\n\tlistSessions(): SessionSummary[] {\n\t\treturn Array.from(this.sessions.values()).map((record) =>\n\t\t\tthis.buildSummary(record),\n\t\t);\n\t}\n\n\t/**\n\t * List all sessions: active sessions merged with persisted discovered sessions.\n\t * Used for the gateway heartbeat so that `sessions:list` sends the\n\t * complete set, allowing the gateway to replace its cache.\n\t */\n\tlistAllSessions(): SessionSummary[] {\n\t\tconst active = this.listSessions();\n\t\tconst merged = new Map<string, SessionSummary>(\n\t\t\tactive.map((s) => [s.sessionId, s]),\n\t\t);\n\n\t\tfor (const s of this.walStore.getDiscoveredSessions()) {\n\t\t\tif (s.cwd === undefined) continue;\n\t\t\tconst existing = merged.get(s.sessionId);\n\t\t\tif (existing) {\n\t\t\t\t// Keep the latest updatedAt between active and discovered\n\t\t\t\tconst discoveredUpdatedAt = s.agentUpdatedAt ?? s.discoveredAt;\n\t\t\t\tif (discoveredUpdatedAt > existing.updatedAt) {\n\t\t\t\t\tmerged.set(s.sessionId, {\n\t\t\t\t\t\t...existing,\n\t\t\t\t\t\tupdatedAt: discoveredUpdatedAt,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tmerged.set(s.sessionId, {\n\t\t\t\t\tsessionId: s.sessionId,\n\t\t\t\t\ttitle: s.title ?? `Session ${s.sessionId.slice(0, 8)}`,\n\t\t\t\t\tbackendId: s.backendId,\n\t\t\t\t\tbackendLabel: s.backendId,\n\t\t\t\t\tcwd: s.cwd as string,\n\t\t\t\t\tcreatedAt: s.discoveredAt,\n\t\t\t\t\tupdatedAt: s.agentUpdatedAt ?? s.discoveredAt,\n\t\t\t\t} satisfies SessionSummary);\n\t\t\t}\n\t\t}\n\n\t\treturn Array.from(merged.values());\n\t}\n\n\tgetSession(sessionId: string): SessionRecord | undefined {\n\t\treturn this.sessions.get(sessionId);\n\t}\n\n\t/**\n\t * Get the current WAL revision for a session.\n\t */\n\tgetSessionRevision(sessionId: string): number | undefined {\n\t\treturn this.sessions.get(sessionId)?.revision;\n\t}\n\n\tonPermissionRequest(listener: (payload: PermissionRequestPayload) => void) {\n\t\tthis.permissionRequestEmitter.on(\"request\", listener);\n\t\treturn () => {\n\t\t\tthis.permissionRequestEmitter.off(\"request\", listener);\n\t\t};\n\t}\n\n\tonPermissionResult(listener: (payload: PermissionDecisionPayload) => void) {\n\t\tthis.permissionResultEmitter.on(\"result\", listener);\n\t\treturn () => {\n\t\t\tthis.permissionResultEmitter.off(\"result\", listener);\n\t\t};\n\t}\n\n\tonSessionsChanged(listener: (payload: SessionsChangedPayload) => void) {\n\t\tthis.sessionsChangedEmitter.on(\"changed\", listener);\n\t\treturn () => {\n\t\t\tthis.sessionsChangedEmitter.off(\"changed\", listener);\n\t\t};\n\t}\n\n\tonSessionAttached(\n\t\tlistener: (payload: {\n\t\t\tsessionId: string;\n\t\t\tmachineId: string;\n\t\t\tattachedAt: string;\n\t\t}) => void,\n\t) {\n\t\tthis.sessionAttachedEmitter.on(\"attached\", listener);\n\t\treturn () => {\n\t\t\tthis.sessionAttachedEmitter.off(\"attached\", listener);\n\t\t};\n\t}\n\n\tonSessionDetached(\n\t\tlistener: (payload: {\n\t\t\tsessionId: string;\n\t\t\tmachineId: string;\n\t\t\tdetachedAt: string;\n\t\t\treason:\n\t\t\t\t| \"agent_exit\"\n\t\t\t\t| \"cli_disconnect\"\n\t\t\t\t| \"gateway_disconnect\"\n\t\t\t\t| \"unknown\";\n\t\t}) => void,\n\t) {\n\t\tthis.sessionDetachedEmitter.on(\"detached\", listener);\n\t\treturn () => {\n\t\t\tthis.sessionDetachedEmitter.off(\"detached\", listener);\n\t\t};\n\t}\n\n\t/**\n\t * Listen for session events (WAL-persisted events with seq/revision).\n\t */\n\tonSessionEvent(listener: (event: SessionEvent) => void) {\n\t\tthis.sessionEventEmitter.on(\"event\", listener);\n\t\treturn () => {\n\t\t\tthis.sessionEventEmitter.off(\"event\", listener);\n\t\t};\n\t}\n\n\t/**\n\t * Query session events from the WAL.\n\t */\n\tgetSessionEvents(params: SessionEventsParams): SessionEventsResponse {\n\t\tconst record = this.sessions.get(params.sessionId);\n\n\t\t// Determine the actual revision from WAL or active session\n\t\tlet actualRevision: number;\n\t\tif (record) {\n\t\t\tactualRevision = record.revision;\n\t\t} else {\n\t\t\t// Session not active, check WAL for persisted revision\n\t\t\tconst walSession = this.walStore.getSession(params.sessionId);\n\t\t\tactualRevision = walSession?.currentRevision ?? params.revision;\n\t\t}\n\n\t\t// If no events in WAL for this session, return empty with actual revision\n\t\tif (!record && !this.walStore.getSession(params.sessionId)) {\n\t\t\treturn {\n\t\t\t\tsessionId: params.sessionId,\n\t\t\t\tmachineId: this.config.machineId,\n\t\t\t\trevision: actualRevision,\n\t\t\t\tevents: [],\n\t\t\t\thasMore: false,\n\t\t\t};\n\t\t}\n\n\t\t// Fix 2: If requested revision doesn't match actual revision, return empty events\n\t\t// This ensures response.revision === events[].revision consistency\n\t\t// Client will see mismatch, reset, and re-request with afterSeq=0\n\t\tif (params.revision !== actualRevision) {\n\t\t\treturn {\n\t\t\t\tsessionId: params.sessionId,\n\t\t\t\tmachineId: this.config.machineId,\n\t\t\t\trevision: actualRevision,\n\t\t\t\tevents: [],\n\t\t\t\thasMore: false,\n\t\t\t};\n\t\t}\n\n\t\tconst limit = params.limit ?? 100;\n\t\tconst events = this.walStore.queryEvents({\n\t\t\tsessionId: params.sessionId,\n\t\t\trevision: actualRevision, // Use consistent revision\n\t\t\tafterSeq: params.afterSeq,\n\t\t\tlimit: limit + 1, // Query one extra to check hasMore\n\t\t});\n\n\t\tconst hasMore = events.length > limit;\n\t\tconst resultEvents = hasMore ? events.slice(0, limit) : events;\n\n\t\treturn {\n\t\t\tsessionId: params.sessionId,\n\t\t\tmachineId: this.config.machineId,\n\t\t\trevision: actualRevision,\n\t\t\tevents: resultEvents.map((e) => ({\n\t\t\t\tsessionId: e.sessionId,\n\t\t\t\tmachineId: this.config.machineId,\n\t\t\t\trevision: e.revision,\n\t\t\t\tseq: e.seq,\n\t\t\t\tkind: e.kind,\n\t\t\t\tcreatedAt: e.createdAt,\n\t\t\t\tpayload: e.payload,\n\t\t\t})),\n\t\t\tnextAfterSeq:\n\t\t\t\tresultEvents.length > 0\n\t\t\t\t\t? resultEvents[resultEvents.length - 1].seq\n\t\t\t\t\t: undefined,\n\t\t\thasMore,\n\t\t};\n\t}\n\n\t/**\n\t * Get unacked events for a session/revision (for reconnection replay).\n\t */\n\tgetUnackedEvents(sessionId: string, revision: number): SessionEvent[] {\n\t\tconst events = this.walStore.getUnackedEvents(sessionId, revision);\n\t\treturn events.map((e) => ({\n\t\t\tsessionId: e.sessionId,\n\t\t\tmachineId: this.config.machineId,\n\t\t\trevision: e.revision,\n\t\t\tseq: e.seq,\n\t\t\tkind: e.kind,\n\t\t\tcreatedAt: e.createdAt,\n\t\t\tpayload: e.payload,\n\t\t}));\n\t}\n\n\t/**\n\t * Acknowledge events up to a given sequence.\n\t */\n\tackEvents(sessionId: string, revision: number, upToSeq: number): void {\n\t\tthis.walStore.ackEvents(sessionId, revision, upToSeq);\n\t}\n\n\trecordTurnEnd(sessionId: string, stopReason: StopReason): void {\n\t\tconst record = this.sessions.get(sessionId);\n\t\tif (!record) {\n\t\t\treturn;\n\t\t}\n\t\trecord.updatedAt = new Date();\n\t\tthis.writeAndEmitEvent(sessionId, record.revision, \"turn_end\", {\n\t\t\tstopReason,\n\t\t});\n\t}\n\n\t/**\n\t * Write an event to the WAL and emit it.\n\t */\n\tprivate writeAndEmitEvent(\n\t\tsessionId: string,\n\t\trevision: number,\n\t\tkind: SessionEventKind,\n\t\tpayload: unknown,\n\t): SessionEvent {\n\t\tlogger.debug(\n\t\t\t{ sessionId, revision, kind },\n\t\t\t\"session_write_and_emit_event_start\",\n\t\t);\n\n\t\tconst walEvent = this.walStore.appendEvent({\n\t\t\tsessionId,\n\t\t\trevision,\n\t\t\tkind,\n\t\t\tpayload,\n\t\t});\n\n\t\tconst event: SessionEvent = {\n\t\t\tsessionId: walEvent.sessionId,\n\t\t\tmachineId: this.config.machineId,\n\t\t\trevision: walEvent.revision,\n\t\t\tseq: walEvent.seq,\n\t\t\tkind: walEvent.kind,\n\t\t\tcreatedAt: walEvent.createdAt,\n\t\t\tpayload: walEvent.payload,\n\t\t};\n\n\t\tlogger.info(\n\t\t\t{\n\t\t\t\tsessionId: event.sessionId,\n\t\t\t\trevision: event.revision,\n\t\t\t\tseq: event.seq,\n\t\t\t\tkind: event.kind,\n\t\t\t},\n\t\t\t\"session_event_emitting\",\n\t\t);\n\n\t\tthis.sessionEventEmitter.emit(\"event\", event);\n\n\t\tlogger.debug(\n\t\t\t{ sessionId: event.sessionId, seq: event.seq },\n\t\t\t\"session_event_emitted\",\n\t\t);\n\n\t\treturn event;\n\t}\n\n\tprivate emitSessionsChanged(payload: SessionsChangedPayload) {\n\t\tthis.sessionsChangedEmitter.emit(\"changed\", payload);\n\t}\n\n\tprivate emitSessionAttached(sessionId: string, force = false) {\n\t\tconst record = this.sessions.get(sessionId);\n\t\tif (!record) {\n\t\t\treturn;\n\t\t}\n\t\tif (record.isAttached && !force) {\n\t\t\treturn;\n\t\t}\n\t\tconst attachedAt = new Date();\n\t\trecord.isAttached = true;\n\t\trecord.attachedAt = attachedAt;\n\t\tthis.sessionAttachedEmitter.emit(\"attached\", {\n\t\t\tsessionId,\n\t\t\tmachineId: this.config.machineId,\n\t\t\tattachedAt: attachedAt.toISOString(),\n\t\t\trevision: record.revision,\n\t\t});\n\t}\n\n\tprivate emitSessionDetached(\n\t\tsessionId: string,\n\t\treason: \"agent_exit\" | \"cli_disconnect\" | \"gateway_disconnect\" | \"unknown\",\n\t) {\n\t\tconst record = this.sessions.get(sessionId);\n\t\tif (!record) {\n\t\t\treturn;\n\t\t}\n\t\tif (!record.isAttached) {\n\t\t\treturn;\n\t\t}\n\t\trecord.isAttached = false;\n\t\tthis.sessionDetachedEmitter.emit(\"detached\", {\n\t\t\tsessionId,\n\t\t\tmachineId: this.config.machineId,\n\t\t\tdetachedAt: new Date().toISOString(),\n\t\t\treason,\n\t\t});\n\t}\n\n\tlistPendingPermissions(sessionId: string): PermissionRequestPayload[] {\n\t\treturn Array.from(this.permissionRequests.values())\n\t\t\t.filter((record) => record.sessionId === sessionId)\n\t\t\t.map((record) => this.buildPermissionRequestPayload(record));\n\t}\n\n\tresolvePermissionRequest(\n\t\tsessionId: string,\n\t\trequestId: string,\n\t\toutcome: RequestPermissionResponse[\"outcome\"],\n\t): PermissionDecisionPayload {\n\t\tconst key = buildPermissionKey(sessionId, requestId);\n\t\tconst permRecord = this.permissionRequests.get(key);\n\t\tif (!permRecord) {\n\t\t\tthrow new AppError(\n\t\t\t\tcreateErrorDetail({\n\t\t\t\t\tcode: \"REQUEST_VALIDATION_FAILED\",\n\t\t\t\t\tmessage: \"Permission request not found\",\n\t\t\t\t\tretryable: false,\n\t\t\t\t\tscope: \"request\",\n\t\t\t\t}),\n\t\t\t\t404,\n\t\t\t);\n\t\t}\n\t\tconst response: RequestPermissionResponse = { outcome };\n\t\tpermRecord.resolve(response);\n\t\tthis.permissionRequests.delete(key);\n\t\tconst payload: PermissionDecisionPayload = {\n\t\t\tsessionId,\n\t\t\trequestId,\n\t\t\toutcome,\n\t\t};\n\n\t\t// Write permission result to WAL\n\t\tconst sessionRecord = this.sessions.get(sessionId);\n\t\tif (sessionRecord) {\n\t\t\tthis.writeAndEmitEvent(\n\t\t\t\tsessionId,\n\t\t\t\tsessionRecord.revision,\n\t\t\t\t\"permission_result\",\n\t\t\t\tpayload,\n\t\t\t);\n\t\t}\n\n\t\tthis.permissionResultEmitter.emit(\"result\", payload);\n\t\treturn payload;\n\t}\n\n\tprivate resolveBackend(backendId: string) {\n\t\tconst normalized = backendId.trim();\n\t\tif (!normalized) {\n\t\t\tthrow new AppError(\n\t\t\t\tcreateErrorDetail({\n\t\t\t\t\tcode: \"REQUEST_VALIDATION_FAILED\",\n\t\t\t\t\tmessage: \"backendId is required\",\n\t\t\t\t\tretryable: false,\n\t\t\t\t\tscope: \"request\",\n\t\t\t\t}),\n\t\t\t\t400,\n\t\t\t);\n\t\t}\n\t\tconst backend = this.backendById.get(normalized);\n\t\tif (!backend) {\n\t\t\tthrow new AppError(\n\t\t\t\tcreateErrorDetail({\n\t\t\t\t\tcode: \"REQUEST_VALIDATION_FAILED\",\n\t\t\t\t\tmessage: \"Invalid backend ID\",\n\t\t\t\t\tretryable: false,\n\t\t\t\t\tscope: \"request\",\n\t\t\t\t}),\n\t\t\t\t400,\n\t\t\t);\n\t\t}\n\t\treturn backend;\n\t}\n\n\tasync createSession(options: {\n\t\tcwd?: string;\n\t\ttitle?: string;\n\t\tbackendId: string;\n\t}): Promise<SessionSummary> {\n\t\tconst backend = this.resolveBackend(options.backendId);\n\t\tconst connection = this.createConnection(backend);\n\t\ttry {\n\t\t\tawait connection.connect();\n\t\t\tconst session = await connection.createSession({ cwd: options?.cwd });\n\t\t\tconnection.setPermissionHandler((params) =>\n\t\t\t\tthis.handlePermissionRequest(session.sessionId, params),\n\t\t\t);\n\t\t\tconst now = new Date();\n\t\t\tconst agentInfo = connection.getAgentInfo();\n\t\t\tconst { modelId, modelName, availableModels } = resolveModelState(\n\t\t\t\tsession.models,\n\t\t\t);\n\t\t\tconst { modeId, modeName, availableModes } = resolveModeState(\n\t\t\t\tsession.modes,\n\t\t\t);\n\n\t\t\t// Initialize WAL session\n\t\t\tconst { revision } = this.walStore.ensureSession({\n\t\t\t\tsessionId: session.sessionId,\n\t\t\t\tmachineId: this.config.machineId,\n\t\t\t\tbackendId: backend.id,\n\t\t\t\tcwd: options?.cwd,\n\t\t\t\ttitle: options?.title ?? `Session ${this.sessions.size + 1}`,\n\t\t\t});\n\n\t\t\t// Initialize DEK for E2EE\n\t\t\tif (this.cryptoService) {\n\t\t\t\tthis.cryptoService.initSessionDek(session.sessionId);\n\t\t\t}\n\n\t\t\tconst record: SessionRecord = {\n\t\t\t\tsessionId: session.sessionId,\n\t\t\t\ttitle: options?.title ?? `Session ${this.sessions.size + 1}`,\n\t\t\t\tbackendId: backend.id,\n\t\t\t\tbackendLabel: backend.label,\n\t\t\t\tconnection,\n\t\t\t\tcreatedAt: now,\n\t\t\t\tupdatedAt: now,\n\t\t\t\tcwd: options?.cwd,\n\t\t\t\tagentName: agentInfo?.title ?? agentInfo?.name,\n\t\t\t\tmodelId,\n\t\t\t\tmodelName,\n\t\t\t\tmodeId,\n\t\t\t\tmodeName,\n\t\t\t\tavailableModes,\n\t\t\t\tavailableModels,\n\t\t\t\tavailableCommands: undefined,\n\t\t\t\trevision,\n\t\t\t};\n\t\t\trecord.unsubscribe = connection.onSessionUpdate(\n\t\t\t\t(notification: SessionNotification) => {\n\t\t\t\t\tlogger.debug(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tsessionId: session.sessionId,\n\t\t\t\t\t\t\tupdateType: notification.update.sessionUpdate,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"acp_session_update_received\",\n\t\t\t\t\t);\n\t\t\t\t\trecord.updatedAt = new Date();\n\t\t\t\t\t// Write to WAL and emit via session:event (unified event channel)\n\t\t\t\t\tthis.writeSessionUpdateToWal(record, notification);\n\t\t\t\t\tthis.applySessionUpdateToRecord(record, notification);\n\t\t\t\t},\n\t\t\t);\n\t\t\trecord.unsubscribeTerminal = connection.onTerminalOutput((event) => {\n\t\t\t\tlogger.debug(\n\t\t\t\t\t{ sessionId: record.sessionId },\n\t\t\t\t\t\"acp_terminal_output_received\",\n\t\t\t\t);\n\t\t\t\t// Write terminal output to WAL (emits via session:event)\n\t\t\t\tthis.writeAndEmitEvent(\n\t\t\t\t\trecord.sessionId,\n\t\t\t\t\trecord.revision,\n\t\t\t\t\t\"terminal_output\",\n\t\t\t\t\tevent,\n\t\t\t\t);\n\t\t\t});\n\t\t\tconnection.onStatusChange((status) => {\n\t\t\t\tif (status.error) {\n\t\t\t\t\t// Write error to WAL (emits via session:event)\n\t\t\t\t\tthis.writeAndEmitEvent(\n\t\t\t\t\t\trecord.sessionId,\n\t\t\t\t\t\trecord.revision,\n\t\t\t\t\t\t\"session_error\",\n\t\t\t\t\t\t{ error: status.error },\n\t\t\t\t\t);\n\t\t\t\t\tthis.emitSessionDetached(session.sessionId, \"agent_exit\");\n\t\t\t\t}\n\t\t\t});\n\t\t\tthis.sessions.set(session.sessionId, record);\n\t\t\tconst summary = this.buildSummary(record);\n\t\t\tthis.emitSessionsChanged({\n\t\t\t\tadded: [summary],\n\t\t\t\tupdated: [],\n\t\t\t\tremoved: [],\n\t\t\t});\n\t\t\tthis.emitSessionAttached(session.sessionId);\n\t\t\treturn summary;\n\t\t} catch (error) {\n\t\t\tconst status = connection.getStatus();\n\t\t\tawait connection.disconnect();\n\t\t\tif (status.error) {\n\t\t\t\tthrow new AppError(status.error, 500);\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tprivate buildPermissionRequestPayload(\n\t\trecord: PermissionRequestRecord,\n\t): PermissionRequestPayload {\n\t\tconst toolCall = record.params.toolCall;\n\t\treturn {\n\t\t\tsessionId: record.sessionId,\n\t\t\trequestId: record.requestId,\n\t\t\toptions: record.params.options.map((option) => ({\n\t\t\t\toptionId: option.optionId,\n\t\t\t\t// SDK uses 'name', our shared type uses 'label'\n\t\t\t\tlabel: option.name,\n\t\t\t\tdescription: (option._meta?.description as string) ?? null,\n\t\t\t})),\n\t\t\ttoolCall: {\n\t\t\t\ttoolCallId: toolCall.toolCallId,\n\t\t\t\tname: (toolCall._meta?.name as string) ?? null,\n\t\t\t\ttitle: toolCall.title,\n\t\t\t\tcommand: (toolCall._meta?.command as string) ?? null,\n\t\t\t\targs: (toolCall._meta?.args as string[]) ?? null,\n\t\t\t},\n\t\t};\n\t}\n\n\tprivate handlePermissionRequest(\n\t\tsessionId: string,\n\t\tparams: RequestPermissionRequest,\n\t): Promise<RequestPermissionResponse> {\n\t\tconst requestId = params.toolCall?.toolCallId ?? randomUUID();\n\t\tconst key = buildPermissionKey(sessionId, requestId);\n\t\tconst existing = this.permissionRequests.get(key);\n\t\tif (existing) {\n\t\t\treturn existing.promise;\n\t\t}\n\t\tlet resolver: (response: RequestPermissionResponse) => void = () => {};\n\t\tconst promise = new Promise<RequestPermissionResponse>((resolve) => {\n\t\t\tresolver = resolve;\n\t\t});\n\t\tconst permRecord: PermissionRequestRecord = {\n\t\t\tsessionId,\n\t\t\trequestId,\n\t\t\tparams,\n\t\t\tpromise,\n\t\t\tresolve: resolver,\n\t\t};\n\t\tthis.permissionRequests.set(key, permRecord);\n\t\tconst payload = this.buildPermissionRequestPayload(permRecord);\n\n\t\t// Write permission request to WAL\n\t\tconst sessionRecord = this.sessions.get(sessionId);\n\t\tif (sessionRecord) {\n\t\t\tthis.writeAndEmitEvent(\n\t\t\t\tsessionId,\n\t\t\t\tsessionRecord.revision,\n\t\t\t\t\"permission_request\",\n\t\t\t\tpayload,\n\t\t\t);\n\t\t}\n\n\t\tthis.permissionRequestEmitter.emit(\"request\", payload);\n\t\treturn promise;\n\t}\n\n\tprivate cancelPermissionRequests(sessionId: string) {\n\t\tconst cancelledOutcome: RequestPermissionResponse[\"outcome\"] = {\n\t\t\toutcome: \"cancelled\",\n\t\t};\n\t\tfor (const [key, record] of this.permissionRequests.entries()) {\n\t\t\tif (record.sessionId !== sessionId) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\trecord.resolve({ outcome: cancelledOutcome });\n\t\t\tthis.permissionRequests.delete(key);\n\t\t\tthis.permissionResultEmitter.emit(\"result\", {\n\t\t\t\tsessionId,\n\t\t\t\trequestId: record.requestId,\n\t\t\t\toutcome: cancelledOutcome,\n\t\t\t});\n\t\t}\n\t}\n\n\tupdateTitle(sessionId: string, title: string): SessionSummary {\n\t\tconst record = this.sessions.get(sessionId);\n\t\tif (!record) {\n\t\t\tthrow new AppError(\n\t\t\t\tcreateErrorDetail({\n\t\t\t\t\tcode: \"SESSION_NOT_FOUND\",\n\t\t\t\t\tmessage: \"Session not found\",\n\t\t\t\t\tretryable: false,\n\t\t\t\t\tscope: \"session\",\n\t\t\t\t}),\n\t\t\t\t404,\n\t\t\t);\n\t\t}\n\t\trecord.title = title;\n\t\trecord.updatedAt = new Date();\n\t\tconst summary = this.buildSummary(record);\n\t\tthis.emitSessionsChanged({\n\t\t\tadded: [],\n\t\t\tupdated: [summary],\n\t\t\tremoved: [],\n\t\t});\n\t\treturn summary;\n\t}\n\n\ttouchSession(sessionId: string) {\n\t\tconst record = this.sessions.get(sessionId);\n\t\tif (!record) {\n\t\t\treturn;\n\t\t}\n\t\trecord.updatedAt = new Date();\n\t}\n\n\tasync setSessionMode(\n\t\tsessionId: string,\n\t\tmodeId: string,\n\t): Promise<SessionSummary> {\n\t\tconst record = this.sessions.get(sessionId);\n\t\tif (!record) {\n\t\t\tthrow new AppError(\n\t\t\t\tcreateErrorDetail({\n\t\t\t\t\tcode: \"SESSION_NOT_FOUND\",\n\t\t\t\t\tmessage: \"Session not found\",\n\t\t\t\t\tretryable: false,\n\t\t\t\t\tscope: \"session\",\n\t\t\t\t}),\n\t\t\t\t404,\n\t\t\t);\n\t\t}\n\t\tif (!record.availableModes || record.availableModes.length === 0) {\n\t\t\tthrow createCapabilityNotSupportedError(\n\t\t\t\t\"Current agent does not support mode switching\",\n\t\t\t);\n\t\t}\n\t\tconst selected = record.availableModes.find((mode) => mode.id === modeId);\n\t\tif (!selected) {\n\t\t\tthrow new AppError(\n\t\t\t\tcreateErrorDetail({\n\t\t\t\t\tcode: \"REQUEST_VALIDATION_FAILED\",\n\t\t\t\t\tmessage: \"Invalid mode ID\",\n\t\t\t\t\tretryable: false,\n\t\t\t\t\tscope: \"request\",\n\t\t\t\t}),\n\t\t\t\t400,\n\t\t\t);\n\t\t}\n\t\tawait record.connection.setSessionMode(sessionId, modeId);\n\t\trecord.modeId = selected.id;\n\t\trecord.modeName = selected.name;\n\t\trecord.updatedAt = new Date();\n\t\tconst summary = this.buildSummary(record);\n\t\tthis.emitSessionsChanged({\n\t\t\tadded: [],\n\t\t\tupdated: [summary],\n\t\t\tremoved: [],\n\t\t});\n\t\treturn summary;\n\t}\n\n\tasync setSessionModel(\n\t\tsessionId: string,\n\t\tmodelId: string,\n\t): Promise<SessionSummary> {\n\t\tconst record = this.sessions.get(sessionId);\n\t\tif (!record) {\n\t\t\tthrow new AppError(\n\t\t\t\tcreateErrorDetail({\n\t\t\t\t\tcode: \"SESSION_NOT_FOUND\",\n\t\t\t\t\tmessage: \"Session not found\",\n\t\t\t\t\tretryable: false,\n\t\t\t\t\tscope: \"session\",\n\t\t\t\t}),\n\t\t\t\t404,\n\t\t\t);\n\t\t}\n\t\tif (!record.availableModels || record.availableModels.length === 0) {\n\t\t\tthrow createCapabilityNotSupportedError(\n\t\t\t\t\"Current agent does not support model switching\",\n\t\t\t);\n\t\t}\n\t\tconst selected = record.availableModels.find(\n\t\t\t(model) => model.id === modelId,\n\t\t);\n\t\tif (!selected) {\n\t\t\tthrow new AppError(\n\t\t\t\tcreateErrorDetail({\n\t\t\t\t\tcode: \"REQUEST_VALIDATION_FAILED\",\n\t\t\t\t\tmessage: \"Invalid model ID\",\n\t\t\t\t\tretryable: false,\n\t\t\t\t\tscope: \"request\",\n\t\t\t\t}),\n\t\t\t\t400,\n\t\t\t);\n\t\t}\n\t\tawait record.connection.setSessionModel(sessionId, modelId);\n\t\trecord.modelId = selected.id;\n\t\trecord.modelName = selected.name;\n\t\trecord.updatedAt = new Date();\n\t\tconst summary = this.buildSummary(record);\n\t\tthis.emitSessionsChanged({\n\t\t\tadded: [],\n\t\t\tupdated: [summary],\n\t\t\tremoved: [],\n\t\t});\n\t\treturn summary;\n\t}\n\n\tasync cancelSession(sessionId: string): Promise<boolean> {\n\t\tconst record = this.sessions.get(sessionId);\n\t\tif (!record) {\n\t\t\treturn false;\n\t\t}\n\t\tthis.cancelPermissionRequests(sessionId);\n\t\tawait record.connection.cancel(sessionId);\n\t\tthis.touchSession(sessionId);\n\t\treturn true;\n\t}\n\n\tasync closeSession(sessionId: string): Promise<boolean> {\n\t\tconst record = this.sessions.get(sessionId);\n\t\tif (!record) {\n\t\t\treturn false;\n\t\t}\n\t\ttry {\n\t\t\trecord.unsubscribe?.();\n\t\t\trecord.unsubscribeTerminal?.();\n\t\t} catch (error) {\n\t\t\tlogger.error({ err: error, sessionId }, \"session_unsubscribe_failed\");\n\t\t}\n\t\tthis.cancelPermissionRequests(sessionId);\n\t\ttry {\n\t\t\tawait record.connection.disconnect();\n\t\t} catch (error) {\n\t\t\tlogger.error({ err: error, sessionId }, \"session_disconnect_failed\");\n\t\t}\n\t\tthis.emitSessionDetached(sessionId, \"unknown\");\n\t\tthis.sessions.delete(sessionId);\n\t\tthis.emitSessionsChanged({\n\t\t\tadded: [],\n\t\t\tupdated: [],\n\t\t\tremoved: [sessionId],\n\t\t});\n\t\treturn true;\n\t}\n\n\tasync closeAll(): Promise<void> {\n\t\tconst sessionIds = Array.from(this.sessions.keys());\n\t\tawait Promise.all(\n\t\t\tsessionIds.map((sessionId) => this.closeSession(sessionId)),\n\t\t);\n\t}\n\n\t/**\n\t * Archive a session: close if active, delete WAL messages, mark as archived.\n\t */\n\tasync archiveSession(sessionId: string): Promise<void> {\n\t\tif (this.sessions.has(sessionId)) {\n\t\t\tawait this.closeSession(sessionId);\n\t\t}\n\t\tthis.walStore.archiveSession(sessionId);\n\t\tthis.discoveredSessions.delete(sessionId);\n\t}\n\n\t/**\n\t * Archive multiple sessions at once.\n\t */\n\tasync bulkArchiveSessions(\n\t\tsessionIds: string[],\n\t): Promise<{ archivedCount: number }> {\n\t\tawait Promise.allSettled(\n\t\t\tsessionIds\n\t\t\t\t.filter((id) => this.sessions.has(id))\n\t\t\t\t.map((id) => this.closeSession(id)),\n\t\t);\n\t\tconst archivedCount = this.walStore.bulkArchiveSessions(sessionIds);\n\t\tfor (const id of sessionIds) {\n\t\t\tthis.discoveredSessions.delete(id);\n\t\t}\n\t\treturn { archivedCount };\n\t}\n\n\t/**\n\t * Shutdown the session manager and close resources.\n\t */\n\tasync shutdown(): Promise<void> {\n\t\tawait this.closeAll();\n\t\tthis.walStore.close();\n\t}\n\n\t/**\n\t * Get previously discovered sessions from WAL storage.\n\t * Filters out sessions that are already loaded.\n\t * @param backendId Optional backend ID to filter by\n\t * @returns List of discovered sessions not currently loaded\n\t */\n\tgetPersistedDiscoveredSessions(backendId?: string): AcpSessionInfo[] {\n\t\treturn this.walStore\n\t\t\t.getDiscoveredSessions(backendId)\n\t\t\t.filter((s) => !this.sessions.has(s.sessionId) && s.cwd !== undefined)\n\t\t\t.map((s) => ({\n\t\t\t\tsessionId: s.sessionId,\n\t\t\t\tcwd: s.cwd as string, // Safe because we filter above\n\t\t\t\ttitle: s.title,\n\t\t\t\tupdatedAt: s.agentUpdatedAt,\n\t\t\t}));\n\t}\n\n\t/**\n\t * Discover sessions persisted by the ACP agent.\n\t * Creates a temporary connection to query sessions.\n\t * @param options Optional parameters for discovery\n\t * @returns List of discovered sessions and agent capabilities\n\t */\n\tasync discoverSessions(options: {\n\t\tcwd?: string;\n\t\tbackendId: string;\n\t\tcursor?: string;\n\t}): Promise<DiscoverSessionsRpcResult> {\n\t\tconst backend = this.resolveBackend(options.backendId);\n\t\tconst connection = this.createConnection(backend);\n\n\t\ttry {\n\t\t\tawait connection.connect();\n\t\t\tconst capabilities = connection.getSessionCapabilities();\n\t\t\tconst sessions: AcpSessionInfo[] = [];\n\t\t\tlet nextCursor: string | undefined;\n\n\t\t\tif (capabilities.list) {\n\t\t\t\tconst response = await connection.listSessions({\n\t\t\t\t\tcwd: options?.cwd,\n\t\t\t\t\tcursor: options?.cursor,\n\t\t\t\t});\n\t\t\t\tnextCursor = response.nextCursor;\n\n\t\t\t\t// Get archived IDs to filter them out\n\t\t\t\tconst archivedIds = new Set(this.walStore.getArchivedSessionIds());\n\n\t\t\t\tconst validity = await Promise.all(\n\t\t\t\t\tresponse.sessions.map(async (session) => ({\n\t\t\t\t\t\tsession,\n\t\t\t\t\t\tisValid: session.cwd\n\t\t\t\t\t\t\t? await isValidWorkspacePath(session.cwd)\n\t\t\t\t\t\t\t: false,\n\t\t\t\t\t})),\n\t\t\t\t);\n\n\t\t\t\tconst now = new Date().toISOString();\n\t\t\t\tconst discoveredRecords: Array<{\n\t\t\t\t\tsessionId: string;\n\t\t\t\t\tbackendId: string;\n\t\t\t\t\tcwd?: string;\n\t\t\t\t\ttitle?: string;\n\t\t\t\t\tagentUpdatedAt?: string;\n\t\t\t\t\tdiscoveredAt: string;\n\t\t\t\t\tisStale: boolean;\n\t\t\t\t}> = [];\n\n\t\t\t\tfor (const { session, isValid } of validity) {\n\t\t\t\t\tif (!isValid) {\n\t\t\t\t\t\tthis.discoveredSessions.delete(session.sessionId);\n\t\t\t\t\t\t// Mark as stale in WAL\n\t\t\t\t\t\tthis.walStore.markDiscoveredSessionStale(session.sessionId);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Skip archived sessions\n\t\t\t\t\tif (archivedIds.has(session.sessionId)) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tthis.discoveredSessions.set(session.sessionId, {\n\t\t\t\t\t\tsessionId: session.sessionId,\n\t\t\t\t\t\tcwd: session.cwd,\n\t\t\t\t\t\ttitle: session.title ?? undefined,\n\t\t\t\t\t\tupdatedAt: session.updatedAt ?? undefined,\n\t\t\t\t\t});\n\t\t\t\t\tsessions.push({\n\t\t\t\t\t\tsessionId: session.sessionId,\n\t\t\t\t\t\tcwd: session.cwd,\n\t\t\t\t\t\ttitle: session.title ?? undefined,\n\t\t\t\t\t\tupdatedAt: session.updatedAt ?? undefined,\n\t\t\t\t\t});\n\n\t\t\t\t\t// Collect for WAL persistence\n\t\t\t\t\tdiscoveredRecords.push({\n\t\t\t\t\t\tsessionId: session.sessionId,\n\t\t\t\t\t\tbackendId: backend.id,\n\t\t\t\t\t\tcwd: session.cwd,\n\t\t\t\t\t\ttitle: session.title ?? undefined,\n\t\t\t\t\t\tagentUpdatedAt: session.updatedAt ?? undefined,\n\t\t\t\t\t\tdiscoveredAt: now,\n\t\t\t\t\t\tisStale: false,\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\t// Persist to WAL\n\t\t\t\tif (discoveredRecords.length > 0) {\n\t\t\t\t\tthis.walStore.saveDiscoveredSessions(discoveredRecords);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlogger.info(\n\t\t\t\t{\n\t\t\t\t\tbackendId: backend.id,\n\t\t\t\t\tsessionCount: sessions.length,\n\t\t\t\t\tcapabilities,\n\t\t\t\t},\n\t\t\t\t\"sessions_discovered\",\n\t\t\t);\n\n\t\t\treturn { sessions, capabilities, nextCursor };\n\t\t} finally {\n\t\t\tawait connection.disconnect();\n\t\t}\n\t}\n\n\t/**\n\t * Load a historical session from the ACP agent.\n\t * This will replay the session's message history.\n\t * @param sessionId The session ID to load\n\t * @param cwd The working directory\n\t * @param backendId Optional backend ID\n\t * @returns The loaded session summary\n\t */\n\tasync loadSession(\n\t\tsessionId: string,\n\t\tcwd: string,\n\t\tbackendId: string,\n\t): Promise<SessionSummary> {\n\t\tlogger.info({ sessionId, cwd, backendId }, \"load_session_start\");\n\n\t\t// Check if session is already loaded\n\t\tconst existing = this.sessions.get(sessionId);\n\t\tif (existing) {\n\t\t\tlogger.debug({ sessionId }, \"load_session_already_loaded\");\n\t\t\tthis.emitSessionAttached(sessionId, true);\n\t\t\treturn this.buildSummary(existing);\n\t\t}\n\n\t\tconst backend = this.resolveBackend(backendId);\n\t\tconst connection = this.createConnection(backend);\n\n\t\ttry {\n\t\t\tawait connection.connect();\n\n\t\t\tif (!connection.supportsSessionLoad()) {\n\t\t\t\tthrow createCapabilityNotSupportedError(\n\t\t\t\t\t\"Agent does not support session loading\",\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// P0-9: Check if WAL already has history for this session\n\t\t\t// If so, bump revision to avoid duplicate imports\n\t\t\tconst existingWalSession = this.walStore.getSession(sessionId);\n\t\t\tconst hasExistingHistory =\n\t\t\t\texistingWalSession !== null &&\n\t\t\t\tthis.walStore.queryEvents({\n\t\t\t\t\tsessionId,\n\t\t\t\t\trevision: existingWalSession.currentRevision,\n\t\t\t\t\tafterSeq: 0,\n\t\t\t\t\tlimit: 1,\n\t\t\t\t}).length > 0;\n\n\t\t\tlet revision: number;\n\t\t\tif (hasExistingHistory) {\n\t\t\t\t// Already have history → bump revision to avoid duplicates\n\t\t\t\trevision = this.walStore.incrementRevision(sessionId);\n\t\t\t\tlogger.debug({ sessionId, revision }, \"load_session_bump_revision\");\n\t\t\t} else {\n\t\t\t\t// First time import → create or get existing revision\n\t\t\t\tconst result = this.walStore.ensureSession({\n\t\t\t\t\tsessionId,\n\t\t\t\t\tmachineId: this.config.machineId,\n\t\t\t\t\tbackendId: backend.id,\n\t\t\t\t\tcwd,\n\t\t\t\t});\n\t\t\t\trevision = result.revision;\n\t\t\t}\n\n\t\t\tconst bufferedUpdates: SessionNotification[] = [];\n\t\t\tlet recordRef: SessionRecord | undefined;\n\t\t\tconst unsubscribe = connection.onSessionUpdate(\n\t\t\t\t(notification: SessionNotification) => {\n\t\t\t\t\tlogger.debug(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tsessionId,\n\t\t\t\t\t\t\tupdateType: notification.update.sessionUpdate,\n\t\t\t\t\t\t\thasRecordRef: !!recordRef,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"load_session_update_received\",\n\t\t\t\t\t);\n\t\t\t\t\t// Write to WAL (emits via session:event)\n\t\t\t\t\tif (recordRef) {\n\t\t\t\t\t\tthis.writeSessionUpdateToWal(recordRef, notification);\n\t\t\t\t\t\trecordRef.updatedAt = new Date();\n\t\t\t\t\t\tthis.applySessionUpdateToRecord(recordRef, notification);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tbufferedUpdates.push(notification);\n\t\t\t\t\t\tlogger.debug(\n\t\t\t\t\t\t\t{ sessionId, bufferedCount: bufferedUpdates.length },\n\t\t\t\t\t\t\t\"load_session_buffered\",\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t);\n\n\t\t\tlogger.debug({ sessionId }, \"load_session_calling_acp\");\n\t\t\tconst response = await connection.loadSession(sessionId, cwd);\n\t\t\tlogger.debug(\n\t\t\t\t{\n\t\t\t\t\tsessionId,\n\t\t\t\t\tbufferedCount: bufferedUpdates.length,\n\t\t\t\t\thasModels: !!response.models,\n\t\t\t\t\thasModes: !!response.modes,\n\t\t\t\t},\n\t\t\t\t\"load_session_acp_returned\",\n\t\t\t);\n\t\t\tconnection.setPermissionHandler((params) =>\n\t\t\t\tthis.handlePermissionRequest(sessionId, params),\n\t\t\t);\n\n\t\t\tconst now = new Date();\n\t\t\tconst agentInfo = connection.getAgentInfo();\n\t\t\tconst { modelId, modelName, availableModels } = resolveModelState(\n\t\t\t\tresponse.models,\n\t\t\t);\n\t\t\tconst { modeId, modeName, availableModes } = resolveModeState(\n\t\t\t\tresponse.modes,\n\t\t\t);\n\t\t\tconst discovered = this.discoveredSessions.get(sessionId);\n\n\t\t\tconst record: SessionRecord = {\n\t\t\t\tsessionId,\n\t\t\t\ttitle: discovered?.title ?? sessionId,\n\t\t\t\tbackendId: backend.id,\n\t\t\t\tbackendLabel: backend.label,\n\t\t\t\tconnection,\n\t\t\t\tcreatedAt: now,\n\t\t\t\tupdatedAt: now,\n\t\t\t\tcwd,\n\t\t\t\tagentName: agentInfo?.title ?? agentInfo?.name,\n\t\t\t\tmodelId,\n\t\t\t\tmodelName,\n\t\t\t\tmodeId,\n\t\t\t\tmodeName,\n\t\t\t\tavailableModes,\n\t\t\t\tavailableModels,\n\t\t\t\tavailableCommands: undefined,\n\t\t\t\trevision,\n\t\t\t};\n\n\t\t\trecordRef = record;\n\t\t\trecord.unsubscribe = unsubscribe;\n\n\t\t\t// Initialize DEK for E2EE (new revision = new key)\n\t\t\tif (this.cryptoService) {\n\t\t\t\tthis.cryptoService.initSessionDek(sessionId);\n\t\t\t}\n\n\t\t\t// Write buffered updates to WAL\n\t\t\tlogger.debug(\n\t\t\t\t{ sessionId, bufferedCount: bufferedUpdates.length },\n\t\t\t\t\"load_session_writing_buffered\",\n\t\t\t);\n\t\t\tfor (const notification of bufferedUpdates) {\n\t\t\t\tlogger.debug(\n\t\t\t\t\t{ sessionId, updateType: notification.update.sessionUpdate },\n\t\t\t\t\t\"load_session_writing_buffered_event\",\n\t\t\t\t);\n\t\t\t\tthis.writeSessionUpdateToWal(record, notification);\n\t\t\t\tthis.applySessionUpdateToRecord(record, notification);\n\t\t\t}\n\n\t\t\tthis.setupSessionSubscriptions(record, { skipSessionUpdates: true });\n\n\t\t\tthis.sessions.set(sessionId, record);\n\n\t\t\tconst summary = this.buildSummary(record);\n\t\t\tthis.emitSessionsChanged({\n\t\t\t\tadded: [summary],\n\t\t\t\tupdated: [],\n\t\t\t\tremoved: [],\n\t\t\t});\n\t\t\tthis.emitSessionAttached(sessionId);\n\n\t\t\tlogger.info(\n\t\t\t\t{ sessionId, backendId: backend.id, revision: record.revision },\n\t\t\t\t\"load_session_complete\",\n\t\t\t);\n\n\t\t\treturn summary;\n\t\t} catch (error) {\n\t\t\tawait connection.disconnect();\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\t/**\n\t * Reload a historical session from the ACP agent.\n\t * Replays session history even if the session is already loaded.\n\t */\n\tasync reloadSession(\n\t\tsessionId: string,\n\t\tcwd: string,\n\t\tbackendId: string,\n\t): Promise<SessionSummary> {\n\t\tconst existing = this.sessions.get(sessionId);\n\t\tif (!existing) {\n\t\t\treturn this.loadSession(sessionId, cwd, backendId);\n\t\t}\n\n\t\tif (!existing.connection.supportsSessionLoad()) {\n\t\t\tthrow createCapabilityNotSupportedError(\n\t\t\t\t\"Agent does not support session loading\",\n\t\t\t);\n\t\t}\n\n\t\t// Increment revision in WAL (signals a fresh replay)\n\t\tconst newRevision = this.walStore.incrementRevision(sessionId);\n\t\texisting.revision = newRevision;\n\n\t\tconst response = await existing.connection.loadSession(sessionId, cwd);\n\t\tconst { modelId, modelName, availableModels } = resolveModelState(\n\t\t\tresponse.models,\n\t\t);\n\t\tconst { modeId, modeName, availableModes } = resolveModeState(\n\t\t\tresponse.modes,\n\t\t);\n\t\tconst agentInfo = existing.connection.getAgentInfo();\n\n\t\texisting.cwd = cwd;\n\t\texisting.agentName =\n\t\t\tagentInfo?.title ?? agentInfo?.name ?? existing.agentName;\n\t\texisting.modelId = modelId;\n\t\texisting.modelName = modelName;\n\t\texisting.availableModels = availableModels;\n\t\texisting.modeId = modeId;\n\t\texisting.modeName = modeName;\n\t\texisting.availableModes = availableModes;\n\t\texisting.updatedAt = new Date();\n\n\t\tconst summary = this.buildSummary(existing);\n\t\tthis.emitSessionsChanged({\n\t\t\tadded: [],\n\t\t\tupdated: [summary],\n\t\t\tremoved: [],\n\t\t});\n\t\tthis.emitSessionAttached(sessionId, true);\n\n\t\tlogger.info(\n\t\t\t{ sessionId, backendId, revision: newRevision },\n\t\t\t\"session_reloaded\",\n\t\t);\n\n\t\treturn summary;\n\t}\n\n\tprivate applySessionUpdateToRecord(\n\t\trecord: SessionRecord,\n\t\tnotification: SessionNotification,\n\t) {\n\t\tconst update = notification.update;\n\t\tif (update.sessionUpdate === \"current_mode_update\") {\n\t\t\trecord.modeId = update.currentModeId;\n\t\t\trecord.modeName =\n\t\t\t\trecord.availableModes?.find((mode) => mode.id === update.currentModeId)\n\t\t\t\t\t?.name ?? record.modeName;\n\t\t\treturn;\n\t\t}\n\t\tif (update.sessionUpdate === \"session_info_update\") {\n\t\t\tif (typeof update.title === \"string\") {\n\t\t\t\trecord.title = update.title;\n\t\t\t}\n\t\t\tif (typeof update.updatedAt === \"string\") {\n\t\t\t\trecord.updatedAt = new Date(update.updatedAt);\n\t\t\t}\n\t\t}\n\t\tif (update.sessionUpdate === \"available_commands_update\") {\n\t\t\tif (update.availableCommands) {\n\t\t\t\trecord.availableCommands = update.availableCommands;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Map a SessionNotification to WAL event kind and write to WAL.\n\t */\n\tprivate writeSessionUpdateToWal(\n\t\trecord: SessionRecord,\n\t\tnotification: SessionNotification,\n\t): void {\n\t\tconst update = notification.update;\n\t\tlet kind: SessionEventKind;\n\n\t\tlogger.debug(\n\t\t\t{\n\t\t\t\tsessionId: record.sessionId,\n\t\t\t\trevision: record.revision,\n\t\t\t\tupdateType: update.sessionUpdate,\n\t\t\t},\n\t\t\t\"write_session_update_to_wal_start\",\n\t\t);\n\n\t\tswitch (update.sessionUpdate) {\n\t\t\tcase \"user_message_chunk\":\n\t\t\t\tkind = \"user_message\";\n\t\t\t\tbreak;\n\t\t\tcase \"agent_message_chunk\":\n\t\t\t\tkind = \"agent_message_chunk\";\n\t\t\t\tbreak;\n\t\t\tcase \"agent_thought_chunk\":\n\t\t\t\tkind = \"agent_thought_chunk\";\n\t\t\t\tbreak;\n\t\t\tcase \"tool_call\":\n\t\t\t\tkind = \"tool_call\";\n\t\t\t\tbreak;\n\t\t\tcase \"tool_call_update\":\n\t\t\t\tkind = \"tool_call_update\";\n\t\t\t\tbreak;\n\t\t\tcase \"session_info_update\":\n\t\t\tcase \"current_mode_update\":\n\t\t\tcase \"available_commands_update\":\n\t\t\t\tkind = \"session_info_update\";\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\t// For unknown types, log but don't write to WAL\n\t\t\t\tlogger.warn(\n\t\t\t\t\t{ sessionId: record.sessionId, updateType: update.sessionUpdate },\n\t\t\t\t\t\"unknown_session_update_type_skipped\",\n\t\t\t\t);\n\t\t\t\treturn;\n\t\t}\n\n\t\tlogger.info(\n\t\t\t{\n\t\t\t\tsessionId: record.sessionId,\n\t\t\t\trevision: record.revision,\n\t\t\t\tupdateType: update.sessionUpdate,\n\t\t\t\tkind,\n\t\t\t},\n\t\t\t\"write_session_update_to_wal_mapped\",\n\t\t);\n\n\t\tthis.writeAndEmitEvent(\n\t\t\trecord.sessionId,\n\t\t\trecord.revision,\n\t\t\tkind,\n\t\t\tnotification,\n\t\t);\n\t}\n\n\t/**\n\t * Set up event subscriptions for a session record.\n\t */\n\tprivate setupSessionSubscriptions(\n\t\trecord: SessionRecord,\n\t\toptions?: { skipSessionUpdates?: boolean },\n\t): void {\n\t\tconst { sessionId, connection } = record;\n\n\t\tlogger.debug(\n\t\t\t{ sessionId, skipSessionUpdates: options?.skipSessionUpdates },\n\t\t\t\"setup_session_subscriptions\",\n\t\t);\n\n\t\tif (!options?.skipSessionUpdates) {\n\t\t\trecord.unsubscribe = connection.onSessionUpdate(\n\t\t\t\t(notification: SessionNotification) => {\n\t\t\t\t\tlogger.debug(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tsessionId,\n\t\t\t\t\t\t\tupdateType: notification.update.sessionUpdate,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"acp_session_update_received_via_setup\",\n\t\t\t\t\t);\n\t\t\t\t\trecord.updatedAt = new Date();\n\t\t\t\t\t// Write to WAL and emit via session:event (unified event channel)\n\t\t\t\t\tthis.writeSessionUpdateToWal(record, notification);\n\t\t\t\t\tthis.applySessionUpdateToRecord(record, notification);\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\n\t\trecord.unsubscribeTerminal = connection.onTerminalOutput((event) => {\n\t\t\tlogger.debug({ sessionId }, \"acp_terminal_output_received_via_setup\");\n\t\t\t// Write terminal output to WAL (emits via session:event)\n\t\t\tthis.writeAndEmitEvent(\n\t\t\t\tsessionId,\n\t\t\t\trecord.revision,\n\t\t\t\t\"terminal_output\",\n\t\t\t\tevent,\n\t\t\t);\n\t\t});\n\n\t\tconnection.onStatusChange((status) => {\n\t\t\tlogger.debug(\n\t\t\t\t{ sessionId, hasError: !!status.error },\n\t\t\t\t\"acp_status_change\",\n\t\t\t);\n\t\t\tif (status.error) {\n\t\t\t\t// Write error to WAL (emits via session:event)\n\t\t\t\tthis.writeAndEmitEvent(sessionId, record.revision, \"session_error\", {\n\t\t\t\t\terror: status.error,\n\t\t\t\t});\n\t\t\t\tthis.emitSessionDetached(sessionId, \"agent_exit\");\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate buildSummary(record: SessionRecord): SessionSummary {\n\t\tconst status = record.connection.getStatus();\n\t\treturn {\n\t\t\tsessionId: record.sessionId,\n\t\t\ttitle: record.title,\n\t\t\tbackendId: record.backendId,\n\t\t\tbackendLabel: record.backendLabel,\n\t\t\terror: status.error,\n\t\t\tpid: status.pid,\n\t\t\tcreatedAt: record.createdAt.toISOString(),\n\t\t\tupdatedAt: record.updatedAt.toISOString(),\n\t\t\tcwd: record.cwd,\n\t\t\tagentName: record.agentName,\n\t\t\tmodelId: record.modelId,\n\t\t\tmodelName: record.modelName,\n\t\t\tmodeId: record.modeId,\n\t\t\tmodeName: record.modeName,\n\t\t\tavailableModes: record.availableModes,\n\t\t\tavailableModels: record.availableModels,\n\t\t\tavailableCommands: record.availableCommands,\n\t\t\trevision: record.revision,\n\t\t\twrappedDek:\n\t\t\t\tthis.cryptoService?.getWrappedDek(record.sessionId) ?? undefined,\n\t\t};\n\t}\n}\n",
13
+ "import type { Database } from \"bun:sqlite\";\nimport type { CompactionConfig } from \"../config.js\";\nimport { logger } from \"../lib/logger.js\";\nimport type { WalStore } from \"./wal-store.js\";\n\nexport type CompactionStats = {\n\tsessionId: string;\n\tackedEventsDeleted: number;\n\toldRevisionsDeleted: number;\n\tdurationMs: number;\n};\n\nexport type CompactionResult = {\n\tstats: CompactionStats[];\n\ttotalDurationMs: number;\n\tskipped: string[];\n};\n\n/**\n * WAL Compactor - handles cleanup and optimization of the WAL database.\n *\n * Operations:\n * 1. Delete acked events older than retention period\n * 2. Delete events from old revisions (keeps latest N revisions)\n * 3. Run SQLite VACUUM to reclaim space\n */\nexport class WalCompactor {\n\tprivate db: Database;\n\tprivate activeSessionIds = new Set<string>();\n\n\t// Prepared statements\n\tprivate stmtGetAllSessions: ReturnType<Database[\"query\"]>;\n\tprivate stmtGetSessionRevisions: ReturnType<Database[\"query\"]>;\n\tprivate stmtDeleteAckedEvents: ReturnType<Database[\"query\"]>;\n\tprivate stmtDeleteOldRevisionEvents: ReturnType<Database[\"query\"]>;\n\tprivate stmtCountEvents: ReturnType<Database[\"query\"]>;\n\tprivate stmtLogCompaction: ReturnType<Database[\"query\"]>;\n\n\tconstructor(\n\t\t_walStore: WalStore,\n\t\tprivate readonly config: CompactionConfig,\n\t\tdb: Database,\n\t) {\n\t\tthis.db = db;\n\n\t\tthis.stmtGetAllSessions = this.db.query(`\n\t\t\tSELECT DISTINCT session_id FROM sessions\n\t\t`);\n\n\t\tthis.stmtGetSessionRevisions = this.db.query(`\n\t\t\tSELECT DISTINCT revision FROM session_events\n\t\t\tWHERE session_id = $sessionId\n\t\t\tORDER BY revision DESC\n\t\t`);\n\n\t\tthis.stmtDeleteAckedEvents = this.db.query(`\n\t\t\tDELETE FROM session_events\n\t\t\tWHERE session_id = $sessionId\n\t\t\t AND revision = $revision\n\t\t\t AND acked_at IS NOT NULL\n\t\t\t AND acked_at < $olderThan\n\t\t\t AND id NOT IN (\n\t\t\t SELECT id FROM session_events\n\t\t\t WHERE session_id = $sessionId AND revision = $revision\n\t\t\t ORDER BY seq DESC\n\t\t\t LIMIT $minKeep\n\t\t\t )\n\t\t`);\n\n\t\tthis.stmtDeleteOldRevisionEvents = this.db.query(`\n\t\t\tDELETE FROM session_events\n\t\t\tWHERE session_id = $sessionId\n\t\t\t AND revision = $revision\n\t\t`);\n\n\t\tthis.stmtCountEvents = this.db.query(`\n\t\t\tSELECT COUNT(*) as count FROM session_events\n\t\t\tWHERE session_id = $sessionId AND revision = $revision\n\t\t`);\n\n\t\tthis.stmtLogCompaction = this.db.query(`\n\t\t\tINSERT INTO compaction_log (session_id, revision, operation, events_affected, started_at, completed_at)\n\t\t\tVALUES ($sessionId, $revision, $operation, $eventsAffected, $startedAt, $completedAt)\n\t\t`);\n\t}\n\n\t/**\n\t * Mark a session as actively streaming (will be skipped during compaction).\n\t */\n\tmarkSessionActive(sessionId: string): void {\n\t\tthis.activeSessionIds.add(sessionId);\n\t}\n\n\t/**\n\t * Mark a session as inactive (eligible for compaction).\n\t */\n\tmarkSessionInactive(sessionId: string): void {\n\t\tthis.activeSessionIds.delete(sessionId);\n\t}\n\n\t/**\n\t * Check if a session should be skipped during compaction.\n\t */\n\tprivate shouldSkipSession(sessionId: string): boolean {\n\t\treturn this.activeSessionIds.has(sessionId);\n\t}\n\n\t/**\n\t * Compact all sessions.\n\t */\n\tasync compactAll(options?: { dryRun?: boolean }): Promise<CompactionResult> {\n\t\tconst startTime = performance.now();\n\t\tconst stats: CompactionStats[] = [];\n\t\tconst skipped: string[] = [];\n\n\t\tconst sessions = this.stmtGetAllSessions.all() as Array<{\n\t\t\tsession_id: string;\n\t\t}>;\n\n\t\tfor (const { session_id: sessionId } of sessions) {\n\t\t\tif (this.shouldSkipSession(sessionId)) {\n\t\t\t\tskipped.push(sessionId);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst sessionStats = await this.compactSession(sessionId, options);\n\t\t\t\tstats.push(sessionStats);\n\t\t\t} catch (error) {\n\t\t\t\tlogger.error({ err: error, sessionId }, \"compaction_session_error\");\n\t\t\t}\n\t\t}\n\n\t\tconst totalDurationMs = performance.now() - startTime;\n\n\t\t// Run VACUUM if not dry run and we deleted anything\n\t\tconst totalDeleted = stats.reduce(\n\t\t\t(sum, s) => sum + s.ackedEventsDeleted + s.oldRevisionsDeleted,\n\t\t\t0,\n\t\t);\n\t\tif (!options?.dryRun && totalDeleted > 0) {\n\t\t\ttry {\n\t\t\t\tthis.db.exec(\"VACUUM\");\n\t\t\t\tlogger.info({ totalDeleted }, \"compaction_vacuum_complete\");\n\t\t\t} catch (error) {\n\t\t\t\tlogger.error({ err: error }, \"compaction_vacuum_error\");\n\t\t\t}\n\t\t}\n\n\t\tlogger.info(\n\t\t\t{\n\t\t\t\tsessionsCompacted: stats.length,\n\t\t\t\tsessionsSkipped: skipped.length,\n\t\t\t\ttotalDeleted,\n\t\t\t\ttotalDurationMs,\n\t\t\t},\n\t\t\t\"compaction_complete\",\n\t\t);\n\n\t\treturn { stats, totalDurationMs, skipped };\n\t}\n\n\t/**\n\t * Compact a single session.\n\t */\n\tasync compactSession(\n\t\tsessionId: string,\n\t\toptions?: { dryRun?: boolean },\n\t): Promise<CompactionStats> {\n\t\tconst startTime = performance.now();\n\t\tlet ackedEventsDeleted = 0;\n\t\tlet oldRevisionsDeleted = 0;\n\n\t\t// Get all revisions for this session\n\t\tconst revisions = this.stmtGetSessionRevisions.all({\n\t\t\t$sessionId: sessionId,\n\t\t}) as Array<{ revision: number }>;\n\n\t\tif (revisions.length === 0) {\n\t\t\treturn {\n\t\t\t\tsessionId,\n\t\t\t\tackedEventsDeleted: 0,\n\t\t\t\toldRevisionsDeleted: 0,\n\t\t\t\tdurationMs: performance.now() - startTime,\n\t\t\t};\n\t\t}\n\n\t\tconst revisionsToKeep = revisions\n\t\t\t.slice(0, this.config.keepLatestRevisionsCount)\n\t\t\t.map((r) => r.revision);\n\n\t\t// Calculate cutoff date for acked events\n\t\tconst ackedCutoff = new Date();\n\t\tackedCutoff.setDate(\n\t\t\tackedCutoff.getDate() - this.config.ackedEventRetentionDays,\n\t\t);\n\t\t// P1-3: Removed unused revisionCutoff - only keepLatestRevisionsCount is used\n\n\t\t// Process each revision\n\t\tfor (const { revision } of revisions) {\n\t\t\t// Check if this is an old revision that can be deleted entirely\n\t\t\tif (!revisionsToKeep.includes(revision)) {\n\t\t\t\t// Delete all events for old revisions\n\t\t\t\tconst countResult = this.stmtCountEvents.get({\n\t\t\t\t\t$sessionId: sessionId,\n\t\t\t\t\t$revision: revision,\n\t\t\t\t}) as { count: number };\n\n\t\t\t\tif (!options?.dryRun) {\n\t\t\t\t\tconst result = this.stmtDeleteOldRevisionEvents.run({\n\t\t\t\t\t\t$sessionId: sessionId,\n\t\t\t\t\t\t$revision: revision,\n\t\t\t\t\t});\n\t\t\t\t\toldRevisionsDeleted += result.changes;\n\n\t\t\t\t\tthis.logCompaction(\n\t\t\t\t\t\tsessionId,\n\t\t\t\t\t\trevision,\n\t\t\t\t\t\t\"delete_old_revision\",\n\t\t\t\t\t\tresult.changes,\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\toldRevisionsDeleted += countResult.count;\n\t\t\t\t}\n\n\t\t\t\tlogger.debug(\n\t\t\t\t\t{ sessionId, revision, count: countResult.count },\n\t\t\t\t\t\"compaction_delete_old_revision\",\n\t\t\t\t);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// For kept revisions, delete old acked events\n\t\t\tif (!options?.dryRun) {\n\t\t\t\tconst result = this.stmtDeleteAckedEvents.run({\n\t\t\t\t\t$sessionId: sessionId,\n\t\t\t\t\t$revision: revision,\n\t\t\t\t\t$olderThan: ackedCutoff.toISOString(),\n\t\t\t\t\t$minKeep: this.config.minEventsToKeep,\n\t\t\t\t});\n\t\t\t\tackedEventsDeleted += result.changes;\n\n\t\t\t\tif (result.changes > 0) {\n\t\t\t\t\tthis.logCompaction(\n\t\t\t\t\t\tsessionId,\n\t\t\t\t\t\trevision,\n\t\t\t\t\t\t\"delete_acked_events\",\n\t\t\t\t\t\tresult.changes,\n\t\t\t\t\t);\n\t\t\t\t\tlogger.debug(\n\t\t\t\t\t\t{ sessionId, revision, deleted: result.changes },\n\t\t\t\t\t\t\"compaction_delete_acked\",\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst durationMs = performance.now() - startTime;\n\n\t\tif (ackedEventsDeleted > 0 || oldRevisionsDeleted > 0) {\n\t\t\tlogger.info(\n\t\t\t\t{ sessionId, ackedEventsDeleted, oldRevisionsDeleted, durationMs },\n\t\t\t\t\"compaction_session_complete\",\n\t\t\t);\n\t\t}\n\n\t\treturn {\n\t\t\tsessionId,\n\t\t\tackedEventsDeleted,\n\t\t\toldRevisionsDeleted,\n\t\t\tdurationMs,\n\t\t};\n\t}\n\n\tprivate logCompaction(\n\t\tsessionId: string,\n\t\trevision: number | null,\n\t\toperation: string,\n\t\teventsAffected: number,\n\t): void {\n\t\tconst now = new Date().toISOString();\n\t\tthis.stmtLogCompaction.run({\n\t\t\t$sessionId: sessionId,\n\t\t\t$revision: revision,\n\t\t\t$operation: operation,\n\t\t\t$eventsAffected: eventsAffected,\n\t\t\t$startedAt: now,\n\t\t\t$completedAt: now,\n\t\t});\n\t}\n}\n",
14
+ "import type { Database } from \"bun:sqlite\";\n\nconst MIGRATIONS = [\n\t{\n\t\tversion: 1,\n\t\tup: `\n -- Sessions table to track session metadata and current revision\n CREATE TABLE IF NOT EXISTS sessions (\n session_id TEXT PRIMARY KEY,\n machine_id TEXT NOT NULL,\n backend_id TEXT NOT NULL,\n current_revision INTEGER NOT NULL DEFAULT 1,\n cwd TEXT,\n title TEXT,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL\n );\n\n -- Session events WAL table\n CREATE TABLE IF NOT EXISTS session_events (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n session_id TEXT NOT NULL,\n revision INTEGER NOT NULL,\n seq INTEGER NOT NULL,\n kind TEXT NOT NULL,\n payload TEXT NOT NULL,\n created_at TEXT NOT NULL,\n acked_at TEXT,\n UNIQUE (session_id, revision, seq)\n );\n\n -- Index for querying events by session and revision\n CREATE INDEX IF NOT EXISTS idx_session_events_session_revision\n ON session_events (session_id, revision, seq);\n\n -- Index for querying unacked events\n CREATE INDEX IF NOT EXISTS idx_session_events_unacked\n ON session_events (session_id, revision, acked_at)\n WHERE acked_at IS NULL;\n\n -- Schema version tracking\n CREATE TABLE IF NOT EXISTS schema_version (\n version INTEGER PRIMARY KEY\n );\n `,\n\t},\n\t{\n\t\tversion: 2,\n\t\tup: `\n -- Discovered sessions table for persisting sessions found via discoverSessions()\n CREATE TABLE IF NOT EXISTS discovered_sessions (\n session_id TEXT PRIMARY KEY,\n backend_id TEXT NOT NULL,\n cwd TEXT,\n title TEXT,\n agent_updated_at TEXT, -- agent-reported update time\n discovered_at TEXT NOT NULL,\n last_verified_at TEXT, -- last time cwd was verified to exist\n is_stale INTEGER DEFAULT 0 -- marked stale when cwd no longer exists\n );\n\n CREATE INDEX IF NOT EXISTS idx_discovered_sessions_backend\n ON discovered_sessions (backend_id);\n\n -- Add agent_updated_at to sessions table\n ALTER TABLE sessions ADD COLUMN agent_updated_at TEXT;\n `,\n\t},\n\t{\n\t\tversion: 3,\n\t\tup: `\n -- Compaction support\n ALTER TABLE session_events ADD COLUMN compacted_at TEXT;\n\n -- Index for finding acked events eligible for cleanup\n CREATE INDEX IF NOT EXISTS idx_session_events_acked_at\n ON session_events (session_id, revision, acked_at)\n WHERE acked_at IS NOT NULL;\n\n -- Index for finding events by kind (for chunk consolidation)\n CREATE INDEX IF NOT EXISTS idx_session_events_kind\n ON session_events (session_id, revision, kind);\n\n -- Compaction operation log\n CREATE TABLE IF NOT EXISTS compaction_log (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n session_id TEXT NOT NULL,\n revision INTEGER,\n operation TEXT NOT NULL,\n events_affected INTEGER NOT NULL,\n started_at TEXT NOT NULL,\n completed_at TEXT\n );\n `,\n\t},\n\t{\n\t\tversion: 4,\n\t\tup: `\n -- Archived sessions table (local archive state)\n CREATE TABLE IF NOT EXISTS archived_session_ids (\n session_id TEXT PRIMARY KEY,\n archived_at TEXT NOT NULL\n );\n `,\n\t},\n];\n\nexport function runMigrations(db: Database): void {\n\t// Enable WAL mode for better concurrency\n\tdb.exec(\"PRAGMA journal_mode = WAL\");\n\tdb.exec(\"PRAGMA synchronous = NORMAL\");\n\n\t// Get current version\n\tlet currentVersion = 0;\n\ttry {\n\t\tconst result = db\n\t\t\t.query(\"SELECT MAX(version) as version FROM schema_version\")\n\t\t\t.get() as { version: number | null } | null;\n\t\tcurrentVersion = result?.version ?? 0;\n\t} catch {\n\t\t// Table doesn't exist yet, version is 0\n\t}\n\n\t// Run pending migrations\n\tfor (const migration of MIGRATIONS) {\n\t\tif (migration.version > currentVersion) {\n\t\t\tdb.exec(migration.up);\n\t\t\tdb.exec(\n\t\t\t\t`INSERT INTO schema_version (version) VALUES (${migration.version})`,\n\t\t\t);\n\t\t}\n\t}\n}\n",
15
+ "/**\n * Sequence generator for monotonically increasing sequence numbers\n * per session/revision combination.\n */\nexport class SeqGenerator {\n\tprivate sequences = new Map<string, number>();\n\n\tprivate buildKey(sessionId: string, revision: number): string {\n\t\treturn `${sessionId}:${revision}`;\n\t}\n\n\t/**\n\t * Initialize the sequence for a session/revision from the last known value.\n\t */\n\tinitialize(sessionId: string, revision: number, lastSeq: number): void {\n\t\tconst key = this.buildKey(sessionId, revision);\n\t\tthis.sequences.set(key, lastSeq);\n\t}\n\n\t/**\n\t * Get the next sequence number for a session/revision.\n\t */\n\tnext(sessionId: string, revision: number): number {\n\t\tconst key = this.buildKey(sessionId, revision);\n\t\tconst current = this.sequences.get(key) ?? 0;\n\t\tconst next = current + 1;\n\t\tthis.sequences.set(key, next);\n\t\treturn next;\n\t}\n\n\t/**\n\t * Get the current (last assigned) sequence number for a session/revision.\n\t * Returns 0 if no sequence has been assigned.\n\t */\n\tcurrent(sessionId: string, revision: number): number {\n\t\tconst key = this.buildKey(sessionId, revision);\n\t\treturn this.sequences.get(key) ?? 0;\n\t}\n\n\t/**\n\t * Reset the sequence for a session/revision (used when revision changes).\n\t */\n\treset(sessionId: string, revision: number): void {\n\t\tconst key = this.buildKey(sessionId, revision);\n\t\tthis.sequences.set(key, 0);\n\t}\n\n\t/**\n\t * Clear all sequences for a session (used when session is closed).\n\t */\n\tclearSession(sessionId: string): void {\n\t\tfor (const key of this.sequences.keys()) {\n\t\t\tif (key.startsWith(`${sessionId}:`)) {\n\t\t\t\tthis.sequences.delete(key);\n\t\t\t}\n\t\t}\n\t}\n}\n",
16
+ "import { Database } from \"bun:sqlite\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport type { SessionEventKind } from \"@mobvibe/shared\";\nimport { logger } from \"../lib/logger.js\";\nimport { runMigrations } from \"./migrations.js\";\nimport { SeqGenerator } from \"./seq-generator.js\";\n\nexport type WalSession = {\n\tsessionId: string;\n\tmachineId: string;\n\tbackendId: string;\n\tcurrentRevision: number;\n\tcwd?: string;\n\ttitle?: string;\n\tcreatedAt: string;\n\tupdatedAt: string;\n};\n\nexport type WalEvent = {\n\tid: number;\n\tsessionId: string;\n\trevision: number;\n\tseq: number;\n\tkind: SessionEventKind;\n\tpayload: unknown;\n\tcreatedAt: string;\n\tackedAt?: string;\n};\n\nexport type AppendEventParams = {\n\tsessionId: string;\n\trevision: number;\n\tkind: SessionEventKind;\n\tpayload: unknown;\n};\n\nexport type QueryEventsParams = {\n\tsessionId: string;\n\trevision: number;\n\tafterSeq?: number;\n\tlimit?: number;\n};\n\nexport type EnsureSessionParams = {\n\tsessionId: string;\n\tmachineId: string;\n\tbackendId: string;\n\tcwd?: string;\n\ttitle?: string;\n};\n\nexport type DiscoveredSession = {\n\tsessionId: string;\n\tbackendId: string;\n\tcwd?: string;\n\ttitle?: string;\n\tagentUpdatedAt?: string;\n\tdiscoveredAt: string;\n\tlastVerifiedAt?: string;\n\tisStale: boolean;\n};\n\nconst DEFAULT_QUERY_LIMIT = 100;\n\nexport class WalStore {\n\tprivate db: Database;\n\tprivate seqGenerator = new SeqGenerator();\n\n\t// Prepared statements for performance\n\tprivate stmtGetSession: ReturnType<Database[\"query\"]>;\n\tprivate stmtInsertSession: ReturnType<Database[\"query\"]>;\n\tprivate stmtUpdateSession: ReturnType<Database[\"query\"]>;\n\tprivate stmtInsertEvent: ReturnType<Database[\"query\"]>;\n\tprivate stmtQueryEvents: ReturnType<Database[\"query\"]>;\n\tprivate stmtQueryUnackedEvents: ReturnType<Database[\"query\"]>;\n\tprivate stmtAckEvents: ReturnType<Database[\"query\"]>;\n\tprivate stmtIncrementRevision: ReturnType<Database[\"query\"]>;\n\tprivate stmtGetMaxSeq: ReturnType<Database[\"query\"]>;\n\n\t// Discovered sessions statements\n\tprivate stmtUpsertDiscoveredSession: ReturnType<Database[\"query\"]>;\n\tprivate stmtGetDiscoveredSessions: ReturnType<Database[\"query\"]>;\n\tprivate stmtGetDiscoveredSessionsByBackend: ReturnType<Database[\"query\"]>;\n\tprivate stmtMarkDiscoveredSessionStale: ReturnType<Database[\"query\"]>;\n\tprivate stmtDeleteStaleDiscoveredSessions: ReturnType<Database[\"query\"]>;\n\n\t// Archive statements\n\tprivate stmtDeleteSessionEvents: ReturnType<Database[\"query\"]>;\n\tprivate stmtDeleteSession: ReturnType<Database[\"query\"]>;\n\tprivate stmtInsertArchivedSession: ReturnType<Database[\"query\"]>;\n\tprivate stmtIsArchived: ReturnType<Database[\"query\"]>;\n\tprivate stmtGetArchivedSessionIds: ReturnType<Database[\"query\"]>;\n\n\tconstructor(dbPath: string) {\n\t\t// Ensure directory exists\n\t\tconst dir = path.dirname(dbPath);\n\t\tif (!fs.existsSync(dir)) {\n\t\t\tfs.mkdirSync(dir, { recursive: true });\n\t\t}\n\n\t\tthis.db = new Database(dbPath);\n\t\trunMigrations(this.db);\n\n\t\t// Prepare statements\n\t\tthis.stmtGetSession = this.db.query(`\n SELECT session_id, machine_id, backend_id, current_revision, cwd, title, created_at, updated_at\n FROM sessions\n WHERE session_id = $sessionId\n `);\n\n\t\tthis.stmtInsertSession = this.db.query(`\n INSERT INTO sessions (session_id, machine_id, backend_id, current_revision, cwd, title, created_at, updated_at)\n VALUES ($sessionId, $machineId, $backendId, 1, $cwd, $title, $createdAt, $updatedAt)\n `);\n\n\t\tthis.stmtUpdateSession = this.db.query(`\n UPDATE sessions\n SET cwd = COALESCE($cwd, cwd),\n title = COALESCE($title, title),\n updated_at = $updatedAt\n WHERE session_id = $sessionId\n `);\n\n\t\tthis.stmtInsertEvent = this.db.query(`\n INSERT INTO session_events (session_id, revision, seq, kind, payload, created_at)\n VALUES ($sessionId, $revision, $seq, $kind, $payload, $createdAt)\n `);\n\n\t\tthis.stmtQueryEvents = this.db.query(`\n SELECT id, session_id, revision, seq, kind, payload, created_at, acked_at\n FROM session_events\n WHERE session_id = $sessionId\n AND revision = $revision\n AND seq > $afterSeq\n ORDER BY seq ASC\n LIMIT $limit\n `);\n\n\t\tthis.stmtQueryUnackedEvents = this.db.query(`\n SELECT id, session_id, revision, seq, kind, payload, created_at, acked_at\n FROM session_events\n WHERE session_id = $sessionId\n AND revision = $revision\n AND acked_at IS NULL\n ORDER BY seq ASC\n `);\n\n\t\tthis.stmtAckEvents = this.db.query(`\n UPDATE session_events\n SET acked_at = $ackedAt\n WHERE session_id = $sessionId\n AND revision = $revision\n AND seq <= $upToSeq\n AND acked_at IS NULL\n `);\n\n\t\tthis.stmtIncrementRevision = this.db.query(`\n UPDATE sessions\n SET current_revision = current_revision + 1,\n updated_at = $updatedAt\n WHERE session_id = $sessionId\n RETURNING current_revision\n `);\n\n\t\tthis.stmtGetMaxSeq = this.db.query(`\n SELECT MAX(seq) as max_seq\n FROM session_events\n WHERE session_id = $sessionId AND revision = $revision\n `);\n\n\t\t// Discovered sessions statements\n\t\tthis.stmtUpsertDiscoveredSession = this.db.query(`\n INSERT INTO discovered_sessions (\n session_id, backend_id, cwd, title, agent_updated_at,\n discovered_at, last_verified_at, is_stale\n ) VALUES (\n $sessionId, $backendId, $cwd, $title, $agentUpdatedAt,\n $discoveredAt, $lastVerifiedAt, 0\n )\n ON CONFLICT (session_id) DO UPDATE SET\n backend_id = $backendId,\n cwd = COALESCE($cwd, discovered_sessions.cwd),\n title = COALESCE($title, discovered_sessions.title),\n agent_updated_at = COALESCE($agentUpdatedAt, discovered_sessions.agent_updated_at),\n last_verified_at = $lastVerifiedAt,\n is_stale = 0\n `);\n\n\t\tthis.stmtGetDiscoveredSessions = this.db.query(`\n SELECT d.session_id, d.backend_id, d.cwd, d.title, d.agent_updated_at,\n d.discovered_at, d.last_verified_at, d.is_stale\n FROM discovered_sessions d\n LEFT JOIN archived_session_ids a ON d.session_id = a.session_id\n WHERE d.is_stale = 0 AND a.session_id IS NULL\n ORDER BY d.discovered_at DESC\n `);\n\n\t\tthis.stmtGetDiscoveredSessionsByBackend = this.db.query(`\n SELECT d.session_id, d.backend_id, d.cwd, d.title, d.agent_updated_at,\n d.discovered_at, d.last_verified_at, d.is_stale\n FROM discovered_sessions d\n LEFT JOIN archived_session_ids a ON d.session_id = a.session_id\n WHERE d.backend_id = $backendId AND d.is_stale = 0 AND a.session_id IS NULL\n ORDER BY d.discovered_at DESC\n `);\n\n\t\tthis.stmtMarkDiscoveredSessionStale = this.db.query(`\n UPDATE discovered_sessions\n SET is_stale = 1\n WHERE session_id = $sessionId\n `);\n\n\t\tthis.stmtDeleteStaleDiscoveredSessions = this.db.query(`\n DELETE FROM discovered_sessions\n WHERE is_stale = 1 AND discovered_at < $olderThan\n `);\n\n\t\t// Archive statements\n\t\tthis.stmtDeleteSessionEvents = this.db.query(`\n DELETE FROM session_events WHERE session_id = $sessionId\n `);\n\n\t\tthis.stmtDeleteSession = this.db.query(`\n DELETE FROM sessions WHERE session_id = $sessionId\n `);\n\n\t\tthis.stmtInsertArchivedSession = this.db.query(`\n INSERT OR IGNORE INTO archived_session_ids (session_id, archived_at)\n VALUES ($sessionId, $archivedAt)\n `);\n\n\t\tthis.stmtIsArchived = this.db.query(`\n SELECT 1 FROM archived_session_ids WHERE session_id = $sessionId\n `);\n\n\t\tthis.stmtGetArchivedSessionIds = this.db.query(`\n SELECT session_id FROM archived_session_ids\n `);\n\t}\n\n\t/**\n\t * Ensure a session exists in the WAL store.\n\t * Creates if not exists, updates metadata if exists.\n\t */\n\tensureSession(params: EnsureSessionParams): { revision: number } {\n\t\tconst now = new Date().toISOString();\n\t\tconst existing = this.stmtGetSession.get({\n\t\t\t$sessionId: params.sessionId,\n\t\t}) as WalSessionRow | null;\n\n\t\tlogger.debug(\n\t\t\t{ sessionId: params.sessionId, exists: !!existing },\n\t\t\t\"wal_ensure_session\",\n\t\t);\n\n\t\tif (existing) {\n\t\t\t// Update metadata\n\t\t\tthis.stmtUpdateSession.run({\n\t\t\t\t$sessionId: params.sessionId,\n\t\t\t\t$cwd: params.cwd ?? null,\n\t\t\t\t$title: params.title ?? null,\n\t\t\t\t$updatedAt: now,\n\t\t\t});\n\n\t\t\t// Initialize sequence generator\n\t\t\tconst maxSeq = this.getMaxSeq(\n\t\t\t\tparams.sessionId,\n\t\t\t\texisting.current_revision,\n\t\t\t);\n\t\t\tthis.seqGenerator.initialize(\n\t\t\t\tparams.sessionId,\n\t\t\t\texisting.current_revision,\n\t\t\t\tmaxSeq,\n\t\t\t);\n\n\t\t\tlogger.debug(\n\t\t\t\t{\n\t\t\t\t\tsessionId: params.sessionId,\n\t\t\t\t\trevision: existing.current_revision,\n\t\t\t\t\tmaxSeq,\n\t\t\t\t},\n\t\t\t\t\"wal_session_existing\",\n\t\t\t);\n\n\t\t\treturn { revision: existing.current_revision };\n\t\t}\n\n\t\t// Insert new session\n\t\tthis.stmtInsertSession.run({\n\t\t\t$sessionId: params.sessionId,\n\t\t\t$machineId: params.machineId,\n\t\t\t$backendId: params.backendId,\n\t\t\t$cwd: params.cwd ?? null,\n\t\t\t$title: params.title ?? null,\n\t\t\t$createdAt: now,\n\t\t\t$updatedAt: now,\n\t\t});\n\n\t\t// Initialize sequence generator at 0\n\t\tthis.seqGenerator.initialize(params.sessionId, 1, 0);\n\n\t\tlogger.info(\n\t\t\t{ sessionId: params.sessionId, revision: 1 },\n\t\t\t\"wal_session_created\",\n\t\t);\n\n\t\treturn { revision: 1 };\n\t}\n\n\t/**\n\t * Get a session by ID.\n\t */\n\tgetSession(sessionId: string): WalSession | null {\n\t\tconst row = this.stmtGetSession.get({\n\t\t\t$sessionId: sessionId,\n\t\t}) as WalSessionRow | null;\n\t\tif (!row) return null;\n\t\treturn this.rowToSession(row);\n\t}\n\n\t/**\n\t * Append an event to the WAL.\n\t */\n\tappendEvent(params: AppendEventParams): WalEvent {\n\t\tconst seq = this.seqGenerator.next(params.sessionId, params.revision);\n\t\tconst now = new Date().toISOString();\n\n\t\tlogger.debug(\n\t\t\t{\n\t\t\t\tsessionId: params.sessionId,\n\t\t\t\trevision: params.revision,\n\t\t\t\tseq,\n\t\t\t\tkind: params.kind,\n\t\t\t},\n\t\t\t\"wal_append_event\",\n\t\t);\n\n\t\tthis.stmtInsertEvent.run({\n\t\t\t$sessionId: params.sessionId,\n\t\t\t$revision: params.revision,\n\t\t\t$seq: seq,\n\t\t\t$kind: params.kind,\n\t\t\t$payload: JSON.stringify(params.payload),\n\t\t\t$createdAt: now,\n\t\t});\n\n\t\t// Get the inserted row ID\n\t\tconst lastId = this.db.query(\"SELECT last_insert_rowid() as id\").get() as {\n\t\t\tid: number;\n\t\t};\n\n\t\tlogger.info(\n\t\t\t{\n\t\t\t\tsessionId: params.sessionId,\n\t\t\t\trevision: params.revision,\n\t\t\t\tseq,\n\t\t\t\tkind: params.kind,\n\t\t\t\teventId: lastId.id,\n\t\t\t},\n\t\t\t\"wal_event_appended\",\n\t\t);\n\n\t\treturn {\n\t\t\tid: lastId.id,\n\t\t\tsessionId: params.sessionId,\n\t\t\trevision: params.revision,\n\t\t\tseq,\n\t\t\tkind: params.kind,\n\t\t\tpayload: params.payload,\n\t\t\tcreatedAt: now,\n\t\t};\n\t}\n\n\t/**\n\t * Query events for a session/revision after a given sequence.\n\t */\n\tqueryEvents(params: QueryEventsParams): WalEvent[] {\n\t\tlogger.debug(\n\t\t\t{\n\t\t\t\tsessionId: params.sessionId,\n\t\t\t\trevision: params.revision,\n\t\t\t\tafterSeq: params.afterSeq ?? 0,\n\t\t\t\tlimit: params.limit ?? DEFAULT_QUERY_LIMIT,\n\t\t\t},\n\t\t\t\"wal_query_events\",\n\t\t);\n\n\t\tconst rows = this.stmtQueryEvents.all({\n\t\t\t$sessionId: params.sessionId,\n\t\t\t$revision: params.revision,\n\t\t\t$afterSeq: params.afterSeq ?? 0,\n\t\t\t$limit: params.limit ?? DEFAULT_QUERY_LIMIT,\n\t\t}) as WalEventRow[];\n\n\t\tlogger.debug(\n\t\t\t{\n\t\t\t\tsessionId: params.sessionId,\n\t\t\t\trevision: params.revision,\n\t\t\t\tcount: rows.length,\n\t\t\t\tseqRange:\n\t\t\t\t\trows.length > 0\n\t\t\t\t\t\t? `${rows[0].seq}-${rows[rows.length - 1].seq}`\n\t\t\t\t\t\t: \"empty\",\n\t\t\t},\n\t\t\t\"wal_query_events_result\",\n\t\t);\n\n\t\treturn rows.map((row) => this.rowToEvent(row));\n\t}\n\n\t/**\n\t * Get all unacked events for a session/revision.\n\t */\n\tgetUnackedEvents(sessionId: string, revision: number): WalEvent[] {\n\t\tconst rows = this.stmtQueryUnackedEvents.all({\n\t\t\t$sessionId: sessionId,\n\t\t\t$revision: revision,\n\t\t}) as WalEventRow[];\n\n\t\treturn rows.map((row) => this.rowToEvent(row));\n\t}\n\n\t/**\n\t * Mark events as acknowledged up to a given sequence.\n\t */\n\tackEvents(sessionId: string, revision: number, upToSeq: number): void {\n\t\tlogger.debug({ sessionId, revision, upToSeq }, \"wal_ack_events\");\n\n\t\tconst result = this.stmtAckEvents.run({\n\t\t\t$sessionId: sessionId,\n\t\t\t$revision: revision,\n\t\t\t$upToSeq: upToSeq,\n\t\t\t$ackedAt: new Date().toISOString(),\n\t\t});\n\n\t\tlogger.debug(\n\t\t\t{ sessionId, revision, upToSeq, changes: result.changes },\n\t\t\t\"wal_ack_events_result\",\n\t\t);\n\t}\n\n\t/**\n\t * Increment the revision for a session (used when session is reloaded).\n\t */\n\tincrementRevision(sessionId: string): number {\n\t\tlogger.info({ sessionId }, \"wal_increment_revision\");\n\n\t\tconst result = this.stmtIncrementRevision.get({\n\t\t\t$sessionId: sessionId,\n\t\t\t$updatedAt: new Date().toISOString(),\n\t\t}) as { current_revision: number } | null;\n\n\t\tif (!result) {\n\t\t\tlogger.error({ sessionId }, \"wal_increment_revision_session_not_found\");\n\t\t\tthrow new Error(`Session not found: ${sessionId}`);\n\t\t}\n\n\t\t// Reset sequence generator for new revision\n\t\tthis.seqGenerator.reset(sessionId, result.current_revision);\n\n\t\tlogger.info(\n\t\t\t{ sessionId, newRevision: result.current_revision },\n\t\t\t\"wal_revision_incremented\",\n\t\t);\n\n\t\treturn result.current_revision;\n\t}\n\n\t/**\n\t * Get the current sequence number for a session/revision.\n\t */\n\tgetCurrentSeq(sessionId: string, revision: number): number {\n\t\treturn this.seqGenerator.current(sessionId, revision);\n\t}\n\n\t// ========== Discovered Sessions Methods ==========\n\n\t/**\n\t * Save discovered sessions (upsert).\n\t * Marks sessions as non-stale and updates verification time.\n\t */\n\tsaveDiscoveredSessions(sessions: DiscoveredSession[]): void {\n\t\tconst now = new Date().toISOString();\n\t\tfor (const session of sessions) {\n\t\t\tthis.stmtUpsertDiscoveredSession.run({\n\t\t\t\t$sessionId: session.sessionId,\n\t\t\t\t$backendId: session.backendId,\n\t\t\t\t$cwd: session.cwd ?? null,\n\t\t\t\t$title: session.title ?? null,\n\t\t\t\t$agentUpdatedAt: session.agentUpdatedAt ?? null,\n\t\t\t\t$discoveredAt: session.discoveredAt,\n\t\t\t\t$lastVerifiedAt: now,\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Get all non-stale discovered sessions.\n\t */\n\tgetDiscoveredSessions(backendId?: string): DiscoveredSession[] {\n\t\tlet rows: DiscoveredSessionRow[];\n\t\tif (backendId) {\n\t\t\trows = this.stmtGetDiscoveredSessionsByBackend.all({\n\t\t\t\t$backendId: backendId,\n\t\t\t}) as DiscoveredSessionRow[];\n\t\t} else {\n\t\t\trows = this.stmtGetDiscoveredSessions.all() as DiscoveredSessionRow[];\n\t\t}\n\t\treturn rows.map((row) => this.rowToDiscoveredSession(row));\n\t}\n\n\t/**\n\t * Mark a discovered session as stale (cwd no longer exists).\n\t */\n\tmarkDiscoveredSessionStale(sessionId: string): void {\n\t\tthis.stmtMarkDiscoveredSessionStale.run({\n\t\t\t$sessionId: sessionId,\n\t\t});\n\t}\n\n\t/**\n\t * Delete stale discovered sessions older than a given date.\n\t */\n\tdeleteStaleDiscoveredSessions(olderThan: Date): number {\n\t\tconst result = this.stmtDeleteStaleDiscoveredSessions.run({\n\t\t\t$olderThan: olderThan.toISOString(),\n\t\t});\n\t\treturn result.changes;\n\t}\n\n\t// ========== Archive Methods ==========\n\n\t/**\n\t * Archive a session: delete WAL events, delete session record, mark as archived.\n\t */\n\tarchiveSession(sessionId: string): void {\n\t\tthis.stmtDeleteSessionEvents.run({ $sessionId: sessionId });\n\t\tthis.stmtDeleteSession.run({ $sessionId: sessionId });\n\t\tthis.stmtInsertArchivedSession.run({\n\t\t\t$sessionId: sessionId,\n\t\t\t$archivedAt: new Date().toISOString(),\n\t\t});\n\t}\n\n\t/**\n\t * Archive multiple sessions. Returns the number archived.\n\t */\n\tbulkArchiveSessions(sessionIds: string[]): number {\n\t\tlet count = 0;\n\t\tfor (const sessionId of sessionIds) {\n\t\t\tthis.archiveSession(sessionId);\n\t\t\tcount++;\n\t\t}\n\t\treturn count;\n\t}\n\n\t/**\n\t * Check if a session ID is archived.\n\t */\n\tisArchived(sessionId: string): boolean {\n\t\tconst row = this.stmtIsArchived.get({ $sessionId: sessionId });\n\t\treturn row !== null;\n\t}\n\n\t/**\n\t * Get all archived session IDs.\n\t */\n\tgetArchivedSessionIds(): string[] {\n\t\tconst rows = this.stmtGetArchivedSessionIds.all() as {\n\t\t\tsession_id: string;\n\t\t}[];\n\t\treturn rows.map((r) => r.session_id);\n\t}\n\n\t/**\n\t * Close the database connection.\n\t */\n\tclose(): void {\n\t\tthis.db.close();\n\t}\n\n\tprivate getMaxSeq(sessionId: string, revision: number): number {\n\t\tconst result = this.stmtGetMaxSeq.get({\n\t\t\t$sessionId: sessionId,\n\t\t\t$revision: revision,\n\t\t}) as { max_seq: number | null } | null;\n\t\treturn result?.max_seq ?? 0;\n\t}\n\n\tprivate rowToSession(row: WalSessionRow): WalSession {\n\t\treturn {\n\t\t\tsessionId: row.session_id,\n\t\t\tmachineId: row.machine_id,\n\t\t\tbackendId: row.backend_id,\n\t\t\tcurrentRevision: row.current_revision,\n\t\t\tcwd: row.cwd ?? undefined,\n\t\t\ttitle: row.title ?? undefined,\n\t\t\tcreatedAt: row.created_at,\n\t\t\tupdatedAt: row.updated_at,\n\t\t};\n\t}\n\n\tprivate rowToEvent(row: WalEventRow): WalEvent {\n\t\treturn {\n\t\t\tid: row.id,\n\t\t\tsessionId: row.session_id,\n\t\t\trevision: row.revision,\n\t\t\tseq: row.seq,\n\t\t\tkind: row.kind as SessionEventKind,\n\t\t\tpayload: JSON.parse(row.payload),\n\t\t\tcreatedAt: row.created_at,\n\t\t\tackedAt: row.acked_at ?? undefined,\n\t\t};\n\t}\n\n\tprivate rowToDiscoveredSession(row: DiscoveredSessionRow): DiscoveredSession {\n\t\treturn {\n\t\t\tsessionId: row.session_id,\n\t\t\tbackendId: row.backend_id,\n\t\t\tcwd: row.cwd ?? undefined,\n\t\t\ttitle: row.title ?? undefined,\n\t\t\tagentUpdatedAt: row.agent_updated_at ?? undefined,\n\t\t\tdiscoveredAt: row.discovered_at,\n\t\t\tlastVerifiedAt: row.last_verified_at ?? undefined,\n\t\t\tisStale: row.is_stale === 1,\n\t\t};\n\t}\n}\n\n// Internal row types for SQLite results\ntype WalSessionRow = {\n\tsession_id: string;\n\tmachine_id: string;\n\tbackend_id: string;\n\tcurrent_revision: number;\n\tcwd: string | null;\n\ttitle: string | null;\n\tcreated_at: string;\n\tupdated_at: string;\n};\n\ntype WalEventRow = {\n\tid: number;\n\tsession_id: string;\n\trevision: number;\n\tseq: number;\n\tkind: string;\n\tpayload: string;\n\tcreated_at: string;\n\tacked_at: string | null;\n};\n\ntype DiscoveredSessionRow = {\n\tsession_id: string;\n\tbackend_id: string;\n\tcwd: string | null;\n\ttitle: string | null;\n\tagent_updated_at: string | null;\n\tdiscovered_at: string;\n\tlast_verified_at: string | null;\n\tis_stale: number;\n};\n",
17
+ "import { type ChildProcessWithoutNullStreams, spawn } from \"node:child_process\";\nimport { randomUUID } from \"node:crypto\";\nimport { EventEmitter } from \"node:events\";\nimport { Readable, Writable } from \"node:stream\";\nimport {\n\ttype AgentCapabilities,\n\ttype Client,\n\tClientSideConnection,\n\ttype ContentBlock,\n\ttype CreateTerminalRequest,\n\ttype CreateTerminalResponse,\n\ttype Implementation,\n\ttype KillTerminalCommandRequest,\n\ttype KillTerminalCommandResponse,\n\ttype ListSessionsResponse,\n\ttype LoadSessionResponse,\n\ttype NewSessionResponse,\n\tndJsonStream,\n\tPROTOCOL_VERSION,\n\ttype PromptResponse,\n\ttype ReleaseTerminalRequest,\n\ttype ReleaseTerminalResponse,\n\ttype RequestPermissionRequest,\n\ttype RequestPermissionResponse,\n\ttype SessionInfo,\n\ttype SessionNotification,\n\ttype TerminalExitStatus,\n\ttype TerminalOutputRequest,\n\ttype TerminalOutputResponse,\n\ttype WaitForTerminalExitRequest,\n\ttype WaitForTerminalExitResponse,\n} from \"@agentclientprotocol/sdk\";\nimport {\n\ttype AcpConnectionState,\n\ttype AgentSessionCapabilities,\n\tcreateErrorDetail,\n\ttype ErrorDetail,\n\tisProtocolMismatch,\n\ttype TerminalOutputEvent,\n} from \"@mobvibe/shared\";\nimport type { AcpBackendConfig } from \"../config.js\";\n\ntype ClientInfo = {\n\tname: string;\n\tversion: string;\n};\n\nexport type AcpBackendStatus = {\n\tbackendId: string;\n\tbackendLabel: string;\n\tstate: AcpConnectionState;\n\tcommand: string;\n\targs: string[];\n\tconnectedAt?: string;\n\terror?: ErrorDetail;\n\tsessionId?: string;\n\tpid?: number;\n};\n\nconst getErrorMessage = (error: unknown) => {\n\tif (error instanceof Error) {\n\t\treturn error.message;\n\t}\n\treturn String(error);\n};\n\ntype SessionUpdateListener = (notification: SessionNotification) => void;\n\ntype TerminalOutputSnapshot = {\n\toutput: string;\n\ttruncated: boolean;\n\texitStatus?: TerminalExitStatus | null;\n};\n\ntype TerminalRecord = {\n\tsessionId: string;\n\tcommand: string;\n\targs: string[];\n\toutputByteLimit: number;\n\toutput: TerminalOutputSnapshot;\n\tprocess?: ChildProcessWithoutNullStreams;\n\tonExit?: Promise<WaitForTerminalExitResponse>;\n\tresolveExit?: (response: WaitForTerminalExitResponse) => void;\n};\n\ntype ClientHandlers = {\n\tonSessionUpdate: (notification: SessionNotification) => void;\n\tonRequestPermission?: (\n\t\tparams: RequestPermissionRequest,\n\t) => Promise<RequestPermissionResponse>;\n\tonCreateTerminal?: (\n\t\tparams: CreateTerminalRequest,\n\t) => Promise<CreateTerminalResponse>;\n\tonTerminalOutput?: (\n\t\tparams: TerminalOutputRequest,\n\t) => Promise<TerminalOutputResponse>;\n\tonWaitForTerminalExit?: (\n\t\tparams: WaitForTerminalExitRequest,\n\t) => Promise<WaitForTerminalExitResponse>;\n\tonKillTerminal?: (\n\t\tparams: KillTerminalCommandRequest,\n\t) => Promise<KillTerminalCommandResponse>;\n\tonReleaseTerminal?: (\n\t\tparams: ReleaseTerminalRequest,\n\t) => Promise<ReleaseTerminalResponse>;\n};\n\nconst buildClient = (handlers: ClientHandlers): Client => ({\n\tasync requestPermission(params: RequestPermissionRequest) {\n\t\tif (handlers.onRequestPermission) {\n\t\t\treturn handlers.onRequestPermission(params);\n\t\t}\n\t\treturn { outcome: { outcome: \"cancelled\" } };\n\t},\n\tasync sessionUpdate(params: SessionNotification) {\n\t\thandlers.onSessionUpdate(params);\n\t},\n\tasync createTerminal(params: CreateTerminalRequest) {\n\t\tif (!handlers.onCreateTerminal) {\n\t\t\tthrow new Error(\"Terminal create handler not configured\");\n\t\t}\n\t\treturn handlers.onCreateTerminal(params);\n\t},\n\tasync terminalOutput(params: TerminalOutputRequest) {\n\t\tif (!handlers.onTerminalOutput) {\n\t\t\treturn { output: \"\", truncated: false };\n\t\t}\n\t\treturn handlers.onTerminalOutput(params);\n\t},\n\tasync waitForTerminalExit(params: WaitForTerminalExitRequest) {\n\t\tif (!handlers.onWaitForTerminalExit) {\n\t\t\treturn { exitCode: null, signal: null };\n\t\t}\n\t\treturn handlers.onWaitForTerminalExit(params);\n\t},\n\tasync killTerminal(params: KillTerminalCommandRequest) {\n\t\tif (!handlers.onKillTerminal) {\n\t\t\treturn {};\n\t\t}\n\t\treturn handlers.onKillTerminal(params);\n\t},\n\tasync releaseTerminal(params: ReleaseTerminalRequest) {\n\t\tif (!handlers.onReleaseTerminal) {\n\t\t\treturn {};\n\t\t}\n\t\treturn handlers.onReleaseTerminal(params);\n\t},\n});\n\nconst formatExitMessage = (\n\tcode: number | null,\n\tsignal: NodeJS.Signals | null,\n) => {\n\tif (signal) {\n\t\treturn `ACP process received signal ${signal}`;\n\t}\n\tif (code !== null) {\n\t\treturn `ACP process exited with code ${code}`;\n\t}\n\treturn \"ACP process exited\";\n};\n\nconst buildConnectError = (error: unknown): ErrorDetail => {\n\tconst detail = getErrorMessage(error);\n\tif (isProtocolMismatch(error)) {\n\t\treturn createErrorDetail({\n\t\t\tcode: \"ACP_PROTOCOL_MISMATCH\",\n\t\t\tmessage: \"ACP protocol version mismatch\",\n\t\t\tretryable: false,\n\t\t\tscope: \"service\",\n\t\t\tdetail,\n\t\t});\n\t}\n\treturn createErrorDetail({\n\t\tcode: \"ACP_CONNECT_FAILED\",\n\t\tmessage: \"Failed to connect to ACP backend process\",\n\t\tretryable: true,\n\t\tscope: \"service\",\n\t\tdetail,\n\t});\n};\n\nconst buildProcessExitError = (detail: string): ErrorDetail =>\n\tcreateErrorDetail({\n\t\tcode: \"ACP_PROCESS_EXITED\",\n\t\tmessage: \"ACP backend process exited unexpectedly\",\n\t\tretryable: true,\n\t\tscope: \"service\",\n\t\tdetail,\n\t});\n\nconst buildConnectionClosedError = (detail: string): ErrorDetail =>\n\tcreateErrorDetail({\n\t\tcode: \"ACP_CONNECTION_CLOSED\",\n\t\tmessage: \"ACP connection closed\",\n\t\tretryable: true,\n\t\tscope: \"service\",\n\t\tdetail,\n\t});\n\nconst normalizeOutputText = (value: string) => value.normalize(\"NFC\");\n\nconst isOutputOverLimit = (value: string, limit: number) =>\n\tBuffer.byteLength(value, \"utf8\") > limit;\n\nconst sliceOutputToLimit = (value: string, limit: number) => {\n\tconst buffer = Buffer.from(value, \"utf8\");\n\tif (buffer.byteLength <= limit) {\n\t\treturn value;\n\t}\n\tconst sliced = buffer.subarray(buffer.byteLength - limit);\n\tlet start = 0;\n\twhile (start < sliced.length && (sliced[start] & 0b11000000) === 0b10000000) {\n\t\tstart += 1;\n\t}\n\treturn sliced.subarray(start).toString(\"utf8\");\n};\n\nexport class AcpConnection {\n\tprivate connection?: ClientSideConnection;\n\tprivate process?: ChildProcessWithoutNullStreams;\n\tprivate closedPromise?: Promise<void>;\n\tprivate state: AcpConnectionState = \"idle\";\n\tprivate connectedAt?: Date;\n\tprivate error?: ErrorDetail;\n\tprivate sessionId?: string;\n\tprivate agentInfo?: Implementation;\n\tprivate agentCapabilities?: AgentCapabilities;\n\tprivate readonly sessionUpdateEmitter = new EventEmitter();\n\tprivate readonly statusEmitter = new EventEmitter();\n\tprivate readonly terminalOutputEmitter = new EventEmitter();\n\tprivate permissionHandler?: (\n\t\tparams: RequestPermissionRequest,\n\t) => Promise<RequestPermissionResponse>;\n\tprivate terminals = new Map<string, TerminalRecord>();\n\n\tconstructor(\n\t\tprivate readonly options: {\n\t\t\tbackend: AcpBackendConfig;\n\t\t\tclient: ClientInfo;\n\t\t},\n\t) {}\n\n\tgetStatus(): AcpBackendStatus {\n\t\treturn {\n\t\t\tbackendId: this.options.backend.id,\n\t\t\tbackendLabel: this.options.backend.label,\n\t\t\tstate: this.state,\n\t\t\tcommand: this.options.backend.command,\n\t\t\targs: [...this.options.backend.args],\n\t\t\tconnectedAt: this.connectedAt?.toISOString(),\n\t\t\terror: this.error,\n\t\t\tsessionId: this.sessionId,\n\t\t\tpid: this.process?.pid,\n\t\t};\n\t}\n\n\tgetAgentInfo(): Implementation | undefined {\n\t\treturn this.agentInfo;\n\t}\n\n\t/**\n\t * Get the agent's session capabilities.\n\t */\n\tgetSessionCapabilities(): AgentSessionCapabilities {\n\t\treturn {\n\t\t\tlist: this.agentCapabilities?.sessionCapabilities?.list != null,\n\t\t\tload: this.agentCapabilities?.loadSession === true,\n\t\t};\n\t}\n\n\t/**\n\t * Check if the agent supports session/list.\n\t */\n\tsupportsSessionList(): boolean {\n\t\treturn this.agentCapabilities?.sessionCapabilities?.list != null;\n\t}\n\n\t/**\n\t * Check if the agent supports session/load.\n\t */\n\tsupportsSessionLoad(): boolean {\n\t\treturn this.agentCapabilities?.loadSession === true;\n\t}\n\n\t/**\n\t * List sessions from the agent (session/list).\n\t * @param params Optional filter parameters\n\t * @returns List of session info from the agent\n\t */\n\tasync listSessions(params?: {\n\t\tcursor?: string;\n\t\tcwd?: string;\n\t}): Promise<{ sessions: SessionInfo[]; nextCursor?: string }> {\n\t\tif (!this.supportsSessionList()) {\n\t\t\treturn { sessions: [] };\n\t\t}\n\t\tconst connection = await this.ensureReady();\n\t\tconst response: ListSessionsResponse =\n\t\t\tawait connection.unstable_listSessions({\n\t\t\t\tcursor: params?.cursor ?? undefined,\n\t\t\t\tcwd: params?.cwd ?? undefined,\n\t\t\t});\n\t\treturn {\n\t\t\tsessions: response.sessions,\n\t\t\tnextCursor: response.nextCursor ?? undefined,\n\t\t};\n\t}\n\n\t/**\n\t * Load a historical session with message history replay (session/load).\n\t * @param sessionId The session ID to load\n\t * @param cwd The working directory\n\t * @returns Load session response with modes/models state\n\t */\n\tasync loadSession(\n\t\tsessionId: string,\n\t\tcwd: string,\n\t): Promise<LoadSessionResponse> {\n\t\tif (!this.supportsSessionLoad()) {\n\t\t\tthrow new Error(\"Agent does not support session/load capability\");\n\t\t}\n\t\tconst connection = await this.ensureReady();\n\t\tconst response = await connection.loadSession({\n\t\t\tsessionId,\n\t\t\tcwd,\n\t\t\tmcpServers: [],\n\t\t});\n\t\tthis.sessionId = sessionId;\n\t\treturn response;\n\t}\n\n\tsetPermissionHandler(\n\t\thandler?: (\n\t\t\tparams: RequestPermissionRequest,\n\t\t) => Promise<RequestPermissionResponse>,\n\t) {\n\t\tthis.permissionHandler = handler;\n\t}\n\n\tonTerminalOutput(listener: (payload: TerminalOutputEvent) => void) {\n\t\tthis.terminalOutputEmitter.on(\"output\", listener);\n\t\treturn () => {\n\t\t\tthis.terminalOutputEmitter.off(\"output\", listener);\n\t\t};\n\t}\n\n\tonSessionUpdate(listener: SessionUpdateListener) {\n\t\tthis.sessionUpdateEmitter.on(\"update\", listener);\n\t\treturn () => {\n\t\t\tthis.sessionUpdateEmitter.off(\"update\", listener);\n\t\t};\n\t}\n\n\tonStatusChange(listener: (status: AcpBackendStatus) => void) {\n\t\tthis.statusEmitter.on(\"status\", listener);\n\t\treturn () => {\n\t\t\tthis.statusEmitter.off(\"status\", listener);\n\t\t};\n\t}\n\n\tprivate updateStatus(state: AcpConnectionState, error?: ErrorDetail) {\n\t\tthis.state = state;\n\t\tthis.error = error;\n\t\tthis.statusEmitter.emit(\"status\", this.getStatus());\n\t}\n\n\tasync connect(): Promise<void> {\n\t\tif (this.state === \"connecting\" || this.state === \"ready\") {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.updateStatus(\"connecting\");\n\t\tthis.agentInfo = undefined;\n\n\t\ttry {\n\t\t\tconst env = this.options.backend.envOverrides\n\t\t\t\t? { ...process.env, ...this.options.backend.envOverrides }\n\t\t\t\t: process.env;\n\t\t\tconst child = spawn(\n\t\t\t\tthis.options.backend.command,\n\t\t\t\tthis.options.backend.args,\n\t\t\t\t{\n\t\t\t\t\tstdio: [\"pipe\", \"pipe\", \"pipe\"],\n\t\t\t\t\tenv,\n\t\t\t\t},\n\t\t\t);\n\t\t\tthis.process = child;\n\t\t\tthis.sessionId = undefined;\n\t\t\tchild.stderr.pipe(process.stderr);\n\n\t\t\tconst input = Writable.toWeb(child.stdin) as WritableStream<Uint8Array>;\n\t\t\tconst output = Readable.toWeb(child.stdout) as ReadableStream<Uint8Array>;\n\t\t\tconst stream = ndJsonStream(input, output);\n\t\t\tconst connection = new ClientSideConnection(\n\t\t\t\t() =>\n\t\t\t\t\tbuildClient({\n\t\t\t\t\t\tonSessionUpdate: (notification) =>\n\t\t\t\t\t\t\tthis.emitSessionUpdate(notification),\n\t\t\t\t\t\tonRequestPermission: (params) =>\n\t\t\t\t\t\t\tthis.handlePermissionRequest(params),\n\t\t\t\t\t\tonCreateTerminal: (params) => this.createTerminal(params),\n\t\t\t\t\t\tonTerminalOutput: (params) => this.getTerminalOutput(params),\n\t\t\t\t\t\tonWaitForTerminalExit: (params) => this.waitForTerminalExit(params),\n\t\t\t\t\t\tonKillTerminal: (params) => this.killTerminal(params),\n\t\t\t\t\t\tonReleaseTerminal: (params) => this.releaseTerminal(params),\n\t\t\t\t\t}),\n\t\t\t\tstream,\n\t\t\t);\n\t\t\tthis.connection = connection;\n\n\t\t\tchild.once(\"error\", (error) => {\n\t\t\t\tif (this.state === \"stopped\") {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tthis.updateStatus(\"error\", buildConnectError(error));\n\t\t\t});\n\n\t\t\tchild.once(\"exit\", (code, signal) => {\n\t\t\t\tif (this.state === \"stopped\") {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tthis.updateStatus(\n\t\t\t\t\t\"error\",\n\t\t\t\t\tbuildProcessExitError(formatExitMessage(code, signal)),\n\t\t\t\t);\n\t\t\t});\n\n\t\t\tthis.closedPromise = connection.closed.catch((error) => {\n\t\t\t\tthis.updateStatus(\n\t\t\t\t\t\"error\",\n\t\t\t\t\tbuildConnectionClosedError(getErrorMessage(error)),\n\t\t\t\t);\n\t\t\t});\n\n\t\t\tconst initializeResponse = await connection.initialize({\n\t\t\t\tprotocolVersion: PROTOCOL_VERSION,\n\t\t\t\tclientInfo: {\n\t\t\t\t\tname: this.options.client.name,\n\t\t\t\t\tversion: this.options.client.version,\n\t\t\t\t},\n\t\t\t\tclientCapabilities: { terminal: true },\n\t\t\t});\n\n\t\t\tthis.agentInfo = initializeResponse.agentInfo ?? undefined;\n\t\t\tthis.agentCapabilities =\n\t\t\t\tinitializeResponse.agentCapabilities ?? undefined;\n\t\t\tthis.connectedAt = new Date();\n\t\t\tthis.updateStatus(\"ready\");\n\t\t} catch (error) {\n\t\t\tthis.updateStatus(\"error\", buildConnectError(error));\n\t\t\tawait this.stopProcess();\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tasync createSession(options?: { cwd?: string }): Promise<NewSessionResponse> {\n\t\tconst connection = await this.ensureReady();\n\t\tconst response = await this.createSessionInternal(\n\t\t\tconnection,\n\t\t\toptions?.cwd ?? process.cwd(),\n\t\t);\n\t\tthis.sessionId = response.sessionId;\n\t\treturn response;\n\t}\n\n\tasync prompt(\n\t\tsessionId: string,\n\t\tprompt: ContentBlock[],\n\t): Promise<PromptResponse> {\n\t\tconst connection = await this.ensureReady();\n\t\treturn connection.prompt({ sessionId, prompt });\n\t}\n\n\tasync cancel(sessionId: string): Promise<void> {\n\t\tconst connection = await this.ensureReady();\n\t\tawait connection.cancel({ sessionId });\n\t}\n\n\tasync setSessionMode(sessionId: string, modeId: string): Promise<void> {\n\t\tconst connection = await this.ensureReady();\n\t\tawait connection.setSessionMode({ sessionId, modeId });\n\t}\n\n\tasync setSessionModel(sessionId: string, modelId: string): Promise<void> {\n\t\tconst connection = await this.ensureReady();\n\t\tawait connection.unstable_setSessionModel({ sessionId, modelId });\n\t}\n\n\tasync createTerminal(\n\t\tparams: CreateTerminalRequest,\n\t): Promise<CreateTerminalResponse> {\n\t\tconst outputLimit =\n\t\t\ttypeof params.outputByteLimit === \"number\" && params.outputByteLimit > 0\n\t\t\t\t? Math.floor(params.outputByteLimit)\n\t\t\t\t: 1024 * 1024;\n\t\tconst resolvedEnv = params.env\n\t\t\t? Object.fromEntries(\n\t\t\t\t\tparams.env.map((envVar) => [envVar.name, envVar.value]),\n\t\t\t\t)\n\t\t\t: undefined;\n\t\tconst terminalId = randomUUID();\n\t\tconst record: TerminalRecord = {\n\t\t\tsessionId: params.sessionId,\n\t\t\tcommand: params.command,\n\t\t\targs: params.args ?? [],\n\t\t\toutputByteLimit: outputLimit,\n\t\t\toutput: {\n\t\t\t\toutput: \"\",\n\t\t\t\ttruncated: false,\n\t\t\t\texitStatus: null,\n\t\t\t},\n\t\t};\n\t\tthis.terminals.set(terminalId, record);\n\n\t\tconst child = spawn(params.command, params.args ?? [], {\n\t\t\tcwd: params.cwd ?? undefined,\n\t\t\tenv: resolvedEnv ? { ...process.env, ...resolvedEnv } : process.env,\n\t\t});\n\t\tchild.once(\"error\", (error) => {\n\t\t\trecord.output.exitStatus = {\n\t\t\t\texitCode: null,\n\t\t\t\tsignal: null,\n\t\t\t};\n\t\t\trecord.resolveExit?.({ exitCode: null, signal: null });\n\t\t\tthis.terminalOutputEmitter.emit(\"output\", {\n\t\t\t\tsessionId: record.sessionId,\n\t\t\t\tterminalId,\n\t\t\t\tdelta: `\\n[terminal error] ${String(error)}`,\n\t\t\t\ttruncated: record.output.truncated,\n\t\t\t\toutput: record.output.output,\n\t\t\t\texitStatus: record.output.exitStatus,\n\t\t\t} satisfies TerminalOutputEvent);\n\t\t});\n\t\trecord.process = child;\n\t\tlet resolveExit: (response: WaitForTerminalExitResponse) => void = () => {};\n\t\trecord.onExit = new Promise<WaitForTerminalExitResponse>((resolve) => {\n\t\t\tresolveExit = resolve;\n\t\t});\n\t\trecord.resolveExit = resolveExit;\n\n\t\tconst handleChunk = (chunk: Buffer) => {\n\t\t\tconst delta = normalizeOutputText(chunk.toString(\"utf8\"));\n\t\t\tif (!delta) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst combinedOutput = record.output.output + delta;\n\t\t\trecord.output.truncated = isOutputOverLimit(\n\t\t\t\tcombinedOutput,\n\t\t\t\trecord.outputByteLimit,\n\t\t\t);\n\t\t\trecord.output.output = sliceOutputToLimit(\n\t\t\t\tcombinedOutput,\n\t\t\t\trecord.outputByteLimit,\n\t\t\t);\n\n\t\t\tthis.terminalOutputEmitter.emit(\"output\", {\n\t\t\t\tsessionId: record.sessionId,\n\t\t\t\tterminalId,\n\t\t\t\tdelta,\n\t\t\t\ttruncated: record.output.truncated,\n\t\t\t\toutput: record.output.truncated ? record.output.output : undefined,\n\t\t\t\texitStatus: record.output.exitStatus,\n\t\t\t} satisfies TerminalOutputEvent);\n\t\t};\n\n\t\tchild.stdout?.on(\"data\", handleChunk);\n\t\tchild.stderr?.on(\"data\", handleChunk);\n\t\tchild.on(\"exit\", (code, signal) => {\n\t\t\trecord.output.exitStatus = {\n\t\t\t\texitCode: code ?? null,\n\t\t\t\tsignal: signal ?? null,\n\t\t\t};\n\t\t\trecord.resolveExit?.({\n\t\t\t\texitCode: code ?? null,\n\t\t\t\tsignal: signal ?? null,\n\t\t\t});\n\t\t\tthis.terminalOutputEmitter.emit(\"output\", {\n\t\t\t\tsessionId: record.sessionId,\n\t\t\t\tterminalId,\n\t\t\t\tdelta: \"\",\n\t\t\t\ttruncated: record.output.truncated,\n\t\t\t\toutput: record.output.output,\n\t\t\t\texitStatus: record.output.exitStatus,\n\t\t\t} satisfies TerminalOutputEvent);\n\t\t});\n\n\t\treturn { terminalId };\n\t}\n\n\tasync getTerminalOutput(\n\t\tparams: TerminalOutputRequest,\n\t): Promise<TerminalOutputResponse> {\n\t\tconst record = this.terminals.get(params.terminalId);\n\t\tif (!record || record.sessionId !== params.sessionId) {\n\t\t\treturn { output: \"\", truncated: false };\n\t\t}\n\t\treturn record.output;\n\t}\n\n\tasync waitForTerminalExit(\n\t\tparams: WaitForTerminalExitRequest,\n\t): Promise<WaitForTerminalExitResponse> {\n\t\tconst record = this.terminals.get(params.terminalId);\n\t\tif (!record || record.sessionId !== params.sessionId) {\n\t\t\treturn Promise.resolve({ exitCode: null, signal: null });\n\t\t}\n\t\treturn record.onExit ?? Promise.resolve({ exitCode: null, signal: null });\n\t}\n\n\tasync killTerminal(\n\t\tparams: KillTerminalCommandRequest,\n\t): Promise<KillTerminalCommandResponse> {\n\t\tconst record = this.terminals.get(params.terminalId);\n\t\tif (!record || record.sessionId !== params.sessionId) {\n\t\t\treturn {};\n\t\t}\n\t\trecord.process?.kill(\"SIGTERM\");\n\t\treturn {};\n\t}\n\n\tasync releaseTerminal(\n\t\tparams: ReleaseTerminalRequest,\n\t): Promise<ReleaseTerminalResponse> {\n\t\tconst record = this.terminals.get(params.terminalId);\n\t\tif (record?.process && record.process.exitCode === null) {\n\t\t\trecord.process.kill(\"SIGTERM\");\n\t\t}\n\t\tthis.terminals.delete(params.terminalId);\n\t\treturn {};\n\t}\n\n\tasync disconnect(): Promise<void> {\n\t\tif (this.state === \"stopped\") {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.updateStatus(\"stopped\");\n\t\tthis.sessionId = undefined;\n\t\tthis.agentInfo = undefined;\n\t\tawait this.stopProcess();\n\t\tawait this.closedPromise;\n\t\tthis.connection = undefined;\n\t}\n\n\tprivate async ensureReady(): Promise<ClientSideConnection> {\n\t\tif (this.state !== \"ready\" || !this.connection) {\n\t\t\tawait this.connect();\n\t\t}\n\n\t\tif (!this.connection || this.state !== \"ready\") {\n\t\t\tthrow new Error(\"ACP connection not available\");\n\t\t}\n\n\t\treturn this.connection;\n\t}\n\n\tprivate async createSessionInternal(\n\t\tconnection: ClientSideConnection,\n\t\tcwd: string,\n\t): Promise<NewSessionResponse> {\n\t\tconst session = await connection.newSession({\n\t\t\tcwd,\n\t\t\tmcpServers: [],\n\t\t});\n\t\treturn session;\n\t}\n\n\tprivate emitSessionUpdate(notification: SessionNotification) {\n\t\tthis.sessionUpdateEmitter.emit(\"update\", notification);\n\t}\n\n\tprivate async handlePermissionRequest(\n\t\tparams: RequestPermissionRequest,\n\t): Promise<RequestPermissionResponse> {\n\t\tif (this.permissionHandler) {\n\t\t\treturn this.permissionHandler(params);\n\t\t}\n\t\treturn { outcome: { outcome: \"cancelled\" } };\n\t}\n\n\tprivate async stopProcess(): Promise<void> {\n\t\tconst child = this.process;\n\t\tif (!child) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.process = undefined;\n\t\tif (child.exitCode === null && !child.killed) {\n\t\t\tchild.kill(\"SIGTERM\");\n\t\t}\n\t}\n}\n",
18
+ "import type { CryptoKeyPair, SessionEvent } from \"@mobvibe/shared\";\nimport {\n\tderiveAuthKeyPair,\n\tderiveContentKeyPair,\n\tencryptPayload,\n\tgenerateDEK,\n\tgetSodium,\n\twrapDEK,\n} from \"@mobvibe/shared\";\n\nexport class CliCryptoService {\n\treadonly authKeyPair: CryptoKeyPair;\n\tprivate contentKeyPair: CryptoKeyPair;\n\tprivate sessionDeks = new Map<string, Uint8Array>();\n\tprivate wrappedDekCache = new Map<string, string>();\n\n\tconstructor(masterSecret: Uint8Array) {\n\t\tthis.authKeyPair = deriveAuthKeyPair(masterSecret);\n\t\tthis.contentKeyPair = deriveContentKeyPair(masterSecret);\n\t}\n\n\t/**\n\t * Initialize a DEK for a session. Generates a random DEK and wraps it\n\t * with the content public key.\n\t */\n\tinitSessionDek(sessionId: string): {\n\t\tdek: Uint8Array;\n\t\twrappedDek: string;\n\t} {\n\t\tconst dek = generateDEK();\n\t\tconst wrappedDek = wrapDEK(dek, this.contentKeyPair.publicKey);\n\t\tthis.sessionDeks.set(sessionId, dek);\n\t\tthis.wrappedDekCache.set(sessionId, wrappedDek);\n\t\treturn { dek, wrappedDek };\n\t}\n\n\t/**\n\t * Set an existing DEK for a session (e.g., loaded from WAL).\n\t */\n\tsetSessionDek(sessionId: string, dek: Uint8Array): void {\n\t\tthis.sessionDeks.set(sessionId, dek);\n\t\tthis.wrappedDekCache.set(\n\t\t\tsessionId,\n\t\t\twrapDEK(dek, this.contentKeyPair.publicKey),\n\t\t);\n\t}\n\n\t/**\n\t * Encrypt a session event's payload in place.\n\t * Returns a new event with the payload replaced by an EncryptedPayload.\n\t */\n\tencryptEvent(event: SessionEvent): SessionEvent {\n\t\tconst dek = this.sessionDeks.get(event.sessionId);\n\t\tif (!dek) {\n\t\t\t// No DEK for this session — pass through unencrypted\n\t\t\treturn event;\n\t\t}\n\t\treturn {\n\t\t\t...event,\n\t\t\tpayload: encryptPayload(event.payload, dek),\n\t\t};\n\t}\n\n\t/**\n\t * Get the wrapped DEK for a session, or null if not initialized.\n\t */\n\tgetWrappedDek(sessionId: string): string | null {\n\t\treturn this.wrappedDekCache.get(sessionId) ?? null;\n\t}\n\n\t/**\n\t * Get the base64-encoded auth public key.\n\t */\n\tgetAuthPublicKeyBase64(): string {\n\t\tconst sodium = getSodium();\n\t\treturn sodium.to_base64(\n\t\t\tthis.authKeyPair.publicKey,\n\t\t\tsodium.base64_variants.ORIGINAL,\n\t\t);\n\t}\n}\n",
19
+ "import { EventEmitter } from \"node:events\";\nimport fs from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport path from \"node:path\";\nimport type {\n\tCliToGatewayEvents,\n\tEventsAckPayload,\n\tFsEntry,\n\tFsRoot,\n\tGatewayToCliEvents,\n\tHostFsRootsResponse,\n\tRpcResponse,\n\tSessionEventsResponse,\n\tSessionFsFilePreview,\n\tSessionFsResourceEntry,\n\tStopReason,\n} from \"@mobvibe/shared\";\nimport { createSignedToken } from \"@mobvibe/shared\";\nimport ignore, { type Ignore } from \"ignore\";\nimport { io, type Socket } from \"socket.io-client\";\nimport type { SessionManager } from \"../acp/session-manager.js\";\nimport type { CliConfig } from \"../config.js\";\nimport type { CliCryptoService } from \"../e2ee/crypto-service.js\";\nimport {\n\taggregateDirStatus,\n\tgetFileDiff,\n\tgetGitBranch,\n\tgetGitStatus,\n\tisGitRepo,\n} from \"../lib/git-utils.js\";\nimport { logger } from \"../lib/logger.js\";\n\ntype SocketClientOptions = {\n\tconfig: CliConfig;\n\tsessionManager: SessionManager;\n\t/** Crypto service for E2EE */\n\tcryptoService: CliCryptoService;\n};\n\nconst SESSION_ROOT_NAME = \"Working Directory\";\nconst MAX_RESOURCE_FILES = 2000;\nconst DEFAULT_IGNORES = [\n\t\"node_modules\",\n\t\".git\",\n\t\"dist\",\n\t\"build\",\n\t\".next\",\n\t\".nuxt\",\n\t\".output\",\n\t\".cache\",\n\t\"__pycache__\",\n\t\".venv\",\n\t\"venv\",\n\t\"target\",\n];\n\nconst loadGitignore = async (rootPath: string): Promise<Ignore> => {\n\tconst ig = ignore().add(DEFAULT_IGNORES);\n\ttry {\n\t\tconst gitignorePath = path.join(rootPath, \".gitignore\");\n\t\tconst content = await fs.readFile(gitignorePath, \"utf8\");\n\t\tig.add(content);\n\t} catch {\n\t\t// No .gitignore file, use defaults only\n\t}\n\treturn ig;\n};\n\nconst resolveImageMimeType = (filePath: string) => {\n\tconst extension = path.extname(filePath).toLowerCase();\n\tswitch (extension) {\n\t\tcase \".apng\":\n\t\t\treturn \"image/apng\";\n\t\tcase \".avif\":\n\t\t\treturn \"image/avif\";\n\t\tcase \".gif\":\n\t\t\treturn \"image/gif\";\n\t\tcase \".jpeg\":\n\t\t\treturn \"image/jpeg\";\n\t\tcase \".jpg\":\n\t\t\treturn \"image/jpeg\";\n\t\tcase \".png\":\n\t\t\treturn \"image/png\";\n\t\tcase \".svg\":\n\t\t\treturn \"image/svg+xml\";\n\t\tcase \".webp\":\n\t\t\treturn \"image/webp\";\n\t\tdefault:\n\t\t\treturn undefined;\n\t}\n};\n\nconst readDirectoryEntries = async (dirPath: string): Promise<FsEntry[]> => {\n\tconst entries = await fs.readdir(dirPath, { withFileTypes: true });\n\tconst resolvedEntries = await Promise.all(\n\t\tentries.map(async (entry) => {\n\t\t\tconst entryPath = path.join(dirPath, entry.name);\n\t\t\tlet isDirectory = entry.isDirectory();\n\t\t\tif (!isDirectory && entry.isSymbolicLink()) {\n\t\t\t\ttry {\n\t\t\t\t\tconst stats = await fs.stat(entryPath);\n\t\t\t\t\tisDirectory = stats.isDirectory();\n\t\t\t\t} catch {\n\t\t\t\t\t// ignore broken symlink\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst entryType: FsEntry[\"type\"] = isDirectory ? \"directory\" : \"file\";\n\t\t\treturn {\n\t\t\t\tname: entry.name,\n\t\t\t\tpath: entryPath,\n\t\t\t\ttype: entryType,\n\t\t\t\thidden: entry.name.startsWith(\".\"),\n\t\t\t};\n\t\t}),\n\t);\n\treturn resolvedEntries.sort((left, right) => {\n\t\tif (left.type !== right.type) {\n\t\t\treturn left.type === \"directory\" ? -1 : 1;\n\t\t}\n\t\treturn left.name.localeCompare(right.name);\n\t});\n};\n\nconst filterVisibleEntries = (entries: FsEntry[]) =>\n\tentries.filter((entry) => !entry.hidden);\n\n/**\n * Resolve a request path within the given cwd.\n * Rejects absolute paths and paths that escape the cwd via \"..\".\n * Returns the resolved absolute path.\n */\nconst resolveWithinCwd = (cwd: string, requestPath: string): string => {\n\tif (path.isAbsolute(requestPath)) {\n\t\tthrow new Error(\"Absolute paths are not allowed\");\n\t}\n\tconst resolved = path.resolve(cwd, requestPath);\n\t// Ensure resolved path is within cwd (cwd itself or a descendant)\n\tif (resolved !== cwd && !resolved.startsWith(`${cwd}/`)) {\n\t\tthrow new Error(\"Path escapes working directory\");\n\t}\n\treturn resolved;\n};\n\nconst buildHostFsRoots = async (): Promise<HostFsRootsResponse> => {\n\tconst homePath = homedir();\n\treturn {\n\t\thomePath,\n\t\troots: [{ name: \"Home\", path: homePath }],\n\t};\n};\n\nexport class SocketClient extends EventEmitter {\n\tprivate socket: Socket<GatewayToCliEvents, CliToGatewayEvents>;\n\tprivate connected = false;\n\tprivate reconnectAttempts = 0;\n\tprivate heartbeatInterval?: NodeJS.Timeout;\n\n\tconstructor(private readonly options: SocketClientOptions) {\n\t\tsuper();\n\t\tconst { cryptoService } = options;\n\t\tthis.socket = io(`${options.config.gatewayUrl}/cli`, {\n\t\t\tpath: \"/socket.io\",\n\t\t\treconnection: true,\n\t\t\treconnectionAttempts: Number.POSITIVE_INFINITY,\n\t\t\treconnectionDelay: 1000,\n\t\t\treconnectionDelayMax: 30000,\n\t\t\ttransports: [\"websocket\"],\n\t\t\tautoConnect: false,\n\t\t\tauth: (cb) => cb(createSignedToken(cryptoService.authKeyPair)),\n\t\t});\n\t\tthis.setupEventHandlers();\n\t\tthis.setupRpcHandlers();\n\t\tthis.setupSessionManagerListeners();\n\t}\n\n\tprivate setupEventHandlers() {\n\t\tthis.socket.on(\"connect\", () => {\n\t\t\tconst wasReconnect = this.reconnectAttempts > 0;\n\t\t\tlogger.info(\n\t\t\t\t{\n\t\t\t\t\tgatewayUrl: this.options.config.gatewayUrl,\n\t\t\t\t\twasReconnect,\n\t\t\t\t},\n\t\t\t\t\"gateway_connected\",\n\t\t\t);\n\t\t\tthis.connected = true;\n\t\t\tthis.reconnectAttempts = 0;\n\t\t\tlogger.info(\"gateway_register_start\");\n\t\t\tthis.register();\n\t\t\tthis.startHeartbeat();\n\n\t\t\t// On reconnect, replay unacked events for all active sessions\n\t\t\tif (wasReconnect) {\n\t\t\t\tthis.replayUnackedEvents();\n\t\t\t}\n\n\t\t\tthis.emit(\"connected\");\n\t\t});\n\n\t\tthis.socket.on(\"disconnect\", (reason) => {\n\t\t\tlogger.warn({ reason }, \"gateway_disconnected\");\n\t\t\tthis.connected = false;\n\t\t\tthis.stopHeartbeat();\n\t\t\tthis.emit(\"disconnected\", reason);\n\t\t});\n\n\t\tthis.socket.on(\"connect_error\", (error) => {\n\t\t\tthis.reconnectAttempts++;\n\t\t\tif (this.reconnectAttempts <= 3 || this.reconnectAttempts % 10 === 0) {\n\t\t\t\tlogger.error(\n\t\t\t\t\t{ attempt: this.reconnectAttempts, err: error },\n\t\t\t\t\t\"gateway_connect_error\",\n\t\t\t\t);\n\t\t\t}\n\t\t});\n\n\t\tthis.socket.on(\"cli:registered\", async (info) => {\n\t\t\tlogger.info({ machineId: info.machineId }, \"gateway_registered\");\n\n\t\t\t// Auto-discover historical sessions from all backends\n\t\t\tfor (const backend of this.options.config.acpBackends) {\n\t\t\t\ttry {\n\t\t\t\t\tlet cursor: string | undefined;\n\t\t\t\t\tlet page = 0;\n\t\t\t\t\tdo {\n\t\t\t\t\t\tconst { sessions, capabilities, nextCursor } =\n\t\t\t\t\t\t\tawait this.options.sessionManager.discoverSessions({\n\t\t\t\t\t\t\t\tbackendId: backend.id,\n\t\t\t\t\t\t\t\tcursor,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\tcursor = nextCursor;\n\t\t\t\t\t\tif (sessions.length > 0) {\n\t\t\t\t\t\t\tthis.socket.emit(\"sessions:discovered\", {\n\t\t\t\t\t\t\t\tsessions,\n\t\t\t\t\t\t\t\tcapabilities,\n\t\t\t\t\t\t\t\tnextCursor,\n\t\t\t\t\t\t\t\tbackendId: backend.id,\n\t\t\t\t\t\t\t\tbackendLabel: backend.label,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tlogger.info(\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tcount: sessions.length,\n\t\t\t\t\t\t\t\t\tcapabilities,\n\t\t\t\t\t\t\t\t\tpage,\n\t\t\t\t\t\t\t\t\tbackendId: backend.id,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\"historical_sessions_discovered\",\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tpage += 1;\n\t\t\t\t\t} while (cursor);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tlogger.warn(\n\t\t\t\t\t\t{ err: error, backendId: backend.id },\n\t\t\t\t\t\t\"session_discovery_failed\",\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\t// Handle authentication errors\n\t\tthis.socket.on(\"cli:error\", (error) => {\n\t\t\tlogger.error({ err: error }, \"gateway_auth_error\");\n\t\t\tthis.emit(\"auth_error\", error);\n\t\t});\n\n\t\t// Handle event acknowledgments from gateway\n\t\tthis.socket.on(\"events:ack\", (payload: EventsAckPayload) => {\n\t\t\tlogger.debug(\n\t\t\t\t{\n\t\t\t\t\tsessionId: payload.sessionId,\n\t\t\t\t\trevision: payload.revision,\n\t\t\t\t\tupToSeq: payload.upToSeq,\n\t\t\t\t},\n\t\t\t\t\"events_acked\",\n\t\t\t);\n\t\t\tthis.options.sessionManager.ackEvents(\n\t\t\t\tpayload.sessionId,\n\t\t\t\tpayload.revision,\n\t\t\t\tpayload.upToSeq,\n\t\t\t);\n\t\t});\n\t}\n\n\tprivate setupRpcHandlers() {\n\t\tconst { sessionManager } = this.options;\n\n\t\t// Session create\n\t\tthis.socket.on(\"rpc:session:create\", async (request) => {\n\t\t\ttry {\n\t\t\t\tlogger.info({ requestId: request.requestId }, \"rpc_session_create\");\n\t\t\t\tconst session = await sessionManager.createSession(request.params);\n\t\t\t\tthis.sendRpcResponse(request.requestId, session);\n\t\t\t} catch (error) {\n\t\t\t\tlogger.error(\n\t\t\t\t\t{ err: error, requestId: request.requestId },\n\t\t\t\t\t\"rpc_session_create_error\",\n\t\t\t\t);\n\t\t\t\tthis.sendRpcError(request.requestId, error);\n\t\t\t}\n\t\t});\n\n\t\t// Session close\n\t\tthis.socket.on(\"rpc:session:close\", async (request) => {\n\t\t\ttry {\n\t\t\t\tlogger.info(\n\t\t\t\t\t{ requestId: request.requestId, sessionId: request.params.sessionId },\n\t\t\t\t\t\"rpc_session_close\",\n\t\t\t\t);\n\t\t\t\tawait sessionManager.closeSession(request.params.sessionId);\n\t\t\t\tthis.sendRpcResponse(request.requestId, { ok: true });\n\t\t\t} catch (error) {\n\t\t\t\tlogger.error(\n\t\t\t\t\t{\n\t\t\t\t\t\terr: error,\n\t\t\t\t\t\trequestId: request.requestId,\n\t\t\t\t\t\tsessionId: request.params.sessionId,\n\t\t\t\t\t},\n\t\t\t\t\t\"rpc_session_close_error\",\n\t\t\t\t);\n\t\t\t\tthis.sendRpcError(request.requestId, error);\n\t\t\t}\n\t\t});\n\n\t\t// Session cancel\n\t\tthis.socket.on(\"rpc:session:cancel\", async (request) => {\n\t\t\ttry {\n\t\t\t\tlogger.info(\n\t\t\t\t\t{ requestId: request.requestId, sessionId: request.params.sessionId },\n\t\t\t\t\t\"rpc_session_cancel\",\n\t\t\t\t);\n\t\t\t\tawait sessionManager.cancelSession(request.params.sessionId);\n\t\t\t\tthis.sendRpcResponse(request.requestId, { ok: true });\n\t\t\t} catch (error) {\n\t\t\t\tlogger.error(\n\t\t\t\t\t{\n\t\t\t\t\t\terr: error,\n\t\t\t\t\t\trequestId: request.requestId,\n\t\t\t\t\t\tsessionId: request.params.sessionId,\n\t\t\t\t\t},\n\t\t\t\t\t\"rpc_session_cancel_error\",\n\t\t\t\t);\n\t\t\t\tthis.sendRpcError(request.requestId, error);\n\t\t\t}\n\t\t});\n\n\t\t// Session mode\n\t\tthis.socket.on(\"rpc:session:mode\", async (request) => {\n\t\t\ttry {\n\t\t\t\tlogger.info(\n\t\t\t\t\t{\n\t\t\t\t\t\trequestId: request.requestId,\n\t\t\t\t\t\tsessionId: request.params.sessionId,\n\t\t\t\t\t\tmodeId: request.params.modeId,\n\t\t\t\t\t},\n\t\t\t\t\t\"rpc_session_mode\",\n\t\t\t\t);\n\t\t\t\tconst session = await sessionManager.setSessionMode(\n\t\t\t\t\trequest.params.sessionId,\n\t\t\t\t\trequest.params.modeId,\n\t\t\t\t);\n\t\t\t\tthis.sendRpcResponse(request.requestId, session);\n\t\t\t} catch (error) {\n\t\t\t\tlogger.error(\n\t\t\t\t\t{\n\t\t\t\t\t\terr: error,\n\t\t\t\t\t\trequestId: request.requestId,\n\t\t\t\t\t\tsessionId: request.params.sessionId,\n\t\t\t\t\t\tmodeId: request.params.modeId,\n\t\t\t\t\t},\n\t\t\t\t\t\"rpc_session_mode_error\",\n\t\t\t\t);\n\t\t\t\tthis.sendRpcError(request.requestId, error);\n\t\t\t}\n\t\t});\n\n\t\t// Session model\n\t\tthis.socket.on(\"rpc:session:model\", async (request) => {\n\t\t\ttry {\n\t\t\t\tlogger.info(\n\t\t\t\t\t{\n\t\t\t\t\t\trequestId: request.requestId,\n\t\t\t\t\t\tsessionId: request.params.sessionId,\n\t\t\t\t\t\tmodelId: request.params.modelId,\n\t\t\t\t\t},\n\t\t\t\t\t\"rpc_session_model\",\n\t\t\t\t);\n\t\t\t\tconst session = await sessionManager.setSessionModel(\n\t\t\t\t\trequest.params.sessionId,\n\t\t\t\t\trequest.params.modelId,\n\t\t\t\t);\n\t\t\t\tthis.sendRpcResponse(request.requestId, session);\n\t\t\t} catch (error) {\n\t\t\t\tlogger.error(\n\t\t\t\t\t{\n\t\t\t\t\t\terr: error,\n\t\t\t\t\t\trequestId: request.requestId,\n\t\t\t\t\t\tsessionId: request.params.sessionId,\n\t\t\t\t\t\tmodelId: request.params.modelId,\n\t\t\t\t\t},\n\t\t\t\t\t\"rpc_session_model_error\",\n\t\t\t\t);\n\t\t\t\tthis.sendRpcError(request.requestId, error);\n\t\t\t}\n\t\t});\n\n\t\t// Send message\n\t\tthis.socket.on(\"rpc:message:send\", async (request) => {\n\t\t\tconst requestStart = process.hrtime.bigint();\n\t\t\ttry {\n\t\t\t\tconst { sessionId, prompt } = request.params;\n\t\t\t\tlogger.info(\n\t\t\t\t\t{\n\t\t\t\t\t\trequestId: request.requestId,\n\t\t\t\t\t\tsessionId,\n\t\t\t\t\t\tpromptBlocks: prompt.length,\n\t\t\t\t\t},\n\t\t\t\t\t\"rpc_message_send\",\n\t\t\t\t);\n\t\t\t\tlogger.debug(\n\t\t\t\t\t{\n\t\t\t\t\t\trequestId: request.requestId,\n\t\t\t\t\t\tsessionId,\n\t\t\t\t\t\tpromptBlocks: prompt.length,\n\t\t\t\t\t},\n\t\t\t\t\t\"rpc_message_send_start\",\n\t\t\t\t);\n\t\t\t\tconst record = sessionManager.getSession(sessionId);\n\t\t\t\tif (!record) {\n\t\t\t\t\tthrow new Error(\"Session not found\");\n\t\t\t\t}\n\t\t\t\tsessionManager.touchSession(sessionId);\n\t\t\t\t// Cast through unknown since SDK and shared ContentBlock types are structurally compatible\n\t\t\t\tconst result = await record.connection.prompt(\n\t\t\t\t\tsessionId,\n\t\t\t\t\tprompt as unknown as import(\"@agentclientprotocol/sdk\").ContentBlock[],\n\t\t\t\t);\n\t\t\t\tsessionManager.touchSession(sessionId);\n\t\t\t\tsessionManager.recordTurnEnd(\n\t\t\t\t\tsessionId,\n\t\t\t\t\tresult.stopReason as StopReason,\n\t\t\t\t);\n\t\t\t\tthis.sendRpcResponse<{ stopReason: StopReason }>(request.requestId, {\n\t\t\t\t\tstopReason: result.stopReason as StopReason,\n\t\t\t\t});\n\t\t\t\tconst durationMs =\n\t\t\t\t\tNumber(process.hrtime.bigint() - requestStart) / 1_000_000;\n\t\t\t\tlogger.info(\n\t\t\t\t\t{\n\t\t\t\t\t\trequestId: request.requestId,\n\t\t\t\t\t\tsessionId,\n\t\t\t\t\t\tstopReason: result.stopReason,\n\t\t\t\t\t\tdurationMs,\n\t\t\t\t\t},\n\t\t\t\t\t\"rpc_message_send_complete\",\n\t\t\t\t);\n\t\t\t\tlogger.debug(\n\t\t\t\t\t{\n\t\t\t\t\t\trequestId: request.requestId,\n\t\t\t\t\t\tsessionId,\n\t\t\t\t\t\tdurationMs,\n\t\t\t\t\t},\n\t\t\t\t\t\"rpc_message_send_finish\",\n\t\t\t\t);\n\t\t\t} catch (error) {\n\t\t\t\tconst durationMs =\n\t\t\t\t\tNumber(process.hrtime.bigint() - requestStart) / 1_000_000;\n\t\t\t\tlogger.error(\n\t\t\t\t\t{\n\t\t\t\t\t\terr: error,\n\t\t\t\t\t\trequestId: request.requestId,\n\t\t\t\t\t\tsessionId: request.params.sessionId,\n\t\t\t\t\t\tpromptBlocks: request.params.prompt.length,\n\t\t\t\t\t\tdurationMs,\n\t\t\t\t\t},\n\t\t\t\t\t\"rpc_message_send_error\",\n\t\t\t\t);\n\t\t\t\tthis.sendRpcError(request.requestId, error);\n\t\t\t}\n\t\t});\n\n\t\t// Permission decision\n\t\tthis.socket.on(\"rpc:permission:decision\", async (request) => {\n\t\t\ttry {\n\t\t\t\tconst { sessionId, requestId, outcome } = request.params;\n\t\t\t\tlogger.info(\n\t\t\t\t\t{ requestId: request.requestId, sessionId, outcome },\n\t\t\t\t\t\"rpc_permission_decision\",\n\t\t\t\t);\n\t\t\t\tsessionManager.resolvePermissionRequest(sessionId, requestId, outcome);\n\t\t\t\tthis.sendRpcResponse(request.requestId, { ok: true });\n\t\t\t} catch (error) {\n\t\t\t\tlogger.error(\n\t\t\t\t\t{\n\t\t\t\t\t\terr: error,\n\t\t\t\t\t\trequestId: request.requestId,\n\t\t\t\t\t\tsessionId: request.params.sessionId,\n\t\t\t\t\t\tpermissionRequestId: request.params.requestId,\n\t\t\t\t\t\toutcome: request.params.outcome,\n\t\t\t\t\t},\n\t\t\t\t\t\"rpc_permission_decision_error\",\n\t\t\t\t);\n\t\t\t\tthis.sendRpcError(request.requestId, error);\n\t\t\t}\n\t\t});\n\n\t\t// File system handlers\n\t\tthis.socket.on(\"rpc:fs:roots\", async (request) => {\n\t\t\ttry {\n\t\t\t\tlogger.debug(\n\t\t\t\t\t{ requestId: request.requestId, sessionId: request.params.sessionId },\n\t\t\t\t\t\"rpc_fs_roots\",\n\t\t\t\t);\n\t\t\t\tconst record = sessionManager.getSession(request.params.sessionId);\n\t\t\t\tif (!record || !record.cwd) {\n\t\t\t\t\tthrow new Error(\"Session not found or no working directory\");\n\t\t\t\t}\n\t\t\t\tconst root: FsRoot = {\n\t\t\t\t\tname: SESSION_ROOT_NAME,\n\t\t\t\t\tpath: record.cwd,\n\t\t\t\t};\n\t\t\t\tthis.sendRpcResponse(request.requestId, { root });\n\t\t\t} catch (error) {\n\t\t\t\tlogger.error(\n\t\t\t\t\t{\n\t\t\t\t\t\terr: error,\n\t\t\t\t\t\trequestId: request.requestId,\n\t\t\t\t\t\tsessionId: request.params.sessionId,\n\t\t\t\t\t},\n\t\t\t\t\t\"rpc_fs_roots_error\",\n\t\t\t\t);\n\t\t\t\tthis.sendRpcError(request.requestId, error);\n\t\t\t}\n\t\t});\n\n\t\tthis.socket.on(\"rpc:hostfs:roots\", async (request) => {\n\t\t\ttry {\n\t\t\t\tlogger.debug(\n\t\t\t\t\t{\n\t\t\t\t\t\trequestId: request.requestId,\n\t\t\t\t\t\tmachineId: request.params.machineId,\n\t\t\t\t\t},\n\t\t\t\t\t\"rpc_hostfs_roots\",\n\t\t\t\t);\n\t\t\t\tconst result = await buildHostFsRoots();\n\t\t\t\tthis.sendRpcResponse(request.requestId, result);\n\t\t\t} catch (error) {\n\t\t\t\tlogger.error(\n\t\t\t\t\t{\n\t\t\t\t\t\terr: error,\n\t\t\t\t\t\trequestId: request.requestId,\n\t\t\t\t\t\tmachineId: request.params.machineId,\n\t\t\t\t\t},\n\t\t\t\t\t\"rpc_hostfs_roots_error\",\n\t\t\t\t);\n\t\t\t\tthis.sendRpcError(request.requestId, error);\n\t\t\t}\n\t\t});\n\n\t\tthis.socket.on(\"rpc:hostfs:entries\", async (request) => {\n\t\t\ttry {\n\t\t\t\tconst { path: requestPath, machineId } = request.params;\n\t\t\t\tlogger.debug(\n\t\t\t\t\t{ requestId: request.requestId, machineId, path: requestPath },\n\t\t\t\t\t\"rpc_hostfs_entries\",\n\t\t\t\t);\n\t\t\t\tconst entries = await readDirectoryEntries(requestPath);\n\t\t\t\tthis.sendRpcResponse(request.requestId, {\n\t\t\t\t\tpath: requestPath,\n\t\t\t\t\tentries: filterVisibleEntries(entries),\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tlogger.error(\n\t\t\t\t\t{\n\t\t\t\t\t\terr: error,\n\t\t\t\t\t\trequestId: request.requestId,\n\t\t\t\t\t\tmachineId: request.params.machineId,\n\t\t\t\t\t},\n\t\t\t\t\t\"rpc_hostfs_entries_error\",\n\t\t\t\t);\n\t\t\t\tthis.sendRpcError(request.requestId, error);\n\t\t\t}\n\t\t});\n\n\t\tthis.socket.on(\"rpc:fs:entries\", async (request) => {\n\t\t\ttry {\n\t\t\t\tconst { sessionId, path: requestPath } = request.params;\n\t\t\t\tlogger.debug(\n\t\t\t\t\t{ requestId: request.requestId, sessionId, path: requestPath },\n\t\t\t\t\t\"rpc_fs_entries\",\n\t\t\t\t);\n\t\t\t\tconst record = sessionManager.getSession(sessionId);\n\t\t\t\tif (!record || !record.cwd) {\n\t\t\t\t\tthrow new Error(\"Session not found or no working directory\");\n\t\t\t\t}\n\t\t\t\tconst resolved = requestPath\n\t\t\t\t\t? resolveWithinCwd(record.cwd, requestPath)\n\t\t\t\t\t: record.cwd;\n\t\t\t\tconst entries = await readDirectoryEntries(resolved);\n\t\t\t\tthis.sendRpcResponse(request.requestId, { path: resolved, entries });\n\t\t\t} catch (error) {\n\t\t\t\tlogger.error(\n\t\t\t\t\t{\n\t\t\t\t\t\terr: error,\n\t\t\t\t\t\trequestId: request.requestId,\n\t\t\t\t\t\tsessionId: request.params.sessionId,\n\t\t\t\t\t},\n\t\t\t\t\t\"rpc_fs_entries_error\",\n\t\t\t\t);\n\t\t\t\tthis.sendRpcError(request.requestId, error);\n\t\t\t}\n\t\t});\n\n\t\tthis.socket.on(\"rpc:fs:file\", async (request) => {\n\t\t\ttry {\n\t\t\t\tconst { sessionId, path: requestPath } = request.params;\n\t\t\t\tlogger.debug(\n\t\t\t\t\t{ requestId: request.requestId, sessionId, path: requestPath },\n\t\t\t\t\t\"rpc_fs_file\",\n\t\t\t\t);\n\t\t\t\tconst record = sessionManager.getSession(sessionId);\n\t\t\t\tif (!record || !record.cwd) {\n\t\t\t\t\tthrow new Error(\"Session not found or no working directory\");\n\t\t\t\t}\n\t\t\t\tconst resolved = resolveWithinCwd(record.cwd, requestPath);\n\t\t\t\tconst mimeType = resolveImageMimeType(resolved);\n\t\t\t\tif (mimeType) {\n\t\t\t\t\tconst buffer = await fs.readFile(resolved);\n\t\t\t\t\tconst preview: SessionFsFilePreview = {\n\t\t\t\t\t\tpath: resolved,\n\t\t\t\t\t\tpreviewType: \"image\",\n\t\t\t\t\t\tcontent: `data:${mimeType};base64,${buffer.toString(\"base64\")}`,\n\t\t\t\t\t\tmimeType,\n\t\t\t\t\t};\n\t\t\t\t\tthis.sendRpcResponse(request.requestId, preview);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst content = await fs.readFile(resolved, \"utf8\");\n\t\t\t\tconst preview: SessionFsFilePreview = {\n\t\t\t\t\tpath: resolved,\n\t\t\t\t\tpreviewType: \"code\",\n\t\t\t\t\tcontent,\n\t\t\t\t};\n\t\t\t\tthis.sendRpcResponse(request.requestId, preview);\n\t\t\t} catch (error) {\n\t\t\t\tlogger.error(\n\t\t\t\t\t{\n\t\t\t\t\t\terr: error,\n\t\t\t\t\t\trequestId: request.requestId,\n\t\t\t\t\t\tsessionId: request.params.sessionId,\n\t\t\t\t\t},\n\t\t\t\t\t\"rpc_fs_file_error\",\n\t\t\t\t);\n\t\t\t\tthis.sendRpcError(request.requestId, error);\n\t\t\t}\n\t\t});\n\n\t\tthis.socket.on(\"rpc:fs:resources\", async (request) => {\n\t\t\ttry {\n\t\t\t\tconst { sessionId } = request.params;\n\t\t\t\tlogger.debug(\n\t\t\t\t\t{ requestId: request.requestId, sessionId },\n\t\t\t\t\t\"rpc_fs_resources\",\n\t\t\t\t);\n\t\t\t\tconst record = sessionManager.getSession(sessionId);\n\t\t\t\tif (!record || !record.cwd) {\n\t\t\t\t\tthrow new Error(\"Session not found or no working directory\");\n\t\t\t\t}\n\t\t\t\tconst entries = await this.listSessionResources(record.cwd);\n\t\t\t\tthis.sendRpcResponse(request.requestId, {\n\t\t\t\t\trootPath: record.cwd,\n\t\t\t\t\tentries,\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tlogger.error(\n\t\t\t\t\t{\n\t\t\t\t\t\terr: error,\n\t\t\t\t\t\trequestId: request.requestId,\n\t\t\t\t\t\tsessionId: request.params.sessionId,\n\t\t\t\t\t},\n\t\t\t\t\t\"rpc_fs_resources_error\",\n\t\t\t\t);\n\t\t\t\tthis.sendRpcError(request.requestId, error);\n\t\t\t}\n\t\t});\n\n\t\t// Session discovery - list sessions from ACP agent\n\t\tthis.socket.on(\"rpc:sessions:discover\", async (request) => {\n\t\t\ttry {\n\t\t\t\tconst { cwd, backendId, cursor } = request.params;\n\t\t\t\tlogger.info(\n\t\t\t\t\t{ requestId: request.requestId, cwd, backendId, cursor },\n\t\t\t\t\t\"rpc_sessions_discover\",\n\t\t\t\t);\n\t\t\t\tconst result = await sessionManager.discoverSessions({\n\t\t\t\t\tcwd,\n\t\t\t\t\tbackendId,\n\t\t\t\t\tcursor,\n\t\t\t\t});\n\t\t\t\tthis.sendRpcResponse(request.requestId, result);\n\t\t\t} catch (error) {\n\t\t\t\tlogger.error(\n\t\t\t\t\t{\n\t\t\t\t\t\terr: error,\n\t\t\t\t\t\trequestId: request.requestId,\n\t\t\t\t\t},\n\t\t\t\t\t\"rpc_sessions_discover_error\",\n\t\t\t\t);\n\t\t\t\tthis.sendRpcError(request.requestId, error);\n\t\t\t}\n\t\t});\n\n\t\t// Load historical session from ACP agent\n\t\tthis.socket.on(\"rpc:session:load\", async (request) => {\n\t\t\ttry {\n\t\t\t\tconst { sessionId, cwd, backendId } = request.params;\n\t\t\t\tlogger.info(\n\t\t\t\t\t{ requestId: request.requestId, sessionId, cwd, backendId },\n\t\t\t\t\t\"rpc_session_load\",\n\t\t\t\t);\n\t\t\t\tconst session = await sessionManager.loadSession(\n\t\t\t\t\tsessionId,\n\t\t\t\t\tcwd,\n\t\t\t\t\tbackendId,\n\t\t\t\t);\n\t\t\t\tthis.sendRpcResponse(request.requestId, session);\n\t\t\t} catch (error) {\n\t\t\t\tlogger.error(\n\t\t\t\t\t{\n\t\t\t\t\t\terr: error,\n\t\t\t\t\t\trequestId: request.requestId,\n\t\t\t\t\t\tsessionId: request.params.sessionId,\n\t\t\t\t\t},\n\t\t\t\t\t\"rpc_session_load_error\",\n\t\t\t\t);\n\t\t\t\tthis.sendRpcError(request.requestId, error);\n\t\t\t}\n\t\t});\n\n\t\t// Reload historical session from ACP agent\n\t\tthis.socket.on(\"rpc:session:reload\", async (request) => {\n\t\t\ttry {\n\t\t\t\tconst { sessionId, cwd, backendId } = request.params;\n\t\t\t\tlogger.info(\n\t\t\t\t\t{ requestId: request.requestId, sessionId, cwd, backendId },\n\t\t\t\t\t\"rpc_session_reload\",\n\t\t\t\t);\n\t\t\t\tconst session = await sessionManager.reloadSession(\n\t\t\t\t\tsessionId,\n\t\t\t\t\tcwd,\n\t\t\t\t\tbackendId,\n\t\t\t\t);\n\t\t\t\tthis.sendRpcResponse(request.requestId, session);\n\t\t\t} catch (error) {\n\t\t\t\tlogger.error(\n\t\t\t\t\t{\n\t\t\t\t\t\terr: error,\n\t\t\t\t\t\trequestId: request.requestId,\n\t\t\t\t\t\tsessionId: request.params.sessionId,\n\t\t\t\t\t},\n\t\t\t\t\t\"rpc_session_reload_error\",\n\t\t\t\t);\n\t\t\t\tthis.sendRpcError(request.requestId, error);\n\t\t\t}\n\t\t});\n\n\t\t// Git status handler\n\t\tthis.socket.on(\"rpc:git:status\", async (request) => {\n\t\t\ttry {\n\t\t\t\tconst { sessionId } = request.params;\n\t\t\t\tlogger.debug(\n\t\t\t\t\t{ requestId: request.requestId, sessionId },\n\t\t\t\t\t\"rpc_git_status\",\n\t\t\t\t);\n\t\t\t\tconst record = sessionManager.getSession(sessionId);\n\t\t\t\tif (!record || !record.cwd) {\n\t\t\t\t\tthrow new Error(\"Session not found or no working directory\");\n\t\t\t\t}\n\n\t\t\t\tconst isRepo = await isGitRepo(record.cwd);\n\t\t\t\tif (!isRepo) {\n\t\t\t\t\tthis.sendRpcResponse(request.requestId, {\n\t\t\t\t\t\tisGitRepo: false,\n\t\t\t\t\t\tfiles: [],\n\t\t\t\t\t\tdirStatus: {},\n\t\t\t\t\t});\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst [branch, files] = await Promise.all([\n\t\t\t\t\tgetGitBranch(record.cwd),\n\t\t\t\t\tgetGitStatus(record.cwd),\n\t\t\t\t]);\n\t\t\t\tconst dirStatus = aggregateDirStatus(files);\n\n\t\t\t\tthis.sendRpcResponse(request.requestId, {\n\t\t\t\t\tisGitRepo: true,\n\t\t\t\t\tbranch,\n\t\t\t\t\tfiles,\n\t\t\t\t\tdirStatus,\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tlogger.error(\n\t\t\t\t\t{\n\t\t\t\t\t\terr: error,\n\t\t\t\t\t\trequestId: request.requestId,\n\t\t\t\t\t\tsessionId: request.params.sessionId,\n\t\t\t\t\t},\n\t\t\t\t\t\"rpc_git_status_error\",\n\t\t\t\t);\n\t\t\t\tthis.sendRpcError(request.requestId, error);\n\t\t\t}\n\t\t});\n\n\t\t// Git file diff handler\n\t\tthis.socket.on(\"rpc:git:fileDiff\", async (request) => {\n\t\t\ttry {\n\t\t\t\tconst { sessionId, path: filePath } = request.params;\n\t\t\t\tlogger.debug(\n\t\t\t\t\t{ requestId: request.requestId, sessionId, path: filePath },\n\t\t\t\t\t\"rpc_git_file_diff\",\n\t\t\t\t);\n\t\t\t\tconst record = sessionManager.getSession(sessionId);\n\t\t\t\tif (!record || !record.cwd) {\n\t\t\t\t\tthrow new Error(\"Session not found or no working directory\");\n\t\t\t\t}\n\n\t\t\t\t// Validate filePath stays within cwd\n\t\t\t\tresolveWithinCwd(record.cwd, filePath);\n\n\t\t\t\tconst isRepo = await isGitRepo(record.cwd);\n\t\t\t\tif (!isRepo) {\n\t\t\t\t\tthis.sendRpcResponse(request.requestId, {\n\t\t\t\t\t\tisGitRepo: false,\n\t\t\t\t\t\tpath: filePath,\n\t\t\t\t\t\taddedLines: [],\n\t\t\t\t\t\tmodifiedLines: [],\n\t\t\t\t\t});\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst { addedLines, modifiedLines } = await getFileDiff(\n\t\t\t\t\trecord.cwd,\n\t\t\t\t\tfilePath,\n\t\t\t\t);\n\n\t\t\t\tthis.sendRpcResponse(request.requestId, {\n\t\t\t\t\tisGitRepo: true,\n\t\t\t\t\tpath: filePath,\n\t\t\t\t\taddedLines,\n\t\t\t\t\tmodifiedLines,\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tlogger.error(\n\t\t\t\t\t{\n\t\t\t\t\t\terr: error,\n\t\t\t\t\t\trequestId: request.requestId,\n\t\t\t\t\t\tsessionId: request.params.sessionId,\n\t\t\t\t\t},\n\t\t\t\t\t\"rpc_git_file_diff_error\",\n\t\t\t\t);\n\t\t\t\tthis.sendRpcError(request.requestId, error);\n\t\t\t}\n\t\t});\n\n\t\t// Archive session\n\t\tthis.socket.on(\"rpc:session:archive\", async (request) => {\n\t\t\ttry {\n\t\t\t\tconst { sessionId } = request.params;\n\t\t\t\tlogger.info(\n\t\t\t\t\t{ requestId: request.requestId, sessionId },\n\t\t\t\t\t\"rpc_session_archive\",\n\t\t\t\t);\n\t\t\t\tawait sessionManager.archiveSession(sessionId);\n\t\t\t\tthis.sendRpcResponse(request.requestId, { ok: true });\n\t\t\t} catch (error) {\n\t\t\t\tlogger.error(\n\t\t\t\t\t{\n\t\t\t\t\t\terr: error,\n\t\t\t\t\t\trequestId: request.requestId,\n\t\t\t\t\t\tsessionId: request.params.sessionId,\n\t\t\t\t\t},\n\t\t\t\t\t\"rpc_session_archive_error\",\n\t\t\t\t);\n\t\t\t\tthis.sendRpcError(request.requestId, error);\n\t\t\t}\n\t\t});\n\n\t\t// Bulk archive sessions\n\t\tthis.socket.on(\"rpc:session:archive-all\", async (request) => {\n\t\t\ttry {\n\t\t\t\tconst { sessionIds } = request.params;\n\t\t\t\tlogger.info(\n\t\t\t\t\t{\n\t\t\t\t\t\trequestId: request.requestId,\n\t\t\t\t\t\tcount: sessionIds.length,\n\t\t\t\t\t},\n\t\t\t\t\t\"rpc_session_archive_all\",\n\t\t\t\t);\n\t\t\t\tconst result = await sessionManager.bulkArchiveSessions(sessionIds);\n\t\t\t\tthis.sendRpcResponse(request.requestId, result);\n\t\t\t} catch (error) {\n\t\t\t\tlogger.error(\n\t\t\t\t\t{\n\t\t\t\t\t\terr: error,\n\t\t\t\t\t\trequestId: request.requestId,\n\t\t\t\t\t},\n\t\t\t\t\t\"rpc_session_archive_all_error\",\n\t\t\t\t);\n\t\t\t\tthis.sendRpcError(request.requestId, error);\n\t\t\t}\n\t\t});\n\n\t\t// Session events RPC handler (for backfill)\n\t\tthis.socket.on(\"rpc:session:events\", (request) => {\n\t\t\ttry {\n\t\t\t\tconst { sessionId, revision, afterSeq, limit } = request.params;\n\t\t\t\tlogger.debug(\n\t\t\t\t\t{\n\t\t\t\t\t\trequestId: request.requestId,\n\t\t\t\t\t\tsessionId,\n\t\t\t\t\t\trevision,\n\t\t\t\t\t\tafterSeq,\n\t\t\t\t\t\tlimit,\n\t\t\t\t\t},\n\t\t\t\t\t\"rpc_session_events\",\n\t\t\t\t);\n\n\t\t\t\tconst result = sessionManager.getSessionEvents({\n\t\t\t\t\tsessionId,\n\t\t\t\t\trevision,\n\t\t\t\t\tafterSeq,\n\t\t\t\t\tlimit,\n\t\t\t\t});\n\n\t\t\t\t// Encrypt event payloads before sending\n\t\t\t\tresult.events = result.events.map((e) =>\n\t\t\t\t\tthis.options.cryptoService.encryptEvent(e),\n\t\t\t\t);\n\n\t\t\t\tthis.sendRpcResponse<SessionEventsResponse>(request.requestId, result);\n\t\t\t} catch (error) {\n\t\t\t\tlogger.error(\n\t\t\t\t\t{\n\t\t\t\t\t\terr: error,\n\t\t\t\t\t\trequestId: request.requestId,\n\t\t\t\t\t\tsessionId: request.params.sessionId,\n\t\t\t\t\t},\n\t\t\t\t\t\"rpc_session_events_error\",\n\t\t\t\t);\n\t\t\t\tthis.sendRpcError(request.requestId, error);\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate setupSessionManagerListeners() {\n\t\tconst { sessionManager } = this.options;\n\n\t\t// Note: session:update, session:error, and terminal:output are no longer\n\t\t// emitted separately - they're unified through session:event (WAL-persisted)\n\n\t\tsessionManager.onPermissionRequest((payload) => {\n\t\t\tif (this.connected) {\n\t\t\t\tthis.socket.emit(\"permission:request\", payload);\n\t\t\t}\n\t\t});\n\n\t\tsessionManager.onPermissionResult((payload) => {\n\t\t\tif (this.connected) {\n\t\t\t\tthis.socket.emit(\"permission:result\", payload);\n\t\t\t}\n\t\t});\n\n\t\tsessionManager.onSessionsChanged((payload) => {\n\t\t\tif (this.connected) {\n\t\t\t\tlogger.info(\n\t\t\t\t\t{\n\t\t\t\t\t\tadded: payload.added.length,\n\t\t\t\t\t\tupdated: payload.updated.length,\n\t\t\t\t\t\tremoved: payload.removed.length,\n\t\t\t\t\t},\n\t\t\t\t\t\"sessions_changed_emit\",\n\t\t\t\t);\n\t\t\t\tthis.socket.emit(\"sessions:changed\", payload);\n\t\t\t}\n\t\t});\n\n\t\tsessionManager.onSessionAttached((payload) => {\n\t\t\tif (this.connected) {\n\t\t\t\tthis.socket.emit(\"session:attached\", payload);\n\t\t\t}\n\t\t});\n\n\t\tsessionManager.onSessionDetached((payload) => {\n\t\t\tif (this.connected) {\n\t\t\t\tthis.socket.emit(\"session:detached\", payload);\n\t\t\t}\n\t\t});\n\n\t\t// Unified event channel - all content updates (messages, tool calls,\n\t\t// terminal output, errors) are WAL-persisted and emitted via session:event\n\t\tsessionManager.onSessionEvent((event) => {\n\t\t\tlogger.info(\n\t\t\t\t{\n\t\t\t\t\tsessionId: event.sessionId,\n\t\t\t\t\trevision: event.revision,\n\t\t\t\t\tseq: event.seq,\n\t\t\t\t\tkind: event.kind,\n\t\t\t\t\tconnected: this.connected,\n\t\t\t\t},\n\t\t\t\t\"session_event_received_from_manager\",\n\t\t\t);\n\t\t\tif (this.connected) {\n\t\t\t\t// Encrypt payload before sending to gateway\n\t\t\t\tconst encrypted = this.options.cryptoService.encryptEvent(event);\n\t\t\t\tlogger.debug(\n\t\t\t\t\t{\n\t\t\t\t\t\tsessionId: event.sessionId,\n\t\t\t\t\t\trevision: event.revision,\n\t\t\t\t\t\tseq: event.seq,\n\t\t\t\t\t\tkind: event.kind,\n\t\t\t\t\t},\n\t\t\t\t\t\"session_event_emitting_to_gateway\",\n\t\t\t\t);\n\t\t\t\tthis.socket.emit(\"session:event\", encrypted);\n\t\t\t\tlogger.debug(\n\t\t\t\t\t{\n\t\t\t\t\t\tsessionId: event.sessionId,\n\t\t\t\t\t\tseq: event.seq,\n\t\t\t\t\t},\n\t\t\t\t\t\"session_event_emitted_to_gateway\",\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tlogger.warn(\n\t\t\t\t\t{\n\t\t\t\t\t\tsessionId: event.sessionId,\n\t\t\t\t\t\tseq: event.seq,\n\t\t\t\t\t\tkind: event.kind,\n\t\t\t\t\t},\n\t\t\t\t\t\"session_event_dropped_not_connected\",\n\t\t\t\t);\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate async listSessionResources(\n\t\trootPath: string,\n\t): Promise<SessionFsResourceEntry[]> {\n\t\tconst ig = await loadGitignore(rootPath);\n\t\tconst allFiles = await this.listAllFiles(rootPath, ig, rootPath, []);\n\t\treturn allFiles.map((filePath) => ({\n\t\t\tname: path.basename(filePath),\n\t\t\trelativePath: path.relative(rootPath, filePath),\n\t\t\tpath: filePath,\n\t\t}));\n\t}\n\n\tprivate async listAllFiles(\n\t\trootPath: string,\n\t\tig: Ignore,\n\t\tbaseDir: string,\n\t\tcollected: string[] = [],\n\t): Promise<string[]> {\n\t\tif (collected.length >= MAX_RESOURCE_FILES) {\n\t\t\treturn collected;\n\t\t}\n\t\tconst entries = await fs.readdir(rootPath, { withFileTypes: true });\n\t\tfor (const entry of entries) {\n\t\t\tif (collected.length >= MAX_RESOURCE_FILES) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tconst entryPath = path.join(rootPath, entry.name);\n\t\t\tconst relativePath = path.relative(baseDir, entryPath);\n\n\t\t\t// Check gitignore (add trailing slash for directories)\n\t\t\tconst checkPath = entry.isDirectory() ? `${relativePath}/` : relativePath;\n\t\t\tif (ig.ignores(checkPath)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (entry.isDirectory()) {\n\t\t\t\tawait this.listAllFiles(entryPath, ig, baseDir, collected);\n\t\t\t} else if (entry.isFile()) {\n\t\t\t\tcollected.push(entryPath);\n\t\t\t}\n\t\t}\n\t\treturn collected;\n\t}\n\n\tprivate sendRpcResponse<T>(requestId: string, result: T) {\n\t\tconst response: RpcResponse<T> = { requestId, result };\n\t\tthis.socket.emit(\"rpc:response\", response);\n\t\tlogger.debug({ requestId }, \"rpc_response_sent\");\n\t}\n\n\tprivate sendRpcError(requestId: string, error: unknown) {\n\t\tconst message = error instanceof Error ? error.message : \"Unknown error\";\n\t\tconst detail =\n\t\t\tprocess.env.NODE_ENV === \"development\"\n\t\t\t\t? error instanceof Error\n\t\t\t\t\t? error.stack\n\t\t\t\t\t: undefined\n\t\t\t\t: undefined;\n\t\tlogger.error(\n\t\t\t{\n\t\t\t\trequestId,\n\t\t\t\terr: error,\n\t\t\t\tmessage,\n\t\t\t\tdetail,\n\t\t\t},\n\t\t\t\"rpc_response_error_sent\",\n\t\t);\n\t\tconst response: RpcResponse<unknown> = {\n\t\t\trequestId,\n\t\t\terror: {\n\t\t\t\tcode: \"INTERNAL_ERROR\",\n\t\t\t\tmessage,\n\t\t\t\tretryable: true,\n\t\t\t\tscope: \"request\",\n\t\t\t\tdetail,\n\t\t\t},\n\t\t};\n\t\tthis.socket.emit(\"rpc:response\", response);\n\t}\n\n\tprivate register() {\n\t\tconst { config, sessionManager } = this.options;\n\t\tlogger.info({ machineId: config.machineId }, \"cli_register_emit\");\n\t\tthis.socket.emit(\"cli:register\", {\n\t\t\tmachineId: config.machineId,\n\t\t\thostname: config.hostname,\n\t\t\tversion: config.clientVersion,\n\t\t\tbackends: config.acpBackends.map((backend) => ({\n\t\t\t\tbackendId: backend.id,\n\t\t\t\tbackendLabel: backend.label,\n\t\t\t})),\n\t\t});\n\t\tlogger.info({ machineId: config.machineId }, \"cli_register_sessions_list\");\n\t\t// Send current sessions list (active + discovered)\n\t\tthis.socket.emit(\"sessions:list\", sessionManager.listAllSessions());\n\t}\n\n\tprivate startHeartbeat() {\n\t\tthis.stopHeartbeat();\n\t\tthis.heartbeatInterval = setInterval(() => {\n\t\t\tif (this.connected) {\n\t\t\t\tthis.socket.emit(\"cli:heartbeat\");\n\t\t\t\tthis.socket.emit(\n\t\t\t\t\t\"sessions:list\",\n\t\t\t\t\tthis.options.sessionManager.listAllSessions(),\n\t\t\t\t);\n\t\t\t}\n\t\t}, 30000);\n\t}\n\n\tprivate stopHeartbeat() {\n\t\tif (this.heartbeatInterval) {\n\t\t\tclearInterval(this.heartbeatInterval);\n\t\t\tthis.heartbeatInterval = undefined;\n\t\t}\n\t}\n\n\t/**\n\t * Replay unacked events for all active sessions after reconnection.\n\t */\n\tprivate replayUnackedEvents() {\n\t\tconst { sessionManager } = this.options;\n\t\tconst sessions = sessionManager.listSessions();\n\n\t\tfor (const session of sessions) {\n\t\t\tconst revision = sessionManager.getSessionRevision(session.sessionId);\n\t\t\tif (revision === undefined) continue;\n\n\t\t\tconst unackedEvents = sessionManager.getUnackedEvents(\n\t\t\t\tsession.sessionId,\n\t\t\t\trevision,\n\t\t\t);\n\n\t\t\tif (unackedEvents.length > 0) {\n\t\t\t\tlogger.info(\n\t\t\t\t\t{\n\t\t\t\t\t\tsessionId: session.sessionId,\n\t\t\t\t\t\trevision,\n\t\t\t\t\t\tcount: unackedEvents.length,\n\t\t\t\t\t},\n\t\t\t\t\t\"replaying_unacked_events\",\n\t\t\t\t);\n\n\t\t\t\tfor (const event of unackedEvents) {\n\t\t\t\t\tconst encrypted = this.options.cryptoService.encryptEvent(event);\n\t\t\t\t\tthis.socket.emit(\"session:event\", encrypted);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tconnect() {\n\t\tthis.socket.connect();\n\t}\n\n\tdisconnect() {\n\t\tthis.stopHeartbeat();\n\t\tthis.socket.disconnect();\n\t}\n\n\tisConnected() {\n\t\treturn this.connected;\n\t}\n}\n",
20
+ "import { execFile } from \"node:child_process\";\nimport { readFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { promisify } from \"node:util\";\nimport type { GitFileStatus } from \"@mobvibe/shared\";\n\nconst execFileAsync = promisify(execFile);\nconst MAX_BUFFER = 10 * 1024 * 1024; // 10MB buffer for large repos\n\n/**\n * Check if a directory is a git repository.\n */\nexport async function isGitRepo(cwd: string): Promise<boolean> {\n\ttry {\n\t\tawait execFileAsync(\"git\", [\"rev-parse\", \"--is-inside-work-tree\"], {\n\t\t\tcwd,\n\t\t\tmaxBuffer: MAX_BUFFER,\n\t\t});\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n/**\n * Get the current git branch name.\n */\nexport async function getGitBranch(cwd: string): Promise<string | undefined> {\n\ttry {\n\t\tconst { stdout } = await execFileAsync(\n\t\t\t\"git\",\n\t\t\t[\"branch\", \"--show-current\"],\n\t\t\t{\n\t\t\t\tcwd,\n\t\t\t\tmaxBuffer: MAX_BUFFER,\n\t\t\t},\n\t\t);\n\t\tconst branch = stdout.trim();\n\t\tif (branch) {\n\t\t\treturn branch;\n\t\t}\n\t\t// Detached HEAD state - try to get the short commit hash\n\t\tconst { stdout: hashOut } = await execFileAsync(\n\t\t\t\"git\",\n\t\t\t[\"rev-parse\", \"--short\", \"HEAD\"],\n\t\t\t{ cwd, maxBuffer: MAX_BUFFER },\n\t\t);\n\t\treturn hashOut.trim() || undefined;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\n/**\n * Parse git status --porcelain output to extract file statuses.\n */\nfunction parseGitStatus(\n\toutput: string,\n): Array<{ path: string; status: GitFileStatus }> {\n\tconst files: Array<{ path: string; status: GitFileStatus }> = [];\n\tconst lines = output.split(\"\\n\").filter((line) => line.length > 0);\n\n\tfor (const line of lines) {\n\t\t// Format: XY path or XY original -> renamed\n\t\tconst indexStatus = line[0];\n\t\tconst workTreeStatus = line[1];\n\t\tconst filePath = line.slice(3).split(\" -> \").pop()?.trim();\n\n\t\tif (!filePath) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Determine the most significant status\n\t\tlet status: GitFileStatus;\n\t\tif (indexStatus === \"?\" || workTreeStatus === \"?\") {\n\t\t\tstatus = \"?\";\n\t\t} else if (indexStatus === \"!\" || workTreeStatus === \"!\") {\n\t\t\tstatus = \"!\";\n\t\t} else if (indexStatus === \"A\" || workTreeStatus === \"A\") {\n\t\t\tstatus = \"A\";\n\t\t} else if (indexStatus === \"D\" || workTreeStatus === \"D\") {\n\t\t\tstatus = \"D\";\n\t\t} else if (indexStatus === \"R\" || workTreeStatus === \"R\") {\n\t\t\tstatus = \"R\";\n\t\t} else if (indexStatus === \"C\" || workTreeStatus === \"C\") {\n\t\t\tstatus = \"C\";\n\t\t} else if (indexStatus === \"U\" || workTreeStatus === \"U\") {\n\t\t\tstatus = \"U\";\n\t\t} else if (\n\t\t\tindexStatus === \"M\" ||\n\t\t\tworkTreeStatus === \"M\" ||\n\t\t\tindexStatus !== \" \" ||\n\t\t\tworkTreeStatus !== \" \"\n\t\t) {\n\t\t\tstatus = \"M\";\n\t\t} else {\n\t\t\tcontinue;\n\t\t}\n\n\t\tfiles.push({ path: filePath, status });\n\t}\n\n\treturn files;\n}\n\n/**\n * Get git status for all files in the repository.\n */\nexport async function getGitStatus(\n\tcwd: string,\n): Promise<Array<{ path: string; status: GitFileStatus }>> {\n\ttry {\n\t\tconst { stdout } = await execFileAsync(\n\t\t\t\"git\",\n\t\t\t[\"status\", \"--porcelain=v1\"],\n\t\t\t{ cwd, maxBuffer: MAX_BUFFER },\n\t\t);\n\t\treturn parseGitStatus(stdout);\n\t} catch {\n\t\treturn [];\n\t}\n}\n\n/**\n * Aggregate file statuses into directory statuses.\n * A directory gets the \"highest priority\" status of its children.\n */\nexport function aggregateDirStatus(\n\tfiles: Array<{ path: string; status: GitFileStatus }>,\n): Record<string, GitFileStatus> {\n\tconst dirStatus: Record<string, GitFileStatus> = {};\n\n\t// Priority order: A > D > M > R > C > U > ? > !\n\tconst statusPriority: Record<GitFileStatus, number> = {\n\t\tA: 7,\n\t\tD: 6,\n\t\tM: 5,\n\t\tR: 4,\n\t\tC: 3,\n\t\tU: 2,\n\t\t\"?\": 1,\n\t\t\"!\": 0,\n\t};\n\n\tfor (const file of files) {\n\t\t// Build all parent directories\n\t\tconst parts = file.path.split(\"/\");\n\t\tlet currentPath = \"\";\n\n\t\tfor (let i = 0; i < parts.length - 1; i++) {\n\t\t\tcurrentPath = currentPath ? `${currentPath}/${parts[i]}` : parts[i];\n\t\t\tconst existing = dirStatus[currentPath];\n\n\t\t\tif (!existing || statusPriority[file.status] > statusPriority[existing]) {\n\t\t\t\tdirStatus[currentPath] = file.status;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn dirStatus;\n}\n\n/**\n * Parse git diff output to extract added, modified, and deleted line numbers.\n * Deleted lines are recorded at the position where the deletion occurred in the new file.\n */\nfunction parseDiffOutput(diffOutput: string): {\n\taddedLines: number[];\n\tmodifiedLines: number[];\n\tdeletedLines: number[];\n} {\n\tconst addedLines: number[] = [];\n\tconst modifiedLines: number[] = [];\n\tconst deletedLines: number[] = [];\n\n\tconst lines = diffOutput.split(\"\\n\");\n\tlet currentLine = 0;\n\tlet inHunk = false;\n\tlet pendingDeletionLine = 0;\n\n\tfor (const line of lines) {\n\t\t// Parse hunk header: @@ -start,count +start,count @@\n\t\tconst hunkMatch = line.match(/^@@\\s+-\\d+(?:,\\d+)?\\s+\\+(\\d+)(?:,\\d+)?\\s+@@/);\n\t\tif (hunkMatch) {\n\t\t\tcurrentLine = Number.parseInt(hunkMatch[1], 10);\n\t\t\tinHunk = true;\n\t\t\tpendingDeletionLine = 0;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (!inHunk) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (line.startsWith(\"+\") && !line.startsWith(\"+++\")) {\n\t\t\t// Added line\n\t\t\taddedLines.push(currentLine);\n\t\t\tcurrentLine++;\n\t\t\tpendingDeletionLine = 0;\n\t\t} else if (line.startsWith(\"-\") && !line.startsWith(\"---\")) {\n\t\t\t// Deleted line - record the current new file position\n\t\t\t// If we're at a deletion, mark the position where content was removed\n\t\t\tif (pendingDeletionLine === 0) {\n\t\t\t\tpendingDeletionLine = currentLine;\n\t\t\t}\n\t\t\t// Record deletion at the current line position (or previous line if at start)\n\t\t\tconst deletionPos = Math.max(1, currentLine);\n\t\t\tif (!deletedLines.includes(deletionPos)) {\n\t\t\t\tdeletedLines.push(deletionPos);\n\t\t\t}\n\t\t} else if (!line.startsWith(\"\\\\\")) {\n\t\t\t// Context line or empty line\n\t\t\tcurrentLine++;\n\t\t\tpendingDeletionLine = 0;\n\t\t}\n\t}\n\n\treturn { addedLines, modifiedLines, deletedLines };\n}\n\n/**\n * Get git diff for a specific file.\n */\nexport async function getFileDiff(\n\tcwd: string,\n\tfilePath: string,\n): Promise<{\n\taddedLines: number[];\n\tmodifiedLines: number[];\n\tdeletedLines: number[];\n}> {\n\ttry {\n\t\t// Get diff against HEAD (includes both staged and unstaged changes)\n\t\tconst relativePath = path.isAbsolute(filePath)\n\t\t\t? path.relative(cwd, filePath)\n\t\t\t: filePath;\n\n\t\tconst { stdout } = await execFileAsync(\n\t\t\t\"git\",\n\t\t\t[\"diff\", \"HEAD\", \"--\", relativePath],\n\t\t\t{ cwd, maxBuffer: MAX_BUFFER },\n\t\t);\n\n\t\tif (!stdout.trim()) {\n\t\t\t// No diff - file might be untracked, check status\n\t\t\tconst { stdout: statusOut } = await execFileAsync(\n\t\t\t\t\"git\",\n\t\t\t\t[\"status\", \"--porcelain=v1\", \"--\", relativePath],\n\t\t\t\t{ cwd, maxBuffer: MAX_BUFFER },\n\t\t\t);\n\n\t\t\tif (statusOut.startsWith(\"?\") || statusOut.startsWith(\"A\")) {\n\t\t\t\t// Untracked or newly added file - all lines are \"added\"\n\t\t\t\tconst absPath = path.isAbsolute(filePath)\n\t\t\t\t\t? filePath\n\t\t\t\t\t: path.resolve(cwd, relativePath);\n\t\t\t\tconst content = await readFile(absPath, \"utf-8\");\n\t\t\t\tconst lineCount = content\n\t\t\t\t\t.split(\"\\n\")\n\t\t\t\t\t.filter((l) => l.length > 0).length;\n\t\t\t\treturn {\n\t\t\t\t\taddedLines: Array.from({ length: lineCount }, (_, i) => i + 1),\n\t\t\t\t\tmodifiedLines: [],\n\t\t\t\t\tdeletedLines: [],\n\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn { addedLines: [], modifiedLines: [], deletedLines: [] };\n\t\t}\n\n\t\treturn parseDiffOutput(stdout);\n\t} catch {\n\t\treturn { addedLines: [], modifiedLines: [], deletedLines: [] };\n\t}\n}\n"
21
+ ],
22
+ "mappings": "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",
23
+ "debugId": "3BEAA052FAC1A9B764756E2164756E21",
24
+ "names": []
25
+ }