@aiready/context-analyzer 0.21.26 → 0.21.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.
Files changed (78) hide show
  1. package/.turbo/turbo-build.log +32 -25
  2. package/.turbo/turbo-test.log +51 -87
  3. package/coverage/clover.xml +392 -1878
  4. package/coverage/coverage-final.json +15 -19
  5. package/coverage/index.html +48 -63
  6. package/coverage/src/analyzers/index.html +21 -21
  7. package/coverage/src/analyzers/python-context.ts.html +96 -96
  8. package/coverage/src/ast-utils.ts.html +34 -109
  9. package/coverage/src/classifier.ts.html +104 -104
  10. package/coverage/src/classify/classification-patterns.ts.html +1 -1
  11. package/coverage/src/classify/file-classifiers.ts.html +1 -1
  12. package/coverage/src/classify/index.html +1 -1
  13. package/coverage/src/cluster-detector.ts.html +72 -72
  14. package/coverage/src/defaults.ts.html +1 -1
  15. package/coverage/src/graph-builder.ts.html +131 -131
  16. package/coverage/src/index.html +101 -116
  17. package/coverage/src/index.ts.html +2 -2
  18. package/coverage/src/issue-analyzer.ts.html +32 -83
  19. package/coverage/src/mapper.ts.html +20 -2
  20. package/coverage/src/metrics.ts.html +127 -130
  21. package/coverage/src/orchestrator.ts.html +13 -13
  22. package/coverage/src/provider.ts.html +19 -19
  23. package/coverage/src/remediation.ts.html +59 -59
  24. package/coverage/src/report/console-report.ts.html +2 -2
  25. package/coverage/src/report/html-report.ts.html +60 -84
  26. package/coverage/src/report/index.html +7 -7
  27. package/coverage/src/report/interactive-setup.ts.html +1 -1
  28. package/coverage/src/scoring.ts.html +62 -62
  29. package/coverage/src/semantic/co-usage.ts.html +1 -1
  30. package/coverage/src/semantic/consolidation.ts.html +1 -1
  31. package/coverage/src/semantic/domain-inference.ts.html +1 -1
  32. package/coverage/src/semantic/index.html +1 -1
  33. package/coverage/src/semantic/type-graph.ts.html +1 -1
  34. package/coverage/src/summary.ts.html +67 -67
  35. package/coverage/src/types.ts.html +1 -1
  36. package/coverage/src/utils/dependency-graph-utils.ts.html +41 -41
  37. package/coverage/src/utils/index.html +21 -21
  38. package/coverage/src/utils/string-utils.ts.html +1 -1
  39. package/dist/chunk-22ZO4EKZ.mjs +1297 -0
  40. package/dist/chunk-4U4LDWGF.mjs +360 -0
  41. package/dist/chunk-BA7QGUHN.mjs +1722 -0
  42. package/dist/chunk-BCEZGRXI.mjs +1297 -0
  43. package/dist/chunk-BQCISA2F.mjs +91 -0
  44. package/dist/chunk-EMYD7NS6.mjs +137 -0
  45. package/dist/chunk-EWFR366Y.mjs +1740 -0
  46. package/dist/chunk-FO6YT6RG.mjs +1751 -0
  47. package/dist/chunk-J3SZQZNU.mjs +221 -0
  48. package/dist/chunk-OZE3FVZT.mjs +1089 -0
  49. package/dist/chunk-WHB7QI7N.mjs +91 -0
  50. package/dist/cli-action-CXIHOVAC.mjs +95 -0
  51. package/dist/cli-action-SA7SCYNV.mjs +95 -0
  52. package/dist/cli-action-YAJOJCXJ.mjs +95 -0
  53. package/dist/cli.js +688 -566
  54. package/dist/cli.mjs +4 -88
  55. package/dist/index.js +889 -773
  56. package/dist/index.mjs +21 -14
  57. package/dist/orchestrator-3L3NAZYP.mjs +10 -0
  58. package/dist/orchestrator-MONOZHVW.mjs +10 -0
  59. package/dist/orchestrator-ZR7JSKWI.mjs +10 -0
  60. package/dist/summary-7PZVW72O.mjs +7 -0
  61. package/dist/summary-LKUCJAIS.mjs +7 -0
  62. package/package.json +2 -2
  63. package/src/__tests__/analyzer.test.ts +1 -1
  64. package/src/__tests__/enhanced-cohesion.test.ts +4 -1
  65. package/src/__tests__/orchestrator.test.ts +19 -4
  66. package/src/__tests__/python-context.test.ts +6 -0
  67. package/src/__tests__/report/html-report.test.ts +8 -2
  68. package/src/ast-utils.ts +1 -26
  69. package/src/cli-definition.ts +4 -2
  70. package/src/issue-analyzer.ts +4 -19
  71. package/src/metrics.ts +1 -2
  72. package/src/provider.ts +4 -4
  73. package/src/report/html-report.ts +43 -59
  74. package/coverage/dist/chunk-64U3PNO3.mjs.html +0 -367
  75. package/coverage/dist/chunk-J3MUOWHC.mjs.html +0 -5326
  76. package/coverage/dist/index.html +0 -146
  77. package/coverage/dist/index.mjs.html +0 -1396
  78. package/coverage/src/analyzer.ts.html +0 -88
package/dist/cli.js CHANGED
@@ -30,6 +30,221 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
30
30
  mod
31
31
  ));
32
32
 
33
+ // src/metrics.ts
34
+ function calculateEnhancedCohesion(exports2, filePath, options) {
35
+ if (exports2.length <= 1) return 1;
36
+ if (filePath && (0, import_core.isTestFile)(filePath)) return 1;
37
+ const domains = exports2.map((e) => e.inferredDomain || "unknown");
38
+ const domainCounts = /* @__PURE__ */ new Map();
39
+ for (const domain of domains)
40
+ domainCounts.set(domain, (domainCounts.get(domain) || 0) + 1);
41
+ if (domainCounts.size === 1 && domains[0] !== "unknown") {
42
+ if (!options?.weights) return 1;
43
+ }
44
+ const probs = Array.from(domainCounts.values()).map(
45
+ (count) => count / exports2.length
46
+ );
47
+ let domainEntropy = 0;
48
+ for (const prob of probs) {
49
+ if (prob > 0) domainEntropy -= prob * Math.log2(prob);
50
+ }
51
+ const maxEntropy = Math.log2(Math.max(2, domainCounts.size));
52
+ const domainScore = 1 - domainEntropy / maxEntropy;
53
+ let importScoreTotal = 0;
54
+ let pairsWithData = 0;
55
+ let anyImportData = false;
56
+ for (let i = 0; i < exports2.length; i++) {
57
+ for (let j = i + 1; j < exports2.length; j++) {
58
+ const exp1Imports = exports2[i].imports;
59
+ const exp2Imports = exports2[j].imports;
60
+ if (exp1Imports || exp2Imports) {
61
+ anyImportData = true;
62
+ const sim = (0, import_core.calculateImportSimilarity)(
63
+ { ...exports2[i], imports: exp1Imports || [] },
64
+ { ...exports2[j], imports: exp2Imports || [] }
65
+ );
66
+ importScoreTotal += sim;
67
+ pairsWithData++;
68
+ }
69
+ }
70
+ }
71
+ const avgImportScore = pairsWithData > 0 ? importScoreTotal / pairsWithData : 0;
72
+ let score = anyImportData ? domainScore * 0.4 + avgImportScore * 0.6 : domainScore;
73
+ if (anyImportData && score === 0 && domainScore === 0) {
74
+ score = 0.1;
75
+ }
76
+ let structuralScore = 0;
77
+ for (const exp of exports2) {
78
+ if (exp.dependencies && exp.dependencies.length > 0) {
79
+ structuralScore += 1;
80
+ }
81
+ }
82
+ if (structuralScore > 0) {
83
+ score = Math.min(1, score + 0.1);
84
+ }
85
+ if (!options?.weights && !anyImportData && domainCounts.size === 1) return 1;
86
+ return score;
87
+ }
88
+ function calculateFragmentation(files, domain, options) {
89
+ if (files.length <= 1) return 0;
90
+ const directories = new Set(
91
+ files.map((file) => file.split("/").slice(0, -1).join("/"))
92
+ );
93
+ const uniqueDirs = directories.size;
94
+ let score = options?.useLogScale ? uniqueDirs <= 1 ? 0 : Math.log(uniqueDirs) / Math.log(options.logBase || Math.E) / (Math.log(files.length) / Math.log(options.logBase || Math.E)) : (uniqueDirs - 1) / (files.length - 1);
95
+ if (options?.sharedImportRatio && options.sharedImportRatio > 0.5) {
96
+ const discount = (options.sharedImportRatio - 0.5) * 0.4;
97
+ score = score * (1 - discount);
98
+ }
99
+ return score;
100
+ }
101
+ function calculatePathEntropy(files) {
102
+ if (!files || files.length === 0) return 0;
103
+ const dirCounts = /* @__PURE__ */ new Map();
104
+ for (const file of files) {
105
+ const dir = file.split("/").slice(0, -1).join("/") || ".";
106
+ dirCounts.set(dir, (dirCounts.get(dir) || 0) + 1);
107
+ }
108
+ const counts = Array.from(dirCounts.values());
109
+ if (counts.length <= 1) return 0;
110
+ const total = counts.reduce((sum, value) => sum + value, 0);
111
+ let entropy = 0;
112
+ for (const count of counts) {
113
+ const prob = count / total;
114
+ entropy -= prob * Math.log2(prob);
115
+ }
116
+ const maxEntropy = Math.log2(counts.length);
117
+ return maxEntropy > 0 ? entropy / maxEntropy : 0;
118
+ }
119
+ var import_core;
120
+ var init_metrics = __esm({
121
+ "src/metrics.ts"() {
122
+ "use strict";
123
+ import_core = require("@aiready/core");
124
+ }
125
+ });
126
+
127
+ // src/issue-analyzer.ts
128
+ function analyzeIssues(params) {
129
+ const {
130
+ file,
131
+ importDepth,
132
+ contextBudget,
133
+ cohesionScore,
134
+ fragmentationScore,
135
+ maxDepth,
136
+ maxContextBudget,
137
+ minCohesion,
138
+ maxFragmentation,
139
+ circularDeps
140
+ } = params;
141
+ const issues = [];
142
+ const recommendations = [];
143
+ let severity = import_core2.Severity.Info;
144
+ let potentialSavings = 0;
145
+ if (circularDeps.length > 0) {
146
+ severity = import_core2.Severity.Critical;
147
+ issues.push(`Part of ${circularDeps.length} circular dependency chain(s)`);
148
+ recommendations.push(
149
+ "Break circular dependencies by extracting interfaces or using dependency injection"
150
+ );
151
+ potentialSavings += contextBudget * 0.2;
152
+ }
153
+ if (importDepth > maxDepth * 1.5) {
154
+ severity = import_core2.Severity.Critical;
155
+ issues.push(`Import depth ${importDepth} exceeds limit by 50%`);
156
+ recommendations.push("Flatten dependency tree or use facade pattern");
157
+ potentialSavings += contextBudget * 0.3;
158
+ } else if (importDepth > maxDepth) {
159
+ if (severity !== import_core2.Severity.Critical) severity = import_core2.Severity.Major;
160
+ issues.push(
161
+ `Import depth ${importDepth} exceeds recommended maximum ${maxDepth}`
162
+ );
163
+ recommendations.push("Consider reducing dependency depth");
164
+ potentialSavings += contextBudget * 0.15;
165
+ }
166
+ if (contextBudget > maxContextBudget * 1.5) {
167
+ severity = import_core2.Severity.Critical;
168
+ issues.push(
169
+ `Context budget ${contextBudget.toLocaleString()} tokens is 50% over limit`
170
+ );
171
+ recommendations.push(
172
+ "Split into smaller modules or reduce dependency tree"
173
+ );
174
+ potentialSavings += contextBudget * 0.4;
175
+ } else if (contextBudget > maxContextBudget) {
176
+ if (severity !== import_core2.Severity.Critical) severity = import_core2.Severity.Major;
177
+ issues.push(
178
+ `Context budget ${contextBudget.toLocaleString()} exceeds ${maxContextBudget.toLocaleString()}`
179
+ );
180
+ recommendations.push("Reduce file size or dependencies");
181
+ potentialSavings += contextBudget * 0.2;
182
+ }
183
+ if (cohesionScore < minCohesion * 0.5) {
184
+ if (severity !== import_core2.Severity.Critical) severity = import_core2.Severity.Major;
185
+ issues.push(
186
+ `Very low cohesion (${(cohesionScore * 100).toFixed(0)}%) - mixed concerns`
187
+ );
188
+ recommendations.push(
189
+ "Split file by domain - separate unrelated functionality"
190
+ );
191
+ potentialSavings += contextBudget * 0.25;
192
+ } else if (cohesionScore < minCohesion) {
193
+ if (severity === import_core2.Severity.Info) severity = import_core2.Severity.Minor;
194
+ issues.push(`Low cohesion (${(cohesionScore * 100).toFixed(0)}%)`);
195
+ recommendations.push("Consider grouping related exports together");
196
+ potentialSavings += contextBudget * 0.1;
197
+ }
198
+ if (fragmentationScore > maxFragmentation) {
199
+ if (severity === import_core2.Severity.Info || severity === import_core2.Severity.Minor)
200
+ severity = import_core2.Severity.Minor;
201
+ issues.push(
202
+ `High fragmentation (${(fragmentationScore * 100).toFixed(0)}%) - scattered implementation`
203
+ );
204
+ recommendations.push("Consolidate with related files in same domain");
205
+ potentialSavings += contextBudget * 0.3;
206
+ }
207
+ if ((0, import_core2.isBuildArtifact)(file)) {
208
+ issues.push("Detected build artifact (bundled/output file)");
209
+ recommendations.push("Exclude build outputs from analysis");
210
+ severity = import_core2.Severity.Info;
211
+ potentialSavings = 0;
212
+ }
213
+ return {
214
+ severity,
215
+ issues,
216
+ recommendations,
217
+ potentialSavings: Math.floor(potentialSavings)
218
+ };
219
+ }
220
+ var import_core2;
221
+ var init_issue_analyzer = __esm({
222
+ "src/issue-analyzer.ts"() {
223
+ "use strict";
224
+ import_core2 = require("@aiready/core");
225
+ }
226
+ });
227
+
228
+ // src/utils/string-utils.ts
229
+ function singularize(word) {
230
+ const irregulars = {
231
+ people: "person",
232
+ children: "child",
233
+ men: "man",
234
+ women: "woman"
235
+ };
236
+ if (irregulars[word]) return irregulars[word];
237
+ if (word.endsWith("ies")) return word.slice(0, -3) + "y";
238
+ if (word.endsWith("ses")) return word.slice(0, -2);
239
+ if (word.endsWith("s") && word.length > 3) return word.slice(0, -1);
240
+ return word;
241
+ }
242
+ var init_string_utils = __esm({
243
+ "src/utils/string-utils.ts"() {
244
+ "use strict";
245
+ }
246
+ });
247
+
33
248
  // src/utils/dependency-graph-utils.ts
34
249
  function calculateImportDepthFromEdges(file, edges, visited = /* @__PURE__ */ new Set(), depth = 0) {
35
250
  if (visited.has(file)) return depth;
@@ -123,202 +338,53 @@ var init_dependency_graph_utils = __esm({
123
338
  }
124
339
  });
125
340
 
126
- // src/analyzers/python-context.ts
127
- var python_context_exports = {};
128
- __export(python_context_exports, {
129
- analyzePythonContext: () => analyzePythonContext
130
- });
131
- async function analyzePythonContext(files, rootDir) {
132
- const results = [];
133
- const parser = await (0, import_core5.getParser)("dummy.py");
134
- if (!parser) {
135
- console.warn("Python parser not available");
136
- return results;
137
- }
138
- const pythonFiles = files.filter((f) => f.toLowerCase().endsWith(".py"));
139
- void import_path2.relative;
140
- void import_path2.join;
141
- const dependencyGraph = await buildPythonDependencyGraph(
142
- pythonFiles,
143
- rootDir
144
- );
145
- for (const file of pythonFiles) {
146
- try {
147
- const code = await import_fs.default.promises.readFile(file, "utf-8");
148
- const result = parser.parse(code, file);
149
- const imports = result.imports.map((imp) => ({
150
- source: imp.source,
151
- specifiers: imp.specifiers,
152
- isRelative: imp.source.startsWith("."),
153
- resolvedPath: resolvePythonImport(file, imp.source, rootDir)
154
- }));
155
- const exports2 = result.exports.map((exp) => ({
156
- name: exp.name,
157
- type: exp.type
158
- }));
159
- const linesOfCode = code.split("\n").length;
160
- const importDepth = calculateImportDepthFromEdges(
161
- file,
162
- dependencyGraph,
163
- /* @__PURE__ */ new Set()
164
- );
165
- const contextBudget = estimateContextBudget(
166
- code,
167
- imports,
168
- dependencyGraph
169
- );
170
- const cohesion = calculatePythonCohesion(exports2, imports);
171
- const circularDependencies = detectGraphCyclesFromFile(
172
- file,
173
- dependencyGraph
174
- ).map((cycle) => cycle.join(" -> "));
175
- results.push({
176
- file,
177
- importDepth,
178
- contextBudget,
179
- cohesion,
180
- imports,
181
- exports: exports2,
182
- metrics: {
183
- linesOfCode,
184
- importCount: imports.length,
185
- exportCount: exports2.length,
186
- circularDependencies
187
- }
188
- });
189
- } catch (error) {
190
- console.warn(`Failed to analyze ${file}:`, error);
191
- }
192
- }
193
- return results;
194
- }
195
- async function buildPythonDependencyGraph(files, rootDir) {
196
- const graph = /* @__PURE__ */ new Map();
197
- const parser = await (0, import_core5.getParser)("dummy.py");
198
- if (!parser) return graph;
199
- for (const file of files) {
200
- try {
201
- const code = await import_fs.default.promises.readFile(file, "utf-8");
202
- const result = parser.parse(code, file);
203
- const dependencies = /* @__PURE__ */ new Set();
204
- for (const imp of result.imports) {
205
- const resolved = resolvePythonImport(file, imp.source, rootDir);
206
- if (resolved && files.includes(resolved)) {
207
- dependencies.add(resolved);
208
- }
209
- }
210
- graph.set(file, dependencies);
211
- } catch (error) {
212
- void error;
213
- }
214
- }
215
- return graph;
216
- }
217
- function resolvePythonImport(fromFile, importPath, rootDir) {
218
- const dir = (0, import_path2.dirname)(fromFile);
219
- if (importPath.startsWith(".")) {
220
- const parts = importPath.split(".");
221
- let upCount = 0;
222
- while (parts[0] === "") {
223
- upCount++;
224
- parts.shift();
225
- }
226
- let targetDir = dir;
227
- for (let i = 0; i < upCount - 1; i++) {
228
- targetDir = (0, import_path2.dirname)(targetDir);
229
- }
230
- const modulePath = parts.join("/");
231
- const possiblePaths = [
232
- (0, import_path2.resolve)(targetDir, `${modulePath}.py`),
233
- (0, import_path2.resolve)(targetDir, modulePath, "__init__.py")
234
- ];
235
- for (const path of possiblePaths) {
236
- if (import_fs.default.existsSync(path)) {
237
- return path;
238
- }
239
- }
240
- } else {
241
- const modulePath = importPath.replace(/\./g, "/");
242
- const possiblePaths = [
243
- (0, import_path2.resolve)(rootDir, `${modulePath}.py`),
244
- (0, import_path2.resolve)(rootDir, modulePath, "__init__.py")
245
- ];
246
- for (const path of possiblePaths) {
247
- if (import_fs.default.existsSync(path)) {
248
- return path;
341
+ // src/semantic/co-usage.ts
342
+ function buildCoUsageMatrix(graph) {
343
+ const coUsageMatrix = /* @__PURE__ */ new Map();
344
+ for (const [, node] of graph.nodes) {
345
+ const imports = node.imports;
346
+ for (let i = 0; i < imports.length; i++) {
347
+ const fileA = imports[i];
348
+ if (!coUsageMatrix.has(fileA)) coUsageMatrix.set(fileA, /* @__PURE__ */ new Map());
349
+ for (let j = i + 1; j < imports.length; j++) {
350
+ const fileB = imports[j];
351
+ const fileAUsage = coUsageMatrix.get(fileA);
352
+ fileAUsage.set(fileB, (fileAUsage.get(fileB) || 0) + 1);
353
+ if (!coUsageMatrix.has(fileB)) coUsageMatrix.set(fileB, /* @__PURE__ */ new Map());
354
+ const fileBUsage = coUsageMatrix.get(fileB);
355
+ fileBUsage.set(fileA, (fileBUsage.get(fileA) || 0) + 1);
249
356
  }
250
357
  }
251
358
  }
252
- return void 0;
253
- }
254
- function estimateContextBudget(code, imports, dependencyGraph) {
255
- void dependencyGraph;
256
- let budget = (0, import_core5.estimateTokens)(code);
257
- const avgTokensPerDep = 500;
258
- budget += imports.length * avgTokensPerDep;
259
- return budget;
359
+ return coUsageMatrix;
260
360
  }
261
- function calculatePythonCohesion(exports2, imports) {
262
- if (exports2.length === 0) return 1;
263
- const exportCount = exports2.length;
264
- const importCount = imports.length;
265
- let cohesion = 1;
266
- if (exportCount > 10) {
267
- cohesion *= 0.6;
268
- } else if (exportCount > 5) {
269
- cohesion *= 0.8;
361
+ var init_co_usage = __esm({
362
+ "src/semantic/co-usage.ts"() {
363
+ "use strict";
270
364
  }
271
- if (exportCount > 0) {
272
- const ratio = importCount / exportCount;
273
- if (ratio > 2) {
274
- cohesion *= 1.1;
275
- } else if (ratio < 0.5) {
276
- cohesion *= 0.9;
365
+ });
366
+
367
+ // src/semantic/type-graph.ts
368
+ function buildTypeGraph(graph) {
369
+ const typeGraph = /* @__PURE__ */ new Map();
370
+ for (const [file, node] of graph.nodes) {
371
+ for (const exp of node.exports) {
372
+ if (exp.typeReferences) {
373
+ for (const typeRef of exp.typeReferences) {
374
+ if (!typeGraph.has(typeRef)) typeGraph.set(typeRef, /* @__PURE__ */ new Set());
375
+ typeGraph.get(typeRef).add(file);
376
+ }
377
+ }
277
378
  }
278
379
  }
279
- return Math.min(1, Math.max(0, cohesion));
280
- }
281
- var import_core5, import_path2, import_fs;
282
- var init_python_context = __esm({
283
- "src/analyzers/python-context.ts"() {
284
- "use strict";
285
- import_core5 = require("@aiready/core");
286
- import_path2 = require("path");
287
- import_fs = __toESM(require("fs"));
288
- init_dependency_graph_utils();
380
+ return typeGraph;
381
+ }
382
+ var init_type_graph = __esm({
383
+ "src/semantic/type-graph.ts"() {
384
+ "use strict";
289
385
  }
290
386
  });
291
387
 
292
- // src/cli.ts
293
- var import_commander = require("commander");
294
-
295
- // src/cli-action.ts
296
- var import_core9 = require("@aiready/core");
297
-
298
- // src/orchestrator.ts
299
- var import_core6 = require("@aiready/core");
300
-
301
- // src/metrics.ts
302
- var import_core2 = require("@aiready/core");
303
-
304
- // src/ast-utils.ts
305
- var import_core = require("@aiready/core");
306
-
307
- // src/utils/string-utils.ts
308
- function singularize(word) {
309
- const irregulars = {
310
- people: "person",
311
- children: "child",
312
- men: "man",
313
- women: "woman"
314
- };
315
- if (irregulars[word]) return irregulars[word];
316
- if (word.endsWith("ies")) return word.slice(0, -3) + "y";
317
- if (word.endsWith("ses")) return word.slice(0, -2);
318
- if (word.endsWith("s") && word.length > 3) return word.slice(0, -1);
319
- return word;
320
- }
321
-
322
388
  // src/semantic/domain-inference.ts
323
389
  function calculateDomainConfidence(signals) {
324
390
  const weights = {
@@ -488,265 +554,47 @@ function inferDomain(name, filePath, domainOptions, fileImports) {
488
554
  }
489
555
  return "unknown";
490
556
  }
491
-
492
- // src/ast-utils.ts
493
- async function extractExportsWithAST(content, filePath, domainOptions, fileImports) {
494
- try {
495
- const { exports: astExports } = await (0, import_core.parseFileExports)(content, filePath);
496
- if (astExports.length === 0 && !isTestFile(filePath)) {
497
- return extractExports(content, filePath, domainOptions, fileImports);
498
- }
499
- return astExports.map((exp) => ({
500
- name: exp.name,
501
- type: exp.type,
502
- inferredDomain: inferDomain(
503
- exp.name,
504
- filePath,
505
- domainOptions,
506
- fileImports
507
- ),
508
- imports: exp.imports,
509
- dependencies: exp.dependencies,
510
- typeReferences: exp.typeReferences
511
- }));
512
- } catch {
513
- return extractExports(content, filePath, domainOptions, fileImports);
514
- }
515
- }
516
- function isTestFile(filePath) {
517
- const lower = filePath.toLowerCase();
518
- return lower.includes(".test.") || lower.includes(".spec.") || lower.includes("/__tests__/") || lower.includes("/tests/") || lower.includes("/test/") || lower.includes("test-") || lower.includes("-test") || lower.includes("/__mocks__/") || lower.includes("/mocks/") || lower.includes("/fixtures/") || lower.includes(".mock.") || lower.includes(".fixture.") || lower.includes("/test-utils/");
519
- }
520
-
521
- // src/metrics.ts
522
- function calculateEnhancedCohesion(exports2, filePath, options) {
523
- if (exports2.length <= 1) return 1;
524
- if (filePath && isTestFile(filePath)) return 1;
525
- const domains = exports2.map((e) => e.inferredDomain || "unknown");
526
- const domainCounts = /* @__PURE__ */ new Map();
527
- for (const domain of domains)
528
- domainCounts.set(domain, (domainCounts.get(domain) || 0) + 1);
529
- if (domainCounts.size === 1 && domains[0] !== "unknown") {
530
- if (!options?.weights) return 1;
531
- }
532
- const probs = Array.from(domainCounts.values()).map(
533
- (count) => count / exports2.length
534
- );
535
- let domainEntropy = 0;
536
- for (const prob of probs) {
537
- if (prob > 0) domainEntropy -= prob * Math.log2(prob);
538
- }
539
- const maxEntropy = Math.log2(Math.max(2, domainCounts.size));
540
- const domainScore = 1 - domainEntropy / maxEntropy;
541
- let importScoreTotal = 0;
542
- let pairsWithData = 0;
543
- let anyImportData = false;
544
- for (let i = 0; i < exports2.length; i++) {
545
- for (let j = i + 1; j < exports2.length; j++) {
546
- const exp1Imports = exports2[i].imports;
547
- const exp2Imports = exports2[j].imports;
548
- if (exp1Imports || exp2Imports) {
549
- anyImportData = true;
550
- const sim = (0, import_core2.calculateImportSimilarity)(
551
- { ...exports2[i], imports: exp1Imports || [] },
552
- { ...exports2[j], imports: exp2Imports || [] }
553
- );
554
- importScoreTotal += sim;
555
- pairsWithData++;
556
- }
557
- }
558
- }
559
- const avgImportScore = pairsWithData > 0 ? importScoreTotal / pairsWithData : 0;
560
- let score = anyImportData ? domainScore * 0.4 + avgImportScore * 0.6 : domainScore;
561
- if (anyImportData && score === 0 && domainScore === 0) {
562
- score = 0.1;
563
- }
564
- let structuralScore = 0;
565
- for (const exp of exports2) {
566
- if (exp.dependencies && exp.dependencies.length > 0) {
567
- structuralScore += 1;
568
- }
569
- }
570
- if (structuralScore > 0) {
571
- score = Math.min(1, score + 0.1);
572
- }
573
- if (!options?.weights && !anyImportData && domainCounts.size === 1) return 1;
574
- return score;
575
- }
576
- function calculateFragmentation(files, domain, options) {
577
- if (files.length <= 1) return 0;
578
- const directories = new Set(
579
- files.map((file) => file.split("/").slice(0, -1).join("/"))
580
- );
581
- const uniqueDirs = directories.size;
582
- let score = options?.useLogScale ? uniqueDirs <= 1 ? 0 : Math.log(uniqueDirs) / Math.log(options.logBase || Math.E) / (Math.log(files.length) / Math.log(options.logBase || Math.E)) : (uniqueDirs - 1) / (files.length - 1);
583
- if (options?.sharedImportRatio && options.sharedImportRatio > 0.5) {
584
- const discount = (options.sharedImportRatio - 0.5) * 0.4;
585
- score = score * (1 - discount);
586
- }
587
- return score;
588
- }
589
- function calculatePathEntropy(files) {
590
- if (!files || files.length === 0) return 0;
591
- const dirCounts = /* @__PURE__ */ new Map();
592
- for (const file of files) {
593
- const dir = file.split("/").slice(0, -1).join("/") || ".";
594
- dirCounts.set(dir, (dirCounts.get(dir) || 0) + 1);
595
- }
596
- const counts = Array.from(dirCounts.values());
597
- if (counts.length <= 1) return 0;
598
- const total = counts.reduce((sum, value) => sum + value, 0);
599
- let entropy = 0;
600
- for (const count of counts) {
601
- const prob = count / total;
602
- entropy -= prob * Math.log2(prob);
603
- }
604
- const maxEntropy = Math.log2(counts.length);
605
- return maxEntropy > 0 ? entropy / maxEntropy : 0;
606
- }
607
-
608
- // src/issue-analyzer.ts
609
- var import_core3 = require("@aiready/core");
610
- function analyzeIssues(params) {
611
- const {
612
- file,
613
- importDepth,
614
- contextBudget,
615
- cohesionScore,
616
- fragmentationScore,
617
- maxDepth,
618
- maxContextBudget,
619
- minCohesion,
620
- maxFragmentation,
621
- circularDeps
622
- } = params;
623
- const issues = [];
624
- const recommendations = [];
625
- let severity = import_core3.Severity.Info;
626
- let potentialSavings = 0;
627
- if (circularDeps.length > 0) {
628
- severity = import_core3.Severity.Critical;
629
- issues.push(`Part of ${circularDeps.length} circular dependency chain(s)`);
630
- recommendations.push(
631
- "Break circular dependencies by extracting interfaces or using dependency injection"
632
- );
633
- potentialSavings += contextBudget * 0.2;
634
- }
635
- if (importDepth > maxDepth * 1.5) {
636
- severity = import_core3.Severity.Critical;
637
- issues.push(`Import depth ${importDepth} exceeds limit by 50%`);
638
- recommendations.push("Flatten dependency tree or use facade pattern");
639
- potentialSavings += contextBudget * 0.3;
640
- } else if (importDepth > maxDepth) {
641
- if (severity !== import_core3.Severity.Critical) severity = import_core3.Severity.Major;
642
- issues.push(
643
- `Import depth ${importDepth} exceeds recommended maximum ${maxDepth}`
644
- );
645
- recommendations.push("Consider reducing dependency depth");
646
- potentialSavings += contextBudget * 0.15;
647
- }
648
- if (contextBudget > maxContextBudget * 1.5) {
649
- severity = import_core3.Severity.Critical;
650
- issues.push(
651
- `Context budget ${contextBudget.toLocaleString()} tokens is 50% over limit`
652
- );
653
- recommendations.push(
654
- "Split into smaller modules or reduce dependency tree"
655
- );
656
- potentialSavings += contextBudget * 0.4;
657
- } else if (contextBudget > maxContextBudget) {
658
- if (severity !== import_core3.Severity.Critical) severity = import_core3.Severity.Major;
659
- issues.push(
660
- `Context budget ${contextBudget.toLocaleString()} exceeds ${maxContextBudget.toLocaleString()}`
661
- );
662
- recommendations.push("Reduce file size or dependencies");
663
- potentialSavings += contextBudget * 0.2;
664
- }
665
- if (cohesionScore < minCohesion * 0.5) {
666
- if (severity !== import_core3.Severity.Critical) severity = import_core3.Severity.Major;
667
- issues.push(
668
- `Very low cohesion (${(cohesionScore * 100).toFixed(0)}%) - mixed concerns`
669
- );
670
- recommendations.push(
671
- "Split file by domain - separate unrelated functionality"
672
- );
673
- potentialSavings += contextBudget * 0.25;
674
- } else if (cohesionScore < minCohesion) {
675
- if (severity === import_core3.Severity.Info) severity = import_core3.Severity.Minor;
676
- issues.push(`Low cohesion (${(cohesionScore * 100).toFixed(0)}%)`);
677
- recommendations.push("Consider grouping related exports together");
678
- potentialSavings += contextBudget * 0.1;
679
- }
680
- if (fragmentationScore > maxFragmentation) {
681
- if (severity === import_core3.Severity.Info || severity === import_core3.Severity.Minor)
682
- severity = import_core3.Severity.Minor;
683
- issues.push(
684
- `High fragmentation (${(fragmentationScore * 100).toFixed(0)}%) - scattered implementation`
685
- );
686
- recommendations.push("Consolidate with related files in same domain");
687
- potentialSavings += contextBudget * 0.3;
688
- }
689
- if (isBuildArtifact(file)) {
690
- issues.push("Detected build artifact (bundled/output file)");
691
- recommendations.push("Exclude build outputs from analysis");
692
- severity = import_core3.Severity.Info;
693
- potentialSavings = 0;
694
- }
695
- return {
696
- severity,
697
- issues,
698
- recommendations,
699
- potentialSavings: Math.floor(potentialSavings)
700
- };
701
- }
702
- function isBuildArtifact(filePath) {
703
- const lower = filePath.toLowerCase();
704
- return lower.includes("/node_modules/") || lower.includes("/dist/") || lower.includes("/build/") || lower.includes("/out/") || lower.includes("/.next/");
705
- }
706
-
707
- // src/graph-builder.ts
708
- var import_core4 = require("@aiready/core");
709
- init_dependency_graph_utils();
710
-
711
- // src/semantic/co-usage.ts
712
- function buildCoUsageMatrix(graph) {
713
- const coUsageMatrix = /* @__PURE__ */ new Map();
714
- for (const [, node] of graph.nodes) {
715
- const imports = node.imports;
716
- for (let i = 0; i < imports.length; i++) {
717
- const fileA = imports[i];
718
- if (!coUsageMatrix.has(fileA)) coUsageMatrix.set(fileA, /* @__PURE__ */ new Map());
719
- for (let j = i + 1; j < imports.length; j++) {
720
- const fileB = imports[j];
721
- const fileAUsage = coUsageMatrix.get(fileA);
722
- fileAUsage.set(fileB, (fileAUsage.get(fileB) || 0) + 1);
723
- if (!coUsageMatrix.has(fileB)) coUsageMatrix.set(fileB, /* @__PURE__ */ new Map());
724
- const fileBUsage = coUsageMatrix.get(fileB);
725
- fileBUsage.set(fileA, (fileBUsage.get(fileA) || 0) + 1);
726
- }
727
- }
557
+ var init_domain_inference = __esm({
558
+ "src/semantic/domain-inference.ts"() {
559
+ "use strict";
560
+ init_string_utils();
728
561
  }
729
- return coUsageMatrix;
730
- }
562
+ });
731
563
 
732
- // src/semantic/type-graph.ts
733
- function buildTypeGraph(graph) {
734
- const typeGraph = /* @__PURE__ */ new Map();
735
- for (const [file, node] of graph.nodes) {
736
- for (const exp of node.exports) {
737
- if (exp.typeReferences) {
738
- for (const typeRef of exp.typeReferences) {
739
- if (!typeGraph.has(typeRef)) typeGraph.set(typeRef, /* @__PURE__ */ new Set());
740
- typeGraph.get(typeRef).add(file);
741
- }
742
- }
564
+ // src/ast-utils.ts
565
+ async function extractExportsWithAST(content, filePath, domainOptions, fileImports) {
566
+ try {
567
+ const { exports: astExports } = await (0, import_core3.parseFileExports)(content, filePath);
568
+ if (astExports.length === 0 && !(0, import_core3.isTestFile)(filePath)) {
569
+ return extractExports(content, filePath, domainOptions, fileImports);
743
570
  }
571
+ return astExports.map((exp) => ({
572
+ name: exp.name,
573
+ type: exp.type,
574
+ inferredDomain: inferDomain(
575
+ exp.name,
576
+ filePath,
577
+ domainOptions,
578
+ fileImports
579
+ ),
580
+ imports: exp.imports,
581
+ dependencies: exp.dependencies,
582
+ typeReferences: exp.typeReferences
583
+ }));
584
+ } catch {
585
+ return extractExports(content, filePath, domainOptions, fileImports);
744
586
  }
745
- return typeGraph;
746
587
  }
588
+ var import_core3;
589
+ var init_ast_utils = __esm({
590
+ "src/ast-utils.ts"() {
591
+ "use strict";
592
+ import_core3 = require("@aiready/core");
593
+ init_domain_inference();
594
+ }
595
+ });
747
596
 
748
597
  // src/graph-builder.ts
749
- var import_path = require("path");
750
598
  function resolveImport(source, importingFile, allFiles) {
751
599
  if (!source.startsWith(".") && !source.startsWith("/")) {
752
600
  if (source.startsWith("@aiready/")) {
@@ -891,61 +739,81 @@ function calculateContextBudget(file, graph) {
891
739
  function detectCircularDependencies(graph) {
892
740
  return detectGraphCycles(graph.edges);
893
741
  }
742
+ var import_core4, import_path;
743
+ var init_graph_builder = __esm({
744
+ "src/graph-builder.ts"() {
745
+ "use strict";
746
+ import_core4 = require("@aiready/core");
747
+ init_string_utils();
748
+ init_dependency_graph_utils();
749
+ init_co_usage();
750
+ init_type_graph();
751
+ init_domain_inference();
752
+ init_ast_utils();
753
+ import_path = require("path");
754
+ }
755
+ });
894
756
 
895
757
  // src/classify/classification-patterns.ts
896
- var BARREL_EXPORT_MIN_EXPORTS = 5;
897
- var BARREL_EXPORT_TOKEN_LIMIT = 1e3;
898
- var HANDLER_NAME_PATTERNS = [
899
- "handler",
900
- ".handler.",
901
- "-handler.",
902
- "lambda",
903
- ".lambda.",
904
- "-lambda."
905
- ];
906
- var SERVICE_NAME_PATTERNS = [
907
- "service",
908
- ".service.",
909
- "-service.",
910
- "_service."
911
- ];
912
- var EMAIL_NAME_PATTERNS = [
913
- "-email-",
914
- ".email.",
915
- "_email_",
916
- "-template",
917
- ".template.",
918
- "_template",
919
- "-mail.",
920
- ".mail."
921
- ];
922
- var PARSER_NAME_PATTERNS = [
923
- "parser",
924
- ".parser.",
925
- "-parser.",
926
- "_parser.",
927
- "transform",
928
- "converter",
929
- "mapper",
930
- "serializer"
931
- ];
932
- var SESSION_NAME_PATTERNS = ["session", "state", "context", "store"];
933
- var NEXTJS_METADATA_EXPORTS = [
934
- "metadata",
935
- "generatemetadata",
936
- "faqjsonld",
937
- "jsonld",
938
- "icon"
939
- ];
940
- var CONFIG_NAME_PATTERNS = [
941
- ".config.",
942
- "tsconfig",
943
- "jest.config",
944
- "package.json",
945
- "aiready.json",
946
- "next.config",
947
- "sst.config"
948
- ];
758
+ var BARREL_EXPORT_MIN_EXPORTS, BARREL_EXPORT_TOKEN_LIMIT, HANDLER_NAME_PATTERNS, SERVICE_NAME_PATTERNS, EMAIL_NAME_PATTERNS, PARSER_NAME_PATTERNS, SESSION_NAME_PATTERNS, NEXTJS_METADATA_EXPORTS, CONFIG_NAME_PATTERNS;
759
+ var init_classification_patterns = __esm({
760
+ "src/classify/classification-patterns.ts"() {
761
+ "use strict";
762
+ BARREL_EXPORT_MIN_EXPORTS = 5;
763
+ BARREL_EXPORT_TOKEN_LIMIT = 1e3;
764
+ HANDLER_NAME_PATTERNS = [
765
+ "handler",
766
+ ".handler.",
767
+ "-handler.",
768
+ "lambda",
769
+ ".lambda.",
770
+ "-lambda."
771
+ ];
772
+ SERVICE_NAME_PATTERNS = [
773
+ "service",
774
+ ".service.",
775
+ "-service.",
776
+ "_service."
777
+ ];
778
+ EMAIL_NAME_PATTERNS = [
779
+ "-email-",
780
+ ".email.",
781
+ "_email_",
782
+ "-template",
783
+ ".template.",
784
+ "_template",
785
+ "-mail.",
786
+ ".mail."
787
+ ];
788
+ PARSER_NAME_PATTERNS = [
789
+ "parser",
790
+ ".parser.",
791
+ "-parser.",
792
+ "_parser.",
793
+ "transform",
794
+ "converter",
795
+ "mapper",
796
+ "serializer"
797
+ ];
798
+ SESSION_NAME_PATTERNS = ["session", "state", "context", "store"];
799
+ NEXTJS_METADATA_EXPORTS = [
800
+ "metadata",
801
+ "generatemetadata",
802
+ "faqjsonld",
803
+ "jsonld",
804
+ "icon"
805
+ ];
806
+ CONFIG_NAME_PATTERNS = [
807
+ ".config.",
808
+ "tsconfig",
809
+ "jest.config",
810
+ "package.json",
811
+ "aiready.json",
812
+ "next.config",
813
+ "sst.config"
814
+ ];
815
+ }
816
+ });
949
817
 
950
818
  // src/classify/file-classifiers.ts
951
819
  function isBoilerplateBarrel(node) {
@@ -1087,23 +955,14 @@ function isHubAndSpokeFile(node) {
1087
955
  const { file } = node;
1088
956
  return /\/packages\/[a-zA-Z0-9-]+\/src\//.test(file);
1089
957
  }
958
+ var init_file_classifiers = __esm({
959
+ "src/classify/file-classifiers.ts"() {
960
+ "use strict";
961
+ init_classification_patterns();
962
+ }
963
+ });
1090
964
 
1091
965
  // src/classifier.ts
1092
- var Classification = {
1093
- BARREL: "barrel-export",
1094
- BOILERPLATE: "boilerplate-barrel",
1095
- TYPE_DEFINITION: "type-definition",
1096
- NEXTJS_PAGE: "nextjs-page",
1097
- LAMBDA_HANDLER: "lambda-handler",
1098
- SERVICE: "service-file",
1099
- EMAIL_TEMPLATE: "email-template",
1100
- PARSER: "parser-file",
1101
- COHESIVE_MODULE: "cohesive-module",
1102
- UTILITY_MODULE: "utility-module",
1103
- SPOKE_MODULE: "spoke-module",
1104
- MIXED_CONCERNS: "mixed-concerns",
1105
- UNKNOWN: "unknown"
1106
- };
1107
966
  function classifyFile(node, cohesionScore = 1, domains = []) {
1108
967
  if (isBoilerplateBarrel(node)) {
1109
968
  return Classification.BOILERPLATE;
@@ -1259,6 +1118,28 @@ function adjustFragmentationForClassification(baseFragmentation, classification)
1259
1118
  return baseFragmentation * 0.7;
1260
1119
  }
1261
1120
  }
1121
+ var Classification;
1122
+ var init_classifier = __esm({
1123
+ "src/classifier.ts"() {
1124
+ "use strict";
1125
+ init_file_classifiers();
1126
+ Classification = {
1127
+ BARREL: "barrel-export",
1128
+ BOILERPLATE: "boilerplate-barrel",
1129
+ TYPE_DEFINITION: "type-definition",
1130
+ NEXTJS_PAGE: "nextjs-page",
1131
+ LAMBDA_HANDLER: "lambda-handler",
1132
+ SERVICE: "service-file",
1133
+ EMAIL_TEMPLATE: "email-template",
1134
+ PARSER: "parser-file",
1135
+ COHESIVE_MODULE: "cohesive-module",
1136
+ UTILITY_MODULE: "utility-module",
1137
+ SPOKE_MODULE: "spoke-module",
1138
+ MIXED_CONCERNS: "mixed-concerns",
1139
+ UNKNOWN: "unknown"
1140
+ };
1141
+ }
1142
+ });
1262
1143
 
1263
1144
  // src/cluster-detector.ts
1264
1145
  function detectModuleClusters(graph, options) {
@@ -1341,6 +1222,13 @@ function detectModuleClusters(graph, options) {
1341
1222
  }
1342
1223
  return clusters;
1343
1224
  }
1225
+ var init_cluster_detector = __esm({
1226
+ "src/cluster-detector.ts"() {
1227
+ "use strict";
1228
+ init_metrics();
1229
+ init_classifier();
1230
+ }
1231
+ });
1344
1232
 
1345
1233
  // src/remediation.ts
1346
1234
  function getClassificationRecommendations(classification, file, issues) {
@@ -1411,6 +1299,11 @@ function getClassificationRecommendations(classification, file, issues) {
1411
1299
  return issues;
1412
1300
  }
1413
1301
  }
1302
+ var init_remediation = __esm({
1303
+ "src/remediation.ts"() {
1304
+ "use strict";
1305
+ }
1306
+ });
1414
1307
 
1415
1308
  // src/mapper.ts
1416
1309
  function mapNodeToResult(node, graph, clusters, allCircularDeps, options) {
@@ -1483,6 +1376,182 @@ function mapNodeToResult(node, graph, clusters, allCircularDeps, options) {
1483
1376
  potentialSavings
1484
1377
  };
1485
1378
  }
1379
+ var init_mapper = __esm({
1380
+ "src/mapper.ts"() {
1381
+ "use strict";
1382
+ init_metrics();
1383
+ init_issue_analyzer();
1384
+ init_graph_builder();
1385
+ init_classifier();
1386
+ init_remediation();
1387
+ }
1388
+ });
1389
+
1390
+ // src/analyzers/python-context.ts
1391
+ var python_context_exports = {};
1392
+ __export(python_context_exports, {
1393
+ analyzePythonContext: () => analyzePythonContext
1394
+ });
1395
+ async function analyzePythonContext(files, rootDir) {
1396
+ const results = [];
1397
+ const parser = await (0, import_core5.getParser)("dummy.py");
1398
+ if (!parser) {
1399
+ console.warn("Python parser not available");
1400
+ return results;
1401
+ }
1402
+ const pythonFiles = files.filter((f) => f.toLowerCase().endsWith(".py"));
1403
+ void import_path2.relative;
1404
+ void import_path2.join;
1405
+ const dependencyGraph = await buildPythonDependencyGraph(
1406
+ pythonFiles,
1407
+ rootDir
1408
+ );
1409
+ for (const file of pythonFiles) {
1410
+ try {
1411
+ const code = await import_fs.default.promises.readFile(file, "utf-8");
1412
+ const result = parser.parse(code, file);
1413
+ const imports = result.imports.map((imp) => ({
1414
+ source: imp.source,
1415
+ specifiers: imp.specifiers,
1416
+ isRelative: imp.source.startsWith("."),
1417
+ resolvedPath: resolvePythonImport(file, imp.source, rootDir)
1418
+ }));
1419
+ const exports2 = result.exports.map((exp) => ({
1420
+ name: exp.name,
1421
+ type: exp.type
1422
+ }));
1423
+ const linesOfCode = code.split("\n").length;
1424
+ const importDepth = calculateImportDepthFromEdges(
1425
+ file,
1426
+ dependencyGraph,
1427
+ /* @__PURE__ */ new Set()
1428
+ );
1429
+ const contextBudget = estimateContextBudget(
1430
+ code,
1431
+ imports,
1432
+ dependencyGraph
1433
+ );
1434
+ const cohesion = calculatePythonCohesion(exports2, imports);
1435
+ const circularDependencies = detectGraphCyclesFromFile(
1436
+ file,
1437
+ dependencyGraph
1438
+ ).map((cycle) => cycle.join(" -> "));
1439
+ results.push({
1440
+ file,
1441
+ importDepth,
1442
+ contextBudget,
1443
+ cohesion,
1444
+ imports,
1445
+ exports: exports2,
1446
+ metrics: {
1447
+ linesOfCode,
1448
+ importCount: imports.length,
1449
+ exportCount: exports2.length,
1450
+ circularDependencies
1451
+ }
1452
+ });
1453
+ } catch (error) {
1454
+ console.warn(`Failed to analyze ${file}:`, error);
1455
+ }
1456
+ }
1457
+ return results;
1458
+ }
1459
+ async function buildPythonDependencyGraph(files, rootDir) {
1460
+ const graph = /* @__PURE__ */ new Map();
1461
+ const parser = await (0, import_core5.getParser)("dummy.py");
1462
+ if (!parser) return graph;
1463
+ for (const file of files) {
1464
+ try {
1465
+ const code = await import_fs.default.promises.readFile(file, "utf-8");
1466
+ const result = parser.parse(code, file);
1467
+ const dependencies = /* @__PURE__ */ new Set();
1468
+ for (const imp of result.imports) {
1469
+ const resolved = resolvePythonImport(file, imp.source, rootDir);
1470
+ if (resolved && files.includes(resolved)) {
1471
+ dependencies.add(resolved);
1472
+ }
1473
+ }
1474
+ graph.set(file, dependencies);
1475
+ } catch (error) {
1476
+ void error;
1477
+ }
1478
+ }
1479
+ return graph;
1480
+ }
1481
+ function resolvePythonImport(fromFile, importPath, rootDir) {
1482
+ const dir = (0, import_path2.dirname)(fromFile);
1483
+ if (importPath.startsWith(".")) {
1484
+ const parts = importPath.split(".");
1485
+ let upCount = 0;
1486
+ while (parts[0] === "") {
1487
+ upCount++;
1488
+ parts.shift();
1489
+ }
1490
+ let targetDir = dir;
1491
+ for (let i = 0; i < upCount - 1; i++) {
1492
+ targetDir = (0, import_path2.dirname)(targetDir);
1493
+ }
1494
+ const modulePath = parts.join("/");
1495
+ const possiblePaths = [
1496
+ (0, import_path2.resolve)(targetDir, `${modulePath}.py`),
1497
+ (0, import_path2.resolve)(targetDir, modulePath, "__init__.py")
1498
+ ];
1499
+ for (const path of possiblePaths) {
1500
+ if (import_fs.default.existsSync(path)) {
1501
+ return path;
1502
+ }
1503
+ }
1504
+ } else {
1505
+ const modulePath = importPath.replace(/\./g, "/");
1506
+ const possiblePaths = [
1507
+ (0, import_path2.resolve)(rootDir, `${modulePath}.py`),
1508
+ (0, import_path2.resolve)(rootDir, modulePath, "__init__.py")
1509
+ ];
1510
+ for (const path of possiblePaths) {
1511
+ if (import_fs.default.existsSync(path)) {
1512
+ return path;
1513
+ }
1514
+ }
1515
+ }
1516
+ return void 0;
1517
+ }
1518
+ function estimateContextBudget(code, imports, dependencyGraph) {
1519
+ void dependencyGraph;
1520
+ let budget = (0, import_core5.estimateTokens)(code);
1521
+ const avgTokensPerDep = 500;
1522
+ budget += imports.length * avgTokensPerDep;
1523
+ return budget;
1524
+ }
1525
+ function calculatePythonCohesion(exports2, imports) {
1526
+ if (exports2.length === 0) return 1;
1527
+ const exportCount = exports2.length;
1528
+ const importCount = imports.length;
1529
+ let cohesion = 1;
1530
+ if (exportCount > 10) {
1531
+ cohesion *= 0.6;
1532
+ } else if (exportCount > 5) {
1533
+ cohesion *= 0.8;
1534
+ }
1535
+ if (exportCount > 0) {
1536
+ const ratio = importCount / exportCount;
1537
+ if (ratio > 2) {
1538
+ cohesion *= 1.1;
1539
+ } else if (ratio < 0.5) {
1540
+ cohesion *= 0.9;
1541
+ }
1542
+ }
1543
+ return Math.min(1, Math.max(0, cohesion));
1544
+ }
1545
+ var import_core5, import_path2, import_fs;
1546
+ var init_python_context = __esm({
1547
+ "src/analyzers/python-context.ts"() {
1548
+ "use strict";
1549
+ import_core5 = require("@aiready/core");
1550
+ import_path2 = require("path");
1551
+ import_fs = __toESM(require("fs"));
1552
+ init_dependency_graph_utils();
1553
+ }
1554
+ });
1486
1555
 
1487
1556
  // src/orchestrator.ts
1488
1557
  async function analyzeContext(options) {
@@ -1564,9 +1633,20 @@ async function analyzeContext(options) {
1564
1633
  );
1565
1634
  return [...results, ...pythonResults];
1566
1635
  }
1636
+ var import_core6;
1637
+ var init_orchestrator = __esm({
1638
+ "src/orchestrator.ts"() {
1639
+ "use strict";
1640
+ import_core6 = require("@aiready/core");
1641
+ init_metrics();
1642
+ init_issue_analyzer();
1643
+ init_graph_builder();
1644
+ init_cluster_detector();
1645
+ init_mapper();
1646
+ }
1647
+ });
1567
1648
 
1568
1649
  // src/summary.ts
1569
- var import_core7 = require("@aiready/core");
1570
1650
  function generateSummary(results, options = {}) {
1571
1651
  const config = options ? Object.fromEntries(
1572
1652
  Object.entries(options).filter(
@@ -1648,9 +1728,16 @@ function generateSummary(results, options = {}) {
1648
1728
  config
1649
1729
  };
1650
1730
  }
1731
+ var import_core7;
1732
+ var init_summary = __esm({
1733
+ "src/summary.ts"() {
1734
+ "use strict";
1735
+ import_core7 = require("@aiready/core");
1736
+ init_metrics();
1737
+ }
1738
+ });
1651
1739
 
1652
1740
  // src/report/console-report.ts
1653
- var import_chalk = __toESM(require("chalk"));
1654
1741
  function displayConsoleReport(summary, results, maxResults = 10) {
1655
1742
  const divider = "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500";
1656
1743
  const totalIssues = summary.criticalIssues + summary.majorIssues + summary.minorIssues;
@@ -1720,14 +1807,19 @@ function displayConsoleReport(summary, results, maxResults = 10) {
1720
1807
  )
1721
1808
  );
1722
1809
  }
1810
+ var import_chalk;
1811
+ var init_console_report = __esm({
1812
+ "src/report/console-report.ts"() {
1813
+ "use strict";
1814
+ import_chalk = __toESM(require("chalk"));
1815
+ }
1816
+ });
1723
1817
 
1724
1818
  // src/report/html-report.ts
1725
- var import_core8 = require("@aiready/core");
1726
1819
  function generateHTMLReport(summary, results) {
1727
1820
  const totalIssues = summary.criticalIssues + summary.majorIssues + summary.minorIssues;
1728
1821
  void results;
1729
- const head = (0, import_core8.generateReportHead)("AIReady Context Analysis Report");
1730
- const stats = (0, import_core8.generateStatCards)([
1822
+ const stats = [
1731
1823
  { value: summary.totalFiles, label: "Files Analyzed" },
1732
1824
  { value: summary.totalTokens.toLocaleString(), label: "Total Tokens" },
1733
1825
  { value: summary.avgContextBudget.toFixed(0), label: "Avg Context Budget" },
@@ -1736,69 +1828,67 @@ function generateHTMLReport(summary, results) {
1736
1828
  label: "Total Issues",
1737
1829
  color: totalIssues > 0 ? "#f39c12" : void 0
1738
1830
  }
1739
- ]);
1740
- const hero = (0, import_core8.generateReportHero)(
1741
- "\u{1F50D} AIReady Context Analysis Report",
1742
- `Generated on ${(/* @__PURE__ */ new Date()).toLocaleString()}`
1743
- );
1744
- let body = `${hero}
1745
- ${stats}`;
1831
+ ];
1832
+ const sections = [];
1746
1833
  if (totalIssues > 0) {
1747
- body += (0, import_core8.generateIssueSummary)(
1748
- summary.criticalIssues,
1749
- summary.majorIssues,
1750
- summary.minorIssues,
1751
- summary.totalPotentialSavings
1752
- );
1834
+ sections.push({
1835
+ title: "\u26A0\uFE0F Issues Summary",
1836
+ content: (0, import_core8.generateIssueSummary)(
1837
+ summary.criticalIssues,
1838
+ summary.majorIssues,
1839
+ summary.minorIssues,
1840
+ summary.totalPotentialSavings
1841
+ )
1842
+ });
1753
1843
  }
1754
1844
  if (summary.fragmentedModules.length > 0) {
1755
- const fragmentedRows = summary.fragmentedModules.map((m) => [
1756
- m.domain,
1757
- String(m.files.length),
1758
- `${(m.fragmentationScore * 100).toFixed(0)}%`,
1759
- m.totalTokens.toLocaleString()
1760
- ]);
1761
- body += (0, import_core8.wrapInCard)(
1762
- (0, import_core8.generateTable)({
1845
+ sections.push({
1846
+ title: "\u{1F9E9} Fragmented Modules",
1847
+ content: (0, import_core8.generateTable)({
1763
1848
  headers: ["Domain", "Files", "Fragmentation", "Token Cost"],
1764
- rows: fragmentedRows
1765
- }),
1766
- "\u{1F9E9} Fragmented Modules"
1767
- );
1849
+ rows: summary.fragmentedModules.map((m) => [
1850
+ m.domain,
1851
+ String(m.files.length),
1852
+ `${(m.fragmentationScore * 100).toFixed(0)}%`,
1853
+ m.totalTokens.toLocaleString()
1854
+ ])
1855
+ })
1856
+ });
1768
1857
  }
1769
1858
  if (summary.topExpensiveFiles.length > 0) {
1770
- const expensiveRows = summary.topExpensiveFiles.map((f) => [
1771
- f.file,
1772
- `${f.contextBudget.toLocaleString()} tokens`,
1773
- `<span class="issue-${f.severity}">${f.severity.toUpperCase()}</span>`
1774
- ]);
1775
- body += (0, import_core8.wrapInCard)(
1776
- (0, import_core8.generateTable)({
1859
+ sections.push({
1860
+ title: "\u{1F4B8} Most Expensive Files",
1861
+ content: (0, import_core8.generateTable)({
1777
1862
  headers: ["File", "Context Budget", "Severity"],
1778
- rows: expensiveRows
1779
- }),
1780
- "\u{1F4B8} Most Expensive Files"
1781
- );
1863
+ rows: summary.topExpensiveFiles.map((f) => [
1864
+ f.file,
1865
+ `${f.contextBudget.toLocaleString()} tokens`,
1866
+ `<span class="issue-${f.severity}">${f.severity.toUpperCase()}</span>`
1867
+ ])
1868
+ })
1869
+ });
1782
1870
  }
1783
- const footer = (0, import_core8.generateReportFooter)({
1784
- title: "Context Analysis Report",
1785
- packageName: "context-analyzer",
1786
- packageUrl: "https://github.com/caopengau/aiready-context-analyzer",
1787
- bugUrl: "https://github.com/caopengau/aiready-context-analyzer/issues"
1788
- });
1789
- return `${head}
1790
- <body>
1791
- ${body}
1792
- ${footer}
1793
- </body>
1794
- </html>`;
1871
+ return (0, import_core8.generateStandardHtmlReport)(
1872
+ {
1873
+ title: "Context Analysis Report",
1874
+ packageName: "context-analyzer",
1875
+ packageUrl: "https://github.com/caopengau/aiready-context-analyzer",
1876
+ bugUrl: "https://github.com/caopengau/aiready-context-analyzer/issues",
1877
+ emoji: "\u{1F9E0}"
1878
+ },
1879
+ stats,
1880
+ sections
1881
+ );
1795
1882
  }
1883
+ var import_core8;
1884
+ var init_html_report = __esm({
1885
+ "src/report/html-report.ts"() {
1886
+ "use strict";
1887
+ import_core8 = require("@aiready/core");
1888
+ }
1889
+ });
1796
1890
 
1797
1891
  // src/report/interactive-setup.ts
1798
- var import_chalk2 = __toESM(require("chalk"));
1799
- var import_fs2 = require("fs");
1800
- var import_path3 = require("path");
1801
- var import_prompts = __toESM(require("prompts"));
1802
1892
  async function runInteractiveSetup(directory, current) {
1803
1893
  console.log(import_chalk2.default.yellow("\u{1F9ED} Interactive mode: let's tailor the analysis."));
1804
1894
  const pkgPath = (0, import_path3.join)(directory, "package.json");
@@ -1866,10 +1956,22 @@ async function runInteractiveSetup(directory, current) {
1866
1956
  console.log(import_chalk2.default.green("\u2713 Interactive configuration applied."));
1867
1957
  return nextOptions;
1868
1958
  }
1959
+ var import_chalk2, import_fs2, import_path3, import_prompts;
1960
+ var init_interactive_setup = __esm({
1961
+ "src/report/interactive-setup.ts"() {
1962
+ "use strict";
1963
+ import_chalk2 = __toESM(require("chalk"));
1964
+ import_fs2 = require("fs");
1965
+ import_path3 = require("path");
1966
+ import_prompts = __toESM(require("prompts"));
1967
+ }
1968
+ });
1869
1969
 
1870
1970
  // src/cli-action.ts
1871
- var import_chalk3 = __toESM(require("chalk"));
1872
- var import_fs3 = require("fs");
1971
+ var cli_action_exports = {};
1972
+ __export(cli_action_exports, {
1973
+ contextActionHandler: () => contextActionHandler
1974
+ });
1873
1975
  async function contextActionHandler(directory, options) {
1874
1976
  console.log(import_chalk3.default.blue("\u{1F50D} Analyzing context window costs...\n"));
1875
1977
  const startTime = Date.now();
@@ -1938,6 +2040,23 @@ async function contextActionHandler(directory, options) {
1938
2040
  (0, import_core9.handleCLIError)(error, "context-analyzer");
1939
2041
  }
1940
2042
  }
2043
+ var import_core9, import_chalk3, import_fs3;
2044
+ var init_cli_action = __esm({
2045
+ "src/cli-action.ts"() {
2046
+ "use strict";
2047
+ import_core9 = require("@aiready/core");
2048
+ init_orchestrator();
2049
+ init_summary();
2050
+ init_console_report();
2051
+ init_html_report();
2052
+ init_interactive_setup();
2053
+ import_chalk3 = __toESM(require("chalk"));
2054
+ import_fs3 = require("fs");
2055
+ }
2056
+ });
2057
+
2058
+ // src/cli.ts
2059
+ var import_commander = require("commander");
1941
2060
 
1942
2061
  // src/cli-definition.ts
1943
2062
  function defineContextCommand(program2) {
@@ -1972,7 +2091,10 @@ function defineContextCommand(program2) {
1972
2091
  ).option("--output-file <path>", "Output file path (for json/html)").option(
1973
2092
  "--interactive",
1974
2093
  "Run interactive setup to suggest excludes and focus areas"
1975
- ).action(contextActionHandler);
2094
+ ).action(async (directory, options) => {
2095
+ const { contextActionHandler: contextActionHandler2 } = await Promise.resolve().then(() => (init_cli_action(), cli_action_exports));
2096
+ await contextActionHandler2(directory, options);
2097
+ });
1976
2098
  }
1977
2099
 
1978
2100
  // src/cli.ts