import { defineCommand } from "citty"; import consola from "consola"; import { input } from "@inquirer/prompts"; import postgres from "postgres"; import { drizzle } from "drizzle-orm/postgres-js"; import * as schema from "@atbb/db"; import { ForumAgent } from "@atbb/atproto"; import { loadCliConfig } from "../lib/config.js"; import { checkEnvironment } from "../lib/preflight.js"; import { createCategory } from "../lib/steps/create-category.js"; import { isProgrammingError } from "../lib/errors.js"; import { logger } from "../lib/logger.js"; const categoryAddCommand = defineCommand({ meta: { name: "add", description: "Add a new category to the forum", }, args: { name: { type: "string", description: "Category name", }, description: { type: "string", description: "Category description (optional)", }, slug: { type: "string", description: "URL-friendly identifier (auto-derived from name if omitted)", }, "sort-order": { type: "string", description: "Numeric sort position — lower values appear first", }, }, async run({ args }) { consola.box("atBB — Add Category"); const config = loadCliConfig(); const envCheck = checkEnvironment(config); if (!envCheck.ok) { consola.error("Missing required environment variables:"); for (const name of envCheck.errors) { consola.error(` - ${name}`); } consola.info("Set these in your .env file or environment, then re-run."); process.exit(1); } const sql = postgres(config.databaseUrl); const db = drizzle(sql, { schema }); async function cleanup() { await sql.end(); } try { await sql`SELECT 1`; consola.success("Database connection successful"); } catch (error) { consola.error( "Failed to connect to database:", error instanceof Error ? error.message : String(error) ); await cleanup(); process.exit(1); } consola.start("Authenticating as Forum DID..."); const forumAgent = new ForumAgent( config.pdsUrl, config.forumHandle, config.forumPassword, logger ); try { await forumAgent.initialize(); } catch (error) { consola.error( "Failed to reach PDS during authentication:", error instanceof Error ? error.message : String(error) ); try { await forumAgent.shutdown(); } catch {} await cleanup(); process.exit(1); } if (!forumAgent.isAuthenticated()) { const status = forumAgent.getStatus(); consola.error(`Failed to authenticate: ${status.error}`); await forumAgent.shutdown(); await cleanup(); process.exit(1); } const agent = forumAgent.getAgent()!; consola.success(`Authenticated as ${config.forumHandle}`); const name = args.name ?? (await input({ message: "Category name:", default: "General" })); const description = args.description ?? (await input({ message: "Category description (optional):" })); const sortOrderRaw = args["sort-order"]; const sortOrder = sortOrderRaw !== undefined ? parseInt(sortOrderRaw, 10) : undefined; try { const result = await createCategory(db, agent, config.forumDid, { name, ...(description && { description }), ...(args.slug && { slug: args.slug }), ...(sortOrder !== undefined && !isNaN(sortOrder) && { sortOrder }), }); if (result.skipped) { consola.warn(`Category "${result.existingName}" already exists: ${result.uri}`); } else { consola.success(`Created category "${name}"`); consola.info(`URI: ${result.uri}`); } } catch (error) { if (isProgrammingError(error)) throw error; consola.error( "Failed to create category:", JSON.stringify({ name, forumDid: config.forumDid, error: error instanceof Error ? error.message : String(error), }) ); await forumAgent.shutdown(); await cleanup(); process.exit(1); } await forumAgent.shutdown(); await cleanup(); }, }); export const categoryCommand = defineCommand({ meta: { name: "category", description: "Manage forum categories", }, subCommands: { add: categoryAddCommand, }, });