@kentwynn/kgraph 0.1.25 → 0.1.27
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 +3 -1
- package/dist/cli/commands/init.js +30 -1
- package/dist/cli/init-prompt.d.ts +8 -0
- package/dist/cli/init-prompt.js +61 -0
- package/dist/cli/init-recommendations.d.ts +20 -0
- package/dist/cli/init-recommendations.js +140 -0
- package/dist/cli/init-summary.d.ts +17 -0
- package/dist/cli/init-summary.js +122 -0
- package/dist/scanner/c-symbol-extractor.d.ts +1 -1
- package/dist/scanner/c-symbol-extractor.js +108 -65
- package/dist/scanner/csharp-symbol-extractor.d.ts +1 -1
- package/dist/scanner/csharp-symbol-extractor.js +93 -67
- package/dist/scanner/go-symbol-extractor.d.ts +1 -1
- package/dist/scanner/go-symbol-extractor.js +75 -60
- package/dist/scanner/jvm-symbol-extractor.d.ts +1 -1
- package/dist/scanner/jvm-symbol-extractor.js +139 -71
- package/dist/scanner/python-symbol-extractor.d.ts +1 -1
- package/dist/scanner/python-symbol-extractor.js +92 -71
- package/dist/scanner/repo-scanner.js +3 -3
- package/dist/scanner/rust-symbol-extractor.d.ts +1 -1
- package/dist/scanner/rust-symbol-extractor.js +94 -89
- package/dist/scanner/tree-sitter-parser.d.ts +5 -0
- package/dist/scanner/tree-sitter-parser.js +55 -0
- package/dist/types/config.d.ts +2 -2
- package/package.json +11 -1
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import { parseSource } from './tree-sitter-parser.js';
|
|
2
|
+
export async function extractPythonSymbols(sourceText, filePath) {
|
|
3
3
|
const symbols = [];
|
|
4
4
|
const dependencies = [];
|
|
5
5
|
const relationships = [];
|
|
6
6
|
const warnings = [];
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
if (!sourceText.trim()) {
|
|
8
|
+
return { symbols, dependencies, relationships, warnings };
|
|
9
|
+
}
|
|
10
|
+
const tree = await parseSource(sourceText, 'python');
|
|
11
|
+
const addSymbol = (name, kind, startLine, endLine, exported, parentName) => {
|
|
12
|
+
const id = [filePath, kind, parentName, name, startLine]
|
|
11
13
|
.filter(Boolean)
|
|
12
14
|
.join('#');
|
|
13
15
|
symbols.push({
|
|
@@ -15,9 +17,9 @@ export function extractPythonSymbols(sourceText, filePath) {
|
|
|
15
17
|
name,
|
|
16
18
|
kind,
|
|
17
19
|
filePath,
|
|
18
|
-
startLine
|
|
19
|
-
endLine
|
|
20
|
-
exported
|
|
20
|
+
startLine,
|
|
21
|
+
endLine,
|
|
22
|
+
exported,
|
|
21
23
|
parentName,
|
|
22
24
|
});
|
|
23
25
|
relationships.push({
|
|
@@ -29,70 +31,89 @@ export function extractPythonSymbols(sourceText, filePath) {
|
|
|
29
31
|
confidence: 'high',
|
|
30
32
|
});
|
|
31
33
|
};
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
34
|
+
function walk(node, parentClassName) {
|
|
35
|
+
switch (node.type) {
|
|
36
|
+
case 'class_definition': {
|
|
37
|
+
const nameNode = node.childForFieldName('name');
|
|
38
|
+
if (nameNode) {
|
|
39
|
+
const startLine = node.startPosition.row + 1;
|
|
40
|
+
const endLine = node.endPosition.row + 1;
|
|
41
|
+
addSymbol(nameNode.text, 'class', startLine, endLine, false, parentClassName);
|
|
42
|
+
// Walk children for nested classes/methods
|
|
43
|
+
const body = node.childForFieldName('body');
|
|
44
|
+
if (body) {
|
|
45
|
+
for (const child of body.namedChildren) {
|
|
46
|
+
walk(child, nameNode.text);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return; // Don't recurse further from here
|
|
51
|
+
}
|
|
52
|
+
case 'function_definition': {
|
|
53
|
+
const nameNode = node.childForFieldName('name');
|
|
54
|
+
if (nameNode) {
|
|
55
|
+
const startLine = node.startPosition.row + 1;
|
|
56
|
+
const endLine = node.endPosition.row + 1;
|
|
57
|
+
const kind = parentClassName
|
|
58
|
+
? 'method'
|
|
59
|
+
: 'function';
|
|
60
|
+
addSymbol(nameNode.text, kind, startLine, endLine, false, parentClassName);
|
|
61
|
+
}
|
|
62
|
+
return; // Don't recurse into function bodies
|
|
63
|
+
}
|
|
64
|
+
case 'import_statement': {
|
|
65
|
+
// import os / import os.path
|
|
66
|
+
const startLine = node.startPosition.row + 1;
|
|
67
|
+
for (const child of node.namedChildren) {
|
|
68
|
+
if (child.type === 'dotted_name' || child.type === 'aliased_import') {
|
|
69
|
+
const specifier = child.type === 'aliased_import'
|
|
70
|
+
? (child.childForFieldName('name')?.text ?? child.text)
|
|
71
|
+
: child.text;
|
|
72
|
+
dependencies.push({
|
|
73
|
+
fromFile: filePath,
|
|
74
|
+
specifier,
|
|
75
|
+
kind: 'package',
|
|
76
|
+
});
|
|
77
|
+
addSymbol(specifier, 'import', startLine, startLine, false);
|
|
78
|
+
relationships.push({
|
|
79
|
+
sourceType: 'file',
|
|
80
|
+
sourceId: filePath,
|
|
81
|
+
targetType: 'package',
|
|
82
|
+
targetId: specifier,
|
|
83
|
+
relationshipType: 'import',
|
|
84
|
+
confidence: 'high',
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
case 'import_from_statement': {
|
|
91
|
+
// from X import Y
|
|
92
|
+
const moduleNode = node.childForFieldName('module_name');
|
|
93
|
+
if (moduleNode) {
|
|
94
|
+
const specifier = moduleNode.text;
|
|
95
|
+
const kind = specifier.startsWith('.')
|
|
96
|
+
? 'local'
|
|
97
|
+
: 'package';
|
|
98
|
+
dependencies.push({ fromFile: filePath, specifier, kind });
|
|
99
|
+
relationships.push({
|
|
100
|
+
sourceType: 'file',
|
|
101
|
+
sourceId: filePath,
|
|
102
|
+
targetType: kind === 'local' ? 'file' : 'package',
|
|
103
|
+
targetId: specifier,
|
|
104
|
+
relationshipType: 'import',
|
|
105
|
+
confidence: kind === 'local' ? 'medium' : 'high',
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
78
110
|
}
|
|
79
|
-
//
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
const specifier = fromMatch[1];
|
|
83
|
-
const kind = specifier.startsWith('.')
|
|
84
|
-
? 'local'
|
|
85
|
-
: 'package';
|
|
86
|
-
dependencies.push({ fromFile: filePath, specifier, kind });
|
|
87
|
-
relationships.push({
|
|
88
|
-
sourceType: 'file',
|
|
89
|
-
sourceId: filePath,
|
|
90
|
-
targetType: kind === 'local' ? 'file' : 'package',
|
|
91
|
-
targetId: specifier,
|
|
92
|
-
relationshipType: 'import',
|
|
93
|
-
confidence: kind === 'local' ? 'medium' : 'high',
|
|
94
|
-
});
|
|
111
|
+
// Recurse into children for top-level statements
|
|
112
|
+
for (const child of node.namedChildren) {
|
|
113
|
+
walk(child, parentClassName);
|
|
95
114
|
}
|
|
96
115
|
}
|
|
116
|
+
walk(tree.rootNode);
|
|
117
|
+
tree.delete();
|
|
97
118
|
return { symbols, dependencies, relationships, warnings };
|
|
98
119
|
}
|
|
@@ -2,6 +2,7 @@ import fg from 'fast-glob';
|
|
|
2
2
|
import crypto from 'node:crypto';
|
|
3
3
|
import { readFile, stat } from 'node:fs/promises';
|
|
4
4
|
import path from 'node:path';
|
|
5
|
+
import { estimateTokens } from '../session/token-estimator.js';
|
|
5
6
|
import { extractCSymbols } from './c-symbol-extractor.js';
|
|
6
7
|
import { extractCSharpSymbols } from './csharp-symbol-extractor.js';
|
|
7
8
|
import { buildFastGlobIgnore, detectLanguage, isPreciseLanguage, readGitignorePatterns, shouldExclude, } from './file-classifier.js';
|
|
@@ -10,10 +11,9 @@ import { extractJvmSymbols } from './jvm-symbol-extractor.js';
|
|
|
10
11
|
import { extractPythonSymbols } from './python-symbol-extractor.js';
|
|
11
12
|
import { extractRustSymbols } from './rust-symbol-extractor.js';
|
|
12
13
|
import { extractTsSymbols } from './ts-symbol-extractor.js';
|
|
13
|
-
import { estimateTokens } from '../session/token-estimator.js';
|
|
14
14
|
const C_EXTS = new Set(['.c', '.h', '.cpp', '.cc', '.cxx', '.hpp', '.hxx']);
|
|
15
15
|
const JVM_EXTS = new Set(['.java', '.kt', '.kts']);
|
|
16
|
-
function extractSymbols(text, repoPath) {
|
|
16
|
+
async function extractSymbols(text, repoPath) {
|
|
17
17
|
const ext = path.extname(repoPath);
|
|
18
18
|
if (ext === '.py' || ext === '.pyw' || ext === '.pyi') {
|
|
19
19
|
return extractPythonSymbols(text, repoPath);
|
|
@@ -79,7 +79,7 @@ export async function scanRepository(rootPath, config, previous) {
|
|
|
79
79
|
warnings: [],
|
|
80
80
|
};
|
|
81
81
|
if (isPreciseLanguage(repoPath, config)) {
|
|
82
|
-
const extracted = extractSymbols(text, repoPath);
|
|
82
|
+
const extracted = await extractSymbols(text, repoPath);
|
|
83
83
|
symbols.push(...extracted.symbols);
|
|
84
84
|
dependencies.push(...extracted.dependencies);
|
|
85
85
|
relationships.push(...extracted.relationships.filter((relationship) => relationship.relationshipType !== 'import'));
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import type { SymbolExtractionResult } from './ts-symbol-extractor.js';
|
|
2
|
-
export declare function extractRustSymbols(sourceText: string, filePath: string): SymbolExtractionResult
|
|
2
|
+
export declare function extractRustSymbols(sourceText: string, filePath: string): Promise<SymbolExtractionResult>;
|
|
@@ -1,38 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import { parseSource } from './tree-sitter-parser.js';
|
|
2
|
+
export async function extractRustSymbols(sourceText, filePath) {
|
|
3
3
|
const symbols = [];
|
|
4
4
|
const dependencies = [];
|
|
5
5
|
const relationships = [];
|
|
6
6
|
const warnings = [];
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
.join('#');
|
|
14
|
-
// Rust: pub = exported
|
|
15
|
-
symbols.push({
|
|
16
|
-
id,
|
|
17
|
-
name,
|
|
18
|
-
kind,
|
|
19
|
-
filePath,
|
|
20
|
-
startLine: lineNum,
|
|
21
|
-
endLine: lineNum,
|
|
22
|
-
exported: false, // set by caller
|
|
23
|
-
parentName,
|
|
24
|
-
});
|
|
25
|
-
relationships.push({
|
|
26
|
-
sourceType: 'file',
|
|
27
|
-
sourceId: filePath,
|
|
28
|
-
targetType: 'symbol',
|
|
29
|
-
targetId: id,
|
|
30
|
-
relationshipType: 'contains',
|
|
31
|
-
confidence: 'high',
|
|
32
|
-
});
|
|
33
|
-
};
|
|
34
|
-
const addSymbolExported = (name, kind, lineNum, exported, parentName) => {
|
|
35
|
-
const id = [filePath, kind, parentName, name, lineNum]
|
|
7
|
+
if (!sourceText.trim()) {
|
|
8
|
+
return { symbols, dependencies, relationships, warnings };
|
|
9
|
+
}
|
|
10
|
+
const tree = await parseSource(sourceText, 'rust');
|
|
11
|
+
const addSymbol = (name, kind, startLine, endLine, exported, parentName) => {
|
|
12
|
+
const id = [filePath, kind, parentName, name, startLine]
|
|
36
13
|
.filter(Boolean)
|
|
37
14
|
.join('#');
|
|
38
15
|
symbols.push({
|
|
@@ -40,8 +17,8 @@ export function extractRustSymbols(sourceText, filePath) {
|
|
|
40
17
|
name,
|
|
41
18
|
kind,
|
|
42
19
|
filePath,
|
|
43
|
-
startLine
|
|
44
|
-
endLine
|
|
20
|
+
startLine,
|
|
21
|
+
endLine,
|
|
45
22
|
exported,
|
|
46
23
|
parentName,
|
|
47
24
|
});
|
|
@@ -54,66 +31,94 @@ export function extractRustSymbols(sourceText, filePath) {
|
|
|
54
31
|
confidence: 'high',
|
|
55
32
|
});
|
|
56
33
|
};
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
while (implStack.length > 0 &&
|
|
68
|
-
braceDepth < implStack[implStack.length - 1].braceDepth) {
|
|
69
|
-
implStack.pop();
|
|
70
|
-
}
|
|
71
|
-
// use statement: use crate::path or use external::path
|
|
72
|
-
const useMatch = trimmed.match(/^use\s+([\w:]+)/);
|
|
73
|
-
if (useMatch) {
|
|
74
|
-
const specifier = useMatch[1];
|
|
75
|
-
const kind = specifier.startsWith('crate::') ||
|
|
76
|
-
specifier.startsWith('super::') ||
|
|
77
|
-
specifier.startsWith('self::')
|
|
78
|
-
? 'local'
|
|
79
|
-
: 'package';
|
|
80
|
-
dependencies.push({ fromFile: filePath, specifier, kind });
|
|
81
|
-
relationships.push({
|
|
82
|
-
sourceType: 'file',
|
|
83
|
-
sourceId: filePath,
|
|
84
|
-
targetType: kind === 'local' ? 'file' : 'package',
|
|
85
|
-
targetId: specifier,
|
|
86
|
-
relationshipType: 'import',
|
|
87
|
-
confidence: 'high',
|
|
88
|
-
});
|
|
89
|
-
continue;
|
|
90
|
-
}
|
|
91
|
-
// impl block: impl TypeName or impl Trait for TypeName
|
|
92
|
-
const implMatch = trimmed.match(/^impl(?:<[^>]*>)?\s+(?:\w+\s+for\s+)?(\w+)/);
|
|
93
|
-
if (implMatch) {
|
|
94
|
-
implStack.push({ typeName: implMatch[1], braceDepth });
|
|
95
|
-
continue;
|
|
96
|
-
}
|
|
97
|
-
// struct / enum / trait definition
|
|
98
|
-
const typeMatch = trimmed.match(/^(pub\s+)?(?:struct|enum|trait)\s+(\w+)/);
|
|
99
|
-
if (typeMatch) {
|
|
100
|
-
addSymbolExported(typeMatch[2], 'class', lineNum, !!typeMatch[1]);
|
|
101
|
-
continue;
|
|
34
|
+
function hasPub(node) {
|
|
35
|
+
return node.namedChildren.some((c) => c.type === 'visibility_modifier');
|
|
36
|
+
}
|
|
37
|
+
function extractUseSpecifier(node) {
|
|
38
|
+
// use_declaration has a child tree of scoped_identifier / scoped_use_list / use_wildcard
|
|
39
|
+
// We want the text without 'use' and ';'
|
|
40
|
+
for (const child of node.namedChildren) {
|
|
41
|
+
if (child.type !== 'visibility_modifier') {
|
|
42
|
+
return child.text;
|
|
43
|
+
}
|
|
102
44
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
45
|
+
return '';
|
|
46
|
+
}
|
|
47
|
+
function walk(node, implTypeName) {
|
|
48
|
+
switch (node.type) {
|
|
49
|
+
case 'use_declaration': {
|
|
50
|
+
const specifier = extractUseSpecifier(node);
|
|
51
|
+
if (specifier) {
|
|
52
|
+
const kind = specifier.startsWith('crate::') ||
|
|
53
|
+
specifier.startsWith('super::') ||
|
|
54
|
+
specifier.startsWith('self::')
|
|
55
|
+
? 'local'
|
|
56
|
+
: 'package';
|
|
57
|
+
dependencies.push({
|
|
58
|
+
fromFile: filePath,
|
|
59
|
+
specifier,
|
|
60
|
+
kind,
|
|
61
|
+
});
|
|
62
|
+
relationships.push({
|
|
63
|
+
sourceType: 'file',
|
|
64
|
+
sourceId: filePath,
|
|
65
|
+
targetType: kind === 'local' ? 'file' : 'package',
|
|
66
|
+
targetId: specifier,
|
|
67
|
+
relationshipType: 'import',
|
|
68
|
+
confidence: 'high',
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
case 'struct_item':
|
|
74
|
+
case 'enum_item':
|
|
75
|
+
case 'trait_item': {
|
|
76
|
+
const nameNode = node.childForFieldName('name');
|
|
77
|
+
if (nameNode) {
|
|
78
|
+
addSymbol(nameNode.text, 'class', node.startPosition.row + 1, node.endPosition.row + 1, hasPub(node));
|
|
79
|
+
}
|
|
80
|
+
return;
|
|
111
81
|
}
|
|
112
|
-
|
|
113
|
-
|
|
82
|
+
case 'impl_item': {
|
|
83
|
+
// impl TypeName { ... } or impl Trait for TypeName { ... }
|
|
84
|
+
const typeNode = node.childForFieldName('type');
|
|
85
|
+
const typeName = typeNode?.type === 'type_identifier' ? typeNode.text : typeNode?.text;
|
|
86
|
+
const body = node.childForFieldName('body') ??
|
|
87
|
+
node.namedChildren.find((c) => c.type === 'declaration_list');
|
|
88
|
+
if (body && typeName) {
|
|
89
|
+
for (const child of body.namedChildren) {
|
|
90
|
+
walk(child, typeName);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return;
|
|
114
94
|
}
|
|
115
|
-
|
|
95
|
+
case 'function_item': {
|
|
96
|
+
const nameNode = node.childForFieldName('name');
|
|
97
|
+
if (nameNode) {
|
|
98
|
+
const exported = hasPub(node);
|
|
99
|
+
if (implTypeName) {
|
|
100
|
+
addSymbol(nameNode.text, 'method', node.startPosition.row + 1, node.endPosition.row + 1, exported, implTypeName);
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
addSymbol(nameNode.text, 'function', node.startPosition.row + 1, node.endPosition.row + 1, exported);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
case 'function_signature_item': {
|
|
109
|
+
// trait method signatures
|
|
110
|
+
const nameNode = node.childForFieldName('name');
|
|
111
|
+
if (nameNode && implTypeName) {
|
|
112
|
+
addSymbol(nameNode.text, 'method', node.startPosition.row + 1, node.endPosition.row + 1, false, implTypeName);
|
|
113
|
+
}
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
for (const child of node.namedChildren) {
|
|
118
|
+
walk(child, implTypeName);
|
|
116
119
|
}
|
|
117
120
|
}
|
|
121
|
+
walk(tree.rootNode);
|
|
122
|
+
tree.delete();
|
|
118
123
|
return { symbols, dependencies, relationships, warnings };
|
|
119
124
|
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { Language, Tree } from 'web-tree-sitter';
|
|
2
|
+
type GrammarKey = 'python' | 'java' | 'kotlin' | 'go' | 'rust' | 'c' | 'cpp' | 'c_sharp';
|
|
3
|
+
export declare function loadLanguage(grammarKey: GrammarKey): Promise<Language>;
|
|
4
|
+
export declare function parseSource(sourceText: string, grammarKey: GrammarKey): Promise<Tree>;
|
|
5
|
+
export {};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { Language, Parser } from 'web-tree-sitter';
|
|
4
|
+
const require = createRequire(import.meta.url);
|
|
5
|
+
let initPromise = null;
|
|
6
|
+
const languageCache = new Map();
|
|
7
|
+
const GRAMMAR_PACKAGES = {
|
|
8
|
+
python: { pkg: 'tree-sitter-python', wasm: 'tree-sitter-python.wasm' },
|
|
9
|
+
java: { pkg: 'tree-sitter-java', wasm: 'tree-sitter-java.wasm' },
|
|
10
|
+
kotlin: {
|
|
11
|
+
pkg: '@tree-sitter-grammars/tree-sitter-kotlin',
|
|
12
|
+
wasm: 'tree-sitter-kotlin.wasm',
|
|
13
|
+
},
|
|
14
|
+
go: { pkg: 'tree-sitter-go', wasm: 'tree-sitter-go.wasm' },
|
|
15
|
+
rust: { pkg: 'tree-sitter-rust', wasm: 'tree-sitter-rust.wasm' },
|
|
16
|
+
c: { pkg: 'tree-sitter-c', wasm: 'tree-sitter-c.wasm' },
|
|
17
|
+
cpp: { pkg: 'tree-sitter-cpp', wasm: 'tree-sitter-cpp.wasm' },
|
|
18
|
+
c_sharp: {
|
|
19
|
+
pkg: 'tree-sitter-c-sharp',
|
|
20
|
+
wasm: 'tree-sitter-c_sharp.wasm',
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
async function ensureInit() {
|
|
24
|
+
if (!initPromise) {
|
|
25
|
+
initPromise = Parser.init();
|
|
26
|
+
}
|
|
27
|
+
return initPromise;
|
|
28
|
+
}
|
|
29
|
+
function resolveWasmPath(grammarKey) {
|
|
30
|
+
const { pkg, wasm } = GRAMMAR_PACKAGES[grammarKey];
|
|
31
|
+
const pkgDir = path.dirname(require.resolve(`${pkg}/package.json`));
|
|
32
|
+
return path.join(pkgDir, wasm);
|
|
33
|
+
}
|
|
34
|
+
export async function loadLanguage(grammarKey) {
|
|
35
|
+
const cached = languageCache.get(grammarKey);
|
|
36
|
+
if (cached)
|
|
37
|
+
return cached;
|
|
38
|
+
await ensureInit();
|
|
39
|
+
const wasmPath = resolveWasmPath(grammarKey);
|
|
40
|
+
const language = await Language.load(wasmPath);
|
|
41
|
+
languageCache.set(grammarKey, language);
|
|
42
|
+
return language;
|
|
43
|
+
}
|
|
44
|
+
export async function parseSource(sourceText, grammarKey) {
|
|
45
|
+
await ensureInit();
|
|
46
|
+
const language = await loadLanguage(grammarKey);
|
|
47
|
+
const parser = new Parser();
|
|
48
|
+
parser.setLanguage(language);
|
|
49
|
+
const tree = parser.parse(sourceText);
|
|
50
|
+
parser.delete();
|
|
51
|
+
if (!tree) {
|
|
52
|
+
throw new Error(`Failed to parse source with grammar ${grammarKey}`);
|
|
53
|
+
}
|
|
54
|
+
return tree;
|
|
55
|
+
}
|
package/dist/types/config.d.ts
CHANGED
|
@@ -12,8 +12,8 @@ export interface DomainHint {
|
|
|
12
12
|
paths?: string[];
|
|
13
13
|
tags?: string[];
|
|
14
14
|
}
|
|
15
|
-
export type IntegrationName =
|
|
16
|
-
export type IntegrationMode =
|
|
15
|
+
export type IntegrationName = 'claude-code' | 'cline' | 'codex' | 'copilot' | 'cursor' | 'gemini' | 'windsurf';
|
|
16
|
+
export type IntegrationMode = 'smart' | 'always' | 'manual' | 'off';
|
|
17
17
|
export interface IntegrationConfig {
|
|
18
18
|
name: IntegrationName;
|
|
19
19
|
enabled: boolean;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kentwynn/kgraph",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.27",
|
|
4
4
|
"description": "Persistent repo intelligence for AI coding assistants.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -39,11 +39,21 @@
|
|
|
39
39
|
},
|
|
40
40
|
"homepage": "https://github.com/kentwynn/KGraph#readme",
|
|
41
41
|
"dependencies": {
|
|
42
|
+
"@clack/prompts": "^1.3.0",
|
|
43
|
+
"@tree-sitter-grammars/tree-sitter-kotlin": "^1.1.0",
|
|
42
44
|
"chalk": "^5.6.2",
|
|
43
45
|
"commander": "^12.1.0",
|
|
44
46
|
"fast-glob": "^3.3.2",
|
|
45
47
|
"figlet": "^1.11.0",
|
|
48
|
+
"tree-sitter-c": "^0.24.1",
|
|
49
|
+
"tree-sitter-c-sharp": "^0.23.5",
|
|
50
|
+
"tree-sitter-cpp": "^0.23.4",
|
|
51
|
+
"tree-sitter-go": "^0.25.0",
|
|
52
|
+
"tree-sitter-java": "^0.23.5",
|
|
53
|
+
"tree-sitter-python": "^0.25.0",
|
|
54
|
+
"tree-sitter-rust": "^0.24.0",
|
|
46
55
|
"typescript": "^5.9.3",
|
|
56
|
+
"web-tree-sitter": "^0.26.8",
|
|
47
57
|
"yaml": "^2.5.1"
|
|
48
58
|
},
|
|
49
59
|
"devDependencies": {
|