#!/usr/bin/env node // ghoststandard CLI — entry point + subcommand dispatch. import pc from 'picocolors'; import { runSetup } from './commands/setup.js'; import { runSync } from './commands/sync.js'; import { runUnsync } from './commands/unsync.js'; import { runBackfill } from './commands/backfill.js'; import { runStatus } from './commands/status.js'; import { runSetIcon } from './commands/set-icon.js'; import { runSetTheme } from './commands/set-theme.js'; import { runConfig } from './commands/config.js'; import { runLogs } from './commands/logs.js'; import { runWebhooksInstall } from './commands/webhooks.js'; import { runSiteAdd, runSiteList, runSiteRm, runSiteShow, } from './commands/site.js'; function printHelp(): void { const cmd = pc.cyan; const arg = pc.dim; console.log(` ${pc.bold('gs')} ${pc.dim('— ghoststandard CLI — Ghost → Standard.site bridge')} ${pc.bold('Setup:')} ${cmd('setup')} First-run interactive setup (one site) ${cmd('site add')} Add another Ghost↔PDS site ${cmd('site list')} Show all configured sites ${cmd('site show')} ${arg('')} Per-site detail ${cmd('site rm')} ${arg('')} Remove a site ${pc.bold('Operate:')} ${pc.dim('(commands take an optional first arg; defaults to the only site)')} ${cmd('sync')} ${arg('[] ')} Manually sync one post ${cmd('unsync')} ${arg('[] ')} Delete one PDS record + mapping ${cmd('backfill')} ${arg('[]')} Re-sync every published post ${cmd('set-icon')} ${arg('[] ')} Replace the publication icon ${cmd('set-theme')} ${arg('[] [preset]')} Change the theme palette ${arg('(preset: skip, light, dark)')} ${cmd('webhooks')} ${arg('[]')} (Re-)install the four Ghost webhooks ${pc.bold('Inspect:')} ${cmd('status')} ${arg('[]')} Health / counts (per-site or summary) ${cmd('config')} ${arg('[]')} Print stored config (secrets masked) ${cmd('logs')} Tail webhook delivery log ${pc.dim('Run inside the container:')} ${pc.dim('docker compose exec app gs ')} ${pc.dim('(or `ghoststandard ` — same binary, longer alias if `gs` collides)')} `); } async function main(): Promise { const [, , command, ...rest] = process.argv; switch (command) { case undefined: case 'help': case '--help': case '-h': printHelp(); return; case 'setup': await runSetup(); return; case 'site': { const sub = rest[0]; switch (sub) { case 'list': await runSiteList(); return; case 'add': await runSiteAdd(); return; case 'show': { const slug = rest[1]; if (!slug) { console.error(pc.red('error: ') + 'site show requires a slug'); process.exit(2); } await runSiteShow(slug); return; } case 'rm': { const slug = rest[1]; if (!slug) { console.error(pc.red('error: ') + 'site rm requires a slug'); process.exit(2); } await runSiteRm(slug); return; } default: console.error(pc.red('error: ') + `unknown site subcommand: ${pc.bold(sub ?? '(none)')}`); console.error(pc.dim(' known: list, add, show, rm')); process.exit(2); } } case 'sync': await runSync(rest); return; case 'unsync': await runUnsync(rest); return; case 'backfill': await runBackfill(rest); return; case 'status': await runStatus(rest); return; case 'config': await runConfig(rest); return; case 'logs': await runLogs(); return; case 'set-icon': await runSetIcon(rest); return; case 'set-theme': await runSetTheme(rest); return; case 'webhooks': await runWebhooksInstall(rest); return; default: console.error(pc.red('error: ') + `unknown command ${pc.bold(command)}`); printHelp(); process.exit(2); } } main().catch((err: unknown) => { const msg = err instanceof Error ? err.message : String(err); console.error(pc.red('\nfailed: ') + msg); if (process.env.GS_DEBUG && err instanceof Error && err.stack) { console.error(pc.dim(err.stack)); } process.exit(1); });