opencode-codebase-index 0.17.1 → 0.18.1
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 +427 -198
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +440 -211
- 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.cjs
CHANGED
|
@@ -678,7 +678,8 @@ var DEFAULT_INCLUDE = [
|
|
|
678
678
|
"**/*.{sh,bash,zsh}",
|
|
679
679
|
"**/*.{txt,html,htm}",
|
|
680
680
|
"**/*.zig",
|
|
681
|
-
"**/*.gd"
|
|
681
|
+
"**/*.gd",
|
|
682
|
+
"**/*.metal"
|
|
682
683
|
];
|
|
683
684
|
var DEFAULT_EXCLUDE = [
|
|
684
685
|
"**/node_modules/**",
|
|
@@ -869,6 +870,9 @@ function isValidProvider(value) {
|
|
|
869
870
|
return typeof value === "string" && Object.keys(EMBEDDING_MODELS).includes(value);
|
|
870
871
|
}
|
|
871
872
|
function isValidModel(value, provider) {
|
|
873
|
+
if (typeof value === "string" && provider === "ollama" && value.trim().length > 0) {
|
|
874
|
+
return true;
|
|
875
|
+
}
|
|
872
876
|
return typeof value === "string" && Object.keys(EMBEDDING_MODELS[provider]).includes(value);
|
|
873
877
|
}
|
|
874
878
|
function isValidScope(value) {
|
|
@@ -1068,6 +1072,9 @@ function loadOpenCodeAuth() {
|
|
|
1068
1072
|
return {};
|
|
1069
1073
|
}
|
|
1070
1074
|
async function detectEmbeddingProvider(preferredProvider, model) {
|
|
1075
|
+
if (preferredProvider === "ollama") {
|
|
1076
|
+
return detectOllamaProvider(model);
|
|
1077
|
+
}
|
|
1071
1078
|
const credentials = await getProviderCredentials(preferredProvider);
|
|
1072
1079
|
if (credentials) {
|
|
1073
1080
|
if (!model) {
|
|
@@ -1083,10 +1090,16 @@ async function detectEmbeddingProvider(preferredProvider, model) {
|
|
|
1083
1090
|
);
|
|
1084
1091
|
}
|
|
1085
1092
|
const providerModels = EMBEDDING_MODELS[preferredProvider];
|
|
1093
|
+
const modelInfo = Object.values(providerModels).find((candidate) => candidate.model === model);
|
|
1094
|
+
if (!modelInfo) {
|
|
1095
|
+
throw new Error(
|
|
1096
|
+
`Model '${model}' is not supported by provider '${preferredProvider}'`
|
|
1097
|
+
);
|
|
1098
|
+
}
|
|
1086
1099
|
return {
|
|
1087
1100
|
provider: preferredProvider,
|
|
1088
1101
|
credentials,
|
|
1089
|
-
modelInfo
|
|
1102
|
+
modelInfo
|
|
1090
1103
|
};
|
|
1091
1104
|
}
|
|
1092
1105
|
throw new Error(
|
|
@@ -1095,6 +1108,13 @@ async function detectEmbeddingProvider(preferredProvider, model) {
|
|
|
1095
1108
|
}
|
|
1096
1109
|
async function tryDetectProvider() {
|
|
1097
1110
|
for (const provider of autoDetectProviders) {
|
|
1111
|
+
if (provider === "ollama") {
|
|
1112
|
+
const ollamaProvider = await tryDetectOllamaProvider();
|
|
1113
|
+
if (ollamaProvider) {
|
|
1114
|
+
return ollamaProvider;
|
|
1115
|
+
}
|
|
1116
|
+
continue;
|
|
1117
|
+
}
|
|
1098
1118
|
const credentials = await getProviderCredentials(provider);
|
|
1099
1119
|
if (credentials) {
|
|
1100
1120
|
return {
|
|
@@ -1162,32 +1182,105 @@ function getGoogleCredentials() {
|
|
|
1162
1182
|
}
|
|
1163
1183
|
return null;
|
|
1164
1184
|
}
|
|
1165
|
-
async function
|
|
1166
|
-
const
|
|
1185
|
+
async function fetchOllama(url, init) {
|
|
1186
|
+
const controller = new AbortController();
|
|
1187
|
+
const timeoutId = setTimeout(() => controller.abort(), 2e3);
|
|
1167
1188
|
try {
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
const response = await fetch(`${baseUrl}/api/tags`, {
|
|
1171
|
-
signal: controller.signal
|
|
1172
|
-
});
|
|
1189
|
+
return await fetch(url, { ...init, signal: controller.signal });
|
|
1190
|
+
} finally {
|
|
1173
1191
|
clearTimeout(timeoutId);
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1194
|
+
async function getOllamaCredentials() {
|
|
1195
|
+
const baseUrl = (process.env.OLLAMA_HOST || "http://localhost:11434").replace(/\/+$/, "");
|
|
1196
|
+
try {
|
|
1197
|
+
const response = await fetchOllama(`${baseUrl}/api/tags`);
|
|
1174
1198
|
if (response.ok) {
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
if (hasEmbeddingModel) {
|
|
1180
|
-
return {
|
|
1181
|
-
provider: "ollama",
|
|
1182
|
-
baseUrl
|
|
1183
|
-
};
|
|
1184
|
-
}
|
|
1199
|
+
return {
|
|
1200
|
+
provider: "ollama",
|
|
1201
|
+
baseUrl
|
|
1202
|
+
};
|
|
1185
1203
|
}
|
|
1186
1204
|
} catch {
|
|
1187
1205
|
return null;
|
|
1188
1206
|
}
|
|
1189
1207
|
return null;
|
|
1190
1208
|
}
|
|
1209
|
+
function findCatalogOllamaModel(model) {
|
|
1210
|
+
const stableName = model.endsWith(":latest") ? model.slice(0, -":latest".length) : model;
|
|
1211
|
+
return Object.values(EMBEDDING_MODELS.ollama).find((candidate) => candidate.model === stableName) ?? null;
|
|
1212
|
+
}
|
|
1213
|
+
function getPositiveIntegerMetadata(modelInfo, suffix) {
|
|
1214
|
+
const values = Object.entries(modelInfo).filter(([key]) => key.endsWith(suffix)).map(([, value]) => value).filter((value) => typeof value === "number" && Number.isInteger(value) && value > 0);
|
|
1215
|
+
return values.length === 1 ? values[0] : null;
|
|
1216
|
+
}
|
|
1217
|
+
async function fetchOllamaModelInfo(credentials, model) {
|
|
1218
|
+
const response = await fetchOllama(`${credentials.baseUrl}/api/show`, {
|
|
1219
|
+
method: "POST",
|
|
1220
|
+
headers: { "Content-Type": "application/json" },
|
|
1221
|
+
body: JSON.stringify({ model })
|
|
1222
|
+
});
|
|
1223
|
+
if (!response.ok) {
|
|
1224
|
+
return null;
|
|
1225
|
+
}
|
|
1226
|
+
const data = await response.json();
|
|
1227
|
+
if (!data.capabilities?.includes("embedding") || !data.model_info) {
|
|
1228
|
+
return null;
|
|
1229
|
+
}
|
|
1230
|
+
const dimensions = getPositiveIntegerMetadata(data.model_info, ".embedding_length");
|
|
1231
|
+
const maxTokens = getPositiveIntegerMetadata(data.model_info, ".context_length");
|
|
1232
|
+
if (!dimensions || !maxTokens) {
|
|
1233
|
+
return null;
|
|
1234
|
+
}
|
|
1235
|
+
return {
|
|
1236
|
+
provider: "ollama",
|
|
1237
|
+
model,
|
|
1238
|
+
dimensions,
|
|
1239
|
+
maxTokens,
|
|
1240
|
+
costPer1MTokens: 0
|
|
1241
|
+
};
|
|
1242
|
+
}
|
|
1243
|
+
async function listOllamaModels(credentials) {
|
|
1244
|
+
const response = await fetchOllama(`${credentials.baseUrl}/api/tags`);
|
|
1245
|
+
if (!response.ok) {
|
|
1246
|
+
return [];
|
|
1247
|
+
}
|
|
1248
|
+
const data = await response.json();
|
|
1249
|
+
return [...new Set((data.models ?? []).map((entry) => entry.name ?? entry.model).filter((name) => typeof name === "string" && name.trim().length > 0))];
|
|
1250
|
+
}
|
|
1251
|
+
async function detectOllamaProvider(model) {
|
|
1252
|
+
const credentials = await getOllamaCredentials();
|
|
1253
|
+
if (!credentials) {
|
|
1254
|
+
throw new Error("Preferred provider 'ollama' is not configured or authenticated");
|
|
1255
|
+
}
|
|
1256
|
+
const requestedModel = model?.trim();
|
|
1257
|
+
if (requestedModel) {
|
|
1258
|
+
const catalogModel = findCatalogOllamaModel(requestedModel);
|
|
1259
|
+
if (catalogModel) {
|
|
1260
|
+
return { provider: "ollama", credentials, modelInfo: catalogModel };
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
const candidates = requestedModel ? [requestedModel] : await listOllamaModels(credentials);
|
|
1264
|
+
for (const candidate of candidates) {
|
|
1265
|
+
const modelInfo = await fetchOllamaModelInfo(credentials, candidate);
|
|
1266
|
+
if (modelInfo) {
|
|
1267
|
+
return {
|
|
1268
|
+
provider: "ollama",
|
|
1269
|
+
credentials,
|
|
1270
|
+
modelInfo: findCatalogOllamaModel(candidate) ?? modelInfo
|
|
1271
|
+
};
|
|
1272
|
+
}
|
|
1273
|
+
}
|
|
1274
|
+
const detail = model ? `Model '${model}' is not installed or is not embedding-capable` : "No installed embedding-capable Ollama model was found";
|
|
1275
|
+
throw new Error(detail);
|
|
1276
|
+
}
|
|
1277
|
+
async function tryDetectOllamaProvider() {
|
|
1278
|
+
try {
|
|
1279
|
+
return await detectOllamaProvider();
|
|
1280
|
+
} catch {
|
|
1281
|
+
return null;
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1191
1284
|
function getProviderDisplayName(provider) {
|
|
1192
1285
|
switch (provider) {
|
|
1193
1286
|
case "github-copilot":
|
|
@@ -1340,10 +1433,6 @@ function formatPrImpact(result) {
|
|
|
1340
1433
|
var import_fs10 = require("fs");
|
|
1341
1434
|
var path16 = __toESM(require("path"), 1);
|
|
1342
1435
|
|
|
1343
|
-
// src/config/merger.ts
|
|
1344
|
-
var import_fs5 = require("fs");
|
|
1345
|
-
var path7 = __toESM(require("path"), 1);
|
|
1346
|
-
|
|
1347
1436
|
// src/config/paths.ts
|
|
1348
1437
|
var import_fs4 = require("fs");
|
|
1349
1438
|
var os2 = __toESM(require("os"), 1);
|
|
@@ -1516,16 +1605,6 @@ function resolveWorktreeFallbackPath(projectRoot3, relativePath) {
|
|
|
1516
1605
|
const fallbackPath = path4.join(mainRepoRoot, relativePath);
|
|
1517
1606
|
return (0, import_fs4.existsSync)(fallbackPath) ? fallbackPath : null;
|
|
1518
1607
|
}
|
|
1519
|
-
function resolveWorktreeFallbackProjectIndexPath(projectRoot3, host) {
|
|
1520
|
-
const inheritedHostPath = resolveWorktreeFallbackPath(projectRoot3, getProjectIndexRelativePath(host));
|
|
1521
|
-
if (inheritedHostPath) {
|
|
1522
|
-
return inheritedHostPath;
|
|
1523
|
-
}
|
|
1524
|
-
if (host !== "opencode") {
|
|
1525
|
-
return resolveWorktreeFallbackPath(projectRoot3, OPENCODE_PROJECT_INDEX_RELATIVE_PATH);
|
|
1526
|
-
}
|
|
1527
|
-
return null;
|
|
1528
|
-
}
|
|
1529
1608
|
function getHostProjectConfigRelativePath(host) {
|
|
1530
1609
|
return getProjectConfigRelativePath(host);
|
|
1531
1610
|
}
|
|
@@ -1630,6 +1709,9 @@ function resolveProjectIndexPath(projectRoot3, scope, host = "opencode") {
|
|
|
1630
1709
|
if (hasHostProjectConfig(projectRoot3, host)) {
|
|
1631
1710
|
return localIndexPath;
|
|
1632
1711
|
}
|
|
1712
|
+
if (resolveWorktreeMainRepoRoot(projectRoot3)) {
|
|
1713
|
+
return localIndexPath;
|
|
1714
|
+
}
|
|
1633
1715
|
const hostFallback = resolveWorktreeFallbackPath(projectRoot3, getProjectIndexRelativePath(host));
|
|
1634
1716
|
if (hostFallback) {
|
|
1635
1717
|
return hostFallback;
|
|
@@ -1643,210 +1725,9 @@ function resolveProjectIndexPath(projectRoot3, scope, host = "opencode") {
|
|
|
1643
1725
|
return localIndexPath;
|
|
1644
1726
|
}
|
|
1645
1727
|
|
|
1646
|
-
// src/config/rebase.ts
|
|
1647
|
-
var path6 = __toESM(require("path"), 1);
|
|
1648
|
-
|
|
1649
|
-
// src/utils/paths.ts
|
|
1650
|
-
var path5 = __toESM(require("path"), 1);
|
|
1651
|
-
function normalizePathSeparators(value) {
|
|
1652
|
-
return value.replace(/\\/g, "/");
|
|
1653
|
-
}
|
|
1654
|
-
function isHiddenPathSegment(part) {
|
|
1655
|
-
return part.startsWith(".") && part !== "." && part !== "..";
|
|
1656
|
-
}
|
|
1657
|
-
function isBuildPathSegment(part) {
|
|
1658
|
-
return part.toLowerCase().includes("build");
|
|
1659
|
-
}
|
|
1660
|
-
|
|
1661
|
-
// src/config/rebase.ts
|
|
1662
|
-
function isWithinRoot(rootDir, targetPath) {
|
|
1663
|
-
const relativePath = path6.relative(rootDir, targetPath);
|
|
1664
|
-
return relativePath === "" || !relativePath.startsWith("..") && !path6.isAbsolute(relativePath);
|
|
1665
|
-
}
|
|
1666
|
-
function resolveInheritedKnowledgeBaseEntries(values, sourceRoot, targetRoot) {
|
|
1667
|
-
if (!Array.isArray(values)) {
|
|
1668
|
-
return [];
|
|
1669
|
-
}
|
|
1670
|
-
return values.filter((value) => typeof value === "string").map((value) => {
|
|
1671
|
-
const trimmed = value.trim();
|
|
1672
|
-
if (!trimmed) {
|
|
1673
|
-
return trimmed;
|
|
1674
|
-
}
|
|
1675
|
-
if (path6.isAbsolute(trimmed)) {
|
|
1676
|
-
if (isWithinRoot(sourceRoot, trimmed)) {
|
|
1677
|
-
return normalizePathSeparators(path6.normalize(path6.relative(sourceRoot, trimmed) || "."));
|
|
1678
|
-
}
|
|
1679
|
-
return path6.normalize(trimmed);
|
|
1680
|
-
}
|
|
1681
|
-
const resolvedFromSource = path6.resolve(sourceRoot, trimmed);
|
|
1682
|
-
if (isWithinRoot(sourceRoot, resolvedFromSource)) {
|
|
1683
|
-
return normalizePathSeparators(path6.normalize(trimmed));
|
|
1684
|
-
}
|
|
1685
|
-
return normalizePathSeparators(path6.normalize(path6.relative(targetRoot, resolvedFromSource)));
|
|
1686
|
-
}).filter(Boolean);
|
|
1687
|
-
}
|
|
1688
|
-
|
|
1689
|
-
// src/config/merger.ts
|
|
1690
|
-
var PROJECT_OVERRIDE_KEYS = [
|
|
1691
|
-
"embeddingProvider",
|
|
1692
|
-
"customProvider",
|
|
1693
|
-
"embeddingModel",
|
|
1694
|
-
"reranker",
|
|
1695
|
-
"include",
|
|
1696
|
-
"exclude",
|
|
1697
|
-
"indexing",
|
|
1698
|
-
"search",
|
|
1699
|
-
"debug",
|
|
1700
|
-
"scope"
|
|
1701
|
-
];
|
|
1702
|
-
var MERGE_ARRAY_KEYS = ["knowledgeBases", "additionalInclude"];
|
|
1703
|
-
function isRecord(value) {
|
|
1704
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1705
|
-
}
|
|
1706
|
-
function isStringArray2(value) {
|
|
1707
|
-
return Array.isArray(value) && value.every((item) => typeof item === "string");
|
|
1708
|
-
}
|
|
1709
|
-
function applyProjectOverride(merged, normalizedProjectConfig, globalConfig, key) {
|
|
1710
|
-
if (key in normalizedProjectConfig) {
|
|
1711
|
-
merged[key] = normalizedProjectConfig[key];
|
|
1712
|
-
return;
|
|
1713
|
-
}
|
|
1714
|
-
if (key in globalConfig) {
|
|
1715
|
-
merged[key] = globalConfig[key];
|
|
1716
|
-
}
|
|
1717
|
-
}
|
|
1718
|
-
function mergeUniqueStringArray(values) {
|
|
1719
|
-
return [...new Set(values.map((value) => String(value).trim()))];
|
|
1720
|
-
}
|
|
1721
|
-
function normalizeKnowledgeBasePath(value) {
|
|
1722
|
-
let normalized = path7.normalize(String(value).trim());
|
|
1723
|
-
const root = path7.parse(normalized).root;
|
|
1724
|
-
while (normalized.length > root.length && /[\\/]$/.test(normalized)) {
|
|
1725
|
-
normalized = normalized.slice(0, -1);
|
|
1726
|
-
}
|
|
1727
|
-
return normalized;
|
|
1728
|
-
}
|
|
1729
|
-
function mergeKnowledgeBasePaths(values) {
|
|
1730
|
-
return [...new Set(values.map((value) => normalizeKnowledgeBasePath(value)).filter((value) => value.length > 0))];
|
|
1731
|
-
}
|
|
1732
|
-
function validateConfigLayerShape(rawConfig, filePath) {
|
|
1733
|
-
if (!isRecord(rawConfig)) {
|
|
1734
|
-
throw new Error(`Config file ${filePath} must contain a JSON object at the root.`);
|
|
1735
|
-
}
|
|
1736
|
-
if (rawConfig.knowledgeBases !== void 0 && !isStringArray2(rawConfig.knowledgeBases)) {
|
|
1737
|
-
throw new Error(`Config file ${filePath} field 'knowledgeBases' must be an array of strings.`);
|
|
1738
|
-
}
|
|
1739
|
-
if (rawConfig.additionalInclude !== void 0 && !isStringArray2(rawConfig.additionalInclude)) {
|
|
1740
|
-
throw new Error(`Config file ${filePath} field 'additionalInclude' must be an array of strings.`);
|
|
1741
|
-
}
|
|
1742
|
-
if (rawConfig.include !== void 0 && !isStringArray2(rawConfig.include)) {
|
|
1743
|
-
throw new Error(`Config file ${filePath} field 'include' must be an array of strings.`);
|
|
1744
|
-
}
|
|
1745
|
-
if (rawConfig.exclude !== void 0 && !isStringArray2(rawConfig.exclude)) {
|
|
1746
|
-
throw new Error(`Config file ${filePath} field 'exclude' must be an array of strings.`);
|
|
1747
|
-
}
|
|
1748
|
-
for (const section of ["customProvider", "indexing", "search", "debug", "reranker"]) {
|
|
1749
|
-
const value = rawConfig[section];
|
|
1750
|
-
if (value !== void 0 && !isRecord(value)) {
|
|
1751
|
-
throw new Error(`Config file ${filePath} field '${section}' must be an object.`);
|
|
1752
|
-
}
|
|
1753
|
-
}
|
|
1754
|
-
return rawConfig;
|
|
1755
|
-
}
|
|
1756
|
-
function loadJsonFile(filePath) {
|
|
1757
|
-
if (!(0, import_fs5.existsSync)(filePath)) {
|
|
1758
|
-
return null;
|
|
1759
|
-
}
|
|
1760
|
-
try {
|
|
1761
|
-
const content = (0, import_fs5.readFileSync)(filePath, "utf-8");
|
|
1762
|
-
return validateConfigLayerShape(JSON.parse(content), filePath);
|
|
1763
|
-
} catch (error) {
|
|
1764
|
-
if (error instanceof Error && error.message.startsWith("Config file ")) {
|
|
1765
|
-
throw error;
|
|
1766
|
-
}
|
|
1767
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
1768
|
-
throw new Error(`Failed to load config file ${filePath}: ${message}`);
|
|
1769
|
-
}
|
|
1770
|
-
}
|
|
1771
|
-
function materializeLocalProjectConfig(projectRoot3, config, host = "opencode") {
|
|
1772
|
-
const localConfigPath = resolveWritableProjectConfigPath(projectRoot3, host);
|
|
1773
|
-
(0, import_fs5.mkdirSync)(path7.dirname(localConfigPath), { recursive: true });
|
|
1774
|
-
(0, import_fs5.writeFileSync)(localConfigPath, JSON.stringify(config, null, 2), "utf-8");
|
|
1775
|
-
return localConfigPath;
|
|
1776
|
-
}
|
|
1777
|
-
function loadProjectConfigLayer(projectRoot3, host = "opencode") {
|
|
1778
|
-
const projectConfigPath = resolveProjectConfigPath(projectRoot3, host);
|
|
1779
|
-
const projectConfig = loadJsonFile(projectConfigPath);
|
|
1780
|
-
if (!projectConfig) {
|
|
1781
|
-
return {};
|
|
1782
|
-
}
|
|
1783
|
-
const normalizedConfig = { ...projectConfig };
|
|
1784
|
-
const projectConfigBaseDir = path7.dirname(path7.dirname(projectConfigPath));
|
|
1785
|
-
if (Array.isArray(normalizedConfig.knowledgeBases)) {
|
|
1786
|
-
normalizedConfig.knowledgeBases = resolveInheritedKnowledgeBaseEntries(
|
|
1787
|
-
normalizedConfig.knowledgeBases,
|
|
1788
|
-
projectConfigBaseDir,
|
|
1789
|
-
projectRoot3
|
|
1790
|
-
);
|
|
1791
|
-
}
|
|
1792
|
-
return normalizedConfig;
|
|
1793
|
-
}
|
|
1794
|
-
function loadMergedConfig(projectRoot3, host = "opencode") {
|
|
1795
|
-
const globalConfigPath = resolveGlobalConfigPath(host);
|
|
1796
|
-
const projectConfigPath = resolveProjectConfigPath(projectRoot3, host);
|
|
1797
|
-
let globalConfig = null;
|
|
1798
|
-
let globalConfigError = null;
|
|
1799
|
-
try {
|
|
1800
|
-
globalConfig = loadJsonFile(globalConfigPath);
|
|
1801
|
-
} catch (error) {
|
|
1802
|
-
globalConfigError = error instanceof Error ? error : new Error(String(error));
|
|
1803
|
-
}
|
|
1804
|
-
const projectConfig = loadJsonFile(projectConfigPath);
|
|
1805
|
-
const normalizedProjectConfig = loadProjectConfigLayer(projectRoot3, host);
|
|
1806
|
-
if (globalConfigError) {
|
|
1807
|
-
if (!projectConfig) {
|
|
1808
|
-
throw globalConfigError;
|
|
1809
|
-
}
|
|
1810
|
-
globalConfig = null;
|
|
1811
|
-
}
|
|
1812
|
-
if (!globalConfig && !projectConfig) {
|
|
1813
|
-
return {};
|
|
1814
|
-
}
|
|
1815
|
-
if (!projectConfig && globalConfig) {
|
|
1816
|
-
return globalConfig;
|
|
1817
|
-
}
|
|
1818
|
-
if (!globalConfig && projectConfig) {
|
|
1819
|
-
return normalizedProjectConfig;
|
|
1820
|
-
}
|
|
1821
|
-
if (!globalConfig || !projectConfig) {
|
|
1822
|
-
return globalConfig ?? normalizedProjectConfig;
|
|
1823
|
-
}
|
|
1824
|
-
const merged = { ...globalConfig };
|
|
1825
|
-
for (const key of PROJECT_OVERRIDE_KEYS) {
|
|
1826
|
-
applyProjectOverride(merged, normalizedProjectConfig, globalConfig, key);
|
|
1827
|
-
}
|
|
1828
|
-
if (projectConfig) {
|
|
1829
|
-
for (const key of Object.keys(projectConfig)) {
|
|
1830
|
-
if (PROJECT_OVERRIDE_KEYS.includes(key) || MERGE_ARRAY_KEYS.includes(key)) {
|
|
1831
|
-
continue;
|
|
1832
|
-
}
|
|
1833
|
-
merged[key] = normalizedProjectConfig[key];
|
|
1834
|
-
}
|
|
1835
|
-
}
|
|
1836
|
-
const globalKbs = globalConfig && Array.isArray(globalConfig.knowledgeBases) ? globalConfig.knowledgeBases : [];
|
|
1837
|
-
const projectKbs = projectConfig ? Array.isArray(normalizedProjectConfig.knowledgeBases) ? normalizedProjectConfig.knowledgeBases : [] : [];
|
|
1838
|
-
const allKbs = [...globalKbs, ...projectKbs];
|
|
1839
|
-
merged.knowledgeBases = mergeKnowledgeBasePaths(allKbs);
|
|
1840
|
-
const globalAdditional = globalConfig && Array.isArray(globalConfig.additionalInclude) ? globalConfig.additionalInclude : [];
|
|
1841
|
-
const projectAdditional = projectConfig && Array.isArray(projectConfig.additionalInclude) ? projectConfig.additionalInclude : [];
|
|
1842
|
-
const allAdditional = [...globalAdditional, ...projectAdditional];
|
|
1843
|
-
merged.additionalInclude = mergeUniqueStringArray(allAdditional);
|
|
1844
|
-
return merged;
|
|
1845
|
-
}
|
|
1846
|
-
|
|
1847
1728
|
// src/indexer/index.ts
|
|
1848
|
-
var
|
|
1849
|
-
var
|
|
1729
|
+
var import_fs7 = require("fs");
|
|
1730
|
+
var path11 = __toESM(require("path"), 1);
|
|
1850
1731
|
var import_perf_hooks = require("perf_hooks");
|
|
1851
1732
|
var import_child_process3 = require("child_process");
|
|
1852
1733
|
var import_util3 = require("util");
|
|
@@ -3197,6 +3078,7 @@ var GoogleEmbeddingProvider = class _GoogleEmbeddingProvider extends BaseEmbeddi
|
|
|
3197
3078
|
// src/embeddings/providers/ollama.ts
|
|
3198
3079
|
var OllamaEmbeddingProvider = class _OllamaEmbeddingProvider extends BaseEmbeddingProvider {
|
|
3199
3080
|
static MIN_TRUNCATION_CHARS = 512;
|
|
3081
|
+
static REQUEST_TIMEOUT_MS = 12e4;
|
|
3200
3082
|
constructor(credentials, modelInfo) {
|
|
3201
3083
|
super(credentials, modelInfo);
|
|
3202
3084
|
}
|
|
@@ -3271,22 +3153,45 @@ var OllamaEmbeddingProvider = class _OllamaEmbeddingProvider extends BaseEmbeddi
|
|
|
3271
3153
|
}
|
|
3272
3154
|
}
|
|
3273
3155
|
async embedSingle(text3) {
|
|
3274
|
-
const
|
|
3275
|
-
|
|
3276
|
-
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
|
|
3284
|
-
|
|
3156
|
+
const controller = new AbortController();
|
|
3157
|
+
const timeout = setTimeout(
|
|
3158
|
+
() => controller.abort(),
|
|
3159
|
+
_OllamaEmbeddingProvider.REQUEST_TIMEOUT_MS
|
|
3160
|
+
);
|
|
3161
|
+
let response;
|
|
3162
|
+
try {
|
|
3163
|
+
response = await fetch(`${this.credentials.baseUrl}/api/embeddings`, {
|
|
3164
|
+
method: "POST",
|
|
3165
|
+
headers: {
|
|
3166
|
+
"Content-Type": "application/json"
|
|
3167
|
+
},
|
|
3168
|
+
body: JSON.stringify({
|
|
3169
|
+
model: this.modelInfo.model,
|
|
3170
|
+
prompt: text3,
|
|
3171
|
+
truncate: false
|
|
3172
|
+
}),
|
|
3173
|
+
signal: controller.signal
|
|
3174
|
+
});
|
|
3175
|
+
} catch (error) {
|
|
3176
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
3177
|
+
throw new Error(
|
|
3178
|
+
`Ollama embedding request timed out after ${_OllamaEmbeddingProvider.REQUEST_TIMEOUT_MS}ms`
|
|
3179
|
+
);
|
|
3180
|
+
}
|
|
3181
|
+
throw error;
|
|
3182
|
+
} finally {
|
|
3183
|
+
clearTimeout(timeout);
|
|
3184
|
+
}
|
|
3285
3185
|
if (!response.ok) {
|
|
3286
3186
|
const error = (await response.text()).slice(0, 500);
|
|
3287
3187
|
throw new Error(`Ollama embedding API error: ${response.status} - ${error}`);
|
|
3288
3188
|
}
|
|
3289
3189
|
const data = await response.json();
|
|
3190
|
+
if (!Array.isArray(data.embedding) || data.embedding.length !== this.modelInfo.dimensions || data.embedding.some((value) => typeof value !== "number" || !Number.isFinite(value))) {
|
|
3191
|
+
throw new Error(
|
|
3192
|
+
`Ollama returned an invalid embedding; expected ${this.modelInfo.dimensions} finite dimensions`
|
|
3193
|
+
);
|
|
3194
|
+
}
|
|
3290
3195
|
return {
|
|
3291
3196
|
embedding: data.embedding,
|
|
3292
3197
|
tokensUsed: this.estimateTokens(text3)
|
|
@@ -3433,9 +3338,23 @@ var SiliconFlowReranker = class {
|
|
|
3433
3338
|
};
|
|
3434
3339
|
|
|
3435
3340
|
// src/utils/files.ts
|
|
3436
|
-
var import_ignore = __toESM(require_ignore(), 1);
|
|
3437
|
-
var
|
|
3438
|
-
var
|
|
3341
|
+
var import_ignore = __toESM(require_ignore(), 1);
|
|
3342
|
+
var import_fs5 = require("fs");
|
|
3343
|
+
var path6 = __toESM(require("path"), 1);
|
|
3344
|
+
|
|
3345
|
+
// src/utils/paths.ts
|
|
3346
|
+
var path5 = __toESM(require("path"), 1);
|
|
3347
|
+
function normalizePathSeparators(value) {
|
|
3348
|
+
return value.replace(/\\/g, "/");
|
|
3349
|
+
}
|
|
3350
|
+
function isHiddenPathSegment(part) {
|
|
3351
|
+
return part.startsWith(".") && part !== "." && part !== "..";
|
|
3352
|
+
}
|
|
3353
|
+
function isBuildPathSegment(part) {
|
|
3354
|
+
return part.toLowerCase().includes("build");
|
|
3355
|
+
}
|
|
3356
|
+
|
|
3357
|
+
// src/utils/files.ts
|
|
3439
3358
|
function createIgnoreFilter(projectRoot3) {
|
|
3440
3359
|
const ig = (0, import_ignore.default)();
|
|
3441
3360
|
const defaultIgnores = [
|
|
@@ -3457,9 +3376,9 @@ function createIgnoreFilter(projectRoot3) {
|
|
|
3457
3376
|
"**/*build*/**"
|
|
3458
3377
|
];
|
|
3459
3378
|
ig.add(defaultIgnores);
|
|
3460
|
-
const gitignorePath =
|
|
3461
|
-
if ((0,
|
|
3462
|
-
const gitignoreContent = (0,
|
|
3379
|
+
const gitignorePath = path6.join(projectRoot3, ".gitignore");
|
|
3380
|
+
if ((0, import_fs5.existsSync)(gitignorePath)) {
|
|
3381
|
+
const gitignoreContent = (0, import_fs5.readFileSync)(gitignorePath, "utf-8");
|
|
3463
3382
|
ig.add(gitignoreContent);
|
|
3464
3383
|
}
|
|
3465
3384
|
return ig;
|
|
@@ -3480,12 +3399,12 @@ function matchGlob(filePath, pattern) {
|
|
|
3480
3399
|
return regex.test(filePath);
|
|
3481
3400
|
}
|
|
3482
3401
|
async function* walkDirectory(dir, projectRoot3, includePatterns, excludePatterns, ignoreFilter, maxFileSize, skipped, options, currentDepth = 0) {
|
|
3483
|
-
const entries = await
|
|
3402
|
+
const entries = await import_fs5.promises.readdir(dir, { withFileTypes: true });
|
|
3484
3403
|
const filesInDir = [];
|
|
3485
3404
|
const subdirs = [];
|
|
3486
3405
|
for (const entry of entries) {
|
|
3487
|
-
const fullPath =
|
|
3488
|
-
const relativePath =
|
|
3406
|
+
const fullPath = path6.join(dir, entry.name);
|
|
3407
|
+
const relativePath = path6.relative(projectRoot3, fullPath);
|
|
3489
3408
|
if (isHiddenPathSegment(entry.name)) {
|
|
3490
3409
|
if (entry.isDirectory()) {
|
|
3491
3410
|
skipped.push({ path: relativePath, reason: "excluded" });
|
|
@@ -3505,7 +3424,7 @@ async function* walkDirectory(dir, projectRoot3, includePatterns, excludePattern
|
|
|
3505
3424
|
if (entry.isDirectory()) {
|
|
3506
3425
|
subdirs.push({ fullPath, relativePath });
|
|
3507
3426
|
} else if (entry.isFile()) {
|
|
3508
|
-
const stat = await
|
|
3427
|
+
const stat = await import_fs5.promises.stat(fullPath);
|
|
3509
3428
|
if (stat.size > maxFileSize) {
|
|
3510
3429
|
skipped.push({ path: relativePath, reason: "too_large" });
|
|
3511
3430
|
continue;
|
|
@@ -3534,7 +3453,7 @@ async function* walkDirectory(dir, projectRoot3, includePatterns, excludePattern
|
|
|
3534
3453
|
yield f;
|
|
3535
3454
|
}
|
|
3536
3455
|
for (let i = options.maxFilesPerDirectory; i < filesInDir.length; i++) {
|
|
3537
|
-
skipped.push({ path:
|
|
3456
|
+
skipped.push({ path: path6.relative(projectRoot3, filesInDir[i].path), reason: "excluded" });
|
|
3538
3457
|
}
|
|
3539
3458
|
const canRecurse = options.maxDepth === -1 || currentDepth < options.maxDepth;
|
|
3540
3459
|
if (canRecurse) {
|
|
@@ -3574,14 +3493,14 @@ async function collectFiles(projectRoot3, includePatterns, excludePatterns, maxF
|
|
|
3574
3493
|
if (additionalRoots && additionalRoots.length > 0) {
|
|
3575
3494
|
const normalizedRoots = /* @__PURE__ */ new Set();
|
|
3576
3495
|
for (const kbRoot of additionalRoots) {
|
|
3577
|
-
const resolved =
|
|
3578
|
-
|
|
3496
|
+
const resolved = path6.normalize(
|
|
3497
|
+
path6.isAbsolute(kbRoot) ? kbRoot : path6.resolve(projectRoot3, kbRoot)
|
|
3579
3498
|
);
|
|
3580
3499
|
normalizedRoots.add(resolved);
|
|
3581
3500
|
}
|
|
3582
3501
|
for (const resolvedKbRoot of normalizedRoots) {
|
|
3583
3502
|
try {
|
|
3584
|
-
const stat = await
|
|
3503
|
+
const stat = await import_fs5.promises.stat(resolvedKbRoot);
|
|
3585
3504
|
if (!stat.isDirectory()) {
|
|
3586
3505
|
skipped.push({ path: resolvedKbRoot, reason: "excluded" });
|
|
3587
3506
|
continue;
|
|
@@ -3922,7 +3841,7 @@ function initializeLogger(config) {
|
|
|
3922
3841
|
}
|
|
3923
3842
|
|
|
3924
3843
|
// src/native/index.ts
|
|
3925
|
-
var
|
|
3844
|
+
var path7 = __toESM(require("path"), 1);
|
|
3926
3845
|
var os3 = __toESM(require("os"), 1);
|
|
3927
3846
|
var module2 = __toESM(require("module"), 1);
|
|
3928
3847
|
var import_url = require("url");
|
|
@@ -3947,19 +3866,19 @@ function getNativeBinding() {
|
|
|
3947
3866
|
let currentDir;
|
|
3948
3867
|
let requireTarget;
|
|
3949
3868
|
if (typeof import_meta !== "undefined" && import_meta.url) {
|
|
3950
|
-
currentDir =
|
|
3869
|
+
currentDir = path7.dirname((0, import_url.fileURLToPath)(import_meta.url));
|
|
3951
3870
|
requireTarget = import_meta.url;
|
|
3952
3871
|
} else if (typeof __dirname !== "undefined") {
|
|
3953
3872
|
currentDir = __dirname;
|
|
3954
3873
|
requireTarget = __filename;
|
|
3955
3874
|
} else {
|
|
3956
3875
|
currentDir = process.cwd();
|
|
3957
|
-
requireTarget =
|
|
3876
|
+
requireTarget = path7.join(currentDir, "index.js");
|
|
3958
3877
|
}
|
|
3959
3878
|
const normalizedDir = currentDir.replace(/\\/g, "/");
|
|
3960
|
-
const isDevMode = normalizedDir.includes("/src/native") || currentDir.includes(
|
|
3961
|
-
const packageRoot = isDevMode ?
|
|
3962
|
-
const nativePath =
|
|
3879
|
+
const isDevMode = normalizedDir.includes("/src/native") || currentDir.includes(path7.join("src", "native"));
|
|
3880
|
+
const packageRoot = isDevMode ? path7.resolve(currentDir, "../..") : path7.resolve(currentDir, "..");
|
|
3881
|
+
const nativePath = path7.join(packageRoot, "native", bindingName);
|
|
3963
3882
|
const require2 = module2.createRequire(requireTarget);
|
|
3964
3883
|
return require2(nativePath);
|
|
3965
3884
|
}
|
|
@@ -4045,7 +3964,9 @@ function mapChunk(c) {
|
|
|
4045
3964
|
return {
|
|
4046
3965
|
content: c.content,
|
|
4047
3966
|
startLine: c.startLine ?? c.start_line,
|
|
3967
|
+
startCol: c.startCol ?? c.start_col,
|
|
4048
3968
|
endLine: c.endLine ?? c.end_line,
|
|
3969
|
+
endCol: c.endCol ?? c.end_col,
|
|
4049
3970
|
chunkType: c.chunkType ?? c.chunk_type,
|
|
4050
3971
|
name: c.name ?? void 0,
|
|
4051
3972
|
language: c.language
|
|
@@ -4166,6 +4087,7 @@ function getEmbeddingHeaderParts(chunk, filePath) {
|
|
|
4166
4087
|
javascript: "JavaScript",
|
|
4167
4088
|
python: "Python",
|
|
4168
4089
|
rust: "Rust",
|
|
4090
|
+
swift: "Swift",
|
|
4169
4091
|
go: "Go",
|
|
4170
4092
|
java: "Java"
|
|
4171
4093
|
};
|
|
@@ -4174,7 +4096,16 @@ function getEmbeddingHeaderParts(chunk, filePath) {
|
|
|
4174
4096
|
function: "function",
|
|
4175
4097
|
arrow_function: "arrow function",
|
|
4176
4098
|
method_definition: "method",
|
|
4099
|
+
method_declaration: "method",
|
|
4100
|
+
protocol_function_declaration: "protocol requirement",
|
|
4101
|
+
init_declaration: "initializer",
|
|
4102
|
+
deinit_declaration: "deinitializer",
|
|
4103
|
+
subscript_declaration: "subscript",
|
|
4177
4104
|
class_declaration: "class",
|
|
4105
|
+
actor_declaration: "actor",
|
|
4106
|
+
extension_declaration: "extension",
|
|
4107
|
+
protocol_declaration: "protocol",
|
|
4108
|
+
struct_declaration: "struct",
|
|
4178
4109
|
interface_declaration: "interface",
|
|
4179
4110
|
type_alias_declaration: "type alias",
|
|
4180
4111
|
enum_declaration: "enum",
|
|
@@ -4692,7 +4623,7 @@ var Database = class _Database {
|
|
|
4692
4623
|
};
|
|
4693
4624
|
|
|
4694
4625
|
// src/tools/changed-files.ts
|
|
4695
|
-
var
|
|
4626
|
+
var path8 = __toESM(require("path"), 1);
|
|
4696
4627
|
var import_child_process = require("child_process");
|
|
4697
4628
|
var import_util = require("util");
|
|
4698
4629
|
var execFileAsync = (0, import_util.promisify)(import_child_process.execFile);
|
|
@@ -4780,8 +4711,8 @@ function normalizeFiles(rawFiles, projectRoot3) {
|
|
|
4780
4711
|
for (const raw of rawFiles) {
|
|
4781
4712
|
const trimmed = raw.trim();
|
|
4782
4713
|
if (!trimmed) continue;
|
|
4783
|
-
const absolute =
|
|
4784
|
-
const relative7 =
|
|
4714
|
+
const absolute = path8.resolve(projectRoot3, trimmed);
|
|
4715
|
+
const relative7 = path8.relative(projectRoot3, absolute);
|
|
4785
4716
|
const cleaned = relative7.startsWith("./") ? relative7.slice(2) : relative7;
|
|
4786
4717
|
if (!seen.has(cleaned)) {
|
|
4787
4718
|
seen.add(cleaned);
|
|
@@ -4793,7 +4724,7 @@ function normalizeFiles(rawFiles, projectRoot3) {
|
|
|
4793
4724
|
|
|
4794
4725
|
// src/indexer/git-blame.ts
|
|
4795
4726
|
var import_child_process2 = require("child_process");
|
|
4796
|
-
var
|
|
4727
|
+
var path9 = __toESM(require("path"), 1);
|
|
4797
4728
|
var import_util2 = require("util");
|
|
4798
4729
|
var execFileAsync2 = (0, import_util2.promisify)(import_child_process2.execFile);
|
|
4799
4730
|
function parseGitBlamePorcelain(output) {
|
|
@@ -4831,7 +4762,7 @@ function parseGitBlamePorcelain(output) {
|
|
|
4831
4762
|
return Array.from(commits.values()).filter((commit) => commit.lines > 0).sort((a, b) => b.lines - a.lines || b.committedAt - a.committedAt)[0];
|
|
4832
4763
|
}
|
|
4833
4764
|
async function getChunkGitBlame(projectRoot3, filePath, startLine, endLine) {
|
|
4834
|
-
const relativePath =
|
|
4765
|
+
const relativePath = path9.relative(projectRoot3, filePath);
|
|
4835
4766
|
try {
|
|
4836
4767
|
const { stdout } = await execFileAsync2(
|
|
4837
4768
|
"git",
|
|
@@ -4846,9 +4777,9 @@ async function getChunkGitBlame(projectRoot3, filePath, startLine, endLine) {
|
|
|
4846
4777
|
|
|
4847
4778
|
// src/indexer/index-lock.ts
|
|
4848
4779
|
var import_crypto = require("crypto");
|
|
4849
|
-
var
|
|
4780
|
+
var import_fs6 = require("fs");
|
|
4850
4781
|
var os4 = __toESM(require("os"), 1);
|
|
4851
|
-
var
|
|
4782
|
+
var path10 = __toESM(require("path"), 1);
|
|
4852
4783
|
var OWNER_FILE_NAME = "owner.json";
|
|
4853
4784
|
var RECLAIM_DIRECTORY_NAME = "reclaiming";
|
|
4854
4785
|
var RECOVERY_MARKER_PREFIX = "indexing.lock.recovery.";
|
|
@@ -4905,7 +4836,7 @@ function parseReclaimOwner(value) {
|
|
|
4905
4836
|
}
|
|
4906
4837
|
function readJsonDirectory(directoryPath, parser) {
|
|
4907
4838
|
try {
|
|
4908
|
-
return parser(JSON.parse((0,
|
|
4839
|
+
return parser(JSON.parse((0, import_fs6.readFileSync)(path10.join(directoryPath, OWNER_FILE_NAME), "utf-8")));
|
|
4909
4840
|
} catch {
|
|
4910
4841
|
return null;
|
|
4911
4842
|
}
|
|
@@ -4921,7 +4852,7 @@ function readRecoveryOwner(markerPath) {
|
|
|
4921
4852
|
}
|
|
4922
4853
|
function readLegacyOwner(lockPath) {
|
|
4923
4854
|
try {
|
|
4924
|
-
const parsed = JSON.parse((0,
|
|
4855
|
+
const parsed = JSON.parse((0, import_fs6.readFileSync)(lockPath, "utf-8"));
|
|
4925
4856
|
if (!Number.isInteger(parsed.pid) || Number(parsed.pid) <= 0) return null;
|
|
4926
4857
|
if (typeof parsed.startedAt !== "string" || Number.isNaN(Date.parse(parsed.startedAt))) return null;
|
|
4927
4858
|
return {
|
|
@@ -4956,23 +4887,23 @@ function sameReclaimOwner(left, right) {
|
|
|
4956
4887
|
function publishJsonDirectory(finalPath, value) {
|
|
4957
4888
|
const candidatePath = `${finalPath}.candidate.${process.pid}.${(0, import_crypto.randomUUID)()}`;
|
|
4958
4889
|
try {
|
|
4959
|
-
(0,
|
|
4890
|
+
(0, import_fs6.mkdirSync)(candidatePath, { mode: 448 });
|
|
4960
4891
|
} catch (error) {
|
|
4961
4892
|
if (getErrorCode(error) === "ENOENT") return false;
|
|
4962
4893
|
throw error;
|
|
4963
4894
|
}
|
|
4964
4895
|
try {
|
|
4965
|
-
(0,
|
|
4896
|
+
(0, import_fs6.writeFileSync)(path10.join(candidatePath, OWNER_FILE_NAME), JSON.stringify(value), {
|
|
4966
4897
|
encoding: "utf-8",
|
|
4967
4898
|
flag: "wx",
|
|
4968
4899
|
mode: 384
|
|
4969
4900
|
});
|
|
4970
|
-
if ((0,
|
|
4901
|
+
if ((0, import_fs6.existsSync)(finalPath)) return false;
|
|
4971
4902
|
try {
|
|
4972
|
-
(0,
|
|
4903
|
+
(0, import_fs6.renameSync)(candidatePath, finalPath);
|
|
4973
4904
|
return true;
|
|
4974
4905
|
} catch (error) {
|
|
4975
|
-
if ((0,
|
|
4906
|
+
if ((0, import_fs6.existsSync)(finalPath)) return false;
|
|
4976
4907
|
if (getErrorCode(error) === "ENOENT") return false;
|
|
4977
4908
|
throw error;
|
|
4978
4909
|
}
|
|
@@ -4980,7 +4911,7 @@ function publishJsonDirectory(finalPath, value) {
|
|
|
4980
4911
|
if (getErrorCode(error) === "ENOENT") return false;
|
|
4981
4912
|
throw error;
|
|
4982
4913
|
} finally {
|
|
4983
|
-
if ((0,
|
|
4914
|
+
if ((0, import_fs6.existsSync)(candidatePath)) (0, import_fs6.rmSync)(candidatePath, { recursive: true, force: true });
|
|
4984
4915
|
}
|
|
4985
4916
|
}
|
|
4986
4917
|
function createOwner(operation) {
|
|
@@ -4993,7 +4924,7 @@ function createOwner(operation) {
|
|
|
4993
4924
|
};
|
|
4994
4925
|
}
|
|
4995
4926
|
function recoveryMarkerPath(indexPath, owner) {
|
|
4996
|
-
return
|
|
4927
|
+
return path10.join(indexPath, `${RECOVERY_MARKER_PREFIX}${owner.token}`);
|
|
4997
4928
|
}
|
|
4998
4929
|
function publishRecoveryMarker(indexPath, owner) {
|
|
4999
4930
|
const markerPath = recoveryMarkerPath(indexPath, owner);
|
|
@@ -5007,16 +4938,16 @@ function publishRecoveryMarker(indexPath, owner) {
|
|
|
5007
4938
|
}
|
|
5008
4939
|
function getPendingRecoveries(indexPath) {
|
|
5009
4940
|
const recoveries = [];
|
|
5010
|
-
const markerNames = (0,
|
|
4941
|
+
const markerNames = (0, import_fs6.readdirSync)(indexPath).filter((name) => {
|
|
5011
4942
|
if (!name.startsWith(RECOVERY_MARKER_PREFIX)) return false;
|
|
5012
4943
|
return UUID_PATTERN.test(name.slice(RECOVERY_MARKER_PREFIX.length));
|
|
5013
4944
|
}).sort();
|
|
5014
4945
|
for (const markerName of markerNames) {
|
|
5015
|
-
const markerPath =
|
|
4946
|
+
const markerPath = path10.join(indexPath, markerName);
|
|
5016
4947
|
const markerToken = markerName.slice(RECOVERY_MARKER_PREFIX.length);
|
|
5017
4948
|
let markerStats;
|
|
5018
4949
|
try {
|
|
5019
|
-
markerStats = (0,
|
|
4950
|
+
markerStats = (0, import_fs6.lstatSync)(markerPath);
|
|
5020
4951
|
} catch (error) {
|
|
5021
4952
|
if (getErrorCode(error) === "ENOENT") continue;
|
|
5022
4953
|
throw error;
|
|
@@ -5038,17 +4969,17 @@ function getPendingRecoveries(indexPath) {
|
|
|
5038
4969
|
}
|
|
5039
4970
|
function cleanupDeadPublicationCandidates(indexPath) {
|
|
5040
4971
|
const candidatePattern = /^indexing\.lock(?:\.recovery\.[0-9a-f-]{36})?\.candidate\.(\d+)\.[0-9a-f-]{36}$/i;
|
|
5041
|
-
for (const entry of (0,
|
|
4972
|
+
for (const entry of (0, import_fs6.readdirSync)(indexPath)) {
|
|
5042
4973
|
const match = candidatePattern.exec(entry);
|
|
5043
4974
|
if (!match) continue;
|
|
5044
4975
|
const pid = Number(match[1]);
|
|
5045
4976
|
if (!Number.isInteger(pid) || pid <= 0) continue;
|
|
5046
4977
|
if (getOwnerLiveness({ pid, hostname: os4.hostname() }) !== "dead") continue;
|
|
5047
|
-
(0,
|
|
4978
|
+
(0, import_fs6.rmSync)(path10.join(indexPath, entry), { recursive: true, force: true });
|
|
5048
4979
|
}
|
|
5049
4980
|
}
|
|
5050
4981
|
function removeDeadReclaimMarker(lockPath, expectedOwner) {
|
|
5051
|
-
const markerPath =
|
|
4982
|
+
const markerPath = path10.join(lockPath, RECLAIM_DIRECTORY_NAME);
|
|
5052
4983
|
const marker = readReclaimOwner(markerPath);
|
|
5053
4984
|
if (!marker || marker.expectedOwnerToken !== expectedOwner.token || getOwnerLiveness(marker) !== "dead") {
|
|
5054
4985
|
return false;
|
|
@@ -5059,7 +4990,7 @@ function removeDeadReclaimMarker(lockPath, expectedOwner) {
|
|
|
5059
4990
|
}
|
|
5060
4991
|
const claimedMarkerPath = `${markerPath}.stale.${marker.pid}.${marker.token}.${(0, import_crypto.randomUUID)()}`;
|
|
5061
4992
|
try {
|
|
5062
|
-
(0,
|
|
4993
|
+
(0, import_fs6.renameSync)(markerPath, claimedMarkerPath);
|
|
5063
4994
|
} catch (error) {
|
|
5064
4995
|
if (getErrorCode(error) === "ENOENT") return false;
|
|
5065
4996
|
throw error;
|
|
@@ -5067,16 +4998,16 @@ function removeDeadReclaimMarker(lockPath, expectedOwner) {
|
|
|
5067
4998
|
const claimedMarker = readReclaimOwner(claimedMarkerPath);
|
|
5068
4999
|
const ownerAfterClaim = readDirectoryOwner(lockPath);
|
|
5069
5000
|
if (!claimedMarker || !sameReclaimOwner(claimedMarker, marker) || !ownerAfterClaim || !sameOwner(ownerAfterClaim, expectedOwner) || getOwnerLiveness(ownerAfterClaim) !== "dead") {
|
|
5070
|
-
if (!(0,
|
|
5071
|
-
(0,
|
|
5001
|
+
if (!(0, import_fs6.existsSync)(markerPath) && (0, import_fs6.existsSync)(claimedMarkerPath)) {
|
|
5002
|
+
(0, import_fs6.renameSync)(claimedMarkerPath, markerPath);
|
|
5072
5003
|
}
|
|
5073
5004
|
return false;
|
|
5074
5005
|
}
|
|
5075
|
-
(0,
|
|
5006
|
+
(0, import_fs6.rmSync)(claimedMarkerPath, { recursive: true, force: true });
|
|
5076
5007
|
return true;
|
|
5077
5008
|
}
|
|
5078
5009
|
function reclaimDeadOwner(indexPath, lockPath, expectedOwner) {
|
|
5079
|
-
const reclaimPath =
|
|
5010
|
+
const reclaimPath = path10.join(lockPath, RECLAIM_DIRECTORY_NAME);
|
|
5080
5011
|
const reclaimOwner = {
|
|
5081
5012
|
pid: process.pid,
|
|
5082
5013
|
hostname: os4.hostname(),
|
|
@@ -5102,8 +5033,8 @@ function reclaimDeadOwner(indexPath, lockPath, expectedOwner) {
|
|
|
5102
5033
|
return false;
|
|
5103
5034
|
}
|
|
5104
5035
|
const quarantinePath = `${lockPath}.stale.${expectedOwner.token}.${reclaimOwner.token}`;
|
|
5105
|
-
(0,
|
|
5106
|
-
(0,
|
|
5036
|
+
(0, import_fs6.renameSync)(lockPath, quarantinePath);
|
|
5037
|
+
(0, import_fs6.rmSync)(quarantinePath, { recursive: true, force: true });
|
|
5107
5038
|
return true;
|
|
5108
5039
|
} catch (error) {
|
|
5109
5040
|
if (getErrorCode(error) === "ENOENT") return false;
|
|
@@ -5128,9 +5059,9 @@ function isIndexLockContentionError(error) {
|
|
|
5128
5059
|
return error instanceof IndexLockContentionError || typeof error === "object" && error !== null && "code" in error && error.code === "INDEX_BUSY";
|
|
5129
5060
|
}
|
|
5130
5061
|
function acquireIndexLock(indexPath, operation) {
|
|
5131
|
-
(0,
|
|
5132
|
-
const canonicalIndexPath =
|
|
5133
|
-
const lockPath =
|
|
5062
|
+
(0, import_fs6.mkdirSync)(indexPath, { recursive: true });
|
|
5063
|
+
const canonicalIndexPath = import_fs6.realpathSync.native(indexPath);
|
|
5064
|
+
const lockPath = path10.join(canonicalIndexPath, "indexing.lock");
|
|
5134
5065
|
cleanupDeadPublicationCandidates(canonicalIndexPath);
|
|
5135
5066
|
for (let attempt = 0; attempt < 6; attempt += 1) {
|
|
5136
5067
|
const owner = createOwner(operation);
|
|
@@ -5151,7 +5082,7 @@ function acquireIndexLock(indexPath, operation) {
|
|
|
5151
5082
|
}
|
|
5152
5083
|
let stats;
|
|
5153
5084
|
try {
|
|
5154
|
-
stats = (0,
|
|
5085
|
+
stats = (0, import_fs6.lstatSync)(lockPath);
|
|
5155
5086
|
} catch (error) {
|
|
5156
5087
|
if (getErrorCode(error) === "ENOENT") continue;
|
|
5157
5088
|
throw error;
|
|
@@ -5179,78 +5110,44 @@ function releaseIndexLock(lease) {
|
|
|
5179
5110
|
if (!currentOwner || !sameOwner(currentOwner, lease.owner)) return false;
|
|
5180
5111
|
const releasePath = `${lease.lockPath}.release.${lease.owner.pid}.${lease.owner.token}`;
|
|
5181
5112
|
try {
|
|
5182
|
-
retryTransientFilesystemOperation(() => (0,
|
|
5113
|
+
retryTransientFilesystemOperation(() => (0, import_fs6.renameSync)(lease.lockPath, releasePath));
|
|
5183
5114
|
} catch (error) {
|
|
5184
5115
|
if (getErrorCode(error) === "ENOENT") return false;
|
|
5185
5116
|
throw error;
|
|
5186
5117
|
}
|
|
5187
5118
|
const claimedOwner = readDirectoryOwner(releasePath);
|
|
5188
5119
|
if (!claimedOwner || !sameOwner(claimedOwner, lease.owner)) {
|
|
5189
|
-
if (!(0,
|
|
5190
|
-
(0,
|
|
5120
|
+
if (!(0, import_fs6.existsSync)(lease.lockPath) && (0, import_fs6.existsSync)(releasePath)) {
|
|
5121
|
+
(0, import_fs6.renameSync)(releasePath, lease.lockPath);
|
|
5191
5122
|
}
|
|
5192
5123
|
return false;
|
|
5193
5124
|
}
|
|
5194
5125
|
try {
|
|
5195
|
-
retryTransientFilesystemOperation(() => (0,
|
|
5126
|
+
retryTransientFilesystemOperation(() => (0, import_fs6.rmSync)(releasePath, { recursive: true, force: true }));
|
|
5196
5127
|
} catch (error) {
|
|
5197
5128
|
console.error(`[codebase-index] Lease released but tombstone cleanup failed: ${releasePath}`, error);
|
|
5198
5129
|
}
|
|
5199
5130
|
return true;
|
|
5200
5131
|
}
|
|
5201
|
-
async function withIndexLock(indexPath, operation, callback, options = {}) {
|
|
5202
|
-
const lease = acquireIndexLock(indexPath, operation);
|
|
5203
|
-
let result;
|
|
5204
|
-
let callbackError;
|
|
5205
|
-
let callbackFailed = false;
|
|
5206
|
-
try {
|
|
5207
|
-
result = await callback(lease);
|
|
5208
|
-
} catch (error) {
|
|
5209
|
-
callbackFailed = true;
|
|
5210
|
-
callbackError = error;
|
|
5211
|
-
}
|
|
5212
|
-
if (!callbackFailed && options.completeRecoveries !== false) {
|
|
5213
|
-
try {
|
|
5214
|
-
completeLeaseRecovery(lease);
|
|
5215
|
-
} catch (error) {
|
|
5216
|
-
callbackFailed = true;
|
|
5217
|
-
callbackError = error;
|
|
5218
|
-
}
|
|
5219
|
-
}
|
|
5220
|
-
let releaseError;
|
|
5221
|
-
try {
|
|
5222
|
-
if (!releaseIndexLock(lease)) {
|
|
5223
|
-
releaseError = new Error(`Lost ownership of index mutation lease ${lease.owner.token}`);
|
|
5224
|
-
}
|
|
5225
|
-
} catch (error) {
|
|
5226
|
-
releaseError = error;
|
|
5227
|
-
}
|
|
5228
|
-
if (releaseError !== void 0) {
|
|
5229
|
-
if (callbackFailed) throw new AggregateError([callbackError, releaseError], "Index mutation and lease release both failed");
|
|
5230
|
-
throw releaseError;
|
|
5231
|
-
}
|
|
5232
|
-
if (callbackFailed) throw callbackError;
|
|
5233
|
-
return result;
|
|
5234
|
-
}
|
|
5235
5132
|
function createLeaseTemporaryPath(targetPath, owner, kind = "tmp") {
|
|
5236
5133
|
if (kind === "bak") return `${targetPath}.bak.${owner.pid}.${owner.token}`;
|
|
5237
5134
|
temporaryCounter += 1;
|
|
5238
5135
|
return `${targetPath}.tmp.${owner.pid}.${owner.token}.${temporaryCounter}`;
|
|
5239
5136
|
}
|
|
5240
5137
|
function removeLeaseTemporaryPath(temporaryPath) {
|
|
5241
|
-
if ((0,
|
|
5138
|
+
if ((0, import_fs6.existsSync)(temporaryPath)) (0, import_fs6.rmSync)(temporaryPath, { recursive: true, force: true });
|
|
5242
5139
|
}
|
|
5243
5140
|
function recoverLeaseArtifacts(indexPath, owner, backupTargets) {
|
|
5244
5141
|
for (const targetPath of backupTargets) {
|
|
5245
5142
|
const backupPath = createLeaseTemporaryPath(targetPath, owner, "bak");
|
|
5246
|
-
if (!(0,
|
|
5247
|
-
if ((0,
|
|
5248
|
-
(0,
|
|
5143
|
+
if (!(0, import_fs6.existsSync)(backupPath)) continue;
|
|
5144
|
+
if ((0, import_fs6.existsSync)(targetPath)) (0, import_fs6.rmSync)(targetPath, { recursive: true, force: true });
|
|
5145
|
+
(0, import_fs6.renameSync)(backupPath, targetPath);
|
|
5249
5146
|
}
|
|
5250
5147
|
const temporaryOwnerMarker = `.tmp.${owner.pid}.${owner.token}.`;
|
|
5251
|
-
for (const entry of (0,
|
|
5148
|
+
for (const entry of (0, import_fs6.readdirSync)(indexPath)) {
|
|
5252
5149
|
if (!entry.includes(temporaryOwnerMarker)) continue;
|
|
5253
|
-
(0,
|
|
5150
|
+
(0, import_fs6.rmSync)(path10.join(indexPath, entry), { recursive: true, force: true });
|
|
5254
5151
|
}
|
|
5255
5152
|
}
|
|
5256
5153
|
function completeLeaseRecovery(lease) {
|
|
@@ -5261,13 +5158,23 @@ function completeLeaseRecovery(lease) {
|
|
|
5261
5158
|
}
|
|
5262
5159
|
}
|
|
5263
5160
|
for (const recovery of lease.recoveries) {
|
|
5264
|
-
(0,
|
|
5161
|
+
(0, import_fs6.rmSync)(recovery.markerPath, { recursive: true, force: true });
|
|
5265
5162
|
}
|
|
5266
5163
|
}
|
|
5267
5164
|
|
|
5268
5165
|
// src/indexer/index.ts
|
|
5269
|
-
var CALL_GRAPH_LANGUAGES = /* @__PURE__ */ new Set(["typescript", "tsx", "javascript", "jsx", "python", "go", "rust", "php", "apex", "zig", "gdscript", "matlab", "bash"]);
|
|
5270
|
-
var CASE_INSENSITIVE_LANGUAGES = /* @__PURE__ */ new Set(["apex"]);
|
|
5166
|
+
var CALL_GRAPH_LANGUAGES = /* @__PURE__ */ new Set(["typescript", "tsx", "javascript", "jsx", "python", "go", "rust", "swift", "php", "apex", "zig", "gdscript", "matlab", "bash", "c", "cpp", "metal"]);
|
|
5167
|
+
var CASE_INSENSITIVE_LANGUAGES = /* @__PURE__ */ new Set(["apex", "php"]);
|
|
5168
|
+
var CALL_GRAPH_RESOLUTION_VERSION = "4";
|
|
5169
|
+
var PHP_FUNCTION_SYMBOL_CHUNK_TYPES = /* @__PURE__ */ new Set([
|
|
5170
|
+
"function_declaration",
|
|
5171
|
+
"function",
|
|
5172
|
+
"function_definition"
|
|
5173
|
+
]);
|
|
5174
|
+
var PHP_CLASS_SYMBOL_CHUNK_TYPES = /* @__PURE__ */ new Set([
|
|
5175
|
+
"class_declaration",
|
|
5176
|
+
"class_definition"
|
|
5177
|
+
]);
|
|
5271
5178
|
var CALL_GRAPH_SYMBOL_CHUNK_TYPES = /* @__PURE__ */ new Set([
|
|
5272
5179
|
"function_declaration",
|
|
5273
5180
|
"function",
|
|
@@ -5280,6 +5187,9 @@ var CALL_GRAPH_SYMBOL_CHUNK_TYPES = /* @__PURE__ */ new Set([
|
|
|
5280
5187
|
"enum_declaration",
|
|
5281
5188
|
"function_definition",
|
|
5282
5189
|
"class_definition",
|
|
5190
|
+
"class_specifier",
|
|
5191
|
+
"struct_specifier",
|
|
5192
|
+
"namespace_definition",
|
|
5283
5193
|
"decorated_definition",
|
|
5284
5194
|
"method_declaration",
|
|
5285
5195
|
"type_declaration",
|
|
@@ -5295,6 +5205,14 @@ var CALL_GRAPH_SYMBOL_CHUNK_TYPES = /* @__PURE__ */ new Set([
|
|
|
5295
5205
|
"test_declaration",
|
|
5296
5206
|
"struct_declaration",
|
|
5297
5207
|
"union_declaration",
|
|
5208
|
+
// Synthetic Swift declarations or declarations specific to tree-sitter-swift.
|
|
5209
|
+
"actor_declaration",
|
|
5210
|
+
"extension_declaration",
|
|
5211
|
+
"protocol_declaration",
|
|
5212
|
+
"protocol_function_declaration",
|
|
5213
|
+
"init_declaration",
|
|
5214
|
+
"deinit_declaration",
|
|
5215
|
+
"subscript_declaration",
|
|
5298
5216
|
// GDScript declarations whose names participate in the call graph.
|
|
5299
5217
|
// `function_definition` and `class_definition` are already in the set
|
|
5300
5218
|
// above (shared with Python/C/Bash and Python, respectively).
|
|
@@ -5304,6 +5222,53 @@ var CALL_GRAPH_SYMBOL_CHUNK_TYPES = /* @__PURE__ */ new Set([
|
|
|
5304
5222
|
"const_statement",
|
|
5305
5223
|
"class_name_statement"
|
|
5306
5224
|
]);
|
|
5225
|
+
var C_FAMILY_TYPE_SYMBOL_CHUNK_TYPES = /* @__PURE__ */ new Set(["class_specifier", "struct_specifier"]);
|
|
5226
|
+
function isCompatibleCFamilyCallTarget(language, callType, symbolKind) {
|
|
5227
|
+
if (language !== "c" && language !== "cpp") return true;
|
|
5228
|
+
if (symbolKind === "namespace_definition") return callType === "Import";
|
|
5229
|
+
const isTypeSymbol = C_FAMILY_TYPE_SYMBOL_CHUNK_TYPES.has(symbolKind);
|
|
5230
|
+
if (callType === "Constructor" || callType === "Inherits" || callType === "Implements") {
|
|
5231
|
+
return isTypeSymbol;
|
|
5232
|
+
}
|
|
5233
|
+
return !isTypeSymbol;
|
|
5234
|
+
}
|
|
5235
|
+
var EXECUTABLE_SYMBOL_CHUNK_TYPES = /* @__PURE__ */ new Set([
|
|
5236
|
+
"function_declaration",
|
|
5237
|
+
"function",
|
|
5238
|
+
"arrow_function",
|
|
5239
|
+
"method_definition",
|
|
5240
|
+
"function_definition",
|
|
5241
|
+
"method_declaration",
|
|
5242
|
+
"function_item",
|
|
5243
|
+
"protocol_function_declaration",
|
|
5244
|
+
"init_declaration",
|
|
5245
|
+
"deinit_declaration",
|
|
5246
|
+
"subscript_declaration",
|
|
5247
|
+
"constructor_definition",
|
|
5248
|
+
"trigger_declaration",
|
|
5249
|
+
"test_declaration"
|
|
5250
|
+
]);
|
|
5251
|
+
function findEnclosingSymbol(symbols, line, column) {
|
|
5252
|
+
let best;
|
|
5253
|
+
for (const symbol of symbols) {
|
|
5254
|
+
if (line < symbol.startLine || line > symbol.endLine) continue;
|
|
5255
|
+
if (column !== void 0 && (line === symbol.startLine && column < symbol.startCol || line === symbol.endLine && column >= symbol.endCol)) {
|
|
5256
|
+
continue;
|
|
5257
|
+
}
|
|
5258
|
+
if (!best) {
|
|
5259
|
+
best = symbol;
|
|
5260
|
+
continue;
|
|
5261
|
+
}
|
|
5262
|
+
const span = symbol.endLine - symbol.startLine;
|
|
5263
|
+
const bestSpan = best.endLine - best.startLine;
|
|
5264
|
+
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);
|
|
5265
|
+
const isMoreSpecificTie = span === bestSpan && symbol.startLine === best.startLine && EXECUTABLE_SYMBOL_CHUNK_TYPES.has(symbol.kind) && !EXECUTABLE_SYMBOL_CHUNK_TYPES.has(best.kind);
|
|
5266
|
+
if (span < bestSpan || span === bestSpan && symbol.startLine > best.startLine || isNarrowerPositionRange || isMoreSpecificTie) {
|
|
5267
|
+
best = symbol;
|
|
5268
|
+
}
|
|
5269
|
+
}
|
|
5270
|
+
return best;
|
|
5271
|
+
}
|
|
5307
5272
|
function float32ArrayToBuffer(arr) {
|
|
5308
5273
|
const float32 = new Float32Array(arr);
|
|
5309
5274
|
return Buffer.from(float32.buffer);
|
|
@@ -5388,6 +5353,8 @@ function hasBlameMetadata(metadata) {
|
|
|
5388
5353
|
}
|
|
5389
5354
|
var INDEX_METADATA_VERSION = "1";
|
|
5390
5355
|
var EMBEDDING_STRATEGY_VERSION = "2";
|
|
5356
|
+
var SWIFT_PARSER_VERSION = "1";
|
|
5357
|
+
var METAL_PARSER_VERSION = "1";
|
|
5391
5358
|
var RANKING_TOKEN_CACHE_LIMIT = 4096;
|
|
5392
5359
|
var RANK_HYBRID_CACHE_LIMIT = 256;
|
|
5393
5360
|
function createPendingChunkStorageText(texts) {
|
|
@@ -5544,9 +5511,9 @@ function hasAllEmbeddingParts(parts, expectedPartCount) {
|
|
|
5544
5511
|
return true;
|
|
5545
5512
|
}
|
|
5546
5513
|
function isPathWithinRoot(filePath, rootPath) {
|
|
5547
|
-
const normalizedFilePath =
|
|
5548
|
-
const normalizedRoot =
|
|
5549
|
-
return normalizedFilePath === normalizedRoot || normalizedFilePath.startsWith(`${normalizedRoot}${
|
|
5514
|
+
const normalizedFilePath = path11.resolve(filePath);
|
|
5515
|
+
const normalizedRoot = path11.resolve(rootPath);
|
|
5516
|
+
return normalizedFilePath === normalizedRoot || normalizedFilePath.startsWith(`${normalizedRoot}${path11.sep}`);
|
|
5550
5517
|
}
|
|
5551
5518
|
var rankingQueryTokenCache = /* @__PURE__ */ new Map();
|
|
5552
5519
|
var rankingNameTokenCache = /* @__PURE__ */ new Map();
|
|
@@ -5710,15 +5677,25 @@ function chunkTypeBoost(chunkType) {
|
|
|
5710
5677
|
case "function_declaration":
|
|
5711
5678
|
case "method":
|
|
5712
5679
|
case "method_definition":
|
|
5680
|
+
case "method_declaration":
|
|
5681
|
+
case "protocol_function_declaration":
|
|
5682
|
+
case "init_declaration":
|
|
5683
|
+
case "deinit_declaration":
|
|
5684
|
+
case "subscript_declaration":
|
|
5713
5685
|
case "class":
|
|
5714
5686
|
case "class_declaration":
|
|
5687
|
+
case "actor_declaration":
|
|
5688
|
+
case "extension_declaration":
|
|
5715
5689
|
return 0.2;
|
|
5716
5690
|
case "interface":
|
|
5717
5691
|
case "type":
|
|
5718
5692
|
case "enum":
|
|
5693
|
+
case "enum_declaration":
|
|
5719
5694
|
case "struct":
|
|
5695
|
+
case "struct_declaration":
|
|
5720
5696
|
case "impl":
|
|
5721
5697
|
case "trait":
|
|
5698
|
+
case "protocol_declaration":
|
|
5722
5699
|
case "module":
|
|
5723
5700
|
return 0.1;
|
|
5724
5701
|
default:
|
|
@@ -5825,11 +5802,21 @@ function isImplementationChunkType(chunkType) {
|
|
|
5825
5802
|
"function_declaration",
|
|
5826
5803
|
"method",
|
|
5827
5804
|
"method_definition",
|
|
5805
|
+
"method_declaration",
|
|
5806
|
+
"protocol_function_declaration",
|
|
5807
|
+
"init_declaration",
|
|
5808
|
+
"deinit_declaration",
|
|
5809
|
+
"subscript_declaration",
|
|
5828
5810
|
"class",
|
|
5829
5811
|
"class_declaration",
|
|
5812
|
+
"actor_declaration",
|
|
5813
|
+
"extension_declaration",
|
|
5830
5814
|
"interface",
|
|
5815
|
+
"protocol_declaration",
|
|
5831
5816
|
"type",
|
|
5832
5817
|
"enum",
|
|
5818
|
+
"enum_declaration",
|
|
5819
|
+
"struct_declaration",
|
|
5833
5820
|
"module"
|
|
5834
5821
|
].includes(chunkType);
|
|
5835
5822
|
}
|
|
@@ -6646,24 +6633,24 @@ var Indexer = class {
|
|
|
6646
6633
|
this.config = config;
|
|
6647
6634
|
this.host = host;
|
|
6648
6635
|
this.indexPath = this.getIndexPath();
|
|
6649
|
-
this.fileHashCachePath =
|
|
6650
|
-
this.failedBatchesPath =
|
|
6636
|
+
this.fileHashCachePath = path11.join(this.indexPath, "file-hashes.json");
|
|
6637
|
+
this.failedBatchesPath = path11.join(this.indexPath, "failed-batches.json");
|
|
6651
6638
|
this.logger = initializeLogger(config.debug);
|
|
6652
6639
|
}
|
|
6653
6640
|
getIndexPath() {
|
|
6654
6641
|
return resolveProjectIndexPath(this.projectRoot, this.config.scope, this.host);
|
|
6655
6642
|
}
|
|
6656
6643
|
isLocalProjectIndexPath() {
|
|
6657
|
-
const localProjectIndexPaths = [
|
|
6644
|
+
const localProjectIndexPaths = [path11.join(this.projectRoot, getHostProjectIndexRelativePath(this.host))];
|
|
6658
6645
|
if (this.host !== "opencode") {
|
|
6659
|
-
localProjectIndexPaths.push(
|
|
6646
|
+
localProjectIndexPaths.push(path11.join(this.projectRoot, getHostProjectIndexRelativePath("opencode")));
|
|
6660
6647
|
}
|
|
6661
6648
|
return localProjectIndexPaths.some((localPath) => {
|
|
6662
|
-
if (!(0,
|
|
6663
|
-
return
|
|
6649
|
+
if (!(0, import_fs7.existsSync)(localPath) || !(0, import_fs7.existsSync)(this.indexPath)) {
|
|
6650
|
+
return path11.resolve(this.indexPath) === path11.resolve(localPath);
|
|
6664
6651
|
}
|
|
6665
|
-
const indexStats = (0,
|
|
6666
|
-
const localStats = (0,
|
|
6652
|
+
const indexStats = (0, import_fs7.statSync)(this.indexPath);
|
|
6653
|
+
const localStats = (0, import_fs7.statSync)(localPath);
|
|
6667
6654
|
return indexStats.dev === localStats.dev && indexStats.ino === localStats.ino;
|
|
6668
6655
|
});
|
|
6669
6656
|
}
|
|
@@ -6702,8 +6689,8 @@ var Indexer = class {
|
|
|
6702
6689
|
async withIndexMutationLease(operation, callback) {
|
|
6703
6690
|
const lease = acquireIndexLock(this.indexPath, operation);
|
|
6704
6691
|
this.indexPath = lease.canonicalIndexPath;
|
|
6705
|
-
this.fileHashCachePath =
|
|
6706
|
-
this.failedBatchesPath =
|
|
6692
|
+
this.fileHashCachePath = path11.join(this.indexPath, "file-hashes.json");
|
|
6693
|
+
this.failedBatchesPath = path11.join(this.indexPath, "failed-batches.json");
|
|
6707
6694
|
this.activeIndexLease = lease;
|
|
6708
6695
|
let result;
|
|
6709
6696
|
let callbackError;
|
|
@@ -6737,7 +6724,7 @@ var Indexer = class {
|
|
|
6737
6724
|
} catch (error) {
|
|
6738
6725
|
releaseError = error;
|
|
6739
6726
|
this.writerArtifactFingerprint = null;
|
|
6740
|
-
if (!(0,
|
|
6727
|
+
if (!(0, import_fs7.existsSync)(lease.lockPath) && this.activeIndexLease?.owner.token === lease.owner.token) {
|
|
6741
6728
|
this.activeIndexLease = null;
|
|
6742
6729
|
}
|
|
6743
6730
|
}
|
|
@@ -6755,11 +6742,11 @@ var Indexer = class {
|
|
|
6755
6742
|
return this.activeIndexLease;
|
|
6756
6743
|
}
|
|
6757
6744
|
loadFileHashCache() {
|
|
6758
|
-
if (!(0,
|
|
6745
|
+
if (!(0, import_fs7.existsSync)(this.fileHashCachePath)) {
|
|
6759
6746
|
return;
|
|
6760
6747
|
}
|
|
6761
6748
|
try {
|
|
6762
|
-
const data = (0,
|
|
6749
|
+
const data = (0, import_fs7.readFileSync)(this.fileHashCachePath, "utf-8");
|
|
6763
6750
|
const parsed = JSON.parse(data);
|
|
6764
6751
|
this.fileHashCache = new Map(Object.entries(parsed));
|
|
6765
6752
|
} catch (error) {
|
|
@@ -6781,24 +6768,24 @@ var Indexer = class {
|
|
|
6781
6768
|
atomicWriteSync(targetPath, data) {
|
|
6782
6769
|
const lease = this.requireActiveLease();
|
|
6783
6770
|
const tempPath = createLeaseTemporaryPath(targetPath, lease.owner, "tmp");
|
|
6784
|
-
(0,
|
|
6771
|
+
(0, import_fs7.mkdirSync)(path11.dirname(targetPath), { recursive: true });
|
|
6785
6772
|
try {
|
|
6786
|
-
(0,
|
|
6787
|
-
(0,
|
|
6773
|
+
(0, import_fs7.writeFileSync)(tempPath, data);
|
|
6774
|
+
(0, import_fs7.renameSync)(tempPath, targetPath);
|
|
6788
6775
|
} finally {
|
|
6789
6776
|
removeLeaseTemporaryPath(tempPath);
|
|
6790
6777
|
}
|
|
6791
6778
|
}
|
|
6792
6779
|
saveInvertedIndex(invertedIndex) {
|
|
6793
6780
|
this.atomicWriteSync(
|
|
6794
|
-
|
|
6781
|
+
path11.join(this.indexPath, "inverted-index.json"),
|
|
6795
6782
|
invertedIndex.serialize()
|
|
6796
6783
|
);
|
|
6797
6784
|
}
|
|
6798
6785
|
getScopedRoots() {
|
|
6799
|
-
const roots = /* @__PURE__ */ new Set([
|
|
6786
|
+
const roots = /* @__PURE__ */ new Set([path11.resolve(this.projectRoot)]);
|
|
6800
6787
|
for (const kbRoot of this.config.knowledgeBases) {
|
|
6801
|
-
roots.add(
|
|
6788
|
+
roots.add(path11.resolve(this.projectRoot, kbRoot));
|
|
6802
6789
|
}
|
|
6803
6790
|
return Array.from(roots);
|
|
6804
6791
|
}
|
|
@@ -6807,31 +6794,54 @@ var Indexer = class {
|
|
|
6807
6794
|
if (this.config.scope !== "global") {
|
|
6808
6795
|
return branchName;
|
|
6809
6796
|
}
|
|
6810
|
-
const projectHash = hashContent(
|
|
6797
|
+
const projectHash = hashContent(path11.resolve(this.projectRoot)).slice(0, 16);
|
|
6811
6798
|
return `${projectHash}:${branchName}`;
|
|
6812
6799
|
}
|
|
6813
6800
|
getBranchCatalogKeyFor(branchName) {
|
|
6814
6801
|
if (this.config.scope !== "global") {
|
|
6815
6802
|
return branchName;
|
|
6816
6803
|
}
|
|
6817
|
-
const projectHash = hashContent(
|
|
6804
|
+
const projectHash = hashContent(path11.resolve(this.projectRoot)).slice(0, 16);
|
|
6818
6805
|
return `${projectHash}:${branchName}`;
|
|
6819
6806
|
}
|
|
6820
6807
|
getLegacyBranchCatalogKey() {
|
|
6821
6808
|
return this.currentBranch || "default";
|
|
6822
6809
|
}
|
|
6823
6810
|
getLegacyMigrationMetadataKey() {
|
|
6824
|
-
const projectHash = hashContent(
|
|
6811
|
+
const projectHash = hashContent(path11.resolve(this.projectRoot)).slice(0, 16);
|
|
6825
6812
|
return `index.globalBranchMigration.${projectHash}`;
|
|
6826
6813
|
}
|
|
6827
6814
|
getProjectEmbeddingStrategyMetadataKey() {
|
|
6828
|
-
const projectHash = hashContent(
|
|
6815
|
+
const projectHash = hashContent(path11.resolve(this.projectRoot)).slice(0, 16);
|
|
6829
6816
|
return `index.embeddingStrategyVersion.${projectHash}`;
|
|
6830
6817
|
}
|
|
6831
6818
|
getProjectForceReembedMetadataKey() {
|
|
6832
|
-
const projectHash = hashContent(
|
|
6819
|
+
const projectHash = hashContent(path11.resolve(this.projectRoot)).slice(0, 16);
|
|
6833
6820
|
return `index.forceReembed.${projectHash}`;
|
|
6834
6821
|
}
|
|
6822
|
+
getCallGraphResolutionMetadataKey() {
|
|
6823
|
+
if (this.config.scope !== "global") {
|
|
6824
|
+
return "index.callGraphResolutionVersion";
|
|
6825
|
+
}
|
|
6826
|
+
const projectHash = hashContent(path11.resolve(this.projectRoot)).slice(0, 16);
|
|
6827
|
+
return `index.callGraphResolutionVersion.${projectHash}`;
|
|
6828
|
+
}
|
|
6829
|
+
getSwiftParserVersionMetadataKey() {
|
|
6830
|
+
const key = "index.parser.swiftVersion";
|
|
6831
|
+
if (this.config.scope !== "global") {
|
|
6832
|
+
return key;
|
|
6833
|
+
}
|
|
6834
|
+
const projectHash = hashContent(path11.resolve(this.projectRoot)).slice(0, 16);
|
|
6835
|
+
return `${key}.${projectHash}`;
|
|
6836
|
+
}
|
|
6837
|
+
getMetalParserVersionMetadataKey() {
|
|
6838
|
+
const key = "index.parser.metalVersion";
|
|
6839
|
+
if (this.config.scope !== "global") {
|
|
6840
|
+
return key;
|
|
6841
|
+
}
|
|
6842
|
+
const projectHash = hashContent(path11.resolve(this.projectRoot)).slice(0, 16);
|
|
6843
|
+
return `${key}.${projectHash}`;
|
|
6844
|
+
}
|
|
6835
6845
|
hasProjectForceReembedPending() {
|
|
6836
6846
|
return this.config.scope === "global" && this.database?.getMetadata(this.getProjectForceReembedMetadataKey()) === "true";
|
|
6837
6847
|
}
|
|
@@ -6923,7 +6933,7 @@ var Indexer = class {
|
|
|
6923
6933
|
if (!this.database) {
|
|
6924
6934
|
return { chunkIds, symbolIds };
|
|
6925
6935
|
}
|
|
6926
|
-
const projectRootPath =
|
|
6936
|
+
const projectRootPath = path11.resolve(this.projectRoot);
|
|
6927
6937
|
const projectLocalFilePaths = /* @__PURE__ */ new Set([
|
|
6928
6938
|
...Array.from(this.fileHashCache.keys()).filter(
|
|
6929
6939
|
(filePath) => this.isFileInCurrentScope(filePath, roots) && isPathWithinRoot(filePath, projectRootPath)
|
|
@@ -6946,7 +6956,7 @@ var Indexer = class {
|
|
|
6946
6956
|
if (this.config.scope !== "global") {
|
|
6947
6957
|
return this.getBranchCatalogCleanupKeys();
|
|
6948
6958
|
}
|
|
6949
|
-
const projectHash = hashContent(
|
|
6959
|
+
const projectHash = hashContent(path11.resolve(this.projectRoot)).slice(0, 16);
|
|
6950
6960
|
const keys = /* @__PURE__ */ new Set();
|
|
6951
6961
|
const projectChunkIdSet = new Set(projectChunkIds);
|
|
6952
6962
|
const projectSymbolIdSet = new Set(projectSymbolIds);
|
|
@@ -7030,7 +7040,7 @@ var Indexer = class {
|
|
|
7030
7040
|
if (!this.database || this.config.scope !== "global") {
|
|
7031
7041
|
return false;
|
|
7032
7042
|
}
|
|
7033
|
-
const projectHash = hashContent(
|
|
7043
|
+
const projectHash = hashContent(path11.resolve(this.projectRoot)).slice(0, 16);
|
|
7034
7044
|
const roots = this.getScopedRoots();
|
|
7035
7045
|
const { chunkIds: projectLocalChunkIds, symbolIds: projectLocalSymbolIds } = this.getProjectLocalScopedOwnershipIds(roots);
|
|
7036
7046
|
return this.database.getAllBranches().some(
|
|
@@ -7064,7 +7074,7 @@ var Indexer = class {
|
|
|
7064
7074
|
...Array.from(this.fileHashCache.keys()).filter((filePath) => this.isFileInCurrentScope(filePath, roots)),
|
|
7065
7075
|
...scopedEntries.map(({ metadata }) => metadata.filePath)
|
|
7066
7076
|
]);
|
|
7067
|
-
const projectRootPath =
|
|
7077
|
+
const projectRootPath = path11.resolve(this.projectRoot);
|
|
7068
7078
|
const projectLocalFilePaths = new Set(
|
|
7069
7079
|
Array.from(filePaths).filter((filePath) => isPathWithinRoot(filePath, projectRootPath))
|
|
7070
7080
|
);
|
|
@@ -7142,8 +7152,8 @@ var Indexer = class {
|
|
|
7142
7152
|
});
|
|
7143
7153
|
}
|
|
7144
7154
|
if (this.config.scope === "global") {
|
|
7145
|
-
if ((0,
|
|
7146
|
-
(0,
|
|
7155
|
+
if ((0, import_fs7.existsSync)(this.fileHashCachePath)) {
|
|
7156
|
+
(0, import_fs7.unlinkSync)(this.fileHashCachePath);
|
|
7147
7157
|
}
|
|
7148
7158
|
await this.healthCheckUnlocked();
|
|
7149
7159
|
}
|
|
@@ -7162,10 +7172,10 @@ var Indexer = class {
|
|
|
7162
7172
|
}
|
|
7163
7173
|
}
|
|
7164
7174
|
loadSerializedFailedBatches() {
|
|
7165
|
-
if (!(0,
|
|
7175
|
+
if (!(0, import_fs7.existsSync)(this.failedBatchesPath)) {
|
|
7166
7176
|
return [];
|
|
7167
7177
|
}
|
|
7168
|
-
const data = (0,
|
|
7178
|
+
const data = (0, import_fs7.readFileSync)(this.failedBatchesPath, "utf-8");
|
|
7169
7179
|
const parsed = JSON.parse(data);
|
|
7170
7180
|
return parsed.map((batch) => {
|
|
7171
7181
|
const chunks = Array.isArray(batch.chunks) ? batch.chunks : [];
|
|
@@ -7182,9 +7192,9 @@ var Indexer = class {
|
|
|
7182
7192
|
}
|
|
7183
7193
|
saveFailedBatches(batches) {
|
|
7184
7194
|
if (batches.length === 0) {
|
|
7185
|
-
if ((0,
|
|
7195
|
+
if ((0, import_fs7.existsSync)(this.failedBatchesPath)) {
|
|
7186
7196
|
try {
|
|
7187
|
-
(0,
|
|
7197
|
+
(0, import_fs7.unlinkSync)(this.failedBatchesPath);
|
|
7188
7198
|
} catch {
|
|
7189
7199
|
}
|
|
7190
7200
|
}
|
|
@@ -7370,7 +7380,7 @@ var Indexer = class {
|
|
|
7370
7380
|
const intent = isLikelyImplementationPath(candidate.metadata.filePath) ? "implementation" : "doc_or_test";
|
|
7371
7381
|
parts.push(`intent_hint: ${intent}`);
|
|
7372
7382
|
try {
|
|
7373
|
-
const fileContent = await
|
|
7383
|
+
const fileContent = await import_fs7.promises.readFile(candidate.metadata.filePath, "utf-8");
|
|
7374
7384
|
const lines = fileContent.split("\n");
|
|
7375
7385
|
const snippetStartLine = Math.max(1, candidate.metadata.startLine - 2);
|
|
7376
7386
|
const snippetEndLine = Math.min(lines.length, candidate.metadata.endLine + 2);
|
|
@@ -7464,7 +7474,7 @@ var Indexer = class {
|
|
|
7464
7474
|
}
|
|
7465
7475
|
getReaderFileFingerprint(filePath, identityOnly = false) {
|
|
7466
7476
|
try {
|
|
7467
|
-
const stats = (0,
|
|
7477
|
+
const stats = (0, import_fs7.statSync)(filePath);
|
|
7468
7478
|
if (identityOnly) {
|
|
7469
7479
|
return `${stats.dev}:${stats.ino}`;
|
|
7470
7480
|
}
|
|
@@ -7474,12 +7484,12 @@ var Indexer = class {
|
|
|
7474
7484
|
}
|
|
7475
7485
|
}
|
|
7476
7486
|
captureReaderArtifactFingerprint() {
|
|
7477
|
-
const storePath =
|
|
7487
|
+
const storePath = path11.join(this.indexPath, "vectors");
|
|
7478
7488
|
return {
|
|
7479
7489
|
vectors: `${this.getReaderFileFingerprint(storePath)}|${this.getReaderFileFingerprint(`${storePath}.meta.json`)}`,
|
|
7480
|
-
keyword: this.getReaderFileFingerprint(
|
|
7481
|
-
database: this.getReaderFileFingerprint(
|
|
7482
|
-
databaseIdentity: this.getReaderFileFingerprint(
|
|
7490
|
+
keyword: this.getReaderFileFingerprint(path11.join(this.indexPath, "inverted-index.json")),
|
|
7491
|
+
database: this.getReaderFileFingerprint(path11.join(this.indexPath, "codebase.db")),
|
|
7492
|
+
databaseIdentity: this.getReaderFileFingerprint(path11.join(this.indexPath, "codebase.db"), true)
|
|
7483
7493
|
};
|
|
7484
7494
|
}
|
|
7485
7495
|
refreshReaderArtifacts() {
|
|
@@ -7504,13 +7514,13 @@ var Indexer = class {
|
|
|
7504
7514
|
issues.set(component, this.createReadIssue(component, message));
|
|
7505
7515
|
this.readerArtifactRetryAfter.set(component, Date.now() + READER_ARTIFACT_RETRY_INTERVAL_MS);
|
|
7506
7516
|
};
|
|
7507
|
-
const storePath =
|
|
7517
|
+
const storePath = path11.join(this.indexPath, "vectors");
|
|
7508
7518
|
const vectorMetadataPath = `${storePath}.meta.json`;
|
|
7509
|
-
const invertedIndexPath =
|
|
7510
|
-
const dbPath =
|
|
7519
|
+
const invertedIndexPath = path11.join(this.indexPath, "inverted-index.json");
|
|
7520
|
+
const dbPath = path11.join(this.indexPath, "codebase.db");
|
|
7511
7521
|
if (vectorsChanged || retryDue("vectors")) {
|
|
7512
|
-
const vectorStoreExists = (0,
|
|
7513
|
-
const vectorMetadataExists = (0,
|
|
7522
|
+
const vectorStoreExists = (0, import_fs7.existsSync)(storePath);
|
|
7523
|
+
const vectorMetadataExists = (0, import_fs7.existsSync)(vectorMetadataPath);
|
|
7514
7524
|
if (vectorStoreExists && vectorMetadataExists) {
|
|
7515
7525
|
try {
|
|
7516
7526
|
const store = new VectorStore(storePath, this.configuredProviderInfo.modelInfo.dimensions);
|
|
@@ -7525,8 +7535,8 @@ var Indexer = class {
|
|
|
7525
7535
|
setIssue("vectors", this.getVectorReadIssueMessage());
|
|
7526
7536
|
}
|
|
7527
7537
|
}
|
|
7528
|
-
if (keywordChanged || retryDue("keyword") || !(0,
|
|
7529
|
-
if ((0,
|
|
7538
|
+
if (keywordChanged || retryDue("keyword") || !(0, import_fs7.existsSync)(invertedIndexPath) && (this.store?.count() ?? 0) > 0) {
|
|
7539
|
+
if ((0, import_fs7.existsSync)(invertedIndexPath)) {
|
|
7530
7540
|
try {
|
|
7531
7541
|
const invertedIndex = new InvertedIndex(invertedIndexPath);
|
|
7532
7542
|
invertedIndex.load();
|
|
@@ -7541,7 +7551,7 @@ var Indexer = class {
|
|
|
7541
7551
|
}
|
|
7542
7552
|
}
|
|
7543
7553
|
if (databaseReplaced || databaseChanged && issues.has("database") || retryDue("database")) {
|
|
7544
|
-
if ((0,
|
|
7554
|
+
if ((0, import_fs7.existsSync)(dbPath)) {
|
|
7545
7555
|
try {
|
|
7546
7556
|
const database = Database.openReadOnly(dbPath);
|
|
7547
7557
|
if (this.database) {
|
|
@@ -7632,14 +7642,14 @@ var Indexer = class {
|
|
|
7632
7642
|
}
|
|
7633
7643
|
}
|
|
7634
7644
|
const dimensions = this.configuredProviderInfo.modelInfo.dimensions;
|
|
7635
|
-
const storePath =
|
|
7645
|
+
const storePath = path11.join(this.indexPath, "vectors");
|
|
7636
7646
|
const vectorMetadataPath = `${storePath}.meta.json`;
|
|
7637
|
-
const invertedIndexPath =
|
|
7638
|
-
const dbPath =
|
|
7639
|
-
let dbIsNew = !(0,
|
|
7647
|
+
const invertedIndexPath = path11.join(this.indexPath, "inverted-index.json");
|
|
7648
|
+
const dbPath = path11.join(this.indexPath, "codebase.db");
|
|
7649
|
+
let dbIsNew = !(0, import_fs7.existsSync)(dbPath);
|
|
7640
7650
|
const readerArtifactFingerprint = mode === "reader" ? this.captureReaderArtifactFingerprint() : null;
|
|
7641
7651
|
if (mode === "writer") {
|
|
7642
|
-
await
|
|
7652
|
+
await import_fs7.promises.mkdir(this.indexPath, { recursive: true });
|
|
7643
7653
|
if (recoveredOwners.length > 0 && this.config.scope === "project" && !this.isLocalProjectIndexPath()) {
|
|
7644
7654
|
throw new Error(
|
|
7645
7655
|
"Interrupted indexing recovery is unsafe while using an inherited worktree index. Run index_codebase with force=true to create a local project index boundary."
|
|
@@ -7655,15 +7665,15 @@ var Indexer = class {
|
|
|
7655
7665
|
await this.resetLocalIndexArtifacts();
|
|
7656
7666
|
}
|
|
7657
7667
|
this.store = new VectorStore(storePath, dimensions);
|
|
7658
|
-
if ((0,
|
|
7668
|
+
if ((0, import_fs7.existsSync)(storePath) || (0, import_fs7.existsSync)(vectorMetadataPath)) {
|
|
7659
7669
|
this.store.load();
|
|
7660
7670
|
}
|
|
7661
7671
|
this.invertedIndex = new InvertedIndex(invertedIndexPath);
|
|
7662
7672
|
try {
|
|
7663
7673
|
this.invertedIndex.load();
|
|
7664
7674
|
} catch {
|
|
7665
|
-
if ((0,
|
|
7666
|
-
await
|
|
7675
|
+
if ((0, import_fs7.existsSync)(invertedIndexPath)) {
|
|
7676
|
+
await import_fs7.promises.unlink(invertedIndexPath);
|
|
7667
7677
|
}
|
|
7668
7678
|
this.invertedIndex = new InvertedIndex(invertedIndexPath);
|
|
7669
7679
|
}
|
|
@@ -7680,8 +7690,8 @@ var Indexer = class {
|
|
|
7680
7690
|
}
|
|
7681
7691
|
} else {
|
|
7682
7692
|
this.store = new VectorStore(storePath, dimensions);
|
|
7683
|
-
const vectorStoreExists = (0,
|
|
7684
|
-
const vectorMetadataExists = (0,
|
|
7693
|
+
const vectorStoreExists = (0, import_fs7.existsSync)(storePath);
|
|
7694
|
+
const vectorMetadataExists = (0, import_fs7.existsSync)(vectorMetadataPath);
|
|
7685
7695
|
const vectorReadFailureMessage = this.getVectorReadIssueMessage();
|
|
7686
7696
|
if (vectorStoreExists !== vectorMetadataExists) {
|
|
7687
7697
|
this.recordReadIssue("vectors", vectorReadFailureMessage);
|
|
@@ -7694,7 +7704,7 @@ var Indexer = class {
|
|
|
7694
7704
|
}
|
|
7695
7705
|
}
|
|
7696
7706
|
this.invertedIndex = new InvertedIndex(invertedIndexPath);
|
|
7697
|
-
if ((0,
|
|
7707
|
+
if ((0, import_fs7.existsSync)(invertedIndexPath)) {
|
|
7698
7708
|
try {
|
|
7699
7709
|
this.invertedIndex.load();
|
|
7700
7710
|
} catch (error) {
|
|
@@ -7708,7 +7718,7 @@ var Indexer = class {
|
|
|
7708
7718
|
} else if (this.store.count() > 0) {
|
|
7709
7719
|
this.recordReadIssue("keyword", this.getKeywordReadIssueMessage());
|
|
7710
7720
|
}
|
|
7711
|
-
if ((0,
|
|
7721
|
+
if ((0, import_fs7.existsSync)(dbPath)) {
|
|
7712
7722
|
try {
|
|
7713
7723
|
this.database = Database.openReadOnly(dbPath);
|
|
7714
7724
|
} catch (error) {
|
|
@@ -7799,7 +7809,7 @@ var Indexer = class {
|
|
|
7799
7809
|
if (await this.tryResetCorruptedIndex("running automatic orphan garbage collection", error)) {
|
|
7800
7810
|
return {
|
|
7801
7811
|
resetCorruptedIndex: true,
|
|
7802
|
-
warning: this.getCorruptedIndexWarning(
|
|
7812
|
+
warning: this.getCorruptedIndexWarning(path11.join(this.indexPath, "codebase.db"))
|
|
7803
7813
|
};
|
|
7804
7814
|
}
|
|
7805
7815
|
throw error;
|
|
@@ -7814,7 +7824,7 @@ var Indexer = class {
|
|
|
7814
7824
|
return;
|
|
7815
7825
|
}
|
|
7816
7826
|
const retainedEntries = store.getAllMetadata().filter(({ key }) => !excludedSet.has(key));
|
|
7817
|
-
const storeBasePath =
|
|
7827
|
+
const storeBasePath = path11.join(this.indexPath, "vectors");
|
|
7818
7828
|
const storeIndexPath = storeBasePath;
|
|
7819
7829
|
const storeMetadataPath = `${storeBasePath}.meta.json`;
|
|
7820
7830
|
const lease = this.requireActiveLease();
|
|
@@ -7824,19 +7834,19 @@ var Indexer = class {
|
|
|
7824
7834
|
let backedUpMetadata = false;
|
|
7825
7835
|
let rebuiltCount = 0;
|
|
7826
7836
|
let skippedCount = 0;
|
|
7827
|
-
if ((0,
|
|
7828
|
-
(0,
|
|
7837
|
+
if ((0, import_fs7.existsSync)(backupIndexPath)) {
|
|
7838
|
+
(0, import_fs7.unlinkSync)(backupIndexPath);
|
|
7829
7839
|
}
|
|
7830
|
-
if ((0,
|
|
7831
|
-
(0,
|
|
7840
|
+
if ((0, import_fs7.existsSync)(backupMetadataPath)) {
|
|
7841
|
+
(0, import_fs7.unlinkSync)(backupMetadataPath);
|
|
7832
7842
|
}
|
|
7833
7843
|
try {
|
|
7834
|
-
if ((0,
|
|
7835
|
-
(0,
|
|
7844
|
+
if ((0, import_fs7.existsSync)(storeIndexPath)) {
|
|
7845
|
+
(0, import_fs7.renameSync)(storeIndexPath, backupIndexPath);
|
|
7836
7846
|
backedUpIndex = true;
|
|
7837
7847
|
}
|
|
7838
|
-
if ((0,
|
|
7839
|
-
(0,
|
|
7848
|
+
if ((0, import_fs7.existsSync)(storeMetadataPath)) {
|
|
7849
|
+
(0, import_fs7.renameSync)(storeMetadataPath, backupMetadataPath);
|
|
7840
7850
|
backedUpMetadata = true;
|
|
7841
7851
|
}
|
|
7842
7852
|
store.clear();
|
|
@@ -7856,11 +7866,11 @@ var Indexer = class {
|
|
|
7856
7866
|
rebuiltCount += 1;
|
|
7857
7867
|
}
|
|
7858
7868
|
store.save();
|
|
7859
|
-
if (backedUpIndex && (0,
|
|
7860
|
-
(0,
|
|
7869
|
+
if (backedUpIndex && (0, import_fs7.existsSync)(backupIndexPath)) {
|
|
7870
|
+
(0, import_fs7.unlinkSync)(backupIndexPath);
|
|
7861
7871
|
}
|
|
7862
|
-
if (backedUpMetadata && (0,
|
|
7863
|
-
(0,
|
|
7872
|
+
if (backedUpMetadata && (0, import_fs7.existsSync)(backupMetadataPath)) {
|
|
7873
|
+
(0, import_fs7.unlinkSync)(backupMetadataPath);
|
|
7864
7874
|
}
|
|
7865
7875
|
this.logger.gc("info", "Rebuilt vector store to avoid native remove", {
|
|
7866
7876
|
excludedChunks: excludedSet.size,
|
|
@@ -7872,17 +7882,17 @@ var Indexer = class {
|
|
|
7872
7882
|
store.clear();
|
|
7873
7883
|
} catch {
|
|
7874
7884
|
}
|
|
7875
|
-
if ((0,
|
|
7876
|
-
(0,
|
|
7885
|
+
if ((0, import_fs7.existsSync)(storeIndexPath)) {
|
|
7886
|
+
(0, import_fs7.unlinkSync)(storeIndexPath);
|
|
7877
7887
|
}
|
|
7878
|
-
if ((0,
|
|
7879
|
-
(0,
|
|
7888
|
+
if ((0, import_fs7.existsSync)(storeMetadataPath)) {
|
|
7889
|
+
(0, import_fs7.unlinkSync)(storeMetadataPath);
|
|
7880
7890
|
}
|
|
7881
|
-
if (backedUpIndex && (0,
|
|
7882
|
-
(0,
|
|
7891
|
+
if (backedUpIndex && (0, import_fs7.existsSync)(backupIndexPath)) {
|
|
7892
|
+
(0, import_fs7.renameSync)(backupIndexPath, storeIndexPath);
|
|
7883
7893
|
}
|
|
7884
|
-
if (backedUpMetadata && (0,
|
|
7885
|
-
(0,
|
|
7894
|
+
if (backedUpMetadata && (0, import_fs7.existsSync)(backupMetadataPath)) {
|
|
7895
|
+
(0, import_fs7.renameSync)(backupMetadataPath, storeMetadataPath);
|
|
7886
7896
|
}
|
|
7887
7897
|
if (backedUpIndex || backedUpMetadata) {
|
|
7888
7898
|
store.load();
|
|
@@ -7909,24 +7919,24 @@ var Indexer = class {
|
|
|
7909
7919
|
this.readerArtifactRetryAfter.clear();
|
|
7910
7920
|
this.fileHashCache.clear();
|
|
7911
7921
|
const resetPaths = [
|
|
7912
|
-
|
|
7913
|
-
|
|
7914
|
-
|
|
7915
|
-
|
|
7916
|
-
|
|
7917
|
-
|
|
7918
|
-
|
|
7919
|
-
|
|
7920
|
-
|
|
7922
|
+
path11.join(this.indexPath, "codebase.db"),
|
|
7923
|
+
path11.join(this.indexPath, "codebase.db-shm"),
|
|
7924
|
+
path11.join(this.indexPath, "codebase.db-wal"),
|
|
7925
|
+
path11.join(this.indexPath, "vectors"),
|
|
7926
|
+
path11.join(this.indexPath, "vectors.usearch"),
|
|
7927
|
+
path11.join(this.indexPath, "vectors.meta.json"),
|
|
7928
|
+
path11.join(this.indexPath, "inverted-index.json"),
|
|
7929
|
+
path11.join(this.indexPath, "file-hashes.json"),
|
|
7930
|
+
path11.join(this.indexPath, "failed-batches.json")
|
|
7921
7931
|
];
|
|
7922
|
-
await Promise.all(resetPaths.map((targetPath) =>
|
|
7923
|
-
await
|
|
7932
|
+
await Promise.all(resetPaths.map((targetPath) => import_fs7.promises.rm(targetPath, { recursive: true, force: true })));
|
|
7933
|
+
await import_fs7.promises.mkdir(this.indexPath, { recursive: true });
|
|
7924
7934
|
}
|
|
7925
7935
|
async tryResetCorruptedIndex(stage, error) {
|
|
7926
7936
|
if (!isSqliteCorruptionError(error)) {
|
|
7927
7937
|
return false;
|
|
7928
7938
|
}
|
|
7929
|
-
const dbPath =
|
|
7939
|
+
const dbPath = path11.join(this.indexPath, "codebase.db");
|
|
7930
7940
|
const warning = this.getCorruptedIndexWarning(dbPath);
|
|
7931
7941
|
const errorMessage = getErrorMessage2(error);
|
|
7932
7942
|
if (this.config.scope === "global") {
|
|
@@ -7992,6 +8002,7 @@ var Indexer = class {
|
|
|
7992
8002
|
this.database.setMetadata("index.embeddingProvider", provider.provider);
|
|
7993
8003
|
this.database.setMetadata("index.embeddingModel", provider.modelInfo.model);
|
|
7994
8004
|
this.database.setMetadata("index.embeddingDimensions", provider.modelInfo.dimensions.toString());
|
|
8005
|
+
this.database.setMetadata(this.getCallGraphResolutionMetadataKey(), CALL_GRAPH_RESOLUTION_VERSION);
|
|
7995
8006
|
if (this.config.scope === "global") {
|
|
7996
8007
|
if (completeProjectEmbeddingStrategyReset) {
|
|
7997
8008
|
this.database.setMetadata(this.getProjectEmbeddingStrategyMetadataKey(), EMBEDDING_STRATEGY_VERSION);
|
|
@@ -8179,6 +8190,20 @@ var Indexer = class {
|
|
|
8179
8190
|
totalChunks: 0
|
|
8180
8191
|
});
|
|
8181
8192
|
this.loadFileHashCache();
|
|
8193
|
+
const swiftParserMetadataKey = this.getSwiftParserVersionMetadataKey();
|
|
8194
|
+
const reparseCachedSwiftFiles = database.getMetadata(swiftParserMetadataKey) !== SWIFT_PARSER_VERSION;
|
|
8195
|
+
const metalParserMetadataKey = this.getMetalParserVersionMetadataKey();
|
|
8196
|
+
const reparseCachedMetalFiles = database.getMetadata(metalParserMetadataKey) !== METAL_PARSER_VERSION;
|
|
8197
|
+
if (reparseCachedSwiftFiles && Array.from(this.fileHashCache.keys()).some(
|
|
8198
|
+
(filePath) => path11.extname(filePath).toLowerCase() === ".swift"
|
|
8199
|
+
)) {
|
|
8200
|
+
this.logger.info("Reindexing cached Swift files for parser support");
|
|
8201
|
+
}
|
|
8202
|
+
if (reparseCachedMetalFiles && Array.from(this.fileHashCache.keys()).some(
|
|
8203
|
+
(filePath) => path11.extname(filePath).toLowerCase() === ".metal"
|
|
8204
|
+
)) {
|
|
8205
|
+
this.logger.info("Reindexing cached Metal files for parser support");
|
|
8206
|
+
}
|
|
8182
8207
|
const includePatterns = [...this.config.include, ...this.config.additionalInclude];
|
|
8183
8208
|
const { files, skipped } = await collectFiles(
|
|
8184
8209
|
this.projectRoot,
|
|
@@ -8198,14 +8223,21 @@ var Indexer = class {
|
|
|
8198
8223
|
const changedFiles = [];
|
|
8199
8224
|
const unchangedFilePaths = /* @__PURE__ */ new Set();
|
|
8200
8225
|
const currentFileHashes = /* @__PURE__ */ new Map();
|
|
8226
|
+
const needsCallGraphResolutionMigration = database.getMetadata(this.getCallGraphResolutionMetadataKey()) !== CALL_GRAPH_RESOLUTION_VERSION;
|
|
8201
8227
|
for (const f of files) {
|
|
8202
8228
|
const currentHash = hashFile(f.path);
|
|
8203
8229
|
currentFileHashes.set(f.path, currentHash);
|
|
8204
|
-
|
|
8230
|
+
const cachedHashMatches = this.fileHashCache.get(f.path) === currentHash;
|
|
8231
|
+
const needsCallGraphRefresh = cachedHashMatches && needsCallGraphResolutionMigration && database.getChunksByFile(f.path).some(
|
|
8232
|
+
(chunk) => chunk.language === "php" || chunk.language === "c" || chunk.language === "cpp"
|
|
8233
|
+
);
|
|
8234
|
+
const requiresSwiftParserUpgrade = reparseCachedSwiftFiles && path11.extname(f.path).toLowerCase() === ".swift";
|
|
8235
|
+
const requiresMetalParserUpgrade = reparseCachedMetalFiles && path11.extname(f.path).toLowerCase() === ".metal";
|
|
8236
|
+
if (cachedHashMatches && !needsCallGraphRefresh && !requiresSwiftParserUpgrade && !requiresMetalParserUpgrade) {
|
|
8205
8237
|
unchangedFilePaths.add(f.path);
|
|
8206
8238
|
this.logger.recordCacheHit();
|
|
8207
8239
|
} else {
|
|
8208
|
-
const content = await
|
|
8240
|
+
const content = await import_fs7.promises.readFile(f.path, "utf-8");
|
|
8209
8241
|
changedFiles.push({ path: f.path, content, hash: currentHash });
|
|
8210
8242
|
this.logger.recordCacheMiss();
|
|
8211
8243
|
}
|
|
@@ -8303,7 +8335,7 @@ var Indexer = class {
|
|
|
8303
8335
|
for (const parsed of parsedFiles) {
|
|
8304
8336
|
currentFilePaths.add(parsed.path);
|
|
8305
8337
|
if (parsed.chunks.length === 0) {
|
|
8306
|
-
const relativePath =
|
|
8338
|
+
const relativePath = path11.relative(this.projectRoot, parsed.path);
|
|
8307
8339
|
stats.parseFailures.push(relativePath);
|
|
8308
8340
|
}
|
|
8309
8341
|
let chunksToProcess = parsed.chunks;
|
|
@@ -8403,16 +8435,28 @@ var Indexer = class {
|
|
|
8403
8435
|
const fileSymbols = [];
|
|
8404
8436
|
for (const chunk of parsed.chunks) {
|
|
8405
8437
|
if (!chunk.name || !CALL_GRAPH_SYMBOL_CHUNK_TYPES.has(chunk.chunkType)) continue;
|
|
8406
|
-
const
|
|
8438
|
+
const existingMetalSymbol = chunk.language === "metal" ? fileSymbols.find(
|
|
8439
|
+
(symbol2) => symbol2.name === chunk.name && symbol2.kind === chunk.chunkType && symbol2.startLine <= chunk.endLine && chunk.startLine <= symbol2.endLine
|
|
8440
|
+
) : void 0;
|
|
8441
|
+
if (existingMetalSymbol) {
|
|
8442
|
+
existingMetalSymbol.startLine = Math.min(existingMetalSymbol.startLine, chunk.startLine);
|
|
8443
|
+
existingMetalSymbol.endLine = Math.max(existingMetalSymbol.endLine, chunk.endLine);
|
|
8444
|
+
existingMetalSymbol.startCol = Math.min(existingMetalSymbol.startCol, chunk.startCol ?? 0);
|
|
8445
|
+
existingMetalSymbol.endCol = Math.max(existingMetalSymbol.endCol, chunk.endCol ?? 0);
|
|
8446
|
+
continue;
|
|
8447
|
+
}
|
|
8448
|
+
const symbolId = `sym_${hashContent(
|
|
8449
|
+
parsed.path + ":" + chunk.name + ":" + chunk.chunkType + ":" + chunk.startLine + ":" + (chunk.startCol ?? 0)
|
|
8450
|
+
).slice(0, 16)}`;
|
|
8407
8451
|
const symbol = {
|
|
8408
8452
|
id: symbolId,
|
|
8409
8453
|
filePath: parsed.path,
|
|
8410
8454
|
name: chunk.name,
|
|
8411
8455
|
kind: chunk.chunkType,
|
|
8412
8456
|
startLine: chunk.startLine,
|
|
8413
|
-
startCol: 0,
|
|
8457
|
+
startCol: chunk.startCol ?? 0,
|
|
8414
8458
|
endLine: chunk.endLine,
|
|
8415
|
-
endCol: 0,
|
|
8459
|
+
endCol: chunk.endCol ?? 0,
|
|
8416
8460
|
language: chunk.language
|
|
8417
8461
|
};
|
|
8418
8462
|
fileSymbols.push(symbol);
|
|
@@ -8437,8 +8481,10 @@ var Indexer = class {
|
|
|
8437
8481
|
if (callSites.length === 0) continue;
|
|
8438
8482
|
const edges = [];
|
|
8439
8483
|
for (const site of callSites) {
|
|
8440
|
-
const enclosingSymbol =
|
|
8441
|
-
|
|
8484
|
+
const enclosingSymbol = findEnclosingSymbol(
|
|
8485
|
+
fileSymbols,
|
|
8486
|
+
site.line,
|
|
8487
|
+
site.column
|
|
8442
8488
|
);
|
|
8443
8489
|
if (!enclosingSymbol) continue;
|
|
8444
8490
|
const edgeId = `edge_${hashContent(enclosingSymbol.id + ":" + site.calleeName + ":" + site.line + ":" + site.column).slice(0, 16)}`;
|
|
@@ -8457,7 +8503,21 @@ var Indexer = class {
|
|
|
8457
8503
|
if (edges.length > 0) {
|
|
8458
8504
|
database.upsertCallEdgesBatch(edges);
|
|
8459
8505
|
for (const edge of edges) {
|
|
8460
|
-
|
|
8506
|
+
let candidates = symbolsByName.get(normalizeSymbolKey(edge.targetName));
|
|
8507
|
+
if (fileLanguage === "php" && candidates) {
|
|
8508
|
+
if (edge.callType === "Constructor") {
|
|
8509
|
+
candidates = candidates.filter(
|
|
8510
|
+
(candidate) => PHP_CLASS_SYMBOL_CHUNK_TYPES.has(candidate.kind)
|
|
8511
|
+
);
|
|
8512
|
+
} else if (edge.callType === "Call") {
|
|
8513
|
+
candidates = candidates.filter(
|
|
8514
|
+
(candidate) => PHP_FUNCTION_SYMBOL_CHUNK_TYPES.has(candidate.kind)
|
|
8515
|
+
);
|
|
8516
|
+
}
|
|
8517
|
+
}
|
|
8518
|
+
candidates = candidates?.filter(
|
|
8519
|
+
(symbol) => isCompatibleCFamilyCallTarget(fileLanguage, edge.callType, symbol.kind)
|
|
8520
|
+
);
|
|
8461
8521
|
if (candidates && candidates.length === 1) {
|
|
8462
8522
|
database.resolveCallEdge(edge.id, candidates[0].id);
|
|
8463
8523
|
}
|
|
@@ -8499,8 +8559,8 @@ var Indexer = class {
|
|
|
8499
8559
|
database.addChunksToBranchBatch(branchCatalogKey, Array.from(currentChunkIds));
|
|
8500
8560
|
database.clearBranchSymbols(branchCatalogKey);
|
|
8501
8561
|
database.addSymbolsToBranchBatch(branchCatalogKey, Array.from(allSymbolIds));
|
|
8502
|
-
const vectorPath =
|
|
8503
|
-
const shouldFingerprintLegacyPair = !store.hasFingerprint() && (0,
|
|
8562
|
+
const vectorPath = path11.join(this.indexPath, "vectors");
|
|
8563
|
+
const shouldFingerprintLegacyPair = !store.hasFingerprint() && (0, import_fs7.existsSync)(vectorPath) && (0, import_fs7.existsSync)(`${vectorPath}.meta.json`);
|
|
8504
8564
|
if (backfilledBlameMetadata || shouldFingerprintLegacyPair) {
|
|
8505
8565
|
store.save();
|
|
8506
8566
|
}
|
|
@@ -8512,6 +8572,8 @@ var Indexer = class {
|
|
|
8512
8572
|
this.saveFileHashCache();
|
|
8513
8573
|
this.saveFailedBatches([]);
|
|
8514
8574
|
}
|
|
8575
|
+
database.setMetadata(swiftParserMetadataKey, SWIFT_PARSER_VERSION);
|
|
8576
|
+
database.setMetadata(metalParserMetadataKey, METAL_PARSER_VERSION);
|
|
8515
8577
|
this.saveIndexMetadata(configuredProviderInfo);
|
|
8516
8578
|
this.indexCompatibility = { compatible: true };
|
|
8517
8579
|
stats.durationMs = Date.now() - startTime;
|
|
@@ -8539,6 +8601,8 @@ var Indexer = class {
|
|
|
8539
8601
|
this.saveFileHashCache();
|
|
8540
8602
|
this.saveFailedBatches([]);
|
|
8541
8603
|
}
|
|
8604
|
+
database.setMetadata(swiftParserMetadataKey, SWIFT_PARSER_VERSION);
|
|
8605
|
+
database.setMetadata(metalParserMetadataKey, METAL_PARSER_VERSION);
|
|
8542
8606
|
this.saveIndexMetadata(configuredProviderInfo);
|
|
8543
8607
|
this.indexCompatibility = { compatible: true };
|
|
8544
8608
|
stats.durationMs = Date.now() - startTime;
|
|
@@ -8809,6 +8873,8 @@ var Indexer = class {
|
|
|
8809
8873
|
if (forceScopedReembed && failedForcedChunkIds.size === 0) {
|
|
8810
8874
|
database.deleteMetadata(this.getProjectForceReembedMetadataKey());
|
|
8811
8875
|
}
|
|
8876
|
+
database.setMetadata(swiftParserMetadataKey, SWIFT_PARSER_VERSION);
|
|
8877
|
+
database.setMetadata(metalParserMetadataKey, METAL_PARSER_VERSION);
|
|
8812
8878
|
this.saveIndexMetadata(configuredProviderInfo);
|
|
8813
8879
|
this.indexCompatibility = { compatible: true };
|
|
8814
8880
|
this.logger.recordIndexingEnd();
|
|
@@ -9055,7 +9121,7 @@ var Indexer = class {
|
|
|
9055
9121
|
let contextEndLine = r.metadata.endLine;
|
|
9056
9122
|
if (!metadataOnly && this.config.search.includeContext) {
|
|
9057
9123
|
try {
|
|
9058
|
-
const fileContent = await
|
|
9124
|
+
const fileContent = await import_fs7.promises.readFile(
|
|
9059
9125
|
r.metadata.filePath,
|
|
9060
9126
|
"utf-8"
|
|
9061
9127
|
);
|
|
@@ -9242,7 +9308,7 @@ var Indexer = class {
|
|
|
9242
9308
|
const removedChunkKeys = [];
|
|
9243
9309
|
const chunkKeysByRemovedFile = /* @__PURE__ */ new Map();
|
|
9244
9310
|
for (const [filePath, chunkKeys] of filePathsToChunkKeys) {
|
|
9245
|
-
if (!(0,
|
|
9311
|
+
if (!(0, import_fs7.existsSync)(filePath)) {
|
|
9246
9312
|
chunkKeysByRemovedFile.set(filePath, chunkKeys);
|
|
9247
9313
|
for (const key of chunkKeys) {
|
|
9248
9314
|
removedChunkKeys.push(key);
|
|
@@ -9291,7 +9357,7 @@ var Indexer = class {
|
|
|
9291
9357
|
gcOrphanSymbols: 0,
|
|
9292
9358
|
gcOrphanCallEdges: 0,
|
|
9293
9359
|
resetCorruptedIndex: true,
|
|
9294
|
-
warning: this.getCorruptedIndexWarning(
|
|
9360
|
+
warning: this.getCorruptedIndexWarning(path11.join(this.indexPath, "codebase.db"))
|
|
9295
9361
|
};
|
|
9296
9362
|
}
|
|
9297
9363
|
this.logger.recordGc(removedCount, gcOrphanChunks, gcOrphanEmbeddings);
|
|
@@ -9601,7 +9667,7 @@ var Indexer = class {
|
|
|
9601
9667
|
let content = "";
|
|
9602
9668
|
if (this.config.search.includeContext) {
|
|
9603
9669
|
try {
|
|
9604
|
-
const fileContent = await
|
|
9670
|
+
const fileContent = await import_fs7.promises.readFile(
|
|
9605
9671
|
r.metadata.filePath,
|
|
9606
9672
|
"utf-8"
|
|
9607
9673
|
);
|
|
@@ -9721,7 +9787,7 @@ var Indexer = class {
|
|
|
9721
9787
|
"Run index_codebase first to build the call graph and symbol index for this branch."
|
|
9722
9788
|
);
|
|
9723
9789
|
}
|
|
9724
|
-
const absoluteChangedFiles = changedFiles.map((f) =>
|
|
9790
|
+
const absoluteChangedFiles = changedFiles.map((f) => path11.resolve(this.projectRoot, f));
|
|
9725
9791
|
const directSymbols = database.getSymbolsForFiles(absoluteChangedFiles, branchKey);
|
|
9726
9792
|
const directIds = directSymbols.map((s) => s.id);
|
|
9727
9793
|
const direction = opts.direction ?? "both";
|
|
@@ -9804,7 +9870,7 @@ var Indexer = class {
|
|
|
9804
9870
|
projectRoot: this.projectRoot,
|
|
9805
9871
|
baseBranch: this.baseBranch
|
|
9806
9872
|
});
|
|
9807
|
-
const otherAbsolute = otherChanged.files.map((f) =>
|
|
9873
|
+
const otherAbsolute = otherChanged.files.map((f) => path11.resolve(this.projectRoot, f));
|
|
9808
9874
|
const otherBranchKey = this.getBranchCatalogKeyFor(openPr.headRefName);
|
|
9809
9875
|
const otherSymbols = database.getSymbolsForFiles(otherAbsolute, otherBranchKey);
|
|
9810
9876
|
const otherLabels = /* @__PURE__ */ new Set();
|
|
@@ -9868,12 +9934,12 @@ var Indexer = class {
|
|
|
9868
9934
|
if (meta.filePath) filePaths.add(meta.filePath);
|
|
9869
9935
|
}
|
|
9870
9936
|
const directory = options?.directory?.replace(/\/$/, "");
|
|
9871
|
-
const absoluteDirectoryFilter = directory ?
|
|
9937
|
+
const absoluteDirectoryFilter = directory ? path11.resolve(this.projectRoot, directory) : void 0;
|
|
9872
9938
|
for (const filePath of filePaths) {
|
|
9873
9939
|
if (directory) {
|
|
9874
|
-
const absoluteFilePath =
|
|
9940
|
+
const absoluteFilePath = path11.resolve(filePath);
|
|
9875
9941
|
const matchesRelative = filePath === directory || filePath.startsWith(directory + "/");
|
|
9876
|
-
const matchesProjectRelative = absoluteDirectoryFilter !== void 0 && (absoluteFilePath === absoluteDirectoryFilter || absoluteFilePath.startsWith(absoluteDirectoryFilter +
|
|
9942
|
+
const matchesProjectRelative = absoluteDirectoryFilter !== void 0 && (absoluteFilePath === absoluteDirectoryFilter || absoluteFilePath.startsWith(absoluteDirectoryFilter + path11.sep));
|
|
9877
9943
|
if (!matchesRelative && !matchesProjectRelative) {
|
|
9878
9944
|
continue;
|
|
9879
9945
|
}
|
|
@@ -9916,43 +9982,43 @@ var Indexer = class {
|
|
|
9916
9982
|
};
|
|
9917
9983
|
|
|
9918
9984
|
// src/tools/knowledge-base-paths.ts
|
|
9919
|
-
var
|
|
9985
|
+
var path12 = __toESM(require("path"), 1);
|
|
9920
9986
|
function resolveConfigPathValue(value, baseDir) {
|
|
9921
9987
|
const trimmed = value.trim();
|
|
9922
9988
|
if (!trimmed) {
|
|
9923
9989
|
return trimmed;
|
|
9924
9990
|
}
|
|
9925
|
-
const absolutePath =
|
|
9926
|
-
return
|
|
9991
|
+
const absolutePath = path12.isAbsolute(trimmed) ? trimmed : path12.resolve(baseDir, trimmed);
|
|
9992
|
+
return path12.normalize(absolutePath);
|
|
9927
9993
|
}
|
|
9928
9994
|
function serializeConfigPathValue(value, baseDir) {
|
|
9929
9995
|
const trimmed = value.trim();
|
|
9930
9996
|
if (!trimmed) {
|
|
9931
9997
|
return trimmed;
|
|
9932
9998
|
}
|
|
9933
|
-
if (!
|
|
9934
|
-
return normalizePathSeparators(
|
|
9999
|
+
if (!path12.isAbsolute(trimmed)) {
|
|
10000
|
+
return normalizePathSeparators(path12.normalize(trimmed));
|
|
9935
10001
|
}
|
|
9936
|
-
const relativePath =
|
|
9937
|
-
if (!relativePath || !relativePath.startsWith("..") && !
|
|
9938
|
-
return normalizePathSeparators(
|
|
10002
|
+
const relativePath = path12.relative(baseDir, trimmed);
|
|
10003
|
+
if (!relativePath || !relativePath.startsWith("..") && !path12.isAbsolute(relativePath)) {
|
|
10004
|
+
return normalizePathSeparators(path12.normalize(relativePath || "."));
|
|
9939
10005
|
}
|
|
9940
|
-
return
|
|
10006
|
+
return path12.normalize(trimmed);
|
|
9941
10007
|
}
|
|
9942
10008
|
function resolveKnowledgeBasePath(value, projectRoot3) {
|
|
9943
|
-
return
|
|
10009
|
+
return path12.isAbsolute(value) ? value : path12.resolve(projectRoot3, value);
|
|
9944
10010
|
}
|
|
9945
|
-
function
|
|
9946
|
-
return
|
|
10011
|
+
function normalizeKnowledgeBasePath(value, projectRoot3) {
|
|
10012
|
+
return path12.normalize(resolveKnowledgeBasePath(value, projectRoot3));
|
|
9947
10013
|
}
|
|
9948
10014
|
function hasMatchingKnowledgeBasePath(knowledgeBases, inputPath, projectRoot3) {
|
|
9949
|
-
const normalizedInput =
|
|
9950
|
-
return knowledgeBases.some((kb) =>
|
|
10015
|
+
const normalizedInput = path12.normalize(inputPath);
|
|
10016
|
+
return knowledgeBases.some((kb) => normalizeKnowledgeBasePath(kb, projectRoot3) === normalizedInput);
|
|
9951
10017
|
}
|
|
9952
10018
|
function findKnowledgeBasePathIndex(knowledgeBases, inputPath, projectRoot3) {
|
|
9953
|
-
const normalizedInput =
|
|
10019
|
+
const normalizedInput = path12.normalize(inputPath);
|
|
9954
10020
|
return knowledgeBases.findIndex(
|
|
9955
|
-
(kb) =>
|
|
10021
|
+
(kb) => path12.normalize(kb) === normalizedInput || normalizeKnowledgeBasePath(kb, projectRoot3) === normalizedInput
|
|
9956
10022
|
);
|
|
9957
10023
|
}
|
|
9958
10024
|
|
|
@@ -10354,6 +10420,193 @@ ${truncateContent(r.content)}
|
|
|
10354
10420
|
// src/tools/config-state.ts
|
|
10355
10421
|
var import_fs9 = require("fs");
|
|
10356
10422
|
var path15 = __toESM(require("path"), 1);
|
|
10423
|
+
|
|
10424
|
+
// src/config/merger.ts
|
|
10425
|
+
var import_fs8 = require("fs");
|
|
10426
|
+
var path14 = __toESM(require("path"), 1);
|
|
10427
|
+
|
|
10428
|
+
// src/config/rebase.ts
|
|
10429
|
+
var path13 = __toESM(require("path"), 1);
|
|
10430
|
+
function isWithinRoot(rootDir, targetPath) {
|
|
10431
|
+
const relativePath = path13.relative(rootDir, targetPath);
|
|
10432
|
+
return relativePath === "" || !relativePath.startsWith("..") && !path13.isAbsolute(relativePath);
|
|
10433
|
+
}
|
|
10434
|
+
function resolveInheritedKnowledgeBaseEntries(values, sourceRoot, targetRoot) {
|
|
10435
|
+
if (!Array.isArray(values)) {
|
|
10436
|
+
return [];
|
|
10437
|
+
}
|
|
10438
|
+
return values.filter((value) => typeof value === "string").map((value) => {
|
|
10439
|
+
const trimmed = value.trim();
|
|
10440
|
+
if (!trimmed) {
|
|
10441
|
+
return trimmed;
|
|
10442
|
+
}
|
|
10443
|
+
if (path13.isAbsolute(trimmed)) {
|
|
10444
|
+
if (isWithinRoot(sourceRoot, trimmed)) {
|
|
10445
|
+
return normalizePathSeparators(path13.normalize(path13.relative(sourceRoot, trimmed) || "."));
|
|
10446
|
+
}
|
|
10447
|
+
return path13.normalize(trimmed);
|
|
10448
|
+
}
|
|
10449
|
+
const resolvedFromSource = path13.resolve(sourceRoot, trimmed);
|
|
10450
|
+
if (isWithinRoot(sourceRoot, resolvedFromSource)) {
|
|
10451
|
+
return normalizePathSeparators(path13.normalize(trimmed));
|
|
10452
|
+
}
|
|
10453
|
+
return normalizePathSeparators(path13.normalize(path13.relative(targetRoot, resolvedFromSource)));
|
|
10454
|
+
}).filter(Boolean);
|
|
10455
|
+
}
|
|
10456
|
+
|
|
10457
|
+
// src/config/merger.ts
|
|
10458
|
+
var PROJECT_OVERRIDE_KEYS = [
|
|
10459
|
+
"embeddingProvider",
|
|
10460
|
+
"customProvider",
|
|
10461
|
+
"embeddingModel",
|
|
10462
|
+
"reranker",
|
|
10463
|
+
"include",
|
|
10464
|
+
"exclude",
|
|
10465
|
+
"indexing",
|
|
10466
|
+
"search",
|
|
10467
|
+
"debug",
|
|
10468
|
+
"scope"
|
|
10469
|
+
];
|
|
10470
|
+
var MERGE_ARRAY_KEYS = ["knowledgeBases", "additionalInclude"];
|
|
10471
|
+
function isRecord(value) {
|
|
10472
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
10473
|
+
}
|
|
10474
|
+
function isStringArray2(value) {
|
|
10475
|
+
return Array.isArray(value) && value.every((item) => typeof item === "string");
|
|
10476
|
+
}
|
|
10477
|
+
function applyProjectOverride(merged, normalizedProjectConfig, globalConfig, key) {
|
|
10478
|
+
if (key in normalizedProjectConfig) {
|
|
10479
|
+
merged[key] = normalizedProjectConfig[key];
|
|
10480
|
+
return;
|
|
10481
|
+
}
|
|
10482
|
+
if (key in globalConfig) {
|
|
10483
|
+
merged[key] = globalConfig[key];
|
|
10484
|
+
}
|
|
10485
|
+
}
|
|
10486
|
+
function mergeUniqueStringArray(values) {
|
|
10487
|
+
return [...new Set(values.map((value) => String(value).trim()))];
|
|
10488
|
+
}
|
|
10489
|
+
function normalizeKnowledgeBasePath2(value) {
|
|
10490
|
+
let normalized = path14.normalize(String(value).trim());
|
|
10491
|
+
const root = path14.parse(normalized).root;
|
|
10492
|
+
while (normalized.length > root.length && /[\\/]$/.test(normalized)) {
|
|
10493
|
+
normalized = normalized.slice(0, -1);
|
|
10494
|
+
}
|
|
10495
|
+
return normalized;
|
|
10496
|
+
}
|
|
10497
|
+
function mergeKnowledgeBasePaths(values) {
|
|
10498
|
+
return [...new Set(values.map((value) => normalizeKnowledgeBasePath2(value)).filter((value) => value.length > 0))];
|
|
10499
|
+
}
|
|
10500
|
+
function validateConfigLayerShape(rawConfig, filePath) {
|
|
10501
|
+
if (!isRecord(rawConfig)) {
|
|
10502
|
+
throw new Error(`Config file ${filePath} must contain a JSON object at the root.`);
|
|
10503
|
+
}
|
|
10504
|
+
if (rawConfig.knowledgeBases !== void 0 && !isStringArray2(rawConfig.knowledgeBases)) {
|
|
10505
|
+
throw new Error(`Config file ${filePath} field 'knowledgeBases' must be an array of strings.`);
|
|
10506
|
+
}
|
|
10507
|
+
if (rawConfig.additionalInclude !== void 0 && !isStringArray2(rawConfig.additionalInclude)) {
|
|
10508
|
+
throw new Error(`Config file ${filePath} field 'additionalInclude' must be an array of strings.`);
|
|
10509
|
+
}
|
|
10510
|
+
if (rawConfig.include !== void 0 && !isStringArray2(rawConfig.include)) {
|
|
10511
|
+
throw new Error(`Config file ${filePath} field 'include' must be an array of strings.`);
|
|
10512
|
+
}
|
|
10513
|
+
if (rawConfig.exclude !== void 0 && !isStringArray2(rawConfig.exclude)) {
|
|
10514
|
+
throw new Error(`Config file ${filePath} field 'exclude' must be an array of strings.`);
|
|
10515
|
+
}
|
|
10516
|
+
for (const section of ["customProvider", "indexing", "search", "debug", "reranker"]) {
|
|
10517
|
+
const value = rawConfig[section];
|
|
10518
|
+
if (value !== void 0 && !isRecord(value)) {
|
|
10519
|
+
throw new Error(`Config file ${filePath} field '${section}' must be an object.`);
|
|
10520
|
+
}
|
|
10521
|
+
}
|
|
10522
|
+
return rawConfig;
|
|
10523
|
+
}
|
|
10524
|
+
function loadJsonFile(filePath) {
|
|
10525
|
+
if (!(0, import_fs8.existsSync)(filePath)) {
|
|
10526
|
+
return null;
|
|
10527
|
+
}
|
|
10528
|
+
try {
|
|
10529
|
+
const content = (0, import_fs8.readFileSync)(filePath, "utf-8");
|
|
10530
|
+
return validateConfigLayerShape(JSON.parse(content), filePath);
|
|
10531
|
+
} catch (error) {
|
|
10532
|
+
if (error instanceof Error && error.message.startsWith("Config file ")) {
|
|
10533
|
+
throw error;
|
|
10534
|
+
}
|
|
10535
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
10536
|
+
throw new Error(`Failed to load config file ${filePath}: ${message}`);
|
|
10537
|
+
}
|
|
10538
|
+
}
|
|
10539
|
+
function loadProjectConfigLayer(projectRoot3, host = "opencode") {
|
|
10540
|
+
const projectConfigPath = resolveProjectConfigPath(projectRoot3, host);
|
|
10541
|
+
const projectConfig = loadJsonFile(projectConfigPath);
|
|
10542
|
+
if (!projectConfig) {
|
|
10543
|
+
return {};
|
|
10544
|
+
}
|
|
10545
|
+
const normalizedConfig = { ...projectConfig };
|
|
10546
|
+
const projectConfigBaseDir = path14.dirname(path14.dirname(projectConfigPath));
|
|
10547
|
+
if (Array.isArray(normalizedConfig.knowledgeBases)) {
|
|
10548
|
+
normalizedConfig.knowledgeBases = resolveInheritedKnowledgeBaseEntries(
|
|
10549
|
+
normalizedConfig.knowledgeBases,
|
|
10550
|
+
projectConfigBaseDir,
|
|
10551
|
+
projectRoot3
|
|
10552
|
+
);
|
|
10553
|
+
}
|
|
10554
|
+
return normalizedConfig;
|
|
10555
|
+
}
|
|
10556
|
+
function loadMergedConfig(projectRoot3, host = "opencode") {
|
|
10557
|
+
const globalConfigPath = resolveGlobalConfigPath(host);
|
|
10558
|
+
const projectConfigPath = resolveProjectConfigPath(projectRoot3, host);
|
|
10559
|
+
let globalConfig = null;
|
|
10560
|
+
let globalConfigError = null;
|
|
10561
|
+
try {
|
|
10562
|
+
globalConfig = loadJsonFile(globalConfigPath);
|
|
10563
|
+
} catch (error) {
|
|
10564
|
+
globalConfigError = error instanceof Error ? error : new Error(String(error));
|
|
10565
|
+
}
|
|
10566
|
+
const projectConfig = loadJsonFile(projectConfigPath);
|
|
10567
|
+
const normalizedProjectConfig = loadProjectConfigLayer(projectRoot3, host);
|
|
10568
|
+
if (globalConfigError) {
|
|
10569
|
+
if (!projectConfig) {
|
|
10570
|
+
throw globalConfigError;
|
|
10571
|
+
}
|
|
10572
|
+
globalConfig = null;
|
|
10573
|
+
}
|
|
10574
|
+
if (!globalConfig && !projectConfig) {
|
|
10575
|
+
return {};
|
|
10576
|
+
}
|
|
10577
|
+
if (!projectConfig && globalConfig) {
|
|
10578
|
+
return globalConfig;
|
|
10579
|
+
}
|
|
10580
|
+
if (!globalConfig && projectConfig) {
|
|
10581
|
+
return normalizedProjectConfig;
|
|
10582
|
+
}
|
|
10583
|
+
if (!globalConfig || !projectConfig) {
|
|
10584
|
+
return globalConfig ?? normalizedProjectConfig;
|
|
10585
|
+
}
|
|
10586
|
+
const merged = { ...globalConfig };
|
|
10587
|
+
for (const key of PROJECT_OVERRIDE_KEYS) {
|
|
10588
|
+
applyProjectOverride(merged, normalizedProjectConfig, globalConfig, key);
|
|
10589
|
+
}
|
|
10590
|
+
if (projectConfig) {
|
|
10591
|
+
for (const key of Object.keys(projectConfig)) {
|
|
10592
|
+
if (PROJECT_OVERRIDE_KEYS.includes(key) || MERGE_ARRAY_KEYS.includes(key)) {
|
|
10593
|
+
continue;
|
|
10594
|
+
}
|
|
10595
|
+
merged[key] = normalizedProjectConfig[key];
|
|
10596
|
+
}
|
|
10597
|
+
}
|
|
10598
|
+
const globalKbs = globalConfig && Array.isArray(globalConfig.knowledgeBases) ? globalConfig.knowledgeBases : [];
|
|
10599
|
+
const projectKbs = projectConfig ? Array.isArray(normalizedProjectConfig.knowledgeBases) ? normalizedProjectConfig.knowledgeBases : [] : [];
|
|
10600
|
+
const allKbs = [...globalKbs, ...projectKbs];
|
|
10601
|
+
merged.knowledgeBases = mergeKnowledgeBasePaths(allKbs);
|
|
10602
|
+
const globalAdditional = globalConfig && Array.isArray(globalConfig.additionalInclude) ? globalConfig.additionalInclude : [];
|
|
10603
|
+
const projectAdditional = projectConfig && Array.isArray(projectConfig.additionalInclude) ? projectConfig.additionalInclude : [];
|
|
10604
|
+
const allAdditional = [...globalAdditional, ...projectAdditional];
|
|
10605
|
+
merged.additionalInclude = mergeUniqueStringArray(allAdditional);
|
|
10606
|
+
return merged;
|
|
10607
|
+
}
|
|
10608
|
+
|
|
10609
|
+
// src/tools/config-state.ts
|
|
10357
10610
|
function normalizeKnowledgeBasePaths(config, projectRoot3) {
|
|
10358
10611
|
const normalized = { ...config };
|
|
10359
10612
|
if (Array.isArray(normalized.knowledgeBases)) {
|
|
@@ -10451,15 +10704,6 @@ function refreshIndexerForDirectory(projectRoot3, host = "opencode", config = pa
|
|
|
10451
10704
|
indexerCache.set(key, indexer);
|
|
10452
10705
|
configCache.set(key, config);
|
|
10453
10706
|
}
|
|
10454
|
-
function shouldForceLocalizeProjectIndex(projectRoot3, host = "opencode") {
|
|
10455
|
-
const root = getProjectRoot(projectRoot3, host);
|
|
10456
|
-
const localIndexPath = path16.join(root, getHostProjectIndexRelativePath(host));
|
|
10457
|
-
if ((0, import_fs10.existsSync)(localIndexPath)) {
|
|
10458
|
-
return false;
|
|
10459
|
-
}
|
|
10460
|
-
const inheritedIndexPath = resolveWorktreeFallbackProjectIndexPath(root, host);
|
|
10461
|
-
return inheritedIndexPath !== null;
|
|
10462
|
-
}
|
|
10463
10707
|
async function searchCodebase(projectRoot3, host, query, options = {}) {
|
|
10464
10708
|
const indexer = getIndexerForProject(projectRoot3, host);
|
|
10465
10709
|
return indexer.search(query, options.limit, {
|
|
@@ -10509,9 +10753,7 @@ async function getCallGraphPath(projectRoot3, host, from, to, maxDepth) {
|
|
|
10509
10753
|
}
|
|
10510
10754
|
async function runIndexCodebase(projectRoot3, host, args, onProgress) {
|
|
10511
10755
|
const root = getProjectRoot(projectRoot3, host);
|
|
10512
|
-
const
|
|
10513
|
-
let indexer = getIndexerForProject(root, host);
|
|
10514
|
-
const runtimeConfig = configCache.get(key);
|
|
10756
|
+
const indexer = getIndexerForProject(root, host);
|
|
10515
10757
|
try {
|
|
10516
10758
|
if (args.estimateOnly) {
|
|
10517
10759
|
return { kind: "estimate", estimate: await indexer.estimateCost() };
|
|
@@ -10532,19 +10774,7 @@ async function runIndexCodebase(projectRoot3, host, args, onProgress) {
|
|
|
10532
10774
|
return Promise.resolve();
|
|
10533
10775
|
});
|
|
10534
10776
|
};
|
|
10535
|
-
|
|
10536
|
-
if (args.force && shouldForceLocalizeProjectIndex(root, host)) {
|
|
10537
|
-
const inheritedIndexPath = resolveProjectIndexPath(root, runtimeConfig.scope, host);
|
|
10538
|
-
stats = await withIndexLock(inheritedIndexPath, "force-index", async () => {
|
|
10539
|
-
materializeLocalProjectConfig(root, loadProjectConfigLayer(root, host), host);
|
|
10540
|
-
refreshIndexerForDirectory(root, host, runtimeConfig);
|
|
10541
|
-
indexer = getIndexerForProject(root, host);
|
|
10542
|
-
return runIndex(indexer);
|
|
10543
|
-
}, { completeRecoveries: false });
|
|
10544
|
-
} else {
|
|
10545
|
-
stats = await runIndex(indexer);
|
|
10546
|
-
}
|
|
10547
|
-
return { kind: "stats", stats };
|
|
10777
|
+
return { kind: "stats", stats: await runIndex(indexer) };
|
|
10548
10778
|
} catch (error) {
|
|
10549
10779
|
const busyResult = getIndexBusyResult(error);
|
|
10550
10780
|
if (!busyResult) throw error;
|