@algosuite/vo-mcp 0.2.0-beta.17 → 0.2.0-beta.19
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/autostart-cli.js +25 -12
- package/dist/autostart-cli.js.map +2 -2
- package/dist/cli.js +253 -31
- package/dist/cli.js.map +4 -4
- package/dist/index.js +241 -17
- package/dist/index.js.map +4 -4
- package/dist/install-cli.js +15 -6
- package/dist/install-cli.js.map +2 -2
- package/dist/login-cli.js +1 -1
- package/dist/login-cli.js.map +2 -2
- package/dist/runner-cli.js +605 -137
- package/dist/runner-cli.js.map +4 -4
- package/dist/runner-supervisor.js +41 -8
- package/dist/runner-supervisor.js.map +2 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2064,7 +2064,11 @@ async function handleConsensusJudgment(deps, rawInput, signal) {
|
|
|
2064
2064
|
...engineResult.low_confidence_sources !== void 0 ? { low_confidence_sources: engineResult.low_confidence_sources } : {},
|
|
2065
2065
|
// Escalation (from citation grade or human-tiebreak synthesizer).
|
|
2066
2066
|
...engineResult.escalation_required !== void 0 ? { escalation_required: engineResult.escalation_required } : {},
|
|
2067
|
-
...engineResult.escalation_reason !== void 0 ? { escalation_reason: engineResult.escalation_reason } : {}
|
|
2067
|
+
...engineResult.escalation_reason !== void 0 ? { escalation_reason: engineResult.escalation_reason } : {},
|
|
2068
|
+
// Critique-uptake (2026-07-20 red-team fix) — the engine computes this
|
|
2069
|
+
// on every call; this spread closes the gap where the visibility report
|
|
2070
|
+
// was itself silently dropped at the payload boundary.
|
|
2071
|
+
...engineResult.critique_uptake !== void 0 ? { critique_uptake: engineResult.critique_uptake } : {}
|
|
2068
2072
|
};
|
|
2069
2073
|
const envelope = {
|
|
2070
2074
|
tool: TOOL_NAME4,
|
|
@@ -5397,6 +5401,195 @@ async function handleHqWhiteboardRead(_deps, rawInput, signal) {
|
|
|
5397
5401
|
return jsonContent(await callWhiteboard("GET", input, signal));
|
|
5398
5402
|
}
|
|
5399
5403
|
|
|
5404
|
+
// src/tools/skills/skill-corpus.ts
|
|
5405
|
+
import { existsSync as existsSync6, statSync as statSync5 } from "node:fs";
|
|
5406
|
+
import { dirname as dirname5, isAbsolute, join as join9, resolve as resolve2 } from "node:path";
|
|
5407
|
+
|
|
5408
|
+
// ../skill-registry/src/loader.ts
|
|
5409
|
+
import { readdirSync as readdirSync5, readFileSync as readFileSync8, statSync as statSync4 } from "node:fs";
|
|
5410
|
+
import { join as join8 } from "node:path";
|
|
5411
|
+
var InvalidSkillFrontmatterError = class extends Error {
|
|
5412
|
+
constructor(skillFile, reason) {
|
|
5413
|
+
super(`Invalid frontmatter in ${skillFile}: ${reason}`);
|
|
5414
|
+
this.skillFile = skillFile;
|
|
5415
|
+
this.reason = reason;
|
|
5416
|
+
}
|
|
5417
|
+
skillFile;
|
|
5418
|
+
reason;
|
|
5419
|
+
name = "InvalidSkillFrontmatterError";
|
|
5420
|
+
};
|
|
5421
|
+
var FRONTMATTER_DELIMITER = "---";
|
|
5422
|
+
function parseFrontmatter(rawInput, sourcePath) {
|
|
5423
|
+
const raw = rawInput.replace(/\r\n/g, "\n");
|
|
5424
|
+
if (!raw.startsWith(`${FRONTMATTER_DELIMITER}
|
|
5425
|
+
`)) {
|
|
5426
|
+
throw new InvalidSkillFrontmatterError(sourcePath, 'file does not start with frontmatter delimiter "---"');
|
|
5427
|
+
}
|
|
5428
|
+
const afterFirst = raw.slice(FRONTMATTER_DELIMITER.length + 1);
|
|
5429
|
+
const closingIdx = afterFirst.indexOf(`
|
|
5430
|
+
${FRONTMATTER_DELIMITER}
|
|
5431
|
+
`);
|
|
5432
|
+
if (closingIdx === -1) {
|
|
5433
|
+
throw new InvalidSkillFrontmatterError(sourcePath, 'missing closing frontmatter delimiter "---"');
|
|
5434
|
+
}
|
|
5435
|
+
const frontmatterText = afterFirst.slice(0, closingIdx);
|
|
5436
|
+
const body = afterFirst.slice(closingIdx + `
|
|
5437
|
+
${FRONTMATTER_DELIMITER}
|
|
5438
|
+
`.length);
|
|
5439
|
+
let name = "";
|
|
5440
|
+
let description23 = "";
|
|
5441
|
+
for (const line of frontmatterText.split("\n")) {
|
|
5442
|
+
const trimmed = line.trim();
|
|
5443
|
+
if (trimmed.length === 0) continue;
|
|
5444
|
+
const colonIdx = trimmed.indexOf(":");
|
|
5445
|
+
if (colonIdx === -1) continue;
|
|
5446
|
+
const key = trimmed.slice(0, colonIdx).trim();
|
|
5447
|
+
const value = trimmed.slice(colonIdx + 1).trim();
|
|
5448
|
+
if (key === "name") name = value;
|
|
5449
|
+
else if (key === "description") description23 = value;
|
|
5450
|
+
}
|
|
5451
|
+
if (name.length === 0) {
|
|
5452
|
+
throw new InvalidSkillFrontmatterError(sourcePath, 'missing required field "name"');
|
|
5453
|
+
}
|
|
5454
|
+
if (description23.length === 0) {
|
|
5455
|
+
throw new InvalidSkillFrontmatterError(sourcePath, 'missing required field "description"');
|
|
5456
|
+
}
|
|
5457
|
+
return { name, description: description23, body };
|
|
5458
|
+
}
|
|
5459
|
+
function loadSkillsFromDir(skillsDir) {
|
|
5460
|
+
const entries = readdirSync5(skillsDir);
|
|
5461
|
+
const skills = [];
|
|
5462
|
+
for (const entry of entries) {
|
|
5463
|
+
const entryPath = join8(skillsDir, entry);
|
|
5464
|
+
let stat;
|
|
5465
|
+
try {
|
|
5466
|
+
stat = statSync4(entryPath);
|
|
5467
|
+
} catch {
|
|
5468
|
+
continue;
|
|
5469
|
+
}
|
|
5470
|
+
if (!stat.isDirectory()) continue;
|
|
5471
|
+
const skillFile = join8(entryPath, "SKILL.md");
|
|
5472
|
+
let raw;
|
|
5473
|
+
try {
|
|
5474
|
+
raw = readFileSync8(skillFile, "utf8");
|
|
5475
|
+
} catch {
|
|
5476
|
+
continue;
|
|
5477
|
+
}
|
|
5478
|
+
const { name, description: description23, body } = parseFrontmatter(raw, skillFile);
|
|
5479
|
+
skills.push({ name, description: description23, body, sourcePath: skillFile });
|
|
5480
|
+
}
|
|
5481
|
+
return [...skills].sort((a, b) => a.name.localeCompare(b.name));
|
|
5482
|
+
}
|
|
5483
|
+
|
|
5484
|
+
// src/tools/skills/skill-corpus.ts
|
|
5485
|
+
var LIST_TOOL_NAME = "vo_skill_list";
|
|
5486
|
+
var GET_TOOL_NAME = "vo_skill_get";
|
|
5487
|
+
var listDescription = "List the Algosuite skill corpus (name + trigger description for every skill). Call once near session start to learn which skills exist; then fetch the full instructions for a relevant skill with vo_skill_get. This is the same corpus Claude Code loads natively from .claude/skills \u2014 served over MCP so every vendor works from identical playbooks. Pass refresh:true to re-scan from disk.";
|
|
5488
|
+
var getDescription = "Fetch the full markdown instructions of one Algosuite skill by name. Follow the returned instructions for the current task the same way a native skill invocation would. Use vo_skill_list to discover skill names.";
|
|
5489
|
+
var listInputSchema = {
|
|
5490
|
+
type: "object",
|
|
5491
|
+
properties: {
|
|
5492
|
+
refresh: {
|
|
5493
|
+
type: "boolean",
|
|
5494
|
+
description: "Re-scan the skills directory instead of using the cached corpus."
|
|
5495
|
+
}
|
|
5496
|
+
},
|
|
5497
|
+
required: []
|
|
5498
|
+
};
|
|
5499
|
+
var getInputSchema = {
|
|
5500
|
+
type: "object",
|
|
5501
|
+
properties: {
|
|
5502
|
+
name: {
|
|
5503
|
+
type: "string",
|
|
5504
|
+
description: "Skill name exactly as returned by vo_skill_list."
|
|
5505
|
+
}
|
|
5506
|
+
},
|
|
5507
|
+
required: ["name"]
|
|
5508
|
+
};
|
|
5509
|
+
var MAX_WALK_UP_LEVELS = 8;
|
|
5510
|
+
var cachedCorpus = null;
|
|
5511
|
+
function resolveSkillsDir(env = process.env, startDir = process.cwd()) {
|
|
5512
|
+
const override = env.VO_SKILLS_DIR;
|
|
5513
|
+
if (typeof override === "string" && override.length > 0) {
|
|
5514
|
+
const abs = isAbsolute(override) ? override : resolve2(startDir, override);
|
|
5515
|
+
return existsSync6(abs) && statSync5(abs).isDirectory() ? abs : null;
|
|
5516
|
+
}
|
|
5517
|
+
let dir = resolve2(startDir);
|
|
5518
|
+
for (let i = 0; i < MAX_WALK_UP_LEVELS; i += 1) {
|
|
5519
|
+
const candidate = join9(dir, ".claude", "skills");
|
|
5520
|
+
if (existsSync6(candidate) && statSync5(candidate).isDirectory()) return candidate;
|
|
5521
|
+
const parent = dirname5(dir);
|
|
5522
|
+
if (parent === dir) break;
|
|
5523
|
+
dir = parent;
|
|
5524
|
+
}
|
|
5525
|
+
return null;
|
|
5526
|
+
}
|
|
5527
|
+
function loadCorpus() {
|
|
5528
|
+
const skillsDir = resolveSkillsDir();
|
|
5529
|
+
if (skillsDir === null) {
|
|
5530
|
+
return {
|
|
5531
|
+
skills: [],
|
|
5532
|
+
skillsDir: null,
|
|
5533
|
+
unavailableReason: "No skills directory found. Set VO_SKILLS_DIR or run inside a repo with .claude/skills."
|
|
5534
|
+
};
|
|
5535
|
+
}
|
|
5536
|
+
try {
|
|
5537
|
+
return { skills: loadSkillsFromDir(skillsDir), skillsDir, unavailableReason: null };
|
|
5538
|
+
} catch (err) {
|
|
5539
|
+
const message = err instanceof Error ? `${err.name}: ${err.message}` : String(err);
|
|
5540
|
+
return { skills: [], skillsDir, unavailableReason: message };
|
|
5541
|
+
}
|
|
5542
|
+
}
|
|
5543
|
+
function getCorpus(refresh) {
|
|
5544
|
+
if (refresh || cachedCorpus === null) {
|
|
5545
|
+
cachedCorpus = loadCorpus();
|
|
5546
|
+
}
|
|
5547
|
+
return cachedCorpus;
|
|
5548
|
+
}
|
|
5549
|
+
async function handleSkillList(_deps, rawInput) {
|
|
5550
|
+
const input = rawInput ?? {};
|
|
5551
|
+
const refresh = input.refresh === true;
|
|
5552
|
+
const corpus = getCorpus(refresh);
|
|
5553
|
+
return jsonContent({
|
|
5554
|
+
corpus_available: corpus.unavailableReason === null,
|
|
5555
|
+
skills_dir: corpus.skillsDir,
|
|
5556
|
+
unavailable_reason: corpus.unavailableReason,
|
|
5557
|
+
skill_count: corpus.skills.length,
|
|
5558
|
+
skills: corpus.skills.map((s) => ({ name: s.name, description: s.description }))
|
|
5559
|
+
});
|
|
5560
|
+
}
|
|
5561
|
+
async function handleSkillGet(_deps, rawInput) {
|
|
5562
|
+
const input = rawInput ?? {};
|
|
5563
|
+
if (typeof input.name !== "string" || input.name.trim().length === 0) {
|
|
5564
|
+
throw invalidParams(GET_TOOL_NAME, 'input field "name" (non-empty string) is required');
|
|
5565
|
+
}
|
|
5566
|
+
const requested = input.name.trim();
|
|
5567
|
+
const corpus = getCorpus(false);
|
|
5568
|
+
if (corpus.unavailableReason !== null) {
|
|
5569
|
+
return jsonContent({
|
|
5570
|
+
corpus_available: false,
|
|
5571
|
+
unavailable_reason: corpus.unavailableReason,
|
|
5572
|
+
skill: null
|
|
5573
|
+
});
|
|
5574
|
+
}
|
|
5575
|
+
const skill = corpus.skills.find((s) => s.name === requested);
|
|
5576
|
+
if (skill === void 0) {
|
|
5577
|
+
throw invalidParams(
|
|
5578
|
+
GET_TOOL_NAME,
|
|
5579
|
+
`unknown skill "${requested}". Known skills: ${corpus.skills.map((s) => s.name).join(", ")}`
|
|
5580
|
+
);
|
|
5581
|
+
}
|
|
5582
|
+
return jsonContent({
|
|
5583
|
+
corpus_available: true,
|
|
5584
|
+
skill: {
|
|
5585
|
+
name: skill.name,
|
|
5586
|
+
description: skill.description,
|
|
5587
|
+
instructions: skill.body,
|
|
5588
|
+
source_path: skill.sourcePath
|
|
5589
|
+
}
|
|
5590
|
+
});
|
|
5591
|
+
}
|
|
5592
|
+
|
|
5400
5593
|
// src/server.ts
|
|
5401
5594
|
function buildToolRegistry() {
|
|
5402
5595
|
return {
|
|
@@ -5607,6 +5800,22 @@ function buildToolRegistry() {
|
|
|
5607
5800
|
inputSchema: readInputSchema
|
|
5608
5801
|
},
|
|
5609
5802
|
handler: handleHqWhiteboardRead
|
|
5803
|
+
},
|
|
5804
|
+
[LIST_TOOL_NAME]: {
|
|
5805
|
+
definition: {
|
|
5806
|
+
name: LIST_TOOL_NAME,
|
|
5807
|
+
description: listDescription,
|
|
5808
|
+
inputSchema: listInputSchema
|
|
5809
|
+
},
|
|
5810
|
+
handler: handleSkillList
|
|
5811
|
+
},
|
|
5812
|
+
[GET_TOOL_NAME]: {
|
|
5813
|
+
definition: {
|
|
5814
|
+
name: GET_TOOL_NAME,
|
|
5815
|
+
description: getDescription,
|
|
5816
|
+
inputSchema: getInputSchema
|
|
5817
|
+
},
|
|
5818
|
+
handler: handleSkillGet
|
|
5610
5819
|
}
|
|
5611
5820
|
};
|
|
5612
5821
|
}
|
|
@@ -5665,7 +5874,7 @@ function listToolNames() {
|
|
|
5665
5874
|
// src/cache/sqlite-cache.ts
|
|
5666
5875
|
import { createHash as createHash3 } from "node:crypto";
|
|
5667
5876
|
import { chmodSync as chmodSync3, mkdirSync as mkdirSync5 } from "node:fs";
|
|
5668
|
-
import { dirname as
|
|
5877
|
+
import { dirname as dirname6 } from "node:path";
|
|
5669
5878
|
import { DatabaseSync } from "node:sqlite";
|
|
5670
5879
|
|
|
5671
5880
|
// src/cache/canonicalize.ts
|
|
@@ -5710,7 +5919,7 @@ function normalizeString(s) {
|
|
|
5710
5919
|
function createSqliteCache(options) {
|
|
5711
5920
|
const fileBacked = options.dbPath !== ":memory:";
|
|
5712
5921
|
if (fileBacked) {
|
|
5713
|
-
mkdirSync5(
|
|
5922
|
+
mkdirSync5(dirname6(options.dbPath), { recursive: true, mode: 448 });
|
|
5714
5923
|
}
|
|
5715
5924
|
const versionNamespace = options.cacheVersionNamespace ?? "";
|
|
5716
5925
|
const db = new DatabaseSync(options.dbPath);
|
|
@@ -5910,6 +6119,30 @@ function createMetaModelCaller(options = {}) {
|
|
|
5910
6119
|
}
|
|
5911
6120
|
var callMetaWithMetrics = createMetaModelCaller();
|
|
5912
6121
|
|
|
6122
|
+
// src/consensus/consensus-panel.ts
|
|
6123
|
+
var VO_MCP_CONSENSUS_PANEL = {
|
|
6124
|
+
anthropic: "claude-opus-4-7",
|
|
6125
|
+
openai: "gpt-5",
|
|
6126
|
+
// gemini-2.5-FLASH (not -pro): flash accepts the default thinkingBudget=0 from
|
|
6127
|
+
// callGeminiWithMetrics; 2.5-pro REJECTS budget 0 ("only works in thinking mode").
|
|
6128
|
+
// Flash is also ~10x cheaper. 2026-06-02.
|
|
6129
|
+
google: "gemini-2.5-flash",
|
|
6130
|
+
deepseek: "deepseek-chat",
|
|
6131
|
+
// Muse Spark identity is owned by meta-model-caller.ts (single source of
|
|
6132
|
+
// truth for the meta slot); re-exported here so the panel stays complete.
|
|
6133
|
+
meta: META_CONSENSUS_MODEL
|
|
6134
|
+
};
|
|
6135
|
+
function getVoMcpConsensusPanel(panel = VO_MCP_CONSENSUS_PANEL) {
|
|
6136
|
+
for (const [provider, modelId] of Object.entries(panel)) {
|
|
6137
|
+
if (typeof modelId !== "string" || modelId.trim().length === 0) {
|
|
6138
|
+
throw new Error(
|
|
6139
|
+
`getVoMcpConsensusPanel: panel slot "${provider}" has a missing or blank model ID`
|
|
6140
|
+
);
|
|
6141
|
+
}
|
|
6142
|
+
}
|
|
6143
|
+
return panel;
|
|
6144
|
+
}
|
|
6145
|
+
|
|
5913
6146
|
// src/consensus/engine-options.ts
|
|
5914
6147
|
var AGREEMENT_GATE_ENV_VAR = "VO_CONSENSUS_AGREEMENT_GATE";
|
|
5915
6148
|
function isTruthyFlag(raw) {
|
|
@@ -6178,6 +6411,10 @@ function createEngineConsensusClient(options) {
|
|
|
6178
6411
|
...mapFanOutDiagnostics(response.fan_out_diagnostics) !== void 0 ? { fan_out_diagnostics: mapFanOutDiagnostics(response.fan_out_diagnostics) } : {},
|
|
6179
6412
|
// Stage A7-shadow — adaptive-vs-incumbent comparison (PII-free; present iff shadow on).
|
|
6180
6413
|
...mapShadowSynthesis(response.shadow_synthesis) !== void 0 ? { shadow_synthesis: mapShadowSynthesis(response.shadow_synthesis) } : {},
|
|
6414
|
+
// Critique-uptake (2026-07-20 red-team fix) — verifier-critique
|
|
6415
|
+
// visibility report; previously computed by the engine on every
|
|
6416
|
+
// call but dropped at this boundary.
|
|
6417
|
+
...response.critique_uptake !== void 0 ? { critique_uptake: response.critique_uptake } : {},
|
|
6181
6418
|
// Source-grounded additive outputs (Tier-4 features).
|
|
6182
6419
|
...useSourceGrounded ? { source_grounded: true } : {},
|
|
6183
6420
|
...sourceExtras?.citation_grade !== void 0 ? { citation_grade: sourceExtras.citation_grade } : {},
|
|
@@ -6193,20 +6430,7 @@ function createEngineConsensusClient(options) {
|
|
|
6193
6430
|
}
|
|
6194
6431
|
};
|
|
6195
6432
|
}
|
|
6196
|
-
var DEFAULT_MODELS =
|
|
6197
|
-
// These ids match the strategic-roadmap §4 `newsStandard` / `newsDeep` panel
|
|
6198
|
-
// intent — current production model ids. Per handoff §C-3 these MUST come
|
|
6199
|
-
// from `CONSENSUS_PANELS` in `functions-shared/shared-model-resolvers.ts`
|
|
6200
|
-
// for V1; placeholder defaults here keep Phase 2 Lane A non-blocking.
|
|
6201
|
-
anthropic: "claude-opus-4-7",
|
|
6202
|
-
openai: "gpt-5",
|
|
6203
|
-
// gemini-2.5-FLASH (not -pro): flash accepts the default thinkingBudget=0 from
|
|
6204
|
-
// callGeminiWithMetrics; 2.5-pro REJECTS budget 0 ("only works in thinking mode").
|
|
6205
|
-
// Flash is also ~10x cheaper. 2026-06-02.
|
|
6206
|
-
google: "gemini-2.5-flash",
|
|
6207
|
-
deepseek: "deepseek-chat",
|
|
6208
|
-
meta: META_CONSENSUS_MODEL
|
|
6209
|
-
};
|
|
6433
|
+
var DEFAULT_MODELS = getVoMcpConsensusPanel();
|
|
6210
6434
|
function probeProviders(env = process.env) {
|
|
6211
6435
|
const out = [];
|
|
6212
6436
|
if ((env["ANTHROPIC_API_KEY"] ?? "").trim().length > 0) out.push("anthropic");
|