@aiready/cli 0.9.43 → 0.9.46

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
@@ -1,8 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  __require,
4
- analyzeUnified
5
- } from "./chunk-LLJMKNBI.mjs";
4
+ analyzeUnified,
5
+ scoreUnified
6
+ } from "./chunk-6FOVC2OE.mjs";
6
7
 
7
8
  // src/cli.ts
8
9
  import { Command } from "commander";
@@ -11,21 +12,23 @@ import { join, dirname } from "path";
11
12
  import { fileURLToPath } from "url";
12
13
 
13
14
  // src/commands/scan.ts
14
- import chalk2 from "chalk";
15
+ import chalk3 from "chalk";
15
16
  import { writeFileSync, readFileSync as readFileSync2 } from "fs";
16
- import { resolve as resolvePath2 } from "path";
17
+ import { resolve as resolvePath3 } from "path";
17
18
  import {
18
19
  loadMergedConfig,
19
20
  handleJSONOutput,
20
- handleCLIError,
21
+ handleCLIError as handleCLIError2,
21
22
  getElapsedTime,
22
23
  resolveOutputPath,
23
- calculateOverallScore,
24
24
  formatScore,
25
25
  formatToolScore,
26
+ calculateTokenBudget,
27
+ estimateCostFromBudget,
28
+ getModelPreset,
26
29
  getRating,
27
30
  getRatingDisplay,
28
- parseWeightString
31
+ getRepoMetadata
29
32
  } from "@aiready/core";
30
33
 
31
34
  // src/utils/helpers.ts
@@ -152,11 +155,113 @@ function truncateArray(arr, cap = 8) {
152
155
  return shown.join(", ") + (more > 0 ? `, ... (+${more} more)` : "");
153
156
  }
154
157
 
158
+ // src/commands/upload.ts
159
+ import fs from "fs";
160
+ import { resolve as resolvePath2 } from "path";
161
+ import chalk2 from "chalk";
162
+ import { handleCLIError } from "@aiready/core";
163
+ async function uploadAction(file, options) {
164
+ const startTime = Date.now();
165
+ const filePath = resolvePath2(process.cwd(), file);
166
+ const serverUrl = options.server || process.env.AIREADY_SERVER || "https://dev.platform.getaiready.dev";
167
+ const apiKey = options.apiKey || process.env.AIREADY_API_KEY;
168
+ if (!apiKey) {
169
+ console.error(chalk2.red("\u274C API Key is required for upload."));
170
+ console.log(
171
+ chalk2.dim(
172
+ " Set AIREADY_API_KEY environment variable or use --api-key flag."
173
+ )
174
+ );
175
+ console.log(
176
+ chalk2.dim(" Get an API key from https://getaiready.dev/dashboard")
177
+ );
178
+ process.exit(1);
179
+ }
180
+ if (!fs.existsSync(filePath)) {
181
+ console.error(chalk2.red(`\u274C File not found: ${filePath}`));
182
+ process.exit(1);
183
+ }
184
+ try {
185
+ console.log(chalk2.blue(`\u{1F680} Uploading report to ${serverUrl}...`));
186
+ console.log(chalk2.dim(` Reading report from ${filePath}...`));
187
+ const reportContent = fs.readFileSync(filePath, "utf-8");
188
+ const reportData = JSON.parse(reportContent);
189
+ console.log(chalk2.dim(` Successfully parsed report JSON.`));
190
+ const repoId = options.repoId || reportData.repository?.repoId;
191
+ const res = await fetch(`${serverUrl}/api/analysis/upload`, {
192
+ method: "POST",
193
+ headers: {
194
+ "Content-Type": "application/json",
195
+ Authorization: `Bearer ${apiKey}`
196
+ },
197
+ body: JSON.stringify({
198
+ data: reportData,
199
+ repoId
200
+ // Might be null, server will handle mapping
201
+ })
202
+ });
203
+ const contentType = res.headers.get("content-type");
204
+ let result = {};
205
+ if (contentType?.includes("application/json")) {
206
+ result = await res.json();
207
+ } else {
208
+ const text = await res.text();
209
+ result = { error: text || res.statusText };
210
+ }
211
+ if (!res.ok) {
212
+ console.error(
213
+ chalk2.red(`\u274C Upload failed: ${result.error || res.statusText}`)
214
+ );
215
+ if (contentType?.includes("text/html")) {
216
+ console.log(
217
+ chalk2.yellow(
218
+ " Note: Received an HTML response. This often indicates a redirect (e.g., to a login page) or a server error."
219
+ )
220
+ );
221
+ if (result.error?.includes("Redirecting")) {
222
+ console.log(
223
+ chalk2.dim(
224
+ " Detected redirect. Check if the API endpoint requires authentication or has changed."
225
+ )
226
+ );
227
+ }
228
+ }
229
+ if (res.status === 401) {
230
+ console.log(
231
+ chalk2.dim(" Hint: Your API key may be invalid or expired.")
232
+ );
233
+ }
234
+ process.exit(1);
235
+ }
236
+ const duration = ((Date.now() - startTime) / 1e3).toFixed(2);
237
+ console.log(chalk2.green(`
238
+ \u2705 Upload successful! (${duration}s)`));
239
+ console.log(chalk2.cyan(` View results: ${serverUrl}/dashboard`));
240
+ if (result.analysis) {
241
+ console.log(chalk2.dim(` Analysis ID: ${result.analysis.id}`));
242
+ console.log(chalk2.dim(` Score: ${result.analysis.aiScore}/100`));
243
+ }
244
+ } catch (error) {
245
+ handleCLIError(error, "Upload");
246
+ }
247
+ }
248
+ var uploadHelpText = `
249
+ EXAMPLES:
250
+ $ aiready upload report.json --api-key ar_...
251
+ $ aiready upload .aiready/latest.json
252
+ $ AIREADY_API_KEY=ar_... aiready upload report.json
253
+
254
+ ENVIRONMENT VARIABLES:
255
+ AIREADY_API_KEY Your platform API key
256
+ AIREADY_SERVER Custom platform URL (default: https://dev.platform.getaiready.dev)
257
+ `;
258
+
155
259
  // src/commands/scan.ts
156
260
  async function scanAction(directory, options) {
157
- console.log(chalk2.blue("\u{1F680} Starting AIReady unified analysis...\n"));
261
+ console.log(chalk3.blue("\u{1F680} Starting AIReady unified analysis...\n"));
158
262
  const startTime = Date.now();
159
- const resolvedDir = resolvePath2(process.cwd(), directory || ".");
263
+ const resolvedDir = resolvePath3(process.cwd(), directory || ".");
264
+ const repoMetadata = getRepoMetadata(resolvedDir);
160
265
  try {
161
266
  const defaults = {
162
267
  tools: [
@@ -199,7 +304,7 @@ async function scanAction(directory, options) {
199
304
  break;
200
305
  default:
201
306
  console.log(
202
- chalk2.yellow(
307
+ chalk3.yellow(
203
308
  `
204
309
  \u26A0\uFE0F Unknown profile '${options.profile}'. Using specified tools or defaults.`
205
310
  )
@@ -231,22 +336,22 @@ async function scanAction(directory, options) {
231
336
  ...baseOptions
232
337
  };
233
338
  }
234
- console.log(chalk2.cyan("\n=== AIReady Run Preview ==="));
339
+ console.log(chalk3.cyan("\n=== AIReady Run Preview ==="));
235
340
  console.log(
236
- chalk2.white("Tools to run:"),
341
+ chalk3.white("Tools to run:"),
237
342
  (finalOptions.tools || ["patterns", "context", "consistency"]).join(", ")
238
343
  );
239
- console.log(chalk2.white("Will use settings from config and defaults."));
240
- console.log(chalk2.white("\nGeneral settings:"));
344
+ console.log(chalk3.white("Will use settings from config and defaults."));
345
+ console.log(chalk3.white("\nGeneral settings:"));
241
346
  if (finalOptions.rootDir)
242
- console.log(` rootDir: ${chalk2.bold(String(finalOptions.rootDir))}`);
347
+ console.log(` rootDir: ${chalk3.bold(String(finalOptions.rootDir))}`);
243
348
  if (finalOptions.include)
244
349
  console.log(
245
- ` include: ${chalk2.bold(truncateArray(finalOptions.include, 6))}`
350
+ ` include: ${chalk3.bold(truncateArray(finalOptions.include, 6))}`
246
351
  );
247
352
  if (finalOptions.exclude)
248
353
  console.log(
249
- ` exclude: ${chalk2.bold(truncateArray(finalOptions.exclude, 6))}`
354
+ ` exclude: ${chalk3.bold(truncateArray(finalOptions.exclude, 6))}`
250
355
  );
251
356
  if (finalOptions["pattern-detect"] || finalOptions.minSimilarity) {
252
357
  const patternDetectConfig = finalOptions["pattern-detect"] || {
@@ -260,40 +365,40 @@ async function scanAction(directory, options) {
260
365
  severity: finalOptions.severity,
261
366
  includeTests: finalOptions.includeTests
262
367
  };
263
- console.log(chalk2.white("\nPattern-detect settings:"));
368
+ console.log(chalk3.white("\nPattern-detect settings:"));
264
369
  console.log(
265
- ` minSimilarity: ${chalk2.bold(patternDetectConfig.minSimilarity ?? "default")}`
370
+ ` minSimilarity: ${chalk3.bold(patternDetectConfig.minSimilarity ?? "default")}`
266
371
  );
267
372
  console.log(
268
- ` minLines: ${chalk2.bold(patternDetectConfig.minLines ?? "default")}`
373
+ ` minLines: ${chalk3.bold(patternDetectConfig.minLines ?? "default")}`
269
374
  );
270
375
  if (patternDetectConfig.approx !== void 0)
271
376
  console.log(
272
- ` approx: ${chalk2.bold(String(patternDetectConfig.approx))}`
377
+ ` approx: ${chalk3.bold(String(patternDetectConfig.approx))}`
273
378
  );
274
379
  if (patternDetectConfig.minSharedTokens !== void 0)
275
380
  console.log(
276
- ` minSharedTokens: ${chalk2.bold(String(patternDetectConfig.minSharedTokens))}`
381
+ ` minSharedTokens: ${chalk3.bold(String(patternDetectConfig.minSharedTokens))}`
277
382
  );
278
383
  if (patternDetectConfig.maxCandidatesPerBlock !== void 0)
279
384
  console.log(
280
- ` maxCandidatesPerBlock: ${chalk2.bold(String(patternDetectConfig.maxCandidatesPerBlock))}`
385
+ ` maxCandidatesPerBlock: ${chalk3.bold(String(patternDetectConfig.maxCandidatesPerBlock))}`
281
386
  );
282
387
  if (patternDetectConfig.batchSize !== void 0)
283
388
  console.log(
284
- ` batchSize: ${chalk2.bold(String(patternDetectConfig.batchSize))}`
389
+ ` batchSize: ${chalk3.bold(String(patternDetectConfig.batchSize))}`
285
390
  );
286
391
  if (patternDetectConfig.streamResults !== void 0)
287
392
  console.log(
288
- ` streamResults: ${chalk2.bold(String(patternDetectConfig.streamResults))}`
393
+ ` streamResults: ${chalk3.bold(String(patternDetectConfig.streamResults))}`
289
394
  );
290
395
  if (patternDetectConfig.severity !== void 0)
291
396
  console.log(
292
- ` severity: ${chalk2.bold(String(patternDetectConfig.severity))}`
397
+ ` severity: ${chalk3.bold(String(patternDetectConfig.severity))}`
293
398
  );
294
399
  if (patternDetectConfig.includeTests !== void 0)
295
400
  console.log(
296
- ` includeTests: ${chalk2.bold(String(patternDetectConfig.includeTests))}`
401
+ ` includeTests: ${chalk3.bold(String(patternDetectConfig.includeTests))}`
297
402
  );
298
403
  }
299
404
  if (finalOptions["context-analyzer"] || finalOptions.maxDepth) {
@@ -304,57 +409,57 @@ async function scanAction(directory, options) {
304
409
  maxFragmentation: finalOptions.maxFragmentation,
305
410
  includeNodeModules: finalOptions.includeNodeModules
306
411
  };
307
- console.log(chalk2.white("\nContext-analyzer settings:"));
308
- console.log(` maxDepth: ${chalk2.bold(ca.maxDepth ?? "default")}`);
412
+ console.log(chalk3.white("\nContext-analyzer settings:"));
413
+ console.log(` maxDepth: ${chalk3.bold(ca.maxDepth ?? "default")}`);
309
414
  console.log(
310
- ` maxContextBudget: ${chalk2.bold(ca.maxContextBudget ?? "default")}`
415
+ ` maxContextBudget: ${chalk3.bold(ca.maxContextBudget ?? "default")}`
311
416
  );
312
417
  if (ca.minCohesion !== void 0)
313
- console.log(` minCohesion: ${chalk2.bold(String(ca.minCohesion))}`);
418
+ console.log(` minCohesion: ${chalk3.bold(String(ca.minCohesion))}`);
314
419
  if (ca.maxFragmentation !== void 0)
315
420
  console.log(
316
- ` maxFragmentation: ${chalk2.bold(String(ca.maxFragmentation))}`
421
+ ` maxFragmentation: ${chalk3.bold(String(ca.maxFragmentation))}`
317
422
  );
318
423
  if (ca.includeNodeModules !== void 0)
319
424
  console.log(
320
- ` includeNodeModules: ${chalk2.bold(String(ca.includeNodeModules))}`
425
+ ` includeNodeModules: ${chalk3.bold(String(ca.includeNodeModules))}`
321
426
  );
322
427
  }
323
428
  if (finalOptions.consistency) {
324
429
  const c = finalOptions.consistency;
325
- console.log(chalk2.white("\nConsistency settings:"));
430
+ console.log(chalk3.white("\nConsistency settings:"));
326
431
  console.log(
327
- ` checkNaming: ${chalk2.bold(String(c.checkNaming ?? true))}`
432
+ ` checkNaming: ${chalk3.bold(String(c.checkNaming ?? true))}`
328
433
  );
329
434
  console.log(
330
- ` checkPatterns: ${chalk2.bold(String(c.checkPatterns ?? true))}`
435
+ ` checkPatterns: ${chalk3.bold(String(c.checkPatterns ?? true))}`
331
436
  );
332
437
  console.log(
333
- ` checkArchitecture: ${chalk2.bold(String(c.checkArchitecture ?? false))}`
438
+ ` checkArchitecture: ${chalk3.bold(String(c.checkArchitecture ?? false))}`
334
439
  );
335
440
  if (c.minSeverity)
336
- console.log(` minSeverity: ${chalk2.bold(c.minSeverity)}`);
441
+ console.log(` minSeverity: ${chalk3.bold(c.minSeverity)}`);
337
442
  if (c.acceptedAbbreviations)
338
443
  console.log(
339
- ` acceptedAbbreviations: ${chalk2.bold(truncateArray(c.acceptedAbbreviations, 8))}`
444
+ ` acceptedAbbreviations: ${chalk3.bold(truncateArray(c.acceptedAbbreviations, 8))}`
340
445
  );
341
446
  if (c.shortWords)
342
447
  console.log(
343
- ` shortWords: ${chalk2.bold(truncateArray(c.shortWords, 8))}`
448
+ ` shortWords: ${chalk3.bold(truncateArray(c.shortWords, 8))}`
344
449
  );
345
450
  }
346
- console.log(chalk2.white("\nStarting analysis..."));
451
+ console.log(chalk3.white("\nStarting analysis..."));
347
452
  const progressCallback = (event) => {
348
- console.log(chalk2.cyan(`
453
+ console.log(chalk3.cyan(`
349
454
  --- ${event.tool.toUpperCase()} RESULTS ---`));
350
455
  try {
351
456
  if (event.tool === "patterns") {
352
457
  const pr = event.data;
353
458
  console.log(
354
- ` Duplicate patterns: ${chalk2.bold(String(pr.duplicates?.length || 0))}`
459
+ ` Duplicate patterns: ${chalk3.bold(String(pr.duplicates?.length || 0))}`
355
460
  );
356
461
  console.log(
357
- ` Files with pattern issues: ${chalk2.bold(String(pr.results?.length || 0))}`
462
+ ` Files with pattern issues: ${chalk3.bold(String(pr.results?.length || 0))}`
358
463
  );
359
464
  if (pr.duplicates && pr.duplicates.length > 0) {
360
465
  pr.duplicates.slice(0, 5).forEach((d, i) => {
@@ -376,12 +481,12 @@ async function scanAction(directory, options) {
376
481
  }
377
482
  if (pr.groups && pr.groups.length >= 0) {
378
483
  console.log(
379
- ` \u2705 Grouped ${chalk2.bold(String(pr.duplicates?.length || 0))} duplicates into ${chalk2.bold(String(pr.groups.length))} file pairs`
484
+ ` \u2705 Grouped ${chalk3.bold(String(pr.duplicates?.length || 0))} duplicates into ${chalk3.bold(String(pr.groups.length))} file pairs`
380
485
  );
381
486
  }
382
487
  if (pr.clusters && pr.clusters.length >= 0) {
383
488
  console.log(
384
- ` \u2705 Created ${chalk2.bold(String(pr.clusters.length))} refactor clusters`
489
+ ` \u2705 Created ${chalk3.bold(String(pr.clusters.length))} refactor clusters`
385
490
  );
386
491
  pr.clusters.slice(0, 3).forEach((cl, idx) => {
387
492
  const files = (cl.files || []).map((f) => f.path.split("/").pop()).join(", ");
@@ -393,7 +498,7 @@ async function scanAction(directory, options) {
393
498
  } else if (event.tool === "context") {
394
499
  const cr = event.data;
395
500
  console.log(
396
- ` Context issues found: ${chalk2.bold(String(cr.length || 0))}`
501
+ ` Context issues found: ${chalk3.bold(String(cr.length || 0))}`
397
502
  );
398
503
  cr.slice(0, 5).forEach((c, i) => {
399
504
  const msg = c.message ? ` - ${c.message}` : "";
@@ -404,7 +509,7 @@ async function scanAction(directory, options) {
404
509
  } else if (event.tool === "consistency") {
405
510
  const rep = event.data;
406
511
  console.log(
407
- ` Consistency totalIssues: ${chalk2.bold(String(rep.summary?.totalIssues || 0))}`
512
+ ` Consistency totalIssues: ${chalk3.bold(String(rep.summary?.totalIssues || 0))}`
408
513
  );
409
514
  if (rep.results && rep.results.length > 0) {
410
515
  const fileMap = /* @__PURE__ */ new Map();
@@ -439,7 +544,7 @@ async function scanAction(directory, options) {
439
544
  const remaining = files.length - topFiles.length;
440
545
  if (remaining > 0) {
441
546
  console.log(
442
- chalk2.dim(
547
+ chalk3.dim(
443
548
  ` ... and ${remaining} more files with issues (use --output json for full details)`
444
549
  )
445
550
  );
@@ -448,37 +553,37 @@ async function scanAction(directory, options) {
448
553
  } else if (event.tool === "doc-drift") {
449
554
  const dr = event.data;
450
555
  console.log(
451
- ` Issues found: ${chalk2.bold(String(dr.issues?.length || 0))}`
556
+ ` Issues found: ${chalk3.bold(String(dr.issues?.length || 0))}`
452
557
  );
453
558
  if (dr.rawData) {
454
559
  console.log(
455
- ` Signature Mismatches: ${chalk2.bold(dr.rawData.outdatedComments || 0)}`
560
+ ` Signature Mismatches: ${chalk3.bold(dr.rawData.outdatedComments || 0)}`
456
561
  );
457
562
  console.log(
458
- ` Undocumented Complexity: ${chalk2.bold(dr.rawData.undocumentedComplexity || 0)}`
563
+ ` Undocumented Complexity: ${chalk3.bold(dr.rawData.undocumentedComplexity || 0)}`
459
564
  );
460
565
  }
461
566
  } else if (event.tool === "deps-health") {
462
567
  const dr = event.data;
463
568
  console.log(
464
- ` Packages Analyzed: ${chalk2.bold(String(dr.summary?.packagesAnalyzed || 0))}`
569
+ ` Packages Analyzed: ${chalk3.bold(String(dr.summary?.packagesAnalyzed || 0))}`
465
570
  );
466
571
  if (dr.rawData) {
467
572
  console.log(
468
- ` Deprecated Packages: ${chalk2.bold(dr.rawData.deprecatedPackages || 0)}`
573
+ ` Deprecated Packages: ${chalk3.bold(dr.rawData.deprecatedPackages || 0)}`
469
574
  );
470
575
  console.log(
471
- ` AI Cutoff Skew Score: ${chalk2.bold(dr.rawData.trainingCutoffSkew?.toFixed(1) || 0)}`
576
+ ` AI Cutoff Skew Score: ${chalk3.bold(dr.rawData.trainingCutoffSkew?.toFixed(1) || 0)}`
472
577
  );
473
578
  }
474
579
  } else if (event.tool === "change-amplification" || event.tool === "changeAmplification") {
475
580
  const dr = event.data;
476
581
  console.log(
477
- ` Coupling issues: ${chalk2.bold(String(dr.issues?.length || 0))}`
582
+ ` Coupling issues: ${chalk3.bold(String(dr.issues?.length || 0))}`
478
583
  );
479
584
  if (dr.summary) {
480
585
  console.log(
481
- ` Complexity Score: ${chalk2.bold(dr.summary.score || 0)}/100`
586
+ ` Complexity Score: ${chalk3.bold(dr.summary.score || 0)}/100`
482
587
  );
483
588
  }
484
589
  }
@@ -499,227 +604,169 @@ async function scanAction(directory, options) {
499
604
  },
500
605
  suppressToolConfig: true
501
606
  });
502
- console.log(chalk2.cyan("\n=== AIReady Run Summary ==="));
607
+ console.log(chalk3.cyan("\n=== AIReady Run Summary ==="));
503
608
  console.log(
504
- chalk2.white("Tools run:"),
609
+ chalk3.white("Tools run:"),
505
610
  (finalOptions.tools || ["patterns", "context", "consistency"]).join(", ")
506
611
  );
507
- console.log(chalk2.cyan("\nResults summary:"));
612
+ console.log(chalk3.cyan("\nResults summary:"));
508
613
  console.log(
509
- ` Total issues (all tools): ${chalk2.bold(String(results.summary.totalIssues || 0))}`
614
+ ` Total issues (all tools): ${chalk3.bold(String(results.summary.totalIssues || 0))}`
510
615
  );
511
616
  if (results.duplicates)
512
617
  console.log(
513
- ` Duplicate patterns found: ${chalk2.bold(String(results.duplicates.length || 0))}`
618
+ ` Duplicate patterns found: ${chalk3.bold(String(results.duplicates.length || 0))}`
514
619
  );
515
620
  if (results.patterns)
516
621
  console.log(
517
- ` Pattern files with issues: ${chalk2.bold(String(results.patterns.length || 0))}`
622
+ ` Pattern files with issues: ${chalk3.bold(String(results.patterns.length || 0))}`
518
623
  );
519
624
  if (results.context)
520
625
  console.log(
521
- ` Context issues: ${chalk2.bold(String(results.context.length || 0))}`
626
+ ` Context issues: ${chalk3.bold(String(results.context.length || 0))}`
522
627
  );
523
628
  console.log(
524
- ` Consistency issues: ${chalk2.bold(String(results.consistency?.summary?.totalIssues || 0))}`
629
+ ` Consistency issues: ${chalk3.bold(String(results.consistency?.summary?.totalIssues || 0))}`
525
630
  );
526
631
  if (results.changeAmplification)
527
632
  console.log(
528
- ` Change amplification: ${chalk2.bold(String(results.changeAmplification.summary?.score || 0))}/100`
633
+ ` Change amplification: ${chalk3.bold(String(results.changeAmplification.summary?.score || 0))}/100`
529
634
  );
530
- console.log(chalk2.cyan("===========================\n"));
635
+ console.log(chalk3.cyan("===========================\n"));
531
636
  const elapsedTime = getElapsedTime(startTime);
532
637
  void elapsedTime;
533
638
  let scoringResult;
534
639
  if (options.score || finalOptions.scoring?.showBreakdown) {
535
- const toolScores = /* @__PURE__ */ new Map();
536
- if (results.duplicates) {
537
- const { calculatePatternScore } = await import("@aiready/pattern-detect");
538
- try {
539
- const patternScore = calculatePatternScore(
540
- results.duplicates,
541
- results.patterns?.length || 0
542
- );
543
- toolScores.set("pattern-detect", patternScore);
544
- } catch (err) {
545
- void err;
546
- }
547
- }
548
- if (results.context) {
549
- const { generateSummary: genContextSummary, calculateContextScore } = await import("@aiready/context-analyzer");
640
+ scoringResult = await scoreUnified(results, finalOptions);
641
+ console.log(chalk3.bold("\n\u{1F4CA} AI Readiness Overall Score"));
642
+ console.log(` ${formatScore(scoringResult)}`);
643
+ if (options.compareTo) {
550
644
  try {
551
- const ctxSummary = genContextSummary(results.context);
552
- const contextScore = calculateContextScore(ctxSummary);
553
- toolScores.set("context-analyzer", contextScore);
554
- } catch (err) {
555
- void err;
556
- }
557
- }
558
- if (results.consistency) {
559
- const { calculateConsistencyScore } = await import("@aiready/consistency");
560
- try {
561
- const issues = results.consistency.results?.flatMap((r) => r.issues) || [];
562
- const totalFiles = results.consistency.summary?.filesAnalyzed || 0;
563
- const consistencyScore = calculateConsistencyScore(
564
- issues,
565
- totalFiles
566
- );
567
- toolScores.set("consistency", consistencyScore);
568
- } catch (err) {
569
- void err;
570
- }
571
- }
572
- if (results.aiSignalClarity) {
573
- const { calculateAiSignalClarityScore } = await import("@aiready/ai-signal-clarity");
574
- try {
575
- const hrScore = calculateAiSignalClarityScore(
576
- results.aiSignalClarity
645
+ const prevReportStr = readFileSync2(
646
+ resolvePath3(process.cwd(), options.compareTo),
647
+ "utf8"
577
648
  );
578
- toolScores.set("ai-signal-clarity", hrScore);
579
- } catch (err) {
580
- void err;
581
- }
582
- }
583
- if (results.grounding) {
584
- const { calculateGroundingScore } = await import("@aiready/agent-grounding");
585
- try {
586
- const agScore = calculateGroundingScore(results.grounding);
587
- toolScores.set("agent-grounding", agScore);
588
- } catch (err) {
589
- void err;
590
- }
591
- }
592
- if (results.testability) {
593
- const { calculateTestabilityScore } = await import("@aiready/testability");
594
- try {
595
- const tbScore = calculateTestabilityScore(results.testability);
596
- toolScores.set("testability", tbScore);
597
- } catch (err) {
598
- void err;
599
- }
600
- }
601
- if (results.docDrift) {
602
- toolScores.set("doc-drift", {
603
- toolName: "doc-drift",
604
- score: results.docDrift.summary.score,
605
- rawMetrics: results.docDrift.rawData,
606
- factors: [],
607
- recommendations: (results.docDrift.recommendations || []).map(
608
- (action) => ({
609
- action,
610
- estimatedImpact: 5,
611
- priority: "medium"
612
- })
613
- )
614
- });
615
- }
616
- if (results.deps) {
617
- toolScores.set("dependency-health", {
618
- toolName: "dependency-health",
619
- score: results.deps.summary.score,
620
- rawMetrics: results.deps.rawData,
621
- factors: [],
622
- recommendations: (results.deps.recommendations || []).map(
623
- (action) => ({
624
- action,
625
- estimatedImpact: 5,
626
- priority: "medium"
627
- })
628
- )
629
- });
630
- }
631
- if (results.changeAmplification) {
632
- toolScores.set("change-amplification", {
633
- toolName: "change-amplification",
634
- score: results.changeAmplification.summary.score,
635
- rawMetrics: results.changeAmplification.rawData,
636
- factors: [],
637
- recommendations: (results.changeAmplification.recommendations || []).map((action) => ({
638
- action,
639
- estimatedImpact: 5,
640
- priority: "medium"
641
- }))
642
- });
643
- }
644
- const cliWeights = parseWeightString(options.weights);
645
- if (toolScores.size > 0) {
646
- scoringResult = calculateOverallScore(
647
- toolScores,
648
- finalOptions,
649
- cliWeights.size ? cliWeights : void 0
650
- );
651
- console.log(chalk2.bold("\n\u{1F4CA} AI Readiness Overall Score"));
652
- console.log(` ${formatScore(scoringResult)}`);
653
- if (options.compareTo) {
654
- try {
655
- const prevReportStr = readFileSync2(
656
- resolvePath2(process.cwd(), options.compareTo),
657
- "utf8"
658
- );
659
- const prevReport = JSON.parse(prevReportStr);
660
- const prevScore = prevReport.scoring?.score || prevReport.scoring?.overallScore;
661
- if (typeof prevScore === "number") {
662
- const diff = scoringResult.overall - prevScore;
663
- const diffStr = diff > 0 ? `+${diff}` : String(diff);
664
- console.log();
665
- if (diff > 0) {
666
- console.log(
667
- chalk2.green(
668
- ` \u{1F4C8} Trend: ${diffStr} compared to ${options.compareTo} (${prevScore} \u2192 ${scoringResult.overall})`
669
- )
670
- );
671
- } else if (diff < 0) {
672
- console.log(
673
- chalk2.red(
674
- ` \u{1F4C9} Trend: ${diffStr} compared to ${options.compareTo} (${prevScore} \u2192 ${scoringResult.overall})`
675
- )
676
- );
677
- } else {
678
- console.log(
679
- chalk2.blue(
680
- ` \u2796 Trend: No change compared to ${options.compareTo} (${prevScore} \u2192 ${scoringResult.overall})`
681
- )
682
- );
683
- }
684
- scoringResult.trend = {
685
- previousScore: prevScore,
686
- difference: diff
687
- };
649
+ const prevReport = JSON.parse(prevReportStr);
650
+ const prevScore = prevReport.scoring?.score || prevReport.scoring?.overallScore;
651
+ if (typeof prevScore === "number") {
652
+ const diff = scoringResult.overall - prevScore;
653
+ const diffStr = diff > 0 ? `+${diff}` : String(diff);
654
+ console.log();
655
+ if (diff > 0) {
656
+ console.log(
657
+ chalk3.green(
658
+ ` \u{1F4C8} Trend: ${diffStr} compared to ${options.compareTo} (${prevScore} \u2192 ${scoringResult.overall})`
659
+ )
660
+ );
661
+ } else if (diff < 0) {
662
+ console.log(
663
+ chalk3.red(
664
+ ` \u{1F4C9} Trend: ${diffStr} compared to ${options.compareTo} (${prevScore} \u2192 ${scoringResult.overall})`
665
+ )
666
+ );
688
667
  } else {
689
668
  console.log(
690
- chalk2.yellow(
691
- `
692
- \u26A0\uFE0F Previous report at ${options.compareTo} does not contain an overall score.`
669
+ chalk3.blue(
670
+ ` \u2796 Trend: No change compared to ${options.compareTo} (${prevScore} \u2192 ${scoringResult.overall})`
693
671
  )
694
672
  );
695
673
  }
696
- } catch (e) {
697
- void e;
674
+ scoringResult.trend = {
675
+ previousScore: prevScore,
676
+ difference: diff
677
+ };
678
+ } else {
698
679
  console.log(
699
- chalk2.yellow(
680
+ chalk3.yellow(
700
681
  `
701
- \u26A0\uFE0F Could not read or parse previous report at ${options.compareTo}.`
682
+ \u26A0\uFE0F Previous report at ${options.compareTo} does not contain an overall score.`
702
683
  )
703
684
  );
704
685
  }
686
+ } catch (e) {
687
+ void e;
688
+ console.log(
689
+ chalk3.yellow(
690
+ `
691
+ \u26A0\uFE0F Could not read or parse previous report at ${options.compareTo}.`
692
+ )
693
+ );
705
694
  }
706
- if (scoringResult.breakdown && scoringResult.breakdown.length > 0) {
707
- console.log(chalk2.bold("\nTool breakdown:"));
695
+ }
696
+ const totalWastedDuplication = (scoringResult.breakdown || []).reduce(
697
+ (sum, s) => sum + (s.tokenBudget?.wastedTokens.bySource.duplication || 0),
698
+ 0
699
+ );
700
+ const totalWastedFragmentation = (scoringResult.breakdown || []).reduce(
701
+ (sum, s) => sum + (s.tokenBudget?.wastedTokens.bySource.fragmentation || 0),
702
+ 0
703
+ );
704
+ const totalContext = Math.max(
705
+ ...(scoringResult.breakdown || []).map(
706
+ (s) => s.tokenBudget?.totalContextTokens || 0
707
+ )
708
+ );
709
+ if (totalContext > 0) {
710
+ const unifiedBudget = calculateTokenBudget({
711
+ totalContextTokens: totalContext,
712
+ wastedTokens: {
713
+ duplication: totalWastedDuplication,
714
+ fragmentation: totalWastedFragmentation,
715
+ chattiness: 0
716
+ }
717
+ });
718
+ const targetModel = options.model || "claude-4.6";
719
+ const modelPreset = getModelPreset(targetModel);
720
+ const costEstimate = estimateCostFromBudget(unifiedBudget, modelPreset);
721
+ const barWidth = 20;
722
+ const filled = Math.round(unifiedBudget.efficiencyRatio * barWidth);
723
+ const bar = chalk3.green("\u2588".repeat(filled)) + chalk3.dim("\u2591".repeat(barWidth - filled));
724
+ console.log(chalk3.bold("\n\u{1F4CA} AI Token Budget Analysis (v0.13)"));
725
+ console.log(
726
+ ` Efficiency: [${bar}] ${(unifiedBudget.efficiencyRatio * 100).toFixed(0)}%`
727
+ );
728
+ console.log(
729
+ ` Total Context: ${chalk3.bold(unifiedBudget.totalContextTokens.toLocaleString())} tokens`
730
+ );
731
+ console.log(
732
+ ` Wasted Tokens: ${chalk3.red(unifiedBudget.wastedTokens.total.toLocaleString())} (${(unifiedBudget.wastedTokens.total / unifiedBudget.totalContextTokens * 100).toFixed(1)}%)`
733
+ );
734
+ console.log(` Waste Breakdown:`);
735
+ console.log(
736
+ ` \u2022 Duplication: ${unifiedBudget.wastedTokens.bySource.duplication.toLocaleString()} tokens`
737
+ );
738
+ console.log(
739
+ ` \u2022 Fragmentation: ${unifiedBudget.wastedTokens.bySource.fragmentation.toLocaleString()} tokens`
740
+ );
741
+ console.log(
742
+ ` Potential Savings: ${chalk3.green(unifiedBudget.potentialRetrievableTokens.toLocaleString())} tokens retrievable`
743
+ );
744
+ console.log(
745
+ `
746
+ Est. Monthly Cost (${modelPreset.name}): ${chalk3.bold("$" + costEstimate.total)} [range: $${costEstimate.range[0]}-$${costEstimate.range[1]}]`
747
+ );
748
+ scoringResult.tokenBudget = unifiedBudget;
749
+ scoringResult.costEstimate = {
750
+ model: modelPreset.name,
751
+ ...costEstimate
752
+ };
753
+ }
754
+ if (scoringResult.breakdown && scoringResult.breakdown.length > 0) {
755
+ console.log(chalk3.bold("\nTool breakdown:"));
756
+ scoringResult.breakdown.forEach((tool) => {
757
+ const rating = getRating(tool.score);
758
+ const rd = getRatingDisplay(rating);
759
+ console.log(
760
+ ` - ${tool.toolName}: ${tool.score}/100 (${rating}) ${rd.emoji}`
761
+ );
762
+ });
763
+ console.log();
764
+ if (finalOptions.scoring?.showBreakdown) {
765
+ console.log(chalk3.bold("Detailed tool breakdown:"));
708
766
  scoringResult.breakdown.forEach((tool) => {
709
- const rating = getRating(tool.score);
710
- const rd = getRatingDisplay(rating);
711
- console.log(
712
- ` - ${tool.toolName}: ${tool.score}/100 (${rating}) ${rd.emoji}`
713
- );
767
+ console.log(formatToolScore(tool));
714
768
  });
715
769
  console.log();
716
- if (finalOptions.scoring?.showBreakdown) {
717
- console.log(chalk2.bold("Detailed tool breakdown:"));
718
- scoringResult.breakdown.forEach((tool) => {
719
- console.log(formatToolScore(tool));
720
- });
721
- console.log();
722
- }
723
770
  }
724
771
  }
725
772
  }
@@ -733,12 +780,23 @@ async function scanAction(directory, options) {
733
780
  defaultFilename,
734
781
  resolvedDir
735
782
  );
736
- const outputData = { ...results, scoring: scoringResult };
783
+ const outputData = {
784
+ ...results,
785
+ scoring: scoringResult,
786
+ repository: repoMetadata
787
+ };
737
788
  handleJSONOutput(
738
789
  outputData,
739
790
  outputPath,
740
791
  `\u2705 Report saved to ${outputPath}`
741
792
  );
793
+ if (options.upload) {
794
+ console.log(chalk3.blue("\n\u{1F4E4} Automatic upload triggered..."));
795
+ await uploadAction(outputPath, {
796
+ apiKey: options.apiKey,
797
+ server: options.server
798
+ });
799
+ }
742
800
  await warnIfGraphCapExceeded(outputData, resolvedDir);
743
801
  } else {
744
802
  const timestamp = getReportTimestamp();
@@ -748,10 +806,21 @@ async function scanAction(directory, options) {
748
806
  defaultFilename,
749
807
  resolvedDir
750
808
  );
751
- const outputData = { ...results, scoring: scoringResult };
809
+ const outputData = {
810
+ ...results,
811
+ scoring: scoringResult,
812
+ repository: repoMetadata
813
+ };
752
814
  try {
753
815
  writeFileSync(outputPath, JSON.stringify(outputData, null, 2));
754
- console.log(chalk2.dim(`\u2705 Report auto-persisted to ${outputPath}`));
816
+ console.log(chalk3.dim(`\u2705 Report auto-persisted to ${outputPath}`));
817
+ if (options.upload) {
818
+ console.log(chalk3.blue("\n\u{1F4E4} Automatic upload triggered..."));
819
+ await uploadAction(outputPath, {
820
+ apiKey: options.apiKey,
821
+ server: options.server
822
+ });
823
+ }
755
824
  await warnIfGraphCapExceeded(outputData, resolvedDir);
756
825
  } catch (err) {
757
826
  void err;
@@ -833,37 +902,37 @@ async function scanAction(directory, options) {
833
902
  }
834
903
  }
835
904
  if (shouldFail) {
836
- console.log(chalk2.red("\n\u{1F6AB} PR BLOCKED: AI Readiness Check Failed"));
837
- console.log(chalk2.red(` Reason: ${failReason}`));
838
- console.log(chalk2.dim("\n Remediation steps:"));
905
+ console.log(chalk3.red("\n\u{1F6AB} PR BLOCKED: AI Readiness Check Failed"));
906
+ console.log(chalk3.red(` Reason: ${failReason}`));
907
+ console.log(chalk3.dim("\n Remediation steps:"));
839
908
  console.log(
840
- chalk2.dim(" 1. Run `aiready scan` locally to see detailed issues")
909
+ chalk3.dim(" 1. Run `aiready scan` locally to see detailed issues")
841
910
  );
842
- console.log(chalk2.dim(" 2. Fix the critical issues before merging"));
911
+ console.log(chalk3.dim(" 2. Fix the critical issues before merging"));
843
912
  console.log(
844
- chalk2.dim(
913
+ chalk3.dim(
845
914
  " 3. Consider upgrading to Team plan for historical tracking: https://getaiready.dev/pricing"
846
915
  )
847
916
  );
848
917
  process.exit(1);
849
918
  } else {
850
- console.log(chalk2.green("\n\u2705 PR PASSED: AI Readiness Check"));
919
+ console.log(chalk3.green("\n\u2705 PR PASSED: AI Readiness Check"));
851
920
  if (threshold) {
852
921
  console.log(
853
- chalk2.green(
922
+ chalk3.green(
854
923
  ` Score: ${scoringResult.overall}/100 (threshold: ${threshold})`
855
924
  )
856
925
  );
857
926
  }
858
927
  console.log(
859
- chalk2.dim(
928
+ chalk3.dim(
860
929
  "\n \u{1F4A1} Track historical trends: https://getaiready.dev \u2014 Team plan $99/mo"
861
930
  )
862
931
  );
863
932
  }
864
933
  }
865
934
  } catch (error) {
866
- handleCLIError(error, "Analysis");
935
+ handleCLIError2(error, "Analysis");
867
936
  }
868
937
  }
869
938
  var scanHelpText = `
@@ -877,6 +946,8 @@ EXAMPLES:
877
946
  $ aiready scan --ci --threshold 70 # GitHub Actions gatekeeper
878
947
  $ aiready scan --ci --fail-on major # Fail on major+ issues
879
948
  $ aiready scan --output json --output-file report.json
949
+ $ aiready scan --upload --api-key ar_... # Automatic platform upload
950
+ $ aiready scan --upload --server custom-url.com # Upload to custom platform
880
951
 
881
952
  PROFILES:
882
953
  agentic: aiSignalClarity, grounding, testability
@@ -896,20 +967,20 @@ CI/CD INTEGRATION (Gatekeeper Mode):
896
967
  `;
897
968
 
898
969
  // src/commands/patterns.ts
899
- import chalk3 from "chalk";
900
- import { resolve as resolvePath3 } from "path";
970
+ import chalk4 from "chalk";
971
+ import { resolve as resolvePath4 } from "path";
901
972
  import {
902
973
  loadMergedConfig as loadMergedConfig2,
903
974
  handleJSONOutput as handleJSONOutput2,
904
- handleCLIError as handleCLIError2,
975
+ handleCLIError as handleCLIError3,
905
976
  getElapsedTime as getElapsedTime2,
906
977
  resolveOutputPath as resolveOutputPath2,
907
978
  formatToolScore as formatToolScore2
908
979
  } from "@aiready/core";
909
980
  async function patternsAction(directory, options) {
910
- console.log(chalk3.blue("\u{1F50D} Analyzing patterns...\n"));
981
+ console.log(chalk4.blue("\u{1F50D} Analyzing patterns...\n"));
911
982
  const startTime = Date.now();
912
- const resolvedDir = resolvePath3(process.cwd(), directory || ".");
983
+ const resolvedDir = resolvePath4(process.cwd(), directory || ".");
913
984
  try {
914
985
  const useSmartDefaults = !options.fullScan;
915
986
  const defaults = {
@@ -973,38 +1044,38 @@ async function patternsAction(directory, options) {
973
1044
  const terminalWidth = process.stdout.columns || 80;
974
1045
  const dividerWidth = Math.min(60, terminalWidth - 2);
975
1046
  const divider = "\u2501".repeat(dividerWidth);
976
- console.log(chalk3.cyan(divider));
977
- console.log(chalk3.bold.white(" PATTERN ANALYSIS SUMMARY"));
978
- console.log(chalk3.cyan(divider) + "\n");
1047
+ console.log(chalk4.cyan(divider));
1048
+ console.log(chalk4.bold.white(" PATTERN ANALYSIS SUMMARY"));
1049
+ console.log(chalk4.cyan(divider) + "\n");
979
1050
  console.log(
980
- chalk3.white(`\u{1F4C1} Files analyzed: ${chalk3.bold(results.length)}`)
1051
+ chalk4.white(`\u{1F4C1} Files analyzed: ${chalk4.bold(results.length)}`)
981
1052
  );
982
1053
  console.log(
983
- chalk3.yellow(
984
- `\u26A0 Duplicate patterns found: ${chalk3.bold(summary.totalPatterns)}`
1054
+ chalk4.yellow(
1055
+ `\u26A0 Duplicate patterns found: ${chalk4.bold(summary.totalPatterns)}`
985
1056
  )
986
1057
  );
987
1058
  console.log(
988
- chalk3.red(
989
- `\u{1F4B0} Token cost (wasted): ${chalk3.bold(summary.totalTokenCost.toLocaleString())}`
1059
+ chalk4.red(
1060
+ `\u{1F4B0} Token cost (wasted): ${chalk4.bold(summary.totalTokenCost.toLocaleString())}`
990
1061
  )
991
1062
  );
992
1063
  console.log(
993
- chalk3.gray(`\u23F1 Analysis time: ${chalk3.bold(elapsedTime + "s")}`)
1064
+ chalk4.gray(`\u23F1 Analysis time: ${chalk4.bold(elapsedTime + "s")}`)
994
1065
  );
995
1066
  const sortedTypes = Object.entries(summary.patternsByType || {}).filter(([, count]) => count > 0).sort(([, a], [, b]) => b - a);
996
1067
  if (sortedTypes.length > 0) {
997
- console.log(chalk3.cyan("\n" + divider));
998
- console.log(chalk3.bold.white(" PATTERNS BY TYPE"));
999
- console.log(chalk3.cyan(divider) + "\n");
1068
+ console.log(chalk4.cyan("\n" + divider));
1069
+ console.log(chalk4.bold.white(" PATTERNS BY TYPE"));
1070
+ console.log(chalk4.cyan(divider) + "\n");
1000
1071
  sortedTypes.forEach(([type, count]) => {
1001
- console.log(` ${chalk3.white(type.padEnd(15))} ${chalk3.bold(count)}`);
1072
+ console.log(` ${chalk4.white(type.padEnd(15))} ${chalk4.bold(count)}`);
1002
1073
  });
1003
1074
  }
1004
1075
  if (summary.totalPatterns > 0 && duplicates.length > 0) {
1005
- console.log(chalk3.cyan("\n" + divider));
1006
- console.log(chalk3.bold.white(" TOP DUPLICATE PATTERNS"));
1007
- console.log(chalk3.cyan(divider) + "\n");
1076
+ console.log(chalk4.cyan("\n" + divider));
1077
+ console.log(chalk4.bold.white(" TOP DUPLICATE PATTERNS"));
1078
+ console.log(chalk4.cyan(divider) + "\n");
1008
1079
  const topDuplicates = [...duplicates].sort((a, b) => b.similarity - a.similarity).slice(0, 10);
1009
1080
  topDuplicates.forEach((dup) => {
1010
1081
  const severity = dup.similarity > 0.95 ? "CRITICAL" : dup.similarity > 0.9 ? "HIGH" : "MEDIUM";
@@ -1012,31 +1083,31 @@ async function patternsAction(directory, options) {
1012
1083
  const file1Name = dup.file1.split("/").pop() || dup.file1;
1013
1084
  const file2Name = dup.file2.split("/").pop() || dup.file2;
1014
1085
  console.log(
1015
- `${severityIcon} ${severity}: ${chalk3.bold(file1Name)} \u2194 ${chalk3.bold(file2Name)}`
1086
+ `${severityIcon} ${severity}: ${chalk4.bold(file1Name)} \u2194 ${chalk4.bold(file2Name)}`
1016
1087
  );
1017
1088
  console.log(
1018
- ` Similarity: ${chalk3.bold(Math.round(dup.similarity * 100) + "%")} | Wasted: ${chalk3.bold(dup.tokenCost.toLocaleString())} tokens each`
1089
+ ` Similarity: ${chalk4.bold(Math.round(dup.similarity * 100) + "%")} | Wasted: ${chalk4.bold(dup.tokenCost.toLocaleString())} tokens each`
1019
1090
  );
1020
1091
  console.log(
1021
- ` Lines: ${chalk3.cyan(dup.line1 + "-" + dup.endLine1)} \u2194 ${chalk3.cyan(dup.line2 + "-" + dup.endLine2)}
1092
+ ` Lines: ${chalk4.cyan(dup.line1 + "-" + dup.endLine1)} \u2194 ${chalk4.cyan(dup.line2 + "-" + dup.endLine2)}
1022
1093
  `
1023
1094
  );
1024
1095
  });
1025
1096
  } else {
1026
1097
  console.log(
1027
- chalk3.green("\n\u2728 Great! No duplicate patterns detected.\n")
1098
+ chalk4.green("\n\u2728 Great! No duplicate patterns detected.\n")
1028
1099
  );
1029
1100
  }
1030
1101
  if (patternScore) {
1031
- console.log(chalk3.cyan(divider));
1032
- console.log(chalk3.bold.white(" AI READINESS SCORE (Patterns)"));
1033
- console.log(chalk3.cyan(divider) + "\n");
1102
+ console.log(chalk4.cyan(divider));
1103
+ console.log(chalk4.bold.white(" AI READINESS SCORE (Patterns)"));
1104
+ console.log(chalk4.cyan(divider) + "\n");
1034
1105
  console.log(formatToolScore2(patternScore));
1035
1106
  console.log();
1036
1107
  }
1037
1108
  }
1038
1109
  } catch (error) {
1039
- handleCLIError2(error, "Pattern analysis");
1110
+ handleCLIError3(error, "Pattern analysis");
1040
1111
  }
1041
1112
  }
1042
1113
  var patternsHelpText = `
@@ -1047,20 +1118,20 @@ EXAMPLES:
1047
1118
  `;
1048
1119
 
1049
1120
  // src/commands/context.ts
1050
- import chalk4 from "chalk";
1051
- import { resolve as resolvePath4 } from "path";
1121
+ import chalk5 from "chalk";
1122
+ import { resolve as resolvePath5 } from "path";
1052
1123
  import {
1053
1124
  loadMergedConfig as loadMergedConfig3,
1054
1125
  handleJSONOutput as handleJSONOutput3,
1055
- handleCLIError as handleCLIError3,
1126
+ handleCLIError as handleCLIError4,
1056
1127
  getElapsedTime as getElapsedTime3,
1057
1128
  resolveOutputPath as resolveOutputPath3,
1058
1129
  formatToolScore as formatToolScore3
1059
1130
  } from "@aiready/core";
1060
1131
  async function contextAction(directory, options) {
1061
- console.log(chalk4.blue("\u{1F9E0} Analyzing context costs...\n"));
1132
+ console.log(chalk5.blue("\u{1F9E0} Analyzing context costs...\n"));
1062
1133
  const startTime = Date.now();
1063
- const resolvedDir = resolvePath4(process.cwd(), directory || ".");
1134
+ const resolvedDir = resolvePath5(process.cwd(), directory || ".");
1064
1135
  try {
1065
1136
  const defaults = {
1066
1137
  maxDepth: 5,
@@ -1126,85 +1197,85 @@ async function contextAction(directory, options) {
1126
1197
  const terminalWidth = process.stdout.columns || 80;
1127
1198
  const dividerWidth = Math.min(60, terminalWidth - 2);
1128
1199
  const divider = "\u2501".repeat(dividerWidth);
1129
- console.log(chalk4.cyan(divider));
1130
- console.log(chalk4.bold.white(" CONTEXT ANALYSIS SUMMARY"));
1131
- console.log(chalk4.cyan(divider) + "\n");
1200
+ console.log(chalk5.cyan(divider));
1201
+ console.log(chalk5.bold.white(" CONTEXT ANALYSIS SUMMARY"));
1202
+ console.log(chalk5.cyan(divider) + "\n");
1132
1203
  console.log(
1133
- chalk4.white(`\u{1F4C1} Files analyzed: ${chalk4.bold(summary.totalFiles)}`)
1204
+ chalk5.white(`\u{1F4C1} Files analyzed: ${chalk5.bold(summary.totalFiles)}`)
1134
1205
  );
1135
1206
  console.log(
1136
- chalk4.white(
1137
- `\u{1F4CA} Total tokens: ${chalk4.bold(summary.totalTokens.toLocaleString())}`
1207
+ chalk5.white(
1208
+ `\u{1F4CA} Total tokens: ${chalk5.bold(summary.totalTokens.toLocaleString())}`
1138
1209
  )
1139
1210
  );
1140
1211
  console.log(
1141
- chalk4.yellow(
1142
- `\u{1F4B0} Avg context budget: ${chalk4.bold(summary.avgContextBudget.toFixed(0))} tokens/file`
1212
+ chalk5.yellow(
1213
+ `\u{1F4B0} Avg context budget: ${chalk5.bold(summary.avgContextBudget.toFixed(0))} tokens/file`
1143
1214
  )
1144
1215
  );
1145
1216
  console.log(
1146
- chalk4.white(`\u23F1 Analysis time: ${chalk4.bold(elapsedTime + "s")}
1217
+ chalk5.white(`\u23F1 Analysis time: ${chalk5.bold(elapsedTime + "s")}
1147
1218
  `)
1148
1219
  );
1149
1220
  const totalIssues = summary.criticalIssues + summary.majorIssues + summary.minorIssues;
1150
1221
  if (totalIssues > 0) {
1151
- console.log(chalk4.bold("\u26A0\uFE0F Issues Found:\n"));
1222
+ console.log(chalk5.bold("\u26A0\uFE0F Issues Found:\n"));
1152
1223
  if (summary.criticalIssues > 0) {
1153
1224
  console.log(
1154
- chalk4.red(` \u{1F534} Critical: ${chalk4.bold(summary.criticalIssues)}`)
1225
+ chalk5.red(` \u{1F534} Critical: ${chalk5.bold(summary.criticalIssues)}`)
1155
1226
  );
1156
1227
  }
1157
1228
  if (summary.majorIssues > 0) {
1158
1229
  console.log(
1159
- chalk4.yellow(` \u{1F7E1} Major: ${chalk4.bold(summary.majorIssues)}`)
1230
+ chalk5.yellow(` \u{1F7E1} Major: ${chalk5.bold(summary.majorIssues)}`)
1160
1231
  );
1161
1232
  }
1162
1233
  if (summary.minorIssues > 0) {
1163
1234
  console.log(
1164
- chalk4.blue(` \u{1F535} Minor: ${chalk4.bold(summary.minorIssues)}`)
1235
+ chalk5.blue(` \u{1F535} Minor: ${chalk5.bold(summary.minorIssues)}`)
1165
1236
  );
1166
1237
  }
1167
1238
  console.log(
1168
- chalk4.green(
1239
+ chalk5.green(
1169
1240
  `
1170
- \u{1F4A1} Potential savings: ${chalk4.bold(summary.totalPotentialSavings.toLocaleString())} tokens
1241
+ \u{1F4A1} Potential savings: ${chalk5.bold(summary.totalPotentialSavings.toLocaleString())} tokens
1171
1242
  `
1172
1243
  )
1173
1244
  );
1174
1245
  } else {
1175
- console.log(chalk4.green("\u2705 No significant issues found!\n"));
1246
+ console.log(chalk5.green("\u2705 No significant issues found!\n"));
1176
1247
  }
1177
1248
  if (summary.deepFiles.length > 0) {
1178
- console.log(chalk4.bold("\u{1F4CF} Deep Import Chains:\n"));
1249
+ console.log(chalk5.bold("\u{1F4CF} Deep Import Chains:\n"));
1179
1250
  console.log(
1180
- chalk4.gray(` Average depth: ${summary.avgImportDepth.toFixed(1)}`)
1251
+ chalk5.gray(` Average depth: ${summary.avgImportDepth.toFixed(1)}`)
1181
1252
  );
1182
1253
  console.log(
1183
- chalk4.gray(` Maximum depth: ${summary.maxImportDepth}
1254
+ chalk5.gray(` Maximum depth: ${summary.maxImportDepth}
1184
1255
  `)
1185
1256
  );
1186
1257
  summary.deepFiles.slice(0, 10).forEach((item) => {
1187
1258
  const fileName = item.file.split("/").slice(-2).join("/");
1188
1259
  console.log(
1189
- ` ${chalk4.cyan("\u2192")} ${chalk4.white(fileName)} ${chalk4.dim(`(depth: ${item.depth})`)}`
1260
+ ` ${chalk5.cyan("\u2192")} ${chalk5.white(fileName)} ${chalk5.dim(`(depth: ${item.depth})`)}`
1190
1261
  );
1191
1262
  });
1192
1263
  console.log();
1193
1264
  }
1194
1265
  if (summary.fragmentedModules.length > 0) {
1195
- console.log(chalk4.bold("\u{1F9E9} Fragmented Modules:\n"));
1266
+ console.log(chalk5.bold("\u{1F9E9} Fragmented Modules:\n"));
1196
1267
  console.log(
1197
- chalk4.gray(
1268
+ chalk5.gray(
1198
1269
  ` Average fragmentation: ${(summary.avgFragmentation * 100).toFixed(0)}%
1199
1270
  `
1200
1271
  )
1201
1272
  );
1202
1273
  summary.fragmentedModules.slice(0, 10).forEach((module) => {
1203
1274
  console.log(
1204
- ` ${chalk4.yellow("\u25CF")} ${chalk4.white(module.domain)} - ${chalk4.dim(`${module.files.length} files, ${(module.fragmentationScore * 100).toFixed(0)}% scattered`)}`
1275
+ ` ${chalk5.yellow("\u25CF")} ${chalk5.white(module.domain)} - ${chalk5.dim(`${module.files.length} files, ${(module.fragmentationScore * 100).toFixed(0)}% scattered`)}`
1205
1276
  );
1206
1277
  console.log(
1207
- chalk4.dim(
1278
+ chalk5.dim(
1208
1279
  ` Token cost: ${module.totalTokens.toLocaleString()}, Cohesion: ${(module.avgCohesion * 100).toFixed(0)}%`
1209
1280
  )
1210
1281
  );
@@ -1212,9 +1283,9 @@ async function contextAction(directory, options) {
1212
1283
  console.log();
1213
1284
  }
1214
1285
  if (summary.lowCohesionFiles.length > 0) {
1215
- console.log(chalk4.bold("\u{1F500} Low Cohesion Files:\n"));
1286
+ console.log(chalk5.bold("\u{1F500} Low Cohesion Files:\n"));
1216
1287
  console.log(
1217
- chalk4.gray(
1288
+ chalk5.gray(
1218
1289
  ` Average cohesion: ${(summary.avgCohesion * 100).toFixed(0)}%
1219
1290
  `
1220
1291
  )
@@ -1222,53 +1293,53 @@ async function contextAction(directory, options) {
1222
1293
  summary.lowCohesionFiles.slice(0, 10).forEach((item) => {
1223
1294
  const fileName = item.file.split("/").slice(-2).join("/");
1224
1295
  const scorePercent = (item.score * 100).toFixed(0);
1225
- const color = item.score < 0.4 ? chalk4.red : chalk4.yellow;
1296
+ const color = item.score < 0.4 ? chalk5.red : chalk5.yellow;
1226
1297
  console.log(
1227
- ` ${color("\u25CB")} ${chalk4.white(fileName)} ${chalk4.dim(`(${scorePercent}% cohesion)`)}`
1298
+ ` ${color("\u25CB")} ${chalk5.white(fileName)} ${chalk5.dim(`(${scorePercent}% cohesion)`)}`
1228
1299
  );
1229
1300
  });
1230
1301
  console.log();
1231
1302
  }
1232
1303
  if (summary.topExpensiveFiles.length > 0) {
1233
- console.log(chalk4.bold("\u{1F4B8} Most Expensive Files (Context Budget):\n"));
1304
+ console.log(chalk5.bold("\u{1F4B8} Most Expensive Files (Context Budget):\n"));
1234
1305
  summary.topExpensiveFiles.slice(0, 10).forEach((item) => {
1235
1306
  const fileName = item.file.split("/").slice(-2).join("/");
1236
- const severityColor = item.severity === "critical" ? chalk4.red : item.severity === "major" ? chalk4.yellow : chalk4.blue;
1307
+ const severityColor = item.severity === "critical" ? chalk5.red : item.severity === "major" ? chalk5.yellow : chalk5.blue;
1237
1308
  console.log(
1238
- ` ${severityColor("\u25CF")} ${chalk4.white(fileName)} ${chalk4.dim(`(${item.contextBudget.toLocaleString()} tokens)`)}`
1309
+ ` ${severityColor("\u25CF")} ${chalk5.white(fileName)} ${chalk5.dim(`(${item.contextBudget.toLocaleString()} tokens)`)}`
1239
1310
  );
1240
1311
  });
1241
1312
  console.log();
1242
1313
  }
1243
1314
  if (contextScore) {
1244
- console.log(chalk4.cyan(divider));
1245
- console.log(chalk4.bold.white(" AI READINESS SCORE (Context)"));
1246
- console.log(chalk4.cyan(divider) + "\n");
1315
+ console.log(chalk5.cyan(divider));
1316
+ console.log(chalk5.bold.white(" AI READINESS SCORE (Context)"));
1317
+ console.log(chalk5.cyan(divider) + "\n");
1247
1318
  console.log(formatToolScore3(contextScore));
1248
1319
  console.log();
1249
1320
  }
1250
1321
  }
1251
1322
  } catch (error) {
1252
- handleCLIError3(error, "Context analysis");
1323
+ handleCLIError4(error, "Context analysis");
1253
1324
  }
1254
1325
  }
1255
1326
 
1256
1327
  // src/commands/consistency.ts
1257
- import chalk5 from "chalk";
1328
+ import chalk6 from "chalk";
1258
1329
  import { writeFileSync as writeFileSync2 } from "fs";
1259
- import { resolve as resolvePath5 } from "path";
1330
+ import { resolve as resolvePath6 } from "path";
1260
1331
  import {
1261
1332
  loadMergedConfig as loadMergedConfig4,
1262
1333
  handleJSONOutput as handleJSONOutput4,
1263
- handleCLIError as handleCLIError4,
1334
+ handleCLIError as handleCLIError5,
1264
1335
  getElapsedTime as getElapsedTime4,
1265
1336
  resolveOutputPath as resolveOutputPath4,
1266
1337
  formatToolScore as formatToolScore4
1267
1338
  } from "@aiready/core";
1268
1339
  async function consistencyAction(directory, options) {
1269
- console.log(chalk5.blue("\u{1F50D} Analyzing consistency...\n"));
1340
+ console.log(chalk6.blue("\u{1F50D} Analyzing consistency...\n"));
1270
1341
  const startTime = Date.now();
1271
- const resolvedDir = resolvePath5(process.cwd(), directory || ".");
1342
+ const resolvedDir = resolvePath6(process.cwd(), directory || ".");
1272
1343
  try {
1273
1344
  const defaults = {
1274
1345
  checkNaming: true,
@@ -1328,23 +1399,23 @@ async function consistencyAction(directory, options) {
1328
1399
  resolvedDir
1329
1400
  );
1330
1401
  writeFileSync2(outputPath, markdown);
1331
- console.log(chalk5.green(`\u2705 Report saved to ${outputPath}`));
1402
+ console.log(chalk6.green(`\u2705 Report saved to ${outputPath}`));
1332
1403
  } else {
1333
- console.log(chalk5.bold("\n\u{1F4CA} Summary\n"));
1404
+ console.log(chalk6.bold("\n\u{1F4CA} Summary\n"));
1334
1405
  console.log(
1335
- `Files Analyzed: ${chalk5.cyan(report.summary.filesAnalyzed)}`
1406
+ `Files Analyzed: ${chalk6.cyan(report.summary.filesAnalyzed)}`
1336
1407
  );
1337
- console.log(`Total Issues: ${chalk5.yellow(report.summary.totalIssues)}`);
1338
- console.log(` Naming: ${chalk5.yellow(report.summary.namingIssues)}`);
1339
- console.log(` Patterns: ${chalk5.yellow(report.summary.patternIssues)}`);
1408
+ console.log(`Total Issues: ${chalk6.yellow(report.summary.totalIssues)}`);
1409
+ console.log(` Naming: ${chalk6.yellow(report.summary.namingIssues)}`);
1410
+ console.log(` Patterns: ${chalk6.yellow(report.summary.patternIssues)}`);
1340
1411
  console.log(
1341
- ` Architecture: ${chalk5.yellow(report.summary.architectureIssues || 0)}`
1412
+ ` Architecture: ${chalk6.yellow(report.summary.architectureIssues || 0)}`
1342
1413
  );
1343
- console.log(`Analysis Time: ${chalk5.gray(elapsedTime + "s")}
1414
+ console.log(`Analysis Time: ${chalk6.gray(elapsedTime + "s")}
1344
1415
  `);
1345
1416
  if (report.summary.totalIssues === 0) {
1346
1417
  console.log(
1347
- chalk5.green(
1418
+ chalk6.green(
1348
1419
  "\u2728 No consistency issues found! Your codebase is well-maintained.\n"
1349
1420
  )
1350
1421
  );
@@ -1356,20 +1427,20 @@ async function consistencyAction(directory, options) {
1356
1427
  (r) => r.issues.some((i) => i.category === "patterns")
1357
1428
  );
1358
1429
  if (namingResults.length > 0) {
1359
- console.log(chalk5.bold("\u{1F3F7}\uFE0F Naming Issues\n"));
1430
+ console.log(chalk6.bold("\u{1F3F7}\uFE0F Naming Issues\n"));
1360
1431
  let shown = 0;
1361
1432
  for (const result of namingResults) {
1362
1433
  if (shown >= 5) break;
1363
1434
  for (const issue of result.issues) {
1364
1435
  if (shown >= 5) break;
1365
- const severityColor = issue.severity === "critical" ? chalk5.red : issue.severity === "major" ? chalk5.yellow : issue.severity === "minor" ? chalk5.blue : chalk5.gray;
1436
+ const severityColor = issue.severity === "critical" ? chalk6.red : issue.severity === "major" ? chalk6.yellow : issue.severity === "minor" ? chalk6.blue : chalk6.gray;
1366
1437
  console.log(
1367
- `${severityColor(issue.severity.toUpperCase())} ${chalk5.dim(`${issue.location.file}:${issue.location.line}`)}`
1438
+ `${severityColor(issue.severity.toUpperCase())} ${chalk6.dim(`${issue.location.file}:${issue.location.line}`)}`
1368
1439
  );
1369
1440
  console.log(` ${issue.message}`);
1370
1441
  if (issue.suggestion) {
1371
1442
  console.log(
1372
- ` ${chalk5.dim("\u2192")} ${chalk5.italic(issue.suggestion)}`
1443
+ ` ${chalk6.dim("\u2192")} ${chalk6.italic(issue.suggestion)}`
1373
1444
  );
1374
1445
  }
1375
1446
  console.log();
@@ -1378,25 +1449,25 @@ async function consistencyAction(directory, options) {
1378
1449
  }
1379
1450
  const remaining = namingResults.reduce((sum, r) => sum + r.issues.length, 0) - shown;
1380
1451
  if (remaining > 0) {
1381
- console.log(chalk5.dim(` ... and ${remaining} more issues
1452
+ console.log(chalk6.dim(` ... and ${remaining} more issues
1382
1453
  `));
1383
1454
  }
1384
1455
  }
1385
1456
  if (patternResults.length > 0) {
1386
- console.log(chalk5.bold("\u{1F504} Pattern Issues\n"));
1457
+ console.log(chalk6.bold("\u{1F504} Pattern Issues\n"));
1387
1458
  let shown = 0;
1388
1459
  for (const result of patternResults) {
1389
1460
  if (shown >= 5) break;
1390
1461
  for (const issue of result.issues) {
1391
1462
  if (shown >= 5) break;
1392
- const severityColor = issue.severity === "critical" ? chalk5.red : issue.severity === "major" ? chalk5.yellow : issue.severity === "minor" ? chalk5.blue : chalk5.gray;
1463
+ const severityColor = issue.severity === "critical" ? chalk6.red : issue.severity === "major" ? chalk6.yellow : issue.severity === "minor" ? chalk6.blue : chalk6.gray;
1393
1464
  console.log(
1394
- `${severityColor(issue.severity.toUpperCase())} ${chalk5.dim(`${issue.location.file}:${issue.location.line}`)}`
1465
+ `${severityColor(issue.severity.toUpperCase())} ${chalk6.dim(`${issue.location.file}:${issue.location.line}`)}`
1395
1466
  );
1396
1467
  console.log(` ${issue.message}`);
1397
1468
  if (issue.suggestion) {
1398
1469
  console.log(
1399
- ` ${chalk5.dim("\u2192")} ${chalk5.italic(issue.suggestion)}`
1470
+ ` ${chalk6.dim("\u2192")} ${chalk6.italic(issue.suggestion)}`
1400
1471
  );
1401
1472
  }
1402
1473
  console.log();
@@ -1405,12 +1476,12 @@ async function consistencyAction(directory, options) {
1405
1476
  }
1406
1477
  const remaining = patternResults.reduce((sum, r) => sum + r.issues.length, 0) - shown;
1407
1478
  if (remaining > 0) {
1408
- console.log(chalk5.dim(` ... and ${remaining} more issues
1479
+ console.log(chalk6.dim(` ... and ${remaining} more issues
1409
1480
  `));
1410
1481
  }
1411
1482
  }
1412
1483
  if (report.recommendations.length > 0) {
1413
- console.log(chalk5.bold("\u{1F4A1} Recommendations\n"));
1484
+ console.log(chalk6.bold("\u{1F4A1} Recommendations\n"));
1414
1485
  report.recommendations.forEach((rec, i) => {
1415
1486
  console.log(`${i + 1}. ${rec}`);
1416
1487
  });
@@ -1418,38 +1489,38 @@ async function consistencyAction(directory, options) {
1418
1489
  }
1419
1490
  }
1420
1491
  if (consistencyScore) {
1421
- console.log(chalk5.bold("\n\u{1F4CA} AI Readiness Score (Consistency)\n"));
1492
+ console.log(chalk6.bold("\n\u{1F4CA} AI Readiness Score (Consistency)\n"));
1422
1493
  console.log(formatToolScore4(consistencyScore));
1423
1494
  console.log();
1424
1495
  }
1425
1496
  }
1426
1497
  } catch (error) {
1427
- handleCLIError4(error, "Consistency analysis");
1498
+ handleCLIError5(error, "Consistency analysis");
1428
1499
  }
1429
1500
  }
1430
1501
 
1431
1502
  // src/commands/visualize.ts
1432
- import chalk6 from "chalk";
1503
+ import chalk7 from "chalk";
1433
1504
  import { writeFileSync as writeFileSync3, readFileSync as readFileSync3, existsSync as existsSync2, copyFileSync } from "fs";
1434
- import { resolve as resolvePath6 } from "path";
1505
+ import { resolve as resolvePath7 } from "path";
1435
1506
  import { spawn } from "child_process";
1436
- import { handleCLIError as handleCLIError5 } from "@aiready/core";
1507
+ import { handleCLIError as handleCLIError6 } from "@aiready/core";
1437
1508
  import { generateHTML } from "@aiready/core";
1438
1509
  async function visualizeAction(directory, options) {
1439
1510
  try {
1440
- const dirPath = resolvePath6(process.cwd(), directory || ".");
1441
- let reportPath = options.report ? resolvePath6(dirPath, options.report) : null;
1511
+ const dirPath = resolvePath7(process.cwd(), directory || ".");
1512
+ let reportPath = options.report ? resolvePath7(dirPath, options.report) : null;
1442
1513
  if (!reportPath || !existsSync2(reportPath)) {
1443
1514
  const latestScan = findLatestScanReport(dirPath);
1444
1515
  if (latestScan) {
1445
1516
  reportPath = latestScan;
1446
1517
  console.log(
1447
- chalk6.dim(`Found latest report: ${latestScan.split("/").pop()}`)
1518
+ chalk7.dim(`Found latest report: ${latestScan.split("/").pop()}`)
1448
1519
  );
1449
1520
  } else {
1450
- console.error(chalk6.red("\u274C No AI readiness report found"));
1521
+ console.error(chalk7.red("\u274C No AI readiness report found"));
1451
1522
  console.log(
1452
- chalk6.dim(
1523
+ chalk7.dim(
1453
1524
  `
1454
1525
  Generate a report with:
1455
1526
  aiready scan --output json
@@ -1463,7 +1534,7 @@ Or specify a custom report:
1463
1534
  }
1464
1535
  const raw = readFileSync3(reportPath, "utf8");
1465
1536
  const report = JSON.parse(raw);
1466
- const configPath = resolvePath6(dirPath, "aiready.json");
1537
+ const configPath = resolvePath7(dirPath, "aiready.json");
1467
1538
  let graphConfig = { maxNodes: 400, maxEdges: 600 };
1468
1539
  if (existsSync2(configPath)) {
1469
1540
  try {
@@ -1487,7 +1558,7 @@ Or specify a custom report:
1487
1558
  let devServerStarted = false;
1488
1559
  if (useDevMode) {
1489
1560
  try {
1490
- const monorepoWebDir = resolvePath6(dirPath, "packages/visualizer");
1561
+ const monorepoWebDir = resolvePath7(dirPath, "packages/visualizer");
1491
1562
  let webDir = "";
1492
1563
  let visualizerAvailable = false;
1493
1564
  if (existsSync2(monorepoWebDir)) {
@@ -1495,8 +1566,8 @@ Or specify a custom report:
1495
1566
  visualizerAvailable = true;
1496
1567
  } else {
1497
1568
  const nodemodulesLocations = [
1498
- resolvePath6(dirPath, "node_modules", "@aiready", "visualizer"),
1499
- resolvePath6(
1569
+ resolvePath7(dirPath, "node_modules", "@aiready", "visualizer"),
1570
+ resolvePath7(
1500
1571
  process.cwd(),
1501
1572
  "node_modules",
1502
1573
  "@aiready",
@@ -1506,14 +1577,14 @@ Or specify a custom report:
1506
1577
  let currentDir = dirPath;
1507
1578
  while (currentDir !== "/" && currentDir !== ".") {
1508
1579
  nodemodulesLocations.push(
1509
- resolvePath6(currentDir, "node_modules", "@aiready", "visualizer")
1580
+ resolvePath7(currentDir, "node_modules", "@aiready", "visualizer")
1510
1581
  );
1511
- const parent = resolvePath6(currentDir, "..");
1582
+ const parent = resolvePath7(currentDir, "..");
1512
1583
  if (parent === currentDir) break;
1513
1584
  currentDir = parent;
1514
1585
  }
1515
1586
  for (const location of nodemodulesLocations) {
1516
- if (existsSync2(location) && existsSync2(resolvePath6(location, "package.json"))) {
1587
+ if (existsSync2(location) && existsSync2(resolvePath7(location, "package.json"))) {
1517
1588
  webDir = location;
1518
1589
  visualizerAvailable = true;
1519
1590
  break;
@@ -1522,20 +1593,20 @@ Or specify a custom report:
1522
1593
  if (!visualizerAvailable) {
1523
1594
  try {
1524
1595
  const vizPkgPath = __require.resolve("@aiready/visualizer/package.json");
1525
- webDir = resolvePath6(vizPkgPath, "..");
1596
+ webDir = resolvePath7(vizPkgPath, "..");
1526
1597
  visualizerAvailable = true;
1527
1598
  } catch (err) {
1528
1599
  void err;
1529
1600
  }
1530
1601
  }
1531
1602
  }
1532
- const webViteConfigExists = webDir && existsSync2(resolvePath6(webDir, "web", "vite.config.ts"));
1603
+ const webViteConfigExists = webDir && existsSync2(resolvePath7(webDir, "web", "vite.config.ts"));
1533
1604
  if (visualizerAvailable && webViteConfigExists) {
1534
1605
  const spawnCwd = webDir;
1535
1606
  const { watch } = await import("fs");
1536
1607
  const copyReportToViz = () => {
1537
1608
  try {
1538
- const destPath = resolvePath6(spawnCwd, "web", "report-data.json");
1609
+ const destPath = resolvePath7(spawnCwd, "web", "report-data.json");
1539
1610
  copyFileSync(reportPath, destPath);
1540
1611
  console.log(`\u{1F4CB} Report synced to ${destPath}`);
1541
1612
  } catch (e) {
@@ -1579,19 +1650,19 @@ Or specify a custom report:
1579
1650
  return;
1580
1651
  } else {
1581
1652
  console.log(
1582
- chalk6.yellow(
1653
+ chalk7.yellow(
1583
1654
  "\u26A0\uFE0F Dev server not available (requires local @aiready/visualizer with web assets)."
1584
1655
  )
1585
1656
  );
1586
1657
  console.log(
1587
- chalk6.cyan(" Falling back to static HTML generation...\n")
1658
+ chalk7.cyan(" Falling back to static HTML generation...\n")
1588
1659
  );
1589
1660
  useDevMode = false;
1590
1661
  }
1591
1662
  } catch (err) {
1592
1663
  console.error("Failed to start dev server:", err);
1593
1664
  console.log(
1594
- chalk6.cyan(" Falling back to static HTML generation...\n")
1665
+ chalk7.cyan(" Falling back to static HTML generation...\n")
1595
1666
  );
1596
1667
  useDevMode = false;
1597
1668
  }
@@ -1599,9 +1670,9 @@ Or specify a custom report:
1599
1670
  console.log("Generating HTML...");
1600
1671
  const html = generateHTML(graph);
1601
1672
  const defaultOutput = "visualization.html";
1602
- const outPath = resolvePath6(dirPath, options.output || defaultOutput);
1673
+ const outPath = resolvePath7(dirPath, options.output || defaultOutput);
1603
1674
  writeFileSync3(outPath, html, "utf8");
1604
- console.log(chalk6.green(`\u2705 Visualization written to: ${outPath}`));
1675
+ console.log(chalk7.green(`\u2705 Visualization written to: ${outPath}`));
1605
1676
  if (options.open || options.serve) {
1606
1677
  const opener = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
1607
1678
  if (options.serve) {
@@ -1631,7 +1702,7 @@ Or specify a custom report:
1631
1702
  server.listen(port, () => {
1632
1703
  const addr = `http://localhost:${port}/`;
1633
1704
  console.log(
1634
- chalk6.cyan(`\u{1F310} Local visualization server running at ${addr}`)
1705
+ chalk7.cyan(`\u{1F310} Local visualization server running at ${addr}`)
1635
1706
  );
1636
1707
  spawn(opener, [`"${addr}"`], { shell: true });
1637
1708
  });
@@ -1647,7 +1718,7 @@ Or specify a custom report:
1647
1718
  }
1648
1719
  }
1649
1720
  } catch (err) {
1650
- handleCLIError5(err, "Visualization");
1721
+ handleCLIError6(err, "Visualization");
1651
1722
  }
1652
1723
  }
1653
1724
  var visualizeHelpText = `
@@ -1678,15 +1749,15 @@ NOTES:
1678
1749
  `;
1679
1750
 
1680
1751
  // src/commands/ai-signal-clarity.ts
1681
- import chalk7 from "chalk";
1752
+ import chalk8 from "chalk";
1682
1753
  import { loadConfig, mergeConfigWithDefaults } from "@aiready/core";
1683
1754
 
1684
1755
  // src/commands/agent-grounding.ts
1685
- import chalk8 from "chalk";
1756
+ import chalk9 from "chalk";
1686
1757
  import { loadConfig as loadConfig2, mergeConfigWithDefaults as mergeConfigWithDefaults2 } from "@aiready/core";
1687
1758
 
1688
1759
  // src/commands/testability.ts
1689
- import chalk9 from "chalk";
1760
+ import chalk10 from "chalk";
1690
1761
  import { loadConfig as loadConfig3, mergeConfigWithDefaults as mergeConfigWithDefaults3 } from "@aiready/core";
1691
1762
 
1692
1763
  // src/commands/change-amplification.ts
@@ -1761,7 +1832,7 @@ program.command("scan").description(
1761
1832
  "--fail-on <level>",
1762
1833
  "Fail on issues: critical, major, any",
1763
1834
  "critical"
1764
- ).addHelpText("after", scanHelpText).action(async (directory, options) => {
1835
+ ).option("--api-key <key>", "Platform API key for automatic upload").option("--upload", "Automatically upload results to the platform").option("--server <url>", "Custom platform URL").addHelpText("after", scanHelpText).action(async (directory, options) => {
1765
1836
  await scanAction(directory, options);
1766
1837
  });
1767
1838
  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(
@@ -1842,4 +1913,7 @@ program.command("visualize").description("Generate interactive visualization fro
1842
1913
  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) => {
1843
1914
  await changeAmplificationAction(directory, options);
1844
1915
  });
1916
+ program.command("upload").description("Upload an AIReady report JSON to the platform").argument("<file>", "Report JSON file to upload").option("--api-key <key>", "Platform API key").option("--repo-id <id>", "Platform repository ID (optional)").option("--server <url>", "Custom platform URL").addHelpText("after", uploadHelpText).action(async (file, options) => {
1917
+ await uploadAction(file, options);
1918
+ });
1845
1919
  program.parse();