























@@ -64,6 +64,7 @@ function createPluginCandidate(params: {
6464origin?: PluginCandidate["origin"];
6565packageName?: string;
6666packageVersion?: string;
67+packageDir?: string;
6768packageManifest?: OpenClawPackageManifest;
6869}): PluginCandidate {
6970return {
@@ -73,7 +74,7 @@ function createPluginCandidate(params: {
7374origin: params.origin ?? "global",
7475packageName: params.packageName,
7576packageVersion: params.packageVersion,
76-packageDir: params.rootDir,
77+packageDir: params.packageDir ?? params.rootDir,
7778packageManifest: params.packageManifest,
7879};
7980}
@@ -211,6 +212,33 @@ describe("installed plugin index", () => {
211212expect(contributions.contracts.get("tools")).toEqual(["demo"]);
212213});
213214215+it("keeps packageJson paths root-relative when packageDir is reached through a symlink", () => {
216+const fixture = createRichPluginFixture();
217+const linkParent = makeTempDir();
218+const linkRoot = path.join(linkParent, "linked-demo");
219+try {
220+fs.symlinkSync(fixture.rootDir, linkRoot, "dir");
221+} catch {
222+return;
223+}
224+225+const index = loadInstalledPluginIndex({
226+candidates: [
227+createPluginCandidate({
228+rootDir: fs.realpathSync(fixture.rootDir),
229+packageDir: linkRoot,
230+packageName: "@vendor/demo-plugin",
231+packageVersion: "1.2.3",
232+}),
233+],
234+env: hermeticEnv(),
235+});
236+237+expect(index.plugins[0]?.packageJson).toMatchObject({
238+path: "package.json",
239+});
240+});
241+214242it("exposes cold registry records and owners for existing plugins without install ledgers", () => {
215243const fixture = createRichPluginFixture();
216244const index = loadInstalledPluginIndex({
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。