@minhspark/codex-mcp-bridge 1.25.3 → 1.26.0
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/.codex-plugin/plugin.json +1 -1
- package/CHANGELOG.md +31 -0
- package/README.md +45 -20
- package/docs/new-macos-setup.md +47 -21
- package/docs/new-windows-setup.md +34 -9
- package/docs/project-onboarding.md +21 -8
- package/package.json +2 -1
- package/plugin.json +1 -1
- package/scripts/background-relay-hidden.vbs +11 -0
- package/scripts/install-antigravity-bridge.mjs +26 -14
- package/scripts/install-background-relay.mjs +428 -0
- package/scripts/install-native-relay.mjs +1 -1
- package/scripts/setup-background-relay.mjs +58 -0
- package/scripts/worker-relay.mjs +41 -0
- package/src/antigravity-bridge.mjs +18 -3
- package/src/antigravity-cli.mjs +13 -2
- package/src/antigravity-outbound-bridge.mjs +27 -6
- package/src/antigravity-outbound-targets.mjs +59 -4
- package/src/background-antigravity-worker.mjs +192 -0
- package/src/background-claude-worker.mjs +240 -0
- package/src/background-codex-worker.mjs +344 -0
- package/src/background-relay-client.mjs +107 -0
- package/src/background-relay-config.mjs +98 -0
- package/src/background-relay-daemon.mjs +60 -0
- package/src/background-relay-mcp.mjs +45 -0
- package/src/background-relay-protocol.mjs +54 -0
- package/src/background-relay-registration.mjs +198 -0
- package/src/background-relay-service.mjs +311 -0
- package/src/background-relay-storage.mjs +203 -0
- package/src/background-relay-storage.ps1 +64 -0
- package/src/background-relay.mjs +373 -0
- package/src/claude-bridge.mjs +6 -3
- package/src/index.mjs +7 -2
- package/src/mcp-supervisor.mjs +17 -11
- package/src/native-relay-companion.mjs +1 -1
- package/src/reload-control.mjs +2 -2
- package/src/setup.mjs +26 -9
- 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
|
-
|
|
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 =
|
|
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
|
|
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
|
|
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 } = {}) {
|
package/src/windows-pipe-acl.ps1
CHANGED
|
@@ -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_.-]
|
|
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;
|