@aiready/context-analyzer 0.21.9 → 0.21.10
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 +12 -12
- package/.turbo/turbo-test.log +26 -26
- package/dist/cli.js +37 -23
- package/dist/cli.mjs +37 -23
- package/dist/index.d.mts +138 -27
- package/dist/index.d.ts +138 -27
- package/dist/index.js +54 -15
- package/dist/index.mjs +54 -15
- package/package.json +2 -2
- package/src/ast-utils.ts +12 -2
- package/src/cli-definition.ts +61 -0
- package/src/cli.ts +2 -44
- package/src/graph-builder.ts +31 -6
- package/src/heuristics.ts +38 -8
- package/src/metrics.ts +21 -8
- package/src/remediation.ts +10 -1
- package/src/scoring.ts +93 -19
- package/src/semantic-analysis.ts +58 -12
- package/src/summary.ts +4 -0
package/src/graph-builder.ts
CHANGED
|
@@ -52,7 +52,10 @@ function resolveImport(
|
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
/**
|
|
55
|
-
* Auto-detect domain keywords from workspace folder structure
|
|
55
|
+
* Auto-detect domain keywords from workspace folder structure.
|
|
56
|
+
*
|
|
57
|
+
* @param files - Array of file contents to analyze for folder patterns.
|
|
58
|
+
* @returns Array of singularized domain keywords.
|
|
56
59
|
*/
|
|
57
60
|
export function extractDomainKeywordsFromPaths(files: FileContent[]): string[] {
|
|
58
61
|
const folderNames = new Set<string>();
|
|
@@ -96,7 +99,11 @@ export function extractDomainKeywordsFromPaths(files: FileContent[]): string[] {
|
|
|
96
99
|
}
|
|
97
100
|
|
|
98
101
|
/**
|
|
99
|
-
* Build a dependency graph from file contents
|
|
102
|
+
* Build a dependency graph from file contents, resolving imports and extracting metadata.
|
|
103
|
+
*
|
|
104
|
+
* @param files - Array of file contents to process.
|
|
105
|
+
* @param options - Optional configuration for domain detection.
|
|
106
|
+
* @returns Complete dependency graph with nodes, edges, and semantic matrices.
|
|
100
107
|
*/
|
|
101
108
|
export function buildDependencyGraph(
|
|
102
109
|
files: FileContent[],
|
|
@@ -170,7 +177,13 @@ export function buildDependencyGraph(
|
|
|
170
177
|
}
|
|
171
178
|
|
|
172
179
|
/**
|
|
173
|
-
* Calculate the maximum depth of import tree for a file
|
|
180
|
+
* Calculate the maximum depth of the import tree for a specific file.
|
|
181
|
+
*
|
|
182
|
+
* @param file - File path to start depth calculation from.
|
|
183
|
+
* @param graph - The dependency graph.
|
|
184
|
+
* @param visited - Optional set to track visited nodes during traversal.
|
|
185
|
+
* @param depth - Current recursion depth.
|
|
186
|
+
* @returns Maximum depth of the import chain.
|
|
174
187
|
*/
|
|
175
188
|
export function calculateImportDepth(
|
|
176
189
|
file: string,
|
|
@@ -182,7 +195,12 @@ export function calculateImportDepth(
|
|
|
182
195
|
}
|
|
183
196
|
|
|
184
197
|
/**
|
|
185
|
-
*
|
|
198
|
+
* Retrieve all transitive dependencies for a specific file.
|
|
199
|
+
*
|
|
200
|
+
* @param file - File path to analyze.
|
|
201
|
+
* @param graph - The dependency graph.
|
|
202
|
+
* @param visited - Optional set to track visited nodes.
|
|
203
|
+
* @returns Array of all reachable file paths.
|
|
186
204
|
*/
|
|
187
205
|
export function getTransitiveDependencies(
|
|
188
206
|
file: string,
|
|
@@ -193,7 +211,11 @@ export function getTransitiveDependencies(
|
|
|
193
211
|
}
|
|
194
212
|
|
|
195
213
|
/**
|
|
196
|
-
* Calculate total context budget (tokens needed to understand this file)
|
|
214
|
+
* Calculate total context budget (tokens needed to understand this file and its dependencies).
|
|
215
|
+
*
|
|
216
|
+
* @param file - File path to calculate budget for.
|
|
217
|
+
* @param graph - The dependency graph.
|
|
218
|
+
* @returns Total token count including recursive dependencies.
|
|
197
219
|
*/
|
|
198
220
|
export function calculateContextBudget(
|
|
199
221
|
file: string,
|
|
@@ -216,7 +238,10 @@ export function calculateContextBudget(
|
|
|
216
238
|
}
|
|
217
239
|
|
|
218
240
|
/**
|
|
219
|
-
* Detect circular dependencies
|
|
241
|
+
* Detect circular dependencies (cycles) within the dependency graph.
|
|
242
|
+
*
|
|
243
|
+
* @param graph - The dependency graph to scan.
|
|
244
|
+
* @returns Array of dependency cycles (each cycle is an array of file paths).
|
|
220
245
|
*/
|
|
221
246
|
export function detectCircularDependencies(graph: DependencyGraph): string[][] {
|
|
222
247
|
return detectGraphCycles(graph.edges);
|
package/src/heuristics.ts
CHANGED
|
@@ -2,6 +2,9 @@ import { DependencyNode } from './types';
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Detect if a file is a barrel export (index.ts)
|
|
5
|
+
*
|
|
6
|
+
* @param node - The dependency node to analyze.
|
|
7
|
+
* @returns True if the file matches barrel export patterns.
|
|
5
8
|
*/
|
|
6
9
|
export function isBarrelExport(node: DependencyNode): boolean {
|
|
7
10
|
const { file, exports } = node;
|
|
@@ -22,6 +25,9 @@ export function isBarrelExport(node: DependencyNode): boolean {
|
|
|
22
25
|
|
|
23
26
|
/**
|
|
24
27
|
* Detect if a file is primarily type definitions
|
|
28
|
+
*
|
|
29
|
+
* @param node - The dependency node to analyze.
|
|
30
|
+
* @returns True if the file contains primarily types or matches type paths.
|
|
25
31
|
*/
|
|
26
32
|
export function isTypeDefinition(node: DependencyNode): boolean {
|
|
27
33
|
const { file } = node;
|
|
@@ -38,7 +44,10 @@ export function isTypeDefinition(node: DependencyNode): boolean {
|
|
|
38
44
|
}
|
|
39
45
|
|
|
40
46
|
/**
|
|
41
|
-
* Detect if a file is a utility module
|
|
47
|
+
* Detect if a file is a utility module.
|
|
48
|
+
*
|
|
49
|
+
* @param node - The dependency node to analyze.
|
|
50
|
+
* @returns True if the file path or name suggests a utility/helper role.
|
|
42
51
|
*/
|
|
43
52
|
export function isUtilityModule(node: DependencyNode): boolean {
|
|
44
53
|
const { file } = node;
|
|
@@ -49,7 +58,10 @@ export function isUtilityModule(node: DependencyNode): boolean {
|
|
|
49
58
|
}
|
|
50
59
|
|
|
51
60
|
/**
|
|
52
|
-
* Detect if a file is a Lambda/API handler
|
|
61
|
+
* Detect if a file is a Lambda/API handler.
|
|
62
|
+
*
|
|
63
|
+
* @param node - The dependency node to analyze.
|
|
64
|
+
* @returns True if the file serves as a coordination point for requests/lambdas.
|
|
53
65
|
*/
|
|
54
66
|
export function isLambdaHandler(node: DependencyNode): boolean {
|
|
55
67
|
const { file, exports } = node;
|
|
@@ -73,7 +85,10 @@ export function isLambdaHandler(node: DependencyNode): boolean {
|
|
|
73
85
|
}
|
|
74
86
|
|
|
75
87
|
/**
|
|
76
|
-
* Detect if a file is a service file
|
|
88
|
+
* Detect if a file is a service file.
|
|
89
|
+
*
|
|
90
|
+
* @param node - The dependency node to analyze.
|
|
91
|
+
* @returns True if the file orchestrates logic or matches service patterns.
|
|
77
92
|
*/
|
|
78
93
|
export function isServiceFile(node: DependencyNode): boolean {
|
|
79
94
|
const { file, exports } = node;
|
|
@@ -91,7 +106,10 @@ export function isServiceFile(node: DependencyNode): boolean {
|
|
|
91
106
|
}
|
|
92
107
|
|
|
93
108
|
/**
|
|
94
|
-
* Detect if a file is an email template/layout
|
|
109
|
+
* Detect if a file is an email template/layout.
|
|
110
|
+
*
|
|
111
|
+
* @param node - The dependency node to analyze.
|
|
112
|
+
* @returns True if the file is used for rendering notifications or emails.
|
|
95
113
|
*/
|
|
96
114
|
export function isEmailTemplate(node: DependencyNode): boolean {
|
|
97
115
|
const { file, exports } = node;
|
|
@@ -118,7 +136,10 @@ export function isEmailTemplate(node: DependencyNode): boolean {
|
|
|
118
136
|
}
|
|
119
137
|
|
|
120
138
|
/**
|
|
121
|
-
* Detect if a file is a parser/transformer
|
|
139
|
+
* Detect if a file is a parser/transformer.
|
|
140
|
+
*
|
|
141
|
+
* @param node - The dependency node to analyze.
|
|
142
|
+
* @returns True if the file handles data conversion or serialization.
|
|
122
143
|
*/
|
|
123
144
|
export function isParserFile(node: DependencyNode): boolean {
|
|
124
145
|
const { file, exports } = node;
|
|
@@ -145,7 +166,10 @@ export function isParserFile(node: DependencyNode): boolean {
|
|
|
145
166
|
}
|
|
146
167
|
|
|
147
168
|
/**
|
|
148
|
-
* Detect if a file is a session/state management file
|
|
169
|
+
* Detect if a file is a session/state management file.
|
|
170
|
+
*
|
|
171
|
+
* @param node - The dependency node to analyze.
|
|
172
|
+
* @returns True if the file manages application state or sessions.
|
|
149
173
|
*/
|
|
150
174
|
export function isSessionFile(node: DependencyNode): boolean {
|
|
151
175
|
const { file, exports } = node;
|
|
@@ -160,7 +184,10 @@ export function isSessionFile(node: DependencyNode): boolean {
|
|
|
160
184
|
}
|
|
161
185
|
|
|
162
186
|
/**
|
|
163
|
-
* Detect if a file is a Next.js App Router page
|
|
187
|
+
* Detect if a file is a Next.js App Router page.
|
|
188
|
+
*
|
|
189
|
+
* @param node - The dependency node to analyze.
|
|
190
|
+
* @returns True if the file is a Next.js page or metadata entry.
|
|
164
191
|
*/
|
|
165
192
|
export function isNextJsPage(node: DependencyNode): boolean {
|
|
166
193
|
const { file, exports } = node;
|
|
@@ -188,7 +215,10 @@ export function isNextJsPage(node: DependencyNode): boolean {
|
|
|
188
215
|
}
|
|
189
216
|
|
|
190
217
|
/**
|
|
191
|
-
* Detect if a file is a configuration or schema file
|
|
218
|
+
* Detect if a file is a configuration or schema file.
|
|
219
|
+
*
|
|
220
|
+
* @param node - The dependency node to analyze.
|
|
221
|
+
* @returns True if the file matches configuration, setting, or schema patterns.
|
|
192
222
|
*/
|
|
193
223
|
export function isConfigFile(node: DependencyNode): boolean {
|
|
194
224
|
const { file, exports } = node;
|
package/src/metrics.ts
CHANGED
|
@@ -2,17 +2,15 @@ import { calculateImportSimilarity } from '@aiready/core';
|
|
|
2
2
|
import type { ExportInfo } from './types';
|
|
3
3
|
import { isTestFile } from './ast-utils';
|
|
4
4
|
|
|
5
|
-
/**
|
|
6
|
-
* Calculate cohesion score (how related are exports in a file)
|
|
7
|
-
*/
|
|
8
5
|
/**
|
|
9
6
|
* Calculates a cohesion score (0-1) for a module based on its exports,
|
|
10
7
|
* shared imports, and internal structure. High cohesion indicates
|
|
11
8
|
* a well-focused module that is easy for AI models to reason about.
|
|
12
9
|
*
|
|
13
|
-
* @param exports - Exported symbols and their metadata
|
|
14
|
-
* @param
|
|
15
|
-
* @
|
|
10
|
+
* @param exports - Exported symbols and their metadata.
|
|
11
|
+
* @param filePath - Optional file path for context.
|
|
12
|
+
* @param options - Optional configuration for weights and co-usage context.
|
|
13
|
+
* @returns Cohesion score between 0 and 1.
|
|
16
14
|
*/
|
|
17
15
|
export function calculateEnhancedCohesion(
|
|
18
16
|
exports: ExportInfo[],
|
|
@@ -105,6 +103,10 @@ export function calculateEnhancedCohesion(
|
|
|
105
103
|
|
|
106
104
|
/**
|
|
107
105
|
* Calculate structural cohesion for a file based on co-usage patterns.
|
|
106
|
+
*
|
|
107
|
+
* @param file - The file path to analyze.
|
|
108
|
+
* @param coUsageMatrix - Matrix of files frequently imported together.
|
|
109
|
+
* @returns Cohesion score between 0 and 1 based on co-usage distribution.
|
|
108
110
|
*/
|
|
109
111
|
export function calculateStructuralCohesionFromCoUsage(
|
|
110
112
|
file: string,
|
|
@@ -137,6 +139,11 @@ export function calculateStructuralCohesionFromCoUsage(
|
|
|
137
139
|
|
|
138
140
|
/**
|
|
139
141
|
* Calculate fragmentation score (how scattered is a domain)
|
|
142
|
+
*
|
|
143
|
+
* @param files - List of files belonging to the domain.
|
|
144
|
+
* @param domain - The domain identifier.
|
|
145
|
+
* @param options - Optional calculation parameters (log scale, thresholds).
|
|
146
|
+
* @returns Fragmentation score from 0 (perfect) to 1 (highly scattered).
|
|
140
147
|
*/
|
|
141
148
|
export function calculateFragmentation(
|
|
142
149
|
files: string[],
|
|
@@ -173,7 +180,10 @@ export function calculateFragmentation(
|
|
|
173
180
|
}
|
|
174
181
|
|
|
175
182
|
/**
|
|
176
|
-
* Calculate path entropy for a set of files
|
|
183
|
+
* Calculate path entropy for a set of files to measure directory distribution.
|
|
184
|
+
*
|
|
185
|
+
* @param files - Array of file paths.
|
|
186
|
+
* @returns Entropy score representing the spread across directories.
|
|
177
187
|
*/
|
|
178
188
|
export function calculatePathEntropy(files: string[]): number {
|
|
179
189
|
if (!files || files.length === 0) return 0;
|
|
@@ -199,7 +209,10 @@ export function calculatePathEntropy(files: string[]): number {
|
|
|
199
209
|
}
|
|
200
210
|
|
|
201
211
|
/**
|
|
202
|
-
* Calculate directory-distance metric based on common ancestor depth
|
|
212
|
+
* Calculate directory-distance metric based on common ancestor depth.
|
|
213
|
+
*
|
|
214
|
+
* @param files - Array of file paths to compare.
|
|
215
|
+
* @returns Normalized distance metric (0-1).
|
|
203
216
|
*/
|
|
204
217
|
export function calculateDirectoryDistance(files: string[]): number {
|
|
205
218
|
if (!files || files.length <= 1) return 0;
|
package/src/remediation.ts
CHANGED
|
@@ -2,6 +2,11 @@ import type { FileClassification } from './types';
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Get classification-specific recommendations
|
|
5
|
+
*
|
|
6
|
+
* @param classification - The identified type of file (e.g., 'barrel-export', 'utility-module').
|
|
7
|
+
* @param file - File path or identifier.
|
|
8
|
+
* @param issues - Initial list of issues to supplement.
|
|
9
|
+
* @returns Array of tailored recommendations.
|
|
5
10
|
*/
|
|
6
11
|
export function getClassificationRecommendations(
|
|
7
12
|
classification: FileClassification,
|
|
@@ -66,7 +71,11 @@ export function getClassificationRecommendations(
|
|
|
66
71
|
}
|
|
67
72
|
|
|
68
73
|
/**
|
|
69
|
-
* Generate general context recommendations
|
|
74
|
+
* Generate general context recommendations based on cross-tool metrics and thresholds.
|
|
75
|
+
*
|
|
76
|
+
* @param metrics - Object containing context budget, depth, circular dependencies, cohesion, and fragmentation.
|
|
77
|
+
* @param thresholds - Configurable limits for each metric.
|
|
78
|
+
* @returns Object with recommendations array, issues array, and overall severity level.
|
|
70
79
|
*/
|
|
71
80
|
export function getGeneralRecommendations(
|
|
72
81
|
metrics: {
|
package/src/scoring.ts
CHANGED
|
@@ -10,7 +10,39 @@ import type { ToolScoringOutput } from '@aiready/core';
|
|
|
10
10
|
import type { ContextSummary } from './types';
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
|
-
*
|
|
13
|
+
* Thresholds and weights for context efficiency scoring.
|
|
14
|
+
*/
|
|
15
|
+
const BUDGET_EXCELLENT_THRESHOLD = 8000;
|
|
16
|
+
const BUDGET_PENALTY_RATE = 200;
|
|
17
|
+
const DEPTH_EXCELLENT_THRESHOLD = 8;
|
|
18
|
+
const DEPTH_PENALTY_WEIGHT = 5;
|
|
19
|
+
const FRAGMENTATION_EXCELLENT_THRESHOLD = 0.5;
|
|
20
|
+
const FRAGMENTATION_PENALTY_WEIGHT = 100;
|
|
21
|
+
const MAX_CRITICAL_PENALTY = 20;
|
|
22
|
+
const CRITICAL_ISSUE_WEIGHT = 3;
|
|
23
|
+
const MAX_MAJOR_PENALTY = 15;
|
|
24
|
+
const MAJOR_ISSUE_WEIGHT = 1;
|
|
25
|
+
const EXTREME_FILE_THRESHOLD = 15000;
|
|
26
|
+
const MAX_EXTREME_PENALTY = 20;
|
|
27
|
+
const EXTREME_PENALTY_DIVISOR = 500;
|
|
28
|
+
const FRAGMENTATION_BONUS_THRESHOLD = 0.2;
|
|
29
|
+
const ORGANIZATION_BONUS = 5;
|
|
30
|
+
const MAX_TOTAL_PENALTY = 30;
|
|
31
|
+
|
|
32
|
+
const WEIGHT_BUDGET = 0.35;
|
|
33
|
+
const WEIGHT_DEPTH = 0.25;
|
|
34
|
+
const WEIGHT_FRAGMENTATION = 0.25;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Calculate AI Readiness Score for context efficiency (0-100).
|
|
38
|
+
*
|
|
39
|
+
* Evaluates how efficiently an AI model can process the project's code context
|
|
40
|
+
* based on token budgets, import depth, and file fragmentation.
|
|
41
|
+
*
|
|
42
|
+
* @param summary - Consolidated context summary from the scan.
|
|
43
|
+
* @param costConfig - Optional configuration for business value calculations.
|
|
44
|
+
* @returns Standardized scoring output for the context analyzer tool.
|
|
45
|
+
* @lastUpdated 2026-03-18
|
|
14
46
|
*/
|
|
15
47
|
export function calculateContextScore(
|
|
16
48
|
summary: ContextSummary,
|
|
@@ -29,54 +61,90 @@ export function calculateContextScore(
|
|
|
29
61
|
|
|
30
62
|
// More reasonable thresholds for modern codebases
|
|
31
63
|
const budgetScore =
|
|
32
|
-
avgContextBudget <
|
|
64
|
+
avgContextBudget < BUDGET_EXCELLENT_THRESHOLD
|
|
33
65
|
? 100
|
|
34
|
-
: Math.max(
|
|
66
|
+
: Math.max(
|
|
67
|
+
0,
|
|
68
|
+
100 -
|
|
69
|
+
(avgContextBudget - BUDGET_EXCELLENT_THRESHOLD) /
|
|
70
|
+
BUDGET_PENALTY_RATE
|
|
71
|
+
);
|
|
35
72
|
|
|
36
73
|
const depthScore =
|
|
37
|
-
avgImportDepth <
|
|
74
|
+
avgImportDepth < DEPTH_EXCELLENT_THRESHOLD
|
|
75
|
+
? 100
|
|
76
|
+
: Math.max(
|
|
77
|
+
0,
|
|
78
|
+
100 -
|
|
79
|
+
(avgImportDepth - DEPTH_EXCELLENT_THRESHOLD) * DEPTH_PENALTY_WEIGHT
|
|
80
|
+
);
|
|
38
81
|
|
|
39
82
|
const fragmentationScore =
|
|
40
|
-
avgFragmentation <
|
|
83
|
+
avgFragmentation < FRAGMENTATION_EXCELLENT_THRESHOLD
|
|
41
84
|
? 100
|
|
42
|
-
: Math.max(
|
|
85
|
+
: Math.max(
|
|
86
|
+
0,
|
|
87
|
+
100 -
|
|
88
|
+
(avgFragmentation - FRAGMENTATION_EXCELLENT_THRESHOLD) *
|
|
89
|
+
FRAGMENTATION_PENALTY_WEIGHT
|
|
90
|
+
);
|
|
43
91
|
|
|
44
92
|
// Cap penalties to prevent score going to 0
|
|
45
|
-
const criticalPenalty = Math.min(
|
|
46
|
-
|
|
93
|
+
const criticalPenalty = Math.min(
|
|
94
|
+
MAX_CRITICAL_PENALTY,
|
|
95
|
+
criticalIssues * CRITICAL_ISSUE_WEIGHT
|
|
96
|
+
);
|
|
97
|
+
const majorPenalty = Math.min(
|
|
98
|
+
MAX_MAJOR_PENALTY,
|
|
99
|
+
majorIssues * MAJOR_ISSUE_WEIGHT
|
|
100
|
+
);
|
|
47
101
|
|
|
48
102
|
const maxBudgetPenalty =
|
|
49
|
-
maxContextBudget >
|
|
50
|
-
? Math.min(
|
|
103
|
+
maxContextBudget > EXTREME_FILE_THRESHOLD
|
|
104
|
+
? Math.min(
|
|
105
|
+
MAX_EXTREME_PENALTY,
|
|
106
|
+
(maxContextBudget - EXTREME_FILE_THRESHOLD) / EXTREME_PENALTY_DIVISOR
|
|
107
|
+
)
|
|
51
108
|
: 0;
|
|
52
109
|
|
|
53
110
|
// Add bonus for well-organized codebases
|
|
54
111
|
let bonus = 0;
|
|
55
|
-
if (
|
|
56
|
-
|
|
112
|
+
if (
|
|
113
|
+
criticalIssues === 0 &&
|
|
114
|
+
majorIssues === 0 &&
|
|
115
|
+
avgFragmentation < FRAGMENTATION_BONUS_THRESHOLD
|
|
116
|
+
) {
|
|
117
|
+
bonus = ORGANIZATION_BONUS;
|
|
57
118
|
}
|
|
58
119
|
|
|
59
120
|
const rawScore =
|
|
60
|
-
budgetScore *
|
|
121
|
+
budgetScore * WEIGHT_BUDGET +
|
|
122
|
+
depthScore * WEIGHT_DEPTH +
|
|
123
|
+
fragmentationScore * WEIGHT_FRAGMENTATION +
|
|
124
|
+
bonus;
|
|
61
125
|
const finalScore =
|
|
62
|
-
rawScore -
|
|
126
|
+
rawScore -
|
|
127
|
+
Math.min(MAX_TOTAL_PENALTY, criticalPenalty + majorPenalty) -
|
|
128
|
+
maxBudgetPenalty;
|
|
63
129
|
|
|
64
130
|
const score = Math.max(0, Math.min(100, Math.round(finalScore)));
|
|
65
131
|
|
|
66
132
|
const factors = [
|
|
67
133
|
{
|
|
68
134
|
name: 'Context Budget',
|
|
69
|
-
impact: Math.round(budgetScore *
|
|
70
|
-
description: `Avg ${Math.round(avgContextBudget)} tokens per file ${avgContextBudget <
|
|
135
|
+
impact: Math.round(budgetScore * WEIGHT_BUDGET - WEIGHT_BUDGET * 100),
|
|
136
|
+
description: `Avg ${Math.round(avgContextBudget)} tokens per file ${avgContextBudget < BUDGET_EXCELLENT_THRESHOLD ? '(excellent)' : avgContextBudget < 12000 ? '(acceptable)' : '(high)'}`,
|
|
71
137
|
},
|
|
72
138
|
{
|
|
73
139
|
name: 'Import Depth',
|
|
74
|
-
impact: Math.round(depthScore *
|
|
75
|
-
description: `Avg ${avgImportDepth.toFixed(1)} levels ${avgImportDepth <
|
|
140
|
+
impact: Math.round(depthScore * WEIGHT_DEPTH - WEIGHT_DEPTH * 100),
|
|
141
|
+
description: `Avg ${avgImportDepth.toFixed(1)} levels ${avgImportDepth < DEPTH_EXCELLENT_THRESHOLD ? '(excellent)' : avgImportDepth < 12 ? '(acceptable)' : '(deep)'}`,
|
|
76
142
|
},
|
|
77
143
|
{
|
|
78
144
|
name: 'Fragmentation',
|
|
79
|
-
impact: Math.round(
|
|
145
|
+
impact: Math.round(
|
|
146
|
+
fragmentationScore * WEIGHT_FRAGMENTATION - WEIGHT_FRAGMENTATION * 100
|
|
147
|
+
),
|
|
80
148
|
description: `${(avgFragmentation * 100).toFixed(0)}% fragmentation ${avgFragmentation < 0.3 ? '(well-organized)' : avgFragmentation < 0.5 ? '(moderate)' : '(high)'}`,
|
|
81
149
|
},
|
|
82
150
|
];
|
|
@@ -190,6 +258,12 @@ export function calculateContextScore(
|
|
|
190
258
|
};
|
|
191
259
|
}
|
|
192
260
|
|
|
261
|
+
/**
|
|
262
|
+
* Maps a numerical score to a human-readable rating slug.
|
|
263
|
+
*
|
|
264
|
+
* @param score - The 0-100 readiness score.
|
|
265
|
+
* @returns A formatted rating string (e.g., "excellent", "at risk").
|
|
266
|
+
*/
|
|
193
267
|
export function mapScoreToRating(score: number): string {
|
|
194
268
|
// Use core implementation to resolve duplication
|
|
195
269
|
return getRatingSlug(score).replace('-', ' ');
|
package/src/semantic-analysis.ts
CHANGED
|
@@ -8,9 +8,10 @@ import type {
|
|
|
8
8
|
import { singularize } from './utils/string-utils';
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
|
-
* Build co-usage matrix: track which files are imported together
|
|
12
|
-
*
|
|
13
|
-
* @
|
|
11
|
+
* Build co-usage matrix: track which files are imported together frequently.
|
|
12
|
+
*
|
|
13
|
+
* @param graph - The dependency graph to analyze.
|
|
14
|
+
* @returns Map of file path to nested map of related files and their co-occurrence counts.
|
|
14
15
|
*/
|
|
15
16
|
export function buildCoUsageMatrix(
|
|
16
17
|
graph: DependencyGraph
|
|
@@ -40,9 +41,10 @@ export function buildCoUsageMatrix(
|
|
|
40
41
|
}
|
|
41
42
|
|
|
42
43
|
/**
|
|
43
|
-
* Extract type dependencies from AST exports
|
|
44
|
-
*
|
|
45
|
-
* @
|
|
44
|
+
* Extract type dependencies from AST exports to build a type-based relationship graph.
|
|
45
|
+
*
|
|
46
|
+
* @param graph - The dependency graph to analyze.
|
|
47
|
+
* @returns Map of type reference names to sets of files that consume or export them.
|
|
46
48
|
*/
|
|
47
49
|
export function buildTypeGraph(
|
|
48
50
|
graph: DependencyGraph
|
|
@@ -64,10 +66,11 @@ export function buildTypeGraph(
|
|
|
64
66
|
}
|
|
65
67
|
|
|
66
68
|
/**
|
|
67
|
-
* Find semantic clusters using co-usage patterns
|
|
68
|
-
*
|
|
69
|
-
* @param
|
|
70
|
-
* @
|
|
69
|
+
* Find semantic clusters using frequently occurring co-usage patterns.
|
|
70
|
+
*
|
|
71
|
+
* @param coUsageMatrix - The co-usage matrix from buildCoUsageMatrix.
|
|
72
|
+
* @param minCoUsage - Minimum co-usage count to consider a strong relationship (default: 3).
|
|
73
|
+
* @returns Map of cluster representative files to their associated cluster members.
|
|
71
74
|
*/
|
|
72
75
|
export function findSemanticClusters(
|
|
73
76
|
coUsageMatrix: Map<string, Map<string, number>>,
|
|
@@ -96,7 +99,15 @@ export function findSemanticClusters(
|
|
|
96
99
|
}
|
|
97
100
|
|
|
98
101
|
/**
|
|
99
|
-
* Infer domain from semantic analysis (co-usage + types)
|
|
102
|
+
* Infer domain from semantic analysis (co-usage + types) to identify logical modules.
|
|
103
|
+
*
|
|
104
|
+
* @param file - The file path to infer domain for.
|
|
105
|
+
* @param exportName - The specific export identifier.
|
|
106
|
+
* @param graph - The full dependency graph.
|
|
107
|
+
* @param coUsageMatrix - Matrix of files frequently imported together.
|
|
108
|
+
* @param typeGraph - Map of type references to files.
|
|
109
|
+
* @param exportTypeRefs - Optional list of types referenced by the export.
|
|
110
|
+
* @returns Array of potential domain assignments with confidence scores.
|
|
100
111
|
*/
|
|
101
112
|
export function inferDomainFromSemantics(
|
|
102
113
|
file: string,
|
|
@@ -173,6 +184,12 @@ export function inferDomainFromSemantics(
|
|
|
173
184
|
return assignments;
|
|
174
185
|
}
|
|
175
186
|
|
|
187
|
+
/**
|
|
188
|
+
* Calculate confidence score for a domain assignment based on signals.
|
|
189
|
+
*
|
|
190
|
+
* @param signals - The set of semantic signals detected for a domain.
|
|
191
|
+
* @returns Numerical confidence score (0-1).
|
|
192
|
+
*/
|
|
176
193
|
export function calculateDomainConfidence(signals: DomainSignals): number {
|
|
177
194
|
const weights = {
|
|
178
195
|
coUsage: 0.35,
|
|
@@ -192,6 +209,12 @@ export function calculateDomainConfidence(signals: DomainSignals): number {
|
|
|
192
209
|
|
|
193
210
|
/**
|
|
194
211
|
* Regex-based export extraction (legacy/fallback)
|
|
212
|
+
*
|
|
213
|
+
* @param content - Source code content.
|
|
214
|
+
* @param filePath - Optional file path for domain context.
|
|
215
|
+
* @param domainOptions - Optional overrides for domain keywords.
|
|
216
|
+
* @param fileImports - Optional list of actual imports for semantic context.
|
|
217
|
+
* @returns Array of extracted export information.
|
|
195
218
|
*/
|
|
196
219
|
export function extractExports(
|
|
197
220
|
content: string,
|
|
@@ -238,6 +261,12 @@ export function extractExports(
|
|
|
238
261
|
|
|
239
262
|
/**
|
|
240
263
|
* Infer domain from name, path, or imports
|
|
264
|
+
*
|
|
265
|
+
* @param name - The identifier name to analyze.
|
|
266
|
+
* @param filePath - Optional file path for structure context.
|
|
267
|
+
* @param domainOptions - Optional overrides for domain keywords.
|
|
268
|
+
* @param fileImports - Optional list of imports for domain context.
|
|
269
|
+
* @returns The inferred domain name (string).
|
|
241
270
|
*/
|
|
242
271
|
export function inferDomain(
|
|
243
272
|
name: string,
|
|
@@ -320,6 +349,13 @@ export function inferDomain(
|
|
|
320
349
|
return 'unknown';
|
|
321
350
|
}
|
|
322
351
|
|
|
352
|
+
/**
|
|
353
|
+
* Retrieve co-usage data for a specific file.
|
|
354
|
+
*
|
|
355
|
+
* @param file - The file path to look up.
|
|
356
|
+
* @param coUsageMatrix - The global co-usage matrix.
|
|
357
|
+
* @returns Formatted co-usage data object.
|
|
358
|
+
*/
|
|
323
359
|
export function getCoUsageData(
|
|
324
360
|
file: string,
|
|
325
361
|
coUsageMatrix: Map<string, Map<string, number>>
|
|
@@ -331,13 +367,23 @@ export function getCoUsageData(
|
|
|
331
367
|
};
|
|
332
368
|
}
|
|
333
369
|
|
|
370
|
+
/**
|
|
371
|
+
* Identify candidates for module consolidation based on high co-usage or shared types.
|
|
372
|
+
*
|
|
373
|
+
* @param graph - The dependency graph.
|
|
374
|
+
* @param coUsageMatrix - Matrix of frequently paired files.
|
|
375
|
+
* @param typeGraph - Map of shared type references.
|
|
376
|
+
* @param minCoUsage - Minimum co-usage count threshold.
|
|
377
|
+
* @param minSharedTypes - Minimum shared types threshold.
|
|
378
|
+
* @returns Array of consolidation candidates sorted by strength.
|
|
379
|
+
*/
|
|
334
380
|
export function findConsolidationCandidates(
|
|
335
381
|
graph: DependencyGraph,
|
|
336
382
|
coUsageMatrix: Map<string, Map<string, number>>,
|
|
337
383
|
typeGraph: Map<string, Set<string>>,
|
|
338
384
|
minCoUsage: number = 5,
|
|
339
385
|
minSharedTypes: number = 2
|
|
340
|
-
) {
|
|
386
|
+
): any[] {
|
|
341
387
|
const candidates: any[] = [];
|
|
342
388
|
for (const [fileA, coUsages] of coUsageMatrix) {
|
|
343
389
|
const nodeA = graph.nodes.get(fileA);
|
package/src/summary.ts
CHANGED
|
@@ -8,6 +8,10 @@ import { calculatePathEntropy } from './metrics';
|
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Generate summary of context analysis results
|
|
11
|
+
*
|
|
12
|
+
* @param results - Array of individual file analysis results.
|
|
13
|
+
* @param options - Optional scan configuration for context extraction.
|
|
14
|
+
* @returns A consolidated summary of the entire context scan.
|
|
11
15
|
*/
|
|
12
16
|
export function generateSummary(
|
|
13
17
|
results: ContextAnalysisResult[],
|