From af6ebf30588516fc96e3318f4d040052d025623b Mon Sep 17 00:00:00 2001 From: chenbaowang <49091147+Rsweater@users.noreply.github.com> Date: Thu, 16 Apr 2026 10:16:33 +0800 Subject: [PATCH] fix(cli): handle 302 redirect in download and fix --skill-version option parsing - undici does not auto-follow HTTP redirects, manually follow 302/307/308 to MinIO presigned URL before piping response body - Commander.js parses --skill-version as skillVersion (camelCase), not skill-version (kebab-case), fix option access in install and download commands --- skillhub-cli/src/commands/download.ts | 15 ++++++++++++--- skillhub-cli/src/commands/install.ts | 18 ++++++++++++++---- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/skillhub-cli/src/commands/download.ts b/skillhub-cli/src/commands/download.ts index 23763156a..3b8d38ad3 100644 --- a/skillhub-cli/src/commands/download.ts +++ b/skillhub-cli/src/commands/download.ts @@ -28,18 +28,27 @@ export function registerDownload(program: Command) { const spinner = ora(`Downloading ${skillSlug} from ${namespace}`).start(); let downloadUrl = `${ApiRoutes.skillDownload.replace("{namespace}", namespace).replace("{slug}", skillSlug)}`; - if (opts["skill-version"]) { - downloadUrl = `/api/v1/skills/${namespace}/${skillSlug}/versions/${opts["skill-version"]}/download`; + if (opts.skillVersion) { + downloadUrl = `/api/v1/skills/${namespace}/${skillSlug}/versions/${opts.skillVersion}/download`; } else if (opts.tag) { downloadUrl = `/api/v1/skills/${namespace}/${skillSlug}/tags/${opts.tag}/download`; } const { request } = await import("undici"); const url = new URL(downloadUrl, config.registry); - const { statusCode, body } = await request(url.toString(), { + let response = await request(url.toString(), { method: "GET", headers: token ? { Authorization: `Bearer ${token}` } : {}, }); + if (response.statusCode === 302 || response.statusCode === 307 || response.statusCode === 308) { + const location = response.headers.location; + if (!location) { + spinner.fail(`Redirect response has no Location header`); + process.exit(1); + } + response = await request(location, { method: "GET" }); + } + const { statusCode, body } = response; if (statusCode >= 400) { spinner.fail(`Download failed: HTTP ${statusCode}`); diff --git a/skillhub-cli/src/commands/install.ts b/skillhub-cli/src/commands/install.ts index 1a9bfbe34..7d1415f82 100644 --- a/skillhub-cli/src/commands/install.ts +++ b/skillhub-cli/src/commands/install.ts @@ -240,9 +240,8 @@ async function installFromRegistry(slug: string, opts: Record= 400) { spinner.fail(`Skill not found: ${ns}/${actualSlug}`);