@wrongstack/tools 0.306.4 → 0.307.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.
Files changed (71) hide show
  1. package/dist/audit.js +14 -8
  2. package/dist/auto-proceed-loop-guard.js +8 -2
  3. package/dist/bash.js +57 -22
  4. package/dist/builtin.d.ts +6 -6
  5. package/dist/builtin.js +11302 -9305
  6. package/dist/clarify.d.ts +32 -0
  7. package/dist/codebase-index/ast-invariant-engine.d.ts +102 -0
  8. package/dist/codebase-index/ast-symbol-mutator.d.ts +28 -0
  9. package/dist/codebase-index/background-indexer.d.ts +9 -0
  10. package/dist/codebase-index/codebase-ast-replace-tool.d.ts +31 -0
  11. package/dist/codebase-index/codebase-impact-analysis-tool.d.ts +40 -0
  12. package/dist/codebase-index/codebase-invariant-check-tool.d.ts +23 -0
  13. package/dist/codebase-index/codebase-repo-map-tool.d.ts +22 -0
  14. package/dist/codebase-index/codebase-skeleton-tool.d.ts +36 -0
  15. package/dist/codebase-index/codebase-targeted-test-tool.d.ts +30 -0
  16. package/dist/codebase-index/index.d.ts +11 -1
  17. package/dist/codebase-index/index.js +4141 -1479
  18. package/dist/codebase-index/project-server-client-state.d.ts +79 -0
  19. package/dist/codebase-index/project-server-client.d.ts +3 -71
  20. package/dist/codebase-index/project-server-protocol.d.ts +1 -0
  21. package/dist/codebase-index/project-server.js +751 -909
  22. package/dist/codebase-index/repo-map.d.ts +20 -0
  23. package/dist/codebase-index/skeleton-extractor.d.ts +64 -0
  24. package/dist/codebase-index/tree-sitter-parser.d.ts +11 -0
  25. package/dist/codebase-index/worker.js +723 -891
  26. package/dist/codebase-index/writer-mutations.d.ts +26 -0
  27. package/dist/codebase-index/writer-refs.d.ts +50 -0
  28. package/dist/codebase-index/writer-search.d.ts +30 -0
  29. package/dist/codebase-index/writer.d.ts +2 -320
  30. package/dist/edit.js +8558 -349
  31. package/dist/exec.js +73 -20
  32. package/dist/fetch.js +11 -9
  33. package/dist/format.js +14 -8
  34. package/dist/glob.js +5 -1
  35. package/dist/grep.js +19 -8
  36. package/dist/index.d.ts +3 -1
  37. package/dist/index.js +11386 -9416
  38. package/dist/install.js +14 -8
  39. package/dist/json.js +88 -15
  40. package/dist/kanban-board-actions.d.ts +4 -0
  41. package/dist/kanban-lifecycle-actions.d.ts +4 -0
  42. package/dist/kanban-serializer.d.ts +21 -0
  43. package/dist/kanban.js +985 -1034
  44. package/dist/languages/index.js +14 -8
  45. package/dist/lint.js +14 -8
  46. package/dist/logs.js +13 -3
  47. package/dist/next-steps.d.ts +8 -0
  48. package/dist/next-steps.js +18 -0
  49. package/dist/outdated.js +14 -8
  50. package/dist/pack.js +11295 -9305
  51. package/dist/patch.js +8301 -78
  52. package/dist/plan.js +1231 -1281
  53. package/dist/process-registry.js +14 -8
  54. package/dist/ps-slash.js +65 -30
  55. package/dist/read.js +751 -910
  56. package/dist/replace.js +8450 -224
  57. package/dist/search.js +21 -15
  58. package/dist/security-ast-scan-tool.d.ts +43 -0
  59. package/dist/session-kanban-graph.d.ts +9 -0
  60. package/dist/session-kanban-sync.d.ts +31 -0
  61. package/dist/session-kanban.d.ts +5 -141
  62. package/dist/session-kanban.js +367 -360
  63. package/dist/task.js +1157 -1207
  64. package/dist/test.js +14 -8
  65. package/dist/todo.js +2187 -2237
  66. package/dist/tool-diff.js +6 -1
  67. package/dist/tool-summary.js +4 -2
  68. package/dist/tool-tier.js +11302 -9305
  69. package/dist/typecheck.js +14 -8
  70. package/dist/write.js +8374 -153
  71. package/package.json +7 -7
@@ -0,0 +1,26 @@
1
+ import type { DatabaseSync } from 'node:sqlite';
2
+ import type { FileMeta, Symbol as IndexSymbol, Ref, SymbolLang } from './schema.js';
3
+ export declare function commitBatchWithStatement(stmtFn: (sql: string) => ReturnType<DatabaseSync['prepare']>, maxSqlVars: number, ftsAvailable: boolean, vectorsAvailable: boolean, allocateSymbolIds: (count: number) => number, invalidateIncomingRefsForFiles: (files: readonly string[]) => Set<string>, resolveRefsForNamesUnsafe: (names: Iterable<string>) => number, entries: Array<{
4
+ file: string;
5
+ lang: SymbolLang;
6
+ symbols: IndexSymbol[];
7
+ refs: Ref[];
8
+ mtimeMs: number;
9
+ symbolCount: number;
10
+ contentHash?: string | undefined;
11
+ }>, options?: {
12
+ deleteForFiles?: string[] | undefined;
13
+ }): IndexSymbol[];
14
+ export declare function replaceEmptyFileWithStatement(stmtFn: (sql: string) => ReturnType<DatabaseSync['prepare']>, ftsAvailable: boolean, vectorsAvailable: boolean, invalidateIncomingRefsForFiles: (files: readonly string[]) => Set<string>, resolveRefsForNamesUnsafe: (names: Iterable<string>) => number, meta: FileMeta): void;
15
+ export declare function insertSymbolsWithStatement(stmtFn: (sql: string) => ReturnType<DatabaseSync['prepare']>, maxSqlVars: number, ftsAvailable: boolean, vectorsAvailable: boolean, allocateSymbolIds: (count: number) => number, symbols: IndexSymbol[]): IndexSymbol[];
16
+ export declare function deleteSymbolsForFileWithStatement(stmtFn: (sql: string) => ReturnType<DatabaseSync['prepare']>, ftsAvailable: boolean, vectorsAvailable: boolean, invalidateIncomingRefsForFiles: (files: readonly string[]) => Set<string>, resolveRefsForNamesUnsafe: (names: Iterable<string>) => number, file: string): void;
17
+ export declare function deleteFileWithStatement(stmtFn: (sql: string) => ReturnType<DatabaseSync['prepare']>, ftsAvailable: boolean, vectorsAvailable: boolean, invalidateIncomingRefsForFiles: (files: readonly string[]) => Set<string>, resolveRefsForNamesUnsafe: (names: Iterable<string>) => number, file: string): void;
18
+ export declare function upsertFileWithStatement(stmtFn: (sql: string) => ReturnType<DatabaseSync['prepare']>, meta: FileMeta): void;
19
+ export declare function setFilePackagesWithStatement(stmtFn: (sql: string) => ReturnType<DatabaseSync['prepare']>, entries: ReadonlyMap<string, string>): void;
20
+ export declare function applyImportResolutionsWithStatement(db: DatabaseSync, stmtFn: (sql: string) => ReturnType<DatabaseSync['prepare']>, maxSqlVars: number, resolutions: ReadonlyArray<{
21
+ fromFile: string;
22
+ lang: string;
23
+ module: string;
24
+ toFile: string;
25
+ }>): number;
26
+ //# sourceMappingURL=writer-mutations.d.ts.map
@@ -0,0 +1,50 @@
1
+ export declare const FAMILY_MATCH_SQL = "(\n sym.lang = refs.lang\n OR EXISTS (\n SELECT 1 FROM lang_family lf1\n JOIN lang_family lf2 ON lf1.family = lf2.family\n WHERE lf1.lang = sym.lang AND lf2.lang = refs.lang\n )\n OR ? IN (\n SELECT family FROM lang_family WHERE lang = refs.lang\n )\n)";
2
+ export declare function getNamespaceDeclarationsWithStatement(stmtFn: (sql: string) => {
3
+ all: () => unknown[];
4
+ }): Array<{
5
+ name: string;
6
+ file: string;
7
+ }>;
8
+ export declare function getFilePackagesWithStatement(stmtFn: (sql: string) => {
9
+ all: () => unknown[];
10
+ }): Map<string, string>;
11
+ export declare function getUnresolvedImportsWithStatement(stmtFn: (sql: string) => {
12
+ all: (...args: (string | number)[]) => unknown[];
13
+ }, maxSqlVars: number, onlyFiles?: readonly string[]): Array<{
14
+ fromFile: string;
15
+ lang: string;
16
+ module: string;
17
+ }>;
18
+ export declare function getAllResolvedRefsWithStatement(stmtFn: (sql: string) => {
19
+ all: () => unknown[];
20
+ }): Array<{
21
+ fromId: number;
22
+ toId: number;
23
+ callType: string;
24
+ }>;
25
+ export declare function getAllImportRefsWithStatement(stmtFn: (sql: string) => {
26
+ all: () => unknown[];
27
+ }): Array<{
28
+ sourceFile: string | null;
29
+ toName: string;
30
+ toId: number | null;
31
+ callType: string;
32
+ line: number;
33
+ }>;
34
+ export declare function resolveRefsWithStatement(stmtFn: (sql: string) => {
35
+ run: (...args: (string | number)[]) => unknown;
36
+ }): number;
37
+ export declare function applyImportResolutionsWithStatement(db: {
38
+ exec: (sql: string) => unknown;
39
+ }, stmtFn: (sql: string) => {
40
+ run: (...args: string[]) => unknown;
41
+ }, runWithRetry: <T>(fn: () => T) => T, maxSqlVars: number, resolutions: ReadonlyArray<{
42
+ fromFile: string;
43
+ lang: string;
44
+ module: string;
45
+ toFile: string;
46
+ }>): number;
47
+ export declare function resolveRefsForNamesUnsafe(stmtFn: (sql: string) => {
48
+ run: (...args: (string | number)[]) => unknown;
49
+ }, maxSqlVars: number, names: Iterable<string>): number;
50
+ //# sourceMappingURL=writer-refs.d.ts.map
@@ -0,0 +1,30 @@
1
+ import { type Bm25Index } from './bm25.js';
2
+ import type { SearchResult } from './schema.js';
3
+ import { type WriterSearchFilter } from './writer-search-helpers.js';
4
+ export declare function searchWithStatement(stmtFn: (sql: string) => {
5
+ all: (...args: (string | number)[]) => unknown[];
6
+ }, query: string, filter?: WriterSearchFilter, opts?: {
7
+ limit?: number | undefined;
8
+ }): SearchResult[];
9
+ export declare function countSearchWithStatement(stmtFn: (sql: string) => {
10
+ get: (...args: (string | number)[]) => unknown;
11
+ }, query: string, filter?: WriterSearchFilter | undefined): number;
12
+ export declare function searchRankedWithStatement(stmtFn: (sql: string) => {
13
+ all: (...args: (string | number)[]) => unknown[];
14
+ get: (...args: (string | number)[]) => unknown;
15
+ }, searchFn: (query: string, filter?: WriterSearchFilter, opts?: {
16
+ limit?: number | undefined;
17
+ }) => SearchResult[], ftsAvailable: boolean, vectorsAvailable: boolean, getOrBuildBm25: () => Bm25Index, query: string, filter: WriterSearchFilter | undefined, limit: number): {
18
+ results: SearchResult[];
19
+ total: number;
20
+ };
21
+ export declare function searchRankedFallbackWithStatement(stmtFn: (sql: string) => {
22
+ all: (...args: (string | number)[]) => unknown[];
23
+ get: (...args: (string | number)[]) => unknown;
24
+ }, searchFn: (query: string, filter?: WriterSearchFilter, opts?: {
25
+ limit?: number | undefined;
26
+ }) => SearchResult[], getOrBuildBm25: () => Bm25Index, query: string, filter: WriterSearchFilter | undefined, limit: number): {
27
+ results: SearchResult[];
28
+ total: number;
29
+ };
30
+ //# sourceMappingURL=writer-search.d.ts.map
@@ -1,194 +1,53 @@
1
1
  import type { CallSite, CodeMapGraph, FileMeta, IndexStats, Symbol as IndexSymbol, Ref, SearchResult, SymbolKind, SymbolLang } from './schema.js';
2
- import { type WriterSearchFilter } from './writer-search-helpers.js';
2
+ import type { WriterSearchFilter } from './writer-search-helpers.js';
3
3
  import { StorePool } from './writer-store-pool.js';
4
4
  export { codebaseIndexDirOverride, resolveIndexDir } from './writer-helpers.js';
5
5
  export { StorePool } from './writer-store-pool.js';
6
6
  export declare class IndexStore {
7
7
  private db;
8
- /**
9
- * True while an index run owns one outer SQLite transaction. Individual
10
- * writer methods normally protect themselves with BEGIN/COMMIT, but during
11
- * a refresh they join this transaction so readers observe either the last
12
- * completed index or the next completed index, never an in-between batch.
13
- */
14
8
  private atomicIndexUpdateActive;
15
9
  private writeSavepointSequence;
16
- /** Absolute path to this project's index directory. */
17
10
  private readonly indexDir;
18
- /**
19
- * True when the SQLite build provides FTS5 (Node's bundled SQLite does).
20
- * When false, ranked search falls back to the LIKE + in-process BM25 path.
21
- */
22
11
  private ftsAvailable;
23
- /**
24
- * Phase 3: true when the `symbol_vectors` table was created successfully.
25
- * When false, hybrid search skips the vector pass and falls back to FTS5
26
- * (or LIKE) only.
27
- */
28
12
  private vectorsAvailable;
29
- /**
30
- * Cache of prepared statements keyed by their SQL text. `DatabaseSync`
31
- * compiles SQL on every `.prepare()` call; for the fixed-SQL methods
32
- * (upsertFile, getFileMeta, deleteFile, insertRefs, …) that runs thousands
33
- * of times during a full reindex. `StatementSync` objects are reusable
34
- * across calls on the same connection, so we compile each distinct SQL once
35
- * and reuse it. Cleared in {@link close} when the connection is torn down.
36
- */
37
13
  private readonly stmtCache;
38
- /**
39
- * Cached full-corpus BM25 index for the FTS5-unavailable fallback path.
40
- * Built lazily on the first `searchRankedFallback` call and invalidated
41
- * (via `bm25Dirty`) whenever the `symbols` table is mutated. Computing
42
- * IDF over the full corpus is also more correct than the old per-query
43
- * candidate-subset IDF.
44
- *
45
- * Cache-lifecycle invariants (single source of truth lives at the
46
- * `invalidateBm25()` helper — see its docblock for the "every mutation
47
- * MUST call this" contract):
48
- * - declaration: this field + `bm25Dirty` (here)
49
- * - invalidation: `invalidateBm25()` flips the flag and nulls the cache
50
- * - build: `getOrBuildBm25()` rebuilds against current `symbols` rows
51
- * - teardown: `close()` resets the flag and nulls the cache
52
- */
53
14
  private bm25Cache;
54
15
  private bm25Dirty;
55
- /**
56
- * Prepare-once helper: compile `sql` on first use, reuse thereafter.
57
- *
58
- * Bounded LRU rather than an open Map. The cache is keyed by SQL TEXT, and
59
- * the fallback search builder emits one `text LIKE ?` clause per query token
60
- * — so the SQL varies with the token count and a stream of differently-sized
61
- * queries grew the cache without limit. Sage's store already bounds its
62
- * equivalent at 128 (WS-096).
63
- *
64
- * Re-inserting on a hit keeps the hot fixed-SQL statements (upsertFile,
65
- * insertRefs, …) at the young end, so a burst of one-off search SQL evicts
66
- * itself rather than the reindex hot path.
67
- */
68
16
  private stmt;
69
17
  constructor(projectRoot: string, opts?: {
70
18
  indexDir?: string | undefined;
71
19
  });
72
20
  runWithRetry<T>(fn: () => T): T;
73
- /** Run a complete index mutation as one WAL-visible publication. */
74
21
  runAtomicIndexUpdate<T>(job: () => Promise<T>): Promise<T>;
75
- /**
76
- * Begin a method-local transaction. Inside an atomic index publication a
77
- * SAVEPOINT preserves the old per-batch rollback boundary, which is needed
78
- * when commitBatch falls back to per-file writes after one batch fails.
79
- */
80
22
  private beginWriteTransaction;
81
23
  private commitWriteTransaction;
82
24
  private rollbackWriteTransaction;
83
- /**
84
- * Mirror the in-process language→family map into SQLite.
85
- *
86
- * Rewritten on every open rather than only on schema bumps: the mapping is
87
- * static lookup data, so a code-side change (a new language, a language
88
- * moving families) must take effect without forcing a full reindex.
89
- */
90
25
  private seedLangFamilies;
91
- /**
92
- * Add any column the current schema expects but the on-disk table lacks.
93
- *
94
- * `CREATE TABLE IF NOT EXISTS` silently keeps an existing table's old shape,
95
- * and the version check above only rebuilds on a version *mismatch*. That
96
- * leaves a real gap: several wstack processes share this database, and while
97
- * a version upgrade is rolling out one of them may still be running the
98
- * previous build. That older process sees the newer version number, drops the
99
- * tables, and recreates them from *its* DDL — without the newer columns —
100
- * while the metadata row still reads the new version. Every later query for
101
- * one of those columns then fails with `no such column`, and no amount of
102
- * reindexing fixes it, because the version numbers already agree.
103
- *
104
- * Repairing column-by-column makes the schema self-healing from any of those
105
- * states. Table and column names are compile-time literals from this module,
106
- * never user input.
107
- */
108
26
  private repairMissingColumns;
109
27
  private initSchema;
110
28
  private static readonly NEXT_SYMBOL_ID_KEY;
111
- /** Stay under typical SQLite SQLITE_MAX_VARIABLE_NUMBER (often 999). */
112
29
  private static readonly MAX_SQL_VARS;
113
- /**
114
- * Correlated predicate: the ref in `refs` and the candidate symbol aliased
115
- * `sym` belong to the same language family — or the ref carries no language,
116
- * in which case the wildcard bind matches everything.
117
- *
118
- * Each textual occurrence consumes one `?` bind of {@link LANG_FAMILY_WILDCARD}.
119
- */
120
- private static readonly FAMILY_MATCH_SQL;
121
- /**
122
- * Ensure `metadata.next_symbol_id` exists. Safe to call outside a write
123
- * transaction on open; the first concurrent writer under BEGIN IMMEDIATE
124
- * re-reads and advances the counter atomically.
125
- */
126
30
  private ensureNextSymbolIdSeeded;
127
- /**
128
- * Reserve `count` consecutive symbol ids. MUST run inside BEGIN IMMEDIATE
129
- * so concurrent indexers cannot hand out overlapping ranges.
130
- */
131
31
  private allocateSymbolIds;
132
- /**
133
- * Disconnect inbound refs before their target symbols are replaced and
134
- * return the affected names for scoped re-resolution.
135
- *
136
- * This also repairs a long-standing dangling-id edge case: `refs.to_id` has
137
- * no physical FK, so deleting a symbol previously left callers pointing at a
138
- * non-existent row.
139
- */
140
32
  private invalidateIncomingRefsForFiles;
141
- /** Resolve only refs whose target names may have changed. */
142
33
  private resolveRefsForNamesUnsafe;
143
- /**
144
- * Insert symbols, assigning IDs atomically inside `BEGIN IMMEDIATE` /
145
- * `COMMIT`. Id ranges come from the `next_symbol_id` metadata counter
146
- * (O(1)); multi-row INSERT amortizes bind overhead for large files.
147
- *
148
- * @returns The symbols array with `id` fields populated so the caller can
149
- * use them for refs without re-reading from the DB.
150
- */
151
34
  insertSymbols(symbols: IndexSymbol[]): IndexSymbol[];
152
35
  deleteSymbolsForFile(file: string): void;
153
- /**
154
- * Remove every trace of a file (refs, symbols, FTS rows, file meta). Used
155
- * when a source file disappears between index runs — previously this only
156
- * dropped the `files` row, leaving its symbols orphaned but still searchable.
157
- */
158
36
  deleteFile(file: string): void;
159
37
  upsertFile(meta: FileMeta): void;
160
38
  getFileMeta(file: string): FileMeta | null;
161
39
  getAllFileMetas(): FileMeta[];
162
- /** Store the Code Atlas grouping label for each indexed file. */
163
40
  setFilePackages(entries: ReadonlyMap<string, string>): void;
164
- /**
165
- * Every indexed `namespace`/`module` declaration, for ecosystems whose import
166
- * specifiers name a namespace rather than a path (C#, PHP, Elixir, Haskell).
167
- * Ordered so the resolver's choice among duplicate declarations is stable.
168
- */
169
41
  getNamespaceDeclarations(): Array<{
170
42
  name: string;
171
43
  file: string;
172
44
  }>;
173
- /** `file → package` for every indexed file that has a label. */
174
45
  getFilePackages(): Map<string, string>;
175
- /**
176
- * Distinct `(fromFile, lang, module)` triples needing module resolution.
177
- *
178
- * Distinct rather than per-ref because resolution depends only on these three
179
- * values: a file importing the same module twenty times resolves it once.
180
- */
181
46
  getUnresolvedImports(onlyFiles?: readonly string[]): Array<{
182
47
  fromFile: string;
183
48
  lang: string;
184
49
  module: string;
185
50
  }>;
186
- /**
187
- * Write resolved import targets back onto `refs.to_file`.
188
- *
189
- * Applied through a temp table and a single UPDATE: one statement per
190
- * resolution would mean thousands of round-trips on a first index.
191
- */
192
51
  applyImportResolutions(resolutions: ReadonlyArray<{
193
52
  fromFile: string;
194
53
  lang: string;
@@ -198,111 +57,25 @@ export declare class IndexStore {
198
57
  search(query: string, filter?: WriterSearchFilter, opts?: {
199
58
  limit?: number | undefined;
200
59
  }): SearchResult[];
201
- /** Shared WHERE builder for {@link search} / empty-query ranked totals. */
202
- private buildSearchWhere;
203
- private countSearch;
204
- /**
205
- * Ranked search — the one-stop query the codebase-search tool and plug-lsp
206
- * use. With FTS5 this is a single indexed `MATCH` ranked by SQLite's native
207
- * `bm25()` with a built-in `snippet()`; without FTS5 it falls back to the
208
- * legacy LIKE scan + in-process BM25 (identical semantics, slower).
209
- *
210
- * Tokens are matched as prefixes (`"tok"*`), mirroring the old
211
- * `LIKE '%tok%'` recall for the common symbol-search shapes ("user" finds
212
- * "users", camelCase-split text makes "complex" find "complexOperation").
213
- */
60
+ countSearch(query: string, filter?: WriterSearchFilter | undefined): number;
214
61
  searchRanked(query: string, filter: WriterSearchFilter | undefined, limit: number): {
215
62
  results: SearchResult[];
216
63
  total: number;
217
64
  };
218
- /**
219
- * Invalidate the cached BM25 index.
220
- *
221
- * **Contract: every method that mutates `symbols` MUST call this before
222
- * returning.** (`refs` mutations do not affect the BM25 fallback because
223
- * the corpus is built from `symbols.text` via `getAllIndexable()` and the
224
- * BM25 score is filtered by the LIKE-selected candidate set in
225
- * `searchRankedFallback`.) Today the call sites are `repairDrift`,
226
- * `insertSymbols`, `deleteSymbolsForFile`, `deleteFile`, `clearAll`, and
227
- * `commitBatch`. A future mutation that adds a new write path (e.g.
228
- * `renameFile`, `updateSignature`) MUST also call this — otherwise the
229
- * FTS5-unavailable fallback will serve stale search results. The
230
- * `close()` reset at L1820-1821 tears the cache down on store shutdown,
231
- * which is the only legitimate place that flips the flag outside this
232
- * helper.
233
- *
234
- * Called *before* `runWithRetry` on purpose: if the write fails all
235
- * retries the flag stays set, forcing a rebuild on the next search rather
236
- * than trusting a cache that may not reflect the intended mutation.
237
- * Do not move this inside the retry closure.
238
- */
239
65
  private invalidateBm25;
240
- /**
241
- * Return the cached full-corpus BM25 index, rebuilding it only when the
242
- * symbols table has been mutated since the last build. The full-corpus IDF
243
- * is more correct than the old per-query candidate-subset IDF, and the
244
- * amortized build cost drops from O(symbols × tokens) per search to once
245
- * per write batch.
246
- *
247
- * Note: the first call after a long idle (or on a freshly opened store)
248
- * pays the full corpus rebuild synchronously on the search path. For a
249
- * 5 500+ symbol corpus this is a visible one-time latency spike.
250
- */
251
66
  private getOrBuildBm25;
252
- /** Legacy ranked path: LIKE candidates + in-process BM25 + JS snippets. */
253
- private searchRankedFallback;
254
67
  getAllIndexable(): Array<{
255
68
  id: number;
256
69
  text: string;
257
70
  }>;
258
- /**
259
- * Largest symbol id currently in the table (0 when empty). New ids must be
260
- * allocated from this, NOT from `COUNT(*)`: incremental reindexes delete a
261
- * changed file's rows, so the row count drops below the max id and a
262
- * count-based id would collide with a surviving row (UNIQUE constraint on
263
- * `symbols.id`). Ids may have gaps — that is fine.
264
- */
265
71
  getMaxSymbolId(): number;
266
72
  getStats(): IndexStats;
267
73
  setLastIndexed(ts: number): void;
268
74
  getMetadata(key: string): string | undefined;
269
75
  setMetadata(key: string, value: string): void;
270
76
  clearAll(): void;
271
- /**
272
- * Insert cross-references for a given source symbol id.
273
- * Replaces any existing refs from the same source (idempotent on re-index).
274
- */
275
77
  insertRefs(fromId: number, refs: Ref[]): void;
276
- /**
277
- * Bulk-insert refs for many source symbols in a single transaction.
278
- *
279
- * Unlike {@link insertRefs} this does NOT delete per source id — the caller
280
- * (the indexer) has already cleared stale refs for the file via
281
- * {@link deleteRefsForFile}, so the per-source DELETE would be redundant work
282
- * repeated once per symbol. One transaction for the whole file instead of one
283
- * per symbol turns an O(symbols) transaction count into O(1).
284
- *
285
- * Each ref's own {@link Ref.fromId} is used; pass an empty array to no-op.
286
- */
287
78
  insertRefsBatch(refs: Ref[]): void;
288
- /**
289
- * Commit a batch of file-level symbol/refs/upserts in a single transaction.
290
- *
291
- * Used by the indexer to amortize SQLite commit overhead across many files.
292
- * Before this, the indexer issued one transaction per file (BEGIN IMMEDIATE
293
- * for symbols, plus per-file deletes and an upsertFile call), so a 20-file
294
- * parallel batch cost ~5+ transactions × 20 files = 100+ commits. With
295
- * this entry point we do exactly one BEGIN/COMMIT per parallel batch.
296
- *
297
- * Each entry must already be a fully-parsed FileSymbols (symbols + refs).
298
- * The caller is responsible for the per-file prefix accounting
299
- * (refsByLine → flat list with `fromId` populated). `deleteForFiles` lets
300
- * the caller clear stale symbols/refs for any files being re-indexed before
301
- * the inserts run (required to keep refs → symbols FK invariants).
302
- *
303
- * Returns the symbols back with their assigned `id` (same shape as
304
- * {@link insertSymbols}) so callers can build final per-file results.
305
- */
306
79
  commitBatch(entries: Array<{
307
80
  file: string;
308
81
  lang: SymbolLang;
@@ -314,119 +87,45 @@ export declare class IndexStore {
314
87
  }>, options?: {
315
88
  deleteForFiles?: string[] | undefined;
316
89
  }): IndexSymbol[];
317
- /**
318
- * Delete all refs whose source symbols are in a given file.
319
- * Used when re-indexing a file to clear stale refs.
320
- */
321
90
  deleteRefsForFile(file: string): void;
322
- /**
323
- * Resolve `to_name` → `to_id` for all refs that have a name but no id.
324
- * Call this after all symbols have been inserted to fill in cross-references.
325
- *
326
- * A match additionally requires the referencing ref and the target symbol to
327
- * be in the same {@link LangFamily}. Without that guard a name match is a
328
- * cross-language accident waiting to happen — `main`, `New`, `Parse` and
329
- * `Config` are declared in most languages at once, and each collision draws a
330
- * Code Atlas edge between files that never reference each other. Refs stored
331
- * without a language keep the old global behaviour via the `'*'` wildcard row.
332
- */
333
91
  resolveRefs(): number;
334
92
  resolveRefsForNames(names: Iterable<string>): number;
335
- /**
336
- * Clear symbols/refs for a file and mark it as indexed with zero symbols.
337
- * Used by the indexer for empty-parse results so three writes share one txn.
338
- */
339
93
  replaceEmptyFile(meta: FileMeta): void;
340
- /** Best-effort query planner refresh after a large reindex. */
341
94
  optimize(): void;
342
- /**
343
- * Reclaim page churn left by repeated force rebuilds.
344
- *
345
- * SQLite's DROP/CREATE path makes rebuilds fast but leaves pages on the
346
- * freelist. Compact only large, materially sparse databases and only when the
347
- * caller is already on a full-index maintenance path.
348
- */
349
95
  compactIfNeeded(options?: {
350
96
  minBytes?: number;
351
97
  minFreeRatio?: number;
352
98
  }): boolean;
353
- /**
354
- * Find all symbols that reference the named target symbol (incoming callers).
355
- * Accepts a name instead of an id so the agent doesn't need a prior lookup.
356
- */
357
99
  findIncomingCallsByName(symbolName: string, file?: string, limit?: number): {
358
100
  calls: CallSite[];
359
101
  symbolFound: boolean;
360
102
  ambiguous: boolean;
361
103
  totalMatches: number;
362
104
  };
363
- /**
364
- * Find all symbols that the named source symbol references (outgoing callees).
365
- * Accepts a name instead of an id so the agent doesn't need a prior lookup.
366
- */
367
105
  findOutgoingCallsByName(symbolName: string, file?: string, limit?: number): {
368
106
  calls: CallSite[];
369
107
  symbolFound: boolean;
370
108
  unresolvedCount: number;
371
109
  totalMatches: number;
372
110
  };
373
- /**
374
- * Transitive incoming-call tree: all symbols that transitively call the
375
- * target, to an unbounded depth (cycle-safe via SQL UNION deduplication).
376
- * Used by `codebase-incoming-calls` when the caller wants the full call
377
- * chain rather than just direct callers.
378
- */
379
111
  findTransitiveIncomingCallsByName(symbolName: string, file?: string, limit?: number): {
380
112
  calls: CallSite[];
381
113
  symbolFound: boolean;
382
114
  ambiguous: boolean;
383
115
  totalMatches: number;
384
116
  };
385
- /**
386
- * Transitive outgoing-call tree: all symbols the target transitively calls.
387
- * Used by `codebase-outgoing-calls` when the caller wants the full
388
- * dependency chain rather than just direct callees.
389
- */
390
117
  findTransitiveOutgoingCallsByName(symbolName: string, file?: string, limit?: number): {
391
118
  calls: CallSite[];
392
119
  symbolFound: boolean;
393
120
  unresolvedCount: number;
394
121
  totalMatches: number;
395
122
  };
396
- /**
397
- * Compute the set of symbol IDs reachable from the given seed IDs using a
398
- * native SQLite recursive CTE. Used by dead-code detection to replace the
399
- * in-memory BFS.
400
- */
401
123
  findReachableSymbolIds(seedIds: number[]): Set<number>;
402
- /**
403
- * Find all references TO a given symbol (who calls / uses this symbol?).
404
- */
405
124
  findRefsTo(symbolId: number): Ref[];
406
- /**
407
- * Find all references FROM a given symbol (what does this symbol call/use?).
408
- */
409
125
  findRefsFrom(symbolId: number): Ref[];
410
- /**
411
- * Package-level graph: each workspace package is a node; edges are derived
412
- * from cross-package symbol references (a symbol in package A references a
413
- * symbol resolved in package B). Node metadata includes symbol/file counts.
414
- */
415
126
  getPackageGraph(): CodeMapGraph;
416
- /**
417
- * File-level graph for a single package: each file is a node; edges are
418
- * derived from cross-file symbol references within the package.
419
- */
420
127
  getFileGraph(packageFilter: string): CodeMapGraph;
421
- /**
422
- * Symbol-level graph for a single file: each symbol is a node; edges are
423
- * derived from intra-file and cross-file symbol references (who calls whom).
424
- */
425
128
  getSymbolGraph(fileFilter: string): CodeMapGraph;
426
- /**
427
- * Returns every symbol in the index. Used by dead-code analysis to
428
- * build the full symbol universe for the reachability scan.
429
- */
430
129
  getAllSymbols(): Array<{
431
130
  id: number;
432
131
  name: string;
@@ -434,36 +133,19 @@ export declare class IndexStore {
434
133
  kind: SymbolKind;
435
134
  line: number;
436
135
  }>;
437
- /**
438
- * Returns every resolved reference (to_id IS NOT NULL). Used by
439
- * dead-code analysis to build the consumer-ship graph. Refs whose
440
- * target symbol id is null (unresolved imports) are excluded.
441
- */
442
136
  getAllResolvedRefs(): Array<{
443
137
  fromId: number;
444
138
  toId: number;
445
139
  callType: string;
446
140
  }>;
447
- /**
448
- * Returns ALL import refs (including unresolved) with their source-file
449
- * path and resolved target id. Used by the dead-code scan's file-level
450
- * graph traversal to handle barrel-only entry points where no symbol
451
- * carries the ref.
452
- *
453
- * Refs whose `from_id` doesn't match a known symbol (e.g. pure-barrel
454
- * files with no declarations) will have `sourceFile === null`.
455
- */
456
141
  getAllImportRefs(): Array<{
457
- /** Source-file path (null when the owning symbol can't be resolved). */
458
142
  sourceFile: string | null;
459
143
  toName: string;
460
- /** Resolved target symbol id (null when the name couldn't be matched). */
461
144
  toId: number | null;
462
145
  callType: string;
463
146
  line: number;
464
147
  }>;
465
148
  close(): void;
466
149
  }
467
- /** Process-wide singleton pool. */
468
150
  export declare const indexStorePool: StorePool<IndexStore>;
469
151
  //# sourceMappingURL=writer.d.ts.map