58 lines
2.5 KiB
JavaScript
58 lines
2.5 KiB
JavaScript
import { chmod, mkdir } from "node:fs/promises";
|
||
import { dirname, resolve } from "node:path";
|
||
import { pathToFileURL } from "node:url";
|
||
import { build } from "esbuild";
|
||
|
||
const defaultPackageRoot = resolve(import.meta.dirname, "..");
|
||
const executableFileMode = 0o755;
|
||
|
||
// esbuild 以 format: "esm" 打包时,会把 CJS 依赖里的 require() 替换成一个 __require shim:
|
||
// typeof require !== "undefined" ? require : (name) => { throw Error('Dynamic require of "' + name + '" is not supported') }
|
||
// ESM 模块作用域里没有 require,于是这个 shim 永远走抛错分支。
|
||
// @zcode/core 从 tool/handlers/write.js -> memory/origin-session.js eager import 了 CJS 的
|
||
// yaml,yaml 内部 require("process") 正好命中 shim,导致 dist/mcp/server.js 在**模块求值阶段**
|
||
// 就抛 `Dynamic require of "process" is not supported`;plugin host 的 await import() 直接失败,
|
||
// 表现为 mcp.server.closed / mcp.server.failed、注册 0 个工具,模型侧彻底看不到 mcp__node_repl__js。
|
||
// 这里注入真实的 createRequire,让 shim 落到可用的 require 上(产物仍是 ESM)。
|
||
// 两个 bundle 都加:browser-client 目前没有 CJS 依赖,但同样是 ESM 产物,后续被拖进一个
|
||
// CJS 依赖就会以同样的方式在加载期炸掉。
|
||
const nodeRequireBanner = `import { createRequire as __zcodeCreateRequire } from "node:module";
|
||
const require = __zcodeCreateRequire(import.meta.url);`;
|
||
|
||
const createBundleOptions = ({ entryPoint, outfile }) => ({
|
||
banner: {
|
||
js: nodeRequireBanner,
|
||
},
|
||
bundle: true,
|
||
entryPoints: [entryPoint],
|
||
format: "esm",
|
||
legalComments: "none",
|
||
outfile,
|
||
platform: "node",
|
||
target: "node24",
|
||
});
|
||
|
||
/**
|
||
* 供 scripts 直跑与 smoke test 复用的构建入口,保证测试校验的产物与发布产物同一套 esbuild 选项。
|
||
*/
|
||
export const buildBrowserUsePluginBundles = async ({
|
||
packageRoot = defaultPackageRoot,
|
||
browserClientOutfile = resolve(packageRoot, "scripts", "browser-client.mjs"),
|
||
} = {}) => {
|
||
// node_repl 宿主的产物由 @zcode/node-repl-host 自己构建与携带;这个包只出 browser-client。
|
||
await mkdir(dirname(browserClientOutfile), { recursive: true });
|
||
await build(
|
||
createBundleOptions({
|
||
entryPoint: resolve(packageRoot, "src", "browser-client.ts"),
|
||
outfile: browserClientOutfile,
|
||
}),
|
||
);
|
||
await chmod(browserClientOutfile, executableFileMode);
|
||
return { browserClientOutfile };
|
||
};
|
||
|
||
const entryPath = process.argv[1];
|
||
if (entryPath && import.meta.url === pathToFileURL(entryPath).href) {
|
||
await buildBrowserUsePluginBundles();
|
||
}
|