@aiready/cli 0.9.40 → 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.
package/dist/cli.mjs CHANGED
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  __require,
4
4
  analyzeUnified
5
- } from "./chunk-PDOONNSK.mjs";
5
+ } from "./chunk-HLBKROD3.mjs";
6
6
 
7
7
  // src/cli.ts
8
8
  import { Command } from "commander";
@@ -42,19 +42,28 @@ function findLatestScanReport(dirPath) {
42
42
  if (!existsSync(aireadyDir)) {
43
43
  return null;
44
44
  }
45
- let files = readdirSync(aireadyDir).filter((f) => f.startsWith("aiready-report-") && f.endsWith(".json"));
45
+ let files = readdirSync(aireadyDir).filter(
46
+ (f) => f.startsWith("aiready-report-") && f.endsWith(".json")
47
+ );
46
48
  if (files.length === 0) {
47
- files = readdirSync(aireadyDir).filter((f) => f.startsWith("aiready-scan-") && f.endsWith(".json"));
49
+ files = readdirSync(aireadyDir).filter(
50
+ (f) => f.startsWith("aiready-scan-") && f.endsWith(".json")
51
+ );
48
52
  }
49
53
  if (files.length === 0) {
50
54
  return null;
51
55
  }
52
- const sortedFiles = files.map((f) => ({ name: f, path: resolvePath(aireadyDir, f), mtime: statSync(resolvePath(aireadyDir, f)).mtime })).sort((a, b) => b.mtime.getTime() - a.mtime.getTime());
56
+ const sortedFiles = files.map((f) => ({
57
+ name: f,
58
+ path: resolvePath(aireadyDir, f),
59
+ mtime: statSync(resolvePath(aireadyDir, f)).mtime
60
+ })).sort((a, b) => b.mtime.getTime() - a.mtime.getTime());
53
61
  return sortedFiles[0].path;
54
62
  }
55
- function warnIfGraphCapExceeded(report, dirPath) {
63
+ async function warnIfGraphCapExceeded(report, dirPath) {
56
64
  try {
57
- const { loadConfig: loadConfig4 } = __require("@aiready/core");
65
+ const { loadConfig: loadConfig4 } = await import("@aiready/core");
66
+ void loadConfig4;
58
67
  let graphConfig = { maxNodes: 400, maxEdges: 600 };
59
68
  const configPath = resolvePath(dirPath, "aiready.json");
60
69
  if (existsSync(configPath)) {
@@ -66,7 +75,8 @@ function warnIfGraphCapExceeded(report, dirPath) {
66
75
  maxEdges: rawConfig.visualizer.graph.maxEdges ?? graphConfig.maxEdges
67
76
  };
68
77
  }
69
- } catch (e) {
78
+ } catch (err) {
79
+ void err;
70
80
  }
71
81
  }
72
82
  const nodeCount = (report.context?.length || 0) + (report.patterns?.length || 0);
@@ -77,21 +87,30 @@ function warnIfGraphCapExceeded(report, dirPath) {
77
87
  }, 0) || 0;
78
88
  if (nodeCount > graphConfig.maxNodes || edgeCount > graphConfig.maxEdges) {
79
89
  console.log("");
80
- console.log(chalk.yellow(`\u26A0\uFE0F Graph may be truncated at visualization time:`));
90
+ console.log(
91
+ chalk.yellow(`\u26A0\uFE0F Graph may be truncated at visualization time:`)
92
+ );
81
93
  if (nodeCount > graphConfig.maxNodes) {
82
- console.log(chalk.dim(` \u2022 Nodes: ${nodeCount} > limit ${graphConfig.maxNodes}`));
94
+ console.log(
95
+ chalk.dim(` \u2022 Nodes: ${nodeCount} > limit ${graphConfig.maxNodes}`)
96
+ );
83
97
  }
84
98
  if (edgeCount > graphConfig.maxEdges) {
85
- console.log(chalk.dim(` \u2022 Edges: ${edgeCount} > limit ${graphConfig.maxEdges}`));
99
+ console.log(
100
+ chalk.dim(` \u2022 Edges: ${edgeCount} > limit ${graphConfig.maxEdges}`)
101
+ );
86
102
  }
87
103
  console.log(chalk.dim(` To increase limits, add to aiready.json:`));
88
104
  console.log(chalk.dim(` {`));
89
105
  console.log(chalk.dim(` "visualizer": {`));
90
- console.log(chalk.dim(` "graph": { "maxNodes": 2000, "maxEdges": 5000 }`));
106
+ console.log(
107
+ chalk.dim(` "graph": { "maxNodes": 2000, "maxEdges": 5000 }`)
108
+ );
91
109
  console.log(chalk.dim(` }`));
92
110
  console.log(chalk.dim(` }`));
93
111
  }
94
- } catch (e) {
112
+ } catch (err) {
113
+ void err;
95
114
  }
96
115
  }
97
116
  function generateMarkdownReport(report, elapsedTime) {
@@ -140,7 +159,17 @@ async function scanAction(directory, options) {
140
159
  const resolvedDir = resolvePath2(process.cwd(), directory || ".");
141
160
  try {
142
161
  const defaults = {
143
- tools: ["patterns", "context", "consistency", "aiSignalClarity", "grounding", "testability", "doc-drift", "deps-health", "changeAmplification"],
162
+ tools: [
163
+ "patterns",
164
+ "context",
165
+ "consistency",
166
+ "aiSignalClarity",
167
+ "grounding",
168
+ "testability",
169
+ "doc-drift",
170
+ "deps-health",
171
+ "changeAmplification"
172
+ ],
144
173
  include: void 0,
145
174
  exclude: void 0,
146
175
  output: {
@@ -150,7 +179,8 @@ async function scanAction(directory, options) {
150
179
  };
151
180
  let profileTools = options.tools ? options.tools.split(",").map((t) => {
152
181
  const tool = t.trim();
153
- if (tool === "hallucination" || tool === "hallucination-risk") return "aiSignalClarity";
182
+ if (tool === "hallucination" || tool === "hallucination-risk")
183
+ return "aiSignalClarity";
154
184
  return tool;
155
185
  }) : void 0;
156
186
  if (options.profile) {
@@ -168,8 +198,12 @@ async function scanAction(directory, options) {
168
198
  profileTools = ["context", "consistency", "grounding"];
169
199
  break;
170
200
  default:
171
- console.log(chalk2.yellow(`
172
- \u26A0\uFE0F Unknown profile '${options.profile}'. Using specified tools or defaults.`));
201
+ console.log(
202
+ chalk2.yellow(
203
+ `
204
+ \u26A0\uFE0F Unknown profile '${options.profile}'. Using specified tools or defaults.`
205
+ )
206
+ );
173
207
  }
174
208
  }
175
209
  const cliOverrides = {
@@ -179,20 +213,41 @@ async function scanAction(directory, options) {
179
213
  if (profileTools) {
180
214
  cliOverrides.tools = profileTools;
181
215
  }
182
- const baseOptions = await loadMergedConfig(resolvedDir, defaults, cliOverrides);
216
+ const baseOptions = await loadMergedConfig(
217
+ resolvedDir,
218
+ defaults,
219
+ cliOverrides
220
+ );
183
221
  let finalOptions = { ...baseOptions };
184
222
  if (baseOptions.tools.includes("patterns")) {
185
223
  const { getSmartDefaults } = await import("@aiready/pattern-detect");
186
- const patternSmartDefaults = await getSmartDefaults(resolvedDir, baseOptions);
187
- finalOptions = { ...patternSmartDefaults, ...finalOptions, ...baseOptions };
224
+ const patternSmartDefaults = await getSmartDefaults(
225
+ resolvedDir,
226
+ baseOptions
227
+ );
228
+ finalOptions = {
229
+ ...patternSmartDefaults,
230
+ ...finalOptions,
231
+ ...baseOptions
232
+ };
188
233
  }
189
234
  console.log(chalk2.cyan("\n=== AIReady Run Preview ==="));
190
- console.log(chalk2.white("Tools to run:"), (finalOptions.tools || ["patterns", "context", "consistency"]).join(", "));
235
+ console.log(
236
+ chalk2.white("Tools to run:"),
237
+ (finalOptions.tools || ["patterns", "context", "consistency"]).join(", ")
238
+ );
191
239
  console.log(chalk2.white("Will use settings from config and defaults."));
192
240
  console.log(chalk2.white("\nGeneral settings:"));
193
- if (finalOptions.rootDir) console.log(` rootDir: ${chalk2.bold(String(finalOptions.rootDir))}`);
194
- if (finalOptions.include) console.log(` include: ${chalk2.bold(truncateArray(finalOptions.include, 6))}`);
195
- if (finalOptions.exclude) console.log(` exclude: ${chalk2.bold(truncateArray(finalOptions.exclude, 6))}`);
241
+ if (finalOptions.rootDir)
242
+ console.log(` rootDir: ${chalk2.bold(String(finalOptions.rootDir))}`);
243
+ if (finalOptions.include)
244
+ console.log(
245
+ ` include: ${chalk2.bold(truncateArray(finalOptions.include, 6))}`
246
+ );
247
+ if (finalOptions.exclude)
248
+ console.log(
249
+ ` exclude: ${chalk2.bold(truncateArray(finalOptions.exclude, 6))}`
250
+ );
196
251
  if (finalOptions["pattern-detect"] || finalOptions.minSimilarity) {
197
252
  const patternDetectConfig = finalOptions["pattern-detect"] || {
198
253
  minSimilarity: finalOptions.minSimilarity,
@@ -206,15 +261,40 @@ async function scanAction(directory, options) {
206
261
  includeTests: finalOptions.includeTests
207
262
  };
208
263
  console.log(chalk2.white("\nPattern-detect settings:"));
209
- console.log(` minSimilarity: ${chalk2.bold(patternDetectConfig.minSimilarity ?? "default")}`);
210
- console.log(` minLines: ${chalk2.bold(patternDetectConfig.minLines ?? "default")}`);
211
- if (patternDetectConfig.approx !== void 0) console.log(` approx: ${chalk2.bold(String(patternDetectConfig.approx))}`);
212
- if (patternDetectConfig.minSharedTokens !== void 0) console.log(` minSharedTokens: ${chalk2.bold(String(patternDetectConfig.minSharedTokens))}`);
213
- if (patternDetectConfig.maxCandidatesPerBlock !== void 0) console.log(` maxCandidatesPerBlock: ${chalk2.bold(String(patternDetectConfig.maxCandidatesPerBlock))}`);
214
- if (patternDetectConfig.batchSize !== void 0) console.log(` batchSize: ${chalk2.bold(String(patternDetectConfig.batchSize))}`);
215
- if (patternDetectConfig.streamResults !== void 0) console.log(` streamResults: ${chalk2.bold(String(patternDetectConfig.streamResults))}`);
216
- if (patternDetectConfig.severity !== void 0) console.log(` severity: ${chalk2.bold(String(patternDetectConfig.severity))}`);
217
- if (patternDetectConfig.includeTests !== void 0) console.log(` includeTests: ${chalk2.bold(String(patternDetectConfig.includeTests))}`);
264
+ console.log(
265
+ ` minSimilarity: ${chalk2.bold(patternDetectConfig.minSimilarity ?? "default")}`
266
+ );
267
+ console.log(
268
+ ` minLines: ${chalk2.bold(patternDetectConfig.minLines ?? "default")}`
269
+ );
270
+ if (patternDetectConfig.approx !== void 0)
271
+ console.log(
272
+ ` approx: ${chalk2.bold(String(patternDetectConfig.approx))}`
273
+ );
274
+ if (patternDetectConfig.minSharedTokens !== void 0)
275
+ console.log(
276
+ ` minSharedTokens: ${chalk2.bold(String(patternDetectConfig.minSharedTokens))}`
277
+ );
278
+ if (patternDetectConfig.maxCandidatesPerBlock !== void 0)
279
+ console.log(
280
+ ` maxCandidatesPerBlock: ${chalk2.bold(String(patternDetectConfig.maxCandidatesPerBlock))}`
281
+ );
282
+ if (patternDetectConfig.batchSize !== void 0)
283
+ console.log(
284
+ ` batchSize: ${chalk2.bold(String(patternDetectConfig.batchSize))}`
285
+ );
286
+ if (patternDetectConfig.streamResults !== void 0)
287
+ console.log(
288
+ ` streamResults: ${chalk2.bold(String(patternDetectConfig.streamResults))}`
289
+ );
290
+ if (patternDetectConfig.severity !== void 0)
291
+ console.log(
292
+ ` severity: ${chalk2.bold(String(patternDetectConfig.severity))}`
293
+ );
294
+ if (patternDetectConfig.includeTests !== void 0)
295
+ console.log(
296
+ ` includeTests: ${chalk2.bold(String(patternDetectConfig.includeTests))}`
297
+ );
218
298
  }
219
299
  if (finalOptions["context-analyzer"] || finalOptions.maxDepth) {
220
300
  const ca = finalOptions["context-analyzer"] || {
@@ -226,20 +306,42 @@ async function scanAction(directory, options) {
226
306
  };
227
307
  console.log(chalk2.white("\nContext-analyzer settings:"));
228
308
  console.log(` maxDepth: ${chalk2.bold(ca.maxDepth ?? "default")}`);
229
- console.log(` maxContextBudget: ${chalk2.bold(ca.maxContextBudget ?? "default")}`);
230
- if (ca.minCohesion !== void 0) console.log(` minCohesion: ${chalk2.bold(String(ca.minCohesion))}`);
231
- if (ca.maxFragmentation !== void 0) console.log(` maxFragmentation: ${chalk2.bold(String(ca.maxFragmentation))}`);
232
- if (ca.includeNodeModules !== void 0) console.log(` includeNodeModules: ${chalk2.bold(String(ca.includeNodeModules))}`);
309
+ console.log(
310
+ ` maxContextBudget: ${chalk2.bold(ca.maxContextBudget ?? "default")}`
311
+ );
312
+ if (ca.minCohesion !== void 0)
313
+ console.log(` minCohesion: ${chalk2.bold(String(ca.minCohesion))}`);
314
+ if (ca.maxFragmentation !== void 0)
315
+ console.log(
316
+ ` maxFragmentation: ${chalk2.bold(String(ca.maxFragmentation))}`
317
+ );
318
+ if (ca.includeNodeModules !== void 0)
319
+ console.log(
320
+ ` includeNodeModules: ${chalk2.bold(String(ca.includeNodeModules))}`
321
+ );
233
322
  }
234
323
  if (finalOptions.consistency) {
235
324
  const c = finalOptions.consistency;
236
325
  console.log(chalk2.white("\nConsistency settings:"));
237
- console.log(` checkNaming: ${chalk2.bold(String(c.checkNaming ?? true))}`);
238
- console.log(` checkPatterns: ${chalk2.bold(String(c.checkPatterns ?? true))}`);
239
- console.log(` checkArchitecture: ${chalk2.bold(String(c.checkArchitecture ?? false))}`);
240
- if (c.minSeverity) console.log(` minSeverity: ${chalk2.bold(c.minSeverity)}`);
241
- if (c.acceptedAbbreviations) console.log(` acceptedAbbreviations: ${chalk2.bold(truncateArray(c.acceptedAbbreviations, 8))}`);
242
- if (c.shortWords) console.log(` shortWords: ${chalk2.bold(truncateArray(c.shortWords, 8))}`);
326
+ console.log(
327
+ ` checkNaming: ${chalk2.bold(String(c.checkNaming ?? true))}`
328
+ );
329
+ console.log(
330
+ ` checkPatterns: ${chalk2.bold(String(c.checkPatterns ?? true))}`
331
+ );
332
+ console.log(
333
+ ` checkArchitecture: ${chalk2.bold(String(c.checkArchitecture ?? false))}`
334
+ );
335
+ if (c.minSeverity)
336
+ console.log(` minSeverity: ${chalk2.bold(c.minSeverity)}`);
337
+ if (c.acceptedAbbreviations)
338
+ console.log(
339
+ ` acceptedAbbreviations: ${chalk2.bold(truncateArray(c.acceptedAbbreviations, 8))}`
340
+ );
341
+ if (c.shortWords)
342
+ console.log(
343
+ ` shortWords: ${chalk2.bold(truncateArray(c.shortWords, 8))}`
344
+ );
243
345
  }
244
346
  console.log(chalk2.white("\nStarting analysis..."));
245
347
  const progressCallback = (event) => {
@@ -248,40 +350,62 @@ async function scanAction(directory, options) {
248
350
  try {
249
351
  if (event.tool === "patterns") {
250
352
  const pr = event.data;
251
- console.log(` Duplicate patterns: ${chalk2.bold(String(pr.duplicates?.length || 0))}`);
252
- console.log(` Files with pattern issues: ${chalk2.bold(String(pr.results?.length || 0))}`);
353
+ console.log(
354
+ ` Duplicate patterns: ${chalk2.bold(String(pr.duplicates?.length || 0))}`
355
+ );
356
+ console.log(
357
+ ` Files with pattern issues: ${chalk2.bold(String(pr.results?.length || 0))}`
358
+ );
253
359
  if (pr.duplicates && pr.duplicates.length > 0) {
254
360
  pr.duplicates.slice(0, 5).forEach((d, i) => {
255
- console.log(` ${i + 1}. ${d.file1.split("/").pop()} \u2194 ${d.file2.split("/").pop()} (sim=${(d.similarity * 100).toFixed(1)}%)`);
361
+ console.log(
362
+ ` ${i + 1}. ${d.file1.split("/").pop()} \u2194 ${d.file2.split("/").pop()} (sim=${(d.similarity * 100).toFixed(1)}%)`
363
+ );
256
364
  });
257
365
  }
258
366
  if (pr.results && pr.results.length > 0) {
259
367
  console.log(` Top files with pattern issues:`);
260
- const sortedByIssues = [...pr.results].sort((a, b) => (b.issues?.length || 0) - (a.issues?.length || 0));
368
+ const sortedByIssues = [...pr.results].sort(
369
+ (a, b) => (b.issues?.length || 0) - (a.issues?.length || 0)
370
+ );
261
371
  sortedByIssues.slice(0, 5).forEach((r, i) => {
262
- console.log(` ${i + 1}. ${r.fileName.split("/").pop()} - ${r.issues.length} issue(s)`);
372
+ console.log(
373
+ ` ${i + 1}. ${r.fileName.split("/").pop()} - ${r.issues.length} issue(s)`
374
+ );
263
375
  });
264
376
  }
265
377
  if (pr.groups && pr.groups.length >= 0) {
266
- console.log(` \u2705 Grouped ${chalk2.bold(String(pr.duplicates?.length || 0))} duplicates into ${chalk2.bold(String(pr.groups.length))} file pairs`);
378
+ console.log(
379
+ ` \u2705 Grouped ${chalk2.bold(String(pr.duplicates?.length || 0))} duplicates into ${chalk2.bold(String(pr.groups.length))} file pairs`
380
+ );
267
381
  }
268
382
  if (pr.clusters && pr.clusters.length >= 0) {
269
- console.log(` \u2705 Created ${chalk2.bold(String(pr.clusters.length))} refactor clusters`);
383
+ console.log(
384
+ ` \u2705 Created ${chalk2.bold(String(pr.clusters.length))} refactor clusters`
385
+ );
270
386
  pr.clusters.slice(0, 3).forEach((cl, idx) => {
271
387
  const files = (cl.files || []).map((f) => f.path.split("/").pop()).join(", ");
272
- console.log(` ${idx + 1}. ${files} (${cl.tokenCost || "n/a"} tokens)`);
388
+ console.log(
389
+ ` ${idx + 1}. ${files} (${cl.tokenCost || "n/a"} tokens)`
390
+ );
273
391
  });
274
392
  }
275
393
  } else if (event.tool === "context") {
276
394
  const cr = event.data;
277
- console.log(` Context issues found: ${chalk2.bold(String(cr.length || 0))}`);
395
+ console.log(
396
+ ` Context issues found: ${chalk2.bold(String(cr.length || 0))}`
397
+ );
278
398
  cr.slice(0, 5).forEach((c, i) => {
279
399
  const msg = c.message ? ` - ${c.message}` : "";
280
- console.log(` ${i + 1}. ${c.file} (${c.severity || "n/a"})${msg}`);
400
+ console.log(
401
+ ` ${i + 1}. ${c.file} (${c.severity || "n/a"})${msg}`
402
+ );
281
403
  });
282
404
  } else if (event.tool === "consistency") {
283
405
  const rep = event.data;
284
- console.log(` Consistency totalIssues: ${chalk2.bold(String(rep.summary?.totalIssues || 0))}`);
406
+ console.log(
407
+ ` Consistency totalIssues: ${chalk2.bold(String(rep.summary?.totalIssues || 0))}`
408
+ );
285
409
  if (rep.results && rep.results.length > 0) {
286
410
  const fileMap = /* @__PURE__ */ new Map();
287
411
  rep.results.forEach((r) => {
@@ -291,68 +415,126 @@ async function scanAction(directory, options) {
291
415
  fileMap.get(file).push(issue);
292
416
  });
293
417
  });
294
- const files = Array.from(fileMap.entries()).sort((a, b) => b[1].length - a[1].length);
418
+ const files = Array.from(fileMap.entries()).sort(
419
+ (a, b) => b[1].length - a[1].length
420
+ );
295
421
  const topFiles = files.slice(0, 10);
296
422
  topFiles.forEach(([file, issues], idx) => {
297
- const counts = issues.reduce((acc, it) => {
298
- const s = (it.severity || "info").toLowerCase();
299
- acc[s] = (acc[s] || 0) + 1;
300
- return acc;
301
- }, {});
302
- const sample = issues.find((it) => it.severity === "critical" || it.severity === "major") || issues[0];
423
+ const counts = issues.reduce(
424
+ (acc, it) => {
425
+ const s = (it.severity || "info").toLowerCase();
426
+ acc[s] = (acc[s] || 0) + 1;
427
+ return acc;
428
+ },
429
+ {}
430
+ );
431
+ const sample = issues.find(
432
+ (it) => it.severity === "critical" || it.severity === "major"
433
+ ) || issues[0];
303
434
  const sampleMsg = sample ? ` \u2014 ${sample.message}` : "";
304
- console.log(` ${idx + 1}. ${file} \u2014 ${issues.length} issue(s) (critical:${counts.critical || 0} major:${counts.major || 0} minor:${counts.minor || 0} info:${counts.info || 0})${sampleMsg}`);
435
+ console.log(
436
+ ` ${idx + 1}. ${file} \u2014 ${issues.length} issue(s) (critical:${counts.critical || 0} major:${counts.major || 0} minor:${counts.minor || 0} info:${counts.info || 0})${sampleMsg}`
437
+ );
305
438
  });
306
439
  const remaining = files.length - topFiles.length;
307
440
  if (remaining > 0) {
308
- console.log(chalk2.dim(` ... and ${remaining} more files with issues (use --output json for full details)`));
441
+ console.log(
442
+ chalk2.dim(
443
+ ` ... and ${remaining} more files with issues (use --output json for full details)`
444
+ )
445
+ );
309
446
  }
310
447
  }
311
448
  } else if (event.tool === "doc-drift") {
312
449
  const dr = event.data;
313
- console.log(` Issues found: ${chalk2.bold(String(dr.issues?.length || 0))}`);
450
+ console.log(
451
+ ` Issues found: ${chalk2.bold(String(dr.issues?.length || 0))}`
452
+ );
314
453
  if (dr.rawData) {
315
- console.log(` Signature Mismatches: ${chalk2.bold(dr.rawData.outdatedComments || 0)}`);
316
- console.log(` Undocumented Complexity: ${chalk2.bold(dr.rawData.undocumentedComplexity || 0)}`);
454
+ console.log(
455
+ ` Signature Mismatches: ${chalk2.bold(dr.rawData.outdatedComments || 0)}`
456
+ );
457
+ console.log(
458
+ ` Undocumented Complexity: ${chalk2.bold(dr.rawData.undocumentedComplexity || 0)}`
459
+ );
317
460
  }
318
461
  } else if (event.tool === "deps-health") {
319
462
  const dr = event.data;
320
- console.log(` Packages Analyzed: ${chalk2.bold(String(dr.summary?.packagesAnalyzed || 0))}`);
463
+ console.log(
464
+ ` Packages Analyzed: ${chalk2.bold(String(dr.summary?.packagesAnalyzed || 0))}`
465
+ );
321
466
  if (dr.rawData) {
322
- console.log(` Deprecated Packages: ${chalk2.bold(dr.rawData.deprecatedPackages || 0)}`);
323
- console.log(` AI Cutoff Skew Score: ${chalk2.bold(dr.rawData.trainingCutoffSkew?.toFixed(1) || 0)}`);
467
+ console.log(
468
+ ` Deprecated Packages: ${chalk2.bold(dr.rawData.deprecatedPackages || 0)}`
469
+ );
470
+ console.log(
471
+ ` AI Cutoff Skew Score: ${chalk2.bold(dr.rawData.trainingCutoffSkew?.toFixed(1) || 0)}`
472
+ );
324
473
  }
325
474
  } else if (event.tool === "change-amplification" || event.tool === "changeAmplification") {
326
475
  const dr = event.data;
327
- console.log(` Coupling issues: ${chalk2.bold(String(dr.issues?.length || 0))}`);
476
+ console.log(
477
+ ` Coupling issues: ${chalk2.bold(String(dr.issues?.length || 0))}`
478
+ );
328
479
  if (dr.summary) {
329
- console.log(` Complexity Score: ${chalk2.bold(dr.summary.score || 0)}/100`);
480
+ console.log(
481
+ ` Complexity Score: ${chalk2.bold(dr.summary.score || 0)}/100`
482
+ );
330
483
  }
331
484
  }
332
485
  } catch (err) {
486
+ void err;
333
487
  }
334
488
  };
335
- const results = await analyzeUnified({ ...finalOptions, progressCallback, suppressToolConfig: true });
489
+ const results = await analyzeUnified({
490
+ ...finalOptions,
491
+ progressCallback,
492
+ suppressToolConfig: true
493
+ });
336
494
  console.log(chalk2.cyan("\n=== AIReady Run Summary ==="));
337
- console.log(chalk2.white("Tools run:"), (finalOptions.tools || ["patterns", "context", "consistency"]).join(", "));
495
+ console.log(
496
+ chalk2.white("Tools run:"),
497
+ (finalOptions.tools || ["patterns", "context", "consistency"]).join(", ")
498
+ );
338
499
  console.log(chalk2.cyan("\nResults summary:"));
339
- console.log(` Total issues (all tools): ${chalk2.bold(String(results.summary.totalIssues || 0))}`);
340
- if (results.duplicates) console.log(` Duplicate patterns found: ${chalk2.bold(String(results.duplicates.length || 0))}`);
341
- if (results.patterns) console.log(` Pattern files with issues: ${chalk2.bold(String(results.patterns.length || 0))}`);
342
- if (results.context) console.log(` Context issues: ${chalk2.bold(String(results.context.length || 0))}`);
343
- console.log(` Consistency issues: ${chalk2.bold(String(results.consistency?.summary?.totalIssues || 0))}`);
344
- if (results.changeAmplification) console.log(` Change amplification: ${chalk2.bold(String(results.changeAmplification.summary?.score || 0))}/100`);
500
+ console.log(
501
+ ` Total issues (all tools): ${chalk2.bold(String(results.summary.totalIssues || 0))}`
502
+ );
503
+ if (results.duplicates)
504
+ console.log(
505
+ ` Duplicate patterns found: ${chalk2.bold(String(results.duplicates.length || 0))}`
506
+ );
507
+ if (results.patterns)
508
+ console.log(
509
+ ` Pattern files with issues: ${chalk2.bold(String(results.patterns.length || 0))}`
510
+ );
511
+ if (results.context)
512
+ console.log(
513
+ ` Context issues: ${chalk2.bold(String(results.context.length || 0))}`
514
+ );
515
+ console.log(
516
+ ` Consistency issues: ${chalk2.bold(String(results.consistency?.summary?.totalIssues || 0))}`
517
+ );
518
+ if (results.changeAmplification)
519
+ console.log(
520
+ ` Change amplification: ${chalk2.bold(String(results.changeAmplification.summary?.score || 0))}/100`
521
+ );
345
522
  console.log(chalk2.cyan("===========================\n"));
346
523
  const elapsedTime = getElapsedTime(startTime);
524
+ void elapsedTime;
347
525
  let scoringResult;
348
526
  if (options.score || finalOptions.scoring?.showBreakdown) {
349
527
  const toolScores = /* @__PURE__ */ new Map();
350
528
  if (results.duplicates) {
351
529
  const { calculatePatternScore } = await import("@aiready/pattern-detect");
352
530
  try {
353
- const patternScore = calculatePatternScore(results.duplicates, results.patterns?.length || 0);
531
+ const patternScore = calculatePatternScore(
532
+ results.duplicates,
533
+ results.patterns?.length || 0
534
+ );
354
535
  toolScores.set("pattern-detect", patternScore);
355
536
  } catch (err) {
537
+ void err;
356
538
  }
357
539
  }
358
540
  if (results.context) {
@@ -362,6 +544,7 @@ async function scanAction(directory, options) {
362
544
  const contextScore = calculateContextScore(ctxSummary);
363
545
  toolScores.set("context-analyzer", contextScore);
364
546
  } catch (err) {
547
+ void err;
365
548
  }
366
549
  }
367
550
  if (results.consistency) {
@@ -369,17 +552,24 @@ async function scanAction(directory, options) {
369
552
  try {
370
553
  const issues = results.consistency.results?.flatMap((r) => r.issues) || [];
371
554
  const totalFiles = results.consistency.summary?.filesAnalyzed || 0;
372
- const consistencyScore = calculateConsistencyScore(issues, totalFiles);
555
+ const consistencyScore = calculateConsistencyScore(
556
+ issues,
557
+ totalFiles
558
+ );
373
559
  toolScores.set("consistency", consistencyScore);
374
560
  } catch (err) {
561
+ void err;
375
562
  }
376
563
  }
377
564
  if (results.aiSignalClarity) {
378
565
  const { calculateAiSignalClarityScore } = await import("@aiready/ai-signal-clarity");
379
566
  try {
380
- const hrScore = calculateAiSignalClarityScore(results.aiSignalClarity);
567
+ const hrScore = calculateAiSignalClarityScore(
568
+ results.aiSignalClarity
569
+ );
381
570
  toolScores.set("ai-signal-clarity", hrScore);
382
571
  } catch (err) {
572
+ void err;
383
573
  }
384
574
  }
385
575
  if (results.grounding) {
@@ -388,6 +578,7 @@ async function scanAction(directory, options) {
388
578
  const agScore = calculateGroundingScore(results.grounding);
389
579
  toolScores.set("agent-grounding", agScore);
390
580
  } catch (err) {
581
+ void err;
391
582
  }
392
583
  }
393
584
  if (results.testability) {
@@ -396,6 +587,7 @@ async function scanAction(directory, options) {
396
587
  const tbScore = calculateTestabilityScore(results.testability);
397
588
  toolScores.set("testability", tbScore);
398
589
  } catch (err) {
590
+ void err;
399
591
  }
400
592
  }
401
593
  if (results.docDrift) {
@@ -404,7 +596,13 @@ async function scanAction(directory, options) {
404
596
  score: results.docDrift.summary.score,
405
597
  rawMetrics: results.docDrift.rawData,
406
598
  factors: [],
407
- recommendations: (results.docDrift.recommendations || []).map((action) => ({ action, estimatedImpact: 5, priority: "medium" }))
599
+ recommendations: (results.docDrift.recommendations || []).map(
600
+ (action) => ({
601
+ action,
602
+ estimatedImpact: 5,
603
+ priority: "medium"
604
+ })
605
+ )
408
606
  });
409
607
  }
410
608
  if (results.deps) {
@@ -413,7 +611,13 @@ async function scanAction(directory, options) {
413
611
  score: results.deps.summary.score,
414
612
  rawMetrics: results.deps.rawData,
415
613
  factors: [],
416
- recommendations: (results.deps.recommendations || []).map((action) => ({ action, estimatedImpact: 5, priority: "medium" }))
614
+ recommendations: (results.deps.recommendations || []).map(
615
+ (action) => ({
616
+ action,
617
+ estimatedImpact: 5,
618
+ priority: "medium"
619
+ })
620
+ )
417
621
  });
418
622
  }
419
623
  if (results.changeAmplification) {
@@ -422,17 +626,28 @@ async function scanAction(directory, options) {
422
626
  score: results.changeAmplification.summary.score,
423
627
  rawMetrics: results.changeAmplification.rawData,
424
628
  factors: [],
425
- recommendations: (results.changeAmplification.recommendations || []).map((action) => ({ action, estimatedImpact: 5, priority: "medium" }))
629
+ recommendations: (results.changeAmplification.recommendations || []).map((action) => ({
630
+ action,
631
+ estimatedImpact: 5,
632
+ priority: "medium"
633
+ }))
426
634
  });
427
635
  }
428
636
  const cliWeights = parseWeightString(options.weights);
429
637
  if (toolScores.size > 0) {
430
- scoringResult = calculateOverallScore(toolScores, finalOptions, cliWeights.size ? cliWeights : void 0);
638
+ scoringResult = calculateOverallScore(
639
+ toolScores,
640
+ finalOptions,
641
+ cliWeights.size ? cliWeights : void 0
642
+ );
431
643
  console.log(chalk2.bold("\n\u{1F4CA} AI Readiness Overall Score"));
432
644
  console.log(` ${formatScore(scoringResult)}`);
433
645
  if (options.compareTo) {
434
646
  try {
435
- const prevReportStr = readFileSync2(resolvePath2(process.cwd(), options.compareTo), "utf8");
647
+ const prevReportStr = readFileSync2(
648
+ resolvePath2(process.cwd(), options.compareTo),
649
+ "utf8"
650
+ );
436
651
  const prevReport = JSON.parse(prevReportStr);
437
652
  const prevScore = prevReport.scoring?.score || prevReport.scoring?.overallScore;
438
653
  if (typeof prevScore === "number") {
@@ -440,23 +655,44 @@ async function scanAction(directory, options) {
440
655
  const diffStr = diff > 0 ? `+${diff}` : String(diff);
441
656
  console.log();
442
657
  if (diff > 0) {
443
- console.log(chalk2.green(` \u{1F4C8} Trend: ${diffStr} compared to ${options.compareTo} (${prevScore} \u2192 ${scoringResult.overall})`));
658
+ console.log(
659
+ chalk2.green(
660
+ ` \u{1F4C8} Trend: ${diffStr} compared to ${options.compareTo} (${prevScore} \u2192 ${scoringResult.overall})`
661
+ )
662
+ );
444
663
  } else if (diff < 0) {
445
- console.log(chalk2.red(` \u{1F4C9} Trend: ${diffStr} compared to ${options.compareTo} (${prevScore} \u2192 ${scoringResult.overall})`));
664
+ console.log(
665
+ chalk2.red(
666
+ ` \u{1F4C9} Trend: ${diffStr} compared to ${options.compareTo} (${prevScore} \u2192 ${scoringResult.overall})`
667
+ )
668
+ );
446
669
  } else {
447
- console.log(chalk2.blue(` \u2796 Trend: No change compared to ${options.compareTo} (${prevScore} \u2192 ${scoringResult.overall})`));
670
+ console.log(
671
+ chalk2.blue(
672
+ ` \u2796 Trend: No change compared to ${options.compareTo} (${prevScore} \u2192 ${scoringResult.overall})`
673
+ )
674
+ );
448
675
  }
449
676
  scoringResult.trend = {
450
677
  previousScore: prevScore,
451
678
  difference: diff
452
679
  };
453
680
  } else {
454
- console.log(chalk2.yellow(`
455
- \u26A0\uFE0F Previous report at ${options.compareTo} does not contain an overall score.`));
681
+ console.log(
682
+ chalk2.yellow(
683
+ `
684
+ \u26A0\uFE0F Previous report at ${options.compareTo} does not contain an overall score.`
685
+ )
686
+ );
456
687
  }
457
688
  } catch (e) {
458
- console.log(chalk2.yellow(`
459
- \u26A0\uFE0F Could not read or parse previous report at ${options.compareTo}.`));
689
+ void e;
690
+ console.log(
691
+ chalk2.yellow(
692
+ `
693
+ \u26A0\uFE0F Could not read or parse previous report at ${options.compareTo}.`
694
+ )
695
+ );
460
696
  }
461
697
  }
462
698
  if (scoringResult.breakdown && scoringResult.breakdown.length > 0) {
@@ -464,7 +700,9 @@ async function scanAction(directory, options) {
464
700
  scoringResult.breakdown.forEach((tool) => {
465
701
  const rating = getRating(tool.score);
466
702
  const rd = getRatingDisplay(rating);
467
- console.log(` - ${tool.toolName}: ${tool.score}/100 (${rating}) ${rd.emoji}`);
703
+ console.log(
704
+ ` - ${tool.toolName}: ${tool.score}/100 (${rating}) ${rd.emoji}`
705
+ );
468
706
  });
469
707
  console.log();
470
708
  if (finalOptions.scoring?.showBreakdown) {
@@ -482,20 +720,33 @@ async function scanAction(directory, options) {
482
720
  if (outputFormat === "json") {
483
721
  const timestamp = getReportTimestamp();
484
722
  const defaultFilename = `aiready-report-${timestamp}.json`;
485
- const outputPath = resolveOutputPath(userOutputFile, defaultFilename, resolvedDir);
723
+ const outputPath = resolveOutputPath(
724
+ userOutputFile,
725
+ defaultFilename,
726
+ resolvedDir
727
+ );
486
728
  const outputData = { ...results, scoring: scoringResult };
487
- handleJSONOutput(outputData, outputPath, `\u2705 Report saved to ${outputPath}`);
488
- warnIfGraphCapExceeded(outputData, resolvedDir);
729
+ handleJSONOutput(
730
+ outputData,
731
+ outputPath,
732
+ `\u2705 Report saved to ${outputPath}`
733
+ );
734
+ await warnIfGraphCapExceeded(outputData, resolvedDir);
489
735
  } else {
490
736
  const timestamp = getReportTimestamp();
491
737
  const defaultFilename = `aiready-report-${timestamp}.json`;
492
- const outputPath = resolveOutputPath(userOutputFile, defaultFilename, resolvedDir);
738
+ const outputPath = resolveOutputPath(
739
+ userOutputFile,
740
+ defaultFilename,
741
+ resolvedDir
742
+ );
493
743
  const outputData = { ...results, scoring: scoringResult };
494
744
  try {
495
745
  writeFileSync(outputPath, JSON.stringify(outputData, null, 2));
496
746
  console.log(chalk2.dim(`\u2705 Report auto-persisted to ${outputPath}`));
497
- warnIfGraphCapExceeded(outputData, resolvedDir);
747
+ await warnIfGraphCapExceeded(outputData, resolvedDir);
498
748
  } catch (err) {
749
+ void err;
499
750
  }
500
751
  }
501
752
  const isCI = options.ci || process.env.CI === "true" || process.env.GITHUB_ACTIONS === "true";
@@ -513,16 +764,22 @@ async function scanAction(directory, options) {
513
764
  }
514
765
  console.log("::endgroup::");
515
766
  if (threshold && scoringResult.overall < threshold) {
516
- console.log(`::error::AI Readiness Score ${scoringResult.overall} is below threshold ${threshold}`);
767
+ console.log(
768
+ `::error::AI Readiness Score ${scoringResult.overall} is below threshold ${threshold}`
769
+ );
517
770
  } else if (threshold) {
518
- console.log(`::notice::AI Readiness Score: ${scoringResult.overall}/100 (threshold: ${threshold})`);
771
+ console.log(
772
+ `::notice::AI Readiness Score: ${scoringResult.overall}/100 (threshold: ${threshold})`
773
+ );
519
774
  }
520
775
  if (results.patterns) {
521
776
  const criticalPatterns = results.patterns.flatMap(
522
777
  (p) => p.issues.filter((i) => i.severity === "critical")
523
778
  );
524
779
  criticalPatterns.slice(0, 10).forEach((issue) => {
525
- console.log(`::warning file=${issue.location?.file || "unknown"},line=${issue.location?.line || 1}::${issue.message}`);
780
+ console.log(
781
+ `::warning file=${issue.location?.file || "unknown"},line=${issue.location?.line || 1}::${issue.message}`
782
+ );
526
783
  });
527
784
  }
528
785
  }
@@ -571,16 +828,30 @@ async function scanAction(directory, options) {
571
828
  console.log(chalk2.red("\n\u{1F6AB} PR BLOCKED: AI Readiness Check Failed"));
572
829
  console.log(chalk2.red(` Reason: ${failReason}`));
573
830
  console.log(chalk2.dim("\n Remediation steps:"));
574
- console.log(chalk2.dim(" 1. Run `aiready scan` locally to see detailed issues"));
831
+ console.log(
832
+ chalk2.dim(" 1. Run `aiready scan` locally to see detailed issues")
833
+ );
575
834
  console.log(chalk2.dim(" 2. Fix the critical issues before merging"));
576
- console.log(chalk2.dim(" 3. Consider upgrading to Team plan for historical tracking: https://getaiready.dev/pricing"));
835
+ console.log(
836
+ chalk2.dim(
837
+ " 3. Consider upgrading to Team plan for historical tracking: https://getaiready.dev/pricing"
838
+ )
839
+ );
577
840
  process.exit(1);
578
841
  } else {
579
842
  console.log(chalk2.green("\n\u2705 PR PASSED: AI Readiness Check"));
580
843
  if (threshold) {
581
- console.log(chalk2.green(` Score: ${scoringResult.overall}/100 (threshold: ${threshold})`));
844
+ console.log(
845
+ chalk2.green(
846
+ ` Score: ${scoringResult.overall}/100 (threshold: ${threshold})`
847
+ )
848
+ );
582
849
  }
583
- console.log(chalk2.dim("\n \u{1F4A1} Track historical trends: https://getaiready.dev \u2014 Team plan $99/mo"));
850
+ console.log(
851
+ chalk2.dim(
852
+ "\n \u{1F4A1} Track historical trends: https://getaiready.dev \u2014 Team plan $99/mo"
853
+ )
854
+ );
584
855
  }
585
856
  }
586
857
  } catch (error) {
@@ -659,7 +930,11 @@ async function patternsAction(directory, options) {
659
930
  if (options.minSharedTokens) {
660
931
  cliOptions.minSharedTokens = parseInt(options.minSharedTokens);
661
932
  }
662
- const finalOptions = await loadMergedConfig2(resolvedDir, defaults, cliOptions);
933
+ const finalOptions = await loadMergedConfig2(
934
+ resolvedDir,
935
+ defaults,
936
+ cliOptions
937
+ );
663
938
  const { analyzePatterns, generateSummary, calculatePatternScore } = await import("@aiready/pattern-detect");
664
939
  const { results, duplicates } = await analyzePatterns(finalOptions);
665
940
  const elapsedTime = getElapsedTime2(startTime);
@@ -681,7 +956,11 @@ async function patternsAction(directory, options) {
681
956
  `aiready-report-${getReportTimestamp()}.json`,
682
957
  resolvedDir
683
958
  );
684
- handleJSONOutput2(outputData, outputPath, `\u2705 Results saved to ${outputPath}`);
959
+ handleJSONOutput2(
960
+ outputData,
961
+ outputPath,
962
+ `\u2705 Results saved to ${outputPath}`
963
+ );
685
964
  } else {
686
965
  const terminalWidth = process.stdout.columns || 80;
687
966
  const dividerWidth = Math.min(60, terminalWidth - 2);
@@ -689,10 +968,22 @@ async function patternsAction(directory, options) {
689
968
  console.log(chalk3.cyan(divider));
690
969
  console.log(chalk3.bold.white(" PATTERN ANALYSIS SUMMARY"));
691
970
  console.log(chalk3.cyan(divider) + "\n");
692
- console.log(chalk3.white(`\u{1F4C1} Files analyzed: ${chalk3.bold(results.length)}`));
693
- console.log(chalk3.yellow(`\u26A0 Duplicate patterns found: ${chalk3.bold(summary.totalPatterns)}`));
694
- console.log(chalk3.red(`\u{1F4B0} Token cost (wasted): ${chalk3.bold(summary.totalTokenCost.toLocaleString())}`));
695
- console.log(chalk3.gray(`\u23F1 Analysis time: ${chalk3.bold(elapsedTime + "s")}`));
971
+ console.log(
972
+ chalk3.white(`\u{1F4C1} Files analyzed: ${chalk3.bold(results.length)}`)
973
+ );
974
+ console.log(
975
+ chalk3.yellow(
976
+ `\u26A0 Duplicate patterns found: ${chalk3.bold(summary.totalPatterns)}`
977
+ )
978
+ );
979
+ console.log(
980
+ chalk3.red(
981
+ `\u{1F4B0} Token cost (wasted): ${chalk3.bold(summary.totalTokenCost.toLocaleString())}`
982
+ )
983
+ );
984
+ console.log(
985
+ chalk3.gray(`\u23F1 Analysis time: ${chalk3.bold(elapsedTime + "s")}`)
986
+ );
696
987
  const sortedTypes = Object.entries(summary.patternsByType || {}).filter(([, count]) => count > 0).sort(([, a], [, b]) => b - a);
697
988
  if (sortedTypes.length > 0) {
698
989
  console.log(chalk3.cyan("\n" + divider));
@@ -712,13 +1003,21 @@ async function patternsAction(directory, options) {
712
1003
  const severityIcon = dup.similarity > 0.95 ? "\u{1F534}" : dup.similarity > 0.9 ? "\u{1F7E1}" : "\u{1F535}";
713
1004
  const file1Name = dup.file1.split("/").pop() || dup.file1;
714
1005
  const file2Name = dup.file2.split("/").pop() || dup.file2;
715
- console.log(`${severityIcon} ${severity}: ${chalk3.bold(file1Name)} \u2194 ${chalk3.bold(file2Name)}`);
716
- console.log(` Similarity: ${chalk3.bold(Math.round(dup.similarity * 100) + "%")} | Wasted: ${chalk3.bold(dup.tokenCost.toLocaleString())} tokens each`);
717
- console.log(` Lines: ${chalk3.cyan(dup.line1 + "-" + dup.endLine1)} \u2194 ${chalk3.cyan(dup.line2 + "-" + dup.endLine2)}
718
- `);
1006
+ console.log(
1007
+ `${severityIcon} ${severity}: ${chalk3.bold(file1Name)} \u2194 ${chalk3.bold(file2Name)}`
1008
+ );
1009
+ console.log(
1010
+ ` Similarity: ${chalk3.bold(Math.round(dup.similarity * 100) + "%")} | Wasted: ${chalk3.bold(dup.tokenCost.toLocaleString())} tokens each`
1011
+ );
1012
+ console.log(
1013
+ ` Lines: ${chalk3.cyan(dup.line1 + "-" + dup.endLine1)} \u2194 ${chalk3.cyan(dup.line2 + "-" + dup.endLine2)}
1014
+ `
1015
+ );
719
1016
  });
720
1017
  } else {
721
- console.log(chalk3.green("\n\u2728 Great! No duplicate patterns detected.\n"));
1018
+ console.log(
1019
+ chalk3.green("\n\u2728 Great! No duplicate patterns detected.\n")
1020
+ );
722
1021
  }
723
1022
  if (patternScore) {
724
1023
  console.log(chalk3.cyan(divider));
@@ -765,7 +1064,7 @@ async function contextAction(directory, options) {
765
1064
  file: void 0
766
1065
  }
767
1066
  };
768
- let baseOptions = await loadMergedConfig3(resolvedDir, defaults, {
1067
+ const baseOptions = await loadMergedConfig3(resolvedDir, defaults, {
769
1068
  maxDepth: options.maxDepth ? parseInt(options.maxDepth) : void 0,
770
1069
  maxContextBudget: options.maxContext ? parseInt(options.maxContext) : void 0,
771
1070
  include: options.include?.split(","),
@@ -773,13 +1072,20 @@ async function contextAction(directory, options) {
773
1072
  });
774
1073
  let finalOptions = { ...baseOptions };
775
1074
  const { getSmartDefaults } = await import("@aiready/context-analyzer");
776
- const contextSmartDefaults = await getSmartDefaults(resolvedDir, baseOptions);
1075
+ const contextSmartDefaults = await getSmartDefaults(
1076
+ resolvedDir,
1077
+ baseOptions
1078
+ );
777
1079
  finalOptions = { ...contextSmartDefaults, ...finalOptions };
778
1080
  console.log("\u{1F4CB} Configuration:");
779
1081
  console.log(` Max depth: ${finalOptions.maxDepth}`);
780
1082
  console.log(` Max context budget: ${finalOptions.maxContextBudget}`);
781
- console.log(` Min cohesion: ${(finalOptions.minCohesion * 100).toFixed(1)}%`);
782
- console.log(` Max fragmentation: ${(finalOptions.maxFragmentation * 100).toFixed(1)}%`);
1083
+ console.log(
1084
+ ` Min cohesion: ${(finalOptions.minCohesion * 100).toFixed(1)}%`
1085
+ );
1086
+ console.log(
1087
+ ` Max fragmentation: ${(finalOptions.maxFragmentation * 100).toFixed(1)}%`
1088
+ );
783
1089
  console.log(` Analysis focus: ${finalOptions.focus}`);
784
1090
  console.log("");
785
1091
  const { analyzeContext, generateSummary, calculateContextScore } = await import("@aiready/context-analyzer");
@@ -803,7 +1109,11 @@ async function contextAction(directory, options) {
803
1109
  `aiready-report-${getReportTimestamp()}.json`,
804
1110
  resolvedDir
805
1111
  );
806
- handleJSONOutput3(outputData, outputPath, `\u2705 Results saved to ${outputPath}`);
1112
+ handleJSONOutput3(
1113
+ outputData,
1114
+ outputPath,
1115
+ `\u2705 Results saved to ${outputPath}`
1116
+ );
807
1117
  } else {
808
1118
  const terminalWidth = process.stdout.columns || 80;
809
1119
  const dividerWidth = Math.min(60, terminalWidth - 2);
@@ -811,59 +1121,103 @@ async function contextAction(directory, options) {
811
1121
  console.log(chalk4.cyan(divider));
812
1122
  console.log(chalk4.bold.white(" CONTEXT ANALYSIS SUMMARY"));
813
1123
  console.log(chalk4.cyan(divider) + "\n");
814
- console.log(chalk4.white(`\u{1F4C1} Files analyzed: ${chalk4.bold(summary.totalFiles)}`));
815
- console.log(chalk4.white(`\u{1F4CA} Total tokens: ${chalk4.bold(summary.totalTokens.toLocaleString())}`));
816
- console.log(chalk4.yellow(`\u{1F4B0} Avg context budget: ${chalk4.bold(summary.avgContextBudget.toFixed(0))} tokens/file`));
817
- console.log(chalk4.white(`\u23F1 Analysis time: ${chalk4.bold(elapsedTime + "s")}
818
- `));
1124
+ console.log(
1125
+ chalk4.white(`\u{1F4C1} Files analyzed: ${chalk4.bold(summary.totalFiles)}`)
1126
+ );
1127
+ console.log(
1128
+ chalk4.white(
1129
+ `\u{1F4CA} Total tokens: ${chalk4.bold(summary.totalTokens.toLocaleString())}`
1130
+ )
1131
+ );
1132
+ console.log(
1133
+ chalk4.yellow(
1134
+ `\u{1F4B0} Avg context budget: ${chalk4.bold(summary.avgContextBudget.toFixed(0))} tokens/file`
1135
+ )
1136
+ );
1137
+ console.log(
1138
+ chalk4.white(`\u23F1 Analysis time: ${chalk4.bold(elapsedTime + "s")}
1139
+ `)
1140
+ );
819
1141
  const totalIssues = summary.criticalIssues + summary.majorIssues + summary.minorIssues;
820
1142
  if (totalIssues > 0) {
821
1143
  console.log(chalk4.bold("\u26A0\uFE0F Issues Found:\n"));
822
1144
  if (summary.criticalIssues > 0) {
823
- console.log(chalk4.red(` \u{1F534} Critical: ${chalk4.bold(summary.criticalIssues)}`));
1145
+ console.log(
1146
+ chalk4.red(` \u{1F534} Critical: ${chalk4.bold(summary.criticalIssues)}`)
1147
+ );
824
1148
  }
825
1149
  if (summary.majorIssues > 0) {
826
- console.log(chalk4.yellow(` \u{1F7E1} Major: ${chalk4.bold(summary.majorIssues)}`));
1150
+ console.log(
1151
+ chalk4.yellow(` \u{1F7E1} Major: ${chalk4.bold(summary.majorIssues)}`)
1152
+ );
827
1153
  }
828
1154
  if (summary.minorIssues > 0) {
829
- console.log(chalk4.blue(` \u{1F535} Minor: ${chalk4.bold(summary.minorIssues)}`));
1155
+ console.log(
1156
+ chalk4.blue(` \u{1F535} Minor: ${chalk4.bold(summary.minorIssues)}`)
1157
+ );
830
1158
  }
831
- console.log(chalk4.green(`
1159
+ console.log(
1160
+ chalk4.green(
1161
+ `
832
1162
  \u{1F4A1} Potential savings: ${chalk4.bold(summary.totalPotentialSavings.toLocaleString())} tokens
833
- `));
1163
+ `
1164
+ )
1165
+ );
834
1166
  } else {
835
1167
  console.log(chalk4.green("\u2705 No significant issues found!\n"));
836
1168
  }
837
1169
  if (summary.deepFiles.length > 0) {
838
1170
  console.log(chalk4.bold("\u{1F4CF} Deep Import Chains:\n"));
839
- console.log(chalk4.gray(` Average depth: ${summary.avgImportDepth.toFixed(1)}`));
840
- console.log(chalk4.gray(` Maximum depth: ${summary.maxImportDepth}
841
- `));
1171
+ console.log(
1172
+ chalk4.gray(` Average depth: ${summary.avgImportDepth.toFixed(1)}`)
1173
+ );
1174
+ console.log(
1175
+ chalk4.gray(` Maximum depth: ${summary.maxImportDepth}
1176
+ `)
1177
+ );
842
1178
  summary.deepFiles.slice(0, 10).forEach((item) => {
843
1179
  const fileName = item.file.split("/").slice(-2).join("/");
844
- console.log(` ${chalk4.cyan("\u2192")} ${chalk4.white(fileName)} ${chalk4.dim(`(depth: ${item.depth})`)}`);
1180
+ console.log(
1181
+ ` ${chalk4.cyan("\u2192")} ${chalk4.white(fileName)} ${chalk4.dim(`(depth: ${item.depth})`)}`
1182
+ );
845
1183
  });
846
1184
  console.log();
847
1185
  }
848
1186
  if (summary.fragmentedModules.length > 0) {
849
1187
  console.log(chalk4.bold("\u{1F9E9} Fragmented Modules:\n"));
850
- console.log(chalk4.gray(` Average fragmentation: ${(summary.avgFragmentation * 100).toFixed(0)}%
851
- `));
1188
+ console.log(
1189
+ chalk4.gray(
1190
+ ` Average fragmentation: ${(summary.avgFragmentation * 100).toFixed(0)}%
1191
+ `
1192
+ )
1193
+ );
852
1194
  summary.fragmentedModules.slice(0, 10).forEach((module) => {
853
- console.log(` ${chalk4.yellow("\u25CF")} ${chalk4.white(module.domain)} - ${chalk4.dim(`${module.files.length} files, ${(module.fragmentationScore * 100).toFixed(0)}% scattered`)}`);
854
- console.log(chalk4.dim(` Token cost: ${module.totalTokens.toLocaleString()}, Cohesion: ${(module.avgCohesion * 100).toFixed(0)}%`));
1195
+ console.log(
1196
+ ` ${chalk4.yellow("\u25CF")} ${chalk4.white(module.domain)} - ${chalk4.dim(`${module.files.length} files, ${(module.fragmentationScore * 100).toFixed(0)}% scattered`)}`
1197
+ );
1198
+ console.log(
1199
+ chalk4.dim(
1200
+ ` Token cost: ${module.totalTokens.toLocaleString()}, Cohesion: ${(module.avgCohesion * 100).toFixed(0)}%`
1201
+ )
1202
+ );
855
1203
  });
856
1204
  console.log();
857
1205
  }
858
1206
  if (summary.lowCohesionFiles.length > 0) {
859
1207
  console.log(chalk4.bold("\u{1F500} Low Cohesion Files:\n"));
860
- console.log(chalk4.gray(` Average cohesion: ${(summary.avgCohesion * 100).toFixed(0)}%
861
- `));
1208
+ console.log(
1209
+ chalk4.gray(
1210
+ ` Average cohesion: ${(summary.avgCohesion * 100).toFixed(0)}%
1211
+ `
1212
+ )
1213
+ );
862
1214
  summary.lowCohesionFiles.slice(0, 10).forEach((item) => {
863
1215
  const fileName = item.file.split("/").slice(-2).join("/");
864
1216
  const scorePercent = (item.score * 100).toFixed(0);
865
1217
  const color = item.score < 0.4 ? chalk4.red : chalk4.yellow;
866
- console.log(` ${color("\u25CB")} ${chalk4.white(fileName)} ${chalk4.dim(`(${scorePercent}% cohesion)`)}`);
1218
+ console.log(
1219
+ ` ${color("\u25CB")} ${chalk4.white(fileName)} ${chalk4.dim(`(${scorePercent}% cohesion)`)}`
1220
+ );
867
1221
  });
868
1222
  console.log();
869
1223
  }
@@ -872,7 +1226,9 @@ async function contextAction(directory, options) {
872
1226
  summary.topExpensiveFiles.slice(0, 10).forEach((item) => {
873
1227
  const fileName = item.file.split("/").slice(-2).join("/");
874
1228
  const severityColor = item.severity === "critical" ? chalk4.red : item.severity === "major" ? chalk4.yellow : chalk4.blue;
875
- console.log(` ${severityColor("\u25CF")} ${chalk4.white(fileName)} ${chalk4.dim(`(${item.contextBudget.toLocaleString()} tokens)`)}`);
1229
+ console.log(
1230
+ ` ${severityColor("\u25CF")} ${chalk4.white(fileName)} ${chalk4.dim(`(${item.contextBudget.toLocaleString()} tokens)`)}`
1231
+ );
876
1232
  });
877
1233
  console.log();
878
1234
  }
@@ -930,7 +1286,10 @@ async function consistencyAction(directory, options) {
930
1286
  let consistencyScore;
931
1287
  if (options.score) {
932
1288
  const issues = report.results?.flatMap((r) => r.issues) || [];
933
- consistencyScore = calculateConsistencyScore(issues, report.summary.filesAnalyzed);
1289
+ consistencyScore = calculateConsistencyScore(
1290
+ issues,
1291
+ report.summary.filesAnalyzed
1292
+ );
934
1293
  }
935
1294
  const outputFormat = options.output || finalOptions.output?.format || "console";
936
1295
  const userOutputFile = options.outputFile || finalOptions.output?.file;
@@ -948,7 +1307,11 @@ async function consistencyAction(directory, options) {
948
1307
  `aiready-report-${getReportTimestamp()}.json`,
949
1308
  resolvedDir
950
1309
  );
951
- handleJSONOutput4(outputData, outputPath, `\u2705 Results saved to ${outputPath}`);
1310
+ handleJSONOutput4(
1311
+ outputData,
1312
+ outputPath,
1313
+ `\u2705 Results saved to ${outputPath}`
1314
+ );
952
1315
  } else if (outputFormat === "markdown") {
953
1316
  const markdown = generateMarkdownReport(report, elapsedTime);
954
1317
  const outputPath = resolveOutputPath4(
@@ -960,15 +1323,23 @@ async function consistencyAction(directory, options) {
960
1323
  console.log(chalk5.green(`\u2705 Report saved to ${outputPath}`));
961
1324
  } else {
962
1325
  console.log(chalk5.bold("\n\u{1F4CA} Summary\n"));
963
- console.log(`Files Analyzed: ${chalk5.cyan(report.summary.filesAnalyzed)}`);
1326
+ console.log(
1327
+ `Files Analyzed: ${chalk5.cyan(report.summary.filesAnalyzed)}`
1328
+ );
964
1329
  console.log(`Total Issues: ${chalk5.yellow(report.summary.totalIssues)}`);
965
1330
  console.log(` Naming: ${chalk5.yellow(report.summary.namingIssues)}`);
966
1331
  console.log(` Patterns: ${chalk5.yellow(report.summary.patternIssues)}`);
967
- console.log(` Architecture: ${chalk5.yellow(report.summary.architectureIssues || 0)}`);
1332
+ console.log(
1333
+ ` Architecture: ${chalk5.yellow(report.summary.architectureIssues || 0)}`
1334
+ );
968
1335
  console.log(`Analysis Time: ${chalk5.gray(elapsedTime + "s")}
969
1336
  `);
970
1337
  if (report.summary.totalIssues === 0) {
971
- console.log(chalk5.green("\u2728 No consistency issues found! Your codebase is well-maintained.\n"));
1338
+ console.log(
1339
+ chalk5.green(
1340
+ "\u2728 No consistency issues found! Your codebase is well-maintained.\n"
1341
+ )
1342
+ );
972
1343
  } else {
973
1344
  const namingResults = report.results.filter(
974
1345
  (r) => r.issues.some((i) => i.category === "naming")
@@ -984,10 +1355,14 @@ async function consistencyAction(directory, options) {
984
1355
  for (const issue of result.issues) {
985
1356
  if (shown >= 5) break;
986
1357
  const severityColor = issue.severity === "critical" ? chalk5.red : issue.severity === "major" ? chalk5.yellow : issue.severity === "minor" ? chalk5.blue : chalk5.gray;
987
- console.log(`${severityColor(issue.severity.toUpperCase())} ${chalk5.dim(`${issue.location.file}:${issue.location.line}`)}`);
1358
+ console.log(
1359
+ `${severityColor(issue.severity.toUpperCase())} ${chalk5.dim(`${issue.location.file}:${issue.location.line}`)}`
1360
+ );
988
1361
  console.log(` ${issue.message}`);
989
1362
  if (issue.suggestion) {
990
- console.log(` ${chalk5.dim("\u2192")} ${chalk5.italic(issue.suggestion)}`);
1363
+ console.log(
1364
+ ` ${chalk5.dim("\u2192")} ${chalk5.italic(issue.suggestion)}`
1365
+ );
991
1366
  }
992
1367
  console.log();
993
1368
  shown++;
@@ -1007,10 +1382,14 @@ async function consistencyAction(directory, options) {
1007
1382
  for (const issue of result.issues) {
1008
1383
  if (shown >= 5) break;
1009
1384
  const severityColor = issue.severity === "critical" ? chalk5.red : issue.severity === "major" ? chalk5.yellow : issue.severity === "minor" ? chalk5.blue : chalk5.gray;
1010
- console.log(`${severityColor(issue.severity.toUpperCase())} ${chalk5.dim(`${issue.location.file}:${issue.location.line}`)}`);
1385
+ console.log(
1386
+ `${severityColor(issue.severity.toUpperCase())} ${chalk5.dim(`${issue.location.file}:${issue.location.line}`)}`
1387
+ );
1011
1388
  console.log(` ${issue.message}`);
1012
1389
  if (issue.suggestion) {
1013
- console.log(` ${chalk5.dim("\u2192")} ${chalk5.italic(issue.suggestion)}`);
1390
+ console.log(
1391
+ ` ${chalk5.dim("\u2192")} ${chalk5.italic(issue.suggestion)}`
1392
+ );
1014
1393
  }
1015
1394
  console.log();
1016
1395
  shown++;
@@ -1043,7 +1422,7 @@ async function consistencyAction(directory, options) {
1043
1422
 
1044
1423
  // src/commands/visualize.ts
1045
1424
  import chalk6 from "chalk";
1046
- import { writeFileSync as writeFileSync3, readFileSync as readFileSync3, existsSync as existsSync2, copyFileSync as copyFileSync2 } from "fs";
1425
+ import { writeFileSync as writeFileSync3, readFileSync as readFileSync3, existsSync as existsSync2, copyFileSync } from "fs";
1047
1426
  import { resolve as resolvePath6 } from "path";
1048
1427
  import { spawn } from "child_process";
1049
1428
  import { handleCLIError as handleCLIError5 } from "@aiready/core";
@@ -1056,15 +1435,21 @@ async function visualizeAction(directory, options) {
1056
1435
  const latestScan = findLatestScanReport(dirPath);
1057
1436
  if (latestScan) {
1058
1437
  reportPath = latestScan;
1059
- console.log(chalk6.dim(`Found latest report: ${latestScan.split("/").pop()}`));
1438
+ console.log(
1439
+ chalk6.dim(`Found latest report: ${latestScan.split("/").pop()}`)
1440
+ );
1060
1441
  } else {
1061
1442
  console.error(chalk6.red("\u274C No AI readiness report found"));
1062
- console.log(chalk6.dim(`
1443
+ console.log(
1444
+ chalk6.dim(
1445
+ `
1063
1446
  Generate a report with:
1064
1447
  aiready scan --output json
1065
1448
 
1066
1449
  Or specify a custom report:
1067
- aiready visualise --report <path-to-report.json>`));
1450
+ aiready visualise --report <path-to-report.json>`
1451
+ )
1452
+ );
1068
1453
  return;
1069
1454
  }
1070
1455
  }
@@ -1082,6 +1467,7 @@ Or specify a custom report:
1082
1467
  };
1083
1468
  }
1084
1469
  } catch (e) {
1470
+ void e;
1085
1471
  }
1086
1472
  }
1087
1473
  const envVisualizerConfig = JSON.stringify(graphConfig);
@@ -1102,11 +1488,18 @@ Or specify a custom report:
1102
1488
  } else {
1103
1489
  const nodemodulesLocations = [
1104
1490
  resolvePath6(dirPath, "node_modules", "@aiready", "visualizer"),
1105
- resolvePath6(process.cwd(), "node_modules", "@aiready", "visualizer")
1491
+ resolvePath6(
1492
+ process.cwd(),
1493
+ "node_modules",
1494
+ "@aiready",
1495
+ "visualizer"
1496
+ )
1106
1497
  ];
1107
1498
  let currentDir = dirPath;
1108
1499
  while (currentDir !== "/" && currentDir !== ".") {
1109
- nodemodulesLocations.push(resolvePath6(currentDir, "node_modules", "@aiready", "visualizer"));
1500
+ nodemodulesLocations.push(
1501
+ resolvePath6(currentDir, "node_modules", "@aiready", "visualizer")
1502
+ );
1110
1503
  const parent = resolvePath6(currentDir, "..");
1111
1504
  if (parent === currentDir) break;
1112
1505
  currentDir = parent;
@@ -1123,7 +1516,8 @@ Or specify a custom report:
1123
1516
  const vizPkgPath = __require.resolve("@aiready/visualizer/package.json");
1124
1517
  webDir = resolvePath6(vizPkgPath, "..");
1125
1518
  visualizerAvailable = true;
1126
- } catch (e) {
1519
+ } catch (err) {
1520
+ void err;
1127
1521
  }
1128
1522
  }
1129
1523
  }
@@ -1134,7 +1528,7 @@ Or specify a custom report:
1134
1528
  const copyReportToViz = () => {
1135
1529
  try {
1136
1530
  const destPath = resolvePath6(spawnCwd, "web", "report-data.json");
1137
- copyFileSync2(reportPath, destPath);
1531
+ copyFileSync(reportPath, destPath);
1138
1532
  console.log(`\u{1F4CB} Report synced to ${destPath}`);
1139
1533
  } catch (e) {
1140
1534
  console.error("Failed to sync report:", e);
@@ -1151,30 +1545,46 @@ Or specify a custom report:
1151
1545
  AIREADY_REPORT_PATH: reportPath,
1152
1546
  AIREADY_VISUALIZER_CONFIG: envVisualizerConfig
1153
1547
  };
1154
- const vite = spawn("pnpm", ["run", "dev:web"], { cwd: spawnCwd, stdio: "inherit", shell: true, env: envForSpawn });
1548
+ const vite = spawn("pnpm", ["run", "dev:web"], {
1549
+ cwd: spawnCwd,
1550
+ stdio: "inherit",
1551
+ shell: true,
1552
+ env: envForSpawn
1553
+ });
1155
1554
  const onExit = () => {
1156
1555
  try {
1157
1556
  reportWatcher.close();
1158
- } catch (e) {
1557
+ } catch (err) {
1558
+ void err;
1159
1559
  }
1160
1560
  try {
1161
1561
  vite.kill();
1162
- } catch (e) {
1562
+ } catch (err) {
1563
+ void err;
1163
1564
  }
1164
1565
  process.exit(0);
1165
1566
  };
1166
1567
  process.on("SIGINT", onExit);
1167
1568
  process.on("SIGTERM", onExit);
1168
1569
  devServerStarted = true;
1570
+ void devServerStarted;
1169
1571
  return;
1170
1572
  } else {
1171
- console.log(chalk6.yellow("\u26A0\uFE0F Dev server not available (requires local @aiready/visualizer with web assets)."));
1172
- console.log(chalk6.cyan(" Falling back to static HTML generation...\n"));
1573
+ console.log(
1574
+ chalk6.yellow(
1575
+ "\u26A0\uFE0F Dev server not available (requires local @aiready/visualizer with web assets)."
1576
+ )
1577
+ );
1578
+ console.log(
1579
+ chalk6.cyan(" Falling back to static HTML generation...\n")
1580
+ );
1173
1581
  useDevMode = false;
1174
1582
  }
1175
1583
  } catch (err) {
1176
1584
  console.error("Failed to start dev server:", err);
1177
- console.log(chalk6.cyan(" Falling back to static HTML generation...\n"));
1585
+ console.log(
1586
+ chalk6.cyan(" Falling back to static HTML generation...\n")
1587
+ );
1178
1588
  useDevMode = false;
1179
1589
  }
1180
1590
  }
@@ -1196,20 +1606,25 @@ Or specify a custom report:
1196
1606
  const urlPath = req.url || "/";
1197
1607
  if (urlPath === "/" || urlPath === "/index.html") {
1198
1608
  const content = await fsp.readFile(outPath, "utf8");
1199
- res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
1609
+ res.writeHead(200, {
1610
+ "Content-Type": "text/html; charset=utf-8"
1611
+ });
1200
1612
  res.end(content);
1201
1613
  return;
1202
1614
  }
1203
1615
  res.writeHead(404, { "Content-Type": "text/plain" });
1204
1616
  res.end("Not found");
1205
1617
  } catch (e) {
1618
+ void e;
1206
1619
  res.writeHead(500, { "Content-Type": "text/plain" });
1207
1620
  res.end("Server error");
1208
1621
  }
1209
1622
  });
1210
1623
  server.listen(port, () => {
1211
1624
  const addr = `http://localhost:${port}/`;
1212
- console.log(chalk6.cyan(`\u{1F310} Local visualization server running at ${addr}`));
1625
+ console.log(
1626
+ chalk6.cyan(`\u{1F310} Local visualization server running at ${addr}`)
1627
+ );
1213
1628
  spawn(opener, [`"${addr}"`], { shell: true });
1214
1629
  });
1215
1630
  process.on("SIGINT", () => {
@@ -1274,9 +1689,13 @@ var getDirname = () => {
1274
1689
  if (typeof __dirname !== "undefined") return __dirname;
1275
1690
  return dirname(fileURLToPath(import.meta.url));
1276
1691
  };
1277
- var packageJson = JSON.parse(readFileSync4(join(getDirname(), "../package.json"), "utf8"));
1692
+ var packageJson = JSON.parse(
1693
+ readFileSync4(join(getDirname(), "../package.json"), "utf8")
1694
+ );
1278
1695
  var program = new Command();
1279
- program.name("aiready").description("AIReady - Assess and improve AI-readiness of codebases").version(packageJson.version).addHelpText("after", `
1696
+ program.name("aiready").description("AIReady - Assess and improve AI-readiness of codebases").version(packageJson.version).addHelpText(
1697
+ "after",
1698
+ `
1280
1699
  AI READINESS SCORING:
1281
1700
  Get a 0-100 score indicating how AI-ready your codebase is.
1282
1701
  Use --score flag with any analysis command for detailed breakdown.
@@ -1311,23 +1730,105 @@ CONFIGURATION:
1311
1730
  VERSION: ${packageJson.version}
1312
1731
  DOCUMENTATION: https://aiready.dev/docs/cli
1313
1732
  GITHUB: https://github.com/caopengau/aiready-cli
1314
- LANDING: https://github.com/caopengau/aiready-landing`);
1315
- program.command("scan").description("Run comprehensive AI-readiness analysis (patterns + context + consistency)").argument("[directory]", "Directory to analyze", ".").option("-t, --tools <tools>", "Tools to run (comma-separated: patterns,context,consistency,doc-drift,deps-health,aiSignalClarity,grounding,testability,changeAmplification)").option("--profile <type>", "Scan profile to use (agentic, cost, security, onboarding)").option("--compare-to <path>", "Compare results against a previous AIReady report JSON").option("--include <patterns>", "File patterns to include (comma-separated)").option("--exclude <patterns>", "File patterns to exclude (comma-separated)").option("-o, --output <format>", "Output format: console, json", "console").option("--output-file <path>", "Output file path (for json)").option("--no-score", "Disable calculating AI Readiness Score (enabled by default)").option("--weights <weights>", "Custom scoring weights").option("--threshold <score>", "Fail CI/CD if score below threshold (0-100)").option("--ci", "CI mode: GitHub Actions annotations, no colors, fail on threshold").option("--fail-on <level>", "Fail on issues: critical, major, any", "critical").addHelpText("after", scanHelpText).action(async (directory, options) => {
1733
+ LANDING: https://github.com/caopengau/aiready-landing`
1734
+ );
1735
+ program.command("scan").description(
1736
+ "Run comprehensive AI-readiness analysis (patterns + context + consistency)"
1737
+ ).argument("[directory]", "Directory to analyze", ".").option(
1738
+ "-t, --tools <tools>",
1739
+ "Tools to run (comma-separated: patterns,context,consistency,doc-drift,deps-health,aiSignalClarity,grounding,testability,changeAmplification)"
1740
+ ).option(
1741
+ "--profile <type>",
1742
+ "Scan profile to use (agentic, cost, security, onboarding)"
1743
+ ).option(
1744
+ "--compare-to <path>",
1745
+ "Compare results against a previous AIReady report JSON"
1746
+ ).option("--include <patterns>", "File patterns to include (comma-separated)").option("--exclude <patterns>", "File patterns to exclude (comma-separated)").option("-o, --output <format>", "Output format: console, json", "console").option("--output-file <path>", "Output file path (for json)").option(
1747
+ "--no-score",
1748
+ "Disable calculating AI Readiness Score (enabled by default)"
1749
+ ).option("--weights <weights>", "Custom scoring weights").option("--threshold <score>", "Fail CI/CD if score below threshold (0-100)").option(
1750
+ "--ci",
1751
+ "CI mode: GitHub Actions annotations, no colors, fail on threshold"
1752
+ ).option(
1753
+ "--fail-on <level>",
1754
+ "Fail on issues: critical, major, any",
1755
+ "critical"
1756
+ ).addHelpText("after", scanHelpText).action(async (directory, options) => {
1316
1757
  await scanAction(directory, options);
1317
1758
  });
1318
- program.command("patterns").description("Detect duplicate code patterns that confuse AI models").argument("[directory]", "Directory to analyze", ".").option("-s, --similarity <number>", "Minimum similarity score (0-1)", "0.40").option("-l, --min-lines <number>", "Minimum lines to consider", "5").option("--max-candidates <number>", "Maximum candidates per block (performance tuning)").option("--min-shared-tokens <number>", "Minimum shared tokens for candidates (performance tuning)").option("--full-scan", "Disable smart defaults for comprehensive analysis (slower)").option("--include <patterns>", "File patterns to include (comma-separated)").option("--exclude <patterns>", "File patterns to exclude (comma-separated)").option("-o, --output <format>", "Output format: console, json", "console").option("--output-file <path>", "Output file path (for json)").option("--score", "Calculate and display AI Readiness Score for patterns (0-100)").addHelpText("after", patternsHelpText).action(async (directory, options) => {
1759
+ program.command("patterns").description("Detect duplicate code patterns that confuse AI models").argument("[directory]", "Directory to analyze", ".").option("-s, --similarity <number>", "Minimum similarity score (0-1)", "0.40").option("-l, --min-lines <number>", "Minimum lines to consider", "5").option(
1760
+ "--max-candidates <number>",
1761
+ "Maximum candidates per block (performance tuning)"
1762
+ ).option(
1763
+ "--min-shared-tokens <number>",
1764
+ "Minimum shared tokens for candidates (performance tuning)"
1765
+ ).option(
1766
+ "--full-scan",
1767
+ "Disable smart defaults for comprehensive analysis (slower)"
1768
+ ).option("--include <patterns>", "File patterns to include (comma-separated)").option("--exclude <patterns>", "File patterns to exclude (comma-separated)").option("-o, --output <format>", "Output format: console, json", "console").option("--output-file <path>", "Output file path (for json)").option(
1769
+ "--score",
1770
+ "Calculate and display AI Readiness Score for patterns (0-100)"
1771
+ ).addHelpText("after", patternsHelpText).action(async (directory, options) => {
1319
1772
  await patternsAction(directory, options);
1320
1773
  });
1321
- program.command("context").description("Analyze context window costs and dependency fragmentation").argument("[directory]", "Directory to analyze", ".").option("--max-depth <number>", "Maximum acceptable import depth", "5").option("--max-context <number>", "Maximum acceptable context budget (tokens)", "10000").option("--include <patterns>", "File patterns to include (comma-separated)").option("--exclude <patterns>", "File patterns to exclude (comma-separated)").option("-o, --output <format>", "Output format: console, json", "console").option("--output-file <path>", "Output file path (for json)").option("--score", "Calculate and display AI Readiness Score for context (0-100)").action(async (directory, options) => {
1774
+ program.command("context").description("Analyze context window costs and dependency fragmentation").argument("[directory]", "Directory to analyze", ".").option("--max-depth <number>", "Maximum acceptable import depth", "5").option(
1775
+ "--max-context <number>",
1776
+ "Maximum acceptable context budget (tokens)",
1777
+ "10000"
1778
+ ).option("--include <patterns>", "File patterns to include (comma-separated)").option("--exclude <patterns>", "File patterns to exclude (comma-separated)").option("-o, --output <format>", "Output format: console, json", "console").option("--output-file <path>", "Output file path (for json)").option(
1779
+ "--score",
1780
+ "Calculate and display AI Readiness Score for context (0-100)"
1781
+ ).action(async (directory, options) => {
1322
1782
  await contextAction(directory, options);
1323
1783
  });
1324
- program.command("consistency").description("Check naming conventions and architectural consistency").argument("[directory]", "Directory to analyze", ".").option("--naming", "Check naming conventions (default: true)").option("--no-naming", "Skip naming analysis").option("--patterns", "Check code patterns (default: true)").option("--no-patterns", "Skip pattern analysis").option("--min-severity <level>", "Minimum severity: info|minor|major|critical", "info").option("--include <patterns>", "File patterns to include (comma-separated)").option("--exclude <patterns>", "File patterns to exclude (comma-separated)").option("-o, --output <format>", "Output format: console, json, markdown", "console").option("--output-file <path>", "Output file path (for json/markdown)").option("--score", "Calculate and display AI Readiness Score for consistency (0-100)").action(async (directory, options) => {
1784
+ program.command("consistency").description("Check naming conventions and architectural consistency").argument("[directory]", "Directory to analyze", ".").option("--naming", "Check naming conventions (default: true)").option("--no-naming", "Skip naming analysis").option("--patterns", "Check code patterns (default: true)").option("--no-patterns", "Skip pattern analysis").option(
1785
+ "--min-severity <level>",
1786
+ "Minimum severity: info|minor|major|critical",
1787
+ "info"
1788
+ ).option("--include <patterns>", "File patterns to include (comma-separated)").option("--exclude <patterns>", "File patterns to exclude (comma-separated)").option(
1789
+ "-o, --output <format>",
1790
+ "Output format: console, json, markdown",
1791
+ "console"
1792
+ ).option("--output-file <path>", "Output file path (for json/markdown)").option(
1793
+ "--score",
1794
+ "Calculate and display AI Readiness Score for consistency (0-100)"
1795
+ ).action(async (directory, options) => {
1325
1796
  await consistencyAction(directory, options);
1326
1797
  });
1327
- program.command("visualise").description("Alias for visualize (British spelling)").argument("[directory]", "Directory to analyze", ".").option("--report <path>", "Report path (auto-detects latest .aiready/aiready-report-*.json if not provided)").option("-o, --output <path>", "Output HTML path (relative to directory)", "packages/visualizer/visualization.html").option("--open", "Open generated HTML in default browser").option("--serve [port]", "Start a local static server to serve the visualization (optional port number)", false).option("--dev", "Start Vite dev server (live reload) for interactive development", true).addHelpText("after", visualiseHelpText).action(async (directory, options) => {
1798
+ program.command("visualise").description("Alias for visualize (British spelling)").argument("[directory]", "Directory to analyze", ".").option(
1799
+ "--report <path>",
1800
+ "Report path (auto-detects latest .aiready/aiready-report-*.json if not provided)"
1801
+ ).option(
1802
+ "-o, --output <path>",
1803
+ "Output HTML path (relative to directory)",
1804
+ "packages/visualizer/visualization.html"
1805
+ ).option("--open", "Open generated HTML in default browser").option(
1806
+ "--serve [port]",
1807
+ "Start a local static server to serve the visualization (optional port number)",
1808
+ false
1809
+ ).option(
1810
+ "--dev",
1811
+ "Start Vite dev server (live reload) for interactive development",
1812
+ true
1813
+ ).addHelpText("after", visualiseHelpText).action(async (directory, options) => {
1328
1814
  await visualizeAction(directory, options);
1329
1815
  });
1330
- program.command("visualize").description("Generate interactive visualization from an AIReady report").argument("[directory]", "Directory to analyze", ".").option("--report <path>", "Report path (auto-detects latest .aiready/aiready-report-*.json if not provided)").option("-o, --output <path>", "Output HTML path (relative to directory)", "packages/visualizer/visualization.html").option("--open", "Open generated HTML in default browser").option("--serve [port]", "Start a local static server to serve the visualization (optional port number)", false).option("--dev", "Start Vite dev server (live reload) for interactive development", false).addHelpText("after", visualizeHelpText).action(async (directory, options) => {
1816
+ program.command("visualize").description("Generate interactive visualization from an AIReady report").argument("[directory]", "Directory to analyze", ".").option(
1817
+ "--report <path>",
1818
+ "Report path (auto-detects latest .aiready/aiready-report-*.json if not provided)"
1819
+ ).option(
1820
+ "-o, --output <path>",
1821
+ "Output HTML path (relative to directory)",
1822
+ "packages/visualizer/visualization.html"
1823
+ ).option("--open", "Open generated HTML in default browser").option(
1824
+ "--serve [port]",
1825
+ "Start a local static server to serve the visualization (optional port number)",
1826
+ false
1827
+ ).option(
1828
+ "--dev",
1829
+ "Start Vite dev server (live reload) for interactive development",
1830
+ false
1831
+ ).addHelpText("after", visualizeHelpText).action(async (directory, options) => {
1331
1832
  await visualizeAction(directory, options);
1332
1833
  });
1333
1834
  program.command("change-amplification").description("Analyze graph metrics for change amplification").argument("[directory]", "Directory to analyze", ".").option("--include <patterns>", "File patterns to include (comma-separated)").option("--exclude <patterns>", "File patterns to exclude (comma-separated)").option("-o, --output <format>", "Output format: console, json", "console").option("--output-file <path>", "Output file path (for json)").action(async (directory, options) => {