fix: preserve bundle format in plugin index

This commit is contained in:
Shakker
2026-04-26 02:23:57 +01:00
parent 4e3b860e60
commit 25ecb2895a
5 changed files with 98 additions and 1 deletions

View File

@@ -55,6 +55,8 @@ const InstalledPluginIndexRecordSchema = z
packageInstall: z.unknown().optional(),
manifestPath: z.string(),
manifestHash: z.string(),
format: z.string().optional(),
bundleFormat: z.string().optional(),
source: z.string().optional(),
setupSource: z.string().optional(),
packageJson: z

View File

@@ -66,12 +66,16 @@ function createPluginCandidate(params: {
packageVersion?: string;
packageDir?: string;
packageManifest?: OpenClawPackageManifest;
format?: PluginCandidate["format"];
bundleFormat?: PluginCandidate["bundleFormat"];
}): PluginCandidate {
return {
idHint: params.idHint ?? "demo",
source: path.join(params.rootDir, "index.ts"),
source: params.format === "bundle" ? params.rootDir : path.join(params.rootDir, "index.ts"),
rootDir: params.rootDir,
origin: params.origin ?? "global",
format: params.format,
bundleFormat: params.bundleFormat,
packageName: params.packageName,
packageVersion: params.packageVersion,
packageDir: params.packageDir ?? params.rootDir,
@@ -198,6 +202,39 @@ describe("installed plugin index", () => {
expect(index.plugins[0]?.installRecordHash).toBeUndefined();
});
it("keeps bundle format metadata needed for manifest reconstruction", () => {
const rootDir = makeTempDir();
fs.mkdirSync(path.join(rootDir, ".claude-plugin"), { recursive: true });
fs.mkdirSync(path.join(rootDir, "commands"), { recursive: true });
fs.writeFileSync(
path.join(rootDir, ".claude-plugin", "plugin.json"),
JSON.stringify({
name: "Claude Bundle",
commands: "commands",
}),
"utf8",
);
const index = loadInstalledPluginIndex({
candidates: [
createPluginCandidate({
rootDir,
idHint: "claude-bundle",
format: "bundle",
bundleFormat: "claude",
}),
],
env: hermeticEnv(),
});
expect(index.plugins[0]).toMatchObject({
pluginId: "claude-bundle",
format: "bundle",
bundleFormat: "claude",
source: rootDir,
});
});
it("keeps packageJson paths root-relative when packageDir is reached through a symlink", () => {
const fixture = createRichPluginFixture();
const linkParent = makeTempDir();

View File

@@ -84,6 +84,8 @@ export type InstalledPluginIndexRecord = {
packageInstall?: PluginInstallSourceInfo;
manifestPath: string;
manifestHash: string;
format?: PluginManifestRecord["format"];
bundleFormat?: PluginManifestRecord["bundleFormat"];
source?: string;
setupSource?: string;
packageJson?: {
@@ -516,6 +518,12 @@ function buildInstalledPluginIndex(
startup: buildStartupInfo(record),
compat: collectCompatCodes(record),
};
if (record.format && record.format !== "openclaw") {
indexRecord.format = record.format;
}
if (record.bundleFormat) {
indexRecord.bundleFormat = record.bundleFormat;
}
if (record.enabledByDefault === true) {
indexRecord.enabledByDefault = true;
}

View File

@@ -89,4 +89,52 @@ describe("loadPluginManifestRegistryForInstalledIndex", () => {
modelPrefixes: ["installed-"],
});
});
it("reconstructs bundle candidates with their bundle manifest format", () => {
const rootDir = makeTempDir();
fs.mkdirSync(path.join(rootDir, ".claude-plugin"), { recursive: true });
fs.mkdirSync(path.join(rootDir, "commands"), { recursive: true });
fs.writeFileSync(
path.join(rootDir, ".claude-plugin", "plugin.json"),
JSON.stringify({
name: "Claude Bundle",
commands: "commands",
}),
"utf8",
);
const index = createIndex(rootDir);
const registry = loadPluginManifestRegistryForInstalledIndex({
index: {
...index,
plugins: [
{
...index.plugins[0],
pluginId: "claude-bundle",
manifestPath: path.join(rootDir, ".claude-plugin", "plugin.json"),
source: rootDir,
format: "bundle",
bundleFormat: "claude",
},
],
},
env: {
OPENCLAW_DISABLE_PLUGIN_DISCOVERY_CACHE: "1",
OPENCLAW_DISABLE_PLUGIN_MANIFEST_CACHE: "1",
OPENCLAW_VERSION: "2026.4.25",
VITEST: "true",
},
includeDisabled: true,
});
expect(registry.diagnostics).toEqual([]);
expect(registry.plugins).toEqual([
expect.objectContaining({
id: "claude-bundle",
format: "bundle",
bundleFormat: "claude",
skills: ["commands"],
}),
]);
});
});

View File

@@ -24,6 +24,8 @@ function toPluginCandidate(record: InstalledPluginIndexRecord): PluginCandidate
...(record.setupSource ? { setupSource: record.setupSource } : {}),
rootDir: record.rootDir,
origin: record.origin,
...(record.format ? { format: record.format } : {}),
...(record.bundleFormat ? { bundleFormat: record.bundleFormat } : {}),
...(record.packageName ? { packageName: record.packageName } : {}),
...(record.packageVersion ? { packageVersion: record.packageVersion } : {}),
packageDir: record.rootDir,