feat(cli): custom grouped help page with aliases and examples

This commit is contained in:
chenbaowang 2026-04-16 23:26:41 +08:00
parent ed21388c30
commit 5cf44c5a98
2 changed files with 115 additions and 1 deletions

View file

@ -1,6 +1,6 @@
{
"name": "motovis-skillhub",
"version": "1.0.6",
"version": "1.0.7",
"type": "module",
"description": "SkillHub CLI - 企业级 Agent Skill 管理工具,支持命名空间",
"bin": {

View file

@ -8,6 +8,11 @@ import { dirname } from "node:path";
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
// ANSI helpers (zero-dependency)
const bold = (s: string) => `\x1b[1m${s}\x1b[0m`;
const dim = (s: string) => `\x1b[2m${s}\x1b[0m`;
const cyan = (s: string) => `\x1b[36m${s}\x1b[0m`;
function getPackageVersion(): string {
try {
const pkgPath = resolve(__dirname, "../package.json");
@ -18,6 +23,108 @@ function getPackageVersion(): string {
}
}
interface HelpEntry {
cmd: string;
desc: string;
alias?: string;
}
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}`);
}
return lines.join("\n");
}
function buildTopLevelHelp(version: string): string {
const sections: string[] = [];
sections.push(`${bold("skillhub")} ${dim(`v${version}`)}`);
sections.push(dim("CLI for SkillHub — publish, search, and manage agent skills"));
sections.push("");
sections.push(formatSection("Auth", [
{ cmd: "login", desc: "Authenticate with SkillHub registry" },
{ cmd: "logout", desc: "Remove stored authentication token" },
{ cmd: "whoami", desc: "Show current authenticated user" },
]));
sections.push("");
sections.push(formatSection("Discover", [
{ cmd: "explore", desc: "Browse or search skills from the registry", alias: "find, find-skills, search" },
{ cmd: "search <query>", desc: dim("[Deprecated: use 'explore' instead]") },
]));
sections.push("");
sections.push(formatSection("Install & Manage", [
{ cmd: "install <source>", 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: "list", desc: "List installed skills", alias: "ls" },
{ cmd: "check", desc: "Check installed skills against lock file" },
]));
sections.push("");
sections.push(formatSection("Publish", [
{ 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: "versions <slug>", desc: "List skill versions" },
]));
sections.push("");
sections.push(formatSection("Info & Review", [
{ cmd: "inspect <slug>", desc: "View skill metadata without installing", alias: "info, view" },
{ cmd: "resolve <slug>", desc: "Resolve the latest version of a skill" },
{ cmd: "rating <slug>", desc: "View your rating for a skill" },
{ cmd: "rate <slug> <score>", desc: "Rate a skill (1-5)" },
{ cmd: "star <slug>", desc: "Star a skill" },
{ cmd: "report <slug>", desc: "Report a skill for review" },
]));
sections.push("");
sections.push(formatSection("Account", [
{ cmd: "me skills", desc: "List your published skills", alias: "me ls" },
{ cmd: "me stars", desc: "List your starred skills" },
{ cmd: "namespaces", desc: "List namespaces you have access to" },
{ cmd: "notifications", desc: "Manage notifications", alias: "notif" },
{ cmd: "reviews my", desc: "List your review submissions", alias: "reviews submissions" },
]));
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: "transfer <ns> <user>", desc: "Transfer namespace ownership" },
]));
sections.push("");
sections.push(bold("Examples"));
sections.push(dim(" skillhub install vision2group/fork-workflow Install a skill"));
sections.push(dim(" skillhub explore Browse available skills"));
sections.push(dim(" skillhub publish Publish current directory"));
sections.push(dim(" skillhub me skills List your published skills"));
sections.push(dim(" skillhub update --global Update all global skills"));
sections.push("");
sections.push(bold("Global Options"));
sections.push(` ${cyan("--registry <url>")} Registry API base URL`);
sections.push(` ${cyan("--json")} Output results as JSON`);
sections.push(` ${cyan("--help")} Show help for a command`);
sections.push(` ${cyan("--version")} Show version number`);
return sections.join("\n");
}
export async function createCli(): Promise<Command> {
const program = new Command();
const version = getPackageVersion();
@ -29,6 +136,13 @@ export async function createCli(): Promise<Command> {
.option("--registry <url>", "Registry API base URL", "http://localhost:8080")
.option("--json", "Output results as JSON");
const customHelp = buildTopLevelHelp(version);
const originalHelpInformation = program.helpInformation.bind(program);
program.helpInformation = () => {
if (program.parent) return originalHelpInformation();
return customHelp;
};
const [
{ registerLogin },
{ registerLogout },