@aiready/context-analyzer 0.17.5 → 0.19.1
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 +11 -11
- package/.turbo/turbo-lint.log +22 -2
- package/.turbo/turbo-test.log +21 -18
- package/dist/chunk-474DEGWW.mjs +1792 -0
- package/dist/chunk-IPIE5TXJ.mjs +1741 -0
- package/dist/chunk-Q2GDZ2FZ.mjs +1794 -0
- package/dist/chunk-S6OPP4L5.mjs +1791 -0
- package/dist/cli.js +190 -35
- package/dist/cli.mjs +1 -1
- package/dist/index.d.mts +7 -2
- package/dist/index.d.ts +7 -2
- package/dist/index.js +64 -30
- package/dist/index.mjs +3 -1
- package/package.json +2 -2
- package/src/index.ts +6 -1
- package/src/metrics.ts +13 -23
- package/src/provider.ts +65 -0
- package/src/scoring.ts +2 -1
package/dist/cli.js
CHANGED
|
@@ -37,7 +37,7 @@ __export(python_context_exports, {
|
|
|
37
37
|
});
|
|
38
38
|
async function analyzePythonContext(files, rootDir) {
|
|
39
39
|
const results = [];
|
|
40
|
-
const parser = (0,
|
|
40
|
+
const parser = (0, import_core8.getParser)("dummy.py");
|
|
41
41
|
if (!parser) {
|
|
42
42
|
console.warn("Python parser not available");
|
|
43
43
|
return results;
|
|
@@ -101,7 +101,7 @@ async function analyzePythonContext(files, rootDir) {
|
|
|
101
101
|
}
|
|
102
102
|
async function buildPythonDependencyGraph(files, rootDir) {
|
|
103
103
|
const graph = /* @__PURE__ */ new Map();
|
|
104
|
-
const parser = (0,
|
|
104
|
+
const parser = (0, import_core8.getParser)("dummy.py");
|
|
105
105
|
if (!parser) return graph;
|
|
106
106
|
for (const file of files) {
|
|
107
107
|
try {
|
|
@@ -181,7 +181,7 @@ async function calculatePythonImportDepth(file, dependencyGraph, visited, depth
|
|
|
181
181
|
}
|
|
182
182
|
function estimateContextBudget(code, imports, dependencyGraph) {
|
|
183
183
|
void dependencyGraph;
|
|
184
|
-
let budget = (0,
|
|
184
|
+
let budget = (0, import_core8.estimateTokens)(code);
|
|
185
185
|
const avgTokensPerDep = 500;
|
|
186
186
|
budget += imports.length * avgTokensPerDep;
|
|
187
187
|
return budget;
|
|
@@ -231,11 +231,11 @@ function detectCircularDependencies2(file, dependencyGraph) {
|
|
|
231
231
|
dfs(file, []);
|
|
232
232
|
return [...new Set(circular)];
|
|
233
233
|
}
|
|
234
|
-
var
|
|
234
|
+
var import_core8, import_path, import_fs;
|
|
235
235
|
var init_python_context = __esm({
|
|
236
236
|
"src/analyzers/python-context.ts"() {
|
|
237
237
|
"use strict";
|
|
238
|
-
|
|
238
|
+
import_core8 = require("@aiready/core");
|
|
239
239
|
import_path = require("path");
|
|
240
240
|
import_fs = __toESM(require("fs"));
|
|
241
241
|
}
|
|
@@ -245,7 +245,7 @@ var init_python_context = __esm({
|
|
|
245
245
|
var import_commander = require("commander");
|
|
246
246
|
|
|
247
247
|
// src/index.ts
|
|
248
|
-
var
|
|
248
|
+
var import_core9 = require("@aiready/core");
|
|
249
249
|
|
|
250
250
|
// src/analyzer.ts
|
|
251
251
|
var import_core4 = require("@aiready/core");
|
|
@@ -537,12 +537,9 @@ function calculateEnhancedCohesion(exports2, filePath, options) {
|
|
|
537
537
|
}
|
|
538
538
|
}
|
|
539
539
|
const avgImportScore = pairsWithData > 0 ? importScoreTotal / pairsWithData : 0;
|
|
540
|
-
let score = 0;
|
|
541
|
-
if (anyImportData) {
|
|
542
|
-
score =
|
|
543
|
-
if (score === 0 && domainScore === 0) score = 0.1;
|
|
544
|
-
} else {
|
|
545
|
-
score = domainScore;
|
|
540
|
+
let score = anyImportData ? domainScore * 0.4 + avgImportScore * 0.6 : domainScore;
|
|
541
|
+
if (anyImportData && score === 0 && domainScore === 0) {
|
|
542
|
+
score = 0.1;
|
|
546
543
|
}
|
|
547
544
|
let structuralScore = 0;
|
|
548
545
|
for (const exp of exports2) {
|
|
@@ -562,19 +559,7 @@ function calculateFragmentation(files, domain, options) {
|
|
|
562
559
|
files.map((f) => f.split("/").slice(0, -1).join("/"))
|
|
563
560
|
);
|
|
564
561
|
const uniqueDirs = directories.size;
|
|
565
|
-
let score = 0;
|
|
566
|
-
if (options?.useLogScale) {
|
|
567
|
-
if (uniqueDirs <= 1) score = 0;
|
|
568
|
-
else {
|
|
569
|
-
const total = files.length;
|
|
570
|
-
const base = options.logBase || Math.E;
|
|
571
|
-
const num = Math.log(uniqueDirs) / Math.log(base);
|
|
572
|
-
const den = Math.log(total) / Math.log(base);
|
|
573
|
-
score = den > 0 ? num / den : 0;
|
|
574
|
-
}
|
|
575
|
-
} else {
|
|
576
|
-
score = (uniqueDirs - 1) / (files.length - 1);
|
|
577
|
-
}
|
|
562
|
+
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);
|
|
578
563
|
if (options?.sharedImportRatio && options.sharedImportRatio > 0.5) {
|
|
579
564
|
const discount = (options.sharedImportRatio - 0.5) * 0.4;
|
|
580
565
|
score = score * (1 - discount);
|
|
@@ -1344,11 +1329,180 @@ function isBuildArtifact(filePath) {
|
|
|
1344
1329
|
return lower.includes("/node_modules/") || lower.includes("/dist/") || lower.includes("/build/") || lower.includes("/out/") || lower.includes("/.next/");
|
|
1345
1330
|
}
|
|
1346
1331
|
|
|
1332
|
+
// src/provider.ts
|
|
1333
|
+
var import_core6 = require("@aiready/core");
|
|
1334
|
+
|
|
1347
1335
|
// src/scoring.ts
|
|
1348
1336
|
var import_core5 = require("@aiready/core");
|
|
1337
|
+
function calculateContextScore(summary, costConfig) {
|
|
1338
|
+
const {
|
|
1339
|
+
avgContextBudget,
|
|
1340
|
+
maxContextBudget,
|
|
1341
|
+
avgImportDepth,
|
|
1342
|
+
maxImportDepth,
|
|
1343
|
+
avgFragmentation,
|
|
1344
|
+
criticalIssues,
|
|
1345
|
+
majorIssues
|
|
1346
|
+
} = summary;
|
|
1347
|
+
const budgetScore = avgContextBudget < 5e3 ? 100 : Math.max(0, 100 - (avgContextBudget - 5e3) / 150);
|
|
1348
|
+
const depthScore = avgImportDepth < 5 ? 100 : Math.max(0, 100 - (avgImportDepth - 5) * 10);
|
|
1349
|
+
const fragmentationScore = avgFragmentation < 0.3 ? 100 : Math.max(0, 100 - (avgFragmentation - 0.3) * 200);
|
|
1350
|
+
const criticalPenalty = criticalIssues * 10;
|
|
1351
|
+
const majorPenalty = majorIssues * 3;
|
|
1352
|
+
const maxBudgetPenalty = maxContextBudget > 15e3 ? Math.min(20, (maxContextBudget - 15e3) / 500) : 0;
|
|
1353
|
+
const rawScore = budgetScore * 0.4 + depthScore * 0.3 + fragmentationScore * 0.3;
|
|
1354
|
+
const finalScore = rawScore - criticalPenalty - majorPenalty - maxBudgetPenalty;
|
|
1355
|
+
const score = Math.max(0, Math.min(100, Math.round(finalScore)));
|
|
1356
|
+
const factors = [
|
|
1357
|
+
{
|
|
1358
|
+
name: "Context Budget",
|
|
1359
|
+
impact: Math.round(budgetScore * 0.4 - 40),
|
|
1360
|
+
description: `Avg ${Math.round(avgContextBudget)} tokens per file ${avgContextBudget < 5e3 ? "(excellent)" : avgContextBudget < 1e4 ? "(acceptable)" : "(high)"}`
|
|
1361
|
+
},
|
|
1362
|
+
{
|
|
1363
|
+
name: "Import Depth",
|
|
1364
|
+
impact: Math.round(depthScore * 0.3 - 30),
|
|
1365
|
+
description: `Avg ${avgImportDepth.toFixed(1)} levels ${avgImportDepth < 5 ? "(excellent)" : avgImportDepth < 8 ? "(acceptable)" : "(deep)"}`
|
|
1366
|
+
},
|
|
1367
|
+
{
|
|
1368
|
+
name: "Fragmentation",
|
|
1369
|
+
impact: Math.round(fragmentationScore * 0.3 - 30),
|
|
1370
|
+
description: `${(avgFragmentation * 100).toFixed(0)}% fragmentation ${avgFragmentation < 0.3 ? "(well-organized)" : avgFragmentation < 0.5 ? "(moderate)" : "(high)"}`
|
|
1371
|
+
}
|
|
1372
|
+
];
|
|
1373
|
+
if (criticalIssues > 0) {
|
|
1374
|
+
factors.push({
|
|
1375
|
+
name: "Critical Issues",
|
|
1376
|
+
impact: -criticalPenalty,
|
|
1377
|
+
description: `${criticalIssues} critical context issue${criticalIssues > 1 ? "s" : ""}`
|
|
1378
|
+
});
|
|
1379
|
+
}
|
|
1380
|
+
if (majorIssues > 0) {
|
|
1381
|
+
factors.push({
|
|
1382
|
+
name: "Major Issues",
|
|
1383
|
+
impact: -majorPenalty,
|
|
1384
|
+
description: `${majorIssues} major context issue${majorIssues > 1 ? "s" : ""}`
|
|
1385
|
+
});
|
|
1386
|
+
}
|
|
1387
|
+
if (maxBudgetPenalty > 0) {
|
|
1388
|
+
factors.push({
|
|
1389
|
+
name: "Extreme File Detected",
|
|
1390
|
+
impact: -Math.round(maxBudgetPenalty),
|
|
1391
|
+
description: `One file requires ${Math.round(maxContextBudget)} tokens (very high)`
|
|
1392
|
+
});
|
|
1393
|
+
}
|
|
1394
|
+
const recommendations = [];
|
|
1395
|
+
if (avgContextBudget > 1e4) {
|
|
1396
|
+
const estimatedImpact = Math.min(
|
|
1397
|
+
15,
|
|
1398
|
+
Math.round((avgContextBudget - 1e4) / 1e3)
|
|
1399
|
+
);
|
|
1400
|
+
recommendations.push({
|
|
1401
|
+
action: "Reduce file dependencies to lower context requirements",
|
|
1402
|
+
estimatedImpact,
|
|
1403
|
+
priority: "high"
|
|
1404
|
+
});
|
|
1405
|
+
}
|
|
1406
|
+
if (avgImportDepth > 8) {
|
|
1407
|
+
const estimatedImpact = Math.min(10, Math.round((avgImportDepth - 8) * 2));
|
|
1408
|
+
recommendations.push({
|
|
1409
|
+
action: "Flatten import chains to reduce depth",
|
|
1410
|
+
estimatedImpact,
|
|
1411
|
+
priority: avgImportDepth > 10 ? "high" : "medium"
|
|
1412
|
+
});
|
|
1413
|
+
}
|
|
1414
|
+
if (avgFragmentation > 0.5) {
|
|
1415
|
+
const estimatedImpact = Math.min(
|
|
1416
|
+
12,
|
|
1417
|
+
Math.round((avgFragmentation - 0.5) * 40)
|
|
1418
|
+
);
|
|
1419
|
+
recommendations.push({
|
|
1420
|
+
action: "Consolidate related code into cohesive modules",
|
|
1421
|
+
estimatedImpact,
|
|
1422
|
+
priority: "medium"
|
|
1423
|
+
});
|
|
1424
|
+
}
|
|
1425
|
+
if (maxContextBudget > 2e4) {
|
|
1426
|
+
recommendations.push({
|
|
1427
|
+
action: `Split large file (${Math.round(maxContextBudget)} tokens) into smaller modules`,
|
|
1428
|
+
estimatedImpact: 8,
|
|
1429
|
+
priority: "high"
|
|
1430
|
+
});
|
|
1431
|
+
}
|
|
1432
|
+
const cfg = { ...import_core5.DEFAULT_COST_CONFIG, ...costConfig };
|
|
1433
|
+
const estimatedMonthlyCost = (0, import_core5.calculateMonthlyCost)(
|
|
1434
|
+
avgContextBudget * (summary.totalFiles || 1),
|
|
1435
|
+
cfg
|
|
1436
|
+
);
|
|
1437
|
+
const issues = [
|
|
1438
|
+
...Array(criticalIssues).fill({ severity: "critical" }),
|
|
1439
|
+
...Array(majorIssues).fill({ severity: "major" })
|
|
1440
|
+
];
|
|
1441
|
+
const productivityImpact = (0, import_core5.calculateProductivityImpact)(issues);
|
|
1442
|
+
return {
|
|
1443
|
+
toolName: import_core5.ToolName.ContextAnalyzer,
|
|
1444
|
+
score,
|
|
1445
|
+
rawMetrics: {
|
|
1446
|
+
avgContextBudget: Math.round(avgContextBudget),
|
|
1447
|
+
maxContextBudget: Math.round(maxContextBudget),
|
|
1448
|
+
avgImportDepth: Math.round(avgImportDepth * 10) / 10,
|
|
1449
|
+
maxImportDepth,
|
|
1450
|
+
avgFragmentation: Math.round(avgFragmentation * 100) / 100,
|
|
1451
|
+
criticalIssues,
|
|
1452
|
+
majorIssues,
|
|
1453
|
+
estimatedMonthlyCost,
|
|
1454
|
+
estimatedDeveloperHours: productivityImpact.totalHours
|
|
1455
|
+
},
|
|
1456
|
+
factors,
|
|
1457
|
+
recommendations
|
|
1458
|
+
};
|
|
1459
|
+
}
|
|
1460
|
+
|
|
1461
|
+
// src/provider.ts
|
|
1462
|
+
var ContextAnalyzerProvider = {
|
|
1463
|
+
id: import_core6.ToolName.ContextAnalyzer,
|
|
1464
|
+
alias: ["context", "fragmentation", "budget"],
|
|
1465
|
+
async analyze(options) {
|
|
1466
|
+
const results = await analyzeContext(options);
|
|
1467
|
+
const summary = generateSummary(results);
|
|
1468
|
+
const normalizedResults = results.map(
|
|
1469
|
+
(r) => ({
|
|
1470
|
+
fileName: r.file,
|
|
1471
|
+
issues: r.issues.map((msg) => ({
|
|
1472
|
+
type: import_core6.IssueType.ContextFragmentation,
|
|
1473
|
+
severity: r.severity,
|
|
1474
|
+
message: msg,
|
|
1475
|
+
location: { file: r.file, line: 1 },
|
|
1476
|
+
suggestion: r.recommendations[0]
|
|
1477
|
+
})),
|
|
1478
|
+
metrics: {
|
|
1479
|
+
tokenCost: r.tokenCost,
|
|
1480
|
+
complexityScore: r.importDepth
|
|
1481
|
+
// Map other context-specific metrics if needed
|
|
1482
|
+
}
|
|
1483
|
+
})
|
|
1484
|
+
);
|
|
1485
|
+
return import_core6.SpokeOutputSchema.parse({
|
|
1486
|
+
results: normalizedResults,
|
|
1487
|
+
summary: {
|
|
1488
|
+
...summary
|
|
1489
|
+
},
|
|
1490
|
+
metadata: {
|
|
1491
|
+
toolName: import_core6.ToolName.ContextAnalyzer,
|
|
1492
|
+
version: "0.17.5",
|
|
1493
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1494
|
+
}
|
|
1495
|
+
});
|
|
1496
|
+
},
|
|
1497
|
+
score(output, options) {
|
|
1498
|
+
const summary = output.summary;
|
|
1499
|
+
return calculateContextScore(summary, options.costConfig);
|
|
1500
|
+
},
|
|
1501
|
+
defaultWeight: 19
|
|
1502
|
+
};
|
|
1349
1503
|
|
|
1350
1504
|
// src/defaults.ts
|
|
1351
|
-
var
|
|
1505
|
+
var import_core7 = require("@aiready/core");
|
|
1352
1506
|
|
|
1353
1507
|
// src/summary.ts
|
|
1354
1508
|
function generateSummary(results) {
|
|
@@ -1478,6 +1632,7 @@ function generateSummary(results) {
|
|
|
1478
1632
|
}
|
|
1479
1633
|
|
|
1480
1634
|
// src/index.ts
|
|
1635
|
+
import_core9.ToolRegistry.register(ContextAnalyzerProvider);
|
|
1481
1636
|
async function analyzeContext(options) {
|
|
1482
1637
|
const {
|
|
1483
1638
|
maxDepth = 5,
|
|
@@ -1488,7 +1643,7 @@ async function analyzeContext(options) {
|
|
|
1488
1643
|
includeNodeModules = false,
|
|
1489
1644
|
...scanOptions
|
|
1490
1645
|
} = options;
|
|
1491
|
-
const files = await (0,
|
|
1646
|
+
const files = await (0, import_core9.scanFiles)({
|
|
1492
1647
|
...scanOptions,
|
|
1493
1648
|
exclude: includeNodeModules && scanOptions.exclude ? scanOptions.exclude.filter(
|
|
1494
1649
|
(pattern) => pattern !== "**/node_modules/**"
|
|
@@ -1498,7 +1653,7 @@ async function analyzeContext(options) {
|
|
|
1498
1653
|
const fileContents = await Promise.all(
|
|
1499
1654
|
files.map(async (file) => ({
|
|
1500
1655
|
file,
|
|
1501
|
-
content: await (0,
|
|
1656
|
+
content: await (0, import_core9.readFileContent)(file)
|
|
1502
1657
|
}))
|
|
1503
1658
|
);
|
|
1504
1659
|
const graph = buildDependencyGraph(
|
|
@@ -1665,7 +1820,7 @@ async function analyzeContext(options) {
|
|
|
1665
1820
|
var import_chalk = __toESM(require("chalk"));
|
|
1666
1821
|
var import_fs2 = require("fs");
|
|
1667
1822
|
var import_path2 = require("path");
|
|
1668
|
-
var
|
|
1823
|
+
var import_core10 = require("@aiready/core");
|
|
1669
1824
|
var import_prompts = __toESM(require("prompts"));
|
|
1670
1825
|
var program = new import_commander.Command();
|
|
1671
1826
|
program.name("aiready-context").description("Analyze AI context window cost and code structure").version("0.1.0").addHelpText(
|
|
@@ -1705,7 +1860,7 @@ program.name("aiready-context").description("Analyze AI context window cost and
|
|
|
1705
1860
|
exclude: void 0,
|
|
1706
1861
|
maxResults: 10
|
|
1707
1862
|
};
|
|
1708
|
-
let finalOptions = await (0,
|
|
1863
|
+
let finalOptions = await (0, import_core10.loadMergedConfig)(directory, defaults, {
|
|
1709
1864
|
maxDepth: options.maxDepth ? parseInt(options.maxDepth) : void 0,
|
|
1710
1865
|
maxContextBudget: options.maxContext ? parseInt(options.maxContext) : void 0,
|
|
1711
1866
|
minCohesion: options.minCohesion ? parseFloat(options.minCohesion) : void 0,
|
|
@@ -1720,7 +1875,7 @@ program.name("aiready-context").description("Analyze AI context window cost and
|
|
|
1720
1875
|
finalOptions = await runInteractiveSetup(directory, finalOptions);
|
|
1721
1876
|
}
|
|
1722
1877
|
const results = await analyzeContext(finalOptions);
|
|
1723
|
-
const elapsedTime = (0,
|
|
1878
|
+
const elapsedTime = (0, import_core10.getElapsedTime)(startTime);
|
|
1724
1879
|
const summary = generateSummary(results);
|
|
1725
1880
|
if (options.output === "json") {
|
|
1726
1881
|
const jsonOutput = {
|
|
@@ -1729,12 +1884,12 @@ program.name("aiready-context").description("Analyze AI context window cost and
|
|
|
1729
1884
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1730
1885
|
analysisTime: elapsedTime
|
|
1731
1886
|
};
|
|
1732
|
-
const outputPath = (0,
|
|
1887
|
+
const outputPath = (0, import_core10.resolveOutputPath)(
|
|
1733
1888
|
options.outputFile,
|
|
1734
1889
|
`context-report-${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}.json`,
|
|
1735
1890
|
directory
|
|
1736
1891
|
);
|
|
1737
|
-
(0,
|
|
1892
|
+
(0, import_core10.handleJSONOutput)(
|
|
1738
1893
|
jsonOutput,
|
|
1739
1894
|
outputPath,
|
|
1740
1895
|
`
|
|
@@ -1744,7 +1899,7 @@ program.name("aiready-context").description("Analyze AI context window cost and
|
|
|
1744
1899
|
}
|
|
1745
1900
|
if (options.output === "html") {
|
|
1746
1901
|
const html = generateHTMLReport(summary, results);
|
|
1747
|
-
const outputPath = (0,
|
|
1902
|
+
const outputPath = (0, import_core10.resolveOutputPath)(
|
|
1748
1903
|
options.outputFile,
|
|
1749
1904
|
`context-report-${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}.html`,
|
|
1750
1905
|
directory
|
|
@@ -1766,7 +1921,7 @@ program.name("aiready-context").description("Analyze AI context window cost and
|
|
|
1766
1921
|
);
|
|
1767
1922
|
displayTuningGuidance(results, finalOptions);
|
|
1768
1923
|
} catch (error) {
|
|
1769
|
-
(0,
|
|
1924
|
+
(0, import_core10.handleCLIError)(error, "Analysis");
|
|
1770
1925
|
}
|
|
1771
1926
|
});
|
|
1772
1927
|
program.parse();
|
package/dist/cli.mjs
CHANGED
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import { Severity, ScanOptions, CostConfig, ToolScoringOutput } from '@aiready/core';
|
|
1
|
+
import { ToolProvider, Severity, ScanOptions, CostConfig, ToolScoringOutput } from '@aiready/core';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Context Analyzer Tool Provider
|
|
5
|
+
*/
|
|
6
|
+
declare const ContextAnalyzerProvider: ToolProvider;
|
|
2
7
|
|
|
3
8
|
interface ContextAnalyzerOptions extends ScanOptions {
|
|
4
9
|
maxDepth?: number;
|
|
@@ -354,4 +359,4 @@ declare function findConsolidationCandidates(graph: DependencyGraph, coUsageMatr
|
|
|
354
359
|
*/
|
|
355
360
|
declare function analyzeContext(options: ContextAnalyzerOptions): Promise<ContextAnalysisResult[]>;
|
|
356
361
|
|
|
357
|
-
export { type CoUsageData, type ContextAnalysisResult, type ContextAnalyzerOptions, type ContextSummary, type DependencyGraph, type DependencyNode, type DomainAssignment, type DomainSignals, type ExportInfo, type FileClassification, type ModuleCluster, type TypeDependency, adjustCohesionForClassification, adjustFragmentationForClassification, analyzeContext, analyzeIssues, buildCoUsageMatrix, buildDependencyGraph, buildTypeGraph, calculateCohesion, calculateContextBudget, calculateContextScore, calculateDirectoryDistance, calculateDomainConfidence, calculateEnhancedCohesion, calculateFragmentation, calculateImportDepth, calculatePathEntropy, calculateStructuralCohesionFromCoUsage, classifyFile, detectCircularDependencies, detectModuleClusters, extractDomainKeywordsFromPaths, extractExports, extractImportsFromContent, findConsolidationCandidates, findSemanticClusters, generateSummary, getClassificationRecommendations, getCoUsageData, getGeneralRecommendations, getSmartDefaults, getTransitiveDependencies, inferDomain, inferDomainFromSemantics, isBarrelExport, isConfigFile, isEmailTemplate, isLambdaHandler, isNextJsPage, isParserFile, isServiceFile, isSessionFile, isTypeDefinition, isUtilityModule, mapScoreToRating };
|
|
362
|
+
export { type CoUsageData, type ContextAnalysisResult, type ContextAnalyzerOptions, ContextAnalyzerProvider, type ContextSummary, type DependencyGraph, type DependencyNode, type DomainAssignment, type DomainSignals, type ExportInfo, type FileClassification, type ModuleCluster, type TypeDependency, adjustCohesionForClassification, adjustFragmentationForClassification, analyzeContext, analyzeIssues, buildCoUsageMatrix, buildDependencyGraph, buildTypeGraph, calculateCohesion, calculateContextBudget, calculateContextScore, calculateDirectoryDistance, calculateDomainConfidence, calculateEnhancedCohesion, calculateFragmentation, calculateImportDepth, calculatePathEntropy, calculateStructuralCohesionFromCoUsage, classifyFile, detectCircularDependencies, detectModuleClusters, extractDomainKeywordsFromPaths, extractExports, extractImportsFromContent, findConsolidationCandidates, findSemanticClusters, generateSummary, getClassificationRecommendations, getCoUsageData, getGeneralRecommendations, getSmartDefaults, getTransitiveDependencies, inferDomain, inferDomainFromSemantics, isBarrelExport, isConfigFile, isEmailTemplate, isLambdaHandler, isNextJsPage, isParserFile, isServiceFile, isSessionFile, isTypeDefinition, isUtilityModule, mapScoreToRating };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import { Severity, ScanOptions, CostConfig, ToolScoringOutput } from '@aiready/core';
|
|
1
|
+
import { ToolProvider, Severity, ScanOptions, CostConfig, ToolScoringOutput } from '@aiready/core';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Context Analyzer Tool Provider
|
|
5
|
+
*/
|
|
6
|
+
declare const ContextAnalyzerProvider: ToolProvider;
|
|
2
7
|
|
|
3
8
|
interface ContextAnalyzerOptions extends ScanOptions {
|
|
4
9
|
maxDepth?: number;
|
|
@@ -354,4 +359,4 @@ declare function findConsolidationCandidates(graph: DependencyGraph, coUsageMatr
|
|
|
354
359
|
*/
|
|
355
360
|
declare function analyzeContext(options: ContextAnalyzerOptions): Promise<ContextAnalysisResult[]>;
|
|
356
361
|
|
|
357
|
-
export { type CoUsageData, type ContextAnalysisResult, type ContextAnalyzerOptions, type ContextSummary, type DependencyGraph, type DependencyNode, type DomainAssignment, type DomainSignals, type ExportInfo, type FileClassification, type ModuleCluster, type TypeDependency, adjustCohesionForClassification, adjustFragmentationForClassification, analyzeContext, analyzeIssues, buildCoUsageMatrix, buildDependencyGraph, buildTypeGraph, calculateCohesion, calculateContextBudget, calculateContextScore, calculateDirectoryDistance, calculateDomainConfidence, calculateEnhancedCohesion, calculateFragmentation, calculateImportDepth, calculatePathEntropy, calculateStructuralCohesionFromCoUsage, classifyFile, detectCircularDependencies, detectModuleClusters, extractDomainKeywordsFromPaths, extractExports, extractImportsFromContent, findConsolidationCandidates, findSemanticClusters, generateSummary, getClassificationRecommendations, getCoUsageData, getGeneralRecommendations, getSmartDefaults, getTransitiveDependencies, inferDomain, inferDomainFromSemantics, isBarrelExport, isConfigFile, isEmailTemplate, isLambdaHandler, isNextJsPage, isParserFile, isServiceFile, isSessionFile, isTypeDefinition, isUtilityModule, mapScoreToRating };
|
|
362
|
+
export { type CoUsageData, type ContextAnalysisResult, type ContextAnalyzerOptions, ContextAnalyzerProvider, type ContextSummary, type DependencyGraph, type DependencyNode, type DomainAssignment, type DomainSignals, type ExportInfo, type FileClassification, type ModuleCluster, type TypeDependency, adjustCohesionForClassification, adjustFragmentationForClassification, analyzeContext, analyzeIssues, buildCoUsageMatrix, buildDependencyGraph, buildTypeGraph, calculateCohesion, calculateContextBudget, calculateContextScore, calculateDirectoryDistance, calculateDomainConfidence, calculateEnhancedCohesion, calculateFragmentation, calculateImportDepth, calculatePathEntropy, calculateStructuralCohesionFromCoUsage, classifyFile, detectCircularDependencies, detectModuleClusters, extractDomainKeywordsFromPaths, extractExports, extractImportsFromContent, findConsolidationCandidates, findSemanticClusters, generateSummary, getClassificationRecommendations, getCoUsageData, getGeneralRecommendations, getSmartDefaults, getTransitiveDependencies, inferDomain, inferDomainFromSemantics, isBarrelExport, isConfigFile, isEmailTemplate, isLambdaHandler, isNextJsPage, isParserFile, isServiceFile, isSessionFile, isTypeDefinition, isUtilityModule, mapScoreToRating };
|
package/dist/index.js
CHANGED
|
@@ -37,7 +37,7 @@ __export(python_context_exports, {
|
|
|
37
37
|
});
|
|
38
38
|
async function analyzePythonContext(files, rootDir) {
|
|
39
39
|
const results = [];
|
|
40
|
-
const parser = (0,
|
|
40
|
+
const parser = (0, import_core8.getParser)("dummy.py");
|
|
41
41
|
if (!parser) {
|
|
42
42
|
console.warn("Python parser not available");
|
|
43
43
|
return results;
|
|
@@ -101,7 +101,7 @@ async function analyzePythonContext(files, rootDir) {
|
|
|
101
101
|
}
|
|
102
102
|
async function buildPythonDependencyGraph(files, rootDir) {
|
|
103
103
|
const graph = /* @__PURE__ */ new Map();
|
|
104
|
-
const parser = (0,
|
|
104
|
+
const parser = (0, import_core8.getParser)("dummy.py");
|
|
105
105
|
if (!parser) return graph;
|
|
106
106
|
for (const file of files) {
|
|
107
107
|
try {
|
|
@@ -181,7 +181,7 @@ async function calculatePythonImportDepth(file, dependencyGraph, visited, depth
|
|
|
181
181
|
}
|
|
182
182
|
function estimateContextBudget(code, imports, dependencyGraph) {
|
|
183
183
|
void dependencyGraph;
|
|
184
|
-
let budget = (0,
|
|
184
|
+
let budget = (0, import_core8.estimateTokens)(code);
|
|
185
185
|
const avgTokensPerDep = 500;
|
|
186
186
|
budget += imports.length * avgTokensPerDep;
|
|
187
187
|
return budget;
|
|
@@ -231,11 +231,11 @@ function detectCircularDependencies2(file, dependencyGraph) {
|
|
|
231
231
|
dfs(file, []);
|
|
232
232
|
return [...new Set(circular)];
|
|
233
233
|
}
|
|
234
|
-
var
|
|
234
|
+
var import_core8, import_path, import_fs;
|
|
235
235
|
var init_python_context = __esm({
|
|
236
236
|
"src/analyzers/python-context.ts"() {
|
|
237
237
|
"use strict";
|
|
238
|
-
|
|
238
|
+
import_core8 = require("@aiready/core");
|
|
239
239
|
import_path = require("path");
|
|
240
240
|
import_fs = __toESM(require("fs"));
|
|
241
241
|
}
|
|
@@ -244,6 +244,7 @@ var init_python_context = __esm({
|
|
|
244
244
|
// src/index.ts
|
|
245
245
|
var index_exports = {};
|
|
246
246
|
__export(index_exports, {
|
|
247
|
+
ContextAnalyzerProvider: () => ContextAnalyzerProvider,
|
|
247
248
|
adjustCohesionForClassification: () => adjustCohesionForClassification,
|
|
248
249
|
adjustFragmentationForClassification: () => adjustFragmentationForClassification,
|
|
249
250
|
analyzeContext: () => analyzeContext,
|
|
@@ -290,7 +291,7 @@ __export(index_exports, {
|
|
|
290
291
|
mapScoreToRating: () => mapScoreToRating
|
|
291
292
|
});
|
|
292
293
|
module.exports = __toCommonJS(index_exports);
|
|
293
|
-
var
|
|
294
|
+
var import_core9 = require("@aiready/core");
|
|
294
295
|
|
|
295
296
|
// src/analyzer.ts
|
|
296
297
|
var import_core4 = require("@aiready/core");
|
|
@@ -633,12 +634,9 @@ function calculateEnhancedCohesion(exports2, filePath, options) {
|
|
|
633
634
|
}
|
|
634
635
|
}
|
|
635
636
|
const avgImportScore = pairsWithData > 0 ? importScoreTotal / pairsWithData : 0;
|
|
636
|
-
let score = 0;
|
|
637
|
-
if (anyImportData) {
|
|
638
|
-
score =
|
|
639
|
-
if (score === 0 && domainScore === 0) score = 0.1;
|
|
640
|
-
} else {
|
|
641
|
-
score = domainScore;
|
|
637
|
+
let score = anyImportData ? domainScore * 0.4 + avgImportScore * 0.6 : domainScore;
|
|
638
|
+
if (anyImportData && score === 0 && domainScore === 0) {
|
|
639
|
+
score = 0.1;
|
|
642
640
|
}
|
|
643
641
|
let structuralScore = 0;
|
|
644
642
|
for (const exp of exports2) {
|
|
@@ -677,19 +675,7 @@ function calculateFragmentation(files, domain, options) {
|
|
|
677
675
|
files.map((f) => f.split("/").slice(0, -1).join("/"))
|
|
678
676
|
);
|
|
679
677
|
const uniqueDirs = directories.size;
|
|
680
|
-
let score = 0;
|
|
681
|
-
if (options?.useLogScale) {
|
|
682
|
-
if (uniqueDirs <= 1) score = 0;
|
|
683
|
-
else {
|
|
684
|
-
const total = files.length;
|
|
685
|
-
const base = options.logBase || Math.E;
|
|
686
|
-
const num = Math.log(uniqueDirs) / Math.log(base);
|
|
687
|
-
const den = Math.log(total) / Math.log(base);
|
|
688
|
-
score = den > 0 ? num / den : 0;
|
|
689
|
-
}
|
|
690
|
-
} else {
|
|
691
|
-
score = (uniqueDirs - 1) / (files.length - 1);
|
|
692
|
-
}
|
|
678
|
+
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);
|
|
693
679
|
if (options?.sharedImportRatio && options.sharedImportRatio > 0.5) {
|
|
694
680
|
const discount = (options.sharedImportRatio - 0.5) * 0.4;
|
|
695
681
|
score = score * (1 - discount);
|
|
@@ -1504,6 +1490,9 @@ function isBuildArtifact(filePath) {
|
|
|
1504
1490
|
return lower.includes("/node_modules/") || lower.includes("/dist/") || lower.includes("/build/") || lower.includes("/out/") || lower.includes("/.next/");
|
|
1505
1491
|
}
|
|
1506
1492
|
|
|
1493
|
+
// src/provider.ts
|
|
1494
|
+
var import_core6 = require("@aiready/core");
|
|
1495
|
+
|
|
1507
1496
|
// src/scoring.ts
|
|
1508
1497
|
var import_core5 = require("@aiready/core");
|
|
1509
1498
|
function calculateContextScore(summary, costConfig) {
|
|
@@ -1612,7 +1601,7 @@ function calculateContextScore(summary, costConfig) {
|
|
|
1612
1601
|
];
|
|
1613
1602
|
const productivityImpact = (0, import_core5.calculateProductivityImpact)(issues);
|
|
1614
1603
|
return {
|
|
1615
|
-
toolName:
|
|
1604
|
+
toolName: import_core5.ToolName.ContextAnalyzer,
|
|
1616
1605
|
score,
|
|
1617
1606
|
rawMetrics: {
|
|
1618
1607
|
avgContextBudget: Math.round(avgContextBudget),
|
|
@@ -1637,10 +1626,53 @@ function mapScoreToRating(score) {
|
|
|
1637
1626
|
return "critical";
|
|
1638
1627
|
}
|
|
1639
1628
|
|
|
1629
|
+
// src/provider.ts
|
|
1630
|
+
var ContextAnalyzerProvider = {
|
|
1631
|
+
id: import_core6.ToolName.ContextAnalyzer,
|
|
1632
|
+
alias: ["context", "fragmentation", "budget"],
|
|
1633
|
+
async analyze(options) {
|
|
1634
|
+
const results = await analyzeContext(options);
|
|
1635
|
+
const summary = generateSummary(results);
|
|
1636
|
+
const normalizedResults = results.map(
|
|
1637
|
+
(r) => ({
|
|
1638
|
+
fileName: r.file,
|
|
1639
|
+
issues: r.issues.map((msg) => ({
|
|
1640
|
+
type: import_core6.IssueType.ContextFragmentation,
|
|
1641
|
+
severity: r.severity,
|
|
1642
|
+
message: msg,
|
|
1643
|
+
location: { file: r.file, line: 1 },
|
|
1644
|
+
suggestion: r.recommendations[0]
|
|
1645
|
+
})),
|
|
1646
|
+
metrics: {
|
|
1647
|
+
tokenCost: r.tokenCost,
|
|
1648
|
+
complexityScore: r.importDepth
|
|
1649
|
+
// Map other context-specific metrics if needed
|
|
1650
|
+
}
|
|
1651
|
+
})
|
|
1652
|
+
);
|
|
1653
|
+
return import_core6.SpokeOutputSchema.parse({
|
|
1654
|
+
results: normalizedResults,
|
|
1655
|
+
summary: {
|
|
1656
|
+
...summary
|
|
1657
|
+
},
|
|
1658
|
+
metadata: {
|
|
1659
|
+
toolName: import_core6.ToolName.ContextAnalyzer,
|
|
1660
|
+
version: "0.17.5",
|
|
1661
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1662
|
+
}
|
|
1663
|
+
});
|
|
1664
|
+
},
|
|
1665
|
+
score(output, options) {
|
|
1666
|
+
const summary = output.summary;
|
|
1667
|
+
return calculateContextScore(summary, options.costConfig);
|
|
1668
|
+
},
|
|
1669
|
+
defaultWeight: 19
|
|
1670
|
+
};
|
|
1671
|
+
|
|
1640
1672
|
// src/defaults.ts
|
|
1641
|
-
var
|
|
1673
|
+
var import_core7 = require("@aiready/core");
|
|
1642
1674
|
async function getSmartDefaults(directory, userOptions) {
|
|
1643
|
-
const files = await (0,
|
|
1675
|
+
const files = await (0, import_core7.scanFiles)({
|
|
1644
1676
|
rootDir: directory,
|
|
1645
1677
|
include: userOptions.include,
|
|
1646
1678
|
exclude: userOptions.exclude
|
|
@@ -1812,6 +1844,7 @@ function generateSummary(results) {
|
|
|
1812
1844
|
}
|
|
1813
1845
|
|
|
1814
1846
|
// src/index.ts
|
|
1847
|
+
import_core9.ToolRegistry.register(ContextAnalyzerProvider);
|
|
1815
1848
|
async function analyzeContext(options) {
|
|
1816
1849
|
const {
|
|
1817
1850
|
maxDepth = 5,
|
|
@@ -1822,7 +1855,7 @@ async function analyzeContext(options) {
|
|
|
1822
1855
|
includeNodeModules = false,
|
|
1823
1856
|
...scanOptions
|
|
1824
1857
|
} = options;
|
|
1825
|
-
const files = await (0,
|
|
1858
|
+
const files = await (0, import_core9.scanFiles)({
|
|
1826
1859
|
...scanOptions,
|
|
1827
1860
|
exclude: includeNodeModules && scanOptions.exclude ? scanOptions.exclude.filter(
|
|
1828
1861
|
(pattern) => pattern !== "**/node_modules/**"
|
|
@@ -1832,7 +1865,7 @@ async function analyzeContext(options) {
|
|
|
1832
1865
|
const fileContents = await Promise.all(
|
|
1833
1866
|
files.map(async (file) => ({
|
|
1834
1867
|
file,
|
|
1835
|
-
content: await (0,
|
|
1868
|
+
content: await (0, import_core9.readFileContent)(file)
|
|
1836
1869
|
}))
|
|
1837
1870
|
);
|
|
1838
1871
|
const graph = buildDependencyGraph(
|
|
@@ -1996,6 +2029,7 @@ async function analyzeContext(options) {
|
|
|
1996
2029
|
}
|
|
1997
2030
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1998
2031
|
0 && (module.exports = {
|
|
2032
|
+
ContextAnalyzerProvider,
|
|
1999
2033
|
adjustCohesionForClassification,
|
|
2000
2034
|
adjustFragmentationForClassification,
|
|
2001
2035
|
analyzeContext,
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
ContextAnalyzerProvider,
|
|
2
3
|
adjustCohesionForClassification,
|
|
3
4
|
adjustFragmentationForClassification,
|
|
4
5
|
analyzeContext,
|
|
@@ -43,8 +44,9 @@ import {
|
|
|
43
44
|
isTypeDefinition,
|
|
44
45
|
isUtilityModule,
|
|
45
46
|
mapScoreToRating
|
|
46
|
-
} from "./chunk-
|
|
47
|
+
} from "./chunk-Q2GDZ2FZ.mjs";
|
|
47
48
|
export {
|
|
49
|
+
ContextAnalyzerProvider,
|
|
48
50
|
adjustCohesionForClassification,
|
|
49
51
|
adjustFragmentationForClassification,
|
|
50
52
|
analyzeContext,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aiready/context-analyzer",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.19.1",
|
|
4
4
|
"description": "AI context window cost analysis - detect fragmented code, deep import chains, and expensive context budgets",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"commander": "^14.0.0",
|
|
50
50
|
"chalk": "^5.3.0",
|
|
51
51
|
"prompts": "^2.4.2",
|
|
52
|
-
"@aiready/core": "0.
|
|
52
|
+
"@aiready/core": "0.21.1"
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|
|
55
55
|
"@types/node": "^24.0.0",
|
package/src/index.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { scanFiles, readFileContent } from '@aiready/core';
|
|
1
|
+
import { scanFiles, readFileContent, ToolRegistry } from '@aiready/core';
|
|
2
2
|
import {
|
|
3
3
|
buildDependencyGraph,
|
|
4
4
|
calculateImportDepth,
|
|
@@ -16,18 +16,23 @@ import {
|
|
|
16
16
|
import { calculateContextScore } from './scoring';
|
|
17
17
|
import { getSmartDefaults } from './defaults';
|
|
18
18
|
import { generateSummary } from './summary';
|
|
19
|
+
import { ContextAnalyzerProvider } from './provider';
|
|
19
20
|
import type {
|
|
20
21
|
ContextAnalyzerOptions,
|
|
21
22
|
ContextAnalysisResult,
|
|
22
23
|
ContextSummary,
|
|
23
24
|
} from './types';
|
|
24
25
|
|
|
26
|
+
// Register with global registry
|
|
27
|
+
ToolRegistry.register(ContextAnalyzerProvider);
|
|
28
|
+
|
|
25
29
|
export * from './analyzer';
|
|
26
30
|
export * from './scoring';
|
|
27
31
|
export * from './defaults';
|
|
28
32
|
export * from './summary';
|
|
29
33
|
export * from './types';
|
|
30
34
|
export * from './semantic-analysis';
|
|
35
|
+
export { ContextAnalyzerProvider };
|
|
31
36
|
|
|
32
37
|
/**
|
|
33
38
|
* Analyze AI context window cost for a codebase
|