@aiready/core 0.9.37 → 0.9.39

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
@@ -40,16 +40,19 @@ __export(index_exports, {
40
40
  ParseError: () => ParseError,
41
41
  ParserFactory: () => ParserFactory,
42
42
  PythonParser: () => PythonParser,
43
+ SEVERITY_TIME_ESTIMATES: () => SEVERITY_TIME_ESTIMATES,
43
44
  SIZE_ADJUSTED_THRESHOLDS: () => SIZE_ADJUSTED_THRESHOLDS,
44
45
  TOOL_NAME_MAP: () => TOOL_NAME_MAP,
45
46
  TypeScriptParser: () => TypeScriptParser,
46
47
  VAGUE_FILE_NAMES: () => VAGUE_FILE_NAMES,
47
48
  calculateAgentGrounding: () => calculateAgentGrounding,
48
49
  calculateAiSignalClarity: () => calculateAiSignalClarity,
50
+ calculateBusinessROI: () => calculateBusinessROI,
49
51
  calculateChangeAmplification: () => calculateChangeAmplification,
50
52
  calculateCognitiveLoad: () => calculateCognitiveLoad,
51
53
  calculateComprehensionDifficulty: () => calculateComprehensionDifficulty,
52
54
  calculateConceptCohesion: () => calculateConceptCohesion,
55
+ calculateDebtInterest: () => calculateDebtInterest,
53
56
  calculateDependencyHealth: () => calculateDependencyHealth,
54
57
  calculateDocDrift: () => calculateDocDrift,
55
58
  calculateExtendedFutureProofScore: () => calculateExtendedFutureProofScore,
@@ -60,10 +63,8 @@ __export(index_exports, {
60
63
  calculateOverallScore: () => calculateOverallScore,
61
64
  calculatePatternEntropy: () => calculatePatternEntropy,
62
65
  calculateProductivityImpact: () => calculateProductivityImpact,
63
- calculateRemediationVelocity: () => calculateRemediationVelocity,
64
- calculateScoreTrend: () => calculateScoreTrend,
65
66
  calculateSemanticDistance: () => calculateSemanticDistance,
66
- calculateTechnicalDebtInterest: () => calculateTechnicalDebtInterest,
67
+ calculateTechnicalValueChain: () => calculateTechnicalValueChain,
67
68
  calculateTestabilityIndex: () => calculateTestabilityIndex,
68
69
  calculateTokenBudget: () => calculateTokenBudget,
69
70
  clearHistory: () => clearHistory,
@@ -79,7 +80,6 @@ __export(index_exports, {
79
80
  formatToolScore: () => formatToolScore,
80
81
  generateHTML: () => generateHTML,
81
82
  generateValueChain: () => generateValueChain,
82
- getDebtBreakdown: () => getDebtBreakdown,
83
83
  getElapsedTime: () => getElapsedTime,
84
84
  getFileCommitTimestamps: () => getFileCommitTimestamps,
85
85
  getFileExtension: () => getFileExtension,
@@ -93,6 +93,9 @@ __export(index_exports, {
93
93
  getRatingWithContext: () => getRatingWithContext,
94
94
  getRecommendedThreshold: () => getRecommendedThreshold,
95
95
  getRepoMetadata: () => getRepoMetadata,
96
+ getSafetyIcon: () => getSafetyIcon,
97
+ getScoreBar: () => getScoreBar,
98
+ getSeverityColor: () => getSeverityColor,
96
99
  getSupportedLanguages: () => getSupportedLanguages,
97
100
  getToolWeight: () => getToolWeight,
98
101
  handleCLIError: () => handleCLIError,
@@ -117,15 +120,15 @@ __export(index_exports, {
117
120
  module.exports = __toCommonJS(index_exports);
118
121
 
119
122
  // src/types/language.ts
120
- var Language = /* @__PURE__ */ ((Language3) => {
121
- Language3["TypeScript"] = "typescript";
122
- Language3["JavaScript"] = "javascript";
123
- Language3["Python"] = "python";
124
- Language3["Java"] = "java";
125
- Language3["Go"] = "go";
126
- Language3["Rust"] = "rust";
127
- Language3["CSharp"] = "csharp";
128
- return Language3;
123
+ var Language = /* @__PURE__ */ ((Language2) => {
124
+ Language2["TypeScript"] = "typescript";
125
+ Language2["JavaScript"] = "javascript";
126
+ Language2["Python"] = "python";
127
+ Language2["Java"] = "java";
128
+ Language2["Go"] = "go";
129
+ Language2["Rust"] = "rust";
130
+ Language2["CSharp"] = "csharp";
131
+ return Language2;
129
132
  })(Language || {});
130
133
  var LANGUAGE_EXTENSIONS = {
131
134
  ".ts": "typescript" /* TypeScript */,
@@ -640,6 +643,41 @@ function handleCLIError(error, commandName) {
640
643
  function getElapsedTime(startTime) {
641
644
  return ((Date.now() - startTime) / 1e3).toFixed(2);
642
645
  }
646
+ function getScoreBar(val) {
647
+ return "\u2588".repeat(Math.round(val / 10)).padEnd(10, "\u2591");
648
+ }
649
+ function getSafetyIcon(rating) {
650
+ switch (rating) {
651
+ case "safe":
652
+ return "\u2705";
653
+ case "moderate-risk":
654
+ return "\u26A0\uFE0F ";
655
+ case "high-risk":
656
+ return "\u{1F534}";
657
+ case "blind-risk":
658
+ return "\u{1F480}";
659
+ default:
660
+ return "\u2753";
661
+ }
662
+ }
663
+ function getSeverityColor(severity, chalk) {
664
+ switch (severity.toLowerCase()) {
665
+ case "critical":
666
+ case "high-risk":
667
+ case "blind-risk":
668
+ return chalk.red;
669
+ case "major":
670
+ case "moderate-risk":
671
+ return chalk.yellow;
672
+ case "minor":
673
+ case "safe":
674
+ return chalk.green;
675
+ case "info":
676
+ return chalk.blue;
677
+ default:
678
+ return chalk.white;
679
+ }
680
+ }
643
681
 
644
682
  // src/utils/visualization.ts
645
683
  function generateHTML(graph) {
@@ -901,7 +939,7 @@ function calculateOverallScore(toolOutputs, config, cliWeights) {
901
939
  for (const [toolName] of toolOutputs.entries()) {
902
940
  const cliWeight = cliWeights?.get(toolName);
903
941
  const configWeight = config?.tools?.[toolName]?.scoreWeight;
904
- const weight = cliWeight ?? configWeight ?? DEFAULT_TOOL_WEIGHTS[toolName] ?? 10;
942
+ const weight = cliWeight ?? configWeight ?? DEFAULT_TOOL_WEIGHTS[toolName] ?? 5;
905
943
  weights.set(toolName, weight);
906
944
  }
907
945
  let weightedSum = 0;
@@ -910,7 +948,7 @@ function calculateOverallScore(toolOutputs, config, cliWeights) {
910
948
  const toolsUsed = [];
911
949
  const calculationWeights = {};
912
950
  for (const [toolName, output] of toolOutputs.entries()) {
913
- const weight = weights.get(toolName) || 10;
951
+ const weight = weights.get(toolName) || 5;
914
952
  const weightedScore = output.score * weight;
915
953
  weightedSum += weightedScore;
916
954
  totalWeight += weight;
@@ -922,7 +960,7 @@ function calculateOverallScore(toolOutputs, config, cliWeights) {
922
960
  const rating = getRating(overall);
923
961
  const formulaParts = Array.from(toolOutputs.entries()).map(
924
962
  ([name, output]) => {
925
- const w = weights.get(name) || 10;
963
+ const w = weights.get(name) || 5;
926
964
  return `(${output.score} \xD7 ${w})`;
927
965
  }
928
966
  );
@@ -967,7 +1005,7 @@ function getRatingDisplay(rating) {
967
1005
  }
968
1006
  }
969
1007
  function formatScore(result) {
970
- const { emoji, color } = getRatingDisplay(result.rating);
1008
+ const { emoji } = getRatingDisplay(result.rating);
971
1009
  return `${result.overall}/100 (${result.rating}) ${emoji}`;
972
1010
  }
973
1011
  function formatToolScore(output) {
@@ -999,7 +1037,7 @@ function formatToolScore(output) {
999
1037
  return result;
1000
1038
  }
1001
1039
 
1002
- // src/business-metrics.ts
1040
+ // src/business/pricing-models.ts
1003
1041
  var MODEL_PRICING_PRESETS = {
1004
1042
  "gpt-5.3": {
1005
1043
  name: "GPT-5.3",
@@ -1061,30 +1099,17 @@ var MODEL_PRICING_PRESETS = {
1061
1099
  function getModelPreset(modelId) {
1062
1100
  return MODEL_PRICING_PRESETS[modelId] ?? MODEL_PRICING_PRESETS["claude-4.6"];
1063
1101
  }
1102
+
1103
+ // src/business/cost-metrics.ts
1064
1104
  var DEFAULT_COST_CONFIG = {
1065
1105
  pricePer1KTokens: 5e-3,
1066
- // GPT-4o input price (updated from GPT-4 era 0.01)
1067
1106
  queriesPerDevPerDay: 60,
1068
- // Average AI queries per developer (updated: 40→60 as of 2026)
1069
1107
  developerCount: 5,
1070
- // Default team size
1071
1108
  daysPerMonth: 30
1072
1109
  };
1073
- var SEVERITY_TIME_ESTIMATES = {
1074
- critical: 4,
1075
- // Complex architectural issues (industry avg: 6.8h)
1076
- major: 2,
1077
- // Significant refactoring needed (avg: 3.4h)
1078
- minor: 0.5,
1079
- // Simple naming/style fixes (avg: 0.8h)
1080
- info: 0.25
1081
- // Documentation improvements
1082
- };
1083
- var DEFAULT_HOURLY_RATE = 75;
1084
1110
  function calculateMonthlyCost(tokenWaste, config = {}) {
1085
1111
  const budget = calculateTokenBudget({
1086
1112
  totalContextTokens: tokenWaste * 2.5,
1087
- // Heuristic: context is larger than waste
1088
1113
  wastedTokens: {
1089
1114
  duplication: tokenWaste * 0.7,
1090
1115
  fragmentation: tokenWaste * 0.3,
@@ -1100,7 +1125,10 @@ function calculateTokenBudget(params) {
1100
1125
  const totalWaste = wastedTokens.duplication + wastedTokens.fragmentation + wastedTokens.chattiness;
1101
1126
  const efficiencyRatio = Math.max(
1102
1127
  0,
1103
- Math.min(1, (totalContextTokens - totalWaste) / Math.max(1, totalContextTokens))
1128
+ Math.min(
1129
+ 1,
1130
+ (totalContextTokens - totalWaste) / Math.max(1, totalContextTokens)
1131
+ )
1104
1132
  );
1105
1133
  return {
1106
1134
  totalContextTokens: Math.round(totalContextTokens),
@@ -1115,7 +1143,6 @@ function calculateTokenBudget(params) {
1115
1143
  },
1116
1144
  efficiencyRatio: Math.round(efficiencyRatio * 100) / 100,
1117
1145
  potentialRetrievableTokens: Math.round(totalWaste * 0.8)
1118
- // Heuristic: 80% is fixable
1119
1146
  };
1120
1147
  }
1121
1148
  function estimateCostFromBudget(budget, model, config = {}) {
@@ -1124,7 +1151,8 @@ function estimateCostFromBudget(budget, model, config = {}) {
1124
1151
  const tokensPerDay = wastePerQuery * cfg.queriesPerDevPerDay;
1125
1152
  const tokensPerMonth = tokensPerDay * cfg.daysPerMonth;
1126
1153
  const totalWeight = cfg.developerCount;
1127
- const baseCost = tokensPerMonth / 1e3 * model.pricePer1KInputTokens * totalWeight;
1154
+ const price = config.pricePer1KTokens ?? model.pricePer1KInputTokens;
1155
+ const baseCost = tokensPerMonth / 1e3 * price * totalWeight;
1128
1156
  let confidence = 0.85;
1129
1157
  if (model.contextTier === "frontier") confidence = 0.7;
1130
1158
  const variance = 0.25;
@@ -1138,6 +1166,15 @@ function estimateCostFromBudget(budget, model, config = {}) {
1138
1166
  confidence
1139
1167
  };
1140
1168
  }
1169
+
1170
+ // src/business/productivity-metrics.ts
1171
+ var SEVERITY_TIME_ESTIMATES = {
1172
+ critical: 4,
1173
+ major: 2,
1174
+ minor: 0.5,
1175
+ info: 0.25
1176
+ };
1177
+ var DEFAULT_HOURLY_RATE = 75;
1141
1178
  function calculateProductivityImpact(issues, hourlyRate = DEFAULT_HOURLY_RATE) {
1142
1179
  const counts = {
1143
1180
  critical: issues.filter((i) => i.severity === "critical").length,
@@ -1178,108 +1215,158 @@ function predictAcceptanceRate(toolOutputs) {
1178
1215
  const baseRate = 0.3;
1179
1216
  const patterns = toolOutputs.get("pattern-detect");
1180
1217
  if (patterns) {
1181
- const patternImpact = (patterns.score - 50) * 3e-3;
1182
1218
  factors.push({
1183
1219
  name: "Semantic Duplication",
1184
- impact: Math.round(patternImpact * 100)
1220
+ impact: Math.round((patterns.score - 50) * 3e-3 * 100)
1185
1221
  });
1186
1222
  }
1187
1223
  const context = toolOutputs.get("context-analyzer");
1188
1224
  if (context) {
1189
- const contextImpact = (context.score - 50) * 4e-3;
1190
1225
  factors.push({
1191
1226
  name: "Context Efficiency",
1192
- impact: Math.round(contextImpact * 100)
1227
+ impact: Math.round((context.score - 50) * 4e-3 * 100)
1193
1228
  });
1194
1229
  }
1195
1230
  const consistency = toolOutputs.get("consistency");
1196
1231
  if (consistency) {
1197
- const consistencyImpact = (consistency.score - 50) * 2e-3;
1198
1232
  factors.push({
1199
1233
  name: "Code Consistency",
1200
- impact: Math.round(consistencyImpact * 100)
1234
+ impact: Math.round((consistency.score - 50) * 2e-3 * 100)
1201
1235
  });
1202
1236
  }
1203
1237
  const aiSignalClarity = toolOutputs.get("ai-signal-clarity");
1204
1238
  if (aiSignalClarity) {
1205
- const hrImpact = (50 - aiSignalClarity.score) * 2e-3;
1206
1239
  factors.push({
1207
1240
  name: "AI Signal Clarity",
1208
- impact: Math.round(hrImpact * 100)
1241
+ impact: Math.round((50 - aiSignalClarity.score) * 2e-3 * 100)
1209
1242
  });
1210
1243
  }
1211
1244
  const totalImpact = factors.reduce((sum, f) => sum + f.impact / 100, 0);
1212
1245
  const rate = Math.max(0.05, Math.min(0.8, baseRate + totalImpact));
1213
- let confidence;
1246
+ let confidence = 0.35;
1214
1247
  if (toolOutputs.size >= 4) confidence = 0.75;
1215
1248
  else if (toolOutputs.size >= 3) confidence = 0.65;
1216
1249
  else if (toolOutputs.size >= 2) confidence = 0.5;
1217
- else confidence = 0.35;
1218
- return {
1219
- rate: Math.round(rate * 100) / 100,
1220
- confidence,
1221
- factors
1222
- };
1250
+ return { rate: Math.round(rate * 100) / 100, confidence, factors };
1223
1251
  }
1224
- function calculateComprehensionDifficulty(contextBudget, importDepth, fragmentation, consistencyScore, totalFiles, modelTier = "standard") {
1225
- const tierThresholds = CONTEXT_TIER_THRESHOLDS[modelTier];
1226
- const idealBudget = tierThresholds.idealTokens;
1227
- const criticalBudget = tierThresholds.criticalTokens;
1228
- const idealDepth = tierThresholds.idealDepth;
1229
- const budgetRange = criticalBudget - idealBudget;
1230
- const budgetFactor = Math.min(
1231
- 100,
1232
- Math.max(0, (contextBudget - idealBudget) / budgetRange * 100)
1233
- );
1234
- const depthFactor = Math.min(
1235
- 100,
1236
- Math.max(0, (importDepth - idealDepth) * 10)
1237
- );
1238
- const fragmentationFactor = Math.min(
1239
- 100,
1240
- Math.max(0, (fragmentation - 0.3) * 250)
1241
- );
1242
- const consistencyFactor = Math.min(100, Math.max(0, 100 - consistencyScore));
1243
- const fileFactor = Math.min(100, Math.max(0, (totalFiles - 50) / 5));
1252
+
1253
+ // src/business/risk-metrics.ts
1254
+ function calculateKnowledgeConcentration(params) {
1255
+ const { uniqueConceptFiles, totalFiles, singleAuthorFiles, orphanFiles } = params;
1256
+ const concentrationRatio = totalFiles > 0 ? (uniqueConceptFiles + singleAuthorFiles) / (totalFiles * 2) : 0;
1244
1257
  const score = Math.round(
1245
- budgetFactor * 0.35 + depthFactor * 0.2 + fragmentationFactor * 0.2 + consistencyFactor * 0.15 + fileFactor * 0.1
1258
+ Math.min(
1259
+ 100,
1260
+ concentrationRatio * 100 + orphanFiles / Math.max(1, totalFiles) * 20
1261
+ )
1246
1262
  );
1247
1263
  let rating;
1248
- if (score < 20) rating = "trivial";
1249
- else if (score < 40) rating = "easy";
1250
- else if (score < 60) rating = "moderate";
1251
- else if (score < 80) rating = "difficult";
1252
- else rating = "expert";
1264
+ if (score < 30) rating = "low";
1265
+ else if (score < 50) rating = "moderate";
1266
+ else if (score < 75) rating = "high";
1267
+ else rating = "critical";
1268
+ const recommendations = [];
1269
+ if (singleAuthorFiles > 0)
1270
+ recommendations.push(
1271
+ `Distribute knowledge for ${singleAuthorFiles} single-author files.`
1272
+ );
1273
+ if (orphanFiles > 0)
1274
+ recommendations.push(
1275
+ `Link ${orphanFiles} orphan files to the rest of the codebase.`
1276
+ );
1253
1277
  return {
1254
1278
  score,
1255
1279
  rating,
1256
- factors: [
1257
- {
1258
- name: "Context Budget",
1259
- contribution: Math.round(budgetFactor * 0.35),
1260
- description: `${Math.round(contextBudget)} tokens required (${modelTier} model tier: ideal <${idealBudget.toLocaleString()})`
1261
- },
1262
- {
1263
- name: "Import Depth",
1264
- contribution: Math.round(depthFactor * 0.2),
1265
- description: `${importDepth.toFixed(1)} average levels (ideal <${idealDepth} for ${modelTier})`
1266
- },
1267
- {
1268
- name: "Code Fragmentation",
1269
- contribution: Math.round(fragmentationFactor * 0.2),
1270
- description: `${(fragmentation * 100).toFixed(0)}% fragmentation`
1271
- },
1272
- {
1273
- name: "Consistency",
1274
- contribution: Math.round(consistencyFactor * 0.15),
1275
- description: `${consistencyScore}/100 consistency score`
1276
- },
1277
- {
1278
- name: "Project Scale",
1279
- contribution: Math.round(fileFactor * 0.1),
1280
- description: `${totalFiles} files analyzed`
1281
- }
1282
- ]
1280
+ recommendations,
1281
+ analysis: {
1282
+ uniqueConceptFiles,
1283
+ totalFiles,
1284
+ concentrationRatio,
1285
+ singleAuthorFiles,
1286
+ orphanFiles
1287
+ }
1288
+ };
1289
+ }
1290
+ function calculateDebtInterest(principal, monthlyGrowthRate) {
1291
+ const monthlyRate = monthlyGrowthRate;
1292
+ const annualRate = Math.pow(1 + monthlyRate, 12) - 1;
1293
+ const monthlyCost = principal * monthlyRate;
1294
+ return {
1295
+ monthlyRate,
1296
+ annualRate,
1297
+ principal,
1298
+ monthlyCost,
1299
+ projections: {
1300
+ months6: principal * Math.pow(1 + monthlyRate, 6),
1301
+ months12: principal * Math.pow(1 + monthlyRate, 12),
1302
+ months24: principal * Math.pow(1 + monthlyRate, 24)
1303
+ }
1304
+ };
1305
+ }
1306
+
1307
+ // src/business/comprehension-metrics.ts
1308
+ function calculateTechnicalValueChain(params) {
1309
+ const { businessLogicDensity, dataAccessComplexity, apiSurfaceArea } = params;
1310
+ const score = (businessLogicDensity * 0.5 + (1 - dataAccessComplexity / 10) * 0.3 + (1 - apiSurfaceArea / 20) * 0.2) * 100;
1311
+ return {
1312
+ score: Math.round(Math.max(0, Math.min(100, score))),
1313
+ density: businessLogicDensity,
1314
+ complexity: dataAccessComplexity,
1315
+ surface: apiSurfaceArea
1316
+ };
1317
+ }
1318
+ function calculateComprehensionDifficulty(contextBudget, importDepth, fragmentation, modelTier = "frontier") {
1319
+ const tierMap = {
1320
+ compact: "compact",
1321
+ standard: "standard",
1322
+ extended: "extended",
1323
+ frontier: "frontier",
1324
+ easy: "frontier",
1325
+ // Map legacy 'easy' to 'frontier'
1326
+ moderate: "standard",
1327
+ difficult: "compact"
1328
+ };
1329
+ const tier = tierMap[modelTier] || "frontier";
1330
+ const threshold = CONTEXT_TIER_THRESHOLDS[tier];
1331
+ const budgetRatio = contextBudget / threshold.idealTokens;
1332
+ const score = (budgetRatio * 0.6 + importDepth / 10 * 0.2 + fragmentation * 0.2) * 100;
1333
+ const finalScore = Math.round(Math.max(0, Math.min(100, score)));
1334
+ let rating;
1335
+ if (finalScore < 20) rating = "trivial";
1336
+ else if (finalScore < 40) rating = "easy";
1337
+ else if (finalScore < 60) rating = "moderate";
1338
+ else if (finalScore < 85) rating = "difficult";
1339
+ else rating = "expert";
1340
+ return {
1341
+ score: finalScore,
1342
+ rating,
1343
+ factors: { budgetRatio, depthRatio: importDepth / 10, fragmentation }
1344
+ };
1345
+ }
1346
+
1347
+ // src/business-metrics.ts
1348
+ function calculateBusinessROI(params) {
1349
+ const model = getModelPreset(params.modelId || "claude-4.6");
1350
+ const devCount = params.developerCount || 5;
1351
+ const budget = calculateTokenBudget({
1352
+ totalContextTokens: params.tokenWaste * 2.5,
1353
+ wastedTokens: {
1354
+ duplication: params.tokenWaste * 0.7,
1355
+ fragmentation: params.tokenWaste * 0.3,
1356
+ chattiness: 0
1357
+ }
1358
+ });
1359
+ const cost = estimateCostFromBudget(budget, model, {
1360
+ developerCount: devCount
1361
+ });
1362
+ const productivity = calculateProductivityImpact(params.issues);
1363
+ const monthlySavings = cost.total;
1364
+ const productivityGainHours = productivity.totalHours;
1365
+ const annualValue = (monthlySavings + productivityGainHours * 75) * 12;
1366
+ return {
1367
+ monthlySavings: Math.round(monthlySavings),
1368
+ productivityGainHours: Math.round(productivityGainHours),
1369
+ annualValue: Math.round(annualValue)
1283
1370
  };
1284
1371
  }
1285
1372
  function formatCost(cost) {
@@ -1305,220 +1392,6 @@ function formatHours(hours) {
1305
1392
  function formatAcceptanceRate(rate) {
1306
1393
  return `${Math.round(rate * 100)}%`;
1307
1394
  }
1308
- function calculateScoreTrend(history) {
1309
- if (history.length < 2) {
1310
- return {
1311
- direction: "stable",
1312
- change30Days: 0,
1313
- change90Days: 0,
1314
- velocity: 0,
1315
- projectedScore: history[0]?.overallScore || 100
1316
- };
1317
- }
1318
- const now = /* @__PURE__ */ new Date();
1319
- const thirtyDaysAgo = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1e3);
1320
- const ninetyDaysAgo = new Date(now.getTime() - 90 * 24 * 60 * 60 * 1e3);
1321
- const last30Days = history.filter(
1322
- (e) => new Date(e.timestamp) >= thirtyDaysAgo
1323
- );
1324
- const last90Days = history.filter(
1325
- (e) => new Date(e.timestamp) >= ninetyDaysAgo
1326
- );
1327
- const currentScore = history[history.length - 1].overallScore;
1328
- const thirtyDaysAgoScore = last30Days[0]?.overallScore || currentScore;
1329
- const ninetyDaysAgoScore = last90Days[0]?.overallScore || thirtyDaysAgoScore;
1330
- const change30Days = currentScore - thirtyDaysAgoScore;
1331
- const change90Days = currentScore - ninetyDaysAgoScore;
1332
- const weeksOfData = Math.max(1, history.length / 7);
1333
- const totalChange = currentScore - history[0].overallScore;
1334
- const velocity = totalChange / weeksOfData;
1335
- let direction;
1336
- if (change30Days > 3) direction = "improving";
1337
- else if (change30Days < -3) direction = "degrading";
1338
- else direction = "stable";
1339
- const projectedScore = Math.max(
1340
- 0,
1341
- Math.min(100, currentScore + velocity * 4)
1342
- );
1343
- return {
1344
- direction,
1345
- change30Days,
1346
- change90Days,
1347
- velocity: Math.round(velocity * 10) / 10,
1348
- projectedScore: Math.round(projectedScore)
1349
- };
1350
- }
1351
- function calculateRemediationVelocity(history, currentIssues) {
1352
- if (history.length < 2) {
1353
- return {
1354
- issuesFixedThisWeek: 0,
1355
- avgIssuesPerWeek: 0,
1356
- trend: "stable",
1357
- estimatedCompletionWeeks: currentIssues > 0 ? Infinity : 0
1358
- };
1359
- }
1360
- const now = /* @__PURE__ */ new Date();
1361
- const oneWeekAgo = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1e3);
1362
- const twoWeeksAgo = new Date(now.getTime() - 14 * 24 * 60 * 60 * 1e3);
1363
- const thisWeek = history.filter((e) => new Date(e.timestamp) >= oneWeekAgo);
1364
- const lastWeek = history.filter(
1365
- (e) => new Date(e.timestamp) >= twoWeeksAgo && new Date(e.timestamp) < oneWeekAgo
1366
- );
1367
- const issuesFixedThisWeek = thisWeek.length > 1 ? thisWeek[0].totalIssues - thisWeek[thisWeek.length - 1].totalIssues : 0;
1368
- const totalIssuesFixed = history[0].totalIssues - history[history.length - 1].totalIssues;
1369
- const weeksOfData = Math.max(1, history.length / 7);
1370
- const avgIssuesPerWeek = totalIssuesFixed / weeksOfData;
1371
- let trend;
1372
- if (lastWeek.length > 1) {
1373
- const lastWeekFixed = lastWeek[0].totalIssues - lastWeek[lastWeek.length - 1].totalIssues;
1374
- if (issuesFixedThisWeek > lastWeekFixed * 1.2) trend = "accelerating";
1375
- else if (issuesFixedThisWeek < lastWeekFixed * 0.8) trend = "decelerating";
1376
- else trend = "stable";
1377
- } else {
1378
- trend = "stable";
1379
- }
1380
- const estimatedCompletionWeeks = avgIssuesPerWeek > 0 ? Math.ceil(currentIssues / avgIssuesPerWeek) : Infinity;
1381
- return {
1382
- issuesFixedThisWeek: Math.max(0, issuesFixedThisWeek),
1383
- avgIssuesPerWeek: Math.round(avgIssuesPerWeek * 10) / 10,
1384
- trend,
1385
- estimatedCompletionWeeks
1386
- };
1387
- }
1388
- function calculateKnowledgeConcentration(files, authorData) {
1389
- if (files.length === 0) {
1390
- return {
1391
- score: 0,
1392
- rating: "low",
1393
- analysis: {
1394
- uniqueConceptFiles: 0,
1395
- totalFiles: 0,
1396
- concentrationRatio: 0,
1397
- singleAuthorFiles: 0,
1398
- orphanFiles: 0
1399
- },
1400
- recommendations: ["No files to analyze"]
1401
- };
1402
- }
1403
- const orphanFiles = files.filter(
1404
- (f) => f.exports < 2 && f.imports < 2
1405
- ).length;
1406
- const avgExports = files.reduce((sum, f) => sum + f.exports, 0) / files.length;
1407
- const uniqueConceptFiles = files.filter(
1408
- (f) => f.exports > avgExports * 2
1409
- ).length;
1410
- const totalExports = files.reduce((sum, f) => sum + f.exports, 0);
1411
- const concentrationRatio = totalExports > 0 ? uniqueConceptFiles / files.length : 0;
1412
- let singleAuthorFiles = 0;
1413
- if (authorData) {
1414
- for (const files2 of authorData.values()) {
1415
- if (files2.length === 1) singleAuthorFiles++;
1416
- }
1417
- }
1418
- const orphanRisk = orphanFiles / files.length * 30;
1419
- const uniqueRisk = concentrationRatio * 40;
1420
- const singleAuthorRisk = authorData ? singleAuthorFiles / files.length * 30 : 0;
1421
- const score = Math.min(
1422
- 100,
1423
- Math.round(orphanRisk + uniqueRisk + singleAuthorRisk)
1424
- );
1425
- let rating;
1426
- if (score < 20) rating = "low";
1427
- else if (score < 40) rating = "moderate";
1428
- else if (score < 70) rating = "high";
1429
- else rating = "critical";
1430
- const recommendations = [];
1431
- if (orphanFiles > files.length * 0.2) {
1432
- recommendations.push(
1433
- `Reduce ${orphanFiles} orphan files by connecting them to main modules`
1434
- );
1435
- }
1436
- if (uniqueConceptFiles > files.length * 0.1) {
1437
- recommendations.push(
1438
- "Distribute high-export files into more focused modules"
1439
- );
1440
- }
1441
- if (authorData && singleAuthorFiles > files.length * 0.3) {
1442
- recommendations.push(
1443
- "Increase knowledge sharing to reduce single-author dependencies"
1444
- );
1445
- }
1446
- return {
1447
- score,
1448
- rating,
1449
- analysis: {
1450
- uniqueConceptFiles,
1451
- totalFiles: files.length,
1452
- concentrationRatio: Math.round(concentrationRatio * 100) / 100,
1453
- singleAuthorFiles,
1454
- orphanFiles
1455
- },
1456
- recommendations
1457
- };
1458
- }
1459
- function calculateTechnicalDebtInterest(params) {
1460
- const { currentMonthlyCost, issues, monthsOpen } = params;
1461
- const criticalCount = issues.filter((i) => i.severity === "critical").length;
1462
- const majorCount = issues.filter((i) => i.severity === "major").length;
1463
- const minorCount = issues.filter((i) => i.severity === "minor").length;
1464
- const severityWeight = (criticalCount * 3 + majorCount * 2 + minorCount * 1) / Math.max(1, issues.length);
1465
- const baseRate = 0.02 + severityWeight * 0.01;
1466
- const timeMultiplier = Math.max(1, 1 + monthsOpen * 0.1);
1467
- const monthlyRate = baseRate * timeMultiplier;
1468
- const projectDebt = (principal2, months) => {
1469
- let debt = principal2;
1470
- for (let i = 0; i < months; i++) {
1471
- debt = debt * (1 + monthlyRate);
1472
- }
1473
- return Math.round(debt);
1474
- };
1475
- const principal = currentMonthlyCost * 12;
1476
- const projections = {
1477
- months6: projectDebt(principal, 6),
1478
- months12: projectDebt(principal, 12),
1479
- months24: projectDebt(principal, 24)
1480
- };
1481
- return {
1482
- monthlyRate: Math.round(monthlyRate * 1e4) / 100,
1483
- annualRate: Math.round((Math.pow(1 + monthlyRate, 12) - 1) * 1e4) / 100,
1484
- principal,
1485
- projections,
1486
- monthlyCost: Math.round(currentMonthlyCost * (1 + monthlyRate) * 100) / 100
1487
- };
1488
- }
1489
- function getDebtBreakdown(patternCost, contextCost, consistencyCost) {
1490
- const breakdowns = [
1491
- {
1492
- category: "Semantic Duplication",
1493
- currentCost: patternCost,
1494
- monthlyGrowthRate: 5,
1495
- // Grows as devs copy-paste
1496
- priority: patternCost > 1e3 ? "high" : "medium",
1497
- fixCost: patternCost * 3
1498
- // Fixing costs 3x current waste
1499
- },
1500
- {
1501
- category: "Context Fragmentation",
1502
- currentCost: contextCost,
1503
- monthlyGrowthRate: 3,
1504
- // Grows with new features
1505
- priority: contextCost > 500 ? "high" : "medium",
1506
- fixCost: contextCost * 2.5
1507
- },
1508
- {
1509
- category: "Consistency Issues",
1510
- currentCost: consistencyCost,
1511
- monthlyGrowthRate: 2,
1512
- // Grows with new devs
1513
- priority: consistencyCost > 200 ? "medium" : "low",
1514
- fixCost: consistencyCost * 1.5
1515
- }
1516
- ];
1517
- return breakdowns.sort((a, b) => {
1518
- const priorityOrder = { high: 0, medium: 1, low: 2 };
1519
- return priorityOrder[a.priority] - priorityOrder[b.priority];
1520
- });
1521
- }
1522
1395
  function generateValueChain(params) {
1523
1396
  const { issueType, count, severity } = params;
1524
1397
  const impacts = {
@@ -1558,9 +1431,7 @@ function generateValueChain(params) {
1558
1431
  },
1559
1432
  businessOutcome: {
1560
1433
  directCost: count * 12,
1561
- // Placeholder linear cost
1562
1434
  opportunityCost: productivityLoss * 15e3,
1563
- // Monthly avg dev cost $15k
1564
1435
  riskLevel: impact.risk
1565
1436
  }
1566
1437
  };
@@ -2004,7 +1875,9 @@ var ParserFactory = class _ParserFactory {
2004
1875
  registerParser(parser) {
2005
1876
  this.parsers.set(parser.language, parser);
2006
1877
  parser.extensions.forEach((ext) => {
2007
- this.extensionMap.set(ext, parser.language);
1878
+ const lang = LANGUAGE_EXTENSIONS[ext] || parser.language;
1879
+ this.extensionMap.set(ext, lang);
1880
+ this.parsers.set(lang, parser);
2008
1881
  });
2009
1882
  }
2010
1883
  /**
@@ -2073,7 +1946,55 @@ function getSupportedLanguages() {
2073
1946
  return ParserFactory.getInstance().getSupportedLanguages();
2074
1947
  }
2075
1948
 
2076
- // src/future-proof-metrics.ts
1949
+ // src/metrics/remediation-utils.ts
1950
+ function collectFutureProofRecommendations(params) {
1951
+ const recommendations = [];
1952
+ for (const rec of params.aiSignalClarity.recommendations) {
1953
+ recommendations.push({ action: rec, estimatedImpact: 8, priority: "high" });
1954
+ }
1955
+ for (const rec of params.agentGrounding.recommendations) {
1956
+ recommendations.push({
1957
+ action: rec,
1958
+ estimatedImpact: 6,
1959
+ priority: "medium"
1960
+ });
1961
+ }
1962
+ for (const rec of params.testability.recommendations) {
1963
+ const priority = params.testability.aiChangeSafetyRating === "blind-risk" ? "high" : "medium";
1964
+ recommendations.push({ action: rec, estimatedImpact: 10, priority });
1965
+ }
1966
+ for (const rec of params.patternEntropy.recommendations) {
1967
+ recommendations.push({ action: rec, estimatedImpact: 5, priority: "low" });
1968
+ }
1969
+ if (params.conceptCohesion.rating === "poor") {
1970
+ recommendations.push({
1971
+ action: "Improve concept cohesion by grouping related exports",
1972
+ estimatedImpact: 8,
1973
+ priority: "high"
1974
+ });
1975
+ }
1976
+ if (params.docDrift) {
1977
+ for (const rec of params.docDrift.recommendations) {
1978
+ recommendations.push({
1979
+ action: rec,
1980
+ estimatedImpact: 8,
1981
+ priority: "high"
1982
+ });
1983
+ }
1984
+ }
1985
+ if (params.dependencyHealth) {
1986
+ for (const rec of params.dependencyHealth.recommendations) {
1987
+ recommendations.push({
1988
+ action: rec,
1989
+ estimatedImpact: 7,
1990
+ priority: "medium"
1991
+ });
1992
+ }
1993
+ }
1994
+ return recommendations;
1995
+ }
1996
+
1997
+ // src/metrics/cognitive-load.ts
2077
1998
  function calculateCognitiveLoad(params) {
2078
1999
  const {
2079
2000
  linesOfCode,
@@ -2132,13 +2053,20 @@ function calculateCognitiveLoad(params) {
2132
2053
  }
2133
2054
  };
2134
2055
  }
2056
+
2057
+ // src/metrics/semantic-distance.ts
2135
2058
  function calculateSemanticDistance(params) {
2136
- const { file1, file2, file1Domain, file2Domain, sharedDependencies } = params;
2059
+ const {
2060
+ file1,
2061
+ file2,
2062
+ file1Domain,
2063
+ file2Domain,
2064
+ sharedDependencies,
2065
+ file1Imports,
2066
+ file2Imports
2067
+ } = params;
2137
2068
  const domainDistance = file1Domain === file2Domain ? 0 : file1Domain && file2Domain ? 0.5 : 0.8;
2138
- const importOverlap = sharedDependencies.length / Math.max(
2139
- 1,
2140
- Math.min(params.file1Imports.length, params.file2Imports.length)
2141
- );
2069
+ const importOverlap = sharedDependencies.length / Math.max(1, Math.min(file1Imports.length, file2Imports.length));
2142
2070
  const importDistance = 1 - importOverlap;
2143
2071
  const distance = domainDistance * 0.4 + importDistance * 0.3 + (sharedDependencies.length > 0 ? 0 : 0.3);
2144
2072
  let relationship;
@@ -2157,6 +2085,8 @@ function calculateSemanticDistance(params) {
2157
2085
  reason: relationship === "same-domain" ? `Both in "${file1Domain}" domain` : relationship === "cross-domain" ? `Share ${sharedDependencies.length} dependency(ies)` : "No strong semantic relationship detected"
2158
2086
  };
2159
2087
  }
2088
+
2089
+ // src/metrics/structural-metrics.ts
2160
2090
  function calculatePatternEntropy(files) {
2161
2091
  if (files.length === 0) {
2162
2092
  return {
@@ -2206,23 +2136,18 @@ function calculatePatternEntropy(files) {
2206
2136
  else if (normalizedEntropy < 0.8) rating = "fragmented";
2207
2137
  else rating = "chaotic";
2208
2138
  const recommendations = [];
2209
- if (normalizedEntropy > 0.5) {
2139
+ if (normalizedEntropy > 0.5)
2210
2140
  recommendations.push(
2211
2141
  `Consolidate ${files.length} files into fewer directories by domain`
2212
2142
  );
2213
- }
2214
- if (dirGroups.size > 5) {
2143
+ if (dirGroups.size > 5)
2215
2144
  recommendations.push(
2216
2145
  "Consider barrel exports to reduce directory navigation"
2217
2146
  );
2218
- }
2219
- if (gini > 0.5) {
2147
+ if (gini > 0.5)
2220
2148
  recommendations.push("Redistribute files more evenly across directories");
2221
- }
2222
- const firstFile = files.length > 0 ? files[0] : null;
2223
- const domainValue = firstFile ? firstFile.domain : "mixed";
2224
2149
  return {
2225
- domain: domainValue,
2150
+ domain: files[0]?.domain || "mixed",
2226
2151
  entropy: Math.round(normalizedEntropy * 100) / 100,
2227
2152
  rating,
2228
2153
  distribution: {
@@ -2253,9 +2178,8 @@ function calculateConceptCohesion(params) {
2253
2178
  }
2254
2179
  const uniqueDomains = new Set(allDomains);
2255
2180
  const domainCounts = /* @__PURE__ */ new Map();
2256
- for (const d of allDomains) {
2181
+ for (const d of allDomains)
2257
2182
  domainCounts.set(d, (domainCounts.get(d) || 0) + 1);
2258
- }
2259
2183
  const maxCount = Math.max(...Array.from(domainCounts.values()), 1);
2260
2184
  const domainConcentration = maxCount / allDomains.length;
2261
2185
  const exportPurposeClarity = 1 - (uniqueDomains.size - 1) / Math.max(1, exports2.length);
@@ -2275,59 +2199,8 @@ function calculateConceptCohesion(params) {
2275
2199
  }
2276
2200
  };
2277
2201
  }
2278
- function calculateFutureProofScore(params) {
2279
- const loadScore = 100 - params.cognitiveLoad.score;
2280
- const entropyScore = 100 - params.patternEntropy.entropy * 100;
2281
- const cohesionScore = params.conceptCohesion.score * 100;
2282
- const overall = Math.round(
2283
- loadScore * 0.4 + entropyScore * 0.3 + cohesionScore * 0.3
2284
- );
2285
- const factors = [
2286
- {
2287
- name: "Cognitive Load",
2288
- impact: Math.round(loadScore - 50),
2289
- description: params.cognitiveLoad.rating
2290
- },
2291
- {
2292
- name: "Pattern Entropy",
2293
- impact: Math.round(entropyScore - 50),
2294
- description: params.patternEntropy.rating
2295
- },
2296
- {
2297
- name: "Concept Cohesion",
2298
- impact: Math.round(cohesionScore - 50),
2299
- description: params.conceptCohesion.rating
2300
- }
2301
- ];
2302
- const recommendations = [];
2303
- for (const rec of params.patternEntropy.recommendations) {
2304
- recommendations.push({
2305
- action: rec,
2306
- estimatedImpact: 5,
2307
- priority: "medium"
2308
- });
2309
- }
2310
- if (params.conceptCohesion.rating === "poor") {
2311
- recommendations.push({
2312
- action: "Improve concept cohesion by grouping related exports",
2313
- estimatedImpact: 8,
2314
- priority: "high"
2315
- });
2316
- }
2317
- const semanticDistanceAvg = params.semanticDistances && params.semanticDistances.length > 0 ? params.semanticDistances.reduce((s, d) => s + d.distance, 0) / params.semanticDistances.length : 0;
2318
- return {
2319
- toolName: "future-proof",
2320
- score: overall,
2321
- rawMetrics: {
2322
- cognitiveLoadScore: params.cognitiveLoad.score,
2323
- entropyScore: params.patternEntropy.entropy,
2324
- cohesionScore: params.conceptCohesion.score,
2325
- semanticDistanceAvg
2326
- },
2327
- factors,
2328
- recommendations
2329
- };
2330
- }
2202
+
2203
+ // src/metrics/ai-signal-clarity.ts
2331
2204
  function calculateAiSignalClarity(params) {
2332
2205
  const {
2333
2206
  overloadedSymbols,
@@ -2349,75 +2222,53 @@ function calculateAiSignalClarity(params) {
2349
2222
  recommendations: []
2350
2223
  };
2351
2224
  }
2352
- const overloadRatio = Math.min(
2353
- 1,
2354
- overloadedSymbols / Math.max(1, totalSymbols)
2355
- );
2225
+ const overloadRatio = overloadedSymbols / Math.max(1, totalSymbols);
2356
2226
  const overloadSignal = {
2357
2227
  name: "Symbol Overloading",
2358
2228
  count: overloadedSymbols,
2359
- riskContribution: Math.round(overloadRatio * 100 * 0.25),
2360
- // 25% weight
2229
+ riskContribution: Math.round(Math.min(1, overloadRatio) * 100 * 0.25),
2361
2230
  description: `${overloadedSymbols} overloaded symbols \u2014 AI picks wrong signature`
2362
2231
  };
2363
- const magicRatio = Math.min(1, magicLiterals / Math.max(1, totalSymbols * 2));
2232
+ const magicRatio = magicLiterals / Math.max(1, totalSymbols * 2);
2364
2233
  const magicSignal = {
2365
2234
  name: "Magic Literals",
2366
2235
  count: magicLiterals,
2367
- riskContribution: Math.round(magicRatio * 100 * 0.2),
2368
- // 20% weight
2236
+ riskContribution: Math.round(Math.min(1, magicRatio) * 100 * 0.2),
2369
2237
  description: `${magicLiterals} unnamed constants \u2014 AI invents wrong values`
2370
2238
  };
2371
- const trapRatio = Math.min(1, booleanTraps / Math.max(1, totalSymbols));
2239
+ const trapRatio = booleanTraps / Math.max(1, totalSymbols);
2372
2240
  const trapSignal = {
2373
2241
  name: "Boolean Traps",
2374
2242
  count: booleanTraps,
2375
- riskContribution: Math.round(trapRatio * 100 * 0.2),
2376
- // 20% weight
2243
+ riskContribution: Math.round(Math.min(1, trapRatio) * 100 * 0.2),
2377
2244
  description: `${booleanTraps} boolean trap parameters \u2014 AI inverts intent`
2378
2245
  };
2379
- const sideEffectRatio = Math.min(
2380
- 1,
2381
- implicitSideEffects / Math.max(1, totalExports)
2382
- );
2246
+ const sideEffectRatio = implicitSideEffects / Math.max(1, totalExports);
2383
2247
  const sideEffectSignal = {
2384
2248
  name: "Implicit Side Effects",
2385
2249
  count: implicitSideEffects,
2386
- riskContribution: Math.round(sideEffectRatio * 100 * 0.15),
2387
- // 15% weight
2250
+ riskContribution: Math.round(Math.min(1, sideEffectRatio) * 100 * 0.15),
2388
2251
  description: `${implicitSideEffects} functions with implicit side effects \u2014 AI misses contracts`
2389
2252
  };
2390
- const callbackRatio = Math.min(
2391
- 1,
2392
- deepCallbacks / Math.max(1, totalSymbols * 0.1)
2393
- );
2253
+ const callbackRatio = deepCallbacks / Math.max(1, totalSymbols * 0.1);
2394
2254
  const callbackSignal = {
2395
2255
  name: "Callback Nesting",
2396
2256
  count: deepCallbacks,
2397
- riskContribution: Math.round(callbackRatio * 100 * 0.1),
2398
- // 10% weight
2257
+ riskContribution: Math.round(Math.min(1, callbackRatio) * 100 * 0.1),
2399
2258
  description: `${deepCallbacks} deep callback chains \u2014 AI loses control flow context`
2400
2259
  };
2401
- const ambiguousRatio = Math.min(
2402
- 1,
2403
- ambiguousNames / Math.max(1, totalSymbols)
2404
- );
2260
+ const ambiguousRatio = ambiguousNames / Math.max(1, totalSymbols);
2405
2261
  const ambiguousSignal = {
2406
2262
  name: "Ambiguous Names",
2407
2263
  count: ambiguousNames,
2408
- riskContribution: Math.round(ambiguousRatio * 100 * 0.1),
2409
- // 10% weight
2264
+ riskContribution: Math.round(Math.min(1, ambiguousRatio) * 100 * 0.1),
2410
2265
  description: `${ambiguousNames} non-descriptive identifiers \u2014 AI guesses wrong intent`
2411
2266
  };
2412
- const undocRatio = Math.min(
2413
- 1,
2414
- undocumentedExports / Math.max(1, totalExports)
2415
- );
2267
+ const undocRatio = undocumentedExports / Math.max(1, totalExports);
2416
2268
  const undocSignal = {
2417
2269
  name: "Undocumented Exports",
2418
2270
  count: undocumentedExports,
2419
- riskContribution: Math.round(undocRatio * 100 * 0.1),
2420
- // 10% weight
2271
+ riskContribution: Math.round(Math.min(1, undocRatio) * 100 * 0.1),
2421
2272
  description: `${undocumentedExports} public functions without docs \u2014 AI fabricates behavior`
2422
2273
  };
2423
2274
  const signals = [
@@ -2442,33 +2293,28 @@ function calculateAiSignalClarity(params) {
2442
2293
  const topSignal = signals.reduce(
2443
2294
  (a, b) => a.riskContribution > b.riskContribution ? a : b
2444
2295
  );
2445
- const topRisk = topSignal.riskContribution > 0 ? topSignal.description : "No significant AI signal claritys detected";
2296
+ const topRisk = topSignal.riskContribution > 0 ? topSignal.description : "No significant issues detected";
2446
2297
  const recommendations = [];
2447
- if (overloadSignal.riskContribution > 5) {
2298
+ if (overloadSignal.riskContribution > 5)
2448
2299
  recommendations.push(
2449
2300
  `Rename ${overloadedSymbols} overloaded symbols to unique, intent-revealing names`
2450
2301
  );
2451
- }
2452
- if (magicSignal.riskContribution > 5) {
2302
+ if (magicSignal.riskContribution > 5)
2453
2303
  recommendations.push(
2454
2304
  `Extract ${magicLiterals} magic literals into named constants`
2455
2305
  );
2456
- }
2457
- if (trapSignal.riskContribution > 5) {
2306
+ if (trapSignal.riskContribution > 5)
2458
2307
  recommendations.push(
2459
2308
  `Replace ${booleanTraps} boolean traps with named options objects`
2460
2309
  );
2461
- }
2462
- if (undocSignal.riskContribution > 5) {
2310
+ if (undocSignal.riskContribution > 5)
2463
2311
  recommendations.push(
2464
2312
  `Add JSDoc/docstrings to ${undocumentedExports} undocumented public functions`
2465
2313
  );
2466
- }
2467
- if (sideEffectSignal.riskContribution > 5) {
2314
+ if (sideEffectSignal.riskContribution > 5)
2468
2315
  recommendations.push(
2469
2316
  "Mark functions with side effects explicitly in their names or docs"
2470
2317
  );
2471
- }
2472
2318
  return {
2473
2319
  score: Math.round(score),
2474
2320
  rating,
@@ -2477,6 +2323,8 @@ function calculateAiSignalClarity(params) {
2477
2323
  recommendations
2478
2324
  };
2479
2325
  }
2326
+
2327
+ // src/metrics/agent-grounding.ts
2480
2328
  function calculateAgentGrounding(params) {
2481
2329
  const {
2482
2330
  deepDirectories,
@@ -2491,25 +2339,33 @@ function calculateAgentGrounding(params) {
2491
2339
  inconsistentDomainTerms,
2492
2340
  domainVocabularySize
2493
2341
  } = params;
2494
- const deepDirRatio = totalDirectories > 0 ? deepDirectories / totalDirectories : 0;
2495
2342
  const structureClarityScore = Math.max(
2496
2343
  0,
2497
- Math.round(100 - deepDirRatio * 80)
2344
+ Math.round(
2345
+ 100 - (totalDirectories > 0 ? deepDirectories / totalDirectories * 80 : 0)
2346
+ )
2347
+ );
2348
+ const selfDocumentationScore = Math.max(
2349
+ 0,
2350
+ Math.round(100 - (totalFiles > 0 ? vagueFileNames / totalFiles * 90 : 0))
2498
2351
  );
2499
- const vagueRatio = totalFiles > 0 ? vagueFileNames / totalFiles : 0;
2500
- const selfDocumentationScore = Math.max(0, Math.round(100 - vagueRatio * 90));
2501
2352
  let entryPointScore = 60;
2502
2353
  if (hasRootReadme) entryPointScore += 25;
2503
2354
  if (readmeIsFresh) entryPointScore += 10;
2504
2355
  const barrelRatio = totalFiles > 0 ? barrelExports / (totalFiles * 0.1) : 0;
2505
2356
  entryPointScore += Math.round(Math.min(5, barrelRatio * 5));
2506
2357
  entryPointScore = Math.min(100, entryPointScore);
2507
- const untypedRatio = totalExports > 0 ? untypedExports / totalExports : 0;
2508
- const apiClarityScore = Math.max(0, Math.round(100 - untypedRatio * 70));
2509
- const inconsistencyRatio = domainVocabularySize > 0 ? inconsistentDomainTerms / domainVocabularySize : 0;
2358
+ const apiClarityScore = Math.max(
2359
+ 0,
2360
+ Math.round(
2361
+ 100 - (totalExports > 0 ? untypedExports / totalExports * 70 : 0)
2362
+ )
2363
+ );
2510
2364
  const domainConsistencyScore = Math.max(
2511
2365
  0,
2512
- Math.round(100 - inconsistencyRatio * 80)
2366
+ Math.round(
2367
+ 100 - (domainVocabularySize > 0 ? inconsistentDomainTerms / domainVocabularySize * 80 : 0)
2368
+ )
2513
2369
  );
2514
2370
  const score = Math.round(
2515
2371
  structureClarityScore * 0.2 + selfDocumentationScore * 0.25 + entryPointScore * 0.2 + apiClarityScore * 0.15 + domainConsistencyScore * 0.2
@@ -2521,35 +2377,30 @@ function calculateAgentGrounding(params) {
2521
2377
  else if (score >= 30) rating = "poor";
2522
2378
  else rating = "disorienting";
2523
2379
  const recommendations = [];
2524
- if (structureClarityScore < 70) {
2380
+ if (structureClarityScore < 70)
2525
2381
  recommendations.push(
2526
2382
  `Flatten ${deepDirectories} overly-deep directories to improve agent navigation`
2527
2383
  );
2528
- }
2529
- if (selfDocumentationScore < 70) {
2384
+ if (selfDocumentationScore < 70)
2530
2385
  recommendations.push(
2531
2386
  `Rename ${vagueFileNames} vague files (utils, helpers, misc) to domain-specific names`
2532
2387
  );
2533
- }
2534
- if (!hasRootReadme) {
2388
+ if (!hasRootReadme)
2535
2389
  recommendations.push(
2536
2390
  "Add a root README.md so agents understand the project context immediately"
2537
2391
  );
2538
- } else if (!readmeIsFresh) {
2392
+ else if (!readmeIsFresh)
2539
2393
  recommendations.push(
2540
2394
  "Update README.md \u2014 stale entry-point documentation disorients agents"
2541
2395
  );
2542
- }
2543
- if (apiClarityScore < 70) {
2396
+ if (apiClarityScore < 70)
2544
2397
  recommendations.push(
2545
2398
  `Add TypeScript types to ${untypedExports} untyped exports to improve API discoverability`
2546
2399
  );
2547
- }
2548
- if (domainConsistencyScore < 70) {
2400
+ if (domainConsistencyScore < 70)
2549
2401
  recommendations.push(
2550
2402
  `Unify ${inconsistentDomainTerms} inconsistent domain terms \u2014 agents need one word per concept`
2551
2403
  );
2552
- }
2553
2404
  return {
2554
2405
  score,
2555
2406
  rating,
@@ -2563,6 +2414,8 @@ function calculateAgentGrounding(params) {
2563
2414
  recommendations
2564
2415
  };
2565
2416
  }
2417
+
2418
+ // src/metrics/testability-index.ts
2566
2419
  function calculateTestabilityIndex(params) {
2567
2420
  const {
2568
2421
  testFiles,
@@ -2578,16 +2431,27 @@ function calculateTestabilityIndex(params) {
2578
2431
  } = params;
2579
2432
  const rawCoverageRatio = sourceFiles > 0 ? testFiles / sourceFiles : 0;
2580
2433
  const testCoverageRatio = Math.min(100, Math.round(rawCoverageRatio * 100));
2581
- const purityRatio = totalFunctions > 0 ? pureFunctions / totalFunctions : 0.5;
2582
- const purityScore = Math.round(purityRatio * 100);
2583
- const injectionRatio = totalClasses > 0 ? injectionPatterns / totalClasses : 0.5;
2434
+ const purityScore = Math.round(
2435
+ (totalFunctions > 0 ? pureFunctions / totalFunctions : 0.5) * 100
2436
+ );
2584
2437
  const dependencyInjectionScore = Math.round(
2585
- Math.min(100, injectionRatio * 100)
2438
+ Math.min(
2439
+ 100,
2440
+ (totalClasses > 0 ? injectionPatterns / totalClasses : 0.5) * 100
2441
+ )
2442
+ );
2443
+ const interfaceFocusScore = Math.max(
2444
+ 0,
2445
+ Math.round(
2446
+ 100 - (totalInterfaces > 0 ? bloatedInterfaces / totalInterfaces * 80 : 0)
2447
+ )
2448
+ );
2449
+ const observabilityScore = Math.max(
2450
+ 0,
2451
+ Math.round(
2452
+ 100 - (totalFunctions > 0 ? externalStateMutations / totalFunctions * 100 : 0)
2453
+ )
2586
2454
  );
2587
- const bloatedRatio = totalInterfaces > 0 ? bloatedInterfaces / totalInterfaces : 0;
2588
- const interfaceFocusScore = Math.max(0, Math.round(100 - bloatedRatio * 80));
2589
- const mutationRatio = totalFunctions > 0 ? externalStateMutations / totalFunctions : 0;
2590
- const observabilityScore = Math.max(0, Math.round(100 - mutationRatio * 100));
2591
2455
  const frameworkWeight = hasTestFramework ? 1 : 0.8;
2592
2456
  const rawScore = (testCoverageRatio * 0.3 + purityScore * 0.25 + dependencyInjectionScore * 0.2 + interfaceFocusScore * 0.1 + observabilityScore * 0.15) * frameworkWeight;
2593
2457
  const score = Math.max(0, Math.min(100, Math.round(rawScore)));
@@ -2604,32 +2468,28 @@ function calculateTestabilityIndex(params) {
2604
2468
  else if (rawCoverageRatio > 0) aiChangeSafetyRating = "high-risk";
2605
2469
  else aiChangeSafetyRating = "blind-risk";
2606
2470
  const recommendations = [];
2607
- if (!hasTestFramework) {
2471
+ if (!hasTestFramework)
2608
2472
  recommendations.push(
2609
2473
  "Add a testing framework (Jest, Vitest, pytest) \u2014 AI changes cannot be verified without tests"
2610
2474
  );
2611
- }
2612
2475
  if (rawCoverageRatio < 0.3) {
2613
2476
  const neededTests = Math.round(sourceFiles * 0.3 - testFiles);
2614
2477
  recommendations.push(
2615
2478
  `Add ~${neededTests} test files to reach 30% coverage ratio \u2014 minimum for safe AI assistance`
2616
2479
  );
2617
2480
  }
2618
- if (purityScore < 50) {
2481
+ if (purityScore < 50)
2619
2482
  recommendations.push(
2620
2483
  "Extract pure functions from side-effectful code \u2014 pure functions are trivially AI-testable"
2621
2484
  );
2622
- }
2623
- if (dependencyInjectionScore < 50 && totalClasses > 0) {
2485
+ if (dependencyInjectionScore < 50 && totalClasses > 0)
2624
2486
  recommendations.push(
2625
2487
  "Adopt dependency injection \u2014 makes classes mockable and AI-generated code verifiable"
2626
2488
  );
2627
- }
2628
- if (externalStateMutations > totalFunctions * 0.3) {
2489
+ if (externalStateMutations > totalFunctions * 0.3)
2629
2490
  recommendations.push(
2630
2491
  "Reduce direct state mutations \u2014 return values instead to improve observability"
2631
2492
  );
2632
- }
2633
2493
  return {
2634
2494
  score,
2635
2495
  rating,
@@ -2644,6 +2504,8 @@ function calculateTestabilityIndex(params) {
2644
2504
  recommendations
2645
2505
  };
2646
2506
  }
2507
+
2508
+ // src/metrics/doc-drift.ts
2647
2509
  function calculateDocDrift(params) {
2648
2510
  const {
2649
2511
  uncommentedExports,
@@ -2666,21 +2528,18 @@ function calculateDocDrift(params) {
2666
2528
  else if (finalScore < 85) rating = "high";
2667
2529
  else rating = "severe";
2668
2530
  const recommendations = [];
2669
- if (outdatedComments > 0) {
2531
+ if (outdatedComments > 0)
2670
2532
  recommendations.push(
2671
2533
  `Update or remove ${outdatedComments} outdated comments that contradict the code.`
2672
2534
  );
2673
- }
2674
- if (uncommentedRatio > 0.3) {
2535
+ if (uncommentedRatio > 0.3)
2675
2536
  recommendations.push(
2676
2537
  `Add JSDoc to ${uncommentedExports} uncommented exports.`
2677
2538
  );
2678
- }
2679
- if (undocumentedComplexity > 0) {
2539
+ if (undocumentedComplexity > 0)
2680
2540
  recommendations.push(
2681
2541
  `Explain the business logic for ${undocumentedComplexity} highly complex functions.`
2682
2542
  );
2683
- }
2684
2543
  return {
2685
2544
  score: finalScore,
2686
2545
  rating,
@@ -2692,6 +2551,8 @@ function calculateDocDrift(params) {
2692
2551
  recommendations
2693
2552
  };
2694
2553
  }
2554
+
2555
+ // src/metrics/dependency-health.ts
2695
2556
  function calculateDependencyHealth(params) {
2696
2557
  const {
2697
2558
  totalPackages,
@@ -2704,8 +2565,12 @@ function calculateDependencyHealth(params) {
2704
2565
  const outdatedScore = Math.max(0, 100 - outdatedRatio * 200);
2705
2566
  const deprecatedScore = Math.max(0, 100 - deprecatedRatio * 500);
2706
2567
  const skewScore = Math.max(0, 100 - trainingCutoffSkew * 100);
2707
- const rawScore = outdatedScore * 0.3 + deprecatedScore * 0.4 + skewScore * 0.3;
2708
- const score = Math.round(Math.min(100, Math.max(0, rawScore)));
2568
+ const score = Math.round(
2569
+ Math.min(
2570
+ 100,
2571
+ Math.max(0, outdatedScore * 0.3 + deprecatedScore * 0.4 + skewScore * 0.3)
2572
+ )
2573
+ );
2709
2574
  let rating;
2710
2575
  if (score >= 85) rating = "excellent";
2711
2576
  else if (score >= 70) rating = "good";
@@ -2720,33 +2585,22 @@ function calculateDependencyHealth(params) {
2720
2585
  else if (trainingCutoffSkew < 0.8) aiKnowledgeConfidence = "low";
2721
2586
  else aiKnowledgeConfidence = "blind";
2722
2587
  const recommendations = [];
2723
- if (deprecatedPackages > 0) {
2724
- recommendations.push(
2725
- `Replace ${deprecatedPackages} deprecated packages, as AI will struggle to find modern solutions.`
2726
- );
2727
- }
2728
- if (outdatedRatio > 0.2) {
2729
- recommendations.push(
2730
- `Update ${outdatedPackages} outdated packages to keep APIs aligned with AI training data.`
2731
- );
2732
- }
2733
- if (trainingCutoffSkew > 0.5) {
2734
- recommendations.push(
2735
- "High training cutoff skew detected. AI may hallucinate APIs that were introduced recently."
2736
- );
2737
- }
2588
+ if (deprecatedPackages > 0)
2589
+ recommendations.push(`Replace ${deprecatedPackages} deprecated packages.`);
2590
+ if (outdatedRatio > 0.2)
2591
+ recommendations.push(`Update ${outdatedPackages} outdated packages.`);
2592
+ if (trainingCutoffSkew > 0.5)
2593
+ recommendations.push("High training cutoff skew detected.");
2738
2594
  return {
2739
2595
  score,
2740
2596
  rating,
2741
- dimensions: {
2742
- outdatedPackages,
2743
- deprecatedPackages,
2744
- trainingCutoffSkew
2745
- },
2597
+ dimensions: { outdatedPackages, deprecatedPackages, trainingCutoffSkew },
2746
2598
  aiKnowledgeConfidence,
2747
2599
  recommendations
2748
2600
  };
2749
2601
  }
2602
+
2603
+ // src/metrics/change-amplification.ts
2750
2604
  function calculateChangeAmplification(params) {
2751
2605
  const { files } = params;
2752
2606
  if (files.length === 0) {
@@ -2759,15 +2613,16 @@ function calculateChangeAmplification(params) {
2759
2613
  recommendations: []
2760
2614
  };
2761
2615
  }
2762
- const hotspots = files.map((f) => {
2763
- const amplificationFactor = f.fanOut + f.fanIn * 0.5;
2764
- return { ...f, amplificationFactor };
2765
- }).sort((a, b) => b.amplificationFactor - a.amplificationFactor);
2616
+ const hotspots = files.map((f) => ({ ...f, amplificationFactor: f.fanOut + f.fanIn * 0.5 })).sort((a, b) => b.amplificationFactor - a.amplificationFactor);
2766
2617
  const maxAmplification = hotspots[0].amplificationFactor;
2767
2618
  const avgAmplification = hotspots.reduce((sum, h) => sum + h.amplificationFactor, 0) / hotspots.length;
2768
- let score = 100 - avgAmplification * 5;
2769
- if (maxAmplification > 20) score -= maxAmplification - 20;
2770
- score = Math.max(0, Math.min(100, score));
2619
+ let score = Math.max(
2620
+ 0,
2621
+ Math.min(
2622
+ 100,
2623
+ 100 - avgAmplification * 5 - (maxAmplification > 20 ? maxAmplification - 20 : 0)
2624
+ )
2625
+ );
2771
2626
  let rating = "isolated";
2772
2627
  if (score < 40) rating = "explosive";
2773
2628
  else if (score < 70) rating = "amplified";
@@ -2775,12 +2630,12 @@ function calculateChangeAmplification(params) {
2775
2630
  const recommendations = [];
2776
2631
  if (score < 70 && hotspots.length > 0) {
2777
2632
  recommendations.push(
2778
- `Refactor top hotspot '${hotspots[0].file}' to reduce coupling (fan-out: ${hotspots[0].fanOut}, fan-in: ${hotspots[0].fanIn}).`
2633
+ `Refactor top hotspot '${hotspots[0].file}' to reduce coupling.`
2779
2634
  );
2780
2635
  }
2781
2636
  if (maxAmplification > 30) {
2782
2637
  recommendations.push(
2783
- `Break down key bottlenecks with amplification factor > 30.`
2638
+ "Break down key bottlenecks with amplification factor > 30."
2784
2639
  );
2785
2640
  }
2786
2641
  return {
@@ -2792,6 +2647,61 @@ function calculateChangeAmplification(params) {
2792
2647
  recommendations
2793
2648
  };
2794
2649
  }
2650
+
2651
+ // src/future-proof-metrics.ts
2652
+ function calculateFutureProofScore(params) {
2653
+ const loadScore = 100 - params.cognitiveLoad.score;
2654
+ const entropyScore = 100 - params.patternEntropy.entropy * 100;
2655
+ const cohesionScore = params.conceptCohesion.score * 100;
2656
+ const overall = Math.round(
2657
+ loadScore * 0.4 + entropyScore * 0.3 + cohesionScore * 0.3
2658
+ );
2659
+ const factors = [
2660
+ {
2661
+ name: "Cognitive Load",
2662
+ impact: Math.round(loadScore - 50),
2663
+ description: params.cognitiveLoad.rating
2664
+ },
2665
+ {
2666
+ name: "Pattern Entropy",
2667
+ impact: Math.round(entropyScore - 50),
2668
+ description: params.patternEntropy.rating
2669
+ },
2670
+ {
2671
+ name: "Concept Cohesion",
2672
+ impact: Math.round(cohesionScore - 50),
2673
+ description: params.conceptCohesion.rating
2674
+ }
2675
+ ];
2676
+ const recommendations = [];
2677
+ for (const rec of params.patternEntropy.recommendations) {
2678
+ recommendations.push({
2679
+ action: rec,
2680
+ estimatedImpact: 5,
2681
+ priority: "medium"
2682
+ });
2683
+ }
2684
+ if (params.conceptCohesion.rating === "poor") {
2685
+ recommendations.push({
2686
+ action: "Improve concept cohesion by grouping related exports",
2687
+ estimatedImpact: 8,
2688
+ priority: "high"
2689
+ });
2690
+ }
2691
+ const semanticDistanceAvg = params.semanticDistances?.length ? params.semanticDistances.reduce((s, d) => s + d.distance, 0) / params.semanticDistances.length : 0;
2692
+ return {
2693
+ toolName: "future-proof",
2694
+ score: overall,
2695
+ rawMetrics: {
2696
+ cognitiveLoadScore: params.cognitiveLoad.score,
2697
+ entropyScore: params.patternEntropy.entropy,
2698
+ cohesionScore: params.conceptCohesion.score,
2699
+ semanticDistanceAvg
2700
+ },
2701
+ factors,
2702
+ recommendations
2703
+ };
2704
+ }
2795
2705
  function calculateExtendedFutureProofScore(params) {
2796
2706
  const loadScore = 100 - params.cognitiveLoad.score;
2797
2707
  const entropyScore = 100 - params.patternEntropy.entropy * 100;
@@ -2800,7 +2710,7 @@ function calculateExtendedFutureProofScore(params) {
2800
2710
  const groundingScore = params.agentGrounding.score;
2801
2711
  const testabilityScore = params.testability.score;
2802
2712
  const docDriftScore = params.docDrift ? 100 - params.docDrift.score : 100;
2803
- const depsHealthScore = params.dependencyHealth ? params.dependencyHealth.score : 100;
2713
+ const depsHealthScore = params.dependencyHealth?.score ?? 100;
2804
2714
  let totalWeight = 0.8;
2805
2715
  let overall = loadScore * 0.15 + entropyScore * 0.1 + cohesionScore * 0.1 + aiSignalClarityScore * 0.15 + groundingScore * 0.15 + testabilityScore * 0.15;
2806
2716
  if (params.docDrift) {
@@ -2831,7 +2741,7 @@ function calculateExtendedFutureProofScore(params) {
2831
2741
  {
2832
2742
  name: "AI Signal Clarity",
2833
2743
  impact: Math.round(aiSignalClarityScore - 50),
2834
- description: `${params.aiSignalClarity.rating} risk (${params.aiSignalClarity.score}/100 raw)`
2744
+ description: `${params.aiSignalClarity.rating} risk`
2835
2745
  },
2836
2746
  {
2837
2747
  name: "Agent Grounding",
@@ -2841,60 +2751,25 @@ function calculateExtendedFutureProofScore(params) {
2841
2751
  {
2842
2752
  name: "Testability",
2843
2753
  impact: Math.round(testabilityScore - 50),
2844
- description: `${params.testability.rating} \u2014 AI changes are ${params.testability.aiChangeSafetyRating}`
2754
+ description: params.testability.rating
2845
2755
  }
2846
2756
  ];
2847
2757
  if (params.docDrift) {
2848
2758
  factors.push({
2849
2759
  name: "Documentation Drift",
2850
2760
  impact: Math.round(docDriftScore - 50),
2851
- description: `${params.docDrift.rating} risk of AI signal clarity from drift`
2761
+ description: params.docDrift.rating
2852
2762
  });
2853
2763
  }
2854
2764
  if (params.dependencyHealth) {
2855
2765
  factors.push({
2856
2766
  name: "Dependency Health",
2857
2767
  impact: Math.round(depsHealthScore - 50),
2858
- description: `${params.dependencyHealth.rating} health \u2014 AI knowledge is ${params.dependencyHealth.aiKnowledgeConfidence}`
2859
- });
2860
- }
2861
- const recommendations = [];
2862
- for (const rec of params.aiSignalClarity.recommendations) {
2863
- recommendations.push({ action: rec, estimatedImpact: 8, priority: "high" });
2864
- }
2865
- for (const rec of params.agentGrounding.recommendations) {
2866
- recommendations.push({
2867
- action: rec,
2868
- estimatedImpact: 6,
2869
- priority: "medium"
2768
+ description: params.dependencyHealth.rating
2870
2769
  });
2871
2770
  }
2872
- for (const rec of params.testability.recommendations) {
2873
- const priority = params.testability.aiChangeSafetyRating === "blind-risk" ? "high" : "medium";
2874
- recommendations.push({ action: rec, estimatedImpact: 10, priority });
2875
- }
2876
- for (const rec of params.patternEntropy.recommendations) {
2877
- recommendations.push({ action: rec, estimatedImpact: 5, priority: "low" });
2878
- }
2879
- if (params.docDrift) {
2880
- for (const rec of params.docDrift.recommendations) {
2881
- recommendations.push({
2882
- action: rec,
2883
- estimatedImpact: 8,
2884
- priority: "high"
2885
- });
2886
- }
2887
- }
2888
- if (params.dependencyHealth) {
2889
- for (const rec of params.dependencyHealth.recommendations) {
2890
- recommendations.push({
2891
- action: rec,
2892
- estimatedImpact: 7,
2893
- priority: "medium"
2894
- });
2895
- }
2896
- }
2897
- const semanticDistanceAvg = params.semanticDistances && params.semanticDistances.length > 0 ? params.semanticDistances.reduce((s, d) => s + d.distance, 0) / params.semanticDistances.length : 0;
2771
+ const recommendations = collectFutureProofRecommendations(params);
2772
+ const semanticDistanceAvg = params.semanticDistances?.length ? params.semanticDistances.reduce((s, d) => s + d.distance, 0) / params.semanticDistances.length : 0;
2898
2773
  return {
2899
2774
  toolName: "future-proof",
2900
2775
  score: overall,
@@ -3071,16 +2946,19 @@ function getRepoMetadata(directory) {
3071
2946
  ParseError,
3072
2947
  ParserFactory,
3073
2948
  PythonParser,
2949
+ SEVERITY_TIME_ESTIMATES,
3074
2950
  SIZE_ADJUSTED_THRESHOLDS,
3075
2951
  TOOL_NAME_MAP,
3076
2952
  TypeScriptParser,
3077
2953
  VAGUE_FILE_NAMES,
3078
2954
  calculateAgentGrounding,
3079
2955
  calculateAiSignalClarity,
2956
+ calculateBusinessROI,
3080
2957
  calculateChangeAmplification,
3081
2958
  calculateCognitiveLoad,
3082
2959
  calculateComprehensionDifficulty,
3083
2960
  calculateConceptCohesion,
2961
+ calculateDebtInterest,
3084
2962
  calculateDependencyHealth,
3085
2963
  calculateDocDrift,
3086
2964
  calculateExtendedFutureProofScore,
@@ -3091,10 +2969,8 @@ function getRepoMetadata(directory) {
3091
2969
  calculateOverallScore,
3092
2970
  calculatePatternEntropy,
3093
2971
  calculateProductivityImpact,
3094
- calculateRemediationVelocity,
3095
- calculateScoreTrend,
3096
2972
  calculateSemanticDistance,
3097
- calculateTechnicalDebtInterest,
2973
+ calculateTechnicalValueChain,
3098
2974
  calculateTestabilityIndex,
3099
2975
  calculateTokenBudget,
3100
2976
  clearHistory,
@@ -3110,7 +2986,6 @@ function getRepoMetadata(directory) {
3110
2986
  formatToolScore,
3111
2987
  generateHTML,
3112
2988
  generateValueChain,
3113
- getDebtBreakdown,
3114
2989
  getElapsedTime,
3115
2990
  getFileCommitTimestamps,
3116
2991
  getFileExtension,
@@ -3124,6 +2999,9 @@ function getRepoMetadata(directory) {
3124
2999
  getRatingWithContext,
3125
3000
  getRecommendedThreshold,
3126
3001
  getRepoMetadata,
3002
+ getSafetyIcon,
3003
+ getScoreBar,
3004
+ getSeverityColor,
3127
3005
  getSupportedLanguages,
3128
3006
  getToolWeight,
3129
3007
  handleCLIError,