@minhspark/codex-mcp-bridge 1.26.1 → 1.26.2
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 +21 -0
- package/README.md +15 -11
- package/docs/new-macos-setup.md +19 -14
- package/docs/new-windows-setup.md +30 -12
- package/docs/project-onboarding.md +20 -14
- package/package.json +2 -1
- package/plugin.json +1 -1
- package/scripts/background-relay-hidden.vbs +1 -0
- package/scripts/install-native-relay.mjs +1 -1
- package/scripts/update.mjs +210 -0
- package/src/background-relay-service.mjs +2 -1
- package/src/claude-bridge.mjs +1 -1
- package/src/index.mjs +1 -1
- package/src/native-relay-companion.mjs +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,27 @@ Follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and [SemVer](ht
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [1.26.2] - 2026-11-01
|
|
8
|
+
|
|
9
|
+
### Upgrade
|
|
10
|
+
|
|
11
|
+
Install or update the global package and all managed client and background-service settings with one command, including upgrades from 1.26.0 or 1.26.1:
|
|
12
|
+
|
|
13
|
+
```sh
|
|
14
|
+
npm exec --yes --ignore-scripts --package=@minhspark/codex-mcp-bridge@latest -- codex-bridge-update
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Use `npm.cmd` in Windows PowerShell. npm downloads the latest updater without running setup in its cache; the updater installs that exact resolved version globally with managed setup enabled and verifies the global installation. No second installation command is required.
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
- Automatic `codex-bridge-update` orchestration for package replacement, all managed client settings and background-service configuration. Before replacing a Windows installation held by an owned legacy relay, it moves only that service to newer code using private relay storage as its working directory, waits for work to drain and verifies replacement readiness. The temporary runtime points to the downloaded updater package. It reports a pending migration instead of killing processes or interrupting jobs.
|
|
22
|
+
- Preserve disabled services, provider authentication, custom project grants and permission denials throughout the update. Setup does not open apps or chats, and a deliberately disabled service is not reported as ready.
|
|
23
|
+
|
|
24
|
+
### Fixed
|
|
25
|
+
|
|
26
|
+
- New background service and daemon launches use private relay storage as their working directory instead of the npm installation directory, preventing those processes from locking the package on Windows. The updater migrates owned legacy instances before package replacement. Worker jobs continue using their explicitly authorized project directories.
|
|
27
|
+
|
|
7
28
|
## [1.26.1] - 2026-11-01
|
|
8
29
|
|
|
9
30
|
### Upgrade
|
package/README.md
CHANGED
|
@@ -23,23 +23,27 @@ https://github.com/user-attachments/assets/98b23989-826f-4d7d-9dcb-ad7dd2739095
|
|
|
23
23
|
|
|
24
24
|
## Installation
|
|
25
25
|
|
|
26
|
-
One
|
|
26
|
+
One npm command installs or updates the global package, applies all managed Claude, Codex and Antigravity settings, and configures the independent worker relay. Native handoffs require the selected Desktop apps; background work requires the selected provider CLIs and their own authentication. Setup preserves existing project restrictions and custom settings; it does not sign in, grant workspace trust, change permission modes, or restart running apps.
|
|
27
27
|
|
|
28
28
|
### Package — npm
|
|
29
29
|
|
|
30
30
|
**macOS / Linux / WSL**
|
|
31
31
|
|
|
32
32
|
```bash
|
|
33
|
-
npm
|
|
33
|
+
npm exec --yes --ignore-scripts --package=@minhspark/codex-mcp-bridge@latest -- codex-bridge-update
|
|
34
34
|
```
|
|
35
35
|
|
|
36
36
|
**Windows PowerShell**
|
|
37
37
|
|
|
38
38
|
```powershell
|
|
39
|
-
npm.cmd
|
|
39
|
+
npm.cmd exec --yes --ignore-scripts --package=@minhspark/codex-mcp-bridge@latest -- codex-bridge-update
|
|
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. **Use this same single command for a fresh install and every update**, including upgrades from 1.26.0 or 1.26.1. npm fetches the latest updater into its cache without running setup there. The updater installs that exact resolved version globally, runs the managed setup hook, and verifies the global version, saved settings and service activation separately. A second installation command is not required.
|
|
43
|
+
|
|
44
|
+
For an enabled legacy Windows relay from 1.26.0 or 1.26.1, the updater moves only this package's owned service to newer code using private relay storage as its working directory before replacing the global package. The temporary service runtime points to the downloaded updater package; changing the working directory releases the old package lock. It waits for active work to drain and the replacement transport to become ready without killing processes or opening apps or chats. If migration is still pending after its bounded wait, it reports `UPDATE_RELAY_PENDING`; keep the existing jobs and receipts and rerun the same command after they finish. Intentionally disabled services stay disabled and are not reported as ready.
|
|
45
|
+
|
|
46
|
+
Managed 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, project grants, unrelated custom registrations and existing permission denials remain unchanged. Setup adds only the four worker-relay communication grants required by headless Antigravity; it does not enable broad permission bypasses. 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
47
|
|
|
44
48
|
### Independent background workers
|
|
45
49
|
|
|
@@ -61,7 +65,7 @@ Keep the same request UUID for retries and read its durable receipt. Queued work
|
|
|
61
65
|
|
|
62
66
|
Worker delegation is bounded. `WORKER_DELEGATION_CAPACITY` means the destination has no free execution slot and that delegation was not sent or queued behind waiting workers. Inspect or finish existing delegated work before retrying the same unsent request. Queue and delegation limits are reported explicitly.
|
|
63
67
|
|
|
64
|
-
`--
|
|
68
|
+
The recommended command's `--ignore-scripts` applies only to downloading the updater into npm's cache. The updater explicitly enables this package's setup hook for the global installation and displays its progress. This avoids client MCP registrations pointing into a temporary npm cache directory. A direct global npm install remains an advanced alternative, but it skips the updater's migration of an old service that can lock the package on Windows.
|
|
65
69
|
|
|
66
70
|
| Client | Installed entry | Purpose |
|
|
67
71
|
| --- | --- | --- |
|
|
@@ -75,11 +79,11 @@ Worker delegation is bounded. `WORKER_DELEGATION_CAPACITY` means the destination
|
|
|
75
79
|
|
|
76
80
|
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.
|
|
77
81
|
|
|
78
|
-
Automatic setup runs
|
|
82
|
+
Automatic setup runs during the updater's **global npm installation**. Local `npm install` and `npm ci` do not change app settings. For a deliberate package-only installation, use a direct global npm install with `CODEX_BRIDGE_SKIP_SETUP=1` or `--ignore-scripts`; that opt-out is separate from the cache-only `--ignore-scripts` in the recommended updater command. The optional [workflow skill](#workflow-skill--npx-skills), VS Code preview, and hosted ChatGPT pairing retain their separate setup steps.
|
|
79
83
|
|
|
80
84
|
### Setup recovery and checks
|
|
81
85
|
|
|
82
|
-
If
|
|
86
|
+
If service migration, installation or managed setup fails, the updater returns a nonzero exit and reports the failed step. Inspect that component and the installed version, correct the reported cause, and rerun the same update command above. npm can roll back package files while settings already written remain changed. For configuration-only repair of an already installed package, the following is an optional alternative:
|
|
83
87
|
|
|
84
88
|
```bash
|
|
85
89
|
codex-bridge-setup
|
|
@@ -545,12 +549,12 @@ Node.js 22.13+ is required. If a command is missing, open a new terminal and che
|
|
|
545
549
|
If the package or registrations are missing, use the complete installation command:
|
|
546
550
|
|
|
547
551
|
```powershell
|
|
548
|
-
npm.cmd
|
|
552
|
+
npm.cmd exec --yes --ignore-scripts --package=@minhspark/codex-mcp-bridge@latest -- codex-bridge-update
|
|
549
553
|
```
|
|
550
554
|
|
|
551
|
-
|
|
555
|
+
This runs the latest updater outside the global package directory, handles an owned legacy service that can lock that directory, and installs the exact resolved package with its setup hook enabled. `--ignore-scripts` suppresses setup only for the temporary cached updater. If a previous direct install printed `1 package had install scripts blocked`, use this same updater command to install and apply the managed settings together. Intentional setup opt-outs and disabled-service choices are not silently removed.
|
|
552
556
|
|
|
553
|
-
For an already-installed package, preview
|
|
557
|
+
For an already-installed package, these optional commands preview or repair configuration without updating package files:
|
|
554
558
|
|
|
555
559
|
```powershell
|
|
556
560
|
codex-bridge-setup.cmd --dry-run
|
|
@@ -558,7 +562,7 @@ codex-bridge-setup.cmd
|
|
|
558
562
|
codex-bridge-setup.cmd --check
|
|
559
563
|
```
|
|
560
564
|
|
|
561
|
-
`--dry-run` does not write settings or download tools. Setup resolves an existing Codex CLI or installs its managed official copy; `--no-download` requires one to be available already.
|
|
565
|
+
`--dry-run` does not write settings or download tools. Setup resolves an existing Codex CLI or installs its managed official copy; `--no-download` requires one to be available already. Failed setup or update returns a nonzero exit; inspect the reported component and installed version, correct the cause, then rerun the same updater command. Package rollback does not guarantee that settings or command shims return to their previous state. Explicit setup and `--check` also return a nonzero exit code for incomplete configuration. Running the same command cannot resolve a deliberate opt-out or an unrelated conflicting registration.
|
|
562
566
|
|
|
563
567
|
### Missing module, stale source path, or a different running version
|
|
564
568
|
|
package/docs/new-macos-setup.md
CHANGED
|
@@ -12,26 +12,28 @@ connector. Install Node.js 22.13+ under the macOS account that will use the
|
|
|
12
12
|
bridges. Native handoffs require signed-in apps and the same local project saved
|
|
13
13
|
in Codex Desktop and Claude's Code tab. Independent background workers use
|
|
14
14
|
separately authenticated provider CLIs and do not require open Desktop apps.
|
|
15
|
-
|
|
15
|
+
Use the same command for a fresh installation and every update:
|
|
16
16
|
|
|
17
17
|
```bash
|
|
18
|
-
npm
|
|
18
|
+
npm exec --yes --ignore-scripts --package=@minhspark/codex-mcp-bridge@latest -- codex-bridge-update
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
21
|
+
npm downloads the latest updater into its cache. `--ignore-scripts` suppresses
|
|
22
|
+
setup only in that temporary location. The updater installs its exact resolved
|
|
23
|
+
version globally, enables this package's managed setup hook, displays progress
|
|
24
|
+
and verifies the global version and configuration. No second installation or
|
|
25
|
+
setup command is required. Existing disabled choices, authentication and custom
|
|
26
|
+
project grants are preserved; the updater does not open apps or chats or kill
|
|
27
|
+
processes. A pending service migration is reported instead of interrupting work.
|
|
26
28
|
|
|
27
29
|
Setup registers the local bridges, adds native pipe forwarding, and bootstraps
|
|
28
30
|
the relay executor. It reuses an available Codex CLI or installs a pinned
|
|
29
31
|
official package under `~/.config/GptClaudeBridge/tools` (or
|
|
30
32
|
`XDG_CONFIG_HOME/GptClaudeBridge/tools`). No separate Codex CLI install command
|
|
31
33
|
is required. Run the install under the account that uses the apps, without `sudo`.
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
34
|
+
If setup or update exits nonzero, inspect the reported component and installed
|
|
35
|
+
version, correct the cause, and rerun the same updater command. npm can roll back
|
|
36
|
+
package files without restoring settings already written or command shims.
|
|
35
37
|
|
|
36
38
|
The command also installs an independent per-user LaunchAgent for separate
|
|
37
39
|
Claude, Codex and Antigravity CLI workers and updates its managed settings on
|
|
@@ -89,6 +91,7 @@ codex-bridge-setup --dry-run
|
|
|
89
91
|
codex-bridge-setup
|
|
90
92
|
```
|
|
91
93
|
|
|
94
|
+
These are optional configuration-only checks and repairs after installation.
|
|
92
95
|
`--check` inspects registrations; `--dry-run` previews components and paths
|
|
93
96
|
without downloads or writes; the plain command applies setup again. Add
|
|
94
97
|
`--json` for structured output or `--no-download` to require an existing Codex
|
|
@@ -96,10 +99,12 @@ CLI. `codex-mcp-bridge setup` runs the same setup. An incomplete result identifi
|
|
|
96
99
|
the component to correct before rerunning. Explicit setup and `--check` return
|
|
97
100
|
a nonzero exit status while configuration is incomplete.
|
|
98
101
|
|
|
99
|
-
Local `npm install` and `npm ci` do not change app settings.
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
102
|
+
Local `npm install` and `npm ci` do not change app settings. For a deliberate
|
|
103
|
+
package-only installation, a direct global npm install can use
|
|
104
|
+
`CODEX_BRIDGE_SKIP_SETUP=1` or `--ignore-scripts`; this differs from the cache-only
|
|
105
|
+
script suppression in the recommended updater command. For Homebrew, run
|
|
106
|
+
`codex-bridge-setup` after installing the formula. A pinned source checkout can
|
|
107
|
+
use `node scripts/setup.mjs`.
|
|
103
108
|
|
|
104
109
|
The [manual macOS commands](../README.md#macos-terminal) and
|
|
105
110
|
[Claude Code registration commands](../README.md#register-claude-code) remain
|
|
@@ -3,25 +3,38 @@
|
|
|
3
3
|
Install Node.js 22.13+. Native handoffs use signed-in Desktop apps and the same
|
|
4
4
|
local project saved in Codex Desktop and Claude Desktop's **Code tab**.
|
|
5
5
|
Independent background work uses separately authenticated provider CLIs and
|
|
6
|
-
does not require the Desktop apps to be open.
|
|
6
|
+
does not require the Desktop apps to be open. Use this one PowerShell command
|
|
7
|
+
for a fresh installation or an update, including from 1.26.0 or 1.26.1:
|
|
7
8
|
|
|
8
9
|
```powershell
|
|
9
|
-
npm.cmd
|
|
10
|
+
npm.cmd exec --yes --ignore-scripts --package=@minhspark/codex-mcp-bridge@latest -- codex-bridge-update
|
|
10
11
|
```
|
|
11
12
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
npm downloads the latest updater into its cache. `--ignore-scripts` prevents
|
|
14
|
+
setup from running in that temporary location; the updater then installs its
|
|
15
|
+
exact resolved version globally with this package's managed setup hook enabled.
|
|
16
|
+
It displays progress and verifies the global version and saved settings.
|
|
17
|
+
No second installation or setup command is required.
|
|
18
|
+
|
|
19
|
+
An older Windows background service can keep the global npm package directory
|
|
20
|
+
locked as its working directory. Before replacing the package, the updater
|
|
21
|
+
moves only this package's owned legacy service to newer code using private relay
|
|
22
|
+
storage as its working directory when needed. The temporary runtime points to
|
|
23
|
+
the downloaded updater package. It waits for active work to drain and the
|
|
24
|
+
replacement transport to become ready, without killing processes or opening
|
|
25
|
+
apps or chats. If that migration
|
|
26
|
+
remains pending, `UPDATE_RELAY_PENDING` leaves jobs and receipts intact; rerun
|
|
27
|
+
the same command after the active work finishes. Deliberately disabled services
|
|
28
|
+
remain disabled and are not reported as ready.
|
|
17
29
|
|
|
18
30
|
The global installation configures the bridges and verifies their saved
|
|
19
31
|
registrations. It reuses an available native Codex CLI, or installs a pinned
|
|
20
32
|
official package in the current user's `.config\GptClaudeBridge\tools`
|
|
21
33
|
directory. It also configures native pipe forwarding and bootstraps the relay
|
|
22
|
-
executor. A failed component is reported as incomplete rather than ready.
|
|
23
|
-
|
|
24
|
-
|
|
34
|
+
executor. A failed component is reported as incomplete rather than ready. If
|
|
35
|
+
setup or update exits nonzero, inspect the reported component and installed
|
|
36
|
+
version, correct the cause, and rerun the same updater command. npm can roll back
|
|
37
|
+
package files without restoring settings already written or command shims.
|
|
25
38
|
|
|
26
39
|
The same command installs the independent worker relay as a hidden per-user
|
|
27
40
|
scheduled task and applies its managed settings on every update. It registers
|
|
@@ -78,6 +91,7 @@ codex-bridge-setup.cmd --dry-run
|
|
|
78
91
|
codex-bridge-setup.cmd
|
|
79
92
|
```
|
|
80
93
|
|
|
94
|
+
These are optional configuration-only checks and repairs after installation.
|
|
81
95
|
The first command inspects configuration; the second previews components and
|
|
82
96
|
paths without writes or downloads; the third applies setup again. Add `--json`
|
|
83
97
|
for structured output or `--no-download` to require an existing Codex CLI.
|
|
@@ -87,8 +101,12 @@ incomplete.
|
|
|
87
101
|
has no bridge tools, inspect and reconnect `codex-bridge` using `/mcp` before
|
|
88
102
|
attempting delivery.
|
|
89
103
|
|
|
90
|
-
Local `npm install` and `npm ci` do not configure apps.
|
|
91
|
-
|
|
104
|
+
Local `npm install` and `npm ci` do not configure apps. For a deliberate
|
|
105
|
+
package-only installation, a direct global npm install can use
|
|
106
|
+
`CODEX_BRIDGE_SKIP_SETUP=1` or `--ignore-scripts`. This differs from the
|
|
107
|
+
recommended updater command, which suppresses setup only in its temporary cache
|
|
108
|
+
and enables it for the final global installation. A direct install skips the
|
|
109
|
+
updater's migration of legacy Windows services that can lock the package.
|
|
92
110
|
The optional card extension, hosted ChatGPT pairing, and VS Code preview have
|
|
93
111
|
separate installation steps.
|
|
94
112
|
|
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
# Project onboarding and shared authorization
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
independent worker relay automatically:
|
|
3
|
+
One command installs or updates the global package, registers the bridges and
|
|
4
|
+
configures the independent worker relay automatically:
|
|
5
5
|
|
|
6
6
|
```sh
|
|
7
|
-
npm
|
|
7
|
+
npm exec --yes --ignore-scripts --package=@minhspark/codex-mcp-bridge@latest -- codex-bridge-update
|
|
8
8
|
```
|
|
9
9
|
|
|
10
|
-
In Windows PowerShell use `npm.cmd`.
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
10
|
+
In Windows PowerShell use `npm.cmd`. npm fetches the latest updater into its
|
|
11
|
+
cache with setup disabled there. The updater moves an owned legacy service to
|
|
12
|
+
newer code using private relay storage as its working directory when needed,
|
|
13
|
+
temporarily using the downloaded updater package. It waits for active work to
|
|
14
|
+
drain, then installs its exact resolved version globally with the setup hook
|
|
15
|
+
enabled. It verifies the global installation and managed settings. No second
|
|
16
|
+
installation command is required. It does not open apps or chats or kill
|
|
17
|
+
processes. The setup creates
|
|
16
18
|
`codex-bridge` for Claude Code and the separate `codex-bridge-desktop` shared
|
|
17
19
|
Claude connector, configures Codex and Antigravity, and initializes the native
|
|
18
20
|
relay on Windows/macOS. It also installs the per-user background service and
|
|
@@ -32,11 +34,15 @@ display results. Use a terminal or another responsive client, subject to the
|
|
|
32
34
|
`codex-bridge-setup --check` inspects all saved registrations. Use
|
|
33
35
|
`codex-bridge-setup --dry-run` to preview or rerun `codex-bridge-setup` to apply
|
|
34
36
|
setup after correcting an incomplete component. Add `.cmd` on Windows and
|
|
35
|
-
`--json` for structured output. Local package installs do not run setup
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
a nonzero
|
|
37
|
+
`--json` for structured output. Local package installs do not run setup.
|
|
38
|
+
For a deliberate package-only direct global installation,
|
|
39
|
+
`CODEX_BRIDGE_SKIP_SETUP=1` or npm `--ignore-scripts` opts out of setup; this is
|
|
40
|
+
separate from the cache-only script suppression in the recommended updater.
|
|
41
|
+
Failed setup or update returns a nonzero exit. Inspect the reported component
|
|
42
|
+
and installed version, correct the cause, then rerun the same updater command.
|
|
43
|
+
npm can roll back package files without restoring settings or command shims.
|
|
44
|
+
Explicit setup and `--check` also return a nonzero status until the saved
|
|
45
|
+
configuration passes verification.
|
|
40
46
|
|
|
41
47
|
## Shared project policy
|
|
42
48
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@minhspark/codex-mcp-bridge",
|
|
3
|
-
"version": "1.26.
|
|
3
|
+
"version": "1.26.2",
|
|
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",
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
"codex-mcp-bridge-install": "scripts/install-claude-desktop.mjs",
|
|
31
31
|
"codex-bridge-code-install": "scripts/install-claude-code.mjs",
|
|
32
32
|
"codex-bridge-setup": "scripts/setup.mjs",
|
|
33
|
+
"codex-bridge-update": "scripts/update.mjs",
|
|
33
34
|
"worker-relay": "scripts/worker-relay.mjs",
|
|
34
35
|
"bridge-projects": "scripts/bridge-projects.mjs",
|
|
35
36
|
"claude-mcp-bridge-install": "scripts/install-codex-mcp.mjs",
|
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.
|
|
4
|
+
"version": "1.26.2",
|
|
5
5
|
"description": "Connect ChatGPT to your own Codex Desktop projects and conversations.",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Bui Dang Minh",
|
|
@@ -8,4 +8,5 @@ relayService = WScript.Arguments(1)
|
|
|
8
8
|
If InStr(relayNode, Chr(34)) > 0 Or InStr(relayNode, "%") > 0 Then WScript.Quit 2
|
|
9
9
|
If InStr(relayService, Chr(34)) > 0 Or InStr(relayService, "%") > 0 Then WScript.Quit 2
|
|
10
10
|
relayEnvironment("AGENT_RELAY_DIRECTORY") = WScript.Arguments(2)
|
|
11
|
+
relayShell.CurrentDirectory = WScript.Arguments(2)
|
|
11
12
|
WScript.Quit relayShell.Run(Chr(34) & relayNode & Chr(34) & " " & Chr(34) & relayService & Chr(34), 0, True)
|
|
@@ -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.
|
|
28
|
+
const VERSION = "1.26.2";
|
|
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"];
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { execFile } from "node:child_process";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
import { installBackgroundRelay } from "./install-background-relay.mjs";
|
|
8
|
+
import { readRelayConfiguration } from "../src/background-relay-config.mjs";
|
|
9
|
+
import { readRelayServiceRuntime, RELAY_SERVICE_OWNER } from "../src/background-relay-service.mjs";
|
|
10
|
+
import { assertPrivateRelayFile } from "../src/background-relay-storage.mjs";
|
|
11
|
+
import { isMainModule } from "../src/install-paths.mjs";
|
|
12
|
+
import { readRegularConfigFile } from "../src/project-policy.mjs";
|
|
13
|
+
import { exitForVersionRequest } from "../src/cli-version.mjs";
|
|
14
|
+
import { bridgeDiagnostic, withBridgeDiagnostic } from "../src/recipient-preflight.mjs";
|
|
15
|
+
|
|
16
|
+
const PACKAGE = "@minhspark/codex-mcp-bridge";
|
|
17
|
+
const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
18
|
+
const MANAGED_ENV = new Set(["HOME", "PATH", "CODEX_HOME", "CLAUDE_CONFIG_DIR", "XDG_CONFIG_HOME"]);
|
|
19
|
+
const RETRY = "Run the same codex-bridge-update command again after inspecting this report. Existing work and receipts were preserved.";
|
|
20
|
+
const pause = ms => new Promise(resolve => setTimeout(resolve, ms));
|
|
21
|
+
|
|
22
|
+
function failure(code, message, phase, cause) {
|
|
23
|
+
return Object.assign(new Error(message), { code, phase, deliveryState: "not_applicable", ...(cause ? { cause } : {}) });
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function packageVersion(root, missing = false) {
|
|
27
|
+
const raw = readRegularConfigFile(path.join(root, "package.json"), { missing, maxBytes: 128 * 1024 });
|
|
28
|
+
if (raw === null) return null;
|
|
29
|
+
let value;
|
|
30
|
+
try { value = JSON.parse(raw); } catch {}
|
|
31
|
+
if (value?.name !== PACKAGE || typeof value.version !== "string" || value.version.length > 96 || !/^\d+\.\d+\.\d+(?:[-+][A-Za-z0-9.+-]+)?$/.test(value.version)) {
|
|
32
|
+
throw failure("UPDATE_PACKAGE_INVALID", "The bridge package identity or version could not be verified.", "preflight");
|
|
33
|
+
}
|
|
34
|
+
return value.version;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function newerVersion(left, right) {
|
|
38
|
+
const split = value => { const [core, ...suffix] = value.split("+")[0].split("-"); return { core: core.split(".").map(BigInt), suffix: suffix.join("-") }; };
|
|
39
|
+
const a = split(left);
|
|
40
|
+
const b = split(right);
|
|
41
|
+
for (let index = 0; index < 3; index++) if (a.core[index] !== b.core[index]) return a.core[index] > b.core[index];
|
|
42
|
+
if (!a.suffix || !b.suffix) return !a.suffix && Boolean(b.suffix);
|
|
43
|
+
const parts = [a.suffix.split("."), b.suffix.split(".")];
|
|
44
|
+
for (let index = 0; index < Math.max(...parts.map(part => part.length)); index++) {
|
|
45
|
+
const [x, y] = parts.map(part => part[index]);
|
|
46
|
+
if (x === y) continue;
|
|
47
|
+
if (x === undefined || y === undefined) return y === undefined;
|
|
48
|
+
const numeric = [x, y].map(value => /^\d+$/.test(value));
|
|
49
|
+
return numeric.every(Boolean) ? BigInt(x) > BigInt(y) : numeric[0] !== numeric[1] ? numeric[1] : x > y;
|
|
50
|
+
}
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function resolveUpdateNpm(env = process.env) {
|
|
55
|
+
for (const candidate of [env.npm_execpath, path.join(path.dirname(process.execPath), "node_modules", "npm", "bin", "npm-cli.js")]) {
|
|
56
|
+
try {
|
|
57
|
+
if (typeof candidate !== "string" || !path.isAbsolute(candidate)) continue;
|
|
58
|
+
const resolved = fs.realpathSync.native(candidate);
|
|
59
|
+
if (!/^(?:npm-cli|npm)\.js$/.test(path.basename(resolved)) || !fs.statSync(resolved).isFile()) continue;
|
|
60
|
+
const metadata = JSON.parse(readRegularConfigFile(path.resolve(path.dirname(resolved), "..", "package.json"), { maxBytes: 128 * 1024 }));
|
|
61
|
+
if (metadata.name === "npm") return resolved;
|
|
62
|
+
} catch {}
|
|
63
|
+
}
|
|
64
|
+
throw failure("UPDATE_NPM_NOT_FOUND", "A supported npm CLI could not be located. Run this updater through npm exec.", "preflight");
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function execute(command, args, options) {
|
|
68
|
+
return new Promise(resolve => {
|
|
69
|
+
execFile(command, args, options, (error, stdout, stderr) => resolve({ status: error ? 1 : 0, error, stdout, stderr }));
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function inside(directory, root) {
|
|
74
|
+
const relative = path.relative(root, directory);
|
|
75
|
+
return relative === "" || relative !== ".." && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function neutralDirectory(roots, env) {
|
|
79
|
+
for (const candidate of [os.tmpdir(), env.USERPROFILE, env.HOME, os.homedir()]) {
|
|
80
|
+
try {
|
|
81
|
+
if (typeof candidate !== "string" || !path.isAbsolute(candidate)) continue;
|
|
82
|
+
const directory = fs.realpathSync.native(candidate);
|
|
83
|
+
if (fs.statSync(directory).isDirectory() && roots.every(root => !inside(directory, root))) return directory;
|
|
84
|
+
} catch {}
|
|
85
|
+
}
|
|
86
|
+
throw failure("UPDATE_DIRECTORY_UNAVAILABLE", "No working directory outside the package installation is available.", "preflight");
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function childFailure(result, phase) {
|
|
90
|
+
const match = /npm\s+(?:ERR!|error)\s+code\s+([A-Z][A-Z0-9_]{0,79})\b/.exec(String(result?.stderr ?? ""));
|
|
91
|
+
const code = match?.[1] ?? (/^[A-Z][A-Z0-9_]{0,79}$/.test(result?.error?.code ?? "") ? result.error.code : null);
|
|
92
|
+
const cause = code ? Object.assign(new Error("The child command reported a failure."), { code }) : undefined;
|
|
93
|
+
return failure(code === "EBUSY" ? "UPDATE_PACKAGE_BUSY" : phase === "verification" ? "UPDATE_SETUP_INCOMPLETE" : "UPDATE_NPM_FAILED",
|
|
94
|
+
code === "EBUSY" ? `The installed package is still held open by another process. No process was stopped. ${RETRY}`
|
|
95
|
+
: `The ${phase === "verification" ? "installed setup verification" : "npm command"} did not complete. ${RETRY}`, phase, cause);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function serviceQuiescent(config) {
|
|
99
|
+
for (const name of ["service.lock", "service-status.json"]) {
|
|
100
|
+
const file = path.join(config.paths.root, name);
|
|
101
|
+
if (!assertPrivateRelayFile(file, { missing: true })) continue;
|
|
102
|
+
let state;
|
|
103
|
+
try { state = JSON.parse(readRegularConfigFile(file, { maxBytes: 64 * 1024 })); } catch { return false; }
|
|
104
|
+
if (state?.schemaVersion !== 1 || state.owner !== RELAY_SERVICE_OWNER || !Number.isSafeInteger(state.pid) || state.pid < 1) return false;
|
|
105
|
+
if (state.status === "running" && (!Number.isSafeInteger(state.daemonPid) || state.daemonPid < 1)) return false;
|
|
106
|
+
for (const pid of [state.pid, state.daemonPid].filter(Number.isSafeInteger)) {
|
|
107
|
+
try { process.kill(pid, 0); return false; }
|
|
108
|
+
catch (error) { if (error.code !== "ESRCH") return false; }
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return true;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export async function runUpdate({ args = [], env = process.env, platform = process.platform, root = ROOT, run = execute,
|
|
115
|
+
installService = installBackgroundRelay, readConfig = readRelayConfiguration, readRuntime = readRelayServiceRuntime,
|
|
116
|
+
quiescent = serviceQuiescent, now = Date.now, sleep = pause, waitMs = 120000, onProgress = () => {} } = {}) {
|
|
117
|
+
if (args.some(arg => !["--help", "--json"].includes(arg))) throw failure("UPDATE_ARGUMENT_INVALID", "Usage: codex-bridge-update [--json] [--help]", "preflight");
|
|
118
|
+
if (args.includes("--help")) return { help: "Usage: codex-bridge-update [--json]\nSafely update the global bridge and all managed settings. Legacy Windows relays migrate when existing work finishes; pending migrations can be retried with the same command." };
|
|
119
|
+
if (env.CODEX_BRIDGE_SKIP_SETUP === "1") throw failure("UPDATE_SETUP_DISABLED", "CODEX_BRIDGE_SKIP_SETUP=1 disables managed setup. Remove that explicit opt-out before requesting this complete update.", "preflight");
|
|
120
|
+
if (!Number.isSafeInteger(waitMs) || waitMs < 1 || waitMs > 600000) throw failure("UPDATE_ARGUMENT_INVALID", "The update readiness deadline is invalid.", "preflight");
|
|
121
|
+
root = fs.realpathSync.native(root);
|
|
122
|
+
const version = packageVersion(root);
|
|
123
|
+
const npm = resolveUpdateNpm(env);
|
|
124
|
+
let cwd = neutralDirectory([root], env);
|
|
125
|
+
let childEnv = Object.fromEntries(Object.entries(env).filter(([name]) => !/^AGENT_RELAY_(?!DIRECTORY$)/i.test(name)));
|
|
126
|
+
const command = async (arguments_, phase, timeout = 600000) => {
|
|
127
|
+
let result;
|
|
128
|
+
try {
|
|
129
|
+
result = await run(process.execPath, arguments_, { env: childEnv, cwd, encoding: "utf8", windowsHide: true,
|
|
130
|
+
shell: false, timeout, maxBuffer: 8 * 1024 * 1024, stdio: ["ignore", "pipe", "pipe"] });
|
|
131
|
+
} catch (error) { throw childFailure({ error, stderr: error.stderr }, phase); }
|
|
132
|
+
if (result?.error || (result?.status ?? result?.exitCode ?? 0) !== 0) throw childFailure(result, phase);
|
|
133
|
+
return String(result?.stdout ?? "");
|
|
134
|
+
};
|
|
135
|
+
const modules = (await command([npm, "root", "--global"], "preflight", 30000)).trim();
|
|
136
|
+
if (!path.isAbsolute(modules) || /[\u0000-\u001f\u007f]/.test(modules)) throw failure("UPDATE_GLOBAL_ROOT_INVALID", "npm returned an invalid global installation directory.", "preflight");
|
|
137
|
+
const prefix = (await command([npm, "prefix", "--global"], "preflight", 30000)).trim();
|
|
138
|
+
if (!path.isAbsolute(prefix) || /[\u0000-\u001f\u007f]/.test(prefix)
|
|
139
|
+
|| path.relative(modules, path.join(prefix, ...(platform === "win32" ? [] : ["lib"]), "node_modules")) !== "") {
|
|
140
|
+
throw failure("UPDATE_GLOBAL_ROOT_INVALID", "npm returned inconsistent global prefix and installation directories.", "preflight");
|
|
141
|
+
}
|
|
142
|
+
const globalRoot = path.join(modules, "@minhspark", "codex-mcp-bridge");
|
|
143
|
+
cwd = neutralDirectory([root, globalRoot], env);
|
|
144
|
+
const previousVersion = packageVersion(globalRoot, true);
|
|
145
|
+
if (previousVersion && newerVersion(previousVersion, version)) throw failure("UPDATE_DOWNGRADE_REFUSED", "The global bridge is newer than this updater. Run the update command with the latest published package.", "preflight");
|
|
146
|
+
const config = readConfig({ env: childEnv, platform, missing: true });
|
|
147
|
+
let runtime;
|
|
148
|
+
if (config) {
|
|
149
|
+
runtime = readRuntime(config.paths.root, { root: globalRoot, nodeExecutable: process.execPath });
|
|
150
|
+
if (runtime.packageVersion && newerVersion(runtime.packageVersion, version)) throw failure("UPDATE_DOWNGRADE_REFUSED", "The owned relay runtime is newer than this updater. Run the update command with the latest published package.", "preflight");
|
|
151
|
+
if (runtime.environment !== undefined) childEnv = { ...Object.fromEntries(Object.entries(childEnv).filter(([name]) => !MANAGED_ENV.has(name.toUpperCase()))), ...runtime.environment };
|
|
152
|
+
childEnv.AGENT_RELAY_DIRECTORY = config.paths.root;
|
|
153
|
+
}
|
|
154
|
+
const awaitService = async (target, mutate, phase, expectedVersion = version) => {
|
|
155
|
+
const deadline = now() + waitMs;
|
|
156
|
+
let check = !mutate;
|
|
157
|
+
for (;;) {
|
|
158
|
+
const service = await installService({ env: childEnv, platform, root: target, check, pollAttempts: 1 });
|
|
159
|
+
check = true;
|
|
160
|
+
if (service.configured !== true) throw failure("UPDATE_SERVICE_UNVERIFIED", `The owned relay service could not be verified. ${RETRY}`, phase,
|
|
161
|
+
service.code ? Object.assign(new Error("The service installer reported a failure."), { code: service.code }) : undefined);
|
|
162
|
+
if (service.enabled === false) {
|
|
163
|
+
if (phase === "migration" && !quiescent(config)) throw Object.assign(failure("UPDATE_RELAY_PENDING", `The disabled relay still has an owned process whose release could not be verified. ${RETRY}`, phase), { pending: true });
|
|
164
|
+
return { enabled: false, ready: false, liveVerified: false };
|
|
165
|
+
}
|
|
166
|
+
if (service.enabled === true && service.liveVerified === true && service.ready === true && service.version === expectedVersion
|
|
167
|
+
&& Number.isSafeInteger(service.pid) && service.pid > 0) return { enabled: true, ready: true, liveVerified: true, version: expectedVersion, pid: service.pid };
|
|
168
|
+
if (now() >= deadline) throw Object.assign(failure("UPDATE_RELAY_PENDING", `The relay is still completing its owned runtime transition. ${RETRY}`, phase), { pending: true });
|
|
169
|
+
await sleep(Math.min(1000, Math.max(1, deadline - now())));
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
let migrated = false;
|
|
173
|
+
const legacy = value => ["1.26.0", "1.26.1"].includes(value);
|
|
174
|
+
if (platform === "win32" && config && (legacy(previousVersion) || legacy(runtime.packageVersion))) {
|
|
175
|
+
if (config.enabled === false) {
|
|
176
|
+
if (!quiescent(config)) throw Object.assign(failure("UPDATE_RELAY_PENDING", `The disabled relay still has an owned process whose release could not be verified. ${RETRY}`, "migration"), { pending: true });
|
|
177
|
+
} else {
|
|
178
|
+
onProgress("Waiting for the legacy relay to finish existing work and activate the update runtime.");
|
|
179
|
+
const staged = runtime.packageVersion && !legacy(runtime.packageVersion) && !newerVersion("1.26.2", runtime.packageVersion);
|
|
180
|
+
const service = await awaitService(staged ? runtime.packageRoot : root, !staged, "migration", staged ? runtime.packageVersion : version);
|
|
181
|
+
migrated = !staged && service.enabled;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
onProgress(`Installing bridge ${version} and applying managed settings.`);
|
|
185
|
+
await command([npm, "install", "--global", "--prefix", prefix, `${PACKAGE}@${version}`, "--ignore-scripts=false", `--allow-scripts=${PACKAGE}`, "--foreground-scripts"], "installation");
|
|
186
|
+
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");
|
|
187
|
+
onProgress("Verifying the global bridge settings and owned relay runtime.");
|
|
188
|
+
let setup;
|
|
189
|
+
try { setup = JSON.parse(await command([path.join(globalRoot, "scripts", "setup.mjs"), "--check", "--json"], "verification")); }
|
|
190
|
+
catch (error) { if (error?.code) throw error; throw failure("UPDATE_SETUP_INCOMPLETE", `Global setup did not return a verifiable result. ${RETRY}`, "verification"); }
|
|
191
|
+
if (setup?.configured !== true) throw failure("UPDATE_SETUP_INCOMPLETE", `The global bridge settings are incomplete. ${RETRY}`, "verification");
|
|
192
|
+
const service = await awaitService(globalRoot, false, "verification");
|
|
193
|
+
return { updated: true, configured: true, version, previousVersion, migrated, service, opensApps: false, opensChats: false };
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
if (isMainModule(process.argv[1], import.meta.url)) {
|
|
197
|
+
exitForVersionRequest(import.meta.url);
|
|
198
|
+
const args = process.argv.slice(2);
|
|
199
|
+
try {
|
|
200
|
+
process.chdir(neutralDirectory([ROOT], process.env));
|
|
201
|
+
const result = await runUpdate({ args, onProgress: message => process.stderr.write(`${message}\n`) });
|
|
202
|
+
process.stdout.write(result.help ? `${result.help}\n` : args.includes("--json") ? `${JSON.stringify(result, null, 2)}\n`
|
|
203
|
+
: `Bridge ${result.version} updated; managed settings verified. Background relay ${result.service.ready ? "ready" : "remains intentionally disabled"}.\n`);
|
|
204
|
+
} catch (error) {
|
|
205
|
+
const options = { component: "bridge-update", operation: "update", deliveryState: "not_applicable" };
|
|
206
|
+
if (args.includes("--json")) process.stdout.write(JSON.stringify({ updated: false, pending: error.pending === true, diagnostic: bridgeDiagnostic(error, options) }, null, 2) + "\n");
|
|
207
|
+
else process.stderr.write(withBridgeDiagnostic({ isError: true, content: [] }, error, options).content.map(item => item.text ?? "").join("\n") + "\n");
|
|
208
|
+
process.exitCode = 1;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
@@ -233,7 +233,7 @@ export async function runBackgroundRelayService({ env = process.env, platform =
|
|
|
233
233
|
signal?.addEventListener("abort", stop, { once: true });
|
|
234
234
|
try {
|
|
235
235
|
child = spawn(runtime.nodeExecutable, [path.join(root, "src", "background-relay-daemon.mjs")], {
|
|
236
|
-
cwd: root, env: childEnv, windowsHide: true, shell: false, stdio: ["ignore", "ignore", "pipe"],
|
|
236
|
+
cwd: config.paths.root, env: childEnv, windowsHide: true, shell: false, stdio: ["ignore", "ignore", "pipe"],
|
|
237
237
|
});
|
|
238
238
|
child.stderr?.on("error", () => {});
|
|
239
239
|
child.stderr?.on("data", captureDiagnostic);
|
|
@@ -291,6 +291,7 @@ if (!new URL(import.meta.url).search && isMainModule(process.argv[1], import.met
|
|
|
291
291
|
process.on("SIGINT", stop);
|
|
292
292
|
process.on("SIGTERM", stop);
|
|
293
293
|
try {
|
|
294
|
+
process.chdir(readRelayConfiguration().paths.root);
|
|
294
295
|
let run = runBackgroundRelayService;
|
|
295
296
|
while (true) {
|
|
296
297
|
const result = await run({ signal: controller.signal });
|
package/src/claude-bridge.mjs
CHANGED
|
@@ -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.
|
|
34
|
+
const VERSION = "1.26.2";
|
|
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;
|
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.
|
|
47
|
+
const VERSION = "1.26.2";
|
|
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.
|
|
46
|
+
const VERSION = "1.26.2";
|
|
47
47
|
const log = (msg) => process.stderr.write(`[native-relay] ${msg}\n`);
|
|
48
48
|
|
|
49
49
|
function errorResponse(code, message, sent, details) {
|