unrag 0.2.9 → 0.2.11

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.
Files changed (106) hide show
  1. package/dist/cli/index.js +227 -29
  2. package/dist/debug-tui/index.js +145 -0
  3. package/package.json +7 -3
  4. package/registry/connectors/google-drive/_api-types.ts +4 -0
  5. package/registry/connectors/google-drive/client.ts +2 -2
  6. package/registry/connectors/google-drive/index.ts +4 -4
  7. package/registry/connectors/google-drive/mime.ts +1 -1
  8. package/registry/connectors/google-drive/sync.ts +7 -7
  9. package/registry/connectors/google-drive/types.ts +3 -3
  10. package/registry/connectors/notion/index.ts +13 -5
  11. package/registry/connectors/notion/render.ts +1 -1
  12. package/registry/connectors/notion/sync.ts +5 -5
  13. package/registry/connectors/notion/types.ts +3 -4
  14. package/registry/core/assets.ts +2 -2
  15. package/registry/core/chunking.ts +1 -1
  16. package/registry/core/config.ts +4 -3
  17. package/registry/core/context-engine.ts +96 -18
  18. package/registry/core/debug-emitter.ts +162 -0
  19. package/registry/core/debug-events.ts +222 -0
  20. package/registry/core/deep-merge.ts +1 -1
  21. package/registry/core/delete.ts +41 -1
  22. package/registry/core/index.ts +10 -10
  23. package/registry/core/ingest.ts +106 -5
  24. package/registry/core/rerank.ts +37 -1
  25. package/registry/core/retrieve.ts +62 -2
  26. package/registry/core/types.ts +11 -6
  27. package/registry/debug/client.ts +332 -0
  28. package/registry/debug/commands.ts +699 -0
  29. package/registry/debug/index.ts +93 -0
  30. package/registry/debug/runtime.ts +63 -0
  31. package/registry/debug/server.ts +554 -0
  32. package/registry/debug/tui/App.tsx +193 -0
  33. package/registry/debug/tui/assets/unragLogo.ts +36 -0
  34. package/registry/debug/tui/components/Dashboard.tsx +192 -0
  35. package/registry/debug/tui/components/Docs.tsx +563 -0
  36. package/registry/debug/tui/components/Doctor.tsx +290 -0
  37. package/registry/debug/tui/components/Eval.tsx +377 -0
  38. package/registry/debug/tui/components/EventDetail.tsx +237 -0
  39. package/registry/debug/tui/components/EventList.tsx +202 -0
  40. package/registry/debug/tui/components/EventRow.tsx +104 -0
  41. package/registry/debug/tui/components/Header.tsx +58 -0
  42. package/registry/debug/tui/components/HelpOverlay.tsx +101 -0
  43. package/registry/debug/tui/components/Ingest.tsx +351 -0
  44. package/registry/debug/tui/components/Logo.tsx +138 -0
  45. package/registry/debug/tui/components/MetricCard.tsx +59 -0
  46. package/registry/debug/tui/components/QueryRunner.tsx +327 -0
  47. package/registry/debug/tui/components/ScrollableText.tsx +120 -0
  48. package/registry/debug/tui/components/Sparkline.tsx +71 -0
  49. package/registry/debug/tui/components/StatusBar.tsx +63 -0
  50. package/registry/debug/tui/components/TabBar.tsx +45 -0
  51. package/registry/debug/tui/components/Traces.tsx +294 -0
  52. package/registry/debug/tui/context/HotkeysLock.tsx +68 -0
  53. package/registry/debug/tui/hooks/useConnection.ts +155 -0
  54. package/registry/debug/tui/hooks/useEvents.ts +68 -0
  55. package/registry/debug/tui/hooks/useScrollWindow.ts +58 -0
  56. package/registry/debug/tui/hooks/useTerminalSize.ts +45 -0
  57. package/registry/debug/tui/theme.ts +175 -0
  58. package/registry/debug/types.ts +593 -0
  59. package/registry/debug/unrag-json.ts +40 -0
  60. package/registry/embedding/ai.ts +1 -1
  61. package/registry/embedding/azure.ts +3 -3
  62. package/registry/embedding/bedrock.ts +3 -3
  63. package/registry/embedding/cohere.ts +3 -3
  64. package/registry/embedding/google.ts +3 -3
  65. package/registry/embedding/mistral.ts +3 -3
  66. package/registry/embedding/ollama.ts +3 -3
  67. package/registry/embedding/openai.ts +3 -3
  68. package/registry/embedding/openrouter.ts +2 -2
  69. package/registry/embedding/together.ts +8 -4
  70. package/registry/embedding/vertex.ts +3 -3
  71. package/registry/embedding/voyage.ts +141 -101
  72. package/registry/eval/index.ts +8 -8
  73. package/registry/eval/report.ts +2 -2
  74. package/registry/eval/runner.ts +10 -6
  75. package/registry/extractors/_shared/fetch.ts +1 -1
  76. package/registry/extractors/audio-transcribe/index.ts +2 -2
  77. package/registry/extractors/file-docx/index.ts +6 -8
  78. package/registry/extractors/file-pptx/index.ts +4 -4
  79. package/registry/extractors/file-text/index.ts +4 -4
  80. package/registry/extractors/file-xlsx/index.ts +4 -4
  81. package/registry/extractors/image-caption-llm/index.ts +4 -4
  82. package/registry/extractors/image-ocr/index.ts +4 -4
  83. package/registry/extractors/pdf-llm/index.ts +4 -4
  84. package/registry/extractors/pdf-ocr/index.ts +3 -3
  85. package/registry/extractors/pdf-text-layer/index.ts +3 -3
  86. package/registry/extractors/video-frames/index.ts +3 -3
  87. package/registry/extractors/video-transcribe/index.ts +2 -2
  88. package/registry/manifest.json +9 -0
  89. package/registry/rerank/cohere.ts +7 -7
  90. package/registry/rerank/custom.ts +2 -2
  91. package/registry/rerank/index.ts +3 -3
  92. package/registry/rerank/types.ts +1 -1
  93. package/registry/shims.d.ts +60 -0
  94. package/registry/store/drizzle/index.ts +9 -0
  95. package/registry/store/drizzle/store.ts +386 -0
  96. package/registry/store/prisma/index.ts +3 -0
  97. package/registry/store/prisma/store.ts +330 -0
  98. package/registry/store/raw-sql/index.ts +3 -0
  99. package/registry/store/raw-sql/store.ts +369 -0
  100. package/registry/store/drizzle-postgres-pgvector/index.ts +0 -4
  101. package/registry/store/drizzle-postgres-pgvector/store.ts +0 -176
  102. package/registry/store/prisma-postgres-pgvector/index.ts +0 -3
  103. package/registry/store/prisma-postgres-pgvector/store.ts +0 -155
  104. package/registry/store/raw-sql-postgres-pgvector/index.ts +0 -3
  105. package/registry/store/raw-sql-postgres-pgvector/store.ts +0 -177
  106. /package/registry/store/{drizzle-postgres-pgvector → drizzle}/schema.ts +0 -0
package/dist/cli/index.js CHANGED
@@ -19,7 +19,7 @@ var __toESM = (mod, isNodeMode, target) => {
19
19
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
20
20
 
21
21
  // cli/run.ts
22
- import { intro, outro as outro5 } from "@clack/prompts";
22
+ import { intro, outro as outro6 } from "@clack/prompts";
23
23
 
24
24
  // cli/commands/init.ts
25
25
  import {
@@ -97,6 +97,11 @@ var writeText = async (filePath, content) => {
97
97
  await ensureDir(path2.dirname(filePath));
98
98
  await writeFile(filePath, content, "utf8");
99
99
  };
100
+ var rewriteRegistryAliasImports = (content, aliasBase) => {
101
+ if (!content.includes("@registry"))
102
+ return content;
103
+ return content.replaceAll("@registry/", `${aliasBase}/`);
104
+ };
100
105
  var EXTRACTOR_FACTORY = {
101
106
  "pdf-llm": "createPdfLlmExtractor",
102
107
  "pdf-text-layer": "createPdfTextLayerExtractor",
@@ -400,6 +405,26 @@ async function copyRegistryFiles(selection) {
400
405
  src: path2.join(selection.registryRoot, "core/rerank.ts"),
401
406
  dest: path2.join(installBaseAbs, "core/rerank.ts")
402
407
  },
408
+ {
409
+ src: path2.join(selection.registryRoot, "core/debug-emitter.ts"),
410
+ dest: path2.join(installBaseAbs, "core/debug-emitter.ts")
411
+ },
412
+ {
413
+ src: path2.join(selection.registryRoot, "core/debug-events.ts"),
414
+ dest: path2.join(installBaseAbs, "core/debug-events.ts")
415
+ },
416
+ {
417
+ src: path2.join(selection.registryRoot, "extractors/_shared/fetch.ts"),
418
+ dest: path2.join(installBaseAbs, "extractors/_shared/fetch.ts")
419
+ },
420
+ {
421
+ src: path2.join(selection.registryRoot, "extractors/_shared/media.ts"),
422
+ dest: path2.join(installBaseAbs, "extractors/_shared/media.ts")
423
+ },
424
+ {
425
+ src: path2.join(selection.registryRoot, "extractors/_shared/text.ts"),
426
+ dest: path2.join(installBaseAbs, "extractors/_shared/text.ts")
427
+ },
403
428
  {
404
429
  src: path2.join(selection.registryRoot, "embedding/_shared.ts"),
405
430
  dest: path2.join(installBaseAbs, "embedding/_shared.ts")
@@ -455,29 +480,29 @@ async function copyRegistryFiles(selection) {
455
480
  ];
456
481
  if (selection.storeAdapter === "drizzle") {
457
482
  fileMappings.push({
458
- src: path2.join(selection.registryRoot, "store/drizzle-postgres-pgvector/index.ts"),
483
+ src: path2.join(selection.registryRoot, "store/drizzle/index.ts"),
459
484
  dest: path2.join(installBaseAbs, "store/drizzle/index.ts")
460
485
  }, {
461
- src: path2.join(selection.registryRoot, "store/drizzle-postgres-pgvector/schema.ts"),
486
+ src: path2.join(selection.registryRoot, "store/drizzle/schema.ts"),
462
487
  dest: path2.join(installBaseAbs, "store/drizzle/schema.ts")
463
488
  }, {
464
- src: path2.join(selection.registryRoot, "store/drizzle-postgres-pgvector/store.ts"),
489
+ src: path2.join(selection.registryRoot, "store/drizzle/store.ts"),
465
490
  dest: path2.join(installBaseAbs, "store/drizzle/store.ts")
466
491
  });
467
492
  } else if (selection.storeAdapter === "raw-sql") {
468
493
  fileMappings.push({
469
- src: path2.join(selection.registryRoot, "store/raw-sql-postgres-pgvector/index.ts"),
494
+ src: path2.join(selection.registryRoot, "store/raw-sql/index.ts"),
470
495
  dest: path2.join(installBaseAbs, "store/raw-sql/index.ts")
471
496
  }, {
472
- src: path2.join(selection.registryRoot, "store/raw-sql-postgres-pgvector/store.ts"),
497
+ src: path2.join(selection.registryRoot, "store/raw-sql/store.ts"),
473
498
  dest: path2.join(installBaseAbs, "store/raw-sql/store.ts")
474
499
  });
475
500
  } else {
476
501
  fileMappings.push({
477
- src: path2.join(selection.registryRoot, "store/prisma-postgres-pgvector/index.ts"),
502
+ src: path2.join(selection.registryRoot, "store/prisma/index.ts"),
478
503
  dest: path2.join(installBaseAbs, "store/prisma/index.ts")
479
504
  }, {
480
- src: path2.join(selection.registryRoot, "store/prisma-postgres-pgvector/store.ts"),
505
+ src: path2.join(selection.registryRoot, "store/prisma/store.ts"),
481
506
  dest: path2.join(installBaseAbs, "store/prisma/store.ts")
482
507
  });
483
508
  }
@@ -505,7 +530,8 @@ async function copyRegistryFiles(selection) {
505
530
  }
506
531
  }
507
532
  const raw = await readText(mapping.src);
508
- const content = mapping.transform ? mapping.transform(raw) : raw;
533
+ const transformed = mapping.transform ? mapping.transform(raw) : raw;
534
+ const content = rewriteRegistryAliasImports(transformed, selection.aliasBase);
509
535
  await writeText(mapping.dest, content);
510
536
  }
511
537
  }
@@ -543,7 +569,8 @@ async function copyConnectorFiles(selection) {
543
569
  }
544
570
  }
545
571
  const raw = await readText(src);
546
- await writeText(dest, raw);
572
+ const content = rewriteRegistryAliasImports(raw, selection.aliasBase);
573
+ await writeText(dest, content);
547
574
  }
548
575
  }
549
576
  async function copyExtractorFiles(selection) {
@@ -569,7 +596,8 @@ async function copyExtractorFiles(selection) {
569
596
  return false;
570
597
  try {
571
598
  const [srcRaw, destRaw] = await Promise.all([readText(src), readText(dest)]);
572
- if (srcRaw === destRaw)
599
+ const nextSrc = rewriteRegistryAliasImports(srcRaw, selection.aliasBase);
600
+ if (nextSrc === destRaw)
573
601
  return false;
574
602
  } catch {}
575
603
  const answer = await confirm({
@@ -591,7 +619,8 @@ async function copyExtractorFiles(selection) {
591
619
  if (!await shouldWrite(src, dest))
592
620
  continue;
593
621
  const raw = await readText(src);
594
- await writeText(dest, raw);
622
+ const content = rewriteRegistryAliasImports(raw, selection.aliasBase);
623
+ await writeText(dest, content);
595
624
  }
596
625
  for (const src of sharedFiles) {
597
626
  if (!await exists(src)) {
@@ -602,7 +631,8 @@ async function copyExtractorFiles(selection) {
602
631
  if (!await shouldWrite(src, dest))
603
632
  continue;
604
633
  const raw = await readText(src);
605
- await writeText(dest, raw);
634
+ const content = rewriteRegistryAliasImports(raw, selection.aliasBase);
635
+ await writeText(dest, content);
606
636
  }
607
637
  }
608
638
  async function copyBatteryFiles(selection) {
@@ -614,6 +644,14 @@ async function copyBatteryFiles(selection) {
614
644
  throw new Error(`Unknown battery registry: ${path2.relative(selection.registryRoot, batteryRegistryAbs)}`);
615
645
  }
616
646
  const batteryFiles = await listFilesRecursive(batteryRegistryAbs);
647
+ const filteredBatteryFiles = batteryFiles.filter((abs) => {
648
+ if (batteryRegistryDir === "debug") {
649
+ const rel = path2.relative(batteryRegistryAbs, abs).replace(/\\/g, "/");
650
+ if (rel === "tui" || rel.startsWith("tui/"))
651
+ return false;
652
+ }
653
+ return true;
654
+ });
617
655
  const destRootAbs = path2.join(installBaseAbs, batteryRegistryDir);
618
656
  const nonInteractive = Boolean(selection.yes) || !process.stdin.isTTY;
619
657
  const overwritePolicy = selection.overwrite ?? "skip";
@@ -626,7 +664,8 @@ async function copyBatteryFiles(selection) {
626
664
  return false;
627
665
  try {
628
666
  const [srcRaw, destRaw] = await Promise.all([readText(src), readText(dest)]);
629
- if (srcRaw === destRaw)
667
+ const nextSrc = rewriteRegistryAliasImports(srcRaw, selection.aliasBase);
668
+ if (nextSrc === destRaw)
630
669
  return false;
631
670
  } catch {}
632
671
  const answer = await confirm({
@@ -639,7 +678,7 @@ async function copyBatteryFiles(selection) {
639
678
  }
640
679
  return Boolean(answer);
641
680
  };
642
- for (const src of batteryFiles) {
681
+ for (const src of filteredBatteryFiles) {
643
682
  if (!await exists(src)) {
644
683
  throw new Error(`Registry file missing: ${src}`);
645
684
  }
@@ -648,7 +687,8 @@ async function copyBatteryFiles(selection) {
648
687
  if (!await shouldWrite(src, dest))
649
688
  continue;
650
689
  const raw = await readText(src);
651
- await writeText(dest, raw);
690
+ const content = rewriteRegistryAliasImports(raw, selection.aliasBase);
691
+ await writeText(dest, content);
652
692
  }
653
693
  }
654
694
 
@@ -887,6 +927,9 @@ function depsForBattery(battery) {
887
927
  deps["@ai-sdk/cohere"] = "^3.0.1";
888
928
  }
889
929
  if (battery === "eval") {}
930
+ if (battery === "debug") {
931
+ deps["ws"] = "^8.18.0";
932
+ }
890
933
  return { deps, devDeps };
891
934
  }
892
935
  function installCmd(pm) {
@@ -1038,7 +1081,7 @@ var EVAL_PACKAGE_JSON_SCRIPTS = {
1038
1081
  "unrag:eval:ci": `bun run scripts/unrag-eval.ts -- --dataset .unrag/eval/datasets/sample.json --ci`
1039
1082
  };
1040
1083
  function renderEvalRunnerScript(opts) {
1041
- const installImportBase = `../${opts.installDir.replace(/\\/g, "/")}`;
1084
+ const aliasBase = String(opts.aliasBase ?? "").trim() || "@unrag";
1042
1085
  return `/**
1043
1086
  * Unrag eval runner entrypoint (generated).
1044
1087
  *
@@ -1048,7 +1091,7 @@ function renderEvalRunnerScript(opts) {
1048
1091
  import path from "node:path";
1049
1092
  import { access, readFile } from "node:fs/promises";
1050
1093
 
1051
- import { createUnragEngine } from "../unrag.config";
1094
+ import { createUnragEngine } from "${aliasBase}/config";
1052
1095
  import {
1053
1096
  runEval,
1054
1097
  readEvalReportFromFile,
@@ -1060,7 +1103,7 @@ import {
1060
1103
  type EvalMode,
1061
1104
  type EvalThresholds,
1062
1105
  type EvalCleanupPolicy,
1063
- } from "${installImportBase}/eval";
1106
+ } from "${aliasBase}/eval";
1064
1107
 
1065
1108
  type CliArgs = {
1066
1109
  dataset?: string;
@@ -1565,6 +1608,7 @@ async function initCommand(args) {
1565
1608
  projectRoot: root,
1566
1609
  registryRoot,
1567
1610
  installDir,
1611
+ aliasBase,
1568
1612
  extractor,
1569
1613
  yes: nonInteractive,
1570
1614
  overwrite: overwritePolicy
@@ -1595,6 +1639,7 @@ async function initCommand(args) {
1595
1639
  projectRoot: root,
1596
1640
  registryRoot,
1597
1641
  installDir,
1642
+ aliasBase,
1598
1643
  connector,
1599
1644
  yes: nonInteractive,
1600
1645
  overwrite: overwritePolicy
@@ -1622,6 +1667,7 @@ async function initCommand(args) {
1622
1667
  projectRoot: root,
1623
1668
  registryRoot,
1624
1669
  installDir,
1670
+ aliasBase,
1625
1671
  battery,
1626
1672
  yes: nonInteractive,
1627
1673
  overwrite: overwritePolicy
@@ -1674,7 +1720,7 @@ async function initCommand(args) {
1674
1720
  `);
1675
1721
  await writeIfMissing(evalConfigAbs, JSON.stringify(EVAL_CONFIG_DEFAULT, null, 2) + `
1676
1722
  `);
1677
- await writeIfMissing(scriptAbs, renderEvalRunnerScript({ installDir }));
1723
+ await writeIfMissing(scriptAbs, renderEvalRunnerScript({ aliasBase }));
1678
1724
  const pkg2 = await readPackageJson(root);
1679
1725
  const existingScripts = pkg2.scripts ?? {};
1680
1726
  const toAdd = {};
@@ -1690,8 +1736,11 @@ async function initCommand(args) {
1690
1736
  }
1691
1737
  const pm = await detectPackageManager(root);
1692
1738
  const installLine = merged.changes.length === 0 ? "Dependencies already satisfied." : noInstall ? `Next: run \`${installCmd(pm)}\`` : "Dependencies installed.";
1693
- const isNext = Boolean((merged.pkg.dependencies ?? {})["next"]) || Boolean((merged.pkg.devDependencies ?? {})["next"]);
1694
- const tsconfigResult = isNext ? await patchTsconfigPaths({ projectRoot: root, installDir, aliasBase }) : { changed: false };
1739
+ const tsconfigResult = await patchTsconfigPaths({
1740
+ projectRoot: root,
1741
+ installDir,
1742
+ aliasBase
1743
+ });
1695
1744
  const envHint = (() => {
1696
1745
  if (embeddingProvider === "ai") {
1697
1746
  return [
@@ -1801,7 +1850,7 @@ async function initCommand(args) {
1801
1850
  `- Embedding provider: ${embeddingProvider}`,
1802
1851
  richMediaEnabled ? `- Extractors: ${selectedExtractors.length > 0 ? selectedExtractors.join(", ") : "none"}` : "",
1803
1852
  richMediaEnabled ? ` Tip: you can tweak extractors + assetProcessing flags in unrag.config.ts later.` : ` Tip: re-run \`unrag init --rich-media\` (or edit unrag.config.ts) to enable rich media later.`,
1804
- isNext ? tsconfigResult.changed ? `- Next.js: updated ${tsconfigResult.file} (added aliases)` : `- Next.js: no tsconfig changes needed` : `- Next.js: not detected`,
1853
+ tsconfigResult.changed ? `- TypeScript: updated ${tsconfigResult.file} (added aliases)` : `- TypeScript: no tsconfig changes needed`,
1805
1854
  "",
1806
1855
  merged.changes.length > 0 ? `Added deps: ${merged.changes.map((c) => c.name).join(", ")}` : "Added deps: none",
1807
1856
  installLine,
@@ -1983,6 +2032,7 @@ Available batteries: ${Array.from(availableBatteries).join(", ")}`);
1983
2032
  projectRoot: root,
1984
2033
  registryRoot,
1985
2034
  installDir: config.installDir,
2035
+ aliasBase: config.aliasBase ?? "@unrag",
1986
2036
  battery,
1987
2037
  yes: nonInteractive
1988
2038
  });
@@ -2038,7 +2088,7 @@ Available batteries: ${Array.from(availableBatteries).join(", ")}`);
2038
2088
  cleanup: "none",
2039
2089
  ingest: true
2040
2090
  };
2041
- const installImportBase = `../${config.installDir.replace(/\\/g, "/")}`;
2091
+ const aliasBase = String(config.aliasBase ?? "").trim() || "@unrag";
2042
2092
  const script = `/**
2043
2093
  * Unrag eval runner entrypoint (generated).
2044
2094
  *
@@ -2048,7 +2098,7 @@ Available batteries: ${Array.from(availableBatteries).join(", ")}`);
2048
2098
  import path from "node:path";
2049
2099
  import { access, readFile } from "node:fs/promises";
2050
2100
 
2051
- import { createUnragEngine } from "../unrag.config";
2101
+ import { createUnragEngine } from "${aliasBase}/config";
2052
2102
  import {
2053
2103
  runEval,
2054
2104
  readEvalReportFromFile,
@@ -2060,7 +2110,7 @@ import {
2060
2110
  type EvalMode,
2061
2111
  type EvalThresholds,
2062
2112
  type EvalCleanupPolicy,
2063
- } from "${installImportBase}/eval";
2113
+ } from "${aliasBase}/eval";
2064
2114
 
2065
2115
  type CliArgs = {
2066
2116
  dataset?: string;
@@ -2326,6 +2376,50 @@ main().catch((err) => {
2326
2376
  " bun run unrag:eval",
2327
2377
  " bun run unrag:eval:ci"
2328
2378
  ].filter(Boolean).join(`
2379
+ `));
2380
+ return;
2381
+ }
2382
+ if (battery === "debug") {
2383
+ const configAbs = path7.join(root, ".unrag/debug/config.json");
2384
+ const debugConfig = {
2385
+ port: 3847,
2386
+ host: "localhost"
2387
+ };
2388
+ if (await shouldWriteFile(configAbs, root, nonInteractive)) {
2389
+ await writeTextFile(configAbs, JSON.stringify(debugConfig, null, 2) + `
2390
+ `);
2391
+ }
2392
+ const scriptsToAdd = {
2393
+ "unrag:debug": "bunx unrag debug"
2394
+ };
2395
+ const scriptsResult = await addPackageJsonScripts({
2396
+ projectRoot: root,
2397
+ pkg,
2398
+ scripts: scriptsToAdd,
2399
+ nonInteractive
2400
+ });
2401
+ outro2([
2402
+ `Installed battery: ${battery}.`,
2403
+ "",
2404
+ `- Code: ${path7.join(config.installDir, "debug")}`,
2405
+ `- Config: .unrag/debug/config.json`,
2406
+ "",
2407
+ merged2.changes.length > 0 ? `Added deps: ${merged2.changes.map((c) => c.name).join(", ")}` : "Added deps: none",
2408
+ merged2.changes.length > 0 && !noInstall ? "Dependencies installed." : merged2.changes.length > 0 && noInstall ? "Dependencies not installed (skipped)." : "",
2409
+ scriptsResult.added.length > 0 ? `Added scripts: ${scriptsResult.added.join(", ")}` : "Added scripts: none",
2410
+ scriptsResult.kept.length > 0 ? `Kept existing scripts: ${scriptsResult.kept.join(", ")}` : "",
2411
+ "",
2412
+ "Usage:",
2413
+ " 1. Set UNRAG_DEBUG=true in your app's environment",
2414
+ " 2. Run your app (debug server auto-starts on port 3847)",
2415
+ " 3. In another terminal: bun run unrag:debug",
2416
+ "",
2417
+ "The debug panel will connect to your app and show live events for:",
2418
+ " - Ingest operations (chunking, embedding, storage)",
2419
+ " - Retrieve operations (embedding, database queries)",
2420
+ " - Rerank operations (scoring, reordering)",
2421
+ " - Delete operations"
2422
+ ].filter(Boolean).join(`
2329
2423
  `));
2330
2424
  return;
2331
2425
  }
@@ -2369,6 +2463,7 @@ Available connectors: ${Array.from(availableConnectors).join(", ")}`);
2369
2463
  projectRoot: root,
2370
2464
  registryRoot,
2371
2465
  installDir: config.installDir,
2466
+ aliasBase: config.aliasBase ?? "@unrag",
2372
2467
  connector,
2373
2468
  yes: nonInteractive
2374
2469
  });
@@ -2406,6 +2501,7 @@ Available extractors: ${Array.from(availableExtractors).join(", ")}`);
2406
2501
  projectRoot: root,
2407
2502
  registryRoot,
2408
2503
  installDir: config.installDir,
2504
+ aliasBase: config.aliasBase ?? "@unrag",
2409
2505
  extractor,
2410
2506
  yes: nonInteractive
2411
2507
  });
@@ -5042,6 +5138,103 @@ async function doctorCommand(args) {
5042
5138
  }
5043
5139
  }
5044
5140
 
5141
+ // cli/commands/debug.ts
5142
+ import { outro as outro5 } from "@clack/prompts";
5143
+ import { fileURLToPath as fileURLToPath3 } from "node:url";
5144
+ import { dirname, join } from "node:path";
5145
+ import { existsSync } from "node:fs";
5146
+ function parseDebugArgs(args) {
5147
+ const out = {};
5148
+ for (let i = 0;i < args.length; i++) {
5149
+ const arg = args[i];
5150
+ if (arg === "--url") {
5151
+ out.url = args[++i];
5152
+ } else if (arg === "--port" || arg === "-p") {
5153
+ const portStr = args[++i] ?? "";
5154
+ out.port = parseInt(portStr, 10);
5155
+ if (isNaN(out.port)) {
5156
+ throw new Error(`Invalid port: ${portStr}`);
5157
+ }
5158
+ } else if (arg === "--help" || arg === "-h") {
5159
+ out.help = true;
5160
+ }
5161
+ }
5162
+ return out;
5163
+ }
5164
+ function renderDebugHelp() {
5165
+ return [
5166
+ "unrag debug — Real-time TUI debugger for RAG operations",
5167
+ "",
5168
+ "Usage:",
5169
+ " bunx unrag debug [options]",
5170
+ "",
5171
+ "Options:",
5172
+ " --url <ws://...> WebSocket URL (default: ws://localhost:3847)",
5173
+ " --port, -p <num> Port to connect to (default: 3847)",
5174
+ " -h, --help Show this help",
5175
+ "",
5176
+ "Setup:",
5177
+ " 1. Set UNRAG_DEBUG=true in your app's environment",
5178
+ " 2. Start your app (debug server auto-starts on port 3847)",
5179
+ " 3. Run: bunx unrag debug",
5180
+ "",
5181
+ "Keyboard shortcuts (in TUI):",
5182
+ " Shift+Tab Cycle tabs",
5183
+ " 1-8 Jump to specific tab",
5184
+ " j/k or arrows Navigate event list",
5185
+ " Enter/e View event details",
5186
+ " a/i/r/k/d Filter events by type",
5187
+ " ?/h Show help",
5188
+ " q Quit",
5189
+ "",
5190
+ "Environment variables (in your app):",
5191
+ " UNRAG_DEBUG=true Enable debug mode",
5192
+ " UNRAG_DEBUG_PORT=3847 Debug server port (optional)",
5193
+ ""
5194
+ ].join(`
5195
+ `);
5196
+ }
5197
+ function getTuiModulePath() {
5198
+ const __filename4 = fileURLToPath3(import.meta.url);
5199
+ const __dirname4 = dirname(__filename4);
5200
+ const dev = process.env.UNRAG_DEBUG_TUI_DEV === "1";
5201
+ const devPath = join(__dirname4, "..", "debug-tui", "index.dev.js");
5202
+ const prodPath = join(__dirname4, "..", "debug-tui", "index.js");
5203
+ if (dev) {
5204
+ if (existsSync(devPath))
5205
+ return devPath;
5206
+ throw new Error("UNRAG_DEBUG_TUI_DEV=1 was set but dev TUI bundle was not found. Rebuild unrag with: `bun run build:debug-tui:dev`");
5207
+ }
5208
+ return prodPath;
5209
+ }
5210
+ async function debugCommand(args) {
5211
+ try {
5212
+ const parsed = parseDebugArgs(args);
5213
+ if (parsed.help) {
5214
+ outro5(renderDebugHelp());
5215
+ return;
5216
+ }
5217
+ let url = parsed.url;
5218
+ if (!url && parsed.port) {
5219
+ url = `ws://localhost:${parsed.port}`;
5220
+ }
5221
+ url = url ?? "ws://localhost:3847";
5222
+ console.log(`Connecting to debug server at ${url}...`);
5223
+ console.log(`Press ? for help, q to quit
5224
+ `);
5225
+ const tuiPath = getTuiModulePath();
5226
+ const { runDebugTui } = await import(tuiPath);
5227
+ await runDebugTui({ url });
5228
+ } catch (error) {
5229
+ if (error instanceof Error) {
5230
+ outro5(`Error: ${error.message}`);
5231
+ } else {
5232
+ outro5(`Error: ${String(error)}`);
5233
+ }
5234
+ process.exitCode = 1;
5235
+ }
5236
+ }
5237
+
5045
5238
  // cli/run.ts
5046
5239
  function renderHelp() {
5047
5240
  return [
@@ -5055,9 +5248,10 @@ function renderHelp() {
5055
5248
  " init Install core files (config + store adapter templates)",
5056
5249
  " add <connector> Install a connector (notion, google-drive)",
5057
5250
  " add extractor <n> Install an extractor (pdf-llm, image-ocr, etc.)",
5058
- " add battery <name> Install a battery module (reranker, etc.)",
5251
+ " add battery <name> Install a battery module (reranker, eval, debug)",
5059
5252
  " doctor Validate installation and configuration",
5060
5253
  " doctor setup Generate project-specific doctor config and scripts",
5254
+ " debug Open real-time debug TUI (requires UNRAG_DEBUG=true in app)",
5061
5255
  " help Show this help",
5062
5256
  "",
5063
5257
  "Global options:",
@@ -5113,7 +5307,7 @@ async function run(argv) {
5113
5307
  const [, , command, ...rest] = argv;
5114
5308
  intro("unrag");
5115
5309
  if (!command || command === "help" || command === "--help" || command === "-h") {
5116
- outro5(renderHelp());
5310
+ outro6(renderHelp());
5117
5311
  return;
5118
5312
  }
5119
5313
  if (command === "init") {
@@ -5128,7 +5322,11 @@ async function run(argv) {
5128
5322
  await doctorCommand(rest);
5129
5323
  return;
5130
5324
  }
5131
- outro5([`Unknown command: ${command}`, "", renderHelp()].join(`
5325
+ if (command === "debug") {
5326
+ await debugCommand(rest);
5327
+ return;
5328
+ }
5329
+ outro6([`Unknown command: ${command}`, "", renderHelp()].join(`
5132
5330
  `));
5133
5331
  process.exitCode = 1;
5134
5332
  }