@aiready/context-analyzer 0.21.6 → 0.21.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -327,16 +327,6 @@ __export(index_exports, {
327
327
  getTransitiveDependencies: () => getTransitiveDependencies,
328
328
  inferDomain: () => inferDomain,
329
329
  inferDomainFromSemantics: () => inferDomainFromSemantics,
330
- isBarrelExport: () => isBarrelExport,
331
- isConfigFile: () => isConfigFile,
332
- isEmailTemplate: () => isEmailTemplate,
333
- isLambdaHandler: () => isLambdaHandler,
334
- isNextJsPage: () => isNextJsPage,
335
- isParserFile: () => isParserFile,
336
- isServiceFile: () => isServiceFile,
337
- isSessionFile: () => isSessionFile,
338
- isTypeDefinition: () => isTypeDefinition,
339
- isUtilityModule: () => isUtilityModule,
340
330
  mapScoreToRating: () => mapScoreToRating,
341
331
  runInteractiveSetup: () => runInteractiveSetup
342
332
  });
@@ -644,7 +634,7 @@ function extractExportsWithAST(content, filePath, domainOptions, fileImports) {
644
634
  dependencies: exp.dependencies,
645
635
  typeReferences: exp.typeReferences
646
636
  }));
647
- } catch (error) {
637
+ } catch {
648
638
  return extractExports(content, filePath, domainOptions, fileImports);
649
639
  }
650
640
  }
@@ -1023,6 +1013,21 @@ function detectModuleClusters(graph, options) {
1023
1013
  domainMap.get(primaryDomain).push(file);
1024
1014
  }
1025
1015
  const clusters = [];
1016
+ const generateSuggestedStructure = (files, tokens, fragmentation) => {
1017
+ const targetFiles = Math.max(1, Math.ceil(tokens / 1e4));
1018
+ const plan = [];
1019
+ if (fragmentation > 0.5) {
1020
+ plan.push(
1021
+ `Consolidate ${files.length} files scattered across multiple directories into ${targetFiles} core module(s)`
1022
+ );
1023
+ }
1024
+ if (tokens > 2e4) {
1025
+ plan.push(
1026
+ `Domain logic is very large (${Math.round(tokens / 1e3)}k tokens). Ensure clear sub-domain boundaries.`
1027
+ );
1028
+ }
1029
+ return { targetFiles, consolidationPlan: plan };
1030
+ };
1026
1031
  for (const [domain, files] of domainMap.entries()) {
1027
1032
  if (files.length < 2 || domain === "unknown") continue;
1028
1033
  const totalTokens = files.reduce((sum, file) => {
@@ -1068,87 +1073,15 @@ function detectModuleClusters(graph, options) {
1068
1073
  }
1069
1074
  return clusters;
1070
1075
  }
1071
- function generateSuggestedStructure(files, tokens, fragmentation) {
1072
- const targetFiles = Math.max(1, Math.ceil(tokens / 1e4));
1073
- const plan = [];
1074
- if (fragmentation > 0.5) {
1075
- plan.push(
1076
- `Consolidate ${files.length} files scattered across multiple directories into ${targetFiles} core module(s)`
1077
- );
1078
- }
1079
- if (tokens > 2e4) {
1080
- plan.push(
1081
- `Domain logic is very large (${Math.round(tokens / 1e3)}k tokens). Ensure clear sub-domain boundaries.`
1082
- );
1083
- }
1084
- return { targetFiles, consolidationPlan: plan };
1085
- }
1086
1076
 
1087
- // src/classifier.ts
1088
- var Classification = {
1089
- BARREL: "barrel-export",
1090
- TYPE_DEFINITION: "type-definition",
1091
- NEXTJS_PAGE: "nextjs-page",
1092
- LAMBDA_HANDLER: "lambda-handler",
1093
- SERVICE: "service-file",
1094
- EMAIL_TEMPLATE: "email-template",
1095
- PARSER: "parser-file",
1096
- COHESIVE_MODULE: "cohesive-module",
1097
- UTILITY_MODULE: "utility-module",
1098
- MIXED_CONCERNS: "mixed-concerns",
1099
- UNKNOWN: "unknown"
1100
- };
1101
- function classifyFile(node, cohesionScore = 1, domains = []) {
1102
- if (isBarrelExport(node)) {
1103
- return Classification.BARREL;
1104
- }
1105
- if (isTypeDefinition(node)) {
1106
- return Classification.TYPE_DEFINITION;
1107
- }
1108
- if (isNextJsPage(node)) {
1109
- return Classification.NEXTJS_PAGE;
1110
- }
1111
- if (isLambdaHandler(node)) {
1112
- return Classification.LAMBDA_HANDLER;
1113
- }
1114
- if (isServiceFile(node)) {
1115
- return Classification.SERVICE;
1116
- }
1117
- if (isEmailTemplate(node)) {
1118
- return Classification.EMAIL_TEMPLATE;
1119
- }
1120
- if (isParserFile(node)) {
1121
- return Classification.PARSER;
1122
- }
1123
- if (isSessionFile(node)) {
1124
- if (cohesionScore >= 0.25 && domains.length <= 1)
1125
- return Classification.COHESIVE_MODULE;
1126
- return Classification.UTILITY_MODULE;
1127
- }
1128
- if (isUtilityModule(node)) {
1129
- return Classification.UTILITY_MODULE;
1130
- }
1131
- if (isConfigFile(node)) {
1132
- return Classification.COHESIVE_MODULE;
1133
- }
1134
- if (domains.length <= 1 && domains[0] !== "unknown") {
1135
- return Classification.COHESIVE_MODULE;
1136
- }
1137
- if (domains.length > 1 && cohesionScore < 0.4) {
1138
- return Classification.MIXED_CONCERNS;
1139
- }
1140
- if (cohesionScore >= 0.7) {
1141
- return Classification.COHESIVE_MODULE;
1142
- }
1143
- return Classification.UNKNOWN;
1144
- }
1077
+ // src/heuristics.ts
1145
1078
  function isBarrelExport(node) {
1146
1079
  const { file, exports: exports2 } = node;
1147
1080
  const fileName = file.split("/").pop()?.toLowerCase();
1148
1081
  const isIndexFile = fileName === "index.ts" || fileName === "index.js";
1149
1082
  const isSmallAndManyExports = node.tokenCost < 1e3 && (exports2 || []).length > 5;
1150
1083
  const isReexportPattern = (exports2 || []).length >= 5 && (exports2 || []).every(
1151
- (e) => e.type === "const" || e.type === "function" || e.type === "type" || e.type === "interface"
1084
+ (e) => ["const", "function", "type", "interface"].includes(e.type)
1152
1085
  );
1153
1086
  return !!isIndexFile || !!isSmallAndManyExports || !!isReexportPattern;
1154
1087
  }
@@ -1158,20 +1091,19 @@ function isTypeDefinition(node) {
1158
1091
  const nodeExports = node.exports || [];
1159
1092
  const hasExports = nodeExports.length > 0;
1160
1093
  const areAllTypes = hasExports && nodeExports.every((e) => e.type === "type" || e.type === "interface");
1161
- const allTypes = !!areAllTypes;
1162
- const isTypePath = file.toLowerCase().includes("/types/") || file.toLowerCase().includes("/interfaces/") || file.toLowerCase().includes("/models/");
1163
- return allTypes || isTypePath && hasExports;
1094
+ const isTypePath = /\/(types|interfaces|models)\//i.test(file);
1095
+ return !!areAllTypes || isTypePath && hasExports;
1164
1096
  }
1165
1097
  function isUtilityModule(node) {
1166
1098
  const { file } = node;
1167
- const isUtilPath = file.toLowerCase().includes("/utils/") || file.toLowerCase().includes("/helpers/") || file.toLowerCase().includes("/util/") || file.toLowerCase().includes("/helper/");
1168
- const fileName = file.split("/").pop()?.toLowerCase();
1169
- const isUtilName = fileName?.includes("utils.") || fileName?.includes("helpers.") || fileName?.includes("util.") || fileName?.includes("helper.");
1170
- return !!isUtilPath || !!isUtilName;
1099
+ const isUtilPath = /\/(utils|helpers|util|helper)\//i.test(file);
1100
+ const fileName = file.split("/").pop()?.toLowerCase() || "";
1101
+ const isUtilName = /(utils\.|helpers\.|util\.|helper\.)/i.test(fileName);
1102
+ return isUtilPath || isUtilName;
1171
1103
  }
1172
1104
  function isLambdaHandler(node) {
1173
1105
  const { file, exports: exports2 } = node;
1174
- const fileName = file.split("/").pop()?.toLowerCase();
1106
+ const fileName = file.split("/").pop()?.toLowerCase() || "";
1175
1107
  const handlerPatterns = [
1176
1108
  "handler",
1177
1109
  ".handler.",
@@ -1180,33 +1112,29 @@ function isLambdaHandler(node) {
1180
1112
  ".lambda.",
1181
1113
  "-lambda."
1182
1114
  ];
1183
- const isHandlerName = handlerPatterns.some(
1184
- (pattern) => fileName?.includes(pattern)
1185
- );
1186
- const isHandlerPath = file.toLowerCase().includes("/handlers/") || file.toLowerCase().includes("/lambdas/") || file.toLowerCase().includes("/lambda/") || file.toLowerCase().includes("/functions/");
1115
+ const isHandlerName = handlerPatterns.some((p) => fileName.includes(p));
1116
+ const isHandlerPath = /\/(handlers|lambdas|lambda|functions)\//i.test(file);
1187
1117
  const hasHandlerExport = (exports2 || []).some(
1188
- (e) => e.name.toLowerCase() === "handler" || e.name.toLowerCase() === "main" || e.name.toLowerCase() === "lambdahandler" || e.name.toLowerCase().endsWith("handler")
1118
+ (e) => ["handler", "main", "lambdahandler"].includes(e.name.toLowerCase()) || e.name.toLowerCase().endsWith("handler")
1189
1119
  );
1190
- return !!isHandlerName || !!isHandlerPath || !!hasHandlerExport;
1120
+ return isHandlerName || isHandlerPath || hasHandlerExport;
1191
1121
  }
1192
1122
  function isServiceFile(node) {
1193
1123
  const { file, exports: exports2 } = node;
1194
- const fileName = file.split("/").pop()?.toLowerCase();
1124
+ const fileName = file.split("/").pop()?.toLowerCase() || "";
1195
1125
  const servicePatterns = ["service", ".service.", "-service.", "_service."];
1196
- const isServiceName = servicePatterns.some(
1197
- (pattern) => fileName?.includes(pattern)
1198
- );
1126
+ const isServiceName = servicePatterns.some((p) => fileName.includes(p));
1199
1127
  const isServicePath = file.toLowerCase().includes("/services/");
1200
1128
  const hasServiceNamedExport = (exports2 || []).some(
1201
- (e) => e.name.toLowerCase().includes("service") || e.name.toLowerCase().endsWith("service")
1129
+ (e) => e.name.toLowerCase().includes("service")
1202
1130
  );
1203
1131
  const hasClassExport = (exports2 || []).some((e) => e.type === "class");
1204
- return !!isServiceName || !!isServicePath || !!hasServiceNamedExport && !!hasClassExport;
1132
+ return isServiceName || isServicePath || hasServiceNamedExport && hasClassExport;
1205
1133
  }
1206
1134
  function isEmailTemplate(node) {
1207
1135
  const { file, exports: exports2 } = node;
1208
- const fileName = file.split("/").pop()?.toLowerCase();
1209
- const emailTemplatePatterns = [
1136
+ const fileName = file.split("/").pop()?.toLowerCase() || "";
1137
+ const emailPatterns = [
1210
1138
  "-email-",
1211
1139
  ".email.",
1212
1140
  "_email_",
@@ -1216,78 +1144,51 @@ function isEmailTemplate(node) {
1216
1144
  "-mail.",
1217
1145
  ".mail."
1218
1146
  ];
1219
- const isEmailTemplateName = emailTemplatePatterns.some(
1220
- (pattern) => fileName?.includes(pattern)
1221
- );
1222
- const isEmailPath = file.toLowerCase().includes("/emails/") || file.toLowerCase().includes("/mail/") || file.toLowerCase().includes("/notifications/");
1147
+ const isEmailName = emailPatterns.some((p) => fileName.includes(p));
1148
+ const isEmailPath = /\/(emails|mail|notifications)\//i.test(file);
1223
1149
  const hasTemplateFunction = (exports2 || []).some(
1224
- (e) => e.type === "function" && (e.name.toLowerCase().startsWith("render") || e.name.toLowerCase().startsWith("generate") || e.name.toLowerCase().includes("template") && e.name.toLowerCase().includes("email"))
1150
+ (e) => e.type === "function" && (e.name.toLowerCase().startsWith("render") || e.name.toLowerCase().startsWith("generate"))
1225
1151
  );
1226
- return !!isEmailPath || !!isEmailTemplateName || !!hasTemplateFunction;
1152
+ return isEmailPath || isEmailName || hasTemplateFunction;
1227
1153
  }
1228
1154
  function isParserFile(node) {
1229
1155
  const { file, exports: exports2 } = node;
1230
- const fileName = file.split("/").pop()?.toLowerCase();
1156
+ const fileName = file.split("/").pop()?.toLowerCase() || "";
1231
1157
  const parserPatterns = [
1232
1158
  "parser",
1233
1159
  ".parser.",
1234
1160
  "-parser.",
1235
1161
  "_parser.",
1236
1162
  "transform",
1237
- ".transform.",
1238
1163
  "converter",
1239
1164
  "mapper",
1240
1165
  "serializer"
1241
1166
  ];
1242
- const isParserName = parserPatterns.some(
1243
- (pattern) => fileName?.includes(pattern)
1244
- );
1245
- const isParserPath = file.toLowerCase().includes("/parsers/") || file.toLowerCase().includes("/transformers/");
1167
+ const isParserName = parserPatterns.some((p) => fileName.includes(p));
1168
+ const isParserPath = /\/(parsers|transformers)\//i.test(file);
1246
1169
  const hasParseFunction = (exports2 || []).some(
1247
- (e) => e.type === "function" && (e.name.toLowerCase().startsWith("parse") || e.name.toLowerCase().startsWith("transform") || e.name.toLowerCase().startsWith("extract"))
1170
+ (e) => e.type === "function" && (e.name.toLowerCase().startsWith("parse") || e.name.toLowerCase().startsWith("transform"))
1248
1171
  );
1249
- return !!isParserName || !!isParserPath || !!hasParseFunction;
1172
+ return isParserName || isParserPath || hasParseFunction;
1250
1173
  }
1251
1174
  function isSessionFile(node) {
1252
1175
  const { file, exports: exports2 } = node;
1253
- const fileName = file.split("/").pop()?.toLowerCase();
1176
+ const fileName = file.split("/").pop()?.toLowerCase() || "";
1254
1177
  const sessionPatterns = ["session", "state", "context", "store"];
1255
- const isSessionName = sessionPatterns.some(
1256
- (pattern) => fileName?.includes(pattern)
1257
- );
1258
- const isSessionPath = file.toLowerCase().includes("/sessions/") || file.toLowerCase().includes("/state/");
1178
+ const isSessionName = sessionPatterns.some((p) => fileName.includes(p));
1179
+ const isSessionPath = /\/(sessions|state)\//i.test(file);
1259
1180
  const hasSessionExport = (exports2 || []).some(
1260
- (e) => e.name.toLowerCase().includes("session") || e.name.toLowerCase().includes("state") || e.name.toLowerCase().includes("store")
1181
+ (e) => ["session", "state", "store"].some((p) => e.name.toLowerCase().includes(p))
1261
1182
  );
1262
- return !!isSessionName || !!isSessionPath || !!hasSessionExport;
1263
- }
1264
- function isConfigFile(node) {
1265
- const { file, exports: exports2 } = node;
1266
- const lowerPath = file.toLowerCase();
1267
- const fileName = file.split("/").pop()?.toLowerCase();
1268
- const configPatterns = [
1269
- ".config.",
1270
- "tsconfig",
1271
- "jest.config",
1272
- "package.json",
1273
- "aiready.json",
1274
- "next.config",
1275
- "sst.config"
1276
- ];
1277
- const isConfigName = configPatterns.some((p) => fileName?.includes(p));
1278
- const isConfigPath = lowerPath.includes("/config/") || lowerPath.includes("/settings/") || lowerPath.includes("/schemas/");
1279
- const hasSchemaExports = (exports2 || []).some(
1280
- (e) => e.name.toLowerCase().includes("schema") || e.name.toLowerCase().includes("config") || e.name.toLowerCase().includes("setting")
1281
- );
1282
- return !!isConfigName || !!isConfigPath || !!hasSchemaExports;
1183
+ return isSessionName || isSessionPath || hasSessionExport;
1283
1184
  }
1284
1185
  function isNextJsPage(node) {
1285
1186
  const { file, exports: exports2 } = node;
1286
1187
  const lowerPath = file.toLowerCase();
1287
- const fileName = file.split("/").pop()?.toLowerCase();
1188
+ const fileName = file.split("/").pop()?.toLowerCase() || "";
1288
1189
  const isInAppDir = lowerPath.includes("/app/") || lowerPath.startsWith("app/");
1289
- const isPageFile = fileName === "page.tsx" || fileName === "page.ts";
1290
- if (!isInAppDir || !isPageFile) return false;
1190
+ if (!isInAppDir || fileName !== "page.tsx" && fileName !== "page.ts")
1191
+ return false;
1291
1192
  const hasDefaultExport = (exports2 || []).some((e) => e.type === "default");
1292
1193
  const nextJsExports = [
1293
1194
  "metadata",
@@ -1296,10 +1197,91 @@ function isNextJsPage(node) {
1296
1197
  "jsonld",
1297
1198
  "icon"
1298
1199
  ];
1299
- const hasNextJsExports = (exports2 || []).some(
1200
+ const hasNextJsExport = (exports2 || []).some(
1300
1201
  (e) => nextJsExports.includes(e.name.toLowerCase())
1301
1202
  );
1302
- return !!hasDefaultExport || !!hasNextJsExports;
1203
+ return hasDefaultExport || hasNextJsExport;
1204
+ }
1205
+ function isConfigFile(node) {
1206
+ const { file, exports: exports2 } = node;
1207
+ const lowerPath = file.toLowerCase();
1208
+ const fileName = file.split("/").pop()?.toLowerCase() || "";
1209
+ const configPatterns = [
1210
+ ".config.",
1211
+ "tsconfig",
1212
+ "jest.config",
1213
+ "package.json",
1214
+ "aiready.json",
1215
+ "next.config",
1216
+ "sst.config"
1217
+ ];
1218
+ const isConfigName = configPatterns.some((p) => fileName.includes(p));
1219
+ const isConfigPath = /\/(config|settings|schemas)\//i.test(lowerPath);
1220
+ const hasSchemaExport = (exports2 || []).some(
1221
+ (e) => ["schema", "config", "setting"].some(
1222
+ (p) => e.name.toLowerCase().includes(p)
1223
+ )
1224
+ );
1225
+ return isConfigName || isConfigPath || hasSchemaExport;
1226
+ }
1227
+
1228
+ // src/classifier.ts
1229
+ var Classification = {
1230
+ BARREL: "barrel-export",
1231
+ TYPE_DEFINITION: "type-definition",
1232
+ NEXTJS_PAGE: "nextjs-page",
1233
+ LAMBDA_HANDLER: "lambda-handler",
1234
+ SERVICE: "service-file",
1235
+ EMAIL_TEMPLATE: "email-template",
1236
+ PARSER: "parser-file",
1237
+ COHESIVE_MODULE: "cohesive-module",
1238
+ UTILITY_MODULE: "utility-module",
1239
+ MIXED_CONCERNS: "mixed-concerns",
1240
+ UNKNOWN: "unknown"
1241
+ };
1242
+ function classifyFile(node, cohesionScore = 1, domains = []) {
1243
+ if (isBarrelExport(node)) {
1244
+ return Classification.BARREL;
1245
+ }
1246
+ if (isTypeDefinition(node)) {
1247
+ return Classification.TYPE_DEFINITION;
1248
+ }
1249
+ if (isNextJsPage(node)) {
1250
+ return Classification.NEXTJS_PAGE;
1251
+ }
1252
+ if (isLambdaHandler(node)) {
1253
+ return Classification.LAMBDA_HANDLER;
1254
+ }
1255
+ if (isServiceFile(node)) {
1256
+ return Classification.SERVICE;
1257
+ }
1258
+ if (isEmailTemplate(node)) {
1259
+ return Classification.EMAIL_TEMPLATE;
1260
+ }
1261
+ if (isParserFile(node)) {
1262
+ return Classification.PARSER;
1263
+ }
1264
+ if (isSessionFile(node)) {
1265
+ if (cohesionScore >= 0.25 && domains.length <= 1)
1266
+ return Classification.COHESIVE_MODULE;
1267
+ return Classification.UTILITY_MODULE;
1268
+ }
1269
+ if (isUtilityModule(node)) {
1270
+ return Classification.UTILITY_MODULE;
1271
+ }
1272
+ if (isConfigFile(node)) {
1273
+ return Classification.COHESIVE_MODULE;
1274
+ }
1275
+ if (domains.length <= 1 && domains[0] !== "unknown") {
1276
+ return Classification.COHESIVE_MODULE;
1277
+ }
1278
+ if (domains.length > 1 && cohesionScore < 0.4) {
1279
+ return Classification.MIXED_CONCERNS;
1280
+ }
1281
+ if (cohesionScore >= 0.7) {
1282
+ return Classification.COHESIVE_MODULE;
1283
+ }
1284
+ return Classification.UNKNOWN;
1303
1285
  }
1304
1286
  function adjustCohesionForClassification(baseCohesion, classification, node) {
1305
1287
  switch (classification) {
@@ -1507,7 +1489,7 @@ function calculateCohesion(exports2, filePath, options) {
1507
1489
  async function analyzeContext(options) {
1508
1490
  const {
1509
1491
  maxDepth = 5,
1510
- maxContextBudget = 1e4,
1492
+ maxContextBudget = 25e3,
1511
1493
  minCohesion = 0.6,
1512
1494
  maxFragmentation = 0.5,
1513
1495
  includeNodeModules = false,
@@ -1875,11 +1857,7 @@ function calculateContextScore(summary, costConfig) {
1875
1857
  };
1876
1858
  }
1877
1859
  function mapScoreToRating(score) {
1878
- if (score >= 90) return "excellent";
1879
- if (score >= 75) return "good";
1880
- if (score >= 60) return "fair";
1881
- if (score >= 40) return "needs work";
1882
- return "critical";
1860
+ return (0, import_core8.getRatingSlug)(score).replace("-", " ");
1883
1861
  }
1884
1862
 
1885
1863
  // src/provider.ts
@@ -2332,16 +2310,6 @@ import_core11.ToolRegistry.register(ContextAnalyzerProvider);
2332
2310
  getTransitiveDependencies,
2333
2311
  inferDomain,
2334
2312
  inferDomainFromSemantics,
2335
- isBarrelExport,
2336
- isConfigFile,
2337
- isEmailTemplate,
2338
- isLambdaHandler,
2339
- isNextJsPage,
2340
- isParserFile,
2341
- isServiceFile,
2342
- isSessionFile,
2343
- isTypeDefinition,
2344
- isUtilityModule,
2345
2313
  mapScoreToRating,
2346
2314
  runInteractiveSetup
2347
2315
  });
package/dist/index.mjs CHANGED
@@ -31,18 +31,8 @@ import {
31
31
  getTransitiveDependencies,
32
32
  inferDomain,
33
33
  inferDomainFromSemantics,
34
- isBarrelExport,
35
- isConfigFile,
36
- isEmailTemplate,
37
- isLambdaHandler,
38
- isNextJsPage,
39
- isParserFile,
40
- isServiceFile,
41
- isSessionFile,
42
- isTypeDefinition,
43
- isUtilityModule,
44
34
  runInteractiveSetup
45
- } from "./chunk-XIXAWCMS.mjs";
35
+ } from "./chunk-D25B5LZR.mjs";
46
36
  import "./chunk-64U3PNO3.mjs";
47
37
 
48
38
  // src/index.ts
@@ -60,7 +50,8 @@ import {
60
50
  calculateMonthlyCost,
61
51
  calculateProductivityImpact,
62
52
  DEFAULT_COST_CONFIG,
63
- ToolName
53
+ ToolName,
54
+ getRatingSlug
64
55
  } from "@aiready/core";
65
56
  function calculateContextScore(summary, costConfig) {
66
57
  const {
@@ -201,11 +192,7 @@ function calculateContextScore(summary, costConfig) {
201
192
  };
202
193
  }
203
194
  function mapScoreToRating(score) {
204
- if (score >= 90) return "excellent";
205
- if (score >= 75) return "good";
206
- if (score >= 60) return "fair";
207
- if (score >= 40) return "needs work";
208
- return "critical";
195
+ return getRatingSlug(score).replace("-", " ");
209
196
  }
210
197
 
211
198
  // src/provider.ts
@@ -336,16 +323,6 @@ export {
336
323
  getTransitiveDependencies,
337
324
  inferDomain,
338
325
  inferDomainFromSemantics,
339
- isBarrelExport,
340
- isConfigFile,
341
- isEmailTemplate,
342
- isLambdaHandler,
343
- isNextJsPage,
344
- isParserFile,
345
- isServiceFile,
346
- isSessionFile,
347
- isTypeDefinition,
348
- isUtilityModule,
349
326
  mapScoreToRating,
350
327
  runInteractiveSetup
351
328
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aiready/context-analyzer",
3
- "version": "0.21.6",
3
+ "version": "0.21.8",
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.23.2"
52
+ "@aiready/core": "0.23.4"
53
53
  },
54
54
  "devDependencies": {
55
55
  "@types/node": "^24.0.0",
package/src/analyzer.ts CHANGED
@@ -1,9 +1,4 @@
1
- import {
2
- estimateTokens,
3
- Severity,
4
- scanFiles,
5
- readFileContent,
6
- } from '@aiready/core';
1
+ import { scanFiles, readFileContent } from '@aiready/core';
7
2
  import type {
8
3
  ExportInfo,
9
4
  ContextAnalysisResult,
@@ -29,8 +24,13 @@ import {
29
24
  import { getClassificationRecommendations } from './remediation';
30
25
 
31
26
  /**
32
- * Calculate cohesion score (how related are exports in a file)
33
- * Legacy wrapper for backward compatibility with exact test expectations
27
+ * Calculate cohesion score (how related are exports in a file).
28
+ * Legacy wrapper for backward compatibility with exact test expectations.
29
+ *
30
+ * @param exports - List of exported symbols
31
+ * @param filePath - Path to the file being analyzed
32
+ * @param options - Additional options for cohesion calculation
33
+ * @returns Cohesion score between 0 and 1
34
34
  */
35
35
  export function calculateCohesion(
36
36
  exports: ExportInfo[],
@@ -43,12 +43,20 @@ export function calculateCohesion(
43
43
  /**
44
44
  * Analyze AI context window cost for a codebase
45
45
  */
46
+ /**
47
+ * Performs deep context analysis of a project.
48
+ * Scans files, builds a dependency graph, calculates context budgets,
49
+ * and identifies structural issues like high fragmentation or depth.
50
+ *
51
+ * @param options - Analysis parameters including root directory and focus areas
52
+ * @returns Comprehensive analysis results with metrics and identified issues
53
+ */
46
54
  export async function analyzeContext(
47
55
  options: ContextAnalyzerOptions
48
56
  ): Promise<ContextAnalysisResult[]> {
49
57
  const {
50
58
  maxDepth = 5,
51
- maxContextBudget = 10000,
59
+ maxContextBudget = 25000,
52
60
  minCohesion = 0.6,
53
61
  maxFragmentation = 0.5,
54
62
  includeNodeModules = false,
package/src/ast-utils.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { parseFileExports } from '@aiready/core';
2
- import type { ExportInfo, DependencyNode, FileClassification } from './types';
2
+ import type { ExportInfo } from './types';
3
3
  import { inferDomain, extractExports } from './semantic-analysis';
4
4
 
5
5
  /**
@@ -33,7 +33,7 @@ export function extractExportsWithAST(
33
33
  dependencies: exp.dependencies,
34
34
  typeReferences: (exp as any).typeReferences,
35
35
  }));
36
- } catch (error) {
36
+ } catch {
37
37
  // Ultimate fallback
38
38
  return extractExports(content, filePath, domainOptions, fileImports);
39
39
  }