@magic-ingredients/tiny-brain-local 0.19.0 → 0.19.1
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.
|
@@ -19,5 +19,9 @@ export declare class QualityTool {
|
|
|
19
19
|
private static handleCompare;
|
|
20
20
|
private static handlePlan;
|
|
21
21
|
private static handlePlanDetails;
|
|
22
|
+
private static handleDetectAnalyzers;
|
|
23
|
+
private static handleRunAnalyzers;
|
|
24
|
+
private static handleAssembleRun;
|
|
25
|
+
private static handleMergeResults;
|
|
22
26
|
}
|
|
23
27
|
//# sourceMappingURL=quality.tool.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"quality.tool.d.ts","sourceRoot":"","sources":["../../../src/tools/quality/quality.tool.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,EAA0C,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AACtF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AACrE,OAAO,EAAE,IAAI,IAAI,OAAO,EAAE,MAAM,oCAAoC,CAAC;
|
|
1
|
+
{"version":3,"file":"quality.tool.d.ts","sourceRoot":"","sources":["../../../src/tools/quality/quality.tool.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,EAA0C,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AACtF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AACrE,OAAO,EAAE,IAAI,IAAI,OAAO,EAAE,MAAM,oCAAoC,CAAC;AAyDrE;;GAEG;AACH,qBAAa,WAAW;IACtB,MAAM,CAAC,iBAAiB,IAAI,OAAO;WA+KtB,OAAO,CAClB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,UAAU,CAAC;mBA8CD,UAAU;mBAqCV,aAAa;mBA2Bb,aAAa;mBA2Eb,aAAa;mBAsEb,UAAU;mBA0CV,iBAAiB;mBAgEjB,qBAAqB;mBA6BrB,kBAAkB;mBA+ClB,iBAAiB;IA8CtC,OAAO,CAAC,MAAM,CAAC,kBAAkB;CAoBlC"}
|
|
@@ -8,12 +8,15 @@ import { z } from 'zod';
|
|
|
8
8
|
import { promises as fs } from 'fs';
|
|
9
9
|
import path from 'path';
|
|
10
10
|
import { createSuccessResult, createErrorResult } from '../index.js';
|
|
11
|
-
import { QualityService, QualityIssueSchema, SaveQualityRunInputSchema, } from '@magic-ingredients/tiny-brain-core';
|
|
11
|
+
import { QualityService, AnalyzerDetectionService, AnalyzerExecutorService, AssemblyService, mergeResults, QualityIssueSchema, SaveQualityRunInputSchema, generateRunId, runIdToPath, } from '@magic-ingredients/tiny-brain-core';
|
|
12
12
|
/**
|
|
13
13
|
* Zod schema for QualityTool arguments
|
|
14
14
|
*/
|
|
15
15
|
const QualityArgsSchema = z.object({
|
|
16
|
-
operation: z.enum([
|
|
16
|
+
operation: z.enum([
|
|
17
|
+
'save', 'history', 'details', 'compare', 'plan', 'plan-details',
|
|
18
|
+
'detect-analyzers', 'run-analyzers', 'merge-results', 'assemble-run',
|
|
19
|
+
]),
|
|
17
20
|
// For 'save' operation
|
|
18
21
|
score: z.number().min(0).max(100).optional(),
|
|
19
22
|
grade: z.enum(['A', 'B', 'C', 'D', 'F']).optional(),
|
|
@@ -38,6 +41,9 @@ const QualityArgsSchema = z.object({
|
|
|
38
41
|
targetGrade: z.string().optional(),
|
|
39
42
|
// For 'plan-details' operation
|
|
40
43
|
planId: z.string().optional(),
|
|
44
|
+
// For 'merge-results' operation
|
|
45
|
+
analyzerIssues: z.array(QualityIssueSchema).optional(),
|
|
46
|
+
llmIssues: z.array(QualityIssueSchema).optional(),
|
|
41
47
|
});
|
|
42
48
|
/**
|
|
43
49
|
* MCP Tool for quality analysis persistence
|
|
@@ -57,6 +63,10 @@ Persists and retrieves quality analysis results. Analysis is performed by agents
|
|
|
57
63
|
• compare: Compare two runs to see new, resolved, and persistent issues
|
|
58
64
|
• plan: Generate a Quality Improvement Plan from a saved run
|
|
59
65
|
• plan-details: Retrieve a saved Quality Improvement Plan by ID
|
|
66
|
+
• detect-analyzers: Scan repo for configured static analyzers
|
|
67
|
+
• run-analyzers: Execute detected analyzers and return normalized issues
|
|
68
|
+
• merge-results: Merge analyzer + LLM issues with deduplication
|
|
69
|
+
• assemble-run: Read all intermediate files, merge, score, and save final report
|
|
60
70
|
|
|
61
71
|
💡 WORKFLOW:
|
|
62
72
|
1. Quality-coordinator agent performs analysis
|
|
@@ -69,7 +79,10 @@ Persists and retrieves quality analysis results. Analysis is performed by agents
|
|
|
69
79
|
properties: {
|
|
70
80
|
operation: {
|
|
71
81
|
type: 'string',
|
|
72
|
-
enum: [
|
|
82
|
+
enum: [
|
|
83
|
+
'save', 'history', 'details', 'compare', 'plan', 'plan-details',
|
|
84
|
+
'detect-analyzers', 'run-analyzers', 'merge-results', 'assemble-run',
|
|
85
|
+
],
|
|
73
86
|
description: 'The quality operation to perform',
|
|
74
87
|
},
|
|
75
88
|
// For 'save' operation
|
|
@@ -176,6 +189,35 @@ Persists and retrieves quality analysis results. Analysis is performed by agents
|
|
|
176
189
|
type: 'string',
|
|
177
190
|
description: 'Plan ID to retrieve details for (required for plan-details)',
|
|
178
191
|
},
|
|
192
|
+
// For 'merge-results' operation
|
|
193
|
+
analyzerIssues: {
|
|
194
|
+
type: 'array',
|
|
195
|
+
description: 'Array of analyzer issues (required for merge-results)',
|
|
196
|
+
items: {
|
|
197
|
+
type: 'object',
|
|
198
|
+
properties: {
|
|
199
|
+
category: { type: 'string' },
|
|
200
|
+
severity: { type: 'string' },
|
|
201
|
+
file: { type: 'string' },
|
|
202
|
+
message: { type: 'string' },
|
|
203
|
+
},
|
|
204
|
+
required: ['category', 'severity', 'file', 'message'],
|
|
205
|
+
},
|
|
206
|
+
},
|
|
207
|
+
llmIssues: {
|
|
208
|
+
type: 'array',
|
|
209
|
+
description: 'Array of LLM investigation issues (required for merge-results)',
|
|
210
|
+
items: {
|
|
211
|
+
type: 'object',
|
|
212
|
+
properties: {
|
|
213
|
+
category: { type: 'string' },
|
|
214
|
+
severity: { type: 'string' },
|
|
215
|
+
file: { type: 'string' },
|
|
216
|
+
message: { type: 'string' },
|
|
217
|
+
},
|
|
218
|
+
required: ['category', 'severity', 'file', 'message'],
|
|
219
|
+
},
|
|
220
|
+
},
|
|
179
221
|
},
|
|
180
222
|
required: ['operation'],
|
|
181
223
|
},
|
|
@@ -202,6 +244,14 @@ Persists and retrieves quality analysis results. Analysis is performed by agents
|
|
|
202
244
|
return await QualityTool.handlePlan(validatedArgs, service);
|
|
203
245
|
case 'plan-details':
|
|
204
246
|
return await QualityTool.handlePlanDetails(validatedArgs, context.repositoryRoot);
|
|
247
|
+
case 'detect-analyzers':
|
|
248
|
+
return await QualityTool.handleDetectAnalyzers(context.repositoryRoot);
|
|
249
|
+
case 'run-analyzers':
|
|
250
|
+
return await QualityTool.handleRunAnalyzers(context.repositoryRoot);
|
|
251
|
+
case 'merge-results':
|
|
252
|
+
return QualityTool.handleMergeResults(validatedArgs);
|
|
253
|
+
case 'assemble-run':
|
|
254
|
+
return await QualityTool.handleAssembleRun(validatedArgs, context.repositoryRoot);
|
|
205
255
|
default:
|
|
206
256
|
return createErrorResult(`Unknown operation: ${validatedArgs.operation}`);
|
|
207
257
|
}
|
|
@@ -458,4 +508,109 @@ Persists and retrieves quality analysis results. Analysis is performed by agents
|
|
|
458
508
|
return createErrorResult(`Improvement plan not found: ${args.planId}`);
|
|
459
509
|
}
|
|
460
510
|
}
|
|
511
|
+
static async handleDetectAnalyzers(repositoryRoot) {
|
|
512
|
+
const service = new AnalyzerDetectionService(repositoryRoot);
|
|
513
|
+
const analyzers = await service.detectAnalyzers();
|
|
514
|
+
if (analyzers.length === 0) {
|
|
515
|
+
return createSuccessResult('No static analyzers detected in this repository.\n\nSupported analyzers: ESLint, TypeScript, npm audit, RuboCop, ruff.');
|
|
516
|
+
}
|
|
517
|
+
const lines = [
|
|
518
|
+
`🔍 Detected ${analyzers.length} analyzer(s):`,
|
|
519
|
+
'',
|
|
520
|
+
];
|
|
521
|
+
for (const analyzer of analyzers) {
|
|
522
|
+
lines.push(`- **${analyzer.name}** (${analyzer.analyzerId})`);
|
|
523
|
+
lines.push(` Configs: ${analyzer.configPaths.join(', ')}`);
|
|
524
|
+
lines.push(` Categories: ${analyzer.categories.join(', ')}`);
|
|
525
|
+
}
|
|
526
|
+
lines.push('');
|
|
527
|
+
lines.push(JSON.stringify(analyzers, null, 2));
|
|
528
|
+
return createSuccessResult(lines.join('\n'));
|
|
529
|
+
}
|
|
530
|
+
static async handleRunAnalyzers(repositoryRoot) {
|
|
531
|
+
const runId = generateRunId();
|
|
532
|
+
const runDir = path.join(repositoryRoot, 'docs', 'quality', 'runs', runIdToPath(runId));
|
|
533
|
+
const outputPath = path.join(runDir, 'analysis.json');
|
|
534
|
+
const outputDir = path.join(runDir, 'analysers');
|
|
535
|
+
const detectionService = new AnalyzerDetectionService(repositoryRoot);
|
|
536
|
+
const analyzers = await detectionService.detectAnalyzers();
|
|
537
|
+
const emptyResults = {
|
|
538
|
+
issues: [],
|
|
539
|
+
executions: [],
|
|
540
|
+
totalDurationMs: 0,
|
|
541
|
+
summary: { total: 0, succeeded: 0, failed: 0, timedOut: 0, skipped: 0 },
|
|
542
|
+
};
|
|
543
|
+
if (analyzers.length === 0) {
|
|
544
|
+
await fs.mkdir(runDir, { recursive: true });
|
|
545
|
+
await fs.writeFile(outputPath, JSON.stringify(emptyResults, null, 2), 'utf-8');
|
|
546
|
+
return createSuccessResult(`🔧 No analyzers detected. Empty results written to file.\n Run ID: ${runId}\n Output: ${outputPath}`);
|
|
547
|
+
}
|
|
548
|
+
const executorService = new AnalyzerExecutorService(repositoryRoot);
|
|
549
|
+
const results = await executorService.executeAnalyzers(analyzers, outputDir);
|
|
550
|
+
// Write merged/normalized result to the auto-generated run directory
|
|
551
|
+
await fs.mkdir(runDir, { recursive: true });
|
|
552
|
+
await fs.writeFile(outputPath, JSON.stringify(results, null, 2), 'utf-8');
|
|
553
|
+
const lines = [
|
|
554
|
+
`🔧 Executed ${results.summary.total} analyzer(s):`,
|
|
555
|
+
` Succeeded: ${results.summary.succeeded}`,
|
|
556
|
+
` Failed: ${results.summary.failed}`,
|
|
557
|
+
` Total issues: ${results.issues.length}`,
|
|
558
|
+
` Duration: ${results.totalDurationMs}ms`,
|
|
559
|
+
` Run ID: ${runId}`,
|
|
560
|
+
` Output: ${outputPath}`,
|
|
561
|
+
` Raw files: ${outputDir}/`,
|
|
562
|
+
];
|
|
563
|
+
return createSuccessResult(lines.join('\n'));
|
|
564
|
+
}
|
|
565
|
+
static async handleAssembleRun(args, repositoryRoot) {
|
|
566
|
+
if (!args.runId) {
|
|
567
|
+
return createErrorResult('runId is required for assemble-run operation (YYYY-MM-DD date prefix)');
|
|
568
|
+
}
|
|
569
|
+
const assemblyService = new AssemblyService(repositoryRoot);
|
|
570
|
+
const result = await assemblyService.assembleRun(args.runId, args.baseRunId);
|
|
571
|
+
const lines = [
|
|
572
|
+
'✅ Quality run assembled successfully!',
|
|
573
|
+
'',
|
|
574
|
+
`📊 Run ID: ${result.runId}`,
|
|
575
|
+
`📈 Score: ${result.score}/100 (Grade: ${result.grade})`,
|
|
576
|
+
`🔍 Issues: ${result.issueCount}`,
|
|
577
|
+
`📁 File: ${result.filePath}`,
|
|
578
|
+
];
|
|
579
|
+
if (result.incremental) {
|
|
580
|
+
lines.push('');
|
|
581
|
+
lines.push('### Incremental Analysis');
|
|
582
|
+
lines.push(` Base run: ${result.baseRunId}`);
|
|
583
|
+
lines.push(` Files analyzed: ${result.filesAnalyzed}`);
|
|
584
|
+
lines.push(` Files carried forward: ${result.filesCarriedForward}`);
|
|
585
|
+
}
|
|
586
|
+
lines.push('');
|
|
587
|
+
lines.push('### Source Breakdown');
|
|
588
|
+
lines.push(` Analyzer: ${result.sourceBreakdown.analyzer}`);
|
|
589
|
+
lines.push(` Specialist: ${result.sourceBreakdown.llm}`);
|
|
590
|
+
lines.push(` Total: ${result.sourceBreakdown.total}`);
|
|
591
|
+
const categoryEntries = Object.entries(result.categoryBreakdown);
|
|
592
|
+
if (categoryEntries.length > 0) {
|
|
593
|
+
lines.push('');
|
|
594
|
+
lines.push('### Category Breakdown');
|
|
595
|
+
for (const [category, count] of categoryEntries) {
|
|
596
|
+
lines.push(` ${category}: ${count}`);
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
return createSuccessResult(lines.join('\n'));
|
|
600
|
+
}
|
|
601
|
+
static handleMergeResults(args) {
|
|
602
|
+
const analyzerIssues = args.analyzerIssues ?? [];
|
|
603
|
+
const llmIssues = args.llmIssues ?? [];
|
|
604
|
+
const result = mergeResults(analyzerIssues, llmIssues);
|
|
605
|
+
const lines = [
|
|
606
|
+
`🔀 Merged results:`,
|
|
607
|
+
` Analyzer issues: ${result.sourceBreakdown.analyzer}`,
|
|
608
|
+
` LLM issues: ${result.sourceBreakdown.llm}`,
|
|
609
|
+
` Total (deduplicated): ${result.sourceBreakdown.total}`,
|
|
610
|
+
` Duplicates removed: ${result.duplicatesRemoved}`,
|
|
611
|
+
'',
|
|
612
|
+
JSON.stringify(result, null, 2),
|
|
613
|
+
];
|
|
614
|
+
return createSuccessResult(lines.join('\n'));
|
|
615
|
+
}
|
|
461
616
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@magic-ingredients/tiny-brain-local",
|
|
3
|
-
"version": "0.19.
|
|
3
|
+
"version": "0.19.1",
|
|
4
4
|
"description": "MCP server for Tiny Brain AI assistant",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"dxt:init": "cd dxt && dxt init"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@magic-ingredients/tiny-brain-core": "^0.19.
|
|
34
|
+
"@magic-ingredients/tiny-brain-core": "^0.19.1",
|
|
35
35
|
"@magic-ingredients/tiny-brain-dashboard": "file:../tiny-brain-dashboard",
|
|
36
36
|
"@modelcontextprotocol/sdk": "^1.0.6",
|
|
37
37
|
"chalk": "^5.3.0",
|