From 7f1beddccc061688fec6cd9ed5c83514bc31e1e2 Mon Sep 17 00:00:00 2001 From: LukeGus Date: Sun, 20 Sep 2026 21:06:16 -0500 Subject: [PATCH] feat: add category and icon fields to plugin manifest schema --- .../manifests/invalid-bad-id.json | 1 + .../manifests/invalid-missing-field.json | 1 + .../manifests/invalid-unknown-category.json | 23 +++++++++++++++++++ .../manifests/invalid-unknown-permission.json | 1 + scripts/__fixtures__/manifests/valid.json | 2 ++ scripts/plugin-manifest.schema.json | 19 +++++++++++++++ scripts/validate-plugin-manifest.cjs | 19 +++++++++++++++ scripts/validate-plugin-manifest.test.ts | 6 +++++ 8 files changed, 72 insertions(+) create mode 100644 scripts/__fixtures__/manifests/invalid-unknown-category.json diff --git a/scripts/__fixtures__/manifests/invalid-bad-id.json b/scripts/__fixtures__/manifests/invalid-bad-id.json index fa4c6fe67..f254857bb 100644 --- a/scripts/__fixtures__/manifests/invalid-bad-id.json +++ b/scripts/__fixtures__/manifests/invalid-bad-id.json @@ -7,6 +7,7 @@ "name": "Jane Doe" }, "license": "MIT", + "category": "Productivity", "engine": { "termix": ">=2.9.0", "api": "1" diff --git a/scripts/__fixtures__/manifests/invalid-missing-field.json b/scripts/__fixtures__/manifests/invalid-missing-field.json index 7688463c0..691c3cef6 100644 --- a/scripts/__fixtures__/manifests/invalid-missing-field.json +++ b/scripts/__fixtures__/manifests/invalid-missing-field.json @@ -6,6 +6,7 @@ "name": "Jane Doe" }, "license": "MIT", + "category": "Productivity", "engine": { "termix": ">=2.9.0", "api": "1" diff --git a/scripts/__fixtures__/manifests/invalid-unknown-category.json b/scripts/__fixtures__/manifests/invalid-unknown-category.json new file mode 100644 index 000000000..17e031af9 --- /dev/null +++ b/scripts/__fixtures__/manifests/invalid-unknown-category.json @@ -0,0 +1,23 @@ +{ + "id": "sample-plugin", + "name": "Sample Plugin", + "version": "1.0.0", + "description": "Has a category that is not in the known category list.", + "author": { + "name": "Jane Doe" + }, + "license": "MIT", + "category": "Miscellaneous", + "engine": { + "termix": ">=2.9.0", + "api": "1" + }, + "capabilities": { + "backend": true, + "frontend": true, + "electron": false, + "platforms": ["linux"] + }, + "permissions": [], + "sidecars": [] +} diff --git a/scripts/__fixtures__/manifests/invalid-unknown-permission.json b/scripts/__fixtures__/manifests/invalid-unknown-permission.json index f13bfead3..3fd89b1d8 100644 --- a/scripts/__fixtures__/manifests/invalid-unknown-permission.json +++ b/scripts/__fixtures__/manifests/invalid-unknown-permission.json @@ -7,6 +7,7 @@ "name": "Jane Doe" }, "license": "MIT", + "category": "Productivity", "engine": { "termix": ">=2.9.0", "api": "1" diff --git a/scripts/__fixtures__/manifests/valid.json b/scripts/__fixtures__/manifests/valid.json index 20b6f1530..b41fdec62 100644 --- a/scripts/__fixtures__/manifests/valid.json +++ b/scripts/__fixtures__/manifests/valid.json @@ -9,6 +9,8 @@ }, "license": "MIT", "repository": "https://github.com/example/sample-plugin", + "category": "Productivity", + "icon": "Box", "engine": { "termix": ">=2.9.0", "api": "1" diff --git a/scripts/plugin-manifest.schema.json b/scripts/plugin-manifest.schema.json index b79023cf1..b34c8c652 100644 --- a/scripts/plugin-manifest.schema.json +++ b/scripts/plugin-manifest.schema.json @@ -12,6 +12,7 @@ "author", "license", "engine", + "category", "capabilities", "permissions", "sidecars" @@ -52,6 +53,24 @@ "type": "string", "format": "uri" }, + "category": { + "type": "string", + "enum": [ + "Terminal", + "Files & Transfer", + "Infrastructure", + "Monitoring", + "Networking", + "Access & Security", + "Productivity" + ], + "description": "Store category used for browsing/filtering. Must match one of the categories the store UI filters by." + }, + "icon": { + "type": "string", + "minLength": 1, + "description": "Either a Lucide icon name (same convention as contributes.tabs[].icon) or a relative path to an icon.svg shipped in the plugin package root. If both a Lucide name and an icon.svg are present, the registry-index build should prefer icon.svg." + }, "engine": { "type": "object", "additionalProperties": false, diff --git a/scripts/validate-plugin-manifest.cjs b/scripts/validate-plugin-manifest.cjs index c86bb9948..2b7d16f99 100644 --- a/scripts/validate-plugin-manifest.cjs +++ b/scripts/validate-plugin-manifest.cjs @@ -27,6 +27,10 @@ function knownPermissions(schema) { return schema.properties.permissions.items.enum; } +function knownCategories(schema) { + return schema.properties.category.enum; +} + function validateManifest(manifest, schema) { const errors = []; @@ -56,6 +60,21 @@ function validateManifest(manifest, schema) { } } + if (typeof manifest.category === "string") { + const categories = knownCategories(schema); + if (!categories.includes(manifest.category)) { + errors.push( + `Field "category" must be one of: ${categories.join(", ")}, got: "${manifest.category}"`, + ); + } + } else if ("category" in manifest) { + errors.push('Field "category" must be a string'); + } + + if ("icon" in manifest && typeof manifest.icon !== "string") { + errors.push('Field "icon" must be a string'); + } + if (manifest.engine && typeof manifest.engine === "object") { if (!manifest.engine.termix) { errors.push('Field "engine.termix" is required'); diff --git a/scripts/validate-plugin-manifest.test.ts b/scripts/validate-plugin-manifest.test.ts index 7c8def76b..c24dcde85 100644 --- a/scripts/validate-plugin-manifest.test.ts +++ b/scripts/validate-plugin-manifest.test.ts @@ -43,4 +43,10 @@ describe("validate-plugin-manifest.cjs", () => { expect(status).not.toBe(0); expect(output).toContain('Unknown permission: "credentials.read"'); }); + + it("rejects a manifest with an unknown category", () => { + const { status, output } = runValidator("invalid-unknown-category.json"); + expect(status).not.toBe(0); + expect(output).toMatch(/Field "category" must be one of/); + }); });