From 04d454b5b3c82289783375bcbeb64ed37583c09d Mon Sep 17 00:00:00 2001 From: markijbema <624143+markijbema@users.noreply.github.com> Date: Wed, 24 Jun 2026 14:08:22 +0000 Subject: [PATCH] fix(vscode): ignore malformed relevance metadata Co-authored-by: kiloconnect[bot] <240665456+kiloconnect[bot]@users.noreply.github.com> --- .../src/services/marketplace/relevance.ts | 11 ++++++++--- .../tests/unit/marketplace-relevance.test.ts | 16 ++++++++++++++++ 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/packages/kilo-vscode/src/services/marketplace/relevance.ts b/packages/kilo-vscode/src/services/marketplace/relevance.ts index 9586ebfea5..62644149f3 100644 --- a/packages/kilo-vscode/src/services/marketplace/relevance.ts +++ b/packages/kilo-vscode/src/services/marketplace/relevance.ts @@ -3,6 +3,11 @@ import type { MarketplaceItem, MarketplaceRelevanceMetadata } from "./types" const EXCLUDE = "**/{node_modules,.git,dist,build,out,.kilo,.opencode,.kilocode}/**" +function strings(value: unknown): string[] { + if (!Array.isArray(value)) return [] + return value.filter((item): item is string => typeof item === "string") +} + interface RelevanceHost { extensions: readonly string[] find: (root: vscode.Uri, pattern: string) => Promise @@ -23,7 +28,7 @@ export async function detectMarketplaceRelevance( roots: readonly vscode.Uri[], source: RelevanceHost = context(), ): Promise { - const patterns = Array.from(new Set(items.flatMap((item) => item.suggest_for?.filename ?? []))) + const patterns = Array.from(new Set(items.flatMap((item) => strings(item.suggest_for?.filename)))) const files = new Map() const batches = Array.from({ length: Math.ceil(patterns.length / 4) }, (_, index) => @@ -48,8 +53,8 @@ export async function detectMarketplaceRelevance( const extensions = new Set(source.extensions.map((id) => id.toLowerCase())) return Object.fromEntries( items.flatMap((item) => { - const filename = item.suggest_for?.filename?.filter((pattern) => files.get(pattern)) - const vscodeExtension = item.suggest_for?.vscode_extension?.filter((id) => extensions.has(id.toLowerCase())) + const filename = strings(item.suggest_for?.filename).filter((pattern) => files.get(pattern)) + const vscodeExtension = strings(item.suggest_for?.vscode_extension).filter((id) => extensions.has(id.toLowerCase())) if (!filename?.length && !vscodeExtension?.length) return [] return [ [ diff --git a/packages/kilo-vscode/tests/unit/marketplace-relevance.test.ts b/packages/kilo-vscode/tests/unit/marketplace-relevance.test.ts index 79a1246242..c0ef116868 100644 --- a/packages/kilo-vscode/tests/unit/marketplace-relevance.test.ts +++ b/packages/kilo-vscode/tests/unit/marketplace-relevance.test.ts @@ -74,6 +74,22 @@ describe("Marketplace relevance", () => { expect(find.mock.calls).toContainEqual([remote, "*.ipynb"]) }) + it("ignores malformed suggestion metadata", async () => { + const malformed = { + ...items[0], + suggest_for: { filename: "*.component.ts", vscode_extension: [42] }, + } as unknown as MarketplaceItem + const find = mock(async () => true) + + const relevance = await detectMarketplaceRelevance([malformed], [vscode.Uri.file("/repo")], { + extensions: ["test.extension"], + find, + }) + + expect(relevance).toEqual({}) + expect(find).not.toHaveBeenCalled() + }) + it("still matches installed extensions without a workspace", async () => { const find = mock(async () => true)