@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/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, import_core7.getParser)("dummy.py");
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, import_core7.getParser)("dummy.py");
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, import_core7.estimateTokens)(code);
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 import_core7, import_path, import_fs;
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
- import_core7 = require("@aiready/core");
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 import_core8 = require("@aiready/core");
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 = domainScore * 0.4 + avgImportScore * 0.6;
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 import_core6 = require("@aiready/core");
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, import_core8.scanFiles)({
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, import_core8.readFileContent)(file)
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 import_core9 = require("@aiready/core");
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, import_core9.loadMergedConfig)(directory, defaults, {
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, import_core9.getElapsedTime)(startTime);
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, import_core9.resolveOutputPath)(
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, import_core9.handleJSONOutput)(
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, import_core9.resolveOutputPath)(
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, import_core9.handleCLIError)(error, "Analysis");
1924
+ (0, import_core10.handleCLIError)(error, "Analysis");
1770
1925
  }
1771
1926
  });
1772
1927
  program.parse();
package/dist/cli.mjs CHANGED
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  analyzeContext,
4
4
  generateSummary
5
- } from "./chunk-7VK3XTSH.mjs";
5
+ } from "./chunk-Q2GDZ2FZ.mjs";
6
6
 
7
7
  // src/cli.ts
8
8
  import { Command } from "commander";
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, import_core7.getParser)("dummy.py");
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, import_core7.getParser)("dummy.py");
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, import_core7.estimateTokens)(code);
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 import_core7, import_path, import_fs;
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
- import_core7 = require("@aiready/core");
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 import_core8 = require("@aiready/core");
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 = domainScore * 0.4 + avgImportScore * 0.6;
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: "context-analyzer",
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 import_core6 = require("@aiready/core");
1673
+ var import_core7 = require("@aiready/core");
1642
1674
  async function getSmartDefaults(directory, userOptions) {
1643
- const files = await (0, import_core6.scanFiles)({
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, import_core8.scanFiles)({
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, import_core8.readFileContent)(file)
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-7VK3XTSH.mjs";
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.17.5",
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.19.5"
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