import { existsSync, readFileSync } from "fs"; import { resolve } from "path"; import chalk from "chalk"; import { validateSkillContent } from "../lib/validate-skill.js"; import { publishSkill } from "../lib/registry-client.js"; import { getRegistryUrl } from "../lib/config.js"; export async function publishCommand( filePath: string, options: { dryRun?: boolean } ): Promise { const absPath = resolve(filePath); if (!existsSync(absPath)) { console.error(chalk.red(`Error: File not found: ${absPath}`)); process.exit(1); } const content = readFileSync(absPath, "utf-8"); // Step 1 — Validate console.log(chalk.bold("Validating skill.md...")); const validation = validateSkillContent(content); for (const w of validation.warnings) { console.log(chalk.yellow(`⚠ ${w}`)); } if (!validation.valid) { for (const e of validation.errors) { console.log(chalk.red(`✗ ${e}`)); } console.log(chalk.red("\nValidation failed. Publish aborted.")); process.exit(1); } console.log(chalk.green("✓ Validation passed")); // Step 2 — Check references resolve const fm = validation.frontmatter!; if (fm.references && fm.references.length > 0) { console.log(chalk.bold(`\nChecking ${fm.references.length} reference(s)...`)); for (const ref of fm.references) { process.stdout.write(` ${ref.url} ... `); try { const resp = await fetch(ref.url, { method: "HEAD" }); if (resp.ok) { process.stdout.write(chalk.green("OK\n")); } else { process.stdout.write(chalk.red(`FAIL (HTTP ${resp.status})\n`)); console.error( chalk.red( `\nReference URL returned ${resp.status}: ${ref.url}\nPublish aborted.` ) ); process.exit(1); } } catch (err) { process.stdout.write(chalk.red(`FAIL (${err})\n`)); console.error( chalk.red(`\nCould not reach reference URL: ${ref.url}\nPublish aborted.`) ); process.exit(1); } } } if (options.dryRun) { console.log(chalk.cyan("\nDry-run mode — skipping upload.")); console.log( ` Would publish: ${chalk.bold(fm.name)}@${fm.version} to ${getRegistryUrl()}` ); return; } // Step 3 — Upload console.log(chalk.bold(`\nPublishing ${chalk.cyan(fm.name)}@${fm.version}...`)); const result = await publishSkill(content); console.log(chalk.green(`\n✓ ${result.message}`)); console.log(` URL: ${chalk.cyan(result.url)}`); console.log(` Pinned URL: ${chalk.dim(result.pinnedUrl)}`); }