@minhspark/codex-mcp-bridge 1.25.2 → 1.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.codex-plugin/plugin.json +1 -1
- package/CHANGELOG.md +58 -0
- package/README.md +81 -32
- package/docs/new-macos-setup.md +47 -21
- package/docs/new-windows-setup.md +34 -9
- package/docs/project-onboarding.md +21 -8
- package/package.json +2 -1
- package/plugin.json +1 -1
- package/scripts/background-relay-hidden.vbs +11 -0
- package/scripts/install-antigravity-bridge.mjs +65 -23
- package/scripts/install-background-relay.mjs +428 -0
- 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-background-relay.mjs +58 -0
- package/scripts/setup.mjs +3 -3
- package/scripts/worker-relay.mjs +41 -0
- package/src/antigravity-bridge.mjs +96 -27
- package/src/antigravity-cli.mjs +13 -2
- package/src/antigravity-deliveries.mjs +32 -8
- package/src/antigravity-ipc.mjs +18 -9
- package/src/antigravity-outbound-bridge.mjs +71 -23
- package/src/antigravity-outbound-targets.mjs +100 -10
- package/src/background-antigravity-worker.mjs +192 -0
- package/src/background-claude-worker.mjs +240 -0
- package/src/background-codex-worker.mjs +344 -0
- package/src/background-relay-client.mjs +107 -0
- package/src/background-relay-config.mjs +98 -0
- package/src/background-relay-daemon.mjs +60 -0
- package/src/background-relay-mcp.mjs +45 -0
- package/src/background-relay-protocol.mjs +54 -0
- package/src/background-relay-registration.mjs +198 -0
- package/src/background-relay-service.mjs +311 -0
- package/src/background-relay-storage.mjs +203 -0
- package/src/background-relay-storage.ps1 +64 -0
- package/src/background-relay.mjs +373 -0
- package/src/bridge-readiness.mjs +2 -2
- package/src/claude-bridge.mjs +43 -25
- package/src/claude-code-registration.mjs +2 -1
- package/src/claude-session-router.mjs +8 -15
- package/src/index.mjs +39 -22
- package/src/mcp-supervisor.mjs +26 -16
- 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/reload-control.mjs +2 -2
- package/src/setup.mjs +62 -25
- package/src/thread-delivery.mjs +10 -5
- package/src/windows-pipe-acl.ps1 +1 -1
package/src/setup.mjs
CHANGED
|
@@ -46,14 +46,23 @@ function execute(command, args, env, timeout = 120000) {
|
|
|
46
46
|
const result = spawnSync(command, args, { env, encoding: "utf8", windowsHide: true, shell: false, timeout,
|
|
47
47
|
maxBuffer: 4 * 1024 * 1024, stdio: ["ignore", "pipe", "pipe"] });
|
|
48
48
|
if (result.error || result.status !== 0) {
|
|
49
|
-
|
|
50
|
-
&& !/Command failed|--env|password|secret|token|authorization/i.test(line));
|
|
51
|
-
const detail = lines.slice(0, 3).join(" ") || result.error?.code || `exit ${result.status}`;
|
|
52
|
-
throw new Error(`${path.basename(command)} ${path.basename(args[0] ?? "")}: ${detail}`);
|
|
49
|
+
throw setupProcessFailure(command, args, result);
|
|
53
50
|
}
|
|
54
51
|
return result.stdout || "";
|
|
55
52
|
}
|
|
56
53
|
|
|
54
|
+
export function setupProcessFailure(command, args, result) {
|
|
55
|
+
let structured;
|
|
56
|
+
try { structured = JSON.parse(String(result.stdout || "")); } catch {}
|
|
57
|
+
const validCode = value => typeof value === "string" && /^[A-Z][A-Z0-9_]{0,79}$/.test(value);
|
|
58
|
+
const codes = [structured?.code, structured?.service?.code, structured?.permissions?.code, structured?.diagnostic?.code,
|
|
59
|
+
...String(result.stderr || "").split(/\r?\n/).map(line => /^([A-Z][A-Z0-9_]{0,79}) \| /.exec(line)?.[1])].filter(validCode);
|
|
60
|
+
const lines = String(result.stderr || "").split(/\r?\n/).filter(line => /^Error:|^(?:Expected|Refusing|Invalid|Unknown|Shared|Claude|Codex|Configuration|The existing|Missing|Unsafe)/.test(line)
|
|
61
|
+
&& !/Command failed|--env|password|secret|token|authorization/i.test(line));
|
|
62
|
+
const detail = [...new Set(codes)].join(", ") || lines.slice(0, 3).join(" ") || result.error?.code || `exit ${result.status}`;
|
|
63
|
+
return Object.assign(new Error(`${path.basename(command)} ${path.basename(args[0] ?? "")}: ${detail}`), codes[0] ? { code: codes[0] } : {});
|
|
64
|
+
}
|
|
65
|
+
|
|
57
66
|
function usableBinary(binary, platform) {
|
|
58
67
|
return typeof binary === "string" && path.isAbsolute(binary) && fs.existsSync(binary)
|
|
59
68
|
&& fs.statSync(binary).isFile() && (platform !== "win32" || /\.(exe|com)$/i.test(binary));
|
|
@@ -83,24 +92,25 @@ export function ensureSetupCodex({ env, paths, platform, download = true, run =
|
|
|
83
92
|
}
|
|
84
93
|
|
|
85
94
|
export function setupEnvironment(env, paths, codex) {
|
|
86
|
-
const result = Object.fromEntries(Object.entries(env).filter(([name]) => !/^(?:CODEX_BRIDGE_|CLAUDE_BRIDGE_|CODEX_NATIVE_RELAY_|CODEX_RELAY_ID$|CODEX_THREAD_ID$|CODEX_APP_TOOLS_PIPE_PATH$)/.test(name)));
|
|
95
|
+
const result = Object.fromEntries(Object.entries(env).filter(([name]) => !/^(?:CODEX_BRIDGE_|CLAUDE_BRIDGE_|CODEX_NATIVE_RELAY_|CODEX_RELAY_ID$|CODEX_THREAD_ID$|CODEX_APP_TOOLS_PIPE_PATH$|AGENT_RELAY_(?:TOKEN|WORKER_ID|REQUEST_ID|ENDPOINT)$)/.test(name)));
|
|
87
96
|
return { ...result, HOME: paths.home, USERPROFILE: paths.home, CODEX_HOME: paths.codex,
|
|
88
97
|
CLAUDE_DESKTOP_CONFIG: paths.desktop, CODEX_EXE: codex, CODEX_BIN: codex };
|
|
89
98
|
}
|
|
90
99
|
|
|
91
100
|
function configurationCheck(label, check, components) {
|
|
92
|
-
try { check(); components.push({ name: label, status: "configured" }); }
|
|
101
|
+
try { const details = check(); components.push({ name: label, status: "configured", ...details }); }
|
|
93
102
|
catch (error) { components.push({ name: label, status: "incomplete", detail: error.message }); }
|
|
94
103
|
}
|
|
95
104
|
|
|
96
105
|
function assertEntry(entry, worker, root, { caller } = {}) {
|
|
97
106
|
if (!entry || typeof entry.command !== "string" || !fs.existsSync(entry.command)) throw new Error("MCP command is missing or unavailable");
|
|
98
107
|
const args = entry.args ?? [];
|
|
99
|
-
const expected =
|
|
108
|
+
const expected = ["index.mjs", "claude-bridge.mjs", "native-relay-companion.mjs", "antigravity-bridge.mjs", "antigravity-outbound-bridge.mjs"].includes(worker)
|
|
100
109
|
? [path.join(root, "src", "mcp-supervisor.mjs"), worker] : [path.join(root, "src", worker)];
|
|
101
110
|
if (JSON.stringify(args) !== JSON.stringify(expected)) throw new Error("MCP entry points to a different installation or unsupported launcher");
|
|
102
|
-
if (entry.enabled === false || entry.disabled === true) throw new Error("MCP entry is disabled; the saved choice was preserved");
|
|
103
111
|
if (caller && entry.env?.ANTIGRAVITY_BRIDGE_CALLER !== caller) throw new Error("Antigravity caller registration is missing or conflicting");
|
|
112
|
+
if (entry.enabled === false || entry.disabled === true) return { deliveryEnabled: false,
|
|
113
|
+
notices: ["This MCP registration is intentionally disabled. Its saved choice was preserved; delivery through this connector is disabled."] };
|
|
104
114
|
}
|
|
105
115
|
|
|
106
116
|
export function checkSetup({ env = process.env, platform = process.platform, root = ROOT, run = execute, resolve = resolveCodexBin } = {}) {
|
|
@@ -119,8 +129,9 @@ export function checkSetup({ env = process.env, platform = process.platform, roo
|
|
|
119
129
|
const item = inventory?.find((server) => server.name === name);
|
|
120
130
|
if (!item) throw new Error("MCP registration is missing");
|
|
121
131
|
const entry = JSON.parse(run(codex, ["mcp", "get", name, "--json"], setupEnvironment(env, paths, codex), 30000));
|
|
122
|
-
assertEntry({ ...entry.transport, enabled: entry.enabled }, worker, root, name === "antigravity-bridge" ? { caller: "codex" } : {});
|
|
132
|
+
const details = assertEntry({ ...entry.transport, enabled: entry.enabled }, worker, root, name === "antigravity-bridge" ? { caller: "codex" } : {});
|
|
123
133
|
if (name === "codex-native-relay" && !entry.transport.env_vars?.includes("CODEX_APP_TOOLS_PIPE_PATH")) throw new Error("Native pipe forwarding is missing");
|
|
134
|
+
return details;
|
|
124
135
|
}, components);
|
|
125
136
|
}
|
|
126
137
|
for (const [label, file, name, worker, caller] of [
|
|
@@ -130,14 +141,26 @@ export function checkSetup({ env = process.env, platform = process.platform, roo
|
|
|
130
141
|
["Antigravity / agent-bridge", path.join(paths.gemini, "mcp_config.json"), "agent-bridge", "antigravity-outbound-bridge.mjs"],
|
|
131
142
|
]) configurationCheck(label, () => {
|
|
132
143
|
const entry = readJson(file)?.mcpServers?.[name];
|
|
133
|
-
assertEntry(entry, worker, root, { caller });
|
|
144
|
+
const details = assertEntry(entry, worker, root, { caller });
|
|
145
|
+
if (worker === "index.mjs" && entry.env?.CODEX_BRIDGE_OPEN_IN_APP === "1") {
|
|
146
|
+
throw new Error("Managed bridge settings still allow opening Codex Desktop. Run codex-bridge-setup to apply the current silent configuration.");
|
|
147
|
+
}
|
|
134
148
|
if (name === "codex-bridge-desktop" && entry.env?.CODEX_BRIDGE_DESKTOP_TASKS === "1") {
|
|
135
|
-
|
|
149
|
+
return { ...details, nativeCodeOnly: true, sharedChatDelivery: "unsupported",
|
|
150
|
+
notices: [...(details?.notices ?? []), "The saved native Code-only policy was preserved. Ordinary Claude Desktop Chat cannot deliver through this connector; native delivery uses the registered Claude Desktop Code connector and remains unverified by setup."] };
|
|
136
151
|
}
|
|
152
|
+
return details;
|
|
153
|
+
}, components);
|
|
154
|
+
configurationCheck("Claude Desktop / background preference", () => {
|
|
155
|
+
if (readJson(paths.desktop)?.preferences?.menuBarEnabled !== true) throw new Error("The managed Claude background preference is not enabled. Run codex-bridge-setup to apply it; live activation is verified separately.");
|
|
137
156
|
}, components);
|
|
138
157
|
configurationCheck("Antigravity / codex-bridge sidecar", () => {
|
|
139
|
-
assertEntry(readJson(path.join(paths.gemini, "sidecars", "codex-bridge", "sidecar.json")), "antigravity-sidecar.mjs", root);
|
|
140
|
-
|
|
158
|
+
const details = assertEntry(readJson(path.join(paths.gemini, "sidecars", "codex-bridge", "sidecar.json")), "antigravity-sidecar.mjs", root);
|
|
159
|
+
const enabled = readJson(path.join(paths.gemini, "config.json"))?.sidecars?.["codex-bridge"]?.enabled;
|
|
160
|
+
if (typeof enabled !== "boolean") throw new Error("Antigravity sidecar enabled setting is missing or invalid");
|
|
161
|
+
if (!enabled) return { deliveryEnabled: false,
|
|
162
|
+
notices: [...(details?.notices ?? []), "The Antigravity bridge sidecar is intentionally disabled. Its saved choice was preserved; native Desktop delivery through this sidecar is disabled."] };
|
|
163
|
+
return details;
|
|
141
164
|
}, components);
|
|
142
165
|
if (native) configurationCheck("Native relay executor", () => {
|
|
143
166
|
const relay = readJson(path.join(paths.codex, "native-relay.json"));
|
|
@@ -146,17 +169,22 @@ export function checkSetup({ env = process.env, platform = process.platform, roo
|
|
|
146
169
|
configurationCheck("Claude registration names", () => {
|
|
147
170
|
if (readJson(paths.desktop)?.mcpServers?.["codex-bridge"]) throw new Error("Shared codex-bridge shadows the Claude Code registration");
|
|
148
171
|
}, components);
|
|
172
|
+
configurationCheck("Independent background relay", () => {
|
|
173
|
+
const details = JSON.parse(run(process.execPath, [path.join(root, "scripts", "setup-background-relay.mjs"), "--check", "--json"], setupEnvironment(env, paths, codex), 90000));
|
|
174
|
+
if (details.configured !== true) throw new Error("Independent worker relay configuration is incomplete");
|
|
175
|
+
return { liveVerified: details.liveVerified === true, transportReady: details.transportReady === true, notices: details.notices ?? [] };
|
|
176
|
+
}, components);
|
|
149
177
|
return { configured: components.every((item) => item.status === "configured"), liveVerified: false, components };
|
|
150
178
|
}
|
|
151
179
|
|
|
152
180
|
export function runSetup({ args = [], env = process.env, platform = process.platform, root = ROOT, run = execute, resolve = resolveCodexBin } = {}) {
|
|
153
181
|
const options = setupArguments(args);
|
|
154
|
-
if (options.help) return { help: "Usage: codex-bridge-setup [--check|--dry-run] [--json] [--no-download]\nGlobal npm installation configures Claude Desktop, Claude Code, Codex and
|
|
182
|
+
if (options.help) return { help: "Usage: codex-bridge-setup [--check|--dry-run] [--json] [--no-download]\nUpdate the package and apply managed settings with: npm install -g @minhspark/codex-mcp-bridge@latest --allow-scripts=@minhspark/codex-mcp-bridge --foreground-scripts\nGlobal npm installation configures Claude Desktop, Claude Code, Codex, Antigravity and the independent worker relay automatically. CODEX_BRIDGE_SKIP_SETUP=1 opts out. Saved configuration, background relay health and loaded native app connections are verified separately." };
|
|
155
183
|
if (options.postinstall && !automaticSetupEnabled(env)) return { skipped: true, reason: "Automatic configuration runs only for a global npm install; use codex-bridge-setup for manual setup." };
|
|
156
184
|
if (options.check) return checkSetup({ env, platform, root, run, resolve });
|
|
157
185
|
const native = platform === "win32" || platform === "darwin";
|
|
158
186
|
const paths = setupPaths(env, platform);
|
|
159
|
-
const planned = ["Claude Code / codex-bridge", "Claude Desktop / codex-bridge-desktop", ...(native ? ["Codex / codex-native-relay and executor"] : []), "Codex / claude-bridge", "Antigravity / all components"];
|
|
187
|
+
const planned = ["Claude Code / codex-bridge", "Claude Desktop / codex-bridge-desktop", ...(native ? ["Codex / codex-native-relay and executor"] : []), "Codex / claude-bridge", "Antigravity / all components", "Independent background relay"];
|
|
160
188
|
if (options.dryRun) return { dryRun: true, configured: false, liveVerified: false, components: planned.map((name) => ({ name, status: "planned" })), files: [paths.code, paths.desktop, path.join(paths.codex, "config.toml"), paths.gemini] };
|
|
161
189
|
if (env.SUDO_USER && env.SUDO_USER !== "root" && typeof process.getuid === "function" && process.getuid() === 0) throw new Error("Run the global install without sudo in the account that runs the apps; setup will not write another account's configuration.");
|
|
162
190
|
const runtime = ensureSetupCodex({ env, paths, platform, download: !options.noDownload, run, resolve });
|
|
@@ -166,39 +194,48 @@ export function runSetup({ args = [], env = process.env, platform = process.plat
|
|
|
166
194
|
const install = (name, script, arguments_, environment = base) => {
|
|
167
195
|
try {
|
|
168
196
|
const output = run(process.execPath, [path.join(root, "scripts", script), ...arguments_], environment, 180000);
|
|
169
|
-
let
|
|
170
|
-
try {
|
|
171
|
-
|
|
197
|
+
let details = {};
|
|
198
|
+
try { details = JSON.parse(output); } catch {}
|
|
199
|
+
const notices = details.notices ?? [];
|
|
200
|
+
components.push({ name, status: "configured", ...(notices.length ? { notices } : {}),
|
|
201
|
+
...(typeof details.liveVerified === "boolean" ? { liveVerified: details.liveVerified, transportReady: details.transportReady === true } : {}),
|
|
202
|
+
...(details.backgroundPreference ? { backgroundPreference: details.backgroundPreference } : {}) });
|
|
172
203
|
return true;
|
|
173
204
|
} catch (error) { components.push({ name, status: "incomplete", detail: error.message }); return false; }
|
|
174
205
|
};
|
|
175
|
-
const code = install(planned[0], "install-claude-code.mjs", ["--install", "--desktop-config", paths.desktop], {
|
|
206
|
+
const code = install(planned[0], "install-claude-code.mjs", ["--install", "--setup", "--desktop-config", paths.desktop], {
|
|
176
207
|
...base, CODEX_BRIDGE_DESKTOP_TASKS: native ? "1" : "0", CODEX_BRIDGE_AUTOSTART: native ? "0" : "1", CODEX_BRIDGE_THREAD_POLICY: "roots",
|
|
177
208
|
});
|
|
178
|
-
if (code) install(planned[1], "install-claude-desktop.mjs", ["--entry-name", "codex-bridge-desktop", "--quiet"]);
|
|
209
|
+
if (code) install(planned[1], "install-claude-desktop.mjs", ["--entry-name", "codex-bridge-desktop", "--quiet", "--setup"]);
|
|
179
210
|
if (native) {
|
|
180
211
|
const relay = readJson(path.join(paths.codex, "native-relay.json"));
|
|
181
212
|
install("Codex / codex-native-relay and executor", "install-native-relay.mjs", ["--setup", ...(relay?.desktopTasks === undefined ? ["--desktop-tasks"] : [])]);
|
|
182
213
|
}
|
|
183
214
|
install("Codex / claude-bridge", "install-codex-mcp.mjs", ["--setup"]);
|
|
184
215
|
if (code) install("Antigravity / all components", "install-antigravity-bridge.mjs", ["--all", "--setup"]);
|
|
216
|
+
install("Independent background relay", "setup-background-relay.mjs", ["--json"]);
|
|
185
217
|
const inspection = checkSetup({ env: base, platform, root, run, resolve: () => runtime.binary });
|
|
186
218
|
return { configured: components.every((item) => item.status === "configured") && inspection.configured, liveVerified: false,
|
|
187
219
|
cliInstalled: runtime.installed, components, verification: inspection.components,
|
|
188
|
-
nextActions: ["
|
|
189
|
-
"
|
|
190
|
-
"
|
|
220
|
+
nextActions: ["Running MCP processes may still hold earlier settings. Setup does not start apps or open conversations.",
|
|
221
|
+
"Existing compatible supervisors reload installed source when idle; configuration changes are not proof of loaded-process readiness.",
|
|
222
|
+
"Native delivery uses the same saved project and signed-in accounts in Claude Desktop Code and Codex Desktop.",
|
|
223
|
+
"codex_bridge_status, native_relay_status and agent_bridge_status report native readiness separately from this configuration check.",
|
|
224
|
+
"worker_status or worker-relay status reports the independent service and CLI workers, which do not require a responsive Desktop host."] };
|
|
191
225
|
}
|
|
192
226
|
|
|
193
227
|
export function printSetup(result, { json = false, output = console.log } = {}) {
|
|
194
228
|
if (json) { output(JSON.stringify(result, null, 2)); return; }
|
|
195
229
|
if (result.help) { output(result.help); return; }
|
|
196
230
|
if (result.skipped) { output(result.reason); return; }
|
|
197
|
-
output(result.dryRun ? "Bridge setup preview (no changes)" : result.configured ? "Bridge configuration verified.
|
|
231
|
+
output(result.dryRun ? "Bridge setup preview (no changes)" : result.configured ? "Bridge configuration verified. Running app connections have not been verified." : "Bridge setup is incomplete. Fix the items below, then run codex-bridge-setup again.");
|
|
198
232
|
for (const item of result.components ?? []) {
|
|
199
233
|
output(`[${item.status}] ${item.name}${item.detail ? `: ${item.detail}` : ""}`);
|
|
200
234
|
for (const notice of item.notices ?? []) output(` ${notice}`);
|
|
201
235
|
}
|
|
202
|
-
for (const item of result.verification ?? [])
|
|
236
|
+
for (const item of result.verification ?? []) {
|
|
237
|
+
if (item.status !== "configured") output(`[${item.status}] ${item.name}: ${item.detail}`);
|
|
238
|
+
for (const notice of item.notices ?? []) output(`${item.name}: ${notice}`);
|
|
239
|
+
}
|
|
203
240
|
for (const action of result.nextActions ?? []) output(action);
|
|
204
241
|
}
|
package/src/thread-delivery.mjs
CHANGED
|
@@ -9,6 +9,7 @@ import { captureCodexRolloutWatermark, inspectCodexNativeTurn, readCodexNativeTu
|
|
|
9
9
|
import { captureProjectScope, recheckProjectScope } from "./project-scope.mjs";
|
|
10
10
|
import { isRolloutChangedDuringRead } from "./rollout-segments.mjs";
|
|
11
11
|
import { requireClaudeSenderContext } from "./claude-sender-context.mjs";
|
|
12
|
+
import { bridgeDiagnostic } from "./recipient-preflight.mjs";
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
15
|
* Which backend puts a message into a Codex thread.
|
|
@@ -74,7 +75,7 @@ export function matchDesktopProject(projects, cwd, { canonicalize = realpathSync
|
|
|
74
75
|
return matches[0];
|
|
75
76
|
}
|
|
76
77
|
|
|
77
|
-
export const RELAY_DOWN_GUIDANCE = "The Codex Desktop native relay is not listening after waiting for silent recovery. Its Desktop-owned supervisor restarts crashed relay workers without replaying requests.
|
|
78
|
+
export const RELAY_DOWN_GUIDANCE = "The Codex Desktop native relay is not listening after waiting for silent recovery. Its Desktop-owned supervisor restarts crashed relay workers without replaying requests. An unloaded native host cannot be cold-started by this bridge. Inspect codex_bridge_status and include its diagnostic in a report. Never open an app or an old, new, empty or failed chat to load a relay.";
|
|
78
79
|
|
|
79
80
|
function relayUnreachable(error) {
|
|
80
81
|
return error?.code === "RELAY_UNREACHABLE" && error.sent === false;
|
|
@@ -196,13 +197,17 @@ export class DesktopTaskDelivery {
|
|
|
196
197
|
async status() {
|
|
197
198
|
const accountContext = this.accountContext?.();
|
|
198
199
|
const socketPath = this.relay.status?.({ accountContext })?.socketPath ?? this.relay.socketPath;
|
|
199
|
-
if (this.accountContext && !accountContext)
|
|
200
|
+
if (this.accountContext && !accountContext) {
|
|
201
|
+
const reason = "The current Claude and Codex accounts could not both be verified. Finish signing in and inspect the account diagnostics before sending work.";
|
|
202
|
+
return { available: false, socketPath, code: "BRIDGE_ACCOUNT_UNVERIFIED", reason, diagnostic: bridgeDiagnostic(new Error(reason), { component: "codex-bridge", operation: "codex_bridge_status", code: "BRIDGE_ACCOUNT_UNVERIFIED", readOnly: true }) };
|
|
203
|
+
}
|
|
200
204
|
try {
|
|
201
205
|
const response = await this.request("list_projects", {});
|
|
202
206
|
if (!Array.isArray(response?.projects)) throw new Error("Desktop returned no project list");
|
|
203
207
|
return { available: true, socketPath, localProjects: response.projects.filter((project) => project.projectKind === "local" && project.hostId === "local").length };
|
|
204
208
|
} catch (err) {
|
|
205
|
-
|
|
209
|
+
const diagnostic = bridgeDiagnostic(err, { component: "codex-bridge", operation: "codex_bridge_status", readOnly: true });
|
|
210
|
+
return { available: false, socketPath, code: diagnostic.code, reason: err.message, diagnostic };
|
|
206
211
|
}
|
|
207
212
|
}
|
|
208
213
|
|
|
@@ -336,11 +341,11 @@ export class DesktopTaskDelivery {
|
|
|
336
341
|
const confirmedId = response?.threadId ?? response?.conversationId;
|
|
337
342
|
threadId = confirmedId;
|
|
338
343
|
if (!threadId && (response?.status === "outcome-unknown" || response?.firstTurn?.status === "outcome-unknown")) threadId = response?.clientThreadId;
|
|
339
|
-
if (typeof confirmedId !== "string" || !confirmedId.trim() || response?.status === "outcome-unknown" || response.hostId !== "local") throw new Error(
|
|
344
|
+
if (typeof confirmedId !== "string" || !confirmedId.trim() || response?.status === "outcome-unknown" || response.hostId !== "local") throw Object.assign(new Error("Desktop creation is not confirmed; inspect the original native receipt."), { code: "CODEX_CREATION_UNCONFIRMED", deliveryState: "unknown", phase: "creation" });
|
|
340
345
|
await this.receipts.write(identity.key, { ...receipt, state: "known", threadId });
|
|
341
346
|
creationConfirmed = true;
|
|
342
347
|
this.security.registerThread(threadId);
|
|
343
|
-
if (response.firstTurn && response.firstTurn.status !== "accepted") throw new Error(`Desktop created task ${threadId}; its first turn reports ${response.firstTurn.status
|
|
348
|
+
if (response.firstTurn && response.firstTurn.status !== "accepted") throw Object.assign(new Error(`Desktop created task ${threadId}; its first turn reports ${["failed", "waitingOnApproval", "waitingOnUserInput", "outcome-unknown"].includes(response.firstTurn.status) ? response.firstTurn.status : "an unconfirmed state"}. Inspect the original native receipt.`), { code: "CODEX_FIRST_TURN_NOT_ACCEPTED", deliveryState: "sent", phase: "first_turn" });
|
|
344
349
|
const created = { threadId, name, cwd, projectId: project.projectId, projectName: project.label, backend: NATIVE_BACKEND };
|
|
345
350
|
const delivered = { ...created, previousTurnId: null, deliveryStatus: "accepted", responseObservation: {
|
|
346
351
|
operation: "create_thread", threadId, previousTurnId: null, expectedCwd: cwd,
|
package/src/windows-pipe-acl.ps1
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
param([Parameter(Mandatory)][string]$PipeName,[Parameter(Mandatory)][uint32]$ServerPid)
|
|
2
2
|
$ErrorActionPreference='Stop'
|
|
3
|
-
if($PipeName -notmatch '^LOCAL\\(?:codex-native-relay|codex-bridge|cc-msg)-[A-Za-z0-9_.-]
|
|
3
|
+
if($PipeName -notmatch '^LOCAL\\(?:(?:codex-native-relay|codex-bridge|cc-msg)-[A-Za-z0-9_.-]+|minhspark-agent-relay-[a-f0-9]{24})$'){throw 'Refusing a pipe outside the bridge-owned namespace.'}
|
|
4
4
|
Add-Type @'
|
|
5
5
|
using System;
|
|
6
6
|
using System.ComponentModel;
|