@aiready/cli 0.14.2 → 0.14.4

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.
Files changed (44) hide show
  1. package/.aiready/aiready-report-20260314-164626.json +2 -5
  2. package/.aiready/aiready-report-20260314-164741.json +2 -5
  3. package/.turbo/turbo-build.log +29 -28
  4. package/.turbo/turbo-lint.log +0 -32
  5. package/.turbo/turbo-test.log +35 -125
  6. package/aiready-report.json +30703 -0
  7. package/dist/cli.js +415 -378
  8. package/dist/cli.mjs +358 -320
  9. package/package.json +12 -12
  10. package/packages/core/src/.aiready/aiready-report-20260314-161145.json +4 -10
  11. package/packages/core/src/.aiready/aiready-report-20260314-161152.json +10 -28
  12. package/packages/pattern-detect/src/.aiready/aiready-report-20260314-161139.json +4 -10
  13. package/src/.aiready/aiready-report-20260312-103623.json +3 -9
  14. package/src/.aiready/aiready-report-20260312-110843.json +3 -9
  15. package/src/.aiready/aiready-report-20260312-110955.json +3 -9
  16. package/src/.aiready/aiready-report-20260314-203209.json +3 -9
  17. package/src/.aiready/aiready-report-20260314-203736.json +3 -9
  18. package/src/.aiready/aiready-report-20260314-203857.json +3 -9
  19. package/src/.aiready/aiready-report-20260314-204047.json +3 -9
  20. package/src/__tests__/cli.test.ts +1 -1
  21. package/src/__tests__/config-shape.test.ts +0 -1
  22. package/src/__tests__/unified.test.ts +1 -1
  23. package/src/cli.ts +2 -1
  24. package/src/commands/__tests__/consistency.test.ts +3 -0
  25. package/src/commands/__tests__/extra-commands.test.ts +29 -38
  26. package/src/commands/__tests__/init.test.ts +56 -0
  27. package/src/commands/__tests__/scan.test.ts +4 -2
  28. package/src/commands/__tests__/upload.test.ts +0 -1
  29. package/src/commands/__tests__/visualize.test.ts +3 -7
  30. package/src/commands/ai-signal-clarity.ts +1 -56
  31. package/src/commands/bug.ts +1 -2
  32. package/src/commands/deps-health.ts +1 -65
  33. package/src/commands/doc-drift.ts +1 -62
  34. package/src/commands/init.ts +58 -2
  35. package/src/commands/patterns.ts +3 -1
  36. package/src/commands/report-formatter.ts +128 -0
  37. package/src/commands/scan.ts +29 -120
  38. package/src/commands/shared/configured-tool-action.ts +35 -0
  39. package/src/commands/shared/standard-tool-actions.ts +126 -0
  40. package/src/commands/upload.ts +15 -13
  41. package/src/commands/visualize.ts +11 -4
  42. package/src/index.ts +18 -3
  43. package/src/utils/helpers.ts +86 -37
  44. package/vitest.config.ts +5 -12
@@ -9,28 +9,20 @@ import {
9
9
  loadMergedConfig,
10
10
  handleJSONOutput,
11
11
  handleCLIError,
12
- getElapsedTime,
13
12
  resolveOutputPath,
14
- formatScore,
15
- formatToolScore,
16
- calculateTokenBudget,
17
- estimateCostFromBudget,
18
- getModelPreset,
19
- getRating,
20
- getRatingDisplay,
21
13
  getRepoMetadata,
22
- Severity,
23
- IssueType,
14
+ calculateTokenBudget,
24
15
  ToolName,
25
- ToolRegistry,
26
16
  emitIssuesAsAnnotations,
27
17
  } from '@aiready/core';
28
18
  import { analyzeUnified, scoreUnified, type ScoringResult } from '../index';
19
+ import { getReportTimestamp, warnIfGraphCapExceeded } from '../utils/helpers';
29
20
  import {
30
- getReportTimestamp,
31
- warnIfGraphCapExceeded,
32
- truncateArray,
33
- } from '../utils/helpers';
21
+ printScanSummary,
22
+ printBusinessImpact,
23
+ printScoring,
24
+ mapToUnifiedReport,
25
+ } from './report-formatter';
34
26
  import { uploadAction } from './upload';
35
27
 
36
28
  interface ScanOptions {
@@ -53,6 +45,14 @@ interface ScanOptions {
53
45
  server?: string;
54
46
  }
55
47
 
48
+ /**
49
+ * CLI action handler for the "scan" command.
50
+ * Runs a comprehensive AI-readiness analysis across multiple tools,
51
+ * including pattern detection, context analysis, and naming consistency.
52
+ *
53
+ * @param directory - The directory to analyze (defaults to ".")
54
+ * @param options - CLI options from commander
55
+ */
56
56
  export async function scanAction(directory: string, options: ScanOptions) {
57
57
  console.log(chalk.blue('šŸš€ Starting AIReady unified analysis...\n'));
58
58
 
@@ -151,7 +151,7 @@ export async function scanAction(directory: string, options: ScanOptions) {
151
151
  )) as any;
152
152
 
153
153
  // Apply smart defaults for pattern detection if requested
154
- let finalOptions = { ...baseOptions };
154
+ const finalOptions = { ...baseOptions };
155
155
  if (
156
156
  baseOptions.tools.includes(ToolName.PatternDetect) ||
157
157
  baseOptions.tools.includes('patterns')
@@ -211,13 +211,7 @@ export async function scanAction(directory: string, options: ScanOptions) {
211
211
  suppressToolConfig: true,
212
212
  });
213
213
 
214
- console.log(chalk.cyan('\n=== AIReady Run Summary ==='));
215
- console.log(
216
- ` Total issues (all tools): ${chalk.bold(String(results.summary.totalIssues || 0))}`
217
- );
218
- console.log(
219
- ` Execution time: ${chalk.bold(((Date.now() - startTime) / 1000).toFixed(2) + 's')}`
220
- );
214
+ printScanSummary(results, startTime);
221
215
 
222
216
  let scoringResult: ScoringResult | undefined;
223
217
  if (options.score || finalOptions.scoring?.showBreakdown) {
@@ -230,9 +224,7 @@ export async function scanAction(directory: string, options: ScanOptions) {
230
224
  },
231
225
  });
232
226
 
233
- console.log(chalk.bold('\nšŸ“Š AI Readiness Overall Score'));
234
- console.log(` ${formatScore(scoringResult)}`);
235
- console.log(chalk.dim(` (Scoring Profile: ${scoringProfile})`));
227
+ printScoring(scoringResult, scoringProfile);
236
228
 
237
229
  // Trend comparison logic
238
230
  if (options.compareTo) {
@@ -315,19 +307,7 @@ export async function scanAction(directory: string, options: ScanOptions) {
315
307
  modelId: modelId,
316
308
  });
317
309
 
318
- console.log(chalk.bold('\nšŸ’° Business Impact Analysis (Monthly)'));
319
- console.log(
320
- ` Potential Savings: ${chalk.green(chalk.bold('$' + roi.monthlySavings.toLocaleString()))}`
321
- );
322
- console.log(
323
- ` Productivity Gain: ${chalk.cyan(chalk.bold(roi.productivityGainHours + 'h'))} (est. dev time)`
324
- );
325
- console.log(
326
- ` Context Efficiency: ${chalk.yellow((unifiedBudget.efficiencyRatio * 100).toFixed(0) + '%')}`
327
- );
328
- console.log(
329
- ` Annual Value: ${chalk.bold('$' + roi.annualValue.toLocaleString())} (ROI Prediction)`
330
- );
310
+ printBusinessImpact(roi, unifiedBudget);
331
311
 
332
312
  (results.summary as any).businessImpact = {
333
313
  estimatedMonthlyWaste: roi.monthlySavings,
@@ -338,43 +318,6 @@ export async function scanAction(directory: string, options: ScanOptions) {
338
318
  (scoringResult as any).tokenBudget = unifiedBudget;
339
319
  (scoringResult as any).businessROI = roi;
340
320
  }
341
-
342
- if (scoringResult.breakdown) {
343
- console.log(chalk.bold('\nTool breakdown:'));
344
- scoringResult.breakdown.forEach((tool) => {
345
- const rating = getRating(tool.score);
346
- const emoji = getRatingDisplay(rating).emoji;
347
- console.log(
348
- ` - ${tool.toolName}: ${tool.score}/100 (${rating}) ${emoji}`
349
- );
350
- });
351
-
352
- // Top Actionable Recommendations
353
- const allRecs = scoringResult.breakdown
354
- .flatMap((t) =>
355
- (t.recommendations || []).map((r) => ({ ...r, tool: t.toolName }))
356
- )
357
- .sort((a, b) => b.estimatedImpact - a.estimatedImpact)
358
- .slice(0, 3);
359
-
360
- if (allRecs.length > 0) {
361
- console.log(chalk.bold('\nšŸŽÆ Top Actionable Recommendations:'));
362
- allRecs.forEach((rec, i) => {
363
- const priorityIcon =
364
- rec.priority === 'high'
365
- ? 'šŸ”“'
366
- : rec.priority === 'medium'
367
- ? '🟔'
368
- : 'šŸ”µ';
369
- console.log(
370
- ` ${i + 1}. ${priorityIcon} ${chalk.bold(rec.action)}`
371
- );
372
- console.log(
373
- ` Impact: ${chalk.green(`+${rec.estimatedImpact} points`)} to ${rec.tool}`
374
- );
375
- });
376
- }
377
- }
378
321
  }
379
322
 
380
323
  console.log(
@@ -395,43 +338,6 @@ export async function scanAction(directory: string, options: ScanOptions) {
395
338
  )
396
339
  );
397
340
 
398
- // Normalized report mapping
399
- const mapToUnifiedReport = (
400
- res: any,
401
- scoring: ScoringResult | undefined
402
- ) => {
403
- const allResults: any[] = [];
404
- const totalFilesSet = new Set<string>();
405
- let criticalCount = 0;
406
- let majorCount = 0;
407
-
408
- res.summary.toolsRun.forEach((toolId: string) => {
409
- const spokeRes = res[toolId];
410
- if (!spokeRes || !spokeRes.results) return;
411
-
412
- spokeRes.results.forEach((r: any) => {
413
- totalFilesSet.add(r.fileName);
414
- allResults.push(r);
415
- r.issues?.forEach((i: any) => {
416
- if (i.severity === Severity.Critical) criticalCount++;
417
- if (i.severity === Severity.Major) majorCount++;
418
- });
419
- });
420
- });
421
-
422
- return {
423
- ...res,
424
- results: allResults,
425
- summary: {
426
- ...res.summary,
427
- totalFiles: totalFilesSet.size,
428
- criticalIssues: criticalCount,
429
- majorIssues: majorCount,
430
- },
431
- scoring,
432
- };
433
- };
434
-
435
341
  const outputData = {
436
342
  ...mapToUnifiedReport(results, scoringResult),
437
343
  repository: repoMetadata,
@@ -469,20 +375,20 @@ export async function scanAction(directory: string, options: ScanOptions) {
469
375
  }
470
376
  await warnIfGraphCapExceeded(outputData, resolvedDir);
471
377
 
472
- // CI/CD Gatekeeper logic
473
- const isCI = options.ci || process.env.CI === 'true';
474
- if (isCI && scoringResult) {
378
+ // Score Check & Gatekeeper logic
379
+ if (scoringResult) {
475
380
  const threshold = options.threshold
476
381
  ? parseInt(options.threshold)
477
382
  : undefined;
478
383
  const failOnLevel = options.failOn || 'critical';
384
+ const isCI = options.ci || process.env.CI === 'true';
479
385
 
480
386
  let shouldFail = false;
481
387
  let failReason = '';
482
388
 
483
- // Emit annotations for all issues found
389
+ // Emit annotations only in CI
484
390
  const report = mapToUnifiedReport(results, scoringResult);
485
- if (report.results && report.results.length > 0) {
391
+ if (isCI && report.results && report.results.length > 0) {
486
392
  console.log(
487
393
  chalk.cyan(
488
394
  `\nšŸ“ Emitting GitHub Action annotations for ${report.results.length} issues...`
@@ -495,6 +401,9 @@ export async function scanAction(directory: string, options: ScanOptions) {
495
401
  shouldFail = true;
496
402
  failReason = `Score ${scoringResult.overall} < threshold ${threshold}`;
497
403
  }
404
+
405
+ // If failOnLevel is set (default 'critical'), check for issues
406
+ // But only fail if not 'none'
498
407
  if (failOnLevel !== 'none') {
499
408
  if (failOnLevel === 'critical' && report.summary.criticalIssues > 0) {
500
409
  shouldFail = true;
@@ -509,10 +418,10 @@ export async function scanAction(directory: string, options: ScanOptions) {
509
418
  }
510
419
 
511
420
  if (shouldFail) {
512
- console.log(chalk.red(`\n🚫 PR BLOCKED: ${failReason}`));
421
+ console.log(chalk.red(`\n🚫 SCAN FAILED: ${failReason}`));
513
422
  process.exit(1);
514
423
  } else {
515
- console.log(chalk.green('\nāœ… PR PASSED'));
424
+ console.log(chalk.green('\nāœ… SCAN PASSED'));
516
425
  }
517
426
  }
518
427
  } catch (error) {
@@ -0,0 +1,35 @@
1
+ import type { ToolScoringOutput } from '@aiready/core';
2
+ import { runConfiguredToolCommand } from '../../utils/helpers';
3
+
4
+ export interface ConfiguredToolActionConfig<TReport> {
5
+ defaults: Record<string, unknown>;
6
+ analyze: (scanOptions: any) => Promise<TReport>;
7
+ getExtras: (
8
+ options: any,
9
+ merged: Record<string, unknown>
10
+ ) => Record<string, unknown>;
11
+ score: (report: TReport) => ToolScoringOutput;
12
+ render: (report: TReport, scoring: ToolScoringOutput) => void;
13
+ }
14
+
15
+ export async function runConfiguredToolAction<TReport>(
16
+ directory: string,
17
+ options: any,
18
+ config: ConfiguredToolActionConfig<TReport>
19
+ ): Promise<ToolScoringOutput | undefined> {
20
+ const { report, scoring } = await runConfiguredToolCommand({
21
+ directory,
22
+ options,
23
+ defaults: config.defaults,
24
+ analyze: config.analyze,
25
+ getExtras: config.getExtras,
26
+ score: config.score,
27
+ });
28
+
29
+ if (options.output === 'json') {
30
+ return scoring;
31
+ }
32
+
33
+ config.render(report, scoring);
34
+ return scoring;
35
+ }
@@ -0,0 +1,126 @@
1
+ /**
2
+ * Shared implementations for standard config-driven CLI actions.
3
+ */
4
+
5
+ import chalk from 'chalk';
6
+ import type { ToolScoringOutput } from '@aiready/core';
7
+ import { buildToolScoringOutput } from '../../utils/helpers';
8
+ import { runConfiguredToolAction } from './configured-tool-action';
9
+
10
+ export async function docDriftAction(
11
+ directory: string,
12
+ options: any
13
+ ): Promise<ToolScoringOutput | undefined> {
14
+ const { analyzeDocDrift } = await import('@aiready/doc-drift');
15
+
16
+ return runConfiguredToolAction(directory, options, {
17
+ defaults: { staleMonths: 6 },
18
+ analyze: analyzeDocDrift as any,
19
+ getExtras: (cmdOptions, merged) => ({
20
+ staleMonths: cmdOptions.staleMonths ?? merged.staleMonths ?? 6,
21
+ }),
22
+ score: (toolReport): ToolScoringOutput =>
23
+ buildToolScoringOutput('doc-drift', toolReport as any),
24
+ render: (report: any, scoring) => {
25
+ const { summary } = report;
26
+ const ratingColors: Record<string, (s: string) => string> = {
27
+ minimal: chalk.green,
28
+ low: chalk.cyan,
29
+ moderate: chalk.yellow,
30
+ high: chalk.red,
31
+ severe: chalk.bgRed.white,
32
+ };
33
+ const color = ratingColors[summary.rating] ?? chalk.white;
34
+ console.log(
35
+ ` šŸ“ Documentation Drift: ${chalk.bold(100 - scoring.score + '/100 health')} (${color(summary.rating)} risk)`
36
+ );
37
+ if (report.issues.length > 0) {
38
+ console.log(
39
+ chalk.dim(` Found ${report.issues.length} drift issues.`)
40
+ );
41
+ } else {
42
+ console.log(chalk.dim(` No documentation drift detected.`));
43
+ }
44
+ },
45
+ });
46
+ }
47
+
48
+ export async function depsHealthAction(
49
+ directory: string,
50
+ options: any
51
+ ): Promise<ToolScoringOutput | undefined> {
52
+ const { analyzeDeps } = await import('@aiready/deps');
53
+
54
+ return runConfiguredToolAction(directory, options, {
55
+ defaults: { trainingCutoffYear: 2023 },
56
+ analyze: analyzeDeps as any,
57
+ getExtras: (cmdOptions, merged) => ({
58
+ trainingCutoffYear:
59
+ cmdOptions.trainingCutoffYear ?? merged.trainingCutoffYear ?? 2023,
60
+ }),
61
+ score: (toolReport): ToolScoringOutput =>
62
+ buildToolScoringOutput('dependency-health', toolReport as any),
63
+ render: (report: any, scoring) => {
64
+ const { summary } = report;
65
+ const ratingColors: Record<string, (s: string) => string> = {
66
+ excellent: chalk.green,
67
+ good: chalk.blueBright,
68
+ moderate: chalk.yellow,
69
+ poor: chalk.red,
70
+ hazardous: chalk.bgRed.white,
71
+ };
72
+ const color = ratingColors[summary.rating] ?? chalk.white;
73
+ console.log(
74
+ ` šŸ“¦ Dependency Health: ${chalk.bold(scoring.score + '/100 health')} (${color(summary.rating)})`
75
+ );
76
+ if (report.issues.length > 0) {
77
+ console.log(
78
+ chalk.dim(` Found ${report.issues.length} dependency issues.`)
79
+ );
80
+ } else {
81
+ console.log(
82
+ chalk.dim(` Dependencies look healthy for AI assistance.`)
83
+ );
84
+ }
85
+ },
86
+ });
87
+ }
88
+
89
+ export async function aiSignalClarityAction(
90
+ directory: string,
91
+ options: any
92
+ ): Promise<ToolScoringOutput | undefined> {
93
+ const { analyzeAiSignalClarity, calculateAiSignalClarityScore } =
94
+ await import('@aiready/ai-signal-clarity');
95
+
96
+ return runConfiguredToolAction(directory, options, {
97
+ defaults: { minSeverity: 'info' },
98
+ analyze: analyzeAiSignalClarity as any,
99
+ getExtras: (cmdOptions, merged) => ({
100
+ minSeverity: cmdOptions.minSeverity ?? merged.minSeverity ?? 'info',
101
+ }),
102
+ score: (toolReport) => calculateAiSignalClarityScore(toolReport as any),
103
+ render: (report: any, scoring) => {
104
+ const { summary } = report;
105
+ const ratingColors: Record<string, (s: string) => string> = {
106
+ minimal: chalk.green,
107
+ low: chalk.cyan,
108
+ moderate: chalk.yellow,
109
+ high: chalk.red,
110
+ severe: chalk.bgRed.white,
111
+ };
112
+ const color = ratingColors[summary.rating] ?? chalk.white;
113
+ console.log(
114
+ ` 🧠 AI Signal Clarity: ${chalk.bold(scoring.score + '/100')} (${color(summary.rating)})`
115
+ );
116
+ console.log(` Top Risk: ${chalk.italic(summary.topRisk)}`);
117
+ if (summary.totalSignals > 0) {
118
+ console.log(
119
+ chalk.dim(
120
+ ` ${summary.criticalSignals} critical ${summary.majorSignals} major ${summary.minorSignals} minor signals`
121
+ )
122
+ );
123
+ }
124
+ },
125
+ });
126
+ }
@@ -51,7 +51,7 @@ export async function uploadAction(file: string, options: UploadOptions) {
51
51
  // Note: repoId is optional if the metadata contains it, but for now we'll require it or infer from metadata
52
52
  const repoId = options.repoId || reportData.repository?.repoId;
53
53
 
54
- const res = await fetch(`${serverUrl}/api/analysis/upload`, {
54
+ const response = await fetch(`${serverUrl}/api/analysis/upload`, {
55
55
  method: 'POST',
56
56
  headers: {
57
57
  'Content-Type': 'application/json',
@@ -63,19 +63,21 @@ export async function uploadAction(file: string, options: UploadOptions) {
63
63
  }),
64
64
  });
65
65
 
66
- const contentType = res.headers.get('content-type');
67
- let result: any = {};
66
+ const contentType = response.headers.get('content-type');
67
+ let uploadResult: any = {};
68
68
 
69
69
  if (contentType?.includes('application/json')) {
70
- result = await res.json();
70
+ uploadResult = await response.json();
71
71
  } else {
72
- const text = await res.text();
73
- result = { error: text || res.statusText };
72
+ const text = await response.text();
73
+ uploadResult = { error: text || response.statusText };
74
74
  }
75
75
 
76
- if (!res.ok) {
76
+ if (!response.ok) {
77
77
  console.error(
78
- chalk.red(`āŒ Upload failed: ${result.error || res.statusText}`)
78
+ chalk.red(
79
+ `āŒ Upload failed: ${uploadResult.error || response.statusText}`
80
+ )
79
81
  );
80
82
 
81
83
  // Special case for redirects or HTML error pages
@@ -85,7 +87,7 @@ export async function uploadAction(file: string, options: UploadOptions) {
85
87
  ' Note: Received an HTML response. This often indicates a redirect (e.g., to a login page) or a server error.'
86
88
  )
87
89
  );
88
- if (result.error?.includes('Redirecting')) {
90
+ if (uploadResult.error?.includes('Redirecting')) {
89
91
  console.log(
90
92
  chalk.dim(
91
93
  ' Detected redirect. Check if the API endpoint requires authentication or has changed.'
@@ -94,7 +96,7 @@ export async function uploadAction(file: string, options: UploadOptions) {
94
96
  }
95
97
  }
96
98
 
97
- if (res.status === 401) {
99
+ if (response.status === 401) {
98
100
  console.log(
99
101
  chalk.dim(' Hint: Your API key may be invalid or expired.')
100
102
  );
@@ -106,9 +108,9 @@ export async function uploadAction(file: string, options: UploadOptions) {
106
108
  console.log(chalk.green(`\nāœ… Upload successful! (${duration}s)`));
107
109
  console.log(chalk.cyan(` View results: ${serverUrl}/dashboard`));
108
110
 
109
- if (result.analysis) {
110
- console.log(chalk.dim(` Analysis ID: ${result.analysis.id}`));
111
- console.log(chalk.dim(` Score: ${result.analysis.aiScore}/100`));
111
+ if (uploadResult.analysis) {
112
+ console.log(chalk.dim(` Analysis ID: ${uploadResult.analysis.id}`));
113
+ console.log(chalk.dim(` Score: ${uploadResult.analysis.aiScore}/100`));
112
114
  }
113
115
  } catch (error) {
114
116
  handleCLIError(error, 'Upload');
@@ -7,8 +7,7 @@ import { writeFileSync, readFileSync, existsSync, copyFileSync } from 'fs';
7
7
  import { resolve as resolvePath } from 'path';
8
8
  import { spawn } from 'child_process';
9
9
  import { handleCLIError } from '@aiready/core';
10
- import { generateHTML } from '@aiready/core';
11
- import { findLatestScanReport } from '../utils/helpers';
10
+ import { generateHTML, findLatestReport } from '@aiready/core';
12
11
 
13
12
  interface VisualizeOptions {
14
13
  report?: string;
@@ -18,6 +17,14 @@ interface VisualizeOptions {
18
17
  dev?: boolean;
19
18
  }
20
19
 
20
+ /**
21
+ * CLI action handler for the "visualize" command.
22
+ * Generates an interactive dependency graph visualization of the project
23
+ * to help understand code structure and AI context usage.
24
+ *
25
+ * @param directory - The directory to analyze and visualize
26
+ * @param options - CLI options from commander
27
+ */
21
28
  export async function visualizeAction(
22
29
  directory: string,
23
30
  options: VisualizeOptions
@@ -30,7 +37,7 @@ export async function visualizeAction(
30
37
 
31
38
  // If report not provided or not found, try to find latest scan report
32
39
  if (!reportPath || !existsSync(reportPath)) {
33
- const latestScan = findLatestScanReport(dirPath);
40
+ const latestScan = findLatestReport(dirPath);
34
41
  if (latestScan) {
35
42
  reportPath = latestScan;
36
43
  console.log(
@@ -221,7 +228,7 @@ export async function visualizeAction(
221
228
 
222
229
  // Generate static HTML (default behavior or fallback from failed --dev)
223
230
  console.log('Generating HTML...');
224
- const html = generateHTML(graph);
231
+ const html = generateHTML(graph as any);
225
232
  const defaultOutput = 'visualization.html';
226
233
  const outPath = resolvePath(dirPath, options.output || defaultOutput);
227
234
  writeFileSync(outPath, html, 'utf8');
package/src/index.ts CHANGED
@@ -3,15 +3,12 @@ import {
3
3
  ToolName,
4
4
  calculateOverallScore,
5
5
  calculateTokenBudget,
6
- GLOBAL_SCAN_OPTIONS,
7
6
  GLOBAL_INFRA_OPTIONS,
8
7
  COMMON_FINE_TUNING_OPTIONS,
9
8
  initializeParsers,
10
9
  } from '@aiready/core';
11
10
  import type {
12
- AnalysisResult,
13
11
  ScanOptions,
14
- SpokeOutput,
15
12
  ToolScoringOutput,
16
13
  ScoringResult,
17
14
  } from '@aiready/core';
@@ -29,16 +26,30 @@ import '@aiready/change-amplification';
29
26
 
30
27
  export type { ToolScoringOutput, ScoringResult };
31
28
 
29
+ /**
30
+ * Options for running a unified AI-readiness analysis across multiple tools.
31
+ * Extends base ScanOptions with CLI-specific configurations.
32
+ */
32
33
  export interface UnifiedAnalysisOptions extends ScanOptions {
34
+ /** Root directory for analysis */
33
35
  rootDir: string;
36
+ /** List of tools to run (e.g. ['patterns', 'context']) */
34
37
  tools?: string[];
38
+ /** Overrides for specific tool configurations */
35
39
  toolConfigs?: Record<string, any>;
40
+ /** Minimum similarity threshold for pattern detection (0-1) */
36
41
  minSimilarity?: number;
42
+ /** Minimum number of lines for a pattern to be considered */
37
43
  minLines?: number;
44
+ /** Maximum number of candidates to check per code block */
38
45
  maxCandidatesPerBlock?: number;
46
+ /** Minimum number of shared tokens for a match */
39
47
  minSharedTokens?: number;
48
+ /** Whether to use optimized defaults based on project size/language */
40
49
  useSmartDefaults?: boolean;
50
+ /** Specific options for naming consistency analysis */
41
51
  consistency?: any;
52
+ /** Optional callback for tracking analysis progress */
42
53
  progressCallback?: (event: {
43
54
  tool: string;
44
55
  data?: any;
@@ -48,6 +59,10 @@ export interface UnifiedAnalysisOptions extends ScanOptions {
48
59
  }) => void;
49
60
  }
50
61
 
62
+ /**
63
+ * The consolidated result of a unified analysis across all requested tools.
64
+ * Contains tool-specific outputs, scoring, and a high-level summary.
65
+ */
51
66
  export interface UnifiedAnalysisResult {
52
67
  // Dynamic keys based on ToolName
53
68
  [key: string]: any;