@aiready/core 0.9.26 → 0.9.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-JJ5JL5FX.mjs +408 -0
- package/dist/client.js +58 -2
- package/dist/client.mjs +11 -1
- package/dist/index.js +512 -20
- package/dist/index.mjs +459 -19
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -30,20 +30,26 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/index.ts
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
|
+
CONTEXT_TIER_THRESHOLDS: () => CONTEXT_TIER_THRESHOLDS,
|
|
33
34
|
DEFAULT_COST_CONFIG: () => DEFAULT_COST_CONFIG,
|
|
34
35
|
DEFAULT_EXCLUDE: () => DEFAULT_EXCLUDE,
|
|
35
36
|
DEFAULT_TOOL_WEIGHTS: () => DEFAULT_TOOL_WEIGHTS,
|
|
36
37
|
LANGUAGE_EXTENSIONS: () => LANGUAGE_EXTENSIONS,
|
|
37
38
|
Language: () => Language,
|
|
39
|
+
MODEL_PRICING_PRESETS: () => MODEL_PRICING_PRESETS,
|
|
38
40
|
ParseError: () => ParseError,
|
|
39
41
|
ParserFactory: () => ParserFactory,
|
|
40
42
|
PythonParser: () => PythonParser,
|
|
43
|
+
SIZE_ADJUSTED_THRESHOLDS: () => SIZE_ADJUSTED_THRESHOLDS,
|
|
41
44
|
TOOL_NAME_MAP: () => TOOL_NAME_MAP,
|
|
42
45
|
TypeScriptParser: () => TypeScriptParser,
|
|
46
|
+
calculateAgentGrounding: () => calculateAgentGrounding,
|
|
43
47
|
calculateCognitiveLoad: () => calculateCognitiveLoad,
|
|
44
48
|
calculateComprehensionDifficulty: () => calculateComprehensionDifficulty,
|
|
45
49
|
calculateConceptCohesion: () => calculateConceptCohesion,
|
|
50
|
+
calculateExtendedFutureProofScore: () => calculateExtendedFutureProofScore,
|
|
46
51
|
calculateFutureProofScore: () => calculateFutureProofScore,
|
|
52
|
+
calculateHallucinationRisk: () => calculateHallucinationRisk,
|
|
47
53
|
calculateImportSimilarity: () => calculateImportSimilarity,
|
|
48
54
|
calculateKnowledgeConcentration: () => calculateKnowledgeConcentration,
|
|
49
55
|
calculateMonthlyCost: () => calculateMonthlyCost,
|
|
@@ -54,6 +60,7 @@ __export(index_exports, {
|
|
|
54
60
|
calculateScoreTrend: () => calculateScoreTrend,
|
|
55
61
|
calculateSemanticDistance: () => calculateSemanticDistance,
|
|
56
62
|
calculateTechnicalDebtInterest: () => calculateTechnicalDebtInterest,
|
|
63
|
+
calculateTestabilityIndex: () => calculateTestabilityIndex,
|
|
57
64
|
clearHistory: () => clearHistory,
|
|
58
65
|
estimateTokens: () => estimateTokens,
|
|
59
66
|
exportHistory: () => exportHistory,
|
|
@@ -69,9 +76,13 @@ __export(index_exports, {
|
|
|
69
76
|
getElapsedTime: () => getElapsedTime,
|
|
70
77
|
getFileExtension: () => getFileExtension,
|
|
71
78
|
getHistorySummary: () => getHistorySummary,
|
|
79
|
+
getModelPreset: () => getModelPreset,
|
|
72
80
|
getParser: () => getParser,
|
|
81
|
+
getProjectSizeTier: () => getProjectSizeTier,
|
|
73
82
|
getRating: () => getRating,
|
|
74
83
|
getRatingDisplay: () => getRatingDisplay,
|
|
84
|
+
getRatingWithContext: () => getRatingWithContext,
|
|
85
|
+
getRecommendedThreshold: () => getRecommendedThreshold,
|
|
75
86
|
getSupportedLanguages: () => getSupportedLanguages,
|
|
76
87
|
getToolWeight: () => getToolWeight,
|
|
77
88
|
handleCLIError: () => handleCLIError,
|
|
@@ -694,16 +705,57 @@ var DEFAULT_TOOL_WEIGHTS = {
|
|
|
694
705
|
"pattern-detect": 40,
|
|
695
706
|
"context-analyzer": 35,
|
|
696
707
|
"consistency": 25,
|
|
697
|
-
"
|
|
698
|
-
"
|
|
708
|
+
"hallucination-risk": 20,
|
|
709
|
+
"agent-grounding": 18,
|
|
710
|
+
"testability": 18,
|
|
711
|
+
"doc-drift": 15,
|
|
712
|
+
"deps": 12
|
|
699
713
|
};
|
|
700
714
|
var TOOL_NAME_MAP = {
|
|
701
715
|
"patterns": "pattern-detect",
|
|
702
716
|
"context": "context-analyzer",
|
|
703
717
|
"consistency": "consistency",
|
|
718
|
+
"hallucination": "hallucination-risk",
|
|
719
|
+
"hallucination-risk": "hallucination-risk",
|
|
720
|
+
"grounding": "agent-grounding",
|
|
721
|
+
"agent-grounding": "agent-grounding",
|
|
722
|
+
"testability": "testability",
|
|
723
|
+
"tests": "testability",
|
|
704
724
|
"doc-drift": "doc-drift",
|
|
725
|
+
"docs": "doc-drift",
|
|
705
726
|
"deps": "deps"
|
|
706
727
|
};
|
|
728
|
+
var CONTEXT_TIER_THRESHOLDS = {
|
|
729
|
+
compact: { idealTokens: 3e3, criticalTokens: 1e4, idealDepth: 4 },
|
|
730
|
+
standard: { idealTokens: 5e3, criticalTokens: 15e3, idealDepth: 5 },
|
|
731
|
+
extended: { idealTokens: 15e3, criticalTokens: 5e4, idealDepth: 7 },
|
|
732
|
+
frontier: { idealTokens: 5e4, criticalTokens: 15e4, idealDepth: 10 }
|
|
733
|
+
};
|
|
734
|
+
var SIZE_ADJUSTED_THRESHOLDS = {
|
|
735
|
+
"xs": 80,
|
|
736
|
+
// < 50 files
|
|
737
|
+
"small": 75,
|
|
738
|
+
// 50-200 files
|
|
739
|
+
"medium": 70,
|
|
740
|
+
// 200-500 files
|
|
741
|
+
"large": 65,
|
|
742
|
+
// 500-2000 files
|
|
743
|
+
"enterprise": 58
|
|
744
|
+
// 2000+ files
|
|
745
|
+
};
|
|
746
|
+
function getProjectSizeTier(fileCount) {
|
|
747
|
+
if (fileCount < 50) return "xs";
|
|
748
|
+
if (fileCount < 200) return "small";
|
|
749
|
+
if (fileCount < 500) return "medium";
|
|
750
|
+
if (fileCount < 2e3) return "large";
|
|
751
|
+
return "enterprise";
|
|
752
|
+
}
|
|
753
|
+
function getRecommendedThreshold(fileCount, modelTier = "standard") {
|
|
754
|
+
const sizeTier = getProjectSizeTier(fileCount);
|
|
755
|
+
const base = SIZE_ADJUSTED_THRESHOLDS[sizeTier];
|
|
756
|
+
const modelBonus = modelTier === "frontier" ? -3 : modelTier === "extended" ? -2 : 0;
|
|
757
|
+
return base + modelBonus;
|
|
758
|
+
}
|
|
707
759
|
function normalizeToolName(shortName) {
|
|
708
760
|
return TOOL_NAME_MAP[shortName] || shortName;
|
|
709
761
|
}
|
|
@@ -786,6 +838,11 @@ function getRating(score) {
|
|
|
786
838
|
if (score >= 40) return "Needs Work";
|
|
787
839
|
return "Critical";
|
|
788
840
|
}
|
|
841
|
+
function getRatingWithContext(score, fileCount, modelTier = "standard") {
|
|
842
|
+
const threshold = getRecommendedThreshold(fileCount, modelTier);
|
|
843
|
+
const normalized = score - threshold + 70;
|
|
844
|
+
return getRating(normalized);
|
|
845
|
+
}
|
|
789
846
|
function getRatingDisplay(rating) {
|
|
790
847
|
switch (rating) {
|
|
791
848
|
case "Excellent":
|
|
@@ -834,11 +891,87 @@ function formatToolScore(output) {
|
|
|
834
891
|
}
|
|
835
892
|
|
|
836
893
|
// src/business-metrics.ts
|
|
894
|
+
var MODEL_PRICING_PRESETS = {
|
|
895
|
+
"gpt-4": {
|
|
896
|
+
name: "GPT-4",
|
|
897
|
+
pricePer1KInputTokens: 0.03,
|
|
898
|
+
pricePer1KOutputTokens: 0.06,
|
|
899
|
+
contextTier: "standard",
|
|
900
|
+
typicalQueriesPerDevPerDay: 40
|
|
901
|
+
},
|
|
902
|
+
"gpt-4o": {
|
|
903
|
+
name: "GPT-4o",
|
|
904
|
+
pricePer1KInputTokens: 5e-3,
|
|
905
|
+
pricePer1KOutputTokens: 0.015,
|
|
906
|
+
contextTier: "extended",
|
|
907
|
+
typicalQueriesPerDevPerDay: 60
|
|
908
|
+
},
|
|
909
|
+
"gpt-4o-mini": {
|
|
910
|
+
name: "GPT-4o mini",
|
|
911
|
+
pricePer1KInputTokens: 15e-5,
|
|
912
|
+
pricePer1KOutputTokens: 6e-4,
|
|
913
|
+
contextTier: "extended",
|
|
914
|
+
typicalQueriesPerDevPerDay: 120
|
|
915
|
+
},
|
|
916
|
+
"claude-3-5-sonnet": {
|
|
917
|
+
name: "Claude 3.5 Sonnet",
|
|
918
|
+
pricePer1KInputTokens: 3e-3,
|
|
919
|
+
pricePer1KOutputTokens: 0.015,
|
|
920
|
+
contextTier: "extended",
|
|
921
|
+
typicalQueriesPerDevPerDay: 80
|
|
922
|
+
},
|
|
923
|
+
"claude-3-7-sonnet": {
|
|
924
|
+
name: "Claude 3.7 Sonnet",
|
|
925
|
+
pricePer1KInputTokens: 3e-3,
|
|
926
|
+
pricePer1KOutputTokens: 0.015,
|
|
927
|
+
contextTier: "frontier",
|
|
928
|
+
typicalQueriesPerDevPerDay: 80
|
|
929
|
+
},
|
|
930
|
+
"claude-sonnet-4": {
|
|
931
|
+
name: "Claude Sonnet 4",
|
|
932
|
+
pricePer1KInputTokens: 3e-3,
|
|
933
|
+
pricePer1KOutputTokens: 0.015,
|
|
934
|
+
contextTier: "frontier",
|
|
935
|
+
typicalQueriesPerDevPerDay: 80
|
|
936
|
+
},
|
|
937
|
+
"gemini-1-5-pro": {
|
|
938
|
+
name: "Gemini 1.5 Pro",
|
|
939
|
+
pricePer1KInputTokens: 125e-5,
|
|
940
|
+
pricePer1KOutputTokens: 5e-3,
|
|
941
|
+
contextTier: "frontier",
|
|
942
|
+
typicalQueriesPerDevPerDay: 80
|
|
943
|
+
},
|
|
944
|
+
"gemini-2-0-flash": {
|
|
945
|
+
name: "Gemini 2.0 Flash",
|
|
946
|
+
pricePer1KInputTokens: 1e-4,
|
|
947
|
+
pricePer1KOutputTokens: 4e-4,
|
|
948
|
+
contextTier: "frontier",
|
|
949
|
+
typicalQueriesPerDevPerDay: 150
|
|
950
|
+
},
|
|
951
|
+
"copilot": {
|
|
952
|
+
name: "GitHub Copilot (subscription)",
|
|
953
|
+
// Amortized per-request cost for a $19/month plan at 80 queries/day
|
|
954
|
+
pricePer1KInputTokens: 1e-4,
|
|
955
|
+
pricePer1KOutputTokens: 1e-4,
|
|
956
|
+
contextTier: "extended",
|
|
957
|
+
typicalQueriesPerDevPerDay: 80
|
|
958
|
+
},
|
|
959
|
+
"cursor-pro": {
|
|
960
|
+
name: "Cursor Pro (subscription)",
|
|
961
|
+
pricePer1KInputTokens: 1e-4,
|
|
962
|
+
pricePer1KOutputTokens: 1e-4,
|
|
963
|
+
contextTier: "frontier",
|
|
964
|
+
typicalQueriesPerDevPerDay: 100
|
|
965
|
+
}
|
|
966
|
+
};
|
|
967
|
+
function getModelPreset(modelId) {
|
|
968
|
+
return MODEL_PRICING_PRESETS[modelId] ?? MODEL_PRICING_PRESETS["gpt-4o"];
|
|
969
|
+
}
|
|
837
970
|
var DEFAULT_COST_CONFIG = {
|
|
838
|
-
pricePer1KTokens:
|
|
839
|
-
//
|
|
840
|
-
queriesPerDevPerDay:
|
|
841
|
-
// Average AI queries per developer
|
|
971
|
+
pricePer1KTokens: 5e-3,
|
|
972
|
+
// GPT-4o input price (updated from GPT-4 era 0.01)
|
|
973
|
+
queriesPerDevPerDay: 60,
|
|
974
|
+
// Average AI queries per developer (updated: 40→60 as of 2026)
|
|
842
975
|
developerCount: 5,
|
|
843
976
|
// Default team size
|
|
844
977
|
daysPerMonth: 30
|
|
@@ -889,43 +1022,63 @@ function calculateProductivityImpact(issues, hourlyRate = DEFAULT_HOURLY_RATE) {
|
|
|
889
1022
|
}
|
|
890
1023
|
function predictAcceptanceRate(toolOutputs) {
|
|
891
1024
|
const factors = [];
|
|
1025
|
+
const baseRate = 0.3;
|
|
892
1026
|
const patterns = toolOutputs.get("pattern-detect");
|
|
893
1027
|
if (patterns) {
|
|
894
|
-
const patternImpact = (patterns.score - 50) *
|
|
1028
|
+
const patternImpact = (patterns.score - 50) * 3e-3;
|
|
895
1029
|
factors.push({
|
|
896
1030
|
name: "Semantic Duplication",
|
|
897
|
-
impact: Math.round(patternImpact)
|
|
1031
|
+
impact: Math.round(patternImpact * 100)
|
|
898
1032
|
});
|
|
899
1033
|
}
|
|
900
1034
|
const context = toolOutputs.get("context-analyzer");
|
|
901
1035
|
if (context) {
|
|
902
|
-
const contextImpact = (context.score - 50) *
|
|
1036
|
+
const contextImpact = (context.score - 50) * 4e-3;
|
|
903
1037
|
factors.push({
|
|
904
1038
|
name: "Context Efficiency",
|
|
905
|
-
impact: Math.round(contextImpact)
|
|
1039
|
+
impact: Math.round(contextImpact * 100)
|
|
906
1040
|
});
|
|
907
1041
|
}
|
|
908
1042
|
const consistency = toolOutputs.get("consistency");
|
|
909
1043
|
if (consistency) {
|
|
910
|
-
const consistencyImpact = (consistency.score - 50) *
|
|
1044
|
+
const consistencyImpact = (consistency.score - 50) * 2e-3;
|
|
911
1045
|
factors.push({
|
|
912
1046
|
name: "Code Consistency",
|
|
913
|
-
impact: Math.round(consistencyImpact)
|
|
1047
|
+
impact: Math.round(consistencyImpact * 100)
|
|
1048
|
+
});
|
|
1049
|
+
}
|
|
1050
|
+
const hallucinationRisk = toolOutputs.get("hallucination-risk");
|
|
1051
|
+
if (hallucinationRisk) {
|
|
1052
|
+
const hrImpact = (50 - hallucinationRisk.score) * 2e-3;
|
|
1053
|
+
factors.push({
|
|
1054
|
+
name: "Hallucination Risk",
|
|
1055
|
+
impact: Math.round(hrImpact * 100)
|
|
914
1056
|
});
|
|
915
1057
|
}
|
|
916
|
-
const baseRate = 0.65;
|
|
917
1058
|
const totalImpact = factors.reduce((sum, f) => sum + f.impact / 100, 0);
|
|
918
|
-
const rate = Math.max(0.
|
|
919
|
-
|
|
1059
|
+
const rate = Math.max(0.05, Math.min(0.8, baseRate + totalImpact));
|
|
1060
|
+
let confidence;
|
|
1061
|
+
if (toolOutputs.size >= 4) confidence = 0.75;
|
|
1062
|
+
else if (toolOutputs.size >= 3) confidence = 0.65;
|
|
1063
|
+
else if (toolOutputs.size >= 2) confidence = 0.5;
|
|
1064
|
+
else confidence = 0.35;
|
|
920
1065
|
return {
|
|
921
1066
|
rate: Math.round(rate * 100) / 100,
|
|
922
1067
|
confidence,
|
|
923
1068
|
factors
|
|
924
1069
|
};
|
|
925
1070
|
}
|
|
926
|
-
function calculateComprehensionDifficulty(contextBudget, importDepth, fragmentation, consistencyScore, totalFiles) {
|
|
927
|
-
const
|
|
928
|
-
const
|
|
1071
|
+
function calculateComprehensionDifficulty(contextBudget, importDepth, fragmentation, consistencyScore, totalFiles, modelTier = "standard") {
|
|
1072
|
+
const tierThresholds = CONTEXT_TIER_THRESHOLDS[modelTier];
|
|
1073
|
+
const idealBudget = tierThresholds.idealTokens;
|
|
1074
|
+
const criticalBudget = tierThresholds.criticalTokens;
|
|
1075
|
+
const idealDepth = tierThresholds.idealDepth;
|
|
1076
|
+
const budgetRange = criticalBudget - idealBudget;
|
|
1077
|
+
const budgetFactor = Math.min(100, Math.max(
|
|
1078
|
+
0,
|
|
1079
|
+
(contextBudget - idealBudget) / budgetRange * 100
|
|
1080
|
+
));
|
|
1081
|
+
const depthFactor = Math.min(100, Math.max(0, (importDepth - idealDepth) * 10));
|
|
929
1082
|
const fragmentationFactor = Math.min(100, Math.max(0, (fragmentation - 0.3) * 250));
|
|
930
1083
|
const consistencyFactor = Math.min(100, Math.max(0, 100 - consistencyScore));
|
|
931
1084
|
const fileFactor = Math.min(100, Math.max(0, (totalFiles - 50) / 5));
|
|
@@ -945,12 +1098,12 @@ function calculateComprehensionDifficulty(contextBudget, importDepth, fragmentat
|
|
|
945
1098
|
{
|
|
946
1099
|
name: "Context Budget",
|
|
947
1100
|
contribution: Math.round(budgetFactor * 0.35),
|
|
948
|
-
description: `${Math.round(contextBudget)} tokens required`
|
|
1101
|
+
description: `${Math.round(contextBudget)} tokens required (${modelTier} model tier: ideal <${idealBudget.toLocaleString()})`
|
|
949
1102
|
},
|
|
950
1103
|
{
|
|
951
1104
|
name: "Import Depth",
|
|
952
1105
|
contribution: Math.round(depthFactor * 0.2),
|
|
953
|
-
description: `${importDepth.toFixed(1)} average levels`
|
|
1106
|
+
description: `${importDepth.toFixed(1)} average levels (ideal <${idealDepth} for ${modelTier})`
|
|
954
1107
|
},
|
|
955
1108
|
{
|
|
956
1109
|
name: "Code Fragmentation",
|
|
@@ -1895,6 +2048,334 @@ function calculateFutureProofScore(params) {
|
|
|
1895
2048
|
recommendations
|
|
1896
2049
|
};
|
|
1897
2050
|
}
|
|
2051
|
+
function calculateHallucinationRisk(params) {
|
|
2052
|
+
const {
|
|
2053
|
+
overloadedSymbols,
|
|
2054
|
+
magicLiterals,
|
|
2055
|
+
booleanTraps,
|
|
2056
|
+
implicitSideEffects,
|
|
2057
|
+
deepCallbacks,
|
|
2058
|
+
ambiguousNames,
|
|
2059
|
+
undocumentedExports,
|
|
2060
|
+
totalSymbols,
|
|
2061
|
+
totalExports
|
|
2062
|
+
} = params;
|
|
2063
|
+
if (totalSymbols === 0) {
|
|
2064
|
+
return {
|
|
2065
|
+
score: 0,
|
|
2066
|
+
rating: "minimal",
|
|
2067
|
+
signals: [],
|
|
2068
|
+
topRisk: "No symbols to analyze",
|
|
2069
|
+
recommendations: []
|
|
2070
|
+
};
|
|
2071
|
+
}
|
|
2072
|
+
const overloadRatio = Math.min(1, overloadedSymbols / Math.max(1, totalSymbols));
|
|
2073
|
+
const overloadSignal = {
|
|
2074
|
+
name: "Symbol Overloading",
|
|
2075
|
+
count: overloadedSymbols,
|
|
2076
|
+
riskContribution: Math.round(overloadRatio * 100 * 0.25),
|
|
2077
|
+
// 25% weight
|
|
2078
|
+
description: `${overloadedSymbols} overloaded symbols \u2014 AI picks wrong signature`
|
|
2079
|
+
};
|
|
2080
|
+
const magicRatio = Math.min(1, magicLiterals / Math.max(1, totalSymbols * 2));
|
|
2081
|
+
const magicSignal = {
|
|
2082
|
+
name: "Magic Literals",
|
|
2083
|
+
count: magicLiterals,
|
|
2084
|
+
riskContribution: Math.round(magicRatio * 100 * 0.2),
|
|
2085
|
+
// 20% weight
|
|
2086
|
+
description: `${magicLiterals} unnamed constants \u2014 AI invents wrong values`
|
|
2087
|
+
};
|
|
2088
|
+
const trapRatio = Math.min(1, booleanTraps / Math.max(1, totalSymbols));
|
|
2089
|
+
const trapSignal = {
|
|
2090
|
+
name: "Boolean Traps",
|
|
2091
|
+
count: booleanTraps,
|
|
2092
|
+
riskContribution: Math.round(trapRatio * 100 * 0.2),
|
|
2093
|
+
// 20% weight
|
|
2094
|
+
description: `${booleanTraps} boolean trap parameters \u2014 AI inverts intent`
|
|
2095
|
+
};
|
|
2096
|
+
const sideEffectRatio = Math.min(1, implicitSideEffects / Math.max(1, totalExports));
|
|
2097
|
+
const sideEffectSignal = {
|
|
2098
|
+
name: "Implicit Side Effects",
|
|
2099
|
+
count: implicitSideEffects,
|
|
2100
|
+
riskContribution: Math.round(sideEffectRatio * 100 * 0.15),
|
|
2101
|
+
// 15% weight
|
|
2102
|
+
description: `${implicitSideEffects} functions with implicit side effects \u2014 AI misses contracts`
|
|
2103
|
+
};
|
|
2104
|
+
const callbackRatio = Math.min(1, deepCallbacks / Math.max(1, totalSymbols * 0.1));
|
|
2105
|
+
const callbackSignal = {
|
|
2106
|
+
name: "Callback Nesting",
|
|
2107
|
+
count: deepCallbacks,
|
|
2108
|
+
riskContribution: Math.round(callbackRatio * 100 * 0.1),
|
|
2109
|
+
// 10% weight
|
|
2110
|
+
description: `${deepCallbacks} deep callback chains \u2014 AI loses control flow context`
|
|
2111
|
+
};
|
|
2112
|
+
const ambiguousRatio = Math.min(1, ambiguousNames / Math.max(1, totalSymbols));
|
|
2113
|
+
const ambiguousSignal = {
|
|
2114
|
+
name: "Ambiguous Names",
|
|
2115
|
+
count: ambiguousNames,
|
|
2116
|
+
riskContribution: Math.round(ambiguousRatio * 100 * 0.1),
|
|
2117
|
+
// 10% weight
|
|
2118
|
+
description: `${ambiguousNames} non-descriptive identifiers \u2014 AI guesses wrong intent`
|
|
2119
|
+
};
|
|
2120
|
+
const undocRatio = Math.min(1, undocumentedExports / Math.max(1, totalExports));
|
|
2121
|
+
const undocSignal = {
|
|
2122
|
+
name: "Undocumented Exports",
|
|
2123
|
+
count: undocumentedExports,
|
|
2124
|
+
riskContribution: Math.round(undocRatio * 100 * 0.1),
|
|
2125
|
+
// 10% weight
|
|
2126
|
+
description: `${undocumentedExports} public functions without docs \u2014 AI fabricates behavior`
|
|
2127
|
+
};
|
|
2128
|
+
const signals = [
|
|
2129
|
+
overloadSignal,
|
|
2130
|
+
magicSignal,
|
|
2131
|
+
trapSignal,
|
|
2132
|
+
sideEffectSignal,
|
|
2133
|
+
callbackSignal,
|
|
2134
|
+
ambiguousSignal,
|
|
2135
|
+
undocSignal
|
|
2136
|
+
];
|
|
2137
|
+
const score = Math.min(100, signals.reduce((sum, s) => sum + s.riskContribution, 0));
|
|
2138
|
+
let rating;
|
|
2139
|
+
if (score < 10) rating = "minimal";
|
|
2140
|
+
else if (score < 25) rating = "low";
|
|
2141
|
+
else if (score < 50) rating = "moderate";
|
|
2142
|
+
else if (score < 75) rating = "high";
|
|
2143
|
+
else rating = "severe";
|
|
2144
|
+
const topSignal = signals.reduce((a, b) => a.riskContribution > b.riskContribution ? a : b);
|
|
2145
|
+
const topRisk = topSignal.riskContribution > 0 ? topSignal.description : "No significant hallucination risks detected";
|
|
2146
|
+
const recommendations = [];
|
|
2147
|
+
if (overloadSignal.riskContribution > 5) {
|
|
2148
|
+
recommendations.push(`Rename ${overloadedSymbols} overloaded symbols to unique, intent-revealing names`);
|
|
2149
|
+
}
|
|
2150
|
+
if (magicSignal.riskContribution > 5) {
|
|
2151
|
+
recommendations.push(`Extract ${magicLiterals} magic literals into named constants`);
|
|
2152
|
+
}
|
|
2153
|
+
if (trapSignal.riskContribution > 5) {
|
|
2154
|
+
recommendations.push(`Replace ${booleanTraps} boolean traps with named options objects`);
|
|
2155
|
+
}
|
|
2156
|
+
if (undocSignal.riskContribution > 5) {
|
|
2157
|
+
recommendations.push(`Add JSDoc/docstrings to ${undocumentedExports} undocumented public functions`);
|
|
2158
|
+
}
|
|
2159
|
+
if (sideEffectSignal.riskContribution > 5) {
|
|
2160
|
+
recommendations.push("Mark functions with side effects explicitly in their names or docs");
|
|
2161
|
+
}
|
|
2162
|
+
return {
|
|
2163
|
+
score: Math.round(score),
|
|
2164
|
+
rating,
|
|
2165
|
+
signals: signals.filter((s) => s.count > 0),
|
|
2166
|
+
topRisk,
|
|
2167
|
+
recommendations
|
|
2168
|
+
};
|
|
2169
|
+
}
|
|
2170
|
+
function calculateAgentGrounding(params) {
|
|
2171
|
+
const {
|
|
2172
|
+
deepDirectories,
|
|
2173
|
+
totalDirectories,
|
|
2174
|
+
vagueFileNames,
|
|
2175
|
+
totalFiles,
|
|
2176
|
+
hasRootReadme,
|
|
2177
|
+
readmeIsFresh,
|
|
2178
|
+
barrelExports,
|
|
2179
|
+
untypedExports,
|
|
2180
|
+
totalExports,
|
|
2181
|
+
inconsistentDomainTerms,
|
|
2182
|
+
domainVocabularySize
|
|
2183
|
+
} = params;
|
|
2184
|
+
const deepDirRatio = totalDirectories > 0 ? deepDirectories / totalDirectories : 0;
|
|
2185
|
+
const structureClarityScore = Math.max(0, Math.round(100 - deepDirRatio * 80));
|
|
2186
|
+
const vagueRatio = totalFiles > 0 ? vagueFileNames / totalFiles : 0;
|
|
2187
|
+
const selfDocumentationScore = Math.max(0, Math.round(100 - vagueRatio * 90));
|
|
2188
|
+
let entryPointScore = 60;
|
|
2189
|
+
if (hasRootReadme) entryPointScore += 25;
|
|
2190
|
+
if (readmeIsFresh) entryPointScore += 10;
|
|
2191
|
+
const barrelRatio = totalFiles > 0 ? barrelExports / (totalFiles * 0.1) : 0;
|
|
2192
|
+
entryPointScore += Math.round(Math.min(5, barrelRatio * 5));
|
|
2193
|
+
entryPointScore = Math.min(100, entryPointScore);
|
|
2194
|
+
const untypedRatio = totalExports > 0 ? untypedExports / totalExports : 0;
|
|
2195
|
+
const apiClarityScore = Math.max(0, Math.round(100 - untypedRatio * 70));
|
|
2196
|
+
const inconsistencyRatio = domainVocabularySize > 0 ? inconsistentDomainTerms / domainVocabularySize : 0;
|
|
2197
|
+
const domainConsistencyScore = Math.max(0, Math.round(100 - inconsistencyRatio * 80));
|
|
2198
|
+
const score = Math.round(
|
|
2199
|
+
structureClarityScore * 0.2 + selfDocumentationScore * 0.25 + entryPointScore * 0.2 + apiClarityScore * 0.15 + domainConsistencyScore * 0.2
|
|
2200
|
+
);
|
|
2201
|
+
let rating;
|
|
2202
|
+
if (score >= 85) rating = "excellent";
|
|
2203
|
+
else if (score >= 70) rating = "good";
|
|
2204
|
+
else if (score >= 50) rating = "moderate";
|
|
2205
|
+
else if (score >= 30) rating = "poor";
|
|
2206
|
+
else rating = "disorienting";
|
|
2207
|
+
const recommendations = [];
|
|
2208
|
+
if (structureClarityScore < 70) {
|
|
2209
|
+
recommendations.push(`Flatten ${deepDirectories} overly-deep directories to improve agent navigation`);
|
|
2210
|
+
}
|
|
2211
|
+
if (selfDocumentationScore < 70) {
|
|
2212
|
+
recommendations.push(`Rename ${vagueFileNames} vague files (utils, helpers, misc) to domain-specific names`);
|
|
2213
|
+
}
|
|
2214
|
+
if (!hasRootReadme) {
|
|
2215
|
+
recommendations.push("Add a root README.md so agents understand the project context immediately");
|
|
2216
|
+
} else if (!readmeIsFresh) {
|
|
2217
|
+
recommendations.push("Update README.md \u2014 stale entry-point documentation disorients agents");
|
|
2218
|
+
}
|
|
2219
|
+
if (apiClarityScore < 70) {
|
|
2220
|
+
recommendations.push(`Add TypeScript types to ${untypedExports} untyped exports to improve API discoverability`);
|
|
2221
|
+
}
|
|
2222
|
+
if (domainConsistencyScore < 70) {
|
|
2223
|
+
recommendations.push(`Unify ${inconsistentDomainTerms} inconsistent domain terms \u2014 agents need one word per concept`);
|
|
2224
|
+
}
|
|
2225
|
+
return {
|
|
2226
|
+
score,
|
|
2227
|
+
rating,
|
|
2228
|
+
dimensions: {
|
|
2229
|
+
structureClarityScore,
|
|
2230
|
+
selfDocumentationScore,
|
|
2231
|
+
entryPointScore,
|
|
2232
|
+
apiClarityScore,
|
|
2233
|
+
domainConsistencyScore
|
|
2234
|
+
},
|
|
2235
|
+
recommendations
|
|
2236
|
+
};
|
|
2237
|
+
}
|
|
2238
|
+
function calculateTestabilityIndex(params) {
|
|
2239
|
+
const {
|
|
2240
|
+
testFiles,
|
|
2241
|
+
sourceFiles,
|
|
2242
|
+
pureFunctions,
|
|
2243
|
+
totalFunctions,
|
|
2244
|
+
injectionPatterns,
|
|
2245
|
+
totalClasses,
|
|
2246
|
+
bloatedInterfaces,
|
|
2247
|
+
totalInterfaces,
|
|
2248
|
+
externalStateMutations,
|
|
2249
|
+
hasTestFramework
|
|
2250
|
+
} = params;
|
|
2251
|
+
const rawCoverageRatio = sourceFiles > 0 ? testFiles / sourceFiles : 0;
|
|
2252
|
+
const testCoverageRatio = Math.min(100, Math.round(rawCoverageRatio * 100));
|
|
2253
|
+
const purityRatio = totalFunctions > 0 ? pureFunctions / totalFunctions : 0.5;
|
|
2254
|
+
const purityScore = Math.round(purityRatio * 100);
|
|
2255
|
+
const injectionRatio = totalClasses > 0 ? injectionPatterns / totalClasses : 0.5;
|
|
2256
|
+
const dependencyInjectionScore = Math.round(Math.min(100, injectionRatio * 100));
|
|
2257
|
+
const bloatedRatio = totalInterfaces > 0 ? bloatedInterfaces / totalInterfaces : 0;
|
|
2258
|
+
const interfaceFocusScore = Math.max(0, Math.round(100 - bloatedRatio * 80));
|
|
2259
|
+
const mutationRatio = totalFunctions > 0 ? externalStateMutations / totalFunctions : 0;
|
|
2260
|
+
const observabilityScore = Math.max(0, Math.round(100 - mutationRatio * 100));
|
|
2261
|
+
const frameworkWeight = hasTestFramework ? 1 : 0.8;
|
|
2262
|
+
const rawScore = (testCoverageRatio * 0.3 + purityScore * 0.25 + dependencyInjectionScore * 0.2 + interfaceFocusScore * 0.1 + observabilityScore * 0.15) * frameworkWeight;
|
|
2263
|
+
const score = Math.max(0, Math.min(100, Math.round(rawScore)));
|
|
2264
|
+
let rating;
|
|
2265
|
+
if (score >= 85) rating = "excellent";
|
|
2266
|
+
else if (score >= 70) rating = "good";
|
|
2267
|
+
else if (score >= 50) rating = "moderate";
|
|
2268
|
+
else if (score >= 30) rating = "poor";
|
|
2269
|
+
else rating = "unverifiable";
|
|
2270
|
+
let aiChangeSafetyRating;
|
|
2271
|
+
if (rawCoverageRatio >= 0.5 && score >= 70) aiChangeSafetyRating = "safe";
|
|
2272
|
+
else if (rawCoverageRatio >= 0.2 && score >= 50) aiChangeSafetyRating = "moderate-risk";
|
|
2273
|
+
else if (rawCoverageRatio > 0) aiChangeSafetyRating = "high-risk";
|
|
2274
|
+
else aiChangeSafetyRating = "blind-risk";
|
|
2275
|
+
const recommendations = [];
|
|
2276
|
+
if (!hasTestFramework) {
|
|
2277
|
+
recommendations.push("Add a testing framework (Jest, Vitest, pytest) \u2014 AI changes cannot be verified without tests");
|
|
2278
|
+
}
|
|
2279
|
+
if (rawCoverageRatio < 0.3) {
|
|
2280
|
+
const neededTests = Math.round(sourceFiles * 0.3 - testFiles);
|
|
2281
|
+
recommendations.push(`Add ~${neededTests} test files to reach 30% coverage ratio \u2014 minimum for safe AI assistance`);
|
|
2282
|
+
}
|
|
2283
|
+
if (purityScore < 50) {
|
|
2284
|
+
recommendations.push("Extract pure functions from side-effectful code \u2014 pure functions are trivially AI-testable");
|
|
2285
|
+
}
|
|
2286
|
+
if (dependencyInjectionScore < 50 && totalClasses > 0) {
|
|
2287
|
+
recommendations.push("Adopt dependency injection \u2014 makes classes mockable and AI-generated code verifiable");
|
|
2288
|
+
}
|
|
2289
|
+
if (externalStateMutations > totalFunctions * 0.3) {
|
|
2290
|
+
recommendations.push("Reduce direct state mutations \u2014 return values instead to improve observability");
|
|
2291
|
+
}
|
|
2292
|
+
return {
|
|
2293
|
+
score,
|
|
2294
|
+
rating,
|
|
2295
|
+
dimensions: {
|
|
2296
|
+
testCoverageRatio,
|
|
2297
|
+
purityScore,
|
|
2298
|
+
dependencyInjectionScore,
|
|
2299
|
+
interfaceFocusScore,
|
|
2300
|
+
observabilityScore
|
|
2301
|
+
},
|
|
2302
|
+
aiChangeSafetyRating,
|
|
2303
|
+
recommendations
|
|
2304
|
+
};
|
|
2305
|
+
}
|
|
2306
|
+
function calculateExtendedFutureProofScore(params) {
|
|
2307
|
+
const loadScore = 100 - params.cognitiveLoad.score;
|
|
2308
|
+
const entropyScore = 100 - params.patternEntropy.entropy * 100;
|
|
2309
|
+
const cohesionScore = params.conceptCohesion.score * 100;
|
|
2310
|
+
const hallucinationScore = 100 - params.hallucinationRisk.score;
|
|
2311
|
+
const groundingScore = params.agentGrounding.score;
|
|
2312
|
+
const testabilityScore = params.testability.score;
|
|
2313
|
+
const overall = Math.round(
|
|
2314
|
+
loadScore * 0.2 + entropyScore * 0.15 + cohesionScore * 0.15 + hallucinationScore * 0.2 + groundingScore * 0.15 + testabilityScore * 0.15
|
|
2315
|
+
);
|
|
2316
|
+
const factors = [
|
|
2317
|
+
{
|
|
2318
|
+
name: "Cognitive Load",
|
|
2319
|
+
impact: Math.round(loadScore - 50),
|
|
2320
|
+
description: params.cognitiveLoad.rating
|
|
2321
|
+
},
|
|
2322
|
+
{
|
|
2323
|
+
name: "Pattern Entropy",
|
|
2324
|
+
impact: Math.round(entropyScore - 50),
|
|
2325
|
+
description: params.patternEntropy.rating
|
|
2326
|
+
},
|
|
2327
|
+
{
|
|
2328
|
+
name: "Concept Cohesion",
|
|
2329
|
+
impact: Math.round(cohesionScore - 50),
|
|
2330
|
+
description: params.conceptCohesion.rating
|
|
2331
|
+
},
|
|
2332
|
+
{
|
|
2333
|
+
name: "Hallucination Risk",
|
|
2334
|
+
impact: Math.round(hallucinationScore - 50),
|
|
2335
|
+
description: `${params.hallucinationRisk.rating} risk (${params.hallucinationRisk.score}/100 raw)`
|
|
2336
|
+
},
|
|
2337
|
+
{
|
|
2338
|
+
name: "Agent Grounding",
|
|
2339
|
+
impact: Math.round(groundingScore - 50),
|
|
2340
|
+
description: params.agentGrounding.rating
|
|
2341
|
+
},
|
|
2342
|
+
{
|
|
2343
|
+
name: "Testability",
|
|
2344
|
+
impact: Math.round(testabilityScore - 50),
|
|
2345
|
+
description: `${params.testability.rating} \u2014 AI changes are ${params.testability.aiChangeSafetyRating}`
|
|
2346
|
+
}
|
|
2347
|
+
];
|
|
2348
|
+
const recommendations = [];
|
|
2349
|
+
for (const rec of params.hallucinationRisk.recommendations) {
|
|
2350
|
+
recommendations.push({ action: rec, estimatedImpact: 8, priority: "high" });
|
|
2351
|
+
}
|
|
2352
|
+
for (const rec of params.agentGrounding.recommendations) {
|
|
2353
|
+
recommendations.push({ action: rec, estimatedImpact: 6, priority: "medium" });
|
|
2354
|
+
}
|
|
2355
|
+
for (const rec of params.testability.recommendations) {
|
|
2356
|
+
const priority = params.testability.aiChangeSafetyRating === "blind-risk" ? "high" : "medium";
|
|
2357
|
+
recommendations.push({ action: rec, estimatedImpact: 10, priority });
|
|
2358
|
+
}
|
|
2359
|
+
for (const rec of params.patternEntropy.recommendations) {
|
|
2360
|
+
recommendations.push({ action: rec, estimatedImpact: 5, priority: "low" });
|
|
2361
|
+
}
|
|
2362
|
+
const semanticDistanceAvg = params.semanticDistances && params.semanticDistances.length > 0 ? params.semanticDistances.reduce((s, d) => s + d.distance, 0) / params.semanticDistances.length : 0;
|
|
2363
|
+
return {
|
|
2364
|
+
toolName: "future-proof",
|
|
2365
|
+
score: overall,
|
|
2366
|
+
rawMetrics: {
|
|
2367
|
+
cognitiveLoadScore: params.cognitiveLoad.score,
|
|
2368
|
+
entropyScore: params.patternEntropy.entropy,
|
|
2369
|
+
cohesionScore: params.conceptCohesion.score,
|
|
2370
|
+
hallucinationRiskScore: params.hallucinationRisk.score,
|
|
2371
|
+
agentGroundingScore: params.agentGrounding.score,
|
|
2372
|
+
testabilityScore: params.testability.score,
|
|
2373
|
+
semanticDistanceAvg
|
|
2374
|
+
},
|
|
2375
|
+
factors,
|
|
2376
|
+
recommendations
|
|
2377
|
+
};
|
|
2378
|
+
}
|
|
1898
2379
|
|
|
1899
2380
|
// src/utils/history.ts
|
|
1900
2381
|
var import_fs4 = require("fs");
|
|
@@ -1971,20 +2452,26 @@ function clearHistory(rootDir) {
|
|
|
1971
2452
|
}
|
|
1972
2453
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1973
2454
|
0 && (module.exports = {
|
|
2455
|
+
CONTEXT_TIER_THRESHOLDS,
|
|
1974
2456
|
DEFAULT_COST_CONFIG,
|
|
1975
2457
|
DEFAULT_EXCLUDE,
|
|
1976
2458
|
DEFAULT_TOOL_WEIGHTS,
|
|
1977
2459
|
LANGUAGE_EXTENSIONS,
|
|
1978
2460
|
Language,
|
|
2461
|
+
MODEL_PRICING_PRESETS,
|
|
1979
2462
|
ParseError,
|
|
1980
2463
|
ParserFactory,
|
|
1981
2464
|
PythonParser,
|
|
2465
|
+
SIZE_ADJUSTED_THRESHOLDS,
|
|
1982
2466
|
TOOL_NAME_MAP,
|
|
1983
2467
|
TypeScriptParser,
|
|
2468
|
+
calculateAgentGrounding,
|
|
1984
2469
|
calculateCognitiveLoad,
|
|
1985
2470
|
calculateComprehensionDifficulty,
|
|
1986
2471
|
calculateConceptCohesion,
|
|
2472
|
+
calculateExtendedFutureProofScore,
|
|
1987
2473
|
calculateFutureProofScore,
|
|
2474
|
+
calculateHallucinationRisk,
|
|
1988
2475
|
calculateImportSimilarity,
|
|
1989
2476
|
calculateKnowledgeConcentration,
|
|
1990
2477
|
calculateMonthlyCost,
|
|
@@ -1995,6 +2482,7 @@ function clearHistory(rootDir) {
|
|
|
1995
2482
|
calculateScoreTrend,
|
|
1996
2483
|
calculateSemanticDistance,
|
|
1997
2484
|
calculateTechnicalDebtInterest,
|
|
2485
|
+
calculateTestabilityIndex,
|
|
1998
2486
|
clearHistory,
|
|
1999
2487
|
estimateTokens,
|
|
2000
2488
|
exportHistory,
|
|
@@ -2010,9 +2498,13 @@ function clearHistory(rootDir) {
|
|
|
2010
2498
|
getElapsedTime,
|
|
2011
2499
|
getFileExtension,
|
|
2012
2500
|
getHistorySummary,
|
|
2501
|
+
getModelPreset,
|
|
2013
2502
|
getParser,
|
|
2503
|
+
getProjectSizeTier,
|
|
2014
2504
|
getRating,
|
|
2015
2505
|
getRatingDisplay,
|
|
2506
|
+
getRatingWithContext,
|
|
2507
|
+
getRecommendedThreshold,
|
|
2016
2508
|
getSupportedLanguages,
|
|
2017
2509
|
getToolWeight,
|
|
2018
2510
|
handleCLIError,
|