@aiready/core 0.21.18 → 0.22.0

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/index.js CHANGED
@@ -57,6 +57,8 @@ __export(index_exports, {
57
57
  ParseError: () => ParseError,
58
58
  ParserFactory: () => ParserFactory,
59
59
  PythonParser: () => PythonParser,
60
+ ReadinessRating: () => ReadinessRating,
61
+ RecommendationPriority: () => RecommendationPriority,
60
62
  SEVERITY_TIME_ESTIMATES: () => SEVERITY_TIME_ESTIMATES,
61
63
  SIZE_ADJUSTED_THRESHOLDS: () => SIZE_ADJUSTED_THRESHOLDS,
62
64
  Severity: () => Severity,
@@ -93,6 +95,8 @@ __export(index_exports, {
93
95
  calculateTestabilityIndex: () => calculateTestabilityIndex,
94
96
  calculateTokenBudget: () => calculateTokenBudget,
95
97
  clearHistory: () => clearHistory,
98
+ emitAnnotation: () => emitAnnotation,
99
+ emitIssuesAsAnnotations: () => emitIssuesAsAnnotations,
96
100
  emitProgress: () => emitProgress,
97
101
  estimateCostFromBudget: () => estimateCostFromBudget,
98
102
  estimateTokens: () => estimateTokens,
@@ -146,6 +150,7 @@ __export(index_exports, {
146
150
  scanEntries: () => scanEntries,
147
151
  scanFiles: () => scanFiles,
148
152
  setupParser: () => setupParser,
153
+ severityToAnnotationLevel: () => severityToAnnotationLevel,
149
154
  validateSpokeOutput: () => validateSpokeOutput,
150
155
  validateWithSchema: () => validateWithSchema
151
156
  });
@@ -291,7 +296,12 @@ var UnifiedReportSchema = import_zod.z.object({
291
296
  totalFiles: import_zod.z.number(),
292
297
  totalIssues: import_zod.z.number(),
293
298
  criticalIssues: import_zod.z.number(),
294
- majorIssues: import_zod.z.number()
299
+ majorIssues: import_zod.z.number(),
300
+ businessImpact: import_zod.z.object({
301
+ estimatedMonthlyWaste: import_zod.z.number().optional(),
302
+ potentialSavings: import_zod.z.number().optional(),
303
+ productivityHours: import_zod.z.number().optional()
304
+ }).optional()
295
305
  }),
296
306
  results: import_zod.z.array(AnalysisResultSchema),
297
307
  scoring: import_zod.z.object({
@@ -428,51 +438,61 @@ function validateWithSchema(schema, data) {
428
438
  }
429
439
 
430
440
  // src/registry.ts
431
- var ToolRegistry = class {
432
- static getProviders() {
433
- const g = globalThis;
434
- if (!g.__AIRE_TOOL_REGISTRY__) {
435
- g.__AIRE_TOOL_REGISTRY__ = /* @__PURE__ */ new Map();
436
- }
437
- return g.__AIRE_TOOL_REGISTRY__;
441
+ var ToolRegistry = class _ToolRegistry {
442
+ /**
443
+ * Create a new ToolRegistry instance
444
+ *
445
+ * @param id Optional identifier for the registry (e.g. for debugging)
446
+ */
447
+ constructor(id = "default") {
448
+ this.providers = /* @__PURE__ */ new Map();
449
+ this.id = `registry-${id}-${Math.random().toString(36).substring(2, 9)}`;
438
450
  }
439
451
  /**
440
452
  * Register a new tool provider.
453
+ *
454
+ * @param provider The tool provider to register
441
455
  */
442
- static register(provider) {
443
- console.log(
444
- `[ToolRegistry#${this.instanceId}] Registering tool: ${provider.id} (${provider.alias.join(", ")})`
445
- );
446
- this.getProviders().set(provider.id, provider);
456
+ register(provider) {
457
+ this.providers.set(provider.id, provider);
447
458
  }
448
459
  /**
449
460
  * Get a provider by its canonical ID.
461
+ *
462
+ * @param id The tool ID
463
+ * @returns The provider if found
450
464
  */
451
- static get(id) {
452
- return this.getProviders().get(id);
465
+ get(id) {
466
+ return this.providers.get(id);
453
467
  }
454
468
  /**
455
469
  * Get a provider by name or alias.
470
+ *
471
+ * @param nameOrAlias The tool name or alias string
472
+ * @returns The provider if found
456
473
  */
457
- static find(nameOrAlias) {
458
- const providers = this.getProviders();
459
- const exact = providers.get(nameOrAlias);
474
+ find(nameOrAlias) {
475
+ const exact = this.providers.get(nameOrAlias);
460
476
  if (exact) return exact;
461
- for (const p of providers.values()) {
477
+ for (const p of this.providers.values()) {
462
478
  if (p.alias.includes(nameOrAlias)) return p;
463
479
  }
464
480
  return void 0;
465
481
  }
466
482
  /**
467
483
  * Get all registered tool providers.
484
+ *
485
+ * @returns Array of all registered tool providers
468
486
  */
469
- static getAll() {
470
- return Array.from(this.getProviders().values());
487
+ getAll() {
488
+ return Array.from(this.providers.values());
471
489
  }
472
490
  /**
473
491
  * Get all available tool IDs from the ToolName enum.
492
+ *
493
+ * @returns Array of valid ToolName identifiers
474
494
  */
475
- static getAvailableIds() {
495
+ getAvailableIds() {
476
496
  return Object.values(ToolName).filter(
477
497
  (v) => typeof v === "string"
478
498
  );
@@ -480,11 +500,54 @@ var ToolRegistry = class {
480
500
  /**
481
501
  * Clear the registry (primarily for testing).
482
502
  */
503
+ clear() {
504
+ this.providers.clear();
505
+ }
506
+ // --- Static Compatibility Layer ---
507
+ static getGlobalRegistry() {
508
+ const g = globalThis;
509
+ if (!g.__AIRE_TOOL_REGISTRY_INSTANCE__) {
510
+ g.__AIRE_TOOL_REGISTRY_INSTANCE__ = new _ToolRegistry("global");
511
+ }
512
+ return g.__AIRE_TOOL_REGISTRY_INSTANCE__;
513
+ }
514
+ /**
515
+ * Static register (Singleton compatibility)
516
+ */
517
+ static register(provider) {
518
+ this.getGlobalRegistry().register(provider);
519
+ }
520
+ /**
521
+ * Static get (Singleton compatibility)
522
+ */
523
+ static get(id) {
524
+ return this.getGlobalRegistry().get(id);
525
+ }
526
+ /**
527
+ * Static find (Singleton compatibility)
528
+ */
529
+ static find(nameOrAlias) {
530
+ return this.getGlobalRegistry().find(nameOrAlias);
531
+ }
532
+ /**
533
+ * Static getAll (Singleton compatibility)
534
+ */
535
+ static getAll() {
536
+ return this.getGlobalRegistry().getAll();
537
+ }
538
+ /**
539
+ * Static getAvailableIds (Singleton compatibility)
540
+ */
541
+ static getAvailableIds() {
542
+ return this.getGlobalRegistry().getAvailableIds();
543
+ }
544
+ /**
545
+ * Static clear (Singleton compatibility)
546
+ */
483
547
  static clear() {
484
- this.getProviders().clear();
548
+ this.getGlobalRegistry().clear();
485
549
  }
486
550
  };
487
- ToolRegistry.instanceId = globalThis.Math.random();
488
551
 
489
552
  // src/utils/file-scanner.ts
490
553
  var import_glob = require("glob");
@@ -596,7 +659,8 @@ async function scanFiles(options) {
596
659
  });
597
660
  const gitignoreFiles = await (0, import_glob.glob)("**/.gitignore", {
598
661
  cwd: rootDir,
599
- ignore: finalExclude,
662
+ ignore: (exclude || []).concat(["**/node_modules/**", "**/.git/**"]),
663
+ // Minimal ignore for gitignore discovery
600
664
  absolute: true
601
665
  });
602
666
  if (gitignoreFiles.length > 0) {
@@ -663,7 +727,7 @@ async function scanEntries(options) {
663
727
  });
664
728
  const gitignoreFiles = await (0, import_glob.glob)("**/.gitignore", {
665
729
  cwd: rootDir,
666
- ignore: finalExclude,
730
+ ignore: (exclude || []).concat(["**/node_modules/**", "**/.git/**"]),
667
731
  absolute: true
668
732
  });
669
733
  if (gitignoreFiles.length > 0) {
@@ -687,8 +751,9 @@ async function scanEntries(options) {
687
751
  }
688
752
  }
689
753
  const filteredDirs = dirs.filter((d) => {
690
- const rel = (0, import_path.relative)(rootDir || ".", d).replace(/\\/g, "/").replace(/\/$/, "");
754
+ let rel = (0, import_path.relative)(rootDir || ".", d).replace(/\\/g, "/");
691
755
  if (rel === "") return true;
756
+ if (!rel.endsWith("/")) rel += "/";
692
757
  return !ig.ignores(rel);
693
758
  });
694
759
  return { files, dirs: filteredDirs };
@@ -753,7 +818,8 @@ function getElapsedTime(startTime) {
753
818
  return ((Date.now() - startTime) / 1e3).toFixed(2);
754
819
  }
755
820
  function getScoreBar(val) {
756
- return "\u2588".repeat(Math.round(val / 10)).padEnd(10, "\u2591");
821
+ const clamped = Math.max(0, Math.min(100, val));
822
+ return "\u2588".repeat(Math.round(clamped / 10)).padEnd(10, "\u2591");
757
823
  }
758
824
  function getSafetyIcon(rating) {
759
825
  switch (rating) {
@@ -1014,7 +1080,7 @@ var TypeScriptParser = class {
1014
1080
  extractFromDeclaration(declaration, importedNames, code, parentNode) {
1015
1081
  const exports2 = [];
1016
1082
  const metadata = this.analyzeMetadata(parentNode || declaration, code);
1017
- if (declaration.type === "FunctionDeclaration" && declaration.id) {
1083
+ if ((declaration.type === "FunctionDeclaration" || declaration.type === "TSDeclareFunction") && declaration.id) {
1018
1084
  exports2.push({
1019
1085
  name: declaration.id.name,
1020
1086
  type: "function",
@@ -1042,11 +1108,21 @@ var TypeScriptParser = class {
1042
1108
  const body = declaration.body.body;
1043
1109
  const methods = body.filter((m) => m.type === "MethodDefinition");
1044
1110
  const properties = body.filter((m) => m.type === "PropertyDefinition");
1111
+ const constructor = methods.find(
1112
+ (m) => m.kind === "constructor"
1113
+ );
1114
+ const parameters = constructor ? constructor.value.params.map((p) => {
1115
+ if (p.type === "Identifier") return p.name;
1116
+ if (p.type === "TSParameterProperty" && p.parameter.type === "Identifier")
1117
+ return p.parameter.name;
1118
+ return "unknown";
1119
+ }) : [];
1045
1120
  exports2.push({
1046
1121
  name: declaration.id.name,
1047
1122
  type: "class",
1048
1123
  methodCount: methods.length,
1049
1124
  propertyCount: properties.length,
1125
+ parameters,
1050
1126
  loc: declaration.loc ? {
1051
1127
  start: {
1052
1128
  line: declaration.loc.start.line,
@@ -2493,6 +2569,9 @@ var GoParser = class {
2493
2569
 
2494
2570
  // src/parsers/parser-factory.ts
2495
2571
  var ParserFactory = class _ParserFactory {
2572
+ /**
2573
+ * Create a new ParserFactory instance
2574
+ */
2496
2575
  constructor() {
2497
2576
  this.parsers = /* @__PURE__ */ new Map();
2498
2577
  this.extensionMap = new Map(
@@ -2505,7 +2584,9 @@ var ParserFactory = class _ParserFactory {
2505
2584
  this.registerParser(new GoParser());
2506
2585
  }
2507
2586
  /**
2508
- * Get singleton instance
2587
+ * Get the global singleton instance
2588
+ *
2589
+ * @returns The singleton ParserFactory instance
2509
2590
  */
2510
2591
  static getInstance() {
2511
2592
  if (!_ParserFactory.instance) {
@@ -3052,6 +3133,20 @@ function generateHTML(graph) {
3052
3133
  }
3053
3134
 
3054
3135
  // src/scoring.ts
3136
+ var RecommendationPriority = /* @__PURE__ */ ((RecommendationPriority2) => {
3137
+ RecommendationPriority2["High"] = "high";
3138
+ RecommendationPriority2["Medium"] = "medium";
3139
+ RecommendationPriority2["Low"] = "low";
3140
+ return RecommendationPriority2;
3141
+ })(RecommendationPriority || {});
3142
+ var ReadinessRating = /* @__PURE__ */ ((ReadinessRating2) => {
3143
+ ReadinessRating2["Excellent"] = "Excellent";
3144
+ ReadinessRating2["Good"] = "Good";
3145
+ ReadinessRating2["Fair"] = "Fair";
3146
+ ReadinessRating2["NeedsWork"] = "Needs Work";
3147
+ ReadinessRating2["Critical"] = "Critical";
3148
+ return ReadinessRating2;
3149
+ })(ReadinessRating || {});
3055
3150
  var DEFAULT_TOOL_WEIGHTS = {
3056
3151
  ["pattern-detect" /* PatternDetect */]: 22,
3057
3152
  ["context-analyzer" /* ContextAnalyzer */]: 19,
@@ -3126,10 +3221,10 @@ function parseWeightString(weightStr) {
3126
3221
  if (!weightStr) return weights;
3127
3222
  const pairs = weightStr.split(",");
3128
3223
  for (const pair of pairs) {
3129
- const [toolShortName, weightStr2] = pair.split(":");
3130
- if (toolShortName && weightStr2) {
3224
+ const [toolShortName, weightValueStr] = pair.split(":");
3225
+ if (toolShortName && weightValueStr) {
3131
3226
  const toolName = normalizeToolName(toolShortName.trim());
3132
- const weight = parseInt(weightStr2.trim(), 10);
3227
+ const weight = parseInt(weightValueStr.trim(), 10);
3133
3228
  if (!isNaN(weight) && weight > 0) {
3134
3229
  weights.set(toolName, weight);
3135
3230
  }
@@ -3184,11 +3279,11 @@ function calculateOverallScore(toolOutputs, config, cliWeights) {
3184
3279
  };
3185
3280
  }
3186
3281
  function getRating(score) {
3187
- if (score >= 90) return "Excellent";
3188
- if (score >= 75) return "Good";
3189
- if (score >= 60) return "Fair";
3190
- if (score >= 40) return "Needs Work";
3191
- return "Critical";
3282
+ if (score >= 90) return "Excellent" /* Excellent */;
3283
+ if (score >= 75) return "Good" /* Good */;
3284
+ if (score >= 60) return "Fair" /* Fair */;
3285
+ if (score >= 40) return "Needs Work" /* NeedsWork */;
3286
+ return "Critical" /* Critical */;
3192
3287
  }
3193
3288
  function getRatingWithContext(score, fileCount, modelTier = "standard") {
3194
3289
  const threshold = getRecommendedThreshold(fileCount, modelTier);
@@ -3197,16 +3292,18 @@ function getRatingWithContext(score, fileCount, modelTier = "standard") {
3197
3292
  }
3198
3293
  function getRatingDisplay(rating) {
3199
3294
  switch (rating) {
3200
- case "Excellent":
3295
+ case "Excellent" /* Excellent */:
3201
3296
  return { emoji: "\u2705", color: "green" };
3202
- case "Good":
3297
+ case "Good" /* Good */:
3203
3298
  return { emoji: "\u{1F44D}", color: "blue" };
3204
- case "Fair":
3299
+ case "Fair" /* Fair */:
3205
3300
  return { emoji: "\u26A0\uFE0F", color: "yellow" };
3206
- case "Needs Work":
3301
+ case "Needs Work" /* NeedsWork */:
3207
3302
  return { emoji: "\u{1F528}", color: "orange" };
3208
- case "Critical":
3303
+ case "Critical" /* Critical */:
3209
3304
  return { emoji: "\u274C", color: "red" };
3305
+ default:
3306
+ return { emoji: "\u2753", color: "gray" };
3210
3307
  }
3211
3308
  }
3212
3309
  function formatScore(result) {
@@ -3231,7 +3328,12 @@ function formatToolScore(output) {
3231
3328
  result += ` Recommendations:
3232
3329
  `;
3233
3330
  output.recommendations.forEach((rec, i) => {
3234
- const priorityIcon = rec.priority === "high" ? "\u{1F534}" : rec.priority === "medium" ? "\u{1F7E1}" : "\u{1F535}";
3331
+ let priorityIcon = "\u{1F535}";
3332
+ const prio = rec.priority;
3333
+ if (prio === "high" /* High */ || prio === "high")
3334
+ priorityIcon = "\u{1F534}";
3335
+ else if (prio === "medium" /* Medium */ || prio === "medium")
3336
+ priorityIcon = "\u{1F7E1}";
3235
3337
  result += ` ${i + 1}. ${priorityIcon} ${rec.action}
3236
3338
  `;
3237
3339
  result += ` Impact: +${rec.estimatedImpact} points
@@ -3313,15 +3415,17 @@ var DEFAULT_COST_CONFIG = {
3313
3415
  daysPerMonth: 30
3314
3416
  };
3315
3417
  function calculateMonthlyCost(tokenWaste, config = {}) {
3418
+ const multiplier = tokenWaste > 5e4 ? 5 : tokenWaste > 1e4 ? 3.5 : 2.5;
3316
3419
  const budget = calculateTokenBudget({
3317
- totalContextTokens: tokenWaste * 2.5,
3420
+ totalContextTokens: tokenWaste * multiplier,
3318
3421
  wastedTokens: {
3319
3422
  duplication: tokenWaste * 0.7,
3320
3423
  fragmentation: tokenWaste * 0.3,
3321
- chattiness: 0
3424
+ chattiness: 0.1 * tokenWaste
3425
+ // Added baseline chattiness
3322
3426
  }
3323
3427
  });
3324
- const preset = getModelPreset("claude-4.6");
3428
+ const preset = getModelPreset("claude-3.5-sonnet");
3325
3429
  return estimateCostFromBudget(budget, preset, config);
3326
3430
  }
3327
3431
  function calculateTokenBudget(params) {
@@ -3803,7 +3907,7 @@ function calculatePatternEntropy(files) {
3803
3907
  }
3804
3908
  const dirGroups = /* @__PURE__ */ new Map();
3805
3909
  for (const file of files) {
3806
- const parts = file.path.split("/").slice(0, 4).join("/") || "root";
3910
+ const parts = file.path.split("/").slice(0, -1).join("/") || "root";
3807
3911
  dirGroups.set(parts, (dirGroups.get(parts) || 0) + 1);
3808
3912
  }
3809
3913
  const counts = Array.from(dirGroups.values());
@@ -3910,6 +4014,8 @@ function calculateAiSignalClarity(params) {
3910
4014
  deepCallbacks,
3911
4015
  ambiguousNames,
3912
4016
  undocumentedExports,
4017
+ largeFiles = 0,
4018
+ // Default to 0 to prevent NaN
3913
4019
  totalSymbols,
3914
4020
  totalExports
3915
4021
  } = params;
@@ -3926,28 +4032,35 @@ function calculateAiSignalClarity(params) {
3926
4032
  const overloadSignal = {
3927
4033
  name: "Symbol Overloading",
3928
4034
  count: overloadedSymbols,
3929
- riskContribution: Math.round(Math.min(1, overloadRatio) * 100 * 0.25),
4035
+ riskContribution: Math.round(Math.min(1, overloadRatio) * 100 * 0.2),
3930
4036
  description: `${overloadedSymbols} overloaded symbols \u2014 AI picks wrong signature`
3931
4037
  };
4038
+ const largeFileSignal = {
4039
+ name: "Large Files",
4040
+ count: largeFiles,
4041
+ riskContribution: Math.round(Math.min(5, largeFiles) * 5),
4042
+ // up to 25 points
4043
+ description: `${largeFiles} large files \u2014 pushing AI context limits`
4044
+ };
3932
4045
  const magicRatio = magicLiterals / Math.max(1, totalSymbols * 2);
3933
4046
  const magicSignal = {
3934
4047
  name: "Magic Literals",
3935
4048
  count: magicLiterals,
3936
- riskContribution: Math.round(Math.min(1, magicRatio) * 100 * 0.2),
4049
+ riskContribution: Math.round(Math.min(1, magicRatio) * 100 * 0.15),
3937
4050
  description: `${magicLiterals} unnamed constants \u2014 AI invents wrong values`
3938
4051
  };
3939
4052
  const trapRatio = booleanTraps / Math.max(1, totalSymbols);
3940
4053
  const trapSignal = {
3941
4054
  name: "Boolean Traps",
3942
4055
  count: booleanTraps,
3943
- riskContribution: Math.round(Math.min(1, trapRatio) * 100 * 0.2),
4056
+ riskContribution: Math.round(Math.min(1, trapRatio) * 100 * 0.15),
3944
4057
  description: `${booleanTraps} boolean trap parameters \u2014 AI inverts intent`
3945
4058
  };
3946
4059
  const sideEffectRatio = implicitSideEffects / Math.max(1, totalExports);
3947
4060
  const sideEffectSignal = {
3948
4061
  name: "Implicit Side Effects",
3949
4062
  count: implicitSideEffects,
3950
- riskContribution: Math.round(Math.min(1, sideEffectRatio) * 100 * 0.15),
4063
+ riskContribution: Math.round(Math.min(1, sideEffectRatio) * 100 * 0.1),
3951
4064
  description: `${implicitSideEffects} functions with implicit side effects \u2014 AI misses contracts`
3952
4065
  };
3953
4066
  const callbackRatio = deepCallbacks / Math.max(1, totalSymbols * 0.1);
@@ -3961,18 +4074,19 @@ function calculateAiSignalClarity(params) {
3961
4074
  const ambiguousSignal = {
3962
4075
  name: "Ambiguous Names",
3963
4076
  count: ambiguousNames,
3964
- riskContribution: Math.round(Math.min(1, ambiguousRatio) * 100 * 0.1),
4077
+ riskContribution: Math.round(Math.min(1, ambiguousRatio) * 100 * 0.05),
3965
4078
  description: `${ambiguousNames} non-descriptive identifiers \u2014 AI guesses wrong intent`
3966
4079
  };
3967
4080
  const undocRatio = undocumentedExports / Math.max(1, totalExports);
3968
4081
  const undocSignal = {
3969
4082
  name: "Undocumented Exports",
3970
4083
  count: undocumentedExports,
3971
- riskContribution: Math.round(Math.min(1, undocRatio) * 100 * 0.1),
4084
+ riskContribution: Math.round(Math.min(1, undocRatio) * 100 * 0.05),
3972
4085
  description: `${undocumentedExports} public functions without docs \u2014 AI fabricates behavior`
3973
4086
  };
3974
4087
  const signals = [
3975
4088
  overloadSignal,
4089
+ largeFileSignal,
3976
4090
  magicSignal,
3977
4091
  trapSignal,
3978
4092
  sideEffectSignal,
@@ -3995,6 +4109,10 @@ function calculateAiSignalClarity(params) {
3995
4109
  );
3996
4110
  const topRisk = topSignal.riskContribution > 0 ? topSignal.description : "No significant issues detected";
3997
4111
  const recommendations = [];
4112
+ if (largeFileSignal.riskContribution > 5)
4113
+ recommendations.push(
4114
+ `Split ${largeFiles} large files (> 500 lines) into smaller, single-responsibility modules`
4115
+ );
3998
4116
  if (overloadSignal.riskContribution > 5)
3999
4117
  recommendations.push(
4000
4118
  `Rename ${overloadedSymbols} overloaded symbols to unique, intent-revealing names`
@@ -4630,6 +4748,46 @@ function getRepoMetadata(directory) {
4630
4748
  }
4631
4749
  return metadata;
4632
4750
  }
4751
+
4752
+ // src/utils/github-utils.ts
4753
+ function emitAnnotation(params) {
4754
+ const { level, file, line, col, title, message } = params;
4755
+ const parts = [];
4756
+ if (file) parts.push(`file=${file}`);
4757
+ if (line) parts.push(`line=${line}`);
4758
+ if (col) parts.push(`col=${col}`);
4759
+ if (title) parts.push(`title=${title}`);
4760
+ const metadata = parts.length > 0 ? ` ${parts.join(",")}` : "";
4761
+ console.log(`::${level}${metadata}::${message.replace(/\n/g, "%0A")}`);
4762
+ }
4763
+ function severityToAnnotationLevel(severity) {
4764
+ switch (severity.toLowerCase()) {
4765
+ case "critical":
4766
+ case "high-risk":
4767
+ case "blind-risk":
4768
+ return "error";
4769
+ case "major":
4770
+ case "moderate-risk":
4771
+ return "warning";
4772
+ case "minor":
4773
+ case "info":
4774
+ case "safe":
4775
+ default:
4776
+ return "notice";
4777
+ }
4778
+ }
4779
+ function emitIssuesAsAnnotations(issues) {
4780
+ issues.forEach((issue) => {
4781
+ emitAnnotation({
4782
+ level: severityToAnnotationLevel(issue.severity || "info"),
4783
+ file: issue.file || issue.fileName || "",
4784
+ line: issue.line || issue.location?.start?.line,
4785
+ col: issue.column || issue.location?.start?.column,
4786
+ title: `${issue.tool || "AIReady"}: ${issue.type || "Issue"}`,
4787
+ message: issue.message || issue.description || "No description provided"
4788
+ });
4789
+ });
4790
+ }
4633
4791
  // Annotate the CommonJS export names for ESM import in node:
4634
4792
  0 && (module.exports = {
4635
4793
  AnalysisResultSchema,
@@ -4659,6 +4817,8 @@ function getRepoMetadata(directory) {
4659
4817
  ParseError,
4660
4818
  ParserFactory,
4661
4819
  PythonParser,
4820
+ ReadinessRating,
4821
+ RecommendationPriority,
4662
4822
  SEVERITY_TIME_ESTIMATES,
4663
4823
  SIZE_ADJUSTED_THRESHOLDS,
4664
4824
  Severity,
@@ -4695,6 +4855,8 @@ function getRepoMetadata(directory) {
4695
4855
  calculateTestabilityIndex,
4696
4856
  calculateTokenBudget,
4697
4857
  clearHistory,
4858
+ emitAnnotation,
4859
+ emitIssuesAsAnnotations,
4698
4860
  emitProgress,
4699
4861
  estimateCostFromBudget,
4700
4862
  estimateTokens,
@@ -4748,6 +4910,7 @@ function getRepoMetadata(directory) {
4748
4910
  scanEntries,
4749
4911
  scanFiles,
4750
4912
  setupParser,
4913
+ severityToAnnotationLevel,
4751
4914
  validateSpokeOutput,
4752
4915
  validateWithSchema
4753
4916
  });