@algosuite/vo-mcp 0.2.0-beta.70 → 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 +206 -16
- package/dist/runner-cli.js +1169 -518
- package/dist/runner-cli.js.map +3 -3
- package/dist/runner-supervisor.js +39 -7
- package/dist/runner-supervisor.js.map +1 -1
- package/package.json +1 -1
|
@@ -300,15 +300,21 @@ function normalizeClaudePermissionMode(value) {
|
|
|
300
300
|
}
|
|
301
301
|
return normalized;
|
|
302
302
|
}
|
|
303
|
-
function buildClaudeArgs({ permissionMode = DEFAULT_PERMISSION_MODE, maxTurns, model, effort, maxBudgetUsd, researchHarness = false, 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
|
+
throw new Error(`unsupported Claude tool policy "${toolPolicy}"`);
|
|
307
|
+
}
|
|
308
|
+
const frozenInputsOnly = toolPolicy === "frozen_inputs_only";
|
|
309
|
+
const skillReadonly = toolPolicy === "skill_readonly";
|
|
310
|
+
const restrictedSkill = frozenInputsOnly || skillReadonly;
|
|
311
|
+
const noWeb = frozenInputsOnly || String(env?.VO_CODE_RUNNER_NO_WEB ?? "").trim() === "1";
|
|
306
312
|
const research = noWeb ? [] : VO_RESEARCH_TOOLS;
|
|
307
313
|
const noWorkflow = noWeb || String(env?.VO_CODE_RUNNER_NO_WORKFLOW ?? "").trim() === "1";
|
|
308
|
-
const workflow = researchHarness === true && !noWorkflow ? VO_WORKFLOW_TOOLS : [];
|
|
309
|
-
const noConsensus = String(env?.VO_CODE_RUNNER_NO_CONSENSUS ?? "").trim() === "1";
|
|
314
|
+
const workflow = !restrictedSkill && researchHarness === true && !noWorkflow ? VO_WORKFLOW_TOOLS : [];
|
|
315
|
+
const noConsensus = frozenInputsOnly || String(env?.VO_CODE_RUNNER_NO_CONSENSUS ?? "").trim() === "1";
|
|
310
316
|
const consensus = noConsensus ? [] : VO_CONSENSUS_TOOLS;
|
|
311
|
-
const baseTools = effectivePermissionMode === DEFAULT_PERMISSION_MODE ? [VO_SESSION_STATE_TOOL, VO_HEADLESS_PNPM_TOOL, VO_HEADLESS_PNPM_FROM_DIR_TOOL] : [VO_SESSION_STATE_TOOL];
|
|
317
|
+
const baseTools = restrictedSkill ? [] : effectivePermissionMode === DEFAULT_PERMISSION_MODE ? [VO_SESSION_STATE_TOOL, VO_HEADLESS_PNPM_TOOL, VO_HEADLESS_PNPM_FROM_DIR_TOOL] : [VO_SESSION_STATE_TOOL];
|
|
312
318
|
const allowedTools = [...baseTools, ...consensus, ...research, ...workflow].join(",");
|
|
313
319
|
const args = [
|
|
314
320
|
"-p",
|
|
@@ -320,6 +326,27 @@ function buildClaudeArgs({ permissionMode = DEFAULT_PERMISSION_MODE, maxTurns, m
|
|
|
320
326
|
"--allowedTools",
|
|
321
327
|
allowedTools
|
|
322
328
|
];
|
|
329
|
+
if (restrictedSkill) {
|
|
330
|
+
const builtInTools = skillReadonly ? research.join(",") : "";
|
|
331
|
+
args.push(
|
|
332
|
+
"--tools",
|
|
333
|
+
builtInTools,
|
|
334
|
+
"--disable-slash-commands",
|
|
335
|
+
"--no-chrome",
|
|
336
|
+
"--no-session-persistence",
|
|
337
|
+
"--permission-prompts",
|
|
338
|
+
"none"
|
|
339
|
+
);
|
|
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
|
+
}
|
|
347
|
+
if (frozenInputsOnly) {
|
|
348
|
+
args.push("--strict-mcp-config", "--safe-mode");
|
|
349
|
+
}
|
|
323
350
|
if (Number.isInteger(maxTurns) && maxTurns > 0) {
|
|
324
351
|
args.push("--max-turns", String(maxTurns));
|
|
325
352
|
}
|
|
@@ -332,7 +359,9 @@ function buildClaudeArgs({ permissionMode = DEFAULT_PERMISSION_MODE, maxTurns, m
|
|
|
332
359
|
if (typeof maxBudgetUsd === "number" && maxBudgetUsd > 0) {
|
|
333
360
|
args.push("--max-budget-usd", String(maxBudgetUsd));
|
|
334
361
|
}
|
|
335
|
-
|
|
362
|
+
if (!restrictedSkill) {
|
|
363
|
+
args.push(...context7McpArgs(env));
|
|
364
|
+
}
|
|
336
365
|
return args;
|
|
337
366
|
}
|
|
338
367
|
|
|
@@ -402,13 +431,15 @@ function extractModelUsage(evt) {
|
|
|
402
431
|
// ../../scripts/virtual-office/code-runner/claude-result-event.mjs
|
|
403
432
|
var CAPPED_RESULT_SUBTYPES = Object.freeze(["error_max_budget_usd", "error_max_turns"]);
|
|
404
433
|
function buildResultEvent(evt) {
|
|
405
|
-
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";
|
|
406
435
|
return {
|
|
407
436
|
kind: "result",
|
|
408
437
|
isError,
|
|
409
438
|
costUsd: typeof evt.total_cost_usd === "number" ? evt.total_cost_usd : null,
|
|
410
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,
|
|
411
441
|
numTurns: typeof evt.num_turns === "number" ? evt.num_turns : null,
|
|
442
|
+
structuredOutput: Object.hasOwn(evt, "structured_output") ? evt.structured_output : null,
|
|
412
443
|
tokenUsage: extractTokenUsage(evt),
|
|
413
444
|
modelUsage: extractModelUsage(evt)
|
|
414
445
|
};
|
|
@@ -521,9 +552,145 @@ function applyCliVersionFloor({ versionOutput, env = process.env, log = console.
|
|
|
521
552
|
return { refused: !allowUnsafe, check, message };
|
|
522
553
|
}
|
|
523
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
|
+
|
|
524
689
|
// ../../scripts/virtual-office/code-runner/claude-auth-check.mjs
|
|
525
690
|
var FIRST_VERSION_TIMEOUT_MS = 4500;
|
|
526
691
|
var RETRY_VERSION_TIMEOUT_MS = 2e3;
|
|
692
|
+
var AUTH_PROBE_BUDGET_MS = 9500;
|
|
693
|
+
var MIN_SKILL_PROBE_MS = 250;
|
|
527
694
|
function errorCode(error) {
|
|
528
695
|
return String(error?.code || "").toUpperCase();
|
|
529
696
|
}
|
|
@@ -549,9 +716,12 @@ async function checkClaudeAuth({
|
|
|
549
716
|
spawnVersion = spawnClaudeSync,
|
|
550
717
|
probeLogin = probeClaudeLoginState,
|
|
551
718
|
getStoredKey = getAnthropicKey,
|
|
552
|
-
|
|
719
|
+
probeSkillCapability = probeClaudeSkillCapability,
|
|
720
|
+
env = process.env,
|
|
721
|
+
now = () => Date.now()
|
|
553
722
|
} = {}) {
|
|
554
723
|
try {
|
|
724
|
+
const startedAt = now();
|
|
555
725
|
let probe = spawnVersion(["--version"], {
|
|
556
726
|
timeout: FIRST_VERSION_TIMEOUT_MS,
|
|
557
727
|
encoding: "utf8",
|
|
@@ -585,23 +755,40 @@ async function checkClaudeAuth({
|
|
|
585
755
|
}
|
|
586
756
|
const floorGate = applyCliVersionFloor({ versionOutput: probe.stdout, env });
|
|
587
757
|
if (floorGate.refused) {
|
|
588
|
-
return {
|
|
758
|
+
return {
|
|
759
|
+
installed: true,
|
|
760
|
+
authenticated: false,
|
|
761
|
+
version: floorGate.check.version ?? void 0,
|
|
762
|
+
skillCapable: false,
|
|
763
|
+
message: floorGate.message
|
|
764
|
+
};
|
|
589
765
|
}
|
|
590
766
|
const loggedIn = retriedAfterTimeout ? null : probeLogin();
|
|
591
767
|
if (loggedIn === false) {
|
|
592
768
|
return {
|
|
593
769
|
installed: true,
|
|
594
770
|
authenticated: false,
|
|
771
|
+
version: floorGate.check.version ?? void 0,
|
|
772
|
+
skillCapable: false,
|
|
595
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."
|
|
596
774
|
};
|
|
597
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 };
|
|
598
783
|
return {
|
|
599
784
|
installed: true,
|
|
600
785
|
authenticated: true,
|
|
786
|
+
version: floorGate.check.version ?? void 0,
|
|
787
|
+
skillCapable: skillCapability.compatible === true,
|
|
601
788
|
// Dispatch-time billing signal, carried on the same probe that already
|
|
602
789
|
// paid for the login read. Never sent for a non-authenticated result:
|
|
603
790
|
// there is no tier without a working credential.
|
|
604
|
-
authTier
|
|
791
|
+
authTier,
|
|
605
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)"
|
|
606
793
|
};
|
|
607
794
|
} catch (error) {
|
|
@@ -624,8 +811,8 @@ var ClaudeRunner = class {
|
|
|
624
811
|
get binary() {
|
|
625
812
|
return "claude";
|
|
626
813
|
}
|
|
627
|
-
buildArgs({ permissionMode, maxTurns, model, effort, maxBudgetUsd, researchHarness } = {}) {
|
|
628
|
-
return buildClaudeArgs({ permissionMode, maxTurns, model, effort, maxBudgetUsd, researchHarness });
|
|
814
|
+
buildArgs({ permissionMode, maxTurns, model, effort, maxBudgetUsd, researchHarness, toolPolicy, structuredOutputSchema } = {}) {
|
|
815
|
+
return buildClaudeArgs({ permissionMode, maxTurns, model, effort, maxBudgetUsd, researchHarness, toolPolicy, structuredOutputSchema });
|
|
629
816
|
}
|
|
630
817
|
parseEvent(line) {
|
|
631
818
|
return parseStreamEvent(line);
|
|
@@ -649,11 +836,14 @@ var ClaudeRunner = class {
|
|
|
649
836
|
async checkAuth() {
|
|
650
837
|
return checkClaudeAuth();
|
|
651
838
|
}
|
|
839
|
+
checkSkillCapability({ bin = this.binary, env = process.env } = {}) {
|
|
840
|
+
return probeClaudeSkillCapability({ bin, env, freshIdentity: true });
|
|
841
|
+
}
|
|
652
842
|
};
|
|
653
843
|
var claudeRunner = new ClaudeRunner();
|
|
654
844
|
|
|
655
845
|
// ../../scripts/virtual-office/code-runner/codex-runner.mjs
|
|
656
|
-
import { spawnSync as
|
|
846
|
+
import { spawnSync as spawnSync7 } from "node:child_process";
|
|
657
847
|
import { existsSync as existsSync3 } from "node:fs";
|
|
658
848
|
import { win32 } from "node:path";
|
|
659
849
|
|
|
@@ -905,7 +1095,7 @@ function parseCodexEvent(line) {
|
|
|
905
1095
|
return null;
|
|
906
1096
|
}
|
|
907
1097
|
var CodexRunner = class {
|
|
908
|
-
constructor({ spawn: spawn2 =
|
|
1098
|
+
constructor({ spawn: spawn2 = spawnSync7, resolveBinary = resolveCodexBinary, env = process.env } = {}) {
|
|
909
1099
|
this.spawn = spawn2;
|
|
910
1100
|
this.resolveBinary = resolveBinary;
|
|
911
1101
|
this.env = env;
|
|
@@ -1016,7 +1206,7 @@ ${login.stderr || ""}`.trim();
|
|
|
1016
1206
|
var codexRunner = new CodexRunner();
|
|
1017
1207
|
|
|
1018
1208
|
// ../../scripts/virtual-office/code-runner/cursor-runner.mjs
|
|
1019
|
-
import { spawnSync as
|
|
1209
|
+
import { spawnSync as spawnSync8 } from "node:child_process";
|
|
1020
1210
|
function buildCursorArgs({ model, prompt } = {}) {
|
|
1021
1211
|
const args = ["-p", "--output-format", "stream-json", "--force"];
|
|
1022
1212
|
if (model) {
|
|
@@ -1121,7 +1311,7 @@ var CursorRunner = class {
|
|
|
1121
1311
|
/** Best-effort: is `cursor-agent` on PATH? Never throws. */
|
|
1122
1312
|
async checkAuth() {
|
|
1123
1313
|
try {
|
|
1124
|
-
const { status, error } =
|
|
1314
|
+
const { status, error } = spawnSync8("cursor-agent", ["--version"], {
|
|
1125
1315
|
shell: false,
|
|
1126
1316
|
windowsHide: true,
|
|
1127
1317
|
timeout: 3e3,
|