mirror of
https://github.com/iflytek/skillhub.git
synced 2026-09-15 23:31:10 +00:00
fix(cli): make --registry parameter work for all commands
Fixed the issue where the --registry command-line parameter was defined but not actually used by any commands. Changes: - Added loadConfigFromProgram() helper in config.ts to read registry from program.opts() - Updated all 21 command files to use loadConfigFromProgram() instead of loadConfig() - Ensured correct priority: CLI args > env vars > config file > defaults Priority order: 1. --registry <url> (command-line flag) - highest priority 2. SKILLHUB_REGISTRY (environment variable) 3. ~/.skillhub/config.json (config file) 4. http://localhost:8080 (default value) This allows users to temporarily override the registry without modifying environment variables or config files, providing better flexibility for: - Testing against different registries - Multi-project/multi-environment setups - CI/CD automation scripts Updated commands: - install, download, update, check, sync, uninstall - explore, search - publish, delete, archive, versions - inspect, resolve, rating, rate, star, report, reviews - whoami, me, namespaces, notifications - transfer, hide, unhide Fixes issue where `npx motovis-skillhub install <skill> --registry <url>` would ignore the --registry parameter and use env vars or defaults instead.
This commit is contained in:
parent
d6b9f026b4
commit
2543cd52e7
22 changed files with 94 additions and 62 deletions
|
|
@ -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}`);
|
||||
|
|
|
|||
|
|
@ -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}`);
|
||||
|
|
|
|||
|
|
@ -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 <dir>", "Output directory")
|
||||
.action(async (slug: string, opts: Record<string, string>) => {
|
||||
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 });
|
||||
|
||||
|
|
|
|||
|
|
@ -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 <n>", "Max results", "20")
|
||||
.option("-s, --sort <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<string, string> = { hot: "rating", newest: "newest", downloads: "downloads" };
|
||||
|
|
|
|||
|
|
@ -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 }>(
|
||||
|
|
|
|||
|
|
@ -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 <ns>", "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 });
|
||||
|
||||
|
|
|
|||
|
|
@ -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<string, string | string[] | boolean>, spinner: any) {
|
||||
async function installFromRegistry(
|
||||
slug: string,
|
||||
opts: Record<string, string | string[] | boolean>,
|
||||
spinner: any,
|
||||
program: Command
|
||||
) {
|
||||
let ns = "global";
|
||||
let actualSlug = slug;
|
||||
let userSpecifiedNamespace = false;
|
||||
|
|
@ -252,7 +257,7 @@ async function installFromRegistry(slug: string, opts: Record<string, string | s
|
|||
}
|
||||
}
|
||||
|
||||
const config = loadConfig();
|
||||
const config = loadConfigFromProgram(program);
|
||||
const token = await readToken();
|
||||
const client = new ApiClient({ baseUrl: config.registry, token: token || undefined });
|
||||
|
||||
|
|
@ -581,7 +586,14 @@ async function installFromRegistry(slug: string, opts: Record<string, string | s
|
|||
await rm(tmpDir, { recursive: true, force: true });
|
||||
}
|
||||
|
||||
async function installFromGit(skillName: string, source: string, sourceType: SourceType, opts: Record<string, string | string[] | boolean>, spinner: any) {
|
||||
async function installFromGit(
|
||||
skillName: string,
|
||||
source: string,
|
||||
sourceType: SourceType,
|
||||
opts: Record<string, string | string[] | boolean>,
|
||||
spinner: any,
|
||||
program: Command
|
||||
) {
|
||||
let skillsDir: string;
|
||||
|
||||
const parsed = parseSource(source);
|
||||
|
|
|
|||
|
|
@ -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<MeSkillsResponse>("/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<MeSkillsResponse>("/api/v1/me/stars");
|
||||
const skills = resp.items || [];
|
||||
|
|
|
|||
|
|
@ -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<NamespaceResponse[]>(ApiRoutes.meNamespaces);
|
||||
const isJson = program.opts().json;
|
||||
|
|
|
|||
|
|
@ -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<Notification[]>("/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");
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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 }>(
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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<string, 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 });
|
||||
|
||||
|
|
|
|||
|
|
@ -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<ReviewSubmission[]>("/api/v1/reviews/my-submissions");
|
||||
if (!submissions || submissions.length === 0) {
|
||||
|
|
|
|||
|
|
@ -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 <n>", "Max results", "20")
|
||||
.option("--namespace <ns>", "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 });
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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...`);
|
||||
|
|
|
|||
|
|
@ -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}`);
|
||||
|
|
|
|||
|
|
@ -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 });
|
||||
|
||||
|
|
|
|||
|
|
@ -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<WhoamiResponse>(ApiRoutes.whoami);
|
||||
const isJson = program.opts().json;
|
||||
|
|
|
|||
|
|
@ -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>): 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<CliConfig> = {};
|
||||
|
||||
if (opts.registry) {
|
||||
overrides.registry = opts.registry as string;
|
||||
}
|
||||
|
||||
return loadConfig(overrides);
|
||||
}
|
||||
|
||||
export function saveConfig(config: Partial<CliConfig>): void {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue