@autorag/librarian 2.5.0 → 2.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/core.js CHANGED
@@ -66,8 +66,6 @@ function normalizeVirtualPath(virtual) {
66
66
  return;
67
67
  if (URL_SCHEME_RE.test(v))
68
68
  return;
69
- if (v.includes("#") || v.includes("?"))
70
- return;
71
69
  if (v.includes("\x00"))
72
70
  return;
73
71
  if (!v.startsWith("/"))
@@ -164,8 +162,21 @@ function saveMirrorIndex(root, index) {
164
162
  function isParsedMirrorIndex(value) {
165
163
  if (!isRecord(value) || value.version !== 1 || !isRecord(value.entries))
166
164
  return false;
165
+ if (value.skipped !== undefined && !isParsedMirrorSkipRecord(value.skipped))
166
+ return false;
167
167
  return Object.entries(value.entries).every(([key, entry]) => isParsedMirrorEntry(entry) && key === entry.virtualPath);
168
168
  }
169
+ function isParsedMirrorSkipRecord(value) {
170
+ if (!isRecord(value))
171
+ return false;
172
+ return Object.entries(value).every(([key, entry]) => isParsedMirrorSkipEntry(entry) && key === entry.virtualPath);
173
+ }
174
+ function isParsedMirrorSkipEntry(value) {
175
+ 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";
176
+ }
177
+ function isParsedMirrorSkipReason(value) {
178
+ return value === "duplicate-excluded" || value === "parser-skipped" || value === "parser-failed";
179
+ }
169
180
  function isParsedMirrorEntry(value) {
170
181
  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";
171
182
  }
@@ -2531,6 +2542,11 @@ function rewriteEmbedderConfig(workspacePath, embedder, chunkerConfig = {}) {
2531
2542
  parsed.chunker = chunker;
2532
2543
  const chunkerOptions = typeof chunker.options === "object" && chunker.options !== null && !Array.isArray(chunker.options) ? chunker.options : {};
2533
2544
  chunker.options = chunkerOptions;
2545
+ if (embedder.id?.startsWith("native:")) {
2546
+ delete embedderSection.base_url;
2547
+ delete embedderSection.query_prefix;
2548
+ delete embedderSection.passage_prefix;
2549
+ }
2534
2550
  if (embedder.id !== undefined)
2535
2551
  embedderSection.id = embedder.id;
2536
2552
  if (embedder.baseUrl !== undefined)
@@ -2555,8 +2571,13 @@ function rewriteEmbedderConfig(workspacePath, embedder, chunkerConfig = {}) {
2555
2571
  writeFileSync3(configPath, stringify(parsed));
2556
2572
  return true;
2557
2573
  }
2558
- var EMBEDDING_IDENTITY_FILE = "autorag-embedding-identity.json", MINSYNC_CONFIG_DIR = ".minsync", MINSYNC_CONFIG_FILE = "config.toml";
2559
- var init_embedder_config = () => {};
2574
+ var EMBEDDING_IDENTITY_FILE = "autorag-embedding-identity.json", DEFAULT_MINSYNC_EMBEDDER_ID = "native:Qwen/Qwen3-Embedding-0.6B", DEFAULT_MINSYNC_EMBEDDER_DIMENSION = 1024, DEFAULT_MINSYNC_EMBEDDER_CONFIG, MINSYNC_CONFIG_DIR = ".minsync", MINSYNC_CONFIG_FILE = "config.toml";
2575
+ var init_embedder_config = __esm(() => {
2576
+ DEFAULT_MINSYNC_EMBEDDER_CONFIG = {
2577
+ id: DEFAULT_MINSYNC_EMBEDDER_ID,
2578
+ dimension: DEFAULT_MINSYNC_EMBEDDER_DIMENSION
2579
+ };
2580
+ });
2560
2581
 
2561
2582
  // src/minsync/local-embedder.ts
2562
2583
  import { spawn as spawn4 } from "node:child_process";
@@ -2697,9 +2718,32 @@ class MinSyncClient {
2697
2718
  }
2698
2719
  async effectiveEmbedder() {
2699
2720
  const configured = this.embedder;
2700
- const useRuntime = this.runtime !== undefined && (configured === undefined || configured.profile !== undefined && configured.baseUrl === undefined);
2701
- if (!useRuntime)
2721
+ const isExplicitNative = configured?.id?.startsWith("native:");
2722
+ const isExplicitRemoteOrTei = configured?.baseUrl !== undefined || configured?.id !== undefined && !isExplicitNative && configured.profile === undefined;
2723
+ const useRuntime = this.runtime !== undefined && !isExplicitNative && !isExplicitRemoteOrTei && (configured?.profile !== undefined || configured === undefined && this.runtime !== undefined);
2724
+ if (!useRuntime) {
2725
+ if (configured?.baseUrl === undefined && (configured === undefined || isExplicitNative || configured.id === undefined)) {
2726
+ const id = configured?.id ?? DEFAULT_MINSYNC_EMBEDDER_ID;
2727
+ const dimension = configured?.dimension ?? DEFAULT_MINSYNC_EMBEDDER_DIMENSION;
2728
+ return {
2729
+ config: {
2730
+ ...configured,
2731
+ id,
2732
+ dimension
2733
+ },
2734
+ identity: {
2735
+ provider: "native",
2736
+ model: id.startsWith("native:") ? id.slice("native:".length) : id,
2737
+ artifactRevision: "default",
2738
+ dimension,
2739
+ queryPrefix: configured?.queryPrefix ?? "",
2740
+ passagePrefix: configured?.passagePrefix ?? "",
2741
+ runtimeBuild: "minsync-native"
2742
+ }
2743
+ };
2744
+ }
2702
2745
  return { config: configured ?? {} };
2746
+ }
2703
2747
  try {
2704
2748
  const ensured = await this.runtime?.ensureRuntime({ profileId: configured?.profile, cachedOnly: true });
2705
2749
  if (!ensured)
@@ -2710,7 +2754,11 @@ class MinSyncClient {
2710
2754
  baseUrl: ensured.baseUrl,
2711
2755
  dimension: ensured.profile.dimension,
2712
2756
  queryPrefix: ensured.profile.queryPrefix,
2713
- passagePrefix: ensured.profile.passagePrefix
2757
+ passagePrefix: ensured.profile.passagePrefix,
2758
+ ...configured?.batchSize !== undefined ? { batchSize: configured.batchSize } : {},
2759
+ ...configured?.maxRetries !== undefined ? { maxRetries: configured.maxRetries } : {},
2760
+ ...configured?.maxConcurrent !== undefined ? { maxConcurrent: configured.maxConcurrent } : {},
2761
+ ...configured?.timeoutMs !== undefined ? { timeoutMs: configured.timeoutMs } : {}
2714
2762
  },
2715
2763
  identity: {
2716
2764
  provider: ensured.identity.provider,
@@ -2790,8 +2838,8 @@ class MinSyncClient {
2790
2838
  const cursorPath = join9(this.workspacePath, ".minsync", "cursor.json");
2791
2839
  if (!initialized) {
2792
2840
  const initArgs = ["init", "--format", "json"];
2793
- if (embedder.id) {
2794
- initArgs.push("--embedder", embedder.id);
2841
+ if (this.embedder?.id) {
2842
+ initArgs.push("--embedder", this.embedder.id);
2795
2843
  }
2796
2844
  const init = await this.spawn(initArgs, spawnOpts);
2797
2845
  if (!init.ok || !existsSync7(minSyncConfigPath(this.workspacePath))) {
@@ -2820,13 +2868,28 @@ class MinSyncClient {
2820
2868
  ok: false,
2821
2869
  synced: 0,
2822
2870
  workspacePath: this.workspacePath,
2823
- reason: "check-failed"
2871
+ reason: "check-failed",
2872
+ diagnostic: {
2873
+ code: "sync-failed",
2874
+ message: check.stderr ? check.stderr.trim() : "MinSync check failed.",
2875
+ retryable: true
2876
+ }
2824
2877
  };
2825
2878
  }
2826
2879
  const checkFailure = readCheckFailure(check.stdout);
2827
2880
  if (checkFailure) {
2828
2881
  restoreConfig();
2829
- return { ok: false, synced: 0, workspacePath: this.workspacePath, reason: checkFailure };
2882
+ return {
2883
+ ok: false,
2884
+ synced: 0,
2885
+ workspacePath: this.workspacePath,
2886
+ reason: checkFailure,
2887
+ diagnostic: {
2888
+ code: checkFailure.includes("embedder") ? "embedder-unavailable" : "sync-failed",
2889
+ message: checkFailure,
2890
+ retryable: true
2891
+ }
2892
+ };
2830
2893
  }
2831
2894
  const chunkSizeChanged = this.maxChunkSize !== undefined && configuredChunkSize !== this.maxChunkSize;
2832
2895
  const dimensionChanged = embedder.dimension !== undefined && configuredDimension !== embedder.dimension;
@@ -2840,7 +2903,12 @@ class MinSyncClient {
2840
2903
  ok: false,
2841
2904
  synced: 0,
2842
2905
  workspacePath: this.workspacePath,
2843
- reason: "sync-failed"
2906
+ reason: "sync-failed",
2907
+ diagnostic: {
2908
+ code: "sync-failed",
2909
+ message: result.stderr ? result.stderr.trim() : "MinSync sync failed.",
2910
+ retryable: true
2911
+ }
2844
2912
  };
2845
2913
  }
2846
2914
  if (!existsSync7(cursorPath)) {
@@ -2871,7 +2939,8 @@ class MinSyncClient {
2871
2939
  const migration = configuredDimension === 768 && effective.config.dimension !== 768 ? ` ${MINSYNC_OLLAMA_MIGRATION_MESSAGE}` : "";
2872
2940
  throw new MinSyncQueryError(null, `configured embedder dimension ${effective.config.dimension} does not match indexed dimension ${configuredDimension}; reindex required.${migration}`);
2873
2941
  }
2874
- if (effective.identity !== undefined && this.identityMismatch(effective.identity)) {
2942
+ const cursorPath = join9(this.workspacePath, ".minsync", "cursor.json");
2943
+ if (existsSync7(cursorPath) && effective.identity !== undefined && this.identityMismatch(effective.identity)) {
2875
2944
  throw new MinSyncQueryError(null, "embedding identity does not match the indexed workspace; full reindex required");
2876
2945
  }
2877
2946
  const shouldRewriteConfig = this.embedder !== undefined || effective.identity !== undefined;
@@ -3196,7 +3265,7 @@ function isGitHubAsset(value) {
3196
3265
  function isRecord5(value) {
3197
3266
  return typeof value === "object" && value !== null;
3198
3267
  }
3199
- 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;
3268
+ var LATEST_RELEASE_URL = "https://api.github.com/repos/NomaDamas/MinSync/releases/latest", SHA256_HEX_PATTERN, MINSYNC_VERSION = "0.4.5", MINSYNC_CARGO_INSTALL_TIMEOUT_MS, CARGO_PROBE_TIMEOUT_MS = 5000, MinSyncReleaseError;
3200
3269
  var init_installer2 = __esm(() => {
3201
3270
  init_process();
3202
3271
  SHA256_HEX_PATTERN = /^[a-f0-9]{64}$/;
@@ -3624,7 +3693,7 @@ function listen(server, port, host) {
3624
3693
  function close(server) {
3625
3694
  return new Promise((resolve, reject) => server.close((error) => error ? reject(error) : resolve()));
3626
3695
  }
3627
- var GatewayError, DEFAULT_MAX_INPUTS = 128, DEFAULT_MAX_CHARACTERS = 1e5, DEFAULT_TIMEOUT_MS3 = 30000, MAX_BODY_BYTES = 2000000;
3696
+ var GatewayError, MINSYNC_DEFAULT_BATCH_SIZE = 64, MINSYNC_DEFAULT_MAX_CHUNK_SIZE = 4096, DEFAULT_MAX_INPUTS = 128, DEFAULT_MAX_CHARACTERS, DEFAULT_TIMEOUT_MS3 = 30000, MAX_BODY_BYTES = 2000000;
3628
3697
  var init_gateway = __esm(() => {
3629
3698
  GatewayError = class GatewayError extends Error {
3630
3699
  code;
@@ -3636,6 +3705,7 @@ var init_gateway = __esm(() => {
3636
3705
  this.status = status;
3637
3706
  }
3638
3707
  };
3708
+ DEFAULT_MAX_CHARACTERS = MINSYNC_DEFAULT_BATCH_SIZE * MINSYNC_DEFAULT_MAX_CHUNK_SIZE;
3639
3709
  });
3640
3710
 
3641
3711
  // src/embedding-runtime/manifest.ts
@@ -4187,6 +4257,22 @@ function identity(profile) {
4187
4257
  artifactSha256: profile.artifactSha256
4188
4258
  };
4189
4259
  }
4260
+ function incompatibleGateway(message) {
4261
+ return { ok: false, code: "incompatible", message, retryable: false };
4262
+ }
4263
+ function normalizeGatewayHealth(payload) {
4264
+ if (typeof payload !== "object" || payload === null) {
4265
+ return incompatibleGateway("Gateway health response was not a JSON object.");
4266
+ }
4267
+ const { status, profileId, dimension, runtimeBuild } = payload;
4268
+ if (status !== "ok") {
4269
+ return incompatibleGateway('Gateway health response did not report status "ok".');
4270
+ }
4271
+ if (typeof profileId !== "string" || typeof dimension !== "number" || typeof runtimeBuild !== "string") {
4272
+ return incompatibleGateway("Gateway health response was missing profile identity fields.");
4273
+ }
4274
+ return { ok: true, profileId, dimension, runtimeBuild };
4275
+ }
4190
4276
  function createEmbeddingRuntime(options = {}) {
4191
4277
  const root = options.cacheRoot ?? resolveAutoRAGHome();
4192
4278
  const cache = options.cache ?? {
@@ -4208,8 +4294,22 @@ function createEmbeddingRuntime(options = {}) {
4208
4294
  const runtimePath = await cache.downloadAsset(runtimeAsset(options.platform, options.backend ?? profile.backend), cacheOptions);
4209
4295
  return { modelPath, runtimePath };
4210
4296
  }
4297
+ let ensureInFlight;
4211
4298
  async function ensureRuntime(input = {}) {
4212
4299
  const profile = profileOf(input.profileId);
4300
+ const pending = ensureInFlight;
4301
+ if (pending !== undefined && pending.profileId === profile.profileId)
4302
+ return pending.promise;
4303
+ const promise = ensureRuntimeOnce(profile, input);
4304
+ ensureInFlight = { profileId: profile.profileId, promise };
4305
+ try {
4306
+ return await promise;
4307
+ } finally {
4308
+ if (ensureInFlight?.promise === promise)
4309
+ ensureInFlight = undefined;
4310
+ }
4311
+ }
4312
+ async function ensureRuntimeOnce(profile, input) {
4213
4313
  stoppedByService = false;
4214
4314
  const selectedSupervisor = input.supervisor ?? options.supervisor;
4215
4315
  if (selectedSupervisor)
@@ -4286,7 +4386,7 @@ function createEmbeddingRuntime(options = {}) {
4286
4386
  const response = await (options.fetch ?? fetch)(`${gateway.url}/healthz`);
4287
4387
  if (!response.ok)
4288
4388
  throw new Error(`Gateway health returned HTTP ${response.status}.`);
4289
- const health = await response.json();
4389
+ const health = normalizeGatewayHealth(await response.json());
4290
4390
  return { ...base, profileId: activeProfile?.profileId, baseUrl: gateway.url, health };
4291
4391
  } catch {
4292
4392
  return {
@@ -4373,7 +4473,9 @@ function syncMinSyncWorkspace(root, options = {}) {
4373
4473
  const workspacePath = options.workspacePath ?? minSyncWorkspaceRoot(root);
4374
4474
  const filesRoot = join14(workspacePath, "files");
4375
4475
  const index = loadMirrorIndex(root);
4376
- const entries = Object.values(index.entries).sort((a, b) => a.virtualPath.localeCompare(b.virtualPath)).filter((entry) => normalizeVirtualPath(entry.virtualPath) === entry.virtualPath && existsSync10(entry.outputPath)).map((entry) => {
4476
+ const candidates = Object.values(index.entries).sort((a, b) => a.virtualPath.localeCompare(b.virtualPath));
4477
+ const excluded = candidates.filter((entry) => normalizeVirtualPath(entry.virtualPath) !== entry.virtualPath || !existsSync10(entry.outputPath)).map((entry) => entry.virtualPath);
4478
+ const entries = candidates.filter((entry) => normalizeVirtualPath(entry.virtualPath) === entry.virtualPath && existsSync10(entry.outputPath)).map((entry) => {
4377
4479
  const minSyncPath = minSyncDocumentPath(workspacePath, entry.virtualPath);
4378
4480
  return {
4379
4481
  virtualPath: entry.virtualPath,
@@ -4404,7 +4506,7 @@ function syncMinSyncWorkspace(root, options = {}) {
4404
4506
  }
4405
4507
  removeUnexpectedStagedFiles(filesRoot, desiredPaths);
4406
4508
  saveStagingState(workspacePath, { version: 1, entries: currentState });
4407
- return { workspacePath, entries };
4509
+ return { workspacePath, entries, excluded };
4408
4510
  }
4409
4511
  function stagingStatePath(workspacePath) {
4410
4512
  return join14(dirname6(workspacePath), `.${basename6(workspacePath)}-autorag-staging.json`);
@@ -4531,6 +4633,16 @@ function lookupInPath(env) {
4531
4633
  }
4532
4634
  return;
4533
4635
  }
4636
+ function withWorkspaceLock(workspacePath, run) {
4637
+ const previous = workspaceOperationTails.get(workspacePath) ?? Promise.resolve();
4638
+ const result = previous.then(run, run);
4639
+ workspaceOperationTails.set(workspacePath, result.then(() => {
4640
+ return;
4641
+ }, () => {
4642
+ return;
4643
+ }));
4644
+ return result;
4645
+ }
4534
4646
 
4535
4647
  class MinSyncVectorMethod {
4536
4648
  root;
@@ -4552,7 +4664,7 @@ class MinSyncVectorMethod {
4552
4664
  this.embedder = options.embedder;
4553
4665
  this.maxChunkSize = options.maxChunkSize;
4554
4666
  this.mode = options.mode ?? "vector";
4555
- this.runtime = options.runtime ?? (options.binaryPath === undefined && options.autoInstall !== false ? { ensureRuntime } : undefined);
4667
+ this.runtime = options.runtime ?? (this.embedder?.profile !== undefined && options.binaryPath === undefined && options.autoInstall !== false ? { ensureRuntime } : undefined);
4556
4668
  }
4557
4669
  describe() {
4558
4670
  return {
@@ -4569,10 +4681,14 @@ class MinSyncVectorMethod {
4569
4681
  };
4570
4682
  }
4571
4683
  async sync(force = false) {
4572
- syncMinSyncWorkspace(this.root, { workspacePath: this.workspacePath });
4684
+ return withWorkspaceLock(this.workspacePath, () => this.syncUnlocked(force));
4685
+ }
4686
+ async syncUnlocked(force) {
4687
+ const staging = syncMinSyncWorkspace(this.root, { workspacePath: this.workspacePath });
4688
+ const withExcluded = (result) => staging.excluded.length === 0 ? result : { ...result, stagingExcluded: staging.excluded };
4573
4689
  const binaryResult = await this.resolveBinary();
4574
4690
  if (binaryResult === undefined) {
4575
- return degrade(this.workspacePath, "missing-binary");
4691
+ return withExcluded(degrade(this.workspacePath, "missing-binary"));
4576
4692
  }
4577
4693
  if (typeof binaryResult === "string") {
4578
4694
  const client = new MinSyncClient({
@@ -4582,9 +4698,9 @@ class MinSyncVectorMethod {
4582
4698
  maxChunkSize: this.maxChunkSize,
4583
4699
  runtime: this.runtime
4584
4700
  });
4585
- return client.sync(force);
4701
+ return withExcluded(await client.sync(force));
4586
4702
  }
4587
- return binaryResult;
4703
+ return withExcluded(binaryResult);
4588
4704
  }
4589
4705
  isBinaryMissing() {
4590
4706
  if (this.binaryPath !== undefined)
@@ -4603,6 +4719,9 @@ class MinSyncVectorMethod {
4603
4719
  return existsSync11(join15(this.workspacePath, ".minsync", "cursor.json"));
4604
4720
  }
4605
4721
  async retrieve(query, options) {
4722
+ return withWorkspaceLock(this.workspacePath, () => this.retrieveUnlocked(query, options));
4723
+ }
4724
+ async retrieveUnlocked(query, options) {
4606
4725
  const topK = options.topK ?? 20;
4607
4726
  const queryK = options.scope ? Math.min(Math.max(topK * 5, topK + 20), 100) : topK;
4608
4727
  const byPath = buildMinSyncPathMap(this.root, this.workspacePath);
@@ -4670,7 +4789,7 @@ class MinSyncVectorMethod {
4670
4789
  return;
4671
4790
  }
4672
4791
  }
4673
- var MinSyncHybridMethod;
4792
+ var workspaceOperationTails, MinSyncHybridMethod;
4674
4793
  var init_method = __esm(() => {
4675
4794
  init_embedding_runtime();
4676
4795
  init_scope();
@@ -4678,6 +4797,7 @@ var init_method = __esm(() => {
4678
4797
  init_installer2();
4679
4798
  init_paths2();
4680
4799
  init_workspace();
4800
+ workspaceOperationTails = new Map;
4681
4801
  MinSyncHybridMethod = class MinSyncHybridMethod extends MinSyncVectorMethod {
4682
4802
  constructor(options) {
4683
4803
  super({ ...options, mode: "hybrid" });
@@ -5841,19 +5961,34 @@ async function syncParsedMirrors(options) {
5841
5961
  const current = await listCurrentFiles(options.searchPaths, supportedExtensions);
5842
5962
  const previous = loadMirrorIndex(options.root);
5843
5963
  const nextEntries = {};
5964
+ const nextSkipped = {};
5844
5965
  const handledPrevious = new Set;
5845
5966
  let written = 0;
5846
5967
  let skipped = 0;
5847
5968
  let deleted = 0;
5848
5969
  let sinceCheckpoint = 0;
5849
5970
  const diagnostics = [];
5971
+ const recordSkip = (entry, reason) => {
5972
+ nextSkipped[entry.virtualPath] = {
5973
+ virtualPath: entry.virtualPath,
5974
+ sourcePath: entry.sourcePath,
5975
+ reason,
5976
+ sourceMtimeNs: entry.mtimeNs,
5977
+ sourceSizeBytes: entry.sizeBytes,
5978
+ updatedAt: new Date().toISOString()
5979
+ };
5980
+ };
5850
5981
  const checkpoint = () => {
5851
5982
  const merged = { ...previous.entries, ...nextEntries };
5983
+ const mergedSkipped = { ...previous.skipped, ...nextSkipped };
5852
5984
  for (const virtualPath of handledPrevious) {
5853
- if (!(virtualPath in nextEntries))
5854
- delete merged[virtualPath];
5985
+ if (virtualPath in nextEntries) {
5986
+ delete mergedSkipped[virtualPath];
5987
+ continue;
5988
+ }
5989
+ delete merged[virtualPath];
5855
5990
  }
5856
- saveMirrorIndex(options.root, { version: 1, entries: merged });
5991
+ saveMirrorIndex(options.root, { version: 1, entries: merged, skipped: mergedSkipped });
5857
5992
  sinceCheckpoint = 0;
5858
5993
  };
5859
5994
  for (const entry of current) {
@@ -5861,6 +5996,7 @@ async function syncParsedMirrors(options) {
5861
5996
  deleted += removePrevious(options.root, previous, entry.virtualPath);
5862
5997
  handledPrevious.add(entry.virtualPath);
5863
5998
  skipped += 1;
5999
+ recordSkip(entry, "duplicate-excluded");
5864
6000
  diagnostics.push({
5865
6001
  code: "duplicate-excluded",
5866
6002
  severity: "info",
@@ -5874,12 +6010,14 @@ async function syncParsedMirrors(options) {
5874
6010
  deleted += removePrevious(options.root, previous, entry.virtualPath);
5875
6011
  handledPrevious.add(entry.virtualPath);
5876
6012
  skipped += 1;
6013
+ recordSkip(entry, "parser-skipped");
5877
6014
  continue;
5878
6015
  }
5879
6016
  if (entry.sizeBytes > maxSourceBytes) {
5880
6017
  deleted += removePrevious(options.root, previous, entry.virtualPath);
5881
6018
  handledPrevious.add(entry.virtualPath);
5882
6019
  skipped += 1;
6020
+ recordSkip(entry, "parser-skipped");
5883
6021
  diagnostics.push({
5884
6022
  code: "parser-skipped",
5885
6023
  severity: "warning",
@@ -5905,6 +6043,7 @@ async function syncParsedMirrors(options) {
5905
6043
  deleted += removePrevious(options.root, previous, entry.virtualPath);
5906
6044
  handledPrevious.add(entry.virtualPath);
5907
6045
  skipped += 1;
6046
+ recordSkip(entry, "parser-failed");
5908
6047
  diagnostics.push({
5909
6048
  code: parserFailureCode(parser, error),
5910
6049
  severity: "warning",
@@ -5955,7 +6094,7 @@ async function syncParsedMirrors(options) {
5955
6094
  source: virtualPath
5956
6095
  });
5957
6096
  }
5958
- const index = { version: 1, entries: nextEntries };
6097
+ const index = { version: 1, entries: nextEntries, skipped: nextSkipped };
5959
6098
  saveMirrorIndex(options.root, index);
5960
6099
  return {
5961
6100
  scanned: current.length,
@@ -5978,16 +6117,20 @@ async function detectMirrorStaleness(options) {
5978
6117
  if (!registry.getForVirtualPath(entry.virtualPath))
5979
6118
  continue;
5980
6119
  const prev = previous.entries[entry.virtualPath];
5981
- if (!prev || prev.sourceMtimeNs !== entry.mtimeNs || prev.sourceSizeBytes !== entry.sizeBytes) {
5982
- const reason = prev === undefined ? "source-added" : prev.sourceMtimeNs !== entry.mtimeNs && prev.sourceSizeBytes !== entry.sizeBytes ? "mtime-and-size-changed" : prev.sourceMtimeNs !== entry.mtimeNs ? "mtime-changed" : "size-changed";
5983
- diagnostics.push({
5984
- code: "stale-index",
5985
- severity: "warning",
5986
- message: `Source ${entry.virtualPath} is ${reason.replaceAll("-", " ")} since the last refresh; indexes may be stale.`,
5987
- source: entry.virtualPath,
5988
- reason
5989
- });
5990
- }
6120
+ if (prev !== undefined && prev.sourceMtimeNs === entry.mtimeNs && prev.sourceSizeBytes === entry.sizeBytes)
6121
+ continue;
6122
+ const prevSkip = previous.skipped?.[entry.virtualPath];
6123
+ if (prevSkip !== undefined && prevSkip.sourceMtimeNs === entry.mtimeNs && prevSkip.sourceSizeBytes === entry.sizeBytes)
6124
+ continue;
6125
+ const known = prev ?? prevSkip;
6126
+ 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";
6127
+ diagnostics.push({
6128
+ code: "stale-index",
6129
+ severity: "warning",
6130
+ message: `Source ${entry.virtualPath} is ${reason.replaceAll("-", " ")} since the last refresh; indexes may be stale.`,
6131
+ source: entry.virtualPath,
6132
+ reason
6133
+ });
5991
6134
  }
5992
6135
  return diagnostics;
5993
6136
  }
@@ -6022,6 +6165,8 @@ async function collectFiles(sourceRoot, directory, entries, supportedExtensions)
6022
6165
  for await (const entry of dir) {
6023
6166
  if (SKIP_DIR_NAMES.has(entry.name))
6024
6167
  continue;
6168
+ if (PRODUCT_ARTIFACT_FILE_NAMES.has(entry.name))
6169
+ continue;
6025
6170
  const sourcePath = resolve9(directory, entry.name);
6026
6171
  if (entry.isDirectory()) {
6027
6172
  await collectFiles(sourceRoot, sourcePath, entries, supportedExtensions);
@@ -6063,7 +6208,7 @@ function removeFile(path) {
6063
6208
  if (existsSync12(path))
6064
6209
  rmSync3(path, { force: true });
6065
6210
  }
6066
- var DEFAULT_MAX_SOURCE_BYTES, MIRROR_CHECKPOINT_EVERY = 25, SKIP_DIR_NAMES;
6211
+ var DEFAULT_MAX_SOURCE_BYTES, MIRROR_CHECKPOINT_EVERY = 25, PRODUCT_ARTIFACT_FILE_NAMES, SKIP_DIR_NAMES;
6067
6212
  var init_sync = __esm(() => {
6068
6213
  init_source_paths();
6069
6214
  init_defaults();
@@ -6072,6 +6217,7 @@ var init_sync = __esm(() => {
6072
6217
  init_index_store();
6073
6218
  init_paths();
6074
6219
  DEFAULT_MAX_SOURCE_BYTES = 50 * 1024 * 1024;
6220
+ PRODUCT_ARTIFACT_FILE_NAMES = new Set([".jikji_agent_map.md"]);
6075
6221
  SKIP_DIR_NAMES = new Set([
6076
6222
  ".autorag",
6077
6223
  ".git",
@@ -9257,7 +9403,7 @@ var init_watch_refresh = __esm(() => {
9257
9403
 
9258
9404
  // src/agent/agent.ts
9259
9405
  import { randomUUID as randomUUID6 } from "node:crypto";
9260
- import { watch as fsWatch, mkdirSync as mkdirSync11, realpathSync as realpathSync4, statSync, writeFileSync as writeFileSync10 } from "node:fs";
9406
+ import { existsSync as existsSync16, watch as fsWatch, mkdirSync as mkdirSync11, realpathSync as realpathSync4, statSync, writeFileSync as writeFileSync10 } from "node:fs";
9261
9407
  import { dirname as dirname12, join as join21, resolve as resolve11 } from "node:path";
9262
9408
  import { Agent } from "@earendil-works/pi-agent-core";
9263
9409
  import { clampThinkingLevel, streamSimple } from "@earendil-works/pi-ai/compat";
@@ -10140,14 +10286,22 @@ ${initialRetrievalContext ?? "Pending; continue only with a brief progress state
10140
10286
  writeFileSync10(refreshReadinessPath(this.workspaceProjectRoot), `{"version":1,"completed":true,"parsed":true}
10141
10287
  `);
10142
10288
  }
10289
+ const minsyncDiagnostics = minSyncRefreshDiagnostics(minsync);
10143
10290
  const publicMinsync = minsync ? {
10144
10291
  ok: minsync.ok,
10145
10292
  synced: minsync.synced,
10146
- ...minsync.reason !== undefined ? { reason: minsync.reason } : {}
10293
+ ...minsync.reason !== undefined ? { reason: sanitizeDiagnosticMessage(minsync.reason) } : {},
10294
+ ...minsyncDiagnostics.length > 0 ? { diagnostics: minsyncDiagnostics } : {},
10295
+ ...minsync.stagingExcluded !== undefined && minsync.stagingExcluded.length > 0 ? { stagingExcludedCount: minsync.stagingExcluded.length } : {}
10147
10296
  } : undefined;
10148
10297
  return {
10149
10298
  ...summary,
10150
- diagnostics: [...this.startupDiagnostics, ...summary.diagnostics],
10299
+ diagnostics: [
10300
+ ...this.startupDiagnostics,
10301
+ ...summary.diagnostics,
10302
+ ...minsyncDiagnostics,
10303
+ ...stagingExcludedDiagnostics(minsync?.stagingExcluded)
10304
+ ],
10151
10305
  minsync: publicMinsync,
10152
10306
  datasources
10153
10307
  };
@@ -10186,6 +10340,11 @@ ${initialRetrievalContext ?? "Pending; continue only with a brief progress state
10186
10340
  for (const result of this.refreshState.datasources) {
10187
10341
  diagnostics.push(...mapDatasourceDiagnostics(result.diagnostics));
10188
10342
  }
10343
+ for (const diag of minSyncRefreshDiagnostics(this.refreshState.minsync)) {
10344
+ if (!diagnostics.some((d) => d.code === diag.code && d.source === diag.source)) {
10345
+ diagnostics.push(diag);
10346
+ }
10347
+ }
10189
10348
  if (this.refreshState.watchLimited) {
10190
10349
  diagnostics.push({
10191
10350
  code: "watch-limited",
@@ -10203,13 +10362,14 @@ ${initialRetrievalContext ?? "Pending; continue only with a brief progress state
10203
10362
  });
10204
10363
  }
10205
10364
  const state = this.refreshState.inFlight ? "indexing" : this.refreshState.lastOutcome === "never" ? "idle" : this.refreshState.lastOutcome;
10365
+ const parsedMirrorReady = this.refreshState.lastOutcome === "success" || existsSync16(refreshReadinessPath(this.workspaceProjectRoot));
10206
10366
  return {
10207
10367
  state,
10208
10368
  inFlight: this.refreshState.inFlight,
10209
10369
  lastStartedAt: this.refreshState.lastStartedAt,
10210
10370
  lastFinishedAt: this.refreshState.lastFinishedAt,
10211
10371
  counts: this.refreshState.counts,
10212
- stale: this.refreshState.lastOutcome === "never" || staleDiagnostics.length > 0,
10372
+ stale: !parsedMirrorReady || staleDiagnostics.length > 0,
10213
10373
  diagnostics,
10214
10374
  components: this.refreshComponentStatus(),
10215
10375
  lastError: this.refreshState.lastError
@@ -10659,6 +10819,14 @@ function lastAssistantText(messages) {
10659
10819
  }
10660
10820
  return;
10661
10821
  }
10822
+ function stagingExcludedDiagnostics(excluded) {
10823
+ return (excluded ?? []).map((source) => ({
10824
+ code: "minsync-staging-excluded",
10825
+ severity: "warning",
10826
+ message: "Excluded from the MinSync index: this file name cannot be represented as a canonical source id.",
10827
+ source
10828
+ }));
10829
+ }
10662
10830
  function toSearchDiagnostic(diagnostic) {
10663
10831
  return {
10664
10832
  code: diagnostic.code,
@@ -10667,6 +10835,38 @@ function toSearchDiagnostic(diagnostic) {
10667
10835
  source: diagnostic.source
10668
10836
  };
10669
10837
  }
10838
+ function sanitizeDiagnosticMessage(raw) {
10839
+ let out = raw.split(/\n\s+at\s/)[0] ?? raw;
10840
+ out = out.replace(/(?:^|[^A-Za-z0-9])(\/(?:[^/\s]+\/)+[^/\s]+)/g, " <path>");
10841
+ out = out.replace(/[A-Za-z]:\\[^\s]+/g, "<path>");
10842
+ return out.replace(/\s{2,}/g, " ").trim();
10843
+ }
10844
+ function minSyncRefreshDiagnostics(minsync) {
10845
+ if (!minsync)
10846
+ return [];
10847
+ if (minsync.diagnostic)
10848
+ return [toMinSyncDiagnostic(minsync.diagnostic, minsync.ok)];
10849
+ if (!minsync.ok && minsync.reason)
10850
+ return [toMinSyncReasonDiagnostic(minsync.reason)];
10851
+ return [];
10852
+ }
10853
+ function toMinSyncDiagnostic(diag, ok) {
10854
+ const code = diag.code === "embedder-unavailable" ? "embedder-unavailable" : diag.code === "embedding-identity-mismatch" ? "embedding-identity-mismatch" : "minsync-sync-failed";
10855
+ return {
10856
+ code,
10857
+ severity: ok ? "info" : "error",
10858
+ message: sanitizeDiagnosticMessage(diag.message),
10859
+ source: "minsync"
10860
+ };
10861
+ }
10862
+ function toMinSyncReasonDiagnostic(reason) {
10863
+ return {
10864
+ code: reason === "missing-binary" ? "minsync-unavailable" : "minsync-sync-failed",
10865
+ severity: reason === "missing-binary" ? "warning" : "error",
10866
+ message: reason === "missing-binary" ? "MinSync binary is not available and auto-install was skipped." : `MinSync sync failed: ${sanitizeDiagnosticMessage(reason)}`,
10867
+ source: "minsync"
10868
+ };
10869
+ }
10670
10870
  function pinSearchRoot(searchPath) {
10671
10871
  const resolvedPath = resolve11(searchPath);
10672
10872
  let canonicalPath;
@@ -10899,7 +11099,7 @@ ${this.description}`
10899
11099
 
10900
11100
  // src/datasource/skills/clawgallery/client.ts
10901
11101
  import { spawn as spawn7 } from "node:child_process";
10902
- import { existsSync as existsSync16 } from "node:fs";
11102
+ import { existsSync as existsSync17 } from "node:fs";
10903
11103
 
10904
11104
  class ClawGalleryClient {
10905
11105
  options;
@@ -10907,7 +11107,7 @@ class ClawGalleryClient {
10907
11107
  this.options = options;
10908
11108
  }
10909
11109
  async bootstrap(signal) {
10910
- if (this.options.path !== undefined && !existsSync16(this.options.path)) {
11110
+ if (this.options.path !== undefined && !existsSync17(this.options.path)) {
10911
11111
  return {
10912
11112
  ok: false,
10913
11113
  reason: "nonzero-exit",
@@ -11864,7 +12064,7 @@ function sanitizeIdSegment(value) {
11864
12064
  var init_connector = () => {};
11865
12065
 
11866
12066
  // src/datasource/chunk-store.ts
11867
- import { existsSync as existsSync17, mkdirSync as mkdirSync13, readFileSync as readFileSync14, writeFileSync as writeFileSync12 } from "node:fs";
12067
+ import { existsSync as existsSync18, mkdirSync as mkdirSync13, readFileSync as readFileSync14, writeFileSync as writeFileSync12 } from "node:fs";
11868
12068
  import { dirname as dirname14, join as join23 } from "node:path";
11869
12069
  function datasourceChunkStorePath(workspaceRoot, skillName, instanceId) {
11870
12070
  return join23(workspaceRoot, ".autorag", "datasources", sanitizeIdSegment(skillName), sanitizeIdSegment(instanceId), "chunks.json");
@@ -11904,7 +12104,7 @@ class DatasourceChunkStore {
11904
12104
  if (this.storePath === undefined)
11905
12105
  return false;
11906
12106
  try {
11907
- if (!existsSync17(this.storePath))
12107
+ if (!existsSync18(this.storePath))
11908
12108
  return false;
11909
12109
  const parsed = JSON.parse(readFileSync14(this.storePath, "utf8"));
11910
12110
  if (parsed.version !== STORE_VERSION || !Array.isArray(parsed.chunks))
@@ -12404,7 +12604,7 @@ var init_cloud_drive = __esm(() => {
12404
12604
  });
12405
12605
 
12406
12606
  // src/datasource/skills/discrawl/types.ts
12407
- var ENGLISH_ONLY_EMBEDDING_MODELS, DEFAULT_DISCRAWL_EMBEDDING_MODEL = "embeddinggemma", DEFAULT_DISCRAWL_BINARY = "discrawl", DEFAULT_DISCRAWL_TIMEOUT_MS = 30000, DEFAULT_DISCRAWL_MAX_BUFFER_BYTES = 1048576, DEFAULT_DISCRAWL_SOURCE = "wiretap", DEFAULT_DISCRAWL_MODE = "hybrid";
12607
+ var ENGLISH_ONLY_EMBEDDING_MODELS, DEFAULT_DISCRAWL_EMBEDDING_MODEL = "embeddinggemma", DEFAULT_DISCRAWL_BINARY = "discrawl", DEFAULT_DISCRAWL_TIMEOUT_MS = 30000, DEFAULT_DISCRAWL_MAX_BUFFER_BYTES = 1048576, DEFAULT_DISCRAWL_MODE = "hybrid";
12408
12608
  var init_types3 = __esm(() => {
12409
12609
  ENGLISH_ONLY_EMBEDDING_MODELS = new Set([
12410
12610
  "nomic-embed-text",
@@ -12493,12 +12693,7 @@ class DiscrawlClient {
12493
12693
  return data === undefined ? toFailure(result, "invalid-shape") : ok2(data, result);
12494
12694
  }
12495
12695
  async sync(signal) {
12496
- const source = this.options.source ?? DEFAULT_DISCRAWL_SOURCE;
12497
- const args = source === "wiretap" ? ["wiretap"] : ["sync", "--source", source];
12498
- if (source !== "wiretap" && this.options.guildId !== undefined) {
12499
- args.push("--guild", this.options.guildId);
12500
- }
12501
- const result = await this.runJson(args, signal);
12696
+ const result = await this.runJson(["wiretap"], signal);
12502
12697
  if (!result.ok)
12503
12698
  return toFailure(result);
12504
12699
  const parsed = parseJsonObject(result.stdout);
@@ -12681,7 +12876,7 @@ function controlledEnv2(configuredEnv) {
12681
12876
  return env;
12682
12877
  }
12683
12878
  function isAllowedDiscrawlEnvKey(key) {
12684
- return SAFE_INHERITED_ENV_KEYS.has(key) || ALLOWED_DISCORD_ENV_KEYS.has(key) || key.startsWith(SAFE_DISCRAWL_ENV_PREFIX);
12879
+ return SAFE_INHERITED_ENV_KEYS.has(key) || key.startsWith(SAFE_DISCRAWL_ENV_PREFIX);
12685
12880
  }
12686
12881
  function findUserTokenKey(env) {
12687
12882
  for (const [key, value] of Object.entries(env)) {
@@ -12920,7 +13115,7 @@ function sanitizeDiagnosticText(value) {
12920
13115
  function ok2(data, result) {
12921
13116
  return { ok: true, data, stdout: result.stdout, stderr: result.stderr, code: result.code ?? 0 };
12922
13117
  }
12923
- var USER_TOKEN_KEYS, SAFE_INHERITED_ENV_KEYS, SAFE_DISCRAWL_ENV_PREFIX = "DISCRAWL_", ALLOWED_DISCORD_ENV_KEYS;
13118
+ var USER_TOKEN_KEYS, SAFE_INHERITED_ENV_KEYS, SAFE_DISCRAWL_ENV_PREFIX = "DISCRAWL_";
12924
13119
  var init_client4 = __esm(() => {
12925
13120
  init_portable_spawn();
12926
13121
  init_types3();
@@ -12931,7 +13126,6 @@ var init_client4 = __esm(() => {
12931
13126
  "discord_account_token"
12932
13127
  ]);
12933
13128
  SAFE_INHERITED_ENV_KEYS = new Set(["HOME", "LANG", "LC_ALL", "PATH", "TMPDIR", "TMP", "TEMP"]);
12934
- ALLOWED_DISCORD_ENV_KEYS = new Set(["DISCORD_BOT_TOKEN"]);
12935
13129
  });
12936
13130
 
12937
13131
  // src/datasource/skills/discrawl/paths.ts
@@ -17069,7 +17263,7 @@ var init_factory = __esm(() => {
17069
17263
 
17070
17264
  // src/cli/config.ts
17071
17265
  import { randomUUID as randomUUID7 } from "node:crypto";
17072
- import { existsSync as existsSync18, mkdirSync as mkdirSync17, readFileSync as readFileSync16, renameSync as renameSync8, unlinkSync as unlinkSync4, writeFileSync as writeFileSync15 } from "node:fs";
17266
+ import { existsSync as existsSync19, mkdirSync as mkdirSync17, readFileSync as readFileSync16, renameSync as renameSync8, unlinkSync as unlinkSync4, writeFileSync as writeFileSync15 } from "node:fs";
17073
17267
  import { basename as basename12, dirname as dirname17, isAbsolute as isAbsolute7, join as join26, resolve as resolve13 } from "node:path";
17074
17268
  import { findEnvKeys, getEnvApiKey, getModel, getProviders } from "@earendil-works/pi-ai/compat";
17075
17269
  function resolveConfigPath(input) {
@@ -17093,7 +17287,7 @@ function resolveConfigPath(input) {
17093
17287
  function readConfigFile(configPath, explicit) {
17094
17288
  let exists;
17095
17289
  try {
17096
- exists = existsSync18(configPath);
17290
+ exists = existsSync19(configPath);
17097
17291
  } catch {
17098
17292
  exists = false;
17099
17293
  }
@@ -17153,7 +17347,7 @@ function replaceFileAtomically(path, contents, assertCommitAllowed) {
17153
17347
  }
17154
17348
  }
17155
17349
  function migrateLegacyConfig(configPath, legacyPath) {
17156
- if (existsSync18(configPath) || !existsSync18(legacyPath))
17350
+ if (existsSync19(configPath) || !existsSync19(legacyPath))
17157
17351
  return;
17158
17352
  const legacy = readConfigFile(legacyPath, true);
17159
17353
  const legacyBytes = readFileSync16(legacyPath);
@@ -17983,7 +18177,7 @@ function writeDefaultConfig(path, partial, opts = {}) {
17983
18177
  `;
17984
18178
  const lock = acquireConfigWriteLock(path);
17985
18179
  try {
17986
- if (!opts.force && existsSync18(path)) {
18180
+ if (!opts.force && existsSync19(path)) {
17987
18181
  throw new ConfigError(`Config file already exists: ${path}`);
17988
18182
  }
17989
18183
  if (opts.force || opts.atomicCreate)