skillhub/skillhub-cli/src/commands/hide.ts
chenbaowang 2543cd52e7 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.
2026-04-21 00:07:15 +08:00

88 lines
3 KiB
TypeScript

import { Command } from "commander";
import { ApiClient } from "../core/api-client.js";
import { requireToken } from "../core/auth-token.js";
import { loadConfig, loadConfigFromProgram } from "../core/config.js";
import { success, error } from "../utils/logger.js";
import { parseSkillName } from "../core/skill-name.js";
export function registerHide(program: Command) {
const hideCmd = program
.command("hide <slug>")
.description("Hide a skill (admin only)")
.option("-y, --yes", "Skip confirmation")
.action(async (slug: string, opts: { yes?: boolean }) => {
const { namespace, slug: skillSlug } = parseSkillName(slug);
if (!opts.yes) {
const { createInterface } = await import("node:readline");
const rl = createInterface({ input: process.stdin, output: process.stdout });
const answer = await new Promise<string>((r) =>
rl.question(`Hide ${skillSlug} from ${namespace}? [y/N] `, r)
);
rl.close();
if (answer.toLowerCase() !== "y") {
console.log("Cancelled.");
return;
}
}
try {
const token = await requireToken();
const config = loadConfigFromProgram(program);
const client = new ApiClient({ baseUrl: config.registry, token });
const detail = await client.get<{ id: number }>(
`/api/v1/skills/${namespace}/${skillSlug}`
);
await client.post(`/api/v1/admin/skills/${detail.id}/hide`, {
body: JSON.stringify({}),
headers: { "Content-Type": "application/json" },
});
success(`Hidden ${skillSlug}`);
} catch (e: any) {
error(`Failed: ${e.message}`);
process.exit(1);
}
});
hideCmd
.command("unhide <slug>")
.description("Unhide a skill (admin only)")
.option("-y, --yes", "Skip confirmation")
.action(async (slug: string, opts: { yes?: boolean }) => {
const { namespace, slug: skillSlug } = parseSkillName(slug);
if (!opts.yes) {
const { createInterface } = await import("node:readline");
const rl = createInterface({ input: process.stdin, output: process.stdout });
const answer = await new Promise<string>((r) =>
rl.question(`Unhide ${skillSlug} from ${namespace}? [y/N] `, r)
);
rl.close();
if (answer.toLowerCase() !== "y") {
console.log("Cancelled.");
return;
}
}
try {
const token = await requireToken();
const config = loadConfigFromProgram(program);
const client = new ApiClient({ baseUrl: config.registry, token });
const detail = await client.get<{ id: number }>(
`/api/v1/skills/${namespace}/${skillSlug}`
);
await client.post(`/api/v1/admin/skills/${detail.id}/unhide`, {
body: JSON.stringify({}),
headers: { "Content-Type": "application/json" },
});
success(`Unhidden ${skillSlug}`);
} catch (e: any) {
error(`Failed: ${e.message}`);
process.exit(1);
}
});
}