@zuvia-software-solutions/code-mapper 1.4.0 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/ai-context.js +1 -1
- package/dist/cli/analyze.d.ts +1 -0
- package/dist/cli/analyze.js +73 -82
- package/dist/cli/augment.js +0 -2
- package/dist/cli/eval-server.d.ts +2 -2
- package/dist/cli/eval-server.js +6 -6
- package/dist/cli/index.js +6 -10
- package/dist/cli/mcp.d.ts +1 -3
- package/dist/cli/mcp.js +3 -3
- package/dist/cli/refresh.d.ts +2 -2
- package/dist/cli/refresh.js +24 -29
- package/dist/cli/status.js +4 -13
- package/dist/cli/tool.d.ts +5 -4
- package/dist/cli/tool.js +8 -10
- package/dist/config/ignore-service.js +14 -34
- package/dist/core/augmentation/engine.js +53 -83
- package/dist/core/db/adapter.d.ts +99 -0
- package/dist/core/db/adapter.js +402 -0
- package/dist/core/db/graph-loader.d.ts +27 -0
- package/dist/core/db/graph-loader.js +148 -0
- package/dist/core/db/queries.d.ts +160 -0
- package/dist/core/db/queries.js +441 -0
- package/dist/core/db/schema.d.ts +108 -0
- package/dist/core/db/schema.js +136 -0
- package/dist/core/embeddings/embedder.d.ts +21 -12
- package/dist/core/embeddings/embedder.js +104 -50
- package/dist/core/embeddings/embedding-pipeline.d.ts +48 -22
- package/dist/core/embeddings/embedding-pipeline.js +220 -262
- package/dist/core/embeddings/text-generator.js +4 -19
- package/dist/core/embeddings/types.d.ts +1 -1
- package/dist/core/graph/graph.d.ts +1 -1
- package/dist/core/graph/graph.js +1 -0
- package/dist/core/graph/types.d.ts +11 -9
- package/dist/core/graph/types.js +4 -1
- package/dist/core/incremental/refresh.d.ts +46 -0
- package/dist/core/incremental/refresh.js +503 -0
- package/dist/core/incremental/types.d.ts +2 -1
- package/dist/core/incremental/types.js +42 -44
- package/dist/core/ingestion/ast-cache.js +1 -0
- package/dist/core/ingestion/call-processor.d.ts +15 -3
- package/dist/core/ingestion/call-processor.js +448 -60
- package/dist/core/ingestion/cluster-enricher.d.ts +1 -1
- package/dist/core/ingestion/cluster-enricher.js +2 -0
- package/dist/core/ingestion/community-processor.d.ts +1 -1
- package/dist/core/ingestion/community-processor.js +8 -3
- package/dist/core/ingestion/export-detection.d.ts +1 -1
- package/dist/core/ingestion/export-detection.js +1 -1
- package/dist/core/ingestion/filesystem-walker.js +1 -1
- package/dist/core/ingestion/heritage-processor.d.ts +2 -2
- package/dist/core/ingestion/heritage-processor.js +22 -11
- package/dist/core/ingestion/import-processor.d.ts +2 -2
- package/dist/core/ingestion/import-processor.js +24 -9
- package/dist/core/ingestion/language-config.js +7 -4
- package/dist/core/ingestion/mro-processor.d.ts +1 -1
- package/dist/core/ingestion/mro-processor.js +23 -11
- package/dist/core/ingestion/named-binding-extraction.js +5 -5
- package/dist/core/ingestion/parsing-processor.d.ts +4 -4
- package/dist/core/ingestion/parsing-processor.js +26 -18
- package/dist/core/ingestion/pipeline.d.ts +4 -2
- package/dist/core/ingestion/pipeline.js +50 -20
- package/dist/core/ingestion/process-processor.d.ts +2 -2
- package/dist/core/ingestion/process-processor.js +28 -14
- package/dist/core/ingestion/resolution-context.d.ts +1 -1
- package/dist/core/ingestion/resolution-context.js +14 -4
- package/dist/core/ingestion/resolvers/csharp.js +4 -3
- package/dist/core/ingestion/resolvers/go.js +3 -1
- package/dist/core/ingestion/resolvers/jvm.js +13 -4
- package/dist/core/ingestion/resolvers/standard.js +2 -2
- package/dist/core/ingestion/resolvers/utils.js +6 -2
- package/dist/core/ingestion/route-stitcher.d.ts +15 -0
- package/dist/core/ingestion/route-stitcher.js +92 -0
- package/dist/core/ingestion/structure-processor.d.ts +1 -1
- package/dist/core/ingestion/structure-processor.js +3 -2
- package/dist/core/ingestion/symbol-table.d.ts +2 -0
- package/dist/core/ingestion/symbol-table.js +5 -1
- package/dist/core/ingestion/tree-sitter-queries.d.ts +2 -2
- package/dist/core/ingestion/tree-sitter-queries.js +177 -0
- package/dist/core/ingestion/type-env.js +20 -0
- package/dist/core/ingestion/type-extractors/csharp.js +4 -3
- package/dist/core/ingestion/type-extractors/go.js +23 -12
- package/dist/core/ingestion/type-extractors/php.js +18 -10
- package/dist/core/ingestion/type-extractors/ruby.js +15 -3
- package/dist/core/ingestion/type-extractors/rust.js +3 -2
- package/dist/core/ingestion/type-extractors/shared.js +3 -2
- package/dist/core/ingestion/type-extractors/typescript.js +11 -5
- package/dist/core/ingestion/utils.d.ts +27 -4
- package/dist/core/ingestion/utils.js +145 -100
- package/dist/core/ingestion/workers/parse-worker.d.ts +1 -0
- package/dist/core/ingestion/workers/parse-worker.js +97 -29
- package/dist/core/ingestion/workers/worker-pool.js +3 -0
- package/dist/core/search/bm25-index.d.ts +15 -8
- package/dist/core/search/bm25-index.js +48 -98
- package/dist/core/search/hybrid-search.d.ts +9 -3
- package/dist/core/search/hybrid-search.js +30 -25
- package/dist/core/search/reranker.js +9 -7
- package/dist/core/search/types.d.ts +0 -4
- package/dist/core/semantic/tsgo-service.d.ts +7 -1
- package/dist/core/semantic/tsgo-service.js +165 -66
- package/dist/lib/tsgo-test.d.ts +2 -0
- package/dist/lib/tsgo-test.js +6 -0
- package/dist/lib/type-utils.d.ts +25 -0
- package/dist/lib/type-utils.js +22 -0
- package/dist/lib/utils.d.ts +3 -2
- package/dist/lib/utils.js +3 -2
- package/dist/mcp/compatible-stdio-transport.js +1 -1
- package/dist/mcp/local/local-backend.d.ts +29 -56
- package/dist/mcp/local/local-backend.js +808 -1118
- package/dist/mcp/resources.js +35 -25
- package/dist/mcp/server.d.ts +1 -1
- package/dist/mcp/server.js +5 -5
- package/dist/mcp/tools.js +24 -25
- package/dist/storage/repo-manager.d.ts +2 -12
- package/dist/storage/repo-manager.js +1 -47
- package/dist/types/pipeline.d.ts +8 -5
- package/dist/types/pipeline.js +5 -0
- package/package.json +18 -11
- package/dist/cli/serve.d.ts +0 -5
- package/dist/cli/serve.js +0 -8
- package/dist/core/incremental/child-process.d.ts +0 -8
- package/dist/core/incremental/child-process.js +0 -649
- package/dist/core/incremental/refresh-coordinator.d.ts +0 -32
- package/dist/core/incremental/refresh-coordinator.js +0 -147
- package/dist/core/lbug/csv-generator.d.ts +0 -28
- package/dist/core/lbug/csv-generator.js +0 -355
- package/dist/core/lbug/lbug-adapter.d.ts +0 -96
- package/dist/core/lbug/lbug-adapter.js +0 -753
- package/dist/core/lbug/schema.d.ts +0 -46
- package/dist/core/lbug/schema.js +0 -402
- package/dist/mcp/core/embedder.d.ts +0 -24
- package/dist/mcp/core/embedder.js +0 -168
- package/dist/mcp/core/lbug-adapter.d.ts +0 -29
- package/dist/mcp/core/lbug-adapter.js +0 -330
- package/dist/server/api.d.ts +0 -5
- package/dist/server/api.js +0 -340
- package/dist/server/mcp-http.d.ts +0 -7
- package/dist/server/mcp-http.js +0 -95
- package/models/mlx-embedder.py +0 -185
package/dist/cli/tool.d.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @file tool.ts
|
|
3
|
-
* @description Direct CLI tool commands (query, context, impact,
|
|
4
|
-
* entirely and invokes LocalBackend directly for minimal overhead.
|
|
5
|
-
* because LadybugDB's native module captures stdout at the OS level during init
|
|
3
|
+
* @description Direct CLI tool commands (query, context, impact, sql). Bypasses MCP
|
|
4
|
+
* entirely and invokes LocalBackend directly for minimal overhead.
|
|
6
5
|
*/
|
|
7
6
|
export declare function queryCommand(queryText: string, options?: {
|
|
8
7
|
repo?: string;
|
|
@@ -16,13 +15,15 @@ export declare function contextCommand(name: string, options?: {
|
|
|
16
15
|
file?: string;
|
|
17
16
|
uid?: string;
|
|
18
17
|
content?: boolean;
|
|
18
|
+
tsgo?: boolean;
|
|
19
19
|
}): Promise<void>;
|
|
20
20
|
export declare function impactCommand(target: string, options?: {
|
|
21
21
|
direction?: string;
|
|
22
22
|
repo?: string;
|
|
23
23
|
depth?: string;
|
|
24
24
|
includeTests?: boolean;
|
|
25
|
+
tsgo?: boolean;
|
|
25
26
|
}): Promise<void>;
|
|
26
|
-
export declare function
|
|
27
|
+
export declare function sqlCommand(query: string, options?: {
|
|
27
28
|
repo?: string;
|
|
28
29
|
}): Promise<void>;
|
package/dist/cli/tool.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
// code-mapper/src/cli/tool.ts
|
|
2
2
|
/**
|
|
3
3
|
* @file tool.ts
|
|
4
|
-
* @description Direct CLI tool commands (query, context, impact,
|
|
5
|
-
* entirely and invokes LocalBackend directly for minimal overhead.
|
|
6
|
-
* because LadybugDB's native module captures stdout at the OS level during init
|
|
4
|
+
* @description Direct CLI tool commands (query, context, impact, sql). Bypasses MCP
|
|
5
|
+
* entirely and invokes LocalBackend directly for minimal overhead.
|
|
7
6
|
*/
|
|
8
7
|
import { LocalBackend } from '../mcp/local/local-backend.js';
|
|
9
8
|
let _backend = null;
|
|
@@ -20,11 +19,8 @@ async function getBackend() {
|
|
|
20
19
|
}
|
|
21
20
|
function output(data) {
|
|
22
21
|
const text = typeof data === 'string' ? data : JSON.stringify(data, null, 2);
|
|
23
|
-
// stderr because LadybugDB captures stdout at OS level
|
|
24
22
|
process.stderr.write(text + '\n');
|
|
25
|
-
// Force exit
|
|
26
|
-
// and prevents the process from exiting. This is safe because CLI is
|
|
27
|
-
// single-shot: once output is written, we're done.
|
|
23
|
+
// Force exit to ensure clean termination — CLI is single-shot.
|
|
28
24
|
setTimeout(() => process.exit(0), 50);
|
|
29
25
|
}
|
|
30
26
|
export async function queryCommand(queryText, options) {
|
|
@@ -54,6 +50,7 @@ export async function contextCommand(name, options) {
|
|
|
54
50
|
uid: options?.uid,
|
|
55
51
|
file_path: options?.file,
|
|
56
52
|
include_content: options?.content ?? false,
|
|
53
|
+
tsgo: options?.tsgo,
|
|
57
54
|
repo: options?.repo,
|
|
58
55
|
});
|
|
59
56
|
output(result);
|
|
@@ -69,17 +66,18 @@ export async function impactCommand(target, options) {
|
|
|
69
66
|
direction: options?.direction || 'upstream',
|
|
70
67
|
maxDepth: options?.depth ? parseInt(options.depth) : undefined,
|
|
71
68
|
includeTests: options?.includeTests ?? false,
|
|
69
|
+
tsgo: options?.tsgo,
|
|
72
70
|
repo: options?.repo,
|
|
73
71
|
});
|
|
74
72
|
output(result);
|
|
75
73
|
}
|
|
76
|
-
export async function
|
|
74
|
+
export async function sqlCommand(query, options) {
|
|
77
75
|
if (!query?.trim()) {
|
|
78
|
-
console.error('Usage: code-mapper
|
|
76
|
+
console.error('Usage: code-mapper sql <sql_query>');
|
|
79
77
|
process.exit(1);
|
|
80
78
|
}
|
|
81
79
|
const backend = await getBackend();
|
|
82
|
-
const result = await backend.callTool('
|
|
80
|
+
const result = await backend.callTool('sql', {
|
|
83
81
|
query,
|
|
84
82
|
repo: options?.repo,
|
|
85
83
|
});
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
// code-mapper/src/config/ignore-service.ts
|
|
2
2
|
/** @file ignore-service.ts @description Hardcoded and user-configurable ignore rules for file/directory filtering during repo traversal */
|
|
3
|
-
import ignore from 'ignore';
|
|
3
|
+
import ignore, {} from 'ignore';
|
|
4
4
|
import fs from 'fs/promises';
|
|
5
5
|
import nodePath from 'path';
|
|
6
6
|
const DEFAULT_IGNORE_LIST = new Set([
|
|
7
|
-
// Version control
|
|
7
|
+
// Version control internals
|
|
8
8
|
'.git',
|
|
9
9
|
'.svn',
|
|
10
10
|
'.hg',
|
|
11
11
|
'.bzr',
|
|
12
|
-
//
|
|
12
|
+
// IDE/editor config (not source code)
|
|
13
13
|
'.idea',
|
|
14
14
|
'.vscode',
|
|
15
15
|
'.vs',
|
|
@@ -17,16 +17,12 @@ const DEFAULT_IGNORE_LIST = new Set([
|
|
|
17
17
|
'.settings',
|
|
18
18
|
'.DS_Store',
|
|
19
19
|
'Thumbs.db',
|
|
20
|
-
//
|
|
20
|
+
// Downloaded dependencies (not your code)
|
|
21
21
|
'node_modules',
|
|
22
22
|
'bower_components',
|
|
23
23
|
'jspm_packages',
|
|
24
|
-
'vendor', // PHP/Go
|
|
25
|
-
// 'packages' not ignored — commonly used for monorepo source code
|
|
26
24
|
'venv',
|
|
27
25
|
'.venv',
|
|
28
|
-
'env',
|
|
29
|
-
'.env',
|
|
30
26
|
'__pycache__',
|
|
31
27
|
'.pytest_cache',
|
|
32
28
|
'.mypy_cache',
|
|
@@ -35,17 +31,14 @@ const DEFAULT_IGNORE_LIST = new Set([
|
|
|
35
31
|
'eggs',
|
|
36
32
|
'.eggs',
|
|
37
33
|
'lib64',
|
|
38
|
-
'parts',
|
|
39
34
|
'sdist',
|
|
40
35
|
'wheels',
|
|
41
|
-
//
|
|
36
|
+
// Compiled/bundled output (derived from source)
|
|
42
37
|
'dist',
|
|
43
38
|
'build',
|
|
44
39
|
'out',
|
|
45
|
-
'output',
|
|
46
|
-
'bin',
|
|
47
40
|
'obj',
|
|
48
|
-
'target', // Java
|
|
41
|
+
'target', // Java/Rust compiled output
|
|
49
42
|
'.next',
|
|
50
43
|
'.nuxt',
|
|
51
44
|
'.output',
|
|
@@ -57,37 +50,26 @@ const DEFAULT_IGNORE_LIST = new Set([
|
|
|
57
50
|
'.parcel-cache',
|
|
58
51
|
'.turbo',
|
|
59
52
|
'.svelte-kit',
|
|
60
|
-
//
|
|
53
|
+
// Coverage reports (not source code)
|
|
61
54
|
'coverage',
|
|
62
55
|
'.nyc_output',
|
|
63
56
|
'htmlcov',
|
|
64
57
|
'.coverage',
|
|
65
|
-
'__tests__',
|
|
66
|
-
'__mocks__',
|
|
67
58
|
'.jest',
|
|
68
|
-
//
|
|
69
|
-
'logs',
|
|
70
|
-
'log',
|
|
59
|
+
// Temp/cache (ephemeral)
|
|
71
60
|
'tmp',
|
|
72
61
|
'temp',
|
|
73
62
|
'cache',
|
|
74
63
|
'.cache',
|
|
75
64
|
'.tmp',
|
|
76
65
|
'.temp',
|
|
77
|
-
//
|
|
78
|
-
'.generated',
|
|
79
|
-
'generated',
|
|
80
|
-
'auto-generated',
|
|
66
|
+
// Infrastructure config (not source code)
|
|
81
67
|
'.terraform',
|
|
82
|
-
|
|
83
|
-
// Misc
|
|
68
|
+
// CI config (not source code)
|
|
84
69
|
'.husky',
|
|
85
70
|
'.github',
|
|
86
71
|
'.circleci',
|
|
87
72
|
'.gitlab',
|
|
88
|
-
'fixtures',
|
|
89
|
-
'snapshots',
|
|
90
|
-
'__snapshots__',
|
|
91
73
|
]);
|
|
92
74
|
const IGNORED_EXTENSIONS = new Set([
|
|
93
75
|
// Images
|
|
@@ -174,7 +156,7 @@ const IGNORED_FILES = new Set([
|
|
|
174
156
|
export const shouldIgnorePath = (filePath) => {
|
|
175
157
|
const normalizedPath = filePath.replace(/\\/g, '/');
|
|
176
158
|
const parts = normalizedPath.split('/');
|
|
177
|
-
const fileName = parts
|
|
159
|
+
const fileName = parts.at(-1) ?? '';
|
|
178
160
|
const fileNameLower = fileName.toLowerCase();
|
|
179
161
|
// Check if any path segment matches the ignore list
|
|
180
162
|
for (const part of parts) {
|
|
@@ -202,11 +184,9 @@ export const shouldIgnorePath = (filePath) => {
|
|
|
202
184
|
}
|
|
203
185
|
// TODO: dot-file filtering intentionally skipped — many are important configs
|
|
204
186
|
// Relies on explicit IGNORED_FILES list above instead
|
|
205
|
-
// Ignore
|
|
187
|
+
// Ignore bundled/minified code (derived output, not source)
|
|
206
188
|
if (fileNameLower.includes('.bundle.') ||
|
|
207
|
-
fileNameLower.includes('.chunk.')
|
|
208
|
-
fileNameLower.includes('.generated.') ||
|
|
209
|
-
fileNameLower.endsWith('.d.ts')) {
|
|
189
|
+
fileNameLower.includes('.chunk.')) {
|
|
210
190
|
return true;
|
|
211
191
|
}
|
|
212
192
|
return false;
|
|
@@ -224,7 +204,7 @@ export const loadIgnoreRules = async (repoPath, options) => {
|
|
|
224
204
|
const ig = ignore();
|
|
225
205
|
let hasRules = false;
|
|
226
206
|
// Allow users to bypass .gitignore parsing (e.g. when .gitignore accidentally excludes source files)
|
|
227
|
-
const skipGitignore = options?.noGitignore ?? !!process.env
|
|
207
|
+
const skipGitignore = options?.noGitignore ?? !!process.env['CODE_MAPPER_NO_GITIGNORE'];
|
|
228
208
|
const filenames = skipGitignore
|
|
229
209
|
? ['.code-mapperignore']
|
|
230
210
|
: ['.gitignore', '.code-mapperignore'];
|
|
@@ -49,7 +49,6 @@ async function findRepoForCwd(cwd) {
|
|
|
49
49
|
return {
|
|
50
50
|
name: bestMatch.name,
|
|
51
51
|
storagePath: bestMatch.storagePath,
|
|
52
|
-
lbugPath: path.join(bestMatch.storagePath, 'lbug'),
|
|
53
52
|
};
|
|
54
53
|
}
|
|
55
54
|
catch {
|
|
@@ -74,64 +73,40 @@ export async function augment(pattern, cwd) {
|
|
|
74
73
|
const repo = await findRepoForCwd(workDir);
|
|
75
74
|
if (!repo)
|
|
76
75
|
return '';
|
|
77
|
-
// Lazy-load
|
|
78
|
-
const {
|
|
79
|
-
const {
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
}
|
|
76
|
+
// Lazy-load SQLite adapter and search
|
|
77
|
+
const { openDb } = await import('../db/adapter.js');
|
|
78
|
+
const { toNodeId } = await import('../db/schema.js');
|
|
79
|
+
const { searchFTSSymbols } = await import('../search/bm25-index.js');
|
|
80
|
+
const { rawQuery } = await import('../db/adapter.js');
|
|
81
|
+
const dbPath = path.join(repo.storagePath, 'index.db');
|
|
82
|
+
const db = openDb(dbPath);
|
|
85
83
|
// Step 1: BM25 search (fast, no embeddings needed)
|
|
86
|
-
const bm25Results =
|
|
84
|
+
const bm25Results = searchFTSSymbols(pattern, 10, db);
|
|
87
85
|
if (bm25Results.length === 0)
|
|
88
86
|
return '';
|
|
89
|
-
//
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
const escaped = result.filePath.replace(/'/g, "''");
|
|
93
|
-
try {
|
|
94
|
-
const symbols = await executeQuery(repoId, `
|
|
95
|
-
MATCH (n) WHERE n.filePath = '${escaped}'
|
|
96
|
-
AND n.name CONTAINS '${pattern.replace(/'/g, "''").split(/\s+/)[0]}'
|
|
97
|
-
RETURN n.id AS id, n.name AS name, labels(n) AS type, n.filePath AS filePath
|
|
98
|
-
LIMIT 3
|
|
99
|
-
`);
|
|
100
|
-
for (const sym of symbols) {
|
|
101
|
-
symbolMatches.push({
|
|
102
|
-
nodeId: sym.id || sym[0],
|
|
103
|
-
name: sym.name || sym[1],
|
|
104
|
-
type: sym.type || sym[2],
|
|
105
|
-
filePath: sym.filePath || sym[3],
|
|
106
|
-
score: result.score,
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
catch { /* skip */ }
|
|
111
|
-
}
|
|
112
|
-
if (symbolMatches.length === 0)
|
|
113
|
-
return '';
|
|
114
|
-
// Step 3: Batch-fetch callers/callees/processes/cohesion (WHERE n.id IN [...])
|
|
115
|
-
const uniqueSymbols = symbolMatches.slice(0, 5).filter((sym, i, arr) => arr.findIndex(s => s.nodeId === sym.nodeId) === i);
|
|
87
|
+
// BM25 already returns symbol-level results (nodeId, name, type, filePath)
|
|
88
|
+
// so we skip the old "map file results to symbols" step.
|
|
89
|
+
const uniqueSymbols = bm25Results.slice(0, 5).filter((sym, i, arr) => arr.findIndex(s => s.nodeId === sym.nodeId) === i);
|
|
116
90
|
if (uniqueSymbols.length === 0)
|
|
117
91
|
return '';
|
|
118
|
-
const
|
|
92
|
+
const nodeIds = uniqueSymbols.map(s => toNodeId(s.nodeId));
|
|
93
|
+
const ph = nodeIds.map(() => '?').join(',');
|
|
94
|
+
// Step 2: Batch-fetch callers/callees/processes/cohesion via SQL
|
|
119
95
|
// Callers
|
|
120
96
|
const callersMap = new Map();
|
|
121
97
|
try {
|
|
122
|
-
const rows =
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
98
|
+
const rows = rawQuery(db, `
|
|
99
|
+
SELECT e.targetId AS targetId, n.name AS name
|
|
100
|
+
FROM edges e
|
|
101
|
+
JOIN nodes n ON n.id = e.sourceId
|
|
102
|
+
WHERE e.targetId IN (${ph}) AND e.type = 'CALLS'
|
|
126
103
|
LIMIT 15
|
|
127
|
-
|
|
104
|
+
`, [...nodeIds]);
|
|
128
105
|
for (const r of rows) {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
callersMap.set(tid, []);
|
|
134
|
-
callersMap.get(tid).push(name);
|
|
106
|
+
if (r.targetId && r.name) {
|
|
107
|
+
if (!callersMap.has(r.targetId))
|
|
108
|
+
callersMap.set(r.targetId, []);
|
|
109
|
+
callersMap.get(r.targetId)?.push(r.name);
|
|
135
110
|
}
|
|
136
111
|
}
|
|
137
112
|
}
|
|
@@ -139,19 +114,18 @@ export async function augment(pattern, cwd) {
|
|
|
139
114
|
// Callees
|
|
140
115
|
const calleesMap = new Map();
|
|
141
116
|
try {
|
|
142
|
-
const rows =
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
117
|
+
const rows = rawQuery(db, `
|
|
118
|
+
SELECT e.sourceId AS sourceId, n.name AS name
|
|
119
|
+
FROM edges e
|
|
120
|
+
JOIN nodes n ON n.id = e.targetId
|
|
121
|
+
WHERE e.sourceId IN (${ph}) AND e.type = 'CALLS'
|
|
146
122
|
LIMIT 15
|
|
147
|
-
|
|
123
|
+
`, [...nodeIds]);
|
|
148
124
|
for (const r of rows) {
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
calleesMap.set(sid, []);
|
|
154
|
-
calleesMap.get(sid).push(name);
|
|
125
|
+
if (r.sourceId && r.name) {
|
|
126
|
+
if (!calleesMap.has(r.sourceId))
|
|
127
|
+
calleesMap.set(r.sourceId, []);
|
|
128
|
+
calleesMap.get(r.sourceId)?.push(r.name);
|
|
155
129
|
}
|
|
156
130
|
}
|
|
157
131
|
}
|
|
@@ -159,20 +133,17 @@ export async function augment(pattern, cwd) {
|
|
|
159
133
|
// Processes
|
|
160
134
|
const processesMap = new Map();
|
|
161
135
|
try {
|
|
162
|
-
const rows =
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
136
|
+
const rows = rawQuery(db, `
|
|
137
|
+
SELECT e.sourceId AS nodeId, p.heuristicLabel AS label, e.step AS step, p.stepCount AS stepCount
|
|
138
|
+
FROM edges e
|
|
139
|
+
JOIN nodes p ON p.id = e.targetId
|
|
140
|
+
WHERE e.sourceId IN (${ph}) AND e.type = 'STEP_IN_PROCESS' AND p.label = 'Process'
|
|
141
|
+
`, [...nodeIds]);
|
|
167
142
|
for (const r of rows) {
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
if (nid && label) {
|
|
173
|
-
if (!processesMap.has(nid))
|
|
174
|
-
processesMap.set(nid, []);
|
|
175
|
-
processesMap.get(nid).push(`${label} (step ${step}/${stepCount})`);
|
|
143
|
+
if (r.nodeId && r.label) {
|
|
144
|
+
if (!processesMap.has(r.nodeId))
|
|
145
|
+
processesMap.set(r.nodeId, []);
|
|
146
|
+
processesMap.get(r.nodeId)?.push(`${r.label} (step ${r.step}/${r.stepCount})`);
|
|
176
147
|
}
|
|
177
148
|
}
|
|
178
149
|
}
|
|
@@ -180,16 +151,15 @@ export async function augment(pattern, cwd) {
|
|
|
180
151
|
// Cohesion (internal ranking signal)
|
|
181
152
|
const cohesionMap = new Map();
|
|
182
153
|
try {
|
|
183
|
-
const rows =
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
154
|
+
const rows = rawQuery(db, `
|
|
155
|
+
SELECT e.sourceId AS nodeId, c.cohesion AS cohesion
|
|
156
|
+
FROM edges e
|
|
157
|
+
JOIN nodes c ON c.id = e.targetId
|
|
158
|
+
WHERE e.sourceId IN (${ph}) AND e.type = 'MEMBER_OF' AND c.label = 'Community'
|
|
159
|
+
`, [...nodeIds]);
|
|
188
160
|
for (const r of rows) {
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
if (nid)
|
|
192
|
-
cohesionMap.set(nid, coh);
|
|
161
|
+
if (r.nodeId)
|
|
162
|
+
cohesionMap.set(r.nodeId, r.cohesion ?? 0);
|
|
193
163
|
}
|
|
194
164
|
}
|
|
195
165
|
catch { /* skip */ }
|
|
@@ -207,7 +177,7 @@ export async function augment(pattern, cwd) {
|
|
|
207
177
|
}
|
|
208
178
|
if (enriched.length === 0)
|
|
209
179
|
return '';
|
|
210
|
-
// Step
|
|
180
|
+
// Step 3: Rank by cohesion and format output
|
|
211
181
|
enriched.sort((a, b) => b.cohesion - a.cohesion);
|
|
212
182
|
const lines = [`[Code Mapper] ${enriched.length} related symbols found:`, ''];
|
|
213
183
|
for (const item of enriched) {
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Unified SQLite database adapter for code-mapper.
|
|
3
|
+
*
|
|
4
|
+
* Single module for both CLI and MCP database access.
|
|
5
|
+
* WAL mode: concurrent readers + single writer, zero lock conflicts.
|
|
6
|
+
* Synchronous better-sqlite3 API: no connection pools needed.
|
|
7
|
+
*
|
|
8
|
+
* All public functions are typed with branded IDs and schema types
|
|
9
|
+
* from schema.ts — the compiler prevents passing wrong ID types
|
|
10
|
+
* or invalid labels/edge types.
|
|
11
|
+
*/
|
|
12
|
+
import Database from 'better-sqlite3';
|
|
13
|
+
import { type NodeId, type NodeLabel, type EdgeType, type NodeRow, type EdgeRow, type NodeInsert, type EdgeInsert } from './schema.js';
|
|
14
|
+
/** Open (or reuse) a SQLite database. Creates schema if new. */
|
|
15
|
+
export declare function openDb(dbPath: string): Database.Database;
|
|
16
|
+
/** Close one or all databases. */
|
|
17
|
+
export declare function closeDb(dbPath?: string): void;
|
|
18
|
+
/** Delete and recreate a database (full re-analyze). */
|
|
19
|
+
export declare function resetDb(dbPath: string): Database.Database;
|
|
20
|
+
/** Check if a database is open. */
|
|
21
|
+
export declare function isDbOpen(dbPath: string): boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Expand an identifier into natural language words for FTS matching.
|
|
24
|
+
* camelCase, PascalCase, snake_case, UPPER_CASE → space-separated words.
|
|
25
|
+
*
|
|
26
|
+
* Examples:
|
|
27
|
+
* buildTestGraph → "build test graph"
|
|
28
|
+
* processCallsFromExtracted → "process calls from extracted"
|
|
29
|
+
* MAX_CHAIN_DEPTH → "max chain depth"
|
|
30
|
+
* deleteNodesByFile → "delete nodes by file"
|
|
31
|
+
*/
|
|
32
|
+
export declare function expandIdentifier(name: string): string;
|
|
33
|
+
/** Insert or replace a node. Automatically expands name for FTS natural language matching. */
|
|
34
|
+
export declare function insertNode(db: Database.Database, node: NodeInsert): void;
|
|
35
|
+
/** Get a node by ID. Returns undefined if not found. */
|
|
36
|
+
export declare function getNode(db: Database.Database, id: NodeId): NodeRow | undefined;
|
|
37
|
+
/** Find nodes by name (optionally filtered by label). */
|
|
38
|
+
export declare function findNodesByName(db: Database.Database, name: string, label?: NodeLabel, limit?: number): NodeRow[];
|
|
39
|
+
/** Find nodes by file path. */
|
|
40
|
+
export declare function findNodesByFile(db: Database.Database, filePath: string): NodeRow[];
|
|
41
|
+
/** Find the node containing a given line in a file (best match). */
|
|
42
|
+
export declare function findNodeAtLine(db: Database.Database, filePath: string, line: number, excludeLabel?: NodeLabel): NodeRow | undefined;
|
|
43
|
+
/** Count nodes, optionally by label. */
|
|
44
|
+
export declare function countNodes(db: Database.Database, label?: NodeLabel): number;
|
|
45
|
+
/** Delete all nodes (and related edges/embeddings) for a file path. Returns count deleted. */
|
|
46
|
+
export declare function deleteNodesByFile(db: Database.Database, filePath: string): number;
|
|
47
|
+
/** Insert an edge (ignores duplicates). */
|
|
48
|
+
export declare function insertEdge(db: Database.Database, edge: EdgeInsert): void;
|
|
49
|
+
/** Find edges from a source node, optionally filtered by type. */
|
|
50
|
+
export declare function findEdgesFrom(db: Database.Database, sourceId: NodeId, type?: EdgeType, minConfidence?: number): EdgeRow[];
|
|
51
|
+
/** Find edges to a target node, optionally filtered by type. */
|
|
52
|
+
export declare function findEdgesTo(db: Database.Database, targetId: NodeId, type?: EdgeType, minConfidence?: number): EdgeRow[];
|
|
53
|
+
/** Count edges. */
|
|
54
|
+
export declare function countEdges(db: Database.Database): number;
|
|
55
|
+
/** Insert or replace an embedding (stores as binary Float32Array). */
|
|
56
|
+
export declare function insertEmbedding(db: Database.Database, nodeId: NodeId, embedding: number[]): void;
|
|
57
|
+
/** Delete embeddings for nodes in a given file. */
|
|
58
|
+
export declare function deleteEmbeddingsByFile(db: Database.Database, filePath: string): void;
|
|
59
|
+
/** Count embeddings. */
|
|
60
|
+
export declare function countEmbeddings(db: Database.Database): number;
|
|
61
|
+
/** Vector similarity search (brute-force cosine). Fast enough for <200K vectors at 256 dims. */
|
|
62
|
+
export declare function searchVector(db: Database.Database, queryVec: number[], limit?: number, maxDistance?: number): Array<{
|
|
63
|
+
nodeId: NodeId;
|
|
64
|
+
distance: number;
|
|
65
|
+
}>;
|
|
66
|
+
/** Full-text search across nodes. FTS5 auto-maintains the index. */
|
|
67
|
+
export declare function searchFTS(db: Database.Database, query: string, limit?: number): Array<{
|
|
68
|
+
id: NodeId;
|
|
69
|
+
name: string;
|
|
70
|
+
label: NodeLabel;
|
|
71
|
+
filePath: string;
|
|
72
|
+
score: number;
|
|
73
|
+
}>;
|
|
74
|
+
/** Get node count, edge count, and embedding count. */
|
|
75
|
+
export declare function getStats(db: Database.Database): {
|
|
76
|
+
nodes: number;
|
|
77
|
+
edges: number;
|
|
78
|
+
embeddings: number;
|
|
79
|
+
};
|
|
80
|
+
/** Batch insert nodes in a single transaction. */
|
|
81
|
+
export declare function insertNodesBatch(db: Database.Database, nodes: readonly NodeInsert[]): void;
|
|
82
|
+
/** Batch insert edges in a single transaction. */
|
|
83
|
+
export declare function insertEdgesBatch(db: Database.Database, edges: readonly EdgeInsert[]): void;
|
|
84
|
+
/** Batch insert embeddings in a single transaction. */
|
|
85
|
+
export declare function insertEmbeddingsBatch(db: Database.Database, items: readonly {
|
|
86
|
+
nodeId: NodeId;
|
|
87
|
+
embedding: number[];
|
|
88
|
+
textHash?: string;
|
|
89
|
+
}[]): void;
|
|
90
|
+
/** Get all textHashes from the embeddings table for hash-based skip on re-index */
|
|
91
|
+
export declare function getEmbeddingHashes(db: Database.Database): Map<string, string>;
|
|
92
|
+
/** Escape a string for use in SQL single-quoted literals. */
|
|
93
|
+
export declare function escapeSql(value: string): string;
|
|
94
|
+
/** Execute a raw SQL query and return rows. */
|
|
95
|
+
export declare function rawQuery(db: Database.Database, sql: string, params?: unknown[]): unknown[];
|
|
96
|
+
/** Execute a raw SQL statement (no return). */
|
|
97
|
+
export declare function rawRun(db: Database.Database, sql: string, params?: unknown[]): {
|
|
98
|
+
changes: number;
|
|
99
|
+
};
|