@aiready/context-analyzer 0.21.26 → 0.21.27

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.
Files changed (78) hide show
  1. package/.turbo/turbo-build.log +32 -25
  2. package/.turbo/turbo-test.log +51 -87
  3. package/coverage/clover.xml +392 -1878
  4. package/coverage/coverage-final.json +15 -19
  5. package/coverage/index.html +48 -63
  6. package/coverage/src/analyzers/index.html +21 -21
  7. package/coverage/src/analyzers/python-context.ts.html +96 -96
  8. package/coverage/src/ast-utils.ts.html +34 -109
  9. package/coverage/src/classifier.ts.html +104 -104
  10. package/coverage/src/classify/classification-patterns.ts.html +1 -1
  11. package/coverage/src/classify/file-classifiers.ts.html +1 -1
  12. package/coverage/src/classify/index.html +1 -1
  13. package/coverage/src/cluster-detector.ts.html +72 -72
  14. package/coverage/src/defaults.ts.html +1 -1
  15. package/coverage/src/graph-builder.ts.html +131 -131
  16. package/coverage/src/index.html +101 -116
  17. package/coverage/src/index.ts.html +2 -2
  18. package/coverage/src/issue-analyzer.ts.html +32 -83
  19. package/coverage/src/mapper.ts.html +20 -2
  20. package/coverage/src/metrics.ts.html +127 -130
  21. package/coverage/src/orchestrator.ts.html +13 -13
  22. package/coverage/src/provider.ts.html +19 -19
  23. package/coverage/src/remediation.ts.html +59 -59
  24. package/coverage/src/report/console-report.ts.html +2 -2
  25. package/coverage/src/report/html-report.ts.html +60 -84
  26. package/coverage/src/report/index.html +7 -7
  27. package/coverage/src/report/interactive-setup.ts.html +1 -1
  28. package/coverage/src/scoring.ts.html +62 -62
  29. package/coverage/src/semantic/co-usage.ts.html +1 -1
  30. package/coverage/src/semantic/consolidation.ts.html +1 -1
  31. package/coverage/src/semantic/domain-inference.ts.html +1 -1
  32. package/coverage/src/semantic/index.html +1 -1
  33. package/coverage/src/semantic/type-graph.ts.html +1 -1
  34. package/coverage/src/summary.ts.html +67 -67
  35. package/coverage/src/types.ts.html +1 -1
  36. package/coverage/src/utils/dependency-graph-utils.ts.html +41 -41
  37. package/coverage/src/utils/index.html +21 -21
  38. package/coverage/src/utils/string-utils.ts.html +1 -1
  39. package/dist/chunk-22ZO4EKZ.mjs +1297 -0
  40. package/dist/chunk-4U4LDWGF.mjs +360 -0
  41. package/dist/chunk-BA7QGUHN.mjs +1722 -0
  42. package/dist/chunk-BCEZGRXI.mjs +1297 -0
  43. package/dist/chunk-BQCISA2F.mjs +91 -0
  44. package/dist/chunk-EMYD7NS6.mjs +137 -0
  45. package/dist/chunk-EWFR366Y.mjs +1740 -0
  46. package/dist/chunk-FO6YT6RG.mjs +1751 -0
  47. package/dist/chunk-J3SZQZNU.mjs +221 -0
  48. package/dist/chunk-OZE3FVZT.mjs +1089 -0
  49. package/dist/chunk-WHB7QI7N.mjs +91 -0
  50. package/dist/cli-action-CXIHOVAC.mjs +95 -0
  51. package/dist/cli-action-SA7SCYNV.mjs +95 -0
  52. package/dist/cli-action-YAJOJCXJ.mjs +95 -0
  53. package/dist/cli.js +688 -566
  54. package/dist/cli.mjs +4 -88
  55. package/dist/index.js +889 -773
  56. package/dist/index.mjs +21 -14
  57. package/dist/orchestrator-3L3NAZYP.mjs +10 -0
  58. package/dist/orchestrator-MONOZHVW.mjs +10 -0
  59. package/dist/orchestrator-ZR7JSKWI.mjs +10 -0
  60. package/dist/summary-7PZVW72O.mjs +7 -0
  61. package/dist/summary-LKUCJAIS.mjs +7 -0
  62. package/package.json +2 -2
  63. package/src/__tests__/analyzer.test.ts +1 -1
  64. package/src/__tests__/enhanced-cohesion.test.ts +4 -1
  65. package/src/__tests__/orchestrator.test.ts +19 -4
  66. package/src/__tests__/python-context.test.ts +6 -0
  67. package/src/__tests__/report/html-report.test.ts +8 -2
  68. package/src/ast-utils.ts +1 -26
  69. package/src/cli-definition.ts +4 -2
  70. package/src/issue-analyzer.ts +4 -19
  71. package/src/metrics.ts +1 -2
  72. package/src/provider.ts +4 -4
  73. package/src/report/html-report.ts +43 -59
  74. package/coverage/dist/chunk-64U3PNO3.mjs.html +0 -367
  75. package/coverage/dist/chunk-J3MUOWHC.mjs.html +0 -5326
  76. package/coverage/dist/index.html +0 -146
  77. package/coverage/dist/index.mjs.html +0 -1396
  78. package/coverage/src/analyzer.ts.html +0 -88
package/dist/index.mjs CHANGED
@@ -1,3 +1,8 @@
1
+ import {
2
+ displayConsoleReport,
3
+ generateHTMLReport,
4
+ runInteractiveSetup
5
+ } from "./chunk-J3SZQZNU.mjs";
1
6
  import {
2
7
  BARREL_EXPORT_MIN_EXPORTS,
3
8
  BARREL_EXPORT_TOKEN_LIMIT,
@@ -17,22 +22,14 @@ import {
17
22
  buildTypeGraph,
18
23
  calculateCohesion,
19
24
  calculateContextBudget,
20
- calculateDirectoryDistance,
21
25
  calculateDomainConfidence,
22
- calculateEnhancedCohesion,
23
- calculateFragmentation,
24
26
  calculateImportDepth,
25
- calculatePathEntropy,
26
- calculateStructuralCohesionFromCoUsage,
27
27
  classifyFile,
28
28
  detectCircularDependencies,
29
29
  detectModuleClusters,
30
- displayConsoleReport,
31
30
  extractDomainKeywordsFromPaths,
32
31
  extractExports,
33
32
  findSemanticClusters,
34
- generateHTMLReport,
35
- generateSummary,
36
33
  getClassificationRecommendations,
37
34
  getCoUsageData,
38
35
  getGeneralRecommendations,
@@ -50,10 +47,19 @@ import {
50
47
  isServiceFile,
51
48
  isSessionFile,
52
49
  isTypeDefinition,
53
- isUtilityModule,
54
- runInteractiveSetup
55
- } from "./chunk-VLV6MXPL.mjs";
50
+ isUtilityModule
51
+ } from "./chunk-BCEZGRXI.mjs";
56
52
  import "./chunk-64U3PNO3.mjs";
53
+ import {
54
+ generateSummary
55
+ } from "./chunk-BQCISA2F.mjs";
56
+ import {
57
+ calculateDirectoryDistance,
58
+ calculateEnhancedCohesion,
59
+ calculateFragmentation,
60
+ calculatePathEntropy,
61
+ calculateStructuralCohesionFromCoUsage
62
+ } from "./chunk-EMYD7NS6.mjs";
57
63
 
58
64
  // src/index.ts
59
65
  import { ToolRegistry } from "@aiready/core";
@@ -259,8 +265,10 @@ var ContextAnalyzerProvider = {
259
265
  id: ToolName2.ContextAnalyzer,
260
266
  alias: ["context", "fragmentation", "budget"],
261
267
  async analyze(options) {
262
- const results = await analyzeContext(options);
263
- const summary = generateSummary(results, options);
268
+ const { analyzeContext: analyzeContext2 } = await import("./orchestrator-3L3NAZYP.mjs");
269
+ const { generateSummary: generateSummary2 } = await import("./summary-7PZVW72O.mjs");
270
+ const results = await analyzeContext2(options);
271
+ const summary = generateSummary2(results, options);
264
272
  const normalizedResults = results.map(
265
273
  (r) => ({
266
274
  fileName: r.file,
@@ -274,7 +282,6 @@ var ContextAnalyzerProvider = {
274
282
  metrics: {
275
283
  tokenCost: r.tokenCost,
276
284
  complexityScore: r.importDepth
277
- // Map other context-specific metrics if needed
278
285
  }
279
286
  })
280
287
  );
@@ -0,0 +1,10 @@
1
+ import {
2
+ analyzeContext,
3
+ calculateCohesion
4
+ } from "./chunk-BCEZGRXI.mjs";
5
+ import "./chunk-64U3PNO3.mjs";
6
+ import "./chunk-EMYD7NS6.mjs";
7
+ export {
8
+ analyzeContext,
9
+ calculateCohesion
10
+ };
@@ -0,0 +1,10 @@
1
+ import {
2
+ analyzeContext,
3
+ calculateCohesion
4
+ } from "./chunk-22ZO4EKZ.mjs";
5
+ import "./chunk-64U3PNO3.mjs";
6
+ import "./chunk-EMYD7NS6.mjs";
7
+ export {
8
+ analyzeContext,
9
+ calculateCohesion
10
+ };
@@ -0,0 +1,10 @@
1
+ import {
2
+ analyzeContext,
3
+ calculateCohesion
4
+ } from "./chunk-OZE3FVZT.mjs";
5
+ import "./chunk-64U3PNO3.mjs";
6
+ import "./chunk-4U4LDWGF.mjs";
7
+ export {
8
+ analyzeContext,
9
+ calculateCohesion
10
+ };
@@ -0,0 +1,7 @@
1
+ import {
2
+ generateSummary
3
+ } from "./chunk-BQCISA2F.mjs";
4
+ import "./chunk-EMYD7NS6.mjs";
5
+ export {
6
+ generateSummary
7
+ };
@@ -0,0 +1,7 @@
1
+ import {
2
+ generateSummary
3
+ } from "./chunk-WHB7QI7N.mjs";
4
+ import "./chunk-4U4LDWGF.mjs";
5
+ export {
6
+ generateSummary
7
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aiready/context-analyzer",
3
- "version": "0.21.26",
3
+ "version": "0.21.27",
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.23.23"
52
+ "@aiready/core": "0.23.24"
53
53
  },
54
54
  "devDependencies": {
55
55
  "@types/node": "^24.0.0",
@@ -207,7 +207,7 @@ describe('calculateCohesion', () => {
207
207
  // Mock file - should return 1 despite mixed domains
208
208
  const cohesionMockFile = calculateCohesion(
209
209
  exports,
210
- 'src/test-utils/mocks.ts'
210
+ 'src/__tests__/mocks.ts'
211
211
  );
212
212
  expect(cohesionMockFile).toBe(1);
213
213
 
@@ -132,7 +132,10 @@ describe('Enhanced Cohesion Calculation', () => {
132
132
  },
133
133
  ];
134
134
 
135
- const cohesion = calculateCohesion(exports, 'src/utils/test-helpers.ts');
135
+ const cohesion = calculateCohesion(
136
+ exports,
137
+ 'src/__tests__/test-helpers.ts'
138
+ );
136
139
  expect(cohesion).toBe(1);
137
140
  });
138
141
  });
@@ -12,6 +12,20 @@ vi.mock('@aiready/core', async () => {
12
12
  };
13
13
  });
14
14
 
15
+ // Mock fs to prevent ENOENT errors when python-context tries to read files
16
+ vi.mock('fs', () => ({
17
+ default: {
18
+ promises: {
19
+ readFile: vi.fn().mockResolvedValue('# Python file\nprint("hello")'),
20
+ },
21
+ existsSync: vi.fn().mockReturnValue(true),
22
+ },
23
+ promises: {
24
+ readFile: vi.fn().mockResolvedValue('# Python file\nprint("hello")'),
25
+ },
26
+ existsSync: vi.fn().mockReturnValue(true),
27
+ }));
28
+
15
29
  describe('analyzeContext', () => {
16
30
  beforeEach(() => {
17
31
  vi.clearAllMocks();
@@ -60,7 +74,7 @@ describe('analyzeContext', () => {
60
74
  expect(results).toEqual([]);
61
75
  });
62
76
 
63
- it('should filter Python files when not present', async () => {
77
+ it('should process both TypeScript and Python files', async () => {
64
78
  const mockFiles = ['src/file1.ts', 'src/file2.py'];
65
79
  vi.mocked(core.scanFiles).mockResolvedValue(mockFiles);
66
80
  vi.mocked(core.readFileContent).mockResolvedValue('export const a = 1;');
@@ -69,9 +83,10 @@ describe('analyzeContext', () => {
69
83
  rootDir: '.',
70
84
  });
71
85
 
72
- // Should only process TypeScript files
73
- expect(results.length).toBe(1);
74
- expect(results[0].file).toBe('src/file1.ts');
86
+ // Orchestrator processes both TypeScript and Python files
87
+ expect(results.length).toBe(2);
88
+ expect(results.some((r) => r.file === 'src/file1.ts')).toBe(true);
89
+ expect(results.some((r) => r.file === 'src/file2.py')).toBe(true);
75
90
  });
76
91
 
77
92
  it('should use default options when not provided', async () => {
@@ -27,6 +27,12 @@ vi.mock('@aiready/core', () => ({
27
27
 
28
28
  // Mock fs
29
29
  vi.mock('fs', () => ({
30
+ default: {
31
+ promises: {
32
+ readFile: vi.fn(),
33
+ },
34
+ existsSync: vi.fn(),
35
+ },
30
36
  promises: {
31
37
  readFile: vi.fn(),
32
38
  },
@@ -22,6 +22,13 @@ vi.mock('@aiready/core', () => ({
22
22
  `<div class="issue-summary">Issues: Critical:${critical}, Major:${major}, Minor:${minor}. Savings: ${savings}</div>`,
23
23
  wrapInCard: (content: string, title?: string) =>
24
24
  `<div class="card"><h2>${title}</h2>${content}</div>`,
25
+ generateStandardHtmlReport: (config: any, stats: any[], sections: any[]) => {
26
+ const sectionHtml = sections
27
+ .map((s: any) => `<h2>${s.title}</h2>${s.content}`)
28
+ .join('');
29
+ const footerHtml = `<footer>${config.packageName} - ${config.packageUrl}</footer>`;
30
+ return `<!DOCTYPE html><html>${config.title}<body>${stats.map((s: any) => s.label).join(', ')}${sectionHtml}${footerHtml}</body></html>`;
31
+ },
25
32
  }));
26
33
 
27
34
  describe('generateHTMLReport', () => {
@@ -81,8 +88,7 @@ describe('generateHTMLReport', () => {
81
88
 
82
89
  const html = generateHTMLReport(summary, results);
83
90
 
84
- expect(html).toContain('AIReady Context Analysis Report');
85
- expect(html).toContain('head');
91
+ expect(html).toContain('Context Analysis Report');
86
92
  expect(html).toContain('body');
87
93
  });
88
94
 
package/src/ast-utils.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { parseFileExports } from '@aiready/core';
1
+ import { parseFileExports, isTestFile } from '@aiready/core';
2
2
  import type { ExportInfo } from './types';
3
3
  import { inferDomain, extractExports } from './semantic/domain-inference';
4
4
 
@@ -46,31 +46,6 @@ export async function extractExportsWithAST(
46
46
  }
47
47
  }
48
48
 
49
- /**
50
- * Check if a file is a test, mock, or fixture file.
51
- *
52
- * @param filePath - The path to the file to check.
53
- * @returns True if the file matches test/mock patterns.
54
- */
55
- export function isTestFile(filePath: string): boolean {
56
- const lower = filePath.toLowerCase();
57
- return (
58
- lower.includes('.test.') ||
59
- lower.includes('.spec.') ||
60
- lower.includes('/__tests__/') ||
61
- lower.includes('/tests/') ||
62
- lower.includes('/test/') ||
63
- lower.includes('test-') ||
64
- lower.includes('-test') ||
65
- lower.includes('/__mocks__/') ||
66
- lower.includes('/mocks/') ||
67
- lower.includes('/fixtures/') ||
68
- lower.includes('.mock.') ||
69
- lower.includes('.fixture.') ||
70
- lower.includes('/test-utils/')
71
- );
72
- }
73
-
74
49
  /**
75
50
  * Heuristic to check if all exports share a common entity noun
76
51
  */
@@ -1,5 +1,4 @@
1
1
  import { Command } from 'commander';
2
- import { contextActionHandler } from './cli-action';
3
2
 
4
3
  /**
5
4
  * Define the context analysis command structure.
@@ -57,5 +56,8 @@ export function defineContextCommand(program: Command): void {
57
56
  '--interactive',
58
57
  'Run interactive setup to suggest excludes and focus areas'
59
58
  )
60
- .action(contextActionHandler);
59
+ .action(async (directory, options) => {
60
+ const { contextActionHandler } = await import('./cli-action');
61
+ await contextActionHandler(directory, options);
62
+ });
61
63
  }
@@ -1,4 +1,7 @@
1
- import { Severity } from '@aiready/core';
1
+ import { Severity, isBuildArtifact } from '@aiready/core';
2
+
3
+ // Re-export for testing
4
+ export { isBuildArtifact };
2
5
 
3
6
  /**
4
7
  * Internal issue analysis logic
@@ -136,21 +139,3 @@ export function analyzeIssues(params: {
136
139
  potentialSavings: Math.floor(potentialSavings),
137
140
  };
138
141
  }
139
-
140
- /**
141
- * Determines if a file path belongs to a build artifact or dependency folder.
142
- * Helps exclude generated files from analysis to prevent false positives.
143
- *
144
- * @param filePath - The path to check
145
- * @returns True if the file is a build artifact, false otherwise
146
- */
147
- export function isBuildArtifact(filePath: string): boolean {
148
- const lower = filePath.toLowerCase();
149
- return (
150
- lower.includes('/node_modules/') ||
151
- lower.includes('/dist/') ||
152
- lower.includes('/build/') ||
153
- lower.includes('/out/') ||
154
- lower.includes('/.next/')
155
- );
156
- }
package/src/metrics.ts CHANGED
@@ -1,6 +1,5 @@
1
- import { calculateImportSimilarity } from '@aiready/core';
1
+ import { calculateImportSimilarity, isTestFile } from '@aiready/core';
2
2
  import type { ExportInfo } from './types';
3
- import { isTestFile } from './ast-utils';
4
3
 
5
4
  /**
6
5
  * Calculates a cohesion score (0-1) for a module based on its exports,
package/src/provider.ts CHANGED
@@ -9,10 +9,8 @@ import {
9
9
  IssueType,
10
10
  SpokeOutputSchema,
11
11
  } from '@aiready/core';
12
- import { analyzeContext } from './orchestrator';
13
- import { generateSummary } from './summary';
14
12
  import { calculateContextScore } from './scoring';
15
- import { ContextAnalyzerOptions, ContextAnalysisResult } from './types';
13
+ import type { ContextAnalyzerOptions, ContextAnalysisResult } from './types';
16
14
 
17
15
  /**
18
16
  * Context Analyzer Tool Provider
@@ -22,6 +20,9 @@ export const ContextAnalyzerProvider: ToolProvider = {
22
20
  alias: ['context', 'fragmentation', 'budget'],
23
21
 
24
22
  async analyze(options: ScanOptions): Promise<SpokeOutput> {
23
+ const { analyzeContext } = await import('./orchestrator');
24
+ const { generateSummary } = await import('./summary');
25
+
25
26
  const results = await analyzeContext(options as ContextAnalyzerOptions);
26
27
  const summary = generateSummary(results, options);
27
28
 
@@ -39,7 +40,6 @@ export const ContextAnalyzerProvider: ToolProvider = {
39
40
  metrics: {
40
41
  tokenCost: r.tokenCost,
41
42
  complexityScore: r.importDepth,
42
- // Map other context-specific metrics if needed
43
43
  },
44
44
  })
45
45
  );
@@ -1,13 +1,9 @@
1
1
  import { analyzeContext } from '../orchestrator';
2
2
  import { generateSummary } from '../summary';
3
3
  import {
4
- generateReportHead,
5
- generateReportHero,
6
- generateStatCards,
7
4
  generateIssueSummary,
8
5
  generateTable,
9
- generateReportFooter,
10
- wrapInCard,
6
+ generateStandardHtmlReport,
11
7
  } from '@aiready/core';
12
8
 
13
9
  /**
@@ -19,13 +15,9 @@ export function generateHTMLReport(
19
15
  ): string {
20
16
  const totalIssues =
21
17
  summary.criticalIssues + summary.majorIssues + summary.minorIssues;
22
-
23
- // 'results' may be used in templates later; reference to avoid lint warnings
24
18
  void results;
25
19
 
26
- const head = generateReportHead('AIReady Context Analysis Report');
27
-
28
- const stats = generateStatCards([
20
+ const stats = [
29
21
  { value: summary.totalFiles, label: 'Files Analyzed' },
30
22
  { value: summary.totalTokens.toLocaleString(), label: 'Total Tokens' },
31
23
  { value: summary.avgContextBudget.toFixed(0), label: 'Avg Context Budget' },
@@ -34,67 +26,59 @@ export function generateHTMLReport(
34
26
  label: 'Total Issues',
35
27
  color: totalIssues > 0 ? '#f39c12' : undefined,
36
28
  },
37
- ]);
38
-
39
- const hero = generateReportHero(
40
- '🔍 AIReady Context Analysis Report',
41
- `Generated on ${new Date().toLocaleString()}`
42
- );
43
-
44
- let body = `${hero}
45
- ${stats}`;
29
+ ];
46
30
 
31
+ const sections: any[] = [];
47
32
  if (totalIssues > 0) {
48
- body += generateIssueSummary(
49
- summary.criticalIssues,
50
- summary.majorIssues,
51
- summary.minorIssues,
52
- summary.totalPotentialSavings
53
- );
33
+ sections.push({
34
+ title: '⚠️ Issues Summary',
35
+ content: generateIssueSummary(
36
+ summary.criticalIssues,
37
+ summary.majorIssues,
38
+ summary.minorIssues,
39
+ summary.totalPotentialSavings
40
+ ),
41
+ });
54
42
  }
55
43
 
56
44
  if (summary.fragmentedModules.length > 0) {
57
- const fragmentedRows = summary.fragmentedModules.map((m) => [
58
- m.domain,
59
- String(m.files.length),
60
- `${(m.fragmentationScore * 100).toFixed(0)}%`,
61
- m.totalTokens.toLocaleString(),
62
- ]);
63
- body += wrapInCard(
64
- generateTable({
45
+ sections.push({
46
+ title: '🧩 Fragmented Modules',
47
+ content: generateTable({
65
48
  headers: ['Domain', 'Files', 'Fragmentation', 'Token Cost'],
66
- rows: fragmentedRows,
49
+ rows: summary.fragmentedModules.map((m) => [
50
+ m.domain,
51
+ String(m.files.length),
52
+ `${(m.fragmentationScore * 100).toFixed(0)}%`,
53
+ m.totalTokens.toLocaleString(),
54
+ ]),
67
55
  }),
68
- '🧩 Fragmented Modules'
69
- );
56
+ });
70
57
  }
71
58
 
72
59
  if (summary.topExpensiveFiles.length > 0) {
73
- const expensiveRows = summary.topExpensiveFiles.map((f) => [
74
- f.file,
75
- `${f.contextBudget.toLocaleString()} tokens`,
76
- `<span class="issue-${f.severity}">${f.severity.toUpperCase()}</span>`,
77
- ]);
78
- body += wrapInCard(
79
- generateTable({
60
+ sections.push({
61
+ title: '💸 Most Expensive Files',
62
+ content: generateTable({
80
63
  headers: ['File', 'Context Budget', 'Severity'],
81
- rows: expensiveRows,
64
+ rows: summary.topExpensiveFiles.map((f) => [
65
+ f.file,
66
+ `${f.contextBudget.toLocaleString()} tokens`,
67
+ `<span class="issue-${f.severity}">${f.severity.toUpperCase()}</span>`,
68
+ ]),
82
69
  }),
83
- '💸 Most Expensive Files'
84
- );
70
+ });
85
71
  }
86
72
 
87
- const footer = generateReportFooter({
88
- title: 'Context Analysis Report',
89
- packageName: 'context-analyzer',
90
- packageUrl: 'https://github.com/caopengau/aiready-context-analyzer',
91
- bugUrl: 'https://github.com/caopengau/aiready-context-analyzer/issues',
92
- });
93
-
94
- return `${head}
95
- <body>
96
- ${body}
97
- ${footer}
98
- </body>
99
- </html>`;
73
+ return generateStandardHtmlReport(
74
+ {
75
+ title: 'Context Analysis Report',
76
+ packageName: 'context-analyzer',
77
+ packageUrl: 'https://github.com/caopengau/aiready-context-analyzer',
78
+ bugUrl: 'https://github.com/caopengau/aiready-context-analyzer/issues',
79
+ emoji: '🧠',
80
+ },
81
+ stats,
82
+ sections
83
+ );
100
84
  }