@lexbuild/cli 1.16.1 → 1.17.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -234,10 +234,7 @@ async function convertSingleFile(inputPath, outputPath, options, spinnerLabel) {
234
234
  if (!result.dryRun) {
235
235
  rows.push(["Files Written", formatNumber(result.files.length)]);
236
236
  }
237
- rows.push(
238
- ["Peak Memory", formatBytes(result.peakMemoryBytes)],
239
- ["Duration", formatDuration(elapsed)]
240
- );
237
+ rows.push(["Peak Memory", formatBytes(result.peakMemoryBytes)], ["Duration", formatDuration(elapsed)]);
241
238
  const titleLabel = result.dryRun ? `lexbuild \u2014 Title ${result.titleNumber}: ${result.titleName} [dry-run]` : `lexbuild \u2014 Title ${result.titleNumber}: ${result.titleName}`;
242
239
  const outputRelative = relative(process.cwd(), outputPath) || outputPath;
243
240
  const output = summaryBlock({
@@ -286,9 +283,7 @@ Examples:
286
283
  ).action(async (input, options) => {
287
284
  const modeCount = [input, options.titles, options.all].filter(Boolean).length;
288
285
  if (modeCount === 0) {
289
- console.error(
290
- error("Specify an input file, --titles <spec>, or --all (e.g. --titles 1-5,8,11)")
291
- );
286
+ console.error(error("Specify an input file, --titles <spec>, or --all (e.g. --titles 1-5,8,11)"));
292
287
  process.exit(1);
293
288
  }
294
289
  if (modeCount > 1) {
@@ -364,12 +359,7 @@ Examples:
364
359
  totalTokens += result.totalTokenEstimate;
365
360
  totalElapsed += elapsed;
366
361
  if (granularity === "title") {
367
- return [
368
- result.titleNumber,
369
- result.titleName,
370
- formatNumber(result.totalTokenEstimate),
371
- formatDuration(elapsed)
372
- ];
362
+ return [result.titleNumber, result.titleName, formatNumber(result.totalTokenEstimate), formatDuration(elapsed)];
373
363
  } else if (granularity === "chapter") {
374
364
  return [
375
365
  result.titleNumber,
@@ -537,11 +527,7 @@ Source: https://uscode.house.gov/download/download.shtml`
537
527
 
538
528
  // src/commands/list-release-points.ts
539
529
  import { Command as Command3 } from "commander";
540
- import {
541
- detectLatestReleasePoint as detectLatestReleasePoint2,
542
- fetchReleasePointHistory,
543
- FALLBACK_RELEASE_POINT as FALLBACK_RELEASE_POINT2
544
- } from "@lexbuild/usc";
530
+ import { detectLatestReleasePoint as detectLatestReleasePoint2, fetchReleasePointHistory, FALLBACK_RELEASE_POINT as FALLBACK_RELEASE_POINT2 } from "@lexbuild/usc";
545
531
  var listReleasePointsCommand = new Command3("list-release-points").description("List available OLRC release points for the U.S. Code").option("-n, --limit <count>", "Maximum number of release points to show", "20").addHelpText(
546
532
  "after",
547
533
  `
@@ -560,10 +546,7 @@ Source: https://uscode.house.gov/download/priorreleasepoints.htm`
560
546
  }
561
547
  const spinner = createSpinner("Fetching release points from OLRC...");
562
548
  spinner.start();
563
- const [current, history] = await Promise.all([
564
- detectLatestReleasePoint2(),
565
- fetchReleasePointHistory()
566
- ]);
549
+ const [current, history] = await Promise.all([detectLatestReleasePoint2(), fetchReleasePointHistory()]);
567
550
  spinner.stop();
568
551
  const currentRp = current?.releasePoint ?? FALLBACK_RELEASE_POINT2;
569
552
  const currentDesc = current?.description ?? "(detection failed \u2014 showing fallback)";
@@ -648,10 +631,7 @@ async function convertSingleFile2(inputPath, outputPath, options, spinnerLabel)
648
631
  if (!result.dryRun) {
649
632
  rows.push(["Files Written", formatNumber(result.files.length)]);
650
633
  }
651
- rows.push(
652
- ["Peak Memory", formatBytes(result.peakMemoryBytes)],
653
- ["Duration", formatDuration(elapsed)]
654
- );
634
+ rows.push(["Peak Memory", formatBytes(result.peakMemoryBytes)], ["Duration", formatDuration(elapsed)]);
655
635
  const titleLabel = result.dryRun ? `lexbuild \u2014 eCFR Title ${result.titleNumber}: ${result.titleName} [dry-run]` : `lexbuild \u2014 eCFR Title ${result.titleNumber}: ${result.titleName}`;
656
636
  const outputRelative = relative3(process.cwd(), outputPath) || outputPath;
657
637
  const output = summaryBlock({
@@ -700,9 +680,7 @@ Examples:
700
680
  ).action(async (input, options) => {
701
681
  const modeCount = [input, options.titles, options.all].filter(Boolean).length;
702
682
  if (modeCount === 0) {
703
- console.error(
704
- error("Specify an input file, --titles <spec>, or --all (e.g. --titles 1-5,17)")
705
- );
683
+ console.error(error("Specify an input file, --titles <spec>, or --all (e.g. --titles 1-5,17)"));
706
684
  process.exit(1);
707
685
  }
708
686
  if (modeCount > 1) {
@@ -777,12 +755,7 @@ Examples:
777
755
  totalTokens += result.totalTokenEstimate;
778
756
  totalElapsed += elapsed;
779
757
  if (granularity === "title") {
780
- return [
781
- result.titleNumber,
782
- result.titleName,
783
- formatNumber(result.totalTokenEstimate),
784
- formatDuration(elapsed)
785
- ];
758
+ return [result.titleNumber, result.titleName, formatNumber(result.totalTokenEstimate), formatDuration(elapsed)];
786
759
  } else if (granularity === "chapter") {
787
760
  return [
788
761
  result.titleNumber,
@@ -868,11 +841,7 @@ Examples:
868
841
  import { Command as Command5 } from "commander";
869
842
  import { relative as relative4, resolve as resolve4 } from "path";
870
843
  import { downloadEcfrTitles, downloadEcfrTitlesFromApi, fetchEcfrTitlesMeta } from "@lexbuild/ecfr";
871
- var downloadEcfrCommand = new Command5("download-ecfr").description("Download eCFR XML from govinfo or eCFR API").option("-o, --output <dir>", "Download directory", "./downloads/ecfr/xml").option("--titles <spec>", "Title(s) to download: 1, 1-5, or 1-5,8,17").option("--all", "Download all 50 eCFR titles", false).option(
872
- "--source <source>",
873
- "Download source: ecfr-api (daily-updated) or govinfo (bulk data)",
874
- "ecfr-api"
875
- ).option("--date <YYYY-MM-DD>", "Point-in-time date (ecfr-api source only)").addHelpText(
844
+ var downloadEcfrCommand = new Command5("download-ecfr").description("Download eCFR XML from govinfo or eCFR API").option("-o, --output <dir>", "Download directory", "./downloads/ecfr/xml").option("--titles <spec>", "Title(s) to download: 1, 1-5, or 1-5,8,17").option("--all", "Download all 50 eCFR titles", false).option("--source <source>", "Download source: ecfr-api (daily-updated) or govinfo (bulk data)", "ecfr-api").option("--date <YYYY-MM-DD>", "Point-in-time date (ecfr-api source only)").addHelpText(
876
845
  "after",
877
846
  `
878
847
  Examples:
@@ -892,9 +861,7 @@ Sources:
892
861
  }
893
862
  const validSources = ["govinfo", "ecfr-api"];
894
863
  if (!validSources.includes(options.source)) {
895
- console.error(
896
- error(`Invalid source "${options.source}". Valid sources: ${validSources.join(", ")}`)
897
- );
864
+ console.error(error(`Invalid source "${options.source}". Valid sources: ${validSources.join(", ")}`));
898
865
  process.exit(1);
899
866
  }
900
867
  if (options.date && options.source !== "ecfr-api") {
@@ -1026,11 +993,7 @@ async function downloadFromApi(options, titles, outputDir, spinner, startTime, m
1026
993
  const uniqueDates = new Set(result.files.map((f) => f.asOfDate));
1027
994
  const dateDisplay = uniqueDates.size <= 1 ? result.asOfDate : `${result.asOfDate} (${uniqueDates.size - 1} titles at earlier dates)`;
1028
995
  const fileRows = result.files.map((file) => {
1029
- const row = [
1030
- String(file.titleNumber),
1031
- formatBytes(file.size),
1032
- relative4(outputDir, file.path) || file.path
1033
- ];
996
+ const row = [String(file.titleNumber), formatBytes(file.size), relative4(outputDir, file.path) || file.path];
1034
997
  if (file.asOfDate !== result.asOfDate) {
1035
998
  row.push(file.asOfDate);
1036
999
  }
@@ -1058,9 +1021,7 @@ async function downloadFromApi(options, titles, outputDir, spinner, startTime, m
1058
1021
  const nums = processing.map((f) => `Title ${f.titleNumber}`).join(", ");
1059
1022
  console.log(` ${error(`Unavailable (processing on server): ${nums}`)}`);
1060
1023
  console.log(` The eCFR API cannot serve these titles while an import is in progress.`);
1061
- console.log(
1062
- ` Re-run this command later to download them. Existing local files (if any) are preserved.`
1063
- );
1024
+ console.log(` Re-run this command later to download them. Existing local files (if any) are preserved.`);
1064
1025
  }
1065
1026
  if (other.length > 0) {
1066
1027
  const nums = other.map((f) => `Title ${f.titleNumber} (${f.status})`).join(", ");
@@ -1084,14 +1045,7 @@ var VALID_TYPES = /* @__PURE__ */ new Map([
1084
1045
  ["notice", "NOTICE"],
1085
1046
  ["presidential_document", "PRESDOCU"]
1086
1047
  ]);
1087
- var downloadFrCommand = new Command6("download-fr").description("Download Federal Register XML and metadata").option("-o, --output <dir>", "Download directory", "./downloads/fr").option(
1088
- "--source <source>",
1089
- "Source: fr-api (default, per-document) or govinfo (bulk daily)",
1090
- "fr-api"
1091
- ).option("--from <YYYY-MM-DD>", "Start date (inclusive)").option("--to <YYYY-MM-DD>", "End date (inclusive, defaults to today)").option(
1092
- "--types <types>",
1093
- "Document types: rule, proposed_rule, notice, presidential_document (fr-api only)"
1094
- ).option("--recent <days>", "Download last N days").option("--document <number>", "Download a single document by number (fr-api only)").option("--limit <n>", "Maximum number of documents (fr-api only)").option("--concurrency <n>", "Concurrent downloads (default: 10)").addHelpText(
1048
+ var downloadFrCommand = new Command6("download-fr").description("Download Federal Register XML and metadata").option("-o, --output <dir>", "Download directory", "./downloads/fr").option("--source <source>", "Source: fr-api (default, per-document) or govinfo (bulk daily)", "fr-api").option("--from <YYYY-MM-DD>", "Start date (inclusive)").option("--to <YYYY-MM-DD>", "End date (inclusive, defaults to today)").option("--types <types>", "Document types: rule, proposed_rule, notice, presidential_document (fr-api only)").option("--recent <days>", "Download last N days").option("--document <number>", "Download a single document by number (fr-api only)").option("--limit <n>", "Maximum number of documents (fr-api only)").option("--concurrency <n>", "Concurrent downloads (default: 10)").addHelpText(
1095
1049
  "after",
1096
1050
  `
1097
1051
  Examples:
@@ -1112,9 +1066,7 @@ Document types (fr-api only):
1112
1066
  presidential_document Executive orders, memoranda, proclamations`
1113
1067
  ).action(async (options) => {
1114
1068
  if (options.source !== "fr-api" && options.source !== "govinfo") {
1115
- console.error(
1116
- error(`Invalid source "${options.source}". Use "fr-api" (default) or "govinfo".`)
1117
- );
1069
+ console.error(error(`Invalid source "${options.source}". Use "fr-api" (default) or "govinfo".`));
1118
1070
  process.exit(1);
1119
1071
  }
1120
1072
  if (!options.from && !options.recent && !options.document) {
@@ -1203,9 +1155,7 @@ async function downloadGovinfo(options, outputDir, startTime, concurrency) {
1203
1155
  }
1204
1156
  });
1205
1157
  const elapsed = performance.now() - startTime;
1206
- spinner.succeed(
1207
- `Downloaded ${formatNumber(result.filesDownloaded)} daily FR issues from govinfo`
1208
- );
1158
+ spinner.succeed(`Downloaded ${formatNumber(result.filesDownloaded)} daily FR issues from govinfo`);
1209
1159
  console.log();
1210
1160
  const rows = [
1211
1161
  ["Source", "govinfo (bulk daily XML)"],
@@ -1235,9 +1185,7 @@ async function downloadFrApi(options, outputDir, startTime, concurrency) {
1235
1185
  const mapped = VALID_TYPES.get(normalized);
1236
1186
  if (!mapped) {
1237
1187
  console.error(
1238
- error(
1239
- `Invalid document type "${raw.trim()}". Valid types: ${[...VALID_TYPES.keys()].join(", ")}`
1240
- )
1188
+ error(`Invalid document type "${raw.trim()}". Valid types: ${[...VALID_TYPES.keys()].join(", ")}`)
1241
1189
  );
1242
1190
  process.exit(1);
1243
1191
  }
@@ -1282,9 +1230,7 @@ async function downloadFrApi(options, outputDir, startTime, concurrency) {
1282
1230
  }
1283
1231
  });
1284
1232
  const elapsed = performance.now() - startTime;
1285
- spinner.succeed(
1286
- `Downloaded ${formatNumber(result.documentsDownloaded)} Federal Register documents`
1287
- );
1233
+ spinner.succeed(`Downloaded ${formatNumber(result.documentsDownloaded)} Federal Register documents`);
1288
1234
  console.log();
1289
1235
  const rows = [
1290
1236
  ["Source", "FederalRegister.gov API"],
@@ -1332,10 +1278,7 @@ var VALID_TYPES2 = /* @__PURE__ */ new Map([
1332
1278
  ["notice", "NOTICE"],
1333
1279
  ["presidential_document", "PRESDOCU"]
1334
1280
  ]);
1335
- var convertFrCommand = new Command7("convert-fr").description("Convert Federal Register XML to Markdown").argument("[input]", "Path to single FR XML file (optional)").option("-o, --output <dir>", "Output directory", "./output").option("-i, --input-dir <dir>", "Directory containing downloaded FR files", "./downloads/fr").option("--all", "Convert all downloaded documents in input directory", false).option("--from <YYYY-MM-DD>", "Filter: start date").option("--to <YYYY-MM-DD>", "Filter: end date").option(
1336
- "--types <types>",
1337
- "Filter: document types (rule, proposed_rule, notice, presidential_document)"
1338
- ).option("--link-style <style>", "Link style: relative, canonical, plaintext", "plaintext").option("--dry-run", "Parse only, don't write files", false).option("-v, --verbose", "Print detailed file output", false).addHelpText(
1281
+ var convertFrCommand = new Command7("convert-fr").description("Convert Federal Register XML to Markdown").argument("[input]", "Path to single FR XML file (optional)").option("-o, --output <dir>", "Output directory", "./output").option("-i, --input-dir <dir>", "Directory containing downloaded FR files", "./downloads/fr").option("--all", "Convert all downloaded documents in input directory", false).option("--from <YYYY-MM-DD>", "Filter: start date").option("--to <YYYY-MM-DD>", "Filter: end date").option("--types <types>", "Filter: document types (rule, proposed_rule, notice, presidential_document)").option("--link-style <style>", "Link style: relative, canonical, plaintext", "plaintext").option("--dry-run", "Parse only, don't write files", false).option("-v, --verbose", "Print detailed file output", false).addHelpText(
1339
1282
  "after",
1340
1283
  `
1341
1284
  Examples:
@@ -1361,9 +1304,7 @@ Examples:
1361
1304
  const mapped = VALID_TYPES2.get(normalized);
1362
1305
  if (!mapped) {
1363
1306
  console.error(
1364
- error(
1365
- `Invalid document type "${raw.trim()}". Valid types: ${[...VALID_TYPES2.keys()].join(", ")}`
1366
- )
1307
+ error(`Invalid document type "${raw.trim()}". Valid types: ${[...VALID_TYPES2.keys()].join(", ")}`)
1367
1308
  );
1368
1309
  process.exit(1);
1369
1310
  }
@@ -1406,13 +1347,9 @@ Examples:
1406
1347
  });
1407
1348
  const elapsed = performance.now() - startTime;
1408
1349
  if (options.dryRun) {
1409
- spinner.succeed(
1410
- `Dry run: ${formatNumber(result.documentsConverted)} documents would be converted`
1411
- );
1350
+ spinner.succeed(`Dry run: ${formatNumber(result.documentsConverted)} documents would be converted`);
1412
1351
  } else {
1413
- spinner.succeed(
1414
- `Converted ${formatNumber(result.documentsConverted)} Federal Register documents`
1415
- );
1352
+ spinner.succeed(`Converted ${formatNumber(result.documentsConverted)} Federal Register documents`);
1416
1353
  }
1417
1354
  console.log();
1418
1355
  const rows = [["Documents", formatNumber(result.documentsConverted)]];
@@ -1452,11 +1389,7 @@ that were originally converted from govinfo bulk XML.
1452
1389
  Files that already have fr_citation are skipped unless --force is used.`
1453
1390
  ).action(async (options) => {
1454
1391
  if (!options.from && !options.recent) {
1455
- console.error(
1456
- error(
1457
- "Specify --from <date> or --recent <days>\nExamples: --from 2000-01-01, --recent 30"
1458
- )
1459
- );
1392
+ console.error(error("Specify --from <date> or --recent <days>\nExamples: --from 2000-01-01, --recent 30"));
1460
1393
  process.exit(1);
1461
1394
  }
1462
1395
  if (options.from && !/^\d{4}-\d{2}-\d{2}$/.test(options.from)) {
@@ -1483,9 +1416,7 @@ Files that already have fr_citation are skipped unless --force is used.`
1483
1416
  const to = options.to ?? (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
1484
1417
  const outputDir = resolve7(options.output);
1485
1418
  const startTime = performance.now();
1486
- const spinner = createSpinner(
1487
- `Enriching FR frontmatter (${from} to ${to})`
1488
- );
1419
+ const spinner = createSpinner(`Enriching FR frontmatter (${from} to ${to})`);
1489
1420
  spinner.start();
1490
1421
  try {
1491
1422
  const result = await enrichFrDocuments({
@@ -1500,9 +1431,7 @@ Files that already have fr_citation are skipped unless --force is used.`
1500
1431
  }
1501
1432
  });
1502
1433
  const elapsed = performance.now() - startTime;
1503
- spinner.succeed(
1504
- `Enriched ${formatNumber(result.enriched)} FR documents`
1505
- );
1434
+ spinner.succeed(`Enriched ${formatNumber(result.enriched)} FR documents`);
1506
1435
  console.log();
1507
1436
  const rows = [
1508
1437
  ["Date range", `${result.dateRange.from} \u2192 ${result.dateRange.to}`],
@@ -1556,9 +1485,7 @@ program.addCommand(
1556
1485
  console.error(error("Please specify a source:\n"));
1557
1486
  console.error(" lexbuild download-usc Download U.S. Code XML from OLRC");
1558
1487
  console.error(" lexbuild download-ecfr Download eCFR XML from govinfo");
1559
- console.error(
1560
- " lexbuild download-fr Download Federal Register XML from federalregister.gov"
1561
- );
1488
+ console.error(" lexbuild download-fr Download Federal Register XML from federalregister.gov");
1562
1489
  console.error("");
1563
1490
  process.exit(1);
1564
1491
  })
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/commands/convert-usc.ts","../src/ui.ts","../src/parse-titles.ts","../src/commands/download-usc.ts","../src/commands/list-release-points.ts","../src/commands/convert-ecfr.ts","../src/commands/download-ecfr.ts","../src/commands/download-fr.ts","../src/commands/convert-fr.ts","../src/commands/enrich-fr.ts"],"sourcesContent":["/** lexbuild CLI — Convert U.S. legal XML to structured Markdown */\n\nimport { createRequire } from \"node:module\";\nimport { Command } from \"commander\";\nimport { convertUscCommand } from \"./commands/convert-usc.js\";\nimport { downloadUscCommand } from \"./commands/download-usc.js\";\nimport { listReleasePointsCommand } from \"./commands/list-release-points.js\";\nimport { convertEcfrCommand } from \"./commands/convert-ecfr.js\";\nimport { downloadEcfrCommand } from \"./commands/download-ecfr.js\";\nimport { downloadFrCommand } from \"./commands/download-fr.js\";\nimport { convertFrCommand } from \"./commands/convert-fr.js\";\nimport { enrichFrCommand } from \"./commands/enrich-fr.js\";\nimport { error } from \"./ui.js\";\n\nconst require = createRequire(import.meta.url);\nconst pkg = require(\"../package.json\") as { version: string };\n\nconst program = new Command();\n\nprogram\n .name(\"lexbuild\")\n .description(\"Convert U.S. legal XML to structured Markdown for AI/RAG ingestion\")\n .version(pkg.version)\n .addHelpText(\n \"after\",\n `\nQuick start (U.S. Code):\n $ lexbuild download-usc --all Download all 54 USC titles from OLRC\n $ lexbuild convert-usc --all Convert all downloaded USC titles\n $ lexbuild convert-usc --titles 1 Convert USC Title 1 only\n\nQuick start (eCFR):\n $ lexbuild download-ecfr --all Download all 50 eCFR titles from govinfo\n $ lexbuild convert-ecfr --all Convert all downloaded eCFR titles\n $ lexbuild convert-ecfr --titles 17 Convert eCFR Title 17 only\n\nQuick start (Federal Register):\n $ lexbuild download-fr --recent 30 Download last 30 days of FR documents\n $ lexbuild convert-fr --all Convert all downloaded FR documents\n\nDocumentation: https://github.com/chris-c-thomas/LexBuild`,\n );\n\n// Source-specific commands\nprogram.addCommand(downloadUscCommand);\nprogram.addCommand(convertUscCommand);\nprogram.addCommand(listReleasePointsCommand);\nprogram.addCommand(downloadEcfrCommand);\nprogram.addCommand(convertEcfrCommand);\nprogram.addCommand(downloadFrCommand);\nprogram.addCommand(convertFrCommand);\nprogram.addCommand(enrichFrCommand);\n\n// Bare \"download\" and \"convert\" stubs — guide users to source-specific commands\nprogram.addCommand(\n new Command(\"download\")\n .description(\"(use download-usc or download-ecfr)\")\n .allowUnknownOption()\n .helpOption(false)\n .action(() => {\n console.error(error(\"Please specify a source:\\n\"));\n console.error(\" lexbuild download-usc Download U.S. Code XML from OLRC\");\n console.error(\" lexbuild download-ecfr Download eCFR XML from govinfo\");\n console.error(\n \" lexbuild download-fr Download Federal Register XML from federalregister.gov\",\n );\n console.error(\"\");\n process.exit(1);\n }),\n);\n\nprogram.addCommand(\n new Command(\"convert\")\n .description(\"(use convert-usc or convert-ecfr)\")\n .allowUnknownOption()\n .helpOption(false)\n .action(() => {\n console.error(error(\"Please specify a source:\\n\"));\n console.error(\" lexbuild convert-usc Convert U.S. Code XML to Markdown\");\n console.error(\" lexbuild convert-ecfr Convert eCFR XML to Markdown\");\n console.error(\" lexbuild convert-fr Convert Federal Register XML to Markdown\");\n console.error(\"\");\n process.exit(1);\n }),\n);\n\nprogram.parse();\n","/**\n * `lexbuild convert-usc` command — converts USC XML files to Markdown.\n */\n\nimport chalk from \"chalk\";\nimport { Command, Option } from \"commander\";\nimport { existsSync, readdirSync } from \"node:fs\";\nimport { basename, dirname, join, relative, resolve } from \"node:path\";\nimport { convertTitle } from \"@lexbuild/usc\";\nimport {\n createSpinner,\n summaryBlock,\n dataTable,\n formatDuration,\n formatBytes,\n formatNumber,\n success,\n error,\n} from \"../ui.js\";\nimport { parseTitles } from \"../parse-titles.js\";\n\n/** Parsed options from the convert command */\ninterface ConvertCommandOptions {\n output: string;\n titles?: string | undefined;\n all: boolean;\n inputDir: string;\n granularity: \"section\" | \"chapter\" | \"title\";\n linkStyle: \"relative\" | \"canonical\" | \"plaintext\";\n includeSourceCredits: boolean;\n includeNotes: boolean;\n includeEditorialNotes: boolean;\n includeStatutoryNotes: boolean;\n includeAmendments: boolean;\n dryRun: boolean;\n verbose: boolean;\n}\n\n/** Build the shared convert options from CLI flags. */\nfunction buildConvertOptions(\n inputPath: string,\n outputPath: string,\n options: ConvertCommandOptions,\n) {\n const hasSelectiveFlags =\n options.includeEditorialNotes || options.includeStatutoryNotes || options.includeAmendments;\n const includeNotes = hasSelectiveFlags ? false : options.includeNotes;\n\n return {\n input: inputPath,\n output: outputPath,\n granularity: options.granularity,\n linkStyle: options.linkStyle,\n includeSourceCredits: options.includeSourceCredits,\n includeNotes,\n includeEditorialNotes: options.includeEditorialNotes,\n includeStatutoryNotes: options.includeStatutoryNotes,\n includeAmendments: options.includeAmendments,\n dryRun: options.dryRun,\n };\n}\n\n/** Resolve the XML file path for a given title number. */\nfunction titleXmlPath(inputDir: string, titleNum: number): string {\n const padded = String(titleNum).padStart(2, \"0\");\n return join(inputDir, `usc${padded}.xml`);\n}\n\n/** Try to resolve a USC XML path, falling back to zero-padded filename. */\nexport function resolveUscXmlPath(inputPath: string): string | undefined {\n if (existsSync(inputPath)) return inputPath;\n\n // Check if filename matches usc{N}.xml pattern and try zero-padded\n const dir = dirname(inputPath);\n const base = basename(inputPath);\n const match = /^usc(\\d+)\\.xml$/.exec(base);\n if (match?.[1]) {\n const padded = match[1].padStart(2, \"0\");\n const paddedPath = join(dir, `usc${padded}.xml`);\n if (existsSync(paddedPath)) return paddedPath;\n }\n\n return undefined;\n}\n\n/** Regex matching USC XML filenames like usc01.xml, usc54.xml */\nconst USC_XML_RE = /^usc(\\d{2})\\.xml$/;\n\n/**\n * Scan a directory for USC XML files and return their title numbers, sorted.\n */\nexport function discoverTitles(inputDir: string): number[] {\n if (!existsSync(inputDir)) return [];\n\n return readdirSync(inputDir)\n .map((name) => USC_XML_RE.exec(name))\n .filter((m): m is RegExpExecArray => m !== null)\n .map((m) => parseInt(m[1] ?? \"0\", 10))\n .sort((a, b) => a - b);\n}\n\n/** Result from runConversion including elapsed time. */\ninterface ConversionRun {\n result: Awaited<ReturnType<typeof convertTitle>>;\n elapsed: number;\n}\n\n/** Run a conversion without printing output. Returns the result and elapsed time. */\nasync function runConversion(\n inputPath: string,\n outputPath: string,\n options: ConvertCommandOptions,\n): Promise<ConversionRun> {\n const startTime = performance.now();\n const result = await convertTitle(buildConvertOptions(inputPath, outputPath, options));\n const elapsed = performance.now() - startTime;\n return { result, elapsed };\n}\n\n/** Convert a single XML file and print its detailed summary. */\nasync function convertSingleFile(\n inputPath: string,\n outputPath: string,\n options: ConvertCommandOptions,\n spinnerLabel: string,\n) {\n const spinner = createSpinner(spinnerLabel);\n spinner.start();\n\n try {\n const { result, elapsed } = await runConversion(inputPath, outputPath, options);\n\n spinner.stop();\n\n const rows: Array<[string, string]> = [];\n if (options.granularity === \"section\") {\n rows.push([\"Sections\", formatNumber(result.sectionsWritten)]);\n rows.push([\"Chapters\", formatNumber(result.chapterCount)]);\n } else if (options.granularity === \"chapter\") {\n rows.push([\"Chapters\", formatNumber(result.chapterCount)]);\n }\n rows.push([\"Est. Tokens\", formatNumber(result.totalTokenEstimate)]);\n\n if (!result.dryRun) {\n rows.push([\"Files Written\", formatNumber(result.files.length)]);\n }\n\n rows.push(\n [\"Peak Memory\", formatBytes(result.peakMemoryBytes)],\n [\"Duration\", formatDuration(elapsed)],\n );\n\n const titleLabel = result.dryRun\n ? `lexbuild — Title ${result.titleNumber}: ${result.titleName} [dry-run]`\n : `lexbuild — Title ${result.titleNumber}: ${result.titleName}`;\n\n const outputRelative = relative(process.cwd(), outputPath) || outputPath;\n\n const output = summaryBlock({\n title: titleLabel,\n rows: [...rows, [\"Output\", outputRelative]],\n footer: result.dryRun ? success(\"Dry run complete\") : success(\"Conversion complete\"),\n });\n process.stdout.write(output);\n\n if (options.verbose && !result.dryRun && result.files.length > 0) {\n console.log(\" Files written:\");\n for (const file of result.files) {\n console.log(` ${relative(process.cwd(), file) || file}`);\n }\n console.log(\"\");\n }\n\n return result;\n } catch (err) {\n spinner.fail(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n}\n\nexport const convertUscCommand = new Command(\"convert-usc\")\n .description(\"Convert U.S. Code XML file(s) to Markdown\")\n .argument(\"[input]\", \"Path to a USC XML file\")\n .option(\"-o, --output <dir>\", \"Output directory\", \"./output\")\n .option(\"--titles <spec>\", \"Title(s) to convert: 1, 1-5, or 1-5,8,11\")\n .option(\"--all\", \"Convert all downloaded titles found in --input-dir\", false)\n .option(\"-i, --input-dir <dir>\", \"Directory containing USC XML files\", \"./downloads/usc/xml\")\n .addOption(\n new Option(\"-g, --granularity <level>\", \"Output granularity: section, chapter, or title\")\n .choices([\"section\", \"chapter\", \"title\"])\n .default(\"section\"),\n )\n .addOption(\n new Option(\"--link-style <style>\", \"Link style: relative, canonical, or plaintext\")\n .choices([\"relative\", \"canonical\", \"plaintext\"])\n .default(\"plaintext\"),\n )\n .option(\"--include-source-credits\", \"Include source credit annotations\", true)\n .option(\"--no-include-source-credits\", \"Exclude source credit annotations\")\n .option(\"--include-notes\", \"Include all notes (default)\", true)\n .option(\"--no-include-notes\", \"Exclude all notes\")\n .option(\"--include-editorial-notes\", \"Include editorial notes only\", false)\n .option(\"--include-statutory-notes\", \"Include statutory notes only\", false)\n .option(\"--include-amendments\", \"Include amendment history notes only\", false)\n .option(\"--dry-run\", \"Parse and report structure without writing files\", false)\n .option(\"-v, --verbose\", \"Enable verbose logging\", false)\n .addHelpText(\n \"after\",\n `\nInput modes (use exactly one):\n <input> Convert a single XML file\n --titles Convert specific titles by number\n --all Convert all titles in --input-dir\n\nGranularity:\n section One .md file per section (default)\n chapter One .md file per chapter, sections inlined\n title One .md file per title, entire hierarchy inlined\n\nExamples:\n $ lexbuild convert-usc --titles 1 Convert Title 1\n $ lexbuild convert-usc --titles 1-5,8,11 Convert a mix of titles\n $ lexbuild convert-usc --all -g chapter All titles, chapter-level\n $ lexbuild convert-usc --titles 26 -g title Title 26 as a single file\n $ lexbuild convert-usc --all --dry-run Preview stats only\n $ lexbuild convert-usc ./downloads/usc/xml/usc01.xml -o ./out`,\n )\n .action(async (input: string | undefined, options: ConvertCommandOptions) => {\n // Validate: must specify exactly one of <input>, --titles, or --all\n const modeCount = [input, options.titles, options.all].filter(Boolean).length;\n if (modeCount === 0) {\n console.error(\n error(\"Specify an input file, --titles <spec>, or --all (e.g. --titles 1-5,8,11)\"),\n );\n process.exit(1);\n }\n if (modeCount > 1) {\n console.error(error(\"Cannot combine <input>, --titles, and --all — use only one\"));\n process.exit(1);\n }\n\n const outputPath = resolve(options.output);\n const dryRunLabel = options.dryRun ? \" [dry-run]\" : \"\";\n\n // Single-file mode\n if (input) {\n const rawPath = resolve(input);\n const inputPath = resolveUscXmlPath(rawPath);\n if (!inputPath) {\n console.error(error(`Input file not found: ${rawPath}`));\n process.exit(1);\n }\n await convertSingleFile(inputPath, outputPath, options, `Converting${dryRunLabel}...`);\n return;\n }\n\n // Multi-title mode\n let titles: number[];\n if (options.all) {\n const inputDir = resolve(options.inputDir);\n titles = discoverTitles(inputDir);\n if (titles.length === 0) {\n console.error(error(`No USC XML files found in ${inputDir}`));\n process.exit(1);\n }\n } else {\n const titlesSpec = options.titles as string;\n try {\n titles = parseTitles(titlesSpec);\n } catch (err) {\n console.error(error(err instanceof Error ? err.message : String(err)));\n process.exit(1);\n }\n }\n\n const inputDir = resolve(options.inputDir);\n const totalTitles = titles.length;\n const results: ConversionRun[] = [];\n\n const spinner = createSpinner(`Converting${dryRunLabel}...`);\n spinner.start();\n\n for (const [i, titleNum] of titles.entries()) {\n const xmlPath = titleXmlPath(inputDir, titleNum);\n\n if (!existsSync(xmlPath)) {\n spinner.stop();\n console.error(error(`XML file not found: ${xmlPath}`));\n process.exit(1);\n }\n\n spinner.text = `Converting Title ${titleNum}${dryRunLabel} (${i + 1}/${totalTitles})...`;\n\n try {\n const run = await runConversion(xmlPath, outputPath, options);\n results.push(run);\n } catch (err) {\n spinner.fail(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n }\n\n spinner.stop();\n\n // Summary header\n const outputRelative = relative(process.cwd(), outputPath) || outputPath;\n const headerTitle = options.dryRun\n ? \"lexbuild — Conversion Summary [dry-run]\"\n : \"lexbuild — Conversion Summary\";\n const header = summaryBlock({\n title: headerTitle,\n rows: [[\"Directory\", outputRelative]],\n });\n process.stdout.write(header);\n\n // Build data table rows — adapt columns to granularity\n const granularity = options.granularity;\n let totalSections = 0;\n let totalChapters = 0;\n let totalTokens = 0;\n let totalElapsed = 0;\n\n const tableRows = results.map(({ result, elapsed }) => {\n totalSections += result.sectionsWritten;\n totalChapters += result.chapterCount;\n totalTokens += result.totalTokenEstimate;\n totalElapsed += elapsed;\n\n if (granularity === \"title\") {\n return [\n result.titleNumber,\n result.titleName,\n formatNumber(result.totalTokenEstimate),\n formatDuration(elapsed),\n ];\n } else if (granularity === \"chapter\") {\n return [\n result.titleNumber,\n result.titleName,\n formatNumber(result.chapterCount),\n formatNumber(result.totalTokenEstimate),\n formatDuration(elapsed),\n ];\n } else {\n return [\n result.titleNumber,\n result.titleName,\n formatNumber(result.chapterCount),\n formatNumber(result.sectionsWritten),\n formatNumber(result.totalTokenEstimate),\n formatDuration(elapsed),\n ];\n }\n });\n\n // Totals row\n if (granularity === \"title\") {\n tableRows.push([\n chalk.bold(\"Total\"),\n \"\",\n chalk.bold(formatNumber(totalTokens)),\n chalk.bold(formatDuration(totalElapsed)),\n ]);\n } else if (granularity === \"chapter\") {\n tableRows.push([\n chalk.bold(\"Total\"),\n \"\",\n chalk.bold(formatNumber(totalChapters)),\n chalk.bold(formatNumber(totalTokens)),\n chalk.bold(formatDuration(totalElapsed)),\n ]);\n } else {\n tableRows.push([\n chalk.bold(\"Total\"),\n \"\",\n chalk.bold(formatNumber(totalChapters)),\n chalk.bold(formatNumber(totalSections)),\n chalk.bold(formatNumber(totalTokens)),\n chalk.bold(formatDuration(totalElapsed)),\n ]);\n }\n\n // Table headers and footer — adapt to granularity\n const tableHeaders =\n granularity === \"title\"\n ? [\"Title\", \"Name\", \"Tokens\", \"Duration\"]\n : granularity === \"chapter\"\n ? [\"Title\", \"Name\", \"Chapters\", \"Tokens\", \"Duration\"]\n : [\"Title\", \"Name\", \"Chapters\", \"Sections\", \"Tokens\", \"Duration\"];\n\n console.log(dataTable(tableHeaders, tableRows));\n\n // Footer — show the primary unit that was converted\n let countLabel: string;\n if (granularity === \"title\") {\n const titleWord = totalTitles === 1 ? \"title\" : \"titles\";\n countLabel = `${formatNumber(totalTitles)} ${titleWord}`;\n } else if (granularity === \"chapter\") {\n const chapterWord = totalChapters === 1 ? \"chapter\" : \"chapters\";\n countLabel = `${formatNumber(totalChapters)} ${chapterWord}`;\n } else {\n const sectionWord = totalSections === 1 ? \"section\" : \"sections\";\n countLabel = `${formatNumber(totalSections)} ${sectionWord}`;\n }\n console.log(`\\n ${success(`Converted ${countLabel} in ${formatDuration(totalElapsed)}`)}`);\n console.log(\"\");\n });\n","/**\n * Shared terminal UI utilities — spinners, tables, and formatting helpers.\n */\n\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport type { Ora } from \"ora\";\nimport Table from \"cli-table3\";\n\n/** Create an ora spinner with consistent styling. */\nexport function createSpinner(text: string): Ora {\n return ora({ text, spinner: \"dots\" });\n}\n\n/** Format milliseconds as human-readable duration (e.g. \"1.5s\" or \"1m 23s\"). */\nexport function formatDuration(ms: number): string {\n const secs = ms / 1000;\n if (secs < 60) {\n return `${secs.toFixed(secs < 10 ? 2 : 1)}s`;\n }\n const mins = Math.floor(secs / 60);\n const remainSecs = Math.round(secs % 60);\n return `${mins}m ${remainSecs}s`;\n}\n\n/** Format bytes as human-readable size (e.g. \"11.0 MB\"). */\nexport function formatBytes(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`;\n const kb = bytes / 1024;\n if (kb < 1024) return `${kb.toFixed(1)} KB`;\n const mb = kb / 1024;\n if (mb < 1024) return `${mb.toFixed(1)} MB`;\n const gb = mb / 1024;\n return `${gb.toFixed(2)} GB`;\n}\n\n/** Format a number with locale-aware separators (e.g. 1,234,567). */\nexport function formatNumber(n: number): string {\n return n.toLocaleString();\n}\n\n/** Regex matching ANSI escape sequences (SGR codes). */\n// eslint-disable-next-line no-control-regex\nconst ANSI_RE = /\\x1B\\[[0-9;]*m/g;\n\n/** Strip ANSI escape codes and return visual string length. */\nfunction visualLength(s: string): number {\n return s.replace(ANSI_RE, \"\").length;\n}\n\n/**\n * Compute column widths that fill the terminal.\n * Expands `flexCol` to absorb remaining space.\n */\nfunction fillWidths(columns: string[][], colCount: number, flexCol: number): number[] | undefined {\n const termWidth = process.stdout.columns || 80;\n // Compute natural width per column (max visual length across all rows)\n const natural = Array.from<number>({ length: colCount }).fill(0);\n for (const row of columns) {\n for (let i = 0; i < colCount; i++) {\n natural[i] = Math.max(natural[i] ?? 0, visualLength(row[i] ?? \"\"));\n }\n }\n // Overhead: 2 chars left pad + 2 chars per column separator (between cols)\n const overhead = 2 + 2 * (colCount - 1);\n const naturalTotal = overhead + natural.reduce((a, b) => a + b, 0);\n if (naturalTotal >= termWidth) return undefined; // already fills or exceeds\n const extra = termWidth - naturalTotal;\n const widths = [...natural];\n widths[flexCol] = (widths[flexCol] ?? 0) + extra;\n return widths;\n}\n\n/**\n * Shared cli-table3 border characters.\n *\n * Uses 2-char left indent (\" \"), 2-char column gap (\" \"), no right border.\n * The \"mid\" intersection chars (\"──\") must match the 2-char width of \"middle\"\n * so horizontal rules span the full table width.\n */\nconst TABLE_CHARS = {\n top: \"─\",\n \"top-mid\": \"──\",\n \"top-left\": \" \",\n \"top-right\": \"\",\n bottom: \"─\",\n \"bottom-mid\": \"──\",\n \"bottom-left\": \" \",\n \"bottom-right\": \"\",\n left: \" \",\n \"left-mid\": \" \",\n right: \"\",\n \"right-mid\": \"\",\n mid: \"─\",\n \"mid-mid\": \"──\",\n middle: \" \",\n} as const;\n\n/** Shared cli-table3 style. */\nconst TABLE_STYLE: {\n head: string[];\n border: string[];\n \"padding-left\": number;\n \"padding-right\": number;\n} = {\n head: [],\n border: [],\n \"padding-left\": 0,\n \"padding-right\": 0,\n};\n\n/** Render a styled heading line. */\nfunction heading(text: string): string {\n return chalk.bold(text);\n}\n\n/** Render a success message with green checkmark. */\nexport function success(text: string): string {\n return chalk.green(`✔ ${text}`);\n}\n\n/** Render an error message with red X. */\nexport function error(text: string): string {\n return chalk.red(`✘ ${text}`);\n}\n\n/** Options for a key-value summary block. */\ninterface SummaryBlockOptions {\n /** Title line displayed above the table */\n title: string;\n /** Key-value pairs to display */\n rows: Array<[label: string, value: string]>;\n /** Optional footer line displayed below the table */\n footer?: string | undefined;\n}\n\n/** Render a key-value summary block with horizontal rules. */\nexport function summaryBlock({ title, rows, footer }: SummaryBlockOptions): string {\n const allCells = rows.map(([l, v]) => [l, v]);\n const colWidths = fillWidths(allCells, 2, 1);\n\n const table = new Table({\n chars: TABLE_CHARS,\n style: TABLE_STYLE,\n ...(colWidths ? { colWidths } : {}),\n });\n\n for (const [label, value] of rows) {\n table.push([chalk.dim(label), value]);\n }\n\n const lines: string[] = [];\n lines.push(\"\");\n lines.push(` ${heading(title)}`);\n lines.push(table.toString());\n if (footer !== undefined) {\n lines.push(` ${footer}`);\n }\n lines.push(\"\");\n\n return lines.join(\"\\n\");\n}\n\n/** Render a multi-column data table. */\nexport function dataTable(head: string[], rows: string[][]): string {\n const table = new Table({\n head: head.map((h) => chalk.dim(h)),\n chars: TABLE_CHARS,\n style: TABLE_STYLE,\n });\n\n for (const row of rows) {\n table.push(row);\n }\n\n return table.toString();\n}\n","/**\n * Parses a title specification string into an array of title numbers.\n *\n * Supports single numbers, comma-separated lists, ranges, and mixed:\n * - `\"29\"` → `[29]`\n * - `\"1,3,8,11\"` → `[1, 3, 8, 11]`\n * - `\"1-5\"` → `[1, 2, 3, 4, 5]`\n * - `\"1-5,8,11\"` → `[1, 2, 3, 4, 5, 8, 11]`\n */\nexport function parseTitles(input: string, maxTitle = 54): number[] {\n const trimmed = input.trim();\n if (trimmed === \"\") {\n throw new Error(\"Title specification cannot be empty\");\n }\n\n const result = new Set<number>();\n const segments = trimmed.split(\",\");\n\n for (const segment of segments) {\n const part = segment.trim();\n if (part === \"\") {\n throw new Error(`Invalid title specification: \"${input}\" (empty segment)`);\n }\n\n if (part.includes(\"-\")) {\n const [startStr, endStr, ...rest] = part.split(\"-\");\n if (rest.length > 0 || !startStr || !endStr) {\n throw new Error(`Invalid range: \"${part}\" (expected format: start-end)`);\n }\n\n const start = parseIntStrict(startStr, input);\n const end = parseIntStrict(endStr, input);\n\n if (start > end) {\n throw new Error(`Invalid range: \"${part}\" (start ${start} must be ≤ end ${end})`);\n }\n\n validateTitleNumber(start, input, maxTitle);\n validateTitleNumber(end, input, maxTitle);\n\n for (let i = start; i <= end; i++) {\n result.add(i);\n }\n } else {\n const num = parseIntStrict(part, input);\n validateTitleNumber(num, input, maxTitle);\n result.add(num);\n }\n }\n\n return [...result].sort((a, b) => a - b);\n}\n\n/** Parse an integer strictly — no NaN, no floats. */\nfunction parseIntStrict(str: string, fullInput: string): number {\n const trimmed = str.trim();\n if (!/^\\d+$/.test(trimmed)) {\n throw new Error(`Invalid number \"${trimmed}\" in title specification: \"${fullInput}\"`);\n }\n return parseInt(trimmed, 10);\n}\n\n/** Validate that a title number is in the valid range. */\nfunction validateTitleNumber(num: number, fullInput: string, max = 54): void {\n if (num < 1 || num > max) {\n throw new Error(`Title number ${num} out of range (must be 1-${max}) in: \"${fullInput}\"`);\n }\n}\n","/**\n * `lexbuild download-usc` command — downloads USC XML from OLRC.\n *\n * Auto-detects the latest OLRC release point unless overridden with --release-point.\n */\n\nimport { Command } from \"commander\";\nimport { relative, resolve } from \"node:path\";\nimport { downloadTitles, detectLatestReleasePoint, FALLBACK_RELEASE_POINT } from \"@lexbuild/usc\";\nimport {\n createSpinner,\n summaryBlock,\n dataTable,\n formatDuration,\n formatBytes,\n success,\n error,\n} from \"../ui.js\";\nimport { parseTitles } from \"../parse-titles.js\";\n\n/** Parsed options from the download command */\ninterface DownloadCommandOptions {\n output: string;\n titles?: string | undefined;\n all: boolean;\n releasePoint?: string | undefined;\n}\n\nexport const downloadUscCommand = new Command(\"download-usc\")\n .description(\"Download U.S. Code XML from OLRC\")\n .option(\"-o, --output <dir>\", \"Download directory\", \"./downloads/usc/xml\")\n .option(\"--titles <spec>\", \"Title(s) to download: 1, 1-5, or 1-5,8,11\")\n .option(\"--all\", \"Download all 54 titles (single bulk zip)\", false)\n .option(\"--release-point <id>\", \"OLRC release point (auto-detected if omitted)\")\n .addHelpText(\n \"after\",\n `\nExamples:\n $ lexbuild download-usc --all Download all 54 titles (latest release)\n $ lexbuild download-usc --titles 1 Download Title 1 only\n $ lexbuild download-usc --titles 1-5,8,11 Download specific titles\n $ lexbuild download-usc --all -o ./my-xml Custom output directory\n $ lexbuild download-usc --all --release-point 119-73not60 Pin a specific release\n\nThe latest release point is auto-detected from the OLRC download page.\nSource: https://uscode.house.gov/download/download.shtml`,\n )\n .action(async (options: DownloadCommandOptions) => {\n // Validate: must specify --titles or --all\n if (!options.titles && !options.all) {\n console.error(error(\"Specify --titles <spec> or --all (e.g. --titles 1-5,8,11)\"));\n process.exit(1);\n }\n\n // Parse title numbers\n let titles: number[] | undefined;\n if (options.titles) {\n try {\n titles = parseTitles(options.titles);\n } catch (err) {\n console.error(error(err instanceof Error ? err.message : String(err)));\n process.exit(1);\n }\n }\n\n const outputDir = resolve(options.output);\n const titleCount = titles ? titles.length : 54;\n\n // Resolve release point: use explicit flag, auto-detect, or fall back\n let releasePoint = options.releasePoint;\n if (!releasePoint) {\n const detectSpinner = createSpinner(\"Detecting latest OLRC release point...\");\n detectSpinner.start();\n const detected = await detectLatestReleasePoint();\n if (detected) {\n releasePoint = detected.releasePoint;\n detectSpinner.succeed(`Release point: ${detected.releasePoint}`);\n } else {\n releasePoint = FALLBACK_RELEASE_POINT;\n detectSpinner.warn(`Could not detect release point, using fallback: ${releasePoint}`);\n }\n }\n\n const label =\n titleCount === 1\n ? `Downloading Title ${titles?.[0]}`\n : `Downloading ${titleCount} USC titles`;\n\n const spinner = createSpinner(`${label}...`);\n spinner.start();\n\n const startTime = performance.now();\n\n try {\n const result = await downloadTitles({\n outputDir,\n titles,\n releasePoint,\n onProgress: ({ current, total, titleNumber, phase }) => {\n if (phase === \"extracting\") {\n spinner.text = `Extracting USC titles (${current}/${total}) — Title ${titleNumber}`;\n } else if (total === 1) {\n spinner.text = `Downloading USC Title ${titleNumber}`;\n } else if (current === 0) {\n spinner.text = \"Downloading USC bulk archive\";\n } else {\n spinner.text = `Downloading USC titles (${current}/${total}) — Title ${titleNumber}`;\n }\n },\n });\n\n const elapsed = performance.now() - startTime;\n\n spinner.stop();\n\n // Build file table rows\n const fileRows = result.files.map((file) => [\n String(file.titleNumber),\n formatBytes(file.size),\n relative(outputDir, file.filePath) || file.filePath,\n ]);\n\n const totalBytes = result.files.reduce((sum, f) => sum + f.size, 0);\n\n // Summary header — show the actual release point used (may be auto-detected)\n const rpLabel = options.releasePoint\n ? result.releasePoint\n : `${result.releasePoint} (auto-detected)`;\n\n const output = summaryBlock({\n title: \"lexbuild — Download Summary\",\n rows: [\n [\"Release Point\", rpLabel],\n [\"Directory\", relative(process.cwd(), outputDir) || outputDir],\n ],\n });\n process.stdout.write(output);\n\n // File table\n if (fileRows.length > 0) {\n console.log(dataTable([\"Title\", \"Size\", \"File\"], fileRows));\n }\n\n // Errors\n if (result.errors.length > 0) {\n console.log(\"\");\n for (const err of result.errors) {\n console.log(` ${error(`Title ${err.titleNumber}: ${err.message}`)}`);\n }\n }\n\n // Footer\n const titleWord = result.files.length === 1 ? \"title\" : \"titles\";\n const summary = `Downloaded ${result.files.length} ${titleWord} (${formatBytes(totalBytes)}) in ${formatDuration(elapsed)}`;\n const failSuffix = result.errors.length > 0 ? ` (${result.errors.length} failed)` : \"\";\n console.log(` ${success(summary + failSuffix)}`);\n console.log(\"\");\n } catch (err) {\n spinner.fail(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n });\n","/**\n * `lexbuild list-release-points` command — lists available OLRC release points.\n *\n * Fetches the current release point from the OLRC download page and the full\n * history from the prior release points page, then displays them in a table.\n */\n\nimport { Command } from \"commander\";\nimport {\n detectLatestReleasePoint,\n fetchReleasePointHistory,\n FALLBACK_RELEASE_POINT,\n} from \"@lexbuild/usc\";\nimport { createSpinner, summaryBlock, dataTable, error } from \"../ui.js\";\n\n/** Parsed options from the list-release-points command */\ninterface ListReleasePointsOptions {\n limit: string;\n}\n\nexport const listReleasePointsCommand = new Command(\"list-release-points\")\n .description(\"List available OLRC release points for the U.S. Code\")\n .option(\"-n, --limit <count>\", \"Maximum number of release points to show\", \"20\")\n .addHelpText(\n \"after\",\n `\nExamples:\n $ lexbuild list-release-points Show the 20 most recent release points\n $ lexbuild list-release-points -n 5 Show the 5 most recent\n $ lexbuild list-release-points -n 0 Show all available release points\n\nUse --release-point <id> with download-usc to pin a specific release.\nSource: https://uscode.house.gov/download/priorreleasepoints.htm`,\n )\n .action(async (options: ListReleasePointsOptions) => {\n const limit = parseInt(options.limit, 10);\n if (Number.isNaN(limit) || limit < 0) {\n console.error(error(\"--limit must be a non-negative integer\"));\n process.exit(1);\n }\n\n const spinner = createSpinner(\"Fetching release points from OLRC...\");\n spinner.start();\n\n // Fetch current and history in parallel\n const [current, history] = await Promise.all([\n detectLatestReleasePoint(),\n fetchReleasePointHistory(),\n ]);\n\n spinner.stop();\n\n // Current release point summary\n const currentRp = current?.releasePoint ?? FALLBACK_RELEASE_POINT;\n const currentDesc = current?.description ?? \"(detection failed — showing fallback)\";\n\n const output = summaryBlock({\n title: \"lexbuild — OLRC Release Points\",\n rows: [\n [\"Latest\", `${currentRp} ${currentDesc}`],\n [\"Prior releases\", `${history.length} available`],\n ],\n });\n process.stdout.write(output);\n\n if (history.length === 0) {\n console.log(\" No prior release points found.\\n\");\n return;\n }\n\n // Apply limit (0 = show all)\n const displayed = limit > 0 ? history.slice(0, limit) : history;\n\n // Build table rows: Release Point, Date, Affected Titles\n const rows = displayed.map((rp) => [\n rp.releasePoint,\n rp.date,\n rp.affectedTitles.length > 0 ? rp.affectedTitles.join(\", \") : \"—\",\n ]);\n\n console.log(dataTable([\"Release Point\", \"Date\", \"Affected Titles\"], rows));\n\n if (limit > 0 && history.length > limit) {\n console.log(` Showing ${limit} of ${history.length} — use -n 0 to show all.\\n`);\n }\n\n console.log(\" Use with: lexbuild download-usc --all --release-point <id>\\n\");\n });\n","/**\n * `lexbuild convert-ecfr` command — converts eCFR XML files to Markdown.\n */\n\nimport chalk from \"chalk\";\nimport { Command, Option } from \"commander\";\nimport { existsSync, readdirSync } from \"node:fs\";\nimport { join, relative, resolve } from \"node:path\";\nimport { convertEcfrTitle } from \"@lexbuild/ecfr\";\nimport type { EcfrConvertOptions, EcfrConvertResult } from \"@lexbuild/ecfr\";\nimport {\n createSpinner,\n summaryBlock,\n dataTable,\n formatDuration,\n formatBytes,\n formatNumber,\n success,\n error,\n} from \"../ui.js\";\nimport { parseTitles } from \"../parse-titles.js\";\n\n/** Parsed options from the convert-ecfr command */\ninterface ConvertEcfrCommandOptions {\n output: string;\n titles?: string | undefined;\n all: boolean;\n inputDir: string;\n granularity: \"section\" | \"part\" | \"chapter\" | \"title\";\n linkStyle: \"relative\" | \"canonical\" | \"plaintext\";\n includeSourceCredits: boolean;\n includeNotes: boolean;\n includeEditorialNotes: boolean;\n includeStatutoryNotes: boolean;\n includeAmendments: boolean;\n dryRun: boolean;\n verbose: boolean;\n}\n\n/** Build EcfrConvertOptions from CLI flags. */\nfunction buildConvertOptions(\n inputPath: string,\n outputPath: string,\n options: ConvertEcfrCommandOptions,\n): EcfrConvertOptions {\n const hasSelectiveFlags =\n options.includeEditorialNotes || options.includeStatutoryNotes || options.includeAmendments;\n const includeNotes = hasSelectiveFlags ? false : options.includeNotes;\n\n return {\n input: inputPath,\n output: outputPath,\n granularity: options.granularity,\n linkStyle: options.linkStyle,\n includeSourceCredits: options.includeSourceCredits,\n includeNotes,\n includeEditorialNotes: options.includeEditorialNotes,\n includeStatutoryNotes: options.includeStatutoryNotes,\n includeAmendments: options.includeAmendments,\n dryRun: options.dryRun,\n };\n}\n\n/** Regex matching eCFR XML filenames like ECFR-title1.xml, ECFR-title17.xml */\nconst ECFR_XML_RE = /^ECFR-title(\\d+)\\.xml$/;\n\n/** Resolve the XML file path for a given eCFR title number. */\nfunction titleXmlPath(inputDir: string, titleNum: number): string {\n return join(inputDir, `ECFR-title${titleNum}.xml`);\n}\n\n/** Scan a directory for eCFR XML files and return their title numbers, sorted. */\nfunction discoverEcfrTitles(inputDir: string): number[] {\n if (!existsSync(inputDir)) return [];\n\n return readdirSync(inputDir)\n .map((name) => ECFR_XML_RE.exec(name))\n .filter((m): m is RegExpExecArray => m !== null)\n .map((m) => parseInt(m[1] ?? \"0\", 10))\n .sort((a, b) => a - b);\n}\n\n/** Result from running a conversion including elapsed time. */\ninterface ConversionRun {\n result: EcfrConvertResult;\n elapsed: number;\n}\n\n/** Run a conversion without printing output. */\nasync function runConversion(\n inputPath: string,\n outputPath: string,\n options: ConvertEcfrCommandOptions,\n): Promise<ConversionRun> {\n const startTime = performance.now();\n const result = await convertEcfrTitle(buildConvertOptions(inputPath, outputPath, options));\n const elapsed = performance.now() - startTime;\n return { result, elapsed };\n}\n\n/** Convert a single file and print its detailed summary. */\nasync function convertSingleFile(\n inputPath: string,\n outputPath: string,\n options: ConvertEcfrCommandOptions,\n spinnerLabel: string,\n) {\n const spinner = createSpinner(spinnerLabel);\n spinner.start();\n\n try {\n const { result, elapsed } = await runConversion(inputPath, outputPath, options);\n spinner.stop();\n\n const rows: Array<[string, string]> = [];\n if (options.granularity === \"section\") {\n rows.push([\"Sections\", formatNumber(result.sectionsWritten)]);\n rows.push([\"Parts\", formatNumber(result.partCount)]);\n } else if (options.granularity === \"part\") {\n rows.push([\"Parts\", formatNumber(result.partCount)]);\n } else if (options.granularity === \"chapter\") {\n rows.push([\"Chapters\", formatNumber(result.sectionsWritten)]);\n }\n rows.push([\"Est. Tokens\", formatNumber(result.totalTokenEstimate)]);\n\n if (!result.dryRun) {\n rows.push([\"Files Written\", formatNumber(result.files.length)]);\n }\n\n rows.push(\n [\"Peak Memory\", formatBytes(result.peakMemoryBytes)],\n [\"Duration\", formatDuration(elapsed)],\n );\n\n const titleLabel = result.dryRun\n ? `lexbuild — eCFR Title ${result.titleNumber}: ${result.titleName} [dry-run]`\n : `lexbuild — eCFR Title ${result.titleNumber}: ${result.titleName}`;\n\n const outputRelative = relative(process.cwd(), outputPath) || outputPath;\n\n const output = summaryBlock({\n title: titleLabel,\n rows: [...rows, [\"Output\", outputRelative]],\n footer: result.dryRun ? success(\"Dry run complete\") : success(\"Conversion complete\"),\n });\n process.stdout.write(output);\n\n if (options.verbose && !result.dryRun && result.files.length > 0) {\n console.log(\" Files written:\");\n for (const file of result.files) {\n console.log(` ${relative(process.cwd(), file) || file}`);\n }\n console.log(\"\");\n }\n\n return result;\n } catch (err) {\n spinner.fail(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n}\n\nexport const convertEcfrCommand = new Command(\"convert-ecfr\")\n .description(\"Convert eCFR XML file(s) to Markdown\")\n .argument(\"[input]\", \"Path to an eCFR XML file\")\n .option(\"-o, --output <dir>\", \"Output directory\", \"./output\")\n .option(\"--titles <spec>\", \"Title(s) to convert: 1, 1-5, or 1-5,17\")\n .option(\"--all\", \"Convert all downloaded eCFR titles found in --input-dir\", false)\n .option(\"-i, --input-dir <dir>\", \"Directory containing eCFR XML files\", \"./downloads/ecfr/xml\")\n .addOption(\n new Option(\"-g, --granularity <level>\", \"Output granularity: section, part, chapter, or title\")\n .choices([\"section\", \"part\", \"chapter\", \"title\"])\n .default(\"section\"),\n )\n .addOption(\n new Option(\"--link-style <style>\", \"Link style: relative, canonical, or plaintext\")\n .choices([\"relative\", \"canonical\", \"plaintext\"])\n .default(\"plaintext\"),\n )\n .option(\"--include-source-credits\", \"Include source credit annotations\", true)\n .option(\"--no-include-source-credits\", \"Exclude source credit annotations\")\n .option(\"--include-notes\", \"Include all notes (default)\", true)\n .option(\"--no-include-notes\", \"Exclude all notes\")\n .option(\"--include-editorial-notes\", \"Include editorial notes only\", false)\n .option(\"--include-statutory-notes\", \"Include statutory/regulatory notes only\", false)\n .option(\"--include-amendments\", \"Include amendment history notes only\", false)\n .option(\"--dry-run\", \"Parse and report structure without writing files\", false)\n .option(\"-v, --verbose\", \"Enable verbose logging\", false)\n .addHelpText(\n \"after\",\n `\nInput modes (use exactly one):\n <input> Convert a single eCFR XML file\n --titles Convert specific titles by number\n --all Convert all titles in --input-dir\n\nGranularity:\n section One .md file per section (default)\n part One .md file per part, sections inlined\n chapter One .md file per chapter, parts and sections inlined\n title One .md file per title, entire hierarchy inlined\n\nExamples:\n $ lexbuild convert-ecfr --titles 1 Convert eCFR Title 1\n $ lexbuild convert-ecfr --titles 1-5,17 Convert specific titles\n $ lexbuild convert-ecfr --all -g part All titles, part-level\n $ lexbuild convert-ecfr --all --dry-run Preview stats only\n $ lexbuild convert-ecfr ./downloads/ecfr/xml/ECFR-title1.xml -o ./out`,\n )\n .action(async (input: string | undefined, options: ConvertEcfrCommandOptions) => {\n const modeCount = [input, options.titles, options.all].filter(Boolean).length;\n if (modeCount === 0) {\n console.error(\n error(\"Specify an input file, --titles <spec>, or --all (e.g. --titles 1-5,17)\"),\n );\n process.exit(1);\n }\n if (modeCount > 1) {\n console.error(error(\"Cannot combine <input>, --titles, and --all — use only one\"));\n process.exit(1);\n }\n\n const outputPath = resolve(options.output);\n const dryRunLabel = options.dryRun ? \" [dry-run]\" : \"\";\n\n // Single-file mode\n if (input) {\n const inputPath = resolve(input);\n if (!existsSync(inputPath)) {\n console.error(error(`Input file not found: ${inputPath}`));\n process.exit(1);\n }\n await convertSingleFile(inputPath, outputPath, options, `Converting eCFR${dryRunLabel}...`);\n return;\n }\n\n // Multi-title mode\n let titles: number[];\n if (options.all) {\n const inputDir = resolve(options.inputDir);\n titles = discoverEcfrTitles(inputDir);\n if (titles.length === 0) {\n console.error(error(`No eCFR XML files found in ${inputDir}`));\n process.exit(1);\n }\n } else {\n const titlesSpec = options.titles as string;\n try {\n titles = parseTitles(titlesSpec, 50);\n } catch (err) {\n console.error(error(err instanceof Error ? err.message : String(err)));\n process.exit(1);\n }\n }\n\n const inputDir = resolve(options.inputDir);\n const totalTitles = titles.length;\n const results: ConversionRun[] = [];\n\n const spinner = createSpinner(`Converting eCFR${dryRunLabel}...`);\n spinner.start();\n\n for (const [i, titleNum] of titles.entries()) {\n const xmlPath = titleXmlPath(inputDir, titleNum);\n\n if (!existsSync(xmlPath)) {\n spinner.stop();\n console.error(error(`XML file not found: ${xmlPath}`));\n process.exit(1);\n }\n\n spinner.text = `Converting eCFR Title ${titleNum}${dryRunLabel} (${i + 1}/${totalTitles})...`;\n\n try {\n const run = await runConversion(xmlPath, outputPath, options);\n results.push(run);\n } catch (err) {\n spinner.fail(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n }\n\n spinner.stop();\n\n const outputRelative = relative(process.cwd(), outputPath) || outputPath;\n const headerTitle = options.dryRun\n ? \"lexbuild — eCFR Conversion Summary [dry-run]\"\n : \"lexbuild — eCFR Conversion Summary\";\n const header = summaryBlock({\n title: headerTitle,\n rows: [[\"Directory\", outputRelative]],\n });\n process.stdout.write(header);\n\n const granularity = options.granularity;\n let totalSections = 0;\n let totalParts = 0;\n let totalTokens = 0;\n let totalElapsed = 0;\n\n const tableRows = results.map(({ result, elapsed }) => {\n totalSections += result.sectionsWritten;\n totalParts += result.partCount;\n totalTokens += result.totalTokenEstimate;\n totalElapsed += elapsed;\n\n if (granularity === \"title\") {\n return [\n result.titleNumber,\n result.titleName,\n formatNumber(result.totalTokenEstimate),\n formatDuration(elapsed),\n ];\n } else if (granularity === \"chapter\") {\n return [\n result.titleNumber,\n result.titleName,\n formatNumber(result.sectionsWritten),\n formatNumber(result.totalTokenEstimate),\n formatDuration(elapsed),\n ];\n } else if (granularity === \"part\") {\n return [\n result.titleNumber,\n result.titleName,\n formatNumber(result.partCount),\n formatNumber(result.totalTokenEstimate),\n formatDuration(elapsed),\n ];\n } else {\n return [\n result.titleNumber,\n result.titleName,\n formatNumber(result.partCount),\n formatNumber(result.sectionsWritten),\n formatNumber(result.totalTokenEstimate),\n formatDuration(elapsed),\n ];\n }\n });\n\n if (granularity === \"title\") {\n tableRows.push([\n chalk.bold(\"Total\"),\n \"\",\n chalk.bold(formatNumber(totalTokens)),\n chalk.bold(formatDuration(totalElapsed)),\n ]);\n } else if (granularity === \"chapter\") {\n tableRows.push([\n chalk.bold(\"Total\"),\n \"\",\n chalk.bold(formatNumber(totalSections)),\n chalk.bold(formatNumber(totalTokens)),\n chalk.bold(formatDuration(totalElapsed)),\n ]);\n } else if (granularity === \"part\") {\n tableRows.push([\n chalk.bold(\"Total\"),\n \"\",\n chalk.bold(formatNumber(totalParts)),\n chalk.bold(formatNumber(totalTokens)),\n chalk.bold(formatDuration(totalElapsed)),\n ]);\n } else {\n tableRows.push([\n chalk.bold(\"Total\"),\n \"\",\n chalk.bold(formatNumber(totalParts)),\n chalk.bold(formatNumber(totalSections)),\n chalk.bold(formatNumber(totalTokens)),\n chalk.bold(formatDuration(totalElapsed)),\n ]);\n }\n\n const tableHeaders =\n granularity === \"title\"\n ? [\"Title\", \"Name\", \"Tokens\", \"Duration\"]\n : granularity === \"chapter\"\n ? [\"Title\", \"Name\", \"Chapters\", \"Tokens\", \"Duration\"]\n : granularity === \"part\"\n ? [\"Title\", \"Name\", \"Parts\", \"Tokens\", \"Duration\"]\n : [\"Title\", \"Name\", \"Parts\", \"Sections\", \"Tokens\", \"Duration\"];\n\n console.log(dataTable(tableHeaders, tableRows));\n\n // Footer — show the primary unit that was converted\n let countLabel: string;\n if (granularity === \"title\") {\n const titleWord = totalTitles === 1 ? \"title\" : \"titles\";\n countLabel = `${formatNumber(totalTitles)} ${titleWord}`;\n } else if (granularity === \"chapter\") {\n const chapterWord = totalSections === 1 ? \"chapter\" : \"chapters\";\n countLabel = `${formatNumber(totalSections)} ${chapterWord}`;\n } else if (granularity === \"part\") {\n const partWord = totalParts === 1 ? \"part\" : \"parts\";\n countLabel = `${formatNumber(totalParts)} ${partWord}`;\n } else {\n const sectionWord = totalSections === 1 ? \"section\" : \"sections\";\n countLabel = `${formatNumber(totalSections)} ${sectionWord}`;\n }\n console.log(`\\n ${success(`Converted ${countLabel} in ${formatDuration(totalElapsed)}`)}`);\n console.log(\"\");\n });\n","/**\n * `lexbuild download-ecfr` command — downloads eCFR XML from govinfo or eCFR API.\n */\n\nimport { Command } from \"commander\";\nimport { relative, resolve } from \"node:path\";\nimport { downloadEcfrTitles, downloadEcfrTitlesFromApi, fetchEcfrTitlesMeta } from \"@lexbuild/ecfr\";\nimport type { EcfrTitlesResponse } from \"@lexbuild/ecfr\";\nimport {\n createSpinner,\n summaryBlock,\n dataTable,\n formatDuration,\n formatBytes,\n success,\n error,\n} from \"../ui.js\";\nimport { parseTitles } from \"../parse-titles.js\";\n\n/** Valid download source values */\ntype EcfrSource = \"govinfo\" | \"ecfr-api\";\n\n/** Parsed options from the download-ecfr command */\ninterface DownloadEcfrOptions {\n output: string;\n titles?: string | undefined;\n all: boolean;\n source: EcfrSource;\n date?: string | undefined;\n}\n\nexport const downloadEcfrCommand = new Command(\"download-ecfr\")\n .description(\"Download eCFR XML from govinfo or eCFR API\")\n .option(\"-o, --output <dir>\", \"Download directory\", \"./downloads/ecfr/xml\")\n .option(\"--titles <spec>\", \"Title(s) to download: 1, 1-5, or 1-5,8,17\")\n .option(\"--all\", \"Download all 50 eCFR titles\", false)\n .option(\n \"--source <source>\",\n \"Download source: ecfr-api (daily-updated) or govinfo (bulk data)\",\n \"ecfr-api\",\n )\n .option(\"--date <YYYY-MM-DD>\", \"Point-in-time date (ecfr-api source only)\")\n .addHelpText(\n \"after\",\n `\nExamples:\n $ lexbuild download-ecfr --all Download all titles from eCFR API\n $ lexbuild download-ecfr --titles 1 Download Title 1 only\n $ lexbuild download-ecfr --titles 1-5,17 Download specific titles\n $ lexbuild download-ecfr --all --date 2026-01-01 Point-in-time download\n $ lexbuild download-ecfr --all --source govinfo Download from govinfo bulk data\n\nSources:\n ecfr-api — eCFR API from ecfr.gov (default, daily-updated, point-in-time support)\n govinfo — Bulk XML from govinfo.gov (updates irregularly)`,\n )\n .action(async (options: DownloadEcfrOptions) => {\n if (!options.titles && !options.all) {\n console.error(error(\"Specify --titles <spec> or --all (e.g. --titles 1-5,17)\"));\n process.exit(1);\n }\n\n // Validate source\n const validSources: EcfrSource[] = [\"govinfo\", \"ecfr-api\"];\n if (!validSources.includes(options.source)) {\n console.error(\n error(`Invalid source \"${options.source}\". Valid sources: ${validSources.join(\", \")}`),\n );\n process.exit(1);\n }\n\n // --date is only valid with ecfr-api source\n if (options.date && options.source !== \"ecfr-api\") {\n console.error(error(\"--date is only supported with --source ecfr-api\"));\n process.exit(1);\n }\n\n // Validate date format if provided\n if (options.date && !/^\\d{4}-\\d{2}-\\d{2}$/.test(options.date)) {\n console.error(error(\"--date must be in YYYY-MM-DD format\"));\n process.exit(1);\n }\n\n let titles: number[] | undefined;\n if (options.titles) {\n try {\n titles = parseTitles(options.titles, 50);\n } catch (err) {\n console.error(error(err instanceof Error ? err.message : String(err)));\n process.exit(1);\n }\n }\n\n const outputDir = resolve(options.output);\n const titleCount = titles ? titles.length : 50;\n const sourceLabel = options.source === \"ecfr-api\" ? \"eCFR API\" : \"govinfo\";\n\n // For ecfr-api, fetch metadata upfront to resolve dates and display status\n let meta: EcfrTitlesResponse | undefined;\n if (options.source === \"ecfr-api\" && !options.date) {\n const metaSpinner = createSpinner(\"Fetching eCFR title metadata...\");\n metaSpinner.start();\n try {\n meta = await fetchEcfrTitlesMeta();\n metaSpinner.succeed(\"eCFR title metadata loaded\");\n } catch (err) {\n metaSpinner.fail(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n }\n\n // Build spinner label with date info\n let dateLabel = \"\";\n let statusNote = \"\";\n if (options.date) {\n dateLabel = ` as of ${options.date}`;\n } else if (meta) {\n const primaryDate = meta.importInProgress\n ? (() => {\n const prev = new Date(meta.date);\n prev.setDate(prev.getDate() - 1);\n return prev.toISOString().slice(0, 10);\n })()\n : meta.date;\n dateLabel = ` as of ${primaryDate}`;\n\n // Check for titles with individual processing\n const processingTitles = meta.titles.filter((t) => t.processingInProgress && !t.reserved);\n if (meta.importInProgress && processingTitles.length > 0) {\n const titleWord = processingTitles.length === 1 ? \"title uses\" : \"titles use\";\n statusNote = ` (import in progress, ${processingTitles.length} ${titleWord} earlier dates)`;\n } else if (meta.importInProgress) {\n statusNote = \" (import in progress, using previous day)\";\n } else if (processingTitles.length > 0) {\n const nums = processingTitles.map((t) => t.number).join(\", \");\n statusNote = ` (Title ${nums} processing, using earlier date)`;\n }\n }\n\n const label =\n titleCount === 1\n ? `Downloading eCFR Title ${titles?.[0]} from ${sourceLabel}${dateLabel}${statusNote}`\n : `Downloading ${titleCount} eCFR titles from ${sourceLabel}${dateLabel}${statusNote}`;\n\n const spinner = createSpinner(`${label}...`);\n spinner.start();\n\n const startTime = performance.now();\n\n try {\n if (options.source === \"ecfr-api\") {\n await downloadFromApi(options, titles, outputDir, spinner, startTime, meta);\n } else {\n await downloadFromGovinfo(titles, outputDir, spinner, startTime);\n }\n } catch (err) {\n spinner.fail(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n });\n\n/** Download from govinfo bulk data (existing behavior) */\nasync function downloadFromGovinfo(\n titles: number[] | undefined,\n outputDir: string,\n spinner: ReturnType<typeof createSpinner>,\n startTime: number,\n): Promise<void> {\n const result = await downloadEcfrTitles({\n output: outputDir,\n titles,\n onProgress: ({ current, total, titleNumber }) => {\n if (total === 1) {\n spinner.text = `Downloading eCFR Title ${titleNumber} from govinfo`;\n } else {\n spinner.text = `Downloading eCFR titles from govinfo (${current}/${total}) — Title ${titleNumber}`;\n }\n },\n });\n\n const elapsed = performance.now() - startTime;\n spinner.stop();\n\n const fileRows = result.files.map((file) => [\n String(file.titleNumber),\n formatBytes(file.size),\n relative(outputDir, file.path) || file.path,\n ]);\n\n const output = summaryBlock({\n title: \"lexbuild — eCFR Download Summary\",\n rows: [\n [\"Source\", \"govinfo.gov/bulkdata/ECFR\"],\n [\"Directory\", relative(process.cwd(), outputDir) || outputDir],\n ],\n });\n process.stdout.write(output);\n\n if (fileRows.length > 0) {\n console.log(dataTable([\"Title\", \"Size\", \"File\"], fileRows));\n }\n\n if (result.errors.length > 0) {\n for (const err of result.errors) {\n console.log(` ${error(`Title ${err.titleNumber}: ${err.error}`)}`);\n }\n }\n\n const titleWord = result.titlesDownloaded === 1 ? \"title\" : \"titles\";\n const failSuffix = result.errors.length > 0 ? ` (${result.errors.length} failed)` : \"\";\n const summary = `Downloaded ${result.titlesDownloaded} ${titleWord} (${formatBytes(result.totalBytes)}) in ${formatDuration(elapsed)}`;\n console.log(` ${success(summary + failSuffix)}`);\n console.log(\"\");\n}\n\n/** Download from eCFR API (daily-updated, point-in-time) */\nasync function downloadFromApi(\n options: DownloadEcfrOptions,\n titles: number[] | undefined,\n outputDir: string,\n spinner: ReturnType<typeof createSpinner>,\n startTime: number,\n meta?: EcfrTitlesResponse,\n): Promise<void> {\n const result = await downloadEcfrTitlesFromApi({\n output: outputDir,\n titles,\n date: options.date,\n titlesMeta: meta,\n onProgress: ({ current, total, titleNumber }) => {\n if (total === 1) {\n spinner.text = `Downloading eCFR Title ${titleNumber} from eCFR API`;\n } else {\n spinner.text = `Downloading eCFR titles from eCFR API (${current}/${total}) — Title ${titleNumber}`;\n }\n },\n });\n\n const elapsed = performance.now() - startTime;\n spinner.stop();\n\n // Check if any titles used different dates\n const uniqueDates = new Set(result.files.map((f) => f.asOfDate));\n const dateDisplay =\n uniqueDates.size <= 1\n ? result.asOfDate\n : `${result.asOfDate} (${uniqueDates.size - 1} titles at earlier dates)`;\n\n const fileRows = result.files.map((file) => {\n const row = [\n String(file.titleNumber),\n formatBytes(file.size),\n relative(outputDir, file.path) || file.path,\n ];\n // Show the date if it differs from the primary\n if (file.asOfDate !== result.asOfDate) {\n row.push(file.asOfDate);\n }\n return row;\n });\n\n const summaryRows: [string, string][] = [\n [\"Source\", \"ecfr.gov/api/versioner/v1\"],\n [\"As of date\", dateDisplay],\n [\"Directory\", relative(process.cwd(), outputDir) || outputDir],\n ];\n\n const output = summaryBlock({\n title: \"lexbuild — eCFR Download Summary\",\n rows: summaryRows,\n });\n process.stdout.write(output);\n\n // Include date column only if some titles used different dates\n const hasMultipleDates = uniqueDates.size > 1;\n const headings = hasMultipleDates ? [\"Title\", \"Size\", \"File\", \"Date\"] : [\"Title\", \"Size\", \"File\"];\n\n if (fileRows.length > 0) {\n console.log(dataTable(headings, fileRows));\n }\n\n // Report failures with context\n if (result.failed.length > 0) {\n const processing = result.failed.filter((f) => f.status === 503);\n const other = result.failed.filter((f) => f.status !== 503);\n\n if (processing.length > 0) {\n const nums = processing.map((f) => `Title ${f.titleNumber}`).join(\", \");\n console.log(` ${error(`Unavailable (processing on server): ${nums}`)}`);\n console.log(` The eCFR API cannot serve these titles while an import is in progress.`);\n console.log(\n ` Re-run this command later to download them. Existing local files (if any) are preserved.`,\n );\n }\n if (other.length > 0) {\n const nums = other.map((f) => `Title ${f.titleNumber} (${f.status})`).join(\", \");\n console.log(` ${error(`Failed: ${nums}`)}`);\n }\n }\n\n const titleWord = result.titlesDownloaded === 1 ? \"title\" : \"titles\";\n const failSuffix = result.failed.length > 0 ? ` (${result.failed.length} failed)` : \"\";\n const summary = `Downloaded ${result.titlesDownloaded} ${titleWord} (${formatBytes(result.totalBytes)}) in ${formatDuration(elapsed)}`;\n console.log(` ${success(summary + failSuffix)}`);\n console.log(\"\");\n}\n","/**\n * `lexbuild download-fr` command — downloads Federal Register XML + JSON.\n *\n * Supports two sources:\n * - `fr-api` (default): Per-document XML + JSON metadata from FederalRegister.gov API\n * - `govinfo`: Bulk daily-issue XML from govinfo.gov (faster for historical backfill)\n */\n\nimport { Command } from \"commander\";\nimport { relative, resolve } from \"node:path\";\nimport { downloadFrDocuments, downloadSingleFrDocument, downloadFrBulk } from \"@lexbuild/fr\";\nimport type { FrDocumentType } from \"@lexbuild/fr\";\nimport {\n createSpinner,\n summaryBlock,\n formatDuration,\n formatBytes,\n formatNumber,\n error,\n} from \"../ui.js\";\n\n/** Valid document type values for --types flag */\nconst VALID_TYPES = new Map<string, FrDocumentType>([\n [\"rule\", \"RULE\"],\n [\"proposed_rule\", \"PRORULE\"],\n [\"notice\", \"NOTICE\"],\n [\"presidential_document\", \"PRESDOCU\"],\n]);\n\n/** Parsed options from the download-fr command */\ninterface DownloadFrOptions {\n output: string;\n source: string;\n from?: string | undefined;\n to?: string | undefined;\n types?: string | undefined;\n recent?: string | undefined;\n document?: string | undefined;\n limit?: string | undefined;\n concurrency?: string | undefined;\n}\n\nexport const downloadFrCommand = new Command(\"download-fr\")\n .description(\"Download Federal Register XML and metadata\")\n .option(\"-o, --output <dir>\", \"Download directory\", \"./downloads/fr\")\n .option(\n \"--source <source>\",\n \"Source: fr-api (default, per-document) or govinfo (bulk daily)\",\n \"fr-api\",\n )\n .option(\"--from <YYYY-MM-DD>\", \"Start date (inclusive)\")\n .option(\"--to <YYYY-MM-DD>\", \"End date (inclusive, defaults to today)\")\n .option(\n \"--types <types>\",\n \"Document types: rule, proposed_rule, notice, presidential_document (fr-api only)\",\n )\n .option(\"--recent <days>\", \"Download last N days\")\n .option(\"--document <number>\", \"Download a single document by number (fr-api only)\")\n .option(\"--limit <n>\", \"Maximum number of documents (fr-api only)\")\n .option(\"--concurrency <n>\", \"Concurrent downloads (default: 10)\")\n .addHelpText(\n \"after\",\n `\nExamples:\n $ lexbuild download-fr --from 2026-01-01 --to 2026-03-31\n $ lexbuild download-fr --from 2026-01-01 --types rule,proposed_rule\n $ lexbuild download-fr --recent 30\n $ lexbuild download-fr --document 2026-06029\n $ lexbuild download-fr --source govinfo --from 2000-01-01 --to 2025-12-31\n\nSources:\n fr-api (default) Per-document XML + JSON from FederalRegister.gov API\n govinfo Bulk daily-issue XML from govinfo.gov (faster for backfill)\n\nDocument types (fr-api only):\n rule Final rules\n proposed_rule Proposed rules (NPRMs)\n notice Notices\n presidential_document Executive orders, memoranda, proclamations`,\n )\n .action(async (options: DownloadFrOptions) => {\n // Validate source\n if (options.source !== \"fr-api\" && options.source !== \"govinfo\") {\n console.error(\n error(`Invalid source \"${options.source}\". Use \"fr-api\" (default) or \"govinfo\".`),\n );\n process.exit(1);\n }\n\n // Validate: need --from, --recent, or --document\n if (!options.from && !options.recent && !options.document) {\n console.error(\n error(\n \"Specify --from <date>, --recent <days>, or --document <number>\\n\" +\n \"Examples: --from 2026-01-01, --recent 30, --document 2026-06029\",\n ),\n );\n process.exit(1);\n }\n\n // Validate date format\n if (options.from && !/^\\d{4}-\\d{2}-\\d{2}$/.test(options.from)) {\n console.error(error(\"--from must be in YYYY-MM-DD format\"));\n process.exit(1);\n }\n if (options.to && !/^\\d{4}-\\d{2}-\\d{2}$/.test(options.to)) {\n console.error(error(\"--to must be in YYYY-MM-DD format\"));\n process.exit(1);\n }\n\n const outputDir = resolve(options.output);\n const startTime = performance.now();\n\n // Parse concurrency\n let concurrency: number | undefined;\n if (options.concurrency) {\n concurrency = parseInt(options.concurrency, 10);\n if (isNaN(concurrency) || concurrency <= 0) {\n console.error(error(\"--concurrency must be a positive integer\"));\n process.exit(1);\n }\n }\n\n // ── Govinfo bulk mode ──\n if (options.source === \"govinfo\") {\n await downloadGovinfo(options, outputDir, startTime, concurrency);\n return;\n }\n\n // ── FR API: Single document mode ──\n if (options.document) {\n const spinner = createSpinner(`Downloading FR document ${options.document}`);\n try {\n const file = await downloadSingleFrDocument(options.document, outputDir);\n spinner.succeed(`Downloaded FR document ${options.document}`);\n console.log();\n console.log(\n summaryBlock({\n title: \"Download Complete\",\n rows: [\n [\"Document\", file.documentNumber],\n [\"Date\", file.publicationDate],\n [\"Size\", formatBytes(file.size)],\n [\"XML\", relative(process.cwd(), file.xmlPath)],\n [\"JSON\", relative(process.cwd(), file.jsonPath)],\n ],\n }),\n );\n } catch (err) {\n spinner.fail(`Failed to download ${options.document}`);\n console.error(error(err instanceof Error ? err.message : String(err)));\n process.exit(1);\n }\n return;\n }\n\n // ── FR API: Date range mode ──\n await downloadFrApi(options, outputDir, startTime, concurrency);\n });\n\n// ── Govinfo bulk download ──\n\nasync function downloadGovinfo(\n options: DownloadFrOptions,\n outputDir: string,\n startTime: number,\n concurrency: number | undefined,\n): Promise<void> {\n let from: string;\n if (options.recent) {\n const days = parseInt(options.recent, 10);\n if (isNaN(days) || days <= 0) {\n console.error(error(\"--recent must be a positive integer\"));\n process.exit(1);\n }\n const d = new Date();\n d.setDate(d.getDate() - days);\n from = d.toISOString().slice(0, 10);\n } else {\n from = options.from ?? \"\";\n }\n const to = options.to ?? new Date().toISOString().slice(0, 10);\n\n const spinner = createSpinner(`Downloading FR bulk XML from govinfo (${from} to ${to})`);\n spinner.start();\n\n try {\n const result = await downloadFrBulk({\n output: outputDir,\n from,\n to,\n concurrency,\n onProgress: (progress) => {\n const pct =\n progress.totalDays > 0 ? Math.round((progress.downloaded / progress.totalDays) * 100) : 0;\n spinner.text = `Downloading FR bulk XML (${formatNumber(progress.downloaded + progress.skipped)}/${formatNumber(progress.totalDays)}) ${pct}% ${progress.currentDate}`;\n },\n });\n\n const elapsed = performance.now() - startTime;\n spinner.succeed(\n `Downloaded ${formatNumber(result.filesDownloaded)} daily FR issues from govinfo`,\n );\n\n console.log();\n const rows: [string, string][] = [\n [\"Source\", \"govinfo (bulk daily XML)\"],\n [\"Date range\", `${result.dateRange.from} → ${result.dateRange.to}`],\n [\"Daily issues\", formatNumber(result.filesDownloaded)],\n [\"Total size\", formatBytes(result.totalBytes)],\n [\"Skipped (no issue)\", formatNumber(result.skipped)],\n [\"Duration\", formatDuration(elapsed)],\n ];\n if (result.failed > 0) {\n rows.push([\"Failed\", formatNumber(result.failed)]);\n }\n rows.push([\"Output\", relative(process.cwd(), outputDir)]);\n\n console.log(summaryBlock({ title: \"Download Complete\", rows }));\n } catch (err) {\n spinner.fail(\"Download failed\");\n console.error(error(err instanceof Error ? err.message : String(err)));\n process.exit(1);\n }\n}\n\n// ── FR API date range download ──\n\nasync function downloadFrApi(\n options: DownloadFrOptions,\n outputDir: string,\n startTime: number,\n concurrency: number | undefined,\n): Promise<void> {\n // Parse --types\n let types: FrDocumentType[] | undefined;\n if (options.types) {\n types = [];\n for (const raw of options.types.split(\",\")) {\n const normalized = raw.trim().toLowerCase();\n const mapped = VALID_TYPES.get(normalized);\n if (!mapped) {\n console.error(\n error(\n `Invalid document type \"${raw.trim()}\". Valid types: ${[...VALID_TYPES.keys()].join(\", \")}`,\n ),\n );\n process.exit(1);\n }\n types.push(mapped);\n }\n }\n\n let from: string;\n if (options.recent) {\n const days = parseInt(options.recent, 10);\n if (isNaN(days) || days <= 0) {\n console.error(error(\"--recent must be a positive integer\"));\n process.exit(1);\n }\n const d = new Date();\n d.setDate(d.getDate() - days);\n from = d.toISOString().slice(0, 10);\n } else {\n from = options.from ?? \"\";\n }\n\n const to = options.to ?? new Date().toISOString().slice(0, 10);\n let limit: number | undefined;\n if (options.limit) {\n limit = parseInt(options.limit, 10);\n if (isNaN(limit) || limit <= 0) {\n console.error(error(\"--limit must be a positive integer\"));\n process.exit(1);\n }\n }\n\n const spinner = createSpinner(`Downloading Federal Register documents from ${from} to ${to}`);\n spinner.start();\n\n try {\n const result = await downloadFrDocuments({\n output: outputDir,\n from,\n to,\n types,\n limit,\n concurrency,\n onProgress: (progress) => {\n const pct =\n progress.totalDocuments > 0\n ? Math.round((progress.documentsDownloaded / progress.totalDocuments) * 100)\n : 0;\n spinner.text = `Downloading FR documents (${formatNumber(progress.documentsDownloaded)}/${formatNumber(progress.totalDocuments)}) ${pct}% [${progress.currentChunk}] ${progress.currentDocument}`;\n },\n });\n\n const elapsed = performance.now() - startTime;\n spinner.succeed(\n `Downloaded ${formatNumber(result.documentsDownloaded)} Federal Register documents`,\n );\n\n console.log();\n const rows: [string, string][] = [\n [\"Source\", \"FederalRegister.gov API\"],\n [\"Date range\", `${result.dateRange.from} → ${result.dateRange.to}`],\n [\"Documents\", formatNumber(result.documentsDownloaded)],\n [\"Total size\", formatBytes(result.totalBytes)],\n [\"Duration\", formatDuration(elapsed)],\n ];\n if (types) {\n rows.push([\"Types\", types.join(\", \")]);\n }\n if (result.skipped > 0) {\n rows.push([\"Skipped (no XML)\", formatNumber(result.skipped)]);\n }\n if (result.failed.length > 0) {\n rows.push([\"Failed\", formatNumber(result.failed.length)]);\n }\n rows.push([\"Output\", relative(process.cwd(), outputDir)]);\n\n console.log(summaryBlock({ title: \"Download Complete\", rows }));\n\n if (result.failed.length > 0) {\n console.log();\n console.log(error(`${result.failed.length} document(s) failed to download:`));\n for (const f of result.failed.slice(0, 10)) {\n console.error(` ${f.documentNumber}: ${f.error}`);\n }\n if (result.failed.length > 10) {\n console.error(` ... and ${result.failed.length - 10} more`);\n }\n }\n } catch (err) {\n spinner.fail(\"Download failed\");\n console.error(error(err instanceof Error ? err.message : String(err)));\n process.exit(1);\n }\n}\n","/**\n * `lexbuild convert-fr` command — converts Federal Register XML files to Markdown.\n */\n\nimport { Command } from \"commander\";\nimport { existsSync } from \"node:fs\";\nimport { relative, resolve } from \"node:path\";\nimport { convertFrDocuments } from \"@lexbuild/fr\";\nimport type { FrDocumentType } from \"@lexbuild/fr\";\nimport { createSpinner, summaryBlock, formatDuration, formatNumber, error } from \"../ui.js\";\n\n/** Valid document type values for --types flag */\nconst VALID_TYPES = new Map<string, FrDocumentType>([\n [\"rule\", \"RULE\"],\n [\"proposed_rule\", \"PRORULE\"],\n [\"notice\", \"NOTICE\"],\n [\"presidential_document\", \"PRESDOCU\"],\n]);\n\n/** Parsed options from the convert-fr command */\ninterface ConvertFrCommandOptions {\n output: string;\n inputDir: string;\n all: boolean;\n from?: string | undefined;\n to?: string | undefined;\n types?: string | undefined;\n linkStyle: \"relative\" | \"canonical\" | \"plaintext\";\n dryRun: boolean;\n verbose: boolean;\n}\n\nexport const convertFrCommand = new Command(\"convert-fr\")\n .description(\"Convert Federal Register XML to Markdown\")\n .argument(\"[input]\", \"Path to single FR XML file (optional)\")\n .option(\"-o, --output <dir>\", \"Output directory\", \"./output\")\n .option(\"-i, --input-dir <dir>\", \"Directory containing downloaded FR files\", \"./downloads/fr\")\n .option(\"--all\", \"Convert all downloaded documents in input directory\", false)\n .option(\"--from <YYYY-MM-DD>\", \"Filter: start date\")\n .option(\"--to <YYYY-MM-DD>\", \"Filter: end date\")\n .option(\n \"--types <types>\",\n \"Filter: document types (rule, proposed_rule, notice, presidential_document)\",\n )\n .option(\"--link-style <style>\", \"Link style: relative, canonical, plaintext\", \"plaintext\")\n .option(\"--dry-run\", \"Parse only, don't write files\", false)\n .option(\"-v, --verbose\", \"Print detailed file output\", false)\n .addHelpText(\n \"after\",\n `\nExamples:\n $ lexbuild convert-fr --all Convert all downloaded FR documents\n $ lexbuild convert-fr --from 2026-01-01 --to 2026-03-31 Convert by date range\n $ lexbuild convert-fr --all --types rule Convert only rules\n $ lexbuild convert-fr ./downloads/fr/2026/03/2026-06029.xml Convert single document\n $ lexbuild convert-fr --all --dry-run Preview without writing files`,\n )\n .action(async (inputArg: string | undefined, options: ConvertFrCommandOptions) => {\n // Validate: need [input], --all, or --from\n if (!inputArg && !options.all && !options.from) {\n console.error(\n error(\n \"Specify a path to an XML file, --all, or --from <date>\\n\" +\n \"Examples: convert-fr --all, convert-fr --from 2026-01-01\",\n ),\n );\n process.exit(1);\n }\n\n // Parse --types\n let types: FrDocumentType[] | undefined;\n if (options.types) {\n types = [];\n for (const raw of options.types.split(\",\")) {\n const normalized = raw.trim().toLowerCase();\n const mapped = VALID_TYPES.get(normalized);\n if (!mapped) {\n console.error(\n error(\n `Invalid document type \"${raw.trim()}\". Valid types: ${[...VALID_TYPES.keys()].join(\", \")}`,\n ),\n );\n process.exit(1);\n }\n types.push(mapped);\n }\n }\n\n // Determine input path\n let inputPath: string;\n if (inputArg) {\n inputPath = resolve(inputArg);\n if (!existsSync(inputPath)) {\n console.error(error(`File not found: ${inputArg}`));\n process.exit(1);\n }\n } else {\n inputPath = resolve(options.inputDir);\n if (!existsSync(inputPath)) {\n console.error(error(`Input directory not found: ${options.inputDir}`));\n process.exit(1);\n }\n }\n\n const outputPath = resolve(options.output);\n const startTime = performance.now();\n\n const spinner = createSpinner(\n options.dryRun\n ? \"Analyzing Federal Register documents (dry run)\"\n : \"Converting Federal Register documents\",\n );\n spinner.start();\n\n try {\n const result = await convertFrDocuments({\n input: inputPath,\n output: outputPath,\n linkStyle: options.linkStyle,\n dryRun: options.dryRun,\n from: options.from,\n to: options.to,\n types,\n onProgress: (progress) => {\n const pct =\n progress.totalFiles > 0\n ? Math.round((progress.filesProcessed / progress.totalFiles) * 100)\n : 0;\n spinner.text = `Converting FR documents (${formatNumber(progress.documentsConverted)} docs, ${formatNumber(progress.filesProcessed)}/${formatNumber(progress.totalFiles)} files) ${pct}%`;\n },\n });\n\n const elapsed = performance.now() - startTime;\n\n if (options.dryRun) {\n spinner.succeed(\n `Dry run: ${formatNumber(result.documentsConverted)} documents would be converted`,\n );\n } else {\n spinner.succeed(\n `Converted ${formatNumber(result.documentsConverted)} Federal Register documents`,\n );\n }\n\n console.log();\n\n const rows: [string, string][] = [[\"Documents\", formatNumber(result.documentsConverted)]];\n\n if (!options.dryRun) {\n rows.push([\"Est. tokens\", formatNumber(result.totalTokenEstimate)]);\n }\n\n rows.push([\"Duration\", formatDuration(elapsed)]);\n\n if (!options.dryRun) {\n rows.push([\"Output\", relative(process.cwd(), outputPath) + \"/fr/\"]);\n }\n\n const footer = options.dryRun\n ? undefined\n : `Converted ${formatNumber(result.documentsConverted)} documents in ${formatDuration(elapsed)}`;\n\n console.log(summaryBlock({ title: \"Conversion Complete\", rows, footer }));\n\n // Verbose file listing not available for streaming conversion (files not tracked in memory)\n } catch (err) {\n spinner.fail(\"Conversion failed\");\n console.error(error(err instanceof Error ? err.message : String(err)));\n process.exit(1);\n }\n });\n","/**\n * `lexbuild enrich-fr` command — enriches FR Markdown frontmatter with API metadata.\n *\n * Fetches rich metadata from the FederalRegister.gov API listing endpoint and\n * patches existing .md files that were converted from govinfo bulk XML. Does not\n * re-parse XML or re-render Markdown — only updates YAML frontmatter.\n */\n\nimport { Command } from \"commander\";\nimport { resolve } from \"node:path\";\nimport { enrichFrDocuments } from \"@lexbuild/fr\";\nimport {\n createSpinner,\n summaryBlock,\n formatDuration,\n formatNumber,\n error,\n} from \"../ui.js\";\n\n/** Parsed options from the enrich-fr command */\ninterface EnrichFrCliOptions {\n output: string;\n from?: string | undefined;\n to?: string | undefined;\n recent?: string | undefined;\n force?: boolean | undefined;\n}\n\nexport const enrichFrCommand = new Command(\"enrich-fr\")\n .description(\"Enrich FR Markdown frontmatter with FederalRegister.gov API metadata\")\n .option(\"-o, --output <dir>\", \"Output directory containing FR .md files\", \"./output\")\n .option(\"--from <YYYY-MM-DD>\", \"Start date (inclusive)\")\n .option(\"--to <YYYY-MM-DD>\", \"End date (inclusive, defaults to today)\")\n .option(\"--recent <days>\", \"Enrich last N days\")\n .option(\"--force\", \"Overwrite already-enriched files (have fr_citation)\")\n .addHelpText(\n \"after\",\n `\nExamples:\n $ lexbuild enrich-fr --from 2000-01-01 --to 2026-03-25\n $ lexbuild enrich-fr --recent 30\n $ lexbuild enrich-fr --from 2020-01-01 --force\n\nThis command fetches metadata from the FederalRegister.gov API listing endpoint\nand patches YAML frontmatter in existing .md files. Use it to backfill rich\nmetadata (agencies, CFR references, docket IDs, citations, etc.) into files\nthat were originally converted from govinfo bulk XML.\n\nFiles that already have fr_citation are skipped unless --force is used.`,\n )\n .action(async (options: EnrichFrCliOptions) => {\n // Validate: need --from or --recent\n if (!options.from && !options.recent) {\n console.error(\n error(\n \"Specify --from <date> or --recent <days>\\n\" +\n \"Examples: --from 2000-01-01, --recent 30\",\n ),\n );\n process.exit(1);\n }\n\n // Validate date format\n if (options.from && !/^\\d{4}-\\d{2}-\\d{2}$/.test(options.from)) {\n console.error(error(\"--from must be in YYYY-MM-DD format\"));\n process.exit(1);\n }\n if (options.to && !/^\\d{4}-\\d{2}-\\d{2}$/.test(options.to)) {\n console.error(error(\"--to must be in YYYY-MM-DD format\"));\n process.exit(1);\n }\n\n let from: string;\n if (options.recent) {\n const days = parseInt(options.recent, 10);\n if (isNaN(days) || days <= 0) {\n console.error(error(\"--recent must be a positive integer\"));\n process.exit(1);\n }\n const d = new Date();\n d.setDate(d.getDate() - days);\n from = d.toISOString().slice(0, 10);\n } else {\n from = options.from ?? \"\";\n }\n\n const to = options.to ?? new Date().toISOString().slice(0, 10);\n const outputDir = resolve(options.output);\n const startTime = performance.now();\n\n const spinner = createSpinner(\n `Enriching FR frontmatter (${from} to ${to})`,\n );\n spinner.start();\n\n try {\n const result = await enrichFrDocuments({\n output: outputDir,\n from,\n to,\n force: options.force,\n onProgress: (progress) => {\n const processed = progress.enriched + progress.skipped + progress.notFound;\n const pct =\n progress.total > 0\n ? Math.round((processed / progress.total) * 100)\n : 0;\n spinner.text = `Enriching FR frontmatter (${formatNumber(progress.enriched)} enriched, ${formatNumber(progress.skipped)} skipped) ${pct}% [${progress.currentChunk}] ${progress.currentDocument}`;\n },\n });\n\n const elapsed = performance.now() - startTime;\n spinner.succeed(\n `Enriched ${formatNumber(result.enriched)} FR documents`,\n );\n\n console.log();\n const rows: [string, string][] = [\n [\"Date range\", `${result.dateRange.from} → ${result.dateRange.to}`],\n [\"API documents\", formatNumber(result.total)],\n [\"Enriched\", formatNumber(result.enriched)],\n [\"Skipped\", formatNumber(result.skipped)],\n [\"Not found\", formatNumber(result.notFound)],\n [\"Duration\", formatDuration(elapsed)],\n ];\n\n console.log(summaryBlock({ title: \"Enrichment Complete\", rows }));\n } catch (err) {\n spinner.fail(\"Enrichment failed\");\n console.error(error(err instanceof Error ? err.message : String(err)));\n process.exit(1);\n }\n });\n"],"mappings":"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","names":["Command","chalk","inputDir","chalk","Command","relative","resolve","Command","resolve","relative","Command","detectLatestReleasePoint","FALLBACK_RELEASE_POINT","Command","detectLatestReleasePoint","FALLBACK_RELEASE_POINT","chalk","Command","Option","existsSync","readdirSync","join","relative","resolve","buildConvertOptions","titleXmlPath","join","existsSync","readdirSync","runConversion","convertSingleFile","relative","Command","Option","resolve","inputDir","chalk","Command","relative","resolve","Command","resolve","relative","Command","relative","resolve","Command","resolve","relative","Command","existsSync","relative","resolve","VALID_TYPES","Command","resolve","existsSync","relative","Command","resolve","Command","resolve","require","Command"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/commands/convert-usc.ts","../src/ui.ts","../src/parse-titles.ts","../src/commands/download-usc.ts","../src/commands/list-release-points.ts","../src/commands/convert-ecfr.ts","../src/commands/download-ecfr.ts","../src/commands/download-fr.ts","../src/commands/convert-fr.ts","../src/commands/enrich-fr.ts"],"sourcesContent":["/** lexbuild CLI — Convert U.S. legal XML to structured Markdown */\n\nimport { createRequire } from \"node:module\";\nimport { Command } from \"commander\";\nimport { convertUscCommand } from \"./commands/convert-usc.js\";\nimport { downloadUscCommand } from \"./commands/download-usc.js\";\nimport { listReleasePointsCommand } from \"./commands/list-release-points.js\";\nimport { convertEcfrCommand } from \"./commands/convert-ecfr.js\";\nimport { downloadEcfrCommand } from \"./commands/download-ecfr.js\";\nimport { downloadFrCommand } from \"./commands/download-fr.js\";\nimport { convertFrCommand } from \"./commands/convert-fr.js\";\nimport { enrichFrCommand } from \"./commands/enrich-fr.js\";\nimport { error } from \"./ui.js\";\n\nconst require = createRequire(import.meta.url);\nconst pkg = require(\"../package.json\") as { version: string };\n\nconst program = new Command();\n\nprogram\n .name(\"lexbuild\")\n .description(\"Convert U.S. legal XML to structured Markdown for AI/RAG ingestion\")\n .version(pkg.version)\n .addHelpText(\n \"after\",\n `\nQuick start (U.S. Code):\n $ lexbuild download-usc --all Download all 54 USC titles from OLRC\n $ lexbuild convert-usc --all Convert all downloaded USC titles\n $ lexbuild convert-usc --titles 1 Convert USC Title 1 only\n\nQuick start (eCFR):\n $ lexbuild download-ecfr --all Download all 50 eCFR titles from govinfo\n $ lexbuild convert-ecfr --all Convert all downloaded eCFR titles\n $ lexbuild convert-ecfr --titles 17 Convert eCFR Title 17 only\n\nQuick start (Federal Register):\n $ lexbuild download-fr --recent 30 Download last 30 days of FR documents\n $ lexbuild convert-fr --all Convert all downloaded FR documents\n\nDocumentation: https://github.com/chris-c-thomas/LexBuild`,\n );\n\n// Source-specific commands\nprogram.addCommand(downloadUscCommand);\nprogram.addCommand(convertUscCommand);\nprogram.addCommand(listReleasePointsCommand);\nprogram.addCommand(downloadEcfrCommand);\nprogram.addCommand(convertEcfrCommand);\nprogram.addCommand(downloadFrCommand);\nprogram.addCommand(convertFrCommand);\nprogram.addCommand(enrichFrCommand);\n\n// Bare \"download\" and \"convert\" stubs — guide users to source-specific commands\nprogram.addCommand(\n new Command(\"download\")\n .description(\"(use download-usc or download-ecfr)\")\n .allowUnknownOption()\n .helpOption(false)\n .action(() => {\n console.error(error(\"Please specify a source:\\n\"));\n console.error(\" lexbuild download-usc Download U.S. Code XML from OLRC\");\n console.error(\" lexbuild download-ecfr Download eCFR XML from govinfo\");\n console.error(\" lexbuild download-fr Download Federal Register XML from federalregister.gov\");\n console.error(\"\");\n process.exit(1);\n }),\n);\n\nprogram.addCommand(\n new Command(\"convert\")\n .description(\"(use convert-usc or convert-ecfr)\")\n .allowUnknownOption()\n .helpOption(false)\n .action(() => {\n console.error(error(\"Please specify a source:\\n\"));\n console.error(\" lexbuild convert-usc Convert U.S. Code XML to Markdown\");\n console.error(\" lexbuild convert-ecfr Convert eCFR XML to Markdown\");\n console.error(\" lexbuild convert-fr Convert Federal Register XML to Markdown\");\n console.error(\"\");\n process.exit(1);\n }),\n);\n\nprogram.parse();\n","/**\n * `lexbuild convert-usc` command — converts USC XML files to Markdown.\n */\n\nimport chalk from \"chalk\";\nimport { Command, Option } from \"commander\";\nimport { existsSync, readdirSync } from \"node:fs\";\nimport { basename, dirname, join, relative, resolve } from \"node:path\";\nimport { convertTitle } from \"@lexbuild/usc\";\nimport {\n createSpinner,\n summaryBlock,\n dataTable,\n formatDuration,\n formatBytes,\n formatNumber,\n success,\n error,\n} from \"../ui.js\";\nimport { parseTitles } from \"../parse-titles.js\";\n\n/** Parsed options from the convert command */\ninterface ConvertCommandOptions {\n output: string;\n titles?: string | undefined;\n all: boolean;\n inputDir: string;\n granularity: \"section\" | \"chapter\" | \"title\";\n linkStyle: \"relative\" | \"canonical\" | \"plaintext\";\n includeSourceCredits: boolean;\n includeNotes: boolean;\n includeEditorialNotes: boolean;\n includeStatutoryNotes: boolean;\n includeAmendments: boolean;\n dryRun: boolean;\n verbose: boolean;\n}\n\n/** Build the shared convert options from CLI flags. */\nfunction buildConvertOptions(inputPath: string, outputPath: string, options: ConvertCommandOptions) {\n const hasSelectiveFlags = options.includeEditorialNotes || options.includeStatutoryNotes || options.includeAmendments;\n const includeNotes = hasSelectiveFlags ? false : options.includeNotes;\n\n return {\n input: inputPath,\n output: outputPath,\n granularity: options.granularity,\n linkStyle: options.linkStyle,\n includeSourceCredits: options.includeSourceCredits,\n includeNotes,\n includeEditorialNotes: options.includeEditorialNotes,\n includeStatutoryNotes: options.includeStatutoryNotes,\n includeAmendments: options.includeAmendments,\n dryRun: options.dryRun,\n };\n}\n\n/** Resolve the XML file path for a given title number. */\nfunction titleXmlPath(inputDir: string, titleNum: number): string {\n const padded = String(titleNum).padStart(2, \"0\");\n return join(inputDir, `usc${padded}.xml`);\n}\n\n/** Try to resolve a USC XML path, falling back to zero-padded filename. */\nexport function resolveUscXmlPath(inputPath: string): string | undefined {\n if (existsSync(inputPath)) return inputPath;\n\n // Check if filename matches usc{N}.xml pattern and try zero-padded\n const dir = dirname(inputPath);\n const base = basename(inputPath);\n const match = /^usc(\\d+)\\.xml$/.exec(base);\n if (match?.[1]) {\n const padded = match[1].padStart(2, \"0\");\n const paddedPath = join(dir, `usc${padded}.xml`);\n if (existsSync(paddedPath)) return paddedPath;\n }\n\n return undefined;\n}\n\n/** Regex matching USC XML filenames like usc01.xml, usc54.xml */\nconst USC_XML_RE = /^usc(\\d{2})\\.xml$/;\n\n/**\n * Scan a directory for USC XML files and return their title numbers, sorted.\n */\nexport function discoverTitles(inputDir: string): number[] {\n if (!existsSync(inputDir)) return [];\n\n return readdirSync(inputDir)\n .map((name) => USC_XML_RE.exec(name))\n .filter((m): m is RegExpExecArray => m !== null)\n .map((m) => parseInt(m[1] ?? \"0\", 10))\n .sort((a, b) => a - b);\n}\n\n/** Result from runConversion including elapsed time. */\ninterface ConversionRun {\n result: Awaited<ReturnType<typeof convertTitle>>;\n elapsed: number;\n}\n\n/** Run a conversion without printing output. Returns the result and elapsed time. */\nasync function runConversion(\n inputPath: string,\n outputPath: string,\n options: ConvertCommandOptions,\n): Promise<ConversionRun> {\n const startTime = performance.now();\n const result = await convertTitle(buildConvertOptions(inputPath, outputPath, options));\n const elapsed = performance.now() - startTime;\n return { result, elapsed };\n}\n\n/** Convert a single XML file and print its detailed summary. */\nasync function convertSingleFile(\n inputPath: string,\n outputPath: string,\n options: ConvertCommandOptions,\n spinnerLabel: string,\n) {\n const spinner = createSpinner(spinnerLabel);\n spinner.start();\n\n try {\n const { result, elapsed } = await runConversion(inputPath, outputPath, options);\n\n spinner.stop();\n\n const rows: Array<[string, string]> = [];\n if (options.granularity === \"section\") {\n rows.push([\"Sections\", formatNumber(result.sectionsWritten)]);\n rows.push([\"Chapters\", formatNumber(result.chapterCount)]);\n } else if (options.granularity === \"chapter\") {\n rows.push([\"Chapters\", formatNumber(result.chapterCount)]);\n }\n rows.push([\"Est. Tokens\", formatNumber(result.totalTokenEstimate)]);\n\n if (!result.dryRun) {\n rows.push([\"Files Written\", formatNumber(result.files.length)]);\n }\n\n rows.push([\"Peak Memory\", formatBytes(result.peakMemoryBytes)], [\"Duration\", formatDuration(elapsed)]);\n\n const titleLabel = result.dryRun\n ? `lexbuild — Title ${result.titleNumber}: ${result.titleName} [dry-run]`\n : `lexbuild — Title ${result.titleNumber}: ${result.titleName}`;\n\n const outputRelative = relative(process.cwd(), outputPath) || outputPath;\n\n const output = summaryBlock({\n title: titleLabel,\n rows: [...rows, [\"Output\", outputRelative]],\n footer: result.dryRun ? success(\"Dry run complete\") : success(\"Conversion complete\"),\n });\n process.stdout.write(output);\n\n if (options.verbose && !result.dryRun && result.files.length > 0) {\n console.log(\" Files written:\");\n for (const file of result.files) {\n console.log(` ${relative(process.cwd(), file) || file}`);\n }\n console.log(\"\");\n }\n\n return result;\n } catch (err) {\n spinner.fail(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n}\n\nexport const convertUscCommand = new Command(\"convert-usc\")\n .description(\"Convert U.S. Code XML file(s) to Markdown\")\n .argument(\"[input]\", \"Path to a USC XML file\")\n .option(\"-o, --output <dir>\", \"Output directory\", \"./output\")\n .option(\"--titles <spec>\", \"Title(s) to convert: 1, 1-5, or 1-5,8,11\")\n .option(\"--all\", \"Convert all downloaded titles found in --input-dir\", false)\n .option(\"-i, --input-dir <dir>\", \"Directory containing USC XML files\", \"./downloads/usc/xml\")\n .addOption(\n new Option(\"-g, --granularity <level>\", \"Output granularity: section, chapter, or title\")\n .choices([\"section\", \"chapter\", \"title\"])\n .default(\"section\"),\n )\n .addOption(\n new Option(\"--link-style <style>\", \"Link style: relative, canonical, or plaintext\")\n .choices([\"relative\", \"canonical\", \"plaintext\"])\n .default(\"plaintext\"),\n )\n .option(\"--include-source-credits\", \"Include source credit annotations\", true)\n .option(\"--no-include-source-credits\", \"Exclude source credit annotations\")\n .option(\"--include-notes\", \"Include all notes (default)\", true)\n .option(\"--no-include-notes\", \"Exclude all notes\")\n .option(\"--include-editorial-notes\", \"Include editorial notes only\", false)\n .option(\"--include-statutory-notes\", \"Include statutory notes only\", false)\n .option(\"--include-amendments\", \"Include amendment history notes only\", false)\n .option(\"--dry-run\", \"Parse and report structure without writing files\", false)\n .option(\"-v, --verbose\", \"Enable verbose logging\", false)\n .addHelpText(\n \"after\",\n `\nInput modes (use exactly one):\n <input> Convert a single XML file\n --titles Convert specific titles by number\n --all Convert all titles in --input-dir\n\nGranularity:\n section One .md file per section (default)\n chapter One .md file per chapter, sections inlined\n title One .md file per title, entire hierarchy inlined\n\nExamples:\n $ lexbuild convert-usc --titles 1 Convert Title 1\n $ lexbuild convert-usc --titles 1-5,8,11 Convert a mix of titles\n $ lexbuild convert-usc --all -g chapter All titles, chapter-level\n $ lexbuild convert-usc --titles 26 -g title Title 26 as a single file\n $ lexbuild convert-usc --all --dry-run Preview stats only\n $ lexbuild convert-usc ./downloads/usc/xml/usc01.xml -o ./out`,\n )\n .action(async (input: string | undefined, options: ConvertCommandOptions) => {\n // Validate: must specify exactly one of <input>, --titles, or --all\n const modeCount = [input, options.titles, options.all].filter(Boolean).length;\n if (modeCount === 0) {\n console.error(error(\"Specify an input file, --titles <spec>, or --all (e.g. --titles 1-5,8,11)\"));\n process.exit(1);\n }\n if (modeCount > 1) {\n console.error(error(\"Cannot combine <input>, --titles, and --all — use only one\"));\n process.exit(1);\n }\n\n const outputPath = resolve(options.output);\n const dryRunLabel = options.dryRun ? \" [dry-run]\" : \"\";\n\n // Single-file mode\n if (input) {\n const rawPath = resolve(input);\n const inputPath = resolveUscXmlPath(rawPath);\n if (!inputPath) {\n console.error(error(`Input file not found: ${rawPath}`));\n process.exit(1);\n }\n await convertSingleFile(inputPath, outputPath, options, `Converting${dryRunLabel}...`);\n return;\n }\n\n // Multi-title mode\n let titles: number[];\n if (options.all) {\n const inputDir = resolve(options.inputDir);\n titles = discoverTitles(inputDir);\n if (titles.length === 0) {\n console.error(error(`No USC XML files found in ${inputDir}`));\n process.exit(1);\n }\n } else {\n const titlesSpec = options.titles as string;\n try {\n titles = parseTitles(titlesSpec);\n } catch (err) {\n console.error(error(err instanceof Error ? err.message : String(err)));\n process.exit(1);\n }\n }\n\n const inputDir = resolve(options.inputDir);\n const totalTitles = titles.length;\n const results: ConversionRun[] = [];\n\n const spinner = createSpinner(`Converting${dryRunLabel}...`);\n spinner.start();\n\n for (const [i, titleNum] of titles.entries()) {\n const xmlPath = titleXmlPath(inputDir, titleNum);\n\n if (!existsSync(xmlPath)) {\n spinner.stop();\n console.error(error(`XML file not found: ${xmlPath}`));\n process.exit(1);\n }\n\n spinner.text = `Converting Title ${titleNum}${dryRunLabel} (${i + 1}/${totalTitles})...`;\n\n try {\n const run = await runConversion(xmlPath, outputPath, options);\n results.push(run);\n } catch (err) {\n spinner.fail(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n }\n\n spinner.stop();\n\n // Summary header\n const outputRelative = relative(process.cwd(), outputPath) || outputPath;\n const headerTitle = options.dryRun ? \"lexbuild — Conversion Summary [dry-run]\" : \"lexbuild — Conversion Summary\";\n const header = summaryBlock({\n title: headerTitle,\n rows: [[\"Directory\", outputRelative]],\n });\n process.stdout.write(header);\n\n // Build data table rows — adapt columns to granularity\n const granularity = options.granularity;\n let totalSections = 0;\n let totalChapters = 0;\n let totalTokens = 0;\n let totalElapsed = 0;\n\n const tableRows = results.map(({ result, elapsed }) => {\n totalSections += result.sectionsWritten;\n totalChapters += result.chapterCount;\n totalTokens += result.totalTokenEstimate;\n totalElapsed += elapsed;\n\n if (granularity === \"title\") {\n return [result.titleNumber, result.titleName, formatNumber(result.totalTokenEstimate), formatDuration(elapsed)];\n } else if (granularity === \"chapter\") {\n return [\n result.titleNumber,\n result.titleName,\n formatNumber(result.chapterCount),\n formatNumber(result.totalTokenEstimate),\n formatDuration(elapsed),\n ];\n } else {\n return [\n result.titleNumber,\n result.titleName,\n formatNumber(result.chapterCount),\n formatNumber(result.sectionsWritten),\n formatNumber(result.totalTokenEstimate),\n formatDuration(elapsed),\n ];\n }\n });\n\n // Totals row\n if (granularity === \"title\") {\n tableRows.push([\n chalk.bold(\"Total\"),\n \"\",\n chalk.bold(formatNumber(totalTokens)),\n chalk.bold(formatDuration(totalElapsed)),\n ]);\n } else if (granularity === \"chapter\") {\n tableRows.push([\n chalk.bold(\"Total\"),\n \"\",\n chalk.bold(formatNumber(totalChapters)),\n chalk.bold(formatNumber(totalTokens)),\n chalk.bold(formatDuration(totalElapsed)),\n ]);\n } else {\n tableRows.push([\n chalk.bold(\"Total\"),\n \"\",\n chalk.bold(formatNumber(totalChapters)),\n chalk.bold(formatNumber(totalSections)),\n chalk.bold(formatNumber(totalTokens)),\n chalk.bold(formatDuration(totalElapsed)),\n ]);\n }\n\n // Table headers and footer — adapt to granularity\n const tableHeaders =\n granularity === \"title\"\n ? [\"Title\", \"Name\", \"Tokens\", \"Duration\"]\n : granularity === \"chapter\"\n ? [\"Title\", \"Name\", \"Chapters\", \"Tokens\", \"Duration\"]\n : [\"Title\", \"Name\", \"Chapters\", \"Sections\", \"Tokens\", \"Duration\"];\n\n console.log(dataTable(tableHeaders, tableRows));\n\n // Footer — show the primary unit that was converted\n let countLabel: string;\n if (granularity === \"title\") {\n const titleWord = totalTitles === 1 ? \"title\" : \"titles\";\n countLabel = `${formatNumber(totalTitles)} ${titleWord}`;\n } else if (granularity === \"chapter\") {\n const chapterWord = totalChapters === 1 ? \"chapter\" : \"chapters\";\n countLabel = `${formatNumber(totalChapters)} ${chapterWord}`;\n } else {\n const sectionWord = totalSections === 1 ? \"section\" : \"sections\";\n countLabel = `${formatNumber(totalSections)} ${sectionWord}`;\n }\n console.log(`\\n ${success(`Converted ${countLabel} in ${formatDuration(totalElapsed)}`)}`);\n console.log(\"\");\n });\n","/**\n * Shared terminal UI utilities — spinners, tables, and formatting helpers.\n */\n\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport type { Ora } from \"ora\";\nimport Table from \"cli-table3\";\n\n/** Create an ora spinner with consistent styling. */\nexport function createSpinner(text: string): Ora {\n return ora({ text, spinner: \"dots\" });\n}\n\n/** Format milliseconds as human-readable duration (e.g. \"1.5s\" or \"1m 23s\"). */\nexport function formatDuration(ms: number): string {\n const secs = ms / 1000;\n if (secs < 60) {\n return `${secs.toFixed(secs < 10 ? 2 : 1)}s`;\n }\n const mins = Math.floor(secs / 60);\n const remainSecs = Math.round(secs % 60);\n return `${mins}m ${remainSecs}s`;\n}\n\n/** Format bytes as human-readable size (e.g. \"11.0 MB\"). */\nexport function formatBytes(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`;\n const kb = bytes / 1024;\n if (kb < 1024) return `${kb.toFixed(1)} KB`;\n const mb = kb / 1024;\n if (mb < 1024) return `${mb.toFixed(1)} MB`;\n const gb = mb / 1024;\n return `${gb.toFixed(2)} GB`;\n}\n\n/** Format a number with locale-aware separators (e.g. 1,234,567). */\nexport function formatNumber(n: number): string {\n return n.toLocaleString();\n}\n\n/** Regex matching ANSI escape sequences (SGR codes). */\n// eslint-disable-next-line no-control-regex\nconst ANSI_RE = /\\x1B\\[[0-9;]*m/g;\n\n/** Strip ANSI escape codes and return visual string length. */\nfunction visualLength(s: string): number {\n return s.replace(ANSI_RE, \"\").length;\n}\n\n/**\n * Compute column widths that fill the terminal.\n * Expands `flexCol` to absorb remaining space.\n */\nfunction fillWidths(columns: string[][], colCount: number, flexCol: number): number[] | undefined {\n const termWidth = process.stdout.columns || 80;\n // Compute natural width per column (max visual length across all rows)\n const natural = Array.from<number>({ length: colCount }).fill(0);\n for (const row of columns) {\n for (let i = 0; i < colCount; i++) {\n natural[i] = Math.max(natural[i] ?? 0, visualLength(row[i] ?? \"\"));\n }\n }\n // Overhead: 2 chars left pad + 2 chars per column separator (between cols)\n const overhead = 2 + 2 * (colCount - 1);\n const naturalTotal = overhead + natural.reduce((a, b) => a + b, 0);\n if (naturalTotal >= termWidth) return undefined; // already fills or exceeds\n const extra = termWidth - naturalTotal;\n const widths = [...natural];\n widths[flexCol] = (widths[flexCol] ?? 0) + extra;\n return widths;\n}\n\n/**\n * Shared cli-table3 border characters.\n *\n * Uses 2-char left indent (\" \"), 2-char column gap (\" \"), no right border.\n * The \"mid\" intersection chars (\"──\") must match the 2-char width of \"middle\"\n * so horizontal rules span the full table width.\n */\nconst TABLE_CHARS = {\n top: \"─\",\n \"top-mid\": \"──\",\n \"top-left\": \" \",\n \"top-right\": \"\",\n bottom: \"─\",\n \"bottom-mid\": \"──\",\n \"bottom-left\": \" \",\n \"bottom-right\": \"\",\n left: \" \",\n \"left-mid\": \" \",\n right: \"\",\n \"right-mid\": \"\",\n mid: \"─\",\n \"mid-mid\": \"──\",\n middle: \" \",\n} as const;\n\n/** Shared cli-table3 style. */\nconst TABLE_STYLE: {\n head: string[];\n border: string[];\n \"padding-left\": number;\n \"padding-right\": number;\n} = {\n head: [],\n border: [],\n \"padding-left\": 0,\n \"padding-right\": 0,\n};\n\n/** Render a styled heading line. */\nfunction heading(text: string): string {\n return chalk.bold(text);\n}\n\n/** Render a success message with green checkmark. */\nexport function success(text: string): string {\n return chalk.green(`✔ ${text}`);\n}\n\n/** Render an error message with red X. */\nexport function error(text: string): string {\n return chalk.red(`✘ ${text}`);\n}\n\n/** Options for a key-value summary block. */\ninterface SummaryBlockOptions {\n /** Title line displayed above the table */\n title: string;\n /** Key-value pairs to display */\n rows: Array<[label: string, value: string]>;\n /** Optional footer line displayed below the table */\n footer?: string | undefined;\n}\n\n/** Render a key-value summary block with horizontal rules. */\nexport function summaryBlock({ title, rows, footer }: SummaryBlockOptions): string {\n const allCells = rows.map(([l, v]) => [l, v]);\n const colWidths = fillWidths(allCells, 2, 1);\n\n const table = new Table({\n chars: TABLE_CHARS,\n style: TABLE_STYLE,\n ...(colWidths ? { colWidths } : {}),\n });\n\n for (const [label, value] of rows) {\n table.push([chalk.dim(label), value]);\n }\n\n const lines: string[] = [];\n lines.push(\"\");\n lines.push(` ${heading(title)}`);\n lines.push(table.toString());\n if (footer !== undefined) {\n lines.push(` ${footer}`);\n }\n lines.push(\"\");\n\n return lines.join(\"\\n\");\n}\n\n/** Render a multi-column data table. */\nexport function dataTable(head: string[], rows: string[][]): string {\n const table = new Table({\n head: head.map((h) => chalk.dim(h)),\n chars: TABLE_CHARS,\n style: TABLE_STYLE,\n });\n\n for (const row of rows) {\n table.push(row);\n }\n\n return table.toString();\n}\n","/**\n * Parses a title specification string into an array of title numbers.\n *\n * Supports single numbers, comma-separated lists, ranges, and mixed:\n * - `\"29\"` → `[29]`\n * - `\"1,3,8,11\"` → `[1, 3, 8, 11]`\n * - `\"1-5\"` → `[1, 2, 3, 4, 5]`\n * - `\"1-5,8,11\"` → `[1, 2, 3, 4, 5, 8, 11]`\n */\nexport function parseTitles(input: string, maxTitle = 54): number[] {\n const trimmed = input.trim();\n if (trimmed === \"\") {\n throw new Error(\"Title specification cannot be empty\");\n }\n\n const result = new Set<number>();\n const segments = trimmed.split(\",\");\n\n for (const segment of segments) {\n const part = segment.trim();\n if (part === \"\") {\n throw new Error(`Invalid title specification: \"${input}\" (empty segment)`);\n }\n\n if (part.includes(\"-\")) {\n const [startStr, endStr, ...rest] = part.split(\"-\");\n if (rest.length > 0 || !startStr || !endStr) {\n throw new Error(`Invalid range: \"${part}\" (expected format: start-end)`);\n }\n\n const start = parseIntStrict(startStr, input);\n const end = parseIntStrict(endStr, input);\n\n if (start > end) {\n throw new Error(`Invalid range: \"${part}\" (start ${start} must be ≤ end ${end})`);\n }\n\n validateTitleNumber(start, input, maxTitle);\n validateTitleNumber(end, input, maxTitle);\n\n for (let i = start; i <= end; i++) {\n result.add(i);\n }\n } else {\n const num = parseIntStrict(part, input);\n validateTitleNumber(num, input, maxTitle);\n result.add(num);\n }\n }\n\n return [...result].sort((a, b) => a - b);\n}\n\n/** Parse an integer strictly — no NaN, no floats. */\nfunction parseIntStrict(str: string, fullInput: string): number {\n const trimmed = str.trim();\n if (!/^\\d+$/.test(trimmed)) {\n throw new Error(`Invalid number \"${trimmed}\" in title specification: \"${fullInput}\"`);\n }\n return parseInt(trimmed, 10);\n}\n\n/** Validate that a title number is in the valid range. */\nfunction validateTitleNumber(num: number, fullInput: string, max = 54): void {\n if (num < 1 || num > max) {\n throw new Error(`Title number ${num} out of range (must be 1-${max}) in: \"${fullInput}\"`);\n }\n}\n","/**\n * `lexbuild download-usc` command — downloads USC XML from OLRC.\n *\n * Auto-detects the latest OLRC release point unless overridden with --release-point.\n */\n\nimport { Command } from \"commander\";\nimport { relative, resolve } from \"node:path\";\nimport { downloadTitles, detectLatestReleasePoint, FALLBACK_RELEASE_POINT } from \"@lexbuild/usc\";\nimport { createSpinner, summaryBlock, dataTable, formatDuration, formatBytes, success, error } from \"../ui.js\";\nimport { parseTitles } from \"../parse-titles.js\";\n\n/** Parsed options from the download command */\ninterface DownloadCommandOptions {\n output: string;\n titles?: string | undefined;\n all: boolean;\n releasePoint?: string | undefined;\n}\n\nexport const downloadUscCommand = new Command(\"download-usc\")\n .description(\"Download U.S. Code XML from OLRC\")\n .option(\"-o, --output <dir>\", \"Download directory\", \"./downloads/usc/xml\")\n .option(\"--titles <spec>\", \"Title(s) to download: 1, 1-5, or 1-5,8,11\")\n .option(\"--all\", \"Download all 54 titles (single bulk zip)\", false)\n .option(\"--release-point <id>\", \"OLRC release point (auto-detected if omitted)\")\n .addHelpText(\n \"after\",\n `\nExamples:\n $ lexbuild download-usc --all Download all 54 titles (latest release)\n $ lexbuild download-usc --titles 1 Download Title 1 only\n $ lexbuild download-usc --titles 1-5,8,11 Download specific titles\n $ lexbuild download-usc --all -o ./my-xml Custom output directory\n $ lexbuild download-usc --all --release-point 119-73not60 Pin a specific release\n\nThe latest release point is auto-detected from the OLRC download page.\nSource: https://uscode.house.gov/download/download.shtml`,\n )\n .action(async (options: DownloadCommandOptions) => {\n // Validate: must specify --titles or --all\n if (!options.titles && !options.all) {\n console.error(error(\"Specify --titles <spec> or --all (e.g. --titles 1-5,8,11)\"));\n process.exit(1);\n }\n\n // Parse title numbers\n let titles: number[] | undefined;\n if (options.titles) {\n try {\n titles = parseTitles(options.titles);\n } catch (err) {\n console.error(error(err instanceof Error ? err.message : String(err)));\n process.exit(1);\n }\n }\n\n const outputDir = resolve(options.output);\n const titleCount = titles ? titles.length : 54;\n\n // Resolve release point: use explicit flag, auto-detect, or fall back\n let releasePoint = options.releasePoint;\n if (!releasePoint) {\n const detectSpinner = createSpinner(\"Detecting latest OLRC release point...\");\n detectSpinner.start();\n const detected = await detectLatestReleasePoint();\n if (detected) {\n releasePoint = detected.releasePoint;\n detectSpinner.succeed(`Release point: ${detected.releasePoint}`);\n } else {\n releasePoint = FALLBACK_RELEASE_POINT;\n detectSpinner.warn(`Could not detect release point, using fallback: ${releasePoint}`);\n }\n }\n\n const label = titleCount === 1 ? `Downloading Title ${titles?.[0]}` : `Downloading ${titleCount} USC titles`;\n\n const spinner = createSpinner(`${label}...`);\n spinner.start();\n\n const startTime = performance.now();\n\n try {\n const result = await downloadTitles({\n outputDir,\n titles,\n releasePoint,\n onProgress: ({ current, total, titleNumber, phase }) => {\n if (phase === \"extracting\") {\n spinner.text = `Extracting USC titles (${current}/${total}) — Title ${titleNumber}`;\n } else if (total === 1) {\n spinner.text = `Downloading USC Title ${titleNumber}`;\n } else if (current === 0) {\n spinner.text = \"Downloading USC bulk archive\";\n } else {\n spinner.text = `Downloading USC titles (${current}/${total}) — Title ${titleNumber}`;\n }\n },\n });\n\n const elapsed = performance.now() - startTime;\n\n spinner.stop();\n\n // Build file table rows\n const fileRows = result.files.map((file) => [\n String(file.titleNumber),\n formatBytes(file.size),\n relative(outputDir, file.filePath) || file.filePath,\n ]);\n\n const totalBytes = result.files.reduce((sum, f) => sum + f.size, 0);\n\n // Summary header — show the actual release point used (may be auto-detected)\n const rpLabel = options.releasePoint ? result.releasePoint : `${result.releasePoint} (auto-detected)`;\n\n const output = summaryBlock({\n title: \"lexbuild — Download Summary\",\n rows: [\n [\"Release Point\", rpLabel],\n [\"Directory\", relative(process.cwd(), outputDir) || outputDir],\n ],\n });\n process.stdout.write(output);\n\n // File table\n if (fileRows.length > 0) {\n console.log(dataTable([\"Title\", \"Size\", \"File\"], fileRows));\n }\n\n // Errors\n if (result.errors.length > 0) {\n console.log(\"\");\n for (const err of result.errors) {\n console.log(` ${error(`Title ${err.titleNumber}: ${err.message}`)}`);\n }\n }\n\n // Footer\n const titleWord = result.files.length === 1 ? \"title\" : \"titles\";\n const summary = `Downloaded ${result.files.length} ${titleWord} (${formatBytes(totalBytes)}) in ${formatDuration(elapsed)}`;\n const failSuffix = result.errors.length > 0 ? ` (${result.errors.length} failed)` : \"\";\n console.log(` ${success(summary + failSuffix)}`);\n console.log(\"\");\n } catch (err) {\n spinner.fail(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n });\n","/**\n * `lexbuild list-release-points` command — lists available OLRC release points.\n *\n * Fetches the current release point from the OLRC download page and the full\n * history from the prior release points page, then displays them in a table.\n */\n\nimport { Command } from \"commander\";\nimport { detectLatestReleasePoint, fetchReleasePointHistory, FALLBACK_RELEASE_POINT } from \"@lexbuild/usc\";\nimport { createSpinner, summaryBlock, dataTable, error } from \"../ui.js\";\n\n/** Parsed options from the list-release-points command */\ninterface ListReleasePointsOptions {\n limit: string;\n}\n\nexport const listReleasePointsCommand = new Command(\"list-release-points\")\n .description(\"List available OLRC release points for the U.S. Code\")\n .option(\"-n, --limit <count>\", \"Maximum number of release points to show\", \"20\")\n .addHelpText(\n \"after\",\n `\nExamples:\n $ lexbuild list-release-points Show the 20 most recent release points\n $ lexbuild list-release-points -n 5 Show the 5 most recent\n $ lexbuild list-release-points -n 0 Show all available release points\n\nUse --release-point <id> with download-usc to pin a specific release.\nSource: https://uscode.house.gov/download/priorreleasepoints.htm`,\n )\n .action(async (options: ListReleasePointsOptions) => {\n const limit = parseInt(options.limit, 10);\n if (Number.isNaN(limit) || limit < 0) {\n console.error(error(\"--limit must be a non-negative integer\"));\n process.exit(1);\n }\n\n const spinner = createSpinner(\"Fetching release points from OLRC...\");\n spinner.start();\n\n // Fetch current and history in parallel\n const [current, history] = await Promise.all([detectLatestReleasePoint(), fetchReleasePointHistory()]);\n\n spinner.stop();\n\n // Current release point summary\n const currentRp = current?.releasePoint ?? FALLBACK_RELEASE_POINT;\n const currentDesc = current?.description ?? \"(detection failed — showing fallback)\";\n\n const output = summaryBlock({\n title: \"lexbuild — OLRC Release Points\",\n rows: [\n [\"Latest\", `${currentRp} ${currentDesc}`],\n [\"Prior releases\", `${history.length} available`],\n ],\n });\n process.stdout.write(output);\n\n if (history.length === 0) {\n console.log(\" No prior release points found.\\n\");\n return;\n }\n\n // Apply limit (0 = show all)\n const displayed = limit > 0 ? history.slice(0, limit) : history;\n\n // Build table rows: Release Point, Date, Affected Titles\n const rows = displayed.map((rp) => [\n rp.releasePoint,\n rp.date,\n rp.affectedTitles.length > 0 ? rp.affectedTitles.join(\", \") : \"—\",\n ]);\n\n console.log(dataTable([\"Release Point\", \"Date\", \"Affected Titles\"], rows));\n\n if (limit > 0 && history.length > limit) {\n console.log(` Showing ${limit} of ${history.length} — use -n 0 to show all.\\n`);\n }\n\n console.log(\" Use with: lexbuild download-usc --all --release-point <id>\\n\");\n });\n","/**\n * `lexbuild convert-ecfr` command — converts eCFR XML files to Markdown.\n */\n\nimport chalk from \"chalk\";\nimport { Command, Option } from \"commander\";\nimport { existsSync, readdirSync } from \"node:fs\";\nimport { join, relative, resolve } from \"node:path\";\nimport { convertEcfrTitle } from \"@lexbuild/ecfr\";\nimport type { EcfrConvertOptions, EcfrConvertResult } from \"@lexbuild/ecfr\";\nimport {\n createSpinner,\n summaryBlock,\n dataTable,\n formatDuration,\n formatBytes,\n formatNumber,\n success,\n error,\n} from \"../ui.js\";\nimport { parseTitles } from \"../parse-titles.js\";\n\n/** Parsed options from the convert-ecfr command */\ninterface ConvertEcfrCommandOptions {\n output: string;\n titles?: string | undefined;\n all: boolean;\n inputDir: string;\n granularity: \"section\" | \"part\" | \"chapter\" | \"title\";\n linkStyle: \"relative\" | \"canonical\" | \"plaintext\";\n includeSourceCredits: boolean;\n includeNotes: boolean;\n includeEditorialNotes: boolean;\n includeStatutoryNotes: boolean;\n includeAmendments: boolean;\n dryRun: boolean;\n verbose: boolean;\n}\n\n/** Build EcfrConvertOptions from CLI flags. */\nfunction buildConvertOptions(\n inputPath: string,\n outputPath: string,\n options: ConvertEcfrCommandOptions,\n): EcfrConvertOptions {\n const hasSelectiveFlags = options.includeEditorialNotes || options.includeStatutoryNotes || options.includeAmendments;\n const includeNotes = hasSelectiveFlags ? false : options.includeNotes;\n\n return {\n input: inputPath,\n output: outputPath,\n granularity: options.granularity,\n linkStyle: options.linkStyle,\n includeSourceCredits: options.includeSourceCredits,\n includeNotes,\n includeEditorialNotes: options.includeEditorialNotes,\n includeStatutoryNotes: options.includeStatutoryNotes,\n includeAmendments: options.includeAmendments,\n dryRun: options.dryRun,\n };\n}\n\n/** Regex matching eCFR XML filenames like ECFR-title1.xml, ECFR-title17.xml */\nconst ECFR_XML_RE = /^ECFR-title(\\d+)\\.xml$/;\n\n/** Resolve the XML file path for a given eCFR title number. */\nfunction titleXmlPath(inputDir: string, titleNum: number): string {\n return join(inputDir, `ECFR-title${titleNum}.xml`);\n}\n\n/** Scan a directory for eCFR XML files and return their title numbers, sorted. */\nfunction discoverEcfrTitles(inputDir: string): number[] {\n if (!existsSync(inputDir)) return [];\n\n return readdirSync(inputDir)\n .map((name) => ECFR_XML_RE.exec(name))\n .filter((m): m is RegExpExecArray => m !== null)\n .map((m) => parseInt(m[1] ?? \"0\", 10))\n .sort((a, b) => a - b);\n}\n\n/** Result from running a conversion including elapsed time. */\ninterface ConversionRun {\n result: EcfrConvertResult;\n elapsed: number;\n}\n\n/** Run a conversion without printing output. */\nasync function runConversion(\n inputPath: string,\n outputPath: string,\n options: ConvertEcfrCommandOptions,\n): Promise<ConversionRun> {\n const startTime = performance.now();\n const result = await convertEcfrTitle(buildConvertOptions(inputPath, outputPath, options));\n const elapsed = performance.now() - startTime;\n return { result, elapsed };\n}\n\n/** Convert a single file and print its detailed summary. */\nasync function convertSingleFile(\n inputPath: string,\n outputPath: string,\n options: ConvertEcfrCommandOptions,\n spinnerLabel: string,\n) {\n const spinner = createSpinner(spinnerLabel);\n spinner.start();\n\n try {\n const { result, elapsed } = await runConversion(inputPath, outputPath, options);\n spinner.stop();\n\n const rows: Array<[string, string]> = [];\n if (options.granularity === \"section\") {\n rows.push([\"Sections\", formatNumber(result.sectionsWritten)]);\n rows.push([\"Parts\", formatNumber(result.partCount)]);\n } else if (options.granularity === \"part\") {\n rows.push([\"Parts\", formatNumber(result.partCount)]);\n } else if (options.granularity === \"chapter\") {\n rows.push([\"Chapters\", formatNumber(result.sectionsWritten)]);\n }\n rows.push([\"Est. Tokens\", formatNumber(result.totalTokenEstimate)]);\n\n if (!result.dryRun) {\n rows.push([\"Files Written\", formatNumber(result.files.length)]);\n }\n\n rows.push([\"Peak Memory\", formatBytes(result.peakMemoryBytes)], [\"Duration\", formatDuration(elapsed)]);\n\n const titleLabel = result.dryRun\n ? `lexbuild — eCFR Title ${result.titleNumber}: ${result.titleName} [dry-run]`\n : `lexbuild — eCFR Title ${result.titleNumber}: ${result.titleName}`;\n\n const outputRelative = relative(process.cwd(), outputPath) || outputPath;\n\n const output = summaryBlock({\n title: titleLabel,\n rows: [...rows, [\"Output\", outputRelative]],\n footer: result.dryRun ? success(\"Dry run complete\") : success(\"Conversion complete\"),\n });\n process.stdout.write(output);\n\n if (options.verbose && !result.dryRun && result.files.length > 0) {\n console.log(\" Files written:\");\n for (const file of result.files) {\n console.log(` ${relative(process.cwd(), file) || file}`);\n }\n console.log(\"\");\n }\n\n return result;\n } catch (err) {\n spinner.fail(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n}\n\nexport const convertEcfrCommand = new Command(\"convert-ecfr\")\n .description(\"Convert eCFR XML file(s) to Markdown\")\n .argument(\"[input]\", \"Path to an eCFR XML file\")\n .option(\"-o, --output <dir>\", \"Output directory\", \"./output\")\n .option(\"--titles <spec>\", \"Title(s) to convert: 1, 1-5, or 1-5,17\")\n .option(\"--all\", \"Convert all downloaded eCFR titles found in --input-dir\", false)\n .option(\"-i, --input-dir <dir>\", \"Directory containing eCFR XML files\", \"./downloads/ecfr/xml\")\n .addOption(\n new Option(\"-g, --granularity <level>\", \"Output granularity: section, part, chapter, or title\")\n .choices([\"section\", \"part\", \"chapter\", \"title\"])\n .default(\"section\"),\n )\n .addOption(\n new Option(\"--link-style <style>\", \"Link style: relative, canonical, or plaintext\")\n .choices([\"relative\", \"canonical\", \"plaintext\"])\n .default(\"plaintext\"),\n )\n .option(\"--include-source-credits\", \"Include source credit annotations\", true)\n .option(\"--no-include-source-credits\", \"Exclude source credit annotations\")\n .option(\"--include-notes\", \"Include all notes (default)\", true)\n .option(\"--no-include-notes\", \"Exclude all notes\")\n .option(\"--include-editorial-notes\", \"Include editorial notes only\", false)\n .option(\"--include-statutory-notes\", \"Include statutory/regulatory notes only\", false)\n .option(\"--include-amendments\", \"Include amendment history notes only\", false)\n .option(\"--dry-run\", \"Parse and report structure without writing files\", false)\n .option(\"-v, --verbose\", \"Enable verbose logging\", false)\n .addHelpText(\n \"after\",\n `\nInput modes (use exactly one):\n <input> Convert a single eCFR XML file\n --titles Convert specific titles by number\n --all Convert all titles in --input-dir\n\nGranularity:\n section One .md file per section (default)\n part One .md file per part, sections inlined\n chapter One .md file per chapter, parts and sections inlined\n title One .md file per title, entire hierarchy inlined\n\nExamples:\n $ lexbuild convert-ecfr --titles 1 Convert eCFR Title 1\n $ lexbuild convert-ecfr --titles 1-5,17 Convert specific titles\n $ lexbuild convert-ecfr --all -g part All titles, part-level\n $ lexbuild convert-ecfr --all --dry-run Preview stats only\n $ lexbuild convert-ecfr ./downloads/ecfr/xml/ECFR-title1.xml -o ./out`,\n )\n .action(async (input: string | undefined, options: ConvertEcfrCommandOptions) => {\n const modeCount = [input, options.titles, options.all].filter(Boolean).length;\n if (modeCount === 0) {\n console.error(error(\"Specify an input file, --titles <spec>, or --all (e.g. --titles 1-5,17)\"));\n process.exit(1);\n }\n if (modeCount > 1) {\n console.error(error(\"Cannot combine <input>, --titles, and --all — use only one\"));\n process.exit(1);\n }\n\n const outputPath = resolve(options.output);\n const dryRunLabel = options.dryRun ? \" [dry-run]\" : \"\";\n\n // Single-file mode\n if (input) {\n const inputPath = resolve(input);\n if (!existsSync(inputPath)) {\n console.error(error(`Input file not found: ${inputPath}`));\n process.exit(1);\n }\n await convertSingleFile(inputPath, outputPath, options, `Converting eCFR${dryRunLabel}...`);\n return;\n }\n\n // Multi-title mode\n let titles: number[];\n if (options.all) {\n const inputDir = resolve(options.inputDir);\n titles = discoverEcfrTitles(inputDir);\n if (titles.length === 0) {\n console.error(error(`No eCFR XML files found in ${inputDir}`));\n process.exit(1);\n }\n } else {\n const titlesSpec = options.titles as string;\n try {\n titles = parseTitles(titlesSpec, 50);\n } catch (err) {\n console.error(error(err instanceof Error ? err.message : String(err)));\n process.exit(1);\n }\n }\n\n const inputDir = resolve(options.inputDir);\n const totalTitles = titles.length;\n const results: ConversionRun[] = [];\n\n const spinner = createSpinner(`Converting eCFR${dryRunLabel}...`);\n spinner.start();\n\n for (const [i, titleNum] of titles.entries()) {\n const xmlPath = titleXmlPath(inputDir, titleNum);\n\n if (!existsSync(xmlPath)) {\n spinner.stop();\n console.error(error(`XML file not found: ${xmlPath}`));\n process.exit(1);\n }\n\n spinner.text = `Converting eCFR Title ${titleNum}${dryRunLabel} (${i + 1}/${totalTitles})...`;\n\n try {\n const run = await runConversion(xmlPath, outputPath, options);\n results.push(run);\n } catch (err) {\n spinner.fail(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n }\n\n spinner.stop();\n\n const outputRelative = relative(process.cwd(), outputPath) || outputPath;\n const headerTitle = options.dryRun\n ? \"lexbuild — eCFR Conversion Summary [dry-run]\"\n : \"lexbuild — eCFR Conversion Summary\";\n const header = summaryBlock({\n title: headerTitle,\n rows: [[\"Directory\", outputRelative]],\n });\n process.stdout.write(header);\n\n const granularity = options.granularity;\n let totalSections = 0;\n let totalParts = 0;\n let totalTokens = 0;\n let totalElapsed = 0;\n\n const tableRows = results.map(({ result, elapsed }) => {\n totalSections += result.sectionsWritten;\n totalParts += result.partCount;\n totalTokens += result.totalTokenEstimate;\n totalElapsed += elapsed;\n\n if (granularity === \"title\") {\n return [result.titleNumber, result.titleName, formatNumber(result.totalTokenEstimate), formatDuration(elapsed)];\n } else if (granularity === \"chapter\") {\n return [\n result.titleNumber,\n result.titleName,\n formatNumber(result.sectionsWritten),\n formatNumber(result.totalTokenEstimate),\n formatDuration(elapsed),\n ];\n } else if (granularity === \"part\") {\n return [\n result.titleNumber,\n result.titleName,\n formatNumber(result.partCount),\n formatNumber(result.totalTokenEstimate),\n formatDuration(elapsed),\n ];\n } else {\n return [\n result.titleNumber,\n result.titleName,\n formatNumber(result.partCount),\n formatNumber(result.sectionsWritten),\n formatNumber(result.totalTokenEstimate),\n formatDuration(elapsed),\n ];\n }\n });\n\n if (granularity === \"title\") {\n tableRows.push([\n chalk.bold(\"Total\"),\n \"\",\n chalk.bold(formatNumber(totalTokens)),\n chalk.bold(formatDuration(totalElapsed)),\n ]);\n } else if (granularity === \"chapter\") {\n tableRows.push([\n chalk.bold(\"Total\"),\n \"\",\n chalk.bold(formatNumber(totalSections)),\n chalk.bold(formatNumber(totalTokens)),\n chalk.bold(formatDuration(totalElapsed)),\n ]);\n } else if (granularity === \"part\") {\n tableRows.push([\n chalk.bold(\"Total\"),\n \"\",\n chalk.bold(formatNumber(totalParts)),\n chalk.bold(formatNumber(totalTokens)),\n chalk.bold(formatDuration(totalElapsed)),\n ]);\n } else {\n tableRows.push([\n chalk.bold(\"Total\"),\n \"\",\n chalk.bold(formatNumber(totalParts)),\n chalk.bold(formatNumber(totalSections)),\n chalk.bold(formatNumber(totalTokens)),\n chalk.bold(formatDuration(totalElapsed)),\n ]);\n }\n\n const tableHeaders =\n granularity === \"title\"\n ? [\"Title\", \"Name\", \"Tokens\", \"Duration\"]\n : granularity === \"chapter\"\n ? [\"Title\", \"Name\", \"Chapters\", \"Tokens\", \"Duration\"]\n : granularity === \"part\"\n ? [\"Title\", \"Name\", \"Parts\", \"Tokens\", \"Duration\"]\n : [\"Title\", \"Name\", \"Parts\", \"Sections\", \"Tokens\", \"Duration\"];\n\n console.log(dataTable(tableHeaders, tableRows));\n\n // Footer — show the primary unit that was converted\n let countLabel: string;\n if (granularity === \"title\") {\n const titleWord = totalTitles === 1 ? \"title\" : \"titles\";\n countLabel = `${formatNumber(totalTitles)} ${titleWord}`;\n } else if (granularity === \"chapter\") {\n const chapterWord = totalSections === 1 ? \"chapter\" : \"chapters\";\n countLabel = `${formatNumber(totalSections)} ${chapterWord}`;\n } else if (granularity === \"part\") {\n const partWord = totalParts === 1 ? \"part\" : \"parts\";\n countLabel = `${formatNumber(totalParts)} ${partWord}`;\n } else {\n const sectionWord = totalSections === 1 ? \"section\" : \"sections\";\n countLabel = `${formatNumber(totalSections)} ${sectionWord}`;\n }\n console.log(`\\n ${success(`Converted ${countLabel} in ${formatDuration(totalElapsed)}`)}`);\n console.log(\"\");\n });\n","/**\n * `lexbuild download-ecfr` command — downloads eCFR XML from govinfo or eCFR API.\n */\n\nimport { Command } from \"commander\";\nimport { relative, resolve } from \"node:path\";\nimport { downloadEcfrTitles, downloadEcfrTitlesFromApi, fetchEcfrTitlesMeta } from \"@lexbuild/ecfr\";\nimport type { EcfrTitlesResponse } from \"@lexbuild/ecfr\";\nimport { createSpinner, summaryBlock, dataTable, formatDuration, formatBytes, success, error } from \"../ui.js\";\nimport { parseTitles } from \"../parse-titles.js\";\n\n/** Valid download source values */\ntype EcfrSource = \"govinfo\" | \"ecfr-api\";\n\n/** Parsed options from the download-ecfr command */\ninterface DownloadEcfrOptions {\n output: string;\n titles?: string | undefined;\n all: boolean;\n source: EcfrSource;\n date?: string | undefined;\n}\n\nexport const downloadEcfrCommand = new Command(\"download-ecfr\")\n .description(\"Download eCFR XML from govinfo or eCFR API\")\n .option(\"-o, --output <dir>\", \"Download directory\", \"./downloads/ecfr/xml\")\n .option(\"--titles <spec>\", \"Title(s) to download: 1, 1-5, or 1-5,8,17\")\n .option(\"--all\", \"Download all 50 eCFR titles\", false)\n .option(\"--source <source>\", \"Download source: ecfr-api (daily-updated) or govinfo (bulk data)\", \"ecfr-api\")\n .option(\"--date <YYYY-MM-DD>\", \"Point-in-time date (ecfr-api source only)\")\n .addHelpText(\n \"after\",\n `\nExamples:\n $ lexbuild download-ecfr --all Download all titles from eCFR API\n $ lexbuild download-ecfr --titles 1 Download Title 1 only\n $ lexbuild download-ecfr --titles 1-5,17 Download specific titles\n $ lexbuild download-ecfr --all --date 2026-01-01 Point-in-time download\n $ lexbuild download-ecfr --all --source govinfo Download from govinfo bulk data\n\nSources:\n ecfr-api — eCFR API from ecfr.gov (default, daily-updated, point-in-time support)\n govinfo — Bulk XML from govinfo.gov (updates irregularly)`,\n )\n .action(async (options: DownloadEcfrOptions) => {\n if (!options.titles && !options.all) {\n console.error(error(\"Specify --titles <spec> or --all (e.g. --titles 1-5,17)\"));\n process.exit(1);\n }\n\n // Validate source\n const validSources: EcfrSource[] = [\"govinfo\", \"ecfr-api\"];\n if (!validSources.includes(options.source)) {\n console.error(error(`Invalid source \"${options.source}\". Valid sources: ${validSources.join(\", \")}`));\n process.exit(1);\n }\n\n // --date is only valid with ecfr-api source\n if (options.date && options.source !== \"ecfr-api\") {\n console.error(error(\"--date is only supported with --source ecfr-api\"));\n process.exit(1);\n }\n\n // Validate date format if provided\n if (options.date && !/^\\d{4}-\\d{2}-\\d{2}$/.test(options.date)) {\n console.error(error(\"--date must be in YYYY-MM-DD format\"));\n process.exit(1);\n }\n\n let titles: number[] | undefined;\n if (options.titles) {\n try {\n titles = parseTitles(options.titles, 50);\n } catch (err) {\n console.error(error(err instanceof Error ? err.message : String(err)));\n process.exit(1);\n }\n }\n\n const outputDir = resolve(options.output);\n const titleCount = titles ? titles.length : 50;\n const sourceLabel = options.source === \"ecfr-api\" ? \"eCFR API\" : \"govinfo\";\n\n // For ecfr-api, fetch metadata upfront to resolve dates and display status\n let meta: EcfrTitlesResponse | undefined;\n if (options.source === \"ecfr-api\" && !options.date) {\n const metaSpinner = createSpinner(\"Fetching eCFR title metadata...\");\n metaSpinner.start();\n try {\n meta = await fetchEcfrTitlesMeta();\n metaSpinner.succeed(\"eCFR title metadata loaded\");\n } catch (err) {\n metaSpinner.fail(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n }\n\n // Build spinner label with date info\n let dateLabel = \"\";\n let statusNote = \"\";\n if (options.date) {\n dateLabel = ` as of ${options.date}`;\n } else if (meta) {\n const primaryDate = meta.importInProgress\n ? (() => {\n const prev = new Date(meta.date);\n prev.setDate(prev.getDate() - 1);\n return prev.toISOString().slice(0, 10);\n })()\n : meta.date;\n dateLabel = ` as of ${primaryDate}`;\n\n // Check for titles with individual processing\n const processingTitles = meta.titles.filter((t) => t.processingInProgress && !t.reserved);\n if (meta.importInProgress && processingTitles.length > 0) {\n const titleWord = processingTitles.length === 1 ? \"title uses\" : \"titles use\";\n statusNote = ` (import in progress, ${processingTitles.length} ${titleWord} earlier dates)`;\n } else if (meta.importInProgress) {\n statusNote = \" (import in progress, using previous day)\";\n } else if (processingTitles.length > 0) {\n const nums = processingTitles.map((t) => t.number).join(\", \");\n statusNote = ` (Title ${nums} processing, using earlier date)`;\n }\n }\n\n const label =\n titleCount === 1\n ? `Downloading eCFR Title ${titles?.[0]} from ${sourceLabel}${dateLabel}${statusNote}`\n : `Downloading ${titleCount} eCFR titles from ${sourceLabel}${dateLabel}${statusNote}`;\n\n const spinner = createSpinner(`${label}...`);\n spinner.start();\n\n const startTime = performance.now();\n\n try {\n if (options.source === \"ecfr-api\") {\n await downloadFromApi(options, titles, outputDir, spinner, startTime, meta);\n } else {\n await downloadFromGovinfo(titles, outputDir, spinner, startTime);\n }\n } catch (err) {\n spinner.fail(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n });\n\n/** Download from govinfo bulk data (existing behavior) */\nasync function downloadFromGovinfo(\n titles: number[] | undefined,\n outputDir: string,\n spinner: ReturnType<typeof createSpinner>,\n startTime: number,\n): Promise<void> {\n const result = await downloadEcfrTitles({\n output: outputDir,\n titles,\n onProgress: ({ current, total, titleNumber }) => {\n if (total === 1) {\n spinner.text = `Downloading eCFR Title ${titleNumber} from govinfo`;\n } else {\n spinner.text = `Downloading eCFR titles from govinfo (${current}/${total}) — Title ${titleNumber}`;\n }\n },\n });\n\n const elapsed = performance.now() - startTime;\n spinner.stop();\n\n const fileRows = result.files.map((file) => [\n String(file.titleNumber),\n formatBytes(file.size),\n relative(outputDir, file.path) || file.path,\n ]);\n\n const output = summaryBlock({\n title: \"lexbuild — eCFR Download Summary\",\n rows: [\n [\"Source\", \"govinfo.gov/bulkdata/ECFR\"],\n [\"Directory\", relative(process.cwd(), outputDir) || outputDir],\n ],\n });\n process.stdout.write(output);\n\n if (fileRows.length > 0) {\n console.log(dataTable([\"Title\", \"Size\", \"File\"], fileRows));\n }\n\n if (result.errors.length > 0) {\n for (const err of result.errors) {\n console.log(` ${error(`Title ${err.titleNumber}: ${err.error}`)}`);\n }\n }\n\n const titleWord = result.titlesDownloaded === 1 ? \"title\" : \"titles\";\n const failSuffix = result.errors.length > 0 ? ` (${result.errors.length} failed)` : \"\";\n const summary = `Downloaded ${result.titlesDownloaded} ${titleWord} (${formatBytes(result.totalBytes)}) in ${formatDuration(elapsed)}`;\n console.log(` ${success(summary + failSuffix)}`);\n console.log(\"\");\n}\n\n/** Download from eCFR API (daily-updated, point-in-time) */\nasync function downloadFromApi(\n options: DownloadEcfrOptions,\n titles: number[] | undefined,\n outputDir: string,\n spinner: ReturnType<typeof createSpinner>,\n startTime: number,\n meta?: EcfrTitlesResponse,\n): Promise<void> {\n const result = await downloadEcfrTitlesFromApi({\n output: outputDir,\n titles,\n date: options.date,\n titlesMeta: meta,\n onProgress: ({ current, total, titleNumber }) => {\n if (total === 1) {\n spinner.text = `Downloading eCFR Title ${titleNumber} from eCFR API`;\n } else {\n spinner.text = `Downloading eCFR titles from eCFR API (${current}/${total}) — Title ${titleNumber}`;\n }\n },\n });\n\n const elapsed = performance.now() - startTime;\n spinner.stop();\n\n // Check if any titles used different dates\n const uniqueDates = new Set(result.files.map((f) => f.asOfDate));\n const dateDisplay =\n uniqueDates.size <= 1 ? result.asOfDate : `${result.asOfDate} (${uniqueDates.size - 1} titles at earlier dates)`;\n\n const fileRows = result.files.map((file) => {\n const row = [String(file.titleNumber), formatBytes(file.size), relative(outputDir, file.path) || file.path];\n // Show the date if it differs from the primary\n if (file.asOfDate !== result.asOfDate) {\n row.push(file.asOfDate);\n }\n return row;\n });\n\n const summaryRows: [string, string][] = [\n [\"Source\", \"ecfr.gov/api/versioner/v1\"],\n [\"As of date\", dateDisplay],\n [\"Directory\", relative(process.cwd(), outputDir) || outputDir],\n ];\n\n const output = summaryBlock({\n title: \"lexbuild — eCFR Download Summary\",\n rows: summaryRows,\n });\n process.stdout.write(output);\n\n // Include date column only if some titles used different dates\n const hasMultipleDates = uniqueDates.size > 1;\n const headings = hasMultipleDates ? [\"Title\", \"Size\", \"File\", \"Date\"] : [\"Title\", \"Size\", \"File\"];\n\n if (fileRows.length > 0) {\n console.log(dataTable(headings, fileRows));\n }\n\n // Report failures with context\n if (result.failed.length > 0) {\n const processing = result.failed.filter((f) => f.status === 503);\n const other = result.failed.filter((f) => f.status !== 503);\n\n if (processing.length > 0) {\n const nums = processing.map((f) => `Title ${f.titleNumber}`).join(\", \");\n console.log(` ${error(`Unavailable (processing on server): ${nums}`)}`);\n console.log(` The eCFR API cannot serve these titles while an import is in progress.`);\n console.log(` Re-run this command later to download them. Existing local files (if any) are preserved.`);\n }\n if (other.length > 0) {\n const nums = other.map((f) => `Title ${f.titleNumber} (${f.status})`).join(\", \");\n console.log(` ${error(`Failed: ${nums}`)}`);\n }\n }\n\n const titleWord = result.titlesDownloaded === 1 ? \"title\" : \"titles\";\n const failSuffix = result.failed.length > 0 ? ` (${result.failed.length} failed)` : \"\";\n const summary = `Downloaded ${result.titlesDownloaded} ${titleWord} (${formatBytes(result.totalBytes)}) in ${formatDuration(elapsed)}`;\n console.log(` ${success(summary + failSuffix)}`);\n console.log(\"\");\n}\n","/**\n * `lexbuild download-fr` command — downloads Federal Register XML + JSON.\n *\n * Supports two sources:\n * - `fr-api` (default): Per-document XML + JSON metadata from FederalRegister.gov API\n * - `govinfo`: Bulk daily-issue XML from govinfo.gov (faster for historical backfill)\n */\n\nimport { Command } from \"commander\";\nimport { relative, resolve } from \"node:path\";\nimport { downloadFrDocuments, downloadSingleFrDocument, downloadFrBulk } from \"@lexbuild/fr\";\nimport type { FrDocumentType } from \"@lexbuild/fr\";\nimport { createSpinner, summaryBlock, formatDuration, formatBytes, formatNumber, error } from \"../ui.js\";\n\n/** Valid document type values for --types flag */\nconst VALID_TYPES = new Map<string, FrDocumentType>([\n [\"rule\", \"RULE\"],\n [\"proposed_rule\", \"PRORULE\"],\n [\"notice\", \"NOTICE\"],\n [\"presidential_document\", \"PRESDOCU\"],\n]);\n\n/** Parsed options from the download-fr command */\ninterface DownloadFrOptions {\n output: string;\n source: string;\n from?: string | undefined;\n to?: string | undefined;\n types?: string | undefined;\n recent?: string | undefined;\n document?: string | undefined;\n limit?: string | undefined;\n concurrency?: string | undefined;\n}\n\nexport const downloadFrCommand = new Command(\"download-fr\")\n .description(\"Download Federal Register XML and metadata\")\n .option(\"-o, --output <dir>\", \"Download directory\", \"./downloads/fr\")\n .option(\"--source <source>\", \"Source: fr-api (default, per-document) or govinfo (bulk daily)\", \"fr-api\")\n .option(\"--from <YYYY-MM-DD>\", \"Start date (inclusive)\")\n .option(\"--to <YYYY-MM-DD>\", \"End date (inclusive, defaults to today)\")\n .option(\"--types <types>\", \"Document types: rule, proposed_rule, notice, presidential_document (fr-api only)\")\n .option(\"--recent <days>\", \"Download last N days\")\n .option(\"--document <number>\", \"Download a single document by number (fr-api only)\")\n .option(\"--limit <n>\", \"Maximum number of documents (fr-api only)\")\n .option(\"--concurrency <n>\", \"Concurrent downloads (default: 10)\")\n .addHelpText(\n \"after\",\n `\nExamples:\n $ lexbuild download-fr --from 2026-01-01 --to 2026-03-31\n $ lexbuild download-fr --from 2026-01-01 --types rule,proposed_rule\n $ lexbuild download-fr --recent 30\n $ lexbuild download-fr --document 2026-06029\n $ lexbuild download-fr --source govinfo --from 2000-01-01 --to 2025-12-31\n\nSources:\n fr-api (default) Per-document XML + JSON from FederalRegister.gov API\n govinfo Bulk daily-issue XML from govinfo.gov (faster for backfill)\n\nDocument types (fr-api only):\n rule Final rules\n proposed_rule Proposed rules (NPRMs)\n notice Notices\n presidential_document Executive orders, memoranda, proclamations`,\n )\n .action(async (options: DownloadFrOptions) => {\n // Validate source\n if (options.source !== \"fr-api\" && options.source !== \"govinfo\") {\n console.error(error(`Invalid source \"${options.source}\". Use \"fr-api\" (default) or \"govinfo\".`));\n process.exit(1);\n }\n\n // Validate: need --from, --recent, or --document\n if (!options.from && !options.recent && !options.document) {\n console.error(\n error(\n \"Specify --from <date>, --recent <days>, or --document <number>\\n\" +\n \"Examples: --from 2026-01-01, --recent 30, --document 2026-06029\",\n ),\n );\n process.exit(1);\n }\n\n // Validate date format\n if (options.from && !/^\\d{4}-\\d{2}-\\d{2}$/.test(options.from)) {\n console.error(error(\"--from must be in YYYY-MM-DD format\"));\n process.exit(1);\n }\n if (options.to && !/^\\d{4}-\\d{2}-\\d{2}$/.test(options.to)) {\n console.error(error(\"--to must be in YYYY-MM-DD format\"));\n process.exit(1);\n }\n\n const outputDir = resolve(options.output);\n const startTime = performance.now();\n\n // Parse concurrency\n let concurrency: number | undefined;\n if (options.concurrency) {\n concurrency = parseInt(options.concurrency, 10);\n if (isNaN(concurrency) || concurrency <= 0) {\n console.error(error(\"--concurrency must be a positive integer\"));\n process.exit(1);\n }\n }\n\n // ── Govinfo bulk mode ──\n if (options.source === \"govinfo\") {\n await downloadGovinfo(options, outputDir, startTime, concurrency);\n return;\n }\n\n // ── FR API: Single document mode ──\n if (options.document) {\n const spinner = createSpinner(`Downloading FR document ${options.document}`);\n try {\n const file = await downloadSingleFrDocument(options.document, outputDir);\n spinner.succeed(`Downloaded FR document ${options.document}`);\n console.log();\n console.log(\n summaryBlock({\n title: \"Download Complete\",\n rows: [\n [\"Document\", file.documentNumber],\n [\"Date\", file.publicationDate],\n [\"Size\", formatBytes(file.size)],\n [\"XML\", relative(process.cwd(), file.xmlPath)],\n [\"JSON\", relative(process.cwd(), file.jsonPath)],\n ],\n }),\n );\n } catch (err) {\n spinner.fail(`Failed to download ${options.document}`);\n console.error(error(err instanceof Error ? err.message : String(err)));\n process.exit(1);\n }\n return;\n }\n\n // ── FR API: Date range mode ──\n await downloadFrApi(options, outputDir, startTime, concurrency);\n });\n\n// ── Govinfo bulk download ──\n\nasync function downloadGovinfo(\n options: DownloadFrOptions,\n outputDir: string,\n startTime: number,\n concurrency: number | undefined,\n): Promise<void> {\n let from: string;\n if (options.recent) {\n const days = parseInt(options.recent, 10);\n if (isNaN(days) || days <= 0) {\n console.error(error(\"--recent must be a positive integer\"));\n process.exit(1);\n }\n const d = new Date();\n d.setDate(d.getDate() - days);\n from = d.toISOString().slice(0, 10);\n } else {\n from = options.from ?? \"\";\n }\n const to = options.to ?? new Date().toISOString().slice(0, 10);\n\n const spinner = createSpinner(`Downloading FR bulk XML from govinfo (${from} to ${to})`);\n spinner.start();\n\n try {\n const result = await downloadFrBulk({\n output: outputDir,\n from,\n to,\n concurrency,\n onProgress: (progress) => {\n const pct = progress.totalDays > 0 ? Math.round((progress.downloaded / progress.totalDays) * 100) : 0;\n spinner.text = `Downloading FR bulk XML (${formatNumber(progress.downloaded + progress.skipped)}/${formatNumber(progress.totalDays)}) ${pct}% ${progress.currentDate}`;\n },\n });\n\n const elapsed = performance.now() - startTime;\n spinner.succeed(`Downloaded ${formatNumber(result.filesDownloaded)} daily FR issues from govinfo`);\n\n console.log();\n const rows: [string, string][] = [\n [\"Source\", \"govinfo (bulk daily XML)\"],\n [\"Date range\", `${result.dateRange.from} → ${result.dateRange.to}`],\n [\"Daily issues\", formatNumber(result.filesDownloaded)],\n [\"Total size\", formatBytes(result.totalBytes)],\n [\"Skipped (no issue)\", formatNumber(result.skipped)],\n [\"Duration\", formatDuration(elapsed)],\n ];\n if (result.failed > 0) {\n rows.push([\"Failed\", formatNumber(result.failed)]);\n }\n rows.push([\"Output\", relative(process.cwd(), outputDir)]);\n\n console.log(summaryBlock({ title: \"Download Complete\", rows }));\n } catch (err) {\n spinner.fail(\"Download failed\");\n console.error(error(err instanceof Error ? err.message : String(err)));\n process.exit(1);\n }\n}\n\n// ── FR API date range download ──\n\nasync function downloadFrApi(\n options: DownloadFrOptions,\n outputDir: string,\n startTime: number,\n concurrency: number | undefined,\n): Promise<void> {\n // Parse --types\n let types: FrDocumentType[] | undefined;\n if (options.types) {\n types = [];\n for (const raw of options.types.split(\",\")) {\n const normalized = raw.trim().toLowerCase();\n const mapped = VALID_TYPES.get(normalized);\n if (!mapped) {\n console.error(\n error(`Invalid document type \"${raw.trim()}\". Valid types: ${[...VALID_TYPES.keys()].join(\", \")}`),\n );\n process.exit(1);\n }\n types.push(mapped);\n }\n }\n\n let from: string;\n if (options.recent) {\n const days = parseInt(options.recent, 10);\n if (isNaN(days) || days <= 0) {\n console.error(error(\"--recent must be a positive integer\"));\n process.exit(1);\n }\n const d = new Date();\n d.setDate(d.getDate() - days);\n from = d.toISOString().slice(0, 10);\n } else {\n from = options.from ?? \"\";\n }\n\n const to = options.to ?? new Date().toISOString().slice(0, 10);\n let limit: number | undefined;\n if (options.limit) {\n limit = parseInt(options.limit, 10);\n if (isNaN(limit) || limit <= 0) {\n console.error(error(\"--limit must be a positive integer\"));\n process.exit(1);\n }\n }\n\n const spinner = createSpinner(`Downloading Federal Register documents from ${from} to ${to}`);\n spinner.start();\n\n try {\n const result = await downloadFrDocuments({\n output: outputDir,\n from,\n to,\n types,\n limit,\n concurrency,\n onProgress: (progress) => {\n const pct =\n progress.totalDocuments > 0 ? Math.round((progress.documentsDownloaded / progress.totalDocuments) * 100) : 0;\n spinner.text = `Downloading FR documents (${formatNumber(progress.documentsDownloaded)}/${formatNumber(progress.totalDocuments)}) ${pct}% [${progress.currentChunk}] ${progress.currentDocument}`;\n },\n });\n\n const elapsed = performance.now() - startTime;\n spinner.succeed(`Downloaded ${formatNumber(result.documentsDownloaded)} Federal Register documents`);\n\n console.log();\n const rows: [string, string][] = [\n [\"Source\", \"FederalRegister.gov API\"],\n [\"Date range\", `${result.dateRange.from} → ${result.dateRange.to}`],\n [\"Documents\", formatNumber(result.documentsDownloaded)],\n [\"Total size\", formatBytes(result.totalBytes)],\n [\"Duration\", formatDuration(elapsed)],\n ];\n if (types) {\n rows.push([\"Types\", types.join(\", \")]);\n }\n if (result.skipped > 0) {\n rows.push([\"Skipped (no XML)\", formatNumber(result.skipped)]);\n }\n if (result.failed.length > 0) {\n rows.push([\"Failed\", formatNumber(result.failed.length)]);\n }\n rows.push([\"Output\", relative(process.cwd(), outputDir)]);\n\n console.log(summaryBlock({ title: \"Download Complete\", rows }));\n\n if (result.failed.length > 0) {\n console.log();\n console.log(error(`${result.failed.length} document(s) failed to download:`));\n for (const f of result.failed.slice(0, 10)) {\n console.error(` ${f.documentNumber}: ${f.error}`);\n }\n if (result.failed.length > 10) {\n console.error(` ... and ${result.failed.length - 10} more`);\n }\n }\n } catch (err) {\n spinner.fail(\"Download failed\");\n console.error(error(err instanceof Error ? err.message : String(err)));\n process.exit(1);\n }\n}\n","/**\n * `lexbuild convert-fr` command — converts Federal Register XML files to Markdown.\n */\n\nimport { Command } from \"commander\";\nimport { existsSync } from \"node:fs\";\nimport { relative, resolve } from \"node:path\";\nimport { convertFrDocuments } from \"@lexbuild/fr\";\nimport type { FrDocumentType } from \"@lexbuild/fr\";\nimport { createSpinner, summaryBlock, formatDuration, formatNumber, error } from \"../ui.js\";\n\n/** Valid document type values for --types flag */\nconst VALID_TYPES = new Map<string, FrDocumentType>([\n [\"rule\", \"RULE\"],\n [\"proposed_rule\", \"PRORULE\"],\n [\"notice\", \"NOTICE\"],\n [\"presidential_document\", \"PRESDOCU\"],\n]);\n\n/** Parsed options from the convert-fr command */\ninterface ConvertFrCommandOptions {\n output: string;\n inputDir: string;\n all: boolean;\n from?: string | undefined;\n to?: string | undefined;\n types?: string | undefined;\n linkStyle: \"relative\" | \"canonical\" | \"plaintext\";\n dryRun: boolean;\n verbose: boolean;\n}\n\nexport const convertFrCommand = new Command(\"convert-fr\")\n .description(\"Convert Federal Register XML to Markdown\")\n .argument(\"[input]\", \"Path to single FR XML file (optional)\")\n .option(\"-o, --output <dir>\", \"Output directory\", \"./output\")\n .option(\"-i, --input-dir <dir>\", \"Directory containing downloaded FR files\", \"./downloads/fr\")\n .option(\"--all\", \"Convert all downloaded documents in input directory\", false)\n .option(\"--from <YYYY-MM-DD>\", \"Filter: start date\")\n .option(\"--to <YYYY-MM-DD>\", \"Filter: end date\")\n .option(\"--types <types>\", \"Filter: document types (rule, proposed_rule, notice, presidential_document)\")\n .option(\"--link-style <style>\", \"Link style: relative, canonical, plaintext\", \"plaintext\")\n .option(\"--dry-run\", \"Parse only, don't write files\", false)\n .option(\"-v, --verbose\", \"Print detailed file output\", false)\n .addHelpText(\n \"after\",\n `\nExamples:\n $ lexbuild convert-fr --all Convert all downloaded FR documents\n $ lexbuild convert-fr --from 2026-01-01 --to 2026-03-31 Convert by date range\n $ lexbuild convert-fr --all --types rule Convert only rules\n $ lexbuild convert-fr ./downloads/fr/2026/03/2026-06029.xml Convert single document\n $ lexbuild convert-fr --all --dry-run Preview without writing files`,\n )\n .action(async (inputArg: string | undefined, options: ConvertFrCommandOptions) => {\n // Validate: need [input], --all, or --from\n if (!inputArg && !options.all && !options.from) {\n console.error(\n error(\n \"Specify a path to an XML file, --all, or --from <date>\\n\" +\n \"Examples: convert-fr --all, convert-fr --from 2026-01-01\",\n ),\n );\n process.exit(1);\n }\n\n // Parse --types\n let types: FrDocumentType[] | undefined;\n if (options.types) {\n types = [];\n for (const raw of options.types.split(\",\")) {\n const normalized = raw.trim().toLowerCase();\n const mapped = VALID_TYPES.get(normalized);\n if (!mapped) {\n console.error(\n error(`Invalid document type \"${raw.trim()}\". Valid types: ${[...VALID_TYPES.keys()].join(\", \")}`),\n );\n process.exit(1);\n }\n types.push(mapped);\n }\n }\n\n // Determine input path\n let inputPath: string;\n if (inputArg) {\n inputPath = resolve(inputArg);\n if (!existsSync(inputPath)) {\n console.error(error(`File not found: ${inputArg}`));\n process.exit(1);\n }\n } else {\n inputPath = resolve(options.inputDir);\n if (!existsSync(inputPath)) {\n console.error(error(`Input directory not found: ${options.inputDir}`));\n process.exit(1);\n }\n }\n\n const outputPath = resolve(options.output);\n const startTime = performance.now();\n\n const spinner = createSpinner(\n options.dryRun ? \"Analyzing Federal Register documents (dry run)\" : \"Converting Federal Register documents\",\n );\n spinner.start();\n\n try {\n const result = await convertFrDocuments({\n input: inputPath,\n output: outputPath,\n linkStyle: options.linkStyle,\n dryRun: options.dryRun,\n from: options.from,\n to: options.to,\n types,\n onProgress: (progress) => {\n const pct = progress.totalFiles > 0 ? Math.round((progress.filesProcessed / progress.totalFiles) * 100) : 0;\n spinner.text = `Converting FR documents (${formatNumber(progress.documentsConverted)} docs, ${formatNumber(progress.filesProcessed)}/${formatNumber(progress.totalFiles)} files) ${pct}%`;\n },\n });\n\n const elapsed = performance.now() - startTime;\n\n if (options.dryRun) {\n spinner.succeed(`Dry run: ${formatNumber(result.documentsConverted)} documents would be converted`);\n } else {\n spinner.succeed(`Converted ${formatNumber(result.documentsConverted)} Federal Register documents`);\n }\n\n console.log();\n\n const rows: [string, string][] = [[\"Documents\", formatNumber(result.documentsConverted)]];\n\n if (!options.dryRun) {\n rows.push([\"Est. tokens\", formatNumber(result.totalTokenEstimate)]);\n }\n\n rows.push([\"Duration\", formatDuration(elapsed)]);\n\n if (!options.dryRun) {\n rows.push([\"Output\", relative(process.cwd(), outputPath) + \"/fr/\"]);\n }\n\n const footer = options.dryRun\n ? undefined\n : `Converted ${formatNumber(result.documentsConverted)} documents in ${formatDuration(elapsed)}`;\n\n console.log(summaryBlock({ title: \"Conversion Complete\", rows, footer }));\n\n // Verbose file listing not available for streaming conversion (files not tracked in memory)\n } catch (err) {\n spinner.fail(\"Conversion failed\");\n console.error(error(err instanceof Error ? err.message : String(err)));\n process.exit(1);\n }\n });\n","/**\n * `lexbuild enrich-fr` command — enriches FR Markdown frontmatter with API metadata.\n *\n * Fetches rich metadata from the FederalRegister.gov API listing endpoint and\n * patches existing .md files that were converted from govinfo bulk XML. Does not\n * re-parse XML or re-render Markdown — only updates YAML frontmatter.\n */\n\nimport { Command } from \"commander\";\nimport { resolve } from \"node:path\";\nimport { enrichFrDocuments } from \"@lexbuild/fr\";\nimport { createSpinner, summaryBlock, formatDuration, formatNumber, error } from \"../ui.js\";\n\n/** Parsed options from the enrich-fr command */\ninterface EnrichFrCliOptions {\n output: string;\n from?: string | undefined;\n to?: string | undefined;\n recent?: string | undefined;\n force?: boolean | undefined;\n}\n\nexport const enrichFrCommand = new Command(\"enrich-fr\")\n .description(\"Enrich FR Markdown frontmatter with FederalRegister.gov API metadata\")\n .option(\"-o, --output <dir>\", \"Output directory containing FR .md files\", \"./output\")\n .option(\"--from <YYYY-MM-DD>\", \"Start date (inclusive)\")\n .option(\"--to <YYYY-MM-DD>\", \"End date (inclusive, defaults to today)\")\n .option(\"--recent <days>\", \"Enrich last N days\")\n .option(\"--force\", \"Overwrite already-enriched files (have fr_citation)\")\n .addHelpText(\n \"after\",\n `\nExamples:\n $ lexbuild enrich-fr --from 2000-01-01 --to 2026-03-25\n $ lexbuild enrich-fr --recent 30\n $ lexbuild enrich-fr --from 2020-01-01 --force\n\nThis command fetches metadata from the FederalRegister.gov API listing endpoint\nand patches YAML frontmatter in existing .md files. Use it to backfill rich\nmetadata (agencies, CFR references, docket IDs, citations, etc.) into files\nthat were originally converted from govinfo bulk XML.\n\nFiles that already have fr_citation are skipped unless --force is used.`,\n )\n .action(async (options: EnrichFrCliOptions) => {\n // Validate: need --from or --recent\n if (!options.from && !options.recent) {\n console.error(error(\"Specify --from <date> or --recent <days>\\n\" + \"Examples: --from 2000-01-01, --recent 30\"));\n process.exit(1);\n }\n\n // Validate date format\n if (options.from && !/^\\d{4}-\\d{2}-\\d{2}$/.test(options.from)) {\n console.error(error(\"--from must be in YYYY-MM-DD format\"));\n process.exit(1);\n }\n if (options.to && !/^\\d{4}-\\d{2}-\\d{2}$/.test(options.to)) {\n console.error(error(\"--to must be in YYYY-MM-DD format\"));\n process.exit(1);\n }\n\n let from: string;\n if (options.recent) {\n const days = parseInt(options.recent, 10);\n if (isNaN(days) || days <= 0) {\n console.error(error(\"--recent must be a positive integer\"));\n process.exit(1);\n }\n const d = new Date();\n d.setDate(d.getDate() - days);\n from = d.toISOString().slice(0, 10);\n } else {\n from = options.from ?? \"\";\n }\n\n const to = options.to ?? new Date().toISOString().slice(0, 10);\n const outputDir = resolve(options.output);\n const startTime = performance.now();\n\n const spinner = createSpinner(`Enriching FR frontmatter (${from} to ${to})`);\n spinner.start();\n\n try {\n const result = await enrichFrDocuments({\n output: outputDir,\n from,\n to,\n force: options.force,\n onProgress: (progress) => {\n const processed = progress.enriched + progress.skipped + progress.notFound;\n const pct = progress.total > 0 ? Math.round((processed / progress.total) * 100) : 0;\n spinner.text = `Enriching FR frontmatter (${formatNumber(progress.enriched)} enriched, ${formatNumber(progress.skipped)} skipped) ${pct}% [${progress.currentChunk}] ${progress.currentDocument}`;\n },\n });\n\n const elapsed = performance.now() - startTime;\n spinner.succeed(`Enriched ${formatNumber(result.enriched)} FR documents`);\n\n console.log();\n const rows: [string, string][] = [\n [\"Date range\", `${result.dateRange.from} → ${result.dateRange.to}`],\n [\"API documents\", formatNumber(result.total)],\n [\"Enriched\", formatNumber(result.enriched)],\n [\"Skipped\", formatNumber(result.skipped)],\n [\"Not found\", formatNumber(result.notFound)],\n [\"Duration\", formatDuration(elapsed)],\n ];\n\n console.log(summaryBlock({ title: \"Enrichment Complete\", rows }));\n } catch (err) {\n spinner.fail(\"Enrichment failed\");\n console.error(error(err instanceof Error ? err.message : String(err)));\n process.exit(1);\n }\n });\n"],"mappings":"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","names":["Command","chalk","inputDir","chalk","Command","relative","resolve","Command","resolve","relative","Command","detectLatestReleasePoint","FALLBACK_RELEASE_POINT","Command","detectLatestReleasePoint","FALLBACK_RELEASE_POINT","chalk","Command","Option","existsSync","readdirSync","join","relative","resolve","buildConvertOptions","titleXmlPath","join","existsSync","readdirSync","runConversion","convertSingleFile","relative","Command","Option","resolve","inputDir","chalk","Command","relative","resolve","Command","resolve","relative","Command","relative","resolve","Command","resolve","relative","Command","existsSync","relative","resolve","VALID_TYPES","Command","resolve","existsSync","relative","Command","resolve","Command","resolve","require","Command"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lexbuild/cli",
3
- "version": "1.16.1",
3
+ "version": "1.17.1",
4
4
  "description": "Compiler for legal and civic texts. Converts disparate statutory data into structured formats optimized for AI, RAG, and semantic search.",
5
5
  "author": "Chris Thomas",
6
6
  "license": "MIT",
@@ -52,9 +52,9 @@
52
52
  "cli-table3": "^0.6.5",
53
53
  "commander": "^13.1.0",
54
54
  "ora": "^8.2.0",
55
- "@lexbuild/ecfr": "1.16.1",
56
- "@lexbuild/fr": "1.16.1",
57
- "@lexbuild/usc": "1.16.1"
55
+ "@lexbuild/fr": "1.17.1",
56
+ "@lexbuild/usc": "1.17.1",
57
+ "@lexbuild/ecfr": "1.17.1"
58
58
  },
59
59
  "devDependencies": {
60
60
  "@types/node": "^25.3.2",