diff --git a/src/bundle/manifest.ts b/src/bundle/manifest.ts index 58627b8..e831127 100644 --- a/src/bundle/manifest.ts +++ b/src/bundle/manifest.ts @@ -84,12 +84,25 @@ export function loadManifest(path: string): ManifestResult { manifest.description = data.description as string; } if (data.extends !== undefined) { + if (!Array.isArray(data.extends) || !data.extends.every((e) => typeof e === "string")) { + throw new UsageError(`bundle ${path}: 'extends' must be a list of names`); + } manifest.extends = data.extends as string[]; } if (data.skills !== undefined) { + if (!Array.isArray(data.skills) || !data.skills.every((s) => typeof s === "string")) { + throw new UsageError( + `bundle ${path}: 'skills' must be a list of qualified / refs`, + ); + } manifest.skills = data.skills as string[]; } if (data.agents !== undefined) { + if (!Array.isArray(data.agents) || !data.agents.every((a) => typeof a === "string")) { + throw new UsageError( + `bundle ${path}: 'agents' must be a list of qualified / refs`, + ); + } manifest.agents = data.agents as string[]; } if (data.hooks !== undefined) { diff --git a/test/unit/bundle/manifest.test.ts b/test/unit/bundle/manifest.test.ts index cd7e74e..617d403 100644 --- a/test/unit/bundle/manifest.test.ts +++ b/test/unit/bundle/manifest.test.ts @@ -171,6 +171,29 @@ mcps: expect(() => loadManifest(path)).toThrow(/mcps.*list.*qualified/i); }); + it.each([ + ["extends", "good"], + ["skills", "local/demo"], + ["agents", "data-scientist"], + ])("rejects scalar %s where a list is required", (field, value) => { + const path = writeBundle( + `scalar-${field}`, + `---\nname: scalar-${field}\n${field}: ${value}\n---\n`, + ); + expect(() => loadManifest(path)).toThrow(new RegExp(`${field}.*list`, "i")); + }); + + it.each(["extends", "skills", "agents"])( + "rejects %s list containing a non-string element", + (field) => { + const path = writeBundle( + `nonstring-${field}`, + `---\nname: nonstring-${field}\n${field}: [123]\n---\n`, + ); + expect(() => loadManifest(path)).toThrow(new RegExp(`${field}.*list`, "i")); + }, + ); + it("warns on unknown frontmatter field but does not error", () => { const path = writeBundle( "with-unknown",