opencode-codebase-index 0.2.5 → 0.3.0

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
@@ -491,7 +491,7 @@ var require_ignore = __commonJS({
491
491
  // path matching.
492
492
  // - check `string` either `MODE_IGNORE` or `MODE_CHECK_IGNORE`
493
493
  // @returns {TestResult} true if a file is ignored
494
- test(path8, checkUnignored, mode) {
494
+ test(path9, checkUnignored, mode) {
495
495
  let ignored = false;
496
496
  let unignored = false;
497
497
  let matchedRule;
@@ -500,7 +500,7 @@ var require_ignore = __commonJS({
500
500
  if (unignored === negative && ignored !== unignored || negative && !ignored && !unignored && !checkUnignored) {
501
501
  return;
502
502
  }
503
- const matched = rule[mode].test(path8);
503
+ const matched = rule[mode].test(path9);
504
504
  if (!matched) {
505
505
  return;
506
506
  }
@@ -521,17 +521,17 @@ var require_ignore = __commonJS({
521
521
  var throwError = (message, Ctor) => {
522
522
  throw new Ctor(message);
523
523
  };
524
- var checkPath = (path8, originalPath, doThrow) => {
525
- if (!isString(path8)) {
524
+ var checkPath = (path9, originalPath, doThrow) => {
525
+ if (!isString(path9)) {
526
526
  return doThrow(
527
527
  `path must be a string, but got \`${originalPath}\``,
528
528
  TypeError
529
529
  );
530
530
  }
531
- if (!path8) {
531
+ if (!path9) {
532
532
  return doThrow(`path must not be empty`, TypeError);
533
533
  }
534
- if (checkPath.isNotRelative(path8)) {
534
+ if (checkPath.isNotRelative(path9)) {
535
535
  const r = "`path.relative()`d";
536
536
  return doThrow(
537
537
  `path should be a ${r} string, but got "${originalPath}"`,
@@ -540,7 +540,7 @@ var require_ignore = __commonJS({
540
540
  }
541
541
  return true;
542
542
  };
543
- var isNotRelative = (path8) => REGEX_TEST_INVALID_PATH.test(path8);
543
+ var isNotRelative = (path9) => REGEX_TEST_INVALID_PATH.test(path9);
544
544
  checkPath.isNotRelative = isNotRelative;
545
545
  checkPath.convert = (p) => p;
546
546
  var Ignore2 = class {
@@ -570,19 +570,19 @@ var require_ignore = __commonJS({
570
570
  }
571
571
  // @returns {TestResult}
572
572
  _test(originalPath, cache, checkUnignored, slices) {
573
- const path8 = originalPath && checkPath.convert(originalPath);
573
+ const path9 = originalPath && checkPath.convert(originalPath);
574
574
  checkPath(
575
- path8,
575
+ path9,
576
576
  originalPath,
577
577
  this._strictPathCheck ? throwError : RETURN_FALSE
578
578
  );
579
- return this._t(path8, cache, checkUnignored, slices);
579
+ return this._t(path9, cache, checkUnignored, slices);
580
580
  }
581
- checkIgnore(path8) {
582
- if (!REGEX_TEST_TRAILING_SLASH.test(path8)) {
583
- return this.test(path8);
581
+ checkIgnore(path9) {
582
+ if (!REGEX_TEST_TRAILING_SLASH.test(path9)) {
583
+ return this.test(path9);
584
584
  }
585
- const slices = path8.split(SLASH2).filter(Boolean);
585
+ const slices = path9.split(SLASH2).filter(Boolean);
586
586
  slices.pop();
587
587
  if (slices.length) {
588
588
  const parent = this._t(
@@ -595,18 +595,18 @@ var require_ignore = __commonJS({
595
595
  return parent;
596
596
  }
597
597
  }
598
- return this._rules.test(path8, false, MODE_CHECK_IGNORE);
598
+ return this._rules.test(path9, false, MODE_CHECK_IGNORE);
599
599
  }
600
- _t(path8, cache, checkUnignored, slices) {
601
- if (path8 in cache) {
602
- return cache[path8];
600
+ _t(path9, cache, checkUnignored, slices) {
601
+ if (path9 in cache) {
602
+ return cache[path9];
603
603
  }
604
604
  if (!slices) {
605
- slices = path8.split(SLASH2).filter(Boolean);
605
+ slices = path9.split(SLASH2).filter(Boolean);
606
606
  }
607
607
  slices.pop();
608
608
  if (!slices.length) {
609
- return cache[path8] = this._rules.test(path8, checkUnignored, MODE_IGNORE);
609
+ return cache[path9] = this._rules.test(path9, checkUnignored, MODE_IGNORE);
610
610
  }
611
611
  const parent = this._t(
612
612
  slices.join(SLASH2) + SLASH2,
@@ -614,29 +614,29 @@ var require_ignore = __commonJS({
614
614
  checkUnignored,
615
615
  slices
616
616
  );
617
- return cache[path8] = parent.ignored ? parent : this._rules.test(path8, checkUnignored, MODE_IGNORE);
617
+ return cache[path9] = parent.ignored ? parent : this._rules.test(path9, checkUnignored, MODE_IGNORE);
618
618
  }
619
- ignores(path8) {
620
- return this._test(path8, this._ignoreCache, false).ignored;
619
+ ignores(path9) {
620
+ return this._test(path9, this._ignoreCache, false).ignored;
621
621
  }
622
622
  createFilter() {
623
- return (path8) => !this.ignores(path8);
623
+ return (path9) => !this.ignores(path9);
624
624
  }
625
625
  filter(paths) {
626
626
  return makeArray(paths).filter(this.createFilter());
627
627
  }
628
628
  // @returns {TestResult}
629
- test(path8) {
630
- return this._test(path8, this._testCache, true);
629
+ test(path9) {
630
+ return this._test(path9, this._testCache, true);
631
631
  }
632
632
  };
633
633
  var factory = (options) => new Ignore2(options);
634
- var isPathValid = (path8) => checkPath(path8 && checkPath.convert(path8), path8, RETURN_FALSE);
634
+ var isPathValid = (path9) => checkPath(path9 && checkPath.convert(path9), path9, RETURN_FALSE);
635
635
  var setupWindows = () => {
636
636
  const makePosix = (str) => /^\\\\\?\\/.test(str) || /["<>|\u0000-\u001F]+/u.test(str) ? str : str.replace(/\\/g, "/");
637
637
  checkPath.convert = makePosix;
638
638
  const REGEX_TEST_WINDOWS_PATH_ABSOLUTE = /^[a-z]:\//i;
639
- checkPath.isNotRelative = (path8) => REGEX_TEST_WINDOWS_PATH_ABSOLUTE.test(path8) || isNotRelative(path8);
639
+ checkPath.isNotRelative = (path9) => REGEX_TEST_WINDOWS_PATH_ABSOLUTE.test(path9) || isNotRelative(path9);
640
640
  };
641
641
  if (
642
642
  // Detect `process` so that it can run in browsers.
@@ -652,9 +652,10 @@ var require_ignore = __commonJS({
652
652
  });
653
653
 
654
654
  // src/index.ts
655
- import { existsSync as existsSync5, readFileSync as readFileSync5 } from "fs";
656
- import * as path7 from "path";
655
+ import { existsSync as existsSync6, readFileSync as readFileSync6 } from "fs";
656
+ import * as path8 from "path";
657
657
  import * as os3 from "os";
658
+ import { fileURLToPath as fileURLToPath2 } from "url";
658
659
 
659
660
  // src/config/schema.ts
660
661
  var DEFAULT_INCLUDE = [
@@ -692,7 +693,10 @@ function getDefaultIndexingConfig() {
692
693
  maxChunksPerFile: 100,
693
694
  semanticOnly: false,
694
695
  retries: 3,
695
- retryDelayMs: 1e3
696
+ retryDelayMs: 1e3,
697
+ autoGc: true,
698
+ gcIntervalDays: 7,
699
+ gcOrphanThreshold: 100
696
700
  };
697
701
  }
698
702
  function getDefaultSearchConfig() {
@@ -727,7 +731,10 @@ function parseConfig(raw) {
727
731
  maxChunksPerFile: typeof rawIndexing.maxChunksPerFile === "number" ? Math.max(1, rawIndexing.maxChunksPerFile) : defaultIndexing.maxChunksPerFile,
728
732
  semanticOnly: typeof rawIndexing.semanticOnly === "boolean" ? rawIndexing.semanticOnly : defaultIndexing.semanticOnly,
729
733
  retries: typeof rawIndexing.retries === "number" ? rawIndexing.retries : defaultIndexing.retries,
730
- retryDelayMs: typeof rawIndexing.retryDelayMs === "number" ? rawIndexing.retryDelayMs : defaultIndexing.retryDelayMs
734
+ retryDelayMs: typeof rawIndexing.retryDelayMs === "number" ? rawIndexing.retryDelayMs : defaultIndexing.retryDelayMs,
735
+ autoGc: typeof rawIndexing.autoGc === "boolean" ? rawIndexing.autoGc : defaultIndexing.autoGc,
736
+ gcIntervalDays: typeof rawIndexing.gcIntervalDays === "number" ? Math.max(1, rawIndexing.gcIntervalDays) : defaultIndexing.gcIntervalDays,
737
+ gcOrphanThreshold: typeof rawIndexing.gcOrphanThreshold === "number" ? Math.max(0, rawIndexing.gcOrphanThreshold) : defaultIndexing.gcOrphanThreshold
731
738
  };
732
739
  const rawSearch = input.search && typeof input.search === "object" ? input.search : {};
733
740
  const search = {
@@ -2066,34 +2073,36 @@ var GoogleEmbeddingProvider = class {
2066
2073
  };
2067
2074
  }
2068
2075
  async embedBatch(texts) {
2069
- const embeddings = [];
2070
- let totalTokens = 0;
2071
- for (const text of texts) {
2072
- const response = await fetch(
2073
- `${this.credentials.baseUrl}/models/${this.modelInfo.model}:embedContent?key=${this.credentials.apiKey}`,
2074
- {
2075
- method: "POST",
2076
- headers: {
2077
- "Content-Type": "application/json"
2078
- },
2079
- body: JSON.stringify({
2080
- content: {
2081
- parts: [{ text }]
2082
- }
2083
- })
2076
+ const results = await Promise.all(
2077
+ texts.map(async (text) => {
2078
+ const response = await fetch(
2079
+ `${this.credentials.baseUrl}/models/${this.modelInfo.model}:embedContent?key=${this.credentials.apiKey}`,
2080
+ {
2081
+ method: "POST",
2082
+ headers: {
2083
+ "Content-Type": "application/json"
2084
+ },
2085
+ body: JSON.stringify({
2086
+ content: {
2087
+ parts: [{ text }]
2088
+ }
2089
+ })
2090
+ }
2091
+ );
2092
+ if (!response.ok) {
2093
+ const error = await response.text();
2094
+ throw new Error(`Google embedding API error: ${response.status} - ${error}`);
2084
2095
  }
2085
- );
2086
- if (!response.ok) {
2087
- const error = await response.text();
2088
- throw new Error(`Google embedding API error: ${response.status} - ${error}`);
2089
- }
2090
- const data = await response.json();
2091
- embeddings.push(data.embedding.values);
2092
- totalTokens += Math.ceil(text.length / 4);
2093
- }
2096
+ const data = await response.json();
2097
+ return {
2098
+ embedding: data.embedding.values,
2099
+ tokensUsed: Math.ceil(text.length / 4)
2100
+ };
2101
+ })
2102
+ );
2094
2103
  return {
2095
- embeddings,
2096
- totalTokensUsed: totalTokens
2104
+ embeddings: results.map((r) => r.embedding),
2105
+ totalTokensUsed: results.reduce((sum, r) => sum + r.tokensUsed, 0)
2097
2106
  };
2098
2107
  }
2099
2108
  getModelInfo() {
@@ -2127,16 +2136,10 @@ var OllamaEmbeddingProvider = class {
2127
2136
  };
2128
2137
  }
2129
2138
  async embedBatch(texts) {
2130
- const embeddings = [];
2131
- let totalTokens = 0;
2132
- for (const text of texts) {
2133
- const result = await this.embed(text);
2134
- embeddings.push(result.embedding);
2135
- totalTokens += result.tokensUsed;
2136
- }
2139
+ const results = await Promise.all(texts.map((text) => this.embed(text)));
2137
2140
  return {
2138
- embeddings,
2139
- totalTokensUsed: totalTokens
2141
+ embeddings: results.map((r) => r.embedding),
2142
+ totalTokensUsed: results.reduce((sum, r) => sum + r.tokensUsed, 0)
2140
2143
  };
2141
2144
  }
2142
2145
  getModelInfo() {
@@ -2677,12 +2680,20 @@ var Database = class {
2677
2680
  upsertEmbedding(contentHash, embedding, chunkText, model) {
2678
2681
  this.inner.upsertEmbedding(contentHash, embedding, chunkText, model);
2679
2682
  }
2683
+ upsertEmbeddingsBatch(items) {
2684
+ if (items.length === 0) return;
2685
+ this.inner.upsertEmbeddingsBatch(items);
2686
+ }
2680
2687
  getMissingEmbeddings(contentHashes) {
2681
2688
  return this.inner.getMissingEmbeddings(contentHashes);
2682
2689
  }
2683
2690
  upsertChunk(chunk) {
2684
2691
  this.inner.upsertChunk(chunk);
2685
2692
  }
2693
+ upsertChunksBatch(chunks) {
2694
+ if (chunks.length === 0) return;
2695
+ this.inner.upsertChunksBatch(chunks);
2696
+ }
2686
2697
  getChunk(chunkId) {
2687
2698
  return this.inner.getChunk(chunkId) ?? null;
2688
2699
  }
@@ -2695,6 +2706,10 @@ var Database = class {
2695
2706
  addChunksToBranch(branch, chunkIds) {
2696
2707
  this.inner.addChunksToBranch(branch, chunkIds);
2697
2708
  }
2709
+ addChunksToBranchBatch(branch, chunkIds) {
2710
+ if (chunkIds.length === 0) return;
2711
+ this.inner.addChunksToBranchBatch(branch, chunkIds);
2712
+ }
2698
2713
  clearBranch(branch) {
2699
2714
  return this.inner.clearBranch(branch);
2700
2715
  }
@@ -2955,11 +2970,45 @@ var Indexer = class {
2955
2970
  this.currentBranch = "default";
2956
2971
  this.baseBranch = "default";
2957
2972
  }
2973
+ if (this.config.indexing.autoGc) {
2974
+ await this.maybeRunAutoGc();
2975
+ }
2976
+ }
2977
+ async maybeRunAutoGc() {
2978
+ if (!this.database) return;
2979
+ const lastGcTimestamp = this.database.getMetadata("lastGcTimestamp");
2980
+ const now = Date.now();
2981
+ const intervalMs = this.config.indexing.gcIntervalDays * 24 * 60 * 60 * 1e3;
2982
+ let shouldRunGc = false;
2983
+ if (!lastGcTimestamp) {
2984
+ shouldRunGc = true;
2985
+ } else {
2986
+ const lastGcTime = parseInt(lastGcTimestamp, 10);
2987
+ if (!isNaN(lastGcTime) && now - lastGcTime > intervalMs) {
2988
+ shouldRunGc = true;
2989
+ }
2990
+ }
2991
+ if (shouldRunGc) {
2992
+ await this.healthCheck();
2993
+ this.database.setMetadata("lastGcTimestamp", now.toString());
2994
+ }
2995
+ }
2996
+ async maybeRunOrphanGc() {
2997
+ if (!this.database) return;
2998
+ const stats = this.database.getStats();
2999
+ if (!stats) return;
3000
+ const orphanCount = stats.embeddingCount - stats.chunkCount;
3001
+ if (orphanCount > this.config.indexing.gcOrphanThreshold) {
3002
+ this.database.gcOrphanEmbeddings();
3003
+ this.database.gcOrphanChunks();
3004
+ this.database.setMetadata("lastGcTimestamp", Date.now().toString());
3005
+ }
2958
3006
  }
2959
3007
  migrateFromLegacyIndex() {
2960
3008
  if (!this.store || !this.database) return;
2961
3009
  const allMetadata = this.store.getAllMetadata();
2962
3010
  const chunkIds = [];
3011
+ const chunkDataBatch = [];
2963
3012
  for (const { key, metadata } of allMetadata) {
2964
3013
  const chunkData = {
2965
3014
  chunkId: key,
@@ -2971,10 +3020,13 @@ var Indexer = class {
2971
3020
  name: metadata.name,
2972
3021
  language: metadata.language
2973
3022
  };
2974
- this.database.upsertChunk(chunkData);
3023
+ chunkDataBatch.push(chunkData);
2975
3024
  chunkIds.push(key);
2976
3025
  }
2977
- this.database.addChunksToBranch(this.currentBranch || "default", chunkIds);
3026
+ if (chunkDataBatch.length > 0) {
3027
+ this.database.upsertChunksBatch(chunkDataBatch);
3028
+ }
3029
+ this.database.addChunksToBranchBatch(this.currentBranch || "default", chunkIds);
2978
3030
  }
2979
3031
  async ensureInitialized() {
2980
3032
  if (!this.store || !this.provider || !this.invertedIndex || !this.detectedProvider || !this.database) {
@@ -3070,6 +3122,7 @@ var Indexer = class {
3070
3122
  }
3071
3123
  }
3072
3124
  }
3125
+ const chunkDataBatch = [];
3073
3126
  for (const parsed of parsedFiles) {
3074
3127
  currentFilePaths.add(parsed.path);
3075
3128
  if (parsed.chunks.length === 0) {
@@ -3097,7 +3150,7 @@ var Indexer = class {
3097
3150
  name: chunk.name,
3098
3151
  language: chunk.language
3099
3152
  };
3100
- database.upsertChunk(chunkData);
3153
+ chunkDataBatch.push(chunkData);
3101
3154
  if (existingChunks.get(id) === contentHash) {
3102
3155
  fileChunkCount++;
3103
3156
  continue;
@@ -3116,6 +3169,9 @@ var Indexer = class {
3116
3169
  fileChunkCount++;
3117
3170
  }
3118
3171
  }
3172
+ if (chunkDataBatch.length > 0) {
3173
+ database.upsertChunksBatch(chunkDataBatch);
3174
+ }
3119
3175
  let removedCount = 0;
3120
3176
  for (const [chunkId] of existingChunks) {
3121
3177
  if (!currentChunkIds.has(chunkId)) {
@@ -3129,7 +3185,7 @@ var Indexer = class {
3129
3185
  stats.removedChunks = removedCount;
3130
3186
  if (pendingChunks.length === 0 && removedCount === 0) {
3131
3187
  database.clearBranch(this.currentBranch);
3132
- database.addChunksToBranch(this.currentBranch, Array.from(currentChunkIds));
3188
+ database.addChunksToBranchBatch(this.currentBranch, Array.from(currentChunkIds));
3133
3189
  this.fileHashCache = currentFileHashes;
3134
3190
  this.saveFileHashCache();
3135
3191
  stats.durationMs = Date.now() - startTime;
@@ -3144,7 +3200,7 @@ var Indexer = class {
3144
3200
  }
3145
3201
  if (pendingChunks.length === 0) {
3146
3202
  database.clearBranch(this.currentBranch);
3147
- database.addChunksToBranch(this.currentBranch, Array.from(currentChunkIds));
3203
+ database.addChunksToBranchBatch(this.currentBranch, Array.from(currentChunkIds));
3148
3204
  store.save();
3149
3205
  invertedIndex.save();
3150
3206
  this.fileHashCache = currentFileHashes;
@@ -3228,15 +3284,14 @@ var Indexer = class {
3228
3284
  metadata: chunk.metadata
3229
3285
  }));
3230
3286
  store.addBatch(items);
3231
- for (let i = 0; i < batch.length; i++) {
3232
- const chunk = batch[i];
3233
- const embedding = result.embeddings[i];
3234
- database.upsertEmbedding(
3235
- chunk.contentHash,
3236
- float32ArrayToBuffer(embedding),
3237
- chunk.text,
3238
- detectedProvider.modelInfo.model
3239
- );
3287
+ const embeddingBatchItems = batch.map((chunk, i) => ({
3288
+ contentHash: chunk.contentHash,
3289
+ embedding: float32ArrayToBuffer(result.embeddings[i]),
3290
+ chunkText: chunk.text,
3291
+ model: detectedProvider.modelInfo.model
3292
+ }));
3293
+ database.upsertEmbeddingsBatch(embeddingBatchItems);
3294
+ for (const chunk of batch) {
3240
3295
  invertedIndex.removeChunk(chunk.id);
3241
3296
  invertedIndex.addChunk(chunk.id, chunk.content);
3242
3297
  }
@@ -3265,11 +3320,14 @@ var Indexer = class {
3265
3320
  totalChunks: pendingChunks.length
3266
3321
  });
3267
3322
  database.clearBranch(this.currentBranch);
3268
- database.addChunksToBranch(this.currentBranch, Array.from(currentChunkIds));
3323
+ database.addChunksToBranchBatch(this.currentBranch, Array.from(currentChunkIds));
3269
3324
  store.save();
3270
3325
  invertedIndex.save();
3271
3326
  this.fileHashCache = currentFileHashes;
3272
3327
  this.saveFileHashCache();
3328
+ if (this.config.indexing.autoGc && stats.removedChunks > 0) {
3329
+ await this.maybeRunOrphanGc();
3330
+ }
3273
3331
  stats.durationMs = Date.now() - startTime;
3274
3332
  if (stats.failedChunks > 0) {
3275
3333
  stats.failedBatchesPath = this.failedBatchesPath;
@@ -3409,11 +3467,14 @@ var Indexer = class {
3409
3467
  };
3410
3468
  }
3411
3469
  async clearIndex() {
3412
- const { store, invertedIndex } = await this.ensureInitialized();
3470
+ const { store, invertedIndex, database } = await this.ensureInitialized();
3413
3471
  store.clear();
3414
3472
  store.save();
3415
3473
  invertedIndex.clear();
3416
3474
  invertedIndex.save();
3475
+ this.fileHashCache.clear();
3476
+ this.saveFileHashCache();
3477
+ database.clearBranch(this.currentBranch);
3417
3478
  }
3418
3479
  async healthCheck() {
3419
3480
  const { store, invertedIndex, database } = await this.ensureInitialized();
@@ -3605,7 +3666,7 @@ var ReaddirpStream = class extends Readable {
3605
3666
  this._directoryFilter = normalizeFilter(opts.directoryFilter);
3606
3667
  const statMethod = opts.lstat ? lstat : stat;
3607
3668
  if (wantBigintFsStats) {
3608
- this._stat = (path8) => statMethod(path8, { bigint: true });
3669
+ this._stat = (path9) => statMethod(path9, { bigint: true });
3609
3670
  } else {
3610
3671
  this._stat = statMethod;
3611
3672
  }
@@ -3630,8 +3691,8 @@ var ReaddirpStream = class extends Readable {
3630
3691
  const par = this.parent;
3631
3692
  const fil = par && par.files;
3632
3693
  if (fil && fil.length > 0) {
3633
- const { path: path8, depth } = par;
3634
- const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path8));
3694
+ const { path: path9, depth } = par;
3695
+ const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path9));
3635
3696
  const awaited = await Promise.all(slice);
3636
3697
  for (const entry of awaited) {
3637
3698
  if (!entry)
@@ -3671,21 +3732,21 @@ var ReaddirpStream = class extends Readable {
3671
3732
  this.reading = false;
3672
3733
  }
3673
3734
  }
3674
- async _exploreDir(path8, depth) {
3735
+ async _exploreDir(path9, depth) {
3675
3736
  let files;
3676
3737
  try {
3677
- files = await readdir(path8, this._rdOptions);
3738
+ files = await readdir(path9, this._rdOptions);
3678
3739
  } catch (error) {
3679
3740
  this._onError(error);
3680
3741
  }
3681
- return { files, depth, path: path8 };
3742
+ return { files, depth, path: path9 };
3682
3743
  }
3683
- async _formatEntry(dirent, path8) {
3744
+ async _formatEntry(dirent, path9) {
3684
3745
  let entry;
3685
- const basename3 = this._isDirent ? dirent.name : dirent;
3746
+ const basename4 = this._isDirent ? dirent.name : dirent;
3686
3747
  try {
3687
- const fullPath = presolve(pjoin(path8, basename3));
3688
- entry = { path: prelative(this._root, fullPath), fullPath, basename: basename3 };
3748
+ const fullPath = presolve(pjoin(path9, basename4));
3749
+ entry = { path: prelative(this._root, fullPath), fullPath, basename: basename4 };
3689
3750
  entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
3690
3751
  } catch (err) {
3691
3752
  this._onError(err);
@@ -4084,16 +4145,16 @@ var delFromSet = (main, prop, item) => {
4084
4145
  };
4085
4146
  var isEmptySet = (val) => val instanceof Set ? val.size === 0 : !val;
4086
4147
  var FsWatchInstances = /* @__PURE__ */ new Map();
4087
- function createFsWatchInstance(path8, options, listener, errHandler, emitRaw) {
4148
+ function createFsWatchInstance(path9, options, listener, errHandler, emitRaw) {
4088
4149
  const handleEvent = (rawEvent, evPath) => {
4089
- listener(path8);
4090
- emitRaw(rawEvent, evPath, { watchedPath: path8 });
4091
- if (evPath && path8 !== evPath) {
4092
- fsWatchBroadcast(sp.resolve(path8, evPath), KEY_LISTENERS, sp.join(path8, evPath));
4150
+ listener(path9);
4151
+ emitRaw(rawEvent, evPath, { watchedPath: path9 });
4152
+ if (evPath && path9 !== evPath) {
4153
+ fsWatchBroadcast(sp.resolve(path9, evPath), KEY_LISTENERS, sp.join(path9, evPath));
4093
4154
  }
4094
4155
  };
4095
4156
  try {
4096
- return fs_watch(path8, {
4157
+ return fs_watch(path9, {
4097
4158
  persistent: options.persistent
4098
4159
  }, handleEvent);
4099
4160
  } catch (error) {
@@ -4109,12 +4170,12 @@ var fsWatchBroadcast = (fullPath, listenerType, val1, val2, val3) => {
4109
4170
  listener(val1, val2, val3);
4110
4171
  });
4111
4172
  };
4112
- var setFsWatchListener = (path8, fullPath, options, handlers) => {
4173
+ var setFsWatchListener = (path9, fullPath, options, handlers) => {
4113
4174
  const { listener, errHandler, rawEmitter } = handlers;
4114
4175
  let cont = FsWatchInstances.get(fullPath);
4115
4176
  let watcher;
4116
4177
  if (!options.persistent) {
4117
- watcher = createFsWatchInstance(path8, options, listener, errHandler, rawEmitter);
4178
+ watcher = createFsWatchInstance(path9, options, listener, errHandler, rawEmitter);
4118
4179
  if (!watcher)
4119
4180
  return;
4120
4181
  return watcher.close.bind(watcher);
@@ -4125,7 +4186,7 @@ var setFsWatchListener = (path8, fullPath, options, handlers) => {
4125
4186
  addAndConvert(cont, KEY_RAW, rawEmitter);
4126
4187
  } else {
4127
4188
  watcher = createFsWatchInstance(
4128
- path8,
4189
+ path9,
4129
4190
  options,
4130
4191
  fsWatchBroadcast.bind(null, fullPath, KEY_LISTENERS),
4131
4192
  errHandler,
@@ -4140,7 +4201,7 @@ var setFsWatchListener = (path8, fullPath, options, handlers) => {
4140
4201
  cont.watcherUnusable = true;
4141
4202
  if (isWindows && error.code === "EPERM") {
4142
4203
  try {
4143
- const fd = await open(path8, "r");
4204
+ const fd = await open(path9, "r");
4144
4205
  await fd.close();
4145
4206
  broadcastErr(error);
4146
4207
  } catch (err) {
@@ -4171,7 +4232,7 @@ var setFsWatchListener = (path8, fullPath, options, handlers) => {
4171
4232
  };
4172
4233
  };
4173
4234
  var FsWatchFileInstances = /* @__PURE__ */ new Map();
4174
- var setFsWatchFileListener = (path8, fullPath, options, handlers) => {
4235
+ var setFsWatchFileListener = (path9, fullPath, options, handlers) => {
4175
4236
  const { listener, rawEmitter } = handlers;
4176
4237
  let cont = FsWatchFileInstances.get(fullPath);
4177
4238
  const copts = cont && cont.options;
@@ -4193,7 +4254,7 @@ var setFsWatchFileListener = (path8, fullPath, options, handlers) => {
4193
4254
  });
4194
4255
  const currmtime = curr.mtimeMs;
4195
4256
  if (curr.size !== prev.size || currmtime > prev.mtimeMs || currmtime === 0) {
4196
- foreach(cont.listeners, (listener2) => listener2(path8, curr));
4257
+ foreach(cont.listeners, (listener2) => listener2(path9, curr));
4197
4258
  }
4198
4259
  })
4199
4260
  };
@@ -4223,13 +4284,13 @@ var NodeFsHandler = class {
4223
4284
  * @param listener on fs change
4224
4285
  * @returns closer for the watcher instance
4225
4286
  */
4226
- _watchWithNodeFs(path8, listener) {
4287
+ _watchWithNodeFs(path9, listener) {
4227
4288
  const opts = this.fsw.options;
4228
- const directory = sp.dirname(path8);
4229
- const basename3 = sp.basename(path8);
4289
+ const directory = sp.dirname(path9);
4290
+ const basename4 = sp.basename(path9);
4230
4291
  const parent = this.fsw._getWatchedDir(directory);
4231
- parent.add(basename3);
4232
- const absolutePath = sp.resolve(path8);
4292
+ parent.add(basename4);
4293
+ const absolutePath = sp.resolve(path9);
4233
4294
  const options = {
4234
4295
  persistent: opts.persistent
4235
4296
  };
@@ -4238,13 +4299,13 @@ var NodeFsHandler = class {
4238
4299
  let closer;
4239
4300
  if (opts.usePolling) {
4240
4301
  const enableBin = opts.interval !== opts.binaryInterval;
4241
- options.interval = enableBin && isBinaryPath(basename3) ? opts.binaryInterval : opts.interval;
4242
- closer = setFsWatchFileListener(path8, absolutePath, options, {
4302
+ options.interval = enableBin && isBinaryPath(basename4) ? opts.binaryInterval : opts.interval;
4303
+ closer = setFsWatchFileListener(path9, absolutePath, options, {
4243
4304
  listener,
4244
4305
  rawEmitter: this.fsw._emitRaw
4245
4306
  });
4246
4307
  } else {
4247
- closer = setFsWatchListener(path8, absolutePath, options, {
4308
+ closer = setFsWatchListener(path9, absolutePath, options, {
4248
4309
  listener,
4249
4310
  errHandler: this._boundHandleError,
4250
4311
  rawEmitter: this.fsw._emitRaw
@@ -4260,13 +4321,13 @@ var NodeFsHandler = class {
4260
4321
  if (this.fsw.closed) {
4261
4322
  return;
4262
4323
  }
4263
- const dirname4 = sp.dirname(file);
4264
- const basename3 = sp.basename(file);
4265
- const parent = this.fsw._getWatchedDir(dirname4);
4324
+ const dirname5 = sp.dirname(file);
4325
+ const basename4 = sp.basename(file);
4326
+ const parent = this.fsw._getWatchedDir(dirname5);
4266
4327
  let prevStats = stats;
4267
- if (parent.has(basename3))
4328
+ if (parent.has(basename4))
4268
4329
  return;
4269
- const listener = async (path8, newStats) => {
4330
+ const listener = async (path9, newStats) => {
4270
4331
  if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file, 5))
4271
4332
  return;
4272
4333
  if (!newStats || newStats.mtimeMs === 0) {
@@ -4280,18 +4341,18 @@ var NodeFsHandler = class {
4280
4341
  this.fsw._emit(EV.CHANGE, file, newStats2);
4281
4342
  }
4282
4343
  if ((isMacos || isLinux || isFreeBSD) && prevStats.ino !== newStats2.ino) {
4283
- this.fsw._closeFile(path8);
4344
+ this.fsw._closeFile(path9);
4284
4345
  prevStats = newStats2;
4285
4346
  const closer2 = this._watchWithNodeFs(file, listener);
4286
4347
  if (closer2)
4287
- this.fsw._addPathCloser(path8, closer2);
4348
+ this.fsw._addPathCloser(path9, closer2);
4288
4349
  } else {
4289
4350
  prevStats = newStats2;
4290
4351
  }
4291
4352
  } catch (error) {
4292
- this.fsw._remove(dirname4, basename3);
4353
+ this.fsw._remove(dirname5, basename4);
4293
4354
  }
4294
- } else if (parent.has(basename3)) {
4355
+ } else if (parent.has(basename4)) {
4295
4356
  const at = newStats.atimeMs;
4296
4357
  const mt = newStats.mtimeMs;
4297
4358
  if (!at || at <= mt || mt !== prevStats.mtimeMs) {
@@ -4316,7 +4377,7 @@ var NodeFsHandler = class {
4316
4377
  * @param item basename of this item
4317
4378
  * @returns true if no more processing is needed for this entry.
4318
4379
  */
4319
- async _handleSymlink(entry, directory, path8, item) {
4380
+ async _handleSymlink(entry, directory, path9, item) {
4320
4381
  if (this.fsw.closed) {
4321
4382
  return;
4322
4383
  }
@@ -4326,7 +4387,7 @@ var NodeFsHandler = class {
4326
4387
  this.fsw._incrReadyCount();
4327
4388
  let linkPath;
4328
4389
  try {
4329
- linkPath = await fsrealpath(path8);
4390
+ linkPath = await fsrealpath(path9);
4330
4391
  } catch (e) {
4331
4392
  this.fsw._emitReady();
4332
4393
  return true;
@@ -4336,12 +4397,12 @@ var NodeFsHandler = class {
4336
4397
  if (dir.has(item)) {
4337
4398
  if (this.fsw._symlinkPaths.get(full) !== linkPath) {
4338
4399
  this.fsw._symlinkPaths.set(full, linkPath);
4339
- this.fsw._emit(EV.CHANGE, path8, entry.stats);
4400
+ this.fsw._emit(EV.CHANGE, path9, entry.stats);
4340
4401
  }
4341
4402
  } else {
4342
4403
  dir.add(item);
4343
4404
  this.fsw._symlinkPaths.set(full, linkPath);
4344
- this.fsw._emit(EV.ADD, path8, entry.stats);
4405
+ this.fsw._emit(EV.ADD, path9, entry.stats);
4345
4406
  }
4346
4407
  this.fsw._emitReady();
4347
4408
  return true;
@@ -4371,9 +4432,9 @@ var NodeFsHandler = class {
4371
4432
  return;
4372
4433
  }
4373
4434
  const item = entry.path;
4374
- let path8 = sp.join(directory, item);
4435
+ let path9 = sp.join(directory, item);
4375
4436
  current.add(item);
4376
- if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path8, item)) {
4437
+ if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path9, item)) {
4377
4438
  return;
4378
4439
  }
4379
4440
  if (this.fsw.closed) {
@@ -4382,8 +4443,8 @@ var NodeFsHandler = class {
4382
4443
  }
4383
4444
  if (item === target || !target && !previous.has(item)) {
4384
4445
  this.fsw._incrReadyCount();
4385
- path8 = sp.join(dir, sp.relative(dir, path8));
4386
- this._addToNodeFs(path8, initialAdd, wh, depth + 1);
4446
+ path9 = sp.join(dir, sp.relative(dir, path9));
4447
+ this._addToNodeFs(path9, initialAdd, wh, depth + 1);
4387
4448
  }
4388
4449
  }).on(EV.ERROR, this._boundHandleError);
4389
4450
  return new Promise((resolve4, reject) => {
@@ -4452,13 +4513,13 @@ var NodeFsHandler = class {
4452
4513
  * @param depth Child path actually targeted for watch
4453
4514
  * @param target Child path actually targeted for watch
4454
4515
  */
4455
- async _addToNodeFs(path8, initialAdd, priorWh, depth, target) {
4516
+ async _addToNodeFs(path9, initialAdd, priorWh, depth, target) {
4456
4517
  const ready = this.fsw._emitReady;
4457
- if (this.fsw._isIgnored(path8) || this.fsw.closed) {
4518
+ if (this.fsw._isIgnored(path9) || this.fsw.closed) {
4458
4519
  ready();
4459
4520
  return false;
4460
4521
  }
4461
- const wh = this.fsw._getWatchHelpers(path8);
4522
+ const wh = this.fsw._getWatchHelpers(path9);
4462
4523
  if (priorWh) {
4463
4524
  wh.filterPath = (entry) => priorWh.filterPath(entry);
4464
4525
  wh.filterDir = (entry) => priorWh.filterDir(entry);
@@ -4474,8 +4535,8 @@ var NodeFsHandler = class {
4474
4535
  const follow = this.fsw.options.followSymlinks;
4475
4536
  let closer;
4476
4537
  if (stats.isDirectory()) {
4477
- const absPath = sp.resolve(path8);
4478
- const targetPath = follow ? await fsrealpath(path8) : path8;
4538
+ const absPath = sp.resolve(path9);
4539
+ const targetPath = follow ? await fsrealpath(path9) : path9;
4479
4540
  if (this.fsw.closed)
4480
4541
  return;
4481
4542
  closer = await this._handleDir(wh.watchPath, stats, initialAdd, depth, target, wh, targetPath);
@@ -4485,29 +4546,29 @@ var NodeFsHandler = class {
4485
4546
  this.fsw._symlinkPaths.set(absPath, targetPath);
4486
4547
  }
4487
4548
  } else if (stats.isSymbolicLink()) {
4488
- const targetPath = follow ? await fsrealpath(path8) : path8;
4549
+ const targetPath = follow ? await fsrealpath(path9) : path9;
4489
4550
  if (this.fsw.closed)
4490
4551
  return;
4491
4552
  const parent = sp.dirname(wh.watchPath);
4492
4553
  this.fsw._getWatchedDir(parent).add(wh.watchPath);
4493
4554
  this.fsw._emit(EV.ADD, wh.watchPath, stats);
4494
- closer = await this._handleDir(parent, stats, initialAdd, depth, path8, wh, targetPath);
4555
+ closer = await this._handleDir(parent, stats, initialAdd, depth, path9, wh, targetPath);
4495
4556
  if (this.fsw.closed)
4496
4557
  return;
4497
4558
  if (targetPath !== void 0) {
4498
- this.fsw._symlinkPaths.set(sp.resolve(path8), targetPath);
4559
+ this.fsw._symlinkPaths.set(sp.resolve(path9), targetPath);
4499
4560
  }
4500
4561
  } else {
4501
4562
  closer = this._handleFile(wh.watchPath, stats, initialAdd);
4502
4563
  }
4503
4564
  ready();
4504
4565
  if (closer)
4505
- this.fsw._addPathCloser(path8, closer);
4566
+ this.fsw._addPathCloser(path9, closer);
4506
4567
  return false;
4507
4568
  } catch (error) {
4508
4569
  if (this.fsw._handleError(error)) {
4509
4570
  ready();
4510
- return path8;
4571
+ return path9;
4511
4572
  }
4512
4573
  }
4513
4574
  }
@@ -4550,24 +4611,24 @@ function createPattern(matcher) {
4550
4611
  }
4551
4612
  return () => false;
4552
4613
  }
4553
- function normalizePath(path8) {
4554
- if (typeof path8 !== "string")
4614
+ function normalizePath(path9) {
4615
+ if (typeof path9 !== "string")
4555
4616
  throw new Error("string expected");
4556
- path8 = sp2.normalize(path8);
4557
- path8 = path8.replace(/\\/g, "/");
4617
+ path9 = sp2.normalize(path9);
4618
+ path9 = path9.replace(/\\/g, "/");
4558
4619
  let prepend = false;
4559
- if (path8.startsWith("//"))
4620
+ if (path9.startsWith("//"))
4560
4621
  prepend = true;
4561
- path8 = path8.replace(DOUBLE_SLASH_RE, "/");
4622
+ path9 = path9.replace(DOUBLE_SLASH_RE, "/");
4562
4623
  if (prepend)
4563
- path8 = "/" + path8;
4564
- return path8;
4624
+ path9 = "/" + path9;
4625
+ return path9;
4565
4626
  }
4566
4627
  function matchPatterns(patterns, testString, stats) {
4567
- const path8 = normalizePath(testString);
4628
+ const path9 = normalizePath(testString);
4568
4629
  for (let index = 0; index < patterns.length; index++) {
4569
4630
  const pattern = patterns[index];
4570
- if (pattern(path8, stats)) {
4631
+ if (pattern(path9, stats)) {
4571
4632
  return true;
4572
4633
  }
4573
4634
  }
@@ -4605,19 +4666,19 @@ var toUnix = (string) => {
4605
4666
  }
4606
4667
  return str;
4607
4668
  };
4608
- var normalizePathToUnix = (path8) => toUnix(sp2.normalize(toUnix(path8)));
4609
- var normalizeIgnored = (cwd = "") => (path8) => {
4610
- if (typeof path8 === "string") {
4611
- return normalizePathToUnix(sp2.isAbsolute(path8) ? path8 : sp2.join(cwd, path8));
4669
+ var normalizePathToUnix = (path9) => toUnix(sp2.normalize(toUnix(path9)));
4670
+ var normalizeIgnored = (cwd = "") => (path9) => {
4671
+ if (typeof path9 === "string") {
4672
+ return normalizePathToUnix(sp2.isAbsolute(path9) ? path9 : sp2.join(cwd, path9));
4612
4673
  } else {
4613
- return path8;
4674
+ return path9;
4614
4675
  }
4615
4676
  };
4616
- var getAbsolutePath = (path8, cwd) => {
4617
- if (sp2.isAbsolute(path8)) {
4618
- return path8;
4677
+ var getAbsolutePath = (path9, cwd) => {
4678
+ if (sp2.isAbsolute(path9)) {
4679
+ return path9;
4619
4680
  }
4620
- return sp2.join(cwd, path8);
4681
+ return sp2.join(cwd, path9);
4621
4682
  };
4622
4683
  var EMPTY_SET = Object.freeze(/* @__PURE__ */ new Set());
4623
4684
  var DirEntry = class {
@@ -4682,10 +4743,10 @@ var WatchHelper = class {
4682
4743
  dirParts;
4683
4744
  followSymlinks;
4684
4745
  statMethod;
4685
- constructor(path8, follow, fsw) {
4746
+ constructor(path9, follow, fsw) {
4686
4747
  this.fsw = fsw;
4687
- const watchPath = path8;
4688
- this.path = path8 = path8.replace(REPLACER_RE, "");
4748
+ const watchPath = path9;
4749
+ this.path = path9 = path9.replace(REPLACER_RE, "");
4689
4750
  this.watchPath = watchPath;
4690
4751
  this.fullWatchPath = sp2.resolve(watchPath);
4691
4752
  this.dirParts = [];
@@ -4825,20 +4886,20 @@ var FSWatcher = class extends EventEmitter2 {
4825
4886
  this._closePromise = void 0;
4826
4887
  let paths = unifyPaths(paths_);
4827
4888
  if (cwd) {
4828
- paths = paths.map((path8) => {
4829
- const absPath = getAbsolutePath(path8, cwd);
4889
+ paths = paths.map((path9) => {
4890
+ const absPath = getAbsolutePath(path9, cwd);
4830
4891
  return absPath;
4831
4892
  });
4832
4893
  }
4833
- paths.forEach((path8) => {
4834
- this._removeIgnoredPath(path8);
4894
+ paths.forEach((path9) => {
4895
+ this._removeIgnoredPath(path9);
4835
4896
  });
4836
4897
  this._userIgnored = void 0;
4837
4898
  if (!this._readyCount)
4838
4899
  this._readyCount = 0;
4839
4900
  this._readyCount += paths.length;
4840
- Promise.all(paths.map(async (path8) => {
4841
- const res = await this._nodeFsHandler._addToNodeFs(path8, !_internal, void 0, 0, _origAdd);
4901
+ Promise.all(paths.map(async (path9) => {
4902
+ const res = await this._nodeFsHandler._addToNodeFs(path9, !_internal, void 0, 0, _origAdd);
4842
4903
  if (res)
4843
4904
  this._emitReady();
4844
4905
  return res;
@@ -4860,17 +4921,17 @@ var FSWatcher = class extends EventEmitter2 {
4860
4921
  return this;
4861
4922
  const paths = unifyPaths(paths_);
4862
4923
  const { cwd } = this.options;
4863
- paths.forEach((path8) => {
4864
- if (!sp2.isAbsolute(path8) && !this._closers.has(path8)) {
4924
+ paths.forEach((path9) => {
4925
+ if (!sp2.isAbsolute(path9) && !this._closers.has(path9)) {
4865
4926
  if (cwd)
4866
- path8 = sp2.join(cwd, path8);
4867
- path8 = sp2.resolve(path8);
4927
+ path9 = sp2.join(cwd, path9);
4928
+ path9 = sp2.resolve(path9);
4868
4929
  }
4869
- this._closePath(path8);
4870
- this._addIgnoredPath(path8);
4871
- if (this._watched.has(path8)) {
4930
+ this._closePath(path9);
4931
+ this._addIgnoredPath(path9);
4932
+ if (this._watched.has(path9)) {
4872
4933
  this._addIgnoredPath({
4873
- path: path8,
4934
+ path: path9,
4874
4935
  recursive: true
4875
4936
  });
4876
4937
  }
@@ -4934,38 +4995,38 @@ var FSWatcher = class extends EventEmitter2 {
4934
4995
  * @param stats arguments to be passed with event
4935
4996
  * @returns the error if defined, otherwise the value of the FSWatcher instance's `closed` flag
4936
4997
  */
4937
- async _emit(event, path8, stats) {
4998
+ async _emit(event, path9, stats) {
4938
4999
  if (this.closed)
4939
5000
  return;
4940
5001
  const opts = this.options;
4941
5002
  if (isWindows)
4942
- path8 = sp2.normalize(path8);
5003
+ path9 = sp2.normalize(path9);
4943
5004
  if (opts.cwd)
4944
- path8 = sp2.relative(opts.cwd, path8);
4945
- const args = [path8];
5005
+ path9 = sp2.relative(opts.cwd, path9);
5006
+ const args = [path9];
4946
5007
  if (stats != null)
4947
5008
  args.push(stats);
4948
5009
  const awf = opts.awaitWriteFinish;
4949
5010
  let pw;
4950
- if (awf && (pw = this._pendingWrites.get(path8))) {
5011
+ if (awf && (pw = this._pendingWrites.get(path9))) {
4951
5012
  pw.lastChange = /* @__PURE__ */ new Date();
4952
5013
  return this;
4953
5014
  }
4954
5015
  if (opts.atomic) {
4955
5016
  if (event === EVENTS.UNLINK) {
4956
- this._pendingUnlinks.set(path8, [event, ...args]);
5017
+ this._pendingUnlinks.set(path9, [event, ...args]);
4957
5018
  setTimeout(() => {
4958
- this._pendingUnlinks.forEach((entry, path9) => {
5019
+ this._pendingUnlinks.forEach((entry, path10) => {
4959
5020
  this.emit(...entry);
4960
5021
  this.emit(EVENTS.ALL, ...entry);
4961
- this._pendingUnlinks.delete(path9);
5022
+ this._pendingUnlinks.delete(path10);
4962
5023
  });
4963
5024
  }, typeof opts.atomic === "number" ? opts.atomic : 100);
4964
5025
  return this;
4965
5026
  }
4966
- if (event === EVENTS.ADD && this._pendingUnlinks.has(path8)) {
5027
+ if (event === EVENTS.ADD && this._pendingUnlinks.has(path9)) {
4967
5028
  event = EVENTS.CHANGE;
4968
- this._pendingUnlinks.delete(path8);
5029
+ this._pendingUnlinks.delete(path9);
4969
5030
  }
4970
5031
  }
4971
5032
  if (awf && (event === EVENTS.ADD || event === EVENTS.CHANGE) && this._readyEmitted) {
@@ -4983,16 +5044,16 @@ var FSWatcher = class extends EventEmitter2 {
4983
5044
  this.emitWithAll(event, args);
4984
5045
  }
4985
5046
  };
4986
- this._awaitWriteFinish(path8, awf.stabilityThreshold, event, awfEmit);
5047
+ this._awaitWriteFinish(path9, awf.stabilityThreshold, event, awfEmit);
4987
5048
  return this;
4988
5049
  }
4989
5050
  if (event === EVENTS.CHANGE) {
4990
- const isThrottled = !this._throttle(EVENTS.CHANGE, path8, 50);
5051
+ const isThrottled = !this._throttle(EVENTS.CHANGE, path9, 50);
4991
5052
  if (isThrottled)
4992
5053
  return this;
4993
5054
  }
4994
5055
  if (opts.alwaysStat && stats === void 0 && (event === EVENTS.ADD || event === EVENTS.ADD_DIR || event === EVENTS.CHANGE)) {
4995
- const fullPath = opts.cwd ? sp2.join(opts.cwd, path8) : path8;
5056
+ const fullPath = opts.cwd ? sp2.join(opts.cwd, path9) : path9;
4996
5057
  let stats2;
4997
5058
  try {
4998
5059
  stats2 = await stat3(fullPath);
@@ -5023,23 +5084,23 @@ var FSWatcher = class extends EventEmitter2 {
5023
5084
  * @param timeout duration of time to suppress duplicate actions
5024
5085
  * @returns tracking object or false if action should be suppressed
5025
5086
  */
5026
- _throttle(actionType, path8, timeout) {
5087
+ _throttle(actionType, path9, timeout) {
5027
5088
  if (!this._throttled.has(actionType)) {
5028
5089
  this._throttled.set(actionType, /* @__PURE__ */ new Map());
5029
5090
  }
5030
5091
  const action = this._throttled.get(actionType);
5031
5092
  if (!action)
5032
5093
  throw new Error("invalid throttle");
5033
- const actionPath = action.get(path8);
5094
+ const actionPath = action.get(path9);
5034
5095
  if (actionPath) {
5035
5096
  actionPath.count++;
5036
5097
  return false;
5037
5098
  }
5038
5099
  let timeoutObject;
5039
5100
  const clear = () => {
5040
- const item = action.get(path8);
5101
+ const item = action.get(path9);
5041
5102
  const count = item ? item.count : 0;
5042
- action.delete(path8);
5103
+ action.delete(path9);
5043
5104
  clearTimeout(timeoutObject);
5044
5105
  if (item)
5045
5106
  clearTimeout(item.timeoutObject);
@@ -5047,7 +5108,7 @@ var FSWatcher = class extends EventEmitter2 {
5047
5108
  };
5048
5109
  timeoutObject = setTimeout(clear, timeout);
5049
5110
  const thr = { timeoutObject, clear, count: 0 };
5050
- action.set(path8, thr);
5111
+ action.set(path9, thr);
5051
5112
  return thr;
5052
5113
  }
5053
5114
  _incrReadyCount() {
@@ -5061,44 +5122,44 @@ var FSWatcher = class extends EventEmitter2 {
5061
5122
  * @param event
5062
5123
  * @param awfEmit Callback to be called when ready for event to be emitted.
5063
5124
  */
5064
- _awaitWriteFinish(path8, threshold, event, awfEmit) {
5125
+ _awaitWriteFinish(path9, threshold, event, awfEmit) {
5065
5126
  const awf = this.options.awaitWriteFinish;
5066
5127
  if (typeof awf !== "object")
5067
5128
  return;
5068
5129
  const pollInterval = awf.pollInterval;
5069
5130
  let timeoutHandler;
5070
- let fullPath = path8;
5071
- if (this.options.cwd && !sp2.isAbsolute(path8)) {
5072
- fullPath = sp2.join(this.options.cwd, path8);
5131
+ let fullPath = path9;
5132
+ if (this.options.cwd && !sp2.isAbsolute(path9)) {
5133
+ fullPath = sp2.join(this.options.cwd, path9);
5073
5134
  }
5074
5135
  const now = /* @__PURE__ */ new Date();
5075
5136
  const writes = this._pendingWrites;
5076
5137
  function awaitWriteFinishFn(prevStat) {
5077
5138
  statcb(fullPath, (err, curStat) => {
5078
- if (err || !writes.has(path8)) {
5139
+ if (err || !writes.has(path9)) {
5079
5140
  if (err && err.code !== "ENOENT")
5080
5141
  awfEmit(err);
5081
5142
  return;
5082
5143
  }
5083
5144
  const now2 = Number(/* @__PURE__ */ new Date());
5084
5145
  if (prevStat && curStat.size !== prevStat.size) {
5085
- writes.get(path8).lastChange = now2;
5146
+ writes.get(path9).lastChange = now2;
5086
5147
  }
5087
- const pw = writes.get(path8);
5148
+ const pw = writes.get(path9);
5088
5149
  const df = now2 - pw.lastChange;
5089
5150
  if (df >= threshold) {
5090
- writes.delete(path8);
5151
+ writes.delete(path9);
5091
5152
  awfEmit(void 0, curStat);
5092
5153
  } else {
5093
5154
  timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval, curStat);
5094
5155
  }
5095
5156
  });
5096
5157
  }
5097
- if (!writes.has(path8)) {
5098
- writes.set(path8, {
5158
+ if (!writes.has(path9)) {
5159
+ writes.set(path9, {
5099
5160
  lastChange: now,
5100
5161
  cancelWait: () => {
5101
- writes.delete(path8);
5162
+ writes.delete(path9);
5102
5163
  clearTimeout(timeoutHandler);
5103
5164
  return event;
5104
5165
  }
@@ -5109,8 +5170,8 @@ var FSWatcher = class extends EventEmitter2 {
5109
5170
  /**
5110
5171
  * Determines whether user has asked to ignore this path.
5111
5172
  */
5112
- _isIgnored(path8, stats) {
5113
- if (this.options.atomic && DOT_RE.test(path8))
5173
+ _isIgnored(path9, stats) {
5174
+ if (this.options.atomic && DOT_RE.test(path9))
5114
5175
  return true;
5115
5176
  if (!this._userIgnored) {
5116
5177
  const { cwd } = this.options;
@@ -5120,17 +5181,17 @@ var FSWatcher = class extends EventEmitter2 {
5120
5181
  const list = [...ignoredPaths.map(normalizeIgnored(cwd)), ...ignored];
5121
5182
  this._userIgnored = anymatch(list, void 0);
5122
5183
  }
5123
- return this._userIgnored(path8, stats);
5184
+ return this._userIgnored(path9, stats);
5124
5185
  }
5125
- _isntIgnored(path8, stat4) {
5126
- return !this._isIgnored(path8, stat4);
5186
+ _isntIgnored(path9, stat4) {
5187
+ return !this._isIgnored(path9, stat4);
5127
5188
  }
5128
5189
  /**
5129
5190
  * Provides a set of common helpers and properties relating to symlink handling.
5130
5191
  * @param path file or directory pattern being watched
5131
5192
  */
5132
- _getWatchHelpers(path8) {
5133
- return new WatchHelper(path8, this.options.followSymlinks, this);
5193
+ _getWatchHelpers(path9) {
5194
+ return new WatchHelper(path9, this.options.followSymlinks, this);
5134
5195
  }
5135
5196
  // Directory helpers
5136
5197
  // -----------------
@@ -5162,63 +5223,63 @@ var FSWatcher = class extends EventEmitter2 {
5162
5223
  * @param item base path of item/directory
5163
5224
  */
5164
5225
  _remove(directory, item, isDirectory) {
5165
- const path8 = sp2.join(directory, item);
5166
- const fullPath = sp2.resolve(path8);
5167
- isDirectory = isDirectory != null ? isDirectory : this._watched.has(path8) || this._watched.has(fullPath);
5168
- if (!this._throttle("remove", path8, 100))
5226
+ const path9 = sp2.join(directory, item);
5227
+ const fullPath = sp2.resolve(path9);
5228
+ isDirectory = isDirectory != null ? isDirectory : this._watched.has(path9) || this._watched.has(fullPath);
5229
+ if (!this._throttle("remove", path9, 100))
5169
5230
  return;
5170
5231
  if (!isDirectory && this._watched.size === 1) {
5171
5232
  this.add(directory, item, true);
5172
5233
  }
5173
- const wp = this._getWatchedDir(path8);
5234
+ const wp = this._getWatchedDir(path9);
5174
5235
  const nestedDirectoryChildren = wp.getChildren();
5175
- nestedDirectoryChildren.forEach((nested) => this._remove(path8, nested));
5236
+ nestedDirectoryChildren.forEach((nested) => this._remove(path9, nested));
5176
5237
  const parent = this._getWatchedDir(directory);
5177
5238
  const wasTracked = parent.has(item);
5178
5239
  parent.remove(item);
5179
5240
  if (this._symlinkPaths.has(fullPath)) {
5180
5241
  this._symlinkPaths.delete(fullPath);
5181
5242
  }
5182
- let relPath = path8;
5243
+ let relPath = path9;
5183
5244
  if (this.options.cwd)
5184
- relPath = sp2.relative(this.options.cwd, path8);
5245
+ relPath = sp2.relative(this.options.cwd, path9);
5185
5246
  if (this.options.awaitWriteFinish && this._pendingWrites.has(relPath)) {
5186
5247
  const event = this._pendingWrites.get(relPath).cancelWait();
5187
5248
  if (event === EVENTS.ADD)
5188
5249
  return;
5189
5250
  }
5190
- this._watched.delete(path8);
5251
+ this._watched.delete(path9);
5191
5252
  this._watched.delete(fullPath);
5192
5253
  const eventName = isDirectory ? EVENTS.UNLINK_DIR : EVENTS.UNLINK;
5193
- if (wasTracked && !this._isIgnored(path8))
5194
- this._emit(eventName, path8);
5195
- this._closePath(path8);
5254
+ if (wasTracked && !this._isIgnored(path9))
5255
+ this._emit(eventName, path9);
5256
+ this._closePath(path9);
5196
5257
  }
5197
5258
  /**
5198
5259
  * Closes all watchers for a path
5199
5260
  */
5200
- _closePath(path8) {
5201
- this._closeFile(path8);
5202
- const dir = sp2.dirname(path8);
5203
- this._getWatchedDir(dir).remove(sp2.basename(path8));
5261
+ _closePath(path9) {
5262
+ this._closeFile(path9);
5263
+ const dir = sp2.dirname(path9);
5264
+ this._getWatchedDir(dir).remove(sp2.basename(path9));
5204
5265
  }
5205
5266
  /**
5206
5267
  * Closes only file-specific watchers
5207
5268
  */
5208
- _closeFile(path8) {
5209
- const closers = this._closers.get(path8);
5269
+ _closeFile(path9) {
5270
+ const closers = this._closers.get(path9);
5210
5271
  if (!closers)
5211
5272
  return;
5212
5273
  closers.forEach((closer) => closer());
5213
- this._closers.delete(path8);
5274
+ this._closers.delete(path9);
5214
5275
  }
5215
- _addPathCloser(path8, closer) {
5276
+ _addPathCloser(path9, closer) {
5216
5277
  if (!closer)
5217
5278
  return;
5218
- let list = this._closers.get(path8);
5279
+ let list = this._closers.get(path9);
5219
5280
  if (!list) {
5220
5281
  list = [];
5221
- this._closers.set(path8, list);
5282
+ this._closers.set(path9, list);
5222
5283
  }
5223
5284
  list.push(closer);
5224
5285
  }
@@ -5313,7 +5374,7 @@ var FileWatcher = class {
5313
5374
  return;
5314
5375
  }
5315
5376
  const changes = Array.from(this.pendingChanges.entries()).map(
5316
- ([path8, type]) => ({ path: path8, type })
5377
+ ([path9, type]) => ({ path: path9, type })
5317
5378
  );
5318
5379
  this.pendingChanges.clear();
5319
5380
  try {
@@ -5493,7 +5554,7 @@ var index_codebase = tool({
5493
5554
  estimateOnly: z.boolean().optional().default(false).describe("Only show cost estimate without indexing"),
5494
5555
  verbose: z.boolean().optional().default(false).describe("Show detailed info about skipped files and parsing failures")
5495
5556
  },
5496
- async execute(args) {
5557
+ async execute(args, context) {
5497
5558
  const indexer = getIndexer();
5498
5559
  if (args.estimateOnly) {
5499
5560
  const estimate = await indexer.estimateCost();
@@ -5502,7 +5563,19 @@ var index_codebase = tool({
5502
5563
  if (args.force) {
5503
5564
  await indexer.clearIndex();
5504
5565
  }
5505
- const stats = await indexer.index();
5566
+ const stats = await indexer.index((progress) => {
5567
+ context.metadata({
5568
+ title: formatProgressTitle(progress),
5569
+ metadata: {
5570
+ phase: progress.phase,
5571
+ filesProcessed: progress.filesProcessed,
5572
+ totalFiles: progress.totalFiles,
5573
+ chunksProcessed: progress.chunksProcessed,
5574
+ totalChunks: progress.totalChunks,
5575
+ percentage: calculatePercentage(progress)
5576
+ }
5577
+ });
5578
+ });
5506
5579
  return formatIndexStats(stats, args.verbose ?? false);
5507
5580
  }
5508
5581
  });
@@ -5601,12 +5674,90 @@ function formatStatus(status) {
5601
5674
  }
5602
5675
  return lines.join("\n");
5603
5676
  }
5677
+ function formatProgressTitle(progress) {
5678
+ switch (progress.phase) {
5679
+ case "scanning":
5680
+ return "Scanning files...";
5681
+ case "parsing":
5682
+ return `Parsing: ${progress.filesProcessed}/${progress.totalFiles} files`;
5683
+ case "embedding":
5684
+ return `Embedding: ${progress.chunksProcessed}/${progress.totalChunks} chunks`;
5685
+ case "storing":
5686
+ return "Storing index...";
5687
+ case "complete":
5688
+ return "Indexing complete";
5689
+ default:
5690
+ return "Indexing...";
5691
+ }
5692
+ }
5693
+ function calculatePercentage(progress) {
5694
+ if (progress.phase === "scanning") return 0;
5695
+ if (progress.phase === "complete") return 100;
5696
+ if (progress.phase === "parsing") {
5697
+ if (progress.totalFiles === 0) return 5;
5698
+ return Math.round(5 + progress.filesProcessed / progress.totalFiles * 15);
5699
+ }
5700
+ if (progress.phase === "embedding") {
5701
+ if (progress.totalChunks === 0) return 20;
5702
+ return Math.round(20 + progress.chunksProcessed / progress.totalChunks * 70);
5703
+ }
5704
+ if (progress.phase === "storing") return 95;
5705
+ return 0;
5706
+ }
5707
+
5708
+ // src/commands/loader.ts
5709
+ import { existsSync as existsSync5, readdirSync as readdirSync2, readFileSync as readFileSync5 } from "fs";
5710
+ import * as path7 from "path";
5711
+ function parseFrontmatter(content) {
5712
+ const frontmatterRegex = /^---\s*\n([\s\S]*?)\n---\s*\n([\s\S]*)$/;
5713
+ const match = content.match(frontmatterRegex);
5714
+ if (!match) {
5715
+ return { frontmatter: {}, body: content.trim() };
5716
+ }
5717
+ const frontmatterLines = match[1].split("\n");
5718
+ const frontmatter = {};
5719
+ for (const line of frontmatterLines) {
5720
+ const colonIndex = line.indexOf(":");
5721
+ if (colonIndex > 0) {
5722
+ const key = line.slice(0, colonIndex).trim();
5723
+ const value = line.slice(colonIndex + 1).trim();
5724
+ frontmatter[key] = value;
5725
+ }
5726
+ }
5727
+ return { frontmatter, body: match[2].trim() };
5728
+ }
5729
+ function loadCommandsFromDirectory(commandsDir) {
5730
+ const commands = /* @__PURE__ */ new Map();
5731
+ if (!existsSync5(commandsDir)) {
5732
+ return commands;
5733
+ }
5734
+ const files = readdirSync2(commandsDir).filter((f) => f.endsWith(".md"));
5735
+ for (const file of files) {
5736
+ const filePath = path7.join(commandsDir, file);
5737
+ const content = readFileSync5(filePath, "utf-8");
5738
+ const { frontmatter, body } = parseFrontmatter(content);
5739
+ const name = path7.basename(file, ".md");
5740
+ const description = frontmatter.description || `Run the ${name} command`;
5741
+ commands.set(name, {
5742
+ description,
5743
+ template: body
5744
+ });
5745
+ }
5746
+ return commands;
5747
+ }
5604
5748
 
5605
5749
  // src/index.ts
5750
+ function getCommandsDir() {
5751
+ let currentDir = process.cwd();
5752
+ if (typeof import.meta !== "undefined" && import.meta.url) {
5753
+ currentDir = path8.dirname(fileURLToPath2(import.meta.url));
5754
+ }
5755
+ return path8.join(currentDir, "..", "commands");
5756
+ }
5606
5757
  function loadJsonFile(filePath) {
5607
5758
  try {
5608
- if (existsSync5(filePath)) {
5609
- const content = readFileSync5(filePath, "utf-8");
5759
+ if (existsSync6(filePath)) {
5760
+ const content = readFileSync6(filePath, "utf-8");
5610
5761
  return JSON.parse(content);
5611
5762
  }
5612
5763
  } catch {
@@ -5614,11 +5765,11 @@ function loadJsonFile(filePath) {
5614
5765
  return null;
5615
5766
  }
5616
5767
  function loadPluginConfig(projectRoot) {
5617
- const projectConfig = loadJsonFile(path7.join(projectRoot, ".opencode", "codebase-index.json"));
5768
+ const projectConfig = loadJsonFile(path8.join(projectRoot, ".opencode", "codebase-index.json"));
5618
5769
  if (projectConfig) {
5619
5770
  return projectConfig;
5620
5771
  }
5621
- const globalConfigPath = path7.join(os3.homedir(), ".config", "opencode", "codebase-index.json");
5772
+ const globalConfigPath = path8.join(os3.homedir(), ".config", "opencode", "codebase-index.json");
5622
5773
  const globalConfig = loadJsonFile(globalConfigPath);
5623
5774
  if (globalConfig) {
5624
5775
  return globalConfig;
@@ -5650,36 +5801,11 @@ var plugin = async ({ directory }) => {
5650
5801
  },
5651
5802
  async config(cfg) {
5652
5803
  cfg.command = cfg.command ?? {};
5653
- cfg.command["search"] = {
5654
- description: "Search codebase by meaning using semantic search",
5655
- template: `Use the \`codebase_search\` tool to find code related to: $ARGUMENTS
5656
-
5657
- If the index doesn't exist yet, run \`index_codebase\` first.
5658
-
5659
- Return the most relevant results with file paths and line numbers.`
5660
- };
5661
- cfg.command["find"] = {
5662
- description: "Find code using hybrid approach (semantic + grep)",
5663
- template: `Find code related to: $ARGUMENTS
5664
-
5665
- Strategy:
5666
- 1. First use \`codebase_search\` to find semantically related code
5667
- 2. From the results, identify specific function/class names
5668
- 3. Use grep to find all occurrences of those identifiers
5669
- 4. Combine findings into a comprehensive answer
5670
-
5671
- If the semantic index doesn't exist, run \`index_codebase\` first.`
5672
- };
5673
- cfg.command["index"] = {
5674
- description: "Index the codebase for semantic search",
5675
- template: `Run the \`index_codebase\` tool to create or update the semantic search index.
5676
-
5677
- Show progress and final statistics including:
5678
- - Number of files processed
5679
- - Number of chunks indexed
5680
- - Tokens used
5681
- - Duration`
5682
- };
5804
+ const commandsDir = getCommandsDir();
5805
+ const commands = loadCommandsFromDirectory(commandsDir);
5806
+ for (const [name, definition] of commands) {
5807
+ cfg.command[name] = definition;
5808
+ }
5683
5809
  }
5684
5810
  };
5685
5811
  };