mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
ee191dbe81
When running `npx @openai/codex-shell-tool-mcp`, the old code derived `__dirname` from `process.argv[1]`, which points to npx’s transient wrapper script in `~/.npm/_npx/134d0fb7e1a27652/node_modules/.bin/codex-shell-tool-mcp`. That made `vendorRoot` resolve to `<npx cache>/vendor`, so the startup checks failed with "Required binary missing" because it looked for `codex-execve-wrapper` in the wrong place. By relying on the real module `__dirname` and `path.resolve(__dirname, "..", "vendor")`, the package now anchors to its installed location under `node_modules/@openai/codex-shell-tool-mcp/`, so the bundled binaries are found and npx launches correctly.
97 lines
2.5 KiB
TypeScript
97 lines
2.5 KiB
TypeScript
// Launches the codex-exec-mcp-server binary bundled in this package.
|
|
|
|
import { spawn } from "node:child_process";
|
|
import { accessSync, constants } from "node:fs";
|
|
import os from "node:os";
|
|
import path from "node:path";
|
|
import { resolveBashPath } from "./bashSelection";
|
|
import { readOsRelease } from "./osRelease";
|
|
import { resolveTargetTriple } from "./platform";
|
|
|
|
async function main(): Promise<void> {
|
|
const targetTriple = resolveTargetTriple(process.platform, process.arch);
|
|
const vendorRoot = path.resolve(__dirname, "..", "vendor");
|
|
const targetRoot = path.join(vendorRoot, targetTriple);
|
|
const execveWrapperPath = path.join(targetRoot, "codex-execve-wrapper");
|
|
const serverPath = path.join(targetRoot, "codex-exec-mcp-server");
|
|
|
|
const osInfo = process.platform === "linux" ? readOsRelease() : null;
|
|
const { path: bashPath } = resolveBashPath(
|
|
targetRoot,
|
|
process.platform,
|
|
os.release(),
|
|
osInfo,
|
|
);
|
|
|
|
[execveWrapperPath, serverPath, bashPath].forEach((checkPath) => {
|
|
try {
|
|
accessSync(checkPath, constants.F_OK);
|
|
} catch {
|
|
throw new Error(`Required binary missing: ${checkPath}`);
|
|
}
|
|
});
|
|
|
|
const args = [
|
|
"--execve",
|
|
execveWrapperPath,
|
|
"--bash",
|
|
bashPath,
|
|
...process.argv.slice(2),
|
|
];
|
|
const child = spawn(serverPath, args, {
|
|
stdio: "inherit",
|
|
});
|
|
|
|
const forwardSignal = (signal: NodeJS.Signals) => {
|
|
if (child.killed) {
|
|
return;
|
|
}
|
|
try {
|
|
child.kill(signal);
|
|
} catch {
|
|
/* ignore */
|
|
}
|
|
};
|
|
|
|
(["SIGINT", "SIGTERM", "SIGHUP"] as const).forEach((sig) => {
|
|
process.on(sig, () => forwardSignal(sig));
|
|
});
|
|
|
|
child.on("error", (err) => {
|
|
// eslint-disable-next-line no-console
|
|
console.error(err);
|
|
process.exit(1);
|
|
});
|
|
|
|
const childResult = await new Promise<
|
|
| { type: "signal"; signal: NodeJS.Signals }
|
|
| { type: "code"; exitCode: number }
|
|
>((resolve) => {
|
|
child.on("exit", (code, signal) => {
|
|
if (signal) {
|
|
resolve({ type: "signal", signal });
|
|
} else {
|
|
resolve({ type: "code", exitCode: code ?? 1 });
|
|
}
|
|
});
|
|
});
|
|
|
|
if (childResult.type === "signal") {
|
|
// This environment running under `node --test` may not allow rethrowing a signal.
|
|
// Wrap in a try to avoid masking the original termination reason.
|
|
try {
|
|
process.kill(process.pid, childResult.signal);
|
|
} catch {
|
|
process.exit(1);
|
|
}
|
|
} else {
|
|
process.exit(childResult.exitCode);
|
|
}
|
|
}
|
|
|
|
void main().catch((err) => {
|
|
// eslint-disable-next-line no-console
|
|
console.error(err);
|
|
process.exit(1);
|
|
});
|