musubi-sdd 5.1.0 → 5.6.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.
- package/README.ja.md +106 -48
- package/README.md +110 -32
- package/bin/musubi-analyze.js +74 -67
- package/bin/musubi-browser.js +27 -26
- package/bin/musubi-change.js +48 -47
- package/bin/musubi-checkpoint.js +10 -7
- package/bin/musubi-convert.js +25 -25
- package/bin/musubi-costs.js +27 -10
- package/bin/musubi-gui.js +52 -46
- package/bin/musubi-init.js +1952 -10
- package/bin/musubi-orchestrate.js +327 -239
- package/bin/musubi-remember.js +69 -56
- package/bin/musubi-resolve.js +53 -45
- package/bin/musubi-trace.js +51 -22
- package/bin/musubi-validate.js +39 -30
- package/bin/musubi-workflow.js +33 -34
- package/bin/musubi.js +39 -2
- package/package.json +1 -1
- package/src/agents/agent-loop.js +94 -95
- package/src/agents/agentic/code-generator.js +119 -109
- package/src/agents/agentic/code-reviewer.js +105 -108
- package/src/agents/agentic/index.js +4 -4
- package/src/agents/browser/action-executor.js +13 -13
- package/src/agents/browser/ai-comparator.js +11 -10
- package/src/agents/browser/context-manager.js +6 -6
- package/src/agents/browser/index.js +5 -5
- package/src/agents/browser/nl-parser.js +31 -46
- package/src/agents/browser/screenshot.js +2 -2
- package/src/agents/browser/test-generator.js +6 -4
- package/src/agents/function-tool.js +71 -65
- package/src/agents/index.js +7 -7
- package/src/agents/schema-generator.js +98 -94
- package/src/analyzers/ast-extractor.js +158 -146
- package/src/analyzers/codegraph-auto-update.js +858 -0
- package/src/analyzers/complexity-analyzer.js +536 -0
- package/src/analyzers/context-optimizer.js +241 -126
- package/src/analyzers/impact-analyzer.js +1 -1
- package/src/analyzers/large-project-analyzer.js +766 -0
- package/src/analyzers/repository-map.js +77 -81
- package/src/analyzers/security-analyzer.js +19 -11
- package/src/analyzers/stuck-detector.js +19 -17
- package/src/converters/index.js +78 -57
- package/src/converters/ir/types.js +12 -12
- package/src/converters/parsers/musubi-parser.js +134 -126
- package/src/converters/parsers/openapi-parser.js +70 -53
- package/src/converters/parsers/speckit-parser.js +239 -175
- package/src/converters/writers/musubi-writer.js +123 -118
- package/src/converters/writers/speckit-writer.js +124 -113
- package/src/generators/rust-migration-generator.js +512 -0
- package/src/gui/public/index.html +1365 -1211
- package/src/gui/server.js +41 -40
- package/src/gui/services/file-watcher.js +23 -8
- package/src/gui/services/project-scanner.js +26 -20
- package/src/gui/services/replanning-service.js +27 -23
- package/src/gui/services/traceability-service.js +8 -8
- package/src/gui/services/workflow-service.js +14 -7
- package/src/index.js +151 -0
- package/src/integrations/cicd.js +90 -104
- package/src/integrations/codegraph-mcp.js +643 -0
- package/src/integrations/documentation.js +142 -103
- package/src/integrations/examples.js +95 -80
- package/src/integrations/github-client.js +17 -17
- package/src/integrations/index.js +5 -5
- package/src/integrations/mcp/index.js +21 -21
- package/src/integrations/mcp/mcp-context-provider.js +76 -78
- package/src/integrations/mcp/mcp-discovery.js +74 -72
- package/src/integrations/mcp/mcp-tool-registry.js +99 -94
- package/src/integrations/mcp-connector.js +70 -66
- package/src/integrations/platforms.js +50 -49
- package/src/integrations/tool-discovery.js +37 -31
- package/src/llm-providers/anthropic-provider.js +11 -11
- package/src/llm-providers/base-provider.js +16 -18
- package/src/llm-providers/copilot-provider.js +22 -19
- package/src/llm-providers/index.js +26 -25
- package/src/llm-providers/ollama-provider.js +11 -11
- package/src/llm-providers/openai-provider.js +12 -12
- package/src/managers/agent-memory.js +36 -24
- package/src/managers/checkpoint-manager.js +4 -8
- package/src/managers/delta-spec.js +19 -19
- package/src/managers/index.js +13 -4
- package/src/managers/memory-condenser.js +35 -45
- package/src/managers/repo-skill-manager.js +57 -31
- package/src/managers/skill-loader.js +25 -22
- package/src/managers/skill-tools.js +36 -72
- package/src/managers/workflow.js +30 -22
- package/src/monitoring/cost-tracker.js +48 -46
- package/src/monitoring/incident-manager.js +116 -106
- package/src/monitoring/index.js +144 -134
- package/src/monitoring/observability.js +75 -62
- package/src/monitoring/quality-dashboard.js +45 -41
- package/src/monitoring/release-manager.js +63 -53
- package/src/orchestration/agent-skill-binding.js +39 -47
- package/src/orchestration/error-handler.js +65 -107
- package/src/orchestration/guardrails/base-guardrail.js +26 -24
- package/src/orchestration/guardrails/guardrail-rules.js +50 -64
- package/src/orchestration/guardrails/index.js +5 -5
- package/src/orchestration/guardrails/input-guardrail.js +58 -45
- package/src/orchestration/guardrails/output-guardrail.js +104 -81
- package/src/orchestration/guardrails/safety-check.js +79 -79
- package/src/orchestration/index.js +38 -55
- package/src/orchestration/mcp-tool-adapters.js +96 -99
- package/src/orchestration/orchestration-engine.js +21 -21
- package/src/orchestration/pattern-registry.js +60 -45
- package/src/orchestration/patterns/auto.js +34 -47
- package/src/orchestration/patterns/group-chat.js +59 -65
- package/src/orchestration/patterns/handoff.js +67 -65
- package/src/orchestration/patterns/human-in-loop.js +51 -72
- package/src/orchestration/patterns/nested.js +25 -40
- package/src/orchestration/patterns/sequential.js +35 -34
- package/src/orchestration/patterns/swarm.js +63 -56
- package/src/orchestration/patterns/triage.js +150 -109
- package/src/orchestration/reasoning/index.js +9 -9
- package/src/orchestration/reasoning/planning-engine.js +143 -140
- package/src/orchestration/reasoning/reasoning-engine.js +206 -144
- package/src/orchestration/reasoning/self-correction.js +121 -128
- package/src/orchestration/replanning/adaptive-goal-modifier.js +107 -112
- package/src/orchestration/replanning/alternative-generator.js +37 -42
- package/src/orchestration/replanning/config.js +63 -59
- package/src/orchestration/replanning/goal-progress-tracker.js +98 -100
- package/src/orchestration/replanning/index.js +24 -20
- package/src/orchestration/replanning/plan-evaluator.js +49 -50
- package/src/orchestration/replanning/plan-monitor.js +32 -28
- package/src/orchestration/replanning/proactive-path-optimizer.js +175 -178
- package/src/orchestration/replanning/replan-history.js +33 -26
- package/src/orchestration/replanning/replanning-engine.js +106 -108
- package/src/orchestration/skill-executor.js +107 -109
- package/src/orchestration/skill-registry.js +85 -89
- package/src/orchestration/workflow-examples.js +228 -231
- package/src/orchestration/workflow-executor.js +65 -68
- package/src/orchestration/workflow-orchestrator.js +72 -73
- package/src/phase4-integration.js +47 -40
- package/src/phase5-integration.js +89 -30
- package/src/reporters/coverage-report.js +82 -30
- package/src/reporters/hierarchical-reporter.js +498 -0
- package/src/reporters/traceability-matrix-report.js +29 -20
- package/src/resolvers/issue-resolver.js +43 -31
- package/src/steering/advanced-validation.js +133 -124
- package/src/steering/auto-updater.js +60 -73
- package/src/steering/index.js +6 -6
- package/src/steering/quality-metrics.js +41 -35
- package/src/steering/steering-auto-update.js +83 -86
- package/src/steering/steering-validator.js +98 -106
- package/src/steering/template-constraints.js +53 -54
- package/src/templates/agents/claude-code/CLAUDE.md +32 -32
- package/src/templates/agents/claude-code/skills/agent-assistant/SKILL.md +13 -5
- package/src/templates/agents/claude-code/skills/ai-ml-engineer/mlops-guide.md +23 -23
- package/src/templates/agents/claude-code/skills/ai-ml-engineer/model-card-template.md +60 -41
- package/src/templates/agents/claude-code/skills/api-designer/api-patterns.md +27 -19
- package/src/templates/agents/claude-code/skills/api-designer/openapi-template.md +11 -7
- package/src/templates/agents/claude-code/skills/bug-hunter/SKILL.md +4 -3
- package/src/templates/agents/claude-code/skills/bug-hunter/root-cause-analysis.md +37 -15
- package/src/templates/agents/claude-code/skills/change-impact-analyzer/dependency-graph-patterns.md +36 -42
- package/src/templates/agents/claude-code/skills/change-impact-analyzer/impact-analysis-template.md +69 -60
- package/src/templates/agents/claude-code/skills/cloud-architect/aws-patterns.md +31 -38
- package/src/templates/agents/claude-code/skills/cloud-architect/azure-patterns.md +28 -23
- package/src/templates/agents/claude-code/skills/code-reviewer/SKILL.md +61 -0
- package/src/templates/agents/claude-code/skills/code-reviewer/best-practices.md +27 -0
- package/src/templates/agents/claude-code/skills/code-reviewer/review-checklist.md +29 -10
- package/src/templates/agents/claude-code/skills/code-reviewer/review-standards.md +29 -24
- package/src/templates/agents/claude-code/skills/constitution-enforcer/SKILL.md +8 -6
- package/src/templates/agents/claude-code/skills/constitution-enforcer/constitutional-articles.md +62 -26
- package/src/templates/agents/claude-code/skills/constitution-enforcer/phase-minus-one-gates.md +35 -16
- package/src/templates/agents/claude-code/skills/database-administrator/backup-recovery.md +27 -17
- package/src/templates/agents/claude-code/skills/database-administrator/tuning-guide.md +25 -20
- package/src/templates/agents/claude-code/skills/database-schema-designer/schema-patterns.md +39 -22
- package/src/templates/agents/claude-code/skills/devops-engineer/ci-cd-templates.md +25 -22
- package/src/templates/agents/claude-code/skills/issue-resolver/SKILL.md +24 -21
- package/src/templates/agents/claude-code/skills/orchestrator/SKILL.md +148 -63
- package/src/templates/agents/claude-code/skills/orchestrator/patterns.md +35 -16
- package/src/templates/agents/claude-code/skills/orchestrator/selection-matrix.md +69 -64
- package/src/templates/agents/claude-code/skills/performance-engineer/optimization-playbook.md +47 -47
- package/src/templates/agents/claude-code/skills/performance-optimizer/SKILL.md +69 -0
- package/src/templates/agents/claude-code/skills/performance-optimizer/benchmark-template.md +63 -45
- package/src/templates/agents/claude-code/skills/performance-optimizer/optimization-patterns.md +33 -35
- package/src/templates/agents/claude-code/skills/project-manager/SKILL.md +7 -6
- package/src/templates/agents/claude-code/skills/project-manager/agile-ceremonies.md +47 -28
- package/src/templates/agents/claude-code/skills/project-manager/project-templates.md +94 -78
- package/src/templates/agents/claude-code/skills/quality-assurance/SKILL.md +20 -17
- package/src/templates/agents/claude-code/skills/quality-assurance/qa-plan-template.md +63 -49
- package/src/templates/agents/claude-code/skills/release-coordinator/SKILL.md +5 -5
- package/src/templates/agents/claude-code/skills/release-coordinator/feature-flag-guide.md +30 -26
- package/src/templates/agents/claude-code/skills/release-coordinator/release-plan-template.md +67 -35
- package/src/templates/agents/claude-code/skills/requirements-analyst/ears-format.md +54 -42
- package/src/templates/agents/claude-code/skills/requirements-analyst/validation-rules.md +36 -33
- package/src/templates/agents/claude-code/skills/security-auditor/SKILL.md +77 -19
- package/src/templates/agents/claude-code/skills/security-auditor/audit-checklists.md +24 -24
- package/src/templates/agents/claude-code/skills/security-auditor/owasp-top-10.md +61 -20
- package/src/templates/agents/claude-code/skills/security-auditor/vulnerability-patterns.md +43 -11
- package/src/templates/agents/claude-code/skills/site-reliability-engineer/SKILL.md +1 -0
- package/src/templates/agents/claude-code/skills/site-reliability-engineer/incident-response-template.md +55 -25
- package/src/templates/agents/claude-code/skills/site-reliability-engineer/observability-patterns.md +78 -68
- package/src/templates/agents/claude-code/skills/site-reliability-engineer/slo-sli-guide.md +73 -53
- package/src/templates/agents/claude-code/skills/software-developer/solid-principles.md +83 -37
- package/src/templates/agents/claude-code/skills/software-developer/test-first-workflow.md +38 -31
- package/src/templates/agents/claude-code/skills/steering/SKILL.md +1 -0
- package/src/templates/agents/claude-code/skills/steering/auto-update-rules.md +31 -0
- package/src/templates/agents/claude-code/skills/system-architect/adr-template.md +25 -7
- package/src/templates/agents/claude-code/skills/system-architect/c4-model-guide.md +74 -61
- package/src/templates/agents/claude-code/skills/technical-writer/doc-templates/documentation-templates.md +70 -52
- package/src/templates/agents/claude-code/skills/test-engineer/SKILL.md +2 -0
- package/src/templates/agents/claude-code/skills/test-engineer/ears-test-mapping.md +75 -71
- package/src/templates/agents/claude-code/skills/test-engineer/test-types.md +85 -63
- package/src/templates/agents/claude-code/skills/traceability-auditor/coverage-matrix-template.md +39 -36
- package/src/templates/agents/claude-code/skills/traceability-auditor/gap-detection-rules.md +22 -17
- package/src/templates/agents/claude-code/skills/ui-ux-designer/SKILL.md +1 -0
- package/src/templates/agents/claude-code/skills/ui-ux-designer/accessibility-guidelines.md +49 -75
- package/src/templates/agents/claude-code/skills/ui-ux-designer/design-system-components.md +71 -59
- package/src/templates/agents/codex/AGENTS.md +74 -42
- package/src/templates/agents/cursor/AGENTS.md +74 -42
- package/src/templates/agents/gemini-cli/GEMINI.md +74 -42
- package/src/templates/agents/github-copilot/AGENTS.md +83 -51
- package/src/templates/agents/qwen-code/QWEN.md +74 -42
- package/src/templates/agents/windsurf/AGENTS.md +74 -42
- package/src/templates/architectures/README.md +41 -0
- package/src/templates/architectures/clean-architecture/README.md +113 -0
- package/src/templates/architectures/event-driven/README.md +162 -0
- package/src/templates/architectures/hexagonal/README.md +130 -0
- package/src/templates/index.js +6 -1
- package/src/templates/locale-manager.js +16 -16
- package/src/templates/shared/delta-spec-template.md +20 -13
- package/src/templates/shared/github-actions/musubi-issue-resolver.yml +5 -5
- package/src/templates/shared/github-actions/musubi-security-check.yml +3 -3
- package/src/templates/shared/github-actions/musubi-validate.yml +4 -4
- package/src/templates/shared/steering/structure.md +95 -0
- package/src/templates/skills/browser-agent.md +21 -16
- package/src/templates/skills/web-gui.md +8 -0
- package/src/templates/template-constraints.js +50 -53
- package/src/validators/advanced-validation.js +30 -36
- package/src/validators/constitutional-validator.js +77 -73
- package/src/validators/critic-system.js +49 -59
- package/src/validators/delta-format.js +59 -55
- package/src/validators/traceability-validator.js +7 -11
|
@@ -0,0 +1,766 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MUSUBI Large Project Analyzer
|
|
3
|
+
*
|
|
4
|
+
* Streaming analysis for large-scale projects (10,000+ files)
|
|
5
|
+
* Designed based on analysis of GCC codebase (1,000万+ lines)
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - Chunk-based file processing
|
|
9
|
+
* - Memory-efficient streaming
|
|
10
|
+
* - Progress tracking
|
|
11
|
+
* - Parallel processing with worker threads
|
|
12
|
+
*
|
|
13
|
+
* @version 5.5.0
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const fs = require('fs-extra');
|
|
17
|
+
const path = require('path');
|
|
18
|
+
const { glob } = require('glob');
|
|
19
|
+
// Worker threads reserved for future parallel processing
|
|
20
|
+
// const { Worker, isMainThread, parentPort, workerData } = require('worker_threads');
|
|
21
|
+
const os = require('os');
|
|
22
|
+
|
|
23
|
+
// ============================================================================
|
|
24
|
+
// Configuration
|
|
25
|
+
// ============================================================================
|
|
26
|
+
|
|
27
|
+
const THRESHOLDS = {
|
|
28
|
+
// File count thresholds
|
|
29
|
+
smallProject: 100,
|
|
30
|
+
mediumProject: 1000,
|
|
31
|
+
largeProject: 10000,
|
|
32
|
+
massiveProject: 100000,
|
|
33
|
+
|
|
34
|
+
// Function size thresholds (lines)
|
|
35
|
+
functionLines: {
|
|
36
|
+
warning: 100,
|
|
37
|
+
critical: 500,
|
|
38
|
+
extreme: 1000,
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
// Cyclomatic complexity thresholds
|
|
42
|
+
cyclomaticComplexity: {
|
|
43
|
+
warning: 10,
|
|
44
|
+
critical: 25,
|
|
45
|
+
extreme: 50,
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
// Dependency count thresholds
|
|
49
|
+
dependencies: {
|
|
50
|
+
warning: 10,
|
|
51
|
+
critical: 30,
|
|
52
|
+
extreme: 100,
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const CHUNK_SIZE = {
|
|
57
|
+
small: 100,
|
|
58
|
+
medium: 500,
|
|
59
|
+
large: 1000,
|
|
60
|
+
streaming: 2000,
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
// ============================================================================
|
|
64
|
+
// Large Project Analyzer
|
|
65
|
+
// ============================================================================
|
|
66
|
+
|
|
67
|
+
class LargeProjectAnalyzer {
|
|
68
|
+
constructor(workspaceRoot, options = {}) {
|
|
69
|
+
this.workspaceRoot = workspaceRoot;
|
|
70
|
+
this.options = {
|
|
71
|
+
chunkSize: CHUNK_SIZE.large,
|
|
72
|
+
parallel: true,
|
|
73
|
+
workerCount: Math.max(1, os.cpus().length - 1),
|
|
74
|
+
progressCallback: null,
|
|
75
|
+
memoryLimit: 2 * 1024 * 1024 * 1024, // 2GB default
|
|
76
|
+
excludePatterns: [
|
|
77
|
+
'node_modules/**',
|
|
78
|
+
'dist/**',
|
|
79
|
+
'build/**',
|
|
80
|
+
'.git/**',
|
|
81
|
+
'coverage/**',
|
|
82
|
+
'*.min.js',
|
|
83
|
+
'*.bundle.js',
|
|
84
|
+
'vendor/**',
|
|
85
|
+
'third_party/**',
|
|
86
|
+
],
|
|
87
|
+
...options,
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
this.stats = {
|
|
91
|
+
totalFiles: 0,
|
|
92
|
+
processedFiles: 0,
|
|
93
|
+
skippedFiles: 0,
|
|
94
|
+
errorFiles: 0,
|
|
95
|
+
startTime: null,
|
|
96
|
+
endTime: null,
|
|
97
|
+
peakMemory: 0,
|
|
98
|
+
chunks: 0,
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
this.results = {
|
|
102
|
+
files: [],
|
|
103
|
+
giantFunctions: [],
|
|
104
|
+
hotspots: [],
|
|
105
|
+
summary: null,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Analyze project with automatic scaling based on size
|
|
111
|
+
*/
|
|
112
|
+
async analyze() {
|
|
113
|
+
this.stats.startTime = Date.now();
|
|
114
|
+
|
|
115
|
+
// Discover all files
|
|
116
|
+
const files = await this.discoverFiles();
|
|
117
|
+
this.stats.totalFiles = files.length;
|
|
118
|
+
|
|
119
|
+
// Determine project scale and strategy
|
|
120
|
+
const scale = this.determineScale(files.length);
|
|
121
|
+
console.log(`📊 Project scale: ${scale.name} (${files.length.toLocaleString()} files)`);
|
|
122
|
+
|
|
123
|
+
// Choose analysis strategy
|
|
124
|
+
let results;
|
|
125
|
+
switch (scale.strategy) {
|
|
126
|
+
case 'batch':
|
|
127
|
+
results = await this.batchAnalyze(files);
|
|
128
|
+
break;
|
|
129
|
+
case 'chunked':
|
|
130
|
+
results = await this.chunkedAnalyze(files);
|
|
131
|
+
break;
|
|
132
|
+
case 'streaming':
|
|
133
|
+
results = await this.streamingAnalyze(files);
|
|
134
|
+
break;
|
|
135
|
+
default:
|
|
136
|
+
results = await this.batchAnalyze(files);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
this.stats.endTime = Date.now();
|
|
140
|
+
this.generateSummary(results);
|
|
141
|
+
|
|
142
|
+
return {
|
|
143
|
+
stats: this.stats,
|
|
144
|
+
results: this.results,
|
|
145
|
+
recommendations: this.generateRecommendations(),
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Discover all analyzable files
|
|
151
|
+
*/
|
|
152
|
+
async discoverFiles() {
|
|
153
|
+
const patterns = [
|
|
154
|
+
'**/*.js',
|
|
155
|
+
'**/*.ts',
|
|
156
|
+
'**/*.jsx',
|
|
157
|
+
'**/*.tsx',
|
|
158
|
+
'**/*.c',
|
|
159
|
+
'**/*.cpp',
|
|
160
|
+
'**/*.cc',
|
|
161
|
+
'**/*.h',
|
|
162
|
+
'**/*.hpp',
|
|
163
|
+
'**/*.py',
|
|
164
|
+
'**/*.rs',
|
|
165
|
+
'**/*.go',
|
|
166
|
+
'**/*.java',
|
|
167
|
+
];
|
|
168
|
+
|
|
169
|
+
let allFiles = [];
|
|
170
|
+
|
|
171
|
+
for (const pattern of patterns) {
|
|
172
|
+
try {
|
|
173
|
+
const files = await glob(pattern, {
|
|
174
|
+
cwd: this.workspaceRoot,
|
|
175
|
+
ignore: this.options.excludePatterns,
|
|
176
|
+
nodir: true,
|
|
177
|
+
absolute: true,
|
|
178
|
+
});
|
|
179
|
+
allFiles = allFiles.concat(files);
|
|
180
|
+
} catch (error) {
|
|
181
|
+
console.warn(`Pattern ${pattern} failed: ${error.message}`);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return allFiles;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Determine project scale and analysis strategy
|
|
190
|
+
*/
|
|
191
|
+
determineScale(fileCount) {
|
|
192
|
+
if (fileCount <= THRESHOLDS.smallProject) {
|
|
193
|
+
return {
|
|
194
|
+
name: 'Small',
|
|
195
|
+
strategy: 'batch',
|
|
196
|
+
chunkSize: CHUNK_SIZE.small,
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
if (fileCount <= THRESHOLDS.mediumProject) {
|
|
200
|
+
return {
|
|
201
|
+
name: 'Medium',
|
|
202
|
+
strategy: 'batch',
|
|
203
|
+
chunkSize: CHUNK_SIZE.medium,
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
if (fileCount <= THRESHOLDS.largeProject) {
|
|
207
|
+
return {
|
|
208
|
+
name: 'Large',
|
|
209
|
+
strategy: 'chunked',
|
|
210
|
+
chunkSize: CHUNK_SIZE.large,
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
return {
|
|
214
|
+
name: 'Massive',
|
|
215
|
+
strategy: 'streaming',
|
|
216
|
+
chunkSize: CHUNK_SIZE.streaming,
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Batch analysis for small/medium projects
|
|
222
|
+
*/
|
|
223
|
+
async batchAnalyze(files) {
|
|
224
|
+
const results = [];
|
|
225
|
+
|
|
226
|
+
for (const file of files) {
|
|
227
|
+
const analysis = await this.analyzeFile(file);
|
|
228
|
+
if (analysis) {
|
|
229
|
+
results.push(analysis);
|
|
230
|
+
}
|
|
231
|
+
this.stats.processedFiles++;
|
|
232
|
+
this.updateProgress();
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
return results;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Chunked analysis for large projects
|
|
240
|
+
*/
|
|
241
|
+
async chunkedAnalyze(files) {
|
|
242
|
+
const chunkSize = this.options.chunkSize;
|
|
243
|
+
const results = [];
|
|
244
|
+
|
|
245
|
+
for (let i = 0; i < files.length; i += chunkSize) {
|
|
246
|
+
const chunk = files.slice(i, i + chunkSize);
|
|
247
|
+
this.stats.chunks++;
|
|
248
|
+
|
|
249
|
+
const chunkResults = await Promise.all(chunk.map(file => this.analyzeFile(file)));
|
|
250
|
+
|
|
251
|
+
results.push(...chunkResults.filter(r => r !== null));
|
|
252
|
+
this.stats.processedFiles += chunk.length;
|
|
253
|
+
|
|
254
|
+
// Memory management
|
|
255
|
+
this.checkMemory();
|
|
256
|
+
this.updateProgress();
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
return results;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Streaming analysis for massive projects
|
|
264
|
+
* Uses worker threads for parallel processing
|
|
265
|
+
*/
|
|
266
|
+
async streamingAnalyze(files) {
|
|
267
|
+
const chunkSize = this.options.chunkSize;
|
|
268
|
+
const results = [];
|
|
269
|
+
|
|
270
|
+
console.log(
|
|
271
|
+
`🚀 Streaming mode: Processing ${files.length.toLocaleString()} files in chunks of ${chunkSize}`
|
|
272
|
+
);
|
|
273
|
+
|
|
274
|
+
for (let i = 0; i < files.length; i += chunkSize) {
|
|
275
|
+
const chunk = files.slice(i, i + chunkSize);
|
|
276
|
+
this.stats.chunks++;
|
|
277
|
+
|
|
278
|
+
// Process chunk with incremental aggregation
|
|
279
|
+
const chunkResults = await this.processChunk(chunk);
|
|
280
|
+
|
|
281
|
+
// Aggregate results incrementally to manage memory
|
|
282
|
+
this.aggregateResults(chunkResults);
|
|
283
|
+
this.stats.processedFiles += chunk.length;
|
|
284
|
+
|
|
285
|
+
// Force garbage collection if available
|
|
286
|
+
if (global.gc) {
|
|
287
|
+
global.gc();
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
this.checkMemory();
|
|
291
|
+
this.updateProgress();
|
|
292
|
+
|
|
293
|
+
// Log progress every 10 chunks
|
|
294
|
+
if (this.stats.chunks % 10 === 0) {
|
|
295
|
+
const percent = Math.round((this.stats.processedFiles / files.length) * 100);
|
|
296
|
+
const elapsed = ((Date.now() - this.stats.startTime) / 1000).toFixed(1);
|
|
297
|
+
console.log(` 📦 Chunk ${this.stats.chunks}: ${percent}% complete (${elapsed}s elapsed)`);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
return results;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Process a chunk of files
|
|
306
|
+
*/
|
|
307
|
+
async processChunk(files) {
|
|
308
|
+
const results = [];
|
|
309
|
+
|
|
310
|
+
for (const file of files) {
|
|
311
|
+
try {
|
|
312
|
+
const analysis = await this.analyzeFile(file);
|
|
313
|
+
if (analysis) {
|
|
314
|
+
results.push(analysis);
|
|
315
|
+
}
|
|
316
|
+
} catch (error) {
|
|
317
|
+
this.stats.errorFiles++;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
return results;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* Analyze a single file
|
|
326
|
+
*/
|
|
327
|
+
async analyzeFile(filePath) {
|
|
328
|
+
try {
|
|
329
|
+
const content = await fs.readFile(filePath, 'utf8');
|
|
330
|
+
const stats = await fs.stat(filePath);
|
|
331
|
+
const lines = content.split('\n');
|
|
332
|
+
const language = this.detectLanguage(filePath);
|
|
333
|
+
|
|
334
|
+
const analysis = {
|
|
335
|
+
path: path.relative(this.workspaceRoot, filePath),
|
|
336
|
+
absolutePath: filePath,
|
|
337
|
+
language,
|
|
338
|
+
lines: lines.length,
|
|
339
|
+
size: stats.size,
|
|
340
|
+
complexity: this.calculateComplexity(content, language),
|
|
341
|
+
maintainability: 0,
|
|
342
|
+
functions: this.extractFunctions(content, language),
|
|
343
|
+
issues: [],
|
|
344
|
+
};
|
|
345
|
+
|
|
346
|
+
// Calculate maintainability
|
|
347
|
+
analysis.maintainability = this.calculateMaintainability(content, analysis.complexity);
|
|
348
|
+
|
|
349
|
+
// Detect issues
|
|
350
|
+
analysis.issues = this.detectIssues(analysis);
|
|
351
|
+
|
|
352
|
+
return analysis;
|
|
353
|
+
} catch (error) {
|
|
354
|
+
this.stats.errorFiles++;
|
|
355
|
+
return null;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* Detect programming language from file extension
|
|
361
|
+
*/
|
|
362
|
+
detectLanguage(filePath) {
|
|
363
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
364
|
+
const langMap = {
|
|
365
|
+
'.js': 'javascript',
|
|
366
|
+
'.ts': 'typescript',
|
|
367
|
+
'.jsx': 'javascript',
|
|
368
|
+
'.tsx': 'typescript',
|
|
369
|
+
'.c': 'c',
|
|
370
|
+
'.h': 'c',
|
|
371
|
+
'.cpp': 'cpp',
|
|
372
|
+
'.cc': 'cpp',
|
|
373
|
+
'.hpp': 'cpp',
|
|
374
|
+
'.py': 'python',
|
|
375
|
+
'.rs': 'rust',
|
|
376
|
+
'.go': 'go',
|
|
377
|
+
'.java': 'java',
|
|
378
|
+
};
|
|
379
|
+
return langMap[ext] || 'unknown';
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
/**
|
|
383
|
+
* Calculate cyclomatic complexity
|
|
384
|
+
*/
|
|
385
|
+
calculateComplexity(code, language) {
|
|
386
|
+
let complexity = 1;
|
|
387
|
+
|
|
388
|
+
// Common decision point patterns
|
|
389
|
+
const patterns = [
|
|
390
|
+
/\bif\b/g,
|
|
391
|
+
/\belse\s+if\b/g,
|
|
392
|
+
/\bfor\b/g,
|
|
393
|
+
/\bwhile\b/g,
|
|
394
|
+
/\bcase\b/g,
|
|
395
|
+
/\bcatch\b/g,
|
|
396
|
+
/&&/g,
|
|
397
|
+
/\|\|/g,
|
|
398
|
+
/\?[^:]*:/g, // Ternary
|
|
399
|
+
];
|
|
400
|
+
|
|
401
|
+
// Language-specific patterns
|
|
402
|
+
if (language === 'rust') {
|
|
403
|
+
patterns.push(/\bmatch\b/g, /\b=>\b/g);
|
|
404
|
+
}
|
|
405
|
+
if (language === 'python') {
|
|
406
|
+
patterns.push(/\belif\b/g, /\bexcept\b/g);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
patterns.forEach(pattern => {
|
|
410
|
+
const matches = code.match(pattern);
|
|
411
|
+
if (matches) complexity += matches.length;
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
return complexity;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/**
|
|
418
|
+
* Calculate maintainability index
|
|
419
|
+
*/
|
|
420
|
+
calculateMaintainability(code, complexity) {
|
|
421
|
+
const lines = code.split('\n');
|
|
422
|
+
const codeLines = lines.filter(line => {
|
|
423
|
+
const trimmed = line.trim();
|
|
424
|
+
return (
|
|
425
|
+
trimmed.length > 0 &&
|
|
426
|
+
!trimmed.startsWith('//') &&
|
|
427
|
+
!trimmed.startsWith('/*') &&
|
|
428
|
+
!trimmed.startsWith('#')
|
|
429
|
+
);
|
|
430
|
+
}).length;
|
|
431
|
+
|
|
432
|
+
const commentLines = lines.filter(line => {
|
|
433
|
+
const trimmed = line.trim();
|
|
434
|
+
return (
|
|
435
|
+
trimmed.startsWith('//') ||
|
|
436
|
+
trimmed.startsWith('/*') ||
|
|
437
|
+
trimmed.startsWith('*') ||
|
|
438
|
+
trimmed.startsWith('#')
|
|
439
|
+
);
|
|
440
|
+
}).length;
|
|
441
|
+
|
|
442
|
+
const commentRatio = codeLines > 0 ? commentLines / codeLines : 0;
|
|
443
|
+
|
|
444
|
+
const volumeScore = Math.max(0, 100 - Math.log2(codeLines + 1) * 5);
|
|
445
|
+
const complexityScore = Math.max(0, 100 - complexity * 2);
|
|
446
|
+
const commentScore = Math.min(100, commentRatio * 100);
|
|
447
|
+
|
|
448
|
+
return Math.round(volumeScore * 0.4 + complexityScore * 0.4 + commentScore * 0.2);
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
/**
|
|
452
|
+
* Extract functions from code
|
|
453
|
+
*/
|
|
454
|
+
extractFunctions(code, language) {
|
|
455
|
+
const functions = [];
|
|
456
|
+
const lines = code.split('\n');
|
|
457
|
+
|
|
458
|
+
// Simple function detection patterns
|
|
459
|
+
const patterns = {
|
|
460
|
+
javascript:
|
|
461
|
+
/(?:function\s+(\w+)|(?:const|let|var)\s+(\w+)\s*=\s*(?:async\s+)?(?:function|\([^)]*\)\s*=>))/g,
|
|
462
|
+
typescript:
|
|
463
|
+
/(?:function\s+(\w+)|(?:const|let|var)\s+(\w+)\s*=\s*(?:async\s+)?(?:function|\([^)]*\)\s*=>))/g,
|
|
464
|
+
c: /(?:static\s+)?(?:inline\s+)?(?:\w+\s+)+(\w+)\s*\([^)]*\)\s*\{/g,
|
|
465
|
+
cpp: /(?:static\s+)?(?:inline\s+)?(?:virtual\s+)?(?:\w+\s+)+(\w+)\s*\([^)]*\)(?:\s*const)?\s*(?:override)?\s*\{/g,
|
|
466
|
+
python: /def\s+(\w+)\s*\(/g,
|
|
467
|
+
rust: /(?:pub\s+)?(?:async\s+)?fn\s+(\w+)/g,
|
|
468
|
+
go: /func\s+(?:\([^)]+\)\s+)?(\w+)/g,
|
|
469
|
+
java: /(?:public|private|protected)?\s*(?:static)?\s*(?:\w+)\s+(\w+)\s*\([^)]*\)\s*(?:throws\s+\w+(?:,\s*\w+)*)?\s*\{/g,
|
|
470
|
+
};
|
|
471
|
+
|
|
472
|
+
const pattern = patterns[language];
|
|
473
|
+
if (!pattern) return functions;
|
|
474
|
+
|
|
475
|
+
let match;
|
|
476
|
+
while ((match = pattern.exec(code)) !== null) {
|
|
477
|
+
const name = match[1] || match[2];
|
|
478
|
+
if (name) {
|
|
479
|
+
// Estimate function size (simple heuristic)
|
|
480
|
+
const startIndex = match.index;
|
|
481
|
+
const startLine = code.substring(0, startIndex).split('\n').length;
|
|
482
|
+
const endLine = this.findFunctionEnd(lines, startLine - 1, language);
|
|
483
|
+
|
|
484
|
+
functions.push({
|
|
485
|
+
name,
|
|
486
|
+
startLine,
|
|
487
|
+
endLine,
|
|
488
|
+
lines: endLine - startLine + 1,
|
|
489
|
+
});
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
return functions;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
/**
|
|
497
|
+
* Find the end of a function (simplified)
|
|
498
|
+
*/
|
|
499
|
+
findFunctionEnd(lines, startLine, language) {
|
|
500
|
+
if (language === 'python') {
|
|
501
|
+
// Python: find next line with same or less indentation
|
|
502
|
+
const startIndent = lines[startLine]?.match(/^\s*/)?.[0].length || 0;
|
|
503
|
+
for (let i = startLine + 1; i < lines.length; i++) {
|
|
504
|
+
const line = lines[i];
|
|
505
|
+
if (line.trim() && line.match(/^\s*/)[0].length <= startIndent) {
|
|
506
|
+
return i;
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
return lines.length;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
// Brace-based languages
|
|
513
|
+
let braceCount = 0;
|
|
514
|
+
let started = false;
|
|
515
|
+
|
|
516
|
+
for (let i = startLine; i < lines.length; i++) {
|
|
517
|
+
const line = lines[i];
|
|
518
|
+
for (const char of line) {
|
|
519
|
+
if (char === '{') {
|
|
520
|
+
braceCount++;
|
|
521
|
+
started = true;
|
|
522
|
+
} else if (char === '}') {
|
|
523
|
+
braceCount--;
|
|
524
|
+
if (started && braceCount === 0) {
|
|
525
|
+
return i + 1;
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
return Math.min(startLine + 100, lines.length);
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
/**
|
|
535
|
+
* Detect issues in analyzed file
|
|
536
|
+
*/
|
|
537
|
+
detectIssues(analysis) {
|
|
538
|
+
const issues = [];
|
|
539
|
+
|
|
540
|
+
// Giant functions
|
|
541
|
+
for (const func of analysis.functions) {
|
|
542
|
+
if (func.lines >= THRESHOLDS.functionLines.extreme) {
|
|
543
|
+
issues.push({
|
|
544
|
+
type: 'giant-function',
|
|
545
|
+
severity: 'extreme',
|
|
546
|
+
message: `Function "${func.name}" has ${func.lines} lines (threshold: ${THRESHOLDS.functionLines.extreme})`,
|
|
547
|
+
function: func.name,
|
|
548
|
+
lines: func.lines,
|
|
549
|
+
recommendations: this.generateFunctionSplitRecommendations(func),
|
|
550
|
+
});
|
|
551
|
+
this.results.giantFunctions.push({
|
|
552
|
+
file: analysis.path,
|
|
553
|
+
...func,
|
|
554
|
+
});
|
|
555
|
+
} else if (func.lines >= THRESHOLDS.functionLines.critical) {
|
|
556
|
+
issues.push({
|
|
557
|
+
type: 'large-function',
|
|
558
|
+
severity: 'critical',
|
|
559
|
+
message: `Function "${func.name}" has ${func.lines} lines (threshold: ${THRESHOLDS.functionLines.critical})`,
|
|
560
|
+
function: func.name,
|
|
561
|
+
lines: func.lines,
|
|
562
|
+
});
|
|
563
|
+
} else if (func.lines >= THRESHOLDS.functionLines.warning) {
|
|
564
|
+
issues.push({
|
|
565
|
+
type: 'long-function',
|
|
566
|
+
severity: 'warning',
|
|
567
|
+
message: `Function "${func.name}" has ${func.lines} lines (threshold: ${THRESHOLDS.functionLines.warning})`,
|
|
568
|
+
function: func.name,
|
|
569
|
+
lines: func.lines,
|
|
570
|
+
});
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
// High file complexity
|
|
575
|
+
if (analysis.complexity >= THRESHOLDS.cyclomaticComplexity.extreme) {
|
|
576
|
+
issues.push({
|
|
577
|
+
type: 'extreme-complexity',
|
|
578
|
+
severity: 'extreme',
|
|
579
|
+
message: `File complexity is ${analysis.complexity} (threshold: ${THRESHOLDS.cyclomaticComplexity.extreme})`,
|
|
580
|
+
});
|
|
581
|
+
this.results.hotspots.push({
|
|
582
|
+
file: analysis.path,
|
|
583
|
+
complexity: analysis.complexity,
|
|
584
|
+
reason: 'extreme-complexity',
|
|
585
|
+
});
|
|
586
|
+
} else if (analysis.complexity >= THRESHOLDS.cyclomaticComplexity.critical) {
|
|
587
|
+
issues.push({
|
|
588
|
+
type: 'high-complexity',
|
|
589
|
+
severity: 'critical',
|
|
590
|
+
message: `File complexity is ${analysis.complexity} (threshold: ${THRESHOLDS.cyclomaticComplexity.critical})`,
|
|
591
|
+
});
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
// Low maintainability
|
|
595
|
+
if (analysis.maintainability < 20) {
|
|
596
|
+
issues.push({
|
|
597
|
+
type: 'low-maintainability',
|
|
598
|
+
severity: 'critical',
|
|
599
|
+
message: `Maintainability index is ${analysis.maintainability} (very poor)`,
|
|
600
|
+
});
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
return issues;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
/**
|
|
607
|
+
* Generate recommendations for splitting a giant function
|
|
608
|
+
*/
|
|
609
|
+
generateFunctionSplitRecommendations(func) {
|
|
610
|
+
const targetCount = Math.ceil(func.lines / 50);
|
|
611
|
+
return [
|
|
612
|
+
`Split "${func.name}" into ${targetCount} smaller functions (target: ~50 lines each)`,
|
|
613
|
+
'Extract helper functions for repeated logic',
|
|
614
|
+
'Consider using the Extract Method refactoring pattern',
|
|
615
|
+
'Group related operations into separate functions by responsibility',
|
|
616
|
+
];
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
/**
|
|
620
|
+
* Aggregate results incrementally for memory efficiency
|
|
621
|
+
*/
|
|
622
|
+
aggregateResults(chunkResults) {
|
|
623
|
+
for (const result of chunkResults) {
|
|
624
|
+
// Keep only essential data for summary
|
|
625
|
+
this.results.files.push({
|
|
626
|
+
path: result.path,
|
|
627
|
+
language: result.language,
|
|
628
|
+
lines: result.lines,
|
|
629
|
+
complexity: result.complexity,
|
|
630
|
+
maintainability: result.maintainability,
|
|
631
|
+
issueCount: result.issues.length,
|
|
632
|
+
});
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
/**
|
|
637
|
+
* Check memory usage and warn if approaching limit
|
|
638
|
+
*/
|
|
639
|
+
checkMemory() {
|
|
640
|
+
const used = process.memoryUsage();
|
|
641
|
+
const heapUsed = used.heapUsed;
|
|
642
|
+
|
|
643
|
+
if (heapUsed > this.stats.peakMemory) {
|
|
644
|
+
this.stats.peakMemory = heapUsed;
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
if (heapUsed > this.options.memoryLimit * 0.9) {
|
|
648
|
+
console.warn(`⚠️ Memory usage high: ${Math.round(heapUsed / 1024 / 1024)}MB`);
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
/**
|
|
653
|
+
* Update progress
|
|
654
|
+
*/
|
|
655
|
+
updateProgress() {
|
|
656
|
+
if (this.options.progressCallback) {
|
|
657
|
+
const percent = Math.round((this.stats.processedFiles / this.stats.totalFiles) * 100);
|
|
658
|
+
this.options.progressCallback({
|
|
659
|
+
processed: this.stats.processedFiles,
|
|
660
|
+
total: this.stats.totalFiles,
|
|
661
|
+
percent,
|
|
662
|
+
chunks: this.stats.chunks,
|
|
663
|
+
});
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
/**
|
|
668
|
+
* Generate summary from results
|
|
669
|
+
*/
|
|
670
|
+
generateSummary(_results) {
|
|
671
|
+
const files = this.results.files;
|
|
672
|
+
|
|
673
|
+
this.results.summary = {
|
|
674
|
+
totalFiles: files.length,
|
|
675
|
+
totalLines: files.reduce((sum, f) => sum + f.lines, 0),
|
|
676
|
+
averageComplexity:
|
|
677
|
+
files.length > 0
|
|
678
|
+
? Math.round(files.reduce((sum, f) => sum + f.complexity, 0) / files.length)
|
|
679
|
+
: 0,
|
|
680
|
+
averageMaintainability:
|
|
681
|
+
files.length > 0
|
|
682
|
+
? Math.round(files.reduce((sum, f) => sum + f.maintainability, 0) / files.length)
|
|
683
|
+
: 0,
|
|
684
|
+
giantFunctions: this.results.giantFunctions.length,
|
|
685
|
+
hotspots: this.results.hotspots.length,
|
|
686
|
+
languageDistribution: this.calculateLanguageDistribution(files),
|
|
687
|
+
processingTime: this.stats.endTime - this.stats.startTime,
|
|
688
|
+
peakMemoryMB: Math.round(this.stats.peakMemory / 1024 / 1024),
|
|
689
|
+
};
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
/**
|
|
693
|
+
* Calculate language distribution
|
|
694
|
+
*/
|
|
695
|
+
calculateLanguageDistribution(files) {
|
|
696
|
+
const distribution = {};
|
|
697
|
+
for (const file of files) {
|
|
698
|
+
distribution[file.language] = (distribution[file.language] || 0) + 1;
|
|
699
|
+
}
|
|
700
|
+
return distribution;
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
/**
|
|
704
|
+
* Generate overall recommendations
|
|
705
|
+
*/
|
|
706
|
+
generateRecommendations() {
|
|
707
|
+
const recommendations = [];
|
|
708
|
+
const summary = this.results.summary;
|
|
709
|
+
|
|
710
|
+
if (!summary) return recommendations;
|
|
711
|
+
|
|
712
|
+
// Giant functions
|
|
713
|
+
if (this.results.giantFunctions.length > 0) {
|
|
714
|
+
recommendations.push({
|
|
715
|
+
priority: 'P0',
|
|
716
|
+
type: 'refactoring',
|
|
717
|
+
title: 'Split Giant Functions',
|
|
718
|
+
message: `${this.results.giantFunctions.length} functions exceed 1000 lines. These require immediate refactoring.`,
|
|
719
|
+
items: this.results.giantFunctions
|
|
720
|
+
.slice(0, 5)
|
|
721
|
+
.map(f => `${f.file}:${f.name} (${f.lines} lines)`),
|
|
722
|
+
});
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
// Hotspots
|
|
726
|
+
if (this.results.hotspots.length > 0) {
|
|
727
|
+
recommendations.push({
|
|
728
|
+
priority: 'P1',
|
|
729
|
+
type: 'complexity',
|
|
730
|
+
title: 'Address Complexity Hotspots',
|
|
731
|
+
message: `${this.results.hotspots.length} files have extreme complexity. Consider breaking them down.`,
|
|
732
|
+
items: this.results.hotspots
|
|
733
|
+
.slice(0, 5)
|
|
734
|
+
.map(h => `${h.file} (complexity: ${h.complexity})`),
|
|
735
|
+
});
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
// Low maintainability
|
|
739
|
+
if (summary.averageMaintainability < 40) {
|
|
740
|
+
recommendations.push({
|
|
741
|
+
priority: 'P2',
|
|
742
|
+
type: 'maintainability',
|
|
743
|
+
title: 'Improve Code Maintainability',
|
|
744
|
+
message: `Average maintainability is ${summary.averageMaintainability}. Consider adding comments and simplifying logic.`,
|
|
745
|
+
});
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
// Large project recommendations
|
|
749
|
+
if (summary.totalFiles > THRESHOLDS.largeProject) {
|
|
750
|
+
recommendations.push({
|
|
751
|
+
priority: 'P2',
|
|
752
|
+
type: 'architecture',
|
|
753
|
+
title: 'Consider Modular Architecture',
|
|
754
|
+
message: `With ${summary.totalFiles.toLocaleString()} files, consider splitting into modules or microservices.`,
|
|
755
|
+
});
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
return recommendations;
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
module.exports = {
|
|
763
|
+
LargeProjectAnalyzer,
|
|
764
|
+
THRESHOLDS,
|
|
765
|
+
CHUNK_SIZE,
|
|
766
|
+
};
|