opencode-codebase-index 0.17.1 → 0.18.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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/README.md +45 -8
- package/THIRD_PARTY_LICENSES.md +64 -0
- package/dist/cli.cjs +576 -346
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +582 -352
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +342 -114
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +356 -128
- package/dist/index.js.map +1 -1
- package/dist/pi-extension.cjs +735 -505
- package/dist/pi-extension.cjs.map +1 -1
- package/dist/pi-extension.js +697 -467
- package/dist/pi-extension.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 +2 -1
package/dist/pi-extension.js
CHANGED
|
@@ -668,7 +668,8 @@ var DEFAULT_INCLUDE = [
|
|
|
668
668
|
"**/*.{sh,bash,zsh}",
|
|
669
669
|
"**/*.{txt,html,htm}",
|
|
670
670
|
"**/*.zig",
|
|
671
|
-
"**/*.gd"
|
|
671
|
+
"**/*.gd",
|
|
672
|
+
"**/*.metal"
|
|
672
673
|
];
|
|
673
674
|
var DEFAULT_EXCLUDE = [
|
|
674
675
|
"**/node_modules/**",
|
|
@@ -859,6 +860,9 @@ function isValidProvider(value) {
|
|
|
859
860
|
return typeof value === "string" && Object.keys(EMBEDDING_MODELS).includes(value);
|
|
860
861
|
}
|
|
861
862
|
function isValidModel(value, provider) {
|
|
863
|
+
if (typeof value === "string" && provider === "ollama" && value.trim().length > 0) {
|
|
864
|
+
return true;
|
|
865
|
+
}
|
|
862
866
|
return typeof value === "string" && Object.keys(EMBEDDING_MODELS[provider]).includes(value);
|
|
863
867
|
}
|
|
864
868
|
function isValidScope(value) {
|
|
@@ -1058,6 +1062,9 @@ function loadOpenCodeAuth() {
|
|
|
1058
1062
|
return {};
|
|
1059
1063
|
}
|
|
1060
1064
|
async function detectEmbeddingProvider(preferredProvider, model) {
|
|
1065
|
+
if (preferredProvider === "ollama") {
|
|
1066
|
+
return detectOllamaProvider(model);
|
|
1067
|
+
}
|
|
1061
1068
|
const credentials = await getProviderCredentials(preferredProvider);
|
|
1062
1069
|
if (credentials) {
|
|
1063
1070
|
if (!model) {
|
|
@@ -1073,10 +1080,16 @@ async function detectEmbeddingProvider(preferredProvider, model) {
|
|
|
1073
1080
|
);
|
|
1074
1081
|
}
|
|
1075
1082
|
const providerModels = EMBEDDING_MODELS[preferredProvider];
|
|
1083
|
+
const modelInfo = Object.values(providerModels).find((candidate) => candidate.model === model);
|
|
1084
|
+
if (!modelInfo) {
|
|
1085
|
+
throw new Error(
|
|
1086
|
+
`Model '${model}' is not supported by provider '${preferredProvider}'`
|
|
1087
|
+
);
|
|
1088
|
+
}
|
|
1076
1089
|
return {
|
|
1077
1090
|
provider: preferredProvider,
|
|
1078
1091
|
credentials,
|
|
1079
|
-
modelInfo
|
|
1092
|
+
modelInfo
|
|
1080
1093
|
};
|
|
1081
1094
|
}
|
|
1082
1095
|
throw new Error(
|
|
@@ -1085,6 +1098,13 @@ async function detectEmbeddingProvider(preferredProvider, model) {
|
|
|
1085
1098
|
}
|
|
1086
1099
|
async function tryDetectProvider() {
|
|
1087
1100
|
for (const provider of autoDetectProviders) {
|
|
1101
|
+
if (provider === "ollama") {
|
|
1102
|
+
const ollamaProvider = await tryDetectOllamaProvider();
|
|
1103
|
+
if (ollamaProvider) {
|
|
1104
|
+
return ollamaProvider;
|
|
1105
|
+
}
|
|
1106
|
+
continue;
|
|
1107
|
+
}
|
|
1088
1108
|
const credentials = await getProviderCredentials(provider);
|
|
1089
1109
|
if (credentials) {
|
|
1090
1110
|
return {
|
|
@@ -1152,32 +1172,105 @@ function getGoogleCredentials() {
|
|
|
1152
1172
|
}
|
|
1153
1173
|
return null;
|
|
1154
1174
|
}
|
|
1155
|
-
async function
|
|
1156
|
-
const
|
|
1175
|
+
async function fetchOllama(url, init) {
|
|
1176
|
+
const controller = new AbortController();
|
|
1177
|
+
const timeoutId = setTimeout(() => controller.abort(), 2e3);
|
|
1157
1178
|
try {
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
const response = await fetch(`${baseUrl}/api/tags`, {
|
|
1161
|
-
signal: controller.signal
|
|
1162
|
-
});
|
|
1179
|
+
return await fetch(url, { ...init, signal: controller.signal });
|
|
1180
|
+
} finally {
|
|
1163
1181
|
clearTimeout(timeoutId);
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
async function getOllamaCredentials() {
|
|
1185
|
+
const baseUrl = (process.env.OLLAMA_HOST || "http://localhost:11434").replace(/\/+$/, "");
|
|
1186
|
+
try {
|
|
1187
|
+
const response = await fetchOllama(`${baseUrl}/api/tags`);
|
|
1164
1188
|
if (response.ok) {
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
if (hasEmbeddingModel) {
|
|
1170
|
-
return {
|
|
1171
|
-
provider: "ollama",
|
|
1172
|
-
baseUrl
|
|
1173
|
-
};
|
|
1174
|
-
}
|
|
1189
|
+
return {
|
|
1190
|
+
provider: "ollama",
|
|
1191
|
+
baseUrl
|
|
1192
|
+
};
|
|
1175
1193
|
}
|
|
1176
1194
|
} catch {
|
|
1177
1195
|
return null;
|
|
1178
1196
|
}
|
|
1179
1197
|
return null;
|
|
1180
1198
|
}
|
|
1199
|
+
function findCatalogOllamaModel(model) {
|
|
1200
|
+
const stableName = model.endsWith(":latest") ? model.slice(0, -":latest".length) : model;
|
|
1201
|
+
return Object.values(EMBEDDING_MODELS.ollama).find((candidate) => candidate.model === stableName) ?? null;
|
|
1202
|
+
}
|
|
1203
|
+
function getPositiveIntegerMetadata(modelInfo, suffix) {
|
|
1204
|
+
const values = Object.entries(modelInfo).filter(([key]) => key.endsWith(suffix)).map(([, value]) => value).filter((value) => typeof value === "number" && Number.isInteger(value) && value > 0);
|
|
1205
|
+
return values.length === 1 ? values[0] : null;
|
|
1206
|
+
}
|
|
1207
|
+
async function fetchOllamaModelInfo(credentials, model) {
|
|
1208
|
+
const response = await fetchOllama(`${credentials.baseUrl}/api/show`, {
|
|
1209
|
+
method: "POST",
|
|
1210
|
+
headers: { "Content-Type": "application/json" },
|
|
1211
|
+
body: JSON.stringify({ model })
|
|
1212
|
+
});
|
|
1213
|
+
if (!response.ok) {
|
|
1214
|
+
return null;
|
|
1215
|
+
}
|
|
1216
|
+
const data = await response.json();
|
|
1217
|
+
if (!data.capabilities?.includes("embedding") || !data.model_info) {
|
|
1218
|
+
return null;
|
|
1219
|
+
}
|
|
1220
|
+
const dimensions = getPositiveIntegerMetadata(data.model_info, ".embedding_length");
|
|
1221
|
+
const maxTokens = getPositiveIntegerMetadata(data.model_info, ".context_length");
|
|
1222
|
+
if (!dimensions || !maxTokens) {
|
|
1223
|
+
return null;
|
|
1224
|
+
}
|
|
1225
|
+
return {
|
|
1226
|
+
provider: "ollama",
|
|
1227
|
+
model,
|
|
1228
|
+
dimensions,
|
|
1229
|
+
maxTokens,
|
|
1230
|
+
costPer1MTokens: 0
|
|
1231
|
+
};
|
|
1232
|
+
}
|
|
1233
|
+
async function listOllamaModels(credentials) {
|
|
1234
|
+
const response = await fetchOllama(`${credentials.baseUrl}/api/tags`);
|
|
1235
|
+
if (!response.ok) {
|
|
1236
|
+
return [];
|
|
1237
|
+
}
|
|
1238
|
+
const data = await response.json();
|
|
1239
|
+
return [...new Set((data.models ?? []).map((entry) => entry.name ?? entry.model).filter((name) => typeof name === "string" && name.trim().length > 0))];
|
|
1240
|
+
}
|
|
1241
|
+
async function detectOllamaProvider(model) {
|
|
1242
|
+
const credentials = await getOllamaCredentials();
|
|
1243
|
+
if (!credentials) {
|
|
1244
|
+
throw new Error("Preferred provider 'ollama' is not configured or authenticated");
|
|
1245
|
+
}
|
|
1246
|
+
const requestedModel = model?.trim();
|
|
1247
|
+
if (requestedModel) {
|
|
1248
|
+
const catalogModel = findCatalogOllamaModel(requestedModel);
|
|
1249
|
+
if (catalogModel) {
|
|
1250
|
+
return { provider: "ollama", credentials, modelInfo: catalogModel };
|
|
1251
|
+
}
|
|
1252
|
+
}
|
|
1253
|
+
const candidates = requestedModel ? [requestedModel] : await listOllamaModels(credentials);
|
|
1254
|
+
for (const candidate of candidates) {
|
|
1255
|
+
const modelInfo = await fetchOllamaModelInfo(credentials, candidate);
|
|
1256
|
+
if (modelInfo) {
|
|
1257
|
+
return {
|
|
1258
|
+
provider: "ollama",
|
|
1259
|
+
credentials,
|
|
1260
|
+
modelInfo: findCatalogOllamaModel(candidate) ?? modelInfo
|
|
1261
|
+
};
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1264
|
+
const detail = model ? `Model '${model}' is not installed or is not embedding-capable` : "No installed embedding-capable Ollama model was found";
|
|
1265
|
+
throw new Error(detail);
|
|
1266
|
+
}
|
|
1267
|
+
async function tryDetectOllamaProvider() {
|
|
1268
|
+
try {
|
|
1269
|
+
return await detectOllamaProvider();
|
|
1270
|
+
} catch {
|
|
1271
|
+
return null;
|
|
1272
|
+
}
|
|
1273
|
+
}
|
|
1181
1274
|
function getProviderDisplayName(provider) {
|
|
1182
1275
|
switch (provider) {
|
|
1183
1276
|
case "github-copilot":
|
|
@@ -1330,10 +1423,6 @@ function formatPrImpact(result) {
|
|
|
1330
1423
|
import { existsSync as existsSync10, realpathSync as realpathSync2, statSync as statSync4 } from "fs";
|
|
1331
1424
|
import * as path16 from "path";
|
|
1332
1425
|
|
|
1333
|
-
// src/config/merger.ts
|
|
1334
|
-
import { existsSync as existsSync5, mkdirSync, readFileSync as readFileSync4, writeFileSync } from "fs";
|
|
1335
|
-
import * as path7 from "path";
|
|
1336
|
-
|
|
1337
1426
|
// src/config/paths.ts
|
|
1338
1427
|
import { existsSync as existsSync4 } from "fs";
|
|
1339
1428
|
import * as os2 from "os";
|
|
@@ -1506,16 +1595,6 @@ function resolveWorktreeFallbackPath(projectRoot3, relativePath) {
|
|
|
1506
1595
|
const fallbackPath = path4.join(mainRepoRoot, relativePath);
|
|
1507
1596
|
return existsSync4(fallbackPath) ? fallbackPath : null;
|
|
1508
1597
|
}
|
|
1509
|
-
function resolveWorktreeFallbackProjectIndexPath(projectRoot3, host) {
|
|
1510
|
-
const inheritedHostPath = resolveWorktreeFallbackPath(projectRoot3, getProjectIndexRelativePath(host));
|
|
1511
|
-
if (inheritedHostPath) {
|
|
1512
|
-
return inheritedHostPath;
|
|
1513
|
-
}
|
|
1514
|
-
if (host !== "opencode") {
|
|
1515
|
-
return resolveWorktreeFallbackPath(projectRoot3, OPENCODE_PROJECT_INDEX_RELATIVE_PATH);
|
|
1516
|
-
}
|
|
1517
|
-
return null;
|
|
1518
|
-
}
|
|
1519
1598
|
function getHostProjectConfigRelativePath(host) {
|
|
1520
1599
|
return getProjectConfigRelativePath(host);
|
|
1521
1600
|
}
|
|
@@ -1620,6 +1699,9 @@ function resolveProjectIndexPath(projectRoot3, scope, host = "opencode") {
|
|
|
1620
1699
|
if (hasHostProjectConfig(projectRoot3, host)) {
|
|
1621
1700
|
return localIndexPath;
|
|
1622
1701
|
}
|
|
1702
|
+
if (resolveWorktreeMainRepoRoot(projectRoot3)) {
|
|
1703
|
+
return localIndexPath;
|
|
1704
|
+
}
|
|
1623
1705
|
const hostFallback = resolveWorktreeFallbackPath(projectRoot3, getProjectIndexRelativePath(host));
|
|
1624
1706
|
if (hostFallback) {
|
|
1625
1707
|
return hostFallback;
|
|
@@ -1633,210 +1715,9 @@ function resolveProjectIndexPath(projectRoot3, scope, host = "opencode") {
|
|
|
1633
1715
|
return localIndexPath;
|
|
1634
1716
|
}
|
|
1635
1717
|
|
|
1636
|
-
// src/config/rebase.ts
|
|
1637
|
-
import * as path6 from "path";
|
|
1638
|
-
|
|
1639
|
-
// src/utils/paths.ts
|
|
1640
|
-
import * as path5 from "path";
|
|
1641
|
-
function normalizePathSeparators(value) {
|
|
1642
|
-
return value.replace(/\\/g, "/");
|
|
1643
|
-
}
|
|
1644
|
-
function isHiddenPathSegment(part) {
|
|
1645
|
-
return part.startsWith(".") && part !== "." && part !== "..";
|
|
1646
|
-
}
|
|
1647
|
-
function isBuildPathSegment(part) {
|
|
1648
|
-
return part.toLowerCase().includes("build");
|
|
1649
|
-
}
|
|
1650
|
-
|
|
1651
|
-
// src/config/rebase.ts
|
|
1652
|
-
function isWithinRoot(rootDir, targetPath) {
|
|
1653
|
-
const relativePath = path6.relative(rootDir, targetPath);
|
|
1654
|
-
return relativePath === "" || !relativePath.startsWith("..") && !path6.isAbsolute(relativePath);
|
|
1655
|
-
}
|
|
1656
|
-
function resolveInheritedKnowledgeBaseEntries(values, sourceRoot, targetRoot) {
|
|
1657
|
-
if (!Array.isArray(values)) {
|
|
1658
|
-
return [];
|
|
1659
|
-
}
|
|
1660
|
-
return values.filter((value) => typeof value === "string").map((value) => {
|
|
1661
|
-
const trimmed = value.trim();
|
|
1662
|
-
if (!trimmed) {
|
|
1663
|
-
return trimmed;
|
|
1664
|
-
}
|
|
1665
|
-
if (path6.isAbsolute(trimmed)) {
|
|
1666
|
-
if (isWithinRoot(sourceRoot, trimmed)) {
|
|
1667
|
-
return normalizePathSeparators(path6.normalize(path6.relative(sourceRoot, trimmed) || "."));
|
|
1668
|
-
}
|
|
1669
|
-
return path6.normalize(trimmed);
|
|
1670
|
-
}
|
|
1671
|
-
const resolvedFromSource = path6.resolve(sourceRoot, trimmed);
|
|
1672
|
-
if (isWithinRoot(sourceRoot, resolvedFromSource)) {
|
|
1673
|
-
return normalizePathSeparators(path6.normalize(trimmed));
|
|
1674
|
-
}
|
|
1675
|
-
return normalizePathSeparators(path6.normalize(path6.relative(targetRoot, resolvedFromSource)));
|
|
1676
|
-
}).filter(Boolean);
|
|
1677
|
-
}
|
|
1678
|
-
|
|
1679
|
-
// src/config/merger.ts
|
|
1680
|
-
var PROJECT_OVERRIDE_KEYS = [
|
|
1681
|
-
"embeddingProvider",
|
|
1682
|
-
"customProvider",
|
|
1683
|
-
"embeddingModel",
|
|
1684
|
-
"reranker",
|
|
1685
|
-
"include",
|
|
1686
|
-
"exclude",
|
|
1687
|
-
"indexing",
|
|
1688
|
-
"search",
|
|
1689
|
-
"debug",
|
|
1690
|
-
"scope"
|
|
1691
|
-
];
|
|
1692
|
-
var MERGE_ARRAY_KEYS = ["knowledgeBases", "additionalInclude"];
|
|
1693
|
-
function isRecord(value) {
|
|
1694
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1695
|
-
}
|
|
1696
|
-
function isStringArray2(value) {
|
|
1697
|
-
return Array.isArray(value) && value.every((item) => typeof item === "string");
|
|
1698
|
-
}
|
|
1699
|
-
function applyProjectOverride(merged, normalizedProjectConfig, globalConfig, key) {
|
|
1700
|
-
if (key in normalizedProjectConfig) {
|
|
1701
|
-
merged[key] = normalizedProjectConfig[key];
|
|
1702
|
-
return;
|
|
1703
|
-
}
|
|
1704
|
-
if (key in globalConfig) {
|
|
1705
|
-
merged[key] = globalConfig[key];
|
|
1706
|
-
}
|
|
1707
|
-
}
|
|
1708
|
-
function mergeUniqueStringArray(values) {
|
|
1709
|
-
return [...new Set(values.map((value) => String(value).trim()))];
|
|
1710
|
-
}
|
|
1711
|
-
function normalizeKnowledgeBasePath(value) {
|
|
1712
|
-
let normalized = path7.normalize(String(value).trim());
|
|
1713
|
-
const root = path7.parse(normalized).root;
|
|
1714
|
-
while (normalized.length > root.length && /[\\/]$/.test(normalized)) {
|
|
1715
|
-
normalized = normalized.slice(0, -1);
|
|
1716
|
-
}
|
|
1717
|
-
return normalized;
|
|
1718
|
-
}
|
|
1719
|
-
function mergeKnowledgeBasePaths(values) {
|
|
1720
|
-
return [...new Set(values.map((value) => normalizeKnowledgeBasePath(value)).filter((value) => value.length > 0))];
|
|
1721
|
-
}
|
|
1722
|
-
function validateConfigLayerShape(rawConfig, filePath) {
|
|
1723
|
-
if (!isRecord(rawConfig)) {
|
|
1724
|
-
throw new Error(`Config file ${filePath} must contain a JSON object at the root.`);
|
|
1725
|
-
}
|
|
1726
|
-
if (rawConfig.knowledgeBases !== void 0 && !isStringArray2(rawConfig.knowledgeBases)) {
|
|
1727
|
-
throw new Error(`Config file ${filePath} field 'knowledgeBases' must be an array of strings.`);
|
|
1728
|
-
}
|
|
1729
|
-
if (rawConfig.additionalInclude !== void 0 && !isStringArray2(rawConfig.additionalInclude)) {
|
|
1730
|
-
throw new Error(`Config file ${filePath} field 'additionalInclude' must be an array of strings.`);
|
|
1731
|
-
}
|
|
1732
|
-
if (rawConfig.include !== void 0 && !isStringArray2(rawConfig.include)) {
|
|
1733
|
-
throw new Error(`Config file ${filePath} field 'include' must be an array of strings.`);
|
|
1734
|
-
}
|
|
1735
|
-
if (rawConfig.exclude !== void 0 && !isStringArray2(rawConfig.exclude)) {
|
|
1736
|
-
throw new Error(`Config file ${filePath} field 'exclude' must be an array of strings.`);
|
|
1737
|
-
}
|
|
1738
|
-
for (const section of ["customProvider", "indexing", "search", "debug", "reranker"]) {
|
|
1739
|
-
const value = rawConfig[section];
|
|
1740
|
-
if (value !== void 0 && !isRecord(value)) {
|
|
1741
|
-
throw new Error(`Config file ${filePath} field '${section}' must be an object.`);
|
|
1742
|
-
}
|
|
1743
|
-
}
|
|
1744
|
-
return rawConfig;
|
|
1745
|
-
}
|
|
1746
|
-
function loadJsonFile(filePath) {
|
|
1747
|
-
if (!existsSync5(filePath)) {
|
|
1748
|
-
return null;
|
|
1749
|
-
}
|
|
1750
|
-
try {
|
|
1751
|
-
const content = readFileSync4(filePath, "utf-8");
|
|
1752
|
-
return validateConfigLayerShape(JSON.parse(content), filePath);
|
|
1753
|
-
} catch (error) {
|
|
1754
|
-
if (error instanceof Error && error.message.startsWith("Config file ")) {
|
|
1755
|
-
throw error;
|
|
1756
|
-
}
|
|
1757
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
1758
|
-
throw new Error(`Failed to load config file ${filePath}: ${message}`);
|
|
1759
|
-
}
|
|
1760
|
-
}
|
|
1761
|
-
function materializeLocalProjectConfig(projectRoot3, config, host = "opencode") {
|
|
1762
|
-
const localConfigPath = resolveWritableProjectConfigPath(projectRoot3, host);
|
|
1763
|
-
mkdirSync(path7.dirname(localConfigPath), { recursive: true });
|
|
1764
|
-
writeFileSync(localConfigPath, JSON.stringify(config, null, 2), "utf-8");
|
|
1765
|
-
return localConfigPath;
|
|
1766
|
-
}
|
|
1767
|
-
function loadProjectConfigLayer(projectRoot3, host = "opencode") {
|
|
1768
|
-
const projectConfigPath = resolveProjectConfigPath(projectRoot3, host);
|
|
1769
|
-
const projectConfig = loadJsonFile(projectConfigPath);
|
|
1770
|
-
if (!projectConfig) {
|
|
1771
|
-
return {};
|
|
1772
|
-
}
|
|
1773
|
-
const normalizedConfig = { ...projectConfig };
|
|
1774
|
-
const projectConfigBaseDir = path7.dirname(path7.dirname(projectConfigPath));
|
|
1775
|
-
if (Array.isArray(normalizedConfig.knowledgeBases)) {
|
|
1776
|
-
normalizedConfig.knowledgeBases = resolveInheritedKnowledgeBaseEntries(
|
|
1777
|
-
normalizedConfig.knowledgeBases,
|
|
1778
|
-
projectConfigBaseDir,
|
|
1779
|
-
projectRoot3
|
|
1780
|
-
);
|
|
1781
|
-
}
|
|
1782
|
-
return normalizedConfig;
|
|
1783
|
-
}
|
|
1784
|
-
function loadMergedConfig(projectRoot3, host = "opencode") {
|
|
1785
|
-
const globalConfigPath = resolveGlobalConfigPath(host);
|
|
1786
|
-
const projectConfigPath = resolveProjectConfigPath(projectRoot3, host);
|
|
1787
|
-
let globalConfig = null;
|
|
1788
|
-
let globalConfigError = null;
|
|
1789
|
-
try {
|
|
1790
|
-
globalConfig = loadJsonFile(globalConfigPath);
|
|
1791
|
-
} catch (error) {
|
|
1792
|
-
globalConfigError = error instanceof Error ? error : new Error(String(error));
|
|
1793
|
-
}
|
|
1794
|
-
const projectConfig = loadJsonFile(projectConfigPath);
|
|
1795
|
-
const normalizedProjectConfig = loadProjectConfigLayer(projectRoot3, host);
|
|
1796
|
-
if (globalConfigError) {
|
|
1797
|
-
if (!projectConfig) {
|
|
1798
|
-
throw globalConfigError;
|
|
1799
|
-
}
|
|
1800
|
-
globalConfig = null;
|
|
1801
|
-
}
|
|
1802
|
-
if (!globalConfig && !projectConfig) {
|
|
1803
|
-
return {};
|
|
1804
|
-
}
|
|
1805
|
-
if (!projectConfig && globalConfig) {
|
|
1806
|
-
return globalConfig;
|
|
1807
|
-
}
|
|
1808
|
-
if (!globalConfig && projectConfig) {
|
|
1809
|
-
return normalizedProjectConfig;
|
|
1810
|
-
}
|
|
1811
|
-
if (!globalConfig || !projectConfig) {
|
|
1812
|
-
return globalConfig ?? normalizedProjectConfig;
|
|
1813
|
-
}
|
|
1814
|
-
const merged = { ...globalConfig };
|
|
1815
|
-
for (const key of PROJECT_OVERRIDE_KEYS) {
|
|
1816
|
-
applyProjectOverride(merged, normalizedProjectConfig, globalConfig, key);
|
|
1817
|
-
}
|
|
1818
|
-
if (projectConfig) {
|
|
1819
|
-
for (const key of Object.keys(projectConfig)) {
|
|
1820
|
-
if (PROJECT_OVERRIDE_KEYS.includes(key) || MERGE_ARRAY_KEYS.includes(key)) {
|
|
1821
|
-
continue;
|
|
1822
|
-
}
|
|
1823
|
-
merged[key] = normalizedProjectConfig[key];
|
|
1824
|
-
}
|
|
1825
|
-
}
|
|
1826
|
-
const globalKbs = globalConfig && Array.isArray(globalConfig.knowledgeBases) ? globalConfig.knowledgeBases : [];
|
|
1827
|
-
const projectKbs = projectConfig ? Array.isArray(normalizedProjectConfig.knowledgeBases) ? normalizedProjectConfig.knowledgeBases : [] : [];
|
|
1828
|
-
const allKbs = [...globalKbs, ...projectKbs];
|
|
1829
|
-
merged.knowledgeBases = mergeKnowledgeBasePaths(allKbs);
|
|
1830
|
-
const globalAdditional = globalConfig && Array.isArray(globalConfig.additionalInclude) ? globalConfig.additionalInclude : [];
|
|
1831
|
-
const projectAdditional = projectConfig && Array.isArray(projectConfig.additionalInclude) ? projectConfig.additionalInclude : [];
|
|
1832
|
-
const allAdditional = [...globalAdditional, ...projectAdditional];
|
|
1833
|
-
merged.additionalInclude = mergeUniqueStringArray(allAdditional);
|
|
1834
|
-
return merged;
|
|
1835
|
-
}
|
|
1836
|
-
|
|
1837
1718
|
// src/indexer/index.ts
|
|
1838
|
-
import { existsSync as
|
|
1839
|
-
import * as
|
|
1719
|
+
import { existsSync as existsSync7, readFileSync as readFileSync6, statSync as statSync3, writeFileSync as writeFileSync2, renameSync as renameSync2, unlinkSync, mkdirSync as mkdirSync2, promises as fsPromises2 } from "fs";
|
|
1720
|
+
import * as path11 from "path";
|
|
1840
1721
|
import { performance as performance2 } from "perf_hooks";
|
|
1841
1722
|
import { execFile as execFile3 } from "child_process";
|
|
1842
1723
|
import { promisify as promisify3 } from "util";
|
|
@@ -3187,6 +3068,7 @@ var GoogleEmbeddingProvider = class _GoogleEmbeddingProvider extends BaseEmbeddi
|
|
|
3187
3068
|
// src/embeddings/providers/ollama.ts
|
|
3188
3069
|
var OllamaEmbeddingProvider = class _OllamaEmbeddingProvider extends BaseEmbeddingProvider {
|
|
3189
3070
|
static MIN_TRUNCATION_CHARS = 512;
|
|
3071
|
+
static REQUEST_TIMEOUT_MS = 12e4;
|
|
3190
3072
|
constructor(credentials, modelInfo) {
|
|
3191
3073
|
super(credentials, modelInfo);
|
|
3192
3074
|
}
|
|
@@ -3261,22 +3143,45 @@ var OllamaEmbeddingProvider = class _OllamaEmbeddingProvider extends BaseEmbeddi
|
|
|
3261
3143
|
}
|
|
3262
3144
|
}
|
|
3263
3145
|
async embedSingle(text3) {
|
|
3264
|
-
const
|
|
3265
|
-
|
|
3266
|
-
|
|
3267
|
-
|
|
3268
|
-
|
|
3269
|
-
|
|
3270
|
-
|
|
3271
|
-
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
|
|
3146
|
+
const controller = new AbortController();
|
|
3147
|
+
const timeout = setTimeout(
|
|
3148
|
+
() => controller.abort(),
|
|
3149
|
+
_OllamaEmbeddingProvider.REQUEST_TIMEOUT_MS
|
|
3150
|
+
);
|
|
3151
|
+
let response;
|
|
3152
|
+
try {
|
|
3153
|
+
response = await fetch(`${this.credentials.baseUrl}/api/embeddings`, {
|
|
3154
|
+
method: "POST",
|
|
3155
|
+
headers: {
|
|
3156
|
+
"Content-Type": "application/json"
|
|
3157
|
+
},
|
|
3158
|
+
body: JSON.stringify({
|
|
3159
|
+
model: this.modelInfo.model,
|
|
3160
|
+
prompt: text3,
|
|
3161
|
+
truncate: false
|
|
3162
|
+
}),
|
|
3163
|
+
signal: controller.signal
|
|
3164
|
+
});
|
|
3165
|
+
} catch (error) {
|
|
3166
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
3167
|
+
throw new Error(
|
|
3168
|
+
`Ollama embedding request timed out after ${_OllamaEmbeddingProvider.REQUEST_TIMEOUT_MS}ms`
|
|
3169
|
+
);
|
|
3170
|
+
}
|
|
3171
|
+
throw error;
|
|
3172
|
+
} finally {
|
|
3173
|
+
clearTimeout(timeout);
|
|
3174
|
+
}
|
|
3275
3175
|
if (!response.ok) {
|
|
3276
3176
|
const error = (await response.text()).slice(0, 500);
|
|
3277
3177
|
throw new Error(`Ollama embedding API error: ${response.status} - ${error}`);
|
|
3278
3178
|
}
|
|
3279
3179
|
const data = await response.json();
|
|
3180
|
+
if (!Array.isArray(data.embedding) || data.embedding.length !== this.modelInfo.dimensions || data.embedding.some((value) => typeof value !== "number" || !Number.isFinite(value))) {
|
|
3181
|
+
throw new Error(
|
|
3182
|
+
`Ollama returned an invalid embedding; expected ${this.modelInfo.dimensions} finite dimensions`
|
|
3183
|
+
);
|
|
3184
|
+
}
|
|
3280
3185
|
return {
|
|
3281
3186
|
embedding: data.embedding,
|
|
3282
3187
|
tokensUsed: this.estimateTokens(text3)
|
|
@@ -3423,9 +3328,23 @@ var SiliconFlowReranker = class {
|
|
|
3423
3328
|
};
|
|
3424
3329
|
|
|
3425
3330
|
// src/utils/files.ts
|
|
3426
|
-
var import_ignore = __toESM(require_ignore(), 1);
|
|
3427
|
-
import { existsSync as
|
|
3428
|
-
import * as
|
|
3331
|
+
var import_ignore = __toESM(require_ignore(), 1);
|
|
3332
|
+
import { existsSync as existsSync5, readFileSync as readFileSync4, promises as fsPromises } from "fs";
|
|
3333
|
+
import * as path6 from "path";
|
|
3334
|
+
|
|
3335
|
+
// src/utils/paths.ts
|
|
3336
|
+
import * as path5 from "path";
|
|
3337
|
+
function normalizePathSeparators(value) {
|
|
3338
|
+
return value.replace(/\\/g, "/");
|
|
3339
|
+
}
|
|
3340
|
+
function isHiddenPathSegment(part) {
|
|
3341
|
+
return part.startsWith(".") && part !== "." && part !== "..";
|
|
3342
|
+
}
|
|
3343
|
+
function isBuildPathSegment(part) {
|
|
3344
|
+
return part.toLowerCase().includes("build");
|
|
3345
|
+
}
|
|
3346
|
+
|
|
3347
|
+
// src/utils/files.ts
|
|
3429
3348
|
function createIgnoreFilter(projectRoot3) {
|
|
3430
3349
|
const ig = (0, import_ignore.default)();
|
|
3431
3350
|
const defaultIgnores = [
|
|
@@ -3447,9 +3366,9 @@ function createIgnoreFilter(projectRoot3) {
|
|
|
3447
3366
|
"**/*build*/**"
|
|
3448
3367
|
];
|
|
3449
3368
|
ig.add(defaultIgnores);
|
|
3450
|
-
const gitignorePath =
|
|
3451
|
-
if (
|
|
3452
|
-
const gitignoreContent =
|
|
3369
|
+
const gitignorePath = path6.join(projectRoot3, ".gitignore");
|
|
3370
|
+
if (existsSync5(gitignorePath)) {
|
|
3371
|
+
const gitignoreContent = readFileSync4(gitignorePath, "utf-8");
|
|
3453
3372
|
ig.add(gitignoreContent);
|
|
3454
3373
|
}
|
|
3455
3374
|
return ig;
|
|
@@ -3474,8 +3393,8 @@ async function* walkDirectory(dir, projectRoot3, includePatterns, excludePattern
|
|
|
3474
3393
|
const filesInDir = [];
|
|
3475
3394
|
const subdirs = [];
|
|
3476
3395
|
for (const entry of entries) {
|
|
3477
|
-
const fullPath =
|
|
3478
|
-
const relativePath =
|
|
3396
|
+
const fullPath = path6.join(dir, entry.name);
|
|
3397
|
+
const relativePath = path6.relative(projectRoot3, fullPath);
|
|
3479
3398
|
if (isHiddenPathSegment(entry.name)) {
|
|
3480
3399
|
if (entry.isDirectory()) {
|
|
3481
3400
|
skipped.push({ path: relativePath, reason: "excluded" });
|
|
@@ -3524,7 +3443,7 @@ async function* walkDirectory(dir, projectRoot3, includePatterns, excludePattern
|
|
|
3524
3443
|
yield f;
|
|
3525
3444
|
}
|
|
3526
3445
|
for (let i = options.maxFilesPerDirectory; i < filesInDir.length; i++) {
|
|
3527
|
-
skipped.push({ path:
|
|
3446
|
+
skipped.push({ path: path6.relative(projectRoot3, filesInDir[i].path), reason: "excluded" });
|
|
3528
3447
|
}
|
|
3529
3448
|
const canRecurse = options.maxDepth === -1 || currentDepth < options.maxDepth;
|
|
3530
3449
|
if (canRecurse) {
|
|
@@ -3564,8 +3483,8 @@ async function collectFiles(projectRoot3, includePatterns, excludePatterns, maxF
|
|
|
3564
3483
|
if (additionalRoots && additionalRoots.length > 0) {
|
|
3565
3484
|
const normalizedRoots = /* @__PURE__ */ new Set();
|
|
3566
3485
|
for (const kbRoot of additionalRoots) {
|
|
3567
|
-
const resolved =
|
|
3568
|
-
|
|
3486
|
+
const resolved = path6.normalize(
|
|
3487
|
+
path6.isAbsolute(kbRoot) ? kbRoot : path6.resolve(projectRoot3, kbRoot)
|
|
3569
3488
|
);
|
|
3570
3489
|
normalizedRoots.add(resolved);
|
|
3571
3490
|
}
|
|
@@ -3912,7 +3831,7 @@ function initializeLogger(config) {
|
|
|
3912
3831
|
}
|
|
3913
3832
|
|
|
3914
3833
|
// src/native/index.ts
|
|
3915
|
-
import * as
|
|
3834
|
+
import * as path7 from "path";
|
|
3916
3835
|
import * as os3 from "os";
|
|
3917
3836
|
import * as module from "module";
|
|
3918
3837
|
import { fileURLToPath } from "url";
|
|
@@ -3936,19 +3855,19 @@ function getNativeBinding() {
|
|
|
3936
3855
|
let currentDir;
|
|
3937
3856
|
let requireTarget;
|
|
3938
3857
|
if (typeof import.meta !== "undefined" && import.meta.url) {
|
|
3939
|
-
currentDir =
|
|
3858
|
+
currentDir = path7.dirname(fileURLToPath(import.meta.url));
|
|
3940
3859
|
requireTarget = import.meta.url;
|
|
3941
3860
|
} else if (typeof __dirname !== "undefined") {
|
|
3942
3861
|
currentDir = __dirname;
|
|
3943
3862
|
requireTarget = __filename;
|
|
3944
3863
|
} else {
|
|
3945
3864
|
currentDir = process.cwd();
|
|
3946
|
-
requireTarget =
|
|
3865
|
+
requireTarget = path7.join(currentDir, "index.js");
|
|
3947
3866
|
}
|
|
3948
3867
|
const normalizedDir = currentDir.replace(/\\/g, "/");
|
|
3949
|
-
const isDevMode = normalizedDir.includes("/src/native") || currentDir.includes(
|
|
3950
|
-
const packageRoot = isDevMode ?
|
|
3951
|
-
const nativePath =
|
|
3868
|
+
const isDevMode = normalizedDir.includes("/src/native") || currentDir.includes(path7.join("src", "native"));
|
|
3869
|
+
const packageRoot = isDevMode ? path7.resolve(currentDir, "../..") : path7.resolve(currentDir, "..");
|
|
3870
|
+
const nativePath = path7.join(packageRoot, "native", bindingName);
|
|
3952
3871
|
const require2 = module.createRequire(requireTarget);
|
|
3953
3872
|
return require2(nativePath);
|
|
3954
3873
|
}
|
|
@@ -4034,7 +3953,9 @@ function mapChunk(c) {
|
|
|
4034
3953
|
return {
|
|
4035
3954
|
content: c.content,
|
|
4036
3955
|
startLine: c.startLine ?? c.start_line,
|
|
3956
|
+
startCol: c.startCol ?? c.start_col,
|
|
4037
3957
|
endLine: c.endLine ?? c.end_line,
|
|
3958
|
+
endCol: c.endCol ?? c.end_col,
|
|
4038
3959
|
chunkType: c.chunkType ?? c.chunk_type,
|
|
4039
3960
|
name: c.name ?? void 0,
|
|
4040
3961
|
language: c.language
|
|
@@ -4155,6 +4076,7 @@ function getEmbeddingHeaderParts(chunk, filePath) {
|
|
|
4155
4076
|
javascript: "JavaScript",
|
|
4156
4077
|
python: "Python",
|
|
4157
4078
|
rust: "Rust",
|
|
4079
|
+
swift: "Swift",
|
|
4158
4080
|
go: "Go",
|
|
4159
4081
|
java: "Java"
|
|
4160
4082
|
};
|
|
@@ -4163,7 +4085,16 @@ function getEmbeddingHeaderParts(chunk, filePath) {
|
|
|
4163
4085
|
function: "function",
|
|
4164
4086
|
arrow_function: "arrow function",
|
|
4165
4087
|
method_definition: "method",
|
|
4088
|
+
method_declaration: "method",
|
|
4089
|
+
protocol_function_declaration: "protocol requirement",
|
|
4090
|
+
init_declaration: "initializer",
|
|
4091
|
+
deinit_declaration: "deinitializer",
|
|
4092
|
+
subscript_declaration: "subscript",
|
|
4166
4093
|
class_declaration: "class",
|
|
4094
|
+
actor_declaration: "actor",
|
|
4095
|
+
extension_declaration: "extension",
|
|
4096
|
+
protocol_declaration: "protocol",
|
|
4097
|
+
struct_declaration: "struct",
|
|
4167
4098
|
interface_declaration: "interface",
|
|
4168
4099
|
type_alias_declaration: "type alias",
|
|
4169
4100
|
enum_declaration: "enum",
|
|
@@ -4681,7 +4612,7 @@ var Database = class _Database {
|
|
|
4681
4612
|
};
|
|
4682
4613
|
|
|
4683
4614
|
// src/tools/changed-files.ts
|
|
4684
|
-
import * as
|
|
4615
|
+
import * as path8 from "path";
|
|
4685
4616
|
import { execFile } from "child_process";
|
|
4686
4617
|
import { promisify } from "util";
|
|
4687
4618
|
var execFileAsync = promisify(execFile);
|
|
@@ -4769,8 +4700,8 @@ function normalizeFiles(rawFiles, projectRoot3) {
|
|
|
4769
4700
|
for (const raw of rawFiles) {
|
|
4770
4701
|
const trimmed = raw.trim();
|
|
4771
4702
|
if (!trimmed) continue;
|
|
4772
|
-
const absolute =
|
|
4773
|
-
const relative7 =
|
|
4703
|
+
const absolute = path8.resolve(projectRoot3, trimmed);
|
|
4704
|
+
const relative7 = path8.relative(projectRoot3, absolute);
|
|
4774
4705
|
const cleaned = relative7.startsWith("./") ? relative7.slice(2) : relative7;
|
|
4775
4706
|
if (!seen.has(cleaned)) {
|
|
4776
4707
|
seen.add(cleaned);
|
|
@@ -4782,7 +4713,7 @@ function normalizeFiles(rawFiles, projectRoot3) {
|
|
|
4782
4713
|
|
|
4783
4714
|
// src/indexer/git-blame.ts
|
|
4784
4715
|
import { execFile as execFile2 } from "child_process";
|
|
4785
|
-
import * as
|
|
4716
|
+
import * as path9 from "path";
|
|
4786
4717
|
import { promisify as promisify2 } from "util";
|
|
4787
4718
|
var execFileAsync2 = promisify2(execFile2);
|
|
4788
4719
|
function parseGitBlamePorcelain(output) {
|
|
@@ -4820,7 +4751,7 @@ function parseGitBlamePorcelain(output) {
|
|
|
4820
4751
|
return Array.from(commits.values()).filter((commit) => commit.lines > 0).sort((a, b) => b.lines - a.lines || b.committedAt - a.committedAt)[0];
|
|
4821
4752
|
}
|
|
4822
4753
|
async function getChunkGitBlame(projectRoot3, filePath, startLine, endLine) {
|
|
4823
|
-
const relativePath =
|
|
4754
|
+
const relativePath = path9.relative(projectRoot3, filePath);
|
|
4824
4755
|
try {
|
|
4825
4756
|
const { stdout } = await execFileAsync2(
|
|
4826
4757
|
"git",
|
|
@@ -4836,18 +4767,18 @@ async function getChunkGitBlame(projectRoot3, filePath, startLine, endLine) {
|
|
|
4836
4767
|
// src/indexer/index-lock.ts
|
|
4837
4768
|
import { randomUUID } from "crypto";
|
|
4838
4769
|
import {
|
|
4839
|
-
existsSync as
|
|
4770
|
+
existsSync as existsSync6,
|
|
4840
4771
|
lstatSync,
|
|
4841
|
-
mkdirSync
|
|
4842
|
-
readFileSync as
|
|
4772
|
+
mkdirSync,
|
|
4773
|
+
readFileSync as readFileSync5,
|
|
4843
4774
|
readdirSync as readdirSync2,
|
|
4844
4775
|
realpathSync,
|
|
4845
4776
|
renameSync,
|
|
4846
4777
|
rmSync,
|
|
4847
|
-
writeFileSync
|
|
4778
|
+
writeFileSync
|
|
4848
4779
|
} from "fs";
|
|
4849
4780
|
import * as os4 from "os";
|
|
4850
|
-
import * as
|
|
4781
|
+
import * as path10 from "path";
|
|
4851
4782
|
var OWNER_FILE_NAME = "owner.json";
|
|
4852
4783
|
var RECLAIM_DIRECTORY_NAME = "reclaiming";
|
|
4853
4784
|
var RECOVERY_MARKER_PREFIX = "indexing.lock.recovery.";
|
|
@@ -4904,7 +4835,7 @@ function parseReclaimOwner(value) {
|
|
|
4904
4835
|
}
|
|
4905
4836
|
function readJsonDirectory(directoryPath, parser) {
|
|
4906
4837
|
try {
|
|
4907
|
-
return parser(JSON.parse(
|
|
4838
|
+
return parser(JSON.parse(readFileSync5(path10.join(directoryPath, OWNER_FILE_NAME), "utf-8")));
|
|
4908
4839
|
} catch {
|
|
4909
4840
|
return null;
|
|
4910
4841
|
}
|
|
@@ -4920,7 +4851,7 @@ function readRecoveryOwner(markerPath) {
|
|
|
4920
4851
|
}
|
|
4921
4852
|
function readLegacyOwner(lockPath) {
|
|
4922
4853
|
try {
|
|
4923
|
-
const parsed = JSON.parse(
|
|
4854
|
+
const parsed = JSON.parse(readFileSync5(lockPath, "utf-8"));
|
|
4924
4855
|
if (!Number.isInteger(parsed.pid) || Number(parsed.pid) <= 0) return null;
|
|
4925
4856
|
if (typeof parsed.startedAt !== "string" || Number.isNaN(Date.parse(parsed.startedAt))) return null;
|
|
4926
4857
|
return {
|
|
@@ -4955,23 +4886,23 @@ function sameReclaimOwner(left, right) {
|
|
|
4955
4886
|
function publishJsonDirectory(finalPath, value) {
|
|
4956
4887
|
const candidatePath = `${finalPath}.candidate.${process.pid}.${randomUUID()}`;
|
|
4957
4888
|
try {
|
|
4958
|
-
|
|
4889
|
+
mkdirSync(candidatePath, { mode: 448 });
|
|
4959
4890
|
} catch (error) {
|
|
4960
4891
|
if (getErrorCode(error) === "ENOENT") return false;
|
|
4961
4892
|
throw error;
|
|
4962
4893
|
}
|
|
4963
4894
|
try {
|
|
4964
|
-
|
|
4895
|
+
writeFileSync(path10.join(candidatePath, OWNER_FILE_NAME), JSON.stringify(value), {
|
|
4965
4896
|
encoding: "utf-8",
|
|
4966
4897
|
flag: "wx",
|
|
4967
4898
|
mode: 384
|
|
4968
4899
|
});
|
|
4969
|
-
if (
|
|
4900
|
+
if (existsSync6(finalPath)) return false;
|
|
4970
4901
|
try {
|
|
4971
4902
|
renameSync(candidatePath, finalPath);
|
|
4972
4903
|
return true;
|
|
4973
4904
|
} catch (error) {
|
|
4974
|
-
if (
|
|
4905
|
+
if (existsSync6(finalPath)) return false;
|
|
4975
4906
|
if (getErrorCode(error) === "ENOENT") return false;
|
|
4976
4907
|
throw error;
|
|
4977
4908
|
}
|
|
@@ -4979,7 +4910,7 @@ function publishJsonDirectory(finalPath, value) {
|
|
|
4979
4910
|
if (getErrorCode(error) === "ENOENT") return false;
|
|
4980
4911
|
throw error;
|
|
4981
4912
|
} finally {
|
|
4982
|
-
if (
|
|
4913
|
+
if (existsSync6(candidatePath)) rmSync(candidatePath, { recursive: true, force: true });
|
|
4983
4914
|
}
|
|
4984
4915
|
}
|
|
4985
4916
|
function createOwner(operation) {
|
|
@@ -4992,7 +4923,7 @@ function createOwner(operation) {
|
|
|
4992
4923
|
};
|
|
4993
4924
|
}
|
|
4994
4925
|
function recoveryMarkerPath(indexPath, owner) {
|
|
4995
|
-
return
|
|
4926
|
+
return path10.join(indexPath, `${RECOVERY_MARKER_PREFIX}${owner.token}`);
|
|
4996
4927
|
}
|
|
4997
4928
|
function publishRecoveryMarker(indexPath, owner) {
|
|
4998
4929
|
const markerPath = recoveryMarkerPath(indexPath, owner);
|
|
@@ -5011,7 +4942,7 @@ function getPendingRecoveries(indexPath) {
|
|
|
5011
4942
|
return UUID_PATTERN.test(name.slice(RECOVERY_MARKER_PREFIX.length));
|
|
5012
4943
|
}).sort();
|
|
5013
4944
|
for (const markerName of markerNames) {
|
|
5014
|
-
const markerPath =
|
|
4945
|
+
const markerPath = path10.join(indexPath, markerName);
|
|
5015
4946
|
const markerToken = markerName.slice(RECOVERY_MARKER_PREFIX.length);
|
|
5016
4947
|
let markerStats;
|
|
5017
4948
|
try {
|
|
@@ -5043,11 +4974,11 @@ function cleanupDeadPublicationCandidates(indexPath) {
|
|
|
5043
4974
|
const pid = Number(match[1]);
|
|
5044
4975
|
if (!Number.isInteger(pid) || pid <= 0) continue;
|
|
5045
4976
|
if (getOwnerLiveness({ pid, hostname: os4.hostname() }) !== "dead") continue;
|
|
5046
|
-
rmSync(
|
|
4977
|
+
rmSync(path10.join(indexPath, entry), { recursive: true, force: true });
|
|
5047
4978
|
}
|
|
5048
4979
|
}
|
|
5049
4980
|
function removeDeadReclaimMarker(lockPath, expectedOwner) {
|
|
5050
|
-
const markerPath =
|
|
4981
|
+
const markerPath = path10.join(lockPath, RECLAIM_DIRECTORY_NAME);
|
|
5051
4982
|
const marker = readReclaimOwner(markerPath);
|
|
5052
4983
|
if (!marker || marker.expectedOwnerToken !== expectedOwner.token || getOwnerLiveness(marker) !== "dead") {
|
|
5053
4984
|
return false;
|
|
@@ -5066,7 +4997,7 @@ function removeDeadReclaimMarker(lockPath, expectedOwner) {
|
|
|
5066
4997
|
const claimedMarker = readReclaimOwner(claimedMarkerPath);
|
|
5067
4998
|
const ownerAfterClaim = readDirectoryOwner(lockPath);
|
|
5068
4999
|
if (!claimedMarker || !sameReclaimOwner(claimedMarker, marker) || !ownerAfterClaim || !sameOwner(ownerAfterClaim, expectedOwner) || getOwnerLiveness(ownerAfterClaim) !== "dead") {
|
|
5069
|
-
if (!
|
|
5000
|
+
if (!existsSync6(markerPath) && existsSync6(claimedMarkerPath)) {
|
|
5070
5001
|
renameSync(claimedMarkerPath, markerPath);
|
|
5071
5002
|
}
|
|
5072
5003
|
return false;
|
|
@@ -5075,7 +5006,7 @@ function removeDeadReclaimMarker(lockPath, expectedOwner) {
|
|
|
5075
5006
|
return true;
|
|
5076
5007
|
}
|
|
5077
5008
|
function reclaimDeadOwner(indexPath, lockPath, expectedOwner) {
|
|
5078
|
-
const reclaimPath =
|
|
5009
|
+
const reclaimPath = path10.join(lockPath, RECLAIM_DIRECTORY_NAME);
|
|
5079
5010
|
const reclaimOwner = {
|
|
5080
5011
|
pid: process.pid,
|
|
5081
5012
|
hostname: os4.hostname(),
|
|
@@ -5127,9 +5058,9 @@ function isIndexLockContentionError(error) {
|
|
|
5127
5058
|
return error instanceof IndexLockContentionError || typeof error === "object" && error !== null && "code" in error && error.code === "INDEX_BUSY";
|
|
5128
5059
|
}
|
|
5129
5060
|
function acquireIndexLock(indexPath, operation) {
|
|
5130
|
-
|
|
5061
|
+
mkdirSync(indexPath, { recursive: true });
|
|
5131
5062
|
const canonicalIndexPath = realpathSync.native(indexPath);
|
|
5132
|
-
const lockPath =
|
|
5063
|
+
const lockPath = path10.join(canonicalIndexPath, "indexing.lock");
|
|
5133
5064
|
cleanupDeadPublicationCandidates(canonicalIndexPath);
|
|
5134
5065
|
for (let attempt = 0; attempt < 6; attempt += 1) {
|
|
5135
5066
|
const owner = createOwner(operation);
|
|
@@ -5185,7 +5116,7 @@ function releaseIndexLock(lease) {
|
|
|
5185
5116
|
}
|
|
5186
5117
|
const claimedOwner = readDirectoryOwner(releasePath);
|
|
5187
5118
|
if (!claimedOwner || !sameOwner(claimedOwner, lease.owner)) {
|
|
5188
|
-
if (!
|
|
5119
|
+
if (!existsSync6(lease.lockPath) && existsSync6(releasePath)) {
|
|
5189
5120
|
renameSync(releasePath, lease.lockPath);
|
|
5190
5121
|
}
|
|
5191
5122
|
return false;
|
|
@@ -5197,59 +5128,25 @@ function releaseIndexLock(lease) {
|
|
|
5197
5128
|
}
|
|
5198
5129
|
return true;
|
|
5199
5130
|
}
|
|
5200
|
-
async function withIndexLock(indexPath, operation, callback, options = {}) {
|
|
5201
|
-
const lease = acquireIndexLock(indexPath, operation);
|
|
5202
|
-
let result;
|
|
5203
|
-
let callbackError;
|
|
5204
|
-
let callbackFailed = false;
|
|
5205
|
-
try {
|
|
5206
|
-
result = await callback(lease);
|
|
5207
|
-
} catch (error) {
|
|
5208
|
-
callbackFailed = true;
|
|
5209
|
-
callbackError = error;
|
|
5210
|
-
}
|
|
5211
|
-
if (!callbackFailed && options.completeRecoveries !== false) {
|
|
5212
|
-
try {
|
|
5213
|
-
completeLeaseRecovery(lease);
|
|
5214
|
-
} catch (error) {
|
|
5215
|
-
callbackFailed = true;
|
|
5216
|
-
callbackError = error;
|
|
5217
|
-
}
|
|
5218
|
-
}
|
|
5219
|
-
let releaseError;
|
|
5220
|
-
try {
|
|
5221
|
-
if (!releaseIndexLock(lease)) {
|
|
5222
|
-
releaseError = new Error(`Lost ownership of index mutation lease ${lease.owner.token}`);
|
|
5223
|
-
}
|
|
5224
|
-
} catch (error) {
|
|
5225
|
-
releaseError = error;
|
|
5226
|
-
}
|
|
5227
|
-
if (releaseError !== void 0) {
|
|
5228
|
-
if (callbackFailed) throw new AggregateError([callbackError, releaseError], "Index mutation and lease release both failed");
|
|
5229
|
-
throw releaseError;
|
|
5230
|
-
}
|
|
5231
|
-
if (callbackFailed) throw callbackError;
|
|
5232
|
-
return result;
|
|
5233
|
-
}
|
|
5234
5131
|
function createLeaseTemporaryPath(targetPath, owner, kind = "tmp") {
|
|
5235
5132
|
if (kind === "bak") return `${targetPath}.bak.${owner.pid}.${owner.token}`;
|
|
5236
5133
|
temporaryCounter += 1;
|
|
5237
5134
|
return `${targetPath}.tmp.${owner.pid}.${owner.token}.${temporaryCounter}`;
|
|
5238
5135
|
}
|
|
5239
5136
|
function removeLeaseTemporaryPath(temporaryPath) {
|
|
5240
|
-
if (
|
|
5137
|
+
if (existsSync6(temporaryPath)) rmSync(temporaryPath, { recursive: true, force: true });
|
|
5241
5138
|
}
|
|
5242
5139
|
function recoverLeaseArtifacts(indexPath, owner, backupTargets) {
|
|
5243
5140
|
for (const targetPath of backupTargets) {
|
|
5244
5141
|
const backupPath = createLeaseTemporaryPath(targetPath, owner, "bak");
|
|
5245
|
-
if (!
|
|
5246
|
-
if (
|
|
5142
|
+
if (!existsSync6(backupPath)) continue;
|
|
5143
|
+
if (existsSync6(targetPath)) rmSync(targetPath, { recursive: true, force: true });
|
|
5247
5144
|
renameSync(backupPath, targetPath);
|
|
5248
5145
|
}
|
|
5249
5146
|
const temporaryOwnerMarker = `.tmp.${owner.pid}.${owner.token}.`;
|
|
5250
5147
|
for (const entry of readdirSync2(indexPath)) {
|
|
5251
5148
|
if (!entry.includes(temporaryOwnerMarker)) continue;
|
|
5252
|
-
rmSync(
|
|
5149
|
+
rmSync(path10.join(indexPath, entry), { recursive: true, force: true });
|
|
5253
5150
|
}
|
|
5254
5151
|
}
|
|
5255
5152
|
function completeLeaseRecovery(lease) {
|
|
@@ -5265,8 +5162,18 @@ function completeLeaseRecovery(lease) {
|
|
|
5265
5162
|
}
|
|
5266
5163
|
|
|
5267
5164
|
// src/indexer/index.ts
|
|
5268
|
-
var CALL_GRAPH_LANGUAGES = /* @__PURE__ */ new Set(["typescript", "tsx", "javascript", "jsx", "python", "go", "rust", "php", "apex", "zig", "gdscript", "matlab", "bash"]);
|
|
5269
|
-
var CASE_INSENSITIVE_LANGUAGES = /* @__PURE__ */ new Set(["apex"]);
|
|
5165
|
+
var CALL_GRAPH_LANGUAGES = /* @__PURE__ */ new Set(["typescript", "tsx", "javascript", "jsx", "python", "go", "rust", "swift", "php", "apex", "zig", "gdscript", "matlab", "bash", "c", "cpp", "metal"]);
|
|
5166
|
+
var CASE_INSENSITIVE_LANGUAGES = /* @__PURE__ */ new Set(["apex", "php"]);
|
|
5167
|
+
var CALL_GRAPH_RESOLUTION_VERSION = "4";
|
|
5168
|
+
var PHP_FUNCTION_SYMBOL_CHUNK_TYPES = /* @__PURE__ */ new Set([
|
|
5169
|
+
"function_declaration",
|
|
5170
|
+
"function",
|
|
5171
|
+
"function_definition"
|
|
5172
|
+
]);
|
|
5173
|
+
var PHP_CLASS_SYMBOL_CHUNK_TYPES = /* @__PURE__ */ new Set([
|
|
5174
|
+
"class_declaration",
|
|
5175
|
+
"class_definition"
|
|
5176
|
+
]);
|
|
5270
5177
|
var CALL_GRAPH_SYMBOL_CHUNK_TYPES = /* @__PURE__ */ new Set([
|
|
5271
5178
|
"function_declaration",
|
|
5272
5179
|
"function",
|
|
@@ -5279,6 +5186,9 @@ var CALL_GRAPH_SYMBOL_CHUNK_TYPES = /* @__PURE__ */ new Set([
|
|
|
5279
5186
|
"enum_declaration",
|
|
5280
5187
|
"function_definition",
|
|
5281
5188
|
"class_definition",
|
|
5189
|
+
"class_specifier",
|
|
5190
|
+
"struct_specifier",
|
|
5191
|
+
"namespace_definition",
|
|
5282
5192
|
"decorated_definition",
|
|
5283
5193
|
"method_declaration",
|
|
5284
5194
|
"type_declaration",
|
|
@@ -5294,6 +5204,14 @@ var CALL_GRAPH_SYMBOL_CHUNK_TYPES = /* @__PURE__ */ new Set([
|
|
|
5294
5204
|
"test_declaration",
|
|
5295
5205
|
"struct_declaration",
|
|
5296
5206
|
"union_declaration",
|
|
5207
|
+
// Synthetic Swift declarations or declarations specific to tree-sitter-swift.
|
|
5208
|
+
"actor_declaration",
|
|
5209
|
+
"extension_declaration",
|
|
5210
|
+
"protocol_declaration",
|
|
5211
|
+
"protocol_function_declaration",
|
|
5212
|
+
"init_declaration",
|
|
5213
|
+
"deinit_declaration",
|
|
5214
|
+
"subscript_declaration",
|
|
5297
5215
|
// GDScript declarations whose names participate in the call graph.
|
|
5298
5216
|
// `function_definition` and `class_definition` are already in the set
|
|
5299
5217
|
// above (shared with Python/C/Bash and Python, respectively).
|
|
@@ -5303,6 +5221,53 @@ var CALL_GRAPH_SYMBOL_CHUNK_TYPES = /* @__PURE__ */ new Set([
|
|
|
5303
5221
|
"const_statement",
|
|
5304
5222
|
"class_name_statement"
|
|
5305
5223
|
]);
|
|
5224
|
+
var C_FAMILY_TYPE_SYMBOL_CHUNK_TYPES = /* @__PURE__ */ new Set(["class_specifier", "struct_specifier"]);
|
|
5225
|
+
function isCompatibleCFamilyCallTarget(language, callType, symbolKind) {
|
|
5226
|
+
if (language !== "c" && language !== "cpp") return true;
|
|
5227
|
+
if (symbolKind === "namespace_definition") return callType === "Import";
|
|
5228
|
+
const isTypeSymbol = C_FAMILY_TYPE_SYMBOL_CHUNK_TYPES.has(symbolKind);
|
|
5229
|
+
if (callType === "Constructor" || callType === "Inherits" || callType === "Implements") {
|
|
5230
|
+
return isTypeSymbol;
|
|
5231
|
+
}
|
|
5232
|
+
return !isTypeSymbol;
|
|
5233
|
+
}
|
|
5234
|
+
var EXECUTABLE_SYMBOL_CHUNK_TYPES = /* @__PURE__ */ new Set([
|
|
5235
|
+
"function_declaration",
|
|
5236
|
+
"function",
|
|
5237
|
+
"arrow_function",
|
|
5238
|
+
"method_definition",
|
|
5239
|
+
"function_definition",
|
|
5240
|
+
"method_declaration",
|
|
5241
|
+
"function_item",
|
|
5242
|
+
"protocol_function_declaration",
|
|
5243
|
+
"init_declaration",
|
|
5244
|
+
"deinit_declaration",
|
|
5245
|
+
"subscript_declaration",
|
|
5246
|
+
"constructor_definition",
|
|
5247
|
+
"trigger_declaration",
|
|
5248
|
+
"test_declaration"
|
|
5249
|
+
]);
|
|
5250
|
+
function findEnclosingSymbol(symbols, line, column) {
|
|
5251
|
+
let best;
|
|
5252
|
+
for (const symbol of symbols) {
|
|
5253
|
+
if (line < symbol.startLine || line > symbol.endLine) continue;
|
|
5254
|
+
if (column !== void 0 && (line === symbol.startLine && column < symbol.startCol || line === symbol.endLine && column >= symbol.endCol)) {
|
|
5255
|
+
continue;
|
|
5256
|
+
}
|
|
5257
|
+
if (!best) {
|
|
5258
|
+
best = symbol;
|
|
5259
|
+
continue;
|
|
5260
|
+
}
|
|
5261
|
+
const span = symbol.endLine - symbol.startLine;
|
|
5262
|
+
const bestSpan = best.endLine - best.startLine;
|
|
5263
|
+
const isNarrowerPositionRange = column !== void 0 && span === bestSpan && symbol.startLine === best.startLine && symbol.endLine === best.endLine && symbol.startCol >= best.startCol && symbol.endCol <= best.endCol && (symbol.startCol > best.startCol || symbol.endCol < best.endCol);
|
|
5264
|
+
const isMoreSpecificTie = span === bestSpan && symbol.startLine === best.startLine && EXECUTABLE_SYMBOL_CHUNK_TYPES.has(symbol.kind) && !EXECUTABLE_SYMBOL_CHUNK_TYPES.has(best.kind);
|
|
5265
|
+
if (span < bestSpan || span === bestSpan && symbol.startLine > best.startLine || isNarrowerPositionRange || isMoreSpecificTie) {
|
|
5266
|
+
best = symbol;
|
|
5267
|
+
}
|
|
5268
|
+
}
|
|
5269
|
+
return best;
|
|
5270
|
+
}
|
|
5306
5271
|
function float32ArrayToBuffer(arr) {
|
|
5307
5272
|
const float32 = new Float32Array(arr);
|
|
5308
5273
|
return Buffer.from(float32.buffer);
|
|
@@ -5387,6 +5352,8 @@ function hasBlameMetadata(metadata) {
|
|
|
5387
5352
|
}
|
|
5388
5353
|
var INDEX_METADATA_VERSION = "1";
|
|
5389
5354
|
var EMBEDDING_STRATEGY_VERSION = "2";
|
|
5355
|
+
var SWIFT_PARSER_VERSION = "1";
|
|
5356
|
+
var METAL_PARSER_VERSION = "1";
|
|
5390
5357
|
var RANKING_TOKEN_CACHE_LIMIT = 4096;
|
|
5391
5358
|
var RANK_HYBRID_CACHE_LIMIT = 256;
|
|
5392
5359
|
function createPendingChunkStorageText(texts) {
|
|
@@ -5543,9 +5510,9 @@ function hasAllEmbeddingParts(parts, expectedPartCount) {
|
|
|
5543
5510
|
return true;
|
|
5544
5511
|
}
|
|
5545
5512
|
function isPathWithinRoot(filePath, rootPath) {
|
|
5546
|
-
const normalizedFilePath =
|
|
5547
|
-
const normalizedRoot =
|
|
5548
|
-
return normalizedFilePath === normalizedRoot || normalizedFilePath.startsWith(`${normalizedRoot}${
|
|
5513
|
+
const normalizedFilePath = path11.resolve(filePath);
|
|
5514
|
+
const normalizedRoot = path11.resolve(rootPath);
|
|
5515
|
+
return normalizedFilePath === normalizedRoot || normalizedFilePath.startsWith(`${normalizedRoot}${path11.sep}`);
|
|
5549
5516
|
}
|
|
5550
5517
|
var rankingQueryTokenCache = /* @__PURE__ */ new Map();
|
|
5551
5518
|
var rankingNameTokenCache = /* @__PURE__ */ new Map();
|
|
@@ -5709,15 +5676,25 @@ function chunkTypeBoost(chunkType) {
|
|
|
5709
5676
|
case "function_declaration":
|
|
5710
5677
|
case "method":
|
|
5711
5678
|
case "method_definition":
|
|
5679
|
+
case "method_declaration":
|
|
5680
|
+
case "protocol_function_declaration":
|
|
5681
|
+
case "init_declaration":
|
|
5682
|
+
case "deinit_declaration":
|
|
5683
|
+
case "subscript_declaration":
|
|
5712
5684
|
case "class":
|
|
5713
5685
|
case "class_declaration":
|
|
5686
|
+
case "actor_declaration":
|
|
5687
|
+
case "extension_declaration":
|
|
5714
5688
|
return 0.2;
|
|
5715
5689
|
case "interface":
|
|
5716
5690
|
case "type":
|
|
5717
5691
|
case "enum":
|
|
5692
|
+
case "enum_declaration":
|
|
5718
5693
|
case "struct":
|
|
5694
|
+
case "struct_declaration":
|
|
5719
5695
|
case "impl":
|
|
5720
5696
|
case "trait":
|
|
5697
|
+
case "protocol_declaration":
|
|
5721
5698
|
case "module":
|
|
5722
5699
|
return 0.1;
|
|
5723
5700
|
default:
|
|
@@ -5824,11 +5801,21 @@ function isImplementationChunkType(chunkType) {
|
|
|
5824
5801
|
"function_declaration",
|
|
5825
5802
|
"method",
|
|
5826
5803
|
"method_definition",
|
|
5804
|
+
"method_declaration",
|
|
5805
|
+
"protocol_function_declaration",
|
|
5806
|
+
"init_declaration",
|
|
5807
|
+
"deinit_declaration",
|
|
5808
|
+
"subscript_declaration",
|
|
5827
5809
|
"class",
|
|
5828
5810
|
"class_declaration",
|
|
5811
|
+
"actor_declaration",
|
|
5812
|
+
"extension_declaration",
|
|
5829
5813
|
"interface",
|
|
5814
|
+
"protocol_declaration",
|
|
5830
5815
|
"type",
|
|
5831
5816
|
"enum",
|
|
5817
|
+
"enum_declaration",
|
|
5818
|
+
"struct_declaration",
|
|
5832
5819
|
"module"
|
|
5833
5820
|
].includes(chunkType);
|
|
5834
5821
|
}
|
|
@@ -6645,21 +6632,21 @@ var Indexer = class {
|
|
|
6645
6632
|
this.config = config;
|
|
6646
6633
|
this.host = host;
|
|
6647
6634
|
this.indexPath = this.getIndexPath();
|
|
6648
|
-
this.fileHashCachePath =
|
|
6649
|
-
this.failedBatchesPath =
|
|
6635
|
+
this.fileHashCachePath = path11.join(this.indexPath, "file-hashes.json");
|
|
6636
|
+
this.failedBatchesPath = path11.join(this.indexPath, "failed-batches.json");
|
|
6650
6637
|
this.logger = initializeLogger(config.debug);
|
|
6651
6638
|
}
|
|
6652
6639
|
getIndexPath() {
|
|
6653
6640
|
return resolveProjectIndexPath(this.projectRoot, this.config.scope, this.host);
|
|
6654
6641
|
}
|
|
6655
6642
|
isLocalProjectIndexPath() {
|
|
6656
|
-
const localProjectIndexPaths = [
|
|
6643
|
+
const localProjectIndexPaths = [path11.join(this.projectRoot, getHostProjectIndexRelativePath(this.host))];
|
|
6657
6644
|
if (this.host !== "opencode") {
|
|
6658
|
-
localProjectIndexPaths.push(
|
|
6645
|
+
localProjectIndexPaths.push(path11.join(this.projectRoot, getHostProjectIndexRelativePath("opencode")));
|
|
6659
6646
|
}
|
|
6660
6647
|
return localProjectIndexPaths.some((localPath) => {
|
|
6661
|
-
if (!
|
|
6662
|
-
return
|
|
6648
|
+
if (!existsSync7(localPath) || !existsSync7(this.indexPath)) {
|
|
6649
|
+
return path11.resolve(this.indexPath) === path11.resolve(localPath);
|
|
6663
6650
|
}
|
|
6664
6651
|
const indexStats = statSync3(this.indexPath);
|
|
6665
6652
|
const localStats = statSync3(localPath);
|
|
@@ -6701,8 +6688,8 @@ var Indexer = class {
|
|
|
6701
6688
|
async withIndexMutationLease(operation, callback) {
|
|
6702
6689
|
const lease = acquireIndexLock(this.indexPath, operation);
|
|
6703
6690
|
this.indexPath = lease.canonicalIndexPath;
|
|
6704
|
-
this.fileHashCachePath =
|
|
6705
|
-
this.failedBatchesPath =
|
|
6691
|
+
this.fileHashCachePath = path11.join(this.indexPath, "file-hashes.json");
|
|
6692
|
+
this.failedBatchesPath = path11.join(this.indexPath, "failed-batches.json");
|
|
6706
6693
|
this.activeIndexLease = lease;
|
|
6707
6694
|
let result;
|
|
6708
6695
|
let callbackError;
|
|
@@ -6736,7 +6723,7 @@ var Indexer = class {
|
|
|
6736
6723
|
} catch (error) {
|
|
6737
6724
|
releaseError = error;
|
|
6738
6725
|
this.writerArtifactFingerprint = null;
|
|
6739
|
-
if (!
|
|
6726
|
+
if (!existsSync7(lease.lockPath) && this.activeIndexLease?.owner.token === lease.owner.token) {
|
|
6740
6727
|
this.activeIndexLease = null;
|
|
6741
6728
|
}
|
|
6742
6729
|
}
|
|
@@ -6754,11 +6741,11 @@ var Indexer = class {
|
|
|
6754
6741
|
return this.activeIndexLease;
|
|
6755
6742
|
}
|
|
6756
6743
|
loadFileHashCache() {
|
|
6757
|
-
if (!
|
|
6744
|
+
if (!existsSync7(this.fileHashCachePath)) {
|
|
6758
6745
|
return;
|
|
6759
6746
|
}
|
|
6760
6747
|
try {
|
|
6761
|
-
const data =
|
|
6748
|
+
const data = readFileSync6(this.fileHashCachePath, "utf-8");
|
|
6762
6749
|
const parsed = JSON.parse(data);
|
|
6763
6750
|
this.fileHashCache = new Map(Object.entries(parsed));
|
|
6764
6751
|
} catch (error) {
|
|
@@ -6780,9 +6767,9 @@ var Indexer = class {
|
|
|
6780
6767
|
atomicWriteSync(targetPath, data) {
|
|
6781
6768
|
const lease = this.requireActiveLease();
|
|
6782
6769
|
const tempPath = createLeaseTemporaryPath(targetPath, lease.owner, "tmp");
|
|
6783
|
-
|
|
6770
|
+
mkdirSync2(path11.dirname(targetPath), { recursive: true });
|
|
6784
6771
|
try {
|
|
6785
|
-
|
|
6772
|
+
writeFileSync2(tempPath, data);
|
|
6786
6773
|
renameSync2(tempPath, targetPath);
|
|
6787
6774
|
} finally {
|
|
6788
6775
|
removeLeaseTemporaryPath(tempPath);
|
|
@@ -6790,14 +6777,14 @@ var Indexer = class {
|
|
|
6790
6777
|
}
|
|
6791
6778
|
saveInvertedIndex(invertedIndex) {
|
|
6792
6779
|
this.atomicWriteSync(
|
|
6793
|
-
|
|
6780
|
+
path11.join(this.indexPath, "inverted-index.json"),
|
|
6794
6781
|
invertedIndex.serialize()
|
|
6795
6782
|
);
|
|
6796
6783
|
}
|
|
6797
6784
|
getScopedRoots() {
|
|
6798
|
-
const roots = /* @__PURE__ */ new Set([
|
|
6785
|
+
const roots = /* @__PURE__ */ new Set([path11.resolve(this.projectRoot)]);
|
|
6799
6786
|
for (const kbRoot of this.config.knowledgeBases) {
|
|
6800
|
-
roots.add(
|
|
6787
|
+
roots.add(path11.resolve(this.projectRoot, kbRoot));
|
|
6801
6788
|
}
|
|
6802
6789
|
return Array.from(roots);
|
|
6803
6790
|
}
|
|
@@ -6806,31 +6793,54 @@ var Indexer = class {
|
|
|
6806
6793
|
if (this.config.scope !== "global") {
|
|
6807
6794
|
return branchName;
|
|
6808
6795
|
}
|
|
6809
|
-
const projectHash = hashContent(
|
|
6796
|
+
const projectHash = hashContent(path11.resolve(this.projectRoot)).slice(0, 16);
|
|
6810
6797
|
return `${projectHash}:${branchName}`;
|
|
6811
6798
|
}
|
|
6812
6799
|
getBranchCatalogKeyFor(branchName) {
|
|
6813
6800
|
if (this.config.scope !== "global") {
|
|
6814
6801
|
return branchName;
|
|
6815
6802
|
}
|
|
6816
|
-
const projectHash = hashContent(
|
|
6803
|
+
const projectHash = hashContent(path11.resolve(this.projectRoot)).slice(0, 16);
|
|
6817
6804
|
return `${projectHash}:${branchName}`;
|
|
6818
6805
|
}
|
|
6819
6806
|
getLegacyBranchCatalogKey() {
|
|
6820
6807
|
return this.currentBranch || "default";
|
|
6821
6808
|
}
|
|
6822
6809
|
getLegacyMigrationMetadataKey() {
|
|
6823
|
-
const projectHash = hashContent(
|
|
6810
|
+
const projectHash = hashContent(path11.resolve(this.projectRoot)).slice(0, 16);
|
|
6824
6811
|
return `index.globalBranchMigration.${projectHash}`;
|
|
6825
6812
|
}
|
|
6826
6813
|
getProjectEmbeddingStrategyMetadataKey() {
|
|
6827
|
-
const projectHash = hashContent(
|
|
6814
|
+
const projectHash = hashContent(path11.resolve(this.projectRoot)).slice(0, 16);
|
|
6828
6815
|
return `index.embeddingStrategyVersion.${projectHash}`;
|
|
6829
6816
|
}
|
|
6830
6817
|
getProjectForceReembedMetadataKey() {
|
|
6831
|
-
const projectHash = hashContent(
|
|
6818
|
+
const projectHash = hashContent(path11.resolve(this.projectRoot)).slice(0, 16);
|
|
6832
6819
|
return `index.forceReembed.${projectHash}`;
|
|
6833
6820
|
}
|
|
6821
|
+
getCallGraphResolutionMetadataKey() {
|
|
6822
|
+
if (this.config.scope !== "global") {
|
|
6823
|
+
return "index.callGraphResolutionVersion";
|
|
6824
|
+
}
|
|
6825
|
+
const projectHash = hashContent(path11.resolve(this.projectRoot)).slice(0, 16);
|
|
6826
|
+
return `index.callGraphResolutionVersion.${projectHash}`;
|
|
6827
|
+
}
|
|
6828
|
+
getSwiftParserVersionMetadataKey() {
|
|
6829
|
+
const key = "index.parser.swiftVersion";
|
|
6830
|
+
if (this.config.scope !== "global") {
|
|
6831
|
+
return key;
|
|
6832
|
+
}
|
|
6833
|
+
const projectHash = hashContent(path11.resolve(this.projectRoot)).slice(0, 16);
|
|
6834
|
+
return `${key}.${projectHash}`;
|
|
6835
|
+
}
|
|
6836
|
+
getMetalParserVersionMetadataKey() {
|
|
6837
|
+
const key = "index.parser.metalVersion";
|
|
6838
|
+
if (this.config.scope !== "global") {
|
|
6839
|
+
return key;
|
|
6840
|
+
}
|
|
6841
|
+
const projectHash = hashContent(path11.resolve(this.projectRoot)).slice(0, 16);
|
|
6842
|
+
return `${key}.${projectHash}`;
|
|
6843
|
+
}
|
|
6834
6844
|
hasProjectForceReembedPending() {
|
|
6835
6845
|
return this.config.scope === "global" && this.database?.getMetadata(this.getProjectForceReembedMetadataKey()) === "true";
|
|
6836
6846
|
}
|
|
@@ -6922,7 +6932,7 @@ var Indexer = class {
|
|
|
6922
6932
|
if (!this.database) {
|
|
6923
6933
|
return { chunkIds, symbolIds };
|
|
6924
6934
|
}
|
|
6925
|
-
const projectRootPath =
|
|
6935
|
+
const projectRootPath = path11.resolve(this.projectRoot);
|
|
6926
6936
|
const projectLocalFilePaths = /* @__PURE__ */ new Set([
|
|
6927
6937
|
...Array.from(this.fileHashCache.keys()).filter(
|
|
6928
6938
|
(filePath) => this.isFileInCurrentScope(filePath, roots) && isPathWithinRoot(filePath, projectRootPath)
|
|
@@ -6945,7 +6955,7 @@ var Indexer = class {
|
|
|
6945
6955
|
if (this.config.scope !== "global") {
|
|
6946
6956
|
return this.getBranchCatalogCleanupKeys();
|
|
6947
6957
|
}
|
|
6948
|
-
const projectHash = hashContent(
|
|
6958
|
+
const projectHash = hashContent(path11.resolve(this.projectRoot)).slice(0, 16);
|
|
6949
6959
|
const keys = /* @__PURE__ */ new Set();
|
|
6950
6960
|
const projectChunkIdSet = new Set(projectChunkIds);
|
|
6951
6961
|
const projectSymbolIdSet = new Set(projectSymbolIds);
|
|
@@ -7029,7 +7039,7 @@ var Indexer = class {
|
|
|
7029
7039
|
if (!this.database || this.config.scope !== "global") {
|
|
7030
7040
|
return false;
|
|
7031
7041
|
}
|
|
7032
|
-
const projectHash = hashContent(
|
|
7042
|
+
const projectHash = hashContent(path11.resolve(this.projectRoot)).slice(0, 16);
|
|
7033
7043
|
const roots = this.getScopedRoots();
|
|
7034
7044
|
const { chunkIds: projectLocalChunkIds, symbolIds: projectLocalSymbolIds } = this.getProjectLocalScopedOwnershipIds(roots);
|
|
7035
7045
|
return this.database.getAllBranches().some(
|
|
@@ -7063,7 +7073,7 @@ var Indexer = class {
|
|
|
7063
7073
|
...Array.from(this.fileHashCache.keys()).filter((filePath) => this.isFileInCurrentScope(filePath, roots)),
|
|
7064
7074
|
...scopedEntries.map(({ metadata }) => metadata.filePath)
|
|
7065
7075
|
]);
|
|
7066
|
-
const projectRootPath =
|
|
7076
|
+
const projectRootPath = path11.resolve(this.projectRoot);
|
|
7067
7077
|
const projectLocalFilePaths = new Set(
|
|
7068
7078
|
Array.from(filePaths).filter((filePath) => isPathWithinRoot(filePath, projectRootPath))
|
|
7069
7079
|
);
|
|
@@ -7141,7 +7151,7 @@ var Indexer = class {
|
|
|
7141
7151
|
});
|
|
7142
7152
|
}
|
|
7143
7153
|
if (this.config.scope === "global") {
|
|
7144
|
-
if (
|
|
7154
|
+
if (existsSync7(this.fileHashCachePath)) {
|
|
7145
7155
|
unlinkSync(this.fileHashCachePath);
|
|
7146
7156
|
}
|
|
7147
7157
|
await this.healthCheckUnlocked();
|
|
@@ -7161,10 +7171,10 @@ var Indexer = class {
|
|
|
7161
7171
|
}
|
|
7162
7172
|
}
|
|
7163
7173
|
loadSerializedFailedBatches() {
|
|
7164
|
-
if (!
|
|
7174
|
+
if (!existsSync7(this.failedBatchesPath)) {
|
|
7165
7175
|
return [];
|
|
7166
7176
|
}
|
|
7167
|
-
const data =
|
|
7177
|
+
const data = readFileSync6(this.failedBatchesPath, "utf-8");
|
|
7168
7178
|
const parsed = JSON.parse(data);
|
|
7169
7179
|
return parsed.map((batch) => {
|
|
7170
7180
|
const chunks = Array.isArray(batch.chunks) ? batch.chunks : [];
|
|
@@ -7181,7 +7191,7 @@ var Indexer = class {
|
|
|
7181
7191
|
}
|
|
7182
7192
|
saveFailedBatches(batches) {
|
|
7183
7193
|
if (batches.length === 0) {
|
|
7184
|
-
if (
|
|
7194
|
+
if (existsSync7(this.failedBatchesPath)) {
|
|
7185
7195
|
try {
|
|
7186
7196
|
unlinkSync(this.failedBatchesPath);
|
|
7187
7197
|
} catch {
|
|
@@ -7473,12 +7483,12 @@ var Indexer = class {
|
|
|
7473
7483
|
}
|
|
7474
7484
|
}
|
|
7475
7485
|
captureReaderArtifactFingerprint() {
|
|
7476
|
-
const storePath =
|
|
7486
|
+
const storePath = path11.join(this.indexPath, "vectors");
|
|
7477
7487
|
return {
|
|
7478
7488
|
vectors: `${this.getReaderFileFingerprint(storePath)}|${this.getReaderFileFingerprint(`${storePath}.meta.json`)}`,
|
|
7479
|
-
keyword: this.getReaderFileFingerprint(
|
|
7480
|
-
database: this.getReaderFileFingerprint(
|
|
7481
|
-
databaseIdentity: this.getReaderFileFingerprint(
|
|
7489
|
+
keyword: this.getReaderFileFingerprint(path11.join(this.indexPath, "inverted-index.json")),
|
|
7490
|
+
database: this.getReaderFileFingerprint(path11.join(this.indexPath, "codebase.db")),
|
|
7491
|
+
databaseIdentity: this.getReaderFileFingerprint(path11.join(this.indexPath, "codebase.db"), true)
|
|
7482
7492
|
};
|
|
7483
7493
|
}
|
|
7484
7494
|
refreshReaderArtifacts() {
|
|
@@ -7503,13 +7513,13 @@ var Indexer = class {
|
|
|
7503
7513
|
issues.set(component, this.createReadIssue(component, message));
|
|
7504
7514
|
this.readerArtifactRetryAfter.set(component, Date.now() + READER_ARTIFACT_RETRY_INTERVAL_MS);
|
|
7505
7515
|
};
|
|
7506
|
-
const storePath =
|
|
7516
|
+
const storePath = path11.join(this.indexPath, "vectors");
|
|
7507
7517
|
const vectorMetadataPath = `${storePath}.meta.json`;
|
|
7508
|
-
const invertedIndexPath =
|
|
7509
|
-
const dbPath =
|
|
7518
|
+
const invertedIndexPath = path11.join(this.indexPath, "inverted-index.json");
|
|
7519
|
+
const dbPath = path11.join(this.indexPath, "codebase.db");
|
|
7510
7520
|
if (vectorsChanged || retryDue("vectors")) {
|
|
7511
|
-
const vectorStoreExists =
|
|
7512
|
-
const vectorMetadataExists =
|
|
7521
|
+
const vectorStoreExists = existsSync7(storePath);
|
|
7522
|
+
const vectorMetadataExists = existsSync7(vectorMetadataPath);
|
|
7513
7523
|
if (vectorStoreExists && vectorMetadataExists) {
|
|
7514
7524
|
try {
|
|
7515
7525
|
const store = new VectorStore(storePath, this.configuredProviderInfo.modelInfo.dimensions);
|
|
@@ -7524,8 +7534,8 @@ var Indexer = class {
|
|
|
7524
7534
|
setIssue("vectors", this.getVectorReadIssueMessage());
|
|
7525
7535
|
}
|
|
7526
7536
|
}
|
|
7527
|
-
if (keywordChanged || retryDue("keyword") || !
|
|
7528
|
-
if (
|
|
7537
|
+
if (keywordChanged || retryDue("keyword") || !existsSync7(invertedIndexPath) && (this.store?.count() ?? 0) > 0) {
|
|
7538
|
+
if (existsSync7(invertedIndexPath)) {
|
|
7529
7539
|
try {
|
|
7530
7540
|
const invertedIndex = new InvertedIndex(invertedIndexPath);
|
|
7531
7541
|
invertedIndex.load();
|
|
@@ -7540,7 +7550,7 @@ var Indexer = class {
|
|
|
7540
7550
|
}
|
|
7541
7551
|
}
|
|
7542
7552
|
if (databaseReplaced || databaseChanged && issues.has("database") || retryDue("database")) {
|
|
7543
|
-
if (
|
|
7553
|
+
if (existsSync7(dbPath)) {
|
|
7544
7554
|
try {
|
|
7545
7555
|
const database = Database.openReadOnly(dbPath);
|
|
7546
7556
|
if (this.database) {
|
|
@@ -7631,11 +7641,11 @@ var Indexer = class {
|
|
|
7631
7641
|
}
|
|
7632
7642
|
}
|
|
7633
7643
|
const dimensions = this.configuredProviderInfo.modelInfo.dimensions;
|
|
7634
|
-
const storePath =
|
|
7644
|
+
const storePath = path11.join(this.indexPath, "vectors");
|
|
7635
7645
|
const vectorMetadataPath = `${storePath}.meta.json`;
|
|
7636
|
-
const invertedIndexPath =
|
|
7637
|
-
const dbPath =
|
|
7638
|
-
let dbIsNew = !
|
|
7646
|
+
const invertedIndexPath = path11.join(this.indexPath, "inverted-index.json");
|
|
7647
|
+
const dbPath = path11.join(this.indexPath, "codebase.db");
|
|
7648
|
+
let dbIsNew = !existsSync7(dbPath);
|
|
7639
7649
|
const readerArtifactFingerprint = mode === "reader" ? this.captureReaderArtifactFingerprint() : null;
|
|
7640
7650
|
if (mode === "writer") {
|
|
7641
7651
|
await fsPromises2.mkdir(this.indexPath, { recursive: true });
|
|
@@ -7654,14 +7664,14 @@ var Indexer = class {
|
|
|
7654
7664
|
await this.resetLocalIndexArtifacts();
|
|
7655
7665
|
}
|
|
7656
7666
|
this.store = new VectorStore(storePath, dimensions);
|
|
7657
|
-
if (
|
|
7667
|
+
if (existsSync7(storePath) || existsSync7(vectorMetadataPath)) {
|
|
7658
7668
|
this.store.load();
|
|
7659
7669
|
}
|
|
7660
7670
|
this.invertedIndex = new InvertedIndex(invertedIndexPath);
|
|
7661
7671
|
try {
|
|
7662
7672
|
this.invertedIndex.load();
|
|
7663
7673
|
} catch {
|
|
7664
|
-
if (
|
|
7674
|
+
if (existsSync7(invertedIndexPath)) {
|
|
7665
7675
|
await fsPromises2.unlink(invertedIndexPath);
|
|
7666
7676
|
}
|
|
7667
7677
|
this.invertedIndex = new InvertedIndex(invertedIndexPath);
|
|
@@ -7679,8 +7689,8 @@ var Indexer = class {
|
|
|
7679
7689
|
}
|
|
7680
7690
|
} else {
|
|
7681
7691
|
this.store = new VectorStore(storePath, dimensions);
|
|
7682
|
-
const vectorStoreExists =
|
|
7683
|
-
const vectorMetadataExists =
|
|
7692
|
+
const vectorStoreExists = existsSync7(storePath);
|
|
7693
|
+
const vectorMetadataExists = existsSync7(vectorMetadataPath);
|
|
7684
7694
|
const vectorReadFailureMessage = this.getVectorReadIssueMessage();
|
|
7685
7695
|
if (vectorStoreExists !== vectorMetadataExists) {
|
|
7686
7696
|
this.recordReadIssue("vectors", vectorReadFailureMessage);
|
|
@@ -7693,7 +7703,7 @@ var Indexer = class {
|
|
|
7693
7703
|
}
|
|
7694
7704
|
}
|
|
7695
7705
|
this.invertedIndex = new InvertedIndex(invertedIndexPath);
|
|
7696
|
-
if (
|
|
7706
|
+
if (existsSync7(invertedIndexPath)) {
|
|
7697
7707
|
try {
|
|
7698
7708
|
this.invertedIndex.load();
|
|
7699
7709
|
} catch (error) {
|
|
@@ -7707,7 +7717,7 @@ var Indexer = class {
|
|
|
7707
7717
|
} else if (this.store.count() > 0) {
|
|
7708
7718
|
this.recordReadIssue("keyword", this.getKeywordReadIssueMessage());
|
|
7709
7719
|
}
|
|
7710
|
-
if (
|
|
7720
|
+
if (existsSync7(dbPath)) {
|
|
7711
7721
|
try {
|
|
7712
7722
|
this.database = Database.openReadOnly(dbPath);
|
|
7713
7723
|
} catch (error) {
|
|
@@ -7798,7 +7808,7 @@ var Indexer = class {
|
|
|
7798
7808
|
if (await this.tryResetCorruptedIndex("running automatic orphan garbage collection", error)) {
|
|
7799
7809
|
return {
|
|
7800
7810
|
resetCorruptedIndex: true,
|
|
7801
|
-
warning: this.getCorruptedIndexWarning(
|
|
7811
|
+
warning: this.getCorruptedIndexWarning(path11.join(this.indexPath, "codebase.db"))
|
|
7802
7812
|
};
|
|
7803
7813
|
}
|
|
7804
7814
|
throw error;
|
|
@@ -7813,7 +7823,7 @@ var Indexer = class {
|
|
|
7813
7823
|
return;
|
|
7814
7824
|
}
|
|
7815
7825
|
const retainedEntries = store.getAllMetadata().filter(({ key }) => !excludedSet.has(key));
|
|
7816
|
-
const storeBasePath =
|
|
7826
|
+
const storeBasePath = path11.join(this.indexPath, "vectors");
|
|
7817
7827
|
const storeIndexPath = storeBasePath;
|
|
7818
7828
|
const storeMetadataPath = `${storeBasePath}.meta.json`;
|
|
7819
7829
|
const lease = this.requireActiveLease();
|
|
@@ -7823,18 +7833,18 @@ var Indexer = class {
|
|
|
7823
7833
|
let backedUpMetadata = false;
|
|
7824
7834
|
let rebuiltCount = 0;
|
|
7825
7835
|
let skippedCount = 0;
|
|
7826
|
-
if (
|
|
7836
|
+
if (existsSync7(backupIndexPath)) {
|
|
7827
7837
|
unlinkSync(backupIndexPath);
|
|
7828
7838
|
}
|
|
7829
|
-
if (
|
|
7839
|
+
if (existsSync7(backupMetadataPath)) {
|
|
7830
7840
|
unlinkSync(backupMetadataPath);
|
|
7831
7841
|
}
|
|
7832
7842
|
try {
|
|
7833
|
-
if (
|
|
7843
|
+
if (existsSync7(storeIndexPath)) {
|
|
7834
7844
|
renameSync2(storeIndexPath, backupIndexPath);
|
|
7835
7845
|
backedUpIndex = true;
|
|
7836
7846
|
}
|
|
7837
|
-
if (
|
|
7847
|
+
if (existsSync7(storeMetadataPath)) {
|
|
7838
7848
|
renameSync2(storeMetadataPath, backupMetadataPath);
|
|
7839
7849
|
backedUpMetadata = true;
|
|
7840
7850
|
}
|
|
@@ -7855,10 +7865,10 @@ var Indexer = class {
|
|
|
7855
7865
|
rebuiltCount += 1;
|
|
7856
7866
|
}
|
|
7857
7867
|
store.save();
|
|
7858
|
-
if (backedUpIndex &&
|
|
7868
|
+
if (backedUpIndex && existsSync7(backupIndexPath)) {
|
|
7859
7869
|
unlinkSync(backupIndexPath);
|
|
7860
7870
|
}
|
|
7861
|
-
if (backedUpMetadata &&
|
|
7871
|
+
if (backedUpMetadata && existsSync7(backupMetadataPath)) {
|
|
7862
7872
|
unlinkSync(backupMetadataPath);
|
|
7863
7873
|
}
|
|
7864
7874
|
this.logger.gc("info", "Rebuilt vector store to avoid native remove", {
|
|
@@ -7871,16 +7881,16 @@ var Indexer = class {
|
|
|
7871
7881
|
store.clear();
|
|
7872
7882
|
} catch {
|
|
7873
7883
|
}
|
|
7874
|
-
if (
|
|
7884
|
+
if (existsSync7(storeIndexPath)) {
|
|
7875
7885
|
unlinkSync(storeIndexPath);
|
|
7876
7886
|
}
|
|
7877
|
-
if (
|
|
7887
|
+
if (existsSync7(storeMetadataPath)) {
|
|
7878
7888
|
unlinkSync(storeMetadataPath);
|
|
7879
7889
|
}
|
|
7880
|
-
if (backedUpIndex &&
|
|
7890
|
+
if (backedUpIndex && existsSync7(backupIndexPath)) {
|
|
7881
7891
|
renameSync2(backupIndexPath, storeIndexPath);
|
|
7882
7892
|
}
|
|
7883
|
-
if (backedUpMetadata &&
|
|
7893
|
+
if (backedUpMetadata && existsSync7(backupMetadataPath)) {
|
|
7884
7894
|
renameSync2(backupMetadataPath, storeMetadataPath);
|
|
7885
7895
|
}
|
|
7886
7896
|
if (backedUpIndex || backedUpMetadata) {
|
|
@@ -7908,15 +7918,15 @@ var Indexer = class {
|
|
|
7908
7918
|
this.readerArtifactRetryAfter.clear();
|
|
7909
7919
|
this.fileHashCache.clear();
|
|
7910
7920
|
const resetPaths = [
|
|
7911
|
-
|
|
7912
|
-
|
|
7913
|
-
|
|
7914
|
-
|
|
7915
|
-
|
|
7916
|
-
|
|
7917
|
-
|
|
7918
|
-
|
|
7919
|
-
|
|
7921
|
+
path11.join(this.indexPath, "codebase.db"),
|
|
7922
|
+
path11.join(this.indexPath, "codebase.db-shm"),
|
|
7923
|
+
path11.join(this.indexPath, "codebase.db-wal"),
|
|
7924
|
+
path11.join(this.indexPath, "vectors"),
|
|
7925
|
+
path11.join(this.indexPath, "vectors.usearch"),
|
|
7926
|
+
path11.join(this.indexPath, "vectors.meta.json"),
|
|
7927
|
+
path11.join(this.indexPath, "inverted-index.json"),
|
|
7928
|
+
path11.join(this.indexPath, "file-hashes.json"),
|
|
7929
|
+
path11.join(this.indexPath, "failed-batches.json")
|
|
7920
7930
|
];
|
|
7921
7931
|
await Promise.all(resetPaths.map((targetPath) => fsPromises2.rm(targetPath, { recursive: true, force: true })));
|
|
7922
7932
|
await fsPromises2.mkdir(this.indexPath, { recursive: true });
|
|
@@ -7925,7 +7935,7 @@ var Indexer = class {
|
|
|
7925
7935
|
if (!isSqliteCorruptionError(error)) {
|
|
7926
7936
|
return false;
|
|
7927
7937
|
}
|
|
7928
|
-
const dbPath =
|
|
7938
|
+
const dbPath = path11.join(this.indexPath, "codebase.db");
|
|
7929
7939
|
const warning = this.getCorruptedIndexWarning(dbPath);
|
|
7930
7940
|
const errorMessage = getErrorMessage2(error);
|
|
7931
7941
|
if (this.config.scope === "global") {
|
|
@@ -7991,6 +8001,7 @@ var Indexer = class {
|
|
|
7991
8001
|
this.database.setMetadata("index.embeddingProvider", provider.provider);
|
|
7992
8002
|
this.database.setMetadata("index.embeddingModel", provider.modelInfo.model);
|
|
7993
8003
|
this.database.setMetadata("index.embeddingDimensions", provider.modelInfo.dimensions.toString());
|
|
8004
|
+
this.database.setMetadata(this.getCallGraphResolutionMetadataKey(), CALL_GRAPH_RESOLUTION_VERSION);
|
|
7994
8005
|
if (this.config.scope === "global") {
|
|
7995
8006
|
if (completeProjectEmbeddingStrategyReset) {
|
|
7996
8007
|
this.database.setMetadata(this.getProjectEmbeddingStrategyMetadataKey(), EMBEDDING_STRATEGY_VERSION);
|
|
@@ -8178,6 +8189,20 @@ var Indexer = class {
|
|
|
8178
8189
|
totalChunks: 0
|
|
8179
8190
|
});
|
|
8180
8191
|
this.loadFileHashCache();
|
|
8192
|
+
const swiftParserMetadataKey = this.getSwiftParserVersionMetadataKey();
|
|
8193
|
+
const reparseCachedSwiftFiles = database.getMetadata(swiftParserMetadataKey) !== SWIFT_PARSER_VERSION;
|
|
8194
|
+
const metalParserMetadataKey = this.getMetalParserVersionMetadataKey();
|
|
8195
|
+
const reparseCachedMetalFiles = database.getMetadata(metalParserMetadataKey) !== METAL_PARSER_VERSION;
|
|
8196
|
+
if (reparseCachedSwiftFiles && Array.from(this.fileHashCache.keys()).some(
|
|
8197
|
+
(filePath) => path11.extname(filePath).toLowerCase() === ".swift"
|
|
8198
|
+
)) {
|
|
8199
|
+
this.logger.info("Reindexing cached Swift files for parser support");
|
|
8200
|
+
}
|
|
8201
|
+
if (reparseCachedMetalFiles && Array.from(this.fileHashCache.keys()).some(
|
|
8202
|
+
(filePath) => path11.extname(filePath).toLowerCase() === ".metal"
|
|
8203
|
+
)) {
|
|
8204
|
+
this.logger.info("Reindexing cached Metal files for parser support");
|
|
8205
|
+
}
|
|
8181
8206
|
const includePatterns = [...this.config.include, ...this.config.additionalInclude];
|
|
8182
8207
|
const { files, skipped } = await collectFiles(
|
|
8183
8208
|
this.projectRoot,
|
|
@@ -8197,10 +8222,17 @@ var Indexer = class {
|
|
|
8197
8222
|
const changedFiles = [];
|
|
8198
8223
|
const unchangedFilePaths = /* @__PURE__ */ new Set();
|
|
8199
8224
|
const currentFileHashes = /* @__PURE__ */ new Map();
|
|
8225
|
+
const needsCallGraphResolutionMigration = database.getMetadata(this.getCallGraphResolutionMetadataKey()) !== CALL_GRAPH_RESOLUTION_VERSION;
|
|
8200
8226
|
for (const f of files) {
|
|
8201
8227
|
const currentHash = hashFile(f.path);
|
|
8202
8228
|
currentFileHashes.set(f.path, currentHash);
|
|
8203
|
-
|
|
8229
|
+
const cachedHashMatches = this.fileHashCache.get(f.path) === currentHash;
|
|
8230
|
+
const needsCallGraphRefresh = cachedHashMatches && needsCallGraphResolutionMigration && database.getChunksByFile(f.path).some(
|
|
8231
|
+
(chunk) => chunk.language === "php" || chunk.language === "c" || chunk.language === "cpp"
|
|
8232
|
+
);
|
|
8233
|
+
const requiresSwiftParserUpgrade = reparseCachedSwiftFiles && path11.extname(f.path).toLowerCase() === ".swift";
|
|
8234
|
+
const requiresMetalParserUpgrade = reparseCachedMetalFiles && path11.extname(f.path).toLowerCase() === ".metal";
|
|
8235
|
+
if (cachedHashMatches && !needsCallGraphRefresh && !requiresSwiftParserUpgrade && !requiresMetalParserUpgrade) {
|
|
8204
8236
|
unchangedFilePaths.add(f.path);
|
|
8205
8237
|
this.logger.recordCacheHit();
|
|
8206
8238
|
} else {
|
|
@@ -8302,7 +8334,7 @@ var Indexer = class {
|
|
|
8302
8334
|
for (const parsed of parsedFiles) {
|
|
8303
8335
|
currentFilePaths.add(parsed.path);
|
|
8304
8336
|
if (parsed.chunks.length === 0) {
|
|
8305
|
-
const relativePath =
|
|
8337
|
+
const relativePath = path11.relative(this.projectRoot, parsed.path);
|
|
8306
8338
|
stats.parseFailures.push(relativePath);
|
|
8307
8339
|
}
|
|
8308
8340
|
let chunksToProcess = parsed.chunks;
|
|
@@ -8402,16 +8434,28 @@ var Indexer = class {
|
|
|
8402
8434
|
const fileSymbols = [];
|
|
8403
8435
|
for (const chunk of parsed.chunks) {
|
|
8404
8436
|
if (!chunk.name || !CALL_GRAPH_SYMBOL_CHUNK_TYPES.has(chunk.chunkType)) continue;
|
|
8405
|
-
const
|
|
8437
|
+
const existingMetalSymbol = chunk.language === "metal" ? fileSymbols.find(
|
|
8438
|
+
(symbol2) => symbol2.name === chunk.name && symbol2.kind === chunk.chunkType && symbol2.startLine <= chunk.endLine && chunk.startLine <= symbol2.endLine
|
|
8439
|
+
) : void 0;
|
|
8440
|
+
if (existingMetalSymbol) {
|
|
8441
|
+
existingMetalSymbol.startLine = Math.min(existingMetalSymbol.startLine, chunk.startLine);
|
|
8442
|
+
existingMetalSymbol.endLine = Math.max(existingMetalSymbol.endLine, chunk.endLine);
|
|
8443
|
+
existingMetalSymbol.startCol = Math.min(existingMetalSymbol.startCol, chunk.startCol ?? 0);
|
|
8444
|
+
existingMetalSymbol.endCol = Math.max(existingMetalSymbol.endCol, chunk.endCol ?? 0);
|
|
8445
|
+
continue;
|
|
8446
|
+
}
|
|
8447
|
+
const symbolId = `sym_${hashContent(
|
|
8448
|
+
parsed.path + ":" + chunk.name + ":" + chunk.chunkType + ":" + chunk.startLine + ":" + (chunk.startCol ?? 0)
|
|
8449
|
+
).slice(0, 16)}`;
|
|
8406
8450
|
const symbol = {
|
|
8407
8451
|
id: symbolId,
|
|
8408
8452
|
filePath: parsed.path,
|
|
8409
8453
|
name: chunk.name,
|
|
8410
8454
|
kind: chunk.chunkType,
|
|
8411
8455
|
startLine: chunk.startLine,
|
|
8412
|
-
startCol: 0,
|
|
8456
|
+
startCol: chunk.startCol ?? 0,
|
|
8413
8457
|
endLine: chunk.endLine,
|
|
8414
|
-
endCol: 0,
|
|
8458
|
+
endCol: chunk.endCol ?? 0,
|
|
8415
8459
|
language: chunk.language
|
|
8416
8460
|
};
|
|
8417
8461
|
fileSymbols.push(symbol);
|
|
@@ -8436,8 +8480,10 @@ var Indexer = class {
|
|
|
8436
8480
|
if (callSites.length === 0) continue;
|
|
8437
8481
|
const edges = [];
|
|
8438
8482
|
for (const site of callSites) {
|
|
8439
|
-
const enclosingSymbol =
|
|
8440
|
-
|
|
8483
|
+
const enclosingSymbol = findEnclosingSymbol(
|
|
8484
|
+
fileSymbols,
|
|
8485
|
+
site.line,
|
|
8486
|
+
site.column
|
|
8441
8487
|
);
|
|
8442
8488
|
if (!enclosingSymbol) continue;
|
|
8443
8489
|
const edgeId = `edge_${hashContent(enclosingSymbol.id + ":" + site.calleeName + ":" + site.line + ":" + site.column).slice(0, 16)}`;
|
|
@@ -8456,7 +8502,21 @@ var Indexer = class {
|
|
|
8456
8502
|
if (edges.length > 0) {
|
|
8457
8503
|
database.upsertCallEdgesBatch(edges);
|
|
8458
8504
|
for (const edge of edges) {
|
|
8459
|
-
|
|
8505
|
+
let candidates = symbolsByName.get(normalizeSymbolKey(edge.targetName));
|
|
8506
|
+
if (fileLanguage === "php" && candidates) {
|
|
8507
|
+
if (edge.callType === "Constructor") {
|
|
8508
|
+
candidates = candidates.filter(
|
|
8509
|
+
(candidate) => PHP_CLASS_SYMBOL_CHUNK_TYPES.has(candidate.kind)
|
|
8510
|
+
);
|
|
8511
|
+
} else if (edge.callType === "Call") {
|
|
8512
|
+
candidates = candidates.filter(
|
|
8513
|
+
(candidate) => PHP_FUNCTION_SYMBOL_CHUNK_TYPES.has(candidate.kind)
|
|
8514
|
+
);
|
|
8515
|
+
}
|
|
8516
|
+
}
|
|
8517
|
+
candidates = candidates?.filter(
|
|
8518
|
+
(symbol) => isCompatibleCFamilyCallTarget(fileLanguage, edge.callType, symbol.kind)
|
|
8519
|
+
);
|
|
8460
8520
|
if (candidates && candidates.length === 1) {
|
|
8461
8521
|
database.resolveCallEdge(edge.id, candidates[0].id);
|
|
8462
8522
|
}
|
|
@@ -8498,8 +8558,8 @@ var Indexer = class {
|
|
|
8498
8558
|
database.addChunksToBranchBatch(branchCatalogKey, Array.from(currentChunkIds));
|
|
8499
8559
|
database.clearBranchSymbols(branchCatalogKey);
|
|
8500
8560
|
database.addSymbolsToBranchBatch(branchCatalogKey, Array.from(allSymbolIds));
|
|
8501
|
-
const vectorPath =
|
|
8502
|
-
const shouldFingerprintLegacyPair = !store.hasFingerprint() &&
|
|
8561
|
+
const vectorPath = path11.join(this.indexPath, "vectors");
|
|
8562
|
+
const shouldFingerprintLegacyPair = !store.hasFingerprint() && existsSync7(vectorPath) && existsSync7(`${vectorPath}.meta.json`);
|
|
8503
8563
|
if (backfilledBlameMetadata || shouldFingerprintLegacyPair) {
|
|
8504
8564
|
store.save();
|
|
8505
8565
|
}
|
|
@@ -8511,6 +8571,8 @@ var Indexer = class {
|
|
|
8511
8571
|
this.saveFileHashCache();
|
|
8512
8572
|
this.saveFailedBatches([]);
|
|
8513
8573
|
}
|
|
8574
|
+
database.setMetadata(swiftParserMetadataKey, SWIFT_PARSER_VERSION);
|
|
8575
|
+
database.setMetadata(metalParserMetadataKey, METAL_PARSER_VERSION);
|
|
8514
8576
|
this.saveIndexMetadata(configuredProviderInfo);
|
|
8515
8577
|
this.indexCompatibility = { compatible: true };
|
|
8516
8578
|
stats.durationMs = Date.now() - startTime;
|
|
@@ -8538,6 +8600,8 @@ var Indexer = class {
|
|
|
8538
8600
|
this.saveFileHashCache();
|
|
8539
8601
|
this.saveFailedBatches([]);
|
|
8540
8602
|
}
|
|
8603
|
+
database.setMetadata(swiftParserMetadataKey, SWIFT_PARSER_VERSION);
|
|
8604
|
+
database.setMetadata(metalParserMetadataKey, METAL_PARSER_VERSION);
|
|
8541
8605
|
this.saveIndexMetadata(configuredProviderInfo);
|
|
8542
8606
|
this.indexCompatibility = { compatible: true };
|
|
8543
8607
|
stats.durationMs = Date.now() - startTime;
|
|
@@ -8808,6 +8872,8 @@ var Indexer = class {
|
|
|
8808
8872
|
if (forceScopedReembed && failedForcedChunkIds.size === 0) {
|
|
8809
8873
|
database.deleteMetadata(this.getProjectForceReembedMetadataKey());
|
|
8810
8874
|
}
|
|
8875
|
+
database.setMetadata(swiftParserMetadataKey, SWIFT_PARSER_VERSION);
|
|
8876
|
+
database.setMetadata(metalParserMetadataKey, METAL_PARSER_VERSION);
|
|
8811
8877
|
this.saveIndexMetadata(configuredProviderInfo);
|
|
8812
8878
|
this.indexCompatibility = { compatible: true };
|
|
8813
8879
|
this.logger.recordIndexingEnd();
|
|
@@ -9241,7 +9307,7 @@ var Indexer = class {
|
|
|
9241
9307
|
const removedChunkKeys = [];
|
|
9242
9308
|
const chunkKeysByRemovedFile = /* @__PURE__ */ new Map();
|
|
9243
9309
|
for (const [filePath, chunkKeys] of filePathsToChunkKeys) {
|
|
9244
|
-
if (!
|
|
9310
|
+
if (!existsSync7(filePath)) {
|
|
9245
9311
|
chunkKeysByRemovedFile.set(filePath, chunkKeys);
|
|
9246
9312
|
for (const key of chunkKeys) {
|
|
9247
9313
|
removedChunkKeys.push(key);
|
|
@@ -9290,7 +9356,7 @@ var Indexer = class {
|
|
|
9290
9356
|
gcOrphanSymbols: 0,
|
|
9291
9357
|
gcOrphanCallEdges: 0,
|
|
9292
9358
|
resetCorruptedIndex: true,
|
|
9293
|
-
warning: this.getCorruptedIndexWarning(
|
|
9359
|
+
warning: this.getCorruptedIndexWarning(path11.join(this.indexPath, "codebase.db"))
|
|
9294
9360
|
};
|
|
9295
9361
|
}
|
|
9296
9362
|
this.logger.recordGc(removedCount, gcOrphanChunks, gcOrphanEmbeddings);
|
|
@@ -9720,7 +9786,7 @@ var Indexer = class {
|
|
|
9720
9786
|
"Run index_codebase first to build the call graph and symbol index for this branch."
|
|
9721
9787
|
);
|
|
9722
9788
|
}
|
|
9723
|
-
const absoluteChangedFiles = changedFiles.map((f) =>
|
|
9789
|
+
const absoluteChangedFiles = changedFiles.map((f) => path11.resolve(this.projectRoot, f));
|
|
9724
9790
|
const directSymbols = database.getSymbolsForFiles(absoluteChangedFiles, branchKey);
|
|
9725
9791
|
const directIds = directSymbols.map((s) => s.id);
|
|
9726
9792
|
const direction = opts.direction ?? "both";
|
|
@@ -9803,7 +9869,7 @@ var Indexer = class {
|
|
|
9803
9869
|
projectRoot: this.projectRoot,
|
|
9804
9870
|
baseBranch: this.baseBranch
|
|
9805
9871
|
});
|
|
9806
|
-
const otherAbsolute = otherChanged.files.map((f) =>
|
|
9872
|
+
const otherAbsolute = otherChanged.files.map((f) => path11.resolve(this.projectRoot, f));
|
|
9807
9873
|
const otherBranchKey = this.getBranchCatalogKeyFor(openPr.headRefName);
|
|
9808
9874
|
const otherSymbols = database.getSymbolsForFiles(otherAbsolute, otherBranchKey);
|
|
9809
9875
|
const otherLabels = /* @__PURE__ */ new Set();
|
|
@@ -9867,12 +9933,12 @@ var Indexer = class {
|
|
|
9867
9933
|
if (meta.filePath) filePaths.add(meta.filePath);
|
|
9868
9934
|
}
|
|
9869
9935
|
const directory = options?.directory?.replace(/\/$/, "");
|
|
9870
|
-
const absoluteDirectoryFilter = directory ?
|
|
9936
|
+
const absoluteDirectoryFilter = directory ? path11.resolve(this.projectRoot, directory) : void 0;
|
|
9871
9937
|
for (const filePath of filePaths) {
|
|
9872
9938
|
if (directory) {
|
|
9873
|
-
const absoluteFilePath =
|
|
9939
|
+
const absoluteFilePath = path11.resolve(filePath);
|
|
9874
9940
|
const matchesRelative = filePath === directory || filePath.startsWith(directory + "/");
|
|
9875
|
-
const matchesProjectRelative = absoluteDirectoryFilter !== void 0 && (absoluteFilePath === absoluteDirectoryFilter || absoluteFilePath.startsWith(absoluteDirectoryFilter +
|
|
9941
|
+
const matchesProjectRelative = absoluteDirectoryFilter !== void 0 && (absoluteFilePath === absoluteDirectoryFilter || absoluteFilePath.startsWith(absoluteDirectoryFilter + path11.sep));
|
|
9876
9942
|
if (!matchesRelative && !matchesProjectRelative) {
|
|
9877
9943
|
continue;
|
|
9878
9944
|
}
|
|
@@ -9915,43 +9981,43 @@ var Indexer = class {
|
|
|
9915
9981
|
};
|
|
9916
9982
|
|
|
9917
9983
|
// src/tools/knowledge-base-paths.ts
|
|
9918
|
-
import * as
|
|
9984
|
+
import * as path12 from "path";
|
|
9919
9985
|
function resolveConfigPathValue(value, baseDir) {
|
|
9920
9986
|
const trimmed = value.trim();
|
|
9921
9987
|
if (!trimmed) {
|
|
9922
9988
|
return trimmed;
|
|
9923
9989
|
}
|
|
9924
|
-
const absolutePath =
|
|
9925
|
-
return
|
|
9990
|
+
const absolutePath = path12.isAbsolute(trimmed) ? trimmed : path12.resolve(baseDir, trimmed);
|
|
9991
|
+
return path12.normalize(absolutePath);
|
|
9926
9992
|
}
|
|
9927
9993
|
function serializeConfigPathValue(value, baseDir) {
|
|
9928
9994
|
const trimmed = value.trim();
|
|
9929
9995
|
if (!trimmed) {
|
|
9930
9996
|
return trimmed;
|
|
9931
9997
|
}
|
|
9932
|
-
if (!
|
|
9933
|
-
return normalizePathSeparators(
|
|
9998
|
+
if (!path12.isAbsolute(trimmed)) {
|
|
9999
|
+
return normalizePathSeparators(path12.normalize(trimmed));
|
|
9934
10000
|
}
|
|
9935
|
-
const relativePath =
|
|
9936
|
-
if (!relativePath || !relativePath.startsWith("..") && !
|
|
9937
|
-
return normalizePathSeparators(
|
|
10001
|
+
const relativePath = path12.relative(baseDir, trimmed);
|
|
10002
|
+
if (!relativePath || !relativePath.startsWith("..") && !path12.isAbsolute(relativePath)) {
|
|
10003
|
+
return normalizePathSeparators(path12.normalize(relativePath || "."));
|
|
9938
10004
|
}
|
|
9939
|
-
return
|
|
10005
|
+
return path12.normalize(trimmed);
|
|
9940
10006
|
}
|
|
9941
10007
|
function resolveKnowledgeBasePath(value, projectRoot3) {
|
|
9942
|
-
return
|
|
10008
|
+
return path12.isAbsolute(value) ? value : path12.resolve(projectRoot3, value);
|
|
9943
10009
|
}
|
|
9944
|
-
function
|
|
9945
|
-
return
|
|
10010
|
+
function normalizeKnowledgeBasePath(value, projectRoot3) {
|
|
10011
|
+
return path12.normalize(resolveKnowledgeBasePath(value, projectRoot3));
|
|
9946
10012
|
}
|
|
9947
10013
|
function hasMatchingKnowledgeBasePath(knowledgeBases, inputPath, projectRoot3) {
|
|
9948
|
-
const normalizedInput =
|
|
9949
|
-
return knowledgeBases.some((kb) =>
|
|
10014
|
+
const normalizedInput = path12.normalize(inputPath);
|
|
10015
|
+
return knowledgeBases.some((kb) => normalizeKnowledgeBasePath(kb, projectRoot3) === normalizedInput);
|
|
9950
10016
|
}
|
|
9951
10017
|
function findKnowledgeBasePathIndex(knowledgeBases, inputPath, projectRoot3) {
|
|
9952
|
-
const normalizedInput =
|
|
10018
|
+
const normalizedInput = path12.normalize(inputPath);
|
|
9953
10019
|
return knowledgeBases.findIndex(
|
|
9954
|
-
(kb) =>
|
|
10020
|
+
(kb) => path12.normalize(kb) === normalizedInput || normalizeKnowledgeBasePath(kb, projectRoot3) === normalizedInput
|
|
9955
10021
|
);
|
|
9956
10022
|
}
|
|
9957
10023
|
|
|
@@ -10351,8 +10417,195 @@ ${truncateContent(r.content)}
|
|
|
10351
10417
|
}
|
|
10352
10418
|
|
|
10353
10419
|
// src/tools/config-state.ts
|
|
10354
|
-
import { existsSync as existsSync9, mkdirSync as
|
|
10420
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
10355
10421
|
import * as path15 from "path";
|
|
10422
|
+
|
|
10423
|
+
// src/config/merger.ts
|
|
10424
|
+
import { existsSync as existsSync8, readFileSync as readFileSync7 } from "fs";
|
|
10425
|
+
import * as path14 from "path";
|
|
10426
|
+
|
|
10427
|
+
// src/config/rebase.ts
|
|
10428
|
+
import * as path13 from "path";
|
|
10429
|
+
function isWithinRoot(rootDir, targetPath) {
|
|
10430
|
+
const relativePath = path13.relative(rootDir, targetPath);
|
|
10431
|
+
return relativePath === "" || !relativePath.startsWith("..") && !path13.isAbsolute(relativePath);
|
|
10432
|
+
}
|
|
10433
|
+
function resolveInheritedKnowledgeBaseEntries(values, sourceRoot, targetRoot) {
|
|
10434
|
+
if (!Array.isArray(values)) {
|
|
10435
|
+
return [];
|
|
10436
|
+
}
|
|
10437
|
+
return values.filter((value) => typeof value === "string").map((value) => {
|
|
10438
|
+
const trimmed = value.trim();
|
|
10439
|
+
if (!trimmed) {
|
|
10440
|
+
return trimmed;
|
|
10441
|
+
}
|
|
10442
|
+
if (path13.isAbsolute(trimmed)) {
|
|
10443
|
+
if (isWithinRoot(sourceRoot, trimmed)) {
|
|
10444
|
+
return normalizePathSeparators(path13.normalize(path13.relative(sourceRoot, trimmed) || "."));
|
|
10445
|
+
}
|
|
10446
|
+
return path13.normalize(trimmed);
|
|
10447
|
+
}
|
|
10448
|
+
const resolvedFromSource = path13.resolve(sourceRoot, trimmed);
|
|
10449
|
+
if (isWithinRoot(sourceRoot, resolvedFromSource)) {
|
|
10450
|
+
return normalizePathSeparators(path13.normalize(trimmed));
|
|
10451
|
+
}
|
|
10452
|
+
return normalizePathSeparators(path13.normalize(path13.relative(targetRoot, resolvedFromSource)));
|
|
10453
|
+
}).filter(Boolean);
|
|
10454
|
+
}
|
|
10455
|
+
|
|
10456
|
+
// src/config/merger.ts
|
|
10457
|
+
var PROJECT_OVERRIDE_KEYS = [
|
|
10458
|
+
"embeddingProvider",
|
|
10459
|
+
"customProvider",
|
|
10460
|
+
"embeddingModel",
|
|
10461
|
+
"reranker",
|
|
10462
|
+
"include",
|
|
10463
|
+
"exclude",
|
|
10464
|
+
"indexing",
|
|
10465
|
+
"search",
|
|
10466
|
+
"debug",
|
|
10467
|
+
"scope"
|
|
10468
|
+
];
|
|
10469
|
+
var MERGE_ARRAY_KEYS = ["knowledgeBases", "additionalInclude"];
|
|
10470
|
+
function isRecord(value) {
|
|
10471
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
10472
|
+
}
|
|
10473
|
+
function isStringArray2(value) {
|
|
10474
|
+
return Array.isArray(value) && value.every((item) => typeof item === "string");
|
|
10475
|
+
}
|
|
10476
|
+
function applyProjectOverride(merged, normalizedProjectConfig, globalConfig, key) {
|
|
10477
|
+
if (key in normalizedProjectConfig) {
|
|
10478
|
+
merged[key] = normalizedProjectConfig[key];
|
|
10479
|
+
return;
|
|
10480
|
+
}
|
|
10481
|
+
if (key in globalConfig) {
|
|
10482
|
+
merged[key] = globalConfig[key];
|
|
10483
|
+
}
|
|
10484
|
+
}
|
|
10485
|
+
function mergeUniqueStringArray(values) {
|
|
10486
|
+
return [...new Set(values.map((value) => String(value).trim()))];
|
|
10487
|
+
}
|
|
10488
|
+
function normalizeKnowledgeBasePath2(value) {
|
|
10489
|
+
let normalized = path14.normalize(String(value).trim());
|
|
10490
|
+
const root = path14.parse(normalized).root;
|
|
10491
|
+
while (normalized.length > root.length && /[\\/]$/.test(normalized)) {
|
|
10492
|
+
normalized = normalized.slice(0, -1);
|
|
10493
|
+
}
|
|
10494
|
+
return normalized;
|
|
10495
|
+
}
|
|
10496
|
+
function mergeKnowledgeBasePaths(values) {
|
|
10497
|
+
return [...new Set(values.map((value) => normalizeKnowledgeBasePath2(value)).filter((value) => value.length > 0))];
|
|
10498
|
+
}
|
|
10499
|
+
function validateConfigLayerShape(rawConfig, filePath) {
|
|
10500
|
+
if (!isRecord(rawConfig)) {
|
|
10501
|
+
throw new Error(`Config file ${filePath} must contain a JSON object at the root.`);
|
|
10502
|
+
}
|
|
10503
|
+
if (rawConfig.knowledgeBases !== void 0 && !isStringArray2(rawConfig.knowledgeBases)) {
|
|
10504
|
+
throw new Error(`Config file ${filePath} field 'knowledgeBases' must be an array of strings.`);
|
|
10505
|
+
}
|
|
10506
|
+
if (rawConfig.additionalInclude !== void 0 && !isStringArray2(rawConfig.additionalInclude)) {
|
|
10507
|
+
throw new Error(`Config file ${filePath} field 'additionalInclude' must be an array of strings.`);
|
|
10508
|
+
}
|
|
10509
|
+
if (rawConfig.include !== void 0 && !isStringArray2(rawConfig.include)) {
|
|
10510
|
+
throw new Error(`Config file ${filePath} field 'include' must be an array of strings.`);
|
|
10511
|
+
}
|
|
10512
|
+
if (rawConfig.exclude !== void 0 && !isStringArray2(rawConfig.exclude)) {
|
|
10513
|
+
throw new Error(`Config file ${filePath} field 'exclude' must be an array of strings.`);
|
|
10514
|
+
}
|
|
10515
|
+
for (const section of ["customProvider", "indexing", "search", "debug", "reranker"]) {
|
|
10516
|
+
const value = rawConfig[section];
|
|
10517
|
+
if (value !== void 0 && !isRecord(value)) {
|
|
10518
|
+
throw new Error(`Config file ${filePath} field '${section}' must be an object.`);
|
|
10519
|
+
}
|
|
10520
|
+
}
|
|
10521
|
+
return rawConfig;
|
|
10522
|
+
}
|
|
10523
|
+
function loadJsonFile(filePath) {
|
|
10524
|
+
if (!existsSync8(filePath)) {
|
|
10525
|
+
return null;
|
|
10526
|
+
}
|
|
10527
|
+
try {
|
|
10528
|
+
const content = readFileSync7(filePath, "utf-8");
|
|
10529
|
+
return validateConfigLayerShape(JSON.parse(content), filePath);
|
|
10530
|
+
} catch (error) {
|
|
10531
|
+
if (error instanceof Error && error.message.startsWith("Config file ")) {
|
|
10532
|
+
throw error;
|
|
10533
|
+
}
|
|
10534
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
10535
|
+
throw new Error(`Failed to load config file ${filePath}: ${message}`);
|
|
10536
|
+
}
|
|
10537
|
+
}
|
|
10538
|
+
function loadProjectConfigLayer(projectRoot3, host = "opencode") {
|
|
10539
|
+
const projectConfigPath = resolveProjectConfigPath(projectRoot3, host);
|
|
10540
|
+
const projectConfig = loadJsonFile(projectConfigPath);
|
|
10541
|
+
if (!projectConfig) {
|
|
10542
|
+
return {};
|
|
10543
|
+
}
|
|
10544
|
+
const normalizedConfig = { ...projectConfig };
|
|
10545
|
+
const projectConfigBaseDir = path14.dirname(path14.dirname(projectConfigPath));
|
|
10546
|
+
if (Array.isArray(normalizedConfig.knowledgeBases)) {
|
|
10547
|
+
normalizedConfig.knowledgeBases = resolveInheritedKnowledgeBaseEntries(
|
|
10548
|
+
normalizedConfig.knowledgeBases,
|
|
10549
|
+
projectConfigBaseDir,
|
|
10550
|
+
projectRoot3
|
|
10551
|
+
);
|
|
10552
|
+
}
|
|
10553
|
+
return normalizedConfig;
|
|
10554
|
+
}
|
|
10555
|
+
function loadMergedConfig(projectRoot3, host = "opencode") {
|
|
10556
|
+
const globalConfigPath = resolveGlobalConfigPath(host);
|
|
10557
|
+
const projectConfigPath = resolveProjectConfigPath(projectRoot3, host);
|
|
10558
|
+
let globalConfig = null;
|
|
10559
|
+
let globalConfigError = null;
|
|
10560
|
+
try {
|
|
10561
|
+
globalConfig = loadJsonFile(globalConfigPath);
|
|
10562
|
+
} catch (error) {
|
|
10563
|
+
globalConfigError = error instanceof Error ? error : new Error(String(error));
|
|
10564
|
+
}
|
|
10565
|
+
const projectConfig = loadJsonFile(projectConfigPath);
|
|
10566
|
+
const normalizedProjectConfig = loadProjectConfigLayer(projectRoot3, host);
|
|
10567
|
+
if (globalConfigError) {
|
|
10568
|
+
if (!projectConfig) {
|
|
10569
|
+
throw globalConfigError;
|
|
10570
|
+
}
|
|
10571
|
+
globalConfig = null;
|
|
10572
|
+
}
|
|
10573
|
+
if (!globalConfig && !projectConfig) {
|
|
10574
|
+
return {};
|
|
10575
|
+
}
|
|
10576
|
+
if (!projectConfig && globalConfig) {
|
|
10577
|
+
return globalConfig;
|
|
10578
|
+
}
|
|
10579
|
+
if (!globalConfig && projectConfig) {
|
|
10580
|
+
return normalizedProjectConfig;
|
|
10581
|
+
}
|
|
10582
|
+
if (!globalConfig || !projectConfig) {
|
|
10583
|
+
return globalConfig ?? normalizedProjectConfig;
|
|
10584
|
+
}
|
|
10585
|
+
const merged = { ...globalConfig };
|
|
10586
|
+
for (const key of PROJECT_OVERRIDE_KEYS) {
|
|
10587
|
+
applyProjectOverride(merged, normalizedProjectConfig, globalConfig, key);
|
|
10588
|
+
}
|
|
10589
|
+
if (projectConfig) {
|
|
10590
|
+
for (const key of Object.keys(projectConfig)) {
|
|
10591
|
+
if (PROJECT_OVERRIDE_KEYS.includes(key) || MERGE_ARRAY_KEYS.includes(key)) {
|
|
10592
|
+
continue;
|
|
10593
|
+
}
|
|
10594
|
+
merged[key] = normalizedProjectConfig[key];
|
|
10595
|
+
}
|
|
10596
|
+
}
|
|
10597
|
+
const globalKbs = globalConfig && Array.isArray(globalConfig.knowledgeBases) ? globalConfig.knowledgeBases : [];
|
|
10598
|
+
const projectKbs = projectConfig ? Array.isArray(normalizedProjectConfig.knowledgeBases) ? normalizedProjectConfig.knowledgeBases : [] : [];
|
|
10599
|
+
const allKbs = [...globalKbs, ...projectKbs];
|
|
10600
|
+
merged.knowledgeBases = mergeKnowledgeBasePaths(allKbs);
|
|
10601
|
+
const globalAdditional = globalConfig && Array.isArray(globalConfig.additionalInclude) ? globalConfig.additionalInclude : [];
|
|
10602
|
+
const projectAdditional = projectConfig && Array.isArray(projectConfig.additionalInclude) ? projectConfig.additionalInclude : [];
|
|
10603
|
+
const allAdditional = [...globalAdditional, ...projectAdditional];
|
|
10604
|
+
merged.additionalInclude = mergeUniqueStringArray(allAdditional);
|
|
10605
|
+
return merged;
|
|
10606
|
+
}
|
|
10607
|
+
|
|
10608
|
+
// src/tools/config-state.ts
|
|
10356
10609
|
function normalizeKnowledgeBasePaths(config, projectRoot3) {
|
|
10357
10610
|
const normalized = { ...config };
|
|
10358
10611
|
if (Array.isArray(normalized.knowledgeBases)) {
|
|
@@ -10382,7 +10635,7 @@ function saveConfig(projectRoot3, config, host = "opencode") {
|
|
|
10382
10635
|
const configDir = path15.dirname(configPath);
|
|
10383
10636
|
const configBaseDir = path15.dirname(configDir);
|
|
10384
10637
|
if (!existsSync9(configDir)) {
|
|
10385
|
-
|
|
10638
|
+
mkdirSync3(configDir, { recursive: true });
|
|
10386
10639
|
}
|
|
10387
10640
|
const serializableConfig = { ...config };
|
|
10388
10641
|
if (Array.isArray(serializableConfig.knowledgeBases)) {
|
|
@@ -10390,7 +10643,7 @@ function saveConfig(projectRoot3, config, host = "opencode") {
|
|
|
10390
10643
|
(kb) => serializeConfigPathValue(kb, configBaseDir)
|
|
10391
10644
|
);
|
|
10392
10645
|
}
|
|
10393
|
-
|
|
10646
|
+
writeFileSync3(configPath, JSON.stringify(serializableConfig, null, 2) + "\n", "utf-8");
|
|
10394
10647
|
}
|
|
10395
10648
|
|
|
10396
10649
|
// src/tools/operations.ts
|
|
@@ -10450,15 +10703,6 @@ function refreshIndexerForDirectory(projectRoot3, host = "opencode", config = pa
|
|
|
10450
10703
|
indexerCache.set(key, indexer);
|
|
10451
10704
|
configCache.set(key, config);
|
|
10452
10705
|
}
|
|
10453
|
-
function shouldForceLocalizeProjectIndex(projectRoot3, host = "opencode") {
|
|
10454
|
-
const root = getProjectRoot(projectRoot3, host);
|
|
10455
|
-
const localIndexPath = path16.join(root, getHostProjectIndexRelativePath(host));
|
|
10456
|
-
if (existsSync10(localIndexPath)) {
|
|
10457
|
-
return false;
|
|
10458
|
-
}
|
|
10459
|
-
const inheritedIndexPath = resolveWorktreeFallbackProjectIndexPath(root, host);
|
|
10460
|
-
return inheritedIndexPath !== null;
|
|
10461
|
-
}
|
|
10462
10706
|
async function searchCodebase(projectRoot3, host, query, options = {}) {
|
|
10463
10707
|
const indexer = getIndexerForProject(projectRoot3, host);
|
|
10464
10708
|
return indexer.search(query, options.limit, {
|
|
@@ -10508,9 +10752,7 @@ async function getCallGraphPath(projectRoot3, host, from, to, maxDepth) {
|
|
|
10508
10752
|
}
|
|
10509
10753
|
async function runIndexCodebase(projectRoot3, host, args, onProgress) {
|
|
10510
10754
|
const root = getProjectRoot(projectRoot3, host);
|
|
10511
|
-
const
|
|
10512
|
-
let indexer = getIndexerForProject(root, host);
|
|
10513
|
-
const runtimeConfig = configCache.get(key);
|
|
10755
|
+
const indexer = getIndexerForProject(root, host);
|
|
10514
10756
|
try {
|
|
10515
10757
|
if (args.estimateOnly) {
|
|
10516
10758
|
return { kind: "estimate", estimate: await indexer.estimateCost() };
|
|
@@ -10531,19 +10773,7 @@ async function runIndexCodebase(projectRoot3, host, args, onProgress) {
|
|
|
10531
10773
|
return Promise.resolve();
|
|
10532
10774
|
});
|
|
10533
10775
|
};
|
|
10534
|
-
|
|
10535
|
-
if (args.force && shouldForceLocalizeProjectIndex(root, host)) {
|
|
10536
|
-
const inheritedIndexPath = resolveProjectIndexPath(root, runtimeConfig.scope, host);
|
|
10537
|
-
stats = await withIndexLock(inheritedIndexPath, "force-index", async () => {
|
|
10538
|
-
materializeLocalProjectConfig(root, loadProjectConfigLayer(root, host), host);
|
|
10539
|
-
refreshIndexerForDirectory(root, host, runtimeConfig);
|
|
10540
|
-
indexer = getIndexerForProject(root, host);
|
|
10541
|
-
return runIndex(indexer);
|
|
10542
|
-
}, { completeRecoveries: false });
|
|
10543
|
-
} else {
|
|
10544
|
-
stats = await runIndex(indexer);
|
|
10545
|
-
}
|
|
10546
|
-
return { kind: "stats", stats };
|
|
10776
|
+
return { kind: "stats", stats: await runIndex(indexer) };
|
|
10547
10777
|
} catch (error) {
|
|
10548
10778
|
const busyResult = getIndexBusyResult(error);
|
|
10549
10779
|
if (!busyResult) throw error;
|