@aiready/cli 0.14.13 → 0.14.15
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/CONTRIBUTING.md +86 -1
- package/LICENSE +21 -0
- package/package.json +33 -12
- package/.aiready/aiready-report-20260227-133806.json +0 -7805
- package/.aiready/aiready-report-20260227-133938.json +0 -7951
- package/.aiready/aiready-report-20260228-003433.json +0 -7939
- package/.aiready/aiready-report-20260228-003613.json +0 -771
- package/.aiready/aiready-report-20260314-164626.json +0 -59
- package/.aiready/aiready-report-20260314-164741.json +0 -59
- package/.aiready/aiready-report-20260319-201106.json +0 -5566
- package/.aiready/aiready-report-20260319-201511.json +0 -5566
- package/.aiready/aiready-report-20260319-202017.json +0 -5708
- package/.github/FUNDING.yml +0 -5
- package/.turbo/turbo-build.log +0 -29
- package/.turbo/turbo-lint.log +0 -0
- package/.turbo/turbo-test.log +0 -76
- package/aiready-report.json +0 -30703
- package/coverage/base.css +0 -224
- package/coverage/block-navigation.js +0 -87
- package/coverage/clover.xml +0 -865
- package/coverage/coverage-final.json +0 -15
- package/coverage/favicon.png +0 -0
- package/coverage/index.html +0 -146
- package/coverage/prettify.css +0 -1
- package/coverage/prettify.js +0 -2
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +0 -210
- package/coverage/src/commands/agent-grounding.ts.html +0 -271
- package/coverage/src/commands/ai-signal-clarity.ts.html +0 -253
- package/coverage/src/commands/change-amplification.ts.html +0 -94
- package/coverage/src/commands/consistency.ts.html +0 -781
- package/coverage/src/commands/context.ts.html +0 -871
- package/coverage/src/commands/deps-health.ts.html +0 -280
- package/coverage/src/commands/doc-drift.ts.html +0 -271
- package/coverage/src/commands/index.html +0 -281
- package/coverage/src/commands/patterns.ts.html +0 -745
- package/coverage/src/commands/scan.ts.html +0 -1393
- package/coverage/src/commands/testability.ts.html +0 -304
- package/coverage/src/commands/upload.ts.html +0 -466
- package/coverage/src/commands/visualize.ts.html +0 -1027
- package/coverage/src/index.html +0 -116
- package/coverage/src/index.ts.html +0 -1372
- package/coverage/src/utils/helpers.ts.html +0 -559
- package/coverage/src/utils/index.html +0 -116
- package/docs/SPOKE_GUIDE.md +0 -184
- package/packages/core/src/.aiready/aiready-report-20260314-161145.json +0 -224
- package/packages/core/src/.aiready/aiready-report-20260314-161152.json +0 -235
- package/packages/pattern-detect/src/.aiready/aiready-report-20260314-161139.json +0 -224
- package/src/.aiready/aiready-report-20260312-103623.json +0 -32574
- package/src/.aiready/aiready-report-20260312-110843.json +0 -28740
- package/src/.aiready/aiready-report-20260312-110955.json +0 -28740
- package/src/.aiready/aiready-report-20260314-203209.json +0 -30713
- package/src/.aiready/aiready-report-20260314-203736.json +0 -30713
- package/src/.aiready/aiready-report-20260314-203857.json +0 -30713
- package/src/.aiready/aiready-report-20260314-204047.json +0 -30713
- package/src/.aiready/aiready-report-20260318-002110.json +0 -28782
- package/src/__tests__/cli.test.ts +0 -85
- package/src/__tests__/config-shape.test.ts +0 -105
- package/src/__tests__/unified.test.ts +0 -95
- package/src/cli.ts +0 -333
- package/src/commands/__tests__/agent-grounding.test.ts +0 -24
- package/src/commands/__tests__/ai-signal-clarity.test.ts +0 -32
- package/src/commands/__tests__/consistency.test.ts +0 -100
- package/src/commands/__tests__/deps-health.test.ts +0 -26
- package/src/commands/__tests__/doc-drift.test.ts +0 -26
- package/src/commands/__tests__/extra-commands.test.ts +0 -168
- package/src/commands/__tests__/init.test.ts +0 -51
- package/src/commands/__tests__/scan.test.ts +0 -153
- package/src/commands/__tests__/testability.test.ts +0 -36
- package/src/commands/__tests__/upload.test.ts +0 -50
- package/src/commands/__tests__/visualize.test.ts +0 -78
- package/src/commands/agent-grounding.ts +0 -62
- package/src/commands/ai-signal-clarity.ts +0 -1
- package/src/commands/bug.ts +0 -99
- package/src/commands/change-amplification.ts +0 -3
- package/src/commands/consistency.ts +0 -232
- package/src/commands/context.ts +0 -262
- package/src/commands/deps-health.ts +0 -1
- package/src/commands/doc-drift.ts +0 -1
- package/src/commands/index.ts +0 -20
- package/src/commands/init.ts +0 -199
- package/src/commands/patterns.ts +0 -222
- package/src/commands/report-formatter.ts +0 -267
- package/src/commands/scan.ts +0 -432
- package/src/commands/shared/configured-tool-action.ts +0 -35
- package/src/commands/shared/standard-tool-actions.ts +0 -126
- package/src/commands/testability.ts +0 -73
- package/src/commands/upload.ts +0 -129
- package/src/commands/visualize.ts +0 -321
- package/src/index.ts +0 -465
- package/src/utils/__tests__/helpers.test.ts +0 -35
- package/src/utils/helpers.ts +0 -234
- package/tsconfig.json +0 -11
- package/tsconfig.tsbuildinfo +0 -1
- package/vitest.config.ts +0 -13
package/src/index.ts
DELETED
|
@@ -1,465 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ToolRegistry,
|
|
3
|
-
ToolName,
|
|
4
|
-
calculateOverallScore,
|
|
5
|
-
calculateTokenBudget,
|
|
6
|
-
GLOBAL_INFRA_OPTIONS,
|
|
7
|
-
COMMON_FINE_TUNING_OPTIONS,
|
|
8
|
-
initializeParsers,
|
|
9
|
-
} from '@aiready/core';
|
|
10
|
-
import type {
|
|
11
|
-
ScanOptions,
|
|
12
|
-
ToolScoringOutput,
|
|
13
|
-
ScoringResult,
|
|
14
|
-
} from '@aiready/core';
|
|
15
|
-
|
|
16
|
-
// Pre-import all tool providers to ensure they are registered by default
|
|
17
|
-
import '@aiready/pattern-detect';
|
|
18
|
-
import '@aiready/context-analyzer';
|
|
19
|
-
import '@aiready/consistency';
|
|
20
|
-
import '@aiready/ai-signal-clarity';
|
|
21
|
-
import '@aiready/agent-grounding';
|
|
22
|
-
import '@aiready/testability';
|
|
23
|
-
import '@aiready/doc-drift';
|
|
24
|
-
import '@aiready/deps';
|
|
25
|
-
import '@aiready/change-amplification';
|
|
26
|
-
|
|
27
|
-
export type { ToolScoringOutput, ScoringResult };
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Options for running a unified AI-readiness analysis across multiple tools.
|
|
31
|
-
* Extends base ScanOptions with CLI-specific configurations.
|
|
32
|
-
*/
|
|
33
|
-
export interface UnifiedAnalysisOptions extends ScanOptions {
|
|
34
|
-
/** Root directory for analysis */
|
|
35
|
-
rootDir: string;
|
|
36
|
-
/** List of tools to run (e.g. ['patterns', 'context']) */
|
|
37
|
-
tools?: string[];
|
|
38
|
-
/** Overrides for specific tool configurations */
|
|
39
|
-
toolConfigs?: Record<string, any>;
|
|
40
|
-
/** Minimum similarity threshold for pattern detection (0-1) */
|
|
41
|
-
minSimilarity?: number;
|
|
42
|
-
/** Minimum number of lines for a pattern to be considered */
|
|
43
|
-
minLines?: number;
|
|
44
|
-
/** Maximum number of candidates to check per code block */
|
|
45
|
-
maxCandidatesPerBlock?: number;
|
|
46
|
-
/** Minimum number of shared tokens for a match */
|
|
47
|
-
minSharedTokens?: number;
|
|
48
|
-
/** Whether to use optimized defaults based on project size/language */
|
|
49
|
-
useSmartDefaults?: boolean;
|
|
50
|
-
/** Specific options for naming consistency analysis */
|
|
51
|
-
consistency?: any;
|
|
52
|
-
/** Optional callback for tracking analysis progress */
|
|
53
|
-
progressCallback?: (event: {
|
|
54
|
-
tool: string;
|
|
55
|
-
data?: any;
|
|
56
|
-
processed?: number;
|
|
57
|
-
total?: number;
|
|
58
|
-
message?: string;
|
|
59
|
-
}) => void;
|
|
60
|
-
/** Files or directories to include in scan */
|
|
61
|
-
include?: string[];
|
|
62
|
-
/** Files or directories to exclude from scan */
|
|
63
|
-
exclude?: string[];
|
|
64
|
-
/** Batch size for comparisons */
|
|
65
|
-
batchSize?: number;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* The consolidated result of a unified analysis across all requested tools.
|
|
70
|
-
* Contains tool-specific outputs, scoring, and a high-level summary.
|
|
71
|
-
*/
|
|
72
|
-
export interface UnifiedAnalysisResult {
|
|
73
|
-
// Dynamic keys based on ToolName
|
|
74
|
-
[key: string]: any;
|
|
75
|
-
|
|
76
|
-
summary: {
|
|
77
|
-
totalFiles: number;
|
|
78
|
-
totalIssues: number;
|
|
79
|
-
criticalIssues: number;
|
|
80
|
-
majorIssues: number;
|
|
81
|
-
toolsRun: string[];
|
|
82
|
-
executionTime: number;
|
|
83
|
-
config?: any;
|
|
84
|
-
toolConfigs?: Record<string, any>;
|
|
85
|
-
};
|
|
86
|
-
scoring?: ScoringResult;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Mapping between ToolName and @aiready/ package names.
|
|
91
|
-
* Used for dynamic registration on-demand.
|
|
92
|
-
*/
|
|
93
|
-
const TOOL_PACKAGE_MAP: Record<string, string> = {
|
|
94
|
-
[ToolName.PatternDetect]: '@aiready/pattern-detect',
|
|
95
|
-
[ToolName.ContextAnalyzer]: '@aiready/context-analyzer',
|
|
96
|
-
[ToolName.NamingConsistency]: '@aiready/consistency',
|
|
97
|
-
[ToolName.AiSignalClarity]: '@aiready/ai-signal-clarity',
|
|
98
|
-
[ToolName.AgentGrounding]: '@aiready/agent-grounding',
|
|
99
|
-
[ToolName.TestabilityIndex]: '@aiready/testability',
|
|
100
|
-
[ToolName.DocDrift]: '@aiready/doc-drift',
|
|
101
|
-
[ToolName.DependencyHealth]: '@aiready/deps',
|
|
102
|
-
[ToolName.ChangeAmplification]: '@aiready/change-amplification',
|
|
103
|
-
// Aliases handled by registry
|
|
104
|
-
patterns: '@aiready/pattern-detect',
|
|
105
|
-
duplicates: '@aiready/pattern-detect',
|
|
106
|
-
context: '@aiready/context-analyzer',
|
|
107
|
-
fragmentation: '@aiready/context-analyzer',
|
|
108
|
-
consistency: '@aiready/consistency',
|
|
109
|
-
'ai-signal': '@aiready/ai-signal-clarity',
|
|
110
|
-
grounding: '@aiready/agent-grounding',
|
|
111
|
-
testability: '@aiready/testability',
|
|
112
|
-
'deps-health': '@aiready/deps',
|
|
113
|
-
'change-amp': '@aiready/change-amplification',
|
|
114
|
-
};
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* Deeply sanitizes a configuration object by removing infrastructure keys like rootDir.
|
|
118
|
-
* Works recursively to clean up nested tool configurations to ensure compatibility
|
|
119
|
-
* with the AIReadyConfig schema for portable configuration files.
|
|
120
|
-
*/
|
|
121
|
-
function sanitizeConfigRecursive(obj: any): any {
|
|
122
|
-
if (!obj || typeof obj !== 'object' || Array.isArray(obj)) return obj;
|
|
123
|
-
|
|
124
|
-
const sanitized: any = {};
|
|
125
|
-
const infraToStrip = [
|
|
126
|
-
'rootDir',
|
|
127
|
-
'onProgress',
|
|
128
|
-
'progressCallback',
|
|
129
|
-
'streamResults',
|
|
130
|
-
'batchSize',
|
|
131
|
-
'useSmartDefaults',
|
|
132
|
-
];
|
|
133
|
-
|
|
134
|
-
for (const [key, value] of Object.entries(obj)) {
|
|
135
|
-
// Skip infrastructure keys that shouldn't be in a portable config file
|
|
136
|
-
if (infraToStrip.includes(key)) continue;
|
|
137
|
-
|
|
138
|
-
if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
|
|
139
|
-
sanitized[key] = sanitizeConfigRecursive(value);
|
|
140
|
-
} else {
|
|
141
|
-
sanitized[key] = value;
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
return sanitized;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
/**
|
|
149
|
-
* Sanitize tool configuration by removing global options to match AIReadyConfig schema
|
|
150
|
-
*/
|
|
151
|
-
function sanitizeToolConfig(config: any): any {
|
|
152
|
-
return sanitizeConfigRecursive(config);
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
/**
|
|
156
|
-
* AIReady Unified Analysis.
|
|
157
|
-
* Orchestrates all registered tools via the ToolRegistry.
|
|
158
|
-
*
|
|
159
|
-
* @param options - Unified analysis configuration including tools and rootDir.
|
|
160
|
-
* @returns Promise resolving to the consolidated analysis result.
|
|
161
|
-
* @lastUpdated 2026-03-18
|
|
162
|
-
*/
|
|
163
|
-
export async function analyzeUnified(
|
|
164
|
-
options: UnifiedAnalysisOptions
|
|
165
|
-
): Promise<UnifiedAnalysisResult> {
|
|
166
|
-
// Initialize language parsers
|
|
167
|
-
await initializeParsers();
|
|
168
|
-
|
|
169
|
-
const startTime = Date.now();
|
|
170
|
-
const requestedTools = options.tools ?? [
|
|
171
|
-
'patterns',
|
|
172
|
-
'context',
|
|
173
|
-
'consistency',
|
|
174
|
-
];
|
|
175
|
-
|
|
176
|
-
const result: UnifiedAnalysisResult = {
|
|
177
|
-
summary: {
|
|
178
|
-
totalIssues: 0,
|
|
179
|
-
criticalIssues: 0, // Added as per instruction
|
|
180
|
-
majorIssues: 0, // Added as per instruction
|
|
181
|
-
totalFiles: 0,
|
|
182
|
-
toolsRun: [],
|
|
183
|
-
executionTime: 0,
|
|
184
|
-
config: options,
|
|
185
|
-
toolConfigs: {},
|
|
186
|
-
},
|
|
187
|
-
};
|
|
188
|
-
|
|
189
|
-
for (const toolName of requestedTools) {
|
|
190
|
-
let provider = ToolRegistry.find(toolName);
|
|
191
|
-
|
|
192
|
-
// Dynamic Loading: If provider not found, attempt to import the package
|
|
193
|
-
if (!provider) {
|
|
194
|
-
const packageName =
|
|
195
|
-
TOOL_PACKAGE_MAP[toolName] ??
|
|
196
|
-
(toolName.startsWith('@aiready/') ? toolName : `@aiready/${toolName}`);
|
|
197
|
-
try {
|
|
198
|
-
await import(packageName);
|
|
199
|
-
provider = ToolRegistry.find(toolName);
|
|
200
|
-
if (provider) {
|
|
201
|
-
console.log(
|
|
202
|
-
`✅ Successfully loaded tool provider: ${toolName} from ${packageName}`
|
|
203
|
-
);
|
|
204
|
-
} else {
|
|
205
|
-
console.log(
|
|
206
|
-
`⚠️ Loaded ${packageName} but provider ${toolName} still not found in registry.`
|
|
207
|
-
);
|
|
208
|
-
}
|
|
209
|
-
} catch (err: any) {
|
|
210
|
-
console.log(
|
|
211
|
-
`❌ Failed to dynamically load tool ${toolName} (${packageName}):`,
|
|
212
|
-
err.message
|
|
213
|
-
);
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
if (!provider) {
|
|
218
|
-
console.warn(
|
|
219
|
-
`⚠️ Warning: Tool provider for '${toolName}' not found. Skipping.`
|
|
220
|
-
);
|
|
221
|
-
continue;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
try {
|
|
225
|
-
// Sanitize options for metadata tracking (remove functions/internal keys)
|
|
226
|
-
const sanitizedOptions = { ...options };
|
|
227
|
-
delete (sanitizedOptions as any).onProgress;
|
|
228
|
-
delete (sanitizedOptions as any).progressCallback;
|
|
229
|
-
|
|
230
|
-
// 1. Start with sanitized global subset
|
|
231
|
-
const toolOptions: any = {
|
|
232
|
-
rootDir: options.rootDir, // Always include rootDir
|
|
233
|
-
};
|
|
234
|
-
|
|
235
|
-
// 1. Pass through all known infra and fine-tuning options from root level
|
|
236
|
-
[...GLOBAL_INFRA_OPTIONS, ...COMMON_FINE_TUNING_OPTIONS].forEach(
|
|
237
|
-
(key) => {
|
|
238
|
-
if (key in options && key !== 'toolConfigs' && key !== 'tools') {
|
|
239
|
-
toolOptions[key] = (options as any)[key];
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
);
|
|
243
|
-
|
|
244
|
-
// 3. Add tool-specific overrides
|
|
245
|
-
// Check priority:
|
|
246
|
-
// a) options.toolConfigs[toolId]
|
|
247
|
-
// b) options.tools[toolId] (if tools is an object, not the array of tool names)
|
|
248
|
-
// c) options[toolId] (legacy)
|
|
249
|
-
if (options.toolConfigs?.[provider.id]) {
|
|
250
|
-
Object.assign(toolOptions, options.toolConfigs[provider.id]);
|
|
251
|
-
} else if (
|
|
252
|
-
options.tools &&
|
|
253
|
-
!Array.isArray(options.tools) &&
|
|
254
|
-
typeof options.tools === 'object' &&
|
|
255
|
-
(options.tools as any)[provider.id]
|
|
256
|
-
) {
|
|
257
|
-
Object.assign(toolOptions, (options.tools as any)[provider.id]);
|
|
258
|
-
} else if ((options as any)[provider.id]) {
|
|
259
|
-
// Fallback for legacy tool-specific keys
|
|
260
|
-
Object.assign(toolOptions, (options as any)[provider.id]);
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
// 4. Attach progress callback
|
|
264
|
-
toolOptions.onProgress = (
|
|
265
|
-
processed: number,
|
|
266
|
-
total: number,
|
|
267
|
-
message: string
|
|
268
|
-
) => {
|
|
269
|
-
if (options.progressCallback) {
|
|
270
|
-
options.progressCallback({
|
|
271
|
-
tool: provider!.id,
|
|
272
|
-
processed,
|
|
273
|
-
total,
|
|
274
|
-
message,
|
|
275
|
-
});
|
|
276
|
-
}
|
|
277
|
-
};
|
|
278
|
-
|
|
279
|
-
const output = await provider.analyze(toolOptions);
|
|
280
|
-
|
|
281
|
-
// Inject sanitized configuration into metadata for audit
|
|
282
|
-
if (output.metadata) {
|
|
283
|
-
output.metadata.config = sanitizeToolConfig(toolOptions);
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
if (options.progressCallback) {
|
|
287
|
-
options.progressCallback({ tool: provider.id, data: output });
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
result[provider.id] = output;
|
|
291
|
-
result.summary.toolsRun.push(provider.id);
|
|
292
|
-
|
|
293
|
-
// Collect tool-specific configuration for the audit log
|
|
294
|
-
if (output.summary?.config) {
|
|
295
|
-
result.summary.toolConfigs![provider.id] = sanitizeToolConfig(
|
|
296
|
-
output.summary.config
|
|
297
|
-
);
|
|
298
|
-
} else if (output.metadata?.config) {
|
|
299
|
-
result.summary.toolConfigs![provider.id] = sanitizeToolConfig(
|
|
300
|
-
output.metadata.config
|
|
301
|
-
);
|
|
302
|
-
} else {
|
|
303
|
-
// Fallback to our sanitized input options if spoke didn't return config
|
|
304
|
-
result.summary.toolConfigs![provider.id] =
|
|
305
|
-
sanitizeToolConfig(toolOptions);
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
// Track total files analyzed across all tools
|
|
309
|
-
const toolFiles =
|
|
310
|
-
output.summary?.totalFiles ?? output.summary?.filesAnalyzed ?? 0;
|
|
311
|
-
if (toolFiles > result.summary.totalFiles) {
|
|
312
|
-
result.summary.totalFiles = toolFiles;
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
const issueCount = output.results.reduce(
|
|
316
|
-
(sum: number, file: any) => sum + (file.issues?.length ?? 0),
|
|
317
|
-
0
|
|
318
|
-
);
|
|
319
|
-
result.summary.totalIssues += issueCount;
|
|
320
|
-
} catch (err) {
|
|
321
|
-
console.error(`❌ Error running tool '${provider.id}':`, err);
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
// Finalize configuration for metadata to match AIReadyConfig schema
|
|
326
|
-
// We use sanitizeConfigRecursive to ensure no internal keys (like rootDir) remain
|
|
327
|
-
result.summary.config = sanitizeConfigRecursive({
|
|
328
|
-
scan: {
|
|
329
|
-
tools: requestedTools,
|
|
330
|
-
include: options.include,
|
|
331
|
-
exclude: options.exclude,
|
|
332
|
-
},
|
|
333
|
-
// Use 'tools' for tool-specific configurations to match AIReadyConfig
|
|
334
|
-
tools: result.summary.toolConfigs,
|
|
335
|
-
});
|
|
336
|
-
|
|
337
|
-
result.summary.executionTime = Date.now() - startTime;
|
|
338
|
-
|
|
339
|
-
// Add backward compatibility key mappings (kebab-case -> camelCase and aliases)
|
|
340
|
-
const keyMappings: Record<string, string[]> = {
|
|
341
|
-
'pattern-detect': ['patternDetect', 'patterns'],
|
|
342
|
-
'context-analyzer': ['contextAnalyzer', 'context'],
|
|
343
|
-
'naming-consistency': ['namingConsistency', 'consistency'],
|
|
344
|
-
'ai-signal-clarity': ['aiSignalClarity'],
|
|
345
|
-
'agent-grounding': ['agentGrounding'],
|
|
346
|
-
'testability-index': ['testabilityIndex', 'testability'],
|
|
347
|
-
'doc-drift': ['docDrift'],
|
|
348
|
-
'dependency-health': ['dependencyHealth', 'deps'],
|
|
349
|
-
'change-amplification': ['changeAmplification'],
|
|
350
|
-
};
|
|
351
|
-
|
|
352
|
-
for (const [kebabKey, aliases] of Object.entries(keyMappings)) {
|
|
353
|
-
if (result[kebabKey]) {
|
|
354
|
-
for (const alias of aliases) {
|
|
355
|
-
result[alias] = result[kebabKey];
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
return result;
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
/**
|
|
364
|
-
* AIReady Unified Scoring.
|
|
365
|
-
* Calculates scores for all analyzed tools.
|
|
366
|
-
*
|
|
367
|
-
* @param results - The consolidated results from a unified analysis.
|
|
368
|
-
* @param options - Analysis options for weighting and budget calculation.
|
|
369
|
-
* @returns Promise resolving to the final scoring result.
|
|
370
|
-
*/
|
|
371
|
-
export async function scoreUnified(
|
|
372
|
-
results: UnifiedAnalysisResult,
|
|
373
|
-
options: UnifiedAnalysisOptions
|
|
374
|
-
): Promise<ScoringResult> {
|
|
375
|
-
const toolScores: Map<string, ToolScoringOutput> = new Map();
|
|
376
|
-
|
|
377
|
-
for (const toolId of results.summary.toolsRun) {
|
|
378
|
-
const provider = ToolRegistry.get(toolId as ToolName);
|
|
379
|
-
if (!provider) continue;
|
|
380
|
-
|
|
381
|
-
const output = results[toolId];
|
|
382
|
-
if (!output) continue;
|
|
383
|
-
|
|
384
|
-
try {
|
|
385
|
-
const toolScore = provider.score(output, options);
|
|
386
|
-
|
|
387
|
-
// Special handling for token budget calculation if not provided by tool
|
|
388
|
-
if (!toolScore.tokenBudget) {
|
|
389
|
-
if (toolId === ToolName.PatternDetect && (output as any).duplicates) {
|
|
390
|
-
const wastedTokens = (output as any).duplicates.reduce(
|
|
391
|
-
(sum: number, d: any) => sum + (d.tokenCost ?? 0),
|
|
392
|
-
0
|
|
393
|
-
);
|
|
394
|
-
toolScore.tokenBudget = calculateTokenBudget({
|
|
395
|
-
totalContextTokens: wastedTokens * 2,
|
|
396
|
-
wastedTokens: {
|
|
397
|
-
duplication: wastedTokens,
|
|
398
|
-
fragmentation: 0,
|
|
399
|
-
chattiness: 0,
|
|
400
|
-
},
|
|
401
|
-
});
|
|
402
|
-
} else if (toolId === ToolName.ContextAnalyzer && output.summary) {
|
|
403
|
-
toolScore.tokenBudget = calculateTokenBudget({
|
|
404
|
-
totalContextTokens: output.summary.totalTokens,
|
|
405
|
-
wastedTokens: {
|
|
406
|
-
duplication: 0,
|
|
407
|
-
fragmentation: output.summary.totalPotentialSavings ?? 0,
|
|
408
|
-
chattiness: 0,
|
|
409
|
-
},
|
|
410
|
-
});
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
toolScores.set(toolId, toolScore);
|
|
415
|
-
} catch (err) {
|
|
416
|
-
console.error(`❌ Error scoring tool '${toolId}':`, err);
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
// Handle case where toolScores is empty
|
|
421
|
-
if (toolScores.size === 0) {
|
|
422
|
-
return {
|
|
423
|
-
overall: 0,
|
|
424
|
-
rating: 'Critical',
|
|
425
|
-
timestamp: new Date().toISOString(),
|
|
426
|
-
toolsUsed: [],
|
|
427
|
-
breakdown: [],
|
|
428
|
-
calculation: {
|
|
429
|
-
formula: '0 / 0 = 0',
|
|
430
|
-
weights: {},
|
|
431
|
-
normalized: '0 / 0 = 0',
|
|
432
|
-
},
|
|
433
|
-
} as ScoringResult;
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
return calculateOverallScore(toolScores, options, undefined);
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
/**
|
|
440
|
-
* Generate human-readable summary of unified results.
|
|
441
|
-
*
|
|
442
|
-
* @param result - The consolidated analysis result object.
|
|
443
|
-
* @returns Formatted summary string.
|
|
444
|
-
*/
|
|
445
|
-
export function generateUnifiedSummary(result: UnifiedAnalysisResult): string {
|
|
446
|
-
const { summary } = result;
|
|
447
|
-
let output = `🚀 AIReady Analysis Complete\n\n`;
|
|
448
|
-
output += `📊 Summary:\n`;
|
|
449
|
-
output += ` Tools run: ${summary.toolsRun.join(', ')}\n`;
|
|
450
|
-
output += ` Total issues found: ${summary.totalIssues}\n`;
|
|
451
|
-
output += ` Execution time: ${(summary.executionTime / 1000).toFixed(2)}s\n\n`;
|
|
452
|
-
|
|
453
|
-
for (const provider of ToolRegistry.getAll()) {
|
|
454
|
-
const toolResult = result[provider.id];
|
|
455
|
-
if (toolResult) {
|
|
456
|
-
const issueCount = toolResult.results.reduce(
|
|
457
|
-
(sum: number, r: any) => sum + (r.issues?.length ?? 0),
|
|
458
|
-
0
|
|
459
|
-
);
|
|
460
|
-
output += `• ${provider.id}: ${issueCount} issues\n`;
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
return output;
|
|
465
|
-
}
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import {
|
|
3
|
-
getReportTimestamp,
|
|
4
|
-
truncateArray,
|
|
5
|
-
generateMarkdownReport,
|
|
6
|
-
} from '../helpers';
|
|
7
|
-
|
|
8
|
-
describe('CLI Helpers', () => {
|
|
9
|
-
it('should generate a valid timestamp', () => {
|
|
10
|
-
const ts = getReportTimestamp();
|
|
11
|
-
expect(ts).toMatch(/^\d{8}-\d{6}$/);
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
it('should truncate arrays correctly', () => {
|
|
15
|
-
const arr = [1, 2, 3, 4, 5];
|
|
16
|
-
expect(truncateArray(arr, 3)).toContain('+2 more');
|
|
17
|
-
expect(truncateArray(arr, 10)).toBe('1, 2, 3, 4, 5');
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
it('should generate markdown report', () => {
|
|
21
|
-
const report = {
|
|
22
|
-
summary: {
|
|
23
|
-
filesAnalyzed: 10,
|
|
24
|
-
totalIssues: 5,
|
|
25
|
-
namingIssues: 2,
|
|
26
|
-
patternIssues: 3,
|
|
27
|
-
},
|
|
28
|
-
recommendations: ['Fix naming'],
|
|
29
|
-
};
|
|
30
|
-
const md = generateMarkdownReport(report, '1.5');
|
|
31
|
-
expect(md).toContain('# Consistency Analysis Report');
|
|
32
|
-
expect(md).toContain('**Files Analyzed:** 10');
|
|
33
|
-
expect(md).toContain('Fix naming');
|
|
34
|
-
});
|
|
35
|
-
});
|