@algosuite/vo-mcp 0.2.0-beta.46 → 0.2.0-beta.49

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../src/install.ts", "../src/cloud/pairing.ts", "../src/cloud/credential-store.ts", "../src/cloud/keychain.ts", "../src/codex-mcp-config.ts", "../src/autostart.ts", "../src/install-cli.ts"],
4
- "sourcesContent": ["/**\n * `vo-mcp install` \u2014 one-command client installer for non-coders.\n *\n * Configures Claude Desktop, Claude Code, and Codex to load vo-mcp; guides login; and\n * explains starting the runner. Cross-platform (Windows + macOS/Linux).\n *\n * Steps:\n * 1. Write/merge the MCP server config (backing up existing config).\n * 2. Pair via device code (`vo-mcp pair`) to mint the scoped credential \u2014 device\n * code (not loopback) so it works in every terminal (no 127.0.0.1 callback).\n * 3. Explain `vo-mcp runner` (not started here \u2014 user does it manually).\n * 4. Print clear next steps + success summary.\n */\nimport { homedir, platform } from 'node:os';\nimport { join, dirname } from 'node:path';\nimport { existsSync, readFileSync, writeFileSync, mkdirSync, copyFileSync } from 'node:fs';\nimport { fileURLToPath } from 'node:url';\nimport { runPairing } from './cloud/pairing.js';\nimport { installCodexMcpConfigAt, resolveCodexConfigPath } from './codex-mcp-config.js';\n\n/** Live vo-control-plane Cloud Run URL \u2014 explicit (was derived from the dashboard\n * URL by string-replace, which silently broke when that default changed). */\nconst DEFAULT_CONTROL_PLANE_URL = 'https://vo-control-plane-bzjphrajaq-uc.a.run.app';\nimport { installAutostart } from './autostart.js';\n\nexport interface InstallOptions {\n readonly log?: (msg: string) => void;\n readonly skipLogin?: boolean;\n readonly skipAutostart?: boolean;\n readonly configOnly?: boolean;\n readonly env?: Readonly<Record<string, string | undefined>>;\n}\n\ninterface McpServerEntry {\n command: string;\n args?: string[];\n env?: Record<string, string>;\n}\n\n/**\n * Resolve the Claude config path. Prefers Claude Code's `.claude.json` in the\n * user home, else Claude Desktop's `claude_desktop_config.json` in the platform\n * config directory.\n */\n/** Claude Code CLI config path (~/.claude.json). `home` is injectable for tests. */\nfunction resolveCodeConfigPath(home: string): string {\n return join(home, '.claude.json');\n}\n\n/** Claude Desktop app config path (per-OS). Linux uses capital-C 'Claude'. */\nfunction resolveDesktopConfigPath(home: string, plat: NodeJS.Platform, appData?: string): string {\n if (plat === 'win32') {\n return join(appData ?? join(home, 'AppData', 'Roaming'), 'Claude', 'claude_desktop_config.json');\n }\n if (plat === 'darwin') {\n return join(home, 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json');\n }\n // Linux / others \u2014 capital-C 'Claude' (matches the Claude Desktop app dir).\n return join(home, '.config', 'Claude', 'claude_desktop_config.json');\n}\n\n/**\n * Read + parse existing Claude config (or return empty shape if missing).\n * Never throws \u2014 returns a default shape on any problem.\n */\nfunction readClaudeConfig(path: string): Record<string, unknown> {\n try {\n if (!existsSync(path)) return {};\n const raw = readFileSync(path, 'utf8');\n const parsed = JSON.parse(raw) as unknown;\n // Preserve the FULL config \u2014 Claude Code's ~/.claude.json holds `projects`,\n // history, etc., and Desktop holds `preferences`. We must keep every key and\n // only touch mcpServers, or `install` would wipe the rest of the user's config.\n return parsed && typeof parsed === 'object' && !Array.isArray(parsed)\n ? (parsed as Record<string, unknown>)\n : {};\n } catch {\n // Malformed JSON \u2014 return empty; the caller backs up the original file before\n // any write, so the on-disk original is preserved either way.\n return {};\n }\n}\n\n/**\n * Write the Claude config, creating parent directories as needed. Writes with\n * 2-space indentation for human readability.\n */\nfunction writeClaudeConfig(path: string, config: Record<string, unknown>): void {\n mkdirSync(dirname(path), { recursive: true });\n writeFileSync(path, `${JSON.stringify(config, null, 2)}\\n`, 'utf8');\n}\n\n/**\n * Resolve the absolute path to the vo-mcp CLI (dist/cli.js). Computes from\n * process.argv[1] which is the path to the currently running script\n * (dist/install-cli.js when invoked via `vo-mcp install`).\n */\nfunction resolveVoMcpCliPath(): string {\n // Resolve from this module, not process.argv[1]. When invoked as\n // `vo-mcp install`, argv[1] is the dispatcher under bin/; cli.js lives in dist/.\n return join(dirname(fileURLToPath(import.meta.url)), 'cli.js');\n}\n\n/**\n * Merge the vo-mcp MCP server entry into ONE config file. Preserves EVERY other\n * key (other mcpServers + top-level keys like Claude Code's `projects` or\n * Desktop's `preferences`) \u2014 only the `vo-mcp` entry is touched. Backs up first.\n * Idempotent: if `vo-mcp` already points at this cli.js, no-op.\n */\nfunction installMcpConfigAt(\n configPath: string,\n cliPath: string,\n controlPlaneUrl: string,\n log: (msg: string) => void,\n label: string,\n): void {\n const existing = readClaudeConfig(configPath);\n const mcpServers: Record<string, McpServerEntry> =\n existing['mcpServers'] && typeof existing['mcpServers'] === 'object'\n ? (existing['mcpServers'] as Record<string, McpServerEntry>)\n : {};\n\n // Idempotency: already wired to THIS cli.js? (re-points if the path changed.)\n const voEntry = mcpServers['vo'] ?? mcpServers['vo-mcp'];\n if (voEntry?.args?.some((a: string) => a.includes(cliPath))) {\n log(` ${label} already current: ${configPath}`);\n return;\n }\n\n // Backup before any write (protects the original even if it was malformed).\n if (existsSync(configPath)) {\n const backupPath = `${configPath}.backup-${Date.now()}`;\n copyFileSync(configPath, backupPath);\n log(` Backed up ${label} config \u2192 ${backupPath}`);\n }\n\n const merged: Record<string, unknown> = {\n ...existing,\n mcpServers: {\n ...mcpServers,\n 'vo-mcp': {\n command: 'node',\n args: [cliPath],\n // Preserve any existing env the user added (e.g. model API keys) \u2014 only\n // ensure VO_CONTROL_PLANE_URL is present. NEVER drop the user's env keys.\n env: { VO_CONTROL_PLANE_URL: controlPlaneUrl, ...(voEntry?.env ?? {}) },\n },\n },\n };\n writeClaudeConfig(configPath, merged);\n log(`\u2713 Wrote vo-mcp to ${label}: ${configPath}`);\n}\n\n/**\n * Wire vo-mcp into BOTH the Claude Code CLI (~/.claude.json) and the Claude\n * Desktop app config, so it loads in whichever the user runs. Each write is\n * idempotent + preserves all other config keys. ONLY VO_CONTROL_PLANE_URL (a\n * public URL) is written \u2014 never a secret.\n */\nfunction installMcpConfig(log: (msg: string) => void, env: Readonly<Record<string, string | undefined>>): void {\n // Resolve home from the injected env (tests pass a temp dir) \u2192 falls back to the\n // OS home. This keeps install hermetic: it never touches real configs in tests.\n const home = env['HOME']?.trim() || env['USERPROFILE']?.trim() || homedir();\n const appData = env['APPDATA']?.trim();\n const plat = platform();\n const cliPath = resolveVoMcpCliPath();\n const controlPlaneUrl = env['VO_CONTROL_PLANE_URL']?.trim() || DEFAULT_CONTROL_PLANE_URL;\n installMcpConfigAt(resolveCodeConfigPath(home), cliPath, controlPlaneUrl, log, 'Claude Code CLI');\n installMcpConfigAt(resolveDesktopConfigPath(home, plat, appData), cliPath, controlPlaneUrl, log, 'Claude Desktop');\n installCodexMcpConfigAt(resolveCodexConfigPath(home), cliPath, controlPlaneUrl, log);\n}\n\n/**\n * Run the DEVICE-CODE pairing flow (same as `vo-mcp pair`): a short code is shown,\n * the user enters it in their browser. Device code \u2014 NOT a loopback OAuth callback \u2014\n * so it works in every terminal (sandboxed/remote/SSH can't receive a 127.0.0.1\n * callback, which is why the old loopback `login` dead-ended at a \"link your terminal\"\n * page). Non-fatal: a pairing hiccup logs a retry hint and lets the install finish\n * (config + autostart are still useful; the user can run `vo-mcp pair` later).\n */\nasync function runPairFlow(log: (msg: string) => void, env: Readonly<Record<string, string | undefined>>): Promise<void> {\n log('\\n\u2501\u2501\u2501 Step 2: Link your AlgoHQ account (device code) \u2501\u2501\u2501');\n log('A short code appears below \u2014 open the URL it prints and enter the code.');\n log('Your raw token never persists; a scoped credential is stored in your OS keychain.\\n');\n\n try {\n const result = await runPairing({ env, log });\n log(`\\n\u2713 Paired \u2014 scoped credential stored at: ${result.credentialPath}`);\n } catch (err: unknown) {\n log(`\\n\u26A0 Pairing didn't complete: ${err instanceof Error ? err.message : String(err)}`);\n log(' No problem \u2014 the rest will finish; pair anytime with: vo-mcp pair');\n }\n}\n\n/**\n * Print the runner guidance + success summary.\n */\nfunction printNextSteps(log: (msg: string) => void, autostartInstalled: boolean, configOnly: boolean): void {\n log('\\n\u2501\u2501\u2501 Installation complete! \u2501\u2501\u2501\\n');\n log('What\\'s configured:');\n log(' \u2713 Claude Desktop, Claude Code, and Codex will load AlgoHQ MCP on next restart');\n if (configOnly) {\n log(' \u2713 Existing pairing and runner auto-start settings were left unchanged');\n } else {\n log(' \u2713 Your scoped credential is stored (revocable via the dashboard)');\n }\n if (autostartInstalled) {\n log(' \u2713 Runner daemon will start automatically at login\\n');\n } else {\n log('\\n');\n }\n log('Next steps:');\n log(' 1. Restart Claude Desktop / Claude Code / Codex (if running).');\n if (configOnly) {\n log(' 2. Restart the existing AlgoHQ runner service or runner terminal.');\n } else if (autostartInstalled) {\n log(' 2. Log out and back in (or start the runner manually now: vo-mcp runner)');\n } else {\n log(' 2. Start the agent runner in a terminal (keep it running):');\n log(' vo-mcp runner');\n log(' (To set up auto-start at login: vo-mcp runner --install-autostart)');\n }\n log(' 3. Visit AlgoHQ to dispatch your first agent:');\n log(' https://algosuite.ai/algohq\\n');\n log('The runner watches for tasks you dispatch and spins up agents in fresh worktrees.');\n log('Agents only run while the runner is connected. Ctrl+C to stop it anytime.\\n');\n}\n\n/**\n * Run the full install flow: MCP config \u2192 login \u2192 auto-start \u2192 guidance.\n */\nexport async function install(opts: InstallOptions = {}): Promise<void> {\n const log = opts.log ?? ((m: string) => console.error(m));\n const env = opts.env ?? process.env;\n\n log('\u2501\u2501\u2501 vo-mcp installer \u2501\u2501\u2501');\n log('This will set up your machine to dispatch AlgoHQ agents from anywhere.\\n');\n\n // Step 1: MCP config\n log('\u2501\u2501\u2501 Step 1: Configure Claude Desktop / Claude Code / Codex \u2501\u2501\u2501');\n installMcpConfig(log, env);\n\n // Step 2: Pair via device code (unless skipped)\n if (!opts.skipLogin) {\n await runPairFlow(log, env);\n } else if (opts.configOnly) {\n log('\\n(Config-only refresh \u2014 existing pairing left unchanged.)');\n } else {\n log('\\n(Pairing skipped \u2014 run `vo-mcp pair` when ready.)');\n }\n\n // Step 3: Auto-start (unless skipped)\n let autostartInstalled = false;\n if (!opts.skipAutostart) {\n const plat = platform();\n if (plat === 'win32' || plat === 'darwin' || plat === 'linux') {\n log('\\n\u2501\u2501\u2501 Step 3: Set up auto-start \u2501\u2501\u2501');\n log('Would you like the runner daemon to start automatically at login?');\n log('(You can skip this and set it up later with: vo-mcp runner --install-autostart)\\n');\n await installAutostart({ log, env });\n autostartInstalled = true;\n }\n }\n\n // Step 4: Guidance\n printNextSteps(log, autostartInstalled, opts.configOnly === true);\n}\n\nexport function installOptionsFromArgs(args: readonly string[]): InstallOptions {\n const configOnly = args.includes('--config-only');\n return configOnly\n ? { configOnly: true, skipLogin: true, skipAutostart: true }\n : {};\n}\n", "/**\n * Device-code pairing for the BYO runner (M1) \u2014 the no-terminal-token onboarding.\n *\n * The runner calls the control-plane `pair/initiate`, shows the friend a short\n * `code` to type at `<dashboard>/pair`, then polls `pair/poll` with its SECRET\n * `poll_token` until the friend authorizes \u2014 at which point it receives a freshly\n * minted `vocred_` and stores it in the OS keychain (via writeStoredCredential).\n *\n * The friend's AI key NEVER flows through here \u2014 this only obtains the\n * control-plane credential the runner needs to claim THEIR tasks.\n */\nimport { hostname, platform } from 'node:os';\n\nimport { writeStoredCredential, type StoredCredential } from './credential-store.js';\n\nexport const DEFAULT_CONTROL_PLANE_URL = 'https://vo-control-plane-bzjphrajaq-uc.a.run.app';\nexport const DEFAULT_DASHBOARD_URL = 'https://algosuite.ai';\n\nexport interface RunPairingDeps {\n readonly env?: Record<string, string | undefined>;\n readonly log?: (message: string) => void;\n readonly fetchImpl?: typeof fetch;\n readonly sleep?: (ms: number) => Promise<void>;\n readonly now?: () => Date;\n /** Test seam: capture the stored credential instead of touching the real keychain. */\n readonly store?: (cred: StoredCredential, storedAtIso: string) => string;\n}\n\nexport interface PairingResult {\n readonly credentialPath: string;\n readonly expires_at: string;\n}\n\n/** ABCD-EFGH grouping for an 8-char code (easier to read aloud / type). */\nexport function formatPairingCode(code: string): string {\n return code.length === 8 ? `${code.slice(0, 4)}-${code.slice(4)}` : code;\n}\n\nasync function readJson(res: { json: () => Promise<unknown> }): Promise<Record<string, unknown>> {\n const body = await res.json().catch(() => ({}));\n return body && typeof body === 'object' ? (body as Record<string, unknown>) : {};\n}\n\n/**\n * Run the full pairing handshake. Resolves once a credential is stored; rejects\n * with a friendly message on expiry / consumption / fatal transport error.\n */\nexport async function runPairing(deps: RunPairingDeps = {}): Promise<PairingResult> {\n const env = deps.env ?? process.env;\n const log = deps.log ?? ((m: string) => console.error(m));\n const fetchImpl = deps.fetchImpl ?? fetch;\n const sleep = deps.sleep ?? ((ms: number) => new Promise<void>((r) => setTimeout(r, ms)));\n const now = deps.now ?? (() => new Date());\n const store = deps.store ?? ((cred: StoredCredential, iso: string) => writeStoredCredential(cred, iso, env));\n\n const controlPlaneUrl = env['VO_CONTROL_PLANE_URL']?.trim() || DEFAULT_CONTROL_PLANE_URL;\n const dashboardUrl = env['VO_DASHBOARD_URL']?.trim() || DEFAULT_DASHBOARD_URL;\n const deviceLabel = `${platform()} on ${hostname()}`.slice(0, 120);\n\n // 1. initiate \u2014 get a display code + a secret poll token.\n const initRes = await fetchImpl(`${controlPlaneUrl}/api/v1/pair/initiate`, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ device_label: deviceLabel }),\n });\n if (!initRes.ok) throw new Error(`Could not start pairing (server ${initRes.status}).`);\n const init = await readJson(initRes);\n const code = String(init['code'] ?? '');\n const pollToken = String(init['poll_token'] ?? '');\n if (!code || !pollToken) throw new Error('Pairing service returned an incomplete response.');\n const intervalMs = (Number(init['poll_interval_seconds']) || 5) * 1000;\n const expiresAtMs = new Date(String(init['expires_at'] ?? '')).getTime();\n\n // 2. show the friend what to do.\n log('');\n log(' To connect this runner, open this page in your browser:');\n log(` ${dashboardUrl}/pair`);\n log(' and enter this code:');\n log('');\n log(` ${formatPairingCode(code)}`);\n log('');\n log(' Your Anthropic key never leaves this computer. Waiting for you to authorize\u2026');\n\n // 3. poll with the SECRET token until authorized / expired.\n for (;;) {\n if (Number.isFinite(expiresAtMs) && now().getTime() >= expiresAtMs) {\n throw new Error('The pairing code expired before it was authorized. Run `vo-mcp pair` again.');\n }\n await sleep(intervalMs);\n const pollRes = await fetchImpl(`${controlPlaneUrl}/api/v1/pair/poll`, {\n method: 'GET',\n headers: { 'x-vo-poll-token': pollToken },\n });\n if (pollRes.status === 404) {\n throw new Error('The pairing expired. Run `vo-mcp pair` again.');\n }\n if (pollRes.status === 410) {\n throw new Error('This code was already used. Run `vo-mcp pair` again.');\n }\n if (!pollRes.ok) {\n // Transient (rate limit / blip) \u2014 keep waiting.\n continue;\n }\n const body = await readJson(pollRes);\n if (body['status'] === 'pending') continue;\n if (body['status'] === 'authorized' && typeof body['vo_credential'] === 'string') {\n const credentialPath = store(\n {\n vo_credential: body['vo_credential'] as string,\n ...(typeof body['expires_at'] === 'string'\n ? { vo_credential_expires_at: body['expires_at'] as string }\n : {}),\n },\n now().toISOString(),\n );\n return { credentialPath, expires_at: String(body['expires_at'] ?? '') };\n }\n throw new Error('Unexpected response from the pairing service.');\n }\n}\n", "/**\n * Local credential store for the thin-client `vo-mcp login` flow (Increment 3b,\n * Option A \u2014 `docs/vo/vo-command-center-inc3b-login-design-2026-06-05.md`).\n *\n * Persists the per-user Firebase refresh token (the user's OWN credential, never\n * the god-token, never model keys) captured by `login`, so the auto-refreshing\n * token source (Inc 3a) can mint fresh ID tokens across MCP restarts.\n *\n * Storage precedence (Inc 3b.3):\n * 1. **OS keychain** (Windows Credential Manager / macOS Keychain / libsecret)\n * via the optional `@napi-rs/keyring` backend (`keychain.ts`). The DEFAULT\n * when available \u2014 the secret never lands in plaintext on disk.\n * 2. **0600 file** at `$VO_MCP_CREDENTIALS_PATH` or `~/.config/vo-mcp/credentials.json`.\n * The fallback when the keychain is unavailable or disabled\n * (`VO_MCP_DISABLE_KEYCHAIN`). `VO_MCP_CREDENTIALS_PATH` only sets the file\n * LOCATION; force file storage with `VO_MCP_DISABLE_KEYCHAIN`.\n *\n * `env`-supplied tokens (`VO_USER_REFRESH_TOKEN`, etc.) still win over BOTH\n * stores \u2014 that precedence lives upstream in `auth-token-source.ts`.\n *\n * **Single source of truth.** The credential lives in EITHER the keychain OR the\n * file, never both: a write to one store CLEARS the other, so a stale entry can\n * never shadow the current credential on read, and the secret never lingers in\n * plaintext after a migration to the keychain.\n *\n * **Keychain durability.** A keychain-stored credential is only readable while\n * the `@napi-rs/keyring` native module loads. If the module later becomes\n * unavailable (an ABI break across a Node upgrade, a corrupted install), the\n * credential can't be read and the user re-runs `vo-mcp login` \u2014 the same\n * behaviour as `gh` / `gcloud` / `firebase` keychain storage. We deliberately do\n * NOT mirror the secret to a plaintext file as a fallback: that would defeat the\n * entire point of keychain storage (keeping the secret off plaintext disk).\n */\nimport { homedir } from 'node:os';\nimport { join, dirname } from 'node:path';\nimport {\n existsSync,\n mkdirSync,\n readFileSync,\n writeFileSync,\n chmodSync,\n rmSync,\n} from 'node:fs';\n\nimport { keychainAvailable, keychainGet, keychainSet, keychainDelete } from './keychain.js';\n\nexport interface StoredCredential {\n /**\n * Firebase refresh token (long-lived; exchanged for short-lived ID tokens).\n * OPTIONAL since Inc 3b.4b: once a scoped `vo_credential` is minted, the raw\n * refresh token is dropped, so a stored credential may carry ONLY the vocred_.\n */\n readonly refresh_token?: string;\n /** Firebase Web API key (PUBLIC) needed for the securetoken refresh exchange. */\n readonly api_key?: string;\n /**\n * Scoped, revocable VO credential (`vocred_`) minted by the control-plane\n * (Inc 3b.4b). Preferred over the raw refresh token; lets the client present a\n * revocable, server-side credential instead of the Firebase refresh token.\n */\n readonly vo_credential?: string;\n /** ISO-8601 expiry of `vo_credential` (the client re-logs-in past this). */\n readonly vo_credential_expires_at?: string;\n /** The signed-in operator email (diagnostics only). */\n readonly email?: string;\n /** ISO timestamp the credential was stored. */\n readonly stored_at?: string;\n}\n\n/**\n * Pluggable OS-keychain backend. Defaults to the real `@napi-rs/keyring` wrapper;\n * tests inject a deterministic fake so they never touch the host keychain.\n */\nexport interface KeychainBackend {\n available(): boolean;\n get(): string | null;\n set(secret: string): boolean;\n delete(): boolean;\n}\n\nconst realKeychain: KeychainBackend = {\n available: keychainAvailable,\n get: keychainGet,\n set: keychainSet,\n delete: keychainDelete,\n};\n\n/** Human-readable \"location\" returned when the credential was stored in the OS keychain. */\nexport const KEYCHAIN_LOCATION = 'OS keychain (service \"vo-mcp\")';\n\n/** Resolve the credentials file path (env override \u2192 XDG-ish default under home). */\nexport function credentialPath(env: Readonly<Record<string, string | undefined>> = process.env): string {\n const override = env['VO_MCP_CREDENTIALS_PATH']?.trim();\n if (override) return override;\n return join(homedir(), '.config', 'vo-mcp', 'credentials.json');\n}\n\n/**\n * Whether the keychain should be consulted at all (read OR write). False when the\n * native backend is unavailable or `VO_MCP_DISABLE_KEYCHAIN` is set (CI/headless).\n */\nfunction keychainEnabled(\n env: Readonly<Record<string, string | undefined>>,\n keychain: KeychainBackend,\n): boolean {\n const disabled = (env['VO_MCP_DISABLE_KEYCHAIN'] ?? '').trim().toLowerCase();\n if (disabled === '1' || disabled === 'true' || disabled === 'yes') return false;\n return keychain.available();\n}\n\n/** Parse + validate a stored credential blob. Returns null on any problem (never throws). */\nfunction deserialize(raw: string): StoredCredential | null {\n try {\n const parsed = JSON.parse(raw) as Partial<StoredCredential>;\n const refresh = typeof parsed.refresh_token === 'string' ? parsed.refresh_token.trim() : '';\n const apiKey = typeof parsed.api_key === 'string' ? parsed.api_key.trim() : '';\n const voCred = typeof parsed.vo_credential === 'string' ? parsed.vo_credential.trim() : '';\n // Valid if it carries a scoped vocred_ OR a full Firebase refresh pair.\n if (!voCred && (!refresh || !apiKey)) return null;\n return {\n ...(refresh ? { refresh_token: refresh } : {}),\n ...(apiKey ? { api_key: apiKey } : {}),\n ...(voCred ? { vo_credential: voCred } : {}),\n ...(typeof parsed.vo_credential_expires_at === 'string' ? { vo_credential_expires_at: parsed.vo_credential_expires_at } : {}),\n ...(typeof parsed.email === 'string' ? { email: parsed.email } : {}),\n ...(typeof parsed.stored_at === 'string' ? { stored_at: parsed.stored_at } : {}),\n };\n } catch {\n return null;\n }\n}\n\nfunction readFromFile(env: Readonly<Record<string, string | undefined>>): StoredCredential | null {\n try {\n const p = credentialPath(env);\n if (!existsSync(p)) return null;\n return deserialize(readFileSync(p, 'utf8'));\n } catch {\n return null;\n }\n}\n\n/**\n * Read the stored credential, or `null` if absent/unreadable/invalid (never\n * throws). Consults an ENABLED keychain first (regardless of the write-target\n * flags, so a credential written to the keychain is found even if\n * `VO_MCP_CREDENTIALS_PATH` is later set), then the 0600 file.\n */\nexport function readStoredCredential(\n env: Readonly<Record<string, string | undefined>> = process.env,\n keychain: KeychainBackend = realKeychain,\n): StoredCredential | null {\n if (keychainEnabled(env, keychain)) {\n const raw = keychain.get();\n const fromKeychain = raw ? deserialize(raw) : null;\n if (fromKeychain) return fromKeychain;\n }\n return readFromFile(env);\n}\n\n/** Read only the OS keychain; never fall back to env-selected plaintext files. */\nexport function readStoredCredentialKeychainOnly(\n env: Readonly<Record<string, string | undefined>> = process.env,\n keychain: KeychainBackend = realKeychain,\n): StoredCredential | null {\n if (!keychainEnabled(env, keychain)) return null;\n const raw = keychain.get();\n return raw ? deserialize(raw) : null;\n}\n\nfunction deleteFile(env: Readonly<Record<string, string | undefined>>): void {\n try {\n rmSync(credentialPath(env), { force: true });\n } catch {\n /* best-effort */\n }\n}\n\nfunction writeToFile(\n payload: StoredCredential,\n env: Readonly<Record<string, string | undefined>>,\n): string {\n const p = credentialPath(env);\n mkdirSync(dirname(p), { recursive: true });\n writeFileSync(p, `${JSON.stringify(payload, null, 2)}\\n`, { mode: 0o600 });\n // Best-effort tighten (no-op / throws on some Windows filesystems \u2014 ignore).\n try {\n chmodSync(p, 0o600);\n } catch {\n /* best-effort */\n }\n return p;\n}\n\n/**\n * Persist the credential. Prefers the OS keychain (secret never hits plaintext\n * disk); otherwise writes the 0600 file. Writing to one store CLEARS the other\n * (single source of truth \u2014 no stale shadow, no lingering plaintext). Returns the\n * location it was stored (`KEYCHAIN_LOCATION` or the file path).\n */\nexport function writeStoredCredential(\n cred: StoredCredential,\n storedAt: string,\n env: Readonly<Record<string, string | undefined>> = process.env,\n keychain: KeychainBackend = realKeychain,\n): string {\n const payload: StoredCredential = {\n ...(cred.refresh_token ? { refresh_token: cred.refresh_token } : {}),\n ...(cred.api_key ? { api_key: cred.api_key } : {}),\n ...(cred.vo_credential ? { vo_credential: cred.vo_credential } : {}),\n ...(cred.vo_credential_expires_at ? { vo_credential_expires_at: cred.vo_credential_expires_at } : {}),\n ...(cred.email ? { email: cred.email } : {}),\n stored_at: cred.stored_at ?? storedAt,\n };\n if (keychainEnabled(env, keychain) && keychain.set(JSON.stringify(payload))) {\n // Stored in the keychain \u2192 clear any stale plaintext file so the secret\n // doesn't linger on disk and can't shadow the keychain on read.\n deleteFile(env);\n return KEYCHAIN_LOCATION;\n }\n const p = writeToFile(payload, env);\n // Stored in the file \u2192 clear any stale keychain entry so it can't shadow the\n // newer file credential on read.\n if (keychainEnabled(env, keychain)) keychain.delete();\n return p;\n}\n", "/**\n * Optional OS-keychain backend for the thin-client credential store (Increment\n * 3b.3 \u2014 `docs/vo/vo-command-center-inc3b-login-design-2026-06-05.md` \u00A75/\u00A76).\n *\n * Loads `@napi-rs/keyring` at runtime via `createRequire`, so it is a TRUE\n * optional dependency: if the native module is absent or fails to load\n * (unsupported platform, prebuilt binary missing, headless CI), every function\n * degrades to a no-op and the caller (`credential-store.ts`) falls back to the\n * 0600 file store. `@napi-rs/keyring`'s `Entry` API is SYNCHRONOUS, so the\n * credential store stays synchronous \u2014 no async ripple into the Inc-3a token\n * source that reads it.\n *\n * Why `createRequire` and not a static/dynamic `import`: a static import would\n * make the native module a HARD dependency (a missing prebuilt would crash the\n * MCP at startup); a dynamic `import()` is async (would force the whole read\n * path async). `createRequire(...)` inside a try/catch loads it lazily and\n * synchronously, and a load failure is just \"keychain unavailable\".\n */\nimport { createRequire } from 'node:module';\n\n/** Keychain service + account the single refresh credential is stored under. */\nconst SERVICE = 'vo-mcp';\nconst ACCOUNT = 'refresh-credential';\n\ninterface KeyringEntry {\n getPassword(): string | null;\n setPassword(password: string): void;\n deletePassword(): boolean;\n}\ninterface KeyringModule {\n Entry: new (service: string, account: string) => KeyringEntry;\n}\n\n// undefined = not yet attempted; null = attempted and unavailable.\nlet cached: KeyringModule | null | undefined;\n\nfunction loadKeyring(): KeyringModule | null {\n if (cached !== undefined) return cached;\n try {\n const req = createRequire(import.meta.url);\n const mod = req('@napi-rs/keyring') as Partial<KeyringModule>;\n cached = mod && typeof mod.Entry === 'function' ? (mod as KeyringModule) : null;\n } catch {\n cached = null;\n }\n return cached;\n}\n\n/** True when the OS keychain backend is usable in this runtime. */\nexport function keychainAvailable(): boolean {\n return loadKeyring() !== null;\n}\n\n/** Read the raw stored secret string from the OS keychain, or null. Never throws. */\nexport function keychainGet(): string | null {\n const k = loadKeyring();\n if (!k) return null;\n try {\n return new k.Entry(SERVICE, ACCOUNT).getPassword();\n } catch {\n return null;\n }\n}\n\n/** Store the raw secret string in the OS keychain. Returns true on success. Never throws. */\nexport function keychainSet(secret: string): boolean {\n const k = loadKeyring();\n if (!k) return false;\n try {\n new k.Entry(SERVICE, ACCOUNT).setPassword(secret);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Delete the stored secret from the OS keychain. Returns true if an entry was\n * removed. Never throws \u2014 a no-op (and `false`) when the backend is unavailable\n * or the entry is absent. Used to keep ONE source of truth: when the credential\n * is (re)written to the file, any stale keychain entry is cleared so it can't\n * shadow the newer file credential on read (and vice-versa).\n */\nexport function keychainDelete(): boolean {\n const k = loadKeyring();\n if (!k) return false;\n try {\n return new k.Entry(SERVICE, ACCOUNT).deletePassword();\n } catch {\n return false;\n }\n}\n\n/** Test-only seam to reset the memoised module load. */\nexport function __resetKeychainCache(): void {\n cached = undefined;\n}\n", "import { copyFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\n\nconst MANAGED_BEGIN = '# BEGIN AlgoHQ MCP (managed by vo-mcp install)';\nconst MANAGED_END = '# END AlgoHQ MCP (managed by vo-mcp install)';\nconst MANAGED_SERVER_NAMES = new Set(['algohq', 'vo', 'vo-mcp', 'vo_mcp']);\n\ninterface TableSection {\n readonly path: readonly string[];\n readonly start: number;\n readonly end: number;\n}\n\nexport function resolveCodexConfigPath(home: string): string {\n return join(home, '.codex', 'config.toml');\n}\n\nfunction normalizeKey(value: string): string {\n const trimmed = value.trim();\n if ((trimmed.startsWith('\"') && trimmed.endsWith('\"')) ||\n (trimmed.startsWith(\"'\") && trimmed.endsWith(\"'\"))) {\n return trimmed.slice(1, -1);\n }\n return trimmed;\n}\n\nfunction tablePath(line: string): string[] | null {\n const match = /^\\s*\\[([^\\r\\n]+)\\]\\s*(?:#.*)?$/.exec(line);\n const rawPath = match?.[1];\n if (!rawPath || rawPath.includes('[') || rawPath.includes(']')) return null;\n return rawPath.split('.').map(normalizeKey);\n}\n\nfunction tableSections(lines: readonly string[]): TableSection[] {\n const starts: Array<{ path: string[]; start: number }> = [];\n for (let index = 0; index < lines.length; index += 1) {\n const path = tablePath(lines[index] ?? '');\n if (path) starts.push({ path, start: index });\n }\n return starts.map((section, index) => ({\n ...section,\n end: starts[index + 1]?.start ?? lines.length,\n }));\n}\n\nfunction isManagedSection(section: TableSection): boolean {\n return section.path[0] === 'mcp_servers' && MANAGED_SERVER_NAMES.has(section.path[1] ?? '');\n}\n\nfunction assignmentKey(line: string): string | null {\n const match = /^\\s*((?:[A-Za-z0-9_-]+)|(?:\"[^\"]+\")|(?:'[^']+'))\\s*=/.exec(line);\n return match?.[1] ? normalizeKey(match[1]) : null;\n}\n\nfunction isStructurallySafeToml(raw: string): boolean {\n const lines = raw.split(/\\r?\\n/);\n const beginIndexes = lines.flatMap((line, index) => line.trim() === MANAGED_BEGIN ? [index] : []);\n const endIndexes = lines.flatMap((line, index) => line.trim() === MANAGED_END ? [index] : []);\n if (beginIndexes.length !== endIndexes.length || beginIndexes.length > 1) return false;\n if (beginIndexes[0] !== undefined && (endIndexes[0] ?? -1) <= beginIndexes[0]) return false;\n\n for (const line of lines) {\n const trimmed = line.trim();\n // Do not attempt to parse user-owned TOML. That would reject valid constructs\n // such as multiline strings. We only require managed-table headers to be\n // complete enough for the surgical section editor below to identify safely.\n if (/^\\[\\[?mcp_servers(?:\\.|\\s|$)/.test(trimmed) && tablePath(line) === null) return false;\n }\n return true;\n}\n\nfunction tomlString(value: string): string {\n return JSON.stringify(value);\n}\n\nfunction preservedSectionLines(\n lines: readonly string[],\n section: TableSection | undefined,\n managedKeys: ReadonlySet<string>,\n): string[] {\n if (!section) return [];\n return lines\n .slice(section.start + 1, section.end)\n .filter((line) => {\n if (line.trim() === MANAGED_BEGIN || line.trim() === MANAGED_END) return false;\n const key = assignmentKey(line);\n return key === null || !managedKeys.has(key);\n })\n .filter((line, index, all) => line.trim() !== '' || (index > 0 && index < all.length - 1));\n}\n\nexport function renderCodexMcpConfig(raw: string, cliPath: string, controlPlaneUrl: string): string {\n if (!isStructurallySafeToml(raw)) {\n throw new Error('Codex config is malformed; refusing to overwrite it');\n }\n\n const eol = raw.includes('\\r\\n') ? '\\r\\n' : '\\n';\n const lines = raw.split(/\\r?\\n/);\n const sections = tableSections(lines);\n const rootSections = sections.filter((section) => isManagedSection(section) && section.path.length === 2);\n const preferredRoot = rootSections.find((section) => section.path[1] === 'algohq') ?? rootSections[0];\n const preferredName = preferredRoot?.path[1];\n const envSection = sections.find((section) =>\n isManagedSection(section) && section.path[1] === preferredName && section.path[2] === 'env');\n const rootExtras = preservedSectionLines(lines, preferredRoot, new Set(['command', 'args', 'required']));\n const envExtras = preservedSectionLines(lines, envSection, new Set(['VO_CONTROL_PLANE_URL']));\n\n const removed = new Set<number>();\n const managedBegin = lines.findIndex((line) => line.trim() === MANAGED_BEGIN);\n const managedEnd = lines.findIndex((line) => line.trim() === MANAGED_END);\n if (managedBegin >= 0 && managedEnd >= managedBegin) {\n for (let index = managedBegin; index <= managedEnd; index += 1) removed.add(index);\n }\n for (const section of sections.filter(isManagedSection)) {\n for (let index = section.start; index < section.end; index += 1) removed.add(index);\n }\n\n const base = lines.filter((_line, index) => !removed.has(index)).join(eol).trimEnd();\n const block = [\n MANAGED_BEGIN,\n '[mcp_servers.algohq]',\n 'command = \"node\"',\n `args = [${tomlString(cliPath)}]`,\n 'required = true',\n ...rootExtras,\n '',\n '[mcp_servers.algohq.env]',\n `VO_CONTROL_PLANE_URL = ${tomlString(controlPlaneUrl)}`,\n ...envExtras,\n MANAGED_END,\n ].join(eol);\n return `${base}${base ? `${eol}${eol}` : ''}${block}${eol}`;\n}\n\nexport function installCodexMcpConfigAt(\n configPath: string,\n cliPath: string,\n controlPlaneUrl: string,\n log: (message: string) => void,\n): void {\n const exists = existsSync(configPath);\n const raw = exists ? readFileSync(configPath, 'utf8') : '';\n let rendered: string;\n try {\n rendered = renderCodexMcpConfig(raw, cliPath, controlPlaneUrl);\n } catch (error) {\n if (exists) {\n const backupPath = `${configPath}.backup-${Date.now()}`;\n copyFileSync(configPath, backupPath);\n log(` Backed up malformed Codex config \u2192 ${backupPath}`);\n }\n throw error;\n }\n if (rendered === raw) {\n log(` Codex already current: ${configPath}`);\n return;\n }\n if (exists) {\n const backupPath = `${configPath}.backup-${Date.now()}`;\n copyFileSync(configPath, backupPath);\n log(` Backed up Codex config \u2192 ${backupPath}`);\n }\n mkdirSync(dirname(configPath), { recursive: true });\n writeFileSync(configPath, rendered, 'utf8');\n log(`\u2713 Wrote AlgoHQ MCP to Codex: ${configPath}`);\n}\n", "/**\n * Cross-platform auto-start registration for `vo-mcp runner`.\n *\n * WINDOWS: Uses the user Startup folder, NOT Task Scheduler. Headless\n * `claude -p` (which the runner spawns) HANGS under the Task Scheduler\n * service session \u2014 it only runs from an interactive, Explorer-descended\n * session. The Startup folder launches the runner HIDDEN at user login via a\n * .vbs shim (wscript is windowless; a .cmd launcher always parks a console on\n * the taskbar \u2014 `start /min` minimizes, it does not hide).\n *\n * MACOS: Uses ~/Library/LaunchAgents (launchd) with RunAtLoad + KeepAlive.\n *\n * LINUX: Uses ~/.config/systemd/user (systemd user unit) with Restart=on-failure;\n * ExecStart runs via a login shell so the npm-global `vo-mcp` resolves on PATH.\n *\n * All operations are idempotent and create backups where applicable.\n */\nimport { homedir, platform } from 'node:os';\nimport { isAbsolute, join } from 'node:path';\nimport { existsSync, mkdirSync, writeFileSync, readFileSync, unlinkSync, copyFileSync } from 'node:fs';\n\nexport interface AutostartOptions {\n readonly log?: (msg: string) => void;\n readonly runnerCommand?: string; // Override for tests\n readonly env?: Readonly<Record<string, string | undefined>>;\n /**\n * Override the detected platform. Injectable ONLY so the Windows branch can be\n * exercised on a Linux CI runner \u2014 every Windows assertion in autostart.test.ts\n * used to early-return on ubuntu-latest, so no Windows autostart behaviour was\n * verified anywhere.\n */\n readonly platform?: NodeJS.Platform;\n}\n\n/**\n * Base restart backoff for the Windows keepalive loop \u2014 short enough that a real\n * crash recovers well within a heartbeat interval.\n */\nconst WINDOWS_RESTART_BACKOFF_MS = 10_000;\n\n/**\n * A run lasting at least this long counts as HEALTHY and resets the backoff.\n * Anything shorter is treated as a fast-fail and doubles the wait.\n */\nconst WINDOWS_HEALTHY_RUN_MS = 60_000;\n\n/**\n * Ceiling for the escalating backoff. Without one, a permanently broken runner\n * (missing credential, bad install) would relaunch every 10s forever \u2014 ~8,600\n * restarts a day, each appending to vo-runner.log. That is a disk-fill risk on a\n * machine nobody is watching, which is the whole premise here. launchd throttles\n * to a 10s floor and systemd has StartLimitBurst for the same reason.\n */\nconst WINDOWS_MAX_BACKOFF_MS = 300_000;\n\n/**\n * Resolve the path to the vo-mcp runner command. Defaults to 'vo-mcp runner'\n * (assumes it's in PATH). Can be overridden for tests.\n */\nfunction resolveRunnerCommand(override?: string): string {\n return override ?? 'vo-mcp runner';\n}\n\n/** Preserve one command string as a single POSIX shell argument. */\nfunction quotePosixShellArgument(value: string): string {\n if (value.includes('\\u0000') || value.includes('\\r') || value.includes('\\n')) {\n throw new Error('Runner command must not contain NUL, carriage return, or newline characters.');\n }\n return `'${value.replace(/'/gu, `'\"'\"'`)}'`;\n}\n\n/**\n * Resolve the freedesktop config root used by both the systemd user unit and\n * the runner's managed clone directory. XDG_CONFIG_HOME is valid only when it\n * is absolute; a relative value falls back to the documented ~/.config root.\n */\nfunction resolveLinuxConfigHome(\n home: string,\n env: Readonly<Record<string, string | undefined>>,\n): string {\n const configured = env['XDG_CONFIG_HOME']?.trim();\n return configured && isAbsolute(configured) ? configured : join(home, '.config');\n}\n\n/**\n * A managed launcher is current only when every byte matches the template.\n * Matching the command substring cannot distinguish an up-to-date launcher\n * from an older broken version that happens to invoke the same command.\n */\nfunction launcherIsCurrent(\n path: string,\n desiredContent: string,\n label: string,\n log: (msg: string) => void,\n): boolean {\n if (!existsSync(path)) return false;\n if (readFileSync(path, 'utf8') === desiredContent) return true;\n const backupPath = `${path}.backup-${Date.now()}`;\n copyFileSync(path, backupPath);\n log(` Backed up existing ${label} to: ${backupPath}`);\n return false;\n}\n\n/**\n * Windows: Install a launcher script in the Startup folder.\n *\n * Creates a .vbs file that starts `vo-mcp runner` with a hidden window\n * (WScript.Shell.Run window style 0 \u2014 wscript itself never shows a window,\n * unlike a .cmd whose console `start /min` only minimizes). The Startup\n * folder is %APPDATA%\\Microsoft\\Windows\\Start Menu\\Programs\\Startup\\.\n */\nfunction installWindowsAutostart(runnerCommand: string, log: (msg: string) => void, env: Readonly<Record<string, string | undefined>>): void {\n const appData = env['APPDATA'] ?? join(homedir(), 'AppData', 'Roaming');\n const startupDir = join(appData, 'Microsoft', 'Windows', 'Start Menu', 'Programs', 'Startup');\n mkdirSync(startupDir, { recursive: true });\n\n const launcherPath = join(startupDir, 'vo-runner.vbs');\n const legacyCmdPath = join(startupDir, 'vo-runner.cmd');\n\n // Migrate: drop the pre-.vbs minimized launcher so logon can't start two runners.\n // Best-effort \u2014 an ACL-blocked/locked .cmd must not prevent installing the .vbs.\n if (existsSync(legacyCmdPath)) {\n try {\n unlinkSync(legacyCmdPath);\n log(` Removed legacy minimized .cmd launcher: ${legacyCmdPath}`);\n } catch (error) {\n log(`\u26A0 Could not remove legacy launcher ${legacyCmdPath} (${error instanceof Error ? error.message : String(error)}); remove it manually to avoid a double start`);\n }\n }\n\n // Write the launcher. VBS escapes embedded double quotes by doubling them.\n // The hidden window discards stdio, so redirect the runner's output to the\n // same log file the macOS plist and Linux unit use \u2014 otherwise every\n // [orphan-sweep]/[orphan-reaper] warning on Windows lands nowhere.\n const hiddenCommand = `cmd /c ${runnerCommand} >> \"%USERPROFILE%\\\\.claude\\\\vo-runner.log\" 2>&1`.replace(/\"/g, '\"\"');\n // KEEPALIVE. Windows was the ONLY platform with no restart supervision: macOS\n // sets launchd `KeepAlive`, Linux sets systemd `Restart=on-failure`, and this\n // was `.Run(..., 0, False)` \u2014 fire-and-forget. If the runner died mid-session\n // nothing restarted it until the next logon, which is why a Windows host could\n // sit dead for hours (2026-07-25) with no way to reach it.\n //\n // `True` makes .Run WAIT for the process, turning this into a supervisor loop.\n // The sleep is a restart backoff so a runner failing instantly cannot spin hot.\n //\n // The stop-sentinel is the escape hatch: wscript has no console, so without it\n // the only way to stop the loop is Task Manager. The file is CONSUMED (deleted)\n // once honoured, so a later logon starts clean instead of silently refusing.\n const launcherContent = `' Auto-start launcher for vo-mcp runner\n' Created by vo-mcp autostart installer\n' Keepalive supervisor: restarts the runner if it exits (parity with launchd\n' KeepAlive on macOS and systemd Restart=on-failure on Linux).\n' To stop: create %USERPROFILE%\\\\.claude\\\\vo-runner.stop, or end wscript.exe.\nDim sh, fso, stopFile, backoff, startedAt, ranMs\nSet sh = CreateObject(\"WScript.Shell\")\nSet fso = CreateObject(\"Scripting.FileSystemObject\")\nsh.CurrentDirectory = sh.ExpandEnvironmentStrings(\"%USERPROFILE%\")\nsh.Environment(\"Process\")(\"VO_CODE_RUNNER_CLONES_ROOT\") = sh.ExpandEnvironmentStrings(\"%APPDATA%\\\\ai.algosuite.vo-runner\\\\clones\")\nstopFile = sh.ExpandEnvironmentStrings(\"%USERPROFILE%\\\\.claude\\\\vo-runner.stop\")\nbackoff = ${WINDOWS_RESTART_BACKOFF_MS}\nDo\n If fso.FileExists(stopFile) Then\n fso.DeleteFile stopFile\n WScript.Quit 0\n End If\n startedAt = Timer\n sh.Run \"${hiddenCommand}\", 0, True\n ranMs = (Timer - startedAt) * 1000\n If ranMs < 0 Then ranMs = ${WINDOWS_HEALTHY_RUN_MS}\n If ranMs >= ${WINDOWS_HEALTHY_RUN_MS} Then\n backoff = ${WINDOWS_RESTART_BACKOFF_MS}\n ElseIf backoff < ${WINDOWS_MAX_BACKOFF_MS} Then\n backoff = backoff * 2\n End If\n WScript.Sleep backoff\nLoop\n`;\n\n if (launcherIsCurrent(launcherPath, launcherContent, 'launcher', log)) {\n log(`\u2713 Auto-start is already configured (Windows Startup folder)`);\n log(` Path: ${launcherPath}`);\n return;\n }\n\n writeFileSync(launcherPath, launcherContent, 'utf8');\n log(`\u2713 Installed Windows auto-start launcher`);\n log(` Path: ${launcherPath}`);\n log(` The runner will start hidden at next login.`);\n}\n\n/**\n * Windows: Uninstall the Startup folder launcher.\n */\nfunction uninstallWindowsAutostart(log: (msg: string) => void, env: Readonly<Record<string, string | undefined>>): void {\n const appData = env['APPDATA'] ?? join(homedir(), 'AppData', 'Roaming');\n const startupDir = join(appData, 'Microsoft', 'Windows', 'Start Menu', 'Programs', 'Startup');\n // Remove the current .vbs launcher AND any legacy .cmd from older installs.\n const launcherPaths = [join(startupDir, 'vo-runner.vbs'), join(startupDir, 'vo-runner.cmd')];\n\n let removedAny = false;\n for (const launcherPath of launcherPaths) {\n if (!existsSync(launcherPath)) continue;\n unlinkSync(launcherPath);\n removedAny = true;\n log(`\u2713 Removed Windows auto-start launcher`);\n log(` Path: ${launcherPath}`);\n }\n if (!removedAny) {\n log(`\u2713 Auto-start launcher not found (already removed)`);\n }\n}\n\n/**\n * macOS: Install a launchd plist in ~/Library/LaunchAgents.\n *\n * The plist runs `vo-mcp runner` at login with RunAtLoad=true and\n * KeepAlive=true (restarts if it crashes).\n */\nasync function installMacAutostart(\n runnerCommand: string,\n log: (msg: string) => void,\n env: Readonly<Record<string, string | undefined>>,\n): Promise<void> {\n const home = env['HOME']?.trim() || homedir();\n const launchAgentsDir = join(home, 'Library', 'LaunchAgents');\n mkdirSync(launchAgentsDir, { recursive: true });\n\n const plistPath = join(launchAgentsDir, 'ai.algosuite.vo-runner.plist');\n\n // Parse the runner command into program + args for launchd\n const parts = runnerCommand.split(/\\s+/);\n const program = parts[0] ?? 'vo-mcp';\n const args = parts.length > 1 ? parts.slice(1) : ['runner'];\n\n const plistContent = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n <key>Label</key>\n <string>ai.algosuite.vo-runner</string>\n <key>ProgramArguments</key>\n <array>\n <string>${program}</string>\n${args.map((a) => ` <string>${a}</string>`).join('\\n')}\n </array>\n <key>RunAtLoad</key>\n <true/>\n <key>KeepAlive</key>\n <true/>\n <key>WorkingDirectory</key>\n <string>${home}</string>\n <key>EnvironmentVariables</key>\n <dict>\n <key>VO_CODE_RUNNER_CLONES_ROOT</key>\n <string>${join(home, 'Library', 'Application Support', 'ai.algosuite.vo-runner', 'clones')}</string>\n </dict>\n <key>StandardOutPath</key>\n <string>${join(home, '.claude', 'vo-runner.log')}</string>\n <key>StandardErrorPath</key>\n <string>${join(home, '.claude', 'vo-runner-error.log')}</string>\n</dict>\n</plist>\n`;\n\n if (launcherIsCurrent(plistPath, plistContent, 'plist', log)) {\n log(`\u2713 Auto-start is already configured (launchd)`);\n log(` Path: ${plistPath}`);\n return;\n }\n\n writeFileSync(plistPath, plistContent, 'utf8');\n log(`\u2713 Installed launchd plist`);\n log(` Path: ${plistPath}`);\n\n // Load the plist with launchctl\n try {\n const { execSync } = await import('node:child_process');\n execSync(`launchctl load \"${plistPath}\"`, { stdio: 'ignore' });\n log(`\u2713 Loaded plist with launchctl (runner will start at next login)`);\n log(` Logs: ${join(home, '.claude', 'vo-runner.log')}`);\n } catch {\n log(`\u26A0 Failed to load plist with launchctl (you may need to load it manually)`);\n log(` Run: launchctl load \"${plistPath}\"`);\n }\n}\n\n/**\n * macOS: Uninstall the launchd plist.\n */\nasync function uninstallMacAutostart(\n log: (msg: string) => void,\n env: Readonly<Record<string, string | undefined>>,\n): Promise<void> {\n const home = env['HOME']?.trim() || homedir();\n const launchAgentsDir = join(home, 'Library', 'LaunchAgents');\n const plistPath = join(launchAgentsDir, 'ai.algosuite.vo-runner.plist');\n\n if (!existsSync(plistPath)) {\n log(`\u2713 Auto-start plist not found (already removed)`);\n return;\n }\n\n // Unload the plist with launchctl\n try {\n const { execSync } = await import('node:child_process');\n execSync(`launchctl unload \"${plistPath}\"`, { stdio: 'ignore' });\n log(`\u2713 Unloaded plist with launchctl`);\n } catch {\n log(`\u26A0 Failed to unload plist with launchctl (continuing anyway)`);\n }\n\n unlinkSync(plistPath);\n log(`\u2713 Removed launchd plist`);\n log(` Path: ${plistPath}`);\n}\n\n/**\n * Linux: Install a systemd USER unit at\n * $XDG_CONFIG_HOME/systemd/user/vo-runner.service (default ~/.config),\n * then enable + start it (`systemctl --user enable --now`). Restart=on-failure\n * mirrors the macOS KeepAlive. ExecStart runs via a login shell so the npm-global\n * `vo-mcp` resolves under systemd's minimal PATH.\n */\nasync function installLinuxAutostart(\n runnerCommand: string,\n log: (msg: string) => void,\n env: Readonly<Record<string, string | undefined>>,\n): Promise<void> {\n const home = env['HOME']?.trim() || homedir();\n const configHome = resolveLinuxConfigHome(home, env);\n const unitDir = join(configHome, 'systemd', 'user');\n mkdirSync(unitDir, { recursive: true });\n const unitPath = join(unitDir, 'vo-runner.service');\n\n const logFile = join(home, '.claude', 'vo-runner.log');\n const errFile = join(home, '.claude', 'vo-runner-error.log');\n const quotedRunnerCommand = quotePosixShellArgument(runnerCommand);\n mkdirSync(join(home, '.claude'), { recursive: true });\n\n const unit = `[Unit]\nDescription=AlgoHQ Code Runner (vo-mcp)\nAfter=network-online.target\nWants=network-online.target\n\n[Service]\nType=simple\nWorkingDirectory=${home}\nEnvironment=\"VO_CODE_RUNNER_CLONES_ROOT=${join(configHome, 'ai.algosuite.vo-runner', 'clones')}\"\nExecStart=/bin/sh -lc ${quotedRunnerCommand}\nRestart=on-failure\nRestartSec=10\nStandardOutput=append:${logFile}\nStandardError=append:${errFile}\n\n[Install]\nWantedBy=default.target\n`;\n if (launcherIsCurrent(unitPath, unit, 'unit', log)) {\n log(`\u2713 Auto-start is already configured (systemd user unit)`);\n log(` Path: ${unitPath}`);\n return;\n }\n writeFileSync(unitPath, unit, 'utf8');\n log(`\u2713 Installed systemd user unit`);\n log(` Path: ${unitPath}`);\n\n // In tests, write the unit but NEVER actually enable/start a real service.\n if (process.env['VITEST']) {\n log(` (test mode: skipping systemctl enable)`);\n return;\n }\n try {\n const { execSync } = await import('node:child_process');\n execSync('systemctl --user daemon-reload', { stdio: 'ignore' });\n execSync('systemctl --user enable --now vo-runner.service', { stdio: 'ignore' });\n log(`\u2713 Enabled + started vo-runner.service (starts at login)`);\n log(` Logs: ${logFile}`);\n } catch {\n log(`\u26A0 Could not enable via systemctl (enable it manually):`);\n log(` systemctl --user daemon-reload && systemctl --user enable --now vo-runner.service`);\n }\n}\n\n/**\n * Linux: Uninstall the systemd user unit.\n */\nasync function uninstallLinuxAutostart(\n log: (msg: string) => void,\n env: Readonly<Record<string, string | undefined>>,\n): Promise<void> {\n const home = env['HOME']?.trim() || homedir();\n const configHome = resolveLinuxConfigHome(home, env);\n const unitPath = join(configHome, 'systemd', 'user', 'vo-runner.service');\n if (!existsSync(unitPath)) {\n log(`\u2713 Auto-start unit not found (already removed)`);\n return;\n }\n if (!process.env['VITEST']) {\n try {\n const { execSync } = await import('node:child_process');\n execSync('systemctl --user disable --now vo-runner.service', { stdio: 'ignore' });\n log(`\u2713 Disabled + stopped vo-runner.service`);\n } catch {\n log(`\u26A0 Could not disable via systemctl (continuing anyway)`);\n }\n }\n unlinkSync(unitPath);\n log(`\u2713 Removed systemd user unit`);\n log(` Path: ${unitPath}`);\n}\n\n/**\n * Install auto-start for the runner daemon. Cross-platform.\n */\nexport async function installAutostart(opts: AutostartOptions = {}): Promise<void> {\n const log = opts.log ?? ((m: string) => console.error(m));\n const env = opts.env ?? process.env;\n const runnerCommand = resolveRunnerCommand(opts.runnerCommand);\n const plat = opts.platform ?? platform();\n\n if (plat === 'win32') {\n installWindowsAutostart(runnerCommand, log, env);\n } else if (plat === 'darwin') {\n await installMacAutostart(runnerCommand, log, env);\n } else if (plat === 'linux') {\n await installLinuxAutostart(runnerCommand, log, env);\n } else {\n log(`\u2717 Auto-start is not supported on platform: ${plat}`);\n log(` Supported platforms: win32 (Windows), darwin (macOS), linux (Linux)`);\n }\n}\n\n/**\n * Uninstall auto-start for the runner daemon. Cross-platform.\n */\nexport async function uninstallAutostart(opts: AutostartOptions = {}): Promise<void> {\n const log = opts.log ?? ((m: string) => console.error(m));\n const env = opts.env ?? process.env;\n const plat = opts.platform ?? platform();\n\n if (plat === 'win32') {\n uninstallWindowsAutostart(log, env);\n } else if (plat === 'darwin') {\n await uninstallMacAutostart(log, env);\n } else if (plat === 'linux') {\n await uninstallLinuxAutostart(log, env);\n } else {\n log(`\u2717 Auto-start is not supported on platform: ${plat}`);\n log(` Supported platforms: win32 (Windows), darwin (macOS), linux (Linux)`);\n }\n}\n", "#!/usr/bin/env node\n/**\n * `vo-mcp install` CLI entry point.\n *\n * Usage:\n * npx @algosuite/vo-mcp@beta install\n * vo-mcp install\n * vo-mcp install --config-only\n */\nimport { install, installOptionsFromArgs } from './install.js';\n\ninstall(installOptionsFromArgs(process.argv.slice(2))).catch((err: unknown) => {\n console.error('[vo-mcp install] fatal:', err);\n process.exit(1);\n});\n"],
5
- "mappings": "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",
6
- "names": ["homedir", "platform", "join", "dirname", "existsSync", "readFileSync", "writeFileSync", "mkdirSync", "copyFileSync", "credentialPath", "existsSync", "mkdirSync", "readFileSync", "writeFileSync", "dirname", "join", "homedir", "platform", "join", "existsSync", "mkdirSync", "writeFileSync", "readFileSync", "copyFileSync", "homedir", "join", "mkdirSync", "writeFileSync", "homedir", "join", "mkdirSync", "writeFileSync", "platform", "DEFAULT_CONTROL_PLANE_URL", "join", "existsSync", "readFileSync", "mkdirSync", "dirname", "writeFileSync", "copyFileSync", "homedir", "platform"]
3
+ "sources": ["../src/install.ts", "../src/cloud/pairing.ts", "../src/cloud/credential-store.ts", "../src/cloud/keychain.ts", "../src/codex-mcp-config.ts", "../src/config-backup.ts", "../src/mcp-launcher.ts", "../src/autostart.ts", "../src/install-cli.ts"],
4
+ "sourcesContent": ["/**\n * `vo-mcp install` \u2014 one-command client installer for non-coders.\n *\n * Configures Claude Desktop, Claude Code, and Codex to load vo-mcp; guides login; and\n * explains starting the runner. Cross-platform (Windows + macOS/Linux).\n *\n * Steps:\n * 1. Write/merge the MCP server config (backing up existing config).\n * 2. Pair via device code (`vo-mcp pair`) to mint the scoped credential \u2014 device\n * code (not loopback) so it works in every terminal (no 127.0.0.1 callback).\n * 3. Explain `vo-mcp runner` (not started here \u2014 user does it manually).\n * 4. Print clear next steps + success summary.\n */\nimport { homedir, platform } from 'node:os';\nimport { join, dirname } from 'node:path';\nimport { existsSync, readFileSync, mkdirSync, statSync } from 'node:fs';\nimport { fileURLToPath } from 'node:url';\nimport { runPairing } from './cloud/pairing.js';\nimport { installCodexMcpConfigAt, readCodexManagedEnv, resolveCodexConfigPath } from './codex-mcp-config.js';\nimport { MCP_FALLBACK_CLI_ENV, chooseFallbackCli, defaultRunnerRuntimeRoot, isStaleVoMcpEntry, writeMcpLauncher } from './mcp-launcher.js';\nimport { backupConfigOnce, writeFileAtomic } from './config-backup.js';\n\n/** Live vo-control-plane Cloud Run URL \u2014 explicit (was derived from the dashboard\n * URL by string-replace, which silently broke when that default changed). */\nconst DEFAULT_CONTROL_PLANE_URL = 'https://vo-control-plane-bzjphrajaq-uc.a.run.app';\nimport { installAutostart } from './autostart.js';\n\nexport interface InstallOptions {\n readonly log?: (msg: string) => void;\n readonly skipLogin?: boolean;\n readonly skipAutostart?: boolean;\n readonly configOnly?: boolean;\n readonly env?: Readonly<Record<string, string | undefined>>;\n}\n\ninterface McpServerEntry {\n command: string;\n args?: string[];\n env?: Record<string, string>;\n}\n\n/**\n * Resolve the Claude config path. Prefers Claude Code's `.claude.json` in the\n * user home, else Claude Desktop's `claude_desktop_config.json` in the platform\n * config directory.\n */\n/** Claude Code CLI config path (~/.claude.json). `home` is injectable for tests. */\nfunction resolveCodeConfigPath(home: string): string {\n return join(home, '.claude.json');\n}\n\n/** Claude Desktop app config path (per-OS). Linux uses capital-C 'Claude'. */\nfunction resolveDesktopConfigPath(home: string, plat: NodeJS.Platform, appData?: string): string {\n if (plat === 'win32') {\n return join(appData ?? join(home, 'AppData', 'Roaming'), 'Claude', 'claude_desktop_config.json');\n }\n if (plat === 'darwin') {\n return join(home, 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json');\n }\n // Linux / others \u2014 capital-C 'Claude' (matches the Claude Desktop app dir).\n return join(home, '.config', 'Claude', 'claude_desktop_config.json');\n}\n\ninterface ClaudeConfigRead {\n readonly kind: 'absent' | 'empty' | 'invalid' | 'ok';\n readonly config: Record<string, unknown>;\n /** mtime observed BEFORE the read (baseline for the changed-under-us guard); null when absent. */\n readonly mtimeMs: number | null;\n}\n\n/**\n * Read + parse an existing Claude config. Preserve the FULL config \u2014 Claude\n * Code's ~/.claude.json holds `projects`, history, etc., and Desktop holds\n * `preferences`; only mcpServers is ever touched. `invalid` (exists but not\n * parseable / not an object) must be left alone by every caller; `empty` (0 bytes\n * \u2014 a torn concurrent write, or a fresh file) is left alone by the unattended\n * heal but treated as absent by the explicit install. A UTF-8 BOM (Windows\n * PowerShell 5.1 `Set-Content -Encoding UTF8` writes one) is tolerated. The\n * baseline stat is taken BEFORE the read and re-checked after it, so a write that\n * lands mid-read is noticed rather than baselined.\n */\nfunction readClaudeConfig(path: string): ClaudeConfigRead {\n if (!existsSync(path)) return { kind: 'absent', config: {}, mtimeMs: null };\n for (let attempt = 0; attempt < 3; attempt += 1) {\n const before = statSync(path).mtimeMs;\n let raw: string;\n try {\n raw = readFileSync(path, 'utf8');\n } catch {\n return { kind: 'invalid', config: {}, mtimeMs: before };\n }\n if (!existsSync(path) || statSync(path).mtimeMs !== before) continue; // moved under the read \u2014 re-read\n const text = raw.replace(/^\\uFEFF/u, '');\n if (!text.trim()) return { kind: 'empty', config: {}, mtimeMs: before };\n try {\n const parsed = JSON.parse(text) as unknown;\n return parsed && typeof parsed === 'object' && !Array.isArray(parsed)\n ? { kind: 'ok', config: parsed as Record<string, unknown>, mtimeMs: before }\n : { kind: 'invalid', config: {}, mtimeMs: before };\n } catch {\n return { kind: 'invalid', config: {}, mtimeMs: before };\n }\n }\n return { kind: 'invalid', config: {}, mtimeMs: null }; // kept moving under three reads \u2014 leave it alone\n}\n\n/**\n * Write the Claude config atomically (temp + rename \u2014 Claude Code rewrites the\n * same file itself), creating parent directories as needed. 2-space indentation.\n */\nfunction writeClaudeConfig(path: string, config: Record<string, unknown>): void {\n mkdirSync(dirname(path), { recursive: true });\n writeFileAtomic(path, `${JSON.stringify(config, null, 2)}\\n`);\n}\n\n/**\n * Keys carried over from the MANAGED `vo-mcp` entry only (never from a legacy\n * `vo` server, whose transport keys \u2014 type:'sse', url, disabled\u2026 \u2014 would make the\n * healed entry unspawnable). Transport keys are carried only when they describe\n * a stdio server, which is what we write; command/args/env are always rebuilt.\n */\nfunction carriedEntryKeys(entry: McpServerEntry | undefined): Record<string, unknown> {\n if (!entry) return {};\n const { command: _c, args: _a, env: _e, type, url: _u, headers: _h, ...rest } = entry as unknown as Record<string, unknown>;\n const stdio = type === undefined || type === 'stdio';\n return { ...(stdio ? rest : {}), ...(type === 'stdio' ? { type } : {}) };\n}\n\n/** Keep an entry's existing `command` when it is a node executable (bootstrap installers write an ABSOLUTE node path for GUI hosts whose PATH lacks node). */\nfunction preferredNodeCommand(existing: string | undefined): string {\n const current = String(existing ?? '').trim();\n return current && /(^|[\\\\/])node(\\.exe)?$/iu.test(current) ? current : 'node';\n}\n\n/**\n * Resolve the absolute path to the vo-mcp CLI (dist/cli.js). Computes from\n * process.argv[1] which is the path to the currently running script\n * (dist/install-cli.js when invoked via `vo-mcp install`).\n */\nfunction resolveVoMcpCliPath(): string {\n // Resolve from this module, not process.argv[1]. When invoked as\n // `vo-mcp install`, argv[1] is the dispatcher under bin/; cli.js lives in dist/.\n return join(dirname(fileURLToPath(import.meta.url)), 'cli.js');\n}\n\n/**\n * Merge the vo-mcp MCP server entry into ONE config file. Preserves EVERY other\n * key (other mcpServers + top-level keys like Claude Code's `projects` or\n * Desktop's `preferences`) \u2014 only the `vo-mcp` entry is touched. Backs up first.\n * Idempotent: if `vo-mcp` already points at this cli.js, no-op.\n */\n/** How the launcher is registered. `sticky`/`onlyExisting` are the daemon-boot heal posture. */\ninterface LauncherOptions {\n readonly launcherPath: string | null;\n /** Keep an existing on-disk fallback instead of refreshing it to this cli.js. */\n readonly sticky: boolean;\n /** Never CREATE a config file \u2014 only re-point one that already exists. */\n readonly onlyExisting: boolean;\n}\nconst INSTALL_LAUNCHER: Omit<LauncherOptions, 'launcherPath'> = { sticky: false, onlyExisting: false };\nconst HEAL_LAUNCHER: Omit<LauncherOptions, 'launcherPath'> = { sticky: true, onlyExisting: true };\n\nfunction installMcpConfigAt(\n configPath: string,\n cliPath: string,\n controlPlaneUrl: string,\n log: (msg: string) => void,\n label: string,\n launcher: LauncherOptions = { launcherPath: null, ...INSTALL_LAUNCHER },\n): void {\n if (launcher.onlyExisting && !existsSync(configPath)) return;\n const read = readClaudeConfig(configPath);\n if (read.kind === 'invalid' || (read.kind === 'empty' && launcher.onlyExisting)) {\n log(` \u26A0 ${label} config is ${read.kind === 'empty' ? 'empty' : 'not valid JSON'} \u2014 left untouched: ${configPath}${read.kind === 'empty' ? '' : ' (fix or remove it, then re-run vo-mcp install)'}`);\n return;\n }\n const existing = read.config;\n const readMtime = read.mtimeMs;\n const mcpServers: Record<string, McpServerEntry> =\n existing['mcpServers'] && typeof existing['mcpServers'] === 'object'\n ? (existing['mcpServers'] as Record<string, McpServerEntry>)\n : {};\n\n // Idempotency. With a launcher: current iff args[0] IS the launcher and the\n // fallback env is the chosen cli.js (an npx-cache / global / slot path is stale\n // \u2014 F24). Without one (no runtime root): current iff wired to THIS cli.js.\n // Prefer the managed 'vo-mcp' entry over a legacy 'vo' one so a leftover legacy\n // entry cannot make every heal look stale. Only the MANAGED entry's keys are ever\n // carried into the rewrite (a legacy `vo` may be an sse/url server).\n const managedEntry = mcpServers['vo-mcp'];\n const voEntry = managedEntry ?? mcpServers['vo'];\n const { launcherPath } = launcher;\n const fallbackCli = chooseFallbackCli(voEntry?.env?.[MCP_FALLBACK_CLI_ENV], cliPath, launcher.sticky, launcherPath ? dirname(launcherPath) : null);\n const current = launcherPath\n ? !isStaleVoMcpEntry(voEntry, launcherPath, fallbackCli)\n : Boolean(voEntry?.args?.some((a: string) => a.includes(cliPath)));\n if (current) {\n log(` ${label} already current: ${configPath}`);\n return;\n }\n\n // Backup before any write \u2014 once per distinct content, never one per boot.\n const backupPath = backupConfigOnce(configPath);\n if (backupPath) log(` Backed up ${label} config \u2192 ${backupPath}`);\n\n // Preserve any existing env the user added (e.g. model API keys) \u2014 only ensure\n // VO_CONTROL_PLANE_URL is present. NEVER drop the user's env keys. Other entry\n // keys (type/cwd/disabled\u2026) and a node `command` are kept too. With a launcher\n // the recorded fallback is refreshed/kept per `chooseFallbackCli` (null = none).\n const { [MCP_FALLBACK_CLI_ENV]: _previousFallback, ...preservedEnv } = voEntry?.env ?? {};\n const merged: Record<string, unknown> = {\n ...existing,\n mcpServers: {\n ...mcpServers,\n 'vo-mcp': {\n ...carriedEntryKeys(managedEntry),\n command: preferredNodeCommand(managedEntry?.command),\n args: [launcherPath ?? cliPath],\n env: {\n VO_CONTROL_PLANE_URL: controlPlaneUrl,\n ...preservedEnv,\n ...(launcherPath && fallbackCli ? { [MCP_FALLBACK_CLI_ENV]: fallbackCli } : {}),\n },\n },\n },\n };\n // Claude Code rewrites this file itself: if it changed under us since the read,\n // do not clobber that write \u2014 skip; the next install/boot heals from fresh state.\n if (readMtime !== null && (!existsSync(configPath) || statSync(configPath).mtimeMs !== readMtime)) {\n log(` \u26A0 ${label} config changed while updating \u2014 left untouched this time: ${configPath}`);\n return;\n }\n writeClaudeConfig(configPath, merged);\n log(`\u2713 Wrote vo-mcp to ${label}: ${configPath}`);\n}\n\n/**\n * Wire vo-mcp into BOTH the Claude Code CLI (~/.claude.json) and the Claude\n * Desktop app config, so it loads in whichever the user runs. Each write is\n * idempotent + preserves all other config keys. ONLY VO_CONTROL_PLANE_URL (a\n * public URL) is written \u2014 never a secret.\n */\nfunction installMcpConfig(\n log: (msg: string) => void,\n env: Readonly<Record<string, string | undefined>>,\n mode: 'install' | 'heal' = 'install',\n): void {\n // Resolve home from the injected env (tests pass a temp dir) \u2192 falls back to the\n // OS home. This keeps install hermetic: it never touches real configs in tests.\n const home = env['HOME']?.trim() || env['USERPROFILE']?.trim() || homedir();\n const appData = env['APPDATA']?.trim();\n const plat = platform();\n const cliPath = resolveVoMcpCliPath();\n const controlPlaneUrl = env['VO_CONTROL_PLANE_URL']?.trim() || DEFAULT_CONTROL_PLANE_URL;\n const launcherPath = writeMcpLauncherForEnv(env, log, { platform: plat, home });\n const launcher: LauncherOptions = { launcherPath, ...(mode === 'heal' ? HEAL_LAUNCHER : INSTALL_LAUNCHER) };\n // For the unattended heal each client is its own leg: one locked/odd file must\n // never abort the others. The explicit `install` still surfaces a malformed\n // config as an error (a human is there to fix it).\n const leg = (label: string, run: () => void): void => {\n try {\n run();\n } catch (err) {\n if (mode !== 'heal') throw err;\n log(` \u26A0 ${label}: could not update the MCP registration \u2014 ${err instanceof Error ? err.message : String(err)}`);\n }\n };\n leg('Claude Code CLI', () => installMcpConfigAt(resolveCodeConfigPath(home), cliPath, controlPlaneUrl, log, 'Claude Code CLI', launcher));\n leg('Claude Desktop', () => installMcpConfigAt(resolveDesktopConfigPath(home, plat, appData), cliPath, controlPlaneUrl, log, 'Claude Desktop', launcher));\n const codexPath = resolveCodexConfigPath(home);\n if (launcher.onlyExisting && !existsSync(codexPath)) return;\n leg('Codex', () => {\n if (launcherPath) {\n const fallbackCli = chooseFallbackCli(readCodexManagedEnv(codexPath, MCP_FALLBACK_CLI_ENV), cliPath, launcher.sticky, dirname(launcherPath));\n installCodexMcpConfigAt(codexPath, launcherPath, controlPlaneUrl, log, fallbackCli ? { [MCP_FALLBACK_CLI_ENV]: fallbackCli } : {});\n } else {\n installCodexMcpConfigAt(codexPath, cliPath, controlPlaneUrl, log);\n }\n });\n}\n\n/**\n * Write the slot-resolving MCP launcher under the runner runtime root (F24).\n * Returns null (\u2192 direct cli.js registration, the pre-F24 shape) only when the\n * runtime root cannot be derived or written; never throws.\n */\nfunction writeMcpLauncherForEnv(\n env: Readonly<Record<string, string | undefined>>,\n log: (msg: string) => void,\n hint: { platform: NodeJS.Platform | string; home: string },\n): string | null {\n try {\n const root = defaultRunnerRuntimeRoot(env, hint);\n if (!root) return null;\n return writeMcpLauncher(root);\n } catch (err) {\n log(` \u26A0 could not write the vo-mcp launcher (registering cli.js directly): ${err instanceof Error ? err.message : String(err)}`);\n return null;\n }\n}\n\n/**\n * Best-effort heal for machines installed before F24: re-point a stale Claude\n * Code / Desktop `vo-mcp` entry or Codex `algohq` table (npx cache, global\n * install, slot path) at the launcher. Called by the runner daemon at boot.\n * Touches ONLY config files that already exist, keeps a still-valid fallback\n * (so a routine runtime-slot update never rewrites the user's config), and is\n * idempotent; never throws.\n */\nexport function healMcpRegistration(\n log: (msg: string) => void = () => {},\n env: Readonly<Record<string, string | undefined>> = process.env,\n): void {\n try {\n installMcpConfig(log, env, 'heal');\n } catch (err) {\n log(`vo-mcp: MCP registration heal skipped: ${err instanceof Error ? err.message : String(err)}`);\n }\n}\n\n/**\n * Run the DEVICE-CODE pairing flow (same as `vo-mcp pair`): a short code is shown,\n * the user enters it in their browser. Device code \u2014 NOT a loopback OAuth callback \u2014\n * so it works in every terminal (sandboxed/remote/SSH can't receive a 127.0.0.1\n * callback, which is why the old loopback `login` dead-ended at a \"link your terminal\"\n * page). Non-fatal: a pairing hiccup logs a retry hint and lets the install finish\n * (config + autostart are still useful; the user can run `vo-mcp pair` later).\n */\nasync function runPairFlow(log: (msg: string) => void, env: Readonly<Record<string, string | undefined>>): Promise<void> {\n log('\\n\u2501\u2501\u2501 Step 2: Link your AlgoHQ account (device code) \u2501\u2501\u2501');\n log('A short code appears below \u2014 open the URL it prints and enter the code.');\n log('Your raw token never persists; a scoped credential is stored in your OS keychain.\\n');\n\n try {\n const result = await runPairing({ env, log });\n log(`\\n\u2713 Paired \u2014 scoped credential stored at: ${result.credentialPath}`);\n } catch (err: unknown) {\n log(`\\n\u26A0 Pairing didn't complete: ${err instanceof Error ? err.message : String(err)}`);\n log(' No problem \u2014 the rest will finish; pair anytime with: vo-mcp pair');\n }\n}\n\n/**\n * Print the runner guidance + success summary.\n */\nfunction printNextSteps(log: (msg: string) => void, autostartInstalled: boolean, configOnly: boolean): void {\n log('\\n\u2501\u2501\u2501 Installation complete! \u2501\u2501\u2501\\n');\n log('What\\'s configured:');\n log(' \u2713 Claude Desktop, Claude Code, and Codex will load AlgoHQ MCP on next restart');\n if (configOnly) {\n log(' \u2713 Existing pairing and runner auto-start settings were left unchanged');\n } else {\n log(' \u2713 Your scoped credential is stored (revocable via the dashboard)');\n }\n if (autostartInstalled) {\n log(' \u2713 Runner daemon will start automatically at login\\n');\n } else {\n log('\\n');\n }\n log('Next steps:');\n log(' 1. Restart Claude Desktop / Claude Code / Codex (if running).');\n if (configOnly) {\n log(' 2. Restart the existing AlgoHQ runner service or runner terminal.');\n } else if (autostartInstalled) {\n log(' 2. Log out and back in (or start the runner manually now: vo-mcp runner)');\n } else {\n log(' 2. Start the agent runner in a terminal (keep it running):');\n log(' vo-mcp runner');\n log(' (To set up auto-start at login: vo-mcp runner --install-autostart)');\n }\n log(' 3. Visit AlgoHQ to dispatch your first agent:');\n log(' https://algosuite.ai/algohq\\n');\n log('The runner watches for tasks you dispatch and spins up agents in fresh worktrees.');\n log('Agents only run while the runner is connected. Ctrl+C to stop it anytime.\\n');\n}\n\n/**\n * Run the full install flow: MCP config \u2192 login \u2192 auto-start \u2192 guidance.\n */\nexport async function install(opts: InstallOptions = {}): Promise<void> {\n const log = opts.log ?? ((m: string) => console.error(m));\n const env = opts.env ?? process.env;\n\n log('\u2501\u2501\u2501 vo-mcp installer \u2501\u2501\u2501');\n log('This will set up your machine to dispatch AlgoHQ agents from anywhere.\\n');\n\n // Step 1: MCP config\n log('\u2501\u2501\u2501 Step 1: Configure Claude Desktop / Claude Code / Codex \u2501\u2501\u2501');\n installMcpConfig(log, env);\n\n // Step 2: Pair via device code (unless skipped)\n if (!opts.skipLogin) {\n await runPairFlow(log, env);\n } else if (opts.configOnly) {\n log('\\n(Config-only refresh \u2014 existing pairing left unchanged.)');\n } else {\n log('\\n(Pairing skipped \u2014 run `vo-mcp pair` when ready.)');\n }\n\n // Step 3: Auto-start (unless skipped)\n let autostartInstalled = false;\n if (!opts.skipAutostart) {\n const plat = platform();\n if (plat === 'win32' || plat === 'darwin' || plat === 'linux') {\n log('\\n\u2501\u2501\u2501 Step 3: Set up auto-start \u2501\u2501\u2501');\n log('Would you like the runner daemon to start automatically at login?');\n log('(You can skip this and set it up later with: vo-mcp runner --install-autostart)\\n');\n await installAutostart({ log, env });\n autostartInstalled = true;\n }\n }\n\n // Step 4: Guidance\n printNextSteps(log, autostartInstalled, opts.configOnly === true);\n}\n\nexport function installOptionsFromArgs(args: readonly string[]): InstallOptions {\n const configOnly = args.includes('--config-only');\n return configOnly\n ? { configOnly: true, skipLogin: true, skipAutostart: true }\n : {};\n}\n", "/**\n * Device-code pairing for the BYO runner (M1) \u2014 the no-terminal-token onboarding.\n *\n * The runner calls the control-plane `pair/initiate`, shows the friend a short\n * `code` to type at `<dashboard>/pair`, then polls `pair/poll` with its SECRET\n * `poll_token` until the friend authorizes \u2014 at which point it receives a freshly\n * minted `vocred_` and stores it in the OS keychain (via writeStoredCredential).\n *\n * The friend's AI key NEVER flows through here \u2014 this only obtains the\n * control-plane credential the runner needs to claim THEIR tasks.\n */\nimport { hostname, platform } from 'node:os';\n\nimport { writeStoredCredential, type StoredCredential } from './credential-store.js';\n\nexport const DEFAULT_CONTROL_PLANE_URL = 'https://vo-control-plane-bzjphrajaq-uc.a.run.app';\nexport const DEFAULT_DASHBOARD_URL = 'https://algosuite.ai';\n\nexport interface RunPairingDeps {\n readonly env?: Record<string, string | undefined>;\n readonly log?: (message: string) => void;\n readonly fetchImpl?: typeof fetch;\n readonly sleep?: (ms: number) => Promise<void>;\n readonly now?: () => Date;\n /** Test seam: capture the stored credential instead of touching the real keychain. */\n readonly store?: (cred: StoredCredential, storedAtIso: string) => string;\n}\n\nexport interface PairingResult {\n readonly credentialPath: string;\n readonly expires_at: string;\n}\n\n/** ABCD-EFGH grouping for an 8-char code (easier to read aloud / type). */\nexport function formatPairingCode(code: string): string {\n return code.length === 8 ? `${code.slice(0, 4)}-${code.slice(4)}` : code;\n}\n\nasync function readJson(res: { json: () => Promise<unknown> }): Promise<Record<string, unknown>> {\n const body = await res.json().catch(() => ({}));\n return body && typeof body === 'object' ? (body as Record<string, unknown>) : {};\n}\n\n/**\n * Run the full pairing handshake. Resolves once a credential is stored; rejects\n * with a friendly message on expiry / consumption / fatal transport error.\n */\nexport async function runPairing(deps: RunPairingDeps = {}): Promise<PairingResult> {\n const env = deps.env ?? process.env;\n const log = deps.log ?? ((m: string) => console.error(m));\n const fetchImpl = deps.fetchImpl ?? fetch;\n const sleep = deps.sleep ?? ((ms: number) => new Promise<void>((r) => setTimeout(r, ms)));\n const now = deps.now ?? (() => new Date());\n const store = deps.store ?? ((cred: StoredCredential, iso: string) => writeStoredCredential(cred, iso, env));\n\n const controlPlaneUrl = env['VO_CONTROL_PLANE_URL']?.trim() || DEFAULT_CONTROL_PLANE_URL;\n const dashboardUrl = env['VO_DASHBOARD_URL']?.trim() || DEFAULT_DASHBOARD_URL;\n const deviceLabel = `${platform()} on ${hostname()}`.slice(0, 120);\n\n // 1. initiate \u2014 get a display code + a secret poll token.\n const initRes = await fetchImpl(`${controlPlaneUrl}/api/v1/pair/initiate`, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ device_label: deviceLabel }),\n });\n if (!initRes.ok) throw new Error(`Could not start pairing (server ${initRes.status}).`);\n const init = await readJson(initRes);\n const code = String(init['code'] ?? '');\n const pollToken = String(init['poll_token'] ?? '');\n if (!code || !pollToken) throw new Error('Pairing service returned an incomplete response.');\n const intervalMs = (Number(init['poll_interval_seconds']) || 5) * 1000;\n const expiresAtMs = new Date(String(init['expires_at'] ?? '')).getTime();\n\n // 2. show the friend what to do.\n log('');\n log(' To connect this runner, open this page in your browser:');\n log(` ${dashboardUrl}/pair`);\n log(' and enter this code:');\n log('');\n log(` ${formatPairingCode(code)}`);\n log('');\n log(' Your Anthropic key never leaves this computer. Waiting for you to authorize\u2026');\n\n // 3. poll with the SECRET token until authorized / expired.\n for (;;) {\n if (Number.isFinite(expiresAtMs) && now().getTime() >= expiresAtMs) {\n throw new Error('The pairing code expired before it was authorized. Run `vo-mcp pair` again.');\n }\n await sleep(intervalMs);\n const pollRes = await fetchImpl(`${controlPlaneUrl}/api/v1/pair/poll`, {\n method: 'GET',\n headers: { 'x-vo-poll-token': pollToken },\n });\n if (pollRes.status === 404) {\n throw new Error('The pairing expired. Run `vo-mcp pair` again.');\n }\n if (pollRes.status === 410) {\n throw new Error('This code was already used. Run `vo-mcp pair` again.');\n }\n if (!pollRes.ok) {\n // Transient (rate limit / blip) \u2014 keep waiting.\n continue;\n }\n const body = await readJson(pollRes);\n if (body['status'] === 'pending') continue;\n if (body['status'] === 'authorized' && typeof body['vo_credential'] === 'string') {\n const credentialPath = store(\n {\n vo_credential: body['vo_credential'] as string,\n ...(typeof body['expires_at'] === 'string'\n ? { vo_credential_expires_at: body['expires_at'] as string }\n : {}),\n },\n now().toISOString(),\n );\n return { credentialPath, expires_at: String(body['expires_at'] ?? '') };\n }\n throw new Error('Unexpected response from the pairing service.');\n }\n}\n", "/**\n * Local credential store for the thin-client `vo-mcp login` flow (Increment 3b,\n * Option A \u2014 `docs/vo/vo-command-center-inc3b-login-design-2026-06-05.md`).\n *\n * Persists the per-user Firebase refresh token (the user's OWN credential, never\n * the god-token, never model keys) captured by `login`, so the auto-refreshing\n * token source (Inc 3a) can mint fresh ID tokens across MCP restarts.\n *\n * Storage precedence (Inc 3b.3):\n * 1. **OS keychain** (Windows Credential Manager / macOS Keychain / libsecret)\n * via the optional `@napi-rs/keyring` backend (`keychain.ts`). The DEFAULT\n * when available \u2014 the secret never lands in plaintext on disk.\n * 2. **0600 file** at `$VO_MCP_CREDENTIALS_PATH` or `~/.config/vo-mcp/credentials.json`.\n * The fallback when the keychain is unavailable or disabled\n * (`VO_MCP_DISABLE_KEYCHAIN`). `VO_MCP_CREDENTIALS_PATH` only sets the file\n * LOCATION; force file storage with `VO_MCP_DISABLE_KEYCHAIN`.\n *\n * `env`-supplied tokens (`VO_USER_REFRESH_TOKEN`, etc.) still win over BOTH\n * stores \u2014 that precedence lives upstream in `auth-token-source.ts`.\n *\n * **Single source of truth.** The credential lives in EITHER the keychain OR the\n * file, never both: a write to one store CLEARS the other, so a stale entry can\n * never shadow the current credential on read, and the secret never lingers in\n * plaintext after a migration to the keychain.\n *\n * **Keychain durability.** A keychain-stored credential is only readable while\n * the `@napi-rs/keyring` native module loads. If the module later becomes\n * unavailable (an ABI break across a Node upgrade, a corrupted install), the\n * credential can't be read and the user re-runs `vo-mcp login` \u2014 the same\n * behaviour as `gh` / `gcloud` / `firebase` keychain storage. We deliberately do\n * NOT mirror the secret to a plaintext file as a fallback: that would defeat the\n * entire point of keychain storage (keeping the secret off plaintext disk).\n */\nimport { homedir } from 'node:os';\nimport { join, dirname } from 'node:path';\nimport {\n existsSync,\n mkdirSync,\n readFileSync,\n writeFileSync,\n chmodSync,\n rmSync,\n} from 'node:fs';\n\nimport { keychainAvailable, keychainGet, keychainSet, keychainDelete } from './keychain.js';\n\nexport interface StoredCredential {\n /**\n * Firebase refresh token (long-lived; exchanged for short-lived ID tokens).\n * OPTIONAL since Inc 3b.4b: once a scoped `vo_credential` is minted, the raw\n * refresh token is dropped, so a stored credential may carry ONLY the vocred_.\n */\n readonly refresh_token?: string;\n /** Firebase Web API key (PUBLIC) needed for the securetoken refresh exchange. */\n readonly api_key?: string;\n /**\n * Scoped, revocable VO credential (`vocred_`) minted by the control-plane\n * (Inc 3b.4b). Preferred over the raw refresh token; lets the client present a\n * revocable, server-side credential instead of the Firebase refresh token.\n */\n readonly vo_credential?: string;\n /** ISO-8601 expiry of `vo_credential` (the client re-logs-in past this). */\n readonly vo_credential_expires_at?: string;\n /** The signed-in operator email (diagnostics only). */\n readonly email?: string;\n /** ISO timestamp the credential was stored. */\n readonly stored_at?: string;\n}\n\n/**\n * Pluggable OS-keychain backend. Defaults to the real `@napi-rs/keyring` wrapper;\n * tests inject a deterministic fake so they never touch the host keychain.\n */\nexport interface KeychainBackend {\n available(): boolean;\n get(): string | null;\n set(secret: string): boolean;\n delete(): boolean;\n}\n\nconst realKeychain: KeychainBackend = {\n available: keychainAvailable,\n get: keychainGet,\n set: keychainSet,\n delete: keychainDelete,\n};\n\n/** Human-readable \"location\" returned when the credential was stored in the OS keychain. */\nexport const KEYCHAIN_LOCATION = 'OS keychain (service \"vo-mcp\")';\n\n/** Resolve the credentials file path (env override \u2192 XDG-ish default under home). */\nexport function credentialPath(env: Readonly<Record<string, string | undefined>> = process.env): string {\n const override = env['VO_MCP_CREDENTIALS_PATH']?.trim();\n if (override) return override;\n return join(homedir(), '.config', 'vo-mcp', 'credentials.json');\n}\n\n/**\n * Whether the keychain should be consulted at all (read OR write). False when the\n * native backend is unavailable or `VO_MCP_DISABLE_KEYCHAIN` is set (CI/headless).\n */\nfunction keychainEnabled(\n env: Readonly<Record<string, string | undefined>>,\n keychain: KeychainBackend,\n): boolean {\n const disabled = (env['VO_MCP_DISABLE_KEYCHAIN'] ?? '').trim().toLowerCase();\n if (disabled === '1' || disabled === 'true' || disabled === 'yes') return false;\n return keychain.available();\n}\n\n/** Parse + validate a stored credential blob. Returns null on any problem (never throws). */\nfunction deserialize(raw: string): StoredCredential | null {\n try {\n const parsed = JSON.parse(raw) as Partial<StoredCredential>;\n const refresh = typeof parsed.refresh_token === 'string' ? parsed.refresh_token.trim() : '';\n const apiKey = typeof parsed.api_key === 'string' ? parsed.api_key.trim() : '';\n const voCred = typeof parsed.vo_credential === 'string' ? parsed.vo_credential.trim() : '';\n // Valid if it carries a scoped vocred_ OR a full Firebase refresh pair.\n if (!voCred && (!refresh || !apiKey)) return null;\n return {\n ...(refresh ? { refresh_token: refresh } : {}),\n ...(apiKey ? { api_key: apiKey } : {}),\n ...(voCred ? { vo_credential: voCred } : {}),\n ...(typeof parsed.vo_credential_expires_at === 'string' ? { vo_credential_expires_at: parsed.vo_credential_expires_at } : {}),\n ...(typeof parsed.email === 'string' ? { email: parsed.email } : {}),\n ...(typeof parsed.stored_at === 'string' ? { stored_at: parsed.stored_at } : {}),\n };\n } catch {\n return null;\n }\n}\n\nfunction readFromFile(env: Readonly<Record<string, string | undefined>>): StoredCredential | null {\n try {\n const p = credentialPath(env);\n if (!existsSync(p)) return null;\n return deserialize(readFileSync(p, 'utf8'));\n } catch {\n return null;\n }\n}\n\n/**\n * Read the stored credential, or `null` if absent/unreadable/invalid (never\n * throws). Consults an ENABLED keychain first (regardless of the write-target\n * flags, so a credential written to the keychain is found even if\n * `VO_MCP_CREDENTIALS_PATH` is later set), then the 0600 file.\n */\nexport function readStoredCredential(\n env: Readonly<Record<string, string | undefined>> = process.env,\n keychain: KeychainBackend = realKeychain,\n): StoredCredential | null {\n if (keychainEnabled(env, keychain)) {\n const raw = keychain.get();\n const fromKeychain = raw ? deserialize(raw) : null;\n if (fromKeychain) return fromKeychain;\n }\n return readFromFile(env);\n}\n\n/** Read only the OS keychain; never fall back to env-selected plaintext files. */\nexport function readStoredCredentialKeychainOnly(\n env: Readonly<Record<string, string | undefined>> = process.env,\n keychain: KeychainBackend = realKeychain,\n): StoredCredential | null {\n if (!keychainEnabled(env, keychain)) return null;\n const raw = keychain.get();\n return raw ? deserialize(raw) : null;\n}\n\nfunction deleteFile(env: Readonly<Record<string, string | undefined>>): void {\n try {\n rmSync(credentialPath(env), { force: true });\n } catch {\n /* best-effort */\n }\n}\n\nfunction writeToFile(\n payload: StoredCredential,\n env: Readonly<Record<string, string | undefined>>,\n): string {\n const p = credentialPath(env);\n mkdirSync(dirname(p), { recursive: true });\n writeFileSync(p, `${JSON.stringify(payload, null, 2)}\\n`, { mode: 0o600 });\n // Best-effort tighten (no-op / throws on some Windows filesystems \u2014 ignore).\n try {\n chmodSync(p, 0o600);\n } catch {\n /* best-effort */\n }\n return p;\n}\n\n/**\n * Persist the credential. Prefers the OS keychain (secret never hits plaintext\n * disk); otherwise writes the 0600 file. Writing to one store CLEARS the other\n * (single source of truth \u2014 no stale shadow, no lingering plaintext). Returns the\n * location it was stored (`KEYCHAIN_LOCATION` or the file path).\n */\nexport function writeStoredCredential(\n cred: StoredCredential,\n storedAt: string,\n env: Readonly<Record<string, string | undefined>> = process.env,\n keychain: KeychainBackend = realKeychain,\n): string {\n const payload: StoredCredential = {\n ...(cred.refresh_token ? { refresh_token: cred.refresh_token } : {}),\n ...(cred.api_key ? { api_key: cred.api_key } : {}),\n ...(cred.vo_credential ? { vo_credential: cred.vo_credential } : {}),\n ...(cred.vo_credential_expires_at ? { vo_credential_expires_at: cred.vo_credential_expires_at } : {}),\n ...(cred.email ? { email: cred.email } : {}),\n stored_at: cred.stored_at ?? storedAt,\n };\n if (keychainEnabled(env, keychain) && keychain.set(JSON.stringify(payload))) {\n // Stored in the keychain \u2192 clear any stale plaintext file so the secret\n // doesn't linger on disk and can't shadow the keychain on read.\n deleteFile(env);\n return KEYCHAIN_LOCATION;\n }\n const p = writeToFile(payload, env);\n // Stored in the file \u2192 clear any stale keychain entry so it can't shadow the\n // newer file credential on read.\n if (keychainEnabled(env, keychain)) keychain.delete();\n return p;\n}\n", "/**\n * Optional OS-keychain backend for the thin-client credential store (Increment\n * 3b.3 \u2014 `docs/vo/vo-command-center-inc3b-login-design-2026-06-05.md` \u00A75/\u00A76).\n *\n * Loads `@napi-rs/keyring` at runtime via `createRequire`, so it is a TRUE\n * optional dependency: if the native module is absent or fails to load\n * (unsupported platform, prebuilt binary missing, headless CI), every function\n * degrades to a no-op and the caller (`credential-store.ts`) falls back to the\n * 0600 file store. `@napi-rs/keyring`'s `Entry` API is SYNCHRONOUS, so the\n * credential store stays synchronous \u2014 no async ripple into the Inc-3a token\n * source that reads it.\n *\n * Why `createRequire` and not a static/dynamic `import`: a static import would\n * make the native module a HARD dependency (a missing prebuilt would crash the\n * MCP at startup); a dynamic `import()` is async (would force the whole read\n * path async). `createRequire(...)` inside a try/catch loads it lazily and\n * synchronously, and a load failure is just \"keychain unavailable\".\n */\nimport { createRequire } from 'node:module';\n\n/** Keychain service + account the single refresh credential is stored under. */\nconst SERVICE = 'vo-mcp';\nconst ACCOUNT = 'refresh-credential';\n\ninterface KeyringEntry {\n getPassword(): string | null;\n setPassword(password: string): void;\n deletePassword(): boolean;\n}\ninterface KeyringModule {\n Entry: new (service: string, account: string) => KeyringEntry;\n}\n\n// undefined = not yet attempted; null = attempted and unavailable.\nlet cached: KeyringModule | null | undefined;\n\nfunction loadKeyring(): KeyringModule | null {\n if (cached !== undefined) return cached;\n try {\n const req = createRequire(import.meta.url);\n const mod = req('@napi-rs/keyring') as Partial<KeyringModule>;\n cached = mod && typeof mod.Entry === 'function' ? (mod as KeyringModule) : null;\n } catch {\n cached = null;\n }\n return cached;\n}\n\n/** True when the OS keychain backend is usable in this runtime. */\nexport function keychainAvailable(): boolean {\n return loadKeyring() !== null;\n}\n\n/** Read the raw stored secret string from the OS keychain, or null. Never throws. */\nexport function keychainGet(): string | null {\n const k = loadKeyring();\n if (!k) return null;\n try {\n return new k.Entry(SERVICE, ACCOUNT).getPassword();\n } catch {\n return null;\n }\n}\n\n/** Store the raw secret string in the OS keychain. Returns true on success. Never throws. */\nexport function keychainSet(secret: string): boolean {\n const k = loadKeyring();\n if (!k) return false;\n try {\n new k.Entry(SERVICE, ACCOUNT).setPassword(secret);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Delete the stored secret from the OS keychain. Returns true if an entry was\n * removed. Never throws \u2014 a no-op (and `false`) when the backend is unavailable\n * or the entry is absent. Used to keep ONE source of truth: when the credential\n * is (re)written to the file, any stale keychain entry is cleared so it can't\n * shadow the newer file credential on read (and vice-versa).\n */\nexport function keychainDelete(): boolean {\n const k = loadKeyring();\n if (!k) return false;\n try {\n return new k.Entry(SERVICE, ACCOUNT).deletePassword();\n } catch {\n return false;\n }\n}\n\n/** Test-only seam to reset the memoised module load. */\nexport function __resetKeychainCache(): void {\n cached = undefined;\n}\n", "import { existsSync, mkdirSync, readFileSync, statSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { backupConfigOnce, writeFileAtomic } from './config-backup.js';\nimport { MCP_FALLBACK_CLI_ENV } from './mcp-launcher.js';\n\nconst MANAGED_BEGIN = '# BEGIN AlgoHQ MCP (managed by vo-mcp install)';\nconst MANAGED_END = '# END AlgoHQ MCP (managed by vo-mcp install)';\nconst MANAGED_SERVER_NAMES = new Set(['algohq', 'vo', 'vo-mcp', 'vo_mcp']);\n\ninterface TableSection {\n readonly path: readonly string[];\n readonly start: number;\n readonly end: number;\n}\n\nexport function resolveCodexConfigPath(home: string): string {\n return join(home, '.codex', 'config.toml');\n}\n\nfunction normalizeKey(value: string): string {\n const trimmed = value.trim();\n if ((trimmed.startsWith('\"') && trimmed.endsWith('\"')) ||\n (trimmed.startsWith(\"'\") && trimmed.endsWith(\"'\"))) {\n return trimmed.slice(1, -1);\n }\n return trimmed;\n}\n\nfunction tablePath(line: string): string[] | null {\n const match = /^\\s*\\[([^\\r\\n]+)\\]\\s*(?:#.*)?$/.exec(line);\n const rawPath = match?.[1];\n if (!rawPath || rawPath.includes('[') || rawPath.includes(']')) return null;\n return rawPath.split('.').map(normalizeKey);\n}\n\nfunction tableSections(lines: readonly string[]): TableSection[] {\n const starts: Array<{ path: string[]; start: number }> = [];\n for (let index = 0; index < lines.length; index += 1) {\n const path = tablePath(lines[index] ?? '');\n if (path) starts.push({ path, start: index });\n }\n return starts.map((section, index) => ({\n ...section,\n end: starts[index + 1]?.start ?? lines.length,\n }));\n}\n\nfunction isManagedSection(section: TableSection): boolean {\n return section.path[0] === 'mcp_servers' && MANAGED_SERVER_NAMES.has(section.path[1] ?? '');\n}\n\nfunction assignmentKey(line: string): string | null {\n const match = /^\\s*((?:[A-Za-z0-9_-]+)|(?:\"[^\"]+\")|(?:'[^']+'))\\s*=/.exec(line);\n return match?.[1] ? normalizeKey(match[1]) : null;\n}\n\nfunction isStructurallySafeToml(raw: string): boolean {\n const lines = raw.split(/\\r?\\n/);\n const beginIndexes = lines.flatMap((line, index) => line.trim() === MANAGED_BEGIN ? [index] : []);\n const endIndexes = lines.flatMap((line, index) => line.trim() === MANAGED_END ? [index] : []);\n if (beginIndexes.length !== endIndexes.length || beginIndexes.length > 1) return false;\n if (beginIndexes[0] !== undefined && (endIndexes[0] ?? -1) <= beginIndexes[0]) return false;\n\n for (const line of lines) {\n const trimmed = line.trim();\n // Do not attempt to parse user-owned TOML. That would reject valid constructs\n // such as multiline strings. We only require managed-table headers to be\n // complete enough for the surgical section editor below to identify safely.\n if (/^\\[\\[?mcp_servers(?:\\.|\\s|$)/.test(trimmed) && tablePath(line) === null) return false;\n }\n return true;\n}\n\nfunction tomlString(value: string): string {\n return JSON.stringify(value);\n}\n\nfunction preservedSectionLines(\n lines: readonly string[],\n section: TableSection | undefined,\n managedKeys: ReadonlySet<string>,\n): string[] {\n if (!section) return [];\n return lines\n .slice(section.start + 1, section.end)\n .filter((line) => {\n if (line.trim() === MANAGED_BEGIN || line.trim() === MANAGED_END) return false;\n const key = assignmentKey(line);\n return key === null || !managedKeys.has(key);\n })\n .filter((line, index, all) => line.trim() !== '' || (index > 0 && index < all.length - 1));\n}\n\n/**\n * Read one managed env value (e.g. VO_MCP_FALLBACK_CLI) back out of the Codex\n * TOML \u2014 used by the daemon-boot heal to keep a still-valid fallback instead of\n * rewriting the file on every runtime-slot update. Values are the JSON-encoded\n * basic strings `tomlString` writes, so JSON.parse decodes them exactly.\n * Returns undefined when the file/key is absent or the value is not decodable.\n */\nexport function readCodexManagedEnv(configPath: string, key: string): string | undefined {\n if (!existsSync(configPath)) return undefined;\n const raw = readFileSync(configPath, 'utf8');\n const lines = raw.split(/\\r?\\n/);\n const sections = tableSections(lines);\n const envSection = sections.find((section) => isManagedSection(section) && section.path[2] === 'env');\n if (!envSection) return undefined;\n for (const line of lines.slice(envSection.start + 1, envSection.end)) {\n if (assignmentKey(line) !== key) continue;\n const match = /=\\s*(\"(?:[^\"\\\\]|\\\\.)*\")\\s*(?:#.*)?$/.exec(line);\n if (!match?.[1]) return undefined;\n try {\n const value: unknown = JSON.parse(match[1]);\n return typeof value === 'string' ? value : undefined;\n } catch {\n return undefined;\n }\n }\n return undefined;\n}\n\nexport function renderCodexMcpConfig(\n raw: string,\n cliPath: string,\n controlPlaneUrl: string,\n managedEnv: Readonly<Record<string, string>> = {},\n): string {\n if (!isStructurallySafeToml(raw)) {\n throw new Error('Codex config is malformed; refusing to overwrite it');\n }\n\n const eol = raw.includes('\\r\\n') ? '\\r\\n' : '\\n';\n const lines = raw.split(/\\r?\\n/);\n const sections = tableSections(lines);\n const rootSections = sections.filter((section) => isManagedSection(section) && section.path.length === 2);\n const preferredRoot = rootSections.find((section) => section.path[1] === 'algohq') ?? rootSections[0];\n const preferredName = preferredRoot?.path[1];\n const envSection = sections.find((section) =>\n isManagedSection(section) && section.path[1] === preferredName && section.path[2] === 'env');\n const rootExtras = preservedSectionLines(lines, preferredRoot, new Set(['command', 'args', 'required']));\n // Managed env keys are ALWAYS ours (even when not emitted this render) so a\n // dropped fallback disappears instead of surviving as a \"user extra\".\n const envExtras = preservedSectionLines(lines, envSection, new Set(['VO_CONTROL_PLANE_URL', MCP_FALLBACK_CLI_ENV, ...Object.keys(managedEnv)]));\n\n // Remove ONLY the two marker lines and the managed tables \u2014 never \"everything\n // between the markers\". Codex re-serialises config.toml itself and leaves the\n // BEGIN comment at the top and the END comment at the bottom with the user's\n // whole config in between (root keys, other MCP servers, plugins, projects\u2026);\n // the older range-removal wiped all of it on the next install/heal (2026-08-16,\n // operator host: 96 lines \u2192 10; restored from the content-deduped backup).\n const removed = new Set<number>();\n for (const [index, line] of lines.entries()) {\n if (line.trim() === MANAGED_BEGIN || line.trim() === MANAGED_END) removed.add(index);\n }\n for (const section of sections.filter(isManagedSection)) {\n for (let index = section.start; index < section.end; index += 1) removed.add(index);\n }\n\n const base = lines.filter((_line, index) => !removed.has(index)).join(eol).trimEnd();\n const block = [\n MANAGED_BEGIN,\n '[mcp_servers.algohq]',\n 'command = \"node\"',\n `args = [${tomlString(cliPath)}]`,\n 'required = true',\n ...rootExtras,\n '',\n '[mcp_servers.algohq.env]',\n `VO_CONTROL_PLANE_URL = ${tomlString(controlPlaneUrl)}`,\n ...Object.entries(managedEnv).map(([key, value]) => `${key} = ${tomlString(value)}`),\n ...envExtras,\n MANAGED_END,\n ].join(eol);\n return `${base}${base ? `${eol}${eol}` : ''}${block}${eol}`;\n}\n\nexport function installCodexMcpConfigAt(\n configPath: string,\n cliPath: string,\n controlPlaneUrl: string,\n log: (message: string) => void,\n managedEnv: Readonly<Record<string, string>> = {},\n): void {\n const exists = existsSync(configPath);\n const readMtime = exists ? statSync(configPath).mtimeMs : null;\n const raw = exists ? readFileSync(configPath, 'utf8') : '';\n let rendered: string;\n try {\n rendered = renderCodexMcpConfig(raw, cliPath, controlPlaneUrl, managedEnv);\n } catch (error) {\n // Nothing is modified on this path; a backup is still useful once (the user\n // will hand-edit the file) but never once per daemon boot \u2014 content-deduped.\n const backupPath = backupConfigOnce(configPath);\n if (backupPath) log(` Backed up malformed Codex config \u2192 ${backupPath}`);\n throw error;\n }\n if (rendered === raw) {\n log(` Codex already current: ${configPath}`);\n return;\n }\n // Codex re-serialises this file itself (F28): if it changed under us since the\n // read, do not clobber that write \u2014 skip; the next install/boot re-renders.\n if (readMtime !== null && (!existsSync(configPath) || statSync(configPath).mtimeMs !== readMtime)) {\n log(` \u26A0 Codex config changed while updating \u2014 left untouched this time: ${configPath}`);\n return;\n }\n const backupPath = backupConfigOnce(configPath);\n if (backupPath) log(` Backed up Codex config \u2192 ${backupPath}`);\n mkdirSync(dirname(configPath), { recursive: true });\n writeFileAtomic(configPath, rendered);\n log(`\u2713 Wrote AlgoHQ MCP to Codex: ${configPath}`);\n}\n", "/**\n * Config-file backups for `vo-mcp install` / the daemon-boot MCP heal.\n *\n * `backupConfigOnce` copies `<path>` to `<path>.backup-<epoch>` UNLESS a backup\n * with byte-identical content already sits beside it \u2014 a heal that runs on every\n * daemon boot (and every supervisor restart) must never grow an unbounded pile of\n * copies of a config that may hold the user's provider keys (refute review of\n * #9796, finding 5: a structurally-unsafe Codex TOML produced one backup per boot).\n *\n * `writeFileAtomic` writes via a sibling temp file + rename so a concurrent\n * reader (Claude Code rewrites `~/.claude.json` itself) never sees a torn file.\n */\nimport { chmodSync, copyFileSync, existsSync, readdirSync, readFileSync, renameSync, statSync, unlinkSync, writeFileSync } from 'node:fs';\nimport { basename, dirname, join } from 'node:path';\n\nconst BACKUP_SUFFIX_RE = /^\\.backup-\\d+$/u;\nconst TEMP_SUFFIX_RE = /^\\.vo-mcp-tmp-\\d+-\\d+$/u;\nconst RENAME_RETRIES = 5;\nconst RENAME_RETRY_MS = 50;\n\n/** Remove stale `<name>.vo-mcp-tmp-*` siblings (a crash between write and rename would otherwise leave a full config copy behind forever). */\nexport function sweepStaleTempFiles(configPath: string): number {\n const dir = dirname(configPath);\n const name = basename(configPath);\n if (!existsSync(dir)) return 0;\n let removed = 0;\n for (const entry of readdirSync(dir)) {\n if (!entry.startsWith(name) || !TEMP_SUFFIX_RE.test(entry.slice(name.length))) continue;\n try { unlinkSync(join(dir, entry)); removed += 1; } catch { /* in use \u2014 leave it */ }\n }\n return removed;\n}\n\nfunction sleepSync(ms: number): void {\n Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);\n}\n\n/** True when a `<name>.backup-<n>` sibling already holds exactly `content`. */\nexport function hasIdenticalBackup(configPath: string, content: string | Buffer): boolean {\n const dir = dirname(configPath);\n const name = basename(configPath);\n if (!existsSync(dir)) return false;\n const buffer = Buffer.isBuffer(content) ? content : Buffer.from(content, 'utf8');\n for (const entry of readdirSync(dir)) {\n if (!entry.startsWith(name) || !BACKUP_SUFFIX_RE.test(entry.slice(name.length))) continue;\n const candidate = join(dir, entry);\n try {\n if (statSync(candidate).size !== buffer.length) continue;\n if (readFileSync(candidate).equals(buffer)) return true;\n } catch {\n // unreadable sibling \u2014 not a match\n }\n }\n return false;\n}\n\n/**\n * Back the file up beside itself unless an identical backup exists. Returns the\n * backup path when one was written, null when skipped (identical backup present\n * or the file does not exist).\n */\nexport function backupConfigOnce(configPath: string): string | null {\n if (!existsSync(configPath)) return null;\n const current = readFileSync(configPath);\n if (hasIdenticalBackup(configPath, current)) return null;\n const backupPath = `${configPath}.backup-${Date.now()}`;\n copyFileSync(configPath, backupPath);\n return backupPath;\n}\n\n/**\n * Temp-file + rename write. The temp is created 0600 and then given the target's\n * existing mode (a chmod-600 config must not come back 0644). On Windows a\n * rename over a file another process merely has open for read fails EPERM/EBUSY\n * (`~/.claude.json` is held transiently by Claude Code / AV / indexers), so the\n * rename is retried briefly and, as the last resort, the content is written in\n * place \u2014 a torn window is better than aborting the whole install/heal. Any\n * failure removes the temp and rethrows.\n */\nexport function writeFileAtomic(path: string, content: string): void {\n sweepStaleTempFiles(path);\n const temp = `${path}.vo-mcp-tmp-${process.pid}-${Date.now()}`;\n try {\n writeFileSync(temp, content, { encoding: 'utf8', mode: 0o600 });\n if (existsSync(path)) {\n try { chmodSync(temp, statSync(path).mode & 0o777); } catch { /* keep 0600 */ }\n }\n let lastErr: unknown = null;\n for (let attempt = 0; attempt < RENAME_RETRIES; attempt += 1) {\n try {\n renameSync(temp, path);\n return;\n } catch (err) {\n lastErr = err;\n const code = (err as { code?: string }).code;\n if (code !== 'EPERM' && code !== 'EBUSY' && code !== 'EACCES') throw err;\n sleepSync(RENAME_RETRY_MS);\n }\n }\n // Rename kept failing (target held open on Windows): write in place.\n writeFileSync(path, content, 'utf8');\n try { unlinkSync(temp); } catch { /* already gone */ }\n void lastErr;\n } catch (err) {\n try { unlinkSync(temp); } catch { /* already gone */ }\n throw err;\n }\n}\n", "/**\n * The vo-mcp MCP LAUNCHER (F24, 2026-08-16).\n *\n * `vo-mcp install` used to register Claude's `mcpServers.vo-mcp` (and Codex's\n * `mcp_servers.algohq`) as `node <the installing package's dist/cli.js>` \u2014\n * whatever copy happened to run `install`. Live: an npx cache of 0.2.0-beta.23\n * served EVERY dispatched agent for two months while the runner daemon itself\n * advanced to beta.46 (the moat entitlement hydration lives in beta.42+, so\n * consensus stayed `unimplemented`). The runner runtime advances through the\n * slot mechanism (`<runtime-root>/current.json` \u2192 `slots/<id>/node_modules/\n * @algosuite/vo-mcp`) but nothing ever re-pointed the MCP registrations.\n *\n * Fix: register a small self-contained LAUNCHER script that resolves the ACTIVE\n * runtime slot at every MCP spawn and imports its `dist/cli.js` (previous slot\n * next, then a non-slot package cli.js via `VO_MCP_FALLBACK_CLI` on the entry).\n * Node builtins only; no version is baked in.\n */\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { homedir, platform as osPlatform } from 'node:os';\nimport { isAbsolute, join, normalize, resolve, sep, posix as pathPosix, win32 as pathWin32 } from 'node:path';\n\nexport const MCP_LAUNCHER_FILE = 'vo-mcp-launcher.mjs';\nexport const MCP_FALLBACK_CLI_ENV = 'VO_MCP_FALLBACK_CLI';\nconst APP_IDENTIFIER = 'ai.algosuite.vo-runner';\nconst RUNNER_RUNTIME_DIR = 'runner-runtime';\n\n/**\n * EXACT mirror of `runner/bundled-runtime-store.mjs` `runtimeRootFromEnv` (that\n * module is .mjs outside the TS rootDir, so it cannot be imported here; keep in\n * lockstep by hand \u2014 `mcp-launcher.test.ts` pins both against each other).\n * Explicit `VO_RUNNER_RUNTIME_ROOT` wins; a SET-but-relative value is a\n * misconfiguration (null); absent \u2192 the desktop app's platform default, null\n * when that cannot be derived (no absolute APPDATA on win32 / no home).\n */\nexport function defaultRunnerRuntimeRoot(\n env: Readonly<Record<string, string | undefined>> = process.env,\n { platform = osPlatform(), home = homedir() }: { platform?: NodeJS.Platform | string; home?: string } = {},\n): string | null {\n const explicit = String(env['VO_RUNNER_RUNTIME_ROOT'] || '').trim();\n if (explicit) return isAbsolute(explicit) ? resolve(explicit) : null;\n if (platform === 'win32') {\n const appData = String(env['APPDATA'] || '').trim();\n return appData && isAbsolute(appData) ? resolve(join(appData, APP_IDENTIFIER, RUNNER_RUNTIME_DIR)) : null;\n }\n if (!home) return null;\n if (platform === 'darwin') return resolve(join(home, 'Library', 'Application Support', APP_IDENTIFIER, RUNNER_RUNTIME_DIR));\n const xdg = String(env['XDG_CONFIG_HOME'] || '').trim();\n return resolve(join(xdg && isAbsolute(xdg) ? xdg : join(home, '.config'), APP_IDENTIFIER, RUNNER_RUNTIME_DIR));\n}\n\nexport function mcpLauncherPath(runtimeRoot: string): string {\n return join(runtimeRoot, MCP_LAUNCHER_FILE);\n}\n\n/**\n * The launcher source. Deterministic (no paths baked in) so rewrites are\n * byte-idempotent. Root precedence: its OWN directory first (the launcher is\n * written INTO a runtime root, so that is self-consistent), then an ABSOLUTE\n * `VO_RUNNER_RUNTIME_ROOT` (a relative/stale/foreign env value never redirects\n * it). Slot ids are validated with the canonical `SLOT_ID_RE` shape and the\n * pointer must be schema_version 1 \u2014 a tampered/foreign pointer resolves nothing.\n */\nexport function renderMcpLauncher(): string {\n return `#!/usr/bin/env node\n// Written by \\`vo-mcp install\\` / the runner daemon (F24, 2026-08-16). Claude's and Codex's vo-mcp MCP\n// server entries point here so every MCP spawn runs the ACTIVE runner runtime slot \u2014 the fleet-approved\n// vo-mcp \u2014 instead of whatever copy \\`install\\` happened to run from. Resolution: this file's directory,\n// then an ABSOLUTE VO_RUNNER_RUNTIME_ROOT -> current.json (schema 1) active slot -> previous slot ->\n// ${MCP_FALLBACK_CLI_ENV} (a non-slot package cli.js) -> exit 2.\nimport { existsSync, readFileSync, readdirSync, statSync } from 'node:fs';\nimport { dirname, isAbsolute, join } from 'node:path';\nimport { fileURLToPath, pathToFileURL } from 'node:url';\nconst SLOT_ID_RE = /^vo-mcp-[0-9A-Za-z._-]{1,96}$/u;\nconst here = dirname(fileURLToPath(import.meta.url));\nconst envRoot = String(process.env.VO_RUNNER_RUNTIME_ROOT || '').trim();\nconst ROOTS = [here, ...(envRoot && isAbsolute(envRoot) && envRoot !== here ? [envRoot] : [])];\nconst FALLBACK_CLI = process.env.${MCP_FALLBACK_CLI_ENV} || '';\nfunction slotCli(root, slotId) {\n if (typeof slotId !== 'string' || !SLOT_ID_RE.test(slotId)) return null;\n const cli = join(root, 'slots', slotId, 'node_modules', '@algosuite', 'vo-mcp', 'dist', 'cli.js');\n return existsSync(cli) ? cli : null;\n}\nfunction rootCli(root) {\n try {\n const cur = JSON.parse(readFileSync(join(root, 'current.json'), 'utf8'));\n if (!cur || cur.schema_version !== 1) return null;\n return slotCli(root, cur.active && cur.active.slot_id) || slotCli(root, cur.previous && cur.previous.slot_id);\n } catch { return null; }\n}\n// Floor: no usable pointer (quarantined by a bootstrap rollback, corrupt, or a\n// future schema) must not leave every agent without MCP \u2014 run the NEWEST slot\n// on disk that carries a cli.js, and say so on stderr.\nfunction newestSlotCli(root) {\n try {\n const dir = join(root, 'slots');\n const found = readdirSync(dir).filter((id) => SLOT_ID_RE.test(id) && slotCli(root, id))\n .map((id) => ({ id, mtime: statSync(join(dir, id)).mtimeMs }))\n .sort((a, b) => b.mtime - a.mtime);\n return found.length ? slotCli(root, found[0].id) : null;\n } catch { return null; }\n}\nlet target = null;\nfor (const root of ROOTS) { target = rootCli(root); if (target) break; }\nif (!target) {\n for (const root of ROOTS) { target = newestSlotCli(root); if (target) { process.stderr.write('[vo-mcp-launcher] no usable runtime pointer \u2014 using the newest slot on disk\\\\n'); break; } }\n}\nif (!target && FALLBACK_CLI && existsSync(FALLBACK_CLI)) target = FALLBACK_CLI;\nif (!target) { process.stderr.write('[vo-mcp-launcher] no runner runtime slot and no fallback cli\\\\n'); process.exit(2); }\nprocess.stderr.write(\\`[vo-mcp-launcher] \\${target}\\\\n\\`);\nawait import(pathToFileURL(target).href);\n`;\n}\n\n/** Write (or refresh) the launcher under the runtime root; returns its path. Byte-idempotent. */\nexport function writeMcpLauncher(runtimeRoot: string): string {\n mkdirSync(runtimeRoot, { recursive: true });\n const target = mcpLauncherPath(runtimeRoot);\n const content = renderMcpLauncher();\n if (!existsSync(target) || readFileSync(target, 'utf8') !== content) writeFileSync(target, content, 'utf8');\n return target;\n}\n\nexport interface McpServerEntryLike {\n readonly command?: string;\n readonly args?: readonly string[];\n readonly env?: Readonly<Record<string, string>>;\n}\n\n/** Path equality: normalised (dot segments, trailing separators), separators unified, case folded only where the FS is case-insensitive. */\nexport function samePath(a: string, b: string, platform: string = osPlatform()): boolean {\n // Normalise with the TARGET platform's rules (win32 treats both separators\n // and drive letters; posix does not), so the comparison is host-independent.\n const pathModule = platform === 'win32' ? pathWin32 : pathPosix;\n const norm = (p: string): string => {\n const slashed = pathModule.normalize(p).replace(/\\\\/g, '/').replace(/\\/+$/u, '');\n return platform === 'win32' || platform === 'darwin' ? slashed.toLowerCase() : slashed;\n };\n return norm(a) === norm(b);\n}\n\n/** True when the entry's first arg is NOT the launcher (npx cache, global install, slot path\u2026). */\nexport function isNotLauncherEntry(entry: McpServerEntryLike | undefined, launcherPath: string, platform?: string): boolean {\n const first = entry?.args && entry.args.length > 0 ? String(entry.args[0]) : '';\n return !first || !samePath(first, launcherPath, platform);\n}\n\n/**\n * True when the registered entry will silently pin an old vo-mcp: it is not the\n * launcher, or its recorded fallback differs from `fallbackCli` (null = none).\n */\nexport function isStaleVoMcpEntry(\n entry: McpServerEntryLike | undefined,\n launcherPath: string,\n fallbackCli: string | null,\n platform?: string,\n): boolean {\n if (!entry || isNotLauncherEntry(entry, launcherPath, platform)) return true;\n const recorded = String(entry.env?.[MCP_FALLBACK_CLI_ENV] ?? '').trim();\n if (!fallbackCli) return recorded !== '';\n return !recorded || !samePath(recorded, fallbackCli, platform);\n}\n\n/**\n * A cli.js that lives inside a runtime SLOT \u2014 never a durable fallback (slots\n * move; a pinned one is F24 again). Anchored to the runtime root when known\n * (`<root>/slots/vo-mcp-\u2026/`), else the bare `/slots/vo-mcp-\u2026/` shape.\n */\nexport function isSlotCli(cliPath: string, runtimeRoot: string | null = null): boolean {\n if (runtimeRoot) {\n const prefix = normalize(join(runtimeRoot, 'slots')) + sep;\n const candidate = normalize(cliPath);\n const under = process.platform === 'win32' ? candidate.toLowerCase().startsWith(prefix.toLowerCase()) : candidate.startsWith(prefix);\n return under && /^vo-mcp-[0-9A-Za-z._-]{1,96}$/u.test(candidate.slice(prefix.length).split(/[\\\\/]/u)[0] ?? '');\n }\n return /[\\\\/]slots[\\\\/]vo-mcp-[0-9A-Za-z._-]{1,96}[\\\\/]/iu.test(cliPath);\n}\n\n/**\n * Which cli.js to record as the launcher's fallback (null = record none: the\n * launcher then exits 2 \u2014 loudly \u2014 when no slot resolves). Never a slot path.\n * `vo-mcp install` (explicit) refreshes to THIS package's cli.js. The daemon-boot\n * heal is STICKY: it keeps an existing non-slot fallback that still exists, so a\n * boot never rewrites (and backs up) the operator's config just because the\n * runtime moved \u2014 only a missing/broken/slot fallback is repaired.\n */\nexport function chooseFallbackCli(existing: string | undefined, cliPath: string, sticky: boolean, runtimeRoot: string | null = null): string | null {\n const current = String(existing ?? '').trim();\n if (sticky && current && !isSlotCli(current, runtimeRoot) && existsSync(current)) return current;\n return isSlotCli(cliPath, runtimeRoot) ? null : cliPath;\n}\n", "/**\n * Cross-platform auto-start registration for `vo-mcp runner`.\n *\n * WINDOWS: Uses the user Startup folder, NOT Task Scheduler. Headless\n * `claude -p` (which the runner spawns) HANGS under the Task Scheduler\n * service session \u2014 it only runs from an interactive, Explorer-descended\n * session. The Startup folder launches the runner HIDDEN at user login via a\n * .vbs shim (wscript is windowless; a .cmd launcher always parks a console on\n * the taskbar \u2014 `start /min` minimizes, it does not hide).\n *\n * MACOS: Uses ~/Library/LaunchAgents (launchd) with RunAtLoad + KeepAlive.\n *\n * LINUX: Uses ~/.config/systemd/user (systemd user unit) with Restart=on-failure;\n * ExecStart runs via a login shell so the npm-global `vo-mcp` resolves on PATH.\n *\n * All operations are idempotent and create backups where applicable.\n */\nimport { homedir, platform } from 'node:os';\nimport { isAbsolute, join } from 'node:path';\nimport { existsSync, mkdirSync, writeFileSync, readFileSync, unlinkSync, copyFileSync } from 'node:fs';\n\nexport interface AutostartOptions {\n readonly log?: (msg: string) => void;\n readonly runnerCommand?: string; // Override for tests\n readonly env?: Readonly<Record<string, string | undefined>>;\n /**\n * Override the detected platform. Injectable ONLY so the Windows branch can be\n * exercised on a Linux CI runner \u2014 every Windows assertion in autostart.test.ts\n * used to early-return on ubuntu-latest, so no Windows autostart behaviour was\n * verified anywhere.\n */\n readonly platform?: NodeJS.Platform;\n}\n\n/**\n * Base restart backoff for the Windows keepalive loop \u2014 short enough that a real\n * crash recovers well within a heartbeat interval.\n */\nconst WINDOWS_RESTART_BACKOFF_MS = 10_000;\n\n/**\n * A run lasting at least this long counts as HEALTHY and resets the backoff.\n * Anything shorter is treated as a fast-fail and doubles the wait.\n */\nconst WINDOWS_HEALTHY_RUN_MS = 60_000;\n\n/**\n * Ceiling for the escalating backoff. Without one, a permanently broken runner\n * (missing credential, bad install) would relaunch every 10s forever \u2014 ~8,600\n * restarts a day, each appending to vo-runner.log. That is a disk-fill risk on a\n * machine nobody is watching, which is the whole premise here. launchd throttles\n * to a 10s floor and systemd has StartLimitBurst for the same reason.\n */\nconst WINDOWS_MAX_BACKOFF_MS = 300_000;\n\n/**\n * Resolve the path to the vo-mcp runner command. Defaults to 'vo-mcp runner'\n * (assumes it's in PATH). Can be overridden for tests.\n */\nfunction resolveRunnerCommand(override?: string): string {\n return override ?? 'vo-mcp runner';\n}\n\n/** Preserve one command string as a single POSIX shell argument. */\nfunction quotePosixShellArgument(value: string): string {\n if (value.includes('\\u0000') || value.includes('\\r') || value.includes('\\n')) {\n throw new Error('Runner command must not contain NUL, carriage return, or newline characters.');\n }\n return `'${value.replace(/'/gu, `'\"'\"'`)}'`;\n}\n\n/**\n * Resolve the freedesktop config root used by both the systemd user unit and\n * the runner's managed clone directory. XDG_CONFIG_HOME is valid only when it\n * is absolute; a relative value falls back to the documented ~/.config root.\n */\nfunction resolveLinuxConfigHome(\n home: string,\n env: Readonly<Record<string, string | undefined>>,\n): string {\n const configured = env['XDG_CONFIG_HOME']?.trim();\n return configured && isAbsolute(configured) ? configured : join(home, '.config');\n}\n\n/**\n * A managed launcher is current only when every byte matches the template.\n * Matching the command substring cannot distinguish an up-to-date launcher\n * from an older broken version that happens to invoke the same command.\n */\nfunction launcherIsCurrent(\n path: string,\n desiredContent: string,\n label: string,\n log: (msg: string) => void,\n): boolean {\n if (!existsSync(path)) return false;\n if (readFileSync(path, 'utf8') === desiredContent) return true;\n const backupPath = `${path}.backup-${Date.now()}`;\n copyFileSync(path, backupPath);\n log(` Backed up existing ${label} to: ${backupPath}`);\n return false;\n}\n\n/**\n * Windows: Install a launcher script in the Startup folder.\n *\n * Creates a .vbs file that starts `vo-mcp runner` with a hidden window\n * (WScript.Shell.Run window style 0 \u2014 wscript itself never shows a window,\n * unlike a .cmd whose console `start /min` only minimizes). The Startup\n * folder is %APPDATA%\\Microsoft\\Windows\\Start Menu\\Programs\\Startup\\.\n */\nfunction installWindowsAutostart(runnerCommand: string, log: (msg: string) => void, env: Readonly<Record<string, string | undefined>>): void {\n const appData = env['APPDATA'] ?? join(homedir(), 'AppData', 'Roaming');\n const startupDir = join(appData, 'Microsoft', 'Windows', 'Start Menu', 'Programs', 'Startup');\n mkdirSync(startupDir, { recursive: true });\n\n const launcherPath = join(startupDir, 'vo-runner.vbs');\n const legacyCmdPath = join(startupDir, 'vo-runner.cmd');\n\n // Migrate: drop the pre-.vbs minimized launcher so logon can't start two runners.\n // Best-effort \u2014 an ACL-blocked/locked .cmd must not prevent installing the .vbs.\n if (existsSync(legacyCmdPath)) {\n try {\n unlinkSync(legacyCmdPath);\n log(` Removed legacy minimized .cmd launcher: ${legacyCmdPath}`);\n } catch (error) {\n log(`\u26A0 Could not remove legacy launcher ${legacyCmdPath} (${error instanceof Error ? error.message : String(error)}); remove it manually to avoid a double start`);\n }\n }\n\n // Write the launcher. VBS escapes embedded double quotes by doubling them.\n // The hidden window discards stdio, so redirect the runner's output to the\n // same log file the macOS plist and Linux unit use \u2014 otherwise every\n // [orphan-sweep]/[orphan-reaper] warning on Windows lands nowhere.\n const hiddenCommand = `cmd /c ${runnerCommand} >> \"%USERPROFILE%\\\\.claude\\\\vo-runner.log\" 2>&1`.replace(/\"/g, '\"\"');\n // KEEPALIVE. Windows was the ONLY platform with no restart supervision: macOS\n // sets launchd `KeepAlive`, Linux sets systemd `Restart=on-failure`, and this\n // was `.Run(..., 0, False)` \u2014 fire-and-forget. If the runner died mid-session\n // nothing restarted it until the next logon, which is why a Windows host could\n // sit dead for hours (2026-07-25) with no way to reach it.\n //\n // `True` makes .Run WAIT for the process, turning this into a supervisor loop.\n // The sleep is a restart backoff so a runner failing instantly cannot spin hot.\n //\n // The stop-sentinel is the escape hatch: wscript has no console, so without it\n // the only way to stop the loop is Task Manager. The file is CONSUMED (deleted)\n // once honoured, so a later logon starts clean instead of silently refusing.\n const launcherContent = `' Auto-start launcher for vo-mcp runner\n' Created by vo-mcp autostart installer\n' Keepalive supervisor: restarts the runner if it exits (parity with launchd\n' KeepAlive on macOS and systemd Restart=on-failure on Linux).\n' To stop: create %USERPROFILE%\\\\.claude\\\\vo-runner.stop, or end wscript.exe.\nDim sh, fso, stopFile, backoff, startedAt, ranMs\nSet sh = CreateObject(\"WScript.Shell\")\nSet fso = CreateObject(\"Scripting.FileSystemObject\")\nsh.CurrentDirectory = sh.ExpandEnvironmentStrings(\"%USERPROFILE%\")\nsh.Environment(\"Process\")(\"VO_CODE_RUNNER_CLONES_ROOT\") = sh.ExpandEnvironmentStrings(\"%APPDATA%\\\\ai.algosuite.vo-runner\\\\clones\")\nstopFile = sh.ExpandEnvironmentStrings(\"%USERPROFILE%\\\\.claude\\\\vo-runner.stop\")\nbackoff = ${WINDOWS_RESTART_BACKOFF_MS}\nDo\n If fso.FileExists(stopFile) Then\n fso.DeleteFile stopFile\n WScript.Quit 0\n End If\n startedAt = Timer\n sh.Run \"${hiddenCommand}\", 0, True\n ranMs = (Timer - startedAt) * 1000\n If ranMs < 0 Then ranMs = ${WINDOWS_HEALTHY_RUN_MS}\n If ranMs >= ${WINDOWS_HEALTHY_RUN_MS} Then\n backoff = ${WINDOWS_RESTART_BACKOFF_MS}\n ElseIf backoff < ${WINDOWS_MAX_BACKOFF_MS} Then\n backoff = backoff * 2\n End If\n WScript.Sleep backoff\nLoop\n`;\n\n if (launcherIsCurrent(launcherPath, launcherContent, 'launcher', log)) {\n log(`\u2713 Auto-start is already configured (Windows Startup folder)`);\n log(` Path: ${launcherPath}`);\n return;\n }\n\n writeFileSync(launcherPath, launcherContent, 'utf8');\n log(`\u2713 Installed Windows auto-start launcher`);\n log(` Path: ${launcherPath}`);\n log(` The runner will start hidden at next login.`);\n}\n\n/**\n * Windows: Uninstall the Startup folder launcher.\n */\nfunction uninstallWindowsAutostart(log: (msg: string) => void, env: Readonly<Record<string, string | undefined>>): void {\n const appData = env['APPDATA'] ?? join(homedir(), 'AppData', 'Roaming');\n const startupDir = join(appData, 'Microsoft', 'Windows', 'Start Menu', 'Programs', 'Startup');\n // Remove the current .vbs launcher AND any legacy .cmd from older installs.\n const launcherPaths = [join(startupDir, 'vo-runner.vbs'), join(startupDir, 'vo-runner.cmd')];\n\n let removedAny = false;\n for (const launcherPath of launcherPaths) {\n if (!existsSync(launcherPath)) continue;\n unlinkSync(launcherPath);\n removedAny = true;\n log(`\u2713 Removed Windows auto-start launcher`);\n log(` Path: ${launcherPath}`);\n }\n if (!removedAny) {\n log(`\u2713 Auto-start launcher not found (already removed)`);\n }\n}\n\n/**\n * macOS: Install a launchd plist in ~/Library/LaunchAgents.\n *\n * The plist runs `vo-mcp runner` at login with RunAtLoad=true and\n * KeepAlive=true (restarts if it crashes).\n */\nasync function installMacAutostart(\n runnerCommand: string,\n log: (msg: string) => void,\n env: Readonly<Record<string, string | undefined>>,\n): Promise<void> {\n const home = env['HOME']?.trim() || homedir();\n const launchAgentsDir = join(home, 'Library', 'LaunchAgents');\n mkdirSync(launchAgentsDir, { recursive: true });\n\n const plistPath = join(launchAgentsDir, 'ai.algosuite.vo-runner.plist');\n\n // Parse the runner command into program + args for launchd\n const parts = runnerCommand.split(/\\s+/);\n const program = parts[0] ?? 'vo-mcp';\n const args = parts.length > 1 ? parts.slice(1) : ['runner'];\n\n const plistContent = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n <key>Label</key>\n <string>ai.algosuite.vo-runner</string>\n <key>ProgramArguments</key>\n <array>\n <string>${program}</string>\n${args.map((a) => ` <string>${a}</string>`).join('\\n')}\n </array>\n <key>RunAtLoad</key>\n <true/>\n <key>KeepAlive</key>\n <true/>\n <key>WorkingDirectory</key>\n <string>${home}</string>\n <key>EnvironmentVariables</key>\n <dict>\n <key>VO_CODE_RUNNER_CLONES_ROOT</key>\n <string>${join(home, 'Library', 'Application Support', 'ai.algosuite.vo-runner', 'clones')}</string>\n </dict>\n <key>StandardOutPath</key>\n <string>${join(home, '.claude', 'vo-runner.log')}</string>\n <key>StandardErrorPath</key>\n <string>${join(home, '.claude', 'vo-runner-error.log')}</string>\n</dict>\n</plist>\n`;\n\n if (launcherIsCurrent(plistPath, plistContent, 'plist', log)) {\n log(`\u2713 Auto-start is already configured (launchd)`);\n log(` Path: ${plistPath}`);\n return;\n }\n\n writeFileSync(plistPath, plistContent, 'utf8');\n log(`\u2713 Installed launchd plist`);\n log(` Path: ${plistPath}`);\n\n // Load the plist with launchctl\n try {\n const { execSync } = await import('node:child_process');\n execSync(`launchctl load \"${plistPath}\"`, { stdio: 'ignore' });\n log(`\u2713 Loaded plist with launchctl (runner will start at next login)`);\n log(` Logs: ${join(home, '.claude', 'vo-runner.log')}`);\n } catch {\n log(`\u26A0 Failed to load plist with launchctl (you may need to load it manually)`);\n log(` Run: launchctl load \"${plistPath}\"`);\n }\n}\n\n/**\n * macOS: Uninstall the launchd plist.\n */\nasync function uninstallMacAutostart(\n log: (msg: string) => void,\n env: Readonly<Record<string, string | undefined>>,\n): Promise<void> {\n const home = env['HOME']?.trim() || homedir();\n const launchAgentsDir = join(home, 'Library', 'LaunchAgents');\n const plistPath = join(launchAgentsDir, 'ai.algosuite.vo-runner.plist');\n\n if (!existsSync(plistPath)) {\n log(`\u2713 Auto-start plist not found (already removed)`);\n return;\n }\n\n // Unload the plist with launchctl\n try {\n const { execSync } = await import('node:child_process');\n execSync(`launchctl unload \"${plistPath}\"`, { stdio: 'ignore' });\n log(`\u2713 Unloaded plist with launchctl`);\n } catch {\n log(`\u26A0 Failed to unload plist with launchctl (continuing anyway)`);\n }\n\n unlinkSync(plistPath);\n log(`\u2713 Removed launchd plist`);\n log(` Path: ${plistPath}`);\n}\n\n/**\n * Linux: Install a systemd USER unit at\n * $XDG_CONFIG_HOME/systemd/user/vo-runner.service (default ~/.config),\n * then enable + start it (`systemctl --user enable --now`). Restart=on-failure\n * mirrors the macOS KeepAlive. ExecStart runs via a login shell so the npm-global\n * `vo-mcp` resolves under systemd's minimal PATH.\n */\nasync function installLinuxAutostart(\n runnerCommand: string,\n log: (msg: string) => void,\n env: Readonly<Record<string, string | undefined>>,\n): Promise<void> {\n const home = env['HOME']?.trim() || homedir();\n const configHome = resolveLinuxConfigHome(home, env);\n const unitDir = join(configHome, 'systemd', 'user');\n mkdirSync(unitDir, { recursive: true });\n const unitPath = join(unitDir, 'vo-runner.service');\n\n const logFile = join(home, '.claude', 'vo-runner.log');\n const errFile = join(home, '.claude', 'vo-runner-error.log');\n const quotedRunnerCommand = quotePosixShellArgument(runnerCommand);\n mkdirSync(join(home, '.claude'), { recursive: true });\n\n const unit = `[Unit]\nDescription=AlgoHQ Code Runner (vo-mcp)\nAfter=network-online.target\nWants=network-online.target\n\n[Service]\nType=simple\nWorkingDirectory=${home}\nEnvironment=\"VO_CODE_RUNNER_CLONES_ROOT=${join(configHome, 'ai.algosuite.vo-runner', 'clones')}\"\nExecStart=/bin/sh -lc ${quotedRunnerCommand}\nRestart=on-failure\nRestartSec=10\nStandardOutput=append:${logFile}\nStandardError=append:${errFile}\n\n[Install]\nWantedBy=default.target\n`;\n if (launcherIsCurrent(unitPath, unit, 'unit', log)) {\n log(`\u2713 Auto-start is already configured (systemd user unit)`);\n log(` Path: ${unitPath}`);\n return;\n }\n writeFileSync(unitPath, unit, 'utf8');\n log(`\u2713 Installed systemd user unit`);\n log(` Path: ${unitPath}`);\n\n // In tests, write the unit but NEVER actually enable/start a real service.\n if (process.env['VITEST']) {\n log(` (test mode: skipping systemctl enable)`);\n return;\n }\n try {\n const { execSync } = await import('node:child_process');\n execSync('systemctl --user daemon-reload', { stdio: 'ignore' });\n execSync('systemctl --user enable --now vo-runner.service', { stdio: 'ignore' });\n log(`\u2713 Enabled + started vo-runner.service (starts at login)`);\n log(` Logs: ${logFile}`);\n } catch {\n log(`\u26A0 Could not enable via systemctl (enable it manually):`);\n log(` systemctl --user daemon-reload && systemctl --user enable --now vo-runner.service`);\n }\n}\n\n/**\n * Linux: Uninstall the systemd user unit.\n */\nasync function uninstallLinuxAutostart(\n log: (msg: string) => void,\n env: Readonly<Record<string, string | undefined>>,\n): Promise<void> {\n const home = env['HOME']?.trim() || homedir();\n const configHome = resolveLinuxConfigHome(home, env);\n const unitPath = join(configHome, 'systemd', 'user', 'vo-runner.service');\n if (!existsSync(unitPath)) {\n log(`\u2713 Auto-start unit not found (already removed)`);\n return;\n }\n if (!process.env['VITEST']) {\n try {\n const { execSync } = await import('node:child_process');\n execSync('systemctl --user disable --now vo-runner.service', { stdio: 'ignore' });\n log(`\u2713 Disabled + stopped vo-runner.service`);\n } catch {\n log(`\u26A0 Could not disable via systemctl (continuing anyway)`);\n }\n }\n unlinkSync(unitPath);\n log(`\u2713 Removed systemd user unit`);\n log(` Path: ${unitPath}`);\n}\n\n/**\n * Install auto-start for the runner daemon. Cross-platform.\n */\nexport async function installAutostart(opts: AutostartOptions = {}): Promise<void> {\n const log = opts.log ?? ((m: string) => console.error(m));\n const env = opts.env ?? process.env;\n const runnerCommand = resolveRunnerCommand(opts.runnerCommand);\n const plat = opts.platform ?? platform();\n\n if (plat === 'win32') {\n installWindowsAutostart(runnerCommand, log, env);\n } else if (plat === 'darwin') {\n await installMacAutostart(runnerCommand, log, env);\n } else if (plat === 'linux') {\n await installLinuxAutostart(runnerCommand, log, env);\n } else {\n log(`\u2717 Auto-start is not supported on platform: ${plat}`);\n log(` Supported platforms: win32 (Windows), darwin (macOS), linux (Linux)`);\n }\n}\n\n/**\n * Uninstall auto-start for the runner daemon. Cross-platform.\n */\nexport async function uninstallAutostart(opts: AutostartOptions = {}): Promise<void> {\n const log = opts.log ?? ((m: string) => console.error(m));\n const env = opts.env ?? process.env;\n const plat = opts.platform ?? platform();\n\n if (plat === 'win32') {\n uninstallWindowsAutostart(log, env);\n } else if (plat === 'darwin') {\n await uninstallMacAutostart(log, env);\n } else if (plat === 'linux') {\n await uninstallLinuxAutostart(log, env);\n } else {\n log(`\u2717 Auto-start is not supported on platform: ${plat}`);\n log(` Supported platforms: win32 (Windows), darwin (macOS), linux (Linux)`);\n }\n}\n", "#!/usr/bin/env node\n/**\n * `vo-mcp install` CLI entry point.\n *\n * Usage:\n * npx @algosuite/vo-mcp@beta install\n * vo-mcp install\n * vo-mcp install --config-only\n */\nimport { install, installOptionsFromArgs } from './install.js';\n\ninstall(installOptionsFromArgs(process.argv.slice(2))).catch((err: unknown) => {\n console.error('[vo-mcp install] fatal:', err);\n process.exit(1);\n});\n"],
5
+ "mappings": "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",
6
+ "names": ["homedir", "platform", "join", "dirname", "existsSync", "readFileSync", "mkdirSync", "statSync", "credentialPath", "existsSync", "mkdirSync", "readFileSync", "statSync", "dirname", "join", "chmodSync", "existsSync", "readFileSync", "writeFileSync", "dirname", "join", "existsSync", "mkdirSync", "readFileSync", "writeFileSync", "homedir", "join", "platform", "join", "existsSync", "readFileSync", "statSync", "backupPath", "mkdirSync", "dirname", "homedir", "platform", "isAbsolute", "join", "existsSync", "mkdirSync", "writeFileSync", "readFileSync", "unlinkSync", "copyFileSync", "homedir", "join", "mkdirSync", "writeFileSync", "homedir", "join", "mkdirSync", "writeFileSync", "platform", "DEFAULT_CONTROL_PLANE_URL", "join", "existsSync", "statSync", "readFileSync", "mkdirSync", "dirname", "homedir", "platform", "platform"]
7
7
  }