@aiready/context-analyzer 0.22.7 → 0.22.9

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.
@@ -1,6 +1,6 @@
1
1
 
2
2
  
3
- > @aiready/context-analyzer@0.22.7 build /Users/pengcao/projects/aiready/packages/context-analyzer
3
+ > @aiready/context-analyzer@0.22.9 build /Users/pengcao/projects/aiready/packages/context-analyzer
4
4
  > tsup src/index.ts src/cli.ts --format cjs,esm --dts
5
5
 
6
6
  CLI Building entry: src/cli.ts, src/index.ts
@@ -9,23 +9,23 @@
9
9
  CLI Target: es2020
10
10
  CJS Build start
11
11
  ESM Build start
12
- CJS dist/cli.js 69.59 KB
13
- CJS dist/index.js 83.38 KB
14
- CJS ⚡️ Build success in 567ms
12
+ CJS dist/cli.js 69.65 KB
13
+ CJS dist/index.js 83.44 KB
14
+ CJS ⚡️ Build success in 98ms
15
+ ESM dist/cli.mjs 1.81 KB
16
+ ESM dist/python-context-BWDC4E5Z.mjs 4.48 KB
17
+ ESM dist/summary-RSPRRY6S.mjs 119.00 B
18
+ ESM dist/orchestrator-62YVSQFV.mjs 190.00 B
19
+ ESM dist/chunk-ZA7HRDAH.mjs 41.00 KB
20
+ ESM dist/chunk-BTDF2ZA4.mjs 3.35 KB
15
21
  ESM dist/index.mjs 12.69 KB
16
- ESM dist/cli-action-VCXBZGZP.mjs 2.86 KB
17
- ESM dist/summary-7PZVW72O.mjs 119.00 B
18
22
  ESM dist/chunk-J3SZQZNU.mjs 8.11 KB
19
- ESM dist/python-context-BWDC4E5Z.mjs 4.48 KB
20
- ESM dist/chunk-M2EGQ36M.mjs 41.00 KB
21
- ESM dist/cli.mjs 1.81 KB
22
- ESM dist/chunk-EMYD7NS6.mjs 4.91 KB
23
+ ESM dist/cli-action-HREY7TK5.mjs 2.86 KB
24
+ ESM dist/chunk-JSM7Q5CY.mjs 4.98 KB
23
25
  ESM dist/chunk-64U3PNO3.mjs 2.65 KB
24
- ESM dist/chunk-BQCISA2F.mjs 3.35 KB
25
- ESM dist/orchestrator-KMAKMHTD.mjs 190.00 B
26
- ESM ⚡️ Build success in 568ms
26
+ ESM ⚡️ Build success in 106ms
27
27
  DTS Build start
28
- DTS ⚡️ Build success in 11173ms
28
+ DTS ⚡️ Build success in 3222ms
29
29
  DTS dist/cli.d.ts 20.00 B
30
30
  DTS dist/index.d.ts 25.64 KB
31
31
  DTS dist/cli.d.mts 20.00 B
@@ -0,0 +1,7 @@
1
+
2
+ 
3
+ > @aiready/context-analyzer@0.22.9 format-check /Users/pengcao/projects/aiready/packages/context-analyzer
4
+ > prettier --check . --ignore-path ../../.prettierignore
5
+
6
+ Checking formatting...
7
+ .aireadyignoreCONTRIBUTING.mdLICENSEpackage.jsonREADME.mdsrc/__tests__/analyzer.test.tssrc/__tests__/auto-detection.test.tssrc/__tests__/boilerplate-barrel.test.tssrc/__tests__/cluster-detector.test.tssrc/__tests__/consolidation.test.tssrc/__tests__/contract.test.tssrc/__tests__/defaults.test.tssrc/__tests__/domain-inference.test.tssrc/__tests__/enhanced-cohesion.test.tssrc/__tests__/file-classification.test.tssrc/__tests__/fragmentation-advanced.test.tssrc/__tests__/fragmentation-coupling.test.tssrc/__tests__/fragmentation-log.test.tssrc/__tests__/issue-analyzer.test.tssrc/__tests__/orchestrator.test.tssrc/__tests__/provider.test.tssrc/__tests__/python-context.test.tssrc/__tests__/remediation.test.tssrc/__tests__/report/console-report.test.tssrc/__tests__/report/html-report.test.tssrc/__tests__/scoring.test.tssrc/__tests__/structural-cohesion.test.tssrc/analyzers/python-context.tssrc/ast-utils.tssrc/classifier.tssrc/classify/classification-patterns.tssrc/classify/file-classifiers.tssrc/cli-action.tssrc/cli-definition.tssrc/cli.tssrc/cluster-detector.tssrc/defaults.tssrc/graph-builder.tssrc/index.tssrc/issue-analyzer.tssrc/metrics.tssrc/orchestrator.tssrc/provider.tssrc/remediation.tssrc/report/console-report.tssrc/report/html-report.tssrc/report/interactive-setup.tssrc/scoring.tssrc/semantic/co-usage.tssrc/semantic/consolidation.tssrc/semantic/domain-inference.tssrc/semantic/type-graph.tssrc/summary.tssrc/types.tssrc/utils/dependency-graph-utils.tssrc/utils/string-utils.tstsconfig.jsontsconfig.tsbuildinfoAll matched files use Prettier code style!
@@ -1,4 +1,5 @@
1
-
2
- > @aiready/context-analyzer@0.21.24 lint /Users/pengcao/projects/aiready/packages/context-analyzer
3
- > eslint src
4
-
1
+
2
+ 
3
+ > @aiready/context-analyzer@0.22.9 lint /Users/pengcao/projects/aiready/packages/context-analyzer
4
+ > eslint src
5
+
@@ -1,15 +1,13 @@
1
1
 
2
2
  
3
- > @aiready/context-analyzer@0.22.6 test /Users/pengcao/projects/aiready/packages/context-analyzer
3
+ > @aiready/context-analyzer@0.22.8 test /Users/pengcao/projects/aiready/packages/context-analyzer
4
4
  > vitest run --exclude "**/dist/**"
5
5
 
6
6
  [?25l
7
7
   RUN  v4.0.18 /Users/pengcao/projects/aiready/packages/context-analyzer
8
8
 
9
- ✓ src/__tests__/report/console-report.test.ts (8 tests) 62ms
10
- ✓ src/__tests__/remediation.test.ts (6 tests) 3ms
11
- ✓ src/__tests__/report/html-report.test.ts (11 tests) 114ms
12
- ✓ src/__tests__/domain-inference.test.ts (26 tests) 14ms
9
+ ✓ src/__tests__/report/console-report.test.ts (8 tests) 42ms
10
+ ✓ src/__tests__/report/html-report.test.ts (11 tests) 67ms
13
11
  stderr | src/__tests__/python-context.test.ts > python-context > analyzePythonContext > should filter for Python files only
14
12
  Failed to analyze src/file2.py: TypeError: Cannot read properties of undefined (reading 'split')
15
13
  at Module.analyzePythonContext (/Users/pengcao/projects/aiready/packages/context-analyzer/src/analyzers/python-context.ts:91:32)
@@ -24,28 +22,30 @@
24
22
  at /Users/pengcao/projects/aiready/packages/context-analyzer/src/__tests__/python-context.test.ts:84:23
25
23
  at file:///Users/pengcao/projects/aiready/node_modules/.pnpm/@vitest+runner@4.0.18/node_modules/@vitest/runner/dist/index.js:915:20
26
24
 
27
- ✓ src/__tests__/python-context.test.ts (4 tests) 55ms
28
- ✓ src/__tests__/consolidation.test.ts (6 tests) 15ms
29
- ✓ src/__tests__/issue-analyzer.test.ts (17 tests) 20ms
30
- ✓ src/__tests__/boilerplate-barrel.test.ts (7 tests) 4ms
31
- ✓ src/__tests__/orchestrator.test.ts (8 tests) 177ms
32
- ✓ src/__tests__/analyzer.test.ts (14 tests) 180ms
33
- ✓ src/__tests__/contract.test.ts (1 test) 25ms
34
- ✓ src/__tests__/auto-detection.test.ts (8 tests) 186ms
35
- ✓ src/__tests__/fragmentation-coupling.test.ts (2 tests) 36ms
25
+ ✓ src/__tests__/python-context.test.ts (4 tests) 13ms
26
+ ✓ src/__tests__/domain-inference.test.ts (26 tests) 6ms
27
+ ✓ src/__tests__/cluster-detector.test.ts (3 tests) 3ms
28
+ ✓ src/__tests__/issue-analyzer.test.ts (17 tests) 99ms
29
+ ✓ src/__tests__/orchestrator.test.ts (8 tests) 70ms
30
+ ✓ src/__tests__/auto-detection.test.ts (8 tests) 25ms
31
+ ✓ src/__tests__/contract.test.ts (1 test) 19ms
32
+ ✓ src/__tests__/consolidation.test.ts (6 tests) 2ms
33
+ ✓ src/__tests__/fragmentation-coupling.test.ts (2 tests) 64ms
34
+ ✓ src/__tests__/structural-cohesion.test.ts (4 tests) 3ms
35
+ ✓ src/__tests__/analyzer.test.ts (14 tests) 47ms
36
36
  ✓ src/__tests__/file-classification.test.ts (63 tests) 6ms
37
- ✓ src/__tests__/provider.test.ts (2 tests) 13ms
38
- ✓ src/__tests__/cluster-detector.test.ts (3 tests) 6ms
39
- ✓ src/__tests__/defaults.test.ts (7 tests) 7ms
40
- ✓ src/__tests__/scoring.test.ts (15 tests) 4ms
37
+ ✓ src/__tests__/remediation.test.ts (6 tests) 3ms
38
+ ✓ src/__tests__/provider.test.ts (2 tests) 4ms
41
39
  ✓ src/__tests__/fragmentation-advanced.test.ts (3 tests) 2ms
40
+ ✓ src/__tests__/scoring.test.ts (15 tests) 6ms
41
+ ✓ src/__tests__/defaults.test.ts (7 tests) 5ms
42
42
  ✓ src/__tests__/enhanced-cohesion.test.ts (6 tests) 2ms
43
- ✓ src/__tests__/fragmentation-log.test.ts (3 tests) 15ms
44
- ✓ src/__tests__/structural-cohesion.test.ts (4 tests) 3ms
43
+ ✓ src/__tests__/fragmentation-log.test.ts (3 tests) 3ms
44
+ ✓ src/__tests__/boilerplate-barrel.test.ts (7 tests) 4ms
45
45
 
46
46
   Test Files  22 passed (22)
47
47
   Tests  224 passed (224)
48
-  Start at  22:04:25
49
-  Duration  8.27s (transform 13.02s, setup 0ms, import 52.87s, tests 948ms, environment 34ms)
48
+  Start at  00:14:06
49
+  Duration  4.74s (transform 8.07s, setup 0ms, import 29.32s, tests 494ms, environment 2ms)
50
50
 
51
51
  [?25h
@@ -0,0 +1,5 @@
1
+
2
+ 
3
+ > @aiready/context-analyzer@0.22.9 type-check /Users/pengcao/projects/aiready/packages/context-analyzer
4
+ > tsc --noEmit
5
+
@@ -0,0 +1,91 @@
1
+ import {
2
+ calculatePathEntropy
3
+ } from "./chunk-JSM7Q5CY.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,143 @@
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
+ {
33
+ ...exports[i],
34
+ imports: exp1Imports || []
35
+ },
36
+ {
37
+ ...exports[j],
38
+ imports: exp2Imports || []
39
+ }
40
+ );
41
+ importScoreTotal += sim;
42
+ pairsWithData++;
43
+ }
44
+ }
45
+ }
46
+ const avgImportScore = pairsWithData > 0 ? importScoreTotal / pairsWithData : 0;
47
+ let score = anyImportData ? domainScore * 0.4 + avgImportScore * 0.6 : domainScore;
48
+ if (anyImportData && score === 0 && domainScore === 0) {
49
+ score = 0.1;
50
+ }
51
+ let structuralScore = 0;
52
+ for (const exp of exports) {
53
+ if (exp.dependencies && exp.dependencies.length > 0) {
54
+ structuralScore += 1;
55
+ }
56
+ }
57
+ if (structuralScore > 0) {
58
+ score = Math.min(1, score + 0.1);
59
+ }
60
+ if (!options?.weights && !anyImportData && domainCounts.size === 1) return 1;
61
+ return score;
62
+ }
63
+ function calculateStructuralCohesionFromCoUsage(file, coUsageMatrix) {
64
+ if (!coUsageMatrix) return 1;
65
+ const coUsages = coUsageMatrix.get(file);
66
+ if (!coUsages || coUsages.size === 0) return 1;
67
+ let total = 0;
68
+ for (const count of coUsages.values()) total += count;
69
+ if (total === 0) return 1;
70
+ const probs = [];
71
+ for (const count of coUsages.values()) {
72
+ if (count > 0) probs.push(count / total);
73
+ }
74
+ if (probs.length <= 1) return 1;
75
+ let entropy = 0;
76
+ for (const prob of probs) {
77
+ entropy -= prob * Math.log2(prob);
78
+ }
79
+ const maxEntropy = Math.log2(probs.length);
80
+ return maxEntropy > 0 ? 1 - entropy / maxEntropy : 1;
81
+ }
82
+ function calculateFragmentation(files, domain, options) {
83
+ if (files.length <= 1) return 0;
84
+ const directories = new Set(
85
+ files.map((file) => file.split("/").slice(0, -1).join("/"))
86
+ );
87
+ const uniqueDirs = directories.size;
88
+ 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);
89
+ if (options?.sharedImportRatio && options.sharedImportRatio > 0.5) {
90
+ const discount = (options.sharedImportRatio - 0.5) * 0.4;
91
+ score = score * (1 - discount);
92
+ }
93
+ return score;
94
+ }
95
+ function calculatePathEntropy(files) {
96
+ if (!files || files.length === 0) return 0;
97
+ const dirCounts = /* @__PURE__ */ new Map();
98
+ for (const file of files) {
99
+ const dir = file.split("/").slice(0, -1).join("/") || ".";
100
+ dirCounts.set(dir, (dirCounts.get(dir) || 0) + 1);
101
+ }
102
+ const counts = Array.from(dirCounts.values());
103
+ if (counts.length <= 1) return 0;
104
+ const total = counts.reduce((sum, value) => sum + value, 0);
105
+ let entropy = 0;
106
+ for (const count of counts) {
107
+ const prob = count / total;
108
+ entropy -= prob * Math.log2(prob);
109
+ }
110
+ const maxEntropy = Math.log2(counts.length);
111
+ return maxEntropy > 0 ? entropy / maxEntropy : 0;
112
+ }
113
+ function calculateDirectoryDistance(files) {
114
+ if (!files || files.length <= 1) return 0;
115
+ const pathSegments = (pathStr) => pathStr.split("/").filter(Boolean);
116
+ const commonAncestorDepth = (pathA, pathB) => {
117
+ const minLen = Math.min(pathA.length, pathB.length);
118
+ let i = 0;
119
+ while (i < minLen && pathA[i] === pathB[i]) i++;
120
+ return i;
121
+ };
122
+ let totalNormalized = 0;
123
+ let comparisons = 0;
124
+ for (let i = 0; i < files.length; i++) {
125
+ for (let j = i + 1; j < files.length; j++) {
126
+ const segA = pathSegments(files[i]);
127
+ const segB = pathSegments(files[j]);
128
+ const shared = commonAncestorDepth(segA, segB);
129
+ const maxDepth = Math.max(segA.length, segB.length);
130
+ totalNormalized += 1 - (maxDepth > 0 ? shared / maxDepth : 0);
131
+ comparisons++;
132
+ }
133
+ }
134
+ return comparisons > 0 ? totalNormalized / comparisons : 0;
135
+ }
136
+
137
+ export {
138
+ calculateEnhancedCohesion,
139
+ calculateStructuralCohesionFromCoUsage,
140
+ calculateFragmentation,
141
+ calculatePathEntropy,
142
+ calculateDirectoryDistance
143
+ };