@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
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import {
|
|
2
|
+
calculatePathEntropy
|
|
3
|
+
} from "./chunk-EMYD7NS6.mjs";
|
|
4
|
+
|
|
5
|
+
// src/summary.ts
|
|
6
|
+
import { GLOBAL_SCAN_OPTIONS } from "@aiready/core";
|
|
7
|
+
function generateSummary(results, options = {}) {
|
|
8
|
+
const config = options ? Object.fromEntries(
|
|
9
|
+
Object.entries(options).filter(
|
|
10
|
+
([key]) => !GLOBAL_SCAN_OPTIONS.includes(key) || key === "rootDir"
|
|
11
|
+
)
|
|
12
|
+
) : {};
|
|
13
|
+
const totalFiles = results.length;
|
|
14
|
+
const totalTokens = results.reduce((sum, r) => sum + r.tokenCost, 0);
|
|
15
|
+
const avgContextBudget = totalFiles > 0 ? results.reduce((sum, r) => sum + r.contextBudget, 0) / totalFiles : 0;
|
|
16
|
+
const deepFiles = results.filter((r) => r.importDepth > 5).map((r) => ({ file: r.file, depth: r.importDepth }));
|
|
17
|
+
const maxImportDepth = Math.max(0, ...results.map((r) => r.importDepth));
|
|
18
|
+
const moduleMap = /* @__PURE__ */ new Map();
|
|
19
|
+
results.forEach((r) => {
|
|
20
|
+
const parts = r.file.split("/");
|
|
21
|
+
let domain = "root";
|
|
22
|
+
if (parts.length > 2) {
|
|
23
|
+
domain = parts.slice(0, 2).join("/");
|
|
24
|
+
}
|
|
25
|
+
if (!moduleMap.has(domain)) moduleMap.set(domain, []);
|
|
26
|
+
moduleMap.get(domain).push(r);
|
|
27
|
+
});
|
|
28
|
+
const fragmentedModules = [];
|
|
29
|
+
moduleMap.forEach((files, domain) => {
|
|
30
|
+
const clusterTokens = files.reduce((sum, f) => sum + f.tokenCost, 0);
|
|
31
|
+
const filePaths = files.map((f) => f.file);
|
|
32
|
+
const avgEntropy = calculatePathEntropy(filePaths);
|
|
33
|
+
const fragmentationScore = Math.min(1, avgEntropy * (files.length / 10));
|
|
34
|
+
if (fragmentationScore > 0.4) {
|
|
35
|
+
fragmentedModules.push({
|
|
36
|
+
domain,
|
|
37
|
+
files: filePaths,
|
|
38
|
+
fragmentationScore,
|
|
39
|
+
totalTokens: clusterTokens,
|
|
40
|
+
avgCohesion: files.reduce((sum, f) => sum + f.cohesionScore, 0) / files.length,
|
|
41
|
+
suggestedStructure: {
|
|
42
|
+
targetFiles: Math.ceil(files.length / 2),
|
|
43
|
+
consolidationPlan: [
|
|
44
|
+
`Consolidate ${files.length} files in ${domain} into fewer modules`
|
|
45
|
+
]
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
fragmentedModules.sort((a, b) => b.fragmentationScore - a.fragmentationScore);
|
|
51
|
+
const avgFragmentation = fragmentedModules.length > 0 ? fragmentedModules.reduce((sum, m) => sum + m.fragmentationScore, 0) / fragmentedModules.length : 0;
|
|
52
|
+
const avgCohesion = results.reduce((sum, r) => sum + r.cohesionScore, 0) / (totalFiles || 1);
|
|
53
|
+
const lowCohesionFiles = results.filter((r) => r.cohesionScore < 0.4).map((r) => ({ file: r.file, score: r.cohesionScore }));
|
|
54
|
+
const criticalIssues = results.filter(
|
|
55
|
+
(r) => r.severity === "critical"
|
|
56
|
+
).length;
|
|
57
|
+
const majorIssues = results.filter((r) => r.severity === "major").length;
|
|
58
|
+
const minorIssues = results.filter((r) => r.severity === "minor").length;
|
|
59
|
+
const totalPotentialSavings = results.reduce(
|
|
60
|
+
(sum, r) => sum + (r.potentialSavings || 0),
|
|
61
|
+
0
|
|
62
|
+
);
|
|
63
|
+
const topExpensiveFiles = [...results].sort((a, b) => b.contextBudget - a.contextBudget).slice(0, 10).map((r) => ({
|
|
64
|
+
file: r.file,
|
|
65
|
+
contextBudget: r.contextBudget,
|
|
66
|
+
severity: r.severity
|
|
67
|
+
}));
|
|
68
|
+
return {
|
|
69
|
+
totalFiles,
|
|
70
|
+
totalTokens,
|
|
71
|
+
avgContextBudget,
|
|
72
|
+
maxContextBudget: Math.max(0, ...results.map((r) => r.contextBudget)),
|
|
73
|
+
avgImportDepth: results.reduce((sum, r) => sum + r.importDepth, 0) / (totalFiles || 1),
|
|
74
|
+
maxImportDepth,
|
|
75
|
+
deepFiles,
|
|
76
|
+
avgFragmentation,
|
|
77
|
+
fragmentedModules,
|
|
78
|
+
avgCohesion,
|
|
79
|
+
lowCohesionFiles,
|
|
80
|
+
criticalIssues,
|
|
81
|
+
majorIssues,
|
|
82
|
+
minorIssues,
|
|
83
|
+
totalPotentialSavings,
|
|
84
|
+
topExpensiveFiles,
|
|
85
|
+
config
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export {
|
|
90
|
+
generateSummary
|
|
91
|
+
};
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
// src/metrics.ts
|
|
2
|
+
import { calculateImportSimilarity, isTestFile } from "@aiready/core";
|
|
3
|
+
function calculateEnhancedCohesion(exports, filePath, options) {
|
|
4
|
+
if (exports.length <= 1) return 1;
|
|
5
|
+
if (filePath && isTestFile(filePath)) return 1;
|
|
6
|
+
const domains = exports.map((e) => e.inferredDomain || "unknown");
|
|
7
|
+
const domainCounts = /* @__PURE__ */ new Map();
|
|
8
|
+
for (const domain of domains)
|
|
9
|
+
domainCounts.set(domain, (domainCounts.get(domain) || 0) + 1);
|
|
10
|
+
if (domainCounts.size === 1 && domains[0] !== "unknown") {
|
|
11
|
+
if (!options?.weights) return 1;
|
|
12
|
+
}
|
|
13
|
+
const probs = Array.from(domainCounts.values()).map(
|
|
14
|
+
(count) => count / exports.length
|
|
15
|
+
);
|
|
16
|
+
let domainEntropy = 0;
|
|
17
|
+
for (const prob of probs) {
|
|
18
|
+
if (prob > 0) domainEntropy -= prob * Math.log2(prob);
|
|
19
|
+
}
|
|
20
|
+
const maxEntropy = Math.log2(Math.max(2, domainCounts.size));
|
|
21
|
+
const domainScore = 1 - domainEntropy / maxEntropy;
|
|
22
|
+
let importScoreTotal = 0;
|
|
23
|
+
let pairsWithData = 0;
|
|
24
|
+
let anyImportData = false;
|
|
25
|
+
for (let i = 0; i < exports.length; i++) {
|
|
26
|
+
for (let j = i + 1; j < exports.length; j++) {
|
|
27
|
+
const exp1Imports = exports[i].imports;
|
|
28
|
+
const exp2Imports = exports[j].imports;
|
|
29
|
+
if (exp1Imports || exp2Imports) {
|
|
30
|
+
anyImportData = true;
|
|
31
|
+
const sim = calculateImportSimilarity(
|
|
32
|
+
{ ...exports[i], imports: exp1Imports || [] },
|
|
33
|
+
{ ...exports[j], imports: exp2Imports || [] }
|
|
34
|
+
);
|
|
35
|
+
importScoreTotal += sim;
|
|
36
|
+
pairsWithData++;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
const avgImportScore = pairsWithData > 0 ? importScoreTotal / pairsWithData : 0;
|
|
41
|
+
let score = anyImportData ? domainScore * 0.4 + avgImportScore * 0.6 : domainScore;
|
|
42
|
+
if (anyImportData && score === 0 && domainScore === 0) {
|
|
43
|
+
score = 0.1;
|
|
44
|
+
}
|
|
45
|
+
let structuralScore = 0;
|
|
46
|
+
for (const exp of exports) {
|
|
47
|
+
if (exp.dependencies && exp.dependencies.length > 0) {
|
|
48
|
+
structuralScore += 1;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
if (structuralScore > 0) {
|
|
52
|
+
score = Math.min(1, score + 0.1);
|
|
53
|
+
}
|
|
54
|
+
if (!options?.weights && !anyImportData && domainCounts.size === 1) return 1;
|
|
55
|
+
return score;
|
|
56
|
+
}
|
|
57
|
+
function calculateStructuralCohesionFromCoUsage(file, coUsageMatrix) {
|
|
58
|
+
if (!coUsageMatrix) return 1;
|
|
59
|
+
const coUsages = coUsageMatrix.get(file);
|
|
60
|
+
if (!coUsages || coUsages.size === 0) return 1;
|
|
61
|
+
let total = 0;
|
|
62
|
+
for (const count of coUsages.values()) total += count;
|
|
63
|
+
if (total === 0) return 1;
|
|
64
|
+
const probs = [];
|
|
65
|
+
for (const count of coUsages.values()) {
|
|
66
|
+
if (count > 0) probs.push(count / total);
|
|
67
|
+
}
|
|
68
|
+
if (probs.length <= 1) return 1;
|
|
69
|
+
let entropy = 0;
|
|
70
|
+
for (const prob of probs) {
|
|
71
|
+
entropy -= prob * Math.log2(prob);
|
|
72
|
+
}
|
|
73
|
+
const maxEntropy = Math.log2(probs.length);
|
|
74
|
+
return maxEntropy > 0 ? 1 - entropy / maxEntropy : 1;
|
|
75
|
+
}
|
|
76
|
+
function calculateFragmentation(files, domain, options) {
|
|
77
|
+
if (files.length <= 1) return 0;
|
|
78
|
+
const directories = new Set(
|
|
79
|
+
files.map((file) => file.split("/").slice(0, -1).join("/"))
|
|
80
|
+
);
|
|
81
|
+
const uniqueDirs = directories.size;
|
|
82
|
+
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);
|
|
83
|
+
if (options?.sharedImportRatio && options.sharedImportRatio > 0.5) {
|
|
84
|
+
const discount = (options.sharedImportRatio - 0.5) * 0.4;
|
|
85
|
+
score = score * (1 - discount);
|
|
86
|
+
}
|
|
87
|
+
return score;
|
|
88
|
+
}
|
|
89
|
+
function calculatePathEntropy(files) {
|
|
90
|
+
if (!files || files.length === 0) return 0;
|
|
91
|
+
const dirCounts = /* @__PURE__ */ new Map();
|
|
92
|
+
for (const file of files) {
|
|
93
|
+
const dir = file.split("/").slice(0, -1).join("/") || ".";
|
|
94
|
+
dirCounts.set(dir, (dirCounts.get(dir) || 0) + 1);
|
|
95
|
+
}
|
|
96
|
+
const counts = Array.from(dirCounts.values());
|
|
97
|
+
if (counts.length <= 1) return 0;
|
|
98
|
+
const total = counts.reduce((sum, value) => sum + value, 0);
|
|
99
|
+
let entropy = 0;
|
|
100
|
+
for (const count of counts) {
|
|
101
|
+
const prob = count / total;
|
|
102
|
+
entropy -= prob * Math.log2(prob);
|
|
103
|
+
}
|
|
104
|
+
const maxEntropy = Math.log2(counts.length);
|
|
105
|
+
return maxEntropy > 0 ? entropy / maxEntropy : 0;
|
|
106
|
+
}
|
|
107
|
+
function calculateDirectoryDistance(files) {
|
|
108
|
+
if (!files || files.length <= 1) return 0;
|
|
109
|
+
const pathSegments = (pathStr) => pathStr.split("/").filter(Boolean);
|
|
110
|
+
const commonAncestorDepth = (pathA, pathB) => {
|
|
111
|
+
const minLen = Math.min(pathA.length, pathB.length);
|
|
112
|
+
let i = 0;
|
|
113
|
+
while (i < minLen && pathA[i] === pathB[i]) i++;
|
|
114
|
+
return i;
|
|
115
|
+
};
|
|
116
|
+
let totalNormalized = 0;
|
|
117
|
+
let comparisons = 0;
|
|
118
|
+
for (let i = 0; i < files.length; i++) {
|
|
119
|
+
for (let j = i + 1; j < files.length; j++) {
|
|
120
|
+
const segA = pathSegments(files[i]);
|
|
121
|
+
const segB = pathSegments(files[j]);
|
|
122
|
+
const shared = commonAncestorDepth(segA, segB);
|
|
123
|
+
const maxDepth = Math.max(segA.length, segB.length);
|
|
124
|
+
totalNormalized += 1 - (maxDepth > 0 ? shared / maxDepth : 0);
|
|
125
|
+
comparisons++;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return comparisons > 0 ? totalNormalized / comparisons : 0;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export {
|
|
132
|
+
calculateEnhancedCohesion,
|
|
133
|
+
calculateStructuralCohesionFromCoUsage,
|
|
134
|
+
calculateFragmentation,
|
|
135
|
+
calculatePathEntropy,
|
|
136
|
+
calculateDirectoryDistance
|
|
137
|
+
};
|