@wrongstack/tools 0.296.3 → 0.296.4
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/dist/builtin.js +1253 -1220
- package/dist/builtin.js.map +4 -4
- package/dist/codebase-index/background-indexer.d.ts.map +1 -1
- package/dist/codebase-index/index.d.ts +1 -0
- package/dist/codebase-index/index.d.ts.map +1 -1
- package/dist/codebase-index/index.js +1233 -1197
- package/dist/codebase-index/index.js.map +4 -4
- package/dist/codebase-index/project-server-client.d.ts +13 -1
- package/dist/codebase-index/project-server-client.d.ts.map +1 -1
- package/dist/codebase-index/project-server-endpoint.d.ts +29 -1
- package/dist/codebase-index/project-server-endpoint.d.ts.map +1 -1
- package/dist/codebase-index/project-server.js +4 -5
- package/dist/codebase-index/project-server.js.map +2 -2
- package/dist/codebase-index/refs-extractor.d.ts.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1220 -1184
- package/dist/index.js.map +4 -4
- package/dist/pack.js +1253 -1220
- package/dist/pack.js.map +4 -4
- package/dist/read.js +40 -9
- package/dist/read.js.map +2 -2
- package/dist/tool-tier.js +1253 -1220
- package/dist/tool-tier.js.map +4 -4
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -4896,16 +4896,16 @@ var init_legacy_bridge = __esm({
|
|
|
4896
4896
|
});
|
|
4897
4897
|
|
|
4898
4898
|
// src/codebase-index/languages.ts
|
|
4899
|
-
import * as
|
|
4899
|
+
import * as path18 from "node:path";
|
|
4900
4900
|
function detectLang(file) {
|
|
4901
|
-
const base =
|
|
4901
|
+
const base = path18.basename(file);
|
|
4902
4902
|
const lowerBase = base.toLowerCase();
|
|
4903
4903
|
if (lowerBase.endsWith(".d.ts") || lowerBase.endsWith(".d.mts") || lowerBase.endsWith(".d.cts")) {
|
|
4904
4904
|
return "ts";
|
|
4905
4905
|
}
|
|
4906
4906
|
const special = SPECIAL_FILENAMES[lowerBase];
|
|
4907
4907
|
if (special) return special;
|
|
4908
|
-
const ext =
|
|
4908
|
+
const ext = path18.extname(base).toLowerCase();
|
|
4909
4909
|
if (!ext) return null;
|
|
4910
4910
|
return EXT_TO_LANG[ext] ?? null;
|
|
4911
4911
|
}
|
|
@@ -5244,10 +5244,10 @@ __export(go_parser_exports, {
|
|
|
5244
5244
|
detectLang: () => detectLang,
|
|
5245
5245
|
parseSymbols: () => parseSymbols2
|
|
5246
5246
|
});
|
|
5247
|
-
import { spawn as
|
|
5248
|
-
import * as
|
|
5249
|
-
import * as
|
|
5250
|
-
import * as
|
|
5247
|
+
import { spawn as spawn5 } from "node:child_process";
|
|
5248
|
+
import * as os6 from "node:os";
|
|
5249
|
+
import * as path19 from "node:path";
|
|
5250
|
+
import * as fs14 from "node:fs/promises";
|
|
5251
5251
|
async function parseSymbols2(opts) {
|
|
5252
5252
|
const { file, content, lang } = opts;
|
|
5253
5253
|
try {
|
|
@@ -5319,16 +5319,16 @@ async function syncGoParse(filePath, content, lang) {
|
|
|
5319
5319
|
try {
|
|
5320
5320
|
let scriptPath = _cachedGoScriptPath;
|
|
5321
5321
|
if (!scriptPath) {
|
|
5322
|
-
const tmpDir = await
|
|
5323
|
-
scriptPath =
|
|
5324
|
-
await
|
|
5322
|
+
const tmpDir = await fs14.mkdtemp(path19.join(os6.tmpdir(), "ws-go-parse-"));
|
|
5323
|
+
scriptPath = path19.join(tmpDir, "parse.go");
|
|
5324
|
+
await fs14.writeFile(scriptPath, GO_PARSE_SCRIPT, "utf8");
|
|
5325
5325
|
_cachedGoScriptPath = scriptPath;
|
|
5326
5326
|
}
|
|
5327
5327
|
const goBinary = resolveWin32Command("go");
|
|
5328
5328
|
const goResult = await new Promise(
|
|
5329
5329
|
(resolve17, reject) => {
|
|
5330
5330
|
let settled = false;
|
|
5331
|
-
const proc =
|
|
5331
|
+
const proc = spawn5(goBinary, ["run", scriptPath], {
|
|
5332
5332
|
stdio: ["pipe", "pipe", "pipe"],
|
|
5333
5333
|
windowsHide: true
|
|
5334
5334
|
});
|
|
@@ -5931,10 +5931,10 @@ __export(py_parser_exports, {
|
|
|
5931
5931
|
detectLang: () => detectLang,
|
|
5932
5932
|
parseSymbols: () => parseSymbols4
|
|
5933
5933
|
});
|
|
5934
|
-
import { spawn as
|
|
5935
|
-
import * as
|
|
5936
|
-
import * as
|
|
5937
|
-
import * as
|
|
5934
|
+
import { spawn as spawn6 } from "node:child_process";
|
|
5935
|
+
import * as fs15 from "node:fs/promises";
|
|
5936
|
+
import * as os7 from "node:os";
|
|
5937
|
+
import * as path20 from "node:path";
|
|
5938
5938
|
async function parseSymbols4(opts) {
|
|
5939
5939
|
const { file, content, lang } = opts;
|
|
5940
5940
|
try {
|
|
@@ -5956,7 +5956,7 @@ async function resolvePython() {
|
|
|
5956
5956
|
function commandIsAvailable(command) {
|
|
5957
5957
|
return new Promise((resolve17) => {
|
|
5958
5958
|
let settled = false;
|
|
5959
|
-
const proc =
|
|
5959
|
+
const proc = spawn6(command, ["--version"], {
|
|
5960
5960
|
stdio: "ignore",
|
|
5961
5961
|
windowsHide: true
|
|
5962
5962
|
});
|
|
@@ -5978,7 +5978,7 @@ function commandIsAvailable(command) {
|
|
|
5978
5978
|
function spawnPyParser(pyBinary, scriptPath, filePath, content) {
|
|
5979
5979
|
return new Promise((resolve17, reject) => {
|
|
5980
5980
|
let settled = false;
|
|
5981
|
-
const proc =
|
|
5981
|
+
const proc = spawn6(pyBinary, [scriptPath, filePath], {
|
|
5982
5982
|
stdio: ["pipe", "pipe", "pipe"],
|
|
5983
5983
|
windowsHide: true
|
|
5984
5984
|
});
|
|
@@ -6012,10 +6012,10 @@ function spawnPyParser(pyBinary, scriptPath, filePath, content) {
|
|
|
6012
6012
|
async function syncPyParse(filePath, content, lang) {
|
|
6013
6013
|
try {
|
|
6014
6014
|
if (!_cachedScriptPath) {
|
|
6015
|
-
const tmpDir =
|
|
6016
|
-
await
|
|
6017
|
-
_cachedScriptPath =
|
|
6018
|
-
await
|
|
6015
|
+
const tmpDir = path20.join(os7.tmpdir(), "ws-py-parse");
|
|
6016
|
+
await fs15.mkdir(tmpDir, { recursive: true });
|
|
6017
|
+
_cachedScriptPath = path20.join(tmpDir, "parse.py");
|
|
6018
|
+
await fs15.writeFile(_cachedScriptPath, PY_PARSE_SCRIPT, "utf8");
|
|
6019
6019
|
}
|
|
6020
6020
|
cachedPyBinary ??= resolvePython();
|
|
6021
6021
|
const pyBinary = await cachedPyBinary;
|
|
@@ -6269,10 +6269,10 @@ __export(rs_parser_exports, {
|
|
|
6269
6269
|
detectLang: () => detectLang,
|
|
6270
6270
|
parseSymbols: () => parseSymbols5
|
|
6271
6271
|
});
|
|
6272
|
-
import { expectDefined as
|
|
6273
|
-
import { execFile, spawn as
|
|
6274
|
-
import * as
|
|
6275
|
-
import * as
|
|
6272
|
+
import { expectDefined as expectDefined3 } from "@wrongstack/core/utils";
|
|
6273
|
+
import { execFile, spawn as spawn7 } from "node:child_process";
|
|
6274
|
+
import * as fs16 from "node:fs/promises";
|
|
6275
|
+
import * as path21 from "node:path";
|
|
6276
6276
|
async function parseSymbols5(opts) {
|
|
6277
6277
|
const { file, content, lang } = opts;
|
|
6278
6278
|
const nativeAvailable = await checkNativeParser();
|
|
@@ -6294,7 +6294,7 @@ function checkNativeParser() {
|
|
|
6294
6294
|
nativeParserAvailability ??= (async () => {
|
|
6295
6295
|
try {
|
|
6296
6296
|
await probe("rustc", ["--version"]);
|
|
6297
|
-
const toolsDir =
|
|
6297
|
+
const toolsDir = path21.join(process.cwd(), "tools");
|
|
6298
6298
|
await probe(
|
|
6299
6299
|
"cargo",
|
|
6300
6300
|
[
|
|
@@ -6303,7 +6303,7 @@ function checkNativeParser() {
|
|
|
6303
6303
|
"--format-version",
|
|
6304
6304
|
"1",
|
|
6305
6305
|
"--manifest-path",
|
|
6306
|
-
|
|
6306
|
+
path21.join(toolsDir, "Cargo.toml")
|
|
6307
6307
|
]
|
|
6308
6308
|
);
|
|
6309
6309
|
return true;
|
|
@@ -6315,17 +6315,17 @@ function checkNativeParser() {
|
|
|
6315
6315
|
}
|
|
6316
6316
|
async function tryNativeParse(file, content) {
|
|
6317
6317
|
try {
|
|
6318
|
-
const toolsDir =
|
|
6319
|
-
const crateDir =
|
|
6320
|
-
const tmpFile =
|
|
6321
|
-
await
|
|
6318
|
+
const toolsDir = path21.join(process.cwd(), "tools");
|
|
6319
|
+
const crateDir = path21.join(toolsDir, "syn-parser");
|
|
6320
|
+
const tmpFile = path21.join(crateDir, "src", "input.rs");
|
|
6321
|
+
await fs16.writeFile(tmpFile, content, "utf8");
|
|
6322
6322
|
const cargoBinary = resolveWin32Command("cargo");
|
|
6323
6323
|
const result = await new Promise(
|
|
6324
6324
|
(resolve17, reject) => {
|
|
6325
6325
|
let settled = false;
|
|
6326
|
-
const proc =
|
|
6326
|
+
const proc = spawn7(
|
|
6327
6327
|
cargoBinary,
|
|
6328
|
-
["run", "--manifest-path",
|
|
6328
|
+
["run", "--manifest-path", path21.join(toolsDir, "Cargo.toml")],
|
|
6329
6329
|
{
|
|
6330
6330
|
cwd: process.cwd(),
|
|
6331
6331
|
stdio: ["pipe", "pipe", "pipe"],
|
|
@@ -6384,7 +6384,7 @@ function regexParse(opts) {
|
|
|
6384
6384
|
let hi = lineOffsets2.length - 1;
|
|
6385
6385
|
while (lo < hi) {
|
|
6386
6386
|
const mid = lo + hi + 1 >>> 1;
|
|
6387
|
-
if (
|
|
6387
|
+
if (expectDefined3(lineOffsets2[mid]) <= offset) lo = mid;
|
|
6388
6388
|
else hi = mid - 1;
|
|
6389
6389
|
}
|
|
6390
6390
|
return lo + 1;
|
|
@@ -6396,7 +6396,7 @@ function regexParse(opts) {
|
|
|
6396
6396
|
for (const pattern of RS_PATTERNS) {
|
|
6397
6397
|
pattern.regex.lastIndex = 0;
|
|
6398
6398
|
for (let match = pattern.regex.exec(content); match !== null; match = pattern.regex.exec(content)) {
|
|
6399
|
-
const name =
|
|
6399
|
+
const name = expectDefined3(match[1]);
|
|
6400
6400
|
const offset = match.index ?? 0;
|
|
6401
6401
|
const line = lineFromOffset(offset);
|
|
6402
6402
|
const col = offset - (lineOffsets2[line - 1] ?? 0);
|
|
@@ -6453,8 +6453,8 @@ __export(json_parser_exports, {
|
|
|
6453
6453
|
detectLang: () => detectLang,
|
|
6454
6454
|
parseSymbols: () => parseSymbols6
|
|
6455
6455
|
});
|
|
6456
|
-
import { expectDefined as
|
|
6457
|
-
import * as
|
|
6456
|
+
import { expectDefined as expectDefined4 } from "@wrongstack/core/utils";
|
|
6457
|
+
import * as path22 from "node:path";
|
|
6458
6458
|
function parseSymbols6(opts) {
|
|
6459
6459
|
const { file, content, lang } = opts;
|
|
6460
6460
|
try {
|
|
@@ -6466,7 +6466,7 @@ function parseSymbols6(opts) {
|
|
|
6466
6466
|
function regexParse2(opts) {
|
|
6467
6467
|
const { file, content, lang } = opts;
|
|
6468
6468
|
const symbols = [];
|
|
6469
|
-
const basename13 =
|
|
6469
|
+
const basename13 = path22.basename(file).toLowerCase();
|
|
6470
6470
|
const isPackageJson = basename13 === "package.json";
|
|
6471
6471
|
const isTsconfig = basename13 === "tsconfig.json" || basename13 === "tsconfig.build.json";
|
|
6472
6472
|
const isJsonSchema = content.includes("$schema") || content.includes("$id") || content.includes("$ref");
|
|
@@ -6481,22 +6481,22 @@ function regexParse2(opts) {
|
|
|
6481
6481
|
let hi = lineOffsets2.length - 1;
|
|
6482
6482
|
while (lo < hi) {
|
|
6483
6483
|
const mid = lo + hi + 1 >>> 1;
|
|
6484
|
-
if (
|
|
6484
|
+
if (expectDefined4(lineOffsets2[mid]) <= offset) lo = mid;
|
|
6485
6485
|
else hi = mid - 1;
|
|
6486
6486
|
}
|
|
6487
6487
|
return lo + 1;
|
|
6488
6488
|
}
|
|
6489
6489
|
const rootMatch = content.match(/^\s*\{/m);
|
|
6490
6490
|
if (rootMatch) {
|
|
6491
|
-
const offset =
|
|
6491
|
+
const offset = expectDefined4(rootMatch.index);
|
|
6492
6492
|
const line = lineFromOffset(offset);
|
|
6493
6493
|
symbols.push(
|
|
6494
6494
|
makeSymbol({
|
|
6495
|
-
name:
|
|
6495
|
+
name: path22.basename(file),
|
|
6496
6496
|
kind: "object",
|
|
6497
6497
|
line,
|
|
6498
6498
|
col: 0,
|
|
6499
|
-
signature: `"${
|
|
6499
|
+
signature: `"${path22.basename(file)}" = { ... }`,
|
|
6500
6500
|
file,
|
|
6501
6501
|
lang
|
|
6502
6502
|
})
|
|
@@ -6504,7 +6504,7 @@ function regexParse2(opts) {
|
|
|
6504
6504
|
}
|
|
6505
6505
|
const topLevelKeyRegex = /^\s*"([^"]+)"\s*:/gm;
|
|
6506
6506
|
for (let match = topLevelKeyRegex.exec(content); match !== null; match = topLevelKeyRegex.exec(content)) {
|
|
6507
|
-
const key =
|
|
6507
|
+
const key = expectDefined4(match[1]);
|
|
6508
6508
|
const offset = match.index ?? 0;
|
|
6509
6509
|
const line = lineFromOffset(offset);
|
|
6510
6510
|
const col = offset - (lineOffsets2[line - 1] ?? 0);
|
|
@@ -6551,7 +6551,7 @@ function regexParse2(opts) {
|
|
|
6551
6551
|
const defsRegex = /"\$defs"\s*:|"\$defs"\s*:/g;
|
|
6552
6552
|
const defsMatch = defsRegex.exec(content);
|
|
6553
6553
|
if (defsMatch !== null) {
|
|
6554
|
-
const offset =
|
|
6554
|
+
const offset = expectDefined4(defsMatch.index);
|
|
6555
6555
|
const line = lineFromOffset(offset);
|
|
6556
6556
|
symbols.push(
|
|
6557
6557
|
makeSymbol({
|
|
@@ -6576,7 +6576,7 @@ function regexParse2(opts) {
|
|
|
6576
6576
|
for (let match = pat.exec(content); match !== null; match = pat.exec(content)) {
|
|
6577
6577
|
const offset = match.index ?? 0;
|
|
6578
6578
|
const line = lineFromOffset(offset);
|
|
6579
|
-
const key = match[0]?.match(/"([^"]+)"/)?.[1] ??
|
|
6579
|
+
const key = match[0]?.match(/"([^"]+)"/)?.[1] ?? expectDefined4(match[0]);
|
|
6580
6580
|
symbols.push(
|
|
6581
6581
|
makeSymbol({
|
|
6582
6582
|
name: key,
|
|
@@ -6595,12 +6595,12 @@ function regexParse2(opts) {
|
|
|
6595
6595
|
function extractPackageScripts(content, symbols, file, lang, lineOffsets2, lineFromOffset) {
|
|
6596
6596
|
const scriptsBlockRegex = /"scripts"\s*:\s*\{([^}]+)\}/g;
|
|
6597
6597
|
for (let match = scriptsBlockRegex.exec(content); match !== null; match = scriptsBlockRegex.exec(content)) {
|
|
6598
|
-
const blockContent =
|
|
6598
|
+
const blockContent = expectDefined4(match[0]);
|
|
6599
6599
|
const blockOffset = match.index ?? 0;
|
|
6600
6600
|
const scriptKeyRegex = /"(\w[\w-]*)"\s*:/g;
|
|
6601
6601
|
for (let scriptMatch = scriptKeyRegex.exec(blockContent); scriptMatch !== null; scriptMatch = scriptKeyRegex.exec(blockContent)) {
|
|
6602
|
-
const key =
|
|
6603
|
-
const keyOffset = blockOffset +
|
|
6602
|
+
const key = expectDefined4(scriptMatch[1]);
|
|
6603
|
+
const keyOffset = blockOffset + expectDefined4(scriptMatch.index);
|
|
6604
6604
|
const line = lineFromOffset(keyOffset);
|
|
6605
6605
|
symbols.push(
|
|
6606
6606
|
makeSymbol({
|
|
@@ -6619,12 +6619,12 @@ function extractPackageScripts(content, symbols, file, lang, lineOffsets2, lineF
|
|
|
6619
6619
|
function extractCompilerOptions(content, symbols, file, lang, lineOffsets2, parentLine, lineFromOffset) {
|
|
6620
6620
|
const optsBlockRegex = /"compilerOptions"\s*:\s*\{([^}]+)\}/g;
|
|
6621
6621
|
for (let match = optsBlockRegex.exec(content); match !== null; match = optsBlockRegex.exec(content)) {
|
|
6622
|
-
const blockContent =
|
|
6622
|
+
const blockContent = expectDefined4(match[0]);
|
|
6623
6623
|
const blockOffset = match.index ?? 0;
|
|
6624
6624
|
const optKeyRegex = /"(\w[\w]*)"\s*:/g;
|
|
6625
6625
|
for (let optMatch = optKeyRegex.exec(blockContent); optMatch !== null; optMatch = optKeyRegex.exec(blockContent)) {
|
|
6626
|
-
const key =
|
|
6627
|
-
const keyOffset = blockOffset +
|
|
6626
|
+
const key = expectDefined4(optMatch[1]);
|
|
6627
|
+
const keyOffset = blockOffset + expectDefined4(optMatch.index);
|
|
6628
6628
|
const line = lineFromOffset(keyOffset);
|
|
6629
6629
|
if (line <= parentLine) continue;
|
|
6630
6630
|
symbols.push(
|
|
@@ -6669,7 +6669,7 @@ __export(yaml_parser_exports, {
|
|
|
6669
6669
|
detectLang: () => detectLang,
|
|
6670
6670
|
parseSymbols: () => parseSymbols7
|
|
6671
6671
|
});
|
|
6672
|
-
import { expectDefined as
|
|
6672
|
+
import { expectDefined as expectDefined5, truncate } from "@wrongstack/core/utils";
|
|
6673
6673
|
function parseSymbols7(opts) {
|
|
6674
6674
|
const { file, content, lang } = opts;
|
|
6675
6675
|
try {
|
|
@@ -6691,14 +6691,14 @@ function regexParse3(opts) {
|
|
|
6691
6691
|
let hi = lineOffsets2.length - 1;
|
|
6692
6692
|
while (lo < hi) {
|
|
6693
6693
|
const mid = lo + hi + 1 >>> 1;
|
|
6694
|
-
if (
|
|
6694
|
+
if (expectDefined5(lineOffsets2[mid]) <= offset) lo = mid;
|
|
6695
6695
|
else hi = mid - 1;
|
|
6696
6696
|
}
|
|
6697
6697
|
return lo + 1;
|
|
6698
6698
|
}
|
|
6699
6699
|
const anchorRegex = /&(\w[\w-]*)/g;
|
|
6700
6700
|
for (let match = anchorRegex.exec(content); match !== null; match = anchorRegex.exec(content)) {
|
|
6701
|
-
const name =
|
|
6701
|
+
const name = expectDefined5(match[1]);
|
|
6702
6702
|
const offset = match.index ?? 0;
|
|
6703
6703
|
const line = lineFromOffset(offset);
|
|
6704
6704
|
const col = offset - (lineOffsets2[line - 1] ?? 0);
|
|
@@ -6716,7 +6716,7 @@ function regexParse3(opts) {
|
|
|
6716
6716
|
}
|
|
6717
6717
|
const aliasRegex = /\*(\w[\w-]*)/g;
|
|
6718
6718
|
for (let match = aliasRegex.exec(content); match !== null; match = aliasRegex.exec(content)) {
|
|
6719
|
-
const name =
|
|
6719
|
+
const name = expectDefined5(match[1]);
|
|
6720
6720
|
const offset = match.index ?? 0;
|
|
6721
6721
|
const line = lineFromOffset(offset);
|
|
6722
6722
|
const col = offset - (lineOffsets2[line - 1] ?? 0);
|
|
@@ -6751,7 +6751,7 @@ function regexParse3(opts) {
|
|
|
6751
6751
|
}
|
|
6752
6752
|
const listItemRegex = /^-(\s+)([^:#\s][^:#\s]*)\s*:/gm;
|
|
6753
6753
|
for (let match = listItemRegex.exec(content); match !== null; match = listItemRegex.exec(content)) {
|
|
6754
|
-
const key =
|
|
6754
|
+
const key = expectDefined5(match[2]);
|
|
6755
6755
|
const offset = match.index ?? 0;
|
|
6756
6756
|
const line = lineFromOffset(offset);
|
|
6757
6757
|
const col = offset - (lineOffsets2[line - 1] ?? 0);
|
|
@@ -6771,7 +6771,7 @@ function regexParse3(opts) {
|
|
|
6771
6771
|
}
|
|
6772
6772
|
const blockScalarRegex = /^(\s*)([^:#\s][^:#\s]*)\s*:\s*[|>](\s|$)/gm;
|
|
6773
6773
|
for (let match = blockScalarRegex.exec(content); match !== null; match = blockScalarRegex.exec(content)) {
|
|
6774
|
-
const key =
|
|
6774
|
+
const key = expectDefined5(match[2]);
|
|
6775
6775
|
const offset = match.index ?? 0;
|
|
6776
6776
|
const line = lineFromOffset(offset);
|
|
6777
6777
|
const col = offset - (lineOffsets2[line - 1] ?? 0);
|
|
@@ -10095,10 +10095,12 @@ async function shutdownBrowserTools() {
|
|
|
10095
10095
|
await Promise.all(active.map((manager) => manager.dispose()));
|
|
10096
10096
|
}
|
|
10097
10097
|
|
|
10098
|
-
// src/codebase-index/
|
|
10099
|
-
import
|
|
10100
|
-
import
|
|
10101
|
-
import
|
|
10098
|
+
// src/codebase-index/project-server-client.ts
|
|
10099
|
+
import { spawn as spawn4 } from "node:child_process";
|
|
10100
|
+
import * as fs12 from "node:fs";
|
|
10101
|
+
import * as net3 from "node:net";
|
|
10102
|
+
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
10103
|
+
import { checkUnixSocketPath } from "@wrongstack/core/utils";
|
|
10102
10104
|
|
|
10103
10105
|
// src/codebase-index/circuit-breaker.ts
|
|
10104
10106
|
var CircuitOpenError = class extends Error {
|
|
@@ -10183,117 +10185,18 @@ function resetIndexCircuitBreaker() {
|
|
|
10183
10185
|
indexCircuitBreaker.reset();
|
|
10184
10186
|
}
|
|
10185
10187
|
|
|
10186
|
-
// src/codebase-index/
|
|
10187
|
-
import {
|
|
10188
|
-
import
|
|
10189
|
-
import * as
|
|
10190
|
-
import
|
|
10191
|
-
import
|
|
10192
|
-
import {
|
|
10193
|
-
DEFAULT_WALK_IGNORE_DIRS,
|
|
10194
|
-
indexParallelBatchSize,
|
|
10195
|
-
isFrugalPerf
|
|
10196
|
-
} from "@wrongstack/core/utils";
|
|
10197
|
-
|
|
10198
|
-
// src/codebase-index/gitignore.ts
|
|
10199
|
-
import * as fs9 from "node:fs/promises";
|
|
10200
|
-
import * as path13 from "node:path";
|
|
10201
|
-
import { compileGlob } from "@wrongstack/core/utils";
|
|
10202
|
-
function globBody(glob) {
|
|
10203
|
-
return compileGlob(glob).source.replace(/^\^/, "").replace(/\$$/, "");
|
|
10204
|
-
}
|
|
10205
|
-
function compileGitignore(lines) {
|
|
10206
|
-
const rules = [];
|
|
10207
|
-
for (const raw of lines) {
|
|
10208
|
-
let line = raw.replace(/\r$/, "");
|
|
10209
|
-
if (!line.trim() || line.trimStart().startsWith("#")) continue;
|
|
10210
|
-
line = line.trim();
|
|
10211
|
-
let negated = false;
|
|
10212
|
-
if (line.startsWith("!")) {
|
|
10213
|
-
negated = true;
|
|
10214
|
-
line = line.slice(1);
|
|
10215
|
-
}
|
|
10216
|
-
let dirOnly = false;
|
|
10217
|
-
if (line.endsWith("/")) {
|
|
10218
|
-
dirOnly = true;
|
|
10219
|
-
line = line.slice(0, -1);
|
|
10220
|
-
}
|
|
10221
|
-
if (!line) continue;
|
|
10222
|
-
const anchored = line.startsWith("/") || line.includes("/");
|
|
10223
|
-
if (line.startsWith("/")) line = line.slice(1);
|
|
10224
|
-
const body = globBody(line);
|
|
10225
|
-
const prefix = anchored ? "^" : "(?:^|.*/)";
|
|
10226
|
-
rules.push({
|
|
10227
|
-
eqOrUnder: new RegExp(`${prefix}${body}(?:/.*)?$`),
|
|
10228
|
-
under: new RegExp(`${prefix}${body}/.*$`),
|
|
10229
|
-
negated,
|
|
10230
|
-
dirOnly
|
|
10231
|
-
});
|
|
10232
|
-
}
|
|
10233
|
-
return (relPath, isDir) => {
|
|
10234
|
-
const p = relPath.replace(/\\/g, "/").replace(/^\/+/, "");
|
|
10235
|
-
let ignored = false;
|
|
10236
|
-
for (const r of rules) {
|
|
10237
|
-
const re = r.dirOnly && !isDir ? r.under : r.eqOrUnder;
|
|
10238
|
-
if (re.test(p)) ignored = !r.negated;
|
|
10239
|
-
}
|
|
10240
|
-
return ignored;
|
|
10241
|
-
};
|
|
10242
|
-
}
|
|
10243
|
-
async function loadGitignoreMatcher(projectRoot) {
|
|
10244
|
-
let lines = [];
|
|
10245
|
-
try {
|
|
10246
|
-
const raw = await fs9.readFile(path13.join(projectRoot, ".gitignore"), "utf8");
|
|
10247
|
-
lines = raw.split("\n");
|
|
10248
|
-
} catch {
|
|
10249
|
-
}
|
|
10250
|
-
return compileGitignore(lines);
|
|
10251
|
-
}
|
|
10252
|
-
|
|
10253
|
-
// src/codebase-index/indexer.ts
|
|
10254
|
-
init_languages2();
|
|
10255
|
-
|
|
10256
|
-
// src/codebase-index/parser-dispatch.ts
|
|
10257
|
-
async function parseFileContent(file, content, lang) {
|
|
10258
|
-
switch (lang) {
|
|
10259
|
-
case "ts":
|
|
10260
|
-
case "tsx":
|
|
10261
|
-
case "js":
|
|
10262
|
-
case "jsx": {
|
|
10263
|
-
const { parseSymbols: parseSymbols8 } = await Promise.resolve().then(() => (init_ts_parser(), ts_parser_exports));
|
|
10264
|
-
return parseSymbols8({ file, content, lang });
|
|
10265
|
-
}
|
|
10266
|
-
case "go": {
|
|
10267
|
-
const { parseSymbols: parseSymbols8 } = await Promise.resolve().then(() => (init_go_parser(), go_parser_exports));
|
|
10268
|
-
return parseSymbols8({ file, content, lang: "go" });
|
|
10269
|
-
}
|
|
10270
|
-
case "py": {
|
|
10271
|
-
const { parseSymbols: parseSymbols8 } = await Promise.resolve().then(() => (init_py_parser(), py_parser_exports));
|
|
10272
|
-
return parseSymbols8({ file, content, lang: "py" });
|
|
10273
|
-
}
|
|
10274
|
-
case "rs": {
|
|
10275
|
-
const { parseSymbols: parseSymbols8 } = await Promise.resolve().then(() => (init_rs_parser(), rs_parser_exports));
|
|
10276
|
-
return parseSymbols8({ file, content, lang: "rs" });
|
|
10277
|
-
}
|
|
10278
|
-
case "json": {
|
|
10279
|
-
const { parseSymbols: parseSymbols8 } = await Promise.resolve().then(() => (init_json_parser(), json_parser_exports));
|
|
10280
|
-
return parseSymbols8({ file, content, lang: "json" });
|
|
10281
|
-
}
|
|
10282
|
-
case "yaml": {
|
|
10283
|
-
const { parseSymbols: parseSymbols8 } = await Promise.resolve().then(() => (init_yaml_parser(), yaml_parser_exports));
|
|
10284
|
-
return parseSymbols8({ file, content, lang: "yaml" });
|
|
10285
|
-
}
|
|
10286
|
-
default: {
|
|
10287
|
-
const { parseSymbols: parseSymbols8 } = await Promise.resolve().then(() => (init_generic_parser(), generic_parser_exports));
|
|
10288
|
-
return parseSymbols8({ file, content, lang });
|
|
10289
|
-
}
|
|
10290
|
-
}
|
|
10291
|
-
}
|
|
10188
|
+
// src/codebase-index/project-server-endpoint.ts
|
|
10189
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
10190
|
+
import * as fs11 from "node:fs";
|
|
10191
|
+
import * as os5 from "node:os";
|
|
10192
|
+
import * as path16 from "node:path";
|
|
10193
|
+
import { fileURLToPath } from "node:url";
|
|
10194
|
+
import { assertUnixSocketPathWithinLimit } from "@wrongstack/core/utils";
|
|
10292
10195
|
|
|
10293
10196
|
// src/codebase-index/writer.ts
|
|
10294
|
-
import { expectDefined as
|
|
10295
|
-
import * as
|
|
10296
|
-
import * as
|
|
10197
|
+
import { expectDefined as expectDefined2 } from "@wrongstack/core/utils";
|
|
10198
|
+
import * as fs10 from "node:fs";
|
|
10199
|
+
import * as path15 from "node:path";
|
|
10297
10200
|
|
|
10298
10201
|
// src/codebase-index/bm25.ts
|
|
10299
10202
|
var K1 = 1.5;
|
|
@@ -10488,8 +10391,8 @@ function runSqliteWithRetry(fn) {
|
|
|
10488
10391
|
}
|
|
10489
10392
|
|
|
10490
10393
|
// src/codebase-index/writer-admin.ts
|
|
10491
|
-
import * as
|
|
10492
|
-
import * as
|
|
10394
|
+
import * as fs9 from "node:fs";
|
|
10395
|
+
import * as path13 from "node:path";
|
|
10493
10396
|
var DB_FILE = "index.db";
|
|
10494
10397
|
function getAllIndexableWithStatement(stmt) {
|
|
10495
10398
|
return stmt("SELECT id, text FROM symbols").all().map(({ id, text }) => ({ id, text }));
|
|
@@ -10548,7 +10451,7 @@ function getAllFileMetasWithStatement(stmt) {
|
|
|
10548
10451
|
}
|
|
10549
10452
|
function getIndexDbSizeBytes(indexDir) {
|
|
10550
10453
|
try {
|
|
10551
|
-
return
|
|
10454
|
+
return fs9.statSync(path13.join(indexDir, DB_FILE)).size;
|
|
10552
10455
|
} catch {
|
|
10553
10456
|
return 0;
|
|
10554
10457
|
}
|
|
@@ -10615,7 +10518,7 @@ function bulkInsertRefsWithStatement(stmt, maxSqlVars, refs) {
|
|
|
10615
10518
|
}
|
|
10616
10519
|
|
|
10617
10520
|
// src/codebase-index/writer-graph-helpers.ts
|
|
10618
|
-
import * as
|
|
10521
|
+
import * as path14 from "node:path";
|
|
10619
10522
|
function derivePackage(filePath) {
|
|
10620
10523
|
const f = filePath.replace(/\\/g, "/");
|
|
10621
10524
|
const pkgsIdx = f.indexOf("/packages/");
|
|
@@ -10730,16 +10633,16 @@ function buildSymbolGraphNodes(symById, relatedIds, fileFilter) {
|
|
|
10730
10633
|
function resolveRelativeImport(fromFile, moduleName, indexedFiles) {
|
|
10731
10634
|
if (!moduleName.startsWith(".")) return void 0;
|
|
10732
10635
|
const normalizedFrom = fromFile.replace(/\\/g, "/");
|
|
10733
|
-
const absolute =
|
|
10734
|
-
|
|
10636
|
+
const absolute = path14.posix.normalize(
|
|
10637
|
+
path14.posix.join(path14.posix.dirname(normalizedFrom), moduleName)
|
|
10735
10638
|
);
|
|
10736
|
-
const extension =
|
|
10639
|
+
const extension = path14.posix.extname(absolute);
|
|
10737
10640
|
const base = extension ? absolute.slice(0, -extension.length) : absolute;
|
|
10738
10641
|
const candidates = [
|
|
10739
10642
|
absolute,
|
|
10740
10643
|
...[".ts", ".tsx", ".js", ".jsx", ".mts", ".cts"].map((ext) => `${base}${ext}`),
|
|
10741
|
-
...[".ts", ".tsx", ".js", ".jsx"].map((ext) =>
|
|
10742
|
-
...[".ts", ".tsx", ".js", ".jsx"].map((ext) =>
|
|
10644
|
+
...[".ts", ".tsx", ".js", ".jsx"].map((ext) => path14.posix.join(absolute, `index${ext}`)),
|
|
10645
|
+
...[".ts", ".tsx", ".js", ".jsx"].map((ext) => path14.posix.join(base, `index${ext}`))
|
|
10743
10646
|
];
|
|
10744
10647
|
const indexedByPortablePath = new Map(
|
|
10745
10648
|
[...indexedFiles].map((file) => [file.replace(/\\/g, "/").toLocaleLowerCase(), file])
|
|
@@ -11255,9 +11158,9 @@ var IndexStore = class _IndexStore {
|
|
|
11255
11158
|
}
|
|
11256
11159
|
constructor(projectRoot, opts = {}) {
|
|
11257
11160
|
this.indexDir = resolveIndexDir(projectRoot, opts.indexDir);
|
|
11258
|
-
|
|
11161
|
+
fs10.mkdirSync(this.indexDir, { recursive: true });
|
|
11259
11162
|
const Database = loadDatabaseSync();
|
|
11260
|
-
this.db = new Database(
|
|
11163
|
+
this.db = new Database(path15.join(this.indexDir, DB_FILE2));
|
|
11261
11164
|
applyIndexStorePragmas(this.db);
|
|
11262
11165
|
this.initSchema();
|
|
11263
11166
|
}
|
|
@@ -11672,13 +11575,13 @@ var IndexStore = class _IndexStore {
|
|
|
11672
11575
|
if (rankDiff !== 0) return rankDiff;
|
|
11673
11576
|
const scoreDiff = b.score - a.score;
|
|
11674
11577
|
if (scoreDiff !== 0) return scoreDiff;
|
|
11675
|
-
const left =
|
|
11676
|
-
const right =
|
|
11578
|
+
const left = expectDefined2(candidateById.get(a.id));
|
|
11579
|
+
const right = expectDefined2(candidateById.get(b.id));
|
|
11677
11580
|
return left.name.localeCompare(right.name) || left.file.localeCompare(right.file) || left.line - right.line || left.col - right.col || left.id - right.id;
|
|
11678
11581
|
});
|
|
11679
11582
|
const qTokens = tokenise(query);
|
|
11680
11583
|
const results = scored.slice(0, limit).map(({ id, score }) => {
|
|
11681
|
-
const c =
|
|
11584
|
+
const c = expectDefined2(candidateById.get(id));
|
|
11682
11585
|
return { ...c, score, snippet: bm25.extractSnippet(id, qTokens) };
|
|
11683
11586
|
});
|
|
11684
11587
|
return { results, total: candidates.length };
|
|
@@ -12092,710 +11995,208 @@ var indexStorePool = new StorePool(
|
|
|
12092
11995
|
(projectRoot, opts) => new IndexStore(projectRoot, opts)
|
|
12093
11996
|
);
|
|
12094
11997
|
|
|
12095
|
-
// src/codebase-index/
|
|
12096
|
-
var
|
|
12097
|
-
|
|
12098
|
-
|
|
12099
|
-
|
|
12100
|
-
function
|
|
12101
|
-
|
|
11998
|
+
// src/codebase-index/project-server-endpoint.ts
|
|
11999
|
+
var PROJECT_INDEX_SERVER_PROTOCOL_VERSION = 1;
|
|
12000
|
+
var PROJECT_INDEX_SERVER_METADATA_FILE = "server.json";
|
|
12001
|
+
var PROJECT_INDEX_SERVER_SOCKET_DIR = `wsci-v${PROJECT_INDEX_SERVER_PROTOCOL_VERSION}`;
|
|
12002
|
+
var buildIdCache;
|
|
12003
|
+
function projectIndexServerBuildId(entrypoint) {
|
|
12004
|
+
const file = entrypoint instanceof URL || entrypoint.startsWith("file:") ? fileURLToPath(entrypoint) : path16.resolve(entrypoint);
|
|
12005
|
+
try {
|
|
12006
|
+
const stat18 = fs11.statSync(file);
|
|
12007
|
+
if (buildIdCache?.file === file && buildIdCache.mtimeMs === stat18.mtimeMs && buildIdCache.size === stat18.size) {
|
|
12008
|
+
return buildIdCache.buildId;
|
|
12009
|
+
}
|
|
12010
|
+
const buildId = createHash4("sha256").update(fs11.readFileSync(file)).digest("hex").slice(0, 24);
|
|
12011
|
+
buildIdCache = { file, mtimeMs: stat18.mtimeMs, size: stat18.size, buildId };
|
|
12012
|
+
return buildId;
|
|
12013
|
+
} catch {
|
|
12014
|
+
return `unreadable:${path16.basename(file)}`;
|
|
12015
|
+
}
|
|
12102
12016
|
}
|
|
12103
|
-
function
|
|
12104
|
-
|
|
12105
|
-
|
|
12106
|
-
throw new Error(typeof signal.reason === "string" ? signal.reason : "Indexing cancelled");
|
|
12017
|
+
function normalizeLocalPath(value) {
|
|
12018
|
+
const resolved = path16.resolve(value);
|
|
12019
|
+
return process.platform === "win32" ? resolved.toLowerCase() : resolved;
|
|
12107
12020
|
}
|
|
12108
|
-
function
|
|
12109
|
-
|
|
12021
|
+
function projectIndexServerKey(projectRoot, indexDir) {
|
|
12022
|
+
const resolvedIndexDir = normalizeLocalPath(resolveIndexDir(projectRoot, indexDir));
|
|
12023
|
+
return createHash4("sha256").update(resolvedIndexDir).digest("hex").slice(0, 24);
|
|
12110
12024
|
}
|
|
12111
|
-
|
|
12112
|
-
|
|
12113
|
-
|
|
12114
|
-
|
|
12115
|
-
|
|
12116
|
-
|
|
12117
|
-
const rel = path22.relative(projectRoot, file);
|
|
12118
|
-
return rel !== "" && !rel.startsWith(`..${path22.sep}`) && rel !== ".." && !path22.isAbsolute(rel);
|
|
12025
|
+
function projectIndexServerEndpoint(projectRoot, indexDir) {
|
|
12026
|
+
const key = projectIndexServerKey(projectRoot, indexDir);
|
|
12027
|
+
if (process.platform === "win32") {
|
|
12028
|
+
return `\\\\.\\pipe\\wrongstack-codebase-index-v${PROJECT_INDEX_SERVER_PROTOCOL_VERSION}-${key}`;
|
|
12029
|
+
}
|
|
12030
|
+
return path16.join(os5.tmpdir(), PROJECT_INDEX_SERVER_SOCKET_DIR, `${key}.sock`);
|
|
12119
12031
|
}
|
|
12120
|
-
function
|
|
12121
|
-
|
|
12122
|
-
|
|
12032
|
+
function projectIndexServerMetadataPath(projectRoot, indexDir) {
|
|
12033
|
+
return path16.join(
|
|
12034
|
+
path16.resolve(resolveIndexDir(projectRoot, indexDir)),
|
|
12035
|
+
PROJECT_INDEX_SERVER_METADATA_FILE
|
|
12036
|
+
);
|
|
12123
12037
|
}
|
|
12124
|
-
|
|
12125
|
-
|
|
12126
|
-
|
|
12038
|
+
|
|
12039
|
+
// src/codebase-index/project-server-protocol.ts
|
|
12040
|
+
var PROJECT_INDEX_SERVER_MAX_FRAME_CHARS = 64 * 1024 * 1024;
|
|
12041
|
+
function encodeProjectServerMessage(message) {
|
|
12042
|
+
return `${JSON.stringify(message)}
|
|
12043
|
+
`;
|
|
12127
12044
|
}
|
|
12128
|
-
|
|
12129
|
-
|
|
12130
|
-
|
|
12131
|
-
|
|
12132
|
-
|
|
12133
|
-
|
|
12134
|
-
|
|
12135
|
-
|
|
12136
|
-
|
|
12137
|
-
|
|
12138
|
-
|
|
12139
|
-
|
|
12140
|
-
|
|
12045
|
+
|
|
12046
|
+
// src/codebase-index/project-server-client.ts
|
|
12047
|
+
var CONNECT_ATTEMPT_TIMEOUT_MS = 750;
|
|
12048
|
+
var SERVER_START_TIMEOUT_MS = 1e4;
|
|
12049
|
+
var SERVER_CONTROL_TIMEOUT_MS = 5e3;
|
|
12050
|
+
var SERVER_HEALTH_TIMEOUT_MS = 3e3;
|
|
12051
|
+
var SERVER_HEARTBEAT_INTERVAL_MS = 1e4;
|
|
12052
|
+
var StaleProjectIndexServerError = class extends Error {
|
|
12053
|
+
constructor(message, pid) {
|
|
12054
|
+
super(message);
|
|
12055
|
+
this.pid = pid;
|
|
12056
|
+
}
|
|
12057
|
+
pid;
|
|
12058
|
+
name = "StaleProjectIndexServerError";
|
|
12059
|
+
};
|
|
12060
|
+
var connectionStates = /* @__PURE__ */ new Map();
|
|
12061
|
+
var connectionStateListeners = /* @__PURE__ */ new Set();
|
|
12062
|
+
var latestConnectionState = {
|
|
12063
|
+
status: "offline",
|
|
12064
|
+
connected: false
|
|
12065
|
+
};
|
|
12066
|
+
function resolveProjectIndexDaemonAvailability(projectRoot, indexDir) {
|
|
12067
|
+
if (process.env["WRONGSTACK_INDEX_INLINE"] || process.env["WRONGSTACK_INDEX_SERVER"] === "0") {
|
|
12068
|
+
return { kind: "inline-requested" };
|
|
12069
|
+
}
|
|
12070
|
+
let builtUrl = null;
|
|
12071
|
+
for (const rel of ["./project-server.js", "./codebase-index/project-server.js"]) {
|
|
12072
|
+
try {
|
|
12073
|
+
const url = new URL(rel, import.meta.url);
|
|
12074
|
+
if (url.protocol === "file:" && fs12.existsSync(fileURLToPath2(url))) {
|
|
12075
|
+
builtUrl = url;
|
|
12076
|
+
break;
|
|
12141
12077
|
}
|
|
12142
|
-
|
|
12143
|
-
|
|
12078
|
+
} catch {
|
|
12079
|
+
}
|
|
12080
|
+
}
|
|
12081
|
+
if (builtUrl === null) return { kind: "missing-build" };
|
|
12082
|
+
if (projectRoot !== void 0) {
|
|
12083
|
+
const endpoint = projectIndexServerEndpoint(projectRoot, indexDir);
|
|
12084
|
+
const check = checkUnixSocketPath(endpoint);
|
|
12085
|
+
if (!check.ok) {
|
|
12086
|
+
return {
|
|
12087
|
+
kind: "endpoint-invalid",
|
|
12088
|
+
endpoint,
|
|
12089
|
+
byteLength: check.byteLength,
|
|
12090
|
+
maxBytes: check.maxBytes
|
|
12091
|
+
};
|
|
12092
|
+
}
|
|
12093
|
+
}
|
|
12094
|
+
return { kind: "available", url: builtUrl };
|
|
12144
12095
|
}
|
|
12145
|
-
|
|
12146
|
-
|
|
12147
|
-
|
|
12148
|
-
|
|
12149
|
-
|
|
12150
|
-
|
|
12151
|
-
|
|
12152
|
-
|
|
12153
|
-
|
|
12154
|
-
|
|
12155
|
-
|
|
12156
|
-
|
|
12157
|
-
|
|
12158
|
-
|
|
12159
|
-
|
|
12160
|
-
|
|
12161
|
-
|
|
12162
|
-
|
|
12163
|
-
|
|
12164
|
-
|
|
12165
|
-
const
|
|
12166
|
-
|
|
12167
|
-
|
|
12168
|
-
|
|
12169
|
-
|
|
12170
|
-
const changedPath = path22.resolve(projectRoot, record.slice(3));
|
|
12171
|
-
dirty.add(changedPath);
|
|
12172
|
-
if (status.includes("D")) deleted.add(changedPath);
|
|
12173
|
-
if (status.includes("R") || status.includes("C")) {
|
|
12174
|
-
const source = statusRecords[++i];
|
|
12175
|
-
if (source) dirty.add(path22.resolve(projectRoot, source));
|
|
12176
|
-
}
|
|
12177
|
-
}
|
|
12178
|
-
const files = [];
|
|
12179
|
-
for (const relative13 of output.toString("utf8").split("\0")) {
|
|
12180
|
-
if (!relative13) continue;
|
|
12181
|
-
const portable = relative13.replace(/\\/g, "/");
|
|
12182
|
-
if (portable.split("/").some((segment) => ignoreSet.has(segment)) || DEFAULT_IGNORE_FILES.has(path22.posix.basename(portable))) {
|
|
12183
|
-
continue;
|
|
12184
|
-
}
|
|
12185
|
-
const full = path22.resolve(projectRoot, relative13);
|
|
12186
|
-
if (deleted.has(full)) continue;
|
|
12187
|
-
const ext = path22.extname(relative13).toLowerCase();
|
|
12188
|
-
if (INDEXABLE_EXTENSION_SET.has(ext) || detectLang(full) !== null) files.push(full);
|
|
12096
|
+
function resolveProjectServerUrl() {
|
|
12097
|
+
const availability = resolveProjectIndexDaemonAvailability();
|
|
12098
|
+
return availability.kind === "available" ? availability.url : null;
|
|
12099
|
+
}
|
|
12100
|
+
function projectIndexServerExpectedBuildId() {
|
|
12101
|
+
const override = process.env["WRONGSTACK_INDEX_SERVER_BUILD_ID"]?.trim();
|
|
12102
|
+
if (override) return override;
|
|
12103
|
+
const url = resolveProjectServerUrl();
|
|
12104
|
+
return url ? projectIndexServerBuildId(url) : null;
|
|
12105
|
+
}
|
|
12106
|
+
function isProjectIndexServerAvailable() {
|
|
12107
|
+
return resolveProjectServerUrl() !== null;
|
|
12108
|
+
}
|
|
12109
|
+
function publishConnectionState(endpoint, state) {
|
|
12110
|
+
connectionStates.set(endpoint, state);
|
|
12111
|
+
latestConnectionState = state;
|
|
12112
|
+
for (const listener of connectionStateListeners) listener(state);
|
|
12113
|
+
}
|
|
12114
|
+
function getProjectIndexServerConnectionState(projectRoot, indexDir) {
|
|
12115
|
+
if (projectRoot) {
|
|
12116
|
+
const endpoint = projectIndexServerEndpoint(projectRoot, indexDir);
|
|
12117
|
+
const existing = connectionStates.get(endpoint);
|
|
12118
|
+
if (existing) return existing;
|
|
12119
|
+
if (!isProjectIndexServerAvailable()) {
|
|
12120
|
+
return { status: "unavailable", connected: false };
|
|
12189
12121
|
}
|
|
12190
12122
|
return {
|
|
12191
|
-
|
|
12192
|
-
|
|
12123
|
+
status: "offline",
|
|
12124
|
+
connected: false,
|
|
12125
|
+
projectRoot,
|
|
12126
|
+
indexDir,
|
|
12127
|
+
endpoint
|
|
12193
12128
|
};
|
|
12194
|
-
} catch {
|
|
12195
|
-
return null;
|
|
12196
12129
|
}
|
|
12130
|
+
if (latestConnectionState.endpoint) return latestConnectionState;
|
|
12131
|
+
if (!isProjectIndexServerAvailable()) return { status: "unavailable", connected: false };
|
|
12132
|
+
return latestConnectionState;
|
|
12197
12133
|
}
|
|
12198
|
-
|
|
12199
|
-
|
|
12200
|
-
|
|
12201
|
-
return {
|
|
12202
|
-
files: gitFiles.files,
|
|
12203
|
-
complete: true,
|
|
12204
|
-
errors: [],
|
|
12205
|
-
trustedUnchanged: gitFiles.trustedUnchanged
|
|
12206
|
-
};
|
|
12207
|
-
}
|
|
12208
|
-
const results = [];
|
|
12209
|
-
const errors = [];
|
|
12210
|
-
let complete = true;
|
|
12211
|
-
const ignoreSet = /* @__PURE__ */ new Set([...DEFAULT_IGNORE, ...ignore]);
|
|
12212
|
-
const indexableExts = new Set(INDEXABLE_EXTENSIONS);
|
|
12213
|
-
let dirCount = 0;
|
|
12214
|
-
const walk2 = async (dir) => {
|
|
12215
|
-
throwIfAborted(signal);
|
|
12216
|
-
if (dirCount > 0 && dirCount % YIELD_EVERY_N === 0) {
|
|
12217
|
-
await yieldEventLoop();
|
|
12218
|
-
throwIfAborted(signal);
|
|
12219
|
-
}
|
|
12220
|
-
let entries;
|
|
12221
|
-
try {
|
|
12222
|
-
entries = await fs15.readdir(dir, { withFileTypes: true });
|
|
12223
|
-
} catch (err) {
|
|
12224
|
-
complete = false;
|
|
12225
|
-
errors.push(`scan error: ${dir}: ${err instanceof Error ? err.message : String(err)}`);
|
|
12226
|
-
return;
|
|
12227
|
-
}
|
|
12228
|
-
dirCount++;
|
|
12229
|
-
for (const e of entries) {
|
|
12230
|
-
if (ignoreSet.has(e.name)) continue;
|
|
12231
|
-
const full = path22.join(dir, e.name);
|
|
12232
|
-
const rel = path22.relative(projectRoot, full).replace(/\\/g, "/");
|
|
12233
|
-
if (e.isDirectory()) {
|
|
12234
|
-
if (isGitIgnored(rel, true)) continue;
|
|
12235
|
-
await walk2(full);
|
|
12236
|
-
} else if (e.isFile()) {
|
|
12237
|
-
if (DEFAULT_IGNORE_FILES.has(e.name) || isGitIgnored(rel, false)) continue;
|
|
12238
|
-
const ext = path22.extname(e.name).toLowerCase();
|
|
12239
|
-
if (indexableExts.has(ext) || detectLang(full) !== null) {
|
|
12240
|
-
results.push(full);
|
|
12241
|
-
}
|
|
12242
|
-
}
|
|
12243
|
-
}
|
|
12244
|
-
};
|
|
12245
|
-
await walk2(projectRoot);
|
|
12246
|
-
return { files: results, complete, errors };
|
|
12134
|
+
function onProjectIndexServerConnectionStateChange(listener) {
|
|
12135
|
+
connectionStateListeners.add(listener);
|
|
12136
|
+
return () => connectionStateListeners.delete(listener);
|
|
12247
12137
|
}
|
|
12248
|
-
function
|
|
12249
|
-
if (
|
|
12250
|
-
|
|
12251
|
-
const
|
|
12252
|
-
|
|
12253
|
-
|
|
12254
|
-
let owner2;
|
|
12255
|
-
for (const symbol of ordered) {
|
|
12256
|
-
if (symbol.line > ref.line) break;
|
|
12257
|
-
owner2 = symbol;
|
|
12258
|
-
}
|
|
12259
|
-
if (!owner2 && ref.callType === "import") owner2 = ordered[0];
|
|
12260
|
-
if (!owner2 || owner2.id <= 0) continue;
|
|
12261
|
-
const key = `${owner2.id}:${ref.toName}:${ref.callType}`;
|
|
12262
|
-
if (seen.has(key)) continue;
|
|
12263
|
-
seen.add(key);
|
|
12264
|
-
assigned.push({ ...ref, fromId: owner2.id });
|
|
12265
|
-
}
|
|
12266
|
-
return assigned;
|
|
12138
|
+
function remoteError(message, name) {
|
|
12139
|
+
if (name === "LockError") return new LockError(message);
|
|
12140
|
+
if (name === "IndexTimeoutError") return new IndexTimeoutError(message);
|
|
12141
|
+
const error = new Error(message);
|
|
12142
|
+
if (name && name !== "Error") error.name = name;
|
|
12143
|
+
return error;
|
|
12267
12144
|
}
|
|
12268
|
-
|
|
12269
|
-
|
|
12270
|
-
const
|
|
12271
|
-
const
|
|
12272
|
-
const
|
|
12273
|
-
|
|
12274
|
-
|
|
12275
|
-
|
|
12276
|
-
|
|
12277
|
-
|
|
12278
|
-
|
|
12279
|
-
|
|
12280
|
-
|
|
12281
|
-
|
|
12282
|
-
|
|
12283
|
-
|
|
12284
|
-
|
|
12285
|
-
|
|
12286
|
-
|
|
12287
|
-
|
|
12288
|
-
|
|
12289
|
-
|
|
12290
|
-
} else {
|
|
12291
|
-
const discovery = await findSourceFiles(projectRoot, ignore, isGitIgnored, signal);
|
|
12292
|
-
files = discovery.files;
|
|
12293
|
-
errors.push(...discovery.errors);
|
|
12294
|
-
discoveryComplete = discovery.complete;
|
|
12295
|
-
discoveredFiles = new Set(files);
|
|
12296
|
-
trustedUnchanged = discovery.trustedUnchanged;
|
|
12145
|
+
function isProjectIndexServerHealth(value) {
|
|
12146
|
+
if (!value || typeof value !== "object") return false;
|
|
12147
|
+
const health = value;
|
|
12148
|
+
const memory = health.memory && typeof health.memory === "object" ? health.memory : void 0;
|
|
12149
|
+
const activity = health.activity && typeof health.activity === "object" ? health.activity : void 0;
|
|
12150
|
+
return typeof health.checkedAt === "number" && typeof health.uptimeMs === "number" && typeof memory?.rss === "number" && typeof memory.heapUsed === "number" && typeof memory.heapTotal === "number" && typeof memory.external === "number" && typeof health.clients === "number" && typeof health.activeRequests === "number" && typeof health.activeWrites === "number" && typeof health.queuedWrites === "number" && typeof health.pendingExternalFiles === "number" && typeof health.watchingExternal === "boolean" && typeof activity?.indexing === "boolean" && typeof activity.currentFile === "number" && typeof activity.totalFiles === "number" && typeof activity.generation === "number";
|
|
12151
|
+
}
|
|
12152
|
+
function delay(ms) {
|
|
12153
|
+
return new Promise((resolve17) => {
|
|
12154
|
+
const timer = setTimeout(resolve17, ms);
|
|
12155
|
+
timer.unref?.();
|
|
12156
|
+
});
|
|
12157
|
+
}
|
|
12158
|
+
function cancellationError(signal) {
|
|
12159
|
+
return signal.reason instanceof Error ? signal.reason : new Error("Indexing cancelled");
|
|
12160
|
+
}
|
|
12161
|
+
var ProjectServerConnection = class {
|
|
12162
|
+
constructor(projectRoot, indexDir, endpoint) {
|
|
12163
|
+
this.projectRoot = projectRoot;
|
|
12164
|
+
this.indexDir = indexDir;
|
|
12165
|
+
this.endpoint = endpoint;
|
|
12166
|
+
this.transition("offline");
|
|
12297
12167
|
}
|
|
12298
|
-
|
|
12299
|
-
|
|
12300
|
-
|
|
12301
|
-
|
|
12302
|
-
|
|
12168
|
+
projectRoot;
|
|
12169
|
+
indexDir;
|
|
12170
|
+
endpoint;
|
|
12171
|
+
socket = null;
|
|
12172
|
+
buffer = "";
|
|
12173
|
+
info = null;
|
|
12174
|
+
activity = null;
|
|
12175
|
+
health = null;
|
|
12176
|
+
healthCheck = null;
|
|
12177
|
+
connecting = null;
|
|
12178
|
+
connectResolve = null;
|
|
12179
|
+
connectReject = null;
|
|
12180
|
+
nextId = 1;
|
|
12181
|
+
pending = /* @__PURE__ */ new Map();
|
|
12182
|
+
transition(status, options = {}) {
|
|
12183
|
+
const previous = connectionStates.get(this.endpoint);
|
|
12184
|
+
const pid = options.pid ?? (status === "connected" ? this.info?.pid : void 0);
|
|
12185
|
+
const lastError = options.error === void 0 ? status === "error" || status === "degraded" || status === "unresponsive" ? previous?.lastError : void 0 : options.error instanceof Error ? options.error.message : String(options.error);
|
|
12186
|
+
publishConnectionState(this.endpoint, {
|
|
12187
|
+
status,
|
|
12188
|
+
connected: status === "connected" || status === "degraded" || status === "unresponsive",
|
|
12189
|
+
projectRoot: this.projectRoot,
|
|
12190
|
+
indexDir: this.indexDir,
|
|
12191
|
+
endpoint: this.endpoint,
|
|
12192
|
+
pid,
|
|
12193
|
+
lastError,
|
|
12194
|
+
...this.activity ? { activity: this.activity } : {},
|
|
12195
|
+
...this.health ? { health: this.health } : {}
|
|
12303
12196
|
});
|
|
12304
12197
|
}
|
|
12305
|
-
|
|
12306
|
-
|
|
12307
|
-
if (!force) {
|
|
12308
|
-
for (const meta of store.getAllFileMetas()) existingMeta.set(meta.file, meta);
|
|
12309
|
-
}
|
|
12310
|
-
const totalFilesForProgress = files.length;
|
|
12311
|
-
let filesPreSkipped = 0;
|
|
12312
|
-
if (!force && trustedUnchanged) {
|
|
12313
|
-
files = files.filter((file) => {
|
|
12314
|
-
const meta = existingMeta.get(file);
|
|
12315
|
-
if (!meta || !trustedUnchanged.has(file)) return true;
|
|
12316
|
-
langStats[meta.lang] = (langStats[meta.lang] ?? 0) + meta.symbolCount;
|
|
12317
|
-
symbolsIndexed += meta.symbolCount;
|
|
12318
|
-
filesIndexed++;
|
|
12319
|
-
filesPreSkipped++;
|
|
12320
|
-
return false;
|
|
12321
|
-
});
|
|
12322
|
-
if (filesPreSkipped > 0) opts.onProgress?.(filesPreSkipped, totalFilesForProgress);
|
|
12323
|
-
}
|
|
12324
|
-
const parallelBatch = resolveParallelBatch();
|
|
12325
|
-
let filesSinceLastYield = 0;
|
|
12326
|
-
for (let batchStart = 0; batchStart < files.length; batchStart += parallelBatch) {
|
|
12327
|
-
const batchEnd = Math.min(batchStart + parallelBatch, files.length);
|
|
12328
|
-
const batchFiles = files.slice(batchStart, batchEnd);
|
|
12329
|
-
opts.onProgress?.(filesPreSkipped + batchEnd, totalFilesForProgress);
|
|
12330
|
-
filesSinceLastYield += batchFiles.length;
|
|
12331
|
-
if (filesSinceLastYield >= YIELD_EVERY_N) {
|
|
12332
|
-
filesSinceLastYield = 0;
|
|
12333
|
-
await yieldEventLoop();
|
|
12334
|
-
if (isFrugalPerf()) {
|
|
12335
|
-
await new Promise((r) => setTimeout(r, 8));
|
|
12336
|
-
}
|
|
12337
|
-
throwIfAborted(signal);
|
|
12338
|
-
}
|
|
12339
|
-
const statOpts = signal ? { signal } : {};
|
|
12340
|
-
const statReadParse = await Promise.allSettled(
|
|
12341
|
-
batchFiles.map(
|
|
12342
|
-
async (file) => {
|
|
12343
|
-
let stat18;
|
|
12344
|
-
try {
|
|
12345
|
-
stat18 = await fs15.stat(file, statOpts);
|
|
12346
|
-
} catch (e) {
|
|
12347
|
-
if (isAbortError(e)) throw e;
|
|
12348
|
-
return {
|
|
12349
|
-
file,
|
|
12350
|
-
stat: null,
|
|
12351
|
-
lang: "",
|
|
12352
|
-
parsed: null,
|
|
12353
|
-
error: `stat error: ${e instanceof Error ? e.message : String(e)}`,
|
|
12354
|
-
missing: isMissingPathError(e)
|
|
12355
|
-
};
|
|
12356
|
-
}
|
|
12357
|
-
if (!stat18.isFile()) return { file, stat: stat18, lang: "", parsed: null };
|
|
12358
|
-
const lang = detectLang(file);
|
|
12359
|
-
if (!lang) return { file, stat: stat18, lang: "", parsed: null };
|
|
12360
|
-
if (stat18.size > MAX_INDEX_FILE_BYTES) {
|
|
12361
|
-
return {
|
|
12362
|
-
file,
|
|
12363
|
-
stat: stat18,
|
|
12364
|
-
lang,
|
|
12365
|
-
parsed: null,
|
|
12366
|
-
error: `file too large (${stat18.size} bytes; max ${MAX_INDEX_FILE_BYTES})`
|
|
12367
|
-
};
|
|
12368
|
-
}
|
|
12369
|
-
const meta = existingMeta.get(file);
|
|
12370
|
-
if (!force && meta && meta.mtimeMs === Math.floor(stat18.mtimeMs)) {
|
|
12371
|
-
return { file, stat: stat18, lang, parsed: null, skippedMeta: meta };
|
|
12372
|
-
}
|
|
12373
|
-
let content;
|
|
12374
|
-
try {
|
|
12375
|
-
content = await fs15.readFile(file, { encoding: "utf8", signal });
|
|
12376
|
-
} catch (e) {
|
|
12377
|
-
if (isAbortError(e)) throw e;
|
|
12378
|
-
return {
|
|
12379
|
-
file,
|
|
12380
|
-
stat: stat18,
|
|
12381
|
-
lang,
|
|
12382
|
-
parsed: null,
|
|
12383
|
-
error: `read error: ${e instanceof Error ? e.message : String(e)}`
|
|
12384
|
-
};
|
|
12385
|
-
}
|
|
12386
|
-
let parsed;
|
|
12387
|
-
try {
|
|
12388
|
-
parsed = await parseFileContent(file, content, lang);
|
|
12389
|
-
} catch (e) {
|
|
12390
|
-
return {
|
|
12391
|
-
file,
|
|
12392
|
-
stat: stat18,
|
|
12393
|
-
lang,
|
|
12394
|
-
parsed: null,
|
|
12395
|
-
error: `parse error: ${e instanceof Error ? e.message : String(e)}`
|
|
12396
|
-
};
|
|
12397
|
-
}
|
|
12398
|
-
return { file, stat: stat18, lang, parsed, content };
|
|
12399
|
-
}
|
|
12400
|
-
)
|
|
12401
|
-
);
|
|
12402
|
-
const batchEntries = [];
|
|
12403
|
-
const deleteForFiles = [];
|
|
12404
|
-
for (let fi = 0; fi < statReadParse.length; fi++) {
|
|
12405
|
-
const settled = statReadParse[fi];
|
|
12406
|
-
const file = expectDefined6(batchFiles[fi]);
|
|
12407
|
-
if (settled.status === "rejected") {
|
|
12408
|
-
const err = settled.reason;
|
|
12409
|
-
if (err instanceof Error && isAbortError(err)) throw err;
|
|
12410
|
-
errors.push(`batch error: ${file}: ${err instanceof Error ? err.message : String(err)}`);
|
|
12411
|
-
continue;
|
|
12412
|
-
}
|
|
12413
|
-
const result = settled.value;
|
|
12414
|
-
if (result.error) {
|
|
12415
|
-
if (result.missing) store.deleteFile(file);
|
|
12416
|
-
errors.push(`${file}: ${result.error}`);
|
|
12417
|
-
continue;
|
|
12418
|
-
}
|
|
12419
|
-
const { stat: stat18, lang, parsed } = result;
|
|
12420
|
-
if (result.skippedMeta) {
|
|
12421
|
-
langStats[lang] = (langStats[lang] ?? 0) + result.skippedMeta.symbolCount;
|
|
12422
|
-
symbolsIndexed += result.skippedMeta.symbolCount;
|
|
12423
|
-
filesIndexed++;
|
|
12424
|
-
continue;
|
|
12425
|
-
}
|
|
12426
|
-
if (!lang || !parsed) {
|
|
12427
|
-
if (lang) {
|
|
12428
|
-
store.upsertFile({
|
|
12429
|
-
file,
|
|
12430
|
-
lang,
|
|
12431
|
-
mtimeMs: Math.floor(stat18.mtimeMs),
|
|
12432
|
-
symbolCount: 0,
|
|
12433
|
-
lastIndexed: Date.now()
|
|
12434
|
-
});
|
|
12435
|
-
filesIndexed++;
|
|
12436
|
-
}
|
|
12437
|
-
continue;
|
|
12438
|
-
}
|
|
12439
|
-
if (parsed.symbols.length === 0) {
|
|
12440
|
-
store.replaceEmptyFile({
|
|
12441
|
-
file,
|
|
12442
|
-
lang,
|
|
12443
|
-
mtimeMs: Math.floor(stat18.mtimeMs),
|
|
12444
|
-
symbolCount: 0,
|
|
12445
|
-
lastIndexed: Date.now()
|
|
12446
|
-
});
|
|
12447
|
-
filesIndexed++;
|
|
12448
|
-
continue;
|
|
12449
|
-
}
|
|
12450
|
-
batchEntries.push({
|
|
12451
|
-
file,
|
|
12452
|
-
lang,
|
|
12453
|
-
symbols: parsed.symbols,
|
|
12454
|
-
refs: parsed.refs ?? [],
|
|
12455
|
-
mtimeMs: Math.floor(stat18.mtimeMs),
|
|
12456
|
-
symbolCount: parsed.symbols.length
|
|
12457
|
-
});
|
|
12458
|
-
deleteForFiles.push(file);
|
|
12459
|
-
}
|
|
12460
|
-
if (batchEntries.length > 0) {
|
|
12461
|
-
try {
|
|
12462
|
-
store.commitBatch(batchEntries, { deleteForFiles });
|
|
12463
|
-
for (const entry of batchEntries) {
|
|
12464
|
-
const count = entry.symbols.length;
|
|
12465
|
-
symbolsIndexed += count;
|
|
12466
|
-
langStats[entry.lang] = (langStats[entry.lang] ?? 0) + count;
|
|
12467
|
-
filesIndexed++;
|
|
12468
|
-
}
|
|
12469
|
-
} catch (err) {
|
|
12470
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
12471
|
-
errors.push(`commitBatch failed: ${message} \u2014 falling back to per-file writes`);
|
|
12472
|
-
for (const entry of batchEntries) {
|
|
12473
|
-
try {
|
|
12474
|
-
store.deleteRefsForFile(entry.file);
|
|
12475
|
-
store.deleteSymbolsForFile(entry.file);
|
|
12476
|
-
const symbolsWithIds = store.insertSymbols(entry.symbols);
|
|
12477
|
-
symbolsIndexed += symbolsWithIds.length;
|
|
12478
|
-
langStats[entry.lang] = (langStats[entry.lang] ?? 0) + symbolsWithIds.length;
|
|
12479
|
-
filesIndexed++;
|
|
12480
|
-
if (entry.refs.length > 0 && symbolsWithIds.length > 0) {
|
|
12481
|
-
const fallbackBatch = assignRefsToSymbols2(entry.refs, symbolsWithIds);
|
|
12482
|
-
if (fallbackBatch.length > 0) store.insertRefsBatch(fallbackBatch);
|
|
12483
|
-
}
|
|
12484
|
-
store.resolveRefsForNames([
|
|
12485
|
-
...entry.symbols.map((symbol) => symbol.name),
|
|
12486
|
-
...entry.refs.map((ref) => ref.toName)
|
|
12487
|
-
]);
|
|
12488
|
-
store.upsertFile({
|
|
12489
|
-
file: entry.file,
|
|
12490
|
-
lang: entry.lang,
|
|
12491
|
-
mtimeMs: entry.mtimeMs,
|
|
12492
|
-
symbolCount: entry.symbolCount,
|
|
12493
|
-
lastIndexed: Date.now()
|
|
12494
|
-
});
|
|
12495
|
-
} catch (innerErr) {
|
|
12496
|
-
errors.push(
|
|
12497
|
-
`fallback write failed: ${entry.file}: ${innerErr instanceof Error ? innerErr.message : String(innerErr)}`
|
|
12498
|
-
);
|
|
12499
|
-
}
|
|
12500
|
-
}
|
|
12501
|
-
}
|
|
12502
|
-
}
|
|
12503
|
-
}
|
|
12504
|
-
if (discoveredFiles && discoveryComplete) {
|
|
12505
|
-
for (const [file_] of existingMeta) {
|
|
12506
|
-
if (!discoveredFiles.has(file_)) {
|
|
12507
|
-
store.deleteFile(file_);
|
|
12508
|
-
}
|
|
12509
|
-
}
|
|
12510
|
-
}
|
|
12511
|
-
if (needsFullRefResolution) store.resolveRefs();
|
|
12512
|
-
store.setMetadata("ref_resolution_version", refResolutionVersion);
|
|
12513
|
-
store.setMetadata("relation_graph_version", relationGraphVersion);
|
|
12514
|
-
if (!opts.files || filesIndexed >= 50) store.optimize();
|
|
12515
|
-
store.setLastIndexed(Date.now());
|
|
12516
|
-
if (!opts.files) store.compactIfNeeded();
|
|
12517
|
-
const durationMs = Date.now() - startMs;
|
|
12518
|
-
return {
|
|
12519
|
-
filesIndexed,
|
|
12520
|
-
symbolsIndexed,
|
|
12521
|
-
langStats,
|
|
12522
|
-
durationMs,
|
|
12523
|
-
errors
|
|
12524
|
-
};
|
|
12525
|
-
}
|
|
12526
|
-
|
|
12527
|
-
// src/codebase-index/index-service.ts
|
|
12528
|
-
async function indexService(args, hooks = {}) {
|
|
12529
|
-
const store = indexStorePool.acquire(args.projectRoot, { indexDir: args.indexDir });
|
|
12530
|
-
try {
|
|
12531
|
-
return await runIndexerWithStore(store, {
|
|
12532
|
-
projectRoot: args.projectRoot,
|
|
12533
|
-
indexDir: args.indexDir,
|
|
12534
|
-
files: args.files,
|
|
12535
|
-
force: args.force,
|
|
12536
|
-
langs: args.langs,
|
|
12537
|
-
ignore: args.ignore,
|
|
12538
|
-
signal: hooks.signal,
|
|
12539
|
-
onProgress: hooks.onProgress
|
|
12540
|
-
});
|
|
12541
|
-
} finally {
|
|
12542
|
-
indexStorePool.release(store);
|
|
12543
|
-
}
|
|
12544
|
-
}
|
|
12545
|
-
function searchService(args) {
|
|
12546
|
-
const store = indexStorePool.acquire(args.projectRoot, { indexDir: args.indexDir });
|
|
12547
|
-
try {
|
|
12548
|
-
return store.searchRanked(
|
|
12549
|
-
args.query,
|
|
12550
|
-
{
|
|
12551
|
-
kind: args.kind,
|
|
12552
|
-
lang: args.lang,
|
|
12553
|
-
file: args.file,
|
|
12554
|
-
lspKind: args.lspKind
|
|
12555
|
-
},
|
|
12556
|
-
args.limit
|
|
12557
|
-
);
|
|
12558
|
-
} finally {
|
|
12559
|
-
indexStorePool.release(store);
|
|
12560
|
-
}
|
|
12561
|
-
}
|
|
12562
|
-
function statsService(args) {
|
|
12563
|
-
const store = indexStorePool.acquire(args.projectRoot, { indexDir: args.indexDir });
|
|
12564
|
-
try {
|
|
12565
|
-
return store.getStats();
|
|
12566
|
-
} finally {
|
|
12567
|
-
indexStorePool.release(store);
|
|
12568
|
-
}
|
|
12569
|
-
}
|
|
12570
|
-
function packageGraphService(args) {
|
|
12571
|
-
const store = indexStorePool.acquire(args.projectRoot, { indexDir: args.indexDir });
|
|
12572
|
-
try {
|
|
12573
|
-
return store.getPackageGraph();
|
|
12574
|
-
} finally {
|
|
12575
|
-
indexStorePool.release(store);
|
|
12576
|
-
}
|
|
12577
|
-
}
|
|
12578
|
-
function fileGraphService(args) {
|
|
12579
|
-
const store = indexStorePool.acquire(args.projectRoot, { indexDir: args.indexDir });
|
|
12580
|
-
try {
|
|
12581
|
-
return store.getFileGraph(args.packageFilter);
|
|
12582
|
-
} finally {
|
|
12583
|
-
indexStorePool.release(store);
|
|
12584
|
-
}
|
|
12585
|
-
}
|
|
12586
|
-
function symbolGraphService(args) {
|
|
12587
|
-
const store = indexStorePool.acquire(args.projectRoot, { indexDir: args.indexDir });
|
|
12588
|
-
try {
|
|
12589
|
-
return store.getSymbolGraph(args.fileFilter);
|
|
12590
|
-
} finally {
|
|
12591
|
-
indexStorePool.release(store);
|
|
12592
|
-
}
|
|
12593
|
-
}
|
|
12594
|
-
|
|
12595
|
-
// src/codebase-index/background-indexer.ts
|
|
12596
|
-
init_languages2();
|
|
12597
|
-
|
|
12598
|
-
// src/codebase-index/project-server-client.ts
|
|
12599
|
-
import { spawn as spawn7 } from "node:child_process";
|
|
12600
|
-
import * as fs17 from "node:fs";
|
|
12601
|
-
import * as net3 from "node:net";
|
|
12602
|
-
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
12603
|
-
|
|
12604
|
-
// src/codebase-index/project-server-endpoint.ts
|
|
12605
|
-
import { createHash as createHash4 } from "node:crypto";
|
|
12606
|
-
import * as fs16 from "node:fs";
|
|
12607
|
-
import * as os7 from "node:os";
|
|
12608
|
-
import * as path23 from "node:path";
|
|
12609
|
-
import { fileURLToPath } from "node:url";
|
|
12610
|
-
var PROJECT_INDEX_SERVER_PROTOCOL_VERSION = 1;
|
|
12611
|
-
var PROJECT_INDEX_SERVER_METADATA_FILE = "server.json";
|
|
12612
|
-
var buildIdCache;
|
|
12613
|
-
function projectIndexServerBuildId(entrypoint) {
|
|
12614
|
-
const file = entrypoint instanceof URL || entrypoint.startsWith("file:") ? fileURLToPath(entrypoint) : path23.resolve(entrypoint);
|
|
12615
|
-
try {
|
|
12616
|
-
const stat18 = fs16.statSync(file);
|
|
12617
|
-
if (buildIdCache?.file === file && buildIdCache.mtimeMs === stat18.mtimeMs && buildIdCache.size === stat18.size) {
|
|
12618
|
-
return buildIdCache.buildId;
|
|
12619
|
-
}
|
|
12620
|
-
const buildId = createHash4("sha256").update(fs16.readFileSync(file)).digest("hex").slice(0, 24);
|
|
12621
|
-
buildIdCache = { file, mtimeMs: stat18.mtimeMs, size: stat18.size, buildId };
|
|
12622
|
-
return buildId;
|
|
12623
|
-
} catch {
|
|
12624
|
-
return `unreadable:${path23.basename(file)}`;
|
|
12625
|
-
}
|
|
12626
|
-
}
|
|
12627
|
-
function normalizeLocalPath(value) {
|
|
12628
|
-
const resolved = path23.resolve(value);
|
|
12629
|
-
return process.platform === "win32" ? resolved.toLowerCase() : resolved;
|
|
12630
|
-
}
|
|
12631
|
-
function projectIndexServerKey(projectRoot, indexDir) {
|
|
12632
|
-
const resolvedIndexDir = normalizeLocalPath(resolveIndexDir(projectRoot, indexDir));
|
|
12633
|
-
return createHash4("sha256").update(resolvedIndexDir).digest("hex").slice(0, 24);
|
|
12634
|
-
}
|
|
12635
|
-
function projectIndexServerEndpoint(projectRoot, indexDir) {
|
|
12636
|
-
const key = projectIndexServerKey(projectRoot, indexDir);
|
|
12637
|
-
if (process.platform === "win32") {
|
|
12638
|
-
return `\\\\.\\pipe\\wrongstack-codebase-index-v${PROJECT_INDEX_SERVER_PROTOCOL_VERSION}-${key}`;
|
|
12639
|
-
}
|
|
12640
|
-
return path23.join(
|
|
12641
|
-
os7.tmpdir(),
|
|
12642
|
-
`wrongstack-codebase-index-v${PROJECT_INDEX_SERVER_PROTOCOL_VERSION}`,
|
|
12643
|
-
`${key}.sock`
|
|
12644
|
-
);
|
|
12645
|
-
}
|
|
12646
|
-
function projectIndexServerMetadataPath(projectRoot, indexDir) {
|
|
12647
|
-
return path23.join(
|
|
12648
|
-
path23.resolve(resolveIndexDir(projectRoot, indexDir)),
|
|
12649
|
-
PROJECT_INDEX_SERVER_METADATA_FILE
|
|
12650
|
-
);
|
|
12651
|
-
}
|
|
12652
|
-
|
|
12653
|
-
// src/codebase-index/project-server-protocol.ts
|
|
12654
|
-
var PROJECT_INDEX_SERVER_MAX_FRAME_CHARS = 64 * 1024 * 1024;
|
|
12655
|
-
function encodeProjectServerMessage(message) {
|
|
12656
|
-
return `${JSON.stringify(message)}
|
|
12657
|
-
`;
|
|
12658
|
-
}
|
|
12659
|
-
|
|
12660
|
-
// src/codebase-index/project-server-client.ts
|
|
12661
|
-
var CONNECT_ATTEMPT_TIMEOUT_MS = 750;
|
|
12662
|
-
var SERVER_START_TIMEOUT_MS = 1e4;
|
|
12663
|
-
var SERVER_CONTROL_TIMEOUT_MS = 5e3;
|
|
12664
|
-
var SERVER_HEALTH_TIMEOUT_MS = 3e3;
|
|
12665
|
-
var SERVER_HEARTBEAT_INTERVAL_MS = 1e4;
|
|
12666
|
-
var StaleProjectIndexServerError = class extends Error {
|
|
12667
|
-
constructor(message, pid) {
|
|
12668
|
-
super(message);
|
|
12669
|
-
this.pid = pid;
|
|
12670
|
-
}
|
|
12671
|
-
pid;
|
|
12672
|
-
name = "StaleProjectIndexServerError";
|
|
12673
|
-
};
|
|
12674
|
-
var connectionStates = /* @__PURE__ */ new Map();
|
|
12675
|
-
var connectionStateListeners = /* @__PURE__ */ new Set();
|
|
12676
|
-
var latestConnectionState = {
|
|
12677
|
-
status: "offline",
|
|
12678
|
-
connected: false
|
|
12679
|
-
};
|
|
12680
|
-
function resolveProjectIndexDaemonAvailability() {
|
|
12681
|
-
if (process.env["WRONGSTACK_INDEX_INLINE"] || process.env["WRONGSTACK_INDEX_SERVER"] === "0") {
|
|
12682
|
-
return { kind: "inline-requested" };
|
|
12683
|
-
}
|
|
12684
|
-
for (const rel of ["./project-server.js", "./codebase-index/project-server.js"]) {
|
|
12685
|
-
try {
|
|
12686
|
-
const url = new URL(rel, import.meta.url);
|
|
12687
|
-
if (url.protocol === "file:" && fs17.existsSync(fileURLToPath2(url))) {
|
|
12688
|
-
return { kind: "available", url };
|
|
12689
|
-
}
|
|
12690
|
-
} catch {
|
|
12691
|
-
}
|
|
12692
|
-
}
|
|
12693
|
-
return { kind: "missing-build" };
|
|
12694
|
-
}
|
|
12695
|
-
function resolveProjectServerUrl() {
|
|
12696
|
-
const availability = resolveProjectIndexDaemonAvailability();
|
|
12697
|
-
return availability.kind === "available" ? availability.url : null;
|
|
12698
|
-
}
|
|
12699
|
-
function projectIndexServerExpectedBuildId() {
|
|
12700
|
-
const override = process.env["WRONGSTACK_INDEX_SERVER_BUILD_ID"]?.trim();
|
|
12701
|
-
if (override) return override;
|
|
12702
|
-
const url = resolveProjectServerUrl();
|
|
12703
|
-
return url ? projectIndexServerBuildId(url) : null;
|
|
12704
|
-
}
|
|
12705
|
-
function isProjectIndexServerAvailable() {
|
|
12706
|
-
return resolveProjectServerUrl() !== null;
|
|
12707
|
-
}
|
|
12708
|
-
function publishConnectionState(endpoint, state) {
|
|
12709
|
-
connectionStates.set(endpoint, state);
|
|
12710
|
-
latestConnectionState = state;
|
|
12711
|
-
for (const listener of connectionStateListeners) listener(state);
|
|
12712
|
-
}
|
|
12713
|
-
function getProjectIndexServerConnectionState(projectRoot, indexDir) {
|
|
12714
|
-
if (projectRoot) {
|
|
12715
|
-
const endpoint = projectIndexServerEndpoint(projectRoot, indexDir);
|
|
12716
|
-
const existing = connectionStates.get(endpoint);
|
|
12717
|
-
if (existing) return existing;
|
|
12718
|
-
if (!isProjectIndexServerAvailable()) {
|
|
12719
|
-
return { status: "unavailable", connected: false };
|
|
12720
|
-
}
|
|
12721
|
-
return {
|
|
12722
|
-
status: "offline",
|
|
12723
|
-
connected: false,
|
|
12724
|
-
projectRoot,
|
|
12725
|
-
indexDir,
|
|
12726
|
-
endpoint
|
|
12727
|
-
};
|
|
12728
|
-
}
|
|
12729
|
-
if (latestConnectionState.endpoint) return latestConnectionState;
|
|
12730
|
-
if (!isProjectIndexServerAvailable()) return { status: "unavailable", connected: false };
|
|
12731
|
-
return latestConnectionState;
|
|
12732
|
-
}
|
|
12733
|
-
function onProjectIndexServerConnectionStateChange(listener) {
|
|
12734
|
-
connectionStateListeners.add(listener);
|
|
12735
|
-
return () => connectionStateListeners.delete(listener);
|
|
12736
|
-
}
|
|
12737
|
-
function remoteError(message, name) {
|
|
12738
|
-
if (name === "LockError") return new LockError(message);
|
|
12739
|
-
if (name === "IndexTimeoutError") return new IndexTimeoutError(message);
|
|
12740
|
-
const error = new Error(message);
|
|
12741
|
-
if (name && name !== "Error") error.name = name;
|
|
12742
|
-
return error;
|
|
12743
|
-
}
|
|
12744
|
-
function isProjectIndexServerHealth(value) {
|
|
12745
|
-
if (!value || typeof value !== "object") return false;
|
|
12746
|
-
const health = value;
|
|
12747
|
-
const memory = health.memory && typeof health.memory === "object" ? health.memory : void 0;
|
|
12748
|
-
const activity = health.activity && typeof health.activity === "object" ? health.activity : void 0;
|
|
12749
|
-
return typeof health.checkedAt === "number" && typeof health.uptimeMs === "number" && typeof memory?.rss === "number" && typeof memory.heapUsed === "number" && typeof memory.heapTotal === "number" && typeof memory.external === "number" && typeof health.clients === "number" && typeof health.activeRequests === "number" && typeof health.activeWrites === "number" && typeof health.queuedWrites === "number" && typeof health.pendingExternalFiles === "number" && typeof health.watchingExternal === "boolean" && typeof activity?.indexing === "boolean" && typeof activity.currentFile === "number" && typeof activity.totalFiles === "number" && typeof activity.generation === "number";
|
|
12750
|
-
}
|
|
12751
|
-
function delay(ms) {
|
|
12752
|
-
return new Promise((resolve17) => {
|
|
12753
|
-
const timer = setTimeout(resolve17, ms);
|
|
12754
|
-
timer.unref?.();
|
|
12755
|
-
});
|
|
12756
|
-
}
|
|
12757
|
-
function cancellationError(signal) {
|
|
12758
|
-
return signal.reason instanceof Error ? signal.reason : new Error("Indexing cancelled");
|
|
12759
|
-
}
|
|
12760
|
-
var ProjectServerConnection = class {
|
|
12761
|
-
constructor(projectRoot, indexDir, endpoint) {
|
|
12762
|
-
this.projectRoot = projectRoot;
|
|
12763
|
-
this.indexDir = indexDir;
|
|
12764
|
-
this.endpoint = endpoint;
|
|
12765
|
-
this.transition("offline");
|
|
12766
|
-
}
|
|
12767
|
-
projectRoot;
|
|
12768
|
-
indexDir;
|
|
12769
|
-
endpoint;
|
|
12770
|
-
socket = null;
|
|
12771
|
-
buffer = "";
|
|
12772
|
-
info = null;
|
|
12773
|
-
activity = null;
|
|
12774
|
-
health = null;
|
|
12775
|
-
healthCheck = null;
|
|
12776
|
-
connecting = null;
|
|
12777
|
-
connectResolve = null;
|
|
12778
|
-
connectReject = null;
|
|
12779
|
-
nextId = 1;
|
|
12780
|
-
pending = /* @__PURE__ */ new Map();
|
|
12781
|
-
transition(status, options = {}) {
|
|
12782
|
-
const previous = connectionStates.get(this.endpoint);
|
|
12783
|
-
const pid = options.pid ?? (status === "connected" ? this.info?.pid : void 0);
|
|
12784
|
-
const lastError = options.error === void 0 ? status === "error" || status === "degraded" || status === "unresponsive" ? previous?.lastError : void 0 : options.error instanceof Error ? options.error.message : String(options.error);
|
|
12785
|
-
publishConnectionState(this.endpoint, {
|
|
12786
|
-
status,
|
|
12787
|
-
connected: status === "connected" || status === "degraded" || status === "unresponsive",
|
|
12788
|
-
projectRoot: this.projectRoot,
|
|
12789
|
-
indexDir: this.indexDir,
|
|
12790
|
-
endpoint: this.endpoint,
|
|
12791
|
-
pid,
|
|
12792
|
-
lastError,
|
|
12793
|
-
...this.activity ? { activity: this.activity } : {},
|
|
12794
|
-
...this.health ? { health: this.health } : {}
|
|
12795
|
-
});
|
|
12796
|
-
}
|
|
12797
|
-
isConnected() {
|
|
12798
|
-
return this.socket !== null && !this.socket.destroyed && this.info !== null;
|
|
12198
|
+
isConnected() {
|
|
12199
|
+
return this.socket !== null && !this.socket.destroyed && this.info !== null;
|
|
12799
12200
|
}
|
|
12800
12201
|
async checkHealth(spawnIfMissing = false, timeoutMs = SERVER_HEALTH_TIMEOUT_MS) {
|
|
12801
12202
|
await this.ensureConnected(spawnIfMissing);
|
|
@@ -12895,371 +12296,984 @@ var ProjectServerConnection = class {
|
|
|
12895
12296
|
this.transition("connected", { pid: this.info?.pid });
|
|
12896
12297
|
}
|
|
12897
12298
|
}
|
|
12898
|
-
close() {
|
|
12899
|
-
const socket = this.socket;
|
|
12299
|
+
close() {
|
|
12300
|
+
const socket = this.socket;
|
|
12301
|
+
this.socket = null;
|
|
12302
|
+
this.info = null;
|
|
12303
|
+
this.activity = null;
|
|
12304
|
+
this.health = null;
|
|
12305
|
+
this.connectReject?.(new Error("codebase-index client disconnected"));
|
|
12306
|
+
this.connectResolve = null;
|
|
12307
|
+
this.connectReject = null;
|
|
12308
|
+
if (socket && !socket.destroyed) socket.destroy();
|
|
12309
|
+
this.rejectPending(new Error("codebase-index client disconnected"));
|
|
12310
|
+
this.transition("offline");
|
|
12311
|
+
maybeStopHeartbeatLoop();
|
|
12312
|
+
}
|
|
12313
|
+
request(message, options) {
|
|
12314
|
+
const socket = this.socket;
|
|
12315
|
+
if (!socket || socket.destroyed) {
|
|
12316
|
+
return Promise.reject(new Error("codebase-index server connection is not available"));
|
|
12317
|
+
}
|
|
12318
|
+
const id = this.nextId++;
|
|
12319
|
+
return new Promise((resolve17, reject) => {
|
|
12320
|
+
const timer = setTimeout(() => {
|
|
12321
|
+
const entry = this.pending.get(id);
|
|
12322
|
+
if (!entry) return;
|
|
12323
|
+
this.pending.delete(id);
|
|
12324
|
+
this.write({ type: "cancel", id });
|
|
12325
|
+
const error = new IndexTimeoutError(
|
|
12326
|
+
`Index ${message.type === "request" ? message.op : message.type} exceeded its ${options.timeoutMs}ms watchdog timeout`
|
|
12327
|
+
);
|
|
12328
|
+
this.cleanupPending(entry);
|
|
12329
|
+
entry.reject(error);
|
|
12330
|
+
}, options.timeoutMs);
|
|
12331
|
+
timer.unref?.();
|
|
12332
|
+
const signal = options.signal;
|
|
12333
|
+
const onAbort = signal ? () => {
|
|
12334
|
+
const entry = this.pending.get(id);
|
|
12335
|
+
if (!entry) return;
|
|
12336
|
+
this.pending.delete(id);
|
|
12337
|
+
this.write({ type: "cancel", id });
|
|
12338
|
+
this.cleanupPending(entry);
|
|
12339
|
+
entry.reject(cancellationError(signal));
|
|
12340
|
+
} : void 0;
|
|
12341
|
+
this.pending.set(id, {
|
|
12342
|
+
resolve: resolve17,
|
|
12343
|
+
reject,
|
|
12344
|
+
timer,
|
|
12345
|
+
signal,
|
|
12346
|
+
onAbort,
|
|
12347
|
+
onProgress: options.onProgress
|
|
12348
|
+
});
|
|
12349
|
+
if (signal && onAbort) {
|
|
12350
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
12351
|
+
if (signal.aborted) {
|
|
12352
|
+
onAbort();
|
|
12353
|
+
return;
|
|
12354
|
+
}
|
|
12355
|
+
}
|
|
12356
|
+
this.write({ ...message, id });
|
|
12357
|
+
});
|
|
12358
|
+
}
|
|
12359
|
+
async ensureConnected(spawnIfMissing) {
|
|
12360
|
+
if (this.socket && !this.socket.destroyed && this.info) return;
|
|
12361
|
+
if (this.connecting) return this.connecting;
|
|
12362
|
+
this.transition("connecting");
|
|
12363
|
+
this.connecting = this.connectWithElection(spawnIfMissing).catch((error) => {
|
|
12364
|
+
this.transition("error", { error });
|
|
12365
|
+
throw error;
|
|
12366
|
+
}).finally(() => {
|
|
12367
|
+
this.connecting = null;
|
|
12368
|
+
});
|
|
12369
|
+
return this.connecting;
|
|
12370
|
+
}
|
|
12371
|
+
async connectWithElection(spawnIfMissing) {
|
|
12372
|
+
const deadline = Date.now() + (spawnIfMissing ? SERVER_START_TIMEOUT_MS : CONNECT_ATTEMPT_TIMEOUT_MS);
|
|
12373
|
+
let spawned = false;
|
|
12374
|
+
let staleAttempts = 0;
|
|
12375
|
+
let lastError = new Error("codebase-index server unavailable");
|
|
12376
|
+
while (Date.now() < deadline) {
|
|
12377
|
+
try {
|
|
12378
|
+
await this.connectOnce();
|
|
12379
|
+
return;
|
|
12380
|
+
} catch (error) {
|
|
12381
|
+
lastError = error;
|
|
12382
|
+
if (error instanceof StaleProjectIndexServerError) {
|
|
12383
|
+
staleAttempts++;
|
|
12384
|
+
if (!spawnIfMissing) break;
|
|
12385
|
+
if (staleAttempts >= 3) this.forceKillServer(error.pid);
|
|
12386
|
+
spawned = false;
|
|
12387
|
+
await delay(100);
|
|
12388
|
+
continue;
|
|
12389
|
+
}
|
|
12390
|
+
}
|
|
12391
|
+
if (!spawnIfMissing) break;
|
|
12392
|
+
if (!spawned) {
|
|
12393
|
+
this.spawnDetachedServer();
|
|
12394
|
+
spawned = true;
|
|
12395
|
+
}
|
|
12396
|
+
await delay(75);
|
|
12397
|
+
}
|
|
12398
|
+
throw lastError;
|
|
12399
|
+
}
|
|
12400
|
+
connectOnce() {
|
|
12401
|
+
this.socket?.destroy();
|
|
12402
|
+
this.socket = null;
|
|
12403
|
+
this.info = null;
|
|
12404
|
+
this.activity = null;
|
|
12405
|
+
this.health = null;
|
|
12406
|
+
this.buffer = "";
|
|
12407
|
+
return new Promise((resolve17, reject) => {
|
|
12408
|
+
const socket = net3.createConnection(this.endpoint);
|
|
12409
|
+
this.socket = socket;
|
|
12410
|
+
socket.setEncoding("utf8");
|
|
12411
|
+
const timer = setTimeout(() => {
|
|
12412
|
+
reject(new Error("codebase-index server handshake timed out"));
|
|
12413
|
+
socket.destroy();
|
|
12414
|
+
}, CONNECT_ATTEMPT_TIMEOUT_MS);
|
|
12415
|
+
timer.unref?.();
|
|
12416
|
+
const finishResolve = () => {
|
|
12417
|
+
clearTimeout(timer);
|
|
12418
|
+
this.connectResolve = null;
|
|
12419
|
+
this.connectReject = null;
|
|
12420
|
+
resolve17();
|
|
12421
|
+
};
|
|
12422
|
+
const finishReject = (error) => {
|
|
12423
|
+
clearTimeout(timer);
|
|
12424
|
+
this.connectResolve = null;
|
|
12425
|
+
this.connectReject = null;
|
|
12426
|
+
reject(error);
|
|
12427
|
+
};
|
|
12428
|
+
this.connectResolve = finishResolve;
|
|
12429
|
+
this.connectReject = finishReject;
|
|
12430
|
+
socket.on("data", (chunk) => this.onData(socket, chunk));
|
|
12431
|
+
socket.on("error", (error) => {
|
|
12432
|
+
if (!this.info) finishReject(error);
|
|
12433
|
+
});
|
|
12434
|
+
socket.on("close", () => this.onClose(socket));
|
|
12435
|
+
});
|
|
12436
|
+
}
|
|
12437
|
+
onData(socket, chunk) {
|
|
12438
|
+
if (socket !== this.socket) return;
|
|
12439
|
+
this.buffer += chunk;
|
|
12440
|
+
while (true) {
|
|
12441
|
+
const newline = this.buffer.indexOf("\n");
|
|
12442
|
+
if (newline < 0) {
|
|
12443
|
+
if (this.buffer.length > PROJECT_INDEX_SERVER_MAX_FRAME_CHARS) {
|
|
12444
|
+
socket.destroy(new Error("codebase-index server response exceeds the IPC limit"));
|
|
12445
|
+
}
|
|
12446
|
+
return;
|
|
12447
|
+
}
|
|
12448
|
+
if (newline > PROJECT_INDEX_SERVER_MAX_FRAME_CHARS) {
|
|
12449
|
+
socket.destroy(new Error("codebase-index server response exceeds the IPC limit"));
|
|
12450
|
+
return;
|
|
12451
|
+
}
|
|
12452
|
+
const line = this.buffer.slice(0, newline);
|
|
12453
|
+
this.buffer = this.buffer.slice(newline + 1);
|
|
12454
|
+
if (!line) continue;
|
|
12455
|
+
let message;
|
|
12456
|
+
try {
|
|
12457
|
+
message = JSON.parse(line);
|
|
12458
|
+
} catch {
|
|
12459
|
+
socket.destroy(new Error("invalid codebase-index server response"));
|
|
12460
|
+
return;
|
|
12461
|
+
}
|
|
12462
|
+
this.onMessage(message);
|
|
12463
|
+
}
|
|
12464
|
+
}
|
|
12465
|
+
onMessage(message) {
|
|
12466
|
+
if (message.type === "hello") {
|
|
12467
|
+
if (message.protocolVersion !== PROJECT_INDEX_SERVER_PROTOCOL_VERSION) {
|
|
12468
|
+
this.rejectStaleServer(
|
|
12469
|
+
message,
|
|
12470
|
+
`codebase-index protocol mismatch: client=${PROJECT_INDEX_SERVER_PROTOCOL_VERSION}, server=${message.protocolVersion}`
|
|
12471
|
+
);
|
|
12472
|
+
return;
|
|
12473
|
+
}
|
|
12474
|
+
const expectedBuildId = projectIndexServerExpectedBuildId();
|
|
12475
|
+
if (expectedBuildId && message.buildId !== expectedBuildId) {
|
|
12476
|
+
this.rejectStaleServer(
|
|
12477
|
+
message,
|
|
12478
|
+
`codebase-index build mismatch: client=${expectedBuildId}, server=${message.buildId ?? "legacy"}`
|
|
12479
|
+
);
|
|
12480
|
+
return;
|
|
12481
|
+
}
|
|
12482
|
+
this.info = message;
|
|
12483
|
+
this.markResponsive();
|
|
12484
|
+
this.transition("connected", { pid: message.pid });
|
|
12485
|
+
ensureHeartbeatLoop();
|
|
12486
|
+
this.connectResolve?.();
|
|
12487
|
+
return;
|
|
12488
|
+
}
|
|
12489
|
+
if (message.type === "index-state") {
|
|
12490
|
+
this.activity = message.state;
|
|
12491
|
+
this.markResponsive();
|
|
12492
|
+
this.transition("connected", { pid: this.info?.pid });
|
|
12493
|
+
return;
|
|
12494
|
+
}
|
|
12495
|
+
const entry = this.pending.get(message.id);
|
|
12496
|
+
if (!entry) return;
|
|
12497
|
+
this.markResponsive();
|
|
12498
|
+
const status = connectionStates.get(this.endpoint)?.status;
|
|
12499
|
+
if (status === "degraded" || status === "unresponsive") {
|
|
12500
|
+
this.transition("connected", { pid: this.info?.pid });
|
|
12501
|
+
}
|
|
12502
|
+
if (message.type === "progress") {
|
|
12503
|
+
entry.onProgress?.(message.current, message.total);
|
|
12504
|
+
return;
|
|
12505
|
+
}
|
|
12506
|
+
this.pending.delete(message.id);
|
|
12507
|
+
this.cleanupPending(entry);
|
|
12508
|
+
if (message.ok) entry.resolve(message.result);
|
|
12509
|
+
else entry.reject(remoteError(message.error, message.errorName));
|
|
12510
|
+
}
|
|
12511
|
+
onClose(socket) {
|
|
12512
|
+
if (socket !== this.socket) return;
|
|
12513
|
+
const wasConnected = this.info !== null;
|
|
12900
12514
|
this.socket = null;
|
|
12901
12515
|
this.info = null;
|
|
12902
12516
|
this.activity = null;
|
|
12903
12517
|
this.health = null;
|
|
12904
|
-
|
|
12518
|
+
const error = new Error("codebase-index server connection closed");
|
|
12519
|
+
this.connectReject?.(error);
|
|
12905
12520
|
this.connectResolve = null;
|
|
12906
12521
|
this.connectReject = null;
|
|
12907
|
-
|
|
12908
|
-
this.
|
|
12909
|
-
this.transition("offline");
|
|
12522
|
+
this.rejectPending(error);
|
|
12523
|
+
if (wasConnected) this.transition("error", { error });
|
|
12910
12524
|
maybeStopHeartbeatLoop();
|
|
12911
12525
|
}
|
|
12912
|
-
|
|
12913
|
-
|
|
12914
|
-
if (
|
|
12915
|
-
|
|
12526
|
+
cleanupPending(entry) {
|
|
12527
|
+
clearTimeout(entry.timer);
|
|
12528
|
+
if (entry.signal && entry.onAbort) {
|
|
12529
|
+
entry.signal.removeEventListener("abort", entry.onAbort);
|
|
12916
12530
|
}
|
|
12917
|
-
|
|
12918
|
-
|
|
12919
|
-
|
|
12920
|
-
|
|
12921
|
-
|
|
12922
|
-
|
|
12923
|
-
|
|
12924
|
-
|
|
12925
|
-
|
|
12926
|
-
|
|
12927
|
-
|
|
12928
|
-
|
|
12929
|
-
|
|
12531
|
+
}
|
|
12532
|
+
rejectPending(error) {
|
|
12533
|
+
const entries = [...this.pending.values()];
|
|
12534
|
+
this.pending.clear();
|
|
12535
|
+
for (const entry of entries) {
|
|
12536
|
+
this.cleanupPending(entry);
|
|
12537
|
+
entry.reject(error);
|
|
12538
|
+
}
|
|
12539
|
+
}
|
|
12540
|
+
write(message) {
|
|
12541
|
+
const socket = this.socket;
|
|
12542
|
+
if (socket && !socket.destroyed) socket.write(encodeProjectServerMessage(message));
|
|
12543
|
+
}
|
|
12544
|
+
rejectStaleServer(message, reason) {
|
|
12545
|
+
const socket = this.socket;
|
|
12546
|
+
if (socket && !socket.destroyed) {
|
|
12547
|
+
socket.write(
|
|
12548
|
+
encodeProjectServerMessage({
|
|
12549
|
+
type: "shutdown",
|
|
12550
|
+
id: 0,
|
|
12551
|
+
reason: "stale-build-replacement"
|
|
12552
|
+
})
|
|
12553
|
+
);
|
|
12554
|
+
const timer = setTimeout(() => socket.destroy(), 25);
|
|
12930
12555
|
timer.unref?.();
|
|
12931
|
-
|
|
12932
|
-
|
|
12933
|
-
|
|
12934
|
-
|
|
12935
|
-
|
|
12936
|
-
|
|
12937
|
-
|
|
12938
|
-
|
|
12939
|
-
|
|
12940
|
-
|
|
12941
|
-
resolve: resolve17,
|
|
12942
|
-
reject,
|
|
12943
|
-
timer,
|
|
12944
|
-
signal,
|
|
12945
|
-
onAbort,
|
|
12946
|
-
onProgress: options.onProgress
|
|
12947
|
-
});
|
|
12948
|
-
if (signal && onAbort) {
|
|
12949
|
-
signal.addEventListener("abort", onAbort, { once: true });
|
|
12950
|
-
if (signal.aborted) {
|
|
12951
|
-
onAbort();
|
|
12952
|
-
return;
|
|
12953
|
-
}
|
|
12556
|
+
}
|
|
12557
|
+
this.connectReject?.(new StaleProjectIndexServerError(reason, message.pid));
|
|
12558
|
+
}
|
|
12559
|
+
spawnDetachedServer() {
|
|
12560
|
+
const url = resolveProjectServerUrl();
|
|
12561
|
+
if (!url) throw new Error("built codebase-index project server is unavailable");
|
|
12562
|
+
if (process.platform !== "win32") {
|
|
12563
|
+
try {
|
|
12564
|
+
fs12.rmSync(this.endpoint, { force: true });
|
|
12565
|
+
} catch {
|
|
12954
12566
|
}
|
|
12955
|
-
|
|
12567
|
+
}
|
|
12568
|
+
const args = [fileURLToPath2(url), "--project-root", this.projectRoot];
|
|
12569
|
+
if (this.indexDir) args.push("--index-dir", this.indexDir);
|
|
12570
|
+
const child = spawn4(process.execPath, args, {
|
|
12571
|
+
detached: true,
|
|
12572
|
+
stdio: "ignore",
|
|
12573
|
+
windowsHide: true,
|
|
12574
|
+
env: process.env
|
|
12956
12575
|
});
|
|
12576
|
+
child.unref();
|
|
12957
12577
|
}
|
|
12958
|
-
|
|
12959
|
-
|
|
12960
|
-
|
|
12961
|
-
|
|
12962
|
-
|
|
12963
|
-
|
|
12964
|
-
|
|
12965
|
-
|
|
12966
|
-
this.
|
|
12578
|
+
forceKillKnownServer() {
|
|
12579
|
+
const pid = this.info?.pid;
|
|
12580
|
+
return pid ? this.forceKillServer(pid) : false;
|
|
12581
|
+
}
|
|
12582
|
+
forceKillServer(pid) {
|
|
12583
|
+
if (pid === process.pid) return false;
|
|
12584
|
+
try {
|
|
12585
|
+
process.kill(pid);
|
|
12586
|
+
const metadataPath = projectIndexServerMetadataPath(this.projectRoot, this.indexDir);
|
|
12587
|
+
try {
|
|
12588
|
+
const metadata = JSON.parse(fs12.readFileSync(metadataPath, "utf8"));
|
|
12589
|
+
if (metadata.pid === pid) fs12.rmSync(metadataPath, { force: true });
|
|
12590
|
+
} catch {
|
|
12591
|
+
}
|
|
12592
|
+
return true;
|
|
12593
|
+
} catch {
|
|
12594
|
+
return false;
|
|
12595
|
+
}
|
|
12596
|
+
}
|
|
12597
|
+
};
|
|
12598
|
+
var connections = /* @__PURE__ */ new Map();
|
|
12599
|
+
var heartbeatTimer;
|
|
12600
|
+
function ensureHeartbeatLoop() {
|
|
12601
|
+
if (heartbeatTimer) return;
|
|
12602
|
+
heartbeatTimer = setInterval(() => {
|
|
12603
|
+
for (const connection of connections.values()) {
|
|
12604
|
+
if (connection.isConnected()) void connection.checkHealth(false).catch(() => {
|
|
12605
|
+
});
|
|
12606
|
+
}
|
|
12607
|
+
}, SERVER_HEARTBEAT_INTERVAL_MS);
|
|
12608
|
+
heartbeatTimer.unref?.();
|
|
12609
|
+
}
|
|
12610
|
+
function maybeStopHeartbeatLoop() {
|
|
12611
|
+
if (!heartbeatTimer) return;
|
|
12612
|
+
if ([...connections.values()].some((connection) => connection.isConnected())) return;
|
|
12613
|
+
clearInterval(heartbeatTimer);
|
|
12614
|
+
heartbeatTimer = void 0;
|
|
12615
|
+
}
|
|
12616
|
+
function connectionFor(projectRoot, indexDir) {
|
|
12617
|
+
const endpoint = projectIndexServerEndpoint(projectRoot, indexDir);
|
|
12618
|
+
let connection = connections.get(endpoint);
|
|
12619
|
+
if (!connection) {
|
|
12620
|
+
connection = new ProjectServerConnection(projectRoot, indexDir, endpoint);
|
|
12621
|
+
connections.set(endpoint, connection);
|
|
12622
|
+
}
|
|
12623
|
+
return connection;
|
|
12624
|
+
}
|
|
12625
|
+
function callProjectIndexServer(op, args, options) {
|
|
12626
|
+
return connectionFor(args.projectRoot, args.indexDir).call(op, args, options);
|
|
12627
|
+
}
|
|
12628
|
+
function ensureProjectIndexServer(options) {
|
|
12629
|
+
return connectionFor(options.projectRoot, options.indexDir).configure(
|
|
12630
|
+
options.watchExternal,
|
|
12631
|
+
options.debounceMs
|
|
12632
|
+
);
|
|
12633
|
+
}
|
|
12634
|
+
function checkProjectIndexServerHealth(projectRoot, indexDir, options = {}) {
|
|
12635
|
+
return connectionFor(projectRoot, indexDir).checkHealth(
|
|
12636
|
+
false,
|
|
12637
|
+
options.timeoutMs ?? SERVER_HEALTH_TIMEOUT_MS
|
|
12638
|
+
);
|
|
12639
|
+
}
|
|
12640
|
+
async function shutdownProjectIndexServer(projectRoot, indexDir, reason) {
|
|
12641
|
+
const endpoint = projectIndexServerEndpoint(projectRoot, indexDir);
|
|
12642
|
+
const connection = connectionFor(projectRoot, indexDir);
|
|
12643
|
+
try {
|
|
12644
|
+
return await connection.shutdownRemote(reason);
|
|
12645
|
+
} finally {
|
|
12646
|
+
connection.close();
|
|
12647
|
+
connections.delete(endpoint);
|
|
12648
|
+
connectionStates.delete(endpoint);
|
|
12649
|
+
}
|
|
12650
|
+
}
|
|
12651
|
+
function closeProjectIndexServerClients() {
|
|
12652
|
+
for (const connection of connections.values()) connection.close();
|
|
12653
|
+
connections.clear();
|
|
12654
|
+
connectionStates.clear();
|
|
12655
|
+
latestConnectionState = {
|
|
12656
|
+
status: isProjectIndexServerAvailable() ? "offline" : "unavailable",
|
|
12657
|
+
connected: false
|
|
12658
|
+
};
|
|
12659
|
+
if (heartbeatTimer) clearInterval(heartbeatTimer);
|
|
12660
|
+
heartbeatTimer = void 0;
|
|
12661
|
+
}
|
|
12662
|
+
|
|
12663
|
+
// src/codebase-index/background-indexer.ts
|
|
12664
|
+
import * as fs18 from "node:fs";
|
|
12665
|
+
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
12666
|
+
import { Worker } from "node:worker_threads";
|
|
12667
|
+
|
|
12668
|
+
// src/codebase-index/indexer.ts
|
|
12669
|
+
import { expectDefined as expectDefined6 } from "@wrongstack/core/utils";
|
|
12670
|
+
import { execFile as execFile2 } from "node:child_process";
|
|
12671
|
+
import * as fs17 from "node:fs/promises";
|
|
12672
|
+
import { availableParallelism } from "node:os";
|
|
12673
|
+
import * as path23 from "node:path";
|
|
12674
|
+
import {
|
|
12675
|
+
DEFAULT_WALK_IGNORE_DIRS,
|
|
12676
|
+
indexParallelBatchSize,
|
|
12677
|
+
isFrugalPerf
|
|
12678
|
+
} from "@wrongstack/core/utils";
|
|
12679
|
+
|
|
12680
|
+
// src/codebase-index/gitignore.ts
|
|
12681
|
+
import * as fs13 from "node:fs/promises";
|
|
12682
|
+
import * as path17 from "node:path";
|
|
12683
|
+
import { compileGlob } from "@wrongstack/core/utils";
|
|
12684
|
+
function globBody(glob) {
|
|
12685
|
+
return compileGlob(glob).source.replace(/^\^/, "").replace(/\$$/, "");
|
|
12686
|
+
}
|
|
12687
|
+
function compileGitignore(lines) {
|
|
12688
|
+
const rules = [];
|
|
12689
|
+
for (const raw of lines) {
|
|
12690
|
+
let line = raw.replace(/\r$/, "");
|
|
12691
|
+
if (!line.trim() || line.trimStart().startsWith("#")) continue;
|
|
12692
|
+
line = line.trim();
|
|
12693
|
+
let negated = false;
|
|
12694
|
+
if (line.startsWith("!")) {
|
|
12695
|
+
negated = true;
|
|
12696
|
+
line = line.slice(1);
|
|
12697
|
+
}
|
|
12698
|
+
let dirOnly = false;
|
|
12699
|
+
if (line.endsWith("/")) {
|
|
12700
|
+
dirOnly = true;
|
|
12701
|
+
line = line.slice(0, -1);
|
|
12702
|
+
}
|
|
12703
|
+
if (!line) continue;
|
|
12704
|
+
const anchored = line.startsWith("/") || line.includes("/");
|
|
12705
|
+
if (line.startsWith("/")) line = line.slice(1);
|
|
12706
|
+
const body = globBody(line);
|
|
12707
|
+
const prefix = anchored ? "^" : "(?:^|.*/)";
|
|
12708
|
+
rules.push({
|
|
12709
|
+
eqOrUnder: new RegExp(`${prefix}${body}(?:/.*)?$`),
|
|
12710
|
+
under: new RegExp(`${prefix}${body}/.*$`),
|
|
12711
|
+
negated,
|
|
12712
|
+
dirOnly
|
|
12967
12713
|
});
|
|
12968
|
-
return this.connecting;
|
|
12969
12714
|
}
|
|
12970
|
-
|
|
12971
|
-
const
|
|
12972
|
-
let
|
|
12973
|
-
|
|
12974
|
-
|
|
12975
|
-
|
|
12976
|
-
try {
|
|
12977
|
-
await this.connectOnce();
|
|
12978
|
-
return;
|
|
12979
|
-
} catch (error) {
|
|
12980
|
-
lastError = error;
|
|
12981
|
-
if (error instanceof StaleProjectIndexServerError) {
|
|
12982
|
-
staleAttempts++;
|
|
12983
|
-
if (!spawnIfMissing) break;
|
|
12984
|
-
if (staleAttempts >= 3) this.forceKillServer(error.pid);
|
|
12985
|
-
spawned = false;
|
|
12986
|
-
await delay(100);
|
|
12987
|
-
continue;
|
|
12988
|
-
}
|
|
12989
|
-
}
|
|
12990
|
-
if (!spawnIfMissing) break;
|
|
12991
|
-
if (!spawned) {
|
|
12992
|
-
this.spawnDetachedServer();
|
|
12993
|
-
spawned = true;
|
|
12994
|
-
}
|
|
12995
|
-
await delay(75);
|
|
12715
|
+
return (relPath, isDir) => {
|
|
12716
|
+
const p = relPath.replace(/\\/g, "/").replace(/^\/+/, "");
|
|
12717
|
+
let ignored = false;
|
|
12718
|
+
for (const r of rules) {
|
|
12719
|
+
const re = r.dirOnly && !isDir ? r.under : r.eqOrUnder;
|
|
12720
|
+
if (re.test(p)) ignored = !r.negated;
|
|
12996
12721
|
}
|
|
12997
|
-
|
|
12722
|
+
return ignored;
|
|
12723
|
+
};
|
|
12724
|
+
}
|
|
12725
|
+
async function loadGitignoreMatcher(projectRoot) {
|
|
12726
|
+
let lines = [];
|
|
12727
|
+
try {
|
|
12728
|
+
const raw = await fs13.readFile(path17.join(projectRoot, ".gitignore"), "utf8");
|
|
12729
|
+
lines = raw.split("\n");
|
|
12730
|
+
} catch {
|
|
12998
12731
|
}
|
|
12999
|
-
|
|
13000
|
-
|
|
13001
|
-
|
|
13002
|
-
|
|
13003
|
-
|
|
13004
|
-
|
|
13005
|
-
|
|
13006
|
-
|
|
13007
|
-
|
|
13008
|
-
|
|
13009
|
-
|
|
13010
|
-
|
|
13011
|
-
|
|
13012
|
-
|
|
13013
|
-
|
|
13014
|
-
|
|
13015
|
-
|
|
13016
|
-
|
|
13017
|
-
|
|
13018
|
-
|
|
13019
|
-
|
|
13020
|
-
};
|
|
13021
|
-
|
|
13022
|
-
|
|
13023
|
-
|
|
13024
|
-
|
|
13025
|
-
|
|
13026
|
-
|
|
13027
|
-
|
|
13028
|
-
|
|
13029
|
-
|
|
13030
|
-
|
|
13031
|
-
|
|
13032
|
-
});
|
|
13033
|
-
|
|
13034
|
-
}
|
|
12732
|
+
return compileGitignore(lines);
|
|
12733
|
+
}
|
|
12734
|
+
|
|
12735
|
+
// src/codebase-index/indexer.ts
|
|
12736
|
+
init_languages2();
|
|
12737
|
+
|
|
12738
|
+
// src/codebase-index/parser-dispatch.ts
|
|
12739
|
+
async function parseFileContent(file, content, lang) {
|
|
12740
|
+
switch (lang) {
|
|
12741
|
+
case "ts":
|
|
12742
|
+
case "tsx":
|
|
12743
|
+
case "js":
|
|
12744
|
+
case "jsx": {
|
|
12745
|
+
const { parseSymbols: parseSymbols8 } = await Promise.resolve().then(() => (init_ts_parser(), ts_parser_exports));
|
|
12746
|
+
return parseSymbols8({ file, content, lang });
|
|
12747
|
+
}
|
|
12748
|
+
case "go": {
|
|
12749
|
+
const { parseSymbols: parseSymbols8 } = await Promise.resolve().then(() => (init_go_parser(), go_parser_exports));
|
|
12750
|
+
return parseSymbols8({ file, content, lang: "go" });
|
|
12751
|
+
}
|
|
12752
|
+
case "py": {
|
|
12753
|
+
const { parseSymbols: parseSymbols8 } = await Promise.resolve().then(() => (init_py_parser(), py_parser_exports));
|
|
12754
|
+
return parseSymbols8({ file, content, lang: "py" });
|
|
12755
|
+
}
|
|
12756
|
+
case "rs": {
|
|
12757
|
+
const { parseSymbols: parseSymbols8 } = await Promise.resolve().then(() => (init_rs_parser(), rs_parser_exports));
|
|
12758
|
+
return parseSymbols8({ file, content, lang: "rs" });
|
|
12759
|
+
}
|
|
12760
|
+
case "json": {
|
|
12761
|
+
const { parseSymbols: parseSymbols8 } = await Promise.resolve().then(() => (init_json_parser(), json_parser_exports));
|
|
12762
|
+
return parseSymbols8({ file, content, lang: "json" });
|
|
12763
|
+
}
|
|
12764
|
+
case "yaml": {
|
|
12765
|
+
const { parseSymbols: parseSymbols8 } = await Promise.resolve().then(() => (init_yaml_parser(), yaml_parser_exports));
|
|
12766
|
+
return parseSymbols8({ file, content, lang: "yaml" });
|
|
12767
|
+
}
|
|
12768
|
+
default: {
|
|
12769
|
+
const { parseSymbols: parseSymbols8 } = await Promise.resolve().then(() => (init_generic_parser(), generic_parser_exports));
|
|
12770
|
+
return parseSymbols8({ file, content, lang });
|
|
12771
|
+
}
|
|
13035
12772
|
}
|
|
13036
|
-
|
|
13037
|
-
|
|
13038
|
-
|
|
13039
|
-
|
|
13040
|
-
|
|
13041
|
-
|
|
13042
|
-
|
|
13043
|
-
|
|
13044
|
-
|
|
13045
|
-
|
|
13046
|
-
|
|
13047
|
-
|
|
13048
|
-
|
|
13049
|
-
|
|
12773
|
+
}
|
|
12774
|
+
|
|
12775
|
+
// src/codebase-index/indexer.ts
|
|
12776
|
+
var YIELD_EVERY_N = 50;
|
|
12777
|
+
function resolveParallelBatch() {
|
|
12778
|
+
return indexParallelBatchSize(availableParallelism());
|
|
12779
|
+
}
|
|
12780
|
+
function yieldEventLoop() {
|
|
12781
|
+
return new Promise((resolve17) => setImmediate(resolve17));
|
|
12782
|
+
}
|
|
12783
|
+
function throwIfAborted(signal) {
|
|
12784
|
+
if (!signal?.aborted) return;
|
|
12785
|
+
if (signal.reason instanceof Error) throw signal.reason;
|
|
12786
|
+
throw new Error(typeof signal.reason === "string" ? signal.reason : "Indexing cancelled");
|
|
12787
|
+
}
|
|
12788
|
+
function isAbortError(err) {
|
|
12789
|
+
return err instanceof DOMException && err.name === "AbortError";
|
|
12790
|
+
}
|
|
12791
|
+
var DEFAULT_IGNORE = DEFAULT_WALK_IGNORE_DIRS;
|
|
12792
|
+
var DEFAULT_IGNORE_FILES = /* @__PURE__ */ new Set(["package-lock.json", "pnpm-lock.yaml", "pnpm-lock.yml"]);
|
|
12793
|
+
var INDEXABLE_EXTENSION_SET = new Set(INDEXABLE_EXTENSIONS);
|
|
12794
|
+
var MAX_INDEX_FILE_BYTES = 5 * 1024 * 1024;
|
|
12795
|
+
var MAX_GIT_FILE_LIST_BYTES = 64 * 1024 * 1024;
|
|
12796
|
+
function isWithinProject(projectRoot, file) {
|
|
12797
|
+
const rel = path23.relative(projectRoot, file);
|
|
12798
|
+
return rel !== "" && !rel.startsWith(`..${path23.sep}`) && rel !== ".." && !path23.isAbsolute(rel);
|
|
12799
|
+
}
|
|
12800
|
+
function isMissingPathError(err) {
|
|
12801
|
+
const code = err?.code;
|
|
12802
|
+
return code === "ENOENT" || code === "ENOTDIR";
|
|
12803
|
+
}
|
|
12804
|
+
function normalizeComparablePath(value) {
|
|
12805
|
+
const resolved = path23.resolve(value);
|
|
12806
|
+
return process.platform === "win32" ? resolved.toLowerCase() : resolved;
|
|
12807
|
+
}
|
|
12808
|
+
function gitOutput(projectRoot, args) {
|
|
12809
|
+
return new Promise((resolve17, reject) => {
|
|
12810
|
+
execFile2(
|
|
12811
|
+
"git",
|
|
12812
|
+
["-C", projectRoot, ...args],
|
|
12813
|
+
{
|
|
12814
|
+
encoding: "buffer",
|
|
12815
|
+
maxBuffer: MAX_GIT_FILE_LIST_BYTES,
|
|
12816
|
+
windowsHide: true
|
|
12817
|
+
},
|
|
12818
|
+
(error, stdout) => {
|
|
12819
|
+
if (error) reject(error);
|
|
12820
|
+
else resolve17(Buffer.isBuffer(stdout) ? stdout : Buffer.from(stdout));
|
|
13050
12821
|
}
|
|
13051
|
-
|
|
13052
|
-
|
|
13053
|
-
|
|
13054
|
-
|
|
13055
|
-
|
|
13056
|
-
|
|
13057
|
-
|
|
13058
|
-
|
|
13059
|
-
|
|
12822
|
+
);
|
|
12823
|
+
});
|
|
12824
|
+
}
|
|
12825
|
+
async function findGitSourceFiles(projectRoot, ignore, signal) {
|
|
12826
|
+
try {
|
|
12827
|
+
throwIfAborted(signal);
|
|
12828
|
+
const topLevel = (await gitOutput(projectRoot, ["rev-parse", "--show-toplevel"])).toString("utf8").trim();
|
|
12829
|
+
if (normalizeComparablePath(topLevel) !== normalizeComparablePath(projectRoot)) return null;
|
|
12830
|
+
throwIfAborted(signal);
|
|
12831
|
+
const ignoreSet = /* @__PURE__ */ new Set([...DEFAULT_IGNORE, ...ignore]);
|
|
12832
|
+
const [output, statusOutput] = await Promise.all([
|
|
12833
|
+
gitOutput(projectRoot, ["ls-files", "--cached", "--others", "--exclude-standard", "-z"]),
|
|
12834
|
+
gitOutput(projectRoot, [
|
|
12835
|
+
"status",
|
|
12836
|
+
"--porcelain=v1",
|
|
12837
|
+
"-z",
|
|
12838
|
+
"--untracked-files=all",
|
|
12839
|
+
"--ignored=no"
|
|
12840
|
+
])
|
|
12841
|
+
]);
|
|
12842
|
+
throwIfAborted(signal);
|
|
12843
|
+
const dirty = /* @__PURE__ */ new Set();
|
|
12844
|
+
const deleted = /* @__PURE__ */ new Set();
|
|
12845
|
+
const statusRecords = statusOutput.toString("utf8").split("\0");
|
|
12846
|
+
for (let i = 0; i < statusRecords.length; i++) {
|
|
12847
|
+
const record = statusRecords[i];
|
|
12848
|
+
if (!record) continue;
|
|
12849
|
+
const status = record.slice(0, 2);
|
|
12850
|
+
const changedPath = path23.resolve(projectRoot, record.slice(3));
|
|
12851
|
+
dirty.add(changedPath);
|
|
12852
|
+
if (status.includes("D")) deleted.add(changedPath);
|
|
12853
|
+
if (status.includes("R") || status.includes("C")) {
|
|
12854
|
+
const source = statusRecords[++i];
|
|
12855
|
+
if (source) dirty.add(path23.resolve(projectRoot, source));
|
|
13060
12856
|
}
|
|
13061
|
-
this.onMessage(message);
|
|
13062
12857
|
}
|
|
13063
|
-
|
|
13064
|
-
|
|
13065
|
-
|
|
13066
|
-
|
|
13067
|
-
|
|
13068
|
-
|
|
13069
|
-
`codebase-index protocol mismatch: client=${PROJECT_INDEX_SERVER_PROTOCOL_VERSION}, server=${message.protocolVersion}`
|
|
13070
|
-
);
|
|
13071
|
-
return;
|
|
13072
|
-
}
|
|
13073
|
-
const expectedBuildId = projectIndexServerExpectedBuildId();
|
|
13074
|
-
if (expectedBuildId && message.buildId !== expectedBuildId) {
|
|
13075
|
-
this.rejectStaleServer(
|
|
13076
|
-
message,
|
|
13077
|
-
`codebase-index build mismatch: client=${expectedBuildId}, server=${message.buildId ?? "legacy"}`
|
|
13078
|
-
);
|
|
13079
|
-
return;
|
|
12858
|
+
const files = [];
|
|
12859
|
+
for (const relative13 of output.toString("utf8").split("\0")) {
|
|
12860
|
+
if (!relative13) continue;
|
|
12861
|
+
const portable = relative13.replace(/\\/g, "/");
|
|
12862
|
+
if (portable.split("/").some((segment) => ignoreSet.has(segment)) || DEFAULT_IGNORE_FILES.has(path23.posix.basename(portable))) {
|
|
12863
|
+
continue;
|
|
13080
12864
|
}
|
|
13081
|
-
|
|
13082
|
-
|
|
13083
|
-
|
|
13084
|
-
|
|
13085
|
-
|
|
13086
|
-
|
|
12865
|
+
const full = path23.resolve(projectRoot, relative13);
|
|
12866
|
+
if (deleted.has(full)) continue;
|
|
12867
|
+
const ext = path23.extname(relative13).toLowerCase();
|
|
12868
|
+
if (INDEXABLE_EXTENSION_SET.has(ext) || detectLang(full) !== null) files.push(full);
|
|
12869
|
+
}
|
|
12870
|
+
return {
|
|
12871
|
+
files,
|
|
12872
|
+
trustedUnchanged: new Set(files.filter((file) => !dirty.has(file)))
|
|
12873
|
+
};
|
|
12874
|
+
} catch {
|
|
12875
|
+
return null;
|
|
12876
|
+
}
|
|
12877
|
+
}
|
|
12878
|
+
async function findSourceFiles(projectRoot, ignore, isGitIgnored, signal) {
|
|
12879
|
+
const gitFiles = await findGitSourceFiles(projectRoot, ignore, signal);
|
|
12880
|
+
if (gitFiles) {
|
|
12881
|
+
return {
|
|
12882
|
+
files: gitFiles.files,
|
|
12883
|
+
complete: true,
|
|
12884
|
+
errors: [],
|
|
12885
|
+
trustedUnchanged: gitFiles.trustedUnchanged
|
|
12886
|
+
};
|
|
12887
|
+
}
|
|
12888
|
+
const results = [];
|
|
12889
|
+
const errors = [];
|
|
12890
|
+
let complete = true;
|
|
12891
|
+
const ignoreSet = /* @__PURE__ */ new Set([...DEFAULT_IGNORE, ...ignore]);
|
|
12892
|
+
const indexableExts = new Set(INDEXABLE_EXTENSIONS);
|
|
12893
|
+
let dirCount = 0;
|
|
12894
|
+
const walk2 = async (dir) => {
|
|
12895
|
+
throwIfAborted(signal);
|
|
12896
|
+
if (dirCount > 0 && dirCount % YIELD_EVERY_N === 0) {
|
|
12897
|
+
await yieldEventLoop();
|
|
12898
|
+
throwIfAborted(signal);
|
|
13087
12899
|
}
|
|
13088
|
-
|
|
13089
|
-
|
|
13090
|
-
|
|
13091
|
-
|
|
12900
|
+
let entries;
|
|
12901
|
+
try {
|
|
12902
|
+
entries = await fs17.readdir(dir, { withFileTypes: true });
|
|
12903
|
+
} catch (err) {
|
|
12904
|
+
complete = false;
|
|
12905
|
+
errors.push(`scan error: ${dir}: ${err instanceof Error ? err.message : String(err)}`);
|
|
13092
12906
|
return;
|
|
13093
12907
|
}
|
|
13094
|
-
|
|
13095
|
-
|
|
13096
|
-
|
|
13097
|
-
|
|
13098
|
-
|
|
13099
|
-
|
|
12908
|
+
dirCount++;
|
|
12909
|
+
for (const e of entries) {
|
|
12910
|
+
if (ignoreSet.has(e.name)) continue;
|
|
12911
|
+
const full = path23.join(dir, e.name);
|
|
12912
|
+
const rel = path23.relative(projectRoot, full).replace(/\\/g, "/");
|
|
12913
|
+
if (e.isDirectory()) {
|
|
12914
|
+
if (isGitIgnored(rel, true)) continue;
|
|
12915
|
+
await walk2(full);
|
|
12916
|
+
} else if (e.isFile()) {
|
|
12917
|
+
if (DEFAULT_IGNORE_FILES.has(e.name) || isGitIgnored(rel, false)) continue;
|
|
12918
|
+
const ext = path23.extname(e.name).toLowerCase();
|
|
12919
|
+
if (indexableExts.has(ext) || detectLang(full) !== null) {
|
|
12920
|
+
results.push(full);
|
|
12921
|
+
}
|
|
12922
|
+
}
|
|
13100
12923
|
}
|
|
13101
|
-
|
|
13102
|
-
|
|
13103
|
-
|
|
12924
|
+
};
|
|
12925
|
+
await walk2(projectRoot);
|
|
12926
|
+
return { files: results, complete, errors };
|
|
12927
|
+
}
|
|
12928
|
+
function assignRefsToSymbols2(refs, symbols) {
|
|
12929
|
+
if (refs.length === 0 || symbols.length === 0) return [];
|
|
12930
|
+
const ordered = [...symbols].sort((a, b) => a.line - b.line || a.col - b.col || a.id - b.id);
|
|
12931
|
+
const seen = /* @__PURE__ */ new Set();
|
|
12932
|
+
const assigned = [];
|
|
12933
|
+
for (const ref of refs) {
|
|
12934
|
+
let owner2;
|
|
12935
|
+
for (const symbol of ordered) {
|
|
12936
|
+
if (symbol.line > ref.line) break;
|
|
12937
|
+
owner2 = symbol;
|
|
13104
12938
|
}
|
|
13105
|
-
|
|
13106
|
-
|
|
13107
|
-
|
|
13108
|
-
|
|
12939
|
+
if (!owner2 && ref.callType === "import") owner2 = ordered[0];
|
|
12940
|
+
if (!owner2 || owner2.id <= 0) continue;
|
|
12941
|
+
const key = `${owner2.id}:${ref.toName}:${ref.callType}`;
|
|
12942
|
+
if (seen.has(key)) continue;
|
|
12943
|
+
seen.add(key);
|
|
12944
|
+
assigned.push({ ...ref, fromId: owner2.id });
|
|
13109
12945
|
}
|
|
13110
|
-
|
|
13111
|
-
|
|
13112
|
-
|
|
13113
|
-
|
|
13114
|
-
|
|
13115
|
-
|
|
13116
|
-
|
|
13117
|
-
|
|
13118
|
-
|
|
13119
|
-
|
|
13120
|
-
|
|
13121
|
-
|
|
13122
|
-
|
|
13123
|
-
|
|
12946
|
+
return assigned;
|
|
12947
|
+
}
|
|
12948
|
+
async function runIndexerWithStore(store, opts) {
|
|
12949
|
+
const { projectRoot, langs, ignore = [], signal } = opts;
|
|
12950
|
+
const relationGraphVersion = "2";
|
|
12951
|
+
const refResolutionVersion = "2";
|
|
12952
|
+
const force = (opts.force ?? false) || store.getMetadata("relation_graph_version") !== relationGraphVersion;
|
|
12953
|
+
const needsFullRefResolution = force || store.getMetadata("ref_resolution_version") !== refResolutionVersion;
|
|
12954
|
+
const startMs = Date.now();
|
|
12955
|
+
const errors = [];
|
|
12956
|
+
const langStats = {};
|
|
12957
|
+
let filesIndexed = 0;
|
|
12958
|
+
let symbolsIndexed = 0;
|
|
12959
|
+
const isGitIgnored = await loadGitignoreMatcher(projectRoot);
|
|
12960
|
+
let files;
|
|
12961
|
+
let discoveredFiles = null;
|
|
12962
|
+
let discoveryComplete = true;
|
|
12963
|
+
let trustedUnchanged;
|
|
12964
|
+
if (opts.files && opts.files.length > 0) {
|
|
12965
|
+
files = opts.files.map((f) => path23.resolve(projectRoot, f)).filter((f) => {
|
|
12966
|
+
if (!isWithinProject(projectRoot, f)) return false;
|
|
12967
|
+
const rel = path23.relative(projectRoot, f).replace(/\\/g, "/");
|
|
12968
|
+
return !rel.split("/").some((seg) => DEFAULT_IGNORE.includes(seg)) && !DEFAULT_IGNORE_FILES.has(path23.basename(f)) && !isGitIgnored(rel, false);
|
|
12969
|
+
});
|
|
12970
|
+
} else {
|
|
12971
|
+
const discovery = await findSourceFiles(projectRoot, ignore, isGitIgnored, signal);
|
|
12972
|
+
files = discovery.files;
|
|
12973
|
+
errors.push(...discovery.errors);
|
|
12974
|
+
discoveryComplete = discovery.complete;
|
|
12975
|
+
discoveredFiles = new Set(files);
|
|
12976
|
+
trustedUnchanged = discovery.trustedUnchanged;
|
|
13124
12977
|
}
|
|
13125
|
-
|
|
13126
|
-
|
|
13127
|
-
|
|
13128
|
-
|
|
13129
|
-
|
|
12978
|
+
if (langs && langs.length > 0) {
|
|
12979
|
+
const langSet = new Set(langs);
|
|
12980
|
+
files = files.filter((f) => {
|
|
12981
|
+
const lang = detectLang(f);
|
|
12982
|
+
return lang ? langSet.has(lang) : false;
|
|
12983
|
+
});
|
|
13130
12984
|
}
|
|
13131
|
-
|
|
13132
|
-
|
|
13133
|
-
|
|
13134
|
-
for (const
|
|
13135
|
-
this.cleanupPending(entry);
|
|
13136
|
-
entry.reject(error);
|
|
13137
|
-
}
|
|
12985
|
+
if (force) store.clearAll();
|
|
12986
|
+
const existingMeta = /* @__PURE__ */ new Map();
|
|
12987
|
+
if (!force) {
|
|
12988
|
+
for (const meta of store.getAllFileMetas()) existingMeta.set(meta.file, meta);
|
|
13138
12989
|
}
|
|
13139
|
-
|
|
13140
|
-
|
|
13141
|
-
|
|
12990
|
+
const totalFilesForProgress = files.length;
|
|
12991
|
+
let filesPreSkipped = 0;
|
|
12992
|
+
if (!force && trustedUnchanged) {
|
|
12993
|
+
files = files.filter((file) => {
|
|
12994
|
+
const meta = existingMeta.get(file);
|
|
12995
|
+
if (!meta || !trustedUnchanged.has(file)) return true;
|
|
12996
|
+
langStats[meta.lang] = (langStats[meta.lang] ?? 0) + meta.symbolCount;
|
|
12997
|
+
symbolsIndexed += meta.symbolCount;
|
|
12998
|
+
filesIndexed++;
|
|
12999
|
+
filesPreSkipped++;
|
|
13000
|
+
return false;
|
|
13001
|
+
});
|
|
13002
|
+
if (filesPreSkipped > 0) opts.onProgress?.(filesPreSkipped, totalFilesForProgress);
|
|
13142
13003
|
}
|
|
13143
|
-
|
|
13144
|
-
|
|
13145
|
-
|
|
13146
|
-
|
|
13147
|
-
|
|
13148
|
-
|
|
13149
|
-
|
|
13150
|
-
|
|
13151
|
-
|
|
13152
|
-
);
|
|
13153
|
-
|
|
13154
|
-
|
|
13004
|
+
const parallelBatch = resolveParallelBatch();
|
|
13005
|
+
let filesSinceLastYield = 0;
|
|
13006
|
+
for (let batchStart = 0; batchStart < files.length; batchStart += parallelBatch) {
|
|
13007
|
+
const batchEnd = Math.min(batchStart + parallelBatch, files.length);
|
|
13008
|
+
const batchFiles = files.slice(batchStart, batchEnd);
|
|
13009
|
+
opts.onProgress?.(filesPreSkipped + batchEnd, totalFilesForProgress);
|
|
13010
|
+
filesSinceLastYield += batchFiles.length;
|
|
13011
|
+
if (filesSinceLastYield >= YIELD_EVERY_N) {
|
|
13012
|
+
filesSinceLastYield = 0;
|
|
13013
|
+
await yieldEventLoop();
|
|
13014
|
+
if (isFrugalPerf()) {
|
|
13015
|
+
await new Promise((r) => setTimeout(r, 8));
|
|
13016
|
+
}
|
|
13017
|
+
throwIfAborted(signal);
|
|
13018
|
+
}
|
|
13019
|
+
const statOpts = signal ? { signal } : {};
|
|
13020
|
+
const statReadParse = await Promise.allSettled(
|
|
13021
|
+
batchFiles.map(
|
|
13022
|
+
async (file) => {
|
|
13023
|
+
let stat18;
|
|
13024
|
+
try {
|
|
13025
|
+
stat18 = await fs17.stat(file, statOpts);
|
|
13026
|
+
} catch (e) {
|
|
13027
|
+
if (isAbortError(e)) throw e;
|
|
13028
|
+
return {
|
|
13029
|
+
file,
|
|
13030
|
+
stat: null,
|
|
13031
|
+
lang: "",
|
|
13032
|
+
parsed: null,
|
|
13033
|
+
error: `stat error: ${e instanceof Error ? e.message : String(e)}`,
|
|
13034
|
+
missing: isMissingPathError(e)
|
|
13035
|
+
};
|
|
13036
|
+
}
|
|
13037
|
+
if (!stat18.isFile()) return { file, stat: stat18, lang: "", parsed: null };
|
|
13038
|
+
const lang = detectLang(file);
|
|
13039
|
+
if (!lang) return { file, stat: stat18, lang: "", parsed: null };
|
|
13040
|
+
if (stat18.size > MAX_INDEX_FILE_BYTES) {
|
|
13041
|
+
return {
|
|
13042
|
+
file,
|
|
13043
|
+
stat: stat18,
|
|
13044
|
+
lang,
|
|
13045
|
+
parsed: null,
|
|
13046
|
+
error: `file too large (${stat18.size} bytes; max ${MAX_INDEX_FILE_BYTES})`
|
|
13047
|
+
};
|
|
13048
|
+
}
|
|
13049
|
+
const meta = existingMeta.get(file);
|
|
13050
|
+
if (!force && meta && meta.mtimeMs === Math.floor(stat18.mtimeMs)) {
|
|
13051
|
+
return { file, stat: stat18, lang, parsed: null, skippedMeta: meta };
|
|
13052
|
+
}
|
|
13053
|
+
let content;
|
|
13054
|
+
try {
|
|
13055
|
+
content = await fs17.readFile(file, { encoding: "utf8", signal });
|
|
13056
|
+
} catch (e) {
|
|
13057
|
+
if (isAbortError(e)) throw e;
|
|
13058
|
+
return {
|
|
13059
|
+
file,
|
|
13060
|
+
stat: stat18,
|
|
13061
|
+
lang,
|
|
13062
|
+
parsed: null,
|
|
13063
|
+
error: `read error: ${e instanceof Error ? e.message : String(e)}`
|
|
13064
|
+
};
|
|
13065
|
+
}
|
|
13066
|
+
let parsed;
|
|
13067
|
+
try {
|
|
13068
|
+
parsed = await parseFileContent(file, content, lang);
|
|
13069
|
+
} catch (e) {
|
|
13070
|
+
return {
|
|
13071
|
+
file,
|
|
13072
|
+
stat: stat18,
|
|
13073
|
+
lang,
|
|
13074
|
+
parsed: null,
|
|
13075
|
+
error: `parse error: ${e instanceof Error ? e.message : String(e)}`
|
|
13076
|
+
};
|
|
13077
|
+
}
|
|
13078
|
+
return { file, stat: stat18, lang, parsed, content };
|
|
13079
|
+
}
|
|
13080
|
+
)
|
|
13081
|
+
);
|
|
13082
|
+
const batchEntries = [];
|
|
13083
|
+
const deleteForFiles = [];
|
|
13084
|
+
for (let fi = 0; fi < statReadParse.length; fi++) {
|
|
13085
|
+
const settled = statReadParse[fi];
|
|
13086
|
+
const file = expectDefined6(batchFiles[fi]);
|
|
13087
|
+
if (settled.status === "rejected") {
|
|
13088
|
+
const err = settled.reason;
|
|
13089
|
+
if (err instanceof Error && isAbortError(err)) throw err;
|
|
13090
|
+
errors.push(`batch error: ${file}: ${err instanceof Error ? err.message : String(err)}`);
|
|
13091
|
+
continue;
|
|
13092
|
+
}
|
|
13093
|
+
const result = settled.value;
|
|
13094
|
+
if (result.error) {
|
|
13095
|
+
if (result.missing) store.deleteFile(file);
|
|
13096
|
+
errors.push(`${file}: ${result.error}`);
|
|
13097
|
+
continue;
|
|
13098
|
+
}
|
|
13099
|
+
const { stat: stat18, lang, parsed } = result;
|
|
13100
|
+
if (result.skippedMeta) {
|
|
13101
|
+
langStats[lang] = (langStats[lang] ?? 0) + result.skippedMeta.symbolCount;
|
|
13102
|
+
symbolsIndexed += result.skippedMeta.symbolCount;
|
|
13103
|
+
filesIndexed++;
|
|
13104
|
+
continue;
|
|
13105
|
+
}
|
|
13106
|
+
if (!lang || !parsed) {
|
|
13107
|
+
if (lang) {
|
|
13108
|
+
store.upsertFile({
|
|
13109
|
+
file,
|
|
13110
|
+
lang,
|
|
13111
|
+
mtimeMs: Math.floor(stat18.mtimeMs),
|
|
13112
|
+
symbolCount: 0,
|
|
13113
|
+
lastIndexed: Date.now()
|
|
13114
|
+
});
|
|
13115
|
+
filesIndexed++;
|
|
13116
|
+
}
|
|
13117
|
+
continue;
|
|
13118
|
+
}
|
|
13119
|
+
if (parsed.symbols.length === 0) {
|
|
13120
|
+
store.replaceEmptyFile({
|
|
13121
|
+
file,
|
|
13122
|
+
lang,
|
|
13123
|
+
mtimeMs: Math.floor(stat18.mtimeMs),
|
|
13124
|
+
symbolCount: 0,
|
|
13125
|
+
lastIndexed: Date.now()
|
|
13126
|
+
});
|
|
13127
|
+
filesIndexed++;
|
|
13128
|
+
continue;
|
|
13129
|
+
}
|
|
13130
|
+
batchEntries.push({
|
|
13131
|
+
file,
|
|
13132
|
+
lang,
|
|
13133
|
+
symbols: parsed.symbols,
|
|
13134
|
+
refs: parsed.refs ?? [],
|
|
13135
|
+
mtimeMs: Math.floor(stat18.mtimeMs),
|
|
13136
|
+
symbolCount: parsed.symbols.length
|
|
13137
|
+
});
|
|
13138
|
+
deleteForFiles.push(file);
|
|
13155
13139
|
}
|
|
13156
|
-
|
|
13157
|
-
}
|
|
13158
|
-
spawnDetachedServer() {
|
|
13159
|
-
const url = resolveProjectServerUrl();
|
|
13160
|
-
if (!url) throw new Error("built codebase-index project server is unavailable");
|
|
13161
|
-
if (process.platform !== "win32") {
|
|
13140
|
+
if (batchEntries.length > 0) {
|
|
13162
13141
|
try {
|
|
13163
|
-
|
|
13164
|
-
|
|
13142
|
+
store.commitBatch(batchEntries, { deleteForFiles });
|
|
13143
|
+
for (const entry of batchEntries) {
|
|
13144
|
+
const count = entry.symbols.length;
|
|
13145
|
+
symbolsIndexed += count;
|
|
13146
|
+
langStats[entry.lang] = (langStats[entry.lang] ?? 0) + count;
|
|
13147
|
+
filesIndexed++;
|
|
13148
|
+
}
|
|
13149
|
+
} catch (err) {
|
|
13150
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
13151
|
+
errors.push(`commitBatch failed: ${message} \u2014 falling back to per-file writes`);
|
|
13152
|
+
for (const entry of batchEntries) {
|
|
13153
|
+
try {
|
|
13154
|
+
store.deleteRefsForFile(entry.file);
|
|
13155
|
+
store.deleteSymbolsForFile(entry.file);
|
|
13156
|
+
const symbolsWithIds = store.insertSymbols(entry.symbols);
|
|
13157
|
+
symbolsIndexed += symbolsWithIds.length;
|
|
13158
|
+
langStats[entry.lang] = (langStats[entry.lang] ?? 0) + symbolsWithIds.length;
|
|
13159
|
+
filesIndexed++;
|
|
13160
|
+
if (entry.refs.length > 0 && symbolsWithIds.length > 0) {
|
|
13161
|
+
const fallbackBatch = assignRefsToSymbols2(entry.refs, symbolsWithIds);
|
|
13162
|
+
if (fallbackBatch.length > 0) store.insertRefsBatch(fallbackBatch);
|
|
13163
|
+
}
|
|
13164
|
+
store.resolveRefsForNames([
|
|
13165
|
+
...entry.symbols.map((symbol) => symbol.name),
|
|
13166
|
+
...entry.refs.map((ref) => ref.toName)
|
|
13167
|
+
]);
|
|
13168
|
+
store.upsertFile({
|
|
13169
|
+
file: entry.file,
|
|
13170
|
+
lang: entry.lang,
|
|
13171
|
+
mtimeMs: entry.mtimeMs,
|
|
13172
|
+
symbolCount: entry.symbolCount,
|
|
13173
|
+
lastIndexed: Date.now()
|
|
13174
|
+
});
|
|
13175
|
+
} catch (innerErr) {
|
|
13176
|
+
errors.push(
|
|
13177
|
+
`fallback write failed: ${entry.file}: ${innerErr instanceof Error ? innerErr.message : String(innerErr)}`
|
|
13178
|
+
);
|
|
13179
|
+
}
|
|
13180
|
+
}
|
|
13165
13181
|
}
|
|
13166
13182
|
}
|
|
13167
|
-
const args = [fileURLToPath2(url), "--project-root", this.projectRoot];
|
|
13168
|
-
if (this.indexDir) args.push("--index-dir", this.indexDir);
|
|
13169
|
-
const child = spawn7(process.execPath, args, {
|
|
13170
|
-
detached: true,
|
|
13171
|
-
stdio: "ignore",
|
|
13172
|
-
windowsHide: true,
|
|
13173
|
-
env: process.env
|
|
13174
|
-
});
|
|
13175
|
-
child.unref();
|
|
13176
|
-
}
|
|
13177
|
-
forceKillKnownServer() {
|
|
13178
|
-
const pid = this.info?.pid;
|
|
13179
|
-
return pid ? this.forceKillServer(pid) : false;
|
|
13180
13183
|
}
|
|
13181
|
-
|
|
13182
|
-
|
|
13183
|
-
|
|
13184
|
-
|
|
13185
|
-
const metadataPath = projectIndexServerMetadataPath(this.projectRoot, this.indexDir);
|
|
13186
|
-
try {
|
|
13187
|
-
const metadata = JSON.parse(fs17.readFileSync(metadataPath, "utf8"));
|
|
13188
|
-
if (metadata.pid === pid) fs17.rmSync(metadataPath, { force: true });
|
|
13189
|
-
} catch {
|
|
13184
|
+
if (discoveredFiles && discoveryComplete) {
|
|
13185
|
+
for (const [file_] of existingMeta) {
|
|
13186
|
+
if (!discoveredFiles.has(file_)) {
|
|
13187
|
+
store.deleteFile(file_);
|
|
13190
13188
|
}
|
|
13191
|
-
return true;
|
|
13192
|
-
} catch {
|
|
13193
|
-
return false;
|
|
13194
13189
|
}
|
|
13195
13190
|
}
|
|
13196
|
-
|
|
13197
|
-
|
|
13198
|
-
|
|
13199
|
-
|
|
13200
|
-
|
|
13201
|
-
|
|
13202
|
-
|
|
13203
|
-
|
|
13204
|
-
|
|
13205
|
-
|
|
13206
|
-
|
|
13207
|
-
|
|
13208
|
-
|
|
13209
|
-
|
|
13210
|
-
if (!heartbeatTimer) return;
|
|
13211
|
-
if ([...connections.values()].some((connection) => connection.isConnected())) return;
|
|
13212
|
-
clearInterval(heartbeatTimer);
|
|
13213
|
-
heartbeatTimer = void 0;
|
|
13191
|
+
if (needsFullRefResolution) store.resolveRefs();
|
|
13192
|
+
store.setMetadata("ref_resolution_version", refResolutionVersion);
|
|
13193
|
+
store.setMetadata("relation_graph_version", relationGraphVersion);
|
|
13194
|
+
if (!opts.files || filesIndexed >= 50) store.optimize();
|
|
13195
|
+
store.setLastIndexed(Date.now());
|
|
13196
|
+
if (!opts.files) store.compactIfNeeded();
|
|
13197
|
+
const durationMs = Date.now() - startMs;
|
|
13198
|
+
return {
|
|
13199
|
+
filesIndexed,
|
|
13200
|
+
symbolsIndexed,
|
|
13201
|
+
langStats,
|
|
13202
|
+
durationMs,
|
|
13203
|
+
errors
|
|
13204
|
+
};
|
|
13214
13205
|
}
|
|
13215
|
-
|
|
13216
|
-
|
|
13217
|
-
|
|
13218
|
-
|
|
13219
|
-
|
|
13220
|
-
|
|
13206
|
+
|
|
13207
|
+
// src/codebase-index/index-service.ts
|
|
13208
|
+
async function indexService(args, hooks = {}) {
|
|
13209
|
+
const store = indexStorePool.acquire(args.projectRoot, { indexDir: args.indexDir });
|
|
13210
|
+
try {
|
|
13211
|
+
return await runIndexerWithStore(store, {
|
|
13212
|
+
projectRoot: args.projectRoot,
|
|
13213
|
+
indexDir: args.indexDir,
|
|
13214
|
+
files: args.files,
|
|
13215
|
+
force: args.force,
|
|
13216
|
+
langs: args.langs,
|
|
13217
|
+
ignore: args.ignore,
|
|
13218
|
+
signal: hooks.signal,
|
|
13219
|
+
onProgress: hooks.onProgress
|
|
13220
|
+
});
|
|
13221
|
+
} finally {
|
|
13222
|
+
indexStorePool.release(store);
|
|
13221
13223
|
}
|
|
13222
|
-
return connection;
|
|
13223
13224
|
}
|
|
13224
|
-
function
|
|
13225
|
-
|
|
13225
|
+
function searchService(args) {
|
|
13226
|
+
const store = indexStorePool.acquire(args.projectRoot, { indexDir: args.indexDir });
|
|
13227
|
+
try {
|
|
13228
|
+
return store.searchRanked(
|
|
13229
|
+
args.query,
|
|
13230
|
+
{
|
|
13231
|
+
kind: args.kind,
|
|
13232
|
+
lang: args.lang,
|
|
13233
|
+
file: args.file,
|
|
13234
|
+
lspKind: args.lspKind
|
|
13235
|
+
},
|
|
13236
|
+
args.limit
|
|
13237
|
+
);
|
|
13238
|
+
} finally {
|
|
13239
|
+
indexStorePool.release(store);
|
|
13240
|
+
}
|
|
13226
13241
|
}
|
|
13227
|
-
function
|
|
13228
|
-
|
|
13229
|
-
|
|
13230
|
-
|
|
13231
|
-
|
|
13242
|
+
function statsService(args) {
|
|
13243
|
+
const store = indexStorePool.acquire(args.projectRoot, { indexDir: args.indexDir });
|
|
13244
|
+
try {
|
|
13245
|
+
return store.getStats();
|
|
13246
|
+
} finally {
|
|
13247
|
+
indexStorePool.release(store);
|
|
13248
|
+
}
|
|
13232
13249
|
}
|
|
13233
|
-
function
|
|
13234
|
-
|
|
13235
|
-
|
|
13236
|
-
|
|
13237
|
-
|
|
13250
|
+
function packageGraphService(args) {
|
|
13251
|
+
const store = indexStorePool.acquire(args.projectRoot, { indexDir: args.indexDir });
|
|
13252
|
+
try {
|
|
13253
|
+
return store.getPackageGraph();
|
|
13254
|
+
} finally {
|
|
13255
|
+
indexStorePool.release(store);
|
|
13256
|
+
}
|
|
13238
13257
|
}
|
|
13239
|
-
|
|
13240
|
-
const
|
|
13241
|
-
const connection = connectionFor(projectRoot, indexDir);
|
|
13258
|
+
function fileGraphService(args) {
|
|
13259
|
+
const store = indexStorePool.acquire(args.projectRoot, { indexDir: args.indexDir });
|
|
13242
13260
|
try {
|
|
13243
|
-
return
|
|
13261
|
+
return store.getFileGraph(args.packageFilter);
|
|
13244
13262
|
} finally {
|
|
13245
|
-
|
|
13246
|
-
connections.delete(endpoint);
|
|
13247
|
-
connectionStates.delete(endpoint);
|
|
13263
|
+
indexStorePool.release(store);
|
|
13248
13264
|
}
|
|
13249
13265
|
}
|
|
13250
|
-
function
|
|
13251
|
-
|
|
13252
|
-
|
|
13253
|
-
|
|
13254
|
-
|
|
13255
|
-
|
|
13256
|
-
|
|
13257
|
-
};
|
|
13258
|
-
if (heartbeatTimer) clearInterval(heartbeatTimer);
|
|
13259
|
-
heartbeatTimer = void 0;
|
|
13266
|
+
function symbolGraphService(args) {
|
|
13267
|
+
const store = indexStorePool.acquire(args.projectRoot, { indexDir: args.indexDir });
|
|
13268
|
+
try {
|
|
13269
|
+
return store.getSymbolGraph(args.fileFilter);
|
|
13270
|
+
} finally {
|
|
13271
|
+
indexStorePool.release(store);
|
|
13272
|
+
}
|
|
13260
13273
|
}
|
|
13261
13274
|
|
|
13262
13275
|
// src/codebase-index/background-indexer.ts
|
|
13276
|
+
init_languages2();
|
|
13263
13277
|
var DEFAULT_FULL_INDEX_TIMEOUT_MS = 24e4;
|
|
13264
13278
|
var DEFAULT_INCREMENTAL_TIMEOUT_MS = 6e4;
|
|
13265
13279
|
var DEFAULT_QUERY_TIMEOUT_MS = 3e4;
|
|
@@ -13392,8 +13406,17 @@ async function shutdownCodebaseIndexHost() {
|
|
|
13392
13406
|
}
|
|
13393
13407
|
}
|
|
13394
13408
|
}
|
|
13409
|
+
var warnedInvalidEndpoints = /* @__PURE__ */ new Set();
|
|
13410
|
+
function warnEndpointInvalidOnce(availability) {
|
|
13411
|
+
if (warnedInvalidEndpoints.has(availability.endpoint)) return;
|
|
13412
|
+
warnedInvalidEndpoints.add(availability.endpoint);
|
|
13413
|
+
process.stderr.write(
|
|
13414
|
+
`codebase-index: socket path is ${availability.byteLength} bytes, over this platform's ${availability.maxBytes}-byte sun_path limit (${availability.endpoint}). Subsequent calls will reject until TMPDIR is shortened to restore the shared daemon.
|
|
13415
|
+
`
|
|
13416
|
+
);
|
|
13417
|
+
}
|
|
13395
13418
|
function callIndexOp(op, args, opts) {
|
|
13396
|
-
const availability = resolveProjectIndexDaemonAvailability();
|
|
13419
|
+
const availability = resolveProjectIndexDaemonAvailability(args.projectRoot, args.indexDir);
|
|
13397
13420
|
if (availability.kind === "available") {
|
|
13398
13421
|
return callProjectIndexServer(op, args, opts);
|
|
13399
13422
|
}
|
|
@@ -13404,6 +13427,14 @@ function callIndexOp(op, args, opts) {
|
|
|
13404
13427
|
)
|
|
13405
13428
|
);
|
|
13406
13429
|
}
|
|
13430
|
+
if (availability.kind === "endpoint-invalid") {
|
|
13431
|
+
warnEndpointInvalidOnce(availability);
|
|
13432
|
+
return Promise.reject(
|
|
13433
|
+
new Error(
|
|
13434
|
+
`codebase-index: socket path is ${availability.byteLength} bytes, over this platform's ${availability.maxBytes}-byte sun_path limit (${availability.endpoint}). Set a shorter TMPDIR to relocate the shared daemon, or set WRONGSTACK_INDEX_INLINE=1 to explicitly opt into a process-local index.`
|
|
13435
|
+
)
|
|
13436
|
+
);
|
|
13437
|
+
}
|
|
13407
13438
|
const w = ensureWorker();
|
|
13408
13439
|
if (!w) return callInline(op, args, opts);
|
|
13409
13440
|
if (opts.signal?.aborted) {
|
|
@@ -13677,7 +13708,11 @@ function checkCodebaseIndexServerHealth(projectRoot, indexDir, options = {}) {
|
|
|
13677
13708
|
return checkProjectIndexServerHealth(projectRoot, indexDir, options);
|
|
13678
13709
|
}
|
|
13679
13710
|
function ensureCodebaseIndexServer(options) {
|
|
13680
|
-
|
|
13711
|
+
const availability = resolveProjectIndexDaemonAvailability(options.projectRoot, options.indexDir);
|
|
13712
|
+
if (availability.kind !== "available") {
|
|
13713
|
+
if (availability.kind === "endpoint-invalid") warnEndpointInvalidOnce(availability);
|
|
13714
|
+
return Promise.resolve();
|
|
13715
|
+
}
|
|
13681
13716
|
return ensureProjectIndexServer({
|
|
13682
13717
|
projectRoot: options.projectRoot,
|
|
13683
13718
|
indexDir: options.indexDir,
|
|
@@ -26450,6 +26485,7 @@ export {
|
|
|
26450
26485
|
resetIndexCircuitBreaker,
|
|
26451
26486
|
resetPersistentProcessRegistry,
|
|
26452
26487
|
resolvePinnedBrowserTarget,
|
|
26488
|
+
resolveProjectIndexDaemonAvailability,
|
|
26453
26489
|
resolveSessionShell,
|
|
26454
26490
|
runDeadCodeScan,
|
|
26455
26491
|
runStartupIndex,
|