@aiready/context-analyzer 0.21.22 → 0.21.23

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 (61) hide show
  1. package/.turbo/turbo-build.log +26 -25
  2. package/.turbo/turbo-lint.log +5 -5
  3. package/.turbo/turbo-test.log +104 -41
  4. package/coverage/clover.xml +2615 -1242
  5. package/coverage/coverage-final.json +30 -13
  6. package/coverage/dist/chunk-64U3PNO3.mjs.html +367 -0
  7. package/coverage/dist/chunk-J3MUOWHC.mjs.html +5326 -0
  8. package/coverage/dist/index.html +146 -0
  9. package/coverage/{classifier.ts.html → dist/index.mjs.html} +537 -912
  10. package/coverage/index.html +84 -189
  11. package/coverage/src/analyzer.ts.html +88 -0
  12. package/coverage/src/analyzers/index.html +116 -0
  13. package/coverage/src/analyzers/python-context.ts.html +910 -0
  14. package/coverage/{ast-utils.ts.html → src/ast-utils.ts.html} +84 -54
  15. package/coverage/src/classifier.ts.html +892 -0
  16. package/coverage/src/classify/classification-patterns.ts.html +307 -0
  17. package/coverage/src/classify/file-classifiers.ts.html +973 -0
  18. package/coverage/src/classify/index.html +131 -0
  19. package/coverage/{cluster-detector.ts.html → src/cluster-detector.ts.html} +154 -91
  20. package/coverage/{defaults.ts.html → src/defaults.ts.html} +74 -65
  21. package/coverage/{graph-builder.ts.html → src/graph-builder.ts.html} +268 -229
  22. package/coverage/src/index.html +341 -0
  23. package/coverage/{index.ts.html → src/index.ts.html} +70 -13
  24. package/coverage/{scoring.ts.html → src/issue-analyzer.ts.html} +201 -261
  25. package/coverage/src/mapper.ts.html +439 -0
  26. package/coverage/{metrics.ts.html → src/metrics.ts.html} +201 -132
  27. package/coverage/src/orchestrator.ts.html +493 -0
  28. package/coverage/{provider.ts.html → src/provider.ts.html} +21 -21
  29. package/coverage/{remediation.ts.html → src/remediation.ts.html} +112 -52
  30. package/coverage/src/report/console-report.ts.html +415 -0
  31. package/coverage/src/report/html-report.ts.html +361 -0
  32. package/coverage/src/report/index.html +146 -0
  33. package/coverage/src/report/interactive-setup.ts.html +373 -0
  34. package/coverage/src/scoring.ts.html +895 -0
  35. package/coverage/src/semantic/co-usage.ts.html +340 -0
  36. package/coverage/src/semantic/consolidation.ts.html +223 -0
  37. package/coverage/src/semantic/domain-inference.ts.html +859 -0
  38. package/coverage/src/semantic/index.html +161 -0
  39. package/coverage/src/semantic/type-graph.ts.html +163 -0
  40. package/coverage/{summary.ts.html → src/summary.ts.html} +155 -275
  41. package/coverage/{types.ts.html → src/types.ts.html} +133 -31
  42. package/coverage/src/utils/dependency-graph-utils.ts.html +463 -0
  43. package/coverage/src/utils/index.html +131 -0
  44. package/coverage/src/utils/string-utils.ts.html +148 -0
  45. package/dist/chunk-J3MUOWHC.mjs +1747 -0
  46. package/dist/cli.js +59 -171
  47. package/dist/cli.mjs +1 -1
  48. package/dist/index.js +55 -167
  49. package/dist/index.mjs +1 -1
  50. package/package.json +2 -2
  51. package/src/__tests__/consolidation.test.ts +247 -0
  52. package/src/__tests__/defaults.test.ts +121 -0
  53. package/src/__tests__/domain-inference.test.ts +420 -0
  54. package/src/__tests__/issue-analyzer.test.ts +155 -0
  55. package/src/__tests__/orchestrator.test.ts +143 -0
  56. package/src/__tests__/python-context.test.ts +98 -0
  57. package/src/__tests__/report/console-report.test.ts +292 -0
  58. package/src/__tests__/report/html-report.test.ts +232 -0
  59. package/src/report/html-report.ts +58 -174
  60. package/coverage/analyzer.ts.html +0 -1369
  61. package/coverage/semantic-analysis.ts.html +0 -1201
@@ -3,15 +3,15 @@
3
3
  <html lang="en">
4
4
 
5
5
  <head>
6
- <title>Code coverage report for scoring.ts</title>
6
+ <title>Code coverage report for src/issue-analyzer.ts</title>
7
7
  <meta charset="utf-8" />
8
- <link rel="stylesheet" href="prettify.css" />
9
- <link rel="stylesheet" href="base.css" />
10
- <link rel="shortcut icon" type="image/x-icon" href="favicon.png" />
8
+ <link rel="stylesheet" href="../prettify.css" />
9
+ <link rel="stylesheet" href="../base.css" />
10
+ <link rel="shortcut icon" type="image/x-icon" href="../favicon.png" />
11
11
  <meta name="viewport" content="width=device-width, initial-scale=1" />
12
12
  <style type='text/css'>
13
13
  .coverage-summary .sorter {
14
- background-image: url(sort-arrow-sprite.png);
14
+ background-image: url(../sort-arrow-sprite.png);
15
15
  }
16
16
  </style>
17
17
  </head>
@@ -19,34 +19,34 @@
19
19
  <body>
20
20
  <div class='wrapper'>
21
21
  <div class='pad1'>
22
- <h1><a href="index.html">All files</a> scoring.ts</h1>
22
+ <h1><a href="../index.html">All files</a> / <a href="index.html">src</a> issue-analyzer.ts</h1>
23
23
  <div class='clearfix'>
24
24
 
25
25
  <div class='fl pad1y space-right2'>
26
- <span class="strong">87.32% </span>
26
+ <span class="strong">100% </span>
27
27
  <span class="quiet">Statements</span>
28
- <span class='fraction'>62/71</span>
28
+ <span class='fraction'>61/61</span>
29
29
  </div>
30
30
 
31
31
 
32
32
  <div class='fl pad1y space-right2'>
33
- <span class="strong">81.81% </span>
33
+ <span class="strong">83.78% </span>
34
34
  <span class="quiet">Branches</span>
35
- <span class='fraction'>72/88</span>
35
+ <span class='fraction'>31/37</span>
36
36
  </div>
37
37
 
38
38
 
39
39
  <div class='fl pad1y space-right2'>
40
- <span class="strong">66.66% </span>
40
+ <span class="strong">100% </span>
41
41
  <span class="quiet">Functions</span>
42
- <span class='fraction'>2/3</span>
42
+ <span class='fraction'>2/2</span>
43
43
  </div>
44
44
 
45
45
 
46
46
  <div class='fl pad1y space-right2'>
47
- <span class="strong">91.66% </span>
47
+ <span class="strong">100% </span>
48
48
  <span class="quiet">Lines</span>
49
- <span class='fraction'>55/60</span>
49
+ <span class='fraction'>57/57</span>
50
50
  </div>
51
51
 
52
52
 
@@ -221,27 +221,7 @@
221
221
  <a name='L156'></a><a href='#L156'>156</a>
222
222
  <a name='L157'></a><a href='#L157'>157</a>
223
223
  <a name='L158'></a><a href='#L158'>158</a>
224
- <a name='L159'></a><a href='#L159'>159</a>
225
- <a name='L160'></a><a href='#L160'>160</a>
226
- <a name='L161'></a><a href='#L161'>161</a>
227
- <a name='L162'></a><a href='#L162'>162</a>
228
- <a name='L163'></a><a href='#L163'>163</a>
229
- <a name='L164'></a><a href='#L164'>164</a>
230
- <a name='L165'></a><a href='#L165'>165</a>
231
- <a name='L166'></a><a href='#L166'>166</a>
232
- <a name='L167'></a><a href='#L167'>167</a>
233
- <a name='L168'></a><a href='#L168'>168</a>
234
- <a name='L169'></a><a href='#L169'>169</a>
235
- <a name='L170'></a><a href='#L170'>170</a>
236
- <a name='L171'></a><a href='#L171'>171</a>
237
- <a name='L172'></a><a href='#L172'>172</a>
238
- <a name='L173'></a><a href='#L173'>173</a>
239
- <a name='L174'></a><a href='#L174'>174</a>
240
- <a name='L175'></a><a href='#L175'>175</a>
241
- <a name='L176'></a><a href='#L176'>176</a>
242
- <a name='L177'></a><a href='#L177'>177</a>
243
- <a name='L178'></a><a href='#L178'>178</a>
244
- <a name='L179'></a><a href='#L179'>179</a></td><td class="line-coverage quiet"><span class="cline-any cline-neutral">&nbsp;</span>
224
+ <a name='L159'></a><a href='#L159'>159</a></td><td class="line-coverage quiet"><span class="cline-any cline-neutral">&nbsp;</span>
245
225
  <span class="cline-any cline-neutral">&nbsp;</span>
246
226
  <span class="cline-any cline-neutral">&nbsp;</span>
247
227
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -264,136 +244,119 @@
264
244
  <span class="cline-any cline-neutral">&nbsp;</span>
265
245
  <span class="cline-any cline-neutral">&nbsp;</span>
266
246
  <span class="cline-any cline-neutral">&nbsp;</span>
267
- <span class="cline-any cline-yes">7x</span>
268
247
  <span class="cline-any cline-neutral">&nbsp;</span>
269
- <span class="cline-any cline-yes">8x</span>
270
248
  <span class="cline-any cline-neutral">&nbsp;</span>
271
249
  <span class="cline-any cline-neutral">&nbsp;</span>
272
- <span class="cline-any cline-yes">8x</span>
273
250
  <span class="cline-any cline-neutral">&nbsp;</span>
274
- <span class="cline-any cline-yes">7x</span>
275
251
  <span class="cline-any cline-neutral">&nbsp;</span>
276
252
  <span class="cline-any cline-neutral">&nbsp;</span>
277
- <span class="cline-any cline-yes">8x</span>
278
253
  <span class="cline-any cline-neutral">&nbsp;</span>
279
254
  <span class="cline-any cline-neutral">&nbsp;</span>
280
- <span class="cline-any cline-yes">8x</span>
281
255
  <span class="cline-any cline-neutral">&nbsp;</span>
282
- <span class="cline-any cline-yes">7x</span>
283
256
  <span class="cline-any cline-neutral">&nbsp;</span>
284
- <span class="cline-any cline-yes">8x</span>
285
- <span class="cline-any cline-yes">8x</span>
286
257
  <span class="cline-any cline-neutral">&nbsp;</span>
287
258
  <span class="cline-any cline-neutral">&nbsp;</span>
288
- <span class="cline-any cline-yes">8x</span>
289
- <span class="cline-any cline-neutral">&nbsp;</span>
290
- <span class="cline-any cline-yes">7x</span>
291
- <span class="cline-any cline-neutral">&nbsp;</span>
292
- <span class="cline-any cline-neutral">&nbsp;</span>
293
- <span class="cline-any cline-yes">8x</span>
294
- <span class="cline-any cline-neutral">&nbsp;</span>
295
- <span class="cline-any cline-yes">15x</span>
296
- <span class="cline-any cline-yes">7x</span>
297
- <span class="cline-any cline-yes">8x</span>
298
259
  <span class="cline-any cline-neutral">&nbsp;</span>
299
- <span class="cline-any cline-yes">15x</span>
300
260
  <span class="cline-any cline-neutral">&nbsp;</span>
301
261
  <span class="cline-any cline-neutral">&nbsp;</span>
302
262
  <span class="cline-any cline-neutral">&nbsp;</span>
303
263
  <span class="cline-any cline-neutral">&nbsp;</span>
304
- <span class="cline-any cline-yes">15x</span>
305
- <span class="cline-any cline-yes">15x</span>
306
264
  <span class="cline-any cline-neutral">&nbsp;</span>
307
- <span class="cline-any cline-yes">15x</span>
265
+ <span class="cline-any cline-yes">16x</span>
308
266
  <span class="cline-any cline-neutral">&nbsp;</span>
267
+ <span class="cline-any cline-yes">16x</span>
268
+ <span class="cline-any cline-yes">16x</span>
269
+ <span class="cline-any cline-yes">16x</span>
270
+ <span class="cline-any cline-yes">16x</span>
309
271
  <span class="cline-any cline-neutral">&nbsp;</span>
310
- <span class="cline-any cline-yes">7x</span>
311
272
  <span class="cline-any cline-neutral">&nbsp;</span>
273
+ <span class="cline-any cline-yes">16x</span>
274
+ <span class="cline-any cline-yes">1x</span>
275
+ <span class="cline-any cline-yes">1x</span>
276
+ <span class="cline-any cline-yes">1x</span>
312
277
  <span class="cline-any cline-neutral">&nbsp;</span>
313
278
  <span class="cline-any cline-neutral">&nbsp;</span>
279
+ <span class="cline-any cline-yes">1x</span>
314
280
  <span class="cline-any cline-neutral">&nbsp;</span>
315
281
  <span class="cline-any cline-neutral">&nbsp;</span>
316
282
  <span class="cline-any cline-neutral">&nbsp;</span>
283
+ <span class="cline-any cline-yes">16x</span>
284
+ <span class="cline-any cline-yes">1x</span>
285
+ <span class="cline-any cline-yes">1x</span>
286
+ <span class="cline-any cline-yes">1x</span>
287
+ <span class="cline-any cline-yes">1x</span>
317
288
  <span class="cline-any cline-yes">15x</span>
318
- <span class="cline-any cline-yes">9x</span>
319
- <span class="cline-any cline-neutral">&nbsp;</span>
320
- <span class="cline-any cline-neutral">&nbsp;</span>
321
- <span class="cline-any cline-neutral">&nbsp;</span>
322
- <span class="cline-any cline-neutral">&nbsp;</span>
323
- <span class="cline-any cline-neutral">&nbsp;</span>
324
- <span class="cline-any cline-neutral">&nbsp;</span>
325
- <span class="cline-any cline-yes">8x</span>
289
+ <span class="cline-any cline-yes">1x</span>
326
290
  <span class="cline-any cline-yes">1x</span>
327
291
  <span class="cline-any cline-neutral">&nbsp;</span>
328
- <span class="cline-any cline-yes">7x</span>
329
- <span class="cline-any cline-yes">2x</span>
330
292
  <span class="cline-any cline-neutral">&nbsp;</span>
293
+ <span class="cline-any cline-yes">1x</span>
294
+ <span class="cline-any cline-yes">1x</span>
331
295
  <span class="cline-any cline-neutral">&nbsp;</span>
332
296
  <span class="cline-any cline-neutral">&nbsp;</span>
333
- <span class="cline-any cline-yes">8x</span>
334
- <span class="cline-any cline-yes">2x</span>
335
297
  <span class="cline-any cline-neutral">&nbsp;</span>
336
- <span class="cline-any cline-yes">7x</span>
298
+ <span class="cline-any cline-yes">16x</span>
299
+ <span class="cline-any cline-yes">1x</span>
337
300
  <span class="cline-any cline-yes">1x</span>
338
301
  <span class="cline-any cline-neutral">&nbsp;</span>
339
302
  <span class="cline-any cline-neutral">&nbsp;</span>
303
+ <span class="cline-any cline-yes">1x</span>
340
304
  <span class="cline-any cline-neutral">&nbsp;</span>
341
- <span class="cline-any cline-yes">9x</span>
342
305
  <span class="cline-any cline-neutral">&nbsp;</span>
343
- <span class="cline-any cline-yes">8x</span>
306
+ <span class="cline-any cline-yes">1x</span>
344
307
  <span class="cline-any cline-yes">15x</span>
345
- <span class="cline-any cline-yes">10x</span>
346
- <span class="cline-any cline-neutral">&nbsp;</span>
347
- <span class="cline-any cline-neutral">&nbsp;</span>
348
- <span class="cline-any cline-yes">2x</span>
349
- <span class="cline-any cline-neutral">&nbsp;</span>
350
- <span class="cline-any cline-neutral">&nbsp;</span>
308
+ <span class="cline-any cline-yes">1x</span>
309
+ <span class="cline-any cline-yes">1x</span>
351
310
  <span class="cline-any cline-neutral">&nbsp;</span>
352
311
  <span class="cline-any cline-neutral">&nbsp;</span>
353
- <span class="cline-any cline-yes">15x</span>
312
+ <span class="cline-any cline-yes">1x</span>
313
+ <span class="cline-any cline-yes">1x</span>
354
314
  <span class="cline-any cline-neutral">&nbsp;</span>
355
- <span class="cline-any cline-yes">15x</span>
356
- <span class="cline-any cline-yes">9x</span>
357
- <span class="cline-any cline-yes">4x</span>
358
315
  <span class="cline-any cline-neutral">&nbsp;</span>
359
316
  <span class="cline-any cline-neutral">&nbsp;</span>
317
+ <span class="cline-any cline-yes">16x</span>
318
+ <span class="cline-any cline-yes">1x</span>
319
+ <span class="cline-any cline-yes">1x</span>
360
320
  <span class="cline-any cline-neutral">&nbsp;</span>
361
321
  <span class="cline-any cline-neutral">&nbsp;</span>
322
+ <span class="cline-any cline-yes">1x</span>
362
323
  <span class="cline-any cline-neutral">&nbsp;</span>
363
324
  <span class="cline-any cline-neutral">&nbsp;</span>
325
+ <span class="cline-any cline-yes">1x</span>
364
326
  <span class="cline-any cline-yes">15x</span>
365
- <span class="cline-any cline-yes">9x</span>
366
- <span class="cline-any cline-yes">10x</span>
367
- <span class="cline-any cline-neutral">&nbsp;</span>
368
- <span class="cline-any cline-neutral">&nbsp;</span>
369
- <span class="cline-any cline-yes">2x</span>
327
+ <span class="cline-any cline-yes">1x</span>
328
+ <span class="cline-any cline-yes">1x</span>
329
+ <span class="cline-any cline-yes">1x</span>
330
+ <span class="cline-any cline-yes">1x</span>
370
331
  <span class="cline-any cline-neutral">&nbsp;</span>
371
332
  <span class="cline-any cline-neutral">&nbsp;</span>
372
333
  <span class="cline-any cline-neutral">&nbsp;</span>
373
- <span class="cline-any cline-yes">7x</span>
374
- <span class="cline-any cline-yes">10x</span>
375
- <span class="cline-any cline-yes">2x</span>
376
- <span class="cline-any cline-yes">8x</span>
334
+ <span class="cline-any cline-yes">16x</span>
335
+ <span class="cline-any cline-yes">1x</span>
336
+ <span class="cline-any cline-yes">1x</span>
377
337
  <span class="cline-any cline-yes">1x</span>
378
338
  <span class="cline-any cline-neutral">&nbsp;</span>
379
339
  <span class="cline-any cline-neutral">&nbsp;</span>
380
- <span class="cline-any cline-neutral">&nbsp;</span>
381
- <span class="cline-any cline-neutral">&nbsp;</span>
382
- <span class="cline-any cline-yes">7x</span>
383
340
  <span class="cline-any cline-yes">1x</span>
384
- <span class="cline-any cline-yes">9x</span>
385
- <span class="cline-any cline-yes">15x</span>
341
+ <span class="cline-any cline-yes">1x</span>
386
342
  <span class="cline-any cline-neutral">&nbsp;</span>
387
343
  <span class="cline-any cline-neutral">&nbsp;</span>
344
+ <span class="cline-any cline-yes">16x</span>
345
+ <span class="cline-any cline-yes">8x</span>
346
+ <span class="cline-any cline-yes">8x</span>
388
347
  <span class="cline-any cline-neutral">&nbsp;</span>
389
348
  <span class="cline-any cline-neutral">&nbsp;</span>
390
- <span class="cline-any cline-yes">15x</span>
391
349
  <span class="cline-any cline-neutral">&nbsp;</span>
350
+ <span class="cline-any cline-yes">16x</span>
351
+ <span class="cline-any cline-yes">1x</span>
352
+ <span class="cline-any cline-yes">1x</span>
353
+ <span class="cline-any cline-yes">1x</span>
354
+ <span class="cline-any cline-yes">1x</span>
392
355
  <span class="cline-any cline-neutral">&nbsp;</span>
393
356
  <span class="cline-any cline-neutral">&nbsp;</span>
394
- <span class="cline-any cline-yes">15x</span>
357
+ <span class="cline-any cline-yes">16x</span>
358
+ <span class="cline-any cline-neutral">&nbsp;</span>
395
359
  <span class="cline-any cline-neutral">&nbsp;</span>
396
- <span class="cline-any cline-yes">8x</span>
397
360
  <span class="cline-any cline-neutral">&nbsp;</span>
398
361
  <span class="cline-any cline-neutral">&nbsp;</span>
399
362
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -407,195 +370,172 @@
407
370
  <span class="cline-any cline-neutral">&nbsp;</span>
408
371
  <span class="cline-any cline-neutral">&nbsp;</span>
409
372
  <span class="cline-any cline-neutral">&nbsp;</span>
373
+ <span class="cline-any cline-yes">24x</span>
374
+ <span class="cline-any cline-yes">24x</span>
410
375
  <span class="cline-any cline-neutral">&nbsp;</span>
411
376
  <span class="cline-any cline-neutral">&nbsp;</span>
412
377
  <span class="cline-any cline-neutral">&nbsp;</span>
413
378
  <span class="cline-any cline-neutral">&nbsp;</span>
414
379
  <span class="cline-any cline-neutral">&nbsp;</span>
415
380
  <span class="cline-any cline-neutral">&nbsp;</span>
416
- <span class="cline-any cline-no">&nbsp;</span>
417
- <span class="cline-any cline-no">&nbsp;</span>
418
- <span class="cline-any cline-no">&nbsp;</span>
419
- <span class="cline-any cline-no">&nbsp;</span>
420
- <span class="cline-any cline-no">&nbsp;</span>
421
381
  <span class="cline-any cline-neutral">&nbsp;</span>
422
- <span class="cline-any cline-neutral">&nbsp;</span></td><td class="text"><pre class="prettyprint lang-js">import {
423
- calculateMonthlyCost,
424
- calculateProductivityImpact,
425
- DEFAULT_COST_CONFIG,
426
- type CostConfig,
427
- ToolName,
428
- } from '@aiready/core';
429
- import type { ToolScoringOutput } from '@aiready/core';
430
- import type { ContextSummary } from './types';
382
+ <span class="cline-any cline-neutral">&nbsp;</span></td><td class="text"><pre class="prettyprint lang-js">import { Severity } from '@aiready/core';
431
383
  &nbsp;
432
384
  /**
433
- * Calculate AI Readiness Score for context efficiency (0-100)
385
+ * Internal issue analysis logic
386
+ */
387
+ /**
388
+ * Analyzes architectural issues related to AI context windows.
389
+ * Detects problems like high import depth, large context budgets,
390
+ * circular dependencies, and low cohesion.
391
+ *
392
+ * @param params - Combined metrics and graph data for a module
393
+ * @returns List of identified issues with severity and suggestions
434
394
  */
435
- export function calculateContextScore(
436
- summary: ContextSummary,
437
- costConfig?: Partial&lt;CostConfig&gt;
438
- ): ToolScoringOutput {
395
+ export function analyzeIssues(params: {
396
+ file: string;
397
+ importDepth: number;
398
+ contextBudget: number;
399
+ cohesionScore: number;
400
+ fragmentationScore: number;
401
+ maxDepth: number;
402
+ maxContextBudget: number;
403
+ minCohesion: number;
404
+ maxFragmentation: number;
405
+ circularDeps: string[][];
406
+ }): {
407
+ severity: Severity;
408
+ issues: string[];
409
+ recommendations: string[];
410
+ potentialSavings: number;
411
+ } {
439
412
  const {
440
- avgContextBudget,
413
+ file,
414
+ importDepth,
415
+ contextBudget,
416
+ cohesionScore,
417
+ fragmentationScore,
418
+ maxDepth,
441
419
  maxContextBudget,
442
- avgImportDepth,
443
- maxImportDepth,
444
- avgFragmentation,
445
- criticalIssues,
446
- majorIssues,
447
- } = summary;
448
- &nbsp;
449
- const budgetScore =
450
- avgContextBudget &lt; 5000
451
- ? 100
452
- : Math.max(0, 100 - (avgContextBudget - 5000) / 150);
453
- &nbsp;
454
- const depthScore =
455
- avgImportDepth &lt; 5 ? 100 : Math.max(0, 100 - (avgImportDepth - 5) * 10);
456
- &nbsp;
457
- const fragmentationScore =
458
- avgFragmentation &lt; 0.3
459
- ? 100
460
- : Math.max(0, 100 - (avgFragmentation - 0.3) * 200);
420
+ minCohesion,
421
+ maxFragmentation,
422
+ circularDeps,
423
+ } = params;
461
424
  &nbsp;
462
- const criticalPenalty = criticalIssues * 10;
463
- const majorPenalty = majorIssues * 3;
425
+ const issues: string[] = [];
426
+ const recommendations: string[] = [];
427
+ let severity: Severity = Severity.Info;
428
+ let potentialSavings = 0;
464
429
  &nbsp;
465
- const maxBudgetPenalty =
466
- maxContextBudget &gt; 15000
467
- ? Math.min(20, (maxContextBudget - 15000) / 500)
468
- : 0;
469
- &nbsp;
470
- const rawScore =
471
- budgetScore * 0.4 + depthScore * 0.3 + fragmentationScore * 0.3;
472
- const finalScore =
473
- rawScore - criticalPenalty - majorPenalty - maxBudgetPenalty;
474
- &nbsp;
475
- const score = Math.max(0, Math.min(100, Math.round(finalScore)));
476
- &nbsp;
477
- const factors = [
478
- {
479
- name: 'Context Budget',
480
- impact: Math.round(budgetScore * 0.4 - 40),
481
- description: `Avg ${Math.round(avgContextBudget)} tokens per file ${avgContextBudget &lt; 5000 ? '(excellent)' : avgContextBudget &lt; 10000 ? <span class="branch-0 cbranch-no" title="branch not covered" >'(acceptable)' : '</span>(high)'}`,
482
- },
483
- {
484
- name: 'Import Depth',
485
- impact: Math.round(depthScore * 0.3 - 30),
486
- description: `Avg ${avgImportDepth.toFixed(1)} levels ${avgImportDepth &lt; 5 ? '(excellent)' : avgImportDepth &lt; 8 ? <span class="branch-0 cbranch-no" title="branch not covered" >'(acceptable)' : '</span>(deep)'}`,
487
- },
488
- {
489
- name: 'Fragmentation',
490
- impact: Math.round(fragmentationScore * 0.3 - 30),
491
- description: `${(avgFragmentation * 100).toFixed(0)}% fragmentation ${avgFragmentation &lt; 0.3 ? '(well-organized)' : avgFragmentation &lt; 0.5 ? <span class="branch-0 cbranch-no" title="branch not covered" >'(moderate)' : '</span>(high)'}`,
492
- },<span class="branch-0 cbranch-no" title="branch not covered" ></span>
493
- ];
494
- &nbsp;
495
- if (criticalIssues &gt; 0) {
496
- factors.push({
497
- name: 'Critical Issues',
498
- impact: -criticalPenalty,
499
- description: `${criticalIssues} critical context issue${criticalIssues &gt; 1 ? 's' : <span class="branch-1 cbranch-no" title="branch not covered" >''}</span>`,
500
- });
501
- }
502
- <span class="branch-0 cbranch-no" title="branch not covered" ></span>
503
- if (majorIssues &gt; 0) {
504
- factors.push({
505
- name: 'Major Issues',
506
- impact: -majorPenalty,
507
- description: `${majorIssues} major context issue${majorIssues &gt; 1 ? 's' : ''}`,
508
- });
509
- }
510
- <span class="branch-1 cbranch-no" title="branch not covered" ></span>
511
- if (maxBudgetPenalty &gt; 0) {
512
- factors.push({
513
- name: 'Extreme File Detected',
514
- impact: -Math.round(maxBudgetPenalty),
515
- description: `One file requires ${Math.round(maxContextBudget)} tokens (very high)`,
516
- });
430
+ // Check circular dependencies (CRITICAL)
431
+ if (circularDeps.length &gt; 0) {
432
+ severity = Severity.Critical;
433
+ issues.push(`Part of ${circularDeps.length} circular dependency chain(s)`);
434
+ recommendations.push(
435
+ 'Break circular dependencies by extracting interfaces or using dependency injection'
436
+ );
437
+ potentialSavings += contextBudget * 0.2;
517
438
  }
518
- <span class="branch-1 cbranch-no" title="branch not covered" ></span>
519
- const recommendations: ToolScoringOutput['recommendations'] = [];
520
439
  &nbsp;
521
- if (avgContextBudget &gt; 10000) {
522
- const estimatedImpact = Math.min(
523
- 15,
524
- Math.round((avgContextBudget - 10000) / 1000)
440
+ // Check import depth
441
+ if (importDepth &gt; maxDepth * 1.5) {
442
+ severity = Severity.Critical;
443
+ issues.push(`Import depth ${importDepth} exceeds limit by 50%`);
444
+ recommendations.push('Flatten dependency tree or use facade pattern');
445
+ potentialSavings += contextBudget * 0.3;
446
+ } else if (importDepth &gt; maxDepth) {
447
+ <span class="missing-if-branch" title="else path not taken" >E</span>if (severity !== Severity.Critical) severity = Severity.Major;
448
+ issues.push(
449
+ `Import depth ${importDepth} exceeds recommended maximum ${maxDepth}`
525
450
  );
526
- recommendations.push({
527
- action: 'Reduce file dependencies to lower context requirements',
528
- estimatedImpact,
529
- priority: 'high',
530
- });
451
+ recommendations.push('Consider reducing dependency depth');
452
+ potentialSavings += contextBudget * 0.15;
531
453
  }
532
454
  &nbsp;
533
- if (avgImportDepth &gt; 8) {
534
- const estimatedImpact = Math.min(10, Math.round((avgImportDepth - 8) * 2));
535
- recommendations.push({
536
- action: 'Flatten import chains to reduce depth',
537
- estimatedImpact,
538
- priority: avgImportDepth &gt; 10 ? 'high' : 'medium',
539
- });
455
+ // Check context budget
456
+ if (contextBudget &gt; maxContextBudget * 1.5) {
457
+ severity = Severity.Critical;
458
+ issues.push(
459
+ `Context budget ${contextBudget.toLocaleString()} tokens is 50% over limit`
460
+ );
461
+ recommendations.push(
462
+ 'Split into smaller modules or reduce dependency tree'
463
+ );
464
+ potentialSavings += contextBudget * 0.4;
465
+ } else if (contextBudget &gt; maxContextBudget) {
466
+ <span class="missing-if-branch" title="else path not taken" >E</span>if (severity !== Severity.Critical) severity = Severity.Major;
467
+ issues.push(
468
+ `Context budget ${contextBudget.toLocaleString()} exceeds ${maxContextBudget.toLocaleString()}`
469
+ );
470
+ recommendations.push('Reduce file size or dependencies');
471
+ potentialSavings += contextBudget * 0.2;
540
472
  }
541
473
  &nbsp;
542
- if (avgFragmentation &gt; 0.5) {
543
- const estimatedImpact = Math.min(
544
- 12,
545
- Math.round((avgFragmentation - 0.5) * 40)
474
+ // Check cohesion
475
+ if (cohesionScore &lt; minCohesion * 0.5) {
476
+ <span class="missing-if-branch" title="else path not taken" >E</span>if (severity !== Severity.Critical) severity = Severity.Major;
477
+ issues.push(
478
+ `Very low cohesion (${(cohesionScore * 100).toFixed(0)}%) - mixed concerns`
479
+ );
480
+ recommendations.push(
481
+ 'Split file by domain - separate unrelated functionality'
546
482
  );
547
- recommendations.push({
548
- action: 'Consolidate related code into cohesive modules',
549
- estimatedImpact,
550
- priority: 'medium',
551
- });
483
+ potentialSavings += contextBudget * 0.25;
484
+ } else if (cohesionScore &lt; minCohesion) {
485
+ <span class="missing-if-branch" title="else path not taken" >E</span>if (severity === Severity.Info) severity = Severity.Minor;
486
+ issues.push(`Low cohesion (${(cohesionScore * 100).toFixed(0)}%)`);
487
+ recommendations.push('Consider grouping related exports together');
488
+ potentialSavings += contextBudget * 0.1;
552
489
  }
553
490
  &nbsp;
554
- if (maxContextBudget &gt; 20000) {
555
- recommendations.push({
556
- action: `Split large file (${Math.round(maxContextBudget)} tokens) into smaller modules`,
557
- estimatedImpact: 8,
558
- priority: 'high',
559
- });
491
+ // Check fragmentation
492
+ if (fragmentationScore &gt; maxFragmentation) {
493
+ <span class="missing-if-branch" title="else path not taken" >E</span>if (severity === Severity.Info || <span class="branch-1 cbranch-no" title="branch not covered" >severity === Severity.Minor)</span>
494
+ severity = Severity.Minor;
495
+ issues.push(
496
+ `High fragmentation (${(fragmentationScore * 100).toFixed(0)}%) - scattered implementation`
497
+ );
498
+ recommendations.push('Consolidate with related files in same domain');
499
+ potentialSavings += contextBudget * 0.3;
560
500
  }
561
501
  &nbsp;
562
- const cfg = { ...DEFAULT_COST_CONFIG, ...costConfig };
563
- const estimatedMonthlyCost = calculateMonthlyCost(
564
- avgContextBudget * (summary.totalFiles || 1),
565
- cfg
566
- );
502
+ if (issues.length === 0) {
503
+ issues.push('No significant issues detected');
504
+ recommendations.push('File is well-structured for AI context usage');
505
+ }
567
506
  &nbsp;
568
- const issues = [
569
- ...Array(criticalIssues).fill({ severity: 'critical' as const }),
570
- ...Array(majorIssues).fill({ severity: 'major' as const }),
571
- ];
572
- const productivityImpact = calculateProductivityImpact(issues);
507
+ // Detect build artifacts
508
+ if (isBuildArtifact(file)) {
509
+ issues.push('Detected build artifact (bundled/output file)');
510
+ recommendations.push('Exclude build outputs from analysis');
511
+ severity = Severity.Info;
512
+ potentialSavings = 0;
513
+ }
573
514
  &nbsp;
574
515
  return {
575
- toolName: ToolName.ContextAnalyzer,
576
- score,
577
- rawMetrics: {
578
- avgContextBudget: Math.round(avgContextBudget),
579
- maxContextBudget: Math.round(maxContextBudget),
580
- avgImportDepth: Math.round(avgImportDepth * 10) / 10,
581
- maxImportDepth,
582
- avgFragmentation: Math.round(avgFragmentation * 100) / 100,
583
- criticalIssues,
584
- majorIssues,
585
- estimatedMonthlyCost,
586
- estimatedDeveloperHours: productivityImpact.totalHours,
587
- },
588
- factors,
516
+ severity,
517
+ issues,
589
518
  recommendations,
519
+ potentialSavings: Math.floor(potentialSavings),
590
520
  };
591
521
  }
592
522
  &nbsp;
593
- export function <span class="fstat-no" title="function not covered" >mapScoreToRating(s</span>core: number): string {
594
- <span class="cstat-no" title="statement not covered" > if (score &gt;= 90) <span class="cstat-no" title="statement not covered" >return 'excellent';</span></span>
595
- <span class="cstat-no" title="statement not covered" > if (score &gt;= 75) <span class="cstat-no" title="statement not covered" >return 'good';</span></span>
596
- <span class="cstat-no" title="statement not covered" > if (score &gt;= 60) <span class="cstat-no" title="statement not covered" >return 'fair';</span></span>
597
- <span class="cstat-no" title="statement not covered" > if (score &gt;= 40) <span class="cstat-no" title="statement not covered" >return 'needs work';</span></span>
598
- <span class="cstat-no" title="statement not covered" > return 'critical';</span>
523
+ /**
524
+ * Determines if a file path belongs to a build artifact or dependency folder.
525
+ * Helps exclude generated files from analysis to prevent false positives.
526
+ *
527
+ * @param filePath - The path to check
528
+ * @returns True if the file is a build artifact, false otherwise
529
+ */
530
+ export function isBuildArtifact(filePath: string): boolean {
531
+ const lower = filePath.toLowerCase();
532
+ return (
533
+ lower.includes('/node_modules/') ||
534
+ lower.includes('/dist/') ||
535
+ lower.includes('/build/') ||
536
+ lower.includes('/out/') ||
537
+ lower.includes('/.next/')
538
+ );
599
539
  }
600
540
  &nbsp;</pre></td></tr></table></pre>
601
541
 
@@ -604,16 +544,16 @@ export function <span class="fstat-no" title="function not covered" >mapScoreToR
604
544
  <div class='footer quiet pad2 space-top1 center small'>
605
545
  Code coverage generated by
606
546
  <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
607
- at 2026-03-09T02:34:18.551Z
547
+ at 2026-03-21T12:52:37.698Z
608
548
  </div>
609
- <script src="prettify.js"></script>
549
+ <script src="../prettify.js"></script>
610
550
  <script>
611
551
  window.onload = function () {
612
552
  prettyPrint();
613
553
  };
614
554
  </script>
615
- <script src="sorter.js"></script>
616
- <script src="block-navigation.js"></script>
555
+ <script src="../sorter.js"></script>
556
+ <script src="../block-navigation.js"></script>
617
557
  </body>
618
558
  </html>
619
559