@optave/codegraph 3.4.1 → 3.6.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 +50 -28
- package/dist/ast-analysis/engine.d.ts.map +1 -1
- package/dist/ast-analysis/engine.js +119 -127
- package/dist/ast-analysis/engine.js.map +1 -1
- package/dist/ast-analysis/rules/javascript.d.ts.map +1 -1
- package/dist/ast-analysis/rules/javascript.js +1 -0
- package/dist/ast-analysis/rules/javascript.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 +116 -35
- package/dist/ast-analysis/visitors/ast-store-visitor.js.map +1 -1
- package/dist/ast-analysis/visitors/complexity-visitor.d.ts.map +1 -1
- package/dist/ast-analysis/visitors/complexity-visitor.js +11 -13
- package/dist/ast-analysis/visitors/complexity-visitor.js.map +1 -1
- package/dist/db/better-sqlite3.d.ts +3 -0
- package/dist/db/better-sqlite3.d.ts.map +1 -0
- package/dist/db/better-sqlite3.js +19 -0
- package/dist/db/better-sqlite3.js.map +1 -0
- package/dist/db/connection.d.ts +25 -4
- package/dist/db/connection.d.ts.map +1 -1
- package/dist/db/connection.js +125 -23
- package/dist/db/connection.js.map +1 -1
- package/dist/db/index.d.ts +2 -2
- package/dist/db/index.d.ts.map +1 -1
- package/dist/db/index.js +1 -1
- package/dist/db/index.js.map +1 -1
- package/dist/db/migrations.d.ts.map +1 -1
- package/dist/db/migrations.js +40 -32
- package/dist/db/migrations.js.map +1 -1
- package/dist/db/query-builder.d.ts +5 -5
- package/dist/db/query-builder.d.ts.map +1 -1
- package/dist/db/query-builder.js +20 -4
- package/dist/db/query-builder.js.map +1 -1
- package/dist/db/repository/index.d.ts +1 -0
- package/dist/db/repository/index.d.ts.map +1 -1
- package/dist/db/repository/index.js +1 -0
- package/dist/db/repository/index.js.map +1 -1
- package/dist/db/repository/native-repository.d.ts +58 -0
- package/dist/db/repository/native-repository.d.ts.map +1 -0
- package/dist/db/repository/native-repository.js +261 -0
- package/dist/db/repository/native-repository.js.map +1 -0
- package/dist/db/repository/nodes.d.ts +4 -4
- package/dist/db/repository/nodes.d.ts.map +1 -1
- package/dist/db/repository/nodes.js +6 -6
- package/dist/db/repository/nodes.js.map +1 -1
- package/dist/domain/analysis/context.d.ts.map +1 -1
- package/dist/domain/analysis/context.js +51 -66
- package/dist/domain/analysis/context.js.map +1 -1
- package/dist/domain/analysis/dependencies.d.ts.map +1 -1
- package/dist/domain/analysis/dependencies.js +62 -70
- package/dist/domain/analysis/dependencies.js.map +1 -1
- package/dist/domain/analysis/diff-impact.d.ts +9 -7
- package/dist/domain/analysis/diff-impact.d.ts.map +1 -1
- package/dist/domain/analysis/exports.d.ts.map +1 -1
- package/dist/domain/analysis/exports.js +29 -33
- package/dist/domain/analysis/exports.js.map +1 -1
- package/dist/domain/analysis/fn-impact.d.ts +15 -17
- package/dist/domain/analysis/fn-impact.d.ts.map +1 -1
- package/dist/domain/analysis/fn-impact.js +35 -65
- package/dist/domain/analysis/fn-impact.js.map +1 -1
- package/dist/domain/analysis/module-map.d.ts.map +1 -1
- package/dist/domain/analysis/module-map.js +91 -6
- package/dist/domain/analysis/module-map.js.map +1 -1
- package/dist/domain/analysis/query-helpers.d.ts +20 -0
- package/dist/domain/analysis/query-helpers.d.ts.map +1 -0
- package/dist/domain/analysis/query-helpers.js +27 -0
- package/dist/domain/analysis/query-helpers.js.map +1 -0
- package/dist/domain/graph/builder/context.d.ts +2 -1
- package/dist/domain/graph/builder/context.d.ts.map +1 -1
- package/dist/domain/graph/builder/context.js +1 -0
- package/dist/domain/graph/builder/context.js.map +1 -1
- package/dist/domain/graph/builder/helpers.d.ts.map +1 -1
- package/dist/domain/graph/builder/helpers.js +15 -9
- package/dist/domain/graph/builder/helpers.js.map +1 -1
- package/dist/domain/graph/builder/incremental.d.ts.map +1 -1
- package/dist/domain/graph/builder/incremental.js +3 -2
- package/dist/domain/graph/builder/incremental.js.map +1 -1
- package/dist/domain/graph/builder/pipeline.d.ts.map +1 -1
- package/dist/domain/graph/builder/pipeline.js +95 -7
- 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 +101 -57
- package/dist/domain/graph/builder/stages/build-edges.js.map +1 -1
- package/dist/domain/graph/builder/stages/build-structure.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/build-structure.js +33 -3
- package/dist/domain/graph/builder/stages/build-structure.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 +70 -6
- package/dist/domain/graph/builder/stages/collect-files.js.map +1 -1
- package/dist/domain/graph/builder/stages/detect-changes.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/detect-changes.js +36 -14
- 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 +130 -88
- package/dist/domain/graph/builder/stages/finalize.js.map +1 -1
- package/dist/domain/graph/builder/stages/insert-nodes.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/insert-nodes.js +124 -16
- 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 +3 -2
- package/dist/domain/graph/builder/stages/resolve-imports.js.map +1 -1
- package/dist/domain/graph/resolve.d.ts +0 -4
- package/dist/domain/graph/resolve.d.ts.map +1 -1
- package/dist/domain/graph/resolve.js +32 -48
- package/dist/domain/graph/resolve.js.map +1 -1
- package/dist/domain/graph/watcher.d.ts.map +1 -1
- package/dist/domain/graph/watcher.js +12 -12
- package/dist/domain/graph/watcher.js.map +1 -1
- package/dist/domain/parser.d.ts +1 -1
- package/dist/domain/parser.d.ts.map +1 -1
- package/dist/domain/parser.js +165 -101
- package/dist/domain/parser.js.map +1 -1
- package/dist/domain/search/search/cli-formatter.d.ts.map +1 -1
- package/dist/domain/search/search/cli-formatter.js +88 -83
- package/dist/domain/search/search/cli-formatter.js.map +1 -1
- package/dist/extractors/bash.d.ts +6 -0
- package/dist/extractors/bash.d.ts.map +1 -0
- package/dist/extractors/bash.js +91 -0
- package/dist/extractors/bash.js.map +1 -0
- package/dist/extractors/c.d.ts +6 -0
- package/dist/extractors/c.d.ts.map +1 -0
- package/dist/extractors/c.js +204 -0
- package/dist/extractors/c.js.map +1 -0
- package/dist/extractors/cpp.d.ts +6 -0
- package/dist/extractors/cpp.d.ts.map +1 -0
- package/dist/extractors/cpp.js +283 -0
- package/dist/extractors/cpp.js.map +1 -0
- package/dist/extractors/csharp.d.ts.map +1 -1
- package/dist/extractors/csharp.js +42 -54
- package/dist/extractors/csharp.js.map +1 -1
- package/dist/extractors/go.d.ts.map +1 -1
- package/dist/extractors/go.js +126 -130
- package/dist/extractors/go.js.map +1 -1
- package/dist/extractors/hcl.js +6 -6
- package/dist/extractors/hcl.js.map +1 -1
- package/dist/extractors/helpers.d.ts +32 -1
- package/dist/extractors/helpers.d.ts.map +1 -1
- package/dist/extractors/helpers.js +74 -0
- package/dist/extractors/helpers.js.map +1 -1
- package/dist/extractors/index.d.ts +6 -0
- package/dist/extractors/index.d.ts.map +1 -1
- package/dist/extractors/index.js +6 -0
- package/dist/extractors/index.js.map +1 -1
- package/dist/extractors/java.d.ts.map +1 -1
- package/dist/extractors/java.js +32 -47
- package/dist/extractors/java.js.map +1 -1
- package/dist/extractors/javascript.d.ts.map +1 -1
- package/dist/extractors/javascript.js +359 -330
- package/dist/extractors/javascript.js.map +1 -1
- package/dist/extractors/kotlin.d.ts +6 -0
- package/dist/extractors/kotlin.d.ts.map +1 -0
- package/dist/extractors/kotlin.js +275 -0
- package/dist/extractors/kotlin.js.map +1 -0
- package/dist/extractors/php.d.ts.map +1 -1
- package/dist/extractors/php.js +39 -44
- package/dist/extractors/php.js.map +1 -1
- package/dist/extractors/python.d.ts.map +1 -1
- package/dist/extractors/python.js +75 -93
- package/dist/extractors/python.js.map +1 -1
- package/dist/extractors/ruby.js +6 -13
- package/dist/extractors/ruby.js.map +1 -1
- package/dist/extractors/rust.d.ts.map +1 -1
- package/dist/extractors/rust.js +58 -82
- package/dist/extractors/rust.js.map +1 -1
- package/dist/extractors/scala.d.ts +6 -0
- package/dist/extractors/scala.d.ts.map +1 -0
- package/dist/extractors/scala.js +269 -0
- package/dist/extractors/scala.js.map +1 -0
- package/dist/extractors/swift.d.ts +6 -0
- package/dist/extractors/swift.d.ts.map +1 -0
- package/dist/extractors/swift.js +275 -0
- package/dist/extractors/swift.js.map +1 -0
- package/dist/features/ast.d.ts +16 -1
- package/dist/features/ast.d.ts.map +1 -1
- package/dist/features/ast.js +45 -23
- package/dist/features/ast.js.map +1 -1
- package/dist/features/audit.d.ts.map +1 -1
- package/dist/features/audit.js +17 -21
- package/dist/features/audit.js.map +1 -1
- package/dist/features/branch-compare.d.ts.map +1 -1
- package/dist/features/branch-compare.js +50 -4
- package/dist/features/branch-compare.js.map +1 -1
- package/dist/features/cfg.d.ts +7 -1
- package/dist/features/cfg.d.ts.map +1 -1
- package/dist/features/cfg.js +118 -62
- package/dist/features/cfg.js.map +1 -1
- package/dist/features/check.d.ts.map +1 -1
- package/dist/features/check.js +79 -62
- package/dist/features/check.js.map +1 -1
- package/dist/features/complexity-query.d.ts.map +1 -1
- package/dist/features/complexity-query.js +142 -137
- package/dist/features/complexity-query.js.map +1 -1
- package/dist/features/complexity.d.ts +7 -1
- package/dist/features/complexity.d.ts.map +1 -1
- package/dist/features/complexity.js +62 -1
- package/dist/features/complexity.js.map +1 -1
- package/dist/features/dataflow.d.ts +7 -1
- package/dist/features/dataflow.d.ts.map +1 -1
- package/dist/features/dataflow.js +356 -188
- package/dist/features/dataflow.js.map +1 -1
- package/dist/features/graph-enrichment.d.ts.map +1 -1
- package/dist/features/graph-enrichment.js +117 -104
- package/dist/features/graph-enrichment.js.map +1 -1
- package/dist/features/sequence.d.ts.map +1 -1
- package/dist/features/sequence.js +25 -4
- package/dist/features/sequence.js.map +1 -1
- package/dist/features/snapshot.d.ts.map +1 -1
- package/dist/features/snapshot.js +2 -1
- package/dist/features/snapshot.js.map +1 -1
- package/dist/features/structure-query.d.ts.map +1 -1
- package/dist/features/structure-query.js +29 -4
- package/dist/features/structure-query.js.map +1 -1
- package/dist/features/structure.d.ts.map +1 -1
- package/dist/features/structure.js +35 -15
- package/dist/features/structure.js.map +1 -1
- package/dist/graph/algorithms/leiden/adapter.d.ts.map +1 -1
- package/dist/graph/algorithms/leiden/adapter.js +88 -73
- package/dist/graph/algorithms/leiden/adapter.js.map +1 -1
- package/dist/graph/algorithms/leiden/index.js +43 -28
- package/dist/graph/algorithms/leiden/index.js.map +1 -1
- package/dist/graph/algorithms/leiden/optimiser.d.ts.map +1 -1
- package/dist/graph/algorithms/leiden/optimiser.js +90 -104
- package/dist/graph/algorithms/leiden/optimiser.js.map +1 -1
- package/dist/graph/algorithms/leiden/partition.d.ts.map +1 -1
- package/dist/graph/algorithms/leiden/partition.js +89 -106
- package/dist/graph/algorithms/leiden/partition.js.map +1 -1
- package/dist/graph/model.d.ts +2 -0
- package/dist/graph/model.d.ts.map +1 -1
- package/dist/graph/model.js +20 -8
- package/dist/graph/model.js.map +1 -1
- package/dist/infrastructure/config.d.ts +0 -8
- package/dist/infrastructure/config.d.ts.map +1 -1
- package/dist/infrastructure/config.js +73 -62
- package/dist/infrastructure/config.js.map +1 -1
- package/dist/infrastructure/registry.d.ts +0 -8
- package/dist/infrastructure/registry.d.ts.map +1 -1
- package/dist/infrastructure/registry.js +12 -14
- package/dist/infrastructure/registry.js.map +1 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +47 -45
- package/dist/mcp/server.js.map +1 -1
- package/dist/presentation/audit.d.ts.map +1 -1
- package/dist/presentation/audit.js +61 -57
- package/dist/presentation/audit.js.map +1 -1
- package/dist/presentation/branch-compare.d.ts.map +1 -1
- package/dist/presentation/branch-compare.js +56 -38
- package/dist/presentation/branch-compare.js.map +1 -1
- package/dist/presentation/check.d.ts.map +1 -1
- package/dist/presentation/check.js +30 -32
- package/dist/presentation/check.js.map +1 -1
- package/dist/presentation/colors.d.ts.map +1 -1
- package/dist/presentation/colors.js +2 -0
- package/dist/presentation/colors.js.map +1 -1
- package/dist/presentation/complexity.d.ts.map +1 -1
- package/dist/presentation/complexity.js +25 -19
- package/dist/presentation/complexity.js.map +1 -1
- package/dist/presentation/queries-cli/exports.d.ts.map +1 -1
- package/dist/presentation/queries-cli/exports.js +15 -15
- package/dist/presentation/queries-cli/exports.js.map +1 -1
- package/dist/presentation/queries-cli/impact.d.ts.map +1 -1
- package/dist/presentation/queries-cli/impact.js +29 -19
- package/dist/presentation/queries-cli/impact.js.map +1 -1
- package/dist/types.d.ts +406 -3
- package/dist/types.d.ts.map +1 -1
- package/grammars/tree-sitter-bash.wasm +0 -0
- package/grammars/tree-sitter-c.wasm +0 -0
- package/grammars/tree-sitter-cpp.wasm +0 -0
- package/grammars/tree-sitter-kotlin.wasm +0 -0
- package/grammars/tree-sitter-scala.wasm +0 -0
- package/grammars/tree-sitter-swift.wasm +0 -0
- package/package.json +67 -11
- package/src/ast-analysis/engine.ts +147 -138
- package/src/ast-analysis/rules/javascript.ts +1 -0
- package/src/ast-analysis/visitors/ast-store-visitor.ts +116 -34
- package/src/ast-analysis/visitors/complexity-visitor.ts +11 -11
- package/src/db/better-sqlite3.ts +20 -0
- package/src/db/connection.ts +148 -26
- package/src/db/index.ts +4 -1
- package/src/db/migrations.ts +38 -32
- package/src/db/query-builder.ts +30 -5
- package/src/db/repository/index.ts +1 -0
- package/src/db/repository/native-repository.ts +361 -0
- package/src/db/repository/nodes.ts +7 -3
- package/src/domain/analysis/context.ts +73 -75
- package/src/domain/analysis/dependencies.ts +78 -68
- package/src/domain/analysis/exports.ts +45 -34
- package/src/domain/analysis/fn-impact.ts +67 -64
- package/src/domain/analysis/module-map.ts +103 -8
- package/src/domain/analysis/query-helpers.ts +35 -0
- package/src/domain/graph/builder/context.ts +2 -0
- package/src/domain/graph/builder/helpers.ts +12 -6
- package/src/domain/graph/builder/incremental.ts +3 -2
- package/src/domain/graph/builder/pipeline.ts +98 -6
- package/src/domain/graph/builder/stages/build-edges.ts +116 -83
- package/src/domain/graph/builder/stages/build-structure.ts +46 -8
- package/src/domain/graph/builder/stages/collect-files.ts +83 -6
- package/src/domain/graph/builder/stages/detect-changes.ts +44 -21
- package/src/domain/graph/builder/stages/finalize.ts +172 -109
- package/src/domain/graph/builder/stages/insert-nodes.ts +147 -17
- package/src/domain/graph/builder/stages/resolve-imports.ts +3 -2
- package/src/domain/graph/resolve.ts +34 -46
- package/src/domain/graph/watcher.ts +12 -14
- package/src/domain/parser.ts +169 -97
- package/src/domain/search/search/cli-formatter.ts +121 -94
- package/src/extractors/bash.ts +97 -0
- package/src/extractors/c.ts +212 -0
- package/src/extractors/cpp.ts +298 -0
- package/src/extractors/csharp.ts +53 -56
- package/src/extractors/go.ts +152 -134
- package/src/extractors/hcl.ts +6 -6
- package/src/extractors/helpers.ts +93 -1
- package/src/extractors/index.ts +6 -0
- package/src/extractors/java.ts +43 -48
- package/src/extractors/javascript.ts +382 -317
- package/src/extractors/kotlin.ts +293 -0
- package/src/extractors/php.ts +46 -40
- package/src/extractors/python.ts +81 -104
- package/src/extractors/ruby.ts +6 -13
- package/src/extractors/rust.ts +65 -84
- package/src/extractors/scala.ts +285 -0
- package/src/extractors/swift.ts +293 -0
- package/src/features/ast.ts +74 -24
- package/src/features/audit.ts +24 -20
- package/src/features/branch-compare.ts +54 -5
- package/src/features/cfg.ts +158 -65
- package/src/features/check.ts +90 -74
- package/src/features/complexity-query.ts +181 -163
- package/src/features/complexity.ts +64 -1
- package/src/features/dataflow.ts +462 -217
- package/src/features/graph-enrichment.ts +161 -117
- package/src/features/sequence.ts +27 -4
- package/src/features/snapshot.ts +2 -1
- package/src/features/structure-query.ts +43 -4
- package/src/features/structure.ts +50 -22
- package/src/graph/algorithms/leiden/adapter.ts +126 -71
- package/src/graph/algorithms/leiden/index.ts +67 -28
- package/src/graph/algorithms/leiden/optimiser.ts +114 -105
- package/src/graph/algorithms/leiden/partition.ts +131 -98
- package/src/graph/model.ts +19 -7
- package/src/infrastructure/config.ts +60 -58
- package/src/infrastructure/registry.ts +17 -14
- package/src/mcp/server.ts +48 -47
- package/src/presentation/audit.ts +72 -67
- package/src/presentation/branch-compare.ts +54 -50
- package/src/presentation/check.ts +34 -34
- package/src/presentation/colors.ts +2 -0
- package/src/presentation/complexity.ts +39 -33
- package/src/presentation/queries-cli/exports.ts +17 -17
- package/src/presentation/queries-cli/impact.ts +30 -22
- package/src/types.ts +458 -3
|
@@ -2,14 +2,78 @@
|
|
|
2
2
|
* Stage: collectFiles
|
|
3
3
|
*
|
|
4
4
|
* Collects all source files to process. Handles both normal and scoped rebuilds.
|
|
5
|
+
* For incremental builds with a valid journal, reconstructs the file list from
|
|
6
|
+
* the DB's file_hashes table + journal deltas, skipping the filesystem scan.
|
|
5
7
|
*/
|
|
6
8
|
import fs from 'node:fs';
|
|
7
9
|
import path from 'node:path';
|
|
8
|
-
import { info } from '../../../../infrastructure/logger.js';
|
|
10
|
+
import { debug, info } from '../../../../infrastructure/logger.js';
|
|
9
11
|
import { normalizePath } from '../../../../shared/constants.js';
|
|
12
|
+
import { readJournal } from '../../journal.js';
|
|
10
13
|
import type { PipelineContext } from '../context.js';
|
|
11
14
|
import { collectFiles as collectFilesUtil } from '../helpers.js';
|
|
12
15
|
|
|
16
|
+
/**
|
|
17
|
+
* Reconstruct allFiles from DB file_hashes + journal deltas.
|
|
18
|
+
* Returns null when the fast path isn't applicable (first build, no journal, etc).
|
|
19
|
+
*/
|
|
20
|
+
function tryFastCollect(
|
|
21
|
+
ctx: PipelineContext,
|
|
22
|
+
): { files: string[]; directories: Set<string> } | null {
|
|
23
|
+
const { db, rootDir } = ctx;
|
|
24
|
+
|
|
25
|
+
// 1. Check that file_hashes table exists and has entries
|
|
26
|
+
let dbFileCount: number;
|
|
27
|
+
try {
|
|
28
|
+
dbFileCount = (db.prepare('SELECT COUNT(*) as c FROM file_hashes').get() as { c: number }).c;
|
|
29
|
+
} catch {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
if (dbFileCount === 0) return null;
|
|
33
|
+
|
|
34
|
+
// 2. Read the journal — only use fast path when journal has entries,
|
|
35
|
+
// proving the watcher was active and tracking changes. An empty-but-valid
|
|
36
|
+
// journal (no watcher) could miss file deletions.
|
|
37
|
+
const journal = readJournal(rootDir);
|
|
38
|
+
if (!journal.valid) return null;
|
|
39
|
+
const hasEntries =
|
|
40
|
+
(journal.changed && journal.changed.length > 0) ||
|
|
41
|
+
(journal.removed && journal.removed.length > 0);
|
|
42
|
+
if (!hasEntries) return null;
|
|
43
|
+
|
|
44
|
+
// 3. Load existing file list from file_hashes (relative paths)
|
|
45
|
+
const dbFiles = (db.prepare('SELECT file FROM file_hashes').all() as Array<{ file: string }>).map(
|
|
46
|
+
(r) => r.file,
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
// 4. Apply journal deltas: remove deleted files, add new/changed files
|
|
50
|
+
const fileSet = new Set(dbFiles);
|
|
51
|
+
if (journal.removed) {
|
|
52
|
+
for (const removed of journal.removed) {
|
|
53
|
+
fileSet.delete(removed);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (journal.changed) {
|
|
57
|
+
for (const changed of journal.changed) {
|
|
58
|
+
fileSet.add(changed);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// 5. Convert to absolute paths and compute directories
|
|
63
|
+
const files: string[] = [];
|
|
64
|
+
const directories = new Set<string>();
|
|
65
|
+
for (const relPath of fileSet) {
|
|
66
|
+
const absPath = path.join(rootDir, relPath);
|
|
67
|
+
files.push(absPath);
|
|
68
|
+
directories.add(path.dirname(absPath));
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
debug(
|
|
72
|
+
`collectFiles fast path: ${dbFiles.length} from DB, journal: +${journal.changed?.length ?? 0}/-${journal.removed?.length ?? 0} → ${files.length} files`,
|
|
73
|
+
);
|
|
74
|
+
return { files, directories };
|
|
75
|
+
}
|
|
76
|
+
|
|
13
77
|
export async function collectFiles(ctx: PipelineContext): Promise<void> {
|
|
14
78
|
const { rootDir, config, opts } = ctx;
|
|
15
79
|
|
|
@@ -33,10 +97,23 @@ export async function collectFiles(ctx: PipelineContext): Promise<void> {
|
|
|
33
97
|
ctx.removed = missing;
|
|
34
98
|
ctx.isFullBuild = false;
|
|
35
99
|
info(`Scoped rebuild: ${existing.length} files to rebuild, ${missing.length} to purge`);
|
|
36
|
-
|
|
37
|
-
const collected = collectFilesUtil(rootDir, [], config, new Set<string>());
|
|
38
|
-
ctx.allFiles = collected.files;
|
|
39
|
-
ctx.discoveredDirs = collected.directories;
|
|
40
|
-
info(`Found ${ctx.allFiles.length} files to parse`);
|
|
100
|
+
return;
|
|
41
101
|
}
|
|
102
|
+
|
|
103
|
+
// Incremental fast path: reconstruct file list from DB + journal deltas
|
|
104
|
+
// instead of full recursive filesystem scan (~8ms savings on 473 files).
|
|
105
|
+
if (ctx.incremental && !ctx.forceFullRebuild) {
|
|
106
|
+
const fast = tryFastCollect(ctx);
|
|
107
|
+
if (fast) {
|
|
108
|
+
ctx.allFiles = fast.files;
|
|
109
|
+
ctx.discoveredDirs = fast.directories;
|
|
110
|
+
info(`Found ${ctx.allFiles.length} files (cached)`);
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const collected = collectFilesUtil(rootDir, [], config, new Set<string>());
|
|
116
|
+
ctx.allFiles = collected.files;
|
|
117
|
+
ctx.discoveredDirs = collected.directories;
|
|
118
|
+
info(`Found ${ctx.allFiles.length} files to parse`);
|
|
42
119
|
}
|
|
@@ -10,7 +10,7 @@ import path from 'node:path';
|
|
|
10
10
|
import { closeDb } from '../../../../db/index.js';
|
|
11
11
|
import { debug, info } from '../../../../infrastructure/logger.js';
|
|
12
12
|
import { normalizePath } from '../../../../shared/constants.js';
|
|
13
|
-
import type { BetterSqlite3Database, ExtractorOutput } from '../../../../types.js';
|
|
13
|
+
import type { BetterSqlite3Database, ExtractorOutput, NativeDatabase } from '../../../../types.js';
|
|
14
14
|
import { parseFilesAuto } from '../../../parser.js';
|
|
15
15
|
import { readJournal, writeJournalHeader } from '../../journal.js';
|
|
16
16
|
import type { PipelineContext } from '../context.js';
|
|
@@ -58,10 +58,16 @@ function getChangedFiles(
|
|
|
58
58
|
db: BetterSqlite3Database,
|
|
59
59
|
allFiles: string[],
|
|
60
60
|
rootDir: string,
|
|
61
|
+
nativeDb?: NativeDatabase,
|
|
61
62
|
): ChangeResult {
|
|
62
63
|
let hasTable = false;
|
|
63
64
|
try {
|
|
64
|
-
|
|
65
|
+
if (nativeDb) {
|
|
66
|
+
nativeDb.queryGet('SELECT 1 FROM file_hashes LIMIT 1', []);
|
|
67
|
+
} else {
|
|
68
|
+
db.prepare('SELECT 1 FROM file_hashes LIMIT 1').get();
|
|
69
|
+
}
|
|
70
|
+
// Query succeeded → table exists (result may be undefined if table is empty)
|
|
65
71
|
hasTable = true;
|
|
66
72
|
} catch {
|
|
67
73
|
/* table doesn't exist */
|
|
@@ -75,11 +81,11 @@ function getChangedFiles(
|
|
|
75
81
|
};
|
|
76
82
|
}
|
|
77
83
|
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
)
|
|
82
|
-
);
|
|
84
|
+
const sql = 'SELECT file, hash, mtime, size FROM file_hashes';
|
|
85
|
+
const rows = nativeDb
|
|
86
|
+
? (nativeDb.queryAll(sql, []) as unknown as FileHashRow[])
|
|
87
|
+
: (db.prepare(sql).all() as FileHashRow[]);
|
|
88
|
+
const existing = new Map<string, FileHashRow>(rows.map((r) => [r.file, r]));
|
|
83
89
|
|
|
84
90
|
const removed = detectRemovedFiles(existing, allFiles, rootDir);
|
|
85
91
|
const journalResult = tryJournalTier(db, existing, rootDir, removed);
|
|
@@ -325,21 +331,33 @@ function purgeAndAddReverseDeps(
|
|
|
325
331
|
reverseDeps: Set<string>,
|
|
326
332
|
): void {
|
|
327
333
|
const { db, rootDir } = ctx;
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
)
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
334
|
+
const hasPurge = changePaths.length > 0 || ctx.removed.length > 0;
|
|
335
|
+
const hasReverseDeps = reverseDeps.size > 0;
|
|
336
|
+
const reverseDepList = hasReverseDeps ? [...reverseDeps] : [];
|
|
337
|
+
|
|
338
|
+
if (hasPurge || hasReverseDeps) {
|
|
339
|
+
const filesToPurge = hasPurge ? [...ctx.removed, ...changePaths] : [];
|
|
340
|
+
// Prefer NativeDatabase: purge + reverse-dep edge deletion in one transaction (#670)
|
|
341
|
+
if (ctx.engineName === 'native' && ctx.nativeDb?.purgeFilesData) {
|
|
342
|
+
ctx.nativeDb.purgeFilesData(filesToPurge, false, hasReverseDeps ? reverseDepList : undefined);
|
|
343
|
+
} else {
|
|
344
|
+
if (hasPurge) {
|
|
345
|
+
purgeFilesFromGraph(db, filesToPurge, { purgeHashes: false });
|
|
346
|
+
}
|
|
347
|
+
if (hasReverseDeps) {
|
|
348
|
+
const deleteOutgoingEdgesForFile = db.prepare(
|
|
349
|
+
'DELETE FROM edges WHERE source_id IN (SELECT id FROM nodes WHERE file = ?)',
|
|
350
|
+
);
|
|
351
|
+
for (const relPath of reverseDepList) {
|
|
352
|
+
deleteOutgoingEdgesForFile.run(relPath);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
341
355
|
}
|
|
342
356
|
}
|
|
357
|
+
for (const relPath of reverseDeps) {
|
|
358
|
+
const absPath = path.join(rootDir, relPath);
|
|
359
|
+
ctx.parseChanges.push({ file: absPath, relPath, _reverseDepOnly: true });
|
|
360
|
+
}
|
|
343
361
|
}
|
|
344
362
|
|
|
345
363
|
function detectHasEmbeddings(db: BetterSqlite3Database): boolean {
|
|
@@ -415,7 +433,12 @@ export async function detectChanges(ctx: PipelineContext): Promise<void> {
|
|
|
415
433
|
}
|
|
416
434
|
const increResult =
|
|
417
435
|
incremental && !forceFullRebuild
|
|
418
|
-
? getChangedFiles(
|
|
436
|
+
? getChangedFiles(
|
|
437
|
+
db,
|
|
438
|
+
allFiles,
|
|
439
|
+
rootDir,
|
|
440
|
+
ctx.engineName === 'native' ? ctx.nativeDb : undefined,
|
|
441
|
+
)
|
|
419
442
|
: {
|
|
420
443
|
changed: allFiles.map((f): ChangedFile => ({ file: f })),
|
|
421
444
|
removed: [] as string[],
|
|
@@ -6,18 +6,19 @@
|
|
|
6
6
|
import { tmpdir } from 'node:os';
|
|
7
7
|
import path from 'node:path';
|
|
8
8
|
import { performance } from 'node:perf_hooks';
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
closeDbPair,
|
|
11
|
+
closeDbPairDeferred,
|
|
12
|
+
getBuildMeta,
|
|
13
|
+
setBuildMeta,
|
|
14
|
+
} from '../../../../db/index.js';
|
|
10
15
|
import { debug, info, warn } from '../../../../infrastructure/logger.js';
|
|
11
16
|
import { CODEGRAPH_VERSION } from '../../../../shared/version.js';
|
|
12
17
|
import { writeJournalHeader } from '../../journal.js';
|
|
13
18
|
import type { PipelineContext } from '../context.js';
|
|
14
19
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
const t0 = performance.now();
|
|
19
|
-
|
|
20
|
-
// Release cached WASM trees
|
|
20
|
+
/** Release cached WASM parse trees to free memory. */
|
|
21
|
+
function releaseWasmTrees(allSymbols: PipelineContext['allSymbols']): void {
|
|
21
22
|
for (const [, symbols] of allSymbols) {
|
|
22
23
|
const tree = symbols._tree as { delete?: () => void } | undefined;
|
|
23
24
|
if (tree && typeof tree.delete === 'function') {
|
|
@@ -30,113 +31,141 @@ export async function finalize(ctx: PipelineContext): Promise<void> {
|
|
|
30
31
|
symbols._tree = undefined;
|
|
31
32
|
symbols._langId = undefined;
|
|
32
33
|
}
|
|
34
|
+
}
|
|
33
35
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
36
|
+
/**
|
|
37
|
+
* Detect significant drift between current and previous node/edge counts.
|
|
38
|
+
* Skipped for small incremental changes where count fluctuation is expected.
|
|
39
|
+
*/
|
|
40
|
+
function detectIncrementalDrift(
|
|
41
|
+
ctx: PipelineContext,
|
|
42
|
+
nodeCount: number,
|
|
43
|
+
actualEdgeCount: number,
|
|
44
|
+
): void {
|
|
45
|
+
const { db, allSymbols, config } = ctx;
|
|
46
|
+
const useNativeDb = ctx.engineName === 'native' && !!ctx.nativeDb;
|
|
47
|
+
if (ctx.isFullBuild || allSymbols.size <= 3) return;
|
|
37
48
|
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
49
|
+
const prevNodes = useNativeDb
|
|
50
|
+
? ctx.nativeDb!.getBuildMeta('node_count')
|
|
51
|
+
: getBuildMeta(db, 'node_count');
|
|
52
|
+
const prevEdges = useNativeDb
|
|
53
|
+
? ctx.nativeDb!.getBuildMeta('edge_count')
|
|
54
|
+
: getBuildMeta(db, 'edge_count');
|
|
55
|
+
if (!prevNodes || !prevEdges) return;
|
|
42
56
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
if (
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
(config as { build?: { driftThreshold?: number } }).build?.driftThreshold ?? 0.2;
|
|
56
|
-
if (nodeDrift > driftThreshold || edgeDrift > driftThreshold) {
|
|
57
|
-
warn(
|
|
58
|
-
`Incremental build diverged significantly from previous counts (nodes: ${prevN}\u2192${nodeCount} [${(nodeDrift * 100).toFixed(1)}%], edges: ${prevE}\u2192${actualEdgeCount} [${(edgeDrift * 100).toFixed(1)}%], threshold: ${(driftThreshold * 100).toFixed(0)}%). Consider rebuilding with --no-incremental.`,
|
|
59
|
-
);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|
|
57
|
+
const prevN = Number(prevNodes);
|
|
58
|
+
const prevE = Number(prevEdges);
|
|
59
|
+
if (prevN <= 0) return;
|
|
60
|
+
|
|
61
|
+
const nodeDrift = Math.abs(nodeCount - prevN) / prevN;
|
|
62
|
+
const edgeDrift = prevE > 0 ? Math.abs(actualEdgeCount - prevE) / prevE : 0;
|
|
63
|
+
const driftThreshold =
|
|
64
|
+
(config as { build?: { driftThreshold?: number } }).build?.driftThreshold ?? 0.2;
|
|
65
|
+
if (nodeDrift > driftThreshold || edgeDrift > driftThreshold) {
|
|
66
|
+
warn(
|
|
67
|
+
`Incremental build diverged significantly from previous counts (nodes: ${prevN}\u2192${nodeCount} [${(nodeDrift * 100).toFixed(1)}%], edges: ${prevE}\u2192${actualEdgeCount} [${(edgeDrift * 100).toFixed(1)}%], threshold: ${(driftThreshold * 100).toFixed(0)}%). Consider rebuilding with --no-incremental.`,
|
|
68
|
+
);
|
|
63
69
|
}
|
|
70
|
+
}
|
|
64
71
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
72
|
+
/**
|
|
73
|
+
* Persist build metadata (engine, version, counts, timestamp).
|
|
74
|
+
* Skipped for small incremental builds to avoid WAL fsync cost.
|
|
75
|
+
*/
|
|
76
|
+
function persistBuildMetadata(
|
|
77
|
+
ctx: PipelineContext,
|
|
78
|
+
nodeCount: number,
|
|
79
|
+
actualEdgeCount: number,
|
|
80
|
+
buildNow: Date,
|
|
81
|
+
): void {
|
|
82
|
+
const useNativeDb = ctx.engineName === 'native' && !!ctx.nativeDb;
|
|
83
|
+
if (!ctx.isFullBuild && ctx.allSymbols.size <= 3) return;
|
|
84
|
+
try {
|
|
85
|
+
if (useNativeDb) {
|
|
86
|
+
ctx.nativeDb!.setBuildMeta(
|
|
87
|
+
Object.entries({
|
|
88
|
+
engine: ctx.engineName,
|
|
89
|
+
engine_version: ctx.engineVersion || '',
|
|
90
|
+
codegraph_version: CODEGRAPH_VERSION,
|
|
91
|
+
schema_version: String(ctx.schemaVersion),
|
|
92
|
+
built_at: buildNow.toISOString(),
|
|
93
|
+
node_count: String(nodeCount),
|
|
94
|
+
edge_count: String(actualEdgeCount),
|
|
95
|
+
}).map(([key, value]) => ({ key, value: String(value) })),
|
|
96
|
+
);
|
|
97
|
+
} else {
|
|
98
|
+
setBuildMeta(ctx.db, {
|
|
73
99
|
engine: ctx.engineName,
|
|
74
100
|
engine_version: ctx.engineVersion || '',
|
|
75
101
|
codegraph_version: CODEGRAPH_VERSION,
|
|
76
|
-
schema_version: String(schemaVersion),
|
|
102
|
+
schema_version: String(ctx.schemaVersion),
|
|
77
103
|
built_at: buildNow.toISOString(),
|
|
78
104
|
node_count: nodeCount,
|
|
79
105
|
edge_count: actualEdgeCount,
|
|
80
106
|
});
|
|
81
|
-
} catch (err) {
|
|
82
|
-
warn(`Failed to write build metadata: ${(err as Error).message}`);
|
|
83
107
|
}
|
|
108
|
+
} catch (err) {
|
|
109
|
+
warn(`Failed to write build metadata: ${(err as Error).message}`);
|
|
84
110
|
}
|
|
111
|
+
}
|
|
85
112
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
/* ignore - embeddings table may have been dropped */
|
|
113
|
+
/**
|
|
114
|
+
* Run advisory checks on full builds: orphaned embeddings, stale embeddings,
|
|
115
|
+
* and unused exports. Informational only — does not affect correctness.
|
|
116
|
+
*/
|
|
117
|
+
function runAdvisoryChecks(
|
|
118
|
+
db: PipelineContext['db'],
|
|
119
|
+
hasEmbeddings: boolean,
|
|
120
|
+
buildNow: Date,
|
|
121
|
+
): void {
|
|
122
|
+
// Orphaned embeddings warning
|
|
123
|
+
if (hasEmbeddings) {
|
|
124
|
+
try {
|
|
125
|
+
const orphaned = (
|
|
126
|
+
db
|
|
127
|
+
.prepare(
|
|
128
|
+
'SELECT COUNT(*) as c FROM embeddings WHERE node_id NOT IN (SELECT id FROM nodes)',
|
|
129
|
+
)
|
|
130
|
+
.get() as { c: number }
|
|
131
|
+
).c;
|
|
132
|
+
if (orphaned > 0) {
|
|
133
|
+
warn(
|
|
134
|
+
`${orphaned} embeddings are orphaned (nodes changed). Run "codegraph embed" to refresh.`,
|
|
135
|
+
);
|
|
110
136
|
}
|
|
137
|
+
} catch {
|
|
138
|
+
/* ignore - embeddings table may have been dropped */
|
|
111
139
|
}
|
|
140
|
+
}
|
|
112
141
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
}
|
|
142
|
+
// Stale embeddings warning (built before current graph rebuild)
|
|
143
|
+
if (hasEmbeddings) {
|
|
144
|
+
try {
|
|
145
|
+
const embedBuiltAt = (
|
|
146
|
+
db.prepare("SELECT value FROM embedding_meta WHERE key = 'built_at'").get() as
|
|
147
|
+
| { value: string }
|
|
148
|
+
| undefined
|
|
149
|
+
)?.value;
|
|
150
|
+
if (embedBuiltAt) {
|
|
151
|
+
const embedTime = new Date(embedBuiltAt).getTime();
|
|
152
|
+
if (!Number.isNaN(embedTime) && embedTime < buildNow.getTime()) {
|
|
153
|
+
warn(
|
|
154
|
+
'Embeddings were built before the last graph rebuild. Run "codegraph embed" to update.',
|
|
155
|
+
);
|
|
128
156
|
}
|
|
129
|
-
} catch {
|
|
130
|
-
/* ignore - embedding_meta table may not exist */
|
|
131
157
|
}
|
|
158
|
+
} catch {
|
|
159
|
+
/* ignore - embedding_meta table may not exist */
|
|
132
160
|
}
|
|
161
|
+
}
|
|
133
162
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
163
|
+
// Unused exports warning
|
|
164
|
+
try {
|
|
165
|
+
const unusedCount = (
|
|
166
|
+
db
|
|
167
|
+
.prepare(
|
|
168
|
+
`SELECT COUNT(*) as c FROM nodes
|
|
140
169
|
WHERE exported = 1 AND kind != 'file'
|
|
141
170
|
AND id NOT IN (
|
|
142
171
|
SELECT DISTINCT e.target_id FROM edges e
|
|
@@ -144,30 +173,65 @@ export async function finalize(ctx: PipelineContext): Promise<void> {
|
|
|
144
173
|
JOIN nodes target ON e.target_id = target.id
|
|
145
174
|
WHERE e.kind = 'calls' AND caller.file != target.file
|
|
146
175
|
)`,
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
}
|
|
155
|
-
} catch {
|
|
156
|
-
/* exported column may not exist on older DBs */
|
|
176
|
+
)
|
|
177
|
+
.get() as { c: number }
|
|
178
|
+
).c;
|
|
179
|
+
if (unusedCount > 0) {
|
|
180
|
+
warn(
|
|
181
|
+
`${unusedCount} exported symbol${unusedCount > 1 ? 's have' : ' has'} zero cross-file consumers. Run "codegraph exports <file> --unused" to inspect.`,
|
|
182
|
+
);
|
|
157
183
|
}
|
|
184
|
+
} catch {
|
|
185
|
+
/* exported column may not exist on older DBs */
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
export async function finalize(ctx: PipelineContext): Promise<void> {
|
|
190
|
+
const { allSymbols, rootDir, isFullBuild, hasEmbeddings, opts } = ctx;
|
|
191
|
+
|
|
192
|
+
const t0 = performance.now();
|
|
193
|
+
|
|
194
|
+
releaseWasmTrees(allSymbols);
|
|
195
|
+
|
|
196
|
+
// Capture a single wall-clock timestamp for the current build — used for
|
|
197
|
+
// both the stale-embeddings comparison and the persisted built_at metadata.
|
|
198
|
+
const buildNow = new Date();
|
|
199
|
+
|
|
200
|
+
const nodeCount = (ctx.db.prepare('SELECT COUNT(*) as c FROM nodes').get() as { c: number }).c;
|
|
201
|
+
const actualEdgeCount = (ctx.db.prepare('SELECT COUNT(*) as c FROM edges').get() as { c: number })
|
|
202
|
+
.c;
|
|
203
|
+
info(`Graph built: ${nodeCount} nodes, ${actualEdgeCount} edges`);
|
|
204
|
+
info(`Stored in ${ctx.dbPath}`);
|
|
205
|
+
|
|
206
|
+
detectIncrementalDrift(ctx, nodeCount, actualEdgeCount);
|
|
207
|
+
persistBuildMetadata(ctx, nodeCount, actualEdgeCount, buildNow);
|
|
208
|
+
|
|
209
|
+
// Skip expensive advisory queries for incremental builds — these are
|
|
210
|
+
// informational warnings that don't affect correctness and cost ~40-60ms.
|
|
211
|
+
if (!isFullBuild) {
|
|
212
|
+
debug(
|
|
213
|
+
'Finalize: skipping advisory queries (orphaned/stale embeddings, unused exports) for incremental build',
|
|
214
|
+
);
|
|
215
|
+
} else {
|
|
216
|
+
runAdvisoryChecks(ctx.db, hasEmbeddings, buildNow);
|
|
158
217
|
}
|
|
159
218
|
|
|
219
|
+
// Intentionally measured before closeDb / writeJournalHeader / auto-registration:
|
|
220
|
+
// for the deferred-close path the close is async (setImmediate), and for full
|
|
221
|
+
// builds the metric captures finalize logic only — DB close cost is tracked
|
|
222
|
+
// separately via timing.closeDbMs when available.
|
|
160
223
|
ctx.timing.finalizeMs = performance.now() - t0;
|
|
161
224
|
|
|
162
|
-
//
|
|
163
|
-
//
|
|
164
|
-
//
|
|
165
|
-
//
|
|
225
|
+
// Close NativeDatabase (fast, ~1ms) then better-sqlite3 (WAL checkpoint).
|
|
226
|
+
// For small incremental builds, defer the expensive WAL checkpoint to the
|
|
227
|
+
// next event loop tick. Skip for temp directories (tests) — they rmSync
|
|
228
|
+
// immediately after build.
|
|
229
|
+
const pair = { db: ctx.db, nativeDb: ctx.nativeDb };
|
|
166
230
|
const isTempDir = path.resolve(rootDir).startsWith(path.resolve(tmpdir()));
|
|
167
231
|
if (!isFullBuild && allSymbols.size <= 5 && !isTempDir) {
|
|
168
|
-
|
|
232
|
+
closeDbPairDeferred(pair);
|
|
169
233
|
} else {
|
|
170
|
-
|
|
234
|
+
closeDbPair(pair);
|
|
171
235
|
}
|
|
172
236
|
|
|
173
237
|
// Write journal header after successful build
|
|
@@ -177,7 +241,6 @@ export async function finalize(ctx: PipelineContext): Promise<void> {
|
|
|
177
241
|
// registered during the initial full build. The dynamic import + file I/O
|
|
178
242
|
// costs ~100ms which dominates incremental finalize time.
|
|
179
243
|
if (!opts.skipRegistry && isFullBuild) {
|
|
180
|
-
const { tmpdir } = await import('node:os');
|
|
181
244
|
const tmpDir = path.resolve(tmpdir());
|
|
182
245
|
const resolvedRoot = path.resolve(rootDir);
|
|
183
246
|
if (resolvedRoot.startsWith(tmpDir)) {
|