@aiready/cli 0.7.18 → 0.7.20
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/.turbo/turbo-build.log +10 -10
- package/.turbo/turbo-test.log +6 -6
- package/dist/{chunk-AGAMURT4.mjs → chunk-2LXCBVPN.mjs} +5 -5
- package/dist/chunk-3SG2GLFJ.mjs +118 -0
- package/dist/chunk-DEZVFBPS.mjs +111 -0
- package/dist/chunk-OVELUOM6.mjs +112 -0
- package/dist/{chunk-Z3TLCO6U.mjs → chunk-QXQP6BMO.mjs} +17 -8
- package/dist/cli.js +202 -115
- package/dist/cli.mjs +193 -85
- package/dist/index.d.mts +6 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.js +15 -7
- package/dist/index.mjs +1 -1
- package/package.json +5 -5
- package/src/cli.ts +240 -111
- package/src/index.ts +22 -7
- package/dist/chunk-KZKXZKES.mjs +0 -54
- package/dist/chunk-NWEWXOUT.mjs +0 -74
- package/dist/chunk-S6JWNLN7.mjs +0 -53
- package/dist/chunk-VOB7SA3E.mjs +0 -71
package/src/cli.ts
CHANGED
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
calculateOverallScore,
|
|
15
15
|
formatScore,
|
|
16
16
|
formatToolScore,
|
|
17
|
+
getRating,
|
|
17
18
|
getRatingDisplay,
|
|
18
19
|
parseWeightString,
|
|
19
20
|
type AIReadyConfig,
|
|
@@ -67,142 +68,270 @@ program
|
|
|
67
68
|
exclude: options.exclude?.split(','),
|
|
68
69
|
}) as any;
|
|
69
70
|
|
|
71
|
+
|
|
70
72
|
// Apply smart defaults for pattern detection if patterns tool is enabled
|
|
71
73
|
let finalOptions = { ...baseOptions };
|
|
72
74
|
if (baseOptions.tools.includes('patterns')) {
|
|
73
75
|
const { getSmartDefaults } = await import('@aiready/pattern-detect');
|
|
74
76
|
const patternSmartDefaults = await getSmartDefaults(directory, baseOptions);
|
|
75
|
-
|
|
77
|
+
// Merge deeply to preserve nested config
|
|
78
|
+
finalOptions = { ...patternSmartDefaults, ...finalOptions, ...baseOptions };
|
|
76
79
|
}
|
|
77
80
|
|
|
78
|
-
|
|
81
|
+
// Print pre-run summary with expanded settings (truncate long arrays)
|
|
82
|
+
console.log(chalk.cyan('\n=== AIReady Run Preview ==='));
|
|
83
|
+
console.log(chalk.white('Tools to run:'), (finalOptions.tools || ['patterns', 'context', 'consistency']).join(', '));
|
|
84
|
+
console.log(chalk.white('Will use settings from config and defaults.'));
|
|
85
|
+
|
|
86
|
+
const truncate = (arr: any[] | undefined, cap = 8) => {
|
|
87
|
+
if (!Array.isArray(arr)) return '';
|
|
88
|
+
const shown = arr.slice(0, cap).map((v) => String(v));
|
|
89
|
+
const more = arr.length - shown.length;
|
|
90
|
+
return shown.join(', ') + (more > 0 ? `, ... (+${more} more)` : '');
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
// Common top-level settings
|
|
94
|
+
console.log(chalk.white('\nGeneral settings:'));
|
|
95
|
+
if (finalOptions.rootDir) console.log(` rootDir: ${chalk.bold(String(finalOptions.rootDir))}`);
|
|
96
|
+
if (finalOptions.include) console.log(` include: ${chalk.bold(truncate(finalOptions.include, 6))}`);
|
|
97
|
+
if (finalOptions.exclude) console.log(` exclude: ${chalk.bold(truncate(finalOptions.exclude, 6))}`);
|
|
98
|
+
|
|
99
|
+
if (finalOptions['pattern-detect'] || finalOptions.minSimilarity) {
|
|
100
|
+
const pd = finalOptions['pattern-detect'] || {
|
|
101
|
+
minSimilarity: finalOptions.minSimilarity,
|
|
102
|
+
minLines: finalOptions.minLines,
|
|
103
|
+
approx: finalOptions.approx,
|
|
104
|
+
minSharedTokens: finalOptions.minSharedTokens,
|
|
105
|
+
maxCandidatesPerBlock: finalOptions.maxCandidatesPerBlock,
|
|
106
|
+
batchSize: finalOptions.batchSize,
|
|
107
|
+
streamResults: finalOptions.streamResults,
|
|
108
|
+
severity: (finalOptions as any).severity,
|
|
109
|
+
includeTests: (finalOptions as any).includeTests,
|
|
110
|
+
};
|
|
111
|
+
console.log(chalk.white('\nPattern-detect settings:'));
|
|
112
|
+
console.log(` minSimilarity: ${chalk.bold(pd.minSimilarity ?? 'default')}`);
|
|
113
|
+
console.log(` minLines: ${chalk.bold(pd.minLines ?? 'default')}`);
|
|
114
|
+
if (pd.approx !== undefined) console.log(` approx: ${chalk.bold(String(pd.approx))}`);
|
|
115
|
+
if (pd.minSharedTokens !== undefined) console.log(` minSharedTokens: ${chalk.bold(String(pd.minSharedTokens))}`);
|
|
116
|
+
if (pd.maxCandidatesPerBlock !== undefined) console.log(` maxCandidatesPerBlock: ${chalk.bold(String(pd.maxCandidatesPerBlock))}`);
|
|
117
|
+
if (pd.batchSize !== undefined) console.log(` batchSize: ${chalk.bold(String(pd.batchSize))}`);
|
|
118
|
+
if (pd.streamResults !== undefined) console.log(` streamResults: ${chalk.bold(String(pd.streamResults))}`);
|
|
119
|
+
if (pd.severity !== undefined) console.log(` severity: ${chalk.bold(String(pd.severity))}`);
|
|
120
|
+
if (pd.includeTests !== undefined) console.log(` includeTests: ${chalk.bold(String(pd.includeTests))}`);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (finalOptions['context-analyzer'] || finalOptions.maxDepth) {
|
|
124
|
+
const ca = finalOptions['context-analyzer'] || {
|
|
125
|
+
maxDepth: finalOptions.maxDepth,
|
|
126
|
+
maxContextBudget: finalOptions.maxContextBudget,
|
|
127
|
+
minCohesion: (finalOptions as any).minCohesion,
|
|
128
|
+
maxFragmentation: (finalOptions as any).maxFragmentation,
|
|
129
|
+
includeNodeModules: (finalOptions as any).includeNodeModules,
|
|
130
|
+
};
|
|
131
|
+
console.log(chalk.white('\nContext-analyzer settings:'));
|
|
132
|
+
console.log(` maxDepth: ${chalk.bold(ca.maxDepth ?? 'default')}`);
|
|
133
|
+
console.log(` maxContextBudget: ${chalk.bold(ca.maxContextBudget ?? 'default')}`);
|
|
134
|
+
if (ca.minCohesion !== undefined) console.log(` minCohesion: ${chalk.bold(String(ca.minCohesion))}`);
|
|
135
|
+
if (ca.maxFragmentation !== undefined) console.log(` maxFragmentation: ${chalk.bold(String(ca.maxFragmentation))}`);
|
|
136
|
+
if (ca.includeNodeModules !== undefined) console.log(` includeNodeModules: ${chalk.bold(String(ca.includeNodeModules))}`);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (finalOptions.consistency) {
|
|
140
|
+
const c = finalOptions.consistency;
|
|
141
|
+
console.log(chalk.white('\nConsistency settings:'));
|
|
142
|
+
console.log(` checkNaming: ${chalk.bold(String(c.checkNaming ?? true))}`);
|
|
143
|
+
console.log(` checkPatterns: ${chalk.bold(String(c.checkPatterns ?? true))}`);
|
|
144
|
+
console.log(` checkArchitecture: ${chalk.bold(String(c.checkArchitecture ?? false))}`);
|
|
145
|
+
if (c.minSeverity) console.log(` minSeverity: ${chalk.bold(c.minSeverity)}`);
|
|
146
|
+
if (c.acceptedAbbreviations) console.log(` acceptedAbbreviations: ${chalk.bold(truncate(c.acceptedAbbreviations, 8))}`);
|
|
147
|
+
if (c.shortWords) console.log(` shortWords: ${chalk.bold(truncate(c.shortWords, 8))}`);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
console.log(chalk.white('\nStarting analysis...'));
|
|
151
|
+
|
|
152
|
+
// Progress callback to surface per-tool output as each tool finishes
|
|
153
|
+
const progressCallback = (event: { tool: string; data: any }) => {
|
|
154
|
+
console.log(chalk.cyan(`\n--- ${event.tool.toUpperCase()} RESULTS ---`));
|
|
155
|
+
try {
|
|
156
|
+
if (event.tool === 'patterns') {
|
|
157
|
+
const pr = event.data as any;
|
|
158
|
+
console.log(` Duplicate patterns: ${chalk.bold(String(pr.duplicates?.length || 0))}`);
|
|
159
|
+
console.log(` Files with pattern issues: ${chalk.bold(String(pr.results?.length || 0))}`);
|
|
160
|
+
// show top duplicate summaries
|
|
161
|
+
if (pr.duplicates && pr.duplicates.length > 0) {
|
|
162
|
+
pr.duplicates.slice(0, 5).forEach((d: any, i: number) => {
|
|
163
|
+
console.log(` ${i + 1}. ${d.file1.split('/').pop()} ↔ ${d.file2.split('/').pop()} (sim=${(d.similarity * 100).toFixed(1)}%)`);
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// show top files with pattern issues (sorted by issue count desc)
|
|
168
|
+
if (pr.results && pr.results.length > 0) {
|
|
169
|
+
console.log(` Top files with pattern issues:`);
|
|
170
|
+
const sortedByIssues = [...pr.results].sort((a: any, b: any) => (b.issues?.length || 0) - (a.issues?.length || 0));
|
|
171
|
+
sortedByIssues.slice(0, 5).forEach((r: any, i: number) => {
|
|
172
|
+
console.log(` ${i + 1}. ${r.fileName.split('/').pop()} - ${r.issues.length} issue(s)`);
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Grouping and clusters summary (if available) — show after detailed findings
|
|
177
|
+
if (pr.groups && pr.groups.length >= 0) {
|
|
178
|
+
console.log(` ✅ Grouped ${chalk.bold(String(pr.duplicates?.length || 0))} duplicates into ${chalk.bold(String(pr.groups.length))} file pairs`);
|
|
179
|
+
}
|
|
180
|
+
if (pr.clusters && pr.clusters.length >= 0) {
|
|
181
|
+
console.log(` ✅ Created ${chalk.bold(String(pr.clusters.length))} refactor clusters`);
|
|
182
|
+
// show brief cluster summaries
|
|
183
|
+
pr.clusters.slice(0, 3).forEach((cl: any, idx: number) => {
|
|
184
|
+
const files = (cl.files || []).map((f: any) => f.path.split('/').pop()).join(', ');
|
|
185
|
+
console.log(` ${idx + 1}. ${files} (${cl.tokenCost || 'n/a'} tokens)`);
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
} else if (event.tool === 'context') {
|
|
189
|
+
const cr = event.data as any[];
|
|
190
|
+
console.log(` Context issues found: ${chalk.bold(String(cr.length || 0))}`);
|
|
191
|
+
cr.slice(0, 5).forEach((c: any, i: number) => {
|
|
192
|
+
const msg = c.message ? ` - ${c.message}` : '';
|
|
193
|
+
console.log(` ${i + 1}. ${c.file} (${c.severity || 'n/a'})${msg}`);
|
|
194
|
+
});
|
|
195
|
+
} else if (event.tool === 'consistency') {
|
|
196
|
+
const rep = event.data as any;
|
|
197
|
+
console.log(` Consistency totalIssues: ${chalk.bold(String(rep.summary?.totalIssues || 0))}`);
|
|
198
|
+
|
|
199
|
+
if (rep.results && rep.results.length > 0) {
|
|
200
|
+
// Group issues by file
|
|
201
|
+
const fileMap = new Map<string, any[]>();
|
|
202
|
+
rep.results.forEach((r: any) => {
|
|
203
|
+
(r.issues || []).forEach((issue: any) => {
|
|
204
|
+
const file = issue.location?.file || r.file || 'unknown';
|
|
205
|
+
if (!fileMap.has(file)) fileMap.set(file, []);
|
|
206
|
+
fileMap.get(file)!.push(issue);
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
// Sort files by number of issues desc
|
|
211
|
+
const files = Array.from(fileMap.entries()).sort((a, b) => b[1].length - a[1].length);
|
|
212
|
+
const topFiles = files.slice(0, 10);
|
|
213
|
+
|
|
214
|
+
topFiles.forEach(([file, issues], idx) => {
|
|
215
|
+
// Count severities
|
|
216
|
+
const counts = issues.reduce((acc: any, it: any) => {
|
|
217
|
+
const s = (it.severity || 'info').toLowerCase();
|
|
218
|
+
acc[s] = (acc[s] || 0) + 1;
|
|
219
|
+
return acc;
|
|
220
|
+
}, {} as Record<string, number>);
|
|
221
|
+
|
|
222
|
+
const sample = issues.find((it: any) => it.severity === 'critical' || it.severity === 'major') || issues[0];
|
|
223
|
+
const sampleMsg = sample ? ` — ${sample.message}` : '';
|
|
224
|
+
|
|
225
|
+
console.log(` ${idx + 1}. ${file} — ${issues.length} issue(s) (critical:${counts.critical||0} major:${counts.major||0} minor:${counts.minor||0} info:${counts.info||0})${sampleMsg}`);
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
const remaining = files.length - topFiles.length;
|
|
229
|
+
if (remaining > 0) {
|
|
230
|
+
console.log(chalk.dim(` ... and ${remaining} more files with issues (use --output json for full details)`));
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
} catch (err) {
|
|
235
|
+
// don't crash the run for progress printing errors
|
|
236
|
+
}
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
const results = await analyzeUnified({ ...finalOptions, progressCallback, suppressToolConfig: true });
|
|
240
|
+
|
|
241
|
+
// Summarize tools and results to console
|
|
242
|
+
console.log(chalk.cyan('\n=== AIReady Run Summary ==='));
|
|
243
|
+
console.log(chalk.white('Tools run:'), (finalOptions.tools || ['patterns', 'context', 'consistency']).join(', '));
|
|
244
|
+
|
|
245
|
+
// Results summary
|
|
246
|
+
console.log(chalk.cyan('\nResults summary:'));
|
|
247
|
+
console.log(` Total issues (all tools): ${chalk.bold(String(results.summary.totalIssues || 0))}`);
|
|
248
|
+
if (results.duplicates) console.log(` Duplicate patterns found: ${chalk.bold(String(results.duplicates.length || 0))}`);
|
|
249
|
+
if (results.patterns) console.log(` Pattern files with issues: ${chalk.bold(String(results.patterns.length || 0))}`);
|
|
250
|
+
if (results.context) console.log(` Context issues: ${chalk.bold(String(results.context.length || 0))}`);
|
|
251
|
+
if (results.consistency) console.log(` Consistency issues: ${chalk.bold(String(results.consistency.summary.totalIssues || 0))}`);
|
|
252
|
+
console.log(chalk.cyan('===========================\n'));
|
|
79
253
|
|
|
80
254
|
const elapsedTime = getElapsedTime(startTime);
|
|
81
255
|
|
|
82
|
-
// Calculate score if requested
|
|
256
|
+
// Calculate score if requested: assemble per-tool scoring outputs
|
|
83
257
|
let scoringResult: ReturnType<typeof calculateOverallScore> | undefined;
|
|
84
258
|
if (options.score || finalOptions.scoring?.showBreakdown) {
|
|
85
259
|
const toolScores: Map<string, ToolScoringOutput> = new Map();
|
|
86
|
-
|
|
87
|
-
//
|
|
88
|
-
if (results.
|
|
260
|
+
|
|
261
|
+
// Patterns score
|
|
262
|
+
if (results.duplicates) {
|
|
89
263
|
const { calculatePatternScore } = await import('@aiready/pattern-detect');
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
264
|
+
try {
|
|
265
|
+
const patternScore = calculatePatternScore(results.duplicates, results.patterns?.length || 0);
|
|
266
|
+
toolScores.set('pattern-detect', patternScore);
|
|
267
|
+
} catch (err) {
|
|
268
|
+
// ignore scoring failures for a single tool
|
|
269
|
+
}
|
|
94
270
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
majorIssues: results.context.filter(r => r.severity === 'major').length,
|
|
107
|
-
};
|
|
108
|
-
const score = calculateContextScore(summary as any);
|
|
109
|
-
toolScores.set('context-analyzer', score);
|
|
271
|
+
|
|
272
|
+
// Context score
|
|
273
|
+
if (results.context) {
|
|
274
|
+
const { generateSummary: genContextSummary, calculateContextScore } = await import('@aiready/context-analyzer');
|
|
275
|
+
try {
|
|
276
|
+
const ctxSummary = genContextSummary(results.context);
|
|
277
|
+
const contextScore = calculateContextScore(ctxSummary);
|
|
278
|
+
toolScores.set('context-analyzer', contextScore);
|
|
279
|
+
} catch (err) {
|
|
280
|
+
// ignore
|
|
281
|
+
}
|
|
110
282
|
}
|
|
111
|
-
|
|
112
|
-
|
|
283
|
+
|
|
284
|
+
// Consistency score
|
|
285
|
+
if (results.consistency) {
|
|
113
286
|
const { calculateConsistencyScore } = await import('@aiready/consistency');
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
// Calculate overall score
|
|
123
|
-
scoringResult = calculateOverallScore(toolScores, finalOptions as AIReadyConfig, cliWeights);
|
|
124
|
-
|
|
125
|
-
// Check threshold
|
|
126
|
-
if (options.threshold) {
|
|
127
|
-
const threshold = parseFloat(options.threshold);
|
|
128
|
-
if (scoringResult.overall < threshold) {
|
|
129
|
-
console.error(chalk.red(`\n❌ Score ${scoringResult.overall} is below threshold ${threshold}\n`));
|
|
130
|
-
process.exit(1);
|
|
287
|
+
try {
|
|
288
|
+
const issues = results.consistency.results?.flatMap((r: any) => r.issues) || [];
|
|
289
|
+
const totalFiles = results.consistency.summary?.filesAnalyzed || 0;
|
|
290
|
+
const consistencyScore = calculateConsistencyScore(issues, totalFiles);
|
|
291
|
+
toolScores.set('consistency', consistencyScore);
|
|
292
|
+
} catch (err) {
|
|
293
|
+
// ignore
|
|
131
294
|
}
|
|
132
295
|
}
|
|
133
|
-
}
|
|
134
296
|
|
|
135
|
-
|
|
136
|
-
|
|
297
|
+
// Parse CLI weight overrides (if any)
|
|
298
|
+
const cliWeights = parseWeightString((options as any).weights);
|
|
137
299
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
summary: {
|
|
142
|
-
...results.summary,
|
|
143
|
-
executionTime: parseFloat(elapsedTime),
|
|
144
|
-
},
|
|
145
|
-
...(scoringResult && { scoring: scoringResult }),
|
|
146
|
-
};
|
|
300
|
+
// Only calculate overall score if we have at least one tool score
|
|
301
|
+
if (toolScores.size > 0) {
|
|
302
|
+
scoringResult = calculateOverallScore(toolScores, finalOptions, cliWeights.size ? cliWeights : undefined);
|
|
147
303
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
// Display score if calculated
|
|
160
|
-
if (scoringResult) {
|
|
161
|
-
const terminalWidth = process.stdout.columns || 80;
|
|
162
|
-
const dividerWidth = Math.min(60, terminalWidth - 2);
|
|
163
|
-
const divider = '━'.repeat(dividerWidth);
|
|
164
|
-
|
|
165
|
-
console.log(chalk.cyan('\n' + divider));
|
|
166
|
-
console.log(chalk.bold.white(' AI READINESS SCORE'));
|
|
167
|
-
console.log(chalk.cyan(divider) + '\n');
|
|
168
|
-
|
|
169
|
-
const { emoji, color } = getRatingDisplay(scoringResult.rating);
|
|
170
|
-
const scoreColor = color === 'green' ? chalk.green :
|
|
171
|
-
color === 'blue' ? chalk.blue :
|
|
172
|
-
color === 'yellow' ? chalk.yellow : chalk.red;
|
|
173
|
-
|
|
174
|
-
console.log(` ${emoji} Overall Score: ${scoreColor.bold(scoringResult.overall + '/100')} (${chalk.bold(scoringResult.rating)})`); console.log(` ${chalk.dim('Timestamp:')} ${new Date(scoringResult.timestamp).toLocaleString()}\n`);
|
|
175
|
-
|
|
176
|
-
// Show breakdown by tool
|
|
177
|
-
if (scoringResult.breakdown.length > 0) {
|
|
178
|
-
console.log(chalk.bold(' Component Scores:\n'));
|
|
179
|
-
scoringResult.breakdown.forEach(tool => {
|
|
180
|
-
const toolEmoji = tool.toolName === 'pattern-detect' ? '🔍' :
|
|
181
|
-
tool.toolName === 'context-analyzer' ? '🧠' : '🏷️';
|
|
182
|
-
const weight = scoringResult.calculation.weights[tool.toolName];
|
|
183
|
-
console.log(` ${toolEmoji} ${chalk.white(tool.toolName.padEnd(20))} ${scoreColor(tool.score + '/100')} ${chalk.dim(`(weight: ${weight})`)}`);
|
|
304
|
+
console.log(chalk.bold('\n📊 AI Readiness Overall Score'));
|
|
305
|
+
console.log(` ${formatScore(scoringResult)}`);
|
|
306
|
+
|
|
307
|
+
// Show concise breakdown; detailed breakdown only if config requests it
|
|
308
|
+
if (scoringResult.breakdown && scoringResult.breakdown.length > 0) {
|
|
309
|
+
console.log(chalk.bold('\nTool breakdown:'));
|
|
310
|
+
scoringResult.breakdown.forEach((tool) => {
|
|
311
|
+
const rating = getRating(tool.score);
|
|
312
|
+
const rd = getRatingDisplay(rating);
|
|
313
|
+
console.log(` - ${tool.toolName}: ${tool.score}/100 (${rating}) ${rd.emoji}`);
|
|
184
314
|
});
|
|
185
315
|
console.log();
|
|
316
|
+
|
|
317
|
+
if (finalOptions.scoring?.showBreakdown) {
|
|
318
|
+
console.log(chalk.bold('Detailed tool breakdown:'));
|
|
319
|
+
scoringResult.breakdown.forEach((tool) => {
|
|
320
|
+
console.log(formatToolScore(tool));
|
|
321
|
+
});
|
|
322
|
+
console.log();
|
|
323
|
+
}
|
|
186
324
|
}
|
|
187
|
-
|
|
188
|
-
//
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
if (allRecommendations.length > 0) {
|
|
199
|
-
console.log(chalk.bold(' Top Recommendations:\n'));
|
|
200
|
-
allRecommendations.forEach((rec, i) => {
|
|
201
|
-
const priorityIcon = rec.priority === 'high' ? '🔴' :
|
|
202
|
-
rec.priority === 'medium' ? '🟡' : '🔵';
|
|
203
|
-
console.log(` ${i + 1}. ${priorityIcon} ${rec.action}`);
|
|
204
|
-
console.log(` ${chalk.dim(`Impact: +${rec.estimatedImpact} points`)}\n`);
|
|
205
|
-
});
|
|
325
|
+
|
|
326
|
+
// Persist JSON summary by default when output is json or when config directory present
|
|
327
|
+
const outputFormat = options.output || finalOptions.output?.format || 'console';
|
|
328
|
+
const userOutputFile = options.outputFile || finalOptions.output?.file;
|
|
329
|
+
if (outputFormat === 'json') {
|
|
330
|
+
const dateStr = new Date().toISOString().split('T')[0];
|
|
331
|
+
const defaultFilename = `aiready-scan-${dateStr}.json`;
|
|
332
|
+
const outputPath = resolveOutputPath(userOutputFile, defaultFilename, directory);
|
|
333
|
+
const outputData = { ...results, scoring: scoringResult };
|
|
334
|
+
handleJSONOutput(outputData, outputPath, `✅ Summary saved to ${outputPath}`);
|
|
206
335
|
}
|
|
207
336
|
}
|
|
208
337
|
}
|
package/src/index.ts
CHANGED
|
@@ -6,6 +6,8 @@ import type { ContextAnalysisResult } from '@aiready/context-analyzer';
|
|
|
6
6
|
import type { PatternDetectOptions, DuplicatePattern } from '@aiready/pattern-detect';
|
|
7
7
|
import type { ConsistencyReport } from '@aiready/consistency';
|
|
8
8
|
|
|
9
|
+
import type { ConsistencyOptions } from '@aiready/consistency';
|
|
10
|
+
|
|
9
11
|
export interface UnifiedAnalysisOptions extends ScanOptions {
|
|
10
12
|
tools?: ('patterns' | 'context' | 'consistency')[];
|
|
11
13
|
minSimilarity?: number;
|
|
@@ -13,6 +15,8 @@ export interface UnifiedAnalysisOptions extends ScanOptions {
|
|
|
13
15
|
maxCandidatesPerBlock?: number;
|
|
14
16
|
minSharedTokens?: number;
|
|
15
17
|
useSmartDefaults?: boolean;
|
|
18
|
+
consistency?: Partial<ConsistencyOptions>;
|
|
19
|
+
progressCallback?: (event: { tool: string; data: any }) => void;
|
|
16
20
|
}
|
|
17
21
|
|
|
18
22
|
export interface UnifiedAnalysisResult {
|
|
@@ -68,6 +72,7 @@ export async function analyzeUnified(
|
|
|
68
72
|
): Promise<UnifiedAnalysisResult> {
|
|
69
73
|
const startTime = Date.now();
|
|
70
74
|
const tools = options.tools || ['patterns', 'context', 'consistency'];
|
|
75
|
+
// Tools requested and effective options are used from `options`
|
|
71
76
|
const result: UnifiedAnalysisResult = {
|
|
72
77
|
summary: {
|
|
73
78
|
totalIssues: 0,
|
|
@@ -79,6 +84,10 @@ export async function analyzeUnified(
|
|
|
79
84
|
// Run pattern detection
|
|
80
85
|
if (tools.includes('patterns')) {
|
|
81
86
|
const patternResult = await analyzePatterns(options);
|
|
87
|
+
// Emit progress for patterns
|
|
88
|
+
if (options.progressCallback) {
|
|
89
|
+
options.progressCallback({ tool: 'patterns', data: patternResult });
|
|
90
|
+
}
|
|
82
91
|
// Sort results by severity
|
|
83
92
|
result.patterns = sortBySeverity(patternResult.results);
|
|
84
93
|
// Store duplicates for scoring
|
|
@@ -93,6 +102,9 @@ export async function analyzeUnified(
|
|
|
93
102
|
// Run context analysis
|
|
94
103
|
if (tools.includes('context')) {
|
|
95
104
|
const contextResults = await analyzeContext(options);
|
|
105
|
+
if (options.progressCallback) {
|
|
106
|
+
options.progressCallback({ tool: 'context', data: contextResults });
|
|
107
|
+
}
|
|
96
108
|
// Sort context results by severity (most severe first)
|
|
97
109
|
result.context = contextResults.sort((a, b) => {
|
|
98
110
|
const severityDiff = (severityOrder[b.severity] || 0) - (severityOrder[a.severity] || 0);
|
|
@@ -107,14 +119,17 @@ export async function analyzeUnified(
|
|
|
107
119
|
|
|
108
120
|
// Run consistency analysis
|
|
109
121
|
if (tools.includes('consistency')) {
|
|
110
|
-
|
|
122
|
+
// Use config fields if present, fallback to defaults
|
|
123
|
+
const consistencyOptions = {
|
|
111
124
|
rootDir: options.rootDir,
|
|
112
125
|
include: options.include,
|
|
113
126
|
exclude: options.exclude,
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
127
|
+
...(options.consistency || {}),
|
|
128
|
+
};
|
|
129
|
+
const report = await analyzeConsistency(consistencyOptions);
|
|
130
|
+
if (options.progressCallback) {
|
|
131
|
+
options.progressCallback({ tool: 'consistency', data: report });
|
|
132
|
+
}
|
|
118
133
|
// Sort consistency results by severity
|
|
119
134
|
if (report.results) {
|
|
120
135
|
report.results = sortBySeverity(report.results);
|
|
@@ -135,11 +150,11 @@ export function generateUnifiedSummary(result: UnifiedAnalysisResult): string {
|
|
|
135
150
|
output += ` Total issues found: ${summary.totalIssues}\n`;
|
|
136
151
|
output += ` Execution time: ${(summary.executionTime / 1000).toFixed(2)}s\n\n`;
|
|
137
152
|
|
|
138
|
-
if (result.patterns
|
|
153
|
+
if (result.patterns) {
|
|
139
154
|
output += `🔍 Pattern Analysis: ${result.patterns.length} issues\n`;
|
|
140
155
|
}
|
|
141
156
|
|
|
142
|
-
if (result.context
|
|
157
|
+
if (result.context) {
|
|
143
158
|
output += `🧠 Context Analysis: ${result.context.length} issues\n`;
|
|
144
159
|
}
|
|
145
160
|
|
package/dist/chunk-KZKXZKES.mjs
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
// src/index.ts
|
|
2
|
-
import { analyzePatterns } from "@aiready/pattern-detect";
|
|
3
|
-
import { analyzeContext } from "@aiready/context-analyzer";
|
|
4
|
-
async function analyzeUnified(options) {
|
|
5
|
-
const startTime = Date.now();
|
|
6
|
-
const tools = options.tools || ["patterns", "context"];
|
|
7
|
-
const result = {
|
|
8
|
-
summary: {
|
|
9
|
-
totalIssues: 0,
|
|
10
|
-
toolsRun: tools,
|
|
11
|
-
executionTime: 0
|
|
12
|
-
}
|
|
13
|
-
};
|
|
14
|
-
if (tools.includes("patterns")) {
|
|
15
|
-
const patternResult = await analyzePatterns(options);
|
|
16
|
-
result.patterns = patternResult.results;
|
|
17
|
-
result.summary.totalIssues += patternResult.results.length;
|
|
18
|
-
}
|
|
19
|
-
if (tools.includes("context")) {
|
|
20
|
-
result.context = await analyzeContext(options);
|
|
21
|
-
result.summary.totalIssues += result.context?.length || 0;
|
|
22
|
-
}
|
|
23
|
-
result.summary.executionTime = Date.now() - startTime;
|
|
24
|
-
return result;
|
|
25
|
-
}
|
|
26
|
-
function generateUnifiedSummary(result) {
|
|
27
|
-
const { summary } = result;
|
|
28
|
-
let output = `\u{1F680} AIReady Analysis Complete
|
|
29
|
-
|
|
30
|
-
`;
|
|
31
|
-
output += `\u{1F4CA} Summary:
|
|
32
|
-
`;
|
|
33
|
-
output += ` Tools run: ${summary.toolsRun.join(", ")}
|
|
34
|
-
`;
|
|
35
|
-
output += ` Total issues found: ${summary.totalIssues}
|
|
36
|
-
`;
|
|
37
|
-
output += ` Execution time: ${(summary.executionTime / 1e3).toFixed(2)}s
|
|
38
|
-
|
|
39
|
-
`;
|
|
40
|
-
if (result.patterns?.length) {
|
|
41
|
-
output += `\u{1F50D} Pattern Analysis: ${result.patterns.length} issues
|
|
42
|
-
`;
|
|
43
|
-
}
|
|
44
|
-
if (result.context?.length) {
|
|
45
|
-
output += `\u{1F9E0} Context Analysis: ${result.context.length} issues
|
|
46
|
-
`;
|
|
47
|
-
}
|
|
48
|
-
return output;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export {
|
|
52
|
-
analyzeUnified,
|
|
53
|
-
generateUnifiedSummary
|
|
54
|
-
};
|
package/dist/chunk-NWEWXOUT.mjs
DELETED
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
// src/index.ts
|
|
2
|
-
import { analyzePatterns } from "@aiready/pattern-detect";
|
|
3
|
-
import { analyzeContext } from "@aiready/context-analyzer";
|
|
4
|
-
import { analyzeConsistency } from "@aiready/consistency";
|
|
5
|
-
async function analyzeUnified(options) {
|
|
6
|
-
const startTime = Date.now();
|
|
7
|
-
const tools = options.tools || ["patterns", "context", "consistency"];
|
|
8
|
-
const result = {
|
|
9
|
-
summary: {
|
|
10
|
-
totalIssues: 0,
|
|
11
|
-
toolsRun: tools,
|
|
12
|
-
executionTime: 0
|
|
13
|
-
}
|
|
14
|
-
};
|
|
15
|
-
if (tools.includes("patterns")) {
|
|
16
|
-
const patternResult = await analyzePatterns(options);
|
|
17
|
-
result.patterns = patternResult.results;
|
|
18
|
-
result.summary.totalIssues += patternResult.results.reduce(
|
|
19
|
-
(sum, file) => sum + file.issues.length,
|
|
20
|
-
0
|
|
21
|
-
);
|
|
22
|
-
}
|
|
23
|
-
if (tools.includes("context")) {
|
|
24
|
-
result.context = await analyzeContext(options);
|
|
25
|
-
result.summary.totalIssues += result.context?.length || 0;
|
|
26
|
-
}
|
|
27
|
-
if (tools.includes("consistency")) {
|
|
28
|
-
const report = await analyzeConsistency({
|
|
29
|
-
rootDir: options.rootDir,
|
|
30
|
-
include: options.include,
|
|
31
|
-
exclude: options.exclude,
|
|
32
|
-
checkNaming: true,
|
|
33
|
-
checkPatterns: true,
|
|
34
|
-
minSeverity: "info"
|
|
35
|
-
});
|
|
36
|
-
result.consistency = report;
|
|
37
|
-
result.summary.totalIssues += report.summary.totalIssues;
|
|
38
|
-
}
|
|
39
|
-
result.summary.executionTime = Date.now() - startTime;
|
|
40
|
-
return result;
|
|
41
|
-
}
|
|
42
|
-
function generateUnifiedSummary(result) {
|
|
43
|
-
const { summary } = result;
|
|
44
|
-
let output = `\u{1F680} AIReady Analysis Complete
|
|
45
|
-
|
|
46
|
-
`;
|
|
47
|
-
output += `\u{1F4CA} Summary:
|
|
48
|
-
`;
|
|
49
|
-
output += ` Tools run: ${summary.toolsRun.join(", ")}
|
|
50
|
-
`;
|
|
51
|
-
output += ` Total issues found: ${summary.totalIssues}
|
|
52
|
-
`;
|
|
53
|
-
output += ` Execution time: ${(summary.executionTime / 1e3).toFixed(2)}s
|
|
54
|
-
|
|
55
|
-
`;
|
|
56
|
-
if (result.patterns?.length) {
|
|
57
|
-
output += `\u{1F50D} Pattern Analysis: ${result.patterns.length} issues
|
|
58
|
-
`;
|
|
59
|
-
}
|
|
60
|
-
if (result.context?.length) {
|
|
61
|
-
output += `\u{1F9E0} Context Analysis: ${result.context.length} issues
|
|
62
|
-
`;
|
|
63
|
-
}
|
|
64
|
-
if (result.consistency) {
|
|
65
|
-
output += `\u{1F3F7}\uFE0F Consistency Analysis: ${result.consistency.summary.totalIssues} issues
|
|
66
|
-
`;
|
|
67
|
-
}
|
|
68
|
-
return output;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
export {
|
|
72
|
-
analyzeUnified,
|
|
73
|
-
generateUnifiedSummary
|
|
74
|
-
};
|
package/dist/chunk-S6JWNLN7.mjs
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
// src/index.ts
|
|
2
|
-
import { analyzePatterns } from "@aiready/pattern-detect";
|
|
3
|
-
import { analyzeContext } from "@aiready/context-analyzer";
|
|
4
|
-
async function analyzeUnified(options) {
|
|
5
|
-
const startTime = Date.now();
|
|
6
|
-
const tools = options.tools || ["patterns", "context"];
|
|
7
|
-
const result = {
|
|
8
|
-
summary: {
|
|
9
|
-
totalIssues: 0,
|
|
10
|
-
toolsRun: tools,
|
|
11
|
-
executionTime: 0
|
|
12
|
-
}
|
|
13
|
-
};
|
|
14
|
-
if (tools.includes("patterns")) {
|
|
15
|
-
result.patterns = await analyzePatterns(options);
|
|
16
|
-
result.summary.totalIssues += result.patterns.length;
|
|
17
|
-
}
|
|
18
|
-
if (tools.includes("context")) {
|
|
19
|
-
result.context = await analyzeContext(options);
|
|
20
|
-
result.summary.totalIssues += result.context?.length || 0;
|
|
21
|
-
}
|
|
22
|
-
result.summary.executionTime = Date.now() - startTime;
|
|
23
|
-
return result;
|
|
24
|
-
}
|
|
25
|
-
function generateUnifiedSummary(result) {
|
|
26
|
-
const { summary } = result;
|
|
27
|
-
let output = `\u{1F680} AIReady Analysis Complete
|
|
28
|
-
|
|
29
|
-
`;
|
|
30
|
-
output += `\u{1F4CA} Summary:
|
|
31
|
-
`;
|
|
32
|
-
output += ` Tools run: ${summary.toolsRun.join(", ")}
|
|
33
|
-
`;
|
|
34
|
-
output += ` Total issues found: ${summary.totalIssues}
|
|
35
|
-
`;
|
|
36
|
-
output += ` Execution time: ${(summary.executionTime / 1e3).toFixed(2)}s
|
|
37
|
-
|
|
38
|
-
`;
|
|
39
|
-
if (result.patterns?.length) {
|
|
40
|
-
output += `\u{1F50D} Pattern Analysis: ${result.patterns.length} issues
|
|
41
|
-
`;
|
|
42
|
-
}
|
|
43
|
-
if (result.context?.length) {
|
|
44
|
-
output += `\u{1F9E0} Context Analysis: ${result.context.length} issues
|
|
45
|
-
`;
|
|
46
|
-
}
|
|
47
|
-
return output;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export {
|
|
51
|
-
analyzeUnified,
|
|
52
|
-
generateUnifiedSummary
|
|
53
|
-
};
|