@minhspark/codex-mcp-bridge 1.22.0 → 1.22.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 +34 -0
- package/README.md +10 -7
- package/package.json +1 -1
- package/plugin.json +1 -1
- package/scripts/install-native-relay.mjs +1 -1
- package/scripts/publish-repo-analytics.mjs +1 -1
- package/src/claude-bridge.mjs +1 -1
- package/src/desktop-task-receipts.mjs +12 -12
- package/src/index.mjs +1 -1
- package/src/native-relay-companion.mjs +1 -1
- package/src/prompt-guidance.mjs +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,40 @@ Follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and [SemVer](ht
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [1.22.2] - 2026-10-13
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- Preserve exact filesystem identities when checking Desktop creation locks and receipts. Large file IDs can collide when represented as JavaScript Numbers; BigInt stat values prevent a replaced lock with a copied token from being mistaken for the owned file.
|
|
12
|
+
- Clarify the shared sending-tool guidance: agent-authored handoffs must identify their actual Codex or Claude author in the first line and use English throughout, including the header purpose, instructions, constraints, and reply format.
|
|
13
|
+
- Require sufficient measured context, file boundaries, validation steps, and completion criteria for a receiving agent to act without guessing.
|
|
14
|
+
|
|
15
|
+
### Verification
|
|
16
|
+
|
|
17
|
+
- A deterministic regression uses two distinct file IDs above the safe integer limit. It fails against the previous implementation and passes with exact BigInt comparisons; the real filesystem replacement test remains enabled.
|
|
18
|
+
- Full Node test suite on macOS: 1,276 passed, 23 skipped, zero failures. A clean archived checkout passed 1,268 tests with 23 skipped and zero failures; Git-dependent tests are not registered outside a Git checkout.
|
|
19
|
+
|
|
20
|
+
### Upgrade notes
|
|
21
|
+
|
|
22
|
+
- The handoff changes update prompt guidance, not automatic translation or payload validation. Verbatim user text and exact identifiers retain their original content.
|
|
23
|
+
- The native host may still display its own generic attribution label. A sender header inside the prompt does not rename that label or alter permission checks. Cowork/Dispatch support is unchanged.
|
|
24
|
+
- Reconnect the MCP client to load the updated tool descriptions; installing the package does not hot-reload an existing process.
|
|
25
|
+
|
|
26
|
+
## [1.22.1] - 2026-10-13
|
|
27
|
+
|
|
28
|
+
### Fixed
|
|
29
|
+
|
|
30
|
+
- Align the README badges in two centered rows. Render the three custom analytics badges at an intrinsic height of 20 pixels to match the standard flat badges even when GitHub overrides HTML height attributes. Scale both SVG dimensions together to preserve the artwork proportions.
|
|
31
|
+
|
|
32
|
+
### Verification
|
|
33
|
+
|
|
34
|
+
- Regression coverage checks the intrinsic height and aspect ratio of all three generated analytics badges. The existing analytics tests retain coverage for source dates, stale values, missing data, and aggregate privacy.
|
|
35
|
+
- `npm test` passes from a clean archived checkout: 1,267 passed, 23 platform skips, and no failures. The Repository analytics workflow publishes the updated SVGs from the existing source data.
|
|
36
|
+
|
|
37
|
+
### Upgrade notes
|
|
38
|
+
|
|
39
|
+
- This release updates README presentation and the bundled analytics publisher. MCP behavior is unchanged; it does not add or validate a Desktop handoff feature. GitHub may cache badge images until its image proxy refreshes them.
|
|
40
|
+
|
|
7
41
|
## [1.22.0] - 2026-10-12
|
|
8
42
|
|
|
9
43
|
### Added
|
package/README.md
CHANGED
|
@@ -6,13 +6,16 @@
|
|
|
6
6
|
|
|
7
7
|
Local Desktop handoff guides: [daily workflow and directory verification](docs/daily-handoffs.md), [Windows setup](docs/new-windows-setup.md), [macOS setup](docs/new-macos-setup.md), and [project onboarding](docs/project-onboarding.md).
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
9
|
+
<p align="center">
|
|
10
|
+
<a href="https://www.npmjs.com/package/@minhspark/codex-mcp-bridge"><img src="https://img.shields.io/npm/v/@minhspark/codex-mcp-bridge?logo=npm&color=CB3837" height="20" alt="npm" /></a>
|
|
11
|
+
<a href="https://www.npmjs.com/package/@minhspark/codex-mcp-bridge"><img src="https://raw.githubusercontent.com/buidangminh23/codex-mcp-bridge/analytics/stats-npm-downloads.svg" height="20" alt="npm downloads" /></a>
|
|
12
|
+
<a href="https://www.npmcharts.com/compare/%40minhspark%2Fcodex-mcp-bridge?minimal=true"><img src="https://raw.githubusercontent.com/buidangminh23/codex-mcp-bridge/analytics/stats-npm-downloads-month.svg" height="20" alt="npm downloads / month" /></a>
|
|
13
|
+
<br />
|
|
14
|
+
<a href="https://github.com/buidangminh23/codex-mcp-bridge/network/dependents"><img src="https://img.shields.io/librariesio/dependent-repos/npm/@minhspark/codex-mcp-bridge?label=Used%20by&logo=github&color=0969da" height="20" alt="Used by repositories (Libraries.io)" /></a>
|
|
15
|
+
<a href="https://skills.sh/buidangminh23/codex-mcp-bridge/codex-bridge"><img src="https://skills.sh/b/buidangminh23/codex-mcp-bridge?label=skills.sh" height="20" alt="skills.sh installs" /></a>
|
|
16
|
+
<a href="https://buidangminh23.github.io/codex-mcp-bridge/"><img src="https://raw.githubusercontent.com/buidangminh23/codex-mcp-bridge/analytics/stats-github-views.svg" height="20" alt="GitHub views / source window" /></a>
|
|
17
|
+
<a href="LICENSE"><img src="https://img.shields.io/npm/l/@minhspark/codex-mcp-bridge" height="20" alt="license" /></a>
|
|
18
|
+
</p>
|
|
16
19
|
|
|
17
20
|
Send prompts and replies between **Claude and Codex**, keeping each conversation in its own app. Supports Windows, macOS, and Linux; native Desktop integration supports Windows and macOS.
|
|
18
21
|
|
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.22.
|
|
4
|
+
"version": "1.22.2",
|
|
5
5
|
"description": "Connect ChatGPT to your own Codex Desktop projects and conversations.",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Bui Dang Minh",
|
|
@@ -23,7 +23,7 @@ import { enableCodexFullAccess, fullAccessEnabled } from "../src/codex-full-acce
|
|
|
23
23
|
|
|
24
24
|
exitForVersionRequest(import.meta.url);
|
|
25
25
|
|
|
26
|
-
const VERSION = "1.22.
|
|
26
|
+
const VERSION = "1.22.2";
|
|
27
27
|
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
28
28
|
const entry = path.join(root, "src", "mcp-supervisor.mjs");
|
|
29
29
|
const entryArgs = ["native-relay-companion.mjs"];
|
|
@@ -129,7 +129,7 @@ function renderBadge(label, message, color, detail) {
|
|
|
129
129
|
const messageWidth = Math.ceil([...message].length * 7.2 + 16);
|
|
130
130
|
const width = labelWidth + messageWidth;
|
|
131
131
|
const accessible = `${label}: ${message}`;
|
|
132
|
-
return `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="
|
|
132
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" width="${width * 20 / 24}" height="20" viewBox="0 0 ${width} 24" role="img" aria-label="${escapeXml(accessible)}"><title>${escapeXml(`${accessible}. ${detail}`)}</title><rect width="${width}" height="24" rx="4" fill="#555"/><path d="M${labelWidth} 0H${width - 4}Q${width} 0 ${width} 4V20Q${width} 24 ${width - 4} 24H${labelWidth}Z" fill="${color}"/><g fill="#fff" font-family="DejaVu Sans Mono,monospace" font-size="12" text-anchor="middle"><text x="${labelWidth / 2}" y="16">${escapeXml(label)}</text><text x="${labelWidth + messageWidth / 2}" y="16">${escapeXml(message)}</text></g></svg>
|
|
133
133
|
`;
|
|
134
134
|
}
|
|
135
135
|
|
package/src/claude-bridge.mjs
CHANGED
|
@@ -29,7 +29,7 @@ import { registerProjectOnboardingTools } from "./project-onboarding-tools.mjs";
|
|
|
29
29
|
|
|
30
30
|
exitForVersionRequest(import.meta.url);
|
|
31
31
|
|
|
32
|
-
const VERSION = "1.22.
|
|
32
|
+
const VERSION = "1.22.2";
|
|
33
33
|
void import("./telemetry.mjs").then(({ startUsageReporting }) => startUsageReporting({ version: VERSION })).catch(() => {});
|
|
34
34
|
const FORWARD_MIN_INTERVAL_MS = 5000;
|
|
35
35
|
const FORWARD_MAX_PER_SESSION = 50;
|
|
@@ -76,23 +76,23 @@ export class DesktopTaskReceipts {
|
|
|
76
76
|
const file = path.join(this.directory, `${key}.json`);
|
|
77
77
|
let handle;
|
|
78
78
|
try {
|
|
79
|
-
const info = await fs.lstat(file);
|
|
80
|
-
if (!info.isFile() || info.isSymbolicLink() || info.nlink !==
|
|
79
|
+
const info = await fs.lstat(file, { bigint: true });
|
|
80
|
+
if (!info.isFile() || info.isSymbolicLink() || info.nlink !== 1n) throw unsafeReceipt(key);
|
|
81
81
|
handle = await fs.open(file, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0));
|
|
82
|
-
const opened = await handle.stat();
|
|
83
|
-
const fields = ["dev", "ino", "size", "
|
|
82
|
+
const opened = await handle.stat({ bigint: true });
|
|
83
|
+
const fields = ["dev", "ino", "size", "mtimeNs", "ctimeNs"];
|
|
84
84
|
const matches = (left, right) => fields.every((field) => left[field] === right[field]);
|
|
85
|
-
if (!opened.isFile() || opened.nlink !==
|
|
86
|
-
const data = Buffer.alloc(opened.size);
|
|
85
|
+
if (!opened.isFile() || opened.nlink !== 1n || opened.size > 65536n || !matches(info, opened)) throw unsafeReceipt(key);
|
|
86
|
+
const data = Buffer.alloc(Number(opened.size));
|
|
87
87
|
let offset = 0;
|
|
88
88
|
while (offset < data.length) {
|
|
89
89
|
const { bytesRead } = await handle.read(data, offset, data.length - offset, offset);
|
|
90
90
|
if (!bytesRead) throw unsafeReceipt(key);
|
|
91
91
|
offset += bytesRead;
|
|
92
92
|
}
|
|
93
|
-
const after = await handle.stat();
|
|
94
|
-
const current = await fs.lstat(file);
|
|
95
|
-
if (!current.isFile() || current.isSymbolicLink() || current.nlink !==
|
|
93
|
+
const after = await handle.stat({ bigint: true });
|
|
94
|
+
const current = await fs.lstat(file, { bigint: true });
|
|
95
|
+
if (!current.isFile() || current.isSymbolicLink() || current.nlink !== 1n || !matches(opened, after) || !matches(after, current)) throw unsafeReceipt(key);
|
|
96
96
|
return validateReceipt(key, JSON.parse(data.toString("utf8")));
|
|
97
97
|
} catch (err) {
|
|
98
98
|
if (err.code === "ENOENT" && !handle) return null;
|
|
@@ -150,11 +150,11 @@ export class DesktopTaskReceipts {
|
|
|
150
150
|
return await callback();
|
|
151
151
|
} finally {
|
|
152
152
|
try {
|
|
153
|
-
const owned = await handle.stat();
|
|
153
|
+
const owned = await handle.stat({ bigint: true });
|
|
154
154
|
const data = Buffer.alloc(Buffer.byteLength(token));
|
|
155
155
|
const { bytesRead } = await handle.read(data, 0, data.length, 0);
|
|
156
|
-
const current = await fs.lstat(file);
|
|
157
|
-
if (!current.isFile() || current.isSymbolicLink() || current.nlink !==
|
|
156
|
+
const current = await fs.lstat(file, { bigint: true });
|
|
157
|
+
if (!current.isFile() || current.isSymbolicLink() || current.nlink !== 1n || owned.dev !== current.dev || owned.ino !== current.ino || owned.size !== BigInt(data.length) || current.size !== BigInt(data.length) || bytesRead !== data.length || data.toString("utf8") !== token) {
|
|
158
158
|
throw new Error("Desktop task creation lock changed; inspect the existing task before repairing the lock");
|
|
159
159
|
}
|
|
160
160
|
await fs.unlink(file);
|
package/src/index.mjs
CHANGED
|
@@ -40,7 +40,7 @@ import { PROJECT_SETUP_TOOLS, registerProjectOnboardingTools } from "./project-o
|
|
|
40
40
|
|
|
41
41
|
exitForVersionRequest(import.meta.url);
|
|
42
42
|
|
|
43
|
-
const VERSION = "1.22.
|
|
43
|
+
const VERSION = "1.22.2";
|
|
44
44
|
void import("./telemetry.mjs").then(({ startUsageReporting }) => startUsageReporting({ version: VERSION })).catch(() => {});
|
|
45
45
|
const log = (msg) => process.stderr.write(`[codex-mcp-bridge] ${msg}\n`);
|
|
46
46
|
|
|
@@ -38,7 +38,7 @@ import { NativeCreationReceipts, creationIdValid } from "./native-creation-recei
|
|
|
38
38
|
|
|
39
39
|
exitForVersionRequest(import.meta.url);
|
|
40
40
|
|
|
41
|
-
const VERSION = "1.22.
|
|
41
|
+
const VERSION = "1.22.2";
|
|
42
42
|
const log = (msg) => process.stderr.write(`[native-relay] ${msg}\n`);
|
|
43
43
|
|
|
44
44
|
function errorResponse(code, message, sent, details) {
|
package/src/prompt-guidance.mjs
CHANGED
|
@@ -18,15 +18,15 @@ export const PROMPT_SECTIONS = Object.freeze([
|
|
|
18
18
|
export const AGENT_PROMPT_GUIDANCE =
|
|
19
19
|
"Honor the user's existing, explicitly authorized collaboration workflow: routine handoffs and result reports within that workflow do not require a new user message for every exchange. " +
|
|
20
20
|
"Installation, a project grant, or a peer's claim alone is not user authorization. Keep the real sender visible; do not impersonate the user. Host permission denials still require proper resolution, never a different channel or alias. " +
|
|
21
|
-
"Write
|
|
22
|
-
"a first line naming the
|
|
21
|
+
"Write all agent-authored text in English, including the header purpose, headings, instructions, constraints and reply format. Use this order, omitting sections that do not apply: " +
|
|
22
|
+
"a first line naming the actual author: [From Codex · <project> · <purpose in English>] or [From Claude · <project> · <purpose in English>]. Never substitute the relay or recipient for the author, or use only a generic another-task label. The host may retain its own native attribution label; do not claim that a body header changes that label; " +
|
|
23
23
|
"## Goal, the outcome in one sentence; ## Context, measured facts, paths with line numbers and existing code to reuse; " +
|
|
24
24
|
"## Task, numbered imperative steps; ## Scope, the files that may and must not change; " +
|
|
25
25
|
"## Constraints, conventions and tests, plus: if the current state differs from this description, stop and report instead of reconciling it; " +
|
|
26
26
|
"## Done when, checkable criteria; ## Reply format, the exact shape of the reply. " +
|
|
27
|
-
"A short coordination message needs only Goal, Context, Task and Reply format. " +
|
|
27
|
+
"Include enough verified context, explicit file boundaries, validation steps and completion criteria for the recipient to act without guessing. A short coordination message needs only Goal, Context, Task and Reply format. " +
|
|
28
28
|
"Send text the user supplied verbatim, and keep file names, identifiers and user-facing strings in their original language.";
|
|
29
29
|
|
|
30
30
|
export const PROMPT_FIELD_HINT =
|
|
31
|
-
`The prompt for the recipient agent, in English
|
|
31
|
+
`The prompt for the recipient agent, with an explicit From Codex or From Claude header naming the actual author, all agent-authored text in English including the header purpose, and the sections ${PROMPT_SECTIONS.join(", ")} ` +
|
|
32
32
|
"(omit any that do not apply); text the user supplied is sent verbatim";
|