@zuvia-software-solutions/code-mapper 2.5.0 → 2.5.2
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.
|
@@ -795,14 +795,17 @@ async function batchResolveTsgo(tsgoService, extractedCalls, ctx, graph, repoPat
|
|
|
795
795
|
}
|
|
796
796
|
const t0 = Date.now();
|
|
797
797
|
const skippedTotal = skippedUnambiguous + skippedBuiltin;
|
|
798
|
-
// Adaptive parallelism
|
|
798
|
+
// Adaptive parallelism — conservative to avoid freezing the machine.
|
|
799
|
+
// Each tsgo LSP process loads the full project into memory (~1.5-3GB for
|
|
800
|
+
// large codebases) and pins a CPU core at 100%, so we cap aggressively.
|
|
799
801
|
const osModule = await import('os');
|
|
800
802
|
const cpuCount = osModule.cpus().length;
|
|
801
803
|
const freeMemGB = osModule.freemem() / (1024 * 1024 * 1024);
|
|
802
|
-
const maxByCpu = Math.max(1, Math.floor(cpuCount * 0.
|
|
803
|
-
const maxByMemory = Math.max(1, Math.floor(freeMemGB /
|
|
804
|
-
const maxByWorkload = Math.max(1, Math.floor(tsgoByFile.size /
|
|
805
|
-
const
|
|
804
|
+
const maxByCpu = Math.max(1, Math.floor(cpuCount * 0.5));
|
|
805
|
+
const maxByMemory = Math.max(1, Math.floor(freeMemGB / 2)); // ~2GB per process
|
|
806
|
+
const maxByWorkload = Math.max(1, Math.floor(tsgoByFile.size / 100));
|
|
807
|
+
const HARD_CAP = 4; // never more than 4 tsgo processes regardless of hardware
|
|
808
|
+
const actualWorkers = Math.min(maxByCpu, maxByMemory, maxByWorkload, HARD_CAP);
|
|
806
809
|
if (process.env['CODE_MAPPER_VERBOSE']) {
|
|
807
810
|
console.error(`Code Mapper: tsgo resolving ${tsgoEligible.length} calls across ${tsgoByFile.size} files with ${actualWorkers} process${actualWorkers > 1 ? 'es' : ''} (skipped ${skippedTotal}: ${skippedUnambiguous} unambiguous, ${skippedBuiltin} builtin)...`);
|
|
808
811
|
}
|
|
@@ -823,15 +826,26 @@ async function batchResolveTsgo(tsgoService, extractedCalls, ctx, graph, repoPat
|
|
|
823
826
|
let sliceFailed = 0;
|
|
824
827
|
let entry;
|
|
825
828
|
while ((entry = getNextFile()) !== null) {
|
|
829
|
+
// Bail out early if tsgo process died — no point sending more requests
|
|
830
|
+
if (!service.isReady())
|
|
831
|
+
break;
|
|
826
832
|
const [filePath, calls] = entry;
|
|
827
833
|
totalFilesProcessed++;
|
|
828
834
|
if (totalFilesProcessed % 25 === 0) {
|
|
829
835
|
onProgress?.(totalFilesProcessed, tsgoTotalFiles, actualWorkers);
|
|
830
836
|
}
|
|
831
837
|
const absFilePath = path.resolve(repoPath, filePath);
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
838
|
+
// Pipeline: fire all definition requests for this file concurrently.
|
|
839
|
+
// The LSP server processes them serially, but we eliminate round-trip
|
|
840
|
+
// latency between requests — major speedup on large files.
|
|
841
|
+
const BATCH = 50;
|
|
842
|
+
for (let i = 0; i < calls.length; i += BATCH) {
|
|
843
|
+
const batch = calls.slice(i, i + BATCH);
|
|
844
|
+
const defs = await Promise.all(batch.map(call => service.resolveDefinition(absFilePath, call.callLine - 1, call.callColumn)
|
|
845
|
+
.catch(() => null)));
|
|
846
|
+
for (let j = 0; j < batch.length; j++) {
|
|
847
|
+
const call = batch[j];
|
|
848
|
+
const def = defs[j];
|
|
835
849
|
if (!def) {
|
|
836
850
|
sliceFailed++;
|
|
837
851
|
continue;
|
|
@@ -879,9 +893,6 @@ async function batchResolveTsgo(tsgoService, extractedCalls, ctx, graph, repoPat
|
|
|
879
893
|
sliceFailed++;
|
|
880
894
|
}
|
|
881
895
|
}
|
|
882
|
-
catch {
|
|
883
|
-
sliceFailed++;
|
|
884
|
-
}
|
|
885
896
|
}
|
|
886
897
|
service.notifyFileDeleted(absFilePath);
|
|
887
898
|
}
|
|
@@ -260,9 +260,25 @@ export class TsgoService {
|
|
|
260
260
|
if (msg)
|
|
261
261
|
verbose('stderr:', msg);
|
|
262
262
|
});
|
|
263
|
+
// Handle EPIPE / write errors on stdin — without this handler,
|
|
264
|
+
// a dead tsgo process causes an unhandled 'error' event that crashes Node.
|
|
265
|
+
this.process.stdin.on('error', (err) => {
|
|
266
|
+
verbose(`stdin error: ${err.code ?? err.message}`);
|
|
267
|
+
this.ready = false;
|
|
268
|
+
// Reject all pending requests so callers don't hang
|
|
269
|
+
for (const cb of this.pending.values()) {
|
|
270
|
+
cb({ id: -1, error: { message: `tsgo stdin error: ${err.code}` } });
|
|
271
|
+
}
|
|
272
|
+
this.pending.clear();
|
|
273
|
+
});
|
|
263
274
|
this.process.on('exit', (code, signal) => {
|
|
264
275
|
verbose(`process exited (code=${code}, signal=${signal})`);
|
|
265
276
|
this.ready = false;
|
|
277
|
+
// Reject all pending requests on unexpected exit
|
|
278
|
+
for (const cb of this.pending.values()) {
|
|
279
|
+
cb({ id: -1, error: { message: `tsgo exited (code=${code}, signal=${signal})` } });
|
|
280
|
+
}
|
|
281
|
+
this.pending.clear();
|
|
266
282
|
this.process = null;
|
|
267
283
|
});
|
|
268
284
|
// Initialize LSP handshake
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zuvia-software-solutions/code-mapper",
|
|
3
|
-
"version": "2.5.
|
|
3
|
+
"version": "2.5.2",
|
|
4
4
|
"description": "Graph-powered code intelligence for AI agents. Index any codebase, query via MCP or CLI.",
|
|
5
5
|
"author": "Abhigyan Patwari",
|
|
6
6
|
"license": "PolyForm-Noncommercial-1.0.0",
|