@algosuite/vo-mcp 0.2.0-beta.0 → 0.2.0-beta.10

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.
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/runner/control-plane-auth-stub.mjs", "../src/runner-supervisor.mjs", "../../../scripts/virtual-office/code-runner/control-plane-client.mjs", "../../../scripts/virtual-office/code-runner/runner-host-maintenance.mjs", "../src/runner/supervisor-child-env.mjs", "../src/runner-readiness.mjs", "../src/runner/supervisor-credential-reader.mjs"],
4
+ "sourcesContent": ["/**\n * Control-plane auth stub for the bundled `vo-mcp runner`.\n *\n * Replaces the daemon's lazy Firebase/SMOKE_* fallback\n * (`scripts/virtual-office/orchestrator-firestore/auth.mjs`), which pulls\n * `vo-config.mjs` (hardcoded Nexus Firebase project) + the firebase-admin chain.\n * A BYO runner ALWAYS authenticates with its own scoped `vo_credential` \u2014 read\n * from the OS keychain by `runner-cli.mjs` and injected as\n * `VO_CONTROL_PLANE_ADMIN_TOKEN` \u2014 so `control-plane-client.mjs`'s `resolveBearer`\n * returns early on the token and NEVER reaches this fallback. It exists only so\n * the bundle has nothing to resolve into the firebase chain; if it ever runs,\n * it fails LOUDLY with the fix.\n *\n * esbuild swaps this in for the heavy original at bundle time (see scripts/bundle.mjs).\n */\nexport async function getFirebaseAuth() {\n throw new Error(\n 'vo-mcp runner: no control-plane credential. Run `vo-mcp login` first \u2014 the runner ' +\n 'authenticates with your stored vo_credential (or set VO_CONTROL_PLANE_ADMIN_TOKEN).',\n );\n}\n", "/**\n * Persistent host supervisor for remote Mission Control maintenance.\n * The task daemon is a replaceable child; this process stays alive while it is\n * updated or repaired. Pairing credentials remain in the existing OS store.\n */\nimport { spawn } from 'node:child_process';\nimport { createRequire } from 'node:module';\nimport { fileURLToPath } from 'node:url';\nimport { dirname, join } from 'node:path';\nimport { createControlPlaneClient } from '../../../scripts/virtual-office/code-runner/control-plane-client.mjs';\nimport { runHostMaintenance } from '../../../scripts/virtual-office/code-runner/runner-host-maintenance.mjs';\nimport { prepareSupervisorAuth, resolveSupervisorRunnerId } from './runner/supervisor-child-env.mjs';\nimport { readStoredCredentialIsolated } from './runner/supervisor-credential-reader.mjs';\n\nconst DEFAULT_CONTROL_PLANE_URL = 'https://vo-control-plane-bzjphrajaq-uc.a.run.app';\nconst POLL_MS = 5000;\nconst CHILD_START_MS = 1500;\nconst childEntry = join(dirname(fileURLToPath(import.meta.url)), 'runner-cli.js');\nconst sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));\n\nconst runnerId = resolveSupervisorRunnerId(process.env);\n\nfunction packageVersion() {\n try { return createRequire(import.meta.url)('../package.json').version || 'unknown'; } catch { return 'unknown'; }\n}\n\nfunction spawnChild(childEnv) {\n return spawn(process.execPath, [childEntry], {\n env: childEnv,\n stdio: 'inherit',\n windowsHide: true,\n });\n}\n\nasync function localStatus() {\n try {\n const port = Number(process.env.VO_CODE_RUNNER_CONTROL_PORT || 7787);\n const response = await fetch(`http://127.0.0.1:${port}/status`, { signal: AbortSignal.timeout(800) });\n if (!response.ok) return null;\n const body = await response.json();\n return body?.ok === true ? body : null;\n } catch {\n return null;\n }\n}\n\nasync function waitForLocalRunner(child) {\n const deadline = Date.now() + 15_000;\n while (Date.now() < deadline) {\n if (child.exitCode !== null) return false;\n if ((await localStatus())?.running === true) return true;\n await sleep(500);\n }\n return false;\n}\n\nasync function stopChild(child) {\n if (!child || child.exitCode !== null) return;\n child.kill(process.platform === 'win32' ? undefined : 'SIGTERM');\n await Promise.race([\n new Promise((resolve) => child.once('exit', resolve)),\n sleep(15_000),\n ]);\n if (child.exitCode === null) child.kill('SIGKILL');\n}\n\nasync function main() {\n // Read keychain-backed credentials in a process that exits before npm ever\n // attempts to replace this package. Windows otherwise keeps the keyring DLL\n // locked for the full supervisor lifetime and global self-updates fail.\n const stored = readStoredCredentialIsolated();\n const controlPlaneUrl = process.env.VO_CONTROL_PLANE_URL || DEFAULT_CONTROL_PLANE_URL;\n const { childEnv, clientEnv, operatorId } = await prepareSupervisorAuth({\n baseEnv: process.env,\n storedCredential: stored,\n controlPlaneUrl,\n });\n const client = createControlPlaneClient({ baseUrl: controlPlaneUrl, env: clientEnv });\n let child = spawnChild(childEnv);\n let stopping = false;\n let handling = false;\n\n const respawn = () => {\n if (!stopping && !handling && (!child || child.exitCode !== null)) child = spawnChild(childEnv);\n };\n child.on('exit', () => setTimeout(respawn, 2000));\n\n const shutdown = async () => {\n if (stopping) return;\n stopping = true;\n await stopChild(child);\n };\n process.on('SIGINT', () => { void shutdown().finally(() => process.exit(0)); });\n process.on('SIGTERM', () => { void shutdown().finally(() => process.exit(0)); });\n\n while (!stopping) {\n try {\n const action = await client.pollRunnerControl({ runnerId, ...(operatorId ? { operatorId } : {}) });\n if (!action) {\n await sleep(POLL_MS);\n continue;\n }\n handling = true;\n const beforeStop = await localStatus();\n if (beforeStop && Number(beforeStop.activeTasks || 0) > 0) {\n await client.completeRunnerControl(action.actionId, {\n runnerId,\n ...(operatorId ? { operatorId } : {}),\n status: 'failed',\n detail: `deferred safely: ${beforeStop.activeTasks} active task(s); retry when the runner is idle`,\n });\n handling = false;\n continue;\n }\n await stopChild(child);\n const result = runHostMaintenance(action.kind, {\n env: clientEnv,\n log: (message) => console.warn(`[vo-runner supervisor] ${message}`),\n });\n child = spawnChild(childEnv);\n await sleep(CHILD_START_MS);\n if (child.exitCode !== null || !(await waitForLocalRunner(child))) result.ok = false;\n await client.completeRunnerControl(action.actionId, {\n runnerId,\n ...(operatorId ? { operatorId } : {}),\n status: result.ok ? 'succeeded' : 'failed',\n detail: result.ok\n ? `runner ${packageVersion()} reconnected`\n : `maintenance exited ${result.status}${result.detail ? `: ${result.detail}` : ''}`,\n });\n handling = false;\n } catch (error) {\n console.error(`[vo-runner supervisor] ${error instanceof Error ? error.message : String(error)}`);\n handling = false;\n await sleep(POLL_MS);\n }\n }\n}\n\nmain().catch((error) => {\n console.error(`[vo-runner supervisor] fatal: ${error instanceof Error ? error.message : String(error)}`);\n process.exitCode = 1;\n});\n", "/**\n * control-plane-client \u2014 the runner's OUTBOUND link to vo-control-plane.\n *\n * Increment 6 (Code-from-Anywhere). The daemon never exposes a port; it reaches\n * OUT to the control-plane (no inbound hole, no Tailscale \u2014 design \u00A72). Auth:\n * prefer the static admin token (`VO_CONTROL_PLANE_ADMIN_TOKEN`, the V1 local\n * dogfood path); fall back to a per-user Firebase ID token via the shared\n * orchestrator auth (`SMOKE_*` creds \u2192 allow-listed operator \u2192 admin).\n *\n * Endpoints used:\n * POST /api/v1/code-task/claim \u2192 claim the next pending task\n * PATCH /api/v1/code-task/:id/progress \u2192 stream progress / set terminal\n * GET /api/v1/code-task/:id \u2192 poll status (cancel detection)\n * POST /api/v1/code-task/:id/resume \u2192 continue a partial/max-turn task\n * POST /api/v1/admin/pr/merge \u2192 CI-green exact-SHA consensus merge\n */\n\nlet cachedFirebaseToken = null;\n\nasync function resolveBearer(env) {\n const adminToken = env.VO_CONTROL_PLANE_ADMIN_TOKEN;\n if (adminToken) return adminToken;\n if (cachedFirebaseToken) return cachedFirebaseToken;\n // Lazy import \u2014 Firebase auth is only needed when no admin token is present.\n const { getFirebaseAuth } = await import('../orchestrator-firestore/auth.mjs');\n const auth = await getFirebaseAuth({ env });\n if (!auth || !auth.idToken) {\n throw new Error(\n 'no control-plane credential: set VO_CONTROL_PLANE_ADMIN_TOKEN, or SMOKE_EMAIL/SMOKE_PASSWORD/SMOKE_API_KEY',\n );\n }\n cachedFirebaseToken = auth.idToken;\n return cachedFirebaseToken;\n}\n\n/**\n * Build a client. `baseUrl` defaults to `VO_CONTROL_PLANE_URL`. `fetchImpl`\n * and `env` are injectable for tests.\n */\nexport function createControlPlaneClient({\n baseUrl = process.env.VO_CONTROL_PLANE_URL || '',\n env = process.env,\n fetchImpl = fetch,\n} = {}) {\n if (!baseUrl) {\n throw new Error('VO_CONTROL_PLANE_URL is required for the code-runner daemon');\n }\n const root = baseUrl.replace(/\\/+$/, '');\n\n async function req(method, path, body) {\n const bearer = await resolveBearer(env);\n return fetchImpl(`${root}${path}`, {\n method,\n headers: {\n 'content-type': 'application/json',\n authorization: `Bearer ${bearer}`,\n },\n body: body === undefined ? undefined : JSON.stringify(body),\n });\n }\n\n return {\n /**\n * Claim the next pending task. Returns the task or null (empty queue).\n * `repos` (optional `owner/name` list) and `operatorIds` (optional\n * `operator_id` list) scope the claim so this daemon only picks up tasks it\n * serves \u2014 the control-plane filters by both (logical AND), so another\n * operator's task never lands on (or bills) this machine.\n */\n async claim(runnerId, repos, operatorIds, session = {}) {\n const body = { runner_id: runnerId };\n if (Array.isArray(repos) && repos.length > 0) body.repos = repos;\n if (Array.isArray(operatorIds) && operatorIds.length > 0) body.operator_ids = operatorIds;\n if (session.runnerInstanceId) body.runner_instance_id = session.runnerInstanceId;\n if (session.runnerInstanceId && session.reconcileStale) body.reconcile_stale = true;\n const res = await req('POST', '/api/v1/code-task/claim', body);\n if (res.status === 401) {\n cachedFirebaseToken = null; // force re-auth next call\n throw new Error('claim unauthorized (401)');\n }\n if (!res.ok) throw new Error(`claim failed: HTTP ${res.status}`);\n const json = await res.json();\n return json && json.task ? json.task : null;\n },\n\n /**\n * Enqueue a new code-task (used by the PR watcher to auto-dispatch a CI fix).\n * Server derives operator/tenant from the daemon's authenticated principal.\n * Returns the created task, or throws on a non-2xx response.\n */\n async enqueueCodeTask({ repo, prompt, max_budget_usd, max_turns }) {\n const body = { repo, prompt };\n if (typeof max_budget_usd === 'number') body.max_budget_usd = max_budget_usd;\n if (typeof max_turns === 'number') body.max_turns = max_turns;\n const res = await req('POST', '/api/v1/code-task', body);\n if (res.status === 401) {\n cachedFirebaseToken = null;\n throw new Error('enqueue unauthorized (401)');\n }\n if (!res.ok) throw new Error(`enqueue failed: HTTP ${res.status}`);\n const json = await res.json();\n return json && json.task ? json.task : null;\n },\n\n /**\n * Resume a failed/cancelled/max-turn partial code-task. The PR watcher uses\n * this after the runner opens a partial draft PR and CI is no longer pending.\n */\n async resumeCodeTask(taskId) {\n const res = await req('POST', `/api/v1/code-task/${encodeURIComponent(taskId)}/resume`, {});\n if (res.status === 401) {\n cachedFirebaseToken = null;\n throw new Error('resume unauthorized (401)');\n }\n if (!res.ok) throw new Error(`resume failed: HTTP ${res.status}`);\n const json = await res.json();\n return json && json.task ? json.task : null;\n },\n\n /**\n * Send a CI-green PR through the production verify-before-act merge route.\n * The server inspects the current diff, applies deterministic blockers, runs\n * consensus, records a receipt, and direct-merges only the inspected SHA.\n */\n async mergeVerifiedPr(prNumber, automationContext) {\n const res = await req('POST', '/api/v1/admin/pr/merge', { prNumber, automationContext });\n if (res.status === 401) {\n cachedFirebaseToken = null;\n throw new Error('gated merge unauthorized (401)');\n }\n const json = await res.json().catch(() => ({}));\n if (res.ok && json?.ok === true) {\n const result = json?.result && typeof json.result === 'object' ? json.result : {};\n const status = result.merged === true || result.status === 'merged'\n ? 'merged'\n : result.status === 'auto-merge-enabled' || String(result.action || '').includes('auto-merge')\n ? 'queued'\n : 'accepted';\n return {\n status,\n detail: typeof result.detail === 'string' ? result.detail : null,\n actionReceiptId: typeof json.action_receipt_id === 'string' ? json.action_receipt_id : null,\n };\n }\n if (res.status === 503 && json?.error === 'verify_unavailable') {\n return { status: 'retry', reason: json.reason || 'verification unavailable' };\n }\n return {\n status: 'blocked',\n reason: json?.reason || json?.message || json?.error || `HTTP ${res.status}`,\n actionReceiptId: typeof json?.action_receipt_id === 'string' ? json.action_receipt_id : null,\n };\n },\n\n /**\n * Append progress / set terminal status. Returns\n * { task } \u2014 applied\n * { terminal: true } \u2014 task already terminal (operator cancelled): STOP\n */\n async postProgress(taskId, patch) {\n const res = await req('PATCH', `/api/v1/code-task/${taskId}/progress`, patch);\n if (res.status === 409) return { terminal: true };\n if (res.status === 404) return { terminal: true, missing: true };\n if (!res.ok) throw new Error(`progress failed: HTTP ${res.status}`);\n const json = await res.json();\n return { task: json && json.task };\n },\n\n /** Read the current task (cancel detection). Null on 404. */\n async getTask(taskId) {\n const res = await req('GET', `/api/v1/code-task/${taskId}`);\n if (res.status === 404) return null;\n if (!res.ok) throw new Error(`getTask failed: HTTP ${res.status}`);\n const json = await res.json();\n return json ? json.task : null;\n },\n\n /** Fetch bounded, prompt-ready AlgoHQ knowledge snippets for this task. */\n async getTaskKnowledgeContext(taskId, { query } = {}) {\n const body = {};\n if (typeof query === 'string' && query.trim()) body.query = query;\n const res = await req('POST', `/api/v1/code-task/${encodeURIComponent(taskId)}/knowledge-context`, body);\n if (res.status === 401) {\n cachedFirebaseToken = null;\n throw new Error('knowledge-context unauthorized (401)');\n }\n if (res.status === 404) return null;\n if (!res.ok) throw new Error(`knowledge-context failed: HTTP ${res.status}`);\n return res.json();\n },\n\n /**\n * Report this machine's rolling-7-day Claude Code token usage (the real\n * weekly-capacity gauge) PLUS the operator's real Claude weekly % (when\n * available). The daemon authenticates as admin, so the target `operatorId`\n * is named explicitly. Best-effort; throws on a non-2xx so the caller can\n * log + move on.\n *\n * `tokens` = { input_tokens, output_tokens, cache_creation_tokens, cache_read_tokens }.\n * Optional: `claudeWeeklyPct` (number) + `claudeWeeklyResetsAt` (ISO string | null).\n */\n async postWeeklyTokens({ operatorId, runnerId, tokens, claudeWeeklyPct, claudeWeeklyResetsAt }) {\n const body = {\n operator_id: operatorId,\n runner_id: runnerId,\n input_tokens: tokens.input_tokens,\n output_tokens: tokens.output_tokens,\n cache_creation_tokens: tokens.cache_creation_tokens,\n cache_read_tokens: tokens.cache_read_tokens,\n };\n if (typeof claudeWeeklyPct === 'number') {\n body.claude_weekly_pct = claudeWeeklyPct;\n }\n if (claudeWeeklyResetsAt !== undefined) {\n body.claude_weekly_resets_at = claudeWeeklyResetsAt;\n }\n const res = await req('POST', '/api/v1/weekly-tokens', body);\n if (res.status === 401) {\n cachedFirebaseToken = null;\n throw new Error('weekly-tokens unauthorized (401)');\n }\n if (!res.ok) throw new Error(`weekly-tokens failed: HTTP ${res.status}`);\n return true;\n },\n\n /**\n * Send a liveness heartbeat (M2). The control-plane upserts it under the\n * authenticated operator so the web shows a TRUE \"runner online\" signal.\n * Best-effort caller; throws on 401/non-ok so the daemon can log + retry.\n */\n async postHeartbeat({ runnerId, operatorId, uptimeSec, activeTasks, version, daemonVersion, servedRepos, servedOperators, availableAgents, accountUsage }) {\n const body = { runner_id: runnerId };\n if (operatorId) body.operator_id = operatorId;\n if (typeof uptimeSec === 'number') body.uptime_sec = uptimeSec;\n if (typeof activeTasks === 'number') body.active_tasks = activeTasks;\n if (version) body.version = version;\n if (daemonVersion) body.daemon_version = daemonVersion;\n if (Array.isArray(servedRepos) && servedRepos.length > 0) body.served_repos = servedRepos;\n if (Array.isArray(servedOperators) && servedOperators.length > 0) {\n body.served_operator_ids = servedOperators;\n }\n if (Array.isArray(availableAgents) && availableAgents.length > 0) {\n body.available_agents = availableAgents;\n }\n if (Array.isArray(accountUsage) && accountUsage.length > 0) {\n body.account_usage = accountUsage;\n }\n const res = await req('POST', '/api/v1/runner/heartbeat', body);\n if (res.status === 401) {\n cachedFirebaseToken = null;\n throw new Error('heartbeat unauthorized (401)');\n }\n if (!res.ok) throw new Error(`heartbeat failed: HTTP ${res.status}`);\n return true;\n },\n\n /** Poll one authenticated runner's durable Mission Control action queue. */\n async pollRunnerControl({ runnerId, operatorId }) {\n const body = { runner_id: runnerId };\n if (operatorId) body.operator_id = operatorId;\n const res = await req('POST', '/api/v1/runner/control/poll', body);\n if (res.status === 401) {\n cachedFirebaseToken = null;\n throw new Error('runner control poll unauthorized (401)');\n }\n if (!res.ok) throw new Error(`runner control poll failed: HTTP ${res.status}`);\n const json = await res.json();\n const action = json?.action;\n return action && typeof action.action_id === 'string' && action.action_id\n ? { ...action, actionId: action.action_id }\n : null;\n },\n\n /** Acknowledge a maintenance action after the host has restarted the child. */\n async completeRunnerControl(actionId, { runnerId, operatorId, status, detail }) {\n const body = { runner_id: runnerId, status };\n if (operatorId) body.operator_id = operatorId;\n if (detail) body.detail = detail;\n const res = await req('POST', `/api/v1/runner/control/${encodeURIComponent(actionId)}/complete`, body);\n if (res.status === 401) {\n cachedFirebaseToken = null;\n throw new Error('runner control completion unauthorized (401)');\n }\n if (!res.ok) throw new Error(`runner control completion failed: HTTP ${res.status}`);\n const json = await res.json();\n return json?.action || null;\n },\n\n /**\n * Mint a short-lived (~1h), repo-scoped GitHub App installation token for\n * THIS runner's operator (M3). The control-plane keys the mint on the\n * authenticated operator (ctx.operator_id), so the token covers only that\n * operator's installation.\n *\n * Returns { token, expiresAt } on success. In legacy/admin mode it returns\n * null on a miss so the caller may use ambient `gh`. In scoped-operator mode\n * callers pass `{ required: true }`, which fails closed instead of letting a\n * missing/mis-scoped installation fall through to the runner machine's `gh`.\n *\n * The minted token is only usable for push + PR if the GitHub App grants\n * BOTH `Contents: write` (git push) AND `Pull requests: write` (gh pr\n * create) \u2014 see docs/vo/github-app-setup-2026-06-18.md. A token missing\n * either scope fails at push (\u2192 ambient fallback) or at `gh pr create`.\n */\n async getInstallationToken({ required = false } = {}) {\n const fail = (reason) => {\n if (required) throw new Error(`installation-token required: ${reason}`);\n return null;\n };\n try {\n const res = await req('POST', '/api/v1/github/installation-token', {});\n if (!res.ok) return fail(`HTTP ${res.status}`);\n const json = await res.json();\n if (!json || !json.token) return fail('missing token');\n return { token: json.token, expiresAt: json.expires_at || null };\n } catch (err) {\n if (required) throw err;\n return null;\n }\n },\n\n /**\n * Read the operator's dispatch-mode config (Fast\u2192Ultracode effort setting).\n * Returns the mode string ('fast'|'standard'|'deep'|'ultra'|'ultracode'),\n * defaulting to 'standard' on any error. Never throws \u2014 best-effort.\n */\n async getDispatchMode() {\n try {\n const res = await req('GET', '/api/v1/dispatch-mode-config');\n if (!res.ok) return 'standard';\n const json = await res.json();\n return json?.dispatchMode || 'standard';\n } catch {\n return 'standard';\n }\n },\n };\n}\n", "/** Allow-listed host maintenance operations used by the runner supervisor. */\nimport { spawnSync } from 'node:child_process';\n\nexport const DEFAULT_RUNNER_PACKAGE = '@algosuite/vo-mcp@beta';\nconst PACKAGE_SPEC_RE = /^@algosuite\\/vo-mcp@(beta|latest|\\d+(?:\\.\\d+){0,2}(?:-[\\w.-]+)?)$/u;\nconst MAX_DIAGNOSTIC_CHARS = 800;\n\nfunction escapeRegExp(value) {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/gu, '\\\\$&');\n}\n\n/** Keep action detail useful without ever returning credentials or tokens. */\nexport function sanitizeMaintenanceDiagnostic(raw, env = {}) {\n let value = String(raw || '')\n .replace(/\\b(?:vocred|npm|gh[oprsu])_[A-Za-z0-9._-]+\\b/gu, '[REDACTED]')\n .replace(/\\bBearer\\s+\\S+/giu, 'Bearer [REDACTED]')\n .replace(/\\b(_?authToken|token|password|secret|credential)(\\s*[=:]\\s*)\\S+/giu, '$1$2[REDACTED]');\n for (const [name, secret] of Object.entries(env)) {\n if (!/(?:TOKEN|KEY|SECRET|PASSWORD|CREDENTIAL)/iu.test(name)) continue;\n const text = String(secret || '');\n if (text.length < 4) continue;\n value = value.replace(new RegExp(escapeRegExp(text), 'gu'), '[REDACTED]');\n }\n value = value.replace(/\\s+/gu, ' ').trim();\n if (value.length <= MAX_DIAGNOSTIC_CHARS) return value;\n return `${value.slice(0, MAX_DIAGNOSTIC_CHARS - 1)}\u2026`;\n}\n\nexport function buildMaintenanceCommand(kind, { platform = process.platform, packageSpec = DEFAULT_RUNNER_PACKAGE } = {}) {\n if (!['update', 'reinstall'].includes(kind)) return null;\n if (!PACKAGE_SPEC_RE.test(packageSpec)) throw new Error('unsafe runner package spec');\n const command = platform === 'win32' ? 'npm.cmd' : 'npm';\n const args = ['install', '-g', packageSpec];\n if (kind === 'reinstall') args.push('--force');\n return { command, args };\n}\n\nexport function runHostMaintenance(kind, {\n platform = process.platform,\n packageSpec = DEFAULT_RUNNER_PACKAGE,\n env = process.env,\n spawn = spawnSync,\n log = () => {},\n} = {}) {\n if (kind === 'reconnect') return { ok: true, status: 0, command: null, args: [] };\n const command = buildMaintenanceCommand(kind, { platform, packageSpec });\n if (!command) return { ok: false, status: 2, command: null, args: [] };\n log(`runner maintenance: ${command.command} ${command.args.join(' ')}`);\n const result = spawn(command.command, command.args, {\n stdio: ['ignore', 'pipe', 'pipe'],\n encoding: 'utf8',\n env,\n shell: false,\n windowsHide: true,\n });\n const status = typeof result.status === 'number' ? result.status : 1;\n const detail = sanitizeMaintenanceDiagnostic(\n [result.stderr, result.stdout, result.error?.message].filter(Boolean).join('\\n'),\n env,\n );\n if (detail) log(`runner maintenance result: ${detail}`);\n return { ok: status === 0, status, command: command.command, args: command.args, detail };\n}\n", "import { hostname as systemHostname } from 'node:os';\nimport { pairedOperatorScope, probeRunnerReadiness } from '../runner-readiness.mjs';\n\n/** Keep the supervisor's control-queue identity byte-identical to the daemon. */\nexport function resolveSupervisorRunnerId(env = {}, hostname = systemHostname) {\n const explicit = String(env.VO_CODE_RUNNER_ID || '').trim();\n return explicit || `vo-code-runner-${hostname()}`;\n}\n\n/** Build the daemon environment without mislabeling a paired credential as admin. */\nexport function buildSupervisorChildEnv({\n baseEnv = {},\n controlPlaneUrl,\n explicitAdminToken = null,\n pairedOperatorId = null,\n} = {}) {\n const childEnv = {\n ...baseEnv,\n VO_CONTROL_PLANE_URL: controlPlaneUrl,\n };\n const adminToken = typeof explicitAdminToken === 'string' ? explicitAdminToken.trim() : '';\n const operatorId = typeof pairedOperatorId === 'string' ? pairedOperatorId.trim() : '';\n\n if (adminToken) childEnv.VO_CONTROL_PLANE_ADMIN_TOKEN = adminToken;\n else delete childEnv.VO_CONTROL_PLANE_ADMIN_TOKEN;\n\n if (operatorId) childEnv.VO_CODE_RUNNER_OPERATOR_IDS = operatorId;\n return childEnv;\n}\n\n/** Resolve auth provenance once so the supervisor and child use the same scope. */\nexport async function prepareSupervisorAuth({\n baseEnv = {},\n storedCredential = null,\n controlPlaneUrl,\n probeReadiness = probeRunnerReadiness,\n} = {}) {\n const explicitAdminToken = baseEnv.VO_CONTROL_PLANE_ADMIN_TOKEN?.trim();\n const token = explicitAdminToken || storedCredential?.vo_credential;\n if (!token) throw new Error('runner is not paired; run `vo-mcp pair` once on this host');\n\n let operatorId = String(baseEnv.VO_CODE_RUNNER_OPERATOR_IDS || '')\n .split(/[\\s,]+/u)\n .filter(Boolean)[0] || undefined;\n if (!explicitAdminToken) {\n const readiness = await probeReadiness({ controlPlaneUrl, token, requireGithub: true });\n if (!readiness.ok) throw new Error(`runner readiness failed: ${readiness.message}`);\n operatorId = pairedOperatorScope(readiness) || undefined;\n if (!operatorId) throw new Error('runner readiness failed: paired operator scope is missing');\n }\n\n const childEnv = buildSupervisorChildEnv({\n baseEnv,\n controlPlaneUrl,\n explicitAdminToken,\n pairedOperatorId: explicitAdminToken ? null : operatorId,\n });\n const clientEnv = {\n ...baseEnv,\n VO_CONTROL_PLANE_ADMIN_TOKEN: token,\n VO_CONTROL_PLANE_URL: controlPlaneUrl,\n ...(operatorId ? { VO_CODE_RUNNER_OPERATOR_IDS: operatorId } : {}),\n };\n return { childEnv, clientEnv, operatorId };\n}\n", "/**\n * Server-backed readiness probe for a paired BYO runner.\n *\n * The credential itself is opaque, so its mere presence is not proof that it is\n * usable or still bound to an operator. `/auth/me` supplies that truth from the\n * authenticated control-plane context. Before daemon startup, the optional\n * GitHub probe also proves the operator can mint an installation token, so a\n * task is never claimed only to fail at publication setup.\n */\n\nfunction failed({ paired = false, operatorId = null, tenantId = null, githubReady = null, error, message }) {\n return { ok: false, paired, operatorId, tenantId, githubReady, error, message };\n}\n\nasync function responseBody(response) {\n try {\n const value = await response.json();\n return value && typeof value === 'object' ? value : {};\n } catch {\n return {};\n }\n}\n\nfunction serverMessage(body, fallback) {\n return typeof body.message === 'string' && body.message.trim() ? body.message.trim() : fallback;\n}\n\nasync function fetchWithTimeout(fetchImpl, url, init, timeoutMs) {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n try {\n return await fetchImpl(url, { ...init, signal: controller.signal });\n } finally {\n clearTimeout(timer);\n }\n}\n\n/**\n * @param {{\n * controlPlaneUrl: string,\n * token: string,\n * fetchImpl?: typeof fetch,\n * requireGithub?: boolean,\n * timeoutMs?: number,\n * }} input\n */\nexport async function probeRunnerReadiness({\n controlPlaneUrl,\n token,\n fetchImpl = fetch,\n requireGithub = false,\n timeoutMs = 10_000,\n}) {\n const base = controlPlaneUrl.replace(/\\/+$/u, '');\n const headers = { authorization: `Bearer ${token}` };\n let identityResponse;\n try {\n identityResponse = await fetchWithTimeout(\n fetchImpl,\n `${base}/api/v1/auth/me`,\n { headers },\n timeoutMs,\n );\n } catch (error) {\n const detail = error instanceof Error ? error.message : String(error);\n return failed({\n error: 'control_plane_unreachable',\n message: `AlgoHQ could not be reached: ${detail}`,\n });\n }\n\n const identity = await responseBody(identityResponse);\n if (!identityResponse.ok) {\n return failed({\n error: 'credential_rejected',\n message: 'The saved pairing is expired or revoked. Pair this computer again.',\n });\n }\n if (\n identity.provisioned !== true ||\n identity.role !== 'operator' ||\n typeof identity.operator_id !== 'string' ||\n !identity.operator_id.trim() ||\n typeof identity.tenant_id !== 'string' ||\n !identity.tenant_id.trim()\n ) {\n return failed({\n error: 'operator_identity_missing',\n message: 'The pairing credential is valid but has no operator identity. Pair this computer again.',\n });\n }\n\n const operatorId = identity.operator_id.trim();\n const tenantId = identity.tenant_id.trim();\n if (!requireGithub) {\n return {\n ok: true,\n paired: true,\n operatorId,\n tenantId,\n githubReady: null,\n error: null,\n message: 'Paired to AlgoHQ.',\n };\n }\n\n let githubResponse;\n try {\n githubResponse = await fetchWithTimeout(\n fetchImpl,\n `${base}/api/v1/github/installation-token`,\n {\n method: 'POST',\n headers: { ...headers, 'content-type': 'application/json' },\n body: '{}',\n },\n timeoutMs,\n );\n } catch (error) {\n const detail = error instanceof Error ? error.message : String(error);\n return failed({\n paired: true,\n operatorId,\n tenantId,\n githubReady: false,\n error: 'github_preflight_unreachable',\n message: `GitHub publication readiness could not be checked: ${detail}`,\n });\n }\n\n const github = await responseBody(githubResponse);\n if (!githubResponse.ok || typeof github.token !== 'string' || !github.token) {\n const error = typeof github.error === 'string' && github.error ? github.error : 'github_not_ready';\n return failed({\n paired: true,\n operatorId,\n tenantId,\n githubReady: false,\n error,\n message: serverMessage(github, `GitHub publication preflight failed (HTTP ${githubResponse.status}).`),\n });\n }\n\n return {\n ok: true,\n paired: true,\n operatorId,\n tenantId,\n githubReady: true,\n error: null,\n message: 'Paired and ready to publish through the Algosuite GitHub App.',\n };\n}\n\nexport function pairedOperatorScope(readiness) {\n return readiness?.ok === true &&\n readiness?.paired === true &&\n typeof readiness.operatorId === 'string' &&\n readiness.operatorId.trim()\n ? readiness.operatorId.trim()\n : null;\n}\n", "import { spawnSync } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nexport function defaultCredentialHelperPath(metaUrl = import.meta.url) {\n const moduleDir = dirname(fileURLToPath(metaUrl));\n const bundled = join(moduleDir, 'supervisor-credential-helper.js');\n const source = join(moduleDir, '..', 'supervisor-credential-helper.mjs');\n return existsSync(source) ? source : bundled;\n}\n\n/** Read the OS-keychain credential without loading its native module here. */\nexport function readStoredCredentialIsolated({\n spawn = spawnSync,\n execPath = process.execPath,\n helperPath = defaultCredentialHelperPath(),\n env = process.env,\n} = {}) {\n const result = spawn(execPath, [helperPath], {\n env,\n encoding: 'utf8',\n stdio: ['ignore', 'pipe', 'pipe'],\n shell: false,\n windowsHide: true,\n timeout: 10_000,\n });\n if (result.status !== 0) {\n throw new Error('runner credential helper could not read the paired credential');\n }\n try {\n const parsed = JSON.parse(String(result.stdout || ''));\n return parsed && typeof parsed === 'object' ? parsed : null;\n } catch {\n throw new Error('runner credential helper returned an invalid credential');\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["fileURLToPath", "dirname", "join", "getFirebaseAuth", "runnerId", "spawn", "spawnSync", "spawn", "join", "dirname", "fileURLToPath"]
7
+ }
@@ -0,0 +1,204 @@
1
+ #!/usr/bin/env node
2
+ import { createRequire as __cr } from 'module'; const require = __cr(import.meta.url);
3
+
4
+ // ../../scripts/virtual-office/code-runner/agent-key-store.mjs
5
+ import { createRequire } from "node:module";
6
+ var require2 = createRequire(import.meta.url);
7
+ var KEY_SERVICE = "algosuite-vo";
8
+ var PROVIDER_ALIAS = {
9
+ claude: "anthropic",
10
+ anthropic: "anthropic",
11
+ codex: "openai",
12
+ openai: "openai",
13
+ cursor: "cursor",
14
+ meta: "meta",
15
+ muse: "meta",
16
+ spark: "meta",
17
+ "muse-spark": "meta",
18
+ oai: "oai-compat",
19
+ "oai-compat": "oai-compat"
20
+ };
21
+ function resolveProvider(name) {
22
+ const key = String(name || "").trim().toLowerCase();
23
+ return PROVIDER_ALIAS[key] || null;
24
+ }
25
+ function resolveRetiredProvider(name) {
26
+ const key = String(name || "").trim().toLowerCase();
27
+ return key === "grok" || key === "xai" ? "xai" : null;
28
+ }
29
+ function accountFor(provider) {
30
+ return `${provider}-api-key`;
31
+ }
32
+ var _entryCtor;
33
+ var _loadTried = false;
34
+ function defaultEntryCtor() {
35
+ if (_loadTried) return _entryCtor;
36
+ _loadTried = true;
37
+ try {
38
+ _entryCtor = require2("@napi-rs/keyring").Entry;
39
+ } catch {
40
+ _entryCtor = null;
41
+ }
42
+ return _entryCtor;
43
+ }
44
+ function setAgentKey(provider, key, { EntryCtor = defaultEntryCtor() } = {}) {
45
+ const p = resolveProvider(provider);
46
+ if (!p || !key || !EntryCtor) return false;
47
+ try {
48
+ new EntryCtor(KEY_SERVICE, accountFor(p)).setPassword(String(key));
49
+ return true;
50
+ } catch {
51
+ return false;
52
+ }
53
+ }
54
+ function getAgentKey(provider, { EntryCtor = defaultEntryCtor() } = {}) {
55
+ const p = resolveProvider(provider);
56
+ if (!p || !EntryCtor) return null;
57
+ try {
58
+ return new EntryCtor(KEY_SERVICE, accountFor(p)).getPassword() || null;
59
+ } catch {
60
+ return null;
61
+ }
62
+ }
63
+ function clearAgentKey(provider, { EntryCtor = defaultEntryCtor() } = {}) {
64
+ const p = resolveProvider(provider);
65
+ if (!p || !EntryCtor) return false;
66
+ try {
67
+ new EntryCtor(KEY_SERVICE, accountFor(p)).deletePassword();
68
+ return true;
69
+ } catch {
70
+ return false;
71
+ }
72
+ }
73
+ function hasAgentKey(provider, opts = {}) {
74
+ return getAgentKey(provider, opts) !== null;
75
+ }
76
+ function clearRetiredAgentKey(provider, { EntryCtor = defaultEntryCtor() } = {}) {
77
+ if (!resolveRetiredProvider(provider) || !EntryCtor) return false;
78
+ try {
79
+ new EntryCtor(KEY_SERVICE, accountFor("xai")).deletePassword();
80
+ return true;
81
+ } catch {
82
+ return false;
83
+ }
84
+ }
85
+
86
+ // src/set-key-args.mjs
87
+ var PROVIDERS = {
88
+ anthropic: { label: "Anthropic", cli: "claude", selector: "claude", envVar: "ANTHROPIC_API_KEY", hint: "sk-" },
89
+ openai: { label: "OpenAI / Codex", cli: "codex", selector: "codex", envVar: "OPENAI_API_KEY", hint: "sk-" },
90
+ cursor: { label: "Cursor", cli: "cursor-agent", selector: "cursor", envVar: "CURSOR_API_KEY", hint: "" },
91
+ meta: { label: "Meta Model API / Muse Spark", cli: "codex", selector: "meta", envVar: "MODEL_API_KEY", hint: "" }
92
+ };
93
+ function parseSetKeyArgs(argv = []) {
94
+ const rest = argv.slice(3);
95
+ let providerArg = "anthropic";
96
+ let mode = "set";
97
+ for (let i = 0; i < rest.length; i += 1) {
98
+ const a = rest[i];
99
+ if (a === "--status") mode = "status";
100
+ else if (a === "--clear") mode = "clear";
101
+ else if (a === "--provider") {
102
+ providerArg = rest[i + 1] || "";
103
+ i += 1;
104
+ } else if (a.startsWith("--provider=")) {
105
+ providerArg = a.slice("--provider=".length);
106
+ }
107
+ }
108
+ const retiredProvider = resolveRetiredProvider(providerArg);
109
+ if (retiredProvider) return { provider: null, providerArg, mode, retiredProvider };
110
+ return { provider: resolveProvider(providerArg), providerArg, mode };
111
+ }
112
+
113
+ // src/set-key-cli.mjs
114
+ var log = (m) => console.error(m);
115
+ var mask = (k) => k && k.length > 8 ? `\u2026${k.slice(-4)}` : "****";
116
+ function readSecret(promptText) {
117
+ return new Promise((resolve) => {
118
+ if (!process.stdin.isTTY) {
119
+ let buf = "";
120
+ process.stdin.setEncoding("utf8");
121
+ process.stdin.on("data", (d) => buf += d);
122
+ process.stdin.on("end", () => resolve(buf.split(/\r?\n/)[0].trim()));
123
+ return;
124
+ }
125
+ process.stdout.write(promptText);
126
+ const stdin = process.stdin;
127
+ stdin.setRawMode?.(true);
128
+ stdin.resume();
129
+ stdin.setEncoding("utf8");
130
+ let val = "";
131
+ const onData = (ch) => {
132
+ if (ch === "\r" || ch === "\n" || ch === "") {
133
+ stdin.setRawMode?.(false);
134
+ stdin.pause();
135
+ stdin.removeListener("data", onData);
136
+ process.stdout.write("\n");
137
+ resolve(val.trim());
138
+ } else if (ch === "") {
139
+ process.stdout.write("\n");
140
+ process.exit(130);
141
+ } else if (ch === "\x7F" || ch === "\b") {
142
+ val = val.slice(0, -1);
143
+ } else {
144
+ val += ch;
145
+ }
146
+ };
147
+ stdin.on("data", onData);
148
+ });
149
+ }
150
+ async function main() {
151
+ const { provider, providerArg, mode, retiredProvider } = parseSetKeyArgs(process.argv);
152
+ if (retiredProvider) {
153
+ if (mode === "clear") {
154
+ log(
155
+ clearRetiredAgentKey(providerArg) ? "\u2713 Removed the legacy xAI/Grok key from your OS keychain." : "No legacy xAI/Grok key to remove (or keychain unavailable)."
156
+ );
157
+ return;
158
+ }
159
+ log("Grok/xAI support is retired. This key will not be stored or used.");
160
+ log("To remove an old local key, run `vo-mcp set-key --provider grok --clear`.");
161
+ process.exitCode = 1;
162
+ return;
163
+ }
164
+ if (!provider) {
165
+ log(`Unknown --provider "${providerArg}". Use one of: claude, codex, cursor, meta.`);
166
+ process.exitCode = 1;
167
+ return;
168
+ }
169
+ const info = PROVIDERS[provider];
170
+ if (mode === "status") {
171
+ log(
172
+ hasAgentKey(provider) ? `\u2713 A ${info.label} API key is stored in your OS keychain.` : `No ${info.label} API key stored. Run \`vo-mcp set-key${provider === "anthropic" ? "" : ` --provider ${info.selector}`}\` to add one.`
173
+ );
174
+ return;
175
+ }
176
+ if (mode === "clear") {
177
+ log(
178
+ clearAgentKey(provider) ? `\u2713 Removed the stored ${info.label} API key.` : `No stored ${info.label} key to remove (or keychain unavailable).`
179
+ );
180
+ return;
181
+ }
182
+ log(`Paste your ${info.label} API key (for the \`${info.cli}\` agent). It is stored ONLY in`);
183
+ log("your computer's keychain \u2014 it never leaves this machine and Algosuite never sees it.");
184
+ const key = await readSecret(`${info.label} API key: `);
185
+ if (!key) {
186
+ log("No key entered \u2014 nothing stored.");
187
+ process.exitCode = 1;
188
+ return;
189
+ }
190
+ if (info.hint && !key.startsWith(info.hint)) {
191
+ log(`Heads up: ${info.label} keys usually start with "${info.hint}". Storing it anyway.`);
192
+ }
193
+ if (setAgentKey(provider, key)) {
194
+ log(`\u2713 Stored your ${info.label} API key (${mask(key)}) in the OS keychain. The runner will use it automatically.`);
195
+ } else {
196
+ log(`Could not access the OS keychain on this machine. As a fallback, set ${info.envVar} in your environment before running \`vo-mcp runner\`.`);
197
+ process.exitCode = 1;
198
+ }
199
+ }
200
+ main().catch((e) => {
201
+ log(`set-key failed: ${e && e.message ? e.message : e}`);
202
+ process.exitCode = 1;
203
+ });
204
+ //# sourceMappingURL=set-key-cli.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../scripts/virtual-office/code-runner/agent-key-store.mjs", "../src/set-key-args.mjs", "../src/set-key-cli.mjs"],
4
+ "sourcesContent": ["/**\n * agent-key-store \u2014 BYO Phase-B multi-agent. A provider-keyed generalization of\n * [anthropic-key-store] so a friend can store the credential for whichever CLI\n * agent they run (Claude / Codex / Cursor) in the OPERATING-SYSTEM keychain\n * (@napi-rs/keyring). The key lives ONLY on the friend's machine and never\n * reaches Algosuite; the runner reads it at spawn time to authenticate the\n * headless agent.\n *\n * Relationship to anthropic-key-store: that module is the Claude-specific M4\n * path and is left UNTOUCHED. This store uses the SAME service ('algosuite-vo')\n * and the SAME account convention ('<provider>-api-key'), so a key written by\n * `vo-mcp set-key` (account 'anthropic-api-key') is readable here as provider\n * 'anthropic' \u2014 the two are interoperable, not competing stores.\n *\n * Design rules (identical posture to anthropic-key-store):\n * - PURELY graceful: if @napi-rs/keyring is absent, EVERY op no-ops\n * (null/false) so the runner falls back to the ambient env / CLI login.\n * - An explicit credential already in the environment ALWAYS wins over the\n * keychain (a manual override is never silently replaced).\n * - The key travels via process env to the spawned agent, never via argv.\n */\nimport { createRequire } from 'node:module';\n\nconst require = createRequire(import.meta.url);\n\nexport const KEY_SERVICE = 'algosuite-vo';\n\n/**\n * Provider \u2192 the env var(s) its CLI reads for its API credential. Filling more\n * than one is harmless (the CLI ignores vars it doesn't use); 'openai' covers\n * both names the Codex CLI accepts across versions.\n */\nexport const PROVIDER_ENV = {\n anthropic: ['ANTHROPIC_API_KEY'],\n openai: ['OPENAI_API_KEY', 'CODEX_API_KEY'],\n cursor: ['CURSOR_API_KEY'],\n meta: ['MODEL_API_KEY'],\n // Generic OpenAI-compatible runner (bring-your-own model + endpoint): its key\n // is a dedicated var so it never collides with a real OpenAI/Codex key.\n 'oai-compat': ['VO_CODE_RUNNER_OAI_API_KEY'],\n};\n\n/** Canonical provider for a runner's logical name (claude\u2192anthropic, codex\u2192openai). */\nconst PROVIDER_ALIAS = {\n claude: 'anthropic',\n anthropic: 'anthropic',\n codex: 'openai',\n openai: 'openai',\n cursor: 'cursor',\n meta: 'meta',\n muse: 'meta',\n spark: 'meta',\n 'muse-spark': 'meta',\n oai: 'oai-compat',\n 'oai-compat': 'oai-compat',\n};\n\n/** Normalize a runner/provider label to its credential provider. Returns null if unknown. */\nexport function resolveProvider(name) {\n const key = String(name || '').trim().toLowerCase();\n return PROVIDER_ALIAS[key] || null;\n}\n\n/** Recognize retired provider aliases only for explicit legacy-key cleanup. */\nexport function resolveRetiredProvider(name) {\n const key = String(name || '').trim().toLowerCase();\n return key === 'grok' || key === 'xai' ? 'xai' : null;\n}\n\n/** Keychain account name for a provider (matches anthropic-key-store's 'anthropic-api-key'). */\nexport function accountFor(provider) {\n return `${provider}-api-key`;\n}\n\nlet _entryCtor;\nlet _loadTried = false;\n\n/** Lazily load @napi-rs/keyring's `Entry`; null when unavailable (\u2192 no-op ops). */\nfunction defaultEntryCtor() {\n if (_loadTried) return _entryCtor;\n _loadTried = true;\n try {\n _entryCtor = require('@napi-rs/keyring').Entry;\n } catch {\n _entryCtor = null; // not installed / unsupported platform \u2192 graceful fallback\n }\n return _entryCtor;\n}\n\n/** Store `key` for `provider` in the OS keychain. Returns true on success. */\nexport function setAgentKey(provider, key, { EntryCtor = defaultEntryCtor() } = {}) {\n const p = resolveProvider(provider);\n if (!p || !key || !EntryCtor) return false;\n try {\n new EntryCtor(KEY_SERVICE, accountFor(p)).setPassword(String(key));\n return true;\n } catch {\n return false;\n }\n}\n\n/** Read `provider`'s key from the OS keychain. Returns the key, or null. */\nexport function getAgentKey(provider, { EntryCtor = defaultEntryCtor() } = {}) {\n const p = resolveProvider(provider);\n if (!p || !EntryCtor) return null;\n try {\n // getPassword throws (keyring-rs NoEntry) when nothing is stored.\n return new EntryCtor(KEY_SERVICE, accountFor(p)).getPassword() || null;\n } catch {\n return null;\n }\n}\n\n/** Delete `provider`'s stored key. Returns true if a key was removed. */\nexport function clearAgentKey(provider, { EntryCtor = defaultEntryCtor() } = {}) {\n const p = resolveProvider(provider);\n if (!p || !EntryCtor) return false;\n try {\n new EntryCtor(KEY_SERVICE, accountFor(p)).deletePassword();\n return true;\n } catch {\n return false;\n }\n}\n\n/** True if a key is currently stored for `provider` (and the keychain is available). */\nexport function hasAgentKey(provider, opts = {}) {\n return getAgentKey(provider, opts) !== null;\n}\n\n/** True only when the legacy xAI keychain account still contains a key. */\nexport function hasRetiredAgentKey(provider, { EntryCtor = defaultEntryCtor() } = {}) {\n if (!resolveRetiredProvider(provider) || !EntryCtor) return false;\n try {\n return Boolean(new EntryCtor(KEY_SERVICE, accountFor('xai')).getPassword());\n } catch {\n return false;\n }\n}\n\n/** Delete the legacy xAI key without restoring any active provider mapping. */\nexport function clearRetiredAgentKey(provider, { EntryCtor = defaultEntryCtor() } = {}) {\n if (!resolveRetiredProvider(provider) || !EntryCtor) return false;\n try {\n new EntryCtor(KEY_SERVICE, accountFor('xai')).deletePassword();\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Return an env for the spawned agent with `provider`'s credential env var(s)\n * filled from the keychain \u2014 but ONLY for vars not already set (explicit env\n * wins) and only when a key is actually stored. Always returns a fresh object;\n * never mutates `baseEnv`. Unknown provider or no stored key \u2192 shallow copy.\n */\nexport function withAgentKey(provider, baseEnv = {}, { getKey = getAgentKey } = {}) {\n const p = resolveProvider(provider);\n const vars = (p && PROVIDER_ENV[p]) || [];\n const out = { ...baseEnv };\n if (!p || vars.length === 0) return out;\n // If any target var is already set, treat the credential as operator-provided.\n if (vars.some((v) => out[v])) return out;\n const key = getKey(p);\n if (!key) return out;\n for (const v of vars) out[v] = key;\n return out;\n}\n", "/**\n * set-key-args \u2014 the PURE arg-parsing + provider table for `vo-mcp set-key`.\n * Split out of set-key-cli.mjs so it can be unit-tested without importing the\n * CLI (whose module body reads stdin and runs on import). esbuild inlines it at\n * bundle time, same as the other runner-tree .mjs imports.\n */\nimport {\n resolveProvider,\n resolveRetiredProvider,\n} from '../../../scripts/virtual-office/code-runner/agent-key-store.mjs';\n\n/**\n * Per-provider metadata: display `label`, the agent `cli` binary, the\n * `selector` keyword the user types after `--provider` (NOT the binary \u2014 e.g.\n * cursor's binary is `cursor-agent`), the `envVar` fallback, and a typical\n * key-prefix `hint` for a gentle (never-blocking) format check.\n */\nexport const PROVIDERS = {\n anthropic: { label: 'Anthropic', cli: 'claude', selector: 'claude', envVar: 'ANTHROPIC_API_KEY', hint: 'sk-' },\n openai: { label: 'OpenAI / Codex', cli: 'codex', selector: 'codex', envVar: 'OPENAI_API_KEY', hint: 'sk-' },\n cursor: { label: 'Cursor', cli: 'cursor-agent', selector: 'cursor', envVar: 'CURSOR_API_KEY', hint: '' },\n meta: { label: 'Meta Model API / Muse Spark', cli: 'codex', selector: 'meta', envVar: 'MODEL_API_KEY', hint: '' },\n};\n\n/**\n * Parse `vo-mcp set-key` argv (the FULL process.argv; the subcommand is argv[2]).\n * Supports `--provider <p>` / `--provider=p` (default anthropic), `--status`,\n * `--clear`. Returns `{ provider, providerArg, mode }` where `provider` is the\n * normalized credential provider (null if the value is unknown) and `mode` is\n * 'set' | 'status' | 'clear'.\n */\nexport function parseSetKeyArgs(argv = []) {\n const rest = argv.slice(3);\n let providerArg = 'anthropic';\n let mode = 'set';\n for (let i = 0; i < rest.length; i += 1) {\n const a = rest[i];\n if (a === '--status') mode = 'status';\n else if (a === '--clear') mode = 'clear';\n else if (a === '--provider') {\n providerArg = rest[i + 1] || '';\n i += 1; // consume the value token\n } else if (a.startsWith('--provider=')) {\n providerArg = a.slice('--provider='.length);\n }\n }\n const retiredProvider = resolveRetiredProvider(providerArg);\n if (retiredProvider) return { provider: null, providerArg, mode, retiredProvider };\n return { provider: resolveProvider(providerArg), providerArg, mode };\n}\n", "#!/usr/bin/env node\n/**\n * `vo-mcp set-key` \u2014 BYO Phase-B M4 + multi-agent. Stores the friend's AI API key\n * in the OS keychain (Windows Credential Manager / macOS Keychain / libsecret) so\n * the runner can authenticate its CLI agent without an env var. The key lives ONLY\n * on the friend's machine \u2014 it never travels to Algosuite.\n *\n * vo-mcp set-key store the Anthropic (Claude) key [default]\n * vo-mcp set-key --provider codex store the OpenAI/Codex key\n * vo-mcp set-key --provider cursor store the Cursor key\n * vo-mcp set-key --provider grok --clear remove a legacy retired xAI key\n * vo-mcp set-key --provider meta store the Meta Model API key\n * vo-mcp set-key --status report whether the provider's key is stored\n * vo-mcp set-key --clear remove the provider's stored key\n *\n * The key may be piped (`echo $KEY | vo-mcp set-key --provider codex`) or typed at\n * the hidden prompt. .mjs (like runner-cli.mjs) because it imports the runner-tree\n * key store, outside tsconfig rootDir \u2014 tsc skips it; esbuild inlines it at bundle.\n */\nimport {\n setAgentKey,\n hasAgentKey,\n clearAgentKey,\n clearRetiredAgentKey,\n} from '../../../scripts/virtual-office/code-runner/agent-key-store.mjs';\nimport { PROVIDERS, parseSetKeyArgs } from './set-key-args.mjs';\n\nconst log = (m) => console.error(m);\nconst mask = (k) => (k && k.length > 8 ? `\u2026${k.slice(-4)}` : '****');\n\n/** Read a secret from a TTY without echoing; falls back to piped stdin. */\nfunction readSecret(promptText) {\n return new Promise((resolve) => {\n if (!process.stdin.isTTY) {\n // Piped: `echo $KEY | vo-mcp set-key` \u2014 read everything, take the first line.\n let buf = '';\n process.stdin.setEncoding('utf8');\n process.stdin.on('data', (d) => (buf += d));\n process.stdin.on('end', () => resolve(buf.split(/\\r?\\n/)[0].trim()));\n return;\n }\n // Interactive: print the prompt, then mute the echoed characters.\n process.stdout.write(promptText);\n const stdin = process.stdin;\n stdin.setRawMode?.(true);\n stdin.resume();\n stdin.setEncoding('utf8');\n let val = '';\n const onData = (ch) => {\n if (ch === '\\r' || ch === '\\n' || ch === '\u0004') {\n stdin.setRawMode?.(false);\n stdin.pause();\n stdin.removeListener('data', onData);\n process.stdout.write('\\n');\n resolve(val.trim());\n } else if (ch === '\u0003') {\n // Ctrl-C\n process.stdout.write('\\n');\n process.exit(130);\n } else if (ch === '\u007F' || ch === '\\b') {\n val = val.slice(0, -1);\n } else {\n val += ch;\n }\n };\n stdin.on('data', onData);\n });\n}\n\nasync function main() {\n const { provider, providerArg, mode, retiredProvider } = parseSetKeyArgs(process.argv);\n if (retiredProvider) {\n if (mode === 'clear') {\n log(\n clearRetiredAgentKey(providerArg)\n ? '\u2713 Removed the legacy xAI/Grok key from your OS keychain.'\n : 'No legacy xAI/Grok key to remove (or keychain unavailable).',\n );\n return;\n }\n log('Grok/xAI support is retired. This key will not be stored or used.');\n log('To remove an old local key, run `vo-mcp set-key --provider grok --clear`.');\n process.exitCode = 1;\n return;\n }\n if (!provider) {\n log(`Unknown --provider \"${providerArg}\". Use one of: claude, codex, cursor, meta.`);\n process.exitCode = 1;\n return;\n }\n const info = PROVIDERS[provider];\n\n if (mode === 'status') {\n log(\n hasAgentKey(provider)\n ? `\u2713 A ${info.label} API key is stored in your OS keychain.`\n : `No ${info.label} API key stored. Run \\`vo-mcp set-key${provider === 'anthropic' ? '' : ` --provider ${info.selector}`}\\` to add one.`,\n );\n return;\n }\n\n if (mode === 'clear') {\n log(\n clearAgentKey(provider)\n ? `\u2713 Removed the stored ${info.label} API key.`\n : `No stored ${info.label} key to remove (or keychain unavailable).`,\n );\n return;\n }\n\n log(`Paste your ${info.label} API key (for the \\`${info.cli}\\` agent). It is stored ONLY in`);\n log(\"your computer's keychain \u2014 it never leaves this machine and Algosuite never sees it.\");\n const key = await readSecret(`${info.label} API key: `);\n if (!key) {\n log('No key entered \u2014 nothing stored.');\n process.exitCode = 1;\n return;\n }\n // A gentle format hint only \u2014 key formats change and Cursor's isn't `sk-`, so\n // never hard-reject a non-matching key (that would block a valid credential).\n if (info.hint && !key.startsWith(info.hint)) {\n log(`Heads up: ${info.label} keys usually start with \"${info.hint}\". Storing it anyway.`);\n }\n if (setAgentKey(provider, key)) {\n log(`\u2713 Stored your ${info.label} API key (${mask(key)}) in the OS keychain. The runner will use it automatically.`);\n } else {\n log(`Could not access the OS keychain on this machine. As a fallback, set ${info.envVar} in your environment before running \\`vo-mcp runner\\`.`);\n process.exitCode = 1;\n }\n}\n\nmain().catch((e) => {\n log(`set-key failed: ${e && e.message ? e.message : e}`);\n process.exitCode = 1;\n});\n"],
5
+ "mappings": "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",
6
+ "names": ["require", "require"]
7
+ }
@@ -0,0 +1,227 @@
1
+ import { createRequire as __cr } from 'module'; const require = __cr(import.meta.url);
2
+
3
+ // src/cloud/credential-store.ts
4
+ import { homedir } from "node:os";
5
+ import { join, dirname } from "node:path";
6
+ import {
7
+ existsSync,
8
+ mkdirSync,
9
+ readFileSync,
10
+ writeFileSync,
11
+ chmodSync,
12
+ rmSync
13
+ } from "node:fs";
14
+
15
+ // src/cloud/keychain.ts
16
+ import { createRequire } from "node:module";
17
+ var SERVICE = "vo-mcp";
18
+ var ACCOUNT = "refresh-credential";
19
+ var cached;
20
+ function loadKeyring() {
21
+ if (cached !== void 0) return cached;
22
+ try {
23
+ const req = createRequire(import.meta.url);
24
+ const mod = req("@napi-rs/keyring");
25
+ cached = mod && typeof mod.Entry === "function" ? mod : null;
26
+ } catch {
27
+ cached = null;
28
+ }
29
+ return cached;
30
+ }
31
+ function keychainAvailable() {
32
+ return loadKeyring() !== null;
33
+ }
34
+ function keychainGet() {
35
+ const k = loadKeyring();
36
+ if (!k) return null;
37
+ try {
38
+ return new k.Entry(SERVICE, ACCOUNT).getPassword();
39
+ } catch {
40
+ return null;
41
+ }
42
+ }
43
+ function keychainSet(secret) {
44
+ const k = loadKeyring();
45
+ if (!k) return false;
46
+ try {
47
+ new k.Entry(SERVICE, ACCOUNT).setPassword(secret);
48
+ return true;
49
+ } catch {
50
+ return false;
51
+ }
52
+ }
53
+ function keychainDelete() {
54
+ const k = loadKeyring();
55
+ if (!k) return false;
56
+ try {
57
+ return new k.Entry(SERVICE, ACCOUNT).deletePassword();
58
+ } catch {
59
+ return false;
60
+ }
61
+ }
62
+
63
+ // src/cloud/credential-store.ts
64
+ var realKeychain = {
65
+ available: keychainAvailable,
66
+ get: keychainGet,
67
+ set: keychainSet,
68
+ delete: keychainDelete
69
+ };
70
+ function credentialPath(env = process.env) {
71
+ const override = env["VO_MCP_CREDENTIALS_PATH"]?.trim();
72
+ if (override) return override;
73
+ return join(homedir(), ".config", "vo-mcp", "credentials.json");
74
+ }
75
+ function keychainEnabled(env, keychain) {
76
+ const disabled = (env["VO_MCP_DISABLE_KEYCHAIN"] ?? "").trim().toLowerCase();
77
+ if (disabled === "1" || disabled === "true" || disabled === "yes") return false;
78
+ return keychain.available();
79
+ }
80
+ function deserialize(raw) {
81
+ try {
82
+ const parsed = JSON.parse(raw);
83
+ const refresh = typeof parsed.refresh_token === "string" ? parsed.refresh_token.trim() : "";
84
+ const apiKey = typeof parsed.api_key === "string" ? parsed.api_key.trim() : "";
85
+ const voCred = typeof parsed.vo_credential === "string" ? parsed.vo_credential.trim() : "";
86
+ if (!voCred && (!refresh || !apiKey)) return null;
87
+ return {
88
+ ...refresh ? { refresh_token: refresh } : {},
89
+ ...apiKey ? { api_key: apiKey } : {},
90
+ ...voCred ? { vo_credential: voCred } : {},
91
+ ...typeof parsed.vo_credential_expires_at === "string" ? { vo_credential_expires_at: parsed.vo_credential_expires_at } : {},
92
+ ...typeof parsed.email === "string" ? { email: parsed.email } : {},
93
+ ...typeof parsed.stored_at === "string" ? { stored_at: parsed.stored_at } : {}
94
+ };
95
+ } catch {
96
+ return null;
97
+ }
98
+ }
99
+ function readFromFile(env) {
100
+ try {
101
+ const p = credentialPath(env);
102
+ if (!existsSync(p)) return null;
103
+ return deserialize(readFileSync(p, "utf8"));
104
+ } catch {
105
+ return null;
106
+ }
107
+ }
108
+ function readStoredCredential(env = process.env, keychain = realKeychain) {
109
+ if (keychainEnabled(env, keychain)) {
110
+ const raw = keychain.get();
111
+ const fromKeychain = raw ? deserialize(raw) : null;
112
+ if (fromKeychain) return fromKeychain;
113
+ }
114
+ return readFromFile(env);
115
+ }
116
+
117
+ // src/cloud/auth-token-source.ts
118
+ var FIREBASE_SECURETOKEN_URL = "https://securetoken.googleapis.com/v1/token";
119
+ var FIREBASE_TOKEN_REFERER = "https://algosuite.ai/";
120
+ var REFRESH_SKEW_MS = 6e4;
121
+ function createStaticTokenSource(token, kind = "admin-token") {
122
+ const value = token.trim();
123
+ return { kind, getToken: async () => value.length > 0 ? value : null };
124
+ }
125
+ function createFirebaseRefreshTokenSource(opts) {
126
+ const refreshToken = opts.refreshToken.trim();
127
+ const apiKey = opts.apiKey.trim();
128
+ const now = opts.now ?? (() => Date.now());
129
+ const fetchFn = opts.fetchFn ?? globalThis.fetch;
130
+ let cachedToken = null;
131
+ let expiresAtMs = 0;
132
+ let inFlight = null;
133
+ async function refresh() {
134
+ try {
135
+ const res = await fetchFn(`${FIREBASE_SECURETOKEN_URL}?key=${encodeURIComponent(apiKey)}`, {
136
+ method: "POST",
137
+ headers: {
138
+ "content-type": "application/x-www-form-urlencoded",
139
+ referer: FIREBASE_TOKEN_REFERER
140
+ },
141
+ body: `grant_type=refresh_token&refresh_token=${encodeURIComponent(refreshToken)}`
142
+ });
143
+ const text = await res.text();
144
+ if (res.status < 200 || res.status >= 300) {
145
+ cachedToken = null;
146
+ return null;
147
+ }
148
+ const parsed = JSON.parse(text);
149
+ const idToken = typeof parsed.id_token === "string" ? parsed.id_token : "";
150
+ if (!idToken) {
151
+ cachedToken = null;
152
+ return null;
153
+ }
154
+ const expiresInSec = Number(parsed.expires_in);
155
+ const ttlMs = Number.isFinite(expiresInSec) && expiresInSec > 0 ? expiresInSec * 1e3 : 36e5;
156
+ cachedToken = idToken;
157
+ expiresAtMs = now() + ttlMs;
158
+ return idToken;
159
+ } catch {
160
+ cachedToken = null;
161
+ return null;
162
+ }
163
+ }
164
+ return {
165
+ kind: "firebase-refresh",
166
+ async getToken() {
167
+ if (cachedToken && now() < expiresAtMs - REFRESH_SKEW_MS) return cachedToken;
168
+ if (!inFlight) {
169
+ inFlight = refresh().finally(() => {
170
+ inFlight = null;
171
+ });
172
+ }
173
+ return inFlight;
174
+ }
175
+ };
176
+ }
177
+ function createAuthTokenSourceFromEnv(env = process.env, fetchFn, readStoredCred = () => null) {
178
+ const refreshToken = env["VO_USER_REFRESH_TOKEN"]?.trim();
179
+ const apiKey = env["VO_FIREBASE_API_KEY"]?.trim();
180
+ const idToken = env["VO_USER_ID_TOKEN"]?.trim();
181
+ const adminToken = env["VO_CONTROL_PLANE_ADMIN_TOKEN"]?.trim();
182
+ if (refreshToken || apiKey) {
183
+ if (!refreshToken || !apiKey) {
184
+ throw new Error(
185
+ "Per-user refresh auth requires BOTH VO_USER_REFRESH_TOKEN and VO_FIREBASE_API_KEY"
186
+ );
187
+ }
188
+ return createFirebaseRefreshTokenSource({
189
+ refreshToken,
190
+ apiKey,
191
+ ...fetchFn ? { fetchFn } : {}
192
+ });
193
+ }
194
+ if (idToken) return createStaticTokenSource(idToken, "firebase-id-token");
195
+ const stored = readStoredCred();
196
+ if (stored?.vo_credential && stored.vo_credential.trim()) {
197
+ return createStaticTokenSource(stored.vo_credential.trim(), "vo-credential");
198
+ }
199
+ if (stored && stored.refresh_token?.trim() && stored.api_key?.trim()) {
200
+ return createFirebaseRefreshTokenSource({
201
+ refreshToken: stored.refresh_token.trim(),
202
+ apiKey: stored.api_key.trim(),
203
+ ...fetchFn ? { fetchFn } : {}
204
+ });
205
+ }
206
+ if (adminToken) return createStaticTokenSource(adminToken, "admin-token");
207
+ return null;
208
+ }
209
+
210
+ // src/supervisor-credential-helper.mjs
211
+ var credential = readStoredCredential();
212
+ if (process.argv.includes("--control-plane-auth")) {
213
+ const source = createAuthTokenSourceFromEnv(process.env, void 0, () => credential);
214
+ const token = await source?.getToken();
215
+ if (!token) {
216
+ process.stderr.write("control-plane credential was not found\n");
217
+ process.exitCode = 2;
218
+ } else {
219
+ process.stdout.write(JSON.stringify({ token }));
220
+ }
221
+ } else if (!credential) {
222
+ process.stderr.write("paired runner credential was not found\n");
223
+ process.exitCode = 2;
224
+ } else {
225
+ process.stdout.write(JSON.stringify(credential));
226
+ }
227
+ //# sourceMappingURL=supervisor-credential-helper.js.map