gitnexus 1.4.7 → 1.4.8
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 +22 -1
- package/dist/cli/ai-context.d.ts +1 -1
- package/dist/cli/ai-context.js +1 -1
- package/dist/cli/analyze.d.ts +2 -0
- package/dist/cli/analyze.js +54 -21
- package/dist/cli/index.js +2 -1
- package/dist/cli/setup.js +78 -1
- package/dist/config/supported-languages.d.ts +30 -0
- package/dist/config/supported-languages.js +30 -0
- package/dist/core/embeddings/embedder.d.ts +6 -1
- package/dist/core/embeddings/embedder.js +65 -5
- package/dist/core/embeddings/embedding-pipeline.js +11 -9
- package/dist/core/embeddings/http-client.d.ts +31 -0
- package/dist/core/embeddings/http-client.js +179 -0
- package/dist/core/embeddings/index.d.ts +1 -0
- package/dist/core/embeddings/index.js +1 -0
- package/dist/core/embeddings/types.d.ts +1 -1
- package/dist/core/graph/types.d.ts +2 -1
- package/dist/core/ingestion/ast-helpers.d.ts +80 -0
- package/dist/core/ingestion/ast-helpers.js +738 -0
- package/dist/core/ingestion/call-analysis.d.ts +73 -0
- package/dist/core/ingestion/call-analysis.js +490 -0
- package/dist/core/ingestion/call-processor.d.ts +48 -1
- package/dist/core/ingestion/call-processor.js +368 -7
- package/dist/core/ingestion/call-routing.d.ts +6 -0
- package/dist/core/ingestion/entry-point-scoring.js +36 -26
- package/dist/core/ingestion/framework-detection.d.ts +10 -2
- package/dist/core/ingestion/framework-detection.js +49 -12
- package/dist/core/ingestion/heritage-processor.js +47 -49
- package/dist/core/ingestion/import-processor.d.ts +1 -1
- package/dist/core/ingestion/import-processor.js +103 -194
- package/dist/core/ingestion/import-resolution.d.ts +101 -0
- package/dist/core/ingestion/import-resolution.js +251 -0
- package/dist/core/ingestion/language-config.d.ts +3 -0
- package/dist/core/ingestion/language-config.js +13 -0
- package/dist/core/ingestion/markdown-processor.d.ts +17 -0
- package/dist/core/ingestion/markdown-processor.js +124 -0
- package/dist/core/ingestion/mro-processor.js +8 -3
- package/dist/core/ingestion/named-binding-extraction.d.ts +9 -43
- package/dist/core/ingestion/named-binding-extraction.js +89 -79
- package/dist/core/ingestion/parsing-processor.d.ts +2 -2
- package/dist/core/ingestion/parsing-processor.js +14 -73
- package/dist/core/ingestion/pipeline.d.ts +10 -0
- package/dist/core/ingestion/pipeline.js +421 -4
- package/dist/core/ingestion/resolution-context.d.ts +5 -0
- package/dist/core/ingestion/resolution-context.js +7 -4
- package/dist/core/ingestion/resolvers/index.d.ts +1 -1
- package/dist/core/ingestion/resolvers/index.js +1 -1
- package/dist/core/ingestion/resolvers/jvm.d.ts +2 -1
- package/dist/core/ingestion/resolvers/jvm.js +25 -9
- package/dist/core/ingestion/resolvers/php.d.ts +14 -0
- package/dist/core/ingestion/resolvers/php.js +43 -3
- package/dist/core/ingestion/resolvers/utils.d.ts +5 -0
- package/dist/core/ingestion/resolvers/utils.js +16 -0
- package/dist/core/ingestion/symbol-table.d.ts +16 -0
- package/dist/core/ingestion/symbol-table.js +20 -6
- package/dist/core/ingestion/tree-sitter-queries.d.ts +4 -4
- package/dist/core/ingestion/tree-sitter-queries.js +43 -2
- package/dist/core/ingestion/type-env.d.ts +28 -1
- package/dist/core/ingestion/type-env.js +419 -96
- package/dist/core/ingestion/type-extractors/c-cpp.d.ts +5 -0
- package/dist/core/ingestion/type-extractors/c-cpp.js +119 -0
- package/dist/core/ingestion/type-extractors/csharp.js +149 -16
- package/dist/core/ingestion/type-extractors/index.d.ts +1 -1
- package/dist/core/ingestion/type-extractors/index.js +1 -1
- package/dist/core/ingestion/type-extractors/jvm.js +169 -66
- package/dist/core/ingestion/type-extractors/rust.js +35 -1
- package/dist/core/ingestion/type-extractors/shared.d.ts +0 -2
- package/dist/core/ingestion/type-extractors/shared.js +5 -10
- package/dist/core/ingestion/type-extractors/swift.js +7 -6
- package/dist/core/ingestion/type-extractors/types.d.ts +37 -7
- package/dist/core/ingestion/type-extractors/typescript.js +141 -9
- package/dist/core/ingestion/utils.d.ts +2 -120
- package/dist/core/ingestion/utils.js +3 -1051
- package/dist/core/ingestion/workers/parse-worker.d.ts +13 -4
- package/dist/core/ingestion/workers/parse-worker.js +66 -87
- package/dist/core/lbug/csv-generator.js +18 -1
- package/dist/core/lbug/lbug-adapter.d.ts +10 -0
- package/dist/core/lbug/lbug-adapter.js +69 -4
- package/dist/core/lbug/schema.d.ts +5 -3
- package/dist/core/lbug/schema.js +26 -2
- package/dist/mcp/core/embedder.js +11 -3
- package/dist/mcp/core/lbug-adapter.js +12 -1
- package/dist/mcp/local/local-backend.d.ts +22 -0
- package/dist/mcp/local/local-backend.js +133 -29
- package/dist/mcp/resources.js +2 -0
- package/dist/mcp/tools.js +2 -2
- package/dist/server/api.d.ts +19 -1
- package/dist/server/api.js +66 -6
- package/dist/storage/git.d.ts +12 -0
- package/dist/storage/git.js +21 -0
- package/package.json +10 -2
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { SupportedLanguages } from '../../../config/supported-languages.js';
|
|
2
2
|
import { type MixedChainStep } from '../utils.js';
|
|
3
3
|
import type { ConstructorBinding } from '../type-env.js';
|
|
4
|
+
import type { NamedBinding } from '../import-resolution.js';
|
|
4
5
|
import type { NodeLabel } from '../../graph/types.js';
|
|
5
6
|
interface ParsedNode {
|
|
6
7
|
id: string;
|
|
@@ -16,6 +17,7 @@ interface ParsedNode {
|
|
|
16
17
|
astFrameworkReason?: string;
|
|
17
18
|
description?: string;
|
|
18
19
|
parameterCount?: number;
|
|
20
|
+
requiredParameterCount?: number;
|
|
19
21
|
returnType?: string;
|
|
20
22
|
};
|
|
21
23
|
}
|
|
@@ -33,6 +35,8 @@ interface ParsedSymbol {
|
|
|
33
35
|
nodeId: string;
|
|
34
36
|
type: NodeLabel;
|
|
35
37
|
parameterCount?: number;
|
|
38
|
+
requiredParameterCount?: number;
|
|
39
|
+
parameterTypes?: string[];
|
|
36
40
|
returnType?: string;
|
|
37
41
|
declaredType?: string;
|
|
38
42
|
ownerId?: string;
|
|
@@ -42,10 +46,7 @@ export interface ExtractedImport {
|
|
|
42
46
|
rawImportPath: string;
|
|
43
47
|
language: SupportedLanguages;
|
|
44
48
|
/** Named bindings from the import (e.g., import {User as U} → [{local:'U', exported:'User'}]) */
|
|
45
|
-
namedBindings?:
|
|
46
|
-
local: string;
|
|
47
|
-
exported: string;
|
|
48
|
-
}[];
|
|
49
|
+
namedBindings?: NamedBinding[];
|
|
49
50
|
}
|
|
50
51
|
export interface ExtractedCall {
|
|
51
52
|
filePath: string;
|
|
@@ -102,6 +103,12 @@ export interface FileConstructorBindings {
|
|
|
102
103
|
filePath: string;
|
|
103
104
|
bindings: ConstructorBinding[];
|
|
104
105
|
}
|
|
106
|
+
/** File-scope type bindings from TypeEnv fixpoint — used for cross-file ExportedTypeMap. */
|
|
107
|
+
export interface FileTypeEnvBindings {
|
|
108
|
+
filePath: string;
|
|
109
|
+
/** [varName, typeName] pairs from file scope (scope = '') */
|
|
110
|
+
bindings: [string, string][];
|
|
111
|
+
}
|
|
105
112
|
export interface ParseWorkerResult {
|
|
106
113
|
nodes: ParsedNode[];
|
|
107
114
|
relationships: ParsedRelationship[];
|
|
@@ -112,6 +119,8 @@ export interface ParseWorkerResult {
|
|
|
112
119
|
heritage: ExtractedHeritage[];
|
|
113
120
|
routes: ExtractedRoute[];
|
|
114
121
|
constructorBindings: FileConstructorBindings[];
|
|
122
|
+
/** File-scope type bindings from TypeEnv fixpoint for exported symbol collection. */
|
|
123
|
+
typeEnvBindings: FileTypeEnvBindings[];
|
|
115
124
|
skippedLanguages: Record<string, number>;
|
|
116
125
|
fileCount: number;
|
|
117
126
|
}
|
|
@@ -28,14 +28,13 @@ try {
|
|
|
28
28
|
Kotlin = _require('tree-sitter-kotlin');
|
|
29
29
|
}
|
|
30
30
|
catch { }
|
|
31
|
-
import { getLanguageFromFilename, FUNCTION_NODE_TYPES, extractFunctionName, isBuiltInOrNoise, getDefinitionNodeFromCaptures, findEnclosingClassId, extractMethodSignature, countCallArguments, inferCallForm, extractReceiverName, extractReceiverNode, extractMixedChain, } from '../utils.js';
|
|
31
|
+
import { getLanguageFromFilename, FUNCTION_NODE_TYPES, extractFunctionName, isBuiltInOrNoise, getDefinitionNodeFromCaptures, findEnclosingClassId, getLabelFromCaptures, extractMethodSignature, countCallArguments, inferCallForm, extractReceiverName, extractReceiverNode, extractMixedChain, } from '../utils.js';
|
|
32
32
|
import { buildTypeEnv } from '../type-env.js';
|
|
33
33
|
import { isNodeExported } from '../export-detection.js';
|
|
34
34
|
import { detectFrameworkFromAST } from '../framework-detection.js';
|
|
35
35
|
import { typeConfigs } from '../type-extractors/index.js';
|
|
36
36
|
import { generateId } from '../../../lib/utils.js';
|
|
37
|
-
import {
|
|
38
|
-
import { appendKotlinWildcard } from '../resolvers/index.js';
|
|
37
|
+
import { namedBindingExtractors, preprocessImportPath } from '../import-resolution.js';
|
|
39
38
|
import { callRouters } from '../call-routing.js';
|
|
40
39
|
import { extractPropertyDeclaredType } from '../type-extractors/shared.js';
|
|
41
40
|
// ============================================================================
|
|
@@ -97,61 +96,7 @@ const findEnclosingFunctionId = (node, filePath) => {
|
|
|
97
96
|
}
|
|
98
97
|
return null;
|
|
99
98
|
};
|
|
100
|
-
//
|
|
101
|
-
// Label detection from capture map
|
|
102
|
-
// ============================================================================
|
|
103
|
-
const getLabelFromCaptures = (captureMap) => {
|
|
104
|
-
// Skip imports (handled separately) and calls
|
|
105
|
-
if (captureMap['import'] || captureMap['call'])
|
|
106
|
-
return null;
|
|
107
|
-
if (!captureMap['name'])
|
|
108
|
-
return null;
|
|
109
|
-
if (captureMap['definition.function'])
|
|
110
|
-
return 'Function';
|
|
111
|
-
if (captureMap['definition.class'])
|
|
112
|
-
return 'Class';
|
|
113
|
-
if (captureMap['definition.interface'])
|
|
114
|
-
return 'Interface';
|
|
115
|
-
if (captureMap['definition.method'])
|
|
116
|
-
return 'Method';
|
|
117
|
-
if (captureMap['definition.struct'])
|
|
118
|
-
return 'Struct';
|
|
119
|
-
if (captureMap['definition.enum'])
|
|
120
|
-
return 'Enum';
|
|
121
|
-
if (captureMap['definition.namespace'])
|
|
122
|
-
return 'Namespace';
|
|
123
|
-
if (captureMap['definition.module'])
|
|
124
|
-
return 'Module';
|
|
125
|
-
if (captureMap['definition.trait'])
|
|
126
|
-
return 'Trait';
|
|
127
|
-
if (captureMap['definition.impl'])
|
|
128
|
-
return 'Impl';
|
|
129
|
-
if (captureMap['definition.type'])
|
|
130
|
-
return 'TypeAlias';
|
|
131
|
-
if (captureMap['definition.const'])
|
|
132
|
-
return 'Const';
|
|
133
|
-
if (captureMap['definition.static'])
|
|
134
|
-
return 'Static';
|
|
135
|
-
if (captureMap['definition.typedef'])
|
|
136
|
-
return 'Typedef';
|
|
137
|
-
if (captureMap['definition.macro'])
|
|
138
|
-
return 'Macro';
|
|
139
|
-
if (captureMap['definition.union'])
|
|
140
|
-
return 'Union';
|
|
141
|
-
if (captureMap['definition.property'])
|
|
142
|
-
return 'Property';
|
|
143
|
-
if (captureMap['definition.record'])
|
|
144
|
-
return 'Record';
|
|
145
|
-
if (captureMap['definition.delegate'])
|
|
146
|
-
return 'Delegate';
|
|
147
|
-
if (captureMap['definition.annotation'])
|
|
148
|
-
return 'Annotation';
|
|
149
|
-
if (captureMap['definition.constructor'])
|
|
150
|
-
return 'Constructor';
|
|
151
|
-
if (captureMap['definition.template'])
|
|
152
|
-
return 'Template';
|
|
153
|
-
return 'CodeElement';
|
|
154
|
-
};
|
|
99
|
+
// Label detection moved to shared getLabelFromCaptures in utils.ts
|
|
155
100
|
// DEFINITION_CAPTURE_KEYS and getDefinitionNodeFromCaptures imported from ../utils.js
|
|
156
101
|
// ============================================================================
|
|
157
102
|
// Process a batch of files
|
|
@@ -167,6 +112,7 @@ const processBatch = (files, onProgress) => {
|
|
|
167
112
|
heritage: [],
|
|
168
113
|
routes: [],
|
|
169
114
|
constructorBindings: [],
|
|
115
|
+
typeEnvBindings: [],
|
|
170
116
|
skippedLanguages: {},
|
|
171
117
|
fileCount: 0,
|
|
172
118
|
};
|
|
@@ -727,13 +673,6 @@ const processFileGroup = (files, language, queryString, result, onFileProcessed)
|
|
|
727
673
|
}
|
|
728
674
|
result.fileCount++;
|
|
729
675
|
onFileProcessed?.();
|
|
730
|
-
// Build per-file type environment + constructor bindings in a single AST walk.
|
|
731
|
-
// Constructor bindings are verified against the SymbolTable in processCallsFromExtracted.
|
|
732
|
-
const typeEnv = buildTypeEnv(tree, language);
|
|
733
|
-
const callRouter = callRouters[language];
|
|
734
|
-
if (typeEnv.constructorBindings.length > 0) {
|
|
735
|
-
result.constructorBindings.push({ filePath: file.path, bindings: [...typeEnv.constructorBindings] });
|
|
736
|
-
}
|
|
737
676
|
let matches;
|
|
738
677
|
try {
|
|
739
678
|
matches = query.matches(tree.rootNode);
|
|
@@ -742,6 +681,51 @@ const processFileGroup = (files, language, queryString, result, onFileProcessed)
|
|
|
742
681
|
console.warn(`Query execution failed for ${file.path}: ${err instanceof Error ? err.message : String(err)}`);
|
|
743
682
|
continue;
|
|
744
683
|
}
|
|
684
|
+
// Pre-pass: extract heritage from query matches to build parentMap for buildTypeEnv.
|
|
685
|
+
// Heritage edges (EXTENDS/IMPLEMENTS) are created by heritage-processor which runs
|
|
686
|
+
// in PARALLEL with call-processor, so the graph edges don't exist when buildTypeEnv
|
|
687
|
+
// runs. This pre-pass makes parent class information available for type resolution.
|
|
688
|
+
const fileParentMap = new Map();
|
|
689
|
+
for (const match of matches) {
|
|
690
|
+
const captureMap = {};
|
|
691
|
+
for (const c of match.captures) {
|
|
692
|
+
captureMap[c.name] = c.node;
|
|
693
|
+
}
|
|
694
|
+
if (captureMap['heritage.class'] && captureMap['heritage.extends']) {
|
|
695
|
+
const className = captureMap['heritage.class'].text;
|
|
696
|
+
const parentName = captureMap['heritage.extends'].text;
|
|
697
|
+
// Skip Go named fields (only anonymous fields are struct embedding)
|
|
698
|
+
const extendsNode = captureMap['heritage.extends'];
|
|
699
|
+
const fieldDecl = extendsNode.parent;
|
|
700
|
+
if (fieldDecl?.type === 'field_declaration' && fieldDecl.childForFieldName('name'))
|
|
701
|
+
continue;
|
|
702
|
+
let parents = fileParentMap.get(className);
|
|
703
|
+
if (!parents) {
|
|
704
|
+
parents = [];
|
|
705
|
+
fileParentMap.set(className, parents);
|
|
706
|
+
}
|
|
707
|
+
if (!parents.includes(parentName))
|
|
708
|
+
parents.push(parentName);
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
// Build per-file type environment + constructor bindings in a single AST walk.
|
|
712
|
+
// Constructor bindings are verified against the SymbolTable in processCallsFromExtracted.
|
|
713
|
+
const parentMap = fileParentMap;
|
|
714
|
+
const typeEnv = buildTypeEnv(tree, language, { parentMap });
|
|
715
|
+
const callRouter = callRouters[language];
|
|
716
|
+
if (typeEnv.constructorBindings.length > 0) {
|
|
717
|
+
result.constructorBindings.push({ filePath: file.path, bindings: [...typeEnv.constructorBindings] });
|
|
718
|
+
}
|
|
719
|
+
// Extract file-scope bindings for ExportedTypeMap (closes worker/sequential quality gap).
|
|
720
|
+
// Sequential path uses collectExportedBindings(typeEnv) directly; worker path serializes
|
|
721
|
+
// these bindings so the main thread can merge them into ExportedTypeMap.
|
|
722
|
+
const fileScope = typeEnv.env.get('');
|
|
723
|
+
if (fileScope && fileScope.size > 0) {
|
|
724
|
+
const bindings = [];
|
|
725
|
+
for (const [name, type] of fileScope)
|
|
726
|
+
bindings.push([name, type]);
|
|
727
|
+
result.typeEnvBindings.push({ filePath: file.path, bindings });
|
|
728
|
+
}
|
|
745
729
|
for (const match of matches) {
|
|
746
730
|
const captureMap = {};
|
|
747
731
|
for (const c of match.captures) {
|
|
@@ -749,10 +733,11 @@ const processFileGroup = (files, language, queryString, result, onFileProcessed)
|
|
|
749
733
|
}
|
|
750
734
|
// Extract import paths before skipping
|
|
751
735
|
if (captureMap['import'] && captureMap['import.source']) {
|
|
752
|
-
const rawImportPath =
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
const
|
|
736
|
+
const rawImportPath = preprocessImportPath(captureMap['import.source'].text, captureMap['import'], language);
|
|
737
|
+
if (!rawImportPath)
|
|
738
|
+
continue;
|
|
739
|
+
const extractor = namedBindingExtractors[language];
|
|
740
|
+
const namedBindings = extractor ? extractor(captureMap['import']) : undefined;
|
|
756
741
|
result.imports.push({
|
|
757
742
|
filePath: file.path,
|
|
758
743
|
rawImportPath,
|
|
@@ -941,24 +926,9 @@ const processFileGroup = (files, language, queryString, result, onFileProcessed)
|
|
|
941
926
|
continue;
|
|
942
927
|
}
|
|
943
928
|
}
|
|
944
|
-
const nodeLabel = getLabelFromCaptures(captureMap);
|
|
929
|
+
const nodeLabel = getLabelFromCaptures(captureMap, language);
|
|
945
930
|
if (!nodeLabel)
|
|
946
931
|
continue;
|
|
947
|
-
// C/C++: @definition.function is broad and also matches inline class methods (inside
|
|
948
|
-
// a class/struct body). Those are already captured by @definition.method, so skip
|
|
949
|
-
// the duplicate Function entry to prevent double-indexing in globalIndex.
|
|
950
|
-
if ((language === SupportedLanguages.CPlusPlus || language === SupportedLanguages.C) &&
|
|
951
|
-
nodeLabel === 'Function') {
|
|
952
|
-
let ancestor = captureMap['definition.function']?.parent;
|
|
953
|
-
while (ancestor) {
|
|
954
|
-
if (ancestor.type === 'class_specifier' || ancestor.type === 'struct_specifier') {
|
|
955
|
-
break; // inside a class body — duplicate of @definition.method
|
|
956
|
-
}
|
|
957
|
-
ancestor = ancestor.parent;
|
|
958
|
-
}
|
|
959
|
-
if (ancestor)
|
|
960
|
-
continue; // found a class/struct ancestor → skip
|
|
961
|
-
}
|
|
962
932
|
const nameNode = captureMap['name'];
|
|
963
933
|
// Synthesize name for constructors without explicit @name capture (e.g. Swift init)
|
|
964
934
|
if (!nameNode && nodeLabel !== 'Constructor')
|
|
@@ -980,11 +950,15 @@ const processFileGroup = (files, language, queryString, result, onFileProcessed)
|
|
|
980
950
|
? detectFrameworkFromAST(language, (definitionNode.text || '').slice(0, 300))
|
|
981
951
|
: null;
|
|
982
952
|
let parameterCount;
|
|
953
|
+
let requiredParameterCount;
|
|
954
|
+
let parameterTypes;
|
|
983
955
|
let returnType;
|
|
984
956
|
let declaredType;
|
|
985
957
|
if (nodeLabel === 'Function' || nodeLabel === 'Method' || nodeLabel === 'Constructor') {
|
|
986
958
|
const sig = extractMethodSignature(definitionNode);
|
|
987
959
|
parameterCount = sig.parameterCount;
|
|
960
|
+
requiredParameterCount = sig.requiredParameterCount;
|
|
961
|
+
parameterTypes = sig.parameterTypes;
|
|
988
962
|
returnType = sig.returnType;
|
|
989
963
|
// Language-specific return type fallback (e.g. Ruby YARD @return [Type])
|
|
990
964
|
// Also upgrades uninformative AST types like PHP `array` with PHPDoc `@return User[]`
|
|
@@ -1018,6 +992,8 @@ const processFileGroup = (files, language, queryString, result, onFileProcessed)
|
|
|
1018
992
|
} : {}),
|
|
1019
993
|
...(description !== undefined ? { description } : {}),
|
|
1020
994
|
...(parameterCount !== undefined ? { parameterCount } : {}),
|
|
995
|
+
...(requiredParameterCount !== undefined ? { requiredParameterCount } : {}),
|
|
996
|
+
...(parameterTypes !== undefined ? { parameterTypes } : {}),
|
|
1021
997
|
...(returnType !== undefined ? { returnType } : {}),
|
|
1022
998
|
},
|
|
1023
999
|
});
|
|
@@ -1031,6 +1007,8 @@ const processFileGroup = (files, language, queryString, result, onFileProcessed)
|
|
|
1031
1007
|
nodeId,
|
|
1032
1008
|
type: nodeLabel,
|
|
1033
1009
|
...(parameterCount !== undefined ? { parameterCount } : {}),
|
|
1010
|
+
...(requiredParameterCount !== undefined ? { requiredParameterCount } : {}),
|
|
1011
|
+
...(parameterTypes !== undefined ? { parameterTypes } : {}),
|
|
1034
1012
|
...(returnType !== undefined ? { returnType } : {}),
|
|
1035
1013
|
...(declaredType !== undefined ? { declaredType } : {}),
|
|
1036
1014
|
...(enclosingClassId ? { ownerId: enclosingClassId } : {}),
|
|
@@ -1071,7 +1049,7 @@ const processFileGroup = (files, language, queryString, result, onFileProcessed)
|
|
|
1071
1049
|
/** Accumulated result across sub-batches */
|
|
1072
1050
|
let accumulated = {
|
|
1073
1051
|
nodes: [], relationships: [], symbols: [],
|
|
1074
|
-
imports: [], calls: [], assignments: [], heritage: [], routes: [], constructorBindings: [], skippedLanguages: {}, fileCount: 0,
|
|
1052
|
+
imports: [], calls: [], assignments: [], heritage: [], routes: [], constructorBindings: [], typeEnvBindings: [], skippedLanguages: {}, fileCount: 0,
|
|
1075
1053
|
};
|
|
1076
1054
|
let cumulativeProcessed = 0;
|
|
1077
1055
|
const mergeResult = (target, src) => {
|
|
@@ -1084,6 +1062,7 @@ const mergeResult = (target, src) => {
|
|
|
1084
1062
|
target.heritage.push(...src.heritage);
|
|
1085
1063
|
target.routes.push(...src.routes);
|
|
1086
1064
|
target.constructorBindings.push(...src.constructorBindings);
|
|
1065
|
+
target.typeEnvBindings.push(...src.typeEnvBindings);
|
|
1087
1066
|
for (const [lang, count] of Object.entries(src.skippedLanguages)) {
|
|
1088
1067
|
target.skippedLanguages[lang] = (target.skippedLanguages[lang] || 0) + count;
|
|
1089
1068
|
}
|
|
@@ -1106,7 +1085,7 @@ parentPort.on('message', (msg) => {
|
|
|
1106
1085
|
if (msg && msg.type === 'flush') {
|
|
1107
1086
|
parentPort.postMessage({ type: 'result', data: accumulated });
|
|
1108
1087
|
// Reset for potential reuse
|
|
1109
|
-
accumulated = { nodes: [], relationships: [], symbols: [], imports: [], calls: [], assignments: [], heritage: [], routes: [], constructorBindings: [], skippedLanguages: {}, fileCount: 0 };
|
|
1088
|
+
accumulated = { nodes: [], relationships: [], symbols: [], imports: [], calls: [], assignments: [], heritage: [], routes: [], constructorBindings: [], typeEnvBindings: [], skippedLanguages: {}, fileCount: 0 };
|
|
1110
1089
|
cumulativeProcessed = 0;
|
|
1111
1090
|
return;
|
|
1112
1091
|
}
|
|
@@ -208,6 +208,8 @@ export const streamAllCSVsToDisk = async (graph, repoPath, csvDir) => {
|
|
|
208
208
|
const codeElemWriter = new BufferedCSVWriter(path.join(csvDir, 'codeelement.csv'), codeElementHeader);
|
|
209
209
|
const communityWriter = new BufferedCSVWriter(path.join(csvDir, 'community.csv'), 'id,label,heuristicLabel,keywords,description,enrichedBy,cohesion,symbolCount');
|
|
210
210
|
const processWriter = new BufferedCSVWriter(path.join(csvDir, 'process.csv'), 'id,label,heuristicLabel,processType,stepCount,communities,entryPointId,terminalId');
|
|
211
|
+
// Section nodes have an extra 'level' column
|
|
212
|
+
const sectionWriter = new BufferedCSVWriter(path.join(csvDir, 'section.csv'), 'id,name,filePath,startLine,endLine,level,content,description');
|
|
211
213
|
// Multi-language node types share the same CSV shape (no isExported column)
|
|
212
214
|
const multiLangHeader = 'id,name,filePath,startLine,endLine,content,description';
|
|
213
215
|
const MULTI_LANG_TYPES = ['Struct', 'Enum', 'Macro', 'Typedef', 'Union', 'Namespace', 'Trait', 'Impl',
|
|
@@ -292,6 +294,20 @@ export const streamAllCSVsToDisk = async (graph, repoPath, csvDir) => {
|
|
|
292
294
|
].join(','));
|
|
293
295
|
break;
|
|
294
296
|
}
|
|
297
|
+
case 'Section': {
|
|
298
|
+
const content = await extractContent(node, contentCache);
|
|
299
|
+
await sectionWriter.addRow([
|
|
300
|
+
escapeCSVField(node.id),
|
|
301
|
+
escapeCSVField(node.properties.name || ''),
|
|
302
|
+
escapeCSVField(node.properties.filePath || ''),
|
|
303
|
+
escapeCSVNumber(node.properties.startLine, -1),
|
|
304
|
+
escapeCSVNumber(node.properties.endLine, -1),
|
|
305
|
+
escapeCSVNumber(node.properties.level, 1),
|
|
306
|
+
escapeCSVField(content),
|
|
307
|
+
escapeCSVField(node.properties.description || ''),
|
|
308
|
+
].join(','));
|
|
309
|
+
break;
|
|
310
|
+
}
|
|
295
311
|
default: {
|
|
296
312
|
// Code element nodes (Function, Class, Interface, CodeElement)
|
|
297
313
|
const writer = codeWriterMap[node.label];
|
|
@@ -329,7 +345,7 @@ export const streamAllCSVsToDisk = async (graph, repoPath, csvDir) => {
|
|
|
329
345
|
}
|
|
330
346
|
}
|
|
331
347
|
// Finish all node writers
|
|
332
|
-
const allWriters = [fileWriter, folderWriter, functionWriter, classWriter, interfaceWriter, methodWriter, codeElemWriter, communityWriter, processWriter, ...multiLangWriters.values()];
|
|
348
|
+
const allWriters = [fileWriter, folderWriter, functionWriter, classWriter, interfaceWriter, methodWriter, codeElemWriter, communityWriter, processWriter, sectionWriter, ...multiLangWriters.values()];
|
|
333
349
|
await Promise.all(allWriters.map(w => w.finish()));
|
|
334
350
|
// --- Stream relationship CSV ---
|
|
335
351
|
const relCsvPath = path.join(csvDir, 'relations.csv');
|
|
@@ -353,6 +369,7 @@ export const streamAllCSVsToDisk = async (graph, repoPath, csvDir) => {
|
|
|
353
369
|
['Interface', interfaceWriter], ['Method', methodWriter],
|
|
354
370
|
['CodeElement', codeElemWriter],
|
|
355
371
|
['Community', communityWriter], ['Process', processWriter],
|
|
372
|
+
['Section', sectionWriter],
|
|
356
373
|
...Array.from(multiLangWriters.entries()).map(([name, w]) => [name, w]),
|
|
357
374
|
];
|
|
358
375
|
for (const [name, writer] of tableMap) {
|
|
@@ -2,6 +2,12 @@ import lbug from '@ladybugdb/core';
|
|
|
2
2
|
import { KnowledgeGraph } from '../graph/types.js';
|
|
3
3
|
/** Expose the current Database for pool adapter reuse in tests. */
|
|
4
4
|
export declare const getDatabase: () => lbug.Database | null;
|
|
5
|
+
/**
|
|
6
|
+
* Return true when the error message indicates that another process holds
|
|
7
|
+
* an exclusive lock on the LadybugDB file (e.g. `gitnexus analyze` or
|
|
8
|
+
* `gitnexus serve` running at the same time).
|
|
9
|
+
*/
|
|
10
|
+
export declare const isDbBusyError: (err: unknown) => boolean;
|
|
5
11
|
export declare const initLbug: (dbPath: string) => Promise<{
|
|
6
12
|
db: lbug.Database;
|
|
7
13
|
conn: lbug.Connection;
|
|
@@ -9,6 +15,10 @@ export declare const initLbug: (dbPath: string) => Promise<{
|
|
|
9
15
|
/**
|
|
10
16
|
* Execute multiple queries against one repo DB atomically.
|
|
11
17
|
* While the callback runs, no other request can switch the active DB.
|
|
18
|
+
*
|
|
19
|
+
* Automatically retries up to DB_LOCK_RETRY_ATTEMPTS times when the
|
|
20
|
+
* database is busy (e.g. `gitnexus analyze` holds the write lock).
|
|
21
|
+
* Each retry waits DB_LOCK_RETRY_DELAY_MS * attempt milliseconds.
|
|
12
22
|
*/
|
|
13
23
|
export declare const withLbugDb: <T>(dbPath: string, operation: () => Promise<T>) => Promise<T>;
|
|
14
24
|
export type LbugProgressCallback = (message: string) => void;
|
|
@@ -14,6 +14,22 @@ export const getDatabase = () => db;
|
|
|
14
14
|
// Global session lock for operations that touch module-level lbug globals.
|
|
15
15
|
// This guarantees no DB switch can happen while an operation is running.
|
|
16
16
|
let sessionLock = Promise.resolve();
|
|
17
|
+
/** Number of times to retry on a BUSY / lock-held error before giving up. */
|
|
18
|
+
const DB_LOCK_RETRY_ATTEMPTS = 3;
|
|
19
|
+
/** Base back-off in ms between BUSY retries (multiplied by attempt number). */
|
|
20
|
+
const DB_LOCK_RETRY_DELAY_MS = 500;
|
|
21
|
+
/**
|
|
22
|
+
* Return true when the error message indicates that another process holds
|
|
23
|
+
* an exclusive lock on the LadybugDB file (e.g. `gitnexus analyze` or
|
|
24
|
+
* `gitnexus serve` running at the same time).
|
|
25
|
+
*/
|
|
26
|
+
export const isDbBusyError = (err) => {
|
|
27
|
+
const msg = (err instanceof Error ? err.message : String(err)).toLowerCase();
|
|
28
|
+
return (msg.includes('busy')
|
|
29
|
+
|| msg.includes('lock')
|
|
30
|
+
|| msg.includes('already in use')
|
|
31
|
+
|| msg.includes('could not set lock'));
|
|
32
|
+
};
|
|
17
33
|
const runWithSessionLock = async (operation) => {
|
|
18
34
|
const previous = sessionLock;
|
|
19
35
|
let release = null;
|
|
@@ -35,12 +51,50 @@ export const initLbug = async (dbPath) => {
|
|
|
35
51
|
/**
|
|
36
52
|
* Execute multiple queries against one repo DB atomically.
|
|
37
53
|
* While the callback runs, no other request can switch the active DB.
|
|
54
|
+
*
|
|
55
|
+
* Automatically retries up to DB_LOCK_RETRY_ATTEMPTS times when the
|
|
56
|
+
* database is busy (e.g. `gitnexus analyze` holds the write lock).
|
|
57
|
+
* Each retry waits DB_LOCK_RETRY_DELAY_MS * attempt milliseconds.
|
|
38
58
|
*/
|
|
39
59
|
export const withLbugDb = async (dbPath, operation) => {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
60
|
+
let lastError;
|
|
61
|
+
for (let attempt = 1; attempt <= DB_LOCK_RETRY_ATTEMPTS; attempt++) {
|
|
62
|
+
try {
|
|
63
|
+
return await runWithSessionLock(async () => {
|
|
64
|
+
await ensureLbugInitialized(dbPath);
|
|
65
|
+
return operation();
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
catch (err) {
|
|
69
|
+
lastError = err;
|
|
70
|
+
if (!isDbBusyError(err) || attempt === DB_LOCK_RETRY_ATTEMPTS) {
|
|
71
|
+
throw err;
|
|
72
|
+
}
|
|
73
|
+
// Close stale connection inside the session lock to prevent race conditions
|
|
74
|
+
// with concurrent operations that might acquire the lock between cleanup steps
|
|
75
|
+
await runWithSessionLock(async () => {
|
|
76
|
+
try {
|
|
77
|
+
if (conn)
|
|
78
|
+
await conn.close();
|
|
79
|
+
}
|
|
80
|
+
catch { /* best-effort */ }
|
|
81
|
+
try {
|
|
82
|
+
if (db)
|
|
83
|
+
await db.close();
|
|
84
|
+
}
|
|
85
|
+
catch { /* best-effort */ }
|
|
86
|
+
conn = null;
|
|
87
|
+
db = null;
|
|
88
|
+
currentDbPath = null;
|
|
89
|
+
ftsLoaded = false;
|
|
90
|
+
});
|
|
91
|
+
// Sleep outside the lock — no need to block others while waiting
|
|
92
|
+
await new Promise(resolve => setTimeout(resolve, DB_LOCK_RETRY_DELAY_MS * attempt));
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
// This line is unreachable — the loop either returns or throws inside,
|
|
96
|
+
// but TypeScript needs an explicit throw to satisfy the return type.
|
|
97
|
+
throw lastError;
|
|
44
98
|
};
|
|
45
99
|
const ensureLbugInitialized = async (dbPath) => {
|
|
46
100
|
if (conn && currentDbPath === dbPath) {
|
|
@@ -323,6 +377,9 @@ const getCopyQuery = (table, filePath) => {
|
|
|
323
377
|
if (table === 'Process') {
|
|
324
378
|
return `COPY ${t}(id, label, heuristicLabel, processType, stepCount, communities, entryPointId, terminalId) FROM "${filePath}" ${COPY_CSV_OPTS}`;
|
|
325
379
|
}
|
|
380
|
+
if (table === 'Section') {
|
|
381
|
+
return `COPY ${t}(id, name, filePath, startLine, endLine, level, content, description) FROM "${filePath}" ${COPY_CSV_OPTS}`;
|
|
382
|
+
}
|
|
326
383
|
if (table === 'Method') {
|
|
327
384
|
return `COPY ${t}(id, name, filePath, startLine, endLine, isExported, content, description, parameterCount, returnType) FROM "${filePath}" ${COPY_CSV_OPTS}`;
|
|
328
385
|
}
|
|
@@ -363,6 +420,10 @@ export const insertNodeToLbug = async (label, properties, dbPath) => {
|
|
|
363
420
|
else if (label === 'Folder') {
|
|
364
421
|
query = `CREATE (n:Folder {id: ${escapeValue(properties.id)}, name: ${escapeValue(properties.name)}, filePath: ${escapeValue(properties.filePath)}})`;
|
|
365
422
|
}
|
|
423
|
+
else if (label === 'Section') {
|
|
424
|
+
const descPart = properties.description ? `, description: ${escapeValue(properties.description)}` : '';
|
|
425
|
+
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}})`;
|
|
426
|
+
}
|
|
366
427
|
else if (TABLES_WITH_EXPORTED.has(label)) {
|
|
367
428
|
const descPart = properties.description ? `, description: ${escapeValue(properties.description)}` : '';
|
|
368
429
|
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}})`;
|
|
@@ -438,6 +499,10 @@ export const batchInsertNodesToLbug = async (nodes, dbPath) => {
|
|
|
438
499
|
else if (label === 'Folder') {
|
|
439
500
|
query = `MERGE (n:Folder {id: ${escapeValue(properties.id)}}) SET n.name = ${escapeValue(properties.name)}, n.filePath = ${escapeValue(properties.filePath)}`;
|
|
440
501
|
}
|
|
502
|
+
else if (label === 'Section') {
|
|
503
|
+
const descPart = properties.description ? `, n.description = ${escapeValue(properties.description)}` : '';
|
|
504
|
+
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}`;
|
|
505
|
+
}
|
|
441
506
|
else if (TABLES_WITH_EXPORTED.has(label)) {
|
|
442
507
|
const descPart = properties.description ? `, n.description = ${escapeValue(properties.description)}` : '';
|
|
443
508
|
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}`;
|
|
@@ -8,7 +8,7 @@
|
|
|
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
|
-
export declare const NODE_TABLES: readonly ["File", "Folder", "Function", "Class", "Interface", "Method", "CodeElement", "Community", "Process", "Struct", "Enum", "Macro", "Typedef", "Union", "Namespace", "Trait", "Impl", "TypeAlias", "Const", "Static", "Property", "Record", "Delegate", "Annotation", "Constructor", "Template", "Module"];
|
|
11
|
+
export declare const NODE_TABLES: readonly ["File", "Folder", "Function", "Class", "Interface", "Method", "CodeElement", "Community", "Process", "Section", "Struct", "Enum", "Macro", "Typedef", "Union", "Namespace", "Trait", "Impl", "TypeAlias", "Const", "Static", "Property", "Record", "Delegate", "Annotation", "Constructor", "Template", "Module"];
|
|
12
12
|
export type NodeTableName = typeof NODE_TABLES[number];
|
|
13
13
|
export declare const REL_TABLE_NAME = "CodeRelation";
|
|
14
14
|
export declare const REL_TYPES: readonly ["CONTAINS", "DEFINES", "IMPORTS", "CALLS", "EXTENDS", "IMPLEMENTS", "HAS_METHOD", "HAS_PROPERTY", "ACCESSES", "OVERRIDES", "MEMBER_OF", "STEP_IN_PROCESS"];
|
|
@@ -41,8 +41,10 @@ export declare const ANNOTATION_SCHEMA: string;
|
|
|
41
41
|
export declare const CONSTRUCTOR_SCHEMA: string;
|
|
42
42
|
export declare const TEMPLATE_SCHEMA: string;
|
|
43
43
|
export declare const MODULE_SCHEMA: string;
|
|
44
|
-
export declare const
|
|
45
|
-
export declare const
|
|
44
|
+
export declare const SECTION_SCHEMA = "\nCREATE NODE TABLE Section (\n id STRING,\n name STRING,\n filePath STRING,\n startLine INT64,\n endLine INT64,\n level INT64,\n content STRING,\n description STRING,\n PRIMARY KEY (id)\n)";
|
|
45
|
+
export declare const RELATION_SCHEMA = "\nCREATE REL TABLE CodeRelation (\n FROM File TO File,\n FROM File TO Folder,\n FROM File TO Function,\n FROM File TO Class,\n FROM File TO Interface,\n FROM File TO Method,\n FROM File TO CodeElement,\n FROM File TO `Struct`,\n FROM File TO `Enum`,\n FROM File TO `Macro`,\n FROM File TO `Typedef`,\n FROM File TO `Union`,\n FROM File TO `Namespace`,\n FROM File TO `Trait`,\n FROM File TO `Impl`,\n FROM File TO `TypeAlias`,\n FROM File TO `Const`,\n FROM File TO `Static`,\n FROM File TO `Property`,\n FROM File TO `Record`,\n FROM File TO `Delegate`,\n FROM File TO `Annotation`,\n FROM File TO `Constructor`,\n FROM File TO `Template`,\n FROM File TO `Module`,\n FROM File TO Section,\n FROM Folder TO Folder,\n FROM Folder TO File,\n FROM Function TO Function,\n FROM Function TO Method,\n FROM Function TO Class,\n FROM Function TO Community,\n FROM Function TO `Macro`,\n FROM Function TO `Struct`,\n FROM Function TO `Template`,\n FROM Function TO `Enum`,\n FROM Function TO `Namespace`,\n FROM Function TO `TypeAlias`,\n FROM Function TO `Module`,\n FROM Function TO `Impl`,\n FROM Function TO Interface,\n FROM Function TO `Constructor`,\n FROM Function TO `Const`,\n FROM Function TO `Typedef`,\n FROM Function TO `Union`,\n FROM Function TO `Property`,\n FROM Class TO Method,\n FROM Class TO Function,\n FROM Class TO Class,\n FROM Class TO Interface,\n FROM Class TO Community,\n FROM Class TO `Template`,\n FROM Class TO `TypeAlias`,\n FROM Class TO `Struct`,\n FROM Class TO `Enum`,\n FROM Class TO `Annotation`,\n FROM Class TO `Constructor`,\n FROM Class TO `Trait`,\n FROM Class TO `Macro`,\n FROM Class TO `Impl`,\n FROM Class TO `Union`,\n FROM Class TO `Namespace`,\n FROM Class TO `Typedef`,\n FROM Class TO `Property`,\n FROM Method TO Function,\n FROM Method TO Method,\n FROM Method TO Class,\n FROM Method TO Community,\n FROM Method TO `Template`,\n FROM Method TO `Struct`,\n FROM Method TO `TypeAlias`,\n FROM Method TO `Enum`,\n FROM Method TO `Macro`,\n FROM Method TO `Namespace`,\n FROM Method TO `Module`,\n FROM Method TO `Impl`,\n FROM Method TO Interface,\n FROM Method TO `Constructor`,\n FROM Method TO `Property`,\n FROM `Template` TO `Template`,\n FROM `Template` TO Function,\n FROM `Template` TO Method,\n FROM `Template` TO Class,\n FROM `Template` TO `Struct`,\n FROM `Template` TO `TypeAlias`,\n FROM `Template` TO `Enum`,\n FROM `Template` TO `Macro`,\n FROM `Template` TO Interface,\n FROM `Template` TO `Constructor`,\n FROM `Module` TO `Module`,\n FROM Section TO Section,\n FROM Section TO File,\n FROM CodeElement TO Community,\n FROM Interface TO Community,\n FROM Interface TO Function,\n FROM Interface TO Method,\n FROM Interface TO Class,\n FROM Interface TO Interface,\n FROM Interface TO `TypeAlias`,\n FROM Interface TO `Struct`,\n FROM Interface TO `Constructor`,\n FROM Interface TO `Property`,\n FROM `Struct` TO Community,\n FROM `Struct` TO `Trait`,\n FROM `Struct` TO `Struct`,\n FROM `Struct` TO Class,\n FROM `Struct` TO `Enum`,\n FROM `Struct` TO Function,\n FROM `Struct` TO Method,\n FROM `Struct` TO Interface,\n FROM `Struct` TO `Constructor`,\n FROM `Struct` TO `Property`,\n FROM `Enum` TO `Enum`,\n FROM `Enum` TO Community,\n FROM `Enum` TO Class,\n FROM `Enum` TO Interface,\n FROM `Macro` TO Community,\n FROM `Macro` TO Function,\n FROM `Macro` TO Method,\n FROM `Module` TO Function,\n FROM `Module` TO Method,\n FROM `Typedef` TO Community,\n FROM `Union` TO Community,\n FROM `Namespace` TO Community,\n FROM `Namespace` TO `Struct`,\n FROM `Trait` TO Method,\n FROM `Trait` TO `Constructor`,\n FROM `Trait` TO `Property`,\n FROM `Trait` TO Community,\n FROM `Impl` TO Method,\n FROM `Impl` TO `Constructor`,\n FROM `Impl` TO `Property`,\n FROM `Impl` TO Community,\n FROM `Impl` TO `Trait`,\n FROM `Impl` TO `Struct`,\n FROM `Impl` TO `Impl`,\n FROM `TypeAlias` TO Community,\n FROM `TypeAlias` TO `Trait`,\n FROM `TypeAlias` TO Class,\n FROM `Const` TO Community,\n FROM `Static` TO Community,\n FROM `Property` TO Community,\n FROM `Record` TO Method,\n FROM `Record` TO `Constructor`,\n FROM `Record` TO `Property`,\n FROM `Record` TO Community,\n FROM `Delegate` TO Community,\n FROM `Annotation` TO Community,\n FROM `Constructor` TO Community,\n FROM `Constructor` TO Interface,\n FROM `Constructor` TO Class,\n FROM `Constructor` TO Method,\n FROM `Constructor` TO Function,\n FROM `Constructor` TO `Constructor`,\n FROM `Constructor` TO `Struct`,\n FROM `Constructor` TO `Macro`,\n FROM `Constructor` TO `Template`,\n FROM `Constructor` TO `TypeAlias`,\n FROM `Constructor` TO `Enum`,\n FROM `Constructor` TO `Annotation`,\n FROM `Constructor` TO `Impl`,\n FROM `Constructor` TO `Namespace`,\n FROM `Constructor` TO `Module`,\n FROM `Constructor` TO `Property`,\n FROM `Constructor` TO `Typedef`,\n FROM `Template` TO Community,\n FROM `Module` TO Community,\n FROM Function TO Process,\n FROM Method TO Process,\n FROM Class TO Process,\n FROM Interface TO Process,\n FROM `Struct` TO Process,\n FROM `Constructor` TO Process,\n FROM `Module` TO Process,\n FROM `Macro` TO Process,\n FROM `Impl` TO Process,\n FROM `Typedef` TO Process,\n FROM `TypeAlias` TO Process,\n FROM `Enum` TO Process,\n FROM `Union` TO Process,\n FROM `Namespace` TO Process,\n FROM `Trait` TO Process,\n FROM `Const` TO Process,\n FROM `Static` TO Process,\n FROM `Property` TO Process,\n FROM `Record` TO Process,\n FROM `Delegate` TO Process,\n FROM `Annotation` TO Process,\n FROM `Template` TO Process,\n FROM CodeElement TO Process,\n type STRING,\n confidence DOUBLE,\n reason STRING,\n step INT32\n)";
|
|
46
|
+
export declare const EMBEDDING_DIMS: number;
|
|
47
|
+
export declare const EMBEDDING_SCHEMA: string;
|
|
46
48
|
/**
|
|
47
49
|
* Create vector index for semantic search
|
|
48
50
|
* Uses HNSW (Hierarchical Navigable Small World) algorithm with cosine similarity
|
package/dist/core/lbug/schema.js
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
// NODE TABLE NAMES
|
|
13
13
|
// ============================================================================
|
|
14
14
|
export const NODE_TABLES = [
|
|
15
|
-
'File', 'Folder', 'Function', 'Class', 'Interface', 'Method', 'CodeElement', 'Community', 'Process',
|
|
15
|
+
'File', 'Folder', 'Function', 'Class', 'Interface', 'Method', 'CodeElement', 'Community', 'Process', 'Section',
|
|
16
16
|
// Multi-language support
|
|
17
17
|
'Struct', 'Enum', 'Macro', 'Typedef', 'Union', 'Namespace', 'Trait', 'Impl',
|
|
18
18
|
'TypeAlias', 'Const', 'Static', 'Property', 'Record', 'Delegate', 'Annotation', 'Constructor', 'Template', 'Module'
|
|
@@ -171,6 +171,19 @@ export const ANNOTATION_SCHEMA = CODE_ELEMENT_BASE('Annotation');
|
|
|
171
171
|
export const CONSTRUCTOR_SCHEMA = CODE_ELEMENT_BASE('Constructor');
|
|
172
172
|
export const TEMPLATE_SCHEMA = CODE_ELEMENT_BASE('Template');
|
|
173
173
|
export const MODULE_SCHEMA = CODE_ELEMENT_BASE('Module');
|
|
174
|
+
// Markdown heading sections
|
|
175
|
+
export const SECTION_SCHEMA = `
|
|
176
|
+
CREATE NODE TABLE Section (
|
|
177
|
+
id STRING,
|
|
178
|
+
name STRING,
|
|
179
|
+
filePath STRING,
|
|
180
|
+
startLine INT64,
|
|
181
|
+
endLine INT64,
|
|
182
|
+
level INT64,
|
|
183
|
+
content STRING,
|
|
184
|
+
description STRING,
|
|
185
|
+
PRIMARY KEY (id)
|
|
186
|
+
)`;
|
|
174
187
|
// ============================================================================
|
|
175
188
|
// RELATION TABLE SCHEMA
|
|
176
189
|
// Single table with 'type' property - connects all node tables
|
|
@@ -202,6 +215,7 @@ CREATE REL TABLE ${REL_TABLE_NAME} (
|
|
|
202
215
|
FROM File TO \`Constructor\`,
|
|
203
216
|
FROM File TO \`Template\`,
|
|
204
217
|
FROM File TO \`Module\`,
|
|
218
|
+
FROM File TO Section,
|
|
205
219
|
FROM Folder TO Folder,
|
|
206
220
|
FROM Folder TO File,
|
|
207
221
|
FROM Function TO Function,
|
|
@@ -266,6 +280,8 @@ CREATE REL TABLE ${REL_TABLE_NAME} (
|
|
|
266
280
|
FROM \`Template\` TO Interface,
|
|
267
281
|
FROM \`Template\` TO \`Constructor\`,
|
|
268
282
|
FROM \`Module\` TO \`Module\`,
|
|
283
|
+
FROM Section TO Section,
|
|
284
|
+
FROM Section TO File,
|
|
269
285
|
FROM CodeElement TO Community,
|
|
270
286
|
FROM Interface TO Community,
|
|
271
287
|
FROM Interface TO Function,
|
|
@@ -373,10 +389,16 @@ CREATE REL TABLE ${REL_TABLE_NAME} (
|
|
|
373
389
|
// EMBEDDING TABLE SCHEMA
|
|
374
390
|
// Separate table for vector storage to avoid copy-on-write overhead
|
|
375
391
|
// ============================================================================
|
|
392
|
+
/** Embedding vector dimensions. Default 384 (snowflake-arctic-embed-xs). */
|
|
393
|
+
const _rawDims = parseInt(process.env.GITNEXUS_EMBEDDING_DIMS ?? '384', 10);
|
|
394
|
+
if (Number.isNaN(_rawDims) || _rawDims <= 0) {
|
|
395
|
+
throw new Error(`GITNEXUS_EMBEDDING_DIMS must be a positive integer, got "${process.env.GITNEXUS_EMBEDDING_DIMS}"`);
|
|
396
|
+
}
|
|
397
|
+
export const EMBEDDING_DIMS = _rawDims;
|
|
376
398
|
export const EMBEDDING_SCHEMA = `
|
|
377
399
|
CREATE NODE TABLE ${EMBEDDING_TABLE_NAME} (
|
|
378
400
|
nodeId STRING,
|
|
379
|
-
embedding FLOAT[
|
|
401
|
+
embedding FLOAT[${EMBEDDING_DIMS}],
|
|
380
402
|
PRIMARY KEY (nodeId)
|
|
381
403
|
)`;
|
|
382
404
|
/**
|
|
@@ -419,6 +441,8 @@ export const NODE_SCHEMA_QUERIES = [
|
|
|
419
441
|
CONSTRUCTOR_SCHEMA,
|
|
420
442
|
TEMPLATE_SCHEMA,
|
|
421
443
|
MODULE_SCHEMA,
|
|
444
|
+
// Markdown support
|
|
445
|
+
SECTION_SCHEMA,
|
|
422
446
|
];
|
|
423
447
|
export const REL_SCHEMA_QUERIES = [
|
|
424
448
|
RELATION_SCHEMA,
|