#!/usr/bin/env node import { Command } from "commander"; import chalk from "chalk"; import { loginCommand } from "./commands/login.js"; import { validateCommand } from "./commands/validate.js"; import { publishCommand } from "./commands/publish.js"; import { previewCommand } from "./commands/preview.js"; import { versionsCommand } from "./commands/versions.js"; const program = new Command(); program .name("paperclip-skills") .description("CLI for publishing and managing Paperclip skills") .version("2.1.1"); // ─── login ───────────────────────────────────────────────────────────────── program .command("login") .description("Save your publish credential for publishing skills") .option( "-c, --credential ", "Publish credential (psk_ns_*) — prompted if omitted" ) .option( "--registry-url ", "Override registry URL (default: https://www.paperclipskills.com)" ) .action(async (opts) => { await loginCommand({ credential: opts.credential, registryUrl: opts.registryUrl, }); }); // ─── validate ────────────────────────────────────────────────────────────── program .command("validate [file]") .description("Validate a skill.md file without uploading") .option("-q, --quiet", "Only print errors (no metadata display)") .action(async (file: string | undefined, opts) => { const filePath = file ?? "skill.md"; const { valid } = await validateCommand(filePath, { quiet: opts.quiet }); process.exit(valid ? 0 : 1); }); // ─── publish ─────────────────────────────────────────────────────────────── program .command("publish [file]") .description("Validate and upload a skill.md to the registry") .option("--dry-run", "Validate and check references but do not upload") .action(async (file: string | undefined, opts) => { const filePath = file ?? "skill.md"; await publishCommand(filePath, { dryRun: opts.dryRun }); }); // ─── preview ─────────────────────────────────────────────────────────────── program .command("preview [file]") .description("Show how a skill.md will appear on the marketplace") .action(async (file: string | undefined) => { const filePath = file ?? "skill.md"; await previewCommand(filePath); }); // ─── versions ────────────────────────────────────────────────────────────── program .command("versions ") .description("List published versions of a skill (e.g. @acme/my-skill)") .action(async (skillName: string) => { await versionsCommand(skillName); }); // ─── global error handling ───────────────────────────────────────────────── program.configureOutput({ writeErr: (str) => process.stderr.write(chalk.red(str)), }); program.parseAsync(process.argv).catch((err: Error) => { console.error(chalk.red(`\nError: ${err.message}`)); process.exit(1); });