@aiready/core 0.9.23 → 0.9.26
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/client.d.mts +91 -1
- package/dist/client.d.ts +91 -1
- package/dist/index.d.mts +318 -3
- package/dist/index.d.ts +318 -3
- package/dist/index.js +730 -0
- package/dist/index.mjs +698 -1
- package/package.json +4 -3
package/dist/index.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __export = (target, all) => {
|
|
7
9
|
for (var name in all)
|
|
@@ -15,11 +17,20 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
17
|
}
|
|
16
18
|
return to;
|
|
17
19
|
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
18
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
29
|
|
|
20
30
|
// src/index.ts
|
|
21
31
|
var index_exports = {};
|
|
22
32
|
__export(index_exports, {
|
|
33
|
+
DEFAULT_COST_CONFIG: () => DEFAULT_COST_CONFIG,
|
|
23
34
|
DEFAULT_EXCLUDE: () => DEFAULT_EXCLUDE,
|
|
24
35
|
DEFAULT_TOOL_WEIGHTS: () => DEFAULT_TOOL_WEIGHTS,
|
|
25
36
|
LANGUAGE_EXTENSIONS: () => LANGUAGE_EXTENSIONS,
|
|
@@ -29,16 +40,35 @@ __export(index_exports, {
|
|
|
29
40
|
PythonParser: () => PythonParser,
|
|
30
41
|
TOOL_NAME_MAP: () => TOOL_NAME_MAP,
|
|
31
42
|
TypeScriptParser: () => TypeScriptParser,
|
|
43
|
+
calculateCognitiveLoad: () => calculateCognitiveLoad,
|
|
44
|
+
calculateComprehensionDifficulty: () => calculateComprehensionDifficulty,
|
|
45
|
+
calculateConceptCohesion: () => calculateConceptCohesion,
|
|
46
|
+
calculateFutureProofScore: () => calculateFutureProofScore,
|
|
32
47
|
calculateImportSimilarity: () => calculateImportSimilarity,
|
|
48
|
+
calculateKnowledgeConcentration: () => calculateKnowledgeConcentration,
|
|
49
|
+
calculateMonthlyCost: () => calculateMonthlyCost,
|
|
33
50
|
calculateOverallScore: () => calculateOverallScore,
|
|
51
|
+
calculatePatternEntropy: () => calculatePatternEntropy,
|
|
52
|
+
calculateProductivityImpact: () => calculateProductivityImpact,
|
|
53
|
+
calculateRemediationVelocity: () => calculateRemediationVelocity,
|
|
54
|
+
calculateScoreTrend: () => calculateScoreTrend,
|
|
55
|
+
calculateSemanticDistance: () => calculateSemanticDistance,
|
|
56
|
+
calculateTechnicalDebtInterest: () => calculateTechnicalDebtInterest,
|
|
57
|
+
clearHistory: () => clearHistory,
|
|
34
58
|
estimateTokens: () => estimateTokens,
|
|
59
|
+
exportHistory: () => exportHistory,
|
|
35
60
|
extractFunctions: () => extractFunctions,
|
|
36
61
|
extractImports: () => extractImports,
|
|
62
|
+
formatAcceptanceRate: () => formatAcceptanceRate,
|
|
63
|
+
formatCost: () => formatCost,
|
|
64
|
+
formatHours: () => formatHours,
|
|
37
65
|
formatScore: () => formatScore,
|
|
38
66
|
formatToolScore: () => formatToolScore,
|
|
39
67
|
generateHTML: () => generateHTML,
|
|
68
|
+
getDebtBreakdown: () => getDebtBreakdown,
|
|
40
69
|
getElapsedTime: () => getElapsedTime,
|
|
41
70
|
getFileExtension: () => getFileExtension,
|
|
71
|
+
getHistorySummary: () => getHistorySummary,
|
|
42
72
|
getParser: () => getParser,
|
|
43
73
|
getRating: () => getRating,
|
|
44
74
|
getRatingDisplay: () => getRatingDisplay,
|
|
@@ -50,13 +80,16 @@ __export(index_exports, {
|
|
|
50
80
|
isSourceFile: () => isSourceFile,
|
|
51
81
|
loadConfig: () => loadConfig,
|
|
52
82
|
loadMergedConfig: () => loadMergedConfig,
|
|
83
|
+
loadScoreHistory: () => loadScoreHistory,
|
|
53
84
|
mergeConfigWithDefaults: () => mergeConfigWithDefaults,
|
|
54
85
|
normalizeToolName: () => normalizeToolName,
|
|
55
86
|
parseCode: () => parseCode,
|
|
56
87
|
parseFileExports: () => parseFileExports,
|
|
57
88
|
parseWeightString: () => parseWeightString,
|
|
89
|
+
predictAcceptanceRate: () => predictAcceptanceRate,
|
|
58
90
|
readFileContent: () => readFileContent,
|
|
59
91
|
resolveOutputPath: () => resolveOutputPath,
|
|
92
|
+
saveScoreEntry: () => saveScoreEntry,
|
|
60
93
|
scanFiles: () => scanFiles
|
|
61
94
|
});
|
|
62
95
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -97,6 +130,7 @@ var import_glob = require("glob");
|
|
|
97
130
|
var import_promises = require("fs/promises");
|
|
98
131
|
var import_fs = require("fs");
|
|
99
132
|
var import_path = require("path");
|
|
133
|
+
var import_ignore = __toESM(require("ignore"));
|
|
100
134
|
var DEFAULT_EXCLUDE = [
|
|
101
135
|
// Dependencies
|
|
102
136
|
"**/node_modules/**",
|
|
@@ -165,6 +199,22 @@ async function scanFiles(options) {
|
|
|
165
199
|
ignore: finalExclude,
|
|
166
200
|
absolute: true
|
|
167
201
|
});
|
|
202
|
+
const gitignorePath = (0, import_path.join)(rootDir || ".", ".gitignore");
|
|
203
|
+
if ((0, import_fs.existsSync)(gitignorePath)) {
|
|
204
|
+
try {
|
|
205
|
+
const gitTxt = await (0, import_promises.readFile)(gitignorePath, "utf-8");
|
|
206
|
+
const ig = (0, import_ignore.default)();
|
|
207
|
+
ig.add(gitTxt);
|
|
208
|
+
const filtered = files.filter((f) => {
|
|
209
|
+
let rel = (0, import_path.relative)(rootDir || ".", f).replace(/\\/g, "/");
|
|
210
|
+
if (rel === "") rel = f;
|
|
211
|
+
return !ig.ignores(rel);
|
|
212
|
+
});
|
|
213
|
+
return filtered;
|
|
214
|
+
} catch (e) {
|
|
215
|
+
return files;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
168
218
|
return files;
|
|
169
219
|
}
|
|
170
220
|
async function readFileContent(filePath) {
|
|
@@ -783,6 +833,361 @@ function formatToolScore(output) {
|
|
|
783
833
|
return result;
|
|
784
834
|
}
|
|
785
835
|
|
|
836
|
+
// src/business-metrics.ts
|
|
837
|
+
var DEFAULT_COST_CONFIG = {
|
|
838
|
+
pricePer1KTokens: 0.01,
|
|
839
|
+
// $0.01 per 1K tokens (GPT-4)
|
|
840
|
+
queriesPerDevPerDay: 50,
|
|
841
|
+
// Average AI queries per developer
|
|
842
|
+
developerCount: 5,
|
|
843
|
+
// Default team size
|
|
844
|
+
daysPerMonth: 30
|
|
845
|
+
};
|
|
846
|
+
var SEVERITY_TIME_ESTIMATES = {
|
|
847
|
+
critical: 4,
|
|
848
|
+
// Complex architectural issues
|
|
849
|
+
major: 2,
|
|
850
|
+
// Significant refactoring needed
|
|
851
|
+
minor: 0.5,
|
|
852
|
+
// Simple naming/style fixes
|
|
853
|
+
info: 0.25
|
|
854
|
+
// Documentation improvements
|
|
855
|
+
};
|
|
856
|
+
var DEFAULT_HOURLY_RATE = 75;
|
|
857
|
+
function calculateMonthlyCost(tokenWaste, config = {}) {
|
|
858
|
+
const cfg = { ...DEFAULT_COST_CONFIG, ...config };
|
|
859
|
+
const tokensPerDay = tokenWaste * cfg.queriesPerDevPerDay;
|
|
860
|
+
const tokensPerMonth = tokensPerDay * cfg.daysPerMonth;
|
|
861
|
+
const cost = tokensPerMonth / 1e3 * cfg.pricePer1KTokens;
|
|
862
|
+
return Math.round(cost * 100) / 100;
|
|
863
|
+
}
|
|
864
|
+
function calculateProductivityImpact(issues, hourlyRate = DEFAULT_HOURLY_RATE) {
|
|
865
|
+
const counts = {
|
|
866
|
+
critical: issues.filter((i) => i.severity === "critical").length,
|
|
867
|
+
major: issues.filter((i) => i.severity === "major").length,
|
|
868
|
+
minor: issues.filter((i) => i.severity === "minor").length,
|
|
869
|
+
info: issues.filter((i) => i.severity === "info").length
|
|
870
|
+
};
|
|
871
|
+
const hours = {
|
|
872
|
+
critical: counts.critical * SEVERITY_TIME_ESTIMATES.critical,
|
|
873
|
+
major: counts.major * SEVERITY_TIME_ESTIMATES.major,
|
|
874
|
+
minor: counts.minor * SEVERITY_TIME_ESTIMATES.minor,
|
|
875
|
+
info: counts.info * SEVERITY_TIME_ESTIMATES.info
|
|
876
|
+
};
|
|
877
|
+
const totalHours = hours.critical + hours.major + hours.minor + hours.info;
|
|
878
|
+
const totalCost = totalHours * hourlyRate;
|
|
879
|
+
return {
|
|
880
|
+
totalHours: Math.round(totalHours * 10) / 10,
|
|
881
|
+
hourlyRate,
|
|
882
|
+
totalCost: Math.round(totalCost),
|
|
883
|
+
bySeverity: {
|
|
884
|
+
critical: { hours: Math.round(hours.critical * 10) / 10, cost: Math.round(hours.critical * hourlyRate) },
|
|
885
|
+
major: { hours: Math.round(hours.major * 10) / 10, cost: Math.round(hours.major * hourlyRate) },
|
|
886
|
+
minor: { hours: Math.round(hours.minor * 10) / 10, cost: Math.round(hours.minor * hourlyRate) }
|
|
887
|
+
}
|
|
888
|
+
};
|
|
889
|
+
}
|
|
890
|
+
function predictAcceptanceRate(toolOutputs) {
|
|
891
|
+
const factors = [];
|
|
892
|
+
const patterns = toolOutputs.get("pattern-detect");
|
|
893
|
+
if (patterns) {
|
|
894
|
+
const patternImpact = (patterns.score - 50) * 0.3;
|
|
895
|
+
factors.push({
|
|
896
|
+
name: "Semantic Duplication",
|
|
897
|
+
impact: Math.round(patternImpact)
|
|
898
|
+
});
|
|
899
|
+
}
|
|
900
|
+
const context = toolOutputs.get("context-analyzer");
|
|
901
|
+
if (context) {
|
|
902
|
+
const contextImpact = (context.score - 50) * 0.4;
|
|
903
|
+
factors.push({
|
|
904
|
+
name: "Context Efficiency",
|
|
905
|
+
impact: Math.round(contextImpact)
|
|
906
|
+
});
|
|
907
|
+
}
|
|
908
|
+
const consistency = toolOutputs.get("consistency");
|
|
909
|
+
if (consistency) {
|
|
910
|
+
const consistencyImpact = (consistency.score - 50) * 0.3;
|
|
911
|
+
factors.push({
|
|
912
|
+
name: "Code Consistency",
|
|
913
|
+
impact: Math.round(consistencyImpact)
|
|
914
|
+
});
|
|
915
|
+
}
|
|
916
|
+
const baseRate = 0.65;
|
|
917
|
+
const totalImpact = factors.reduce((sum, f) => sum + f.impact / 100, 0);
|
|
918
|
+
const rate = Math.max(0.1, Math.min(0.95, baseRate + totalImpact));
|
|
919
|
+
const confidence = toolOutputs.size >= 3 ? 0.8 : toolOutputs.size >= 2 ? 0.6 : 0.4;
|
|
920
|
+
return {
|
|
921
|
+
rate: Math.round(rate * 100) / 100,
|
|
922
|
+
confidence,
|
|
923
|
+
factors
|
|
924
|
+
};
|
|
925
|
+
}
|
|
926
|
+
function calculateComprehensionDifficulty(contextBudget, importDepth, fragmentation, consistencyScore, totalFiles) {
|
|
927
|
+
const budgetFactor = Math.min(100, Math.max(0, (contextBudget - 5e3) / 250));
|
|
928
|
+
const depthFactor = Math.min(100, Math.max(0, (importDepth - 5) * 10));
|
|
929
|
+
const fragmentationFactor = Math.min(100, Math.max(0, (fragmentation - 0.3) * 250));
|
|
930
|
+
const consistencyFactor = Math.min(100, Math.max(0, 100 - consistencyScore));
|
|
931
|
+
const fileFactor = Math.min(100, Math.max(0, (totalFiles - 50) / 5));
|
|
932
|
+
const score = Math.round(
|
|
933
|
+
budgetFactor * 0.35 + depthFactor * 0.2 + fragmentationFactor * 0.2 + consistencyFactor * 0.15 + fileFactor * 0.1
|
|
934
|
+
);
|
|
935
|
+
let rating;
|
|
936
|
+
if (score < 20) rating = "trivial";
|
|
937
|
+
else if (score < 40) rating = "easy";
|
|
938
|
+
else if (score < 60) rating = "moderate";
|
|
939
|
+
else if (score < 80) rating = "difficult";
|
|
940
|
+
else rating = "expert";
|
|
941
|
+
return {
|
|
942
|
+
score,
|
|
943
|
+
rating,
|
|
944
|
+
factors: [
|
|
945
|
+
{
|
|
946
|
+
name: "Context Budget",
|
|
947
|
+
contribution: Math.round(budgetFactor * 0.35),
|
|
948
|
+
description: `${Math.round(contextBudget)} tokens required`
|
|
949
|
+
},
|
|
950
|
+
{
|
|
951
|
+
name: "Import Depth",
|
|
952
|
+
contribution: Math.round(depthFactor * 0.2),
|
|
953
|
+
description: `${importDepth.toFixed(1)} average levels`
|
|
954
|
+
},
|
|
955
|
+
{
|
|
956
|
+
name: "Code Fragmentation",
|
|
957
|
+
contribution: Math.round(fragmentationFactor * 0.2),
|
|
958
|
+
description: `${(fragmentation * 100).toFixed(0)}% fragmentation`
|
|
959
|
+
},
|
|
960
|
+
{
|
|
961
|
+
name: "Consistency",
|
|
962
|
+
contribution: Math.round(consistencyFactor * 0.15),
|
|
963
|
+
description: `${consistencyScore}/100 consistency score`
|
|
964
|
+
},
|
|
965
|
+
{
|
|
966
|
+
name: "Project Scale",
|
|
967
|
+
contribution: Math.round(fileFactor * 0.1),
|
|
968
|
+
description: `${totalFiles} files analyzed`
|
|
969
|
+
}
|
|
970
|
+
]
|
|
971
|
+
};
|
|
972
|
+
}
|
|
973
|
+
function formatCost(cost) {
|
|
974
|
+
if (cost < 1) {
|
|
975
|
+
return `$${cost.toFixed(2)}`;
|
|
976
|
+
} else if (cost < 1e3) {
|
|
977
|
+
return `$${cost.toFixed(0)}`;
|
|
978
|
+
} else {
|
|
979
|
+
return `$${(cost / 1e3).toFixed(1)}k`;
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
function formatHours(hours) {
|
|
983
|
+
if (hours < 1) {
|
|
984
|
+
return `${Math.round(hours * 60)}min`;
|
|
985
|
+
} else if (hours < 8) {
|
|
986
|
+
return `${hours.toFixed(1)}h`;
|
|
987
|
+
} else if (hours < 40) {
|
|
988
|
+
return `${Math.round(hours)}h`;
|
|
989
|
+
} else {
|
|
990
|
+
return `${(hours / 40).toFixed(1)} weeks`;
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
function formatAcceptanceRate(rate) {
|
|
994
|
+
return `${Math.round(rate * 100)}%`;
|
|
995
|
+
}
|
|
996
|
+
function calculateScoreTrend(history) {
|
|
997
|
+
if (history.length < 2) {
|
|
998
|
+
return {
|
|
999
|
+
direction: "stable",
|
|
1000
|
+
change30Days: 0,
|
|
1001
|
+
change90Days: 0,
|
|
1002
|
+
velocity: 0,
|
|
1003
|
+
projectedScore: history[0]?.overallScore || 100
|
|
1004
|
+
};
|
|
1005
|
+
}
|
|
1006
|
+
const now = /* @__PURE__ */ new Date();
|
|
1007
|
+
const thirtyDaysAgo = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1e3);
|
|
1008
|
+
const ninetyDaysAgo = new Date(now.getTime() - 90 * 24 * 60 * 60 * 1e3);
|
|
1009
|
+
const last30Days = history.filter((e) => new Date(e.timestamp) >= thirtyDaysAgo);
|
|
1010
|
+
const last90Days = history.filter((e) => new Date(e.timestamp) >= ninetyDaysAgo);
|
|
1011
|
+
const currentScore = history[history.length - 1].overallScore;
|
|
1012
|
+
const thirtyDaysAgoScore = last30Days[0]?.overallScore || currentScore;
|
|
1013
|
+
const ninetyDaysAgoScore = last90Days[0]?.overallScore || thirtyDaysAgoScore;
|
|
1014
|
+
const change30Days = currentScore - thirtyDaysAgoScore;
|
|
1015
|
+
const change90Days = currentScore - ninetyDaysAgoScore;
|
|
1016
|
+
const weeksOfData = Math.max(1, history.length / 7);
|
|
1017
|
+
const totalChange = currentScore - history[0].overallScore;
|
|
1018
|
+
const velocity = totalChange / weeksOfData;
|
|
1019
|
+
let direction;
|
|
1020
|
+
if (change30Days > 3) direction = "improving";
|
|
1021
|
+
else if (change30Days < -3) direction = "degrading";
|
|
1022
|
+
else direction = "stable";
|
|
1023
|
+
const projectedScore = Math.max(0, Math.min(100, currentScore + velocity * 4));
|
|
1024
|
+
return {
|
|
1025
|
+
direction,
|
|
1026
|
+
change30Days,
|
|
1027
|
+
change90Days,
|
|
1028
|
+
velocity: Math.round(velocity * 10) / 10,
|
|
1029
|
+
projectedScore: Math.round(projectedScore)
|
|
1030
|
+
};
|
|
1031
|
+
}
|
|
1032
|
+
function calculateRemediationVelocity(history, currentIssues) {
|
|
1033
|
+
if (history.length < 2) {
|
|
1034
|
+
return {
|
|
1035
|
+
issuesFixedThisWeek: 0,
|
|
1036
|
+
avgIssuesPerWeek: 0,
|
|
1037
|
+
trend: "stable",
|
|
1038
|
+
estimatedCompletionWeeks: currentIssues > 0 ? Infinity : 0
|
|
1039
|
+
};
|
|
1040
|
+
}
|
|
1041
|
+
const now = /* @__PURE__ */ new Date();
|
|
1042
|
+
const oneWeekAgo = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1e3);
|
|
1043
|
+
const twoWeeksAgo = new Date(now.getTime() - 14 * 24 * 60 * 60 * 1e3);
|
|
1044
|
+
const thisWeek = history.filter((e) => new Date(e.timestamp) >= oneWeekAgo);
|
|
1045
|
+
const lastWeek = history.filter(
|
|
1046
|
+
(e) => new Date(e.timestamp) >= twoWeeksAgo && new Date(e.timestamp) < oneWeekAgo
|
|
1047
|
+
);
|
|
1048
|
+
const issuesFixedThisWeek = thisWeek.length > 1 ? thisWeek[0].totalIssues - thisWeek[thisWeek.length - 1].totalIssues : 0;
|
|
1049
|
+
const totalIssuesFixed = history[0].totalIssues - history[history.length - 1].totalIssues;
|
|
1050
|
+
const weeksOfData = Math.max(1, history.length / 7);
|
|
1051
|
+
const avgIssuesPerWeek = totalIssuesFixed / weeksOfData;
|
|
1052
|
+
let trend;
|
|
1053
|
+
if (lastWeek.length > 1) {
|
|
1054
|
+
const lastWeekFixed = lastWeek[0].totalIssues - lastWeek[lastWeek.length - 1].totalIssues;
|
|
1055
|
+
if (issuesFixedThisWeek > lastWeekFixed * 1.2) trend = "accelerating";
|
|
1056
|
+
else if (issuesFixedThisWeek < lastWeekFixed * 0.8) trend = "decelerating";
|
|
1057
|
+
else trend = "stable";
|
|
1058
|
+
} else {
|
|
1059
|
+
trend = "stable";
|
|
1060
|
+
}
|
|
1061
|
+
const estimatedCompletionWeeks = avgIssuesPerWeek > 0 ? Math.ceil(currentIssues / avgIssuesPerWeek) : Infinity;
|
|
1062
|
+
return {
|
|
1063
|
+
issuesFixedThisWeek: Math.max(0, issuesFixedThisWeek),
|
|
1064
|
+
avgIssuesPerWeek: Math.round(avgIssuesPerWeek * 10) / 10,
|
|
1065
|
+
trend,
|
|
1066
|
+
estimatedCompletionWeeks
|
|
1067
|
+
};
|
|
1068
|
+
}
|
|
1069
|
+
function calculateKnowledgeConcentration(files, authorData) {
|
|
1070
|
+
if (files.length === 0) {
|
|
1071
|
+
return {
|
|
1072
|
+
score: 0,
|
|
1073
|
+
rating: "low",
|
|
1074
|
+
analysis: {
|
|
1075
|
+
uniqueConceptFiles: 0,
|
|
1076
|
+
totalFiles: 0,
|
|
1077
|
+
concentrationRatio: 0,
|
|
1078
|
+
singleAuthorFiles: 0,
|
|
1079
|
+
orphanFiles: 0
|
|
1080
|
+
},
|
|
1081
|
+
recommendations: ["No files to analyze"]
|
|
1082
|
+
};
|
|
1083
|
+
}
|
|
1084
|
+
const orphanFiles = files.filter((f) => f.exports < 2 && f.imports < 2).length;
|
|
1085
|
+
const avgExports = files.reduce((sum, f) => sum + f.exports, 0) / files.length;
|
|
1086
|
+
const uniqueConceptFiles = files.filter((f) => f.exports > avgExports * 2).length;
|
|
1087
|
+
const totalExports = files.reduce((sum, f) => sum + f.exports, 0);
|
|
1088
|
+
const concentrationRatio = totalExports > 0 ? uniqueConceptFiles / files.length : 0;
|
|
1089
|
+
let singleAuthorFiles = 0;
|
|
1090
|
+
if (authorData) {
|
|
1091
|
+
for (const files2 of authorData.values()) {
|
|
1092
|
+
if (files2.length === 1) singleAuthorFiles++;
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
const orphanRisk = orphanFiles / files.length * 30;
|
|
1096
|
+
const uniqueRisk = concentrationRatio * 40;
|
|
1097
|
+
const singleAuthorRisk = authorData ? singleAuthorFiles / files.length * 30 : 0;
|
|
1098
|
+
const score = Math.min(100, Math.round(orphanRisk + uniqueRisk + singleAuthorRisk));
|
|
1099
|
+
let rating;
|
|
1100
|
+
if (score < 20) rating = "low";
|
|
1101
|
+
else if (score < 40) rating = "moderate";
|
|
1102
|
+
else if (score < 70) rating = "high";
|
|
1103
|
+
else rating = "critical";
|
|
1104
|
+
const recommendations = [];
|
|
1105
|
+
if (orphanFiles > files.length * 0.2) {
|
|
1106
|
+
recommendations.push(`Reduce ${orphanFiles} orphan files by connecting them to main modules`);
|
|
1107
|
+
}
|
|
1108
|
+
if (uniqueConceptFiles > files.length * 0.1) {
|
|
1109
|
+
recommendations.push("Distribute high-export files into more focused modules");
|
|
1110
|
+
}
|
|
1111
|
+
if (authorData && singleAuthorFiles > files.length * 0.3) {
|
|
1112
|
+
recommendations.push("Increase knowledge sharing to reduce single-author dependencies");
|
|
1113
|
+
}
|
|
1114
|
+
return {
|
|
1115
|
+
score,
|
|
1116
|
+
rating,
|
|
1117
|
+
analysis: {
|
|
1118
|
+
uniqueConceptFiles,
|
|
1119
|
+
totalFiles: files.length,
|
|
1120
|
+
concentrationRatio: Math.round(concentrationRatio * 100) / 100,
|
|
1121
|
+
singleAuthorFiles,
|
|
1122
|
+
orphanFiles
|
|
1123
|
+
},
|
|
1124
|
+
recommendations
|
|
1125
|
+
};
|
|
1126
|
+
}
|
|
1127
|
+
function calculateTechnicalDebtInterest(params) {
|
|
1128
|
+
const { currentMonthlyCost, issues, monthsOpen } = params;
|
|
1129
|
+
const criticalCount = issues.filter((i) => i.severity === "critical").length;
|
|
1130
|
+
const majorCount = issues.filter((i) => i.severity === "major").length;
|
|
1131
|
+
const minorCount = issues.filter((i) => i.severity === "minor").length;
|
|
1132
|
+
const severityWeight = (criticalCount * 3 + majorCount * 2 + minorCount * 1) / Math.max(1, issues.length);
|
|
1133
|
+
const baseRate = 0.02 + severityWeight * 0.01;
|
|
1134
|
+
const timeMultiplier = Math.max(1, 1 + monthsOpen * 0.1);
|
|
1135
|
+
const monthlyRate = baseRate * timeMultiplier;
|
|
1136
|
+
const projectDebt = (principal2, months) => {
|
|
1137
|
+
let debt = principal2;
|
|
1138
|
+
for (let i = 0; i < months; i++) {
|
|
1139
|
+
debt = debt * (1 + monthlyRate);
|
|
1140
|
+
}
|
|
1141
|
+
return Math.round(debt);
|
|
1142
|
+
};
|
|
1143
|
+
const principal = currentMonthlyCost * 12;
|
|
1144
|
+
const projections = {
|
|
1145
|
+
months6: projectDebt(principal, 6),
|
|
1146
|
+
months12: projectDebt(principal, 12),
|
|
1147
|
+
months24: projectDebt(principal, 24)
|
|
1148
|
+
};
|
|
1149
|
+
return {
|
|
1150
|
+
monthlyRate: Math.round(monthlyRate * 1e4) / 100,
|
|
1151
|
+
annualRate: Math.round((Math.pow(1 + monthlyRate, 12) - 1) * 1e4) / 100,
|
|
1152
|
+
principal,
|
|
1153
|
+
projections,
|
|
1154
|
+
monthlyCost: Math.round(currentMonthlyCost * (1 + monthlyRate) * 100) / 100
|
|
1155
|
+
};
|
|
1156
|
+
}
|
|
1157
|
+
function getDebtBreakdown(patternCost, contextCost, consistencyCost) {
|
|
1158
|
+
const breakdowns = [
|
|
1159
|
+
{
|
|
1160
|
+
category: "Semantic Duplication",
|
|
1161
|
+
currentCost: patternCost,
|
|
1162
|
+
monthlyGrowthRate: 5,
|
|
1163
|
+
// Grows as devs copy-paste
|
|
1164
|
+
priority: patternCost > 1e3 ? "high" : "medium",
|
|
1165
|
+
fixCost: patternCost * 3
|
|
1166
|
+
// Fixing costs 3x current waste
|
|
1167
|
+
},
|
|
1168
|
+
{
|
|
1169
|
+
category: "Context Fragmentation",
|
|
1170
|
+
currentCost: contextCost,
|
|
1171
|
+
monthlyGrowthRate: 3,
|
|
1172
|
+
// Grows with new features
|
|
1173
|
+
priority: contextCost > 500 ? "high" : "medium",
|
|
1174
|
+
fixCost: contextCost * 2.5
|
|
1175
|
+
},
|
|
1176
|
+
{
|
|
1177
|
+
category: "Consistency Issues",
|
|
1178
|
+
currentCost: consistencyCost,
|
|
1179
|
+
monthlyGrowthRate: 2,
|
|
1180
|
+
// Grows with new devs
|
|
1181
|
+
priority: consistencyCost > 200 ? "medium" : "low",
|
|
1182
|
+
fixCost: consistencyCost * 1.5
|
|
1183
|
+
}
|
|
1184
|
+
];
|
|
1185
|
+
return breakdowns.sort((a, b) => {
|
|
1186
|
+
const priorityOrder = { high: 0, medium: 1, low: 2 };
|
|
1187
|
+
return priorityOrder[a.priority] - priorityOrder[b.priority];
|
|
1188
|
+
});
|
|
1189
|
+
}
|
|
1190
|
+
|
|
786
1191
|
// src/parsers/typescript-parser.ts
|
|
787
1192
|
var import_typescript_estree2 = require("@typescript-eslint/typescript-estree");
|
|
788
1193
|
var TypeScriptParser = class {
|
|
@@ -1262,8 +1667,311 @@ function isFileSupported(filePath) {
|
|
|
1262
1667
|
function getSupportedLanguages() {
|
|
1263
1668
|
return ParserFactory.getInstance().getSupportedLanguages();
|
|
1264
1669
|
}
|
|
1670
|
+
|
|
1671
|
+
// src/future-proof-metrics.ts
|
|
1672
|
+
function calculateCognitiveLoad(params) {
|
|
1673
|
+
const { linesOfCode, exportCount, importCount, uniqueConcepts, cyclomaticComplexity = 1 } = params;
|
|
1674
|
+
const sizeFactor = {
|
|
1675
|
+
name: "Size Complexity",
|
|
1676
|
+
score: Math.min(100, Math.max(0, (linesOfCode - 50) / 10)),
|
|
1677
|
+
weight: 0.3,
|
|
1678
|
+
description: `${linesOfCode} lines of code`
|
|
1679
|
+
};
|
|
1680
|
+
const interfaceFactor = {
|
|
1681
|
+
name: "Interface Complexity",
|
|
1682
|
+
score: Math.min(100, exportCount * 5),
|
|
1683
|
+
weight: 0.25,
|
|
1684
|
+
description: `${exportCount} exported concepts`
|
|
1685
|
+
};
|
|
1686
|
+
const dependencyFactor = {
|
|
1687
|
+
name: "Dependency Complexity",
|
|
1688
|
+
score: Math.min(100, importCount * 8),
|
|
1689
|
+
weight: 0.25,
|
|
1690
|
+
description: `${importCount} dependencies`
|
|
1691
|
+
};
|
|
1692
|
+
const conceptDensity = linesOfCode > 0 ? uniqueConcepts / linesOfCode : 0;
|
|
1693
|
+
const conceptFactor = {
|
|
1694
|
+
name: "Conceptual Density",
|
|
1695
|
+
score: Math.min(100, conceptDensity * 500),
|
|
1696
|
+
weight: 0.2,
|
|
1697
|
+
description: `${uniqueConcepts} unique concepts`
|
|
1698
|
+
};
|
|
1699
|
+
const factors = [sizeFactor, interfaceFactor, dependencyFactor, conceptFactor];
|
|
1700
|
+
const score = factors.reduce((sum, f) => sum + f.score * f.weight, 0);
|
|
1701
|
+
let rating;
|
|
1702
|
+
if (score < 20) rating = "trivial";
|
|
1703
|
+
else if (score < 40) rating = "easy";
|
|
1704
|
+
else if (score < 60) rating = "moderate";
|
|
1705
|
+
else if (score < 80) rating = "difficult";
|
|
1706
|
+
else rating = "expert";
|
|
1707
|
+
return {
|
|
1708
|
+
score: Math.round(score),
|
|
1709
|
+
rating,
|
|
1710
|
+
factors,
|
|
1711
|
+
rawValues: {
|
|
1712
|
+
size: linesOfCode,
|
|
1713
|
+
complexity: cyclomaticComplexity,
|
|
1714
|
+
dependencyCount: importCount,
|
|
1715
|
+
conceptCount: uniqueConcepts
|
|
1716
|
+
}
|
|
1717
|
+
};
|
|
1718
|
+
}
|
|
1719
|
+
function calculateSemanticDistance(params) {
|
|
1720
|
+
const { file1, file2, file1Domain, file2Domain, sharedDependencies } = params;
|
|
1721
|
+
const domainDistance = file1Domain === file2Domain ? 0 : file1Domain && file2Domain ? 0.5 : 0.8;
|
|
1722
|
+
const importOverlap = sharedDependencies.length / Math.max(1, Math.min(params.file1Imports.length, params.file2Imports.length));
|
|
1723
|
+
const importDistance = 1 - importOverlap;
|
|
1724
|
+
const distance = domainDistance * 0.4 + importDistance * 0.3 + (sharedDependencies.length > 0 ? 0 : 0.3);
|
|
1725
|
+
let relationship;
|
|
1726
|
+
if (file1 === file2) relationship = "same-file";
|
|
1727
|
+
else if (file1Domain === file2Domain) relationship = "same-domain";
|
|
1728
|
+
else if (sharedDependencies.length > 0) relationship = "cross-domain";
|
|
1729
|
+
else relationship = "unrelated";
|
|
1730
|
+
const pathItems = [file1Domain, ...sharedDependencies, file2Domain].filter((s) => typeof s === "string" && s.length > 0);
|
|
1731
|
+
return {
|
|
1732
|
+
between: [file1, file2],
|
|
1733
|
+
distance: Math.round(distance * 100) / 100,
|
|
1734
|
+
relationship,
|
|
1735
|
+
path: pathItems,
|
|
1736
|
+
reason: relationship === "same-domain" ? `Both in "${file1Domain}" domain` : relationship === "cross-domain" ? `Share ${sharedDependencies.length} dependency(ies)` : "No strong semantic relationship detected"
|
|
1737
|
+
};
|
|
1738
|
+
}
|
|
1739
|
+
function calculatePatternEntropy(files) {
|
|
1740
|
+
if (files.length === 0) {
|
|
1741
|
+
return {
|
|
1742
|
+
domain: "unknown",
|
|
1743
|
+
entropy: 0,
|
|
1744
|
+
rating: "crystalline",
|
|
1745
|
+
distribution: { locationCount: 0, dominantLocation: "", giniCoefficient: 0 },
|
|
1746
|
+
recommendations: ["No files to analyze"]
|
|
1747
|
+
};
|
|
1748
|
+
}
|
|
1749
|
+
const dirGroups = /* @__PURE__ */ new Map();
|
|
1750
|
+
for (const file of files) {
|
|
1751
|
+
const parts = file.path.split("/").slice(0, 4).join("/") || "root";
|
|
1752
|
+
dirGroups.set(parts, (dirGroups.get(parts) || 0) + 1);
|
|
1753
|
+
}
|
|
1754
|
+
const counts = Array.from(dirGroups.values());
|
|
1755
|
+
const total = counts.reduce((a, b) => a + b, 0);
|
|
1756
|
+
let entropy = 0;
|
|
1757
|
+
for (const count of counts) {
|
|
1758
|
+
const p = count / total;
|
|
1759
|
+
if (p > 0) entropy -= p * Math.log2(p);
|
|
1760
|
+
}
|
|
1761
|
+
const maxEntropy = Math.log2(dirGroups.size || 1);
|
|
1762
|
+
const normalizedEntropy = maxEntropy > 0 ? entropy / maxEntropy : 0;
|
|
1763
|
+
const sortedCounts = counts.sort((a, b) => a - b);
|
|
1764
|
+
let gini = 0;
|
|
1765
|
+
for (let i = 0; i < sortedCounts.length; i++) {
|
|
1766
|
+
gini += (2 * (i + 1) - sortedCounts.length - 1) * sortedCounts[i];
|
|
1767
|
+
}
|
|
1768
|
+
gini /= total * sortedCounts.length;
|
|
1769
|
+
let dominantLocation = "";
|
|
1770
|
+
let maxCount = 0;
|
|
1771
|
+
for (const [loc, count] of dirGroups.entries()) {
|
|
1772
|
+
if (count > maxCount) {
|
|
1773
|
+
maxCount = count;
|
|
1774
|
+
dominantLocation = loc;
|
|
1775
|
+
}
|
|
1776
|
+
}
|
|
1777
|
+
let rating;
|
|
1778
|
+
if (normalizedEntropy < 0.2) rating = "crystalline";
|
|
1779
|
+
else if (normalizedEntropy < 0.4) rating = "well-structured";
|
|
1780
|
+
else if (normalizedEntropy < 0.6) rating = "moderate";
|
|
1781
|
+
else if (normalizedEntropy < 0.8) rating = "fragmented";
|
|
1782
|
+
else rating = "chaotic";
|
|
1783
|
+
const recommendations = [];
|
|
1784
|
+
if (normalizedEntropy > 0.5) {
|
|
1785
|
+
recommendations.push(`Consolidate ${files.length} files into fewer directories by domain`);
|
|
1786
|
+
}
|
|
1787
|
+
if (dirGroups.size > 5) {
|
|
1788
|
+
recommendations.push("Consider barrel exports to reduce directory navigation");
|
|
1789
|
+
}
|
|
1790
|
+
if (gini > 0.5) {
|
|
1791
|
+
recommendations.push("Redistribute files more evenly across directories");
|
|
1792
|
+
}
|
|
1793
|
+
const firstFile = files.length > 0 ? files[0] : null;
|
|
1794
|
+
const domainValue = firstFile ? firstFile.domain : "mixed";
|
|
1795
|
+
return {
|
|
1796
|
+
domain: domainValue,
|
|
1797
|
+
entropy: Math.round(normalizedEntropy * 100) / 100,
|
|
1798
|
+
rating,
|
|
1799
|
+
distribution: {
|
|
1800
|
+
locationCount: dirGroups.size,
|
|
1801
|
+
dominantLocation,
|
|
1802
|
+
giniCoefficient: Math.round(gini * 100) / 100
|
|
1803
|
+
},
|
|
1804
|
+
recommendations
|
|
1805
|
+
};
|
|
1806
|
+
}
|
|
1807
|
+
function calculateConceptCohesion(params) {
|
|
1808
|
+
const { exports: exports2 } = params;
|
|
1809
|
+
if (exports2.length === 0) {
|
|
1810
|
+
return {
|
|
1811
|
+
score: 1,
|
|
1812
|
+
rating: "excellent",
|
|
1813
|
+
analysis: { uniqueDomains: 0, domainConcentration: 0, exportPurposeClarity: 1 }
|
|
1814
|
+
};
|
|
1815
|
+
}
|
|
1816
|
+
const allDomains = [];
|
|
1817
|
+
for (const exp of exports2) {
|
|
1818
|
+
if (exp.inferredDomain) allDomains.push(exp.inferredDomain);
|
|
1819
|
+
if (exp.domains) allDomains.push(...exp.domains);
|
|
1820
|
+
}
|
|
1821
|
+
const uniqueDomains = new Set(allDomains);
|
|
1822
|
+
const domainCounts = /* @__PURE__ */ new Map();
|
|
1823
|
+
for (const d of allDomains) {
|
|
1824
|
+
domainCounts.set(d, (domainCounts.get(d) || 0) + 1);
|
|
1825
|
+
}
|
|
1826
|
+
const maxCount = Math.max(...Array.from(domainCounts.values()), 1);
|
|
1827
|
+
const domainConcentration = maxCount / allDomains.length;
|
|
1828
|
+
const exportPurposeClarity = 1 - (uniqueDomains.size - 1) / Math.max(1, exports2.length);
|
|
1829
|
+
const score = domainConcentration * 0.5 + exportPurposeClarity * 0.5;
|
|
1830
|
+
let rating;
|
|
1831
|
+
if (score > 0.8) rating = "excellent";
|
|
1832
|
+
else if (score > 0.6) rating = "good";
|
|
1833
|
+
else if (score > 0.4) rating = "moderate";
|
|
1834
|
+
else rating = "poor";
|
|
1835
|
+
return {
|
|
1836
|
+
score: Math.round(score * 100) / 100,
|
|
1837
|
+
rating,
|
|
1838
|
+
analysis: {
|
|
1839
|
+
uniqueDomains: uniqueDomains.size,
|
|
1840
|
+
domainConcentration: Math.round(domainConcentration * 100) / 100,
|
|
1841
|
+
exportPurposeClarity: Math.round(exportPurposeClarity * 100) / 100
|
|
1842
|
+
}
|
|
1843
|
+
};
|
|
1844
|
+
}
|
|
1845
|
+
function calculateFutureProofScore(params) {
|
|
1846
|
+
const loadScore = 100 - params.cognitiveLoad.score;
|
|
1847
|
+
const entropyScore = 100 - params.patternEntropy.entropy * 100;
|
|
1848
|
+
const cohesionScore = params.conceptCohesion.score * 100;
|
|
1849
|
+
const overall = Math.round(
|
|
1850
|
+
loadScore * 0.4 + entropyScore * 0.3 + cohesionScore * 0.3
|
|
1851
|
+
);
|
|
1852
|
+
const factors = [
|
|
1853
|
+
{
|
|
1854
|
+
name: "Cognitive Load",
|
|
1855
|
+
impact: Math.round(loadScore - 50),
|
|
1856
|
+
description: params.cognitiveLoad.rating
|
|
1857
|
+
},
|
|
1858
|
+
{
|
|
1859
|
+
name: "Pattern Entropy",
|
|
1860
|
+
impact: Math.round(entropyScore - 50),
|
|
1861
|
+
description: params.patternEntropy.rating
|
|
1862
|
+
},
|
|
1863
|
+
{
|
|
1864
|
+
name: "Concept Cohesion",
|
|
1865
|
+
impact: Math.round(cohesionScore - 50),
|
|
1866
|
+
description: params.conceptCohesion.rating
|
|
1867
|
+
}
|
|
1868
|
+
];
|
|
1869
|
+
const recommendations = [];
|
|
1870
|
+
for (const rec of params.patternEntropy.recommendations) {
|
|
1871
|
+
recommendations.push({
|
|
1872
|
+
action: rec,
|
|
1873
|
+
estimatedImpact: 5,
|
|
1874
|
+
priority: "medium"
|
|
1875
|
+
});
|
|
1876
|
+
}
|
|
1877
|
+
if (params.conceptCohesion.rating === "poor") {
|
|
1878
|
+
recommendations.push({
|
|
1879
|
+
action: "Improve concept cohesion by grouping related exports",
|
|
1880
|
+
estimatedImpact: 8,
|
|
1881
|
+
priority: "high"
|
|
1882
|
+
});
|
|
1883
|
+
}
|
|
1884
|
+
const semanticDistanceAvg = params.semanticDistances && params.semanticDistances.length > 0 ? params.semanticDistances.reduce((s, d) => s + d.distance, 0) / params.semanticDistances.length : 0;
|
|
1885
|
+
return {
|
|
1886
|
+
toolName: "future-proof",
|
|
1887
|
+
score: overall,
|
|
1888
|
+
rawMetrics: {
|
|
1889
|
+
cognitiveLoadScore: params.cognitiveLoad.score,
|
|
1890
|
+
entropyScore: params.patternEntropy.entropy,
|
|
1891
|
+
cohesionScore: params.conceptCohesion.score,
|
|
1892
|
+
semanticDistanceAvg
|
|
1893
|
+
},
|
|
1894
|
+
factors,
|
|
1895
|
+
recommendations
|
|
1896
|
+
};
|
|
1897
|
+
}
|
|
1898
|
+
|
|
1899
|
+
// src/utils/history.ts
|
|
1900
|
+
var import_fs4 = require("fs");
|
|
1901
|
+
var import_path4 = require("path");
|
|
1902
|
+
function getHistoryPath(rootDir) {
|
|
1903
|
+
return (0, import_path4.join)(rootDir, ".aiready", "history.json");
|
|
1904
|
+
}
|
|
1905
|
+
function loadScoreHistory(rootDir) {
|
|
1906
|
+
const historyPath = getHistoryPath(rootDir);
|
|
1907
|
+
if (!(0, import_fs4.existsSync)(historyPath)) {
|
|
1908
|
+
return [];
|
|
1909
|
+
}
|
|
1910
|
+
try {
|
|
1911
|
+
const data = (0, import_fs4.readFileSync)(historyPath, "utf-8");
|
|
1912
|
+
return JSON.parse(data);
|
|
1913
|
+
} catch (error) {
|
|
1914
|
+
console.warn("Failed to load score history:", error);
|
|
1915
|
+
return [];
|
|
1916
|
+
}
|
|
1917
|
+
}
|
|
1918
|
+
function saveScoreEntry(rootDir, entry) {
|
|
1919
|
+
const historyPath = getHistoryPath(rootDir);
|
|
1920
|
+
const historyDir = (0, import_path4.dirname)(historyPath);
|
|
1921
|
+
if (!(0, import_fs4.existsSync)(historyDir)) {
|
|
1922
|
+
(0, import_fs4.mkdirSync)(historyDir, { recursive: true });
|
|
1923
|
+
}
|
|
1924
|
+
const history = loadScoreHistory(rootDir);
|
|
1925
|
+
const newEntry = {
|
|
1926
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1927
|
+
...entry
|
|
1928
|
+
};
|
|
1929
|
+
const oneYearAgo = Date.now() - 365 * 24 * 60 * 60 * 1e3;
|
|
1930
|
+
const filteredHistory = history.filter(
|
|
1931
|
+
(e) => new Date(e.timestamp).getTime() > oneYearAgo
|
|
1932
|
+
);
|
|
1933
|
+
filteredHistory.push(newEntry);
|
|
1934
|
+
(0, import_fs4.writeFileSync)(historyPath, JSON.stringify(filteredHistory, null, 2));
|
|
1935
|
+
}
|
|
1936
|
+
function getHistorySummary(rootDir) {
|
|
1937
|
+
const history = loadScoreHistory(rootDir);
|
|
1938
|
+
if (history.length === 0) {
|
|
1939
|
+
return {
|
|
1940
|
+
totalScans: 0,
|
|
1941
|
+
firstScan: null,
|
|
1942
|
+
lastScan: null,
|
|
1943
|
+
avgScore: 0
|
|
1944
|
+
};
|
|
1945
|
+
}
|
|
1946
|
+
const scores = history.map((e) => e.overallScore);
|
|
1947
|
+
const avgScore = scores.reduce((a, b) => a + b, 0) / scores.length;
|
|
1948
|
+
return {
|
|
1949
|
+
totalScans: history.length,
|
|
1950
|
+
firstScan: history[0].timestamp,
|
|
1951
|
+
lastScan: history[history.length - 1].timestamp,
|
|
1952
|
+
avgScore: Math.round(avgScore)
|
|
1953
|
+
};
|
|
1954
|
+
}
|
|
1955
|
+
function exportHistory(rootDir, format = "json") {
|
|
1956
|
+
const history = loadScoreHistory(rootDir);
|
|
1957
|
+
if (format === "csv") {
|
|
1958
|
+
const headers = "timestamp,overallScore,totalIssues,totalTokens,patternScore,contextScore,consistencyScore\n";
|
|
1959
|
+
const rows = history.map(
|
|
1960
|
+
(e) => `${e.timestamp},${e.overallScore},${e.totalIssues},${e.totalTokens},${e.breakdown?.["pattern-detect"] || ""},${e.breakdown?.["context-analyzer"] || ""},${e.breakdown?.["consistency"] || ""}`
|
|
1961
|
+
).join("\n");
|
|
1962
|
+
return headers + rows;
|
|
1963
|
+
}
|
|
1964
|
+
return JSON.stringify(history, null, 2);
|
|
1965
|
+
}
|
|
1966
|
+
function clearHistory(rootDir) {
|
|
1967
|
+
const historyPath = getHistoryPath(rootDir);
|
|
1968
|
+
if ((0, import_fs4.existsSync)(historyPath)) {
|
|
1969
|
+
(0, import_fs4.writeFileSync)(historyPath, JSON.stringify([]));
|
|
1970
|
+
}
|
|
1971
|
+
}
|
|
1265
1972
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1266
1973
|
0 && (module.exports = {
|
|
1974
|
+
DEFAULT_COST_CONFIG,
|
|
1267
1975
|
DEFAULT_EXCLUDE,
|
|
1268
1976
|
DEFAULT_TOOL_WEIGHTS,
|
|
1269
1977
|
LANGUAGE_EXTENSIONS,
|
|
@@ -1273,16 +1981,35 @@ function getSupportedLanguages() {
|
|
|
1273
1981
|
PythonParser,
|
|
1274
1982
|
TOOL_NAME_MAP,
|
|
1275
1983
|
TypeScriptParser,
|
|
1984
|
+
calculateCognitiveLoad,
|
|
1985
|
+
calculateComprehensionDifficulty,
|
|
1986
|
+
calculateConceptCohesion,
|
|
1987
|
+
calculateFutureProofScore,
|
|
1276
1988
|
calculateImportSimilarity,
|
|
1989
|
+
calculateKnowledgeConcentration,
|
|
1990
|
+
calculateMonthlyCost,
|
|
1277
1991
|
calculateOverallScore,
|
|
1992
|
+
calculatePatternEntropy,
|
|
1993
|
+
calculateProductivityImpact,
|
|
1994
|
+
calculateRemediationVelocity,
|
|
1995
|
+
calculateScoreTrend,
|
|
1996
|
+
calculateSemanticDistance,
|
|
1997
|
+
calculateTechnicalDebtInterest,
|
|
1998
|
+
clearHistory,
|
|
1278
1999
|
estimateTokens,
|
|
2000
|
+
exportHistory,
|
|
1279
2001
|
extractFunctions,
|
|
1280
2002
|
extractImports,
|
|
2003
|
+
formatAcceptanceRate,
|
|
2004
|
+
formatCost,
|
|
2005
|
+
formatHours,
|
|
1281
2006
|
formatScore,
|
|
1282
2007
|
formatToolScore,
|
|
1283
2008
|
generateHTML,
|
|
2009
|
+
getDebtBreakdown,
|
|
1284
2010
|
getElapsedTime,
|
|
1285
2011
|
getFileExtension,
|
|
2012
|
+
getHistorySummary,
|
|
1286
2013
|
getParser,
|
|
1287
2014
|
getRating,
|
|
1288
2015
|
getRatingDisplay,
|
|
@@ -1294,12 +2021,15 @@ function getSupportedLanguages() {
|
|
|
1294
2021
|
isSourceFile,
|
|
1295
2022
|
loadConfig,
|
|
1296
2023
|
loadMergedConfig,
|
|
2024
|
+
loadScoreHistory,
|
|
1297
2025
|
mergeConfigWithDefaults,
|
|
1298
2026
|
normalizeToolName,
|
|
1299
2027
|
parseCode,
|
|
1300
2028
|
parseFileExports,
|
|
1301
2029
|
parseWeightString,
|
|
2030
|
+
predictAcceptanceRate,
|
|
1302
2031
|
readFileContent,
|
|
1303
2032
|
resolveOutputPath,
|
|
2033
|
+
saveScoreEntry,
|
|
1304
2034
|
scanFiles
|
|
1305
2035
|
});
|