@jafreck/lore 0.1.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/LICENSE +21 -0
- package/README.md +405 -0
- package/dist/cli.d.ts +19 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +345 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/indexer/call-graph.d.ts +39 -0
- package/dist/indexer/call-graph.d.ts.map +1 -0
- package/dist/indexer/call-graph.js +193 -0
- package/dist/indexer/call-graph.js.map +1 -0
- package/dist/indexer/complexity.d.ts +9 -0
- package/dist/indexer/complexity.d.ts.map +1 -0
- package/dist/indexer/complexity.js +66 -0
- package/dist/indexer/complexity.js.map +1 -0
- package/dist/indexer/config-parser.d.ts +16 -0
- package/dist/indexer/config-parser.d.ts.map +1 -0
- package/dist/indexer/config-parser.js +261 -0
- package/dist/indexer/config-parser.js.map +1 -0
- package/dist/indexer/coverage.d.ts +13 -0
- package/dist/indexer/coverage.d.ts.map +1 -0
- package/dist/indexer/coverage.js +84 -0
- package/dist/indexer/coverage.js.map +1 -0
- package/dist/indexer/db.d.ts +38 -0
- package/dist/indexer/db.d.ts.map +1 -0
- package/dist/indexer/db.js +275 -0
- package/dist/indexer/db.js.map +1 -0
- package/dist/indexer/embedder.d.ts +70 -0
- package/dist/indexer/embedder.d.ts.map +1 -0
- package/dist/indexer/embedder.js +186 -0
- package/dist/indexer/embedder.js.map +1 -0
- package/dist/indexer/ensure-python-deps.d.ts +22 -0
- package/dist/indexer/ensure-python-deps.d.ts.map +1 -0
- package/dist/indexer/ensure-python-deps.js +47 -0
- package/dist/indexer/ensure-python-deps.js.map +1 -0
- package/dist/indexer/extractors/bash.d.ts +12 -0
- package/dist/indexer/extractors/bash.d.ts.map +1 -0
- package/dist/indexer/extractors/bash.js +57 -0
- package/dist/indexer/extractors/bash.js.map +1 -0
- package/dist/indexer/extractors/c.d.ts +12 -0
- package/dist/indexer/extractors/c.d.ts.map +1 -0
- package/dist/indexer/extractors/c.js +106 -0
- package/dist/indexer/extractors/c.js.map +1 -0
- package/dist/indexer/extractors/cpp.d.ts +12 -0
- package/dist/indexer/extractors/cpp.d.ts.map +1 -0
- package/dist/indexer/extractors/cpp.js +84 -0
- package/dist/indexer/extractors/cpp.js.map +1 -0
- package/dist/indexer/extractors/csharp.d.ts +12 -0
- package/dist/indexer/extractors/csharp.d.ts.map +1 -0
- package/dist/indexer/extractors/csharp.js +79 -0
- package/dist/indexer/extractors/csharp.js.map +1 -0
- package/dist/indexer/extractors/dart.d.ts +12 -0
- package/dist/indexer/extractors/dart.d.ts.map +1 -0
- package/dist/indexer/extractors/dart.js +80 -0
- package/dist/indexer/extractors/dart.js.map +1 -0
- package/dist/indexer/extractors/elixir.d.ts +12 -0
- package/dist/indexer/extractors/elixir.d.ts.map +1 -0
- package/dist/indexer/extractors/elixir.js +87 -0
- package/dist/indexer/extractors/elixir.js.map +1 -0
- package/dist/indexer/extractors/elm.d.ts +12 -0
- package/dist/indexer/extractors/elm.d.ts.map +1 -0
- package/dist/indexer/extractors/elm.js +87 -0
- package/dist/indexer/extractors/elm.js.map +1 -0
- package/dist/indexer/extractors/go.d.ts +12 -0
- package/dist/indexer/extractors/go.d.ts.map +1 -0
- package/dist/indexer/extractors/go.js +158 -0
- package/dist/indexer/extractors/go.js.map +1 -0
- package/dist/indexer/extractors/haskell.d.ts +12 -0
- package/dist/indexer/extractors/haskell.d.ts.map +1 -0
- package/dist/indexer/extractors/haskell.js +104 -0
- package/dist/indexer/extractors/haskell.js.map +1 -0
- package/dist/indexer/extractors/java.d.ts +12 -0
- package/dist/indexer/extractors/java.d.ts.map +1 -0
- package/dist/indexer/extractors/java.js +68 -0
- package/dist/indexer/extractors/java.js.map +1 -0
- package/dist/indexer/extractors/javascript.d.ts +13 -0
- package/dist/indexer/extractors/javascript.d.ts.map +1 -0
- package/dist/indexer/extractors/javascript.js +180 -0
- package/dist/indexer/extractors/javascript.js.map +1 -0
- package/dist/indexer/extractors/julia.d.ts +12 -0
- package/dist/indexer/extractors/julia.d.ts.map +1 -0
- package/dist/indexer/extractors/julia.js +94 -0
- package/dist/indexer/extractors/julia.js.map +1 -0
- package/dist/indexer/extractors/kotlin.d.ts +12 -0
- package/dist/indexer/extractors/kotlin.d.ts.map +1 -0
- package/dist/indexer/extractors/kotlin.js +71 -0
- package/dist/indexer/extractors/kotlin.js.map +1 -0
- package/dist/indexer/extractors/lua.d.ts +12 -0
- package/dist/indexer/extractors/lua.d.ts.map +1 -0
- package/dist/indexer/extractors/lua.js +68 -0
- package/dist/indexer/extractors/lua.js.map +1 -0
- package/dist/indexer/extractors/objc.d.ts +12 -0
- package/dist/indexer/extractors/objc.d.ts.map +1 -0
- package/dist/indexer/extractors/objc.js +129 -0
- package/dist/indexer/extractors/objc.js.map +1 -0
- package/dist/indexer/extractors/ocaml.d.ts +12 -0
- package/dist/indexer/extractors/ocaml.d.ts.map +1 -0
- package/dist/indexer/extractors/ocaml.js +92 -0
- package/dist/indexer/extractors/ocaml.js.map +1 -0
- package/dist/indexer/extractors/php.d.ts +12 -0
- package/dist/indexer/extractors/php.d.ts.map +1 -0
- package/dist/indexer/extractors/php.js +99 -0
- package/dist/indexer/extractors/php.js.map +1 -0
- package/dist/indexer/extractors/python.d.ts +12 -0
- package/dist/indexer/extractors/python.d.ts.map +1 -0
- package/dist/indexer/extractors/python.js +129 -0
- package/dist/indexer/extractors/python.js.map +1 -0
- package/dist/indexer/extractors/ruby.d.ts +12 -0
- package/dist/indexer/extractors/ruby.d.ts.map +1 -0
- package/dist/indexer/extractors/ruby.js +100 -0
- package/dist/indexer/extractors/ruby.js.map +1 -0
- package/dist/indexer/extractors/rust.d.ts +12 -0
- package/dist/indexer/extractors/rust.d.ts.map +1 -0
- package/dist/indexer/extractors/rust.js +82 -0
- package/dist/indexer/extractors/rust.js.map +1 -0
- package/dist/indexer/extractors/scala.d.ts +12 -0
- package/dist/indexer/extractors/scala.d.ts.map +1 -0
- package/dist/indexer/extractors/scala.js +91 -0
- package/dist/indexer/extractors/scala.js.map +1 -0
- package/dist/indexer/extractors/swift.d.ts +12 -0
- package/dist/indexer/extractors/swift.d.ts.map +1 -0
- package/dist/indexer/extractors/swift.js +90 -0
- package/dist/indexer/extractors/swift.js.map +1 -0
- package/dist/indexer/extractors/types.d.ts +118 -0
- package/dist/indexer/extractors/types.d.ts.map +1 -0
- package/dist/indexer/extractors/types.js +43 -0
- package/dist/indexer/extractors/types.js.map +1 -0
- package/dist/indexer/extractors/typescript.d.ts +14 -0
- package/dist/indexer/extractors/typescript.d.ts.map +1 -0
- package/dist/indexer/extractors/typescript.js +172 -0
- package/dist/indexer/extractors/typescript.js.map +1 -0
- package/dist/indexer/extractors/zig.d.ts +12 -0
- package/dist/indexer/extractors/zig.d.ts.map +1 -0
- package/dist/indexer/extractors/zig.js +95 -0
- package/dist/indexer/extractors/zig.js.map +1 -0
- package/dist/indexer/git-history.d.ts +23 -0
- package/dist/indexer/git-history.d.ts.map +1 -0
- package/dist/indexer/git-history.js +144 -0
- package/dist/indexer/git-history.js.map +1 -0
- package/dist/indexer/git-hooks.d.ts +19 -0
- package/dist/indexer/git-hooks.d.ts.map +1 -0
- package/dist/indexer/git-hooks.js +74 -0
- package/dist/indexer/git-hooks.js.map +1 -0
- package/dist/indexer/index.d.ts +83 -0
- package/dist/indexer/index.d.ts.map +1 -0
- package/dist/indexer/index.js +431 -0
- package/dist/indexer/index.js.map +1 -0
- package/dist/indexer/parser.d.ts +30 -0
- package/dist/indexer/parser.d.ts.map +1 -0
- package/dist/indexer/parser.js +114 -0
- package/dist/indexer/parser.js.map +1 -0
- package/dist/indexer/poller.d.ts +50 -0
- package/dist/indexer/poller.d.ts.map +1 -0
- package/dist/indexer/poller.js +140 -0
- package/dist/indexer/poller.js.map +1 -0
- package/dist/indexer/resolver.d.ts +52 -0
- package/dist/indexer/resolver.d.ts.map +1 -0
- package/dist/indexer/resolver.js +271 -0
- package/dist/indexer/resolver.js.map +1 -0
- package/dist/indexer/test-mapper.d.ts +6 -0
- package/dist/indexer/test-mapper.d.ts.map +1 -0
- package/dist/indexer/test-mapper.js +48 -0
- package/dist/indexer/test-mapper.js.map +1 -0
- package/dist/indexer/walker.d.ts +51 -0
- package/dist/indexer/walker.d.ts.map +1 -0
- package/dist/indexer/walker.js +100 -0
- package/dist/indexer/walker.js.map +1 -0
- package/dist/indexer/watcher.d.ts +51 -0
- package/dist/indexer/watcher.d.ts.map +1 -0
- package/dist/indexer/watcher.js +107 -0
- package/dist/indexer/watcher.js.map +1 -0
- package/dist/kb-server/db.d.ts +241 -0
- package/dist/kb-server/db.d.ts.map +1 -0
- package/dist/kb-server/db.js +659 -0
- package/dist/kb-server/db.js.map +1 -0
- package/dist/kb-server/server.d.ts +35 -0
- package/dist/kb-server/server.d.ts.map +1 -0
- package/dist/kb-server/server.js +240 -0
- package/dist/kb-server/server.js.map +1 -0
- package/dist/kb-server/tools/annotations.d.ts +40 -0
- package/dist/kb-server/tools/annotations.d.ts.map +1 -0
- package/dist/kb-server/tools/annotations.js +35 -0
- package/dist/kb-server/tools/annotations.js.map +1 -0
- package/dist/kb-server/tools/architecture.d.ts +60 -0
- package/dist/kb-server/tools/architecture.d.ts.map +1 -0
- package/dist/kb-server/tools/architecture.js +174 -0
- package/dist/kb-server/tools/architecture.js.map +1 -0
- package/dist/kb-server/tools/blame.d.ts +67 -0
- package/dist/kb-server/tools/blame.d.ts.map +1 -0
- package/dist/kb-server/tools/blame.js +162 -0
- package/dist/kb-server/tools/blame.js.map +1 -0
- package/dist/kb-server/tools/coverage.d.ts +67 -0
- package/dist/kb-server/tools/coverage.d.ts.map +1 -0
- package/dist/kb-server/tools/coverage.js +74 -0
- package/dist/kb-server/tools/coverage.js.map +1 -0
- package/dist/kb-server/tools/graph.d.ts +56 -0
- package/dist/kb-server/tools/graph.d.ts.map +1 -0
- package/dist/kb-server/tools/graph.js +188 -0
- package/dist/kb-server/tools/graph.js.map +1 -0
- package/dist/kb-server/tools/history.d.ts +47 -0
- package/dist/kb-server/tools/history.d.ts.map +1 -0
- package/dist/kb-server/tools/history.js +91 -0
- package/dist/kb-server/tools/history.js.map +1 -0
- package/dist/kb-server/tools/lookup.d.ts +36 -0
- package/dist/kb-server/tools/lookup.d.ts.map +1 -0
- package/dist/kb-server/tools/lookup.js +45 -0
- package/dist/kb-server/tools/lookup.js.map +1 -0
- package/dist/kb-server/tools/metrics.d.ts +73 -0
- package/dist/kb-server/tools/metrics.d.ts.map +1 -0
- package/dist/kb-server/tools/metrics.js +79 -0
- package/dist/kb-server/tools/metrics.js.map +1 -0
- package/dist/kb-server/tools/notes.d.ts +165 -0
- package/dist/kb-server/tools/notes.d.ts.map +1 -0
- package/dist/kb-server/tools/notes.js +175 -0
- package/dist/kb-server/tools/notes.js.map +1 -0
- package/dist/kb-server/tools/routes.d.ts +38 -0
- package/dist/kb-server/tools/routes.d.ts.map +1 -0
- package/dist/kb-server/tools/routes.js +38 -0
- package/dist/kb-server/tools/routes.js.map +1 -0
- package/dist/kb-server/tools/search.d.ts +60 -0
- package/dist/kb-server/tools/search.d.ts.map +1 -0
- package/dist/kb-server/tools/search.js +170 -0
- package/dist/kb-server/tools/search.js.map +1 -0
- package/dist/kb-server/tools/snippet.d.ts +44 -0
- package/dist/kb-server/tools/snippet.d.ts.map +1 -0
- package/dist/kb-server/tools/snippet.js +49 -0
- package/dist/kb-server/tools/snippet.js.map +1 -0
- package/dist/kb-server/tools/test-map.d.ts +38 -0
- package/dist/kb-server/tools/test-map.d.ts.map +1 -0
- package/dist/kb-server/tools/test-map.js +32 -0
- package/dist/kb-server/tools/test-map.js.map +1 -0
- package/dist/kb-server/tools/writeback.d.ts +49 -0
- package/dist/kb-server/tools/writeback.d.ts.map +1 -0
- package/dist/kb-server/tools/writeback.js +68 -0
- package/dist/kb-server/tools/writeback.js.map +1 -0
- package/package.json +92 -0
package/dist/cli.js
ADDED
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* @module cli
|
|
4
|
+
*
|
|
5
|
+
* Lore CLI — unified entry point for indexing and the MCP server.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* lore index --root <dir> --db <path> [--embedding-model <id>]
|
|
9
|
+
* Index a codebase into a knowledge-base file.
|
|
10
|
+
* lore mcp --db <path> Start the knowledge-base MCP server (stdio transport).
|
|
11
|
+
* lore refresh --db <path> --root <dir> Run an incremental index update and exit.
|
|
12
|
+
* lore refresh --db <path> --root <dir> --watch Watch for changes and refresh automatically.
|
|
13
|
+
* lore refresh --db <path> --root <dir> --poll Poll for changes and refresh automatically.
|
|
14
|
+
* lore hooks --root <dir> --db <path> Install git hooks for automatic Lore refresh.
|
|
15
|
+
* lore ingest-coverage --db <path> --root <dir> --file <path> --format <lcov|cobertura>
|
|
16
|
+
* Ingest a coverage report file into the knowledge base.
|
|
17
|
+
*/
|
|
18
|
+
import * as fs from 'node:fs';
|
|
19
|
+
// ─── Argument helpers ─────────────────────────────────────────────────────────
|
|
20
|
+
function usage() {
|
|
21
|
+
console.error(`Usage:
|
|
22
|
+
lore index --root <dir> --db <path> [--embedding-model <id>] [--history] [--history-depth <n>] [--history-all]
|
|
23
|
+
Index a codebase into a knowledge-base SQLite file
|
|
24
|
+
lore mcp --db <path> Start the KB MCP server (stdio transport)
|
|
25
|
+
lore refresh --db <path> --root <dir> [--history] [--history-depth <n>] [--history-all] Run an incremental index update and exit
|
|
26
|
+
lore refresh --db <path> --root <dir> --watch Watch for file changes and refresh automatically
|
|
27
|
+
lore refresh --db <path> --root <dir> --poll Poll for file changes and refresh automatically
|
|
28
|
+
lore hooks --db <path> --root <dir> [--history] [--history-depth <n>] [--history-all]
|
|
29
|
+
Install git hooks for automatic refresh on commit/merge/checkout
|
|
30
|
+
lore ingest-coverage --db <path> --root <dir> --file <path> --format <lcov|cobertura> [--commit <sha>]
|
|
31
|
+
Ingest an explicit coverage report file into the knowledge base
|
|
32
|
+
|
|
33
|
+
Options:
|
|
34
|
+
--root <dir> Root directory to index (required for index, refresh)
|
|
35
|
+
--db <path> Path to a Lore knowledge-base SQLite file (required for index, mcp, refresh)
|
|
36
|
+
--embedding-model <id> Embedding model identifier (default: Qwen/Qwen3-Embedding-4B)
|
|
37
|
+
--history Enable git history ingestion
|
|
38
|
+
--history-depth <n> Limit commit ingestion to the most recent N commits
|
|
39
|
+
--history-all Traverse all refs (branches/tags) for history ingestion
|
|
40
|
+
--include <glob> Glob pattern for files to include (repeatable)
|
|
41
|
+
--exclude <glob> Glob pattern for paths to exclude (repeatable)
|
|
42
|
+
--language <lang> Language name to filter by, e.g. typescript (repeatable)
|
|
43
|
+
--watch Enable fs-event watch mode (low-latency, may miss events on some platforms)
|
|
44
|
+
--poll Enable polling mode (reliable but higher CPU/IO cost)
|
|
45
|
+
--file <path> Coverage report path (required for ingest-coverage)
|
|
46
|
+
--format <name> Coverage format: lcov or cobertura (required for ingest-coverage)
|
|
47
|
+
--commit <sha> Commit SHA to associate with coverage ingestion (default: HEAD)
|
|
48
|
+
--help, -h Show this help message`);
|
|
49
|
+
process.exit(1);
|
|
50
|
+
}
|
|
51
|
+
function flag(args, name) {
|
|
52
|
+
const idx = args.indexOf(name);
|
|
53
|
+
if (idx === -1)
|
|
54
|
+
return undefined;
|
|
55
|
+
return args[idx + 1];
|
|
56
|
+
}
|
|
57
|
+
/** Returns all values provided for a repeatable flag (e.g. --include a --include b → ['a', 'b']). */
|
|
58
|
+
function flags(args, name) {
|
|
59
|
+
const results = [];
|
|
60
|
+
for (let i = 0; i < args.length - 1; i++) {
|
|
61
|
+
if (args[i] === name)
|
|
62
|
+
results.push(args[i + 1]);
|
|
63
|
+
}
|
|
64
|
+
return results;
|
|
65
|
+
}
|
|
66
|
+
// ─── Main ─────────────────────────────────────────────────────────────────────
|
|
67
|
+
async function main() {
|
|
68
|
+
const args = process.argv.slice(2);
|
|
69
|
+
if (args.includes('--help') || args.includes('-h') || args.length === 0) {
|
|
70
|
+
usage();
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
const subcommand = args[0];
|
|
74
|
+
if (subcommand === 'index') {
|
|
75
|
+
const rootDir = flag(args, '--root');
|
|
76
|
+
const dbPath = flag(args, '--db');
|
|
77
|
+
if (!rootDir) {
|
|
78
|
+
console.error('Error: --root <dir> is required for the index subcommand.\n');
|
|
79
|
+
usage();
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
if (!dbPath) {
|
|
83
|
+
console.error('Error: --db <path> is required for the index subcommand.\n');
|
|
84
|
+
usage();
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const embeddingModel = flag(args, '--embedding-model');
|
|
88
|
+
const historyEnabled = args.includes('--history');
|
|
89
|
+
const historyAll = args.includes('--history-all');
|
|
90
|
+
const historyDepthRaw = flag(args, '--history-depth');
|
|
91
|
+
let historyDepth;
|
|
92
|
+
if (historyDepthRaw !== undefined) {
|
|
93
|
+
const parsed = Number(historyDepthRaw);
|
|
94
|
+
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
95
|
+
console.error('Error: --history-depth must be a positive number.\n');
|
|
96
|
+
usage();
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
historyDepth = Math.floor(parsed);
|
|
100
|
+
}
|
|
101
|
+
const includeGlobs = flags(args, '--include');
|
|
102
|
+
const excludeGlobs = flags(args, '--exclude');
|
|
103
|
+
const languageNames = flags(args, '--language');
|
|
104
|
+
// Static reverse map: language name → extensions (mirrors EXT_TO_LANG in walker.ts)
|
|
105
|
+
const LANG_TO_EXTS = {
|
|
106
|
+
c: ['.c', '.h'],
|
|
107
|
+
rust: ['.rs'],
|
|
108
|
+
python: ['.py'],
|
|
109
|
+
cpp: ['.cpp', '.cc', '.cxx', '.hpp', '.hxx'],
|
|
110
|
+
typescript: ['.ts', '.tsx'],
|
|
111
|
+
javascript: ['.js', '.jsx', '.mjs', '.cjs'],
|
|
112
|
+
go: ['.go'],
|
|
113
|
+
java: ['.java'],
|
|
114
|
+
csharp: ['.cs'],
|
|
115
|
+
ruby: ['.rb'],
|
|
116
|
+
php: ['.php'],
|
|
117
|
+
swift: ['.swift'],
|
|
118
|
+
kotlin: ['.kt', '.kts'],
|
|
119
|
+
scala: ['.scala', '.sc'],
|
|
120
|
+
lua: ['.lua'],
|
|
121
|
+
bash: ['.sh', '.bash', '.zsh'],
|
|
122
|
+
elixir: ['.ex', '.exs'],
|
|
123
|
+
zig: ['.zig'],
|
|
124
|
+
dart: ['.dart'],
|
|
125
|
+
ocaml: ['.ml', '.mli'],
|
|
126
|
+
haskell: ['.hs'],
|
|
127
|
+
julia: ['.jl'],
|
|
128
|
+
elm: ['.elm'],
|
|
129
|
+
objc: ['.m', '.mm'],
|
|
130
|
+
};
|
|
131
|
+
// Resolve --language names to extensions
|
|
132
|
+
let extensions;
|
|
133
|
+
if (languageNames.length > 0) {
|
|
134
|
+
extensions = [];
|
|
135
|
+
for (const lang of languageNames) {
|
|
136
|
+
const exts = LANG_TO_EXTS[lang];
|
|
137
|
+
if (!exts) {
|
|
138
|
+
console.error(`Error: unknown language "${lang}". Known languages: ${Object.keys(LANG_TO_EXTS).sort().join(', ')}\n`);
|
|
139
|
+
process.exit(1);
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
extensions.push(...exts);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
const { IndexBuilder } = await import('./indexer/index.js');
|
|
146
|
+
const shouldEnableHistory = historyEnabled || historyAll || historyDepth !== undefined;
|
|
147
|
+
const options = {
|
|
148
|
+
...(embeddingModel && { embeddingModel }),
|
|
149
|
+
...(shouldEnableHistory && {
|
|
150
|
+
history: {
|
|
151
|
+
...(historyDepth !== undefined && { depth: historyDepth }),
|
|
152
|
+
...(historyAll && { all: true }),
|
|
153
|
+
},
|
|
154
|
+
}),
|
|
155
|
+
};
|
|
156
|
+
const builder = new IndexBuilder(dbPath, {
|
|
157
|
+
rootDir,
|
|
158
|
+
...(includeGlobs.length > 0 && { includeGlobs }),
|
|
159
|
+
...(excludeGlobs.length > 0 && { excludeGlobs }),
|
|
160
|
+
...(extensions && { extensions }),
|
|
161
|
+
}, undefined, Object.keys(options).length > 0 ? options : undefined);
|
|
162
|
+
await builder.build();
|
|
163
|
+
}
|
|
164
|
+
else if (subcommand === 'mcp') {
|
|
165
|
+
const dbPath = flag(args, '--db');
|
|
166
|
+
if (!dbPath) {
|
|
167
|
+
console.error('Error: --db <path> is required for the mcp subcommand.\n');
|
|
168
|
+
usage();
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
// Dynamically import so tree-shaking keeps the MCP server out of the
|
|
172
|
+
// library entry point for consumers who only need the indexer.
|
|
173
|
+
const { McpServer } = await import('@modelcontextprotocol/sdk/server/mcp.js');
|
|
174
|
+
const { StdioServerTransport } = await import('@modelcontextprotocol/sdk/server/stdio.js');
|
|
175
|
+
const { openReadOnly } = await import('./kb-server/db.js');
|
|
176
|
+
const { createKbMcpServer } = await import('./kb-server/server.js');
|
|
177
|
+
const { getKbMeta } = await import('./indexer/db.js');
|
|
178
|
+
const { SentenceTransformersProvider, } = await import('./indexer/embedder.js');
|
|
179
|
+
const db = openReadOnly(dbPath);
|
|
180
|
+
// Build optional embedder from model recorded at index time.
|
|
181
|
+
let embedder;
|
|
182
|
+
const modelName = getKbMeta(db, 'embedding_model');
|
|
183
|
+
if (modelName) {
|
|
184
|
+
const provider = new SentenceTransformersProvider(modelName);
|
|
185
|
+
try {
|
|
186
|
+
await provider.init();
|
|
187
|
+
embedder = provider;
|
|
188
|
+
}
|
|
189
|
+
catch {
|
|
190
|
+
try {
|
|
191
|
+
await provider.dispose();
|
|
192
|
+
}
|
|
193
|
+
catch {
|
|
194
|
+
/* ignore */
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
const server = createKbMcpServer(db, dbPath, embedder);
|
|
199
|
+
const transport = new StdioServerTransport();
|
|
200
|
+
await server.connect(transport);
|
|
201
|
+
// Signal readiness on stderr so parent processes can detect it.
|
|
202
|
+
process.stderr.write('READY\n');
|
|
203
|
+
}
|
|
204
|
+
else if (subcommand === 'refresh') {
|
|
205
|
+
const dbPath = flag(args, '--db');
|
|
206
|
+
const rootDir = flag(args, '--root');
|
|
207
|
+
if (!dbPath || !rootDir) {
|
|
208
|
+
console.error('Error: --db <path> and --root <dir> are required for the refresh subcommand.\n');
|
|
209
|
+
usage();
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
const watchMode = args.includes('--watch');
|
|
213
|
+
const pollMode = args.includes('--poll');
|
|
214
|
+
const historyEnabled = args.includes('--history');
|
|
215
|
+
const historyAll = args.includes('--history-all');
|
|
216
|
+
const historyDepthRaw = flag(args, '--history-depth');
|
|
217
|
+
let historyDepth;
|
|
218
|
+
if (historyDepthRaw !== undefined) {
|
|
219
|
+
const parsed = Number(historyDepthRaw);
|
|
220
|
+
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
221
|
+
console.error('Error: --history-depth must be a positive number.\n');
|
|
222
|
+
usage();
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
historyDepth = Math.floor(parsed);
|
|
226
|
+
}
|
|
227
|
+
const shouldEnableHistory = historyEnabled || historyAll || historyDepth !== undefined;
|
|
228
|
+
const historyOption = shouldEnableHistory
|
|
229
|
+
? {
|
|
230
|
+
...(historyDepth !== undefined && { depth: historyDepth }),
|
|
231
|
+
...(historyAll && { all: true }),
|
|
232
|
+
}
|
|
233
|
+
: false;
|
|
234
|
+
const walkerConfig = { rootDir };
|
|
235
|
+
if (watchMode) {
|
|
236
|
+
const { FileWatcher } = await import('./indexer/watcher.js');
|
|
237
|
+
const watcher = new FileWatcher(dbPath, walkerConfig, {
|
|
238
|
+
history: historyOption,
|
|
239
|
+
});
|
|
240
|
+
watcher.start();
|
|
241
|
+
process.stderr.write(JSON.stringify({ level: 'info', source: 'cli', message: 'watch mode started', rootDir }) + '\n');
|
|
242
|
+
// Keep the process alive until interrupted
|
|
243
|
+
process.on('SIGINT', () => { watcher.stop(); process.exit(0); });
|
|
244
|
+
process.on('SIGTERM', () => { watcher.stop(); process.exit(0); });
|
|
245
|
+
}
|
|
246
|
+
else if (pollMode) {
|
|
247
|
+
const { FilePoller } = await import('./indexer/poller.js');
|
|
248
|
+
const poller = new FilePoller(dbPath, walkerConfig, {
|
|
249
|
+
history: historyOption,
|
|
250
|
+
});
|
|
251
|
+
poller.start();
|
|
252
|
+
process.stderr.write(JSON.stringify({ level: 'info', source: 'cli', message: 'poll mode started', rootDir }) + '\n');
|
|
253
|
+
// Keep the process alive until interrupted
|
|
254
|
+
process.on('SIGINT', () => { poller.stop(); process.exit(0); });
|
|
255
|
+
process.on('SIGTERM', () => { poller.stop(); process.exit(0); });
|
|
256
|
+
}
|
|
257
|
+
else {
|
|
258
|
+
// Manual refresh: full build if DB doesn't exist yet, otherwise incremental update
|
|
259
|
+
const { IndexBuilder } = await import('./indexer/index.js');
|
|
260
|
+
const builder = new IndexBuilder(dbPath, walkerConfig, undefined, {
|
|
261
|
+
...(shouldEnableHistory && { history: historyOption }),
|
|
262
|
+
});
|
|
263
|
+
const dbExists = fs.existsSync(dbPath);
|
|
264
|
+
if (dbExists) {
|
|
265
|
+
const [{ openDb }, { walkFiles }] = await Promise.all([
|
|
266
|
+
import('./indexer/db.js'),
|
|
267
|
+
import('./indexer/walker.js'),
|
|
268
|
+
]);
|
|
269
|
+
const files = await walkFiles(walkerConfig);
|
|
270
|
+
const db = openDb(dbPath);
|
|
271
|
+
const branch = 'HEAD';
|
|
272
|
+
let indexedPaths;
|
|
273
|
+
try {
|
|
274
|
+
indexedPaths = db.prepare('SELECT path FROM files WHERE branch = ?').all(branch).map((row) => row.path);
|
|
275
|
+
}
|
|
276
|
+
finally {
|
|
277
|
+
db.close();
|
|
278
|
+
}
|
|
279
|
+
const changedPaths = [...new Set([...files.map(f => f.path), ...indexedPaths])];
|
|
280
|
+
await builder.update(changedPaths);
|
|
281
|
+
}
|
|
282
|
+
else {
|
|
283
|
+
await builder.build();
|
|
284
|
+
}
|
|
285
|
+
process.stderr.write(JSON.stringify({ level: 'info', source: 'cli', message: 'refresh complete', rootDir }) + '\n');
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
else if (subcommand === 'hooks') {
|
|
289
|
+
const dbPath = flag(args, '--db');
|
|
290
|
+
const rootDir = flag(args, '--root');
|
|
291
|
+
if (!dbPath || !rootDir) {
|
|
292
|
+
console.error('Error: --db <path> and --root <dir> are required for the hooks subcommand.\n');
|
|
293
|
+
usage();
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
const historyEnabled = args.includes('--history');
|
|
297
|
+
const historyAll = args.includes('--history-all');
|
|
298
|
+
const historyDepthRaw = flag(args, '--history-depth');
|
|
299
|
+
const includeHistory = historyEnabled || historyAll || historyDepthRaw !== undefined;
|
|
300
|
+
const { installGitHooks } = await import('./indexer/git-hooks.js');
|
|
301
|
+
const result = installGitHooks({
|
|
302
|
+
repoRoot: rootDir,
|
|
303
|
+
rootDir,
|
|
304
|
+
dbPath,
|
|
305
|
+
includeHistory,
|
|
306
|
+
});
|
|
307
|
+
process.stderr.write(JSON.stringify({
|
|
308
|
+
level: 'info',
|
|
309
|
+
source: 'cli',
|
|
310
|
+
message: 'git hooks installed',
|
|
311
|
+
rootDir,
|
|
312
|
+
hooks: result.installed,
|
|
313
|
+
}) + '\n');
|
|
314
|
+
}
|
|
315
|
+
else if (subcommand === 'ingest-coverage') {
|
|
316
|
+
const dbPath = flag(args, '--db');
|
|
317
|
+
const rootDir = flag(args, '--root');
|
|
318
|
+
const reportPath = flag(args, '--file');
|
|
319
|
+
const format = flag(args, '--format');
|
|
320
|
+
const commitSha = flag(args, '--commit');
|
|
321
|
+
if (!dbPath || !rootDir || !reportPath || !format) {
|
|
322
|
+
console.error('Error: --db <path>, --root <dir>, --file <path>, and --format <lcov|cobertura> are required for the ingest-coverage subcommand.\n');
|
|
323
|
+
usage();
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
if (format !== 'lcov' && format !== 'cobertura') {
|
|
327
|
+
console.error(`Error: unsupported coverage format "${format}". Use "lcov" or "cobertura".\n`);
|
|
328
|
+
usage();
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
const { IndexBuilder } = await import('./indexer/index.js');
|
|
332
|
+
const builder = new IndexBuilder(dbPath, { rootDir });
|
|
333
|
+
await builder.ingestCoverage(reportPath, format, commitSha);
|
|
334
|
+
}
|
|
335
|
+
else {
|
|
336
|
+
console.error(`Unknown subcommand: ${subcommand}\n`);
|
|
337
|
+
usage();
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
main().catch((err) => {
|
|
342
|
+
console.error('lore: fatal error:', err);
|
|
343
|
+
process.exit(1);
|
|
344
|
+
});
|
|
345
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export { IndexBuilder } from './indexer/index.js';
|
|
2
|
+
export { openDb, setKbMeta, getKbMeta, createVec0Tables } from './indexer/db.js';
|
|
3
|
+
export type { Database } from './indexer/db.js';
|
|
4
|
+
export { buildCallGraph, topoSort, detectCycles } from './indexer/call-graph.js';
|
|
5
|
+
export { walkFiles, detectLanguageForPath } from './indexer/walker.js';
|
|
6
|
+
export type { WalkerConfig, FileEntry } from './indexer/walker.js';
|
|
7
|
+
export { ImportResolver } from './indexer/resolver.js';
|
|
8
|
+
export { ParserPool } from './indexer/parser.js';
|
|
9
|
+
export { ensurePythonDeps } from './indexer/ensure-python-deps.js';
|
|
10
|
+
export { installGitHooks } from './indexer/git-hooks.js';
|
|
11
|
+
export type { InstallGitHooksOptions } from './indexer/git-hooks.js';
|
|
12
|
+
export { SentenceTransformersProvider, Qwen3EmbeddingProvider, DEFAULT_EMBEDDING_MODEL } from './indexer/embedder.js';
|
|
13
|
+
export type { EmbeddingProvider } from './indexer/embedder.js';
|
|
14
|
+
export type { ExtractionResult, RawCallRef, RawImport, RawSymbol, SymbolExtractor, } from './indexer/extractors/types.js';
|
|
15
|
+
export { FileWatcher } from './indexer/watcher.js';
|
|
16
|
+
export type { WatcherOptions } from './indexer/watcher.js';
|
|
17
|
+
export { FilePoller } from './indexer/poller.js';
|
|
18
|
+
export type { PollerOptions } from './indexer/poller.js';
|
|
19
|
+
export { createKbMcpServer } from './kb-server/server.js';
|
|
20
|
+
export { openReadOnly, getSymbolById, getSymbolsByName, listSymbols, getFileById, getFileByPath, listFiles, } from './kb-server/db.js';
|
|
21
|
+
export type { SymbolRow, FileRow } from './kb-server/db.js';
|
|
22
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACjF,YAAY,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACjF,OAAO,EAAE,SAAS,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AACvE,YAAY,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACnE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,YAAY,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AACrE,OAAO,EAAE,4BAA4B,EAAE,sBAAsB,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AACtH,YAAY,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,YAAY,EACV,gBAAgB,EAChB,UAAU,EACV,SAAS,EACT,SAAS,EACT,eAAe,GAChB,MAAM,+BAA+B,CAAC;AAGvC,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,YAAY,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,YAAY,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAGzD,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EACL,YAAY,EACZ,aAAa,EACb,gBAAgB,EAChB,WAAW,EACX,WAAW,EACX,aAAa,EACb,SAAS,GACV,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export { IndexBuilder } from './indexer/index.js';
|
|
2
|
+
export { openDb, setKbMeta, getKbMeta, createVec0Tables } from './indexer/db.js';
|
|
3
|
+
export { buildCallGraph, topoSort, detectCycles } from './indexer/call-graph.js';
|
|
4
|
+
export { walkFiles, detectLanguageForPath } from './indexer/walker.js';
|
|
5
|
+
export { ImportResolver } from './indexer/resolver.js';
|
|
6
|
+
export { ParserPool } from './indexer/parser.js';
|
|
7
|
+
export { ensurePythonDeps } from './indexer/ensure-python-deps.js';
|
|
8
|
+
export { installGitHooks } from './indexer/git-hooks.js';
|
|
9
|
+
export { SentenceTransformersProvider, Qwen3EmbeddingProvider, DEFAULT_EMBEDDING_MODEL } from './indexer/embedder.js';
|
|
10
|
+
// ── File watcher / poller ─────────────────────────────────────────────────────
|
|
11
|
+
export { FileWatcher } from './indexer/watcher.js';
|
|
12
|
+
export { FilePoller } from './indexer/poller.js';
|
|
13
|
+
// ── MCP server ────────────────────────────────────────────────────────────────
|
|
14
|
+
export { createKbMcpServer } from './kb-server/server.js';
|
|
15
|
+
export { openReadOnly, getSymbolById, getSymbolsByName, listSymbols, getFileById, getFileByPath, listFiles, } from './kb-server/db.js';
|
|
16
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAEjF,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACjF,OAAO,EAAE,SAAS,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAEvE,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACnE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAEzD,OAAO,EAAE,4BAA4B,EAAE,sBAAsB,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAUtH,iFAAiF;AACjF,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAEnD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAGjD,iFAAiF;AACjF,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EACL,YAAY,EACZ,aAAa,EACb,gBAAgB,EAChB,WAAW,EACX,WAAW,EACX,aAAa,EACb,SAAS,GACV,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module indexer/call-graph
|
|
3
|
+
*
|
|
4
|
+
* Call-graph utilities operating on the SQLite knowledge-base:
|
|
5
|
+
*
|
|
6
|
+
* - `buildCallGraph(db)` — resolves raw callee names in `symbol_refs` to
|
|
7
|
+
* concrete symbol IDs where possible.
|
|
8
|
+
* - `topoSort(db)` — topological ordering of files based on `file_imports`
|
|
9
|
+
* using Kahn's algorithm.
|
|
10
|
+
* - `detectCycles(db)` — cycle detection over the `file_imports` graph using
|
|
11
|
+
* Tarjan's strongly-connected-components algorithm.
|
|
12
|
+
*/
|
|
13
|
+
import type { Database } from './db.js';
|
|
14
|
+
/**
|
|
15
|
+
* Resolves unresolved `symbol_refs` rows by looking up `callee_name` in the
|
|
16
|
+
* `symbols` table and writing the matching `callee_id` back.
|
|
17
|
+
*
|
|
18
|
+
* Only exact-name matches within the same DB are performed; cross-file
|
|
19
|
+
* disambiguation is not attempted here.
|
|
20
|
+
*/
|
|
21
|
+
export declare function buildCallGraph(db: Database.Database): void;
|
|
22
|
+
/**
|
|
23
|
+
* Returns file IDs in topologically sorted order (dependencies before
|
|
24
|
+
* dependents) using Kahn's algorithm over the `file_imports` graph.
|
|
25
|
+
*
|
|
26
|
+
* Files that are part of a cycle are excluded from the returned list (they
|
|
27
|
+
* have no valid topological position). Use `detectCycles()` to identify them.
|
|
28
|
+
*/
|
|
29
|
+
export declare function topoSort(db: Database.Database): string[];
|
|
30
|
+
/**
|
|
31
|
+
* Detects cycles in the `file_imports` graph using Tarjan's
|
|
32
|
+
* strongly-connected-components (SCC) algorithm.
|
|
33
|
+
*
|
|
34
|
+
* Returns an array of SCCs where each SCC has more than one node (or a
|
|
35
|
+
* single node with a self-loop). Each SCC is represented as an array of
|
|
36
|
+
* file IDs (as strings).
|
|
37
|
+
*/
|
|
38
|
+
export declare function detectCycles(db: Database.Database): string[][];
|
|
39
|
+
//# sourceMappingURL=call-graph.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"call-graph.d.ts","sourceRoot":"","sources":["../../src/indexer/call-graph.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAIxC;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,GAAG,IAAI,CAwC1D;AAID;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,GAAG,MAAM,EAAE,CA2DxD;AAID;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,GAAG,MAAM,EAAE,EAAE,CA+E9D"}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module indexer/call-graph
|
|
3
|
+
*
|
|
4
|
+
* Call-graph utilities operating on the SQLite knowledge-base:
|
|
5
|
+
*
|
|
6
|
+
* - `buildCallGraph(db)` — resolves raw callee names in `symbol_refs` to
|
|
7
|
+
* concrete symbol IDs where possible.
|
|
8
|
+
* - `topoSort(db)` — topological ordering of files based on `file_imports`
|
|
9
|
+
* using Kahn's algorithm.
|
|
10
|
+
* - `detectCycles(db)` — cycle detection over the `file_imports` graph using
|
|
11
|
+
* Tarjan's strongly-connected-components algorithm.
|
|
12
|
+
*/
|
|
13
|
+
// ─── buildCallGraph ───────────────────────────────────────────────────────────
|
|
14
|
+
/**
|
|
15
|
+
* Resolves unresolved `symbol_refs` rows by looking up `callee_name` in the
|
|
16
|
+
* `symbols` table and writing the matching `callee_id` back.
|
|
17
|
+
*
|
|
18
|
+
* Only exact-name matches within the same DB are performed; cross-file
|
|
19
|
+
* disambiguation is not attempted here.
|
|
20
|
+
*/
|
|
21
|
+
export function buildCallGraph(db) {
|
|
22
|
+
// Build a multimap: symbol name → array of { id, file_id }
|
|
23
|
+
const nameToSymbols = new Map();
|
|
24
|
+
const allSymbols = db
|
|
25
|
+
.prepare('SELECT id, name, file_id FROM symbols')
|
|
26
|
+
.all();
|
|
27
|
+
for (const row of allSymbols) {
|
|
28
|
+
let list = nameToSymbols.get(row.name);
|
|
29
|
+
if (!list) {
|
|
30
|
+
list = [];
|
|
31
|
+
nameToSymbols.set(row.name, list);
|
|
32
|
+
}
|
|
33
|
+
list.push({ id: row.id, file_id: row.file_id });
|
|
34
|
+
}
|
|
35
|
+
// Fetch all unresolved refs along with the caller's file_id for proximity.
|
|
36
|
+
const unresolved = db
|
|
37
|
+
.prepare(`SELECT sr.id, sr.callee_name, s.file_id AS caller_file_id
|
|
38
|
+
FROM symbol_refs sr
|
|
39
|
+
JOIN symbols s ON s.id = sr.caller_id
|
|
40
|
+
WHERE sr.callee_id IS NULL`)
|
|
41
|
+
.all();
|
|
42
|
+
const update = db.prepare('UPDATE symbol_refs SET callee_id = ? WHERE id = ?');
|
|
43
|
+
const updateMany = db.transaction(() => {
|
|
44
|
+
for (const ref of unresolved) {
|
|
45
|
+
const candidates = nameToSymbols.get(ref.callee_name);
|
|
46
|
+
if (!candidates || candidates.length === 0)
|
|
47
|
+
continue;
|
|
48
|
+
// Prefer same-file match for common names like init, new, parse.
|
|
49
|
+
const sameFile = candidates.find(c => c.file_id === ref.caller_file_id);
|
|
50
|
+
const best = sameFile ?? candidates[0];
|
|
51
|
+
update.run(best.id, ref.id);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
updateMany();
|
|
55
|
+
}
|
|
56
|
+
// ─── topoSort ─────────────────────────────────────────────────────────────────
|
|
57
|
+
/**
|
|
58
|
+
* Returns file IDs in topologically sorted order (dependencies before
|
|
59
|
+
* dependents) using Kahn's algorithm over the `file_imports` graph.
|
|
60
|
+
*
|
|
61
|
+
* Files that are part of a cycle are excluded from the returned list (they
|
|
62
|
+
* have no valid topological position). Use `detectCycles()` to identify them.
|
|
63
|
+
*/
|
|
64
|
+
export function topoSort(db) {
|
|
65
|
+
// Build adjacency: importer → set of importees (edges point from user to dep)
|
|
66
|
+
// For topological sort we need: dep comes before user, so reverse edges.
|
|
67
|
+
// adjacency[dep] → [users]
|
|
68
|
+
// in-degree[user] = number of deps it imports
|
|
69
|
+
const allFiles = db
|
|
70
|
+
.prepare('SELECT id FROM files')
|
|
71
|
+
.all();
|
|
72
|
+
const fileIds = allFiles.map(r => String(r.id));
|
|
73
|
+
const inDegree = new Map();
|
|
74
|
+
const dependents = new Map(); // dep → users
|
|
75
|
+
for (const id of fileIds) {
|
|
76
|
+
inDegree.set(id, 0);
|
|
77
|
+
dependents.set(id, []);
|
|
78
|
+
}
|
|
79
|
+
const edges = db
|
|
80
|
+
.prepare(`SELECT fi.file_id AS importer, fi.resolved_id AS dep
|
|
81
|
+
FROM file_imports fi
|
|
82
|
+
WHERE fi.resolved_id IS NOT NULL`)
|
|
83
|
+
.all();
|
|
84
|
+
for (const { importer, dep } of edges) {
|
|
85
|
+
const importerStr = String(importer);
|
|
86
|
+
const depStr = String(dep);
|
|
87
|
+
if (!inDegree.has(importerStr) || !inDegree.has(depStr))
|
|
88
|
+
continue;
|
|
89
|
+
// importer has one more dependency
|
|
90
|
+
inDegree.set(importerStr, (inDegree.get(importerStr) ?? 0) + 1);
|
|
91
|
+
dependents.get(depStr).push(importerStr);
|
|
92
|
+
}
|
|
93
|
+
// Queue all nodes with in-degree 0 (no dependencies)
|
|
94
|
+
const queue = [];
|
|
95
|
+
for (const [id, deg] of inDegree) {
|
|
96
|
+
if (deg === 0)
|
|
97
|
+
queue.push(id);
|
|
98
|
+
}
|
|
99
|
+
const sorted = [];
|
|
100
|
+
while (queue.length > 0) {
|
|
101
|
+
const node = queue.shift();
|
|
102
|
+
sorted.push(node);
|
|
103
|
+
for (const dependent of dependents.get(node) ?? []) {
|
|
104
|
+
const newDeg = (inDegree.get(dependent) ?? 1) - 1;
|
|
105
|
+
inDegree.set(dependent, newDeg);
|
|
106
|
+
if (newDeg === 0) {
|
|
107
|
+
queue.push(dependent);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return sorted;
|
|
112
|
+
}
|
|
113
|
+
// ─── detectCycles ─────────────────────────────────────────────────────────────
|
|
114
|
+
/**
|
|
115
|
+
* Detects cycles in the `file_imports` graph using Tarjan's
|
|
116
|
+
* strongly-connected-components (SCC) algorithm.
|
|
117
|
+
*
|
|
118
|
+
* Returns an array of SCCs where each SCC has more than one node (or a
|
|
119
|
+
* single node with a self-loop). Each SCC is represented as an array of
|
|
120
|
+
* file IDs (as strings).
|
|
121
|
+
*/
|
|
122
|
+
export function detectCycles(db) {
|
|
123
|
+
const allFiles = db
|
|
124
|
+
.prepare('SELECT id FROM files')
|
|
125
|
+
.all();
|
|
126
|
+
// Build adjacency list: importer → [dep, ...]
|
|
127
|
+
const adjacency = new Map();
|
|
128
|
+
for (const { id } of allFiles) {
|
|
129
|
+
adjacency.set(String(id), []);
|
|
130
|
+
}
|
|
131
|
+
const edges = db
|
|
132
|
+
.prepare(`SELECT fi.file_id AS importer, fi.resolved_id AS dep
|
|
133
|
+
FROM file_imports fi
|
|
134
|
+
WHERE fi.resolved_id IS NOT NULL`)
|
|
135
|
+
.all();
|
|
136
|
+
for (const { importer, dep } of edges) {
|
|
137
|
+
const imp = String(importer);
|
|
138
|
+
const d = String(dep);
|
|
139
|
+
if (adjacency.has(imp)) {
|
|
140
|
+
adjacency.get(imp).push(d);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
// Tarjan's SCC
|
|
144
|
+
let index = 0;
|
|
145
|
+
const indices = new Map();
|
|
146
|
+
const lowlink = new Map();
|
|
147
|
+
const onStack = new Map();
|
|
148
|
+
const stack = [];
|
|
149
|
+
const sccs = [];
|
|
150
|
+
function strongConnect(v) {
|
|
151
|
+
indices.set(v, index);
|
|
152
|
+
lowlink.set(v, index);
|
|
153
|
+
index++;
|
|
154
|
+
stack.push(v);
|
|
155
|
+
onStack.set(v, true);
|
|
156
|
+
for (const w of adjacency.get(v) ?? []) {
|
|
157
|
+
if (!indices.has(w)) {
|
|
158
|
+
strongConnect(w);
|
|
159
|
+
lowlink.set(v, Math.min(lowlink.get(v), lowlink.get(w)));
|
|
160
|
+
}
|
|
161
|
+
else if (onStack.get(w)) {
|
|
162
|
+
lowlink.set(v, Math.min(lowlink.get(v), indices.get(w)));
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
if (lowlink.get(v) === indices.get(v)) {
|
|
166
|
+
const scc = [];
|
|
167
|
+
let w;
|
|
168
|
+
do {
|
|
169
|
+
w = stack.pop();
|
|
170
|
+
onStack.set(w, false);
|
|
171
|
+
scc.push(w);
|
|
172
|
+
} while (w !== v);
|
|
173
|
+
// Self-loops: check if any node in the scc has an edge to itself
|
|
174
|
+
if (scc.length > 1) {
|
|
175
|
+
sccs.push(scc);
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
// Single-node SCC — only a cycle if there's a self-loop
|
|
179
|
+
const selfLoop = (adjacency.get(scc[0]) ?? []).includes(scc[0]);
|
|
180
|
+
if (selfLoop)
|
|
181
|
+
sccs.push(scc);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
for (const { id } of allFiles) {
|
|
186
|
+
const v = String(id);
|
|
187
|
+
if (!indices.has(v)) {
|
|
188
|
+
strongConnect(v);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
return sccs;
|
|
192
|
+
}
|
|
193
|
+
//# sourceMappingURL=call-graph.js.map
|