agentic-qe 3.8.11 → 3.8.13
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/.claude/skills/qe-code-intelligence/SKILL.md +29 -20
- package/.claude/skills/qe-code-intelligence/evals/qe-code-intelligence.yaml +3 -3
- package/.claude/skills/qe-quality-assessment/SKILL.md +1 -1
- package/.claude/skills/qe-test-generation/SKILL.md +1 -1
- package/.claude/skills/skills-manifest.json +1 -1
- package/CHANGELOG.md +45 -0
- package/README.md +9 -0
- package/assets/skills/qe-code-intelligence/SKILL.md +29 -20
- package/assets/skills/qe-code-intelligence/evals/qe-code-intelligence.yaml +3 -3
- package/assets/skills/qe-quality-assessment/SKILL.md +1 -1
- package/assets/skills/qe-test-generation/SKILL.md +1 -1
- package/dist/cli/bundle.js +1162 -1046
- package/dist/cli/commands/code.js +149 -11
- package/dist/cli/commands/init.js +3 -2
- package/dist/cli/commands/ruvector-commands.js +17 -0
- package/dist/cli/handlers/init-handler.d.ts +1 -0
- package/dist/cli/handlers/init-handler.js +15 -10
- package/dist/cli/utils/file-discovery.d.ts +1 -0
- package/dist/cli/utils/file-discovery.js +1 -1
- package/dist/domains/code-intelligence/coordinator-gnn.d.ts +21 -0
- package/dist/domains/code-intelligence/coordinator-gnn.js +102 -0
- package/dist/domains/contract-testing/coordinator.js +13 -0
- package/dist/domains/coverage-analysis/coordinator.js +5 -0
- package/dist/domains/defect-intelligence/coordinator.d.ts +1 -0
- package/dist/domains/defect-intelligence/coordinator.js +43 -0
- package/dist/domains/quality-assessment/coordinator.js +26 -0
- package/dist/domains/test-generation/coordinator.js +14 -0
- package/dist/init/orchestrator.js +1 -0
- package/dist/init/phases/08-mcp.js +4 -4
- package/dist/init/phases/phase-interface.d.ts +3 -1
- package/dist/integrations/agentic-flow/reasoning-bank/experience-replay.d.ts +11 -0
- package/dist/integrations/agentic-flow/reasoning-bank/experience-replay.js +44 -1
- package/dist/integrations/rl-suite/algorithms/eprop.d.ts +79 -0
- package/dist/integrations/rl-suite/algorithms/eprop.js +284 -0
- package/dist/integrations/rl-suite/algorithms/index.d.ts +2 -1
- package/dist/integrations/rl-suite/algorithms/index.js +2 -1
- package/dist/integrations/rl-suite/index.d.ts +2 -2
- package/dist/integrations/rl-suite/index.js +2 -2
- package/dist/integrations/rl-suite/interfaces.d.ts +3 -3
- package/dist/integrations/rl-suite/interfaces.js +1 -1
- package/dist/integrations/rl-suite/orchestrator.d.ts +2 -2
- package/dist/integrations/rl-suite/orchestrator.js +3 -2
- package/dist/integrations/rl-suite/reward-signals.d.ts +1 -1
- package/dist/integrations/rl-suite/reward-signals.js +1 -1
- package/dist/integrations/ruvector/coherence-gate-cohomology.d.ts +41 -0
- package/dist/integrations/ruvector/coherence-gate-cohomology.js +47 -0
- package/dist/integrations/ruvector/coherence-gate-core.d.ts +200 -0
- package/dist/integrations/ruvector/coherence-gate-core.js +294 -0
- package/dist/integrations/ruvector/coherence-gate-energy.d.ts +136 -0
- package/dist/integrations/ruvector/coherence-gate-energy.js +373 -0
- package/dist/integrations/ruvector/coherence-gate-vector.d.ts +38 -0
- package/dist/integrations/ruvector/coherence-gate-vector.js +76 -0
- package/dist/integrations/ruvector/coherence-gate.d.ts +10 -311
- package/dist/integrations/ruvector/coherence-gate.js +10 -652
- package/dist/integrations/ruvector/cold-tier-trainer.d.ts +103 -0
- package/dist/integrations/ruvector/cold-tier-trainer.js +377 -0
- package/dist/integrations/ruvector/cusum-detector.d.ts +70 -0
- package/dist/integrations/ruvector/cusum-detector.js +142 -0
- package/dist/integrations/ruvector/delta-tracker.d.ts +122 -0
- package/dist/integrations/ruvector/delta-tracker.js +311 -0
- package/dist/integrations/ruvector/domain-transfer.d.ts +79 -1
- package/dist/integrations/ruvector/domain-transfer.js +158 -2
- package/dist/integrations/ruvector/eprop-learner.d.ts +135 -0
- package/dist/integrations/ruvector/eprop-learner.js +351 -0
- package/dist/integrations/ruvector/feature-flags.d.ts +177 -0
- package/dist/integrations/ruvector/feature-flags.js +145 -0
- package/dist/integrations/ruvector/graphmae-encoder.d.ts +88 -0
- package/dist/integrations/ruvector/graphmae-encoder.js +360 -0
- package/dist/integrations/ruvector/hdc-fingerprint.d.ts +127 -0
- package/dist/integrations/ruvector/hdc-fingerprint.js +222 -0
- package/dist/integrations/ruvector/hopfield-memory.d.ts +97 -0
- package/dist/integrations/ruvector/hopfield-memory.js +238 -0
- package/dist/integrations/ruvector/index.d.ts +13 -2
- package/dist/integrations/ruvector/index.js +46 -2
- package/dist/integrations/ruvector/mincut-wrapper.d.ts +7 -0
- package/dist/integrations/ruvector/mincut-wrapper.js +54 -2
- package/dist/integrations/ruvector/reservoir-replay.d.ts +172 -0
- package/dist/integrations/ruvector/reservoir-replay.js +335 -0
- package/dist/integrations/ruvector/solver-adapter.d.ts +93 -0
- package/dist/integrations/ruvector/solver-adapter.js +299 -0
- package/dist/integrations/ruvector/sona-persistence.d.ts +33 -0
- package/dist/integrations/ruvector/sona-persistence.js +47 -0
- package/dist/integrations/ruvector/spectral-sparsifier.d.ts +154 -0
- package/dist/integrations/ruvector/spectral-sparsifier.js +389 -0
- package/dist/integrations/ruvector/temporal-causality.d.ts +63 -0
- package/dist/integrations/ruvector/temporal-causality.js +317 -0
- package/dist/learning/pattern-promotion.d.ts +63 -0
- package/dist/learning/pattern-promotion.js +235 -1
- package/dist/learning/pattern-store.d.ts +2 -0
- package/dist/learning/pattern-store.js +187 -1
- package/dist/learning/sqlite-persistence.d.ts +2 -0
- package/dist/learning/sqlite-persistence.js +4 -0
- package/dist/mcp/bundle.js +506 -427
- package/dist/shared/utils/index.d.ts +1 -0
- package/dist/shared/utils/index.js +1 -0
- package/dist/shared/utils/xorshift128.d.ts +24 -0
- package/dist/shared/utils/xorshift128.js +50 -0
- package/package.json +1 -1
|
@@ -5,17 +5,29 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { Command } from 'commander';
|
|
7
7
|
import chalk from 'chalk';
|
|
8
|
-
import { walkSourceFiles } from '../utils/file-discovery.js';
|
|
8
|
+
import { walkSourceFiles, SOURCE_EXTENSIONS } from '../utils/file-discovery.js';
|
|
9
9
|
import { writeOutput, toJSON } from '../utils/ci-output.js';
|
|
10
10
|
export function createCodeCommand(context, cleanupAndExit, ensureInitialized) {
|
|
11
11
|
const codeCmd = new Command('code')
|
|
12
12
|
.description('Code intelligence analysis')
|
|
13
|
-
.argument('<action>', 'Action (index|search|impact|deps)')
|
|
13
|
+
.argument('<action>', 'Action (index|search|impact|deps|complexity)')
|
|
14
14
|
.argument('[target]', 'Target path or query')
|
|
15
15
|
.option('--depth <depth>', 'Analysis depth', '3')
|
|
16
16
|
.option('--include-tests', 'Include test files')
|
|
17
|
+
.option('--incremental', 'Incremental indexing (index action only)')
|
|
18
|
+
.option('--git-since <ref>', 'Index changes since git ref (index action only)')
|
|
17
19
|
.option('-F, --format <format>', 'Output format (text|json)', 'text')
|
|
18
20
|
.option('-o, --output <path>', 'Write output to file')
|
|
21
|
+
.addHelpText('after', `
|
|
22
|
+
Examples:
|
|
23
|
+
aqe code index src/ Index source files into knowledge graph
|
|
24
|
+
aqe code index src/ --incremental Incremental index (only changed files)
|
|
25
|
+
aqe code index . --git-since HEAD~5 Index files changed in last 5 commits
|
|
26
|
+
aqe code search "authentication" Semantic code search
|
|
27
|
+
aqe code impact src/auth/ Analyze change impact
|
|
28
|
+
aqe code deps src/ Map dependencies
|
|
29
|
+
aqe code complexity src/ Analyze code complexity metrics
|
|
30
|
+
`)
|
|
19
31
|
.action(async (action, target, options) => {
|
|
20
32
|
if (!await ensureInitialized())
|
|
21
33
|
return;
|
|
@@ -27,17 +39,47 @@ export function createCodeCommand(context, cleanupAndExit, ensureInitialized) {
|
|
|
27
39
|
}
|
|
28
40
|
const path = await import('path');
|
|
29
41
|
const format = (options.format || 'text');
|
|
42
|
+
const parsedDepth = parseInt(options.depth);
|
|
43
|
+
if (isNaN(parsedDepth) || parsedDepth < 1) {
|
|
44
|
+
console.log(chalk.red(`Invalid --depth value: "${options.depth}" (must be a positive integer)`));
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
30
47
|
if (action === 'index') {
|
|
31
|
-
|
|
48
|
+
const incremental = options.incremental || false;
|
|
49
|
+
const gitSince = options.gitSince;
|
|
50
|
+
const label = incremental ? 'Incrementally indexing' : 'Indexing';
|
|
51
|
+
console.log(chalk.blue(`\n ${label} codebase at ${target || '.'}${gitSince ? ` (since ${gitSince})` : ''}...\n`));
|
|
32
52
|
const targetPath = path.resolve(target || '.');
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
53
|
+
let paths;
|
|
54
|
+
if (gitSince) {
|
|
55
|
+
// Use git diff to find changed files since the ref
|
|
56
|
+
// SEC: Use execFileSync with array args to prevent shell injection (CWE-78)
|
|
57
|
+
const { execFileSync } = await import('child_process');
|
|
58
|
+
try {
|
|
59
|
+
const diffOutput = execFileSync('git', ['diff', '--name-only', '--diff-filter=ACMR', gitSince, '--', targetPath], { encoding: 'utf-8', cwd: process.cwd() }).trim();
|
|
60
|
+
paths = diffOutput
|
|
61
|
+
? diffOutput.split('\n')
|
|
62
|
+
.filter(f => SOURCE_EXTENSIONS.has(path.extname(f)))
|
|
63
|
+
.map(f => path.resolve(f))
|
|
64
|
+
: [];
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
console.log(chalk.yellow(` Warning: git diff failed for ref "${gitSince}", falling back to full scan`));
|
|
68
|
+
paths = walkSourceFiles(targetPath, {
|
|
69
|
+
includeTests: options.includeTests || false,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
// Fix #280: Use shared file discovery supporting all languages
|
|
75
|
+
paths = walkSourceFiles(targetPath, {
|
|
76
|
+
includeTests: options.includeTests || false,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
37
79
|
console.log(chalk.gray(` Found ${paths.length} files to index...\n`));
|
|
38
80
|
const result = await codeAPI.index({
|
|
39
81
|
paths,
|
|
40
|
-
incremental
|
|
82
|
+
incremental,
|
|
41
83
|
includeTests: options.includeTests || false,
|
|
42
84
|
});
|
|
43
85
|
if (result.success && result.value) {
|
|
@@ -101,7 +143,7 @@ export function createCodeCommand(context, cleanupAndExit, ensureInitialized) {
|
|
|
101
143
|
const changedFiles = walkSourceFiles(targetPath, { maxDepth: 2 }).slice(0, 10);
|
|
102
144
|
const result = await codeAPI.analyzeImpact({
|
|
103
145
|
changedFiles,
|
|
104
|
-
depth:
|
|
146
|
+
depth: parsedDepth,
|
|
105
147
|
includeTests: options.includeTests || false,
|
|
106
148
|
});
|
|
107
149
|
if (result.success && result.value) {
|
|
@@ -151,7 +193,7 @@ export function createCodeCommand(context, cleanupAndExit, ensureInitialized) {
|
|
|
151
193
|
const result = await codeAPI.mapDependencies({
|
|
152
194
|
files,
|
|
153
195
|
direction: 'both',
|
|
154
|
-
depth:
|
|
196
|
+
depth: parsedDepth,
|
|
155
197
|
});
|
|
156
198
|
if (result.success && result.value) {
|
|
157
199
|
const deps = result.value;
|
|
@@ -184,9 +226,105 @@ export function createCodeCommand(context, cleanupAndExit, ensureInitialized) {
|
|
|
184
226
|
console.log(chalk.red(`Failed: ${result.error?.message || 'Unknown error'}`));
|
|
185
227
|
}
|
|
186
228
|
}
|
|
229
|
+
else if (action === 'complexity') {
|
|
230
|
+
console.log(chalk.blue(`\n Analyzing complexity for ${target || '.'}...\n`));
|
|
231
|
+
const targetPath = path.resolve(target || '.');
|
|
232
|
+
const files = walkSourceFiles(targetPath, {
|
|
233
|
+
includeTests: options.includeTests || false,
|
|
234
|
+
maxDepth: 3,
|
|
235
|
+
}).slice(0, 50);
|
|
236
|
+
if (files.length === 0) {
|
|
237
|
+
console.log(chalk.yellow(' No source files found'));
|
|
238
|
+
return await cleanupAndExit(0);
|
|
239
|
+
}
|
|
240
|
+
const fs = await import('fs');
|
|
241
|
+
const analyzer = typeof codeAPI.getSemanticAnalyzer === 'function'
|
|
242
|
+
? codeAPI.getSemanticAnalyzer()
|
|
243
|
+
: null;
|
|
244
|
+
if (!analyzer) {
|
|
245
|
+
console.log(chalk.red('Semantic analyzer not available — ensure fleet is initialized'));
|
|
246
|
+
return await cleanupAndExit(1);
|
|
247
|
+
}
|
|
248
|
+
// Analyze files in batches of 8 for concurrency
|
|
249
|
+
const BATCH_SIZE = 8;
|
|
250
|
+
const results = [];
|
|
251
|
+
for (let i = 0; i < files.length; i += BATCH_SIZE) {
|
|
252
|
+
const batch = files.slice(i, i + BATCH_SIZE);
|
|
253
|
+
const batchResults = await Promise.all(batch.map(async (file) => {
|
|
254
|
+
try {
|
|
255
|
+
const content = fs.readFileSync(file, 'utf-8');
|
|
256
|
+
const analysisResult = await analyzer.analyze(content);
|
|
257
|
+
if (analysisResult.success && analysisResult.value) {
|
|
258
|
+
const a = analysisResult.value;
|
|
259
|
+
return {
|
|
260
|
+
file,
|
|
261
|
+
cyclomatic: a.complexity.cyclomatic,
|
|
262
|
+
cognitive: a.complexity.cognitive,
|
|
263
|
+
halstead: a.complexity.halstead,
|
|
264
|
+
suggestions: a.suggestions,
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
catch {
|
|
269
|
+
// Skip files that can't be read/analyzed
|
|
270
|
+
}
|
|
271
|
+
return null;
|
|
272
|
+
}));
|
|
273
|
+
for (const r of batchResults) {
|
|
274
|
+
if (r)
|
|
275
|
+
results.push(r);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
// Sort by cyclomatic complexity descending
|
|
279
|
+
results.sort((a, b) => b.cyclomatic - a.cyclomatic);
|
|
280
|
+
// Compute aggregates
|
|
281
|
+
const totalCyclomatic = results.reduce((s, r) => s + r.cyclomatic, 0);
|
|
282
|
+
const avgCyclomatic = results.length > 0 ? totalCyclomatic / results.length : 0;
|
|
283
|
+
const maxCyclomatic = results.length > 0 ? results[0].cyclomatic : 0;
|
|
284
|
+
const totalBugs = results.reduce((s, r) => s + r.halstead.bugs, 0);
|
|
285
|
+
const highComplexity = results.filter(r => r.cyclomatic > 10).length;
|
|
286
|
+
if (format === 'json') {
|
|
287
|
+
writeOutput(toJSON({
|
|
288
|
+
filesAnalyzed: results.length,
|
|
289
|
+
aggregate: {
|
|
290
|
+
totalCyclomatic,
|
|
291
|
+
avgCyclomatic: Math.round(avgCyclomatic * 100) / 100,
|
|
292
|
+
maxCyclomatic,
|
|
293
|
+
estimatedBugs: Math.round(totalBugs * 1000) / 1000,
|
|
294
|
+
highComplexityFiles: highComplexity,
|
|
295
|
+
},
|
|
296
|
+
files: results,
|
|
297
|
+
}), options.output);
|
|
298
|
+
}
|
|
299
|
+
else {
|
|
300
|
+
console.log(chalk.cyan(' Aggregate Metrics:'));
|
|
301
|
+
console.log(` Files analyzed: ${chalk.white(results.length)}`);
|
|
302
|
+
console.log(` Avg cyclomatic: ${chalk.yellow(avgCyclomatic.toFixed(2))}`);
|
|
303
|
+
console.log(` Max cyclomatic: ${maxCyclomatic > 20 ? chalk.red(maxCyclomatic) : maxCyclomatic > 10 ? chalk.yellow(maxCyclomatic) : chalk.green(maxCyclomatic)}`);
|
|
304
|
+
console.log(` Estimated bugs: ${chalk.yellow(totalBugs.toFixed(3))}`);
|
|
305
|
+
console.log(` High complexity (>10): ${highComplexity > 0 ? chalk.red(highComplexity) : chalk.green(highComplexity)}`);
|
|
306
|
+
// Show top hotspots
|
|
307
|
+
const hotspots = results.filter(r => r.cyclomatic > 5).slice(0, 10);
|
|
308
|
+
if (hotspots.length > 0) {
|
|
309
|
+
console.log(chalk.cyan('\n Complexity Hotspots:'));
|
|
310
|
+
for (const h of hotspots) {
|
|
311
|
+
const filePath = h.file.replace(process.cwd() + '/', '');
|
|
312
|
+
const cyclColor = h.cyclomatic > 20 ? chalk.red : h.cyclomatic > 10 ? chalk.yellow : chalk.white;
|
|
313
|
+
console.log(` ${chalk.white(filePath)}`);
|
|
314
|
+
console.log(chalk.gray(` Cyclomatic: ${cyclColor(h.cyclomatic)} Cognitive: ${h.cognitive} Halstead bugs: ${h.halstead.bugs}`));
|
|
315
|
+
if (h.suggestions.length > 0) {
|
|
316
|
+
console.log(chalk.gray(` Suggestion: ${h.suggestions[0]}`));
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
if (highComplexity === 0) {
|
|
321
|
+
console.log(chalk.green('\n All files within acceptable complexity thresholds'));
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}
|
|
187
325
|
else {
|
|
188
326
|
console.log(chalk.red(`\nUnknown action: ${action}`));
|
|
189
|
-
console.log(chalk.gray(' Available: index, search, impact, deps\n'));
|
|
327
|
+
console.log(chalk.gray(' Available: index, search, impact, deps, complexity\n'));
|
|
190
328
|
await cleanupAndExit(1);
|
|
191
329
|
}
|
|
192
330
|
console.log('');
|
|
@@ -41,7 +41,8 @@ export function createInitCommand() {
|
|
|
41
41
|
.option('--with-codex', 'Include OpenAI Codex CLI MCP config and AGENTS.md')
|
|
42
42
|
.option('--with-windsurf', 'Include Windsurf MCP config and rules')
|
|
43
43
|
.option('--with-continuedev', 'Include Continue.dev MCP config and rules')
|
|
44
|
-
.option('--
|
|
44
|
+
.option('--no-mcp', 'Skip MCP server config (MCP is enabled by default)')
|
|
45
|
+
.option('--with-mcp', 'Enable MCP server config (default — kept for backward compatibility)')
|
|
45
46
|
.option('--with-all-platforms', 'Include all coding agent platform configurations')
|
|
46
47
|
.option('--with-claude-flow', 'Force Claude Flow integration setup')
|
|
47
48
|
.option('--skip-claude-flow', 'Skip Claude Flow integration')
|
|
@@ -114,7 +115,7 @@ async function runInit(options) {
|
|
|
114
115
|
withCodex: options.withCodex,
|
|
115
116
|
withWindsurf: options.withWindsurf,
|
|
116
117
|
withContinueDev: options.withContinuedev,
|
|
117
|
-
|
|
118
|
+
noMcp: options.noMcp && !options.withMcp,
|
|
118
119
|
noGovernance: options.noGovernance,
|
|
119
120
|
});
|
|
120
121
|
// Run initialization
|
|
@@ -50,6 +50,23 @@ const FLAG_DESCRIPTIONS = {
|
|
|
50
50
|
useDAGAttention: 'DAG attention for test scheduling (Task 4.2)',
|
|
51
51
|
useCoherenceActionGate: 'Coherence-gated agent actions (ADR-083, Task 3.2)',
|
|
52
52
|
useReasoningQEC: 'Reasoning QEC error correction (Task 4.5)',
|
|
53
|
+
// Phase 5 (ADR-087)
|
|
54
|
+
useHDCFingerprinting: 'HDC pattern fingerprinting (R1, ADR-087)',
|
|
55
|
+
useCusumDriftDetection: 'CUSUM drift detection (R2, ADR-087)',
|
|
56
|
+
useDeltaEventSourcing: 'Delta event sourcing (R3, ADR-087)',
|
|
57
|
+
useEwcPlusPlusRegularization: 'EWC++ regularization (ADR-087)',
|
|
58
|
+
// Phase 5 Milestone 2 (ADR-087)
|
|
59
|
+
useGraphMAEEmbeddings: 'GraphMAE self-supervised embeddings (R4, ADR-087)',
|
|
60
|
+
useHopfieldMemory: 'Modern Hopfield memory (R5, ADR-087)',
|
|
61
|
+
useColdTierGNN: 'Cold-tier GNN training (R6, ADR-087)',
|
|
62
|
+
// Phase 5 Milestone 3 (ADR-087)
|
|
63
|
+
useMetaLearningEnhancements: 'Meta-learning enhancements (R7, ADR-087)',
|
|
64
|
+
useSublinearSolver: 'Sublinear PageRank solver (R8, ADR-087)',
|
|
65
|
+
useSpectralSparsification: 'Spectral graph sparsification (R9, ADR-087)',
|
|
66
|
+
useReservoirReplay: 'Reservoir replay with coherence gating (R10, ADR-087)',
|
|
67
|
+
// Phase 5 Milestone 4 (ADR-087)
|
|
68
|
+
useEpropOnlineLearning: 'E-prop online learning, RL algorithm #10 (R11, ADR-087)',
|
|
69
|
+
useGrangerCausality: 'Granger causality for test failure prediction (R12, ADR-087)',
|
|
53
70
|
};
|
|
54
71
|
const PROFILES = {
|
|
55
72
|
performance: {
|
|
@@ -49,7 +49,8 @@ export class InitHandler {
|
|
|
49
49
|
.option('--with-codex', 'Include OpenAI Codex CLI MCP config and AGENTS.md')
|
|
50
50
|
.option('--with-windsurf', 'Include Windsurf MCP config and rules')
|
|
51
51
|
.option('--with-continuedev', 'Include Continue.dev MCP config and rules')
|
|
52
|
-
.option('--
|
|
52
|
+
.option('--no-mcp', 'Skip MCP server config (MCP is enabled by default)')
|
|
53
|
+
.option('--with-mcp', 'Enable MCP server config (default — kept for backward compatibility)')
|
|
53
54
|
.option('--with-all-platforms', 'Include all coding agent platform configurations')
|
|
54
55
|
.option('--auto-migrate', 'Automatically migrate from v2 if detected')
|
|
55
56
|
.option('--with-claude-flow', 'Force Claude Flow integration setup')
|
|
@@ -115,7 +116,7 @@ export class InitHandler {
|
|
|
115
116
|
withCodex: options.withCodex,
|
|
116
117
|
withWindsurf: options.withWindsurf,
|
|
117
118
|
withContinueDev: options.withContinuedev,
|
|
118
|
-
|
|
119
|
+
noMcp: options.noMcp && !options.withMcp,
|
|
119
120
|
noGovernance: options.noGovernance,
|
|
120
121
|
});
|
|
121
122
|
console.log(chalk.white(' Analyzing project...\n'));
|
|
@@ -175,10 +176,9 @@ export class InitHandler {
|
|
|
175
176
|
console.log(chalk.gray(' 1. Run tests: aqe test <path>'));
|
|
176
177
|
console.log(chalk.gray(' 2. Check coverage: aqe coverage <path>'));
|
|
177
178
|
console.log(chalk.gray(' 3. Check status: aqe status'));
|
|
178
|
-
if (
|
|
179
|
-
console.log(chalk.gray('\n
|
|
180
|
-
console.log(chalk.gray('
|
|
181
|
-
console.log(chalk.gray(' # or manually: claude mcp add aqe -- aqe-mcp\n'));
|
|
179
|
+
if (result.summary.mcpConfigured) {
|
|
180
|
+
console.log(chalk.gray('\n MCP server configured in .mcp.json'));
|
|
181
|
+
console.log(chalk.gray(' Use --no-mcp to skip MCP setup if using CLI only\n'));
|
|
182
182
|
}
|
|
183
183
|
}
|
|
184
184
|
else {
|
|
@@ -230,10 +230,9 @@ export class InitHandler {
|
|
|
230
230
|
console.log(chalk.gray(' 1. Run tests: aqe test <path>'));
|
|
231
231
|
console.log(chalk.gray(' 2. Check coverage: aqe coverage <path>'));
|
|
232
232
|
console.log(chalk.gray(' 3. Check status: aqe status'));
|
|
233
|
-
if (
|
|
234
|
-
console.log(chalk.gray('\n
|
|
235
|
-
console.log(chalk.gray('
|
|
236
|
-
console.log(chalk.gray(' # or manually: claude mcp add aqe -- aqe-mcp\n'));
|
|
233
|
+
if (result.summary.mcpConfigured) {
|
|
234
|
+
console.log(chalk.gray('\n MCP server configured in .mcp.json'));
|
|
235
|
+
console.log(chalk.gray(' Use --no-mcp to skip MCP setup if using CLI only\n'));
|
|
237
236
|
}
|
|
238
237
|
}
|
|
239
238
|
else {
|
|
@@ -338,9 +337,15 @@ Options:
|
|
|
338
337
|
--auto-migrate Automatically migrate from v2 if detected
|
|
339
338
|
--with-claude-flow Force Claude Flow integration setup
|
|
340
339
|
--skip-claude-flow Skip Claude Flow integration
|
|
340
|
+
--no-mcp Skip MCP server config (MCP is enabled by default)
|
|
341
341
|
--no-governance Skip governance configuration (ADR-058)
|
|
342
342
|
--modular Use new modular init system
|
|
343
343
|
|
|
344
|
+
MCP Server:
|
|
345
|
+
MCP server configuration is ENABLED BY DEFAULT. It writes .mcp.json
|
|
346
|
+
at the project root so Claude Code auto-discovers the AQE MCP server.
|
|
347
|
+
Use --no-mcp to skip if you only want CLI commands.
|
|
348
|
+
|
|
344
349
|
Governance:
|
|
345
350
|
Governance is ENABLED BY DEFAULT. It installs .claude/guidance/ with:
|
|
346
351
|
- constitution.md: 7 unbreakable QE invariants
|
|
@@ -11,7 +11,7 @@ import { join, extname } from 'path';
|
|
|
11
11
|
// ============================================================================
|
|
12
12
|
// Source File Extensions by Language
|
|
13
13
|
// ============================================================================
|
|
14
|
-
const SOURCE_EXTENSIONS = new Set([
|
|
14
|
+
export const SOURCE_EXTENSIONS = new Set([
|
|
15
15
|
// JavaScript / TypeScript
|
|
16
16
|
'.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs',
|
|
17
17
|
// Python
|
|
@@ -12,6 +12,13 @@ export declare function initializeGNNIndex(domainKey: string): QEGNNEmbeddingInd
|
|
|
12
12
|
* Index code embeddings in GNN for fast similarity search
|
|
13
13
|
*/
|
|
14
14
|
export declare function indexCodeEmbeddings(gnnIndex: QEGNNEmbeddingIndex, fileReader: FileReader, paths: string[]): Promise<void>;
|
|
15
|
+
/**
|
|
16
|
+
* R4: Generate graph-aware embeddings for a set of files using GraphMAE.
|
|
17
|
+
* Builds a dependency graph from import relationships and uses masked
|
|
18
|
+
* autoencoders to produce structure-aware embeddings.
|
|
19
|
+
* Falls back to feature-hash embeddings when GraphMAE is disabled.
|
|
20
|
+
*/
|
|
21
|
+
export declare function generateGraphMAEEmbeddings(fileReader: FileReader, paths: string[]): Promise<Map<string, number[]>>;
|
|
15
22
|
/**
|
|
16
23
|
* Generate code embedding using semantic features
|
|
17
24
|
*/
|
|
@@ -34,6 +41,20 @@ export declare function mergeSearchResults(semanticResults: SearchResult[], gnnR
|
|
|
34
41
|
file: string;
|
|
35
42
|
similarity: number;
|
|
36
43
|
}>): SearchResult[];
|
|
44
|
+
/**
|
|
45
|
+
* R6: Train GNN embeddings with memory-bounded cold-tier training.
|
|
46
|
+
* Uses LRU hotset caching when the graph exceeds hotsetSize, falling
|
|
47
|
+
* back to full in-memory training for small graphs.
|
|
48
|
+
*/
|
|
49
|
+
export declare function trainWithColdTier(nodeFeatures: Map<number, Float32Array>, adjacency: Map<number, number[]>, options?: {
|
|
50
|
+
hotsetSize?: number;
|
|
51
|
+
epochs?: number;
|
|
52
|
+
hiddenDim?: number;
|
|
53
|
+
}): {
|
|
54
|
+
embeddings: Map<number, Float32Array>;
|
|
55
|
+
loss: number;
|
|
56
|
+
usedColdTier: boolean;
|
|
57
|
+
};
|
|
37
58
|
/**
|
|
38
59
|
* Simple hash function for strings
|
|
39
60
|
*/
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { LoggerFactory } from '../../logging/index.js';
|
|
8
8
|
import { QEGNNIndexFactory, initGNN, } from '../../integrations/ruvector/wrappers';
|
|
9
|
+
import { isGraphMAEEnabled, isColdTierGNNEnabled, createGraphMAEEncoder, createColdTierTrainer, InMemoryGraph, } from '../../integrations/ruvector/index.js';
|
|
9
10
|
/**
|
|
10
11
|
* Initialize GNN for code graph embeddings
|
|
11
12
|
*/
|
|
@@ -55,6 +56,73 @@ export async function indexCodeEmbeddings(gnnIndex, fileReader, paths) {
|
|
|
55
56
|
logger.error('Failed to index code embeddings:', error instanceof Error ? error : undefined);
|
|
56
57
|
}
|
|
57
58
|
}
|
|
59
|
+
// R4: GraphMAE singleton encoder (lazy-initialized)
|
|
60
|
+
let graphMAEEncoder = null;
|
|
61
|
+
/**
|
|
62
|
+
* R4: Generate graph-aware embeddings for a set of files using GraphMAE.
|
|
63
|
+
* Builds a dependency graph from import relationships and uses masked
|
|
64
|
+
* autoencoders to produce structure-aware embeddings.
|
|
65
|
+
* Falls back to feature-hash embeddings when GraphMAE is disabled.
|
|
66
|
+
*/
|
|
67
|
+
export async function generateGraphMAEEmbeddings(fileReader, paths) {
|
|
68
|
+
const embeddings = new Map();
|
|
69
|
+
if (!isGraphMAEEnabled() || paths.length < 2) {
|
|
70
|
+
// Fallback: use feature-hash for each file independently
|
|
71
|
+
for (const p of paths) {
|
|
72
|
+
const result = await fileReader.readFile(p);
|
|
73
|
+
if (result.success && result.value) {
|
|
74
|
+
embeddings.set(p, await generateCodeEmbedding(p, result.value));
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return embeddings;
|
|
78
|
+
}
|
|
79
|
+
try {
|
|
80
|
+
// Build QEGraph: nodes are files, edges are import dependencies
|
|
81
|
+
const nodes = new Map();
|
|
82
|
+
const edges = new Map();
|
|
83
|
+
const contentCache = new Map();
|
|
84
|
+
for (const p of paths) {
|
|
85
|
+
const result = await fileReader.readFile(p);
|
|
86
|
+
if (result.success && result.value) {
|
|
87
|
+
contentCache.set(p, result.value);
|
|
88
|
+
const featureVec = await generateCodeEmbedding(p, result.value);
|
|
89
|
+
nodes.set(p, new Float32Array(featureVec.slice(0, 32)));
|
|
90
|
+
// Extract import targets as edges
|
|
91
|
+
const imports = result.value.match(/from\s+['"]([^'"]+)['"]/g) ?? [];
|
|
92
|
+
const targets = imports
|
|
93
|
+
.map(m => m.replace(/from\s+['"]/, '').replace(/['"]$/, ''))
|
|
94
|
+
.filter(t => paths.some(pp => pp.includes(t.replace(/^\.\//, ''))));
|
|
95
|
+
edges.set(p, targets.length > 0 ? targets : []);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
if (nodes.size < 2) {
|
|
99
|
+
// Not enough nodes for meaningful graph learning
|
|
100
|
+
for (const [p, content] of contentCache) {
|
|
101
|
+
embeddings.set(p, await generateCodeEmbedding(p, content));
|
|
102
|
+
}
|
|
103
|
+
return embeddings;
|
|
104
|
+
}
|
|
105
|
+
const graph = { nodes, edges };
|
|
106
|
+
if (!graphMAEEncoder) {
|
|
107
|
+
graphMAEEncoder = createGraphMAEEncoder({ embeddingDim: 128, numHeads: 4 });
|
|
108
|
+
}
|
|
109
|
+
const graphEmbeddings = graphMAEEncoder.embed(graph);
|
|
110
|
+
for (const [nodeId, emb] of graphEmbeddings) {
|
|
111
|
+
embeddings.set(nodeId, Array.from(emb));
|
|
112
|
+
}
|
|
113
|
+
logger.info(`[R4] GraphMAE generated ${graphEmbeddings.size} graph-aware embeddings`);
|
|
114
|
+
}
|
|
115
|
+
catch (error) {
|
|
116
|
+
logger.error('[R4] GraphMAE embedding failed, using feature-hash fallback:', error instanceof Error ? error : undefined);
|
|
117
|
+
for (const p of paths) {
|
|
118
|
+
const result = await fileReader.readFile(p);
|
|
119
|
+
if (result.success && result.value) {
|
|
120
|
+
embeddings.set(p, await generateCodeEmbedding(p, result.value));
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return embeddings;
|
|
125
|
+
}
|
|
58
126
|
/**
|
|
59
127
|
* Generate code embedding using semantic features
|
|
60
128
|
*/
|
|
@@ -171,6 +239,40 @@ export function mergeSearchResults(semanticResults, gnnResults) {
|
|
|
171
239
|
.sort((a, b) => b.score - a.score)
|
|
172
240
|
.slice(0, 20);
|
|
173
241
|
}
|
|
242
|
+
// R6: ColdTier trainer singleton (lazy-initialized)
|
|
243
|
+
let coldTierTrainer = null;
|
|
244
|
+
/**
|
|
245
|
+
* R6: Train GNN embeddings with memory-bounded cold-tier training.
|
|
246
|
+
* Uses LRU hotset caching when the graph exceeds hotsetSize, falling
|
|
247
|
+
* back to full in-memory training for small graphs.
|
|
248
|
+
*/
|
|
249
|
+
export function trainWithColdTier(nodeFeatures, adjacency, options = {}) {
|
|
250
|
+
if (!isColdTierGNNEnabled()) {
|
|
251
|
+
return { embeddings: new Map(), loss: 0, usedColdTier: false };
|
|
252
|
+
}
|
|
253
|
+
try {
|
|
254
|
+
if (!coldTierTrainer) {
|
|
255
|
+
coldTierTrainer = createColdTierTrainer({
|
|
256
|
+
hotsetSize: options.hotsetSize ?? 10000,
|
|
257
|
+
epochs: options.epochs ?? 10,
|
|
258
|
+
hiddenDim: options.hiddenDim ?? 64,
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
const graph = new InMemoryGraph(nodeFeatures, adjacency);
|
|
262
|
+
const result = coldTierTrainer.train(graph);
|
|
263
|
+
logger.info(`[R6] ColdTier training: ${graph.nodeCount} nodes, ` +
|
|
264
|
+
`loss=${result.loss.toFixed(4)}, mode=${result.usedInMemoryMode ? 'in-memory' : 'cold-tier'}`);
|
|
265
|
+
return {
|
|
266
|
+
embeddings: result.embeddings,
|
|
267
|
+
loss: result.loss,
|
|
268
|
+
usedColdTier: !result.usedInMemoryMode,
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
catch (error) {
|
|
272
|
+
logger.error('[R6] ColdTier training failed:', error instanceof Error ? error : undefined);
|
|
273
|
+
return { embeddings: new Map(), loss: 0, usedColdTier: false };
|
|
274
|
+
}
|
|
275
|
+
}
|
|
174
276
|
/**
|
|
175
277
|
* Simple hash function for strings
|
|
176
278
|
*/
|
|
@@ -16,6 +16,8 @@ import { ContractValidatorService } from './services/contract-validator.js';
|
|
|
16
16
|
import { ApiCompatibilityService } from './services/api-compatibility.js';
|
|
17
17
|
import { SARSAAlgorithm } from '../../integrations/rl-suite/algorithms/sarsa.js';
|
|
18
18
|
import { createPersistentSONAEngine } from '../../integrations/ruvector/sona-persistence.js';
|
|
19
|
+
// Three-loop feature flag for instantAdapt protocol
|
|
20
|
+
import { isSONAThreeLoopEnabled } from '../../integrations/ruvector/feature-flags.js';
|
|
19
21
|
import { createDomainFinding, } from '../../coordination/consensus/domain-findings.js';
|
|
20
22
|
// CQ-002: Base domain coordinator
|
|
21
23
|
import { BaseDomainCoordinator, } from '../base-domain-coordinator.js';
|
|
@@ -960,6 +962,17 @@ export class ContractTestingCoordinator extends BaseDomainCoordinator {
|
|
|
960
962
|
contract.endpoints.filter((e) => e.responseSchema).length / 100,
|
|
961
963
|
],
|
|
962
964
|
};
|
|
965
|
+
// Three-loop protocol: instantAdapt must precede recordOutcome
|
|
966
|
+
if (isSONAThreeLoopEnabled() && this.qesona.isThreeLoopEnabled()) {
|
|
967
|
+
this.qesona.instantAdapt([
|
|
968
|
+
contract.endpoints.length / 100,
|
|
969
|
+
contract.consumers.length / 50,
|
|
970
|
+
contract.schemas.length / 50,
|
|
971
|
+
quality,
|
|
972
|
+
validationSuccess ? 1 : 0,
|
|
973
|
+
contract.version.major / 10,
|
|
974
|
+
]);
|
|
975
|
+
}
|
|
963
976
|
const action = {
|
|
964
977
|
type: validationSuccess ? 'validate' : 'reject',
|
|
965
978
|
value: quality,
|
|
@@ -69,6 +69,11 @@ export class CoverageAnalysisCoordinator extends BaseDomainCoordinator {
|
|
|
69
69
|
async onInitialize() {
|
|
70
70
|
// Services are stateless, no domain-specific initialization needed
|
|
71
71
|
// ADR-059: Ghost coverage analyzer is lazy-initialized on first use
|
|
72
|
+
// NOTE: EWC++ three-loop integration not available in this coordinator.
|
|
73
|
+
// Coverage-analysis uses Q-Learning (not SONA), so the three-loop engine
|
|
74
|
+
// is not accessible here. To enable EWC++ for coverage patterns, this
|
|
75
|
+
// coordinator would need a PersistentSONAEngine instance wired the same
|
|
76
|
+
// way as quality-assessment and test-generation coordinators.
|
|
72
77
|
}
|
|
73
78
|
async onDispose() {
|
|
74
79
|
// No domain-specific cleanup needed
|
|
@@ -54,6 +54,7 @@ export declare class DefectIntelligenceCoordinator extends BaseDomainCoordinator
|
|
|
54
54
|
private readonly predictor;
|
|
55
55
|
private readonly patternLearner;
|
|
56
56
|
private readonly rootCauseAnalyzer;
|
|
57
|
+
private readonly testExecutionHistory;
|
|
57
58
|
constructor(eventBus: EventBus, memory: MemoryBackend, agentCoordinator: AgentCoordinator, config?: Partial<CoordinatorConfig>);
|
|
58
59
|
protected onInitialize(): Promise<void>;
|
|
59
60
|
protected onDispose(): Promise<void>;
|
|
@@ -17,6 +17,9 @@ import { PatternLearnerService, } from './services/pattern-learner';
|
|
|
17
17
|
import { RootCauseAnalyzerService, } from './services/root-cause-analyzer';
|
|
18
18
|
// CQ-002: Base domain coordinator
|
|
19
19
|
import { BaseDomainCoordinator, } from '../base-domain-coordinator.js';
|
|
20
|
+
// R12: Granger Causality for temporal failure prediction (ADR-087)
|
|
21
|
+
import { getRuVectorFeatureFlags } from '../../integrations/ruvector/feature-flags.js';
|
|
22
|
+
import { GrangerAnalyzer } from '../../integrations/ruvector/temporal-causality.js';
|
|
20
23
|
const DEFAULT_CONFIG = {
|
|
21
24
|
maxConcurrentWorkflows: 5,
|
|
22
25
|
defaultTimeout: 60000,
|
|
@@ -49,6 +52,8 @@ export class DefectIntelligenceCoordinator extends BaseDomainCoordinator {
|
|
|
49
52
|
predictor;
|
|
50
53
|
patternLearner;
|
|
51
54
|
rootCauseAnalyzer;
|
|
55
|
+
// R12: Accumulated test execution history for Granger causality (ADR-087)
|
|
56
|
+
testExecutionHistory = new Map();
|
|
52
57
|
constructor(eventBus, memory, agentCoordinator, config = {}) {
|
|
53
58
|
const fullConfig = { ...DEFAULT_CONFIG, ...config };
|
|
54
59
|
super(eventBus, 'defect-intelligence', fullConfig, {
|
|
@@ -160,6 +165,44 @@ export class DefectIntelligenceCoordinator extends BaseDomainCoordinator {
|
|
|
160
165
|
if (this.config.enablePatternLearning) {
|
|
161
166
|
await this.autoAnalyzeHighRisk(enhancedResult);
|
|
162
167
|
}
|
|
168
|
+
// R12: Accumulate test history and run Granger causality (ADR-087)
|
|
169
|
+
if (getRuVectorFeatureFlags().useGrangerCausality) {
|
|
170
|
+
try {
|
|
171
|
+
const now = Date.now();
|
|
172
|
+
// Accumulate prediction outcomes into per-test history
|
|
173
|
+
for (const p of enhancedResult.predictions) {
|
|
174
|
+
const history = this.testExecutionHistory.get(p.file) ?? { timestamps: [], outcomes: [] };
|
|
175
|
+
history.timestamps.push(now);
|
|
176
|
+
history.outcomes.push(p.probability > 0.5 ? 0 : 1);
|
|
177
|
+
// Cap history at 500 points per test
|
|
178
|
+
if (history.timestamps.length > 500) {
|
|
179
|
+
history.timestamps.splice(0, history.timestamps.length - 500);
|
|
180
|
+
history.outcomes.splice(0, history.outcomes.length - 500);
|
|
181
|
+
}
|
|
182
|
+
this.testExecutionHistory.set(p.file, history);
|
|
183
|
+
}
|
|
184
|
+
// Run Granger analysis when we have enough accumulated history
|
|
185
|
+
const eligibleSeries = Array.from(this.testExecutionHistory.entries())
|
|
186
|
+
.filter(([, h]) => h.timestamps.length >= 30)
|
|
187
|
+
.map(([testId, h]) => ({ testId, timestamps: h.timestamps, outcomes: h.outcomes }));
|
|
188
|
+
if (eligibleSeries.length >= 3) {
|
|
189
|
+
const analyzer = new GrangerAnalyzer({ maxLag: 5, alpha: 0.05 });
|
|
190
|
+
const causalLinks = analyzer.analyzeCausality(eligibleSeries);
|
|
191
|
+
if (causalLinks.length > 0) {
|
|
192
|
+
logger.info('Granger causality found causal links in defect predictions', {
|
|
193
|
+
linkCount: causalLinks.length,
|
|
194
|
+
historyDepth: eligibleSeries[0].timestamps.length,
|
|
195
|
+
topLink: `${causalLinks[0].sourceTestId} → ${causalLinks[0].targetTestId} (lag=${causalLinks[0].lag}, p=${causalLinks[0].pValue.toFixed(4)})`,
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
catch (grangerErr) {
|
|
201
|
+
logger.warn('Granger causality analysis failed (non-fatal)', {
|
|
202
|
+
error: grangerErr instanceof Error ? grangerErr.message : 'unknown',
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
}
|
|
163
206
|
// Stop the agent
|
|
164
207
|
await this.agentCoordinator.stop(agentResult.value);
|
|
165
208
|
return ok(enhancedResult);
|