@autorag/librarian 2.4.1 → 2.4.2

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/cli/index.js CHANGED
@@ -206,7 +206,7 @@ function renderMemory(schema, opts) {
206
206
  function renderFeedback(result, opts) {
207
207
  const envelope = { ok: true, applied: result.applied, sessionId: result.sessionId };
208
208
  if (opts.json) {
209
- return JSON.stringify(envelope, null, 2);
209
+ return JSON.stringify(envelope);
210
210
  }
211
211
  const lines = [];
212
212
  lines.push(`feedback: ${result.applied ? "applied" : "not applied"}`);
@@ -877,7 +877,10 @@ function parsedOutputPath(root, virtualPath) {
877
877
  const digest = createHash("sha256").update(virtualPath).digest("hex");
878
878
  return join3(parsedMirrorRoot(root), PARSED_FILES_SUBDIR, `${digest}.md`);
879
879
  }
880
- var PARSED_MIRROR_SUBDIR, PARSED_FILES_SUBDIR = "files", PARSED_INDEX_FILE = "index.json";
880
+ function refreshReadinessPath(root) {
881
+ return join3(root, ".autorag", REFRESH_READINESS_FILE);
882
+ }
883
+ var PARSED_MIRROR_SUBDIR, PARSED_FILES_SUBDIR = "files", PARSED_INDEX_FILE = "index.json", REFRESH_READINESS_FILE = "refresh-complete.json";
881
884
  var init_paths = __esm(() => {
882
885
  PARSED_MIRROR_SUBDIR = join3(".autorag", "parsed");
883
886
  });
@@ -6356,6 +6359,11 @@ function globalArgs(options) {
6356
6359
  return options.configPath !== undefined ? ["--config", options.configPath] : [];
6357
6360
  }
6358
6361
  function parseCount(stdout) {
6362
+ const trimmed = stdout.trim();
6363
+ if (!trimmed.startsWith("{") && !trimmed.startsWith("[")) {
6364
+ const textMatch = /\bpages=(\d+)/.exec(trimmed);
6365
+ return textMatch ? Number(textMatch[1]) : 0;
6366
+ }
6359
6367
  const parsed = parseJson3(stdout);
6360
6368
  if (parsed === undefined)
6361
6369
  return;
@@ -6371,6 +6379,10 @@ function parseCount(stdout) {
6371
6379
  return 0;
6372
6380
  }
6373
6381
  function parseHits(stdout) {
6382
+ const trimmed = stdout.trim();
6383
+ if (trimmed.length > 0 && !trimmed.startsWith("{") && !trimmed.startsWith("[")) {
6384
+ return parseTabSeparatedHits(trimmed);
6385
+ }
6374
6386
  const parsed = parseJson3(stdout);
6375
6387
  const rows = Array.isArray(parsed) ? parsed : isRecord3(parsed) && Array.isArray(parsed.results) ? parsed.results : undefined;
6376
6388
  if (rows === undefined)
@@ -6404,6 +6416,33 @@ function parseHits(stdout) {
6404
6416
  }
6405
6417
  return hits;
6406
6418
  }
6419
+ function parseTabSeparatedHits(stdout) {
6420
+ const hits = [];
6421
+ for (const [index, line] of stdout.split(`
6422
+ `).entries()) {
6423
+ if (line.trim().length === 0)
6424
+ continue;
6425
+ const [kind, id, title, ...textParts] = line.split("\t");
6426
+ if (kind === undefined || id === undefined || id.length === 0)
6427
+ return;
6428
+ const content = textParts.join("\t");
6429
+ const cleanTitle = (title ?? "").replace(/\\t/g, "\t").replace(/\\n/g, `
6430
+ `);
6431
+ hits.push({
6432
+ id,
6433
+ content: content.replace(/\\t/g, "\t").replace(/\\n/g, `
6434
+ `),
6435
+ score: 1 / (index + 1),
6436
+ ...cleanTitle.length > 0 ? { title: cleanTitle } : {},
6437
+ hierarchy: [kind, ...cleanTitle.length > 0 ? [cleanTitle] : [], id],
6438
+ metadata: {
6439
+ kind,
6440
+ ...cleanTitle.length > 0 ? { title: cleanTitle } : {}
6441
+ }
6442
+ });
6443
+ }
6444
+ return hits;
6445
+ }
6407
6446
  function parseJson3(stdout) {
6408
6447
  const trimmed = stdout.trim();
6409
6448
  if (trimmed.length === 0)
@@ -6433,7 +6472,7 @@ var init_notion = __esm(() => {
6433
6472
  binaryName: "notcrawl",
6434
6473
  allowedEnvPrefixes: ["NOTCRAWL_"],
6435
6474
  syncArgs: (options) => [...globalArgs(options), "sync"],
6436
- searchArgs: (options, query, topK) => [...globalArgs(options), "search", query, "--limit", String(topK), "--json"],
6475
+ searchArgs: (options, query, topK) => [...globalArgs(options), "search", query, "--limit", String(topK)],
6437
6476
  parseSyncCount: parseCount,
6438
6477
  parseHits
6439
6478
  };
@@ -9032,6 +9071,12 @@ function resolveBuiltInModel(reference) {
9032
9071
  }
9033
9072
  return;
9034
9073
  }
9074
+ function resolveModel(config) {
9075
+ if (!config.model) {
9076
+ throw new ConfigError('No model configured. Provide --model-provider and --model-id on the command line, or set the "model" key (with provider and id) in the config file.');
9077
+ }
9078
+ return resolveRegisteredModel(config.model);
9079
+ }
9035
9080
  function resolveAgentModelCore(config, localOptions = {}) {
9036
9081
  const modelRef = config.model;
9037
9082
  const registered = resolveBuiltInModel(modelRef);
@@ -9442,18 +9487,21 @@ class DatasourceAccessContext {
9442
9487
  return false;
9443
9488
  return tags.some((tag) => this.allowedTags.includes(tag));
9444
9489
  }
9445
- allowedSourcesPredicate(_userScope) {
9490
+ allowedSourcesPredicate(_userScope, userScopes) {
9446
9491
  if (this.denyAll)
9447
9492
  return () => false;
9448
9493
  const trustedScopes = this.allowedScopes;
9449
9494
  const normalizedUserScope = _userScope === undefined ? undefined : normalizeVirtualPath2(_userScope);
9495
+ const normalizedUserScopes = userScopes?.map(normalizeVirtualPath2);
9450
9496
  return (source) => {
9451
9497
  if (source.includes("#"))
9452
9498
  return false;
9453
9499
  const inTrusted = trustedScopes.length === 0 ? true : trustedScopes.some((scope) => matchesVirtualPathScope(source, scope));
9454
9500
  if (!inTrusted)
9455
9501
  return false;
9456
- return normalizedUserScope === undefined ? true : matchesVirtualPathScope(source, normalizedUserScope);
9502
+ if (normalizedUserScope !== undefined && !matchesVirtualPathScope(source, normalizedUserScope))
9503
+ return false;
9504
+ return normalizedUserScopes === undefined || normalizedUserScopes.length === 0 ? true : normalizedUserScopes.some((scope) => matchesVirtualPathScope(source, scope));
9457
9505
  };
9458
9506
  }
9459
9507
  }
@@ -9490,7 +9538,7 @@ function datasourceCodeToRetrieval(code) {
9490
9538
 
9491
9539
  // src/datasource/result-filter.ts
9492
9540
  class DatasourceResultFilter {
9493
- filter(byMethod, methods, ctx, userScope) {
9541
+ filter(byMethod, methods, ctx, userScope, userScopes) {
9494
9542
  const descriptors = new Map;
9495
9543
  for (const method of methods) {
9496
9544
  descriptors.set(method.describe().name, method);
@@ -9515,7 +9563,7 @@ class DatasourceResultFilter {
9515
9563
  out.set(name, results);
9516
9564
  continue;
9517
9565
  }
9518
- const predicate = ctx.allowedSourcesPredicate(userScope);
9566
+ const predicate = ctx.allowedSourcesPredicate(userScope, userScopes);
9519
9567
  out.set(name, results.filter((r) => predicate(r.source)));
9520
9568
  }
9521
9569
  return out;
@@ -11324,7 +11372,7 @@ class MinSyncClient {
11324
11372
  this.embedder = options.embedder;
11325
11373
  this.maxChunkSize = options.maxChunkSize;
11326
11374
  }
11327
- async sync() {
11375
+ async sync(force = false) {
11328
11376
  if (!existsSync11(this.binaryPath)) {
11329
11377
  return { ok: false, synced: 0, workspacePath: this.workspacePath, reason: "missing-binary" };
11330
11378
  }
@@ -11352,7 +11400,7 @@ class MinSyncClient {
11352
11400
  initArgs.push("--embedder", this.embedder.id);
11353
11401
  }
11354
11402
  const init = await this.spawn(initArgs, spawnOpts);
11355
- if (!init.ok) {
11403
+ if (!init.ok || !existsSync11(minSyncConfigPath(this.workspacePath))) {
11356
11404
  return {
11357
11405
  ok: false,
11358
11406
  synced: 0,
@@ -11388,7 +11436,7 @@ class MinSyncClient {
11388
11436
  const chunkSizeChanged = this.maxChunkSize !== undefined && configuredChunkSize !== this.maxChunkSize;
11389
11437
  if (chunkSizeChanged)
11390
11438
  rmSync2(cursorPath, { force: true });
11391
- const syncArgs = existsSync11(cursorPath) && !chunkSizeChanged ? ["sync", "--format", "json"] : ["sync", "--full", "--format", "json"];
11439
+ const syncArgs = existsSync11(cursorPath) && !chunkSizeChanged && !force ? ["sync", "--format", "json"] : ["sync", "--full", "--format", "json"];
11392
11440
  const result = await this.spawn(syncArgs, spawnOpts);
11393
11441
  if (!result.ok) {
11394
11442
  if (chunkSizeChanged)
@@ -11412,7 +11460,7 @@ class MinSyncClient {
11412
11460
  async query(text, topK, mode = "vector") {
11413
11461
  if (!existsSync11(this.binaryPath))
11414
11462
  return [];
11415
- const result = await this.spawn(["query", "--format", "json", "-k", String(topK), "--mode", mode, text]);
11463
+ const result = await this.spawn(["query", "--format", "json", "--mode", mode, "-k", String(topK), text]);
11416
11464
  if (!result.ok)
11417
11465
  return [];
11418
11466
  return parseQueryHits(result.stdout);
@@ -11490,34 +11538,51 @@ import { copyFileSync, createWriteStream, existsSync as existsSync12, mkdirSync
11490
11538
  import { chmod, mkdtemp as mkdtemp2 } from "node:fs/promises";
11491
11539
  import { get } from "node:https";
11492
11540
  import { tmpdir as tmpdir2 } from "node:os";
11493
- import { basename as basename6, dirname as dirname9, join as join17 } from "node:path";
11541
+ import { basename as basename6, delimiter as delimiter2, dirname as dirname9, join as join17 } from "node:path";
11494
11542
  import { pipeline } from "node:stream/promises";
11495
11543
  async function ensureMinSyncBinary(options) {
11496
11544
  const binaryPath = join17(options.root, ".autorag", "bin", executableName(options.platform ?? process.platform));
11497
11545
  if (existsSync12(binaryPath))
11498
11546
  return { binaryPath, version: "cached" };
11499
- const releaseProvider = options.releaseProvider ?? fetchLatestMinSyncRelease;
11500
- const release = await releaseProvider();
11501
- let asset;
11547
+ mkdirSync9(dirname9(binaryPath), { recursive: true });
11548
+ const cargoInstaller = options.cargoInstaller ?? ((destination) => installMinSyncFromCargoIfAvailable(options, destination));
11502
11549
  try {
11503
- asset = selectReleaseAsset(release, options.platform ?? process.platform, options.arch ?? process.arch);
11550
+ const fromCargo = await cargoInstaller(binaryPath);
11551
+ if (fromCargo !== undefined)
11552
+ return fromCargo;
11504
11553
  } catch (error) {
11505
- if (!(error instanceof MinSyncReleaseError) || !error.message.startsWith("No MinSync"))
11554
+ if (!(error instanceof MinSyncReleaseError))
11506
11555
  throw error;
11507
- return installMinSyncFromCargo(options, binaryPath);
11508
11556
  }
11557
+ const releaseProvider = options.releaseProvider ?? fetchLatestMinSyncRelease;
11558
+ const release = await releaseProvider();
11559
+ const asset = selectReleaseAsset(release, options.platform ?? process.platform, options.arch ?? process.arch);
11509
11560
  requireSha256(asset);
11510
11561
  const assetInstaller = options.assetInstaller ?? installReleaseAsset;
11511
- mkdirSync9(dirname9(binaryPath), { recursive: true });
11512
11562
  await assetInstaller(asset, binaryPath);
11513
11563
  await chmod(binaryPath, 493);
11514
11564
  return { binaryPath, version: release.tagName };
11515
11565
  }
11516
- async function installMinSyncFromCargo(options, destination) {
11566
+ function isIsolatedTestRuntime() {
11567
+ return false;
11568
+ }
11569
+ async function installMinSyncFromCargoIfAvailable(options, destination) {
11570
+ if (isIsolatedTestRuntime() && options.cargoLocator === undefined)
11571
+ return;
11572
+ const env = options.env ?? process.env;
11573
+ const cargoLocator = options.cargoLocator ?? ((lookupEnv) => lookupCargo(lookupEnv, options.platform ?? process.platform));
11574
+ const cargo = cargoLocator(env);
11575
+ if (cargo === undefined)
11576
+ return;
11577
+ if (!await cargoIsUsable(cargo, options.root))
11578
+ return;
11579
+ return installMinSyncFromCargo(options, destination, cargo);
11580
+ }
11581
+ async function installMinSyncFromCargo(options, destination, cargo) {
11517
11582
  const cargoRoot = join17(options.root, ".autorag", "minsync-cargo");
11518
11583
  mkdirSync9(dirname9(destination), { recursive: true });
11519
11584
  mkdirSync9(cargoRoot, { recursive: true });
11520
- const result = await spawnProcess("cargo", ["install", "minsync", "--version", MINSYNC_VERSION, "--locked", "--root", cargoRoot], options.root);
11585
+ const result = await spawnProcess(cargo, ["install", "minsync", "--version", MINSYNC_VERSION, "--locked", "--root", cargoRoot], options.root, { timeoutMs: MINSYNC_CARGO_INSTALL_TIMEOUT_MS });
11521
11586
  if (!result.ok) {
11522
11587
  throw new MinSyncReleaseError(result.stderr || `Could not install MinSync ${MINSYNC_VERSION} from crates.io`);
11523
11588
  }
@@ -11642,6 +11707,27 @@ function targetTriple(platform, arch) {
11642
11707
  function executableName(platform) {
11643
11708
  return platform === "win32" ? "minsync.exe" : "minsync";
11644
11709
  }
11710
+ function cargoExecutableName2(platform) {
11711
+ return platform === "win32" ? "cargo.exe" : "cargo";
11712
+ }
11713
+ function lookupCargo(env, platform) {
11714
+ const pathEnv = env.PATH;
11715
+ if (typeof pathEnv !== "string" || pathEnv.length === 0)
11716
+ return;
11717
+ const execName = cargoExecutableName2(platform);
11718
+ for (const dir of pathEnv.split(delimiter2)) {
11719
+ if (dir.length === 0)
11720
+ continue;
11721
+ const candidate = join17(dir, execName);
11722
+ if (existsSync12(candidate))
11723
+ return candidate;
11724
+ }
11725
+ return;
11726
+ }
11727
+ async function cargoIsUsable(cargo, cwd) {
11728
+ const result = await spawnProcess(cargo, ["--version"], cwd, { timeoutMs: CARGO_PROBE_TIMEOUT_MS });
11729
+ return result.ok && result.stdout.toLowerCase().includes("cargo");
11730
+ }
11645
11731
  function parseDigest(value) {
11646
11732
  if (typeof value !== "string")
11647
11733
  return;
@@ -11664,10 +11750,11 @@ function isGitHubAsset(value) {
11664
11750
  function isRecord11(value) {
11665
11751
  return typeof value === "object" && value !== null;
11666
11752
  }
11667
- var LATEST_RELEASE_URL = "https://api.github.com/repos/NomaDamas/MinSync/releases/latest", SHA256_HEX_PATTERN, MINSYNC_VERSION = "0.3.0", MinSyncReleaseError;
11753
+ var LATEST_RELEASE_URL = "https://api.github.com/repos/NomaDamas/MinSync/releases/latest", SHA256_HEX_PATTERN, MINSYNC_VERSION = "0.4.2", MINSYNC_CARGO_INSTALL_TIMEOUT_MS, CARGO_PROBE_TIMEOUT_MS = 5000, MinSyncReleaseError;
11668
11754
  var init_installer2 = __esm(() => {
11669
11755
  init_process();
11670
11756
  SHA256_HEX_PATTERN = /^[a-f0-9]{64}$/;
11757
+ MINSYNC_CARGO_INSTALL_TIMEOUT_MS = 10 * 60 * 1000;
11671
11758
  MinSyncReleaseError = class MinSyncReleaseError extends Error {
11672
11759
  name = "MinSyncReleaseError";
11673
11760
  };
@@ -11843,7 +11930,7 @@ var init_workspace = __esm(() => {
11843
11930
 
11844
11931
  // src/minsync/method.ts
11845
11932
  import { accessSync, constants, existsSync as existsSync14, realpathSync as realpathSync3 } from "node:fs";
11846
- import { basename as basename8, delimiter as delimiter2, join as join20, normalize as normalize2 } from "node:path";
11933
+ import { basename as basename8, delimiter as delimiter3, join as join20, normalize as normalize2 } from "node:path";
11847
11934
  function degrade(workspacePath, reason) {
11848
11935
  return { ok: false, synced: 0, workspacePath, reason };
11849
11936
  }
@@ -11852,7 +11939,7 @@ function lookupInPath(env) {
11852
11939
  if (typeof pathEnv !== "string" || pathEnv.length === 0)
11853
11940
  return;
11854
11941
  const execName = executableName(process.platform);
11855
- for (const dir of pathEnv.split(delimiter2)) {
11942
+ for (const dir of pathEnv.split(delimiter3)) {
11856
11943
  if (dir.length === 0)
11857
11944
  continue;
11858
11945
  const candidate = join20(dir, execName);
@@ -11873,6 +11960,7 @@ class MinSyncVectorMethod {
11873
11960
  embedder;
11874
11961
  maxChunkSize;
11875
11962
  mode;
11963
+ installFailed = false;
11876
11964
  constructor(options) {
11877
11965
  this.root = options.root;
11878
11966
  this.binaryPath = options.binaryPath;
@@ -11897,7 +11985,7 @@ class MinSyncVectorMethod {
11897
11985
  ]
11898
11986
  };
11899
11987
  }
11900
- async sync() {
11988
+ async sync(force = false) {
11901
11989
  syncMinSyncWorkspace(this.root, { workspacePath: this.workspacePath });
11902
11990
  const binaryResult = await this.resolveBinary();
11903
11991
  if (binaryResult === undefined) {
@@ -11910,11 +11998,21 @@ class MinSyncVectorMethod {
11910
11998
  embedder: this.embedder,
11911
11999
  maxChunkSize: this.maxChunkSize
11912
12000
  });
11913
- return client.sync();
12001
+ return client.sync(force);
11914
12002
  }
11915
12003
  return binaryResult;
11916
12004
  }
11917
12005
  isBinaryMissing() {
12006
+ if (this.binaryPath !== undefined)
12007
+ return !existsSync14(this.binaryPath);
12008
+ if (lookupInPath(process.env) !== undefined)
12009
+ return false;
12010
+ const cachedBinary = join20(this.root, ".autorag", "bin", executableName(process.platform));
12011
+ if (existsSync14(cachedBinary))
12012
+ return false;
12013
+ return this.installFailed || !this.autoInstall;
12014
+ }
12015
+ isExplicitBinaryMissing() {
11918
12016
  return this.binaryPath !== undefined && !existsSync14(this.binaryPath);
11919
12017
  }
11920
12018
  isReady() {
@@ -11973,6 +12071,7 @@ class MinSyncVectorMethod {
11973
12071
  const installed = await ensureMinSyncBinary({ ...this.installer, root: this.root });
11974
12072
  return installed.binaryPath;
11975
12073
  } catch {
12074
+ this.installFailed = true;
11976
12075
  return degrade(this.workspacePath, "install-failed");
11977
12076
  }
11978
12077
  }
@@ -12444,6 +12543,106 @@ class RetrievalMethodRegistry {
12444
12543
  }
12445
12544
  }
12446
12545
 
12546
+ // src/retrieval/engine.ts
12547
+ class RetrievalEngine {
12548
+ registry;
12549
+ retriever;
12550
+ filter;
12551
+ merger;
12552
+ accessContext;
12553
+ defaultTopK;
12554
+ defaultDedup;
12555
+ isMinSyncBinaryMissing;
12556
+ constructor(options = {}) {
12557
+ this.registry = new RetrievalMethodRegistry;
12558
+ this.retriever = new ParallelRetriever;
12559
+ this.filter = new DatasourceResultFilter;
12560
+ this.merger = new ResultMerger;
12561
+ this.accessContext = new DatasourceAccessContext(options.datasourceAccess);
12562
+ this.defaultTopK = options.defaultTopK ?? 20;
12563
+ this.defaultDedup = options.defaultDedup ?? true;
12564
+ this.isMinSyncBinaryMissing = options.isMinSyncBinaryMissing;
12565
+ }
12566
+ getMethodRegistry() {
12567
+ return this.registry;
12568
+ }
12569
+ getAccessContext() {
12570
+ return this.accessContext;
12571
+ }
12572
+ register(method) {
12573
+ this.registry.register(method);
12574
+ }
12575
+ registerMany(methods) {
12576
+ const names = new Set;
12577
+ for (const method of methods) {
12578
+ const name = method.describe().name;
12579
+ if (this.registry.get(name) !== undefined || names.has(name)) {
12580
+ throw new Error(`Retrieval method "${name}" is already registered`);
12581
+ }
12582
+ names.add(name);
12583
+ }
12584
+ for (const method of methods) {
12585
+ this.registry.register(method);
12586
+ }
12587
+ }
12588
+ async retrieve(query, options = {}) {
12589
+ const topK = options.topK ?? this.defaultTopK;
12590
+ const methods = this.registry.list();
12591
+ const { results: byMethod, diagnostics } = await this.retriever.retrieveWithDiagnostics(methods, query, options);
12592
+ const ctx = this.accessContextFor(options);
12593
+ const filtered = this.filter.filter(byMethod, methods, ctx, options.scope, options.allowedScopes);
12594
+ const allDiagnostics = this.appendMinSyncUnavailableDiagnostic(methods, filtered, diagnostics);
12595
+ return {
12596
+ results: this.merger.merge(filtered, { topK, dedup: this.defaultDedup }),
12597
+ diagnostics: allDiagnostics
12598
+ };
12599
+ }
12600
+ async retrieveByMethod(query, options = {}) {
12601
+ const methods = this.registry.list();
12602
+ const { results: byMethod, diagnostics } = await this.retriever.retrieveWithDiagnostics(methods, query, options);
12603
+ const ctx = this.accessContextFor(options);
12604
+ const filtered = this.filter.filter(byMethod, methods, ctx, options.scope, options.allowedScopes);
12605
+ const allDiagnostics = this.appendMinSyncUnavailableDiagnostic(methods, filtered, diagnostics);
12606
+ return { byMethod: filtered, diagnostics: allDiagnostics };
12607
+ }
12608
+ appendMinSyncUnavailableDiagnostic(methods, filtered, diagnostics) {
12609
+ if (this.isMinSyncBinaryMissing === undefined)
12610
+ return diagnostics;
12611
+ if (!this.isMinSyncBinaryMissing())
12612
+ return diagnostics;
12613
+ if (diagnostics.some((d) => d.code === "minsync-unavailable"))
12614
+ return diagnostics;
12615
+ const hasEmptyMinsync = methods.some((m) => {
12616
+ const name = m.describe().name;
12617
+ if (name !== "minsync")
12618
+ return false;
12619
+ const results = filtered.get(name);
12620
+ return results === undefined || results.length === 0;
12621
+ });
12622
+ if (!hasEmptyMinsync)
12623
+ return diagnostics;
12624
+ return [
12625
+ ...diagnostics,
12626
+ {
12627
+ code: "minsync-unavailable",
12628
+ severity: "warning",
12629
+ message: "MinSync semantic search is unavailable; results rely on other retrieval paths.",
12630
+ source: "minsync"
12631
+ }
12632
+ ];
12633
+ }
12634
+ accessContextFor(options) {
12635
+ const baseTags = this.accessContext.allowedTags;
12636
+ const baseScopes = this.accessContext.allowedScopes;
12637
+ const userTags = options.allowedTags;
12638
+ const allowedTags = baseTags.length === 0 ? [] : userTags !== undefined ? baseTags.filter((t) => userTags.includes(t)) : baseTags;
12639
+ return new DatasourceAccessContext({ allowedTags, allowedScopes: baseScopes });
12640
+ }
12641
+ }
12642
+ var init_engine = __esm(() => {
12643
+ init_access_context();
12644
+ });
12645
+
12447
12646
  // src/filesystem/cloud-placeholder.ts
12448
12647
  import { execFile } from "node:child_process";
12449
12648
  import { lstat } from "node:fs/promises";
@@ -13001,7 +13200,7 @@ var init_emit_results_tool = __esm(() => {
13001
13200
  excerpt: Type5.String({ description: "Supporting excerpt" }),
13002
13201
  lineNumber: Type5.Optional(Type5.Integer({ description: "Line number of the excerpt, if known" }))
13003
13202
  })),
13004
- confidence: Type5.Number({ description: "Confidence in this result, 0..1" })
13203
+ confidence: Type5.Number({ description: "Confidence in this result, 0..1", minimum: 0, maximum: 1 })
13005
13204
  }), { description: "Numbered curated knowledge units." }),
13006
13205
  mapping: Type5.Array(Type5.Object({
13007
13206
  number: Type5.Integer({ description: "Matches the result number this entry maps" }),
@@ -13655,7 +13854,7 @@ var init_watch_refresh = __esm(() => {
13655
13854
 
13656
13855
  // src/agent/agent.ts
13657
13856
  import { randomUUID as randomUUID7 } from "node:crypto";
13658
- import { watch as fsWatch, realpathSync as realpathSync4, statSync } from "node:fs";
13857
+ import { watch as fsWatch, mkdirSync as mkdirSync13, realpathSync as realpathSync4, statSync, writeFileSync as writeFileSync11 } from "node:fs";
13659
13858
  import { dirname as dirname14, join as join21, resolve as resolve11 } from "node:path";
13660
13859
  import { Agent } from "@earendil-works/pi-agent-core";
13661
13860
  import { streamSimple } from "@earendil-works/pi-ai/compat";
@@ -14205,9 +14404,12 @@ ${initialRetrievalContext}`);
14205
14404
  }
14206
14405
  }
14207
14406
  datasourceAccessContext(options = {}) {
14407
+ const trustedTags = this.datasourceAccessOptions.allowedTags ?? [];
14408
+ const requestedTags = options.allowedTags;
14409
+ const allowedTags = requestedTags === undefined ? trustedTags : trustedTags.filter((tag) => requestedTags.includes(tag));
14208
14410
  return new DatasourceAccessContext({
14209
- allowedTags: options.allowedTags ?? this.datasourceAccessOptions.allowedTags,
14210
- allowedScopes: options.allowedScopes ?? this.datasourceAccessOptions.allowedScopes
14411
+ allowedTags,
14412
+ allowedScopes: this.datasourceAccessOptions.allowedScopes
14211
14413
  });
14212
14414
  }
14213
14415
  buildAuthorizedDatasourceSkills() {
@@ -14361,7 +14563,7 @@ ${initialRetrievalContext ?? "Pending; continue only with a brief progress state
14361
14563
  };
14362
14564
  try {
14363
14565
  const summary = needsParsed ? await this.syncParsedMirrors(force) : await this.scanMirrorStaleness();
14364
- const minsync = wants("minsync") ? await this.syncMinSync() : undefined;
14566
+ const minsync = wants("minsync") ? await this.syncMinSync(force) : undefined;
14365
14567
  const datasources = wants("datasources") ? await this.indexDatasources() : [];
14366
14568
  const jikji = allMethods || wants("jikji") || wants("minsync") ? await this.executeJikjiPrepare() : undefined;
14367
14569
  this.retrievalScopeBindings = buildRetrievalScopeBindings(this.workspaceProjectRoot, this.searchPaths, this.configuredSearchPaths);
@@ -14381,6 +14583,11 @@ ${initialRetrievalContext ?? "Pending; continue only with a brief progress state
14381
14583
  datasources,
14382
14584
  lastError: undefined
14383
14585
  };
14586
+ if (needsParsed) {
14587
+ mkdirSync13(dirname14(refreshReadinessPath(this.workspaceProjectRoot)), { recursive: true });
14588
+ writeFileSync11(refreshReadinessPath(this.workspaceProjectRoot), `{"version":1,"completed":true,"parsed":true}
14589
+ `);
14590
+ }
14384
14591
  const publicMinsync = minsync ? {
14385
14592
  ok: minsync.ok,
14386
14593
  synced: minsync.synced,
@@ -14459,7 +14666,7 @@ ${initialRetrievalContext ?? "Pending; continue only with a brief progress state
14459
14666
  refreshComponentStatus() {
14460
14667
  const status = {};
14461
14668
  if (this.minSyncMethod !== undefined) {
14462
- status.minsync = this.minSyncMethod.isBinaryMissing() ? "unavailable" : this.refreshState.minsync?.ok === false ? "degraded" : this.minSyncMethod.isReady() ? "ready" : "configured";
14669
+ status.minsync = this.minSyncMethod.isExplicitBinaryMissing() ? "unavailable" : this.refreshState.minsync?.ok === false ? "degraded" : this.minSyncMethod.isReady() ? "ready" : "configured";
14463
14670
  }
14464
14671
  if (this.jikjiClient !== undefined) {
14465
14672
  status.jikji = this.refreshState.jikjiDiagnostics.length > 0 ? "degraded" : "configured";
@@ -14546,8 +14753,8 @@ ${initialRetrievalContext ?? "Pending; continue only with a brief progress state
14546
14753
  }
14547
14754
  return { excluded };
14548
14755
  }
14549
- async syncMinSync() {
14550
- const result = await this.minSyncMethod?.sync();
14756
+ async syncMinSync(force = false) {
14757
+ const result = await this.minSyncMethod?.sync(force);
14551
14758
  this.minSyncReady = result?.ok === true;
14552
14759
  this.refreshState = { ...this.refreshState, minsync: result };
14553
14760
  return result;
@@ -14748,7 +14955,7 @@ ${initialRetrievalContext ?? "Pending; continue only with a brief progress state
14748
14955
  options = this.normalizeRetrievalOptions(options);
14749
14956
  const methods = this.methodRegistry.list();
14750
14957
  const { results: byMethod, diagnostics } = await this.retriever.retrieveWithDiagnostics(methods, query, options);
14751
- const filteredByMethod = this.datasourceFilter.filter(byMethod, methods, this.datasourceAccessContext(options), options.scope);
14958
+ const filteredByMethod = this.datasourceFilter.filter(byMethod, methods, this.datasourceAccessContext(options), options.scope, options.allowedScopes);
14752
14959
  if (this.minSyncMethod?.isBinaryMissing() && !diagnostics.some((d) => d.source === "minsync")) {
14753
14960
  diagnostics.push({
14754
14961
  code: "minsync-unavailable",
@@ -14784,6 +14991,19 @@ ${initialRetrievalContext ?? "Pending; continue only with a brief progress state
14784
14991
  getMethodRegistry() {
14785
14992
  return this.methodRegistry;
14786
14993
  }
14994
+ retrievalEngine;
14995
+ getRetrievalEngine() {
14996
+ if (this.retrievalEngine === undefined) {
14997
+ this.retrievalEngine = new RetrievalEngine({
14998
+ datasourceAccess: this.datasourceAccessOptions,
14999
+ isMinSyncBinaryMissing: this.minSyncMethod !== undefined ? () => this.minSyncMethod.isBinaryMissing() : undefined
15000
+ });
15001
+ for (const method of this.methodRegistry.list()) {
15002
+ this.retrievalEngine.register(method);
15003
+ }
15004
+ }
15005
+ return this.retrievalEngine;
15006
+ }
14787
15007
  getSystemPrompt() {
14788
15008
  return this.innerAgent.state.systemPrompt;
14789
15009
  }
@@ -14887,6 +15107,7 @@ var init_agent = __esm(() => {
14887
15107
  init_paths();
14888
15108
  init_sync();
14889
15109
  init_run_log();
15110
+ init_engine();
14890
15111
  init_scope();
14891
15112
  init_bash_tool();
14892
15113
  init_datasource_skill();
@@ -14920,7 +15141,7 @@ async function runRefresh(ctx) {
14920
15141
  return 0;
14921
15142
  } catch (error) {
14922
15143
  ctx.stderr(renderError(error, { json: ctx.json, debug: ctx.debug }));
14923
- return 1;
15144
+ return error instanceof ConfigError ? 2 : 1;
14924
15145
  }
14925
15146
  }
14926
15147
  function parseMethodFlag(flag) {
@@ -14964,7 +15185,7 @@ async function runStatus(ctx) {
14964
15185
  return 0;
14965
15186
  } catch (error) {
14966
15187
  ctx.stderr(renderError(error, { json: ctx.json, debug: ctx.debug }));
14967
- return 1;
15188
+ return error instanceof ConfigError ? 2 : 1;
14968
15189
  }
14969
15190
  }
14970
15191
  var init_status = __esm(() => {
@@ -15318,6 +15539,9 @@ async function runIndex(ctx) {
15318
15539
  for (const target of targets) {
15319
15540
  rmSync6(target, { recursive: true, force: true });
15320
15541
  }
15542
+ if (sub === "reset" || targetSubdirs.includes(PARSED_MIRROR_SUBDIR)) {
15543
+ rmSync6(refreshReadinessPath(config.workspacePath), { force: true });
15544
+ }
15321
15545
  if (sub === "reset") {
15322
15546
  ctx.stdout(renderIndex({ action: "reset", removed: [...targetNames] }, { json: ctx.json }));
15323
15547
  return 0;
@@ -15436,7 +15660,7 @@ async function runWatch(ctx) {
15436
15660
  return 0;
15437
15661
  } catch (error) {
15438
15662
  ctx.stderr(renderError(error, { json: ctx.json, debug: ctx.debug }));
15439
- return 1;
15663
+ return error instanceof ConfigError ? 2 : 1;
15440
15664
  }
15441
15665
  }
15442
15666
  var init_watch = __esm(() => {
@@ -15682,7 +15906,7 @@ async function runDuplicates(ctx, scanner = (path) => scanWithDupey(path)) {
15682
15906
  return 0;
15683
15907
  } catch (error) {
15684
15908
  ctx.stderr(renderError(error, { json: ctx.json, debug: ctx.debug }));
15685
- return 1;
15909
+ return error instanceof ConfigError ? 2 : 1;
15686
15910
  }
15687
15911
  }
15688
15912
  function exactGroupsFromScan(scan) {
@@ -15740,7 +15964,7 @@ function renderSlashHelp() {
15740
15964
  }
15741
15965
 
15742
15966
  // src/cli/tui-session-store.ts
15743
- import { existsSync as existsSync17, mkdirSync as mkdirSync13, readFileSync as readFileSync14, renameSync as renameSync8, writeFileSync as writeFileSync11 } from "node:fs";
15967
+ import { existsSync as existsSync17, mkdirSync as mkdirSync14, readFileSync as readFileSync14, renameSync as renameSync8, writeFileSync as writeFileSync12 } from "node:fs";
15744
15968
  import { dirname as dirname15 } from "node:path";
15745
15969
  function createFileTuiSessionStore(path) {
15746
15970
  const readSessions = () => {
@@ -15762,9 +15986,9 @@ function createFileTuiSessionStore(path) {
15762
15986
  const sessions = readSessions().filter((item) => item.id !== session.id);
15763
15987
  sessions.unshift(session);
15764
15988
  const dir = dirname15(path);
15765
- mkdirSync13(dir, { recursive: true });
15989
+ mkdirSync14(dir, { recursive: true });
15766
15990
  const tmpPath = `${path}.${process.pid}.tmp`;
15767
- writeFileSync11(tmpPath, `${JSON.stringify(sessions.slice(0, MAX_SESSIONS), null, 2)}
15991
+ writeFileSync12(tmpPath, `${JSON.stringify(sessions.slice(0, MAX_SESSIONS), null, 2)}
15768
15992
  `, "utf8");
15769
15993
  renameSync8(tmpPath, path);
15770
15994
  }
@@ -16770,7 +16994,7 @@ var init_catalog = __esm(() => {
16770
16994
 
16771
16995
  // src/ui/probe.ts
16772
16996
  import { existsSync as existsSync19 } from "node:fs";
16773
- import { delimiter as delimiter3, join as join25 } from "node:path";
16997
+ import { delimiter as delimiter4, join as join25 } from "node:path";
16774
16998
  function probeConnection(input, deps = {}) {
16775
16999
  const catalog = getDatasourceType(input.type);
16776
17000
  if (catalog === undefined) {
@@ -16898,7 +17122,7 @@ function defaultBinaryExists(binaryName, binaryPath) {
16898
17122
  return existsSync19(binaryPath);
16899
17123
  const pathEnv = process.env.PATH ?? "";
16900
17124
  const extensions = process.platform === "win32" ? [".exe", ".cmd", ".bat", ""] : [""];
16901
- for (const dir of pathEnv.split(delimiter3)) {
17125
+ for (const dir of pathEnv.split(delimiter4)) {
16902
17126
  if (dir.length === 0)
16903
17127
  continue;
16904
17128
  for (const extension of extensions) {
@@ -17982,6 +18206,484 @@ var init_ui = __esm(() => {
17982
18206
  init_config2();
17983
18207
  });
17984
18208
 
18209
+ // src/core.ts
18210
+ import { randomUUID as randomUUID8 } from "node:crypto";
18211
+
18212
+ class AutoRAGLite {
18213
+ config;
18214
+ agent;
18215
+ retrievalEngine;
18216
+ memory;
18217
+ sessions = new Map;
18218
+ constructor(config) {
18219
+ this.config = config;
18220
+ const agentOptions = buildAgentOptions(config);
18221
+ this.agent = new AutoRAGAgent(agentOptions);
18222
+ this.retrievalEngine = this.agent.getRetrievalEngine();
18223
+ this.memory = new RetrievalMemory({ storagePath: config.memoryPath });
18224
+ this.memory.load();
18225
+ }
18226
+ refresh(force = false, options) {
18227
+ return this.agent.refresh(force, options);
18228
+ }
18229
+ index(force = false, options) {
18230
+ return this.refresh(force, options);
18231
+ }
18232
+ getRefreshStatus() {
18233
+ return this.agent.getRefreshStatus();
18234
+ }
18235
+ status() {
18236
+ return this.getRefreshStatus();
18237
+ }
18238
+ syncParsedMirrors(force = false) {
18239
+ return this.agent.syncParsedMirrors(force);
18240
+ }
18241
+ syncMinSync() {
18242
+ return this.agent.syncMinSync();
18243
+ }
18244
+ prepareJikji() {
18245
+ return this.agent.prepareJikji();
18246
+ }
18247
+ startWatchRefresh(options) {
18248
+ return this.agent.startWatchRefresh(options);
18249
+ }
18250
+ getRetrievalEngine() {
18251
+ return this.retrievalEngine;
18252
+ }
18253
+ retrieve(query, options) {
18254
+ return this.retrievalEngine.retrieve(query, options);
18255
+ }
18256
+ retrieveByMethod(query, options) {
18257
+ return this.retrievalEngine.retrieveByMethod(query, options);
18258
+ }
18259
+ recordStructuredResultsSession(sessionId, query, details) {
18260
+ return recordStructuredResultsSession(sessionId, query, details, this.sessions, this.memory);
18261
+ }
18262
+ recordReport(query, details) {
18263
+ return this.recordStructuredResultsSession(randomUUID8(), query, details);
18264
+ }
18265
+ getResultRegistry(sessionId) {
18266
+ return this.sessions.get(sessionId)?.registry ?? new Map;
18267
+ }
18268
+ recordFeedbackByNumbers(sessionId, usefulNumbers, notUsefulNumbers = []) {
18269
+ recordNumberedFeedback(this.sessions, this.memory, sessionId, usefulNumbers, notUsefulNumbers);
18270
+ }
18271
+ getMemorySchema() {
18272
+ return structuredClone(this.memory.getSchema());
18273
+ }
18274
+ }
18275
+ function createAutoRAGLite(options = {}) {
18276
+ const input = { flags: options.flags ?? {} };
18277
+ if (options.env !== undefined)
18278
+ input.env = options.env;
18279
+ if (options.cwd !== undefined)
18280
+ input.cwd = options.cwd;
18281
+ if (options.readOnly !== undefined)
18282
+ input.readOnly = options.readOnly;
18283
+ return new AutoRAGLite(resolveConfig(input));
18284
+ }
18285
+ var init_core = __esm(() => {
18286
+ init_agent();
18287
+ init_search_documents();
18288
+ init_config2();
18289
+ init_memory();
18290
+ init_config2();
18291
+ });
18292
+
18293
+ // src/cli/commands/lite-refresh.ts
18294
+ async function runLiteRefresh(ctx) {
18295
+ try {
18296
+ const lite = createAutoRAGLite({ flags: ctx.flags, cwd: ctx.cwd });
18297
+ const methods = parseMethodFlag(ctx.flags.method);
18298
+ const force = ctx.flags.force === true || ctx.flags.full === true;
18299
+ const result = await lite.refresh(force, methods ? { methods } : undefined);
18300
+ await Promise.resolve();
18301
+ ctx.stdout(renderRefresh(result, { json: ctx.json, debug: ctx.debug }));
18302
+ return 0;
18303
+ } catch (error) {
18304
+ ctx.stderr(renderError(error, { json: ctx.json, debug: ctx.debug }));
18305
+ return error instanceof ConfigError ? 2 : 1;
18306
+ }
18307
+ }
18308
+ var init_lite_refresh = __esm(() => {
18309
+ init_core();
18310
+ init_config2();
18311
+ init_refresh();
18312
+ });
18313
+
18314
+ // src/mirror/index.ts
18315
+ var init_mirror = __esm(() => {
18316
+ init_index_store();
18317
+ init_paths();
18318
+ init_sync();
18319
+ });
18320
+
18321
+ // src/cli/commands/lite-retrieve.ts
18322
+ import { existsSync as existsSync21, readFileSync as readFileSync15 } from "node:fs";
18323
+ function parseIntOptional2(value) {
18324
+ if (typeof value !== "string" || value.trim() === "")
18325
+ return;
18326
+ const parsed = Number(value);
18327
+ if (!Number.isFinite(parsed))
18328
+ return;
18329
+ return Math.trunc(parsed);
18330
+ }
18331
+ function parseCsvStrings2(value) {
18332
+ if (typeof value !== "string" || value.trim() === "")
18333
+ return;
18334
+ const parts = value.split(",").map((part) => part.trim()).filter((part) => part !== "");
18335
+ return parts.length > 0 ? parts : undefined;
18336
+ }
18337
+ function buildRetrieveOptions(flags) {
18338
+ const options = {};
18339
+ const topK = parseIntOptional2(flags["top-k"]);
18340
+ if (topK !== undefined)
18341
+ options.topK = topK;
18342
+ if (typeof flags.scope === "string" && flags.scope.trim() !== "")
18343
+ options.scope = flags.scope;
18344
+ const tags = parseCsvStrings2(flags.tags);
18345
+ if (tags !== undefined)
18346
+ options.allowedTags = tags;
18347
+ return options;
18348
+ }
18349
+ function parseTopK(value) {
18350
+ if (value === undefined || value === true || value === false)
18351
+ return { kind: "ok", value: undefined };
18352
+ const parsed = Number(value);
18353
+ if (!Number.isFinite(parsed) || !Number.isInteger(parsed)) {
18354
+ return { kind: "reject", error: `Invalid --top-k value: "${String(value)}". Must be a positive integer.` };
18355
+ }
18356
+ if (parsed < 1) {
18357
+ return { kind: "reject", error: `Invalid --top-k value: ${parsed}. Must be a positive integer.` };
18358
+ }
18359
+ return { kind: "ok", value: parsed };
18360
+ }
18361
+ function diagnosticProjection2(d) {
18362
+ const out = {
18363
+ code: d.code,
18364
+ severity: d.severity,
18365
+ message: d.message
18366
+ };
18367
+ if (d.source !== undefined) {
18368
+ out.source = d.source;
18369
+ }
18370
+ return out;
18371
+ }
18372
+ function renderLiteRetrieveJson(envelope) {
18373
+ return JSON.stringify(envelope, null, 2);
18374
+ }
18375
+ function renderLiteRetrieveHuman(envelope, debug) {
18376
+ const lines = [];
18377
+ if (!envelope.ok) {
18378
+ lines.push(`error: index not ready`);
18379
+ for (const d of envelope.diagnostics) {
18380
+ lines.push(` diagnostic: [${d.severity}] ${d.code}: ${d.message}`);
18381
+ }
18382
+ return lines.join(`
18383
+ `);
18384
+ }
18385
+ const okEnvelope = envelope;
18386
+ if (okEnvelope.results.length === 0) {
18387
+ lines.push("retrieve: no results");
18388
+ } else {
18389
+ lines.push("results:");
18390
+ for (const r of okEnvelope.results) {
18391
+ lines.push(` ${r.number}. source: ${r.source} | method: ${r.method} | score: ${r.score}`);
18392
+ if (r.content.length > 0) {
18393
+ lines.push(` ${r.content.slice(0, 200)}`);
18394
+ }
18395
+ if (debug) {
18396
+ lines.push(` metadata: ${JSON.stringify(r.metadata)}`);
18397
+ }
18398
+ }
18399
+ }
18400
+ if (debug && okEnvelope.diagnostics.length > 0) {
18401
+ for (const d of okEnvelope.diagnostics) {
18402
+ lines.push(` diagnostic: [${d.severity}] ${d.code}: ${d.message}`);
18403
+ }
18404
+ }
18405
+ return lines.join(`
18406
+ `);
18407
+ }
18408
+ function hasCompletedParsedRefresh(workspacePath) {
18409
+ const markerPath = refreshReadinessPath(workspacePath);
18410
+ if (!existsSync21(markerPath))
18411
+ return false;
18412
+ try {
18413
+ const marker = JSON.parse(readFileSync15(markerPath, "utf8"));
18414
+ return typeof marker === "object" && marker !== null && "version" in marker && marker.version === 1 && "completed" in marker && marker.completed === true && "parsed" in marker && marker.parsed === true;
18415
+ } catch {
18416
+ return false;
18417
+ }
18418
+ }
18419
+ async function runLiteRetrieve(ctx) {
18420
+ const query = ctx.positionals.join(" ").trim();
18421
+ if (query.length === 0) {
18422
+ ctx.stderr(renderError(new Error("Usage: autorag lite retrieve <query> [--top-k N] [--scope SCOPE] [--tags tag1,tag2]"), {
18423
+ json: ctx.json,
18424
+ debug: ctx.debug
18425
+ }));
18426
+ return 2;
18427
+ }
18428
+ const topKResult = parseTopK(ctx.flags["top-k"]);
18429
+ if (topKResult.kind === "reject") {
18430
+ const envelope = { ok: false, error: topKResult.error };
18431
+ ctx.stderr(renderLiteRetrieveJson(envelope));
18432
+ return 2;
18433
+ }
18434
+ let lite;
18435
+ try {
18436
+ lite = createAutoRAGLite({ flags: ctx.flags, cwd: ctx.cwd });
18437
+ } catch (error) {
18438
+ ctx.stderr(renderError(error, { json: ctx.json, debug: ctx.debug }));
18439
+ return 2;
18440
+ }
18441
+ const workspacePath = lite.config.workspacePath;
18442
+ const parsedReady = hasCompletedParsedRefresh(workspacePath);
18443
+ if (!parsedReady) {
18444
+ const envelope = {
18445
+ ok: false,
18446
+ query,
18447
+ diagnostics: [
18448
+ {
18449
+ code: "index-not-ready",
18450
+ severity: "error",
18451
+ message: "Index has not been refreshed. Run `autorag lite refresh` or `autorag refresh` before retrieving."
18452
+ }
18453
+ ]
18454
+ };
18455
+ ctx.stdout(renderLiteRetrieveJson(envelope));
18456
+ return 2;
18457
+ }
18458
+ const staleDiagnostics = await detectMirrorStaleness({
18459
+ root: workspacePath,
18460
+ searchPaths: lite.config.searchPaths,
18461
+ parserOptions: lite.config.parserOptions
18462
+ });
18463
+ if (staleDiagnostics.length > 0) {
18464
+ const envelope = {
18465
+ ok: false,
18466
+ query,
18467
+ diagnostics: [
18468
+ {
18469
+ code: "index-not-ready",
18470
+ severity: "error",
18471
+ message: "Index is stale. Run `autorag lite refresh` or `autorag refresh` before retrieving."
18472
+ }
18473
+ ]
18474
+ };
18475
+ ctx.stdout(renderLiteRetrieveJson(envelope));
18476
+ return 2;
18477
+ }
18478
+ const options = buildRetrieveOptions(ctx.flags);
18479
+ let retrievalResult;
18480
+ try {
18481
+ retrievalResult = await lite.retrieve(query, {
18482
+ topK: topKResult.value ?? options.topK,
18483
+ scope: options.scope,
18484
+ allowedTags: options.allowedTags
18485
+ });
18486
+ } catch (error) {
18487
+ ctx.stderr(renderError(error, { json: ctx.json, debug: ctx.debug }));
18488
+ return 1;
18489
+ }
18490
+ const diagnostics = (retrievalResult.diagnostics ?? []).map(diagnosticProjection2);
18491
+ const results = retrievalResult.results.map((r, i) => ({
18492
+ number: i + 1,
18493
+ source: r.source,
18494
+ method: typeof r.metadata.method === "string" ? r.metadata.method : "unknown",
18495
+ score: r.score,
18496
+ metadata: r.metadata,
18497
+ content: r.content
18498
+ }));
18499
+ const envelope = {
18500
+ ok: true,
18501
+ query,
18502
+ results,
18503
+ diagnostics
18504
+ };
18505
+ if (ctx.json) {
18506
+ ctx.stdout(renderLiteRetrieveJson(envelope));
18507
+ } else {
18508
+ ctx.stdout(renderLiteRetrieveHuman(envelope, ctx.debug));
18509
+ }
18510
+ return 0;
18511
+ }
18512
+ var init_lite_retrieve = __esm(() => {
18513
+ init_core();
18514
+ init_mirror();
18515
+ init_paths();
18516
+ });
18517
+
18518
+ // src/cli/commands/report.ts
18519
+ import { readFileSync as readFileSync16 } from "node:fs";
18520
+ import { Value } from "typebox/value";
18521
+ function readReportInput(input) {
18522
+ if (typeof input === "string" && input.length > 0)
18523
+ return readFileSync16(input, "utf8");
18524
+ return readFileSync16(0, "utf8");
18525
+ }
18526
+ function validateReport(value) {
18527
+ if (!Value.Check(emitResultsSchema, value)) {
18528
+ throw new Error("Invalid report: expected the emit_autorag_results JSON schema");
18529
+ }
18530
+ const parsed = Value.Parse(emitResultsSchema, value);
18531
+ const resultNumbers = parsed.results.map((result) => result.number);
18532
+ const mappingNumbers = parsed.mapping.map((entry) => entry.number);
18533
+ const allNumbers = [...resultNumbers, ...mappingNumbers];
18534
+ const uniqueResultNumbers = new Set(resultNumbers);
18535
+ const uniqueMappingNumbers = new Set(mappingNumbers);
18536
+ const oneToOne = resultNumbers.length === mappingNumbers.length && uniqueResultNumbers.size === resultNumbers.length && uniqueMappingNumbers.size === mappingNumbers.length && resultNumbers.every((number) => uniqueMappingNumbers.has(number));
18537
+ if (!oneToOne || allNumbers.some((number) => number < 1)) {
18538
+ throw new Error("Invalid report: results and mapping numbers must be one-to-one positive numbers");
18539
+ }
18540
+ if (parsed.results.some((result) => !Number.isFinite(result.confidence) || result.confidence < 0 || result.confidence > 1)) {
18541
+ throw new Error("Invalid report: result confidence must be in [0, 1]");
18542
+ }
18543
+ if (parsed.mapping.some((entry) => (entry.evidenceRefs ?? []).some((reference) => reference.confidence !== undefined && (!Number.isFinite(reference.confidence) || reference.confidence < 0 || reference.confidence > 1)))) {
18544
+ throw new Error("Invalid report: evidence confidence must be in [0, 1]");
18545
+ }
18546
+ return {
18547
+ answer: parsed.answer,
18548
+ results: parsed.results,
18549
+ mapping: parsed.mapping.map((entry) => ({
18550
+ ...entry,
18551
+ evidenceRefs: entry.evidenceRefs ?? [{ method: entry.method, source: entry.source, content: entry.content }]
18552
+ })),
18553
+ warnings: parsed.warnings ?? []
18554
+ };
18555
+ }
18556
+ function renderReport(details, sessionId, query, json) {
18557
+ const envelope = { ok: true, sessionId, query, answer: details.answer, resultCount: details.results.length };
18558
+ if (json)
18559
+ return JSON.stringify(envelope, null, 2);
18560
+ return `report: ok
18561
+ sessionId: ${sessionId}
18562
+ results: ${details.results.length}`;
18563
+ }
18564
+ function renderReportError(error, json, debug) {
18565
+ if (!json)
18566
+ return renderError(error, { json, debug });
18567
+ const message = error instanceof Error ? error.message : String(error);
18568
+ return JSON.stringify({ ok: false, error: message });
18569
+ }
18570
+ async function runReport(ctx) {
18571
+ const query = ctx.positionals.join(" ").trim();
18572
+ if (query.length === 0) {
18573
+ ctx.stderr(renderError(new Error("Usage: autorag lite report <query> [--input FILE]"), { json: ctx.json }));
18574
+ return 2;
18575
+ }
18576
+ let details;
18577
+ try {
18578
+ const text = readReportInput(ctx.flags.input);
18579
+ const parsed = JSON.parse(text);
18580
+ details = validateReport(parsed);
18581
+ } catch (error) {
18582
+ ctx.stderr(renderReportError(error, ctx.json, ctx.debug));
18583
+ return 2;
18584
+ }
18585
+ try {
18586
+ const lite = createAutoRAGLite({ flags: ctx.flags, cwd: ctx.cwd });
18587
+ const response = lite.recordReport(query, details);
18588
+ ctx.stdout(renderReport(details, response.sessionId, query, ctx.json));
18589
+ return 0;
18590
+ } catch (error) {
18591
+ ctx.stderr(renderError(error, { json: ctx.json, debug: ctx.debug }));
18592
+ return error instanceof ConfigError ? 2 : 1;
18593
+ }
18594
+ }
18595
+ var init_report = __esm(() => {
18596
+ init_emit_results_tool();
18597
+ init_core();
18598
+ init_config2();
18599
+ });
18600
+
18601
+ // src/cli/commands/lite.ts
18602
+ async function runLite(ctx) {
18603
+ const sub = ctx.positionals[0];
18604
+ if (ctx.flags.help === true || sub === undefined || sub === "help") {
18605
+ ctx.stdout(LITE_USAGE.trimEnd());
18606
+ return 0;
18607
+ }
18608
+ const subCtx = {
18609
+ ...ctx,
18610
+ positionals: ctx.positionals.slice(1)
18611
+ };
18612
+ switch (sub) {
18613
+ case "init":
18614
+ return runInit(subCtx);
18615
+ case "ui":
18616
+ return runUi(subCtx);
18617
+ case "refresh":
18618
+ return runLiteRefresh(subCtx);
18619
+ case "watch":
18620
+ return runWatch(subCtx);
18621
+ case "status":
18622
+ return runStatus(subCtx);
18623
+ case "index":
18624
+ return runIndex(subCtx);
18625
+ case "duplicates":
18626
+ return runDuplicates(subCtx);
18627
+ case "health":
18628
+ return runStatus(subCtx);
18629
+ case "retrieve": {
18630
+ await Promise.resolve().then(() => init_lite_retrieve());
18631
+ return runLiteRetrieve(subCtx);
18632
+ }
18633
+ case "report": {
18634
+ await Promise.resolve().then(() => init_report());
18635
+ return runReport(subCtx);
18636
+ }
18637
+ default:
18638
+ ctx.stderr(`Unknown lite subcommand: ${sub}
18639
+
18640
+ ${LITE_USAGE}`);
18641
+ return 2;
18642
+ }
18643
+ }
18644
+ var LITE_USAGE = `autorag lite - model-free AutoRAG lifecycle CLI
18645
+
18646
+ Usage: autorag lite <subcommand> [args] [flags]
18647
+
18648
+ Subcommands:
18649
+ autorag lite init
18650
+ Write the configured model-free lifecycle config
18651
+ (--search-paths PATHS --workspace DIR --memory-path FILE --force)
18652
+ autorag lite ui Open the local datasource setup UI
18653
+ (--port N --host 127.0.0.1 --no-open --allow-remote)
18654
+ autorag lite refresh Run an incremental index refresh (no model required)
18655
+ (--full --force --method minsync,parsed,datasources,jikji,all)
18656
+ autorag lite watch Watch configured roots (or --once for one refresh tick)
18657
+ (--once --immediate --debounce-ms N --force)
18658
+ autorag lite status Show path-opaque corpus freshness and index health
18659
+ autorag lite index Reset or rebuild parsed/MinSync indexes
18660
+ (reset|rebuild --yes --method)
18661
+ autorag lite duplicates
18662
+ Scan duplicate document families without deleting files
18663
+ autorag lite health Show model-free index health (alias of lite status)
18664
+ autorag lite retrieve <query>
18665
+ Retrieve documents without model curation
18666
+ (--top-k N --scope SCOPE --tags A,B --json --debug)
18667
+ autorag lite report <query>
18668
+ Persist a structured report from external curation
18669
+ (--input FILE --json --debug)
18670
+
18671
+ Global flags:
18672
+ --json Emit machine-readable JSON
18673
+ --debug Reveal opaque internal diagnostics
18674
+ --config <path> Use a specific config file
18675
+ --help, -h Show this help
18676
+ `;
18677
+ var init_lite = __esm(() => {
18678
+ init_duplicates();
18679
+ init_commands();
18680
+ init_init();
18681
+ init_lite_refresh();
18682
+ init_status();
18683
+ init_ui();
18684
+ init_watch();
18685
+ });
18686
+
17985
18687
  // src/cli/index.ts
17986
18688
  import { realpathSync as realpathSync5 } from "node:fs";
17987
18689
  import { createInterface } from "node:readline";
@@ -17996,7 +18698,8 @@ var BOOLEAN_FLAGS = new Set([
17996
18698
  "immediate",
17997
18699
  "skip-probes",
17998
18700
  "no-open",
17999
- "allow-remote"
18701
+ "allow-remote",
18702
+ "full"
18000
18703
  ]);
18001
18704
  var VALUE_FLAGS = new Set([
18002
18705
  "config",
@@ -18024,7 +18727,8 @@ var VALUE_FLAGS = new Set([
18024
18727
  "minsync-max-chunk-size",
18025
18728
  "timeout-ms",
18026
18729
  "port",
18027
- "host"
18730
+ "host",
18731
+ "input"
18028
18732
  ]);
18029
18733
  var COMMANDS = [
18030
18734
  "init",
@@ -18039,7 +18743,8 @@ var COMMANDS = [
18039
18743
  "health",
18040
18744
  "duplicates",
18041
18745
  "tui",
18042
- "ui"
18746
+ "ui",
18747
+ "lite"
18043
18748
  ];
18044
18749
  var USAGE2 = `autorag - self-evolving librarian CLI
18045
18750
 
@@ -18062,6 +18767,13 @@ Commands:
18062
18767
  index reset Remove parsed/minsync indexes (--method)
18063
18768
  index rebuild Reset then re-run a refresh (--method minsync|all)
18064
18769
  health Check model/provider auth and completion access (no index check)
18770
+ lite init|ui|refresh|watch|status|index|duplicates|health
18771
+ Model-free setup, indexing, status, and datasource lifecycle
18772
+ (lite refresh: --full --force --method; watch: --once)
18773
+ lite retrieve <query>
18774
+ Retrieve documents without model curation
18775
+ (--top-k N --scope SCOPE --tags A,B --json --debug)
18776
+ lite report <query> Persist a structured report (--input FILE)
18065
18777
  duplicates [DIR] Scan exact/near duplicate document families; never deletes files
18066
18778
  tui Open an interactive Pi-powered librarian terminal UI
18067
18779
  ui Open a local loopback page to connect and manage data sources
@@ -18190,6 +18902,9 @@ async function dispatch(command, ctx) {
18190
18902
  await Promise.resolve().then(() => init_ui());
18191
18903
  return runUi(ctx);
18192
18904
  }
18905
+ case "lite": {
18906
+ return dispatchLite(ctx);
18907
+ }
18193
18908
  }
18194
18909
  }
18195
18910
  async function main(argv) {
@@ -18204,8 +18919,10 @@ async function main(argv) {
18204
18919
  const json = flags.json === true;
18205
18920
  const debug = flags.debug === true;
18206
18921
  if (flags.help === true || command === undefined || command === "help") {
18207
- process.stdout.write(USAGE2);
18208
- return 0;
18922
+ if (command === "lite") {} else {
18923
+ process.stdout.write(USAGE2);
18924
+ return 0;
18925
+ }
18209
18926
  }
18210
18927
  if (!COMMANDS.includes(command)) {
18211
18928
  process.stderr.write(`Unknown command: ${command}
@@ -18243,6 +18960,10 @@ function isInvokedDirectly() {
18243
18960
  return false;
18244
18961
  }
18245
18962
  }
18963
+ async function dispatchLite(ctx) {
18964
+ await Promise.resolve().then(() => init_lite());
18965
+ return runLite(ctx);
18966
+ }
18246
18967
  if (isInvokedDirectly()) {
18247
18968
  main(process.argv.slice(2)).then((code) => {
18248
18969
  process.exitCode = code;