@aiready/cli 0.9.40 → 0.9.43

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-LLJMKNBI.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,134 @@ 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
+ onProgress: (processed, total, message) => {
493
+ process.stdout.write(
494
+ `\r\x1B[K [${processed}/${total}] ${message}...`
495
+ );
496
+ if (processed === total) {
497
+ process.stdout.write("\n");
498
+ }
499
+ },
500
+ suppressToolConfig: true
501
+ });
336
502
  console.log(chalk2.cyan("\n=== AIReady Run Summary ==="));
337
- console.log(chalk2.white("Tools run:"), (finalOptions.tools || ["patterns", "context", "consistency"]).join(", "));
503
+ console.log(
504
+ chalk2.white("Tools run:"),
505
+ (finalOptions.tools || ["patterns", "context", "consistency"]).join(", ")
506
+ );
338
507
  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`);
508
+ console.log(
509
+ ` Total issues (all tools): ${chalk2.bold(String(results.summary.totalIssues || 0))}`
510
+ );
511
+ if (results.duplicates)
512
+ console.log(
513
+ ` Duplicate patterns found: ${chalk2.bold(String(results.duplicates.length || 0))}`
514
+ );
515
+ if (results.patterns)
516
+ console.log(
517
+ ` Pattern files with issues: ${chalk2.bold(String(results.patterns.length || 0))}`
518
+ );
519
+ if (results.context)
520
+ console.log(
521
+ ` Context issues: ${chalk2.bold(String(results.context.length || 0))}`
522
+ );
523
+ console.log(
524
+ ` Consistency issues: ${chalk2.bold(String(results.consistency?.summary?.totalIssues || 0))}`
525
+ );
526
+ if (results.changeAmplification)
527
+ console.log(
528
+ ` Change amplification: ${chalk2.bold(String(results.changeAmplification.summary?.score || 0))}/100`
529
+ );
345
530
  console.log(chalk2.cyan("===========================\n"));
346
531
  const elapsedTime = getElapsedTime(startTime);
532
+ void elapsedTime;
347
533
  let scoringResult;
348
534
  if (options.score || finalOptions.scoring?.showBreakdown) {
349
535
  const toolScores = /* @__PURE__ */ new Map();
350
536
  if (results.duplicates) {
351
537
  const { calculatePatternScore } = await import("@aiready/pattern-detect");
352
538
  try {
353
- const patternScore = calculatePatternScore(results.duplicates, results.patterns?.length || 0);
539
+ const patternScore = calculatePatternScore(
540
+ results.duplicates,
541
+ results.patterns?.length || 0
542
+ );
354
543
  toolScores.set("pattern-detect", patternScore);
355
544
  } catch (err) {
545
+ void err;
356
546
  }
357
547
  }
358
548
  if (results.context) {
@@ -362,6 +552,7 @@ async function scanAction(directory, options) {
362
552
  const contextScore = calculateContextScore(ctxSummary);
363
553
  toolScores.set("context-analyzer", contextScore);
364
554
  } catch (err) {
555
+ void err;
365
556
  }
366
557
  }
367
558
  if (results.consistency) {
@@ -369,17 +560,24 @@ async function scanAction(directory, options) {
369
560
  try {
370
561
  const issues = results.consistency.results?.flatMap((r) => r.issues) || [];
371
562
  const totalFiles = results.consistency.summary?.filesAnalyzed || 0;
372
- const consistencyScore = calculateConsistencyScore(issues, totalFiles);
563
+ const consistencyScore = calculateConsistencyScore(
564
+ issues,
565
+ totalFiles
566
+ );
373
567
  toolScores.set("consistency", consistencyScore);
374
568
  } catch (err) {
569
+ void err;
375
570
  }
376
571
  }
377
572
  if (results.aiSignalClarity) {
378
573
  const { calculateAiSignalClarityScore } = await import("@aiready/ai-signal-clarity");
379
574
  try {
380
- const hrScore = calculateAiSignalClarityScore(results.aiSignalClarity);
575
+ const hrScore = calculateAiSignalClarityScore(
576
+ results.aiSignalClarity
577
+ );
381
578
  toolScores.set("ai-signal-clarity", hrScore);
382
579
  } catch (err) {
580
+ void err;
383
581
  }
384
582
  }
385
583
  if (results.grounding) {
@@ -388,6 +586,7 @@ async function scanAction(directory, options) {
388
586
  const agScore = calculateGroundingScore(results.grounding);
389
587
  toolScores.set("agent-grounding", agScore);
390
588
  } catch (err) {
589
+ void err;
391
590
  }
392
591
  }
393
592
  if (results.testability) {
@@ -396,6 +595,7 @@ async function scanAction(directory, options) {
396
595
  const tbScore = calculateTestabilityScore(results.testability);
397
596
  toolScores.set("testability", tbScore);
398
597
  } catch (err) {
598
+ void err;
399
599
  }
400
600
  }
401
601
  if (results.docDrift) {
@@ -404,7 +604,13 @@ async function scanAction(directory, options) {
404
604
  score: results.docDrift.summary.score,
405
605
  rawMetrics: results.docDrift.rawData,
406
606
  factors: [],
407
- recommendations: (results.docDrift.recommendations || []).map((action) => ({ action, estimatedImpact: 5, priority: "medium" }))
607
+ recommendations: (results.docDrift.recommendations || []).map(
608
+ (action) => ({
609
+ action,
610
+ estimatedImpact: 5,
611
+ priority: "medium"
612
+ })
613
+ )
408
614
  });
409
615
  }
410
616
  if (results.deps) {
@@ -413,7 +619,13 @@ async function scanAction(directory, options) {
413
619
  score: results.deps.summary.score,
414
620
  rawMetrics: results.deps.rawData,
415
621
  factors: [],
416
- recommendations: (results.deps.recommendations || []).map((action) => ({ action, estimatedImpact: 5, priority: "medium" }))
622
+ recommendations: (results.deps.recommendations || []).map(
623
+ (action) => ({
624
+ action,
625
+ estimatedImpact: 5,
626
+ priority: "medium"
627
+ })
628
+ )
417
629
  });
418
630
  }
419
631
  if (results.changeAmplification) {
@@ -422,17 +634,28 @@ async function scanAction(directory, options) {
422
634
  score: results.changeAmplification.summary.score,
423
635
  rawMetrics: results.changeAmplification.rawData,
424
636
  factors: [],
425
- recommendations: (results.changeAmplification.recommendations || []).map((action) => ({ action, estimatedImpact: 5, priority: "medium" }))
637
+ recommendations: (results.changeAmplification.recommendations || []).map((action) => ({
638
+ action,
639
+ estimatedImpact: 5,
640
+ priority: "medium"
641
+ }))
426
642
  });
427
643
  }
428
644
  const cliWeights = parseWeightString(options.weights);
429
645
  if (toolScores.size > 0) {
430
- scoringResult = calculateOverallScore(toolScores, finalOptions, cliWeights.size ? cliWeights : void 0);
646
+ scoringResult = calculateOverallScore(
647
+ toolScores,
648
+ finalOptions,
649
+ cliWeights.size ? cliWeights : void 0
650
+ );
431
651
  console.log(chalk2.bold("\n\u{1F4CA} AI Readiness Overall Score"));
432
652
  console.log(` ${formatScore(scoringResult)}`);
433
653
  if (options.compareTo) {
434
654
  try {
435
- const prevReportStr = readFileSync2(resolvePath2(process.cwd(), options.compareTo), "utf8");
655
+ const prevReportStr = readFileSync2(
656
+ resolvePath2(process.cwd(), options.compareTo),
657
+ "utf8"
658
+ );
436
659
  const prevReport = JSON.parse(prevReportStr);
437
660
  const prevScore = prevReport.scoring?.score || prevReport.scoring?.overallScore;
438
661
  if (typeof prevScore === "number") {
@@ -440,23 +663,44 @@ async function scanAction(directory, options) {
440
663
  const diffStr = diff > 0 ? `+${diff}` : String(diff);
441
664
  console.log();
442
665
  if (diff > 0) {
443
- console.log(chalk2.green(` \u{1F4C8} Trend: ${diffStr} compared to ${options.compareTo} (${prevScore} \u2192 ${scoringResult.overall})`));
666
+ console.log(
667
+ chalk2.green(
668
+ ` \u{1F4C8} Trend: ${diffStr} compared to ${options.compareTo} (${prevScore} \u2192 ${scoringResult.overall})`
669
+ )
670
+ );
444
671
  } else if (diff < 0) {
445
- console.log(chalk2.red(` \u{1F4C9} Trend: ${diffStr} compared to ${options.compareTo} (${prevScore} \u2192 ${scoringResult.overall})`));
672
+ console.log(
673
+ chalk2.red(
674
+ ` \u{1F4C9} Trend: ${diffStr} compared to ${options.compareTo} (${prevScore} \u2192 ${scoringResult.overall})`
675
+ )
676
+ );
446
677
  } else {
447
- console.log(chalk2.blue(` \u2796 Trend: No change compared to ${options.compareTo} (${prevScore} \u2192 ${scoringResult.overall})`));
678
+ console.log(
679
+ chalk2.blue(
680
+ ` \u2796 Trend: No change compared to ${options.compareTo} (${prevScore} \u2192 ${scoringResult.overall})`
681
+ )
682
+ );
448
683
  }
449
684
  scoringResult.trend = {
450
685
  previousScore: prevScore,
451
686
  difference: diff
452
687
  };
453
688
  } else {
454
- console.log(chalk2.yellow(`
455
- \u26A0\uFE0F Previous report at ${options.compareTo} does not contain an overall score.`));
689
+ console.log(
690
+ chalk2.yellow(
691
+ `
692
+ \u26A0\uFE0F Previous report at ${options.compareTo} does not contain an overall score.`
693
+ )
694
+ );
456
695
  }
457
696
  } catch (e) {
458
- console.log(chalk2.yellow(`
459
- \u26A0\uFE0F Could not read or parse previous report at ${options.compareTo}.`));
697
+ void e;
698
+ console.log(
699
+ chalk2.yellow(
700
+ `
701
+ \u26A0\uFE0F Could not read or parse previous report at ${options.compareTo}.`
702
+ )
703
+ );
460
704
  }
461
705
  }
462
706
  if (scoringResult.breakdown && scoringResult.breakdown.length > 0) {
@@ -464,7 +708,9 @@ async function scanAction(directory, options) {
464
708
  scoringResult.breakdown.forEach((tool) => {
465
709
  const rating = getRating(tool.score);
466
710
  const rd = getRatingDisplay(rating);
467
- console.log(` - ${tool.toolName}: ${tool.score}/100 (${rating}) ${rd.emoji}`);
711
+ console.log(
712
+ ` - ${tool.toolName}: ${tool.score}/100 (${rating}) ${rd.emoji}`
713
+ );
468
714
  });
469
715
  console.log();
470
716
  if (finalOptions.scoring?.showBreakdown) {
@@ -482,20 +728,33 @@ async function scanAction(directory, options) {
482
728
  if (outputFormat === "json") {
483
729
  const timestamp = getReportTimestamp();
484
730
  const defaultFilename = `aiready-report-${timestamp}.json`;
485
- const outputPath = resolveOutputPath(userOutputFile, defaultFilename, resolvedDir);
731
+ const outputPath = resolveOutputPath(
732
+ userOutputFile,
733
+ defaultFilename,
734
+ resolvedDir
735
+ );
486
736
  const outputData = { ...results, scoring: scoringResult };
487
- handleJSONOutput(outputData, outputPath, `\u2705 Report saved to ${outputPath}`);
488
- warnIfGraphCapExceeded(outputData, resolvedDir);
737
+ handleJSONOutput(
738
+ outputData,
739
+ outputPath,
740
+ `\u2705 Report saved to ${outputPath}`
741
+ );
742
+ await warnIfGraphCapExceeded(outputData, resolvedDir);
489
743
  } else {
490
744
  const timestamp = getReportTimestamp();
491
745
  const defaultFilename = `aiready-report-${timestamp}.json`;
492
- const outputPath = resolveOutputPath(userOutputFile, defaultFilename, resolvedDir);
746
+ const outputPath = resolveOutputPath(
747
+ userOutputFile,
748
+ defaultFilename,
749
+ resolvedDir
750
+ );
493
751
  const outputData = { ...results, scoring: scoringResult };
494
752
  try {
495
753
  writeFileSync(outputPath, JSON.stringify(outputData, null, 2));
496
754
  console.log(chalk2.dim(`\u2705 Report auto-persisted to ${outputPath}`));
497
- warnIfGraphCapExceeded(outputData, resolvedDir);
755
+ await warnIfGraphCapExceeded(outputData, resolvedDir);
498
756
  } catch (err) {
757
+ void err;
499
758
  }
500
759
  }
501
760
  const isCI = options.ci || process.env.CI === "true" || process.env.GITHUB_ACTIONS === "true";
@@ -513,16 +772,22 @@ async function scanAction(directory, options) {
513
772
  }
514
773
  console.log("::endgroup::");
515
774
  if (threshold && scoringResult.overall < threshold) {
516
- console.log(`::error::AI Readiness Score ${scoringResult.overall} is below threshold ${threshold}`);
775
+ console.log(
776
+ `::error::AI Readiness Score ${scoringResult.overall} is below threshold ${threshold}`
777
+ );
517
778
  } else if (threshold) {
518
- console.log(`::notice::AI Readiness Score: ${scoringResult.overall}/100 (threshold: ${threshold})`);
779
+ console.log(
780
+ `::notice::AI Readiness Score: ${scoringResult.overall}/100 (threshold: ${threshold})`
781
+ );
519
782
  }
520
783
  if (results.patterns) {
521
784
  const criticalPatterns = results.patterns.flatMap(
522
785
  (p) => p.issues.filter((i) => i.severity === "critical")
523
786
  );
524
787
  criticalPatterns.slice(0, 10).forEach((issue) => {
525
- console.log(`::warning file=${issue.location?.file || "unknown"},line=${issue.location?.line || 1}::${issue.message}`);
788
+ console.log(
789
+ `::warning file=${issue.location?.file || "unknown"},line=${issue.location?.line || 1}::${issue.message}`
790
+ );
526
791
  });
527
792
  }
528
793
  }
@@ -571,16 +836,30 @@ async function scanAction(directory, options) {
571
836
  console.log(chalk2.red("\n\u{1F6AB} PR BLOCKED: AI Readiness Check Failed"));
572
837
  console.log(chalk2.red(` Reason: ${failReason}`));
573
838
  console.log(chalk2.dim("\n Remediation steps:"));
574
- console.log(chalk2.dim(" 1. Run `aiready scan` locally to see detailed issues"));
839
+ console.log(
840
+ chalk2.dim(" 1. Run `aiready scan` locally to see detailed issues")
841
+ );
575
842
  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"));
843
+ console.log(
844
+ chalk2.dim(
845
+ " 3. Consider upgrading to Team plan for historical tracking: https://getaiready.dev/pricing"
846
+ )
847
+ );
577
848
  process.exit(1);
578
849
  } else {
579
850
  console.log(chalk2.green("\n\u2705 PR PASSED: AI Readiness Check"));
580
851
  if (threshold) {
581
- console.log(chalk2.green(` Score: ${scoringResult.overall}/100 (threshold: ${threshold})`));
852
+ console.log(
853
+ chalk2.green(
854
+ ` Score: ${scoringResult.overall}/100 (threshold: ${threshold})`
855
+ )
856
+ );
582
857
  }
583
- console.log(chalk2.dim("\n \u{1F4A1} Track historical trends: https://getaiready.dev \u2014 Team plan $99/mo"));
858
+ console.log(
859
+ chalk2.dim(
860
+ "\n \u{1F4A1} Track historical trends: https://getaiready.dev \u2014 Team plan $99/mo"
861
+ )
862
+ );
584
863
  }
585
864
  }
586
865
  } catch (error) {
@@ -659,7 +938,11 @@ async function patternsAction(directory, options) {
659
938
  if (options.minSharedTokens) {
660
939
  cliOptions.minSharedTokens = parseInt(options.minSharedTokens);
661
940
  }
662
- const finalOptions = await loadMergedConfig2(resolvedDir, defaults, cliOptions);
941
+ const finalOptions = await loadMergedConfig2(
942
+ resolvedDir,
943
+ defaults,
944
+ cliOptions
945
+ );
663
946
  const { analyzePatterns, generateSummary, calculatePatternScore } = await import("@aiready/pattern-detect");
664
947
  const { results, duplicates } = await analyzePatterns(finalOptions);
665
948
  const elapsedTime = getElapsedTime2(startTime);
@@ -681,7 +964,11 @@ async function patternsAction(directory, options) {
681
964
  `aiready-report-${getReportTimestamp()}.json`,
682
965
  resolvedDir
683
966
  );
684
- handleJSONOutput2(outputData, outputPath, `\u2705 Results saved to ${outputPath}`);
967
+ handleJSONOutput2(
968
+ outputData,
969
+ outputPath,
970
+ `\u2705 Results saved to ${outputPath}`
971
+ );
685
972
  } else {
686
973
  const terminalWidth = process.stdout.columns || 80;
687
974
  const dividerWidth = Math.min(60, terminalWidth - 2);
@@ -689,10 +976,22 @@ async function patternsAction(directory, options) {
689
976
  console.log(chalk3.cyan(divider));
690
977
  console.log(chalk3.bold.white(" PATTERN ANALYSIS SUMMARY"));
691
978
  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")}`));
979
+ console.log(
980
+ chalk3.white(`\u{1F4C1} Files analyzed: ${chalk3.bold(results.length)}`)
981
+ );
982
+ console.log(
983
+ chalk3.yellow(
984
+ `\u26A0 Duplicate patterns found: ${chalk3.bold(summary.totalPatterns)}`
985
+ )
986
+ );
987
+ console.log(
988
+ chalk3.red(
989
+ `\u{1F4B0} Token cost (wasted): ${chalk3.bold(summary.totalTokenCost.toLocaleString())}`
990
+ )
991
+ );
992
+ console.log(
993
+ chalk3.gray(`\u23F1 Analysis time: ${chalk3.bold(elapsedTime + "s")}`)
994
+ );
696
995
  const sortedTypes = Object.entries(summary.patternsByType || {}).filter(([, count]) => count > 0).sort(([, a], [, b]) => b - a);
697
996
  if (sortedTypes.length > 0) {
698
997
  console.log(chalk3.cyan("\n" + divider));
@@ -712,13 +1011,21 @@ async function patternsAction(directory, options) {
712
1011
  const severityIcon = dup.similarity > 0.95 ? "\u{1F534}" : dup.similarity > 0.9 ? "\u{1F7E1}" : "\u{1F535}";
713
1012
  const file1Name = dup.file1.split("/").pop() || dup.file1;
714
1013
  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
- `);
1014
+ console.log(
1015
+ `${severityIcon} ${severity}: ${chalk3.bold(file1Name)} \u2194 ${chalk3.bold(file2Name)}`
1016
+ );
1017
+ console.log(
1018
+ ` Similarity: ${chalk3.bold(Math.round(dup.similarity * 100) + "%")} | Wasted: ${chalk3.bold(dup.tokenCost.toLocaleString())} tokens each`
1019
+ );
1020
+ console.log(
1021
+ ` Lines: ${chalk3.cyan(dup.line1 + "-" + dup.endLine1)} \u2194 ${chalk3.cyan(dup.line2 + "-" + dup.endLine2)}
1022
+ `
1023
+ );
719
1024
  });
720
1025
  } else {
721
- console.log(chalk3.green("\n\u2728 Great! No duplicate patterns detected.\n"));
1026
+ console.log(
1027
+ chalk3.green("\n\u2728 Great! No duplicate patterns detected.\n")
1028
+ );
722
1029
  }
723
1030
  if (patternScore) {
724
1031
  console.log(chalk3.cyan(divider));
@@ -765,7 +1072,7 @@ async function contextAction(directory, options) {
765
1072
  file: void 0
766
1073
  }
767
1074
  };
768
- let baseOptions = await loadMergedConfig3(resolvedDir, defaults, {
1075
+ const baseOptions = await loadMergedConfig3(resolvedDir, defaults, {
769
1076
  maxDepth: options.maxDepth ? parseInt(options.maxDepth) : void 0,
770
1077
  maxContextBudget: options.maxContext ? parseInt(options.maxContext) : void 0,
771
1078
  include: options.include?.split(","),
@@ -773,13 +1080,20 @@ async function contextAction(directory, options) {
773
1080
  });
774
1081
  let finalOptions = { ...baseOptions };
775
1082
  const { getSmartDefaults } = await import("@aiready/context-analyzer");
776
- const contextSmartDefaults = await getSmartDefaults(resolvedDir, baseOptions);
1083
+ const contextSmartDefaults = await getSmartDefaults(
1084
+ resolvedDir,
1085
+ baseOptions
1086
+ );
777
1087
  finalOptions = { ...contextSmartDefaults, ...finalOptions };
778
1088
  console.log("\u{1F4CB} Configuration:");
779
1089
  console.log(` Max depth: ${finalOptions.maxDepth}`);
780
1090
  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)}%`);
1091
+ console.log(
1092
+ ` Min cohesion: ${(finalOptions.minCohesion * 100).toFixed(1)}%`
1093
+ );
1094
+ console.log(
1095
+ ` Max fragmentation: ${(finalOptions.maxFragmentation * 100).toFixed(1)}%`
1096
+ );
783
1097
  console.log(` Analysis focus: ${finalOptions.focus}`);
784
1098
  console.log("");
785
1099
  const { analyzeContext, generateSummary, calculateContextScore } = await import("@aiready/context-analyzer");
@@ -803,7 +1117,11 @@ async function contextAction(directory, options) {
803
1117
  `aiready-report-${getReportTimestamp()}.json`,
804
1118
  resolvedDir
805
1119
  );
806
- handleJSONOutput3(outputData, outputPath, `\u2705 Results saved to ${outputPath}`);
1120
+ handleJSONOutput3(
1121
+ outputData,
1122
+ outputPath,
1123
+ `\u2705 Results saved to ${outputPath}`
1124
+ );
807
1125
  } else {
808
1126
  const terminalWidth = process.stdout.columns || 80;
809
1127
  const dividerWidth = Math.min(60, terminalWidth - 2);
@@ -811,59 +1129,103 @@ async function contextAction(directory, options) {
811
1129
  console.log(chalk4.cyan(divider));
812
1130
  console.log(chalk4.bold.white(" CONTEXT ANALYSIS SUMMARY"));
813
1131
  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
- `));
1132
+ console.log(
1133
+ chalk4.white(`\u{1F4C1} Files analyzed: ${chalk4.bold(summary.totalFiles)}`)
1134
+ );
1135
+ console.log(
1136
+ chalk4.white(
1137
+ `\u{1F4CA} Total tokens: ${chalk4.bold(summary.totalTokens.toLocaleString())}`
1138
+ )
1139
+ );
1140
+ console.log(
1141
+ chalk4.yellow(
1142
+ `\u{1F4B0} Avg context budget: ${chalk4.bold(summary.avgContextBudget.toFixed(0))} tokens/file`
1143
+ )
1144
+ );
1145
+ console.log(
1146
+ chalk4.white(`\u23F1 Analysis time: ${chalk4.bold(elapsedTime + "s")}
1147
+ `)
1148
+ );
819
1149
  const totalIssues = summary.criticalIssues + summary.majorIssues + summary.minorIssues;
820
1150
  if (totalIssues > 0) {
821
1151
  console.log(chalk4.bold("\u26A0\uFE0F Issues Found:\n"));
822
1152
  if (summary.criticalIssues > 0) {
823
- console.log(chalk4.red(` \u{1F534} Critical: ${chalk4.bold(summary.criticalIssues)}`));
1153
+ console.log(
1154
+ chalk4.red(` \u{1F534} Critical: ${chalk4.bold(summary.criticalIssues)}`)
1155
+ );
824
1156
  }
825
1157
  if (summary.majorIssues > 0) {
826
- console.log(chalk4.yellow(` \u{1F7E1} Major: ${chalk4.bold(summary.majorIssues)}`));
1158
+ console.log(
1159
+ chalk4.yellow(` \u{1F7E1} Major: ${chalk4.bold(summary.majorIssues)}`)
1160
+ );
827
1161
  }
828
1162
  if (summary.minorIssues > 0) {
829
- console.log(chalk4.blue(` \u{1F535} Minor: ${chalk4.bold(summary.minorIssues)}`));
1163
+ console.log(
1164
+ chalk4.blue(` \u{1F535} Minor: ${chalk4.bold(summary.minorIssues)}`)
1165
+ );
830
1166
  }
831
- console.log(chalk4.green(`
1167
+ console.log(
1168
+ chalk4.green(
1169
+ `
832
1170
  \u{1F4A1} Potential savings: ${chalk4.bold(summary.totalPotentialSavings.toLocaleString())} tokens
833
- `));
1171
+ `
1172
+ )
1173
+ );
834
1174
  } else {
835
1175
  console.log(chalk4.green("\u2705 No significant issues found!\n"));
836
1176
  }
837
1177
  if (summary.deepFiles.length > 0) {
838
1178
  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
- `));
1179
+ console.log(
1180
+ chalk4.gray(` Average depth: ${summary.avgImportDepth.toFixed(1)}`)
1181
+ );
1182
+ console.log(
1183
+ chalk4.gray(` Maximum depth: ${summary.maxImportDepth}
1184
+ `)
1185
+ );
842
1186
  summary.deepFiles.slice(0, 10).forEach((item) => {
843
1187
  const fileName = item.file.split("/").slice(-2).join("/");
844
- console.log(` ${chalk4.cyan("\u2192")} ${chalk4.white(fileName)} ${chalk4.dim(`(depth: ${item.depth})`)}`);
1188
+ console.log(
1189
+ ` ${chalk4.cyan("\u2192")} ${chalk4.white(fileName)} ${chalk4.dim(`(depth: ${item.depth})`)}`
1190
+ );
845
1191
  });
846
1192
  console.log();
847
1193
  }
848
1194
  if (summary.fragmentedModules.length > 0) {
849
1195
  console.log(chalk4.bold("\u{1F9E9} Fragmented Modules:\n"));
850
- console.log(chalk4.gray(` Average fragmentation: ${(summary.avgFragmentation * 100).toFixed(0)}%
851
- `));
1196
+ console.log(
1197
+ chalk4.gray(
1198
+ ` Average fragmentation: ${(summary.avgFragmentation * 100).toFixed(0)}%
1199
+ `
1200
+ )
1201
+ );
852
1202
  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)}%`));
1203
+ console.log(
1204
+ ` ${chalk4.yellow("\u25CF")} ${chalk4.white(module.domain)} - ${chalk4.dim(`${module.files.length} files, ${(module.fragmentationScore * 100).toFixed(0)}% scattered`)}`
1205
+ );
1206
+ console.log(
1207
+ chalk4.dim(
1208
+ ` Token cost: ${module.totalTokens.toLocaleString()}, Cohesion: ${(module.avgCohesion * 100).toFixed(0)}%`
1209
+ )
1210
+ );
855
1211
  });
856
1212
  console.log();
857
1213
  }
858
1214
  if (summary.lowCohesionFiles.length > 0) {
859
1215
  console.log(chalk4.bold("\u{1F500} Low Cohesion Files:\n"));
860
- console.log(chalk4.gray(` Average cohesion: ${(summary.avgCohesion * 100).toFixed(0)}%
861
- `));
1216
+ console.log(
1217
+ chalk4.gray(
1218
+ ` Average cohesion: ${(summary.avgCohesion * 100).toFixed(0)}%
1219
+ `
1220
+ )
1221
+ );
862
1222
  summary.lowCohesionFiles.slice(0, 10).forEach((item) => {
863
1223
  const fileName = item.file.split("/").slice(-2).join("/");
864
1224
  const scorePercent = (item.score * 100).toFixed(0);
865
1225
  const color = item.score < 0.4 ? chalk4.red : chalk4.yellow;
866
- console.log(` ${color("\u25CB")} ${chalk4.white(fileName)} ${chalk4.dim(`(${scorePercent}% cohesion)`)}`);
1226
+ console.log(
1227
+ ` ${color("\u25CB")} ${chalk4.white(fileName)} ${chalk4.dim(`(${scorePercent}% cohesion)`)}`
1228
+ );
867
1229
  });
868
1230
  console.log();
869
1231
  }
@@ -872,7 +1234,9 @@ async function contextAction(directory, options) {
872
1234
  summary.topExpensiveFiles.slice(0, 10).forEach((item) => {
873
1235
  const fileName = item.file.split("/").slice(-2).join("/");
874
1236
  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)`)}`);
1237
+ console.log(
1238
+ ` ${severityColor("\u25CF")} ${chalk4.white(fileName)} ${chalk4.dim(`(${item.contextBudget.toLocaleString()} tokens)`)}`
1239
+ );
876
1240
  });
877
1241
  console.log();
878
1242
  }
@@ -930,7 +1294,10 @@ async function consistencyAction(directory, options) {
930
1294
  let consistencyScore;
931
1295
  if (options.score) {
932
1296
  const issues = report.results?.flatMap((r) => r.issues) || [];
933
- consistencyScore = calculateConsistencyScore(issues, report.summary.filesAnalyzed);
1297
+ consistencyScore = calculateConsistencyScore(
1298
+ issues,
1299
+ report.summary.filesAnalyzed
1300
+ );
934
1301
  }
935
1302
  const outputFormat = options.output || finalOptions.output?.format || "console";
936
1303
  const userOutputFile = options.outputFile || finalOptions.output?.file;
@@ -948,7 +1315,11 @@ async function consistencyAction(directory, options) {
948
1315
  `aiready-report-${getReportTimestamp()}.json`,
949
1316
  resolvedDir
950
1317
  );
951
- handleJSONOutput4(outputData, outputPath, `\u2705 Results saved to ${outputPath}`);
1318
+ handleJSONOutput4(
1319
+ outputData,
1320
+ outputPath,
1321
+ `\u2705 Results saved to ${outputPath}`
1322
+ );
952
1323
  } else if (outputFormat === "markdown") {
953
1324
  const markdown = generateMarkdownReport(report, elapsedTime);
954
1325
  const outputPath = resolveOutputPath4(
@@ -960,15 +1331,23 @@ async function consistencyAction(directory, options) {
960
1331
  console.log(chalk5.green(`\u2705 Report saved to ${outputPath}`));
961
1332
  } else {
962
1333
  console.log(chalk5.bold("\n\u{1F4CA} Summary\n"));
963
- console.log(`Files Analyzed: ${chalk5.cyan(report.summary.filesAnalyzed)}`);
1334
+ console.log(
1335
+ `Files Analyzed: ${chalk5.cyan(report.summary.filesAnalyzed)}`
1336
+ );
964
1337
  console.log(`Total Issues: ${chalk5.yellow(report.summary.totalIssues)}`);
965
1338
  console.log(` Naming: ${chalk5.yellow(report.summary.namingIssues)}`);
966
1339
  console.log(` Patterns: ${chalk5.yellow(report.summary.patternIssues)}`);
967
- console.log(` Architecture: ${chalk5.yellow(report.summary.architectureIssues || 0)}`);
1340
+ console.log(
1341
+ ` Architecture: ${chalk5.yellow(report.summary.architectureIssues || 0)}`
1342
+ );
968
1343
  console.log(`Analysis Time: ${chalk5.gray(elapsedTime + "s")}
969
1344
  `);
970
1345
  if (report.summary.totalIssues === 0) {
971
- console.log(chalk5.green("\u2728 No consistency issues found! Your codebase is well-maintained.\n"));
1346
+ console.log(
1347
+ chalk5.green(
1348
+ "\u2728 No consistency issues found! Your codebase is well-maintained.\n"
1349
+ )
1350
+ );
972
1351
  } else {
973
1352
  const namingResults = report.results.filter(
974
1353
  (r) => r.issues.some((i) => i.category === "naming")
@@ -984,10 +1363,14 @@ async function consistencyAction(directory, options) {
984
1363
  for (const issue of result.issues) {
985
1364
  if (shown >= 5) break;
986
1365
  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}`)}`);
1366
+ console.log(
1367
+ `${severityColor(issue.severity.toUpperCase())} ${chalk5.dim(`${issue.location.file}:${issue.location.line}`)}`
1368
+ );
988
1369
  console.log(` ${issue.message}`);
989
1370
  if (issue.suggestion) {
990
- console.log(` ${chalk5.dim("\u2192")} ${chalk5.italic(issue.suggestion)}`);
1371
+ console.log(
1372
+ ` ${chalk5.dim("\u2192")} ${chalk5.italic(issue.suggestion)}`
1373
+ );
991
1374
  }
992
1375
  console.log();
993
1376
  shown++;
@@ -1007,10 +1390,14 @@ async function consistencyAction(directory, options) {
1007
1390
  for (const issue of result.issues) {
1008
1391
  if (shown >= 5) break;
1009
1392
  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}`)}`);
1393
+ console.log(
1394
+ `${severityColor(issue.severity.toUpperCase())} ${chalk5.dim(`${issue.location.file}:${issue.location.line}`)}`
1395
+ );
1011
1396
  console.log(` ${issue.message}`);
1012
1397
  if (issue.suggestion) {
1013
- console.log(` ${chalk5.dim("\u2192")} ${chalk5.italic(issue.suggestion)}`);
1398
+ console.log(
1399
+ ` ${chalk5.dim("\u2192")} ${chalk5.italic(issue.suggestion)}`
1400
+ );
1014
1401
  }
1015
1402
  console.log();
1016
1403
  shown++;
@@ -1043,7 +1430,7 @@ async function consistencyAction(directory, options) {
1043
1430
 
1044
1431
  // src/commands/visualize.ts
1045
1432
  import chalk6 from "chalk";
1046
- import { writeFileSync as writeFileSync3, readFileSync as readFileSync3, existsSync as existsSync2, copyFileSync as copyFileSync2 } from "fs";
1433
+ import { writeFileSync as writeFileSync3, readFileSync as readFileSync3, existsSync as existsSync2, copyFileSync } from "fs";
1047
1434
  import { resolve as resolvePath6 } from "path";
1048
1435
  import { spawn } from "child_process";
1049
1436
  import { handleCLIError as handleCLIError5 } from "@aiready/core";
@@ -1056,15 +1443,21 @@ async function visualizeAction(directory, options) {
1056
1443
  const latestScan = findLatestScanReport(dirPath);
1057
1444
  if (latestScan) {
1058
1445
  reportPath = latestScan;
1059
- console.log(chalk6.dim(`Found latest report: ${latestScan.split("/").pop()}`));
1446
+ console.log(
1447
+ chalk6.dim(`Found latest report: ${latestScan.split("/").pop()}`)
1448
+ );
1060
1449
  } else {
1061
1450
  console.error(chalk6.red("\u274C No AI readiness report found"));
1062
- console.log(chalk6.dim(`
1451
+ console.log(
1452
+ chalk6.dim(
1453
+ `
1063
1454
  Generate a report with:
1064
1455
  aiready scan --output json
1065
1456
 
1066
1457
  Or specify a custom report:
1067
- aiready visualise --report <path-to-report.json>`));
1458
+ aiready visualise --report <path-to-report.json>`
1459
+ )
1460
+ );
1068
1461
  return;
1069
1462
  }
1070
1463
  }
@@ -1082,6 +1475,7 @@ Or specify a custom report:
1082
1475
  };
1083
1476
  }
1084
1477
  } catch (e) {
1478
+ void e;
1085
1479
  }
1086
1480
  }
1087
1481
  const envVisualizerConfig = JSON.stringify(graphConfig);
@@ -1102,11 +1496,18 @@ Or specify a custom report:
1102
1496
  } else {
1103
1497
  const nodemodulesLocations = [
1104
1498
  resolvePath6(dirPath, "node_modules", "@aiready", "visualizer"),
1105
- resolvePath6(process.cwd(), "node_modules", "@aiready", "visualizer")
1499
+ resolvePath6(
1500
+ process.cwd(),
1501
+ "node_modules",
1502
+ "@aiready",
1503
+ "visualizer"
1504
+ )
1106
1505
  ];
1107
1506
  let currentDir = dirPath;
1108
1507
  while (currentDir !== "/" && currentDir !== ".") {
1109
- nodemodulesLocations.push(resolvePath6(currentDir, "node_modules", "@aiready", "visualizer"));
1508
+ nodemodulesLocations.push(
1509
+ resolvePath6(currentDir, "node_modules", "@aiready", "visualizer")
1510
+ );
1110
1511
  const parent = resolvePath6(currentDir, "..");
1111
1512
  if (parent === currentDir) break;
1112
1513
  currentDir = parent;
@@ -1123,7 +1524,8 @@ Or specify a custom report:
1123
1524
  const vizPkgPath = __require.resolve("@aiready/visualizer/package.json");
1124
1525
  webDir = resolvePath6(vizPkgPath, "..");
1125
1526
  visualizerAvailable = true;
1126
- } catch (e) {
1527
+ } catch (err) {
1528
+ void err;
1127
1529
  }
1128
1530
  }
1129
1531
  }
@@ -1134,7 +1536,7 @@ Or specify a custom report:
1134
1536
  const copyReportToViz = () => {
1135
1537
  try {
1136
1538
  const destPath = resolvePath6(spawnCwd, "web", "report-data.json");
1137
- copyFileSync2(reportPath, destPath);
1539
+ copyFileSync(reportPath, destPath);
1138
1540
  console.log(`\u{1F4CB} Report synced to ${destPath}`);
1139
1541
  } catch (e) {
1140
1542
  console.error("Failed to sync report:", e);
@@ -1151,30 +1553,46 @@ Or specify a custom report:
1151
1553
  AIREADY_REPORT_PATH: reportPath,
1152
1554
  AIREADY_VISUALIZER_CONFIG: envVisualizerConfig
1153
1555
  };
1154
- const vite = spawn("pnpm", ["run", "dev:web"], { cwd: spawnCwd, stdio: "inherit", shell: true, env: envForSpawn });
1556
+ const vite = spawn("pnpm", ["run", "dev:web"], {
1557
+ cwd: spawnCwd,
1558
+ stdio: "inherit",
1559
+ shell: true,
1560
+ env: envForSpawn
1561
+ });
1155
1562
  const onExit = () => {
1156
1563
  try {
1157
1564
  reportWatcher.close();
1158
- } catch (e) {
1565
+ } catch (err) {
1566
+ void err;
1159
1567
  }
1160
1568
  try {
1161
1569
  vite.kill();
1162
- } catch (e) {
1570
+ } catch (err) {
1571
+ void err;
1163
1572
  }
1164
1573
  process.exit(0);
1165
1574
  };
1166
1575
  process.on("SIGINT", onExit);
1167
1576
  process.on("SIGTERM", onExit);
1168
1577
  devServerStarted = true;
1578
+ void devServerStarted;
1169
1579
  return;
1170
1580
  } 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"));
1581
+ console.log(
1582
+ chalk6.yellow(
1583
+ "\u26A0\uFE0F Dev server not available (requires local @aiready/visualizer with web assets)."
1584
+ )
1585
+ );
1586
+ console.log(
1587
+ chalk6.cyan(" Falling back to static HTML generation...\n")
1588
+ );
1173
1589
  useDevMode = false;
1174
1590
  }
1175
1591
  } catch (err) {
1176
1592
  console.error("Failed to start dev server:", err);
1177
- console.log(chalk6.cyan(" Falling back to static HTML generation...\n"));
1593
+ console.log(
1594
+ chalk6.cyan(" Falling back to static HTML generation...\n")
1595
+ );
1178
1596
  useDevMode = false;
1179
1597
  }
1180
1598
  }
@@ -1196,20 +1614,25 @@ Or specify a custom report:
1196
1614
  const urlPath = req.url || "/";
1197
1615
  if (urlPath === "/" || urlPath === "/index.html") {
1198
1616
  const content = await fsp.readFile(outPath, "utf8");
1199
- res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
1617
+ res.writeHead(200, {
1618
+ "Content-Type": "text/html; charset=utf-8"
1619
+ });
1200
1620
  res.end(content);
1201
1621
  return;
1202
1622
  }
1203
1623
  res.writeHead(404, { "Content-Type": "text/plain" });
1204
1624
  res.end("Not found");
1205
1625
  } catch (e) {
1626
+ void e;
1206
1627
  res.writeHead(500, { "Content-Type": "text/plain" });
1207
1628
  res.end("Server error");
1208
1629
  }
1209
1630
  });
1210
1631
  server.listen(port, () => {
1211
1632
  const addr = `http://localhost:${port}/`;
1212
- console.log(chalk6.cyan(`\u{1F310} Local visualization server running at ${addr}`));
1633
+ console.log(
1634
+ chalk6.cyan(`\u{1F310} Local visualization server running at ${addr}`)
1635
+ );
1213
1636
  spawn(opener, [`"${addr}"`], { shell: true });
1214
1637
  });
1215
1638
  process.on("SIGINT", () => {
@@ -1274,9 +1697,13 @@ var getDirname = () => {
1274
1697
  if (typeof __dirname !== "undefined") return __dirname;
1275
1698
  return dirname(fileURLToPath(import.meta.url));
1276
1699
  };
1277
- var packageJson = JSON.parse(readFileSync4(join(getDirname(), "../package.json"), "utf8"));
1700
+ var packageJson = JSON.parse(
1701
+ readFileSync4(join(getDirname(), "../package.json"), "utf8")
1702
+ );
1278
1703
  var program = new Command();
1279
- program.name("aiready").description("AIReady - Assess and improve AI-readiness of codebases").version(packageJson.version).addHelpText("after", `
1704
+ program.name("aiready").description("AIReady - Assess and improve AI-readiness of codebases").version(packageJson.version).addHelpText(
1705
+ "after",
1706
+ `
1280
1707
  AI READINESS SCORING:
1281
1708
  Get a 0-100 score indicating how AI-ready your codebase is.
1282
1709
  Use --score flag with any analysis command for detailed breakdown.
@@ -1311,23 +1738,105 @@ CONFIGURATION:
1311
1738
  VERSION: ${packageJson.version}
1312
1739
  DOCUMENTATION: https://aiready.dev/docs/cli
1313
1740
  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) => {
1741
+ LANDING: https://github.com/caopengau/aiready-landing`
1742
+ );
1743
+ program.command("scan").description(
1744
+ "Run comprehensive AI-readiness analysis (patterns + context + consistency)"
1745
+ ).argument("[directory]", "Directory to analyze", ".").option(
1746
+ "-t, --tools <tools>",
1747
+ "Tools to run (comma-separated: patterns,context,consistency,doc-drift,deps-health,aiSignalClarity,grounding,testability,changeAmplification)"
1748
+ ).option(
1749
+ "--profile <type>",
1750
+ "Scan profile to use (agentic, cost, security, onboarding)"
1751
+ ).option(
1752
+ "--compare-to <path>",
1753
+ "Compare results against a previous AIReady report JSON"
1754
+ ).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(
1755
+ "--no-score",
1756
+ "Disable calculating AI Readiness Score (enabled by default)"
1757
+ ).option("--weights <weights>", "Custom scoring weights").option("--threshold <score>", "Fail CI/CD if score below threshold (0-100)").option(
1758
+ "--ci",
1759
+ "CI mode: GitHub Actions annotations, no colors, fail on threshold"
1760
+ ).option(
1761
+ "--fail-on <level>",
1762
+ "Fail on issues: critical, major, any",
1763
+ "critical"
1764
+ ).addHelpText("after", scanHelpText).action(async (directory, options) => {
1316
1765
  await scanAction(directory, options);
1317
1766
  });
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) => {
1767
+ 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(
1768
+ "--max-candidates <number>",
1769
+ "Maximum candidates per block (performance tuning)"
1770
+ ).option(
1771
+ "--min-shared-tokens <number>",
1772
+ "Minimum shared tokens for candidates (performance tuning)"
1773
+ ).option(
1774
+ "--full-scan",
1775
+ "Disable smart defaults for comprehensive analysis (slower)"
1776
+ ).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(
1777
+ "--score",
1778
+ "Calculate and display AI Readiness Score for patterns (0-100)"
1779
+ ).addHelpText("after", patternsHelpText).action(async (directory, options) => {
1319
1780
  await patternsAction(directory, options);
1320
1781
  });
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) => {
1782
+ 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(
1783
+ "--max-context <number>",
1784
+ "Maximum acceptable context budget (tokens)",
1785
+ "10000"
1786
+ ).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(
1787
+ "--score",
1788
+ "Calculate and display AI Readiness Score for context (0-100)"
1789
+ ).action(async (directory, options) => {
1322
1790
  await contextAction(directory, options);
1323
1791
  });
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) => {
1792
+ 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(
1793
+ "--min-severity <level>",
1794
+ "Minimum severity: info|minor|major|critical",
1795
+ "info"
1796
+ ).option("--include <patterns>", "File patterns to include (comma-separated)").option("--exclude <patterns>", "File patterns to exclude (comma-separated)").option(
1797
+ "-o, --output <format>",
1798
+ "Output format: console, json, markdown",
1799
+ "console"
1800
+ ).option("--output-file <path>", "Output file path (for json/markdown)").option(
1801
+ "--score",
1802
+ "Calculate and display AI Readiness Score for consistency (0-100)"
1803
+ ).action(async (directory, options) => {
1325
1804
  await consistencyAction(directory, options);
1326
1805
  });
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) => {
1806
+ program.command("visualise").description("Alias for visualize (British spelling)").argument("[directory]", "Directory to analyze", ".").option(
1807
+ "--report <path>",
1808
+ "Report path (auto-detects latest .aiready/aiready-report-*.json if not provided)"
1809
+ ).option(
1810
+ "-o, --output <path>",
1811
+ "Output HTML path (relative to directory)",
1812
+ "packages/visualizer/visualization.html"
1813
+ ).option("--open", "Open generated HTML in default browser").option(
1814
+ "--serve [port]",
1815
+ "Start a local static server to serve the visualization (optional port number)",
1816
+ false
1817
+ ).option(
1818
+ "--dev",
1819
+ "Start Vite dev server (live reload) for interactive development",
1820
+ true
1821
+ ).addHelpText("after", visualiseHelpText).action(async (directory, options) => {
1328
1822
  await visualizeAction(directory, options);
1329
1823
  });
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) => {
1824
+ program.command("visualize").description("Generate interactive visualization from an AIReady report").argument("[directory]", "Directory to analyze", ".").option(
1825
+ "--report <path>",
1826
+ "Report path (auto-detects latest .aiready/aiready-report-*.json if not provided)"
1827
+ ).option(
1828
+ "-o, --output <path>",
1829
+ "Output HTML path (relative to directory)",
1830
+ "packages/visualizer/visualization.html"
1831
+ ).option("--open", "Open generated HTML in default browser").option(
1832
+ "--serve [port]",
1833
+ "Start a local static server to serve the visualization (optional port number)",
1834
+ false
1835
+ ).option(
1836
+ "--dev",
1837
+ "Start Vite dev server (live reload) for interactive development",
1838
+ false
1839
+ ).addHelpText("after", visualizeHelpText).action(async (directory, options) => {
1331
1840
  await visualizeAction(directory, options);
1332
1841
  });
1333
1842
  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) => {