gitnexus 1.4.10 → 1.5.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 +6 -5
- package/dist/cli/ai-context.d.ts +4 -1
- package/dist/cli/ai-context.js +19 -11
- package/dist/cli/analyze.d.ts +6 -0
- package/dist/cli/analyze.js +105 -251
- package/dist/cli/eval-server.js +20 -11
- package/dist/cli/index-repo.js +20 -22
- package/dist/cli/index.js +8 -7
- package/dist/cli/mcp.js +1 -1
- package/dist/cli/serve.js +29 -1
- package/dist/cli/setup.js +9 -9
- package/dist/cli/skill-gen.js +15 -9
- package/dist/cli/wiki.d.ts +2 -0
- package/dist/cli/wiki.js +141 -26
- package/dist/config/ignore-service.js +102 -22
- package/dist/config/supported-languages.d.ts +8 -42
- package/dist/config/supported-languages.js +8 -43
- package/dist/core/augmentation/engine.js +19 -7
- package/dist/core/embeddings/embedder.js +19 -15
- package/dist/core/embeddings/embedding-pipeline.js +6 -6
- package/dist/core/embeddings/http-client.js +3 -3
- package/dist/core/embeddings/text-generator.js +9 -24
- package/dist/core/embeddings/types.d.ts +1 -1
- package/dist/core/embeddings/types.js +1 -7
- package/dist/core/graph/graph.js +6 -2
- package/dist/core/graph/types.d.ts +9 -59
- package/dist/core/ingestion/ast-cache.js +3 -3
- package/dist/core/ingestion/call-processor.d.ts +20 -2
- package/dist/core/ingestion/call-processor.js +347 -144
- package/dist/core/ingestion/call-routing.js +10 -4
- package/dist/core/ingestion/call-sites/extract-language-call-site.d.ts +10 -0
- package/dist/core/ingestion/call-sites/extract-language-call-site.js +22 -0
- package/dist/core/ingestion/call-sites/java.d.ts +9 -0
- package/dist/core/ingestion/call-sites/java.js +30 -0
- package/dist/core/ingestion/cluster-enricher.js +6 -8
- package/dist/core/ingestion/cobol/cobol-copy-expander.js +10 -3
- package/dist/core/ingestion/cobol/cobol-preprocessor.js +287 -81
- package/dist/core/ingestion/cobol/jcl-parser.js +1 -1
- package/dist/core/ingestion/cobol/jcl-processor.js +1 -1
- package/dist/core/ingestion/cobol-processor.js +102 -56
- package/dist/core/ingestion/community-processor.js +21 -15
- package/dist/core/ingestion/entry-point-scoring.d.ts +1 -1
- package/dist/core/ingestion/entry-point-scoring.js +5 -6
- package/dist/core/ingestion/export-detection.js +32 -9
- package/dist/core/ingestion/field-extractor.d.ts +1 -1
- package/dist/core/ingestion/field-extractors/configs/c-cpp.js +8 -12
- package/dist/core/ingestion/field-extractors/configs/csharp.js +45 -2
- package/dist/core/ingestion/field-extractors/configs/dart.js +5 -3
- package/dist/core/ingestion/field-extractors/configs/go.js +3 -7
- package/dist/core/ingestion/field-extractors/configs/helpers.d.ts +5 -0
- package/dist/core/ingestion/field-extractors/configs/helpers.js +14 -0
- package/dist/core/ingestion/field-extractors/configs/jvm.js +7 -7
- package/dist/core/ingestion/field-extractors/configs/php.js +9 -11
- package/dist/core/ingestion/field-extractors/configs/python.js +1 -1
- package/dist/core/ingestion/field-extractors/configs/ruby.js +4 -3
- package/dist/core/ingestion/field-extractors/configs/rust.js +2 -5
- package/dist/core/ingestion/field-extractors/configs/swift.js +9 -7
- package/dist/core/ingestion/field-extractors/configs/typescript-javascript.js +2 -6
- package/dist/core/ingestion/field-extractors/generic.d.ts +5 -2
- package/dist/core/ingestion/field-extractors/generic.js +6 -0
- package/dist/core/ingestion/field-extractors/typescript.d.ts +1 -1
- package/dist/core/ingestion/field-extractors/typescript.js +1 -1
- package/dist/core/ingestion/field-types.d.ts +4 -2
- package/dist/core/ingestion/filesystem-walker.js +3 -3
- package/dist/core/ingestion/framework-detection.d.ts +1 -1
- package/dist/core/ingestion/framework-detection.js +355 -85
- package/dist/core/ingestion/heritage-processor.d.ts +24 -0
- package/dist/core/ingestion/heritage-processor.js +99 -8
- package/dist/core/ingestion/import-processor.js +44 -15
- package/dist/core/ingestion/import-resolvers/csharp.js +7 -3
- package/dist/core/ingestion/import-resolvers/dart.js +1 -1
- package/dist/core/ingestion/import-resolvers/go.js +4 -2
- package/dist/core/ingestion/import-resolvers/jvm.js +4 -4
- package/dist/core/ingestion/import-resolvers/php.js +4 -4
- package/dist/core/ingestion/import-resolvers/python.js +1 -1
- package/dist/core/ingestion/import-resolvers/rust.js +9 -3
- package/dist/core/ingestion/import-resolvers/standard.d.ts +1 -1
- package/dist/core/ingestion/import-resolvers/standard.js +6 -5
- package/dist/core/ingestion/import-resolvers/swift.js +2 -1
- package/dist/core/ingestion/import-resolvers/utils.js +26 -7
- package/dist/core/ingestion/language-config.js +5 -4
- package/dist/core/ingestion/language-provider.d.ts +7 -2
- package/dist/core/ingestion/languages/c-cpp.js +106 -21
- package/dist/core/ingestion/languages/cobol.js +1 -1
- package/dist/core/ingestion/languages/csharp.js +96 -19
- package/dist/core/ingestion/languages/dart.js +23 -7
- package/dist/core/ingestion/languages/go.js +1 -1
- package/dist/core/ingestion/languages/index.d.ts +1 -1
- package/dist/core/ingestion/languages/index.js +2 -3
- package/dist/core/ingestion/languages/java.js +4 -1
- package/dist/core/ingestion/languages/kotlin.js +60 -13
- package/dist/core/ingestion/languages/php.js +102 -25
- package/dist/core/ingestion/languages/python.js +28 -5
- package/dist/core/ingestion/languages/ruby.js +56 -14
- package/dist/core/ingestion/languages/rust.js +55 -11
- package/dist/core/ingestion/languages/swift.js +112 -27
- package/dist/core/ingestion/languages/typescript.js +95 -19
- package/dist/core/ingestion/markdown-processor.js +5 -5
- package/dist/core/ingestion/method-extractors/configs/csharp.d.ts +2 -0
- package/dist/core/ingestion/method-extractors/configs/csharp.js +283 -0
- package/dist/core/ingestion/method-extractors/configs/jvm.d.ts +3 -0
- package/dist/core/ingestion/method-extractors/configs/jvm.js +326 -0
- package/dist/core/ingestion/method-extractors/generic.d.ts +5 -0
- package/dist/core/ingestion/method-extractors/generic.js +137 -0
- package/dist/core/ingestion/method-types.d.ts +61 -0
- package/dist/core/ingestion/method-types.js +2 -0
- package/dist/core/ingestion/mro-processor.d.ts +1 -1
- package/dist/core/ingestion/mro-processor.js +12 -8
- package/dist/core/ingestion/named-binding-processor.js +2 -2
- package/dist/core/ingestion/named-bindings/rust.js +3 -1
- package/dist/core/ingestion/parsing-processor.js +74 -24
- package/dist/core/ingestion/pipeline.d.ts +2 -1
- package/dist/core/ingestion/pipeline.js +208 -102
- package/dist/core/ingestion/process-processor.js +12 -10
- package/dist/core/ingestion/resolution-context.js +3 -3
- package/dist/core/ingestion/route-extractors/middleware.js +31 -7
- package/dist/core/ingestion/route-extractors/php.js +2 -1
- package/dist/core/ingestion/route-extractors/response-shapes.js +8 -4
- package/dist/core/ingestion/structure-processor.d.ts +1 -1
- package/dist/core/ingestion/structure-processor.js +4 -4
- package/dist/core/ingestion/symbol-table.d.ts +1 -1
- package/dist/core/ingestion/symbol-table.js +22 -6
- package/dist/core/ingestion/tree-sitter-queries.d.ts +1 -1
- package/dist/core/ingestion/tree-sitter-queries.js +1 -1
- package/dist/core/ingestion/type-env.d.ts +2 -2
- package/dist/core/ingestion/type-env.js +75 -50
- package/dist/core/ingestion/type-extractors/c-cpp.js +33 -30
- package/dist/core/ingestion/type-extractors/csharp.js +24 -14
- package/dist/core/ingestion/type-extractors/dart.js +6 -8
- package/dist/core/ingestion/type-extractors/go.js +7 -6
- package/dist/core/ingestion/type-extractors/jvm.js +10 -21
- package/dist/core/ingestion/type-extractors/php.js +26 -13
- package/dist/core/ingestion/type-extractors/python.js +11 -15
- package/dist/core/ingestion/type-extractors/ruby.js +8 -3
- package/dist/core/ingestion/type-extractors/rust.js +6 -8
- package/dist/core/ingestion/type-extractors/shared.js +134 -50
- package/dist/core/ingestion/type-extractors/swift.js +16 -13
- package/dist/core/ingestion/type-extractors/typescript.js +23 -15
- package/dist/core/ingestion/utils/ast-helpers.d.ts +8 -8
- package/dist/core/ingestion/utils/ast-helpers.js +72 -35
- package/dist/core/ingestion/utils/call-analysis.d.ts +2 -0
- package/dist/core/ingestion/utils/call-analysis.js +96 -49
- package/dist/core/ingestion/utils/event-loop.js +1 -1
- package/dist/core/ingestion/workers/parse-worker.d.ts +7 -2
- package/dist/core/ingestion/workers/parse-worker.js +364 -84
- package/dist/core/ingestion/workers/worker-pool.js +5 -10
- package/dist/core/lbug/csv-generator.js +54 -15
- package/dist/core/lbug/lbug-adapter.d.ts +5 -0
- package/dist/core/lbug/lbug-adapter.js +86 -23
- package/dist/core/lbug/schema.d.ts +3 -6
- package/dist/core/lbug/schema.js +6 -30
- package/dist/core/run-analyze.d.ts +49 -0
- package/dist/core/run-analyze.js +257 -0
- package/dist/core/tree-sitter/parser-loader.d.ts +1 -1
- package/dist/core/tree-sitter/parser-loader.js +1 -1
- package/dist/core/wiki/cursor-client.js +2 -7
- package/dist/core/wiki/generator.js +38 -23
- package/dist/core/wiki/graph-queries.js +10 -10
- package/dist/core/wiki/html-viewer.js +7 -3
- package/dist/core/wiki/llm-client.d.ts +23 -2
- package/dist/core/wiki/llm-client.js +96 -26
- package/dist/core/wiki/prompts.js +7 -6
- package/dist/mcp/core/embedder.js +1 -1
- package/dist/mcp/core/lbug-adapter.d.ts +4 -1
- package/dist/mcp/core/lbug-adapter.js +17 -7
- package/dist/mcp/local/local-backend.js +247 -95
- package/dist/mcp/resources.js +14 -6
- package/dist/mcp/server.js +13 -5
- package/dist/mcp/staleness.js +5 -1
- package/dist/mcp/tools.js +100 -23
- package/dist/server/analyze-job.d.ts +53 -0
- package/dist/server/analyze-job.js +146 -0
- package/dist/server/analyze-worker.d.ts +13 -0
- package/dist/server/analyze-worker.js +59 -0
- package/dist/server/api.js +795 -44
- package/dist/server/git-clone.d.ts +25 -0
- package/dist/server/git-clone.js +91 -0
- package/dist/storage/git.js +1 -3
- package/dist/storage/repo-manager.d.ts +5 -2
- package/dist/storage/repo-manager.js +4 -4
- package/dist/types/pipeline.d.ts +1 -21
- package/dist/types/pipeline.js +1 -18
- package/hooks/claude/gitnexus-hook.cjs +52 -22
- package/package.json +3 -2
- package/dist/core/ingestion/utils/language-detection.d.ts +0 -9
- package/dist/core/ingestion/utils/language-detection.js +0 -70
|
@@ -72,31 +72,26 @@ export const createWorkerPool = (workerUrl, poolSize) => {
|
|
|
72
72
|
const handler = (msg) => {
|
|
73
73
|
if (settled)
|
|
74
74
|
return;
|
|
75
|
-
if (msg
|
|
75
|
+
if (msg.type === 'progress') {
|
|
76
76
|
workerProgress[i] = msg.filesProcessed;
|
|
77
77
|
if (onProgress) {
|
|
78
78
|
const total = workerProgress.reduce((a, b) => a + b, 0);
|
|
79
79
|
onProgress(total);
|
|
80
80
|
}
|
|
81
81
|
}
|
|
82
|
-
else if (msg
|
|
82
|
+
else if (msg.type === 'sub-batch-done') {
|
|
83
83
|
sendNextSubBatch();
|
|
84
84
|
}
|
|
85
|
-
else if (msg
|
|
85
|
+
else if (msg.type === 'error') {
|
|
86
86
|
settled = true;
|
|
87
87
|
cleanup();
|
|
88
88
|
reject(new Error(`Worker ${i} error: ${msg.error}`));
|
|
89
89
|
}
|
|
90
|
-
else if (msg
|
|
90
|
+
else if (msg.type === 'result') {
|
|
91
91
|
settled = true;
|
|
92
92
|
cleanup();
|
|
93
93
|
resolve(msg.data);
|
|
94
94
|
}
|
|
95
|
-
else {
|
|
96
|
-
settled = true;
|
|
97
|
-
cleanup();
|
|
98
|
-
resolve(msg);
|
|
99
|
-
}
|
|
100
95
|
};
|
|
101
96
|
const errorHandler = (err) => {
|
|
102
97
|
if (!settled) {
|
|
@@ -121,7 +116,7 @@ export const createWorkerPool = (workerUrl, poolSize) => {
|
|
|
121
116
|
return Promise.all(promises);
|
|
122
117
|
};
|
|
123
118
|
const terminate = async () => {
|
|
124
|
-
await Promise.all(workers.map(w => w.terminate()));
|
|
119
|
+
await Promise.all(workers.map((w) => w.terminate()));
|
|
125
120
|
workers.length = 0;
|
|
126
121
|
};
|
|
127
122
|
return { dispatch, terminate, size };
|
|
@@ -49,10 +49,10 @@ export const isBinaryContent = (content) => {
|
|
|
49
49
|
let nonPrintable = 0;
|
|
50
50
|
for (let i = 0; i < sample.length; i++) {
|
|
51
51
|
const code = sample.charCodeAt(i);
|
|
52
|
-
if (
|
|
52
|
+
if (code < 9 || (code > 13 && code < 32) || code === 127)
|
|
53
53
|
nonPrintable++;
|
|
54
54
|
}
|
|
55
|
-
return
|
|
55
|
+
return nonPrintable / sample.length > 0.1;
|
|
56
56
|
};
|
|
57
57
|
/**
|
|
58
58
|
* LRU content cache — avoids re-reading the same source file for every
|
|
@@ -216,17 +216,35 @@ export const streamAllCSVsToDisk = async (graph, repoPath, csvDir) => {
|
|
|
216
216
|
const toolWriter = new BufferedCSVWriter(path.join(csvDir, 'tool.csv'), 'id,name,filePath,description');
|
|
217
217
|
// Multi-language node types share the same CSV shape (no isExported column)
|
|
218
218
|
const multiLangHeader = 'id,name,filePath,startLine,endLine,content,description';
|
|
219
|
-
const MULTI_LANG_TYPES = [
|
|
220
|
-
'
|
|
219
|
+
const MULTI_LANG_TYPES = [
|
|
220
|
+
'Struct',
|
|
221
|
+
'Enum',
|
|
222
|
+
'Macro',
|
|
223
|
+
'Typedef',
|
|
224
|
+
'Union',
|
|
225
|
+
'Namespace',
|
|
226
|
+
'Trait',
|
|
227
|
+
'Impl',
|
|
228
|
+
'TypeAlias',
|
|
229
|
+
'Const',
|
|
230
|
+
'Static',
|
|
231
|
+
'Property',
|
|
232
|
+
'Record',
|
|
233
|
+
'Delegate',
|
|
234
|
+
'Annotation',
|
|
235
|
+
'Constructor',
|
|
236
|
+
'Template',
|
|
237
|
+
'Module',
|
|
238
|
+
];
|
|
221
239
|
const multiLangWriters = new Map();
|
|
222
240
|
for (const t of MULTI_LANG_TYPES) {
|
|
223
241
|
multiLangWriters.set(t, new BufferedCSVWriter(path.join(csvDir, `${t.toLowerCase()}.csv`), multiLangHeader));
|
|
224
242
|
}
|
|
225
243
|
const codeWriterMap = {
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
244
|
+
Function: functionWriter,
|
|
245
|
+
Class: classWriter,
|
|
246
|
+
Interface: interfaceWriter,
|
|
247
|
+
CodeElement: codeElemWriter,
|
|
230
248
|
};
|
|
231
249
|
const seenFileIds = new Set();
|
|
232
250
|
// --- SINGLE PASS over all nodes ---
|
|
@@ -376,8 +394,22 @@ export const streamAllCSVsToDisk = async (graph, repoPath, csvDir) => {
|
|
|
376
394
|
}
|
|
377
395
|
}
|
|
378
396
|
// Finish all node writers
|
|
379
|
-
const allWriters = [
|
|
380
|
-
|
|
397
|
+
const allWriters = [
|
|
398
|
+
fileWriter,
|
|
399
|
+
folderWriter,
|
|
400
|
+
functionWriter,
|
|
401
|
+
classWriter,
|
|
402
|
+
interfaceWriter,
|
|
403
|
+
methodWriter,
|
|
404
|
+
codeElemWriter,
|
|
405
|
+
communityWriter,
|
|
406
|
+
processWriter,
|
|
407
|
+
sectionWriter,
|
|
408
|
+
routeWriter,
|
|
409
|
+
toolWriter,
|
|
410
|
+
...multiLangWriters.values(),
|
|
411
|
+
];
|
|
412
|
+
await Promise.all(allWriters.map((w) => w.finish()));
|
|
381
413
|
// --- Stream relationship CSV ---
|
|
382
414
|
const relCsvPath = path.join(csvDir, 'relations.csv');
|
|
383
415
|
const relWriter = new BufferedCSVWriter(relCsvPath, 'from,to,type,confidence,reason,step');
|
|
@@ -395,11 +427,15 @@ export const streamAllCSVsToDisk = async (graph, repoPath, csvDir) => {
|
|
|
395
427
|
// Build result map — only include tables that have rows
|
|
396
428
|
const nodeFiles = new Map();
|
|
397
429
|
const tableMap = [
|
|
398
|
-
['File', fileWriter],
|
|
399
|
-
['
|
|
400
|
-
['
|
|
430
|
+
['File', fileWriter],
|
|
431
|
+
['Folder', folderWriter],
|
|
432
|
+
['Function', functionWriter],
|
|
433
|
+
['Class', classWriter],
|
|
434
|
+
['Interface', interfaceWriter],
|
|
435
|
+
['Method', methodWriter],
|
|
401
436
|
['CodeElement', codeElemWriter],
|
|
402
|
-
['Community', communityWriter],
|
|
437
|
+
['Community', communityWriter],
|
|
438
|
+
['Process', processWriter],
|
|
403
439
|
['Section', sectionWriter],
|
|
404
440
|
['Route', routeWriter],
|
|
405
441
|
['Tool', toolWriter],
|
|
@@ -407,7 +443,10 @@ export const streamAllCSVsToDisk = async (graph, repoPath, csvDir) => {
|
|
|
407
443
|
];
|
|
408
444
|
for (const [name, writer] of tableMap) {
|
|
409
445
|
if (writer.rows > 0) {
|
|
410
|
-
nodeFiles.set(name, {
|
|
446
|
+
nodeFiles.set(name, {
|
|
447
|
+
csvPath: path.join(csvDir, `${name.toLowerCase()}.csv`),
|
|
448
|
+
rows: writer.rows,
|
|
449
|
+
});
|
|
411
450
|
}
|
|
412
451
|
}
|
|
413
452
|
// Restore original process listener limit
|
|
@@ -49,6 +49,11 @@ export declare const batchInsertNodesToLbug: (nodes: Array<{
|
|
|
49
49
|
failed: number;
|
|
50
50
|
}>;
|
|
51
51
|
export declare const executeQuery: (cypher: string) => Promise<any[]>;
|
|
52
|
+
/**
|
|
53
|
+
* Execute a single parameterized query (prepare/execute pattern).
|
|
54
|
+
* Prevents Cypher injection by binding values as parameters.
|
|
55
|
+
*/
|
|
56
|
+
export declare const executePrepared: (cypher: string, params: Record<string, any>) => Promise<any[]>;
|
|
52
57
|
export declare const executeWithReusedStatement: (cypher: string, paramsList: Array<Record<string, any>>) => Promise<void>;
|
|
53
58
|
export declare const getLbugStats: () => Promise<{
|
|
54
59
|
nodes: number;
|
|
@@ -25,15 +25,15 @@ const DB_LOCK_RETRY_DELAY_MS = 500;
|
|
|
25
25
|
*/
|
|
26
26
|
export const isDbBusyError = (err) => {
|
|
27
27
|
const msg = (err instanceof Error ? err.message : String(err)).toLowerCase();
|
|
28
|
-
return (msg.includes('busy')
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
28
|
+
return (msg.includes('busy') ||
|
|
29
|
+
msg.includes('lock') ||
|
|
30
|
+
msg.includes('already in use') ||
|
|
31
|
+
msg.includes('could not set lock'));
|
|
32
32
|
};
|
|
33
33
|
const runWithSessionLock = async (operation) => {
|
|
34
34
|
const previous = sessionLock;
|
|
35
35
|
let release = null;
|
|
36
|
-
sessionLock = new Promise(resolve => {
|
|
36
|
+
sessionLock = new Promise((resolve) => {
|
|
37
37
|
release = resolve;
|
|
38
38
|
});
|
|
39
39
|
await previous;
|
|
@@ -77,19 +77,23 @@ export const withLbugDb = async (dbPath, operation) => {
|
|
|
77
77
|
if (conn)
|
|
78
78
|
await conn.close();
|
|
79
79
|
}
|
|
80
|
-
catch {
|
|
80
|
+
catch {
|
|
81
|
+
/* best-effort */
|
|
82
|
+
}
|
|
81
83
|
try {
|
|
82
84
|
if (db)
|
|
83
85
|
await db.close();
|
|
84
86
|
}
|
|
85
|
-
catch {
|
|
87
|
+
catch {
|
|
88
|
+
/* best-effort */
|
|
89
|
+
}
|
|
86
90
|
conn = null;
|
|
87
91
|
db = null;
|
|
88
92
|
currentDbPath = null;
|
|
89
93
|
ftsLoaded = false;
|
|
90
94
|
});
|
|
91
95
|
// Sleep outside the lock — no need to block others while waiting
|
|
92
|
-
await new Promise(resolve => setTimeout(resolve, DB_LOCK_RETRY_DELAY_MS * attempt));
|
|
96
|
+
await new Promise((resolve) => setTimeout(resolve, DB_LOCK_RETRY_DELAY_MS * attempt));
|
|
93
97
|
}
|
|
94
98
|
}
|
|
95
99
|
// This line is unreachable — the loop either returns or throws inside,
|
|
@@ -212,7 +216,10 @@ export const loadGraphToLbug = async (graph, repoPath, storagePath, onProgress)
|
|
|
212
216
|
let skippedRels = 0;
|
|
213
217
|
let totalValidRels = 0;
|
|
214
218
|
await new Promise((resolve, reject) => {
|
|
215
|
-
const rl = createInterface({
|
|
219
|
+
const rl = createInterface({
|
|
220
|
+
input: createReadStream(csvResult.relCsvPath, 'utf-8'),
|
|
221
|
+
crlfDelay: Infinity,
|
|
222
|
+
});
|
|
216
223
|
let isFirst = true;
|
|
217
224
|
rl.on('line', (line) => {
|
|
218
225
|
if (isFirst) {
|
|
@@ -322,9 +329,24 @@ const COPY_CSV_OPTS = `(HEADER=true, ESCAPE='"', DELIM=',', QUOTE='"', PARALLEL=
|
|
|
322
329
|
// Multi-language table names that were created with backticks in CODE_ELEMENT_BASE
|
|
323
330
|
// and must always be referenced with backticks in queries
|
|
324
331
|
const BACKTICK_TABLES = new Set([
|
|
325
|
-
'Struct',
|
|
326
|
-
'
|
|
327
|
-
'
|
|
332
|
+
'Struct',
|
|
333
|
+
'Enum',
|
|
334
|
+
'Macro',
|
|
335
|
+
'Typedef',
|
|
336
|
+
'Union',
|
|
337
|
+
'Namespace',
|
|
338
|
+
'Trait',
|
|
339
|
+
'Impl',
|
|
340
|
+
'TypeAlias',
|
|
341
|
+
'Const',
|
|
342
|
+
'Static',
|
|
343
|
+
'Property',
|
|
344
|
+
'Record',
|
|
345
|
+
'Delegate',
|
|
346
|
+
'Annotation',
|
|
347
|
+
'Constructor',
|
|
348
|
+
'Template',
|
|
349
|
+
'Module',
|
|
328
350
|
]);
|
|
329
351
|
const escapeTableName = (table) => {
|
|
330
352
|
return BACKTICK_TABLES.has(table) ? `\`${table}\`` : table;
|
|
@@ -362,7 +384,13 @@ const fallbackRelationshipInserts = async (validRelLines, validTables, getNodeLa
|
|
|
362
384
|
}
|
|
363
385
|
};
|
|
364
386
|
/** Tables with isExported column (TypeScript/JS-native types) */
|
|
365
|
-
const TABLES_WITH_EXPORTED = new Set([
|
|
387
|
+
const TABLES_WITH_EXPORTED = new Set([
|
|
388
|
+
'Function',
|
|
389
|
+
'Class',
|
|
390
|
+
'Interface',
|
|
391
|
+
'Method',
|
|
392
|
+
'CodeElement',
|
|
393
|
+
]);
|
|
366
394
|
const getCopyQuery = (table, filePath) => {
|
|
367
395
|
const t = escapeTableName(table);
|
|
368
396
|
if (table === 'File') {
|
|
@@ -427,16 +455,22 @@ export const insertNodeToLbug = async (label, properties, dbPath) => {
|
|
|
427
455
|
query = `CREATE (n:Folder {id: ${escapeValue(properties.id)}, name: ${escapeValue(properties.name)}, filePath: ${escapeValue(properties.filePath)}})`;
|
|
428
456
|
}
|
|
429
457
|
else if (label === 'Section') {
|
|
430
|
-
const descPart = properties.description
|
|
458
|
+
const descPart = properties.description
|
|
459
|
+
? `, description: ${escapeValue(properties.description)}`
|
|
460
|
+
: '';
|
|
431
461
|
query = `CREATE (n:Section {id: ${escapeValue(properties.id)}, name: ${escapeValue(properties.name)}, filePath: ${escapeValue(properties.filePath)}, startLine: ${properties.startLine || 0}, endLine: ${properties.endLine || 0}, level: ${properties.level || 1}, content: ${escapeValue(properties.content || '')}${descPart}})`;
|
|
432
462
|
}
|
|
433
463
|
else if (TABLES_WITH_EXPORTED.has(label)) {
|
|
434
|
-
const descPart = properties.description
|
|
464
|
+
const descPart = properties.description
|
|
465
|
+
? `, description: ${escapeValue(properties.description)}`
|
|
466
|
+
: '';
|
|
435
467
|
query = `CREATE (n:${t} {id: ${escapeValue(properties.id)}, name: ${escapeValue(properties.name)}, filePath: ${escapeValue(properties.filePath)}, startLine: ${properties.startLine || 0}, endLine: ${properties.endLine || 0}, isExported: ${!!properties.isExported}, content: ${escapeValue(properties.content || '')}${descPart}})`;
|
|
436
468
|
}
|
|
437
469
|
else {
|
|
438
470
|
// Multi-language tables (Struct, Impl, Trait, Macro, etc.) — no isExported
|
|
439
|
-
const descPart = properties.description
|
|
471
|
+
const descPart = properties.description
|
|
472
|
+
? `, description: ${escapeValue(properties.description)}`
|
|
473
|
+
: '';
|
|
440
474
|
query = `CREATE (n:${t} {id: ${escapeValue(properties.id)}, name: ${escapeValue(properties.name)}, filePath: ${escapeValue(properties.filePath)}, startLine: ${properties.startLine || 0}, endLine: ${properties.endLine || 0}, content: ${escapeValue(properties.content || '')}${descPart}})`;
|
|
441
475
|
}
|
|
442
476
|
// Use per-query connection if dbPath provided (avoids lock conflicts)
|
|
@@ -506,15 +540,21 @@ export const batchInsertNodesToLbug = async (nodes, dbPath) => {
|
|
|
506
540
|
query = `MERGE (n:Folder {id: ${escapeValue(properties.id)}}) SET n.name = ${escapeValue(properties.name)}, n.filePath = ${escapeValue(properties.filePath)}`;
|
|
507
541
|
}
|
|
508
542
|
else if (label === 'Section') {
|
|
509
|
-
const descPart = properties.description
|
|
543
|
+
const descPart = properties.description
|
|
544
|
+
? `, n.description = ${escapeValue(properties.description)}`
|
|
545
|
+
: '';
|
|
510
546
|
query = `MERGE (n:Section {id: ${escapeValue(properties.id)}}) SET n.name = ${escapeValue(properties.name)}, n.filePath = ${escapeValue(properties.filePath)}, n.startLine = ${properties.startLine || 0}, n.endLine = ${properties.endLine || 0}, n.level = ${properties.level || 1}, n.content = ${escapeValue(properties.content || '')}${descPart}`;
|
|
511
547
|
}
|
|
512
548
|
else if (TABLES_WITH_EXPORTED.has(label)) {
|
|
513
|
-
const descPart = properties.description
|
|
549
|
+
const descPart = properties.description
|
|
550
|
+
? `, n.description = ${escapeValue(properties.description)}`
|
|
551
|
+
: '';
|
|
514
552
|
query = `MERGE (n:${t} {id: ${escapeValue(properties.id)}}) SET n.name = ${escapeValue(properties.name)}, n.filePath = ${escapeValue(properties.filePath)}, n.startLine = ${properties.startLine || 0}, n.endLine = ${properties.endLine || 0}, n.isExported = ${!!properties.isExported}, n.content = ${escapeValue(properties.content || '')}${descPart}`;
|
|
515
553
|
}
|
|
516
554
|
else {
|
|
517
|
-
const descPart = properties.description
|
|
555
|
+
const descPart = properties.description
|
|
556
|
+
? `, n.description = ${escapeValue(properties.description)}`
|
|
557
|
+
: '';
|
|
518
558
|
query = `MERGE (n:${t} {id: ${escapeValue(properties.id)}}) SET n.name = ${escapeValue(properties.name)}, n.filePath = ${escapeValue(properties.filePath)}, n.startLine = ${properties.startLine || 0}, n.endLine = ${properties.endLine || 0}, n.content = ${escapeValue(properties.content || '')}${descPart}`;
|
|
519
559
|
}
|
|
520
560
|
await tempConn.query(query);
|
|
@@ -549,6 +589,23 @@ export const executeQuery = async (cypher) => {
|
|
|
549
589
|
const rows = await result.getAll();
|
|
550
590
|
return rows;
|
|
551
591
|
};
|
|
592
|
+
/**
|
|
593
|
+
* Execute a single parameterized query (prepare/execute pattern).
|
|
594
|
+
* Prevents Cypher injection by binding values as parameters.
|
|
595
|
+
*/
|
|
596
|
+
export const executePrepared = async (cypher, params) => {
|
|
597
|
+
if (!conn) {
|
|
598
|
+
throw new Error('LadybugDB not initialized. Call initLbug first.');
|
|
599
|
+
}
|
|
600
|
+
const stmt = await conn.prepare(cypher);
|
|
601
|
+
if (!stmt.isSuccess()) {
|
|
602
|
+
const errMsg = await stmt.getErrorMessage();
|
|
603
|
+
throw new Error(`Prepare failed: ${errMsg}`);
|
|
604
|
+
}
|
|
605
|
+
const queryResult = await conn.execute(stmt, params);
|
|
606
|
+
const result = Array.isArray(queryResult) ? queryResult[0] : queryResult;
|
|
607
|
+
return await result.getAll();
|
|
608
|
+
};
|
|
552
609
|
export const executeWithReusedStatement = async (cypher, paramsList) => {
|
|
553
610
|
if (!conn) {
|
|
554
611
|
throw new Error('LadybugDB not initialized. Call initLbug first.');
|
|
@@ -629,12 +686,16 @@ export const loadCachedEmbeddings = async () => {
|
|
|
629
686
|
if (embedding) {
|
|
630
687
|
embeddings.push({
|
|
631
688
|
nodeId,
|
|
632
|
-
embedding: Array.isArray(embedding)
|
|
689
|
+
embedding: Array.isArray(embedding)
|
|
690
|
+
? embedding.map(Number)
|
|
691
|
+
: Array.from(embedding).map(Number),
|
|
633
692
|
});
|
|
634
693
|
}
|
|
635
694
|
}
|
|
636
695
|
}
|
|
637
|
-
catch {
|
|
696
|
+
catch {
|
|
697
|
+
/* embedding table may not exist */
|
|
698
|
+
}
|
|
638
699
|
return { embeddingNodeIds, embeddings };
|
|
639
700
|
};
|
|
640
701
|
export const closeLbug = async () => {
|
|
@@ -748,7 +809,9 @@ export const loadFTSExtension = async () => {
|
|
|
748
809
|
}
|
|
749
810
|
catch (err) {
|
|
750
811
|
const msg = err?.message || '';
|
|
751
|
-
if (msg.includes('already loaded') ||
|
|
812
|
+
if (msg.includes('already loaded') ||
|
|
813
|
+
msg.includes('already installed') ||
|
|
814
|
+
msg.includes('already exists')) {
|
|
752
815
|
ftsLoaded = true;
|
|
753
816
|
}
|
|
754
817
|
else {
|
|
@@ -768,7 +831,7 @@ export const createFTSIndex = async (tableName, indexName, properties, stemmer =
|
|
|
768
831
|
throw new Error('LadybugDB not initialized. Call initLbug first.');
|
|
769
832
|
}
|
|
770
833
|
await loadFTSExtension();
|
|
771
|
-
const propList = properties.map(p => `'${p}'`).join(', ');
|
|
834
|
+
const propList = properties.map((p) => `'${p}'`).join(', ');
|
|
772
835
|
const query = `CALL CREATE_FTS_INDEX('${tableName}', '${indexName}', [${propList}], stemmer := '${stemmer}')`;
|
|
773
836
|
try {
|
|
774
837
|
await conn.query(query);
|
|
@@ -8,12 +8,9 @@
|
|
|
8
8
|
* This allows LLMs to write natural Cypher queries like:
|
|
9
9
|
* MATCH (f:Function)-[r:CodeRelation {type: 'CALLS'}]->(g:Function) RETURN f, g
|
|
10
10
|
*/
|
|
11
|
-
|
|
12
|
-
export
|
|
13
|
-
export
|
|
14
|
-
export declare const REL_TYPES: readonly ["CONTAINS", "DEFINES", "IMPORTS", "CALLS", "EXTENDS", "IMPLEMENTS", "HAS_METHOD", "HAS_PROPERTY", "ACCESSES", "OVERRIDES", "MEMBER_OF", "STEP_IN_PROCESS", "HANDLES_ROUTE", "FETCHES", "HANDLES_TOOL", "ENTRY_POINT_OF", "WRAPS", "QUERIES"];
|
|
15
|
-
export type RelType = typeof REL_TYPES[number];
|
|
16
|
-
export declare const EMBEDDING_TABLE_NAME = "CodeEmbedding";
|
|
11
|
+
import { NODE_TABLES, REL_TABLE_NAME, REL_TYPES, EMBEDDING_TABLE_NAME } from 'gitnexus-shared';
|
|
12
|
+
export { NODE_TABLES, REL_TABLE_NAME, REL_TYPES, EMBEDDING_TABLE_NAME };
|
|
13
|
+
export type { NodeTableName, RelType } from 'gitnexus-shared';
|
|
17
14
|
export declare const FILE_SCHEMA = "\nCREATE NODE TABLE File (\n id STRING,\n name STRING,\n filePath STRING,\n content STRING,\n PRIMARY KEY (id)\n)";
|
|
18
15
|
export declare const FOLDER_SCHEMA = "\nCREATE NODE TABLE Folder (\n id STRING,\n name STRING,\n filePath STRING,\n PRIMARY KEY (id)\n)";
|
|
19
16
|
export declare const FUNCTION_SCHEMA = "\nCREATE NODE TABLE Function (\n id STRING,\n name STRING,\n filePath STRING,\n startLine INT64,\n endLine INT64,\n isExported BOOLEAN,\n content STRING,\n description STRING,\n PRIMARY KEY (id)\n)";
|
package/dist/core/lbug/schema.js
CHANGED
|
@@ -8,28 +8,10 @@
|
|
|
8
8
|
* This allows LLMs to write natural Cypher queries like:
|
|
9
9
|
* MATCH (f:Function)-[r:CodeRelation {type: 'CALLS'}]->(g:Function) RETURN f, g
|
|
10
10
|
*/
|
|
11
|
-
//
|
|
12
|
-
|
|
13
|
-
//
|
|
14
|
-
export
|
|
15
|
-
'File', 'Folder', 'Function', 'Class', 'Interface', 'Method', 'CodeElement', 'Community', 'Process', 'Section',
|
|
16
|
-
// Multi-language support
|
|
17
|
-
'Struct', 'Enum', 'Macro', 'Typedef', 'Union', 'Namespace', 'Trait', 'Impl',
|
|
18
|
-
'TypeAlias', 'Const', 'Static', 'Property', 'Record', 'Delegate', 'Annotation', 'Constructor', 'Template', 'Module',
|
|
19
|
-
'Route',
|
|
20
|
-
'Tool'
|
|
21
|
-
];
|
|
22
|
-
// ============================================================================
|
|
23
|
-
// RELATION TABLE
|
|
24
|
-
// ============================================================================
|
|
25
|
-
export const REL_TABLE_NAME = 'CodeRelation';
|
|
26
|
-
// Valid relation types
|
|
27
|
-
// Note: WRAPS is reserved for future middleware graph traversal (not yet emitted)
|
|
28
|
-
export const REL_TYPES = ['CONTAINS', 'DEFINES', 'IMPORTS', 'CALLS', 'EXTENDS', 'IMPLEMENTS', 'HAS_METHOD', 'HAS_PROPERTY', 'ACCESSES', 'OVERRIDES', 'MEMBER_OF', 'STEP_IN_PROCESS', 'HANDLES_ROUTE', 'FETCHES', 'HANDLES_TOOL', 'ENTRY_POINT_OF', 'WRAPS', 'QUERIES'];
|
|
29
|
-
// ============================================================================
|
|
30
|
-
// EMBEDDING TABLE
|
|
31
|
-
// ============================================================================
|
|
32
|
-
export const EMBEDDING_TABLE_NAME = 'CodeEmbedding';
|
|
11
|
+
// Import from shared package (single source of truth) — used in DDL templates below
|
|
12
|
+
import { NODE_TABLES, REL_TABLE_NAME, REL_TYPES, EMBEDDING_TABLE_NAME } from 'gitnexus-shared';
|
|
13
|
+
// Re-export so downstream consumers keep the same import path
|
|
14
|
+
export { NODE_TABLES, REL_TABLE_NAME, REL_TYPES, EMBEDDING_TABLE_NAME };
|
|
33
15
|
// ============================================================================
|
|
34
16
|
// NODE TABLE SCHEMAS
|
|
35
17
|
// ============================================================================
|
|
@@ -481,11 +463,5 @@ export const NODE_SCHEMA_QUERIES = [
|
|
|
481
463
|
// MCP tools
|
|
482
464
|
TOOL_SCHEMA,
|
|
483
465
|
];
|
|
484
|
-
export const REL_SCHEMA_QUERIES = [
|
|
485
|
-
|
|
486
|
-
];
|
|
487
|
-
export const SCHEMA_QUERIES = [
|
|
488
|
-
...NODE_SCHEMA_QUERIES,
|
|
489
|
-
...REL_SCHEMA_QUERIES,
|
|
490
|
-
EMBEDDING_SCHEMA,
|
|
491
|
-
];
|
|
466
|
+
export const REL_SCHEMA_QUERIES = [RELATION_SCHEMA];
|
|
467
|
+
export const SCHEMA_QUERIES = [...NODE_SCHEMA_QUERIES, ...REL_SCHEMA_QUERIES, EMBEDDING_SCHEMA];
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared Analysis Orchestrator
|
|
3
|
+
*
|
|
4
|
+
* Extracts the core analysis pipeline from the CLI analyze command into a
|
|
5
|
+
* reusable function that can be called from both the CLI and a server-side
|
|
6
|
+
* worker process.
|
|
7
|
+
*
|
|
8
|
+
* IMPORTANT: This module must NEVER call process.exit(). The caller (CLI
|
|
9
|
+
* wrapper or server worker) is responsible for process lifecycle.
|
|
10
|
+
*/
|
|
11
|
+
export interface AnalyzeCallbacks {
|
|
12
|
+
onProgress: (phase: string, percent: number, message: string) => void;
|
|
13
|
+
onLog?: (message: string) => void;
|
|
14
|
+
}
|
|
15
|
+
export interface AnalyzeOptions {
|
|
16
|
+
force?: boolean;
|
|
17
|
+
embeddings?: boolean;
|
|
18
|
+
skipGit?: boolean;
|
|
19
|
+
/** Skip AGENTS.md and CLAUDE.md gitnexus block updates. */
|
|
20
|
+
skipAgentsMd?: boolean;
|
|
21
|
+
}
|
|
22
|
+
export interface AnalyzeResult {
|
|
23
|
+
repoName: string;
|
|
24
|
+
repoPath: string;
|
|
25
|
+
stats: {
|
|
26
|
+
files?: number;
|
|
27
|
+
nodes?: number;
|
|
28
|
+
edges?: number;
|
|
29
|
+
communities?: number;
|
|
30
|
+
processes?: number;
|
|
31
|
+
embeddings?: number;
|
|
32
|
+
};
|
|
33
|
+
alreadyUpToDate?: boolean;
|
|
34
|
+
/** The raw pipeline result — only populated when needed by callers (e.g. skill generation). */
|
|
35
|
+
pipelineResult?: any;
|
|
36
|
+
}
|
|
37
|
+
export declare const PHASE_LABELS: Record<string, string>;
|
|
38
|
+
/**
|
|
39
|
+
* Run the full GitNexus analysis pipeline.
|
|
40
|
+
*
|
|
41
|
+
* This is the shared core extracted from the CLI `analyze` command. It
|
|
42
|
+
* handles: pipeline execution, LadybugDB loading, FTS indexing, embedding
|
|
43
|
+
* generation, metadata persistence, and AI context file generation.
|
|
44
|
+
*
|
|
45
|
+
* The function communicates progress and log messages exclusively through
|
|
46
|
+
* the {@link AnalyzeCallbacks} interface — it never writes to stdout/stderr
|
|
47
|
+
* directly and never calls `process.exit()`.
|
|
48
|
+
*/
|
|
49
|
+
export declare function runFullAnalysis(repoPath: string, options: AnalyzeOptions, callbacks: AnalyzeCallbacks): Promise<AnalyzeResult>;
|