@algosuite/vo-mcp 0.1.0 → 0.2.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/vo-mcp +2 -5
- package/dist/cli.js +1087 -319
- package/dist/cli.js.map +4 -4
- package/dist/index.js +1083 -92
- package/dist/index.js.map +4 -4
- package/dist/install-cli.js +12 -7
- package/dist/install-cli.js.map +2 -2
- package/dist/login-cli.js +9 -5
- package/dist/login-cli.js.map +2 -2
- package/dist/runner-cli.js +1940 -0
- package/dist/runner-cli.js.map +7 -0
- package/package.json +1 -1
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/runner/control-plane-auth-stub.mjs", "../src/cloud/credential-store.ts", "../src/cloud/keychain.ts", "../../../scripts/virtual-office/code-runner-daemon.mjs", "../src/runner/worktree-helper.mjs", "../src/runner/spend-cap-shim.mjs", "../../../scripts/virtual-office/code-runner/control-plane-client.mjs", "../../../scripts/virtual-office/code-runner/claude-runner.mjs", "../../../scripts/virtual-office/code-runner/rate-limit-resume.mjs", "../../../scripts/ci/rate-limit-detector-core.mjs", "../../../scripts/virtual-office/code-runner/publish.mjs", "../../../scripts/virtual-office/code-runner/dispatch-onboarding.mjs", "../../../scripts/virtual-office/code-runner/session-spool-forwarder.mjs", "../../../scripts/virtual-office/code-runner/pr-watcher.mjs", "../../../scripts/virtual-office/code-runner/control-server.mjs", "../../../scripts/virtual-office/code-runner/effort-mode-config.mjs", "../../../scripts/virtual-office/model-registry.mjs", "../../../scripts/virtual-office/code-runner/model-router.mjs", "../../../scripts/virtual-office/code-runner/apply-effort-mode.mjs", "../../../scripts/virtual-office/code-runner/claim-scoping-log.mjs", "../src/runner-cli.mjs"],
|
|
4
|
+
"sourcesContent": ["/**\r\n * Control-plane auth stub for the bundled `vo-mcp runner`.\r\n *\r\n * Replaces the daemon's lazy Firebase/SMOKE_* fallback\r\n * (`scripts/virtual-office/orchestrator-firestore/auth.mjs`), which pulls\r\n * `vo-config.mjs` (hardcoded Nexus Firebase project) + the firebase-admin chain.\r\n * A BYO runner ALWAYS authenticates with its own scoped `vo_credential` \u2014 read\r\n * from the OS keychain by `runner-cli.mjs` and injected as\r\n * `VO_CONTROL_PLANE_ADMIN_TOKEN` \u2014 so `control-plane-client.mjs`'s `resolveBearer`\r\n * returns early on the token and NEVER reaches this fallback. It exists only so\r\n * the bundle has nothing to resolve into the firebase chain; if it ever runs,\r\n * it fails LOUDLY with the fix.\r\n *\r\n * esbuild swaps this in for the heavy original at bundle time (see scripts/bundle.mjs).\r\n */\r\nexport async function getFirebaseAuth() {\r\n throw new Error(\r\n 'vo-mcp runner: no control-plane credential. Run `vo-mcp login` first \u2014 the runner ' +\r\n 'authenticates with your stored vo_credential (or set VO_CONTROL_PLANE_ADMIN_TOKEN).',\r\n );\r\n}\r\n", "/**\r\n * Local credential store for the thin-client `vo-mcp login` flow (Increment 3b,\r\n * Option A \u2014 `docs/vo/vo-command-center-inc3b-login-design-2026-06-05.md`).\r\n *\r\n * Persists the per-user Firebase refresh token (the user's OWN credential, never\r\n * the god-token, never model keys) captured by `login`, so the auto-refreshing\r\n * token source (Inc 3a) can mint fresh ID tokens across MCP restarts.\r\n *\r\n * Storage precedence (Inc 3b.3):\r\n * 1. **OS keychain** (Windows Credential Manager / macOS Keychain / libsecret)\r\n * via the optional `@napi-rs/keyring` backend (`keychain.ts`). The DEFAULT\r\n * when available \u2014 the secret never lands in plaintext on disk.\r\n * 2. **0600 file** at `$VO_MCP_CREDENTIALS_PATH` or `~/.config/vo-mcp/credentials.json`.\r\n * The fallback when the keychain is unavailable or disabled\r\n * (`VO_MCP_DISABLE_KEYCHAIN`). `VO_MCP_CREDENTIALS_PATH` only sets the file\r\n * LOCATION; force file storage with `VO_MCP_DISABLE_KEYCHAIN`.\r\n *\r\n * `env`-supplied tokens (`VO_USER_REFRESH_TOKEN`, etc.) still win over BOTH\r\n * stores \u2014 that precedence lives upstream in `auth-token-source.ts`.\r\n *\r\n * **Single source of truth.** The credential lives in EITHER the keychain OR the\r\n * file, never both: a write to one store CLEARS the other, so a stale entry can\r\n * never shadow the current credential on read, and the secret never lingers in\r\n * plaintext after a migration to the keychain.\r\n *\r\n * **Keychain durability.** A keychain-stored credential is only readable while\r\n * the `@napi-rs/keyring` native module loads. If the module later becomes\r\n * unavailable (an ABI break across a Node upgrade, a corrupted install), the\r\n * credential can't be read and the user re-runs `vo-mcp login` \u2014 the same\r\n * behaviour as `gh` / `gcloud` / `firebase` keychain storage. We deliberately do\r\n * NOT mirror the secret to a plaintext file as a fallback: that would defeat the\r\n * entire point of keychain storage (keeping the secret off plaintext disk).\r\n */\r\nimport { homedir } from 'node:os';\r\nimport { join, dirname } from 'node:path';\r\nimport {\r\n existsSync,\r\n mkdirSync,\r\n readFileSync,\r\n writeFileSync,\r\n chmodSync,\r\n rmSync,\r\n} from 'node:fs';\r\n\r\nimport { keychainAvailable, keychainGet, keychainSet, keychainDelete } from './keychain.js';\r\n\r\nexport interface StoredCredential {\r\n /**\r\n * Firebase refresh token (long-lived; exchanged for short-lived ID tokens).\r\n * OPTIONAL since Inc 3b.4b: once a scoped `vo_credential` is minted, the raw\r\n * refresh token is dropped, so a stored credential may carry ONLY the vocred_.\r\n */\r\n readonly refresh_token?: string;\r\n /** Firebase Web API key (PUBLIC) needed for the securetoken refresh exchange. */\r\n readonly api_key?: string;\r\n /**\r\n * Scoped, revocable VO credential (`vocred_`) minted by the control-plane\r\n * (Inc 3b.4b). Preferred over the raw refresh token; lets the client present a\r\n * revocable, server-side credential instead of the Firebase refresh token.\r\n */\r\n readonly vo_credential?: string;\r\n /** ISO-8601 expiry of `vo_credential` (the client re-logs-in past this). */\r\n readonly vo_credential_expires_at?: string;\r\n /** The signed-in operator email (diagnostics only). */\r\n readonly email?: string;\r\n /** ISO timestamp the credential was stored. */\r\n readonly stored_at?: string;\r\n}\r\n\r\n/**\r\n * Pluggable OS-keychain backend. Defaults to the real `@napi-rs/keyring` wrapper;\r\n * tests inject a deterministic fake so they never touch the host keychain.\r\n */\r\nexport interface KeychainBackend {\r\n available(): boolean;\r\n get(): string | null;\r\n set(secret: string): boolean;\r\n delete(): boolean;\r\n}\r\n\r\nconst realKeychain: KeychainBackend = {\r\n available: keychainAvailable,\r\n get: keychainGet,\r\n set: keychainSet,\r\n delete: keychainDelete,\r\n};\r\n\r\n/** Human-readable \"location\" returned when the credential was stored in the OS keychain. */\r\nexport const KEYCHAIN_LOCATION = 'OS keychain (service \"vo-mcp\")';\r\n\r\n/** Resolve the credentials file path (env override \u2192 XDG-ish default under home). */\r\nexport function credentialPath(env: Readonly<Record<string, string | undefined>> = process.env): string {\r\n const override = env['VO_MCP_CREDENTIALS_PATH']?.trim();\r\n if (override) return override;\r\n return join(homedir(), '.config', 'vo-mcp', 'credentials.json');\r\n}\r\n\r\n/**\r\n * Whether the keychain should be consulted at all (read OR write). False when the\r\n * native backend is unavailable or `VO_MCP_DISABLE_KEYCHAIN` is set (CI/headless).\r\n */\r\nfunction keychainEnabled(\r\n env: Readonly<Record<string, string | undefined>>,\r\n keychain: KeychainBackend,\r\n): boolean {\r\n const disabled = (env['VO_MCP_DISABLE_KEYCHAIN'] ?? '').trim().toLowerCase();\r\n if (disabled === '1' || disabled === 'true' || disabled === 'yes') return false;\r\n return keychain.available();\r\n}\r\n\r\n/** Parse + validate a stored credential blob. Returns null on any problem (never throws). */\r\nfunction deserialize(raw: string): StoredCredential | null {\r\n try {\r\n const parsed = JSON.parse(raw) as Partial<StoredCredential>;\r\n const refresh = typeof parsed.refresh_token === 'string' ? parsed.refresh_token.trim() : '';\r\n const apiKey = typeof parsed.api_key === 'string' ? parsed.api_key.trim() : '';\r\n const voCred = typeof parsed.vo_credential === 'string' ? parsed.vo_credential.trim() : '';\r\n // Valid if it carries a scoped vocred_ OR a full Firebase refresh pair.\r\n if (!voCred && (!refresh || !apiKey)) return null;\r\n return {\r\n ...(refresh ? { refresh_token: refresh } : {}),\r\n ...(apiKey ? { api_key: apiKey } : {}),\r\n ...(voCred ? { vo_credential: voCred } : {}),\r\n ...(typeof parsed.vo_credential_expires_at === 'string' ? { vo_credential_expires_at: parsed.vo_credential_expires_at } : {}),\r\n ...(typeof parsed.email === 'string' ? { email: parsed.email } : {}),\r\n ...(typeof parsed.stored_at === 'string' ? { stored_at: parsed.stored_at } : {}),\r\n };\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\nfunction readFromFile(env: Readonly<Record<string, string | undefined>>): StoredCredential | null {\r\n try {\r\n const p = credentialPath(env);\r\n if (!existsSync(p)) return null;\r\n return deserialize(readFileSync(p, 'utf8'));\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Read the stored credential, or `null` if absent/unreadable/invalid (never\r\n * throws). Consults an ENABLED keychain first (regardless of the write-target\r\n * flags, so a credential written to the keychain is found even if\r\n * `VO_MCP_CREDENTIALS_PATH` is later set), then the 0600 file.\r\n */\r\nexport function readStoredCredential(\r\n env: Readonly<Record<string, string | undefined>> = process.env,\r\n keychain: KeychainBackend = realKeychain,\r\n): StoredCredential | null {\r\n if (keychainEnabled(env, keychain)) {\r\n const raw = keychain.get();\r\n const fromKeychain = raw ? deserialize(raw) : null;\r\n if (fromKeychain) return fromKeychain;\r\n }\r\n return readFromFile(env);\r\n}\r\n\r\nfunction deleteFile(env: Readonly<Record<string, string | undefined>>): void {\r\n try {\r\n rmSync(credentialPath(env), { force: true });\r\n } catch {\r\n /* best-effort */\r\n }\r\n}\r\n\r\nfunction writeToFile(\r\n payload: StoredCredential,\r\n env: Readonly<Record<string, string | undefined>>,\r\n): string {\r\n const p = credentialPath(env);\r\n mkdirSync(dirname(p), { recursive: true });\r\n writeFileSync(p, `${JSON.stringify(payload, null, 2)}\\n`, { mode: 0o600 });\r\n // Best-effort tighten (no-op / throws on some Windows filesystems \u2014 ignore).\r\n try {\r\n chmodSync(p, 0o600);\r\n } catch {\r\n /* best-effort */\r\n }\r\n return p;\r\n}\r\n\r\n/**\r\n * Persist the credential. Prefers the OS keychain (secret never hits plaintext\r\n * disk); otherwise writes the 0600 file. Writing to one store CLEARS the other\r\n * (single source of truth \u2014 no stale shadow, no lingering plaintext). Returns the\r\n * location it was stored (`KEYCHAIN_LOCATION` or the file path).\r\n */\r\nexport function writeStoredCredential(\r\n cred: StoredCredential,\r\n storedAt: string,\r\n env: Readonly<Record<string, string | undefined>> = process.env,\r\n keychain: KeychainBackend = realKeychain,\r\n): string {\r\n const payload: StoredCredential = {\r\n ...(cred.refresh_token ? { refresh_token: cred.refresh_token } : {}),\r\n ...(cred.api_key ? { api_key: cred.api_key } : {}),\r\n ...(cred.vo_credential ? { vo_credential: cred.vo_credential } : {}),\r\n ...(cred.vo_credential_expires_at ? { vo_credential_expires_at: cred.vo_credential_expires_at } : {}),\r\n ...(cred.email ? { email: cred.email } : {}),\r\n stored_at: cred.stored_at ?? storedAt,\r\n };\r\n if (keychainEnabled(env, keychain) && keychain.set(JSON.stringify(payload))) {\r\n // Stored in the keychain \u2192 clear any stale plaintext file so the secret\r\n // doesn't linger on disk and can't shadow the keychain on read.\r\n deleteFile(env);\r\n return KEYCHAIN_LOCATION;\r\n }\r\n const p = writeToFile(payload, env);\r\n // Stored in the file \u2192 clear any stale keychain entry so it can't shadow the\r\n // newer file credential on read.\r\n if (keychainEnabled(env, keychain)) keychain.delete();\r\n return p;\r\n}\r\n", "/**\r\n * Optional OS-keychain backend for the thin-client credential store (Increment\r\n * 3b.3 \u2014 `docs/vo/vo-command-center-inc3b-login-design-2026-06-05.md` \u00A75/\u00A76).\r\n *\r\n * Loads `@napi-rs/keyring` at runtime via `createRequire`, so it is a TRUE\r\n * optional dependency: if the native module is absent or fails to load\r\n * (unsupported platform, prebuilt binary missing, headless CI), every function\r\n * degrades to a no-op and the caller (`credential-store.ts`) falls back to the\r\n * 0600 file store. `@napi-rs/keyring`'s `Entry` API is SYNCHRONOUS, so the\r\n * credential store stays synchronous \u2014 no async ripple into the Inc-3a token\r\n * source that reads it.\r\n *\r\n * Why `createRequire` and not a static/dynamic `import`: a static import would\r\n * make the native module a HARD dependency (a missing prebuilt would crash the\r\n * MCP at startup); a dynamic `import()` is async (would force the whole read\r\n * path async). `createRequire(...)` inside a try/catch loads it lazily and\r\n * synchronously, and a load failure is just \"keychain unavailable\".\r\n */\r\nimport { createRequire } from 'node:module';\r\n\r\n/** Keychain service + account the single refresh credential is stored under. */\r\nconst SERVICE = 'vo-mcp';\r\nconst ACCOUNT = 'refresh-credential';\r\n\r\ninterface KeyringEntry {\r\n getPassword(): string | null;\r\n setPassword(password: string): void;\r\n deletePassword(): boolean;\r\n}\r\ninterface KeyringModule {\r\n Entry: new (service: string, account: string) => KeyringEntry;\r\n}\r\n\r\n// undefined = not yet attempted; null = attempted and unavailable.\r\nlet cached: KeyringModule | null | undefined;\r\n\r\nfunction loadKeyring(): KeyringModule | null {\r\n if (cached !== undefined) return cached;\r\n try {\r\n const req = createRequire(import.meta.url);\r\n const mod = req('@napi-rs/keyring') as Partial<KeyringModule>;\r\n cached = mod && typeof mod.Entry === 'function' ? (mod as KeyringModule) : null;\r\n } catch {\r\n cached = null;\r\n }\r\n return cached;\r\n}\r\n\r\n/** True when the OS keychain backend is usable in this runtime. */\r\nexport function keychainAvailable(): boolean {\r\n return loadKeyring() !== null;\r\n}\r\n\r\n/** Read the raw stored secret string from the OS keychain, or null. Never throws. */\r\nexport function keychainGet(): string | null {\r\n const k = loadKeyring();\r\n if (!k) return null;\r\n try {\r\n return new k.Entry(SERVICE, ACCOUNT).getPassword();\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\n/** Store the raw secret string in the OS keychain. Returns true on success. Never throws. */\r\nexport function keychainSet(secret: string): boolean {\r\n const k = loadKeyring();\r\n if (!k) return false;\r\n try {\r\n new k.Entry(SERVICE, ACCOUNT).setPassword(secret);\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Delete the stored secret from the OS keychain. Returns true if an entry was\r\n * removed. Never throws \u2014 a no-op (and `false`) when the backend is unavailable\r\n * or the entry is absent. Used to keep ONE source of truth: when the credential\r\n * is (re)written to the file, any stale keychain entry is cleared so it can't\r\n * shadow the newer file credential on read (and vice-versa).\r\n */\r\nexport function keychainDelete(): boolean {\r\n const k = loadKeyring();\r\n if (!k) return false;\r\n try {\r\n return new k.Entry(SERVICE, ACCOUNT).deletePassword();\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/** Test-only seam to reset the memoised module load. */\r\nexport function __resetKeychainCache(): void {\r\n cached = undefined;\r\n}\r\n", "/* eslint-disable no-console */\r\n/**\r\n * code-runner-daemon \u2014 the LOCAL runner for VO Command Center \"Code-from-Anywhere\"\r\n * (Increment 6, `docs/vo/vo-command-center-codeanywhere-design-2026-06-06.md`).\r\n *\r\n * Loop: poll vo-control-plane OUTBOUND \u2192 claim a pending CodeTask \u2192 make a fresh\r\n * worktree off origin/main \u2192 spawn a headless `claude -p` agent with the FULL\r\n * operator config (NO `--bare`) \u2192 stream progress back \u2192 on completion commit +\r\n * open a PR (NO auto-merge \u2014 the verify gate / human review governs the merge).\r\n *\r\n * Guardrails (design \u00A75): per-task `max_budget_usd` + `max_turns` governors; a\r\n * server-side kill switch (`POST /code-task/:id/cancel`) observed via cancel\r\n * polling; a concurrency cap (`VO_CODE_TASK_MAX_CONCURRENCY`, default 2); every\r\n * lifecycle action flows through the signed audit chain on the control-plane.\r\n *\r\n * Run: VO_CONTROL_PLANE_URL=... VO_CONTROL_PLANE_ADMIN_TOKEN=... \\\r\n * node scripts/virtual-office/code-runner-daemon.mjs [--once]\r\n *\r\n * Env:\r\n * VO_CONTROL_PLANE_URL (required) control-plane base URL\r\n * VO_CONTROL_PLANE_ADMIN_TOKEN admin bearer (or SMOKE_* for Firebase auth)\r\n * VO_CODE_RUNNER_ID runner identity (default vo-code-runner-<host>)\r\n * VO_CODE_RUNNER_CLAUDE_BIN claude binary (default 'claude')\r\n * VO_CODE_RUNNER_PERMISSION_MODE claude --permission-mode (default acceptEdits)\r\n * VO_CODE_TASK_MAX_CONCURRENCY max simultaneous tasks (default 2)\r\n * VO_CODE_RUNNER_POLL_SEC poll interval seconds (default 5)\r\n * VO_CODE_RUNNER_MAX_WALL_CLOCK_MS hard per-task time bound (default 1800000; 0=off)\r\n * VO_CODE_RUNNER_CANCEL_POLL_MS cancel-detection poll (default 2500)\r\n */\r\nimport os from 'node:os';\r\nimport { fileURLToPath } from 'node:url';\r\nimport { createFixWorktree, cleanupFixWorktree } from './orchestrator/validation-and-worktree.mjs';\r\nimport { resolveSpendCapUsd } from './spend-cap-guard.mjs';\r\nimport { createControlPlaneClient } from './code-runner/control-plane-client.mjs';\r\nimport { runClaudeTask } from './code-runner/claude-runner.mjs';\r\nimport { classifyFailureForResume } from './code-runner/rate-limit-resume.mjs';\r\nimport {\r\n isAgentScratch,\r\n listChangedFiles,\r\n listCommittedFiles,\r\n openCodeTaskPr,\r\n} from './code-runner/publish.mjs';\r\nimport { composeDispatchPrompt } from './code-runner/dispatch-onboarding.mjs';\r\nimport { forwardSessionSpool } from './code-runner/session-spool-forwarder.mjs';\r\nimport {\r\n makeWatchRunner,\r\n trackDispatchedPr,\r\n CI_FIX_MARKER,\r\n} from './code-runner/pr-watcher.mjs';\r\nimport { startDaemonControl } from './code-runner/control-server.mjs';\r\nimport { resolveEffortDispatch } from './code-runner/apply-effort-mode.mjs';\r\nimport { describeClaimScoping } from './code-runner/claim-scoping-log.mjs';\r\n\r\nfunction log(msg) {\r\n console.log(`[code-runner ${new Date().toISOString()}] ${msg}`);\r\n}\r\n\r\n// PR12: when ON, a usage/rate-limit stop is recorded RATE_LIMITED (resumable)\r\n// instead of dropped as 'failed'. Default OFF => legacy. Detection+recording only;\r\n// auto-resume/re-dispatch (token spend) is the scheduler's job (PR12b).\r\nconst RATE_LIMIT_RESUME_ENABLED = process.env.VO_RATE_LIMIT_RESUME === '1';\r\n\r\n// Parse a comma/space/newline-separated env list \u2192 trimmed, blank-free array.\r\nconst parseList = (s) => String(s || '').split(/[\\s,]+/).map((x) => x.trim()).filter(Boolean);\r\n\r\nfunction loadConfig(env = process.env) {\r\n return {\r\n runnerId: env.VO_CODE_RUNNER_ID || `vo-code-runner-${os.hostname()}`,\r\n claudeBin: env.VO_CODE_RUNNER_CLAUDE_BIN || 'claude',\r\n permissionMode: env.VO_CODE_RUNNER_PERMISSION_MODE || 'acceptEdits',\r\n maxConcurrency: Math.max(1, Number(env.VO_CODE_TASK_MAX_CONCURRENCY || 2) || 2),\r\n pollSec: Math.max(1, Number(env.VO_CODE_RUNNER_POLL_SEC || 5) || 5),\r\n // Repos this daemon may BUILD + operators it serves (`owner/name` repos /\r\n // operator_ids; comma/space/newline separated). Sent on every claim so the\r\n // control-plane only hands this machine its own work \u2014 another operator's\r\n // task can never land here. Both UNSET \u21D2 claims any pending task (legacy).\r\n servedRepos: parseList(env.VO_CODE_RUNNER_REPOS),\r\n servedOperators: parseList(env.VO_CODE_RUNNER_OPERATOR_IDS),\r\n // 'Sees ALL agents': how often to forward the local session spool to the\r\n // cloud (best-effort). Default 30s. Set 0 to disable forwarding.\r\n sessionForwardSec: Math.max(0, Number(env.VO_SESSION_FORWARD_SEC ?? 30) || 0),\r\n operatorSeed: env.VO_LOCAL_OPERATOR_SEED || env.VO_CODE_RUNNER_ID || `local-${os.hostname()}`,\r\n cancelPollMs: Math.max(1000, Number(env.VO_CODE_RUNNER_CANCEL_POLL_MS || 2500) || 2500),\r\n // HARD enforced spend bound (max_budget_usd can only be checked post-hoc).\r\n // Default 30 min; set 0 to disable.\r\n maxWallClockMs: Math.max(0, Number(env.VO_CODE_RUNNER_MAX_WALL_CLOCK_MS ?? 1_800_000) || 1_800_000),\r\n // Active PR watcher: monitor each dispatched PR's CI + auto-dispatch ONE fix\r\n // on failure (never auto-merges). Off: VO_CODE_RUNNER_WATCH=0; cap/interval below.\r\n watchEnabled: env.VO_CODE_RUNNER_WATCH !== '0',\r\n watchMaxFix: Math.max(0, Number(env.VO_CODE_RUNNER_WATCH_MAX_FIX ?? 1) || 0),\r\n watchIntervalSec: Math.max(30, Number(env.VO_CODE_RUNNER_WATCH_SEC ?? 60) || 60),\r\n // In-product runner control (Phase 8.4): localhost-only status + Stop surface\r\n // for /virtualoffice. Off: VO_CODE_RUNNER_CONTROL=0. appOrigin = CORS allow.\r\n controlEnabled: env.VO_CODE_RUNNER_CONTROL !== '0',\r\n controlPort: Math.max(1, Number(env.VO_CODE_RUNNER_CONTROL_PORT ?? 7787) || 7787),\r\n appOrigin: env.VO_APP_ORIGIN || 'https://algosuite.ai',\r\n };\r\n}\r\nconst sleep = (ms) => new Promise((r) => setTimeout(r, ms));\r\nconst numOrUndef = (x) => (typeof x === 'number' ? x : undefined);\r\n/** Post progress; swallow transport errors. Returns the response or null. */\r\nasync function safeProgress(client, id, patch) {\r\n try {\r\n const r = await client.postProgress(id, patch);\r\n if (r && r.terminal) log(`task ${id} is terminal server-side; stopping updates`);\r\n return r;\r\n } catch (err) {\r\n log(`progress post failed for ${id}: ${err.message}`);\r\n return null;\r\n }\r\n}\r\nfunction buildPrBody(task, run, files) {\r\n return [\r\n '## VO Command Center \u2014 Code-from-Anywhere task',\r\n '',\r\n `- **Task:** \\`${task.code_task_id}\\``,\r\n `- **Operator:** ${task.operator_id}`,\r\n `- **Repo:** ${task.repo}`,\r\n typeof run.costUsd === 'number' ? `- **Agent cost:** $${run.costUsd.toFixed(4)}` : '- **Agent cost:** n/a',\r\n typeof run.numTurns === 'number' ? `- **Turns:** ${run.numTurns}` : '',\r\n `- **Files changed:** ${files.length}`,\r\n '',\r\n '### Prompt',\r\n '',\r\n '```',\r\n String(task.prompt).slice(0, 2000),\r\n '```',\r\n '',\r\n '### Agent summary',\r\n '',\r\n String(run.summary || '').slice(0, 2000),\r\n '',\r\n '---',\r\n '_Opened by the VO code-runner daemon. This PR awaits the verify-before-act gate / operator review \u2014 it is NOT auto-merged._',\r\n ]\r\n .filter((l) => l !== '')\r\n .join('\\n');\r\n}\r\n/** Run one claimed task end-to-end: worktree \u2192 claude \u2192 PR. Never throws. */\r\nasync function processOneTask(client, task, cfg) {\r\n const id = task.code_task_id;\r\n let worktreeName = '';\r\n try {\r\n const wt = createFixWorktree('code-task', { source: id.slice(0, 8) });\r\n worktreeName = wt.worktreeName;\r\n // Fast\u2192Ultracode dispatch-effort: the operator's level supplies model-tier,\r\n // permission-mode, max-turns + thinking/multi-agent directive defaults (per-task\r\n // tier / max_turns / VO_CODE_RUNNER_PERMISSION_MODE env override them).\r\n const { dispatchMode, tier, model, permissionMode: effectivePermissionMode, maxTurns: effectiveMaxTurns, prompt: effortPrompt } =\r\n await resolveEffortDispatch({ client, task, env: process.env, basePrompt: composeDispatchPrompt(task.prompt, { repo: task.repo }) });\r\n await safeProgress(client, id, { message: `${cfg.runnerId} spawning ${model} (${tier}, effort ${dispatchMode})` });\r\n const cap = typeof task.max_budget_usd === 'number' ? task.max_budget_usd : resolveSpendCapUsd();\r\n const run = await runClaudeTask({\r\n prompt: effortPrompt,\r\n cwd: wt.worktreeDir,\r\n claudeBin: cfg.claudeBin,\r\n permissionMode: effectivePermissionMode,\r\n maxTurns: effectiveMaxTurns,\r\n model,\r\n env: process.env,\r\n onProgress: (text) => {\r\n void safeProgress(client, id, { message: text });\r\n },\r\n shouldCancel: async () => {\r\n const t = await client.getTask(id).catch(() => null);\r\n return Boolean(t && t.status === 'cancelled');\r\n },\r\n cancelPollMs: cfg.cancelPollMs,\r\n maxWallClockMs: cfg.maxWallClockMs,\r\n });\r\n if (run.killed) {\r\n log(`task ${id} cancelled by operator`);\r\n return;\r\n }\r\n if (run.timedOut) {\r\n await safeProgress(client, id, {\r\n status: 'failed',\r\n message: run.summary,\r\n result: 'wall_clock_timeout',\r\n cost_usd: numOrUndef(run.costUsd),\r\n });\r\n return;\r\n }\r\n if (typeof task.max_turns === 'number' && typeof run.numTurns === 'number' && run.numTurns > task.max_turns) {\r\n log(`task ${id} WARNING: agent ran ${run.numTurns} turns > max_turns ${task.max_turns}`);\r\n }\r\n // ADVISORY only \u2014 NEVER discard completed work over a notional cost estimate.\r\n // run.costUsd is Claude Code's API-EQUIVALENT token cost; on a Pro/Max\r\n // subscription (no ANTHROPIC_API_KEY) it is NOT dollars billed \u2014 the agent\r\n // runs on the operator's plan allowance. The real in-flight bound is\r\n // `maxWallClockMs`. The old hard cap discarded REAL committed bug fixes after\r\n // the agent had already done (and pushed) the work \u2014 the worst outcome\r\n // (live-found 2026-06-12: two $15 fixes thrown away). Now we log and publish.\r\n if (typeof run.costUsd === 'number' && cap > 0 && run.costUsd > cap) {\r\n log(\r\n `task ${id}: usage ~$${run.costUsd.toFixed(2)} (est, API-equivalent \u2014 not billed on a ` +\r\n `subscription) exceeded soft cap $${cap}; publishing the agent's work anyway`,\r\n );\r\n }\r\n if (!run.ok) {\r\n // PR12: a usage/rate-limit stop is recorded RATE_LIMITED (resumable) so the\r\n // scheduler can relaunch it, instead of dropped as 'failed'. Flag-gated OFF\r\n // (classifyFailureForResume returns the legacy payload when disabled).\r\n const v = classifyFailureForResume({ enabled: RATE_LIMIT_RESUME_ENABLED, run, task });\r\n if (v.rateLimited) log(`task ${id}: RATE_LIMITED (resumeAfter=${v.resumeAfter || 'backoff'}); queued (${v.recorded ? 'ok' : 'queue-write-failed'})`);\r\n await safeProgress(client, id, { ...v.progress, cost_usd: numOrUndef(run.costUsd) });\r\n return;\r\n }\r\n // Primary: uncommitted edits (the runner commits + PRs them \u2014 the intended\r\n // flow per the dispatch preamble). Safety net: if the agent committed its\r\n // work to a branch anyway, recover those committed files rather than\r\n // discarding them as `no_changes` (live-found 2026-06-12).\r\n let files = listChangedFiles(wt.worktreeDir);\r\n let alreadyCommitted = false;\r\n if (files.length === 0) {\r\n const committed = listCommittedFiles(wt.worktreeDir);\r\n if (committed.length > 0) {\r\n files = committed;\r\n alreadyCommitted = true;\r\n log(`task ${id}: agent committed ${committed.length} file(s) to a branch; recovering`);\r\n }\r\n }\r\n // Strip agent scratch (drafted PR bodies, tmp notes) so it never lands in a\r\n // PR \u2014 leaked into #6515 as .tmp-pr-body.md / tmp/pr-body.md. Log every drop\r\n // so the filter is observable, never a silent swallow.\r\n const scratch = files.filter(isAgentScratch);\r\n if (scratch.length > 0) {\r\n files = files.filter((f) => !isAgentScratch(f));\r\n log(`task ${id}: dropped ${scratch.length} scratch file(s): ${scratch.join(', ')}`);\r\n }\r\n if (files.length === 0) {\r\n await safeProgress(client, id, {\r\n status: 'failed',\r\n message: 'agent made no file changes',\r\n result: 'no_changes',\r\n cost_usd: numOrUndef(run.costUsd),\r\n });\r\n return;\r\n }\r\n // Final cancel check before the irreversible PR open \u2014 closes the\r\n // cancel-poll-window gap between the agent finishing and the PR being created.\r\n const fresh = await client.getTask(id).catch(() => null);\r\n if (fresh && fresh.status === 'cancelled') {\r\n log(`task ${id} cancelled before PR open; discarding changes`);\r\n return;\r\n }\r\n\r\n await safeProgress(client, id, { message: `opening PR for ${files.length} changed file(s)` });\r\n const pr = openCodeTaskPr(wt.worktreeDir, files, {\r\n title: `code-task: ${task.prompt}`,\r\n body: buildPrBody(task, run, files),\r\n alreadyCommitted,\r\n });\r\n await safeProgress(client, id, {\r\n status: 'pr_opened',\r\n message: `opened ${pr.prUrl}`,\r\n pr_url: pr.prUrl,\r\n pr_number: pr.prNumber,\r\n result: String(run.summary).slice(0, 2000),\r\n cost_usd: numOrUndef(run.costUsd),\r\n });\r\n log(`task ${id} \u2192 PR ${pr.prUrl}`);\r\n\r\n // Active PR watching: track this dispatched PR so the daemon monitors its CI\r\n // and auto-fixes a failure (cap `watchMaxFix`). A fix-PR (its prompt carries\r\n // CI_FIX_MARKER) is NEVER tracked, so a fix that also fails cannot chain into\r\n // an unbounded supersede loop on the operator's subscription.\r\n if (cfg.watchEnabled && !String(task.prompt || '').includes(CI_FIX_MARKER)) {\r\n await trackDispatchedPr({\r\n prNumber: pr.prNumber,\r\n repo: task.repo,\r\n branch: pr.branch,\r\n taskId: id,\r\n }).catch((e) => log(`watch: track failed for #${pr.prNumber}: ${e.message}`));\r\n }\r\n } catch (err) {\r\n const msg = err && err.message ? err.message : String(err);\r\n log(`task ${id} error: ${msg}`);\r\n await safeProgress(client, id, {\r\n status: 'failed',\r\n message: `runner error: ${msg}`.slice(0, 1500),\r\n result: msg.slice(0, 2000),\r\n }).catch(() => {});\r\n } finally {\r\n if (worktreeName) cleanupFixWorktree(worktreeName);\r\n }\r\n}\r\nexport async function main({ env = process.env, once = false } = {}) {\r\n const cfg = loadConfig(env);\r\n const client = createControlPlaneClient({ env });\r\n let stopping = false;\r\n let active = 0;\r\n\r\n const stop = (sig) => {\r\n if (stopping) return;\r\n stopping = true;\r\n log(`${sig} received \u2014 draining ${active} active task(s), no new claims`);\r\n };\r\n process.on('SIGINT', () => stop('SIGINT'));\r\n process.on('SIGTERM', () => stop('SIGTERM'));\r\n\r\n // In-product runner control (Phase 8.4): localhost-only status + Stop surface\r\n // for /virtualoffice, so the operator no longer needs the desktop HTA.\r\n const startedAt = Date.now();\r\n const controlServer = startDaemonControl({\r\n cfg,\r\n requestStop: () => stop('web-control'),\r\n getActiveCount: () => active,\r\n isRunning: () => !stopping,\r\n startedAt,\r\n log,\r\n });\r\n log(\r\n `up as ${cfg.runnerId} \u2192 ${env.VO_CONTROL_PLANE_URL} ` +\r\n `(concurrency ${cfg.maxConcurrency}, poll ${cfg.pollSec}s, once=${once})`,\r\n );\r\n for (const line of describeClaimScoping(cfg, env)) log(line);\r\n log(\r\n cfg.watchEnabled\r\n ? `PR watcher ON \u2014 auto-fix ${cfg.watchMaxFix}/PR on CI failure, never auto-merges, every ${cfg.watchIntervalSec}s (VO_CODE_RUNNER_WATCH=0 to disable)`\r\n : 'PR watcher OFF (VO_CODE_RUNNER_WATCH=0)',\r\n );\r\n\r\n let lastSessionForward = 0;\r\n let lastWatchCycle = 0;\r\n const runWatch = makeWatchRunner({ client, log, maxFixAttempts: cfg.watchMaxFix });\r\n while (!stopping) {\r\n // 'Sees ALL agents': forward the local session spool to the cloud so the\r\n // Mission Control Sessions panel shows EVERY Claude Code session, not just\r\n // VO-dispatched tasks. Best-effort, throttled, never blocks claiming.\r\n if (cfg.sessionForwardSec > 0 && Date.now() - lastSessionForward >= cfg.sessionForwardSec * 1000) {\r\n lastSessionForward = Date.now();\r\n forwardSessionSpool({\r\n baseUrl: String(env.VO_CONTROL_PLANE_URL || '').replace(/\\/$/, ''),\r\n token: env.VO_CONTROL_PLANE_ADMIN_TOKEN || '',\r\n operatorSeed: cfg.operatorSeed,\r\n }).catch(() => {});\r\n }\r\n\r\n // Active PR watcher: monitor dispatched PRs and auto-dispatch one CI fix on\r\n // failure. Throttled, never auto-merges, capped per PR. Best-effort.\r\n if (cfg.watchEnabled && Date.now() - lastWatchCycle >= cfg.watchIntervalSec * 1000) {\r\n lastWatchCycle = Date.now();\r\n runWatch()\r\n .then((r) => {\r\n if (r.checked > 0) log(`watch: ${r.checked} PR(s) checked, ${r.fixed} fix(es), ${r.untracked} untracked`);\r\n })\r\n .catch((e) => log(`watch cycle error: ${e.message}`));\r\n }\r\n if (active >= cfg.maxConcurrency) {\r\n await sleep(cfg.pollSec * 1000);\r\n continue;\r\n }\r\n let task;\r\n try {\r\n task = await client.claim(cfg.runnerId, cfg.servedRepos, cfg.servedOperators);\r\n } catch (err) {\r\n log(`claim error: ${err.message}`);\r\n if (once) break;\r\n await sleep(cfg.pollSec * 1000);\r\n continue;\r\n }\r\n if (!task) {\r\n if (once) {\r\n log('no pending task; --once exiting');\r\n break;\r\n }\r\n await sleep(cfg.pollSec * 1000);\r\n continue;\r\n }\r\n\r\n log(`claimed task ${task.code_task_id} (${task.repo})`);\r\n active += 1;\r\n const done = processOneTask(client, task, cfg).finally(() => {\r\n active -= 1;\r\n });\r\n if (once) {\r\n await done;\r\n break;\r\n }\r\n }\r\n\r\n // Drain in-flight tasks before exit.\r\n while (active > 0) {\r\n await sleep(500);\r\n }\r\n if (controlServer) controlServer.close();\r\n log('stopped');\r\n}\r\n\r\nconst invokedDirectly =\r\n process.argv[1] &&\r\n fileURLToPath(import.meta.url) === process.argv[1] &&\r\n // Bundle-safe: only self-start when THIS file is the real entry, not when the\r\n // module is inlined into a bundle (e.g. @algosuite/vo-mcp's dist/runner-cli.js,\r\n // which calls main() itself \u2014 without this, `node dist/runner-cli.js` would\r\n // start a SECOND daemon loop and double-claim tasks).\r\n import.meta.url.endsWith('code-runner-daemon.mjs');\r\nif (invokedDirectly) {\r\n const once = process.argv.includes('--once');\r\n main({ once }).catch((err) => {\r\n console.error('[code-runner] fatal:', err);\r\n process.exit(1);\r\n });\r\n}\r\n", "/**\r\n * Lightweight git-worktree helper for the bundled `vo-mcp runner` (bring-your-own).\r\n *\r\n * Drop-in replacement for the daemon's\r\n * `scripts/virtual-office/orchestrator/validation-and-worktree.mjs`\r\n * createFixWorktree/cleanupFixWorktree \u2014 but with ZERO Nexus-repo coupling. The\r\n * original shells the Nexus-only `scripts/agent-worktree.mjs` and transitively\r\n * pulls `orchestrator/config` (a hardcoded PROJECT_ROOT) + `qa/patch-syntax-guard`\r\n * (the `esbuild` native dep), neither of which exist on a friend's machine. This\r\n * version shells plain `git worktree add/remove` inside the operator's OWN clone\r\n * (`VO_CODE_RUNNER_REPO`, defaulting to cwd), so the runner bundles clean and\r\n * runs anywhere. Returns the SAME shape the daemon expects: { worktreeDir, worktreeName }.\r\n *\r\n * esbuild swaps this in for the heavy original at bundle time via an onResolve\r\n * redirect in scripts/bundle.mjs (the daemon source is never edited).\r\n */\r\nimport { spawnSync } from 'node:child_process';\r\nimport path from 'node:path';\r\nimport fs from 'node:fs';\r\n\r\n/** The operator's repo clone the runner builds in (set by runner-cli; defaults to cwd). */\r\nfunction repoRoot() {\r\n return process.env.VO_CODE_RUNNER_REPO || process.cwd();\r\n}\r\n\r\n/** Lower-case, filesystem-safe name segment. */\r\nfunction sanitize(value, fallback) {\r\n const cleaned = String(value || '')\r\n .trim()\r\n .toLowerCase()\r\n .replace(/[^a-z0-9._-]+/g, '-')\r\n .replace(/^-+|-+$/g, '');\r\n return cleaned || fallback;\r\n}\r\n\r\n/**\r\n * Create a fresh worktree off origin/main inside the operator's clone.\r\n * Mirrors the daemon's call: createFixWorktree('code-task', { source: <id8> }).\r\n * On any failure, falls back to the repo root (no isolation) \u2014 same as the original.\r\n */\r\nexport function createFixWorktree(kind, error = {}) {\r\n const root = repoRoot();\r\n const safeKind = sanitize(kind, 'task');\r\n const safeTarget = sanitize(error.source || error.tester || 'run', 'run').slice(0, 24);\r\n const stamp = new Date().toISOString().replace(/[:.]/g, '-');\r\n const worktreeName = `${safeKind}-${safeTarget}-${stamp}`;\r\n const branchName = `vo/${worktreeName}`;\r\n const worktreeDir = path.join(root, '.agent-worktrees', worktreeName);\r\n\r\n // Base the worktree on a CURRENT origin/main (the daemon's design = a fresh\r\n // worktree off origin/main). Refresh origin first; ignore a fetch failure\r\n // (offline / no remote) and let the add fall back below.\r\n spawnSync('git', ['fetch', 'origin', 'main'], { cwd: root, timeout: 120_000 });\r\n const add = spawnSync(\r\n 'git',\r\n ['worktree', 'add', '-B', branchName, worktreeDir, 'origin/main'],\r\n { cwd: root, encoding: 'utf8', timeout: 120_000 },\r\n );\r\n if (add.status === 0 && fs.existsSync(worktreeDir)) {\r\n return { worktreeDir, worktreeName };\r\n }\r\n console.error(\r\n `[vo-mcp runner] worktree isolation unavailable: ${String(add.stderr || add.error || '').slice(0, 200)}`,\r\n );\r\n return { worktreeDir: root, worktreeName: '' };\r\n}\r\n\r\n/** Remove a worktree created by createFixWorktree. No-op when name is empty. */\r\nexport function cleanupFixWorktree(worktreeName) {\r\n if (!worktreeName) return;\r\n const root = repoRoot();\r\n const worktreeDir = path.join(root, '.agent-worktrees', worktreeName);\r\n spawnSync('git', ['worktree', 'remove', '--force', worktreeDir], { cwd: root, timeout: 120_000 });\r\n}\r\n", "/**\r\n * Env-based spend cap for the bundled `vo-mcp runner`.\r\n *\r\n * Replaces the daemon's `scripts/virtual-office/spend-cap-guard.mjs`, whose\r\n * module pulls `bug-work-key.mjs` + the per-bug Firestore cap machinery the\r\n * heal-orchestrator uses \u2014 none of which a friend's runner has. The daemon only\r\n * calls the argless `resolveSpendCapUsd()`, and its check is ADVISORY (it logs\r\n * and publishes the agent's work regardless \u2014 a dispatched agent runs on the\r\n * operator's own Claude subscription, so the cost is a notional API-equivalent,\r\n * not billed). So the BYO default is 0 = no advisory cap; opt in with\r\n * VO_SPEND_CAP_USD / VO_CODE_DISPATCH_CAP_USD. A single task's max_budget_usd\r\n * still applies (the daemon honors it directly).\r\n *\r\n * esbuild swaps this in for the heavy original at bundle time (see scripts/bundle.mjs).\r\n */\r\nexport function resolveSpendCapUsd(\r\n value = process.env.VO_SPEND_CAP_USD ?? process.env.VO_CODE_DISPATCH_CAP_USD,\r\n) {\r\n const parsed = Number.parseFloat(String(value ?? ''));\r\n // Unset / non-numeric / negative \u21D2 0 (no advisory cap). The daemon treats\r\n // cap <= 0 as \"no cap\" (its check is `cap > 0 && costUsd > cap`).\r\n if (!Number.isFinite(parsed) || parsed < 0) return 0;\r\n return parsed;\r\n}\r\n", "/**\r\n * control-plane-client \u2014 the runner's OUTBOUND link to vo-control-plane.\r\n *\r\n * Increment 6 (Code-from-Anywhere). The daemon never exposes a port; it reaches\r\n * OUT to the control-plane (no inbound hole, no Tailscale \u2014 design \u00A72). Auth:\r\n * prefer the static admin token (`VO_CONTROL_PLANE_ADMIN_TOKEN`, the V1 local\r\n * dogfood path); fall back to a per-user Firebase ID token via the shared\r\n * orchestrator auth (`SMOKE_*` creds \u2192 allow-listed operator \u2192 admin).\r\n *\r\n * Endpoints used:\r\n * POST /api/v1/code-task/claim \u2192 claim the next pending task\r\n * PATCH /api/v1/code-task/:id/progress \u2192 stream progress / set terminal\r\n * GET /api/v1/code-task/:id \u2192 poll status (cancel detection)\r\n */\r\n\r\nlet cachedFirebaseToken = null;\r\n\r\nasync function resolveBearer(env) {\r\n const adminToken = env.VO_CONTROL_PLANE_ADMIN_TOKEN;\r\n if (adminToken) return adminToken;\r\n if (cachedFirebaseToken) return cachedFirebaseToken;\r\n // Lazy import \u2014 Firebase auth is only needed when no admin token is present.\r\n const { getFirebaseAuth } = await import('../orchestrator-firestore/auth.mjs');\r\n const auth = await getFirebaseAuth({ env });\r\n if (!auth || !auth.idToken) {\r\n throw new Error(\r\n 'no control-plane credential: set VO_CONTROL_PLANE_ADMIN_TOKEN, or SMOKE_EMAIL/SMOKE_PASSWORD/SMOKE_API_KEY',\r\n );\r\n }\r\n cachedFirebaseToken = auth.idToken;\r\n return cachedFirebaseToken;\r\n}\r\n\r\n/**\r\n * Build a client. `baseUrl` defaults to `VO_CONTROL_PLANE_URL`. `fetchImpl`\r\n * and `env` are injectable for tests.\r\n */\r\nexport function createControlPlaneClient({\r\n baseUrl = process.env.VO_CONTROL_PLANE_URL || '',\r\n env = process.env,\r\n fetchImpl = fetch,\r\n} = {}) {\r\n if (!baseUrl) {\r\n throw new Error('VO_CONTROL_PLANE_URL is required for the code-runner daemon');\r\n }\r\n const root = baseUrl.replace(/\\/+$/, '');\r\n\r\n async function req(method, path, body) {\r\n const bearer = await resolveBearer(env);\r\n return fetchImpl(`${root}${path}`, {\r\n method,\r\n headers: {\r\n 'content-type': 'application/json',\r\n authorization: `Bearer ${bearer}`,\r\n },\r\n body: body === undefined ? undefined : JSON.stringify(body),\r\n });\r\n }\r\n\r\n return {\r\n /**\r\n * Claim the next pending task. Returns the task or null (empty queue).\r\n * `repos` (optional `owner/name` list) and `operatorIds` (optional\r\n * `operator_id` list) scope the claim so this daemon only picks up tasks it\r\n * serves \u2014 the control-plane filters by both (logical AND), so another\r\n * operator's task never lands on (or bills) this machine.\r\n */\r\n async claim(runnerId, repos, operatorIds) {\r\n const body = { runner_id: runnerId };\r\n if (Array.isArray(repos) && repos.length > 0) body.repos = repos;\r\n if (Array.isArray(operatorIds) && operatorIds.length > 0) body.operator_ids = operatorIds;\r\n const res = await req('POST', '/api/v1/code-task/claim', body);\r\n if (res.status === 401) {\r\n cachedFirebaseToken = null; // force re-auth next call\r\n throw new Error('claim unauthorized (401)');\r\n }\r\n if (!res.ok) throw new Error(`claim failed: HTTP ${res.status}`);\r\n const json = await res.json();\r\n return json && json.task ? json.task : null;\r\n },\r\n\r\n /**\r\n * Enqueue a new code-task (used by the PR watcher to auto-dispatch a CI fix).\r\n * Server derives operator/tenant from the daemon's authenticated principal.\r\n * Returns the created task, or throws on a non-2xx response.\r\n */\r\n async enqueueCodeTask({ repo, prompt, max_budget_usd, max_turns }) {\r\n const body = { repo, prompt };\r\n if (typeof max_budget_usd === 'number') body.max_budget_usd = max_budget_usd;\r\n if (typeof max_turns === 'number') body.max_turns = max_turns;\r\n const res = await req('POST', '/api/v1/code-task', body);\r\n if (res.status === 401) {\r\n cachedFirebaseToken = null;\r\n throw new Error('enqueue unauthorized (401)');\r\n }\r\n if (!res.ok) throw new Error(`enqueue failed: HTTP ${res.status}`);\r\n const json = await res.json();\r\n return json && json.task ? json.task : null;\r\n },\r\n\r\n /**\r\n * Append progress / set terminal status. Returns\r\n * { task } \u2014 applied\r\n * { terminal: true } \u2014 task already terminal (operator cancelled): STOP\r\n */\r\n async postProgress(taskId, patch) {\r\n const res = await req('PATCH', `/api/v1/code-task/${taskId}/progress`, patch);\r\n if (res.status === 409) return { terminal: true };\r\n if (res.status === 404) return { terminal: true, missing: true };\r\n if (!res.ok) throw new Error(`progress failed: HTTP ${res.status}`);\r\n const json = await res.json();\r\n return { task: json && json.task };\r\n },\r\n\r\n /** Read the current task (cancel detection). Null on 404. */\r\n async getTask(taskId) {\r\n const res = await req('GET', `/api/v1/code-task/${taskId}`);\r\n if (res.status === 404) return null;\r\n if (!res.ok) throw new Error(`getTask failed: HTTP ${res.status}`);\r\n const json = await res.json();\r\n return json ? json.task : null;\r\n },\r\n\r\n /**\r\n * Report this machine's rolling-7-day Claude Code token usage (the real\r\n * weekly-capacity gauge) PLUS the operator's real Claude weekly % (when\r\n * available). The daemon authenticates as admin, so the target `operatorId`\r\n * is named explicitly. Best-effort; throws on a non-2xx so the caller can\r\n * log + move on.\r\n *\r\n * `tokens` = { input_tokens, output_tokens, cache_creation_tokens, cache_read_tokens }.\r\n * Optional: `claudeWeeklyPct` (number) + `claudeWeeklyResetsAt` (ISO string | null).\r\n */\r\n async postWeeklyTokens({ operatorId, runnerId, tokens, claudeWeeklyPct, claudeWeeklyResetsAt }) {\r\n const body = {\r\n operator_id: operatorId,\r\n runner_id: runnerId,\r\n input_tokens: tokens.input_tokens,\r\n output_tokens: tokens.output_tokens,\r\n cache_creation_tokens: tokens.cache_creation_tokens,\r\n cache_read_tokens: tokens.cache_read_tokens,\r\n };\r\n if (typeof claudeWeeklyPct === 'number') {\r\n body.claude_weekly_pct = claudeWeeklyPct;\r\n }\r\n if (claudeWeeklyResetsAt !== undefined) {\r\n body.claude_weekly_resets_at = claudeWeeklyResetsAt;\r\n }\r\n const res = await req('POST', '/api/v1/weekly-tokens', body);\r\n if (res.status === 401) {\r\n cachedFirebaseToken = null;\r\n throw new Error('weekly-tokens unauthorized (401)');\r\n }\r\n if (!res.ok) throw new Error(`weekly-tokens failed: HTTP ${res.status}`);\r\n return true;\r\n },\r\n\r\n /**\r\n * Read the operator's dispatch-mode config (Fast\u2192Ultracode effort setting).\r\n * Returns the mode string ('fast'|'standard'|'deep'|'ultra'|'ultracode'),\r\n * defaulting to 'standard' on any error. Never throws \u2014 best-effort.\r\n */\r\n async getDispatchMode() {\r\n try {\r\n const res = await req('GET', '/api/v1/dispatch-mode-config');\r\n if (!res.ok) return 'standard';\r\n const json = await res.json();\r\n return json?.dispatchMode || 'standard';\r\n } catch {\r\n return 'standard';\r\n }\r\n },\r\n };\r\n}\r\n", "/**\r\n * claude-runner \u2014 spawn a headless `claude -p` agent and stream its progress.\r\n *\r\n * Increment 6 (Code-from-Anywhere). The daemon hands a CodeTask prompt here;\r\n * we spawn `claude -p \"<prompt>\" --output-format stream-json` in the task's\r\n * worktree, parse the event stream for progress text + final cost, and resolve\r\n * a result. A cancel poller kills the child when the operator hits the kill\r\n * switch.\r\n *\r\n * CRITICAL (design \u00A73): we do NOT pass `--bare`. `--bare` strips CLAUDE.md,\r\n * the operator memory, the VO skills, the hooks and vo-mcp \u2014 i.e. exactly the\r\n * full-agent context that makes the runner \"the operator's session\". The\r\n * permission posture comes from the operator's `~/.claude/settings.json`\r\n * deny-list (inherited) PLUS the configurable `--permission-mode` here.\r\n *\r\n * `parseStreamEvent` + `buildClaudeArgs` are pure and unit-tested.\r\n *\r\n * BYO-runner Phase 1: this module now ALSO exports a ClaudeRunner class that\r\n * implements the AgentRunner interface. The existing `runClaudeTask` +\r\n * `buildClaudeArgs` + `parseStreamEvent` exports are UNCHANGED and still used\r\n * by the daemon \u2014 the ClaudeRunner is purely additive for the Phase 2 daemon\r\n * refactor.\r\n */\r\nimport { spawn } from 'node:child_process';\r\nimport { spawnSync } from 'node:child_process';\r\n\r\nexport const DEFAULT_PERMISSION_MODE = 'acceptEdits';\r\n\r\n/** Extract concatenated text from a Claude message `content` block array. */\r\nfunction extractText(content) {\r\n if (typeof content === 'string') return content.trim();\r\n if (Array.isArray(content)) {\r\n return content\r\n .filter((b) => b && b.type === 'text' && typeof b.text === 'string')\r\n .map((b) => b.text)\r\n .join('')\r\n .trim();\r\n }\r\n return '';\r\n}\r\n\r\n/**\r\n * Parse one stream-json line into a normalized event:\r\n * { kind: 'progress', text } \u2014 assistant said something\r\n * { kind: 'result', isError, costUsd, summary, numTurns } \u2014 final result event\r\n * null \u2014 ignorable / unparseable\r\n * Tolerant of unknown event types and malformed lines (returns null).\r\n */\r\nexport function parseStreamEvent(line) {\r\n const trimmed = String(line || '').trim();\r\n if (!trimmed) return null;\r\n let evt;\r\n try {\r\n evt = JSON.parse(trimmed);\r\n } catch {\r\n return null;\r\n }\r\n if (!evt || typeof evt !== 'object') return null;\r\n\r\n if (evt.type === 'assistant' && evt.message && evt.message.content) {\r\n const text = extractText(evt.message.content);\r\n return text ? { kind: 'progress', text } : null;\r\n }\r\n if (evt.type === 'result') {\r\n const isError =\r\n Boolean(evt.is_error) ||\r\n evt.subtype === 'error_max_turns' ||\r\n evt.subtype === 'error_during_execution';\r\n return {\r\n kind: 'result',\r\n isError,\r\n costUsd: typeof evt.total_cost_usd === 'number' ? evt.total_cost_usd : null,\r\n summary:\r\n typeof evt.result === 'string' && evt.result.length > 0\r\n ? evt.result\r\n : evt.subtype || (isError ? 'error' : 'completed'),\r\n numTurns: typeof evt.num_turns === 'number' ? evt.num_turns : null,\r\n };\r\n }\r\n return null;\r\n}\r\n\r\n/**\r\n * Build the `claude` argv. NEVER includes `--bare` (design \u00A73). `--verbose` is\r\n * required alongside `--output-format stream-json` for the streamed events.\r\n */\r\nexport function buildClaudeArgs({ permissionMode = DEFAULT_PERMISSION_MODE, maxTurns, model } = {}) {\r\n // The prompt is fed via STDIN (see runClaudeTask), NOT argv. On Windows\r\n // `claude` is a `.cmd` shim that spawn can only resolve with shell:true, and\r\n // shell:true + an untrusted prompt in argv would be a command-injection hole.\r\n // stdin keeps the operator prompt inert.\r\n const args = [\r\n '-p',\r\n '--output-format',\r\n 'stream-json',\r\n '--verbose',\r\n '--permission-mode',\r\n String(permissionMode || DEFAULT_PERMISSION_MODE),\r\n ];\r\n if (Number.isInteger(maxTurns) && maxTurns > 0) {\r\n args.push('--max-turns', String(maxTurns));\r\n }\r\n if (model) {\r\n args.push('--model', String(model));\r\n }\r\n return args;\r\n}\r\n\r\n/**\r\n * Spawn the agent and stream. Resolves\r\n * { ok, costUsd, summary, numTurns, killed, timedOut }\r\n * `onProgress(text)` is called per assistant message. `shouldCancel()` is\r\n * polled every `cancelPollMs`; when it returns true the child is SIGTERM'd\r\n * (then SIGKILL after a grace) and the result is marked `killed`.\r\n * `maxWallClockMs` (>0) is a HARD deadline \u2014 the only enforced spend bound,\r\n * since `max_budget_usd` can only be checked post-hoc. The child is killed and\r\n * the result marked `timedOut` when the deadline passes.\r\n */\r\nexport function runClaudeTask({\r\n prompt,\r\n cwd,\r\n claudeBin = 'claude',\r\n permissionMode,\r\n maxTurns,\r\n model,\r\n env = process.env,\r\n onProgress = () => {},\r\n shouldCancel = async () => false,\r\n cancelPollMs = 5000,\r\n maxWallClockMs = 0,\r\n spawnImpl = spawn,\r\n}) {\r\n return new Promise((resolve) => {\r\n const args = buildClaudeArgs({ permissionMode, maxTurns, model });\r\n const child = spawnImpl(claudeBin, args, {\r\n cwd,\r\n env: { ...env },\r\n stdio: ['pipe', 'pipe', 'pipe'],\r\n // Windows: `claude` is a `.cmd` shim \u2192 spawn needs a shell to resolve it\r\n // (without it: spawn ENOENT). Safe because the prompt goes via stdin\r\n // below, never argv, so the shell never sees untrusted input.\r\n shell: process.platform === 'win32',\r\n windowsHide: true,\r\n });\r\n // Feed the prompt via stdin so it never hits a shell (injection-safe).\r\n try {\r\n child.stdin.write(String(prompt));\r\n child.stdin.end();\r\n } catch {\r\n /* spawn failed (e.g. ENOENT) \u2014 the 'error' handler resolves the result */\r\n }\r\n\r\n let buffer = '';\r\n let result = { ok: false, costUsd: null, summary: '', numTurns: null, killed: false };\r\n let killed = false;\r\n let timedOut = false;\r\n let stderrTail = '';\r\n\r\n const hardKill = () => {\r\n try {\r\n child.kill('SIGTERM');\r\n } catch {\r\n /* already dead */\r\n }\r\n setTimeout(() => {\r\n try {\r\n child.kill('SIGKILL');\r\n } catch {\r\n /* already dead */\r\n }\r\n }, 5000);\r\n };\r\n const wallTimer =\r\n maxWallClockMs > 0\r\n ? setTimeout(() => {\r\n timedOut = true;\r\n clearInterval(poll);\r\n hardKill();\r\n }, maxWallClockMs)\r\n : null;\r\n\r\n child.stdout.on('data', (chunk) => {\r\n buffer += chunk.toString();\r\n let nl;\r\n while ((nl = buffer.indexOf('\\n')) >= 0) {\r\n const line = buffer.slice(0, nl);\r\n buffer = buffer.slice(nl + 1);\r\n const evt = parseStreamEvent(line);\r\n if (!evt) continue;\r\n if (evt.kind === 'progress') {\r\n try {\r\n onProgress(evt.text.slice(0, 1500));\r\n } catch {\r\n /* progress sink is best-effort */\r\n }\r\n } else if (evt.kind === 'result') {\r\n result = {\r\n ...result,\r\n ok: !evt.isError,\r\n costUsd: evt.costUsd,\r\n summary: evt.summary,\r\n numTurns: evt.numTurns,\r\n };\r\n }\r\n }\r\n });\r\n\r\n child.stderr.on('data', (c) => {\r\n stderrTail = (stderrTail + c.toString()).slice(-4000);\r\n });\r\n\r\n child.on('error', (err) => {\r\n clearInterval(poll);\r\n if (wallTimer) clearTimeout(wallTimer);\r\n resolve({ ...result, ok: false, summary: `spawn error: ${err.message}` });\r\n });\r\n\r\n const poll = setInterval(() => {\r\n Promise.resolve()\r\n .then(() => shouldCancel())\r\n .then((cancel) => {\r\n if (cancel && !killed) {\r\n killed = true;\r\n clearInterval(poll);\r\n hardKill();\r\n }\r\n })\r\n .catch(() => {});\r\n }, cancelPollMs);\r\n\r\n child.on('close', (code) => {\r\n clearInterval(poll);\r\n if (wallTimer) clearTimeout(wallTimer);\r\n if (timedOut) {\r\n resolve({\r\n ...result,\r\n ok: false,\r\n timedOut: true,\r\n summary: `wall-clock timeout (${maxWallClockMs}ms)`,\r\n });\r\n return;\r\n }\r\n if (killed) {\r\n resolve({ ...result, ok: false, killed: true, summary: 'cancelled by operator' });\r\n return;\r\n }\r\n if (!result.summary && code !== 0) {\r\n result.summary = stderrTail.slice(-500) || `claude exited ${code}`;\r\n }\r\n resolve({ ...result, ok: result.ok && code === 0 });\r\n });\r\n });\r\n}\r\n\r\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n// AgentRunner interface implementation (BYO-runner Phase 1, additive)\r\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n\r\n/**\r\n * ClaudeRunner \u2014 AgentRunner implementation for the Claude CLI.\r\n *\r\n * Delegates to the EXISTING `buildClaudeArgs` + `parseStreamEvent` exports\r\n * (which the daemon still imports directly) so there's zero behavior change.\r\n * The daemon will adopt this interface in Phase 2; for now this is purely\r\n * additive to allow testing the abstraction without touching the daemon.\r\n *\r\n * @implements {import('./agent-runner-interface.mjs').AgentRunner}\r\n */\r\nexport class ClaudeRunner {\r\n get binary() {\r\n return 'claude';\r\n }\r\n\r\n buildArgs({ permissionMode, maxTurns, model } = {}) {\r\n return buildClaudeArgs({ permissionMode, maxTurns, model });\r\n }\r\n\r\n parseEvent(line) {\r\n return parseStreamEvent(line);\r\n }\r\n\r\n getSpawnOptions() {\r\n return {\r\n shell: process.platform === 'win32',\r\n windowsHide: true,\r\n };\r\n }\r\n\r\n /**\r\n * Best-effort auth check: is `claude` on PATH and can we verify login?\r\n * Never throws. If we can't cheaply detect auth, we return installed:true\r\n * and let the real spawn fail with a clearer error from the CLI itself.\r\n */\r\n async checkAuth() {\r\n try {\r\n const { status, error } = spawnSync('claude', ['--version'], {\r\n shell: process.platform === 'win32',\r\n windowsHide: true,\r\n timeout: 3000,\r\n stdio: 'ignore',\r\n });\r\n if (error) {\r\n return {\r\n installed: false,\r\n authenticated: false,\r\n message: `claude not found on PATH: ${error.message}`,\r\n };\r\n }\r\n if (status !== 0) {\r\n return {\r\n installed: true,\r\n authenticated: false,\r\n message: 'claude binary exists but --version failed (auth unclear)',\r\n };\r\n }\r\n // claude --version succeeds \u2192 binary is callable. We can't cheaply\r\n // detect auth without spawning a real session, so assume the operator\r\n // is logged in. If they aren't, the daemon spawn will fail + surface\r\n // the real auth error.\r\n return {\r\n installed: true,\r\n authenticated: true,\r\n message: 'claude binary found (auth check is best-effort)',\r\n };\r\n } catch (err) {\r\n return {\r\n installed: false,\r\n authenticated: false,\r\n message: `checkAuth probe failed: ${err.message}`,\r\n };\r\n }\r\n }\r\n}\r\n\r\n/** Singleton instance for convenience. */\r\nexport const claudeRunner = new ClaudeRunner();\r\n", "// rate-limit-resume.mjs \u2014 record a rate-limited code-task to the local resume\r\n// queue so a resume scheduler can relaunch it. PR12 (Pillar 6).\r\n//\r\n// The VO daemon, when it detects a usage/rate-limit stop (not a code bug), appends\r\n// an entry here instead of dropping the task as an indistinguishable 'failed'.\r\n// The queue is append-only JSONL at ~/.claude/resume-queue.jsonl. ACTUAL\r\n// re-dispatch (which spends tokens) is the resume scheduler's job (PR12b) \u2014 this\r\n// module only RECORDS, so it is safe + cost-free on its own.\r\nimport { appendFileSync, mkdirSync } from 'node:fs';\r\nimport { homedir } from 'node:os';\r\nimport { join, dirname } from 'node:path';\r\nimport { detectRateLimit } from '../../ci/rate-limit-detector-core.mjs';\r\n\r\nexport function resumeQueuePath() {\r\n return join(homedir(), '.claude', 'resume-queue.jsonl');\r\n}\r\n\r\n// Build the resume-queue entry (pure \u2014 no I/O \u2014 so it is unit-testable).\r\nexport function buildResumeEntry({ task = {}, resumeAfter = null, summary = '', at } = {}) {\r\n return {\r\n kind: 'rate_limited_code_task',\r\n at,\r\n code_task_id: task.code_task_id || null,\r\n repo: task.repo || null,\r\n operator_id: task.operator_id || null,\r\n prompt: task.prompt || '',\r\n resume_after: resumeAfter, // ISO string, or null (scheduler backs off when null)\r\n attempts: Number(task._resume_attempts || 0) + 1,\r\n summary: String(summary).slice(0, 500),\r\n };\r\n}\r\n\r\n// Append a resume entry. Best-effort + fail-soft: a queue-write failure must never\r\n// break the daemon's task handling (the task is still reported failed either way).\r\nexport function recordRateLimited({ task = {}, resumeAfter = null, summary = '', queuePath = resumeQueuePath(), at = new Date().toISOString() } = {}) {\r\n const entry = buildResumeEntry({ task, resumeAfter, summary, at });\r\n try {\r\n mkdirSync(dirname(queuePath), { recursive: true });\r\n appendFileSync(queuePath, `${JSON.stringify(entry)}\\n`, 'utf-8');\r\n return { ok: true, entry };\r\n } catch (e) {\r\n return { ok: false, error: e && e.message ? e.message : 'write failed', entry };\r\n }\r\n}\r\n\r\n// Decide how the daemon should report a !run.ok failure. When `enabled` and the\r\n// failure is a usage/rate-limit, record a resume-queue entry and return a\r\n// distinguishable result='rate_limited' progress payload; otherwise return the\r\n// legacy 'failed' payload. Extracted here (out of the near-cap daemon) so the\r\n// branch is unit-testable. `record`/`detect` are injectable for tests.\r\nexport function classifyFailureForResume({\r\n enabled = false,\r\n run = {},\r\n task = {},\r\n now = new Date().toISOString(),\r\n detect = detectRateLimit,\r\n record = recordRateLimited,\r\n} = {}) {\r\n if (enabled) {\r\n const rl = detect(run.summary, { now });\r\n if (rl.rateLimited) {\r\n const rec = record({ task, resumeAfter: rl.resumeAfter, summary: run.summary });\r\n return {\r\n rateLimited: true,\r\n resumeAfter: rl.resumeAfter,\r\n recorded: !!(rec && rec.ok),\r\n progress: {\r\n status: 'failed',\r\n message: `rate-limited (resumable): ${run.summary}`.slice(0, 1500),\r\n result: 'rate_limited',\r\n },\r\n };\r\n }\r\n }\r\n return {\r\n rateLimited: false,\r\n progress: {\r\n status: 'failed',\r\n message: `agent failed: ${run.summary}`.slice(0, 1500),\r\n result: String(run.summary).slice(0, 2000),\r\n },\r\n };\r\n}\r\n", "// rate-limit-detector-core.mjs \u2014 PURE, testable detection of a Claude usage /\r\n// rate-limit signal in a headless `claude -p` failure summary.\r\n//\r\n// PR12 of the PR->LIVE enforcement campaign (Pillar 6, operator add): the VO\r\n// code-runner daemon currently marks a rate-limited agent TERMINAL-FAILED with no\r\n// retry, so an agent that runs out of usage at 2am never picks its work back up.\r\n// A usage/rate-limit is an OPERATOR-ONLY / TIME-ONLY blocker (it clears when the\r\n// window resets) \u2014 the same class as PR9's engaged-but-blocked states. This\r\n// detector lets the daemon record such a stop as RATE_LIMITED { resumeAfter } so a\r\n// resume scheduler can relaunch the work, instead of silently dropping it.\r\n//\r\n// PURE: no I/O. The daemon supplies the failure text; this returns the verdict.\r\n\r\n// Conservative Claude usage/rate-limit signals. We match ONLY strong, specific\r\n// phrases so a normal agent failure is never mislabeled as resumable (which would\r\n// wrongly retry a genuine bug). Deliberately EXCLUDES \"quota exceeded\" \u2014 that is\r\n// GCP-ambiguous (a GCP quota error in the agent's work is NOT a Claude usage stop)\r\n// and matching it would false-positive. A missed signal simply falls through to\r\n// the legacy 'failed' path (the current behavior), so under-matching is the safe\r\n// failure mode.\r\nconst RATE_LIMIT_RE =\r\n /\\b(?:usage limit reached|usage limit|rate[ _-]?limit(?:ed|_error)?|too many requests|\\b429\\b|limit (?:will )?reset)/i;\r\n\r\n// Try to pull a concrete resume time out of the message (best-effort). Claude Code\r\n// surfaces forms like \"resets at 2026-06-16T15:00:00Z\", \"reset at 3:00 PM\", or a\r\n// Unix epoch. Returns an ISO string when confidently parsed, else null (the\r\n// scheduler falls back to exponential backoff when null).\r\nexport function extractResumeAfter(text, { now = null } = {}) {\r\n const s = String(text || '');\r\n // 1. ISO-8601 timestamp.\r\n const iso = s.match(/\\b(\\d{4}-\\d{2}-\\d{2}[T ]\\d{2}:\\d{2}(?::\\d{2})?(?:\\.\\d+)?(?:Z|[+-]\\d{2}:?\\d{2})?)\\b/);\r\n if (iso) {\r\n const t = Date.parse(iso[1].replace(' ', 'T'));\r\n if (Number.isFinite(t)) return new Date(t).toISOString();\r\n }\r\n // 2. Unix epoch (seconds or ms) near a reset word.\r\n const epoch = s.match(/(?:reset|resets|retry[- ]?after|available)[^0-9]{0,20}(\\d{10,13})/i);\r\n if (epoch) {\r\n let n = Number(epoch[1]);\r\n if (n < 1e12) n *= 1000; // seconds -> ms\r\n if (Number.isFinite(n)) return new Date(n).toISOString();\r\n }\r\n // 3. \"retry-after: <seconds>\" relative form (needs a `now` anchor; callers pass\r\n // a timestamp because Date.now() is unavailable in some sandboxes).\r\n const after = s.match(/retry[- ]?after[^0-9]{0,8}(\\d{1,6})\\s*(?:s|sec|seconds)?\\b/i);\r\n if (after && now != null) {\r\n const t = new Date(now).getTime() + Number(after[1]) * 1000;\r\n if (Number.isFinite(t)) return new Date(t).toISOString();\r\n }\r\n return null;\r\n}\r\n\r\n// Detect a usage/rate-limit stop. Returns { rateLimited, resumeAfter }.\r\n// rateLimited : the failure is a usage/rate-limit (resumable), not a code bug\r\n// resumeAfter : ISO string when a reset time was parseable, else null\r\nexport function detectRateLimit(text, { now = null } = {}) {\r\n const s = String(text || '');\r\n const rateLimited = RATE_LIMIT_RE.test(s);\r\n return {\r\n rateLimited,\r\n resumeAfter: rateLimited ? extractResumeAfter(s, { now }) : null,\r\n };\r\n}\r\n", "/**\r\n * publish \u2014 open a PR for a completed code-task. DELIBERATELY LIGHTER than\r\n * orchestrator/publish-auto-fix.mjs: it commits + pushes + opens a PR but does\r\n * NOT arm auto-merge. Agent-produced PRs must await the verify-before-act gate\r\n * / human review (design \u00A75.2: \"NEVER auto-merges without the verify gate\").\r\n *\r\n * Security: every git/gh invocation uses spawnSync with an ARGV ARRAY (no\r\n * shell), so the operator-supplied prompt \u2014 which flows into the PR title/body\r\n * \u2014 cannot inject shell commands.\r\n */\r\nimport { spawnSync } from 'node:child_process';\r\n\r\nfunction run(cmd, args, cwd, { timeout = 180_000, raw = false } = {}) {\r\n const r = spawnSync(cmd, args, { cwd, encoding: 'utf8', timeout });\r\n if (r.error) throw r.error;\r\n if (r.status !== 0) {\r\n throw new Error(`${cmd} ${args[0]} failed (exit ${r.status}): ${(r.stderr || '').slice(-300)}`);\r\n }\r\n const out = r.stdout || '';\r\n // `raw` preserves the exact bytes \u2014 REQUIRED for `--porcelain -z`, whose first\r\n // entry may start with a SPACE status (e.g. ` M path`); trimming it shifts the\r\n // 3-char `XY ` prefix and corrupts the path.\r\n return raw ? out : out.trim();\r\n}\r\n\r\n/**\r\n * Files changed in the worktree. Uses `--porcelain -z` (NUL-delimited, no octal\r\n * escaping or quoting) so filenames containing newlines/quotes/spaces cannot\r\n * corrupt the list or smuggle extra entries. Paths flow only into spawnSync\r\n * argv arrays (`git add -- <path>`), so a hostile filename stays inert.\r\n */\r\n/** Pure parser for `git status --porcelain -z` output. Unit-tested. */\r\nexport function parsePorcelainZ(out) {\r\n const tokens = String(out).split('\\0');\r\n const files = [];\r\n for (let i = 0; i < tokens.length; i += 1) {\r\n const tok = tokens[i];\r\n if (!tok) continue;\r\n const path = tok.slice(3); // strip the 2-char XY status + space\r\n if (path) files.push(path);\r\n // Rename (R) / copy (C) entries carry an extra NUL field (the source path).\r\n if (tok[0] === 'R' || tok[0] === 'C') i += 1;\r\n }\r\n return files;\r\n}\r\n\r\n/**\r\n * Agent scratch the runner must NEVER commit into a PR. Dispatched agents\r\n * sometimes draft a PR body / scratch notes to a file in the worktree (despite\r\n * the preamble telling them not to), which then leaked into the diff as\r\n * `.tmp-pr-body.md` / `tmp/pr-body.md` (observed live in #6515, 2026-06-12).\r\n * These names are runner/agent ephemera, never legitimate task output. Kept\r\n * deliberately NARROW \u2014 only dot-temp scratch and PR-body/description drafts \u2014\r\n * so it can't silently swallow a real file the task meant to produce.\r\n */\r\nconst SCRATCH_PATTERNS = [\r\n /(^|\\/)\\.tmp-/i, // .tmp-pr-body.md and other dot-temp scratch\r\n /(^|\\/)tmp\\/pr[-_]?(body|description)/i, // tmp/pr-body.md, tmp/pr_description...\r\n /(^|\\/)pr[-_]?(body|description)(\\.(md|txt))?$/i, // pr-body.md, PR_DESCRIPTION.txt\r\n];\r\n\r\n/** True if `path` is agent/runner scratch that must not land in a PR. */\r\nexport function isAgentScratch(path) {\r\n const p = String(path || '');\r\n return SCRATCH_PATTERNS.some((re) => re.test(p));\r\n}\r\n\r\nexport function listChangedFiles(cwd) {\r\n const out = run('git', ['-c', 'core.quotepath=false', 'status', '--porcelain', '-z'], cwd, {\r\n timeout: 60_000,\r\n raw: true,\r\n });\r\n return parsePorcelainZ(out);\r\n}\r\n\r\n/**\r\n * Files an agent COMMITTED ahead of `base` (default origin/main). Safety net:\r\n * if a dispatched agent commits its work to a branch (despite the preamble\r\n * telling it not to), the working tree is clean and `listChangedFiles` returns\r\n * nothing \u2014 without this the runner would discard real work as `no_changes`\r\n * (observed live 2026-06-12). Returns [] on any error (porcelain remains the\r\n * primary path).\r\n */\r\nexport function listCommittedFiles(cwd, base = 'origin/main') {\r\n try {\r\n run('git', ['fetch', 'origin', 'main'], cwd, { timeout: 60_000 });\r\n } catch {\r\n /* offline / no remote \u2014 fall through to the diff against whatever base resolves */\r\n }\r\n try {\r\n const out = run(\r\n 'git',\r\n ['-c', 'core.quotepath=false', 'diff', '--name-only', '-z', `${base}...HEAD`],\r\n cwd,\r\n { timeout: 60_000, raw: true },\r\n );\r\n return String(out)\r\n .split('\\0')\r\n .map((s) => s.trim())\r\n .filter(Boolean);\r\n } catch {\r\n return [];\r\n }\r\n}\r\n\r\nfunction compactTitle(s, max = 100) {\r\n return String(s || '').replace(/\\s+/g, ' ').trim().slice(0, max) || 'code-task';\r\n}\r\n\r\n/**\r\n * Commit the given files, push a fresh feature branch off origin/main, and open\r\n * a PR. Returns { prUrl, prNumber, branch }. NO auto-merge.\r\n */\r\nexport function openCodeTaskPr(\r\n worktreeDir,\r\n files,\r\n {\r\n title,\r\n body,\r\n branchPrefix = 'vo/code-task',\r\n botName = 'vo-code-runner',\r\n botEmail = 'vo-code-runner@algosuite.ai',\r\n maxFiles = 200,\r\n // Safety net: the agent already COMMITTED its work to a branch (despite the\r\n // preamble). Skip add+commit; just push the existing branch and open the PR.\r\n alreadyCommitted = false,\r\n } = {},\r\n) {\r\n if (!Array.isArray(files) || files.length === 0) {\r\n throw new Error('openCodeTaskPr: no files to commit');\r\n }\r\n // Defense-in-depth: never `git add` agent scratch even if a caller forgets to\r\n // filter it. The daemon also strips + logs scratch upstream; this guarantees a\r\n // drafted PR-body / tmp note can't ride into the diff via any code path.\r\n const cleaned = files.filter((f) => !isAgentScratch(f));\r\n if (!alreadyCommitted && cleaned.length === 0) {\r\n throw new Error('openCodeTaskPr: only scratch files, nothing to commit');\r\n }\r\n const toAdd = cleaned.slice(0, maxFiles);\r\n\r\n run('git', ['config', 'user.name', botName], worktreeDir);\r\n run('git', ['config', 'user.email', botEmail], worktreeDir);\r\n\r\n let branch = '';\r\n try {\r\n branch = run('git', ['branch', '--show-current'], worktreeDir, { timeout: 30_000 });\r\n } catch {\r\n // leave branch = '' \u2192 triggers fresh feature-branch creation below\r\n }\r\n\r\n if (alreadyCommitted) {\r\n // The agent's commits exist on HEAD. Move them onto a clean, never-main\r\n // branch (the agent may have committed onto a name we don't want, or onto\r\n // a detached HEAD) and push that \u2014 no add/commit.\r\n if (!branch || branch === 'main' || branch === 'HEAD') {\r\n const stamp = new Date().toISOString().replace(/[:.]/g, '-');\r\n branch = `${branchPrefix}-${stamp}`;\r\n run('git', ['checkout', '-b', branch], worktreeDir); // branch from current HEAD (keeps commits)\r\n }\r\n run('git', ['push', 'origin', branch], worktreeDir);\r\n } else {\r\n // CI/main-refresh can park the worktree on main/detached \u2014 never push that.\r\n if (!branch || branch === 'main' || branch === 'HEAD') {\r\n const stamp = new Date().toISOString().replace(/[:.]/g, '-');\r\n branch = `${branchPrefix}-${stamp}`;\r\n run('git', ['fetch', 'origin', 'main'], worktreeDir, { timeout: 60_000 });\r\n run('git', ['checkout', '-b', branch, 'origin/main'], worktreeDir);\r\n }\r\n\r\n for (const f of toAdd) {\r\n run('git', ['add', '--', f], worktreeDir, { timeout: 60_000 });\r\n }\r\n\r\n const commitMsg = compactTitle(title, 180);\r\n run('git', ['commit', '--no-verify', '-m', commitMsg], worktreeDir);\r\n run('git', ['push', 'origin', branch], worktreeDir);\r\n }\r\n\r\n // NOTE: NO `gh pr merge --auto`. The verify gate / operator review governs the\r\n // eventual merge of an agent-produced PR.\r\n const out = run(\r\n 'gh',\r\n [\r\n 'pr',\r\n 'create',\r\n '--base',\r\n 'main',\r\n '--head',\r\n branch,\r\n '--title',\r\n compactTitle(title),\r\n '--body',\r\n String(body || ''),\r\n ],\r\n worktreeDir,\r\n );\r\n const m = out.match(/https:\\/\\/github\\.com\\/[^/]+\\/[^/]+\\/pull\\/(\\d+)/);\r\n if (!m) throw new Error('gh pr create returned no parseable PR URL');\r\n return { prUrl: m[0], prNumber: Number(m[1]), branch, truncated: cleaned.length > maxFiles };\r\n}\r\n", "/**\r\n * dispatch-onboarding \u2014 the MANDATORY onboarding preamble prepended to EVERY\r\n * VO-dispatched agent's prompt (Code-from-Anywhere runner, successor spawns).\r\n *\r\n * Why this exists: a dispatched `claude -p` runs in a repo worktree, so the\r\n * harness auto-loads `CLAUDE.md` \u2014 but NOT the things CLAUDE.md only *references*\r\n * (AGENTS.md, the VO charter/operating-model/test-architect standards, the\r\n * evidence-grounded-consensus doctrine, ADR-001/002, the roadmap, operator\r\n * memory). A bare task prompt therefore briefs the agent only half-way. This\r\n * preamble is the single choke point that makes the full reading list + the\r\n * non-negotiable rules explicit and in-context for every dispatch, regardless\r\n * of what the dispatching UI sent.\r\n *\r\n * Keep it COMPLETE but tight \u2014 it is prepended to every task, so every line\r\n * costs tokens on every dispatch. List the reads; inline only the rules an\r\n * agent could violate before it finishes reading.\r\n */\r\n\r\n/** The authoritative mandatory-reads list (mirrors AGENTS.md \"spawned subagent\" contract). */\r\nexport const MANDATORY_READS = [\r\n 'CLAUDE.md (repo root \u2014 Claude-specific rules; auto-loaded, but READ it)',\r\n 'AGENTS.md (repo root \u2014 cross-vendor rules + \"Onboarding for a lane\"; NOT auto-loaded)',\r\n 'README.md (repo root \u2014 product context)',\r\n 'docs/current/virtual-office-agent-charter.md',\r\n 'docs/current/virtual-office-operating-model.md',\r\n 'docs/current/virtual-office-test-architect.md',\r\n 'docs/current/evidence-grounded-consensus-testing.md',\r\n 'docs/vo/ADR-001-verification-oracle-not-orchestrator-2026-05-29.md (VO verifies + signs; human approves merges; NO autonomous bot-merge / headless triggers)',\r\n 'docs/vo/vo-adr-002-two-plane-moat.md (fat secret server / thin dumb client)',\r\n 'docs/vo/vo-roadmap-2026-05-26.md (the live roadmap \u2014 read its Change log tail for current state)',\r\n 'the nearest scoped CLAUDE.md for any directory you edit',\r\n 'for AlgoTax work: docs/current/algotax-progressive-return-roadmap.md + docs/current/algotax-coverage-roadmap.md',\r\n 'docs/current/pr-live-stewardship-doctrine.md (own EVERY PR to LIVE-VERIFIED; never let the operator discover a red PR or a backed-up deploy)',\r\n];\r\n\r\n/** Non-negotiable rules inlined so they bind even before the agent finishes reading. */\r\nexport const NON_NEGOTIABLES = [\r\n 'MULTI-MODEL CONSENSUS VERIFICATION IS THE CORE of every Algosuite product \u2014 never ship single-model judgment as the product; route verifiable decisions through the consensus/verify path.',\r\n 'TEST HONESTY (enforced): a test passes ONLY when it proves the product returned the VERIFIED CORRECT answer. No broad catch-alls; INVALID_ARGUMENT / null / PERMISSION_DENIED / empty / \"no data\" / SKIP are NOT passes. Fake green is a blocking bug.',\r\n 'VERIFY BEFORE ACT, human approves the merge (ADR-001). Never arm an autonomous bot-merge loop; never add a headless/automatic agent trigger.',\r\n 'NEVER trigger a full / all-codebase functions deploy, and NEVER edit functions-shared/src without an explicit plan \u2014 a full functions deploy is ~24h and catastrophic (RED LINE).',\r\n 'Gen2 Cloud Functions ONLY (firebase-functions/v2/*). Gen1 is CI-blocked.',\r\n 'Work on your OWN branch in a worktree; never `git add -A` / `git add .` (add files by name); respect file-size caps (components \u2264300, functions/services/utils \u2264400).',\r\n 'A handoff or roadmap line is a CLAIM, not evidence \u2014 verify shipped state against `git show origin/main:<path>`, never the stale local main tree.',\r\n 'MANDATORY FOR EVERY VO PR (cloud-run/vo-*, packages/vo-mcp, packages/consensus-engine, packages/vo-ratchets, packages/vo-arch-defaults, scripts/virtual-office, vo-claude-plugin): record a dated Change-log entry IN THE SAME PR via EITHER appending to the \"\u00A7 10 Change log\" of docs/vo/vo-roadmap-2026-05-26.md OR (PREFERRED) creating docs/vo/roadmap-log/<YYYY-MM-DD>-<short-slug>.md (fragments avoid conflicts when PRs ship concurrently) and flip any status the work shipped. CI enforces this (check-vo-roadmap-discipline.mjs); bypass ONLY via \"VO-ROADMAP-ALLOW: <reason>\" in the PR body. The roadmap is the single source of truth \u2014 if you didn\\'t update it, you didn\\'t ship. Finish line = MERGED + DEPLOYED + LIVE-VERIFIED.',\r\n 'Every UI change ships against docs/current/ui-trust-standard.md and adds VO QA tester coverage; verify in a real browser, not selector-presence.',\r\n 'PR \u2192 LIVE is YOUR job end-to-end \u2014 the operator must NEVER be the one to discover a red PR or a backed-up deploy. Own every PR from branch \u2192 CI \u2192 merge \u2192 functions deploy \u2192 LIVE-VERIFIED. \"Done\" = the functions you changed are actually SERVING in prod in every region; prove it with `node scripts/ci/prove-pr-live.mjs --pr <N>` \u2014 a merge / green deploy checkmark / homepage 200 is NOT proof. If a function staled, re-deploy ONLY the affected functions (targeted), never a full deploy. If you hit a usage/rate limit, STOP cleanly with the PR obligation OPEN \u2014 the watchdog auto-resumes when it resets; do not abandon it. See docs/current/pr-live-stewardship-doctrine.md.',\r\n 'CONTEXT DEPTH IS NOT A REASON TO STOP. \"I\\'m deep in context / fresh context would be better / I\\'ll checkpoint\" is the SAME premature-stop failure as doing 20 minutes of work instead of 6 hours \u2014 there is no quality cliff before compaction and the harness carries work forward. Keep BUILDING until the task is genuinely DONE; delicate or fleet-governing work means be CAREFUL, not stop. The ONLY valid pauses are real blockers: an operator decision is required, a dependency is not merged, or a hard external wait.',\r\n];\r\n\r\n/**\r\n * Build the onboarding preamble. `repo` is the target repo (e.g.\r\n * \"Algosuite-ai/Nexus\") so the agent knows where it is. The returned string is\r\n * meant to be PREPENDED to the operator/UI task prompt with a clear separator.\r\n */\r\nexport function buildDispatchOnboarding({ repo = 'Algosuite-ai/Nexus' } = {}) {\r\n const reads = MANDATORY_READS.map((r, i) => ` ${i + 1}. ${r}`).join('\\n');\r\n const rules = NON_NEGOTIABLES.map((r) => ` - ${r}`).join('\\n');\r\n return [\r\n `You are a Virtual Office (VO) dispatched coding agent working in a fresh worktree of ${repo}.`,\r\n 'You were dispatched by the operator (greylor, a non-coder founder) to do the TASK at the end of this message.',\r\n 'Before writing ANY code, you MUST read the onboarding docs below \u2014 they are mandatory, not optional. Your worktree auto-loads CLAUDE.md, but the rest are NOT auto-loaded; open and read them.',\r\n '',\r\n 'MANDATORY READS (read these FIRST, in order):',\r\n reads,\r\n '',\r\n 'NON-NEGOTIABLE RULES (these bind you even before you finish reading):',\r\n rules,\r\n '',\r\n 'HOW THE RUNNER PUBLISHES YOUR WORK (critical \u2014 read carefully):',\r\n ' - Leave your changes as UNCOMMITTED edits in this worktree. The VO runner commits them, pushes a branch, and opens the PR FOR you \u2014 that is its job, not yours.',\r\n ' - Do NOT run git (no commit, no branch, no checkout) and do NOT run `gh` / open a PR yourself. You are sandboxed to file edits; git/gh commands will be denied, and committing your work moves it where the runner cannot see it (your change would be silently discarded).',\r\n ' - When the task is done, simply STOP. Your final message should summarize what you changed; the runner detects your edited files and creates the PR.',\r\n ' - If a git or `gh` command is DENIED, that is EXPECTED and CORRECT \u2014 it means the runner will handle publishing. Do NOT retry it, do NOT try a different git/gh invocation, and do NOT wait for an approval that will not come. STOP immediately with your edits uncommitted. (Agents that retried a denied `gh pr create` burned ~25 minutes of usage and their finished fix was lost.)',\r\n ' - Do NOT create scratch files \u2014 no drafted PR body, no notes/TODO/plan files, nothing under tmp/ or named pr-body*/pr-description*. The runner writes the PR body itself; the worktree should contain ONLY the real file changes the task requires. (Stray scratch files have leaked into PRs.)',\r\n '',\r\n 'Definition of done: the change is correct, tested to the standard above, type-checks + lints clean, and (for VO surfaces) updates the roadmap. Leave it as UNCOMMITTED edits and STOP \u2014 the runner opens the PR. If the task is ambiguous or would violate a rule, STOP and report rather than guessing.',\r\n '',\r\n '\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 YOUR TASK \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550',\r\n ].join('\\n');\r\n}\r\n\r\n/** Compose the full prompt for a dispatched agent: onboarding preamble + the task. */\r\nexport function composeDispatchPrompt(taskPrompt, opts = {}) {\r\n return `${buildDispatchOnboarding(opts)}\\n${String(taskPrompt ?? '').trim()}\\n`;\r\n}\r\n", "/**\r\n * session-spool-forwarder \u2014 the daemon half of \"VO sees ALL agents\".\r\n *\r\n * The vo-session-report hook spools every Claude Code session locally (no\r\n * secrets). The daemon \u2014 which holds the control-plane token \u2014 reads the spool\r\n * each poll and forwards it to the cloud session API so the Mission Control\r\n * Sessions panel shows EVERY active session, not just VO-dispatched ones.\r\n *\r\n * Identity: hooks don't know the operator/tenant UUIDs, so the daemon derives\r\n * deterministic synthetic UUIDs from a stable local seed (same sha256\u2192UUIDv5\r\n * shape the V3-ledger migration uses), keeping all of this machine's sessions\r\n * under one synthetic operator/tenant. The cloud session_id is derived from\r\n * the spool session_key, so create is idempotent across polls (report-state\r\n * after the first create).\r\n *\r\n * FAIL-OPEN: every network error is swallowed \u2014 forwarding telemetry must never\r\n * disrupt the runner's primary job (claiming + executing code tasks).\r\n */\r\nimport { homedir } from 'node:os';\r\nimport { join } from 'node:path';\r\nimport { readdir, readFile, unlink, writeFile } from 'node:fs/promises';\r\nimport { createHash } from 'node:crypto';\r\n\r\nconst SPOOL_DIR = join(homedir(), '.vo', 'session-spool');\r\n/**\r\n * Persistent map session_key \u2192 SERVER-assigned cloud session_id. Critical:\r\n * `POST /api/v1/session` MINTS a new session_id each call (the create input has\r\n * no session_id field) \u2014 so the forwarder must remember the id the server gave\r\n * it and report-state to THAT, or every poll would (a) 404 on report-state\r\n * (wrong id) and (b) create a duplicate session. Live-found 2026-06-12.\r\n */\r\nconst CLOUD_MAP_FILE = join(homedir(), '.vo', 'session-cloud-map.json');\r\n/** Drop spool files whose session ended or went silent longer than this. */\r\nconst STALE_MS = 60 * 60 * 1000; // 1h\r\n/** Treat a session as no-longer-active after this much silence (UI: stops listing). */\r\nconst ACTIVE_SILENCE_MS = 10 * 60 * 1000; // 10m\r\n\r\n/** Deterministic UUIDv5-shaped id from a seed (matches migrate-v3-ledger). */\r\nexport function deriveUuid(seed) {\r\n const h = createHash('sha256').update(seed).digest('hex');\r\n return (\r\n `${h.slice(0, 8)}-${h.slice(8, 12)}-5${h.slice(13, 16)}-` +\r\n `${((parseInt(h.slice(16, 18), 16) & 0x3f) | 0x80).toString(16)}${h.slice(18, 20)}-` +\r\n `${h.slice(20, 32)}`\r\n );\r\n}\r\n\r\n/** Map a spool record \u2192 the cloud session create/report shape. */\r\nexport function spoolToCloud(record, ids) {\r\n const ended = record.status === 'ended';\r\n const silentMs = Date.now() - Date.parse(record.last_seen_at || 0);\r\n const status = ended ? 'handed_off' : silentMs > ACTIVE_SILENCE_MS ? 'abandoned' : 'active';\r\n return {\r\n session_id: deriveUuid(`vo-session:${record.session_key}`),\r\n operator_id: ids.operator_id,\r\n tenant_id: ids.tenant_id,\r\n agent_type: record.agent_type === 'claude-code' ? 'claude-code' : 'other',\r\n current_goal: (record.current_goal || 'Interactive Claude Code session').slice(0, 2000),\r\n status,\r\n last_seen_at: record.last_seen_at,\r\n };\r\n}\r\n\r\n/** Read + parse every spool file (skips unreadable ones). */\r\nasync function readSpool(spoolDir = SPOOL_DIR) {\r\n let files = [];\r\n try {\r\n files = await readdir(spoolDir);\r\n } catch {\r\n return [];\r\n }\r\n const out = [];\r\n for (const f of files) {\r\n if (!f.endsWith('.json')) continue;\r\n try {\r\n const record = JSON.parse(await readFile(join(spoolDir, f), 'utf8'));\r\n // Defense-in-depth: a spool record MUST have a string session_key. This\r\n // skips any non-spool json that lands in the dir (e.g. a misplaced\r\n // cloud-map) so it's never forwarded as a bogus session.\r\n if (record && typeof record.session_key === 'string') {\r\n out.push({ full: join(spoolDir, f), record });\r\n }\r\n } catch {\r\n /* skip corrupt */\r\n }\r\n }\r\n return out;\r\n}\r\n\r\n/**\r\n * Forward all spooled sessions to the control-plane. `deps`:\r\n * { baseUrl, token, operatorSeed, fetchImpl?, now? }\r\n * Returns { forwarded, pruned } counts.\r\n */\r\nasync function readCloudMap(path) {\r\n try {\r\n return JSON.parse(await readFile(path, 'utf8'));\r\n } catch {\r\n return {};\r\n }\r\n}\r\n\r\nexport async function forwardSessionSpool(deps) {\r\n const fetchImpl = deps.fetchImpl ?? fetch;\r\n const now = deps.now ? deps.now() : Date.now();\r\n const mapPath = deps.cloudMapPath ?? CLOUD_MAP_FILE;\r\n const ids = {\r\n operator_id: deriveUuid(`vo-operator:${deps.operatorSeed}`),\r\n tenant_id: deriveUuid(`vo-tenant:${deps.operatorSeed}`),\r\n };\r\n const entries = await readSpool(deps.spoolDir);\r\n // session_key \u2192 SERVER cloud session_id, persisted across polls so we create\r\n // ONCE per session and report-state to the id the server actually assigned.\r\n const cloudMap = await readCloudMap(mapPath);\r\n let forwarded = 0;\r\n let pruned = 0;\r\n\r\n for (const { full, record } of entries) {\r\n const key = record.session_key;\r\n const lastSeen = Date.parse(record.last_seen_at || 0);\r\n const isPrune =\r\n (record.status === 'ended' && now - lastSeen > ACTIVE_SILENCE_MS) ||\r\n now - lastSeen > STALE_MS;\r\n\r\n const cloud = spoolToCloud(record, ids);\r\n try {\r\n // CREATE ONCE: the create endpoint MINTS a new session_id every call\r\n // (no client-supplied id), so the first forward creates the session and\r\n // remembers the server's id; later forwards reuse it. Without this each\r\n // poll would duplicate the session and report-state to a nonexistent id.\r\n let cloudSessionId = cloudMap[key];\r\n if (!cloudSessionId) {\r\n const res = await fetchImpl(`${deps.baseUrl}/api/v1/session`, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${deps.token}` },\r\n body: JSON.stringify({\r\n operator_id: cloud.operator_id,\r\n tenant_id: cloud.tenant_id,\r\n agent_type: cloud.agent_type,\r\n current_goal: cloud.current_goal,\r\n }),\r\n });\r\n const body = await res.json().catch(() => null);\r\n cloudSessionId = body?.session?.session_id ?? null;\r\n if (cloudSessionId) cloudMap[key] = cloudSessionId;\r\n }\r\n if (cloudSessionId) {\r\n await fetchImpl(`${deps.baseUrl}/api/v1/session/${cloudSessionId}/report-state`, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${deps.token}` },\r\n body: JSON.stringify({\r\n context_used_pct: 0,\r\n current_goal: cloud.current_goal,\r\n status: cloud.status,\r\n }),\r\n }).catch(() => {});\r\n forwarded++;\r\n }\r\n } catch {\r\n /* FAIL-OPEN: telemetry never disrupts the runner */\r\n }\r\n\r\n // Prune AFTER the final forward so an ended session reports 'handed_off'\r\n // once before we drop its spool + map entry.\r\n if (isPrune) {\r\n try {\r\n await unlink(full);\r\n pruned++;\r\n } catch {\r\n /* ignore */\r\n }\r\n delete cloudMap[key];\r\n }\r\n }\r\n\r\n try {\r\n await writeFile(mapPath, JSON.stringify(cloudMap), 'utf8');\r\n } catch {\r\n /* map persistence is best-effort */\r\n }\r\n return { forwarded, pruned };\r\n}\r\n", "/**\r\n * pr-watcher \u2014 the daemon-side ACTIVE watcher for dispatched-task PRs.\r\n *\r\n * Operator ask (2026-06-12): dispatched agents should \"put up watchers to\r\n * actively monitor PRs and fix any issues\" \u2014 like a human steward does. After\r\n * the runner opens a PR for a dispatched task, the daemon tracks it; each watch\r\n * cycle it checks the PR's CI and, on failure, auto-dispatches ONE fix attempt\r\n * (cap is per-PR, default 1). It NEVER auto-merges \u2014 the operator approves the\r\n * merge (ADR-001: human initiates, gate verifies).\r\n *\r\n * COST SAFETY (the operator runs on a Claude subscription and is usage-sensitive):\r\n * - Each fix is one more agent run \u2192 bounded by `maxFixAttempts` PER PR.\r\n * - Fix-PRs are tagged `[VO-CI-FIX]` and are NEVER themselves watched, so a\r\n * fix that also fails can't chain into an unbounded supersede loop.\r\n * - Kill switch: `VO_CODE_RUNNER_WATCH=0` disables the whole watcher.\r\n * - Throttled (default 60s); every action is logged.\r\n *\r\n * The PR-state read + fix-enqueue are injected so the decision logic is pure +\r\n * unit-tested without gh/network.\r\n */\r\nimport { homedir } from 'node:os';\r\nimport { join } from 'node:path';\r\nimport { readFile, writeFile, mkdir } from 'node:fs/promises';\r\nimport { spawnSync } from 'node:child_process';\r\n\r\n/** Marker prepended to an auto-dispatched CI-fix prompt \u2014 see daemon (skips watching fix-PRs). */\r\nexport const CI_FIX_MARKER = '[VO-CI-FIX]';\r\n\r\n/** Read a dispatched PR's state + CI rollup via gh (throws on non-zero exit). */\r\nexport function ghViewPr(prNumber, repo) {\r\n const r = spawnSync(\r\n 'gh',\r\n ['pr', 'view', String(prNumber), '-R', repo, '--json', 'state,statusCheckRollup,headRefName'],\r\n { encoding: 'utf8', timeout: 30_000 },\r\n );\r\n if (r.status !== 0) throw new Error((r.stderr || 'gh pr view failed').slice(-200));\r\n return JSON.parse(r.stdout || '{}');\r\n}\r\n\r\nconst DEFAULT_STATE_FILE = join(homedir(), '.vo', 'dispatched-prs.json');\r\n\r\nconst FAIL_CONCLUSIONS = new Set([\r\n 'FAILURE', 'TIMED_OUT', 'CANCELLED', 'ACTION_REQUIRED', 'ERROR', 'STARTUP_FAILURE', 'STALE',\r\n]);\r\nconst PENDING_STATES = new Set([\r\n 'IN_PROGRESS', 'QUEUED', 'PENDING', 'WAITING', 'REQUESTED', 'EXPECTED',\r\n]);\r\n\r\n/** Drop a capped+failing PR untouched this long, so the state file stays bounded. */\r\nconst STALE_MS = 24 * 60 * 60 * 1000;\r\n/** Stop retrying a PR's fix dispatch after this many consecutive enqueue errors. */\r\nconst MAX_ENQUEUE_ERRORS = 3;\r\n\r\n/**\r\n * Pure: reduce a `gh pr view --json state,statusCheckRollup,headRefName` object\r\n * to `{ state, ci: 'passing'|'failing'|'pending', failedChecks, branch }`.\r\n */\r\nexport function parsePrCiStatus(view) {\r\n const state = (view && typeof view.state === 'string' ? view.state : 'UNKNOWN').toUpperCase();\r\n const rollup = view && Array.isArray(view.statusCheckRollup) ? view.statusCheckRollup : [];\r\n const failedChecks = [];\r\n let pending = false;\r\n for (const c of rollup) {\r\n const name = c.name || c.context || 'check';\r\n const conclusion = String(c.conclusion || '').toUpperCase();\r\n if (conclusion) {\r\n // Check-run with a conclusion (terminal): classify by it. SUCCESS /\r\n // SKIPPED / NEUTRAL \u21D2 passing (no-op).\r\n if (FAIL_CONCLUSIONS.has(conclusion)) failedChecks.push(name);\r\n } else if (c.status) {\r\n // Check-run WITHOUT a conclusion \u2014 IN_PROGRESS/QUEUED, or COMPLETED-with-no-\r\n // conclusion (unknown). Treat all as pending (safe: don't call it passing).\r\n pending = true;\r\n } else {\r\n // Legacy commit-STATUS context: classify by `state` (it has no conclusion).\r\n // Previously this mis-classified a SUCCESS status-context as pending.\r\n const st = String(c.state || '').toUpperCase();\r\n if (st === 'FAILURE' || st === 'ERROR') failedChecks.push(name);\r\n else if (st !== 'SUCCESS') pending = true; // PENDING / EXPECTED / unknown\r\n }\r\n }\r\n const ci = failedChecks.length > 0 ? 'failing' : pending ? 'pending' : 'passing';\r\n return { state, ci, failedChecks, branch: (view && view.headRefName) || null };\r\n}\r\n\r\n/**\r\n * Pure: given a PR's parsed status + how many fixes we've already dispatched for\r\n * it, decide what to do. 'untrack' (no longer OPEN), 'fix' (failing + under cap),\r\n * or 'wait' (passing/pending, or over cap \u2014 leave for the operator).\r\n */\r\nexport function decideWatchAction(pr, fixAttempts, maxFixAttempts) {\r\n if (pr.state !== 'OPEN') return 'untrack';\r\n if (pr.ci === 'failing' && (fixAttempts || 0) < maxFixAttempts) return 'fix';\r\n return 'wait';\r\n}\r\n\r\n/** The fix-task prompt. Tagged CI_FIX_MARKER so the daemon never re-watches the fix-PR. */\r\nexport function buildCiFixPrompt({ prNumber, repo, branch, failedChecks }) {\r\n return [\r\n `${CI_FIX_MARKER} A VO-dispatched pull request has FAILING CI and needs a fix.`,\r\n '',\r\n `Repo: ${repo}`,\r\n `PR: #${prNumber} (head branch: ${branch || 'unknown'})`,\r\n `Failing checks: ${(failedChecks && failedChecks.length ? failedChecks.join(', ') : 'unknown')}`,\r\n '',\r\n 'Diagnose the failure from the failing check NAMES + the PR diff (you cannot run gh).',\r\n 'Fix it. Follow the PR Freshness / safe-rebuild protocol: open a FRESH fix on a new',\r\n `branch off current main that SUPERSEDES PR #${prNumber} (note \"Supersedes #${prNumber}\"`,\r\n 'in your summary). Leave UNCOMMITTED edits and STOP \u2014 the runner opens the PR. A denied',\r\n 'git/gh is EXPECTED; do NOT retry it.',\r\n ].join('\\n');\r\n}\r\n\r\nasync function readState(stateFile) {\r\n try {\r\n const parsed = JSON.parse(await readFile(stateFile, 'utf8'));\r\n return parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? parsed : {};\r\n } catch {\r\n return {};\r\n }\r\n}\r\n\r\nasync function writeState(stateFile, state) {\r\n try {\r\n await mkdir(join(stateFile, '..'), { recursive: true });\r\n await writeFile(stateFile, JSON.stringify(state, null, 2), 'utf8');\r\n } catch {\r\n /* best-effort persistence \u2014 never break the daemon loop */\r\n }\r\n}\r\n\r\n/** Add a freshly-opened dispatched PR to the watch list (persisted). */\r\nexport async function trackDispatchedPr({ prNumber, repo, branch, taskId }, { stateFile = DEFAULT_STATE_FILE, now = () => Date.now() } = {}) {\r\n if (!prNumber || !repo) return;\r\n const state = await readState(stateFile);\r\n state[String(prNumber)] = {\r\n repo,\r\n branch: branch || null,\r\n taskId: taskId || null,\r\n fixAttempts: 0,\r\n trackedAt: now(),\r\n };\r\n await writeState(stateFile, state);\r\n}\r\n\r\n/**\r\n * Run one watch cycle over every tracked PR. Deps:\r\n * viewPr(prNumber, repo) \u2192 the gh-json object (or throws)\r\n * enqueueFix({prNumber, repo, branch, failedChecks}) \u2192 dispatch one fix\r\n * log(msg), now(), maxFixAttempts, stateFile\r\n * Returns { checked, fixed, untracked }.\r\n */\r\nexport async function runWatchCycle({ viewPr, enqueueFix, log = () => {}, now = () => Date.now(), maxFixAttempts = 1, stateFile = DEFAULT_STATE_FILE }) {\r\n const state = await readState(stateFile);\r\n const prNumbers = Object.keys(state);\r\n let checked = 0;\r\n let fixed = 0;\r\n let untracked = 0;\r\n\r\n for (const prNumber of prNumbers) {\r\n const entry = state[prNumber];\r\n let view;\r\n try {\r\n view = await viewPr(prNumber, entry.repo);\r\n } catch (err) {\r\n log(`watch: pr #${prNumber} view failed: ${err.message}`);\r\n continue;\r\n }\r\n checked += 1;\r\n const pr = parsePrCiStatus(view);\r\n entry.lastCi = pr.ci; // remembered for the stale-prune below\r\n const action = decideWatchAction(pr, entry.fixAttempts, maxFixAttempts);\r\n if (action === 'untrack') {\r\n delete state[prNumber];\r\n untracked += 1;\r\n log(`watch: pr #${prNumber} is ${pr.state} \u2014 untracked`);\r\n } else if (action === 'fix') {\r\n entry.fixAttempts = (entry.fixAttempts || 0) + 1;\r\n entry.lastCheckedAt = now();\r\n try {\r\n await enqueueFix({ prNumber: Number(prNumber), repo: entry.repo, branch: pr.branch || entry.branch, failedChecks: pr.failedChecks });\r\n fixed += 1;\r\n log(`watch: pr #${prNumber} CI failing (${pr.failedChecks.join(', ') || 'unknown'}) \u2014 dispatched fix ${entry.fixAttempts}/${maxFixAttempts}`);\r\n } catch (err) {\r\n entry.enqueueErrors = (entry.enqueueErrors || 0) + 1;\r\n if (entry.enqueueErrors >= MAX_ENQUEUE_ERRORS) {\r\n // Persistent enqueue failure \u2014 STOP retrying (keep the attempt counted\r\n // as spent) so it can't re-fire every cycle forever.\r\n log(`watch: pr #${prNumber} fix enqueue failed ${entry.enqueueErrors}x \u2014 giving up: ${err.message}`);\r\n } else {\r\n // Transient \u2014 roll back so the next cycle retries.\r\n entry.fixAttempts = Math.max(0, (entry.fixAttempts || 1) - 1);\r\n log(`watch: pr #${prNumber} fix enqueue failed (${entry.enqueueErrors}/${MAX_ENQUEUE_ERRORS}): ${err.message}`);\r\n }\r\n }\r\n } else {\r\n entry.lastCheckedAt = now();\r\n }\r\n }\r\n\r\n // Stale-prune: a PR that exhausted its fix cap, is still failing, and was first\r\n // tracked >24h ago is the operator's now \u2014 drop it so the state file can't grow\r\n // unbounded on PRs that are abandoned without ever merging or closing.\r\n for (const [n, e] of Object.entries(state)) {\r\n const cappedFailing = e.lastCi === 'failing' && (e.fixAttempts || 0) >= maxFixAttempts;\r\n if (cappedFailing && e.trackedAt && now() - e.trackedAt > STALE_MS) {\r\n delete state[n];\r\n untracked += 1;\r\n log(`watch: pr #${n} capped + failing + tracked >24h ago \u2014 pruned from watch state`);\r\n }\r\n }\r\n\r\n await writeState(stateFile, state);\r\n return { checked, fixed, untracked };\r\n}\r\n\r\n/**\r\n * A configured watch-cycle runner: binds runWatchCycle to a control-plane client\r\n * (for the fix enqueue) + gh (for PR reads). Returns a zero-arg async function\r\n * the daemon calls each throttled tick. Keeps the daemon thin.\r\n */\r\nexport function makeWatchRunner({ client, viewPr = ghViewPr, log, maxFixAttempts }) {\r\n return () =>\r\n runWatchCycle({\r\n viewPr,\r\n enqueueFix: ({ prNumber, repo, branch, failedChecks }) =>\r\n client.enqueueCodeTask({ repo, prompt: buildCiFixPrompt({ prNumber, repo, branch, failedChecks }) }),\r\n log,\r\n maxFixAttempts,\r\n });\r\n}\r\n", "/**\r\n * control-server \u2014 a tiny LOCALHOST-only HTTP control surface for the runner\r\n * daemon, so the operator can see status + Stop the daemon FROM the in-product\r\n * /virtualoffice page (Phase 8.4) instead of the desktop \"VO Runner\" HTA.\r\n *\r\n * How a remote HTTPS page reaches a local daemon:\r\n * - Browsers treat http://127.0.0.1 / http://localhost as a SECURE context, so\r\n * an https://algosuite.ai page may fetch it without mixed-content blocking.\r\n * - CORS: we echo an allow-listed Origin (the app origin + any localhost).\r\n * - Chrome Private-Network-Access: a public page \u2192 private/localhost resource\r\n * triggers a preflight that needs `Access-Control-Allow-Private-Network: true`.\r\n *\r\n * Bound to 127.0.0.1 ONLY (never 0.0.0.0) so nothing off-machine can reach it.\r\n * Endpoints: GET /status, POST /stop. Start-when-stopped is intentionally NOT\r\n * here \u2014 a fully-stopped daemon has no server to call; the page surfaces the\r\n * one-click \"VO Runner\" launcher for that.\r\n */\r\nimport { createServer } from 'node:http';\r\n\r\nconst LOCALHOST_ORIGIN_RE = /^https?:\\/\\/(localhost|127\\.0\\.0\\.1)(:\\d+)?$/;\r\n\r\n/** Pick the Origin to echo: the request's origin if allow-listed, else the app origin. */\r\nexport function resolveCorsOrigin(reqOrigin, allowedOrigin) {\r\n if (typeof reqOrigin === 'string' && (reqOrigin === allowedOrigin || LOCALHOST_ORIGIN_RE.test(reqOrigin))) {\r\n return reqOrigin;\r\n }\r\n return allowedOrigin;\r\n}\r\n\r\n/**\r\n * True when a state-changing request may proceed: no Origin (non-browser /\r\n * same-origin) OR an allow-listed Origin (the app or localhost). A cross-site\r\n * Origin returns false so /stop rejects it. CSRF guard for the control server.\r\n */\r\nexport function isControlOriginAllowed(reqOrigin, allowedOrigin) {\r\n return !reqOrigin || resolveCorsOrigin(reqOrigin, allowedOrigin) === reqOrigin;\r\n}\r\n\r\n/**\r\n * Build the request handler. `deps`: { getStatus(), requestStop(reason), allowedOrigin }.\r\n * Pure-ish + injectable so it unit-tests without a real socket.\r\n */\r\nexport function buildControlHandler({ getStatus, requestStop, allowedOrigin }) {\r\n return (req, res) => {\r\n res.setHeader('Access-Control-Allow-Origin', resolveCorsOrigin(req.headers.origin, allowedOrigin));\r\n res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');\r\n // `x-vo-control` is REQUIRED on /stop. A custom header forces a CORS preflight\r\n // even for a POST, and the preflight's Origin scoping (above) blocks a\r\n // non-app origin \u2014 so a cross-site fetch can't reach /stop.\r\n res.setHeader('Access-Control-Allow-Headers', 'content-type, x-vo-control');\r\n res.setHeader('Access-Control-Allow-Private-Network', 'true');\r\n res.setHeader('Vary', 'Origin');\r\n res.setHeader('Cache-Control', 'no-store');\r\n\r\n if (req.method === 'OPTIONS') {\r\n res.statusCode = 204;\r\n res.end();\r\n return;\r\n }\r\n\r\n const path = String(req.url || '').split('?')[0];\r\n res.setHeader('content-type', 'application/json');\r\n\r\n if (req.method === 'GET' && path === '/status') {\r\n let status;\r\n try {\r\n status = getStatus();\r\n } catch {\r\n status = {};\r\n }\r\n res.statusCode = 200;\r\n res.end(JSON.stringify({ ok: true, ...status }));\r\n return;\r\n }\r\n\r\n if (req.method === 'POST' && path === '/stop') {\r\n // CSRF DEFENSE: CORS does NOT stop a cross-site POST from being SENT +\r\n // EXECUTED \u2014 it only hides the response. So gate /stop server-side:\r\n // (1) a cross-site request carries the attacker's Origin \u2192 reject it;\r\n // (2) require the custom x-vo-control header, which a simple cross-site\r\n // form POST cannot set and which forces a preflight for fetch (then\r\n // blocked by the Origin scoping above).\r\n if (!isControlOriginAllowed(req.headers.origin, allowedOrigin) || !req.headers['x-vo-control']) {\r\n res.statusCode = 403;\r\n res.end(JSON.stringify({ ok: false, error: 'forbidden' }));\r\n return;\r\n }\r\n try {\r\n requestStop('web-control');\r\n } catch {\r\n /* ignore \u2014 stop is best-effort */\r\n }\r\n res.statusCode = 200;\r\n res.end(JSON.stringify({ ok: true, stopping: true }));\r\n return;\r\n }\r\n\r\n res.statusCode = 404;\r\n res.end(JSON.stringify({ ok: false, error: 'not_found' }));\r\n };\r\n}\r\n\r\n/**\r\n * Start the control server on 127.0.0.1:port. Returns the http.Server (call\r\n * .close() on shutdown). Never throws synchronously; logs listen/errors.\r\n */\r\nexport function startControlServer({ port, getStatus, requestStop, allowedOrigin, log = () => {} }) {\r\n const server = createServer(buildControlHandler({ getStatus, requestStop, allowedOrigin }));\r\n server.on('error', (e) => log(`control server error: ${e.message} (in-product runner control disabled)`));\r\n // 127.0.0.1 ONLY \u2014 never expose the control surface beyond this machine.\r\n server.listen(port, '127.0.0.1', () => log(`control server on http://127.0.0.1:${port} (allow ${allowedOrigin})`));\r\n server.unref?.(); // don't keep the process alive on its own\r\n return server;\r\n}\r\n\r\n/**\r\n * Start the in-product control surface for a running daemon, building the live\r\n * `getStatus` snapshot from the daemon's own callbacks. Returns the server (or\r\n * null when disabled). Keeps the daemon's main loop thin.\r\n */\r\nexport function startDaemonControl({ cfg, requestStop, getActiveCount, isRunning, startedAt, log = () => {} }) {\r\n if (!cfg.controlEnabled) return null;\r\n return startControlServer({\r\n port: cfg.controlPort,\r\n allowedOrigin: cfg.appOrigin,\r\n requestStop,\r\n getStatus: () => ({\r\n running: isRunning(),\r\n pid: process.pid,\r\n runnerId: cfg.runnerId,\r\n servedRepos: cfg.servedRepos,\r\n watchEnabled: cfg.watchEnabled,\r\n activeTasks: getActiveCount(),\r\n startedAt: new Date(startedAt).toISOString(),\r\n uptimeSec: Math.round((Date.now() - startedAt) / 1000),\r\n }),\r\n log,\r\n });\r\n}\r\n", "/**\r\n * effort-mode-config \u2014 map dispatch-effort levels to agent run parameters.\r\n *\r\n * Each level bundles: model tier, permission mode, max turns, and optional\r\n * thinking + multi-agent prompt directives the daemon prepends. The operator\r\n * sets a per-system default; the daemon applies it to every dispatched agent\r\n * (unless a per-task override exists).\r\n */\r\n\r\nexport const EFFORT_MODE_CONFIG = {\r\n fast: {\r\n tier: 'cheap',\r\n permissionMode: 'acceptEdits',\r\n maxTurns: 20,\r\n thinkingDirective: '',\r\n multiAgentInstruction: '',\r\n },\r\n standard: {\r\n tier: 'mid',\r\n permissionMode: 'acceptEdits',\r\n maxTurns: 40,\r\n thinkingDirective: '',\r\n multiAgentInstruction: '',\r\n },\r\n deep: {\r\n tier: 'best',\r\n permissionMode: 'acceptEdits',\r\n maxTurns: 60,\r\n thinkingDirective:\r\n 'Think step-by-step. Verify assumptions against source code. Check edge cases.',\r\n multiAgentInstruction: '',\r\n },\r\n ultra: {\r\n tier: 'best',\r\n permissionMode: 'acceptEdits',\r\n maxTurns: 80,\r\n thinkingDirective:\r\n 'Think step-by-step. Exhaustively verify every assumption against source code and documentation. Adversarially review your own work.',\r\n multiAgentInstruction:\r\n 'If this task needs multiple phases (research, build, verify), propose a plan first.',\r\n },\r\n ultracode: {\r\n tier: 'best',\r\n permissionMode: 'default',\r\n maxTurns: 120,\r\n thinkingDirective:\r\n 'Think step-by-step. Exhaustively verify every assumption against source code and documentation. Build worked examples to validate correctness. Adversarially review your own work.',\r\n multiAgentInstruction:\r\n 'Decompose this work into parallel research, build, and verification streams; use workflow orchestration where it helps.',\r\n },\r\n};\r\n\r\nconst DEFAULT_MODE = 'standard';\r\n\r\n/**\r\n * Resolve an effort mode string to its config. Unknown/missing \u2192 'standard'.\r\n */\r\nexport function resolveEffortMode(mode) {\r\n const normalized = String(mode || '').trim().toLowerCase();\r\n return EFFORT_MODE_CONFIG[normalized] || EFFORT_MODE_CONFIG[DEFAULT_MODE];\r\n}\r\n\r\n/**\r\n * Compose a prompt with the level's thinking + multi-agent directives prepended.\r\n * When a directive is absent/empty, omit its section.\r\n */\r\nexport function composeEffortPrompt(basePrompt, effortConfig) {\r\n const parts = [];\r\n if (effortConfig.thinkingDirective) {\r\n parts.push(`## Thinking directive\\n${effortConfig.thinkingDirective}\\n`);\r\n }\r\n if (effortConfig.multiAgentInstruction) {\r\n parts.push(`## Multi-agent instruction\\n${effortConfig.multiAgentInstruction}\\n`);\r\n }\r\n parts.push(String(basePrompt || '').trim());\r\n return parts.join('\\n');\r\n}\r\n", "#!/usr/bin/env node\r\n// Runtime model-family resolver for VO model panels.\r\n\r\nimport fs from 'node:fs';\r\nimport path from 'node:path';\r\nimport { fileURLToPath } from 'node:url';\r\n\r\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\r\nconst ROOT = path.resolve(__dirname, '..', '..');\r\nconst DEFAULT_CACHE_DIR = path.join(ROOT, '.virtual-office-cache', 'model-registry');\r\nconst DEFAULT_CACHE_FILE = path.join(DEFAULT_CACHE_DIR, 'catalog.json');\r\nconst DEFAULT_TTL_MS = 60 * 60 * 1000;\r\nconst ANTHROPIC_API_VERSION = '2023-06-01';\r\n\r\nconst FAMILY_DEFINITIONS = {\r\n 'anthropic-flagship': {\r\n provider: 'anthropic',\r\n include: [/^claude-opus/i],\r\n // Reject `-fast` SKUs: they cost more and route to the same underlying\r\n // weights, and at least one (`claude-opus-4-7-fast`) gets silently\r\n // substituted server-side when callers ask for it (observed 2026-05-14:\r\n // 24 model-fallback events per consensus run, collapsing diversity).\r\n exclude: [/haiku/i, /-fast(?:[-.]|$)/i],\r\n fallbacks: [\r\n 'claude-opus-4-8[1m]',\r\n 'claude-opus-4-8',\r\n 'claude-opus-4-7',\r\n 'claude-opus-4-6',\r\n 'claude-opus-4-5-20251101',\r\n 'claude-sonnet-4-6',\r\n ],\r\n },\r\n 'anthropic-balanced': {\r\n provider: 'anthropic',\r\n include: [/^claude-sonnet/i],\r\n exclude: [/haiku/i, /-fast(?:[-.]|$)/i],\r\n fallbacks: ['claude-sonnet-4-6', 'claude-sonnet-4-5-20250929', 'claude-sonnet-4-20250514'],\r\n },\r\n 'openai-flagship': {\r\n provider: 'openai',\r\n include: [/^gpt-\\d+(?:[.-]\\d+)?$/i, /^gpt-\\d+(?:[.-]\\d+)?-pro$/i],\r\n // -fast SKUs cost more and silently downgrade server-side; want standard.\r\n exclude: [/mini|nano|chat|codex/i, /-fast(?:[-.]|$)/i],\r\n fallbacks: ['gpt-5.4', 'gpt-5.2', 'gpt-5.3-codex'],\r\n },\r\n 'openai-coding': {\r\n provider: 'openai',\r\n include: [/codex/i],\r\n exclude: [/mini|nano/i, /-fast(?:[-.]|$)/i],\r\n fallbacks: ['gpt-5.3-codex', 'gpt-5.2-codex', 'gpt-5.4'],\r\n },\r\n 'google-pro': {\r\n provider: 'google',\r\n include: [/^gemini-.*pro/i],\r\n exclude: [/vision|embedding|customtools/i, /-fast(?:[-.]|$)/i],\r\n fallbacks: ['gemini-2.5-pro', 'gemini-3.1-pro-preview'],\r\n },\r\n 'google-flash': {\r\n provider: 'google',\r\n // 'google-flash' is the explicit fast/low-latency family \u2014 DON'T exclude\r\n // -fast here; that's the whole point of this family. Other families\r\n // exclude -fast to avoid the silent server-side substitution problem.\r\n include: [/^gemini-.*flash/i],\r\n exclude: [/vision|embedding/i],\r\n fallbacks: ['gemini-2.5-flash', 'gemini-3-flash-preview'],\r\n },\r\n};\r\n\r\n// MODEL_FALLBACKS must be WITHIN-FAMILY ONLY.\r\n//\r\n// Each entry below maps a primary model to fallback candidates from the SAME\r\n// provider family. Cross-provider substitution (Claude -> GPT, GPT -> Gemini,\r\n// etc.) is forbidden here because consensus diversity is a load-bearing\r\n// property of the VO consensus-fixer: when caller asks for `gpt-5.4` and we\r\n// silently return `claude-sonnet-4-6`, the \"two GPT models + one Claude\"\r\n// panel collapses into \"three Claude models\" and we lose the cross-provider\r\n// disagreement signal the consensus algorithm needs.\r\n//\r\n// History:\r\n// * 2026-05-15: incident \u2014 cross-provider substitution collapsed consensus\r\n// diversity in production. BACKEND-1 (PR #4782) fixed the *callable*\r\n// path (functions-core/src/consensus-shared/code-provider-fallback.ts)\r\n// but missed this VO-side table.\r\n// * 2026-05-17: verification probe (gh run 25997832014) confirmed the leak\r\n// survived BACKEND-1 deploy. Logs showed `gpt-5.4 -> claude-sonnet-4-6`\r\n// and `gpt-5.5-pro -> claude-sonnet-4-6` substitutions originating in\r\n// this file. Probe of `getModelFallbackChain('gpt-5.4')` returned\r\n// `['gpt-5.4','claude-sonnet-4-6','gemini-2.5-pro']` \u2014 the smoking gun.\r\n// * This PR: rewrote the table to be within-family only. Anything that\r\n// wants cross-provider behavior must do it explicitly at the call site,\r\n// not by accident through this fallback chain.\r\n//\r\n// Within-family canonical chains (see FAMILY_DEFINITIONS above for source):\r\n// anthropic-flagship (Opus): claude-opus-4-7 / 4-6 / 4-5-20251101\r\n// anthropic-balanced (Sonnet): claude-sonnet-4-6 / 4-5 / 4-20250514\r\n// openai-flagship: gpt-5.4 / 5.2 / 5.3-codex\r\n// google-pro: gemini-2.5-pro / 3.1-pro-preview\r\n// google-flash: gemini-2.5-flash / 3-flash-preview\r\nconst MODEL_FALLBACKS = {\r\n // Claude flagship (Opus) \u2014 only other Opus + Sonnet inside Anthropic.\r\n 'claude-opus-4-7': ['claude-opus-4-6', 'claude-opus-4-5-20251101', 'claude-sonnet-4-6'],\r\n 'claude-opus-4-6': ['claude-opus-4-7', 'claude-opus-4-5-20251101', 'claude-sonnet-4-6'],\r\n 'claude-opus-4-5-20251101': ['claude-opus-4-7', 'claude-opus-4-6', 'claude-sonnet-4-6'],\r\n // Claude balanced (Sonnet) \u2014 fall back within Sonnet line, then Opus.\r\n 'claude-sonnet-4-6': ['claude-sonnet-4-5-20250929', 'claude-sonnet-4-20250514', 'claude-opus-4-7'],\r\n // GPT flagship \u2014 only other GPT variants.\r\n 'gpt-5.4': ['gpt-5.2', 'gpt-5.3-codex'],\r\n // Gemini \u2014 pro and flash are separate families; fall back inside each.\r\n 'gemini-2.5-pro': ['gemini-3.1-pro-preview'],\r\n 'gemini-2.5-flash': ['gemini-3-flash-preview'],\r\n};\r\n\r\nlet memoryCache = null;\r\n\r\nfunction uniqueModels(models = []) {\r\n return [...new Set(models.map((model) => String(model || '').trim()).filter(Boolean))];\r\n}\r\n\r\nfunction normalizeProvider(value = '') {\r\n const lower = String(value || '').trim().toLowerCase();\r\n if (lower.includes('anthropic')) return 'anthropic';\r\n if (lower.includes('openai')) return 'openai';\r\n if (lower.includes('google') || lower.includes('gemini')) return 'google';\r\n return lower;\r\n}\r\n\r\nfunction stripProviderPrefix(id = '') {\r\n const raw = String(id || '').trim();\r\n if (!raw.includes('/')) return raw.replace(/^models\\//, '');\r\n return raw.split('/').slice(1).join('/').replace(/^models\\//, '');\r\n}\r\n\r\nfunction canonicalizeRegistryModelId(id = '', provider = '') {\r\n let normalized = stripProviderPrefix(id).trim();\r\n const normalizedProvider = normalizeProvider(provider) || inferProviderFromId(normalized);\r\n if (normalizedProvider === 'anthropic') {\r\n normalized = normalized.replace(/^(claude-(?:opus|sonnet|haiku)-\\d+)\\.(\\d+)(.*)$/i, '$1-$2$3');\r\n }\r\n if (normalizedProvider === 'google') {\r\n normalized = normalized.replace(/-customtools$/i, '');\r\n }\r\n return normalized;\r\n}\r\n\r\nfunction inferProviderFromId(rawId = '', explicitProvider = '') {\r\n const provider = normalizeProvider(explicitProvider);\r\n if (provider) return provider;\r\n const id = String(rawId || '').toLowerCase();\r\n if (id.startsWith('anthropic/') || id.includes('claude')) return 'anthropic';\r\n if (id.startsWith('openai/') || /^gpt-|^o\\d/.test(stripProviderPrefix(id))) return 'openai';\r\n if (id.startsWith('google/') || id.includes('gemini')) return 'google';\r\n return 'unknown';\r\n}\r\n\r\nfunction normalizeCatalogModel(model = {}) {\r\n const rawId = String(model.id || model.name || model.modelId || '').trim();\r\n const provider = inferProviderFromId(rawId, model.provider || model.owned_by || model.owner || model.developer);\r\n const id = canonicalizeRegistryModelId(rawId, provider);\r\n if (!id) return null;\r\n return {\r\n id,\r\n rawId,\r\n name: String(model.display_name || model.displayName || model.name || id).replace(/^models\\//, ''),\r\n provider,\r\n source: model.source || 'unknown',\r\n createdAt: model.created_at || model.createdAt || model.created || '',\r\n };\r\n}\r\n\r\nfunction parseVersionScore(id = '') {\r\n const lower = String(id || '').toLowerCase();\r\n const numbers = [...lower.matchAll(/\\d+/g)].map((match) => Number(match[0])).filter(Number.isFinite);\r\n let score = 0;\r\n for (let i = 0; i < numbers.length; i++) score += numbers[i] / Math.pow(1000, i);\r\n if (/opus|pro|flagship/.test(lower)) score += 10;\r\n if (/sonnet/.test(lower)) score += 5;\r\n if (/preview|latest/.test(lower)) score += 0.25;\r\n // [1m] / (1m) variants get a bonus so best-at-the-time picks them first.\r\n if (/\\[1m\\]|\\(1m\\)/i.test(lower)) score += 1;\r\n if (/mini|nano|haiku|lite/.test(lower)) score -= 20;\r\n return score;\r\n}\r\n\r\nfunction familyMatches(model, family) {\r\n const def = FAMILY_DEFINITIONS[family];\r\n if (!def) return false;\r\n const id = String(model?.id || '').trim();\r\n if (!id || normalizeProvider(model.provider) !== def.provider) return false;\r\n if (def.exclude?.some((pattern) => pattern.test(id))) return false;\r\n return def.include?.some((pattern) => pattern.test(id)) ?? false;\r\n}\r\n\r\nfunction inferFallbacksForModel(primaryModel = '') {\r\n const model = String(primaryModel || '').trim();\r\n const family = Object.keys(FAMILY_DEFINITIONS).find((key) => {\r\n const def = FAMILY_DEFINITIONS[key];\r\n return familyMatches({ id: model, provider: def.provider }, key);\r\n });\r\n return family ? FAMILY_DEFINITIONS[family].fallbacks : [];\r\n}\r\n\r\nfunction selectBestFamilyModel(models = [], family) {\r\n const matches = models.filter((model) => familyMatches(model, family));\r\n matches.sort((left, right) => {\r\n const scoreDelta = parseVersionScore(right.id) - parseVersionScore(left.id);\r\n if (scoreDelta !== 0) return scoreDelta;\r\n return String(right.createdAt || '').localeCompare(String(left.createdAt || ''));\r\n });\r\n return matches[0]?.id || '';\r\n}\r\n\r\nasync function fetchJson(fetchImpl, url, options = {}) {\r\n const res = await fetchImpl(url, options);\r\n if (!res?.ok) return null;\r\n return await res.json().catch(() => null);\r\n}\r\n\r\nasync function fetchOpenRouterModels(fetchImpl) {\r\n const data = await fetchJson(fetchImpl, 'https://openrouter.ai/api/v1/models');\r\n return (data?.data || []).map((model) => normalizeCatalogModel({ ...model, source: 'openrouter' })).filter(Boolean);\r\n}\r\n\r\nasync function fetchAnthropicModels(fetchImpl, env = process.env) {\r\n const apiKey = env.ANTHROPIC_API_KEY;\r\n if (!apiKey) return [];\r\n const data = await fetchJson(fetchImpl, 'https://api.anthropic.com/v1/models?limit=1000', {\r\n headers: { 'x-api-key': apiKey, 'anthropic-version': ANTHROPIC_API_VERSION },\r\n });\r\n return (data?.data || []).map((model) => normalizeCatalogModel({ ...model, provider: 'anthropic', source: 'anthropic' })).filter(Boolean);\r\n}\r\n\r\nasync function fetchOpenAIModels(fetchImpl, env = process.env) {\r\n const apiKey = env.OPENAI_API_KEY;\r\n if (!apiKey) return [];\r\n const data = await fetchJson(fetchImpl, 'https://api.openai.com/v1/models', {\r\n headers: { Authorization: `Bearer ${apiKey}` },\r\n });\r\n return (data?.data || []).map((model) => normalizeCatalogModel({ ...model, provider: 'openai', source: 'openai' })).filter(Boolean);\r\n}\r\n\r\nasync function fetchGoogleModels(fetchImpl, env = process.env) {\r\n const apiKey = env.GOOGLE_AI_API_KEY || env.GEMINI_API_KEY || env.GOOGLE_API_KEY;\r\n if (!apiKey) return [];\r\n const data = await fetchJson(fetchImpl, `https://generativelanguage.googleapis.com/v1beta/models?key=${encodeURIComponent(apiKey)}`);\r\n return (data?.models || []).map((model) => normalizeCatalogModel({ ...model, provider: 'google', source: 'google' })).filter(Boolean);\r\n}\r\n\r\nfunction readCache(cacheFile = DEFAULT_CACHE_FILE, nowMs = Date.now(), ttlMs = DEFAULT_TTL_MS) {\r\n if (!fs.existsSync(cacheFile)) return null;\r\n try {\r\n const parsed = JSON.parse(fs.readFileSync(cacheFile, 'utf-8'));\r\n if (nowMs - Number(parsed.checkedAtMs || 0) > ttlMs) return null;\r\n if (!Array.isArray(parsed.models)) return null;\r\n return parsed;\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\nfunction writeCache(cacheFile = DEFAULT_CACHE_FILE, payload) {\r\n fs.mkdirSync(path.dirname(cacheFile), { recursive: true });\r\n fs.writeFileSync(cacheFile, JSON.stringify(payload, null, 2));\r\n}\r\n\r\nasync function fetchRegistryCatalog({\r\n fetchImpl = fetch,\r\n env = process.env,\r\n cacheFile = DEFAULT_CACHE_FILE,\r\n nowMs = Date.now(),\r\n} = {}) {\r\n const sources = await Promise.allSettled([\r\n fetchOpenRouterModels(fetchImpl),\r\n fetchAnthropicModels(fetchImpl, env),\r\n fetchOpenAIModels(fetchImpl, env),\r\n fetchGoogleModels(fetchImpl, env),\r\n ]);\r\n const models = uniqueModels(\r\n sources\r\n .flatMap((result) => (result.status === 'fulfilled' ? result.value : []))\r\n .map((model) => JSON.stringify(model)),\r\n ).map((raw) => JSON.parse(raw));\r\n const payload = { checkedAt: new Date(nowMs).toISOString(), checkedAtMs: nowMs, models };\r\n if (models.length > 0) writeCache(cacheFile, payload);\r\n return payload;\r\n}\r\n\r\nexport async function getModelRegistryCatalog({\r\n fetchImpl = fetch,\r\n env = process.env,\r\n cacheFile = DEFAULT_CACHE_FILE,\r\n ttlMs = Number(env.VO_MODEL_REGISTRY_TTL_MS || DEFAULT_TTL_MS),\r\n nowMs = Date.now(),\r\n forceRefresh = false,\r\n} = {}) {\r\n if (!forceRefresh && memoryCache && nowMs - memoryCache.checkedAtMs <= ttlMs) return memoryCache;\r\n if (!forceRefresh) {\r\n const cached = readCache(cacheFile, nowMs, ttlMs);\r\n if (cached) {\r\n memoryCache = cached;\r\n return cached;\r\n }\r\n }\r\n if (env.VO_MODEL_REGISTRY_OFFLINE === '1') return { checkedAt: '', checkedAtMs: nowMs, models: [] };\r\n try {\r\n memoryCache = await fetchRegistryCatalog({ fetchImpl, env, cacheFile, nowMs });\r\n return memoryCache;\r\n } catch {\r\n const cached = readCache(cacheFile, nowMs, Number.MAX_SAFE_INTEGER);\r\n return cached || { checkedAt: '', checkedAtMs: nowMs, models: [] };\r\n }\r\n}\r\n\r\nexport async function resolveModelFamily(family, options = {}) {\r\n const def = FAMILY_DEFINITIONS[family];\r\n if (!def) return String(family || '').trim();\r\n const catalog = await getModelRegistryCatalog(options);\r\n const resolved = selectBestFamilyModel(catalog.models || [], family);\r\n return resolved || def.fallbacks[0];\r\n}\r\n\r\nexport async function resolveModelConfig(config = {}, options = {}) {\r\n if (config.family) return resolveModelFamily(config.family, options);\r\n return String(config.model || '').trim();\r\n}\r\n\r\nexport function getModelFallbackChain(primaryModel) {\r\n const normalized = String(primaryModel || '').trim();\r\n if (!normalized) return [];\r\n return uniqueModels([normalized, ...(MODEL_FALLBACKS[normalized] || inferFallbacksForModel(normalized))]);\r\n}\r\n\r\nexport const __test = {\r\n FAMILY_DEFINITIONS,\r\n MODEL_FALLBACKS,\r\n normalizeCatalogModel,\r\n canonicalizeRegistryModelId,\r\n parseVersionScore,\r\n selectBestFamilyModel,\r\n familyMatches,\r\n stripProviderPrefix,\r\n};\r\n", "/**\r\n * model-router \u2014 task-appropriate model selection for VO code-runner.\r\n *\r\n * Classifies tasks as cheap/mid/best based on the prompt content and resolves\r\n * each tier to a specific model via the live model registry. The daemon runs\r\n * every dispatched task on the right-sized model: Sonnet for chores, Opus for\r\n * bugs, Opus-1M for features/roadmap \u2014 auto-classified or manually overridden.\r\n */\r\nimport { resolveModelFamily } from '../model-registry.mjs';\r\n\r\n/** Tier vocabulary \u2014 'auto' means classify from the prompt. */\r\nexport const TIER_VALUES = ['auto', 'cheap', 'mid', 'best'];\r\n\r\n/**\r\n * Classify a task prompt into a tier: cheap | mid | best.\r\n *\r\n * - **cheap** (Sonnet): chores, lint, formatting, typo fixes, missing imports,\r\n * dependency updates, maintenance, runner/daemon tweaks.\r\n * - **best** (Opus-1M): roadmap generation, new features, major refactors,\r\n * strategic changes, OR long prompts (>1500 chars).\r\n * - **mid** (Opus): everything else \u2014 small bugs, tests, docs, typical PRs.\r\n */\r\nexport function classifyTier(prompt) {\r\n const text = String(prompt || '').trim();\r\n if (!text) return 'mid';\r\n\r\n const lower = text.toLowerCase();\r\n\r\n // Cheap: routine maintenance, chores, trivial fixes.\r\n if (\r\n /lint|format|typo|missing import|update deps|chore|maintenance|runner|daemon/.test(\r\n lower,\r\n )\r\n ) {\r\n return 'cheap';\r\n }\r\n\r\n // Best: roadmap generation, new features, major work, OR long prompts.\r\n if (\r\n /generate roadmap|new feature|implement .* feature|major refactor|strategic/.test(\r\n lower,\r\n ) ||\r\n text.length > 1500\r\n ) {\r\n return 'best';\r\n }\r\n\r\n // Default: mid tier for typical bugs and small PRs.\r\n return 'mid';\r\n}\r\n\r\n/**\r\n * Resolve a tier to a specific model ID via the model registry.\r\n *\r\n * - **cheap** \u2192 anthropic-balanced (Sonnet), fallback claude-sonnet-4-6\r\n * - **mid** \u2192 anthropic-flagship (Opus), fallback claude-opus-4-7\r\n * - **best** \u2192 anthropic-flagship preferring [1m] variants, fallback claude-opus-4-8\r\n *\r\n * The injected `resolveModelFamily` is used for testability; defaults to the\r\n * real import. Returns a model ID string (never null).\r\n */\r\nexport async function resolveModelForTier(\r\n tier,\r\n { resolveModelFamily: resolver = resolveModelFamily } = {},\r\n) {\r\n const t = String(tier || 'mid').trim();\r\n\r\n if (t === 'cheap') {\r\n const resolved = await resolver('anthropic-balanced');\r\n return resolved || 'claude-sonnet-4-6';\r\n }\r\n if (t === 'best') {\r\n // Best: flagship Opus, preferring [1m] variants. The model-registry [1m]\r\n // scoring change should bubble up the 1M variant when present.\r\n const resolved = await resolver('anthropic-flagship');\r\n return resolved || 'claude-opus-4-8';\r\n }\r\n // Default mid: flagship Opus (standard context).\r\n const resolved = await resolver('anthropic-flagship');\r\n return resolved || 'claude-opus-4-7';\r\n}\r\n\r\n/**\r\n * Resolve a CodeTask's tier\u2192model for the daemon. Classifies when tier='auto'\r\n * or null, then resolves via the live registry. Returns { tier, model }.\r\n */\r\nexport async function resolveTaskModel(task) {\r\n const tier = (task.tier && task.tier !== 'auto') ? task.tier : classifyTier(task.prompt);\r\n const model = await resolveModelForTier(tier);\r\n return { tier, model };\r\n}\r\n", "// apply-effort-mode \u2014 resolve a dispatched task's run parameters under the\r\n// operator's Fast\u2192Ultracode effort level. Keeps the daemon lean + the precedence\r\n// rules unit-testable.\r\n//\r\n// Precedence (per-task overrides win over the level's defaults):\r\n// - model tier: task.tier (DispatchBar) \u2192 else the level's tier\r\n// - permission mode: VO_CODE_RUNNER_PERMISSION_MODE env \u2192 else the level's mode\r\n// - max turns: task.max_turns \u2192 else the level's maxTurns\r\n// The level also contributes thinking + multi-agent directives, prepended to the\r\n// already-composed dispatch prompt.\r\nimport { resolveEffortMode, composeEffortPrompt } from './effort-mode-config.mjs';\r\nimport { resolveTaskModel } from './model-router.mjs';\r\n\r\n/**\r\n * @param {object} a\r\n * @param {{ getDispatchMode: () => Promise<string> }} a.client\r\n * @param {object} a.task the code-task record\r\n * @param {object} a.env process env (for the permission-mode override)\r\n * @param {string} a.basePrompt the dispatch prompt (onboarding preamble + task)\r\n * @param {Function} [a.resolveModel] injectable for tests; defaults to the router\r\n * @returns {Promise<{ dispatchMode: string, tier: string, model: string,\r\n * permissionMode: string, maxTurns: number, prompt: string }>}\r\n */\r\nexport async function resolveEffortDispatch({ client, task, env, basePrompt, resolveModel = resolveTaskModel }) {\r\n // Best-effort: any read error falls back to 'standard' (today's behavior).\r\n const dispatchMode = await client.getDispatchMode().catch(() => 'standard');\r\n const effortConfig = resolveEffortMode(dispatchMode);\r\n const { tier, model } = await resolveModel({ ...task, tier: task.tier ?? effortConfig.tier });\r\n return {\r\n dispatchMode,\r\n tier,\r\n model,\r\n permissionMode: env.VO_CODE_RUNNER_PERMISSION_MODE || effortConfig.permissionMode,\r\n maxTurns: typeof task.max_turns === 'number' ? task.max_turns : effortConfig.maxTurns,\r\n prompt: composeEffortPrompt(basePrompt, effortConfig),\r\n };\r\n}\r\n", "/**\r\n * claim-scoping-log \u2014 describe a runner's claim-scoping posture as startup log\r\n * lines so an operator can SEE whether their bring-your-own-runner isolation is\r\n * actually in effect.\r\n *\r\n * The claim filters (VO_CODE_RUNNER_REPOS / VO_CODE_RUNNER_OPERATOR_IDS) treat an\r\n * unset OR empty value as \"no scoping on that axis\" (legacy, backward-compatible).\r\n * That is convenient but dangerous silently: an operator who sets only repos \u2014\r\n * or fat-fingers an all-whitespace value \u2014 gets LESS isolation than they think,\r\n * and on a shared repo their machine could claim (and bill) another operator's\r\n * task. This helper surfaces every posture explicitly, with a WARNING whenever an\r\n * axis the operator appears to have tried to configure is actually OFF.\r\n *\r\n * Pure + side-effect-free (returns strings; the daemon does the logging) so it is\r\n * unit-testable without spawning the daemon.\r\n */\r\n\r\n/**\r\n * True when an env var was actually supplied a value. A non-empty string counts\r\n * even if it is all whitespace \u2014 that is exactly the \"looks configured but parses\r\n * to nothing\" case we want to warn about. An undefined/empty string is \"unset\".\r\n */\r\nfunction envProvided(raw) {\r\n return typeof raw === 'string' && raw.length > 0;\r\n}\r\n\r\n/**\r\n * @param {{ servedRepos?: string[], servedOperators?: string[] }} cfg\r\n * Parsed (trimmed, blank-free) repo + operator allow-lists.\r\n * @param {Record<string, string|undefined>} [env]\r\n * Raw environment \u2014 used only to tell \"unset\" apart from \"set but empty\".\r\n * @returns {string[]} startup log lines (warnings are prefixed `WARNING: `).\r\n */\r\nexport function describeClaimScoping(cfg = {}, env = {}) {\r\n const repos = cfg.servedRepos ?? [];\r\n const operators = cfg.servedOperators ?? [];\r\n const repoScoped = repos.length > 0;\r\n const opScoped = operators.length > 0;\r\n const reposEnvSet = envProvided(env.VO_CODE_RUNNER_REPOS);\r\n const opsEnvSet = envProvided(env.VO_CODE_RUNNER_OPERATOR_IDS);\r\n\r\n const lines = [];\r\n if (repoScoped) lines.push(`claim-scoped to repos: ${repos.join(', ')}`);\r\n if (opScoped) lines.push(`claim-scoped to operators: ${operators.join(', ')}`);\r\n\r\n // Set-but-empty: the operator tried to configure an axis but it parsed to\r\n // nothing, so it is silently OFF. Only meaningful when the env was non-blank.\r\n if (reposEnvSet && !repoScoped) {\r\n lines.push(\r\n 'WARNING: VO_CODE_RUNNER_REPOS is set but has no valid entries \u2014 repo scoping is OFF (claims any repo).',\r\n );\r\n }\r\n if (opsEnvSet && !opScoped) {\r\n lines.push(\r\n 'WARNING: VO_CODE_RUNNER_OPERATOR_IDS is set but has no valid entries \u2014 operator scoping is OFF (claims any operator).',\r\n );\r\n }\r\n\r\n // Partial scoping: one axis is constrained, the other is wide open.\r\n if (repoScoped && !opScoped) {\r\n lines.push(\r\n \"WARNING: operator scoping is OFF \u2014 this runner may claim ANY operator's tasks on the served repos. \" +\r\n 'Set VO_CODE_RUNNER_OPERATOR_IDS to bind it to your operator (bring-your-own-runner).',\r\n );\r\n }\r\n if (opScoped && !repoScoped) {\r\n lines.push(\r\n \"WARNING: repo scoping is OFF \u2014 this runner may claim the served operators' tasks on ANY repo. \" +\r\n 'Set VO_CODE_RUNNER_REPOS to constrain it.',\r\n );\r\n }\r\n\r\n // Fully unscoped \u2014 claims anything.\r\n if (!repoScoped && !opScoped) {\r\n lines.push(\r\n 'WARNING: no claim scoping \u2014 this daemon claims ANY pending task. ' +\r\n 'Set VO_CODE_RUNNER_REPOS and/or VO_CODE_RUNNER_OPERATOR_IDS to scope claims to this machine.',\r\n );\r\n }\r\n\r\n return lines;\r\n}\r\n", "#!/usr/bin/env node\r\n/**\r\n * `vo-mcp runner` \u2014 the bring-your-own (BYO) agent runner daemon entry.\r\n *\r\n * Reads the scoped `vo_credential` stored by `vo-mcp login` (OS keychain / 0600\r\n * file), injects it as the control-plane bearer, defaults the control-plane URL\r\n * to production, and starts the bundled code-runner daemon. The daemon polls the\r\n * control-plane, claims THIS operator's own tasks (the control-plane forces the\r\n * claim scope to the authenticated operator), runs a headless agent in a fresh\r\n * worktree of the operator's repo clone, and opens a PR.\r\n *\r\n * Authored as `.mjs` (not `.ts`) on purpose: it statically imports the daemon\r\n * from the repo's script tree (`scripts/virtual-office/code-runner-daemon.mjs`),\r\n * which is outside this package's tsconfig rootDir. tsc only compiles `src/**\\/*.ts`\r\n * (see tsconfig `include`), so it ignores this file; esbuild (scripts/bundle.mjs)\r\n * inlines the daemon + its code-runner modules into `dist/runner-cli.js`, swapping\r\n * the 3 heavy daemon couplings (validation-and-worktree, spend-cap-guard,\r\n * orchestrator-firestore/auth) for the lightweight `src/runner/*` replacements.\r\n *\r\n * Usage:\r\n * vo-mcp runner # poll forever\r\n * vo-mcp runner --once # claim + run one task, then exit\r\n *\r\n * Env (all optional):\r\n * VO_CONTROL_PLANE_ADMIN_TOKEN explicit bearer (wins over the stored credential)\r\n * VO_CONTROL_PLANE_URL control-plane base URL (default: production)\r\n * VO_CODE_RUNNER_REPO path to your repo clone (default: cwd)\r\n * VO_CODE_RUNNER_OPERATOR_IDS operator id(s) this runner serves (your own)\r\n * VO_CODE_RUNNER_REPOS owner/name repo(s) this runner builds\r\n */\r\nimport { readStoredCredential } from './cloud/credential-store.js';\r\nimport { main } from '../../../scripts/virtual-office/code-runner-daemon.mjs';\r\n\r\n/** Production control-plane (override with VO_CONTROL_PLANE_URL for local dev). */\r\nconst DEFAULT_CONTROL_PLANE_URL = 'https://vo-control-plane-bzjphrajaq-uc.a.run.app';\r\n\r\nfunction resolveToken() {\r\n if (process.env.VO_CONTROL_PLANE_ADMIN_TOKEN) {\r\n return process.env.VO_CONTROL_PLANE_ADMIN_TOKEN;\r\n }\r\n const cred = readStoredCredential();\r\n return cred && cred.vo_credential ? cred.vo_credential : undefined;\r\n}\r\n\r\nconst token = resolveToken();\r\nif (!token) {\r\n console.error('[vo-mcp runner] No credential found. Run `vo-mcp login` first.');\r\n console.error(' (or set VO_CONTROL_PLANE_ADMIN_TOKEN to a control-plane bearer)');\r\n process.exit(1);\r\n}\r\n\r\nconst env = {\r\n ...process.env,\r\n VO_CONTROL_PLANE_ADMIN_TOKEN: token,\r\n VO_CONTROL_PLANE_URL: process.env.VO_CONTROL_PLANE_URL || DEFAULT_CONTROL_PLANE_URL,\r\n VO_CODE_RUNNER_REPO: process.env.VO_CODE_RUNNER_REPO || process.cwd(),\r\n};\r\n\r\nconst once = process.argv.includes('--once');\r\n\r\nmain({ env, once }).catch((err) => {\r\n console.error('[vo-mcp runner] fatal:', err);\r\n process.exit(1);\r\n});\r\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["env", "fileURLToPath", "env", "getFirebaseAuth", "path", "spawnSync", "env", "mkdirSync", "homedir", "join", "dirname", "join", "homedir", "mkdirSync", "dirname", "run", "spawnSync", "path", "homedir", "join", "path", "homedir", "join", "readFile", "writeFile", "spawnSync", "STALE_MS", "readFile", "join", "writeFile", "log", "path", "log", "fs", "path", "env", "fs", "path", "cached", "resolved", "env", "env", "env", "run", "once", "fileURLToPath"]
|
|
7
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@algosuite/vo-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0-beta.1",
|
|
4
4
|
"description": "Virtual Office MCP server — open protocol surface for the VO consensus / ratchet tool family. Stdio transport, cross-vendor MCP client compatible (Claude Code, Claude Desktop, Cursor, Continue).",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|