@aiready/context-analyzer 0.22.14 → 0.22.16
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 +19 -19
- package/.turbo/turbo-format-check.log +1 -1
- package/.turbo/turbo-lint.log +1 -1
- package/.turbo/turbo-test.log +347 -25
- package/.turbo/turbo-type-check.log +1 -1
- package/dist/chunk-2LEHY2GV.mjs +1287 -0
- package/dist/chunk-P2ZQGQAO.mjs +1282 -0
- package/dist/chunk-QGI23DBA.mjs +1282 -0
- package/dist/chunk-QTB4KYCX.mjs +1260 -0
- package/dist/chunk-RQ5BQLT6.mjs +102 -0
- package/dist/chunk-VYFHSGV6.mjs +1283 -0
- package/dist/chunk-WLXLBWDU.mjs +96 -0
- package/dist/chunk-XDYPMFCH.mjs +1250 -0
- package/dist/cli-action-332WE54N.mjs +95 -0
- package/dist/cli-action-7QXG7LHS.mjs +95 -0
- package/dist/cli-action-BIX6TYXF.mjs +95 -0
- package/dist/cli-action-BUGVCH44.mjs +95 -0
- package/dist/cli-action-JKG3R6RV.mjs +93 -0
- package/dist/cli-action-RO24U52W.mjs +95 -0
- package/dist/cli-action-WAZ5KM6X.mjs +95 -0
- package/dist/cli-action-XDKINE2R.mjs +95 -0
- package/dist/cli-action-Y6VATXMV.mjs +95 -0
- package/dist/cli.js +79 -31
- package/dist/cli.mjs +1 -1
- package/dist/console-report-CVGRMWEU.mjs +74 -0
- package/dist/html-report-BYGKWC3K.mjs +73 -0
- package/dist/index.d.mts +4 -2
- package/dist/index.d.ts +4 -2
- package/dist/index.js +71 -25
- package/dist/index.mjs +3 -3
- package/dist/orchestrator-2KQNMO2L.mjs +10 -0
- package/dist/orchestrator-66ZVNOLR.mjs +10 -0
- package/dist/orchestrator-KM2OJPZD.mjs +10 -0
- package/dist/orchestrator-MKDZPRBA.mjs +10 -0
- package/dist/orchestrator-QSHWWBWS.mjs +10 -0
- package/dist/orchestrator-WFQPMNSD.mjs +10 -0
- package/dist/python-context-H2OLC5JN.mjs +162 -0
- package/dist/python-context-OBP7JD5P.mjs +162 -0
- package/package.json +8 -6
- package/src/__tests__/analyzer.test.ts +4 -3
- package/src/__tests__/issue-analyzer.test.ts +4 -2
- package/src/classify/file-classifiers.ts +14 -13
- package/src/cli-action.ts +6 -3
- package/src/graph-builder.ts +43 -8
- package/src/issue-analyzer.ts +19 -7
- package/src/orchestrator.ts +6 -4
- package/src/report/console-report.ts +2 -2
- package/src/report/html-report.ts +2 -2
- package/src/semantic/domain-inference.ts +1 -1
- package/src/types.ts +2 -0
- package/src/utils/dependency-graph-utils.ts +22 -13
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import {
|
|
2
|
+
analyzeContext
|
|
3
|
+
} from "./chunk-VYFHSGV6.mjs";
|
|
4
|
+
import "./chunk-RQ5BQLT6.mjs";
|
|
5
|
+
import {
|
|
6
|
+
generateSummary
|
|
7
|
+
} from "./chunk-HD4Y3GYL.mjs";
|
|
8
|
+
import "./chunk-JSM7Q5CY.mjs";
|
|
9
|
+
|
|
10
|
+
// src/cli-action.ts
|
|
11
|
+
import {
|
|
12
|
+
loadMergedConfig,
|
|
13
|
+
handleJSONOutput,
|
|
14
|
+
handleCLIError,
|
|
15
|
+
getElapsedTime,
|
|
16
|
+
resolveOutputPath
|
|
17
|
+
} from "@aiready/core";
|
|
18
|
+
import chalk from "chalk";
|
|
19
|
+
import { writeFileSync } from "fs";
|
|
20
|
+
async function contextActionHandler(directory, options) {
|
|
21
|
+
console.log(chalk.blue("\u{1F50D} Analyzing context window costs...\n"));
|
|
22
|
+
const startTime = Date.now();
|
|
23
|
+
try {
|
|
24
|
+
const defaults = {
|
|
25
|
+
maxDepth: 10,
|
|
26
|
+
maxContextBudget: 1e4,
|
|
27
|
+
minCohesion: 0.6,
|
|
28
|
+
maxFragmentation: 0.5,
|
|
29
|
+
focus: "all",
|
|
30
|
+
includeNodeModules: false,
|
|
31
|
+
include: void 0,
|
|
32
|
+
exclude: void 0,
|
|
33
|
+
maxResults: 10
|
|
34
|
+
};
|
|
35
|
+
let finalOptions = await loadMergedConfig(directory, defaults, {
|
|
36
|
+
maxDepth: options.maxDepth ? parseInt(options.maxDepth) : void 0,
|
|
37
|
+
maxContextBudget: options.maxContext ? parseInt(options.maxContext) : void 0,
|
|
38
|
+
minCohesion: options.minCohesion ? parseFloat(options.minCohesion) : void 0,
|
|
39
|
+
maxFragmentation: options.maxFragmentation ? parseFloat(options.maxFragmentation) : void 0,
|
|
40
|
+
focus: options.focus || void 0,
|
|
41
|
+
includeNodeModules: options.includeNodeModules,
|
|
42
|
+
include: options.include?.split(","),
|
|
43
|
+
exclude: options.exclude?.split(","),
|
|
44
|
+
maxResults: options.maxResults ? parseInt(options.maxResults) : void 0
|
|
45
|
+
});
|
|
46
|
+
if (options.interactive) {
|
|
47
|
+
const { runInteractiveSetup } = await import("./interactive-setup-JGFBFI3M.mjs");
|
|
48
|
+
finalOptions = await runInteractiveSetup(directory, finalOptions);
|
|
49
|
+
}
|
|
50
|
+
const results = await analyzeContext(
|
|
51
|
+
finalOptions
|
|
52
|
+
);
|
|
53
|
+
const summary = generateSummary(results, finalOptions);
|
|
54
|
+
const duration = getElapsedTime(startTime);
|
|
55
|
+
if (options.output === "json") {
|
|
56
|
+
handleJSONOutput(
|
|
57
|
+
{
|
|
58
|
+
summary: {
|
|
59
|
+
...summary,
|
|
60
|
+
executionTime: duration,
|
|
61
|
+
config: {
|
|
62
|
+
scan: { tools: ["context"] },
|
|
63
|
+
tools: { context: finalOptions }
|
|
64
|
+
},
|
|
65
|
+
toolConfigs: { context: finalOptions }
|
|
66
|
+
},
|
|
67
|
+
context: { results }
|
|
68
|
+
},
|
|
69
|
+
options.outputFile
|
|
70
|
+
);
|
|
71
|
+
} else if (options.output === "html") {
|
|
72
|
+
const { generateHTMLReport } = await import("./html-report-BYGKWC3K.mjs");
|
|
73
|
+
const html = generateHTMLReport(summary, results);
|
|
74
|
+
const outputPath = resolveOutputPath(
|
|
75
|
+
directory,
|
|
76
|
+
options.outputFile,
|
|
77
|
+
"context-report.html"
|
|
78
|
+
);
|
|
79
|
+
writeFileSync(outputPath, html, "utf-8");
|
|
80
|
+
console.log(chalk.green(`
|
|
81
|
+
\u2705 HTML report saved to: ${outputPath}`));
|
|
82
|
+
} else {
|
|
83
|
+
const { displayConsoleReport } = await import("./console-report-CVGRMWEU.mjs");
|
|
84
|
+
displayConsoleReport(summary, results, finalOptions.maxResults);
|
|
85
|
+
console.log(chalk.dim(`
|
|
86
|
+
\u2728 Analysis completed in ${duration}ms
|
|
87
|
+
`));
|
|
88
|
+
}
|
|
89
|
+
} catch (error) {
|
|
90
|
+
handleCLIError(error, "context-analyzer");
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
export {
|
|
94
|
+
contextActionHandler
|
|
95
|
+
};
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import {
|
|
2
|
+
analyzeContext
|
|
3
|
+
} from "./chunk-XDYPMFCH.mjs";
|
|
4
|
+
import "./chunk-64U3PNO3.mjs";
|
|
5
|
+
import {
|
|
6
|
+
generateSummary
|
|
7
|
+
} from "./chunk-HD4Y3GYL.mjs";
|
|
8
|
+
import "./chunk-JSM7Q5CY.mjs";
|
|
9
|
+
|
|
10
|
+
// src/cli-action.ts
|
|
11
|
+
import {
|
|
12
|
+
loadMergedConfig,
|
|
13
|
+
handleJSONOutput,
|
|
14
|
+
handleCLIError,
|
|
15
|
+
getElapsedTime,
|
|
16
|
+
resolveOutputPath
|
|
17
|
+
} from "@aiready/core";
|
|
18
|
+
import chalk from "chalk";
|
|
19
|
+
import { writeFileSync } from "fs";
|
|
20
|
+
async function contextActionHandler(directory, options) {
|
|
21
|
+
console.log(chalk.blue("\u{1F50D} Analyzing context window costs...\n"));
|
|
22
|
+
const startTime = Date.now();
|
|
23
|
+
try {
|
|
24
|
+
const defaults = {
|
|
25
|
+
maxDepth: 5,
|
|
26
|
+
maxContextBudget: 1e4,
|
|
27
|
+
minCohesion: 0.6,
|
|
28
|
+
maxFragmentation: 0.5,
|
|
29
|
+
focus: "all",
|
|
30
|
+
includeNodeModules: false,
|
|
31
|
+
include: void 0,
|
|
32
|
+
exclude: void 0,
|
|
33
|
+
maxResults: 10
|
|
34
|
+
};
|
|
35
|
+
let finalOptions = await loadMergedConfig(directory, defaults, {
|
|
36
|
+
maxDepth: options.maxDepth ? parseInt(options.maxDepth) : void 0,
|
|
37
|
+
maxContextBudget: options.maxContext ? parseInt(options.maxContext) : void 0,
|
|
38
|
+
minCohesion: options.minCohesion ? parseFloat(options.minCohesion) : void 0,
|
|
39
|
+
maxFragmentation: options.maxFragmentation ? parseFloat(options.maxFragmentation) : void 0,
|
|
40
|
+
focus: options.focus || void 0,
|
|
41
|
+
includeNodeModules: options.includeNodeModules,
|
|
42
|
+
include: options.include?.split(","),
|
|
43
|
+
exclude: options.exclude?.split(","),
|
|
44
|
+
maxResults: options.maxResults ? parseInt(options.maxResults) : void 0
|
|
45
|
+
});
|
|
46
|
+
if (options.interactive) {
|
|
47
|
+
const { runInteractiveSetup } = await import("./interactive-setup-JGFBFI3M.mjs");
|
|
48
|
+
finalOptions = await runInteractiveSetup(directory, finalOptions);
|
|
49
|
+
}
|
|
50
|
+
const results = await analyzeContext(
|
|
51
|
+
finalOptions
|
|
52
|
+
);
|
|
53
|
+
const summary = generateSummary(results, finalOptions);
|
|
54
|
+
const duration = getElapsedTime(startTime);
|
|
55
|
+
if (options.output === "json") {
|
|
56
|
+
handleJSONOutput(
|
|
57
|
+
{
|
|
58
|
+
summary: {
|
|
59
|
+
...summary,
|
|
60
|
+
executionTime: duration,
|
|
61
|
+
config: {
|
|
62
|
+
scan: { tools: ["context"] },
|
|
63
|
+
tools: { context: finalOptions }
|
|
64
|
+
},
|
|
65
|
+
toolConfigs: { context: finalOptions }
|
|
66
|
+
},
|
|
67
|
+
context: { results }
|
|
68
|
+
},
|
|
69
|
+
options.outputFile
|
|
70
|
+
);
|
|
71
|
+
} else if (options.output === "html") {
|
|
72
|
+
const { generateHTMLReport } = await import("./html-report-BYGKWC3K.mjs");
|
|
73
|
+
const html = generateHTMLReport(summary, results);
|
|
74
|
+
const outputPath = resolveOutputPath(
|
|
75
|
+
directory,
|
|
76
|
+
options.outputFile,
|
|
77
|
+
"context-report.html"
|
|
78
|
+
);
|
|
79
|
+
writeFileSync(outputPath, html, "utf-8");
|
|
80
|
+
console.log(chalk.green(`
|
|
81
|
+
\u2705 HTML report saved to: ${outputPath}`));
|
|
82
|
+
} else {
|
|
83
|
+
const { displayConsoleReport } = await import("./console-report-CVGRMWEU.mjs");
|
|
84
|
+
displayConsoleReport(summary, results, finalOptions.maxResults);
|
|
85
|
+
console.log(chalk.dim(`
|
|
86
|
+
\u2728 Analysis completed in ${duration}ms
|
|
87
|
+
`));
|
|
88
|
+
}
|
|
89
|
+
} catch (error) {
|
|
90
|
+
handleCLIError(error, "context-analyzer");
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
export {
|
|
94
|
+
contextActionHandler
|
|
95
|
+
};
|
package/dist/cli.js
CHANGED
|
@@ -135,6 +135,7 @@ function analyzeIssues(params) {
|
|
|
135
135
|
const {
|
|
136
136
|
file,
|
|
137
137
|
importDepth,
|
|
138
|
+
tokenCost,
|
|
138
139
|
contextBudget,
|
|
139
140
|
cohesionScore,
|
|
140
141
|
fragmentationScore,
|
|
@@ -169,21 +170,29 @@ function analyzeIssues(params) {
|
|
|
169
170
|
recommendations.push("Consider reducing dependency depth");
|
|
170
171
|
potentialSavings += contextBudget * 0.15;
|
|
171
172
|
}
|
|
172
|
-
|
|
173
|
-
|
|
173
|
+
const MAX_FILE_TOKENS = 1e4;
|
|
174
|
+
if (tokenCost > MAX_FILE_TOKENS) {
|
|
175
|
+
if (severity !== import_core2.Severity.Critical) severity = import_core2.Severity.Major;
|
|
174
176
|
issues.push(
|
|
175
|
-
`
|
|
177
|
+
`File is excessively large (${tokenCost.toLocaleString()} tokens)`
|
|
176
178
|
);
|
|
177
179
|
recommendations.push(
|
|
178
|
-
"Split into smaller modules
|
|
180
|
+
"Split file into smaller, single-responsibility modules"
|
|
179
181
|
);
|
|
182
|
+
}
|
|
183
|
+
if (contextBudget > maxContextBudget * 1.5) {
|
|
184
|
+
severity = import_core2.Severity.Critical;
|
|
185
|
+
issues.push(
|
|
186
|
+
`Total context budget ${contextBudget.toLocaleString()} tokens is 50% over limit`
|
|
187
|
+
);
|
|
188
|
+
recommendations.push("Reduce dependency tree width or reduce deep imports");
|
|
180
189
|
potentialSavings += contextBudget * 0.4;
|
|
181
190
|
} else if (contextBudget > maxContextBudget) {
|
|
182
191
|
if (severity !== import_core2.Severity.Critical) severity = import_core2.Severity.Major;
|
|
183
192
|
issues.push(
|
|
184
|
-
`
|
|
193
|
+
`Total context budget ${contextBudget.toLocaleString()} exceeds ${maxContextBudget.toLocaleString()}`
|
|
185
194
|
);
|
|
186
|
-
recommendations.push("
|
|
195
|
+
recommendations.push("Optimize dependency graph and reduce deep imports");
|
|
187
196
|
potentialSavings += contextBudget * 0.2;
|
|
188
197
|
}
|
|
189
198
|
if (cohesionScore < minCohesion * 0.5) {
|
|
@@ -268,19 +277,27 @@ function calculateImportDepthFromEdges(file, edges, visited = /* @__PURE__ */ ne
|
|
|
268
277
|
return maxDepth;
|
|
269
278
|
}
|
|
270
279
|
function getTransitiveDependenciesFromEdges(file, edges, visited = /* @__PURE__ */ new Set()) {
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
)
|
|
280
|
+
const result = /* @__PURE__ */ new Map();
|
|
281
|
+
function dfs(current, depth) {
|
|
282
|
+
if (visited.has(current)) {
|
|
283
|
+
const existingDepth = result.get(current);
|
|
284
|
+
if (existingDepth !== void 0 && depth < existingDepth) {
|
|
285
|
+
result.set(current, depth);
|
|
286
|
+
}
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
visited.add(current);
|
|
290
|
+
if (current !== file) {
|
|
291
|
+
result.set(current, depth);
|
|
292
|
+
}
|
|
293
|
+
const dependencies = edges.get(current);
|
|
294
|
+
if (!dependencies) return;
|
|
295
|
+
for (const dep of dependencies) {
|
|
296
|
+
dfs(dep, depth + 1);
|
|
297
|
+
}
|
|
282
298
|
}
|
|
283
|
-
|
|
299
|
+
dfs(file, 0);
|
|
300
|
+
return result;
|
|
284
301
|
}
|
|
285
302
|
function detectGraphCycles(edges) {
|
|
286
303
|
const cycles = [];
|
|
@@ -605,6 +622,30 @@ var init_ast_utils = __esm({
|
|
|
605
622
|
// src/graph-builder.ts
|
|
606
623
|
function resolveImport(source, importingFile, allFiles) {
|
|
607
624
|
if (!source.startsWith(".") && !source.startsWith("/")) {
|
|
625
|
+
const externalIgnores = [
|
|
626
|
+
"react",
|
|
627
|
+
"next",
|
|
628
|
+
"lucide-react",
|
|
629
|
+
"framer-motion",
|
|
630
|
+
"@aws-sdk",
|
|
631
|
+
"stripe",
|
|
632
|
+
"clsx",
|
|
633
|
+
"tailwind-merge",
|
|
634
|
+
"zod",
|
|
635
|
+
"commander",
|
|
636
|
+
"chalk",
|
|
637
|
+
"fs",
|
|
638
|
+
"path",
|
|
639
|
+
"util",
|
|
640
|
+
"child_process",
|
|
641
|
+
"os",
|
|
642
|
+
"crypto"
|
|
643
|
+
];
|
|
644
|
+
if (externalIgnores.some(
|
|
645
|
+
(pkg) => source === pkg || source.startsWith(`${pkg}/`)
|
|
646
|
+
)) {
|
|
647
|
+
return null;
|
|
648
|
+
}
|
|
608
649
|
if (source.startsWith("@aiready/")) {
|
|
609
650
|
const pkgName = source.split("/")[1];
|
|
610
651
|
const possiblePaths = [
|
|
@@ -683,8 +724,9 @@ async function buildDependencyGraph(files, options) {
|
|
|
683
724
|
const allFilePaths = new Set(files.map((f) => f.file));
|
|
684
725
|
for (const { file, content } of files) {
|
|
685
726
|
const { imports: astImports } = await (0, import_core4.parseFileExports)(content, file);
|
|
686
|
-
const
|
|
687
|
-
const
|
|
727
|
+
const runtimeImports = astImports.filter((i) => !i.isTypeOnly);
|
|
728
|
+
const resolvedImports = runtimeImports.map((i) => resolveImport(i.source, file, allFilePaths)).filter((path) => path !== null);
|
|
729
|
+
const importSources = runtimeImports.map((i) => i.source);
|
|
688
730
|
const exports2 = await extractExportsWithAST(
|
|
689
731
|
content,
|
|
690
732
|
file,
|
|
@@ -737,13 +779,14 @@ function calculateContextBudget(file, graph) {
|
|
|
737
779
|
if (!node) return 0;
|
|
738
780
|
let totalTokens = node.tokenCost;
|
|
739
781
|
const deps = getTransitiveDependencies(file, graph);
|
|
740
|
-
for (const dep of deps) {
|
|
782
|
+
for (const [dep, depth] of deps.entries()) {
|
|
741
783
|
const depNode = graph.nodes.get(dep);
|
|
742
784
|
if (depNode) {
|
|
743
|
-
|
|
785
|
+
const discountFactor = Math.pow(0.8, depth - 1);
|
|
786
|
+
totalTokens += depNode.tokenCost * discountFactor;
|
|
744
787
|
}
|
|
745
788
|
}
|
|
746
|
-
return totalTokens;
|
|
789
|
+
return Math.round(totalTokens);
|
|
747
790
|
}
|
|
748
791
|
function detectCircularDependencies(graph) {
|
|
749
792
|
return detectGraphCycles(graph.edges);
|
|
@@ -1508,6 +1551,7 @@ function mapNodeToResult(node, graph, clusters, allCircularDeps, options) {
|
|
|
1508
1551
|
{
|
|
1509
1552
|
file,
|
|
1510
1553
|
importDepth,
|
|
1554
|
+
tokenCost,
|
|
1511
1555
|
contextBudget,
|
|
1512
1556
|
cohesionScore,
|
|
1513
1557
|
fragmentationScore,
|
|
@@ -1531,8 +1575,8 @@ function mapNodeToResult(node, graph, clusters, allCircularDeps, options) {
|
|
|
1531
1575
|
tokenCost,
|
|
1532
1576
|
linesOfCode: node.linesOfCode,
|
|
1533
1577
|
importDepth,
|
|
1534
|
-
dependencyCount: transitiveDeps.
|
|
1535
|
-
dependencyList: transitiveDeps,
|
|
1578
|
+
dependencyCount: transitiveDeps.size,
|
|
1579
|
+
dependencyList: Array.from(transitiveDeps.keys()),
|
|
1536
1580
|
circularDeps,
|
|
1537
1581
|
cohesionScore,
|
|
1538
1582
|
domains: Array.from(
|
|
@@ -1589,6 +1633,8 @@ async function analyzeContext(options) {
|
|
|
1589
1633
|
const { severity, issues, recommendations, potentialSavings } = analyzeIssues({
|
|
1590
1634
|
file: metric.file,
|
|
1591
1635
|
importDepth: metric.importDepth,
|
|
1636
|
+
tokenCost: metric.contextBudget,
|
|
1637
|
+
// For Python, we use the reported budget as self-cost for now
|
|
1592
1638
|
contextBudget: metric.contextBudget,
|
|
1593
1639
|
cohesionScore: metric.cohesion,
|
|
1594
1640
|
fragmentationScore: 0,
|
|
@@ -1914,8 +1960,8 @@ function generateHTMLReport(summary, results) {
|
|
|
1914
1960
|
{
|
|
1915
1961
|
title: "Context Analysis Report",
|
|
1916
1962
|
packageName: "context-analyzer",
|
|
1917
|
-
packageUrl: "https://github.com/
|
|
1918
|
-
bugUrl: "https://github.com/
|
|
1963
|
+
packageUrl: "https://github.com/getaiready/aiready-context-analyzer",
|
|
1964
|
+
bugUrl: "https://github.com/getaiready/aiready-context-analyzer/issues",
|
|
1919
1965
|
emoji: "\u{1F9E0}"
|
|
1920
1966
|
},
|
|
1921
1967
|
stats,
|
|
@@ -1995,12 +2041,12 @@ function displayConsoleReport(summary, results, maxResults = 10) {
|
|
|
1995
2041
|
console.log(import_chalk2.default.cyan(divider));
|
|
1996
2042
|
console.log(
|
|
1997
2043
|
import_chalk2.default.dim(
|
|
1998
|
-
"\n\u2B50 Like aiready? Star us on GitHub: https://github.com/
|
|
2044
|
+
"\n\u2B50 Like aiready? Star us on GitHub: https://github.com/getaiready/aiready-context-analyzer"
|
|
1999
2045
|
)
|
|
2000
2046
|
);
|
|
2001
2047
|
console.log(
|
|
2002
2048
|
import_chalk2.default.dim(
|
|
2003
|
-
"\u{1F41B} Found a bug? Report it: https://github.com/
|
|
2049
|
+
"\u{1F41B} Found a bug? Report it: https://github.com/getaiready/aiready-context-analyzer/issues\n"
|
|
2004
2050
|
)
|
|
2005
2051
|
);
|
|
2006
2052
|
}
|
|
@@ -2022,7 +2068,7 @@ async function contextActionHandler(directory, options) {
|
|
|
2022
2068
|
const startTime = Date.now();
|
|
2023
2069
|
try {
|
|
2024
2070
|
const defaults = {
|
|
2025
|
-
maxDepth:
|
|
2071
|
+
maxDepth: 10,
|
|
2026
2072
|
maxContextBudget: 1e4,
|
|
2027
2073
|
minCohesion: 0.6,
|
|
2028
2074
|
maxFragmentation: 0.5,
|
|
@@ -2047,7 +2093,9 @@ async function contextActionHandler(directory, options) {
|
|
|
2047
2093
|
const { runInteractiveSetup: runInteractiveSetup2 } = await Promise.resolve().then(() => (init_interactive_setup(), interactive_setup_exports));
|
|
2048
2094
|
finalOptions = await runInteractiveSetup2(directory, finalOptions);
|
|
2049
2095
|
}
|
|
2050
|
-
const results = await analyzeContext(
|
|
2096
|
+
const results = await analyzeContext(
|
|
2097
|
+
finalOptions
|
|
2098
|
+
);
|
|
2051
2099
|
const summary = generateSummary(results, finalOptions);
|
|
2052
2100
|
const duration = (0, import_core9.getElapsedTime)(startTime);
|
|
2053
2101
|
if (options.output === "json") {
|
package/dist/cli.mjs
CHANGED
|
@@ -37,7 +37,7 @@ function defineContextCommand(program2) {
|
|
|
37
37
|
"--interactive",
|
|
38
38
|
"Run interactive setup to suggest excludes and focus areas"
|
|
39
39
|
).action(async (directory, options) => {
|
|
40
|
-
const { contextActionHandler } = await import("./cli-action-
|
|
40
|
+
const { contextActionHandler } = await import("./cli-action-7QXG7LHS.mjs");
|
|
41
41
|
await contextActionHandler(directory, options);
|
|
42
42
|
});
|
|
43
43
|
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
// src/report/console-report.ts
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
function displayConsoleReport(summary, results, maxResults = 10) {
|
|
4
|
+
const divider = "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500";
|
|
5
|
+
const totalIssues = summary.criticalIssues + summary.majorIssues + summary.minorIssues;
|
|
6
|
+
console.log(chalk.bold("\u{1F4CA} Context Analysis Summary:\n"));
|
|
7
|
+
console.log(` \u2022 Total Files: ${chalk.cyan(summary.totalFiles)}`);
|
|
8
|
+
console.log(
|
|
9
|
+
` \u2022 Total Tokens: ${chalk.cyan(summary.totalTokens.toLocaleString())}`
|
|
10
|
+
);
|
|
11
|
+
console.log(
|
|
12
|
+
` \u2022 Avg Budget: ${chalk.cyan(summary.avgContextBudget.toFixed(0))} tokens`
|
|
13
|
+
);
|
|
14
|
+
console.log(
|
|
15
|
+
` \u2022 Potential Saving: ${chalk.green(summary.totalPotentialSavings.toLocaleString())} tokens`
|
|
16
|
+
);
|
|
17
|
+
console.log();
|
|
18
|
+
if (totalIssues > 0) {
|
|
19
|
+
console.log(chalk.bold("\u26A0\uFE0F Issues Detected:\n"));
|
|
20
|
+
console.log(` \u2022 ${chalk.red("\u{1F534} Critical:")} ${summary.criticalIssues}`);
|
|
21
|
+
console.log(` \u2022 ${chalk.yellow("\u{1F7E1} Major:")} ${summary.majorIssues}`);
|
|
22
|
+
console.log(` \u2022 ${chalk.blue("\u{1F535} Minor:")} ${summary.minorIssues}`);
|
|
23
|
+
console.log();
|
|
24
|
+
} else {
|
|
25
|
+
console.log(chalk.green("\u2705 No significant context issues detected!\n"));
|
|
26
|
+
}
|
|
27
|
+
if (summary.fragmentedModules.length > 0) {
|
|
28
|
+
console.log(chalk.bold("\u{1F9E9} Top Fragmented Modules:\n"));
|
|
29
|
+
summary.fragmentedModules.slice(0, maxResults).forEach((mod) => {
|
|
30
|
+
const scoreColor = mod.fragmentationScore > 0.7 ? chalk.red : mod.fragmentationScore > 0.4 ? chalk.yellow : chalk.green;
|
|
31
|
+
console.log(
|
|
32
|
+
` ${scoreColor("\u25A0")} ${chalk.white(mod.domain)} ${chalk.dim(`(${mod.files.length} files, ${(mod.fragmentationScore * 100).toFixed(0)}% frag)`)}`
|
|
33
|
+
);
|
|
34
|
+
});
|
|
35
|
+
console.log();
|
|
36
|
+
}
|
|
37
|
+
if (summary.topExpensiveFiles.length > 0) {
|
|
38
|
+
console.log(chalk.bold("\u{1F4B8} Most Expensive Files (Context Budget):\n"));
|
|
39
|
+
summary.topExpensiveFiles.slice(0, maxResults).forEach((item) => {
|
|
40
|
+
const fileName = item.file.split("/").slice(-2).join("/");
|
|
41
|
+
const severityColor = item.severity === "critical" ? chalk.red : item.severity === "major" ? chalk.yellow : chalk.blue;
|
|
42
|
+
console.log(
|
|
43
|
+
` ${severityColor("\u25CF")} ${chalk.white(fileName)} ${chalk.dim(`- ${item.contextBudget.toLocaleString()} tokens`)}`
|
|
44
|
+
);
|
|
45
|
+
});
|
|
46
|
+
console.log();
|
|
47
|
+
}
|
|
48
|
+
if (totalIssues > 0) {
|
|
49
|
+
console.log(chalk.bold("\u{1F4A1} Top Recommendations:\n"));
|
|
50
|
+
const topFiles = results.filter((r) => r.severity === "critical" || r.severity === "major").slice(0, 3);
|
|
51
|
+
topFiles.forEach((result, index) => {
|
|
52
|
+
const fileName = result.file.split("/").slice(-2).join("/");
|
|
53
|
+
console.log(chalk.cyan(` ${index + 1}. ${fileName}`));
|
|
54
|
+
result.recommendations.slice(0, 2).forEach((rec) => {
|
|
55
|
+
console.log(chalk.dim(` \u2022 ${rec}`));
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
console.log();
|
|
59
|
+
}
|
|
60
|
+
console.log(chalk.cyan(divider));
|
|
61
|
+
console.log(
|
|
62
|
+
chalk.dim(
|
|
63
|
+
"\n\u2B50 Like aiready? Star us on GitHub: https://github.com/getaiready/aiready-context-analyzer"
|
|
64
|
+
)
|
|
65
|
+
);
|
|
66
|
+
console.log(
|
|
67
|
+
chalk.dim(
|
|
68
|
+
"\u{1F41B} Found a bug? Report it: https://github.com/getaiready/aiready-context-analyzer/issues\n"
|
|
69
|
+
)
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
export {
|
|
73
|
+
displayConsoleReport
|
|
74
|
+
};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
// src/report/html-report.ts
|
|
2
|
+
import {
|
|
3
|
+
generateIssueSummary,
|
|
4
|
+
generateTable,
|
|
5
|
+
generateStandardHtmlReport
|
|
6
|
+
} from "@aiready/core";
|
|
7
|
+
function generateHTMLReport(summary, results) {
|
|
8
|
+
const totalIssues = summary.criticalIssues + summary.majorIssues + summary.minorIssues;
|
|
9
|
+
void results;
|
|
10
|
+
const stats = [
|
|
11
|
+
{ value: summary.totalFiles, label: "Files Analyzed" },
|
|
12
|
+
{ value: summary.totalTokens.toLocaleString(), label: "Total Tokens" },
|
|
13
|
+
{ value: summary.avgContextBudget.toFixed(0), label: "Avg Context Budget" },
|
|
14
|
+
{
|
|
15
|
+
value: totalIssues,
|
|
16
|
+
label: "Total Issues",
|
|
17
|
+
color: totalIssues > 0 ? "#f39c12" : void 0
|
|
18
|
+
}
|
|
19
|
+
];
|
|
20
|
+
const sections = [];
|
|
21
|
+
if (totalIssues > 0) {
|
|
22
|
+
sections.push({
|
|
23
|
+
title: "\u26A0\uFE0F Issues Summary",
|
|
24
|
+
content: generateIssueSummary(
|
|
25
|
+
summary.criticalIssues,
|
|
26
|
+
summary.majorIssues,
|
|
27
|
+
summary.minorIssues,
|
|
28
|
+
summary.totalPotentialSavings
|
|
29
|
+
)
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
if (summary.fragmentedModules.length > 0) {
|
|
33
|
+
sections.push({
|
|
34
|
+
title: "\u{1F9E9} Fragmented Modules",
|
|
35
|
+
content: generateTable({
|
|
36
|
+
headers: ["Domain", "Files", "Fragmentation", "Token Cost"],
|
|
37
|
+
rows: summary.fragmentedModules.map((m) => [
|
|
38
|
+
m.domain,
|
|
39
|
+
String(m.files.length),
|
|
40
|
+
`${(m.fragmentationScore * 100).toFixed(0)}%`,
|
|
41
|
+
m.totalTokens.toLocaleString()
|
|
42
|
+
])
|
|
43
|
+
})
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
if (summary.topExpensiveFiles.length > 0) {
|
|
47
|
+
sections.push({
|
|
48
|
+
title: "\u{1F4B8} Most Expensive Files",
|
|
49
|
+
content: generateTable({
|
|
50
|
+
headers: ["File", "Context Budget", "Severity"],
|
|
51
|
+
rows: summary.topExpensiveFiles.map((f) => [
|
|
52
|
+
f.file,
|
|
53
|
+
`${f.contextBudget.toLocaleString()} tokens`,
|
|
54
|
+
`<span class="issue-${f.severity}">${f.severity.toUpperCase()}</span>`
|
|
55
|
+
])
|
|
56
|
+
})
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
return generateStandardHtmlReport(
|
|
60
|
+
{
|
|
61
|
+
title: "Context Analysis Report",
|
|
62
|
+
packageName: "context-analyzer",
|
|
63
|
+
packageUrl: "https://github.com/getaiready/aiready-context-analyzer",
|
|
64
|
+
bugUrl: "https://github.com/getaiready/aiready-context-analyzer/issues",
|
|
65
|
+
emoji: "\u{1F9E0}"
|
|
66
|
+
},
|
|
67
|
+
stats,
|
|
68
|
+
sections
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
export {
|
|
72
|
+
generateHTMLReport
|
|
73
|
+
};
|
package/dist/index.d.mts
CHANGED
|
@@ -23,6 +23,8 @@ interface ContextAnalyzerOptions extends ScanOptions {
|
|
|
23
23
|
focus?: 'fragmentation' | 'cohesion' | 'depth' | 'all';
|
|
24
24
|
/** Whether to include node_modules in the analysis (default: false) */
|
|
25
25
|
includeNodeModules?: boolean;
|
|
26
|
+
/** Maximum number of results to display in console output (default: 10) */
|
|
27
|
+
maxResults?: number;
|
|
26
28
|
}
|
|
27
29
|
/**
|
|
28
30
|
* The result of a context analysis for a single file or module.
|
|
@@ -286,13 +288,13 @@ declare function calculateImportDepth(file: string, graph: DependencyGraph, visi
|
|
|
286
288
|
* @param visited - Optional set to track visited nodes.
|
|
287
289
|
* @returns Array of all reachable file paths.
|
|
288
290
|
*/
|
|
289
|
-
declare function getTransitiveDependencies(file: string, graph: DependencyGraph, visited?: Set<string>): string
|
|
291
|
+
declare function getTransitiveDependencies(file: string, graph: DependencyGraph, visited?: Set<string>): Map<string, number>;
|
|
290
292
|
/**
|
|
291
293
|
* Calculate total context budget (tokens needed to understand this file and its dependencies).
|
|
292
294
|
*
|
|
293
295
|
* @param file - File path to calculate budget for.
|
|
294
296
|
* @param graph - The dependency graph.
|
|
295
|
-
* @returns Total token count including recursive dependencies.
|
|
297
|
+
* @returns Total token count including recursive dependencies (discounted by depth).
|
|
296
298
|
*/
|
|
297
299
|
declare function calculateContextBudget(file: string, graph: DependencyGraph): number;
|
|
298
300
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -23,6 +23,8 @@ interface ContextAnalyzerOptions extends ScanOptions {
|
|
|
23
23
|
focus?: 'fragmentation' | 'cohesion' | 'depth' | 'all';
|
|
24
24
|
/** Whether to include node_modules in the analysis (default: false) */
|
|
25
25
|
includeNodeModules?: boolean;
|
|
26
|
+
/** Maximum number of results to display in console output (default: 10) */
|
|
27
|
+
maxResults?: number;
|
|
26
28
|
}
|
|
27
29
|
/**
|
|
28
30
|
* The result of a context analysis for a single file or module.
|
|
@@ -286,13 +288,13 @@ declare function calculateImportDepth(file: string, graph: DependencyGraph, visi
|
|
|
286
288
|
* @param visited - Optional set to track visited nodes.
|
|
287
289
|
* @returns Array of all reachable file paths.
|
|
288
290
|
*/
|
|
289
|
-
declare function getTransitiveDependencies(file: string, graph: DependencyGraph, visited?: Set<string>): string
|
|
291
|
+
declare function getTransitiveDependencies(file: string, graph: DependencyGraph, visited?: Set<string>): Map<string, number>;
|
|
290
292
|
/**
|
|
291
293
|
* Calculate total context budget (tokens needed to understand this file and its dependencies).
|
|
292
294
|
*
|
|
293
295
|
* @param file - File path to calculate budget for.
|
|
294
296
|
* @param graph - The dependency graph.
|
|
295
|
-
* @returns Total token count including recursive dependencies.
|
|
297
|
+
* @returns Total token count including recursive dependencies (discounted by depth).
|
|
296
298
|
*/
|
|
297
299
|
declare function calculateContextBudget(file: string, graph: DependencyGraph): number;
|
|
298
300
|
/**
|