@autorag/librarian 2.13.8 → 2.13.10

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
@@ -3668,20 +3668,30 @@ var init_bundle = __esm(() => {
3668
3668
  });
3669
3669
 
3670
3670
  // src/filesystem/path-exclusions.ts
3671
- import { posix as posix2, win32 as win322 } from "node:path";
3671
+ import { matchesGlob, posix as posix2, win32 as win322 } from "node:path";
3672
+ function isGlobExclusion(entry) {
3673
+ return /[*?[]/u.test(entry);
3674
+ }
3675
+ function matchesGlobExclusion(path, glob) {
3676
+ const slashed = path.replaceAll("\\", "/");
3677
+ if (matchesGlob(slashed, glob))
3678
+ return true;
3679
+ return glob.startsWith("**/") && matchesGlob(slashed, glob.slice(3));
3680
+ }
3672
3681
  function createPathExclusionMatcher(excludedPaths, platform = process.platform) {
3673
3682
  const paths = platform === "win32" ? win322 : posix2;
3674
3683
  const normalize = (path) => {
3675
3684
  const absolute = paths.resolve(path);
3676
3685
  return platform === "win32" ? absolute.toLowerCase() : absolute;
3677
3686
  };
3678
- const excluded = excludedPaths.map((path) => {
3687
+ const globs = excludedPaths.filter(isGlobExclusion).map((glob) => platform === "win32" ? glob.toLowerCase() : glob);
3688
+ const excluded = excludedPaths.filter((path) => !isGlobExclusion(path)).map((path) => {
3679
3689
  const absolute = normalize(path);
3680
3690
  return { absolute, prefix: absolute.endsWith(paths.sep) ? absolute : `${absolute}${paths.sep}` };
3681
3691
  });
3682
3692
  return (path) => {
3683
3693
  const absolute = normalize(path);
3684
- return excluded.some((entry) => absolute === entry.absolute || absolute.startsWith(entry.prefix));
3694
+ return excluded.some((entry) => absolute === entry.absolute || absolute.startsWith(entry.prefix)) || globs.some((glob) => matchesGlobExclusion(absolute, glob));
3685
3695
  };
3686
3696
  }
3687
3697
  var init_path_exclusions = () => {};
@@ -7618,6 +7628,34 @@ var init_memory = __esm(() => {
7618
7628
  });
7619
7629
  });
7620
7630
 
7631
+ // src/minsync/channel-union.ts
7632
+ function unionChannelResults(channels, options = {}) {
7633
+ const byChunk = new Map;
7634
+ const depth = Math.max(0, ...channels.map((channel) => channel.results.length));
7635
+ for (let rank = 0;rank < depth; rank++) {
7636
+ for (const channel of channels) {
7637
+ const result = channel.results[rank];
7638
+ if (result === undefined)
7639
+ continue;
7640
+ const key = `${result.source}\x00${result.id}`;
7641
+ const existing = byChunk.get(key);
7642
+ if (existing === undefined)
7643
+ byChunk.set(key, { result, ranks: { [channel.channel]: rank + 1 } });
7644
+ else
7645
+ existing.ranks[channel.channel] ??= rank + 1;
7646
+ }
7647
+ }
7648
+ const union = [...byChunk.values()].map(({ result, ranks }) => ({
7649
+ ...result,
7650
+ metadata: {
7651
+ ...result.metadata,
7652
+ minsyncChannels: Object.keys(ranks).sort(),
7653
+ minsyncChannelRanks: ranks
7654
+ }
7655
+ }));
7656
+ return options.limit === undefined ? union : union.slice(0, options.limit);
7657
+ }
7658
+
7621
7659
  // src/minsync/local-embedder.ts
7622
7660
  import { spawn as spawn11 } from "node:child_process";
7623
7661
  import { request } from "node:http";
@@ -10305,7 +10343,7 @@ var init_cloud = __esm(() => {
10305
10343
  // src/mirror/sync.ts
10306
10344
  import { createHash as createHash11 } from "node:crypto";
10307
10345
  import { opendir, readFile, stat as stat3 } from "node:fs/promises";
10308
- import { basename as basename9, dirname as dirname12, extname as extname6, join as join27, resolve as resolve11, sep as sep6 } from "node:path";
10346
+ import { basename as basename9, dirname as dirname12, extname as extname6, join as join27, resolve as resolve11 } from "node:path";
10309
10347
  import { setTimeout as sleep3 } from "node:timers/promises";
10310
10348
  function errorCode(error) {
10311
10349
  if (!(error instanceof Error))
@@ -10852,13 +10890,14 @@ function normalizeExtension2(extension) {
10852
10890
  return lower.startsWith(".") ? lower : `.${lower}`;
10853
10891
  }
10854
10892
  function isPathExcluded(sourcePath, excluded) {
10855
- if (excluded === undefined)
10893
+ if (excluded === undefined || excluded.size === 0)
10856
10894
  return false;
10857
- for (const excludedPath of excluded) {
10858
- if (sourcePath === excludedPath || sourcePath.startsWith(`${excludedPath}${sep6}`))
10859
- return true;
10895
+ let matcher = matcherBySet.get(excluded);
10896
+ if (matcher === undefined) {
10897
+ matcher = createPathExclusionMatcher([...excluded]);
10898
+ matcherBySet.set(excluded, matcher);
10860
10899
  }
10861
- return false;
10900
+ return matcher(sourcePath);
10862
10901
  }
10863
10902
  function walkLimits(options) {
10864
10903
  return {
@@ -11025,10 +11064,11 @@ async function collectFiles(state, directory, depth) {
11025
11064
  warnDirectoryUnreadable(state, directory, code);
11026
11065
  }
11027
11066
  }
11028
- var DEFAULT_MAX_SOURCE_BYTES, DEFAULT_MAX_DELETE_RATIO = 0.3, MASS_DELETE_FLOOR = 100, DEFAULT_MAX_SCANNED_ENTRIES = 2000000, DEFAULT_MAX_WALK_DEPTH = 64, DEFAULT_MIRROR_BATCH_SIZE = 25, PRODUCT_ARTIFACT_FILE_NAMES, SKIP_DIR_NAMES, PARSER_FAILURE_MESSAGE = "The registered parser failed on this file; it was skipped during indexing.", PARSER_CRASH_MESSAGE = "The registered parser crashed unexpectedly on this file; it was skipped during indexing.", DEFAULT_TRANSIENT_RETRIES = 3, DEFAULT_TRANSIENT_BACKOFF_MS = 50, TRANSIENT_ERROR_CODES, WORKSPACE_ERROR_CODES, MirrorWorkspaceError, STANDALONE_OCR_IMAGE_EXTENSIONS, SEARCH_ROOT_UNAVAILABLE_MESSAGES;
11067
+ var DEFAULT_MAX_SOURCE_BYTES, DEFAULT_MAX_DELETE_RATIO = 0.3, MASS_DELETE_FLOOR = 100, DEFAULT_MAX_SCANNED_ENTRIES = 2000000, DEFAULT_MAX_WALK_DEPTH = 64, DEFAULT_MIRROR_BATCH_SIZE = 25, PRODUCT_ARTIFACT_FILE_NAMES, SKIP_DIR_NAMES, PARSER_FAILURE_MESSAGE = "The registered parser failed on this file; it was skipped during indexing.", PARSER_CRASH_MESSAGE = "The registered parser crashed unexpectedly on this file; it was skipped during indexing.", DEFAULT_TRANSIENT_RETRIES = 3, DEFAULT_TRANSIENT_BACKOFF_MS = 50, TRANSIENT_ERROR_CODES, WORKSPACE_ERROR_CODES, MirrorWorkspaceError, STANDALONE_OCR_IMAGE_EXTENSIONS, matcherBySet, SEARCH_ROOT_UNAVAILABLE_MESSAGES;
11029
11068
  var init_sync = __esm(() => {
11030
11069
  init_cli2();
11031
11070
  init_cloud_placeholder();
11071
+ init_path_exclusions();
11032
11072
  init_source_paths();
11033
11073
  init_binary();
11034
11074
  init_stage();
@@ -11087,6 +11127,7 @@ var init_sync = __esm(() => {
11087
11127
  }
11088
11128
  };
11089
11129
  STANDALONE_OCR_IMAGE_EXTENSIONS = new Set(KORDOC_IMAGE_EXTENSIONS);
11130
+ matcherBySet = new WeakMap;
11090
11131
  SEARCH_ROOT_UNAVAILABLE_MESSAGES = {
11091
11132
  gone: "A search root no longer exists; its previously indexed documents were left untouched.",
11092
11133
  "not-a-directory": "A search root is no longer a directory; its previously indexed documents were left untouched.",
@@ -16161,7 +16202,7 @@ var init_automation_profiles = __esm(() => {
16161
16202
 
16162
16203
  // src/automation/config.ts
16163
16204
  import { existsSync as existsSync19, readFileSync as readFileSync14, realpathSync as realpathSync7 } from "node:fs";
16164
- import { basename as basename10, dirname as dirname15, isAbsolute as isAbsolute8, join as join30, matchesGlob, relative as relative5, resolve as resolve12 } from "node:path";
16205
+ import { basename as basename10, dirname as dirname15, isAbsolute as isAbsolute8, join as join30, matchesGlob as matchesGlob2, relative as relative5, resolve as resolve12 } from "node:path";
16165
16206
  function automationsConfigPath(env = process.env) {
16166
16207
  return join30(resolveAutoRAGHome(env), "automations.json");
16167
16208
  }
@@ -16337,9 +16378,9 @@ function deleteAutomation(configPath, id) {
16337
16378
  function globMatches(relPosix, pattern) {
16338
16379
  if (pattern === "**")
16339
16380
  return true;
16340
- if (matchesGlob(relPosix, pattern))
16381
+ if (matchesGlob2(relPosix, pattern))
16341
16382
  return true;
16342
- if (pattern.startsWith("**/") && matchesGlob(relPosix, pattern.slice(3)))
16383
+ if (pattern.startsWith("**/") && matchesGlob2(relPosix, pattern.slice(3)))
16343
16384
  return true;
16344
16385
  return false;
16345
16386
  }
@@ -17136,7 +17177,7 @@ var init_permission_judgment = __esm(() => {
17136
17177
 
17137
17178
  // src/agent/permission-gate.ts
17138
17179
  import { statSync as statSync7 } from "node:fs";
17139
- import { isAbsolute as isAbsolute9, relative as relative6, sep as sep7 } from "node:path";
17180
+ import { isAbsolute as isAbsolute9, relative as relative6, sep as sep6 } from "node:path";
17140
17181
  import { matchesKey } from "@earendil-works/pi-tui";
17141
17182
  function pathExists(path) {
17142
17183
  try {
@@ -17199,7 +17240,7 @@ class PermissionController {
17199
17240
  if (path === root)
17200
17241
  return true;
17201
17242
  const rel = relative6(root, path);
17202
- if (rel !== "" && rel !== ".." && !rel.startsWith(`..${sep7}`) && !isAbsolute9(rel))
17243
+ if (rel !== "" && rel !== ".." && !rel.startsWith(`..${sep6}`) && !isAbsolute9(rel))
17203
17244
  return true;
17204
17245
  }
17205
17246
  return false;
@@ -18651,7 +18692,7 @@ var init_connector = () => {};
18651
18692
  // src/datasource/sidecar/config.ts
18652
18693
  import { readFileSync as readFileSync17 } from "node:fs";
18653
18694
  import { homedir as homedir5 } from "node:os";
18654
- import { dirname as dirname17, isAbsolute as isAbsolute10, join as join34, resolve as resolve14, sep as sep8 } from "node:path";
18695
+ import { dirname as dirname17, isAbsolute as isAbsolute10, join as join34, resolve as resolve14, sep as sep7 } from "node:path";
18655
18696
  import { parse as parseToml } from "smol-toml";
18656
18697
  function resolveSidecarOptions(input) {
18657
18698
  const { connector, workspaceRoot } = input;
@@ -18691,7 +18732,7 @@ function archivePathFromCrawlerConfig(input) {
18691
18732
  function expandHome(path) {
18692
18733
  if (path === "~")
18693
18734
  return homedir5();
18694
- const prefixed = path.startsWith("~/") || sep8 === "\\" && path.startsWith("~\\");
18735
+ const prefixed = path.startsWith("~/") || sep7 === "\\" && path.startsWith("~\\");
18695
18736
  return prefixed ? join34(homedir5(), path.slice(2)) : path;
18696
18737
  }
18697
18738
  var init_config3 = __esm(() => {
@@ -25945,7 +25986,7 @@ import {
25945
25986
  writeFileSync as writeFileSync13
25946
25987
  } from "node:fs";
25947
25988
  import { opendir as opendir2, stat as stat4 } from "node:fs/promises";
25948
- import { basename as basename11, dirname as dirname23, extname as extname8, join as join40, relative as relative7, sep as sep9 } from "node:path";
25989
+ import { basename as basename11, dirname as dirname23, extname as extname8, join as join40, relative as relative7, sep as sep8 } from "node:path";
25949
25990
  function errnoCode2(error) {
25950
25991
  const code = error instanceof Error ? error.code : undefined;
25951
25992
  return typeof code === "string" ? code : "UNKNOWN";
@@ -26015,7 +26056,7 @@ async function listVaultNotes(vaultPath) {
26015
26056
  return { notes, unreadableFolders, collisions };
26016
26057
  }
26017
26058
  function toRelative(vaultPath, path) {
26018
- return relative7(vaultPath, path).split(sep9).join("/").normalize("NFC");
26059
+ return relative7(vaultPath, path).split(sep8).join("/").normalize("NFC");
26019
26060
  }
26020
26061
  function loadStagingState2(statePath) {
26021
26062
  try {
@@ -26099,7 +26140,7 @@ function removeUnexpected(filesRoot, directory, wanted) {
26099
26140
  return removed;
26100
26141
  }
26101
26142
  function toStagedRelative(filesRoot, path) {
26102
- return relative7(filesRoot, path).split(sep9).join("/").normalize("NFC");
26143
+ return relative7(filesRoot, path).split(sep8).join("/").normalize("NFC");
26103
26144
  }
26104
26145
  var NOTE_EXTENSIONS, SKIPPED_DIRECTORIES, MAX_WALK_DEPTH = 64, VaultUnavailableError;
26105
26146
  var init_staging = __esm(() => {
@@ -28020,7 +28061,7 @@ function resolveExcludePaths(value, origin) {
28020
28061
  if (!Array.isArray(value) || value.some((path) => typeof path !== "string" || path.length === 0)) {
28021
28062
  throw new ConfigError("Config field 'excludePaths' must be a non-empty string array");
28022
28063
  }
28023
- return resolveSearchPaths(value, origin);
28064
+ return value.map((entry) => isGlobExclusion(entry) ? entry : resolvePersistedPath(entry, origin));
28024
28065
  }
28025
28066
  function resolvePersistedPath(path, origin) {
28026
28067
  return isAbsolute11(path) ? path : resolve15(origin, path);
@@ -29325,6 +29366,7 @@ var init_config5 = __esm(() => {
29325
29366
  init_factory();
29326
29367
  init_embedding();
29327
29368
  init_file_lock();
29369
+ init_path_exclusions();
29328
29370
  init_language();
29329
29371
  init_atomic_write();
29330
29372
  init_rerank();
@@ -38578,7 +38620,7 @@ var init_web_search_tool = __esm(() => {
38578
38620
  // src/agent/agent.ts
38579
38621
  import { randomUUID as randomUUID7 } from "node:crypto";
38580
38622
  import { existsSync as existsSync34, watch as fsWatch, mkdirSync as mkdirSync24, realpathSync as realpathSync8, statSync as statSync11, writeFileSync as writeFileSync17 } from "node:fs";
38581
- import { basename as basename15, dirname as dirname27, join as join55, relative as relative8, resolve as resolve18, sep as sep10 } from "node:path";
38623
+ import { basename as basename15, dirname as dirname27, join as join55, relative as relative8, resolve as resolve18, sep as sep9 } from "node:path";
38582
38624
  import { clampThinkingLevel } from "@earendil-works/pi-ai/compat";
38583
38625
  import { getAgentDir as getAgentDir6, keyText } from "@earendil-works/pi-coding-agent";
38584
38626
  function describeDecisionModel(status) {
@@ -38721,6 +38763,7 @@ class AutoRAGAgent {
38721
38763
  reranker;
38722
38764
  rerankTopN;
38723
38765
  minSyncMethod;
38766
+ minSyncSparseMethod;
38724
38767
  minSyncEmbedderConfig;
38725
38768
  minSyncBinaryPath;
38726
38769
  jikjiClient;
@@ -38843,6 +38886,7 @@ class AutoRAGAgent {
38843
38886
  ...this.limits.recordCut === undefined ? {} : { recordCut: this.limits.recordCut }
38844
38887
  };
38845
38888
  this.minSyncMethod = new MinSyncVectorMethod(minSyncDefaults);
38889
+ this.minSyncSparseMethod = isSparseOnlyEmbedder(options.minSync?.embedder) ? undefined : new MinSyncVectorMethod({ ...minSyncDefaults, mode: "sparse" });
38846
38890
  this.methodRegistry.register(new MinSyncHybridMethod(minSyncDefaults));
38847
38891
  const registeredDatasourceIds = new Set;
38848
38892
  for (const skill of this.datasourceSkills) {
@@ -40317,13 +40361,7 @@ Warning: the edited config did not validate, so the previous config was restored
40317
40361
  ${list.map((entry, index) => `[${index + 1}] ${entry}`).join(`
40318
40362
  `)}`;
40319
40363
  const perQuery = await Promise.all(searchQueries.map((searchQuery) => Promise.all([
40320
- this.searchProgress.track("minsync", "MinSync semantic search", this.minSyncMethod.retrieve(searchQuery, retrieveOptions), {
40321
- count: (found) => found.length
40322
- }).catch((error) => {
40323
- if (error instanceof MinSyncRequiredError)
40324
- throw error;
40325
- return [];
40326
- }),
40364
+ this.prefetchMinSyncCandidates(searchQuery, retrieveOptions),
40327
40365
  Promise.all(datasources.map((datasourceId) => this.searchProgress.track(`datasource:${datasourceId}`, `Datasource ${datasourceId}`, this.searchSingleDatasourceDocuments(datasourceId, searchQuery, {
40328
40366
  topK: this.limits.prefetch.datasourceTopK,
40329
40367
  scope: options.scope,
@@ -40438,6 +40476,30 @@ ${result.content.replace(/\s+/gu, " ")}`).join(`
40438
40476
 
40439
40477
  `);
40440
40478
  }
40479
+ async prefetchMinSyncCandidates(searchQuery, options) {
40480
+ const sparse = this.reranker === undefined ? undefined : this.minSyncSparseMethod;
40481
+ const run = (id, label, method) => this.searchProgress.track(id, label, method.retrieve(searchQuery, options), { count: (found) => found.length }).catch((error) => {
40482
+ if (error instanceof MinSyncRequiredError)
40483
+ throw error;
40484
+ if (sparse !== undefined) {
40485
+ this.routingDiagnostics.push({
40486
+ code: "retrieval-method-failed",
40487
+ severity: "warning",
40488
+ message: `MinSync ${id === "minsync" ? "dense" : "SPLADE"} search failed and its candidates were skipped; the other channel's were used: ${describeRetrievalError(error)}`,
40489
+ source: id
40490
+ });
40491
+ }
40492
+ return [];
40493
+ });
40494
+ const dense = run("minsync", "MinSync semantic search", this.minSyncMethod);
40495
+ if (sparse === undefined)
40496
+ return dense;
40497
+ const [vector, splade] = await Promise.all([dense, run("minsync-sparse", "MinSync SPLADE search", sparse)]);
40498
+ return unionChannelResults([
40499
+ { channel: "vector", results: vector },
40500
+ { channel: "sparse", results: splade }
40501
+ ]);
40502
+ }
40441
40503
  async prefetchWebSearch(searchQuery, signal) {
40442
40504
  const web = this.webSearchOptions;
40443
40505
  if (web === undefined)
@@ -41231,7 +41293,7 @@ ${this.discoveryHint((tools) => `When exploring local files and folders, activel
41231
41293
  return { ok: false, reason: "cloud-root-skipped", stdout: "", stderr: "", code: null };
41232
41294
  }
41233
41295
  const canonicalSourcePath = canonicalPath(sourcePath);
41234
- const exclude = scope.nestedCloudRoots.map((root) => relative8(canonicalSourcePath, root.path).split(sep10).join("/")).filter((pattern) => pattern !== "" && !pattern.startsWith(".."));
41296
+ const exclude = scope.nestedCloudRoots.map((root) => relative8(canonicalSourcePath, root.path).split(sep9).join("/")).filter((pattern) => pattern !== "" && !pattern.startsWith(".."));
41235
41297
  return client.prepare(sourcePath, { ...options, ...exclude.length === 0 ? {} : { exclude } });
41236
41298
  }));
41237
41299
  }
@@ -41745,6 +41807,8 @@ function toMinSyncReasonDiagnostic(reason) {
41745
41807
  };
41746
41808
  }
41747
41809
  function pinExcludedPath(path) {
41810
+ if (isGlobExclusion(path))
41811
+ return path;
41748
41812
  const resolvedPath = resolve18(path);
41749
41813
  try {
41750
41814
  return join55(realpathSync8(dirname27(resolvedPath)), basename15(resolvedPath));
@@ -41793,6 +41857,7 @@ var init_agent = __esm(() => {
41793
41857
  init_embedding();
41794
41858
  init_everything();
41795
41859
  init_cloud_placeholder();
41860
+ init_path_exclusions();
41796
41861
  init_fsearch();
41797
41862
  init_diagnostics();
41798
41863
  init_jikji();
@@ -41815,6 +41880,7 @@ var init_agent = __esm(() => {
41815
41880
  init_merger();
41816
41881
  init_rerank();
41817
41882
  init_scope();
41883
+ init_skip();
41818
41884
  init_search();
41819
41885
  init_model_auth();
41820
41886
  init_answer_citations();
@@ -42009,6 +42075,12 @@ class AutoRAGLite {
42009
42075
  getMemorySchema() {
42010
42076
  return structuredClone(this.memory.getSchema());
42011
42077
  }
42078
+ convertFiles(request, signal) {
42079
+ return this.agent.convertFiles(request, signal);
42080
+ }
42081
+ listFileConversions(from, signal) {
42082
+ return this.agent.listFileConversions(from, signal);
42083
+ }
42012
42084
  }
42013
42085
  function createAutoRAGLite(options = {}) {
42014
42086
  const input = { flags: options.flags ?? {} };
@@ -42878,7 +42950,7 @@ import { z as z4 } from "zod";
42878
42950
  // src/filesystem/name-search.ts
42879
42951
  import { realpathSync as realpathSync9 } from "node:fs";
42880
42952
  import { lstat as lstat2, readdir as readdir5 } from "node:fs/promises";
42881
- import { basename as basename16, dirname as dirname28, isAbsolute as isAbsolute14, join as join56, relative as relative9, resolve as resolve19, sep as sep11 } from "node:path";
42953
+ import { basename as basename16, dirname as dirname28, isAbsolute as isAbsolute14, join as join56, relative as relative9, resolve as resolve19, sep as sep10 } from "node:path";
42882
42954
  var SKIP_DIR_NAMES2 = {
42883
42955
  ".git": true,
42884
42956
  ".autorag": true,
@@ -42906,7 +42978,7 @@ function fsErrorCode(error) {
42906
42978
  return typeof code === "string" ? code : undefined;
42907
42979
  }
42908
42980
  function isContained(childReal, parentReal) {
42909
- const prefix = parentReal.endsWith(sep11) ? parentReal : `${parentReal}${sep11}`;
42981
+ const prefix = parentReal.endsWith(sep10) ? parentReal : `${parentReal}${sep10}`;
42910
42982
  return childReal === parentReal || childReal.startsWith(prefix);
42911
42983
  }
42912
42984
  function pinExcludedPath2(path) {
@@ -42919,14 +42991,14 @@ function pinExcludedPath2(path) {
42919
42991
  }
42920
42992
  function isExcluded2(absPath, excluded) {
42921
42993
  for (const excludedPath of excluded) {
42922
- const prefix = excludedPath.endsWith(sep11) ? excludedPath : `${excludedPath}${sep11}`;
42994
+ const prefix = excludedPath.endsWith(sep10) ? excludedPath : `${excludedPath}${sep10}`;
42923
42995
  if (absPath === excludedPath || absPath.startsWith(prefix))
42924
42996
  return true;
42925
42997
  }
42926
42998
  return false;
42927
42999
  }
42928
43000
  function matchesEntry(context, absPath, name) {
42929
- const haystackRaw = context.matchPath ? relative9(context.rootReal, absPath).split(sep11).join("/") : name;
43001
+ const haystackRaw = context.matchPath ? relative9(context.rootReal, absPath).split(sep10).join("/") : name;
42930
43002
  const haystack = context.matchCase ? haystackRaw : haystackRaw.toLowerCase();
42931
43003
  const needle = context.matchCase ? context.query : context.query.toLowerCase();
42932
43004
  return haystack.includes(needle);
@@ -43067,7 +43139,7 @@ async function filterFileNameSearchMatches(roots, candidates, excludePaths = [])
43067
43139
  continue;
43068
43140
  if (isExcluded2(real, excluded))
43069
43141
  continue;
43070
- const segments = real.split(sep11);
43142
+ const segments = real.split(sep10);
43071
43143
  if (segments.some((segment) => SKIP_DIR_NAMES2[segment] === true))
43072
43144
  continue;
43073
43145
  matches.push({ path: real, type: stat.isDirectory() ? "folder" : "file" });
@@ -43191,6 +43263,16 @@ var evidenceInput = z4.strictObject({
43191
43263
  sessionId: z4.string().trim().min(1),
43192
43264
  resultNumber: z4.number().int().positive().optional()
43193
43265
  });
43266
+ var convertInput = z4.strictObject({
43267
+ inputs: z4.array(z4.string().trim().min(1)).min(1).max(500),
43268
+ to: z4.string().trim().min(1),
43269
+ outputDir: z4.string().trim().min(1).optional(),
43270
+ recursive: z4.boolean().optional(),
43271
+ quality: z4.number().int().min(1).max(100).optional(),
43272
+ keepDates: z4.boolean().optional()
43273
+ });
43274
+ var convertFormatsInput = z4.strictObject({ from: z4.string().trim().min(1).optional() });
43275
+ var MAX_CONVERT_FILES = 200;
43194
43276
  function exactGroupsFromScan(scan) {
43195
43277
  const groups = new Map;
43196
43278
  for (const file of scan.files) {
@@ -43212,6 +43294,26 @@ function jsonResult(value, isError = false) {
43212
43294
  function toolError(code, message, extra = {}) {
43213
43295
  return jsonResult({ ok: false, errorCode: code, message, ...extra }, true);
43214
43296
  }
43297
+ function convertResult(details) {
43298
+ const { result, links } = details;
43299
+ const files = result.files.slice(0, MAX_CONVERT_FILES).map((file) => ({
43300
+ source: file.source,
43301
+ state: file.state,
43302
+ outputs: file.outputs,
43303
+ ...file.error !== undefined ? { error: file.error } : {},
43304
+ ...file.notice !== undefined ? { notice: file.notice } : {}
43305
+ }));
43306
+ const body = {
43307
+ target: result.target,
43308
+ converted: result.converted,
43309
+ skipped: result.skipped,
43310
+ failed: result.failed,
43311
+ files,
43312
+ ...result.files.length > files.length ? { omittedFiles: result.files.length - files.length } : {},
43313
+ links
43314
+ };
43315
+ return result.converted === 0 && result.failed > 0 ? toolError("convert-failed", "No file was converted.", body) : jsonResult({ ok: true, ...body });
43316
+ }
43215
43317
  function isToolEnabled(name, options) {
43216
43318
  return options.tools === undefined || options.tools.includes(name);
43217
43319
  }
@@ -43506,6 +43608,46 @@ function createAutoRAGMcpServer(lite, options = {}) {
43506
43608
  return datasource === undefined ? toolError("datasource-not-found", `No configured datasource named ${datasourceId}.`, { datasourceId }) : jsonResult({ ok: true, datasource });
43507
43609
  });
43508
43610
  }
43611
+ const convertEnabled = lite.config.filee?.enabled !== false;
43612
+ if (convertEnabled && !readOnly && isToolEnabled("autorag.convert", options)) {
43613
+ server.registerTool("autorag.convert", {
43614
+ title: "Convert Files",
43615
+ description: "Convert local files to another format offline with Filee: documents, spreadsheets, slides, HWP/HWPX, images, e-books, archives, audio, video, data. Writes new files next to each source (or into outputDir) and never replaces an existing file: a colliding name gets a number added. Each output is compared with its source by Dupey, so the result says whether the copy would count as a duplicate. Use autorag.convert.formats when unsure what a source can become.",
43616
+ inputSchema: convertInput,
43617
+ outputSchema: objectOutput,
43618
+ annotations: { readOnlyHint: false, idempotentHint: false, destructiveHint: false, openWorldHint: false }
43619
+ }, async ({ inputs, to, outputDir, recursive, quality, keepDates }, ctx) => {
43620
+ try {
43621
+ const details = await lite.convertFiles({
43622
+ inputs,
43623
+ to,
43624
+ ...outputDir !== undefined ? { outputDir } : {},
43625
+ ...recursive !== undefined ? { recursive } : {},
43626
+ ...quality !== undefined ? { quality } : {},
43627
+ ...keepDates !== undefined ? { keepDates } : {}
43628
+ }, ctx.mcpReq.signal);
43629
+ return convertResult(details);
43630
+ } catch (error) {
43631
+ return toolError("convert-failed", error instanceof Error ? error.message : String(error));
43632
+ }
43633
+ });
43634
+ }
43635
+ if (convertEnabled && isToolEnabled("autorag.convert.formats", options)) {
43636
+ server.registerTool("autorag.convert.formats", {
43637
+ title: "List Convertible Formats",
43638
+ description: "List the file formats Filee knows, or what one source format (heic, docx, hwp, mkv) can be converted to, including targets that need an optional engine. Read-only.",
43639
+ inputSchema: convertFormatsInput,
43640
+ outputSchema: objectOutput,
43641
+ annotations: { readOnlyHint: true, openWorldHint: false }
43642
+ }, async ({ from }, ctx) => {
43643
+ try {
43644
+ const formats = await lite.listFileConversions(from, ctx.mcpReq.signal);
43645
+ return jsonResult({ ok: true, ...from !== undefined ? { from } : {}, formats });
43646
+ } catch (error) {
43647
+ return toolError("convert-failed", error instanceof Error ? error.message : String(error));
43648
+ }
43649
+ });
43650
+ }
43509
43651
  if (!readOnly && isToolEnabled("autorag.report", options)) {
43510
43652
  server.registerTool("autorag.report", {
43511
43653
  title: "Persist AutoRAG Curated Report",