@optave/codegraph 3.9.6 → 3.11.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/README.md +26 -12
- package/dist/ast-analysis/engine.d.ts.map +1 -1
- package/dist/ast-analysis/engine.js +1 -1
- package/dist/ast-analysis/engine.js.map +1 -1
- package/dist/ast-analysis/rules/index.d.ts.map +1 -1
- package/dist/ast-analysis/rules/index.js +77 -0
- package/dist/ast-analysis/rules/index.js.map +1 -1
- package/dist/ast-analysis/visitors/ast-store-visitor.d.ts.map +1 -1
- package/dist/ast-analysis/visitors/ast-store-visitor.js +50 -8
- package/dist/ast-analysis/visitors/ast-store-visitor.js.map +1 -1
- package/dist/cli/commands/audit.js +1 -1
- package/dist/cli/commands/audit.js.map +1 -1
- package/dist/cli/commands/build.d.ts.map +1 -1
- package/dist/cli/commands/build.js +2 -0
- package/dist/cli/commands/build.js.map +1 -1
- package/dist/cli/commands/check.js +1 -1
- package/dist/cli/commands/check.js.map +1 -1
- package/dist/cli/commands/children.js +1 -1
- package/dist/cli/commands/children.js.map +1 -1
- package/dist/cli/commands/diff-impact.js +1 -1
- package/dist/cli/commands/diff-impact.js.map +1 -1
- package/dist/cli/commands/roles.js +1 -1
- package/dist/cli/commands/roles.js.map +1 -1
- package/dist/cli/commands/structure.js +1 -1
- package/dist/cli/commands/structure.js.map +1 -1
- package/dist/cli/shared/options.js +1 -1
- package/dist/cli/shared/options.js.map +1 -1
- package/dist/db/connection.d.ts.map +1 -1
- package/dist/db/connection.js +8 -0
- package/dist/db/connection.js.map +1 -1
- package/dist/domain/graph/builder/context.d.ts +10 -0
- package/dist/domain/graph/builder/context.d.ts.map +1 -1
- package/dist/domain/graph/builder/context.js +10 -0
- package/dist/domain/graph/builder/context.js.map +1 -1
- package/dist/domain/graph/builder/helpers.d.ts +7 -2
- package/dist/domain/graph/builder/helpers.d.ts.map +1 -1
- package/dist/domain/graph/builder/helpers.js +7 -2
- package/dist/domain/graph/builder/helpers.js.map +1 -1
- package/dist/domain/graph/builder/incremental.d.ts +0 -6
- package/dist/domain/graph/builder/incremental.d.ts.map +1 -1
- package/dist/domain/graph/builder/incremental.js +6 -23
- package/dist/domain/graph/builder/incremental.js.map +1 -1
- package/dist/domain/graph/builder/pipeline.d.ts +44 -0
- package/dist/domain/graph/builder/pipeline.d.ts.map +1 -1
- package/dist/domain/graph/builder/pipeline.js +348 -42
- package/dist/domain/graph/builder/pipeline.js.map +1 -1
- package/dist/domain/graph/builder/stages/build-edges.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/build-edges.js +8 -2
- package/dist/domain/graph/builder/stages/build-edges.js.map +1 -1
- package/dist/domain/graph/builder/stages/collect-files.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/collect-files.js +8 -0
- package/dist/domain/graph/builder/stages/collect-files.js.map +1 -1
- package/dist/domain/graph/builder/stages/detect-changes.d.ts +24 -0
- package/dist/domain/graph/builder/stages/detect-changes.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/detect-changes.js +117 -3
- package/dist/domain/graph/builder/stages/detect-changes.js.map +1 -1
- package/dist/domain/graph/builder/stages/finalize.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/finalize.js +9 -6
- package/dist/domain/graph/builder/stages/finalize.js.map +1 -1
- package/dist/domain/graph/builder/stages/insert-nodes.d.ts +30 -0
- package/dist/domain/graph/builder/stages/insert-nodes.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/insert-nodes.js +36 -13
- package/dist/domain/graph/builder/stages/insert-nodes.js.map +1 -1
- package/dist/domain/graph/builder/stages/resolve-imports.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/resolve-imports.js +73 -22
- package/dist/domain/graph/builder/stages/resolve-imports.js.map +1 -1
- package/dist/domain/graph/watcher.d.ts.map +1 -1
- package/dist/domain/graph/watcher.js +23 -18
- package/dist/domain/graph/watcher.js.map +1 -1
- package/dist/domain/parser.d.ts +14 -1
- package/dist/domain/parser.d.ts.map +1 -1
- package/dist/domain/parser.js +104 -11
- package/dist/domain/parser.js.map +1 -1
- package/dist/domain/search/models.d.ts +16 -0
- package/dist/domain/search/models.d.ts.map +1 -1
- package/dist/domain/search/models.js +36 -2
- package/dist/domain/search/models.js.map +1 -1
- package/dist/domain/wasm-worker-entry.js +20 -13
- package/dist/domain/wasm-worker-entry.js.map +1 -1
- package/dist/extractors/c.js +25 -6
- package/dist/extractors/c.js.map +1 -1
- package/dist/extractors/cpp.js +47 -6
- package/dist/extractors/cpp.js.map +1 -1
- package/dist/extractors/cuda.js +90 -14
- package/dist/extractors/cuda.js.map +1 -1
- package/dist/extractors/elixir.js +83 -3
- package/dist/extractors/elixir.js.map +1 -1
- package/dist/extractors/erlang.js +56 -20
- package/dist/extractors/erlang.js.map +1 -1
- package/dist/extractors/fsharp.d.ts +7 -0
- package/dist/extractors/fsharp.d.ts.map +1 -1
- package/dist/extractors/fsharp.js +94 -0
- package/dist/extractors/fsharp.js.map +1 -1
- package/dist/extractors/gleam.js +6 -2
- package/dist/extractors/gleam.js.map +1 -1
- package/dist/extractors/groovy.js +41 -1
- package/dist/extractors/groovy.js.map +1 -1
- package/dist/extractors/haskell.js +48 -4
- package/dist/extractors/haskell.js.map +1 -1
- package/dist/extractors/julia.js +172 -41
- package/dist/extractors/julia.js.map +1 -1
- package/dist/extractors/kotlin.js +4 -0
- package/dist/extractors/kotlin.js.map +1 -1
- package/dist/extractors/objc.js +184 -47
- package/dist/extractors/objc.js.map +1 -1
- package/dist/extractors/python.js +7 -4
- package/dist/extractors/python.js.map +1 -1
- package/dist/extractors/r.js +93 -52
- package/dist/extractors/r.js.map +1 -1
- package/dist/extractors/scala.d.ts.map +1 -1
- package/dist/extractors/scala.js +18 -32
- package/dist/extractors/scala.js.map +1 -1
- package/dist/extractors/solidity.js +18 -9
- package/dist/extractors/solidity.js.map +1 -1
- package/dist/extractors/verilog.js +80 -15
- package/dist/extractors/verilog.js.map +1 -1
- package/dist/infrastructure/config.d.ts +1 -0
- package/dist/infrastructure/config.d.ts.map +1 -1
- package/dist/infrastructure/config.js +1 -0
- package/dist/infrastructure/config.js.map +1 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +14 -8
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tool-registry.d.ts +1 -1
- package/dist/mcp/tool-registry.d.ts.map +1 -1
- package/dist/mcp/tool-registry.js +23 -5
- package/dist/mcp/tool-registry.js.map +1 -1
- package/dist/mcp/tools/semantic-search.d.ts +1 -0
- package/dist/mcp/tools/semantic-search.d.ts.map +1 -1
- package/dist/mcp/tools/semantic-search.js +1 -0
- package/dist/mcp/tools/semantic-search.js.map +1 -1
- package/dist/types.d.ts +16 -1
- package/dist/types.d.ts.map +1 -1
- package/grammars/tree-sitter-erlang.wasm +0 -0
- package/grammars/tree-sitter-fsharp.wasm +0 -0
- package/grammars/tree-sitter-fsharp_signature.wasm +0 -0
- package/grammars/tree-sitter-gleam.wasm +0 -0
- package/package.json +11 -10
- package/src/ast-analysis/engine.ts +3 -1
- package/src/ast-analysis/rules/index.ts +87 -0
- package/src/ast-analysis/visitors/ast-store-visitor.ts +45 -9
- package/src/cli/commands/audit.ts +1 -1
- package/src/cli/commands/build.ts +2 -0
- package/src/cli/commands/check.ts +1 -1
- package/src/cli/commands/children.ts +1 -1
- package/src/cli/commands/diff-impact.ts +1 -1
- package/src/cli/commands/roles.ts +1 -1
- package/src/cli/commands/structure.ts +1 -1
- package/src/cli/shared/options.ts +1 -1
- package/src/db/connection.ts +8 -0
- package/src/domain/graph/builder/context.ts +10 -0
- package/src/domain/graph/builder/helpers.ts +8 -3
- package/src/domain/graph/builder/incremental.ts +6 -41
- package/src/domain/graph/builder/pipeline.ts +404 -41
- package/src/domain/graph/builder/stages/build-edges.ts +9 -2
- package/src/domain/graph/builder/stages/collect-files.ts +9 -0
- package/src/domain/graph/builder/stages/detect-changes.ts +130 -4
- package/src/domain/graph/builder/stages/finalize.ts +9 -6
- package/src/domain/graph/builder/stages/insert-nodes.ts +38 -14
- package/src/domain/graph/builder/stages/resolve-imports.ts +79 -25
- package/src/domain/graph/watcher.ts +21 -23
- package/src/domain/parser.ts +110 -10
- package/src/domain/search/models.ts +37 -2
- package/src/domain/wasm-worker-entry.ts +20 -13
- package/src/extractors/c.ts +27 -8
- package/src/extractors/cpp.ts +50 -8
- package/src/extractors/cuda.ts +90 -16
- package/src/extractors/elixir.ts +75 -3
- package/src/extractors/erlang.ts +63 -20
- package/src/extractors/fsharp.ts +104 -0
- package/src/extractors/gleam.ts +7 -2
- package/src/extractors/groovy.ts +45 -1
- package/src/extractors/haskell.ts +45 -4
- package/src/extractors/julia.ts +164 -43
- package/src/extractors/kotlin.ts +4 -0
- package/src/extractors/objc.ts +171 -47
- package/src/extractors/python.ts +5 -3
- package/src/extractors/r.ts +88 -48
- package/src/extractors/scala.ts +24 -36
- package/src/extractors/solidity.ts +17 -8
- package/src/extractors/verilog.ts +83 -15
- package/src/infrastructure/config.ts +1 -0
- package/src/mcp/server.ts +16 -9
- package/src/mcp/tool-registry.ts +28 -5
- package/src/mcp/tools/semantic-search.ts +2 -0
- package/src/types.ts +16 -0
|
@@ -131,6 +131,21 @@ function extractChildExpressionText(node: TreeSitterNode): string | null {
|
|
|
131
131
|
return truncate(node.text);
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
+
/**
|
|
135
|
+
* Count code points cheaply: skip the `[...s]` spread when `s.length` already
|
|
136
|
+
* decides the answer. Each code point is 1 or 2 UTF-16 units, so `.length < 2`
|
|
137
|
+
* implies `< 2` code points and `.length >= 3` already guarantees `>= 2` code
|
|
138
|
+
* points (worst case: one surrogate pair + one BMP char = 2 code points).
|
|
139
|
+
* Only `.length === 2` is genuinely ambiguous (could be a single surrogate
|
|
140
|
+
* pair = 1 code point, or two BMP chars = 2 code points) and needs the spread.
|
|
141
|
+
*/
|
|
142
|
+
function codePointCountAtLeast2(s: string): boolean {
|
|
143
|
+
const len = s.length;
|
|
144
|
+
if (len < 2) return false;
|
|
145
|
+
if (len >= 3) return true;
|
|
146
|
+
return [...s].length >= 2;
|
|
147
|
+
}
|
|
148
|
+
|
|
134
149
|
/**
|
|
135
150
|
* Extract string content from a string-literal node, mirroring the native
|
|
136
151
|
* engine's `build_string_node` (`helpers.rs`). Returns `null` when the
|
|
@@ -142,15 +157,27 @@ function extractStringContent(node: TreeSitterNode, cfg: AstStringConfig): strin
|
|
|
142
157
|
|
|
143
158
|
let s = raw;
|
|
144
159
|
s = trimLeadingChars(s, '@');
|
|
145
|
-
s = trimLeadingChars(s, cfg.stringPrefixes);
|
|
160
|
+
if (cfg.stringPrefixes) s = trimLeadingChars(s, cfg.stringPrefixes);
|
|
146
161
|
if (isRawString) s = trimLeadingChars(s, 'r#');
|
|
147
162
|
s = trimLeadingChars(s, cfg.quoteChars);
|
|
148
163
|
if (isRawString) s = trimTrailingChars(s, '#');
|
|
149
164
|
s = trimTrailingChars(s, cfg.quoteChars);
|
|
150
165
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
166
|
+
return codePointCountAtLeast2(s) ? s : null;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Per-astTypeMap cache for the set of node-types that map to kind 'new'.
|
|
170
|
+
// Computed once per unique astTypeMap reference (one per language) instead
|
|
171
|
+
// of once per file.
|
|
172
|
+
const _newTypesCache = new WeakMap<Record<string, string>, Set<string>>();
|
|
173
|
+
function newTypesFor(astTypeMap: Record<string, string>): Set<string> {
|
|
174
|
+
let s = _newTypesCache.get(astTypeMap);
|
|
175
|
+
if (s) return s;
|
|
176
|
+
s = new Set<string>();
|
|
177
|
+
for (const type in astTypeMap) {
|
|
178
|
+
if (astTypeMap[type] === 'new') s.add(type);
|
|
179
|
+
}
|
|
180
|
+
_newTypesCache.set(astTypeMap, s);
|
|
154
181
|
return s;
|
|
155
182
|
}
|
|
156
183
|
|
|
@@ -164,11 +191,12 @@ export function createAstStoreVisitor(
|
|
|
164
191
|
): Visitor {
|
|
165
192
|
const rows: AstStoreRow[] = [];
|
|
166
193
|
const matched = new Set<number>();
|
|
167
|
-
const newTypes =
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
194
|
+
const newTypes = newTypesFor(astTypeMap);
|
|
195
|
+
// When nodeIdMap is empty, parentNodeId resolution is wasted work — the
|
|
196
|
+
// worker passes an empty map and the main thread re-resolves against its
|
|
197
|
+
// own DB-populated map in features/ast.ts::collectFileAstRows. Skip the
|
|
198
|
+
// findParentDef linear scan in that case.
|
|
199
|
+
const skipParentLookup = nodeIdMap.size === 0;
|
|
172
200
|
|
|
173
201
|
function findParentDef(line: number): Definition | null {
|
|
174
202
|
let best: Definition | null = null;
|
|
@@ -183,6 +211,7 @@ export function createAstStoreVisitor(
|
|
|
183
211
|
}
|
|
184
212
|
|
|
185
213
|
function resolveParentNodeId(line: number): number | null {
|
|
214
|
+
if (skipParentLookup) return null;
|
|
186
215
|
const parentDef = findParentDef(line);
|
|
187
216
|
if (!parentDef) return null;
|
|
188
217
|
return nodeIdMap.get(`${parentDef.name}|${parentDef.kind}|${parentDef.line}`) || null;
|
|
@@ -240,6 +269,13 @@ export function createAstStoreVisitor(
|
|
|
240
269
|
// unrelated subtree. The parent call's skipChildren handles the intended case.
|
|
241
270
|
if (matched.has(node.id)) return;
|
|
242
271
|
|
|
272
|
+
// Gate with `hasOwn` because plain-object lookup walks Object.prototype:
|
|
273
|
+
// tree-sitter node types like `constructor` (Haskell sum-types: Left,
|
|
274
|
+
// Right) would otherwise resolve to `Object.prototype.constructor` (the
|
|
275
|
+
// Object() function), which then crashes the worker boundary with
|
|
276
|
+
// "function Object() { [native code] } could not be cloned" when the
|
|
277
|
+
// resulting astNodes row is structured-cloned back to the main thread.
|
|
278
|
+
if (!Object.hasOwn(astTypeMap, node.type)) return;
|
|
243
279
|
const kind = astTypeMap[node.type];
|
|
244
280
|
if (!kind) return;
|
|
245
281
|
|
|
@@ -17,7 +17,7 @@ export const command: CommandDefinition = {
|
|
|
17
17
|
['-T, --no-tests', 'Exclude test/spec files from results'],
|
|
18
18
|
['--include-tests', 'Include test/spec files (overrides excludeTests config)'],
|
|
19
19
|
['-j, --json', 'Output as JSON'],
|
|
20
|
-
['--limit <number>', 'Max results to return (quick mode)'],
|
|
20
|
+
['-n, --limit <number>', 'Max results to return (quick mode)'],
|
|
21
21
|
['--offset <number>', 'Skip N results (quick mode)'],
|
|
22
22
|
['--ndjson', 'Newline-delimited JSON output (quick mode)'],
|
|
23
23
|
],
|
|
@@ -7,6 +7,7 @@ export const command: CommandDefinition = {
|
|
|
7
7
|
name: 'build [dir]',
|
|
8
8
|
description: 'Parse repo and build graph in .codegraph/graph.db',
|
|
9
9
|
options: [
|
|
10
|
+
['-d, --db <path>', 'Path to graph.db (default: <dir>/.codegraph/graph.db)'],
|
|
10
11
|
['--no-incremental', 'Force full rebuild (ignore file hashes)'],
|
|
11
12
|
['--no-ast', 'Skip AST node extraction (calls, new, string, regex, throw, await)'],
|
|
12
13
|
['--no-complexity', 'Skip complexity metrics computation'],
|
|
@@ -23,6 +24,7 @@ export const command: CommandDefinition = {
|
|
|
23
24
|
engine: engine as EngineMode,
|
|
24
25
|
dataflow: opts.dataflow as boolean,
|
|
25
26
|
cfg: opts.cfg as boolean,
|
|
27
|
+
dbPath: opts.db ? path.resolve(opts.db as string) : undefined,
|
|
26
28
|
});
|
|
27
29
|
},
|
|
28
30
|
};
|
|
@@ -38,7 +38,7 @@ export const command: CommandDefinition = {
|
|
|
38
38
|
['-T, --no-tests', 'Exclude test/spec files from results'],
|
|
39
39
|
['--include-tests', 'Include test/spec files (overrides excludeTests config)'],
|
|
40
40
|
['-j, --json', 'Output as JSON'],
|
|
41
|
-
['--limit <number>', 'Max results to return (manifesto mode)'],
|
|
41
|
+
['-n, --limit <number>', 'Max results to return (manifesto mode)'],
|
|
42
42
|
['--offset <number>', 'Skip N results (manifesto mode)'],
|
|
43
43
|
['--ndjson', 'Newline-delimited JSON output (manifesto mode)'],
|
|
44
44
|
],
|
|
@@ -16,7 +16,7 @@ export const command: CommandDefinition = {
|
|
|
16
16
|
['-k, --kind <kind>', 'Filter to a specific symbol kind'],
|
|
17
17
|
['-T, --no-tests', 'Exclude test/spec files from results'],
|
|
18
18
|
['-j, --json', 'Output as JSON'],
|
|
19
|
-
['--limit <number>', 'Max results to return'],
|
|
19
|
+
['-n, --limit <number>', 'Max results to return'],
|
|
20
20
|
['--offset <number>', 'Skip N results (default: 0)'],
|
|
21
21
|
],
|
|
22
22
|
validate([_name], opts) {
|
|
@@ -8,7 +8,7 @@ export const command: CommandDefinition = {
|
|
|
8
8
|
['-d, --db <path>', 'Path to graph.db'],
|
|
9
9
|
['-T, --no-tests', 'Exclude test/spec files from results'],
|
|
10
10
|
['--include-tests', 'Include test/spec files (overrides excludeTests config)'],
|
|
11
|
-
['--limit <number>', 'Max results to return'],
|
|
11
|
+
['-n, --limit <number>', 'Max results to return'],
|
|
12
12
|
['--offset <number>', 'Skip N results (default: 0)'],
|
|
13
13
|
['--ndjson', 'Newline-delimited JSON output'],
|
|
14
14
|
['--staged', 'Analyze staged changes instead of unstaged'],
|
|
@@ -14,7 +14,7 @@ export const command: CommandDefinition = {
|
|
|
14
14
|
['-T, --no-tests', 'Exclude test/spec files'],
|
|
15
15
|
['--include-tests', 'Include test/spec files (overrides excludeTests config)'],
|
|
16
16
|
['-j, --json', 'Output as JSON'],
|
|
17
|
-
['--limit <number>', 'Max results to return'],
|
|
17
|
+
['-n, --limit <number>', 'Max results to return'],
|
|
18
18
|
['--offset <number>', 'Skip N results (default: 0)'],
|
|
19
19
|
['--ndjson', 'Newline-delimited JSON output'],
|
|
20
20
|
],
|
|
@@ -12,7 +12,7 @@ export const command: CommandDefinition = {
|
|
|
12
12
|
['-T, --no-tests', 'Exclude test/spec files'],
|
|
13
13
|
['--include-tests', 'Include test/spec files (overrides excludeTests config)'],
|
|
14
14
|
['-j, --json', 'Output as JSON'],
|
|
15
|
-
['--limit <number>', 'Max results to return'],
|
|
15
|
+
['-n, --limit <number>', 'Max results to return'],
|
|
16
16
|
['--offset <number>', 'Skip N results (default: 0)'],
|
|
17
17
|
['--ndjson', 'Newline-delimited JSON output'],
|
|
18
18
|
['--modules', 'Show module boundaries (directories with high cohesion)'],
|
|
@@ -13,7 +13,7 @@ export function applyQueryOpts(cmd: Command): Command {
|
|
|
13
13
|
.option('-T, --no-tests', 'Exclude test/spec files from results')
|
|
14
14
|
.option('--include-tests', 'Include test/spec files (overrides excludeTests config)')
|
|
15
15
|
.option('-j, --json', 'Output as JSON')
|
|
16
|
-
.option('--limit <number>', 'Max results to return')
|
|
16
|
+
.option('-n, --limit <number>', 'Max results to return')
|
|
17
17
|
.option('--offset <number>', 'Skip N results (default: 0)')
|
|
18
18
|
.option('--ndjson', 'Newline-delimited JSON output')
|
|
19
19
|
.option('--table', 'Output as aligned table')
|
package/src/db/connection.ts
CHANGED
|
@@ -292,6 +292,14 @@ export function findDbPath(customPath?: string): string {
|
|
|
292
292
|
debug(`findDbPath: stopped at git ceiling ${ceiling}`);
|
|
293
293
|
break;
|
|
294
294
|
}
|
|
295
|
+
// Outside a git repo, cwd is the first (and only) directory we'll check.
|
|
296
|
+
// Walking past it risks attaching to a stale .codegraph/ in an unrelated
|
|
297
|
+
// parent — e.g. /private/tmp/.codegraph/ leaking into every /tmp/foo/ run,
|
|
298
|
+
// or $HOME/.codegraph/ leaking into every scratch dir under $HOME.
|
|
299
|
+
if (!ceiling) {
|
|
300
|
+
debug(`findDbPath: no git ceiling, stopping at ${dir}`);
|
|
301
|
+
break;
|
|
302
|
+
}
|
|
295
303
|
const parent = path.dirname(dir);
|
|
296
304
|
if (parent === dir) break;
|
|
297
305
|
dir = parent;
|
|
@@ -28,6 +28,16 @@ export class PipelineContext {
|
|
|
28
28
|
engineOpts!: EngineOpts;
|
|
29
29
|
engineName!: 'native' | 'wasm';
|
|
30
30
|
engineVersion!: string | null;
|
|
31
|
+
/**
|
|
32
|
+
* The version reported by the native binary itself (CARGO_PKG_VERSION at
|
|
33
|
+
* build time), as opposed to `engineVersion` which prefers the platform
|
|
34
|
+
* package.json. The Rust orchestrator's check_version_mismatch compares
|
|
35
|
+
* `build_meta.engine_version` against CARGO_PKG_VERSION, so build_meta
|
|
36
|
+
* writes must use this value to avoid a perpetual full-rebuild loop when
|
|
37
|
+
* the binary and platform package.json drift apart (e.g., CI hot-swap
|
|
38
|
+
* via ci-install-native.mjs — #1066).
|
|
39
|
+
*/
|
|
40
|
+
nativeBinaryVersion!: string | null;
|
|
31
41
|
aliases!: PathAliases;
|
|
32
42
|
incremental!: boolean;
|
|
33
43
|
forceFullRebuild: boolean = false;
|
|
@@ -222,12 +222,17 @@ export function fileHash(content: string): string {
|
|
|
222
222
|
}
|
|
223
223
|
|
|
224
224
|
/**
|
|
225
|
-
* Stat a file, returning {
|
|
225
|
+
* Stat a file, returning { mtime, size } or null on error.
|
|
226
|
+
*
|
|
227
|
+
* `mtime` is `Math.floor(stat.mtimeMs)` so it matches the integer column
|
|
228
|
+
* stored in the DB. Floor-once-here keeps every consumer honest: storing or
|
|
229
|
+
* comparing a non-floored `mtimeMs` against the integer DB column would cause
|
|
230
|
+
* spurious fast-skip misses on the next build.
|
|
226
231
|
*/
|
|
227
|
-
export function fileStat(filePath: string): {
|
|
232
|
+
export function fileStat(filePath: string): { mtime: number; size: number } | null {
|
|
228
233
|
try {
|
|
229
234
|
const s = fs.statSync(filePath);
|
|
230
|
-
return {
|
|
235
|
+
return { mtime: Math.floor(s.mtimeMs), size: s.size };
|
|
231
236
|
} catch {
|
|
232
237
|
return null;
|
|
233
238
|
}
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import fs from 'node:fs';
|
|
11
11
|
import path from 'node:path';
|
|
12
|
-
import { bulkNodeIdsByFile } from '../../../db/index.js';
|
|
12
|
+
import { bulkNodeIdsByFile, purgeFileData } from '../../../db/index.js';
|
|
13
13
|
import { debug, warn } from '../../../infrastructure/logger.js';
|
|
14
14
|
import { normalizePath } from '../../../shared/constants.js';
|
|
15
15
|
import type {
|
|
@@ -29,8 +29,6 @@ export interface IncrementalStmts {
|
|
|
29
29
|
insertNode: { run: (...params: unknown[]) => unknown };
|
|
30
30
|
insertEdge: { run: (...params: unknown[]) => unknown };
|
|
31
31
|
getNodeId: { get: (...params: unknown[]) => { id: number } | undefined };
|
|
32
|
-
deleteEdgesForFile: { run: (...params: unknown[]) => unknown };
|
|
33
|
-
deleteNodes: { run: (...params: unknown[]) => unknown };
|
|
34
32
|
countNodes: { get: (...params: unknown[]) => { c: number } | undefined };
|
|
35
33
|
listSymbols: { all: (...params: unknown[]) => unknown[] };
|
|
36
34
|
findNodeInFile: { all: (...params: unknown[]) => unknown[] };
|
|
@@ -208,40 +206,6 @@ function rebuildDirContainment(
|
|
|
208
206
|
return 0;
|
|
209
207
|
}
|
|
210
208
|
|
|
211
|
-
// ── Ancillary table cleanup ────────────────────────────────────────────
|
|
212
|
-
|
|
213
|
-
function purgeAncillaryData(db: BetterSqlite3Database, relPath: string): void {
|
|
214
|
-
const tryExec = (sql: string, ...args: string[]): void => {
|
|
215
|
-
try {
|
|
216
|
-
db.prepare(sql).run(...args);
|
|
217
|
-
} catch (err: unknown) {
|
|
218
|
-
if (!(err as Error | undefined)?.message?.includes('no such table')) throw err;
|
|
219
|
-
}
|
|
220
|
-
};
|
|
221
|
-
tryExec(
|
|
222
|
-
'DELETE FROM function_complexity WHERE node_id IN (SELECT id FROM nodes WHERE file = ?)',
|
|
223
|
-
relPath,
|
|
224
|
-
);
|
|
225
|
-
tryExec(
|
|
226
|
-
'DELETE FROM node_metrics WHERE node_id IN (SELECT id FROM nodes WHERE file = ?)',
|
|
227
|
-
relPath,
|
|
228
|
-
);
|
|
229
|
-
tryExec(
|
|
230
|
-
'DELETE FROM cfg_edges WHERE function_node_id IN (SELECT id FROM nodes WHERE file = ?)',
|
|
231
|
-
relPath,
|
|
232
|
-
);
|
|
233
|
-
tryExec(
|
|
234
|
-
'DELETE FROM cfg_blocks WHERE function_node_id IN (SELECT id FROM nodes WHERE file = ?)',
|
|
235
|
-
relPath,
|
|
236
|
-
);
|
|
237
|
-
tryExec(
|
|
238
|
-
'DELETE FROM dataflow WHERE source_id IN (SELECT id FROM nodes WHERE file = ?) OR target_id IN (SELECT id FROM nodes WHERE file = ?)',
|
|
239
|
-
relPath,
|
|
240
|
-
relPath,
|
|
241
|
-
);
|
|
242
|
-
tryExec('DELETE FROM ast_nodes WHERE file = ?', relPath);
|
|
243
|
-
}
|
|
244
|
-
|
|
245
209
|
// ── Import edge building ────────────────────────────────────────────────
|
|
246
210
|
|
|
247
211
|
// Lazily-cached prepared statements for barrel resolution (avoid re-preparing in hot loops)
|
|
@@ -547,10 +511,11 @@ export async function rebuildFile(
|
|
|
547
511
|
// Find reverse-deps BEFORE purging (edges still reference the old nodes)
|
|
548
512
|
const reverseDeps = findReverseDeps(db, relPath);
|
|
549
513
|
|
|
550
|
-
// Purge ancillary tables,
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
514
|
+
// Purge ancillary tables (incl. embeddings), edges, and nodes in one pass.
|
|
515
|
+
// Embeddings must be purged before nodes — better-sqlite3 enforces foreign
|
|
516
|
+
// keys by default, and `embeddings.node_id` references `nodes.id`. Issue #1176.
|
|
517
|
+
// `purgeHashes: false` preserves file_hashes for the next incremental build.
|
|
518
|
+
purgeFileData(db, relPath, { purgeHashes: false });
|
|
554
519
|
|
|
555
520
|
if (!fs.existsSync(filePath)) {
|
|
556
521
|
if (cache) (cache as { remove(p: string): void }).remove(filePath);
|