@aiready/cli 0.9.39 → 0.9.41

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.
@@ -8,9 +8,10 @@ import type { ToolScoringOutput } from '@aiready/core';
8
8
 
9
9
  export async function testabilityAction(
10
10
  directory: string,
11
- options: any,
11
+ options: any
12
12
  ): Promise<ToolScoringOutput | undefined> {
13
- const { analyzeTestability, calculateTestabilityScore } = await import('@aiready/testability');
13
+ const { analyzeTestability, calculateTestabilityScore } =
14
+ await import('@aiready/testability');
14
15
 
15
16
  const config = await loadConfig(directory);
16
17
  const merged = mergeConfigWithDefaults(config, {
@@ -31,13 +32,13 @@ export async function testabilityAction(
31
32
  }
32
33
 
33
34
  const safetyIcons: Record<string, string> = {
34
- 'safe': '✅',
35
+ safe: '✅',
35
36
  'moderate-risk': '⚠️ ',
36
37
  'high-risk': '🔴',
37
38
  'blind-risk': '💀',
38
39
  };
39
- const safetyColors: Record<string, Function> = {
40
- 'safe': chalk.green,
40
+ const safetyColors: Record<string, (s: string) => string> = {
41
+ safe: chalk.green,
41
42
  'moderate-risk': chalk.yellow,
42
43
  'high-risk': chalk.red,
43
44
  'blind-risk': chalk.bgRed.white,
@@ -47,13 +48,25 @@ export async function testabilityAction(
47
48
  const icon = safetyIcons[safety] ?? '❓';
48
49
  const color = safetyColors[safety] ?? chalk.white;
49
50
 
50
- console.log(` 🧪 Testability: ${chalk.bold(scoring.score + '/100')} (${report.summary.rating})`);
51
- console.log(` AI Change Safety: ${color(`${icon} ${safety.toUpperCase()}`)}`);
52
- console.log(chalk.dim(` Coverage: ${Math.round(report.summary.coverageRatio * 100)}% (${report.rawData.testFiles} test / ${report.rawData.sourceFiles} source files)`));
51
+ console.log(
52
+ ` 🧪 Testability: ${chalk.bold(scoring.score + '/100')} (${report.summary.rating})`
53
+ );
54
+ console.log(
55
+ ` AI Change Safety: ${color(`${icon} ${safety.toUpperCase()}`)}`
56
+ );
57
+ console.log(
58
+ chalk.dim(
59
+ ` Coverage: ${Math.round(report.summary.coverageRatio * 100)}% (${report.rawData.testFiles} test / ${report.rawData.sourceFiles} source files)`
60
+ )
61
+ );
53
62
 
54
63
  // Critical blind-risk banner in the unified output
55
64
  if (safety === 'blind-risk') {
56
- console.log(chalk.red.bold('\n ⚠️ NO TESTS — AI changes to this codebase are completely unverifiable!\n'));
65
+ console.log(
66
+ chalk.red.bold(
67
+ '\n ⚠️ NO TESTS — AI changes to this codebase are completely unverifiable!\n'
68
+ )
69
+ );
57
70
  }
58
71
 
59
72
  return scoring;
@@ -18,20 +18,31 @@ interface VisualizeOptions {
18
18
  dev?: boolean;
19
19
  }
20
20
 
21
- export async function visualizeAction(directory: string, options: VisualizeOptions) {
21
+ export async function visualizeAction(
22
+ directory: string,
23
+ options: VisualizeOptions
24
+ ) {
22
25
  try {
23
26
  const dirPath = resolvePath(process.cwd(), directory || '.');
24
- let reportPath = options.report ? resolvePath(dirPath, options.report) : null;
25
-
27
+ let reportPath = options.report
28
+ ? resolvePath(dirPath, options.report)
29
+ : null;
30
+
26
31
  // If report not provided or not found, try to find latest scan report
27
32
  if (!reportPath || !existsSync(reportPath)) {
28
33
  const latestScan = findLatestScanReport(dirPath);
29
34
  if (latestScan) {
30
35
  reportPath = latestScan;
31
- console.log(chalk.dim(`Found latest report: ${latestScan.split('/').pop()}`));
36
+ console.log(
37
+ chalk.dim(`Found latest report: ${latestScan.split('/').pop()}`)
38
+ );
32
39
  } else {
33
40
  console.error(chalk.red('❌ No AI readiness report found'));
34
- console.log(chalk.dim(`\nGenerate a report with:\n aiready scan --output json\n\nOr specify a custom report:\n aiready visualise --report <path-to-report.json>`));
41
+ console.log(
42
+ chalk.dim(
43
+ `\nGenerate a report with:\n aiready scan --output json\n\nOr specify a custom report:\n aiready visualise --report <path-to-report.json>`
44
+ )
45
+ );
35
46
  return;
36
47
  }
37
48
  }
@@ -42,39 +53,42 @@ export async function visualizeAction(directory: string, options: VisualizeOptio
42
53
  // Load config to extract graph caps
43
54
  const configPath = resolvePath(dirPath, 'aiready.json');
44
55
  let graphConfig = { maxNodes: 400, maxEdges: 600 };
45
-
56
+
46
57
  if (existsSync(configPath)) {
47
58
  try {
48
59
  const rawConfig = JSON.parse(readFileSync(configPath, 'utf8'));
49
60
  if (rawConfig.visualizer?.graph) {
50
61
  graphConfig = {
51
- maxNodes: rawConfig.visualizer.graph.maxNodes ?? graphConfig.maxNodes,
52
- maxEdges: rawConfig.visualizer.graph.maxEdges ?? graphConfig.maxEdges,
62
+ maxNodes:
63
+ rawConfig.visualizer.graph.maxNodes ?? graphConfig.maxNodes,
64
+ maxEdges:
65
+ rawConfig.visualizer.graph.maxEdges ?? graphConfig.maxEdges,
53
66
  };
54
67
  }
55
68
  } catch (e) {
69
+ void e;
56
70
  // Silently ignore parse errors and use defaults
57
71
  }
58
72
  }
59
-
73
+
60
74
  // Store config in env for vite middleware to pass to client
61
75
  const envVisualizerConfig = JSON.stringify(graphConfig);
62
76
  process.env.AIREADY_VISUALIZER_CONFIG = envVisualizerConfig;
63
77
 
64
- console.log("Building graph from report...");
78
+ console.log('Building graph from report...');
65
79
  const { GraphBuilder } = await import('@aiready/visualizer/graph');
66
80
  const graph = GraphBuilder.buildFromReport(report, dirPath);
67
81
 
68
82
  // Check if --dev mode is requested and available
69
83
  let useDevMode = options.dev || false;
70
84
  let devServerStarted = false;
71
-
85
+
72
86
  if (useDevMode) {
73
87
  try {
74
88
  const monorepoWebDir = resolvePath(dirPath, 'packages/visualizer');
75
89
  let webDir = '';
76
90
  let visualizerAvailable = false;
77
-
91
+
78
92
  if (existsSync(monorepoWebDir)) {
79
93
  webDir = monorepoWebDir;
80
94
  visualizerAvailable = true;
@@ -82,41 +96,54 @@ export async function visualizeAction(directory: string, options: VisualizeOptio
82
96
  // Try to resolve installed @aiready/visualizer package from node_modules
83
97
  const nodemodulesLocations: string[] = [
84
98
  resolvePath(dirPath, 'node_modules', '@aiready', 'visualizer'),
85
- resolvePath(process.cwd(), 'node_modules', '@aiready', 'visualizer'),
99
+ resolvePath(
100
+ process.cwd(),
101
+ 'node_modules',
102
+ '@aiready',
103
+ 'visualizer'
104
+ ),
86
105
  ];
87
-
106
+
88
107
  // Walk up directory tree to find node_modules in parent directories
89
108
  let currentDir = dirPath;
90
109
  while (currentDir !== '/' && currentDir !== '.') {
91
- nodemodulesLocations.push(resolvePath(currentDir, 'node_modules', '@aiready', 'visualizer'));
110
+ nodemodulesLocations.push(
111
+ resolvePath(currentDir, 'node_modules', '@aiready', 'visualizer')
112
+ );
92
113
  const parent = resolvePath(currentDir, '..');
93
114
  if (parent === currentDir) break;
94
115
  currentDir = parent;
95
116
  }
96
-
117
+
97
118
  for (const location of nodemodulesLocations) {
98
- if (existsSync(location) && existsSync(resolvePath(location, 'package.json'))) {
119
+ if (
120
+ existsSync(location) &&
121
+ existsSync(resolvePath(location, 'package.json'))
122
+ ) {
99
123
  webDir = location;
100
124
  visualizerAvailable = true;
101
125
  break;
102
126
  }
103
127
  }
104
-
128
+
105
129
  // Fallback: try require.resolve
106
130
  if (!visualizerAvailable) {
107
131
  try {
108
- const vizPkgPath = require.resolve('@aiready/visualizer/package.json');
132
+ const vizPkgPath =
133
+ require.resolve('@aiready/visualizer/package.json');
109
134
  webDir = resolvePath(vizPkgPath, '..');
110
135
  visualizerAvailable = true;
111
- } catch (e) {
136
+ } catch (err) {
137
+ void err;
112
138
  // Visualizer not found
113
139
  }
114
140
  }
115
141
  }
116
-
142
+
117
143
  // Check if web directory with vite config exists (required for dev mode)
118
- const webViteConfigExists = webDir && existsSync(resolvePath(webDir, 'web', 'vite.config.ts'));
119
-
144
+ const webViteConfigExists =
145
+ webDir && existsSync(resolvePath(webDir, 'web', 'vite.config.ts'));
146
+
120
147
  if (visualizerAvailable && webViteConfigExists) {
121
148
  // Dev mode is available - start Vite dev server
122
149
  const spawnCwd = webDir!;
@@ -132,10 +159,10 @@ export async function visualizeAction(directory: string, options: VisualizeOptio
132
159
  console.error('Failed to sync report:', e);
133
160
  }
134
161
  };
135
-
162
+
136
163
  // Initial copy
137
164
  copyReportToViz();
138
-
165
+
139
166
  // Watch source report for changes
140
167
  let watchTimeout: NodeJS.Timeout | null = null;
141
168
  const reportWatcher = watch(reportPath, () => {
@@ -143,45 +170,71 @@ export async function visualizeAction(directory: string, options: VisualizeOptio
143
170
  watchTimeout = setTimeout(copyReportToViz, 100);
144
171
  });
145
172
 
146
- const envForSpawn = {
147
- ...process.env,
173
+ const envForSpawn = {
174
+ ...process.env,
148
175
  AIREADY_REPORT_PATH: reportPath,
149
- AIREADY_VISUALIZER_CONFIG: envVisualizerConfig
176
+ AIREADY_VISUALIZER_CONFIG: envVisualizerConfig,
150
177
  };
151
- const vite = spawn("pnpm", ["run", "dev:web"], { cwd: spawnCwd, stdio: "inherit", shell: true, env: envForSpawn });
178
+ const vite = spawn('pnpm', ['run', 'dev:web'], {
179
+ cwd: spawnCwd,
180
+ stdio: 'inherit',
181
+ shell: true,
182
+ env: envForSpawn,
183
+ });
152
184
  const onExit = () => {
153
- try { reportWatcher.close(); } catch (e) {}
154
- try { vite.kill(); } catch (e) {}
185
+ try {
186
+ reportWatcher.close();
187
+ } catch (err) {
188
+ void err;
189
+ }
190
+ try {
191
+ vite.kill();
192
+ } catch (err) {
193
+ void err;
194
+ }
155
195
  process.exit(0);
156
196
  };
157
- process.on("SIGINT", onExit);
158
- process.on("SIGTERM", onExit);
197
+ process.on('SIGINT', onExit);
198
+ process.on('SIGTERM', onExit);
159
199
  devServerStarted = true;
200
+ void devServerStarted;
160
201
  return;
161
202
  } else {
162
- console.log(chalk.yellow('⚠️ Dev server not available (requires local @aiready/visualizer with web assets).'));
163
- console.log(chalk.cyan(' Falling back to static HTML generation...\n'));
203
+ console.log(
204
+ chalk.yellow(
205
+ '⚠️ Dev server not available (requires local @aiready/visualizer with web assets).'
206
+ )
207
+ );
208
+ console.log(
209
+ chalk.cyan(' Falling back to static HTML generation...\n')
210
+ );
164
211
  useDevMode = false;
165
212
  }
166
213
  } catch (err) {
167
- console.error("Failed to start dev server:", err);
168
- console.log(chalk.cyan(' Falling back to static HTML generation...\n'));
214
+ console.error('Failed to start dev server:', err);
215
+ console.log(
216
+ chalk.cyan(' Falling back to static HTML generation...\n')
217
+ );
169
218
  useDevMode = false;
170
219
  }
171
220
  }
172
221
 
173
222
  // Generate static HTML (default behavior or fallback from failed --dev)
174
- console.log("Generating HTML...");
223
+ console.log('Generating HTML...');
175
224
  const html = generateHTML(graph);
176
225
  const defaultOutput = 'visualization.html';
177
226
  const outPath = resolvePath(dirPath, options.output || defaultOutput);
178
227
  writeFileSync(outPath, html, 'utf8');
179
228
  console.log(chalk.green(`✅ Visualization written to: ${outPath}`));
180
-
181
229
 
182
230
  if (options.open || options.serve) {
183
- const opener = process.platform === 'darwin' ? 'open' : process.platform === 'win32' ? 'start' : 'xdg-open';
184
-
231
+ const opener =
232
+ process.platform === 'darwin'
233
+ ? 'open'
234
+ : process.platform === 'win32'
235
+ ? 'start'
236
+ : 'xdg-open';
237
+
185
238
  if (options.serve) {
186
239
  try {
187
240
  const port = typeof options.serve === 'number' ? options.serve : 5173;
@@ -193,13 +246,16 @@ export async function visualizeAction(directory: string, options: VisualizeOptio
193
246
  const urlPath = req.url || '/';
194
247
  if (urlPath === '/' || urlPath === '/index.html') {
195
248
  const content = await fsp.readFile(outPath, 'utf8');
196
- res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
249
+ res.writeHead(200, {
250
+ 'Content-Type': 'text/html; charset=utf-8',
251
+ });
197
252
  res.end(content);
198
253
  return;
199
254
  }
200
255
  res.writeHead(404, { 'Content-Type': 'text/plain' });
201
256
  res.end('Not found');
202
257
  } catch (e: any) {
258
+ void e;
203
259
  res.writeHead(500, { 'Content-Type': 'text/plain' });
204
260
  res.end('Server error');
205
261
  }
@@ -207,7 +263,9 @@ export async function visualizeAction(directory: string, options: VisualizeOptio
207
263
 
208
264
  server.listen(port, () => {
209
265
  const addr = `http://localhost:${port}/`;
210
- console.log(chalk.cyan(`🌐 Local visualization server running at ${addr}`));
266
+ console.log(
267
+ chalk.cyan(`🌐 Local visualization server running at ${addr}`)
268
+ );
211
269
  spawn(opener, [`"${addr}"`], { shell: true });
212
270
  });
213
271
 
@@ -222,7 +280,6 @@ export async function visualizeAction(directory: string, options: VisualizeOptio
222
280
  spawn(opener, [`"${outPath}"`], { shell: true });
223
281
  }
224
282
  }
225
-
226
283
  } catch (err: any) {
227
284
  handleCLIError(err, 'Visualization');
228
285
  }
@@ -254,4 +311,4 @@ EXAMPLES:
254
311
 
255
312
  NOTES:
256
313
  - Same options as 'visualize'. Use --serve to host the static HTML, or --dev for live reload.
257
- `;
314
+ `;
package/src/index.ts CHANGED
@@ -3,13 +3,23 @@ import { analyzeContext } from '@aiready/context-analyzer';
3
3
  import { analyzeConsistency } from '@aiready/consistency';
4
4
  import type { AnalysisResult, ScanOptions } from '@aiready/core';
5
5
  import type { ContextAnalysisResult } from '@aiready/context-analyzer';
6
- import type { PatternDetectOptions, DuplicatePattern } from '@aiready/pattern-detect';
6
+ import type { DuplicatePattern } from '@aiready/pattern-detect';
7
7
  import type { ConsistencyReport } from '@aiready/consistency';
8
8
 
9
9
  import type { ConsistencyOptions } from '@aiready/consistency';
10
10
 
11
11
  export interface UnifiedAnalysisOptions extends ScanOptions {
12
- tools?: ('patterns' | 'context' | 'consistency' | 'doc-drift' | 'deps-health' | 'aiSignalClarity' | 'grounding' | 'testability' | 'changeAmplification')[];
12
+ tools?: (
13
+ | 'patterns'
14
+ | 'context'
15
+ | 'consistency'
16
+ | 'doc-drift'
17
+ | 'deps-health'
18
+ | 'aiSignalClarity'
19
+ | 'grounding'
20
+ | 'testability'
21
+ | 'changeAmplification'
22
+ )[];
13
23
  minSimilarity?: number;
14
24
  minLines?: number;
15
25
  maxCandidatesPerBlock?: number;
@@ -50,7 +60,8 @@ function sortBySeverity(results: AnalysisResult[]): AnalysisResult[] {
50
60
  .map((file) => {
51
61
  // Sort issues within each file by severity (most severe first)
52
62
  const sortedIssues = [...file.issues].sort((a, b) => {
53
- const severityDiff = (severityOrder[b.severity] || 0) - (severityOrder[a.severity] || 0);
63
+ const severityDiff =
64
+ (severityOrder[b.severity] || 0) - (severityOrder[a.severity] || 0);
54
65
  if (severityDiff !== 0) return severityDiff;
55
66
  // If same severity, sort by line number
56
67
  return (a.location?.line || 0) - (b.location?.line || 0);
@@ -59,8 +70,14 @@ function sortBySeverity(results: AnalysisResult[]): AnalysisResult[] {
59
70
  })
60
71
  .sort((a, b) => {
61
72
  // Sort files by most severe issue first
62
- const aMaxSeverity = Math.max(...a.issues.map((i) => severityOrder[i.severity] || 0), 0);
63
- const bMaxSeverity = Math.max(...b.issues.map((i) => severityOrder[i.severity] || 0), 0);
73
+ const aMaxSeverity = Math.max(
74
+ ...a.issues.map((i) => severityOrder[i.severity] || 0),
75
+ 0
76
+ );
77
+ const bMaxSeverity = Math.max(
78
+ ...b.issues.map((i) => severityOrder[i.severity] || 0),
79
+ 0
80
+ );
64
81
  if (aMaxSeverity !== bMaxSeverity) {
65
82
  return bMaxSeverity - aMaxSeverity;
66
83
  }
@@ -113,7 +130,8 @@ export async function analyzeUnified(
113
130
  }
114
131
  // Sort context results by severity (most severe first)
115
132
  result.context = contextResults.sort((a, b) => {
116
- const severityDiff = (severityOrder[b.severity] || 0) - (severityOrder[a.severity] || 0);
133
+ const severityDiff =
134
+ (severityOrder[b.severity] || 0) - (severityOrder[a.severity] || 0);
117
135
  if (severityDiff !== 0) return severityDiff;
118
136
  // If same severity, sort by token cost (higher cost first)
119
137
  if (a.tokenCost !== b.tokenCost) return b.tokenCost - a.tokenCost;
@@ -176,7 +194,8 @@ export async function analyzeUnified(
176
194
 
177
195
  // Run AI Signal Clarity analysis
178
196
  if (tools.includes('aiSignalClarity')) {
179
- const { analyzeAiSignalClarity } = await import('@aiready/ai-signal-clarity');
197
+ const { analyzeAiSignalClarity } =
198
+ await import('@aiready/ai-signal-clarity');
180
199
  const report = await analyzeAiSignalClarity({
181
200
  rootDir: options.rootDir,
182
201
  include: options.include,
@@ -186,7 +205,11 @@ export async function analyzeUnified(
186
205
  options.progressCallback({ tool: 'aiSignalClarity', data: report });
187
206
  }
188
207
  result.aiSignalClarity = report;
189
- result.summary.totalIssues += report.results?.reduce((sum: number, r: any) => sum + (r.issues?.length || 0), 0) || 0;
208
+ result.summary.totalIssues +=
209
+ report.results?.reduce(
210
+ (sum: number, r: any) => sum + (r.issues?.length || 0),
211
+ 0
212
+ ) || 0;
190
213
  }
191
214
 
192
215
  // Run Agent Grounding analysis
@@ -221,7 +244,8 @@ export async function analyzeUnified(
221
244
 
222
245
  // Run Change Amplification analysis
223
246
  if (tools.includes('changeAmplification')) {
224
- const { analyzeChangeAmplification } = await import('@aiready/change-amplification');
247
+ const { analyzeChangeAmplification } =
248
+ await import('@aiready/change-amplification');
225
249
  const report = await analyzeChangeAmplification({
226
250
  rootDir: options.rootDir,
227
251
  include: options.include,
@@ -283,4 +307,4 @@ export function generateUnifiedSummary(result: UnifiedAnalysisResult): string {
283
307
  }
284
308
 
285
309
  return output;
286
- }
310
+ }
@@ -3,7 +3,7 @@
3
3
  */
4
4
 
5
5
  import { resolve as resolvePath } from 'path';
6
- import { existsSync, readdirSync, statSync, readFileSync, copyFileSync } from 'fs';
6
+ import { existsSync, readdirSync, statSync, readFileSync } from 'fs';
7
7
  import chalk from 'chalk';
8
8
 
9
9
  /**
@@ -25,35 +25,45 @@ export function findLatestScanReport(dirPath: string): string | null {
25
25
  if (!existsSync(aireadyDir)) {
26
26
  return null;
27
27
  }
28
-
28
+
29
29
  // Search for new format first, then legacy format
30
- let files = readdirSync(aireadyDir).filter(f => f.startsWith('aiready-report-') && f.endsWith('.json'));
30
+ let files = readdirSync(aireadyDir).filter(
31
+ (f) => f.startsWith('aiready-report-') && f.endsWith('.json')
32
+ );
31
33
  if (files.length === 0) {
32
- files = readdirSync(aireadyDir).filter(f => f.startsWith('aiready-scan-') && f.endsWith('.json'));
34
+ files = readdirSync(aireadyDir).filter(
35
+ (f) => f.startsWith('aiready-scan-') && f.endsWith('.json')
36
+ );
33
37
  }
34
-
38
+
35
39
  if (files.length === 0) {
36
40
  return null;
37
41
  }
38
-
42
+
39
43
  // Sort by modification time, most recent first
40
44
  const sortedFiles = files
41
- .map(f => ({ name: f, path: resolvePath(aireadyDir, f), mtime: statSync(resolvePath(aireadyDir, f)).mtime }))
45
+ .map((f) => ({
46
+ name: f,
47
+ path: resolvePath(aireadyDir, f),
48
+ mtime: statSync(resolvePath(aireadyDir, f)).mtime,
49
+ }))
42
50
  .sort((a, b) => b.mtime.getTime() - a.mtime.getTime());
43
-
51
+
44
52
  return sortedFiles[0].path;
45
53
  }
46
54
 
47
55
  /**
48
56
  * Warn if graph caps may be exceeded
49
57
  */
50
- export function warnIfGraphCapExceeded(report: any, dirPath: string) {
58
+ export async function warnIfGraphCapExceeded(report: any, dirPath: string) {
51
59
  try {
52
60
  // Use dynamic import and loadConfig to get the raw visualizer config
53
- const { loadConfig } = require('@aiready/core');
54
-
61
+ // Use dynamic import instead of require
62
+ const { loadConfig } = await import('@aiready/core');
63
+ void loadConfig;
64
+
55
65
  let graphConfig = { maxNodes: 400, maxEdges: 600 };
56
-
66
+
57
67
  // Try to read aiready.json synchronously
58
68
  const configPath = resolvePath(dirPath, 'aiready.json');
59
69
  if (existsSync(configPath)) {
@@ -61,47 +71,62 @@ export function warnIfGraphCapExceeded(report: any, dirPath: string) {
61
71
  const rawConfig = JSON.parse(readFileSync(configPath, 'utf8'));
62
72
  if (rawConfig.visualizer?.graph) {
63
73
  graphConfig = {
64
- maxNodes: rawConfig.visualizer.graph.maxNodes ?? graphConfig.maxNodes,
65
- maxEdges: rawConfig.visualizer.graph.maxEdges ?? graphConfig.maxEdges,
74
+ maxNodes:
75
+ rawConfig.visualizer.graph.maxNodes ?? graphConfig.maxNodes,
76
+ maxEdges:
77
+ rawConfig.visualizer.graph.maxEdges ?? graphConfig.maxEdges,
66
78
  };
67
79
  }
68
- } catch (e) {
69
- // Silently ignore parse errors and use defaults
80
+ } catch (err) {
81
+ void err;
70
82
  }
71
83
  }
72
-
73
- const nodeCount = (report.context?.length || 0) + (report.patterns?.length || 0);
74
- const edgeCount = report.context?.reduce((sum: number, ctx: any) => {
75
- const relCount = ctx.relatedFiles?.length || 0;
76
- const depCount = ctx.dependencies?.length || 0;
77
- return sum + relCount + depCount;
78
- }, 0) || 0;
79
-
84
+
85
+ const nodeCount =
86
+ (report.context?.length || 0) + (report.patterns?.length || 0);
87
+ const edgeCount =
88
+ report.context?.reduce((sum: number, ctx: any) => {
89
+ const relCount = ctx.relatedFiles?.length || 0;
90
+ const depCount = ctx.dependencies?.length || 0;
91
+ return sum + relCount + depCount;
92
+ }, 0) || 0;
93
+
80
94
  if (nodeCount > graphConfig.maxNodes || edgeCount > graphConfig.maxEdges) {
81
95
  console.log('');
82
- console.log(chalk.yellow(`⚠️ Graph may be truncated at visualization time:`));
96
+ console.log(
97
+ chalk.yellow(`⚠️ Graph may be truncated at visualization time:`)
98
+ );
83
99
  if (nodeCount > graphConfig.maxNodes) {
84
- console.log(chalk.dim(` • Nodes: ${nodeCount} > limit ${graphConfig.maxNodes}`));
100
+ console.log(
101
+ chalk.dim(` • Nodes: ${nodeCount} > limit ${graphConfig.maxNodes}`)
102
+ );
85
103
  }
86
104
  if (edgeCount > graphConfig.maxEdges) {
87
- console.log(chalk.dim(` • Edges: ${edgeCount} > limit ${graphConfig.maxEdges}`));
105
+ console.log(
106
+ chalk.dim(` • Edges: ${edgeCount} > limit ${graphConfig.maxEdges}`)
107
+ );
88
108
  }
89
109
  console.log(chalk.dim(` To increase limits, add to aiready.json:`));
90
110
  console.log(chalk.dim(` {`));
91
111
  console.log(chalk.dim(` "visualizer": {`));
92
- console.log(chalk.dim(` "graph": { "maxNodes": 2000, "maxEdges": 5000 }`));
112
+ console.log(
113
+ chalk.dim(` "graph": { "maxNodes": 2000, "maxEdges": 5000 }`)
114
+ );
93
115
  console.log(chalk.dim(` }`));
94
116
  console.log(chalk.dim(` }`));
95
117
  }
96
- } catch (e) {
97
- // Silently fail on config read errors
118
+ } catch (err) {
119
+ void err;
98
120
  }
99
121
  }
100
122
 
101
123
  /**
102
124
  * Generate markdown report for consistency command
103
125
  */
104
- export function generateMarkdownReport(report: any, elapsedTime: string): string {
126
+ export function generateMarkdownReport(
127
+ report: any,
128
+ elapsedTime: string
129
+ ): string {
105
130
  let markdown = `# Consistency Analysis Report\n\n`;
106
131
  markdown += `**Generated:** ${new Date().toISOString()}\n`;
107
132
  markdown += `**Analysis Time:** ${elapsedTime}s\n\n`;
@@ -130,4 +155,4 @@ export function truncateArray(arr: any[] | undefined, cap = 8): string {
130
155
  const shown = arr.slice(0, cap).map((v) => String(v));
131
156
  const more = arr.length - shown.length;
132
157
  return shown.join(', ') + (more > 0 ? `, ... (+${more} more)` : '');
133
- }
158
+ }