export.ts 1.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445
  1. import { Command } from "commander";
  2. import { StateManager, writeExportArtifact } from "@actalk/inkos-core";
  3. import { join } from "node:path";
  4. import { findProjectRoot, resolveBookId, log, logError } from "../utils.js";
  5. export const exportCommand = new Command("export")
  6. .description("Export book chapters to a single file")
  7. .argument("[book-id]", "Book ID (auto-detected if only one book)")
  8. .option("--format <format>", "Output format (txt, md, epub)", "txt")
  9. .option("--output <path>", "Output file path")
  10. .option("--approved-only", "Only export approved chapters")
  11. .option("--json", "Output JSON metadata")
  12. .action(async (bookIdArg: string | undefined, opts) => {
  13. try {
  14. const root = findProjectRoot();
  15. const bookId = await resolveBookId(bookIdArg, root);
  16. const state = new StateManager(root);
  17. const result = await writeExportArtifact(state, bookId, {
  18. format: opts.format as "txt" | "md" | "epub",
  19. approvedOnly: Boolean(opts.approvedOnly),
  20. outputPath: opts.output ?? join(root, `${bookId}_export.${opts.format}`),
  21. });
  22. if (opts.json) {
  23. log(JSON.stringify({
  24. bookId,
  25. chaptersExported: result.chaptersExported,
  26. totalWords: result.totalWords,
  27. format: result.format,
  28. outputPath: result.outputPath,
  29. }, null, 2));
  30. } else {
  31. log(`Exported ${result.chaptersExported} chapters (${result.totalWords} words)`);
  32. log(`Output: ${result.outputPath}`);
  33. }
  34. } catch (e) {
  35. if (opts.json) {
  36. log(JSON.stringify({ error: String(e) }));
  37. } else {
  38. logError(`Failed to export: ${e}`);
  39. }
  40. process.exit(1);
  41. }
  42. });