@algosuite/vo-mcp 0.2.0-beta.61 → 0.2.0-beta.62

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.
@@ -8937,15 +8937,25 @@ function parseFrontmatterNameDescription(raw) {
8937
8937
  }
8938
8938
  return name && description ? { name, description } : null;
8939
8939
  }
8940
+ function isRepoCheckout(dir) {
8941
+ try {
8942
+ if (!statSync4(join10(dir, ".claude", "skills")).isDirectory()) return false;
8943
+ } catch {
8944
+ return false;
8945
+ }
8946
+ try {
8947
+ statSync4(join10(dir, ".git"));
8948
+ return true;
8949
+ } catch {
8950
+ return false;
8951
+ }
8952
+ }
8940
8953
  function resolveDefaultRepoRoot() {
8941
8954
  const starts = [dirname7(fileURLToPath4(import.meta.url)), process.cwd()];
8942
8955
  for (const start of starts) {
8943
8956
  let dir = start;
8944
8957
  for (let i = 0; i < 8; i += 1) {
8945
- try {
8946
- if (statSync4(join10(dir, ".claude", "skills")).isDirectory()) return dir;
8947
- } catch {
8948
- }
8958
+ if (isRepoCheckout(dir)) return dir;
8949
8959
  const parent = dirname7(dir);
8950
8960
  if (parent === dir) break;
8951
8961
  dir = parent;
@@ -9306,11 +9316,12 @@ function methodologyLedgerFields(methodology) {
9306
9316
  return { ...shape ? { methodology_shape: shape } : {}, ...stakes ? { governed_stakes: stakes } : {} };
9307
9317
  }
9308
9318
  async function composeCodeTaskPrompt(client, task, { log: log2 = () => {
9309
- }, allowMissingKnowledgeContext = false, attachmentManifestMarkdown = "", onMethodology } = {}) {
9319
+ }, allowMissingKnowledgeContext = false, attachmentManifestMarkdown = "", onMethodology, repoRoot: repoRoot2 } = {}) {
9310
9320
  const taskId = task?.code_task_id;
9311
9321
  if (!taskId) {
9312
9322
  return composeDispatchPrompt(withComposedMethodology(withAttachmentManifest(task?.prompt, attachmentManifestMarkdown), task, log2, taskId, onMethodology), {
9313
9323
  repo: task?.repo,
9324
+ repoRoot: repoRoot2,
9314
9325
  knowledgeContextMarkdown: handleMissingKnowledgeContext(taskId, "missing code_task_id on the claimed task", {
9315
9326
  allowMissingKnowledgeContext,
9316
9327
  log: log2
@@ -9320,6 +9331,7 @@ async function composeCodeTaskPrompt(client, task, { log: log2 = () => {
9320
9331
  if (typeof client?.getTaskKnowledgeContext !== "function") {
9321
9332
  return composeDispatchPrompt(withComposedMethodology(withAttachmentManifest(task?.prompt, attachmentManifestMarkdown), task, log2, taskId, onMethodology), {
9322
9333
  repo: task?.repo,
9334
+ repoRoot: repoRoot2,
9323
9335
  knowledgeContextMarkdown: handleMissingKnowledgeContext(taskId, "control-plane client cannot fetch knowledge context", {
9324
9336
  allowMissingKnowledgeContext,
9325
9337
  log: log2
@@ -9349,6 +9361,7 @@ async function composeCodeTaskPrompt(client, task, { log: log2 = () => {
9349
9361
  ${operatorInstructions}` : task?.prompt;
9350
9362
  return composeDispatchPrompt(withComposedMethodology(withAttachmentManifest(prompt, attachmentManifestMarkdown), task, log2, taskId, onMethodology), {
9351
9363
  repo: task?.repo,
9364
+ repoRoot: repoRoot2,
9352
9365
  knowledgeContextMarkdown
9353
9366
  });
9354
9367
  }
@@ -10608,6 +10621,167 @@ var init_local_model_remote_config = __esm({
10608
10621
  }
10609
10622
  });
10610
10623
 
10624
+ // ../../scripts/virtual-office/code-runner/prepared-job-divergence.mjs
10625
+ function context7LocalOnlyEnvPresent(env2 = {}) {
10626
+ return CONTEXT7_LOCAL_ONLY_ENV_KEYS.some((k) => String(env2?.[k] ?? "").trim().length > 0);
10627
+ }
10628
+ function argvDivergesOnlyOnModel(runnerArgv, planeArgv, { runnerModel, planeModel } = {}) {
10629
+ if (!Array.isArray(runnerArgv) || !Array.isArray(planeArgv)) return false;
10630
+ if (runnerArgv.length !== planeArgv.length) return false;
10631
+ if (runnerModel === void 0 || runnerModel === null) return false;
10632
+ if (planeModel === void 0 || planeModel === null) return false;
10633
+ let modelValueDiffs = 0;
10634
+ for (let i = 0; i < runnerArgv.length; i += 1) {
10635
+ if (runnerArgv[i] === planeArgv[i]) continue;
10636
+ if (i === 0) return false;
10637
+ if (runnerArgv[i - 1] !== MODEL_FLAG || planeArgv[i - 1] !== MODEL_FLAG) return false;
10638
+ if (runnerArgv[i] !== String(runnerModel) || planeArgv[i] !== String(planeModel)) return false;
10639
+ modelValueDiffs += 1;
10640
+ }
10641
+ return modelValueDiffs > 0;
10642
+ }
10643
+ function splitPromptSections(prompt) {
10644
+ const text = String(prompt ?? "");
10645
+ const hits = [];
10646
+ let cursor = 0;
10647
+ for (const [name, marker] of PROMPT_SECTION_MARKERS) {
10648
+ const at = text.indexOf(marker, cursor);
10649
+ if (at === -1) continue;
10650
+ hits.push({ name, at });
10651
+ cursor = at + marker.length;
10652
+ }
10653
+ const sections = { preamble: text.slice(0, hits.length ? hits[0].at : text.length) };
10654
+ for (let i = 0; i < hits.length; i += 1) {
10655
+ sections[hits[i].name] = text.slice(hits[i].at, i + 1 < hits.length ? hits[i + 1].at : text.length);
10656
+ }
10657
+ return sections;
10658
+ }
10659
+ function promptSectionDivergence(runnerPrompt, planePrompt) {
10660
+ const a = splitPromptSections(runnerPrompt);
10661
+ const b = splitPromptSections(planePrompt);
10662
+ const names = PROMPT_SECTION_ORDER.filter((n) => n in a || n in b);
10663
+ if (names.some((n) => !(n in a) || !(n in b))) return null;
10664
+ return names.filter((n) => a[n] !== b[n]);
10665
+ }
10666
+ function promptConfinedTo(sections, section) {
10667
+ return Array.isArray(sections) && sections.length === 1 && sections[0] === section;
10668
+ }
10669
+ function context7Config(raw) {
10670
+ let parsed;
10671
+ try {
10672
+ parsed = JSON.parse(String(raw));
10673
+ } catch {
10674
+ return null;
10675
+ }
10676
+ const server = parsed?.mcpServers?.context7;
10677
+ return server && typeof server === "object" && !Array.isArray(server) ? parsed : null;
10678
+ }
10679
+ function mcpConfigDiffersOnlyOnHostLocalContext7(runnerRaw, planeRaw) {
10680
+ const runner = context7Config(runnerRaw);
10681
+ const plane = context7Config(planeRaw);
10682
+ if (!runner || !plane) return false;
10683
+ if (plane.mcpServers.context7.headers !== void 0) return false;
10684
+ const strip = (cfg) => {
10685
+ const copy = JSON.parse(JSON.stringify(cfg));
10686
+ for (const field of CONTEXT7_HOST_LOCAL_FIELDS) delete copy.mcpServers.context7[field];
10687
+ return JSON.stringify(copy);
10688
+ };
10689
+ return strip(runner) === strip(plane);
10690
+ }
10691
+ function argvDivergesOnlyOnLocalMcpConfig(runnerArgv, planeArgv) {
10692
+ if (!Array.isArray(runnerArgv) || !Array.isArray(planeArgv)) return false;
10693
+ if (runnerArgv.length !== planeArgv.length) return false;
10694
+ let diffs = 0;
10695
+ for (let i = 0; i < runnerArgv.length; i += 1) {
10696
+ if (runnerArgv[i] === planeArgv[i]) continue;
10697
+ if (i === 0) return false;
10698
+ if (runnerArgv[i - 1] !== MCP_CONFIG_FLAG || planeArgv[i - 1] !== MCP_CONFIG_FLAG) return false;
10699
+ if (!mcpConfigDiffersOnlyOnHostLocalContext7(runnerArgv[i], planeArgv[i])) return false;
10700
+ diffs += 1;
10701
+ }
10702
+ return diffs > 0;
10703
+ }
10704
+ function safeEndpoint(url) {
10705
+ try {
10706
+ const u = new URL(String(url));
10707
+ return `${u.protocol}//${u.host}${u.pathname}`;
10708
+ } catch {
10709
+ return REDACTED;
10710
+ }
10711
+ }
10712
+ function redactArgvForRecord(argv) {
10713
+ if (!Array.isArray(argv)) return argv ?? null;
10714
+ return argv.map((value, i) => {
10715
+ if (i === 0 || argv[i - 1] !== MCP_CONFIG_FLAG) return value;
10716
+ let parsed;
10717
+ try {
10718
+ parsed = JSON.parse(String(value));
10719
+ } catch {
10720
+ return REDACTED;
10721
+ }
10722
+ for (const server of Object.values(parsed?.mcpServers ?? {})) {
10723
+ if (!server || typeof server !== "object") continue;
10724
+ if (typeof server.url === "string") server.url = safeEndpoint(server.url);
10725
+ if (server.headers && typeof server.headers === "object") {
10726
+ for (const key of Object.keys(server.headers)) server.headers[key] = REDACTED;
10727
+ }
10728
+ }
10729
+ return JSON.stringify(parsed);
10730
+ });
10731
+ }
10732
+ function classifyDivergence(field, ctx = {}) {
10733
+ const known = (reason) => ({ class: "known_remainder", reason });
10734
+ if (Array.isArray(ctx.envDropped) && ctx.envDropped.length > 0) {
10735
+ return known(`env_value_too_long:${ctx.envDropped.join("+")}`);
10736
+ }
10737
+ if ((field === "model" || field === "tier") && ctx.planeModelRegistryUnavailable) {
10738
+ return known("no_plane_model_registry");
10739
+ }
10740
+ if (field === "argv" && ctx.planeModelRegistryUnavailable && ctx.argvDivergesOnlyOnModel) {
10741
+ return known("downstream_of_model_remainder");
10742
+ }
10743
+ if (field === "argv" && ctx.context7LocalOnlyEnvPresent && ctx.argvDivergesOnlyOnLocalMcpConfig) {
10744
+ return known("host_local_context7_mcp_config");
10745
+ }
10746
+ if (field === "dispatch_mode" && ctx.taskDispatchModeAbsent) return known("plane_dispatch_mode_default");
10747
+ if (ctx.dispatchModeDiverged && DISPATCH_MODE_DEPENDENT.has(field)) {
10748
+ return known("downstream_of_dispatch_mode");
10749
+ }
10750
+ if (field === "prompt" && ctx.attachmentManifestPresent && promptConfinedTo(ctx.promptSectionsDiverged, "task")) {
10751
+ return known("attachment_manifest_not_sent");
10752
+ }
10753
+ if (field === "prompt" && ctx.planeSkillCatalogUnavailable && (ctx.promptSectionsDiverged === null || promptConfinedTo(ctx.promptSectionsDiverged, "skill_catalog"))) {
10754
+ return known("skill_catalog_unavailable");
10755
+ }
10756
+ return { class: "unexplained", reason: null };
10757
+ }
10758
+ var DISPATCH_MODE_DEPENDENT, MODEL_FLAG, MCP_CONFIG_FLAG, CONTEXT7_HOST_LOCAL_FIELDS, CONTEXT7_LOCAL_ONLY_ENV_KEYS, PROMPT_SECTION_MARKERS, PROMPT_SECTION_ORDER, REDACTED;
10759
+ var init_prepared_job_divergence = __esm({
10760
+ "../../scripts/virtual-office/code-runner/prepared-job-divergence.mjs"() {
10761
+ "use strict";
10762
+ DISPATCH_MODE_DEPENDENT = /* @__PURE__ */ new Set([
10763
+ "prompt",
10764
+ "argv",
10765
+ "permission_mode",
10766
+ "tier",
10767
+ "model",
10768
+ "effort",
10769
+ "max_turns"
10770
+ ]);
10771
+ MODEL_FLAG = "--model";
10772
+ MCP_CONFIG_FLAG = "--mcp-config";
10773
+ CONTEXT7_HOST_LOCAL_FIELDS = ["url", "headers"];
10774
+ CONTEXT7_LOCAL_ONLY_ENV_KEYS = ["CONTEXT7_API_KEY", "VO_CONTEXT7_URL"];
10775
+ PROMPT_SECTION_MARKERS = [
10776
+ ["skill_catalog", "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 ALGOSUITE SKILL CATALOG \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"],
10777
+ ["knowledge_context", "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 ALGOHQ KNOWLEDGE CONTEXT \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"],
10778
+ ["task", "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 YOUR TASK \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"]
10779
+ ];
10780
+ PROMPT_SECTION_ORDER = ["preamble", "skill_catalog", "knowledge_context", "task"];
10781
+ REDACTED = "[redacted]";
10782
+ }
10783
+ });
10784
+
10611
10785
  // ../../scripts/virtual-office/code-runner/prepared-job-shadow.mjs
10612
10786
  import { appendFileSync, mkdirSync as mkdirSync8 } from "node:fs";
10613
10787
  import { createHash as createHash6 } from "node:crypto";
@@ -10672,33 +10846,29 @@ function planeJobAsComparable(job = {}) {
10672
10846
  methodology_stakes: job.methodology?.stakes ?? null
10673
10847
  };
10674
10848
  }
10675
- function classifyDivergence(field, ctx = {}) {
10676
- const known = (reason) => ({ class: "known_remainder", reason });
10677
- if (Array.isArray(ctx.envDropped) && ctx.envDropped.length > 0) {
10678
- return known(`env_value_too_long:${ctx.envDropped.join("+")}`);
10679
- }
10680
- if ((field === "model" || field === "tier") && ctx.planeModelRegistryUnavailable) {
10681
- return known("no_plane_model_registry");
10682
- }
10683
- if (field === "dispatch_mode" && ctx.taskDispatchModeAbsent) return known("plane_dispatch_mode_default");
10684
- if (ctx.dispatchModeDiverged && DISPATCH_MODE_DEPENDENT.has(field)) {
10685
- return known("downstream_of_dispatch_mode");
10686
- }
10687
- if (field === "prompt" && ctx.attachmentManifestPresent) return known("attachment_manifest_not_sent");
10688
- if (field === "prompt" && ctx.planeSkillCatalogUnavailable) return known("skill_catalog_unavailable");
10689
- return { class: "unexplained", reason: null };
10690
- }
10691
10849
  function comparePreparedJob({ local, plane, context = {} }) {
10692
10850
  const L = local || {};
10693
10851
  const P = plane || {};
10694
10852
  const raw = COMPARED_FIELDS.filter((f) => !sameValue(L[f], P[f]));
10695
- const ctx = { ...context, dispatchModeDiverged: raw.includes("dispatch_mode") };
10853
+ const ctx = {
10854
+ ...context,
10855
+ dispatchModeDiverged: raw.includes("dispatch_mode"),
10856
+ // ADR-004 § 11.1c: computed from the argv arrays themselves, never asserted
10857
+ // by the caller — the classifier may only explain argv when the bytes say so.
10858
+ argvDivergesOnlyOnModel: argvDivergesOnlyOnModel(L.argv, P.argv, {
10859
+ runnerModel: L.model,
10860
+ planeModel: P.model
10861
+ }),
10862
+ argvDivergesOnlyOnLocalMcpConfig: argvDivergesOnlyOnLocalMcpConfig(L.argv, P.argv),
10863
+ // Section NAMES, never text; null when the banners differ (fail-closed).
10864
+ promptSectionsDiverged: promptSectionDivergence(L.prompt, P.prompt)
10865
+ };
10696
10866
  const divergences = raw.map((field) => {
10697
10867
  const { class: cls, reason } = classifyDivergence(field, ctx);
10698
10868
  const entry = { field, class: cls, reason };
10699
10869
  if (field !== "prompt") {
10700
- entry.runner = L[field] ?? null;
10701
- entry.plane = P[field] ?? null;
10870
+ entry.runner = (field === "argv" ? redactArgvForRecord(L.argv) : L[field]) ?? null;
10871
+ entry.plane = (field === "argv" ? redactArgvForRecord(P.argv) : P[field]) ?? null;
10702
10872
  }
10703
10873
  return entry;
10704
10874
  });
@@ -10713,7 +10883,9 @@ function comparePreparedJob({ local, plane, context = {} }) {
10713
10883
  plane_len: String(P.prompt ?? "").length,
10714
10884
  runner_sha256: sha256(L.prompt),
10715
10885
  plane_sha256: sha256(P.prompt),
10716
- first_diff_index: firstDivergenceIndex(L.prompt, P.prompt)
10886
+ first_diff_index: firstDivergenceIndex(L.prompt, P.prompt),
10887
+ // null ⇒ the two prompts do not carry the same banners (not attributable).
10888
+ divergent_sections: ctx.promptSectionsDiverged
10717
10889
  }
10718
10890
  };
10719
10891
  }
@@ -10781,6 +10953,7 @@ function formatShadowLogLine(record) {
10781
10953
  if (known.length) parts.push(`known=${known.map((d) => `${d.field}(${d.reason})`).join(",")}`);
10782
10954
  if (record.verdict === "parity_diverged" && typeof record.prompt?.first_diff_index === "number" && record.prompt.first_diff_index >= 0 && record.unexplained_fields?.includes("prompt")) {
10783
10955
  parts.push(`prompt_first_diff_index=${record.prompt.first_diff_index}`);
10956
+ parts.push(`prompt_sections=${record.prompt.divergent_sections?.join(",") || "not_attributable"}`);
10784
10957
  }
10785
10958
  const loud = record.unexplained_fields?.length ? "!! " : "";
10786
10959
  return `${loud}[prepared-job-shadow] ${parts.join(" ")}`;
@@ -10829,6 +11002,7 @@ async function preparedJobShadowPass({
10829
11002
  planeSkillCatalogUnavailable: fetched.composition?.skill_catalog_available === false,
10830
11003
  taskDispatchModeAbsent: !task?.dispatch_mode,
10831
11004
  attachmentManifestPresent: Boolean(local?.attachmentManifestMarkdown),
11005
+ context7LocalOnlyEnvPresent: context7LocalOnlyEnvPresent(env2),
10832
11006
  envDropped: fetched.envDropped
10833
11007
  }
10834
11008
  }) : null;
@@ -10873,11 +11047,13 @@ async function runPreparedJobShadow(options = {}) {
10873
11047
  }
10874
11048
  return result;
10875
11049
  }
10876
- var PREPARED_JOB_MODES, PREPARED_JOB_MODE_ENV, PREPARED_JOB_SHADOW_TIMEOUT_ENV, DEFAULT_SHADOW_TIMEOUT_MS, PREPARED_JOB_SHADOW_SINK, remotePreparedJobMode, COMPARED_FIELDS, DISPATCH_MODE_DEPENDENT, sha256, sameValue, verdictObserver;
11050
+ var PREPARED_JOB_MODES, PREPARED_JOB_MODE_ENV, PREPARED_JOB_SHADOW_TIMEOUT_ENV, DEFAULT_SHADOW_TIMEOUT_MS, PREPARED_JOB_SHADOW_SINK, remotePreparedJobMode, COMPARED_FIELDS, sha256, sameValue, verdictObserver;
10877
11051
  var init_prepared_job_shadow = __esm({
10878
11052
  "../../scripts/virtual-office/code-runner/prepared-job-shadow.mjs"() {
10879
11053
  "use strict";
10880
11054
  init_claude_args();
11055
+ init_prepared_job_divergence();
11056
+ init_prepared_job_divergence();
10881
11057
  PREPARED_JOB_MODES = ["off", "shadow", "prepared"];
10882
11058
  PREPARED_JOB_MODE_ENV = "VO_CODE_RUNNER_PREPARED_JOB";
10883
11059
  PREPARED_JOB_SHADOW_TIMEOUT_ENV = "VO_PREPARED_JOB_SHADOW_TIMEOUT_MS";
@@ -10897,15 +11073,6 @@ var init_prepared_job_shadow = __esm({
10897
11073
  "methodology_shape",
10898
11074
  "methodology_stakes"
10899
11075
  ];
10900
- DISPATCH_MODE_DEPENDENT = /* @__PURE__ */ new Set([
10901
- "prompt",
10902
- "argv",
10903
- "permission_mode",
10904
- "tier",
10905
- "model",
10906
- "effort",
10907
- "max_turns"
10908
- ]);
10909
11076
  sha256 = (s) => createHash6("sha256").update(String(s ?? ""), "utf8").digest("hex");
10910
11077
  sameValue = (a, b) => Array.isArray(a) || Array.isArray(b) ? JSON.stringify(a) === JSON.stringify(b) : (a ?? null) === (b ?? null);
10911
11078
  verdictObserver = null;
@@ -13094,8 +13261,8 @@ function resolveCacheBaseDir(env2 = process.env, moduleDir = __dirname) {
13094
13261
  if (env2.VO_MODEL_REGISTRY_CACHE_DIR) return env2.VO_MODEL_REGISTRY_CACHE_DIR;
13095
13262
  if (env2.VO_RUNNER_RUNTIME_ROOT) return env2.VO_RUNNER_RUNTIME_ROOT;
13096
13263
  const segments = moduleDir.split(path18.sep);
13097
- const isRepoCheckout = segments.at(-1) === "virtual-office" && segments.at(-2) === "scripts";
13098
- return isRepoCheckout ? path18.resolve(moduleDir, "..", "..") : userCacheRoot();
13264
+ const isRepoCheckout2 = segments.at(-1) === "virtual-office" && segments.at(-2) === "scripts";
13265
+ return isRepoCheckout2 ? path18.resolve(moduleDir, "..", "..") : userCacheRoot();
13099
13266
  }
13100
13267
  function uniqueModels(models = []) {
13101
13268
  return [...new Set(models.map((model) => String(model || "").trim()).filter(Boolean))];
@@ -16717,7 +16884,9 @@ async function processOneTask(client, task, cfg, runnerInstanceId, swarmAdmissio
16717
16884
  methodology = m;
16718
16885
  },
16719
16886
  allowMissingKnowledgeContext: process.env.VO_CODE_RUNNER_ALLOW_MISSING_KNOWLEDGE_CONTEXT === "1",
16720
- attachmentManifestMarkdown: attachmentBundle.manifestMarkdown
16887
+ attachmentManifestMarkdown: attachmentBundle.manifestMarkdown,
16888
+ repoRoot: wt.worktreeDir
16889
+ // ADR-004 § 11.1c: the skill catalog must be the one THIS agent can read
16721
16890
  }) });
16722
16891
  await runPreparedJobShadow({ client, task, agent: sel.agent, env: process.env, log, local: {
16723
16892
  // ADR-004 § 11.1b SHADOW: default OFF; return value deliberately unread — slice C owns consumption