@algosuite/vo-mcp 0.2.0-beta.26 → 0.2.0-beta.27
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 +105 -8
- package/dist/runner-cli.js +508 -98
- package/dist/runner-cli.js.map +4 -4
- package/package.json +1 -1
package/dist/runner-cli.js
CHANGED
|
@@ -3026,23 +3026,40 @@ function isTruthyFlag(v) {
|
|
|
3026
3026
|
const s = String(v ?? "").trim().toLowerCase();
|
|
3027
3027
|
return s === "1" || s === "true" || s === "yes" || s === "on";
|
|
3028
3028
|
}
|
|
3029
|
-
function
|
|
3030
|
-
|
|
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
|
+
function withAnthropicKey(baseEnv = {}, { getKey = getAnthropicKey, probeLogin = probeClaudeLoginState } = {}) {
|
|
3036
|
+
if (wantsLogin(baseEnv)) {
|
|
3031
3037
|
const next = { ...baseEnv };
|
|
3032
3038
|
delete next.ANTHROPIC_API_KEY;
|
|
3033
3039
|
return next;
|
|
3034
3040
|
}
|
|
3035
3041
|
if (baseEnv.ANTHROPIC_API_KEY) return { ...baseEnv };
|
|
3036
3042
|
const key = getKey();
|
|
3037
|
-
|
|
3043
|
+
if (!key) return { ...baseEnv };
|
|
3044
|
+
if (!wantsKey(baseEnv) && probeLogin() === true) return { ...baseEnv };
|
|
3045
|
+
return { ...baseEnv, ANTHROPIC_API_KEY: key };
|
|
3046
|
+
}
|
|
3047
|
+
function claudeCostBasis(env2 = process.env) {
|
|
3048
|
+
return String(env2.ANTHROPIC_API_KEY || "").trim() ? "vendor_billed" : "subscription_api_equivalent";
|
|
3038
3049
|
}
|
|
3039
|
-
function describeAnthropicAuthSource(baseEnv = {}, { getKey = getAnthropicKey } = {}) {
|
|
3040
|
-
if (
|
|
3050
|
+
function describeAnthropicAuthSource(baseEnv = {}, { getKey = getAnthropicKey, probeLogin = probeClaudeLoginState } = {}) {
|
|
3051
|
+
if (wantsLogin(baseEnv)) {
|
|
3041
3052
|
return "claude auth login (VO_RUNNER_PREFER_LOGIN set \u2014 any API key ignored)";
|
|
3042
3053
|
}
|
|
3043
3054
|
if (baseEnv.ANTHROPIC_API_KEY) return "ANTHROPIC_API_KEY from environment";
|
|
3044
|
-
if (getKey()) return "
|
|
3045
|
-
|
|
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";
|
|
3046
3063
|
}
|
|
3047
3064
|
function augmentAuthError(summary) {
|
|
3048
3065
|
const s = String(summary ?? "");
|
|
@@ -3051,20 +3068,20 @@ function augmentAuthError(summary) {
|
|
|
3051
3068
|
\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"\`.`;
|
|
3052
3069
|
}
|
|
3053
3070
|
function probeClaudeLoginState({
|
|
3054
|
-
spawn:
|
|
3071
|
+
spawn: spawn6 = spawnSync2,
|
|
3055
3072
|
buildWindowsLaunch = buildWindowsClaudeLaunch,
|
|
3056
3073
|
platform = process.platform
|
|
3057
3074
|
} = {}) {
|
|
3058
3075
|
try {
|
|
3059
3076
|
const launch = platform === "win32" ? buildWindowsLaunch({ bin: "claude", args: ["auth", "status"] }) : { bin: "claude", args: ["auth", "status"], spawnOptions: { windowsHide: true } };
|
|
3060
|
-
const st =
|
|
3077
|
+
const st = spawn6(launch.bin, launch.args, { ...launch.spawnOptions, timeout: 5e3, encoding: "utf8" });
|
|
3061
3078
|
const parsed = JSON.parse(String(st.stdout || "").trim() || "{}");
|
|
3062
3079
|
return typeof parsed.loggedIn === "boolean" ? parsed.loggedIn : null;
|
|
3063
3080
|
} catch {
|
|
3064
3081
|
return null;
|
|
3065
3082
|
}
|
|
3066
3083
|
}
|
|
3067
|
-
var require2, KEY_SERVICE, KEY_ACCOUNT, _entryCtor, _loadTried, PREFER_LOGIN_ENV, CLAUDE_PREFER_LOGIN_ENV, AUTH_ERROR_RE;
|
|
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;
|
|
3068
3085
|
var init_anthropic_key_store = __esm({
|
|
3069
3086
|
"../../scripts/virtual-office/code-runner/anthropic-key-store.mjs"() {
|
|
3070
3087
|
"use strict";
|
|
@@ -3075,6 +3092,8 @@ var init_anthropic_key_store = __esm({
|
|
|
3075
3092
|
_loadTried = false;
|
|
3076
3093
|
PREFER_LOGIN_ENV = "VO_RUNNER_PREFER_LOGIN";
|
|
3077
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";
|
|
3078
3097
|
AUTH_ERROR_RE = /\b401\b|invalid[^.]{0,24}(authentication|credential)|authentication_error|unauthorized|not[ _-]?authenticated/i;
|
|
3079
3098
|
}
|
|
3080
3099
|
});
|
|
@@ -3308,11 +3327,11 @@ import { spawnSync as spawnSync4 } from "node:child_process";
|
|
|
3308
3327
|
function terminateAgentProcessTree({
|
|
3309
3328
|
child,
|
|
3310
3329
|
platform = process.platform,
|
|
3311
|
-
spawn:
|
|
3330
|
+
spawn: spawn6 = spawnSync4
|
|
3312
3331
|
} = {}) {
|
|
3313
3332
|
if (!child || !Number.isInteger(child.pid) || child.pid <= 0) return false;
|
|
3314
3333
|
if (platform === "win32") {
|
|
3315
|
-
const result =
|
|
3334
|
+
const result = spawn6("taskkill", ["/PID", String(child.pid), "/T", "/F"], {
|
|
3316
3335
|
windowsHide: true,
|
|
3317
3336
|
stdio: "ignore",
|
|
3318
3337
|
timeout: 15e3
|
|
@@ -3488,11 +3507,11 @@ function windowsSystemRoot(env2 = process.env) {
|
|
|
3488
3507
|
function windowsPowershellExe(env2 = process.env) {
|
|
3489
3508
|
return path11.join(windowsSystemRoot(env2), "System32", "WindowsPowerShell", "v1.0", "powershell.exe");
|
|
3490
3509
|
}
|
|
3491
|
-
function listProcessCreationTimes({ platform = process.platform, spawn:
|
|
3510
|
+
function listProcessCreationTimes({ platform = process.platform, spawn: spawn6 = spawnSync5, env: env2 = process.env, warn = console.warn } = {}) {
|
|
3492
3511
|
const map = /* @__PURE__ */ new Map();
|
|
3493
3512
|
if (platform === "win32") {
|
|
3494
3513
|
const ps = "Get-CimInstance Win32_Process | ForEach-Object { '{0} {1}' -f $_.ProcessId, (([DateTimeOffset]$_.CreationDate.ToUniversalTime()).ToUnixTimeMilliseconds()) }";
|
|
3495
|
-
const result2 =
|
|
3514
|
+
const result2 = spawn6(windowsPowershellExe(env2), ["-NoProfile", "-NonInteractive", "-Command", ps], {
|
|
3496
3515
|
windowsHide: true,
|
|
3497
3516
|
encoding: "utf8",
|
|
3498
3517
|
timeout: 2e4,
|
|
@@ -3508,7 +3527,7 @@ function listProcessCreationTimes({ platform = process.platform, spawn: spawn5 =
|
|
|
3508
3527
|
}
|
|
3509
3528
|
return map;
|
|
3510
3529
|
}
|
|
3511
|
-
const result =
|
|
3530
|
+
const result = spawn6("ps", ["-eo", "pid=,lstart="], { encoding: "utf8", timeout: 2e4, maxBuffer: 32 * 1024 * 1024 });
|
|
3512
3531
|
if (result.error || result.status !== 0 || typeof result.stdout !== "string") {
|
|
3513
3532
|
warn(`[orphan-reaper] process enumeration failed (${result.error ? result.error.message : `ps exit ${result.status}`}); reaping nothing this cycle`);
|
|
3514
3533
|
return map;
|
|
@@ -3528,11 +3547,11 @@ function parsePosixPsLine(line) {
|
|
|
3528
3547
|
if (!Number.isInteger(pid) || pid <= 0 || !Number.isFinite(when)) return null;
|
|
3529
3548
|
return { pid, creationMs: when };
|
|
3530
3549
|
}
|
|
3531
|
-
function killProcessTree(pid, { platform = process.platform, spawn:
|
|
3550
|
+
function killProcessTree(pid, { platform = process.platform, spawn: spawn6 = spawnSync5, env: env2 = process.env } = {}) {
|
|
3532
3551
|
if (!Number.isInteger(pid) || pid <= 0) return false;
|
|
3533
3552
|
if (platform === "win32") {
|
|
3534
3553
|
const taskkill = path11.join(windowsSystemRoot(env2), "System32", "taskkill.exe");
|
|
3535
|
-
const r =
|
|
3554
|
+
const r = spawn6(taskkill, ["/PID", String(pid), "/T", "/F"], { windowsHide: true, stdio: "ignore", timeout: 15e3 });
|
|
3536
3555
|
return !r.error && r.status === 0;
|
|
3537
3556
|
}
|
|
3538
3557
|
try {
|
|
@@ -3734,6 +3753,46 @@ var init_claude_stream_event = __esm({
|
|
|
3734
3753
|
}
|
|
3735
3754
|
});
|
|
3736
3755
|
|
|
3756
|
+
// ../../scripts/virtual-office/code-runner/agent-auth-tier.mjs
|
|
3757
|
+
function authTierFromCostBasis(costBasis) {
|
|
3758
|
+
return COST_BASIS_TO_TIER[String(costBasis ?? "")] ?? AUTH_TIER_UNKNOWN;
|
|
3759
|
+
}
|
|
3760
|
+
function safeAuthTier(compute) {
|
|
3761
|
+
try {
|
|
3762
|
+
return normalizeAuthTier(compute());
|
|
3763
|
+
} catch {
|
|
3764
|
+
return AUTH_TIER_UNKNOWN;
|
|
3765
|
+
}
|
|
3766
|
+
}
|
|
3767
|
+
function normalizeAuthTier(value) {
|
|
3768
|
+
return AUTH_TIERS.includes(value) ? value : AUTH_TIER_UNKNOWN;
|
|
3769
|
+
}
|
|
3770
|
+
function resolveReportedAuthTier({ authTier, installed, authenticated } = {}) {
|
|
3771
|
+
if (installed !== true || authenticated !== true) return AUTH_TIER_UNKNOWN;
|
|
3772
|
+
return normalizeAuthTier(authTier);
|
|
3773
|
+
}
|
|
3774
|
+
var AUTH_TIER_SUBSCRIPTION, AUTH_TIER_API_KEY, AUTH_TIER_LOCAL, AUTH_TIER_UNKNOWN, AUTH_TIERS, COST_BASIS_TO_TIER;
|
|
3775
|
+
var init_agent_auth_tier = __esm({
|
|
3776
|
+
"../../scripts/virtual-office/code-runner/agent-auth-tier.mjs"() {
|
|
3777
|
+
"use strict";
|
|
3778
|
+
AUTH_TIER_SUBSCRIPTION = "subscription";
|
|
3779
|
+
AUTH_TIER_API_KEY = "api_key";
|
|
3780
|
+
AUTH_TIER_LOCAL = "local";
|
|
3781
|
+
AUTH_TIER_UNKNOWN = "unknown";
|
|
3782
|
+
AUTH_TIERS = Object.freeze([
|
|
3783
|
+
AUTH_TIER_SUBSCRIPTION,
|
|
3784
|
+
AUTH_TIER_API_KEY,
|
|
3785
|
+
AUTH_TIER_LOCAL,
|
|
3786
|
+
AUTH_TIER_UNKNOWN
|
|
3787
|
+
]);
|
|
3788
|
+
COST_BASIS_TO_TIER = Object.freeze({
|
|
3789
|
+
subscription_api_equivalent: AUTH_TIER_SUBSCRIPTION,
|
|
3790
|
+
vendor_billed: AUTH_TIER_API_KEY,
|
|
3791
|
+
local_zero: AUTH_TIER_LOCAL
|
|
3792
|
+
});
|
|
3793
|
+
}
|
|
3794
|
+
});
|
|
3795
|
+
|
|
3737
3796
|
// ../../scripts/virtual-office/code-runner/cli-version-floor.mjs
|
|
3738
3797
|
function parseCliVersion(output) {
|
|
3739
3798
|
const match = /\b(\d+)\.(\d+)\.(\d+)(?:-[0-9A-Za-z.-]+)?\b/.exec(String(output ?? ""));
|
|
@@ -3803,9 +3862,22 @@ function isTimeout(probe) {
|
|
|
3803
3862
|
function notFound(probe) {
|
|
3804
3863
|
return errorCode(probe?.error) === "ENOENT";
|
|
3805
3864
|
}
|
|
3865
|
+
function resolveClaudeAuthTier({
|
|
3866
|
+
env: env2 = process.env,
|
|
3867
|
+
loggedIn = null,
|
|
3868
|
+
getStoredKey = getAnthropicKey
|
|
3869
|
+
} = {}) {
|
|
3870
|
+
return safeAuthTier(() => {
|
|
3871
|
+
const spawnEnv = withAnthropicKey(env2, { getKey: getStoredKey, probeLogin: () => loggedIn });
|
|
3872
|
+
const tier = authTierFromCostBasis(claudeCostBasis(spawnEnv));
|
|
3873
|
+
if (tier === AUTH_TIER_SUBSCRIPTION && loggedIn !== true) return AUTH_TIER_UNKNOWN;
|
|
3874
|
+
return tier;
|
|
3875
|
+
});
|
|
3876
|
+
}
|
|
3806
3877
|
async function checkClaudeAuth({
|
|
3807
3878
|
spawnVersion = spawnClaudeSync,
|
|
3808
3879
|
probeLogin = probeClaudeLoginState,
|
|
3880
|
+
getStoredKey = getAnthropicKey,
|
|
3809
3881
|
env: env2 = process.env
|
|
3810
3882
|
} = {}) {
|
|
3811
3883
|
try {
|
|
@@ -3855,6 +3927,10 @@ async function checkClaudeAuth({
|
|
|
3855
3927
|
return {
|
|
3856
3928
|
installed: true,
|
|
3857
3929
|
authenticated: true,
|
|
3930
|
+
// Dispatch-time billing signal, carried on the same probe that already
|
|
3931
|
+
// paid for the login read. Never sent for a non-authenticated result:
|
|
3932
|
+
// there is no tier without a working credential.
|
|
3933
|
+
authTier: resolveClaudeAuthTier({ env: env2, loggedIn, getStoredKey }),
|
|
3858
3934
|
message: loggedIn === true ? "claude CLI installed and logged in (claude auth status)" : "claude binary found (login state unknown \u2014 auth check is best-effort)"
|
|
3859
3935
|
};
|
|
3860
3936
|
} catch (error) {
|
|
@@ -3870,6 +3946,7 @@ var init_claude_auth_check = __esm({
|
|
|
3870
3946
|
"../../scripts/virtual-office/code-runner/claude-auth-check.mjs"() {
|
|
3871
3947
|
"use strict";
|
|
3872
3948
|
init_anthropic_key_store();
|
|
3949
|
+
init_agent_auth_tier();
|
|
3873
3950
|
init_cli_version_floor();
|
|
3874
3951
|
init_windows_claude_launch();
|
|
3875
3952
|
FIRST_VERSION_TIMEOUT_MS = 4500;
|
|
@@ -4134,7 +4211,7 @@ var init_claude_runner = __esm({
|
|
|
4134
4211
|
return withAnthropicKey(env2);
|
|
4135
4212
|
}
|
|
4136
4213
|
costBasis(env2 = process.env) {
|
|
4137
|
-
return
|
|
4214
|
+
return claudeCostBasis(env2);
|
|
4138
4215
|
}
|
|
4139
4216
|
/** Describe which Anthropic auth source the spawn will use (for runner logs). */
|
|
4140
4217
|
describeAuth(env2 = process.env) {
|
|
@@ -4369,12 +4446,13 @@ var init_codex_runner = __esm({
|
|
|
4369
4446
|
"../../scripts/virtual-office/code-runner/codex-runner.mjs"() {
|
|
4370
4447
|
"use strict";
|
|
4371
4448
|
init_agent_key_store();
|
|
4449
|
+
init_agent_auth_tier();
|
|
4372
4450
|
init_flat_token_usage();
|
|
4373
4451
|
CODEX_PREFER_LOGIN_ENV = "VO_RUNNER_CODEX_PREFER_LOGIN";
|
|
4374
4452
|
LEGACY_PREFER_LOGIN_ENV = "VO_RUNNER_PREFER_LOGIN";
|
|
4375
4453
|
CodexRunner = class {
|
|
4376
|
-
constructor({ spawn:
|
|
4377
|
-
this.spawn =
|
|
4454
|
+
constructor({ spawn: spawn6 = spawnSync6, resolveBinary = resolveCodexBinary, env: env2 = process.env } = {}) {
|
|
4455
|
+
this.spawn = spawn6;
|
|
4378
4456
|
this.resolveBinary = resolveBinary;
|
|
4379
4457
|
this.env = env2;
|
|
4380
4458
|
}
|
|
@@ -4426,6 +4504,19 @@ var init_codex_runner = __esm({
|
|
|
4426
4504
|
costBasis(env2 = process.env) {
|
|
4427
4505
|
return String(env2.OPENAI_API_KEY || env2.CODEX_API_KEY || "").trim() ? "vendor_billed" : "subscription_api_equivalent";
|
|
4428
4506
|
}
|
|
4507
|
+
/**
|
|
4508
|
+
* Dispatch-time billing tier for the NEXT codex spawn, from the SAME facts
|
|
4509
|
+
* checkAuth() already gathered — no extra subprocess. applyAuthEnv() is a
|
|
4510
|
+
* keychain read in this process (@napi-rs/keyring), not a spawn.
|
|
4511
|
+
*
|
|
4512
|
+
* Codex is the agent where this signal was already computed and then thrown
|
|
4513
|
+
* away: checkAuth() distinguished "API key available (no persisted ChatGPT
|
|
4514
|
+
* login)" from a real login, but only inside a `message` string that the
|
|
4515
|
+
* heartbeat schema strips before storage. This gives that fact a typed home.
|
|
4516
|
+
*/
|
|
4517
|
+
authTier(env2 = this.env) {
|
|
4518
|
+
return safeAuthTier(() => authTierFromCostBasis(this.costBasis(this.applyAuthEnv(env2))));
|
|
4519
|
+
}
|
|
4429
4520
|
/** Best-effort binary + persisted-login probe. Never throws or spends tokens. */
|
|
4430
4521
|
async checkAuth() {
|
|
4431
4522
|
try {
|
|
@@ -4459,6 +4550,7 @@ ${login.stderr || ""}`.trim();
|
|
|
4459
4550
|
installed: true,
|
|
4460
4551
|
authenticated: true,
|
|
4461
4552
|
...versionField,
|
|
4553
|
+
authTier: this.authTier(),
|
|
4462
4554
|
message: "codex API key available (no persisted ChatGPT login)"
|
|
4463
4555
|
};
|
|
4464
4556
|
}
|
|
@@ -4473,6 +4565,7 @@ ${login.stderr || ""}`.trim();
|
|
|
4473
4565
|
installed: true,
|
|
4474
4566
|
authenticated: true,
|
|
4475
4567
|
...versionField,
|
|
4568
|
+
authTier: this.authTier(),
|
|
4476
4569
|
message: output || "codex login status succeeded"
|
|
4477
4570
|
};
|
|
4478
4571
|
} catch (err) {
|
|
@@ -4539,6 +4632,7 @@ var init_cursor_runner = __esm({
|
|
|
4539
4632
|
"../../scripts/virtual-office/code-runner/cursor-runner.mjs"() {
|
|
4540
4633
|
"use strict";
|
|
4541
4634
|
init_agent_key_store();
|
|
4635
|
+
init_agent_auth_tier();
|
|
4542
4636
|
init_flat_token_usage();
|
|
4543
4637
|
CursorRunner = class {
|
|
4544
4638
|
get binary() {
|
|
@@ -4583,6 +4677,16 @@ var init_cursor_runner = __esm({
|
|
|
4583
4677
|
costBasis(env2 = process.env) {
|
|
4584
4678
|
return env2.CURSOR_API_KEY ? "vendor_billed" : "unknown";
|
|
4585
4679
|
}
|
|
4680
|
+
/**
|
|
4681
|
+
* Dispatch-time billing tier. Inherits costBasis()'s deliberate refusal to
|
|
4682
|
+
* guess: a prior interactive `cursor-agent login` has undocumented
|
|
4683
|
+
* subscription semantics, so it reports 'unknown' rather than claiming a
|
|
4684
|
+
* flat-cost seat the runner cannot actually prove. Keychain read only — the
|
|
4685
|
+
* heartbeat never pays for a subprocess to answer this.
|
|
4686
|
+
*/
|
|
4687
|
+
authTier(env2 = process.env) {
|
|
4688
|
+
return safeAuthTier(() => authTierFromCostBasis(this.costBasis(this.applyAuthEnv(env2))));
|
|
4689
|
+
}
|
|
4586
4690
|
/** Best-effort: is `cursor-agent` on PATH? Never throws. */
|
|
4587
4691
|
async checkAuth() {
|
|
4588
4692
|
try {
|
|
@@ -4608,6 +4712,7 @@ var init_cursor_runner = __esm({
|
|
|
4608
4712
|
return {
|
|
4609
4713
|
installed: true,
|
|
4610
4714
|
authenticated: true,
|
|
4715
|
+
authTier: this.authTier(),
|
|
4611
4716
|
message: "cursor-agent found (EXPERIMENTAL: headless mode may need a TTY; auth check is best-effort)"
|
|
4612
4717
|
};
|
|
4613
4718
|
} catch (err) {
|
|
@@ -4704,6 +4809,7 @@ var init_local_model_runner = __esm({
|
|
|
4704
4809
|
"use strict";
|
|
4705
4810
|
init_codex_runner();
|
|
4706
4811
|
init_agent_key_store();
|
|
4812
|
+
init_agent_auth_tier();
|
|
4707
4813
|
LOCAL_API_KEY_ENV = "VO_CODE_RUNNER_LOCAL_API_KEY";
|
|
4708
4814
|
LOCAL_PROVIDERS = ["ollama", "lmstudio"];
|
|
4709
4815
|
DEFAULT_LOCAL_PROVIDER = "ollama";
|
|
@@ -4715,12 +4821,12 @@ var init_local_model_runner = __esm({
|
|
|
4715
4821
|
LOCAL_MODEL_RE = new RegExp("^[A-Za-z0-9][A-Za-z0-9._/:-]{0,127}$");
|
|
4716
4822
|
LocalModelRunner = class {
|
|
4717
4823
|
constructor({
|
|
4718
|
-
spawn:
|
|
4824
|
+
spawn: spawn6 = null,
|
|
4719
4825
|
resolveBinary = resolveCodexBinary,
|
|
4720
4826
|
env: env2 = process.env,
|
|
4721
4827
|
fetchImpl = globalThis.fetch
|
|
4722
4828
|
} = {}) {
|
|
4723
|
-
this.spawn =
|
|
4829
|
+
this.spawn = spawn6;
|
|
4724
4830
|
this.resolveBinary = resolveBinary;
|
|
4725
4831
|
this.env = env2;
|
|
4726
4832
|
this.fetchImpl = fetchImpl;
|
|
@@ -4756,6 +4862,10 @@ var init_local_model_runner = __esm({
|
|
|
4756
4862
|
costBasis() {
|
|
4757
4863
|
return "local_zero";
|
|
4758
4864
|
}
|
|
4865
|
+
/** Dispatch-time billing tier: local inference is never billed by a vendor. */
|
|
4866
|
+
authTier() {
|
|
4867
|
+
return safeAuthTier(() => authTierFromCostBasis(this.costBasis()));
|
|
4868
|
+
}
|
|
4759
4869
|
describeAuth(env2 = process.env) {
|
|
4760
4870
|
const authEnv = this.applyAuthEnv(env2);
|
|
4761
4871
|
const provider = resolveLocalProvider(this.env);
|
|
@@ -4813,6 +4923,7 @@ var init_local_model_runner = __esm({
|
|
|
4813
4923
|
return {
|
|
4814
4924
|
installed: true,
|
|
4815
4925
|
authenticated: true,
|
|
4926
|
+
authTier: this.authTier(),
|
|
4816
4927
|
message: `${provider} reachable; model "${model}" configured (local-only, no cloud spend)`
|
|
4817
4928
|
};
|
|
4818
4929
|
}
|
|
@@ -7080,11 +7191,18 @@ async function collectAgentAvailability({
|
|
|
7080
7191
|
new Promise((resolve2) => setTimeout(() => resolve2(null), probeTimeoutMs))
|
|
7081
7192
|
]);
|
|
7082
7193
|
if (!r) return degraded;
|
|
7194
|
+
const installed = Boolean(r?.installed);
|
|
7195
|
+
const authenticated = Boolean(r?.authenticated);
|
|
7196
|
+
const authTier = resolveReportedAuthTier({ authTier: r?.authTier, installed, authenticated });
|
|
7083
7197
|
return {
|
|
7084
7198
|
agent,
|
|
7085
|
-
installed
|
|
7086
|
-
authenticated
|
|
7087
|
-
...typeof r?.version === "string" && r.version ? { version: r.version } : {}
|
|
7199
|
+
installed,
|
|
7200
|
+
authenticated,
|
|
7201
|
+
...typeof r?.version === "string" && r.version ? { version: r.version } : {},
|
|
7202
|
+
// Omitted when unknown, which is what an older daemon's silence already
|
|
7203
|
+
// means — the control-plane schema resolves BOTH to 'unknown'. Never
|
|
7204
|
+
// invent a tier to fill the gap.
|
|
7205
|
+
...authTier !== AUTH_TIER_UNKNOWN ? { auth_tier: authTier } : {}
|
|
7088
7206
|
};
|
|
7089
7207
|
} catch {
|
|
7090
7208
|
return { agent, installed: false, authenticated: false };
|
|
@@ -7147,6 +7265,7 @@ var init_agent_availability = __esm({
|
|
|
7147
7265
|
"use strict";
|
|
7148
7266
|
init_resolve_runner();
|
|
7149
7267
|
init_agent_auth_probe_process();
|
|
7268
|
+
init_agent_auth_tier();
|
|
7150
7269
|
DEFAULT_TTL_MS = 5 * 60 * 1e3;
|
|
7151
7270
|
PROBE_TIMEOUT_MS = 1e4;
|
|
7152
7271
|
}
|
|
@@ -7273,26 +7392,183 @@ var init_local_model_remote_config = __esm({
|
|
|
7273
7392
|
}
|
|
7274
7393
|
});
|
|
7275
7394
|
|
|
7276
|
-
// ../../scripts/virtual-office/code-runner/account-usage.mjs
|
|
7277
|
-
import
|
|
7395
|
+
// ../../scripts/virtual-office/code-runner/account-usage/shared.mjs
|
|
7396
|
+
import crypto from "node:crypto";
|
|
7278
7397
|
import fs6 from "node:fs";
|
|
7398
|
+
function accountKey(agent, rawId) {
|
|
7399
|
+
const id = typeof rawId === "string" ? rawId.trim() : "";
|
|
7400
|
+
if (!id) return null;
|
|
7401
|
+
try {
|
|
7402
|
+
return crypto.scryptSync(`${agent}:${id}`, ACCOUNT_KEY_SALT, 8).toString("hex");
|
|
7403
|
+
} catch {
|
|
7404
|
+
return null;
|
|
7405
|
+
}
|
|
7406
|
+
}
|
|
7407
|
+
function makeUsageRow({
|
|
7408
|
+
agent,
|
|
7409
|
+
sevenDay,
|
|
7410
|
+
fiveHour,
|
|
7411
|
+
monthly,
|
|
7412
|
+
source,
|
|
7413
|
+
capturedAt,
|
|
7414
|
+
accountId,
|
|
7415
|
+
sevenDayResetsAt,
|
|
7416
|
+
fiveHourResetsAt,
|
|
7417
|
+
monthlyResetsAt
|
|
7418
|
+
}) {
|
|
7419
|
+
const seven = clampPct(sevenDay);
|
|
7420
|
+
const five = clampPct(fiveHour);
|
|
7421
|
+
const month = clampPct(monthly);
|
|
7422
|
+
if (seven === null && five === null && month === null) return null;
|
|
7423
|
+
const row = {
|
|
7424
|
+
agent,
|
|
7425
|
+
seven_day_used_pct: seven,
|
|
7426
|
+
five_hour_used_pct: five,
|
|
7427
|
+
source
|
|
7428
|
+
};
|
|
7429
|
+
if (month !== null) row.monthly_used_pct = month;
|
|
7430
|
+
if (typeof monthlyResetsAt === "string" && monthlyResetsAt) {
|
|
7431
|
+
row.monthly_resets_at = monthlyResetsAt;
|
|
7432
|
+
}
|
|
7433
|
+
if (typeof capturedAt === "string" && capturedAt) row.captured_at = capturedAt;
|
|
7434
|
+
const key = accountKey(agent, accountId);
|
|
7435
|
+
if (key) row.account_key = key;
|
|
7436
|
+
if (typeof sevenDayResetsAt === "string" && sevenDayResetsAt) {
|
|
7437
|
+
row.seven_day_resets_at = sevenDayResetsAt;
|
|
7438
|
+
}
|
|
7439
|
+
if (typeof fiveHourResetsAt === "string" && fiveHourResetsAt) {
|
|
7440
|
+
row.five_hour_resets_at = fiveHourResetsAt;
|
|
7441
|
+
}
|
|
7442
|
+
return row;
|
|
7443
|
+
}
|
|
7444
|
+
var clampPct, readJson, ACCOUNT_KEY_SALT;
|
|
7445
|
+
var init_shared = __esm({
|
|
7446
|
+
"../../scripts/virtual-office/code-runner/account-usage/shared.mjs"() {
|
|
7447
|
+
"use strict";
|
|
7448
|
+
clampPct = (v) => {
|
|
7449
|
+
const n = typeof v === "number" ? v : typeof v === "string" && v.trim() !== "" ? Number(v) : NaN;
|
|
7450
|
+
return Number.isFinite(n) ? Math.min(100, Math.max(0, Math.round(n))) : null;
|
|
7451
|
+
};
|
|
7452
|
+
readJson = (p) => {
|
|
7453
|
+
try {
|
|
7454
|
+
return JSON.parse(fs6.readFileSync(p, "utf8"));
|
|
7455
|
+
} catch {
|
|
7456
|
+
return null;
|
|
7457
|
+
}
|
|
7458
|
+
};
|
|
7459
|
+
ACCOUNT_KEY_SALT = "algohq/account-usage/v1";
|
|
7460
|
+
}
|
|
7461
|
+
});
|
|
7462
|
+
|
|
7463
|
+
// ../../scripts/virtual-office/code-runner/account-usage/claude.mjs
|
|
7279
7464
|
import os3 from "node:os";
|
|
7280
7465
|
import path14 from "node:path";
|
|
7281
|
-
function
|
|
7282
|
-
const
|
|
7283
|
-
|
|
7284
|
-
|
|
7285
|
-
|
|
7466
|
+
function usageBaseUrl(env2 = process.env) {
|
|
7467
|
+
const raw = env2.ANTHROPIC_BASE_URL || "https://api.anthropic.com";
|
|
7468
|
+
return String(raw).replace(/\/+$/, "");
|
|
7469
|
+
}
|
|
7470
|
+
function readOAuthToken({ homeDir = os3.homedir(), read = readJson, now = Date.now() } = {}) {
|
|
7471
|
+
const creds = read(path14.join(homeDir, ".claude", ".credentials.json"));
|
|
7472
|
+
const oauth = creds && typeof creds === "object" ? creds.claudeAiOauth : null;
|
|
7473
|
+
if (!oauth || typeof oauth !== "object") return null;
|
|
7474
|
+
const token2 = typeof oauth.accessToken === "string" ? oauth.accessToken.trim() : "";
|
|
7475
|
+
if (!token2) return null;
|
|
7476
|
+
const expiresAt = Number(oauth.expiresAt);
|
|
7477
|
+
if (Number.isFinite(expiresAt) && expiresAt > 0 && expiresAt <= now) return null;
|
|
7478
|
+
return token2;
|
|
7479
|
+
}
|
|
7480
|
+
function readAccountId({ homeDir = os3.homedir(), read = readJson } = {}) {
|
|
7481
|
+
const cfg = read(path14.join(homeDir, ".claude.json"));
|
|
7482
|
+
const account = cfg && typeof cfg === "object" ? cfg.oauthAccount : null;
|
|
7483
|
+
return account && typeof account.accountUuid === "string" ? account.accountUuid : null;
|
|
7484
|
+
}
|
|
7485
|
+
function entryPct(entry) {
|
|
7486
|
+
if (!entry || typeof entry !== "object") return null;
|
|
7487
|
+
for (const field of ["used_percentage", "utilization", "percent"]) {
|
|
7488
|
+
const pct = clampPct(entry[field]);
|
|
7489
|
+
if (pct !== null) return pct;
|
|
7286
7490
|
}
|
|
7287
|
-
|
|
7288
|
-
|
|
7491
|
+
return null;
|
|
7492
|
+
}
|
|
7493
|
+
function entryResetsAt(entry) {
|
|
7494
|
+
if (!entry || typeof entry !== "object") return null;
|
|
7495
|
+
for (const field of ["resets_at", "reset_at", "resetsAt"]) {
|
|
7496
|
+
const value = entry[field];
|
|
7497
|
+
if (typeof value === "string" && value) return value;
|
|
7498
|
+
if (typeof value === "number" && Number.isFinite(value) && value > 0) {
|
|
7499
|
+
return new Date(value * 1e3).toISOString();
|
|
7500
|
+
}
|
|
7501
|
+
}
|
|
7502
|
+
return null;
|
|
7503
|
+
}
|
|
7504
|
+
function parseOAuthUsage(body) {
|
|
7505
|
+
if (!body || typeof body !== "object") return null;
|
|
7506
|
+
let fiveHour = null;
|
|
7507
|
+
let sevenDay = null;
|
|
7508
|
+
const list = Array.isArray(body) ? body : Array.isArray(body.limits) ? body.limits : null;
|
|
7509
|
+
if (list) {
|
|
7510
|
+
for (const entry of list) {
|
|
7511
|
+
const kind = entry && typeof entry.kind === "string" ? entry.kind : "";
|
|
7512
|
+
if ((kind === "five_hour" || kind === "session") && !fiveHour) fiveHour = entry;
|
|
7513
|
+
else if ((kind === "seven_day" || kind === "weekly_all") && !sevenDay) sevenDay = entry;
|
|
7514
|
+
}
|
|
7515
|
+
}
|
|
7516
|
+
if (!fiveHour && body.five_hour) fiveHour = body.five_hour;
|
|
7517
|
+
if (!sevenDay && body.seven_day) sevenDay = body.seven_day;
|
|
7518
|
+
const five = entryPct(fiveHour);
|
|
7519
|
+
const seven = entryPct(sevenDay);
|
|
7520
|
+
if (five === null && seven === null) return null;
|
|
7521
|
+
return {
|
|
7522
|
+
five_hour_used_pct: five,
|
|
7523
|
+
seven_day_used_pct: seven,
|
|
7524
|
+
five_hour_resets_at: entryResetsAt(fiveHour),
|
|
7525
|
+
seven_day_resets_at: entryResetsAt(sevenDay)
|
|
7526
|
+
};
|
|
7289
7527
|
}
|
|
7290
|
-
function
|
|
7528
|
+
async function readClaudeOAuthUsage({
|
|
7529
|
+
fetchImpl = fetch,
|
|
7530
|
+
env: env2 = process.env,
|
|
7531
|
+
timeoutMs = DEFAULT_TIMEOUT_MS,
|
|
7291
7532
|
homeDir = os3.homedir(),
|
|
7292
|
-
read
|
|
7293
|
-
now = Date.now()
|
|
7294
|
-
mtimeMs = mtimeMsOf
|
|
7533
|
+
read = readJson,
|
|
7534
|
+
now = () => Date.now()
|
|
7295
7535
|
} = {}) {
|
|
7536
|
+
const token2 = readOAuthToken({ homeDir, read, now: now() });
|
|
7537
|
+
if (!token2) return null;
|
|
7538
|
+
const controller = new AbortController();
|
|
7539
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
7540
|
+
try {
|
|
7541
|
+
const res = await fetchImpl(`${usageBaseUrl(env2)}${USAGE_PATH}`, {
|
|
7542
|
+
method: "GET",
|
|
7543
|
+
headers: {
|
|
7544
|
+
authorization: `Bearer ${token2}`,
|
|
7545
|
+
"anthropic-beta": OAUTH_BETA,
|
|
7546
|
+
"content-type": "application/json",
|
|
7547
|
+
accept: "application/json"
|
|
7548
|
+
},
|
|
7549
|
+
signal: controller.signal
|
|
7550
|
+
});
|
|
7551
|
+
if (!res || !res.ok) return null;
|
|
7552
|
+
const parsed = parseOAuthUsage(await res.json());
|
|
7553
|
+
if (!parsed) return null;
|
|
7554
|
+
return makeUsageRow({
|
|
7555
|
+
agent: "claude",
|
|
7556
|
+
source: "oauth",
|
|
7557
|
+
// The response describes the account AS OF NOW, so the reading time is now.
|
|
7558
|
+
capturedAt: new Date(now()).toISOString(),
|
|
7559
|
+
accountId: readAccountId({ homeDir, read }),
|
|
7560
|
+
sevenDay: parsed.seven_day_used_pct,
|
|
7561
|
+
fiveHour: parsed.five_hour_used_pct,
|
|
7562
|
+
sevenDayResetsAt: parsed.seven_day_resets_at,
|
|
7563
|
+
fiveHourResetsAt: parsed.five_hour_resets_at
|
|
7564
|
+
});
|
|
7565
|
+
} catch {
|
|
7566
|
+
return null;
|
|
7567
|
+
} finally {
|
|
7568
|
+
clearTimeout(timer);
|
|
7569
|
+
}
|
|
7570
|
+
}
|
|
7571
|
+
function readClaudeFileUsage({ homeDir = os3.homedir(), read: rawRead = readJson } = {}) {
|
|
7296
7572
|
const read = (p) => {
|
|
7297
7573
|
try {
|
|
7298
7574
|
return rawRead(p);
|
|
@@ -7300,55 +7576,89 @@ function readClaudeUsage({
|
|
|
7300
7576
|
return null;
|
|
7301
7577
|
}
|
|
7302
7578
|
};
|
|
7303
|
-
const
|
|
7304
|
-
const status = read(
|
|
7305
|
-
if (status && (status.seven_day || status.five_hour)
|
|
7306
|
-
const
|
|
7579
|
+
const accountId = readAccountId({ homeDir, read });
|
|
7580
|
+
const status = read(path14.join(homeDir, ".claude", "claude-usage.json"));
|
|
7581
|
+
if (status && (status.seven_day || status.five_hour)) {
|
|
7582
|
+
const row = makeUsageRow({
|
|
7307
7583
|
agent: "claude",
|
|
7308
|
-
|
|
7309
|
-
|
|
7310
|
-
|
|
7311
|
-
|
|
7584
|
+
source: "statusline",
|
|
7585
|
+
capturedAt: typeof status.capturedAt === "string" ? status.capturedAt : null,
|
|
7586
|
+
accountId,
|
|
7587
|
+
sevenDay: status.seven_day?.used_percentage,
|
|
7588
|
+
fiveHour: status.five_hour?.used_percentage,
|
|
7589
|
+
sevenDayResetsAt: status.seven_day?.resets_at ?? null,
|
|
7590
|
+
fiveHourResetsAt: status.five_hour?.resets_at ?? null
|
|
7591
|
+
});
|
|
7592
|
+
if (row) return row;
|
|
7312
7593
|
}
|
|
7313
|
-
const
|
|
7314
|
-
|
|
7315
|
-
|
|
7316
|
-
const entry = {
|
|
7594
|
+
const weekly = read(path14.join(homeDir, ".claude", "claude-weekly-usage.json"));
|
|
7595
|
+
if (weekly) {
|
|
7596
|
+
const row = makeUsageRow({
|
|
7317
7597
|
agent: "claude",
|
|
7318
|
-
|
|
7319
|
-
|
|
7320
|
-
|
|
7321
|
-
|
|
7598
|
+
source: "file",
|
|
7599
|
+
capturedAt: typeof weekly.capturedAt === "string" ? weekly.capturedAt : null,
|
|
7600
|
+
accountId,
|
|
7601
|
+
sevenDay: weekly.sevenDayPct,
|
|
7602
|
+
fiveHour: weekly.fiveHourPct,
|
|
7603
|
+
sevenDayResetsAt: weekly.sevenDayResetsAt ?? null
|
|
7604
|
+
});
|
|
7605
|
+
if (row) return row;
|
|
7322
7606
|
}
|
|
7323
7607
|
return null;
|
|
7324
7608
|
}
|
|
7325
|
-
function
|
|
7326
|
-
|
|
7327
|
-
|
|
7609
|
+
async function readClaudeUsage(opts = {}) {
|
|
7610
|
+
try {
|
|
7611
|
+
const live = await readClaudeOAuthUsage(opts);
|
|
7612
|
+
if (live) return live;
|
|
7613
|
+
} catch {
|
|
7614
|
+
}
|
|
7615
|
+
return readClaudeFileUsage(opts);
|
|
7328
7616
|
}
|
|
7617
|
+
var USAGE_PATH, OAUTH_BETA, DEFAULT_TIMEOUT_MS;
|
|
7618
|
+
var init_claude = __esm({
|
|
7619
|
+
"../../scripts/virtual-office/code-runner/account-usage/claude.mjs"() {
|
|
7620
|
+
"use strict";
|
|
7621
|
+
init_shared();
|
|
7622
|
+
USAGE_PATH = "/api/oauth/usage";
|
|
7623
|
+
OAUTH_BETA = "oauth-2025-04-20";
|
|
7624
|
+
DEFAULT_TIMEOUT_MS = 5e3;
|
|
7625
|
+
}
|
|
7626
|
+
});
|
|
7627
|
+
|
|
7628
|
+
// ../../scripts/virtual-office/code-runner/account-usage/codex.mjs
|
|
7629
|
+
import { spawn as spawn4 } from "node:child_process";
|
|
7329
7630
|
function weeklyWindow(snapshot2) {
|
|
7330
7631
|
if (!snapshot2 || typeof snapshot2 !== "object") return null;
|
|
7331
7632
|
const windows = [snapshot2.primary, snapshot2.secondary].filter(Boolean);
|
|
7332
7633
|
return windows.find((window) => Number(window?.windowDurationMins) === 7 * 24 * 60) ?? windows.find((window) => Number(window?.windowDurationMins) >= 6 * 24 * 60) ?? null;
|
|
7333
7634
|
}
|
|
7334
|
-
function
|
|
7635
|
+
function resetsAtIso(window) {
|
|
7636
|
+
const raw = Number(window?.resetsAt);
|
|
7637
|
+
if (!Number.isFinite(raw) || raw <= 0) return null;
|
|
7638
|
+
return new Date(raw * 1e3).toISOString();
|
|
7639
|
+
}
|
|
7640
|
+
function parseCodexUsage(response, { now = () => Date.now() } = {}) {
|
|
7335
7641
|
const result = response?.result;
|
|
7336
7642
|
const snapshot2 = result?.rateLimitsByLimitId?.codex ?? result?.rateLimits;
|
|
7337
7643
|
const weekly = weeklyWindow(snapshot2);
|
|
7338
7644
|
const used = clampPct(weekly?.usedPercent);
|
|
7339
7645
|
if (used === null) return null;
|
|
7340
|
-
return {
|
|
7646
|
+
return makeUsageRow({
|
|
7341
7647
|
agent: "codex",
|
|
7342
|
-
|
|
7343
|
-
|
|
7344
|
-
|
|
7648
|
+
source: "app-server",
|
|
7649
|
+
capturedAt: new Date(now()).toISOString(),
|
|
7650
|
+
sevenDay: used,
|
|
7651
|
+
fiveHour: null,
|
|
7652
|
+
sevenDayResetsAt: resetsAtIso(weekly)
|
|
7653
|
+
});
|
|
7345
7654
|
}
|
|
7346
7655
|
function readCodexUsage({
|
|
7347
7656
|
spawnImpl = spawn4,
|
|
7348
7657
|
resolveBinary = resolveCodexBinary,
|
|
7349
7658
|
timeoutMs = 8e3,
|
|
7350
7659
|
env: env2 = process.env,
|
|
7351
|
-
platform = process.platform
|
|
7660
|
+
platform = process.platform,
|
|
7661
|
+
now = () => Date.now()
|
|
7352
7662
|
} = {}) {
|
|
7353
7663
|
return new Promise((resolve2) => {
|
|
7354
7664
|
let child;
|
|
@@ -7370,7 +7680,8 @@ function readCodexUsage({
|
|
|
7370
7680
|
child = spawnImpl(binary, ["app-server", "--stdio"], {
|
|
7371
7681
|
env: env2,
|
|
7372
7682
|
windowsHide: true,
|
|
7373
|
-
shell:
|
|
7683
|
+
shell: false,
|
|
7684
|
+
windowsVerbatimArguments: false,
|
|
7374
7685
|
stdio: ["pipe", "pipe", "ignore"]
|
|
7375
7686
|
});
|
|
7376
7687
|
child.on("error", () => finish(null));
|
|
@@ -7394,7 +7705,7 @@ function readCodexUsage({
|
|
|
7394
7705
|
child.stdin?.write(`${JSON.stringify({ method: "account/rateLimits/read", id: 2 })}
|
|
7395
7706
|
`);
|
|
7396
7707
|
} else if (message?.id === 2) {
|
|
7397
|
-
finish(parseCodexUsage(message));
|
|
7708
|
+
finish(parseCodexUsage(message, { now }));
|
|
7398
7709
|
}
|
|
7399
7710
|
}
|
|
7400
7711
|
});
|
|
@@ -7412,14 +7723,108 @@ function readCodexUsage({
|
|
|
7412
7723
|
}
|
|
7413
7724
|
});
|
|
7414
7725
|
}
|
|
7415
|
-
|
|
7416
|
-
|
|
7417
|
-
|
|
7418
|
-
|
|
7419
|
-
|
|
7420
|
-
}
|
|
7726
|
+
var init_codex = __esm({
|
|
7727
|
+
"../../scripts/virtual-office/code-runner/account-usage/codex.mjs"() {
|
|
7728
|
+
"use strict";
|
|
7729
|
+
init_shared();
|
|
7730
|
+
init_codex_runner();
|
|
7731
|
+
}
|
|
7732
|
+
});
|
|
7733
|
+
|
|
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";
|
|
7421
7808
|
}
|
|
7422
|
-
|
|
7809
|
+
});
|
|
7810
|
+
|
|
7811
|
+
// ../../scripts/virtual-office/code-runner/account-usage/index.mjs
|
|
7812
|
+
function collectAccountUsage(opts = {}) {
|
|
7813
|
+
const claude = readClaudeFileUsage(opts);
|
|
7814
|
+
return claude ? [claude] : [];
|
|
7815
|
+
}
|
|
7816
|
+
async function collectConnectedAccountUsage({
|
|
7817
|
+
readClaude = readClaudeUsage,
|
|
7818
|
+
readCodex = readCodexUsage,
|
|
7819
|
+
readCopilot = readCopilotUsage,
|
|
7820
|
+
...agentOptions
|
|
7821
|
+
} = {}) {
|
|
7822
|
+
const settled = await Promise.allSettled([
|
|
7823
|
+
readClaude(agentOptions),
|
|
7824
|
+
readCodex(agentOptions),
|
|
7825
|
+
readCopilot(agentOptions)
|
|
7826
|
+
]);
|
|
7827
|
+
return settled.map((outcome) => outcome.status === "fulfilled" ? outcome.value : null).filter(Boolean);
|
|
7423
7828
|
}
|
|
7424
7829
|
function makeAccountUsageProvider({
|
|
7425
7830
|
ttlMs = DEFAULT_TTL_MS2,
|
|
@@ -7447,35 +7852,33 @@ function makeAccountUsageProvider({
|
|
|
7447
7852
|
}
|
|
7448
7853
|
};
|
|
7449
7854
|
}
|
|
7450
|
-
var
|
|
7855
|
+
var AGENT_USAGE_CAPABILITY, DEFAULT_TTL_MS2;
|
|
7451
7856
|
var init_account_usage = __esm({
|
|
7452
|
-
"../../scripts/virtual-office/code-runner/account-usage.mjs"() {
|
|
7857
|
+
"../../scripts/virtual-office/code-runner/account-usage/index.mjs"() {
|
|
7453
7858
|
"use strict";
|
|
7454
|
-
|
|
7455
|
-
|
|
7456
|
-
|
|
7457
|
-
|
|
7458
|
-
|
|
7459
|
-
|
|
7460
|
-
|
|
7461
|
-
|
|
7462
|
-
|
|
7463
|
-
|
|
7464
|
-
|
|
7465
|
-
};
|
|
7466
|
-
STALE_AFTER_MS = 2 * 60 * 60 * 1e3;
|
|
7467
|
-
mtimeMsOf = (p) => {
|
|
7468
|
-
try {
|
|
7469
|
-
return fs6.statSync(p).mtimeMs;
|
|
7470
|
-
} catch {
|
|
7471
|
-
return null;
|
|
7472
|
-
}
|
|
7473
|
-
};
|
|
7474
|
-
isFresh = (ageMs) => ageMs !== null && ageMs <= STALE_AFTER_MS;
|
|
7859
|
+
init_claude();
|
|
7860
|
+
init_codex();
|
|
7861
|
+
init_copilot();
|
|
7862
|
+
init_shared();
|
|
7863
|
+
AGENT_USAGE_CAPABILITY = Object.freeze({
|
|
7864
|
+
claude: Object.freeze({ five_hour: true, seven_day: true, monthly: false }),
|
|
7865
|
+
codex: Object.freeze({ five_hour: false, seven_day: true, monthly: false }),
|
|
7866
|
+
copilot: Object.freeze({ five_hour: false, seven_day: false, monthly: true }),
|
|
7867
|
+
cursor: Object.freeze({ five_hour: false, seven_day: false, monthly: false }),
|
|
7868
|
+
gemini: Object.freeze({ five_hour: false, seven_day: false, monthly: false })
|
|
7869
|
+
});
|
|
7475
7870
|
DEFAULT_TTL_MS2 = 5 * 60 * 1e3;
|
|
7476
7871
|
}
|
|
7477
7872
|
});
|
|
7478
7873
|
|
|
7874
|
+
// ../../scripts/virtual-office/code-runner/account-usage.mjs
|
|
7875
|
+
var init_account_usage2 = __esm({
|
|
7876
|
+
"../../scripts/virtual-office/code-runner/account-usage.mjs"() {
|
|
7877
|
+
"use strict";
|
|
7878
|
+
init_account_usage();
|
|
7879
|
+
}
|
|
7880
|
+
});
|
|
7881
|
+
|
|
7479
7882
|
// ../../scripts/virtual-office/code-runner/ci-repair-evidence.mjs
|
|
7480
7883
|
function extractWorkflowRunIds(links = []) {
|
|
7481
7884
|
const ids = [];
|
|
@@ -8268,7 +8671,6 @@ function makeWatchRunner({
|
|
|
8268
8671
|
repairAttempt: chain.attempt + 1
|
|
8269
8672
|
}),
|
|
8270
8673
|
...operatorId && operatorId !== "admin" ? { on_behalf_of_operator_id: operatorId } : {},
|
|
8271
|
-
agent: "claude",
|
|
8272
8674
|
dispatch_mode: "fast",
|
|
8273
8675
|
max_turns: 80,
|
|
8274
8676
|
max_budget_usd: chain.per_attempt_budget_usd,
|
|
@@ -10180,7 +10582,15 @@ var init_agent_process_env = __esm({
|
|
|
10180
10582
|
"WINDIR",
|
|
10181
10583
|
"VO_RUNNER_PREFER_LOGIN",
|
|
10182
10584
|
"VO_RUNNER_CLAUDE_PREFER_LOGIN",
|
|
10183
|
-
"VO_RUNNER_CODEX_PREFER_LOGIN"
|
|
10585
|
+
"VO_RUNNER_CODEX_PREFER_LOGIN",
|
|
10586
|
+
// The tier-1 opt-out (PR #9242). Auth-preference flags are only visible to a
|
|
10587
|
+
// runner's applyAuthEnv() if they are listed HERE: the daemon builds the child
|
|
10588
|
+
// env with buildAgentProcessEnv(process.env) (code-runner-daemon.mjs:117), so
|
|
10589
|
+
// anything absent from this set is stripped before withAnthropicKey ever sees
|
|
10590
|
+
// it. #9242 added VO_RUNNER_PREFER_KEY without this line, which left the
|
|
10591
|
+
// escape hatch inert — an operator who set it still got the subscription.
|
|
10592
|
+
"VO_RUNNER_PREFER_KEY",
|
|
10593
|
+
"VO_RUNNER_CLAUDE_PREFER_KEY"
|
|
10184
10594
|
]);
|
|
10185
10595
|
}
|
|
10186
10596
|
});
|
|
@@ -12444,7 +12854,7 @@ var init_code_runner_daemon = __esm({
|
|
|
12444
12854
|
init_runner_capacity();
|
|
12445
12855
|
init_agent_availability();
|
|
12446
12856
|
init_local_model_remote_config();
|
|
12447
|
-
|
|
12857
|
+
init_account_usage2();
|
|
12448
12858
|
init_pr_watcher();
|
|
12449
12859
|
init_existing_pr_target();
|
|
12450
12860
|
init_watch_cycle_coordinator();
|