@autorag/librarian 2.6.1 → 2.6.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.
@@ -158,6 +158,7 @@ export interface AutoRAGAgentOptions {
158
158
  parserOptions?: DefaultParserRegistryOptions;
159
159
  dupey?: DupeyCliOptions | false;
160
160
  excludeExactDuplicates?: boolean;
161
+ excludePaths?: readonly string[];
161
162
  datasourceSkills?: readonly DatasourceSkill[];
162
163
  datasourceAccess?: DatasourceAccessContextOptions;
163
164
  /** Non-fatal diagnostics from config/agent construction (e.g. skipped unknown datasources). */
@@ -242,6 +243,7 @@ export declare class AutoRAGAgent {
242
243
  private readonly parserOptions;
243
244
  private readonly dupeyOptions;
244
245
  private readonly excludeExactDuplicates;
246
+ private readonly excludePaths;
245
247
  private readonly baseSystemPromptConfig;
246
248
  private readonly droppedCallerToolNames;
247
249
  private readonly searchTimeoutMs;
@@ -111,6 +111,8 @@ export interface CliConfig {
111
111
  timeoutMs?: number;
112
112
  };
113
113
  excludeExactDuplicates?: boolean;
114
+ /** Absolute or workspace-relative files/directories omitted from local indexing. */
115
+ excludePaths?: string[];
114
116
  /** Trusted datasource skill configuration (skill name → config). */
115
117
  datasources?: DatasourcesConfig;
116
118
  /** Trusted datasource allow-tags/allow-scopes. Absent ⇒ default-deny. */
package/dist/cli/index.js CHANGED
@@ -2301,7 +2301,7 @@ function isParsedMirrorSkipEntry(value) {
2301
2301
  return isRecord2(value) && typeof value.virtualPath === "string" && typeof value.sourcePath === "string" && isParsedMirrorSkipReason(value.reason) && typeof value.sourceMtimeNs === "number" && typeof value.sourceSizeBytes === "number" && typeof value.updatedAt === "string";
2302
2302
  }
2303
2303
  function isParsedMirrorSkipReason(value) {
2304
- return value === "duplicate-excluded" || value === "parser-skipped" || value === "parser-failed";
2304
+ return value === "duplicate-excluded" || value === "user-excluded" || value === "parser-skipped" || value === "parser-failed";
2305
2305
  }
2306
2306
  function isParsedMirrorEntry(value) {
2307
2307
  return isRecord2(value) && typeof value.virtualPath === "string" && typeof value.sourcePath === "string" && typeof value.outputPath === "string" && typeof value.parserName === "string" && typeof value.sourceMtimeNs === "number" && typeof value.sourceSizeBytes === "number" && typeof value.updatedAt === "string";
@@ -11043,6 +11043,10 @@ function resolveConfig(input) {
11043
11043
  const configOrigin = dirname10(resolve6(configPath));
11044
11044
  const fileWorkspacePath = typeof file.workspacePath === "string" ? resolvePersistedPath(file.workspacePath, configOrigin) : undefined;
11045
11045
  const fileSearchPaths = file.searchPaths ? resolveSearchPaths(file.searchPaths, fileWorkspacePath ?? configOrigin) : undefined;
11046
+ if (file.excludePaths !== undefined && (!Array.isArray(file.excludePaths) || file.excludePaths.some((path) => typeof path !== "string" || path.length === 0))) {
11047
+ throw new ConfigError("Config field 'excludePaths' must be a non-empty string array");
11048
+ }
11049
+ const fileExcludePaths = file.excludePaths ? resolveSearchPaths(file.excludePaths, fileWorkspacePath ?? configOrigin) : undefined;
11046
11050
  const searchPaths = flagSearchPaths ?? envSearchPaths ?? fileSearchPaths ?? defaultSearchPaths;
11047
11051
  const flagWorkspacePath = flagString(flags, "workspace");
11048
11052
  const envWorkspacePath = envString(env, "AUTORAG_WORKSPACE");
@@ -11066,6 +11070,8 @@ function resolveConfig(input) {
11066
11070
  };
11067
11071
  if (model)
11068
11072
  config.model = model;
11073
+ if (fileExcludePaths !== undefined)
11074
+ config.excludePaths = fileExcludePaths;
11069
11075
  const normalized = normalizeIndexingConfig({
11070
11076
  minSync: file.minSync
11071
11077
  });
@@ -11182,6 +11188,8 @@ function buildAgentOptions(config) {
11182
11188
  };
11183
11189
  }
11184
11190
  opts.excludeExactDuplicates = config.excludeExactDuplicates ?? true;
11191
+ if (config.excludePaths !== undefined)
11192
+ opts.excludePaths = config.excludePaths;
11185
11193
  if (config.datasources !== undefined) {
11186
11194
  const { skills, unknown } = buildDatasourceSkills(config.datasources, config.workspacePath);
11187
11195
  if (skills.length > 0)
@@ -11437,6 +11445,8 @@ function writeDefaultConfig(path, partial, opts = {}) {
11437
11445
  full.jikji = partial.jikji ?? {};
11438
11446
  full.dupey = partial.dupey ?? { enabled: true };
11439
11447
  full.excludeExactDuplicates = partial.excludeExactDuplicates ?? true;
11448
+ if (partial.excludePaths !== undefined)
11449
+ full.excludePaths = resolveSearchPaths(partial.excludePaths, workspacePath);
11440
11450
  if (partial.parserOptions)
11441
11451
  full.parserOptions = partial.parserOptions;
11442
11452
  if (partial.p2p !== undefined)
@@ -12234,7 +12244,7 @@ var init_cli = __esm(() => {
12234
12244
  // src/dupey/filter.ts
12235
12245
  import { stat as stat5 } from "node:fs/promises";
12236
12246
  import { resolve as resolve8 } from "node:path";
12237
- async function selectExactDuplicateExclusions(root, scan) {
12247
+ async function selectExactDuplicateExclusions(root, scan, isUnavailable) {
12238
12248
  const byHash = new Map;
12239
12249
  for (const file of scan.files) {
12240
12250
  if (typeof file.content_hash !== "string" || file.content_hash.length === 0)
@@ -12260,11 +12270,12 @@ async function selectExactDuplicateExclusions(root, scan) {
12260
12270
  }
12261
12271
  }));
12262
12272
  ranked.sort((a, b) => b.mtimeMs - a.mtimeMs || a.path.localeCompare(b.path));
12263
- const keeper = ranked[0]?.path;
12273
+ const candidates = isUnavailable === undefined ? ranked : ranked.filter(({ path }) => !isUnavailable(path));
12274
+ const keeper = candidates[0]?.path;
12264
12275
  if (!keeper)
12265
12276
  continue;
12266
12277
  keepers.add(keeper);
12267
- for (const candidate of ranked.slice(1))
12278
+ for (const candidate of candidates.slice(1))
12268
12279
  excluded.add(candidate.path);
12269
12280
  }
12270
12281
  return { excluded, keepers, errors };
@@ -14939,7 +14950,7 @@ var init_minsync = __esm(() => {
14939
14950
  import { randomUUID as randomUUID6 } from "node:crypto";
14940
14951
  import { existsSync as existsSync21, mkdirSync as mkdirSync14, renameSync as renameSync7, rmSync as rmSync4, writeFileSync as writeFileSync13 } from "node:fs";
14941
14952
  import { opendir, readFile as readFile5, stat as stat6 } from "node:fs/promises";
14942
- import { dirname as dirname15, extname as extname6, resolve as resolve11 } from "node:path";
14953
+ import { dirname as dirname15, extname as extname6, resolve as resolve11, sep as sep4 } from "node:path";
14943
14954
  async function syncParsedMirrors(options) {
14944
14955
  const registry = options.registry ?? createDefaultParserRegistry(options.parserOptions);
14945
14956
  const maxSourceBytes = options.maxSourceBytes ?? DEFAULT_MAX_SOURCE_BYTES;
@@ -14978,6 +14989,13 @@ async function syncParsedMirrors(options) {
14978
14989
  sinceCheckpoint = 0;
14979
14990
  };
14980
14991
  for (const entry of current) {
14992
+ if (isPathExcluded(entry.sourcePath, options.userExcludedSourcePaths)) {
14993
+ deleted += removePrevious(options.root, previous, entry.virtualPath);
14994
+ handledPrevious.add(entry.virtualPath);
14995
+ skipped += 1;
14996
+ recordSkip(entry, "user-excluded");
14997
+ continue;
14998
+ }
14981
14999
  if (options.excludeSourcePaths?.has(entry.sourcePath)) {
14982
15000
  deleted += removePrevious(options.root, previous, entry.virtualPath);
14983
15001
  handledPrevious.add(entry.virtualPath);
@@ -15098,7 +15116,7 @@ async function detectMirrorStaleness(options) {
15098
15116
  const previous = loadMirrorIndex(options.root);
15099
15117
  const diagnostics = [];
15100
15118
  for (const entry of current) {
15101
- if (options.excludeSourcePaths?.has(entry.sourcePath))
15119
+ if (options.excludeSourcePaths?.has(entry.sourcePath) || isPathExcluded(entry.sourcePath, options.userExcludedSourcePaths))
15102
15120
  continue;
15103
15121
  if (!registry.getForVirtualPath(entry.virtualPath))
15104
15122
  continue;
@@ -15106,9 +15124,10 @@ async function detectMirrorStaleness(options) {
15106
15124
  if (prev !== undefined && prev.sourceMtimeNs === entry.mtimeNs && prev.sourceSizeBytes === entry.sizeBytes)
15107
15125
  continue;
15108
15126
  const prevSkip = previous.skipped?.[entry.virtualPath];
15109
- if (prevSkip !== undefined && prevSkip.sourceMtimeNs === entry.mtimeNs && prevSkip.sourceSizeBytes === entry.sizeBytes)
15127
+ const honoredSkip = prevSkip?.reason === "user-excluded" ? undefined : prevSkip;
15128
+ if (honoredSkip !== undefined && honoredSkip.sourceMtimeNs === entry.mtimeNs && honoredSkip.sourceSizeBytes === entry.sizeBytes)
15110
15129
  continue;
15111
- const known = prev ?? prevSkip;
15130
+ const known = prev ?? honoredSkip;
15112
15131
  const reason = known === undefined ? "source-added" : known.sourceMtimeNs !== entry.mtimeNs && known.sourceSizeBytes !== entry.sizeBytes ? "mtime-and-size-changed" : known.sourceMtimeNs !== entry.mtimeNs ? "mtime-changed" : "size-changed";
15113
15132
  diagnostics.push({
15114
15133
  code: "stale-index",
@@ -15133,6 +15152,15 @@ function normalizeExtension2(extension) {
15133
15152
  const lower = extension.toLowerCase();
15134
15153
  return lower.startsWith(".") ? lower : `.${lower}`;
15135
15154
  }
15155
+ function isPathExcluded(sourcePath, excluded) {
15156
+ if (excluded === undefined)
15157
+ return false;
15158
+ for (const excludedPath of excluded) {
15159
+ if (sourcePath === excludedPath || sourcePath.startsWith(`${excludedPath}${sep4}`))
15160
+ return true;
15161
+ }
15162
+ return false;
15163
+ }
15136
15164
  async function listCurrentFiles(searchPaths, supportedExtensions) {
15137
15165
  const entries = [];
15138
15166
  for (const sourceRoot of planSourceRoots(searchPaths)) {
@@ -16225,7 +16253,7 @@ var init_model_auth = __esm(() => {
16225
16253
  // src/filesystem/cloud-placeholder.ts
16226
16254
  import { execFile as execFile3 } from "node:child_process";
16227
16255
  import { lstat } from "node:fs/promises";
16228
- import { dirname as dirname17, relative as relative6, sep as sep4 } from "node:path";
16256
+ import { dirname as dirname17, relative as relative6, sep as sep5 } from "node:path";
16229
16257
  import { promisify as promisify2 } from "node:util";
16230
16258
  function pathLooksLikeCloudRoot(target) {
16231
16259
  const normalized = target.replaceAll("\\", "/");
@@ -24922,6 +24950,7 @@ class AutoRAGAgent {
24922
24950
  parserOptions;
24923
24951
  dupeyOptions;
24924
24952
  excludeExactDuplicates;
24953
+ excludePaths;
24925
24954
  baseSystemPromptConfig;
24926
24955
  droppedCallerToolNames;
24927
24956
  searchTimeoutMs;
@@ -24960,6 +24989,7 @@ class AutoRAGAgent {
24960
24989
  this.parserOptions = resolveParserOptions(options.parserOptions, this.languages);
24961
24990
  this.dupeyOptions = options.dupey ?? {};
24962
24991
  this.excludeExactDuplicates = options.excludeExactDuplicates ?? true;
24992
+ this.excludePaths = (options.excludePaths ?? []).map(pinExcludedPath);
24963
24993
  if (options.minSync !== false) {
24964
24994
  const minSyncOpts = options.minSync ?? { autoInstall: true };
24965
24995
  this.minSyncMethod = new MinSyncVectorMethod({
@@ -25894,7 +25924,8 @@ ${initialRetrievalContext ?? "Pending; continue only with a brief progress state
25894
25924
  const staleDiagnostics = await detectMirrorStaleness({
25895
25925
  root: this.workspaceProjectRoot,
25896
25926
  searchPaths: this.searchPaths,
25897
- parserOptions: this.parserOptions
25927
+ parserOptions: this.parserOptions,
25928
+ userExcludedSourcePaths: new Set(this.excludePaths)
25898
25929
  });
25899
25930
  const diagnostics = [
25900
25931
  ...this.startupDiagnostics,
@@ -26017,7 +26048,8 @@ ${initialRetrievalContext ?? "Pending; continue only with a brief progress state
26017
26048
  searchPaths: this.searchPaths,
26018
26049
  force,
26019
26050
  parserOptions: this.parserOptions,
26020
- excludeSourcePaths: duplicateFilter.excluded
26051
+ excludeSourcePaths: duplicateFilter.excluded,
26052
+ userExcludedSourcePaths: new Set(this.excludePaths)
26021
26053
  });
26022
26054
  }
26023
26055
  async scanMirrorStaleness() {
@@ -26026,7 +26058,8 @@ ${initialRetrievalContext ?? "Pending; continue only with a brief progress state
26026
26058
  root: this.workspaceProjectRoot,
26027
26059
  searchPaths: this.searchPaths,
26028
26060
  parserOptions: this.parserOptions,
26029
- excludeSourcePaths: duplicateFilter.excluded
26061
+ excludeSourcePaths: duplicateFilter.excluded,
26062
+ userExcludedSourcePaths: new Set(this.excludePaths)
26030
26063
  });
26031
26064
  return {
26032
26065
  scanned: 0,
@@ -26041,10 +26074,11 @@ ${initialRetrievalContext ?? "Pending; continue only with a brief progress state
26041
26074
  if (!this.excludeExactDuplicates || this.dupeyOptions === false)
26042
26075
  return { excluded: new Set };
26043
26076
  const excluded = new Set;
26077
+ const userExcluded = new Set(this.excludePaths);
26044
26078
  for (const searchPath of this.searchPaths) {
26045
26079
  try {
26046
26080
  const scan = await scanWithDupey(searchPath, this.dupeyOptions || {});
26047
- const selected = await selectExactDuplicateExclusions(searchPath, scan);
26081
+ const selected = await selectExactDuplicateExclusions(searchPath, scan, (path) => isPathExcluded(path, userExcluded));
26048
26082
  for (const path of selected.excluded)
26049
26083
  excluded.add(path);
26050
26084
  } catch (error) {
@@ -26459,6 +26493,14 @@ function toMinSyncReasonDiagnostic(reason) {
26459
26493
  source: "minsync"
26460
26494
  };
26461
26495
  }
26496
+ function pinExcludedPath(path) {
26497
+ const resolvedPath = resolve13(path);
26498
+ try {
26499
+ return join30(realpathSync4(dirname22(resolvedPath)), basename12(resolvedPath));
26500
+ } catch {
26501
+ return resolvedPath;
26502
+ }
26503
+ }
26462
26504
  function pinSearchRoot(searchPath) {
26463
26505
  const resolvedPath = resolve13(searchPath);
26464
26506
  let canonicalPath;
@@ -26948,7 +26990,7 @@ var init_memory2 = __esm(() => {
26948
26990
 
26949
26991
  // src/cli/commands/index.ts
26950
26992
  import { existsSync as existsSync28, lstatSync as lstatSync3, rmSync as rmSync6 } from "node:fs";
26951
- import { join as join31, resolve as resolve14, sep as sep5 } from "node:path";
26993
+ import { join as join31, resolve as resolve14, sep as sep6 } from "node:path";
26952
26994
  async function runIndex(ctx) {
26953
26995
  const sub = ctx.positionals[0];
26954
26996
  if (sub !== "reset" && sub !== "rebuild") {
@@ -27046,7 +27088,7 @@ function resolveResetScope(methods) {
27046
27088
  };
27047
27089
  }
27048
27090
  function isWithin(target, base) {
27049
- const prefix = base.endsWith(sep5) ? base : `${base}${sep5}`;
27091
+ const prefix = base.endsWith(sep6) ? base : `${base}${sep6}`;
27050
27092
  return target === base || target.startsWith(prefix);
27051
27093
  }
27052
27094
  var ALL_RESET_TARGETS, ALL_RESET_TARGET_NAMES;
@@ -28965,7 +29007,8 @@ async function runLiteRetrieve(ctx) {
28965
29007
  const staleDiagnostics = await detectMirrorStaleness({
28966
29008
  root: workspacePath,
28967
29009
  searchPaths: lite.config.searchPaths,
28968
- parserOptions: resolveParserOptions(lite.config.parserOptions, normalizeLanguages(lite.config.languages))
29010
+ parserOptions: resolveParserOptions(lite.config.parserOptions, normalizeLanguages(lite.config.languages)),
29011
+ userExcludedSourcePaths: new Set(lite.config.excludePaths ?? [])
28969
29012
  });
28970
29013
  if (staleDiagnostics.length > 0 && ctx.flags.strict === true) {
28971
29014
  const envelope = {
package/dist/core.js CHANGED
@@ -192,7 +192,7 @@ function isParsedMirrorSkipEntry(value) {
192
192
  return isRecord(value) && typeof value.virtualPath === "string" && typeof value.sourcePath === "string" && isParsedMirrorSkipReason(value.reason) && typeof value.sourceMtimeNs === "number" && typeof value.sourceSizeBytes === "number" && typeof value.updatedAt === "string";
193
193
  }
194
194
  function isParsedMirrorSkipReason(value) {
195
- return value === "duplicate-excluded" || value === "parser-skipped" || value === "parser-failed";
195
+ return value === "duplicate-excluded" || value === "user-excluded" || value === "parser-skipped" || value === "parser-failed";
196
196
  }
197
197
  function isParsedMirrorEntry(value) {
198
198
  return isRecord(value) && typeof value.virtualPath === "string" && typeof value.sourcePath === "string" && typeof value.outputPath === "string" && typeof value.parserName === "string" && typeof value.sourceMtimeNs === "number" && typeof value.sourceSizeBytes === "number" && typeof value.updatedAt === "string";
@@ -548,7 +548,7 @@ var init_cli = __esm(() => {
548
548
  // src/dupey/filter.ts
549
549
  import { stat } from "node:fs/promises";
550
550
  import { resolve as resolve5 } from "node:path";
551
- async function selectExactDuplicateExclusions(root, scan) {
551
+ async function selectExactDuplicateExclusions(root, scan, isUnavailable) {
552
552
  const byHash = new Map;
553
553
  for (const file of scan.files) {
554
554
  if (typeof file.content_hash !== "string" || file.content_hash.length === 0)
@@ -574,11 +574,12 @@ async function selectExactDuplicateExclusions(root, scan) {
574
574
  }
575
575
  }));
576
576
  ranked.sort((a, b) => b.mtimeMs - a.mtimeMs || a.path.localeCompare(b.path));
577
- const keeper = ranked[0]?.path;
577
+ const candidates = isUnavailable === undefined ? ranked : ranked.filter(({ path }) => !isUnavailable(path));
578
+ const keeper = candidates[0]?.path;
578
579
  if (!keeper)
579
580
  continue;
580
581
  keepers.add(keeper);
581
- for (const candidate of ranked.slice(1))
582
+ for (const candidate of candidates.slice(1))
582
583
  excluded.add(candidate.path);
583
584
  }
584
585
  return { excluded, keepers, errors };
@@ -5475,7 +5476,7 @@ var init_defaults = __esm(() => {
5475
5476
  import { randomUUID as randomUUID5 } from "node:crypto";
5476
5477
  import { existsSync as existsSync12, mkdirSync as mkdirSync6, renameSync as renameSync5, rmSync as rmSync3, writeFileSync as writeFileSync6 } from "node:fs";
5477
5478
  import { opendir, readFile as readFile3, stat as stat4 } from "node:fs/promises";
5478
- import { dirname as dirname7, extname as extname4, resolve as resolve9 } from "node:path";
5479
+ import { dirname as dirname7, extname as extname4, resolve as resolve9, sep as sep4 } from "node:path";
5479
5480
  async function syncParsedMirrors(options) {
5480
5481
  const registry = options.registry ?? createDefaultParserRegistry(options.parserOptions);
5481
5482
  const maxSourceBytes = options.maxSourceBytes ?? DEFAULT_MAX_SOURCE_BYTES;
@@ -5514,6 +5515,13 @@ async function syncParsedMirrors(options) {
5514
5515
  sinceCheckpoint = 0;
5515
5516
  };
5516
5517
  for (const entry of current) {
5518
+ if (isPathExcluded(entry.sourcePath, options.userExcludedSourcePaths)) {
5519
+ deleted += removePrevious(options.root, previous, entry.virtualPath);
5520
+ handledPrevious.add(entry.virtualPath);
5521
+ skipped += 1;
5522
+ recordSkip(entry, "user-excluded");
5523
+ continue;
5524
+ }
5517
5525
  if (options.excludeSourcePaths?.has(entry.sourcePath)) {
5518
5526
  deleted += removePrevious(options.root, previous, entry.virtualPath);
5519
5527
  handledPrevious.add(entry.virtualPath);
@@ -5634,7 +5642,7 @@ async function detectMirrorStaleness(options) {
5634
5642
  const previous = loadMirrorIndex(options.root);
5635
5643
  const diagnostics = [];
5636
5644
  for (const entry of current) {
5637
- if (options.excludeSourcePaths?.has(entry.sourcePath))
5645
+ if (options.excludeSourcePaths?.has(entry.sourcePath) || isPathExcluded(entry.sourcePath, options.userExcludedSourcePaths))
5638
5646
  continue;
5639
5647
  if (!registry.getForVirtualPath(entry.virtualPath))
5640
5648
  continue;
@@ -5642,9 +5650,10 @@ async function detectMirrorStaleness(options) {
5642
5650
  if (prev !== undefined && prev.sourceMtimeNs === entry.mtimeNs && prev.sourceSizeBytes === entry.sizeBytes)
5643
5651
  continue;
5644
5652
  const prevSkip = previous.skipped?.[entry.virtualPath];
5645
- if (prevSkip !== undefined && prevSkip.sourceMtimeNs === entry.mtimeNs && prevSkip.sourceSizeBytes === entry.sizeBytes)
5653
+ const honoredSkip = prevSkip?.reason === "user-excluded" ? undefined : prevSkip;
5654
+ if (honoredSkip !== undefined && honoredSkip.sourceMtimeNs === entry.mtimeNs && honoredSkip.sourceSizeBytes === entry.sizeBytes)
5646
5655
  continue;
5647
- const known = prev ?? prevSkip;
5656
+ const known = prev ?? honoredSkip;
5648
5657
  const reason = known === undefined ? "source-added" : known.sourceMtimeNs !== entry.mtimeNs && known.sourceSizeBytes !== entry.sizeBytes ? "mtime-and-size-changed" : known.sourceMtimeNs !== entry.mtimeNs ? "mtime-changed" : "size-changed";
5649
5658
  diagnostics.push({
5650
5659
  code: "stale-index",
@@ -5669,6 +5678,15 @@ function normalizeExtension2(extension) {
5669
5678
  const lower = extension.toLowerCase();
5670
5679
  return lower.startsWith(".") ? lower : `.${lower}`;
5671
5680
  }
5681
+ function isPathExcluded(sourcePath, excluded) {
5682
+ if (excluded === undefined)
5683
+ return false;
5684
+ for (const excludedPath of excluded) {
5685
+ if (sourcePath === excludedPath || sourcePath.startsWith(`${excludedPath}${sep4}`))
5686
+ return true;
5687
+ }
5688
+ return false;
5689
+ }
5672
5690
  async function listCurrentFiles(searchPaths, supportedExtensions) {
5673
5691
  const entries = [];
5674
5692
  for (const sourceRoot of planSourceRoots(searchPaths)) {
@@ -6802,7 +6820,7 @@ var init_model_auth = __esm(() => {
6802
6820
  // src/filesystem/cloud-placeholder.ts
6803
6821
  import { execFile as execFile2 } from "node:child_process";
6804
6822
  import { lstat } from "node:fs/promises";
6805
- import { dirname as dirname9, relative as relative6, sep as sep4 } from "node:path";
6823
+ import { dirname as dirname9, relative as relative6, sep as sep5 } from "node:path";
6806
6824
  import { promisify as promisify2 } from "node:util";
6807
6825
  function pathLooksLikeCloudRoot(target) {
6808
6826
  const normalized = target.replaceAll("\\", "/");
@@ -15653,6 +15671,7 @@ class AutoRAGAgent {
15653
15671
  parserOptions;
15654
15672
  dupeyOptions;
15655
15673
  excludeExactDuplicates;
15674
+ excludePaths;
15656
15675
  baseSystemPromptConfig;
15657
15676
  droppedCallerToolNames;
15658
15677
  searchTimeoutMs;
@@ -15691,6 +15710,7 @@ class AutoRAGAgent {
15691
15710
  this.parserOptions = resolveParserOptions(options.parserOptions, this.languages);
15692
15711
  this.dupeyOptions = options.dupey ?? {};
15693
15712
  this.excludeExactDuplicates = options.excludeExactDuplicates ?? true;
15713
+ this.excludePaths = (options.excludePaths ?? []).map(pinExcludedPath);
15694
15714
  if (options.minSync !== false) {
15695
15715
  const minSyncOpts = options.minSync ?? { autoInstall: true };
15696
15716
  this.minSyncMethod = new MinSyncVectorMethod({
@@ -16625,7 +16645,8 @@ ${initialRetrievalContext ?? "Pending; continue only with a brief progress state
16625
16645
  const staleDiagnostics = await detectMirrorStaleness({
16626
16646
  root: this.workspaceProjectRoot,
16627
16647
  searchPaths: this.searchPaths,
16628
- parserOptions: this.parserOptions
16648
+ parserOptions: this.parserOptions,
16649
+ userExcludedSourcePaths: new Set(this.excludePaths)
16629
16650
  });
16630
16651
  const diagnostics = [
16631
16652
  ...this.startupDiagnostics,
@@ -16748,7 +16769,8 @@ ${initialRetrievalContext ?? "Pending; continue only with a brief progress state
16748
16769
  searchPaths: this.searchPaths,
16749
16770
  force,
16750
16771
  parserOptions: this.parserOptions,
16751
- excludeSourcePaths: duplicateFilter.excluded
16772
+ excludeSourcePaths: duplicateFilter.excluded,
16773
+ userExcludedSourcePaths: new Set(this.excludePaths)
16752
16774
  });
16753
16775
  }
16754
16776
  async scanMirrorStaleness() {
@@ -16757,7 +16779,8 @@ ${initialRetrievalContext ?? "Pending; continue only with a brief progress state
16757
16779
  root: this.workspaceProjectRoot,
16758
16780
  searchPaths: this.searchPaths,
16759
16781
  parserOptions: this.parserOptions,
16760
- excludeSourcePaths: duplicateFilter.excluded
16782
+ excludeSourcePaths: duplicateFilter.excluded,
16783
+ userExcludedSourcePaths: new Set(this.excludePaths)
16761
16784
  });
16762
16785
  return {
16763
16786
  scanned: 0,
@@ -16772,10 +16795,11 @@ ${initialRetrievalContext ?? "Pending; continue only with a brief progress state
16772
16795
  if (!this.excludeExactDuplicates || this.dupeyOptions === false)
16773
16796
  return { excluded: new Set };
16774
16797
  const excluded = new Set;
16798
+ const userExcluded = new Set(this.excludePaths);
16775
16799
  for (const searchPath of this.searchPaths) {
16776
16800
  try {
16777
16801
  const scan = await scanWithDupey(searchPath, this.dupeyOptions || {});
16778
- const selected = await selectExactDuplicateExclusions(searchPath, scan);
16802
+ const selected = await selectExactDuplicateExclusions(searchPath, scan, (path) => isPathExcluded(path, userExcluded));
16779
16803
  for (const path of selected.excluded)
16780
16804
  excluded.add(path);
16781
16805
  } catch (error) {
@@ -17190,6 +17214,14 @@ function toMinSyncReasonDiagnostic(reason) {
17190
17214
  source: "minsync"
17191
17215
  };
17192
17216
  }
17217
+ function pinExcludedPath(path) {
17218
+ const resolvedPath = resolve11(path);
17219
+ try {
17220
+ return join22(realpathSync4(dirname14(resolvedPath)), basename9(resolvedPath));
17221
+ } catch {
17222
+ return resolvedPath;
17223
+ }
17224
+ }
17193
17225
  function pinSearchRoot(searchPath) {
17194
17226
  const resolvedPath = resolve11(searchPath);
17195
17227
  let canonicalPath;
@@ -25283,6 +25315,10 @@ function resolveConfig(input) {
25283
25315
  const configOrigin = dirname21(resolve13(configPath));
25284
25316
  const fileWorkspacePath = typeof file.workspacePath === "string" ? resolvePersistedPath(file.workspacePath, configOrigin) : undefined;
25285
25317
  const fileSearchPaths = file.searchPaths ? resolveSearchPaths(file.searchPaths, fileWorkspacePath ?? configOrigin) : undefined;
25318
+ if (file.excludePaths !== undefined && (!Array.isArray(file.excludePaths) || file.excludePaths.some((path) => typeof path !== "string" || path.length === 0))) {
25319
+ throw new ConfigError("Config field 'excludePaths' must be a non-empty string array");
25320
+ }
25321
+ const fileExcludePaths = file.excludePaths ? resolveSearchPaths(file.excludePaths, fileWorkspacePath ?? configOrigin) : undefined;
25286
25322
  const searchPaths = flagSearchPaths ?? envSearchPaths ?? fileSearchPaths ?? defaultSearchPaths;
25287
25323
  const flagWorkspacePath = flagString(flags, "workspace");
25288
25324
  const envWorkspacePath = envString(env, "AUTORAG_WORKSPACE");
@@ -25306,6 +25342,8 @@ function resolveConfig(input) {
25306
25342
  };
25307
25343
  if (model)
25308
25344
  config.model = model;
25345
+ if (fileExcludePaths !== undefined)
25346
+ config.excludePaths = fileExcludePaths;
25309
25347
  const normalized = normalizeIndexingConfig({
25310
25348
  minSync: file.minSync
25311
25349
  });
@@ -25422,6 +25460,8 @@ function buildAgentOptions(config) {
25422
25460
  };
25423
25461
  }
25424
25462
  opts.excludeExactDuplicates = config.excludeExactDuplicates ?? true;
25463
+ if (config.excludePaths !== undefined)
25464
+ opts.excludePaths = config.excludePaths;
25425
25465
  if (config.datasources !== undefined) {
25426
25466
  const { skills, unknown } = buildDatasourceSkills(config.datasources, config.workspacePath);
25427
25467
  if (skills.length > 0)
@@ -25677,6 +25717,8 @@ function writeDefaultConfig(path, partial, opts = {}) {
25677
25717
  full.jikji = partial.jikji ?? {};
25678
25718
  full.dupey = partial.dupey ?? { enabled: true };
25679
25719
  full.excludeExactDuplicates = partial.excludeExactDuplicates ?? true;
25720
+ if (partial.excludePaths !== undefined)
25721
+ full.excludePaths = resolveSearchPaths(partial.excludePaths, workspacePath);
25680
25722
  if (partial.parserOptions)
25681
25723
  full.parserOptions = partial.parserOptions;
25682
25724
  if (partial.p2p !== undefined)
@@ -5,4 +5,4 @@ export interface ExactDuplicateFilterResult {
5
5
  readonly errors: readonly string[];
6
6
  }
7
7
  /** Selects the newest filesystem copy for each exact canonical-text hash. */
8
- export declare function selectExactDuplicateExclusions(root: string, scan: DupeyScanResult): Promise<ExactDuplicateFilterResult>;
8
+ export declare function selectExactDuplicateExclusions(root: string, scan: DupeyScanResult, isUnavailable?: (path: string) => boolean): Promise<ExactDuplicateFilterResult>;
package/dist/index.js CHANGED
@@ -192,7 +192,7 @@ function isParsedMirrorSkipEntry(value) {
192
192
  return isRecord(value) && typeof value.virtualPath === "string" && typeof value.sourcePath === "string" && isParsedMirrorSkipReason(value.reason) && typeof value.sourceMtimeNs === "number" && typeof value.sourceSizeBytes === "number" && typeof value.updatedAt === "string";
193
193
  }
194
194
  function isParsedMirrorSkipReason(value) {
195
- return value === "duplicate-excluded" || value === "parser-skipped" || value === "parser-failed";
195
+ return value === "duplicate-excluded" || value === "user-excluded" || value === "parser-skipped" || value === "parser-failed";
196
196
  }
197
197
  function isParsedMirrorEntry(value) {
198
198
  return isRecord(value) && typeof value.virtualPath === "string" && typeof value.sourcePath === "string" && typeof value.outputPath === "string" && typeof value.parserName === "string" && typeof value.sourceMtimeNs === "number" && typeof value.sourceSizeBytes === "number" && typeof value.updatedAt === "string";
@@ -548,7 +548,7 @@ var init_cli = __esm(() => {
548
548
  // src/dupey/filter.ts
549
549
  import { stat } from "node:fs/promises";
550
550
  import { resolve as resolve5 } from "node:path";
551
- async function selectExactDuplicateExclusions(root, scan) {
551
+ async function selectExactDuplicateExclusions(root, scan, isUnavailable) {
552
552
  const byHash = new Map;
553
553
  for (const file of scan.files) {
554
554
  if (typeof file.content_hash !== "string" || file.content_hash.length === 0)
@@ -574,11 +574,12 @@ async function selectExactDuplicateExclusions(root, scan) {
574
574
  }
575
575
  }));
576
576
  ranked.sort((a, b) => b.mtimeMs - a.mtimeMs || a.path.localeCompare(b.path));
577
- const keeper = ranked[0]?.path;
577
+ const candidates = isUnavailable === undefined ? ranked : ranked.filter(({ path }) => !isUnavailable(path));
578
+ const keeper = candidates[0]?.path;
578
579
  if (!keeper)
579
580
  continue;
580
581
  keepers.add(keeper);
581
- for (const candidate of ranked.slice(1))
582
+ for (const candidate of candidates.slice(1))
582
583
  excluded.add(candidate.path);
583
584
  }
584
585
  return { excluded, keepers, errors };
@@ -5475,7 +5476,7 @@ var init_defaults = __esm(() => {
5475
5476
  import { randomUUID as randomUUID5 } from "node:crypto";
5476
5477
  import { existsSync as existsSync12, mkdirSync as mkdirSync6, renameSync as renameSync5, rmSync as rmSync3, writeFileSync as writeFileSync6 } from "node:fs";
5477
5478
  import { opendir, readFile as readFile3, stat as stat4 } from "node:fs/promises";
5478
- import { dirname as dirname7, extname as extname4, resolve as resolve9 } from "node:path";
5479
+ import { dirname as dirname7, extname as extname4, resolve as resolve9, sep as sep4 } from "node:path";
5479
5480
  async function syncParsedMirrors(options) {
5480
5481
  const registry = options.registry ?? createDefaultParserRegistry(options.parserOptions);
5481
5482
  const maxSourceBytes = options.maxSourceBytes ?? DEFAULT_MAX_SOURCE_BYTES;
@@ -5514,6 +5515,13 @@ async function syncParsedMirrors(options) {
5514
5515
  sinceCheckpoint = 0;
5515
5516
  };
5516
5517
  for (const entry of current) {
5518
+ if (isPathExcluded(entry.sourcePath, options.userExcludedSourcePaths)) {
5519
+ deleted += removePrevious(options.root, previous, entry.virtualPath);
5520
+ handledPrevious.add(entry.virtualPath);
5521
+ skipped += 1;
5522
+ recordSkip(entry, "user-excluded");
5523
+ continue;
5524
+ }
5517
5525
  if (options.excludeSourcePaths?.has(entry.sourcePath)) {
5518
5526
  deleted += removePrevious(options.root, previous, entry.virtualPath);
5519
5527
  handledPrevious.add(entry.virtualPath);
@@ -5634,7 +5642,7 @@ async function detectMirrorStaleness(options) {
5634
5642
  const previous = loadMirrorIndex(options.root);
5635
5643
  const diagnostics = [];
5636
5644
  for (const entry of current) {
5637
- if (options.excludeSourcePaths?.has(entry.sourcePath))
5645
+ if (options.excludeSourcePaths?.has(entry.sourcePath) || isPathExcluded(entry.sourcePath, options.userExcludedSourcePaths))
5638
5646
  continue;
5639
5647
  if (!registry.getForVirtualPath(entry.virtualPath))
5640
5648
  continue;
@@ -5642,9 +5650,10 @@ async function detectMirrorStaleness(options) {
5642
5650
  if (prev !== undefined && prev.sourceMtimeNs === entry.mtimeNs && prev.sourceSizeBytes === entry.sizeBytes)
5643
5651
  continue;
5644
5652
  const prevSkip = previous.skipped?.[entry.virtualPath];
5645
- if (prevSkip !== undefined && prevSkip.sourceMtimeNs === entry.mtimeNs && prevSkip.sourceSizeBytes === entry.sizeBytes)
5653
+ const honoredSkip = prevSkip?.reason === "user-excluded" ? undefined : prevSkip;
5654
+ if (honoredSkip !== undefined && honoredSkip.sourceMtimeNs === entry.mtimeNs && honoredSkip.sourceSizeBytes === entry.sizeBytes)
5646
5655
  continue;
5647
- const known = prev ?? prevSkip;
5656
+ const known = prev ?? honoredSkip;
5648
5657
  const reason = known === undefined ? "source-added" : known.sourceMtimeNs !== entry.mtimeNs && known.sourceSizeBytes !== entry.sizeBytes ? "mtime-and-size-changed" : known.sourceMtimeNs !== entry.mtimeNs ? "mtime-changed" : "size-changed";
5649
5658
  diagnostics.push({
5650
5659
  code: "stale-index",
@@ -5669,6 +5678,15 @@ function normalizeExtension2(extension) {
5669
5678
  const lower = extension.toLowerCase();
5670
5679
  return lower.startsWith(".") ? lower : `.${lower}`;
5671
5680
  }
5681
+ function isPathExcluded(sourcePath, excluded) {
5682
+ if (excluded === undefined)
5683
+ return false;
5684
+ for (const excludedPath of excluded) {
5685
+ if (sourcePath === excludedPath || sourcePath.startsWith(`${excludedPath}${sep4}`))
5686
+ return true;
5687
+ }
5688
+ return false;
5689
+ }
5672
5690
  async function listCurrentFiles(searchPaths, supportedExtensions) {
5673
5691
  const entries = [];
5674
5692
  for (const sourceRoot of planSourceRoots(searchPaths)) {
@@ -6802,7 +6820,7 @@ var init_model_auth = __esm(() => {
6802
6820
  // src/filesystem/cloud-placeholder.ts
6803
6821
  import { execFile as execFile2 } from "node:child_process";
6804
6822
  import { lstat } from "node:fs/promises";
6805
- import { dirname as dirname9, relative as relative6, sep as sep4 } from "node:path";
6823
+ import { dirname as dirname9, relative as relative6, sep as sep5 } from "node:path";
6806
6824
  import { promisify as promisify2 } from "node:util";
6807
6825
  function pathLooksLikeCloudRoot(target) {
6808
6826
  const normalized = target.replaceAll("\\", "/");
@@ -15653,6 +15671,7 @@ class AutoRAGAgent {
15653
15671
  parserOptions;
15654
15672
  dupeyOptions;
15655
15673
  excludeExactDuplicates;
15674
+ excludePaths;
15656
15675
  baseSystemPromptConfig;
15657
15676
  droppedCallerToolNames;
15658
15677
  searchTimeoutMs;
@@ -15691,6 +15710,7 @@ class AutoRAGAgent {
15691
15710
  this.parserOptions = resolveParserOptions(options.parserOptions, this.languages);
15692
15711
  this.dupeyOptions = options.dupey ?? {};
15693
15712
  this.excludeExactDuplicates = options.excludeExactDuplicates ?? true;
15713
+ this.excludePaths = (options.excludePaths ?? []).map(pinExcludedPath);
15694
15714
  if (options.minSync !== false) {
15695
15715
  const minSyncOpts = options.minSync ?? { autoInstall: true };
15696
15716
  this.minSyncMethod = new MinSyncVectorMethod({
@@ -16625,7 +16645,8 @@ ${initialRetrievalContext ?? "Pending; continue only with a brief progress state
16625
16645
  const staleDiagnostics = await detectMirrorStaleness({
16626
16646
  root: this.workspaceProjectRoot,
16627
16647
  searchPaths: this.searchPaths,
16628
- parserOptions: this.parserOptions
16648
+ parserOptions: this.parserOptions,
16649
+ userExcludedSourcePaths: new Set(this.excludePaths)
16629
16650
  });
16630
16651
  const diagnostics = [
16631
16652
  ...this.startupDiagnostics,
@@ -16748,7 +16769,8 @@ ${initialRetrievalContext ?? "Pending; continue only with a brief progress state
16748
16769
  searchPaths: this.searchPaths,
16749
16770
  force,
16750
16771
  parserOptions: this.parserOptions,
16751
- excludeSourcePaths: duplicateFilter.excluded
16772
+ excludeSourcePaths: duplicateFilter.excluded,
16773
+ userExcludedSourcePaths: new Set(this.excludePaths)
16752
16774
  });
16753
16775
  }
16754
16776
  async scanMirrorStaleness() {
@@ -16757,7 +16779,8 @@ ${initialRetrievalContext ?? "Pending; continue only with a brief progress state
16757
16779
  root: this.workspaceProjectRoot,
16758
16780
  searchPaths: this.searchPaths,
16759
16781
  parserOptions: this.parserOptions,
16760
- excludeSourcePaths: duplicateFilter.excluded
16782
+ excludeSourcePaths: duplicateFilter.excluded,
16783
+ userExcludedSourcePaths: new Set(this.excludePaths)
16761
16784
  });
16762
16785
  return {
16763
16786
  scanned: 0,
@@ -16772,10 +16795,11 @@ ${initialRetrievalContext ?? "Pending; continue only with a brief progress state
16772
16795
  if (!this.excludeExactDuplicates || this.dupeyOptions === false)
16773
16796
  return { excluded: new Set };
16774
16797
  const excluded = new Set;
16798
+ const userExcluded = new Set(this.excludePaths);
16775
16799
  for (const searchPath of this.searchPaths) {
16776
16800
  try {
16777
16801
  const scan = await scanWithDupey(searchPath, this.dupeyOptions || {});
16778
- const selected = await selectExactDuplicateExclusions(searchPath, scan);
16802
+ const selected = await selectExactDuplicateExclusions(searchPath, scan, (path) => isPathExcluded(path, userExcluded));
16779
16803
  for (const path of selected.excluded)
16780
16804
  excluded.add(path);
16781
16805
  } catch (error) {
@@ -17190,6 +17214,14 @@ function toMinSyncReasonDiagnostic(reason) {
17190
17214
  source: "minsync"
17191
17215
  };
17192
17216
  }
17217
+ function pinExcludedPath(path) {
17218
+ const resolvedPath = resolve11(path);
17219
+ try {
17220
+ return join22(realpathSync4(dirname14(resolvedPath)), basename9(resolvedPath));
17221
+ } catch {
17222
+ return resolvedPath;
17223
+ }
17224
+ }
17193
17225
  function pinSearchRoot(searchPath) {
17194
17226
  const resolvedPath = resolve11(searchPath);
17195
17227
  let canonicalPath;
@@ -25283,6 +25315,10 @@ function resolveConfig(input) {
25283
25315
  const configOrigin = dirname21(resolve13(configPath));
25284
25316
  const fileWorkspacePath = typeof file.workspacePath === "string" ? resolvePersistedPath(file.workspacePath, configOrigin) : undefined;
25285
25317
  const fileSearchPaths = file.searchPaths ? resolveSearchPaths(file.searchPaths, fileWorkspacePath ?? configOrigin) : undefined;
25318
+ if (file.excludePaths !== undefined && (!Array.isArray(file.excludePaths) || file.excludePaths.some((path) => typeof path !== "string" || path.length === 0))) {
25319
+ throw new ConfigError("Config field 'excludePaths' must be a non-empty string array");
25320
+ }
25321
+ const fileExcludePaths = file.excludePaths ? resolveSearchPaths(file.excludePaths, fileWorkspacePath ?? configOrigin) : undefined;
25286
25322
  const searchPaths = flagSearchPaths ?? envSearchPaths ?? fileSearchPaths ?? defaultSearchPaths;
25287
25323
  const flagWorkspacePath = flagString(flags, "workspace");
25288
25324
  const envWorkspacePath = envString(env, "AUTORAG_WORKSPACE");
@@ -25306,6 +25342,8 @@ function resolveConfig(input) {
25306
25342
  };
25307
25343
  if (model)
25308
25344
  config.model = model;
25345
+ if (fileExcludePaths !== undefined)
25346
+ config.excludePaths = fileExcludePaths;
25309
25347
  const normalized = normalizeIndexingConfig({
25310
25348
  minSync: file.minSync
25311
25349
  });
@@ -25422,6 +25460,8 @@ function buildAgentOptions(config) {
25422
25460
  };
25423
25461
  }
25424
25462
  opts.excludeExactDuplicates = config.excludeExactDuplicates ?? true;
25463
+ if (config.excludePaths !== undefined)
25464
+ opts.excludePaths = config.excludePaths;
25425
25465
  if (config.datasources !== undefined) {
25426
25466
  const { skills, unknown } = buildDatasourceSkills(config.datasources, config.workspacePath);
25427
25467
  if (skills.length > 0)
@@ -25677,6 +25717,8 @@ function writeDefaultConfig(path, partial, opts = {}) {
25677
25717
  full.jikji = partial.jikji ?? {};
25678
25718
  full.dupey = partial.dupey ?? { enabled: true };
25679
25719
  full.excludeExactDuplicates = partial.excludeExactDuplicates ?? true;
25720
+ if (partial.excludePaths !== undefined)
25721
+ full.excludePaths = resolveSearchPaths(partial.excludePaths, workspacePath);
25680
25722
  if (partial.parserOptions)
25681
25723
  full.parserOptions = partial.parserOptions;
25682
25724
  if (partial.p2p !== undefined)
@@ -26211,6 +26253,7 @@ export {
26211
26253
  groupUnsearchedSurfaces,
26212
26254
  isDatasourceSource,
26213
26255
  isDue,
26256
+ isPathExcluded,
26214
26257
  jikjiExecutableName,
26215
26258
  jikjiFindDiagnostic,
26216
26259
  jikjiPrepareDiagnostic,
@@ -8,7 +8,7 @@ export interface ParsedMirrorEntry {
8
8
  readonly updatedAt: string;
9
9
  }
10
10
  /** Why refresh deliberately left a source out of the parsed mirror. */
11
- export type ParsedMirrorSkipReason = "duplicate-excluded" | "parser-skipped" | "parser-failed";
11
+ export type ParsedMirrorSkipReason = "duplicate-excluded" | "user-excluded" | "parser-skipped" | "parser-failed";
12
12
  /**
13
13
  * A source the last refresh decided not to mirror, pinned to the exact version it
14
14
  * decided on. Staleness checks compare against this record instead of re-deriving
@@ -2,4 +2,4 @@ export type { ParsedMirrorEntry, ParsedMirrorIndex } from "./index-store.js";
2
2
  export { emptyMirrorIndex, loadMirrorIndex, saveMirrorIndex } from "./index-store.js";
3
3
  export { parsedMirrorIndexPath, parsedMirrorRoot, parsedOutputPath, refreshReadinessPath } from "./paths.js";
4
4
  export type { ParsedMirrorDiagnostic, ParsedMirrorDiagnosticCode, ParsedMirrorSyncOptions, ParsedMirrorSyncResult, } from "./sync.js";
5
- export { DEFAULT_MAX_SOURCE_BYTES, detectMirrorStaleness, syncParsedMirrors } from "./sync.js";
5
+ export { DEFAULT_MAX_SOURCE_BYTES, detectMirrorStaleness, isPathExcluded, syncParsedMirrors } from "./sync.js";
@@ -12,6 +12,8 @@ export interface ParsedMirrorSyncOptions {
12
12
  readonly maxSourceBytes?: number;
13
13
  /** Absolute source paths omitted from parsed mirrors (for example exact duplicate copies). */
14
14
  readonly excludeSourcePaths?: ReadonlySet<string>;
15
+ /** Absolute source paths or directories omitted by the user. */
16
+ readonly userExcludedSourcePaths?: ReadonlySet<string>;
15
17
  }
16
18
  export type ParsedMirrorDiagnosticCode = "unsupported-file" | "parser-skipped" | "parser-failed" | "duplicate-excluded" | "deleted-mirror" | "stale-index" | "pdf-extract-thin" | "parser-warning";
17
19
  /** Path-opaque refresh diagnostic. `source` is an opaque virtual path, never a real fs path. */
@@ -42,3 +44,4 @@ export declare function syncParsedMirrors(options: ParsedMirrorSyncOptions): Pro
42
44
  * getRefreshStatus).
43
45
  */
44
46
  export declare function detectMirrorStaleness(options: ParsedMirrorSyncOptions): Promise<ParsedMirrorDiagnostic[]>;
47
+ export declare function isPathExcluded(sourcePath: string, excluded: ReadonlySet<string> | undefined): boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@autorag/librarian",
3
- "version": "2.6.1",
3
+ "version": "2.6.2",
4
4
  "description": "Self-evolving librarian agent on Pi framework with pluggable retrieval methods",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -41,6 +41,14 @@ near/contains families require human review. Exact duplicate exclusion during
41
41
  refresh is enabled by default and can be disabled with
42
42
  `"excludeExactDuplicates": false` in `config.json`.
43
43
 
44
+ ### Excluding local files from the index
45
+
46
+ `"excludePaths"` in `config.json` lists files or folders (absolute, or relative
47
+ to `workspacePath`) that refresh keeps out of the parsed mirror and MinSync.
48
+ A folder entry excludes everything under it. Removing an entry and running
49
+ `autorag refresh --method minsync` indexes the file again. Excluded sources are
50
+ recorded as `user-excluded` skips, so they are not reported as stale.
51
+
44
52
  `status` is model-free and path-opaque. `health` resolves the single model,
45
53
  checks credential presence, and normally probes one live completion. If the
46
54
  model, authentication, configuration, or indexes are unhealthy, use