opencode-codebase-index 0.2.4 → 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/README.md +152 -1
- package/commands/find.md +17 -5
- package/commands/index.md +16 -6
- package/commands/search.md +18 -3
- package/commands/status.md +15 -0
- package/dist/index.cjs +421 -277
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +420 -277
- package/dist/index.js.map +1 -1
- package/native/codebase-index-native.darwin-arm64.node +0 -0
- package/native/codebase-index-native.darwin-x64.node +0 -0
- package/native/codebase-index-native.linux-arm64-gnu.node +0 -0
- package/native/codebase-index-native.linux-x64-gnu.node +0 -0
- package/native/codebase-index-native.win32-x64-msvc.node +0 -0
- package/package.json +1 -1
- package/skill/SKILL.md +101 -1
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(
|
|
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(
|
|
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 = (
|
|
525
|
-
if (!isString(
|
|
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 (!
|
|
531
|
+
if (!path9) {
|
|
532
532
|
return doThrow(`path must not be empty`, TypeError);
|
|
533
533
|
}
|
|
534
|
-
if (checkPath.isNotRelative(
|
|
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 = (
|
|
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
|
|
573
|
+
const path9 = originalPath && checkPath.convert(originalPath);
|
|
574
574
|
checkPath(
|
|
575
|
-
|
|
575
|
+
path9,
|
|
576
576
|
originalPath,
|
|
577
577
|
this._strictPathCheck ? throwError : RETURN_FALSE
|
|
578
578
|
);
|
|
579
|
-
return this._t(
|
|
579
|
+
return this._t(path9, cache, checkUnignored, slices);
|
|
580
580
|
}
|
|
581
|
-
checkIgnore(
|
|
582
|
-
if (!REGEX_TEST_TRAILING_SLASH.test(
|
|
583
|
-
return this.test(
|
|
581
|
+
checkIgnore(path9) {
|
|
582
|
+
if (!REGEX_TEST_TRAILING_SLASH.test(path9)) {
|
|
583
|
+
return this.test(path9);
|
|
584
584
|
}
|
|
585
|
-
const slices =
|
|
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(
|
|
598
|
+
return this._rules.test(path9, false, MODE_CHECK_IGNORE);
|
|
599
599
|
}
|
|
600
|
-
_t(
|
|
601
|
-
if (
|
|
602
|
-
return cache[
|
|
600
|
+
_t(path9, cache, checkUnignored, slices) {
|
|
601
|
+
if (path9 in cache) {
|
|
602
|
+
return cache[path9];
|
|
603
603
|
}
|
|
604
604
|
if (!slices) {
|
|
605
|
-
slices =
|
|
605
|
+
slices = path9.split(SLASH2).filter(Boolean);
|
|
606
606
|
}
|
|
607
607
|
slices.pop();
|
|
608
608
|
if (!slices.length) {
|
|
609
|
-
return cache[
|
|
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[
|
|
617
|
+
return cache[path9] = parent.ignored ? parent : this._rules.test(path9, checkUnignored, MODE_IGNORE);
|
|
618
618
|
}
|
|
619
|
-
ignores(
|
|
620
|
-
return this._test(
|
|
619
|
+
ignores(path9) {
|
|
620
|
+
return this._test(path9, this._ignoreCache, false).ignored;
|
|
621
621
|
}
|
|
622
622
|
createFilter() {
|
|
623
|
-
return (
|
|
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(
|
|
630
|
-
return this._test(
|
|
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 = (
|
|
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 = (
|
|
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
|
|
656
|
-
import * as
|
|
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
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
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
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
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:
|
|
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
|
|
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:
|
|
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
|
}
|
|
@@ -2899,6 +2914,20 @@ var Indexer = class {
|
|
|
2899
2914
|
});
|
|
2900
2915
|
this.saveFailedBatches(existing);
|
|
2901
2916
|
}
|
|
2917
|
+
getProviderRateLimits(provider) {
|
|
2918
|
+
switch (provider) {
|
|
2919
|
+
case "github-copilot":
|
|
2920
|
+
return { concurrency: 1, intervalMs: 4e3, minRetryMs: 5e3, maxRetryMs: 6e4 };
|
|
2921
|
+
case "openai":
|
|
2922
|
+
return { concurrency: 3, intervalMs: 500, minRetryMs: 1e3, maxRetryMs: 3e4 };
|
|
2923
|
+
case "google":
|
|
2924
|
+
return { concurrency: 5, intervalMs: 200, minRetryMs: 1e3, maxRetryMs: 3e4 };
|
|
2925
|
+
case "ollama":
|
|
2926
|
+
return { concurrency: 5, intervalMs: 0, minRetryMs: 500, maxRetryMs: 5e3 };
|
|
2927
|
+
default:
|
|
2928
|
+
return { concurrency: 3, intervalMs: 1e3, minRetryMs: 1e3, maxRetryMs: 3e4 };
|
|
2929
|
+
}
|
|
2930
|
+
}
|
|
2902
2931
|
async initialize() {
|
|
2903
2932
|
this.detectedProvider = await detectEmbeddingProvider(this.config.embeddingProvider);
|
|
2904
2933
|
if (!this.detectedProvider) {
|
|
@@ -2941,11 +2970,45 @@ var Indexer = class {
|
|
|
2941
2970
|
this.currentBranch = "default";
|
|
2942
2971
|
this.baseBranch = "default";
|
|
2943
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
|
+
}
|
|
2944
3006
|
}
|
|
2945
3007
|
migrateFromLegacyIndex() {
|
|
2946
3008
|
if (!this.store || !this.database) return;
|
|
2947
3009
|
const allMetadata = this.store.getAllMetadata();
|
|
2948
3010
|
const chunkIds = [];
|
|
3011
|
+
const chunkDataBatch = [];
|
|
2949
3012
|
for (const { key, metadata } of allMetadata) {
|
|
2950
3013
|
const chunkData = {
|
|
2951
3014
|
chunkId: key,
|
|
@@ -2957,10 +3020,13 @@ var Indexer = class {
|
|
|
2957
3020
|
name: metadata.name,
|
|
2958
3021
|
language: metadata.language
|
|
2959
3022
|
};
|
|
2960
|
-
|
|
3023
|
+
chunkDataBatch.push(chunkData);
|
|
2961
3024
|
chunkIds.push(key);
|
|
2962
3025
|
}
|
|
2963
|
-
|
|
3026
|
+
if (chunkDataBatch.length > 0) {
|
|
3027
|
+
this.database.upsertChunksBatch(chunkDataBatch);
|
|
3028
|
+
}
|
|
3029
|
+
this.database.addChunksToBranchBatch(this.currentBranch || "default", chunkIds);
|
|
2964
3030
|
}
|
|
2965
3031
|
async ensureInitialized() {
|
|
2966
3032
|
if (!this.store || !this.provider || !this.invertedIndex || !this.detectedProvider || !this.database) {
|
|
@@ -3056,6 +3122,7 @@ var Indexer = class {
|
|
|
3056
3122
|
}
|
|
3057
3123
|
}
|
|
3058
3124
|
}
|
|
3125
|
+
const chunkDataBatch = [];
|
|
3059
3126
|
for (const parsed of parsedFiles) {
|
|
3060
3127
|
currentFilePaths.add(parsed.path);
|
|
3061
3128
|
if (parsed.chunks.length === 0) {
|
|
@@ -3083,7 +3150,7 @@ var Indexer = class {
|
|
|
3083
3150
|
name: chunk.name,
|
|
3084
3151
|
language: chunk.language
|
|
3085
3152
|
};
|
|
3086
|
-
|
|
3153
|
+
chunkDataBatch.push(chunkData);
|
|
3087
3154
|
if (existingChunks.get(id) === contentHash) {
|
|
3088
3155
|
fileChunkCount++;
|
|
3089
3156
|
continue;
|
|
@@ -3102,6 +3169,9 @@ var Indexer = class {
|
|
|
3102
3169
|
fileChunkCount++;
|
|
3103
3170
|
}
|
|
3104
3171
|
}
|
|
3172
|
+
if (chunkDataBatch.length > 0) {
|
|
3173
|
+
database.upsertChunksBatch(chunkDataBatch);
|
|
3174
|
+
}
|
|
3105
3175
|
let removedCount = 0;
|
|
3106
3176
|
for (const [chunkId] of existingChunks) {
|
|
3107
3177
|
if (!currentChunkIds.has(chunkId)) {
|
|
@@ -3115,7 +3185,7 @@ var Indexer = class {
|
|
|
3115
3185
|
stats.removedChunks = removedCount;
|
|
3116
3186
|
if (pendingChunks.length === 0 && removedCount === 0) {
|
|
3117
3187
|
database.clearBranch(this.currentBranch);
|
|
3118
|
-
database.
|
|
3188
|
+
database.addChunksToBranchBatch(this.currentBranch, Array.from(currentChunkIds));
|
|
3119
3189
|
this.fileHashCache = currentFileHashes;
|
|
3120
3190
|
this.saveFileHashCache();
|
|
3121
3191
|
stats.durationMs = Date.now() - startTime;
|
|
@@ -3130,7 +3200,7 @@ var Indexer = class {
|
|
|
3130
3200
|
}
|
|
3131
3201
|
if (pendingChunks.length === 0) {
|
|
3132
3202
|
database.clearBranch(this.currentBranch);
|
|
3133
|
-
database.
|
|
3203
|
+
database.addChunksToBranchBatch(this.currentBranch, Array.from(currentChunkIds));
|
|
3134
3204
|
store.save();
|
|
3135
3205
|
invertedIndex.save();
|
|
3136
3206
|
this.fileHashCache = currentFileHashes;
|
|
@@ -3166,7 +3236,12 @@ var Indexer = class {
|
|
|
3166
3236
|
stats.indexedChunks++;
|
|
3167
3237
|
}
|
|
3168
3238
|
}
|
|
3169
|
-
const
|
|
3239
|
+
const providerRateLimits = this.getProviderRateLimits(detectedProvider.provider);
|
|
3240
|
+
const queue = new PQueue({
|
|
3241
|
+
concurrency: providerRateLimits.concurrency,
|
|
3242
|
+
interval: providerRateLimits.intervalMs,
|
|
3243
|
+
intervalCap: providerRateLimits.concurrency
|
|
3244
|
+
});
|
|
3170
3245
|
const dynamicBatches = createDynamicBatches(chunksNeedingEmbedding);
|
|
3171
3246
|
let rateLimitBackoffMs = 0;
|
|
3172
3247
|
for (const batch of dynamicBatches) {
|
|
@@ -3182,15 +3257,13 @@ var Indexer = class {
|
|
|
3182
3257
|
},
|
|
3183
3258
|
{
|
|
3184
3259
|
retries: this.config.indexing.retries,
|
|
3185
|
-
minTimeout: Math.max(this.config.indexing.retryDelayMs,
|
|
3186
|
-
|
|
3187
|
-
maxTimeout: 6e4,
|
|
3188
|
-
// Max 60s backoff
|
|
3260
|
+
minTimeout: Math.max(this.config.indexing.retryDelayMs, providerRateLimits.minRetryMs),
|
|
3261
|
+
maxTimeout: providerRateLimits.maxRetryMs,
|
|
3189
3262
|
factor: 2,
|
|
3190
3263
|
onFailedAttempt: (error) => {
|
|
3191
3264
|
const message = getErrorMessage(error);
|
|
3192
3265
|
if (isRateLimitError(error)) {
|
|
3193
|
-
rateLimitBackoffMs = Math.min(
|
|
3266
|
+
rateLimitBackoffMs = Math.min(providerRateLimits.maxRetryMs, (rateLimitBackoffMs || providerRateLimits.minRetryMs) * 2);
|
|
3194
3267
|
console.error(
|
|
3195
3268
|
`Rate limited (attempt ${error.attemptNumber}/${error.retriesLeft + error.attemptNumber}): waiting ${rateLimitBackoffMs / 1e3}s before retry...`
|
|
3196
3269
|
);
|
|
@@ -3211,15 +3284,14 @@ var Indexer = class {
|
|
|
3211
3284
|
metadata: chunk.metadata
|
|
3212
3285
|
}));
|
|
3213
3286
|
store.addBatch(items);
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
|
|
3217
|
-
|
|
3218
|
-
|
|
3219
|
-
|
|
3220
|
-
|
|
3221
|
-
|
|
3222
|
-
);
|
|
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) {
|
|
3223
3295
|
invertedIndex.removeChunk(chunk.id);
|
|
3224
3296
|
invertedIndex.addChunk(chunk.id, chunk.content);
|
|
3225
3297
|
}
|
|
@@ -3248,11 +3320,14 @@ var Indexer = class {
|
|
|
3248
3320
|
totalChunks: pendingChunks.length
|
|
3249
3321
|
});
|
|
3250
3322
|
database.clearBranch(this.currentBranch);
|
|
3251
|
-
database.
|
|
3323
|
+
database.addChunksToBranchBatch(this.currentBranch, Array.from(currentChunkIds));
|
|
3252
3324
|
store.save();
|
|
3253
3325
|
invertedIndex.save();
|
|
3254
3326
|
this.fileHashCache = currentFileHashes;
|
|
3255
3327
|
this.saveFileHashCache();
|
|
3328
|
+
if (this.config.indexing.autoGc && stats.removedChunks > 0) {
|
|
3329
|
+
await this.maybeRunOrphanGc();
|
|
3330
|
+
}
|
|
3256
3331
|
stats.durationMs = Date.now() - startTime;
|
|
3257
3332
|
if (stats.failedChunks > 0) {
|
|
3258
3333
|
stats.failedBatchesPath = this.failedBatchesPath;
|
|
@@ -3392,11 +3467,14 @@ var Indexer = class {
|
|
|
3392
3467
|
};
|
|
3393
3468
|
}
|
|
3394
3469
|
async clearIndex() {
|
|
3395
|
-
const { store, invertedIndex } = await this.ensureInitialized();
|
|
3470
|
+
const { store, invertedIndex, database } = await this.ensureInitialized();
|
|
3396
3471
|
store.clear();
|
|
3397
3472
|
store.save();
|
|
3398
3473
|
invertedIndex.clear();
|
|
3399
3474
|
invertedIndex.save();
|
|
3475
|
+
this.fileHashCache.clear();
|
|
3476
|
+
this.saveFileHashCache();
|
|
3477
|
+
database.clearBranch(this.currentBranch);
|
|
3400
3478
|
}
|
|
3401
3479
|
async healthCheck() {
|
|
3402
3480
|
const { store, invertedIndex, database } = await this.ensureInitialized();
|
|
@@ -3588,7 +3666,7 @@ var ReaddirpStream = class extends Readable {
|
|
|
3588
3666
|
this._directoryFilter = normalizeFilter(opts.directoryFilter);
|
|
3589
3667
|
const statMethod = opts.lstat ? lstat : stat;
|
|
3590
3668
|
if (wantBigintFsStats) {
|
|
3591
|
-
this._stat = (
|
|
3669
|
+
this._stat = (path9) => statMethod(path9, { bigint: true });
|
|
3592
3670
|
} else {
|
|
3593
3671
|
this._stat = statMethod;
|
|
3594
3672
|
}
|
|
@@ -3613,8 +3691,8 @@ var ReaddirpStream = class extends Readable {
|
|
|
3613
3691
|
const par = this.parent;
|
|
3614
3692
|
const fil = par && par.files;
|
|
3615
3693
|
if (fil && fil.length > 0) {
|
|
3616
|
-
const { path:
|
|
3617
|
-
const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent,
|
|
3694
|
+
const { path: path9, depth } = par;
|
|
3695
|
+
const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path9));
|
|
3618
3696
|
const awaited = await Promise.all(slice);
|
|
3619
3697
|
for (const entry of awaited) {
|
|
3620
3698
|
if (!entry)
|
|
@@ -3654,21 +3732,21 @@ var ReaddirpStream = class extends Readable {
|
|
|
3654
3732
|
this.reading = false;
|
|
3655
3733
|
}
|
|
3656
3734
|
}
|
|
3657
|
-
async _exploreDir(
|
|
3735
|
+
async _exploreDir(path9, depth) {
|
|
3658
3736
|
let files;
|
|
3659
3737
|
try {
|
|
3660
|
-
files = await readdir(
|
|
3738
|
+
files = await readdir(path9, this._rdOptions);
|
|
3661
3739
|
} catch (error) {
|
|
3662
3740
|
this._onError(error);
|
|
3663
3741
|
}
|
|
3664
|
-
return { files, depth, path:
|
|
3742
|
+
return { files, depth, path: path9 };
|
|
3665
3743
|
}
|
|
3666
|
-
async _formatEntry(dirent,
|
|
3744
|
+
async _formatEntry(dirent, path9) {
|
|
3667
3745
|
let entry;
|
|
3668
|
-
const
|
|
3746
|
+
const basename4 = this._isDirent ? dirent.name : dirent;
|
|
3669
3747
|
try {
|
|
3670
|
-
const fullPath = presolve(pjoin(
|
|
3671
|
-
entry = { path: prelative(this._root, fullPath), fullPath, basename:
|
|
3748
|
+
const fullPath = presolve(pjoin(path9, basename4));
|
|
3749
|
+
entry = { path: prelative(this._root, fullPath), fullPath, basename: basename4 };
|
|
3672
3750
|
entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
|
|
3673
3751
|
} catch (err) {
|
|
3674
3752
|
this._onError(err);
|
|
@@ -4067,16 +4145,16 @@ var delFromSet = (main, prop, item) => {
|
|
|
4067
4145
|
};
|
|
4068
4146
|
var isEmptySet = (val) => val instanceof Set ? val.size === 0 : !val;
|
|
4069
4147
|
var FsWatchInstances = /* @__PURE__ */ new Map();
|
|
4070
|
-
function createFsWatchInstance(
|
|
4148
|
+
function createFsWatchInstance(path9, options, listener, errHandler, emitRaw) {
|
|
4071
4149
|
const handleEvent = (rawEvent, evPath) => {
|
|
4072
|
-
listener(
|
|
4073
|
-
emitRaw(rawEvent, evPath, { watchedPath:
|
|
4074
|
-
if (evPath &&
|
|
4075
|
-
fsWatchBroadcast(sp.resolve(
|
|
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));
|
|
4076
4154
|
}
|
|
4077
4155
|
};
|
|
4078
4156
|
try {
|
|
4079
|
-
return fs_watch(
|
|
4157
|
+
return fs_watch(path9, {
|
|
4080
4158
|
persistent: options.persistent
|
|
4081
4159
|
}, handleEvent);
|
|
4082
4160
|
} catch (error) {
|
|
@@ -4092,12 +4170,12 @@ var fsWatchBroadcast = (fullPath, listenerType, val1, val2, val3) => {
|
|
|
4092
4170
|
listener(val1, val2, val3);
|
|
4093
4171
|
});
|
|
4094
4172
|
};
|
|
4095
|
-
var setFsWatchListener = (
|
|
4173
|
+
var setFsWatchListener = (path9, fullPath, options, handlers) => {
|
|
4096
4174
|
const { listener, errHandler, rawEmitter } = handlers;
|
|
4097
4175
|
let cont = FsWatchInstances.get(fullPath);
|
|
4098
4176
|
let watcher;
|
|
4099
4177
|
if (!options.persistent) {
|
|
4100
|
-
watcher = createFsWatchInstance(
|
|
4178
|
+
watcher = createFsWatchInstance(path9, options, listener, errHandler, rawEmitter);
|
|
4101
4179
|
if (!watcher)
|
|
4102
4180
|
return;
|
|
4103
4181
|
return watcher.close.bind(watcher);
|
|
@@ -4108,7 +4186,7 @@ var setFsWatchListener = (path8, fullPath, options, handlers) => {
|
|
|
4108
4186
|
addAndConvert(cont, KEY_RAW, rawEmitter);
|
|
4109
4187
|
} else {
|
|
4110
4188
|
watcher = createFsWatchInstance(
|
|
4111
|
-
|
|
4189
|
+
path9,
|
|
4112
4190
|
options,
|
|
4113
4191
|
fsWatchBroadcast.bind(null, fullPath, KEY_LISTENERS),
|
|
4114
4192
|
errHandler,
|
|
@@ -4123,7 +4201,7 @@ var setFsWatchListener = (path8, fullPath, options, handlers) => {
|
|
|
4123
4201
|
cont.watcherUnusable = true;
|
|
4124
4202
|
if (isWindows && error.code === "EPERM") {
|
|
4125
4203
|
try {
|
|
4126
|
-
const fd = await open(
|
|
4204
|
+
const fd = await open(path9, "r");
|
|
4127
4205
|
await fd.close();
|
|
4128
4206
|
broadcastErr(error);
|
|
4129
4207
|
} catch (err) {
|
|
@@ -4154,7 +4232,7 @@ var setFsWatchListener = (path8, fullPath, options, handlers) => {
|
|
|
4154
4232
|
};
|
|
4155
4233
|
};
|
|
4156
4234
|
var FsWatchFileInstances = /* @__PURE__ */ new Map();
|
|
4157
|
-
var setFsWatchFileListener = (
|
|
4235
|
+
var setFsWatchFileListener = (path9, fullPath, options, handlers) => {
|
|
4158
4236
|
const { listener, rawEmitter } = handlers;
|
|
4159
4237
|
let cont = FsWatchFileInstances.get(fullPath);
|
|
4160
4238
|
const copts = cont && cont.options;
|
|
@@ -4176,7 +4254,7 @@ var setFsWatchFileListener = (path8, fullPath, options, handlers) => {
|
|
|
4176
4254
|
});
|
|
4177
4255
|
const currmtime = curr.mtimeMs;
|
|
4178
4256
|
if (curr.size !== prev.size || currmtime > prev.mtimeMs || currmtime === 0) {
|
|
4179
|
-
foreach(cont.listeners, (listener2) => listener2(
|
|
4257
|
+
foreach(cont.listeners, (listener2) => listener2(path9, curr));
|
|
4180
4258
|
}
|
|
4181
4259
|
})
|
|
4182
4260
|
};
|
|
@@ -4206,13 +4284,13 @@ var NodeFsHandler = class {
|
|
|
4206
4284
|
* @param listener on fs change
|
|
4207
4285
|
* @returns closer for the watcher instance
|
|
4208
4286
|
*/
|
|
4209
|
-
_watchWithNodeFs(
|
|
4287
|
+
_watchWithNodeFs(path9, listener) {
|
|
4210
4288
|
const opts = this.fsw.options;
|
|
4211
|
-
const directory = sp.dirname(
|
|
4212
|
-
const
|
|
4289
|
+
const directory = sp.dirname(path9);
|
|
4290
|
+
const basename4 = sp.basename(path9);
|
|
4213
4291
|
const parent = this.fsw._getWatchedDir(directory);
|
|
4214
|
-
parent.add(
|
|
4215
|
-
const absolutePath = sp.resolve(
|
|
4292
|
+
parent.add(basename4);
|
|
4293
|
+
const absolutePath = sp.resolve(path9);
|
|
4216
4294
|
const options = {
|
|
4217
4295
|
persistent: opts.persistent
|
|
4218
4296
|
};
|
|
@@ -4221,13 +4299,13 @@ var NodeFsHandler = class {
|
|
|
4221
4299
|
let closer;
|
|
4222
4300
|
if (opts.usePolling) {
|
|
4223
4301
|
const enableBin = opts.interval !== opts.binaryInterval;
|
|
4224
|
-
options.interval = enableBin && isBinaryPath(
|
|
4225
|
-
closer = setFsWatchFileListener(
|
|
4302
|
+
options.interval = enableBin && isBinaryPath(basename4) ? opts.binaryInterval : opts.interval;
|
|
4303
|
+
closer = setFsWatchFileListener(path9, absolutePath, options, {
|
|
4226
4304
|
listener,
|
|
4227
4305
|
rawEmitter: this.fsw._emitRaw
|
|
4228
4306
|
});
|
|
4229
4307
|
} else {
|
|
4230
|
-
closer = setFsWatchListener(
|
|
4308
|
+
closer = setFsWatchListener(path9, absolutePath, options, {
|
|
4231
4309
|
listener,
|
|
4232
4310
|
errHandler: this._boundHandleError,
|
|
4233
4311
|
rawEmitter: this.fsw._emitRaw
|
|
@@ -4243,13 +4321,13 @@ var NodeFsHandler = class {
|
|
|
4243
4321
|
if (this.fsw.closed) {
|
|
4244
4322
|
return;
|
|
4245
4323
|
}
|
|
4246
|
-
const
|
|
4247
|
-
const
|
|
4248
|
-
const parent = this.fsw._getWatchedDir(
|
|
4324
|
+
const dirname5 = sp.dirname(file);
|
|
4325
|
+
const basename4 = sp.basename(file);
|
|
4326
|
+
const parent = this.fsw._getWatchedDir(dirname5);
|
|
4249
4327
|
let prevStats = stats;
|
|
4250
|
-
if (parent.has(
|
|
4328
|
+
if (parent.has(basename4))
|
|
4251
4329
|
return;
|
|
4252
|
-
const listener = async (
|
|
4330
|
+
const listener = async (path9, newStats) => {
|
|
4253
4331
|
if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file, 5))
|
|
4254
4332
|
return;
|
|
4255
4333
|
if (!newStats || newStats.mtimeMs === 0) {
|
|
@@ -4263,18 +4341,18 @@ var NodeFsHandler = class {
|
|
|
4263
4341
|
this.fsw._emit(EV.CHANGE, file, newStats2);
|
|
4264
4342
|
}
|
|
4265
4343
|
if ((isMacos || isLinux || isFreeBSD) && prevStats.ino !== newStats2.ino) {
|
|
4266
|
-
this.fsw._closeFile(
|
|
4344
|
+
this.fsw._closeFile(path9);
|
|
4267
4345
|
prevStats = newStats2;
|
|
4268
4346
|
const closer2 = this._watchWithNodeFs(file, listener);
|
|
4269
4347
|
if (closer2)
|
|
4270
|
-
this.fsw._addPathCloser(
|
|
4348
|
+
this.fsw._addPathCloser(path9, closer2);
|
|
4271
4349
|
} else {
|
|
4272
4350
|
prevStats = newStats2;
|
|
4273
4351
|
}
|
|
4274
4352
|
} catch (error) {
|
|
4275
|
-
this.fsw._remove(
|
|
4353
|
+
this.fsw._remove(dirname5, basename4);
|
|
4276
4354
|
}
|
|
4277
|
-
} else if (parent.has(
|
|
4355
|
+
} else if (parent.has(basename4)) {
|
|
4278
4356
|
const at = newStats.atimeMs;
|
|
4279
4357
|
const mt = newStats.mtimeMs;
|
|
4280
4358
|
if (!at || at <= mt || mt !== prevStats.mtimeMs) {
|
|
@@ -4299,7 +4377,7 @@ var NodeFsHandler = class {
|
|
|
4299
4377
|
* @param item basename of this item
|
|
4300
4378
|
* @returns true if no more processing is needed for this entry.
|
|
4301
4379
|
*/
|
|
4302
|
-
async _handleSymlink(entry, directory,
|
|
4380
|
+
async _handleSymlink(entry, directory, path9, item) {
|
|
4303
4381
|
if (this.fsw.closed) {
|
|
4304
4382
|
return;
|
|
4305
4383
|
}
|
|
@@ -4309,7 +4387,7 @@ var NodeFsHandler = class {
|
|
|
4309
4387
|
this.fsw._incrReadyCount();
|
|
4310
4388
|
let linkPath;
|
|
4311
4389
|
try {
|
|
4312
|
-
linkPath = await fsrealpath(
|
|
4390
|
+
linkPath = await fsrealpath(path9);
|
|
4313
4391
|
} catch (e) {
|
|
4314
4392
|
this.fsw._emitReady();
|
|
4315
4393
|
return true;
|
|
@@ -4319,12 +4397,12 @@ var NodeFsHandler = class {
|
|
|
4319
4397
|
if (dir.has(item)) {
|
|
4320
4398
|
if (this.fsw._symlinkPaths.get(full) !== linkPath) {
|
|
4321
4399
|
this.fsw._symlinkPaths.set(full, linkPath);
|
|
4322
|
-
this.fsw._emit(EV.CHANGE,
|
|
4400
|
+
this.fsw._emit(EV.CHANGE, path9, entry.stats);
|
|
4323
4401
|
}
|
|
4324
4402
|
} else {
|
|
4325
4403
|
dir.add(item);
|
|
4326
4404
|
this.fsw._symlinkPaths.set(full, linkPath);
|
|
4327
|
-
this.fsw._emit(EV.ADD,
|
|
4405
|
+
this.fsw._emit(EV.ADD, path9, entry.stats);
|
|
4328
4406
|
}
|
|
4329
4407
|
this.fsw._emitReady();
|
|
4330
4408
|
return true;
|
|
@@ -4354,9 +4432,9 @@ var NodeFsHandler = class {
|
|
|
4354
4432
|
return;
|
|
4355
4433
|
}
|
|
4356
4434
|
const item = entry.path;
|
|
4357
|
-
let
|
|
4435
|
+
let path9 = sp.join(directory, item);
|
|
4358
4436
|
current.add(item);
|
|
4359
|
-
if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory,
|
|
4437
|
+
if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path9, item)) {
|
|
4360
4438
|
return;
|
|
4361
4439
|
}
|
|
4362
4440
|
if (this.fsw.closed) {
|
|
@@ -4365,8 +4443,8 @@ var NodeFsHandler = class {
|
|
|
4365
4443
|
}
|
|
4366
4444
|
if (item === target || !target && !previous.has(item)) {
|
|
4367
4445
|
this.fsw._incrReadyCount();
|
|
4368
|
-
|
|
4369
|
-
this._addToNodeFs(
|
|
4446
|
+
path9 = sp.join(dir, sp.relative(dir, path9));
|
|
4447
|
+
this._addToNodeFs(path9, initialAdd, wh, depth + 1);
|
|
4370
4448
|
}
|
|
4371
4449
|
}).on(EV.ERROR, this._boundHandleError);
|
|
4372
4450
|
return new Promise((resolve4, reject) => {
|
|
@@ -4435,13 +4513,13 @@ var NodeFsHandler = class {
|
|
|
4435
4513
|
* @param depth Child path actually targeted for watch
|
|
4436
4514
|
* @param target Child path actually targeted for watch
|
|
4437
4515
|
*/
|
|
4438
|
-
async _addToNodeFs(
|
|
4516
|
+
async _addToNodeFs(path9, initialAdd, priorWh, depth, target) {
|
|
4439
4517
|
const ready = this.fsw._emitReady;
|
|
4440
|
-
if (this.fsw._isIgnored(
|
|
4518
|
+
if (this.fsw._isIgnored(path9) || this.fsw.closed) {
|
|
4441
4519
|
ready();
|
|
4442
4520
|
return false;
|
|
4443
4521
|
}
|
|
4444
|
-
const wh = this.fsw._getWatchHelpers(
|
|
4522
|
+
const wh = this.fsw._getWatchHelpers(path9);
|
|
4445
4523
|
if (priorWh) {
|
|
4446
4524
|
wh.filterPath = (entry) => priorWh.filterPath(entry);
|
|
4447
4525
|
wh.filterDir = (entry) => priorWh.filterDir(entry);
|
|
@@ -4457,8 +4535,8 @@ var NodeFsHandler = class {
|
|
|
4457
4535
|
const follow = this.fsw.options.followSymlinks;
|
|
4458
4536
|
let closer;
|
|
4459
4537
|
if (stats.isDirectory()) {
|
|
4460
|
-
const absPath = sp.resolve(
|
|
4461
|
-
const targetPath = follow ? await fsrealpath(
|
|
4538
|
+
const absPath = sp.resolve(path9);
|
|
4539
|
+
const targetPath = follow ? await fsrealpath(path9) : path9;
|
|
4462
4540
|
if (this.fsw.closed)
|
|
4463
4541
|
return;
|
|
4464
4542
|
closer = await this._handleDir(wh.watchPath, stats, initialAdd, depth, target, wh, targetPath);
|
|
@@ -4468,29 +4546,29 @@ var NodeFsHandler = class {
|
|
|
4468
4546
|
this.fsw._symlinkPaths.set(absPath, targetPath);
|
|
4469
4547
|
}
|
|
4470
4548
|
} else if (stats.isSymbolicLink()) {
|
|
4471
|
-
const targetPath = follow ? await fsrealpath(
|
|
4549
|
+
const targetPath = follow ? await fsrealpath(path9) : path9;
|
|
4472
4550
|
if (this.fsw.closed)
|
|
4473
4551
|
return;
|
|
4474
4552
|
const parent = sp.dirname(wh.watchPath);
|
|
4475
4553
|
this.fsw._getWatchedDir(parent).add(wh.watchPath);
|
|
4476
4554
|
this.fsw._emit(EV.ADD, wh.watchPath, stats);
|
|
4477
|
-
closer = await this._handleDir(parent, stats, initialAdd, depth,
|
|
4555
|
+
closer = await this._handleDir(parent, stats, initialAdd, depth, path9, wh, targetPath);
|
|
4478
4556
|
if (this.fsw.closed)
|
|
4479
4557
|
return;
|
|
4480
4558
|
if (targetPath !== void 0) {
|
|
4481
|
-
this.fsw._symlinkPaths.set(sp.resolve(
|
|
4559
|
+
this.fsw._symlinkPaths.set(sp.resolve(path9), targetPath);
|
|
4482
4560
|
}
|
|
4483
4561
|
} else {
|
|
4484
4562
|
closer = this._handleFile(wh.watchPath, stats, initialAdd);
|
|
4485
4563
|
}
|
|
4486
4564
|
ready();
|
|
4487
4565
|
if (closer)
|
|
4488
|
-
this.fsw._addPathCloser(
|
|
4566
|
+
this.fsw._addPathCloser(path9, closer);
|
|
4489
4567
|
return false;
|
|
4490
4568
|
} catch (error) {
|
|
4491
4569
|
if (this.fsw._handleError(error)) {
|
|
4492
4570
|
ready();
|
|
4493
|
-
return
|
|
4571
|
+
return path9;
|
|
4494
4572
|
}
|
|
4495
4573
|
}
|
|
4496
4574
|
}
|
|
@@ -4533,24 +4611,24 @@ function createPattern(matcher) {
|
|
|
4533
4611
|
}
|
|
4534
4612
|
return () => false;
|
|
4535
4613
|
}
|
|
4536
|
-
function normalizePath(
|
|
4537
|
-
if (typeof
|
|
4614
|
+
function normalizePath(path9) {
|
|
4615
|
+
if (typeof path9 !== "string")
|
|
4538
4616
|
throw new Error("string expected");
|
|
4539
|
-
|
|
4540
|
-
|
|
4617
|
+
path9 = sp2.normalize(path9);
|
|
4618
|
+
path9 = path9.replace(/\\/g, "/");
|
|
4541
4619
|
let prepend = false;
|
|
4542
|
-
if (
|
|
4620
|
+
if (path9.startsWith("//"))
|
|
4543
4621
|
prepend = true;
|
|
4544
|
-
|
|
4622
|
+
path9 = path9.replace(DOUBLE_SLASH_RE, "/");
|
|
4545
4623
|
if (prepend)
|
|
4546
|
-
|
|
4547
|
-
return
|
|
4624
|
+
path9 = "/" + path9;
|
|
4625
|
+
return path9;
|
|
4548
4626
|
}
|
|
4549
4627
|
function matchPatterns(patterns, testString, stats) {
|
|
4550
|
-
const
|
|
4628
|
+
const path9 = normalizePath(testString);
|
|
4551
4629
|
for (let index = 0; index < patterns.length; index++) {
|
|
4552
4630
|
const pattern = patterns[index];
|
|
4553
|
-
if (pattern(
|
|
4631
|
+
if (pattern(path9, stats)) {
|
|
4554
4632
|
return true;
|
|
4555
4633
|
}
|
|
4556
4634
|
}
|
|
@@ -4588,19 +4666,19 @@ var toUnix = (string) => {
|
|
|
4588
4666
|
}
|
|
4589
4667
|
return str;
|
|
4590
4668
|
};
|
|
4591
|
-
var normalizePathToUnix = (
|
|
4592
|
-
var normalizeIgnored = (cwd = "") => (
|
|
4593
|
-
if (typeof
|
|
4594
|
-
return normalizePathToUnix(sp2.isAbsolute(
|
|
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));
|
|
4595
4673
|
} else {
|
|
4596
|
-
return
|
|
4674
|
+
return path9;
|
|
4597
4675
|
}
|
|
4598
4676
|
};
|
|
4599
|
-
var getAbsolutePath = (
|
|
4600
|
-
if (sp2.isAbsolute(
|
|
4601
|
-
return
|
|
4677
|
+
var getAbsolutePath = (path9, cwd) => {
|
|
4678
|
+
if (sp2.isAbsolute(path9)) {
|
|
4679
|
+
return path9;
|
|
4602
4680
|
}
|
|
4603
|
-
return sp2.join(cwd,
|
|
4681
|
+
return sp2.join(cwd, path9);
|
|
4604
4682
|
};
|
|
4605
4683
|
var EMPTY_SET = Object.freeze(/* @__PURE__ */ new Set());
|
|
4606
4684
|
var DirEntry = class {
|
|
@@ -4665,10 +4743,10 @@ var WatchHelper = class {
|
|
|
4665
4743
|
dirParts;
|
|
4666
4744
|
followSymlinks;
|
|
4667
4745
|
statMethod;
|
|
4668
|
-
constructor(
|
|
4746
|
+
constructor(path9, follow, fsw) {
|
|
4669
4747
|
this.fsw = fsw;
|
|
4670
|
-
const watchPath =
|
|
4671
|
-
this.path =
|
|
4748
|
+
const watchPath = path9;
|
|
4749
|
+
this.path = path9 = path9.replace(REPLACER_RE, "");
|
|
4672
4750
|
this.watchPath = watchPath;
|
|
4673
4751
|
this.fullWatchPath = sp2.resolve(watchPath);
|
|
4674
4752
|
this.dirParts = [];
|
|
@@ -4808,20 +4886,20 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
4808
4886
|
this._closePromise = void 0;
|
|
4809
4887
|
let paths = unifyPaths(paths_);
|
|
4810
4888
|
if (cwd) {
|
|
4811
|
-
paths = paths.map((
|
|
4812
|
-
const absPath = getAbsolutePath(
|
|
4889
|
+
paths = paths.map((path9) => {
|
|
4890
|
+
const absPath = getAbsolutePath(path9, cwd);
|
|
4813
4891
|
return absPath;
|
|
4814
4892
|
});
|
|
4815
4893
|
}
|
|
4816
|
-
paths.forEach((
|
|
4817
|
-
this._removeIgnoredPath(
|
|
4894
|
+
paths.forEach((path9) => {
|
|
4895
|
+
this._removeIgnoredPath(path9);
|
|
4818
4896
|
});
|
|
4819
4897
|
this._userIgnored = void 0;
|
|
4820
4898
|
if (!this._readyCount)
|
|
4821
4899
|
this._readyCount = 0;
|
|
4822
4900
|
this._readyCount += paths.length;
|
|
4823
|
-
Promise.all(paths.map(async (
|
|
4824
|
-
const res = await this._nodeFsHandler._addToNodeFs(
|
|
4901
|
+
Promise.all(paths.map(async (path9) => {
|
|
4902
|
+
const res = await this._nodeFsHandler._addToNodeFs(path9, !_internal, void 0, 0, _origAdd);
|
|
4825
4903
|
if (res)
|
|
4826
4904
|
this._emitReady();
|
|
4827
4905
|
return res;
|
|
@@ -4843,17 +4921,17 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
4843
4921
|
return this;
|
|
4844
4922
|
const paths = unifyPaths(paths_);
|
|
4845
4923
|
const { cwd } = this.options;
|
|
4846
|
-
paths.forEach((
|
|
4847
|
-
if (!sp2.isAbsolute(
|
|
4924
|
+
paths.forEach((path9) => {
|
|
4925
|
+
if (!sp2.isAbsolute(path9) && !this._closers.has(path9)) {
|
|
4848
4926
|
if (cwd)
|
|
4849
|
-
|
|
4850
|
-
|
|
4927
|
+
path9 = sp2.join(cwd, path9);
|
|
4928
|
+
path9 = sp2.resolve(path9);
|
|
4851
4929
|
}
|
|
4852
|
-
this._closePath(
|
|
4853
|
-
this._addIgnoredPath(
|
|
4854
|
-
if (this._watched.has(
|
|
4930
|
+
this._closePath(path9);
|
|
4931
|
+
this._addIgnoredPath(path9);
|
|
4932
|
+
if (this._watched.has(path9)) {
|
|
4855
4933
|
this._addIgnoredPath({
|
|
4856
|
-
path:
|
|
4934
|
+
path: path9,
|
|
4857
4935
|
recursive: true
|
|
4858
4936
|
});
|
|
4859
4937
|
}
|
|
@@ -4917,38 +4995,38 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
4917
4995
|
* @param stats arguments to be passed with event
|
|
4918
4996
|
* @returns the error if defined, otherwise the value of the FSWatcher instance's `closed` flag
|
|
4919
4997
|
*/
|
|
4920
|
-
async _emit(event,
|
|
4998
|
+
async _emit(event, path9, stats) {
|
|
4921
4999
|
if (this.closed)
|
|
4922
5000
|
return;
|
|
4923
5001
|
const opts = this.options;
|
|
4924
5002
|
if (isWindows)
|
|
4925
|
-
|
|
5003
|
+
path9 = sp2.normalize(path9);
|
|
4926
5004
|
if (opts.cwd)
|
|
4927
|
-
|
|
4928
|
-
const args = [
|
|
5005
|
+
path9 = sp2.relative(opts.cwd, path9);
|
|
5006
|
+
const args = [path9];
|
|
4929
5007
|
if (stats != null)
|
|
4930
5008
|
args.push(stats);
|
|
4931
5009
|
const awf = opts.awaitWriteFinish;
|
|
4932
5010
|
let pw;
|
|
4933
|
-
if (awf && (pw = this._pendingWrites.get(
|
|
5011
|
+
if (awf && (pw = this._pendingWrites.get(path9))) {
|
|
4934
5012
|
pw.lastChange = /* @__PURE__ */ new Date();
|
|
4935
5013
|
return this;
|
|
4936
5014
|
}
|
|
4937
5015
|
if (opts.atomic) {
|
|
4938
5016
|
if (event === EVENTS.UNLINK) {
|
|
4939
|
-
this._pendingUnlinks.set(
|
|
5017
|
+
this._pendingUnlinks.set(path9, [event, ...args]);
|
|
4940
5018
|
setTimeout(() => {
|
|
4941
|
-
this._pendingUnlinks.forEach((entry,
|
|
5019
|
+
this._pendingUnlinks.forEach((entry, path10) => {
|
|
4942
5020
|
this.emit(...entry);
|
|
4943
5021
|
this.emit(EVENTS.ALL, ...entry);
|
|
4944
|
-
this._pendingUnlinks.delete(
|
|
5022
|
+
this._pendingUnlinks.delete(path10);
|
|
4945
5023
|
});
|
|
4946
5024
|
}, typeof opts.atomic === "number" ? opts.atomic : 100);
|
|
4947
5025
|
return this;
|
|
4948
5026
|
}
|
|
4949
|
-
if (event === EVENTS.ADD && this._pendingUnlinks.has(
|
|
5027
|
+
if (event === EVENTS.ADD && this._pendingUnlinks.has(path9)) {
|
|
4950
5028
|
event = EVENTS.CHANGE;
|
|
4951
|
-
this._pendingUnlinks.delete(
|
|
5029
|
+
this._pendingUnlinks.delete(path9);
|
|
4952
5030
|
}
|
|
4953
5031
|
}
|
|
4954
5032
|
if (awf && (event === EVENTS.ADD || event === EVENTS.CHANGE) && this._readyEmitted) {
|
|
@@ -4966,16 +5044,16 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
4966
5044
|
this.emitWithAll(event, args);
|
|
4967
5045
|
}
|
|
4968
5046
|
};
|
|
4969
|
-
this._awaitWriteFinish(
|
|
5047
|
+
this._awaitWriteFinish(path9, awf.stabilityThreshold, event, awfEmit);
|
|
4970
5048
|
return this;
|
|
4971
5049
|
}
|
|
4972
5050
|
if (event === EVENTS.CHANGE) {
|
|
4973
|
-
const isThrottled = !this._throttle(EVENTS.CHANGE,
|
|
5051
|
+
const isThrottled = !this._throttle(EVENTS.CHANGE, path9, 50);
|
|
4974
5052
|
if (isThrottled)
|
|
4975
5053
|
return this;
|
|
4976
5054
|
}
|
|
4977
5055
|
if (opts.alwaysStat && stats === void 0 && (event === EVENTS.ADD || event === EVENTS.ADD_DIR || event === EVENTS.CHANGE)) {
|
|
4978
|
-
const fullPath = opts.cwd ? sp2.join(opts.cwd,
|
|
5056
|
+
const fullPath = opts.cwd ? sp2.join(opts.cwd, path9) : path9;
|
|
4979
5057
|
let stats2;
|
|
4980
5058
|
try {
|
|
4981
5059
|
stats2 = await stat3(fullPath);
|
|
@@ -5006,23 +5084,23 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
5006
5084
|
* @param timeout duration of time to suppress duplicate actions
|
|
5007
5085
|
* @returns tracking object or false if action should be suppressed
|
|
5008
5086
|
*/
|
|
5009
|
-
_throttle(actionType,
|
|
5087
|
+
_throttle(actionType, path9, timeout) {
|
|
5010
5088
|
if (!this._throttled.has(actionType)) {
|
|
5011
5089
|
this._throttled.set(actionType, /* @__PURE__ */ new Map());
|
|
5012
5090
|
}
|
|
5013
5091
|
const action = this._throttled.get(actionType);
|
|
5014
5092
|
if (!action)
|
|
5015
5093
|
throw new Error("invalid throttle");
|
|
5016
|
-
const actionPath = action.get(
|
|
5094
|
+
const actionPath = action.get(path9);
|
|
5017
5095
|
if (actionPath) {
|
|
5018
5096
|
actionPath.count++;
|
|
5019
5097
|
return false;
|
|
5020
5098
|
}
|
|
5021
5099
|
let timeoutObject;
|
|
5022
5100
|
const clear = () => {
|
|
5023
|
-
const item = action.get(
|
|
5101
|
+
const item = action.get(path9);
|
|
5024
5102
|
const count = item ? item.count : 0;
|
|
5025
|
-
action.delete(
|
|
5103
|
+
action.delete(path9);
|
|
5026
5104
|
clearTimeout(timeoutObject);
|
|
5027
5105
|
if (item)
|
|
5028
5106
|
clearTimeout(item.timeoutObject);
|
|
@@ -5030,7 +5108,7 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
5030
5108
|
};
|
|
5031
5109
|
timeoutObject = setTimeout(clear, timeout);
|
|
5032
5110
|
const thr = { timeoutObject, clear, count: 0 };
|
|
5033
|
-
action.set(
|
|
5111
|
+
action.set(path9, thr);
|
|
5034
5112
|
return thr;
|
|
5035
5113
|
}
|
|
5036
5114
|
_incrReadyCount() {
|
|
@@ -5044,44 +5122,44 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
5044
5122
|
* @param event
|
|
5045
5123
|
* @param awfEmit Callback to be called when ready for event to be emitted.
|
|
5046
5124
|
*/
|
|
5047
|
-
_awaitWriteFinish(
|
|
5125
|
+
_awaitWriteFinish(path9, threshold, event, awfEmit) {
|
|
5048
5126
|
const awf = this.options.awaitWriteFinish;
|
|
5049
5127
|
if (typeof awf !== "object")
|
|
5050
5128
|
return;
|
|
5051
5129
|
const pollInterval = awf.pollInterval;
|
|
5052
5130
|
let timeoutHandler;
|
|
5053
|
-
let fullPath =
|
|
5054
|
-
if (this.options.cwd && !sp2.isAbsolute(
|
|
5055
|
-
fullPath = sp2.join(this.options.cwd,
|
|
5131
|
+
let fullPath = path9;
|
|
5132
|
+
if (this.options.cwd && !sp2.isAbsolute(path9)) {
|
|
5133
|
+
fullPath = sp2.join(this.options.cwd, path9);
|
|
5056
5134
|
}
|
|
5057
5135
|
const now = /* @__PURE__ */ new Date();
|
|
5058
5136
|
const writes = this._pendingWrites;
|
|
5059
5137
|
function awaitWriteFinishFn(prevStat) {
|
|
5060
5138
|
statcb(fullPath, (err, curStat) => {
|
|
5061
|
-
if (err || !writes.has(
|
|
5139
|
+
if (err || !writes.has(path9)) {
|
|
5062
5140
|
if (err && err.code !== "ENOENT")
|
|
5063
5141
|
awfEmit(err);
|
|
5064
5142
|
return;
|
|
5065
5143
|
}
|
|
5066
5144
|
const now2 = Number(/* @__PURE__ */ new Date());
|
|
5067
5145
|
if (prevStat && curStat.size !== prevStat.size) {
|
|
5068
|
-
writes.get(
|
|
5146
|
+
writes.get(path9).lastChange = now2;
|
|
5069
5147
|
}
|
|
5070
|
-
const pw = writes.get(
|
|
5148
|
+
const pw = writes.get(path9);
|
|
5071
5149
|
const df = now2 - pw.lastChange;
|
|
5072
5150
|
if (df >= threshold) {
|
|
5073
|
-
writes.delete(
|
|
5151
|
+
writes.delete(path9);
|
|
5074
5152
|
awfEmit(void 0, curStat);
|
|
5075
5153
|
} else {
|
|
5076
5154
|
timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval, curStat);
|
|
5077
5155
|
}
|
|
5078
5156
|
});
|
|
5079
5157
|
}
|
|
5080
|
-
if (!writes.has(
|
|
5081
|
-
writes.set(
|
|
5158
|
+
if (!writes.has(path9)) {
|
|
5159
|
+
writes.set(path9, {
|
|
5082
5160
|
lastChange: now,
|
|
5083
5161
|
cancelWait: () => {
|
|
5084
|
-
writes.delete(
|
|
5162
|
+
writes.delete(path9);
|
|
5085
5163
|
clearTimeout(timeoutHandler);
|
|
5086
5164
|
return event;
|
|
5087
5165
|
}
|
|
@@ -5092,8 +5170,8 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
5092
5170
|
/**
|
|
5093
5171
|
* Determines whether user has asked to ignore this path.
|
|
5094
5172
|
*/
|
|
5095
|
-
_isIgnored(
|
|
5096
|
-
if (this.options.atomic && DOT_RE.test(
|
|
5173
|
+
_isIgnored(path9, stats) {
|
|
5174
|
+
if (this.options.atomic && DOT_RE.test(path9))
|
|
5097
5175
|
return true;
|
|
5098
5176
|
if (!this._userIgnored) {
|
|
5099
5177
|
const { cwd } = this.options;
|
|
@@ -5103,17 +5181,17 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
5103
5181
|
const list = [...ignoredPaths.map(normalizeIgnored(cwd)), ...ignored];
|
|
5104
5182
|
this._userIgnored = anymatch(list, void 0);
|
|
5105
5183
|
}
|
|
5106
|
-
return this._userIgnored(
|
|
5184
|
+
return this._userIgnored(path9, stats);
|
|
5107
5185
|
}
|
|
5108
|
-
_isntIgnored(
|
|
5109
|
-
return !this._isIgnored(
|
|
5186
|
+
_isntIgnored(path9, stat4) {
|
|
5187
|
+
return !this._isIgnored(path9, stat4);
|
|
5110
5188
|
}
|
|
5111
5189
|
/**
|
|
5112
5190
|
* Provides a set of common helpers and properties relating to symlink handling.
|
|
5113
5191
|
* @param path file or directory pattern being watched
|
|
5114
5192
|
*/
|
|
5115
|
-
_getWatchHelpers(
|
|
5116
|
-
return new WatchHelper(
|
|
5193
|
+
_getWatchHelpers(path9) {
|
|
5194
|
+
return new WatchHelper(path9, this.options.followSymlinks, this);
|
|
5117
5195
|
}
|
|
5118
5196
|
// Directory helpers
|
|
5119
5197
|
// -----------------
|
|
@@ -5145,63 +5223,63 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
5145
5223
|
* @param item base path of item/directory
|
|
5146
5224
|
*/
|
|
5147
5225
|
_remove(directory, item, isDirectory) {
|
|
5148
|
-
const
|
|
5149
|
-
const fullPath = sp2.resolve(
|
|
5150
|
-
isDirectory = isDirectory != null ? isDirectory : this._watched.has(
|
|
5151
|
-
if (!this._throttle("remove",
|
|
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))
|
|
5152
5230
|
return;
|
|
5153
5231
|
if (!isDirectory && this._watched.size === 1) {
|
|
5154
5232
|
this.add(directory, item, true);
|
|
5155
5233
|
}
|
|
5156
|
-
const wp = this._getWatchedDir(
|
|
5234
|
+
const wp = this._getWatchedDir(path9);
|
|
5157
5235
|
const nestedDirectoryChildren = wp.getChildren();
|
|
5158
|
-
nestedDirectoryChildren.forEach((nested) => this._remove(
|
|
5236
|
+
nestedDirectoryChildren.forEach((nested) => this._remove(path9, nested));
|
|
5159
5237
|
const parent = this._getWatchedDir(directory);
|
|
5160
5238
|
const wasTracked = parent.has(item);
|
|
5161
5239
|
parent.remove(item);
|
|
5162
5240
|
if (this._symlinkPaths.has(fullPath)) {
|
|
5163
5241
|
this._symlinkPaths.delete(fullPath);
|
|
5164
5242
|
}
|
|
5165
|
-
let relPath =
|
|
5243
|
+
let relPath = path9;
|
|
5166
5244
|
if (this.options.cwd)
|
|
5167
|
-
relPath = sp2.relative(this.options.cwd,
|
|
5245
|
+
relPath = sp2.relative(this.options.cwd, path9);
|
|
5168
5246
|
if (this.options.awaitWriteFinish && this._pendingWrites.has(relPath)) {
|
|
5169
5247
|
const event = this._pendingWrites.get(relPath).cancelWait();
|
|
5170
5248
|
if (event === EVENTS.ADD)
|
|
5171
5249
|
return;
|
|
5172
5250
|
}
|
|
5173
|
-
this._watched.delete(
|
|
5251
|
+
this._watched.delete(path9);
|
|
5174
5252
|
this._watched.delete(fullPath);
|
|
5175
5253
|
const eventName = isDirectory ? EVENTS.UNLINK_DIR : EVENTS.UNLINK;
|
|
5176
|
-
if (wasTracked && !this._isIgnored(
|
|
5177
|
-
this._emit(eventName,
|
|
5178
|
-
this._closePath(
|
|
5254
|
+
if (wasTracked && !this._isIgnored(path9))
|
|
5255
|
+
this._emit(eventName, path9);
|
|
5256
|
+
this._closePath(path9);
|
|
5179
5257
|
}
|
|
5180
5258
|
/**
|
|
5181
5259
|
* Closes all watchers for a path
|
|
5182
5260
|
*/
|
|
5183
|
-
_closePath(
|
|
5184
|
-
this._closeFile(
|
|
5185
|
-
const dir = sp2.dirname(
|
|
5186
|
-
this._getWatchedDir(dir).remove(sp2.basename(
|
|
5261
|
+
_closePath(path9) {
|
|
5262
|
+
this._closeFile(path9);
|
|
5263
|
+
const dir = sp2.dirname(path9);
|
|
5264
|
+
this._getWatchedDir(dir).remove(sp2.basename(path9));
|
|
5187
5265
|
}
|
|
5188
5266
|
/**
|
|
5189
5267
|
* Closes only file-specific watchers
|
|
5190
5268
|
*/
|
|
5191
|
-
_closeFile(
|
|
5192
|
-
const closers = this._closers.get(
|
|
5269
|
+
_closeFile(path9) {
|
|
5270
|
+
const closers = this._closers.get(path9);
|
|
5193
5271
|
if (!closers)
|
|
5194
5272
|
return;
|
|
5195
5273
|
closers.forEach((closer) => closer());
|
|
5196
|
-
this._closers.delete(
|
|
5274
|
+
this._closers.delete(path9);
|
|
5197
5275
|
}
|
|
5198
|
-
_addPathCloser(
|
|
5276
|
+
_addPathCloser(path9, closer) {
|
|
5199
5277
|
if (!closer)
|
|
5200
5278
|
return;
|
|
5201
|
-
let list = this._closers.get(
|
|
5279
|
+
let list = this._closers.get(path9);
|
|
5202
5280
|
if (!list) {
|
|
5203
5281
|
list = [];
|
|
5204
|
-
this._closers.set(
|
|
5282
|
+
this._closers.set(path9, list);
|
|
5205
5283
|
}
|
|
5206
5284
|
list.push(closer);
|
|
5207
5285
|
}
|
|
@@ -5296,7 +5374,7 @@ var FileWatcher = class {
|
|
|
5296
5374
|
return;
|
|
5297
5375
|
}
|
|
5298
5376
|
const changes = Array.from(this.pendingChanges.entries()).map(
|
|
5299
|
-
([
|
|
5377
|
+
([path9, type]) => ({ path: path9, type })
|
|
5300
5378
|
);
|
|
5301
5379
|
this.pendingChanges.clear();
|
|
5302
5380
|
try {
|
|
@@ -5476,7 +5554,7 @@ var index_codebase = tool({
|
|
|
5476
5554
|
estimateOnly: z.boolean().optional().default(false).describe("Only show cost estimate without indexing"),
|
|
5477
5555
|
verbose: z.boolean().optional().default(false).describe("Show detailed info about skipped files and parsing failures")
|
|
5478
5556
|
},
|
|
5479
|
-
async execute(args) {
|
|
5557
|
+
async execute(args, context) {
|
|
5480
5558
|
const indexer = getIndexer();
|
|
5481
5559
|
if (args.estimateOnly) {
|
|
5482
5560
|
const estimate = await indexer.estimateCost();
|
|
@@ -5485,7 +5563,19 @@ var index_codebase = tool({
|
|
|
5485
5563
|
if (args.force) {
|
|
5486
5564
|
await indexer.clearIndex();
|
|
5487
5565
|
}
|
|
5488
|
-
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
|
+
});
|
|
5489
5579
|
return formatIndexStats(stats, args.verbose ?? false);
|
|
5490
5580
|
}
|
|
5491
5581
|
});
|
|
@@ -5584,12 +5674,90 @@ function formatStatus(status) {
|
|
|
5584
5674
|
}
|
|
5585
5675
|
return lines.join("\n");
|
|
5586
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
|
+
}
|
|
5587
5748
|
|
|
5588
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
|
+
}
|
|
5589
5757
|
function loadJsonFile(filePath) {
|
|
5590
5758
|
try {
|
|
5591
|
-
if (
|
|
5592
|
-
const content =
|
|
5759
|
+
if (existsSync6(filePath)) {
|
|
5760
|
+
const content = readFileSync6(filePath, "utf-8");
|
|
5593
5761
|
return JSON.parse(content);
|
|
5594
5762
|
}
|
|
5595
5763
|
} catch {
|
|
@@ -5597,11 +5765,11 @@ function loadJsonFile(filePath) {
|
|
|
5597
5765
|
return null;
|
|
5598
5766
|
}
|
|
5599
5767
|
function loadPluginConfig(projectRoot) {
|
|
5600
|
-
const projectConfig = loadJsonFile(
|
|
5768
|
+
const projectConfig = loadJsonFile(path8.join(projectRoot, ".opencode", "codebase-index.json"));
|
|
5601
5769
|
if (projectConfig) {
|
|
5602
5770
|
return projectConfig;
|
|
5603
5771
|
}
|
|
5604
|
-
const globalConfigPath =
|
|
5772
|
+
const globalConfigPath = path8.join(os3.homedir(), ".config", "opencode", "codebase-index.json");
|
|
5605
5773
|
const globalConfig = loadJsonFile(globalConfigPath);
|
|
5606
5774
|
if (globalConfig) {
|
|
5607
5775
|
return globalConfig;
|
|
@@ -5633,36 +5801,11 @@ var plugin = async ({ directory }) => {
|
|
|
5633
5801
|
},
|
|
5634
5802
|
async config(cfg) {
|
|
5635
5803
|
cfg.command = cfg.command ?? {};
|
|
5636
|
-
|
|
5637
|
-
|
|
5638
|
-
|
|
5639
|
-
|
|
5640
|
-
|
|
5641
|
-
|
|
5642
|
-
Return the most relevant results with file paths and line numbers.`
|
|
5643
|
-
};
|
|
5644
|
-
cfg.command["find"] = {
|
|
5645
|
-
description: "Find code using hybrid approach (semantic + grep)",
|
|
5646
|
-
template: `Find code related to: $ARGUMENTS
|
|
5647
|
-
|
|
5648
|
-
Strategy:
|
|
5649
|
-
1. First use \`codebase_search\` to find semantically related code
|
|
5650
|
-
2. From the results, identify specific function/class names
|
|
5651
|
-
3. Use grep to find all occurrences of those identifiers
|
|
5652
|
-
4. Combine findings into a comprehensive answer
|
|
5653
|
-
|
|
5654
|
-
If the semantic index doesn't exist, run \`index_codebase\` first.`
|
|
5655
|
-
};
|
|
5656
|
-
cfg.command["index"] = {
|
|
5657
|
-
description: "Index the codebase for semantic search",
|
|
5658
|
-
template: `Run the \`index_codebase\` tool to create or update the semantic search index.
|
|
5659
|
-
|
|
5660
|
-
Show progress and final statistics including:
|
|
5661
|
-
- Number of files processed
|
|
5662
|
-
- Number of chunks indexed
|
|
5663
|
-
- Tokens used
|
|
5664
|
-
- Duration`
|
|
5665
|
-
};
|
|
5804
|
+
const commandsDir = getCommandsDir();
|
|
5805
|
+
const commands = loadCommandsFromDirectory(commandsDir);
|
|
5806
|
+
for (const [name, definition] of commands) {
|
|
5807
|
+
cfg.command[name] = definition;
|
|
5808
|
+
}
|
|
5666
5809
|
}
|
|
5667
5810
|
};
|
|
5668
5811
|
};
|