@aiready/cli 0.9.45 → 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.js CHANGED
@@ -33,12 +33,13 @@ var import_url = require("url");
33
33
  var import_chalk3 = __toESM(require("chalk"));
34
34
  var import_fs3 = require("fs");
35
35
  var import_path3 = require("path");
36
- var import_core2 = require("@aiready/core");
36
+ var import_core3 = require("@aiready/core");
37
37
 
38
38
  // src/index.ts
39
39
  var import_pattern_detect = require("@aiready/pattern-detect");
40
40
  var import_context_analyzer = require("@aiready/context-analyzer");
41
41
  var import_consistency = require("@aiready/consistency");
42
+ var import_core = require("@aiready/core");
42
43
  var severityOrder = {
43
44
  critical: 4,
44
45
  major: 3,
@@ -213,6 +214,150 @@ async function analyzeUnified(options) {
213
214
  result.summary.executionTime = Date.now() - startTime;
214
215
  return result;
215
216
  }
217
+ async function scoreUnified(results, options) {
218
+ const toolScores = /* @__PURE__ */ new Map();
219
+ if (results.duplicates) {
220
+ const { calculatePatternScore } = await import("@aiready/pattern-detect");
221
+ try {
222
+ const patternScore = calculatePatternScore(
223
+ results.duplicates,
224
+ results.patterns?.length || 0
225
+ );
226
+ const wastedTokens = results.duplicates.reduce(
227
+ (sum, d) => sum + (d.tokenCost || 0),
228
+ 0
229
+ );
230
+ patternScore.tokenBudget = (0, import_core.calculateTokenBudget)({
231
+ totalContextTokens: wastedTokens * 2,
232
+ // Estimated context
233
+ wastedTokens: {
234
+ duplication: wastedTokens,
235
+ fragmentation: 0,
236
+ chattiness: 0
237
+ }
238
+ });
239
+ toolScores.set("pattern-detect", patternScore);
240
+ } catch (err) {
241
+ void err;
242
+ }
243
+ }
244
+ if (results.context) {
245
+ const { generateSummary: genContextSummary, calculateContextScore } = await import("@aiready/context-analyzer");
246
+ try {
247
+ const ctxSummary = genContextSummary(results.context);
248
+ const contextScore = calculateContextScore(ctxSummary);
249
+ contextScore.tokenBudget = (0, import_core.calculateTokenBudget)({
250
+ totalContextTokens: ctxSummary.totalTokens,
251
+ wastedTokens: {
252
+ duplication: 0,
253
+ fragmentation: ctxSummary.totalPotentialSavings || 0,
254
+ chattiness: 0
255
+ }
256
+ });
257
+ toolScores.set("context-analyzer", contextScore);
258
+ } catch (err) {
259
+ void err;
260
+ }
261
+ }
262
+ if (results.consistency) {
263
+ const { calculateConsistencyScore } = await import("@aiready/consistency");
264
+ try {
265
+ const issues = results.consistency.results?.flatMap((r) => r.issues) || [];
266
+ const totalFiles = results.consistency.summary?.filesAnalyzed || 0;
267
+ const consistencyScore = calculateConsistencyScore(issues, totalFiles);
268
+ toolScores.set("consistency", consistencyScore);
269
+ } catch (err) {
270
+ void err;
271
+ }
272
+ }
273
+ if (results.aiSignalClarity) {
274
+ const { calculateAiSignalClarityScore } = await import("@aiready/ai-signal-clarity");
275
+ try {
276
+ const hrScore = calculateAiSignalClarityScore(results.aiSignalClarity);
277
+ toolScores.set("ai-signal-clarity", hrScore);
278
+ } catch (err) {
279
+ void err;
280
+ }
281
+ }
282
+ if (results.grounding) {
283
+ const { calculateGroundingScore } = await import("@aiready/agent-grounding");
284
+ try {
285
+ const agScore = calculateGroundingScore(results.grounding);
286
+ toolScores.set("agent-grounding", agScore);
287
+ } catch (err) {
288
+ void err;
289
+ }
290
+ }
291
+ if (results.testability) {
292
+ const { calculateTestabilityScore } = await import("@aiready/testability");
293
+ try {
294
+ const tbScore = calculateTestabilityScore(results.testability);
295
+ toolScores.set("testability", tbScore);
296
+ } catch (err) {
297
+ void err;
298
+ }
299
+ }
300
+ if (results.docDrift) {
301
+ toolScores.set("doc-drift", {
302
+ toolName: "doc-drift",
303
+ score: results.docDrift.summary.score,
304
+ rawMetrics: results.docDrift.rawData,
305
+ factors: [],
306
+ recommendations: (results.docDrift.recommendations || []).map(
307
+ (action) => ({
308
+ action,
309
+ estimatedImpact: 5,
310
+ priority: "medium"
311
+ })
312
+ )
313
+ });
314
+ }
315
+ if (results.deps) {
316
+ toolScores.set("dependency-health", {
317
+ toolName: "dependency-health",
318
+ score: results.deps.summary.score,
319
+ rawMetrics: results.deps.rawData,
320
+ factors: [],
321
+ recommendations: (results.deps.recommendations || []).map(
322
+ (action) => ({
323
+ action,
324
+ estimatedImpact: 5,
325
+ priority: "medium"
326
+ })
327
+ )
328
+ });
329
+ }
330
+ if (results.changeAmplification) {
331
+ toolScores.set("change-amplification", {
332
+ toolName: "change-amplification",
333
+ score: results.changeAmplification.summary.score,
334
+ rawMetrics: results.changeAmplification.rawData,
335
+ factors: [],
336
+ recommendations: (results.changeAmplification.recommendations || []).map(
337
+ (action) => ({
338
+ action,
339
+ estimatedImpact: 5,
340
+ priority: "medium"
341
+ })
342
+ )
343
+ });
344
+ }
345
+ if (toolScores.size === 0) {
346
+ return {
347
+ overall: 0,
348
+ rating: "Critical",
349
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
350
+ toolsUsed: [],
351
+ breakdown: [],
352
+ calculation: {
353
+ formula: "0 / 0 = 0",
354
+ weights: {},
355
+ normalized: "0 / 0 = 0"
356
+ }
357
+ };
358
+ }
359
+ return (0, import_core.calculateOverallScore)(toolScores, options, void 0);
360
+ }
216
361
 
217
362
  // src/utils/helpers.ts
218
363
  var import_path = require("path");
@@ -342,7 +487,7 @@ function truncateArray(arr, cap = 8) {
342
487
  var import_fs2 = __toESM(require("fs"));
343
488
  var import_path2 = require("path");
344
489
  var import_chalk2 = __toESM(require("chalk"));
345
- var import_core = require("@aiready/core");
490
+ var import_core2 = require("@aiready/core");
346
491
  async function uploadAction(file, options) {
347
492
  const startTime = Date.now();
348
493
  const filePath = (0, import_path2.resolve)(process.cwd(), file);
@@ -350,8 +495,14 @@ async function uploadAction(file, options) {
350
495
  const apiKey = options.apiKey || process.env.AIREADY_API_KEY;
351
496
  if (!apiKey) {
352
497
  console.error(import_chalk2.default.red("\u274C API Key is required for upload."));
353
- console.log(import_chalk2.default.dim(" Set AIREADY_API_KEY environment variable or use --api-key flag."));
354
- console.log(import_chalk2.default.dim(" Get an API key from https://getaiready.dev/dashboard"));
498
+ console.log(
499
+ import_chalk2.default.dim(
500
+ " Set AIREADY_API_KEY environment variable or use --api-key flag."
501
+ )
502
+ );
503
+ console.log(
504
+ import_chalk2.default.dim(" Get an API key from https://getaiready.dev/dashboard")
505
+ );
355
506
  process.exit(1);
356
507
  }
357
508
  if (!import_fs2.default.existsSync(filePath)) {
@@ -360,13 +511,16 @@ async function uploadAction(file, options) {
360
511
  }
361
512
  try {
362
513
  console.log(import_chalk2.default.blue(`\u{1F680} Uploading report to ${serverUrl}...`));
363
- const reportData = JSON.parse(import_fs2.default.readFileSync(filePath, "utf-8"));
514
+ console.log(import_chalk2.default.dim(` Reading report from ${filePath}...`));
515
+ const reportContent = import_fs2.default.readFileSync(filePath, "utf-8");
516
+ const reportData = JSON.parse(reportContent);
517
+ console.log(import_chalk2.default.dim(` Successfully parsed report JSON.`));
364
518
  const repoId = options.repoId || reportData.repository?.repoId;
365
519
  const res = await fetch(`${serverUrl}/api/analysis/upload`, {
366
520
  method: "POST",
367
521
  headers: {
368
522
  "Content-Type": "application/json",
369
- "Authorization": `Bearer ${apiKey}`
523
+ Authorization: `Bearer ${apiKey}`
370
524
  },
371
525
  body: JSON.stringify({
372
526
  data: reportData,
@@ -374,11 +528,36 @@ async function uploadAction(file, options) {
374
528
  // Might be null, server will handle mapping
375
529
  })
376
530
  });
377
- const result = await res.json();
531
+ const contentType = res.headers.get("content-type");
532
+ let result = {};
533
+ if (contentType?.includes("application/json")) {
534
+ result = await res.json();
535
+ } else {
536
+ const text = await res.text();
537
+ result = { error: text || res.statusText };
538
+ }
378
539
  if (!res.ok) {
379
- console.error(import_chalk2.default.red(`\u274C Upload failed: ${result.error || res.statusText}`));
540
+ console.error(
541
+ import_chalk2.default.red(`\u274C Upload failed: ${result.error || res.statusText}`)
542
+ );
543
+ if (contentType?.includes("text/html")) {
544
+ console.log(
545
+ import_chalk2.default.yellow(
546
+ " Note: Received an HTML response. This often indicates a redirect (e.g., to a login page) or a server error."
547
+ )
548
+ );
549
+ if (result.error?.includes("Redirecting")) {
550
+ console.log(
551
+ import_chalk2.default.dim(
552
+ " Detected redirect. Check if the API endpoint requires authentication or has changed."
553
+ )
554
+ );
555
+ }
556
+ }
380
557
  if (res.status === 401) {
381
- console.log(import_chalk2.default.dim(" Hint: Your API key may be invalid or expired."));
558
+ console.log(
559
+ import_chalk2.default.dim(" Hint: Your API key may be invalid or expired.")
560
+ );
382
561
  }
383
562
  process.exit(1);
384
563
  }
@@ -391,7 +570,7 @@ async function uploadAction(file, options) {
391
570
  console.log(import_chalk2.default.dim(` Score: ${result.analysis.aiScore}/100`));
392
571
  }
393
572
  } catch (error) {
394
- (0, import_core.handleCLIError)(error, "Upload");
573
+ (0, import_core2.handleCLIError)(error, "Upload");
395
574
  }
396
575
  }
397
576
  var uploadHelpText = `
@@ -410,7 +589,7 @@ async function scanAction(directory, options) {
410
589
  console.log(import_chalk3.default.blue("\u{1F680} Starting AIReady unified analysis...\n"));
411
590
  const startTime = Date.now();
412
591
  const resolvedDir = (0, import_path3.resolve)(process.cwd(), directory || ".");
413
- const repoMetadata = (0, import_core2.getRepoMetadata)(resolvedDir);
592
+ const repoMetadata = (0, import_core3.getRepoMetadata)(resolvedDir);
414
593
  try {
415
594
  const defaults = {
416
595
  tools: [
@@ -467,7 +646,7 @@ async function scanAction(directory, options) {
467
646
  if (profileTools) {
468
647
  cliOverrides.tools = profileTools;
469
648
  }
470
- const baseOptions = await (0, import_core2.loadMergedConfig)(
649
+ const baseOptions = await (0, import_core3.loadMergedConfig)(
471
650
  resolvedDir,
472
651
  defaults,
473
652
  cliOverrides
@@ -782,250 +961,140 @@ async function scanAction(directory, options) {
782
961
  ` Change amplification: ${import_chalk3.default.bold(String(results.changeAmplification.summary?.score || 0))}/100`
783
962
  );
784
963
  console.log(import_chalk3.default.cyan("===========================\n"));
785
- const elapsedTime = (0, import_core2.getElapsedTime)(startTime);
964
+ const elapsedTime = (0, import_core3.getElapsedTime)(startTime);
786
965
  void elapsedTime;
787
966
  let scoringResult;
788
967
  if (options.score || finalOptions.scoring?.showBreakdown) {
789
- const toolScores = /* @__PURE__ */ new Map();
790
- if (results.duplicates) {
791
- const { calculatePatternScore } = await import("@aiready/pattern-detect");
968
+ scoringResult = await scoreUnified(results, finalOptions);
969
+ console.log(import_chalk3.default.bold("\n\u{1F4CA} AI Readiness Overall Score"));
970
+ console.log(` ${(0, import_core3.formatScore)(scoringResult)}`);
971
+ if (options.compareTo) {
792
972
  try {
793
- const patternScore = calculatePatternScore(
794
- results.duplicates,
795
- results.patterns?.length || 0
973
+ const prevReportStr = (0, import_fs3.readFileSync)(
974
+ (0, import_path3.resolve)(process.cwd(), options.compareTo),
975
+ "utf8"
796
976
  );
797
- const wastedTokens = results.duplicates.reduce((sum, d) => sum + (d.tokenCost || 0), 0);
798
- patternScore.tokenBudget = (0, import_core2.calculateTokenBudget)({
799
- totalContextTokens: wastedTokens * 2,
800
- // Estimated context
801
- wastedTokens: {
802
- duplication: wastedTokens,
803
- fragmentation: 0,
804
- chattiness: 0
805
- }
806
- });
807
- toolScores.set("pattern-detect", patternScore);
808
- } catch (err) {
809
- void err;
810
- }
811
- }
812
- if (results.context) {
813
- const { generateSummary: genContextSummary, calculateContextScore } = await import("@aiready/context-analyzer");
814
- try {
815
- const ctxSummary = genContextSummary(results.context);
816
- const contextScore = calculateContextScore(ctxSummary);
817
- contextScore.tokenBudget = (0, import_core2.calculateTokenBudget)({
818
- totalContextTokens: ctxSummary.totalTokens,
819
- wastedTokens: {
820
- duplication: 0,
821
- fragmentation: ctxSummary.totalPotentialSavings || 0,
822
- chattiness: 0
823
- }
824
- });
825
- toolScores.set("context-analyzer", contextScore);
826
- } catch (err) {
827
- void err;
828
- }
829
- }
830
- if (results.consistency) {
831
- const { calculateConsistencyScore } = await import("@aiready/consistency");
832
- try {
833
- const issues = results.consistency.results?.flatMap((r) => r.issues) || [];
834
- const totalFiles = results.consistency.summary?.filesAnalyzed || 0;
835
- const consistencyScore = calculateConsistencyScore(
836
- issues,
837
- totalFiles
838
- );
839
- toolScores.set("consistency", consistencyScore);
840
- } catch (err) {
841
- void err;
842
- }
843
- }
844
- if (results.aiSignalClarity) {
845
- const { calculateAiSignalClarityScore } = await import("@aiready/ai-signal-clarity");
846
- try {
847
- const hrScore = calculateAiSignalClarityScore(
848
- results.aiSignalClarity
849
- );
850
- toolScores.set("ai-signal-clarity", hrScore);
851
- } catch (err) {
852
- void err;
853
- }
854
- }
855
- if (results.grounding) {
856
- const { calculateGroundingScore } = await import("@aiready/agent-grounding");
857
- try {
858
- const agScore = calculateGroundingScore(results.grounding);
859
- toolScores.set("agent-grounding", agScore);
860
- } catch (err) {
861
- void err;
862
- }
863
- }
864
- if (results.testability) {
865
- const { calculateTestabilityScore } = await import("@aiready/testability");
866
- try {
867
- const tbScore = calculateTestabilityScore(results.testability);
868
- toolScores.set("testability", tbScore);
869
- } catch (err) {
870
- void err;
871
- }
872
- }
873
- if (results.docDrift) {
874
- toolScores.set("doc-drift", {
875
- toolName: "doc-drift",
876
- score: results.docDrift.summary.score,
877
- rawMetrics: results.docDrift.rawData,
878
- factors: [],
879
- recommendations: (results.docDrift.recommendations || []).map(
880
- (action) => ({
881
- action,
882
- estimatedImpact: 5,
883
- priority: "medium"
884
- })
885
- )
886
- });
887
- }
888
- if (results.deps) {
889
- toolScores.set("dependency-health", {
890
- toolName: "dependency-health",
891
- score: results.deps.summary.score,
892
- rawMetrics: results.deps.rawData,
893
- factors: [],
894
- recommendations: (results.deps.recommendations || []).map(
895
- (action) => ({
896
- action,
897
- estimatedImpact: 5,
898
- priority: "medium"
899
- })
900
- )
901
- });
902
- }
903
- if (results.changeAmplification) {
904
- toolScores.set("change-amplification", {
905
- toolName: "change-amplification",
906
- score: results.changeAmplification.summary.score,
907
- rawMetrics: results.changeAmplification.rawData,
908
- factors: [],
909
- recommendations: (results.changeAmplification.recommendations || []).map((action) => ({
910
- action,
911
- estimatedImpact: 5,
912
- priority: "medium"
913
- }))
914
- });
915
- }
916
- const cliWeights = (0, import_core2.parseWeightString)(options.weights);
917
- if (toolScores.size > 0) {
918
- scoringResult = (0, import_core2.calculateOverallScore)(
919
- toolScores,
920
- finalOptions,
921
- cliWeights.size ? cliWeights : void 0
922
- );
923
- console.log(import_chalk3.default.bold("\n\u{1F4CA} AI Readiness Overall Score"));
924
- console.log(` ${(0, import_core2.formatScore)(scoringResult)}`);
925
- if (options.compareTo) {
926
- try {
927
- const prevReportStr = (0, import_fs3.readFileSync)(
928
- (0, import_path3.resolve)(process.cwd(), options.compareTo),
929
- "utf8"
930
- );
931
- const prevReport = JSON.parse(prevReportStr);
932
- const prevScore = prevReport.scoring?.score || prevReport.scoring?.overallScore;
933
- if (typeof prevScore === "number") {
934
- const diff = scoringResult.overall - prevScore;
935
- const diffStr = diff > 0 ? `+${diff}` : String(diff);
936
- console.log();
937
- if (diff > 0) {
938
- console.log(
939
- import_chalk3.default.green(
940
- ` \u{1F4C8} Trend: ${diffStr} compared to ${options.compareTo} (${prevScore} \u2192 ${scoringResult.overall})`
941
- )
942
- );
943
- } else if (diff < 0) {
944
- console.log(
945
- import_chalk3.default.red(
946
- ` \u{1F4C9} Trend: ${diffStr} compared to ${options.compareTo} (${prevScore} \u2192 ${scoringResult.overall})`
947
- )
948
- );
949
- } else {
950
- console.log(
951
- import_chalk3.default.blue(
952
- ` \u2796 Trend: No change compared to ${options.compareTo} (${prevScore} \u2192 ${scoringResult.overall})`
953
- )
954
- );
955
- }
956
- scoringResult.trend = {
957
- previousScore: prevScore,
958
- difference: diff
959
- };
977
+ const prevReport = JSON.parse(prevReportStr);
978
+ const prevScore = prevReport.scoring?.score || prevReport.scoring?.overallScore;
979
+ if (typeof prevScore === "number") {
980
+ const diff = scoringResult.overall - prevScore;
981
+ const diffStr = diff > 0 ? `+${diff}` : String(diff);
982
+ console.log();
983
+ if (diff > 0) {
984
+ console.log(
985
+ import_chalk3.default.green(
986
+ ` \u{1F4C8} Trend: ${diffStr} compared to ${options.compareTo} (${prevScore} \u2192 ${scoringResult.overall})`
987
+ )
988
+ );
989
+ } else if (diff < 0) {
990
+ console.log(
991
+ import_chalk3.default.red(
992
+ ` \u{1F4C9} Trend: ${diffStr} compared to ${options.compareTo} (${prevScore} \u2192 ${scoringResult.overall})`
993
+ )
994
+ );
960
995
  } else {
961
996
  console.log(
962
- import_chalk3.default.yellow(
963
- `
964
- \u26A0\uFE0F Previous report at ${options.compareTo} does not contain an overall score.`
997
+ import_chalk3.default.blue(
998
+ ` \u2796 Trend: No change compared to ${options.compareTo} (${prevScore} \u2192 ${scoringResult.overall})`
965
999
  )
966
1000
  );
967
1001
  }
968
- } catch (e) {
969
- void e;
1002
+ scoringResult.trend = {
1003
+ previousScore: prevScore,
1004
+ difference: diff
1005
+ };
1006
+ } else {
970
1007
  console.log(
971
1008
  import_chalk3.default.yellow(
972
1009
  `
973
- \u26A0\uFE0F Could not read or parse previous report at ${options.compareTo}.`
1010
+ \u26A0\uFE0F Previous report at ${options.compareTo} does not contain an overall score.`
974
1011
  )
975
1012
  );
976
1013
  }
1014
+ } catch (e) {
1015
+ void e;
1016
+ console.log(
1017
+ import_chalk3.default.yellow(
1018
+ `
1019
+ \u26A0\uFE0F Could not read or parse previous report at ${options.compareTo}.`
1020
+ )
1021
+ );
977
1022
  }
978
- const totalWastedDuplication = Array.from(toolScores.values()).reduce((sum, s) => sum + (s.tokenBudget?.wastedTokens.bySource.duplication || 0), 0);
979
- const totalWastedFragmentation = Array.from(toolScores.values()).reduce((sum, s) => sum + (s.tokenBudget?.wastedTokens.bySource.fragmentation || 0), 0);
980
- const totalContext = Math.max(...Array.from(toolScores.values()).map((s) => s.tokenBudget?.totalContextTokens || 0));
981
- if (totalContext > 0) {
982
- const unifiedBudget = (0, import_core2.calculateTokenBudget)({
983
- totalContextTokens: totalContext,
984
- wastedTokens: {
985
- duplication: totalWastedDuplication,
986
- fragmentation: totalWastedFragmentation,
987
- chattiness: 0
988
- }
989
- });
990
- const targetModel = options.model || "claude-4.6";
991
- const modelPreset = (0, import_core2.getModelPreset)(targetModel);
992
- const costEstimate = (0, import_core2.estimateCostFromBudget)(unifiedBudget, modelPreset);
993
- const barWidth = 20;
994
- const filled = Math.round(unifiedBudget.efficiencyRatio * barWidth);
995
- const bar = import_chalk3.default.green("\u2588".repeat(filled)) + import_chalk3.default.dim("\u2591".repeat(barWidth - filled));
996
- console.log(import_chalk3.default.bold("\n\u{1F4CA} AI Token Budget Analysis (v0.13)"));
997
- console.log(` Efficiency: [${bar}] ${(unifiedBudget.efficiencyRatio * 100).toFixed(0)}%`);
998
- console.log(` Total Context: ${import_chalk3.default.bold(unifiedBudget.totalContextTokens.toLocaleString())} tokens`);
999
- console.log(` Wasted Tokens: ${import_chalk3.default.red(unifiedBudget.wastedTokens.total.toLocaleString())} (${(unifiedBudget.wastedTokens.total / unifiedBudget.totalContextTokens * 100).toFixed(1)}%)`);
1000
- console.log(` Waste Breakdown:`);
1001
- console.log(` \u2022 Duplication: ${unifiedBudget.wastedTokens.bySource.duplication.toLocaleString()} tokens`);
1002
- console.log(` \u2022 Fragmentation: ${unifiedBudget.wastedTokens.bySource.fragmentation.toLocaleString()} tokens`);
1003
- console.log(` Potential Savings: ${import_chalk3.default.green(unifiedBudget.potentialRetrievableTokens.toLocaleString())} tokens retrievable`);
1004
- console.log(`
1005
- Est. Monthly Cost (${modelPreset.name}): ${import_chalk3.default.bold("$" + costEstimate.total)} [range: $${costEstimate.range[0]}-$${costEstimate.range[1]}]`);
1006
- scoringResult.tokenBudget = unifiedBudget;
1007
- scoringResult.costEstimate = {
1008
- model: modelPreset.name,
1009
- ...costEstimate
1010
- };
1011
- }
1012
- if (scoringResult.breakdown && scoringResult.breakdown.length > 0) {
1013
- console.log(import_chalk3.default.bold("\nTool breakdown:"));
1023
+ }
1024
+ const totalWastedDuplication = (scoringResult.breakdown || []).reduce(
1025
+ (sum, s) => sum + (s.tokenBudget?.wastedTokens.bySource.duplication || 0),
1026
+ 0
1027
+ );
1028
+ const totalWastedFragmentation = (scoringResult.breakdown || []).reduce(
1029
+ (sum, s) => sum + (s.tokenBudget?.wastedTokens.bySource.fragmentation || 0),
1030
+ 0
1031
+ );
1032
+ const totalContext = Math.max(
1033
+ ...(scoringResult.breakdown || []).map(
1034
+ (s) => s.tokenBudget?.totalContextTokens || 0
1035
+ )
1036
+ );
1037
+ if (totalContext > 0) {
1038
+ const unifiedBudget = (0, import_core3.calculateTokenBudget)({
1039
+ totalContextTokens: totalContext,
1040
+ wastedTokens: {
1041
+ duplication: totalWastedDuplication,
1042
+ fragmentation: totalWastedFragmentation,
1043
+ chattiness: 0
1044
+ }
1045
+ });
1046
+ const targetModel = options.model || "claude-4.6";
1047
+ const modelPreset = (0, import_core3.getModelPreset)(targetModel);
1048
+ const costEstimate = (0, import_core3.estimateCostFromBudget)(unifiedBudget, modelPreset);
1049
+ const barWidth = 20;
1050
+ const filled = Math.round(unifiedBudget.efficiencyRatio * barWidth);
1051
+ const bar = import_chalk3.default.green("\u2588".repeat(filled)) + import_chalk3.default.dim("\u2591".repeat(barWidth - filled));
1052
+ console.log(import_chalk3.default.bold("\n\u{1F4CA} AI Token Budget Analysis (v0.13)"));
1053
+ console.log(
1054
+ ` Efficiency: [${bar}] ${(unifiedBudget.efficiencyRatio * 100).toFixed(0)}%`
1055
+ );
1056
+ console.log(
1057
+ ` Total Context: ${import_chalk3.default.bold(unifiedBudget.totalContextTokens.toLocaleString())} tokens`
1058
+ );
1059
+ console.log(
1060
+ ` Wasted Tokens: ${import_chalk3.default.red(unifiedBudget.wastedTokens.total.toLocaleString())} (${(unifiedBudget.wastedTokens.total / unifiedBudget.totalContextTokens * 100).toFixed(1)}%)`
1061
+ );
1062
+ console.log(` Waste Breakdown:`);
1063
+ console.log(
1064
+ ` \u2022 Duplication: ${unifiedBudget.wastedTokens.bySource.duplication.toLocaleString()} tokens`
1065
+ );
1066
+ console.log(
1067
+ ` \u2022 Fragmentation: ${unifiedBudget.wastedTokens.bySource.fragmentation.toLocaleString()} tokens`
1068
+ );
1069
+ console.log(
1070
+ ` Potential Savings: ${import_chalk3.default.green(unifiedBudget.potentialRetrievableTokens.toLocaleString())} tokens retrievable`
1071
+ );
1072
+ console.log(
1073
+ `
1074
+ Est. Monthly Cost (${modelPreset.name}): ${import_chalk3.default.bold("$" + costEstimate.total)} [range: $${costEstimate.range[0]}-$${costEstimate.range[1]}]`
1075
+ );
1076
+ scoringResult.tokenBudget = unifiedBudget;
1077
+ scoringResult.costEstimate = {
1078
+ model: modelPreset.name,
1079
+ ...costEstimate
1080
+ };
1081
+ }
1082
+ if (scoringResult.breakdown && scoringResult.breakdown.length > 0) {
1083
+ console.log(import_chalk3.default.bold("\nTool breakdown:"));
1084
+ scoringResult.breakdown.forEach((tool) => {
1085
+ const rating = (0, import_core3.getRating)(tool.score);
1086
+ const rd = (0, import_core3.getRatingDisplay)(rating);
1087
+ console.log(
1088
+ ` - ${tool.toolName}: ${tool.score}/100 (${rating}) ${rd.emoji}`
1089
+ );
1090
+ });
1091
+ console.log();
1092
+ if (finalOptions.scoring?.showBreakdown) {
1093
+ console.log(import_chalk3.default.bold("Detailed tool breakdown:"));
1014
1094
  scoringResult.breakdown.forEach((tool) => {
1015
- const rating = (0, import_core2.getRating)(tool.score);
1016
- const rd = (0, import_core2.getRatingDisplay)(rating);
1017
- console.log(
1018
- ` - ${tool.toolName}: ${tool.score}/100 (${rating}) ${rd.emoji}`
1019
- );
1095
+ console.log((0, import_core3.formatToolScore)(tool));
1020
1096
  });
1021
1097
  console.log();
1022
- if (finalOptions.scoring?.showBreakdown) {
1023
- console.log(import_chalk3.default.bold("Detailed tool breakdown:"));
1024
- scoringResult.breakdown.forEach((tool) => {
1025
- console.log((0, import_core2.formatToolScore)(tool));
1026
- });
1027
- console.log();
1028
- }
1029
1098
  }
1030
1099
  }
1031
1100
  }
@@ -1034,7 +1103,7 @@ async function scanAction(directory, options) {
1034
1103
  if (outputFormat === "json") {
1035
1104
  const timestamp = getReportTimestamp();
1036
1105
  const defaultFilename = `aiready-report-${timestamp}.json`;
1037
- const outputPath = (0, import_core2.resolveOutputPath)(
1106
+ const outputPath = (0, import_core3.resolveOutputPath)(
1038
1107
  userOutputFile,
1039
1108
  defaultFilename,
1040
1109
  resolvedDir
@@ -1044,7 +1113,7 @@ async function scanAction(directory, options) {
1044
1113
  scoring: scoringResult,
1045
1114
  repository: repoMetadata
1046
1115
  };
1047
- (0, import_core2.handleJSONOutput)(
1116
+ (0, import_core3.handleJSONOutput)(
1048
1117
  outputData,
1049
1118
  outputPath,
1050
1119
  `\u2705 Report saved to ${outputPath}`
@@ -1060,7 +1129,7 @@ async function scanAction(directory, options) {
1060
1129
  } else {
1061
1130
  const timestamp = getReportTimestamp();
1062
1131
  const defaultFilename = `aiready-report-${timestamp}.json`;
1063
- const outputPath = (0, import_core2.resolveOutputPath)(
1132
+ const outputPath = (0, import_core3.resolveOutputPath)(
1064
1133
  userOutputFile,
1065
1134
  defaultFilename,
1066
1135
  resolvedDir
@@ -1191,7 +1260,7 @@ async function scanAction(directory, options) {
1191
1260
  }
1192
1261
  }
1193
1262
  } catch (error) {
1194
- (0, import_core2.handleCLIError)(error, "Analysis");
1263
+ (0, import_core3.handleCLIError)(error, "Analysis");
1195
1264
  }
1196
1265
  }
1197
1266
  var scanHelpText = `
@@ -1228,7 +1297,7 @@ CI/CD INTEGRATION (Gatekeeper Mode):
1228
1297
  // src/commands/patterns.ts
1229
1298
  var import_chalk4 = __toESM(require("chalk"));
1230
1299
  var import_path4 = require("path");
1231
- var import_core3 = require("@aiready/core");
1300
+ var import_core4 = require("@aiready/core");
1232
1301
  async function patternsAction(directory, options) {
1233
1302
  console.log(import_chalk4.default.blue("\u{1F50D} Analyzing patterns...\n"));
1234
1303
  const startTime = Date.now();
@@ -1261,14 +1330,14 @@ async function patternsAction(directory, options) {
1261
1330
  if (options.minSharedTokens) {
1262
1331
  cliOptions.minSharedTokens = parseInt(options.minSharedTokens);
1263
1332
  }
1264
- const finalOptions = await (0, import_core3.loadMergedConfig)(
1333
+ const finalOptions = await (0, import_core4.loadMergedConfig)(
1265
1334
  resolvedDir,
1266
1335
  defaults,
1267
1336
  cliOptions
1268
1337
  );
1269
1338
  const { analyzePatterns: analyzePatterns2, generateSummary, calculatePatternScore } = await import("@aiready/pattern-detect");
1270
1339
  const { results, duplicates } = await analyzePatterns2(finalOptions);
1271
- const elapsedTime = (0, import_core3.getElapsedTime)(startTime);
1340
+ const elapsedTime = (0, import_core4.getElapsedTime)(startTime);
1272
1341
  const summary = generateSummary(results);
1273
1342
  let patternScore;
1274
1343
  if (options.score) {
@@ -1282,12 +1351,12 @@ async function patternsAction(directory, options) {
1282
1351
  summary: { ...summary, executionTime: parseFloat(elapsedTime) },
1283
1352
  ...patternScore && { scoring: patternScore }
1284
1353
  };
1285
- const outputPath = (0, import_core3.resolveOutputPath)(
1354
+ const outputPath = (0, import_core4.resolveOutputPath)(
1286
1355
  userOutputFile,
1287
1356
  `aiready-report-${getReportTimestamp()}.json`,
1288
1357
  resolvedDir
1289
1358
  );
1290
- (0, import_core3.handleJSONOutput)(
1359
+ (0, import_core4.handleJSONOutput)(
1291
1360
  outputData,
1292
1361
  outputPath,
1293
1362
  `\u2705 Results saved to ${outputPath}`
@@ -1354,12 +1423,12 @@ async function patternsAction(directory, options) {
1354
1423
  console.log(import_chalk4.default.cyan(divider));
1355
1424
  console.log(import_chalk4.default.bold.white(" AI READINESS SCORE (Patterns)"));
1356
1425
  console.log(import_chalk4.default.cyan(divider) + "\n");
1357
- console.log((0, import_core3.formatToolScore)(patternScore));
1426
+ console.log((0, import_core4.formatToolScore)(patternScore));
1358
1427
  console.log();
1359
1428
  }
1360
1429
  }
1361
1430
  } catch (error) {
1362
- (0, import_core3.handleCLIError)(error, "Pattern analysis");
1431
+ (0, import_core4.handleCLIError)(error, "Pattern analysis");
1363
1432
  }
1364
1433
  }
1365
1434
  var patternsHelpText = `
@@ -1372,7 +1441,7 @@ EXAMPLES:
1372
1441
  // src/commands/context.ts
1373
1442
  var import_chalk5 = __toESM(require("chalk"));
1374
1443
  var import_path5 = require("path");
1375
- var import_core4 = require("@aiready/core");
1444
+ var import_core5 = require("@aiready/core");
1376
1445
  async function contextAction(directory, options) {
1377
1446
  console.log(import_chalk5.default.blue("\u{1F9E0} Analyzing context costs...\n"));
1378
1447
  const startTime = Date.now();
@@ -1388,7 +1457,7 @@ async function contextAction(directory, options) {
1388
1457
  file: void 0
1389
1458
  }
1390
1459
  };
1391
- const baseOptions = await (0, import_core4.loadMergedConfig)(resolvedDir, defaults, {
1460
+ const baseOptions = await (0, import_core5.loadMergedConfig)(resolvedDir, defaults, {
1392
1461
  maxDepth: options.maxDepth ? parseInt(options.maxDepth) : void 0,
1393
1462
  maxContextBudget: options.maxContext ? parseInt(options.maxContext) : void 0,
1394
1463
  include: options.include?.split(","),
@@ -1414,7 +1483,7 @@ async function contextAction(directory, options) {
1414
1483
  console.log("");
1415
1484
  const { analyzeContext: analyzeContext2, generateSummary, calculateContextScore } = await import("@aiready/context-analyzer");
1416
1485
  const results = await analyzeContext2(finalOptions);
1417
- const elapsedTime = (0, import_core4.getElapsedTime)(startTime);
1486
+ const elapsedTime = (0, import_core5.getElapsedTime)(startTime);
1418
1487
  const summary = generateSummary(results);
1419
1488
  let contextScore;
1420
1489
  if (options.score) {
@@ -1428,12 +1497,12 @@ async function contextAction(directory, options) {
1428
1497
  summary: { ...summary, executionTime: parseFloat(elapsedTime) },
1429
1498
  ...contextScore && { scoring: contextScore }
1430
1499
  };
1431
- const outputPath = (0, import_core4.resolveOutputPath)(
1500
+ const outputPath = (0, import_core5.resolveOutputPath)(
1432
1501
  userOutputFile,
1433
1502
  `aiready-report-${getReportTimestamp()}.json`,
1434
1503
  resolvedDir
1435
1504
  );
1436
- (0, import_core4.handleJSONOutput)(
1505
+ (0, import_core5.handleJSONOutput)(
1437
1506
  outputData,
1438
1507
  outputPath,
1439
1508
  `\u2705 Results saved to ${outputPath}`
@@ -1560,12 +1629,12 @@ async function contextAction(directory, options) {
1560
1629
  console.log(import_chalk5.default.cyan(divider));
1561
1630
  console.log(import_chalk5.default.bold.white(" AI READINESS SCORE (Context)"));
1562
1631
  console.log(import_chalk5.default.cyan(divider) + "\n");
1563
- console.log((0, import_core4.formatToolScore)(contextScore));
1632
+ console.log((0, import_core5.formatToolScore)(contextScore));
1564
1633
  console.log();
1565
1634
  }
1566
1635
  }
1567
1636
  } catch (error) {
1568
- (0, import_core4.handleCLIError)(error, "Context analysis");
1637
+ (0, import_core5.handleCLIError)(error, "Context analysis");
1569
1638
  }
1570
1639
  }
1571
1640
 
@@ -1573,7 +1642,7 @@ async function contextAction(directory, options) {
1573
1642
  var import_chalk6 = __toESM(require("chalk"));
1574
1643
  var import_fs4 = require("fs");
1575
1644
  var import_path6 = require("path");
1576
- var import_core5 = require("@aiready/core");
1645
+ var import_core6 = require("@aiready/core");
1577
1646
  async function consistencyAction(directory, options) {
1578
1647
  console.log(import_chalk6.default.blue("\u{1F50D} Analyzing consistency...\n"));
1579
1648
  const startTime = Date.now();
@@ -1590,7 +1659,7 @@ async function consistencyAction(directory, options) {
1590
1659
  file: void 0
1591
1660
  }
1592
1661
  };
1593
- const finalOptions = await (0, import_core5.loadMergedConfig)(resolvedDir, defaults, {
1662
+ const finalOptions = await (0, import_core6.loadMergedConfig)(resolvedDir, defaults, {
1594
1663
  checkNaming: options.naming !== false,
1595
1664
  checkPatterns: options.patterns !== false,
1596
1665
  minSeverity: options.minSeverity,
@@ -1599,7 +1668,7 @@ async function consistencyAction(directory, options) {
1599
1668
  });
1600
1669
  const { analyzeConsistency: analyzeConsistency2, calculateConsistencyScore } = await import("@aiready/consistency");
1601
1670
  const report = await analyzeConsistency2(finalOptions);
1602
- const elapsedTime = (0, import_core5.getElapsedTime)(startTime);
1671
+ const elapsedTime = (0, import_core6.getElapsedTime)(startTime);
1603
1672
  let consistencyScore;
1604
1673
  if (options.score) {
1605
1674
  const issues = report.results?.flatMap((r) => r.issues) || [];
@@ -1619,19 +1688,19 @@ async function consistencyAction(directory, options) {
1619
1688
  },
1620
1689
  ...consistencyScore && { scoring: consistencyScore }
1621
1690
  };
1622
- const outputPath = (0, import_core5.resolveOutputPath)(
1691
+ const outputPath = (0, import_core6.resolveOutputPath)(
1623
1692
  userOutputFile,
1624
1693
  `aiready-report-${getReportTimestamp()}.json`,
1625
1694
  resolvedDir
1626
1695
  );
1627
- (0, import_core5.handleJSONOutput)(
1696
+ (0, import_core6.handleJSONOutput)(
1628
1697
  outputData,
1629
1698
  outputPath,
1630
1699
  `\u2705 Results saved to ${outputPath}`
1631
1700
  );
1632
1701
  } else if (outputFormat === "markdown") {
1633
1702
  const markdown = generateMarkdownReport(report, elapsedTime);
1634
- const outputPath = (0, import_core5.resolveOutputPath)(
1703
+ const outputPath = (0, import_core6.resolveOutputPath)(
1635
1704
  userOutputFile,
1636
1705
  `aiready-report-${getReportTimestamp()}.md`,
1637
1706
  resolvedDir
@@ -1728,12 +1797,12 @@ async function consistencyAction(directory, options) {
1728
1797
  }
1729
1798
  if (consistencyScore) {
1730
1799
  console.log(import_chalk6.default.bold("\n\u{1F4CA} AI Readiness Score (Consistency)\n"));
1731
- console.log((0, import_core5.formatToolScore)(consistencyScore));
1800
+ console.log((0, import_core6.formatToolScore)(consistencyScore));
1732
1801
  console.log();
1733
1802
  }
1734
1803
  }
1735
1804
  } catch (error) {
1736
- (0, import_core5.handleCLIError)(error, "Consistency analysis");
1805
+ (0, import_core6.handleCLIError)(error, "Consistency analysis");
1737
1806
  }
1738
1807
  }
1739
1808
 
@@ -1742,8 +1811,8 @@ var import_chalk7 = __toESM(require("chalk"));
1742
1811
  var import_fs5 = require("fs");
1743
1812
  var import_path7 = require("path");
1744
1813
  var import_child_process = require("child_process");
1745
- var import_core6 = require("@aiready/core");
1746
1814
  var import_core7 = require("@aiready/core");
1815
+ var import_core8 = require("@aiready/core");
1747
1816
  async function visualizeAction(directory, options) {
1748
1817
  try {
1749
1818
  const dirPath = (0, import_path7.resolve)(process.cwd(), directory || ".");
@@ -1906,7 +1975,7 @@ Or specify a custom report:
1906
1975
  }
1907
1976
  }
1908
1977
  console.log("Generating HTML...");
1909
- const html = (0, import_core7.generateHTML)(graph);
1978
+ const html = (0, import_core8.generateHTML)(graph);
1910
1979
  const defaultOutput = "visualization.html";
1911
1980
  const outPath = (0, import_path7.resolve)(dirPath, options.output || defaultOutput);
1912
1981
  (0, import_fs5.writeFileSync)(outPath, html, "utf8");
@@ -1956,7 +2025,7 @@ Or specify a custom report:
1956
2025
  }
1957
2026
  }
1958
2027
  } catch (err) {
1959
- (0, import_core6.handleCLIError)(err, "Visualization");
2028
+ (0, import_core7.handleCLIError)(err, "Visualization");
1960
2029
  }
1961
2030
  }
1962
2031
  var visualizeHelpText = `
@@ -1988,15 +2057,15 @@ NOTES:
1988
2057
 
1989
2058
  // src/commands/ai-signal-clarity.ts
1990
2059
  var import_chalk8 = __toESM(require("chalk"));
1991
- var import_core8 = require("@aiready/core");
2060
+ var import_core9 = require("@aiready/core");
1992
2061
 
1993
2062
  // src/commands/agent-grounding.ts
1994
2063
  var import_chalk9 = __toESM(require("chalk"));
1995
- var import_core9 = require("@aiready/core");
2064
+ var import_core10 = require("@aiready/core");
1996
2065
 
1997
2066
  // src/commands/testability.ts
1998
2067
  var import_chalk10 = __toESM(require("chalk"));
1999
- var import_core10 = require("@aiready/core");
2068
+ var import_core11 = require("@aiready/core");
2000
2069
 
2001
2070
  // src/commands/change-amplification.ts
2002
2071
  var import_cli = require("@aiready/change-amplification/dist/cli.js");