erosolar-cli 2.0.5 → 2.1.2
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/agents/erosolar-security.rules.json +147 -0
- package/dist/capabilities/enhancedAnalysisCapability.d.ts +13 -0
- package/dist/capabilities/enhancedAnalysisCapability.d.ts.map +1 -0
- package/dist/capabilities/enhancedAnalysisCapability.js +20 -0
- package/dist/capabilities/enhancedAnalysisCapability.js.map +1 -0
- package/dist/capabilities/offsecOpsCapability.d.ts +6 -0
- package/dist/capabilities/offsecOpsCapability.d.ts.map +1 -0
- package/dist/capabilities/offsecOpsCapability.js +20 -0
- package/dist/capabilities/offsecOpsCapability.js.map +1 -0
- package/dist/capabilities/offsecSearchCapability.d.ts +12 -0
- package/dist/capabilities/offsecSearchCapability.d.ts.map +1 -0
- package/dist/capabilities/offsecSearchCapability.js +27 -0
- package/dist/capabilities/offsecSearchCapability.js.map +1 -0
- package/dist/capabilities/taoCapability.d.ts +6 -0
- package/dist/capabilities/taoCapability.d.ts.map +1 -0
- package/dist/capabilities/taoCapability.js +20 -0
- package/dist/capabilities/taoCapability.js.map +1 -0
- package/dist/capabilities/toolRegistry.d.ts +2 -1
- package/dist/capabilities/toolRegistry.d.ts.map +1 -1
- package/dist/capabilities/toolRegistry.js +6 -1
- package/dist/capabilities/toolRegistry.js.map +1 -1
- package/dist/contracts/agent-schemas.json +18 -19
- package/dist/contracts/tools.schema.json +38 -8
- package/dist/core/agent.js +4 -4
- package/dist/core/agent.js.map +1 -1
- package/dist/core/alphaZeroEngine.js +1 -1
- package/dist/core/alphaZeroEngine.js.map +1 -1
- package/dist/core/alphaZeroModular.js +2 -2
- package/dist/core/alphaZeroModular.js.map +1 -1
- package/dist/core/contextManager.d.ts +8 -2
- package/dist/core/contextManager.d.ts.map +1 -1
- package/dist/core/contextManager.js +15 -2
- package/dist/core/contextManager.js.map +1 -1
- package/dist/core/costTracker.js +1 -1
- package/dist/core/costTracker.js.map +1 -1
- package/dist/core/deepBugAnalyzer.d.ts +128 -0
- package/dist/core/deepBugAnalyzer.d.ts.map +1 -0
- package/dist/core/deepBugAnalyzer.js +406 -0
- package/dist/core/deepBugAnalyzer.js.map +1 -0
- package/dist/core/hypothesisEngine.d.ts +113 -0
- package/dist/core/hypothesisEngine.d.ts.map +1 -0
- package/dist/core/hypothesisEngine.js +264 -0
- package/dist/core/hypothesisEngine.js.map +1 -0
- package/dist/core/intelligentSummarizer.d.ts +79 -0
- package/dist/core/intelligentSummarizer.d.ts.map +1 -0
- package/dist/core/intelligentSummarizer.js +273 -0
- package/dist/core/intelligentSummarizer.js.map +1 -0
- package/dist/core/memorySystem.js +2 -2
- package/dist/core/memorySystem.js.map +1 -1
- package/dist/core/offsecAlphaZero.d.ts +3 -0
- package/dist/core/offsecAlphaZero.d.ts.map +1 -1
- package/dist/core/offsecAlphaZero.js +166 -5
- package/dist/core/offsecAlphaZero.js.map +1 -1
- package/dist/core/productTestHarness.d.ts +113 -0
- package/dist/core/productTestHarness.d.ts.map +1 -0
- package/dist/core/productTestHarness.js +345 -0
- package/dist/core/productTestHarness.js.map +1 -0
- package/dist/core/securityAssessment.js +1 -1
- package/dist/core/securityAssessment.js.map +1 -1
- package/dist/core/toolPatternAnalyzer.d.ts +87 -0
- package/dist/core/toolPatternAnalyzer.d.ts.map +1 -0
- package/dist/core/toolPatternAnalyzer.js +272 -0
- package/dist/core/toolPatternAnalyzer.js.map +1 -0
- package/dist/core/updateChecker.js +3 -3
- package/dist/core/updateChecker.js.map +1 -1
- package/dist/mcp/sseClient.js +1 -1
- package/dist/mcp/sseClient.js.map +1 -1
- package/dist/plugins/tools/enhancedAnalysis/enhancedAnalysisPlugin.d.ts +3 -0
- package/dist/plugins/tools/enhancedAnalysis/enhancedAnalysisPlugin.d.ts.map +1 -0
- package/dist/plugins/tools/enhancedAnalysis/enhancedAnalysisPlugin.js +14 -0
- package/dist/plugins/tools/enhancedAnalysis/enhancedAnalysisPlugin.js.map +1 -0
- package/dist/plugins/tools/enhancedCodeIntelligence/enhancedCodeIntelligencePlugin.d.ts +3 -0
- package/dist/plugins/tools/enhancedCodeIntelligence/enhancedCodeIntelligencePlugin.d.ts.map +1 -0
- package/dist/plugins/tools/enhancedCodeIntelligence/enhancedCodeIntelligencePlugin.js +12 -0
- package/dist/plugins/tools/enhancedCodeIntelligence/enhancedCodeIntelligencePlugin.js.map +1 -0
- package/dist/plugins/tools/enhancedDevWorkflow/enhancedDevWorkflowPlugin.d.ts +3 -0
- package/dist/plugins/tools/enhancedDevWorkflow/enhancedDevWorkflowPlugin.d.ts.map +1 -0
- package/dist/plugins/tools/enhancedDevWorkflow/enhancedDevWorkflowPlugin.js +12 -0
- package/dist/plugins/tools/enhancedDevWorkflow/enhancedDevWorkflowPlugin.js.map +1 -0
- package/dist/plugins/tools/nodeDefaults.d.ts.map +1 -1
- package/dist/plugins/tools/nodeDefaults.js +12 -0
- package/dist/plugins/tools/nodeDefaults.js.map +1 -1
- package/dist/plugins/tools/offsec/offsecOpsPlugin.d.ts +3 -0
- package/dist/plugins/tools/offsec/offsecOpsPlugin.d.ts.map +1 -0
- package/dist/plugins/tools/offsec/offsecOpsPlugin.js +10 -0
- package/dist/plugins/tools/offsec/offsecOpsPlugin.js.map +1 -0
- package/dist/plugins/tools/offsec/offsecSearchPlugin.d.ts +3 -0
- package/dist/plugins/tools/offsec/offsecSearchPlugin.d.ts.map +1 -0
- package/dist/plugins/tools/offsec/offsecSearchPlugin.js +12 -0
- package/dist/plugins/tools/offsec/offsecSearchPlugin.js.map +1 -0
- package/dist/plugins/tools/tao/taoPlugin.d.ts +3 -0
- package/dist/plugins/tools/tao/taoPlugin.d.ts.map +1 -0
- package/dist/plugins/tools/tao/taoPlugin.js +10 -0
- package/dist/plugins/tools/tao/taoPlugin.js.map +1 -0
- package/dist/shell/composableMessage.js +2 -2
- package/dist/shell/composableMessage.js.map +1 -1
- package/dist/shell/interactiveShell.d.ts +6 -0
- package/dist/shell/interactiveShell.d.ts.map +1 -1
- package/dist/shell/interactiveShell.js +50 -15
- package/dist/shell/interactiveShell.js.map +1 -1
- package/dist/shell/shellApp.js +1 -1
- package/dist/shell/shellApp.js.map +1 -1
- package/dist/shell/systemPrompt.d.ts.map +1 -1
- package/dist/shell/systemPrompt.js +3 -0
- package/dist/shell/systemPrompt.js.map +1 -1
- package/dist/tools/buildTools.js +1 -1
- package/dist/tools/buildTools.js.map +1 -1
- package/dist/tools/diffUtils.js +6 -6
- package/dist/tools/diffUtils.js.map +1 -1
- package/dist/tools/editTools.js +1 -1
- package/dist/tools/editTools.js.map +1 -1
- package/dist/tools/enhancedAnalysisTools.d.ts +9 -0
- package/dist/tools/enhancedAnalysisTools.d.ts.map +1 -0
- package/dist/tools/enhancedAnalysisTools.js +382 -0
- package/dist/tools/enhancedAnalysisTools.js.map +1 -0
- package/dist/tools/enhancedCodeIntelligenceTools.d.ts +1 -21
- package/dist/tools/enhancedCodeIntelligenceTools.d.ts.map +1 -1
- package/dist/tools/enhancedCodeIntelligenceTools.js +378 -256
- package/dist/tools/enhancedCodeIntelligenceTools.js.map +1 -1
- package/dist/tools/enhancedDevWorkflowTools.d.ts +2 -10
- package/dist/tools/enhancedDevWorkflowTools.d.ts.map +1 -1
- package/dist/tools/enhancedDevWorkflowTools.js +293 -165
- package/dist/tools/enhancedDevWorkflowTools.js.map +1 -1
- package/dist/tools/interactionTools.d.ts.map +1 -1
- package/dist/tools/interactionTools.js +55 -0
- package/dist/tools/interactionTools.js.map +1 -1
- package/dist/tools/learnTools.js +1 -1
- package/dist/tools/learnTools.js.map +1 -1
- package/dist/tools/offsec/offsecOperationsTools.d.ts +3 -0
- package/dist/tools/offsec/offsecOperationsTools.d.ts.map +1 -0
- package/dist/tools/offsec/offsecOperationsTools.js +333 -0
- package/dist/tools/offsec/offsecOperationsTools.js.map +1 -0
- package/dist/tools/offsecSearchTools.d.ts +3 -0
- package/dist/tools/offsecSearchTools.d.ts.map +1 -0
- package/dist/tools/offsecSearchTools.js +330 -0
- package/dist/tools/offsecSearchTools.js.map +1 -0
- package/dist/tools/taoOperations.d.ts +7 -0
- package/dist/tools/taoOperations.d.ts.map +1 -0
- package/dist/tools/taoOperations.js +744 -0
- package/dist/tools/taoOperations.js.map +1 -0
- package/dist/ui/ClaudeCodeRenderer.js +1 -1
- package/dist/ui/ClaudeCodeRenderer.js.map +1 -1
- package/dist/ui/ShellUIAdapter.d.ts +10 -6
- package/dist/ui/ShellUIAdapter.d.ts.map +1 -1
- package/dist/ui/ShellUIAdapter.js +69 -67
- package/dist/ui/ShellUIAdapter.js.map +1 -1
- package/dist/ui/UnifiedUIRenderer.d.ts +2 -0
- package/dist/ui/UnifiedUIRenderer.d.ts.map +1 -1
- package/dist/ui/UnifiedUIRenderer.js +64 -13
- package/dist/ui/UnifiedUIRenderer.js.map +1 -1
- package/dist/ui/globalWriteLock.d.ts.map +1 -1
- package/dist/ui/globalWriteLock.js +6 -0
- package/dist/ui/globalWriteLock.js.map +1 -1
- package/dist/ui/inPlaceUpdater.js +1 -1
- package/dist/ui/inPlaceUpdater.js.map +1 -1
- package/dist/ui/outputMode.d.ts.map +1 -1
- package/dist/ui/outputMode.js +1 -2
- package/dist/ui/outputMode.js.map +1 -1
- package/dist/ui/richText.js +4 -4
- package/dist/ui/richText.js.map +1 -1
- package/dist/ui/streamingFormatter.d.ts +11 -0
- package/dist/ui/streamingFormatter.d.ts.map +1 -1
- package/dist/ui/streamingFormatter.js +27 -1
- package/dist/ui/streamingFormatter.js.map +1 -1
- package/dist/ui/toolDisplay.js +1 -1
- package/dist/ui/toolDisplay.js.map +1 -1
- package/package.json +4 -13
|
@@ -1,418 +1,540 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Enhanced Code Intelligence Tools
|
|
3
|
-
*
|
|
3
|
+
* Production-ready code analysis, refactoring, and automation helpers.
|
|
4
4
|
*/
|
|
5
|
-
import { readFileSync,
|
|
6
|
-
import { join, relative } from 'node:path';
|
|
5
|
+
import { existsSync, readFileSync, readdirSync, statSync, writeFileSync } from 'node:fs';
|
|
6
|
+
import { join, relative, resolve } from 'node:path';
|
|
7
7
|
import { performAdvancedAstAnalysis } from './codeAnalysisTools.js';
|
|
8
|
+
import { CodeIntelligenceEngine } from '../intelligence/codeIntelligence.js';
|
|
9
|
+
import { RefactoringEngine } from '../intelligence/refactoring.js';
|
|
10
|
+
import { CodeIntelligenceSuite } from '../intelligence/index.js';
|
|
11
|
+
const SUPPORTED_EXTENSIONS = ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs'];
|
|
12
|
+
const IGNORED_DIRECTORIES = new Set(['node_modules', '.git', 'dist', 'build', '.next', '.turbo']);
|
|
8
13
|
export function createEnhancedCodeIntelligenceTools(workingDir) {
|
|
9
14
|
return [
|
|
10
15
|
{
|
|
11
16
|
name: 'analyze_code_complexity',
|
|
12
|
-
description: 'Analyze code complexity
|
|
17
|
+
description: 'Analyze code complexity across files, highlighting hotspots and risky symbols.',
|
|
13
18
|
parameters: {
|
|
14
19
|
type: 'object',
|
|
15
20
|
properties: {
|
|
16
21
|
path: {
|
|
17
22
|
type: 'string',
|
|
18
|
-
description: 'File or directory path to analyze (default:
|
|
23
|
+
description: 'File or directory path to analyze (default: working directory).',
|
|
19
24
|
},
|
|
20
25
|
maxFiles: {
|
|
21
26
|
type: 'number',
|
|
22
|
-
description: 'Maximum number of files to
|
|
27
|
+
description: 'Maximum number of files to scan (default: 50).',
|
|
23
28
|
},
|
|
24
29
|
},
|
|
25
30
|
additionalProperties: false,
|
|
26
31
|
},
|
|
27
32
|
handler: async (args) => {
|
|
28
|
-
const
|
|
33
|
+
const target = resolveTargetPath(workingDir, args['path'] ?? workingDir);
|
|
29
34
|
const maxFiles = args['maxFiles'] ?? 50;
|
|
30
|
-
return
|
|
35
|
+
return analyzeCodeComplexity(target, workingDir, maxFiles);
|
|
31
36
|
},
|
|
32
37
|
},
|
|
33
38
|
{
|
|
34
39
|
name: 'suggest_refactoring',
|
|
35
|
-
description: 'Generate
|
|
40
|
+
description: 'Generate refactoring suggestions with previews from the refactoring engine.',
|
|
36
41
|
parameters: {
|
|
37
42
|
type: 'object',
|
|
38
43
|
properties: {
|
|
39
44
|
path: {
|
|
40
45
|
type: 'string',
|
|
41
|
-
description: 'File or directory
|
|
46
|
+
description: 'File or directory to scan (default: working directory).',
|
|
42
47
|
},
|
|
43
48
|
priority: {
|
|
44
49
|
type: 'string',
|
|
45
50
|
enum: ['low', 'medium', 'high'],
|
|
46
|
-
description: '
|
|
51
|
+
description: 'Filter suggestions by impact priority.',
|
|
47
52
|
},
|
|
48
53
|
},
|
|
49
54
|
additionalProperties: false,
|
|
50
55
|
},
|
|
51
56
|
handler: async (args) => {
|
|
52
|
-
const
|
|
57
|
+
const target = resolveTargetPath(workingDir, args['path'] ?? workingDir);
|
|
53
58
|
const priority = args['priority'];
|
|
54
|
-
return
|
|
59
|
+
return suggestRefactoring(target, workingDir, priority);
|
|
55
60
|
},
|
|
56
61
|
},
|
|
57
62
|
{
|
|
58
63
|
name: 'auto_refactor_complexity',
|
|
59
|
-
description: '
|
|
64
|
+
description: 'Apply safe refactorings for complex code paths. Uses previews by default.',
|
|
60
65
|
parameters: {
|
|
61
66
|
type: 'object',
|
|
62
67
|
properties: {
|
|
63
68
|
path: {
|
|
64
69
|
type: 'string',
|
|
65
|
-
description: 'File
|
|
66
|
-
},
|
|
67
|
-
maxNestingDepth: {
|
|
68
|
-
type: 'number',
|
|
69
|
-
description: 'Maximum allowed nesting depth (default: 4).',
|
|
70
|
+
description: 'File or directory to refactor.',
|
|
70
71
|
},
|
|
71
72
|
preview: {
|
|
72
73
|
type: 'boolean',
|
|
73
|
-
description: '
|
|
74
|
+
description: 'If true, only show planned changes without writing files (default: true).',
|
|
74
75
|
},
|
|
75
76
|
},
|
|
76
77
|
required: ['path'],
|
|
77
78
|
additionalProperties: false,
|
|
78
79
|
},
|
|
79
80
|
handler: async (args) => {
|
|
80
|
-
const
|
|
81
|
-
const maxNestingDepth = args['maxNestingDepth'] ?? 4;
|
|
81
|
+
const target = resolveTargetPath(workingDir, args['path']);
|
|
82
82
|
const preview = args['preview'] ?? true;
|
|
83
|
-
return autoRefactorComplexity(
|
|
83
|
+
return autoRefactorComplexity(target, workingDir, preview);
|
|
84
84
|
},
|
|
85
85
|
},
|
|
86
86
|
{
|
|
87
87
|
name: 'improve_type_safety',
|
|
88
|
-
description: '
|
|
88
|
+
description: 'Find and optionally replace unsafe `any` usage with safer defaults.',
|
|
89
89
|
parameters: {
|
|
90
90
|
type: 'object',
|
|
91
91
|
properties: {
|
|
92
92
|
path: {
|
|
93
93
|
type: 'string',
|
|
94
|
-
description: 'File path to
|
|
94
|
+
description: 'File path to analyze for unsafe types.',
|
|
95
95
|
},
|
|
96
96
|
preview: {
|
|
97
97
|
type: 'boolean',
|
|
98
|
-
description: '
|
|
98
|
+
description: 'If true, only report findings; if false, applies safer replacements (default: true).',
|
|
99
99
|
},
|
|
100
100
|
},
|
|
101
101
|
required: ['path'],
|
|
102
102
|
additionalProperties: false,
|
|
103
103
|
},
|
|
104
104
|
handler: async (args) => {
|
|
105
|
-
const
|
|
105
|
+
const target = resolveTargetPath(workingDir, args['path']);
|
|
106
106
|
const preview = args['preview'] ?? true;
|
|
107
|
-
return improveTypeSafety(
|
|
107
|
+
return improveTypeSafety(target, workingDir, preview);
|
|
108
108
|
},
|
|
109
109
|
},
|
|
110
110
|
{
|
|
111
111
|
name: 'detect_code_smells',
|
|
112
|
-
description: 'Detect common code smells and anti-patterns
|
|
112
|
+
description: 'Detect common code smells and anti-patterns using the intelligence engine.',
|
|
113
113
|
parameters: {
|
|
114
114
|
type: 'object',
|
|
115
115
|
properties: {
|
|
116
116
|
path: {
|
|
117
117
|
type: 'string',
|
|
118
|
-
description: '
|
|
119
|
-
},
|
|
120
|
-
maxFiles: {
|
|
121
|
-
type: 'number',
|
|
122
|
-
description: 'Maximum number of files to analyze (default: 50).',
|
|
118
|
+
description: 'File or directory to scan (default: working directory).',
|
|
123
119
|
},
|
|
124
120
|
},
|
|
125
121
|
additionalProperties: false,
|
|
126
122
|
},
|
|
127
123
|
handler: async (args) => {
|
|
128
|
-
const
|
|
129
|
-
|
|
130
|
-
return detectCodeSmells(path, maxFiles);
|
|
124
|
+
const target = resolveTargetPath(workingDir, args['path'] ?? workingDir);
|
|
125
|
+
return detectCodeSmells(target, workingDir);
|
|
131
126
|
},
|
|
132
127
|
},
|
|
133
128
|
{
|
|
134
129
|
name: 'generate_code_quality_report',
|
|
135
|
-
description: 'Generate
|
|
130
|
+
description: 'Generate a quality report (issues, metrics, refactor hotspots) and return a condensed summary.',
|
|
136
131
|
parameters: {
|
|
137
132
|
type: 'object',
|
|
138
133
|
properties: {
|
|
139
134
|
path: {
|
|
140
135
|
type: 'string',
|
|
141
|
-
description: 'File or directory
|
|
136
|
+
description: 'File or directory to analyze (default: working directory).',
|
|
137
|
+
},
|
|
138
|
+
},
|
|
139
|
+
additionalProperties: false,
|
|
140
|
+
},
|
|
141
|
+
handler: async (args) => {
|
|
142
|
+
const target = resolveTargetPath(workingDir, args['path'] ?? workingDir);
|
|
143
|
+
return generateQualityReport(target, workingDir);
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
name: 'run_code_intelligence_suite',
|
|
148
|
+
description: 'Run the full code intelligence suite (analysis, safe auto-fixes, refactor suggestions, docs/tests generation).',
|
|
149
|
+
parameters: {
|
|
150
|
+
type: 'object',
|
|
151
|
+
properties: {
|
|
152
|
+
enableAutoFix: {
|
|
153
|
+
type: 'boolean',
|
|
154
|
+
description: 'Apply safe auto-fixes and refactorings (default: false).',
|
|
155
|
+
},
|
|
156
|
+
generateTests: {
|
|
157
|
+
type: 'boolean',
|
|
158
|
+
description: 'Generate test plans/files (default: true).',
|
|
159
|
+
},
|
|
160
|
+
generateDocs: {
|
|
161
|
+
type: 'boolean',
|
|
162
|
+
description: 'Generate documentation summaries (default: true).',
|
|
163
|
+
},
|
|
164
|
+
outputDir: {
|
|
165
|
+
type: 'string',
|
|
166
|
+
description: 'Custom output directory for reports (default: .intelligence under workingDir).',
|
|
142
167
|
},
|
|
143
168
|
},
|
|
144
169
|
additionalProperties: false,
|
|
145
170
|
},
|
|
146
171
|
handler: async (args) => {
|
|
147
|
-
const
|
|
148
|
-
|
|
172
|
+
const enableAutoFix = args['enableAutoFix'] === true;
|
|
173
|
+
const generateTests = args['generateTests'] !== false;
|
|
174
|
+
const generateDocs = args['generateDocs'] !== false;
|
|
175
|
+
const outputDir = typeof args['outputDir'] === 'string'
|
|
176
|
+
? resolveTargetPath(workingDir, args['outputDir'])
|
|
177
|
+
: undefined;
|
|
178
|
+
return runCodeIntelligenceSuite({
|
|
179
|
+
workingDir,
|
|
180
|
+
enableAutoFix,
|
|
181
|
+
generateTests,
|
|
182
|
+
generateDocs,
|
|
183
|
+
outputDir,
|
|
184
|
+
});
|
|
149
185
|
},
|
|
150
186
|
},
|
|
151
187
|
];
|
|
152
188
|
}
|
|
153
|
-
function
|
|
154
|
-
|
|
155
|
-
|
|
189
|
+
function resolveTargetPath(workingDir, targetPath) {
|
|
190
|
+
return targetPath.startsWith('/') ? targetPath : resolve(workingDir, targetPath);
|
|
191
|
+
}
|
|
192
|
+
function collectSourceFiles(target, maxFiles) {
|
|
193
|
+
const files = [];
|
|
194
|
+
const visit = (current) => {
|
|
195
|
+
if (files.length >= maxFiles) {
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
const stats = statSync(current);
|
|
199
|
+
if (stats.isFile()) {
|
|
200
|
+
if (SUPPORTED_EXTENSIONS.some((ext) => current.endsWith(ext))) {
|
|
201
|
+
files.push(current);
|
|
202
|
+
}
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
if (!stats.isDirectory()) {
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
const entries = readdirSync(current, { withFileTypes: true });
|
|
209
|
+
for (const entry of entries) {
|
|
210
|
+
if (files.length >= maxFiles) {
|
|
211
|
+
break;
|
|
212
|
+
}
|
|
213
|
+
if (entry.isDirectory() && IGNORED_DIRECTORIES.has(entry.name)) {
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
visit(join(current, entry.name));
|
|
217
|
+
}
|
|
218
|
+
};
|
|
219
|
+
if (existsSync(target)) {
|
|
220
|
+
visit(target);
|
|
156
221
|
}
|
|
157
|
-
return
|
|
222
|
+
return files;
|
|
158
223
|
}
|
|
159
|
-
function
|
|
224
|
+
function analyzeCodeComplexity(target, workingDir, maxFiles) {
|
|
225
|
+
if (!existsSync(target)) {
|
|
226
|
+
return `Error: path not found: ${target}`;
|
|
227
|
+
}
|
|
228
|
+
const files = collectSourceFiles(target, Math.max(1, maxFiles));
|
|
229
|
+
if (files.length === 0) {
|
|
230
|
+
return `No TypeScript/JavaScript files found under ${target}.`;
|
|
231
|
+
}
|
|
232
|
+
const hotspots = [];
|
|
233
|
+
let totalLines = 0;
|
|
234
|
+
let totalSymbols = 0;
|
|
235
|
+
let totalCyclomatic = 0;
|
|
236
|
+
for (const file of files) {
|
|
237
|
+
const content = readFileSync(file, 'utf-8');
|
|
238
|
+
const lines = content.split(/\r?\n/).length;
|
|
239
|
+
totalLines += lines;
|
|
240
|
+
const analysis = performAdvancedAstAnalysis(content, file);
|
|
241
|
+
totalSymbols += analysis.symbols.length;
|
|
242
|
+
totalCyclomatic += analysis.totalCyclomaticComplexity;
|
|
243
|
+
const worst = selectWorstSymbol(analysis.symbols);
|
|
244
|
+
if (worst) {
|
|
245
|
+
const span = worst.endLine - worst.startLine + 1;
|
|
246
|
+
const reasons = [];
|
|
247
|
+
if (worst.cyclomaticComplexity > 10) {
|
|
248
|
+
reasons.push(`high complexity (${worst.cyclomaticComplexity})`);
|
|
249
|
+
}
|
|
250
|
+
if (worst.statementCount > 50) {
|
|
251
|
+
reasons.push(`long body (${worst.statementCount} statements)`);
|
|
252
|
+
}
|
|
253
|
+
if (span > 120) {
|
|
254
|
+
reasons.push(`spans ${span} lines`);
|
|
255
|
+
}
|
|
256
|
+
hotspots.push({ file, symbol: worst, span, reasons });
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
hotspots.sort((a, b) => {
|
|
260
|
+
if (b.symbol.cyclomaticComplexity !== a.symbol.cyclomaticComplexity) {
|
|
261
|
+
return b.symbol.cyclomaticComplexity - a.symbol.cyclomaticComplexity;
|
|
262
|
+
}
|
|
263
|
+
return b.symbol.statementCount - a.symbol.statementCount;
|
|
264
|
+
});
|
|
265
|
+
const averageCyclomatic = totalSymbols === 0 ? 0 : Math.round((totalCyclomatic / totalSymbols) * 10) / 10;
|
|
160
266
|
const output = [];
|
|
161
267
|
output.push('# Code Complexity Analysis');
|
|
268
|
+
output.push(`Files scanned: ${files.length} (limit ${maxFiles})`);
|
|
269
|
+
output.push(`Lines of code: ${totalLines.toLocaleString()}`);
|
|
270
|
+
output.push(`Average cyclomatic complexity per symbol: ${averageCyclomatic}`);
|
|
162
271
|
output.push('');
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
272
|
+
output.push('## Top Complexity Hotspots');
|
|
273
|
+
const topHotspots = hotspots.slice(0, 10);
|
|
274
|
+
if (topHotspots.length === 0) {
|
|
275
|
+
output.push('No complex symbols detected.');
|
|
276
|
+
}
|
|
277
|
+
else {
|
|
278
|
+
topHotspots.forEach((hotspot, index) => {
|
|
279
|
+
output.push(`${index + 1}. ${relative(workingDir, hotspot.file)} :: ${hotspot.symbol.name} (lines ${hotspot.symbol.startLine}-${hotspot.symbol.endLine})`);
|
|
280
|
+
output.push(` - CC: ${hotspot.symbol.cyclomaticComplexity}, statements: ${hotspot.symbol.statementCount}, span: ${hotspot.span} lines`);
|
|
281
|
+
if (hotspot.reasons.length > 0) {
|
|
282
|
+
output.push(` - Reasons: ${hotspot.reasons.join(', ')}`);
|
|
283
|
+
}
|
|
284
|
+
});
|
|
285
|
+
}
|
|
173
286
|
output.push('');
|
|
174
|
-
output.push('
|
|
287
|
+
output.push('Use `suggest_refactoring` to get concrete improvement steps or `auto_refactor_complexity` to apply safe changes.');
|
|
175
288
|
return output.join('\n');
|
|
176
289
|
}
|
|
177
|
-
function
|
|
290
|
+
function selectWorstSymbol(symbols) {
|
|
291
|
+
if (!symbols.length) {
|
|
292
|
+
return null;
|
|
293
|
+
}
|
|
294
|
+
const initial = symbols[0];
|
|
295
|
+
return symbols.reduce((worst, current) => {
|
|
296
|
+
const score = current.cyclomaticComplexity * 2 + current.statementCount;
|
|
297
|
+
const worstScore = worst.cyclomaticComplexity * 2 + worst.statementCount;
|
|
298
|
+
return score > worstScore ? current : worst;
|
|
299
|
+
}, initial);
|
|
300
|
+
}
|
|
301
|
+
function suggestRefactoring(target, workingDir, priority) {
|
|
302
|
+
const engine = new RefactoringEngine(workingDir);
|
|
303
|
+
const opportunities = engine.findOpportunities(target);
|
|
304
|
+
const filtered = priority ? opportunities.filter((o) => mapImpactToPriority(o.impact) === priority) : opportunities;
|
|
305
|
+
if (filtered.length === 0) {
|
|
306
|
+
return 'No refactoring opportunities detected for the specified scope.';
|
|
307
|
+
}
|
|
178
308
|
const output = [];
|
|
179
309
|
output.push('# Refactoring Suggestions');
|
|
180
|
-
output.push('');
|
|
181
|
-
// Implementation would analyze code and generate specific suggestions
|
|
182
|
-
output.push('🔧 Refactoring suggestions would include:');
|
|
183
|
-
output.push('- Breaking down complex functions');
|
|
184
|
-
output.push('- Reducing nesting depth');
|
|
185
|
-
output.push('- Replacing `any` types with proper types');
|
|
186
|
-
output.push('- Improving function naming');
|
|
187
|
-
output.push('- Removing code duplication');
|
|
188
|
-
output.push('');
|
|
189
310
|
if (priority) {
|
|
190
|
-
output.push(
|
|
311
|
+
output.push(`Filtered by priority: ${priority}`);
|
|
191
312
|
}
|
|
192
313
|
output.push('');
|
|
193
|
-
|
|
314
|
+
filtered.slice(0, 20).forEach((opp, index) => {
|
|
315
|
+
const preview = opp.preview
|
|
316
|
+
? `${opp.preview.before.trim().slice(0, 80)} → ${opp.preview.after.trim().slice(0, 80)}`
|
|
317
|
+
: 'Preview unavailable';
|
|
318
|
+
output.push(`${index + 1}. ${opp.type} (${opp.impact}/${opp.risk}) - ${opp.description}`);
|
|
319
|
+
output.push(` • ${opp.file}:${opp.line}`);
|
|
320
|
+
output.push(` • ${preview}`);
|
|
321
|
+
});
|
|
322
|
+
if (filtered.length > 20) {
|
|
323
|
+
output.push('');
|
|
324
|
+
output.push(`…${filtered.length - 20} additional opportunities not shown.`);
|
|
325
|
+
}
|
|
326
|
+
output.push('');
|
|
327
|
+
output.push('Run `auto_refactor_complexity` to apply safe changes automatically.');
|
|
194
328
|
return output.join('\n');
|
|
195
329
|
}
|
|
196
|
-
function
|
|
197
|
-
|
|
198
|
-
|
|
330
|
+
function mapImpactToPriority(impact) {
|
|
331
|
+
return impact;
|
|
332
|
+
}
|
|
333
|
+
function autoRefactorComplexity(target, workingDir, preview) {
|
|
334
|
+
if (!existsSync(target)) {
|
|
335
|
+
return `Error: path not found: ${target}`;
|
|
199
336
|
}
|
|
200
|
-
const
|
|
201
|
-
const
|
|
202
|
-
const
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
337
|
+
const engine = new RefactoringEngine(workingDir);
|
|
338
|
+
const opportunities = engine.findOpportunities(target);
|
|
339
|
+
const safe = opportunities.filter((o) => o.risk === 'safe');
|
|
340
|
+
if (safe.length === 0) {
|
|
341
|
+
return 'No safe refactorings available to apply.';
|
|
342
|
+
}
|
|
343
|
+
if (preview) {
|
|
344
|
+
const output = [];
|
|
345
|
+
output.push('# Preview: Safe Refactorings');
|
|
346
|
+
safe.slice(0, 15).forEach((opp, index) => {
|
|
347
|
+
output.push(`${index + 1}. ${opp.type} :: ${opp.file}:${opp.line} (${opp.description})`);
|
|
348
|
+
});
|
|
349
|
+
if (safe.length > 15) {
|
|
350
|
+
output.push(`…${safe.length - 15} additional safe refactorings not shown.`);
|
|
351
|
+
}
|
|
352
|
+
output.push('');
|
|
353
|
+
output.push('Run again with `preview: false` to apply these changes.');
|
|
214
354
|
return output.join('\n');
|
|
215
355
|
}
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
356
|
+
const result = engine.applySafeRefactorings(safe);
|
|
357
|
+
const output = [];
|
|
358
|
+
output.push('# Applied Safe Refactorings');
|
|
359
|
+
output.push(`Files modified: ${result.filesModified.length}`);
|
|
360
|
+
result.changes.forEach((change, index) => {
|
|
361
|
+
output.push(`${index + 1}. ${change.file} - ${change.description} (${change.linesChanged} lines changed)`);
|
|
219
362
|
});
|
|
220
|
-
if (
|
|
363
|
+
if (result.errors.length > 0) {
|
|
221
364
|
output.push('');
|
|
222
|
-
output.push('
|
|
365
|
+
output.push('Errors:');
|
|
366
|
+
result.errors.forEach((err) => output.push(`- ${err}`));
|
|
223
367
|
}
|
|
224
368
|
return output.join('\n');
|
|
225
369
|
}
|
|
226
|
-
function improveTypeSafety(
|
|
227
|
-
if (!existsSync(
|
|
228
|
-
return `Error:
|
|
370
|
+
function improveTypeSafety(target, workingDir, preview) {
|
|
371
|
+
if (!existsSync(target)) {
|
|
372
|
+
return `Error: file not found: ${target}`;
|
|
229
373
|
}
|
|
230
|
-
const content = readFileSync(
|
|
231
|
-
const
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
output.push(`📁 File: ${relative(workingDir, filePath)}`);
|
|
235
|
-
output.push(`👁️ Preview mode: ${preview ? 'ON' : 'OFF'}`);
|
|
236
|
-
output.push('');
|
|
237
|
-
// Count any types
|
|
238
|
-
const anyCount = (content.match(/\bany\b/g) || []).length;
|
|
239
|
-
output.push(`🔍 Found ${anyCount} instances of 'any' type`);
|
|
240
|
-
if (anyCount === 0) {
|
|
241
|
-
output.push('✅ No type safety issues found.');
|
|
242
|
-
return output.join('\n');
|
|
374
|
+
const content = readFileSync(target, 'utf-8');
|
|
375
|
+
const occurrences = findAnyOccurrences(content);
|
|
376
|
+
if (occurrences.length === 0) {
|
|
377
|
+
return 'No unsafe `any` usage detected.';
|
|
243
378
|
}
|
|
244
|
-
output.push('');
|
|
245
|
-
output.push('## Type Safety Issues');
|
|
246
|
-
output.push('- Replace `any` with specific types');
|
|
247
|
-
output.push('- Add proper interface definitions');
|
|
248
|
-
output.push('- Improve function return types');
|
|
249
|
-
output.push('- Add parameter types');
|
|
250
379
|
if (preview) {
|
|
380
|
+
const output = [];
|
|
381
|
+
output.push('# Type Safety Findings');
|
|
382
|
+
occurrences.slice(0, 20).forEach((occurrence, index) => {
|
|
383
|
+
output.push(`${index + 1}. line ${occurrence.line} → ${occurrence.snippet}`);
|
|
384
|
+
});
|
|
385
|
+
if (occurrences.length > 20) {
|
|
386
|
+
output.push(`…${occurrences.length - 20} additional occurrences not shown.`);
|
|
387
|
+
}
|
|
251
388
|
output.push('');
|
|
252
|
-
output.push('
|
|
389
|
+
output.push('Run with `preview: false` to replace `any` with `unknown` in-place.');
|
|
390
|
+
return output.join('\n');
|
|
391
|
+
}
|
|
392
|
+
let updated = content;
|
|
393
|
+
const replacements = [
|
|
394
|
+
{ pattern: /:\s*any\b/g, replacement: ': unknown' },
|
|
395
|
+
{ pattern: /\bas any\b/g, replacement: ' as unknown' },
|
|
396
|
+
{ pattern: /<any>/g, replacement: '<unknown>' },
|
|
397
|
+
];
|
|
398
|
+
replacements.forEach(({ pattern, replacement }) => {
|
|
399
|
+
updated = updated.replace(pattern, replacement);
|
|
400
|
+
});
|
|
401
|
+
if (updated === content) {
|
|
402
|
+
return 'No replaceable `any` tokens found after analysis.';
|
|
253
403
|
}
|
|
404
|
+
writeFileSync(target, updated, 'utf-8');
|
|
405
|
+
const output = [];
|
|
406
|
+
output.push('# Type Safety Applied');
|
|
407
|
+
output.push(`File updated: ${relative(workingDir, target)}`);
|
|
408
|
+
output.push(`Occurrences replaced: ${occurrences.length}`);
|
|
409
|
+
output.push('Re-run type checking to validate changes.');
|
|
254
410
|
return output.join('\n');
|
|
255
411
|
}
|
|
256
|
-
function
|
|
257
|
-
const
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
const
|
|
263
|
-
const
|
|
264
|
-
|
|
265
|
-
return [basePath];
|
|
266
|
-
}
|
|
267
|
-
if (stats.isDirectory()) {
|
|
268
|
-
const scanDir = (dir) => {
|
|
269
|
-
if (files.length >= maxFiles)
|
|
270
|
-
return;
|
|
271
|
-
try {
|
|
272
|
-
const entries = readdirSync(dir, { withFileTypes: true });
|
|
273
|
-
for (const entry of entries) {
|
|
274
|
-
if (files.length >= maxFiles)
|
|
275
|
-
break;
|
|
276
|
-
const fullPath = join(dir, entry.name);
|
|
277
|
-
if (entry.isDirectory() && !entry.name.startsWith('.') && entry.name !== 'node_modules' && entry.name !== 'dist') {
|
|
278
|
-
scanDir(fullPath);
|
|
279
|
-
}
|
|
280
|
-
else if (entry.isFile() && (entry.name.endsWith('.ts') || entry.name.endsWith('.js') || entry.name.endsWith('.tsx') || entry.name.endsWith('.jsx'))) {
|
|
281
|
-
files.push(fullPath);
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
catch {
|
|
286
|
-
// Ignore permission errors
|
|
287
|
-
}
|
|
288
|
-
};
|
|
289
|
-
scanDir(basePath);
|
|
290
|
-
}
|
|
412
|
+
function findAnyOccurrences(content) {
|
|
413
|
+
const regex = /\bany\b/g;
|
|
414
|
+
const occurrences = [];
|
|
415
|
+
let match;
|
|
416
|
+
while ((match = regex.exec(content))) {
|
|
417
|
+
const before = content.slice(0, match.index);
|
|
418
|
+
const line = before.split(/\r?\n/).length;
|
|
419
|
+
const lineText = content.split(/\r?\n/)[line - 1] ?? '';
|
|
420
|
+
occurrences.push({ line, snippet: lineText.trim().slice(0, 120) });
|
|
291
421
|
}
|
|
292
|
-
return
|
|
422
|
+
return occurrences;
|
|
293
423
|
}
|
|
294
|
-
function detectCodeSmells(
|
|
424
|
+
async function detectCodeSmells(target, workingDir) {
|
|
425
|
+
if (!existsSync(target)) {
|
|
426
|
+
return `Error: path not found: ${target}`;
|
|
427
|
+
}
|
|
428
|
+
const engine = new CodeIntelligenceEngine(workingDir);
|
|
429
|
+
const result = await engine.analyze(target);
|
|
430
|
+
const smells = result.issues.filter((issue) => ['complexity', 'duplication', 'maintainability', 'bug', 'performance'].includes(issue.type));
|
|
431
|
+
if (smells.length === 0) {
|
|
432
|
+
return 'No code smells detected.';
|
|
433
|
+
}
|
|
434
|
+
const severityOrder = { critical: 0, high: 1, medium: 2, low: 3, info: 4 };
|
|
435
|
+
smells.sort((a, b) => (severityOrder[a.severity] ?? 5) - (severityOrder[b.severity] ?? 5));
|
|
295
436
|
const output = [];
|
|
296
|
-
output.push('# Code
|
|
437
|
+
output.push('# Code Smells');
|
|
438
|
+
output.push(`Total smells: ${smells.length}`);
|
|
297
439
|
output.push('');
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
{
|
|
301
|
-
|
|
302
|
-
pattern: /function\s+\w+\s*\([^)]*\)\s*\{[\s\S]{200,}/g,
|
|
303
|
-
description: 'Methods longer than 200 characters suggest they do too much',
|
|
304
|
-
fix: 'Extract smaller methods with single responsibilities'
|
|
305
|
-
},
|
|
306
|
-
{
|
|
307
|
-
name: 'Large Class',
|
|
308
|
-
pattern: /class\s+\w+\s*\{[\s\S]{500,}/g,
|
|
309
|
-
description: 'Classes with excessive lines violate single responsibility principle',
|
|
310
|
-
fix: 'Split into smaller, focused classes'
|
|
311
|
-
},
|
|
312
|
-
{
|
|
313
|
-
name: 'Primitive Obsession',
|
|
314
|
-
pattern: /(?:let|const|var)\s+\w+\s*:\s*(string|number|boolean)\b/g,
|
|
315
|
-
description: 'Overuse of primitives instead of domain-specific types',
|
|
316
|
-
fix: 'Create value objects or domain-specific types'
|
|
317
|
-
},
|
|
318
|
-
{
|
|
319
|
-
name: 'Data Clumps',
|
|
320
|
-
pattern: /(?:\w+,\s*){3,}\w+/g,
|
|
321
|
-
description: 'Groups of data items that appear together frequently',
|
|
322
|
-
fix: 'Extract into parameter objects or data classes'
|
|
323
|
-
},
|
|
324
|
-
{
|
|
325
|
-
name: 'Feature Envy',
|
|
326
|
-
pattern: /this\.\w+\.\w+/g,
|
|
327
|
-
description: 'Method uses more features of another class than its own',
|
|
328
|
-
fix: 'Move method to the class it envies'
|
|
329
|
-
},
|
|
330
|
-
{
|
|
331
|
-
name: 'Inappropriate Intimacy',
|
|
332
|
-
pattern: /private\s+\w+\s*:\s*\w+/g,
|
|
333
|
-
description: 'Classes know too much about each other\'s internals',
|
|
334
|
-
fix: 'Reduce coupling through interfaces or mediators'
|
|
335
|
-
},
|
|
336
|
-
{
|
|
337
|
-
name: 'Message Chains',
|
|
338
|
-
pattern: /\.\w+\(\)\.\w+\(\)\.\w+\(\)/g,
|
|
339
|
-
description: 'Long chains of method calls indicate tight coupling',
|
|
340
|
-
fix: 'Hide delegate or extract intermediate object'
|
|
341
|
-
},
|
|
342
|
-
{
|
|
343
|
-
name: 'Shotgun Surgery',
|
|
344
|
-
pattern: /\/\/\s*TODO.*change|FIXME.*multiple/i,
|
|
345
|
-
description: 'Single change requires modifications in many places',
|
|
346
|
-
fix: 'Move related behavior into single class'
|
|
440
|
+
smells.slice(0, 20).forEach((issue, index) => {
|
|
441
|
+
output.push(`${index + 1}. [${issue.severity}] ${issue.file}:${issue.line ?? '?'} - ${issue.message}`);
|
|
442
|
+
if (issue.suggestion) {
|
|
443
|
+
output.push(` → ${issue.suggestion}`);
|
|
347
444
|
}
|
|
348
|
-
|
|
349
|
-
|
|
445
|
+
});
|
|
446
|
+
if (smells.length > 20) {
|
|
447
|
+
output.push(`…${smells.length - 20} additional smells not shown.`);
|
|
448
|
+
}
|
|
449
|
+
return output.join('\n');
|
|
450
|
+
}
|
|
451
|
+
async function generateQualityReport(target, workingDir) {
|
|
452
|
+
const engine = new CodeIntelligenceEngine(workingDir);
|
|
453
|
+
const result = await engine.analyze(target);
|
|
454
|
+
const refEngine = new RefactoringEngine(workingDir);
|
|
455
|
+
const refOps = refEngine.findOpportunities(target).slice(0, 5);
|
|
456
|
+
const output = [];
|
|
457
|
+
output.push('# Code Quality Report');
|
|
458
|
+
output.push(`Files analyzed: ${result.files}`);
|
|
459
|
+
output.push(`Lines of code: ${result.linesOfCode.toLocaleString()}`);
|
|
460
|
+
output.push('');
|
|
461
|
+
output.push('## Metrics (0-100, higher is better)');
|
|
462
|
+
output.push(`- Complexity: ${Math.round(result.metrics.complexity)}`);
|
|
463
|
+
output.push(`- Maintainability: ${Math.round(result.metrics.maintainability)}`);
|
|
464
|
+
output.push(`- Testability: ${Math.round(result.metrics.testability)}`);
|
|
465
|
+
output.push(`- Duplication: ${Math.round(result.metrics.duplication)}`);
|
|
466
|
+
output.push(`- Documentation: ${Math.round(result.metrics.documentation)}`);
|
|
350
467
|
output.push('');
|
|
351
|
-
|
|
352
|
-
const
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
const
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
468
|
+
output.push('## Top Issues');
|
|
469
|
+
const topIssues = result.issues
|
|
470
|
+
.slice()
|
|
471
|
+
.sort((a, b) => {
|
|
472
|
+
const order = { critical: 0, high: 1, medium: 2, low: 3, info: 4 };
|
|
473
|
+
return (order[a.severity] ?? 5) - (order[b.severity] ?? 5);
|
|
474
|
+
})
|
|
475
|
+
.slice(0, 10);
|
|
476
|
+
if (topIssues.length === 0) {
|
|
477
|
+
output.push('No issues detected.');
|
|
478
|
+
}
|
|
479
|
+
else {
|
|
480
|
+
topIssues.forEach((issue, index) => {
|
|
481
|
+
output.push(`${index + 1}. [${issue.severity}] ${issue.file}:${issue.line ?? '?'} - ${issue.message}`);
|
|
482
|
+
if (issue.suggestion) {
|
|
483
|
+
output.push(` → ${issue.suggestion}`);
|
|
361
484
|
}
|
|
362
485
|
});
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
});
|
|
369
|
-
if (totalSmells === 0) {
|
|
370
|
-
output.push('✅ No significant code smells detected.');
|
|
371
|
-
output.push('');
|
|
372
|
-
output.push('The codebase appears to follow good design principles.');
|
|
486
|
+
}
|
|
487
|
+
output.push('');
|
|
488
|
+
output.push('## Refactor Hotspots');
|
|
489
|
+
if (refOps.length === 0) {
|
|
490
|
+
output.push('No refactor hotspots identified.');
|
|
373
491
|
}
|
|
374
492
|
else {
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
output.push(`- **Files analyzed**: ${files.length}`);
|
|
378
|
-
output.push('');
|
|
379
|
-
output.push('## Recommended Refactoring Actions');
|
|
380
|
-
output.push('');
|
|
381
|
-
codeSmells.forEach(smell => {
|
|
382
|
-
output.push(`- **${smell.name}**: ${smell.fix}`);
|
|
493
|
+
refOps.forEach((opp, index) => {
|
|
494
|
+
output.push(`${index + 1}. ${opp.file}:${opp.line} - ${opp.description} (${opp.impact}/${opp.risk})`);
|
|
383
495
|
});
|
|
384
496
|
}
|
|
385
497
|
output.push('');
|
|
386
|
-
output.push('
|
|
387
|
-
output.push('💡 Use `auto_refactor_complexity` for automated refactoring.');
|
|
498
|
+
output.push('Use `run_code_intelligence_suite` for a full analysis + optional auto-fixes and documentation generation.');
|
|
388
499
|
return output.join('\n');
|
|
389
500
|
}
|
|
390
|
-
function
|
|
501
|
+
async function runCodeIntelligenceSuite(options) {
|
|
502
|
+
const suite = new CodeIntelligenceSuite({
|
|
503
|
+
workingDir: options.workingDir,
|
|
504
|
+
enableAutoFix: options.enableAutoFix,
|
|
505
|
+
generateTests: options.generateTests,
|
|
506
|
+
generateDocs: options.generateDocs,
|
|
507
|
+
outputDir: options.outputDir ?? join(options.workingDir, '.intelligence'),
|
|
508
|
+
});
|
|
509
|
+
const report = await suite.runFullAnalysis();
|
|
391
510
|
const output = [];
|
|
392
|
-
output.push('#
|
|
511
|
+
output.push('# Code Intelligence Suite');
|
|
512
|
+
output.push(`Analysis completed at ${report.timestamp}`);
|
|
513
|
+
output.push(`Issues found: ${report.analysis.issues.length}`);
|
|
514
|
+
output.push(`Refactoring opportunities: ${report.refactoring.length}`);
|
|
515
|
+
output.push(`Auto-fix enabled: ${options.enableAutoFix ? 'yes' : 'no'}`);
|
|
393
516
|
output.push('');
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
517
|
+
const actions = report.actions ?? [];
|
|
518
|
+
if (actions.length > 0) {
|
|
519
|
+
output.push('## Actions Taken');
|
|
520
|
+
actions.forEach((action, index) => {
|
|
521
|
+
output.push(`${index + 1}. [${action.type}] ${action.description} (${action.success ? 'success' : 'partial'})`);
|
|
522
|
+
if (action.filesAffected.length > 0) {
|
|
523
|
+
output.push(` Files: ${action.filesAffected.join(', ')}`);
|
|
524
|
+
}
|
|
525
|
+
});
|
|
526
|
+
output.push('');
|
|
527
|
+
}
|
|
528
|
+
if (report.documentation) {
|
|
529
|
+
output.push('Documentation generated: API.md and API-reference.md');
|
|
530
|
+
}
|
|
531
|
+
if (report.tests) {
|
|
532
|
+
output.push('Tests generated: see .intelligence/generated-tests');
|
|
533
|
+
}
|
|
534
|
+
const dest = options.outputDir ?? join(options.workingDir, '.intelligence');
|
|
409
535
|
output.push('');
|
|
410
|
-
output.push(
|
|
411
|
-
output.push('-
|
|
412
|
-
output.push('- `suggest_refactoring` for improvement suggestions');
|
|
413
|
-
output.push('- `auto_refactor_complexity` for automated refactoring');
|
|
414
|
-
output.push('- `improve_type_safety` for type improvements');
|
|
415
|
-
output.push('- `detect_code_smells` for anti-pattern detection');
|
|
536
|
+
output.push(`Artifacts written to: ${dest}`);
|
|
537
|
+
output.push('Re-run this tool to keep reports fresh after additional edits.');
|
|
416
538
|
return output.join('\n');
|
|
417
539
|
}
|
|
418
540
|
//# sourceMappingURL=enhancedCodeIntelligenceTools.js.map
|