@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
package/dist/pack.js
CHANGED
|
@@ -7774,6 +7774,53 @@ function codebaseIndexDirOverride(ctx) {
|
|
|
7774
7774
|
const v = ctx.meta?.["codebaseIndexDir"];
|
|
7775
7775
|
return typeof v === "string" ? v : void 0;
|
|
7776
7776
|
}
|
|
7777
|
+
var StorePool = class {
|
|
7778
|
+
stores = /* @__PURE__ */ new Map();
|
|
7779
|
+
key(projectRoot, indexDir) {
|
|
7780
|
+
return `${projectRoot}\0${indexDir ?? ""}`;
|
|
7781
|
+
}
|
|
7782
|
+
/** Borrow a store. Creates it on first access for this key. */
|
|
7783
|
+
acquire(projectRoot, opts) {
|
|
7784
|
+
const k = this.key(projectRoot, opts?.indexDir);
|
|
7785
|
+
let store = this.stores.get(k);
|
|
7786
|
+
if (!store) {
|
|
7787
|
+
store = new IndexStore(projectRoot, { indexDir: opts?.indexDir });
|
|
7788
|
+
this.stores.set(k, store);
|
|
7789
|
+
}
|
|
7790
|
+
return store;
|
|
7791
|
+
}
|
|
7792
|
+
/** Return the store to the pool. The connection stays warm for subsequent
|
|
7793
|
+
* operations on the same (projectRoot, indexDir). */
|
|
7794
|
+
release(_store) {
|
|
7795
|
+
}
|
|
7796
|
+
/** Close every pooled connection and drain the pool. Call on shutdown. */
|
|
7797
|
+
closeAll() {
|
|
7798
|
+
for (const store of this.stores.values()) {
|
|
7799
|
+
try {
|
|
7800
|
+
store.close();
|
|
7801
|
+
} catch {
|
|
7802
|
+
}
|
|
7803
|
+
}
|
|
7804
|
+
this.stores.clear();
|
|
7805
|
+
}
|
|
7806
|
+
/** Remove one store from the pool. Used by tests that need isolation. */
|
|
7807
|
+
evict(projectRoot, indexDir) {
|
|
7808
|
+
const k = this.key(projectRoot, indexDir);
|
|
7809
|
+
const store = this.stores.get(k);
|
|
7810
|
+
if (store) {
|
|
7811
|
+
try {
|
|
7812
|
+
store.close();
|
|
7813
|
+
} catch {
|
|
7814
|
+
}
|
|
7815
|
+
this.stores.delete(k);
|
|
7816
|
+
}
|
|
7817
|
+
}
|
|
7818
|
+
/** True when the pool holds a connection for the given key. */
|
|
7819
|
+
has(projectRoot, indexDir) {
|
|
7820
|
+
return this.stores.has(this.key(projectRoot, indexDir));
|
|
7821
|
+
}
|
|
7822
|
+
};
|
|
7823
|
+
var indexStorePool = new StorePool();
|
|
7777
7824
|
var warningSilenced = false;
|
|
7778
7825
|
function silenceSqliteExperimentalWarning() {
|
|
7779
7826
|
if (warningSilenced) return;
|
|
@@ -7991,7 +8038,7 @@ var IndexStore = class _IndexStore {
|
|
|
7991
8038
|
return this.runWithRetry(() => {
|
|
7992
8039
|
this.db.exec("BEGIN IMMEDIATE");
|
|
7993
8040
|
try {
|
|
7994
|
-
const maxRows = this.
|
|
8041
|
+
const maxRows = this.stmt("SELECT MAX(id) AS m FROM symbols").all();
|
|
7995
8042
|
let nextId = (maxRows[0]?.m ?? 0) + 1;
|
|
7996
8043
|
const stmt = this.db.prepare(
|
|
7997
8044
|
`INSERT INTO symbols(id, lang, kind, name, file, line, col, signature, doc_comment, scope, text, file_fk)
|
|
@@ -8263,7 +8310,7 @@ var IndexStore = class _IndexStore {
|
|
|
8263
8310
|
return { results, total: candidates.length };
|
|
8264
8311
|
}
|
|
8265
8312
|
getAllIndexable() {
|
|
8266
|
-
return this.
|
|
8313
|
+
return this.stmt("SELECT id, text FROM symbols").all().map(({ id, text }) => ({ id, text }));
|
|
8267
8314
|
}
|
|
8268
8315
|
/**
|
|
8269
8316
|
* Largest symbol id currently in the table (0 when empty). New ids must be
|
|
@@ -8273,7 +8320,7 @@ var IndexStore = class _IndexStore {
|
|
|
8273
8320
|
* `symbols.id`). Ids may have gaps — that is fine.
|
|
8274
8321
|
*/
|
|
8275
8322
|
getMaxSymbolId() {
|
|
8276
|
-
const rows = this.
|
|
8323
|
+
const rows = this.stmt("SELECT MAX(id) AS m FROM symbols").all();
|
|
8277
8324
|
return rows[0]?.m ?? 0;
|
|
8278
8325
|
}
|
|
8279
8326
|
// ─── Stats ───────────────────────────────────────────────────────────────────
|
|
@@ -8281,14 +8328,14 @@ var IndexStore = class _IndexStore {
|
|
|
8281
8328
|
const sizeBytes = this.sizeBytes();
|
|
8282
8329
|
const lastRows = this.db.prepare("SELECT value FROM metadata WHERE key = 'last_indexed'").all();
|
|
8283
8330
|
const lastIndexed = lastRows.length ? Number(lastRows[0]?.value) : null;
|
|
8284
|
-
const totalRows = this.
|
|
8331
|
+
const totalRows = this.stmt("SELECT COUNT(*) FROM symbols").all();
|
|
8285
8332
|
const totalSymbols = totalRows[0] ? Number(totalRows[0]["COUNT(*)"]) : 0;
|
|
8286
|
-
const fileRows = this.
|
|
8333
|
+
const fileRows = this.stmt("SELECT COUNT(*) FROM files").all();
|
|
8287
8334
|
const totalFiles = fileRows[0] ? Number(fileRows[0]["COUNT(*)"]) : 0;
|
|
8288
|
-
const langRows = this.
|
|
8335
|
+
const langRows = this.stmt("SELECT lang, COUNT(*) FROM symbols GROUP BY lang").all();
|
|
8289
8336
|
const byLang = {};
|
|
8290
8337
|
for (const row of langRows) byLang[row.lang] = Number(row["COUNT(*)"]);
|
|
8291
|
-
const kindRows = this.
|
|
8338
|
+
const kindRows = this.stmt("SELECT kind, COUNT(*) FROM symbols GROUP BY kind").all();
|
|
8292
8339
|
const byKind = {};
|
|
8293
8340
|
for (const row of kindRows) byKind[row.kind] = Number(row["COUNT(*)"]);
|
|
8294
8341
|
return {
|
|
@@ -8320,11 +8367,14 @@ var IndexStore = class _IndexStore {
|
|
|
8320
8367
|
this.runWithRetry(() => {
|
|
8321
8368
|
this.db.exec("BEGIN IMMEDIATE");
|
|
8322
8369
|
try {
|
|
8323
|
-
this.db.exec("
|
|
8324
|
-
this.db.exec("
|
|
8325
|
-
this.db.exec("
|
|
8326
|
-
|
|
8370
|
+
this.db.exec("DROP TABLE IF EXISTS refs");
|
|
8371
|
+
this.db.exec("DROP TABLE IF EXISTS symbols");
|
|
8372
|
+
this.db.exec("DROP TABLE IF EXISTS files");
|
|
8373
|
+
this.db.exec("DROP TABLE IF EXISTS metadata");
|
|
8374
|
+
if (this.ftsAvailable) this.db.exec("DROP TABLE IF EXISTS symbols_fts");
|
|
8327
8375
|
this.db.exec("COMMIT");
|
|
8376
|
+
this.stmtCache.clear();
|
|
8377
|
+
this.initSchema();
|
|
8328
8378
|
} catch (err) {
|
|
8329
8379
|
this.db.exec("ROLLBACK");
|
|
8330
8380
|
throw err;
|
|
@@ -8409,7 +8459,7 @@ var IndexStore = class _IndexStore {
|
|
|
8409
8459
|
).run(...options.deleteForFiles);
|
|
8410
8460
|
this.db.prepare(`DELETE FROM symbols WHERE file IN (${placeholders})`).run(...options.deleteForFiles);
|
|
8411
8461
|
}
|
|
8412
|
-
const maxRows = this.
|
|
8462
|
+
const maxRows = this.stmt("SELECT MAX(id) AS m FROM symbols").all();
|
|
8413
8463
|
let nextId = (maxRows[0]?.m ?? 0) + 1;
|
|
8414
8464
|
const symStmt = this.db.prepare(
|
|
8415
8465
|
`INSERT INTO symbols(id, lang, kind, name, file, line, col, signature, doc_comment, scope, text, file_fk)
|
|
@@ -8593,7 +8643,7 @@ var IndexStore = class _IndexStore {
|
|
|
8593
8643
|
* symbol resolved in package B). Node metadata includes symbol/file counts.
|
|
8594
8644
|
*/
|
|
8595
8645
|
getPackageGraph() {
|
|
8596
|
-
const symbols = this.db.prepare("SELECT file, id
|
|
8646
|
+
const symbols = this.db.prepare("SELECT file, id FROM symbols ORDER BY id").all();
|
|
8597
8647
|
const pkgNodes = /* @__PURE__ */ new Map();
|
|
8598
8648
|
const fileToPkg = /* @__PURE__ */ new Map();
|
|
8599
8649
|
const symbolToPkg = /* @__PURE__ */ new Map();
|
|
@@ -8684,15 +8734,18 @@ var IndexStore = class _IndexStore {
|
|
|
8684
8734
|
* derived from cross-file symbol references within the package.
|
|
8685
8735
|
*/
|
|
8686
8736
|
getFileGraph(packageFilter) {
|
|
8687
|
-
const
|
|
8688
|
-
const
|
|
8689
|
-
|
|
8690
|
-
);
|
|
8691
|
-
|
|
8737
|
+
const allFiles = this.db.prepare("SELECT DISTINCT file FROM symbols").all();
|
|
8738
|
+
const pkgFilePaths = allFiles.filter((f) => (_IndexStore.derivePackage(f.file) ?? "(root)") === packageFilter).map((f) => f.file);
|
|
8739
|
+
const localFiles = new Set(pkgFilePaths);
|
|
8740
|
+
if (localFiles.size === 0) return { nodes: [], edges: [] };
|
|
8741
|
+
const filePlaceholders = [...localFiles].map(() => "?").join(",");
|
|
8742
|
+
const pkgSyms = this.db.prepare(
|
|
8743
|
+
`SELECT file, id, name, kind, lang, line FROM symbols WHERE file IN (${filePlaceholders}) ORDER BY id`
|
|
8744
|
+
).all(...pkgFilePaths);
|
|
8692
8745
|
const fileNodes = /* @__PURE__ */ new Map();
|
|
8693
8746
|
const symToFile = /* @__PURE__ */ new Map();
|
|
8694
8747
|
const fileStats = /* @__PURE__ */ new Map();
|
|
8695
|
-
for (const s of
|
|
8748
|
+
for (const s of pkgSyms) {
|
|
8696
8749
|
symToFile.set(s.id, s.file);
|
|
8697
8750
|
const current = fileStats.get(s.file);
|
|
8698
8751
|
fileStats.set(s.file, {
|
|
@@ -8700,8 +8753,6 @@ var IndexStore = class _IndexStore {
|
|
|
8700
8753
|
lang: current?.lang ?? s.lang
|
|
8701
8754
|
});
|
|
8702
8755
|
}
|
|
8703
|
-
const localFiles = new Set(pkgSyms.map((s) => s.file));
|
|
8704
|
-
const indexedFiles = new Set(allSymbols.map((s) => s.file));
|
|
8705
8756
|
const ensureFileNode = (file) => {
|
|
8706
8757
|
if (fileNodes.has(file)) return;
|
|
8707
8758
|
const stats = fileStats.get(file);
|
|
@@ -8719,11 +8770,32 @@ var IndexStore = class _IndexStore {
|
|
|
8719
8770
|
for (const file of localFiles) {
|
|
8720
8771
|
ensureFileNode(file);
|
|
8721
8772
|
}
|
|
8773
|
+
const indexedFiles = new Set(allFiles.map((f) => f.file));
|
|
8722
8774
|
const refRows = this.db.prepare(
|
|
8723
8775
|
`SELECT r.from_id, r.to_id, r.call_type
|
|
8724
8776
|
FROM refs r
|
|
8725
|
-
WHERE r.
|
|
8726
|
-
|
|
8777
|
+
WHERE (r.from_id IN (SELECT id FROM symbols WHERE file IN (${filePlaceholders}))
|
|
8778
|
+
OR r.to_id IN (SELECT id FROM symbols WHERE file IN (${filePlaceholders})))
|
|
8779
|
+
AND r.to_id IS NOT NULL`
|
|
8780
|
+
).all(...pkgFilePaths, ...pkgFilePaths);
|
|
8781
|
+
const knownSymIds = new Set(pkgSyms.map((s) => s.id));
|
|
8782
|
+
const crossRefIds = /* @__PURE__ */ new Set();
|
|
8783
|
+
for (const r of refRows) {
|
|
8784
|
+
if (!knownSymIds.has(r.from_id)) crossRefIds.add(r.from_id);
|
|
8785
|
+
if (!knownSymIds.has(r.to_id)) crossRefIds.add(r.to_id);
|
|
8786
|
+
}
|
|
8787
|
+
if (crossRefIds.size > 0) {
|
|
8788
|
+
const crossPlaceholders = [...crossRefIds].map(() => "?").join(",");
|
|
8789
|
+
const extras = this.db.prepare(
|
|
8790
|
+
`SELECT id, file FROM symbols WHERE id IN (${crossPlaceholders})`
|
|
8791
|
+
).all(...crossRefIds);
|
|
8792
|
+
for (const x of extras) {
|
|
8793
|
+
symToFile.set(x.id, x.file);
|
|
8794
|
+
if (!fileStats.has(x.file)) {
|
|
8795
|
+
fileStats.set(x.file, { count: 0, lang: "ts" });
|
|
8796
|
+
}
|
|
8797
|
+
}
|
|
8798
|
+
}
|
|
8727
8799
|
const edgeMap = /* @__PURE__ */ new Map();
|
|
8728
8800
|
for (const r of refRows) {
|
|
8729
8801
|
if (r.call_type === "import") continue;
|
|
@@ -8745,8 +8817,9 @@ var IndexStore = class _IndexStore {
|
|
|
8745
8817
|
const importRows = this.db.prepare(
|
|
8746
8818
|
`SELECT r.from_id, r.to_name
|
|
8747
8819
|
FROM refs r
|
|
8748
|
-
WHERE r.call_type = 'import'
|
|
8749
|
-
|
|
8820
|
+
WHERE r.call_type = 'import'
|
|
8821
|
+
AND r.from_id IN (SELECT id FROM symbols WHERE file IN (${filePlaceholders}))`
|
|
8822
|
+
).all(...pkgFilePaths);
|
|
8750
8823
|
for (const r of importRows) {
|
|
8751
8824
|
const fromFile = symToFile.get(r.from_id);
|
|
8752
8825
|
if (!fromFile || !localFiles.has(fromFile)) continue;
|
|
@@ -8788,12 +8861,11 @@ var IndexStore = class _IndexStore {
|
|
|
8788
8861
|
* derived from intra-file and cross-file symbol references (who calls whom).
|
|
8789
8862
|
*/
|
|
8790
8863
|
getSymbolGraph(fileFilter) {
|
|
8791
|
-
const
|
|
8792
|
-
"SELECT id, name, kind, lang, file, line, signature, scope FROM symbols ORDER BY
|
|
8793
|
-
).all();
|
|
8794
|
-
const syms = allSymbols.filter((symbol) => symbol.file === fileFilter);
|
|
8864
|
+
const syms = this.db.prepare(
|
|
8865
|
+
"SELECT id, name, kind, lang, file, line, signature, scope FROM symbols WHERE file = ? ORDER BY line, id"
|
|
8866
|
+
).all(fileFilter);
|
|
8795
8867
|
if (syms.length === 0) return { nodes: [], edges: [] };
|
|
8796
|
-
const symById = new Map(
|
|
8868
|
+
const symById = new Map(syms.map((symbol) => [symbol.id, symbol]));
|
|
8797
8869
|
const relatedIds = new Set(syms.map((symbol) => symbol.id));
|
|
8798
8870
|
const toGraphNode = (s) => ({
|
|
8799
8871
|
id: `sym:${s.id}`,
|
|
@@ -8849,6 +8921,15 @@ var IndexStore = class _IndexStore {
|
|
|
8849
8921
|
refType: bestType
|
|
8850
8922
|
});
|
|
8851
8923
|
}
|
|
8924
|
+
const loadedIds = new Set(syms.map((s) => s.id));
|
|
8925
|
+
const missingIds = [...relatedIds].filter((id) => !loadedIds.has(id));
|
|
8926
|
+
if (missingIds.length > 0) {
|
|
8927
|
+
const placeholders = missingIds.map(() => "?").join(",");
|
|
8928
|
+
const extras = this.db.prepare(
|
|
8929
|
+
`SELECT id, name, kind, lang, file, line, signature, scope FROM symbols WHERE id IN (${placeholders})`
|
|
8930
|
+
).all(...missingIds);
|
|
8931
|
+
for (const s of extras) symById.set(s.id, s);
|
|
8932
|
+
}
|
|
8852
8933
|
const nodes = [...relatedIds].map((id) => symById.get(id)).filter((symbol) => symbol !== void 0).sort((a, b) => {
|
|
8853
8934
|
const aExternal = a.file === fileFilter ? 0 : 1;
|
|
8854
8935
|
const bExternal = b.file === fileFilter ? 0 : 1;
|
|
@@ -8874,6 +8955,7 @@ import { Worker } from "node:worker_threads";
|
|
|
8874
8955
|
import { expectDefined as expectDefined6 } from "@wrongstack/core";
|
|
8875
8956
|
import * as fs14 from "node:fs/promises";
|
|
8876
8957
|
import * as path19 from "node:path";
|
|
8958
|
+
import { availableParallelism } from "node:os";
|
|
8877
8959
|
import { compileGlob as compileGlob2 } from "@wrongstack/core";
|
|
8878
8960
|
|
|
8879
8961
|
// src/codebase-index/ts-parser.ts
|
|
@@ -8930,8 +9012,7 @@ function extToLang(ext) {
|
|
|
8930
9012
|
return null;
|
|
8931
9013
|
}
|
|
8932
9014
|
}
|
|
8933
|
-
function getSignature(node, sourceFile) {
|
|
8934
|
-
const printer = ts.createPrinter({});
|
|
9015
|
+
function getSignature(printer, node, sourceFile) {
|
|
8935
9016
|
const raw = printer.printNode(ts.EmitHint.Unspecified, node, sourceFile);
|
|
8936
9017
|
return raw.replace(/\s+/g, " ").slice(0, 500);
|
|
8937
9018
|
}
|
|
@@ -8950,28 +9031,14 @@ function getJsDoc(node, sourceFile) {
|
|
|
8950
9031
|
}
|
|
8951
9032
|
return "";
|
|
8952
9033
|
}
|
|
8953
|
-
function
|
|
8954
|
-
|
|
8955
|
-
|
|
8956
|
-
|
|
8957
|
-
|
|
8958
|
-
|
|
8959
|
-
return false;
|
|
8960
|
-
}
|
|
8961
|
-
function buildScope(node) {
|
|
8962
|
-
const parts = [];
|
|
8963
|
-
let current = node.parent;
|
|
8964
|
-
while (current) {
|
|
8965
|
-
if (ts.isClassDeclaration(current) || ts.isInterfaceDeclaration(current) || ts.isEnumDeclaration(current) || ts.isTypeAliasDeclaration(current)) {
|
|
8966
|
-
parts.unshift(current.name?.text ?? "Anon");
|
|
8967
|
-
} else if (ts.isMethodDeclaration(current) || ts.isGetAccessor(current) || ts.isSetAccessor(current) || ts.isPropertyDeclaration(current) || ts.isFunctionDeclaration(current)) {
|
|
8968
|
-
if (current.name && ts.isIdentifier(current.name)) {
|
|
8969
|
-
parts.unshift(current.name.text);
|
|
8970
|
-
}
|
|
9034
|
+
function pushScopeName(node, parts) {
|
|
9035
|
+
if (ts.isClassDeclaration(node) || ts.isInterfaceDeclaration(node) || ts.isEnumDeclaration(node) || ts.isTypeAliasDeclaration(node)) {
|
|
9036
|
+
parts.push(node.name?.text ?? "Anon");
|
|
9037
|
+
} else if (ts.isMethodDeclaration(node) || ts.isGetAccessor(node) || ts.isSetAccessor(node) || ts.isPropertyDeclaration(node) || ts.isFunctionDeclaration(node)) {
|
|
9038
|
+
if (node.name && ts.isIdentifier(node.name)) {
|
|
9039
|
+
parts.push(node.name.text);
|
|
8971
9040
|
}
|
|
8972
|
-
current = current.parent;
|
|
8973
9041
|
}
|
|
8974
|
-
return parts.join(".");
|
|
8975
9042
|
}
|
|
8976
9043
|
function parseSymbols(opts) {
|
|
8977
9044
|
const { file, content, lang } = opts;
|
|
@@ -8982,45 +9049,39 @@ function parseSymbols(opts) {
|
|
|
8982
9049
|
return { file, lang, symbols: [], mtimeMs: Date.now() };
|
|
8983
9050
|
}
|
|
8984
9051
|
const symbols = [];
|
|
8985
|
-
|
|
9052
|
+
const refs = [];
|
|
9053
|
+
const printer = ts.createPrinter({});
|
|
9054
|
+
function visit(node, funcDepth, scopeParts) {
|
|
8986
9055
|
const kind = kindOf(node);
|
|
8987
9056
|
if (kind) {
|
|
8988
|
-
if ((kind === "const" || kind === "let" || kind === "var" || kind === "parameter") &&
|
|
8989
|
-
|
|
8990
|
-
|
|
9057
|
+
if ((kind === "const" || kind === "let" || kind === "var" || kind === "parameter") && funcDepth > 0) {
|
|
9058
|
+
} else {
|
|
9059
|
+
const nameNode = node.name;
|
|
9060
|
+
if (!nameNode || !ts.isIdentifier(nameNode)) {
|
|
9061
|
+
return;
|
|
9062
|
+
}
|
|
9063
|
+
const name = nameNode.text;
|
|
9064
|
+
const pos2 = nameNode.getStart(sourceFile);
|
|
9065
|
+
const { line: line2, character } = sourceFile.getLineAndCharacterOfPosition(pos2);
|
|
9066
|
+
const scope = scopeParts.join(".");
|
|
9067
|
+
const signature = getSignature(printer, node, sourceFile);
|
|
9068
|
+
const docComment = getJsDoc(node, sourceFile);
|
|
9069
|
+
const text = [name, signature, docComment].filter(Boolean).join(" | ");
|
|
9070
|
+
symbols.push({
|
|
9071
|
+
id: 0,
|
|
9072
|
+
lang,
|
|
9073
|
+
kind,
|
|
9074
|
+
name,
|
|
9075
|
+
file,
|
|
9076
|
+
line: line2 + 1,
|
|
9077
|
+
col: character,
|
|
9078
|
+
signature,
|
|
9079
|
+
docComment,
|
|
9080
|
+
scope,
|
|
9081
|
+
text
|
|
9082
|
+
});
|
|
8991
9083
|
}
|
|
8992
|
-
const nameNode = node.name;
|
|
8993
|
-
if (!nameNode || !ts.isIdentifier(nameNode)) return;
|
|
8994
|
-
const name = nameNode.text;
|
|
8995
|
-
const pos = nameNode.getStart(sourceFile);
|
|
8996
|
-
const { line, character } = sourceFile.getLineAndCharacterOfPosition(pos);
|
|
8997
|
-
const scope = buildScope(node);
|
|
8998
|
-
const signature = getSignature(node, sourceFile);
|
|
8999
|
-
const docComment = getJsDoc(node, sourceFile);
|
|
9000
|
-
const text = [name, signature, docComment].filter(Boolean).join(" | ");
|
|
9001
|
-
symbols.push({
|
|
9002
|
-
id: 0,
|
|
9003
|
-
lang,
|
|
9004
|
-
kind,
|
|
9005
|
-
name,
|
|
9006
|
-
file,
|
|
9007
|
-
line: line + 1,
|
|
9008
|
-
col: character,
|
|
9009
|
-
signature,
|
|
9010
|
-
docComment,
|
|
9011
|
-
scope,
|
|
9012
|
-
text
|
|
9013
|
-
});
|
|
9014
9084
|
}
|
|
9015
|
-
ts.forEachChild(node, visit);
|
|
9016
|
-
}
|
|
9017
|
-
visit(sourceFile);
|
|
9018
|
-
const refs = extractRefs(sourceFile);
|
|
9019
|
-
return { file, lang, symbols, refs, mtimeMs: Date.now() };
|
|
9020
|
-
}
|
|
9021
|
-
function extractRefs(sourceFile) {
|
|
9022
|
-
const refs = [];
|
|
9023
|
-
function visit(node) {
|
|
9024
9085
|
const pos = node.getStart(sourceFile);
|
|
9025
9086
|
const { line } = sourceFile.getLineAndCharacterOfPosition(pos);
|
|
9026
9087
|
const lineNum = line + 1;
|
|
@@ -9045,10 +9106,14 @@ function extractRefs(sourceFile) {
|
|
|
9045
9106
|
const moduleName = getModuleName(node);
|
|
9046
9107
|
if (moduleName) refs.push({ fromId: 0, toName: moduleName, callType: "import", line: lineNum });
|
|
9047
9108
|
}
|
|
9048
|
-
|
|
9109
|
+
const scopeIdx = scopeParts.length;
|
|
9110
|
+
pushScopeName(node, scopeParts);
|
|
9111
|
+
const childFuncDepth = ts.isFunctionLike(node) ? funcDepth + 1 : funcDepth;
|
|
9112
|
+
ts.forEachChild(node, (child) => visit(child, childFuncDepth, scopeParts));
|
|
9113
|
+
scopeParts.length = scopeIdx;
|
|
9049
9114
|
}
|
|
9050
|
-
visit(sourceFile);
|
|
9051
|
-
return deduplicateRefs(refs);
|
|
9115
|
+
visit(sourceFile, 0, []);
|
|
9116
|
+
return { file, lang, symbols, refs: deduplicateRefs(refs), mtimeMs: Date.now() };
|
|
9052
9117
|
}
|
|
9053
9118
|
function getTypeName(name) {
|
|
9054
9119
|
if (ts.isIdentifier(name)) return name.text;
|
|
@@ -10330,7 +10395,7 @@ async function loadGitignoreMatcher(projectRoot) {
|
|
|
10330
10395
|
|
|
10331
10396
|
// src/codebase-index/indexer.ts
|
|
10332
10397
|
var YIELD_EVERY_N = 50;
|
|
10333
|
-
var PARALLEL_BATCH =
|
|
10398
|
+
var PARALLEL_BATCH = Math.min(availableParallelism() * 4, 40);
|
|
10334
10399
|
function yieldEventLoop() {
|
|
10335
10400
|
return new Promise((resolve14) => setImmediate(resolve14));
|
|
10336
10401
|
}
|
|
@@ -10508,11 +10573,14 @@ async function runIndexerWithStore(store, opts) {
|
|
|
10508
10573
|
if (!force) {
|
|
10509
10574
|
for (const meta of store.getAllFileMetas()) existingMeta.set(meta.file, meta);
|
|
10510
10575
|
}
|
|
10576
|
+
let filesSinceLastYield = 0;
|
|
10511
10577
|
for (let batchStart = 0; batchStart < files.length; batchStart += PARALLEL_BATCH) {
|
|
10512
10578
|
const batchEnd = Math.min(batchStart + PARALLEL_BATCH, files.length);
|
|
10513
10579
|
const batchFiles = files.slice(batchStart, batchEnd);
|
|
10514
10580
|
opts.onProgress?.(batchEnd, files.length);
|
|
10515
|
-
|
|
10581
|
+
filesSinceLastYield += batchFiles.length;
|
|
10582
|
+
if (filesSinceLastYield >= YIELD_EVERY_N) {
|
|
10583
|
+
filesSinceLastYield = 0;
|
|
10516
10584
|
await yieldEventLoop();
|
|
10517
10585
|
throwIfAborted(signal);
|
|
10518
10586
|
}
|
|
@@ -10723,7 +10791,7 @@ async function indexService(args, hooks = {}) {
|
|
|
10723
10791
|
});
|
|
10724
10792
|
}
|
|
10725
10793
|
function searchService(args) {
|
|
10726
|
-
const store =
|
|
10794
|
+
const store = indexStorePool.acquire(args.projectRoot, { indexDir: args.indexDir });
|
|
10727
10795
|
try {
|
|
10728
10796
|
return store.searchRanked(
|
|
10729
10797
|
args.query,
|
|
@@ -10736,15 +10804,15 @@ function searchService(args) {
|
|
|
10736
10804
|
args.limit
|
|
10737
10805
|
);
|
|
10738
10806
|
} finally {
|
|
10739
|
-
|
|
10807
|
+
indexStorePool.release(store);
|
|
10740
10808
|
}
|
|
10741
10809
|
}
|
|
10742
10810
|
function statsService(args) {
|
|
10743
|
-
const store =
|
|
10811
|
+
const store = indexStorePool.acquire(args.projectRoot, { indexDir: args.indexDir });
|
|
10744
10812
|
try {
|
|
10745
10813
|
return store.getStats();
|
|
10746
10814
|
} finally {
|
|
10747
|
-
|
|
10815
|
+
indexStorePool.release(store);
|
|
10748
10816
|
}
|
|
10749
10817
|
}
|
|
10750
10818
|
|
|
@@ -16098,7 +16166,7 @@ import {
|
|
|
16098
16166
|
duplicateBoard,
|
|
16099
16167
|
exportBoardAsMarkdown,
|
|
16100
16168
|
exportBoardToTaskGraph,
|
|
16101
|
-
|
|
16169
|
+
createBoardFromText,
|
|
16102
16170
|
getBoard as getBoard2,
|
|
16103
16171
|
getKanbanOrchestrationSnapshot,
|
|
16104
16172
|
getKanbanQueueHealth,
|
|
@@ -16622,7 +16690,7 @@ var kanbanTool = {
|
|
|
16622
16690
|
}
|
|
16623
16691
|
case "generate_board": {
|
|
16624
16692
|
if (!input.description) return fail("generate_board requires description.");
|
|
16625
|
-
const boardInput =
|
|
16693
|
+
const boardInput = createBoardFromText({
|
|
16626
16694
|
description: input.description,
|
|
16627
16695
|
...input.title !== void 0 ? { title: input.title } : {},
|
|
16628
16696
|
...input.context !== void 0 ? { context: input.context } : {},
|
|
@@ -17007,20 +17075,31 @@ var kanbanTool = {
|
|
|
17007
17075
|
if (!input.boardId || !input.taskId)
|
|
17008
17076
|
return fail("mark_assignment requires boardId and taskId.");
|
|
17009
17077
|
const assignmentStatus = input.assignmentStatus ?? (input.status === "completed" ? "completed" : input.error ? "failed" : void 0);
|
|
17010
|
-
const board = await updateTaskAssignment(
|
|
17011
|
-
|
|
17012
|
-
|
|
17013
|
-
|
|
17014
|
-
|
|
17015
|
-
|
|
17016
|
-
|
|
17017
|
-
|
|
17018
|
-
|
|
17019
|
-
|
|
17020
|
-
|
|
17021
|
-
|
|
17022
|
-
|
|
17023
|
-
|
|
17078
|
+
const board = await updateTaskAssignment(
|
|
17079
|
+
projectRoot,
|
|
17080
|
+
input.boardId,
|
|
17081
|
+
input.taskId,
|
|
17082
|
+
{
|
|
17083
|
+
...assignmentStatus !== void 0 ? { status: assignmentStatus } : {},
|
|
17084
|
+
...input.subagentId !== void 0 ? { subagentId: input.subagentId } : {},
|
|
17085
|
+
...input.runTaskId !== void 0 ? { runTaskId: input.runTaskId } : {},
|
|
17086
|
+
...input.lastResult !== void 0 ? { lastResult: input.lastResult } : {},
|
|
17087
|
+
...input.error !== void 0 ? { error: input.error } : {},
|
|
17088
|
+
...input.agentId !== void 0 ? { agentId: input.agentId } : {},
|
|
17089
|
+
...input.leaseId !== void 0 ? { leaseId: input.leaseId } : {},
|
|
17090
|
+
...input.claimedAt !== void 0 ? { claimedAt: input.claimedAt } : {},
|
|
17091
|
+
...input.heartbeatAt !== void 0 ? { heartbeatAt: input.heartbeatAt } : {},
|
|
17092
|
+
...input.leaseExpiresAt !== void 0 ? { leaseExpiresAt: input.leaseExpiresAt } : {},
|
|
17093
|
+
...input.attempt !== void 0 ? { attempt: input.attempt } : {},
|
|
17094
|
+
...input.maxAttempts !== void 0 ? { maxAttempts: input.maxAttempts } : {}
|
|
17095
|
+
},
|
|
17096
|
+
// Ownership fence: when expectedLeaseId is supplied, the write is
|
|
17097
|
+
// applied only if the current assignment still holds this lease.
|
|
17098
|
+
// This prevents a recovered+reassigned stale worker's terminal
|
|
17099
|
+
// mark_assignment from overwriting the successor's state. The check
|
|
17100
|
+
// is atomic inside updateTaskAssignment's mutateBoard lock.
|
|
17101
|
+
input.expectedLeaseId !== void 0 ? { expectedLeaseId: input.expectedLeaseId } : {}
|
|
17102
|
+
);
|
|
17024
17103
|
return board ? okBoard(board, "Assignment updated.") : fail("Task not found.");
|
|
17025
17104
|
}
|
|
17026
17105
|
case "heartbeat_assignment": {
|
|
@@ -17029,7 +17108,13 @@ var kanbanTool = {
|
|
|
17029
17108
|
}
|
|
17030
17109
|
const board = await heartbeatTaskAssignment(projectRoot, input.boardId, input.taskId, {
|
|
17031
17110
|
...input.heartbeatAt !== void 0 ? { heartbeatAt: input.heartbeatAt } : {},
|
|
17032
|
-
...input.leaseExpiresAt !== void 0 ? { leaseExpiresAt: input.leaseExpiresAt } : {}
|
|
17111
|
+
...input.leaseExpiresAt !== void 0 ? { leaseExpiresAt: input.leaseExpiresAt } : {},
|
|
17112
|
+
// Ownership fence: when expectedLeaseId is supplied, the renewal
|
|
17113
|
+
// is applied only if the current assignment still holds this lease.
|
|
17114
|
+
// This prevents a recovered+reassigned stale worker's heartbeat
|
|
17115
|
+
// from renewing the successor's lease. The check is atomic inside
|
|
17116
|
+
// heartbeatTaskAssignment's mutateBoard lock.
|
|
17117
|
+
...input.expectedLeaseId !== void 0 ? { expectedLeaseId: input.expectedLeaseId } : {}
|
|
17033
17118
|
});
|
|
17034
17119
|
return board ? okBoard(board, "Assignment heartbeat updated.") : fail("Task assignment not found.");
|
|
17035
17120
|
}
|