@minhspark/codex-mcp-bridge 1.25.2 → 1.25.3
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 +27 -0
- package/README.md +38 -14
- package/package.json +1 -1
- package/plugin.json +1 -1
- package/scripts/install-antigravity-bridge.mjs +40 -10
- package/scripts/install-claude-code.mjs +2 -2
- package/scripts/install-claude-desktop.mjs +12 -7
- package/scripts/install-native-relay.mjs +2 -2
- package/scripts/setup.mjs +3 -3
- package/src/antigravity-bridge.mjs +79 -25
- package/src/antigravity-deliveries.mjs +32 -8
- package/src/antigravity-ipc.mjs +18 -9
- package/src/antigravity-outbound-bridge.mjs +46 -19
- package/src/antigravity-outbound-targets.mjs +41 -6
- package/src/bridge-readiness.mjs +2 -2
- package/src/claude-bridge.mjs +38 -23
- package/src/claude-code-registration.mjs +2 -1
- package/src/claude-session-router.mjs +8 -15
- package/src/index.mjs +33 -21
- package/src/mcp-supervisor.mjs +10 -6
- package/src/native-relay-companion.mjs +4 -1
- package/src/native-relay.mjs +5 -1
- package/src/peer-protocol.mjs +9 -6
- package/src/recipient-preflight.mjs +81 -0
- package/src/setup.mjs +38 -18
- package/src/thread-delivery.mjs +10 -5
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,33 @@ Follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and [SemVer](ht
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [1.25.3] - 2026-11-01
|
|
8
|
+
|
|
9
|
+
### Upgrade
|
|
10
|
+
|
|
11
|
+
One command updates the package and reapplies managed settings for all clients:
|
|
12
|
+
|
|
13
|
+
```sh
|
|
14
|
+
npm install -g @minhspark/codex-mcp-bridge@latest --allow-scripts=@minhspark/codex-mcp-bridge --foreground-scripts
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
On Windows PowerShell use `npm.cmd` in place of `npm`. Setup reports saved configuration separately from live host readiness and never opens apps or chats to load a relay.
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
|
|
21
|
+
- Normal Codex task creation and delivery no longer navigate or activate the Desktop window by default, including on Windows. Explicit `openInApp: true` remains available. Comprehensive install/update migrates historical automatic navigation settings to the silent default.
|
|
22
|
+
- The native relay refuses navigation to its internal executor, which has no user conversation history and must not be opened as a task.
|
|
23
|
+
- Claude endpoint rediscovery from Codex and Antigravity no longer opens apps or saved chats to load a relay. A dormant native task reports `CLAUDE_SESSION_NOT_READY` with `sent: false`; an endpoint that becomes available is revalidated against the current account, process, directory and native permission policy.
|
|
24
|
+
- Antigravity inbound MCP instructions now describe the existing outbound `agent-bridge` instead of incorrectly claiming that Antigravity cannot send to Codex or Claude. Status reports distinguish supported Desktop routes from unverified outbound readiness and retain the CLI and automatic-reply-forwarding limits.
|
|
25
|
+
- An unreachable Antigravity sidecar now reports a connectivity problem without assuming the App is closed, and points callers to the sidecar diagnostics when the App is already running.
|
|
26
|
+
- Relay and tool failures include a readable diagnostic block and structured report with the exact error/cause codes, operation, phase, bridge/Node/platform versions, UTC time, report ID and safe request identifiers. Credential and private-path redaction applies to the report block. Uncertain sends remain uncertain and are never automatically replayed.
|
|
27
|
+
- Antigravity IPC and durable delivery records preserve original failure codes and reports; failed or unknown receipt reads are surfaced as errors instead of successful-looking results. Supervisor crashes distinguish in-flight unknown delivery from a new request refused before dispatch.
|
|
28
|
+
- The same one-command npm install/update applies managed settings for all clients, shows setup progress, and fails if configuration is incomplete. It enables supported native background preferences without changing accounts or permissions and distinguishes saved configuration from unverified running-client activation.
|
|
29
|
+
|
|
30
|
+
### Limitations
|
|
31
|
+
|
|
32
|
+
- Background delivery still requires the native host process and its loaded bridge. Closing a window can retain these processes; fully quitting a native host cannot provide an always-ready endpoint. An unloaded Codex MCP or dormant Claude Code process has no supported silent cold-start path in this bridge. Recovery never opens old, new, empty or failed chats, uses Computer Use, or launches a substitute CLI/app-server.
|
|
33
|
+
|
|
7
34
|
## [1.25.2] - 2026-10-31
|
|
8
35
|
|
|
9
36
|
### Fixed
|
package/README.md
CHANGED
|
@@ -30,18 +30,18 @@ One global npm command installs the package and configures the local Claude, Cod
|
|
|
30
30
|
**macOS / Linux / WSL**
|
|
31
31
|
|
|
32
32
|
```bash
|
|
33
|
-
npm install -g @minhspark/codex-mcp-bridge@latest --allow-scripts=@minhspark/codex-mcp-bridge
|
|
33
|
+
npm install -g @minhspark/codex-mcp-bridge@latest --allow-scripts=@minhspark/codex-mcp-bridge --foreground-scripts
|
|
34
34
|
```
|
|
35
35
|
|
|
36
36
|
**Windows PowerShell**
|
|
37
37
|
|
|
38
38
|
```powershell
|
|
39
|
-
npm.cmd install -g @minhspark/codex-mcp-bridge@latest --allow-scripts=@minhspark/codex-mcp-bridge
|
|
39
|
+
npm.cmd install -g @minhspark/codex-mcp-bridge@latest --allow-scripts=@minhspark/codex-mcp-bridge --foreground-scripts
|
|
40
40
|
```
|
|
41
41
|
|
|
42
|
-
Requires **Node.js 22.13+**. Use `.cmd` for this package's commands in Windows PowerShell.
|
|
42
|
+
Requires **Node.js 22.13+**. Use `.cmd` for this package's commands in Windows PowerShell. **Every release uses this same single install/update command.** It updates the package, applies the managed bridge settings across Claude, Codex and Antigravity, and verifies the saved registrations. Comprehensive setup migrates historical automatic Codex navigation to `CODEX_BRIDGE_OPEN_IN_APP=0`, enables Claude's native background preference and updates Antigravity's existing Windows background preference where supported. Accounts, permissions, project grants and unrelated custom registrations remain unchanged. If a native Codex CLI is missing, setup installs a pinned official `@openai/codex` package in the current user's `~/.config/GptClaudeBridge/tools` (or the corresponding `XDG_CONFIG_HOME` path); no separate CLI install command is needed.
|
|
43
43
|
|
|
44
|
-
`--allow-scripts=@minhspark/codex-mcp-bridge` authorizes only this package's setup hook. npm versions that block install scripts by default need this flag; a plain install works only when the hook is allowed.
|
|
44
|
+
`--allow-scripts=@minhspark/codex-mcp-bridge` authorizes only this package's setup hook. npm versions that block install scripts by default need this flag; a plain install works only when the hook is allowed. `--foreground-scripts` displays configuration progress and failures that npm otherwise hides. If npm prints `1 package had install scripts blocked`, rerun the recommended command or run `codex-bridge-setup` explicitly.
|
|
45
45
|
|
|
46
46
|
| Client | Installed entry | Purpose |
|
|
47
47
|
| --- | --- | --- |
|
|
@@ -52,19 +52,19 @@ Requires **Node.js 22.13+**. Use `.cmd` for this package's commands in Windows P
|
|
|
52
52
|
| Codex and Claude Code | `antigravity-bridge` | Send to Antigravity App or bridge-owned CLI sessions |
|
|
53
53
|
| Antigravity | `agent-bridge` and `codex-bridge` sidecar | Outbound agent messages and native App connectivity |
|
|
54
54
|
|
|
55
|
-
|
|
55
|
+
For native Claude-to-Codex handoffs, use an existing native Claude **Code** session and the same local project saved in Codex Desktop. The shared `codex-bridge-desktop` connector has its own legacy route; it does not establish a native Code sender identity. Setup applies saved configuration without opening or restarting apps. Saved configuration is not proof of a live connection; available supervisors reload compatible workers when idle. Complete [verification](#verify-the-installation) with the tools already available in the actual clients. If a native host is unloaded, report the diagnostic instead of opening chats to load a relay.
|
|
56
56
|
|
|
57
57
|
Automatic setup runs only for a **global npm install**. Local `npm install` and `npm ci` do not change app settings. Set `CODEX_BRIDGE_SKIP_SETUP=1`, or pass `--ignore-scripts`, to install the package without configuring apps. The optional [workflow skill](#workflow-skill--npx-skills), VS Code preview, and hosted ChatGPT pairing retain their separate setup steps.
|
|
58
58
|
|
|
59
59
|
### Setup recovery and checks
|
|
60
60
|
|
|
61
|
-
If an app configuration step fails, the
|
|
61
|
+
If an app configuration step fails, setup and the global install return a nonzero exit with the failing component. Correct its reported issue and rerun the update command above, or rerun configuration on an existing installation:
|
|
62
62
|
|
|
63
63
|
```bash
|
|
64
64
|
codex-bridge-setup
|
|
65
65
|
```
|
|
66
66
|
|
|
67
|
-
On Windows use `codex-bridge-setup.cmd`. `codex-mcp-bridge setup` is an equivalent entry point. Repeated setup
|
|
67
|
+
On Windows use `codex-bridge-setup.cmd`. `codex-mcp-bridge setup` is an equivalent entry point. Repeated setup reapplies managed bridge settings and reports conflicts rather than overwriting unrelated registrations. `configured: true` confirms saved configuration; `liveVerified: false` means running clients have not been verified to load it. Setup never opens an app or chat, uses Computer Use, or interrupts active work to load a relay. Missing or unsupported native background preferences are reported separately.
|
|
68
68
|
|
|
69
69
|
```bash
|
|
70
70
|
codex-bridge-setup --check
|
|
@@ -146,7 +146,7 @@ The `agy` CLI must be installed and signed in separately. CLI sessions are start
|
|
|
146
146
|
|
|
147
147
|
| Tool | Behavior |
|
|
148
148
|
| --- | --- |
|
|
149
|
-
| `antigravity_bridge_status` | Reports native sidecar connectivity and
|
|
149
|
+
| `antigravity_bridge_status` | Reports native sidecar connectivity, CLI capabilities, and the separate outbound Desktop route. Outbound readiness requires `agent_bridge_status` inside Antigravity. |
|
|
150
150
|
| `list_antigravity_conversations` | Lists the selected surface in the verified sender's exact project directory. |
|
|
151
151
|
| `send_to_antigravity_conversation` | Sends to an exact existing App conversation or a CLI session owned by this bridge. |
|
|
152
152
|
| `start_antigravity_cli_session` | Starts an explicitly authorized CLI streaming session with its initial prompt. |
|
|
@@ -161,6 +161,8 @@ The installer also registers **agent-bridge inside Antigravity Desktop** in `~/.
|
|
|
161
161
|
|
|
162
162
|
Outbound calls verify Antigravity's per-call MCP metadata, Desktop process ancestry, native workspace/project, and effective permission settings. The sender is attributed as Antigravity. Codex keeps its native task settings; Claude's inbound policy and permission-class checks remain in effect. A socket write to Claude is `sent_unconfirmed`, not acceptance or completion. After MCP restart, a saved receipt remains available but live Claude reply tracking may be unavailable; inspect the exact native task before further action.
|
|
163
163
|
|
|
164
|
+
If a caller says the bridge only supports one-way messaging, reload its `antigravity-bridge` MCP server after updating: older initialization instructions incorrectly denied the separate outbound route. An unavailable inbound sidecar does not prove that the App is closed or that outbound messaging is unsupported. If the App is already running, inspect its `codex-bridge` sidecar; check `agent_bridge_status` from Antigravity to verify outbound readiness independently.
|
|
165
|
+
|
|
164
166
|
Outbound support targets existing local Codex tasks and live Claude Desktop Code sessions in the same project. Nested Antigravity callers, outbound CLI callers, App conversation creation, and automatic App reply forwarding are not implemented. Windows Desktop is the live verification platform; macOS ancestry has unit coverage and Linux outbound host verification fails closed. The existing Codex↔Claude bridge remains separate. Use `antigravity-mcp-bridge-install --all --remove` to remove only these registrations; delivery receipts are retained.
|
|
165
167
|
|
|
166
168
|
### Windows (PowerShell)
|
|
@@ -276,7 +278,7 @@ codex-mcp-bridge-install.cmd --entry-name codex-bridge-desktop
|
|
|
276
278
|
CODEX_BRIDGE_DESKTOP_TASKS=0 CODEX_BRIDGE_AUTOSTART=1 codex-mcp-bridge-install --entry-name codex-bridge-desktop
|
|
277
279
|
```
|
|
278
280
|
|
|
279
|
-
|
|
281
|
+
Running clients may retain their previously loaded configuration; setup reports live activation as unverified and does not interrupt them. A fresh `--entry-name codex-bridge-desktop` registration defaults to legacy mode even when the native relay is configured. Existing custom modes are preserved. `--desktop-tasks` does not make a shared Desktop chat server a verified Code sender.
|
|
280
282
|
|
|
281
283
|
### VS Code extensions — Windows preview
|
|
282
284
|
|
|
@@ -444,7 +446,7 @@ This repository ships a hosted ChatGPT plugin and the skill above. It does not c
|
|
|
444
446
|
|
|
445
447
|
Run `codex-bridge-setup --check` (`codex-bridge-setup.cmd --check` on Windows) to inspect saved registrations. An incomplete result names the component requiring attention; rerun setup after correcting it.
|
|
446
448
|
|
|
447
|
-
|
|
449
|
+
Use the bridge tools already available in the actual clients. Configuration checks do not prove that a running client loaded new registrations. Setup does not open, kill or restart apps or chats. If a tool is unavailable, retain that exact failure for reporting. Run these **MCP tools** when available:
|
|
448
450
|
|
|
449
451
|
| Client | Tool |
|
|
450
452
|
|---|---|
|
|
@@ -667,11 +669,15 @@ For a repeatable failure, capture the app/OS/Node versions, the version reported
|
|
|
667
669
|
|
|
668
670
|
### Relay unavailable, stale pipe, or an active writer
|
|
669
671
|
|
|
672
|
+
Normal task creation and delivery run without navigating or focusing Codex Desktop. Use `openInApp: true` only when the user wants to see the target task. The comprehensive install/update command migrates older `CODEX_BRIDGE_OPEN_IN_APP=1` settings to `0`. The internal relay executor is not a user conversation and cannot be opened through the bridge.
|
|
673
|
+
|
|
674
|
+
Closing an application window and quitting its native host have different effects. Antigravity's native `runInBackground` setting keeps its sidecar running after the last window closes; Windows defaults to quitting when this setting is off. On Windows, use Codex's native startup task for background startup instead of an additional foreground `shell:AppsFolder` launcher. A healthy loaded relay can recover its worker, but cannot cold-start an unloaded Codex MCP. No periodic task-opening loop is used to simulate readiness.
|
|
675
|
+
|
|
670
676
|
**Symptoms:** `RELAY_UNAVAILABLE`, `connect ENOENT`, a missing native relay socket, or `thread ... already has an active writer`.
|
|
671
677
|
|
|
672
678
|
Native Desktop handoffs require Codex Desktop to be installed, signed in and open on Windows/macOS. The app runs `codex-native-relay` while a regular task has its MCP servers loaded. Recovery never navigates to a task, launches a window, or activates Codex. The Desktop-owned supervisor restarts crashed native relay workers with bounded exponential backoff; pending requests fail without replay, and later requests use the recovered worker. Inherited native pipe hints are rediscovered through the original Desktop process ancestry when they become stale. Requests that never reached the relay wait up to 20 seconds, within their original deadline, for its transport to recover. `CODEX_BRIDGE_RELAY_WAKE=0` disables that wait; the retired `CODEX_BRIDGE_RELAY_KEEPER` flag cannot enable UI navigation.
|
|
673
679
|
|
|
674
|
-
|
|
680
|
+
Use the available `native_relay_status` and `codex_bridge_status` tools without opening a chat to load them. Native status performs a read-only `list_projects` probe and reports native dispatch separately from socket availability. Recovery requires the original Desktop-owned supervisor to remain alive: it cannot cold-start an unloaded native MCP, and it stops when the MCP client closes. After five unsuccessful worker replacements, report the exact diagnostic. Never open an old, new, empty, failed or internal **Native Relay** chat to bootstrap readiness. Rerun setup if registration/executor configuration is missing, and verify [native relay pipe forwarding](#native-relay-pipe-forwarding). Never persist a pipe address copied from a different app process. Worker hot reload cannot replace a running supervisor from an older release; configuration success alone does not prove that process is upgraded.
|
|
675
681
|
|
|
676
682
|
An active-writer error usually identifies the legacy app-server route attempting to attach to a thread already owned by Desktop. Use the registered native Code-to-Desktop route for that conversation. Do not start another app-server or terminate shared work to force access. The ordinary `codex-bridge-desktop` Chat connector remains a legacy app-server connection; it is not a substitute for the verified native sender. An unused `CODEX_APP_SERVER_URL` alongside `external app-server disabled` is not by itself a native connection failure.
|
|
677
683
|
|
|
@@ -681,13 +687,31 @@ Use native session discovery and peer delivery from the Codex task:
|
|
|
681
687
|
|
|
682
688
|
1. Call `list_claude_sessions` with the exact absolute `expectedCwd`.
|
|
683
689
|
2. Verify the returned `entrypoint: claude-desktop`, `sessionId`, native `desktop.taskId`, and project directory. Use `read_claude_transcript` with that session identity to confirm the intended unfinished work when needed; a title alone is insufficient.
|
|
684
|
-
3. Call `send_to_claude_session` with the exact session identity as `target`, the independently verified `expectedCwd`, and the returned native ID as `expectedTaskId`.
|
|
690
|
+
3. Call `send_to_claude_session` with the exact session identity as `target`, the independently verified `expectedCwd`, and the returned native ID as `expectedTaskId`. `target: "auto"` plus `expectedTaskId` rediscovers the exact live endpoint without opening the app or chat. A dormant saved task returns `CLAUDE_SESSION_NOT_READY`, `sent: false`.
|
|
685
691
|
4. Preserve the returned `msgId`. After a timeout, inspect it with `read_claude_delivery`; read `read_claude_inbox` for late replies and correlated bridge-status notifications.
|
|
686
692
|
|
|
687
|
-
If no eligible session appears,
|
|
693
|
+
If no eligible session appears, inspect sign-in, data-root selection and sender status using available bridge diagnostics. Saved history does not prove that a native Code endpoint is running. There is no supported silent cold-start API for a dormant Claude task. The bridge reports this limitation instead of opening a chat, using Computer Use, or launching a substitute CLI. Closing a window can preserve native background work; fully quitting the native host removes its receiving endpoint.
|
|
694
|
+
|
|
695
|
+
Antigravity's `list_agent_tasks` also reports verified dormant Claude tasks with `status: "dormant"`, `recoverable: false` and `code: "CLAUDE_SESSION_NOT_READY"`. Discovery and sends never open the application or a chat to load its endpoint. Archived tasks, changed accounts, mismatched directories and uncertain sends remain blocked.
|
|
688
696
|
|
|
689
697
|
`PEER_REPLY_PENDING` protects an earlier unresolved message. A `held` receipt, `CLAUDE_RECIPIENT_INBOUND_POLICY`, or `CLAUDE_RECIPIENT_CLASS_MISMATCH` identifies an actual recipient policy/permission boundary. Inspect the original receipt and task; resolve the stated policy through the user's intended host settings. Installing a newer bridge does not authorize changing permissions. An `interrupted` bridge-status notification ends observation only: it is not Claude's answer, does not cancel background work, and does not make retrying the original action safe.
|
|
690
698
|
|
|
699
|
+
### Screenshot-ready error reports
|
|
700
|
+
|
|
701
|
+
Failures include a **Bridge diagnostic** block in the tool result and `structuredContent.diagnostic` for clients. Capture that block when filing an issue. It contains the exact error and cause codes, component, tool, phase, bridge/Node/platform versions, UTC timestamp, report ID and available request/message/delivery IDs. It excludes request prompts, tokens and account identities and redacts common credential, URL, email and private-path patterns from the error reason. Review any surrounding output before sharing it.
|
|
702
|
+
|
|
703
|
+
| Diagnostic | Meaning |
|
|
704
|
+
|---|---|
|
|
705
|
+
| `RELAY_UNREACHABLE` | Native relay transport could not be reached; this alone does not prove the app is closed. |
|
|
706
|
+
| `NATIVE_PIPE_UNAVAILABLE` | The native dispatch pipe could not be verified. |
|
|
707
|
+
| `CLAUDE_SESSION_NOT_READY` | The exact saved task has no live native Code endpoint; silent cold-start is unavailable. |
|
|
708
|
+
| `CLAUDE_RECIPIENT_INBOUND_POLICY` / `CLAUDE_RECIPIENT_CLASS_MISMATCH` | Native recipient policy or permission classes block the handoff. |
|
|
709
|
+
| `CLAUDE_REPLY_TIMEOUT` | A send has no confirmed reply yet; retain its message ID. |
|
|
710
|
+
| `MCP_WORKER_EXITED` | A worker exited while handling a request; its delivery may already have happened. |
|
|
711
|
+
| `MCP_WORKER_UNAVAILABLE` | This new request was refused before dispatch while its worker was unavailable. |
|
|
712
|
+
|
|
713
|
+
`deliveryState: not_sent` means this operation did not send a message. `unknown` means delivery remains uncertain; inspect the original receipt and never automatically resend. `not_applicable` marks a diagnostic read rather than a send. A diagnostic does not instruct an agent to create/open chats, use Computer Use, or change permissions to make the error disappear.
|
|
714
|
+
|
|
691
715
|
### Normal startup output labelled as an error
|
|
692
716
|
|
|
693
717
|
Claude may label stderr as `ERR: Server stderr`, including ordinary `[bridge-supervisor] preparing`, `prepared`, and `[codex-mcp-bridge] ready` lines. The label alone is not a failure. Look for the actual connection result, exception, or timeout and verify the tool from the client. Keep diagnostics on stderr: stdout is reserved for MCP protocol messages, and redirecting logs there can break initialization.
|
|
@@ -729,7 +753,7 @@ The catalog below records user-visible failures fixed in earlier releases. It is
|
|
|
729
753
|
| An account switch, a large task database or a concurrent metadata update hid an otherwise valid Claude task | [1.14.0](CHANGELOG.md#1140---2026-09-07): per-call account discovery, including Store data. [1.18.1](CHANGELOG.md#1181---2026-09-25): bounded discovery beyond 32 MiB. [1.22.3](CHANGELOG.md#1223---2026-10-15): retry changed metadata snapshots. | Check sign-in and [data-root selection](#microsoft-store-claude-or-multiple-data-directories), then rediscover. Conflicting, archived or persistently changing identities still fail closed; shared Chat still cannot prove Code ancestry. |
|
|
730
754
|
| Windows ancestry checks expired while PowerShell was still starting | [1.19.1](CHANGELOG.md#1191---2026-09-29): separate startup/read deadlines. [1.25.0](CHANGELOG.md#1250---2026-10-30): coalesce identical simultaneous inspections. | Use the [timeout diagnostic steps](#connection-timeout-versus-sender-inspection-timeout). These changes do not establish a fix for every MCP initialization timeout. |
|
|
731
755
|
| Ordinary managed Codex tasks were rejected as unverified senders; some review flags caused incorrect permission classification | [1.19.0](CHANGELOG.md#1190---2026-09-29): support verified managed prompting profiles. [1.13.6](CHANGELOG.md#1136---2026-09-06): correct human-review classification. | Upgrade and inspect `claude_bridge_status`. A real recipient class/inbound-policy mismatch remains a denial; do not change sandbox or approval settings merely to suppress it. |
|
|
732
|
-
| Dormant Claude tasks could not resume; a new Windows conversation opened in “No folder”; an app update broke its URI launcher | [1.19.7](CHANGELOG.md#1197---2026-10-02): exact-task recovery
|
|
756
|
+
| Dormant Claude tasks could not resume; a new Windows conversation opened in “No folder”; an app update broke its URI launcher | [1.19.7](CHANGELOG.md#1197---2026-10-02): exact-task recovery and composer verification. [1.25.3](CHANGELOG.md#1253---2026-11-01): removes implicit app/chat reopening from recovery. | `target: "auto"` rediscovers an existing live endpoint only. A dormant task reports `CLAUDE_SESSION_NOT_READY`; never open or create a chat to load a relay. A moved directory remains an unverified discovery candidate. |
|
|
733
757
|
| A listed human-created thread returned `NOT AUTHORIZED`; a path from another computer resolved incorrectly | [1.11.0](CHANGELOG.md#1110---2026-08-23): explicit thread policy. [1.8.0](CHANGELOG.md#180---2026-08-19) / [1.11.2](CHANGELOG.md#1112---2026-08-28): usable cross-machine path resolution. | Verify the exact saved project and intended grant/thread policy. Listing and mutation have different authorization requirements; setup preserves existing restrictions and cannot authorize a different project. |
|
|
734
758
|
| An Antigravity App restart could leave a sidecar attached to the retired parent | [1.24.0](CHANGELOG.md#1240---2026-10-28): sidecars track native parent identity and exit when that parent stops. | Use current setup and reconnect through the active App. An App receipt confirms native acceptance only; App reply forwarding and new App conversation creation remain unsupported. |
|
|
735
759
|
|
package/package.json
CHANGED
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.25.
|
|
4
|
+
"version": "1.25.3",
|
|
5
5
|
"description": "Connect ChatGPT to your own Codex Desktop projects and conversations.",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Bui Dang Minh",
|
|
@@ -17,7 +17,7 @@ function object(value, label) {
|
|
|
17
17
|
return value;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
function snapshot(file) {
|
|
20
|
+
function snapshot(file, jsonLabel) {
|
|
21
21
|
let descriptor;
|
|
22
22
|
try { descriptor = fs.openSync(file, fs.constants.O_RDONLY | (fs.constants.O_NOFOLLOW ?? 0)); }
|
|
23
23
|
catch (error) {
|
|
@@ -41,7 +41,13 @@ function snapshot(file) {
|
|
|
41
41
|
}
|
|
42
42
|
if (length !== opened.size || !matches(opened, fs.fstatSync(descriptor)) || !matches(opened, fs.lstatSync(file))) throw new Error(`Configuration changed while reading: ${file}`);
|
|
43
43
|
const text = buffer.subarray(0, length).toString("utf8");
|
|
44
|
-
|
|
44
|
+
let value;
|
|
45
|
+
try { value = object(JSON.parse(text), file); }
|
|
46
|
+
catch (error) {
|
|
47
|
+
if (jsonLabel) throw new Error(`Invalid ${jsonLabel}: expected a JSON object.`);
|
|
48
|
+
throw error;
|
|
49
|
+
}
|
|
50
|
+
return { file, text, value, ...(jsonLabel ? { jsonLabel } : {}), mode: opened.mode & 0o777, dev: opened.dev, ino: opened.ino };
|
|
45
51
|
} finally { fs.closeSync(descriptor); }
|
|
46
52
|
}
|
|
47
53
|
|
|
@@ -79,7 +85,7 @@ function changed(original, value) {
|
|
|
79
85
|
return { ...original, next: text };
|
|
80
86
|
}
|
|
81
87
|
|
|
82
|
-
export function planAntigravityInstallation({ home = homeDir(), codeConfigDir = process.env.CLAUDE_CONFIG_DIR || home, root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."), node = stableNodeBin(), targets = ["codex", "claude", "desktop"], remove = false, setup = false, codexExisting = null } = {}) {
|
|
88
|
+
export function planAntigravityInstallation({ home = homeDir(), codeConfigDir = process.env.CLAUDE_CONFIG_DIR || home, root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."), node = stableNodeBin(), targets = ["codex", "claude", "desktop"], remove = false, setup = false, codexExisting = null, platform = process.platform, appData = process.env.APPDATA } = {}) {
|
|
83
89
|
if (!path.isAbsolute(home) || !path.isAbsolute(codeConfigDir) || !path.isAbsolute(root) || !path.isAbsolute(node)) throw new Error("Installer paths must be absolute");
|
|
84
90
|
if (!targets.length || targets.some((target) => !["codex", "claude", "desktop"].includes(target))) throw new Error("Unknown installation target");
|
|
85
91
|
const entry = path.join(root, "src", "antigravity-bridge.mjs");
|
|
@@ -87,6 +93,7 @@ export function planAntigravityInstallation({ home = homeDir(), codeConfigDir =
|
|
|
87
93
|
const outboundEntry = path.join(root, "src", "antigravity-outbound-bridge.mjs");
|
|
88
94
|
const edits = [];
|
|
89
95
|
const notices = [];
|
|
96
|
+
let backgroundPreference = null;
|
|
90
97
|
const retarget = setup && !remove;
|
|
91
98
|
let codex = null;
|
|
92
99
|
if (targets.includes("codex")) {
|
|
@@ -154,12 +161,30 @@ export function planAntigravityInstallation({ home = homeDir(), codeConfigDir =
|
|
|
154
161
|
const configEdit = changed(originalConfig, config);
|
|
155
162
|
if (sidecarEdit) edits.push(sidecarEdit);
|
|
156
163
|
if (configEdit) edits.push(configEdit);
|
|
164
|
+
if (setup && !remove) {
|
|
165
|
+
backgroundPreference = { setting: "runInBackground", status: "unavailable", liveVerified: false };
|
|
166
|
+
if (platform !== "win32") {
|
|
167
|
+
backgroundPreference.detail = "Automatic Antigravity background preferences are not verified on this platform; native settings were preserved.";
|
|
168
|
+
} else if (typeof appData !== "string" || !path.isAbsolute(appData)) {
|
|
169
|
+
backgroundPreference.detail = "Antigravity background preferences were not applied because an absolute APPDATA path is unavailable.";
|
|
170
|
+
} else {
|
|
171
|
+
const storage = snapshot(path.join(appData, "Antigravity", "app_storage.json"), "Antigravity native preferences");
|
|
172
|
+
if (storage.text === null) {
|
|
173
|
+
backgroundPreference.detail = "Antigravity app_storage.json was not found; no native preferences file was created and background operation is unverified.";
|
|
174
|
+
} else {
|
|
175
|
+
const storageEdit = changed(storage, { ...storage.value, runInBackground: "true" });
|
|
176
|
+
if (storageEdit) edits.push(storageEdit);
|
|
177
|
+
backgroundPreference.status = storageEdit ? "planned" : "configured";
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
if (backgroundPreference.detail) notices.push(backgroundPreference.detail);
|
|
181
|
+
}
|
|
157
182
|
}
|
|
158
|
-
return { name: NAME, targets: [...new Set(targets)], remove, edits, notices, codex, entry, sidecarEntry, outboundEntry };
|
|
183
|
+
return { name: NAME, targets: [...new Set(targets)], remove, edits, notices, codex, entry, sidecarEntry, outboundEntry, backgroundPreference };
|
|
159
184
|
}
|
|
160
185
|
|
|
161
186
|
function assertCurrent(edit) {
|
|
162
|
-
const current = snapshot(edit.file);
|
|
187
|
+
const current = snapshot(edit.file, edit.jsonLabel);
|
|
163
188
|
if (current.text !== edit.text || current.dev !== edit.dev || current.ino !== edit.ino) throw new Error(`Configuration changed while preparing installation: ${edit.file}`);
|
|
164
189
|
}
|
|
165
190
|
|
|
@@ -180,11 +205,11 @@ export function applyJsonEdits(edits) {
|
|
|
180
205
|
} finally { if (fs.existsSync(temporary)) fs.unlinkSync(temporary); }
|
|
181
206
|
}
|
|
182
207
|
completed.push(edit);
|
|
183
|
-
if (snapshot(edit.file).text !== edit.next) throw new Error(`Configuration readback did not match the saved update: ${edit.file}`);
|
|
208
|
+
if (snapshot(edit.file, edit.jsonLabel).text !== edit.next) throw new Error(`Configuration readback did not match the saved update: ${edit.file}`);
|
|
184
209
|
}
|
|
185
210
|
} catch (error) {
|
|
186
211
|
for (const edit of completed.reverse()) {
|
|
187
|
-
if (snapshot(edit.file).text !== edit.next) continue;
|
|
212
|
+
if (snapshot(edit.file, edit.jsonLabel).text !== edit.next) continue;
|
|
188
213
|
if (edit.text === null) fs.unlinkSync(edit.file);
|
|
189
214
|
else fs.writeFileSync(edit.file, edit.text, { mode: edit.mode ?? 0o600 });
|
|
190
215
|
}
|
|
@@ -224,7 +249,7 @@ export function runAntigravityInstaller(args = process.argv.slice(2)) {
|
|
|
224
249
|
}
|
|
225
250
|
}
|
|
226
251
|
if (options.dryRun) {
|
|
227
|
-
console.log(JSON.stringify({ dryRun: true, remove: plan.remove, targets: plan.targets, files: plan.edits.map((edit) => ({ path: edit.file, action: edit.next === null ? "remove" : "write" })), notices: plan.notices, codex: plan.codex ? { name: NAME, action: options.remove ? "remove" : "register" } : null }, null, 2));
|
|
252
|
+
console.log(JSON.stringify({ dryRun: true, remove: plan.remove, targets: plan.targets, files: plan.edits.map((edit) => ({ path: edit.file, action: edit.next === null ? "remove" : "write" })), notices: plan.notices, backgroundPreference: plan.backgroundPreference, codex: plan.codex ? { name: NAME, action: options.remove ? "remove" : "register" } : null }, null, 2));
|
|
228
253
|
return plan;
|
|
229
254
|
}
|
|
230
255
|
for (const edit of plan.edits) assertCurrent(edit);
|
|
@@ -233,10 +258,15 @@ export function runAntigravityInstaller(args = process.argv.slice(2)) {
|
|
|
233
258
|
else applyStdioMcpRegistration({ name: NAME, registration: plan.codex, existing: codexExisting, run, configPath: path.join(process.env.CODEX_HOME ?? path.join(home, ".codex"), "config.toml") });
|
|
234
259
|
}
|
|
235
260
|
applyJsonEdits(plan.edits);
|
|
261
|
+
if (plan.backgroundPreference?.status === "planned") plan.backgroundPreference.status = "configured";
|
|
262
|
+
if (options.setup) {
|
|
263
|
+
console.log(JSON.stringify({ action: options.remove ? "remove" : "install", targets: plan.targets, configured: true, liveVerified: false,
|
|
264
|
+
changedFiles: plan.edits.length, notices: plan.notices, backgroundPreference: plan.backgroundPreference }));
|
|
265
|
+
return plan;
|
|
266
|
+
}
|
|
236
267
|
console.log(`${options.remove ? "Removed" : "Installed"} Antigravity bridge: ${plan.targets.join(", ")}.`);
|
|
237
268
|
for (const notice of plan.notices) console.log(notice);
|
|
238
|
-
if (!options.remove
|
|
239
|
-
if (!options.remove) console.log("Reload the selected clients to load the bridge. Antigravity Desktop must launch its sidecar; installation alone does not prove a live connection. Native permissions were preserved.");
|
|
269
|
+
if (!options.remove) console.log("Bridge configuration saved; running clients and native permissions were preserved. Installation does not prove a live connection or load new settings into existing processes. This installer does not start apps or open conversations.");
|
|
240
270
|
return plan;
|
|
241
271
|
}
|
|
242
272
|
|
|
@@ -68,7 +68,7 @@ try {
|
|
|
68
68
|
if (args.includes("--install")) {
|
|
69
69
|
if (args.includes("--check") || args.includes("--apply")) throw new Error("Use --install separately from --check or --apply");
|
|
70
70
|
const root = stableInstallPath(path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."));
|
|
71
|
-
const plan = planInitialCodeRegistration({ code, desktop, root, node: stableNodeBin(), environment: process.env });
|
|
71
|
+
const plan = planInitialCodeRegistration({ code, desktop, root, node: stableNodeBin(), environment: process.env, setup: args.includes("--setup") });
|
|
72
72
|
const dryRun = args.includes("--dry-run");
|
|
73
73
|
const writtenFiles = dryRun ? 0 : apply(plan);
|
|
74
74
|
console.log(JSON.stringify({ action: dryRun ? "plan" : "install", configured: !dryRun, liveVerified: false,
|
|
@@ -86,7 +86,7 @@ try {
|
|
|
86
86
|
if (args.includes("--apply")) {
|
|
87
87
|
if (!args.includes("--clients-stopped")) throw new Error("Exit Claude and the configuration manager first, then pass --clients-stopped to avoid their overwriting the migration");
|
|
88
88
|
apply(plan);
|
|
89
|
-
console.log("
|
|
89
|
+
console.log("Shared policy migration applied. Loaded Code registrations have not been verified; codex_bridge_status reports the active configuration. The configuration manager's matching entry must use the same policy file.");
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
92
|
} catch (error) { console.error(error.message); process.exitCode = 1; }
|
|
@@ -20,10 +20,11 @@ const entryOption = process.argv.indexOf("--entry-name");
|
|
|
20
20
|
const requestedEntryName = entryOption < 0 ? undefined : process.argv[entryOption + 1];
|
|
21
21
|
if (entryOption >= 0 && !["codex-bridge", "codex-bridge-desktop"].includes(requestedEntryName)) throw new Error("--entry-name must be codex-bridge or codex-bridge-desktop");
|
|
22
22
|
const quiet = process.argv.includes("--quiet");
|
|
23
|
+
const setup = process.argv.includes("--setup");
|
|
23
24
|
const log = (...values) => { if (!quiet) console.log(...values); };
|
|
24
25
|
const reset = process.argv.includes("--reset");
|
|
25
26
|
const forceDesktopTasks = process.argv.includes("--desktop-tasks");
|
|
26
|
-
const fullAccess = process.argv.includes("--full-access") || requestedEntryName === undefined && fullAccessEnabled();
|
|
27
|
+
const fullAccess = process.argv.includes("--full-access") || !setup && requestedEntryName === undefined && fullAccessEnabled();
|
|
27
28
|
|
|
28
29
|
/**
|
|
29
30
|
* This bridge is intentionally the local hand-off point between Claude and
|
|
@@ -80,6 +81,7 @@ const original = readConfig();
|
|
|
80
81
|
const cfg = original ? JSON.parse(original.data.toString("utf8")) : {};
|
|
81
82
|
if (!cfg || typeof cfg !== "object" || Array.isArray(cfg)) throw new Error("Desktop configuration must be a JSON object");
|
|
82
83
|
if (cfg.mcpServers !== undefined && (!cfg.mcpServers || typeof cfg.mcpServers !== "object" || Array.isArray(cfg.mcpServers))) throw new Error("Desktop mcpServers must be a JSON object");
|
|
84
|
+
if (setup && cfg.preferences !== undefined && (!cfg.preferences || typeof cfg.preferences !== "object" || Array.isArray(cfg.preferences))) throw new Error("Desktop preferences must be a JSON object");
|
|
83
85
|
cfg.mcpServers = cfg.mcpServers ?? {};
|
|
84
86
|
|
|
85
87
|
/**
|
|
@@ -108,7 +110,7 @@ if (bridgeEntries.length > 1 || requestedEntryName && bridgeEntries.some((name)
|
|
|
108
110
|
throw new Error(`Claude Desktop already has several bridge entries (${bridgeEntries.join(", ")}); remove all but one and re-run. No configuration was changed.`);
|
|
109
111
|
}
|
|
110
112
|
const entryName = requestedEntryName ?? bridgeEntries[0] ?? "codex-bridge";
|
|
111
|
-
if (requestedEntryName && cfg.mcpServers[entryName] !== undefined) {
|
|
113
|
+
if ((requestedEntryName || setup) && cfg.mcpServers[entryName] !== undefined) {
|
|
112
114
|
const existing = cfg.mcpServers[entryName];
|
|
113
115
|
const script = existing?.args?.[0];
|
|
114
116
|
const source = typeof script === "string" && path.isAbsolute(script) ? path.dirname(script) : null;
|
|
@@ -133,6 +135,7 @@ const desktopEnabled = desktopMode === undefined ? desktopTasksConfigured() : de
|
|
|
133
135
|
|
|
134
136
|
const kept = Object.keys(previousEnv).filter(
|
|
135
137
|
(name) => process.env[name] === undefined && name !== "CODEX_BIN" &&
|
|
138
|
+
!(setup && name === "CODEX_BRIDGE_OPEN_IN_APP") &&
|
|
136
139
|
!(forceDesktopTasks && name === "CODEX_BRIDGE_DESKTOP_TASKS") &&
|
|
137
140
|
!(desktopEnabled && name === "CODEX_BRIDGE_AUTOSTART"),
|
|
138
141
|
);
|
|
@@ -168,7 +171,7 @@ cfg.mcpServers[entryName] = {
|
|
|
168
171
|
*/
|
|
169
172
|
CODEX_BRIDGE_THREAD_POLICY: settled("CODEX_BRIDGE_THREAD_POLICY", "roots"),
|
|
170
173
|
CODEX_BRIDGE_SANDBOX: fullAccess ? "danger-full-access" : settled("CODEX_BRIDGE_SANDBOX", "workspace-write"),
|
|
171
|
-
CODEX_BRIDGE_OPEN_IN_APP:
|
|
174
|
+
CODEX_BRIDGE_OPEN_IN_APP: setup ? "0" : settled("CODEX_BRIDGE_OPEN_IN_APP", "0"),
|
|
172
175
|
CODEX_BRIDGE_RELEASE_AFTER_TURN: settled("CODEX_BRIDGE_RELEASE_AFTER_TURN", IS_WINDOWS ? "1" : "0"),
|
|
173
176
|
...(desktopMode !== undefined ? { CODEX_BRIDGE_DESKTOP_TASKS: desktopMode } : {}),
|
|
174
177
|
CODEX_BRIDGE_AUTOSTART: desktopEnabled ? "0" : settled("CODEX_BRIDGE_AUTOSTART", "1"),
|
|
@@ -185,6 +188,7 @@ cfg.mcpServers[entryName] = {
|
|
|
185
188
|
: {}),
|
|
186
189
|
},
|
|
187
190
|
};
|
|
191
|
+
if (setup) cfg.preferences = { ...cfg.preferences, menuBarEnabled: true };
|
|
188
192
|
|
|
189
193
|
createReleaseSnapshot(root, { cache: snapshotRoot({ ...process.env, ...cfg.mcpServers[entryName].env }) });
|
|
190
194
|
|
|
@@ -255,7 +259,8 @@ if (entryName === "codex-bridge") {
|
|
|
255
259
|
}
|
|
256
260
|
}
|
|
257
261
|
|
|
258
|
-
log(`\
|
|
259
|
-
log("
|
|
260
|
-
if (desktopEnabled) log("
|
|
261
|
-
if (quiet) console.log(JSON.stringify({ action: "install", entry: entryName, configured: true, liveVerified: false, changed, restartRequired: changed, desktopTasks: desktopEnabled
|
|
262
|
+
log(`\nConfiguration saved for ${entryName}. Running MCP processes were not restarted and may still hold earlier settings.`);
|
|
263
|
+
log("An existing compatible supervisor reloads installed source when the worker is safely idle. codex_bridge_status reports the loaded process; a separate diagnostic process cannot verify it.");
|
|
264
|
+
if (desktopEnabled) log("Native delivery requires a loaded Desktop-owned relay. This installer does not start apps or open conversations, and saved configuration does not prove live readiness.");
|
|
265
|
+
if (quiet) console.log(JSON.stringify({ action: "install", entry: entryName, configured: true, liveVerified: false, changed, restartRequired: changed, desktopTasks: desktopEnabled,
|
|
266
|
+
...(setup ? { backgroundPreference: { setting: "preferences.menuBarEnabled", status: "configured", liveVerified: false } } : {}) }));
|
|
@@ -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.25.
|
|
28
|
+
const VERSION = "1.25.3";
|
|
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"];
|
|
@@ -136,5 +136,5 @@ if (process.argv.includes("--desktop-tasks")) {
|
|
|
136
136
|
writeRelayConfig({ ...readRelayConfig(), desktopTasks: true });
|
|
137
137
|
console.log("Desktop task creation enabled: exact saved local projects, immediate visibility, Codex Desktop permissions.");
|
|
138
138
|
}
|
|
139
|
-
console.log("
|
|
139
|
+
console.log("Native relay configuration saved. Running MCP processes were not restarted; native_relay_status reports whether a Desktop-owned relay is loaded and current. Existing compatible supervisors reload installed source when idle, but saved configuration does not prove the running process has loaded new settings. This installer does not start Codex Desktop or open conversations.");
|
|
140
140
|
console.log("remove: node scripts/install-native-relay.mjs --remove");
|
package/scripts/setup.mjs
CHANGED
|
@@ -6,9 +6,9 @@ exitForVersionRequest(import.meta.url);
|
|
|
6
6
|
try {
|
|
7
7
|
const result = runSetup({ args: process.argv.slice(2) });
|
|
8
8
|
printSetup(result, { json: process.argv.includes("--json") });
|
|
9
|
-
if (result.configured === false && !result.dryRun
|
|
9
|
+
if (result.configured === false && !result.dryRun) process.exitCode = 1;
|
|
10
10
|
} catch (error) {
|
|
11
11
|
process.stderr.write(`Bridge setup: ${error.message}\n`);
|
|
12
|
-
process.stderr.write("Run codex-bridge-setup to retry
|
|
13
|
-
|
|
12
|
+
process.stderr.write("Bridge configuration was not completed. Run codex-bridge-setup to retry after resolving the reported error.\n");
|
|
13
|
+
process.exitCode = 1;
|
|
14
14
|
}
|