opencode-codebase-index 0.8.1 → 0.10.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 +32 -13
- package/dist/cli.cjs +1526 -1293
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +1525 -1292
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +1235 -968
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1206 -939
- 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 +8 -2
package/dist/index.cjs
CHANGED
|
@@ -329,7 +329,7 @@ var require_ignore = __commonJS({
|
|
|
329
329
|
// path matching.
|
|
330
330
|
// - check `string` either `MODE_IGNORE` or `MODE_CHECK_IGNORE`
|
|
331
331
|
// @returns {TestResult} true if a file is ignored
|
|
332
|
-
test(
|
|
332
|
+
test(path18, checkUnignored, mode) {
|
|
333
333
|
let ignored = false;
|
|
334
334
|
let unignored = false;
|
|
335
335
|
let matchedRule;
|
|
@@ -338,7 +338,7 @@ var require_ignore = __commonJS({
|
|
|
338
338
|
if (unignored === negative && ignored !== unignored || negative && !ignored && !unignored && !checkUnignored) {
|
|
339
339
|
return;
|
|
340
340
|
}
|
|
341
|
-
const matched = rule[mode].test(
|
|
341
|
+
const matched = rule[mode].test(path18);
|
|
342
342
|
if (!matched) {
|
|
343
343
|
return;
|
|
344
344
|
}
|
|
@@ -359,17 +359,17 @@ var require_ignore = __commonJS({
|
|
|
359
359
|
var throwError = (message, Ctor) => {
|
|
360
360
|
throw new Ctor(message);
|
|
361
361
|
};
|
|
362
|
-
var checkPath = (
|
|
363
|
-
if (!isString(
|
|
362
|
+
var checkPath = (path18, originalPath, doThrow) => {
|
|
363
|
+
if (!isString(path18)) {
|
|
364
364
|
return doThrow(
|
|
365
365
|
`path must be a string, but got \`${originalPath}\``,
|
|
366
366
|
TypeError
|
|
367
367
|
);
|
|
368
368
|
}
|
|
369
|
-
if (!
|
|
369
|
+
if (!path18) {
|
|
370
370
|
return doThrow(`path must not be empty`, TypeError);
|
|
371
371
|
}
|
|
372
|
-
if (checkPath.isNotRelative(
|
|
372
|
+
if (checkPath.isNotRelative(path18)) {
|
|
373
373
|
const r = "`path.relative()`d";
|
|
374
374
|
return doThrow(
|
|
375
375
|
`path should be a ${r} string, but got "${originalPath}"`,
|
|
@@ -378,7 +378,7 @@ var require_ignore = __commonJS({
|
|
|
378
378
|
}
|
|
379
379
|
return true;
|
|
380
380
|
};
|
|
381
|
-
var isNotRelative = (
|
|
381
|
+
var isNotRelative = (path18) => REGEX_TEST_INVALID_PATH.test(path18);
|
|
382
382
|
checkPath.isNotRelative = isNotRelative;
|
|
383
383
|
checkPath.convert = (p) => p;
|
|
384
384
|
var Ignore2 = class {
|
|
@@ -408,19 +408,19 @@ var require_ignore = __commonJS({
|
|
|
408
408
|
}
|
|
409
409
|
// @returns {TestResult}
|
|
410
410
|
_test(originalPath, cache, checkUnignored, slices) {
|
|
411
|
-
const
|
|
411
|
+
const path18 = originalPath && checkPath.convert(originalPath);
|
|
412
412
|
checkPath(
|
|
413
|
-
|
|
413
|
+
path18,
|
|
414
414
|
originalPath,
|
|
415
415
|
this._strictPathCheck ? throwError : RETURN_FALSE
|
|
416
416
|
);
|
|
417
|
-
return this._t(
|
|
417
|
+
return this._t(path18, cache, checkUnignored, slices);
|
|
418
418
|
}
|
|
419
|
-
checkIgnore(
|
|
420
|
-
if (!REGEX_TEST_TRAILING_SLASH.test(
|
|
421
|
-
return this.test(
|
|
419
|
+
checkIgnore(path18) {
|
|
420
|
+
if (!REGEX_TEST_TRAILING_SLASH.test(path18)) {
|
|
421
|
+
return this.test(path18);
|
|
422
422
|
}
|
|
423
|
-
const slices =
|
|
423
|
+
const slices = path18.split(SLASH2).filter(Boolean);
|
|
424
424
|
slices.pop();
|
|
425
425
|
if (slices.length) {
|
|
426
426
|
const parent = this._t(
|
|
@@ -433,18 +433,18 @@ var require_ignore = __commonJS({
|
|
|
433
433
|
return parent;
|
|
434
434
|
}
|
|
435
435
|
}
|
|
436
|
-
return this._rules.test(
|
|
436
|
+
return this._rules.test(path18, false, MODE_CHECK_IGNORE);
|
|
437
437
|
}
|
|
438
|
-
_t(
|
|
439
|
-
if (
|
|
440
|
-
return cache[
|
|
438
|
+
_t(path18, cache, checkUnignored, slices) {
|
|
439
|
+
if (path18 in cache) {
|
|
440
|
+
return cache[path18];
|
|
441
441
|
}
|
|
442
442
|
if (!slices) {
|
|
443
|
-
slices =
|
|
443
|
+
slices = path18.split(SLASH2).filter(Boolean);
|
|
444
444
|
}
|
|
445
445
|
slices.pop();
|
|
446
446
|
if (!slices.length) {
|
|
447
|
-
return cache[
|
|
447
|
+
return cache[path18] = this._rules.test(path18, checkUnignored, MODE_IGNORE);
|
|
448
448
|
}
|
|
449
449
|
const parent = this._t(
|
|
450
450
|
slices.join(SLASH2) + SLASH2,
|
|
@@ -452,29 +452,29 @@ var require_ignore = __commonJS({
|
|
|
452
452
|
checkUnignored,
|
|
453
453
|
slices
|
|
454
454
|
);
|
|
455
|
-
return cache[
|
|
455
|
+
return cache[path18] = parent.ignored ? parent : this._rules.test(path18, checkUnignored, MODE_IGNORE);
|
|
456
456
|
}
|
|
457
|
-
ignores(
|
|
458
|
-
return this._test(
|
|
457
|
+
ignores(path18) {
|
|
458
|
+
return this._test(path18, this._ignoreCache, false).ignored;
|
|
459
459
|
}
|
|
460
460
|
createFilter() {
|
|
461
|
-
return (
|
|
461
|
+
return (path18) => !this.ignores(path18);
|
|
462
462
|
}
|
|
463
463
|
filter(paths) {
|
|
464
464
|
return makeArray(paths).filter(this.createFilter());
|
|
465
465
|
}
|
|
466
466
|
// @returns {TestResult}
|
|
467
|
-
test(
|
|
468
|
-
return this._test(
|
|
467
|
+
test(path18) {
|
|
468
|
+
return this._test(path18, this._testCache, true);
|
|
469
469
|
}
|
|
470
470
|
};
|
|
471
471
|
var factory = (options) => new Ignore2(options);
|
|
472
|
-
var isPathValid = (
|
|
472
|
+
var isPathValid = (path18) => checkPath(path18 && checkPath.convert(path18), path18, RETURN_FALSE);
|
|
473
473
|
var setupWindows = () => {
|
|
474
474
|
const makePosix = (str) => /^\\\\\?\\/.test(str) || /["<>|\u0000-\u001F]+/u.test(str) ? str : str.replace(/\\/g, "/");
|
|
475
475
|
checkPath.convert = makePosix;
|
|
476
476
|
const REGEX_TEST_WINDOWS_PATH_ABSOLUTE = /^[a-z]:\//i;
|
|
477
|
-
checkPath.isNotRelative = (
|
|
477
|
+
checkPath.isNotRelative = (path18) => REGEX_TEST_WINDOWS_PATH_ABSOLUTE.test(path18) || isNotRelative(path18);
|
|
478
478
|
};
|
|
479
479
|
if (
|
|
480
480
|
// Detect `process` so that it can run in browsers.
|
|
@@ -657,7 +657,8 @@ __export(index_exports, {
|
|
|
657
657
|
default: () => index_default
|
|
658
658
|
});
|
|
659
659
|
module.exports = __toCommonJS(index_exports);
|
|
660
|
-
var
|
|
660
|
+
var os6 = __toESM(require("os"), 1);
|
|
661
|
+
var path17 = __toESM(require("path"), 1);
|
|
661
662
|
var import_url2 = require("url");
|
|
662
663
|
|
|
663
664
|
// src/config/constants.ts
|
|
@@ -674,7 +675,8 @@ var DEFAULT_INCLUDE = [
|
|
|
674
675
|
"**/*.{md,mdx}",
|
|
675
676
|
"**/*.{sh,bash,zsh}",
|
|
676
677
|
"**/*.{txt,html,htm}",
|
|
677
|
-
"**/*.zig"
|
|
678
|
+
"**/*.zig",
|
|
679
|
+
"**/*.gd"
|
|
678
680
|
];
|
|
679
681
|
var DEFAULT_EXCLUDE = [
|
|
680
682
|
"**/node_modules/**",
|
|
@@ -773,28 +775,7 @@ var AUTO_DETECT_PROVIDER_ORDER = [
|
|
|
773
775
|
"google"
|
|
774
776
|
];
|
|
775
777
|
|
|
776
|
-
// src/config/
|
|
777
|
-
var ENV_REFERENCE_PATTERN = /^\{env:([A-Z_][A-Z0-9_]*)\}$/;
|
|
778
|
-
var ENV_REFERENCE_LIKE_PATTERN = /\{env:[^}]+\}/;
|
|
779
|
-
function substituteEnvString(value, keyPath) {
|
|
780
|
-
const match = value.match(ENV_REFERENCE_PATTERN);
|
|
781
|
-
if (!match) {
|
|
782
|
-
if (ENV_REFERENCE_LIKE_PATTERN.test(value)) {
|
|
783
|
-
throw new Error(
|
|
784
|
-
`Invalid environment variable reference at '${keyPath}'. Expected the entire string to match '{env:VAR_NAME}' with VAR_NAME matching [A-Z_][A-Z0-9_]*.`
|
|
785
|
-
);
|
|
786
|
-
}
|
|
787
|
-
return value;
|
|
788
|
-
}
|
|
789
|
-
const variableName = match[1];
|
|
790
|
-
const envValue = process.env[variableName];
|
|
791
|
-
if (envValue === void 0) {
|
|
792
|
-
throw new Error(`Missing environment variable '${variableName}' referenced by config at '${keyPath}'.`);
|
|
793
|
-
}
|
|
794
|
-
return envValue;
|
|
795
|
-
}
|
|
796
|
-
|
|
797
|
-
// src/config/schema.ts
|
|
778
|
+
// src/config/defaults.ts
|
|
798
779
|
function getDefaultIndexingConfig() {
|
|
799
780
|
return {
|
|
800
781
|
autoIndex: false,
|
|
@@ -823,15 +804,10 @@ function getDefaultSearchConfig() {
|
|
|
823
804
|
rrfK: 60,
|
|
824
805
|
rerankTopN: 20,
|
|
825
806
|
contextLines: 0,
|
|
826
|
-
routingHints: true
|
|
807
|
+
routingHints: true,
|
|
808
|
+
routingHintRole: "system"
|
|
827
809
|
};
|
|
828
810
|
}
|
|
829
|
-
function isValidFusionStrategy(value) {
|
|
830
|
-
return value === "weighted" || value === "rrf";
|
|
831
|
-
}
|
|
832
|
-
function isValidRerankerProvider(value) {
|
|
833
|
-
return value === "cohere" || value === "jina" || value === "custom";
|
|
834
|
-
}
|
|
835
811
|
function getDefaultRerankerBaseUrl(provider) {
|
|
836
812
|
switch (provider) {
|
|
837
813
|
case "cohere":
|
|
@@ -854,8 +830,37 @@ function getDefaultDebugConfig() {
|
|
|
854
830
|
metrics: true
|
|
855
831
|
};
|
|
856
832
|
}
|
|
833
|
+
|
|
834
|
+
// src/config/env-substitution.ts
|
|
835
|
+
var ENV_REFERENCE_PATTERN = /^\{env:([A-Z_][A-Z0-9_]*)\}$/;
|
|
836
|
+
var ENV_REFERENCE_LIKE_PATTERN = /\{env:[^}]+\}/;
|
|
837
|
+
function substituteEnvString(value, keyPath) {
|
|
838
|
+
const match = value.match(ENV_REFERENCE_PATTERN);
|
|
839
|
+
if (!match) {
|
|
840
|
+
if (ENV_REFERENCE_LIKE_PATTERN.test(value)) {
|
|
841
|
+
throw new Error(
|
|
842
|
+
`Invalid environment variable reference at '${keyPath}'. Expected the entire string to match '{env:VAR_NAME}' with VAR_NAME matching [A-Z_][A-Z0-9_]*.`
|
|
843
|
+
);
|
|
844
|
+
}
|
|
845
|
+
return value;
|
|
846
|
+
}
|
|
847
|
+
const variableName = match[1];
|
|
848
|
+
const envValue = process.env[variableName];
|
|
849
|
+
if (envValue === void 0) {
|
|
850
|
+
throw new Error(`Missing environment variable '${variableName}' referenced by config at '${keyPath}'.`);
|
|
851
|
+
}
|
|
852
|
+
return envValue;
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
// src/config/validators.ts
|
|
857
856
|
var VALID_SCOPES = ["project", "global"];
|
|
858
857
|
var VALID_LOG_LEVELS = ["error", "warn", "info", "debug"];
|
|
858
|
+
function isValidFusionStrategy(value) {
|
|
859
|
+
return value === "weighted" || value === "rrf";
|
|
860
|
+
}
|
|
861
|
+
function isValidRerankerProvider(value) {
|
|
862
|
+
return value === "cohere" || value === "jina" || value === "custom";
|
|
863
|
+
}
|
|
859
864
|
function isValidProvider(value) {
|
|
860
865
|
return typeof value === "string" && Object.keys(EMBEDDING_MODELS).includes(value);
|
|
861
866
|
}
|
|
@@ -883,6 +888,8 @@ function getResolvedStringArray(value, keyPath) {
|
|
|
883
888
|
function isValidLogLevel(value) {
|
|
884
889
|
return typeof value === "string" && VALID_LOG_LEVELS.includes(value);
|
|
885
890
|
}
|
|
891
|
+
|
|
892
|
+
// src/config/schema.ts
|
|
886
893
|
function parseConfig(raw) {
|
|
887
894
|
const input = raw && typeof raw === "object" ? raw : {};
|
|
888
895
|
const embeddingProviderValue = getResolvedString(input.embeddingProvider, "$root.embeddingProvider");
|
|
@@ -919,7 +926,8 @@ function parseConfig(raw) {
|
|
|
919
926
|
rrfK: typeof rawSearch.rrfK === "number" ? Math.max(1, Math.floor(rawSearch.rrfK)) : defaultSearch.rrfK,
|
|
920
927
|
rerankTopN: typeof rawSearch.rerankTopN === "number" ? Math.min(200, Math.max(0, Math.floor(rawSearch.rerankTopN))) : defaultSearch.rerankTopN,
|
|
921
928
|
contextLines: typeof rawSearch.contextLines === "number" ? Math.min(50, Math.max(0, rawSearch.contextLines)) : defaultSearch.contextLines,
|
|
922
|
-
routingHints: typeof rawSearch.routingHints === "boolean" ? rawSearch.routingHints : defaultSearch.routingHints
|
|
929
|
+
routingHints: typeof rawSearch.routingHints === "boolean" ? rawSearch.routingHints : defaultSearch.routingHints,
|
|
930
|
+
routingHintRole: rawSearch.routingHintRole === "developer" || rawSearch.routingHintRole === "system" ? rawSearch.routingHintRole : defaultSearch.routingHintRole
|
|
923
931
|
};
|
|
924
932
|
const rawDebug = input.debug && typeof input.debug === "object" ? input.debug : {};
|
|
925
933
|
const debug = {
|
|
@@ -937,9 +945,9 @@ function parseConfig(raw) {
|
|
|
937
945
|
const rawAdditionalInclude = input.additionalInclude;
|
|
938
946
|
const additionalInclude = isStringArray(rawAdditionalInclude) ? rawAdditionalInclude.filter((p) => typeof p === "string" && p.trim().length > 0).map((p) => p.trim()) : [];
|
|
939
947
|
let embeddingProvider;
|
|
940
|
-
let embeddingModel
|
|
941
|
-
let customProvider
|
|
942
|
-
let reranker
|
|
948
|
+
let embeddingModel;
|
|
949
|
+
let customProvider;
|
|
950
|
+
let reranker;
|
|
943
951
|
if (embeddingProviderValue === "custom") {
|
|
944
952
|
embeddingProvider = "custom";
|
|
945
953
|
const rawCustom = input.customProvider && typeof input.customProvider === "object" ? input.customProvider : null;
|
|
@@ -972,7 +980,7 @@ function parseConfig(raw) {
|
|
|
972
980
|
embeddingProvider = embeddingProviderValue;
|
|
973
981
|
const rawEmbeddingModel = input.embeddingModel;
|
|
974
982
|
if (typeof rawEmbeddingModel === "string") {
|
|
975
|
-
const embeddingModelValue =
|
|
983
|
+
const embeddingModelValue = getResolvedString(rawEmbeddingModel, "$root.embeddingModel");
|
|
976
984
|
if (embeddingModelValue) {
|
|
977
985
|
embeddingModel = isValidModel(embeddingModelValue, embeddingProvider) ? embeddingModelValue : DEFAULT_PROVIDER_MODELS[embeddingProvider];
|
|
978
986
|
}
|
|
@@ -1035,16 +1043,20 @@ var autoDetectProviders = AUTO_DETECT_PROVIDER_ORDER.filter(
|
|
|
1035
1043
|
);
|
|
1036
1044
|
|
|
1037
1045
|
// src/config/merger.ts
|
|
1038
|
-
var
|
|
1046
|
+
var import_fs4 = require("fs");
|
|
1039
1047
|
var os2 = __toESM(require("os"), 1);
|
|
1040
|
-
var
|
|
1048
|
+
var path6 = __toESM(require("path"), 1);
|
|
1041
1049
|
|
|
1042
1050
|
// src/config/paths.ts
|
|
1043
|
-
var
|
|
1051
|
+
var import_fs3 = require("fs");
|
|
1044
1052
|
var os = __toESM(require("os"), 1);
|
|
1045
|
-
var
|
|
1053
|
+
var path3 = __toESM(require("path"), 1);
|
|
1046
1054
|
|
|
1047
1055
|
// src/git/index.ts
|
|
1056
|
+
var import_fs2 = require("fs");
|
|
1057
|
+
var path2 = __toESM(require("path"), 1);
|
|
1058
|
+
|
|
1059
|
+
// src/git/refs.ts
|
|
1048
1060
|
var import_fs = require("fs");
|
|
1049
1061
|
var path = __toESM(require("path"), 1);
|
|
1050
1062
|
function readPackedRefs(gitDir) {
|
|
@@ -1077,38 +1089,40 @@ function resolveCommonGitDir(gitDir) {
|
|
|
1077
1089
|
}
|
|
1078
1090
|
return gitDir;
|
|
1079
1091
|
}
|
|
1092
|
+
|
|
1093
|
+
// src/git/index.ts
|
|
1080
1094
|
function resolveWorktreeMainRepoRoot(repoRoot) {
|
|
1081
1095
|
const gitDir = resolveGitDir(repoRoot);
|
|
1082
1096
|
if (!gitDir) {
|
|
1083
1097
|
return null;
|
|
1084
1098
|
}
|
|
1085
1099
|
const commonGitDir = resolveCommonGitDir(gitDir);
|
|
1086
|
-
if (commonGitDir === gitDir ||
|
|
1100
|
+
if (commonGitDir === gitDir || path2.basename(commonGitDir) !== ".git") {
|
|
1087
1101
|
return null;
|
|
1088
1102
|
}
|
|
1089
|
-
const mainRepoRoot =
|
|
1090
|
-
if (!(0,
|
|
1103
|
+
const mainRepoRoot = path2.dirname(commonGitDir);
|
|
1104
|
+
if (!(0, import_fs2.existsSync)(mainRepoRoot)) {
|
|
1091
1105
|
return null;
|
|
1092
1106
|
}
|
|
1093
|
-
return
|
|
1107
|
+
return path2.resolve(mainRepoRoot) === path2.resolve(repoRoot) ? null : mainRepoRoot;
|
|
1094
1108
|
}
|
|
1095
1109
|
function resolveGitDir(repoRoot) {
|
|
1096
|
-
const gitPath =
|
|
1097
|
-
if (!(0,
|
|
1110
|
+
const gitPath = path2.join(repoRoot, ".git");
|
|
1111
|
+
if (!(0, import_fs2.existsSync)(gitPath)) {
|
|
1098
1112
|
return null;
|
|
1099
1113
|
}
|
|
1100
1114
|
try {
|
|
1101
|
-
const stat4 = (0,
|
|
1115
|
+
const stat4 = (0, import_fs2.statSync)(gitPath);
|
|
1102
1116
|
if (stat4.isDirectory()) {
|
|
1103
1117
|
return gitPath;
|
|
1104
1118
|
}
|
|
1105
1119
|
if (stat4.isFile()) {
|
|
1106
|
-
const content = (0,
|
|
1120
|
+
const content = (0, import_fs2.readFileSync)(gitPath, "utf-8").trim();
|
|
1107
1121
|
const match = content.match(/^gitdir:\s*(.+)$/);
|
|
1108
1122
|
if (match) {
|
|
1109
1123
|
const gitdir = match[1];
|
|
1110
|
-
const resolvedPath =
|
|
1111
|
-
if ((0,
|
|
1124
|
+
const resolvedPath = path2.isAbsolute(gitdir) ? gitdir : path2.resolve(repoRoot, gitdir);
|
|
1125
|
+
if ((0, import_fs2.existsSync)(resolvedPath)) {
|
|
1112
1126
|
return resolvedPath;
|
|
1113
1127
|
}
|
|
1114
1128
|
}
|
|
@@ -1125,12 +1139,12 @@ function getCurrentBranch(repoRoot) {
|
|
|
1125
1139
|
if (!gitDir) {
|
|
1126
1140
|
return null;
|
|
1127
1141
|
}
|
|
1128
|
-
const headPath =
|
|
1129
|
-
if (!(0,
|
|
1142
|
+
const headPath = path2.join(gitDir, "HEAD");
|
|
1143
|
+
if (!(0, import_fs2.existsSync)(headPath)) {
|
|
1130
1144
|
return null;
|
|
1131
1145
|
}
|
|
1132
1146
|
try {
|
|
1133
|
-
const headContent = (0,
|
|
1147
|
+
const headContent = (0, import_fs2.readFileSync)(headPath, "utf-8").trim();
|
|
1134
1148
|
const match = headContent.match(/^ref: refs\/heads\/(.+)$/);
|
|
1135
1149
|
if (match) {
|
|
1136
1150
|
return match[1];
|
|
@@ -1149,8 +1163,8 @@ function getBaseBranch(repoRoot) {
|
|
|
1149
1163
|
const candidates = ["main", "master", "develop", "trunk"];
|
|
1150
1164
|
if (refStoreDir) {
|
|
1151
1165
|
for (const candidate of candidates) {
|
|
1152
|
-
const refPath =
|
|
1153
|
-
if ((0,
|
|
1166
|
+
const refPath = path2.join(refStoreDir, "refs", "heads", candidate);
|
|
1167
|
+
if ((0, import_fs2.existsSync)(refPath)) {
|
|
1154
1168
|
return candidate;
|
|
1155
1169
|
}
|
|
1156
1170
|
const packedRefs = readPackedRefs(refStoreDir);
|
|
@@ -1170,44 +1184,44 @@ function getBranchOrDefault(repoRoot) {
|
|
|
1170
1184
|
function getHeadPath(repoRoot) {
|
|
1171
1185
|
const gitDir = resolveGitDir(repoRoot);
|
|
1172
1186
|
if (gitDir) {
|
|
1173
|
-
return
|
|
1187
|
+
return path2.join(gitDir, "HEAD");
|
|
1174
1188
|
}
|
|
1175
|
-
return
|
|
1189
|
+
return path2.join(repoRoot, ".git", "HEAD");
|
|
1176
1190
|
}
|
|
1177
1191
|
|
|
1178
1192
|
// src/config/paths.ts
|
|
1179
|
-
var PROJECT_CONFIG_RELATIVE_PATH =
|
|
1180
|
-
var PROJECT_INDEX_RELATIVE_PATH =
|
|
1193
|
+
var PROJECT_CONFIG_RELATIVE_PATH = path3.join(".opencode", "codebase-index.json");
|
|
1194
|
+
var PROJECT_INDEX_RELATIVE_PATH = path3.join(".opencode", "index");
|
|
1181
1195
|
function resolveWorktreeFallbackPath(projectRoot, relativePath) {
|
|
1182
1196
|
const mainRepoRoot = resolveWorktreeMainRepoRoot(projectRoot);
|
|
1183
1197
|
if (!mainRepoRoot) {
|
|
1184
1198
|
return null;
|
|
1185
1199
|
}
|
|
1186
|
-
const fallbackPath =
|
|
1187
|
-
return (0,
|
|
1200
|
+
const fallbackPath = path3.join(mainRepoRoot, relativePath);
|
|
1201
|
+
return (0, import_fs3.existsSync)(fallbackPath) ? fallbackPath : null;
|
|
1188
1202
|
}
|
|
1189
1203
|
function hasProjectConfig(projectRoot) {
|
|
1190
|
-
return (0,
|
|
1204
|
+
return (0, import_fs3.existsSync)(path3.join(projectRoot, PROJECT_CONFIG_RELATIVE_PATH));
|
|
1191
1205
|
}
|
|
1192
1206
|
function getGlobalIndexPath() {
|
|
1193
|
-
return
|
|
1207
|
+
return path3.join(os.homedir(), ".opencode", "global-index");
|
|
1194
1208
|
}
|
|
1195
1209
|
function resolveProjectConfigPath(projectRoot) {
|
|
1196
|
-
const localConfigPath =
|
|
1197
|
-
if ((0,
|
|
1210
|
+
const localConfigPath = path3.join(projectRoot, PROJECT_CONFIG_RELATIVE_PATH);
|
|
1211
|
+
if ((0, import_fs3.existsSync)(localConfigPath)) {
|
|
1198
1212
|
return localConfigPath;
|
|
1199
1213
|
}
|
|
1200
1214
|
return resolveWorktreeFallbackPath(projectRoot, PROJECT_CONFIG_RELATIVE_PATH) ?? localConfigPath;
|
|
1201
1215
|
}
|
|
1202
1216
|
function resolveWritableProjectConfigPath(projectRoot) {
|
|
1203
|
-
return
|
|
1217
|
+
return path3.join(projectRoot, PROJECT_CONFIG_RELATIVE_PATH);
|
|
1204
1218
|
}
|
|
1205
1219
|
function resolveProjectIndexPath(projectRoot, scope) {
|
|
1206
1220
|
if (scope === "global") {
|
|
1207
1221
|
return getGlobalIndexPath();
|
|
1208
1222
|
}
|
|
1209
|
-
const localIndexPath =
|
|
1210
|
-
if ((0,
|
|
1223
|
+
const localIndexPath = path3.join(projectRoot, PROJECT_INDEX_RELATIVE_PATH);
|
|
1224
|
+
if ((0, import_fs3.existsSync)(localIndexPath)) {
|
|
1211
1225
|
return localIndexPath;
|
|
1212
1226
|
}
|
|
1213
1227
|
if (hasProjectConfig(projectRoot)) {
|
|
@@ -1216,23 +1230,56 @@ function resolveProjectIndexPath(projectRoot, scope) {
|
|
|
1216
1230
|
return resolveWorktreeFallbackPath(projectRoot, PROJECT_INDEX_RELATIVE_PATH) ?? localIndexPath;
|
|
1217
1231
|
}
|
|
1218
1232
|
|
|
1219
|
-
// src/config/
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
} catch {
|
|
1227
|
-
}
|
|
1228
|
-
return null;
|
|
1233
|
+
// src/config/rebase.ts
|
|
1234
|
+
var path5 = __toESM(require("path"), 1);
|
|
1235
|
+
|
|
1236
|
+
// src/utils/paths.ts
|
|
1237
|
+
var path4 = __toESM(require("path"), 1);
|
|
1238
|
+
function normalizePathSeparators(value) {
|
|
1239
|
+
return value.replace(/\\/g, "/");
|
|
1229
1240
|
}
|
|
1230
|
-
function
|
|
1231
|
-
return
|
|
1241
|
+
function isHiddenPathSegment(part) {
|
|
1242
|
+
return part.startsWith(".") && part !== "." && part !== "..";
|
|
1232
1243
|
}
|
|
1244
|
+
function isBuildPathSegment(part) {
|
|
1245
|
+
return part.toLowerCase().includes("build");
|
|
1246
|
+
}
|
|
1247
|
+
function hasFilteredPathSegment(relativePath, separator = path4.sep) {
|
|
1248
|
+
return relativePath.split(separator).some(
|
|
1249
|
+
(part) => isHiddenPathSegment(part) || isBuildPathSegment(part)
|
|
1250
|
+
);
|
|
1251
|
+
}
|
|
1252
|
+
var RESTRICTED_DIRECTORIES = /* @__PURE__ */ new Set([
|
|
1253
|
+
// macOS
|
|
1254
|
+
"library",
|
|
1255
|
+
"applications",
|
|
1256
|
+
"system",
|
|
1257
|
+
"volumes",
|
|
1258
|
+
"private",
|
|
1259
|
+
"cores",
|
|
1260
|
+
// Linux
|
|
1261
|
+
"proc",
|
|
1262
|
+
"sys",
|
|
1263
|
+
"dev",
|
|
1264
|
+
"run",
|
|
1265
|
+
"snap",
|
|
1266
|
+
// Windows
|
|
1267
|
+
"windows",
|
|
1268
|
+
"programdata",
|
|
1269
|
+
"program files",
|
|
1270
|
+
"program files (x86)",
|
|
1271
|
+
"$recycle.bin"
|
|
1272
|
+
]);
|
|
1273
|
+
function isRestrictedDirectory(relativePath, separator = path4.sep) {
|
|
1274
|
+
const firstSegment = relativePath.split(separator)[0];
|
|
1275
|
+
if (!firstSegment) return false;
|
|
1276
|
+
return RESTRICTED_DIRECTORIES.has(firstSegment.toLowerCase());
|
|
1277
|
+
}
|
|
1278
|
+
|
|
1279
|
+
// src/config/rebase.ts
|
|
1233
1280
|
function isWithinRoot(rootDir, targetPath) {
|
|
1234
|
-
const relativePath =
|
|
1235
|
-
return relativePath === "" || !relativePath.startsWith("..") && !
|
|
1281
|
+
const relativePath = path5.relative(rootDir, targetPath);
|
|
1282
|
+
return relativePath === "" || !relativePath.startsWith("..") && !path5.isAbsolute(relativePath);
|
|
1236
1283
|
}
|
|
1237
1284
|
function resolveInheritedKnowledgeBaseEntries(values, sourceRoot, targetRoot) {
|
|
1238
1285
|
if (!Array.isArray(values)) {
|
|
@@ -1243,23 +1290,107 @@ function resolveInheritedKnowledgeBaseEntries(values, sourceRoot, targetRoot) {
|
|
|
1243
1290
|
if (!trimmed) {
|
|
1244
1291
|
return trimmed;
|
|
1245
1292
|
}
|
|
1246
|
-
if (
|
|
1293
|
+
if (path5.isAbsolute(trimmed)) {
|
|
1247
1294
|
if (isWithinRoot(sourceRoot, trimmed)) {
|
|
1248
|
-
return
|
|
1295
|
+
return normalizePathSeparators(path5.normalize(path5.relative(sourceRoot, trimmed) || "."));
|
|
1249
1296
|
}
|
|
1250
|
-
return
|
|
1297
|
+
return path5.normalize(trimmed);
|
|
1251
1298
|
}
|
|
1252
|
-
const resolvedFromSource =
|
|
1299
|
+
const resolvedFromSource = path5.resolve(sourceRoot, trimmed);
|
|
1253
1300
|
if (isWithinRoot(sourceRoot, resolvedFromSource)) {
|
|
1254
|
-
return
|
|
1301
|
+
return normalizePathSeparators(path5.normalize(trimmed));
|
|
1255
1302
|
}
|
|
1256
|
-
return
|
|
1303
|
+
return normalizePathSeparators(path5.normalize(path5.relative(targetRoot, resolvedFromSource)));
|
|
1257
1304
|
}).filter(Boolean);
|
|
1258
1305
|
}
|
|
1306
|
+
|
|
1307
|
+
// src/config/merger.ts
|
|
1308
|
+
var PROJECT_OVERRIDE_KEYS = [
|
|
1309
|
+
"embeddingProvider",
|
|
1310
|
+
"customProvider",
|
|
1311
|
+
"embeddingModel",
|
|
1312
|
+
"reranker",
|
|
1313
|
+
"include",
|
|
1314
|
+
"exclude",
|
|
1315
|
+
"indexing",
|
|
1316
|
+
"search",
|
|
1317
|
+
"debug",
|
|
1318
|
+
"scope"
|
|
1319
|
+
];
|
|
1320
|
+
var MERGE_ARRAY_KEYS = ["knowledgeBases", "additionalInclude"];
|
|
1321
|
+
function isRecord(value) {
|
|
1322
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1323
|
+
}
|
|
1324
|
+
function isStringArray2(value) {
|
|
1325
|
+
return Array.isArray(value) && value.every((item) => typeof item === "string");
|
|
1326
|
+
}
|
|
1327
|
+
function applyProjectOverride(merged, normalizedProjectConfig, globalConfig, key) {
|
|
1328
|
+
if (key in normalizedProjectConfig) {
|
|
1329
|
+
merged[key] = normalizedProjectConfig[key];
|
|
1330
|
+
return;
|
|
1331
|
+
}
|
|
1332
|
+
if (key in globalConfig) {
|
|
1333
|
+
merged[key] = globalConfig[key];
|
|
1334
|
+
}
|
|
1335
|
+
}
|
|
1336
|
+
function mergeUniqueStringArray(values) {
|
|
1337
|
+
return [...new Set(values.map((value) => String(value).trim()))];
|
|
1338
|
+
}
|
|
1339
|
+
function normalizeKnowledgeBasePath(value) {
|
|
1340
|
+
let normalized = path6.normalize(String(value).trim());
|
|
1341
|
+
const root = path6.parse(normalized).root;
|
|
1342
|
+
while (normalized.length > root.length && /[\\/]$/.test(normalized)) {
|
|
1343
|
+
normalized = normalized.slice(0, -1);
|
|
1344
|
+
}
|
|
1345
|
+
return normalized;
|
|
1346
|
+
}
|
|
1347
|
+
function mergeKnowledgeBasePaths(values) {
|
|
1348
|
+
return [...new Set(values.map((value) => normalizeKnowledgeBasePath(value)).filter((value) => value.length > 0))];
|
|
1349
|
+
}
|
|
1350
|
+
function validateConfigLayerShape(rawConfig, filePath) {
|
|
1351
|
+
if (!isRecord(rawConfig)) {
|
|
1352
|
+
throw new Error(`Config file ${filePath} must contain a JSON object at the root.`);
|
|
1353
|
+
}
|
|
1354
|
+
if (rawConfig.knowledgeBases !== void 0 && !isStringArray2(rawConfig.knowledgeBases)) {
|
|
1355
|
+
throw new Error(`Config file ${filePath} field 'knowledgeBases' must be an array of strings.`);
|
|
1356
|
+
}
|
|
1357
|
+
if (rawConfig.additionalInclude !== void 0 && !isStringArray2(rawConfig.additionalInclude)) {
|
|
1358
|
+
throw new Error(`Config file ${filePath} field 'additionalInclude' must be an array of strings.`);
|
|
1359
|
+
}
|
|
1360
|
+
if (rawConfig.include !== void 0 && !isStringArray2(rawConfig.include)) {
|
|
1361
|
+
throw new Error(`Config file ${filePath} field 'include' must be an array of strings.`);
|
|
1362
|
+
}
|
|
1363
|
+
if (rawConfig.exclude !== void 0 && !isStringArray2(rawConfig.exclude)) {
|
|
1364
|
+
throw new Error(`Config file ${filePath} field 'exclude' must be an array of strings.`);
|
|
1365
|
+
}
|
|
1366
|
+
for (const section of ["customProvider", "indexing", "search", "debug", "reranker"]) {
|
|
1367
|
+
const value = rawConfig[section];
|
|
1368
|
+
if (value !== void 0 && !isRecord(value)) {
|
|
1369
|
+
throw new Error(`Config file ${filePath} field '${section}' must be an object.`);
|
|
1370
|
+
}
|
|
1371
|
+
}
|
|
1372
|
+
return rawConfig;
|
|
1373
|
+
}
|
|
1374
|
+
function loadJsonFile(filePath) {
|
|
1375
|
+
if (!(0, import_fs4.existsSync)(filePath)) {
|
|
1376
|
+
return null;
|
|
1377
|
+
}
|
|
1378
|
+
try {
|
|
1379
|
+
const content = (0, import_fs4.readFileSync)(filePath, "utf-8");
|
|
1380
|
+
return validateConfigLayerShape(JSON.parse(content), filePath);
|
|
1381
|
+
} catch (error) {
|
|
1382
|
+
if (error instanceof Error && error.message.startsWith("Config file ")) {
|
|
1383
|
+
throw error;
|
|
1384
|
+
}
|
|
1385
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1386
|
+
throw new Error(`Failed to load config file ${filePath}: ${message}`);
|
|
1387
|
+
}
|
|
1388
|
+
return null;
|
|
1389
|
+
}
|
|
1259
1390
|
function materializeLocalProjectConfig(projectRoot, config) {
|
|
1260
|
-
const localConfigPath =
|
|
1261
|
-
(0,
|
|
1262
|
-
(0,
|
|
1391
|
+
const localConfigPath = path6.join(projectRoot, ".opencode", "codebase-index.json");
|
|
1392
|
+
(0, import_fs4.mkdirSync)(path6.dirname(localConfigPath), { recursive: true });
|
|
1393
|
+
(0, import_fs4.writeFileSync)(localConfigPath, JSON.stringify(config, null, 2), "utf-8");
|
|
1263
1394
|
return localConfigPath;
|
|
1264
1395
|
}
|
|
1265
1396
|
function loadProjectConfigLayer(projectRoot) {
|
|
@@ -1269,7 +1400,7 @@ function loadProjectConfigLayer(projectRoot) {
|
|
|
1269
1400
|
return {};
|
|
1270
1401
|
}
|
|
1271
1402
|
const normalizedConfig = { ...projectConfig };
|
|
1272
|
-
const projectConfigBaseDir =
|
|
1403
|
+
const projectConfigBaseDir = path6.dirname(path6.dirname(projectConfigPath));
|
|
1273
1404
|
if (Array.isArray(normalizedConfig.knowledgeBases)) {
|
|
1274
1405
|
normalizedConfig.knowledgeBases = resolveInheritedKnowledgeBaseEntries(
|
|
1275
1406
|
normalizedConfig.knowledgeBases,
|
|
@@ -1281,10 +1412,22 @@ function loadProjectConfigLayer(projectRoot) {
|
|
|
1281
1412
|
}
|
|
1282
1413
|
function loadMergedConfig(projectRoot) {
|
|
1283
1414
|
const globalConfigPath = os2.homedir() + "/.config/opencode/codebase-index.json";
|
|
1284
|
-
const globalConfig = loadJsonFile(globalConfigPath);
|
|
1285
1415
|
const projectConfigPath = resolveProjectConfigPath(projectRoot);
|
|
1416
|
+
let globalConfig = null;
|
|
1417
|
+
let globalConfigError = null;
|
|
1418
|
+
try {
|
|
1419
|
+
globalConfig = loadJsonFile(globalConfigPath);
|
|
1420
|
+
} catch (error) {
|
|
1421
|
+
globalConfigError = error instanceof Error ? error : new Error(String(error));
|
|
1422
|
+
}
|
|
1286
1423
|
const projectConfig = loadJsonFile(projectConfigPath);
|
|
1287
1424
|
const normalizedProjectConfig = loadProjectConfigLayer(projectRoot);
|
|
1425
|
+
if (globalConfigError) {
|
|
1426
|
+
if (!projectConfig) {
|
|
1427
|
+
throw globalConfigError;
|
|
1428
|
+
}
|
|
1429
|
+
globalConfig = null;
|
|
1430
|
+
}
|
|
1288
1431
|
if (!globalConfig && !projectConfig) {
|
|
1289
1432
|
return {};
|
|
1290
1433
|
}
|
|
@@ -1294,60 +1437,16 @@ function loadMergedConfig(projectRoot) {
|
|
|
1294
1437
|
if (!globalConfig && projectConfig) {
|
|
1295
1438
|
return normalizedProjectConfig;
|
|
1296
1439
|
}
|
|
1440
|
+
if (!globalConfig || !projectConfig) {
|
|
1441
|
+
return globalConfig ?? normalizedProjectConfig;
|
|
1442
|
+
}
|
|
1297
1443
|
const merged = { ...globalConfig };
|
|
1298
|
-
|
|
1299
|
-
merged
|
|
1300
|
-
} else if (globalConfig && globalConfig.embeddingProvider) {
|
|
1301
|
-
merged.embeddingProvider = globalConfig.embeddingProvider;
|
|
1302
|
-
}
|
|
1303
|
-
if (projectConfig && "customProvider" in normalizedProjectConfig) {
|
|
1304
|
-
merged.customProvider = normalizedProjectConfig.customProvider;
|
|
1305
|
-
} else if (globalConfig && globalConfig.customProvider) {
|
|
1306
|
-
merged.customProvider = globalConfig.customProvider;
|
|
1307
|
-
}
|
|
1308
|
-
if (projectConfig && "embeddingModel" in normalizedProjectConfig) {
|
|
1309
|
-
merged.embeddingModel = normalizedProjectConfig.embeddingModel;
|
|
1310
|
-
} else if (globalConfig && globalConfig.embeddingModel) {
|
|
1311
|
-
merged.embeddingModel = globalConfig.embeddingModel;
|
|
1312
|
-
}
|
|
1313
|
-
if (projectConfig && "reranker" in normalizedProjectConfig) {
|
|
1314
|
-
merged.reranker = normalizedProjectConfig.reranker;
|
|
1315
|
-
} else if (globalConfig && globalConfig.reranker) {
|
|
1316
|
-
merged.reranker = globalConfig.reranker;
|
|
1317
|
-
}
|
|
1318
|
-
if (projectConfig && "include" in normalizedProjectConfig) {
|
|
1319
|
-
merged.include = normalizedProjectConfig.include;
|
|
1320
|
-
} else if (globalConfig && globalConfig.include) {
|
|
1321
|
-
merged.include = globalConfig.include;
|
|
1322
|
-
}
|
|
1323
|
-
if (projectConfig && "exclude" in normalizedProjectConfig) {
|
|
1324
|
-
merged.exclude = normalizedProjectConfig.exclude;
|
|
1325
|
-
} else if (globalConfig && globalConfig.exclude) {
|
|
1326
|
-
merged.exclude = globalConfig.exclude;
|
|
1327
|
-
}
|
|
1328
|
-
if (projectConfig && "indexing" in normalizedProjectConfig) {
|
|
1329
|
-
merged.indexing = normalizedProjectConfig.indexing;
|
|
1330
|
-
} else if (globalConfig && globalConfig.indexing) {
|
|
1331
|
-
merged.indexing = globalConfig.indexing;
|
|
1332
|
-
}
|
|
1333
|
-
if (projectConfig && "search" in normalizedProjectConfig) {
|
|
1334
|
-
merged.search = normalizedProjectConfig.search;
|
|
1335
|
-
} else if (globalConfig && globalConfig.search) {
|
|
1336
|
-
merged.search = globalConfig.search;
|
|
1337
|
-
}
|
|
1338
|
-
if (projectConfig && "debug" in normalizedProjectConfig) {
|
|
1339
|
-
merged.debug = normalizedProjectConfig.debug;
|
|
1340
|
-
} else if (globalConfig && globalConfig.debug) {
|
|
1341
|
-
merged.debug = globalConfig.debug;
|
|
1342
|
-
}
|
|
1343
|
-
if (projectConfig && "scope" in normalizedProjectConfig) {
|
|
1344
|
-
merged.scope = normalizedProjectConfig.scope;
|
|
1345
|
-
} else if (globalConfig && "scope" in globalConfig) {
|
|
1346
|
-
merged.scope = globalConfig.scope;
|
|
1444
|
+
for (const key of PROJECT_OVERRIDE_KEYS) {
|
|
1445
|
+
applyProjectOverride(merged, normalizedProjectConfig, globalConfig, key);
|
|
1347
1446
|
}
|
|
1348
1447
|
if (projectConfig) {
|
|
1349
1448
|
for (const key of Object.keys(projectConfig)) {
|
|
1350
|
-
if (key
|
|
1449
|
+
if (PROJECT_OVERRIDE_KEYS.includes(key) || MERGE_ARRAY_KEYS.includes(key)) {
|
|
1351
1450
|
continue;
|
|
1352
1451
|
}
|
|
1353
1452
|
merged[key] = normalizedProjectConfig[key];
|
|
@@ -1356,13 +1455,11 @@ function loadMergedConfig(projectRoot) {
|
|
|
1356
1455
|
const globalKbs = globalConfig && Array.isArray(globalConfig.knowledgeBases) ? globalConfig.knowledgeBases : [];
|
|
1357
1456
|
const projectKbs = projectConfig ? Array.isArray(normalizedProjectConfig.knowledgeBases) ? normalizedProjectConfig.knowledgeBases : [] : [];
|
|
1358
1457
|
const allKbs = [...globalKbs, ...projectKbs];
|
|
1359
|
-
|
|
1360
|
-
merged.knowledgeBases = uniqueKbs;
|
|
1458
|
+
merged.knowledgeBases = mergeKnowledgeBasePaths(allKbs);
|
|
1361
1459
|
const globalAdditional = globalConfig && Array.isArray(globalConfig.additionalInclude) ? globalConfig.additionalInclude : [];
|
|
1362
1460
|
const projectAdditional = projectConfig && Array.isArray(projectConfig.additionalInclude) ? projectConfig.additionalInclude : [];
|
|
1363
1461
|
const allAdditional = [...globalAdditional, ...projectAdditional];
|
|
1364
|
-
|
|
1365
|
-
merged.additionalInclude = uniqueAdditional;
|
|
1462
|
+
merged.additionalInclude = mergeUniqueStringArray(allAdditional);
|
|
1366
1463
|
return merged;
|
|
1367
1464
|
}
|
|
1368
1465
|
|
|
@@ -1456,7 +1553,7 @@ var ReaddirpStream = class extends import_node_stream.Readable {
|
|
|
1456
1553
|
this._directoryFilter = normalizeFilter(opts.directoryFilter);
|
|
1457
1554
|
const statMethod = opts.lstat ? import_promises.lstat : import_promises.stat;
|
|
1458
1555
|
if (wantBigintFsStats) {
|
|
1459
|
-
this._stat = (
|
|
1556
|
+
this._stat = (path18) => statMethod(path18, { bigint: true });
|
|
1460
1557
|
} else {
|
|
1461
1558
|
this._stat = statMethod;
|
|
1462
1559
|
}
|
|
@@ -1481,8 +1578,8 @@ var ReaddirpStream = class extends import_node_stream.Readable {
|
|
|
1481
1578
|
const par = this.parent;
|
|
1482
1579
|
const fil = par && par.files;
|
|
1483
1580
|
if (fil && fil.length > 0) {
|
|
1484
|
-
const { path:
|
|
1485
|
-
const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent,
|
|
1581
|
+
const { path: path18, depth } = par;
|
|
1582
|
+
const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path18));
|
|
1486
1583
|
const awaited = await Promise.all(slice);
|
|
1487
1584
|
for (const entry of awaited) {
|
|
1488
1585
|
if (!entry)
|
|
@@ -1522,20 +1619,20 @@ var ReaddirpStream = class extends import_node_stream.Readable {
|
|
|
1522
1619
|
this.reading = false;
|
|
1523
1620
|
}
|
|
1524
1621
|
}
|
|
1525
|
-
async _exploreDir(
|
|
1622
|
+
async _exploreDir(path18, depth) {
|
|
1526
1623
|
let files;
|
|
1527
1624
|
try {
|
|
1528
|
-
files = await (0, import_promises.readdir)(
|
|
1625
|
+
files = await (0, import_promises.readdir)(path18, this._rdOptions);
|
|
1529
1626
|
} catch (error) {
|
|
1530
1627
|
this._onError(error);
|
|
1531
1628
|
}
|
|
1532
|
-
return { files, depth, path:
|
|
1629
|
+
return { files, depth, path: path18 };
|
|
1533
1630
|
}
|
|
1534
|
-
async _formatEntry(dirent,
|
|
1631
|
+
async _formatEntry(dirent, path18) {
|
|
1535
1632
|
let entry;
|
|
1536
1633
|
const basename5 = this._isDirent ? dirent.name : dirent;
|
|
1537
1634
|
try {
|
|
1538
|
-
const fullPath = (0, import_node_path.resolve)((0, import_node_path.join)(
|
|
1635
|
+
const fullPath = (0, import_node_path.resolve)((0, import_node_path.join)(path18, basename5));
|
|
1539
1636
|
entry = { path: (0, import_node_path.relative)(this._root, fullPath), fullPath, basename: basename5 };
|
|
1540
1637
|
entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
|
|
1541
1638
|
} catch (err) {
|
|
@@ -1935,16 +2032,16 @@ var delFromSet = (main, prop, item) => {
|
|
|
1935
2032
|
};
|
|
1936
2033
|
var isEmptySet = (val) => val instanceof Set ? val.size === 0 : !val;
|
|
1937
2034
|
var FsWatchInstances = /* @__PURE__ */ new Map();
|
|
1938
|
-
function createFsWatchInstance(
|
|
2035
|
+
function createFsWatchInstance(path18, options, listener, errHandler, emitRaw) {
|
|
1939
2036
|
const handleEvent = (rawEvent, evPath) => {
|
|
1940
|
-
listener(
|
|
1941
|
-
emitRaw(rawEvent, evPath, { watchedPath:
|
|
1942
|
-
if (evPath &&
|
|
1943
|
-
fsWatchBroadcast(sp.resolve(
|
|
2037
|
+
listener(path18);
|
|
2038
|
+
emitRaw(rawEvent, evPath, { watchedPath: path18 });
|
|
2039
|
+
if (evPath && path18 !== evPath) {
|
|
2040
|
+
fsWatchBroadcast(sp.resolve(path18, evPath), KEY_LISTENERS, sp.join(path18, evPath));
|
|
1944
2041
|
}
|
|
1945
2042
|
};
|
|
1946
2043
|
try {
|
|
1947
|
-
return (0, import_node_fs.watch)(
|
|
2044
|
+
return (0, import_node_fs.watch)(path18, {
|
|
1948
2045
|
persistent: options.persistent
|
|
1949
2046
|
}, handleEvent);
|
|
1950
2047
|
} catch (error) {
|
|
@@ -1960,12 +2057,12 @@ var fsWatchBroadcast = (fullPath, listenerType, val1, val2, val3) => {
|
|
|
1960
2057
|
listener(val1, val2, val3);
|
|
1961
2058
|
});
|
|
1962
2059
|
};
|
|
1963
|
-
var setFsWatchListener = (
|
|
2060
|
+
var setFsWatchListener = (path18, fullPath, options, handlers) => {
|
|
1964
2061
|
const { listener, errHandler, rawEmitter } = handlers;
|
|
1965
2062
|
let cont = FsWatchInstances.get(fullPath);
|
|
1966
2063
|
let watcher;
|
|
1967
2064
|
if (!options.persistent) {
|
|
1968
|
-
watcher = createFsWatchInstance(
|
|
2065
|
+
watcher = createFsWatchInstance(path18, options, listener, errHandler, rawEmitter);
|
|
1969
2066
|
if (!watcher)
|
|
1970
2067
|
return;
|
|
1971
2068
|
return watcher.close.bind(watcher);
|
|
@@ -1976,7 +2073,7 @@ var setFsWatchListener = (path12, fullPath, options, handlers) => {
|
|
|
1976
2073
|
addAndConvert(cont, KEY_RAW, rawEmitter);
|
|
1977
2074
|
} else {
|
|
1978
2075
|
watcher = createFsWatchInstance(
|
|
1979
|
-
|
|
2076
|
+
path18,
|
|
1980
2077
|
options,
|
|
1981
2078
|
fsWatchBroadcast.bind(null, fullPath, KEY_LISTENERS),
|
|
1982
2079
|
errHandler,
|
|
@@ -1991,7 +2088,7 @@ var setFsWatchListener = (path12, fullPath, options, handlers) => {
|
|
|
1991
2088
|
cont.watcherUnusable = true;
|
|
1992
2089
|
if (isWindows && error.code === "EPERM") {
|
|
1993
2090
|
try {
|
|
1994
|
-
const fd = await (0, import_promises2.open)(
|
|
2091
|
+
const fd = await (0, import_promises2.open)(path18, "r");
|
|
1995
2092
|
await fd.close();
|
|
1996
2093
|
broadcastErr(error);
|
|
1997
2094
|
} catch (err) {
|
|
@@ -2022,7 +2119,7 @@ var setFsWatchListener = (path12, fullPath, options, handlers) => {
|
|
|
2022
2119
|
};
|
|
2023
2120
|
};
|
|
2024
2121
|
var FsWatchFileInstances = /* @__PURE__ */ new Map();
|
|
2025
|
-
var setFsWatchFileListener = (
|
|
2122
|
+
var setFsWatchFileListener = (path18, fullPath, options, handlers) => {
|
|
2026
2123
|
const { listener, rawEmitter } = handlers;
|
|
2027
2124
|
let cont = FsWatchFileInstances.get(fullPath);
|
|
2028
2125
|
const copts = cont && cont.options;
|
|
@@ -2044,7 +2141,7 @@ var setFsWatchFileListener = (path12, fullPath, options, handlers) => {
|
|
|
2044
2141
|
});
|
|
2045
2142
|
const currmtime = curr.mtimeMs;
|
|
2046
2143
|
if (curr.size !== prev.size || currmtime > prev.mtimeMs || currmtime === 0) {
|
|
2047
|
-
foreach(cont.listeners, (listener2) => listener2(
|
|
2144
|
+
foreach(cont.listeners, (listener2) => listener2(path18, curr));
|
|
2048
2145
|
}
|
|
2049
2146
|
})
|
|
2050
2147
|
};
|
|
@@ -2074,13 +2171,13 @@ var NodeFsHandler = class {
|
|
|
2074
2171
|
* @param listener on fs change
|
|
2075
2172
|
* @returns closer for the watcher instance
|
|
2076
2173
|
*/
|
|
2077
|
-
_watchWithNodeFs(
|
|
2174
|
+
_watchWithNodeFs(path18, listener) {
|
|
2078
2175
|
const opts = this.fsw.options;
|
|
2079
|
-
const directory = sp.dirname(
|
|
2080
|
-
const basename5 = sp.basename(
|
|
2176
|
+
const directory = sp.dirname(path18);
|
|
2177
|
+
const basename5 = sp.basename(path18);
|
|
2081
2178
|
const parent = this.fsw._getWatchedDir(directory);
|
|
2082
2179
|
parent.add(basename5);
|
|
2083
|
-
const absolutePath = sp.resolve(
|
|
2180
|
+
const absolutePath = sp.resolve(path18);
|
|
2084
2181
|
const options = {
|
|
2085
2182
|
persistent: opts.persistent
|
|
2086
2183
|
};
|
|
@@ -2090,12 +2187,12 @@ var NodeFsHandler = class {
|
|
|
2090
2187
|
if (opts.usePolling) {
|
|
2091
2188
|
const enableBin = opts.interval !== opts.binaryInterval;
|
|
2092
2189
|
options.interval = enableBin && isBinaryPath(basename5) ? opts.binaryInterval : opts.interval;
|
|
2093
|
-
closer = setFsWatchFileListener(
|
|
2190
|
+
closer = setFsWatchFileListener(path18, absolutePath, options, {
|
|
2094
2191
|
listener,
|
|
2095
2192
|
rawEmitter: this.fsw._emitRaw
|
|
2096
2193
|
});
|
|
2097
2194
|
} else {
|
|
2098
|
-
closer = setFsWatchListener(
|
|
2195
|
+
closer = setFsWatchListener(path18, absolutePath, options, {
|
|
2099
2196
|
listener,
|
|
2100
2197
|
errHandler: this._boundHandleError,
|
|
2101
2198
|
rawEmitter: this.fsw._emitRaw
|
|
@@ -2117,7 +2214,7 @@ var NodeFsHandler = class {
|
|
|
2117
2214
|
let prevStats = stats;
|
|
2118
2215
|
if (parent.has(basename5))
|
|
2119
2216
|
return;
|
|
2120
|
-
const listener = async (
|
|
2217
|
+
const listener = async (path18, newStats) => {
|
|
2121
2218
|
if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file, 5))
|
|
2122
2219
|
return;
|
|
2123
2220
|
if (!newStats || newStats.mtimeMs === 0) {
|
|
@@ -2131,11 +2228,11 @@ var NodeFsHandler = class {
|
|
|
2131
2228
|
this.fsw._emit(EV.CHANGE, file, newStats2);
|
|
2132
2229
|
}
|
|
2133
2230
|
if ((isMacos || isLinux || isFreeBSD) && prevStats.ino !== newStats2.ino) {
|
|
2134
|
-
this.fsw._closeFile(
|
|
2231
|
+
this.fsw._closeFile(path18);
|
|
2135
2232
|
prevStats = newStats2;
|
|
2136
2233
|
const closer2 = this._watchWithNodeFs(file, listener);
|
|
2137
2234
|
if (closer2)
|
|
2138
|
-
this.fsw._addPathCloser(
|
|
2235
|
+
this.fsw._addPathCloser(path18, closer2);
|
|
2139
2236
|
} else {
|
|
2140
2237
|
prevStats = newStats2;
|
|
2141
2238
|
}
|
|
@@ -2167,7 +2264,7 @@ var NodeFsHandler = class {
|
|
|
2167
2264
|
* @param item basename of this item
|
|
2168
2265
|
* @returns true if no more processing is needed for this entry.
|
|
2169
2266
|
*/
|
|
2170
|
-
async _handleSymlink(entry, directory,
|
|
2267
|
+
async _handleSymlink(entry, directory, path18, item) {
|
|
2171
2268
|
if (this.fsw.closed) {
|
|
2172
2269
|
return;
|
|
2173
2270
|
}
|
|
@@ -2177,7 +2274,7 @@ var NodeFsHandler = class {
|
|
|
2177
2274
|
this.fsw._incrReadyCount();
|
|
2178
2275
|
let linkPath;
|
|
2179
2276
|
try {
|
|
2180
|
-
linkPath = await (0, import_promises2.realpath)(
|
|
2277
|
+
linkPath = await (0, import_promises2.realpath)(path18);
|
|
2181
2278
|
} catch (e) {
|
|
2182
2279
|
this.fsw._emitReady();
|
|
2183
2280
|
return true;
|
|
@@ -2187,12 +2284,12 @@ var NodeFsHandler = class {
|
|
|
2187
2284
|
if (dir.has(item)) {
|
|
2188
2285
|
if (this.fsw._symlinkPaths.get(full) !== linkPath) {
|
|
2189
2286
|
this.fsw._symlinkPaths.set(full, linkPath);
|
|
2190
|
-
this.fsw._emit(EV.CHANGE,
|
|
2287
|
+
this.fsw._emit(EV.CHANGE, path18, entry.stats);
|
|
2191
2288
|
}
|
|
2192
2289
|
} else {
|
|
2193
2290
|
dir.add(item);
|
|
2194
2291
|
this.fsw._symlinkPaths.set(full, linkPath);
|
|
2195
|
-
this.fsw._emit(EV.ADD,
|
|
2292
|
+
this.fsw._emit(EV.ADD, path18, entry.stats);
|
|
2196
2293
|
}
|
|
2197
2294
|
this.fsw._emitReady();
|
|
2198
2295
|
return true;
|
|
@@ -2222,9 +2319,9 @@ var NodeFsHandler = class {
|
|
|
2222
2319
|
return;
|
|
2223
2320
|
}
|
|
2224
2321
|
const item = entry.path;
|
|
2225
|
-
let
|
|
2322
|
+
let path18 = sp.join(directory, item);
|
|
2226
2323
|
current.add(item);
|
|
2227
|
-
if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory,
|
|
2324
|
+
if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path18, item)) {
|
|
2228
2325
|
return;
|
|
2229
2326
|
}
|
|
2230
2327
|
if (this.fsw.closed) {
|
|
@@ -2233,11 +2330,11 @@ var NodeFsHandler = class {
|
|
|
2233
2330
|
}
|
|
2234
2331
|
if (item === target || !target && !previous.has(item)) {
|
|
2235
2332
|
this.fsw._incrReadyCount();
|
|
2236
|
-
|
|
2237
|
-
this._addToNodeFs(
|
|
2333
|
+
path18 = sp.join(dir, sp.relative(dir, path18));
|
|
2334
|
+
this._addToNodeFs(path18, initialAdd, wh, depth + 1);
|
|
2238
2335
|
}
|
|
2239
2336
|
}).on(EV.ERROR, this._boundHandleError);
|
|
2240
|
-
return new Promise((
|
|
2337
|
+
return new Promise((resolve12, reject) => {
|
|
2241
2338
|
if (!stream)
|
|
2242
2339
|
return reject();
|
|
2243
2340
|
stream.once(STR_END, () => {
|
|
@@ -2246,7 +2343,7 @@ var NodeFsHandler = class {
|
|
|
2246
2343
|
return;
|
|
2247
2344
|
}
|
|
2248
2345
|
const wasThrottled = throttler ? throttler.clear() : false;
|
|
2249
|
-
|
|
2346
|
+
resolve12(void 0);
|
|
2250
2347
|
previous.getChildren().filter((item) => {
|
|
2251
2348
|
return item !== directory && !current.has(item);
|
|
2252
2349
|
}).forEach((item) => {
|
|
@@ -2303,13 +2400,13 @@ var NodeFsHandler = class {
|
|
|
2303
2400
|
* @param depth Child path actually targeted for watch
|
|
2304
2401
|
* @param target Child path actually targeted for watch
|
|
2305
2402
|
*/
|
|
2306
|
-
async _addToNodeFs(
|
|
2403
|
+
async _addToNodeFs(path18, initialAdd, priorWh, depth, target) {
|
|
2307
2404
|
const ready = this.fsw._emitReady;
|
|
2308
|
-
if (this.fsw._isIgnored(
|
|
2405
|
+
if (this.fsw._isIgnored(path18) || this.fsw.closed) {
|
|
2309
2406
|
ready();
|
|
2310
2407
|
return false;
|
|
2311
2408
|
}
|
|
2312
|
-
const wh = this.fsw._getWatchHelpers(
|
|
2409
|
+
const wh = this.fsw._getWatchHelpers(path18);
|
|
2313
2410
|
if (priorWh) {
|
|
2314
2411
|
wh.filterPath = (entry) => priorWh.filterPath(entry);
|
|
2315
2412
|
wh.filterDir = (entry) => priorWh.filterDir(entry);
|
|
@@ -2325,8 +2422,8 @@ var NodeFsHandler = class {
|
|
|
2325
2422
|
const follow = this.fsw.options.followSymlinks;
|
|
2326
2423
|
let closer;
|
|
2327
2424
|
if (stats.isDirectory()) {
|
|
2328
|
-
const absPath = sp.resolve(
|
|
2329
|
-
const targetPath = follow ? await (0, import_promises2.realpath)(
|
|
2425
|
+
const absPath = sp.resolve(path18);
|
|
2426
|
+
const targetPath = follow ? await (0, import_promises2.realpath)(path18) : path18;
|
|
2330
2427
|
if (this.fsw.closed)
|
|
2331
2428
|
return;
|
|
2332
2429
|
closer = await this._handleDir(wh.watchPath, stats, initialAdd, depth, target, wh, targetPath);
|
|
@@ -2336,29 +2433,29 @@ var NodeFsHandler = class {
|
|
|
2336
2433
|
this.fsw._symlinkPaths.set(absPath, targetPath);
|
|
2337
2434
|
}
|
|
2338
2435
|
} else if (stats.isSymbolicLink()) {
|
|
2339
|
-
const targetPath = follow ? await (0, import_promises2.realpath)(
|
|
2436
|
+
const targetPath = follow ? await (0, import_promises2.realpath)(path18) : path18;
|
|
2340
2437
|
if (this.fsw.closed)
|
|
2341
2438
|
return;
|
|
2342
2439
|
const parent = sp.dirname(wh.watchPath);
|
|
2343
2440
|
this.fsw._getWatchedDir(parent).add(wh.watchPath);
|
|
2344
2441
|
this.fsw._emit(EV.ADD, wh.watchPath, stats);
|
|
2345
|
-
closer = await this._handleDir(parent, stats, initialAdd, depth,
|
|
2442
|
+
closer = await this._handleDir(parent, stats, initialAdd, depth, path18, wh, targetPath);
|
|
2346
2443
|
if (this.fsw.closed)
|
|
2347
2444
|
return;
|
|
2348
2445
|
if (targetPath !== void 0) {
|
|
2349
|
-
this.fsw._symlinkPaths.set(sp.resolve(
|
|
2446
|
+
this.fsw._symlinkPaths.set(sp.resolve(path18), targetPath);
|
|
2350
2447
|
}
|
|
2351
2448
|
} else {
|
|
2352
2449
|
closer = this._handleFile(wh.watchPath, stats, initialAdd);
|
|
2353
2450
|
}
|
|
2354
2451
|
ready();
|
|
2355
2452
|
if (closer)
|
|
2356
|
-
this.fsw._addPathCloser(
|
|
2453
|
+
this.fsw._addPathCloser(path18, closer);
|
|
2357
2454
|
return false;
|
|
2358
2455
|
} catch (error) {
|
|
2359
2456
|
if (this.fsw._handleError(error)) {
|
|
2360
2457
|
ready();
|
|
2361
|
-
return
|
|
2458
|
+
return path18;
|
|
2362
2459
|
}
|
|
2363
2460
|
}
|
|
2364
2461
|
}
|
|
@@ -2401,24 +2498,24 @@ function createPattern(matcher) {
|
|
|
2401
2498
|
}
|
|
2402
2499
|
return () => false;
|
|
2403
2500
|
}
|
|
2404
|
-
function normalizePath(
|
|
2405
|
-
if (typeof
|
|
2501
|
+
function normalizePath(path18) {
|
|
2502
|
+
if (typeof path18 !== "string")
|
|
2406
2503
|
throw new Error("string expected");
|
|
2407
|
-
|
|
2408
|
-
|
|
2504
|
+
path18 = sp2.normalize(path18);
|
|
2505
|
+
path18 = path18.replace(/\\/g, "/");
|
|
2409
2506
|
let prepend = false;
|
|
2410
|
-
if (
|
|
2507
|
+
if (path18.startsWith("//"))
|
|
2411
2508
|
prepend = true;
|
|
2412
|
-
|
|
2509
|
+
path18 = path18.replace(DOUBLE_SLASH_RE, "/");
|
|
2413
2510
|
if (prepend)
|
|
2414
|
-
|
|
2415
|
-
return
|
|
2511
|
+
path18 = "/" + path18;
|
|
2512
|
+
return path18;
|
|
2416
2513
|
}
|
|
2417
2514
|
function matchPatterns(patterns, testString, stats) {
|
|
2418
|
-
const
|
|
2515
|
+
const path18 = normalizePath(testString);
|
|
2419
2516
|
for (let index = 0; index < patterns.length; index++) {
|
|
2420
2517
|
const pattern = patterns[index];
|
|
2421
|
-
if (pattern(
|
|
2518
|
+
if (pattern(path18, stats)) {
|
|
2422
2519
|
return true;
|
|
2423
2520
|
}
|
|
2424
2521
|
}
|
|
@@ -2456,19 +2553,19 @@ var toUnix = (string) => {
|
|
|
2456
2553
|
}
|
|
2457
2554
|
return str;
|
|
2458
2555
|
};
|
|
2459
|
-
var normalizePathToUnix = (
|
|
2460
|
-
var normalizeIgnored = (cwd = "") => (
|
|
2461
|
-
if (typeof
|
|
2462
|
-
return normalizePathToUnix(sp2.isAbsolute(
|
|
2556
|
+
var normalizePathToUnix = (path18) => toUnix(sp2.normalize(toUnix(path18)));
|
|
2557
|
+
var normalizeIgnored = (cwd = "") => (path18) => {
|
|
2558
|
+
if (typeof path18 === "string") {
|
|
2559
|
+
return normalizePathToUnix(sp2.isAbsolute(path18) ? path18 : sp2.join(cwd, path18));
|
|
2463
2560
|
} else {
|
|
2464
|
-
return
|
|
2561
|
+
return path18;
|
|
2465
2562
|
}
|
|
2466
2563
|
};
|
|
2467
|
-
var getAbsolutePath = (
|
|
2468
|
-
if (sp2.isAbsolute(
|
|
2469
|
-
return
|
|
2564
|
+
var getAbsolutePath = (path18, cwd) => {
|
|
2565
|
+
if (sp2.isAbsolute(path18)) {
|
|
2566
|
+
return path18;
|
|
2470
2567
|
}
|
|
2471
|
-
return sp2.join(cwd,
|
|
2568
|
+
return sp2.join(cwd, path18);
|
|
2472
2569
|
};
|
|
2473
2570
|
var EMPTY_SET = Object.freeze(/* @__PURE__ */ new Set());
|
|
2474
2571
|
var DirEntry = class {
|
|
@@ -2533,10 +2630,10 @@ var WatchHelper = class {
|
|
|
2533
2630
|
dirParts;
|
|
2534
2631
|
followSymlinks;
|
|
2535
2632
|
statMethod;
|
|
2536
|
-
constructor(
|
|
2633
|
+
constructor(path18, follow, fsw) {
|
|
2537
2634
|
this.fsw = fsw;
|
|
2538
|
-
const watchPath =
|
|
2539
|
-
this.path =
|
|
2635
|
+
const watchPath = path18;
|
|
2636
|
+
this.path = path18 = path18.replace(REPLACER_RE, "");
|
|
2540
2637
|
this.watchPath = watchPath;
|
|
2541
2638
|
this.fullWatchPath = sp2.resolve(watchPath);
|
|
2542
2639
|
this.dirParts = [];
|
|
@@ -2676,20 +2773,20 @@ var FSWatcher = class extends import_node_events.EventEmitter {
|
|
|
2676
2773
|
this._closePromise = void 0;
|
|
2677
2774
|
let paths = unifyPaths(paths_);
|
|
2678
2775
|
if (cwd) {
|
|
2679
|
-
paths = paths.map((
|
|
2680
|
-
const absPath = getAbsolutePath(
|
|
2776
|
+
paths = paths.map((path18) => {
|
|
2777
|
+
const absPath = getAbsolutePath(path18, cwd);
|
|
2681
2778
|
return absPath;
|
|
2682
2779
|
});
|
|
2683
2780
|
}
|
|
2684
|
-
paths.forEach((
|
|
2685
|
-
this._removeIgnoredPath(
|
|
2781
|
+
paths.forEach((path18) => {
|
|
2782
|
+
this._removeIgnoredPath(path18);
|
|
2686
2783
|
});
|
|
2687
2784
|
this._userIgnored = void 0;
|
|
2688
2785
|
if (!this._readyCount)
|
|
2689
2786
|
this._readyCount = 0;
|
|
2690
2787
|
this._readyCount += paths.length;
|
|
2691
|
-
Promise.all(paths.map(async (
|
|
2692
|
-
const res = await this._nodeFsHandler._addToNodeFs(
|
|
2788
|
+
Promise.all(paths.map(async (path18) => {
|
|
2789
|
+
const res = await this._nodeFsHandler._addToNodeFs(path18, !_internal, void 0, 0, _origAdd);
|
|
2693
2790
|
if (res)
|
|
2694
2791
|
this._emitReady();
|
|
2695
2792
|
return res;
|
|
@@ -2711,17 +2808,17 @@ var FSWatcher = class extends import_node_events.EventEmitter {
|
|
|
2711
2808
|
return this;
|
|
2712
2809
|
const paths = unifyPaths(paths_);
|
|
2713
2810
|
const { cwd } = this.options;
|
|
2714
|
-
paths.forEach((
|
|
2715
|
-
if (!sp2.isAbsolute(
|
|
2811
|
+
paths.forEach((path18) => {
|
|
2812
|
+
if (!sp2.isAbsolute(path18) && !this._closers.has(path18)) {
|
|
2716
2813
|
if (cwd)
|
|
2717
|
-
|
|
2718
|
-
|
|
2814
|
+
path18 = sp2.join(cwd, path18);
|
|
2815
|
+
path18 = sp2.resolve(path18);
|
|
2719
2816
|
}
|
|
2720
|
-
this._closePath(
|
|
2721
|
-
this._addIgnoredPath(
|
|
2722
|
-
if (this._watched.has(
|
|
2817
|
+
this._closePath(path18);
|
|
2818
|
+
this._addIgnoredPath(path18);
|
|
2819
|
+
if (this._watched.has(path18)) {
|
|
2723
2820
|
this._addIgnoredPath({
|
|
2724
|
-
path:
|
|
2821
|
+
path: path18,
|
|
2725
2822
|
recursive: true
|
|
2726
2823
|
});
|
|
2727
2824
|
}
|
|
@@ -2785,38 +2882,38 @@ var FSWatcher = class extends import_node_events.EventEmitter {
|
|
|
2785
2882
|
* @param stats arguments to be passed with event
|
|
2786
2883
|
* @returns the error if defined, otherwise the value of the FSWatcher instance's `closed` flag
|
|
2787
2884
|
*/
|
|
2788
|
-
async _emit(event,
|
|
2885
|
+
async _emit(event, path18, stats) {
|
|
2789
2886
|
if (this.closed)
|
|
2790
2887
|
return;
|
|
2791
2888
|
const opts = this.options;
|
|
2792
2889
|
if (isWindows)
|
|
2793
|
-
|
|
2890
|
+
path18 = sp2.normalize(path18);
|
|
2794
2891
|
if (opts.cwd)
|
|
2795
|
-
|
|
2796
|
-
const args = [
|
|
2892
|
+
path18 = sp2.relative(opts.cwd, path18);
|
|
2893
|
+
const args = [path18];
|
|
2797
2894
|
if (stats != null)
|
|
2798
2895
|
args.push(stats);
|
|
2799
2896
|
const awf = opts.awaitWriteFinish;
|
|
2800
2897
|
let pw;
|
|
2801
|
-
if (awf && (pw = this._pendingWrites.get(
|
|
2898
|
+
if (awf && (pw = this._pendingWrites.get(path18))) {
|
|
2802
2899
|
pw.lastChange = /* @__PURE__ */ new Date();
|
|
2803
2900
|
return this;
|
|
2804
2901
|
}
|
|
2805
2902
|
if (opts.atomic) {
|
|
2806
2903
|
if (event === EVENTS.UNLINK) {
|
|
2807
|
-
this._pendingUnlinks.set(
|
|
2904
|
+
this._pendingUnlinks.set(path18, [event, ...args]);
|
|
2808
2905
|
setTimeout(() => {
|
|
2809
|
-
this._pendingUnlinks.forEach((entry,
|
|
2906
|
+
this._pendingUnlinks.forEach((entry, path19) => {
|
|
2810
2907
|
this.emit(...entry);
|
|
2811
2908
|
this.emit(EVENTS.ALL, ...entry);
|
|
2812
|
-
this._pendingUnlinks.delete(
|
|
2909
|
+
this._pendingUnlinks.delete(path19);
|
|
2813
2910
|
});
|
|
2814
2911
|
}, typeof opts.atomic === "number" ? opts.atomic : 100);
|
|
2815
2912
|
return this;
|
|
2816
2913
|
}
|
|
2817
|
-
if (event === EVENTS.ADD && this._pendingUnlinks.has(
|
|
2914
|
+
if (event === EVENTS.ADD && this._pendingUnlinks.has(path18)) {
|
|
2818
2915
|
event = EVENTS.CHANGE;
|
|
2819
|
-
this._pendingUnlinks.delete(
|
|
2916
|
+
this._pendingUnlinks.delete(path18);
|
|
2820
2917
|
}
|
|
2821
2918
|
}
|
|
2822
2919
|
if (awf && (event === EVENTS.ADD || event === EVENTS.CHANGE) && this._readyEmitted) {
|
|
@@ -2834,16 +2931,16 @@ var FSWatcher = class extends import_node_events.EventEmitter {
|
|
|
2834
2931
|
this.emitWithAll(event, args);
|
|
2835
2932
|
}
|
|
2836
2933
|
};
|
|
2837
|
-
this._awaitWriteFinish(
|
|
2934
|
+
this._awaitWriteFinish(path18, awf.stabilityThreshold, event, awfEmit);
|
|
2838
2935
|
return this;
|
|
2839
2936
|
}
|
|
2840
2937
|
if (event === EVENTS.CHANGE) {
|
|
2841
|
-
const isThrottled = !this._throttle(EVENTS.CHANGE,
|
|
2938
|
+
const isThrottled = !this._throttle(EVENTS.CHANGE, path18, 50);
|
|
2842
2939
|
if (isThrottled)
|
|
2843
2940
|
return this;
|
|
2844
2941
|
}
|
|
2845
2942
|
if (opts.alwaysStat && stats === void 0 && (event === EVENTS.ADD || event === EVENTS.ADD_DIR || event === EVENTS.CHANGE)) {
|
|
2846
|
-
const fullPath = opts.cwd ? sp2.join(opts.cwd,
|
|
2943
|
+
const fullPath = opts.cwd ? sp2.join(opts.cwd, path18) : path18;
|
|
2847
2944
|
let stats2;
|
|
2848
2945
|
try {
|
|
2849
2946
|
stats2 = await (0, import_promises3.stat)(fullPath);
|
|
@@ -2874,23 +2971,23 @@ var FSWatcher = class extends import_node_events.EventEmitter {
|
|
|
2874
2971
|
* @param timeout duration of time to suppress duplicate actions
|
|
2875
2972
|
* @returns tracking object or false if action should be suppressed
|
|
2876
2973
|
*/
|
|
2877
|
-
_throttle(actionType,
|
|
2974
|
+
_throttle(actionType, path18, timeout) {
|
|
2878
2975
|
if (!this._throttled.has(actionType)) {
|
|
2879
2976
|
this._throttled.set(actionType, /* @__PURE__ */ new Map());
|
|
2880
2977
|
}
|
|
2881
2978
|
const action = this._throttled.get(actionType);
|
|
2882
2979
|
if (!action)
|
|
2883
2980
|
throw new Error("invalid throttle");
|
|
2884
|
-
const actionPath = action.get(
|
|
2981
|
+
const actionPath = action.get(path18);
|
|
2885
2982
|
if (actionPath) {
|
|
2886
2983
|
actionPath.count++;
|
|
2887
2984
|
return false;
|
|
2888
2985
|
}
|
|
2889
2986
|
let timeoutObject;
|
|
2890
2987
|
const clear = () => {
|
|
2891
|
-
const item = action.get(
|
|
2988
|
+
const item = action.get(path18);
|
|
2892
2989
|
const count = item ? item.count : 0;
|
|
2893
|
-
action.delete(
|
|
2990
|
+
action.delete(path18);
|
|
2894
2991
|
clearTimeout(timeoutObject);
|
|
2895
2992
|
if (item)
|
|
2896
2993
|
clearTimeout(item.timeoutObject);
|
|
@@ -2898,7 +2995,7 @@ var FSWatcher = class extends import_node_events.EventEmitter {
|
|
|
2898
2995
|
};
|
|
2899
2996
|
timeoutObject = setTimeout(clear, timeout);
|
|
2900
2997
|
const thr = { timeoutObject, clear, count: 0 };
|
|
2901
|
-
action.set(
|
|
2998
|
+
action.set(path18, thr);
|
|
2902
2999
|
return thr;
|
|
2903
3000
|
}
|
|
2904
3001
|
_incrReadyCount() {
|
|
@@ -2912,44 +3009,44 @@ var FSWatcher = class extends import_node_events.EventEmitter {
|
|
|
2912
3009
|
* @param event
|
|
2913
3010
|
* @param awfEmit Callback to be called when ready for event to be emitted.
|
|
2914
3011
|
*/
|
|
2915
|
-
_awaitWriteFinish(
|
|
3012
|
+
_awaitWriteFinish(path18, threshold, event, awfEmit) {
|
|
2916
3013
|
const awf = this.options.awaitWriteFinish;
|
|
2917
3014
|
if (typeof awf !== "object")
|
|
2918
3015
|
return;
|
|
2919
3016
|
const pollInterval = awf.pollInterval;
|
|
2920
3017
|
let timeoutHandler;
|
|
2921
|
-
let fullPath =
|
|
2922
|
-
if (this.options.cwd && !sp2.isAbsolute(
|
|
2923
|
-
fullPath = sp2.join(this.options.cwd,
|
|
3018
|
+
let fullPath = path18;
|
|
3019
|
+
if (this.options.cwd && !sp2.isAbsolute(path18)) {
|
|
3020
|
+
fullPath = sp2.join(this.options.cwd, path18);
|
|
2924
3021
|
}
|
|
2925
3022
|
const now = /* @__PURE__ */ new Date();
|
|
2926
3023
|
const writes = this._pendingWrites;
|
|
2927
3024
|
function awaitWriteFinishFn(prevStat) {
|
|
2928
3025
|
(0, import_node_fs2.stat)(fullPath, (err, curStat) => {
|
|
2929
|
-
if (err || !writes.has(
|
|
3026
|
+
if (err || !writes.has(path18)) {
|
|
2930
3027
|
if (err && err.code !== "ENOENT")
|
|
2931
3028
|
awfEmit(err);
|
|
2932
3029
|
return;
|
|
2933
3030
|
}
|
|
2934
3031
|
const now2 = Number(/* @__PURE__ */ new Date());
|
|
2935
3032
|
if (prevStat && curStat.size !== prevStat.size) {
|
|
2936
|
-
writes.get(
|
|
3033
|
+
writes.get(path18).lastChange = now2;
|
|
2937
3034
|
}
|
|
2938
|
-
const pw = writes.get(
|
|
3035
|
+
const pw = writes.get(path18);
|
|
2939
3036
|
const df = now2 - pw.lastChange;
|
|
2940
3037
|
if (df >= threshold) {
|
|
2941
|
-
writes.delete(
|
|
3038
|
+
writes.delete(path18);
|
|
2942
3039
|
awfEmit(void 0, curStat);
|
|
2943
3040
|
} else {
|
|
2944
3041
|
timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval, curStat);
|
|
2945
3042
|
}
|
|
2946
3043
|
});
|
|
2947
3044
|
}
|
|
2948
|
-
if (!writes.has(
|
|
2949
|
-
writes.set(
|
|
3045
|
+
if (!writes.has(path18)) {
|
|
3046
|
+
writes.set(path18, {
|
|
2950
3047
|
lastChange: now,
|
|
2951
3048
|
cancelWait: () => {
|
|
2952
|
-
writes.delete(
|
|
3049
|
+
writes.delete(path18);
|
|
2953
3050
|
clearTimeout(timeoutHandler);
|
|
2954
3051
|
return event;
|
|
2955
3052
|
}
|
|
@@ -2960,8 +3057,8 @@ var FSWatcher = class extends import_node_events.EventEmitter {
|
|
|
2960
3057
|
/**
|
|
2961
3058
|
* Determines whether user has asked to ignore this path.
|
|
2962
3059
|
*/
|
|
2963
|
-
_isIgnored(
|
|
2964
|
-
if (this.options.atomic && DOT_RE.test(
|
|
3060
|
+
_isIgnored(path18, stats) {
|
|
3061
|
+
if (this.options.atomic && DOT_RE.test(path18))
|
|
2965
3062
|
return true;
|
|
2966
3063
|
if (!this._userIgnored) {
|
|
2967
3064
|
const { cwd } = this.options;
|
|
@@ -2971,17 +3068,17 @@ var FSWatcher = class extends import_node_events.EventEmitter {
|
|
|
2971
3068
|
const list = [...ignoredPaths.map(normalizeIgnored(cwd)), ...ignored];
|
|
2972
3069
|
this._userIgnored = anymatch(list, void 0);
|
|
2973
3070
|
}
|
|
2974
|
-
return this._userIgnored(
|
|
3071
|
+
return this._userIgnored(path18, stats);
|
|
2975
3072
|
}
|
|
2976
|
-
_isntIgnored(
|
|
2977
|
-
return !this._isIgnored(
|
|
3073
|
+
_isntIgnored(path18, stat4) {
|
|
3074
|
+
return !this._isIgnored(path18, stat4);
|
|
2978
3075
|
}
|
|
2979
3076
|
/**
|
|
2980
3077
|
* Provides a set of common helpers and properties relating to symlink handling.
|
|
2981
3078
|
* @param path file or directory pattern being watched
|
|
2982
3079
|
*/
|
|
2983
|
-
_getWatchHelpers(
|
|
2984
|
-
return new WatchHelper(
|
|
3080
|
+
_getWatchHelpers(path18) {
|
|
3081
|
+
return new WatchHelper(path18, this.options.followSymlinks, this);
|
|
2985
3082
|
}
|
|
2986
3083
|
// Directory helpers
|
|
2987
3084
|
// -----------------
|
|
@@ -3013,63 +3110,63 @@ var FSWatcher = class extends import_node_events.EventEmitter {
|
|
|
3013
3110
|
* @param item base path of item/directory
|
|
3014
3111
|
*/
|
|
3015
3112
|
_remove(directory, item, isDirectory) {
|
|
3016
|
-
const
|
|
3017
|
-
const fullPath = sp2.resolve(
|
|
3018
|
-
isDirectory = isDirectory != null ? isDirectory : this._watched.has(
|
|
3019
|
-
if (!this._throttle("remove",
|
|
3113
|
+
const path18 = sp2.join(directory, item);
|
|
3114
|
+
const fullPath = sp2.resolve(path18);
|
|
3115
|
+
isDirectory = isDirectory != null ? isDirectory : this._watched.has(path18) || this._watched.has(fullPath);
|
|
3116
|
+
if (!this._throttle("remove", path18, 100))
|
|
3020
3117
|
return;
|
|
3021
3118
|
if (!isDirectory && this._watched.size === 1) {
|
|
3022
3119
|
this.add(directory, item, true);
|
|
3023
3120
|
}
|
|
3024
|
-
const wp = this._getWatchedDir(
|
|
3121
|
+
const wp = this._getWatchedDir(path18);
|
|
3025
3122
|
const nestedDirectoryChildren = wp.getChildren();
|
|
3026
|
-
nestedDirectoryChildren.forEach((nested) => this._remove(
|
|
3123
|
+
nestedDirectoryChildren.forEach((nested) => this._remove(path18, nested));
|
|
3027
3124
|
const parent = this._getWatchedDir(directory);
|
|
3028
3125
|
const wasTracked = parent.has(item);
|
|
3029
3126
|
parent.remove(item);
|
|
3030
3127
|
if (this._symlinkPaths.has(fullPath)) {
|
|
3031
3128
|
this._symlinkPaths.delete(fullPath);
|
|
3032
3129
|
}
|
|
3033
|
-
let relPath =
|
|
3130
|
+
let relPath = path18;
|
|
3034
3131
|
if (this.options.cwd)
|
|
3035
|
-
relPath = sp2.relative(this.options.cwd,
|
|
3132
|
+
relPath = sp2.relative(this.options.cwd, path18);
|
|
3036
3133
|
if (this.options.awaitWriteFinish && this._pendingWrites.has(relPath)) {
|
|
3037
3134
|
const event = this._pendingWrites.get(relPath).cancelWait();
|
|
3038
3135
|
if (event === EVENTS.ADD)
|
|
3039
3136
|
return;
|
|
3040
3137
|
}
|
|
3041
|
-
this._watched.delete(
|
|
3138
|
+
this._watched.delete(path18);
|
|
3042
3139
|
this._watched.delete(fullPath);
|
|
3043
3140
|
const eventName = isDirectory ? EVENTS.UNLINK_DIR : EVENTS.UNLINK;
|
|
3044
|
-
if (wasTracked && !this._isIgnored(
|
|
3045
|
-
this._emit(eventName,
|
|
3046
|
-
this._closePath(
|
|
3141
|
+
if (wasTracked && !this._isIgnored(path18))
|
|
3142
|
+
this._emit(eventName, path18);
|
|
3143
|
+
this._closePath(path18);
|
|
3047
3144
|
}
|
|
3048
3145
|
/**
|
|
3049
3146
|
* Closes all watchers for a path
|
|
3050
3147
|
*/
|
|
3051
|
-
_closePath(
|
|
3052
|
-
this._closeFile(
|
|
3053
|
-
const dir = sp2.dirname(
|
|
3054
|
-
this._getWatchedDir(dir).remove(sp2.basename(
|
|
3148
|
+
_closePath(path18) {
|
|
3149
|
+
this._closeFile(path18);
|
|
3150
|
+
const dir = sp2.dirname(path18);
|
|
3151
|
+
this._getWatchedDir(dir).remove(sp2.basename(path18));
|
|
3055
3152
|
}
|
|
3056
3153
|
/**
|
|
3057
3154
|
* Closes only file-specific watchers
|
|
3058
3155
|
*/
|
|
3059
|
-
_closeFile(
|
|
3060
|
-
const closers = this._closers.get(
|
|
3156
|
+
_closeFile(path18) {
|
|
3157
|
+
const closers = this._closers.get(path18);
|
|
3061
3158
|
if (!closers)
|
|
3062
3159
|
return;
|
|
3063
3160
|
closers.forEach((closer) => closer());
|
|
3064
|
-
this._closers.delete(
|
|
3161
|
+
this._closers.delete(path18);
|
|
3065
3162
|
}
|
|
3066
|
-
_addPathCloser(
|
|
3163
|
+
_addPathCloser(path18, closer) {
|
|
3067
3164
|
if (!closer)
|
|
3068
3165
|
return;
|
|
3069
|
-
let list = this._closers.get(
|
|
3166
|
+
let list = this._closers.get(path18);
|
|
3070
3167
|
if (!list) {
|
|
3071
3168
|
list = [];
|
|
3072
|
-
this._closers.set(
|
|
3169
|
+
this._closers.set(path18, list);
|
|
3073
3170
|
}
|
|
3074
3171
|
list.push(closer);
|
|
3075
3172
|
}
|
|
@@ -3098,13 +3195,13 @@ function watch(paths, options = {}) {
|
|
|
3098
3195
|
}
|
|
3099
3196
|
var chokidar_default = { watch, FSWatcher };
|
|
3100
3197
|
|
|
3101
|
-
// src/watcher/
|
|
3102
|
-
var
|
|
3198
|
+
// src/watcher/file-watcher.ts
|
|
3199
|
+
var path8 = __toESM(require("path"), 1);
|
|
3103
3200
|
|
|
3104
3201
|
// src/utils/files.ts
|
|
3105
3202
|
var import_ignore = __toESM(require_ignore(), 1);
|
|
3106
|
-
var
|
|
3107
|
-
var
|
|
3203
|
+
var import_fs5 = require("fs");
|
|
3204
|
+
var path7 = __toESM(require("path"), 1);
|
|
3108
3205
|
var PROJECT_MARKERS = [
|
|
3109
3206
|
".git",
|
|
3110
3207
|
"package.json",
|
|
@@ -3123,7 +3220,7 @@ var PROJECT_MARKERS = [
|
|
|
3123
3220
|
];
|
|
3124
3221
|
function hasProjectMarker(projectRoot) {
|
|
3125
3222
|
for (const marker of PROJECT_MARKERS) {
|
|
3126
|
-
if ((0,
|
|
3223
|
+
if ((0, import_fs5.existsSync)(path7.join(projectRoot, marker))) {
|
|
3127
3224
|
return true;
|
|
3128
3225
|
}
|
|
3129
3226
|
}
|
|
@@ -3149,23 +3246,17 @@ function createIgnoreFilter(projectRoot) {
|
|
|
3149
3246
|
"**/*build*/**"
|
|
3150
3247
|
];
|
|
3151
3248
|
ig.add(defaultIgnores);
|
|
3152
|
-
const gitignorePath =
|
|
3153
|
-
if ((0,
|
|
3154
|
-
const gitignoreContent = (0,
|
|
3249
|
+
const gitignorePath = path7.join(projectRoot, ".gitignore");
|
|
3250
|
+
if ((0, import_fs5.existsSync)(gitignorePath)) {
|
|
3251
|
+
const gitignoreContent = (0, import_fs5.readFileSync)(gitignorePath, "utf-8");
|
|
3155
3252
|
ig.add(gitignoreContent);
|
|
3156
3253
|
}
|
|
3157
3254
|
return ig;
|
|
3158
3255
|
}
|
|
3159
3256
|
function shouldIncludeFile(filePath, projectRoot, includePatterns, excludePatterns, ignoreFilter) {
|
|
3160
|
-
const relativePath =
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
if (part.startsWith(".") && part !== "." && part !== "..") {
|
|
3164
|
-
return false;
|
|
3165
|
-
}
|
|
3166
|
-
if (part.toLowerCase().includes("build")) {
|
|
3167
|
-
return false;
|
|
3168
|
-
}
|
|
3257
|
+
const relativePath = path7.relative(projectRoot, filePath);
|
|
3258
|
+
if (hasFilteredPathSegment(relativePath, path7.sep)) {
|
|
3259
|
+
return false;
|
|
3169
3260
|
}
|
|
3170
3261
|
if (ignoreFilter.ignores(relativePath)) {
|
|
3171
3262
|
return false;
|
|
@@ -3198,19 +3289,19 @@ function matchGlob(filePath, pattern) {
|
|
|
3198
3289
|
return regex.test(filePath);
|
|
3199
3290
|
}
|
|
3200
3291
|
async function* walkDirectory(dir, projectRoot, includePatterns, excludePatterns, ignoreFilter, maxFileSize, skipped, options, currentDepth = 0) {
|
|
3201
|
-
const entries = await
|
|
3292
|
+
const entries = await import_fs5.promises.readdir(dir, { withFileTypes: true });
|
|
3202
3293
|
const filesInDir = [];
|
|
3203
3294
|
const subdirs = [];
|
|
3204
3295
|
for (const entry of entries) {
|
|
3205
|
-
const fullPath =
|
|
3206
|
-
const relativePath =
|
|
3207
|
-
if (
|
|
3296
|
+
const fullPath = path7.join(dir, entry.name);
|
|
3297
|
+
const relativePath = path7.relative(projectRoot, fullPath);
|
|
3298
|
+
if (isHiddenPathSegment(entry.name)) {
|
|
3208
3299
|
if (entry.isDirectory()) {
|
|
3209
3300
|
skipped.push({ path: relativePath, reason: "excluded" });
|
|
3210
3301
|
}
|
|
3211
3302
|
continue;
|
|
3212
3303
|
}
|
|
3213
|
-
if (entry.isDirectory() && entry.name
|
|
3304
|
+
if (entry.isDirectory() && isBuildPathSegment(entry.name)) {
|
|
3214
3305
|
skipped.push({ path: relativePath, reason: "excluded" });
|
|
3215
3306
|
continue;
|
|
3216
3307
|
}
|
|
@@ -3223,7 +3314,7 @@ async function* walkDirectory(dir, projectRoot, includePatterns, excludePatterns
|
|
|
3223
3314
|
if (entry.isDirectory()) {
|
|
3224
3315
|
subdirs.push({ fullPath, relativePath });
|
|
3225
3316
|
} else if (entry.isFile()) {
|
|
3226
|
-
const stat4 = await
|
|
3317
|
+
const stat4 = await import_fs5.promises.stat(fullPath);
|
|
3227
3318
|
if (stat4.size > maxFileSize) {
|
|
3228
3319
|
skipped.push({ path: relativePath, reason: "too_large" });
|
|
3229
3320
|
continue;
|
|
@@ -3252,7 +3343,7 @@ async function* walkDirectory(dir, projectRoot, includePatterns, excludePatterns
|
|
|
3252
3343
|
yield f;
|
|
3253
3344
|
}
|
|
3254
3345
|
for (let i = options.maxFilesPerDirectory; i < filesInDir.length; i++) {
|
|
3255
|
-
skipped.push({ path:
|
|
3346
|
+
skipped.push({ path: path7.relative(projectRoot, filesInDir[i].path), reason: "excluded" });
|
|
3256
3347
|
}
|
|
3257
3348
|
const canRecurse = options.maxDepth === -1 || currentDepth < options.maxDepth;
|
|
3258
3349
|
if (canRecurse) {
|
|
@@ -3292,14 +3383,14 @@ async function collectFiles(projectRoot, includePatterns, excludePatterns, maxFi
|
|
|
3292
3383
|
if (additionalRoots && additionalRoots.length > 0) {
|
|
3293
3384
|
const normalizedRoots = /* @__PURE__ */ new Set();
|
|
3294
3385
|
for (const kbRoot of additionalRoots) {
|
|
3295
|
-
const resolved =
|
|
3296
|
-
|
|
3386
|
+
const resolved = path7.normalize(
|
|
3387
|
+
path7.isAbsolute(kbRoot) ? kbRoot : path7.resolve(projectRoot, kbRoot)
|
|
3297
3388
|
);
|
|
3298
3389
|
normalizedRoots.add(resolved);
|
|
3299
3390
|
}
|
|
3300
3391
|
for (const resolvedKbRoot of normalizedRoots) {
|
|
3301
3392
|
try {
|
|
3302
|
-
const stat4 = await
|
|
3393
|
+
const stat4 = await import_fs5.promises.stat(resolvedKbRoot);
|
|
3303
3394
|
if (!stat4.isDirectory()) {
|
|
3304
3395
|
skipped.push({ path: resolvedKbRoot, reason: "excluded" });
|
|
3305
3396
|
continue;
|
|
@@ -3326,7 +3417,7 @@ async function collectFiles(projectRoot, includePatterns, excludePatterns, maxFi
|
|
|
3326
3417
|
return { files, skipped };
|
|
3327
3418
|
}
|
|
3328
3419
|
|
|
3329
|
-
// src/watcher/
|
|
3420
|
+
// src/watcher/file-watcher.ts
|
|
3330
3421
|
var FileWatcher = class {
|
|
3331
3422
|
watcher = null;
|
|
3332
3423
|
projectRoot;
|
|
@@ -3347,16 +3438,13 @@ var FileWatcher = class {
|
|
|
3347
3438
|
const ignoreFilter = createIgnoreFilter(this.projectRoot);
|
|
3348
3439
|
this.watcher = chokidar_default.watch(this.projectRoot, {
|
|
3349
3440
|
ignored: (filePath) => {
|
|
3350
|
-
const relativePath =
|
|
3441
|
+
const relativePath = path8.relative(this.projectRoot, filePath);
|
|
3351
3442
|
if (!relativePath) return false;
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
|
|
3356
|
-
|
|
3357
|
-
if (part.toLowerCase().includes("build")) {
|
|
3358
|
-
return true;
|
|
3359
|
-
}
|
|
3443
|
+
if (hasFilteredPathSegment(relativePath, path8.sep)) {
|
|
3444
|
+
return true;
|
|
3445
|
+
}
|
|
3446
|
+
if (isRestrictedDirectory(relativePath, path8.sep)) {
|
|
3447
|
+
return true;
|
|
3360
3448
|
}
|
|
3361
3449
|
if (ignoreFilter.ignores(relativePath)) {
|
|
3362
3450
|
return true;
|
|
@@ -3370,6 +3458,13 @@ var FileWatcher = class {
|
|
|
3370
3458
|
pollInterval: 100
|
|
3371
3459
|
}
|
|
3372
3460
|
});
|
|
3461
|
+
this.watcher.on("error", (error) => {
|
|
3462
|
+
const err = error instanceof Error ? error : null;
|
|
3463
|
+
if (err?.code === "EPERM" || err?.code === "EACCES") {
|
|
3464
|
+
return;
|
|
3465
|
+
}
|
|
3466
|
+
console.error("[codebase-index] Watcher error:", err?.message ?? error);
|
|
3467
|
+
});
|
|
3373
3468
|
this.watcher.on("add", (filePath) => this.handleChange("add", filePath));
|
|
3374
3469
|
this.watcher.on("change", (filePath) => this.handleChange("change", filePath));
|
|
3375
3470
|
this.watcher.on("unlink", (filePath) => this.handleChange("unlink", filePath));
|
|
@@ -3401,7 +3496,7 @@ var FileWatcher = class {
|
|
|
3401
3496
|
return;
|
|
3402
3497
|
}
|
|
3403
3498
|
const changes = Array.from(this.pendingChanges.entries()).map(
|
|
3404
|
-
([
|
|
3499
|
+
([path18, type]) => ({ path: path18, type })
|
|
3405
3500
|
);
|
|
3406
3501
|
this.pendingChanges.clear();
|
|
3407
3502
|
try {
|
|
@@ -3426,6 +3521,9 @@ var FileWatcher = class {
|
|
|
3426
3521
|
return this.watcher !== null;
|
|
3427
3522
|
}
|
|
3428
3523
|
};
|
|
3524
|
+
|
|
3525
|
+
// src/watcher/git-head-watcher.ts
|
|
3526
|
+
var path9 = __toESM(require("path"), 1);
|
|
3429
3527
|
var GitHeadWatcher = class {
|
|
3430
3528
|
watcher = null;
|
|
3431
3529
|
projectRoot;
|
|
@@ -3447,7 +3545,7 @@ var GitHeadWatcher = class {
|
|
|
3447
3545
|
this.onBranchChange = handler;
|
|
3448
3546
|
this.currentBranch = getCurrentBranch(this.projectRoot);
|
|
3449
3547
|
const headPath = getHeadPath(this.projectRoot);
|
|
3450
|
-
const refsPath =
|
|
3548
|
+
const refsPath = path9.join(this.projectRoot, ".git", "refs", "heads");
|
|
3451
3549
|
this.watcher = chokidar_default.watch([headPath, refsPath], {
|
|
3452
3550
|
persistent: true,
|
|
3453
3551
|
ignoreInitial: true,
|
|
@@ -3499,7 +3597,9 @@ var GitHeadWatcher = class {
|
|
|
3499
3597
|
return this.watcher !== null;
|
|
3500
3598
|
}
|
|
3501
3599
|
};
|
|
3502
|
-
|
|
3600
|
+
|
|
3601
|
+
// src/watcher/index.ts
|
|
3602
|
+
function createWatcherWithIndexer(getIndexer, projectRoot, config) {
|
|
3503
3603
|
const fileWatcher = new FileWatcher(projectRoot, config);
|
|
3504
3604
|
fileWatcher.start(async (changes) => {
|
|
3505
3605
|
const hasAddOrChange = changes.some(
|
|
@@ -3507,7 +3607,7 @@ function createWatcherWithIndexer(getIndexer2, projectRoot, config) {
|
|
|
3507
3607
|
);
|
|
3508
3608
|
const hasDelete = changes.some((c) => c.type === "unlink");
|
|
3509
3609
|
if (hasAddOrChange || hasDelete) {
|
|
3510
|
-
await
|
|
3610
|
+
await getIndexer().index();
|
|
3511
3611
|
}
|
|
3512
3612
|
});
|
|
3513
3613
|
let gitWatcher = null;
|
|
@@ -3515,7 +3615,7 @@ function createWatcherWithIndexer(getIndexer2, projectRoot, config) {
|
|
|
3515
3615
|
gitWatcher = new GitHeadWatcher(projectRoot);
|
|
3516
3616
|
gitWatcher.start(async (oldBranch, newBranch) => {
|
|
3517
3617
|
console.log(`Branch changed: ${oldBranch ?? "(none)"} -> ${newBranch}`);
|
|
3518
|
-
await
|
|
3618
|
+
await getIndexer().index();
|
|
3519
3619
|
});
|
|
3520
3620
|
}
|
|
3521
3621
|
return {
|
|
@@ -3532,8 +3632,8 @@ function createWatcherWithIndexer(getIndexer2, projectRoot, config) {
|
|
|
3532
3632
|
var import_plugin = require("@opencode-ai/plugin");
|
|
3533
3633
|
|
|
3534
3634
|
// src/indexer/index.ts
|
|
3535
|
-
var
|
|
3536
|
-
var
|
|
3635
|
+
var import_fs7 = require("fs");
|
|
3636
|
+
var path12 = __toESM(require("path"), 1);
|
|
3537
3637
|
var import_perf_hooks = require("perf_hooks");
|
|
3538
3638
|
|
|
3539
3639
|
// node_modules/eventemitter3/index.mjs
|
|
@@ -3558,7 +3658,7 @@ function pTimeout(promise, options) {
|
|
|
3558
3658
|
} = options;
|
|
3559
3659
|
let timer;
|
|
3560
3660
|
let abortHandler;
|
|
3561
|
-
const wrappedPromise = new Promise((
|
|
3661
|
+
const wrappedPromise = new Promise((resolve12, reject) => {
|
|
3562
3662
|
if (typeof milliseconds !== "number" || Math.sign(milliseconds) !== 1) {
|
|
3563
3663
|
throw new TypeError(`Expected \`milliseconds\` to be a positive number, got \`${milliseconds}\``);
|
|
3564
3664
|
}
|
|
@@ -3572,7 +3672,7 @@ function pTimeout(promise, options) {
|
|
|
3572
3672
|
};
|
|
3573
3673
|
signal.addEventListener("abort", abortHandler, { once: true });
|
|
3574
3674
|
}
|
|
3575
|
-
promise.then(
|
|
3675
|
+
promise.then(resolve12, reject);
|
|
3576
3676
|
if (milliseconds === Number.POSITIVE_INFINITY) {
|
|
3577
3677
|
return;
|
|
3578
3678
|
}
|
|
@@ -3580,7 +3680,7 @@ function pTimeout(promise, options) {
|
|
|
3580
3680
|
timer = customTimers.setTimeout.call(void 0, () => {
|
|
3581
3681
|
if (fallback) {
|
|
3582
3682
|
try {
|
|
3583
|
-
|
|
3683
|
+
resolve12(fallback());
|
|
3584
3684
|
} catch (error) {
|
|
3585
3685
|
reject(error);
|
|
3586
3686
|
}
|
|
@@ -3590,7 +3690,7 @@ function pTimeout(promise, options) {
|
|
|
3590
3690
|
promise.cancel();
|
|
3591
3691
|
}
|
|
3592
3692
|
if (message === false) {
|
|
3593
|
-
|
|
3693
|
+
resolve12();
|
|
3594
3694
|
} else if (message instanceof Error) {
|
|
3595
3695
|
reject(message);
|
|
3596
3696
|
} else {
|
|
@@ -3992,7 +4092,7 @@ var PQueue = class extends import_index.default {
|
|
|
3992
4092
|
// Assign unique ID if not provided
|
|
3993
4093
|
id: options.id ?? (this.#idAssigner++).toString()
|
|
3994
4094
|
};
|
|
3995
|
-
return new Promise((
|
|
4095
|
+
return new Promise((resolve12, reject) => {
|
|
3996
4096
|
const taskSymbol = /* @__PURE__ */ Symbol(`task-${options.id}`);
|
|
3997
4097
|
let cleanupQueueAbortHandler = () => void 0;
|
|
3998
4098
|
const run = async () => {
|
|
@@ -4032,7 +4132,7 @@ var PQueue = class extends import_index.default {
|
|
|
4032
4132
|
})]);
|
|
4033
4133
|
}
|
|
4034
4134
|
const result = await operation;
|
|
4035
|
-
|
|
4135
|
+
resolve12(result);
|
|
4036
4136
|
this.emit("completed", result);
|
|
4037
4137
|
} catch (error) {
|
|
4038
4138
|
reject(error);
|
|
@@ -4220,13 +4320,13 @@ var PQueue = class extends import_index.default {
|
|
|
4220
4320
|
});
|
|
4221
4321
|
}
|
|
4222
4322
|
async #onEvent(event, filter) {
|
|
4223
|
-
return new Promise((
|
|
4323
|
+
return new Promise((resolve12) => {
|
|
4224
4324
|
const listener = () => {
|
|
4225
4325
|
if (filter && !filter()) {
|
|
4226
4326
|
return;
|
|
4227
4327
|
}
|
|
4228
4328
|
this.off(event, listener);
|
|
4229
|
-
|
|
4329
|
+
resolve12();
|
|
4230
4330
|
};
|
|
4231
4331
|
this.on(event, listener);
|
|
4232
4332
|
});
|
|
@@ -4512,7 +4612,7 @@ async function onAttemptFailure({ error, attemptNumber, retriesConsumed, startTi
|
|
|
4512
4612
|
const finalDelay = Math.min(delayTime, remainingTime);
|
|
4513
4613
|
options.signal?.throwIfAborted();
|
|
4514
4614
|
if (finalDelay > 0) {
|
|
4515
|
-
await new Promise((
|
|
4615
|
+
await new Promise((resolve12, reject) => {
|
|
4516
4616
|
const onAbort = () => {
|
|
4517
4617
|
clearTimeout(timeoutToken);
|
|
4518
4618
|
options.signal?.removeEventListener("abort", onAbort);
|
|
@@ -4520,7 +4620,7 @@ async function onAttemptFailure({ error, attemptNumber, retriesConsumed, startTi
|
|
|
4520
4620
|
};
|
|
4521
4621
|
const timeoutToken = setTimeout(() => {
|
|
4522
4622
|
options.signal?.removeEventListener("abort", onAbort);
|
|
4523
|
-
|
|
4623
|
+
resolve12();
|
|
4524
4624
|
}, finalDelay);
|
|
4525
4625
|
if (options.unref) {
|
|
4526
4626
|
timeoutToken.unref?.();
|
|
@@ -4581,17 +4681,17 @@ async function pRetry(input, options = {}) {
|
|
|
4581
4681
|
}
|
|
4582
4682
|
|
|
4583
4683
|
// src/embeddings/detector.ts
|
|
4584
|
-
var
|
|
4585
|
-
var
|
|
4684
|
+
var import_fs6 = require("fs");
|
|
4685
|
+
var path10 = __toESM(require("path"), 1);
|
|
4586
4686
|
var os3 = __toESM(require("os"), 1);
|
|
4587
4687
|
function getOpenCodeAuthPath() {
|
|
4588
|
-
return
|
|
4688
|
+
return path10.join(os3.homedir(), ".local", "share", "opencode", "auth.json");
|
|
4589
4689
|
}
|
|
4590
4690
|
function loadOpenCodeAuth() {
|
|
4591
4691
|
const authPath = getOpenCodeAuthPath();
|
|
4592
4692
|
try {
|
|
4593
|
-
if ((0,
|
|
4594
|
-
return JSON.parse((0,
|
|
4693
|
+
if ((0, import_fs6.existsSync)(authPath)) {
|
|
4694
|
+
return JSON.parse((0, import_fs6.readFileSync)(authPath, "utf-8"));
|
|
4595
4695
|
}
|
|
4596
4696
|
} catch {
|
|
4597
4697
|
}
|
|
@@ -4658,7 +4758,8 @@ function getGitHubCopilotCredentials() {
|
|
|
4658
4758
|
if (!copilotAuth || copilotAuth.type !== "oauth") {
|
|
4659
4759
|
return null;
|
|
4660
4760
|
}
|
|
4661
|
-
const
|
|
4761
|
+
const auth = copilotAuth;
|
|
4762
|
+
const baseUrl = auth.enterpriseUrl ? `https://copilot-api.${auth.enterpriseUrl.replace(/^https?:\/\//, "").replace(/\/$/, "")}` : "https://models.github.ai";
|
|
4662
4763
|
return {
|
|
4663
4764
|
provider: "github-copilot",
|
|
4664
4765
|
baseUrl,
|
|
@@ -4754,42 +4855,12 @@ function createCustomProviderInfo(config) {
|
|
|
4754
4855
|
};
|
|
4755
4856
|
}
|
|
4756
4857
|
|
|
4757
|
-
// src/embeddings/provider.ts
|
|
4758
|
-
var
|
|
4759
|
-
constructor(message) {
|
|
4760
|
-
super(message);
|
|
4761
|
-
this.name = "CustomProviderNonRetryableError";
|
|
4762
|
-
}
|
|
4763
|
-
};
|
|
4764
|
-
function createEmbeddingProvider(configuredProviderInfo) {
|
|
4765
|
-
switch (configuredProviderInfo.provider) {
|
|
4766
|
-
case "github-copilot":
|
|
4767
|
-
return new GitHubCopilotEmbeddingProvider(configuredProviderInfo.credentials, configuredProviderInfo.modelInfo);
|
|
4768
|
-
case "openai":
|
|
4769
|
-
return new OpenAIEmbeddingProvider(configuredProviderInfo.credentials, configuredProviderInfo.modelInfo);
|
|
4770
|
-
case "google":
|
|
4771
|
-
return new GoogleEmbeddingProvider(configuredProviderInfo.credentials, configuredProviderInfo.modelInfo);
|
|
4772
|
-
case "ollama":
|
|
4773
|
-
return new OllamaEmbeddingProvider(configuredProviderInfo.credentials, configuredProviderInfo.modelInfo);
|
|
4774
|
-
case "custom":
|
|
4775
|
-
return new CustomEmbeddingProvider(configuredProviderInfo.credentials, configuredProviderInfo.modelInfo);
|
|
4776
|
-
default: {
|
|
4777
|
-
const _exhaustive = configuredProviderInfo;
|
|
4778
|
-
throw new Error(`Unsupported embedding provider: ${_exhaustive.provider}`);
|
|
4779
|
-
}
|
|
4780
|
-
}
|
|
4781
|
-
}
|
|
4782
|
-
var GitHubCopilotEmbeddingProvider = class {
|
|
4858
|
+
// src/embeddings/provider-types.ts
|
|
4859
|
+
var BaseEmbeddingProvider = class {
|
|
4783
4860
|
constructor(credentials, modelInfo) {
|
|
4784
4861
|
this.credentials = credentials;
|
|
4785
4862
|
this.modelInfo = modelInfo;
|
|
4786
4863
|
}
|
|
4787
|
-
getToken() {
|
|
4788
|
-
if (!this.credentials.refreshToken) {
|
|
4789
|
-
throw new Error("No OAuth token available for GitHub");
|
|
4790
|
-
}
|
|
4791
|
-
return this.credentials.refreshToken;
|
|
4792
|
-
}
|
|
4793
4864
|
async embedQuery(query) {
|
|
4794
4865
|
const result = await this.embedBatch([query]);
|
|
4795
4866
|
return {
|
|
@@ -4804,69 +4875,204 @@ var GitHubCopilotEmbeddingProvider = class {
|
|
|
4804
4875
|
tokensUsed: result.totalTokensUsed
|
|
4805
4876
|
};
|
|
4806
4877
|
}
|
|
4807
|
-
async embedBatch(texts) {
|
|
4808
|
-
const token = this.getToken();
|
|
4809
|
-
const response = await fetch(`${this.credentials.baseUrl}/inference/embeddings`, {
|
|
4810
|
-
method: "POST",
|
|
4811
|
-
headers: {
|
|
4812
|
-
Authorization: `Bearer ${token}`,
|
|
4813
|
-
"Content-Type": "application/json",
|
|
4814
|
-
Accept: "application/vnd.github+json",
|
|
4815
|
-
"X-GitHub-Api-Version": "2022-11-28"
|
|
4816
|
-
},
|
|
4817
|
-
body: JSON.stringify({
|
|
4818
|
-
model: `openai/${this.modelInfo.model}`,
|
|
4819
|
-
input: texts
|
|
4820
|
-
})
|
|
4821
|
-
});
|
|
4822
|
-
if (!response.ok) {
|
|
4823
|
-
const error = await response.text();
|
|
4824
|
-
throw new Error(`GitHub Copilot embedding API error: ${response.status} - ${error}`);
|
|
4825
|
-
}
|
|
4826
|
-
const data = await response.json();
|
|
4827
|
-
return {
|
|
4828
|
-
embeddings: data.data.map((d) => d.embedding),
|
|
4829
|
-
totalTokensUsed: data.usage.total_tokens
|
|
4830
|
-
};
|
|
4831
|
-
}
|
|
4832
4878
|
getModelInfo() {
|
|
4833
4879
|
return this.modelInfo;
|
|
4834
4880
|
}
|
|
4835
4881
|
};
|
|
4836
|
-
var
|
|
4882
|
+
var CustomProviderNonRetryableError = class extends Error {
|
|
4883
|
+
constructor(message) {
|
|
4884
|
+
super(message);
|
|
4885
|
+
this.name = "CustomProviderNonRetryableError";
|
|
4886
|
+
}
|
|
4887
|
+
};
|
|
4888
|
+
|
|
4889
|
+
// src/utils/url-validation.ts
|
|
4890
|
+
var BLOCKED_METADATA_IPS = [
|
|
4891
|
+
/^169\.254\.169\.254$/,
|
|
4892
|
+
// AWS/Azure/GCP metadata
|
|
4893
|
+
/^169\.254\.170\.2$/,
|
|
4894
|
+
// AWS ECS task metadata
|
|
4895
|
+
/^fd00:ec2::254$/
|
|
4896
|
+
// AWS IMDSv2 IPv6
|
|
4897
|
+
];
|
|
4898
|
+
var BLOCKED_HOSTNAMES = /* @__PURE__ */ new Set([
|
|
4899
|
+
"metadata.google.internal",
|
|
4900
|
+
"metadata.google",
|
|
4901
|
+
"metadata.goog",
|
|
4902
|
+
"kubernetes.default.svc"
|
|
4903
|
+
]);
|
|
4904
|
+
function validateExternalUrl(urlString) {
|
|
4905
|
+
let parsed;
|
|
4906
|
+
try {
|
|
4907
|
+
parsed = new URL(urlString);
|
|
4908
|
+
} catch {
|
|
4909
|
+
return { valid: false, reason: `Invalid URL: ${sanitizeUrlForError(urlString)}` };
|
|
4910
|
+
}
|
|
4911
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
4912
|
+
return { valid: false, reason: `Blocked protocol: ${parsed.protocol}` };
|
|
4913
|
+
}
|
|
4914
|
+
const hostname = parsed.hostname.toLowerCase();
|
|
4915
|
+
if (BLOCKED_HOSTNAMES.has(hostname)) {
|
|
4916
|
+
return { valid: false, reason: `Blocked: cloud metadata service (${hostname})` };
|
|
4917
|
+
}
|
|
4918
|
+
for (const pattern of BLOCKED_METADATA_IPS) {
|
|
4919
|
+
if (pattern.test(hostname)) {
|
|
4920
|
+
return { valid: false, reason: `Blocked: cloud metadata IP (${hostname})` };
|
|
4921
|
+
}
|
|
4922
|
+
}
|
|
4923
|
+
if (/^169\.254\./.test(hostname)) {
|
|
4924
|
+
return { valid: false, reason: `Blocked: link-local address (${hostname})` };
|
|
4925
|
+
}
|
|
4926
|
+
return { valid: true };
|
|
4927
|
+
}
|
|
4928
|
+
function sanitizeUrlForError(url) {
|
|
4929
|
+
try {
|
|
4930
|
+
const parsed = new URL(url);
|
|
4931
|
+
parsed.username = "";
|
|
4932
|
+
parsed.password = "";
|
|
4933
|
+
return parsed.toString();
|
|
4934
|
+
} catch {
|
|
4935
|
+
const maxLen = 80;
|
|
4936
|
+
if (url.length > maxLen) {
|
|
4937
|
+
return url.slice(0, maxLen) + "...";
|
|
4938
|
+
}
|
|
4939
|
+
return url;
|
|
4940
|
+
}
|
|
4941
|
+
}
|
|
4942
|
+
|
|
4943
|
+
// src/embeddings/providers/custom.ts
|
|
4944
|
+
var CustomEmbeddingProvider = class extends BaseEmbeddingProvider {
|
|
4837
4945
|
constructor(credentials, modelInfo) {
|
|
4838
|
-
|
|
4839
|
-
this.modelInfo = modelInfo;
|
|
4946
|
+
super(credentials, modelInfo);
|
|
4840
4947
|
}
|
|
4841
|
-
|
|
4842
|
-
const
|
|
4843
|
-
|
|
4844
|
-
|
|
4845
|
-
|
|
4948
|
+
splitIntoRequestBatches(texts) {
|
|
4949
|
+
const maxBatchSize = this.modelInfo.maxBatchSize;
|
|
4950
|
+
if (!maxBatchSize || texts.length <= maxBatchSize) {
|
|
4951
|
+
return [texts];
|
|
4952
|
+
}
|
|
4953
|
+
const batches = [];
|
|
4954
|
+
for (let i = 0; i < texts.length; i += maxBatchSize) {
|
|
4955
|
+
batches.push(texts.slice(i, i + maxBatchSize));
|
|
4956
|
+
}
|
|
4957
|
+
return batches;
|
|
4958
|
+
}
|
|
4959
|
+
async embedRequest(texts) {
|
|
4960
|
+
if (texts.length === 0) {
|
|
4961
|
+
return {
|
|
4962
|
+
embeddings: [],
|
|
4963
|
+
totalTokensUsed: 0
|
|
4964
|
+
};
|
|
4965
|
+
}
|
|
4966
|
+
const headers = {
|
|
4967
|
+
"Content-Type": "application/json"
|
|
4846
4968
|
};
|
|
4969
|
+
if (this.credentials.apiKey) {
|
|
4970
|
+
headers.Authorization = `Bearer ${this.credentials.apiKey}`;
|
|
4971
|
+
}
|
|
4972
|
+
const baseUrl = this.credentials.baseUrl ?? "";
|
|
4973
|
+
const fullUrl = `${baseUrl}/embeddings`;
|
|
4974
|
+
const urlCheck = validateExternalUrl(fullUrl);
|
|
4975
|
+
if (!urlCheck.valid) {
|
|
4976
|
+
throw new CustomProviderNonRetryableError(
|
|
4977
|
+
`Custom embedding provider URL blocked (SSRF protection): ${urlCheck.reason}`
|
|
4978
|
+
);
|
|
4979
|
+
}
|
|
4980
|
+
const timeoutMs = this.modelInfo.timeoutMs;
|
|
4981
|
+
const controller = new AbortController();
|
|
4982
|
+
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
4983
|
+
let response;
|
|
4984
|
+
try {
|
|
4985
|
+
response = await fetch(fullUrl, {
|
|
4986
|
+
method: "POST",
|
|
4987
|
+
headers,
|
|
4988
|
+
body: JSON.stringify({
|
|
4989
|
+
model: this.modelInfo.model,
|
|
4990
|
+
input: texts
|
|
4991
|
+
}),
|
|
4992
|
+
signal: controller.signal
|
|
4993
|
+
});
|
|
4994
|
+
} catch (error) {
|
|
4995
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
4996
|
+
throw new Error(`Custom embedding API request timed out after ${timeoutMs}ms for ${sanitizeUrlForError(fullUrl)}`);
|
|
4997
|
+
}
|
|
4998
|
+
throw error;
|
|
4999
|
+
} finally {
|
|
5000
|
+
clearTimeout(timeout);
|
|
5001
|
+
}
|
|
5002
|
+
if (!response.ok) {
|
|
5003
|
+
const errorText = (await response.text()).slice(0, 500);
|
|
5004
|
+
if (response.status >= 400 && response.status < 500 && response.status !== 429) {
|
|
5005
|
+
throw new CustomProviderNonRetryableError(`Custom embedding API error (non-retryable): ${response.status} - ${errorText}`);
|
|
5006
|
+
}
|
|
5007
|
+
throw new Error(`Custom embedding API error: ${response.status} - ${errorText}`);
|
|
5008
|
+
}
|
|
5009
|
+
const data = await response.json();
|
|
5010
|
+
if (data.data && Array.isArray(data.data)) {
|
|
5011
|
+
if (data.data.length > 0) {
|
|
5012
|
+
const actualDims = data.data[0].embedding.length;
|
|
5013
|
+
if (actualDims !== this.modelInfo.dimensions) {
|
|
5014
|
+
throw new Error(
|
|
5015
|
+
`Dimension mismatch: customProvider.dimensions is ${this.modelInfo.dimensions}, but the API returned vectors with ${actualDims} dimensions. Update your config to match the model's actual output dimensions.`
|
|
5016
|
+
);
|
|
5017
|
+
}
|
|
5018
|
+
}
|
|
5019
|
+
if (data.data.length !== texts.length) {
|
|
5020
|
+
throw new Error(
|
|
5021
|
+
`Embedding count mismatch: sent ${texts.length} texts but received ${data.data.length} embeddings. The custom embedding server may not support batch input.`
|
|
5022
|
+
);
|
|
5023
|
+
}
|
|
5024
|
+
return {
|
|
5025
|
+
embeddings: data.data.map((d) => d.embedding),
|
|
5026
|
+
totalTokensUsed: data.usage?.total_tokens ?? texts.reduce((sum, t) => sum + Math.ceil(t.length / 4), 0)
|
|
5027
|
+
};
|
|
5028
|
+
}
|
|
5029
|
+
throw new Error("Custom embedding API returned unexpected response format. Expected OpenAI-compatible format with data[].embedding.");
|
|
4847
5030
|
}
|
|
4848
|
-
async
|
|
4849
|
-
const
|
|
5031
|
+
async embedBatch(texts) {
|
|
5032
|
+
const requestBatches = this.splitIntoRequestBatches(texts);
|
|
5033
|
+
const embeddings = [];
|
|
5034
|
+
let totalTokensUsed = 0;
|
|
5035
|
+
for (const batch of requestBatches) {
|
|
5036
|
+
const result = await this.embedRequest(batch);
|
|
5037
|
+
embeddings.push(...result.embeddings);
|
|
5038
|
+
totalTokensUsed += result.totalTokensUsed;
|
|
5039
|
+
}
|
|
4850
5040
|
return {
|
|
4851
|
-
|
|
4852
|
-
|
|
5041
|
+
embeddings,
|
|
5042
|
+
totalTokensUsed
|
|
4853
5043
|
};
|
|
4854
5044
|
}
|
|
5045
|
+
};
|
|
5046
|
+
|
|
5047
|
+
// src/embeddings/providers/github-copilot.ts
|
|
5048
|
+
var GitHubCopilotEmbeddingProvider = class extends BaseEmbeddingProvider {
|
|
5049
|
+
constructor(credentials, modelInfo) {
|
|
5050
|
+
super(credentials, modelInfo);
|
|
5051
|
+
}
|
|
5052
|
+
getToken() {
|
|
5053
|
+
if (!this.credentials.refreshToken) {
|
|
5054
|
+
throw new Error("No OAuth token available for GitHub");
|
|
5055
|
+
}
|
|
5056
|
+
return this.credentials.refreshToken;
|
|
5057
|
+
}
|
|
4855
5058
|
async embedBatch(texts) {
|
|
4856
|
-
const
|
|
5059
|
+
const token = this.getToken();
|
|
5060
|
+
const response = await fetch(`${this.credentials.baseUrl}/inference/embeddings`, {
|
|
4857
5061
|
method: "POST",
|
|
4858
5062
|
headers: {
|
|
4859
|
-
Authorization: `Bearer ${
|
|
4860
|
-
"Content-Type": "application/json"
|
|
5063
|
+
Authorization: `Bearer ${token}`,
|
|
5064
|
+
"Content-Type": "application/json",
|
|
5065
|
+
Accept: "application/vnd.github+json",
|
|
5066
|
+
"X-GitHub-Api-Version": "2022-11-28"
|
|
4861
5067
|
},
|
|
4862
5068
|
body: JSON.stringify({
|
|
4863
|
-
model: this.modelInfo.model
|
|
5069
|
+
model: `openai/${this.modelInfo.model}`,
|
|
4864
5070
|
input: texts
|
|
4865
5071
|
})
|
|
4866
5072
|
});
|
|
4867
5073
|
if (!response.ok) {
|
|
4868
|
-
const error = await response.text();
|
|
4869
|
-
throw new Error(`
|
|
5074
|
+
const error = (await response.text()).slice(0, 500);
|
|
5075
|
+
throw new Error(`GitHub Copilot embedding API error: ${response.status} - ${error}`);
|
|
4870
5076
|
}
|
|
4871
5077
|
const data = await response.json();
|
|
4872
5078
|
return {
|
|
@@ -4874,16 +5080,14 @@ var OpenAIEmbeddingProvider = class {
|
|
|
4874
5080
|
totalTokensUsed: data.usage.total_tokens
|
|
4875
5081
|
};
|
|
4876
5082
|
}
|
|
4877
|
-
getModelInfo() {
|
|
4878
|
-
return this.modelInfo;
|
|
4879
|
-
}
|
|
4880
5083
|
};
|
|
4881
|
-
|
|
5084
|
+
|
|
5085
|
+
// src/embeddings/providers/google.ts
|
|
5086
|
+
var GoogleEmbeddingProvider = class _GoogleEmbeddingProvider extends BaseEmbeddingProvider {
|
|
5087
|
+
static BATCH_SIZE = 20;
|
|
4882
5088
|
constructor(credentials, modelInfo) {
|
|
4883
|
-
|
|
4884
|
-
this.modelInfo = modelInfo;
|
|
5089
|
+
super(credentials, modelInfo);
|
|
4885
5090
|
}
|
|
4886
|
-
static BATCH_SIZE = 20;
|
|
4887
5091
|
async embedQuery(query) {
|
|
4888
5092
|
const taskType = this.modelInfo.taskAble ? "CODE_RETRIEVAL_QUERY" : void 0;
|
|
4889
5093
|
const result = await this.embedWithTaskType([query], taskType);
|
|
@@ -4904,12 +5108,6 @@ var GoogleEmbeddingProvider = class _GoogleEmbeddingProvider {
|
|
|
4904
5108
|
const taskType = this.modelInfo.taskAble ? "RETRIEVAL_DOCUMENT" : void 0;
|
|
4905
5109
|
return this.embedWithTaskType(texts, taskType);
|
|
4906
5110
|
}
|
|
4907
|
-
/**
|
|
4908
|
-
* Embeds texts using the Google embedContent API.
|
|
4909
|
-
* Sends multiple texts as parts in batched requests (up to BATCH_SIZE per call).
|
|
4910
|
-
* When taskType is provided (gemini-embedding-001), includes it in the request
|
|
4911
|
-
* for task-specific embedding optimization.
|
|
4912
|
-
*/
|
|
4913
5111
|
async embedWithTaskType(texts, taskType) {
|
|
4914
5112
|
const batches = [];
|
|
4915
5113
|
for (let i = 0; i < texts.length; i += _GoogleEmbeddingProvider.BATCH_SIZE) {
|
|
@@ -4926,17 +5124,18 @@ var GoogleEmbeddingProvider = class _GoogleEmbeddingProvider {
|
|
|
4926
5124
|
outputDimensionality: this.modelInfo.dimensions
|
|
4927
5125
|
}));
|
|
4928
5126
|
const response = await fetch(
|
|
4929
|
-
`${this.credentials.baseUrl}/models/${this.modelInfo.model}:batchEmbedContents
|
|
5127
|
+
`${this.credentials.baseUrl}/models/${this.modelInfo.model}:batchEmbedContents`,
|
|
4930
5128
|
{
|
|
4931
5129
|
method: "POST",
|
|
4932
5130
|
headers: {
|
|
4933
|
-
"Content-Type": "application/json"
|
|
5131
|
+
"Content-Type": "application/json",
|
|
5132
|
+
...this.credentials.apiKey && { "x-goog-api-key": this.credentials.apiKey }
|
|
4934
5133
|
},
|
|
4935
5134
|
body: JSON.stringify({ requests })
|
|
4936
5135
|
}
|
|
4937
5136
|
);
|
|
4938
5137
|
if (!response.ok) {
|
|
4939
|
-
const error = await response.text();
|
|
5138
|
+
const error = (await response.text()).slice(0, 500);
|
|
4940
5139
|
throw new Error(`Google embedding API error: ${response.status} - ${error}`);
|
|
4941
5140
|
}
|
|
4942
5141
|
const data = await response.json();
|
|
@@ -4951,29 +5150,13 @@ var GoogleEmbeddingProvider = class _GoogleEmbeddingProvider {
|
|
|
4951
5150
|
totalTokensUsed: batchResults.reduce((sum, r) => sum + r.tokensUsed, 0)
|
|
4952
5151
|
};
|
|
4953
5152
|
}
|
|
4954
|
-
getModelInfo() {
|
|
4955
|
-
return this.modelInfo;
|
|
4956
|
-
}
|
|
4957
5153
|
};
|
|
4958
|
-
|
|
4959
|
-
|
|
4960
|
-
|
|
4961
|
-
this.modelInfo = modelInfo;
|
|
4962
|
-
}
|
|
5154
|
+
|
|
5155
|
+
// src/embeddings/providers/ollama.ts
|
|
5156
|
+
var OllamaEmbeddingProvider = class _OllamaEmbeddingProvider extends BaseEmbeddingProvider {
|
|
4963
5157
|
static MIN_TRUNCATION_CHARS = 512;
|
|
4964
|
-
|
|
4965
|
-
|
|
4966
|
-
return {
|
|
4967
|
-
embedding: result.embeddings[0],
|
|
4968
|
-
tokensUsed: result.totalTokensUsed
|
|
4969
|
-
};
|
|
4970
|
-
}
|
|
4971
|
-
async embedDocument(document) {
|
|
4972
|
-
const result = await this.embedBatch([document]);
|
|
4973
|
-
return {
|
|
4974
|
-
embedding: result.embeddings[0],
|
|
4975
|
-
tokensUsed: result.totalTokensUsed
|
|
4976
|
-
};
|
|
5158
|
+
constructor(credentials, modelInfo) {
|
|
5159
|
+
super(credentials, modelInfo);
|
|
4977
5160
|
}
|
|
4978
5161
|
estimateTokens(text) {
|
|
4979
5162
|
return Math.ceil(text.length / 4);
|
|
@@ -5042,161 +5225,92 @@ var OllamaEmbeddingProvider = class _OllamaEmbeddingProvider {
|
|
|
5042
5225
|
lastError = retryError;
|
|
5043
5226
|
}
|
|
5044
5227
|
}
|
|
5045
|
-
throw lastError;
|
|
5046
|
-
}
|
|
5047
|
-
}
|
|
5048
|
-
async embedSingle(text) {
|
|
5049
|
-
const response = await fetch(`${this.credentials.baseUrl}/api/embeddings`, {
|
|
5050
|
-
method: "POST",
|
|
5051
|
-
headers: {
|
|
5052
|
-
"Content-Type": "application/json"
|
|
5053
|
-
},
|
|
5054
|
-
body: JSON.stringify({
|
|
5055
|
-
model: this.modelInfo.model,
|
|
5056
|
-
prompt: text,
|
|
5057
|
-
truncate: false
|
|
5058
|
-
})
|
|
5059
|
-
});
|
|
5060
|
-
if (!response.ok) {
|
|
5061
|
-
const error = await response.text();
|
|
5062
|
-
throw new Error(`Ollama embedding API error: ${response.status} - ${error}`);
|
|
5063
|
-
}
|
|
5064
|
-
const data = await response.json();
|
|
5065
|
-
return {
|
|
5066
|
-
embedding: data.embedding,
|
|
5067
|
-
tokensUsed: this.estimateTokens(text)
|
|
5068
|
-
};
|
|
5069
|
-
}
|
|
5070
|
-
async embedBatch(texts) {
|
|
5071
|
-
const results = [];
|
|
5072
|
-
for (const text of texts) {
|
|
5073
|
-
results.push(await this.embedSingleWithFallback(text));
|
|
5074
|
-
}
|
|
5075
|
-
return {
|
|
5076
|
-
embeddings: results.map((r) => r.embedding),
|
|
5077
|
-
totalTokensUsed: results.reduce((sum, r) => sum + r.tokensUsed, 0)
|
|
5078
|
-
};
|
|
5079
|
-
}
|
|
5080
|
-
getModelInfo() {
|
|
5081
|
-
return this.modelInfo;
|
|
5082
|
-
}
|
|
5083
|
-
};
|
|
5084
|
-
var CustomEmbeddingProvider = class {
|
|
5085
|
-
constructor(credentials, modelInfo) {
|
|
5086
|
-
this.credentials = credentials;
|
|
5087
|
-
this.modelInfo = modelInfo;
|
|
5088
|
-
}
|
|
5089
|
-
splitIntoRequestBatches(texts) {
|
|
5090
|
-
const maxBatchSize = this.modelInfo.maxBatchSize;
|
|
5091
|
-
if (!maxBatchSize || texts.length <= maxBatchSize) {
|
|
5092
|
-
return [texts];
|
|
5093
|
-
}
|
|
5094
|
-
const batches = [];
|
|
5095
|
-
for (let i = 0; i < texts.length; i += maxBatchSize) {
|
|
5096
|
-
batches.push(texts.slice(i, i + maxBatchSize));
|
|
5097
|
-
}
|
|
5098
|
-
return batches;
|
|
5099
|
-
}
|
|
5100
|
-
async embedRequest(texts) {
|
|
5101
|
-
if (texts.length === 0) {
|
|
5102
|
-
return {
|
|
5103
|
-
embeddings: [],
|
|
5104
|
-
totalTokensUsed: 0
|
|
5105
|
-
};
|
|
5106
|
-
}
|
|
5107
|
-
const headers = {
|
|
5108
|
-
"Content-Type": "application/json"
|
|
5109
|
-
};
|
|
5110
|
-
if (this.credentials.apiKey) {
|
|
5111
|
-
headers["Authorization"] = `Bearer ${this.credentials.apiKey}`;
|
|
5112
|
-
}
|
|
5113
|
-
const baseUrl = this.credentials.baseUrl ?? "";
|
|
5114
|
-
const timeoutMs = this.modelInfo.timeoutMs;
|
|
5115
|
-
const controller = new AbortController();
|
|
5116
|
-
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
5117
|
-
let response;
|
|
5118
|
-
try {
|
|
5119
|
-
response = await fetch(`${baseUrl}/embeddings`, {
|
|
5120
|
-
method: "POST",
|
|
5121
|
-
headers,
|
|
5122
|
-
body: JSON.stringify({
|
|
5123
|
-
model: this.modelInfo.model,
|
|
5124
|
-
input: texts
|
|
5125
|
-
}),
|
|
5126
|
-
signal: controller.signal
|
|
5127
|
-
});
|
|
5128
|
-
} catch (error) {
|
|
5129
|
-
if (error instanceof Error && error.name === "AbortError") {
|
|
5130
|
-
throw new Error(`Custom embedding API request timed out after ${timeoutMs}ms for ${baseUrl}/embeddings`);
|
|
5131
|
-
}
|
|
5132
|
-
throw error;
|
|
5133
|
-
} finally {
|
|
5134
|
-
clearTimeout(timeout);
|
|
5135
|
-
}
|
|
5136
|
-
if (!response.ok) {
|
|
5137
|
-
const errorText = await response.text();
|
|
5138
|
-
if (response.status >= 400 && response.status < 500 && response.status !== 429) {
|
|
5139
|
-
throw new CustomProviderNonRetryableError(`Custom embedding API error (non-retryable): ${response.status} - ${errorText}`);
|
|
5140
|
-
}
|
|
5141
|
-
throw new Error(`Custom embedding API error: ${response.status} - ${errorText}`);
|
|
5142
|
-
}
|
|
5143
|
-
const data = await response.json();
|
|
5144
|
-
if (data.data && Array.isArray(data.data)) {
|
|
5145
|
-
if (data.data.length > 0) {
|
|
5146
|
-
const actualDims = data.data[0].embedding.length;
|
|
5147
|
-
if (actualDims !== this.modelInfo.dimensions) {
|
|
5148
|
-
throw new Error(
|
|
5149
|
-
`Dimension mismatch: customProvider.dimensions is ${this.modelInfo.dimensions}, but the API returned vectors with ${actualDims} dimensions. Update your config to match the model's actual output dimensions.`
|
|
5150
|
-
);
|
|
5151
|
-
}
|
|
5152
|
-
}
|
|
5153
|
-
if (data.data.length !== texts.length) {
|
|
5154
|
-
throw new Error(
|
|
5155
|
-
`Embedding count mismatch: sent ${texts.length} texts but received ${data.data.length} embeddings. The custom embedding server may not support batch input.`
|
|
5156
|
-
);
|
|
5157
|
-
}
|
|
5158
|
-
return {
|
|
5159
|
-
embeddings: data.data.map((d) => d.embedding),
|
|
5160
|
-
// Rough estimate: ~4 chars per token. Used as fallback when the server
|
|
5161
|
-
// doesn't return usage.total_tokens (e.g. llama.cpp, some vLLM configs).
|
|
5162
|
-
totalTokensUsed: data.usage?.total_tokens ?? texts.reduce((sum, t) => sum + Math.ceil(t.length / 4), 0)
|
|
5163
|
-
};
|
|
5228
|
+
throw lastError;
|
|
5164
5229
|
}
|
|
5165
|
-
throw new Error("Custom embedding API returned unexpected response format. Expected OpenAI-compatible format with data[].embedding.");
|
|
5166
5230
|
}
|
|
5167
|
-
async
|
|
5168
|
-
const
|
|
5231
|
+
async embedSingle(text) {
|
|
5232
|
+
const response = await fetch(`${this.credentials.baseUrl}/api/embeddings`, {
|
|
5233
|
+
method: "POST",
|
|
5234
|
+
headers: {
|
|
5235
|
+
"Content-Type": "application/json"
|
|
5236
|
+
},
|
|
5237
|
+
body: JSON.stringify({
|
|
5238
|
+
model: this.modelInfo.model,
|
|
5239
|
+
prompt: text,
|
|
5240
|
+
truncate: false
|
|
5241
|
+
})
|
|
5242
|
+
});
|
|
5243
|
+
if (!response.ok) {
|
|
5244
|
+
const error = (await response.text()).slice(0, 500);
|
|
5245
|
+
throw new Error(`Ollama embedding API error: ${response.status} - ${error}`);
|
|
5246
|
+
}
|
|
5247
|
+
const data = await response.json();
|
|
5169
5248
|
return {
|
|
5170
|
-
embedding:
|
|
5171
|
-
tokensUsed:
|
|
5249
|
+
embedding: data.embedding,
|
|
5250
|
+
tokensUsed: this.estimateTokens(text)
|
|
5172
5251
|
};
|
|
5173
5252
|
}
|
|
5174
|
-
async
|
|
5175
|
-
const
|
|
5253
|
+
async embedBatch(texts) {
|
|
5254
|
+
const results = [];
|
|
5255
|
+
for (const text of texts) {
|
|
5256
|
+
results.push(await this.embedSingleWithFallback(text));
|
|
5257
|
+
}
|
|
5176
5258
|
return {
|
|
5177
|
-
|
|
5178
|
-
|
|
5259
|
+
embeddings: results.map((r) => r.embedding),
|
|
5260
|
+
totalTokensUsed: results.reduce((sum, r) => sum + r.tokensUsed, 0)
|
|
5179
5261
|
};
|
|
5180
5262
|
}
|
|
5263
|
+
};
|
|
5264
|
+
|
|
5265
|
+
// src/embeddings/providers/openai.ts
|
|
5266
|
+
var OpenAIEmbeddingProvider = class extends BaseEmbeddingProvider {
|
|
5267
|
+
constructor(credentials, modelInfo) {
|
|
5268
|
+
super(credentials, modelInfo);
|
|
5269
|
+
}
|
|
5181
5270
|
async embedBatch(texts) {
|
|
5182
|
-
const
|
|
5183
|
-
|
|
5184
|
-
|
|
5185
|
-
|
|
5186
|
-
|
|
5187
|
-
|
|
5188
|
-
|
|
5271
|
+
const response = await fetch(`${this.credentials.baseUrl}/embeddings`, {
|
|
5272
|
+
method: "POST",
|
|
5273
|
+
headers: {
|
|
5274
|
+
Authorization: `Bearer ${this.credentials.apiKey}`,
|
|
5275
|
+
"Content-Type": "application/json"
|
|
5276
|
+
},
|
|
5277
|
+
body: JSON.stringify({
|
|
5278
|
+
model: this.modelInfo.model,
|
|
5279
|
+
input: texts
|
|
5280
|
+
})
|
|
5281
|
+
});
|
|
5282
|
+
if (!response.ok) {
|
|
5283
|
+
const error = (await response.text()).slice(0, 500);
|
|
5284
|
+
throw new Error(`OpenAI embedding API error: ${response.status} - ${error}`);
|
|
5189
5285
|
}
|
|
5286
|
+
const data = await response.json();
|
|
5190
5287
|
return {
|
|
5191
|
-
embeddings,
|
|
5192
|
-
totalTokensUsed
|
|
5288
|
+
embeddings: data.data.map((d) => d.embedding),
|
|
5289
|
+
totalTokensUsed: data.usage.total_tokens
|
|
5193
5290
|
};
|
|
5194
5291
|
}
|
|
5195
|
-
getModelInfo() {
|
|
5196
|
-
return this.modelInfo;
|
|
5197
|
-
}
|
|
5198
5292
|
};
|
|
5199
5293
|
|
|
5294
|
+
// src/embeddings/provider.ts
|
|
5295
|
+
function createEmbeddingProvider(configuredProviderInfo) {
|
|
5296
|
+
switch (configuredProviderInfo.provider) {
|
|
5297
|
+
case "github-copilot":
|
|
5298
|
+
return new GitHubCopilotEmbeddingProvider(configuredProviderInfo.credentials, configuredProviderInfo.modelInfo);
|
|
5299
|
+
case "openai":
|
|
5300
|
+
return new OpenAIEmbeddingProvider(configuredProviderInfo.credentials, configuredProviderInfo.modelInfo);
|
|
5301
|
+
case "google":
|
|
5302
|
+
return new GoogleEmbeddingProvider(configuredProviderInfo.credentials, configuredProviderInfo.modelInfo);
|
|
5303
|
+
case "ollama":
|
|
5304
|
+
return new OllamaEmbeddingProvider(configuredProviderInfo.credentials, configuredProviderInfo.modelInfo);
|
|
5305
|
+
case "custom":
|
|
5306
|
+
return new CustomEmbeddingProvider(configuredProviderInfo.credentials, configuredProviderInfo.modelInfo);
|
|
5307
|
+
default: {
|
|
5308
|
+
const _exhaustive = configuredProviderInfo;
|
|
5309
|
+
throw new Error(`Unsupported embedding provider: ${_exhaustive.provider}`);
|
|
5310
|
+
}
|
|
5311
|
+
}
|
|
5312
|
+
}
|
|
5313
|
+
|
|
5200
5314
|
// src/rerank/index.ts
|
|
5201
5315
|
function createReranker(config) {
|
|
5202
5316
|
if (!config.enabled) {
|
|
@@ -5232,7 +5346,10 @@ var SiliconFlowReranker = class {
|
|
|
5232
5346
|
if (this.config.apiKey) {
|
|
5233
5347
|
headers["Authorization"] = `Bearer ${this.config.apiKey}`;
|
|
5234
5348
|
}
|
|
5235
|
-
const baseUrl = this.config.baseUrl
|
|
5349
|
+
const baseUrl = this.config.baseUrl;
|
|
5350
|
+
if (!baseUrl) {
|
|
5351
|
+
throw new Error("Reranker baseUrl is required. Configure reranker.baseUrl in your codebase-index.json.");
|
|
5352
|
+
}
|
|
5236
5353
|
const timeoutMs = this.config.timeoutMs ?? 3e4;
|
|
5237
5354
|
const controller = new AbortController();
|
|
5238
5355
|
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
@@ -5306,20 +5423,21 @@ function createCostEstimate(files, provider) {
|
|
|
5306
5423
|
}
|
|
5307
5424
|
function formatCostEstimate(estimate) {
|
|
5308
5425
|
const sizeFormatted = formatBytes(estimate.totalSizeBytes);
|
|
5426
|
+
const filesFormatted = `${estimate.filesCount.toLocaleString()} files`;
|
|
5309
5427
|
const costFormatted = estimate.isFree ? "Free" : `~$${estimate.estimatedCost.toFixed(4)}`;
|
|
5310
5428
|
return `
|
|
5311
5429
|
\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510
|
|
5312
5430
|
\u2502 \u{1F4CA} Indexing Estimate \u2502
|
|
5313
5431
|
\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524
|
|
5314
5432
|
\u2502 \u2502
|
|
5315
|
-
\u2502 Files to index: ${
|
|
5316
|
-
\u2502 Total size: ${
|
|
5317
|
-
\u2502 Estimated chunks: ${
|
|
5318
|
-
\u2502 Estimated tokens: ${
|
|
5433
|
+
\u2502 Files to index: ${filesFormatted.padEnd(40)}\u2502
|
|
5434
|
+
\u2502 Total size: ${sizeFormatted.padEnd(40)}\u2502
|
|
5435
|
+
\u2502 Estimated chunks: ${("~" + estimate.estimatedChunks.toLocaleString() + " chunks").padEnd(40)}\u2502
|
|
5436
|
+
\u2502 Estimated tokens: ${("~" + estimate.estimatedTokens.toLocaleString() + " tokens").padEnd(40)}\u2502
|
|
5319
5437
|
\u2502 \u2502
|
|
5320
|
-
\u2502 Provider: ${
|
|
5321
|
-
\u2502 Model: ${
|
|
5322
|
-
\u2502 Cost: ${
|
|
5438
|
+
\u2502 Provider: ${estimate.provider.padEnd(52)}\u2502
|
|
5439
|
+
\u2502 Model: ${estimate.model.padEnd(52)}\u2502
|
|
5440
|
+
\u2502 Cost: ${costFormatted.padEnd(52)}\u2502
|
|
5323
5441
|
\u2502 \u2502
|
|
5324
5442
|
\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518
|
|
5325
5443
|
`;
|
|
@@ -5331,9 +5449,6 @@ function formatBytes(bytes) {
|
|
|
5331
5449
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
5332
5450
|
return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + " " + sizes[i];
|
|
5333
5451
|
}
|
|
5334
|
-
function padRight(str, length) {
|
|
5335
|
-
return str.padEnd(length);
|
|
5336
|
-
}
|
|
5337
5452
|
|
|
5338
5453
|
// src/utils/logger.ts
|
|
5339
5454
|
var LOG_LEVEL_PRIORITY = {
|
|
@@ -5400,6 +5515,10 @@ var Logger = class {
|
|
|
5400
5515
|
this.logs.shift();
|
|
5401
5516
|
}
|
|
5402
5517
|
}
|
|
5518
|
+
withMetrics(fn) {
|
|
5519
|
+
if (!this.config.metrics) return;
|
|
5520
|
+
fn();
|
|
5521
|
+
}
|
|
5403
5522
|
search(level, message, data) {
|
|
5404
5523
|
if (this.config.logSearch) {
|
|
5405
5524
|
this.log(level, "search", message, data);
|
|
@@ -5438,89 +5557,107 @@ var Logger = class {
|
|
|
5438
5557
|
this.log("debug", "general", message, data);
|
|
5439
5558
|
}
|
|
5440
5559
|
recordIndexingStart() {
|
|
5441
|
-
|
|
5442
|
-
|
|
5560
|
+
this.withMetrics(() => {
|
|
5561
|
+
this.metrics.indexingStartTime = Date.now();
|
|
5562
|
+
});
|
|
5443
5563
|
}
|
|
5444
5564
|
recordIndexingEnd() {
|
|
5445
|
-
|
|
5446
|
-
|
|
5565
|
+
this.withMetrics(() => {
|
|
5566
|
+
this.metrics.indexingEndTime = Date.now();
|
|
5567
|
+
});
|
|
5447
5568
|
}
|
|
5448
5569
|
recordFilesScanned(count) {
|
|
5449
|
-
|
|
5450
|
-
|
|
5570
|
+
this.withMetrics(() => {
|
|
5571
|
+
this.metrics.filesScanned = count;
|
|
5572
|
+
});
|
|
5451
5573
|
}
|
|
5452
5574
|
recordFilesParsed(count) {
|
|
5453
|
-
|
|
5454
|
-
|
|
5575
|
+
this.withMetrics(() => {
|
|
5576
|
+
this.metrics.filesParsed = count;
|
|
5577
|
+
});
|
|
5455
5578
|
}
|
|
5456
5579
|
recordParseDuration(durationMs) {
|
|
5457
|
-
|
|
5458
|
-
|
|
5580
|
+
this.withMetrics(() => {
|
|
5581
|
+
this.metrics.parseMs = durationMs;
|
|
5582
|
+
});
|
|
5459
5583
|
}
|
|
5460
5584
|
recordChunksProcessed(count) {
|
|
5461
|
-
|
|
5462
|
-
|
|
5585
|
+
this.withMetrics(() => {
|
|
5586
|
+
this.metrics.chunksProcessed += count;
|
|
5587
|
+
});
|
|
5463
5588
|
}
|
|
5464
5589
|
recordChunksEmbedded(count) {
|
|
5465
|
-
|
|
5466
|
-
|
|
5590
|
+
this.withMetrics(() => {
|
|
5591
|
+
this.metrics.chunksEmbedded += count;
|
|
5592
|
+
});
|
|
5467
5593
|
}
|
|
5468
5594
|
recordChunksFromCache(count) {
|
|
5469
|
-
|
|
5470
|
-
|
|
5595
|
+
this.withMetrics(() => {
|
|
5596
|
+
this.metrics.chunksFromCache += count;
|
|
5597
|
+
});
|
|
5471
5598
|
}
|
|
5472
5599
|
recordChunksRemoved(count) {
|
|
5473
|
-
|
|
5474
|
-
|
|
5600
|
+
this.withMetrics(() => {
|
|
5601
|
+
this.metrics.chunksRemoved += count;
|
|
5602
|
+
});
|
|
5475
5603
|
}
|
|
5476
5604
|
recordEmbeddingApiCall(tokens) {
|
|
5477
|
-
|
|
5478
|
-
|
|
5479
|
-
|
|
5605
|
+
this.withMetrics(() => {
|
|
5606
|
+
this.metrics.embeddingApiCalls++;
|
|
5607
|
+
this.metrics.embeddingTokensUsed += tokens;
|
|
5608
|
+
});
|
|
5480
5609
|
}
|
|
5481
5610
|
recordEmbeddingError() {
|
|
5482
|
-
|
|
5483
|
-
|
|
5611
|
+
this.withMetrics(() => {
|
|
5612
|
+
this.metrics.embeddingErrors++;
|
|
5613
|
+
});
|
|
5484
5614
|
}
|
|
5485
5615
|
recordSearch(durationMs, breakdown) {
|
|
5486
|
-
|
|
5487
|
-
|
|
5488
|
-
|
|
5489
|
-
|
|
5490
|
-
|
|
5491
|
-
|
|
5492
|
-
|
|
5493
|
-
|
|
5494
|
-
|
|
5495
|
-
|
|
5496
|
-
|
|
5616
|
+
this.withMetrics(() => {
|
|
5617
|
+
this.metrics.searchCount++;
|
|
5618
|
+
this.metrics.searchTotalMs += durationMs;
|
|
5619
|
+
this.metrics.searchLastMs = durationMs;
|
|
5620
|
+
this.metrics.searchAvgMs = this.metrics.searchTotalMs / this.metrics.searchCount;
|
|
5621
|
+
if (breakdown) {
|
|
5622
|
+
this.metrics.embeddingCallMs = breakdown.embeddingMs;
|
|
5623
|
+
this.metrics.vectorSearchMs = breakdown.vectorMs;
|
|
5624
|
+
this.metrics.keywordSearchMs = breakdown.keywordMs;
|
|
5625
|
+
this.metrics.fusionMs = breakdown.fusionMs;
|
|
5626
|
+
}
|
|
5627
|
+
});
|
|
5497
5628
|
}
|
|
5498
5629
|
recordCacheHit() {
|
|
5499
|
-
|
|
5500
|
-
|
|
5630
|
+
this.withMetrics(() => {
|
|
5631
|
+
this.metrics.cacheHits++;
|
|
5632
|
+
});
|
|
5501
5633
|
}
|
|
5502
5634
|
recordCacheMiss() {
|
|
5503
|
-
|
|
5504
|
-
|
|
5635
|
+
this.withMetrics(() => {
|
|
5636
|
+
this.metrics.cacheMisses++;
|
|
5637
|
+
});
|
|
5505
5638
|
}
|
|
5506
5639
|
recordQueryCacheHit() {
|
|
5507
|
-
|
|
5508
|
-
|
|
5640
|
+
this.withMetrics(() => {
|
|
5641
|
+
this.metrics.queryCacheHits++;
|
|
5642
|
+
});
|
|
5509
5643
|
}
|
|
5510
5644
|
recordQueryCacheSimilarHit() {
|
|
5511
|
-
|
|
5512
|
-
|
|
5645
|
+
this.withMetrics(() => {
|
|
5646
|
+
this.metrics.queryCacheSimilarHits++;
|
|
5647
|
+
});
|
|
5513
5648
|
}
|
|
5514
5649
|
recordQueryCacheMiss() {
|
|
5515
|
-
|
|
5516
|
-
|
|
5650
|
+
this.withMetrics(() => {
|
|
5651
|
+
this.metrics.queryCacheMisses++;
|
|
5652
|
+
});
|
|
5517
5653
|
}
|
|
5518
5654
|
recordGc(orphans, chunks, embeddings) {
|
|
5519
|
-
|
|
5520
|
-
|
|
5521
|
-
|
|
5522
|
-
|
|
5523
|
-
|
|
5655
|
+
this.withMetrics(() => {
|
|
5656
|
+
this.metrics.gcRuns++;
|
|
5657
|
+
this.metrics.gcOrphansRemoved += orphans;
|
|
5658
|
+
this.metrics.gcChunksRemoved += chunks;
|
|
5659
|
+
this.metrics.gcEmbeddingsRemoved += embeddings;
|
|
5660
|
+
});
|
|
5524
5661
|
}
|
|
5525
5662
|
getMetrics() {
|
|
5526
5663
|
return { ...this.metrics };
|
|
@@ -5627,7 +5764,7 @@ function initializeLogger(config) {
|
|
|
5627
5764
|
}
|
|
5628
5765
|
|
|
5629
5766
|
// src/native/index.ts
|
|
5630
|
-
var
|
|
5767
|
+
var path11 = __toESM(require("path"), 1);
|
|
5631
5768
|
var os4 = __toESM(require("os"), 1);
|
|
5632
5769
|
var module2 = __toESM(require("module"), 1);
|
|
5633
5770
|
var import_url = require("url");
|
|
@@ -5652,19 +5789,19 @@ function getNativeBinding() {
|
|
|
5652
5789
|
let currentDir;
|
|
5653
5790
|
let requireTarget;
|
|
5654
5791
|
if (typeof import_meta !== "undefined" && import_meta.url) {
|
|
5655
|
-
currentDir =
|
|
5792
|
+
currentDir = path11.dirname((0, import_url.fileURLToPath)(import_meta.url));
|
|
5656
5793
|
requireTarget = import_meta.url;
|
|
5657
5794
|
} else if (typeof __dirname !== "undefined") {
|
|
5658
5795
|
currentDir = __dirname;
|
|
5659
5796
|
requireTarget = __filename;
|
|
5660
5797
|
} else {
|
|
5661
5798
|
currentDir = process.cwd();
|
|
5662
|
-
requireTarget =
|
|
5799
|
+
requireTarget = path11.join(currentDir, "index.js");
|
|
5663
5800
|
}
|
|
5664
5801
|
const normalizedDir = currentDir.replace(/\\/g, "/");
|
|
5665
|
-
const isDevMode = normalizedDir.includes("/src/native") || currentDir.includes(
|
|
5666
|
-
const packageRoot = isDevMode ?
|
|
5667
|
-
const nativePath =
|
|
5802
|
+
const isDevMode = normalizedDir.includes("/src/native") || currentDir.includes(path11.join("src", "native"));
|
|
5803
|
+
const packageRoot = isDevMode ? path11.resolve(currentDir, "../..") : path11.resolve(currentDir, "..");
|
|
5804
|
+
const nativePath = path11.join(packageRoot, "native", bindingName);
|
|
5668
5805
|
const require2 = module2.createRequire(requireTarget);
|
|
5669
5806
|
return require2(nativePath);
|
|
5670
5807
|
}
|
|
@@ -6234,7 +6371,6 @@ var Database = class {
|
|
|
6234
6371
|
this.throwIfClosed();
|
|
6235
6372
|
return this.inner.getStats();
|
|
6236
6373
|
}
|
|
6237
|
-
// ── Symbol methods ──────────────────────────────────────────────
|
|
6238
6374
|
upsertSymbol(symbol) {
|
|
6239
6375
|
this.throwIfClosed();
|
|
6240
6376
|
this.inner.upsertSymbol(symbol);
|
|
@@ -6264,7 +6400,6 @@ var Database = class {
|
|
|
6264
6400
|
this.throwIfClosed();
|
|
6265
6401
|
return this.inner.deleteSymbolsByFile(filePath);
|
|
6266
6402
|
}
|
|
6267
|
-
// ── Call Edge methods ────────────────────────────────────────────
|
|
6268
6403
|
upsertCallEdge(edge) {
|
|
6269
6404
|
this.throwIfClosed();
|
|
6270
6405
|
this.inner.upsertCallEdge(edge);
|
|
@@ -6294,7 +6429,6 @@ var Database = class {
|
|
|
6294
6429
|
this.throwIfClosed();
|
|
6295
6430
|
this.inner.resolveCallEdge(edgeId, toSymbolId);
|
|
6296
6431
|
}
|
|
6297
|
-
// ── Branch Symbol methods ────────────────────────────────────────
|
|
6298
6432
|
addSymbolsToBranch(branch, symbolIds) {
|
|
6299
6433
|
this.throwIfClosed();
|
|
6300
6434
|
this.inner.addSymbolsToBranch(branch, symbolIds);
|
|
@@ -6327,7 +6461,6 @@ var Database = class {
|
|
|
6327
6461
|
if (symbolIds.length === 0) return 0;
|
|
6328
6462
|
return this.inner.deleteBranchSymbolsForBranch(branch, symbolIds);
|
|
6329
6463
|
}
|
|
6330
|
-
// ── GC methods for symbols/edges ─────────────────────────────────
|
|
6331
6464
|
gcOrphanSymbols() {
|
|
6332
6465
|
this.throwIfClosed();
|
|
6333
6466
|
return this.inner.gcOrphanSymbols();
|
|
@@ -6339,7 +6472,7 @@ var Database = class {
|
|
|
6339
6472
|
};
|
|
6340
6473
|
|
|
6341
6474
|
// src/indexer/index.ts
|
|
6342
|
-
var CALL_GRAPH_LANGUAGES = /* @__PURE__ */ new Set(["typescript", "tsx", "javascript", "jsx", "python", "go", "rust", "php", "apex", "zig"]);
|
|
6475
|
+
var CALL_GRAPH_LANGUAGES = /* @__PURE__ */ new Set(["typescript", "tsx", "javascript", "jsx", "python", "go", "rust", "php", "apex", "zig", "gdscript", "matlab"]);
|
|
6343
6476
|
var CASE_INSENSITIVE_LANGUAGES = /* @__PURE__ */ new Set(["apex"]);
|
|
6344
6477
|
var CALL_GRAPH_SYMBOL_CHUNK_TYPES = /* @__PURE__ */ new Set([
|
|
6345
6478
|
"function_declaration",
|
|
@@ -6366,7 +6499,15 @@ var CALL_GRAPH_SYMBOL_CHUNK_TYPES = /* @__PURE__ */ new Set([
|
|
|
6366
6499
|
"trigger_declaration",
|
|
6367
6500
|
"test_declaration",
|
|
6368
6501
|
"struct_declaration",
|
|
6369
|
-
"union_declaration"
|
|
6502
|
+
"union_declaration",
|
|
6503
|
+
// GDScript declarations whose names participate in the call graph.
|
|
6504
|
+
// `function_definition` and `class_definition` are already in the set
|
|
6505
|
+
// above (shared with Python/C/Bash and Python, respectively).
|
|
6506
|
+
"constructor_definition",
|
|
6507
|
+
"enum_definition",
|
|
6508
|
+
"signal_statement",
|
|
6509
|
+
"const_statement",
|
|
6510
|
+
"class_name_statement"
|
|
6370
6511
|
]);
|
|
6371
6512
|
function float32ArrayToBuffer(arr) {
|
|
6372
6513
|
const float32 = new Float32Array(arr);
|
|
@@ -6568,9 +6709,9 @@ function hasAllEmbeddingParts(parts, expectedPartCount) {
|
|
|
6568
6709
|
return true;
|
|
6569
6710
|
}
|
|
6570
6711
|
function isPathWithinRoot(filePath, rootPath) {
|
|
6571
|
-
const normalizedFilePath =
|
|
6572
|
-
const normalizedRoot =
|
|
6573
|
-
return normalizedFilePath === normalizedRoot || normalizedFilePath.startsWith(`${normalizedRoot}${
|
|
6712
|
+
const normalizedFilePath = path12.resolve(filePath);
|
|
6713
|
+
const normalizedRoot = path12.resolve(rootPath);
|
|
6714
|
+
return normalizedFilePath === normalizedRoot || normalizedFilePath.startsWith(`${normalizedRoot}${path12.sep}`);
|
|
6574
6715
|
}
|
|
6575
6716
|
var rankingQueryTokenCache = /* @__PURE__ */ new Map();
|
|
6576
6717
|
var rankingNameTokenCache = /* @__PURE__ */ new Map();
|
|
@@ -7623,22 +7764,28 @@ var Indexer = class {
|
|
|
7623
7764
|
this.projectRoot = projectRoot;
|
|
7624
7765
|
this.config = config;
|
|
7625
7766
|
this.indexPath = this.getIndexPath();
|
|
7626
|
-
this.fileHashCachePath =
|
|
7627
|
-
this.failedBatchesPath =
|
|
7628
|
-
this.indexingLockPath =
|
|
7767
|
+
this.fileHashCachePath = path12.join(this.indexPath, "file-hashes.json");
|
|
7768
|
+
this.failedBatchesPath = path12.join(this.indexPath, "failed-batches.json");
|
|
7769
|
+
this.indexingLockPath = path12.join(this.indexPath, "indexing.lock");
|
|
7629
7770
|
this.logger = initializeLogger(config.debug);
|
|
7630
7771
|
}
|
|
7631
7772
|
getIndexPath() {
|
|
7632
7773
|
return resolveProjectIndexPath(this.projectRoot, this.config.scope);
|
|
7633
7774
|
}
|
|
7634
7775
|
loadFileHashCache() {
|
|
7776
|
+
if (!(0, import_fs7.existsSync)(this.fileHashCachePath)) {
|
|
7777
|
+
return;
|
|
7778
|
+
}
|
|
7635
7779
|
try {
|
|
7636
|
-
|
|
7637
|
-
|
|
7638
|
-
|
|
7639
|
-
|
|
7640
|
-
|
|
7641
|
-
|
|
7780
|
+
const data = (0, import_fs7.readFileSync)(this.fileHashCachePath, "utf-8");
|
|
7781
|
+
const parsed = JSON.parse(data);
|
|
7782
|
+
this.fileHashCache = new Map(Object.entries(parsed));
|
|
7783
|
+
} catch (error) {
|
|
7784
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
7785
|
+
this.logger.warn("Failed to load file hash cache, resetting cache state", {
|
|
7786
|
+
fileHashCachePath: this.fileHashCachePath,
|
|
7787
|
+
error: message
|
|
7788
|
+
});
|
|
7642
7789
|
this.fileHashCache = /* @__PURE__ */ new Map();
|
|
7643
7790
|
}
|
|
7644
7791
|
}
|
|
@@ -7651,14 +7798,14 @@ var Indexer = class {
|
|
|
7651
7798
|
}
|
|
7652
7799
|
atomicWriteSync(targetPath, data) {
|
|
7653
7800
|
const tempPath = `${targetPath}.tmp`;
|
|
7654
|
-
(0,
|
|
7655
|
-
(0,
|
|
7656
|
-
(0,
|
|
7801
|
+
(0, import_fs7.mkdirSync)(path12.dirname(targetPath), { recursive: true });
|
|
7802
|
+
(0, import_fs7.writeFileSync)(tempPath, data);
|
|
7803
|
+
(0, import_fs7.renameSync)(tempPath, targetPath);
|
|
7657
7804
|
}
|
|
7658
7805
|
getScopedRoots() {
|
|
7659
|
-
const roots = /* @__PURE__ */ new Set([
|
|
7806
|
+
const roots = /* @__PURE__ */ new Set([path12.resolve(this.projectRoot)]);
|
|
7660
7807
|
for (const kbRoot of this.config.knowledgeBases) {
|
|
7661
|
-
roots.add(
|
|
7808
|
+
roots.add(path12.resolve(this.projectRoot, kbRoot));
|
|
7662
7809
|
}
|
|
7663
7810
|
return Array.from(roots);
|
|
7664
7811
|
}
|
|
@@ -7667,22 +7814,22 @@ var Indexer = class {
|
|
|
7667
7814
|
if (this.config.scope !== "global") {
|
|
7668
7815
|
return branchName;
|
|
7669
7816
|
}
|
|
7670
|
-
const projectHash = hashContent(
|
|
7817
|
+
const projectHash = hashContent(path12.resolve(this.projectRoot)).slice(0, 16);
|
|
7671
7818
|
return `${projectHash}:${branchName}`;
|
|
7672
7819
|
}
|
|
7673
7820
|
getLegacyBranchCatalogKey() {
|
|
7674
7821
|
return this.currentBranch || "default";
|
|
7675
7822
|
}
|
|
7676
7823
|
getLegacyMigrationMetadataKey() {
|
|
7677
|
-
const projectHash = hashContent(
|
|
7824
|
+
const projectHash = hashContent(path12.resolve(this.projectRoot)).slice(0, 16);
|
|
7678
7825
|
return `index.globalBranchMigration.${projectHash}`;
|
|
7679
7826
|
}
|
|
7680
7827
|
getProjectEmbeddingStrategyMetadataKey() {
|
|
7681
|
-
const projectHash = hashContent(
|
|
7828
|
+
const projectHash = hashContent(path12.resolve(this.projectRoot)).slice(0, 16);
|
|
7682
7829
|
return `index.embeddingStrategyVersion.${projectHash}`;
|
|
7683
7830
|
}
|
|
7684
7831
|
getProjectForceReembedMetadataKey() {
|
|
7685
|
-
const projectHash = hashContent(
|
|
7832
|
+
const projectHash = hashContent(path12.resolve(this.projectRoot)).slice(0, 16);
|
|
7686
7833
|
return `index.forceReembed.${projectHash}`;
|
|
7687
7834
|
}
|
|
7688
7835
|
hasProjectForceReembedPending() {
|
|
@@ -7776,7 +7923,7 @@ var Indexer = class {
|
|
|
7776
7923
|
if (!this.database) {
|
|
7777
7924
|
return { chunkIds, symbolIds };
|
|
7778
7925
|
}
|
|
7779
|
-
const projectRootPath =
|
|
7926
|
+
const projectRootPath = path12.resolve(this.projectRoot);
|
|
7780
7927
|
const projectLocalFilePaths = /* @__PURE__ */ new Set([
|
|
7781
7928
|
...Array.from(this.fileHashCache.keys()).filter(
|
|
7782
7929
|
(filePath) => this.isFileInCurrentScope(filePath, roots) && isPathWithinRoot(filePath, projectRootPath)
|
|
@@ -7799,7 +7946,7 @@ var Indexer = class {
|
|
|
7799
7946
|
if (this.config.scope !== "global") {
|
|
7800
7947
|
return this.getBranchCatalogCleanupKeys();
|
|
7801
7948
|
}
|
|
7802
|
-
const projectHash = hashContent(
|
|
7949
|
+
const projectHash = hashContent(path12.resolve(this.projectRoot)).slice(0, 16);
|
|
7803
7950
|
const keys = /* @__PURE__ */ new Set();
|
|
7804
7951
|
const projectChunkIdSet = new Set(projectChunkIds);
|
|
7805
7952
|
const projectSymbolIdSet = new Set(projectSymbolIds);
|
|
@@ -7883,7 +8030,7 @@ var Indexer = class {
|
|
|
7883
8030
|
if (!this.database || this.config.scope !== "global") {
|
|
7884
8031
|
return false;
|
|
7885
8032
|
}
|
|
7886
|
-
const projectHash = hashContent(
|
|
8033
|
+
const projectHash = hashContent(path12.resolve(this.projectRoot)).slice(0, 16);
|
|
7887
8034
|
const roots = this.getScopedRoots();
|
|
7888
8035
|
const { chunkIds: projectLocalChunkIds, symbolIds: projectLocalSymbolIds } = this.getProjectLocalScopedOwnershipIds(roots);
|
|
7889
8036
|
return this.database.getAllBranches().some(
|
|
@@ -7917,7 +8064,7 @@ var Indexer = class {
|
|
|
7917
8064
|
...Array.from(this.fileHashCache.keys()).filter((filePath) => this.isFileInCurrentScope(filePath, roots)),
|
|
7918
8065
|
...scopedEntries.map(({ metadata }) => metadata.filePath)
|
|
7919
8066
|
]);
|
|
7920
|
-
const projectRootPath =
|
|
8067
|
+
const projectRootPath = path12.resolve(this.projectRoot);
|
|
7921
8068
|
const projectLocalFilePaths = new Set(
|
|
7922
8069
|
Array.from(filePaths).filter((filePath) => isPathWithinRoot(filePath, projectRootPath))
|
|
7923
8070
|
);
|
|
@@ -7986,24 +8133,24 @@ var Indexer = class {
|
|
|
7986
8133
|
};
|
|
7987
8134
|
}
|
|
7988
8135
|
checkForInterruptedIndexing() {
|
|
7989
|
-
return (0,
|
|
8136
|
+
return (0, import_fs7.existsSync)(this.indexingLockPath);
|
|
7990
8137
|
}
|
|
7991
8138
|
acquireIndexingLock() {
|
|
7992
8139
|
const lockData = {
|
|
7993
8140
|
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7994
8141
|
pid: process.pid
|
|
7995
8142
|
};
|
|
7996
|
-
(0,
|
|
8143
|
+
(0, import_fs7.writeFileSync)(this.indexingLockPath, JSON.stringify(lockData));
|
|
7997
8144
|
}
|
|
7998
8145
|
releaseIndexingLock() {
|
|
7999
|
-
if ((0,
|
|
8000
|
-
(0,
|
|
8146
|
+
if ((0, import_fs7.existsSync)(this.indexingLockPath)) {
|
|
8147
|
+
(0, import_fs7.unlinkSync)(this.indexingLockPath);
|
|
8001
8148
|
}
|
|
8002
8149
|
}
|
|
8003
8150
|
async recoverFromInterruptedIndexing() {
|
|
8004
8151
|
this.logger.warn("Detected interrupted indexing session, recovering...");
|
|
8005
|
-
if ((0,
|
|
8006
|
-
(0,
|
|
8152
|
+
if ((0, import_fs7.existsSync)(this.fileHashCachePath)) {
|
|
8153
|
+
(0, import_fs7.unlinkSync)(this.fileHashCachePath);
|
|
8007
8154
|
}
|
|
8008
8155
|
await this.healthCheck();
|
|
8009
8156
|
this.releaseIndexingLock();
|
|
@@ -8012,15 +8159,20 @@ var Indexer = class {
|
|
|
8012
8159
|
loadFailedBatches(maxChunkTokens) {
|
|
8013
8160
|
try {
|
|
8014
8161
|
return this.loadSerializedFailedBatches().map((batch) => normalizeFailedBatch(batch, maxChunkTokens)).filter((batch) => batch !== null);
|
|
8015
|
-
} catch {
|
|
8162
|
+
} catch (error) {
|
|
8163
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
8164
|
+
this.logger.warn("Failed to load failed batch state, skipping persisted retries", {
|
|
8165
|
+
failedBatchesPath: this.failedBatchesPath,
|
|
8166
|
+
error: message
|
|
8167
|
+
});
|
|
8016
8168
|
return [];
|
|
8017
8169
|
}
|
|
8018
8170
|
}
|
|
8019
8171
|
loadSerializedFailedBatches() {
|
|
8020
|
-
if (!(0,
|
|
8172
|
+
if (!(0, import_fs7.existsSync)(this.failedBatchesPath)) {
|
|
8021
8173
|
return [];
|
|
8022
8174
|
}
|
|
8023
|
-
const data = (0,
|
|
8175
|
+
const data = (0, import_fs7.readFileSync)(this.failedBatchesPath, "utf-8");
|
|
8024
8176
|
const parsed = JSON.parse(data);
|
|
8025
8177
|
return parsed.map((batch) => {
|
|
8026
8178
|
const chunks = Array.isArray(batch.chunks) ? batch.chunks : [];
|
|
@@ -8037,15 +8189,15 @@ var Indexer = class {
|
|
|
8037
8189
|
}
|
|
8038
8190
|
saveFailedBatches(batches) {
|
|
8039
8191
|
if (batches.length === 0) {
|
|
8040
|
-
if ((0,
|
|
8192
|
+
if ((0, import_fs7.existsSync)(this.failedBatchesPath)) {
|
|
8041
8193
|
try {
|
|
8042
|
-
(0,
|
|
8194
|
+
(0, import_fs7.unlinkSync)(this.failedBatchesPath);
|
|
8043
8195
|
} catch {
|
|
8044
8196
|
}
|
|
8045
8197
|
}
|
|
8046
8198
|
return;
|
|
8047
8199
|
}
|
|
8048
|
-
(0,
|
|
8200
|
+
(0, import_fs7.writeFileSync)(this.failedBatchesPath, JSON.stringify(batches, null, 2));
|
|
8049
8201
|
}
|
|
8050
8202
|
collectRetryableFailedChunks(currentFileHashes, unchangedFilePaths, maxChunkTokens) {
|
|
8051
8203
|
const retryableById = /* @__PURE__ */ new Map();
|
|
@@ -8225,7 +8377,7 @@ var Indexer = class {
|
|
|
8225
8377
|
const intent = isLikelyImplementationPath(candidate.metadata.filePath) ? "implementation" : "doc_or_test";
|
|
8226
8378
|
parts.push(`intent_hint: ${intent}`);
|
|
8227
8379
|
try {
|
|
8228
|
-
const fileContent = await
|
|
8380
|
+
const fileContent = await import_fs7.promises.readFile(candidate.metadata.filePath, "utf-8");
|
|
8229
8381
|
const lines = fileContent.split("\n");
|
|
8230
8382
|
const snippetStartLine = Math.max(1, candidate.metadata.startLine - 2);
|
|
8231
8383
|
const snippetEndLine = Math.min(lines.length, candidate.metadata.endLine + 2);
|
|
@@ -8270,26 +8422,26 @@ var Indexer = class {
|
|
|
8270
8422
|
});
|
|
8271
8423
|
}
|
|
8272
8424
|
}
|
|
8273
|
-
await
|
|
8425
|
+
await import_fs7.promises.mkdir(this.indexPath, { recursive: true });
|
|
8274
8426
|
const dimensions = this.configuredProviderInfo.modelInfo.dimensions;
|
|
8275
|
-
const storePath =
|
|
8427
|
+
const storePath = path12.join(this.indexPath, "vectors");
|
|
8276
8428
|
this.store = new VectorStore(storePath, dimensions);
|
|
8277
|
-
const indexFilePath =
|
|
8278
|
-
if ((0,
|
|
8429
|
+
const indexFilePath = path12.join(this.indexPath, "vectors.usearch");
|
|
8430
|
+
if ((0, import_fs7.existsSync)(indexFilePath)) {
|
|
8279
8431
|
this.store.load();
|
|
8280
8432
|
}
|
|
8281
|
-
const invertedIndexPath =
|
|
8433
|
+
const invertedIndexPath = path12.join(this.indexPath, "inverted-index.json");
|
|
8282
8434
|
this.invertedIndex = new InvertedIndex(invertedIndexPath);
|
|
8283
8435
|
try {
|
|
8284
8436
|
this.invertedIndex.load();
|
|
8285
8437
|
} catch {
|
|
8286
|
-
if ((0,
|
|
8287
|
-
await
|
|
8438
|
+
if ((0, import_fs7.existsSync)(invertedIndexPath)) {
|
|
8439
|
+
await import_fs7.promises.unlink(invertedIndexPath);
|
|
8288
8440
|
}
|
|
8289
8441
|
this.invertedIndex = new InvertedIndex(invertedIndexPath);
|
|
8290
8442
|
}
|
|
8291
|
-
const dbPath =
|
|
8292
|
-
let dbIsNew = !(0,
|
|
8443
|
+
const dbPath = path12.join(this.indexPath, "codebase.db");
|
|
8444
|
+
let dbIsNew = !(0, import_fs7.existsSync)(dbPath);
|
|
8293
8445
|
try {
|
|
8294
8446
|
this.database = new Database(dbPath);
|
|
8295
8447
|
} catch (error) {
|
|
@@ -8369,7 +8521,7 @@ var Indexer = class {
|
|
|
8369
8521
|
if (await this.tryResetCorruptedIndex("running automatic orphan garbage collection", error)) {
|
|
8370
8522
|
return {
|
|
8371
8523
|
resetCorruptedIndex: true,
|
|
8372
|
-
warning: this.getCorruptedIndexWarning(
|
|
8524
|
+
warning: this.getCorruptedIndexWarning(path12.join(this.indexPath, "codebase.db"))
|
|
8373
8525
|
};
|
|
8374
8526
|
}
|
|
8375
8527
|
throw error;
|
|
@@ -8384,7 +8536,7 @@ var Indexer = class {
|
|
|
8384
8536
|
return;
|
|
8385
8537
|
}
|
|
8386
8538
|
const retainedEntries = store.getAllMetadata().filter(({ key }) => !excludedSet.has(key));
|
|
8387
|
-
const storeBasePath =
|
|
8539
|
+
const storeBasePath = path12.join(this.indexPath, "vectors");
|
|
8388
8540
|
const storeIndexPath = `${storeBasePath}.usearch`;
|
|
8389
8541
|
const storeMetadataPath = `${storeBasePath}.meta.json`;
|
|
8390
8542
|
const backupIndexPath = `${storeIndexPath}.bak`;
|
|
@@ -8393,19 +8545,19 @@ var Indexer = class {
|
|
|
8393
8545
|
let backedUpMetadata = false;
|
|
8394
8546
|
let rebuiltCount = 0;
|
|
8395
8547
|
let skippedCount = 0;
|
|
8396
|
-
if ((0,
|
|
8397
|
-
(0,
|
|
8548
|
+
if ((0, import_fs7.existsSync)(backupIndexPath)) {
|
|
8549
|
+
(0, import_fs7.unlinkSync)(backupIndexPath);
|
|
8398
8550
|
}
|
|
8399
|
-
if ((0,
|
|
8400
|
-
(0,
|
|
8551
|
+
if ((0, import_fs7.existsSync)(backupMetadataPath)) {
|
|
8552
|
+
(0, import_fs7.unlinkSync)(backupMetadataPath);
|
|
8401
8553
|
}
|
|
8402
8554
|
try {
|
|
8403
|
-
if ((0,
|
|
8404
|
-
(0,
|
|
8555
|
+
if ((0, import_fs7.existsSync)(storeIndexPath)) {
|
|
8556
|
+
(0, import_fs7.renameSync)(storeIndexPath, backupIndexPath);
|
|
8405
8557
|
backedUpIndex = true;
|
|
8406
8558
|
}
|
|
8407
|
-
if ((0,
|
|
8408
|
-
(0,
|
|
8559
|
+
if ((0, import_fs7.existsSync)(storeMetadataPath)) {
|
|
8560
|
+
(0, import_fs7.renameSync)(storeMetadataPath, backupMetadataPath);
|
|
8409
8561
|
backedUpMetadata = true;
|
|
8410
8562
|
}
|
|
8411
8563
|
store.clear();
|
|
@@ -8425,11 +8577,11 @@ var Indexer = class {
|
|
|
8425
8577
|
rebuiltCount += 1;
|
|
8426
8578
|
}
|
|
8427
8579
|
store.save();
|
|
8428
|
-
if (backedUpIndex && (0,
|
|
8429
|
-
(0,
|
|
8580
|
+
if (backedUpIndex && (0, import_fs7.existsSync)(backupIndexPath)) {
|
|
8581
|
+
(0, import_fs7.unlinkSync)(backupIndexPath);
|
|
8430
8582
|
}
|
|
8431
|
-
if (backedUpMetadata && (0,
|
|
8432
|
-
(0,
|
|
8583
|
+
if (backedUpMetadata && (0, import_fs7.existsSync)(backupMetadataPath)) {
|
|
8584
|
+
(0, import_fs7.unlinkSync)(backupMetadataPath);
|
|
8433
8585
|
}
|
|
8434
8586
|
this.logger.gc("info", "Rebuilt vector store to avoid native remove", {
|
|
8435
8587
|
excludedChunks: excludedSet.size,
|
|
@@ -8441,17 +8593,17 @@ var Indexer = class {
|
|
|
8441
8593
|
store.clear();
|
|
8442
8594
|
} catch {
|
|
8443
8595
|
}
|
|
8444
|
-
if ((0,
|
|
8445
|
-
(0,
|
|
8596
|
+
if ((0, import_fs7.existsSync)(storeIndexPath)) {
|
|
8597
|
+
(0, import_fs7.unlinkSync)(storeIndexPath);
|
|
8446
8598
|
}
|
|
8447
|
-
if ((0,
|
|
8448
|
-
(0,
|
|
8599
|
+
if ((0, import_fs7.existsSync)(storeMetadataPath)) {
|
|
8600
|
+
(0, import_fs7.unlinkSync)(storeMetadataPath);
|
|
8449
8601
|
}
|
|
8450
|
-
if (backedUpIndex && (0,
|
|
8451
|
-
(0,
|
|
8602
|
+
if (backedUpIndex && (0, import_fs7.existsSync)(backupIndexPath)) {
|
|
8603
|
+
(0, import_fs7.renameSync)(backupIndexPath, storeIndexPath);
|
|
8452
8604
|
}
|
|
8453
|
-
if (backedUpMetadata && (0,
|
|
8454
|
-
(0,
|
|
8605
|
+
if (backedUpMetadata && (0, import_fs7.existsSync)(backupMetadataPath)) {
|
|
8606
|
+
(0, import_fs7.renameSync)(backupMetadataPath, storeMetadataPath);
|
|
8455
8607
|
}
|
|
8456
8608
|
if (backedUpIndex || backedUpMetadata) {
|
|
8457
8609
|
store.load();
|
|
@@ -8469,7 +8621,7 @@ var Indexer = class {
|
|
|
8469
8621
|
if (!isSqliteCorruptionError(error)) {
|
|
8470
8622
|
return false;
|
|
8471
8623
|
}
|
|
8472
|
-
const dbPath =
|
|
8624
|
+
const dbPath = path12.join(this.indexPath, "codebase.db");
|
|
8473
8625
|
const warning = this.getCorruptedIndexWarning(dbPath);
|
|
8474
8626
|
const errorMessage = getErrorMessage(error);
|
|
8475
8627
|
if (this.config.scope === "global") {
|
|
@@ -8492,23 +8644,23 @@ var Indexer = class {
|
|
|
8492
8644
|
this.indexCompatibility = null;
|
|
8493
8645
|
this.fileHashCache.clear();
|
|
8494
8646
|
const resetPaths = [
|
|
8495
|
-
|
|
8496
|
-
|
|
8497
|
-
|
|
8498
|
-
|
|
8499
|
-
|
|
8500
|
-
|
|
8501
|
-
|
|
8502
|
-
|
|
8503
|
-
|
|
8647
|
+
path12.join(this.indexPath, "codebase.db"),
|
|
8648
|
+
path12.join(this.indexPath, "codebase.db-shm"),
|
|
8649
|
+
path12.join(this.indexPath, "codebase.db-wal"),
|
|
8650
|
+
path12.join(this.indexPath, "vectors.usearch"),
|
|
8651
|
+
path12.join(this.indexPath, "inverted-index.json"),
|
|
8652
|
+
path12.join(this.indexPath, "file-hashes.json"),
|
|
8653
|
+
path12.join(this.indexPath, "failed-batches.json"),
|
|
8654
|
+
path12.join(this.indexPath, "indexing.lock"),
|
|
8655
|
+
path12.join(this.indexPath, "vectors")
|
|
8504
8656
|
];
|
|
8505
8657
|
await Promise.all(resetPaths.map(async (targetPath) => {
|
|
8506
8658
|
try {
|
|
8507
|
-
await
|
|
8659
|
+
await import_fs7.promises.rm(targetPath, { recursive: true, force: true });
|
|
8508
8660
|
} catch {
|
|
8509
8661
|
}
|
|
8510
8662
|
}));
|
|
8511
|
-
await
|
|
8663
|
+
await import_fs7.promises.mkdir(this.indexPath, { recursive: true });
|
|
8512
8664
|
return true;
|
|
8513
8665
|
}
|
|
8514
8666
|
migrateFromLegacyIndex() {
|
|
@@ -8713,7 +8865,7 @@ var Indexer = class {
|
|
|
8713
8865
|
unchangedFilePaths.add(f.path);
|
|
8714
8866
|
this.logger.recordCacheHit();
|
|
8715
8867
|
} else {
|
|
8716
|
-
const content = await
|
|
8868
|
+
const content = await import_fs7.promises.readFile(f.path, "utf-8");
|
|
8717
8869
|
changedFiles.push({ path: f.path, content, hash: currentHash });
|
|
8718
8870
|
this.logger.recordCacheMiss();
|
|
8719
8871
|
}
|
|
@@ -8765,7 +8917,7 @@ var Indexer = class {
|
|
|
8765
8917
|
for (const parsed of parsedFiles) {
|
|
8766
8918
|
currentFilePaths.add(parsed.path);
|
|
8767
8919
|
if (parsed.chunks.length === 0) {
|
|
8768
|
-
const relativePath =
|
|
8920
|
+
const relativePath = path12.relative(this.projectRoot, parsed.path);
|
|
8769
8921
|
stats.parseFailures.push(relativePath);
|
|
8770
8922
|
}
|
|
8771
8923
|
let fileChunkCount = 0;
|
|
@@ -9048,7 +9200,7 @@ var Indexer = class {
|
|
|
9048
9200
|
for (const requestBatch of requestBatches) {
|
|
9049
9201
|
queue.add(async () => {
|
|
9050
9202
|
if (rateLimitBackoffMs > 0) {
|
|
9051
|
-
await new Promise((
|
|
9203
|
+
await new Promise((resolve12) => setTimeout(resolve12, rateLimitBackoffMs));
|
|
9052
9204
|
}
|
|
9053
9205
|
try {
|
|
9054
9206
|
const result = await pRetry(
|
|
@@ -9497,7 +9649,7 @@ var Indexer = class {
|
|
|
9497
9649
|
let contextEndLine = r.metadata.endLine;
|
|
9498
9650
|
if (!metadataOnly && this.config.search.includeContext) {
|
|
9499
9651
|
try {
|
|
9500
|
-
const fileContent = await
|
|
9652
|
+
const fileContent = await import_fs7.promises.readFile(
|
|
9501
9653
|
r.metadata.filePath,
|
|
9502
9654
|
"utf-8"
|
|
9503
9655
|
);
|
|
@@ -9609,8 +9761,8 @@ var Indexer = class {
|
|
|
9609
9761
|
this.indexCompatibility = compatibility;
|
|
9610
9762
|
return;
|
|
9611
9763
|
}
|
|
9612
|
-
const localProjectIndexPath =
|
|
9613
|
-
if (
|
|
9764
|
+
const localProjectIndexPath = path12.join(this.projectRoot, ".opencode", "index");
|
|
9765
|
+
if (path12.resolve(this.indexPath) !== path12.resolve(localProjectIndexPath)) {
|
|
9614
9766
|
throw new Error(
|
|
9615
9767
|
"Project-scoped force rebuild is unsafe while using an inherited worktree index. Create a local project config boundary before clearing the index."
|
|
9616
9768
|
);
|
|
@@ -9649,7 +9801,7 @@ var Indexer = class {
|
|
|
9649
9801
|
const removedChunkKeys = [];
|
|
9650
9802
|
const chunkKeysByRemovedFile = /* @__PURE__ */ new Map();
|
|
9651
9803
|
for (const [filePath, chunkKeys] of filePathsToChunkKeys) {
|
|
9652
|
-
if (!(0,
|
|
9804
|
+
if (!(0, import_fs7.existsSync)(filePath)) {
|
|
9653
9805
|
chunkKeysByRemovedFile.set(filePath, chunkKeys);
|
|
9654
9806
|
for (const key of chunkKeys) {
|
|
9655
9807
|
removedChunkKeys.push(key);
|
|
@@ -9698,7 +9850,7 @@ var Indexer = class {
|
|
|
9698
9850
|
gcOrphanSymbols: 0,
|
|
9699
9851
|
gcOrphanCallEdges: 0,
|
|
9700
9852
|
resetCorruptedIndex: true,
|
|
9701
|
-
warning: this.getCorruptedIndexWarning(
|
|
9853
|
+
warning: this.getCorruptedIndexWarning(path12.join(this.indexPath, "codebase.db"))
|
|
9702
9854
|
};
|
|
9703
9855
|
}
|
|
9704
9856
|
this.logger.recordGc(removedCount, gcOrphanChunks, gcOrphanEmbeddings);
|
|
@@ -10001,7 +10153,7 @@ var Indexer = class {
|
|
|
10001
10153
|
let content = "";
|
|
10002
10154
|
if (this.config.search.includeContext) {
|
|
10003
10155
|
try {
|
|
10004
|
-
const fileContent = await
|
|
10156
|
+
const fileContent = await import_fs7.promises.readFile(
|
|
10005
10157
|
r.metadata.filePath,
|
|
10006
10158
|
"utf-8"
|
|
10007
10159
|
);
|
|
@@ -10250,12 +10402,15 @@ function formatLogs(logs) {
|
|
|
10250
10402
|
return `[${l.timestamp}] [${l.level.toUpperCase()}] [${l.category}] ${l.message}${dataStr}`;
|
|
10251
10403
|
}).join("\n");
|
|
10252
10404
|
}
|
|
10405
|
+
function formatResultHeader(result, index) {
|
|
10406
|
+
return result.name ? `[${index + 1}] ${result.chunkType} "${result.name}" in ${result.filePath}:${result.startLine}-${result.endLine}` : `[${index + 1}] ${result.chunkType} in ${result.filePath}:${result.startLine}-${result.endLine}`;
|
|
10407
|
+
}
|
|
10253
10408
|
function formatDefinitionLookup(results, query) {
|
|
10254
10409
|
if (results.length === 0) {
|
|
10255
10410
|
return `No definition found for "${query}". Try codebase_search for broader discovery, or verify the symbol name.`;
|
|
10256
10411
|
}
|
|
10257
10412
|
const formatted = results.map((r, idx) => {
|
|
10258
|
-
const header = r
|
|
10413
|
+
const header = formatResultHeader(r, idx);
|
|
10259
10414
|
return `${header} (score: ${r.score.toFixed(2)})
|
|
10260
10415
|
\`\`\`
|
|
10261
10416
|
${truncateContent(r.content)}
|
|
@@ -10265,7 +10420,7 @@ ${truncateContent(r.content)}
|
|
|
10265
10420
|
}
|
|
10266
10421
|
function formatSearchResults(results, scoreFormat = "similarity") {
|
|
10267
10422
|
const formatted = results.map((r, idx) => {
|
|
10268
|
-
const header = r
|
|
10423
|
+
const header = formatResultHeader(r, idx);
|
|
10269
10424
|
const scoreLabel = scoreFormat === "similarity" ? `(similarity: ${(r.score * 100).toFixed(1)}%)` : `(score: ${r.score.toFixed(2)})`;
|
|
10270
10425
|
return `${header} ${scoreLabel}
|
|
10271
10426
|
\`\`\`
|
|
@@ -10275,105 +10430,84 @@ ${truncateContent(r.content)}
|
|
|
10275
10430
|
return formatted.join("\n\n");
|
|
10276
10431
|
}
|
|
10277
10432
|
|
|
10278
|
-
// src/tools/
|
|
10279
|
-
var
|
|
10280
|
-
|
|
10281
|
-
var z = import_plugin.tool.schema;
|
|
10282
|
-
var sharedIndexer = null;
|
|
10283
|
-
var sharedProjectRoot = "";
|
|
10284
|
-
function initializeTools(projectRoot, config) {
|
|
10285
|
-
sharedProjectRoot = projectRoot;
|
|
10286
|
-
sharedIndexer = new Indexer(projectRoot, config);
|
|
10287
|
-
}
|
|
10288
|
-
function getSharedIndexer() {
|
|
10289
|
-
return getIndexer();
|
|
10290
|
-
}
|
|
10291
|
-
function refreshIndexerFromConfig() {
|
|
10292
|
-
if (!sharedProjectRoot) {
|
|
10293
|
-
throw new Error("Codebase index tools not initialized. Plugin may not be loaded correctly.");
|
|
10294
|
-
}
|
|
10295
|
-
sharedIndexer = new Indexer(sharedProjectRoot, parseConfig(loadRuntimeConfig()));
|
|
10296
|
-
}
|
|
10297
|
-
function shouldForceLocalizeProjectIndex() {
|
|
10298
|
-
const currentConfig = parseConfig(loadRuntimeConfig());
|
|
10299
|
-
if (currentConfig.scope !== "project") {
|
|
10300
|
-
return false;
|
|
10301
|
-
}
|
|
10302
|
-
const localIndexPath = path9.join(sharedProjectRoot, ".opencode", "index");
|
|
10303
|
-
const mainRepoRoot = resolveWorktreeMainRepoRoot(sharedProjectRoot);
|
|
10304
|
-
if (!mainRepoRoot) {
|
|
10305
|
-
return false;
|
|
10306
|
-
}
|
|
10307
|
-
const inheritedIndexPath = path9.join(mainRepoRoot, ".opencode", "index");
|
|
10308
|
-
return !(0, import_fs7.existsSync)(localIndexPath) && (0, import_fs7.existsSync)(inheritedIndexPath);
|
|
10309
|
-
}
|
|
10310
|
-
function getIndexer() {
|
|
10311
|
-
if (!sharedIndexer) {
|
|
10312
|
-
throw new Error("Codebase index tools not initialized. Plugin may not be loaded correctly.");
|
|
10313
|
-
}
|
|
10314
|
-
return sharedIndexer;
|
|
10315
|
-
}
|
|
10316
|
-
function getConfigPath() {
|
|
10317
|
-
return resolveWritableProjectConfigPath(sharedProjectRoot);
|
|
10318
|
-
}
|
|
10319
|
-
function normalizeConfigPathValue(value, baseDir) {
|
|
10433
|
+
// src/tools/knowledge-base-paths.ts
|
|
10434
|
+
var path13 = __toESM(require("path"), 1);
|
|
10435
|
+
function resolveConfigPathValue(value, baseDir) {
|
|
10320
10436
|
const trimmed = value.trim();
|
|
10321
10437
|
if (!trimmed) {
|
|
10322
10438
|
return trimmed;
|
|
10323
10439
|
}
|
|
10324
|
-
const absolutePath =
|
|
10325
|
-
return
|
|
10440
|
+
const absolutePath = path13.isAbsolute(trimmed) ? trimmed : path13.resolve(baseDir, trimmed);
|
|
10441
|
+
return path13.normalize(absolutePath);
|
|
10326
10442
|
}
|
|
10327
10443
|
function serializeConfigPathValue(value, baseDir) {
|
|
10328
10444
|
const trimmed = value.trim();
|
|
10329
10445
|
if (!trimmed) {
|
|
10330
10446
|
return trimmed;
|
|
10331
10447
|
}
|
|
10332
|
-
|
|
10333
|
-
|
|
10334
|
-
return normalizeRelativePath(path9.normalize(trimmed));
|
|
10448
|
+
if (!path13.isAbsolute(trimmed)) {
|
|
10449
|
+
return normalizePathSeparators(path13.normalize(trimmed));
|
|
10335
10450
|
}
|
|
10336
|
-
const relativePath =
|
|
10337
|
-
if (!relativePath || !relativePath.startsWith("..") && !
|
|
10338
|
-
return
|
|
10451
|
+
const relativePath = path13.relative(baseDir, trimmed);
|
|
10452
|
+
if (!relativePath || !relativePath.startsWith("..") && !path13.isAbsolute(relativePath)) {
|
|
10453
|
+
return normalizePathSeparators(path13.normalize(relativePath || "."));
|
|
10339
10454
|
}
|
|
10340
|
-
return
|
|
10455
|
+
return path13.normalize(trimmed);
|
|
10456
|
+
}
|
|
10457
|
+
function resolveKnowledgeBasePath(value, projectRoot) {
|
|
10458
|
+
return path13.isAbsolute(value) ? value : path13.resolve(projectRoot, value);
|
|
10459
|
+
}
|
|
10460
|
+
function normalizeKnowledgeBasePath2(value, projectRoot) {
|
|
10461
|
+
return path13.normalize(resolveKnowledgeBasePath(value, projectRoot));
|
|
10462
|
+
}
|
|
10463
|
+
function hasMatchingKnowledgeBasePath(knowledgeBases, inputPath, projectRoot) {
|
|
10464
|
+
const normalizedInput = path13.normalize(inputPath);
|
|
10465
|
+
return knowledgeBases.some((kb) => normalizeKnowledgeBasePath2(kb, projectRoot) === normalizedInput);
|
|
10466
|
+
}
|
|
10467
|
+
function findKnowledgeBasePathIndex(knowledgeBases, inputPath, projectRoot) {
|
|
10468
|
+
const normalizedInput = path13.normalize(inputPath);
|
|
10469
|
+
return knowledgeBases.findIndex(
|
|
10470
|
+
(kb) => path13.normalize(kb) === normalizedInput || normalizeKnowledgeBasePath2(kb, projectRoot) === normalizedInput
|
|
10471
|
+
);
|
|
10341
10472
|
}
|
|
10342
|
-
|
|
10473
|
+
|
|
10474
|
+
// src/tools/index.ts
|
|
10475
|
+
var import_fs9 = require("fs");
|
|
10476
|
+
var path15 = __toESM(require("path"), 1);
|
|
10477
|
+
|
|
10478
|
+
// src/tools/config-state.ts
|
|
10479
|
+
var import_fs8 = require("fs");
|
|
10480
|
+
var path14 = __toESM(require("path"), 1);
|
|
10481
|
+
function normalizeKnowledgeBasePaths(config, projectRoot) {
|
|
10343
10482
|
const normalized = { ...config };
|
|
10344
10483
|
if (Array.isArray(normalized.knowledgeBases)) {
|
|
10345
|
-
normalized.knowledgeBases = normalized.knowledgeBases.map(
|
|
10346
|
-
|
|
10347
|
-
|
|
10484
|
+
normalized.knowledgeBases = normalized.knowledgeBases.map(
|
|
10485
|
+
(kb) => resolveConfigPathValue(kb, projectRoot)
|
|
10486
|
+
);
|
|
10348
10487
|
}
|
|
10349
10488
|
return normalized;
|
|
10350
10489
|
}
|
|
10351
|
-
function
|
|
10352
|
-
|
|
10353
|
-
|
|
10354
|
-
if (rawConfig && typeof rawConfig === "object") {
|
|
10355
|
-
for (const key of Object.keys(rawConfig)) {
|
|
10356
|
-
config[key] = rawConfig[key];
|
|
10357
|
-
}
|
|
10490
|
+
function toConfigRecord(rawConfig) {
|
|
10491
|
+
if (!rawConfig || typeof rawConfig !== "object") {
|
|
10492
|
+
return {};
|
|
10358
10493
|
}
|
|
10359
|
-
return
|
|
10494
|
+
return { ...rawConfig };
|
|
10360
10495
|
}
|
|
10361
|
-
function
|
|
10362
|
-
|
|
10363
|
-
|
|
10364
|
-
|
|
10365
|
-
|
|
10366
|
-
|
|
10367
|
-
|
|
10368
|
-
|
|
10369
|
-
return normalizeKnowledgeBasePaths(config);
|
|
10496
|
+
function getConfigPath(projectRoot) {
|
|
10497
|
+
return resolveWritableProjectConfigPath(projectRoot);
|
|
10498
|
+
}
|
|
10499
|
+
function loadRuntimeConfig(projectRoot) {
|
|
10500
|
+
return normalizeKnowledgeBasePaths(toConfigRecord(loadMergedConfig(projectRoot)), projectRoot);
|
|
10501
|
+
}
|
|
10502
|
+
function loadEditableConfig(projectRoot) {
|
|
10503
|
+
return normalizeKnowledgeBasePaths(toConfigRecord(loadProjectConfigLayer(projectRoot)), projectRoot);
|
|
10370
10504
|
}
|
|
10371
|
-
function saveConfig(config) {
|
|
10372
|
-
const configPath = getConfigPath();
|
|
10373
|
-
const configDir =
|
|
10374
|
-
const configBaseDir =
|
|
10375
|
-
if (!(0,
|
|
10376
|
-
(0,
|
|
10505
|
+
function saveConfig(projectRoot, config) {
|
|
10506
|
+
const configPath = getConfigPath(projectRoot);
|
|
10507
|
+
const configDir = path14.dirname(configPath);
|
|
10508
|
+
const configBaseDir = path14.dirname(configDir);
|
|
10509
|
+
if (!(0, import_fs8.existsSync)(configDir)) {
|
|
10510
|
+
(0, import_fs8.mkdirSync)(configDir, { recursive: true });
|
|
10377
10511
|
}
|
|
10378
10512
|
const serializableConfig = { ...config };
|
|
10379
10513
|
if (Array.isArray(serializableConfig.knowledgeBases)) {
|
|
@@ -10381,7 +10515,54 @@ function saveConfig(config) {
|
|
|
10381
10515
|
(kb) => serializeConfigPathValue(kb, configBaseDir)
|
|
10382
10516
|
);
|
|
10383
10517
|
}
|
|
10384
|
-
(0,
|
|
10518
|
+
(0, import_fs8.writeFileSync)(configPath, JSON.stringify(serializableConfig, null, 2) + "\n", "utf-8");
|
|
10519
|
+
}
|
|
10520
|
+
|
|
10521
|
+
// src/tools/index.ts
|
|
10522
|
+
var os5 = __toESM(require("os"), 1);
|
|
10523
|
+
function ensureStringArray(value) {
|
|
10524
|
+
return Array.isArray(value) ? value : [];
|
|
10525
|
+
}
|
|
10526
|
+
var z = import_plugin.tool.schema;
|
|
10527
|
+
var indexerMap = /* @__PURE__ */ new Map();
|
|
10528
|
+
var defaultProjectRoot = "";
|
|
10529
|
+
function initializeTools(projectRoot, config) {
|
|
10530
|
+
defaultProjectRoot = projectRoot;
|
|
10531
|
+
const indexer = new Indexer(projectRoot, config);
|
|
10532
|
+
indexerMap.set(projectRoot, indexer);
|
|
10533
|
+
}
|
|
10534
|
+
function refreshIndexerForDirectory(projectRoot) {
|
|
10535
|
+
if (!projectRoot) {
|
|
10536
|
+
throw new Error("Codebase index tools not initialized. Plugin may not be loaded correctly.");
|
|
10537
|
+
}
|
|
10538
|
+
const indexer = new Indexer(projectRoot, parseConfig(loadRuntimeConfig(projectRoot)));
|
|
10539
|
+
indexerMap.set(projectRoot, indexer);
|
|
10540
|
+
}
|
|
10541
|
+
function shouldForceLocalizeProjectIndex(projectRoot) {
|
|
10542
|
+
const currentConfig = parseConfig(loadRuntimeConfig(projectRoot));
|
|
10543
|
+
if (currentConfig.scope !== "project") {
|
|
10544
|
+
return false;
|
|
10545
|
+
}
|
|
10546
|
+
const localIndexPath = path15.join(projectRoot, ".opencode", "index");
|
|
10547
|
+
const mainRepoRoot = resolveWorktreeMainRepoRoot(projectRoot);
|
|
10548
|
+
if (!mainRepoRoot) {
|
|
10549
|
+
return false;
|
|
10550
|
+
}
|
|
10551
|
+
const inheritedIndexPath = path15.join(mainRepoRoot, ".opencode", "index");
|
|
10552
|
+
return !(0, import_fs9.existsSync)(localIndexPath) && (0, import_fs9.existsSync)(inheritedIndexPath);
|
|
10553
|
+
}
|
|
10554
|
+
function getIndexerForProject(directory) {
|
|
10555
|
+
const projectRoot = directory || defaultProjectRoot;
|
|
10556
|
+
if (!projectRoot) {
|
|
10557
|
+
throw new Error("Codebase index tools not initialized. Plugin may not be loaded correctly.");
|
|
10558
|
+
}
|
|
10559
|
+
let indexer = indexerMap.get(projectRoot);
|
|
10560
|
+
if (!indexer) {
|
|
10561
|
+
const config = parseConfig(loadRuntimeConfig(projectRoot));
|
|
10562
|
+
indexer = new Indexer(projectRoot, config);
|
|
10563
|
+
indexerMap.set(projectRoot, indexer);
|
|
10564
|
+
}
|
|
10565
|
+
return indexer;
|
|
10385
10566
|
}
|
|
10386
10567
|
var codebase_peek = (0, import_plugin.tool)({
|
|
10387
10568
|
description: "Quick lookup of code locations by meaning. Returns only metadata (file, line, name, type) WITHOUT code content. Use this first to find WHERE code is, then use Read tool to examine specific files. Saves tokens by not returning full code blocks. Best for: discovery, navigation, finding multiple related locations.",
|
|
@@ -10392,8 +10573,8 @@ var codebase_peek = (0, import_plugin.tool)({
|
|
|
10392
10573
|
directory: z.string().optional().describe("Filter by directory path (e.g., 'src/utils', 'lib')"),
|
|
10393
10574
|
chunkType: z.enum(["function", "class", "method", "interface", "type", "enum", "struct", "impl", "trait", "module", "other"]).optional().describe("Filter by code chunk type")
|
|
10394
10575
|
},
|
|
10395
|
-
async execute(args) {
|
|
10396
|
-
const indexer =
|
|
10576
|
+
async execute(args, context) {
|
|
10577
|
+
const indexer = getIndexerForProject(context?.worktree);
|
|
10397
10578
|
const results = await indexer.search(args.query, args.limit ?? 10, {
|
|
10398
10579
|
fileType: args.fileType,
|
|
10399
10580
|
directory: args.directory,
|
|
@@ -10411,16 +10592,17 @@ var index_codebase = (0, import_plugin.tool)({
|
|
|
10411
10592
|
verbose: z.boolean().optional().default(false).describe("Show detailed info about skipped files and parsing failures")
|
|
10412
10593
|
},
|
|
10413
10594
|
async execute(args, context) {
|
|
10414
|
-
|
|
10595
|
+
const projectRoot = context?.worktree || defaultProjectRoot;
|
|
10596
|
+
let indexer = getIndexerForProject(projectRoot);
|
|
10415
10597
|
if (args.estimateOnly) {
|
|
10416
10598
|
const estimate = await indexer.estimateCost();
|
|
10417
10599
|
return formatCostEstimate(estimate);
|
|
10418
10600
|
}
|
|
10419
10601
|
if (args.force) {
|
|
10420
|
-
if (shouldForceLocalizeProjectIndex()) {
|
|
10421
|
-
materializeLocalProjectConfig(
|
|
10422
|
-
|
|
10423
|
-
indexer =
|
|
10602
|
+
if (shouldForceLocalizeProjectIndex(projectRoot)) {
|
|
10603
|
+
materializeLocalProjectConfig(projectRoot, loadProjectConfigLayer(projectRoot));
|
|
10604
|
+
refreshIndexerForDirectory(projectRoot);
|
|
10605
|
+
indexer = getIndexerForProject(projectRoot);
|
|
10424
10606
|
}
|
|
10425
10607
|
await indexer.clearIndex();
|
|
10426
10608
|
}
|
|
@@ -10443,8 +10625,8 @@ var index_codebase = (0, import_plugin.tool)({
|
|
|
10443
10625
|
var index_status = (0, import_plugin.tool)({
|
|
10444
10626
|
description: "Check the status of the codebase index. Shows whether the codebase is indexed, how many chunks are stored, and the embedding provider being used.",
|
|
10445
10627
|
args: {},
|
|
10446
|
-
async execute() {
|
|
10447
|
-
const indexer =
|
|
10628
|
+
async execute(_args, context) {
|
|
10629
|
+
const indexer = getIndexerForProject(context?.worktree);
|
|
10448
10630
|
const status = await indexer.getStatus();
|
|
10449
10631
|
return formatStatus(status);
|
|
10450
10632
|
}
|
|
@@ -10452,8 +10634,8 @@ var index_status = (0, import_plugin.tool)({
|
|
|
10452
10634
|
var index_health_check = (0, import_plugin.tool)({
|
|
10453
10635
|
description: "Check index health and remove stale entries from deleted files. Run this to clean up the index after files have been deleted.",
|
|
10454
10636
|
args: {},
|
|
10455
|
-
async execute() {
|
|
10456
|
-
const indexer =
|
|
10637
|
+
async execute(_args, context) {
|
|
10638
|
+
const indexer = getIndexerForProject(context?.worktree);
|
|
10457
10639
|
const result = await indexer.healthCheck();
|
|
10458
10640
|
return formatHealthCheck(result);
|
|
10459
10641
|
}
|
|
@@ -10461,8 +10643,8 @@ var index_health_check = (0, import_plugin.tool)({
|
|
|
10461
10643
|
var index_metrics = (0, import_plugin.tool)({
|
|
10462
10644
|
description: "Get metrics and performance statistics for the codebase index. Shows indexing stats, search timings, cache hit rates, and API usage. Requires debug.enabled=true and debug.metrics=true in config.",
|
|
10463
10645
|
args: {},
|
|
10464
|
-
async execute() {
|
|
10465
|
-
const indexer =
|
|
10646
|
+
async execute(_args, context) {
|
|
10647
|
+
const indexer = getIndexerForProject(context?.worktree);
|
|
10466
10648
|
const logger = indexer.getLogger();
|
|
10467
10649
|
if (!logger.isEnabled()) {
|
|
10468
10650
|
return 'Debug mode is disabled. Enable it in your config:\n\n```json\n{\n "debug": {\n "enabled": true,\n "metrics": true\n }\n}\n```';
|
|
@@ -10480,8 +10662,8 @@ var index_logs = (0, import_plugin.tool)({
|
|
|
10480
10662
|
category: z.enum(["search", "embedding", "cache", "gc", "branch", "general"]).optional().describe("Filter by log category"),
|
|
10481
10663
|
level: z.enum(["error", "warn", "info", "debug"]).optional().describe("Filter by minimum log level")
|
|
10482
10664
|
},
|
|
10483
|
-
async execute(args) {
|
|
10484
|
-
const indexer =
|
|
10665
|
+
async execute(args, context) {
|
|
10666
|
+
const indexer = getIndexerForProject(context?.worktree);
|
|
10485
10667
|
const logger = indexer.getLogger();
|
|
10486
10668
|
if (!logger.isEnabled()) {
|
|
10487
10669
|
return 'Debug mode is disabled. Enable it in your config:\n\n```json\n{\n "debug": {\n "enabled": true\n }\n}\n```';
|
|
@@ -10507,8 +10689,8 @@ var find_similar = (0, import_plugin.tool)({
|
|
|
10507
10689
|
chunkType: z.enum(["function", "class", "method", "interface", "type", "enum", "struct", "impl", "trait", "module", "other"]).optional().describe("Filter by code chunk type"),
|
|
10508
10690
|
excludeFile: z.string().optional().describe("Exclude results from this file path (useful when searching for duplicates of code from a specific file)")
|
|
10509
10691
|
},
|
|
10510
|
-
async execute(args) {
|
|
10511
|
-
const indexer =
|
|
10692
|
+
async execute(args, context) {
|
|
10693
|
+
const indexer = getIndexerForProject(context?.worktree);
|
|
10512
10694
|
const results = await indexer.findSimilar(args.code, args.limit, {
|
|
10513
10695
|
fileType: args.fileType,
|
|
10514
10696
|
directory: args.directory,
|
|
@@ -10531,8 +10713,8 @@ var codebase_search = (0, import_plugin.tool)({
|
|
|
10531
10713
|
chunkType: z.enum(["function", "class", "method", "interface", "type", "enum", "struct", "impl", "trait", "module", "other"]).optional().describe("Filter by code chunk type"),
|
|
10532
10714
|
contextLines: z.number().optional().describe("Number of extra lines to include before/after each match (default: 0)")
|
|
10533
10715
|
},
|
|
10534
|
-
async execute(args) {
|
|
10535
|
-
const indexer =
|
|
10716
|
+
async execute(args, context) {
|
|
10717
|
+
const indexer = getIndexerForProject(context?.worktree);
|
|
10536
10718
|
const results = await indexer.search(args.query, args.limit ?? 5, {
|
|
10537
10719
|
fileType: args.fileType,
|
|
10538
10720
|
directory: args.directory,
|
|
@@ -10553,8 +10735,8 @@ var implementation_lookup = (0, import_plugin.tool)({
|
|
|
10553
10735
|
fileType: z.string().optional().describe("Filter by file extension (e.g., 'ts', 'py')"),
|
|
10554
10736
|
directory: z.string().optional().describe("Filter by directory path (e.g., 'src/utils')")
|
|
10555
10737
|
},
|
|
10556
|
-
async execute(args) {
|
|
10557
|
-
const indexer =
|
|
10738
|
+
async execute(args, context) {
|
|
10739
|
+
const indexer = getIndexerForProject(context?.worktree);
|
|
10558
10740
|
const results = await indexer.search(args.query, args.limit ?? 5, {
|
|
10559
10741
|
fileType: args.fileType,
|
|
10560
10742
|
directory: args.directory,
|
|
@@ -10570,8 +10752,8 @@ var call_graph = (0, import_plugin.tool)({
|
|
|
10570
10752
|
direction: z.enum(["callers", "callees"]).default("callers").describe("Direction: 'callers' finds who calls this function, 'callees' finds what this function calls"),
|
|
10571
10753
|
symbolId: z.string().optional().describe("Symbol ID (required for 'callees' direction, returned by previous call_graph queries)")
|
|
10572
10754
|
},
|
|
10573
|
-
async execute(args) {
|
|
10574
|
-
const indexer =
|
|
10755
|
+
async execute(args, context) {
|
|
10756
|
+
const indexer = getIndexerForProject(context?.worktree);
|
|
10575
10757
|
if (args.direction === "callees") {
|
|
10576
10758
|
if (!args.symbolId) {
|
|
10577
10759
|
return "Error: 'symbolId' is required when direction is 'callees'. First use direction='callers' to find the symbol ID.";
|
|
@@ -10600,38 +10782,67 @@ var add_knowledge_base = (0, import_plugin.tool)({
|
|
|
10600
10782
|
args: {
|
|
10601
10783
|
path: z.string().describe("Path to the folder to add as a knowledge base (absolute or relative to project root)")
|
|
10602
10784
|
},
|
|
10603
|
-
async execute(args) {
|
|
10785
|
+
async execute(args, context) {
|
|
10786
|
+
const projectRoot = context?.worktree || defaultProjectRoot;
|
|
10604
10787
|
const inputPath = args.path.trim();
|
|
10605
|
-
const
|
|
10606
|
-
|
|
10607
|
-
|
|
10788
|
+
const normalizedPath = path15.resolve(
|
|
10789
|
+
path15.isAbsolute(inputPath) ? inputPath : resolveKnowledgeBasePath(inputPath, projectRoot)
|
|
10790
|
+
);
|
|
10791
|
+
if (!(0, import_fs9.existsSync)(normalizedPath)) {
|
|
10792
|
+
return `Error: Directory does not exist: ${normalizedPath}`;
|
|
10793
|
+
}
|
|
10794
|
+
let realPath;
|
|
10795
|
+
try {
|
|
10796
|
+
realPath = (0, import_fs9.realpathSync)(normalizedPath);
|
|
10797
|
+
} catch {
|
|
10798
|
+
return `Error: Cannot resolve path: ${normalizedPath}`;
|
|
10799
|
+
}
|
|
10800
|
+
const blockedPrefixes = [
|
|
10801
|
+
"/etc",
|
|
10802
|
+
"/proc",
|
|
10803
|
+
"/sys",
|
|
10804
|
+
"/dev",
|
|
10805
|
+
"/boot",
|
|
10806
|
+
"/root",
|
|
10807
|
+
"/var/run",
|
|
10808
|
+
"/var/log"
|
|
10809
|
+
];
|
|
10810
|
+
const homeDir = os5.homedir();
|
|
10811
|
+
const sensitiveDotDirs = [".ssh", ".gnupg", ".aws", ".config/gcloud", ".docker", ".kube"];
|
|
10812
|
+
for (const prefix of blockedPrefixes) {
|
|
10813
|
+
if (realPath === prefix || realPath.startsWith(prefix + "/")) {
|
|
10814
|
+
return `Error: Adding system directory as knowledge base is not allowed: ${normalizedPath}`;
|
|
10815
|
+
}
|
|
10816
|
+
}
|
|
10817
|
+
for (const dotDir of sensitiveDotDirs) {
|
|
10818
|
+
const sensitiveDir = path15.join(homeDir, dotDir);
|
|
10819
|
+
if (realPath === sensitiveDir || realPath.startsWith(sensitiveDir + "/")) {
|
|
10820
|
+
return `Error: Adding sensitive directory as knowledge base is not allowed: ${normalizedPath}`;
|
|
10821
|
+
}
|
|
10608
10822
|
}
|
|
10609
10823
|
try {
|
|
10610
|
-
const stat4 = (0,
|
|
10824
|
+
const stat4 = (0, import_fs9.statSync)(normalizedPath);
|
|
10611
10825
|
if (!stat4.isDirectory()) {
|
|
10612
|
-
return `Error: Path is not a directory: ${
|
|
10826
|
+
return `Error: Path is not a directory: ${normalizedPath}`;
|
|
10613
10827
|
}
|
|
10614
10828
|
} catch (error) {
|
|
10615
|
-
return `Error: Cannot access directory: ${
|
|
10829
|
+
return `Error: Cannot access directory: ${normalizedPath} - ${error instanceof Error ? error.message : String(error)}`;
|
|
10616
10830
|
}
|
|
10617
|
-
const config = loadEditableConfig();
|
|
10618
|
-
const knowledgeBases =
|
|
10619
|
-
const
|
|
10620
|
-
const alreadyExists = knowledgeBases.some(
|
|
10621
|
-
(kb) => path9.normalize(path9.isAbsolute(kb) ? kb : path9.resolve(sharedProjectRoot, kb)) === normalizedPath
|
|
10622
|
-
);
|
|
10831
|
+
const config = loadEditableConfig(projectRoot);
|
|
10832
|
+
const knowledgeBases = ensureStringArray(config.knowledgeBases);
|
|
10833
|
+
const alreadyExists = hasMatchingKnowledgeBasePath(knowledgeBases, normalizedPath, projectRoot);
|
|
10623
10834
|
if (alreadyExists) {
|
|
10624
|
-
return `Knowledge base already configured: ${
|
|
10835
|
+
return `Knowledge base already configured: ${normalizedPath}`;
|
|
10625
10836
|
}
|
|
10626
|
-
knowledgeBases.push(
|
|
10837
|
+
knowledgeBases.push(normalizedPath);
|
|
10627
10838
|
config.knowledgeBases = knowledgeBases;
|
|
10628
|
-
saveConfig(config);
|
|
10629
|
-
|
|
10630
|
-
let result = `${
|
|
10839
|
+
saveConfig(projectRoot, config);
|
|
10840
|
+
refreshIndexerForDirectory(projectRoot);
|
|
10841
|
+
let result = `${normalizedPath}
|
|
10631
10842
|
`;
|
|
10632
10843
|
result += `Total knowledge bases: ${knowledgeBases.length}
|
|
10633
10844
|
`;
|
|
10634
|
-
result += `Config saved to: ${getConfigPath()}
|
|
10845
|
+
result += `Config saved to: ${getConfigPath(projectRoot)}
|
|
10635
10846
|
`;
|
|
10636
10847
|
result += `
|
|
10637
10848
|
Run /index to rebuild the index with the new knowledge base.`;
|
|
@@ -10641,9 +10852,10 @@ Run /index to rebuild the index with the new knowledge base.`;
|
|
|
10641
10852
|
var list_knowledge_bases = (0, import_plugin.tool)({
|
|
10642
10853
|
description: "List all configured knowledge base folders that are indexed alongside the main project.",
|
|
10643
10854
|
args: {},
|
|
10644
|
-
async execute() {
|
|
10645
|
-
const
|
|
10646
|
-
const
|
|
10855
|
+
async execute(_args, context) {
|
|
10856
|
+
const projectRoot = context?.worktree || defaultProjectRoot;
|
|
10857
|
+
const config = loadRuntimeConfig(projectRoot);
|
|
10858
|
+
const knowledgeBases = ensureStringArray(config.knowledgeBases);
|
|
10647
10859
|
if (knowledgeBases.length === 0) {
|
|
10648
10860
|
return "No knowledge bases configured. Use add_knowledge_base to add folders.";
|
|
10649
10861
|
}
|
|
@@ -10652,8 +10864,8 @@ var list_knowledge_bases = (0, import_plugin.tool)({
|
|
|
10652
10864
|
`;
|
|
10653
10865
|
for (let i = 0; i < knowledgeBases.length; i++) {
|
|
10654
10866
|
const kb = knowledgeBases[i];
|
|
10655
|
-
const resolvedPath =
|
|
10656
|
-
const exists = (0,
|
|
10867
|
+
const resolvedPath = resolveKnowledgeBasePath(kb, projectRoot);
|
|
10868
|
+
const exists = (0, import_fs9.existsSync)(resolvedPath);
|
|
10657
10869
|
result += `[${i + 1}] ${kb}
|
|
10658
10870
|
`;
|
|
10659
10871
|
result += ` Resolved: ${resolvedPath}
|
|
@@ -10662,7 +10874,7 @@ var list_knowledge_bases = (0, import_plugin.tool)({
|
|
|
10662
10874
|
`;
|
|
10663
10875
|
if (exists) {
|
|
10664
10876
|
try {
|
|
10665
|
-
const stat4 = (0,
|
|
10877
|
+
const stat4 = (0, import_fs9.statSync)(resolvedPath);
|
|
10666
10878
|
result += ` Type: ${stat4.isDirectory() ? "Directory" : "File"}
|
|
10667
10879
|
`;
|
|
10668
10880
|
} catch {
|
|
@@ -10670,7 +10882,7 @@ var list_knowledge_bases = (0, import_plugin.tool)({
|
|
|
10670
10882
|
}
|
|
10671
10883
|
result += "\n";
|
|
10672
10884
|
}
|
|
10673
|
-
result += `Config file: ${getConfigPath()}`;
|
|
10885
|
+
result += `Config file: ${getConfigPath(projectRoot)}`;
|
|
10674
10886
|
return result;
|
|
10675
10887
|
}
|
|
10676
10888
|
});
|
|
@@ -10679,17 +10891,15 @@ var remove_knowledge_base = (0, import_plugin.tool)({
|
|
|
10679
10891
|
args: {
|
|
10680
10892
|
path: z.string().describe("Path of the knowledge base to remove (must match the configured path exactly)")
|
|
10681
10893
|
},
|
|
10682
|
-
async execute(args) {
|
|
10894
|
+
async execute(args, context) {
|
|
10895
|
+
const projectRoot = context?.worktree || defaultProjectRoot;
|
|
10683
10896
|
const inputPath = args.path.trim();
|
|
10684
|
-
const config = loadEditableConfig();
|
|
10685
|
-
const knowledgeBases =
|
|
10897
|
+
const config = loadEditableConfig(projectRoot);
|
|
10898
|
+
const knowledgeBases = ensureStringArray(config.knowledgeBases);
|
|
10686
10899
|
if (knowledgeBases.length === 0) {
|
|
10687
10900
|
return "No knowledge bases configured.";
|
|
10688
10901
|
}
|
|
10689
|
-
const
|
|
10690
|
-
const index = knowledgeBases.findIndex(
|
|
10691
|
-
(kb) => path9.normalize(kb) === normalizedInput || path9.normalize(path9.isAbsolute(kb) ? kb : path9.resolve(sharedProjectRoot, kb)) === normalizedInput
|
|
10692
|
-
);
|
|
10902
|
+
const index = findKnowledgeBasePathIndex(knowledgeBases, inputPath, projectRoot);
|
|
10693
10903
|
if (index === -1) {
|
|
10694
10904
|
let result2 = `Knowledge base not found: ${inputPath}
|
|
10695
10905
|
|
|
@@ -10704,14 +10914,14 @@ var remove_knowledge_base = (0, import_plugin.tool)({
|
|
|
10704
10914
|
}
|
|
10705
10915
|
const removed = knowledgeBases.splice(index, 1)[0];
|
|
10706
10916
|
config.knowledgeBases = knowledgeBases;
|
|
10707
|
-
saveConfig(config);
|
|
10708
|
-
|
|
10917
|
+
saveConfig(projectRoot, config);
|
|
10918
|
+
refreshIndexerForDirectory(projectRoot);
|
|
10709
10919
|
let result = `Removed: ${removed}
|
|
10710
10920
|
|
|
10711
10921
|
`;
|
|
10712
10922
|
result += `Remaining knowledge bases: ${knowledgeBases.length}
|
|
10713
10923
|
`;
|
|
10714
|
-
result += `Config saved to: ${getConfigPath()}
|
|
10924
|
+
result += `Config saved to: ${getConfigPath(projectRoot)}
|
|
10715
10925
|
`;
|
|
10716
10926
|
result += `
|
|
10717
10927
|
Run /index to rebuild the index without the removed knowledge base.`;
|
|
@@ -10720,8 +10930,8 @@ Run /index to rebuild the index without the removed knowledge base.`;
|
|
|
10720
10930
|
});
|
|
10721
10931
|
|
|
10722
10932
|
// src/commands/loader.ts
|
|
10723
|
-
var
|
|
10724
|
-
var
|
|
10933
|
+
var import_fs10 = require("fs");
|
|
10934
|
+
var path16 = __toESM(require("path"), 1);
|
|
10725
10935
|
function parseFrontmatter(content) {
|
|
10726
10936
|
const frontmatterRegex = /^---\s*\n([\s\S]*?)\n---\s*\n([\s\S]*)$/;
|
|
10727
10937
|
const match = content.match(frontmatterRegex);
|
|
@@ -10742,15 +10952,21 @@ function parseFrontmatter(content) {
|
|
|
10742
10952
|
}
|
|
10743
10953
|
function loadCommandsFromDirectory(commandsDir) {
|
|
10744
10954
|
const commands = /* @__PURE__ */ new Map();
|
|
10745
|
-
if (!(0,
|
|
10955
|
+
if (!(0, import_fs10.existsSync)(commandsDir)) {
|
|
10746
10956
|
return commands;
|
|
10747
10957
|
}
|
|
10748
|
-
const files = (0,
|
|
10958
|
+
const files = (0, import_fs10.readdirSync)(commandsDir).filter((f) => f.endsWith(".md"));
|
|
10749
10959
|
for (const file of files) {
|
|
10750
|
-
const filePath =
|
|
10751
|
-
|
|
10960
|
+
const filePath = path16.join(commandsDir, file);
|
|
10961
|
+
let content;
|
|
10962
|
+
try {
|
|
10963
|
+
content = (0, import_fs10.readFileSync)(filePath, "utf-8");
|
|
10964
|
+
} catch (error) {
|
|
10965
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
10966
|
+
throw new Error(`Failed to load command file ${filePath}: ${message}`);
|
|
10967
|
+
}
|
|
10752
10968
|
const { frontmatter, body } = parseFrontmatter(content);
|
|
10753
|
-
const name =
|
|
10969
|
+
const name = path16.basename(file, ".md");
|
|
10754
10970
|
const description = frontmatter.description || `Run the ${name} command`;
|
|
10755
10971
|
commands.set(name, {
|
|
10756
10972
|
description,
|
|
@@ -10760,7 +10976,7 @@ function loadCommandsFromDirectory(commandsDir) {
|
|
|
10760
10976
|
return commands;
|
|
10761
10977
|
}
|
|
10762
10978
|
|
|
10763
|
-
// src/routing-hints.ts
|
|
10979
|
+
// src/routing-hints-patterns.ts
|
|
10764
10980
|
var EXTERNAL_HINTS = [
|
|
10765
10981
|
"docs",
|
|
10766
10982
|
"documentation",
|
|
@@ -10851,6 +11067,8 @@ var SNAKE_PATTERN = /\b[a-z0-9]+_[a-z0-9_]+\b/g;
|
|
|
10851
11067
|
var KEBAB_PATTERN = /\b[a-z0-9]+-[a-z0-9-]+\b/g;
|
|
10852
11068
|
var BACKTICK_IDENTIFIER_PATTERN = /`([^`]+)`/g;
|
|
10853
11069
|
var BACKTICK_IDENTIFIER_PRESENCE_PATTERN = /`([^`]+)`/;
|
|
11070
|
+
var DOUBLE_QUOTED_PATTERN = /"[^"]+"/;
|
|
11071
|
+
var SINGLE_QUOTED_PATTERN = /'[^']+'/;
|
|
10854
11072
|
function normalizeText(text) {
|
|
10855
11073
|
return text.trim().replace(/\s+/g, " ");
|
|
10856
11074
|
}
|
|
@@ -10863,6 +11081,21 @@ function countWords(text) {
|
|
|
10863
11081
|
}
|
|
10864
11082
|
return text.split(/\s+/).filter(Boolean).length;
|
|
10865
11083
|
}
|
|
11084
|
+
function isExternalLookup(text) {
|
|
11085
|
+
return URL_PATTERN.test(text) || includesHint(text, EXTERNAL_HINTS);
|
|
11086
|
+
}
|
|
11087
|
+
function hasConceptualDiscoveryHint(text) {
|
|
11088
|
+
return includesHint(text, CONCEPTUAL_DISCOVERY_HINTS);
|
|
11089
|
+
}
|
|
11090
|
+
function hasDefinitionHint(text) {
|
|
11091
|
+
return includesHint(text, DEFINITION_HINTS);
|
|
11092
|
+
}
|
|
11093
|
+
function hasExactMatchHint(text) {
|
|
11094
|
+
return includesHint(text, EXACT_MATCH_HINTS);
|
|
11095
|
+
}
|
|
11096
|
+
function hasNonDiscoveryHint(text) {
|
|
11097
|
+
return includesHint(text, NON_DISCOVERY_HINTS);
|
|
11098
|
+
}
|
|
10866
11099
|
function hasIdentifierShape(text) {
|
|
10867
11100
|
const matches = [
|
|
10868
11101
|
...text.match(CAMEL_OR_PASCAL_PATTERN) ?? [],
|
|
@@ -10878,11 +11111,13 @@ function hasIdentifierShape(text) {
|
|
|
10878
11111
|
});
|
|
10879
11112
|
}
|
|
10880
11113
|
function containsQuotedIdentifier(text) {
|
|
10881
|
-
return BACKTICK_IDENTIFIER_PRESENCE_PATTERN.test(text) ||
|
|
11114
|
+
return BACKTICK_IDENTIFIER_PRESENCE_PATTERN.test(text) || DOUBLE_QUOTED_PATTERN.test(text) || SINGLE_QUOTED_PATTERN.test(text);
|
|
10882
11115
|
}
|
|
10883
11116
|
function looksLikeDirectPath(text) {
|
|
10884
11117
|
return FILE_PATH_PATTERN.test(text) || /\b[a-z0-9_-]+\.(ts|tsx|js|jsx|rs|py|go|java|json|md|yaml|yml)\b/i.test(text);
|
|
10885
11118
|
}
|
|
11119
|
+
|
|
11120
|
+
// src/routing-hints.ts
|
|
10886
11121
|
function extractUserText(parts) {
|
|
10887
11122
|
return normalizeText(
|
|
10888
11123
|
parts.filter((part) => part.type === "text" && typeof part.text === "string").map((part) => part.text ?? "").join(" ")
|
|
@@ -10898,21 +11133,21 @@ function assessRoutingIntent(text) {
|
|
|
10898
11133
|
reason: "empty_text"
|
|
10899
11134
|
};
|
|
10900
11135
|
}
|
|
10901
|
-
if (
|
|
11136
|
+
if (isExternalLookup(lowered)) {
|
|
10902
11137
|
return {
|
|
10903
11138
|
intent: "external",
|
|
10904
11139
|
text: normalizedText,
|
|
10905
11140
|
reason: "external_lookup"
|
|
10906
11141
|
};
|
|
10907
11142
|
}
|
|
10908
|
-
const
|
|
10909
|
-
const
|
|
10910
|
-
const
|
|
10911
|
-
const
|
|
11143
|
+
const matchedConceptualHint = hasConceptualDiscoveryHint(lowered);
|
|
11144
|
+
const matchedDefinitionHint = hasDefinitionHint(lowered);
|
|
11145
|
+
const matchedExactMatchHint = hasExactMatchHint(lowered);
|
|
11146
|
+
const matchedNonDiscoveryHint = hasNonDiscoveryHint(lowered);
|
|
10912
11147
|
const hasIdentifier = hasIdentifierShape(normalizedText);
|
|
10913
11148
|
const hasQuotedIdentifier = containsQuotedIdentifier(normalizedText);
|
|
10914
11149
|
const shortQuery = countWords(lowered) <= 10;
|
|
10915
|
-
if (
|
|
11150
|
+
if (matchedNonDiscoveryHint && !matchedConceptualHint) {
|
|
10916
11151
|
return {
|
|
10917
11152
|
intent: "other",
|
|
10918
11153
|
text: normalizedText,
|
|
@@ -10926,21 +11161,21 @@ function assessRoutingIntent(text) {
|
|
|
10926
11161
|
reason: "direct_path_reference"
|
|
10927
11162
|
};
|
|
10928
11163
|
}
|
|
10929
|
-
if ((
|
|
11164
|
+
if ((matchedDefinitionHint || lowered.includes("where is") || lowered.includes("where are")) && (lowered.includes("defined") || lowered.includes("definition"))) {
|
|
10930
11165
|
return {
|
|
10931
11166
|
intent: "definition_lookup",
|
|
10932
11167
|
text: normalizedText,
|
|
10933
11168
|
reason: "definition_lookup_request"
|
|
10934
11169
|
};
|
|
10935
11170
|
}
|
|
10936
|
-
if ((
|
|
11171
|
+
if ((matchedExactMatchHint || hasQuotedIdentifier || hasIdentifier) && !matchedConceptualHint && shortQuery) {
|
|
10937
11172
|
return {
|
|
10938
11173
|
intent: "exact_identifier",
|
|
10939
11174
|
text: normalizedText,
|
|
10940
|
-
reason:
|
|
11175
|
+
reason: matchedExactMatchHint || hasQuotedIdentifier ? "exact_match_request" : "identifier_shaped_query"
|
|
10941
11176
|
};
|
|
10942
11177
|
}
|
|
10943
|
-
if (
|
|
11178
|
+
if (matchedConceptualHint) {
|
|
10944
11179
|
return {
|
|
10945
11180
|
intent: "local_conceptual",
|
|
10946
11181
|
text: normalizedText,
|
|
@@ -11030,33 +11265,55 @@ var RoutingHintController = class {
|
|
|
11030
11265
|
|
|
11031
11266
|
// src/index.ts
|
|
11032
11267
|
var import_meta2 = {};
|
|
11033
|
-
var
|
|
11034
|
-
function replaceActiveWatcher(nextWatcher) {
|
|
11035
|
-
|
|
11036
|
-
|
|
11268
|
+
var activeWatchers = /* @__PURE__ */ new Map();
|
|
11269
|
+
function replaceActiveWatcher(projectRoot, nextWatcher) {
|
|
11270
|
+
const existing = activeWatchers.get(projectRoot);
|
|
11271
|
+
if (existing) {
|
|
11272
|
+
existing.stop();
|
|
11273
|
+
activeWatchers.delete(projectRoot);
|
|
11274
|
+
}
|
|
11275
|
+
if (nextWatcher) {
|
|
11276
|
+
activeWatchers.set(projectRoot, nextWatcher);
|
|
11277
|
+
}
|
|
11037
11278
|
}
|
|
11038
11279
|
function getCommandsDir() {
|
|
11039
11280
|
let currentDir = process.cwd();
|
|
11040
11281
|
if (typeof import_meta2 !== "undefined" && import_meta2.url) {
|
|
11041
|
-
currentDir =
|
|
11282
|
+
currentDir = path17.dirname((0, import_url2.fileURLToPath)(import_meta2.url));
|
|
11283
|
+
}
|
|
11284
|
+
return path17.join(currentDir, "..", "commands");
|
|
11285
|
+
}
|
|
11286
|
+
function appendRoutingHints(output, hints, preferredRole) {
|
|
11287
|
+
const preferredBucket = preferredRole === "developer" ? output.developer : output.system;
|
|
11288
|
+
if (Array.isArray(preferredBucket)) {
|
|
11289
|
+
preferredBucket.push(...hints);
|
|
11290
|
+
return;
|
|
11291
|
+
}
|
|
11292
|
+
if (Array.isArray(output.system)) {
|
|
11293
|
+
output.system.push(...hints);
|
|
11042
11294
|
}
|
|
11043
|
-
return path11.join(currentDir, "..", "commands");
|
|
11044
11295
|
}
|
|
11045
|
-
var plugin = async ({ directory }) => {
|
|
11296
|
+
var plugin = async ({ directory, worktree }) => {
|
|
11046
11297
|
try {
|
|
11047
|
-
const projectRoot = directory;
|
|
11298
|
+
const projectRoot = worktree || directory;
|
|
11048
11299
|
const rawConfig = loadMergedConfig(projectRoot);
|
|
11049
11300
|
const config = parseConfig(rawConfig);
|
|
11050
11301
|
initializeTools(projectRoot, config);
|
|
11051
|
-
const
|
|
11052
|
-
const routingHints = config.search.routingHints ? new RoutingHintController(() =>
|
|
11053
|
-
const
|
|
11054
|
-
|
|
11302
|
+
const getProjectIndexer = () => getIndexerForProject(projectRoot);
|
|
11303
|
+
const routingHints = config.search.routingHints ? new RoutingHintController(() => getProjectIndexer().getStatus()) : null;
|
|
11304
|
+
const isHomeDir = path17.resolve(projectRoot) === path17.resolve(os6.homedir());
|
|
11305
|
+
const isValidProject = !isHomeDir && (!config.indexing.requireProjectMarker || hasProjectMarker(projectRoot));
|
|
11306
|
+
if (isHomeDir) {
|
|
11307
|
+
console.warn(
|
|
11308
|
+
`[codebase-index] Refusing to watch or index home directory "${projectRoot}". Open a specific project directory instead.`
|
|
11309
|
+
);
|
|
11310
|
+
} else if (!isValidProject) {
|
|
11055
11311
|
console.warn(
|
|
11056
11312
|
`[codebase-index] Skipping file watching and auto-indexing: no project marker found in "${projectRoot}". Set "indexing.requireProjectMarker": false in config to override.`
|
|
11057
11313
|
);
|
|
11058
11314
|
}
|
|
11059
11315
|
if (config.indexing.autoIndex && isValidProject) {
|
|
11316
|
+
const indexer = getProjectIndexer();
|
|
11060
11317
|
indexer.initialize().then(() => {
|
|
11061
11318
|
indexer.index().catch(() => {
|
|
11062
11319
|
});
|
|
@@ -11064,9 +11321,9 @@ var plugin = async ({ directory }) => {
|
|
|
11064
11321
|
});
|
|
11065
11322
|
}
|
|
11066
11323
|
if (config.indexing.watchFiles && isValidProject) {
|
|
11067
|
-
replaceActiveWatcher(createWatcherWithIndexer(
|
|
11324
|
+
replaceActiveWatcher(projectRoot, createWatcherWithIndexer(getProjectIndexer, projectRoot, config));
|
|
11068
11325
|
} else {
|
|
11069
|
-
replaceActiveWatcher(null);
|
|
11326
|
+
replaceActiveWatcher(projectRoot, null);
|
|
11070
11327
|
}
|
|
11071
11328
|
return {
|
|
11072
11329
|
tool: {
|
|
@@ -11088,8 +11345,18 @@ var plugin = async ({ directory }) => {
|
|
|
11088
11345
|
routingHints?.observeUserMessage(input.sessionID, output.parts);
|
|
11089
11346
|
},
|
|
11090
11347
|
async "experimental.chat.system.transform"(input, output) {
|
|
11348
|
+
if (config.search.routingHintRole !== "system") {
|
|
11349
|
+
return;
|
|
11350
|
+
}
|
|
11351
|
+
const hints = await routingHints?.getSystemHints(input.sessionID) ?? [];
|
|
11352
|
+
appendRoutingHints(output, hints, "system");
|
|
11353
|
+
},
|
|
11354
|
+
async "experimental.chat.developer.transform"(input, output) {
|
|
11355
|
+
if (config.search.routingHintRole !== "developer") {
|
|
11356
|
+
return;
|
|
11357
|
+
}
|
|
11091
11358
|
const hints = await routingHints?.getSystemHints(input.sessionID) ?? [];
|
|
11092
|
-
output
|
|
11359
|
+
appendRoutingHints(output, hints, "developer");
|
|
11093
11360
|
},
|
|
11094
11361
|
async "tool.execute.after"(input) {
|
|
11095
11362
|
routingHints?.markToolUsed(input.sessionID, input.tool);
|
|
@@ -11103,8 +11370,8 @@ var plugin = async ({ directory }) => {
|
|
|
11103
11370
|
}
|
|
11104
11371
|
}
|
|
11105
11372
|
};
|
|
11106
|
-
} catch
|
|
11107
|
-
console.error("[codebase-index] Failed to initialize plugin
|
|
11373
|
+
} catch {
|
|
11374
|
+
console.error("[codebase-index] Failed to initialize plugin (check config and network)");
|
|
11108
11375
|
return {
|
|
11109
11376
|
tool: void 0,
|
|
11110
11377
|
async config() {
|