@minhspark/codex-mcp-bridge 1.26.8 → 1.26.9

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codex-mcp-bridge",
3
- "version": "1.26.8",
3
+ "version": "1.26.9",
4
4
  "description": "Connect ChatGPT to your own Codex Desktop projects and conversations.",
5
5
  "author": {
6
6
  "name": "Bui Dang Minh"
package/CHANGELOG.md CHANGED
@@ -4,6 +4,26 @@ Follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and [SemVer](ht
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [1.26.9] - 2026-11-03
8
+
9
+ ### Fixed
10
+
11
+ - Shorten the "Applying managed settings" step of `npx @minhspark/codex-mcp-bridge@latest`. Each Codex `mcp` command takes several seconds to start on a machine with many MCP servers and plugins, and one update ran about sixteen of them. The Codex installers now read their own entry with one `codex mcp get` instead of listing every server first, the verification reads all three registrations from a single `codex mcp list`, and the updater no longer runs a second, separate verification process after setup has already verified the saved settings.
12
+ - Show which component the updater is configuring while managed settings are applied, instead of a single line that looked frozen for a minute or more.
13
+ - Stop reporting `MCP registration is missing` for `claude-bridge`, `codex-native-relay` and `antigravity-bridge` when Codex CLI was merely too slow to answer. A slow inventory now says so, and the three registrations are reported as not checked. Codex `mcp` commands used by setup may take up to 120 seconds instead of 30, so a busy computer no longer fails an otherwise complete update.
14
+
15
+ ### Verification
16
+
17
+ - Regression coverage checks that verification makes exactly one Codex inventory call, that only Codex's own "No MCP server named" error counts as an absent entry, that a timed-out inventory is reported as unchecked, and that the updater runs setup once and relays only its progress lines.
18
+
19
+ ### Upgrade
20
+
21
+ ```powershell
22
+ npx.cmd -y @minhspark/codex-mcp-bridge@latest
23
+ ```
24
+
25
+ This command runs the 1.26.9 updater itself, so the shorter sequence applies to this update.
26
+
7
27
  ## [1.26.8] - 2026-11-03
8
28
 
9
29
  ### Fixed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@minhspark/codex-mcp-bridge",
3
- "version": "1.26.8",
3
+ "version": "1.26.9",
4
4
  "description": "Connect Claude, Codex, and Antigravity through MCP, with native Desktop handoffs and bridge-owned Antigravity CLI sessions.",
5
5
  "keywords": [
6
6
  "mcp",
package/plugin.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
3
3
  "name": "codex-mcp-bridge",
4
- "version": "1.26.8",
4
+ "version": "1.26.9",
5
5
  "description": "Connect ChatGPT to your own Codex Desktop projects and conversations.",
6
6
  "author": {
7
7
  "name": "Bui Dang Minh",
@@ -4,7 +4,7 @@ import fs from "node:fs";
4
4
  import path from "node:path";
5
5
  import { fileURLToPath } from "node:url";
6
6
  import { randomUUID } from "node:crypto";
7
- import { applyStdioMcpRegistration, stdioMcpRegistration } from "../src/codex-mcp-registration.mjs";
7
+ import { applyStdioMcpRegistration, CODEX_MCP_TIMEOUT_MS, readCodexMcpServer, stdioMcpRegistration } from "../src/codex-mcp-registration.mjs";
8
8
  import { bridgeEntrypointConflict, isBridgeSource, isMainModule, isNodeLauncher, stableInstallPath, stableNodeBin } from "../src/install-paths.mjs";
9
9
  import { backupRegularConfigFile } from "../src/project-policy.mjs";
10
10
  import { homeDir, resolveCodexBin, spawnEnv } from "../src/platform.mjs";
@@ -256,10 +256,8 @@ export function runAntigravityInstaller(args = process.argv.slice(2), { prepareR
256
256
  let codexExisting = null;
257
257
  if (options.targets.includes("codex")) {
258
258
  const codexBin = validateCodexExecutable(resolveCodexBin(process.env.CODEX_EXE));
259
- run = (command) => execFileSync(codexBin, command, { encoding: "utf8", env: spawnEnv(), windowsHide: true, shell: false, timeout: 30000, stdio: "pipe" });
260
- const inventory = JSON.parse(run(["mcp", "list", "--json"]));
261
- if (!Array.isArray(inventory)) throw new Error("Codex returned an invalid MCP inventory");
262
- if (inventory.some((item) => item.name === NAME)) codexExisting = JSON.parse(run(["mcp", "get", NAME, "--json"]));
259
+ run = (command) => execFileSync(codexBin, command, { encoding: "utf8", env: spawnEnv(), windowsHide: true, shell: false, timeout: CODEX_MCP_TIMEOUT_MS, stdio: "pipe" });
260
+ codexExisting = readCodexMcpServer(run, NAME);
263
261
  }
264
262
  const plan = planAntigravityInstallation({ ...options, home, root, node, codexExisting });
265
263
  if (!options.remove) {
@@ -7,7 +7,7 @@ import { fileURLToPath } from "node:url";
7
7
  import { PLATFORM_LABEL, resolveCodexBin, spawnEnv } from "../src/platform.mjs";
8
8
  import { exitForVersionRequest } from "../src/cli-version.mjs";
9
9
  import { desktopTasksConfigured } from "../src/native-relay.mjs";
10
- import { applyStdioMcpRegistration, codexMcpRegistration } from "../src/codex-mcp-registration.mjs";
10
+ import { applyStdioMcpRegistration, codexMcpRegistration, readCodexMcpServer } from "../src/codex-mcp-registration.mjs";
11
11
  import { createReleaseSnapshot, snapshotRoot } from "../src/release-snapshot.mjs";
12
12
  import { codexAccessPaths, enableCodexFullAccess, fullAccessEnabled } from "../src/codex-full-access.mjs";
13
13
  import { stableInstallPath, stableNodeBin } from "../src/install-paths.mjs";
@@ -37,10 +37,7 @@ if (remove) {
37
37
  process.exit(0);
38
38
  }
39
39
 
40
- const servers = JSON.parse(run(["mcp", "list", "--json"]));
41
- if (!Array.isArray(servers)) throw new Error("Codex returned an invalid MCP inventory; existing configuration was not changed");
42
- const existing = servers.some((server) => server.name === serverName)
43
- ? JSON.parse(run(["mcp", "get", serverName, "--json"])) : null;
40
+ const existing = readCodexMcpServer(run, serverName);
44
41
  const registration = codexMcpRegistration({ name: serverName, existing, node: nodeBin, entry, entryArgs, env: process.env, desktopOnly: desktopTasksConfigured() });
45
42
  createReleaseSnapshot(root, { cache: snapshotRoot({ ...process.env, ...registration.environment }) });
46
43
  const applied = applyStdioMcpRegistration({ name: serverName, registration, existing, run, configPath: codexAccessPaths().config });
@@ -17,7 +17,7 @@ import {
17
17
  spawnEnv,
18
18
  } from "../src/platform.mjs";
19
19
  import { exitForVersionRequest } from "../src/cli-version.mjs";
20
- import { applyStdioMcpRegistration, stdioMcpRegistration } from "../src/codex-mcp-registration.mjs";
20
+ import { applyStdioMcpRegistration, readCodexMcpServer, stdioMcpRegistration } from "../src/codex-mcp-registration.mjs";
21
21
  import { createReleaseSnapshot, snapshotRoot } from "../src/release-snapshot.mjs";
22
22
  import { codexAccessPaths, enableCodexFullAccess, fullAccessEnabled } from "../src/codex-full-access.mjs";
23
23
  import { stableInstallPath } from "../src/install-paths.mjs";
@@ -25,7 +25,7 @@ import { removeRelayFile } from "../src/native-relay-files.mjs";
25
25
 
26
26
  exitForVersionRequest(import.meta.url);
27
27
 
28
- const VERSION = "1.26.8";
28
+ const VERSION = "1.26.9";
29
29
  const root = stableInstallPath(path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."));
30
30
  const entry = path.join(root, "src", "mcp-supervisor.mjs");
31
31
  const entryArgs = ["native-relay-companion.mjs"];
@@ -69,10 +69,7 @@ if (!IS_MACOS && !IS_WINDOWS) {
69
69
  console.log("claude-bridge will keep using the app-server path here.");
70
70
  }
71
71
 
72
- const servers = JSON.parse(run(["mcp", "list", "--json"]));
73
- if (!Array.isArray(servers)) throw new Error("Codex returned an invalid MCP inventory; existing configuration was not changed");
74
- const existingServer = servers.some((server) => server.name === serverName)
75
- ? JSON.parse(run(["mcp", "get", serverName, "--json"])) : null;
72
+ const existingServer = readCodexMcpServer(run, serverName);
76
73
  /**
77
74
  * Registering under whichever Node happens to run this installer is what made
78
75
  * the companion unreachable on macOS: Codex Desktop rejects a peer whose
@@ -105,7 +102,7 @@ if (runtime.source === "process.execPath" && hasCodexDesktopApp()) {
105
102
  console.log("runtime shipped inside Codex Desktop if that happens.");
106
103
  }
107
104
  console.log(`registered MCP server "${serverName}" with Codex (${applied.mode === "retarget" ? "existing entry retargeted in place; its other settings were kept" : "codex mcp add"}):`);
108
- console.log(run(["mcp", "get", serverName]));
105
+ if (!process.argv.includes("--setup")) console.log(run(["mcp", "get", serverName]));
109
106
  if (applied.notice) console.log(`NOTE: ${applied.notice}`);
110
107
  else if (ensureEnvVars.length) console.log(`env_vars includes ${ensureEnvVars.join(", ")}; the temporary pipe path itself is never saved.`);
111
108
 
package/scripts/setup.mjs CHANGED
@@ -4,7 +4,8 @@ import { printSetup, runSetup, setupFailureResult } from "../src/setup.mjs";
4
4
 
5
5
  exitForVersionRequest(import.meta.url);
6
6
  try {
7
- const result = runSetup({ args: process.argv.slice(2) });
7
+ const onProgress = process.argv.includes("--progress") ? (step) => process.stderr.write(`setup-progress: ${step}\n`) : undefined;
8
+ const result = runSetup({ args: process.argv.slice(2), onProgress });
8
9
  printSetup(result, { json: process.argv.includes("--json") });
9
10
  if (result.configured === false && !result.dryRun) process.exitCode = 1;
10
11
  } catch (error) {
@@ -65,9 +65,18 @@ export function resolveUpdateNpm(env = process.env) {
65
65
  throw failure("UPDATE_NPM_NOT_FOUND", "A supported npm CLI could not be located. Run this updater through npm exec.", "preflight");
66
66
  }
67
67
 
68
- function execute(command, args, options) {
68
+ const SETUP_PROGRESS = /^setup-progress: ([^\u0000-\u001f\u007f]{1,120})$/;
69
+
70
+ function execute(command, args, { onStderrLine, ...options }) {
69
71
  return new Promise(resolve => {
70
- execFile(command, args, options, (error, stdout, stderr) => resolve({ status: error ? 1 : 0, error, stdout, stderr }));
72
+ const child = execFile(command, args, options, (error, stdout, stderr) => resolve({ status: error ? 1 : 0, error, stdout, stderr }));
73
+ if (!onStderrLine || !child.stderr) return;
74
+ let pending = "";
75
+ child.stderr.on("data", chunk => {
76
+ const lines = (pending + chunk).split(/\r?\n/);
77
+ pending = lines.pop();
78
+ for (const line of lines) onStderrLine(line);
79
+ });
71
80
  });
72
81
  }
73
82
 
@@ -141,11 +150,11 @@ export async function runUpdate({ args = [], env = process.env, platform = proce
141
150
  const prefixArgs = userPrefix ? ["--prefix", userPrefix] : [];
142
151
  let cwd = neutralDirectory([root], env);
143
152
  let childEnv = Object.fromEntries(Object.entries(env).filter(([name]) => !/^AGENT_RELAY_(?!DIRECTORY$)/i.test(name)));
144
- const command = async (arguments_, phase, timeout = 600000, environment = childEnv, setupCommand = false) => {
153
+ const command = async (arguments_, phase, timeout = 600000, environment = childEnv, setupCommand = false, onStderrLine) => {
145
154
  let result;
146
155
  try {
147
156
  result = await run(process.execPath, arguments_, { env: environment, cwd, encoding: "utf8", windowsHide: true,
148
- shell: false, timeout, maxBuffer: 8 * 1024 * 1024, stdio: ["ignore", "pipe", "pipe"] });
157
+ shell: false, timeout, maxBuffer: 8 * 1024 * 1024, stdio: ["ignore", "pipe", "pipe"], ...(onStderrLine ? { onStderrLine } : {}) });
149
158
  } catch (error) { throw childFailure({ error, stdout: error.stdout, stderr: error.stderr }, phase, setupCommand); }
150
159
  if (result?.error || (result?.status ?? result?.exitCode ?? 0) !== 0) throw childFailure(result, phase, setupCommand);
151
160
  return String(result?.stdout ?? "");
@@ -203,13 +212,13 @@ export async function runUpdate({ args = [], env = process.env, platform = proce
203
212
  await command([npm, "install", "--global", "--prefix", prefix, `${PACKAGE}@${version}`, "--ignore-scripts"],
204
213
  "installation", 600000, { ...childEnv, CODEX_BRIDGE_SKIP_SETUP: "1" });
205
214
  if (packageVersion(globalRoot) !== version) throw failure("UPDATE_VERSION_MISMATCH", "The global package version does not match the updater version. Rerun the same update command.", "verification");
206
- for (const check of [false, true]) {
207
- onProgress(check ? "Verifying the global bridge settings and owned relay runtime." : "Applying managed settings from the installed bridge.");
208
- let setup;
209
- try { setup = JSON.parse(await command([path.join(globalRoot, "scripts", "setup.mjs"), ...(check ? ["--check"] : []), "--json"], "verification", 600000, childEnv, true)); }
210
- catch (error) { if (error?.code) throw error; throw failure("UPDATE_SETUP_INCOMPLETE", `Global setup did not return a verifiable result. ${SETUP_INSPECTION} ${RETRY}`, "verification"); }
211
- if (setup?.configured !== true) throw failure("UPDATE_SETUP_INCOMPLETE", `The global bridge settings are incomplete. ${setupFailureSummary(setup) ?? SETUP_INSPECTION} ${RETRY}`, "verification");
212
- }
215
+ onProgress("Applying and verifying managed settings from the installed bridge. Each step can take up to a minute while Codex CLI reads its configuration.");
216
+ const setupProgress = line => { const step = SETUP_PROGRESS.exec(line)?.[1]; if (step) onProgress(` ${step}`); };
217
+ let setup;
218
+ try { setup = JSON.parse(await command([path.join(globalRoot, "scripts", "setup.mjs"), "--json", "--progress"], "verification", 600000, childEnv, true, setupProgress)); }
219
+ catch (error) { if (error?.code) throw error; throw failure("UPDATE_SETUP_INCOMPLETE", `Global setup did not return a verifiable result. ${SETUP_INSPECTION} ${RETRY}`, "verification"); }
220
+ if (setup?.configured !== true) throw failure("UPDATE_SETUP_INCOMPLETE", `The global bridge settings are incomplete. ${setupFailureSummary(setup) ?? SETUP_INSPECTION} ${RETRY}`, "verification");
221
+ onProgress("Verifying the owned relay runtime.");
213
222
  const service = await awaitService(globalRoot, false, "verification");
214
223
  return { updated: true, configured: true, version, previousVersion, migrated, service, opensApps: false, opensChats: false };
215
224
  }
@@ -31,7 +31,7 @@ import { BACKGROUND_WORKER_GUIDANCE, registerBackgroundTools } from "./backgroun
31
31
 
32
32
  exitForVersionRequest(import.meta.url);
33
33
 
34
- const VERSION = "1.26.8";
34
+ const VERSION = "1.26.9";
35
35
  void import("./telemetry.mjs").then(({ startUsageReporting }) => startUsageReporting({ version: VERSION })).catch(() => {});
36
36
  const FORWARD_MIN_INTERVAL_MS = 5000;
37
37
  const FORWARD_MAX_PER_SESSION = 50;
@@ -6,6 +6,27 @@ import { backupRegularConfigFile } from "./project-policy.mjs";
6
6
 
7
7
  const PRESERVED_FIELDS = ["enabled", "disabled_reason", "enabled_tools", "disabled_tools", "startup_timeout_sec", "tool_timeout_sec"];
8
8
 
9
+ export const CODEX_MCP_TIMEOUT_MS = 120000;
10
+
11
+ function missingServerError(error, name) {
12
+ const output = `${error?.stderr ?? ""}\n${error?.stdout ?? ""}\n${error?.message ?? ""}`;
13
+ return output.includes(`No MCP server named '${name}' found`);
14
+ }
15
+
16
+ export function readCodexMcpServer(run, name) {
17
+ let output;
18
+ try { output = run(["mcp", "get", name, "--json"]); }
19
+ catch (error) {
20
+ if (missingServerError(error, name)) return null;
21
+ throw error;
22
+ }
23
+ const entry = JSON.parse(output);
24
+ if (!entry || typeof entry !== "object" || Array.isArray(entry) || entry.name !== name) {
25
+ throw new Error(`Codex returned an invalid ${name} entry; existing configuration was not changed`);
26
+ }
27
+ return entry;
28
+ }
29
+
9
30
  function sameEnvironment(left = {}, right = {}) {
10
31
  const keys = (value) => Object.keys(value ?? {}).sort();
11
32
  return JSON.stringify(keys(left)) === JSON.stringify(keys(right)) && keys(left).every((key) => left[key] === right[key]);
package/src/index.mjs CHANGED
@@ -44,7 +44,7 @@ import { BACKGROUND_WORKER_GUIDANCE, registerBackgroundTools } from "./backgroun
44
44
 
45
45
  exitForVersionRequest(import.meta.url);
46
46
 
47
- const VERSION = "1.26.8";
47
+ const VERSION = "1.26.9";
48
48
  void import("./telemetry.mjs").then(({ startUsageReporting }) => startUsageReporting({ version: VERSION })).catch(() => {});
49
49
  const log = (msg) => process.stderr.write(`[codex-mcp-bridge] ${msg}\n`);
50
50
 
@@ -43,7 +43,7 @@ import { remoteCodexSocketPath, remoteNativeAdapter, remoteRequestResponse } fro
43
43
 
44
44
  exitForVersionRequest(import.meta.url);
45
45
 
46
- const VERSION = "1.26.8";
46
+ const VERSION = "1.26.9";
47
47
  const log = (msg) => process.stderr.write(`[native-relay] ${msg}\n`);
48
48
 
49
49
  function errorResponse(code, message, sent, details) {
package/src/setup.mjs CHANGED
@@ -8,6 +8,7 @@ import { resolveCodexBin, resolvePackagedCodexBin } from "./platform.mjs";
8
8
  import { readRegularConfigFile } from "./project-policy.mjs";
9
9
  import { stableInstallPath } from "./install-paths.mjs";
10
10
  import { resolveClaudeDesktopConfigRoot } from "./desktop-account-context.mjs";
11
+ import { CODEX_MCP_TIMEOUT_MS } from "./codex-mcp-registration.mjs";
11
12
 
12
13
  const ROOT = stableInstallPath(path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."));
13
14
  const CODEX_PACKAGE = "@openai/codex@0.166.0";
@@ -64,7 +65,7 @@ export function setupFailureSummary(value) {
64
65
  }
65
66
 
66
67
  export function setupArguments(args) {
67
- const allowed = new Set(["--postinstall", "--check", "--dry-run", "--json", "--no-download", "--help"]);
68
+ const allowed = new Set(["--postinstall", "--check", "--dry-run", "--json", "--no-download", "--progress", "--help"]);
68
69
  if (args.some((arg) => !allowed.has(arg))) throw new Error("Unknown setup option; use codex-bridge-setup --help");
69
70
  if (args.includes("--check") && args.includes("--dry-run")) throw new Error("Use --check or --dry-run, not both");
70
71
  return Object.fromEntries([...allowed].map((arg) => [arg.slice(2).replace(/-([a-z])/g, (_, letter) => letter.toUpperCase()), args.includes(arg)]));
@@ -148,6 +149,13 @@ export function setupEnvironment(env, paths, codex) {
148
149
  CLAUDE_DESKTOP_CONFIG: paths.desktop, CODEX_EXE: codex, CODEX_BIN: codex };
149
150
  }
150
151
 
152
+ function codexInventoryFailure(error) {
153
+ const detail = error?.message?.includes("ETIMEDOUT") || error?.code === "ETIMEDOUT"
154
+ ? `Codex CLI did not list its MCP servers within ${CODEX_MCP_TIMEOUT_MS / 1000} seconds; the computer may be busy. Rerun the check when it is idle`
155
+ : error?.message ?? String(error);
156
+ return Object.assign(new Error(detail), error?.code ? { code: error.code } : {});
157
+ }
158
+
151
159
  function configurationCheck(label, check, components) {
152
160
  try { const details = check(); components.push({ name: label, status: "configured", ...details }); }
153
161
  catch (error) { components.push(failedComponent(label, error)); }
@@ -171,15 +179,16 @@ export function checkSetup({ env = process.env, platform = process.platform, roo
171
179
  let inventory;
172
180
  configurationCheck("Codex CLI", () => {
173
181
  codex = ensureSetupCodex({ env, paths, platform, download: false, run, resolve }).binary;
174
- inventory = JSON.parse(run(codex, ["mcp", "list", "--json"], setupEnvironment(env, paths, codex), 30000));
175
- if (!Array.isArray(inventory)) throw new Error("Codex returned an invalid MCP inventory");
182
+ try { inventory = JSON.parse(run(codex, ["mcp", "list", "--json"], setupEnvironment(env, paths, codex), CODEX_MCP_TIMEOUT_MS)); }
183
+ catch (error) { throw codexInventoryFailure(error); }
184
+ if (!Array.isArray(inventory)) { inventory = undefined; throw new Error("Codex returned an invalid MCP inventory"); }
176
185
  }, components);
177
186
  const native = platform === "win32" || platform === "darwin";
178
187
  for (const [name, worker] of [["claude-bridge", "claude-bridge.mjs"], ...(native ? [["codex-native-relay", "native-relay-companion.mjs"]] : []), ["antigravity-bridge", "antigravity-bridge.mjs"]]) {
179
188
  configurationCheck(`Codex / ${name}`, () => {
180
- const item = inventory?.find((server) => server.name === name);
181
- if (!item) throw new Error("MCP registration is missing");
182
- const entry = JSON.parse(run(codex, ["mcp", "get", name, "--json"], setupEnvironment(env, paths, codex), 30000));
189
+ if (!inventory) throw new Error("Not checked because Codex CLI did not report its MCP servers; the registration may still be present");
190
+ const entry = inventory.find((server) => server?.name === name);
191
+ if (!entry) throw new Error("MCP registration is missing");
183
192
  const details = assertEntry({ ...entry.transport, enabled: entry.enabled }, worker, root, name === "antigravity-bridge" ? { caller: "codex" } : {});
184
193
  if (name === "codex-native-relay" && !entry.transport.env_vars?.includes("CODEX_APP_TOOLS_PIPE_PATH")) throw new Error("Native pipe forwarding is missing");
185
194
  return details;
@@ -228,7 +237,7 @@ export function checkSetup({ env = process.env, platform = process.platform, roo
228
237
  return { configured: components.every((item) => item.status === "configured"), liveVerified: false, components };
229
238
  }
230
239
 
231
- export function runSetup({ args = [], env = process.env, platform = process.platform, root = ROOT, run = execute, resolve = resolveCodexBin } = {}) {
240
+ export function runSetup({ args = [], env = process.env, platform = process.platform, root = ROOT, run = execute, resolve = resolveCodexBin, onProgress = () => {} } = {}) {
232
241
  const options = setupArguments(args);
233
242
  if (options.help) return { help: `Usage: codex-bridge-setup [--check|--dry-run] [--json] [--no-download]\nUpdate the package and apply managed settings in an interactive terminal with: ${platform === "win32" ? "npx.cmd" : "npx"} -y @minhspark/codex-mcp-bridge@latest\nThe updater installs the package with lifecycle scripts disabled, then directly configures Claude Desktop, Claude Code, Codex, Antigravity and the independent worker relay. CODEX_BRIDGE_SKIP_SETUP=1 opts out. Saved configuration, background relay health and loaded native app connections are verified separately.` };
234
243
  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." };
@@ -243,6 +252,7 @@ export function runSetup({ args = [], env = process.env, platform = process.plat
243
252
  const base = setupEnvironment(env, paths, runtime.binary);
244
253
  const components = [];
245
254
  const install = (name, script, arguments_, environment = base) => {
255
+ onProgress(name);
246
256
  try {
247
257
  const output = run(process.execPath, [path.join(root, "scripts", script), ...arguments_], environment, 180000);
248
258
  let details = {};
@@ -265,6 +275,7 @@ export function runSetup({ args = [], env = process.env, platform = process.plat
265
275
  install("Codex / claude-bridge", "install-codex-mcp.mjs", ["--setup"]);
266
276
  if (code) install("Antigravity / all components", "install-antigravity-bridge.mjs", ["--all", "--setup"]);
267
277
  install("Independent background relay", "setup-background-relay.mjs", ["--json"]);
278
+ onProgress("Verifying saved settings");
268
279
  const inspection = checkSetup({ env: base, platform, root, run, resolve: () => runtime.binary });
269
280
  return { configured: components.every((item) => item.status === "configured") && inspection.configured, liveVerified: false,
270
281
  cliInstalled: runtime.installed, components, verification: inspection.components,