@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/chunk-CKVKHN3G.mjs +643 -0
- package/dist/chunk-LTNXTXRI.mjs +642 -0
- package/dist/chunk-SWTDBVYJ.mjs +645 -0
- package/dist/client.d.mts +206 -92
- package/dist/client.d.ts +206 -92
- package/dist/client.js +45 -15
- package/dist/client.mjs +5 -1
- package/dist/index.d.mts +89 -13
- package/dist/index.d.ts +89 -13
- package/dist/index.js +217 -54
- package/dist/index.mjs +174 -40
- package/package.json +1 -1
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
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
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
|
-
|
|
443
|
-
|
|
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
|
-
|
|
452
|
-
return this.
|
|
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
|
-
|
|
458
|
-
const
|
|
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
|
-
|
|
470
|
-
return Array.from(this.
|
|
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
|
-
|
|
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.
|
|
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:
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
3130
|
-
if (toolShortName &&
|
|
3224
|
+
const [toolShortName, weightValueStr] = pair.split(":");
|
|
3225
|
+
if (toolShortName && weightValueStr) {
|
|
3131
3226
|
const toolName = normalizeToolName(toolShortName.trim());
|
|
3132
|
-
const weight = parseInt(
|
|
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
|
-
|
|
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 *
|
|
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-
|
|
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,
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
});
|