import chalk from "chalk"; import { define } from "gunshi"; import { articleUrl } from "@/crawlers/fc2"; import { openDb } from "@/db"; import * as worksQ from "@/db/queries/works"; import { formatDate, parseRangeBounds } from "@/utils/dates"; import { ExitCodes, exitWith, wrap } from "../envelope"; import { enterJsonMode, isJsonMode, printHuman, printJson } from "../output"; export const listCommand = define({ name: "list", description: "List an author's works (optionally filtered by date range)", args: { author: { type: "string", short: "a", required: true, description: "FC2 author slug" }, since: { type: "string", description: "Lower bound (YYYY-MM-DD, ISO, or ms)" }, until: { type: "string", description: "Upper bound (YYYY-MM-DD, ISO, or ms)" }, db: { type: "string", description: "SQLite DB path (default: ~/.fc2cma/db.sqlite or $FC2CMA_DB)" }, json: { type: "boolean", description: "Emit machine-readable JSON envelope on stdout" } }, run(ctx) { const args = ctx.values; enterJsonMode(Boolean(args.json)); const bounds = (() => { try { return parseRangeBounds(args.since, args.until); } catch (err) { const msg = err instanceof Error ? err.message : String(err); exitWith(ExitCodes.USAGE, `list: ${msg}`); } })(); const db = openDb(args.db); const works = worksQ.listWorks(db, { author: args.author, sinceMs: bounds.sinceMs, untilMs: bounds.untilMs }); const payload = { author: args.author, sinceMs: bounds.sinceMs ?? null, untilMs: bounds.untilMs ?? null, works: works.map((w) => ({ ...w, url: articleUrl(w.id) })) }; if (isJsonMode()) { printJson(wrap("list", payload)); } else { if (works.length === 0) { printHuman(chalk.dim(`(no works for ${args.author})`)); } else { printHuman(chalk.bold(`${args.author}: ${works.length} work(s)`)); for (const w of works) { const when = w.publishedAt ?? w.firstSeenAt; const whenIso = formatDate(when); const price = w.latestPriceYen != null ? `¥${w.latestPriceYen}${w.latestOnPromo ? "*" : ""}` : "—"; printHuman( ` ${chalk.dim(whenIso)} ${chalk.cyan(w.id)} ${price.padStart(8)} ${w.title}` ); } } } db.close(); } });