@wrongstack/tools 0.289.0 → 0.291.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auto-proceed-loop-guard.d.ts +128 -0
- package/dist/auto-proceed-loop-guard.d.ts.map +1 -0
- package/dist/auto-proceed-loop-guard.js +46 -0
- package/dist/auto-proceed-loop-guard.js.map +7 -0
- package/dist/builtin.js +198 -113
- package/dist/builtin.js.map +3 -3
- package/dist/codebase-index/background-indexer.d.ts +1 -1
- package/dist/codebase-index/background-indexer.d.ts.map +1 -1
- package/dist/codebase-index/index.js +181 -104
- package/dist/codebase-index/index.js.map +3 -3
- package/dist/codebase-index/indexer.d.ts.map +1 -1
- package/dist/codebase-index/refs-extractor.d.ts +2 -17
- package/dist/codebase-index/refs-extractor.d.ts.map +1 -1
- package/dist/codebase-index/ts-parser.d.ts.map +1 -1
- package/dist/codebase-index/worker.js +164 -96
- package/dist/codebase-index/worker.js.map +3 -3
- package/dist/codebase-index/writer.d.ts +33 -0
- package/dist/codebase-index/writer.d.ts.map +1 -1
- package/dist/index.js +275 -124
- package/dist/index.js.map +3 -3
- package/dist/kanban.d.ts +10 -0
- package/dist/kanban.d.ts.map +1 -1
- package/dist/kanban.js +34 -17
- package/dist/kanban.js.map +2 -2
- package/dist/pack.js +198 -113
- package/dist/pack.js.map +3 -3
- package/dist/plan.js.map +2 -2
- package/dist/read.d.ts.map +1 -1
- package/dist/read.js.map +2 -2
- package/dist/session-kanban.d.ts.map +1 -1
- package/dist/session-kanban.js +60 -3
- package/dist/session-kanban.js.map +2 -2
- package/dist/task.js.map +2 -2
- package/dist/todo.js.map +2 -2
- package/package.json +9 -5
|
@@ -58,7 +58,7 @@ export declare function onIndexStateChange(listener: IndexStateListener): () =>
|
|
|
58
58
|
* Tear down the index host (worker + pending debounces). Call on process
|
|
59
59
|
* shutdown; safe to call when nothing is running.
|
|
60
60
|
*/
|
|
61
|
-
export declare function shutdownCodebaseIndexHost(): void
|
|
61
|
+
export declare function shutdownCodebaseIndexHost(): Promise<void>;
|
|
62
62
|
/** True when the file's extension maps to a language the indexer can parse. */
|
|
63
63
|
export declare function isIndexableFile(filePath: string): boolean;
|
|
64
64
|
export declare function runStartupIndex(opts: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"background-indexer.d.ts","sourceRoot":"","sources":["../../src/codebase-index/background-indexer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAKH,OAAO,EAEL,KAAK,eAAe,EAIrB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"background-indexer.d.ts","sourceRoot":"","sources":["../../src/codebase-index/background-indexer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAKH,OAAO,EAEL,KAAK,eAAe,EAIrB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAG3D,OAAO,KAAK,EAKV,YAAY,EACZ,cAAc,EACd,WAAW,EAEZ,MAAM,sBAAsB,CAAC;AAkC9B,iFAAiF;AACjF,wBAAgB,YAAY,IAAI,OAAO,CAEtC;AAED;;;GAGG;AACH,wBAAgB,aAAa,IAAI,IAAI,CAEpC;AAED,qDAAqD;AACrD,wBAAgB,UAAU,IAAI,OAAO,CAEpC;AAED,wFAAwF;AACxF,wBAAgB,aAAa,IAAI;IAC/B,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,uFAAuF;IACvF,OAAO,EAAE,eAAe,CAAC;CAC1B,CASA;AAED;;;;GAIG;AACH,KAAK,kBAAkB,GAAG,CAAC,KAAK,EAAE,UAAU,CAAC,OAAO,aAAa,CAAC,KAAK,IAAI,CAAC;AAG5E,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,kBAAkB,GAAG,MAAM,IAAI,CAK3E;AA8GD;;;GAGG;AACH,wBAAsB,yBAAyB,IAAI,OAAO,CAAC,IAAI,CAAC,CAiB/D;AA4JD,+EAA+E;AAC/E,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAEzD;AAmBD,wBAAsB,eAAe,CAAC,IAAI,EAAE;IAC1C,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,KAAK,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IAC7B,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;IACjC,yDAAyD;IACzD,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAChC,GAAG,OAAO,CAAC,WAAW,CAAC,CA2DvB;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE;IACnC,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,+CAA+C;IAC/C,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,OAAO,CAAC,EAAE,CAAC,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;CAChD,GAAG,IAAI,CAmCP;AAED,oEAAoE;AACpE,wBAAgB,sBAAsB,IAAI,IAAI,CAG7C;AAED;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,YAAY,EAClB,IAAI,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,CAAA;CAAO,GAC9E,OAAO,CAAC,cAAc,CAAC,CAKzB;AAED,0EAA0E;AAC1E,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,WAAW,EACjB,IAAI,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,CAAA;CAAO,GAC9E,OAAO,CAAC,UAAU,CAAC,CAKrB;AAID;;;;;;;GAOG;AACH,wBAAgB,yBAAyB,IAAI,IAAI,CAchD"}
|
|
@@ -277,6 +277,53 @@ function codebaseIndexDirOverride(ctx) {
|
|
|
277
277
|
const v = ctx.meta?.["codebaseIndexDir"];
|
|
278
278
|
return typeof v === "string" ? v : void 0;
|
|
279
279
|
}
|
|
280
|
+
var StorePool = class {
|
|
281
|
+
stores = /* @__PURE__ */ new Map();
|
|
282
|
+
key(projectRoot, indexDir) {
|
|
283
|
+
return `${projectRoot}\0${indexDir ?? ""}`;
|
|
284
|
+
}
|
|
285
|
+
/** Borrow a store. Creates it on first access for this key. */
|
|
286
|
+
acquire(projectRoot, opts) {
|
|
287
|
+
const k = this.key(projectRoot, opts?.indexDir);
|
|
288
|
+
let store = this.stores.get(k);
|
|
289
|
+
if (!store) {
|
|
290
|
+
store = new IndexStore(projectRoot, { indexDir: opts?.indexDir });
|
|
291
|
+
this.stores.set(k, store);
|
|
292
|
+
}
|
|
293
|
+
return store;
|
|
294
|
+
}
|
|
295
|
+
/** Return the store to the pool. The connection stays warm for subsequent
|
|
296
|
+
* operations on the same (projectRoot, indexDir). */
|
|
297
|
+
release(_store) {
|
|
298
|
+
}
|
|
299
|
+
/** Close every pooled connection and drain the pool. Call on shutdown. */
|
|
300
|
+
closeAll() {
|
|
301
|
+
for (const store of this.stores.values()) {
|
|
302
|
+
try {
|
|
303
|
+
store.close();
|
|
304
|
+
} catch {
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
this.stores.clear();
|
|
308
|
+
}
|
|
309
|
+
/** Remove one store from the pool. Used by tests that need isolation. */
|
|
310
|
+
evict(projectRoot, indexDir) {
|
|
311
|
+
const k = this.key(projectRoot, indexDir);
|
|
312
|
+
const store = this.stores.get(k);
|
|
313
|
+
if (store) {
|
|
314
|
+
try {
|
|
315
|
+
store.close();
|
|
316
|
+
} catch {
|
|
317
|
+
}
|
|
318
|
+
this.stores.delete(k);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
/** True when the pool holds a connection for the given key. */
|
|
322
|
+
has(projectRoot, indexDir) {
|
|
323
|
+
return this.stores.has(this.key(projectRoot, indexDir));
|
|
324
|
+
}
|
|
325
|
+
};
|
|
326
|
+
var indexStorePool = new StorePool();
|
|
280
327
|
var warningSilenced = false;
|
|
281
328
|
function silenceSqliteExperimentalWarning() {
|
|
282
329
|
if (warningSilenced) return;
|
|
@@ -494,7 +541,7 @@ var IndexStore = class _IndexStore {
|
|
|
494
541
|
return this.runWithRetry(() => {
|
|
495
542
|
this.db.exec("BEGIN IMMEDIATE");
|
|
496
543
|
try {
|
|
497
|
-
const maxRows = this.
|
|
544
|
+
const maxRows = this.stmt("SELECT MAX(id) AS m FROM symbols").all();
|
|
498
545
|
let nextId = (maxRows[0]?.m ?? 0) + 1;
|
|
499
546
|
const stmt = this.db.prepare(
|
|
500
547
|
`INSERT INTO symbols(id, lang, kind, name, file, line, col, signature, doc_comment, scope, text, file_fk)
|
|
@@ -766,7 +813,7 @@ var IndexStore = class _IndexStore {
|
|
|
766
813
|
return { results, total: candidates.length };
|
|
767
814
|
}
|
|
768
815
|
getAllIndexable() {
|
|
769
|
-
return this.
|
|
816
|
+
return this.stmt("SELECT id, text FROM symbols").all().map(({ id, text }) => ({ id, text }));
|
|
770
817
|
}
|
|
771
818
|
/**
|
|
772
819
|
* Largest symbol id currently in the table (0 when empty). New ids must be
|
|
@@ -776,7 +823,7 @@ var IndexStore = class _IndexStore {
|
|
|
776
823
|
* `symbols.id`). Ids may have gaps — that is fine.
|
|
777
824
|
*/
|
|
778
825
|
getMaxSymbolId() {
|
|
779
|
-
const rows = this.
|
|
826
|
+
const rows = this.stmt("SELECT MAX(id) AS m FROM symbols").all();
|
|
780
827
|
return rows[0]?.m ?? 0;
|
|
781
828
|
}
|
|
782
829
|
// ─── Stats ───────────────────────────────────────────────────────────────────
|
|
@@ -784,14 +831,14 @@ var IndexStore = class _IndexStore {
|
|
|
784
831
|
const sizeBytes = this.sizeBytes();
|
|
785
832
|
const lastRows = this.db.prepare("SELECT value FROM metadata WHERE key = 'last_indexed'").all();
|
|
786
833
|
const lastIndexed = lastRows.length ? Number(lastRows[0]?.value) : null;
|
|
787
|
-
const totalRows = this.
|
|
834
|
+
const totalRows = this.stmt("SELECT COUNT(*) FROM symbols").all();
|
|
788
835
|
const totalSymbols = totalRows[0] ? Number(totalRows[0]["COUNT(*)"]) : 0;
|
|
789
|
-
const fileRows = this.
|
|
836
|
+
const fileRows = this.stmt("SELECT COUNT(*) FROM files").all();
|
|
790
837
|
const totalFiles = fileRows[0] ? Number(fileRows[0]["COUNT(*)"]) : 0;
|
|
791
|
-
const langRows = this.
|
|
838
|
+
const langRows = this.stmt("SELECT lang, COUNT(*) FROM symbols GROUP BY lang").all();
|
|
792
839
|
const byLang = {};
|
|
793
840
|
for (const row of langRows) byLang[row.lang] = Number(row["COUNT(*)"]);
|
|
794
|
-
const kindRows = this.
|
|
841
|
+
const kindRows = this.stmt("SELECT kind, COUNT(*) FROM symbols GROUP BY kind").all();
|
|
795
842
|
const byKind = {};
|
|
796
843
|
for (const row of kindRows) byKind[row.kind] = Number(row["COUNT(*)"]);
|
|
797
844
|
return {
|
|
@@ -823,11 +870,14 @@ var IndexStore = class _IndexStore {
|
|
|
823
870
|
this.runWithRetry(() => {
|
|
824
871
|
this.db.exec("BEGIN IMMEDIATE");
|
|
825
872
|
try {
|
|
826
|
-
this.db.exec("
|
|
827
|
-
this.db.exec("
|
|
828
|
-
this.db.exec("
|
|
829
|
-
|
|
873
|
+
this.db.exec("DROP TABLE IF EXISTS refs");
|
|
874
|
+
this.db.exec("DROP TABLE IF EXISTS symbols");
|
|
875
|
+
this.db.exec("DROP TABLE IF EXISTS files");
|
|
876
|
+
this.db.exec("DROP TABLE IF EXISTS metadata");
|
|
877
|
+
if (this.ftsAvailable) this.db.exec("DROP TABLE IF EXISTS symbols_fts");
|
|
830
878
|
this.db.exec("COMMIT");
|
|
879
|
+
this.stmtCache.clear();
|
|
880
|
+
this.initSchema();
|
|
831
881
|
} catch (err) {
|
|
832
882
|
this.db.exec("ROLLBACK");
|
|
833
883
|
throw err;
|
|
@@ -912,7 +962,7 @@ var IndexStore = class _IndexStore {
|
|
|
912
962
|
).run(...options.deleteForFiles);
|
|
913
963
|
this.db.prepare(`DELETE FROM symbols WHERE file IN (${placeholders})`).run(...options.deleteForFiles);
|
|
914
964
|
}
|
|
915
|
-
const maxRows = this.
|
|
965
|
+
const maxRows = this.stmt("SELECT MAX(id) AS m FROM symbols").all();
|
|
916
966
|
let nextId = (maxRows[0]?.m ?? 0) + 1;
|
|
917
967
|
const symStmt = this.db.prepare(
|
|
918
968
|
`INSERT INTO symbols(id, lang, kind, name, file, line, col, signature, doc_comment, scope, text, file_fk)
|
|
@@ -1096,7 +1146,7 @@ var IndexStore = class _IndexStore {
|
|
|
1096
1146
|
* symbol resolved in package B). Node metadata includes symbol/file counts.
|
|
1097
1147
|
*/
|
|
1098
1148
|
getPackageGraph() {
|
|
1099
|
-
const symbols = this.db.prepare("SELECT file, id
|
|
1149
|
+
const symbols = this.db.prepare("SELECT file, id FROM symbols ORDER BY id").all();
|
|
1100
1150
|
const pkgNodes = /* @__PURE__ */ new Map();
|
|
1101
1151
|
const fileToPkg = /* @__PURE__ */ new Map();
|
|
1102
1152
|
const symbolToPkg = /* @__PURE__ */ new Map();
|
|
@@ -1187,15 +1237,18 @@ var IndexStore = class _IndexStore {
|
|
|
1187
1237
|
* derived from cross-file symbol references within the package.
|
|
1188
1238
|
*/
|
|
1189
1239
|
getFileGraph(packageFilter) {
|
|
1190
|
-
const
|
|
1191
|
-
const
|
|
1192
|
-
|
|
1193
|
-
);
|
|
1194
|
-
|
|
1240
|
+
const allFiles = this.db.prepare("SELECT DISTINCT file FROM symbols").all();
|
|
1241
|
+
const pkgFilePaths = allFiles.filter((f) => (_IndexStore.derivePackage(f.file) ?? "(root)") === packageFilter).map((f) => f.file);
|
|
1242
|
+
const localFiles = new Set(pkgFilePaths);
|
|
1243
|
+
if (localFiles.size === 0) return { nodes: [], edges: [] };
|
|
1244
|
+
const filePlaceholders = [...localFiles].map(() => "?").join(",");
|
|
1245
|
+
const pkgSyms = this.db.prepare(
|
|
1246
|
+
`SELECT file, id, name, kind, lang, line FROM symbols WHERE file IN (${filePlaceholders}) ORDER BY id`
|
|
1247
|
+
).all(...pkgFilePaths);
|
|
1195
1248
|
const fileNodes = /* @__PURE__ */ new Map();
|
|
1196
1249
|
const symToFile = /* @__PURE__ */ new Map();
|
|
1197
1250
|
const fileStats = /* @__PURE__ */ new Map();
|
|
1198
|
-
for (const s of
|
|
1251
|
+
for (const s of pkgSyms) {
|
|
1199
1252
|
symToFile.set(s.id, s.file);
|
|
1200
1253
|
const current = fileStats.get(s.file);
|
|
1201
1254
|
fileStats.set(s.file, {
|
|
@@ -1203,8 +1256,6 @@ var IndexStore = class _IndexStore {
|
|
|
1203
1256
|
lang: current?.lang ?? s.lang
|
|
1204
1257
|
});
|
|
1205
1258
|
}
|
|
1206
|
-
const localFiles = new Set(pkgSyms.map((s) => s.file));
|
|
1207
|
-
const indexedFiles = new Set(allSymbols.map((s) => s.file));
|
|
1208
1259
|
const ensureFileNode = (file) => {
|
|
1209
1260
|
if (fileNodes.has(file)) return;
|
|
1210
1261
|
const stats = fileStats.get(file);
|
|
@@ -1222,11 +1273,32 @@ var IndexStore = class _IndexStore {
|
|
|
1222
1273
|
for (const file of localFiles) {
|
|
1223
1274
|
ensureFileNode(file);
|
|
1224
1275
|
}
|
|
1276
|
+
const indexedFiles = new Set(allFiles.map((f) => f.file));
|
|
1225
1277
|
const refRows = this.db.prepare(
|
|
1226
1278
|
`SELECT r.from_id, r.to_id, r.call_type
|
|
1227
1279
|
FROM refs r
|
|
1228
|
-
WHERE r.
|
|
1229
|
-
|
|
1280
|
+
WHERE (r.from_id IN (SELECT id FROM symbols WHERE file IN (${filePlaceholders}))
|
|
1281
|
+
OR r.to_id IN (SELECT id FROM symbols WHERE file IN (${filePlaceholders})))
|
|
1282
|
+
AND r.to_id IS NOT NULL`
|
|
1283
|
+
).all(...pkgFilePaths, ...pkgFilePaths);
|
|
1284
|
+
const knownSymIds = new Set(pkgSyms.map((s) => s.id));
|
|
1285
|
+
const crossRefIds = /* @__PURE__ */ new Set();
|
|
1286
|
+
for (const r of refRows) {
|
|
1287
|
+
if (!knownSymIds.has(r.from_id)) crossRefIds.add(r.from_id);
|
|
1288
|
+
if (!knownSymIds.has(r.to_id)) crossRefIds.add(r.to_id);
|
|
1289
|
+
}
|
|
1290
|
+
if (crossRefIds.size > 0) {
|
|
1291
|
+
const crossPlaceholders = [...crossRefIds].map(() => "?").join(",");
|
|
1292
|
+
const extras = this.db.prepare(
|
|
1293
|
+
`SELECT id, file FROM symbols WHERE id IN (${crossPlaceholders})`
|
|
1294
|
+
).all(...crossRefIds);
|
|
1295
|
+
for (const x of extras) {
|
|
1296
|
+
symToFile.set(x.id, x.file);
|
|
1297
|
+
if (!fileStats.has(x.file)) {
|
|
1298
|
+
fileStats.set(x.file, { count: 0, lang: "ts" });
|
|
1299
|
+
}
|
|
1300
|
+
}
|
|
1301
|
+
}
|
|
1230
1302
|
const edgeMap = /* @__PURE__ */ new Map();
|
|
1231
1303
|
for (const r of refRows) {
|
|
1232
1304
|
if (r.call_type === "import") continue;
|
|
@@ -1248,8 +1320,9 @@ var IndexStore = class _IndexStore {
|
|
|
1248
1320
|
const importRows = this.db.prepare(
|
|
1249
1321
|
`SELECT r.from_id, r.to_name
|
|
1250
1322
|
FROM refs r
|
|
1251
|
-
WHERE r.call_type = 'import'
|
|
1252
|
-
|
|
1323
|
+
WHERE r.call_type = 'import'
|
|
1324
|
+
AND r.from_id IN (SELECT id FROM symbols WHERE file IN (${filePlaceholders}))`
|
|
1325
|
+
).all(...pkgFilePaths);
|
|
1253
1326
|
for (const r of importRows) {
|
|
1254
1327
|
const fromFile = symToFile.get(r.from_id);
|
|
1255
1328
|
if (!fromFile || !localFiles.has(fromFile)) continue;
|
|
@@ -1291,12 +1364,11 @@ var IndexStore = class _IndexStore {
|
|
|
1291
1364
|
* derived from intra-file and cross-file symbol references (who calls whom).
|
|
1292
1365
|
*/
|
|
1293
1366
|
getSymbolGraph(fileFilter) {
|
|
1294
|
-
const
|
|
1295
|
-
"SELECT id, name, kind, lang, file, line, signature, scope FROM symbols ORDER BY
|
|
1296
|
-
).all();
|
|
1297
|
-
const syms = allSymbols.filter((symbol) => symbol.file === fileFilter);
|
|
1367
|
+
const syms = this.db.prepare(
|
|
1368
|
+
"SELECT id, name, kind, lang, file, line, signature, scope FROM symbols WHERE file = ? ORDER BY line, id"
|
|
1369
|
+
).all(fileFilter);
|
|
1298
1370
|
if (syms.length === 0) return { nodes: [], edges: [] };
|
|
1299
|
-
const symById = new Map(
|
|
1371
|
+
const symById = new Map(syms.map((symbol) => [symbol.id, symbol]));
|
|
1300
1372
|
const relatedIds = new Set(syms.map((symbol) => symbol.id));
|
|
1301
1373
|
const toGraphNode = (s) => ({
|
|
1302
1374
|
id: `sym:${s.id}`,
|
|
@@ -1352,6 +1424,15 @@ var IndexStore = class _IndexStore {
|
|
|
1352
1424
|
refType: bestType
|
|
1353
1425
|
});
|
|
1354
1426
|
}
|
|
1427
|
+
const loadedIds = new Set(syms.map((s) => s.id));
|
|
1428
|
+
const missingIds = [...relatedIds].filter((id) => !loadedIds.has(id));
|
|
1429
|
+
if (missingIds.length > 0) {
|
|
1430
|
+
const placeholders = missingIds.map(() => "?").join(",");
|
|
1431
|
+
const extras = this.db.prepare(
|
|
1432
|
+
`SELECT id, name, kind, lang, file, line, signature, scope FROM symbols WHERE id IN (${placeholders})`
|
|
1433
|
+
).all(...missingIds);
|
|
1434
|
+
for (const s of extras) symById.set(s.id, s);
|
|
1435
|
+
}
|
|
1355
1436
|
const nodes = [...relatedIds].map((id) => symById.get(id)).filter((symbol) => symbol !== void 0).sort((a, b) => {
|
|
1356
1437
|
const aExternal = a.file === fileFilter ? 0 : 1;
|
|
1357
1438
|
const bExternal = b.file === fileFilter ? 0 : 1;
|
|
@@ -1377,6 +1458,7 @@ import { Worker } from "node:worker_threads";
|
|
|
1377
1458
|
import { expectDefined as expectDefined5 } from "@wrongstack/core";
|
|
1378
1459
|
import * as fs7 from "node:fs/promises";
|
|
1379
1460
|
import * as path8 from "node:path";
|
|
1461
|
+
import { availableParallelism } from "node:os";
|
|
1380
1462
|
import { compileGlob as compileGlob2 } from "@wrongstack/core";
|
|
1381
1463
|
|
|
1382
1464
|
// src/codebase-index/ts-parser.ts
|
|
@@ -1433,8 +1515,7 @@ function extToLang(ext) {
|
|
|
1433
1515
|
return null;
|
|
1434
1516
|
}
|
|
1435
1517
|
}
|
|
1436
|
-
function getSignature(node, sourceFile) {
|
|
1437
|
-
const printer = ts.createPrinter({});
|
|
1518
|
+
function getSignature(printer, node, sourceFile) {
|
|
1438
1519
|
const raw = printer.printNode(ts.EmitHint.Unspecified, node, sourceFile);
|
|
1439
1520
|
return raw.replace(/\s+/g, " ").slice(0, 500);
|
|
1440
1521
|
}
|
|
@@ -1453,28 +1534,14 @@ function getJsDoc(node, sourceFile) {
|
|
|
1453
1534
|
}
|
|
1454
1535
|
return "";
|
|
1455
1536
|
}
|
|
1456
|
-
function
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
return false;
|
|
1463
|
-
}
|
|
1464
|
-
function buildScope(node) {
|
|
1465
|
-
const parts = [];
|
|
1466
|
-
let current = node.parent;
|
|
1467
|
-
while (current) {
|
|
1468
|
-
if (ts.isClassDeclaration(current) || ts.isInterfaceDeclaration(current) || ts.isEnumDeclaration(current) || ts.isTypeAliasDeclaration(current)) {
|
|
1469
|
-
parts.unshift(current.name?.text ?? "Anon");
|
|
1470
|
-
} else if (ts.isMethodDeclaration(current) || ts.isGetAccessor(current) || ts.isSetAccessor(current) || ts.isPropertyDeclaration(current) || ts.isFunctionDeclaration(current)) {
|
|
1471
|
-
if (current.name && ts.isIdentifier(current.name)) {
|
|
1472
|
-
parts.unshift(current.name.text);
|
|
1473
|
-
}
|
|
1537
|
+
function pushScopeName(node, parts) {
|
|
1538
|
+
if (ts.isClassDeclaration(node) || ts.isInterfaceDeclaration(node) || ts.isEnumDeclaration(node) || ts.isTypeAliasDeclaration(node)) {
|
|
1539
|
+
parts.push(node.name?.text ?? "Anon");
|
|
1540
|
+
} else if (ts.isMethodDeclaration(node) || ts.isGetAccessor(node) || ts.isSetAccessor(node) || ts.isPropertyDeclaration(node) || ts.isFunctionDeclaration(node)) {
|
|
1541
|
+
if (node.name && ts.isIdentifier(node.name)) {
|
|
1542
|
+
parts.push(node.name.text);
|
|
1474
1543
|
}
|
|
1475
|
-
current = current.parent;
|
|
1476
1544
|
}
|
|
1477
|
-
return parts.join(".");
|
|
1478
1545
|
}
|
|
1479
1546
|
function parseSymbols(opts) {
|
|
1480
1547
|
const { file, content, lang } = opts;
|
|
@@ -1485,45 +1552,39 @@ function parseSymbols(opts) {
|
|
|
1485
1552
|
return { file, lang, symbols: [], mtimeMs: Date.now() };
|
|
1486
1553
|
}
|
|
1487
1554
|
const symbols = [];
|
|
1488
|
-
|
|
1555
|
+
const refs = [];
|
|
1556
|
+
const printer = ts.createPrinter({});
|
|
1557
|
+
function visit(node, funcDepth, scopeParts) {
|
|
1489
1558
|
const kind = kindOf(node);
|
|
1490
1559
|
if (kind) {
|
|
1491
|
-
if ((kind === "const" || kind === "let" || kind === "var" || kind === "parameter") &&
|
|
1492
|
-
|
|
1493
|
-
|
|
1560
|
+
if ((kind === "const" || kind === "let" || kind === "var" || kind === "parameter") && funcDepth > 0) {
|
|
1561
|
+
} else {
|
|
1562
|
+
const nameNode = node.name;
|
|
1563
|
+
if (!nameNode || !ts.isIdentifier(nameNode)) {
|
|
1564
|
+
return;
|
|
1565
|
+
}
|
|
1566
|
+
const name = nameNode.text;
|
|
1567
|
+
const pos2 = nameNode.getStart(sourceFile);
|
|
1568
|
+
const { line: line2, character } = sourceFile.getLineAndCharacterOfPosition(pos2);
|
|
1569
|
+
const scope = scopeParts.join(".");
|
|
1570
|
+
const signature = getSignature(printer, node, sourceFile);
|
|
1571
|
+
const docComment = getJsDoc(node, sourceFile);
|
|
1572
|
+
const text = [name, signature, docComment].filter(Boolean).join(" | ");
|
|
1573
|
+
symbols.push({
|
|
1574
|
+
id: 0,
|
|
1575
|
+
lang,
|
|
1576
|
+
kind,
|
|
1577
|
+
name,
|
|
1578
|
+
file,
|
|
1579
|
+
line: line2 + 1,
|
|
1580
|
+
col: character,
|
|
1581
|
+
signature,
|
|
1582
|
+
docComment,
|
|
1583
|
+
scope,
|
|
1584
|
+
text
|
|
1585
|
+
});
|
|
1494
1586
|
}
|
|
1495
|
-
const nameNode = node.name;
|
|
1496
|
-
if (!nameNode || !ts.isIdentifier(nameNode)) return;
|
|
1497
|
-
const name = nameNode.text;
|
|
1498
|
-
const pos = nameNode.getStart(sourceFile);
|
|
1499
|
-
const { line, character } = sourceFile.getLineAndCharacterOfPosition(pos);
|
|
1500
|
-
const scope = buildScope(node);
|
|
1501
|
-
const signature = getSignature(node, sourceFile);
|
|
1502
|
-
const docComment = getJsDoc(node, sourceFile);
|
|
1503
|
-
const text = [name, signature, docComment].filter(Boolean).join(" | ");
|
|
1504
|
-
symbols.push({
|
|
1505
|
-
id: 0,
|
|
1506
|
-
lang,
|
|
1507
|
-
kind,
|
|
1508
|
-
name,
|
|
1509
|
-
file,
|
|
1510
|
-
line: line + 1,
|
|
1511
|
-
col: character,
|
|
1512
|
-
signature,
|
|
1513
|
-
docComment,
|
|
1514
|
-
scope,
|
|
1515
|
-
text
|
|
1516
|
-
});
|
|
1517
1587
|
}
|
|
1518
|
-
ts.forEachChild(node, visit);
|
|
1519
|
-
}
|
|
1520
|
-
visit(sourceFile);
|
|
1521
|
-
const refs = extractRefs(sourceFile);
|
|
1522
|
-
return { file, lang, symbols, refs, mtimeMs: Date.now() };
|
|
1523
|
-
}
|
|
1524
|
-
function extractRefs(sourceFile) {
|
|
1525
|
-
const refs = [];
|
|
1526
|
-
function visit(node) {
|
|
1527
1588
|
const pos = node.getStart(sourceFile);
|
|
1528
1589
|
const { line } = sourceFile.getLineAndCharacterOfPosition(pos);
|
|
1529
1590
|
const lineNum = line + 1;
|
|
@@ -1548,10 +1609,14 @@ function extractRefs(sourceFile) {
|
|
|
1548
1609
|
const moduleName = getModuleName(node);
|
|
1549
1610
|
if (moduleName) refs.push({ fromId: 0, toName: moduleName, callType: "import", line: lineNum });
|
|
1550
1611
|
}
|
|
1551
|
-
|
|
1612
|
+
const scopeIdx = scopeParts.length;
|
|
1613
|
+
pushScopeName(node, scopeParts);
|
|
1614
|
+
const childFuncDepth = ts.isFunctionLike(node) ? funcDepth + 1 : funcDepth;
|
|
1615
|
+
ts.forEachChild(node, (child) => visit(child, childFuncDepth, scopeParts));
|
|
1616
|
+
scopeParts.length = scopeIdx;
|
|
1552
1617
|
}
|
|
1553
|
-
visit(sourceFile);
|
|
1554
|
-
return deduplicateRefs(refs);
|
|
1618
|
+
visit(sourceFile, 0, []);
|
|
1619
|
+
return { file, lang, symbols, refs: deduplicateRefs(refs), mtimeMs: Date.now() };
|
|
1555
1620
|
}
|
|
1556
1621
|
function getTypeName(name) {
|
|
1557
1622
|
if (ts.isIdentifier(name)) return name.text;
|
|
@@ -2856,7 +2921,7 @@ async function loadGitignoreMatcher(projectRoot) {
|
|
|
2856
2921
|
|
|
2857
2922
|
// src/codebase-index/indexer.ts
|
|
2858
2923
|
var YIELD_EVERY_N = 50;
|
|
2859
|
-
var PARALLEL_BATCH =
|
|
2924
|
+
var PARALLEL_BATCH = Math.min(availableParallelism() * 4, 40);
|
|
2860
2925
|
function yieldEventLoop() {
|
|
2861
2926
|
return new Promise((resolve2) => setImmediate(resolve2));
|
|
2862
2927
|
}
|
|
@@ -3034,11 +3099,14 @@ async function runIndexerWithStore(store, opts) {
|
|
|
3034
3099
|
if (!force) {
|
|
3035
3100
|
for (const meta of store.getAllFileMetas()) existingMeta.set(meta.file, meta);
|
|
3036
3101
|
}
|
|
3102
|
+
let filesSinceLastYield = 0;
|
|
3037
3103
|
for (let batchStart = 0; batchStart < files.length; batchStart += PARALLEL_BATCH) {
|
|
3038
3104
|
const batchEnd = Math.min(batchStart + PARALLEL_BATCH, files.length);
|
|
3039
3105
|
const batchFiles = files.slice(batchStart, batchEnd);
|
|
3040
3106
|
opts.onProgress?.(batchEnd, files.length);
|
|
3041
|
-
|
|
3107
|
+
filesSinceLastYield += batchFiles.length;
|
|
3108
|
+
if (filesSinceLastYield >= YIELD_EVERY_N) {
|
|
3109
|
+
filesSinceLastYield = 0;
|
|
3042
3110
|
await yieldEventLoop();
|
|
3043
3111
|
throwIfAborted(signal);
|
|
3044
3112
|
}
|
|
@@ -3249,7 +3317,7 @@ async function indexService(args, hooks = {}) {
|
|
|
3249
3317
|
});
|
|
3250
3318
|
}
|
|
3251
3319
|
function searchService(args) {
|
|
3252
|
-
const store =
|
|
3320
|
+
const store = indexStorePool.acquire(args.projectRoot, { indexDir: args.indexDir });
|
|
3253
3321
|
try {
|
|
3254
3322
|
return store.searchRanked(
|
|
3255
3323
|
args.query,
|
|
@@ -3262,39 +3330,39 @@ function searchService(args) {
|
|
|
3262
3330
|
args.limit
|
|
3263
3331
|
);
|
|
3264
3332
|
} finally {
|
|
3265
|
-
|
|
3333
|
+
indexStorePool.release(store);
|
|
3266
3334
|
}
|
|
3267
3335
|
}
|
|
3268
3336
|
function statsService(args) {
|
|
3269
|
-
const store =
|
|
3337
|
+
const store = indexStorePool.acquire(args.projectRoot, { indexDir: args.indexDir });
|
|
3270
3338
|
try {
|
|
3271
3339
|
return store.getStats();
|
|
3272
3340
|
} finally {
|
|
3273
|
-
|
|
3341
|
+
indexStorePool.release(store);
|
|
3274
3342
|
}
|
|
3275
3343
|
}
|
|
3276
3344
|
function packageGraphService(args) {
|
|
3277
|
-
const store =
|
|
3345
|
+
const store = indexStorePool.acquire(args.projectRoot, { indexDir: args.indexDir });
|
|
3278
3346
|
try {
|
|
3279
3347
|
return store.getPackageGraph();
|
|
3280
3348
|
} finally {
|
|
3281
|
-
|
|
3349
|
+
indexStorePool.release(store);
|
|
3282
3350
|
}
|
|
3283
3351
|
}
|
|
3284
3352
|
function fileGraphService(args) {
|
|
3285
|
-
const store =
|
|
3353
|
+
const store = indexStorePool.acquire(args.projectRoot, { indexDir: args.indexDir });
|
|
3286
3354
|
try {
|
|
3287
3355
|
return store.getFileGraph(args.packageFilter);
|
|
3288
3356
|
} finally {
|
|
3289
|
-
|
|
3357
|
+
indexStorePool.release(store);
|
|
3290
3358
|
}
|
|
3291
3359
|
}
|
|
3292
3360
|
function symbolGraphService(args) {
|
|
3293
|
-
const store =
|
|
3361
|
+
const store = indexStorePool.acquire(args.projectRoot, { indexDir: args.indexDir });
|
|
3294
3362
|
try {
|
|
3295
3363
|
return store.getSymbolGraph(args.fileFilter);
|
|
3296
3364
|
} finally {
|
|
3297
|
-
|
|
3365
|
+
indexStorePool.release(store);
|
|
3298
3366
|
}
|
|
3299
3367
|
}
|
|
3300
3368
|
|
|
@@ -3411,10 +3479,19 @@ function terminateWorker(reason) {
|
|
|
3411
3479
|
if (w) void w.terminate().catch(() => {
|
|
3412
3480
|
});
|
|
3413
3481
|
}
|
|
3414
|
-
function shutdownCodebaseIndexHost() {
|
|
3482
|
+
async function shutdownCodebaseIndexHost() {
|
|
3415
3483
|
cancelPendingReindexes();
|
|
3416
|
-
|
|
3484
|
+
indexStorePool.closeAll();
|
|
3485
|
+
const w = worker;
|
|
3486
|
+
worker = null;
|
|
3487
|
+
failAllPending(new Error("codebase-index host shut down"));
|
|
3417
3488
|
workerUnavailable = false;
|
|
3489
|
+
if (w) {
|
|
3490
|
+
try {
|
|
3491
|
+
await w.terminate();
|
|
3492
|
+
} catch {
|
|
3493
|
+
}
|
|
3494
|
+
}
|
|
3418
3495
|
}
|
|
3419
3496
|
function callIndexOp(op, args, opts) {
|
|
3420
3497
|
const w = ensureWorker();
|