From b2213f147e621ae2cebdcdd4efafdc48c48dbc50 Mon Sep 17 00:00:00 2001 From: Tak Hoffman <781889+Takhoffman@users.noreply.github.com> Date: Thu, 19 Mar 2026 01:06:05 -0500 Subject: [PATCH] Preserve lexical bundle plugin roots --- src/plugins/bundle-mcp.test.ts | 16 ++++++---------- src/plugins/discovery.test.ts | 4 +--- src/plugins/discovery.ts | 5 +++-- 3 files changed, 10 insertions(+), 15 deletions(-) diff --git a/src/plugins/bundle-mcp.test.ts b/src/plugins/bundle-mcp.test.ts index b9d5ca18cf3..dc1f98ab882 100644 --- a/src/plugins/bundle-mcp.test.ts +++ b/src/plugins/bundle-mcp.test.ts @@ -46,8 +46,6 @@ describe("loadEnabledBundleMcpConfig", () => { const loadedServer = loaded.config.mcpServers.bundleProbe; const loadedArgs = getServerArgs(loadedServer); const loadedServerPath = typeof loadedArgs?.[0] === "string" ? loadedArgs[0] : undefined; - const resolvedPluginRoot = await fs.realpath(pluginRoot); - expect(loaded.diagnostics).toEqual([]); expect(isRecord(loadedServer) ? loadedServer.command : undefined).toBe("node"); expect(loadedArgs).toHaveLength(1); @@ -56,7 +54,7 @@ describe("loadEnabledBundleMcpConfig", () => { throw new Error("expected bundled MCP args to include the server path"); } expect(await fs.realpath(loadedServerPath)).toBe(resolvedServerPath); - expect(loadedServer.cwd).toBe(resolvedPluginRoot); + expect(loadedServer.cwd).toBe(pluginRoot); } finally { env.restore(); } @@ -178,18 +176,16 @@ describe("loadEnabledBundleMcpConfig", () => { }, }, }); - const resolvedPluginRoot = await fs.realpath(pluginRoot); - expect(loaded.diagnostics).toEqual([]); expect(loaded.config.mcpServers.inlineProbe).toEqual({ - command: path.join(resolvedPluginRoot, "bin", "server.sh"), + command: path.join(pluginRoot, "bin", "server.sh"), args: [ - path.join(resolvedPluginRoot, "servers", "probe.mjs"), - path.join(resolvedPluginRoot, "local-probe.mjs"), + path.join(pluginRoot, "servers", "probe.mjs"), + path.join(pluginRoot, "local-probe.mjs"), ], - cwd: resolvedPluginRoot, + cwd: pluginRoot, env: { - PLUGIN_ROOT: resolvedPluginRoot, + PLUGIN_ROOT: pluginRoot, }, }); } finally { diff --git a/src/plugins/discovery.test.ts b/src/plugins/discovery.test.ts index 37d43a69e43..20c1fefc87d 100644 --- a/src/plugins/discovery.test.ts +++ b/src/plugins/discovery.test.ts @@ -299,9 +299,7 @@ describe("discoverOpenClawPlugins", () => { expect(bundle?.format).toBe("bundle"); expect(bundle?.bundleFormat).toBe("codex"); expect(bundle?.source).toBe(bundleDir); - expect(normalizePathForAssertion(bundle?.rootDir)).toBe( - normalizePathForAssertion(fs.realpathSync(bundleDir)), - ); + expect(normalizePathForAssertion(bundle?.rootDir)).toBe(normalizePathForAssertion(bundleDir)); }); it("auto-detects manifestless Claude bundles from the default layout", async () => { diff --git a/src/plugins/discovery.ts b/src/plugins/discovery.ts index 3efe1ccc565..2b1c19ad756 100644 --- a/src/plugins/discovery.ts +++ b/src/plugins/discovery.ts @@ -377,7 +377,8 @@ function addCandidate(params: { if (params.seen.has(resolved)) { return; } - const resolvedRoot = safeRealpathSync(params.rootDir) ?? path.resolve(params.rootDir); + const lexicalRoot = path.resolve(params.rootDir); + const resolvedRoot = safeRealpathSync(params.rootDir) ?? lexicalRoot; if ( isUnsafePluginCandidate({ source: resolved, @@ -395,7 +396,7 @@ function addCandidate(params: { idHint: params.idHint, source: resolved, setupSource: params.setupSource, - rootDir: resolvedRoot, + rootDir: lexicalRoot, origin: params.origin, format: params.format ?? "openclaw", bundleFormat: params.bundleFormat,