@minhspark/codex-mcp-bridge 1.25.3 → 1.26.1

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 (38) hide show
  1. package/.codex-plugin/plugin.json +1 -1
  2. package/CHANGELOG.md +47 -0
  3. package/README.md +45 -20
  4. package/docs/new-macos-setup.md +47 -21
  5. package/docs/new-windows-setup.md +34 -9
  6. package/docs/project-onboarding.md +21 -8
  7. package/package.json +2 -1
  8. package/plugin.json +1 -1
  9. package/scripts/background-relay-hidden.vbs +11 -0
  10. package/scripts/install-antigravity-bridge.mjs +26 -14
  11. package/scripts/install-background-relay.mjs +437 -0
  12. package/scripts/install-native-relay.mjs +1 -1
  13. package/scripts/setup-background-relay.mjs +58 -0
  14. package/scripts/worker-relay.mjs +41 -0
  15. package/src/antigravity-bridge.mjs +18 -3
  16. package/src/antigravity-cli.mjs +13 -2
  17. package/src/antigravity-outbound-bridge.mjs +27 -6
  18. package/src/antigravity-outbound-targets.mjs +59 -4
  19. package/src/background-antigravity-worker.mjs +192 -0
  20. package/src/background-claude-worker.mjs +240 -0
  21. package/src/background-codex-worker.mjs +344 -0
  22. package/src/background-relay-client.mjs +107 -0
  23. package/src/background-relay-config.mjs +98 -0
  24. package/src/background-relay-daemon.mjs +60 -0
  25. package/src/background-relay-mcp.mjs +45 -0
  26. package/src/background-relay-protocol.mjs +54 -0
  27. package/src/background-relay-registration.mjs +198 -0
  28. package/src/background-relay-service.mjs +311 -0
  29. package/src/background-relay-storage.mjs +203 -0
  30. package/src/background-relay-storage.ps1 +64 -0
  31. package/src/background-relay.mjs +373 -0
  32. package/src/claude-bridge.mjs +6 -3
  33. package/src/index.mjs +7 -2
  34. package/src/mcp-supervisor.mjs +17 -11
  35. package/src/native-relay-companion.mjs +1 -1
  36. package/src/reload-control.mjs +2 -2
  37. package/src/setup.mjs +26 -9
  38. package/src/windows-pipe-acl.ps1 +1 -1
package/src/setup.mjs CHANGED
@@ -46,14 +46,23 @@ function execute(command, args, env, timeout = 120000) {
46
46
  const result = spawnSync(command, args, { env, encoding: "utf8", windowsHide: true, shell: false, timeout,
47
47
  maxBuffer: 4 * 1024 * 1024, stdio: ["ignore", "pipe", "pipe"] });
48
48
  if (result.error || result.status !== 0) {
49
- const lines = String(result.stderr || "").split(/\r?\n/).filter((line) => /^Error:|^(?:Expected|Refusing|Invalid|Unknown|Shared|Claude|Codex|Configuration|The existing|Missing|Unsafe)/.test(line)
50
- && !/Command failed|--env|password|secret|token|authorization/i.test(line));
51
- const detail = lines.slice(0, 3).join(" ") || result.error?.code || `exit ${result.status}`;
52
- throw new Error(`${path.basename(command)} ${path.basename(args[0] ?? "")}: ${detail}`);
49
+ throw setupProcessFailure(command, args, result);
53
50
  }
54
51
  return result.stdout || "";
55
52
  }
56
53
 
54
+ export function setupProcessFailure(command, args, result) {
55
+ let structured;
56
+ try { structured = JSON.parse(String(result.stdout || "")); } catch {}
57
+ const validCode = value => typeof value === "string" && /^[A-Z][A-Z0-9_]{0,79}$/.test(value);
58
+ const codes = [structured?.code, structured?.service?.code, structured?.permissions?.code, structured?.diagnostic?.code,
59
+ ...String(result.stderr || "").split(/\r?\n/).map(line => /^([A-Z][A-Z0-9_]{0,79}) \| /.exec(line)?.[1])].filter(validCode);
60
+ const lines = String(result.stderr || "").split(/\r?\n/).filter(line => /^Error:|^(?:Expected|Refusing|Invalid|Unknown|Shared|Claude|Codex|Configuration|The existing|Missing|Unsafe)/.test(line)
61
+ && !/Command failed|--env|password|secret|token|authorization/i.test(line));
62
+ const detail = [...new Set(codes)].join(", ") || lines.slice(0, 3).join(" ") || result.error?.code || `exit ${result.status}`;
63
+ return Object.assign(new Error(`${path.basename(command)} ${path.basename(args[0] ?? "")}: ${detail}`), codes[0] ? { code: codes[0] } : {});
64
+ }
65
+
57
66
  function usableBinary(binary, platform) {
58
67
  return typeof binary === "string" && path.isAbsolute(binary) && fs.existsSync(binary)
59
68
  && fs.statSync(binary).isFile() && (platform !== "win32" || /\.(exe|com)$/i.test(binary));
@@ -83,7 +92,7 @@ export function ensureSetupCodex({ env, paths, platform, download = true, run =
83
92
  }
84
93
 
85
94
  export function setupEnvironment(env, paths, codex) {
86
- const result = Object.fromEntries(Object.entries(env).filter(([name]) => !/^(?:CODEX_BRIDGE_|CLAUDE_BRIDGE_|CODEX_NATIVE_RELAY_|CODEX_RELAY_ID$|CODEX_THREAD_ID$|CODEX_APP_TOOLS_PIPE_PATH$)/.test(name)));
95
+ const result = Object.fromEntries(Object.entries(env).filter(([name]) => !/^(?:CODEX_BRIDGE_|CLAUDE_BRIDGE_|CODEX_NATIVE_RELAY_|CODEX_RELAY_ID$|CODEX_THREAD_ID$|CODEX_APP_TOOLS_PIPE_PATH$|AGENT_RELAY_(?:TOKEN|WORKER_ID|REQUEST_ID|ENDPOINT)$)/.test(name)));
87
96
  return { ...result, HOME: paths.home, USERPROFILE: paths.home, CODEX_HOME: paths.codex,
88
97
  CLAUDE_DESKTOP_CONFIG: paths.desktop, CODEX_EXE: codex, CODEX_BIN: codex };
89
98
  }
@@ -96,7 +105,7 @@ function configurationCheck(label, check, components) {
96
105
  function assertEntry(entry, worker, root, { caller } = {}) {
97
106
  if (!entry || typeof entry.command !== "string" || !fs.existsSync(entry.command)) throw new Error("MCP command is missing or unavailable");
98
107
  const args = entry.args ?? [];
99
- const expected = worker === "index.mjs" || worker === "claude-bridge.mjs" || worker === "native-relay-companion.mjs"
108
+ const expected = ["index.mjs", "claude-bridge.mjs", "native-relay-companion.mjs", "antigravity-bridge.mjs", "antigravity-outbound-bridge.mjs"].includes(worker)
100
109
  ? [path.join(root, "src", "mcp-supervisor.mjs"), worker] : [path.join(root, "src", worker)];
101
110
  if (JSON.stringify(args) !== JSON.stringify(expected)) throw new Error("MCP entry points to a different installation or unsupported launcher");
102
111
  if (caller && entry.env?.ANTIGRAVITY_BRIDGE_CALLER !== caller) throw new Error("Antigravity caller registration is missing or conflicting");
@@ -160,17 +169,22 @@ export function checkSetup({ env = process.env, platform = process.platform, roo
160
169
  configurationCheck("Claude registration names", () => {
161
170
  if (readJson(paths.desktop)?.mcpServers?.["codex-bridge"]) throw new Error("Shared codex-bridge shadows the Claude Code registration");
162
171
  }, components);
172
+ configurationCheck("Independent background relay", () => {
173
+ const details = JSON.parse(run(process.execPath, [path.join(root, "scripts", "setup-background-relay.mjs"), "--check", "--json"], setupEnvironment(env, paths, codex), 90000));
174
+ if (details.configured !== true) throw new Error("Independent worker relay configuration is incomplete");
175
+ return { liveVerified: details.liveVerified === true, transportReady: details.transportReady === true, notices: details.notices ?? [] };
176
+ }, components);
163
177
  return { configured: components.every((item) => item.status === "configured"), liveVerified: false, components };
164
178
  }
165
179
 
166
180
  export function runSetup({ args = [], env = process.env, platform = process.platform, root = ROOT, run = execute, resolve = resolveCodexBin } = {}) {
167
181
  const options = setupArguments(args);
168
- if (options.help) return { help: "Usage: codex-bridge-setup [--check|--dry-run] [--json] [--no-download]\nUpdate the package and apply managed settings with: npm install -g @minhspark/codex-mcp-bridge@latest --allow-scripts=@minhspark/codex-mcp-bridge\nGlobal npm installation configures Claude Desktop, Claude Code, Codex and Antigravity automatically. CODEX_BRIDGE_SKIP_SETUP=1 opts out. Saved configuration and loaded app connections are verified separately." };
182
+ if (options.help) return { help: "Usage: codex-bridge-setup [--check|--dry-run] [--json] [--no-download]\nUpdate the package and apply managed settings with: npm install -g @minhspark/codex-mcp-bridge@latest --allow-scripts=@minhspark/codex-mcp-bridge --foreground-scripts\nGlobal npm installation configures Claude Desktop, Claude Code, Codex, Antigravity and the independent worker relay automatically. CODEX_BRIDGE_SKIP_SETUP=1 opts out. Saved configuration, background relay health and loaded native app connections are verified separately." };
169
183
  if (options.postinstall && !automaticSetupEnabled(env)) return { skipped: true, reason: "Automatic configuration runs only for a global npm install; use codex-bridge-setup for manual setup." };
170
184
  if (options.check) return checkSetup({ env, platform, root, run, resolve });
171
185
  const native = platform === "win32" || platform === "darwin";
172
186
  const paths = setupPaths(env, platform);
173
- const planned = ["Claude Code / codex-bridge", "Claude Desktop / codex-bridge-desktop", ...(native ? ["Codex / codex-native-relay and executor"] : []), "Codex / claude-bridge", "Antigravity / all components"];
187
+ const planned = ["Claude Code / codex-bridge", "Claude Desktop / codex-bridge-desktop", ...(native ? ["Codex / codex-native-relay and executor"] : []), "Codex / claude-bridge", "Antigravity / all components", "Independent background relay"];
174
188
  if (options.dryRun) return { dryRun: true, configured: false, liveVerified: false, components: planned.map((name) => ({ name, status: "planned" })), files: [paths.code, paths.desktop, path.join(paths.codex, "config.toml"), paths.gemini] };
175
189
  if (env.SUDO_USER && env.SUDO_USER !== "root" && typeof process.getuid === "function" && process.getuid() === 0) throw new Error("Run the global install without sudo in the account that runs the apps; setup will not write another account's configuration.");
176
190
  const runtime = ensureSetupCodex({ env, paths, platform, download: !options.noDownload, run, resolve });
@@ -184,6 +198,7 @@ export function runSetup({ args = [], env = process.env, platform = process.plat
184
198
  try { details = JSON.parse(output); } catch {}
185
199
  const notices = details.notices ?? [];
186
200
  components.push({ name, status: "configured", ...(notices.length ? { notices } : {}),
201
+ ...(typeof details.liveVerified === "boolean" ? { liveVerified: details.liveVerified, transportReady: details.transportReady === true } : {}),
187
202
  ...(details.backgroundPreference ? { backgroundPreference: details.backgroundPreference } : {}) });
188
203
  return true;
189
204
  } catch (error) { components.push({ name, status: "incomplete", detail: error.message }); return false; }
@@ -198,13 +213,15 @@ export function runSetup({ args = [], env = process.env, platform = process.plat
198
213
  }
199
214
  install("Codex / claude-bridge", "install-codex-mcp.mjs", ["--setup"]);
200
215
  if (code) install("Antigravity / all components", "install-antigravity-bridge.mjs", ["--all", "--setup"]);
216
+ install("Independent background relay", "setup-background-relay.mjs", ["--json"]);
201
217
  const inspection = checkSetup({ env: base, platform, root, run, resolve: () => runtime.binary });
202
218
  return { configured: components.every((item) => item.status === "configured") && inspection.configured, liveVerified: false,
203
219
  cliInstalled: runtime.installed, components, verification: inspection.components,
204
220
  nextActions: ["Running MCP processes may still hold earlier settings. Setup does not start apps or open conversations.",
205
221
  "Existing compatible supervisors reload installed source when idle; configuration changes are not proof of loaded-process readiness.",
206
222
  "Native delivery uses the same saved project and signed-in accounts in Claude Desktop Code and Codex Desktop.",
207
- "codex_bridge_status, native_relay_status and agent_bridge_status report live readiness separately from this configuration check."] };
223
+ "codex_bridge_status, native_relay_status and agent_bridge_status report native readiness separately from this configuration check.",
224
+ "worker_status or worker-relay status reports the independent service and CLI workers, which do not require a responsive Desktop host."] };
208
225
  }
209
226
 
210
227
  export function printSetup(result, { json = false, output = console.log } = {}) {
@@ -1,6 +1,6 @@
1
1
  param([Parameter(Mandatory)][string]$PipeName,[Parameter(Mandatory)][uint32]$ServerPid)
2
2
  $ErrorActionPreference='Stop'
3
- if($PipeName -notmatch '^LOCAL\\(?:codex-native-relay|codex-bridge|cc-msg)-[A-Za-z0-9_.-]+$'){throw 'Refusing a pipe outside the bridge-owned namespace.'}
3
+ if($PipeName -notmatch '^LOCAL\\(?:(?:codex-native-relay|codex-bridge|cc-msg)-[A-Za-z0-9_.-]+|minhspark-agent-relay-[a-f0-9]{24})$'){throw 'Refusing a pipe outside the bridge-owned namespace.'}
4
4
  Add-Type @'
5
5
  using System;
6
6
  using System.ComponentModel;