fix(coding-agent): respect package.json pi.extensions manifest in settings extensions paths

collectAutoExtensionEntries now checks if the directory itself has a
package.json with pi.extensions (or index.ts) before scanning children.
This fixes duplicate extension loading when a manifest-aware directory
is specified directly in settings.json extensions array.

Fixes #1274
This commit is contained in:
Mario Zechner 2026-02-05 22:32:12 +01:00
parent d27df1afa4
commit 5f5cd080b9
3 changed files with 45 additions and 0 deletions

View file

@ -2,6 +2,10 @@
## [Unreleased]
### Fixed
- Fixed extensions setting not respecting `package.json` `pi.extensions` manifest when directory is specified directly ([#1302](https://github.com/badlogic/pi-mono/pull/1302) by [@hjanuschka](https://github.com/hjanuschka))
## [0.52.3] - 2026-02-05
### Fixed

View file

@ -402,6 +402,13 @@ function collectAutoExtensionEntries(dir: string): string[] {
const entries: string[] = [];
if (!existsSync(dir)) return entries;
// First check if this directory itself has explicit extension entries (package.json or index)
const rootEntries = resolveExtensionEntries(dir);
if (rootEntries) {
return rootEntries;
}
// Otherwise, discover extensions from directory contents
const ig = ignore();
addIgnoreRules(ig, dir, dir);

View file

@ -111,6 +111,40 @@ Content`,
const result = await packageManager.resolve();
expect(result.prompts.some((r) => r.path === promptPath && !r.enabled)).toBe(true);
});
it("should resolve directory with package.json pi.extensions in extensions setting", async () => {
// Create a package with pi.extensions in package.json
const pkgDir = join(tempDir, "my-extensions-pkg");
mkdirSync(join(pkgDir, "extensions"), { recursive: true });
writeFileSync(
join(pkgDir, "package.json"),
JSON.stringify({
name: "my-extensions-pkg",
pi: {
extensions: ["./extensions/clip.ts", "./extensions/cost.ts"],
},
}),
);
writeFileSync(join(pkgDir, "extensions", "clip.ts"), "export default function() {}");
writeFileSync(join(pkgDir, "extensions", "cost.ts"), "export default function() {}");
writeFileSync(join(pkgDir, "extensions", "helper.ts"), "export const x = 1;"); // Not in manifest, shouldn't be loaded
// Add the directory to extensions setting (not packages setting)
settingsManager.setExtensionPaths([pkgDir]);
const result = await packageManager.resolve();
// Should find the extensions declared in package.json pi.extensions
expect(result.extensions.some((r) => r.path === join(pkgDir, "extensions", "clip.ts") && r.enabled)).toBe(
true,
);
expect(result.extensions.some((r) => r.path === join(pkgDir, "extensions", "cost.ts") && r.enabled)).toBe(
true,
);
// Should NOT find helper.ts (not declared in manifest)
expect(result.extensions.some((r) => r.path.endsWith("helper.ts"))).toBe(false);
});
});
describe("ignore files", () => {