@aiready/context-analyzer 0.22.7 → 0.22.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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.8 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
15
12
  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
- 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
13
  ESM dist/cli.mjs 1.81 KB
22
- ESM dist/chunk-EMYD7NS6.mjs 4.91 KB
14
+ ESM dist/python-context-BWDC4E5Z.mjs 4.48 KB
15
+ ESM dist/orchestrator-62YVSQFV.mjs 190.00 B
16
+ ESM dist/cli-action-HREY7TK5.mjs 2.86 KB
17
+ ESM dist/chunk-BTDF2ZA4.mjs 3.35 KB
18
+ ESM dist/chunk-J3SZQZNU.mjs 8.11 KB
23
19
  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
20
+ ESM dist/summary-RSPRRY6S.mjs 119.00 B
21
+ ESM dist/chunk-JSM7Q5CY.mjs 4.98 KB
22
+ ESM dist/chunk-ZA7HRDAH.mjs 41.00 KB
23
+ ESM ⚡️ Build success in 180ms
24
+ CJS dist/index.js 83.44 KB
25
+ CJS dist/cli.js 69.65 KB
26
+ CJS ⚡️ Build success in 180ms
27
27
  DTS Build start
28
- DTS ⚡️ Build success in 11173ms
28
+ DTS ⚡️ Build success in 2332ms
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.8 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.8 lint /Users/pengcao/projects/aiready/packages/context-analyzer
4
+ > eslint src
5
+
@@ -1,15 +1,15 @@
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.7 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__/consolidation.test.ts (6 tests) 3ms
10
+ ✓ src/__tests__/report/html-report.test.ts (11 tests) 32ms
11
+ ✓ src/__tests__/report/console-report.test.ts (8 tests) 124ms
12
+ ✓ src/__tests__/domain-inference.test.ts (26 tests) 6ms
13
13
  stderr | src/__tests__/python-context.test.ts > python-context > analyzePythonContext > should filter for Python files only
14
14
  Failed to analyze src/file2.py: TypeError: Cannot read properties of undefined (reading 'split')
15
15
  at Module.analyzePythonContext (/Users/pengcao/projects/aiready/packages/context-analyzer/src/analyzers/python-context.ts:91:32)
@@ -24,28 +24,28 @@
24
24
  at /Users/pengcao/projects/aiready/packages/context-analyzer/src/__tests__/python-context.test.ts:84:23
25
25
  at file:///Users/pengcao/projects/aiready/node_modules/.pnpm/@vitest+runner@4.0.18/node_modules/@vitest/runner/dist/index.js:915:20
26
26
 
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
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
41
- ✓ src/__tests__/fragmentation-advanced.test.ts (3 tests) 2ms
27
+ ✓ src/__tests__/python-context.test.ts (4 tests) 14ms
28
+ ✓ src/__tests__/fragmentation-log.test.ts (3 tests) 1ms
29
+ ✓ src/__tests__/fragmentation-coupling.test.ts (2 tests) 42ms
30
+ ✓ src/__tests__/analyzer.test.ts (14 tests) 46ms
31
+ ✓ src/__tests__/issue-analyzer.test.ts (17 tests) 14ms
32
+ ✓ src/__tests__/auto-detection.test.ts (8 tests) 177ms
33
+ ✓ src/__tests__/orchestrator.test.ts (8 tests) 226ms
34
+ ✓ src/__tests__/provider.test.ts (2 tests) 10ms
35
+ ✓ src/__tests__/defaults.test.ts (7 tests) 3ms
36
+ ✓ src/__tests__/cluster-detector.test.ts (3 tests) 35ms
37
+ ✓ src/__tests__/file-classification.test.ts (63 tests) 12ms
38
+ ✓ src/__tests__/remediation.test.ts (6 tests) 2ms
39
+ ✓ src/__tests__/contract.test.ts (1 test) 19ms
40
+ ✓ src/__tests__/scoring.test.ts (15 tests) 3ms
42
41
  ✓ 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
42
+ ✓ src/__tests__/structural-cohesion.test.ts (4 tests) 39ms
43
+ ✓ src/__tests__/fragmentation-advanced.test.ts (3 tests) 1ms
44
+ ✓ src/__tests__/boilerplate-barrel.test.ts (7 tests) 3ms
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:08:32
49
+  Duration  5.11s (transform 8.77s, setup 0ms, import 35.15s, tests 815ms, environment 9ms)
50
50
 
51
51
  [?25h
@@ -0,0 +1,5 @@
1
+
2
+ 
3
+ > @aiready/context-analyzer@0.22.8 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
+ };