@algosuite/vo-mcp 0.2.0-beta.71 → 0.2.0-beta.72
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 +178 -11
- package/dist/runner-cli.js +431 -162
- package/dist/runner-cli.js.map +3 -3
- package/package.json +1 -1
|
@@ -300,7 +300,7 @@ function normalizeClaudePermissionMode(value) {
|
|
|
300
300
|
}
|
|
301
301
|
return normalized;
|
|
302
302
|
}
|
|
303
|
-
function buildClaudeArgs({ permissionMode = DEFAULT_PERMISSION_MODE, maxTurns, model, effort, maxBudgetUsd, researchHarness = false, toolPolicy = "default", env = process.env } = {}) {
|
|
303
|
+
function buildClaudeArgs({ permissionMode = DEFAULT_PERMISSION_MODE, maxTurns, model, effort, maxBudgetUsd, researchHarness = false, toolPolicy = "default", structuredOutputSchema, env = process.env } = {}) {
|
|
304
304
|
const effectivePermissionMode = normalizeClaudePermissionMode(permissionMode);
|
|
305
305
|
if (!["default", "skill_readonly", "frozen_inputs_only"].includes(toolPolicy)) {
|
|
306
306
|
throw new Error(`unsupported Claude tool policy "${toolPolicy}"`);
|
|
@@ -338,6 +338,12 @@ function buildClaudeArgs({ permissionMode = DEFAULT_PERMISSION_MODE, maxTurns, m
|
|
|
338
338
|
"none"
|
|
339
339
|
);
|
|
340
340
|
}
|
|
341
|
+
if (structuredOutputSchema !== void 0) {
|
|
342
|
+
if (!restrictedSkill || !structuredOutputSchema || typeof structuredOutputSchema !== "object" || Array.isArray(structuredOutputSchema)) {
|
|
343
|
+
throw new Error("structured output schema is allowed only for a restricted skill");
|
|
344
|
+
}
|
|
345
|
+
args.push("--json-schema", JSON.stringify(structuredOutputSchema));
|
|
346
|
+
}
|
|
341
347
|
if (frozenInputsOnly) {
|
|
342
348
|
args.push("--strict-mcp-config", "--safe-mode");
|
|
343
349
|
}
|
|
@@ -425,13 +431,15 @@ function extractModelUsage(evt) {
|
|
|
425
431
|
// ../../scripts/virtual-office/code-runner/claude-result-event.mjs
|
|
426
432
|
var CAPPED_RESULT_SUBTYPES = Object.freeze(["error_max_budget_usd", "error_max_turns"]);
|
|
427
433
|
function buildResultEvent(evt) {
|
|
428
|
-
const isError = Boolean(evt.is_error) || evt.subtype === "error_max_turns" || evt.subtype === "error_during_execution";
|
|
434
|
+
const isError = Boolean(evt.is_error) || evt.subtype === "error_max_budget_usd" || evt.subtype === "error_max_turns" || evt.subtype === "error_max_structured_output_retries" || evt.subtype === "error_during_execution";
|
|
429
435
|
return {
|
|
430
436
|
kind: "result",
|
|
431
437
|
isError,
|
|
432
438
|
costUsd: typeof evt.total_cost_usd === "number" ? evt.total_cost_usd : null,
|
|
433
439
|
summary: typeof evt.result === "string" && evt.result.length > 0 ? evt.result : evt.subtype || (isError ? "error" : "completed"),
|
|
440
|
+
terminalSubtype: typeof evt.subtype === "string" ? evt.subtype : null,
|
|
434
441
|
numTurns: typeof evt.num_turns === "number" ? evt.num_turns : null,
|
|
442
|
+
structuredOutput: Object.hasOwn(evt, "structured_output") ? evt.structured_output : null,
|
|
435
443
|
tokenUsage: extractTokenUsage(evt),
|
|
436
444
|
modelUsage: extractModelUsage(evt)
|
|
437
445
|
};
|
|
@@ -544,9 +552,145 @@ function applyCliVersionFloor({ versionOutput, env = process.env, log = console.
|
|
|
544
552
|
return { refused: !allowUnsafe, check, message };
|
|
545
553
|
}
|
|
546
554
|
|
|
555
|
+
// ../../scripts/virtual-office/code-runner/claude-skill-capability.mjs
|
|
556
|
+
import { spawnSync as spawnSync6 } from "node:child_process";
|
|
557
|
+
import { accessSync, constants, realpathSync as realpathSync2, statSync } from "node:fs";
|
|
558
|
+
import path3 from "node:path";
|
|
559
|
+
var VALIDATED_CLAUDE_SKILL_VERSIONS = Object.freeze(["2.1.263"]);
|
|
560
|
+
var REQUIRED_CLAUDE_SKILL_HELP = Object.freeze([
|
|
561
|
+
"--allowedTools",
|
|
562
|
+
"--disable-slash-commands",
|
|
563
|
+
"--json-schema",
|
|
564
|
+
"--max-budget-usd",
|
|
565
|
+
"--no-chrome",
|
|
566
|
+
"--no-session-persistence",
|
|
567
|
+
"--output-format",
|
|
568
|
+
"--permission-mode",
|
|
569
|
+
"--permission-prompts",
|
|
570
|
+
"--safe-mode",
|
|
571
|
+
"--strict-mcp-config",
|
|
572
|
+
"--tools"
|
|
573
|
+
]);
|
|
574
|
+
var PROBE_TIMEOUT_MS = 2e3;
|
|
575
|
+
var CACHE_TTL_MS = 5 * 60 * 1e3;
|
|
576
|
+
var cache = /* @__PURE__ */ new Map();
|
|
577
|
+
function hasOption(help, option) {
|
|
578
|
+
const literal = option.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
|
|
579
|
+
return new RegExp(`(^|\\s)${literal}(?=\\s|,|=|<|$)`, "mu").test(help);
|
|
580
|
+
}
|
|
581
|
+
function assessClaudeSkillCapability({ versionOutput, helpOutput }) {
|
|
582
|
+
const version = parseCliVersion(versionOutput);
|
|
583
|
+
if (!version || !VALIDATED_CLAUDE_SKILL_VERSIONS.includes(version)) {
|
|
584
|
+
return { compatible: false, version, reason: "claude version is not in the validated restricted-skill manifest" };
|
|
585
|
+
}
|
|
586
|
+
const help = String(helpOutput ?? "");
|
|
587
|
+
const missing = REQUIRED_CLAUDE_SKILL_HELP.filter((option) => !hasOption(help, option));
|
|
588
|
+
if (missing.length > 0) {
|
|
589
|
+
return { compatible: false, version, reason: `claude help is missing required options: ${missing.join(", ")}` };
|
|
590
|
+
}
|
|
591
|
+
if (!/--permission-prompts[\s\S]{0,300}(?:"none"|\bnone\b)/mu.test(help) || !/--output-format[\s\S]{0,300}\bstream-json\b/mu.test(help)) {
|
|
592
|
+
return { compatible: false, version, reason: "claude help does not prove required none/stream-json values" };
|
|
593
|
+
}
|
|
594
|
+
return { compatible: true, version, reason: "validated restricted-skill CLI contract" };
|
|
595
|
+
}
|
|
596
|
+
function runProbe(bin, args, env, timeoutMs = PROBE_TIMEOUT_MS) {
|
|
597
|
+
if (process.platform === "win32") {
|
|
598
|
+
try {
|
|
599
|
+
const launch = buildWindowsClaudeLaunch({ bin, args, env });
|
|
600
|
+
return spawnSync6(launch.bin, launch.args, {
|
|
601
|
+
...launch.spawnOptions,
|
|
602
|
+
env,
|
|
603
|
+
encoding: "utf8",
|
|
604
|
+
timeout: timeoutMs
|
|
605
|
+
});
|
|
606
|
+
} catch (error) {
|
|
607
|
+
return { status: null, stdout: "", stderr: "", error };
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
return spawnSync6(bin, args, { env, encoding: "utf8", timeout: timeoutMs, windowsHide: true });
|
|
611
|
+
}
|
|
612
|
+
function probeText(probe) {
|
|
613
|
+
return `${String(probe?.stdout ?? "")}
|
|
614
|
+
${String(probe?.stderr ?? "")}`.trim();
|
|
615
|
+
}
|
|
616
|
+
function resolveClaudeBinaryIdentity(bin = "claude", env = process.env) {
|
|
617
|
+
let resolvedBin = String(bin);
|
|
618
|
+
try {
|
|
619
|
+
if (process.platform === "win32") {
|
|
620
|
+
resolvedBin = buildWindowsClaudeLaunch({ bin: resolvedBin, args: [], env }).bin;
|
|
621
|
+
} else if (!path3.isAbsolute(resolvedBin)) {
|
|
622
|
+
const found = String(env?.PATH ?? "").split(path3.delimiter).find((dir) => {
|
|
623
|
+
try {
|
|
624
|
+
accessSync(path3.join(dir, resolvedBin), constants.X_OK);
|
|
625
|
+
return true;
|
|
626
|
+
} catch {
|
|
627
|
+
return false;
|
|
628
|
+
}
|
|
629
|
+
});
|
|
630
|
+
if (found) resolvedBin = path3.join(found, resolvedBin);
|
|
631
|
+
}
|
|
632
|
+
const canonical = realpathSync2(resolvedBin);
|
|
633
|
+
const stat = statSync(canonical);
|
|
634
|
+
return { resolvedBin: canonical, fingerprint: `${canonical}\0${stat.size}\0${stat.mtimeMs}` };
|
|
635
|
+
} catch {
|
|
636
|
+
const pathValue2 = String(env?.PATH ?? env?.Path ?? "");
|
|
637
|
+
return { resolvedBin, fingerprint: `${resolvedBin}\0${pathValue2}` };
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
function probeClaudeSkillCapability({
|
|
641
|
+
bin = "claude",
|
|
642
|
+
env = process.env,
|
|
643
|
+
versionOutput,
|
|
644
|
+
spawnProbe = runProbe,
|
|
645
|
+
now = () => Date.now(),
|
|
646
|
+
cacheTtlMs = CACHE_TTL_MS,
|
|
647
|
+
timeoutMs = PROBE_TIMEOUT_MS,
|
|
648
|
+
freshIdentity = false,
|
|
649
|
+
resolveIdentity = resolveClaudeBinaryIdentity
|
|
650
|
+
} = {}) {
|
|
651
|
+
const identity = resolveIdentity(bin, env);
|
|
652
|
+
const key = identity.fingerprint;
|
|
653
|
+
const existing = cache.get(key);
|
|
654
|
+
if (!freshIdentity && versionOutput === void 0 && existing && now() - existing.at < cacheTtlMs) {
|
|
655
|
+
return existing.value;
|
|
656
|
+
}
|
|
657
|
+
const versionProbe = freshIdentity || versionOutput === void 0 ? spawnProbe(identity.resolvedBin, ["--version"], env, timeoutMs) : null;
|
|
658
|
+
if (versionProbe?.error || versionProbe && versionProbe.status !== 0) {
|
|
659
|
+
return {
|
|
660
|
+
compatible: false,
|
|
661
|
+
version: null,
|
|
662
|
+
resolvedBin: identity.resolvedBin,
|
|
663
|
+
reason: "claude version capability probe failed"
|
|
664
|
+
};
|
|
665
|
+
}
|
|
666
|
+
const effectiveVersionOutput = versionProbe ? probeText(versionProbe) : versionOutput;
|
|
667
|
+
const suppliedVersion = parseCliVersion(effectiveVersionOutput);
|
|
668
|
+
if (existing && now() - existing.at < cacheTtlMs && suppliedVersion === existing.value.version) {
|
|
669
|
+
return existing.value;
|
|
670
|
+
}
|
|
671
|
+
const helpProbe = spawnProbe(identity.resolvedBin, ["--help"], env, timeoutMs);
|
|
672
|
+
if (helpProbe?.error || helpProbe?.status !== 0) {
|
|
673
|
+
return {
|
|
674
|
+
compatible: false,
|
|
675
|
+
version: suppliedVersion,
|
|
676
|
+
resolvedBin: identity.resolvedBin,
|
|
677
|
+
reason: "claude help capability probe failed"
|
|
678
|
+
};
|
|
679
|
+
}
|
|
680
|
+
const assessed = assessClaudeSkillCapability({
|
|
681
|
+
versionOutput: effectiveVersionOutput,
|
|
682
|
+
helpOutput: probeText(helpProbe)
|
|
683
|
+
});
|
|
684
|
+
const value = { ...assessed, resolvedBin: identity.resolvedBin };
|
|
685
|
+
cache.set(key, { at: now(), value });
|
|
686
|
+
return value;
|
|
687
|
+
}
|
|
688
|
+
|
|
547
689
|
// ../../scripts/virtual-office/code-runner/claude-auth-check.mjs
|
|
548
690
|
var FIRST_VERSION_TIMEOUT_MS = 4500;
|
|
549
691
|
var RETRY_VERSION_TIMEOUT_MS = 2e3;
|
|
692
|
+
var AUTH_PROBE_BUDGET_MS = 9500;
|
|
693
|
+
var MIN_SKILL_PROBE_MS = 250;
|
|
550
694
|
function errorCode(error) {
|
|
551
695
|
return String(error?.code || "").toUpperCase();
|
|
552
696
|
}
|
|
@@ -572,9 +716,12 @@ async function checkClaudeAuth({
|
|
|
572
716
|
spawnVersion = spawnClaudeSync,
|
|
573
717
|
probeLogin = probeClaudeLoginState,
|
|
574
718
|
getStoredKey = getAnthropicKey,
|
|
575
|
-
|
|
719
|
+
probeSkillCapability = probeClaudeSkillCapability,
|
|
720
|
+
env = process.env,
|
|
721
|
+
now = () => Date.now()
|
|
576
722
|
} = {}) {
|
|
577
723
|
try {
|
|
724
|
+
const startedAt = now();
|
|
578
725
|
let probe = spawnVersion(["--version"], {
|
|
579
726
|
timeout: FIRST_VERSION_TIMEOUT_MS,
|
|
580
727
|
encoding: "utf8",
|
|
@@ -608,23 +755,40 @@ async function checkClaudeAuth({
|
|
|
608
755
|
}
|
|
609
756
|
const floorGate = applyCliVersionFloor({ versionOutput: probe.stdout, env });
|
|
610
757
|
if (floorGate.refused) {
|
|
611
|
-
return {
|
|
758
|
+
return {
|
|
759
|
+
installed: true,
|
|
760
|
+
authenticated: false,
|
|
761
|
+
version: floorGate.check.version ?? void 0,
|
|
762
|
+
skillCapable: false,
|
|
763
|
+
message: floorGate.message
|
|
764
|
+
};
|
|
612
765
|
}
|
|
613
766
|
const loggedIn = retriedAfterTimeout ? null : probeLogin();
|
|
614
767
|
if (loggedIn === false) {
|
|
615
768
|
return {
|
|
616
769
|
installed: true,
|
|
617
770
|
authenticated: false,
|
|
771
|
+
version: floorGate.check.version ?? void 0,
|
|
772
|
+
skillCapable: false,
|
|
618
773
|
message: "claude CLI is installed but NOT logged in \u2014 its login is SEPARATE from the Claude Desktop app and the Claude Code IDE extension. Run: claude auth login (Claude subscription), then restart the runner."
|
|
619
774
|
};
|
|
620
775
|
}
|
|
776
|
+
const authTier = resolveClaudeAuthTier({ env, loggedIn, getStoredKey });
|
|
777
|
+
const remainingMs = AUTH_PROBE_BUDGET_MS - (now() - startedAt);
|
|
778
|
+
const skillCapability = loggedIn === true && remainingMs >= MIN_SKILL_PROBE_MS ? probeSkillCapability({
|
|
779
|
+
versionOutput: probe.stdout,
|
|
780
|
+
env,
|
|
781
|
+
timeoutMs: Math.min(2e3, remainingMs)
|
|
782
|
+
}) : { compatible: false };
|
|
621
783
|
return {
|
|
622
784
|
installed: true,
|
|
623
785
|
authenticated: true,
|
|
786
|
+
version: floorGate.check.version ?? void 0,
|
|
787
|
+
skillCapable: skillCapability.compatible === true,
|
|
624
788
|
// Dispatch-time billing signal, carried on the same probe that already
|
|
625
789
|
// paid for the login read. Never sent for a non-authenticated result:
|
|
626
790
|
// there is no tier without a working credential.
|
|
627
|
-
authTier
|
|
791
|
+
authTier,
|
|
628
792
|
message: loggedIn === true ? "claude CLI installed and logged in (claude auth status)" : "claude binary found (login state unknown \u2014 auth check is best-effort)"
|
|
629
793
|
};
|
|
630
794
|
} catch (error) {
|
|
@@ -647,8 +811,8 @@ var ClaudeRunner = class {
|
|
|
647
811
|
get binary() {
|
|
648
812
|
return "claude";
|
|
649
813
|
}
|
|
650
|
-
buildArgs({ permissionMode, maxTurns, model, effort, maxBudgetUsd, researchHarness, toolPolicy } = {}) {
|
|
651
|
-
return buildClaudeArgs({ permissionMode, maxTurns, model, effort, maxBudgetUsd, researchHarness, toolPolicy });
|
|
814
|
+
buildArgs({ permissionMode, maxTurns, model, effort, maxBudgetUsd, researchHarness, toolPolicy, structuredOutputSchema } = {}) {
|
|
815
|
+
return buildClaudeArgs({ permissionMode, maxTurns, model, effort, maxBudgetUsd, researchHarness, toolPolicy, structuredOutputSchema });
|
|
652
816
|
}
|
|
653
817
|
parseEvent(line) {
|
|
654
818
|
return parseStreamEvent(line);
|
|
@@ -672,11 +836,14 @@ var ClaudeRunner = class {
|
|
|
672
836
|
async checkAuth() {
|
|
673
837
|
return checkClaudeAuth();
|
|
674
838
|
}
|
|
839
|
+
checkSkillCapability({ bin = this.binary, env = process.env } = {}) {
|
|
840
|
+
return probeClaudeSkillCapability({ bin, env, freshIdentity: true });
|
|
841
|
+
}
|
|
675
842
|
};
|
|
676
843
|
var claudeRunner = new ClaudeRunner();
|
|
677
844
|
|
|
678
845
|
// ../../scripts/virtual-office/code-runner/codex-runner.mjs
|
|
679
|
-
import { spawnSync as
|
|
846
|
+
import { spawnSync as spawnSync7 } from "node:child_process";
|
|
680
847
|
import { existsSync as existsSync3 } from "node:fs";
|
|
681
848
|
import { win32 } from "node:path";
|
|
682
849
|
|
|
@@ -928,7 +1095,7 @@ function parseCodexEvent(line) {
|
|
|
928
1095
|
return null;
|
|
929
1096
|
}
|
|
930
1097
|
var CodexRunner = class {
|
|
931
|
-
constructor({ spawn: spawn2 =
|
|
1098
|
+
constructor({ spawn: spawn2 = spawnSync7, resolveBinary = resolveCodexBinary, env = process.env } = {}) {
|
|
932
1099
|
this.spawn = spawn2;
|
|
933
1100
|
this.resolveBinary = resolveBinary;
|
|
934
1101
|
this.env = env;
|
|
@@ -1039,7 +1206,7 @@ ${login.stderr || ""}`.trim();
|
|
|
1039
1206
|
var codexRunner = new CodexRunner();
|
|
1040
1207
|
|
|
1041
1208
|
// ../../scripts/virtual-office/code-runner/cursor-runner.mjs
|
|
1042
|
-
import { spawnSync as
|
|
1209
|
+
import { spawnSync as spawnSync8 } from "node:child_process";
|
|
1043
1210
|
function buildCursorArgs({ model, prompt } = {}) {
|
|
1044
1211
|
const args = ["-p", "--output-format", "stream-json", "--force"];
|
|
1045
1212
|
if (model) {
|
|
@@ -1144,7 +1311,7 @@ var CursorRunner = class {
|
|
|
1144
1311
|
/** Best-effort: is `cursor-agent` on PATH? Never throws. */
|
|
1145
1312
|
async checkAuth() {
|
|
1146
1313
|
try {
|
|
1147
|
-
const { status, error } =
|
|
1314
|
+
const { status, error } = spawnSync8("cursor-agent", ["--version"], {
|
|
1148
1315
|
shell: false,
|
|
1149
1316
|
windowsHide: true,
|
|
1150
1317
|
timeout: 3e3,
|