openmausbot 0.1.92 → 0.1.94

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.
Files changed (163) hide show
  1. package/dist/assets/{DesktopViewer-Do6lBa4C.js → DesktopViewer-bxM7NV3N.js} +1 -1
  2. package/dist/assets/{abnfDiagram-O67JEVCF-Cd3X7Hxc.js → abnfDiagram-O67JEVCF-BhMdJhRJ.js} +1 -1
  3. package/dist/assets/{arc-DIYc7Ymx.js → arc-B5itKDcx.js} +1 -1
  4. package/dist/assets/{architectureDiagram-NJMV4G6O-DBmRGVyP.js → architectureDiagram-NJMV4G6O-C5d7UY6U.js} +1 -1
  5. package/dist/assets/{blockDiagram-BEXU5L5S-CPFePSEE.js → blockDiagram-BEXU5L5S-BrZIhMmu.js} +1 -1
  6. package/dist/assets/{c4Diagram-YGBWAQC7-DD_DO1qy.js → c4Diagram-YGBWAQC7-7I0ArfbD.js} +1 -1
  7. package/dist/assets/channel-CdJX6i8k.js +1 -0
  8. package/dist/assets/{chunk-2Q5K7J3B-BNEeNSjX.js → chunk-2Q5K7J3B-BnEsyN36.js} +1 -1
  9. package/dist/assets/{chunk-3FUC2YCW-BbinLaqH.js → chunk-3FUC2YCW-BXATQ52s.js} +2 -2
  10. package/dist/assets/{chunk-5VM5RSS4-BBgYrgDR.js → chunk-5VM5RSS4-B0BpTkEx.js} +1 -1
  11. package/dist/assets/{chunk-GTNCS2PH-ezXj-kA-.js → chunk-GTNCS2PH-BtLTz6FR.js} +1 -1
  12. package/dist/assets/{chunk-GWA4HPMP-9FxZ3diV.js → chunk-GWA4HPMP-D6gcZOYt.js} +1 -1
  13. package/dist/assets/{chunk-JWPE2WC7-CO-40JpI.js → chunk-JWPE2WC7-DCLrosvf.js} +1 -1
  14. package/dist/assets/{chunk-NETBCI7D-BEhjslYE.js → chunk-NETBCI7D-B9JsknV9.js} +1 -1
  15. package/dist/assets/{chunk-WEXAMYUT-CNeq4n7_.js → chunk-WEXAMYUT-CsoTxw7z.js} +1 -1
  16. package/dist/assets/{chunk-XXDRQBXY-OsCY7KSi.js → chunk-XXDRQBXY-0F_frB0c.js} +1 -1
  17. package/dist/assets/{classDiagram-v2-NBCMYWYE-CloRUEtk.js → classDiagram-v2-NBCMYWYE-DkrpnflX.js} +1 -1
  18. package/dist/assets/{cose-bilkent-JH36ORCC-D1BGZhp4.js → cose-bilkent-JH36ORCC-BNDwYBt9.js} +1 -1
  19. package/dist/assets/{cynefin-OW5HDTMX-CUf4T2CN.js → cynefin-OW5HDTMX-JUkNr1Mk.js} +1 -1
  20. package/dist/assets/{cynefinDiagram-VND7K2PF-DPEZrFGA.js → cynefinDiagram-VND7K2PF-DKeh9N4M.js} +1 -1
  21. package/dist/assets/{dagre-6A5THRUB-bDe6GIv5.js → dagre-6A5THRUB-ve-6T_wX.js} +1 -1
  22. package/dist/assets/{diagram-22UHCM2B-CdcUQz55.js → diagram-22UHCM2B-BuJ2d8rT.js} +1 -1
  23. package/dist/assets/{diagram-3UASUU5V-BZpqGg7c.js → diagram-3UASUU5V-BgOs_Ni-.js} +1 -1
  24. package/dist/assets/{diagram-ATOU4E4O-DvGM6ugp.js → diagram-ATOU4E4O-DMK6VmcP.js} +1 -1
  25. package/dist/assets/{diagram-CDSNMT55-DSTmMm0s.js → diagram-CDSNMT55-DksASlcY.js} +1 -1
  26. package/dist/assets/{diagram-MLGK6HIB-15cucnMn.js → diagram-MLGK6HIB-Bgn8I5k6.js} +1 -1
  27. package/dist/assets/{diagram-MPIPVDR6-tMbuaE6n.js → diagram-MPIPVDR6-zK0jqO8N.js} +1 -1
  28. package/dist/assets/{ebnfDiagram-ZINNZB2B-BYxYzjHI.js → ebnfDiagram-ZINNZB2B-vKrbzTwr.js} +1 -1
  29. package/dist/assets/{elk-276RUBZZ-v6bj852W.js → elk-276RUBZZ-Bzv2mPNf.js} +1 -1
  30. package/dist/assets/{erDiagram-OPXOYQCR-5lBBlnd2.js → erDiagram-OPXOYQCR-CvOyYuxu.js} +1 -1
  31. package/dist/assets/{flowDiagram-KWPJA3E3-CZyl1zIj.js → flowDiagram-KWPJA3E3-CtbnDbc0.js} +1 -1
  32. package/dist/assets/{ganttDiagram-FUAMR5RP-BiAI-ltZ.js → ganttDiagram-FUAMR5RP-c4dMRYyG.js} +1 -1
  33. package/dist/assets/{gitGraphDiagram-X574FWY7-BAZISkj3.js → gitGraphDiagram-X574FWY7-B34uaQho.js} +1 -1
  34. package/dist/assets/index-CPYrGsv1.js +610 -0
  35. package/dist/assets/{index-DGBaEXrM.js → index-CPiqc_DN.js} +1 -1
  36. package/dist/assets/index-CzT42GR8.css +1 -0
  37. package/dist/assets/{infoDiagram-VRGFBTTK-B6ooOy-Z.js → infoDiagram-VRGFBTTK-o64ma4CI.js} +1 -1
  38. package/dist/assets/{ishikawaDiagram-OU5B5YK6-BZ9ksi-B.js → ishikawaDiagram-OU5B5YK6-DV4C9BAm.js} +1 -1
  39. package/dist/assets/{journeyDiagram-ZHPQQLJL-DWqlzIEe.js → journeyDiagram-ZHPQQLJL-Bf0AHk1H.js} +1 -1
  40. package/dist/assets/{kanban-definition-PNTS6WVX-JX6piDwL.js → kanban-definition-PNTS6WVX-B1UMSKmE.js} +1 -1
  41. package/dist/assets/{linear-CmOWzX0P.js → linear-BpKhuyLm.js} +1 -1
  42. package/dist/assets/{mermaid.core-CF1zwoQ-.js → mermaid.core-B_BKNCw5.js} +5 -5
  43. package/dist/assets/{mindmap-definition-NLK3R4M7-CGh2K4fW.js → mindmap-definition-NLK3R4M7-DeARruT1.js} +1 -1
  44. package/dist/assets/{pegDiagram-GJSIUBJH-CDwYN0s7.js → pegDiagram-GJSIUBJH-BOQEk_1D.js} +1 -1
  45. package/dist/assets/{pieDiagram-5QR66LMP-1rfjJocB.js → pieDiagram-5QR66LMP-EIfoiTZo.js} +1 -1
  46. package/dist/assets/{quadrantDiagram-O4NWA36T-tKPvPiok.js → quadrantDiagram-O4NWA36T-GgZwT-fi.js} +1 -1
  47. package/dist/assets/{railroadDiagram-XR7U4H2S-BHLm5vXR.js → railroadDiagram-XR7U4H2S-D9rDQomj.js} +1 -1
  48. package/dist/assets/{requirementDiagram-PLB6GJNP-CB45STp7.js → requirementDiagram-PLB6GJNP-DAh1MIeo.js} +1 -1
  49. package/dist/assets/{sankeyDiagram-IPEJSGJF-55QA_huC.js → sankeyDiagram-IPEJSGJF-CPr6Uz64.js} +1 -1
  50. package/dist/assets/{sequenceDiagram-PO4LG4MO-BckFmQHn.js → sequenceDiagram-PO4LG4MO-BU6VIdcm.js} +1 -1
  51. package/dist/assets/{sizeCapture-INFHLROL-BFCOJF11.js → sizeCapture-INFHLROL-qF2HO41r.js} +1 -1
  52. package/dist/assets/{stateDiagram-v2-GCMORJYK-CZvmiVVN.js → stateDiagram-v2-GCMORJYK-DlJ8G4MD.js} +1 -1
  53. package/dist/assets/{swimlanes-2SLR337P-BpDUCEKy.js → swimlanes-2SLR337P-DzYE8I54.js} +1 -1
  54. package/dist/assets/swimlanesDiagram-TC7HE7FX-D-U4GtLQ.js +8 -0
  55. package/dist/assets/{timeline-definition-EJHVYXUP-BpxHq6IK.js → timeline-definition-EJHVYXUP-B7wzEQ0A.js} +1 -1
  56. package/dist/assets/{usecaseDiagram-POWQR4AR-Cj66vm02.js → usecaseDiagram-POWQR4AR-BvGgrxIP.js} +1 -1
  57. package/dist/assets/{vennDiagram-UO4OBE2U-C9nRkWE_.js → vennDiagram-UO4OBE2U-CEECdgQg.js} +1 -1
  58. package/dist/assets/{wardleyDiagram-VNRHLVJA-D-me_nWj.js → wardleyDiagram-VNRHLVJA-XQHA0P_P.js} +1 -1
  59. package/dist/assets/{xychartDiagram-PMCCYNJV-Dc_fL4mk.js → xychartDiagram-PMCCYNJV-B5mLcZI2.js} +1 -1
  60. package/dist/index.html +2 -2
  61. package/dist-server/cloud-home-start.js +1 -0
  62. package/dist-server/companion/src/routes.js +45 -1
  63. package/dist-server/container-mcp.js +99 -77
  64. package/dist-server/drivers/agents-proxy.js +40 -1
  65. package/dist-server/drivers/pi-mcp-extension.ts +245 -299
  66. package/dist-server/enterprise/server/index.js +1 -0
  67. package/dist-server/index.js +18361 -13794
  68. package/dist-server/local-computer-proxy.js +5 -1
  69. package/dist-server/local-computer.js +1 -0
  70. package/dist-server/mcp-gate.js +152 -20
  71. package/dist-server/mcp-remote-proxy.js +437 -0
  72. package/dist-server/openmausbot.js +8872 -7620
  73. package/dist-server/pair-cli.js +8872 -7620
  74. package/dist-server/permission-proxy.js +65 -1
  75. package/dist-server/proxy-paths.js +1 -0
  76. package/dist-server/server/auto-approve.js +33 -11
  77. package/dist-server/server/boat.js +3 -3
  78. package/dist-server/server/browser-live.js +14 -5
  79. package/dist-server/server/browser-runtime.js +6 -0
  80. package/dist-server/server/channel-queue.js +4 -1
  81. package/dist-server/server/cli.js +32 -12
  82. package/dist-server/server/cloud-move-http.js +9 -3
  83. package/dist-server/server/cloud-move.js +18 -0
  84. package/dist-server/server/cloud-owner.js +1 -1
  85. package/dist-server/server/computer-control.js +6 -0
  86. package/dist-server/server/computer-wait.js +33 -13
  87. package/dist-server/server/config.js +57 -10
  88. package/dist-server/server/container-computer.js +43 -32
  89. package/dist-server/server/decision-log.js +9 -6
  90. package/dist-server/server/delegations.js +47 -22
  91. package/dist-server/server/digest.js +12 -2
  92. package/dist-server/server/drivers/acp/core.js +229 -20
  93. package/dist-server/server/drivers/acp/cursor.js +13 -1
  94. package/dist-server/server/drivers/acp/grok.js +208 -3
  95. package/dist-server/server/drivers/acp/quiet-status.js +257 -0
  96. package/dist-server/server/drivers/acp/qwen.js +18 -0
  97. package/dist-server/server/drivers/agents-call.js +28 -0
  98. package/dist-server/server/drivers/agents-catalog.js +10 -1
  99. package/dist-server/server/drivers/boatagent.js +2 -0
  100. package/dist-server/server/drivers/builtIn.js +2 -0
  101. package/dist-server/server/drivers/cerebras.js +108 -0
  102. package/dist-server/server/drivers/chat-mcp-tools.js +45 -15
  103. package/dist-server/server/drivers/claude.js +35 -9
  104. package/dist-server/server/drivers/codex.js +84 -10
  105. package/dist-server/server/drivers/openai-chat.js +37 -5
  106. package/dist-server/server/drivers/pi.js +48 -4
  107. package/dist-server/server/drivers/prompt-split.js +2 -0
  108. package/dist-server/server/env-path.js +6 -2
  109. package/dist-server/server/environment.js +3 -0
  110. package/dist-server/server/guarded-requests.js +2 -1
  111. package/dist-server/server/index.js +1353 -311
  112. package/dist-server/server/live-call-controller.js +868 -0
  113. package/dist-server/server/live-call.js +216 -0
  114. package/dist-server/server/local-vm-stop-reason.js +26 -0
  115. package/dist-server/server/mcp-gate-config.js +43 -12
  116. package/dist-server/server/mcp-gate.js +127 -25
  117. package/dist-server/server/mcp-http.js +46 -8
  118. package/dist-server/server/mcp-remote-proxy.js +108 -0
  119. package/dist-server/server/new-bot-defaults.js +3 -0
  120. package/dist-server/server/peer-provenance.js +4 -2
  121. package/dist-server/server/permission-proxy.js +15 -1
  122. package/dist-server/server/plan-usage.js +797 -0
  123. package/dist-server/server/provider-key-check.js +2 -1
  124. package/dist-server/server/proxy-paths.js +1 -0
  125. package/dist-server/server/redact.js +2 -0
  126. package/dist-server/server/request-auth.js +3 -2
  127. package/dist-server/server/routes/desktop-viewer.js +50 -6
  128. package/dist-server/server/routes/live.js +98 -0
  129. package/dist-server/server/routines.js +6 -3
  130. package/dist-server/server/skill-library.js +207 -0
  131. package/dist-server/server/skills-library-migration.js +235 -0
  132. package/dist-server/server/skills.js +66 -3
  133. package/dist-server/server/steer-queue.js +13 -1
  134. package/dist-server/server/store.js +86 -4
  135. package/dist-server/server/surface.js +9 -3
  136. package/dist-server/server/team-backup.js +2 -1
  137. package/dist-server/server/thread-events.js +1 -1
  138. package/dist-server/server/tunnel.js +20 -1
  139. package/dist-server/server/turn-log.js +10 -0
  140. package/dist-server/server/turn-resources.js +124 -0
  141. package/dist-server/server/vps-computer.js +1 -1
  142. package/dist-server/server/workspace-backup.js +22 -0
  143. package/dist-server/server/workspace.js +1 -1
  144. package/dist-server/shared/approval-mode.js +1 -1
  145. package/dist-server/shared/ask-question.js +13 -0
  146. package/dist-server/shared/call-consent.js +28 -0
  147. package/dist-server/shared/live-approval.js +124 -0
  148. package/dist-server/shared/live-call.js +176 -0
  149. package/dist-server/shared/redact.js +1 -0
  150. package/dist-server/shared/skill-md.js +10 -0
  151. package/dist-server/shared/team-backup.js +3 -0
  152. package/dist-server/shared/tool-name.js +22 -0
  153. package/dist-server/shared/tool-scope-support.js +25 -0
  154. package/dist-server/shared/tool-scope.js +136 -0
  155. package/dist-server/src/lib/thread-refs.js +406 -0
  156. package/dist-server/vps-container-mcp.js +99 -77
  157. package/dist-server/workspace-backup.worker.js +103 -100
  158. package/enterprise/server/index.js +1 -0
  159. package/package.json +1 -1
  160. package/dist/assets/channel-Dtk5Mtic.js +0 -1
  161. package/dist/assets/index-Cdmjrl28.css +0 -1
  162. package/dist/assets/index-DR7YPMkW.js +0 -597
  163. package/dist/assets/swimlanesDiagram-TC7HE7FX-M0GYW9Y3.js +0 -8
@@ -130,6 +130,8 @@ function windowsKnownDirs() {
130
130
  // x.ai installer
131
131
  join(localAppData, "agy", "bin"),
132
132
  // Antigravity installer
133
+ // Cursor installer: cursor-agent.* and its `agent` copies (MOCA-272)
134
+ join(localAppData, "cursor-agent"),
133
135
  join(home, ".local", "bin"),
134
136
  // claude native installer
135
137
  join(home, ".claude", "local"),
@@ -137,7 +139,9 @@ function windowsKnownDirs() {
137
139
  // Factory droid installer (%USERPROFILE%\bin)
138
140
  join(home, ".bun", "bin"),
139
141
  join(home, ".deno", "bin"),
140
- join(home, "go", "bin")
142
+ join(home, "go", "bin"),
143
+ join(process.env.ProgramFiles ?? "C:\\Program Files", "Docker", "Docker", "resources", "bin")
144
+ // Docker Desktop installer
141
145
  ];
142
146
  }
143
147
  var cached = null;
@@ -22,6 +22,7 @@ var SPAWNED_PROXIES = {
22
22
  dweb: resolveProxy("drivers/dweb-proxy"),
23
23
  connectors: resolveProxy("connector-proxy"),
24
24
  mcpGate: resolveProxy("mcp-gate"),
25
+ mcpRemote: resolveProxy("mcp-remote-proxy"),
25
26
  phone: resolveProxy("drivers/phone-proxy"),
26
27
  hook: resolveProxy("hooks/omb-hook"),
27
28
  // Loaded by the external `pi` process via `-e`, not by this server — but
@@ -4,6 +4,60 @@ import { mkdirSync, readdirSync as readdirSync2, rmSync, statSync as statSync2,
4
4
  import { join as join2 } from "node:path";
5
5
  import { createInterface } from "node:readline";
6
6
 
7
+ // shared/tool-scope.ts
8
+ var SERVER_NAME = /^[a-z][a-z0-9_-]{0,31}$/;
9
+ var CONTROL_CHARACTER = /[\x00-\x1f\x7f]/;
10
+ var MAX_SELECTORS = 256;
11
+ var MAX_SELECTOR_LENGTH = 1024;
12
+ function validName(name) {
13
+ return typeof name === "string" && name.trim().length > 0 && name.length <= MAX_SELECTOR_LENGTH && !CONTROL_CHARACTER.test(name) && !name.includes("*");
14
+ }
15
+ function selectorIdentity(selector) {
16
+ if (selector.length > MAX_SELECTOR_LENGTH || CONTROL_CHARACTER.test(selector)) return;
17
+ if (selector.startsWith("native:")) {
18
+ const name = selector.slice(7);
19
+ if (name === "*" || validName(name)) return { kind: "native", name };
20
+ } else if (selector.startsWith("mcp:")) {
21
+ const separator = selector.indexOf(":", 4);
22
+ if (separator < 0) return;
23
+ const server = selector.slice(4, separator);
24
+ const name = selector.slice(separator + 1);
25
+ if (SERVER_NAME.test(server) && (name === "*" || validName(name))) {
26
+ return { kind: "mcp", server, name };
27
+ }
28
+ }
29
+ }
30
+ function parseToolScope(value) {
31
+ if (value === void 0) return { ok: true, scope: void 0 };
32
+ const invalid = { ok: false, error: "Tool selection must contain only valid allow and deny lists." };
33
+ if (!value || typeof value !== "object" || Array.isArray(value)) return invalid;
34
+ const prototype = Object.getPrototypeOf(value);
35
+ if (prototype !== Object.prototype && prototype !== null) return invalid;
36
+ const scope2 = {};
37
+ for (const key of Reflect.ownKeys(value)) {
38
+ if (key !== "allow" && key !== "deny") return invalid;
39
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
40
+ if (!descriptor || !("value" in descriptor)) return invalid;
41
+ const list = descriptor.value;
42
+ if (!Array.isArray(list) || list.length > MAX_SELECTORS) return invalid;
43
+ if (!Array.from(list).every((entry) => typeof entry === "string" && selectorIdentity(entry))) return invalid;
44
+ scope2[key] = [...new Set(list)];
45
+ }
46
+ return { ok: true, scope: scope2 };
47
+ }
48
+ function matches(selector, tool) {
49
+ const selected = selectorIdentity(selector);
50
+ return selected?.kind === tool.kind && (selected.kind !== "mcp" || tool.kind === "mcp" && selected.server === tool.server) && (selected.name === "*" || selected.name === tool.name);
51
+ }
52
+ function permits(scope2, tool) {
53
+ if (!validName(tool.name) || tool.kind === "mcp" && !SERVER_NAME.test(tool.server)) return false;
54
+ return (scope2?.allow === void 0 || scope2.allow.some((selector) => matches(selector, tool))) && !scope2?.deny?.some((selector) => matches(selector, tool));
55
+ }
56
+ function allowsTool(scope2, tool) {
57
+ const parsed = parseToolScope(scope2);
58
+ return parsed.ok && permits(parsed.scope, tool);
59
+ }
60
+
7
61
  // server/env-path.ts
8
62
  import { execFile } from "node:child_process";
9
63
  import { closeSync, existsSync, openSync, readFileSync, readSync, statSync, readdirSync } from "node:fs";
@@ -63,6 +117,8 @@ function windowsKnownDirs() {
63
117
  // x.ai installer
64
118
  join(localAppData, "agy", "bin"),
65
119
  // Antigravity installer
120
+ // Cursor installer: cursor-agent.* and its `agent` copies (MOCA-272)
121
+ join(localAppData, "cursor-agent"),
66
122
  join(home, ".local", "bin"),
67
123
  // claude native installer
68
124
  join(home, ".claude", "local"),
@@ -70,7 +126,9 @@ function windowsKnownDirs() {
70
126
  // Factory droid installer (%USERPROFILE%\bin)
71
127
  join(home, ".bun", "bin"),
72
128
  join(home, ".deno", "bin"),
73
- join(home, "go", "bin")
129
+ join(home, "go", "bin"),
130
+ join(process.env.ProgramFiles ?? "C:\\Program Files", "Docker", "Docker", "resources", "bin")
131
+ // Docker Desktop installer
74
132
  ];
75
133
  }
76
134
  var cached = null;
@@ -443,21 +501,60 @@ async function stopCliTree(child2, pid, timeoutMs) {
443
501
  }
444
502
 
445
503
  // server/mcp-gate.ts
446
- var NAME = process.env.OMB_GATE_NAME || "mcp";
447
- var SPILL_DIR = process.env.OMB_GATE_SPILL_DIR || "";
448
- var BUDGET = Number(process.env.OMB_GATE_BUDGET) > 0 ? Number(process.env.OMB_GATE_BUDGET) : DEFAULT_RESULT_BUDGET;
504
+ function gateEnvironment() {
505
+ if (process.argv.length === 2) return process.env;
506
+ try {
507
+ const key = process.argv[3];
508
+ if (process.argv.length !== 4 || process.argv[2] !== "--config-env" || !key || !/^OMB_GATE_CONFIG_[a-f0-9]{64}$/.test(key)) throw new Error();
509
+ const value = JSON.parse(process.env[key] ?? "");
510
+ if (!value || typeof value !== "object" || Array.isArray(value) || !["OMB_GATE_NAME", "OMB_GATE_UPSTREAM", "OMB_GATE_TOOL_SCOPE"].every((name) => typeof value[name] === "string") || !Object.entries(value).every(([name, setting]) => GATE_ENV_KEYS.includes(name) && typeof setting === "string")) throw new Error();
511
+ return value;
512
+ } catch {
513
+ process.stderr.write("mcp-gate: invalid private configuration\n");
514
+ process.exit(1);
515
+ }
516
+ }
517
+ var GATE_ENV_KEYS = ["OMB_GATE_NAME", "OMB_GATE_SPILL_DIR", "OMB_GATE_BUDGET", "OMB_GATE_UPSTREAM", "OMB_GATE_SPILL_HINT", "OMB_GATE_TOOL_SCOPE"];
518
+ var gateEnv = gateEnvironment();
519
+ var NAME = gateEnv.OMB_GATE_NAME || "mcp";
520
+ var SPILL_DIR = gateEnv.OMB_GATE_SPILL_DIR || "";
521
+ var rawBudget = Number(gateEnv.OMB_GATE_BUDGET);
522
+ var BUDGET = Number.isFinite(rawBudget) && rawBudget >= 0 ? rawBudget : DEFAULT_RESULT_BUDGET;
449
523
  var SPILL_MAX_AGE_MS = 24 * 60 * 6e4;
450
- var SPILL_HINT = process.env.OMB_GATE_SPILL_HINT === "1";
451
- var GATE_ENV_KEYS = ["OMB_GATE_NAME", "OMB_GATE_SPILL_DIR", "OMB_GATE_BUDGET", "OMB_GATE_UPSTREAM", "OMB_GATE_SPILL_HINT"];
524
+ var SPILL_HINT = gateEnv.OMB_GATE_SPILL_HINT === "1";
452
525
  function fail(message) {
453
526
  process.stderr.write(`mcp-gate(${NAME}): ${message}
454
527
  `);
455
528
  process.exit(1);
456
529
  }
530
+ function toolScope() {
531
+ const raw = gateEnv.OMB_GATE_TOOL_SCOPE;
532
+ if (raw === void 0) return;
533
+ let value;
534
+ try {
535
+ value = JSON.parse(raw);
536
+ } catch {
537
+ fail("invalid tool selection JSON");
538
+ }
539
+ const parsed = parseToolScope(value);
540
+ if (!parsed.ok || parsed.scope === void 0) fail("invalid tool selection; check the bot's Access settings");
541
+ if (!/^[a-z][a-z0-9_-]{0,31}$/.test(NAME)) fail("invalid MCP server identity for tool selection");
542
+ return parsed.scope;
543
+ }
544
+ function isRecord(value) {
545
+ return !!value && typeof value === "object" && !Array.isArray(value);
546
+ }
547
+ function requestKey(id) {
548
+ return typeof id === "string" || typeof id === "number" && Number.isFinite(id) ? `${typeof id}:${id}` : void 0;
549
+ }
550
+ function rejectRequest(id, code, message) {
551
+ process.stdout.write(`${JSON.stringify({ jsonrpc: "2.0", id: requestKey(id) ? id : null, error: { code, message } })}
552
+ `);
553
+ }
457
554
  function upstreamSpec() {
458
555
  let parsed;
459
556
  try {
460
- parsed = JSON.parse(process.env.OMB_GATE_UPSTREAM ?? "");
557
+ parsed = JSON.parse(gateEnv.OMB_GATE_UPSTREAM ?? "");
461
558
  } catch {
462
559
  fail("OMB_GATE_UPSTREAM is not valid JSON");
463
560
  }
@@ -499,6 +596,7 @@ function spill(tool, text) {
499
596
  }
500
597
  }
501
598
  function trimCallResult(result, tool) {
599
+ if (BUDGET === 0) return false;
502
600
  const content = result.content;
503
601
  if (!Array.isArray(content)) return false;
504
602
  const textBlocks = content.filter(
@@ -521,10 +619,11 @@ function trimCallResult(result, tool) {
521
619
  }
522
620
  return trimmed;
523
621
  }
622
+ var scope = toolScope();
524
623
  var spec = upstreamSpec();
525
624
  if (SPILL_DIR) sweepSpill(SPILL_DIR);
526
625
  var childEnv = { ...process.env, ...spec.env };
527
- for (const key of GATE_ENV_KEYS) delete childEnv[key];
626
+ for (const key of Object.keys(childEnv)) if (key.startsWith("OMB_GATE_")) delete childEnv[key];
528
627
  var resolved = resolveCliSpawn(spec.command, spec.args ?? []);
529
628
  var child = spawn2(resolved.command, resolved.args, {
530
629
  stdio: ["pipe", "pipe", "pipe"],
@@ -556,14 +655,35 @@ child.on("error", (error) => {
556
655
  child.stderr.pipe(process.stderr);
557
656
  var pending = /* @__PURE__ */ new Map();
558
657
  createInterface({ input: process.stdin }).on("line", (line) => {
658
+ let message;
559
659
  if (line.trim()) {
560
660
  try {
561
- const message = JSON.parse(line);
562
- if (message.method === "tools/call" && message.id !== void 0 && message.id !== null) {
563
- const params = message.params;
564
- pending.set(String(message.id), typeof params?.name === "string" ? params.name : "tool");
565
- }
661
+ const parsed = JSON.parse(line);
662
+ if (isRecord(parsed)) message = parsed;
566
663
  } catch {
664
+ if (scope) return rejectRequest(null, -32700, "Invalid JSON-RPC frame");
665
+ }
666
+ if (scope && (!message || message.jsonrpc !== "2.0")) return rejectRequest(message?.id, -32600, "Invalid JSON-RPC frame");
667
+ }
668
+ const id = requestKey(message?.id);
669
+ const params = isRecord(message?.params) ? message.params : void 0;
670
+ if (scope && message?.method === "tools/call") {
671
+ if (!id || typeof params?.name !== "string" || params.arguments !== void 0 && !isRecord(params.arguments)) {
672
+ return rejectRequest(message.id, -32602, "Invalid tool call");
673
+ }
674
+ if (!allowsTool(scope, { kind: "mcp", server: NAME, name: params.name })) {
675
+ return rejectRequest(message.id, -32602, "Tool selection excludes this tool. Check the bot's Access settings.");
676
+ }
677
+ }
678
+ if (scope && message?.method === "tools/list" && !id) {
679
+ return rejectRequest(message.id, -32600, "Tool listing needs a request ID");
680
+ }
681
+ if (id && typeof message?.method === "string") {
682
+ if (scope && pending.has(id)) fail("duplicate request ID on a restricted connection");
683
+ if (message.method === "tools/call") {
684
+ pending.set(id, { kind: "call", tool: typeof params?.name === "string" ? params.name : "tool" });
685
+ } else if (scope) {
686
+ pending.set(id, { kind: message.method === "tools/list" ? "list" : "other" });
567
687
  }
568
688
  }
569
689
  child.stdin.write(`${line}
@@ -574,24 +694,36 @@ createInterface({ input: child.stdout }).on("line", (line) => {
574
694
  if (!line.trim()) return;
575
695
  let message;
576
696
  try {
577
- message = JSON.parse(line);
697
+ const parsed = JSON.parse(line);
698
+ if (isRecord(parsed)) message = parsed;
578
699
  } catch {
700
+ if (scope) fail("unreadable upstream frame on a restricted connection");
701
+ }
702
+ if (!message || scope && message.jsonrpc !== "2.0") {
703
+ if (scope) fail("invalid upstream frame on a restricted connection");
579
704
  process.stdout.write(`${line}
580
705
  `);
581
706
  return;
582
707
  }
583
- const id = message.id === void 0 || message.id === null ? void 0 : String(message.id);
584
- const tool = id === void 0 ? void 0 : pending.get(id);
708
+ const id = typeof message.method === "string" ? void 0 : requestKey(message.id);
709
+ const request = id === void 0 ? void 0 : pending.get(id);
710
+ if (scope && id !== void 0 && !request) fail("unrequested upstream response on a restricted connection");
585
711
  if (id !== void 0) pending.delete(id);
586
712
  const result = message.result;
587
- if (tool && result && typeof result === "object" && !Array.isArray(result)) {
713
+ if (scope && request?.kind === "list" && message.error === void 0) {
714
+ if (!isRecord(result) || !Array.isArray(result.tools) || !result.tools.every((tool) => isRecord(tool) && typeof tool.name === "string" && tool.name.trim().length > 0) || result.nextCursor !== void 0 && typeof result.nextCursor !== "string") {
715
+ return rejectRequest(message.id, -32603, "Invalid tool catalog on a restricted connection");
716
+ }
717
+ result.tools = result.tools.filter((tool) => allowsTool(scope, { kind: "mcp", server: NAME, name: tool.name }));
718
+ }
719
+ if (request?.kind === "call" && isRecord(result)) {
588
720
  try {
589
- if (trimCallResult(result, tool)) {
590
- process.stderr.write(`mcp-gate(${NAME}): trimmed ${tool} to ${BUDGET} chars
721
+ if (trimCallResult(result, request.tool)) {
722
+ process.stderr.write(`mcp-gate(${NAME}): trimmed ${request.tool} to ${BUDGET} chars
591
723
  `);
592
724
  }
593
725
  } catch (error) {
594
- process.stderr.write(`mcp-gate(${NAME}): could not trim ${tool}: ${String(error)}
726
+ process.stderr.write(`mcp-gate(${NAME}): could not trim ${request.tool}: ${String(error)}
595
727
  `);
596
728
  process.stdout.write(`${line}
597
729
  `);