musubi-sdd 3.6.1 → 3.7.0
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/bin/musubi-analyze.js +275 -3
- package/bin/musubi-checkpoint.js +396 -0
- package/bin/musubi-convert.js +40 -1
- package/bin/musubi-costs.js +344 -0
- package/bin/musubi-init.js +44 -2
- package/package.json +1 -1
- package/src/converters/index.js +39 -0
- package/src/converters/parsers/openapi-parser.js +350 -0
- package/src/gui/public/index.html +443 -0
- package/src/gui/server.js +79 -0
- package/src/gui/services/index.js +2 -0
- package/src/gui/services/replanning-service.js +276 -0
- package/src/llm-providers/index.js +20 -1
- package/src/llm-providers/ollama-provider.js +401 -0
- package/src/managers/checkpoint-manager.js +556 -0
- package/src/managers/index.js +30 -0
- package/src/monitoring/cost-tracker.js +510 -0
- package/src/monitoring/index.js +5 -1
- package/src/templates/index.js +15 -0
- package/src/templates/locale-manager.js +288 -0
package/bin/musubi-analyze.js
CHANGED
|
@@ -8,8 +8,9 @@
|
|
|
8
8
|
* - Technical debt detection
|
|
9
9
|
* - Dependency analysis
|
|
10
10
|
* - Security vulnerabilities
|
|
11
|
+
* - CodeGraph MCP integration for code structure analysis
|
|
11
12
|
*
|
|
12
|
-
* @version
|
|
13
|
+
* @version 3.6.1
|
|
13
14
|
*/
|
|
14
15
|
|
|
15
16
|
const fs = require('fs-extra');
|
|
@@ -17,6 +18,7 @@ const path = require('path');
|
|
|
17
18
|
const chalk = require('chalk');
|
|
18
19
|
const { program } = require('commander');
|
|
19
20
|
const { glob } = require('glob');
|
|
21
|
+
const { execSync, spawn } = require('child_process');
|
|
20
22
|
|
|
21
23
|
// ============================================================================
|
|
22
24
|
// Configuration
|
|
@@ -59,12 +61,14 @@ const CONFIG = {
|
|
|
59
61
|
program
|
|
60
62
|
.name('musubi-analyze')
|
|
61
63
|
.description('Analyze codebase for quality, complexity, and technical debt')
|
|
62
|
-
.version('
|
|
63
|
-
.option('-t, --type <type>', 'Analysis type: quality, dependencies, security, stuck, all', 'all')
|
|
64
|
+
.version('3.6.1')
|
|
65
|
+
.option('-t, --type <type>', 'Analysis type: quality, dependencies, security, stuck, codegraph, all', 'all')
|
|
64
66
|
.option('-o, --output <file>', 'Output file for analysis report')
|
|
65
67
|
.option('--json', 'Output in JSON format')
|
|
66
68
|
.option('--threshold <level>', 'Quality threshold: low, medium, high', 'medium')
|
|
67
69
|
.option('--detect-stuck', 'Detect stuck agent patterns (repetitive errors, circular edits)')
|
|
70
|
+
.option('--codegraph', 'Run CodeGraph MCP index and update steering/memories/codegraph.md')
|
|
71
|
+
.option('--codegraph-full', 'Run full CodeGraph MCP index (not incremental)')
|
|
68
72
|
.option('-v, --verbose', 'Verbose output')
|
|
69
73
|
.parse(process.argv);
|
|
70
74
|
|
|
@@ -406,6 +410,255 @@ async function generateReport(analysisData) {
|
|
|
406
410
|
log(`Report saved to: ${reportPath}`, 'success');
|
|
407
411
|
}
|
|
408
412
|
|
|
413
|
+
// ============================================================================
|
|
414
|
+
// CodeGraph MCP Integration
|
|
415
|
+
// ============================================================================
|
|
416
|
+
|
|
417
|
+
/**
|
|
418
|
+
* Check if CodeGraph MCP is installed
|
|
419
|
+
* @returns {boolean} True if codegraph-mcp is available
|
|
420
|
+
*/
|
|
421
|
+
function isCodeGraphInstalled() {
|
|
422
|
+
try {
|
|
423
|
+
execSync('codegraph-mcp --version', { stdio: 'pipe' });
|
|
424
|
+
return true;
|
|
425
|
+
} catch {
|
|
426
|
+
return false;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
/**
|
|
431
|
+
* Run CodeGraph MCP index command
|
|
432
|
+
* @param {boolean} full - Whether to run full index (not incremental)
|
|
433
|
+
* @returns {Promise<Object>} Index results
|
|
434
|
+
*/
|
|
435
|
+
async function runCodeGraphIndex(full = false) {
|
|
436
|
+
return new Promise((resolve, reject) => {
|
|
437
|
+
const args = ['index', '.'];
|
|
438
|
+
if (full) {
|
|
439
|
+
args.push('--full');
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
log(`Running CodeGraph MCP index (${full ? 'full' : 'incremental'})...`, 'analyze');
|
|
443
|
+
|
|
444
|
+
const proc = spawn('codegraph-mcp', args, {
|
|
445
|
+
cwd: process.cwd(),
|
|
446
|
+
stdio: ['inherit', 'pipe', 'pipe']
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
let stdout = '';
|
|
450
|
+
let stderr = '';
|
|
451
|
+
|
|
452
|
+
proc.stdout.on('data', (data) => {
|
|
453
|
+
stdout += data.toString();
|
|
454
|
+
if (options.verbose) {
|
|
455
|
+
process.stdout.write(data);
|
|
456
|
+
}
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
proc.stderr.on('data', (data) => {
|
|
460
|
+
stderr += data.toString();
|
|
461
|
+
});
|
|
462
|
+
|
|
463
|
+
proc.on('close', (code) => {
|
|
464
|
+
if (code === 0) {
|
|
465
|
+
resolve({ success: true, output: stdout });
|
|
466
|
+
} else {
|
|
467
|
+
reject(new Error(`CodeGraph index failed: ${stderr}`));
|
|
468
|
+
}
|
|
469
|
+
});
|
|
470
|
+
});
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
/**
|
|
474
|
+
* Get CodeGraph MCP statistics
|
|
475
|
+
* @returns {Promise<Object>} Statistics object
|
|
476
|
+
*/
|
|
477
|
+
async function getCodeGraphStats() {
|
|
478
|
+
return new Promise((resolve, reject) => {
|
|
479
|
+
const proc = spawn('codegraph-mcp', ['stats', '.'], {
|
|
480
|
+
cwd: process.cwd(),
|
|
481
|
+
stdio: ['inherit', 'pipe', 'pipe']
|
|
482
|
+
});
|
|
483
|
+
|
|
484
|
+
let stdout = '';
|
|
485
|
+
|
|
486
|
+
proc.stdout.on('data', (data) => {
|
|
487
|
+
stdout += data.toString();
|
|
488
|
+
});
|
|
489
|
+
|
|
490
|
+
proc.on('close', (code) => {
|
|
491
|
+
if (code === 0) {
|
|
492
|
+
// Parse the stats output
|
|
493
|
+
const stats = parseCodeGraphStats(stdout);
|
|
494
|
+
resolve(stats);
|
|
495
|
+
} else {
|
|
496
|
+
reject(new Error('Failed to get CodeGraph stats'));
|
|
497
|
+
}
|
|
498
|
+
});
|
|
499
|
+
});
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
/**
|
|
503
|
+
* Parse CodeGraph MCP stats output
|
|
504
|
+
* @param {string} output - Raw stats output
|
|
505
|
+
* @returns {Object} Parsed statistics
|
|
506
|
+
*/
|
|
507
|
+
function parseCodeGraphStats(output) {
|
|
508
|
+
const stats = {
|
|
509
|
+
entities: 0,
|
|
510
|
+
relations: 0,
|
|
511
|
+
communities: 0,
|
|
512
|
+
files: 0,
|
|
513
|
+
entityTypes: {}
|
|
514
|
+
};
|
|
515
|
+
|
|
516
|
+
const lines = output.split('\n');
|
|
517
|
+
let inEntityTypes = false;
|
|
518
|
+
|
|
519
|
+
for (const line of lines) {
|
|
520
|
+
if (line.startsWith('Entities:')) {
|
|
521
|
+
stats.entities = parseInt(line.split(':')[1].trim(), 10);
|
|
522
|
+
} else if (line.startsWith('Relations:')) {
|
|
523
|
+
stats.relations = parseInt(line.split(':')[1].trim(), 10);
|
|
524
|
+
} else if (line.startsWith('Communities:')) {
|
|
525
|
+
stats.communities = parseInt(line.split(':')[1].trim(), 10);
|
|
526
|
+
} else if (line.startsWith('Files:')) {
|
|
527
|
+
stats.files = parseInt(line.split(':')[1].trim(), 10);
|
|
528
|
+
} else if (line.includes('Entities by type:')) {
|
|
529
|
+
inEntityTypes = true;
|
|
530
|
+
} else if (inEntityTypes && line.trim().startsWith('-')) {
|
|
531
|
+
const match = line.match(/-\s*(\w+):\s*(\d+)/);
|
|
532
|
+
if (match) {
|
|
533
|
+
stats.entityTypes[match[1]] = parseInt(match[2], 10);
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
return stats;
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
/**
|
|
542
|
+
* Generate CodeGraph report in steering/memories/codegraph.md
|
|
543
|
+
* @param {Object} stats - CodeGraph statistics
|
|
544
|
+
*/
|
|
545
|
+
async function generateCodeGraphReport(stats) {
|
|
546
|
+
const reportPath = 'steering/memories/codegraph.md';
|
|
547
|
+
const timestamp = new Date().toISOString();
|
|
548
|
+
const version = require('../package.json').version;
|
|
549
|
+
|
|
550
|
+
let report = `# CodeGraph MCP Index Report
|
|
551
|
+
|
|
552
|
+
**Generated**: ${timestamp}
|
|
553
|
+
**Version**: MUSUBI v${version}
|
|
554
|
+
**Indexed by**: CodeGraph MCP Server
|
|
555
|
+
|
|
556
|
+
---
|
|
557
|
+
|
|
558
|
+
## Graph Statistics
|
|
559
|
+
|
|
560
|
+
| Metric | Value |
|
|
561
|
+
|--------|-------|
|
|
562
|
+
| Entities | ${stats.entities.toLocaleString()} |
|
|
563
|
+
| Relations | ${stats.relations.toLocaleString()} |
|
|
564
|
+
| Communities | ${stats.communities} |
|
|
565
|
+
| Files Indexed | ${stats.files.toLocaleString()} |
|
|
566
|
+
|
|
567
|
+
## Entity Types
|
|
568
|
+
|
|
569
|
+
| Type | Count |
|
|
570
|
+
|------|-------|
|
|
571
|
+
`;
|
|
572
|
+
|
|
573
|
+
for (const [type, count] of Object.entries(stats.entityTypes)) {
|
|
574
|
+
report += `| ${type} | ${count.toLocaleString()} |\n`;
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
report += `
|
|
578
|
+
---
|
|
579
|
+
|
|
580
|
+
## Usage
|
|
581
|
+
|
|
582
|
+
CodeGraph MCP provides AI assistants with deep code understanding:
|
|
583
|
+
|
|
584
|
+
\`\`\`bash
|
|
585
|
+
# Re-index (incremental)
|
|
586
|
+
codegraph-mcp index .
|
|
587
|
+
|
|
588
|
+
# Full re-index
|
|
589
|
+
codegraph-mcp index . --full
|
|
590
|
+
|
|
591
|
+
# View stats
|
|
592
|
+
codegraph-mcp stats .
|
|
593
|
+
|
|
594
|
+
# Start MCP server
|
|
595
|
+
codegraph-mcp serve --repo .
|
|
596
|
+
\`\`\`
|
|
597
|
+
|
|
598
|
+
---
|
|
599
|
+
|
|
600
|
+
*Generated by MUSUBI v${version} using CodeGraph MCP Server*
|
|
601
|
+
`;
|
|
602
|
+
|
|
603
|
+
fs.ensureDirSync(path.dirname(reportPath));
|
|
604
|
+
fs.writeFileSync(reportPath, report);
|
|
605
|
+
|
|
606
|
+
log(`CodeGraph report saved to: ${reportPath}`, 'success');
|
|
607
|
+
|
|
608
|
+
return reportPath;
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
/**
|
|
612
|
+
* Run CodeGraph MCP analysis
|
|
613
|
+
* @param {boolean} full - Whether to run full index
|
|
614
|
+
* @returns {Promise<Object>} Analysis results
|
|
615
|
+
*/
|
|
616
|
+
async function analyzeCodeGraph(full = false) {
|
|
617
|
+
log('CodeGraph MCP Analysis', 'analyze');
|
|
618
|
+
console.log();
|
|
619
|
+
|
|
620
|
+
// Check if CodeGraph MCP is installed
|
|
621
|
+
if (!isCodeGraphInstalled()) {
|
|
622
|
+
log('CodeGraph MCP is not installed. Install with:', 'warning');
|
|
623
|
+
console.log(chalk.cyan(' pipx install codegraph-mcp-server'));
|
|
624
|
+
console.log();
|
|
625
|
+
return null;
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
try {
|
|
629
|
+
// Run index
|
|
630
|
+
await runCodeGraphIndex(full);
|
|
631
|
+
console.log();
|
|
632
|
+
|
|
633
|
+
// Get statistics
|
|
634
|
+
const stats = await getCodeGraphStats();
|
|
635
|
+
|
|
636
|
+
// Display stats
|
|
637
|
+
console.log(chalk.bold('CodeGraph Statistics:'));
|
|
638
|
+
console.log(` Entities: ${chalk.green(stats.entities.toLocaleString())}`);
|
|
639
|
+
console.log(` Relations: ${chalk.green(stats.relations.toLocaleString())}`);
|
|
640
|
+
console.log(` Communities: ${chalk.green(stats.communities)}`);
|
|
641
|
+
console.log(` Files: ${chalk.green(stats.files.toLocaleString())}`);
|
|
642
|
+
console.log();
|
|
643
|
+
|
|
644
|
+
if (Object.keys(stats.entityTypes).length > 0) {
|
|
645
|
+
console.log(chalk.bold('Entity Types:'));
|
|
646
|
+
for (const [type, count] of Object.entries(stats.entityTypes)) {
|
|
647
|
+
console.log(` ${type}: ${chalk.cyan(count.toLocaleString())}`);
|
|
648
|
+
}
|
|
649
|
+
console.log();
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
// Generate report
|
|
653
|
+
await generateCodeGraphReport(stats);
|
|
654
|
+
|
|
655
|
+
return stats;
|
|
656
|
+
} catch (error) {
|
|
657
|
+
log(`CodeGraph analysis failed: ${error.message}`, 'error');
|
|
658
|
+
return null;
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
|
|
409
662
|
// ============================================================================
|
|
410
663
|
// Stuck Detection Analysis
|
|
411
664
|
// ============================================================================
|
|
@@ -620,6 +873,20 @@ async function main() {
|
|
|
620
873
|
const analysisData = {};
|
|
621
874
|
|
|
622
875
|
try {
|
|
876
|
+
// Handle --codegraph or --codegraph-full options
|
|
877
|
+
if (options.codegraph || options.codegraphFull || options.type === 'codegraph') {
|
|
878
|
+
analysisData.codegraph = await analyzeCodeGraph(options.codegraphFull);
|
|
879
|
+
|
|
880
|
+
if (options.json && analysisData.codegraph) {
|
|
881
|
+
console.log(JSON.stringify(analysisData.codegraph, null, 2));
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
if (options.type === 'codegraph') {
|
|
885
|
+
log('CodeGraph analysis complete!', 'success');
|
|
886
|
+
process.exit(0);
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
|
|
623
890
|
// Handle --detect-stuck option
|
|
624
891
|
if (options.detectStuck || options.type === 'stuck') {
|
|
625
892
|
analysisData.stuck = await analyzeStuckPatterns();
|
|
@@ -645,6 +912,11 @@ async function main() {
|
|
|
645
912
|
analysisData.security = await analyzeSecurity();
|
|
646
913
|
}
|
|
647
914
|
|
|
915
|
+
// Run CodeGraph analysis in 'all' mode if codegraph-mcp is available
|
|
916
|
+
if (options.type === 'all' && isCodeGraphInstalled() && !analysisData.codegraph) {
|
|
917
|
+
analysisData.codegraph = await analyzeCodeGraph(false);
|
|
918
|
+
}
|
|
919
|
+
|
|
648
920
|
// Generate report if output specified
|
|
649
921
|
if (options.output || options.type === 'all') {
|
|
650
922
|
await generateReport(analysisData);
|