ruvector 0.1.64 → 0.1.66
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/.ruvector/intelligence.json +125 -0
- package/README.md +169 -20
- package/bin/cli.js +1276 -24
- package/bin/mcp-server.js +694 -0
- package/dist/core/ast-parser.d.ts +108 -0
- package/dist/core/ast-parser.d.ts.map +1 -0
- package/dist/core/ast-parser.js +602 -0
- package/dist/core/coverage-router.d.ts +88 -0
- package/dist/core/coverage-router.d.ts.map +1 -0
- package/dist/core/coverage-router.js +315 -0
- package/dist/core/diff-embeddings.d.ts +93 -0
- package/dist/core/diff-embeddings.d.ts.map +1 -0
- package/dist/core/diff-embeddings.js +334 -0
- package/dist/core/graph-algorithms.d.ts +83 -0
- package/dist/core/graph-algorithms.d.ts.map +1 -0
- package/dist/core/graph-algorithms.js +514 -0
- package/dist/core/index.d.ts +10 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +17 -1
- package/dist/core/learning-engine.d.ts +160 -0
- package/dist/core/learning-engine.d.ts.map +1 -0
- package/dist/core/learning-engine.js +589 -0
- package/dist/core/tensor-compress.d.ts +134 -0
- package/dist/core/tensor-compress.d.ts.map +1 -0
- package/dist/core/tensor-compress.js +432 -0
- package/package.json +1 -1
- package/ruvector.db +0 -0
|
@@ -0,0 +1,602 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* AST Parser - Tree-sitter based code parsing
|
|
4
|
+
*
|
|
5
|
+
* Provides real AST parsing for accurate code analysis,
|
|
6
|
+
* replacing regex-based heuristics with proper parsing.
|
|
7
|
+
*
|
|
8
|
+
* Supports: TypeScript, JavaScript, Python, Rust, Go, Java, C/C++
|
|
9
|
+
*/
|
|
10
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
13
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
14
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
15
|
+
}
|
|
16
|
+
Object.defineProperty(o, k2, desc);
|
|
17
|
+
}) : (function(o, m, k, k2) {
|
|
18
|
+
if (k2 === undefined) k2 = k;
|
|
19
|
+
o[k2] = m[k];
|
|
20
|
+
}));
|
|
21
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
22
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
23
|
+
}) : function(o, v) {
|
|
24
|
+
o["default"] = v;
|
|
25
|
+
});
|
|
26
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
27
|
+
var ownKeys = function(o) {
|
|
28
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
29
|
+
var ar = [];
|
|
30
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
31
|
+
return ar;
|
|
32
|
+
};
|
|
33
|
+
return ownKeys(o);
|
|
34
|
+
};
|
|
35
|
+
return function (mod) {
|
|
36
|
+
if (mod && mod.__esModule) return mod;
|
|
37
|
+
var result = {};
|
|
38
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
39
|
+
__setModuleDefault(result, mod);
|
|
40
|
+
return result;
|
|
41
|
+
};
|
|
42
|
+
})();
|
|
43
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
44
|
+
exports.CodeParser = void 0;
|
|
45
|
+
exports.isTreeSitterAvailable = isTreeSitterAvailable;
|
|
46
|
+
exports.getCodeParser = getCodeParser;
|
|
47
|
+
exports.initCodeParser = initCodeParser;
|
|
48
|
+
const fs = __importStar(require("fs"));
|
|
49
|
+
const path = __importStar(require("path"));
|
|
50
|
+
// Try to load tree-sitter
|
|
51
|
+
let Parser = null;
|
|
52
|
+
let languages = new Map();
|
|
53
|
+
let parserError = null;
|
|
54
|
+
async function loadTreeSitter() {
|
|
55
|
+
if (Parser)
|
|
56
|
+
return true;
|
|
57
|
+
if (parserError)
|
|
58
|
+
return false;
|
|
59
|
+
try {
|
|
60
|
+
// Dynamic require to avoid TypeScript errors
|
|
61
|
+
Parser = require('tree-sitter');
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
catch (e) {
|
|
65
|
+
parserError = new Error(`tree-sitter not installed: ${e.message}\n` +
|
|
66
|
+
`Install with: npm install tree-sitter tree-sitter-typescript tree-sitter-javascript tree-sitter-python`);
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
async function loadLanguage(lang) {
|
|
71
|
+
if (languages.has(lang))
|
|
72
|
+
return languages.get(lang);
|
|
73
|
+
const langPackages = {
|
|
74
|
+
typescript: 'tree-sitter-typescript',
|
|
75
|
+
javascript: 'tree-sitter-javascript',
|
|
76
|
+
python: 'tree-sitter-python',
|
|
77
|
+
rust: 'tree-sitter-rust',
|
|
78
|
+
go: 'tree-sitter-go',
|
|
79
|
+
java: 'tree-sitter-java',
|
|
80
|
+
c: 'tree-sitter-c',
|
|
81
|
+
cpp: 'tree-sitter-cpp',
|
|
82
|
+
ruby: 'tree-sitter-ruby',
|
|
83
|
+
php: 'tree-sitter-php',
|
|
84
|
+
};
|
|
85
|
+
const pkg = langPackages[lang];
|
|
86
|
+
if (!pkg)
|
|
87
|
+
return null;
|
|
88
|
+
try {
|
|
89
|
+
const langModule = await Promise.resolve(`${pkg}`).then(s => __importStar(require(s)));
|
|
90
|
+
const language = langModule.default || langModule;
|
|
91
|
+
// Handle TypeScript which exports tsx and typescript
|
|
92
|
+
if (lang === 'typescript' && language.typescript) {
|
|
93
|
+
languages.set(lang, language.typescript);
|
|
94
|
+
languages.set('tsx', language.tsx);
|
|
95
|
+
return language.typescript;
|
|
96
|
+
}
|
|
97
|
+
languages.set(lang, language);
|
|
98
|
+
return language;
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
function isTreeSitterAvailable() {
|
|
105
|
+
try {
|
|
106
|
+
require.resolve('tree-sitter');
|
|
107
|
+
return true;
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
// ============================================================================
|
|
114
|
+
// Parser
|
|
115
|
+
// ============================================================================
|
|
116
|
+
class CodeParser {
|
|
117
|
+
constructor() {
|
|
118
|
+
this.parser = null;
|
|
119
|
+
this.initialized = false;
|
|
120
|
+
}
|
|
121
|
+
async init() {
|
|
122
|
+
if (this.initialized)
|
|
123
|
+
return true;
|
|
124
|
+
const loaded = await loadTreeSitter();
|
|
125
|
+
if (!loaded)
|
|
126
|
+
return false;
|
|
127
|
+
this.parser = new Parser();
|
|
128
|
+
this.initialized = true;
|
|
129
|
+
return true;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Detect language from file extension
|
|
133
|
+
*/
|
|
134
|
+
detectLanguage(file) {
|
|
135
|
+
const ext = path.extname(file).toLowerCase();
|
|
136
|
+
const langMap = {
|
|
137
|
+
'.ts': 'typescript',
|
|
138
|
+
'.tsx': 'tsx',
|
|
139
|
+
'.js': 'javascript',
|
|
140
|
+
'.jsx': 'javascript',
|
|
141
|
+
'.mjs': 'javascript',
|
|
142
|
+
'.cjs': 'javascript',
|
|
143
|
+
'.py': 'python',
|
|
144
|
+
'.rs': 'rust',
|
|
145
|
+
'.go': 'go',
|
|
146
|
+
'.java': 'java',
|
|
147
|
+
'.c': 'c',
|
|
148
|
+
'.h': 'c',
|
|
149
|
+
'.cpp': 'cpp',
|
|
150
|
+
'.cc': 'cpp',
|
|
151
|
+
'.cxx': 'cpp',
|
|
152
|
+
'.hpp': 'cpp',
|
|
153
|
+
'.rb': 'ruby',
|
|
154
|
+
'.php': 'php',
|
|
155
|
+
};
|
|
156
|
+
return langMap[ext] || 'unknown';
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Parse a file and return the AST
|
|
160
|
+
*/
|
|
161
|
+
async parse(file, content) {
|
|
162
|
+
if (!this.initialized) {
|
|
163
|
+
await this.init();
|
|
164
|
+
}
|
|
165
|
+
if (!this.parser)
|
|
166
|
+
return null;
|
|
167
|
+
const lang = this.detectLanguage(file);
|
|
168
|
+
const language = await loadLanguage(lang);
|
|
169
|
+
if (!language)
|
|
170
|
+
return null;
|
|
171
|
+
this.parser.setLanguage(language);
|
|
172
|
+
const code = content ?? (fs.existsSync(file) ? fs.readFileSync(file, 'utf8') : '');
|
|
173
|
+
const tree = this.parser.parse(code);
|
|
174
|
+
return this.convertNode(tree.rootNode);
|
|
175
|
+
}
|
|
176
|
+
convertNode(node) {
|
|
177
|
+
return {
|
|
178
|
+
type: node.type,
|
|
179
|
+
text: node.text,
|
|
180
|
+
startPosition: node.startPosition,
|
|
181
|
+
endPosition: node.endPosition,
|
|
182
|
+
children: node.children?.map((c) => this.convertNode(c)) || [],
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Analyze a file for functions, classes, imports, etc.
|
|
187
|
+
*/
|
|
188
|
+
async analyze(file, content) {
|
|
189
|
+
const start = performance.now();
|
|
190
|
+
const lang = this.detectLanguage(file);
|
|
191
|
+
const code = content ?? (fs.existsSync(file) ? fs.readFileSync(file, 'utf8') : '');
|
|
192
|
+
// Try tree-sitter first, fall back to regex
|
|
193
|
+
if (this.initialized && this.parser) {
|
|
194
|
+
const language = await loadLanguage(lang);
|
|
195
|
+
if (language) {
|
|
196
|
+
this.parser.setLanguage(language);
|
|
197
|
+
const tree = this.parser.parse(code);
|
|
198
|
+
return this.analyzeTree(file, lang, tree.rootNode, code, start);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
// Regex fallback
|
|
202
|
+
return this.analyzeWithRegex(file, lang, code, start);
|
|
203
|
+
}
|
|
204
|
+
analyzeTree(file, lang, root, code, start) {
|
|
205
|
+
const imports = [];
|
|
206
|
+
const exports = [];
|
|
207
|
+
const functions = [];
|
|
208
|
+
const classes = [];
|
|
209
|
+
const variables = [];
|
|
210
|
+
const types = [];
|
|
211
|
+
const visit = (node) => {
|
|
212
|
+
// Imports
|
|
213
|
+
if (node.type === 'import_statement' || node.type === 'import_declaration') {
|
|
214
|
+
const imp = this.parseImport(node, lang);
|
|
215
|
+
if (imp)
|
|
216
|
+
imports.push(imp);
|
|
217
|
+
}
|
|
218
|
+
// Exports
|
|
219
|
+
if (node.type.includes('export')) {
|
|
220
|
+
const exp = this.parseExport(node, lang);
|
|
221
|
+
if (exp)
|
|
222
|
+
exports.push(exp);
|
|
223
|
+
}
|
|
224
|
+
// Functions
|
|
225
|
+
if (node.type.includes('function') || node.type === 'method_definition' || node.type === 'arrow_function') {
|
|
226
|
+
const fn = this.parseFunction(node, code, lang);
|
|
227
|
+
if (fn)
|
|
228
|
+
functions.push(fn);
|
|
229
|
+
}
|
|
230
|
+
// Classes
|
|
231
|
+
if (node.type === 'class_declaration' || node.type === 'class') {
|
|
232
|
+
const cls = this.parseClass(node, code, lang);
|
|
233
|
+
if (cls)
|
|
234
|
+
classes.push(cls);
|
|
235
|
+
}
|
|
236
|
+
// Variables
|
|
237
|
+
if (node.type === 'variable_declarator' || node.type === 'assignment') {
|
|
238
|
+
const name = this.getIdentifierName(node);
|
|
239
|
+
if (name)
|
|
240
|
+
variables.push(name);
|
|
241
|
+
}
|
|
242
|
+
// Type definitions
|
|
243
|
+
if (node.type === 'type_alias_declaration' || node.type === 'interface_declaration') {
|
|
244
|
+
const name = this.getIdentifierName(node);
|
|
245
|
+
if (name)
|
|
246
|
+
types.push(name);
|
|
247
|
+
}
|
|
248
|
+
// Recurse
|
|
249
|
+
for (const child of node.children || []) {
|
|
250
|
+
visit(child);
|
|
251
|
+
}
|
|
252
|
+
};
|
|
253
|
+
visit(root);
|
|
254
|
+
const lines = code.split('\n').length;
|
|
255
|
+
const complexity = this.calculateComplexity(code);
|
|
256
|
+
return {
|
|
257
|
+
file,
|
|
258
|
+
language: lang,
|
|
259
|
+
imports,
|
|
260
|
+
exports,
|
|
261
|
+
functions,
|
|
262
|
+
classes,
|
|
263
|
+
variables,
|
|
264
|
+
types,
|
|
265
|
+
complexity,
|
|
266
|
+
lines,
|
|
267
|
+
parseTime: performance.now() - start,
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
parseImport(node, lang) {
|
|
271
|
+
try {
|
|
272
|
+
const source = this.findChild(node, 'string')?.text?.replace(/['"]/g, '') || '';
|
|
273
|
+
const named = [];
|
|
274
|
+
let defaultImport;
|
|
275
|
+
let namespace;
|
|
276
|
+
// Find import specifiers
|
|
277
|
+
const specifiers = this.findChild(node, 'import_clause') || node;
|
|
278
|
+
for (const child of specifiers.children || []) {
|
|
279
|
+
if (child.type === 'identifier') {
|
|
280
|
+
defaultImport = child.text;
|
|
281
|
+
}
|
|
282
|
+
else if (child.type === 'namespace_import') {
|
|
283
|
+
namespace = this.getIdentifierName(child) || undefined;
|
|
284
|
+
}
|
|
285
|
+
else if (child.type === 'named_imports') {
|
|
286
|
+
for (const spec of child.children || []) {
|
|
287
|
+
if (spec.type === 'import_specifier') {
|
|
288
|
+
named.push(this.getIdentifierName(spec) || '');
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
return {
|
|
294
|
+
source,
|
|
295
|
+
default: defaultImport,
|
|
296
|
+
named: named.filter(Boolean),
|
|
297
|
+
namespace,
|
|
298
|
+
type: 'esm',
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
catch {
|
|
302
|
+
return null;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
parseExport(node, lang) {
|
|
306
|
+
try {
|
|
307
|
+
if (node.type === 'export_statement') {
|
|
308
|
+
const declaration = this.findChild(node, 'declaration');
|
|
309
|
+
if (declaration) {
|
|
310
|
+
const name = this.getIdentifierName(declaration);
|
|
311
|
+
return { name: name || 'default', type: node.text.includes('default') ? 'default' : 'named' };
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
return null;
|
|
315
|
+
}
|
|
316
|
+
catch {
|
|
317
|
+
return null;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
parseFunction(node, code, lang) {
|
|
321
|
+
try {
|
|
322
|
+
const name = this.getIdentifierName(node) || '<anonymous>';
|
|
323
|
+
const params = [];
|
|
324
|
+
let returnType;
|
|
325
|
+
const isAsync = node.text.includes('async');
|
|
326
|
+
const isExported = node.parent?.type?.includes('export');
|
|
327
|
+
// Get parameters
|
|
328
|
+
const paramsNode = this.findChild(node, 'formal_parameters') || this.findChild(node, 'parameters');
|
|
329
|
+
if (paramsNode) {
|
|
330
|
+
for (const param of paramsNode.children || []) {
|
|
331
|
+
if (param.type === 'identifier' || param.type === 'required_parameter') {
|
|
332
|
+
params.push(this.getIdentifierName(param) || '');
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
// Get return type
|
|
337
|
+
const returnNode = this.findChild(node, 'type_annotation');
|
|
338
|
+
if (returnNode) {
|
|
339
|
+
returnType = returnNode.text.replace(/^:\s*/, '');
|
|
340
|
+
}
|
|
341
|
+
// Calculate complexity
|
|
342
|
+
const bodyText = this.findChild(node, 'statement_block')?.text || '';
|
|
343
|
+
const complexity = this.calculateComplexity(bodyText);
|
|
344
|
+
// Find function calls
|
|
345
|
+
const calls = [];
|
|
346
|
+
const callRegex = /(\w+)\s*\(/g;
|
|
347
|
+
let match;
|
|
348
|
+
while ((match = callRegex.exec(bodyText)) !== null) {
|
|
349
|
+
if (!['if', 'for', 'while', 'switch', 'catch', 'function'].includes(match[1])) {
|
|
350
|
+
calls.push(match[1]);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
return {
|
|
354
|
+
name,
|
|
355
|
+
params: params.filter(Boolean),
|
|
356
|
+
returnType,
|
|
357
|
+
async: isAsync,
|
|
358
|
+
exported: isExported,
|
|
359
|
+
startLine: node.startPosition.row + 1,
|
|
360
|
+
endLine: node.endPosition.row + 1,
|
|
361
|
+
complexity,
|
|
362
|
+
calls: [...new Set(calls)],
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
catch {
|
|
366
|
+
return null;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
parseClass(node, code, lang) {
|
|
370
|
+
try {
|
|
371
|
+
const name = this.getIdentifierName(node) || '<anonymous>';
|
|
372
|
+
let extendsClass;
|
|
373
|
+
const implementsList = [];
|
|
374
|
+
const methods = [];
|
|
375
|
+
const properties = [];
|
|
376
|
+
// Get extends/implements
|
|
377
|
+
const heritage = this.findChild(node, 'class_heritage');
|
|
378
|
+
if (heritage) {
|
|
379
|
+
const extendsNode = this.findChild(heritage, 'extends_clause');
|
|
380
|
+
if (extendsNode) {
|
|
381
|
+
extendsClass = this.getIdentifierName(extendsNode) || undefined;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
// Get methods and properties
|
|
385
|
+
const body = this.findChild(node, 'class_body');
|
|
386
|
+
if (body) {
|
|
387
|
+
for (const member of body.children || []) {
|
|
388
|
+
if (member.type === 'method_definition') {
|
|
389
|
+
const method = this.parseFunction(member, code, lang);
|
|
390
|
+
if (method)
|
|
391
|
+
methods.push(method);
|
|
392
|
+
}
|
|
393
|
+
else if (member.type === 'field_definition' || member.type === 'public_field_definition') {
|
|
394
|
+
const propName = this.getIdentifierName(member);
|
|
395
|
+
if (propName)
|
|
396
|
+
properties.push(propName);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
return {
|
|
401
|
+
name,
|
|
402
|
+
extends: extendsClass,
|
|
403
|
+
implements: implementsList,
|
|
404
|
+
methods,
|
|
405
|
+
properties,
|
|
406
|
+
exported: node.parent?.type?.includes('export'),
|
|
407
|
+
startLine: node.startPosition.row + 1,
|
|
408
|
+
endLine: node.endPosition.row + 1,
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
catch {
|
|
412
|
+
return null;
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
findChild(node, type) {
|
|
416
|
+
if (!node.children)
|
|
417
|
+
return null;
|
|
418
|
+
for (const child of node.children) {
|
|
419
|
+
if (child.type === type)
|
|
420
|
+
return child;
|
|
421
|
+
const found = this.findChild(child, type);
|
|
422
|
+
if (found)
|
|
423
|
+
return found;
|
|
424
|
+
}
|
|
425
|
+
return null;
|
|
426
|
+
}
|
|
427
|
+
getIdentifierName(node) {
|
|
428
|
+
if (node.type === 'identifier')
|
|
429
|
+
return node.text;
|
|
430
|
+
if (!node.children)
|
|
431
|
+
return null;
|
|
432
|
+
for (const child of node.children) {
|
|
433
|
+
if (child.type === 'identifier' || child.type === 'property_identifier') {
|
|
434
|
+
return child.text;
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
return null;
|
|
438
|
+
}
|
|
439
|
+
calculateComplexity(code) {
|
|
440
|
+
const patterns = [
|
|
441
|
+
/\bif\b/g,
|
|
442
|
+
/\belse\b/g,
|
|
443
|
+
/\bfor\b/g,
|
|
444
|
+
/\bwhile\b/g,
|
|
445
|
+
/\bcase\b/g,
|
|
446
|
+
/\bcatch\b/g,
|
|
447
|
+
/\?\s*[^:]/g, // ternary
|
|
448
|
+
/&&/g,
|
|
449
|
+
/\|\|/g,
|
|
450
|
+
];
|
|
451
|
+
let complexity = 1;
|
|
452
|
+
for (const pattern of patterns) {
|
|
453
|
+
complexity += (code.match(pattern) || []).length;
|
|
454
|
+
}
|
|
455
|
+
return complexity;
|
|
456
|
+
}
|
|
457
|
+
analyzeWithRegex(file, lang, code, start) {
|
|
458
|
+
const lines = code.split('\n');
|
|
459
|
+
const imports = [];
|
|
460
|
+
const exports = [];
|
|
461
|
+
const functions = [];
|
|
462
|
+
const classes = [];
|
|
463
|
+
const variables = [];
|
|
464
|
+
const types = [];
|
|
465
|
+
// Regex patterns
|
|
466
|
+
const importRegex = /import\s+(?:(\w+)\s*,?\s*)?(?:\{([^}]+)\}\s*)?(?:\*\s+as\s+(\w+)\s*)?from\s+['"]([^'"]+)['"]/g;
|
|
467
|
+
const requireRegex = /(?:const|let|var)\s+(?:(\w+)|\{([^}]+)\})\s*=\s*require\s*\(['"]([^'"]+)['"]\)/g;
|
|
468
|
+
const exportRegex = /export\s+(?:(default)\s+)?(?:(class|function|const|let|var|interface|type)\s+)?(\w+)?/g;
|
|
469
|
+
const functionRegex = /(?:export\s+)?(?:async\s+)?function\s+(\w+)\s*\(([^)]*)\)/g;
|
|
470
|
+
const arrowRegex = /(?:const|let|var)\s+(\w+)\s*=\s*(?:async\s*)?\([^)]*\)\s*=>/g;
|
|
471
|
+
const classRegex = /(?:export\s+)?class\s+(\w+)(?:\s+extends\s+(\w+))?/g;
|
|
472
|
+
const typeRegex = /(?:export\s+)?(?:type|interface)\s+(\w+)/g;
|
|
473
|
+
// Parse imports
|
|
474
|
+
let match;
|
|
475
|
+
while ((match = importRegex.exec(code)) !== null) {
|
|
476
|
+
imports.push({
|
|
477
|
+
source: match[4],
|
|
478
|
+
default: match[1],
|
|
479
|
+
named: match[2] ? match[2].split(',').map(s => s.trim().split(/\s+as\s+/)[0]) : [],
|
|
480
|
+
namespace: match[3],
|
|
481
|
+
type: 'esm',
|
|
482
|
+
});
|
|
483
|
+
}
|
|
484
|
+
while ((match = requireRegex.exec(code)) !== null) {
|
|
485
|
+
imports.push({
|
|
486
|
+
source: match[3],
|
|
487
|
+
default: match[1],
|
|
488
|
+
named: match[2] ? match[2].split(',').map(s => s.trim()) : [],
|
|
489
|
+
type: 'commonjs',
|
|
490
|
+
});
|
|
491
|
+
}
|
|
492
|
+
// Parse exports
|
|
493
|
+
while ((match = exportRegex.exec(code)) !== null) {
|
|
494
|
+
if (match[3]) {
|
|
495
|
+
exports.push({
|
|
496
|
+
name: match[3],
|
|
497
|
+
type: match[1] === 'default' ? 'default' : 'named',
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
// Parse functions
|
|
502
|
+
while ((match = functionRegex.exec(code)) !== null) {
|
|
503
|
+
functions.push({
|
|
504
|
+
name: match[1],
|
|
505
|
+
params: match[2].split(',').map(p => p.trim().split(/[:\s]/)[0]).filter(Boolean),
|
|
506
|
+
async: code.substring(match.index - 10, match.index).includes('async'),
|
|
507
|
+
exported: code.substring(match.index - 10, match.index).includes('export'),
|
|
508
|
+
startLine: code.substring(0, match.index).split('\n').length,
|
|
509
|
+
endLine: 0,
|
|
510
|
+
complexity: 1,
|
|
511
|
+
calls: [],
|
|
512
|
+
});
|
|
513
|
+
}
|
|
514
|
+
while ((match = arrowRegex.exec(code)) !== null) {
|
|
515
|
+
functions.push({
|
|
516
|
+
name: match[1],
|
|
517
|
+
params: [],
|
|
518
|
+
async: code.substring(match.index, match.index + 50).includes('async'),
|
|
519
|
+
exported: false,
|
|
520
|
+
startLine: code.substring(0, match.index).split('\n').length,
|
|
521
|
+
endLine: 0,
|
|
522
|
+
complexity: 1,
|
|
523
|
+
calls: [],
|
|
524
|
+
});
|
|
525
|
+
}
|
|
526
|
+
// Parse classes
|
|
527
|
+
while ((match = classRegex.exec(code)) !== null) {
|
|
528
|
+
classes.push({
|
|
529
|
+
name: match[1],
|
|
530
|
+
extends: match[2],
|
|
531
|
+
implements: [],
|
|
532
|
+
methods: [],
|
|
533
|
+
properties: [],
|
|
534
|
+
exported: code.substring(match.index - 10, match.index).includes('export'),
|
|
535
|
+
startLine: code.substring(0, match.index).split('\n').length,
|
|
536
|
+
endLine: 0,
|
|
537
|
+
});
|
|
538
|
+
}
|
|
539
|
+
// Parse types
|
|
540
|
+
while ((match = typeRegex.exec(code)) !== null) {
|
|
541
|
+
types.push(match[1]);
|
|
542
|
+
}
|
|
543
|
+
return {
|
|
544
|
+
file,
|
|
545
|
+
language: lang,
|
|
546
|
+
imports,
|
|
547
|
+
exports,
|
|
548
|
+
functions,
|
|
549
|
+
classes,
|
|
550
|
+
variables,
|
|
551
|
+
types,
|
|
552
|
+
complexity: this.calculateComplexity(code),
|
|
553
|
+
lines: lines.length,
|
|
554
|
+
parseTime: performance.now() - start,
|
|
555
|
+
};
|
|
556
|
+
}
|
|
557
|
+
/**
|
|
558
|
+
* Get all symbols (functions, classes, types) in a file
|
|
559
|
+
*/
|
|
560
|
+
async getSymbols(file) {
|
|
561
|
+
const analysis = await this.analyze(file);
|
|
562
|
+
return [
|
|
563
|
+
...analysis.functions.map(f => f.name),
|
|
564
|
+
...analysis.classes.map(c => c.name),
|
|
565
|
+
...analysis.types,
|
|
566
|
+
...analysis.variables,
|
|
567
|
+
];
|
|
568
|
+
}
|
|
569
|
+
/**
|
|
570
|
+
* Get the call graph for a file
|
|
571
|
+
*/
|
|
572
|
+
async getCallGraph(file) {
|
|
573
|
+
const analysis = await this.analyze(file);
|
|
574
|
+
const graph = new Map();
|
|
575
|
+
for (const fn of analysis.functions) {
|
|
576
|
+
graph.set(fn.name, fn.calls);
|
|
577
|
+
}
|
|
578
|
+
for (const cls of analysis.classes) {
|
|
579
|
+
for (const method of cls.methods) {
|
|
580
|
+
graph.set(`${cls.name}.${method.name}`, method.calls);
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
return graph;
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
exports.CodeParser = CodeParser;
|
|
587
|
+
// ============================================================================
|
|
588
|
+
// Singleton
|
|
589
|
+
// ============================================================================
|
|
590
|
+
let parserInstance = null;
|
|
591
|
+
function getCodeParser() {
|
|
592
|
+
if (!parserInstance) {
|
|
593
|
+
parserInstance = new CodeParser();
|
|
594
|
+
}
|
|
595
|
+
return parserInstance;
|
|
596
|
+
}
|
|
597
|
+
async function initCodeParser() {
|
|
598
|
+
const parser = getCodeParser();
|
|
599
|
+
await parser.init();
|
|
600
|
+
return parser;
|
|
601
|
+
}
|
|
602
|
+
exports.default = CodeParser;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Coverage Router - Test coverage-aware agent routing
|
|
3
|
+
*
|
|
4
|
+
* Uses test coverage data to make smarter routing decisions:
|
|
5
|
+
* - Prioritize testing for uncovered code
|
|
6
|
+
* - Route to tester agent for low-coverage files
|
|
7
|
+
* - Suggest test files for modified code
|
|
8
|
+
*/
|
|
9
|
+
export interface CoverageData {
|
|
10
|
+
file: string;
|
|
11
|
+
lines: {
|
|
12
|
+
total: number;
|
|
13
|
+
covered: number;
|
|
14
|
+
percentage: number;
|
|
15
|
+
};
|
|
16
|
+
functions: {
|
|
17
|
+
total: number;
|
|
18
|
+
covered: number;
|
|
19
|
+
percentage: number;
|
|
20
|
+
};
|
|
21
|
+
branches: {
|
|
22
|
+
total: number;
|
|
23
|
+
covered: number;
|
|
24
|
+
percentage: number;
|
|
25
|
+
};
|
|
26
|
+
uncoveredLines: number[];
|
|
27
|
+
uncoveredFunctions: string[];
|
|
28
|
+
}
|
|
29
|
+
export interface CoverageSummary {
|
|
30
|
+
files: Map<string, CoverageData>;
|
|
31
|
+
overall: {
|
|
32
|
+
lines: number;
|
|
33
|
+
functions: number;
|
|
34
|
+
branches: number;
|
|
35
|
+
};
|
|
36
|
+
lowCoverageFiles: string[];
|
|
37
|
+
uncoveredFiles: string[];
|
|
38
|
+
}
|
|
39
|
+
export interface TestSuggestion {
|
|
40
|
+
file: string;
|
|
41
|
+
testFile: string;
|
|
42
|
+
reason: string;
|
|
43
|
+
priority: 'high' | 'medium' | 'low';
|
|
44
|
+
coverage: number;
|
|
45
|
+
uncoveredFunctions: string[];
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Parse Istanbul/NYC JSON coverage report
|
|
49
|
+
*/
|
|
50
|
+
export declare function parseIstanbulCoverage(coveragePath: string): CoverageSummary;
|
|
51
|
+
/**
|
|
52
|
+
* Find coverage report in project
|
|
53
|
+
*/
|
|
54
|
+
export declare function findCoverageReport(projectRoot?: string): string | null;
|
|
55
|
+
/**
|
|
56
|
+
* Get coverage data for a specific file
|
|
57
|
+
*/
|
|
58
|
+
export declare function getFileCoverage(file: string, summary?: CoverageSummary): CoverageData | null;
|
|
59
|
+
/**
|
|
60
|
+
* Suggest tests for files based on coverage
|
|
61
|
+
*/
|
|
62
|
+
export declare function suggestTests(files: string[], summary?: CoverageSummary): TestSuggestion[];
|
|
63
|
+
/**
|
|
64
|
+
* Determine if a file needs the tester agent based on coverage
|
|
65
|
+
*/
|
|
66
|
+
export declare function shouldRouteToTester(file: string, summary?: CoverageSummary): {
|
|
67
|
+
route: boolean;
|
|
68
|
+
reason: string;
|
|
69
|
+
coverage: number;
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* Get coverage-aware routing weight for agent selection
|
|
73
|
+
*/
|
|
74
|
+
export declare function getCoverageRoutingWeight(file: string, summary?: CoverageSummary): {
|
|
75
|
+
coder: number;
|
|
76
|
+
tester: number;
|
|
77
|
+
reviewer: number;
|
|
78
|
+
};
|
|
79
|
+
declare const _default: {
|
|
80
|
+
parseIstanbulCoverage: typeof parseIstanbulCoverage;
|
|
81
|
+
findCoverageReport: typeof findCoverageReport;
|
|
82
|
+
getFileCoverage: typeof getFileCoverage;
|
|
83
|
+
suggestTests: typeof suggestTests;
|
|
84
|
+
shouldRouteToTester: typeof shouldRouteToTester;
|
|
85
|
+
getCoverageRoutingWeight: typeof getCoverageRoutingWeight;
|
|
86
|
+
};
|
|
87
|
+
export default _default;
|
|
88
|
+
//# sourceMappingURL=coverage-router.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coverage-router.d.ts","sourceRoot":"","sources":["../../src/core/coverage-router.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE;QACL,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,EAAE,MAAM,CAAC;QAChB,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,SAAS,EAAE;QACT,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,EAAE,MAAM,CAAC;QAChB,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,QAAQ,EAAE;QACR,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,EAAE,MAAM,CAAC;QAChB,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,kBAAkB,EAAE,MAAM,EAAE,CAAC;CAC9B;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IACjC,OAAO,EAAE;QACP,KAAK,EAAE,MAAM,CAAC;QACd,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC;IACF,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,kBAAkB,EAAE,MAAM,EAAE,CAAC;CAC9B;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,YAAY,EAAE,MAAM,GAAG,eAAe,CA0F3E;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,GAAE,MAAsB,GAAG,MAAM,GAAG,IAAI,CAiBrF;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,YAAY,GAAG,IAAI,CAqB5F;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,cAAc,EAAE,CAwEzF;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG;IAC5E,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB,CAgCA;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG;IACjF,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB,CAuBA;;;;;;;;;AAED,wBAOE"}
|