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.cjs
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.
|
|
@@ -657,9 +657,10 @@ __export(index_exports, {
|
|
|
657
657
|
default: () => index_default
|
|
658
658
|
});
|
|
659
659
|
module.exports = __toCommonJS(index_exports);
|
|
660
|
-
var
|
|
661
|
-
var
|
|
660
|
+
var import_fs6 = require("fs");
|
|
661
|
+
var path8 = __toESM(require("path"), 1);
|
|
662
662
|
var os3 = __toESM(require("os"), 1);
|
|
663
|
+
var import_url2 = require("url");
|
|
663
664
|
|
|
664
665
|
// src/config/schema.ts
|
|
665
666
|
var DEFAULT_INCLUDE = [
|
|
@@ -697,7 +698,10 @@ function getDefaultIndexingConfig() {
|
|
|
697
698
|
maxChunksPerFile: 100,
|
|
698
699
|
semanticOnly: false,
|
|
699
700
|
retries: 3,
|
|
700
|
-
retryDelayMs: 1e3
|
|
701
|
+
retryDelayMs: 1e3,
|
|
702
|
+
autoGc: true,
|
|
703
|
+
gcIntervalDays: 7,
|
|
704
|
+
gcOrphanThreshold: 100
|
|
701
705
|
};
|
|
702
706
|
}
|
|
703
707
|
function getDefaultSearchConfig() {
|
|
@@ -732,7 +736,10 @@ function parseConfig(raw) {
|
|
|
732
736
|
maxChunksPerFile: typeof rawIndexing.maxChunksPerFile === "number" ? Math.max(1, rawIndexing.maxChunksPerFile) : defaultIndexing.maxChunksPerFile,
|
|
733
737
|
semanticOnly: typeof rawIndexing.semanticOnly === "boolean" ? rawIndexing.semanticOnly : defaultIndexing.semanticOnly,
|
|
734
738
|
retries: typeof rawIndexing.retries === "number" ? rawIndexing.retries : defaultIndexing.retries,
|
|
735
|
-
retryDelayMs: typeof rawIndexing.retryDelayMs === "number" ? rawIndexing.retryDelayMs : defaultIndexing.retryDelayMs
|
|
739
|
+
retryDelayMs: typeof rawIndexing.retryDelayMs === "number" ? rawIndexing.retryDelayMs : defaultIndexing.retryDelayMs,
|
|
740
|
+
autoGc: typeof rawIndexing.autoGc === "boolean" ? rawIndexing.autoGc : defaultIndexing.autoGc,
|
|
741
|
+
gcIntervalDays: typeof rawIndexing.gcIntervalDays === "number" ? Math.max(1, rawIndexing.gcIntervalDays) : defaultIndexing.gcIntervalDays,
|
|
742
|
+
gcOrphanThreshold: typeof rawIndexing.gcOrphanThreshold === "number" ? Math.max(0, rawIndexing.gcOrphanThreshold) : defaultIndexing.gcOrphanThreshold
|
|
736
743
|
};
|
|
737
744
|
const rawSearch = input.search && typeof input.search === "object" ? input.search : {};
|
|
738
745
|
const search = {
|
|
@@ -2071,34 +2078,36 @@ var GoogleEmbeddingProvider = class {
|
|
|
2071
2078
|
};
|
|
2072
2079
|
}
|
|
2073
2080
|
async embedBatch(texts) {
|
|
2074
|
-
const
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
}
|
|
2088
|
-
}
|
|
2081
|
+
const results = await Promise.all(
|
|
2082
|
+
texts.map(async (text) => {
|
|
2083
|
+
const response = await fetch(
|
|
2084
|
+
`${this.credentials.baseUrl}/models/${this.modelInfo.model}:embedContent?key=${this.credentials.apiKey}`,
|
|
2085
|
+
{
|
|
2086
|
+
method: "POST",
|
|
2087
|
+
headers: {
|
|
2088
|
+
"Content-Type": "application/json"
|
|
2089
|
+
},
|
|
2090
|
+
body: JSON.stringify({
|
|
2091
|
+
content: {
|
|
2092
|
+
parts: [{ text }]
|
|
2093
|
+
}
|
|
2094
|
+
})
|
|
2095
|
+
}
|
|
2096
|
+
);
|
|
2097
|
+
if (!response.ok) {
|
|
2098
|
+
const error = await response.text();
|
|
2099
|
+
throw new Error(`Google embedding API error: ${response.status} - ${error}`);
|
|
2089
2100
|
}
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
totalTokens += Math.ceil(text.length / 4);
|
|
2098
|
-
}
|
|
2101
|
+
const data = await response.json();
|
|
2102
|
+
return {
|
|
2103
|
+
embedding: data.embedding.values,
|
|
2104
|
+
tokensUsed: Math.ceil(text.length / 4)
|
|
2105
|
+
};
|
|
2106
|
+
})
|
|
2107
|
+
);
|
|
2099
2108
|
return {
|
|
2100
|
-
embeddings,
|
|
2101
|
-
totalTokensUsed:
|
|
2109
|
+
embeddings: results.map((r) => r.embedding),
|
|
2110
|
+
totalTokensUsed: results.reduce((sum, r) => sum + r.tokensUsed, 0)
|
|
2102
2111
|
};
|
|
2103
2112
|
}
|
|
2104
2113
|
getModelInfo() {
|
|
@@ -2132,16 +2141,10 @@ var OllamaEmbeddingProvider = class {
|
|
|
2132
2141
|
};
|
|
2133
2142
|
}
|
|
2134
2143
|
async embedBatch(texts) {
|
|
2135
|
-
const
|
|
2136
|
-
let totalTokens = 0;
|
|
2137
|
-
for (const text of texts) {
|
|
2138
|
-
const result = await this.embed(text);
|
|
2139
|
-
embeddings.push(result.embedding);
|
|
2140
|
-
totalTokens += result.tokensUsed;
|
|
2141
|
-
}
|
|
2144
|
+
const results = await Promise.all(texts.map((text) => this.embed(text)));
|
|
2142
2145
|
return {
|
|
2143
|
-
embeddings,
|
|
2144
|
-
totalTokensUsed:
|
|
2146
|
+
embeddings: results.map((r) => r.embedding),
|
|
2147
|
+
totalTokensUsed: results.reduce((sum, r) => sum + r.tokensUsed, 0)
|
|
2145
2148
|
};
|
|
2146
2149
|
}
|
|
2147
2150
|
getModelInfo() {
|
|
@@ -2683,12 +2686,20 @@ var Database = class {
|
|
|
2683
2686
|
upsertEmbedding(contentHash, embedding, chunkText, model) {
|
|
2684
2687
|
this.inner.upsertEmbedding(contentHash, embedding, chunkText, model);
|
|
2685
2688
|
}
|
|
2689
|
+
upsertEmbeddingsBatch(items) {
|
|
2690
|
+
if (items.length === 0) return;
|
|
2691
|
+
this.inner.upsertEmbeddingsBatch(items);
|
|
2692
|
+
}
|
|
2686
2693
|
getMissingEmbeddings(contentHashes) {
|
|
2687
2694
|
return this.inner.getMissingEmbeddings(contentHashes);
|
|
2688
2695
|
}
|
|
2689
2696
|
upsertChunk(chunk) {
|
|
2690
2697
|
this.inner.upsertChunk(chunk);
|
|
2691
2698
|
}
|
|
2699
|
+
upsertChunksBatch(chunks) {
|
|
2700
|
+
if (chunks.length === 0) return;
|
|
2701
|
+
this.inner.upsertChunksBatch(chunks);
|
|
2702
|
+
}
|
|
2692
2703
|
getChunk(chunkId) {
|
|
2693
2704
|
return this.inner.getChunk(chunkId) ?? null;
|
|
2694
2705
|
}
|
|
@@ -2701,6 +2712,10 @@ var Database = class {
|
|
|
2701
2712
|
addChunksToBranch(branch, chunkIds) {
|
|
2702
2713
|
this.inner.addChunksToBranch(branch, chunkIds);
|
|
2703
2714
|
}
|
|
2715
|
+
addChunksToBranchBatch(branch, chunkIds) {
|
|
2716
|
+
if (chunkIds.length === 0) return;
|
|
2717
|
+
this.inner.addChunksToBranchBatch(branch, chunkIds);
|
|
2718
|
+
}
|
|
2704
2719
|
clearBranch(branch) {
|
|
2705
2720
|
return this.inner.clearBranch(branch);
|
|
2706
2721
|
}
|
|
@@ -2905,6 +2920,20 @@ var Indexer = class {
|
|
|
2905
2920
|
});
|
|
2906
2921
|
this.saveFailedBatches(existing);
|
|
2907
2922
|
}
|
|
2923
|
+
getProviderRateLimits(provider) {
|
|
2924
|
+
switch (provider) {
|
|
2925
|
+
case "github-copilot":
|
|
2926
|
+
return { concurrency: 1, intervalMs: 4e3, minRetryMs: 5e3, maxRetryMs: 6e4 };
|
|
2927
|
+
case "openai":
|
|
2928
|
+
return { concurrency: 3, intervalMs: 500, minRetryMs: 1e3, maxRetryMs: 3e4 };
|
|
2929
|
+
case "google":
|
|
2930
|
+
return { concurrency: 5, intervalMs: 200, minRetryMs: 1e3, maxRetryMs: 3e4 };
|
|
2931
|
+
case "ollama":
|
|
2932
|
+
return { concurrency: 5, intervalMs: 0, minRetryMs: 500, maxRetryMs: 5e3 };
|
|
2933
|
+
default:
|
|
2934
|
+
return { concurrency: 3, intervalMs: 1e3, minRetryMs: 1e3, maxRetryMs: 3e4 };
|
|
2935
|
+
}
|
|
2936
|
+
}
|
|
2908
2937
|
async initialize() {
|
|
2909
2938
|
this.detectedProvider = await detectEmbeddingProvider(this.config.embeddingProvider);
|
|
2910
2939
|
if (!this.detectedProvider) {
|
|
@@ -2947,11 +2976,45 @@ var Indexer = class {
|
|
|
2947
2976
|
this.currentBranch = "default";
|
|
2948
2977
|
this.baseBranch = "default";
|
|
2949
2978
|
}
|
|
2979
|
+
if (this.config.indexing.autoGc) {
|
|
2980
|
+
await this.maybeRunAutoGc();
|
|
2981
|
+
}
|
|
2982
|
+
}
|
|
2983
|
+
async maybeRunAutoGc() {
|
|
2984
|
+
if (!this.database) return;
|
|
2985
|
+
const lastGcTimestamp = this.database.getMetadata("lastGcTimestamp");
|
|
2986
|
+
const now = Date.now();
|
|
2987
|
+
const intervalMs = this.config.indexing.gcIntervalDays * 24 * 60 * 60 * 1e3;
|
|
2988
|
+
let shouldRunGc = false;
|
|
2989
|
+
if (!lastGcTimestamp) {
|
|
2990
|
+
shouldRunGc = true;
|
|
2991
|
+
} else {
|
|
2992
|
+
const lastGcTime = parseInt(lastGcTimestamp, 10);
|
|
2993
|
+
if (!isNaN(lastGcTime) && now - lastGcTime > intervalMs) {
|
|
2994
|
+
shouldRunGc = true;
|
|
2995
|
+
}
|
|
2996
|
+
}
|
|
2997
|
+
if (shouldRunGc) {
|
|
2998
|
+
await this.healthCheck();
|
|
2999
|
+
this.database.setMetadata("lastGcTimestamp", now.toString());
|
|
3000
|
+
}
|
|
3001
|
+
}
|
|
3002
|
+
async maybeRunOrphanGc() {
|
|
3003
|
+
if (!this.database) return;
|
|
3004
|
+
const stats = this.database.getStats();
|
|
3005
|
+
if (!stats) return;
|
|
3006
|
+
const orphanCount = stats.embeddingCount - stats.chunkCount;
|
|
3007
|
+
if (orphanCount > this.config.indexing.gcOrphanThreshold) {
|
|
3008
|
+
this.database.gcOrphanEmbeddings();
|
|
3009
|
+
this.database.gcOrphanChunks();
|
|
3010
|
+
this.database.setMetadata("lastGcTimestamp", Date.now().toString());
|
|
3011
|
+
}
|
|
2950
3012
|
}
|
|
2951
3013
|
migrateFromLegacyIndex() {
|
|
2952
3014
|
if (!this.store || !this.database) return;
|
|
2953
3015
|
const allMetadata = this.store.getAllMetadata();
|
|
2954
3016
|
const chunkIds = [];
|
|
3017
|
+
const chunkDataBatch = [];
|
|
2955
3018
|
for (const { key, metadata } of allMetadata) {
|
|
2956
3019
|
const chunkData = {
|
|
2957
3020
|
chunkId: key,
|
|
@@ -2963,10 +3026,13 @@ var Indexer = class {
|
|
|
2963
3026
|
name: metadata.name,
|
|
2964
3027
|
language: metadata.language
|
|
2965
3028
|
};
|
|
2966
|
-
|
|
3029
|
+
chunkDataBatch.push(chunkData);
|
|
2967
3030
|
chunkIds.push(key);
|
|
2968
3031
|
}
|
|
2969
|
-
|
|
3032
|
+
if (chunkDataBatch.length > 0) {
|
|
3033
|
+
this.database.upsertChunksBatch(chunkDataBatch);
|
|
3034
|
+
}
|
|
3035
|
+
this.database.addChunksToBranchBatch(this.currentBranch || "default", chunkIds);
|
|
2970
3036
|
}
|
|
2971
3037
|
async ensureInitialized() {
|
|
2972
3038
|
if (!this.store || !this.provider || !this.invertedIndex || !this.detectedProvider || !this.database) {
|
|
@@ -3062,6 +3128,7 @@ var Indexer = class {
|
|
|
3062
3128
|
}
|
|
3063
3129
|
}
|
|
3064
3130
|
}
|
|
3131
|
+
const chunkDataBatch = [];
|
|
3065
3132
|
for (const parsed of parsedFiles) {
|
|
3066
3133
|
currentFilePaths.add(parsed.path);
|
|
3067
3134
|
if (parsed.chunks.length === 0) {
|
|
@@ -3089,7 +3156,7 @@ var Indexer = class {
|
|
|
3089
3156
|
name: chunk.name,
|
|
3090
3157
|
language: chunk.language
|
|
3091
3158
|
};
|
|
3092
|
-
|
|
3159
|
+
chunkDataBatch.push(chunkData);
|
|
3093
3160
|
if (existingChunks.get(id) === contentHash) {
|
|
3094
3161
|
fileChunkCount++;
|
|
3095
3162
|
continue;
|
|
@@ -3108,6 +3175,9 @@ var Indexer = class {
|
|
|
3108
3175
|
fileChunkCount++;
|
|
3109
3176
|
}
|
|
3110
3177
|
}
|
|
3178
|
+
if (chunkDataBatch.length > 0) {
|
|
3179
|
+
database.upsertChunksBatch(chunkDataBatch);
|
|
3180
|
+
}
|
|
3111
3181
|
let removedCount = 0;
|
|
3112
3182
|
for (const [chunkId] of existingChunks) {
|
|
3113
3183
|
if (!currentChunkIds.has(chunkId)) {
|
|
@@ -3121,7 +3191,7 @@ var Indexer = class {
|
|
|
3121
3191
|
stats.removedChunks = removedCount;
|
|
3122
3192
|
if (pendingChunks.length === 0 && removedCount === 0) {
|
|
3123
3193
|
database.clearBranch(this.currentBranch);
|
|
3124
|
-
database.
|
|
3194
|
+
database.addChunksToBranchBatch(this.currentBranch, Array.from(currentChunkIds));
|
|
3125
3195
|
this.fileHashCache = currentFileHashes;
|
|
3126
3196
|
this.saveFileHashCache();
|
|
3127
3197
|
stats.durationMs = Date.now() - startTime;
|
|
@@ -3136,7 +3206,7 @@ var Indexer = class {
|
|
|
3136
3206
|
}
|
|
3137
3207
|
if (pendingChunks.length === 0) {
|
|
3138
3208
|
database.clearBranch(this.currentBranch);
|
|
3139
|
-
database.
|
|
3209
|
+
database.addChunksToBranchBatch(this.currentBranch, Array.from(currentChunkIds));
|
|
3140
3210
|
store.save();
|
|
3141
3211
|
invertedIndex.save();
|
|
3142
3212
|
this.fileHashCache = currentFileHashes;
|
|
@@ -3172,7 +3242,12 @@ var Indexer = class {
|
|
|
3172
3242
|
stats.indexedChunks++;
|
|
3173
3243
|
}
|
|
3174
3244
|
}
|
|
3175
|
-
const
|
|
3245
|
+
const providerRateLimits = this.getProviderRateLimits(detectedProvider.provider);
|
|
3246
|
+
const queue = new PQueue({
|
|
3247
|
+
concurrency: providerRateLimits.concurrency,
|
|
3248
|
+
interval: providerRateLimits.intervalMs,
|
|
3249
|
+
intervalCap: providerRateLimits.concurrency
|
|
3250
|
+
});
|
|
3176
3251
|
const dynamicBatches = createDynamicBatches(chunksNeedingEmbedding);
|
|
3177
3252
|
let rateLimitBackoffMs = 0;
|
|
3178
3253
|
for (const batch of dynamicBatches) {
|
|
@@ -3188,15 +3263,13 @@ var Indexer = class {
|
|
|
3188
3263
|
},
|
|
3189
3264
|
{
|
|
3190
3265
|
retries: this.config.indexing.retries,
|
|
3191
|
-
minTimeout: Math.max(this.config.indexing.retryDelayMs,
|
|
3192
|
-
|
|
3193
|
-
maxTimeout: 6e4,
|
|
3194
|
-
// Max 60s backoff
|
|
3266
|
+
minTimeout: Math.max(this.config.indexing.retryDelayMs, providerRateLimits.minRetryMs),
|
|
3267
|
+
maxTimeout: providerRateLimits.maxRetryMs,
|
|
3195
3268
|
factor: 2,
|
|
3196
3269
|
onFailedAttempt: (error) => {
|
|
3197
3270
|
const message = getErrorMessage(error);
|
|
3198
3271
|
if (isRateLimitError(error)) {
|
|
3199
|
-
rateLimitBackoffMs = Math.min(
|
|
3272
|
+
rateLimitBackoffMs = Math.min(providerRateLimits.maxRetryMs, (rateLimitBackoffMs || providerRateLimits.minRetryMs) * 2);
|
|
3200
3273
|
console.error(
|
|
3201
3274
|
`Rate limited (attempt ${error.attemptNumber}/${error.retriesLeft + error.attemptNumber}): waiting ${rateLimitBackoffMs / 1e3}s before retry...`
|
|
3202
3275
|
);
|
|
@@ -3217,15 +3290,14 @@ var Indexer = class {
|
|
|
3217
3290
|
metadata: chunk.metadata
|
|
3218
3291
|
}));
|
|
3219
3292
|
store.addBatch(items);
|
|
3220
|
-
|
|
3221
|
-
|
|
3222
|
-
|
|
3223
|
-
|
|
3224
|
-
|
|
3225
|
-
|
|
3226
|
-
|
|
3227
|
-
|
|
3228
|
-
);
|
|
3293
|
+
const embeddingBatchItems = batch.map((chunk, i) => ({
|
|
3294
|
+
contentHash: chunk.contentHash,
|
|
3295
|
+
embedding: float32ArrayToBuffer(result.embeddings[i]),
|
|
3296
|
+
chunkText: chunk.text,
|
|
3297
|
+
model: detectedProvider.modelInfo.model
|
|
3298
|
+
}));
|
|
3299
|
+
database.upsertEmbeddingsBatch(embeddingBatchItems);
|
|
3300
|
+
for (const chunk of batch) {
|
|
3229
3301
|
invertedIndex.removeChunk(chunk.id);
|
|
3230
3302
|
invertedIndex.addChunk(chunk.id, chunk.content);
|
|
3231
3303
|
}
|
|
@@ -3254,11 +3326,14 @@ var Indexer = class {
|
|
|
3254
3326
|
totalChunks: pendingChunks.length
|
|
3255
3327
|
});
|
|
3256
3328
|
database.clearBranch(this.currentBranch);
|
|
3257
|
-
database.
|
|
3329
|
+
database.addChunksToBranchBatch(this.currentBranch, Array.from(currentChunkIds));
|
|
3258
3330
|
store.save();
|
|
3259
3331
|
invertedIndex.save();
|
|
3260
3332
|
this.fileHashCache = currentFileHashes;
|
|
3261
3333
|
this.saveFileHashCache();
|
|
3334
|
+
if (this.config.indexing.autoGc && stats.removedChunks > 0) {
|
|
3335
|
+
await this.maybeRunOrphanGc();
|
|
3336
|
+
}
|
|
3262
3337
|
stats.durationMs = Date.now() - startTime;
|
|
3263
3338
|
if (stats.failedChunks > 0) {
|
|
3264
3339
|
stats.failedBatchesPath = this.failedBatchesPath;
|
|
@@ -3398,11 +3473,14 @@ var Indexer = class {
|
|
|
3398
3473
|
};
|
|
3399
3474
|
}
|
|
3400
3475
|
async clearIndex() {
|
|
3401
|
-
const { store, invertedIndex } = await this.ensureInitialized();
|
|
3476
|
+
const { store, invertedIndex, database } = await this.ensureInitialized();
|
|
3402
3477
|
store.clear();
|
|
3403
3478
|
store.save();
|
|
3404
3479
|
invertedIndex.clear();
|
|
3405
3480
|
invertedIndex.save();
|
|
3481
|
+
this.fileHashCache.clear();
|
|
3482
|
+
this.saveFileHashCache();
|
|
3483
|
+
database.clearBranch(this.currentBranch);
|
|
3406
3484
|
}
|
|
3407
3485
|
async healthCheck() {
|
|
3408
3486
|
const { store, invertedIndex, database } = await this.ensureInitialized();
|
|
@@ -3594,7 +3672,7 @@ var ReaddirpStream = class extends import_node_stream.Readable {
|
|
|
3594
3672
|
this._directoryFilter = normalizeFilter(opts.directoryFilter);
|
|
3595
3673
|
const statMethod = opts.lstat ? import_promises.lstat : import_promises.stat;
|
|
3596
3674
|
if (wantBigintFsStats) {
|
|
3597
|
-
this._stat = (
|
|
3675
|
+
this._stat = (path9) => statMethod(path9, { bigint: true });
|
|
3598
3676
|
} else {
|
|
3599
3677
|
this._stat = statMethod;
|
|
3600
3678
|
}
|
|
@@ -3619,8 +3697,8 @@ var ReaddirpStream = class extends import_node_stream.Readable {
|
|
|
3619
3697
|
const par = this.parent;
|
|
3620
3698
|
const fil = par && par.files;
|
|
3621
3699
|
if (fil && fil.length > 0) {
|
|
3622
|
-
const { path:
|
|
3623
|
-
const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent,
|
|
3700
|
+
const { path: path9, depth } = par;
|
|
3701
|
+
const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path9));
|
|
3624
3702
|
const awaited = await Promise.all(slice);
|
|
3625
3703
|
for (const entry of awaited) {
|
|
3626
3704
|
if (!entry)
|
|
@@ -3660,21 +3738,21 @@ var ReaddirpStream = class extends import_node_stream.Readable {
|
|
|
3660
3738
|
this.reading = false;
|
|
3661
3739
|
}
|
|
3662
3740
|
}
|
|
3663
|
-
async _exploreDir(
|
|
3741
|
+
async _exploreDir(path9, depth) {
|
|
3664
3742
|
let files;
|
|
3665
3743
|
try {
|
|
3666
|
-
files = await (0, import_promises.readdir)(
|
|
3744
|
+
files = await (0, import_promises.readdir)(path9, this._rdOptions);
|
|
3667
3745
|
} catch (error) {
|
|
3668
3746
|
this._onError(error);
|
|
3669
3747
|
}
|
|
3670
|
-
return { files, depth, path:
|
|
3748
|
+
return { files, depth, path: path9 };
|
|
3671
3749
|
}
|
|
3672
|
-
async _formatEntry(dirent,
|
|
3750
|
+
async _formatEntry(dirent, path9) {
|
|
3673
3751
|
let entry;
|
|
3674
|
-
const
|
|
3752
|
+
const basename4 = this._isDirent ? dirent.name : dirent;
|
|
3675
3753
|
try {
|
|
3676
|
-
const fullPath = (0, import_node_path.resolve)((0, import_node_path.join)(
|
|
3677
|
-
entry = { path: (0, import_node_path.relative)(this._root, fullPath), fullPath, basename:
|
|
3754
|
+
const fullPath = (0, import_node_path.resolve)((0, import_node_path.join)(path9, basename4));
|
|
3755
|
+
entry = { path: (0, import_node_path.relative)(this._root, fullPath), fullPath, basename: basename4 };
|
|
3678
3756
|
entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
|
|
3679
3757
|
} catch (err) {
|
|
3680
3758
|
this._onError(err);
|
|
@@ -4073,16 +4151,16 @@ var delFromSet = (main, prop, item) => {
|
|
|
4073
4151
|
};
|
|
4074
4152
|
var isEmptySet = (val) => val instanceof Set ? val.size === 0 : !val;
|
|
4075
4153
|
var FsWatchInstances = /* @__PURE__ */ new Map();
|
|
4076
|
-
function createFsWatchInstance(
|
|
4154
|
+
function createFsWatchInstance(path9, options, listener, errHandler, emitRaw) {
|
|
4077
4155
|
const handleEvent = (rawEvent, evPath) => {
|
|
4078
|
-
listener(
|
|
4079
|
-
emitRaw(rawEvent, evPath, { watchedPath:
|
|
4080
|
-
if (evPath &&
|
|
4081
|
-
fsWatchBroadcast(sp.resolve(
|
|
4156
|
+
listener(path9);
|
|
4157
|
+
emitRaw(rawEvent, evPath, { watchedPath: path9 });
|
|
4158
|
+
if (evPath && path9 !== evPath) {
|
|
4159
|
+
fsWatchBroadcast(sp.resolve(path9, evPath), KEY_LISTENERS, sp.join(path9, evPath));
|
|
4082
4160
|
}
|
|
4083
4161
|
};
|
|
4084
4162
|
try {
|
|
4085
|
-
return (0, import_node_fs.watch)(
|
|
4163
|
+
return (0, import_node_fs.watch)(path9, {
|
|
4086
4164
|
persistent: options.persistent
|
|
4087
4165
|
}, handleEvent);
|
|
4088
4166
|
} catch (error) {
|
|
@@ -4098,12 +4176,12 @@ var fsWatchBroadcast = (fullPath, listenerType, val1, val2, val3) => {
|
|
|
4098
4176
|
listener(val1, val2, val3);
|
|
4099
4177
|
});
|
|
4100
4178
|
};
|
|
4101
|
-
var setFsWatchListener = (
|
|
4179
|
+
var setFsWatchListener = (path9, fullPath, options, handlers) => {
|
|
4102
4180
|
const { listener, errHandler, rawEmitter } = handlers;
|
|
4103
4181
|
let cont = FsWatchInstances.get(fullPath);
|
|
4104
4182
|
let watcher;
|
|
4105
4183
|
if (!options.persistent) {
|
|
4106
|
-
watcher = createFsWatchInstance(
|
|
4184
|
+
watcher = createFsWatchInstance(path9, options, listener, errHandler, rawEmitter);
|
|
4107
4185
|
if (!watcher)
|
|
4108
4186
|
return;
|
|
4109
4187
|
return watcher.close.bind(watcher);
|
|
@@ -4114,7 +4192,7 @@ var setFsWatchListener = (path8, fullPath, options, handlers) => {
|
|
|
4114
4192
|
addAndConvert(cont, KEY_RAW, rawEmitter);
|
|
4115
4193
|
} else {
|
|
4116
4194
|
watcher = createFsWatchInstance(
|
|
4117
|
-
|
|
4195
|
+
path9,
|
|
4118
4196
|
options,
|
|
4119
4197
|
fsWatchBroadcast.bind(null, fullPath, KEY_LISTENERS),
|
|
4120
4198
|
errHandler,
|
|
@@ -4129,7 +4207,7 @@ var setFsWatchListener = (path8, fullPath, options, handlers) => {
|
|
|
4129
4207
|
cont.watcherUnusable = true;
|
|
4130
4208
|
if (isWindows && error.code === "EPERM") {
|
|
4131
4209
|
try {
|
|
4132
|
-
const fd = await (0, import_promises2.open)(
|
|
4210
|
+
const fd = await (0, import_promises2.open)(path9, "r");
|
|
4133
4211
|
await fd.close();
|
|
4134
4212
|
broadcastErr(error);
|
|
4135
4213
|
} catch (err) {
|
|
@@ -4160,7 +4238,7 @@ var setFsWatchListener = (path8, fullPath, options, handlers) => {
|
|
|
4160
4238
|
};
|
|
4161
4239
|
};
|
|
4162
4240
|
var FsWatchFileInstances = /* @__PURE__ */ new Map();
|
|
4163
|
-
var setFsWatchFileListener = (
|
|
4241
|
+
var setFsWatchFileListener = (path9, fullPath, options, handlers) => {
|
|
4164
4242
|
const { listener, rawEmitter } = handlers;
|
|
4165
4243
|
let cont = FsWatchFileInstances.get(fullPath);
|
|
4166
4244
|
const copts = cont && cont.options;
|
|
@@ -4182,7 +4260,7 @@ var setFsWatchFileListener = (path8, fullPath, options, handlers) => {
|
|
|
4182
4260
|
});
|
|
4183
4261
|
const currmtime = curr.mtimeMs;
|
|
4184
4262
|
if (curr.size !== prev.size || currmtime > prev.mtimeMs || currmtime === 0) {
|
|
4185
|
-
foreach(cont.listeners, (listener2) => listener2(
|
|
4263
|
+
foreach(cont.listeners, (listener2) => listener2(path9, curr));
|
|
4186
4264
|
}
|
|
4187
4265
|
})
|
|
4188
4266
|
};
|
|
@@ -4212,13 +4290,13 @@ var NodeFsHandler = class {
|
|
|
4212
4290
|
* @param listener on fs change
|
|
4213
4291
|
* @returns closer for the watcher instance
|
|
4214
4292
|
*/
|
|
4215
|
-
_watchWithNodeFs(
|
|
4293
|
+
_watchWithNodeFs(path9, listener) {
|
|
4216
4294
|
const opts = this.fsw.options;
|
|
4217
|
-
const directory = sp.dirname(
|
|
4218
|
-
const
|
|
4295
|
+
const directory = sp.dirname(path9);
|
|
4296
|
+
const basename4 = sp.basename(path9);
|
|
4219
4297
|
const parent = this.fsw._getWatchedDir(directory);
|
|
4220
|
-
parent.add(
|
|
4221
|
-
const absolutePath = sp.resolve(
|
|
4298
|
+
parent.add(basename4);
|
|
4299
|
+
const absolutePath = sp.resolve(path9);
|
|
4222
4300
|
const options = {
|
|
4223
4301
|
persistent: opts.persistent
|
|
4224
4302
|
};
|
|
@@ -4227,13 +4305,13 @@ var NodeFsHandler = class {
|
|
|
4227
4305
|
let closer;
|
|
4228
4306
|
if (opts.usePolling) {
|
|
4229
4307
|
const enableBin = opts.interval !== opts.binaryInterval;
|
|
4230
|
-
options.interval = enableBin && isBinaryPath(
|
|
4231
|
-
closer = setFsWatchFileListener(
|
|
4308
|
+
options.interval = enableBin && isBinaryPath(basename4) ? opts.binaryInterval : opts.interval;
|
|
4309
|
+
closer = setFsWatchFileListener(path9, absolutePath, options, {
|
|
4232
4310
|
listener,
|
|
4233
4311
|
rawEmitter: this.fsw._emitRaw
|
|
4234
4312
|
});
|
|
4235
4313
|
} else {
|
|
4236
|
-
closer = setFsWatchListener(
|
|
4314
|
+
closer = setFsWatchListener(path9, absolutePath, options, {
|
|
4237
4315
|
listener,
|
|
4238
4316
|
errHandler: this._boundHandleError,
|
|
4239
4317
|
rawEmitter: this.fsw._emitRaw
|
|
@@ -4249,13 +4327,13 @@ var NodeFsHandler = class {
|
|
|
4249
4327
|
if (this.fsw.closed) {
|
|
4250
4328
|
return;
|
|
4251
4329
|
}
|
|
4252
|
-
const
|
|
4253
|
-
const
|
|
4254
|
-
const parent = this.fsw._getWatchedDir(
|
|
4330
|
+
const dirname5 = sp.dirname(file);
|
|
4331
|
+
const basename4 = sp.basename(file);
|
|
4332
|
+
const parent = this.fsw._getWatchedDir(dirname5);
|
|
4255
4333
|
let prevStats = stats;
|
|
4256
|
-
if (parent.has(
|
|
4334
|
+
if (parent.has(basename4))
|
|
4257
4335
|
return;
|
|
4258
|
-
const listener = async (
|
|
4336
|
+
const listener = async (path9, newStats) => {
|
|
4259
4337
|
if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file, 5))
|
|
4260
4338
|
return;
|
|
4261
4339
|
if (!newStats || newStats.mtimeMs === 0) {
|
|
@@ -4269,18 +4347,18 @@ var NodeFsHandler = class {
|
|
|
4269
4347
|
this.fsw._emit(EV.CHANGE, file, newStats2);
|
|
4270
4348
|
}
|
|
4271
4349
|
if ((isMacos || isLinux || isFreeBSD) && prevStats.ino !== newStats2.ino) {
|
|
4272
|
-
this.fsw._closeFile(
|
|
4350
|
+
this.fsw._closeFile(path9);
|
|
4273
4351
|
prevStats = newStats2;
|
|
4274
4352
|
const closer2 = this._watchWithNodeFs(file, listener);
|
|
4275
4353
|
if (closer2)
|
|
4276
|
-
this.fsw._addPathCloser(
|
|
4354
|
+
this.fsw._addPathCloser(path9, closer2);
|
|
4277
4355
|
} else {
|
|
4278
4356
|
prevStats = newStats2;
|
|
4279
4357
|
}
|
|
4280
4358
|
} catch (error) {
|
|
4281
|
-
this.fsw._remove(
|
|
4359
|
+
this.fsw._remove(dirname5, basename4);
|
|
4282
4360
|
}
|
|
4283
|
-
} else if (parent.has(
|
|
4361
|
+
} else if (parent.has(basename4)) {
|
|
4284
4362
|
const at = newStats.atimeMs;
|
|
4285
4363
|
const mt = newStats.mtimeMs;
|
|
4286
4364
|
if (!at || at <= mt || mt !== prevStats.mtimeMs) {
|
|
@@ -4305,7 +4383,7 @@ var NodeFsHandler = class {
|
|
|
4305
4383
|
* @param item basename of this item
|
|
4306
4384
|
* @returns true if no more processing is needed for this entry.
|
|
4307
4385
|
*/
|
|
4308
|
-
async _handleSymlink(entry, directory,
|
|
4386
|
+
async _handleSymlink(entry, directory, path9, item) {
|
|
4309
4387
|
if (this.fsw.closed) {
|
|
4310
4388
|
return;
|
|
4311
4389
|
}
|
|
@@ -4315,7 +4393,7 @@ var NodeFsHandler = class {
|
|
|
4315
4393
|
this.fsw._incrReadyCount();
|
|
4316
4394
|
let linkPath;
|
|
4317
4395
|
try {
|
|
4318
|
-
linkPath = await (0, import_promises2.realpath)(
|
|
4396
|
+
linkPath = await (0, import_promises2.realpath)(path9);
|
|
4319
4397
|
} catch (e) {
|
|
4320
4398
|
this.fsw._emitReady();
|
|
4321
4399
|
return true;
|
|
@@ -4325,12 +4403,12 @@ var NodeFsHandler = class {
|
|
|
4325
4403
|
if (dir.has(item)) {
|
|
4326
4404
|
if (this.fsw._symlinkPaths.get(full) !== linkPath) {
|
|
4327
4405
|
this.fsw._symlinkPaths.set(full, linkPath);
|
|
4328
|
-
this.fsw._emit(EV.CHANGE,
|
|
4406
|
+
this.fsw._emit(EV.CHANGE, path9, entry.stats);
|
|
4329
4407
|
}
|
|
4330
4408
|
} else {
|
|
4331
4409
|
dir.add(item);
|
|
4332
4410
|
this.fsw._symlinkPaths.set(full, linkPath);
|
|
4333
|
-
this.fsw._emit(EV.ADD,
|
|
4411
|
+
this.fsw._emit(EV.ADD, path9, entry.stats);
|
|
4334
4412
|
}
|
|
4335
4413
|
this.fsw._emitReady();
|
|
4336
4414
|
return true;
|
|
@@ -4360,9 +4438,9 @@ var NodeFsHandler = class {
|
|
|
4360
4438
|
return;
|
|
4361
4439
|
}
|
|
4362
4440
|
const item = entry.path;
|
|
4363
|
-
let
|
|
4441
|
+
let path9 = sp.join(directory, item);
|
|
4364
4442
|
current.add(item);
|
|
4365
|
-
if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory,
|
|
4443
|
+
if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path9, item)) {
|
|
4366
4444
|
return;
|
|
4367
4445
|
}
|
|
4368
4446
|
if (this.fsw.closed) {
|
|
@@ -4371,8 +4449,8 @@ var NodeFsHandler = class {
|
|
|
4371
4449
|
}
|
|
4372
4450
|
if (item === target || !target && !previous.has(item)) {
|
|
4373
4451
|
this.fsw._incrReadyCount();
|
|
4374
|
-
|
|
4375
|
-
this._addToNodeFs(
|
|
4452
|
+
path9 = sp.join(dir, sp.relative(dir, path9));
|
|
4453
|
+
this._addToNodeFs(path9, initialAdd, wh, depth + 1);
|
|
4376
4454
|
}
|
|
4377
4455
|
}).on(EV.ERROR, this._boundHandleError);
|
|
4378
4456
|
return new Promise((resolve4, reject) => {
|
|
@@ -4441,13 +4519,13 @@ var NodeFsHandler = class {
|
|
|
4441
4519
|
* @param depth Child path actually targeted for watch
|
|
4442
4520
|
* @param target Child path actually targeted for watch
|
|
4443
4521
|
*/
|
|
4444
|
-
async _addToNodeFs(
|
|
4522
|
+
async _addToNodeFs(path9, initialAdd, priorWh, depth, target) {
|
|
4445
4523
|
const ready = this.fsw._emitReady;
|
|
4446
|
-
if (this.fsw._isIgnored(
|
|
4524
|
+
if (this.fsw._isIgnored(path9) || this.fsw.closed) {
|
|
4447
4525
|
ready();
|
|
4448
4526
|
return false;
|
|
4449
4527
|
}
|
|
4450
|
-
const wh = this.fsw._getWatchHelpers(
|
|
4528
|
+
const wh = this.fsw._getWatchHelpers(path9);
|
|
4451
4529
|
if (priorWh) {
|
|
4452
4530
|
wh.filterPath = (entry) => priorWh.filterPath(entry);
|
|
4453
4531
|
wh.filterDir = (entry) => priorWh.filterDir(entry);
|
|
@@ -4463,8 +4541,8 @@ var NodeFsHandler = class {
|
|
|
4463
4541
|
const follow = this.fsw.options.followSymlinks;
|
|
4464
4542
|
let closer;
|
|
4465
4543
|
if (stats.isDirectory()) {
|
|
4466
|
-
const absPath = sp.resolve(
|
|
4467
|
-
const targetPath = follow ? await (0, import_promises2.realpath)(
|
|
4544
|
+
const absPath = sp.resolve(path9);
|
|
4545
|
+
const targetPath = follow ? await (0, import_promises2.realpath)(path9) : path9;
|
|
4468
4546
|
if (this.fsw.closed)
|
|
4469
4547
|
return;
|
|
4470
4548
|
closer = await this._handleDir(wh.watchPath, stats, initialAdd, depth, target, wh, targetPath);
|
|
@@ -4474,29 +4552,29 @@ var NodeFsHandler = class {
|
|
|
4474
4552
|
this.fsw._symlinkPaths.set(absPath, targetPath);
|
|
4475
4553
|
}
|
|
4476
4554
|
} else if (stats.isSymbolicLink()) {
|
|
4477
|
-
const targetPath = follow ? await (0, import_promises2.realpath)(
|
|
4555
|
+
const targetPath = follow ? await (0, import_promises2.realpath)(path9) : path9;
|
|
4478
4556
|
if (this.fsw.closed)
|
|
4479
4557
|
return;
|
|
4480
4558
|
const parent = sp.dirname(wh.watchPath);
|
|
4481
4559
|
this.fsw._getWatchedDir(parent).add(wh.watchPath);
|
|
4482
4560
|
this.fsw._emit(EV.ADD, wh.watchPath, stats);
|
|
4483
|
-
closer = await this._handleDir(parent, stats, initialAdd, depth,
|
|
4561
|
+
closer = await this._handleDir(parent, stats, initialAdd, depth, path9, wh, targetPath);
|
|
4484
4562
|
if (this.fsw.closed)
|
|
4485
4563
|
return;
|
|
4486
4564
|
if (targetPath !== void 0) {
|
|
4487
|
-
this.fsw._symlinkPaths.set(sp.resolve(
|
|
4565
|
+
this.fsw._symlinkPaths.set(sp.resolve(path9), targetPath);
|
|
4488
4566
|
}
|
|
4489
4567
|
} else {
|
|
4490
4568
|
closer = this._handleFile(wh.watchPath, stats, initialAdd);
|
|
4491
4569
|
}
|
|
4492
4570
|
ready();
|
|
4493
4571
|
if (closer)
|
|
4494
|
-
this.fsw._addPathCloser(
|
|
4572
|
+
this.fsw._addPathCloser(path9, closer);
|
|
4495
4573
|
return false;
|
|
4496
4574
|
} catch (error) {
|
|
4497
4575
|
if (this.fsw._handleError(error)) {
|
|
4498
4576
|
ready();
|
|
4499
|
-
return
|
|
4577
|
+
return path9;
|
|
4500
4578
|
}
|
|
4501
4579
|
}
|
|
4502
4580
|
}
|
|
@@ -4539,24 +4617,24 @@ function createPattern(matcher) {
|
|
|
4539
4617
|
}
|
|
4540
4618
|
return () => false;
|
|
4541
4619
|
}
|
|
4542
|
-
function normalizePath(
|
|
4543
|
-
if (typeof
|
|
4620
|
+
function normalizePath(path9) {
|
|
4621
|
+
if (typeof path9 !== "string")
|
|
4544
4622
|
throw new Error("string expected");
|
|
4545
|
-
|
|
4546
|
-
|
|
4623
|
+
path9 = sp2.normalize(path9);
|
|
4624
|
+
path9 = path9.replace(/\\/g, "/");
|
|
4547
4625
|
let prepend = false;
|
|
4548
|
-
if (
|
|
4626
|
+
if (path9.startsWith("//"))
|
|
4549
4627
|
prepend = true;
|
|
4550
|
-
|
|
4628
|
+
path9 = path9.replace(DOUBLE_SLASH_RE, "/");
|
|
4551
4629
|
if (prepend)
|
|
4552
|
-
|
|
4553
|
-
return
|
|
4630
|
+
path9 = "/" + path9;
|
|
4631
|
+
return path9;
|
|
4554
4632
|
}
|
|
4555
4633
|
function matchPatterns(patterns, testString, stats) {
|
|
4556
|
-
const
|
|
4634
|
+
const path9 = normalizePath(testString);
|
|
4557
4635
|
for (let index = 0; index < patterns.length; index++) {
|
|
4558
4636
|
const pattern = patterns[index];
|
|
4559
|
-
if (pattern(
|
|
4637
|
+
if (pattern(path9, stats)) {
|
|
4560
4638
|
return true;
|
|
4561
4639
|
}
|
|
4562
4640
|
}
|
|
@@ -4594,19 +4672,19 @@ var toUnix = (string) => {
|
|
|
4594
4672
|
}
|
|
4595
4673
|
return str;
|
|
4596
4674
|
};
|
|
4597
|
-
var normalizePathToUnix = (
|
|
4598
|
-
var normalizeIgnored = (cwd = "") => (
|
|
4599
|
-
if (typeof
|
|
4600
|
-
return normalizePathToUnix(sp2.isAbsolute(
|
|
4675
|
+
var normalizePathToUnix = (path9) => toUnix(sp2.normalize(toUnix(path9)));
|
|
4676
|
+
var normalizeIgnored = (cwd = "") => (path9) => {
|
|
4677
|
+
if (typeof path9 === "string") {
|
|
4678
|
+
return normalizePathToUnix(sp2.isAbsolute(path9) ? path9 : sp2.join(cwd, path9));
|
|
4601
4679
|
} else {
|
|
4602
|
-
return
|
|
4680
|
+
return path9;
|
|
4603
4681
|
}
|
|
4604
4682
|
};
|
|
4605
|
-
var getAbsolutePath = (
|
|
4606
|
-
if (sp2.isAbsolute(
|
|
4607
|
-
return
|
|
4683
|
+
var getAbsolutePath = (path9, cwd) => {
|
|
4684
|
+
if (sp2.isAbsolute(path9)) {
|
|
4685
|
+
return path9;
|
|
4608
4686
|
}
|
|
4609
|
-
return sp2.join(cwd,
|
|
4687
|
+
return sp2.join(cwd, path9);
|
|
4610
4688
|
};
|
|
4611
4689
|
var EMPTY_SET = Object.freeze(/* @__PURE__ */ new Set());
|
|
4612
4690
|
var DirEntry = class {
|
|
@@ -4671,10 +4749,10 @@ var WatchHelper = class {
|
|
|
4671
4749
|
dirParts;
|
|
4672
4750
|
followSymlinks;
|
|
4673
4751
|
statMethod;
|
|
4674
|
-
constructor(
|
|
4752
|
+
constructor(path9, follow, fsw) {
|
|
4675
4753
|
this.fsw = fsw;
|
|
4676
|
-
const watchPath =
|
|
4677
|
-
this.path =
|
|
4754
|
+
const watchPath = path9;
|
|
4755
|
+
this.path = path9 = path9.replace(REPLACER_RE, "");
|
|
4678
4756
|
this.watchPath = watchPath;
|
|
4679
4757
|
this.fullWatchPath = sp2.resolve(watchPath);
|
|
4680
4758
|
this.dirParts = [];
|
|
@@ -4814,20 +4892,20 @@ var FSWatcher = class extends import_node_events.EventEmitter {
|
|
|
4814
4892
|
this._closePromise = void 0;
|
|
4815
4893
|
let paths = unifyPaths(paths_);
|
|
4816
4894
|
if (cwd) {
|
|
4817
|
-
paths = paths.map((
|
|
4818
|
-
const absPath = getAbsolutePath(
|
|
4895
|
+
paths = paths.map((path9) => {
|
|
4896
|
+
const absPath = getAbsolutePath(path9, cwd);
|
|
4819
4897
|
return absPath;
|
|
4820
4898
|
});
|
|
4821
4899
|
}
|
|
4822
|
-
paths.forEach((
|
|
4823
|
-
this._removeIgnoredPath(
|
|
4900
|
+
paths.forEach((path9) => {
|
|
4901
|
+
this._removeIgnoredPath(path9);
|
|
4824
4902
|
});
|
|
4825
4903
|
this._userIgnored = void 0;
|
|
4826
4904
|
if (!this._readyCount)
|
|
4827
4905
|
this._readyCount = 0;
|
|
4828
4906
|
this._readyCount += paths.length;
|
|
4829
|
-
Promise.all(paths.map(async (
|
|
4830
|
-
const res = await this._nodeFsHandler._addToNodeFs(
|
|
4907
|
+
Promise.all(paths.map(async (path9) => {
|
|
4908
|
+
const res = await this._nodeFsHandler._addToNodeFs(path9, !_internal, void 0, 0, _origAdd);
|
|
4831
4909
|
if (res)
|
|
4832
4910
|
this._emitReady();
|
|
4833
4911
|
return res;
|
|
@@ -4849,17 +4927,17 @@ var FSWatcher = class extends import_node_events.EventEmitter {
|
|
|
4849
4927
|
return this;
|
|
4850
4928
|
const paths = unifyPaths(paths_);
|
|
4851
4929
|
const { cwd } = this.options;
|
|
4852
|
-
paths.forEach((
|
|
4853
|
-
if (!sp2.isAbsolute(
|
|
4930
|
+
paths.forEach((path9) => {
|
|
4931
|
+
if (!sp2.isAbsolute(path9) && !this._closers.has(path9)) {
|
|
4854
4932
|
if (cwd)
|
|
4855
|
-
|
|
4856
|
-
|
|
4933
|
+
path9 = sp2.join(cwd, path9);
|
|
4934
|
+
path9 = sp2.resolve(path9);
|
|
4857
4935
|
}
|
|
4858
|
-
this._closePath(
|
|
4859
|
-
this._addIgnoredPath(
|
|
4860
|
-
if (this._watched.has(
|
|
4936
|
+
this._closePath(path9);
|
|
4937
|
+
this._addIgnoredPath(path9);
|
|
4938
|
+
if (this._watched.has(path9)) {
|
|
4861
4939
|
this._addIgnoredPath({
|
|
4862
|
-
path:
|
|
4940
|
+
path: path9,
|
|
4863
4941
|
recursive: true
|
|
4864
4942
|
});
|
|
4865
4943
|
}
|
|
@@ -4923,38 +5001,38 @@ var FSWatcher = class extends import_node_events.EventEmitter {
|
|
|
4923
5001
|
* @param stats arguments to be passed with event
|
|
4924
5002
|
* @returns the error if defined, otherwise the value of the FSWatcher instance's `closed` flag
|
|
4925
5003
|
*/
|
|
4926
|
-
async _emit(event,
|
|
5004
|
+
async _emit(event, path9, stats) {
|
|
4927
5005
|
if (this.closed)
|
|
4928
5006
|
return;
|
|
4929
5007
|
const opts = this.options;
|
|
4930
5008
|
if (isWindows)
|
|
4931
|
-
|
|
5009
|
+
path9 = sp2.normalize(path9);
|
|
4932
5010
|
if (opts.cwd)
|
|
4933
|
-
|
|
4934
|
-
const args = [
|
|
5011
|
+
path9 = sp2.relative(opts.cwd, path9);
|
|
5012
|
+
const args = [path9];
|
|
4935
5013
|
if (stats != null)
|
|
4936
5014
|
args.push(stats);
|
|
4937
5015
|
const awf = opts.awaitWriteFinish;
|
|
4938
5016
|
let pw;
|
|
4939
|
-
if (awf && (pw = this._pendingWrites.get(
|
|
5017
|
+
if (awf && (pw = this._pendingWrites.get(path9))) {
|
|
4940
5018
|
pw.lastChange = /* @__PURE__ */ new Date();
|
|
4941
5019
|
return this;
|
|
4942
5020
|
}
|
|
4943
5021
|
if (opts.atomic) {
|
|
4944
5022
|
if (event === EVENTS.UNLINK) {
|
|
4945
|
-
this._pendingUnlinks.set(
|
|
5023
|
+
this._pendingUnlinks.set(path9, [event, ...args]);
|
|
4946
5024
|
setTimeout(() => {
|
|
4947
|
-
this._pendingUnlinks.forEach((entry,
|
|
5025
|
+
this._pendingUnlinks.forEach((entry, path10) => {
|
|
4948
5026
|
this.emit(...entry);
|
|
4949
5027
|
this.emit(EVENTS.ALL, ...entry);
|
|
4950
|
-
this._pendingUnlinks.delete(
|
|
5028
|
+
this._pendingUnlinks.delete(path10);
|
|
4951
5029
|
});
|
|
4952
5030
|
}, typeof opts.atomic === "number" ? opts.atomic : 100);
|
|
4953
5031
|
return this;
|
|
4954
5032
|
}
|
|
4955
|
-
if (event === EVENTS.ADD && this._pendingUnlinks.has(
|
|
5033
|
+
if (event === EVENTS.ADD && this._pendingUnlinks.has(path9)) {
|
|
4956
5034
|
event = EVENTS.CHANGE;
|
|
4957
|
-
this._pendingUnlinks.delete(
|
|
5035
|
+
this._pendingUnlinks.delete(path9);
|
|
4958
5036
|
}
|
|
4959
5037
|
}
|
|
4960
5038
|
if (awf && (event === EVENTS.ADD || event === EVENTS.CHANGE) && this._readyEmitted) {
|
|
@@ -4972,16 +5050,16 @@ var FSWatcher = class extends import_node_events.EventEmitter {
|
|
|
4972
5050
|
this.emitWithAll(event, args);
|
|
4973
5051
|
}
|
|
4974
5052
|
};
|
|
4975
|
-
this._awaitWriteFinish(
|
|
5053
|
+
this._awaitWriteFinish(path9, awf.stabilityThreshold, event, awfEmit);
|
|
4976
5054
|
return this;
|
|
4977
5055
|
}
|
|
4978
5056
|
if (event === EVENTS.CHANGE) {
|
|
4979
|
-
const isThrottled = !this._throttle(EVENTS.CHANGE,
|
|
5057
|
+
const isThrottled = !this._throttle(EVENTS.CHANGE, path9, 50);
|
|
4980
5058
|
if (isThrottled)
|
|
4981
5059
|
return this;
|
|
4982
5060
|
}
|
|
4983
5061
|
if (opts.alwaysStat && stats === void 0 && (event === EVENTS.ADD || event === EVENTS.ADD_DIR || event === EVENTS.CHANGE)) {
|
|
4984
|
-
const fullPath = opts.cwd ? sp2.join(opts.cwd,
|
|
5062
|
+
const fullPath = opts.cwd ? sp2.join(opts.cwd, path9) : path9;
|
|
4985
5063
|
let stats2;
|
|
4986
5064
|
try {
|
|
4987
5065
|
stats2 = await (0, import_promises3.stat)(fullPath);
|
|
@@ -5012,23 +5090,23 @@ var FSWatcher = class extends import_node_events.EventEmitter {
|
|
|
5012
5090
|
* @param timeout duration of time to suppress duplicate actions
|
|
5013
5091
|
* @returns tracking object or false if action should be suppressed
|
|
5014
5092
|
*/
|
|
5015
|
-
_throttle(actionType,
|
|
5093
|
+
_throttle(actionType, path9, timeout) {
|
|
5016
5094
|
if (!this._throttled.has(actionType)) {
|
|
5017
5095
|
this._throttled.set(actionType, /* @__PURE__ */ new Map());
|
|
5018
5096
|
}
|
|
5019
5097
|
const action = this._throttled.get(actionType);
|
|
5020
5098
|
if (!action)
|
|
5021
5099
|
throw new Error("invalid throttle");
|
|
5022
|
-
const actionPath = action.get(
|
|
5100
|
+
const actionPath = action.get(path9);
|
|
5023
5101
|
if (actionPath) {
|
|
5024
5102
|
actionPath.count++;
|
|
5025
5103
|
return false;
|
|
5026
5104
|
}
|
|
5027
5105
|
let timeoutObject;
|
|
5028
5106
|
const clear = () => {
|
|
5029
|
-
const item = action.get(
|
|
5107
|
+
const item = action.get(path9);
|
|
5030
5108
|
const count = item ? item.count : 0;
|
|
5031
|
-
action.delete(
|
|
5109
|
+
action.delete(path9);
|
|
5032
5110
|
clearTimeout(timeoutObject);
|
|
5033
5111
|
if (item)
|
|
5034
5112
|
clearTimeout(item.timeoutObject);
|
|
@@ -5036,7 +5114,7 @@ var FSWatcher = class extends import_node_events.EventEmitter {
|
|
|
5036
5114
|
};
|
|
5037
5115
|
timeoutObject = setTimeout(clear, timeout);
|
|
5038
5116
|
const thr = { timeoutObject, clear, count: 0 };
|
|
5039
|
-
action.set(
|
|
5117
|
+
action.set(path9, thr);
|
|
5040
5118
|
return thr;
|
|
5041
5119
|
}
|
|
5042
5120
|
_incrReadyCount() {
|
|
@@ -5050,44 +5128,44 @@ var FSWatcher = class extends import_node_events.EventEmitter {
|
|
|
5050
5128
|
* @param event
|
|
5051
5129
|
* @param awfEmit Callback to be called when ready for event to be emitted.
|
|
5052
5130
|
*/
|
|
5053
|
-
_awaitWriteFinish(
|
|
5131
|
+
_awaitWriteFinish(path9, threshold, event, awfEmit) {
|
|
5054
5132
|
const awf = this.options.awaitWriteFinish;
|
|
5055
5133
|
if (typeof awf !== "object")
|
|
5056
5134
|
return;
|
|
5057
5135
|
const pollInterval = awf.pollInterval;
|
|
5058
5136
|
let timeoutHandler;
|
|
5059
|
-
let fullPath =
|
|
5060
|
-
if (this.options.cwd && !sp2.isAbsolute(
|
|
5061
|
-
fullPath = sp2.join(this.options.cwd,
|
|
5137
|
+
let fullPath = path9;
|
|
5138
|
+
if (this.options.cwd && !sp2.isAbsolute(path9)) {
|
|
5139
|
+
fullPath = sp2.join(this.options.cwd, path9);
|
|
5062
5140
|
}
|
|
5063
5141
|
const now = /* @__PURE__ */ new Date();
|
|
5064
5142
|
const writes = this._pendingWrites;
|
|
5065
5143
|
function awaitWriteFinishFn(prevStat) {
|
|
5066
5144
|
(0, import_node_fs2.stat)(fullPath, (err, curStat) => {
|
|
5067
|
-
if (err || !writes.has(
|
|
5145
|
+
if (err || !writes.has(path9)) {
|
|
5068
5146
|
if (err && err.code !== "ENOENT")
|
|
5069
5147
|
awfEmit(err);
|
|
5070
5148
|
return;
|
|
5071
5149
|
}
|
|
5072
5150
|
const now2 = Number(/* @__PURE__ */ new Date());
|
|
5073
5151
|
if (prevStat && curStat.size !== prevStat.size) {
|
|
5074
|
-
writes.get(
|
|
5152
|
+
writes.get(path9).lastChange = now2;
|
|
5075
5153
|
}
|
|
5076
|
-
const pw = writes.get(
|
|
5154
|
+
const pw = writes.get(path9);
|
|
5077
5155
|
const df = now2 - pw.lastChange;
|
|
5078
5156
|
if (df >= threshold) {
|
|
5079
|
-
writes.delete(
|
|
5157
|
+
writes.delete(path9);
|
|
5080
5158
|
awfEmit(void 0, curStat);
|
|
5081
5159
|
} else {
|
|
5082
5160
|
timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval, curStat);
|
|
5083
5161
|
}
|
|
5084
5162
|
});
|
|
5085
5163
|
}
|
|
5086
|
-
if (!writes.has(
|
|
5087
|
-
writes.set(
|
|
5164
|
+
if (!writes.has(path9)) {
|
|
5165
|
+
writes.set(path9, {
|
|
5088
5166
|
lastChange: now,
|
|
5089
5167
|
cancelWait: () => {
|
|
5090
|
-
writes.delete(
|
|
5168
|
+
writes.delete(path9);
|
|
5091
5169
|
clearTimeout(timeoutHandler);
|
|
5092
5170
|
return event;
|
|
5093
5171
|
}
|
|
@@ -5098,8 +5176,8 @@ var FSWatcher = class extends import_node_events.EventEmitter {
|
|
|
5098
5176
|
/**
|
|
5099
5177
|
* Determines whether user has asked to ignore this path.
|
|
5100
5178
|
*/
|
|
5101
|
-
_isIgnored(
|
|
5102
|
-
if (this.options.atomic && DOT_RE.test(
|
|
5179
|
+
_isIgnored(path9, stats) {
|
|
5180
|
+
if (this.options.atomic && DOT_RE.test(path9))
|
|
5103
5181
|
return true;
|
|
5104
5182
|
if (!this._userIgnored) {
|
|
5105
5183
|
const { cwd } = this.options;
|
|
@@ -5109,17 +5187,17 @@ var FSWatcher = class extends import_node_events.EventEmitter {
|
|
|
5109
5187
|
const list = [...ignoredPaths.map(normalizeIgnored(cwd)), ...ignored];
|
|
5110
5188
|
this._userIgnored = anymatch(list, void 0);
|
|
5111
5189
|
}
|
|
5112
|
-
return this._userIgnored(
|
|
5190
|
+
return this._userIgnored(path9, stats);
|
|
5113
5191
|
}
|
|
5114
|
-
_isntIgnored(
|
|
5115
|
-
return !this._isIgnored(
|
|
5192
|
+
_isntIgnored(path9, stat4) {
|
|
5193
|
+
return !this._isIgnored(path9, stat4);
|
|
5116
5194
|
}
|
|
5117
5195
|
/**
|
|
5118
5196
|
* Provides a set of common helpers and properties relating to symlink handling.
|
|
5119
5197
|
* @param path file or directory pattern being watched
|
|
5120
5198
|
*/
|
|
5121
|
-
_getWatchHelpers(
|
|
5122
|
-
return new WatchHelper(
|
|
5199
|
+
_getWatchHelpers(path9) {
|
|
5200
|
+
return new WatchHelper(path9, this.options.followSymlinks, this);
|
|
5123
5201
|
}
|
|
5124
5202
|
// Directory helpers
|
|
5125
5203
|
// -----------------
|
|
@@ -5151,63 +5229,63 @@ var FSWatcher = class extends import_node_events.EventEmitter {
|
|
|
5151
5229
|
* @param item base path of item/directory
|
|
5152
5230
|
*/
|
|
5153
5231
|
_remove(directory, item, isDirectory) {
|
|
5154
|
-
const
|
|
5155
|
-
const fullPath = sp2.resolve(
|
|
5156
|
-
isDirectory = isDirectory != null ? isDirectory : this._watched.has(
|
|
5157
|
-
if (!this._throttle("remove",
|
|
5232
|
+
const path9 = sp2.join(directory, item);
|
|
5233
|
+
const fullPath = sp2.resolve(path9);
|
|
5234
|
+
isDirectory = isDirectory != null ? isDirectory : this._watched.has(path9) || this._watched.has(fullPath);
|
|
5235
|
+
if (!this._throttle("remove", path9, 100))
|
|
5158
5236
|
return;
|
|
5159
5237
|
if (!isDirectory && this._watched.size === 1) {
|
|
5160
5238
|
this.add(directory, item, true);
|
|
5161
5239
|
}
|
|
5162
|
-
const wp = this._getWatchedDir(
|
|
5240
|
+
const wp = this._getWatchedDir(path9);
|
|
5163
5241
|
const nestedDirectoryChildren = wp.getChildren();
|
|
5164
|
-
nestedDirectoryChildren.forEach((nested) => this._remove(
|
|
5242
|
+
nestedDirectoryChildren.forEach((nested) => this._remove(path9, nested));
|
|
5165
5243
|
const parent = this._getWatchedDir(directory);
|
|
5166
5244
|
const wasTracked = parent.has(item);
|
|
5167
5245
|
parent.remove(item);
|
|
5168
5246
|
if (this._symlinkPaths.has(fullPath)) {
|
|
5169
5247
|
this._symlinkPaths.delete(fullPath);
|
|
5170
5248
|
}
|
|
5171
|
-
let relPath =
|
|
5249
|
+
let relPath = path9;
|
|
5172
5250
|
if (this.options.cwd)
|
|
5173
|
-
relPath = sp2.relative(this.options.cwd,
|
|
5251
|
+
relPath = sp2.relative(this.options.cwd, path9);
|
|
5174
5252
|
if (this.options.awaitWriteFinish && this._pendingWrites.has(relPath)) {
|
|
5175
5253
|
const event = this._pendingWrites.get(relPath).cancelWait();
|
|
5176
5254
|
if (event === EVENTS.ADD)
|
|
5177
5255
|
return;
|
|
5178
5256
|
}
|
|
5179
|
-
this._watched.delete(
|
|
5257
|
+
this._watched.delete(path9);
|
|
5180
5258
|
this._watched.delete(fullPath);
|
|
5181
5259
|
const eventName = isDirectory ? EVENTS.UNLINK_DIR : EVENTS.UNLINK;
|
|
5182
|
-
if (wasTracked && !this._isIgnored(
|
|
5183
|
-
this._emit(eventName,
|
|
5184
|
-
this._closePath(
|
|
5260
|
+
if (wasTracked && !this._isIgnored(path9))
|
|
5261
|
+
this._emit(eventName, path9);
|
|
5262
|
+
this._closePath(path9);
|
|
5185
5263
|
}
|
|
5186
5264
|
/**
|
|
5187
5265
|
* Closes all watchers for a path
|
|
5188
5266
|
*/
|
|
5189
|
-
_closePath(
|
|
5190
|
-
this._closeFile(
|
|
5191
|
-
const dir = sp2.dirname(
|
|
5192
|
-
this._getWatchedDir(dir).remove(sp2.basename(
|
|
5267
|
+
_closePath(path9) {
|
|
5268
|
+
this._closeFile(path9);
|
|
5269
|
+
const dir = sp2.dirname(path9);
|
|
5270
|
+
this._getWatchedDir(dir).remove(sp2.basename(path9));
|
|
5193
5271
|
}
|
|
5194
5272
|
/**
|
|
5195
5273
|
* Closes only file-specific watchers
|
|
5196
5274
|
*/
|
|
5197
|
-
_closeFile(
|
|
5198
|
-
const closers = this._closers.get(
|
|
5275
|
+
_closeFile(path9) {
|
|
5276
|
+
const closers = this._closers.get(path9);
|
|
5199
5277
|
if (!closers)
|
|
5200
5278
|
return;
|
|
5201
5279
|
closers.forEach((closer) => closer());
|
|
5202
|
-
this._closers.delete(
|
|
5280
|
+
this._closers.delete(path9);
|
|
5203
5281
|
}
|
|
5204
|
-
_addPathCloser(
|
|
5282
|
+
_addPathCloser(path9, closer) {
|
|
5205
5283
|
if (!closer)
|
|
5206
5284
|
return;
|
|
5207
|
-
let list = this._closers.get(
|
|
5285
|
+
let list = this._closers.get(path9);
|
|
5208
5286
|
if (!list) {
|
|
5209
5287
|
list = [];
|
|
5210
|
-
this._closers.set(
|
|
5288
|
+
this._closers.set(path9, list);
|
|
5211
5289
|
}
|
|
5212
5290
|
list.push(closer);
|
|
5213
5291
|
}
|
|
@@ -5302,7 +5380,7 @@ var FileWatcher = class {
|
|
|
5302
5380
|
return;
|
|
5303
5381
|
}
|
|
5304
5382
|
const changes = Array.from(this.pendingChanges.entries()).map(
|
|
5305
|
-
([
|
|
5383
|
+
([path9, type]) => ({ path: path9, type })
|
|
5306
5384
|
);
|
|
5307
5385
|
this.pendingChanges.clear();
|
|
5308
5386
|
try {
|
|
@@ -5482,7 +5560,7 @@ var index_codebase = (0, import_plugin.tool)({
|
|
|
5482
5560
|
estimateOnly: z.boolean().optional().default(false).describe("Only show cost estimate without indexing"),
|
|
5483
5561
|
verbose: z.boolean().optional().default(false).describe("Show detailed info about skipped files and parsing failures")
|
|
5484
5562
|
},
|
|
5485
|
-
async execute(args) {
|
|
5563
|
+
async execute(args, context) {
|
|
5486
5564
|
const indexer = getIndexer();
|
|
5487
5565
|
if (args.estimateOnly) {
|
|
5488
5566
|
const estimate = await indexer.estimateCost();
|
|
@@ -5491,7 +5569,19 @@ var index_codebase = (0, import_plugin.tool)({
|
|
|
5491
5569
|
if (args.force) {
|
|
5492
5570
|
await indexer.clearIndex();
|
|
5493
5571
|
}
|
|
5494
|
-
const stats = await indexer.index()
|
|
5572
|
+
const stats = await indexer.index((progress) => {
|
|
5573
|
+
context.metadata({
|
|
5574
|
+
title: formatProgressTitle(progress),
|
|
5575
|
+
metadata: {
|
|
5576
|
+
phase: progress.phase,
|
|
5577
|
+
filesProcessed: progress.filesProcessed,
|
|
5578
|
+
totalFiles: progress.totalFiles,
|
|
5579
|
+
chunksProcessed: progress.chunksProcessed,
|
|
5580
|
+
totalChunks: progress.totalChunks,
|
|
5581
|
+
percentage: calculatePercentage(progress)
|
|
5582
|
+
}
|
|
5583
|
+
});
|
|
5584
|
+
});
|
|
5495
5585
|
return formatIndexStats(stats, args.verbose ?? false);
|
|
5496
5586
|
}
|
|
5497
5587
|
});
|
|
@@ -5590,12 +5680,91 @@ function formatStatus(status) {
|
|
|
5590
5680
|
}
|
|
5591
5681
|
return lines.join("\n");
|
|
5592
5682
|
}
|
|
5683
|
+
function formatProgressTitle(progress) {
|
|
5684
|
+
switch (progress.phase) {
|
|
5685
|
+
case "scanning":
|
|
5686
|
+
return "Scanning files...";
|
|
5687
|
+
case "parsing":
|
|
5688
|
+
return `Parsing: ${progress.filesProcessed}/${progress.totalFiles} files`;
|
|
5689
|
+
case "embedding":
|
|
5690
|
+
return `Embedding: ${progress.chunksProcessed}/${progress.totalChunks} chunks`;
|
|
5691
|
+
case "storing":
|
|
5692
|
+
return "Storing index...";
|
|
5693
|
+
case "complete":
|
|
5694
|
+
return "Indexing complete";
|
|
5695
|
+
default:
|
|
5696
|
+
return "Indexing...";
|
|
5697
|
+
}
|
|
5698
|
+
}
|
|
5699
|
+
function calculatePercentage(progress) {
|
|
5700
|
+
if (progress.phase === "scanning") return 0;
|
|
5701
|
+
if (progress.phase === "complete") return 100;
|
|
5702
|
+
if (progress.phase === "parsing") {
|
|
5703
|
+
if (progress.totalFiles === 0) return 5;
|
|
5704
|
+
return Math.round(5 + progress.filesProcessed / progress.totalFiles * 15);
|
|
5705
|
+
}
|
|
5706
|
+
if (progress.phase === "embedding") {
|
|
5707
|
+
if (progress.totalChunks === 0) return 20;
|
|
5708
|
+
return Math.round(20 + progress.chunksProcessed / progress.totalChunks * 70);
|
|
5709
|
+
}
|
|
5710
|
+
if (progress.phase === "storing") return 95;
|
|
5711
|
+
return 0;
|
|
5712
|
+
}
|
|
5713
|
+
|
|
5714
|
+
// src/commands/loader.ts
|
|
5715
|
+
var import_fs5 = require("fs");
|
|
5716
|
+
var path7 = __toESM(require("path"), 1);
|
|
5717
|
+
function parseFrontmatter(content) {
|
|
5718
|
+
const frontmatterRegex = /^---\s*\n([\s\S]*?)\n---\s*\n([\s\S]*)$/;
|
|
5719
|
+
const match = content.match(frontmatterRegex);
|
|
5720
|
+
if (!match) {
|
|
5721
|
+
return { frontmatter: {}, body: content.trim() };
|
|
5722
|
+
}
|
|
5723
|
+
const frontmatterLines = match[1].split("\n");
|
|
5724
|
+
const frontmatter = {};
|
|
5725
|
+
for (const line of frontmatterLines) {
|
|
5726
|
+
const colonIndex = line.indexOf(":");
|
|
5727
|
+
if (colonIndex > 0) {
|
|
5728
|
+
const key = line.slice(0, colonIndex).trim();
|
|
5729
|
+
const value = line.slice(colonIndex + 1).trim();
|
|
5730
|
+
frontmatter[key] = value;
|
|
5731
|
+
}
|
|
5732
|
+
}
|
|
5733
|
+
return { frontmatter, body: match[2].trim() };
|
|
5734
|
+
}
|
|
5735
|
+
function loadCommandsFromDirectory(commandsDir) {
|
|
5736
|
+
const commands = /* @__PURE__ */ new Map();
|
|
5737
|
+
if (!(0, import_fs5.existsSync)(commandsDir)) {
|
|
5738
|
+
return commands;
|
|
5739
|
+
}
|
|
5740
|
+
const files = (0, import_fs5.readdirSync)(commandsDir).filter((f) => f.endsWith(".md"));
|
|
5741
|
+
for (const file of files) {
|
|
5742
|
+
const filePath = path7.join(commandsDir, file);
|
|
5743
|
+
const content = (0, import_fs5.readFileSync)(filePath, "utf-8");
|
|
5744
|
+
const { frontmatter, body } = parseFrontmatter(content);
|
|
5745
|
+
const name = path7.basename(file, ".md");
|
|
5746
|
+
const description = frontmatter.description || `Run the ${name} command`;
|
|
5747
|
+
commands.set(name, {
|
|
5748
|
+
description,
|
|
5749
|
+
template: body
|
|
5750
|
+
});
|
|
5751
|
+
}
|
|
5752
|
+
return commands;
|
|
5753
|
+
}
|
|
5593
5754
|
|
|
5594
5755
|
// src/index.ts
|
|
5756
|
+
var import_meta2 = {};
|
|
5757
|
+
function getCommandsDir() {
|
|
5758
|
+
let currentDir = process.cwd();
|
|
5759
|
+
if (typeof import_meta2 !== "undefined" && import_meta2.url) {
|
|
5760
|
+
currentDir = path8.dirname((0, import_url2.fileURLToPath)(import_meta2.url));
|
|
5761
|
+
}
|
|
5762
|
+
return path8.join(currentDir, "..", "commands");
|
|
5763
|
+
}
|
|
5595
5764
|
function loadJsonFile(filePath) {
|
|
5596
5765
|
try {
|
|
5597
|
-
if ((0,
|
|
5598
|
-
const content = (0,
|
|
5766
|
+
if ((0, import_fs6.existsSync)(filePath)) {
|
|
5767
|
+
const content = (0, import_fs6.readFileSync)(filePath, "utf-8");
|
|
5599
5768
|
return JSON.parse(content);
|
|
5600
5769
|
}
|
|
5601
5770
|
} catch {
|
|
@@ -5603,11 +5772,11 @@ function loadJsonFile(filePath) {
|
|
|
5603
5772
|
return null;
|
|
5604
5773
|
}
|
|
5605
5774
|
function loadPluginConfig(projectRoot) {
|
|
5606
|
-
const projectConfig = loadJsonFile(
|
|
5775
|
+
const projectConfig = loadJsonFile(path8.join(projectRoot, ".opencode", "codebase-index.json"));
|
|
5607
5776
|
if (projectConfig) {
|
|
5608
5777
|
return projectConfig;
|
|
5609
5778
|
}
|
|
5610
|
-
const globalConfigPath =
|
|
5779
|
+
const globalConfigPath = path8.join(os3.homedir(), ".config", "opencode", "codebase-index.json");
|
|
5611
5780
|
const globalConfig = loadJsonFile(globalConfigPath);
|
|
5612
5781
|
if (globalConfig) {
|
|
5613
5782
|
return globalConfig;
|
|
@@ -5639,36 +5808,11 @@ var plugin = async ({ directory }) => {
|
|
|
5639
5808
|
},
|
|
5640
5809
|
async config(cfg) {
|
|
5641
5810
|
cfg.command = cfg.command ?? {};
|
|
5642
|
-
|
|
5643
|
-
|
|
5644
|
-
|
|
5645
|
-
|
|
5646
|
-
|
|
5647
|
-
|
|
5648
|
-
Return the most relevant results with file paths and line numbers.`
|
|
5649
|
-
};
|
|
5650
|
-
cfg.command["find"] = {
|
|
5651
|
-
description: "Find code using hybrid approach (semantic + grep)",
|
|
5652
|
-
template: `Find code related to: $ARGUMENTS
|
|
5653
|
-
|
|
5654
|
-
Strategy:
|
|
5655
|
-
1. First use \`codebase_search\` to find semantically related code
|
|
5656
|
-
2. From the results, identify specific function/class names
|
|
5657
|
-
3. Use grep to find all occurrences of those identifiers
|
|
5658
|
-
4. Combine findings into a comprehensive answer
|
|
5659
|
-
|
|
5660
|
-
If the semantic index doesn't exist, run \`index_codebase\` first.`
|
|
5661
|
-
};
|
|
5662
|
-
cfg.command["index"] = {
|
|
5663
|
-
description: "Index the codebase for semantic search",
|
|
5664
|
-
template: `Run the \`index_codebase\` tool to create or update the semantic search index.
|
|
5665
|
-
|
|
5666
|
-
Show progress and final statistics including:
|
|
5667
|
-
- Number of files processed
|
|
5668
|
-
- Number of chunks indexed
|
|
5669
|
-
- Tokens used
|
|
5670
|
-
- Duration`
|
|
5671
|
-
};
|
|
5811
|
+
const commandsDir = getCommandsDir();
|
|
5812
|
+
const commands = loadCommandsFromDirectory(commandsDir);
|
|
5813
|
+
for (const [name, definition] of commands) {
|
|
5814
|
+
cfg.command[name] = definition;
|
|
5815
|
+
}
|
|
5672
5816
|
}
|
|
5673
5817
|
};
|
|
5674
5818
|
};
|