mirror of
https://github.com/iflytek/skillhub.git
synced 2026-09-16 23:41:19 +00:00
feat(cli): 优化帮助界面和命令结构
- 重新组织帮助分类(Publish → Publish & Manage) - 统一参数命名为 <skill>,添加参数说明 - 简化 config 命令描述 - 优化 explore 帮助,添加选项分组和示例 - 修复参数重复显示问题 - 子命令帮助显示 Arguments 部分
This commit is contained in:
parent
c7d4f8273d
commit
08ce3d59a1
21 changed files with 199 additions and 77 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -1,6 +1,7 @@
|
|||
# OS files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
.nfs*
|
||||
|
||||
# Editors / IDEs / local tooling
|
||||
.claude/
|
||||
|
|
@ -14,6 +15,7 @@ Thumbs.db
|
|||
*.iml
|
||||
*.swp
|
||||
*.swo
|
||||
*.code-workspace
|
||||
|
||||
# Logs
|
||||
*.log
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "motovis-skillhub",
|
||||
"version": "1.2.6",
|
||||
"version": "1.2.8",
|
||||
"type": "module",
|
||||
"description": "SkillHub CLI - 企业级 Agent Skill 管理工具,支持命名空间",
|
||||
"bin": {
|
||||
|
|
|
|||
|
|
@ -30,14 +30,12 @@ interface HelpEntry {
|
|||
}
|
||||
|
||||
function formatSection(header: string, entries: HelpEntry[]): string {
|
||||
const displayWidth = (e: HelpEntry) => e.cmd.length + (e.alias ? e.alias.length + 3 : 0);
|
||||
const maxW = entries.reduce((max, e) => Math.max(max, displayWidth(e)), 0);
|
||||
const col = Math.max(maxW + 4, 28);
|
||||
const lines = [bold(header)];
|
||||
|
||||
for (const e of entries) {
|
||||
const aliasPart = e.alias ? dim(` (${e.alias})`) : "";
|
||||
const pad = " ".repeat(Math.max(col - displayWidth(e), 2));
|
||||
lines.push(` ${cyan(e.cmd)}${aliasPart}${pad}${e.desc}`);
|
||||
lines.push(` ${cyan(e.cmd)}${aliasPart}`);
|
||||
lines.push(` ${e.desc}`);
|
||||
}
|
||||
return lines.join("\n");
|
||||
}
|
||||
|
|
@ -51,8 +49,8 @@ function buildTopLevelHelp(version: string): string {
|
|||
|
||||
sections.push(formatSection("Configuration", [
|
||||
{ cmd: "config list", desc: "Show current registry configuration" },
|
||||
{ cmd: "config set <key> <value>", desc: "Set configuration (e.g., registry URL)" },
|
||||
{ cmd: "config get <key>", desc: "Get configuration value" },
|
||||
{ cmd: "config set <value>", desc: "Set registry URL" },
|
||||
{ cmd: "config get", desc: "Get current registry configuration" },
|
||||
{ cmd: "config show-env-instructions", desc: "Show environment variable setup guide" },
|
||||
]));
|
||||
sections.push("");
|
||||
|
|
@ -64,37 +62,37 @@ function buildTopLevelHelp(version: string): string {
|
|||
]));
|
||||
sections.push("");
|
||||
|
||||
sections.push(formatSection("Discover & Info", [
|
||||
sections.push(formatSection("Discovery", [
|
||||
{ cmd: "explore", desc: "Browse or search skills from the registry", alias: "find, find-skills, search" },
|
||||
{ cmd: "inspect <slug>", desc: "View skill metadata and versions", alias: "info, view" },
|
||||
{ cmd: "resolve <slug>", desc: "Resolve the latest version of a skill" },
|
||||
]));
|
||||
sections.push("");
|
||||
|
||||
sections.push(formatSection("Social & Reviews", [
|
||||
{ cmd: "star <slug>", desc: "Star or unstar a skill" },
|
||||
{ cmd: "rating <slug>", desc: "View your rating for a skill" },
|
||||
{ cmd: "rate <slug> <score>", desc: "Rate a skill (1-5)" },
|
||||
{ cmd: "report <slug>", desc: "Report a skill for review" },
|
||||
{ cmd: "inspect <skill>", desc: "View skill metadata and versions", alias: "info, view" },
|
||||
{ cmd: "resolve <skill>", desc: "Resolve the latest version of a skill" },
|
||||
]));
|
||||
sections.push("");
|
||||
|
||||
sections.push(formatSection("Install & Manage", [
|
||||
{ cmd: "install <skill-name>", desc: "Install from registry, git, or local path", alias: "i" },
|
||||
{ cmd: "download <slug>", desc: "Download a skill package to local directory" },
|
||||
{ cmd: "update [slug]", desc: "Update installed skills from their source", alias: "up" },
|
||||
{ cmd: "uninstall [name]", desc: "Uninstall a skill from local agent", alias: "un" },
|
||||
{ cmd: "install <skill>", desc: "Install from registry, git, or local path", alias: "i" },
|
||||
{ cmd: "download <skill>", desc: "Download a skill package to local directory" },
|
||||
{ cmd: "update [skill]", desc: "Update installed skills from their source", alias: "up" },
|
||||
{ cmd: "uninstall [skill]", desc: "Uninstall a skill from local agent", alias: "un" },
|
||||
{ cmd: "list", desc: "List installed skills", alias: "ls" },
|
||||
{ cmd: "check", desc: "Check installed skills against lock file" },
|
||||
]));
|
||||
sections.push("");
|
||||
|
||||
sections.push(formatSection("Publish", [
|
||||
sections.push(formatSection("Social", [
|
||||
{ cmd: "star <skill>", desc: "Star or unstar a skill" },
|
||||
{ cmd: "rating <skill>", desc: "View your rating for a skill" },
|
||||
{ cmd: "rate <skill> <score>", desc: "Rate a skill (1-5)" },
|
||||
{ cmd: "report <skill>", desc: "Report a skill for review" },
|
||||
]));
|
||||
sections.push("");
|
||||
|
||||
sections.push(formatSection("Publish & Manage", [
|
||||
{ cmd: "init [name]", desc: "Create a new SKILL.md template" },
|
||||
{ cmd: "publish [path]", desc: "Publish a skill to SkillHub registry" },
|
||||
{ cmd: "sync [path]", desc: "Scan and publish all skills from a directory" },
|
||||
{ cmd: "delete <slug>", desc: "Delete a skill you own", alias: "del, unpublish" },
|
||||
{ cmd: "archive <slug>", desc: "Archive a skill you own" },
|
||||
{ cmd: "delete <skill>", desc: "Delete a skill you own", alias: "del, unpublish" },
|
||||
{ cmd: "archive <skill>", desc: "Archive a skill you own" },
|
||||
]));
|
||||
sections.push("");
|
||||
|
||||
|
|
@ -108,8 +106,8 @@ function buildTopLevelHelp(version: string): string {
|
|||
sections.push("");
|
||||
|
||||
sections.push(formatSection("Admin", [
|
||||
{ cmd: "hide <slug>", desc: "Hide a skill (admin only)" },
|
||||
{ cmd: "unhide <slug>", desc: "Unhide a skill (admin only)" },
|
||||
{ cmd: "hide <skill>", desc: "Hide a skill (admin only)" },
|
||||
{ cmd: "unhide <skill>", desc: "Unhide a skill (admin only)" },
|
||||
{ cmd: "transfer <ns> <user>", desc: "Transfer namespace ownership" },
|
||||
]));
|
||||
sections.push("");
|
||||
|
|
|
|||
|
|
@ -7,8 +7,9 @@ import { parseSkillName } from "../core/skill-name.js";
|
|||
|
||||
export function registerArchive(program: Command) {
|
||||
program
|
||||
.command("archive <slug>")
|
||||
.command("archive")
|
||||
.description("Archive a skill you own")
|
||||
.argument("<skill>", "Skill name or namespace/skill-name")
|
||||
.option("-y, --yes", "Skip confirmation")
|
||||
.action(async (slug: string, opts: { yes?: boolean }) => {
|
||||
const { namespace, slug: skillSlug } = parseSkillName(slug);
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ export function registerConfig(program: Command) {
|
|||
|
||||
configCmd
|
||||
.command("list")
|
||||
.description("List all configuration sources and their values")
|
||||
.description("Show all config values and their sources")
|
||||
.action(() => {
|
||||
const env = process.env.SKILLHUB_REGISTRY;
|
||||
let fileConfig: { registry?: string } = {};
|
||||
|
|
@ -56,7 +56,7 @@ export function registerConfig(program: Command) {
|
|||
|
||||
configCmd
|
||||
.command("set <value>")
|
||||
.description("Set registry URL in ~/.skillhub/config.json")
|
||||
.description("Set registry URL (e.g., https://api.example.com)")
|
||||
.action((value: string) => {
|
||||
if (!existsSync(CONFIG_DIR)) {
|
||||
mkdirSync(CONFIG_DIR, { recursive: true });
|
||||
|
|
@ -79,7 +79,7 @@ export function registerConfig(program: Command) {
|
|||
|
||||
configCmd
|
||||
.command("get")
|
||||
.description("Get registry configuration value")
|
||||
.description("Show the current registry URL")
|
||||
.option("--source <source>", "Source: env, file, or resolved (default)")
|
||||
.action((opts: { source?: string }) => {
|
||||
const source = opts.source || "resolved";
|
||||
|
|
|
|||
|
|
@ -7,9 +7,9 @@ import { parseSkillName } from "../core/skill-name.js";
|
|||
|
||||
export function registerDelete(program: Command) {
|
||||
program
|
||||
.command("delete <slug>")
|
||||
.aliases(["del", "unpublish"])
|
||||
.command("delete")
|
||||
.description("Delete a skill you own")
|
||||
.argument("<skill>", "Skill name or namespace/skill-name")
|
||||
.option("-y, --yes", "Skip confirmation")
|
||||
.action(async (slug: string, opts: { yes?: boolean }) => {
|
||||
const { namespace, slug: skillSlug } = parseSkillName(slug);
|
||||
|
|
|
|||
|
|
@ -12,8 +12,9 @@ import ora from "ora";
|
|||
|
||||
export function registerDownload(program: Command) {
|
||||
program
|
||||
.command("download <slug>")
|
||||
.command("download")
|
||||
.description("Download a skill package to local directory")
|
||||
.argument("<skill>", "Skill name or namespace/skill-name")
|
||||
.option("-v, --skill-version <ver>", "Specific version")
|
||||
.option("--tag <tag>", "Tag to download", "latest")
|
||||
.option("--output <dir>", "Output directory")
|
||||
|
|
|
|||
|
|
@ -214,20 +214,60 @@ async function runInteractiveSearch(
|
|||
});
|
||||
}
|
||||
|
||||
function buildExploreHelp(cmd: Command): string {
|
||||
const lines: string[] = [];
|
||||
|
||||
lines.push(`${BOLD}Usage:${RESET} skillhub explore [options] [query]`);
|
||||
lines.push("");
|
||||
lines.push("Browse or search skills from the registry");
|
||||
lines.push("");
|
||||
|
||||
lines.push(`${BOLD}Arguments:${RESET}`);
|
||||
lines.push(` ${CYAN}[query]${RESET} Search query for finding skills`);
|
||||
lines.push("");
|
||||
|
||||
lines.push(`${BOLD}Search Options:${RESET}`);
|
||||
lines.push(` ${CYAN}-n, --limit <n>${RESET} Max results (default: "20")`);
|
||||
lines.push("");
|
||||
|
||||
lines.push(`${BOLD}Sorting Options:${RESET}`);
|
||||
lines.push(` ${CYAN}-s, --sort <sort>${RESET} Sort by: hot, newest, downloads, stars, rating`);
|
||||
lines.push(` ${CYAN}--hot${RESET} Sort by comprehensive popularity (downloads + stars)`);
|
||||
lines.push(` ${CYAN}--newest${RESET} Sort by newest first`);
|
||||
lines.push(` ${CYAN}--downloads${RESET} Sort by download count`);
|
||||
lines.push(` ${CYAN}--stars${RESET} Sort by star count`);
|
||||
lines.push(` ${CYAN}--rating${RESET} Sort by average rating`);
|
||||
lines.push("");
|
||||
|
||||
lines.push(`${BOLD}Other Options:${RESET}`);
|
||||
lines.push(` ${CYAN}-h, --help${RESET} Display help for command`);
|
||||
lines.push("");
|
||||
|
||||
lines.push(`${BOLD}Examples:${RESET}`);
|
||||
lines.push(`${DIM} skillhub explore Interactive skill search${RESET}`);
|
||||
lines.push(`${DIM} skillhub explore --hot Browse popular skills${RESET}`);
|
||||
lines.push(`${DIM} skillhub explore ai-assistant Search for skills${RESET}`);
|
||||
lines.push(`${DIM} skillhub explore --sort newest --limit 10 Show 10 newest skills${RESET}`);
|
||||
|
||||
return lines.join("\n");
|
||||
}
|
||||
|
||||
export function registerExplore(program: Command) {
|
||||
program
|
||||
const exploreCmd = program
|
||||
.command("explore")
|
||||
.aliases(["find", "find-skills", "search"])
|
||||
.description("Browse or search skills from the registry")
|
||||
.argument("[query]", "Search query for finding skills")
|
||||
.option("-n, --limit <n>", "Max results", "20")
|
||||
.option("-s, --sort <sort>", "Sort by: hot, newest, downloads, stars, rating (default: interactive mode)")
|
||||
.option("-s, --sort <sort>", "Sort by: hot, newest, downloads, stars, rating (browse mode)")
|
||||
.option("--hot", "Sort by comprehensive popularity (downloads + stars)")
|
||||
.option("--newest", "Sort by newest first (shorthand for --sort newest)")
|
||||
.option("--downloads", "Sort by download count (shorthand for --sort downloads)")
|
||||
.option("--stars", "Sort by star count (shorthand for --sort stars)")
|
||||
.option("--rating", "Sort by average rating (shorthand for --sort rating)")
|
||||
.action(async (query: string | undefined, opts: { limit: string; sort?: string; hot?: boolean; newest?: boolean; downloads?: boolean; stars?: boolean; rating?: boolean }) => {
|
||||
.option("--rating", "Sort by average rating (shorthand for --sort rating)");
|
||||
|
||||
exploreCmd.helpInformation = () => buildExploreHelp(exploreCmd);
|
||||
|
||||
exploreCmd.action(async (query: string | undefined, opts: { limit: string; sort?: string; hot?: boolean; newest?: boolean; downloads?: boolean; stars?: boolean; rating?: boolean }) => {
|
||||
const config = loadConfigFromProgram(program);
|
||||
const token = await readToken();
|
||||
const client = new ApiClient({ baseUrl: config.registry, token: token || undefined });
|
||||
|
|
|
|||
|
|
@ -7,8 +7,9 @@ import { parseSkillName } from "../core/skill-name.js";
|
|||
|
||||
export function registerHide(program: Command) {
|
||||
const hideCmd = program
|
||||
.command("hide <slug>")
|
||||
.command("hide")
|
||||
.description("Hide a skill (admin only)")
|
||||
.argument("<skill>", "Skill name or namespace/skill-name")
|
||||
.option("-y, --yes", "Skip confirmation")
|
||||
.action(async (slug: string, opts: { yes?: boolean }) => {
|
||||
const { namespace, slug: skillSlug } = parseSkillName(slug);
|
||||
|
|
@ -47,8 +48,9 @@ export function registerHide(program: Command) {
|
|||
});
|
||||
|
||||
hideCmd
|
||||
.command("unhide <slug>")
|
||||
.command("unhide")
|
||||
.description("Unhide a skill (admin only)")
|
||||
.argument("<skill>", "Skill name or namespace/skill-name")
|
||||
.option("-y, --yes", "Skip confirmation")
|
||||
.action(async (slug: string, opts: { yes?: boolean }) => {
|
||||
const { namespace, slug: skillSlug } = parseSkillName(slug);
|
||||
|
|
|
|||
|
|
@ -137,12 +137,13 @@ function printInspectHeader(detail: SkillDetailResponse, versions?: SkillVersion
|
|||
|
||||
export function registerInspect(program: Command) {
|
||||
program
|
||||
.command("inspect <slug>")
|
||||
.aliases(["info", "view"])
|
||||
.command("inspect")
|
||||
.description("View skill metadata without installing")
|
||||
.argument("<skill>", "Skill name or namespace/skill-name")
|
||||
.option("--namespace <ns>", "Search in specific namespace (searches all if not specified)")
|
||||
.option("--details", "Show all versions with tags")
|
||||
.action(async (slug: string, opts: { namespace?: string; details?: boolean }) => {
|
||||
.option("-v, --version <ver>", "Inspect specific version")
|
||||
.action(async (slug: string, opts: { namespace?: string; details?: boolean; version?: string }) => {
|
||||
const config = loadConfigFromProgram(program);
|
||||
const token = await readToken();
|
||||
const client = new ApiClient({ baseUrl: config.registry, token: token || undefined });
|
||||
|
|
@ -152,7 +153,6 @@ export function registerInspect(program: Command) {
|
|||
const targetNamespace = opts.namespace || defaultNs;
|
||||
|
||||
async function fetchVersionsAndTags(ns: string, skillSlug: string) {
|
||||
if (!opts.details) return { versions: undefined, tags: undefined };
|
||||
try {
|
||||
const [versionsResp, tagsResp] = await Promise.all([
|
||||
client.get<VersionsResponse>(`/api/v1/skills/${ns}/${skillSlug}/versions`),
|
||||
|
|
@ -164,21 +164,91 @@ export function registerInspect(program: Command) {
|
|||
}
|
||||
}
|
||||
|
||||
async function displaySkillDetail(ns: string, skillSlug: string) {
|
||||
const detail = await client.get<SkillDetailResponse>(
|
||||
`${ApiRoutes.skillDetail.replace("{namespace}", ns).replace("{slug}", skillSlug)}`
|
||||
);
|
||||
const { versions, tags } = await fetchVersionsAndTags(ns, skillSlug);
|
||||
if (isJson) {
|
||||
const output = opts.details ? { ...detail, versions, tags } : detail;
|
||||
console.log(JSON.stringify(output, null, 2));
|
||||
} else {
|
||||
printSkillDetail(detail, versions, tags);
|
||||
async function displaySkillDetail(ns: string, skillSlug: string, version?: string) {
|
||||
try {
|
||||
const detail = await client.get<SkillDetailResponse>(
|
||||
`${ApiRoutes.skillDetail.replace("{namespace}", ns).replace("{slug}", skillSlug)}`
|
||||
);
|
||||
|
||||
const { versions, tags } = await fetchVersionsAndTags(ns, skillSlug);
|
||||
|
||||
if (version && versions) {
|
||||
const selectedVersion = versions.find(v => v.version === version);
|
||||
if (selectedVersion) {
|
||||
detail.publishedVersion = { version: selectedVersion.version };
|
||||
}
|
||||
}
|
||||
|
||||
if (isJson) {
|
||||
const output = opts.details ? { ...detail, versions, tags } : detail;
|
||||
console.log(JSON.stringify(output, null, 2));
|
||||
} else {
|
||||
printSkillDetail(detail, opts.details ? versions : undefined, opts.details ? tags : undefined);
|
||||
}
|
||||
} catch (e: any) {
|
||||
if (e.statusCode === 403) {
|
||||
error(`Access denied: ${ns}/${skillSlug}`);
|
||||
dim("Run 'skillhub login' to authenticate.");
|
||||
} else if (e.statusCode === 404) {
|
||||
error(`Skill not found: ${ns}/${skillSlug}`);
|
||||
} else {
|
||||
error(`Failed to fetch skill details: ${e.message}`);
|
||||
}
|
||||
process.exitCode = 1;
|
||||
}
|
||||
}
|
||||
|
||||
async function inspectWithVersionSelection(ns: string, skillSlug: string) {
|
||||
const { versions, tags } = await fetchVersionsAndTags(ns, skillSlug);
|
||||
|
||||
if (!versions || versions.length === 0) {
|
||||
await displaySkillDetail(ns, skillSlug);
|
||||
return;
|
||||
}
|
||||
|
||||
if (opts.details) {
|
||||
await displaySkillDetail(ns, skillSlug);
|
||||
return;
|
||||
}
|
||||
|
||||
if (versions.length === 1) {
|
||||
await displaySkillDetail(ns, skillSlug);
|
||||
return;
|
||||
}
|
||||
|
||||
const versionTagsMap = new Map<number, string[]>();
|
||||
if (tags) {
|
||||
for (const tag of tags) {
|
||||
if (!versionTagsMap.has(tag.versionId)) {
|
||||
versionTagsMap.set(tag.versionId, []);
|
||||
}
|
||||
versionTagsMap.get(tag.versionId)!.push(tag.tagName);
|
||||
}
|
||||
}
|
||||
|
||||
const selected = await p.select({
|
||||
message: "Select version to inspect",
|
||||
options: versions.map((v) => ({
|
||||
value: v.version,
|
||||
label: `v${v.version}`,
|
||||
hint: versionTagsMap.get(v.id)?.join(", ") || "",
|
||||
})),
|
||||
});
|
||||
|
||||
if (p.isCancel(selected)) {
|
||||
console.log("Cancelled.");
|
||||
return;
|
||||
}
|
||||
|
||||
await displaySkillDetail(ns, skillSlug, selected as string);
|
||||
}
|
||||
|
||||
if (targetNamespace) {
|
||||
await displaySkillDetail(targetNamespace, parsedSlug);
|
||||
if (opts.version) {
|
||||
await displaySkillDetail(targetNamespace, parsedSlug, opts.version);
|
||||
} else {
|
||||
await inspectWithVersionSelection(targetNamespace, parsedSlug);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -207,7 +277,11 @@ export function registerInspect(program: Command) {
|
|||
spinner.stop();
|
||||
const ns = uniqueResults[0].namespace;
|
||||
const name = uniqueResults[0].name;
|
||||
await displaySkillDetail(ns, name);
|
||||
if (opts.version) {
|
||||
await displaySkillDetail(ns, name, opts.version);
|
||||
} else {
|
||||
await inspectWithVersionSelection(ns, name);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -228,7 +302,11 @@ export function registerInspect(program: Command) {
|
|||
}
|
||||
|
||||
const [selectedNs, selectedName] = (selected as string).split("/", 2);
|
||||
await displaySkillDetail(selectedNs, selectedName);
|
||||
if (opts.version) {
|
||||
await displaySkillDetail(selectedNs, selectedName, opts.version);
|
||||
} else {
|
||||
await inspectWithVersionSelection(selectedNs, selectedName);
|
||||
}
|
||||
} catch (e: any) {
|
||||
spinner.fail(e.message);
|
||||
process.exitCode = 1;
|
||||
|
|
|
|||
|
|
@ -200,13 +200,13 @@ function buildAgentSummary(targetAgents: AgentInfo[], mode: "symlink" | "copy",
|
|||
function buildInstallHelp(cmd: Command): string {
|
||||
const lines: string[] = [];
|
||||
|
||||
lines.push(`${chalk.bold("Usage:")} skillhub install|i [options] ${chalk.cyan("<skill-name>")}`);
|
||||
lines.push(`${chalk.bold("Usage:")} skillhub install [options] ${chalk.cyan("<skill>")}`);
|
||||
lines.push("");
|
||||
lines.push("Install skills from registry, git repositories, or local paths");
|
||||
lines.push("");
|
||||
|
||||
lines.push(chalk.bold("Arguments:"));
|
||||
lines.push(` ${chalk.cyan("skill-name")} Skill name or namespace/skill-name from registry`);
|
||||
lines.push(` ${chalk.cyan("skill")} Skill name or namespace/skill-name from registry`);
|
||||
lines.push("");
|
||||
|
||||
lines.push(chalk.bold("Source Options:"));
|
||||
|
|
@ -246,9 +246,10 @@ function buildInstallHelp(cmd: Command): string {
|
|||
|
||||
export function registerInstall(program: Command) {
|
||||
const installCmd = program
|
||||
.command("install <skill-name>")
|
||||
.command("install")
|
||||
.alias("i")
|
||||
.description("Install skills from registry, git repositories, or local paths")
|
||||
.argument("<skill>", "Skill name or namespace/skill-name from registry")
|
||||
.option("-a, --add <source>", "Install from GitHub or local path (alias for --from)")
|
||||
.option("--from <source>", "Install from GitHub or local path (alias for -a)")
|
||||
.option("--agent <agents...>", "Target specific agents")
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ interface ListOptions {
|
|||
export function registerList(program: Command) {
|
||||
program
|
||||
.command("list")
|
||||
.alias("ls")
|
||||
.description("List installed skills")
|
||||
.option("-g, --global", "List global skills only")
|
||||
.option("-p, --project", "List project skills only")
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@ export function registerMe(program: Command) {
|
|||
|
||||
me
|
||||
.command("skills")
|
||||
.alias("ls")
|
||||
.description("List your published skills")
|
||||
.action(async () => {
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -15,12 +15,10 @@ export interface Notification {
|
|||
export function registerNotifications(program: Command) {
|
||||
const cmd = program
|
||||
.command("notifications")
|
||||
.alias("notif")
|
||||
.description("Manage notifications");
|
||||
|
||||
cmd
|
||||
.command("list")
|
||||
.alias("ls")
|
||||
.description("List notifications")
|
||||
.option("--unread", "Show unread only")
|
||||
.action(async (opts: { unread?: boolean }) => {
|
||||
|
|
|
|||
|
|
@ -7,8 +7,9 @@ import { parseSkillName } from "../core/skill-name.js";
|
|||
|
||||
export function registerRating(program: Command) {
|
||||
program
|
||||
.command("rating <slug>")
|
||||
.command("rating")
|
||||
.description("View your rating for a skill")
|
||||
.argument("<skill>", "Skill name or namespace/skill-name")
|
||||
.action(async (slug: string) => {
|
||||
try {
|
||||
const { namespace, slug: skillSlug } = parseSkillName(slug);
|
||||
|
|
@ -28,7 +29,7 @@ export function registerRating(program: Command) {
|
|||
info(`${skillSlug}: ${"★".repeat(rating.score)}${"☆".repeat(5 - rating.score)} (${rating.score}/5)`);
|
||||
} else {
|
||||
info(`${skillSlug}: Not rated yet`);
|
||||
dim("Use: skillhub rate <slug> <score>");
|
||||
dim("Use: skillhub rate <skill> <score>");
|
||||
}
|
||||
} catch (e: any) {
|
||||
error(`Failed: ${e.message}`);
|
||||
|
|
@ -39,8 +40,10 @@ export function registerRating(program: Command) {
|
|||
|
||||
export function registerRate(program: Command) {
|
||||
program
|
||||
.command("rate <slug> <score>")
|
||||
.command("rate")
|
||||
.description("Rate a skill (1-5)")
|
||||
.argument("<skill>", "Skill name or namespace/skill-name")
|
||||
.argument("<score>", "Rating score (1-5)")
|
||||
.action(async (slug: string, scoreStr: string) => {
|
||||
const score = parseInt(scoreStr, 10);
|
||||
if (isNaN(score) || score < 1 || score > 5) {
|
||||
|
|
|
|||
|
|
@ -8,8 +8,9 @@ import { parseSkillName } from "../core/skill-name.js";
|
|||
|
||||
export function registerReport(program: Command) {
|
||||
program
|
||||
.command("report <slug>")
|
||||
.command("report")
|
||||
.description("Report a skill for review")
|
||||
.argument("<skill>", "Skill name or namespace/skill-name")
|
||||
.option("--reason <reason>", "Report reason")
|
||||
.action(async (slug: string, opts: { reason?: string }) => {
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -43,8 +43,9 @@ async function resolveWithVersion(
|
|||
|
||||
export function registerResolve(program: Command) {
|
||||
program
|
||||
.command("resolve <slug>")
|
||||
.command("resolve")
|
||||
.description("Resolve the latest version of a skill")
|
||||
.argument("<skill>", "Skill name or namespace/skill-name")
|
||||
.option("-v, --skill-version <ver>", "Specific version")
|
||||
.option("--tag <tag>", "Tag to resolve (default: latest, ignored if --skill-version)")
|
||||
.option("--hash <hash>", "Content hash")
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ export function registerReviews(program: Command) {
|
|||
|
||||
reviews
|
||||
.command("my")
|
||||
.alias("submissions")
|
||||
.description("List your review submissions")
|
||||
.action(async () => {
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -8,8 +8,9 @@ import { parseSkillName } from "../core/skill-name.js";
|
|||
|
||||
export function registerStar(program: Command) {
|
||||
program
|
||||
.command("star <slug>")
|
||||
.command("star")
|
||||
.description("Star a skill")
|
||||
.argument("<skill>", "Skill name or namespace/skill-name")
|
||||
.option("--unstar", "Remove star")
|
||||
.action(async (slug: string, opts: { unstar: boolean }) => {
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -110,8 +110,7 @@ function findAgentsWithSkill(skillName: string, scope: "global" | "local", agent
|
|||
|
||||
export function registerUninstall(program: Command) {
|
||||
program
|
||||
.command("uninstall [name]")
|
||||
.alias("un")
|
||||
.command("uninstall [skill]")
|
||||
.description("Uninstall a skill or all skills from local agent")
|
||||
.option("-g, --global", "Uninstall from global scope")
|
||||
.option("-a, --agent <agents...>", "Uninstall from specific agents")
|
||||
|
|
|
|||
|
|
@ -12,8 +12,7 @@ function getCliCommand(): string {
|
|||
|
||||
export function registerUpdate(program: Command) {
|
||||
program
|
||||
.command("update [slug]")
|
||||
.alias("up")
|
||||
.command("update [skill]")
|
||||
.description("Update installed skills from their source")
|
||||
.option("-a, --all", "Update all installed skills")
|
||||
.option("-g, --global", "Update global scope skills")
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue