@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.
- package/.turbo/turbo-build.log +32 -25
- package/.turbo/turbo-test.log +51 -87
- package/coverage/clover.xml +392 -1878
- package/coverage/coverage-final.json +15 -19
- package/coverage/index.html +48 -63
- package/coverage/src/analyzers/index.html +21 -21
- package/coverage/src/analyzers/python-context.ts.html +96 -96
- package/coverage/src/ast-utils.ts.html +34 -109
- package/coverage/src/classifier.ts.html +104 -104
- package/coverage/src/classify/classification-patterns.ts.html +1 -1
- package/coverage/src/classify/file-classifiers.ts.html +1 -1
- package/coverage/src/classify/index.html +1 -1
- package/coverage/src/cluster-detector.ts.html +72 -72
- package/coverage/src/defaults.ts.html +1 -1
- package/coverage/src/graph-builder.ts.html +131 -131
- package/coverage/src/index.html +101 -116
- package/coverage/src/index.ts.html +2 -2
- package/coverage/src/issue-analyzer.ts.html +32 -83
- package/coverage/src/mapper.ts.html +20 -2
- package/coverage/src/metrics.ts.html +127 -130
- package/coverage/src/orchestrator.ts.html +13 -13
- package/coverage/src/provider.ts.html +19 -19
- package/coverage/src/remediation.ts.html +59 -59
- package/coverage/src/report/console-report.ts.html +2 -2
- package/coverage/src/report/html-report.ts.html +60 -84
- package/coverage/src/report/index.html +7 -7
- package/coverage/src/report/interactive-setup.ts.html +1 -1
- package/coverage/src/scoring.ts.html +62 -62
- package/coverage/src/semantic/co-usage.ts.html +1 -1
- package/coverage/src/semantic/consolidation.ts.html +1 -1
- package/coverage/src/semantic/domain-inference.ts.html +1 -1
- package/coverage/src/semantic/index.html +1 -1
- package/coverage/src/semantic/type-graph.ts.html +1 -1
- package/coverage/src/summary.ts.html +67 -67
- package/coverage/src/types.ts.html +1 -1
- package/coverage/src/utils/dependency-graph-utils.ts.html +41 -41
- package/coverage/src/utils/index.html +21 -21
- package/coverage/src/utils/string-utils.ts.html +1 -1
- package/dist/chunk-22ZO4EKZ.mjs +1297 -0
- package/dist/chunk-4U4LDWGF.mjs +360 -0
- package/dist/chunk-BA7QGUHN.mjs +1722 -0
- package/dist/chunk-BCEZGRXI.mjs +1297 -0
- package/dist/chunk-BQCISA2F.mjs +91 -0
- package/dist/chunk-EMYD7NS6.mjs +137 -0
- package/dist/chunk-EWFR366Y.mjs +1740 -0
- package/dist/chunk-FO6YT6RG.mjs +1751 -0
- package/dist/chunk-J3SZQZNU.mjs +221 -0
- package/dist/chunk-OZE3FVZT.mjs +1089 -0
- package/dist/chunk-WHB7QI7N.mjs +91 -0
- package/dist/cli-action-CXIHOVAC.mjs +95 -0
- package/dist/cli-action-SA7SCYNV.mjs +95 -0
- package/dist/cli-action-YAJOJCXJ.mjs +95 -0
- package/dist/cli.js +688 -566
- package/dist/cli.mjs +4 -88
- package/dist/index.js +889 -773
- package/dist/index.mjs +21 -14
- package/dist/orchestrator-3L3NAZYP.mjs +10 -0
- package/dist/orchestrator-MONOZHVW.mjs +10 -0
- package/dist/orchestrator-ZR7JSKWI.mjs +10 -0
- package/dist/summary-7PZVW72O.mjs +7 -0
- package/dist/summary-LKUCJAIS.mjs +7 -0
- package/package.json +2 -2
- package/src/__tests__/analyzer.test.ts +1 -1
- package/src/__tests__/enhanced-cohesion.test.ts +4 -1
- package/src/__tests__/orchestrator.test.ts +19 -4
- package/src/__tests__/python-context.test.ts +6 -0
- package/src/__tests__/report/html-report.test.ts +8 -2
- package/src/ast-utils.ts +1 -26
- package/src/cli-definition.ts +4 -2
- package/src/issue-analyzer.ts +4 -19
- package/src/metrics.ts +1 -2
- package/src/provider.ts +4 -4
- package/src/report/html-report.ts +43 -59
- package/coverage/dist/chunk-64U3PNO3.mjs.html +0 -367
- package/coverage/dist/chunk-J3MUOWHC.mjs.html +0 -5326
- package/coverage/dist/index.html +0 -146
- package/coverage/dist/index.mjs.html +0 -1396
- 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/
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
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
|
|
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
|
-
|
|
262
|
-
|
|
263
|
-
|
|
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
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
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
|
|
280
|
-
}
|
|
281
|
-
var
|
|
282
|
-
|
|
283
|
-
|
|
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
|
-
|
|
493
|
-
|
|
494
|
-
|
|
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
|
-
|
|
730
|
-
}
|
|
562
|
+
});
|
|
731
563
|
|
|
732
|
-
// src/
|
|
733
|
-
function
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
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
|
|
897
|
-
var
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
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
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
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:
|
|
1765
|
-
|
|
1766
|
-
|
|
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
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
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:
|
|
1779
|
-
|
|
1780
|
-
|
|
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
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
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
|
|
1872
|
-
|
|
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(
|
|
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
|