





















@@ -15,6 +15,26 @@ async function makeLauncherFixture(fixtureRoots: string[]): Promise<string> {
1515return fixtureRoot;
1616}
171718+async function makeLauncherProbeFixture(
19+fixtureRoots: string[],
20+probeSource: string,
21+): Promise<string> {
22+const fixtureRoot = await makeLauncherFixture(fixtureRoots);
23+const launcherPath = path.join(fixtureRoot, "openclaw.mjs");
24+const launcher = await fs.readFile(launcherPath, "utf8");
25+const bootstrapStart = "\nif (!waitingForCompileCacheRespawn) {";
26+const bootstrapIndex = launcher.indexOf(bootstrapStart);
27+if (bootstrapIndex < 0) {
28+throw new Error("openclaw launcher bootstrap block was not found");
29+}
30+await fs.writeFile(
31+launcherPath,
32+`${launcher.slice(0, bootstrapIndex)}\n${probeSource}\n`,
33+"utf8",
34+);
35+return fixtureRoot;
36+}
37+1838async function addSourceTreeMarker(fixtureRoot: string): Promise<void> {
1939await fs.mkdir(path.join(fixtureRoot, "src"), { recursive: true });
2040await fs.writeFile(path.join(fixtureRoot, "src", "entry.ts"), "export {};\n", "utf8");
@@ -98,6 +118,14 @@ function launcherEnv(extra: NodeJS.ProcessEnv = {}): NodeJS.ProcessEnv {
98118return env;
99119}
100120121+function hasBunRuntime(): boolean {
122+return (
123+spawnSync(process.env.BUN_BIN ?? "bun", ["--version"], {
124+encoding: "utf8",
125+}).status === 0
126+);
127+}
128+101129describe("openclaw launcher", () => {
102130const fixtureRoots: string[] = [];
103131@@ -203,6 +231,113 @@ describe("openclaw launcher", () => {
203231expect(result.stderr).toContain("missing dist/entry.(m)js");
204232});
205233234+it("treats Bun direct optional import misses as direct launcher misses", async () => {
235+const fixtureRoot = await makeLauncherProbeFixture(
236+fixtureRoots,
237+[
238+"const result = {",
239+" direct: isDirectModuleNotFoundError(",
240+" { message: `Cannot find module './dist/warning-filter.js' from '${fileURLToPath(import.meta.url)}'` },",
241+" './dist/warning-filter.js',",
242+" ),",
243+" directWithCode: isDirectModuleNotFoundError(",
244+" { code: 'ERR_MODULE_NOT_FOUND', message: `Cannot find module './dist/warning-filter.js' from '${fileURLToPath(import.meta.url)}'` },",
245+" './dist/warning-filter.js',",
246+" ),",
247+" transitive: isDirectModuleNotFoundError(",
248+" { message: \"Cannot find module './nested.js' from '/pkg/openclaw/dist/entry.js'\" },",
249+" './dist/entry.js',",
250+" ),",
251+" sameSpecifierTransitive: isDirectModuleNotFoundError(",
252+" { message: \"Cannot find module './dist/entry.js' from '/pkg/openclaw/dist/entry.js'\" },",
253+" './dist/entry.js',",
254+" ),",
255+" nonModuleUrl: isDirectModuleNotFoundError(",
256+" { message: 'boom', url: new URL('./dist/warning-filter.js', import.meta.url).href },",
257+" './dist/warning-filter.js',",
258+" ),",
259+" nonModulePath: isDirectModuleNotFoundError(",
260+" { message: `Cannot find module '${fileURLToPath(new URL('./dist/warning-filter.js', import.meta.url))}'` },",
261+" './dist/warning-filter.js',",
262+" ),",
263+"};",
264+"process.stdout.write(`${JSON.stringify(result)}\\n`);",
265+].join("\n"),
266+);
267+268+const result = spawnSync(process.execPath, [path.join(fixtureRoot, "openclaw.mjs")], {
269+cwd: fixtureRoot,
270+env: launcherEnv(),
271+encoding: "utf8",
272+});
273+274+expect(result.status).toBe(0);
275+expect(JSON.parse(result.stdout)).toEqual({
276+direct: true,
277+directWithCode: true,
278+nonModulePath: false,
279+nonModuleUrl: false,
280+sameSpecifierTransitive: false,
281+transitive: false,
282+});
283+});
284+285+it.runIf(process.env.OPENCLAW_TEST_BUN_LAUNCHER === "1" && hasBunRuntime())(
286+"falls through Bun optional warning filter misses",
287+async () => {
288+const fixtureRoot = await makeLauncherFixture(fixtureRoots);
289+await fs.writeFile(
290+path.join(fixtureRoot, "dist", "entry.js"),
291+"process.stdout.write('bun entry ok\\n');\n",
292+"utf8",
293+);
294+295+const result = spawnSync(
296+process.env.BUN_BIN ?? "bun",
297+[path.join(fixtureRoot, "openclaw.mjs")],
298+{
299+cwd: fixtureRoot,
300+env: launcherEnv(),
301+encoding: "utf8",
302+},
303+);
304+305+expect(result.status).toBe(0);
306+expect(result.stdout).toBe("bun entry ok\n");
307+},
308+);
309+310+it.runIf(process.env.OPENCLAW_TEST_BUN_LAUNCHER === "1" && hasBunRuntime())(
311+"surfaces Bun transitive entry misses with the same raw specifier",
312+async () => {
313+const fixtureRoot = await makeLauncherFixture(fixtureRoots);
314+await fs.writeFile(
315+path.join(fixtureRoot, "dist", "warning-filter.js"),
316+"export function installProcessWarningFilter() {}\n",
317+"utf8",
318+);
319+await fs.writeFile(
320+path.join(fixtureRoot, "dist", "entry.js"),
321+'import "./dist/entry.js";\n',
322+"utf8",
323+);
324+325+const result = spawnSync(
326+process.env.BUN_BIN ?? "bun",
327+[path.join(fixtureRoot, "openclaw.mjs"), "--help"],
328+{
329+cwd: fixtureRoot,
330+env: launcherEnv(),
331+encoding: "utf8",
332+},
333+);
334+335+expect(result.status).not.toBe(0);
336+expect(result.stderr).toContain("Cannot find module './dist/entry.js'");
337+expect(result.stderr).not.toContain("missing dist/entry.(m)js");
338+},
339+);
340+206341it("uses precomputed root help when plugin config does not invalidate it", async () => {
207342const fixtureRoot = await makeLauncherFixture(fixtureRoots);
208343await fs.writeFile(
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。