@algosuite/vo-mcp 0.2.0-beta.27 → 0.2.0-beta.29

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.
@@ -3001,6 +3001,62 @@ var init_windows_claude_launch = __esm({
3001
3001
  }
3002
3002
  });
3003
3003
 
3004
+ // ../../scripts/virtual-office/code-runner/claude-credential-choice.mjs
3005
+ function isTruthyFlag(v) {
3006
+ const s = String(v ?? "").trim().toLowerCase();
3007
+ return s === "1" || s === "true" || s === "yes" || s === "on";
3008
+ }
3009
+ function wantsLogin(env2) {
3010
+ return isTruthyFlag(env2[CLAUDE_PREFER_LOGIN_ENV]) || isTruthyFlag(env2[PREFER_LOGIN_ENV]);
3011
+ }
3012
+ function wantsKey(env2) {
3013
+ return isTruthyFlag(env2[CLAUDE_PREFER_KEY_ENV]) || isTruthyFlag(env2[PREFER_KEY_ENV]);
3014
+ }
3015
+ function classifyClaudeCredential(baseEnv = {}, { getKey, probeLogin } = {}) {
3016
+ const preferKey = wantsKey(baseEnv);
3017
+ if (!preferKey && wantsLogin(baseEnv)) {
3018
+ return { source: CLAUDE_CREDENTIAL_SOURCE.PREFER_LOGIN, key: null };
3019
+ }
3020
+ if (baseEnv.ANTHROPIC_API_KEY) {
3021
+ return { source: CLAUDE_CREDENTIAL_SOURCE.ENV_KEY, key: null };
3022
+ }
3023
+ const key = getKey();
3024
+ if (!key) {
3025
+ return { source: CLAUDE_CREDENTIAL_SOURCE.NO_KEY, key: null };
3026
+ }
3027
+ if (preferKey) {
3028
+ return { source: CLAUDE_CREDENTIAL_SOURCE.KEYCHAIN_PREFER_KEY, key };
3029
+ }
3030
+ if (probeLogin() === true) {
3031
+ return { source: CLAUDE_CREDENTIAL_SOURCE.SUBSCRIPTION_WINS, key: null };
3032
+ }
3033
+ return { source: CLAUDE_CREDENTIAL_SOURCE.KEYCHAIN, key };
3034
+ }
3035
+ var PREFER_LOGIN_ENV, CLAUDE_PREFER_LOGIN_ENV, PREFER_KEY_ENV, CLAUDE_PREFER_KEY_ENV, CLAUDE_CREDENTIAL_SOURCE;
3036
+ var init_claude_credential_choice = __esm({
3037
+ "../../scripts/virtual-office/code-runner/claude-credential-choice.mjs"() {
3038
+ "use strict";
3039
+ PREFER_LOGIN_ENV = "VO_RUNNER_PREFER_LOGIN";
3040
+ CLAUDE_PREFER_LOGIN_ENV = "VO_RUNNER_CLAUDE_PREFER_LOGIN";
3041
+ PREFER_KEY_ENV = "VO_RUNNER_PREFER_KEY";
3042
+ CLAUDE_PREFER_KEY_ENV = "VO_RUNNER_CLAUDE_PREFER_KEY";
3043
+ CLAUDE_CREDENTIAL_SOURCE = Object.freeze({
3044
+ /** PREFER_LOGIN set (and not overridden): any API key is ignored. */
3045
+ PREFER_LOGIN: "prefer_login",
3046
+ /** An explicit ANTHROPIC_API_KEY in the environment — the manual override. */
3047
+ ENV_KEY: "env_key",
3048
+ /** No key anywhere; the spawn falls through to the login session. */
3049
+ NO_KEY: "no_key",
3050
+ /** A stored key, used because the operator explicitly opted out of tier 1. */
3051
+ KEYCHAIN_PREFER_KEY: "keychain_prefer_key",
3052
+ /** A stored key exists but a proven live subscription outranks it. */
3053
+ SUBSCRIPTION_WINS: "subscription_wins",
3054
+ /** A stored key, used because no live subscription was proven. */
3055
+ KEYCHAIN: "keychain"
3056
+ });
3057
+ }
3058
+ });
3059
+
3004
3060
  // ../../scripts/virtual-office/code-runner/anthropic-key-store.mjs
3005
3061
  import { createRequire as createRequire2 } from "node:module";
3006
3062
  import { spawnSync as spawnSync2 } from "node:child_process";
@@ -3022,44 +3078,22 @@ function getAnthropicKey({ EntryCtor = defaultEntryCtor() } = {}) {
3022
3078
  return null;
3023
3079
  }
3024
3080
  }
3025
- function isTruthyFlag(v) {
3026
- const s = String(v ?? "").trim().toLowerCase();
3027
- return s === "1" || s === "true" || s === "yes" || s === "on";
3028
- }
3029
- function wantsLogin(env2) {
3030
- return isTruthyFlag(env2[CLAUDE_PREFER_LOGIN_ENV]) || isTruthyFlag(env2[PREFER_LOGIN_ENV]);
3031
- }
3032
- function wantsKey(env2) {
3033
- return isTruthyFlag(env2[CLAUDE_PREFER_KEY_ENV]) || isTruthyFlag(env2[PREFER_KEY_ENV]);
3034
- }
3035
3081
  function withAnthropicKey(baseEnv = {}, { getKey = getAnthropicKey, probeLogin = probeClaudeLoginState } = {}) {
3036
- if (wantsLogin(baseEnv)) {
3037
- const next = { ...baseEnv };
3082
+ const { source, key } = classifyClaudeCredential(baseEnv, { getKey, probeLogin });
3083
+ const next = { ...baseEnv };
3084
+ if (source === CLAUDE_CREDENTIAL_SOURCE.PREFER_LOGIN) {
3038
3085
  delete next.ANTHROPIC_API_KEY;
3039
3086
  return next;
3040
3087
  }
3041
- if (baseEnv.ANTHROPIC_API_KEY) return { ...baseEnv };
3042
- const key = getKey();
3043
- if (!key) return { ...baseEnv };
3044
- if (!wantsKey(baseEnv) && probeLogin() === true) return { ...baseEnv };
3045
- return { ...baseEnv, ANTHROPIC_API_KEY: key };
3088
+ if (key !== null) next.ANTHROPIC_API_KEY = key;
3089
+ return next;
3046
3090
  }
3047
3091
  function claudeCostBasis(env2 = process.env) {
3048
3092
  return String(env2.ANTHROPIC_API_KEY || "").trim() ? "vendor_billed" : "subscription_api_equivalent";
3049
3093
  }
3050
3094
  function describeAnthropicAuthSource(baseEnv = {}, { getKey = getAnthropicKey, probeLogin = probeClaudeLoginState } = {}) {
3051
- if (wantsLogin(baseEnv)) {
3052
- return "claude auth login (VO_RUNNER_PREFER_LOGIN set \u2014 any API key ignored)";
3053
- }
3054
- if (baseEnv.ANTHROPIC_API_KEY) return "ANTHROPIC_API_KEY from environment";
3055
- if (!getKey()) return "claude auth login session (no API key set)";
3056
- if (wantsKey(baseEnv)) {
3057
- return "ANTHROPIC_API_KEY from OS keychain (VO_RUNNER_PREFER_KEY set \u2014 subscription ignored)";
3058
- }
3059
- if (probeLogin() === true) {
3060
- return "claude auth login session (subscription beats the stored keychain key)";
3061
- }
3062
- return "ANTHROPIC_API_KEY from OS keychain";
3095
+ const { source } = classifyClaudeCredential(baseEnv, { getKey, probeLogin });
3096
+ return AUTH_SOURCE_DESCRIPTION[source];
3063
3097
  }
3064
3098
  function augmentAuthError(summary) {
3065
3099
  const s = String(summary ?? "");
@@ -3068,32 +3102,38 @@ function augmentAuthError(summary) {
3068
3102
  \u21B3 Anthropic auth failed on the runner. The \`claude\` CLI is a SEPARATE install/login from the Claude Desktop app and the Claude Code IDE extension \u2014 signing into those does NOT authenticate it. Fix: run \`claude auth login\` (Claude subscription) on the runner machine, or clear any stale ANTHROPIC_API_KEY (env / OS keychain / .env.local) and set VO_RUNNER_PREFER_LOGIN=1 \u2014 then restart the runner. Verify with \`claude -p "say hi"\`.`;
3069
3103
  }
3070
3104
  function probeClaudeLoginState({
3071
- spawn: spawn6 = spawnSync2,
3105
+ spawn: spawn5 = spawnSync2,
3072
3106
  buildWindowsLaunch = buildWindowsClaudeLaunch,
3073
3107
  platform = process.platform
3074
3108
  } = {}) {
3075
3109
  try {
3076
3110
  const launch = platform === "win32" ? buildWindowsLaunch({ bin: "claude", args: ["auth", "status"] }) : { bin: "claude", args: ["auth", "status"], spawnOptions: { windowsHide: true } };
3077
- const st = spawn6(launch.bin, launch.args, { ...launch.spawnOptions, timeout: 5e3, encoding: "utf8" });
3111
+ const st = spawn5(launch.bin, launch.args, { ...launch.spawnOptions, timeout: 5e3, encoding: "utf8" });
3078
3112
  const parsed = JSON.parse(String(st.stdout || "").trim() || "{}");
3079
3113
  return typeof parsed.loggedIn === "boolean" ? parsed.loggedIn : null;
3080
3114
  } catch {
3081
3115
  return null;
3082
3116
  }
3083
3117
  }
3084
- var require2, KEY_SERVICE, KEY_ACCOUNT, _entryCtor, _loadTried, PREFER_LOGIN_ENV, CLAUDE_PREFER_LOGIN_ENV, PREFER_KEY_ENV, CLAUDE_PREFER_KEY_ENV, AUTH_ERROR_RE;
3118
+ var require2, KEY_SERVICE, KEY_ACCOUNT, _entryCtor, _loadTried, AUTH_SOURCE_DESCRIPTION, AUTH_ERROR_RE;
3085
3119
  var init_anthropic_key_store = __esm({
3086
3120
  "../../scripts/virtual-office/code-runner/anthropic-key-store.mjs"() {
3087
3121
  "use strict";
3088
3122
  init_windows_claude_launch();
3123
+ init_claude_credential_choice();
3124
+ init_claude_credential_choice();
3089
3125
  require2 = createRequire2(import.meta.url);
3090
3126
  KEY_SERVICE = "algosuite-vo";
3091
3127
  KEY_ACCOUNT = "anthropic-api-key";
3092
3128
  _loadTried = false;
3093
- PREFER_LOGIN_ENV = "VO_RUNNER_PREFER_LOGIN";
3094
- CLAUDE_PREFER_LOGIN_ENV = "VO_RUNNER_CLAUDE_PREFER_LOGIN";
3095
- PREFER_KEY_ENV = "VO_RUNNER_PREFER_KEY";
3096
- CLAUDE_PREFER_KEY_ENV = "VO_RUNNER_CLAUDE_PREFER_KEY";
3129
+ AUTH_SOURCE_DESCRIPTION = Object.freeze({
3130
+ [CLAUDE_CREDENTIAL_SOURCE.PREFER_LOGIN]: "claude auth login (VO_RUNNER_PREFER_LOGIN set \u2014 any API key ignored)",
3131
+ [CLAUDE_CREDENTIAL_SOURCE.ENV_KEY]: "ANTHROPIC_API_KEY from environment",
3132
+ [CLAUDE_CREDENTIAL_SOURCE.NO_KEY]: "claude auth login session (no API key set)",
3133
+ [CLAUDE_CREDENTIAL_SOURCE.KEYCHAIN_PREFER_KEY]: "ANTHROPIC_API_KEY from OS keychain (VO_RUNNER_PREFER_KEY set \u2014 subscription ignored)",
3134
+ [CLAUDE_CREDENTIAL_SOURCE.SUBSCRIPTION_WINS]: "claude auth login session (subscription beats the stored keychain key)",
3135
+ [CLAUDE_CREDENTIAL_SOURCE.KEYCHAIN]: "ANTHROPIC_API_KEY from OS keychain"
3136
+ });
3097
3137
  AUTH_ERROR_RE = /\b401\b|invalid[^.]{0,24}(authentication|credential)|authentication_error|unauthorized|not[ _-]?authenticated/i;
3098
3138
  }
3099
3139
  });
@@ -3327,11 +3367,11 @@ import { spawnSync as spawnSync4 } from "node:child_process";
3327
3367
  function terminateAgentProcessTree({
3328
3368
  child,
3329
3369
  platform = process.platform,
3330
- spawn: spawn6 = spawnSync4
3370
+ spawn: spawn5 = spawnSync4
3331
3371
  } = {}) {
3332
3372
  if (!child || !Number.isInteger(child.pid) || child.pid <= 0) return false;
3333
3373
  if (platform === "win32") {
3334
- const result = spawn6("taskkill", ["/PID", String(child.pid), "/T", "/F"], {
3374
+ const result = spawn5("taskkill", ["/PID", String(child.pid), "/T", "/F"], {
3335
3375
  windowsHide: true,
3336
3376
  stdio: "ignore",
3337
3377
  timeout: 15e3
@@ -3507,11 +3547,11 @@ function windowsSystemRoot(env2 = process.env) {
3507
3547
  function windowsPowershellExe(env2 = process.env) {
3508
3548
  return path11.join(windowsSystemRoot(env2), "System32", "WindowsPowerShell", "v1.0", "powershell.exe");
3509
3549
  }
3510
- function listProcessCreationTimes({ platform = process.platform, spawn: spawn6 = spawnSync5, env: env2 = process.env, warn = console.warn } = {}) {
3550
+ function listProcessCreationTimes({ platform = process.platform, spawn: spawn5 = spawnSync5, env: env2 = process.env, warn = console.warn } = {}) {
3511
3551
  const map = /* @__PURE__ */ new Map();
3512
3552
  if (platform === "win32") {
3513
3553
  const ps = "Get-CimInstance Win32_Process | ForEach-Object { '{0} {1}' -f $_.ProcessId, (([DateTimeOffset]$_.CreationDate.ToUniversalTime()).ToUnixTimeMilliseconds()) }";
3514
- const result2 = spawn6(windowsPowershellExe(env2), ["-NoProfile", "-NonInteractive", "-Command", ps], {
3554
+ const result2 = spawn5(windowsPowershellExe(env2), ["-NoProfile", "-NonInteractive", "-Command", ps], {
3515
3555
  windowsHide: true,
3516
3556
  encoding: "utf8",
3517
3557
  timeout: 2e4,
@@ -3527,7 +3567,7 @@ function listProcessCreationTimes({ platform = process.platform, spawn: spawn6 =
3527
3567
  }
3528
3568
  return map;
3529
3569
  }
3530
- const result = spawn6("ps", ["-eo", "pid=,lstart="], { encoding: "utf8", timeout: 2e4, maxBuffer: 32 * 1024 * 1024 });
3570
+ const result = spawn5("ps", ["-eo", "pid=,lstart="], { encoding: "utf8", timeout: 2e4, maxBuffer: 32 * 1024 * 1024 });
3531
3571
  if (result.error || result.status !== 0 || typeof result.stdout !== "string") {
3532
3572
  warn(`[orphan-reaper] process enumeration failed (${result.error ? result.error.message : `ps exit ${result.status}`}); reaping nothing this cycle`);
3533
3573
  return map;
@@ -3547,11 +3587,11 @@ function parsePosixPsLine(line) {
3547
3587
  if (!Number.isInteger(pid) || pid <= 0 || !Number.isFinite(when)) return null;
3548
3588
  return { pid, creationMs: when };
3549
3589
  }
3550
- function killProcessTree(pid, { platform = process.platform, spawn: spawn6 = spawnSync5, env: env2 = process.env } = {}) {
3590
+ function killProcessTree(pid, { platform = process.platform, spawn: spawn5 = spawnSync5, env: env2 = process.env } = {}) {
3551
3591
  if (!Number.isInteger(pid) || pid <= 0) return false;
3552
3592
  if (platform === "win32") {
3553
3593
  const taskkill = path11.join(windowsSystemRoot(env2), "System32", "taskkill.exe");
3554
- const r = spawn6(taskkill, ["/PID", String(pid), "/T", "/F"], { windowsHide: true, stdio: "ignore", timeout: 15e3 });
3594
+ const r = spawn5(taskkill, ["/PID", String(pid), "/T", "/F"], { windowsHide: true, stdio: "ignore", timeout: 15e3 });
3555
3595
  return !r.error && r.status === 0;
3556
3596
  }
3557
3597
  try {
@@ -4451,8 +4491,8 @@ var init_codex_runner = __esm({
4451
4491
  CODEX_PREFER_LOGIN_ENV = "VO_RUNNER_CODEX_PREFER_LOGIN";
4452
4492
  LEGACY_PREFER_LOGIN_ENV = "VO_RUNNER_PREFER_LOGIN";
4453
4493
  CodexRunner = class {
4454
- constructor({ spawn: spawn6 = spawnSync6, resolveBinary = resolveCodexBinary, env: env2 = process.env } = {}) {
4455
- this.spawn = spawn6;
4494
+ constructor({ spawn: spawn5 = spawnSync6, resolveBinary = resolveCodexBinary, env: env2 = process.env } = {}) {
4495
+ this.spawn = spawn5;
4456
4496
  this.resolveBinary = resolveBinary;
4457
4497
  this.env = env2;
4458
4498
  }
@@ -4821,12 +4861,12 @@ var init_local_model_runner = __esm({
4821
4861
  LOCAL_MODEL_RE = new RegExp("^[A-Za-z0-9][A-Za-z0-9._/:-]{0,127}$");
4822
4862
  LocalModelRunner = class {
4823
4863
  constructor({
4824
- spawn: spawn6 = null,
4864
+ spawn: spawn5 = null,
4825
4865
  resolveBinary = resolveCodexBinary,
4826
4866
  env: env2 = process.env,
4827
4867
  fetchImpl = globalThis.fetch
4828
4868
  } = {}) {
4829
- this.spawn = spawn6;
4869
+ this.spawn = spawn5;
4830
4870
  this.resolveBinary = resolveBinary;
4831
4871
  this.env = env2;
4832
4872
  this.fetchImpl = fetchImpl;
@@ -5012,7 +5052,7 @@ var init_openai_compatible_runner = __esm({
5012
5052
  buildArgs(opts = {}) {
5013
5053
  void opts;
5014
5054
  throw new Error(
5015
- "OpenAI-compatible full-repository coding is disabled. Use an explicit sanitized task capsule through the AlgoSuite Model Firewall."
5055
+ "OpenAI-compatible full-repository coding is disabled. The `oai` runner lane is RETIRED (PR #8742) and executes nothing. Set VO_CODE_RUNNER_AGENT to claude, codex, cursor, local, or meta. Use an explicit sanitized task capsule through the AlgoSuite Model Firewall."
5016
5056
  );
5017
5057
  }
5018
5058
  /** Codex JSONL events map identically → reuse the proven parser. */
@@ -5035,14 +5075,14 @@ var init_openai_compatible_runner = __esm({
5035
5075
  describeAuth(env2 = process.env) {
5036
5076
  const hasKey = Boolean(String(env2[OAI_API_KEY_ENV] || "").trim());
5037
5077
  const baseUrl = resolveOaiBaseUrl(env2);
5038
- return `oai-compat endpoint=${baseUrl || "<unset>"} key=${hasKey ? "set" : "MISSING"}`;
5078
+ return `oai-compat RETIRED endpoint=${baseUrl || "<unset>"} key=${hasKey ? "set" : "MISSING"}`;
5039
5079
  }
5040
- /** Best-effort: base URL chosen AND the codex transport is installed. */
5080
+ /** Always unavailable: the lane is retired, so nothing can authenticate it. */
5041
5081
  async checkAuth() {
5042
5082
  return {
5043
5083
  installed: false,
5044
5084
  authenticated: false,
5045
- message: "OpenAI-compatible coding is disabled; sanitized Model Firewall task capsules only"
5085
+ message: "the `oai` lane is RETIRED (PR #8742); OpenAI-compatible coding is disabled \u2014 sanitized Model Firewall task capsules only"
5046
5086
  };
5047
5087
  }
5048
5088
  };
@@ -7441,6 +7481,13 @@ function makeUsageRow({
7441
7481
  }
7442
7482
  return row;
7443
7483
  }
7484
+ function readingAgeMs(row, nowMs = Date.now()) {
7485
+ const at = row && typeof row.captured_at === "string" ? row.captured_at : null;
7486
+ if (!at) return null;
7487
+ const ms = new Date(at).getTime();
7488
+ if (!Number.isFinite(ms)) return null;
7489
+ return Math.max(0, nowMs - ms);
7490
+ }
7444
7491
  var clampPct, readJson, ACCOUNT_KEY_SALT;
7445
7492
  var init_shared = __esm({
7446
7493
  "../../scripts/virtual-office/code-runner/account-usage/shared.mjs"() {
@@ -7461,8 +7508,17 @@ var init_shared = __esm({
7461
7508
  });
7462
7509
 
7463
7510
  // ../../scripts/virtual-office/code-runner/account-usage/claude.mjs
7511
+ import fs7 from "node:fs";
7464
7512
  import os3 from "node:os";
7465
7513
  import path14 from "node:path";
7514
+ function fileCaptureTime(filePath, explicit, statFn) {
7515
+ if (typeof explicit === "string" && explicit) return explicit;
7516
+ try {
7517
+ return statFn(filePath).mtime.toISOString();
7518
+ } catch {
7519
+ return null;
7520
+ }
7521
+ }
7466
7522
  function usageBaseUrl(env2 = process.env) {
7467
7523
  const raw = env2.ANTHROPIC_BASE_URL || "https://api.anthropic.com";
7468
7524
  return String(raw).replace(/\/+$/, "");
@@ -7568,7 +7624,12 @@ async function readClaudeOAuthUsage({
7568
7624
  clearTimeout(timer);
7569
7625
  }
7570
7626
  }
7571
- function readClaudeFileUsage({ homeDir = os3.homedir(), read: rawRead = readJson } = {}) {
7627
+ function readClaudeFileUsage({
7628
+ homeDir = os3.homedir(),
7629
+ read: rawRead = readJson,
7630
+ statFn = fs7.statSync,
7631
+ now = () => Date.now()
7632
+ } = {}) {
7572
7633
  const read = (p) => {
7573
7634
  try {
7574
7635
  return rawRead(p);
@@ -7577,31 +7638,39 @@ function readClaudeFileUsage({ homeDir = os3.homedir(), read: rawRead = readJson
7577
7638
  }
7578
7639
  };
7579
7640
  const accountId = readAccountId({ homeDir, read });
7580
- const status = read(path14.join(homeDir, ".claude", "claude-usage.json"));
7641
+ const fresh = (row) => {
7642
+ if (!row) return null;
7643
+ const age = readingAgeMs(row, now());
7644
+ if (age === null || age > MAX_FILE_AGE_MS) return null;
7645
+ return row;
7646
+ };
7647
+ const statusPath = path14.join(homeDir, ".claude", "claude-usage.json");
7648
+ const status = read(statusPath);
7581
7649
  if (status && (status.seven_day || status.five_hour)) {
7582
- const row = makeUsageRow({
7650
+ const row = fresh(makeUsageRow({
7583
7651
  agent: "claude",
7584
7652
  source: "statusline",
7585
- capturedAt: typeof status.capturedAt === "string" ? status.capturedAt : null,
7653
+ capturedAt: fileCaptureTime(statusPath, status.capturedAt, statFn),
7586
7654
  accountId,
7587
7655
  sevenDay: status.seven_day?.used_percentage,
7588
7656
  fiveHour: status.five_hour?.used_percentage,
7589
7657
  sevenDayResetsAt: status.seven_day?.resets_at ?? null,
7590
7658
  fiveHourResetsAt: status.five_hour?.resets_at ?? null
7591
- });
7659
+ }));
7592
7660
  if (row) return row;
7593
7661
  }
7594
- const weekly = read(path14.join(homeDir, ".claude", "claude-weekly-usage.json"));
7662
+ const weeklyPath = path14.join(homeDir, ".claude", "claude-weekly-usage.json");
7663
+ const weekly = read(weeklyPath);
7595
7664
  if (weekly) {
7596
- const row = makeUsageRow({
7665
+ const row = fresh(makeUsageRow({
7597
7666
  agent: "claude",
7598
7667
  source: "file",
7599
- capturedAt: typeof weekly.capturedAt === "string" ? weekly.capturedAt : null,
7668
+ capturedAt: fileCaptureTime(weeklyPath, weekly.capturedAt, statFn),
7600
7669
  accountId,
7601
7670
  sevenDay: weekly.sevenDayPct,
7602
7671
  fiveHour: weekly.fiveHourPct,
7603
7672
  sevenDayResetsAt: weekly.sevenDayResetsAt ?? null
7604
- });
7673
+ }));
7605
7674
  if (row) return row;
7606
7675
  }
7607
7676
  return null;
@@ -7614,11 +7683,12 @@ async function readClaudeUsage(opts = {}) {
7614
7683
  }
7615
7684
  return readClaudeFileUsage(opts);
7616
7685
  }
7617
- var USAGE_PATH, OAUTH_BETA, DEFAULT_TIMEOUT_MS;
7686
+ var MAX_FILE_AGE_MS, USAGE_PATH, OAUTH_BETA, DEFAULT_TIMEOUT_MS;
7618
7687
  var init_claude = __esm({
7619
7688
  "../../scripts/virtual-office/code-runner/account-usage/claude.mjs"() {
7620
7689
  "use strict";
7621
7690
  init_shared();
7691
+ MAX_FILE_AGE_MS = 6 * 60 * 60 * 1e3;
7622
7692
  USAGE_PATH = "/api/oauth/usage";
7623
7693
  OAUTH_BETA = "oauth-2025-04-20";
7624
7694
  DEFAULT_TIMEOUT_MS = 5e3;
@@ -7731,83 +7801,6 @@ var init_codex = __esm({
7731
7801
  }
7732
7802
  });
7733
7803
 
7734
- // ../../scripts/virtual-office/code-runner/account-usage/copilot.mjs
7735
- import { spawn as spawn5 } from "node:child_process";
7736
- function parseCopilotUsage(body, { now = () => Date.now() } = {}) {
7737
- if (!body || typeof body !== "object") return null;
7738
- const snapshots = body.quota_snapshots;
7739
- if (!snapshots || typeof snapshots !== "object") return null;
7740
- const bucket = snapshots[METERED_BUCKET];
7741
- if (!bucket || typeof bucket !== "object") return null;
7742
- if (bucket.unlimited === true || bucket.has_quota === false) return null;
7743
- const remaining = clampPct(bucket.percent_remaining);
7744
- if (remaining === null) return null;
7745
- const resetDate = typeof body.quota_reset_date === "string" ? body.quota_reset_date : null;
7746
- const resetsAt = resetDate && /^\d{4}-\d{2}-\d{2}$/.test(resetDate) ? `${resetDate}T00:00:00.000Z` : null;
7747
- return makeUsageRow({
7748
- agent: "copilot",
7749
- source: "cli",
7750
- capturedAt: new Date(now()).toISOString(),
7751
- // The API reports REMAINING; every row in this system stores USED.
7752
- monthly: 100 - remaining,
7753
- monthlyResetsAt: resetsAt,
7754
- accountId: typeof body.login === "string" ? body.login : null
7755
- });
7756
- }
7757
- function readCopilotUsage({
7758
- spawnImpl = spawn5,
7759
- timeoutMs = 8e3,
7760
- env: env2 = process.env,
7761
- now = () => Date.now()
7762
- } = {}) {
7763
- return new Promise((resolve2) => {
7764
- let child;
7765
- let settled = false;
7766
- let stdout = "";
7767
- const finish = (value) => {
7768
- if (settled) return;
7769
- settled = true;
7770
- clearTimeout(timer);
7771
- try {
7772
- child?.kill();
7773
- } catch {
7774
- }
7775
- resolve2(value);
7776
- };
7777
- const timer = setTimeout(() => finish(null), timeoutMs);
7778
- try {
7779
- child = spawnImpl("gh", ["api", "copilot_internal/user"], {
7780
- env: env2,
7781
- windowsHide: true,
7782
- shell: false,
7783
- stdio: ["ignore", "pipe", "ignore"]
7784
- });
7785
- child.on("error", () => finish(null));
7786
- child.stdout?.on("data", (chunk) => {
7787
- stdout += chunk.toString();
7788
- });
7789
- child.on("close", (code) => {
7790
- if (code !== 0) return finish(null);
7791
- try {
7792
- finish(parseCopilotUsage(JSON.parse(stdout), { now }));
7793
- } catch {
7794
- finish(null);
7795
- }
7796
- });
7797
- } catch {
7798
- finish(null);
7799
- }
7800
- });
7801
- }
7802
- var METERED_BUCKET;
7803
- var init_copilot = __esm({
7804
- "../../scripts/virtual-office/code-runner/account-usage/copilot.mjs"() {
7805
- "use strict";
7806
- init_shared();
7807
- METERED_BUCKET = "premium_interactions";
7808
- }
7809
- });
7810
-
7811
7804
  // ../../scripts/virtual-office/code-runner/account-usage/index.mjs
7812
7805
  function collectAccountUsage(opts = {}) {
7813
7806
  const claude = readClaudeFileUsage(opts);
@@ -7816,13 +7809,11 @@ function collectAccountUsage(opts = {}) {
7816
7809
  async function collectConnectedAccountUsage({
7817
7810
  readClaude = readClaudeUsage,
7818
7811
  readCodex = readCodexUsage,
7819
- readCopilot = readCopilotUsage,
7820
7812
  ...agentOptions
7821
7813
  } = {}) {
7822
7814
  const settled = await Promise.allSettled([
7823
7815
  readClaude(agentOptions),
7824
- readCodex(agentOptions),
7825
- readCopilot(agentOptions)
7816
+ readCodex(agentOptions)
7826
7817
  ]);
7827
7818
  return settled.map((outcome) => outcome.status === "fulfilled" ? outcome.value : null).filter(Boolean);
7828
7819
  }
@@ -7858,12 +7849,10 @@ var init_account_usage = __esm({
7858
7849
  "use strict";
7859
7850
  init_claude();
7860
7851
  init_codex();
7861
- init_copilot();
7862
7852
  init_shared();
7863
7853
  AGENT_USAGE_CAPABILITY = Object.freeze({
7864
7854
  claude: Object.freeze({ five_hour: true, seven_day: true, monthly: false }),
7865
7855
  codex: Object.freeze({ five_hour: false, seven_day: true, monthly: false }),
7866
- copilot: Object.freeze({ five_hour: false, seven_day: false, monthly: true }),
7867
7856
  cursor: Object.freeze({ five_hour: false, seven_day: false, monthly: false }),
7868
7857
  gemini: Object.freeze({ five_hour: false, seven_day: false, monthly: false })
7869
7858
  });
@@ -9122,7 +9111,7 @@ var init_effort_mode_config = __esm({
9122
9111
  });
9123
9112
 
9124
9113
  // ../../scripts/virtual-office/model-registry.mjs
9125
- import fs7 from "node:fs";
9114
+ import fs8 from "node:fs";
9126
9115
  import path15 from "node:path";
9127
9116
  import { fileURLToPath as fileURLToPath4 } from "node:url";
9128
9117
  function uniqueModels(models = []) {
@@ -9235,9 +9224,9 @@ async function fetchGoogleModels(fetchImpl, env2 = process.env) {
9235
9224
  return (data?.models || []).map((model) => normalizeCatalogModel({ ...model, provider: "google", source: "google" })).filter(Boolean);
9236
9225
  }
9237
9226
  function readCache(cacheFile = DEFAULT_CACHE_FILE, nowMs = Date.now(), ttlMs = DEFAULT_TTL_MS3) {
9238
- if (!fs7.existsSync(cacheFile)) return null;
9227
+ if (!fs8.existsSync(cacheFile)) return null;
9239
9228
  try {
9240
- const parsed = JSON.parse(fs7.readFileSync(cacheFile, "utf-8"));
9229
+ const parsed = JSON.parse(fs8.readFileSync(cacheFile, "utf-8"));
9241
9230
  if (nowMs - Number(parsed.checkedAtMs || 0) > ttlMs) return null;
9242
9231
  if (!Array.isArray(parsed.models)) return null;
9243
9232
  return parsed;
@@ -9246,8 +9235,8 @@ function readCache(cacheFile = DEFAULT_CACHE_FILE, nowMs = Date.now(), ttlMs = D
9246
9235
  }
9247
9236
  }
9248
9237
  function writeCache(cacheFile = DEFAULT_CACHE_FILE, payload) {
9249
- fs7.mkdirSync(path15.dirname(cacheFile), { recursive: true });
9250
- fs7.writeFileSync(cacheFile, JSON.stringify(payload, null, 2));
9238
+ fs8.mkdirSync(path15.dirname(cacheFile), { recursive: true });
9239
+ fs8.writeFileSync(cacheFile, JSON.stringify(payload, null, 2));
9251
9240
  }
9252
9241
  async function fetchRegistryCatalog({
9253
9242
  fetchImpl = fetch,
@@ -10519,6 +10508,93 @@ var init_task_helpers = __esm({
10519
10508
  }
10520
10509
  });
10521
10510
 
10511
+ // ../../scripts/virtual-office/code-runner/swarm-admission.mjs
10512
+ function canLaunchSuccessorAgent(agent, platform = process.platform) {
10513
+ const name = typeof agent === "string" ? agent.trim() : "";
10514
+ if (!Object.prototype.hasOwnProperty.call(SUCCESSOR_LAUNCH_SHAPES, name)) return false;
10515
+ if (platform === "win32" && !SUCCESSOR_LAUNCH_SHAPES[name]) return false;
10516
+ return true;
10517
+ }
10518
+ function isSubscriptionExhausted(usage) {
10519
+ if (!usage || typeof usage !== "object") return false;
10520
+ const readings = [usage.seven_day_used_pct, usage.five_hour_used_pct, usage.monthly_used_pct];
10521
+ return readings.some((v) => typeof v === "number" && Number.isFinite(v) && v >= SUBSCRIPTION_EXHAUSTED_PCT);
10522
+ }
10523
+ function clampSubagents(requested) {
10524
+ if (!Number.isFinite(requested) || requested < 1) return 0;
10525
+ return Math.min(Math.floor(requested), MAX_BOUND_SUBAGENTS);
10526
+ }
10527
+ function usageFor(accountUsage, agent) {
10528
+ if (!Array.isArray(accountUsage)) return null;
10529
+ return accountUsage.find((row) => row && row.agent === agent) ?? null;
10530
+ }
10531
+ function exhaustedAgents(availableAgents, accountUsage) {
10532
+ if (!Array.isArray(availableAgents)) return [];
10533
+ return availableAgents.filter((row) => row && row.installed === true && row.authenticated === true && row.auth_tier === AUTH_TIER_SUBSCRIPTION && isSubscriptionExhausted(usageFor(accountUsage, row.agent))).map((row) => row.agent);
10534
+ }
10535
+ function resolveRunnerSwarmBinding({
10536
+ swarmId,
10537
+ agent,
10538
+ availableAgents,
10539
+ accountUsage = [],
10540
+ requestedSubagents = MAX_BOUND_SUBAGENTS,
10541
+ nowIso,
10542
+ platform = process.platform
10543
+ } = {}) {
10544
+ const id = typeof swarmId === "string" ? swarmId.trim() : "";
10545
+ const boundAgent = typeof agent === "string" ? agent.trim() : "";
10546
+ if (id.length === 0 || boundAgent.length === 0) return null;
10547
+ if (!canLaunchSuccessorAgent(boundAgent, platform)) return null;
10548
+ const budget = clampSubagents(requestedSubagents);
10549
+ if (budget === 0) return null;
10550
+ const rows = Array.isArray(availableAgents) ? availableAgents : [];
10551
+ const row = rows.find((r) => r && r.agent === boundAgent) ?? null;
10552
+ if (!row || row.installed !== true || row.authenticated !== true) return null;
10553
+ const tier = AUTH_TIER_TO_SWARM_TIER[row.auth_tier];
10554
+ if (!tier) return null;
10555
+ const exhausted = exhaustedAgents(rows, accountUsage);
10556
+ const boundExhausted = tier === "tier1_subscription" && isSubscriptionExhausted(usageFor(accountUsage, boundAgent));
10557
+ const effectiveBudget = boundExhausted ? Math.min(budget, EXHAUSTED_SUBAGENT_BUDGET) : budget;
10558
+ const basis = `code-task dispatch admitted on '${boundAgent}' at auth tier '${row.auth_tier}' (runner-local capability probe)`;
10559
+ return {
10560
+ schema_version: 1,
10561
+ swarm_id: id,
10562
+ tier,
10563
+ agent: boundAgent,
10564
+ reason: boundExhausted ? `${basis}; that subscription window is >=${SUBSCRIPTION_EXHAUSTED_PCT}% spent, so the fan-out is bound at a REDUCED ceiling of ${effectiveBudget} instead of being left unbound and uncapped` : basis,
10565
+ exhausted_agents: exhausted,
10566
+ subagent_budget: effectiveBudget,
10567
+ // Never a platform-billed fan-out in this lane — see the module header.
10568
+ spend_cap_usd: null,
10569
+ resolved_at: typeof nowIso === "string" && nowIso ? nowIso : (/* @__PURE__ */ new Date()).toISOString()
10570
+ };
10571
+ }
10572
+ function mintSwarmTierBindingEnv(input) {
10573
+ const binding = resolveRunnerSwarmBinding(input);
10574
+ if (!binding) return {};
10575
+ return { [SWARM_TIER_BINDING_ENV]: JSON.stringify(binding) };
10576
+ }
10577
+ var SWARM_TIER_BINDING_ENV, MAX_BOUND_SUBAGENTS, SUBSCRIPTION_EXHAUSTED_PCT, EXHAUSTED_SUBAGENT_BUDGET, SUCCESSOR_LAUNCH_SHAPES, AUTH_TIER_TO_SWARM_TIER;
10578
+ var init_swarm_admission = __esm({
10579
+ "../../scripts/virtual-office/code-runner/swarm-admission.mjs"() {
10580
+ "use strict";
10581
+ init_agent_auth_tier();
10582
+ SWARM_TIER_BINDING_ENV = "VO_SWARM_TIER_BINDING";
10583
+ MAX_BOUND_SUBAGENTS = 20;
10584
+ SUBSCRIPTION_EXHAUSTED_PCT = 95;
10585
+ EXHAUSTED_SUBAGENT_BUDGET = 1;
10586
+ SUCCESSOR_LAUNCH_SHAPES = Object.freeze({
10587
+ claude: true,
10588
+ codex: false
10589
+ });
10590
+ AUTH_TIER_TO_SWARM_TIER = Object.freeze({
10591
+ [AUTH_TIER_SUBSCRIPTION]: "tier1_subscription",
10592
+ [AUTH_TIER_LOCAL]: "tier1_local",
10593
+ [AUTH_TIER_API_KEY]: "tier2_user_key"
10594
+ });
10595
+ }
10596
+ });
10597
+
10522
10598
  // ../../scripts/virtual-office/code-runner/agent-process-env.mjs
10523
10599
  function safeIdentityPart(value, fallback) {
10524
10600
  const normalized = String(value || "").trim().replace(/[^a-zA-Z0-9_-]+/g, "-").replace(/^-+|-+$/g, "");
@@ -10531,8 +10607,14 @@ function safeBaseEnv(env2 = {}) {
10531
10607
  }
10532
10608
  return result;
10533
10609
  }
10534
- function buildAgentProcessEnv(env2, { agent = "agent", runnerId = "vo-runner", taskId = "task", githubReadToken = null } = {}) {
10610
+ function buildAgentProcessEnv(env2, { agent = "agent", runnerId = "vo-runner", taskId = "task", githubReadToken = null, swarmAdmission = null } = {}) {
10535
10611
  const base = safeBaseEnv(env2);
10612
+ if (swarmAdmission) {
10613
+ for (const key of Object.keys(base)) {
10614
+ if (key.toUpperCase() === SWARM_TIER_BINDING_ENV) delete base[key];
10615
+ }
10616
+ Object.assign(base, mintSwarmTierBindingEnv({ ...swarmAdmission, agent, swarmId: taskId }));
10617
+ }
10536
10618
  if (typeof githubReadToken === "string" && githubReadToken) {
10537
10619
  base.GH_TOKEN = githubReadToken;
10538
10620
  base.GITHUB_TOKEN = githubReadToken;
@@ -10550,6 +10632,7 @@ var SAFE_ENV_NAMES;
10550
10632
  var init_agent_process_env = __esm({
10551
10633
  "../../scripts/virtual-office/code-runner/agent-process-env.mjs"() {
10552
10634
  "use strict";
10635
+ init_swarm_admission();
10553
10636
  SAFE_ENV_NAMES = /* @__PURE__ */ new Set([
10554
10637
  "AGENT_ID",
10555
10638
  "APPDATA",
@@ -10590,7 +10673,31 @@ var init_agent_process_env = __esm({
10590
10673
  // it. #9242 added VO_RUNNER_PREFER_KEY without this line, which left the
10591
10674
  // escape hatch inert — an operator who set it still got the subscription.
10592
10675
  "VO_RUNNER_PREFER_KEY",
10593
- "VO_RUNNER_CLAUDE_PREFER_KEY"
10676
+ "VO_RUNNER_CLAUDE_PREFER_KEY",
10677
+ // The swarm tier binding (SWARM_TIER_BINDING_ENV in
10678
+ // packages/vo-mcp/src/swarm/tier-binding.ts). A fan-out resolves its billing
10679
+ // tier ONCE at admission and exports the binding so every subagent inherits
10680
+ // the same answer instead of re-resolving its own. This line is what lets it
10681
+ // cross the process boundary at all: the daemon builds each child env with
10682
+ // buildAgentProcessEnv(process.env) at
10683
+ // scripts/virtual-office/code-runner-daemon.mjs:117 (sibling dir, not this
10684
+ // one), so a name absent from this set is stripped and the binding binds
10685
+ // NOTHING —
10686
+ // exactly how #9242's VO_RUNNER_PREFER_KEY shipped inert until #9247.
10687
+ //
10688
+ // NOT a credential and NOT an authorization input: it names a tier, it never
10689
+ // grants one, and it carries no key material (see the module's header rule).
10690
+ "VO_SWARM_TIER_BINDING",
10691
+ // Where the swarm SPAWN LEDGER lives (SWARM_LEDGER_DIR_ENV in
10692
+ // packages/vo-mcp/src/swarm/spawn-ledger.ts). The ledger is the durable,
10693
+ // host-shared counter that bounds the TOTAL spawns under one swarm_id; the
10694
+ // binding above only bounds the depth of one chain. If a parent's override
10695
+ // were stripped here, the child would ledger into a DIFFERENT directory,
10696
+ // claim slot 0 again, and the shared ceiling would silently degrade back to a
10697
+ // per-process quota — which is precisely the defect the ledger closes.
10698
+ //
10699
+ // A path, not a credential. Absent means the default ~/.vo/swarm-ledger.
10700
+ "VO_SWARM_LEDGER_DIR"
10594
10701
  ]);
10595
10702
  }
10596
10703
  });
@@ -11081,7 +11188,7 @@ var init_inference_task_runner = __esm({
11081
11188
  });
11082
11189
 
11083
11190
  // ../../scripts/virtual-office/code-runner/isolation-audit.mjs
11084
- import fs8 from "node:fs";
11191
+ import fs9 from "node:fs";
11085
11192
  import fsp11 from "node:fs/promises";
11086
11193
  import path16 from "node:path";
11087
11194
  async function defaultRun(command, args, cwd, options = {}) {
@@ -11176,7 +11283,7 @@ async function restoreExactCanonicalPaths(baseline, evidence, run) {
11176
11283
  for (const relative of evidence.untracked) {
11177
11284
  const target = path16.resolve(baseline.root, relative);
11178
11285
  const prefix = `${path16.resolve(baseline.root)}${path16.sep}`;
11179
- if (!target.startsWith(prefix) || !fs8.existsSync(target)) continue;
11286
+ if (!target.startsWith(prefix) || !fs9.existsSync(target)) continue;
11180
11287
  await fsp11.rm(target, { force: true });
11181
11288
  }
11182
11289
  }
@@ -11706,7 +11813,7 @@ var init_publication_scope = __esm({
11706
11813
  });
11707
11814
 
11708
11815
  // ../../scripts/virtual-office/code-runner/recovery-ledger.mjs
11709
- import fs9 from "node:fs";
11816
+ import fs10 from "node:fs";
11710
11817
  import fsp13 from "node:fs/promises";
11711
11818
  import path18 from "node:path";
11712
11819
  function recoveryTaskId(prompt) {
@@ -11744,7 +11851,7 @@ async function readLedger(file, readFile5) {
11744
11851
  async function findPreservedRecovery(task, {
11745
11852
  clonesRoot: clonesRoot2 = process.env.VO_CODE_RUNNER_CLONES_ROOT || "",
11746
11853
  readFile: readFile5 = fsp13.readFile,
11747
- exists = fs9.existsSync
11854
+ exists = fs10.existsSync
11748
11855
  } = {}) {
11749
11856
  const resumedFrom = /^[0-9a-f-]{36}$/iu.test(String(task.resumed_from || "")) ? String(task.resumed_from).toLowerCase() : null;
11750
11857
  const originalTaskId = recoveryTaskId(task.prompt) ?? resumedFrom;
@@ -12468,7 +12575,7 @@ import { fileURLToPath as fileURLToPath6 } from "node:url";
12468
12575
  function log(msg) {
12469
12576
  console.log(`[code-runner ${(/* @__PURE__ */ new Date()).toISOString()}] ${msg}`);
12470
12577
  }
12471
- async function processOneTask(client, task, cfg, runnerInstanceId) {
12578
+ async function processOneTask(client, task, cfg, runnerInstanceId, swarmAdmission = null) {
12472
12579
  const id = task.code_task_id;
12473
12580
  let worktreeName = "";
12474
12581
  let preserveReason = null;
@@ -12518,7 +12625,8 @@ async function processOneTask(client, task, cfg, runnerInstanceId) {
12518
12625
  model,
12519
12626
  effort: effectiveEffort,
12520
12627
  maxBudgetUsd: sel.agent === "claude" ? effectiveMaxBudgetUsd : void 0,
12521
- env: buildAgentProcessEnv(process.env, { agent: sel.agent, runnerId: cfg.runnerId, taskId: id, githubReadToken: agentGithubReadToken }),
12628
+ env: buildAgentProcessEnv(process.env, { agent: sel.agent, runnerId: cfg.runnerId, taskId: id, githubReadToken: agentGithubReadToken, swarmAdmission }),
12629
+ // swarmAdmission mints VO_SWARM_TIER_BINDING: ONE tier decision for this task's whole agent tree
12522
12630
  sandbox,
12523
12631
  onProgress: (text, checkpoint) => {
12524
12632
  const usage = checkpoint?.tokenUsage ? { token_usage: checkpoint.tokenUsage } : {};
@@ -12804,7 +12912,7 @@ async function main({ env: env2 = process.env, once: once2 = false } = {}) {
12804
12912
  }
12805
12913
  log(`claimed task ${task.code_task_id} (${task.repo})`);
12806
12914
  active += 1;
12807
- const runTask = task.kind === "inference" ? processInferenceTask(client, task, cfg, { safeProgress, runnerStagePatch, log }) : processOneTask(client, task, cfg, runnerInstanceId);
12915
+ const runTask = task.kind === "inference" ? processInferenceTask(client, task, cfg, { safeProgress, runnerStagePatch, log }) : processOneTask(client, task, cfg, runnerInstanceId, { availableAgents: claimAgents.availableAgents, accountUsage: accountUsage.get() });
12808
12916
  const done = runTask.catch(async (error) => {
12809
12917
  log(`task ${task.code_task_id} unhandled runner error: ${error.message}`);
12810
12918
  if (task.kind === "inference") await deliverTerminalRun({