@aiready/context-analyzer 0.9.26 → 0.9.28
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/.turbo/turbo-build.log +11 -11
- package/.turbo/turbo-test.log +21 -20
- package/dist/chunk-FYI56A5M.mjs +1892 -0
- package/dist/chunk-I77HFFZU.mjs +1876 -0
- package/dist/chunk-KYSZF5N6.mjs +1876 -0
- package/dist/chunk-M64RHH4D.mjs +1896 -0
- package/dist/chunk-OP4G6GLN.mjs +1876 -0
- package/dist/chunk-P3T3H27S.mjs +1895 -0
- package/dist/chunk-VBWXHKGD.mjs +1895 -0
- package/dist/cli.js +197 -36
- package/dist/cli.mjs +1 -1
- package/dist/index.d.mts +6 -2
- package/dist/index.d.ts +6 -2
- package/dist/index.js +202 -32
- package/dist/index.mjs +1 -1
- package/package.json +2 -2
- package/src/analyzer.ts +168 -34
- package/src/index.ts +1 -1
- package/src/scoring.ts +28 -1
package/dist/index.js
CHANGED
|
@@ -37,7 +37,7 @@ __export(python_context_exports, {
|
|
|
37
37
|
});
|
|
38
38
|
async function analyzePythonContext(files, rootDir) {
|
|
39
39
|
const results = [];
|
|
40
|
-
const parser = (0,
|
|
40
|
+
const parser = (0, import_core3.getParser)("dummy.py");
|
|
41
41
|
if (!parser) {
|
|
42
42
|
console.warn("Python parser not available");
|
|
43
43
|
return results;
|
|
@@ -86,7 +86,7 @@ async function analyzePythonContext(files, rootDir) {
|
|
|
86
86
|
}
|
|
87
87
|
async function buildPythonDependencyGraph(files, rootDir) {
|
|
88
88
|
const graph = /* @__PURE__ */ new Map();
|
|
89
|
-
const parser = (0,
|
|
89
|
+
const parser = (0, import_core3.getParser)("dummy.py");
|
|
90
90
|
if (!parser) return graph;
|
|
91
91
|
for (const file of files) {
|
|
92
92
|
try {
|
|
@@ -167,7 +167,7 @@ async function calculatePythonImportDepth(file, dependencyGraph, visited, depth
|
|
|
167
167
|
return maxDepth;
|
|
168
168
|
}
|
|
169
169
|
function estimateContextBudget(code, imports, dependencyGraph) {
|
|
170
|
-
let budget = (0,
|
|
170
|
+
let budget = (0, import_core3.estimateTokens)(code);
|
|
171
171
|
const avgTokensPerDep = 500;
|
|
172
172
|
budget += imports.length * avgTokensPerDep;
|
|
173
173
|
return budget;
|
|
@@ -217,11 +217,11 @@ function detectCircularDependencies2(file, dependencyGraph) {
|
|
|
217
217
|
dfs(file, []);
|
|
218
218
|
return [...new Set(circular)];
|
|
219
219
|
}
|
|
220
|
-
var
|
|
220
|
+
var import_core3, import_path;
|
|
221
221
|
var init_python_context = __esm({
|
|
222
222
|
"src/analyzers/python-context.ts"() {
|
|
223
223
|
"use strict";
|
|
224
|
-
|
|
224
|
+
import_core3 = require("@aiready/core");
|
|
225
225
|
import_path = require("path");
|
|
226
226
|
}
|
|
227
227
|
});
|
|
@@ -244,7 +244,7 @@ __export(index_exports, {
|
|
|
244
244
|
inferDomainFromSemantics: () => inferDomainFromSemantics
|
|
245
245
|
});
|
|
246
246
|
module.exports = __toCommonJS(index_exports);
|
|
247
|
-
var
|
|
247
|
+
var import_core4 = require("@aiready/core");
|
|
248
248
|
|
|
249
249
|
// src/analyzer.ts
|
|
250
250
|
var import_core = require("@aiready/core");
|
|
@@ -645,9 +645,9 @@ function calculatePathEntropy(files) {
|
|
|
645
645
|
if (counts.length <= 1) return 0;
|
|
646
646
|
const total = counts.reduce((s, v) => s + v, 0);
|
|
647
647
|
let entropy = 0;
|
|
648
|
-
for (const
|
|
649
|
-
const
|
|
650
|
-
entropy -=
|
|
648
|
+
for (const count of counts) {
|
|
649
|
+
const prob = count / total;
|
|
650
|
+
entropy -= prob * Math.log2(prob);
|
|
651
651
|
}
|
|
652
652
|
const maxEntropy = Math.log2(counts.length);
|
|
653
653
|
return maxEntropy > 0 ? entropy / maxEntropy : 0;
|
|
@@ -915,8 +915,8 @@ function calculateStructuralCohesionFromCoUsage(file, coUsageMatrix) {
|
|
|
915
915
|
}
|
|
916
916
|
if (probs.length <= 1) return 1;
|
|
917
917
|
let entropy = 0;
|
|
918
|
-
for (const
|
|
919
|
-
entropy -=
|
|
918
|
+
for (const prob of probs) {
|
|
919
|
+
entropy -= prob * Math.log2(prob);
|
|
920
920
|
}
|
|
921
921
|
const maxEntropy = Math.log2(probs.length);
|
|
922
922
|
return maxEntropy > 0 ? 1 - entropy / maxEntropy : 1;
|
|
@@ -956,10 +956,10 @@ function calculateDomainCohesion(exports2) {
|
|
|
956
956
|
}
|
|
957
957
|
const total = domains.length;
|
|
958
958
|
let entropy = 0;
|
|
959
|
-
for (const
|
|
960
|
-
const
|
|
961
|
-
if (
|
|
962
|
-
entropy -=
|
|
959
|
+
for (const domainCount of domainCounts.values()) {
|
|
960
|
+
const prob = domainCount / total;
|
|
961
|
+
if (prob > 0) {
|
|
962
|
+
entropy -= prob * Math.log2(prob);
|
|
963
963
|
}
|
|
964
964
|
}
|
|
965
965
|
const maxEntropy = Math.log2(total);
|
|
@@ -979,6 +979,9 @@ function classifyFile(node, cohesionScore, domains) {
|
|
|
979
979
|
if (isLambdaHandler(node)) {
|
|
980
980
|
return "lambda-handler";
|
|
981
981
|
}
|
|
982
|
+
if (isDataAccessFile(node)) {
|
|
983
|
+
return "cohesive-module";
|
|
984
|
+
}
|
|
982
985
|
if (isEmailTemplate(node)) {
|
|
983
986
|
return "email-template";
|
|
984
987
|
}
|
|
@@ -997,11 +1000,17 @@ function classifyFile(node, cohesionScore, domains) {
|
|
|
997
1000
|
if (isUtilityFile(node)) {
|
|
998
1001
|
return "utility-module";
|
|
999
1002
|
}
|
|
1003
|
+
if (file.toLowerCase().includes("/utils/") || file.toLowerCase().includes("/helpers/")) {
|
|
1004
|
+
return "utility-module";
|
|
1005
|
+
}
|
|
1000
1006
|
const uniqueDomains = domains.filter((d) => d !== "unknown");
|
|
1001
1007
|
const hasSingleDomain = uniqueDomains.length <= 1;
|
|
1002
1008
|
if (hasSingleDomain) {
|
|
1003
1009
|
return "cohesive-module";
|
|
1004
1010
|
}
|
|
1011
|
+
if (allExportsShareEntityNoun(exports2)) {
|
|
1012
|
+
return "cohesive-module";
|
|
1013
|
+
}
|
|
1005
1014
|
const hasMultipleDomains = uniqueDomains.length > 1;
|
|
1006
1015
|
const hasLowCohesion = cohesionScore < 0.4;
|
|
1007
1016
|
if (hasMultipleDomains && hasLowCohesion) {
|
|
@@ -1093,6 +1102,107 @@ function isUtilityFile(node) {
|
|
|
1093
1102
|
const hasManySmallExportsInUtilityContext = exports2.length >= 3 && exports2.every((e) => e.type === "function" || e.type === "const") && (isUtilityName || isUtilityPath);
|
|
1094
1103
|
return isUtilityName || isUtilityPath || hasManySmallExportsInUtilityContext;
|
|
1095
1104
|
}
|
|
1105
|
+
function splitCamelCase(name) {
|
|
1106
|
+
return name.replace(/([A-Z])/g, " $1").trim().toLowerCase().split(/[\s_-]+/).filter(Boolean);
|
|
1107
|
+
}
|
|
1108
|
+
var SKIP_WORDS = /* @__PURE__ */ new Set([
|
|
1109
|
+
"get",
|
|
1110
|
+
"set",
|
|
1111
|
+
"create",
|
|
1112
|
+
"update",
|
|
1113
|
+
"delete",
|
|
1114
|
+
"fetch",
|
|
1115
|
+
"save",
|
|
1116
|
+
"load",
|
|
1117
|
+
"parse",
|
|
1118
|
+
"format",
|
|
1119
|
+
"validate",
|
|
1120
|
+
"convert",
|
|
1121
|
+
"transform",
|
|
1122
|
+
"build",
|
|
1123
|
+
"generate",
|
|
1124
|
+
"render",
|
|
1125
|
+
"send",
|
|
1126
|
+
"receive",
|
|
1127
|
+
"find",
|
|
1128
|
+
"list",
|
|
1129
|
+
"add",
|
|
1130
|
+
"remove",
|
|
1131
|
+
"insert",
|
|
1132
|
+
"upsert",
|
|
1133
|
+
"put",
|
|
1134
|
+
"read",
|
|
1135
|
+
"write",
|
|
1136
|
+
"check",
|
|
1137
|
+
"handle",
|
|
1138
|
+
"process",
|
|
1139
|
+
"compute",
|
|
1140
|
+
"calculate",
|
|
1141
|
+
"init",
|
|
1142
|
+
"reset",
|
|
1143
|
+
"clear",
|
|
1144
|
+
"pending",
|
|
1145
|
+
"active",
|
|
1146
|
+
"current",
|
|
1147
|
+
"new",
|
|
1148
|
+
"old",
|
|
1149
|
+
"all",
|
|
1150
|
+
"by",
|
|
1151
|
+
"with",
|
|
1152
|
+
"from",
|
|
1153
|
+
"to",
|
|
1154
|
+
"and",
|
|
1155
|
+
"or",
|
|
1156
|
+
"is",
|
|
1157
|
+
"has",
|
|
1158
|
+
"in",
|
|
1159
|
+
"on",
|
|
1160
|
+
"of",
|
|
1161
|
+
"the"
|
|
1162
|
+
]);
|
|
1163
|
+
function simpleSingularize(word) {
|
|
1164
|
+
if (word.endsWith("ies") && word.length > 3) return word.slice(0, -3) + "y";
|
|
1165
|
+
if (word.endsWith("ses") && word.length > 4) return word.slice(0, -2);
|
|
1166
|
+
if (word.endsWith("s") && word.length > 3) return word.slice(0, -1);
|
|
1167
|
+
return word;
|
|
1168
|
+
}
|
|
1169
|
+
function extractEntityNouns(name) {
|
|
1170
|
+
return splitCamelCase(name).filter((token) => !SKIP_WORDS.has(token) && token.length > 2).map(simpleSingularize);
|
|
1171
|
+
}
|
|
1172
|
+
function allExportsShareEntityNoun(exports2) {
|
|
1173
|
+
if (exports2.length < 2 || exports2.length > 30) return false;
|
|
1174
|
+
const nounSets = exports2.map((e) => new Set(extractEntityNouns(e.name)));
|
|
1175
|
+
if (nounSets.some((s) => s.size === 0)) return false;
|
|
1176
|
+
const [first, ...rest] = nounSets;
|
|
1177
|
+
const commonNouns = Array.from(first).filter(
|
|
1178
|
+
(noun) => rest.every((s) => s.has(noun))
|
|
1179
|
+
);
|
|
1180
|
+
return commonNouns.length > 0;
|
|
1181
|
+
}
|
|
1182
|
+
function isDataAccessFile(node) {
|
|
1183
|
+
const { file, exports: exports2 } = node;
|
|
1184
|
+
const fileName = file.split("/").pop()?.toLowerCase();
|
|
1185
|
+
const dalPatterns = [
|
|
1186
|
+
"dynamo",
|
|
1187
|
+
"database",
|
|
1188
|
+
"repository",
|
|
1189
|
+
"repo",
|
|
1190
|
+
"dao",
|
|
1191
|
+
"firestore",
|
|
1192
|
+
"postgres",
|
|
1193
|
+
"mysql",
|
|
1194
|
+
"mongo",
|
|
1195
|
+
"redis",
|
|
1196
|
+
"sqlite",
|
|
1197
|
+
"supabase",
|
|
1198
|
+
"prisma"
|
|
1199
|
+
];
|
|
1200
|
+
const isDalName = dalPatterns.some((p) => fileName?.includes(p));
|
|
1201
|
+
const isDalPath = file.toLowerCase().includes("/repositories/") || file.toLowerCase().includes("/dao/") || file.toLowerCase().includes("/data/");
|
|
1202
|
+
const hasDalExportPattern = exports2.length >= 1 && exports2.length <= 10 && allExportsShareEntityNoun(exports2);
|
|
1203
|
+
const isUtilityPathLocal = file.toLowerCase().includes("/utils/") || file.toLowerCase().includes("/helpers/");
|
|
1204
|
+
return isDalPath || isDalName && hasDalExportPattern && !isUtilityPathLocal;
|
|
1205
|
+
}
|
|
1096
1206
|
function isLambdaHandler(node) {
|
|
1097
1207
|
const { file, exports: exports2 } = node;
|
|
1098
1208
|
const fileName = file.split("/").pop()?.toLowerCase();
|
|
@@ -1107,7 +1217,7 @@ function isLambdaHandler(node) {
|
|
|
1107
1217
|
const isHandlerName = handlerPatterns.some(
|
|
1108
1218
|
(pattern) => fileName?.includes(pattern)
|
|
1109
1219
|
);
|
|
1110
|
-
const isHandlerPath = file.toLowerCase().includes("/handlers/") || file.toLowerCase().includes("/lambdas/") || file.toLowerCase().includes("/functions/");
|
|
1220
|
+
const isHandlerPath = file.toLowerCase().includes("/handlers/") || file.toLowerCase().includes("/lambdas/") || file.toLowerCase().includes("/lambda/") || file.toLowerCase().includes("/functions/");
|
|
1111
1221
|
const hasHandlerExport = exports2.some(
|
|
1112
1222
|
(e) => e.name.toLowerCase() === "handler" || e.name.toLowerCase() === "main" || e.name.toLowerCase() === "lambdahandler" || e.name.toLowerCase().endsWith("handler")
|
|
1113
1223
|
);
|
|
@@ -1247,25 +1357,25 @@ function adjustCohesionForClassification(baseCohesion, classification, node) {
|
|
|
1247
1357
|
const exportNames = node.exports.map((e) => e.name.toLowerCase());
|
|
1248
1358
|
const hasRelatedNames = hasRelatedExportNames(exportNames);
|
|
1249
1359
|
if (hasRelatedNames) {
|
|
1250
|
-
return Math.min(1, baseCohesion + 0.45);
|
|
1360
|
+
return Math.max(0.8, Math.min(1, baseCohesion + 0.45));
|
|
1251
1361
|
}
|
|
1252
1362
|
}
|
|
1253
|
-
return Math.min(1, baseCohesion + 0.35);
|
|
1363
|
+
return Math.max(0.75, Math.min(1, baseCohesion + 0.35));
|
|
1254
1364
|
}
|
|
1255
1365
|
case "service-file": {
|
|
1256
1366
|
if (node?.exports.some((e) => e.type === "class")) {
|
|
1257
|
-
return Math.min(1, baseCohesion + 0.4);
|
|
1367
|
+
return Math.max(0.78, Math.min(1, baseCohesion + 0.4));
|
|
1258
1368
|
}
|
|
1259
|
-
return Math.min(1, baseCohesion + 0.3);
|
|
1369
|
+
return Math.max(0.72, Math.min(1, baseCohesion + 0.3));
|
|
1260
1370
|
}
|
|
1261
1371
|
case "lambda-handler": {
|
|
1262
1372
|
if (node) {
|
|
1263
1373
|
const hasSingleEntry = node.exports.length === 1 || node.exports.some((e) => e.name.toLowerCase() === "handler");
|
|
1264
1374
|
if (hasSingleEntry) {
|
|
1265
|
-
return Math.min(1, baseCohesion + 0.45);
|
|
1375
|
+
return Math.max(0.8, Math.min(1, baseCohesion + 0.45));
|
|
1266
1376
|
}
|
|
1267
1377
|
}
|
|
1268
|
-
return Math.min(1, baseCohesion + 0.35);
|
|
1378
|
+
return Math.max(0.75, Math.min(1, baseCohesion + 0.35));
|
|
1269
1379
|
}
|
|
1270
1380
|
case "email-template": {
|
|
1271
1381
|
if (node) {
|
|
@@ -1273,10 +1383,10 @@ function adjustCohesionForClassification(baseCohesion, classification, node) {
|
|
|
1273
1383
|
(e) => e.name.toLowerCase().includes("render") || e.name.toLowerCase().includes("generate") || e.name.toLowerCase().includes("template")
|
|
1274
1384
|
);
|
|
1275
1385
|
if (hasTemplateFunc) {
|
|
1276
|
-
return Math.min(1, baseCohesion + 0.4);
|
|
1386
|
+
return Math.max(0.75, Math.min(1, baseCohesion + 0.4));
|
|
1277
1387
|
}
|
|
1278
1388
|
}
|
|
1279
|
-
return Math.min(1, baseCohesion + 0.3);
|
|
1389
|
+
return Math.max(0.72, Math.min(1, baseCohesion + 0.3));
|
|
1280
1390
|
}
|
|
1281
1391
|
case "parser-file": {
|
|
1282
1392
|
if (node) {
|
|
@@ -1284,10 +1394,10 @@ function adjustCohesionForClassification(baseCohesion, classification, node) {
|
|
|
1284
1394
|
(e) => e.name.toLowerCase().startsWith("parse") || e.name.toLowerCase().startsWith("transform") || e.name.toLowerCase().startsWith("convert")
|
|
1285
1395
|
);
|
|
1286
1396
|
if (hasParseFunc) {
|
|
1287
|
-
return Math.min(1, baseCohesion + 0.4);
|
|
1397
|
+
return Math.max(0.75, Math.min(1, baseCohesion + 0.4));
|
|
1288
1398
|
}
|
|
1289
1399
|
}
|
|
1290
|
-
return Math.min(1, baseCohesion + 0.3);
|
|
1400
|
+
return Math.max(0.7, Math.min(1, baseCohesion + 0.3));
|
|
1291
1401
|
}
|
|
1292
1402
|
case "nextjs-page":
|
|
1293
1403
|
return 1;
|
|
@@ -1327,6 +1437,54 @@ function hasRelatedExportNames(exportNames) {
|
|
|
1327
1437
|
const uniquePrefixes = new Set(prefixes);
|
|
1328
1438
|
if (uniquePrefixes.size === 1) return true;
|
|
1329
1439
|
}
|
|
1440
|
+
const nounSets = exportNames.map((name) => {
|
|
1441
|
+
const tokens = name.replace(/([A-Z])/g, " $1").trim().toLowerCase().split(/[\s_-]+/).filter(Boolean);
|
|
1442
|
+
const skip = /* @__PURE__ */ new Set([
|
|
1443
|
+
"get",
|
|
1444
|
+
"set",
|
|
1445
|
+
"create",
|
|
1446
|
+
"update",
|
|
1447
|
+
"delete",
|
|
1448
|
+
"fetch",
|
|
1449
|
+
"save",
|
|
1450
|
+
"load",
|
|
1451
|
+
"parse",
|
|
1452
|
+
"format",
|
|
1453
|
+
"validate",
|
|
1454
|
+
"convert",
|
|
1455
|
+
"transform",
|
|
1456
|
+
"build",
|
|
1457
|
+
"generate",
|
|
1458
|
+
"render",
|
|
1459
|
+
"send",
|
|
1460
|
+
"receive",
|
|
1461
|
+
"find",
|
|
1462
|
+
"list",
|
|
1463
|
+
"add",
|
|
1464
|
+
"remove",
|
|
1465
|
+
"insert",
|
|
1466
|
+
"upsert",
|
|
1467
|
+
"put",
|
|
1468
|
+
"read",
|
|
1469
|
+
"write",
|
|
1470
|
+
"check",
|
|
1471
|
+
"handle",
|
|
1472
|
+
"process",
|
|
1473
|
+
"pending",
|
|
1474
|
+
"active",
|
|
1475
|
+
"current",
|
|
1476
|
+
"new",
|
|
1477
|
+
"old",
|
|
1478
|
+
"all"
|
|
1479
|
+
]);
|
|
1480
|
+
const singularize2 = (w) => w.endsWith("s") && w.length > 3 ? w.slice(0, -1) : w;
|
|
1481
|
+
return new Set(tokens.filter((t) => !skip.has(t) && t.length > 2).map(singularize2));
|
|
1482
|
+
});
|
|
1483
|
+
if (nounSets.length >= 2 && nounSets.every((s) => s.size > 0)) {
|
|
1484
|
+
const [first, ...rest] = nounSets;
|
|
1485
|
+
const commonNouns = Array.from(first).filter((n) => rest.every((s) => s.has(n)));
|
|
1486
|
+
if (commonNouns.length > 0) return true;
|
|
1487
|
+
}
|
|
1330
1488
|
return false;
|
|
1331
1489
|
}
|
|
1332
1490
|
function adjustFragmentationForClassification(baseFragmentation, classification) {
|
|
@@ -1409,7 +1567,8 @@ function getClassificationRecommendations(classification, file, issues) {
|
|
|
1409
1567
|
}
|
|
1410
1568
|
|
|
1411
1569
|
// src/scoring.ts
|
|
1412
|
-
|
|
1570
|
+
var import_core2 = require("@aiready/core");
|
|
1571
|
+
function calculateContextScore(summary, costConfig) {
|
|
1413
1572
|
const {
|
|
1414
1573
|
avgContextBudget,
|
|
1415
1574
|
maxContextBudget,
|
|
@@ -1498,6 +1657,14 @@ function calculateContextScore(summary) {
|
|
|
1498
1657
|
priority: "high"
|
|
1499
1658
|
});
|
|
1500
1659
|
}
|
|
1660
|
+
const cfg = { ...import_core2.DEFAULT_COST_CONFIG, ...costConfig };
|
|
1661
|
+
const totalContextBudget = avgContextBudget * summary.totalFiles;
|
|
1662
|
+
const estimatedMonthlyCost = (0, import_core2.calculateMonthlyCost)(totalContextBudget, cfg);
|
|
1663
|
+
const issues = [
|
|
1664
|
+
...Array(criticalIssues).fill({ severity: "critical" }),
|
|
1665
|
+
...Array(majorIssues).fill({ severity: "major" })
|
|
1666
|
+
];
|
|
1667
|
+
const productivityImpact = (0, import_core2.calculateProductivityImpact)(issues);
|
|
1501
1668
|
return {
|
|
1502
1669
|
toolName: "context-analyzer",
|
|
1503
1670
|
score,
|
|
@@ -1508,7 +1675,10 @@ function calculateContextScore(summary) {
|
|
|
1508
1675
|
maxImportDepth,
|
|
1509
1676
|
avgFragmentation: Math.round(avgFragmentation * 100) / 100,
|
|
1510
1677
|
criticalIssues,
|
|
1511
|
-
majorIssues
|
|
1678
|
+
majorIssues,
|
|
1679
|
+
// Business value metrics
|
|
1680
|
+
estimatedMonthlyCost,
|
|
1681
|
+
estimatedDeveloperHours: productivityImpact.totalHours
|
|
1512
1682
|
},
|
|
1513
1683
|
factors,
|
|
1514
1684
|
recommendations
|
|
@@ -1517,7 +1687,7 @@ function calculateContextScore(summary) {
|
|
|
1517
1687
|
|
|
1518
1688
|
// src/index.ts
|
|
1519
1689
|
async function getSmartDefaults(directory, userOptions) {
|
|
1520
|
-
const files = await (0,
|
|
1690
|
+
const files = await (0, import_core4.scanFiles)({
|
|
1521
1691
|
rootDir: directory,
|
|
1522
1692
|
include: userOptions.include,
|
|
1523
1693
|
exclude: userOptions.exclude
|
|
@@ -1570,7 +1740,7 @@ async function analyzeContext(options) {
|
|
|
1570
1740
|
includeNodeModules = false,
|
|
1571
1741
|
...scanOptions
|
|
1572
1742
|
} = options;
|
|
1573
|
-
const files = await (0,
|
|
1743
|
+
const files = await (0, import_core4.scanFiles)({
|
|
1574
1744
|
...scanOptions,
|
|
1575
1745
|
// Only add node_modules to exclude if includeNodeModules is false
|
|
1576
1746
|
// The DEFAULT_EXCLUDE already includes node_modules, so this is only needed
|
|
@@ -1582,7 +1752,7 @@ async function analyzeContext(options) {
|
|
|
1582
1752
|
const fileContents = await Promise.all(
|
|
1583
1753
|
files.map(async (file) => ({
|
|
1584
1754
|
file,
|
|
1585
|
-
content: await (0,
|
|
1755
|
+
content: await (0, import_core4.readFileContent)(file)
|
|
1586
1756
|
}))
|
|
1587
1757
|
);
|
|
1588
1758
|
const graph = buildDependencyGraph(fileContents.filter((f) => !f.file.toLowerCase().endsWith(".py")));
|
|
@@ -1645,7 +1815,7 @@ async function analyzeContext(options) {
|
|
|
1645
1815
|
const importDepth = focus === "depth" || focus === "all" ? calculateImportDepth(file, graph) : 0;
|
|
1646
1816
|
const dependencyList = focus === "depth" || focus === "all" ? getTransitiveDependencies(file, graph) : [];
|
|
1647
1817
|
const contextBudget = focus === "all" ? calculateContextBudget(file, graph) : node.tokenCost;
|
|
1648
|
-
const cohesionScore = focus === "cohesion" || focus === "all" ? calculateCohesion(node.exports, file) : 1;
|
|
1818
|
+
const cohesionScore = focus === "cohesion" || focus === "all" ? calculateCohesion(node.exports, file, { coUsageMatrix: graph.coUsageMatrix }) : 1;
|
|
1649
1819
|
const fragmentationScore = fragmentationMap.get(file) || 0;
|
|
1650
1820
|
const relatedFiles = [];
|
|
1651
1821
|
for (const cluster of clusters) {
|
package/dist/index.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aiready/context-analyzer",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.28",
|
|
4
4
|
"description": "AI context window cost analysis - detect fragmented code, deep import chains, and expensive context budgets",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"commander": "^14.0.0",
|
|
50
50
|
"chalk": "^5.3.0",
|
|
51
51
|
"prompts": "^2.4.2",
|
|
52
|
-
"@aiready/core": "0.9.
|
|
52
|
+
"@aiready/core": "0.9.25"
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|
|
55
55
|
"@types/node": "^24.0.0",
|