@wrongstack/tools 0.275.1 → 0.276.3
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/{background-indexer-BoTUw0EM.d.ts → background-indexer-BeDBxfSh.d.ts} +6 -0
- package/dist/builtin.js +1056 -246
- package/dist/builtin.js.map +1 -1
- package/dist/codebase-index/index.d.ts +30 -2
- package/dist/codebase-index/index.js +201 -24
- package/dist/codebase-index/index.js.map +1 -1
- package/dist/codebase-index/worker.js +196 -23
- package/dist/codebase-index/worker.js.map +1 -1
- package/dist/document.js +2 -2
- package/dist/document.js.map +1 -1
- package/dist/edit.js +52 -15
- package/dist/edit.js.map +1 -1
- package/dist/fetch.js +89 -18
- package/dist/fetch.js.map +1 -1
- package/dist/glob.js +35 -1
- package/dist/glob.js.map +1 -1
- package/dist/grep.js +15 -4
- package/dist/grep.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1090 -255
- package/dist/index.js.map +1 -1
- package/dist/install.d.ts +7 -0
- package/dist/install.js +6 -0
- package/dist/install.js.map +1 -1
- package/dist/json.d.ts +26 -1
- package/dist/json.js +453 -46
- package/dist/json.js.map +1 -1
- package/dist/memory.js +26 -4
- package/dist/memory.js.map +1 -1
- package/dist/outdated.js +2 -2
- package/dist/outdated.js.map +1 -1
- package/dist/pack.js +1056 -246
- package/dist/pack.js.map +1 -1
- package/dist/read.js +36 -6
- package/dist/read.js.map +1 -1
- package/dist/replace.js +27 -9
- package/dist/replace.js.map +1 -1
- package/dist/search.d.ts +5 -1
- package/dist/search.js +179 -62
- package/dist/search.js.map +1 -1
- package/dist/tool-help.js +2 -2
- package/dist/tool-help.js.map +1 -1
- package/dist/tool-search.js +2 -2
- package/dist/tool-search.js.map +1 -1
- package/dist/write.js +13 -3
- package/dist/write.js.map +1 -1
- package/package.json +2 -2
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { I as IndexResult, S as Symbol, F as FileMeta, a as SymbolKind, b as SymbolLang, c as SearchResult, d as IndexStats, R as Ref } from '../background-indexer-
|
|
2
|
-
export { C as CircuitOpenError, e as CircuitSnapshot, f as CircuitState, g as FileSymbols, h as IndexCircuitBreaker, i as IndexTimeoutError, j as SCHEMA_VERSION, k as cancelPendingReindexes, l as codebaseIndexStats, m as codebaseIndexTool, n as codebaseSearchTool, o as codebaseStatsTool, p as enqueueReindex, q as getIndexState, r as indexCircuitBreaker, s as isIndexReady, t as isIndexableFile, u as isIndexing, v as onIndexStateChange, w as resetIndexCircuitBreaker, x as runStartupIndex, y as searchCodebaseIndex, z as shutdownCodebaseIndexHost } from '../background-indexer-
|
|
1
|
+
import { I as IndexResult, S as Symbol, F as FileMeta, a as SymbolKind, b as SymbolLang, c as SearchResult, d as IndexStats, R as Ref } from '../background-indexer-BeDBxfSh.js';
|
|
2
|
+
export { C as CircuitOpenError, e as CircuitSnapshot, f as CircuitState, g as FileSymbols, h as IndexCircuitBreaker, i as IndexTimeoutError, j as SCHEMA_VERSION, k as cancelPendingReindexes, l as codebaseIndexStats, m as codebaseIndexTool, n as codebaseSearchTool, o as codebaseStatsTool, p as enqueueReindex, q as getIndexState, r as indexCircuitBreaker, s as isIndexReady, t as isIndexableFile, u as isIndexing, v as onIndexStateChange, w as resetIndexCircuitBreaker, x as runStartupIndex, y as searchCodebaseIndex, z as shutdownCodebaseIndexHost } from '../background-indexer-BeDBxfSh.js';
|
|
3
3
|
import { Context } from '@wrongstack/core';
|
|
4
4
|
|
|
5
5
|
interface IndexerOptions {
|
|
@@ -150,6 +150,34 @@ declare class IndexStore {
|
|
|
150
150
|
* Each ref's own {@link Ref.fromId} is used; pass an empty array to no-op.
|
|
151
151
|
*/
|
|
152
152
|
insertRefsBatch(refs: Ref[]): void;
|
|
153
|
+
/**
|
|
154
|
+
* Commit a batch of file-level symbol/refs/upserts in a single transaction.
|
|
155
|
+
*
|
|
156
|
+
* Used by the indexer to amortize SQLite commit overhead across many files.
|
|
157
|
+
* Before this, the indexer issued one transaction per file (BEGIN IMMEDIATE
|
|
158
|
+
* for symbols, plus per-file deletes and an upsertFile call), so a 20-file
|
|
159
|
+
* parallel batch cost ~5+ transactions × 20 files = 100+ commits. With
|
|
160
|
+
* this entry point we do exactly one BEGIN/COMMIT per parallel batch.
|
|
161
|
+
*
|
|
162
|
+
* Each entry must already be a fully-parsed FileSymbols (symbols + refs).
|
|
163
|
+
* The caller is responsible for the per-file prefix accounting
|
|
164
|
+
* (refsByLine → flat list with `fromId` populated). `deleteForFiles` lets
|
|
165
|
+
* the caller clear stale symbols/refs for any files being re-indexed before
|
|
166
|
+
* the inserts run (required to keep refs → symbols FK invariants).
|
|
167
|
+
*
|
|
168
|
+
* Returns the symbols back with their assigned `id` (same shape as
|
|
169
|
+
* {@link insertSymbols}) so callers can build final per-file results.
|
|
170
|
+
*/
|
|
171
|
+
commitBatch(entries: Array<{
|
|
172
|
+
file: string;
|
|
173
|
+
lang: SymbolLang;
|
|
174
|
+
symbols: Symbol[];
|
|
175
|
+
refs: Ref[];
|
|
176
|
+
mtimeMs: number;
|
|
177
|
+
symbolCount: number;
|
|
178
|
+
}>, options?: {
|
|
179
|
+
deleteForFiles?: string[] | undefined;
|
|
180
|
+
}): Symbol[];
|
|
153
181
|
/**
|
|
154
182
|
* Delete all refs whose source symbols are in a given file.
|
|
155
183
|
* Used when re-indexing a file to clear stale refs.
|
|
@@ -770,6 +770,104 @@ var IndexStore = class {
|
|
|
770
770
|
}
|
|
771
771
|
});
|
|
772
772
|
}
|
|
773
|
+
/**
|
|
774
|
+
* Commit a batch of file-level symbol/refs/upserts in a single transaction.
|
|
775
|
+
*
|
|
776
|
+
* Used by the indexer to amortize SQLite commit overhead across many files.
|
|
777
|
+
* Before this, the indexer issued one transaction per file (BEGIN IMMEDIATE
|
|
778
|
+
* for symbols, plus per-file deletes and an upsertFile call), so a 20-file
|
|
779
|
+
* parallel batch cost ~5+ transactions × 20 files = 100+ commits. With
|
|
780
|
+
* this entry point we do exactly one BEGIN/COMMIT per parallel batch.
|
|
781
|
+
*
|
|
782
|
+
* Each entry must already be a fully-parsed FileSymbols (symbols + refs).
|
|
783
|
+
* The caller is responsible for the per-file prefix accounting
|
|
784
|
+
* (refsByLine → flat list with `fromId` populated). `deleteForFiles` lets
|
|
785
|
+
* the caller clear stale symbols/refs for any files being re-indexed before
|
|
786
|
+
* the inserts run (required to keep refs → symbols FK invariants).
|
|
787
|
+
*
|
|
788
|
+
* Returns the symbols back with their assigned `id` (same shape as
|
|
789
|
+
* {@link insertSymbols}) so callers can build final per-file results.
|
|
790
|
+
*/
|
|
791
|
+
commitBatch(entries, options = {}) {
|
|
792
|
+
if (entries.length === 0 && (options.deleteForFiles?.length ?? 0) === 0) {
|
|
793
|
+
return [];
|
|
794
|
+
}
|
|
795
|
+
return this.runWithRetry(() => {
|
|
796
|
+
this.db.exec("BEGIN IMMEDIATE");
|
|
797
|
+
try {
|
|
798
|
+
if (options.deleteForFiles && options.deleteForFiles.length > 0) {
|
|
799
|
+
const placeholders = options.deleteForFiles.map(() => "?").join(",");
|
|
800
|
+
if (this.ftsAvailable) {
|
|
801
|
+
this.db.prepare(
|
|
802
|
+
`DELETE FROM symbols_fts WHERE rowid IN (SELECT id FROM symbols WHERE file IN (${placeholders}))`
|
|
803
|
+
).run(...options.deleteForFiles);
|
|
804
|
+
}
|
|
805
|
+
this.db.prepare(
|
|
806
|
+
`DELETE FROM refs WHERE from_id IN (SELECT id FROM symbols WHERE file IN (${placeholders}))`
|
|
807
|
+
).run(...options.deleteForFiles);
|
|
808
|
+
this.db.prepare(`DELETE FROM symbols WHERE file IN (${placeholders})`).run(...options.deleteForFiles);
|
|
809
|
+
}
|
|
810
|
+
const maxRows = this.db.prepare("SELECT MAX(id) AS m FROM symbols").all();
|
|
811
|
+
let nextId = (maxRows[0]?.m ?? 0) + 1;
|
|
812
|
+
const symStmt = this.db.prepare(
|
|
813
|
+
`INSERT INTO symbols(id, lang, kind, name, file, line, col, signature, doc_comment, scope, text, file_fk)
|
|
814
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
|
|
815
|
+
);
|
|
816
|
+
const ftsStmt = this.ftsAvailable ? this.db.prepare("INSERT INTO symbols_fts(rowid, text) VALUES (?, ?)") : null;
|
|
817
|
+
const allInserted = [];
|
|
818
|
+
const refsToInsert = [];
|
|
819
|
+
for (const entry of entries) {
|
|
820
|
+
for (const s of entry.symbols) {
|
|
821
|
+
const id = nextId++;
|
|
822
|
+
symStmt.run(
|
|
823
|
+
id,
|
|
824
|
+
s.lang,
|
|
825
|
+
s.kind,
|
|
826
|
+
s.name,
|
|
827
|
+
s.file,
|
|
828
|
+
s.line,
|
|
829
|
+
s.col,
|
|
830
|
+
s.signature,
|
|
831
|
+
s.docComment,
|
|
832
|
+
s.scope,
|
|
833
|
+
s.text,
|
|
834
|
+
s.file
|
|
835
|
+
);
|
|
836
|
+
ftsStmt?.run(id, buildIndexableText(s.name, s.signature, s.docComment));
|
|
837
|
+
allInserted.push({ ...s, id });
|
|
838
|
+
}
|
|
839
|
+
for (const r of entry.refs) refsToInsert.push(r);
|
|
840
|
+
}
|
|
841
|
+
if (refsToInsert.length > 0) {
|
|
842
|
+
const refStmt = this.db.prepare(
|
|
843
|
+
`INSERT INTO refs(from_id, to_name, to_id, call_type, line)
|
|
844
|
+
VALUES (?, ?, ?, ?, ?)`
|
|
845
|
+
);
|
|
846
|
+
for (const ref of refsToInsert) {
|
|
847
|
+
refStmt.run(ref.fromId, ref.toName, ref.toId ?? null, ref.callType, ref.line);
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
const upsertStmt = this.db.prepare(
|
|
851
|
+
`INSERT INTO files(file, lang, mtime_ms, symbol_count, last_indexed)
|
|
852
|
+
VALUES (?, ?, ?, ?, ?)
|
|
853
|
+
ON CONFLICT(file) DO UPDATE SET
|
|
854
|
+
lang = excluded.lang,
|
|
855
|
+
mtime_ms = excluded.mtime_ms,
|
|
856
|
+
symbol_count = excluded.symbol_count,
|
|
857
|
+
last_indexed = excluded.last_indexed`
|
|
858
|
+
);
|
|
859
|
+
const now = Date.now();
|
|
860
|
+
for (const entry of entries) {
|
|
861
|
+
upsertStmt.run(entry.file, entry.lang, entry.mtimeMs, entry.symbolCount, now);
|
|
862
|
+
}
|
|
863
|
+
this.db.exec("COMMIT");
|
|
864
|
+
return allInserted;
|
|
865
|
+
} catch (err) {
|
|
866
|
+
this.db.exec("ROLLBACK");
|
|
867
|
+
throw err;
|
|
868
|
+
}
|
|
869
|
+
});
|
|
870
|
+
}
|
|
773
871
|
/**
|
|
774
872
|
* Delete all refs whose source symbols are in a given file.
|
|
775
873
|
* Used when re-indexing a file to clear stale refs.
|
|
@@ -2301,6 +2399,8 @@ async function runIndexerWithStore(store, opts) {
|
|
|
2301
2399
|
return { file, stat: stat2, lang, parsed, content };
|
|
2302
2400
|
})
|
|
2303
2401
|
);
|
|
2402
|
+
const batchEntries = [];
|
|
2403
|
+
const deleteForFiles = [];
|
|
2304
2404
|
for (let fi = 0; fi < statReadParse.length; fi++) {
|
|
2305
2405
|
const settled = statReadParse[fi];
|
|
2306
2406
|
const file = expectDefined(batchFiles[fi]);
|
|
@@ -2325,43 +2425,116 @@ async function runIndexerWithStore(store, opts) {
|
|
|
2325
2425
|
}
|
|
2326
2426
|
if (!lang || !parsed) {
|
|
2327
2427
|
if (lang) {
|
|
2328
|
-
store.upsertFile({
|
|
2428
|
+
store.upsertFile({
|
|
2429
|
+
file,
|
|
2430
|
+
lang,
|
|
2431
|
+
mtimeMs: Math.floor(stat2.mtimeMs),
|
|
2432
|
+
symbolCount: 0,
|
|
2433
|
+
lastIndexed: Date.now()
|
|
2434
|
+
});
|
|
2329
2435
|
filesIndexed++;
|
|
2330
2436
|
}
|
|
2331
2437
|
continue;
|
|
2332
2438
|
}
|
|
2333
|
-
store.deleteRefsForFile(file);
|
|
2334
|
-
store.deleteSymbolsForFile(file);
|
|
2335
2439
|
if (parsed.symbols.length === 0) {
|
|
2336
|
-
store.upsertFile({
|
|
2440
|
+
store.upsertFile({
|
|
2441
|
+
file,
|
|
2442
|
+
lang,
|
|
2443
|
+
mtimeMs: Math.floor(stat2.mtimeMs),
|
|
2444
|
+
symbolCount: 0,
|
|
2445
|
+
lastIndexed: Date.now()
|
|
2446
|
+
});
|
|
2337
2447
|
filesIndexed++;
|
|
2338
2448
|
continue;
|
|
2339
2449
|
}
|
|
2340
|
-
const
|
|
2341
|
-
const count = symbolsWithIds.length;
|
|
2342
|
-
symbolsIndexed += count;
|
|
2343
|
-
langStats[lang] = (langStats[lang] ?? 0) + count;
|
|
2450
|
+
const refs = [];
|
|
2344
2451
|
if (parsed.refs && parsed.refs.length > 0) {
|
|
2345
|
-
const
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2452
|
+
for (const r of parsed.refs) refs.push({ ...r, fromId: 0 });
|
|
2453
|
+
}
|
|
2454
|
+
batchEntries.push({
|
|
2455
|
+
file,
|
|
2456
|
+
lang,
|
|
2457
|
+
symbols: parsed.symbols,
|
|
2458
|
+
refs,
|
|
2459
|
+
mtimeMs: Math.floor(stat2.mtimeMs),
|
|
2460
|
+
symbolCount: parsed.symbols.length
|
|
2461
|
+
});
|
|
2462
|
+
deleteForFiles.push(file);
|
|
2463
|
+
}
|
|
2464
|
+
if (batchEntries.length > 0) {
|
|
2465
|
+
try {
|
|
2466
|
+
const inserted = store.commitBatch(batchEntries, { deleteForFiles });
|
|
2467
|
+
let cursor = 0;
|
|
2468
|
+
for (const entry of batchEntries) {
|
|
2469
|
+
const count = entry.symbols.length;
|
|
2470
|
+
const symbolsWithIds = inserted.slice(cursor, cursor + count);
|
|
2471
|
+
cursor += count;
|
|
2472
|
+
symbolsIndexed += count;
|
|
2473
|
+
langStats[entry.lang] = (langStats[entry.lang] ?? 0) + count;
|
|
2474
|
+
filesIndexed++;
|
|
2475
|
+
if (entry.refs.length > 0 && symbolsWithIds.length > 0) {
|
|
2476
|
+
const refsByLine = /* @__PURE__ */ new Map();
|
|
2477
|
+
for (let i = 0; i < symbolsWithIds.length; i++) {
|
|
2478
|
+
const sym = symbolsWithIds[i];
|
|
2479
|
+
let arr = refsByLine.get(sym.line);
|
|
2480
|
+
if (!arr) {
|
|
2481
|
+
arr = [];
|
|
2482
|
+
refsByLine.set(sym.line, arr);
|
|
2483
|
+
}
|
|
2484
|
+
arr.push(i);
|
|
2485
|
+
}
|
|
2486
|
+
for (const ref of entry.refs) {
|
|
2487
|
+
const indices = refsByLine.get(ref.line);
|
|
2488
|
+
if (indices && indices.length > 0) {
|
|
2489
|
+
const idx = indices.shift();
|
|
2490
|
+
ref.fromId = symbolsWithIds[idx].id;
|
|
2491
|
+
}
|
|
2492
|
+
}
|
|
2351
2493
|
}
|
|
2352
|
-
arr.push(r);
|
|
2353
2494
|
}
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2495
|
+
} catch (err) {
|
|
2496
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
2497
|
+
errors.push(`commitBatch failed: ${message} \u2014 falling back to per-file writes`);
|
|
2498
|
+
for (const entry of batchEntries) {
|
|
2499
|
+
try {
|
|
2500
|
+
store.deleteRefsForFile(entry.file);
|
|
2501
|
+
store.deleteSymbolsForFile(entry.file);
|
|
2502
|
+
const symbolsWithIds = store.insertSymbols(entry.symbols);
|
|
2503
|
+
symbolsIndexed += symbolsWithIds.length;
|
|
2504
|
+
langStats[entry.lang] = (langStats[entry.lang] ?? 0) + symbolsWithIds.length;
|
|
2505
|
+
filesIndexed++;
|
|
2506
|
+
if (entry.refs.length > 0 && symbolsWithIds.length > 0) {
|
|
2507
|
+
const refsByLine = /* @__PURE__ */ new Map();
|
|
2508
|
+
for (const sym of symbolsWithIds) {
|
|
2509
|
+
let arr = refsByLine.get(sym.line);
|
|
2510
|
+
if (!arr) {
|
|
2511
|
+
arr = [];
|
|
2512
|
+
refsByLine.set(sym.line, arr);
|
|
2513
|
+
}
|
|
2514
|
+
arr.push(sym);
|
|
2515
|
+
}
|
|
2516
|
+
const fallbackBatch = [];
|
|
2517
|
+
for (const ref of entry.refs) {
|
|
2518
|
+
const syms = refsByLine.get(ref.line);
|
|
2519
|
+
if (syms && syms.length > 0) {
|
|
2520
|
+
const sym = syms.shift();
|
|
2521
|
+
fallbackBatch.push({ ...ref, fromId: sym.id });
|
|
2522
|
+
}
|
|
2523
|
+
}
|
|
2524
|
+
if (fallbackBatch.length > 0) store.insertRefsBatch(fallbackBatch);
|
|
2525
|
+
}
|
|
2526
|
+
store.upsertFile({
|
|
2527
|
+
file: entry.file,
|
|
2528
|
+
lang: entry.lang,
|
|
2529
|
+
mtimeMs: entry.mtimeMs,
|
|
2530
|
+
symbolCount: entry.symbolCount,
|
|
2531
|
+
lastIndexed: Date.now()
|
|
2532
|
+
});
|
|
2533
|
+
} catch (innerErr) {
|
|
2534
|
+
errors.push(`fallback write failed: ${entry.file}: ${innerErr instanceof Error ? innerErr.message : String(innerErr)}`);
|
|
2359
2535
|
}
|
|
2360
2536
|
}
|
|
2361
|
-
if (batch.length > 0) store.insertRefsBatch(batch);
|
|
2362
2537
|
}
|
|
2363
|
-
store.upsertFile({ file, lang, mtimeMs: Math.floor(stat2.mtimeMs), symbolCount: count, lastIndexed: Date.now() });
|
|
2364
|
-
filesIndexed++;
|
|
2365
2538
|
}
|
|
2366
2539
|
}
|
|
2367
2540
|
if (discoveredFiles) {
|
|
@@ -2803,7 +2976,7 @@ var codebaseSearchTool = {
|
|
|
2803
2976
|
name: "codebase-search",
|
|
2804
2977
|
category: "Project",
|
|
2805
2978
|
icon: "index",
|
|
2806
|
-
description: "
|
|
2979
|
+
description: "Search code symbols using a fast SQLite+BM25 index, with optional LSP fallback. Much more powerful and structured than raw `grep` for finding code by name or concept. Set `preferLsp: true` for live precision when the LSP plugin is active (supersedes codebase-lsp-search).",
|
|
2807
2980
|
usageHint: "PREFERRED FOR CODE UNDERSTANDING:\n\n- Use when you need to find where something is defined or used by name.\n- `kind` filter is very useful (e.g. only functions or only interfaces).\n- Combine with `file` filter to scope to a specific directory or module.\nThis is generally better than `grep` when you are looking for symbols rather than arbitrary text patterns.",
|
|
2808
2981
|
permission: "auto",
|
|
2809
2982
|
mutating: false,
|
|
@@ -2837,6 +3010,10 @@ var codebaseSearchTool = {
|
|
|
2837
3010
|
description: "Maximum results to return (default 20, max 100)",
|
|
2838
3011
|
minimum: 1,
|
|
2839
3012
|
maximum: 100
|
|
3013
|
+
},
|
|
3014
|
+
preferLsp: {
|
|
3015
|
+
type: "boolean",
|
|
3016
|
+
description: "Prefer live LSP results over the index. Index-only when the LSP plugin is not active. When the LSP plugin is active and this is true, results come from live workspaceSymbol queries."
|
|
2840
3017
|
}
|
|
2841
3018
|
},
|
|
2842
3019
|
required: ["query"]
|