@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.
- package/dist/agent-auth-probe-cli.mjs +69 -37
- package/dist/cli.js +476 -42
- package/dist/cli.js.map +4 -4
- package/dist/index.js +467 -33
- package/dist/index.js.map +4 -4
- package/dist/runner-cli.js +265 -157
- package/dist/runner-cli.js.map +4 -4
- package/dist/set-key-cli.js +38 -2
- package/dist/set-key-cli.js.map +2 -2
- package/package.json +1 -1
package/dist/runner-cli.js
CHANGED
|
@@ -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
|
-
|
|
3037
|
-
|
|
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 (
|
|
3042
|
-
|
|
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
|
-
|
|
3052
|
-
|
|
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:
|
|
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 =
|
|
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,
|
|
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
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
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:
|
|
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 =
|
|
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:
|
|
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 =
|
|
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 =
|
|
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:
|
|
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 =
|
|
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:
|
|
4455
|
-
this.spawn =
|
|
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:
|
|
4864
|
+
spawn: spawn5 = null,
|
|
4825
4865
|
resolveBinary = resolveCodexBinary,
|
|
4826
4866
|
env: env2 = process.env,
|
|
4827
4867
|
fetchImpl = globalThis.fetch
|
|
4828
4868
|
} = {}) {
|
|
4829
|
-
this.spawn =
|
|
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
|
-
/**
|
|
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
|
|
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({
|
|
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
|
|
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:
|
|
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
|
|
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:
|
|
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
|
|
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 (!
|
|
9227
|
+
if (!fs8.existsSync(cacheFile)) return null;
|
|
9239
9228
|
try {
|
|
9240
|
-
const parsed = JSON.parse(
|
|
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
|
-
|
|
9250
|
-
|
|
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
|
|
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) || !
|
|
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
|
|
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 =
|
|
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({
|