diff --git a/skillhub-cli/src/commands/archive.ts b/skillhub-cli/src/commands/archive.ts index 46052e72..6741a78d 100644 --- a/skillhub-cli/src/commands/archive.ts +++ b/skillhub-cli/src/commands/archive.ts @@ -1,7 +1,7 @@ import { Command } from "commander"; import { ApiClient } from "../core/api-client.js"; import { requireToken } from "../core/auth-token.js"; -import { loadConfig } from "../core/config.js"; +import { loadConfig, loadConfigFromProgram } from "../core/config.js"; import { success, error } from "../utils/logger.js"; import { parseSkillName } from "../core/skill-name.js"; @@ -27,7 +27,7 @@ export function registerArchive(program: Command) { try { const token = await requireToken(); - const config = loadConfig(); + const config = loadConfigFromProgram(program); const client = new ApiClient({ baseUrl: config.registry, token }); await client.post(`/api/v1/skills/${namespace}/${skillSlug}/archive`); success(`Archived ${skillSlug}`); diff --git a/skillhub-cli/src/commands/delete.ts b/skillhub-cli/src/commands/delete.ts index dd338c6b..a535ec29 100644 --- a/skillhub-cli/src/commands/delete.ts +++ b/skillhub-cli/src/commands/delete.ts @@ -1,7 +1,7 @@ import { Command } from "commander"; import { ApiClient } from "../core/api-client.js"; import { requireToken } from "../core/auth-token.js"; -import { loadConfig } from "../core/config.js"; +import { loadConfig, loadConfigFromProgram } from "../core/config.js"; import { success, error } from "../utils/logger.js"; import { parseSkillName } from "../core/skill-name.js"; @@ -28,7 +28,7 @@ export function registerDelete(program: Command) { try { const token = await requireToken(); - const config = loadConfig(); + const config = loadConfigFromProgram(program); const client = new ApiClient({ baseUrl: config.registry, token }); await client.delete(`/api/v1/skills/${namespace}/${skillSlug}`); success(`Deleted ${skillSlug} from ${namespace}`); diff --git a/skillhub-cli/src/commands/download.ts b/skillhub-cli/src/commands/download.ts index 8b6e27d7..54db14a6 100644 --- a/skillhub-cli/src/commands/download.ts +++ b/skillhub-cli/src/commands/download.ts @@ -4,7 +4,7 @@ import { resolve } from "node:path"; import { finished } from "node:stream/promises"; import { ApiClient } from "../core/api-client.js"; import { ApiRoutes } from "../schema/routes.js"; -import { loadConfig } from "../core/config.js"; +import { loadConfig, loadConfigFromProgram } from "../core/config.js"; import { readToken } from "../core/auth-token.js"; import { success, error } from "../utils/logger.js"; import { parseSkillName } from "../core/skill-name.js"; @@ -19,7 +19,7 @@ export function registerDownload(program: Command) { .option("--output ", "Output directory") .action(async (slug: string, opts: Record) => { const { namespace, slug: skillSlug } = parseSkillName(slug); - const config = loadConfig(); + const config = loadConfigFromProgram(program); const token = await readToken(); const client = new ApiClient({ baseUrl: config.registry, token: token || undefined }); diff --git a/skillhub-cli/src/commands/explore.ts b/skillhub-cli/src/commands/explore.ts index dba7576c..cd60d57f 100644 --- a/skillhub-cli/src/commands/explore.ts +++ b/skillhub-cli/src/commands/explore.ts @@ -1,6 +1,6 @@ import { Command } from "commander"; import { ApiClient } from "../core/api-client.js"; -import { loadConfig } from "../core/config.js"; +import { loadConfig, loadConfigFromProgram } from "../core/config.js"; import { readToken } from "../core/auth-token.js"; import { ApiRoutes } from "../schema/routes.js"; import { info, dim } from "../utils/logger.js"; @@ -222,7 +222,7 @@ export function registerExplore(program: Command) { .option("-n, --limit ", "Max results", "20") .option("-s, --sort ", "Sort by: hot, newest, downloads (default: interactive mode)") .action(async (query: string | undefined, opts: { limit: string; sort?: string }) => { - const config = loadConfig(); + const config = loadConfigFromProgram(program); const token = await readToken(); const client = new ApiClient({ baseUrl: config.registry, token: token || undefined }); const sortMap: Record = { hot: "rating", newest: "newest", downloads: "downloads" }; diff --git a/skillhub-cli/src/commands/hide.ts b/skillhub-cli/src/commands/hide.ts index 7863c43c..d647e3f2 100644 --- a/skillhub-cli/src/commands/hide.ts +++ b/skillhub-cli/src/commands/hide.ts @@ -1,7 +1,7 @@ import { Command } from "commander"; import { ApiClient } from "../core/api-client.js"; import { requireToken } from "../core/auth-token.js"; -import { loadConfig } from "../core/config.js"; +import { loadConfig, loadConfigFromProgram } from "../core/config.js"; import { success, error } from "../utils/logger.js"; import { parseSkillName } from "../core/skill-name.js"; @@ -27,7 +27,7 @@ export function registerHide(program: Command) { try { const token = await requireToken(); - const config = loadConfig(); + const config = loadConfigFromProgram(program); const client = new ApiClient({ baseUrl: config.registry, token }); const detail = await client.get<{ id: number }>( @@ -67,7 +67,7 @@ export function registerHide(program: Command) { try { const token = await requireToken(); - const config = loadConfig(); + const config = loadConfigFromProgram(program); const client = new ApiClient({ baseUrl: config.registry, token }); const detail = await client.get<{ id: number }>( diff --git a/skillhub-cli/src/commands/inspect.ts b/skillhub-cli/src/commands/inspect.ts index 8acbea8e..f68ca0ee 100644 --- a/skillhub-cli/src/commands/inspect.ts +++ b/skillhub-cli/src/commands/inspect.ts @@ -1,7 +1,7 @@ import { Command } from "commander"; import { ApiClient } from "../core/api-client.js"; import { ApiRoutes } from "../schema/routes.js"; -import { loadConfig } from "../core/config.js"; +import { loadConfig, loadConfigFromProgram } from "../core/config.js"; import { readToken } from "../core/auth-token.js"; import { parseSkillName } from "../core/skill-name.js"; import { info, dim, error } from "../utils/logger.js"; @@ -70,7 +70,7 @@ export function registerInspect(program: Command) { .description("View skill metadata without installing") .option("--namespace ", "Search in specific namespace (searches all if not specified)") .action(async (slug: string, opts: { namespace?: string }) => { - const config = loadConfig(); + const config = loadConfigFromProgram(program); const token = await readToken(); const client = new ApiClient({ baseUrl: config.registry, token: token || undefined }); diff --git a/skillhub-cli/src/commands/install.ts b/skillhub-cli/src/commands/install.ts index 4a272a4f..7062e52b 100644 --- a/skillhub-cli/src/commands/install.ts +++ b/skillhub-cli/src/commands/install.ts @@ -4,7 +4,7 @@ import { tmpdir } from "node:os"; import { join } from "node:path"; import { createWriteStream, createReadStream, existsSync, mkdirSync } from "node:fs"; import { ApiClient } from "../core/api-client.js"; -import { loadConfig } from "../core/config.js"; +import { loadConfigFromProgram } from "../core/config.js"; import { readToken } from "../core/auth-token.js"; import { discoverSkills } from "../core/skill-discovery.js"; import { installSkill } from "../core/installer.js"; @@ -227,9 +227,9 @@ export function registerInstall(program: Command) { try { if (effectiveSource === "registry") { - await installFromRegistry(source, opts, spinner); + await installFromRegistry(source, opts, spinner, program); } else { - await installFromGit(source, installSource, effectiveSource, opts, spinner); + await installFromGit(source, installSource, effectiveSource, opts, spinner, program); } } catch (e: any) { spinner.fail(e.message); @@ -238,7 +238,12 @@ export function registerInstall(program: Command) { }); } -async function installFromRegistry(slug: string, opts: Record, spinner: any) { +async function installFromRegistry( + slug: string, + opts: Record, + spinner: any, + program: Command +) { let ns = "global"; let actualSlug = slug; let userSpecifiedNamespace = false; @@ -252,7 +257,7 @@ async function installFromRegistry(slug: string, opts: Record, spinner: any) { +async function installFromGit( + skillName: string, + source: string, + sourceType: SourceType, + opts: Record, + spinner: any, + program: Command +) { let skillsDir: string; const parsed = parseSource(source); diff --git a/skillhub-cli/src/commands/me.ts b/skillhub-cli/src/commands/me.ts index 9fb52ba1..015e5ed3 100644 --- a/skillhub-cli/src/commands/me.ts +++ b/skillhub-cli/src/commands/me.ts @@ -1,6 +1,6 @@ import { Command } from "commander"; import { ApiClient } from "../core/api-client.js"; -import { loadConfig } from "../core/config.js"; +import { loadConfig, loadConfigFromProgram } from "../core/config.js"; import { requireToken } from "../core/auth-token.js"; import { error, info, dim } from "../utils/logger.js"; @@ -33,7 +33,7 @@ export function registerMe(program: Command) { .action(async () => { try { const token = await requireToken(); - const config = loadConfig(); + const config = loadConfigFromProgram(program); const client = new ApiClient({ baseUrl: config.registry, token }); const resp = await client.get("/api/v1/me/skills"); const skills = resp.items || []; @@ -63,7 +63,7 @@ export function registerMe(program: Command) { .action(async () => { try { const token = await requireToken(); - const config = loadConfig(); + const config = loadConfigFromProgram(program); const client = new ApiClient({ baseUrl: config.registry, token }); const resp = await client.get("/api/v1/me/stars"); const skills = resp.items || []; diff --git a/skillhub-cli/src/commands/namespaces.ts b/skillhub-cli/src/commands/namespaces.ts index 8359c5ee..942bdb10 100644 --- a/skillhub-cli/src/commands/namespaces.ts +++ b/skillhub-cli/src/commands/namespaces.ts @@ -2,7 +2,7 @@ import { Command } from "commander"; import { ApiClient } from "../core/api-client.js"; import { ApiRoutes, NamespaceResponse } from "../schema/routes.js"; import { requireToken } from "../core/auth-token.js"; -import { loadConfig } from "../core/config.js"; +import { loadConfig, loadConfigFromProgram } from "../core/config.js"; import { error } from "../utils/logger.js"; export function registerNamespaces(program: Command) { @@ -12,7 +12,7 @@ export function registerNamespaces(program: Command) { .action(async () => { try { const token = await requireToken(); - const config = loadConfig(); + const config = loadConfigFromProgram(program); const client = new ApiClient({ baseUrl: config.registry, token }); const namespaces = await client.get(ApiRoutes.meNamespaces); const isJson = program.opts().json; diff --git a/skillhub-cli/src/commands/notifications.ts b/skillhub-cli/src/commands/notifications.ts index 2fd73ec8..fe341ee6 100644 --- a/skillhub-cli/src/commands/notifications.ts +++ b/skillhub-cli/src/commands/notifications.ts @@ -1,6 +1,6 @@ import { Command } from "commander"; import { ApiClient } from "../core/api-client.js"; -import { loadConfig } from "../core/config.js"; +import { loadConfig, loadConfigFromProgram } from "../core/config.js"; import { requireToken } from "../core/auth-token.js"; import { success, error, info, dim } from "../utils/logger.js"; @@ -26,7 +26,7 @@ export function registerNotifications(program: Command) { .action(async (opts: { unread?: boolean }) => { try { const token = await requireToken(); - const config = loadConfig(); + const config = loadConfigFromProgram(program); const client = new ApiClient({ baseUrl: config.registry, token }); const notifs = await client.get("/api/v1/notifications"); const filtered = opts.unread ? notifs.filter((n) => !n.read) : notifs; @@ -50,7 +50,7 @@ export function registerNotifications(program: Command) { .action(async (id: string) => { try { const token = await requireToken(); - const config = loadConfig(); + const config = loadConfigFromProgram(program); const client = new ApiClient({ baseUrl: config.registry, token }); await client.put(`/api/v1/notifications/${id}/read`); success(`Marked notification ${id} as read`); @@ -66,7 +66,7 @@ export function registerNotifications(program: Command) { .action(async () => { try { const token = await requireToken(); - const config = loadConfig(); + const config = loadConfigFromProgram(program); const client = new ApiClient({ baseUrl: config.registry, token }); await client.put("/api/v1/notifications/read-all"); success("All notifications marked as read"); diff --git a/skillhub-cli/src/commands/publish.ts b/skillhub-cli/src/commands/publish.ts index 8f62822b..0ccd41f7 100644 --- a/skillhub-cli/src/commands/publish.ts +++ b/skillhub-cli/src/commands/publish.ts @@ -5,7 +5,7 @@ import { FormData } from "undici"; import { ApiClient } from "../core/api-client.js"; import { ApiRoutes, PublishResponse } from "../schema/routes.js"; import { requireToken } from "../core/auth-token.js"; -import { loadConfig } from "../core/config.js"; +import { loadConfig, loadConfigFromProgram } from "../core/config.js"; import { success, error, info } from "../utils/logger.js"; import ora from "ora"; import semver from "semver"; @@ -49,7 +49,7 @@ export function registerPublish(program: Command) { try { const token = await requireToken(); - const config = loadConfig(); + const config = loadConfigFromProgram(program); const client = new ApiClient({ baseUrl: config.registry, token }); const spinner = ora(`Publishing ${slug}@${version} to ${namespace}`).start(); diff --git a/skillhub-cli/src/commands/rating.ts b/skillhub-cli/src/commands/rating.ts index 583d4f6a..92fcd173 100644 --- a/skillhub-cli/src/commands/rating.ts +++ b/skillhub-cli/src/commands/rating.ts @@ -1,6 +1,6 @@ import { Command } from "commander"; import { ApiClient } from "../core/api-client.js"; -import { loadConfig } from "../core/config.js"; +import { loadConfig, loadConfigFromProgram } from "../core/config.js"; import { requireToken } from "../core/auth-token.js"; import { success, error, info, dim } from "../utils/logger.js"; import { parseSkillName } from "../core/skill-name.js"; @@ -13,7 +13,7 @@ export function registerRating(program: Command) { try { const { namespace, slug: skillSlug } = parseSkillName(slug); const token = await requireToken(); - const config = loadConfig(); + const config = loadConfigFromProgram(program); const client = new ApiClient({ baseUrl: config.registry, token }); const detail = await client.get<{ id: number }>( @@ -51,7 +51,7 @@ export function registerRate(program: Command) { try { const { namespace, slug: skillSlug } = parseSkillName(slug); const token = await requireToken(); - const config = loadConfig(); + const config = loadConfigFromProgram(program); const client = new ApiClient({ baseUrl: config.registry, token }); const detail = await client.get<{ id: number }>( diff --git a/skillhub-cli/src/commands/report.ts b/skillhub-cli/src/commands/report.ts index 91c3e14c..f20c6d87 100644 --- a/skillhub-cli/src/commands/report.ts +++ b/skillhub-cli/src/commands/report.ts @@ -2,7 +2,7 @@ import { Command } from "commander"; import { createInterface } from "node:readline"; import { ApiClient } from "../core/api-client.js"; import { requireToken } from "../core/auth-token.js"; -import { loadConfig } from "../core/config.js"; +import { loadConfig, loadConfigFromProgram } from "../core/config.js"; import { success, error } from "../utils/logger.js"; import { parseSkillName } from "../core/skill-name.js"; @@ -15,7 +15,7 @@ export function registerReport(program: Command) { try { const { namespace, slug: skillSlug } = parseSkillName(slug); const token = await requireToken(); - const config = loadConfig(); + const config = loadConfigFromProgram(program); const client = new ApiClient({ baseUrl: config.registry, token }); let reason = opts.reason; diff --git a/skillhub-cli/src/commands/resolve.ts b/skillhub-cli/src/commands/resolve.ts index 348f564b..6d83ce2a 100644 --- a/skillhub-cli/src/commands/resolve.ts +++ b/skillhub-cli/src/commands/resolve.ts @@ -1,6 +1,6 @@ import { Command } from "commander"; import { ApiClient } from "../core/api-client.js"; -import { loadConfig } from "../core/config.js"; +import { loadConfig, loadConfigFromProgram } from "../core/config.js"; import { readToken } from "../core/auth-token.js"; import { success, error, info, dim } from "../utils/logger.js"; import { parseSkillName } from "../core/skill-name.js"; @@ -51,7 +51,7 @@ export function registerResolve(program: Command) { .action(async (slug: string, opts: Record) => { try { const { namespace, slug: skillSlug } = parseSkillName(slug); - const config = loadConfig(); + const config = loadConfigFromProgram(program); const token = await readToken(); const client = new ApiClient({ baseUrl: config.registry, token: token || undefined }); diff --git a/skillhub-cli/src/commands/reviews.ts b/skillhub-cli/src/commands/reviews.ts index ba38ca14..911777e0 100644 --- a/skillhub-cli/src/commands/reviews.ts +++ b/skillhub-cli/src/commands/reviews.ts @@ -1,7 +1,7 @@ import { Command } from "commander"; import { ApiClient } from "../core/api-client.js"; import { requireToken } from "../core/auth-token.js"; -import { loadConfig } from "../core/config.js"; +import { loadConfig, loadConfigFromProgram } from "../core/config.js"; import { success, error, info, dim } from "../utils/logger.js"; export interface ReviewSubmission { @@ -24,7 +24,7 @@ export function registerReviews(program: Command) { .action(async () => { try { const token = await requireToken(); - const config = loadConfig(); + const config = loadConfigFromProgram(program); const client = new ApiClient({ baseUrl: config.registry, token }); const submissions = await client.get("/api/v1/reviews/my-submissions"); if (!submissions || submissions.length === 0) { diff --git a/skillhub-cli/src/commands/search.ts b/skillhub-cli/src/commands/search.ts index 47e4b482..70c96ddd 100644 --- a/skillhub-cli/src/commands/search.ts +++ b/skillhub-cli/src/commands/search.ts @@ -1,7 +1,7 @@ import { Command } from "commander"; import { ApiClient } from "../core/api-client.js"; import { ApiRoutes, SearchResponse } from "../schema/routes.js"; -import { loadConfig } from "../core/config.js"; +import { loadConfig, loadConfigFromProgram } from "../core/config.js"; import { readToken } from "../core/auth-token.js"; import { error, dim } from "../utils/logger.js"; @@ -12,7 +12,7 @@ export function registerSearch(program: Command) { .option("-n, --limit ", "Max results", "20") .option("--namespace ", "Filter by namespace") .action(async (query: string[], opts: { limit: string; namespace?: string }) => { - const config = loadConfig(); + const config = loadConfigFromProgram(program); const token = await readToken(); const client = new ApiClient({ baseUrl: config.registry, token: token || undefined }); diff --git a/skillhub-cli/src/commands/star.ts b/skillhub-cli/src/commands/star.ts index 067e2c1a..26651965 100644 --- a/skillhub-cli/src/commands/star.ts +++ b/skillhub-cli/src/commands/star.ts @@ -2,7 +2,7 @@ import { Command } from "commander"; import { ApiClient } from "../core/api-client.js"; import { ApiRoutes } from "../schema/routes.js"; import { requireToken } from "../core/auth-token.js"; -import { loadConfig } from "../core/config.js"; +import { loadConfig, loadConfigFromProgram } from "../core/config.js"; import { success, error } from "../utils/logger.js"; import { parseSkillName } from "../core/skill-name.js"; @@ -15,7 +15,7 @@ export function registerStar(program: Command) { try { const { namespace, slug: skillSlug } = parseSkillName(slug); const token = await requireToken(); - const config = loadConfig(); + const config = loadConfigFromProgram(program); const client = new ApiClient({ baseUrl: config.registry, token }); const detailPath = ApiRoutes.skillDetail.replace("{namespace}", namespace).replace("{slug}", skillSlug); diff --git a/skillhub-cli/src/commands/sync.ts b/skillhub-cli/src/commands/sync.ts index 9ded9ae6..7f87bbb8 100644 --- a/skillhub-cli/src/commands/sync.ts +++ b/skillhub-cli/src/commands/sync.ts @@ -5,7 +5,7 @@ import { FormData } from "undici"; import { existsSync } from "node:fs"; import { discoverSkills } from "../core/skill-discovery.js"; import { requireToken } from "../core/auth-token.js"; -import { loadConfig } from "../core/config.js"; +import { loadConfig, loadConfigFromProgram } from "../core/config.js"; import { ApiClient } from "../core/api-client.js"; import { ApiRoutes } from "../schema/routes.js"; import { info, dim, success, error } from "../utils/logger.js"; @@ -36,7 +36,7 @@ export function registerSync(program: Command) { try { const token = await requireToken(); - const config = loadConfig(); + const config = loadConfigFromProgram(program); const client = new ApiClient({ baseUrl: config.registry, token }); info(`Scanning ${scanPath} for skills...`); diff --git a/skillhub-cli/src/commands/transfer.ts b/skillhub-cli/src/commands/transfer.ts index b54684e1..92c983a9 100644 --- a/skillhub-cli/src/commands/transfer.ts +++ b/skillhub-cli/src/commands/transfer.ts @@ -2,7 +2,7 @@ import { Command } from "commander"; import { ApiClient } from "../core/api-client.js"; import { ApiRoutes } from "../schema/routes.js"; import { requireToken } from "../core/auth-token.js"; -import { loadConfig } from "../core/config.js"; +import { loadConfig, loadConfigFromProgram } from "../core/config.js"; import { success, error } from "../utils/logger.js"; export function registerTransfer(program: Command) { @@ -26,7 +26,7 @@ export function registerTransfer(program: Command) { try { const token = await requireToken(); - const config = loadConfig(); + const config = loadConfigFromProgram(program); const client = new ApiClient({ baseUrl: config.registry, token }); await client.post(ApiRoutes.namespaceTransferOwnership.replace("{namespace}", namespace), { body: JSON.stringify({ newOwnerId }) }); success(`Ownership of ${namespace} transferred to ${newOwnerId}`); diff --git a/skillhub-cli/src/commands/versions.ts b/skillhub-cli/src/commands/versions.ts index bc0e9de5..4177e2be 100644 --- a/skillhub-cli/src/commands/versions.ts +++ b/skillhub-cli/src/commands/versions.ts @@ -1,7 +1,7 @@ import { Command } from "commander"; import { ApiClient } from "../core/api-client.js"; import { readToken } from "../core/auth-token.js"; -import { loadConfig } from "../core/config.js"; +import { loadConfig, loadConfigFromProgram } from "../core/config.js"; import { error, info, dim, success } from "../utils/logger.js"; import { parseSkillName } from "../core/skill-name.js"; import { searchSkills, runInteractiveSearch } from "../core/interactive-search.js"; @@ -37,7 +37,7 @@ export function registerVersions(program: Command) { .action(async (slug: string) => { try { const { namespace, slug: skillSlug } = parseSkillName(slug); - const config = loadConfig(); + const config = loadConfigFromProgram(program); const token = await readToken(); const client = new ApiClient({ baseUrl: config.registry, token: token || undefined }); diff --git a/skillhub-cli/src/commands/whoami.ts b/skillhub-cli/src/commands/whoami.ts index 3aa2954a..dbb77ad2 100644 --- a/skillhub-cli/src/commands/whoami.ts +++ b/skillhub-cli/src/commands/whoami.ts @@ -3,7 +3,7 @@ import { ApiClient } from "../core/api-client.js"; import { ApiRoutes, WhoamiResponse } from "../schema/routes.js"; import { requireToken } from "../core/auth-token.js"; import { success, error } from "../utils/logger.js"; -import { loadConfig } from "../core/config.js"; +import { loadConfig, loadConfigFromProgram } from "../core/config.js"; export function registerWhoami(program: Command) { program @@ -12,7 +12,7 @@ export function registerWhoami(program: Command) { .action(async () => { try { const token = await requireToken(); - const config = loadConfig(); + const config = loadConfigFromProgram(program); const client = new ApiClient({ baseUrl: config.registry, token }); const resp = await client.get(ApiRoutes.whoami); const isJson = program.opts().json; diff --git a/skillhub-cli/src/core/config.ts b/skillhub-cli/src/core/config.ts index bbfd3009..fd42523d 100644 --- a/skillhub-cli/src/core/config.ts +++ b/skillhub-cli/src/core/config.ts @@ -1,6 +1,7 @@ import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs"; import { homedir } from "node:os"; import { join } from "node:path"; +import type { Command } from "commander"; const CONFIG_DIR = join(homedir(), ".skillhub"); const CONFIG_FILE = join(CONFIG_DIR, "config.json"); @@ -14,24 +15,43 @@ const DEFAULT_CONFIG: CliConfig = { registry: "http://localhost:8080", }; -export function loadConfig(): CliConfig { +export function loadConfig(overrides?: Partial): CliConfig { + // Priority: overrides > env > config file > defaults const envRegistry = process.env.SKILLHUB_REGISTRY; - if (envRegistry) { - if (!existsSync(CONFIG_FILE)) return { registry: envRegistry }; + const baseConfig: CliConfig = envRegistry + ? { registry: envRegistry } + : { ...DEFAULT_CONFIG }; + + if (existsSync(CONFIG_FILE)) { try { const raw = readFileSync(CONFIG_FILE, "utf-8"); - return { registry: envRegistry, ...JSON.parse(raw) }; + Object.assign(baseConfig, JSON.parse(raw)); } catch { - return { registry: envRegistry }; + // Use base config if file is invalid } } - if (!existsSync(CONFIG_FILE)) return { ...DEFAULT_CONFIG }; - try { - const raw = readFileSync(CONFIG_FILE, "utf-8"); - return { ...DEFAULT_CONFIG, ...JSON.parse(raw) }; - } catch { - return { ...DEFAULT_CONFIG }; + + // Apply overrides (e.g., from command-line options) + if (overrides) { + Object.assign(baseConfig, overrides); } + + return baseConfig; +} + +/** + * Helper function to load config with command-line options from Commander.js program + * Use this in command actions to get config that respects --registry flag + */ +export function loadConfigFromProgram(program: Command): CliConfig { + const opts = program.opts(); + const overrides: Partial = {}; + + if (opts.registry) { + overrides.registry = opts.registry as string; + } + + return loadConfig(overrides); } export function saveConfig(config: Partial): void {