@aiready/context-analyzer 0.9.34 → 0.9.36
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/.github/FUNDING.yml +2 -2
- package/.turbo/turbo-build.log +9 -9
- package/.turbo/turbo-test.log +19 -19
- package/CONTRIBUTING.md +10 -2
- package/dist/chunk-7LUSCLGR.mjs +2058 -0
- package/dist/cli.js +346 -83
- package/dist/cli.mjs +137 -33
- package/dist/index.js +231 -56
- package/dist/index.mjs +1 -1
- package/dist/python-context-GOH747QU.mjs +202 -0
- package/package.json +2 -2
- package/src/__tests__/analyzer.test.ts +69 -17
- package/src/__tests__/auto-detection.test.ts +1 -1
- package/src/__tests__/enhanced-cohesion.test.ts +19 -7
- package/src/__tests__/file-classification.test.ts +188 -53
- package/src/__tests__/fragmentation-advanced.test.ts +2 -11
- package/src/__tests__/fragmentation-coupling.test.ts +8 -2
- package/src/__tests__/fragmentation-log.test.ts +9 -9
- package/src/__tests__/scoring.test.ts +19 -7
- package/src/__tests__/structural-cohesion.test.ts +33 -21
- package/src/analyzer.ts +724 -376
- package/src/analyzers/python-context.ts +33 -10
- package/src/cli.ts +223 -59
- package/src/index.ts +112 -55
- package/src/scoring.ts +53 -43
- package/src/semantic-analysis.ts +73 -55
- package/src/types.ts +12 -13
package/dist/cli.mjs
CHANGED
|
@@ -2,17 +2,26 @@
|
|
|
2
2
|
import {
|
|
3
3
|
analyzeContext,
|
|
4
4
|
generateSummary
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-7LUSCLGR.mjs";
|
|
6
6
|
|
|
7
7
|
// src/cli.ts
|
|
8
8
|
import { Command } from "commander";
|
|
9
9
|
import chalk from "chalk";
|
|
10
10
|
import { writeFileSync, existsSync, readFileSync, mkdirSync } from "fs";
|
|
11
11
|
import { join, dirname } from "path";
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
loadMergedConfig,
|
|
14
|
+
handleJSONOutput,
|
|
15
|
+
handleCLIError,
|
|
16
|
+
getElapsedTime,
|
|
17
|
+
resolveOutputPath
|
|
18
|
+
} from "@aiready/core";
|
|
13
19
|
import prompts from "prompts";
|
|
14
20
|
var program = new Command();
|
|
15
|
-
program.name("aiready-context").description("Analyze AI context window cost and code structure").version("0.1.0").addHelpText(
|
|
21
|
+
program.name("aiready-context").description("Analyze AI context window cost and code structure").version("0.1.0").addHelpText(
|
|
22
|
+
"after",
|
|
23
|
+
"\nCONFIGURATION:\n Supports config files: aiready.json, aiready.config.json, .aiready.json, .aireadyrc.json, aiready.config.js, .aireadyrc.js\n CLI options override config file settings"
|
|
24
|
+
).argument("<directory>", "Directory to analyze").option("--max-depth <number>", "Maximum acceptable import depth").option(
|
|
16
25
|
"--max-context <number>",
|
|
17
26
|
"Maximum acceptable context budget (tokens)"
|
|
18
27
|
).option("--min-cohesion <number>", "Minimum acceptable cohesion score (0-1)").option(
|
|
@@ -21,11 +30,17 @@ program.name("aiready-context").description("Analyze AI context window cost and
|
|
|
21
30
|
).option(
|
|
22
31
|
"--focus <type>",
|
|
23
32
|
"Analysis focus: fragmentation, cohesion, depth, all"
|
|
24
|
-
).option("--include-node-modules", "Include node_modules in analysis").option("--include <patterns>", "File patterns to include (comma-separated)").option("--exclude <patterns>", "File patterns to exclude (comma-separated)").option(
|
|
33
|
+
).option("--include-node-modules", "Include node_modules in analysis").option("--include <patterns>", "File patterns to include (comma-separated)").option("--exclude <patterns>", "File patterns to exclude (comma-separated)").option(
|
|
34
|
+
"--max-results <number>",
|
|
35
|
+
"Maximum number of results to show in console output"
|
|
36
|
+
).option(
|
|
25
37
|
"-o, --output <format>",
|
|
26
38
|
"Output format: console, json, html",
|
|
27
39
|
"console"
|
|
28
|
-
).option("--output-file <path>", "Output file path (for json/html)").option(
|
|
40
|
+
).option("--output-file <path>", "Output file path (for json/html)").option(
|
|
41
|
+
"--interactive",
|
|
42
|
+
"Run interactive setup to suggest excludes and focus areas"
|
|
43
|
+
).action(async (directory, options) => {
|
|
29
44
|
console.log(chalk.blue("\u{1F50D} Analyzing context window costs...\n"));
|
|
30
45
|
const startTime = Date.now();
|
|
31
46
|
try {
|
|
@@ -69,8 +84,12 @@ program.name("aiready-context").description("Analyze AI context window cost and
|
|
|
69
84
|
`context-report-${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}.json`,
|
|
70
85
|
directory
|
|
71
86
|
);
|
|
72
|
-
handleJSONOutput(
|
|
73
|
-
|
|
87
|
+
handleJSONOutput(
|
|
88
|
+
jsonOutput,
|
|
89
|
+
outputPath,
|
|
90
|
+
`
|
|
91
|
+
\u2713 JSON report saved to ${outputPath}`
|
|
92
|
+
);
|
|
74
93
|
return;
|
|
75
94
|
}
|
|
76
95
|
if (options.output === "html") {
|
|
@@ -89,7 +108,12 @@ program.name("aiready-context").description("Analyze AI context window cost and
|
|
|
89
108
|
\u2713 HTML report saved to ${outputPath}`));
|
|
90
109
|
return;
|
|
91
110
|
}
|
|
92
|
-
displayConsoleReport(
|
|
111
|
+
displayConsoleReport(
|
|
112
|
+
summary,
|
|
113
|
+
results,
|
|
114
|
+
elapsedTime,
|
|
115
|
+
finalOptions.maxResults
|
|
116
|
+
);
|
|
93
117
|
displayTuningGuidance(results, finalOptions);
|
|
94
118
|
} catch (error) {
|
|
95
119
|
handleCLIError(error, "Analysis");
|
|
@@ -99,28 +123,80 @@ program.parse();
|
|
|
99
123
|
function displayTuningGuidance(results, options) {
|
|
100
124
|
const issueCount = results.filter((r) => r.severity !== "info").length;
|
|
101
125
|
if (issueCount === 0) {
|
|
102
|
-
console.log(
|
|
126
|
+
console.log(
|
|
127
|
+
chalk.green(
|
|
128
|
+
"\n\u2728 No optimization opportunities found! Your code is well-structured for AI context usage.\n"
|
|
129
|
+
)
|
|
130
|
+
);
|
|
103
131
|
return;
|
|
104
132
|
}
|
|
105
133
|
console.log(chalk.cyan("\n\u2501".repeat(60)));
|
|
106
134
|
console.log(chalk.bold.white(" TUNING GUIDANCE"));
|
|
107
135
|
console.log(chalk.cyan("\u2501".repeat(60) + "\n"));
|
|
108
136
|
if (issueCount < 5) {
|
|
109
|
-
console.log(
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
137
|
+
console.log(
|
|
138
|
+
chalk.yellow(
|
|
139
|
+
"\u{1F4CA} Showing few optimization opportunities. To find more areas to improve:\n"
|
|
140
|
+
)
|
|
141
|
+
);
|
|
142
|
+
console.log(
|
|
143
|
+
chalk.dim(
|
|
144
|
+
" \u2022 Lower --max-depth (currently: " + options.maxDepth + ") to catch shallower import chains"
|
|
145
|
+
)
|
|
146
|
+
);
|
|
147
|
+
console.log(
|
|
148
|
+
chalk.dim(
|
|
149
|
+
" \u2022 Lower --max-context (currently: " + options.maxContextBudget.toLocaleString() + ") to catch smaller files"
|
|
150
|
+
)
|
|
151
|
+
);
|
|
152
|
+
console.log(
|
|
153
|
+
chalk.dim(
|
|
154
|
+
" \u2022 Raise --min-cohesion (currently: " + (options.minCohesion * 100).toFixed(0) + "%) to be stricter about mixed concerns"
|
|
155
|
+
)
|
|
156
|
+
);
|
|
157
|
+
console.log(
|
|
158
|
+
chalk.dim(
|
|
159
|
+
" \u2022 Lower --max-fragmentation (currently: " + (options.maxFragmentation * 100).toFixed(0) + "%) to catch scattered code\n"
|
|
160
|
+
)
|
|
161
|
+
);
|
|
114
162
|
} else if (issueCount > 20) {
|
|
115
|
-
console.log(
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
163
|
+
console.log(
|
|
164
|
+
chalk.yellow(
|
|
165
|
+
"\u{1F4CA} Showing many opportunities. To focus on highest-impact areas:\n"
|
|
166
|
+
)
|
|
167
|
+
);
|
|
168
|
+
console.log(
|
|
169
|
+
chalk.dim(
|
|
170
|
+
" \u2022 Raise --max-depth (currently: " + options.maxDepth + ") to only catch very deep chains"
|
|
171
|
+
)
|
|
172
|
+
);
|
|
173
|
+
console.log(
|
|
174
|
+
chalk.dim(
|
|
175
|
+
" \u2022 Raise --max-context (currently: " + options.maxContextBudget.toLocaleString() + ") to focus on largest files"
|
|
176
|
+
)
|
|
177
|
+
);
|
|
178
|
+
console.log(
|
|
179
|
+
chalk.dim(
|
|
180
|
+
" \u2022 Lower --min-cohesion (currently: " + (options.minCohesion * 100).toFixed(0) + "%) to only flag severe mixed concerns"
|
|
181
|
+
)
|
|
182
|
+
);
|
|
183
|
+
console.log(
|
|
184
|
+
chalk.dim(
|
|
185
|
+
" \u2022 Raise --max-fragmentation (currently: " + (options.maxFragmentation * 100).toFixed(0) + "%) to only flag highly scattered code\n"
|
|
186
|
+
)
|
|
187
|
+
);
|
|
120
188
|
} else {
|
|
121
|
-
console.log(
|
|
189
|
+
console.log(
|
|
190
|
+
chalk.green(
|
|
191
|
+
"\u{1F4CA} Good balance of optimization opportunities (showing " + issueCount + " areas)\n"
|
|
192
|
+
)
|
|
193
|
+
);
|
|
122
194
|
console.log(chalk.dim(" \u{1F4A1} Tip: Adjust thresholds if needed:"));
|
|
123
|
-
console.log(
|
|
195
|
+
console.log(
|
|
196
|
+
chalk.dim(
|
|
197
|
+
" aiready-context . --max-depth N --max-context N --min-cohesion 0.X\n"
|
|
198
|
+
)
|
|
199
|
+
);
|
|
124
200
|
}
|
|
125
201
|
console.log(chalk.dim(" \u{1F4D6} See README for detailed tuning guide\n"));
|
|
126
202
|
}
|
|
@@ -131,9 +207,13 @@ function displayConsoleReport(summary, results, elapsedTime, maxResults = 10) {
|
|
|
131
207
|
console.log(chalk.cyan(divider));
|
|
132
208
|
console.log(chalk.bold.white(" CONTEXT ANALYSIS SUMMARY"));
|
|
133
209
|
console.log(chalk.cyan(divider) + "\n");
|
|
134
|
-
console.log(chalk.white(`\u{1F4C1} Files analyzed: ${chalk.bold(summary.totalFiles)}`));
|
|
135
210
|
console.log(
|
|
136
|
-
chalk.white(`\u{
|
|
211
|
+
chalk.white(`\u{1F4C1} Files analyzed: ${chalk.bold(summary.totalFiles)}`)
|
|
212
|
+
);
|
|
213
|
+
console.log(
|
|
214
|
+
chalk.white(
|
|
215
|
+
`\u{1F4CA} Total tokens: ${chalk.bold(summary.totalTokens.toLocaleString())}`
|
|
216
|
+
)
|
|
137
217
|
);
|
|
138
218
|
console.log(
|
|
139
219
|
chalk.yellow(
|
|
@@ -158,7 +238,9 @@ function displayConsoleReport(summary, results, elapsedTime, maxResults = 10) {
|
|
|
158
238
|
);
|
|
159
239
|
}
|
|
160
240
|
if (summary.minorIssues > 0) {
|
|
161
|
-
console.log(
|
|
241
|
+
console.log(
|
|
242
|
+
chalk.blue(` \u{1F535} Minor: ${chalk.bold(summary.minorIssues)}`)
|
|
243
|
+
);
|
|
162
244
|
}
|
|
163
245
|
console.log(
|
|
164
246
|
chalk.green(
|
|
@@ -253,11 +335,14 @@ function displayConsoleReport(summary, results, elapsedTime, maxResults = 10) {
|
|
|
253
335
|
)
|
|
254
336
|
);
|
|
255
337
|
console.log(
|
|
256
|
-
chalk.dim(
|
|
338
|
+
chalk.dim(
|
|
339
|
+
"\u{1F41B} Found a bug? Report it: https://github.com/caopengau/aiready-context-analyzer/issues\n"
|
|
340
|
+
)
|
|
257
341
|
);
|
|
258
342
|
}
|
|
259
343
|
function generateHTMLReport(summary, results) {
|
|
260
344
|
const totalIssues = summary.criticalIssues + summary.majorIssues + summary.minorIssues;
|
|
345
|
+
void results;
|
|
261
346
|
return `<!DOCTYPE html>
|
|
262
347
|
<html lang="en">
|
|
263
348
|
<head>
|
|
@@ -385,14 +470,16 @@ function generateHTMLReport(summary, results) {
|
|
|
385
470
|
</tr>
|
|
386
471
|
</thead>
|
|
387
472
|
<tbody>
|
|
388
|
-
${summary.fragmentedModules.map(
|
|
473
|
+
${summary.fragmentedModules.map(
|
|
474
|
+
(m) => `
|
|
389
475
|
<tr>
|
|
390
476
|
<td>${m.domain}</td>
|
|
391
477
|
<td>${m.files.length}</td>
|
|
392
478
|
<td>${(m.fragmentationScore * 100).toFixed(0)}%</td>
|
|
393
479
|
<td>${m.totalTokens.toLocaleString()}</td>
|
|
394
480
|
</tr>
|
|
395
|
-
`
|
|
481
|
+
`
|
|
482
|
+
).join("")}
|
|
396
483
|
</tbody>
|
|
397
484
|
</table>
|
|
398
485
|
</div>
|
|
@@ -410,13 +497,15 @@ function generateHTMLReport(summary, results) {
|
|
|
410
497
|
</tr>
|
|
411
498
|
</thead>
|
|
412
499
|
<tbody>
|
|
413
|
-
${summary.topExpensiveFiles.map(
|
|
500
|
+
${summary.topExpensiveFiles.map(
|
|
501
|
+
(f) => `
|
|
414
502
|
<tr>
|
|
415
503
|
<td>${f.file}</td>
|
|
416
504
|
<td>${f.contextBudget.toLocaleString()} tokens</td>
|
|
417
505
|
<td class="issue-${f.severity}">${f.severity.toUpperCase()}</td>
|
|
418
506
|
</tr>
|
|
419
|
-
`
|
|
507
|
+
`
|
|
508
|
+
).join("")}
|
|
420
509
|
</tbody>
|
|
421
510
|
</table>
|
|
422
511
|
</div>
|
|
@@ -438,7 +527,8 @@ async function runInteractiveSetup(directory, current) {
|
|
|
438
527
|
try {
|
|
439
528
|
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
440
529
|
deps = { ...pkg.dependencies || {}, ...pkg.devDependencies || {} };
|
|
441
|
-
} catch {
|
|
530
|
+
} catch (e) {
|
|
531
|
+
void e;
|
|
442
532
|
}
|
|
443
533
|
}
|
|
444
534
|
const hasNextJs = existsSync(join(directory, ".next")) || !!deps["next"];
|
|
@@ -458,7 +548,7 @@ async function runInteractiveSetup(directory, current) {
|
|
|
458
548
|
active: "yes",
|
|
459
549
|
inactive: "no"
|
|
460
550
|
});
|
|
461
|
-
|
|
551
|
+
const nextOptions = { ...current };
|
|
462
552
|
if (applyExcludes) {
|
|
463
553
|
nextOptions.exclude = Array.from(recommendedExcludes);
|
|
464
554
|
}
|
|
@@ -475,9 +565,23 @@ async function runInteractiveSetup(directory, current) {
|
|
|
475
565
|
});
|
|
476
566
|
if (focusArea === "frontend") {
|
|
477
567
|
nextOptions.include = ["**/*.{ts,tsx,js,jsx}"];
|
|
478
|
-
nextOptions.exclude = Array.from(
|
|
568
|
+
nextOptions.exclude = Array.from(
|
|
569
|
+
/* @__PURE__ */ new Set([
|
|
570
|
+
...nextOptions.exclude || [],
|
|
571
|
+
"**/cdk.out/**",
|
|
572
|
+
"**/infra/**",
|
|
573
|
+
"**/server/**",
|
|
574
|
+
"**/backend/**"
|
|
575
|
+
])
|
|
576
|
+
);
|
|
479
577
|
} else if (focusArea === "backend") {
|
|
480
|
-
nextOptions.include = [
|
|
578
|
+
nextOptions.include = [
|
|
579
|
+
"**/api/**",
|
|
580
|
+
"**/server/**",
|
|
581
|
+
"**/backend/**",
|
|
582
|
+
"**/infra/**",
|
|
583
|
+
"**/*.{ts,js,py,java}"
|
|
584
|
+
];
|
|
481
585
|
}
|
|
482
586
|
console.log(chalk.green("\u2713 Interactive configuration applied."));
|
|
483
587
|
return nextOptions;
|