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

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.
@@ -106643,6 +106643,81 @@ if (process.argv[1] && import.meta.url === pathToFileURL(path.resolve(process.ar
106643
106643
  process.exitCode = exitCode;
106644
106644
  }
106645
106645
 
106646
+ // ../../scripts/virtual-office/code-runner/self-claim-identity.mjs
106647
+ var CODE_TASK_BRANCH_RE = /^(?:refs\/heads\/)?vo\/code-task-([0-9a-z]{8,})-/iu;
106648
+ var CODE_TASK_MARKER_RE = /(?:^|[\s[(])code-task:([0-9a-z][0-9a-z-]{7,63})/iu;
106649
+ var MIN_TASK_ID_TOKEN_LENGTH = 8;
106650
+ var MAX_TASK_ID_LENGTH = 36;
106651
+ var TASK_ID_CHARS_RE = /^[0-9a-z][0-9a-z-]*$/u;
106652
+ function normalizeTaskId(value) {
106653
+ return String(value ?? "").trim().toLowerCase();
106654
+ }
106655
+ function taskIdFromCodeTaskBranch(branch) {
106656
+ const match = CODE_TASK_BRANCH_RE.exec(String(branch ?? "").trim());
106657
+ return match ? match[1].toLowerCase() : "";
106658
+ }
106659
+ function taskIdFromClaimMarker(currentTask) {
106660
+ const match = CODE_TASK_MARKER_RE.exec(String(currentTask ?? ""));
106661
+ return match ? match[1].toLowerCase() : "";
106662
+ }
106663
+ function resolvePublishingTaskId({ taskId = "", branch = "", env = {} } = {}) {
106664
+ const none = { taskId: "", token: "", source: "none", exact: false };
106665
+ const fromBranch = taskIdFromCodeTaskBranch(branch);
106666
+ const branchToken = fromBranch.length >= MIN_TASK_ID_TOKEN_LENGTH ? fromBranch : "";
106667
+ const explicit = normalizeTaskId(taskId);
106668
+ if (explicit.length >= MIN_TASK_ID_TOKEN_LENGTH && TASK_ID_CHARS_RE.test(explicit)) {
106669
+ return { taskId: explicit, token: explicit.slice(0, MIN_TASK_ID_TOKEN_LENGTH), source: "explicit", exact: true };
106670
+ }
106671
+ const fromEnv = normalizeTaskId(env?.VO_CODE_TASK_ID);
106672
+ if (fromEnv.length >= MIN_TASK_ID_TOKEN_LENGTH && TASK_ID_CHARS_RE.test(fromEnv)) {
106673
+ if (branchToken && !fromEnv.startsWith(branchToken)) {
106674
+ return { ...none, source: "conflict" };
106675
+ }
106676
+ return { taskId: fromEnv, token: fromEnv.slice(0, MIN_TASK_ID_TOKEN_LENGTH), source: "env", exact: true };
106677
+ }
106678
+ if (branchToken) return { taskId: branchToken, token: branchToken, source: "branch", exact: false };
106679
+ return none;
106680
+ }
106681
+ function matchesPublishingTask(candidate, publishing) {
106682
+ const value = normalizeTaskId(candidate);
106683
+ if (!publishing?.token) return false;
106684
+ if (value.length < MIN_TASK_ID_TOKEN_LENGTH || value.length > MAX_TASK_ID_LENGTH) return false;
106685
+ if (!TASK_ID_CHARS_RE.test(value)) return false;
106686
+ if (!value.startsWith(publishing.token)) return false;
106687
+ if (publishing.exact) return publishing.taskId.startsWith(value) || value.startsWith(publishing.taskId);
106688
+ return true;
106689
+ }
106690
+ function claimTaskId(conflict, publishing) {
106691
+ if (!publishing?.token) return "";
106692
+ const marked = taskIdFromClaimMarker(conflict?.currentTask);
106693
+ if (marked && matchesPublishingTask(marked, publishing)) return marked;
106694
+ const agentId = String(conflict?.agentId ?? "").trim().toLowerCase();
106695
+ if (!agentId) return "";
106696
+ const index = agentId.lastIndexOf(`-${publishing.token}`);
106697
+ if (index < 0) return "";
106698
+ const tail = agentId.slice(index + 1);
106699
+ return matchesPublishingTask(tail, publishing) ? tail : "";
106700
+ }
106701
+ function claimBelongsToTask(conflict, publishing) {
106702
+ return claimTaskId(conflict, publishing) !== "";
106703
+ }
106704
+ function partitionSelfClaims(conflicts = [], publishing = { token: "" }) {
106705
+ const self2 = [];
106706
+ const foreign = [];
106707
+ for (const conflict of conflicts) {
106708
+ (claimBelongsToTask(conflict, publishing) ? self2 : foreign).push(conflict);
106709
+ }
106710
+ return { self: self2, foreign };
106711
+ }
106712
+ function describeSelfClaimExclusion(self2 = [], publishing = { token: "" }) {
106713
+ if (self2.length === 0) return "";
106714
+ const files = [...new Set(self2.map((conflict) => conflict?.matchedFile || conflict?.file || "?"))];
106715
+ return [
106716
+ `Self-claims ignored: ${self2.length} live whiteboard claim(s) held by this publishing task (task ${publishing.taskId || publishing.token}, matched via ${publishing.source}).`,
106717
+ ...files.map((file) => `- ${file}`)
106718
+ ].join("\n");
106719
+ }
106720
+
106646
106721
  // ../../scripts/ci/check-local-pr-overlap.mjs
106647
106722
  function normalizeFileList(files = []) {
106648
106723
  return [...new Set(files.flatMap((file) => String(file || "").split(/\r?\n/)).map((file) => file.trim().replaceAll("\\", "/")).filter(Boolean))];
@@ -106728,7 +106803,10 @@ function evaluateOverlapGate({
106728
106803
  whiteboardReason = "",
106729
106804
  requireWhiteboard = true,
106730
106805
  allowOverlap = false,
106731
- prLabel = "local branch"
106806
+ prLabel = "local branch",
106807
+ // Never silent: when the publishing task's OWN claims were dropped, say so and
106808
+ // name them. A gate that quietly ignores claims cannot be told from a broken one.
106809
+ selfClaimNote = ""
106732
106810
  } = {}) {
106733
106811
  const files = normalizeFileList(changedFiles);
106734
106812
  const overlaps = classifyOverlaps(files, otherPrs || []);
@@ -106740,6 +106818,7 @@ function evaluateOverlapGate({
106740
106818
  lines.push(`Local overlap gate for ${prLabel}`);
106741
106819
  lines.push(`Changed files: ${files.length}`);
106742
106820
  if (otherPrs?.length) lines.push(`Compared against open PRs: ${otherPrs.length}`);
106821
+ if (selfClaimNote) lines.push(selfClaimNote);
106743
106822
  if (directOverlap || overlaps.packageOverlaps.length || overlaps.sharedDepOverlaps.length) {
106744
106823
  lines.push("");
106745
106824
  lines.push(buildOverlapReport(overlaps, 0));
@@ -106780,6 +106859,32 @@ function evaluateOverlapGate({
106780
106859
  report: lines.join("\n")
106781
106860
  };
106782
106861
  }
106862
+ function decideOverlapGate({
106863
+ changedFiles,
106864
+ otherPrs = [],
106865
+ busResult = { available: true, conflicts: [] },
106866
+ taskId = "",
106867
+ branch = "",
106868
+ env = process.env,
106869
+ requireWhiteboard = true,
106870
+ allowOverlap = false,
106871
+ prLabel = branch || "local branch"
106872
+ } = {}) {
106873
+ const publishing = resolvePublishingTaskId({ taskId, branch, env });
106874
+ const { self: self2, foreign } = partitionSelfClaims(busResult?.conflicts || [], publishing);
106875
+ const evaluated = evaluateOverlapGate({
106876
+ changedFiles,
106877
+ otherPrs,
106878
+ busConflicts: foreign,
106879
+ whiteboardAvailable: busResult?.available !== false,
106880
+ whiteboardReason: busResult?.reason || "",
106881
+ requireWhiteboard,
106882
+ allowOverlap,
106883
+ prLabel,
106884
+ selfClaimNote: describeSelfClaimExclusion(self2, publishing)
106885
+ });
106886
+ return { ...evaluated, publishing, selfClaims: self2 };
106887
+ }
106783
106888
  async function main() {
106784
106889
  const { values: args } = parseArgs({
106785
106890
  options: {
@@ -106788,7 +106893,10 @@ async function main() {
106788
106893
  branch: { type: "string", default: "" },
106789
106894
  stdin: { type: "boolean", default: false },
106790
106895
  "exclude-pr": { type: "string", default: "" },
106791
- "agent-id": { type: "string", default: process.env.AGENT_ID || "" }
106896
+ "agent-id": { type: "string", default: process.env.AGENT_ID || "" },
106897
+ // The publishing code task. Explicit beats VO_CODE_TASK_ID beats the
106898
+ // `vo/code-task-<id8>-…` branch; absent everywhere ⇒ nothing is excluded.
106899
+ "task-id": { type: "string", default: "" }
106792
106900
  }
106793
106901
  });
106794
106902
  const changedFiles = args.stdin ? readFilesFromStdin() : readChangedFiles({ base: args.base, head: args.head });
@@ -106815,12 +106923,12 @@ async function main() {
106815
106923
  return 2;
106816
106924
  }
106817
106925
  const busResult = await checkForConflicts(changedFiles, { excludeAgentId: args["agent-id"] });
106818
- const result = evaluateOverlapGate({
106926
+ const result = decideOverlapGate({
106819
106927
  changedFiles,
106820
106928
  otherPrs,
106821
- busConflicts: busResult.conflicts || [],
106822
- whiteboardAvailable: busResult.available !== false,
106823
- whiteboardReason: busResult.reason || "",
106929
+ busResult,
106930
+ taskId: args["task-id"],
106931
+ branch: args.branch,
106824
106932
  requireWhiteboard: process.env.VO_ALLOW_WHITEBOARD_UNAVAILABLE !== "1",
106825
106933
  allowOverlap: process.env.VO_ALLOW_PR_OVERLAP === "1",
106826
106934
  prLabel: args.branch || "local branch"
@@ -106831,6 +106939,7 @@ async function main() {
106831
106939
  var __test3 = {
106832
106940
  HOSTILE_WORKTREE_GIT_GUARDS,
106833
106941
  gitText,
106942
+ decideOverlapGate,
106834
106943
  evaluateOverlapGate,
106835
106944
  isPrDiffTooLargeError,
106836
106945
  normalizeFileList,
@@ -106842,7 +106951,8 @@ if (process.argv[1] && import.meta.url === pathToFileURL2(path2.resolve(process.
106842
106951
  process.exit(await main());
106843
106952
  }
106844
106953
  export {
106845
- __test3 as __test
106954
+ __test3 as __test,
106955
+ decideOverlapGate
106846
106956
  };
106847
106957
  /*! Bundled license information:
106848
106958
 
@@ -546,6 +546,43 @@ function installCodexMcpConfigAt(configPath, cliPath, controlPlaneUrl, log, mana
546
546
  log(`\u2713 Wrote AlgoHQ MCP to Codex: ${configPath}`);
547
547
  }
548
548
 
549
+ // src/remote-mcp-entry.ts
550
+ var REMOTE_MCP_SERVER_KEY = "vo-mcp-remote";
551
+ var REMOTE_MCP_TOKEN_ENV = "VO_MCP_REMOTE_TOKEN";
552
+ var REMOTE_MCP_ENDPOINT_PATH = "/api/v1/mcp";
553
+ var REMOTE_MCP_AUTH_HEADER = `Bearer \${${REMOTE_MCP_TOKEN_ENV}}`;
554
+ function remoteMcpOptIn(env) {
555
+ return (env["VO_REMOTE_MCP"] ?? "").trim() === "1";
556
+ }
557
+ function remoteMcpUrl(controlPlaneUrl) {
558
+ return `${controlPlaneUrl.trim().replace(/\/+$/, "")}${REMOTE_MCP_ENDPOINT_PATH}`;
559
+ }
560
+ function buildRemoteMcpEntry(controlPlaneUrl) {
561
+ return {
562
+ type: "http",
563
+ url: remoteMcpUrl(controlPlaneUrl),
564
+ headers: { Authorization: REMOTE_MCP_AUTH_HEADER }
565
+ };
566
+ }
567
+ function asRecord(value) {
568
+ return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
569
+ }
570
+ function isManagedRemoteMcpEntry(value) {
571
+ const entry = asRecord(value);
572
+ if (!entry) return false;
573
+ if (entry["type"] !== "http") return false;
574
+ const url = entry["url"];
575
+ if (typeof url !== "string" || !url.endsWith(REMOTE_MCP_ENDPOINT_PATH)) return false;
576
+ const headers = asRecord(entry["headers"]);
577
+ return headers?.["Authorization"] === REMOTE_MCP_AUTH_HEADER;
578
+ }
579
+ function remoteMcpEntryIsCurrent(value, desired) {
580
+ const entry = asRecord(value);
581
+ if (!entry) return false;
582
+ const headers = asRecord(entry["headers"]);
583
+ return entry["type"] === desired.type && entry["url"] === desired.url && headers?.["Authorization"] === desired.headers["Authorization"];
584
+ }
585
+
549
586
  // src/autostart.ts
550
587
  import { homedir as homedir3, platform as platform2 } from "node:os";
551
588
  import { isAbsolute as isAbsolute2, join as join5 } from "node:path";
@@ -810,7 +847,20 @@ function resolveVoMcpCliPath() {
810
847
  }
811
848
  var INSTALL_LAUNCHER = { sticky: false, onlyExisting: false };
812
849
  var HEAL_LAUNCHER = { sticky: true, onlyExisting: true };
813
- function installMcpConfigAt(configPath, cliPath, controlPlaneUrl, log, label, launcher = { launcherPath: null, ...INSTALL_LAUNCHER }) {
850
+ function reconcileRemoteEntry(mcpServers, remote) {
851
+ const existing = mcpServers[REMOTE_MCP_SERVER_KEY];
852
+ if (remote) {
853
+ return {
854
+ fragment: { [REMOTE_MCP_SERVER_KEY]: remote },
855
+ current: remoteMcpEntryIsCurrent(existing, remote)
856
+ };
857
+ }
858
+ if (existing !== void 0 && isManagedRemoteMcpEntry(existing)) {
859
+ return { fragment: { [REMOTE_MCP_SERVER_KEY]: void 0 }, current: false };
860
+ }
861
+ return { fragment: {}, current: true };
862
+ }
863
+ function installMcpConfigAt(configPath, cliPath, controlPlaneUrl, log, label, launcher = { launcherPath: null, ...INSTALL_LAUNCHER }, remote = null) {
814
864
  if (launcher.onlyExisting && !existsSync6(configPath)) return;
815
865
  const read = readClaudeConfig(configPath);
816
866
  if (read.kind === "invalid" || read.kind === "empty" && launcher.onlyExisting) {
@@ -824,8 +874,9 @@ function installMcpConfigAt(configPath, cliPath, controlPlaneUrl, log, label, la
824
874
  const voEntry = managedEntry ?? mcpServers["vo"];
825
875
  const { launcherPath } = launcher;
826
876
  const fallbackCli = chooseFallbackCli(voEntry?.env?.[MCP_FALLBACK_CLI_ENV], cliPath, launcher.sticky, launcherPath ? dirname4(launcherPath) : null);
827
- const current = launcherPath ? !isStaleVoMcpEntry(voEntry, launcherPath, fallbackCli) : Boolean(voEntry?.args?.some((a) => a.includes(cliPath)));
828
- if (current) {
877
+ const localCurrent = launcherPath ? !isStaleVoMcpEntry(voEntry, launcherPath, fallbackCli) : Boolean(voEntry?.args?.some((a) => a.includes(cliPath)));
878
+ const remoteState = reconcileRemoteEntry(mcpServers, remote);
879
+ if (localCurrent && remoteState.current) {
829
880
  log(` ${label} already current: ${configPath}`);
830
881
  return;
831
882
  }
@@ -845,7 +896,11 @@ function installMcpConfigAt(configPath, cliPath, controlPlaneUrl, log, label, la
845
896
  ...preservedEnv,
846
897
  ...launcherPath && fallbackCli ? { [MCP_FALLBACK_CLI_ENV]: fallbackCli } : {}
847
898
  }
848
- }
899
+ },
900
+ // Additive remote entry (11.3 slice A) — or the removal of one we wrote,
901
+ // when the operator has opted back out. Spread LAST so it can delete its
902
+ // own key; it never names 'vo-mcp', so the stdio entry above is safe.
903
+ ...remoteState.fragment
849
904
  }
850
905
  };
851
906
  if (readMtime !== null && (!existsSync6(configPath) || statSync3(configPath).mtimeMs !== readMtime)) {
@@ -854,6 +909,12 @@ function installMcpConfigAt(configPath, cliPath, controlPlaneUrl, log, label, la
854
909
  }
855
910
  writeClaudeConfig(configPath, merged);
856
911
  log(`\u2713 Wrote vo-mcp to ${label}: ${configPath}`);
912
+ if (remote) {
913
+ log(` + remote MCP entry '${REMOTE_MCP_SERVER_KEY}' \u2192 ${remote.url} (serves vo_skill_list; every other tool stays on the local vo-mcp entry)`);
914
+ log(` Set ${REMOTE_MCP_TOKEN_ENV} in your environment to authenticate it \u2014 no token is written to this file.`);
915
+ } else if (!remoteState.current) {
916
+ log(` - removed the remote MCP entry '${REMOTE_MCP_SERVER_KEY}' (VO_REMOTE_MCP is not set to 1)`);
917
+ }
857
918
  }
858
919
  function installMcpConfig(log, env, mode = "install") {
859
920
  const home = env["HOME"]?.trim() || env["USERPROFILE"]?.trim() || homedir4();
@@ -861,6 +922,7 @@ function installMcpConfig(log, env, mode = "install") {
861
922
  const plat = platform3();
862
923
  const cliPath = resolveVoMcpCliPath();
863
924
  const controlPlaneUrl = env["VO_CONTROL_PLANE_URL"]?.trim() || DEFAULT_CONTROL_PLANE_URL2;
925
+ const remote = remoteMcpOptIn(env) ? buildRemoteMcpEntry(controlPlaneUrl) : null;
864
926
  const launcherPath = writeMcpLauncherForEnv(env, log, { platform: plat, home });
865
927
  const launcher = { launcherPath, ...mode === "heal" ? HEAL_LAUNCHER : INSTALL_LAUNCHER };
866
928
  const leg = (label, run) => {
@@ -871,8 +933,8 @@ function installMcpConfig(log, env, mode = "install") {
871
933
  log(` \u26A0 ${label}: could not update the MCP registration \u2014 ${err instanceof Error ? err.message : String(err)}`);
872
934
  }
873
935
  };
874
- leg("Claude Code CLI", () => installMcpConfigAt(resolveCodeConfigPath(home), cliPath, controlPlaneUrl, log, "Claude Code CLI", launcher));
875
- leg("Claude Desktop", () => installMcpConfigAt(resolveDesktopConfigPath(home, plat, appData), cliPath, controlPlaneUrl, log, "Claude Desktop", launcher));
936
+ leg("Claude Code CLI", () => installMcpConfigAt(resolveCodeConfigPath(home), cliPath, controlPlaneUrl, log, "Claude Code CLI", launcher, remote));
937
+ leg("Claude Desktop", () => installMcpConfigAt(resolveDesktopConfigPath(home, plat, appData), cliPath, controlPlaneUrl, log, "Claude Desktop", launcher, remote));
876
938
  const codexPath = resolveCodexConfigPath(home);
877
939
  if (launcher.onlyExisting && !existsSync6(codexPath)) return;
878
940
  leg("Codex", () => {