From c812d76b6f3ff92aafcec2ea213ea2fe1e1bb061 Mon Sep 17 00:00:00 2001 From: Vinaywho Date: Tue, 28 Apr 2026 16:00:30 +0530 Subject: [PATCH] feat: wire qoder into the download API allowlist Add qoder to FILE_DOWNLOAD_PROVIDER_CONFIG_DIRS so the download endpoint accepts /api/download/skill/qoder/* and resolves to dist/qoder/.qoder/. Without this, the website install surface returned 400 Invalid provider even though qoder was a first-class harness everywhere else. Cover the new provider with two assertions in download-validation.test.js (allowlist + path resolution). Co-Authored-By: Claude Opus 4.7 (1M context) --- lib/download-providers.js | 1 + tests/server/download-validation.test.js | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/lib/download-providers.js b/lib/download-providers.js index 07d26990b..d1c5cfd5b 100644 --- a/lib/download-providers.js +++ b/lib/download-providers.js @@ -8,6 +8,7 @@ export const FILE_DOWNLOAD_PROVIDER_CONFIG_DIRS = Object.freeze({ kiro: '.kiro', opencode: '.opencode', pi: '.pi', + qoder: '.qoder', }); export const FILE_DOWNLOAD_PROVIDERS = Object.freeze( diff --git a/tests/server/download-validation.test.js b/tests/server/download-validation.test.js index 5b7cf8343..d3c86a43c 100644 --- a/tests/server/download-validation.test.js +++ b/tests/server/download-validation.test.js @@ -19,6 +19,11 @@ describe('download provider validation', () => { expect(isAllowedFileProvider('github')).toBe(true); }); + test('allows qoder as an individual download provider', () => { + expect(ALLOWED_FILE_PROVIDERS).toContain('qoder'); + expect(isAllowedFileProvider('qoder')).toBe(true); + }); + test('separates file downloads from bundle downloads', () => { expect(ALLOWED_BUNDLE_PROVIDERS).toContain('universal'); expect(isAllowedBundleProvider('universal')).toBe(true); @@ -46,6 +51,12 @@ describe('download file paths', () => { ); }); + test('maps qoder skills into the .qoder config directory', () => { + expect(getFilePath('skill', 'qoder', 'impeccable')).toBe( + path.join(process.cwd(), 'dist', 'qoder', '.qoder', 'skills', 'impeccable', 'SKILL.md') + ); + }); + test('rejects bundle-only providers on the individual download route', async () => { const response = await handleFileDownload('skill', 'universal', 'impeccable'); expect(response.status).toBe(400);