@algosuite/vo-mcp 0.2.0-beta.26 → 0.2.0-beta.28
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 +111 -12
- package/dist/runner-cli.js +420 -89
- 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
|
@@ -177,27 +177,48 @@ function getAnthropicKey({ EntryCtor = defaultEntryCtor() } = {}) {
|
|
|
177
177
|
}
|
|
178
178
|
var PREFER_LOGIN_ENV = "VO_RUNNER_PREFER_LOGIN";
|
|
179
179
|
var CLAUDE_PREFER_LOGIN_ENV = "VO_RUNNER_CLAUDE_PREFER_LOGIN";
|
|
180
|
+
var PREFER_KEY_ENV = "VO_RUNNER_PREFER_KEY";
|
|
181
|
+
var CLAUDE_PREFER_KEY_ENV = "VO_RUNNER_CLAUDE_PREFER_KEY";
|
|
180
182
|
function isTruthyFlag(v) {
|
|
181
183
|
const s = String(v ?? "").trim().toLowerCase();
|
|
182
184
|
return s === "1" || s === "true" || s === "yes" || s === "on";
|
|
183
185
|
}
|
|
184
|
-
function
|
|
185
|
-
|
|
186
|
+
function wantsLogin(env) {
|
|
187
|
+
return isTruthyFlag(env[CLAUDE_PREFER_LOGIN_ENV]) || isTruthyFlag(env[PREFER_LOGIN_ENV]);
|
|
188
|
+
}
|
|
189
|
+
function wantsKey(env) {
|
|
190
|
+
return isTruthyFlag(env[CLAUDE_PREFER_KEY_ENV]) || isTruthyFlag(env[PREFER_KEY_ENV]);
|
|
191
|
+
}
|
|
192
|
+
function withAnthropicKey(baseEnv = {}, { getKey = getAnthropicKey, probeLogin = probeClaudeLoginState } = {}) {
|
|
193
|
+
const preferKey = wantsKey(baseEnv);
|
|
194
|
+
if (!preferKey && wantsLogin(baseEnv)) {
|
|
186
195
|
const next = { ...baseEnv };
|
|
187
196
|
delete next.ANTHROPIC_API_KEY;
|
|
188
197
|
return next;
|
|
189
198
|
}
|
|
190
199
|
if (baseEnv.ANTHROPIC_API_KEY) return { ...baseEnv };
|
|
191
200
|
const key = getKey();
|
|
192
|
-
|
|
201
|
+
if (!key) return { ...baseEnv };
|
|
202
|
+
if (!preferKey && probeLogin() === true) return { ...baseEnv };
|
|
203
|
+
return { ...baseEnv, ANTHROPIC_API_KEY: key };
|
|
204
|
+
}
|
|
205
|
+
function claudeCostBasis(env = process.env) {
|
|
206
|
+
return String(env.ANTHROPIC_API_KEY || "").trim() ? "vendor_billed" : "subscription_api_equivalent";
|
|
193
207
|
}
|
|
194
|
-
function describeAnthropicAuthSource(baseEnv = {}, { getKey = getAnthropicKey } = {}) {
|
|
195
|
-
|
|
208
|
+
function describeAnthropicAuthSource(baseEnv = {}, { getKey = getAnthropicKey, probeLogin = probeClaudeLoginState } = {}) {
|
|
209
|
+
const preferKey = wantsKey(baseEnv);
|
|
210
|
+
if (!preferKey && wantsLogin(baseEnv)) {
|
|
196
211
|
return "claude auth login (VO_RUNNER_PREFER_LOGIN set \u2014 any API key ignored)";
|
|
197
212
|
}
|
|
198
213
|
if (baseEnv.ANTHROPIC_API_KEY) return "ANTHROPIC_API_KEY from environment";
|
|
199
|
-
if (getKey()) return "
|
|
200
|
-
|
|
214
|
+
if (!getKey()) return "claude auth login session (no API key set)";
|
|
215
|
+
if (preferKey) {
|
|
216
|
+
return "ANTHROPIC_API_KEY from OS keychain (VO_RUNNER_PREFER_KEY set \u2014 subscription ignored)";
|
|
217
|
+
}
|
|
218
|
+
if (probeLogin() === true) {
|
|
219
|
+
return "claude auth login session (subscription beats the stored keychain key)";
|
|
220
|
+
}
|
|
221
|
+
return "ANTHROPIC_API_KEY from OS keychain";
|
|
201
222
|
}
|
|
202
223
|
function probeClaudeLoginState({
|
|
203
224
|
spawn: spawn2 = spawnSync2,
|
|
@@ -375,6 +396,36 @@ function parseClaudeStreamEvent(line) {
|
|
|
375
396
|
return event.type === "result" ? buildResultEvent(event) : null;
|
|
376
397
|
}
|
|
377
398
|
|
|
399
|
+
// ../../scripts/virtual-office/code-runner/agent-auth-tier.mjs
|
|
400
|
+
var AUTH_TIER_SUBSCRIPTION = "subscription";
|
|
401
|
+
var AUTH_TIER_API_KEY = "api_key";
|
|
402
|
+
var AUTH_TIER_LOCAL = "local";
|
|
403
|
+
var AUTH_TIER_UNKNOWN = "unknown";
|
|
404
|
+
var AUTH_TIERS = Object.freeze([
|
|
405
|
+
AUTH_TIER_SUBSCRIPTION,
|
|
406
|
+
AUTH_TIER_API_KEY,
|
|
407
|
+
AUTH_TIER_LOCAL,
|
|
408
|
+
AUTH_TIER_UNKNOWN
|
|
409
|
+
]);
|
|
410
|
+
var COST_BASIS_TO_TIER = Object.freeze({
|
|
411
|
+
subscription_api_equivalent: AUTH_TIER_SUBSCRIPTION,
|
|
412
|
+
vendor_billed: AUTH_TIER_API_KEY,
|
|
413
|
+
local_zero: AUTH_TIER_LOCAL
|
|
414
|
+
});
|
|
415
|
+
function authTierFromCostBasis(costBasis) {
|
|
416
|
+
return COST_BASIS_TO_TIER[String(costBasis ?? "")] ?? AUTH_TIER_UNKNOWN;
|
|
417
|
+
}
|
|
418
|
+
function safeAuthTier(compute) {
|
|
419
|
+
try {
|
|
420
|
+
return normalizeAuthTier(compute());
|
|
421
|
+
} catch {
|
|
422
|
+
return AUTH_TIER_UNKNOWN;
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
function normalizeAuthTier(value) {
|
|
426
|
+
return AUTH_TIERS.includes(value) ? value : AUTH_TIER_UNKNOWN;
|
|
427
|
+
}
|
|
428
|
+
|
|
378
429
|
// ../../scripts/virtual-office/code-runner/cli-version-floor.mjs
|
|
379
430
|
var MIN_CLAUDE_CLI_VERSION = "2.1.218";
|
|
380
431
|
var SECURITY_RATIONALE = "Claude Code 2.1.211/2.1.213 fixed a PreToolUse-hook bypass on unsandboxed Bash (our destructive-fs/git/cloud tripwires DO NOT FIRE on older CLIs) and worktree-subagents mutating the main checkout. 2.1.218 fixed Windows paths with a lowercase-\\u segment (e.g. ...\\utils\\, ...\\ui\\) being corrupted into CJK in tool inputs, making those files silently inaccessible \u2014 the fleet is Windows and 1,376 tracked files sit under utils/ alone. Update: npm install -g @anthropic-ai/claude-code (or the native installer).";
|
|
@@ -440,9 +491,22 @@ function isTimeout(probe) {
|
|
|
440
491
|
function notFound(probe) {
|
|
441
492
|
return errorCode(probe?.error) === "ENOENT";
|
|
442
493
|
}
|
|
494
|
+
function resolveClaudeAuthTier({
|
|
495
|
+
env = process.env,
|
|
496
|
+
loggedIn = null,
|
|
497
|
+
getStoredKey = getAnthropicKey
|
|
498
|
+
} = {}) {
|
|
499
|
+
return safeAuthTier(() => {
|
|
500
|
+
const spawnEnv = withAnthropicKey(env, { getKey: getStoredKey, probeLogin: () => loggedIn });
|
|
501
|
+
const tier = authTierFromCostBasis(claudeCostBasis(spawnEnv));
|
|
502
|
+
if (tier === AUTH_TIER_SUBSCRIPTION && loggedIn !== true) return AUTH_TIER_UNKNOWN;
|
|
503
|
+
return tier;
|
|
504
|
+
});
|
|
505
|
+
}
|
|
443
506
|
async function checkClaudeAuth({
|
|
444
507
|
spawnVersion = spawnClaudeSync,
|
|
445
508
|
probeLogin = probeClaudeLoginState,
|
|
509
|
+
getStoredKey = getAnthropicKey,
|
|
446
510
|
env = process.env
|
|
447
511
|
} = {}) {
|
|
448
512
|
try {
|
|
@@ -492,6 +556,10 @@ async function checkClaudeAuth({
|
|
|
492
556
|
return {
|
|
493
557
|
installed: true,
|
|
494
558
|
authenticated: true,
|
|
559
|
+
// Dispatch-time billing signal, carried on the same probe that already
|
|
560
|
+
// paid for the login read. Never sent for a non-authenticated result:
|
|
561
|
+
// there is no tier without a working credential.
|
|
562
|
+
authTier: resolveClaudeAuthTier({ env, loggedIn, getStoredKey }),
|
|
495
563
|
message: loggedIn === true ? "claude CLI installed and logged in (claude auth status)" : "claude binary found (login state unknown \u2014 auth check is best-effort)"
|
|
496
564
|
};
|
|
497
565
|
} catch (error) {
|
|
@@ -536,7 +604,7 @@ var ClaudeRunner = class {
|
|
|
536
604
|
return withAnthropicKey(env);
|
|
537
605
|
}
|
|
538
606
|
costBasis(env = process.env) {
|
|
539
|
-
return
|
|
607
|
+
return claudeCostBasis(env);
|
|
540
608
|
}
|
|
541
609
|
/** Describe which Anthropic auth source the spawn will use (for runner logs). */
|
|
542
610
|
describeAuth(env = process.env) {
|
|
@@ -811,6 +879,19 @@ var CodexRunner = class {
|
|
|
811
879
|
costBasis(env = process.env) {
|
|
812
880
|
return String(env.OPENAI_API_KEY || env.CODEX_API_KEY || "").trim() ? "vendor_billed" : "subscription_api_equivalent";
|
|
813
881
|
}
|
|
882
|
+
/**
|
|
883
|
+
* Dispatch-time billing tier for the NEXT codex spawn, from the SAME facts
|
|
884
|
+
* checkAuth() already gathered — no extra subprocess. applyAuthEnv() is a
|
|
885
|
+
* keychain read in this process (@napi-rs/keyring), not a spawn.
|
|
886
|
+
*
|
|
887
|
+
* Codex is the agent where this signal was already computed and then thrown
|
|
888
|
+
* away: checkAuth() distinguished "API key available (no persisted ChatGPT
|
|
889
|
+
* login)" from a real login, but only inside a `message` string that the
|
|
890
|
+
* heartbeat schema strips before storage. This gives that fact a typed home.
|
|
891
|
+
*/
|
|
892
|
+
authTier(env = this.env) {
|
|
893
|
+
return safeAuthTier(() => authTierFromCostBasis(this.costBasis(this.applyAuthEnv(env))));
|
|
894
|
+
}
|
|
814
895
|
/** Best-effort binary + persisted-login probe. Never throws or spends tokens. */
|
|
815
896
|
async checkAuth() {
|
|
816
897
|
try {
|
|
@@ -844,6 +925,7 @@ ${login.stderr || ""}`.trim();
|
|
|
844
925
|
installed: true,
|
|
845
926
|
authenticated: true,
|
|
846
927
|
...versionField,
|
|
928
|
+
authTier: this.authTier(),
|
|
847
929
|
message: "codex API key available (no persisted ChatGPT login)"
|
|
848
930
|
};
|
|
849
931
|
}
|
|
@@ -858,6 +940,7 @@ ${login.stderr || ""}`.trim();
|
|
|
858
940
|
installed: true,
|
|
859
941
|
authenticated: true,
|
|
860
942
|
...versionField,
|
|
943
|
+
authTier: this.authTier(),
|
|
861
944
|
message: output || "codex login status succeeded"
|
|
862
945
|
};
|
|
863
946
|
} catch (err) {
|
|
@@ -960,6 +1043,16 @@ var CursorRunner = class {
|
|
|
960
1043
|
costBasis(env = process.env) {
|
|
961
1044
|
return env.CURSOR_API_KEY ? "vendor_billed" : "unknown";
|
|
962
1045
|
}
|
|
1046
|
+
/**
|
|
1047
|
+
* Dispatch-time billing tier. Inherits costBasis()'s deliberate refusal to
|
|
1048
|
+
* guess: a prior interactive `cursor-agent login` has undocumented
|
|
1049
|
+
* subscription semantics, so it reports 'unknown' rather than claiming a
|
|
1050
|
+
* flat-cost seat the runner cannot actually prove. Keychain read only — the
|
|
1051
|
+
* heartbeat never pays for a subprocess to answer this.
|
|
1052
|
+
*/
|
|
1053
|
+
authTier(env = process.env) {
|
|
1054
|
+
return safeAuthTier(() => authTierFromCostBasis(this.costBasis(this.applyAuthEnv(env))));
|
|
1055
|
+
}
|
|
963
1056
|
/** Best-effort: is `cursor-agent` on PATH? Never throws. */
|
|
964
1057
|
async checkAuth() {
|
|
965
1058
|
try {
|
|
@@ -985,6 +1078,7 @@ var CursorRunner = class {
|
|
|
985
1078
|
return {
|
|
986
1079
|
installed: true,
|
|
987
1080
|
authenticated: true,
|
|
1081
|
+
authTier: this.authTier(),
|
|
988
1082
|
message: "cursor-agent found (EXPERIMENTAL: headless mode may need a TTY; auth check is best-effort)"
|
|
989
1083
|
};
|
|
990
1084
|
} catch (err) {
|
|
@@ -1121,6 +1215,10 @@ var LocalModelRunner = class {
|
|
|
1121
1215
|
costBasis() {
|
|
1122
1216
|
return "local_zero";
|
|
1123
1217
|
}
|
|
1218
|
+
/** Dispatch-time billing tier: local inference is never billed by a vendor. */
|
|
1219
|
+
authTier() {
|
|
1220
|
+
return safeAuthTier(() => authTierFromCostBasis(this.costBasis()));
|
|
1221
|
+
}
|
|
1124
1222
|
describeAuth(env = process.env) {
|
|
1125
1223
|
const authEnv = this.applyAuthEnv(env);
|
|
1126
1224
|
const provider = resolveLocalProvider(this.env);
|
|
@@ -1178,6 +1276,7 @@ var LocalModelRunner = class {
|
|
|
1178
1276
|
return {
|
|
1179
1277
|
installed: true,
|
|
1180
1278
|
authenticated: true,
|
|
1279
|
+
authTier: this.authTier(),
|
|
1181
1280
|
message: `${provider} reachable; model "${model}" configured (local-only, no cloud spend)`
|
|
1182
1281
|
};
|
|
1183
1282
|
}
|
|
@@ -1250,7 +1349,7 @@ var OpenAICompatibleRunner = class {
|
|
|
1250
1349
|
buildArgs(opts = {}) {
|
|
1251
1350
|
void opts;
|
|
1252
1351
|
throw new Error(
|
|
1253
|
-
"OpenAI-compatible full-repository coding is disabled. Use an explicit sanitized task capsule through the AlgoSuite Model Firewall."
|
|
1352
|
+
"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."
|
|
1254
1353
|
);
|
|
1255
1354
|
}
|
|
1256
1355
|
/** Codex JSONL events map identically → reuse the proven parser. */
|
|
@@ -1273,14 +1372,14 @@ var OpenAICompatibleRunner = class {
|
|
|
1273
1372
|
describeAuth(env = process.env) {
|
|
1274
1373
|
const hasKey = Boolean(String(env[OAI_API_KEY_ENV] || "").trim());
|
|
1275
1374
|
const baseUrl = resolveOaiBaseUrl(env);
|
|
1276
|
-
return `oai-compat endpoint=${baseUrl || "<unset>"} key=${hasKey ? "set" : "MISSING"}`;
|
|
1375
|
+
return `oai-compat RETIRED endpoint=${baseUrl || "<unset>"} key=${hasKey ? "set" : "MISSING"}`;
|
|
1277
1376
|
}
|
|
1278
|
-
/**
|
|
1377
|
+
/** Always unavailable: the lane is retired, so nothing can authenticate it. */
|
|
1279
1378
|
async checkAuth() {
|
|
1280
1379
|
return {
|
|
1281
1380
|
installed: false,
|
|
1282
1381
|
authenticated: false,
|
|
1283
|
-
message: "OpenAI-compatible coding is disabled
|
|
1382
|
+
message: "the `oai` lane is RETIRED (PR #8742); OpenAI-compatible coding is disabled \u2014 sanitized Model Firewall task capsules only"
|
|
1284
1383
|
};
|
|
1285
1384
|
}
|
|
1286
1385
|
};
|