@principal-ade/code-quality-panels 0.1.19 → 0.1.21

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 (40) hide show
  1. package/README.md +27 -27
  2. package/dist/panels.bundle.js +1661 -800
  3. package/dist/panels.bundle.js.map +1 -1
  4. package/dist/src/components/LensDataDebugPanel.d.ts +2 -2
  5. package/dist/src/components/LensDataDebugPanel.d.ts.map +1 -1
  6. package/dist/src/components/LensDataDebugPanel.stories.d.ts +2 -2
  7. package/dist/src/components/LensDataDebugPanel.stories.d.ts.map +1 -1
  8. package/dist/src/components/QualityEmptyState.d.ts +2 -2
  9. package/dist/src/components/QualityEmptyState.d.ts.map +1 -1
  10. package/dist/src/components/QualityHexagon.d.ts +16 -10
  11. package/dist/src/components/QualityHexagon.d.ts.map +1 -1
  12. package/dist/src/components/QualityHexagon.stories.d.ts +2 -2
  13. package/dist/src/components/QualityHexagon.stories.d.ts.map +1 -1
  14. package/dist/src/components/QualityMetricsList.d.ts +4 -4
  15. package/dist/src/components/QualityMetricsList.d.ts.map +1 -1
  16. package/dist/src/components/QualityMetricsList.stories.d.ts +2 -2
  17. package/dist/src/components/QualityMetricsList.stories.d.ts.map +1 -1
  18. package/dist/src/components/RepositoryQualityGrid.d.ts +3 -3
  19. package/dist/src/components/RepositoryQualityGrid.d.ts.map +1 -1
  20. package/dist/src/components/RepositoryQualityGrid.stories.d.ts +2 -2
  21. package/dist/src/components/RepositoryQualityGrid.stories.d.ts.map +1 -1
  22. package/dist/src/components/index.d.ts +5 -5
  23. package/dist/src/index.d.ts +7 -7
  24. package/dist/src/index.d.ts.map +1 -1
  25. package/dist/src/mocks/panelContext.d.ts +2 -2
  26. package/dist/src/mocks/panelContext.d.ts.map +1 -1
  27. package/dist/src/panels/LensDataDebugPanel.d.ts +2 -2
  28. package/dist/src/panels/LensDataDebugPanel.d.ts.map +1 -1
  29. package/dist/src/panels/LensDataDebugPanel.stories.d.ts +1 -1
  30. package/dist/src/panels/LensDataDebugPanel.stories.d.ts.map +1 -1
  31. package/dist/src/panels/QualityHexagonPanel.d.ts +2 -2
  32. package/dist/src/panels/QualityHexagonPanel.d.ts.map +1 -1
  33. package/dist/src/panels/QualityHexagonPanel.stories.d.ts +1 -1
  34. package/dist/src/panels/QualityHexagonPanel.stories.d.ts.map +1 -1
  35. package/dist/src/panels/RepositoryQualityGridPanel.d.ts +2 -2
  36. package/dist/src/panels/RepositoryQualityGridPanel.d.ts.map +1 -1
  37. package/dist/src/panels/RepositoryQualityGridPanel.stories.d.ts +1 -1
  38. package/dist/src/panels/RepositoryQualityGridPanel.stories.d.ts.map +1 -1
  39. package/dist/src/types/index.d.ts +1 -1
  40. package/package.json +1 -1
@@ -106,7 +106,7 @@ const createLucideIcon = (iconName, iconNode) => {
106
106
  * This source code is licensed under the ISC license.
107
107
  * See the LICENSE file in the root directory of this source tree.
108
108
  */
109
- const __iconNode$e = [
109
+ const __iconNode$f = [
110
110
  ["path", { d: "M12 7v14", key: "1akyts" }],
111
111
  [
112
112
  "path",
@@ -116,14 +116,14 @@ const __iconNode$e = [
116
116
  }
117
117
  ]
118
118
  ];
119
- const BookOpen = createLucideIcon("book-open", __iconNode$e);
119
+ const BookOpen = createLucideIcon("book-open", __iconNode$f);
120
120
  /**
121
121
  * @license lucide-react v0.552.0 - ISC
122
122
  *
123
123
  * This source code is licensed under the ISC license.
124
124
  * See the LICENSE file in the root directory of this source tree.
125
125
  */
126
- const __iconNode$d = [
126
+ const __iconNode$e = [
127
127
  [
128
128
  "path",
129
129
  { d: "M8 3H7a2 2 0 0 0-2 2v5a2 2 0 0 1-2 2 2 2 0 0 1 2 2v5c0 1.1.9 2 2 2h1", key: "ezmyqa" }
@@ -136,14 +136,14 @@ const __iconNode$d = [
136
136
  }
137
137
  ]
138
138
  ];
139
- const Braces = createLucideIcon("braces", __iconNode$d);
139
+ const Braces = createLucideIcon("braces", __iconNode$e);
140
140
  /**
141
141
  * @license lucide-react v0.552.0 - ISC
142
142
  *
143
143
  * This source code is licensed under the ISC license.
144
144
  * See the LICENSE file in the root directory of this source tree.
145
145
  */
146
- const __iconNode$c = [
146
+ const __iconNode$d = [
147
147
  ["path", { d: "M12 20v-9", key: "1qisl0" }],
148
148
  ["path", { d: "M14 7a4 4 0 0 1 4 4v3a6 6 0 0 1-12 0v-3a4 4 0 0 1 4-4z", key: "uouzyp" }],
149
149
  ["path", { d: "M14.12 3.88 16 2", key: "qol33r" }],
@@ -156,41 +156,41 @@ const __iconNode$c = [
156
156
  ["path", { d: "m8 2 1.88 1.88", key: "fmnt4t" }],
157
157
  ["path", { d: "M9 7.13V6a3 3 0 1 1 6 0v1.13", key: "1vgav8" }]
158
158
  ];
159
- const Bug = createLucideIcon("bug", __iconNode$c);
159
+ const Bug = createLucideIcon("bug", __iconNode$d);
160
160
  /**
161
161
  * @license lucide-react v0.552.0 - ISC
162
162
  *
163
163
  * This source code is licensed under the ISC license.
164
164
  * See the LICENSE file in the root directory of this source tree.
165
165
  */
166
- const __iconNode$b = [["path", { d: "M20 6 9 17l-5-5", key: "1gmf2c" }]];
167
- const Check = createLucideIcon("check", __iconNode$b);
166
+ const __iconNode$c = [["path", { d: "M20 6 9 17l-5-5", key: "1gmf2c" }]];
167
+ const Check = createLucideIcon("check", __iconNode$c);
168
168
  /**
169
169
  * @license lucide-react v0.552.0 - ISC
170
170
  *
171
171
  * This source code is licensed under the ISC license.
172
172
  * See the LICENSE file in the root directory of this source tree.
173
173
  */
174
- const __iconNode$a = [["path", { d: "m9 18 6-6-6-6", key: "mthhwq" }]];
175
- const ChevronRight = createLucideIcon("chevron-right", __iconNode$a);
174
+ const __iconNode$b = [["path", { d: "m9 18 6-6-6-6", key: "mthhwq" }]];
175
+ const ChevronRight = createLucideIcon("chevron-right", __iconNode$b);
176
176
  /**
177
177
  * @license lucide-react v0.552.0 - ISC
178
178
  *
179
179
  * This source code is licensed under the ISC license.
180
180
  * See the LICENSE file in the root directory of this source tree.
181
181
  */
182
- const __iconNode$9 = [
182
+ const __iconNode$a = [
183
183
  ["rect", { width: "14", height: "14", x: "8", y: "8", rx: "2", ry: "2", key: "17jyea" }],
184
184
  ["path", { d: "M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2", key: "zix9uf" }]
185
185
  ];
186
- const Copy = createLucideIcon("copy", __iconNode$9);
186
+ const Copy = createLucideIcon("copy", __iconNode$a);
187
187
  /**
188
188
  * @license lucide-react v0.552.0 - ISC
189
189
  *
190
190
  * This source code is licensed under the ISC license.
191
191
  * See the LICENSE file in the root directory of this source tree.
192
192
  */
193
- const __iconNode$8 = [
193
+ const __iconNode$9 = [
194
194
  [
195
195
  "path",
196
196
  {
@@ -202,14 +202,14 @@ const __iconNode$8 = [
202
202
  ["circle", { cx: "11.5", cy: "14.5", r: "2.5", key: "1bq0ko" }],
203
203
  ["path", { d: "M13.3 16.3 15 18", key: "2quom7" }]
204
204
  ];
205
- const FileSearch = createLucideIcon("file-search", __iconNode$8);
205
+ const FileSearch = createLucideIcon("file-search", __iconNode$9);
206
206
  /**
207
207
  * @license lucide-react v0.552.0 - ISC
208
208
  *
209
209
  * This source code is licensed under the ISC license.
210
210
  * See the LICENSE file in the root directory of this source tree.
211
211
  */
212
- const __iconNode$7 = [
212
+ const __iconNode$8 = [
213
213
  [
214
214
  "path",
215
215
  {
@@ -220,27 +220,27 @@ const __iconNode$7 = [
220
220
  ["path", { d: "M6.453 15h11.094", key: "3shlmq" }],
221
221
  ["path", { d: "M8.5 2h7", key: "csnxdl" }]
222
222
  ];
223
- const FlaskConical = createLucideIcon("flask-conical", __iconNode$7);
223
+ const FlaskConical = createLucideIcon("flask-conical", __iconNode$8);
224
224
  /**
225
225
  * @license lucide-react v0.552.0 - ISC
226
226
  *
227
227
  * This source code is licensed under the ISC license.
228
228
  * See the LICENSE file in the root directory of this source tree.
229
229
  */
230
- const __iconNode$6 = [
230
+ const __iconNode$7 = [
231
231
  ["line", { x1: "6", x2: "6", y1: "3", y2: "15", key: "17qcm7" }],
232
232
  ["circle", { cx: "18", cy: "6", r: "3", key: "1h7g24" }],
233
233
  ["circle", { cx: "6", cy: "18", r: "3", key: "fqmcym" }],
234
234
  ["path", { d: "M18 9a9 9 0 0 1-9 9", key: "n2h4wq" }]
235
235
  ];
236
- const GitBranch = createLucideIcon("git-branch", __iconNode$6);
236
+ const GitBranch = createLucideIcon("git-branch", __iconNode$7);
237
237
  /**
238
238
  * @license lucide-react v0.552.0 - ISC
239
239
  *
240
240
  * This source code is licensed under the ISC license.
241
241
  * See the LICENSE file in the root directory of this source tree.
242
242
  */
243
- const __iconNode$5 = [
243
+ const __iconNode$6 = [
244
244
  [
245
245
  "path",
246
246
  {
@@ -249,26 +249,26 @@ const __iconNode$5 = [
249
249
  }
250
250
  ]
251
251
  ];
252
- const Hexagon = createLucideIcon("hexagon", __iconNode$5);
252
+ const Hexagon = createLucideIcon("hexagon", __iconNode$6);
253
253
  /**
254
254
  * @license lucide-react v0.552.0 - ISC
255
255
  *
256
256
  * This source code is licensed under the ISC license.
257
257
  * See the LICENSE file in the root directory of this source tree.
258
258
  */
259
- const __iconNode$4 = [
259
+ const __iconNode$5 = [
260
260
  ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
261
261
  ["path", { d: "M12 16v-4", key: "1dtifu" }],
262
262
  ["path", { d: "M12 8h.01", key: "e9boi3" }]
263
263
  ];
264
- const Info = createLucideIcon("info", __iconNode$4);
264
+ const Info = createLucideIcon("info", __iconNode$5);
265
265
  /**
266
266
  * @license lucide-react v0.552.0 - ISC
267
267
  *
268
268
  * This source code is licensed under the ISC license.
269
269
  * See the LICENSE file in the root directory of this source tree.
270
270
  */
271
- const __iconNode$3 = [
271
+ const __iconNode$4 = [
272
272
  [
273
273
  "path",
274
274
  {
@@ -280,32 +280,43 @@ const __iconNode$3 = [
280
280
  ["path", { d: "M22 4h-4", key: "gwowj6" }],
281
281
  ["circle", { cx: "4", cy: "20", r: "2", key: "6kqj1y" }]
282
282
  ];
283
- const Sparkles = createLucideIcon("sparkles", __iconNode$3);
283
+ const Sparkles = createLucideIcon("sparkles", __iconNode$4);
284
284
  /**
285
285
  * @license lucide-react v0.552.0 - ISC
286
286
  *
287
287
  * This source code is licensed under the ISC license.
288
288
  * See the LICENSE file in the root directory of this source tree.
289
289
  */
290
- const __iconNode$2 = [
290
+ const __iconNode$3 = [
291
291
  ["path", { d: "M12 19h8", key: "baeox8" }],
292
292
  ["path", { d: "m4 17 6-6-6-6", key: "1yngyt" }]
293
293
  ];
294
- const Terminal = createLucideIcon("terminal", __iconNode$2);
294
+ const Terminal = createLucideIcon("terminal", __iconNode$3);
295
295
  /**
296
296
  * @license lucide-react v0.552.0 - ISC
297
297
  *
298
298
  * This source code is licensed under the ISC license.
299
299
  * See the LICENSE file in the root directory of this source tree.
300
300
  */
301
- const __iconNode$1 = [
301
+ const __iconNode$2 = [
302
302
  ["path", { d: "M10 11v6", key: "nco0om" }],
303
303
  ["path", { d: "M14 11v6", key: "outv1u" }],
304
304
  ["path", { d: "M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6", key: "miytrc" }],
305
305
  ["path", { d: "M3 6h18", key: "d0wm0j" }],
306
306
  ["path", { d: "M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2", key: "e791ji" }]
307
307
  ];
308
- const Trash2 = createLucideIcon("trash-2", __iconNode$1);
308
+ const Trash2 = createLucideIcon("trash-2", __iconNode$2);
309
+ /**
310
+ * @license lucide-react v0.552.0 - ISC
311
+ *
312
+ * This source code is licensed under the ISC license.
313
+ * See the LICENSE file in the root directory of this source tree.
314
+ */
315
+ const __iconNode$1 = [
316
+ ["path", { d: "M18 6 6 18", key: "1bl5f8" }],
317
+ ["path", { d: "m6 6 12 12", key: "d8bk6v" }]
318
+ ];
319
+ const X = createLucideIcon("x", __iconNode$1);
309
320
  /**
310
321
  * @license lucide-react v0.552.0 - ISC
311
322
  *
@@ -368,11 +379,31 @@ function getThemeColors(theme) {
368
379
  textColor: theme.colors.text,
369
380
  scoreColor: theme.colors.text,
370
381
  tierColors: {
371
- none: { fill: "#808080", stroke: "#808080", bg: theme.colors.backgroundLight },
372
- bronze: { fill: "#CD7F32", stroke: "#CD7F32", bg: theme.colors.backgroundLight },
373
- silver: { fill: "#C0C0C0", stroke: "#C0C0C0", bg: theme.colors.backgroundLight },
374
- gold: { fill: "#FFD700", stroke: "#FFD700", bg: theme.colors.backgroundLight },
375
- platinum: { fill: "#E5E4E2", stroke: "#E5E4E2", bg: theme.colors.backgroundLight }
382
+ none: {
383
+ fill: "#808080",
384
+ stroke: "#808080",
385
+ bg: theme.colors.backgroundLight
386
+ },
387
+ bronze: {
388
+ fill: "#CD7F32",
389
+ stroke: "#CD7F32",
390
+ bg: theme.colors.backgroundLight
391
+ },
392
+ silver: {
393
+ fill: "#C0C0C0",
394
+ stroke: "#C0C0C0",
395
+ bg: theme.colors.backgroundLight
396
+ },
397
+ gold: {
398
+ fill: "#FFD700",
399
+ stroke: "#FFD700",
400
+ bg: theme.colors.backgroundLight
401
+ },
402
+ platinum: {
403
+ fill: "#E5E4E2",
404
+ stroke: "#E5E4E2",
405
+ bg: theme.colors.backgroundLight
406
+ }
376
407
  },
377
408
  metricColors: {
378
409
  types: theme.colors.warning,
@@ -395,13 +426,77 @@ function getValueColor$2(value, key) {
395
426
  if (effectiveValue >= 60) return "#E6A700";
396
427
  return "#C62828";
397
428
  }
429
+ const LENS_TO_METRIC_MAP = {
430
+ // Linting tools
431
+ eslint: "linting",
432
+ biome: "linting",
433
+ "biome-lint": "linting",
434
+ oxlint: "linting",
435
+ // Type checking tools
436
+ typescript: "types",
437
+ flow: "types",
438
+ // Testing tools
439
+ test: "tests",
440
+ jest: "tests",
441
+ vitest: "tests",
442
+ "bun-test": "tests",
443
+ mocha: "tests",
444
+ playwright: "tests",
445
+ cypress: "tests",
446
+ // Formatting tools
447
+ prettier: "formatting",
448
+ "biome-format": "formatting",
449
+ // Dead code detection
450
+ knip: "deadCode",
451
+ depcheck: "deadCode",
452
+ // Documentation
453
+ typedoc: "documentation",
454
+ jsdoc: "documentation",
455
+ alexandria: "documentation"
456
+ };
457
+ function isMetricConfigured(metricKey, lensesRan) {
458
+ if (!lensesRan || lensesRan.length === 0) {
459
+ return true;
460
+ }
461
+ return lensesRan.some((lensId) => LENS_TO_METRIC_MAP[lensId] === metricKey);
462
+ }
398
463
  const getMetricConfig = (themeColors) => [
399
- { key: "formatting", label: "Format", color: themeColors.metricColors.formatting, angle: -120 },
400
- { key: "linting", label: "Linting", color: themeColors.metricColors.linting, angle: -60 },
401
- { key: "types", label: "Types", color: themeColors.metricColors.types, angle: 0 },
402
- { key: "tests", label: "Tests", color: themeColors.metricColors.tests, angle: 60 },
403
- { key: "deadCode", label: "Dead Code", color: themeColors.metricColors.deadCode, angle: 120 },
404
- { key: "documentation", label: "Docs", color: themeColors.metricColors.documentation, angle: 180 }
464
+ {
465
+ key: "formatting",
466
+ label: "Format",
467
+ color: themeColors.metricColors.formatting,
468
+ angle: -120
469
+ },
470
+ {
471
+ key: "linting",
472
+ label: "Linting",
473
+ color: themeColors.metricColors.linting,
474
+ angle: -60
475
+ },
476
+ {
477
+ key: "types",
478
+ label: "Types",
479
+ color: themeColors.metricColors.types,
480
+ angle: 0
481
+ },
482
+ {
483
+ key: "tests",
484
+ label: "Tests",
485
+ color: themeColors.metricColors.tests,
486
+ angle: 60
487
+ },
488
+ {
489
+ key: "deadCode",
490
+ label: "Dead Code",
491
+ color: themeColors.metricColors.deadCode,
492
+ angle: 120
493
+ },
494
+ {
495
+ key: "documentation",
496
+ label: "Docs",
497
+ color: themeColors.metricColors.documentation,
498
+ angle: 180
499
+ }
405
500
  ];
406
501
  function calculateHexagonPoints(center, radius, metricConfig) {
407
502
  return metricConfig.map(({ angle }) => {
@@ -426,6 +521,7 @@ function QualityHexagon({
426
521
  showLabels = false,
427
522
  showValues = false,
428
523
  className,
524
+ lensesRan,
429
525
  onVertexHover,
430
526
  onVertexLeave,
431
527
  onVertexClick
@@ -442,17 +538,26 @@ function QualityHexagon({
442
538
  const dotSize = viewBoxSize * 0.015;
443
539
  const hexagonPoints = calculateHexagonPoints(center, radius, metricConfig);
444
540
  const dataPoints = metricConfig.map(({ key, angle }) => {
541
+ const configured = isMetricConfigured(key, lensesRan);
542
+ if (!configured) {
543
+ return calculateMetricPoint(center, radius, angle, 0);
544
+ }
445
545
  let value = metrics[key];
446
546
  if (key === "deadCode") {
447
547
  value = 100 - value;
448
548
  }
449
549
  return calculateMetricPoint(center, radius, angle, value);
450
550
  }).map((p) => `${p.x},${p.y}`).join(" ");
451
- const metricsForAverage = { ...metrics };
452
- metricsForAverage.deadCode = 100 - metricsForAverage.deadCode;
453
- const averageScore = Math.round(
454
- Object.values(metricsForAverage).reduce((a, b) => a + b, 0) / 6
551
+ const configuredMetrics = metricConfig.filter(
552
+ ({ key }) => isMetricConfigured(key, lensesRan)
455
553
  );
554
+ const metricsForAverage = configuredMetrics.map(({ key }) => {
555
+ const value = metrics[key];
556
+ return key === "deadCode" ? 100 - value : value;
557
+ });
558
+ const averageScore = metricsForAverage.length > 0 ? Math.round(
559
+ metricsForAverage.reduce((a, b) => a + b, 0) / metricsForAverage.length
560
+ ) : 0;
456
561
  const hexagon = /* @__PURE__ */ jsxs(
457
562
  "svg",
458
563
  {
@@ -463,7 +568,11 @@ function QualityHexagon({
463
568
  /* @__PURE__ */ jsx("g", { className: "opacity-20", children: [20, 40, 60, 80, 100].map((percent) => /* @__PURE__ */ jsx(
464
569
  "polygon",
465
570
  {
466
- points: calculateHexagonPoints(center, radius * percent / 100, metricConfig),
571
+ points: calculateHexagonPoints(
572
+ center,
573
+ radius * percent / 100,
574
+ metricConfig
575
+ ),
467
576
  fill: "none",
468
577
  stroke: themeColors.gridColor,
469
578
  strokeWidth: 0.5,
@@ -509,13 +618,20 @@ function QualityHexagon({
509
618
  }
510
619
  ),
511
620
  metricConfig.map(({ key, label, color, angle }) => {
621
+ const configured = isMetricConfigured(key, lensesRan);
512
622
  const rawValue = metrics[key];
513
623
  let value = rawValue;
514
624
  if (key === "deadCode") {
515
625
  value = 100 - value;
516
626
  }
627
+ const effectiveValue = configured ? value : 0;
517
628
  const point = calculateMetricPoint(center, radius, angle, 100);
518
- const dataPoint = calculateMetricPoint(center, radius, angle, value);
629
+ const dataPoint = calculateMetricPoint(
630
+ center,
631
+ radius,
632
+ angle,
633
+ effectiveValue
634
+ );
519
635
  const vertexInfo = {
520
636
  key,
521
637
  label,
@@ -527,7 +643,9 @@ function QualityHexagon({
527
643
  };
528
644
  const handleClick = (e) => {
529
645
  e.stopPropagation();
530
- onVertexClick == null ? void 0 : onVertexClick(vertexInfo);
646
+ if (configured) {
647
+ onVertexClick == null ? void 0 : onVertexClick(vertexInfo);
648
+ }
531
649
  };
532
650
  return /* @__PURE__ */ jsxs(
533
651
  "g",
@@ -535,7 +653,10 @@ function QualityHexagon({
535
653
  onMouseEnter: handleMouseEnter,
536
654
  onMouseLeave: onVertexLeave,
537
655
  onClick: handleClick,
538
- style: { cursor: onVertexHover || onVertexClick ? "pointer" : "default" },
656
+ style: {
657
+ cursor: configured && (onVertexHover || onVertexClick) ? "pointer" : "default",
658
+ opacity: configured ? 1 : 0.4
659
+ },
539
660
  children: [
540
661
  /* @__PURE__ */ jsx(
541
662
  "circle",
@@ -552,12 +673,13 @@ function QualityHexagon({
552
673
  cx: point.x,
553
674
  cy: point.y,
554
675
  r: dotSize,
555
- fill: "white",
556
- stroke: colors.stroke,
557
- strokeWidth: 1.5
676
+ fill: configured ? "white" : themeColors.gridColor,
677
+ stroke: configured ? colors.stroke : themeColors.gridColor,
678
+ strokeWidth: 1.5,
679
+ strokeDasharray: configured ? "none" : "2,2"
558
680
  }
559
681
  ),
560
- /* @__PURE__ */ jsx(
682
+ configured && /* @__PURE__ */ jsx(
561
683
  "circle",
562
684
  {
563
685
  cx: dataPoint.x,
@@ -667,117 +789,190 @@ function QualityHexagonDetailed({
667
789
  backgroundColor: colors.bg
668
790
  },
669
791
  children: [
670
- hasHeader && /* @__PURE__ */ jsxs("div", { style: {
671
- display: "flex",
672
- alignItems: "center",
673
- justifyContent: "space-between",
674
- gap: 12
675
- }, children: [
676
- packageName ? /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: 2 }, children: [
677
- packageName.startsWith("@") && packageName.includes("/") ? /* @__PURE__ */ jsxs(Fragment, { children: [
678
- /* @__PURE__ */ jsx("span", { style: {
679
- fontSize: 12,
680
- color: theme.colors.textMuted
681
- }, children: packageName.split("/")[0] }),
682
- /* @__PURE__ */ jsx("span", { style: {
683
- fontSize: 14,
684
- fontWeight: 500,
685
- color: colors.stroke
686
- }, children: packageName.split("/")[1] })
687
- ] }) : /* @__PURE__ */ jsx("span", { style: {
688
- fontSize: 14,
689
- fontWeight: 500,
690
- color: colors.stroke
691
- }, children: packageName }),
692
- packageVersion && /* @__PURE__ */ jsxs("span", { style: {
693
- fontSize: 12,
694
- color: theme.colors.textMuted
695
- }, children: [
696
- "v",
697
- packageVersion
698
- ] })
699
- ] }) : /* @__PURE__ */ jsx("span", {}),
700
- onRefresh && /* @__PURE__ */ jsx(
701
- "button",
702
- {
703
- onClick: onRefresh,
704
- disabled: isRefreshing,
705
- style: {
706
- padding: 6,
707
- display: "flex",
708
- alignItems: "center",
709
- justifyContent: "center",
710
- border: `1px solid ${theme.colors.border}`,
711
- borderRadius: 4,
712
- background: theme.colors.surface,
713
- color: theme.colors.textMuted,
714
- cursor: isRefreshing ? "not-allowed" : "pointer",
715
- opacity: isRefreshing ? 0.6 : 1
716
- },
717
- title: "Refresh",
718
- children: /* @__PURE__ */ jsxs(
719
- "svg",
792
+ hasHeader && /* @__PURE__ */ jsxs(
793
+ "div",
794
+ {
795
+ style: {
796
+ display: "flex",
797
+ alignItems: "center",
798
+ justifyContent: "space-between",
799
+ gap: 12
800
+ },
801
+ children: [
802
+ packageName ? /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: 2 }, children: [
803
+ packageName.startsWith("@") && packageName.includes("/") ? /* @__PURE__ */ jsxs(Fragment, { children: [
804
+ /* @__PURE__ */ jsx(
805
+ "span",
806
+ {
807
+ style: {
808
+ fontSize: 12,
809
+ color: theme.colors.textMuted
810
+ },
811
+ children: packageName.split("/")[0]
812
+ }
813
+ ),
814
+ /* @__PURE__ */ jsx(
815
+ "span",
816
+ {
817
+ style: {
818
+ fontSize: 14,
819
+ fontWeight: 500,
820
+ color: colors.stroke
821
+ },
822
+ children: packageName.split("/")[1]
823
+ }
824
+ )
825
+ ] }) : /* @__PURE__ */ jsx(
826
+ "span",
827
+ {
828
+ style: {
829
+ fontSize: 14,
830
+ fontWeight: 500,
831
+ color: colors.stroke
832
+ },
833
+ children: packageName
834
+ }
835
+ ),
836
+ packageVersion && /* @__PURE__ */ jsxs(
837
+ "span",
838
+ {
839
+ style: {
840
+ fontSize: 12,
841
+ color: theme.colors.textMuted
842
+ },
843
+ children: [
844
+ "v",
845
+ packageVersion
846
+ ]
847
+ }
848
+ )
849
+ ] }) : /* @__PURE__ */ jsx("span", {}),
850
+ onRefresh && /* @__PURE__ */ jsx(
851
+ "button",
720
852
  {
721
- width: "14",
722
- height: "14",
723
- viewBox: "0 0 24 24",
724
- fill: "none",
725
- stroke: "currentColor",
726
- strokeWidth: "2",
727
- strokeLinecap: "round",
728
- strokeLinejoin: "round",
853
+ onClick: onRefresh,
854
+ disabled: isRefreshing,
729
855
  style: {
730
- animation: isRefreshing ? "spin 1s linear infinite" : "none"
856
+ padding: 6,
857
+ display: "flex",
858
+ alignItems: "center",
859
+ justifyContent: "center",
860
+ border: `1px solid ${theme.colors.border}`,
861
+ borderRadius: 4,
862
+ background: theme.colors.surface,
863
+ color: theme.colors.textMuted,
864
+ cursor: isRefreshing ? "not-allowed" : "pointer",
865
+ opacity: isRefreshing ? 0.6 : 1
731
866
  },
732
- children: [
733
- /* @__PURE__ */ jsx("path", { d: "M21 12a9 9 0 0 0-9-9 9.75 9.75 0 0 0-6.74 2.74L3 8" }),
734
- /* @__PURE__ */ jsx("path", { d: "M3 3v5h5" }),
735
- /* @__PURE__ */ jsx("path", { d: "M3 12a9 9 0 0 0 9 9 9.75 9.75 0 0 0 6.74-2.74L21 16" }),
736
- /* @__PURE__ */ jsx("path", { d: "M16 16h5v5" })
737
- ]
867
+ title: "Refresh",
868
+ children: /* @__PURE__ */ jsxs(
869
+ "svg",
870
+ {
871
+ width: "14",
872
+ height: "14",
873
+ viewBox: "0 0 24 24",
874
+ fill: "none",
875
+ stroke: "currentColor",
876
+ strokeWidth: "2",
877
+ strokeLinecap: "round",
878
+ strokeLinejoin: "round",
879
+ style: {
880
+ animation: isRefreshing ? "spin 1s linear infinite" : "none"
881
+ },
882
+ children: [
883
+ /* @__PURE__ */ jsx("path", { d: "M21 12a9 9 0 0 0-9-9 9.75 9.75 0 0 0-6.74 2.74L3 8" }),
884
+ /* @__PURE__ */ jsx("path", { d: "M3 3v5h5" }),
885
+ /* @__PURE__ */ jsx("path", { d: "M3 12a9 9 0 0 0 9 9 9.75 9.75 0 0 0 6.74-2.74L21 16" }),
886
+ /* @__PURE__ */ jsx("path", { d: "M16 16h5v5" })
887
+ ]
888
+ }
889
+ )
738
890
  }
739
891
  )
740
- }
741
- )
742
- ] }),
743
- /* @__PURE__ */ jsxs("div", { style: {
744
- display: "flex",
745
- flexWrap: "wrap",
746
- alignItems: "center",
747
- justifyContent: "center",
748
- gap: 24
749
- }, children: [
750
- /* @__PURE__ */ jsx("div", { style: { flex: "1 1 200px", maxWidth: 300, aspectRatio: "1 / 1" }, children: /* @__PURE__ */ jsx(
751
- QualityHexagon,
752
- {
753
- metrics,
754
- tier,
755
- theme,
756
- showLabels: true,
757
- showValues: false
758
- }
759
- ) }),
760
- /* @__PURE__ */ jsx("div", { style: { flex: "1 1 200px", minWidth: 200, display: "flex", flexDirection: "column", gap: 8, padding: "8px 24px" }, children: metricConfig.map(({ key, label }) => {
761
- const value = metrics[key];
762
- return /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between", gap: 12 }, children: [
763
- /* @__PURE__ */ jsxs("span", { style: {
764
- fontSize: 14,
765
- color: theme.colors.textMuted
766
- }, children: [
767
- label,
768
- key === "deadCode" ? " ↓" : ""
769
- ] }),
770
- /* @__PURE__ */ jsxs("span", { style: {
771
- fontSize: 14,
772
- fontWeight: 500,
773
- color: getValueColor$2(value, key)
774
- }, children: [
775
- value,
776
- "%"
777
- ] })
778
- ] }, key);
779
- }) })
780
- ] })
892
+ ]
893
+ }
894
+ ),
895
+ /* @__PURE__ */ jsxs(
896
+ "div",
897
+ {
898
+ style: {
899
+ display: "flex",
900
+ flexWrap: "wrap",
901
+ alignItems: "center",
902
+ justifyContent: "center",
903
+ gap: 24
904
+ },
905
+ children: [
906
+ /* @__PURE__ */ jsx("div", { style: { flex: "1 1 200px", maxWidth: 300, aspectRatio: "1 / 1" }, children: /* @__PURE__ */ jsx(
907
+ QualityHexagon,
908
+ {
909
+ metrics,
910
+ tier,
911
+ theme,
912
+ showLabels: true,
913
+ showValues: false
914
+ }
915
+ ) }),
916
+ /* @__PURE__ */ jsx(
917
+ "div",
918
+ {
919
+ style: {
920
+ flex: "1 1 200px",
921
+ minWidth: 200,
922
+ display: "flex",
923
+ flexDirection: "column",
924
+ gap: 8,
925
+ padding: "8px 24px"
926
+ },
927
+ children: metricConfig.map(({ key, label }) => {
928
+ const value = metrics[key];
929
+ return /* @__PURE__ */ jsxs(
930
+ "div",
931
+ {
932
+ style: {
933
+ display: "flex",
934
+ alignItems: "center",
935
+ justifyContent: "space-between",
936
+ gap: 12
937
+ },
938
+ children: [
939
+ /* @__PURE__ */ jsxs(
940
+ "span",
941
+ {
942
+ style: {
943
+ fontSize: 14,
944
+ color: theme.colors.textMuted
945
+ },
946
+ children: [
947
+ label,
948
+ key === "deadCode" ? " ↓" : ""
949
+ ]
950
+ }
951
+ ),
952
+ /* @__PURE__ */ jsxs(
953
+ "span",
954
+ {
955
+ style: {
956
+ fontSize: 14,
957
+ fontWeight: 500,
958
+ color: getValueColor$2(value, key)
959
+ },
960
+ children: [
961
+ value,
962
+ "%"
963
+ ]
964
+ }
965
+ )
966
+ ]
967
+ },
968
+ key
969
+ );
970
+ })
971
+ }
972
+ )
973
+ ]
974
+ }
975
+ )
781
976
  ]
782
977
  }
783
978
  );
@@ -790,6 +985,7 @@ function QualityHexagonExpandable({
790
985
  packageName,
791
986
  packageVersion,
792
987
  packagePath,
988
+ lensesRan,
793
989
  onRefresh,
794
990
  isRefreshing = false,
795
991
  defaultExpanded = false,
@@ -820,79 +1016,109 @@ function QualityHexagonExpandable({
820
1016
  flex: "1 1 200px"
821
1017
  },
822
1018
  children: [
823
- hasHeader && /* @__PURE__ */ jsxs("div", { style: {
824
- display: "flex",
825
- alignItems: "center",
826
- justifyContent: "space-between",
827
- gap: 12
828
- }, children: [
829
- packageName ? /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: 2 }, children: [
830
- packageName.startsWith("@") && packageName.includes("/") ? /* @__PURE__ */ jsxs(Fragment, { children: [
831
- /* @__PURE__ */ jsx("span", { style: {
832
- fontSize: 12,
833
- color: theme.colors.textMuted
834
- }, children: packageName.split("/")[0] }),
835
- /* @__PURE__ */ jsx("span", { style: {
836
- fontSize: 14,
837
- fontWeight: 500,
838
- color: colors.stroke
839
- }, children: packageName.split("/")[1] })
840
- ] }) : /* @__PURE__ */ jsx("span", { style: {
841
- fontSize: 14,
842
- fontWeight: 500,
843
- color: colors.stroke
844
- }, children: packageName }),
845
- packageVersion && /* @__PURE__ */ jsxs("span", { style: {
846
- fontSize: 12,
847
- color: theme.colors.textMuted
848
- }, children: [
849
- "v",
850
- packageVersion
851
- ] })
852
- ] }) : /* @__PURE__ */ jsx("span", {}),
853
- onRefresh && /* @__PURE__ */ jsx(
854
- "button",
855
- {
856
- onClick: onRefresh,
857
- disabled: isRefreshing,
858
- style: {
859
- padding: 6,
860
- display: "flex",
861
- alignItems: "center",
862
- justifyContent: "center",
863
- border: `1px solid ${theme.colors.border}`,
864
- borderRadius: 4,
865
- background: theme.colors.surface,
866
- color: theme.colors.textMuted,
867
- cursor: isRefreshing ? "not-allowed" : "pointer",
868
- opacity: isRefreshing ? 0.6 : 1
869
- },
870
- title: "Refresh",
871
- children: /* @__PURE__ */ jsxs(
872
- "svg",
1019
+ hasHeader && /* @__PURE__ */ jsxs(
1020
+ "div",
1021
+ {
1022
+ style: {
1023
+ display: "flex",
1024
+ alignItems: "center",
1025
+ justifyContent: "space-between",
1026
+ gap: 12
1027
+ },
1028
+ children: [
1029
+ packageName ? /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: 2 }, children: [
1030
+ packageName.startsWith("@") && packageName.includes("/") ? /* @__PURE__ */ jsxs(Fragment, { children: [
1031
+ /* @__PURE__ */ jsx(
1032
+ "span",
1033
+ {
1034
+ style: {
1035
+ fontSize: 12,
1036
+ color: theme.colors.textMuted
1037
+ },
1038
+ children: packageName.split("/")[0]
1039
+ }
1040
+ ),
1041
+ /* @__PURE__ */ jsx(
1042
+ "span",
1043
+ {
1044
+ style: {
1045
+ fontSize: 14,
1046
+ fontWeight: 500,
1047
+ color: colors.stroke
1048
+ },
1049
+ children: packageName.split("/")[1]
1050
+ }
1051
+ )
1052
+ ] }) : /* @__PURE__ */ jsx(
1053
+ "span",
1054
+ {
1055
+ style: {
1056
+ fontSize: 14,
1057
+ fontWeight: 500,
1058
+ color: colors.stroke
1059
+ },
1060
+ children: packageName
1061
+ }
1062
+ ),
1063
+ packageVersion && /* @__PURE__ */ jsxs(
1064
+ "span",
1065
+ {
1066
+ style: {
1067
+ fontSize: 12,
1068
+ color: theme.colors.textMuted
1069
+ },
1070
+ children: [
1071
+ "v",
1072
+ packageVersion
1073
+ ]
1074
+ }
1075
+ )
1076
+ ] }) : /* @__PURE__ */ jsx("span", {}),
1077
+ onRefresh && /* @__PURE__ */ jsx(
1078
+ "button",
873
1079
  {
874
- width: "14",
875
- height: "14",
876
- viewBox: "0 0 24 24",
877
- fill: "none",
878
- stroke: "currentColor",
879
- strokeWidth: "2",
880
- strokeLinecap: "round",
881
- strokeLinejoin: "round",
1080
+ onClick: onRefresh,
1081
+ disabled: isRefreshing,
882
1082
  style: {
883
- animation: isRefreshing ? "spin 1s linear infinite" : "none"
1083
+ padding: 6,
1084
+ display: "flex",
1085
+ alignItems: "center",
1086
+ justifyContent: "center",
1087
+ border: `1px solid ${theme.colors.border}`,
1088
+ borderRadius: 4,
1089
+ background: theme.colors.surface,
1090
+ color: theme.colors.textMuted,
1091
+ cursor: isRefreshing ? "not-allowed" : "pointer",
1092
+ opacity: isRefreshing ? 0.6 : 1
884
1093
  },
885
- children: [
886
- /* @__PURE__ */ jsx("path", { d: "M21 12a9 9 0 0 0-9-9 9.75 9.75 0 0 0-6.74 2.74L3 8" }),
887
- /* @__PURE__ */ jsx("path", { d: "M3 3v5h5" }),
888
- /* @__PURE__ */ jsx("path", { d: "M3 12a9 9 0 0 0 9 9 9.75 9.75 0 0 0 6.74-2.74L21 16" }),
889
- /* @__PURE__ */ jsx("path", { d: "M16 16h5v5" })
890
- ]
1094
+ title: "Refresh",
1095
+ children: /* @__PURE__ */ jsxs(
1096
+ "svg",
1097
+ {
1098
+ width: "14",
1099
+ height: "14",
1100
+ viewBox: "0 0 24 24",
1101
+ fill: "none",
1102
+ stroke: "currentColor",
1103
+ strokeWidth: "2",
1104
+ strokeLinecap: "round",
1105
+ strokeLinejoin: "round",
1106
+ style: {
1107
+ animation: isRefreshing ? "spin 1s linear infinite" : "none"
1108
+ },
1109
+ children: [
1110
+ /* @__PURE__ */ jsx("path", { d: "M21 12a9 9 0 0 0-9-9 9.75 9.75 0 0 0-6.74 2.74L3 8" }),
1111
+ /* @__PURE__ */ jsx("path", { d: "M3 3v5h5" }),
1112
+ /* @__PURE__ */ jsx("path", { d: "M3 12a9 9 0 0 0 9 9 9.75 9.75 0 0 0 6.74-2.74L21 16" }),
1113
+ /* @__PURE__ */ jsx("path", { d: "M16 16h5v5" })
1114
+ ]
1115
+ }
1116
+ )
891
1117
  }
892
1118
  )
893
- }
894
- )
895
- ] }),
1119
+ ]
1120
+ }
1121
+ ),
896
1122
  /* @__PURE__ */ jsx(
897
1123
  "div",
898
1124
  {
@@ -910,7 +1136,8 @@ function QualityHexagonExpandable({
910
1136
  tier,
911
1137
  theme,
912
1138
  showLabels: true,
913
- showValues: false
1139
+ showValues: false,
1140
+ lensesRan
914
1141
  }
915
1142
  ) })
916
1143
  }
@@ -923,62 +1150,82 @@ function QualityHexagonExpandable({
923
1150
  gridTemplateRows: expanded ? "1fr" : "0fr",
924
1151
  transition: "grid-template-rows 0.3s ease"
925
1152
  },
926
- children: /* @__PURE__ */ jsx("div", { style: { overflow: "hidden" }, children: /* @__PURE__ */ jsx("div", { style: {
927
- display: "flex",
928
- flexDirection: "column",
929
- gap: 8,
930
- padding: "8px 24px",
931
- borderTop: `1px solid ${theme.colors.border}`,
932
- marginTop: 8
933
- }, children: metricConfig.map(({ key, label }) => {
934
- const value = metrics[key];
935
- return /* @__PURE__ */ jsxs(
936
- "div",
937
- {
938
- onClick: (e) => {
939
- e.stopPropagation();
940
- onMetricClick == null ? void 0 : onMetricClick(key);
941
- },
942
- style: {
943
- display: "flex",
944
- alignItems: "center",
945
- justifyContent: "space-between",
946
- gap: 12,
947
- cursor: onMetricClick ? "pointer" : "default",
948
- padding: "4px 8px",
949
- margin: "0 -8px",
950
- borderRadius: 4,
951
- transition: "background-color 0.15s ease"
952
- },
953
- onMouseEnter: (e) => {
954
- if (onMetricClick) {
955
- e.currentTarget.style.backgroundColor = theme.colors.surface;
956
- }
957
- },
958
- onMouseLeave: (e) => {
959
- e.currentTarget.style.backgroundColor = "transparent";
960
- },
961
- children: [
962
- /* @__PURE__ */ jsxs("span", { style: {
963
- fontSize: 14,
964
- color: theme.colors.textMuted
965
- }, children: [
966
- label,
967
- key === "deadCode" ? " ↓" : ""
968
- ] }),
969
- /* @__PURE__ */ jsxs("span", { style: {
970
- fontSize: 14,
971
- fontWeight: 500,
972
- color: getValueColor$2(value, key)
973
- }, children: [
974
- value,
975
- "%"
976
- ] })
977
- ]
1153
+ children: /* @__PURE__ */ jsx("div", { style: { overflow: "hidden" }, children: /* @__PURE__ */ jsx(
1154
+ "div",
1155
+ {
1156
+ style: {
1157
+ display: "flex",
1158
+ flexDirection: "column",
1159
+ gap: 8,
1160
+ padding: "8px 24px",
1161
+ borderTop: `1px solid ${theme.colors.border}`,
1162
+ marginTop: 8
978
1163
  },
979
- key
980
- );
981
- }) }) })
1164
+ children: metricConfig.map(({ key, label }) => {
1165
+ const value = metrics[key];
1166
+ const configured = isMetricConfigured(key, lensesRan);
1167
+ return /* @__PURE__ */ jsxs(
1168
+ "div",
1169
+ {
1170
+ onClick: (e) => {
1171
+ e.stopPropagation();
1172
+ if (configured) {
1173
+ onMetricClick == null ? void 0 : onMetricClick(key);
1174
+ }
1175
+ },
1176
+ style: {
1177
+ display: "flex",
1178
+ alignItems: "center",
1179
+ justifyContent: "space-between",
1180
+ gap: 12,
1181
+ cursor: configured && onMetricClick ? "pointer" : "default",
1182
+ padding: "4px 8px",
1183
+ margin: "0 -8px",
1184
+ borderRadius: 4,
1185
+ transition: "background-color 0.15s ease",
1186
+ opacity: configured ? 1 : 0.5
1187
+ },
1188
+ onMouseEnter: (e) => {
1189
+ if (configured && onMetricClick) {
1190
+ e.currentTarget.style.backgroundColor = theme.colors.surface;
1191
+ }
1192
+ },
1193
+ onMouseLeave: (e) => {
1194
+ e.currentTarget.style.backgroundColor = "transparent";
1195
+ },
1196
+ children: [
1197
+ /* @__PURE__ */ jsxs(
1198
+ "span",
1199
+ {
1200
+ style: {
1201
+ fontSize: 14,
1202
+ color: theme.colors.textMuted
1203
+ },
1204
+ children: [
1205
+ label,
1206
+ key === "deadCode" ? " ↓" : ""
1207
+ ]
1208
+ }
1209
+ ),
1210
+ /* @__PURE__ */ jsx(
1211
+ "span",
1212
+ {
1213
+ style: {
1214
+ fontSize: 14,
1215
+ fontWeight: 500,
1216
+ color: configured ? getValueColor$2(value, key) : theme.colors.textMuted
1217
+ },
1218
+ title: configured ? void 0 : "Not configured",
1219
+ children: configured ? `${value}%` : "N/A"
1220
+ }
1221
+ )
1222
+ ]
1223
+ },
1224
+ key
1225
+ );
1226
+ })
1227
+ }
1228
+ ) })
982
1229
  }
983
1230
  ),
984
1231
  /* @__PURE__ */ jsx(
@@ -1015,10 +1262,26 @@ function QualityHexagonExpandable({
1015
1262
  }
1016
1263
  );
1017
1264
  }
1018
- function calculateQualityTier(metrics) {
1019
- const metricsForAverage = { ...metrics };
1020
- metricsForAverage.deadCode = 100 - metricsForAverage.deadCode;
1021
- const average = Object.values(metricsForAverage).reduce((a, b) => a + b, 0) / 6;
1265
+ function calculateQualityTier(metrics, lensesRan) {
1266
+ const allMetricKeys = [
1267
+ "formatting",
1268
+ "linting",
1269
+ "types",
1270
+ "tests",
1271
+ "deadCode",
1272
+ "documentation"
1273
+ ];
1274
+ const configuredKeys = allMetricKeys.filter(
1275
+ (key) => isMetricConfigured(key, lensesRan)
1276
+ );
1277
+ if (configuredKeys.length === 0) {
1278
+ return "none";
1279
+ }
1280
+ const values = configuredKeys.map((key) => {
1281
+ const value = metrics[key];
1282
+ return key === "deadCode" ? 100 - value : value;
1283
+ });
1284
+ const average = values.reduce((a, b) => a + b, 0) / values.length;
1022
1285
  if (average >= 90) return "platinum";
1023
1286
  if (average >= 75) return "gold";
1024
1287
  if (average >= 60) return "silver";
@@ -1089,12 +1352,42 @@ const CommandLine = ({ command, theme, label }) => {
1089
1352
  };
1090
1353
  const MetricsPreview = ({ theme }) => {
1091
1354
  const metrics = [
1092
- { key: "formatting", label: "Formatting", description: "Prettier code style", Icon: Sparkles },
1093
- { key: "linting", label: "Linting", description: "ESLint code quality", Icon: FileSearch },
1094
- { key: "types", label: "Types", description: "TypeScript type safety", Icon: Braces },
1095
- { key: "tests", label: "Tests", description: "Test coverage & pass rate", Icon: FlaskConical },
1096
- { key: "deadCode", label: "Dead Code", description: "Unused exports & deps", Icon: Trash2 },
1097
- { key: "documentation", label: "Docs", description: "Code documentation", Icon: BookOpen }
1355
+ {
1356
+ key: "formatting",
1357
+ label: "Formatting",
1358
+ description: "Prettier code style",
1359
+ Icon: Sparkles
1360
+ },
1361
+ {
1362
+ key: "linting",
1363
+ label: "Linting",
1364
+ description: "ESLint code quality",
1365
+ Icon: FileSearch
1366
+ },
1367
+ {
1368
+ key: "types",
1369
+ label: "Types",
1370
+ description: "TypeScript type safety",
1371
+ Icon: Braces
1372
+ },
1373
+ {
1374
+ key: "tests",
1375
+ label: "Tests",
1376
+ description: "Test coverage & pass rate",
1377
+ Icon: FlaskConical
1378
+ },
1379
+ {
1380
+ key: "deadCode",
1381
+ label: "Dead Code",
1382
+ description: "Unused exports & deps",
1383
+ Icon: Trash2
1384
+ },
1385
+ {
1386
+ key: "documentation",
1387
+ label: "Docs",
1388
+ description: "Code documentation",
1389
+ Icon: BookOpen
1390
+ }
1098
1391
  ];
1099
1392
  return /* @__PURE__ */ jsx(
1100
1393
  "div",
@@ -1198,13 +1491,32 @@ const QualityEmptyState = ({
1198
1491
  color: theme.colors.textMuted
1199
1492
  },
1200
1493
  children: [
1201
- /* @__PURE__ */ jsx(Info, { size: 14, style: { flexShrink: 0, marginTop: 2 }, color: theme.colors.warning }),
1494
+ /* @__PURE__ */ jsx(
1495
+ Info,
1496
+ {
1497
+ size: 14,
1498
+ style: { flexShrink: 0, marginTop: 2 },
1499
+ color: theme.colors.warning
1500
+ }
1501
+ ),
1202
1502
  /* @__PURE__ */ jsxs("div", { children: [
1203
1503
  /* @__PURE__ */ jsx("strong", { style: { color: theme.colors.text }, children: "Using private npm packages?" }),
1204
1504
  /* @__PURE__ */ jsx("br", {}),
1205
- "Add ",
1206
- /* @__PURE__ */ jsx("code", { style: { backgroundColor: theme.colors.background, padding: "1px 4px", borderRadius: 3 }, children: "NPM_TOKEN" }),
1207
- " to your repository secrets and ensure the workflow has access to it."
1505
+ "Add",
1506
+ " ",
1507
+ /* @__PURE__ */ jsx(
1508
+ "code",
1509
+ {
1510
+ style: {
1511
+ backgroundColor: theme.colors.background,
1512
+ padding: "1px 4px",
1513
+ borderRadius: 3
1514
+ },
1515
+ children: "NPM_TOKEN"
1516
+ }
1517
+ ),
1518
+ " ",
1519
+ "to your repository secrets and ensure the workflow has access to it."
1208
1520
  ] })
1209
1521
  ]
1210
1522
  }
@@ -1424,13 +1736,32 @@ const QualityEmptyState = ({
1424
1736
  color: theme.colors.textMuted
1425
1737
  },
1426
1738
  children: [
1427
- /* @__PURE__ */ jsx(Info, { size: 14, style: { flexShrink: 0, marginTop: 2 }, color: theme.colors.warning }),
1739
+ /* @__PURE__ */ jsx(
1740
+ Info,
1741
+ {
1742
+ size: 14,
1743
+ style: { flexShrink: 0, marginTop: 2 },
1744
+ color: theme.colors.warning
1745
+ }
1746
+ ),
1428
1747
  /* @__PURE__ */ jsxs("div", { children: [
1429
1748
  /* @__PURE__ */ jsx("strong", { style: { color: theme.colors.text }, children: "Private npm packages?" }),
1430
1749
  /* @__PURE__ */ jsx("br", {}),
1431
- "If your project uses private @org packages, add ",
1432
- /* @__PURE__ */ jsx("code", { style: { backgroundColor: theme.colors.background, padding: "1px 4px", borderRadius: 3 }, children: "NPM_TOKEN" }),
1433
- " to your GitHub repository secrets under Settings → Secrets → Actions, and set the workflow environment if needed."
1750
+ "If your project uses private @org packages, add",
1751
+ " ",
1752
+ /* @__PURE__ */ jsx(
1753
+ "code",
1754
+ {
1755
+ style: {
1756
+ backgroundColor: theme.colors.background,
1757
+ padding: "1px 4px",
1758
+ borderRadius: 3
1759
+ },
1760
+ children: "NPM_TOKEN"
1761
+ }
1762
+ ),
1763
+ " ",
1764
+ "to your GitHub repository secrets under Settings → Secrets → Actions, and set the workflow environment if needed."
1434
1765
  ] })
1435
1766
  ]
1436
1767
  }
@@ -1471,12 +1802,26 @@ const QualityHexagonPanelContent = ({
1471
1802
  var _a;
1472
1803
  const { theme } = useTheme();
1473
1804
  const [refreshingPackages, setRefreshingPackages] = React2__default.useState(/* @__PURE__ */ new Set());
1805
+ const [showHelpOverlay, setShowHelpOverlay] = React2__default.useState(false);
1806
+ const [copiedCommand, setCopiedCommand] = React2__default.useState(null);
1807
+ const handleCopyCommand = async (command) => {
1808
+ try {
1809
+ await navigator.clipboard.writeText(command);
1810
+ setCopiedCommand(command);
1811
+ setTimeout(() => setCopiedCommand(null), 2e3);
1812
+ } catch {
1813
+ console.log("Copy:", command);
1814
+ }
1815
+ };
1474
1816
  const qualitySlice = context.getSlice("quality");
1475
1817
  const hasQualitySlice = context.hasSlice("quality");
1476
1818
  const isLoading = (qualitySlice == null ? void 0 : qualitySlice.loading) ?? false;
1477
1819
  const fileTreeSlice = context.getSlice("fileTree");
1478
1820
  const hasWorkflow = React2__default.useMemo(() => {
1479
- return checkFileExistsInTree((fileTreeSlice == null ? void 0 : fileTreeSlice.data) ?? void 0, WORKFLOW_FILE_PATH);
1821
+ return checkFileExistsInTree(
1822
+ (fileTreeSlice == null ? void 0 : fileTreeSlice.data) ?? void 0,
1823
+ WORKFLOW_FILE_PATH
1824
+ );
1480
1825
  }, [fileTreeSlice == null ? void 0 : fileTreeSlice.data]);
1481
1826
  const packages = React2__default.useMemo(() => {
1482
1827
  var _a2;
@@ -1514,15 +1859,37 @@ const QualityHexagonPanelContent = ({
1514
1859
  gold: "#FFD700",
1515
1860
  platinum: "#E5E4E2"
1516
1861
  };
1862
+ const allLensesRan = React2__default.useMemo(() => {
1863
+ const lensSet = /* @__PURE__ */ new Set();
1864
+ for (const pkg of packages) {
1865
+ if (pkg.lensesRan) {
1866
+ for (const lens of pkg.lensesRan) {
1867
+ lensSet.add(lens);
1868
+ }
1869
+ }
1870
+ }
1871
+ return lensSet.size > 0 ? Array.from(lensSet) : void 0;
1872
+ }, [packages]);
1517
1873
  const overallTier = packages.length > 0 ? calculateQualityTier(
1518
- packages.reduce((acc, pkg) => ({
1519
- tests: acc.tests + pkg.metrics.tests / packages.length,
1520
- deadCode: acc.deadCode + pkg.metrics.deadCode / packages.length,
1521
- linting: acc.linting + pkg.metrics.linting / packages.length,
1522
- formatting: acc.formatting + pkg.metrics.formatting / packages.length,
1523
- types: acc.types + pkg.metrics.types / packages.length,
1524
- documentation: acc.documentation + pkg.metrics.documentation / packages.length
1525
- }), { tests: 0, deadCode: 0, linting: 0, formatting: 0, types: 0, documentation: 0 })
1874
+ packages.reduce(
1875
+ (acc, pkg) => ({
1876
+ tests: acc.tests + pkg.metrics.tests / packages.length,
1877
+ deadCode: acc.deadCode + pkg.metrics.deadCode / packages.length,
1878
+ linting: acc.linting + pkg.metrics.linting / packages.length,
1879
+ formatting: acc.formatting + pkg.metrics.formatting / packages.length,
1880
+ types: acc.types + pkg.metrics.types / packages.length,
1881
+ documentation: acc.documentation + pkg.metrics.documentation / packages.length
1882
+ }),
1883
+ {
1884
+ tests: 0,
1885
+ deadCode: 0,
1886
+ linting: 0,
1887
+ formatting: 0,
1888
+ types: 0,
1889
+ documentation: 0
1890
+ }
1891
+ ),
1892
+ allLensesRan
1526
1893
  ) : "none";
1527
1894
  return /* @__PURE__ */ jsxs(
1528
1895
  "div",
@@ -1536,59 +1903,73 @@ const QualityHexagonPanelContent = ({
1536
1903
  overflowY: "auto",
1537
1904
  boxSizing: "border-box",
1538
1905
  display: "flex",
1539
- flexDirection: "column"
1906
+ flexDirection: "column",
1907
+ position: "relative"
1540
1908
  },
1541
1909
  children: [
1542
- /* @__PURE__ */ jsxs("div", { style: {
1543
- display: "flex",
1544
- alignItems: "center",
1545
- gap: 12,
1546
- height: 40,
1547
- flexShrink: 0,
1548
- padding: "0 16px",
1549
- borderBottom: `1px solid ${theme.colors.border}`,
1550
- boxSizing: "border-box"
1551
- }, children: [
1552
- /* @__PURE__ */ jsx(Hexagon, { size: 20, color: tierColors[overallTier] }),
1553
- /* @__PURE__ */ jsx(
1554
- "h2",
1555
- {
1556
- style: {
1557
- margin: 0,
1558
- fontSize: 14,
1559
- fontWeight: 600,
1560
- color: theme.colors.text
1561
- },
1562
- children: "Code Quality"
1563
- }
1564
- ),
1565
- /* @__PURE__ */ jsx(
1566
- "span",
1567
- {
1568
- title: "Platinum: 90%+ avg | Gold: 75%+ | Silver: 60%+ | Bronze: 40%+",
1569
- style: {
1570
- display: "inline-flex",
1571
- alignItems: "center",
1572
- justifyContent: "center",
1573
- width: 16,
1574
- height: 16,
1575
- borderRadius: "50%",
1576
- border: `1px solid ${theme.colors.border}`,
1577
- fontSize: 11,
1578
- color: theme.colors.textMuted,
1579
- cursor: "help"
1580
- },
1581
- children: "?"
1582
- }
1583
- ),
1584
- packages.length > 1 && /* @__PURE__ */ jsxs("span", { style: {
1585
- fontSize: 13,
1586
- color: theme.colors.textMuted
1587
- }, children: [
1588
- packages.length,
1589
- " packages"
1590
- ] })
1591
- ] }),
1910
+ /* @__PURE__ */ jsxs(
1911
+ "div",
1912
+ {
1913
+ style: {
1914
+ display: "flex",
1915
+ alignItems: "center",
1916
+ gap: 12,
1917
+ height: 40,
1918
+ flexShrink: 0,
1919
+ padding: "0 16px",
1920
+ borderBottom: `1px solid ${theme.colors.border}`,
1921
+ boxSizing: "border-box"
1922
+ },
1923
+ children: [
1924
+ /* @__PURE__ */ jsx(Hexagon, { size: 20, color: tierColors[overallTier] }),
1925
+ /* @__PURE__ */ jsx(
1926
+ "h2",
1927
+ {
1928
+ style: {
1929
+ margin: 0,
1930
+ fontSize: 14,
1931
+ fontWeight: 600,
1932
+ color: theme.colors.text
1933
+ },
1934
+ children: "Code Quality"
1935
+ }
1936
+ ),
1937
+ /* @__PURE__ */ jsx(
1938
+ "span",
1939
+ {
1940
+ onClick: () => setShowHelpOverlay(true),
1941
+ title: "Click for help",
1942
+ style: {
1943
+ display: "inline-flex",
1944
+ alignItems: "center",
1945
+ justifyContent: "center",
1946
+ width: 16,
1947
+ height: 16,
1948
+ borderRadius: "50%",
1949
+ border: `1px solid ${theme.colors.border}`,
1950
+ fontSize: 11,
1951
+ color: theme.colors.textMuted,
1952
+ cursor: "pointer"
1953
+ },
1954
+ children: "?"
1955
+ }
1956
+ ),
1957
+ packages.length > 1 && /* @__PURE__ */ jsxs(
1958
+ "span",
1959
+ {
1960
+ style: {
1961
+ fontSize: 13,
1962
+ color: theme.colors.textMuted
1963
+ },
1964
+ children: [
1965
+ packages.length,
1966
+ " packages"
1967
+ ]
1968
+ }
1969
+ )
1970
+ ]
1971
+ }
1972
+ ),
1592
1973
  /* @__PURE__ */ jsx(
1593
1974
  "div",
1594
1975
  {
@@ -1600,54 +1981,229 @@ const QualityHexagonPanelContent = ({
1600
1981
  flex: 1,
1601
1982
  minHeight: 0
1602
1983
  },
1603
- children: /* @__PURE__ */ jsx("div", { style: { display: "flex", flexWrap: "wrap", gap: 16, minHeight: 0 }, children: isLoading ? /* @__PURE__ */ jsx("div", { style: {
1604
- padding: 40,
1605
- textAlign: "center",
1606
- color: theme.colors.textMuted
1607
- }, children: "Loading quality metrics..." }) : packages.length === 0 ? /* @__PURE__ */ jsx(
1608
- QualityEmptyState,
1984
+ children: /* @__PURE__ */ jsx(
1985
+ "div",
1609
1986
  {
1610
- theme,
1611
- hasWorkflow
1612
- }
1613
- ) : packages.map((pkg) => {
1614
- const tier = calculateQualityTier(pkg.metrics);
1615
- const packagePath = pkg.path ?? "";
1616
- return /* @__PURE__ */ jsx(
1617
- QualityHexagonExpandable,
1618
- {
1619
- metrics: pkg.metrics,
1620
- tier,
1621
- theme,
1622
- packageName: pkg.name,
1623
- packageVersion: pkg.version,
1624
- packagePath,
1625
- onExpandChange: (expanded, info) => {
1626
- events.emit({
1627
- type: "package:select",
1628
- source: "principal-ade.quality-hexagon-panel",
1629
- timestamp: Date.now(),
1630
- payload: expanded ? {
1631
- packagePath: info.packagePath ?? "",
1632
- packageName: info.packageName
1633
- } : null
1634
- });
1635
- },
1636
- onMetricClick: (metric) => {
1637
- const colorMode = METRIC_TO_COLOR_MODE[metric];
1638
- if (colorMode) {
1639
- events.emit({
1640
- type: "quality:colorMode:select",
1641
- source: "principal-ade.quality-hexagon-panel",
1642
- timestamp: Date.now(),
1643
- payload: { colorMode }
1644
- });
1645
- }
1987
+ style: { display: "flex", flexWrap: "wrap", gap: 16, minHeight: 0 },
1988
+ children: isLoading ? /* @__PURE__ */ jsx(
1989
+ "div",
1990
+ {
1991
+ style: {
1992
+ padding: 40,
1993
+ textAlign: "center",
1994
+ color: theme.colors.textMuted
1995
+ },
1996
+ children: "Loading quality metrics..."
1646
1997
  }
1998
+ ) : packages.length === 0 ? /* @__PURE__ */ jsx(QualityEmptyState, { theme, hasWorkflow }) : packages.map((pkg) => {
1999
+ const tier = calculateQualityTier(pkg.metrics, pkg.lensesRan);
2000
+ const packagePath = pkg.path ?? "";
2001
+ return /* @__PURE__ */ jsx(
2002
+ QualityHexagonExpandable,
2003
+ {
2004
+ metrics: pkg.metrics,
2005
+ tier,
2006
+ theme,
2007
+ packageName: pkg.name,
2008
+ packageVersion: pkg.version,
2009
+ packagePath,
2010
+ lensesRan: pkg.lensesRan,
2011
+ onExpandChange: (expanded, info) => {
2012
+ events.emit({
2013
+ type: "package:select",
2014
+ source: "principal-ade.quality-hexagon-panel",
2015
+ timestamp: Date.now(),
2016
+ payload: expanded ? {
2017
+ packagePath: info.packagePath ?? "",
2018
+ packageName: info.packageName
2019
+ } : null
2020
+ });
2021
+ },
2022
+ onMetricClick: (metric) => {
2023
+ const colorMode = METRIC_TO_COLOR_MODE[metric];
2024
+ if (colorMode) {
2025
+ events.emit({
2026
+ type: "quality:colorMode:select",
2027
+ source: "principal-ade.quality-hexagon-panel",
2028
+ timestamp: Date.now(),
2029
+ payload: { colorMode }
2030
+ });
2031
+ }
2032
+ }
2033
+ },
2034
+ pkg.name
2035
+ );
2036
+ })
2037
+ }
2038
+ )
2039
+ }
2040
+ ),
2041
+ showHelpOverlay && /* @__PURE__ */ jsx(
2042
+ "div",
2043
+ {
2044
+ style: {
2045
+ position: "absolute",
2046
+ top: 0,
2047
+ left: 0,
2048
+ right: 0,
2049
+ bottom: 0,
2050
+ backgroundColor: "rgba(0, 0, 0, 0.7)",
2051
+ display: "flex",
2052
+ alignItems: "center",
2053
+ justifyContent: "center",
2054
+ zIndex: 100
2055
+ },
2056
+ onClick: () => setShowHelpOverlay(false),
2057
+ children: /* @__PURE__ */ jsxs(
2058
+ "div",
2059
+ {
2060
+ style: {
2061
+ backgroundColor: theme.colors.surface,
2062
+ borderRadius: 8,
2063
+ padding: 20,
2064
+ maxWidth: 400,
2065
+ width: "90%",
2066
+ border: `1px solid ${theme.colors.border}`
1647
2067
  },
1648
- pkg.name
1649
- );
1650
- }) })
2068
+ onClick: (e) => e.stopPropagation(),
2069
+ children: [
2070
+ /* @__PURE__ */ jsxs(
2071
+ "div",
2072
+ {
2073
+ style: {
2074
+ display: "flex",
2075
+ justifyContent: "space-between",
2076
+ alignItems: "center",
2077
+ marginBottom: 16
2078
+ },
2079
+ children: [
2080
+ /* @__PURE__ */ jsx(
2081
+ "h3",
2082
+ {
2083
+ style: {
2084
+ margin: 0,
2085
+ fontSize: 16,
2086
+ fontWeight: 600,
2087
+ color: theme.colors.text
2088
+ },
2089
+ children: "Quality Lens CLI"
2090
+ }
2091
+ ),
2092
+ /* @__PURE__ */ jsx(
2093
+ "button",
2094
+ {
2095
+ onClick: () => setShowHelpOverlay(false),
2096
+ style: {
2097
+ background: "none",
2098
+ border: "none",
2099
+ cursor: "pointer",
2100
+ padding: 4,
2101
+ display: "flex",
2102
+ color: theme.colors.textMuted
2103
+ },
2104
+ children: /* @__PURE__ */ jsx(X, { size: 18 })
2105
+ }
2106
+ )
2107
+ ]
2108
+ }
2109
+ ),
2110
+ /* @__PURE__ */ jsx(
2111
+ "p",
2112
+ {
2113
+ style: {
2114
+ fontSize: 13,
2115
+ color: theme.colors.textMuted,
2116
+ margin: "0 0 12px 0"
2117
+ },
2118
+ children: "Run quality checks locally with the CLI:"
2119
+ }
2120
+ ),
2121
+ [
2122
+ {
2123
+ cmd: "npx @principal-ai/quality-lens-cli init",
2124
+ label: "Initialize quality lens in your project"
2125
+ },
2126
+ {
2127
+ cmd: "npx @principal-ai/quality-lens-cli list",
2128
+ label: "List available quality lenses"
2129
+ }
2130
+ ].map(({ cmd, label }) => /* @__PURE__ */ jsxs("div", { style: { marginBottom: 12 }, children: [
2131
+ /* @__PURE__ */ jsx("span", { style: { fontSize: 11, color: theme.colors.textMuted }, children: label }),
2132
+ /* @__PURE__ */ jsxs(
2133
+ "div",
2134
+ {
2135
+ style: {
2136
+ display: "flex",
2137
+ alignItems: "center",
2138
+ justifyContent: "space-between",
2139
+ gap: 8,
2140
+ padding: "8px 12px",
2141
+ borderRadius: 6,
2142
+ backgroundColor: theme.colors.background,
2143
+ border: `1px solid ${theme.colors.border}`,
2144
+ fontFamily: "monospace",
2145
+ fontSize: 12,
2146
+ marginTop: 4
2147
+ },
2148
+ children: [
2149
+ /* @__PURE__ */ jsx("code", { style: { color: theme.colors.text }, children: cmd }),
2150
+ /* @__PURE__ */ jsx(
2151
+ "button",
2152
+ {
2153
+ onClick: () => handleCopyCommand(cmd),
2154
+ style: {
2155
+ display: "flex",
2156
+ alignItems: "center",
2157
+ padding: 4,
2158
+ border: "none",
2159
+ backgroundColor: "transparent",
2160
+ color: theme.colors.textMuted,
2161
+ cursor: "pointer"
2162
+ },
2163
+ title: "Copy command",
2164
+ children: copiedCommand === cmd ? /* @__PURE__ */ jsx(Check, { size: 14, color: theme.colors.success }) : /* @__PURE__ */ jsx(Copy, { size: 14 })
2165
+ }
2166
+ )
2167
+ ]
2168
+ }
2169
+ )
2170
+ ] }, cmd)),
2171
+ /* @__PURE__ */ jsxs(
2172
+ "div",
2173
+ {
2174
+ style: {
2175
+ marginTop: 16,
2176
+ padding: 12,
2177
+ backgroundColor: theme.colors.background,
2178
+ borderRadius: 6,
2179
+ fontSize: 12,
2180
+ color: theme.colors.textMuted
2181
+ },
2182
+ children: [
2183
+ /* @__PURE__ */ jsx("strong", { style: { color: theme.colors.text }, children: "Tiers:" }),
2184
+ /* @__PURE__ */ jsxs(
2185
+ "div",
2186
+ {
2187
+ style: {
2188
+ marginTop: 8,
2189
+ display: "flex",
2190
+ flexDirection: "column",
2191
+ gap: 4
2192
+ },
2193
+ children: [
2194
+ /* @__PURE__ */ jsx("span", { children: "🏆 Platinum: 90%+ average" }),
2195
+ /* @__PURE__ */ jsx("span", { children: "🥇 Gold: 75%+ average" }),
2196
+ /* @__PURE__ */ jsx("span", { children: "🥈 Silver: 60%+ average" }),
2197
+ /* @__PURE__ */ jsx("span", { children: "🥉 Bronze: 40%+ average" })
2198
+ ]
2199
+ }
2200
+ )
2201
+ ]
2202
+ }
2203
+ )
2204
+ ]
2205
+ }
2206
+ )
1651
2207
  }
1652
2208
  )
1653
2209
  ]
@@ -1692,7 +2248,14 @@ function calculateOverallTier(items) {
1692
2248
  types: acc.types + item.metrics.types / items.length,
1693
2249
  documentation: acc.documentation + item.metrics.documentation / items.length
1694
2250
  }),
1695
- { tests: 0, deadCode: 0, linting: 0, formatting: 0, types: 0, documentation: 0 }
2251
+ {
2252
+ tests: 0,
2253
+ deadCode: 0,
2254
+ linting: 0,
2255
+ formatting: 0,
2256
+ types: 0,
2257
+ documentation: 0
2258
+ }
1696
2259
  );
1697
2260
  return calculateQualityTier(avgMetrics);
1698
2261
  }
@@ -1873,11 +2436,6 @@ function RepositoryQualityGridItem({
1873
2436
  }
1874
2437
  );
1875
2438
  }
1876
- function calculateAverageScore(metrics) {
1877
- const adjusted = { ...metrics };
1878
- adjusted.deadCode = 100 - adjusted.deadCode;
1879
- return Object.values(adjusted).reduce((a, b) => a + b, 0) / 6;
1880
- }
1881
2439
  function RepositoryQualityGrid({
1882
2440
  repositories,
1883
2441
  theme,
@@ -1887,20 +2445,19 @@ function RepositoryQualityGrid({
1887
2445
  showRepositoryName = true,
1888
2446
  showSummary = true
1889
2447
  }) {
1890
- const [selectedMetric, setSelectedMetric] = React2.useState(null);
1891
- const items = React2.useMemo(() => flattenRepositories(repositories), [repositories]);
2448
+ const [selectedMetric, setSelectedMetric] = React2.useState(
2449
+ null
2450
+ );
2451
+ const items = React2.useMemo(
2452
+ () => flattenRepositories(repositories),
2453
+ [repositories]
2454
+ );
1892
2455
  const overallTier = React2.useMemo(() => calculateOverallTier(items), [items]);
1893
2456
  const sortedItems = React2.useMemo(() => {
1894
- return [...items].sort((a, b) => {
1895
- if (selectedMetric) {
1896
- const aVal = selectedMetric === "deadCode" ? 100 - a.metrics[selectedMetric] : a.metrics[selectedMetric];
1897
- const bVal = selectedMetric === "deadCode" ? 100 - b.metrics[selectedMetric] : b.metrics[selectedMetric];
1898
- return bVal - aVal;
1899
- } else {
1900
- return calculateAverageScore(b.metrics) - calculateAverageScore(a.metrics);
1901
- }
1902
- });
1903
- }, [items, selectedMetric]);
2457
+ return [...items].sort(
2458
+ (a, b) => a.packageName.localeCompare(b.packageName)
2459
+ );
2460
+ }, [items]);
1904
2461
  const tierColors = {
1905
2462
  none: "#808080",
1906
2463
  bronze: "#CD7F32",
@@ -1994,7 +2551,9 @@ function RepositoryQualityGrid({
1994
2551
  "select",
1995
2552
  {
1996
2553
  value: selectedMetric ?? "",
1997
- onChange: (e) => setSelectedMetric(e.target.value ? e.target.value : null),
2554
+ onChange: (e) => setSelectedMetric(
2555
+ e.target.value ? e.target.value : null
2556
+ ),
1998
2557
  style: {
1999
2558
  padding: "4px 8px",
2000
2559
  fontSize: 13,
@@ -2086,8 +2645,12 @@ const RepositoryQualityGridPanelContent = ({
2086
2645
  }) => {
2087
2646
  var _a;
2088
2647
  const { theme } = useTheme();
2089
- const [selectedItemKey, setSelectedItemKey] = React2__default.useState(null);
2090
- const qualitySlice = context.getSlice("repositoriesQuality");
2648
+ const [selectedItemKey, setSelectedItemKey] = React2__default.useState(
2649
+ null
2650
+ );
2651
+ const qualitySlice = context.getSlice(
2652
+ "repositoriesQuality"
2653
+ );
2091
2654
  const isLoading = (qualitySlice == null ? void 0 : qualitySlice.loading) ?? false;
2092
2655
  const repositories = React2__default.useMemo(() => {
2093
2656
  var _a2;
@@ -2249,7 +2812,13 @@ function getPackageSummary(results) {
2249
2812
  failCount++;
2250
2813
  }
2251
2814
  }
2252
- return { totalErrors, totalWarnings, passCount, failCount, lensCount: results.length };
2815
+ return {
2816
+ totalErrors,
2817
+ totalWarnings,
2818
+ passCount,
2819
+ failCount,
2820
+ lensCount: results.length
2821
+ };
2253
2822
  }
2254
2823
  function LensDataDebugPanel$1({
2255
2824
  data,
@@ -2259,13 +2828,21 @@ function LensDataDebugPanel$1({
2259
2828
  onFileClick,
2260
2829
  onPackageSelect
2261
2830
  }) {
2262
- const packageGroups = React2.useMemo(() => groupResultsByPackage((data == null ? void 0 : data.results) ?? []), [data == null ? void 0 : data.results]);
2263
- const packageNames = React2.useMemo(() => Array.from(packageGroups.keys()), [packageGroups]);
2831
+ const packageGroups = React2.useMemo(
2832
+ () => groupResultsByPackage((data == null ? void 0 : data.results) ?? []),
2833
+ [data == null ? void 0 : data.results]
2834
+ );
2835
+ const packageNames = React2.useMemo(
2836
+ () => Array.from(packageGroups.keys()),
2837
+ [packageGroups]
2838
+ );
2264
2839
  const [selectedPackage, setSelectedPackage] = React2.useState(
2265
2840
  initialSelectedPackage || (packageNames.length === 1 ? packageNames[0] : null)
2266
2841
  );
2267
2842
  const [expandedLens, setExpandedLens] = React2.useState(null);
2268
- const [expandedFiles, setExpandedFiles] = React2.useState(/* @__PURE__ */ new Set());
2843
+ const [expandedFiles, setExpandedFiles] = React2.useState(
2844
+ /* @__PURE__ */ new Set()
2845
+ );
2269
2846
  const handlePackageSelect = (pkg) => {
2270
2847
  setSelectedPackage(pkg);
2271
2848
  setExpandedLens(null);
@@ -2300,82 +2877,112 @@ function LensDataDebugPanel$1({
2300
2877
  fontSize: 13
2301
2878
  },
2302
2879
  children: [
2303
- packageNames.length > 1 && /* @__PURE__ */ jsx("div", { style: {
2304
- display: "flex",
2305
- flexWrap: "wrap",
2306
- gap: 8,
2307
- marginBottom: 8
2308
- }, children: packageNames.map((pkg) => {
2309
- const summary = getPackageSummary(packageGroups.get(pkg) || []);
2310
- const isSelected = selectedPackage === pkg;
2311
- return /* @__PURE__ */ jsxs(
2312
- "button",
2313
- {
2314
- onClick: () => handlePackageSelect(pkg),
2315
- style: {
2316
- display: "flex",
2317
- alignItems: "center",
2318
- gap: 8,
2319
- padding: "8px 12px",
2320
- borderRadius: 6,
2321
- border: `1px solid ${isSelected ? theme.colors.primary : theme.colors.border}`,
2322
- backgroundColor: isSelected ? theme.colors.surface : "transparent",
2323
- color: theme.colors.text,
2324
- cursor: "pointer",
2325
- transition: "all 0.15s ease"
2326
- },
2327
- children: [
2328
- /* @__PURE__ */ jsx("span", { style: { fontWeight: 500 }, children: pkg }),
2329
- /* @__PURE__ */ jsxs("span", { style: {
2330
- fontSize: 11,
2331
- padding: "2px 6px",
2332
- borderRadius: 4,
2333
- backgroundColor: summary.totalErrors > 0 ? getSeverityBg("error") : summary.totalWarnings > 0 ? getSeverityBg("warning") : "rgba(34, 197, 94, 0.1)",
2334
- color: summary.totalErrors > 0 ? getSeverityColor("error") : summary.totalWarnings > 0 ? getSeverityColor("warning") : "#22c55e"
2335
- }, children: [
2336
- summary.passCount,
2337
- "/",
2338
- summary.lensCount,
2339
- " pass"
2340
- ] })
2341
- ]
2880
+ packageNames.length > 1 && /* @__PURE__ */ jsx(
2881
+ "div",
2882
+ {
2883
+ style: {
2884
+ display: "flex",
2885
+ flexWrap: "wrap",
2886
+ gap: 8,
2887
+ marginBottom: 8
2342
2888
  },
2343
- pkg
2344
- );
2345
- }) }),
2346
- packageNames.length === 1 && /* @__PURE__ */ jsxs("div", { style: {
2347
- display: "flex",
2348
- alignItems: "center",
2349
- gap: 12,
2350
- padding: "8px 12px",
2351
- backgroundColor: theme.colors.surface,
2352
- borderRadius: 6,
2353
- marginBottom: 8
2354
- }, children: [
2355
- /* @__PURE__ */ jsx("span", { style: { fontWeight: 600, color: theme.colors.text }, children: packageNames[0] }),
2356
- (() => {
2357
- const summary = getPackageSummary(selectedResults);
2358
- return /* @__PURE__ */ jsxs("span", { style: {
2359
- fontSize: 11,
2360
- padding: "2px 6px",
2361
- borderRadius: 4,
2362
- backgroundColor: summary.totalErrors > 0 ? getSeverityBg("error") : summary.totalWarnings > 0 ? getSeverityBg("warning") : "rgba(34, 197, 94, 0.1)",
2363
- color: summary.totalErrors > 0 ? getSeverityColor("error") : summary.totalWarnings > 0 ? getSeverityColor("warning") : "#22c55e"
2364
- }, children: [
2365
- summary.passCount,
2366
- "/",
2367
- summary.lensCount,
2368
- " pass"
2369
- ] });
2370
- })()
2371
- ] }),
2372
- !selectedPackage && packageNames.length > 1 && /* @__PURE__ */ jsx("div", { style: {
2373
- padding: 24,
2374
- textAlign: "center",
2375
- color: theme.colors.textMuted,
2376
- backgroundColor: theme.colors.surface,
2377
- borderRadius: 6
2378
- }, children: "Select a package above to view lens results" }),
2889
+ children: packageNames.map((pkg) => {
2890
+ const summary = getPackageSummary(packageGroups.get(pkg) || []);
2891
+ const isSelected = selectedPackage === pkg;
2892
+ return /* @__PURE__ */ jsxs(
2893
+ "button",
2894
+ {
2895
+ onClick: () => handlePackageSelect(pkg),
2896
+ style: {
2897
+ display: "flex",
2898
+ alignItems: "center",
2899
+ gap: 8,
2900
+ padding: "8px 12px",
2901
+ borderRadius: 6,
2902
+ border: `1px solid ${isSelected ? theme.colors.primary : theme.colors.border}`,
2903
+ backgroundColor: isSelected ? theme.colors.surface : "transparent",
2904
+ color: theme.colors.text,
2905
+ cursor: "pointer",
2906
+ transition: "all 0.15s ease"
2907
+ },
2908
+ children: [
2909
+ /* @__PURE__ */ jsx("span", { style: { fontWeight: 500 }, children: pkg }),
2910
+ /* @__PURE__ */ jsxs(
2911
+ "span",
2912
+ {
2913
+ style: {
2914
+ fontSize: 11,
2915
+ padding: "2px 6px",
2916
+ borderRadius: 4,
2917
+ backgroundColor: summary.totalErrors > 0 ? getSeverityBg("error") : summary.totalWarnings > 0 ? getSeverityBg("warning") : "rgba(34, 197, 94, 0.1)",
2918
+ color: summary.totalErrors > 0 ? getSeverityColor("error") : summary.totalWarnings > 0 ? getSeverityColor("warning") : "#22c55e"
2919
+ },
2920
+ children: [
2921
+ summary.passCount,
2922
+ "/",
2923
+ summary.lensCount,
2924
+ " pass"
2925
+ ]
2926
+ }
2927
+ )
2928
+ ]
2929
+ },
2930
+ pkg
2931
+ );
2932
+ })
2933
+ }
2934
+ ),
2935
+ packageNames.length === 1 && /* @__PURE__ */ jsxs(
2936
+ "div",
2937
+ {
2938
+ style: {
2939
+ display: "flex",
2940
+ alignItems: "center",
2941
+ gap: 12,
2942
+ padding: "8px 12px",
2943
+ backgroundColor: theme.colors.surface,
2944
+ borderRadius: 6,
2945
+ marginBottom: 8
2946
+ },
2947
+ children: [
2948
+ /* @__PURE__ */ jsx("span", { style: { fontWeight: 600, color: theme.colors.text }, children: packageNames[0] }),
2949
+ (() => {
2950
+ const summary = getPackageSummary(selectedResults);
2951
+ return /* @__PURE__ */ jsxs(
2952
+ "span",
2953
+ {
2954
+ style: {
2955
+ fontSize: 11,
2956
+ padding: "2px 6px",
2957
+ borderRadius: 4,
2958
+ backgroundColor: summary.totalErrors > 0 ? getSeverityBg("error") : summary.totalWarnings > 0 ? getSeverityBg("warning") : "rgba(34, 197, 94, 0.1)",
2959
+ color: summary.totalErrors > 0 ? getSeverityColor("error") : summary.totalWarnings > 0 ? getSeverityColor("warning") : "#22c55e"
2960
+ },
2961
+ children: [
2962
+ summary.passCount,
2963
+ "/",
2964
+ summary.lensCount,
2965
+ " pass"
2966
+ ]
2967
+ }
2968
+ );
2969
+ })()
2970
+ ]
2971
+ }
2972
+ ),
2973
+ !selectedPackage && packageNames.length > 1 && /* @__PURE__ */ jsx(
2974
+ "div",
2975
+ {
2976
+ style: {
2977
+ padding: 24,
2978
+ textAlign: "center",
2979
+ color: theme.colors.textMuted,
2980
+ backgroundColor: theme.colors.surface,
2981
+ borderRadius: 6
2982
+ },
2983
+ children: "Select a package above to view lens results"
2984
+ }
2985
+ ),
2379
2986
  selectedPackage && selectedResults.map((result, idx) => {
2380
2987
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s;
2381
2988
  const lensKey = `${((_a = result.lens) == null ? void 0 : _a.id) ?? "unknown"}-${idx}`;
@@ -2430,34 +3037,53 @@ function LensDataDebugPanel$1({
2430
3037
  ] })
2431
3038
  ] }),
2432
3039
  /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 12 }, children: [
2433
- /* @__PURE__ */ jsx("span", { style: {
2434
- padding: "2px 6px",
2435
- borderRadius: 4,
2436
- fontSize: 11,
2437
- backgroundColor: ((_e = result.execution) == null ? void 0 : _e.success) ? "rgba(34, 197, 94, 0.1)" : "rgba(239, 68, 68, 0.1)",
2438
- color: ((_f = result.execution) == null ? void 0 : _f.success) ? "#22c55e" : "#ef4444"
2439
- }, children: ((_g = result.execution) == null ? void 0 : _g.success) ? "pass" : "fail" }),
3040
+ /* @__PURE__ */ jsx(
3041
+ "span",
3042
+ {
3043
+ style: {
3044
+ padding: "2px 6px",
3045
+ borderRadius: 4,
3046
+ fontSize: 11,
3047
+ backgroundColor: ((_e = result.execution) == null ? void 0 : _e.success) ? "rgba(34, 197, 94, 0.1)" : "rgba(239, 68, 68, 0.1)",
3048
+ color: ((_f = result.execution) == null ? void 0 : _f.success) ? "#22c55e" : "#ef4444"
3049
+ },
3050
+ children: ((_g = result.execution) == null ? void 0 : _g.success) ? "pass" : "fail"
3051
+ }
3052
+ ),
2440
3053
  hasIssues && /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: 6 }, children: [
2441
- (((_i = (_h = result.metrics) == null ? void 0 : _h.issuesBySeverity) == null ? void 0 : _i.error) ?? 0) > 0 && /* @__PURE__ */ jsxs("span", { style: {
2442
- padding: "2px 6px",
2443
- borderRadius: 4,
2444
- fontSize: 11,
2445
- backgroundColor: getSeverityBg("error"),
2446
- color: getSeverityColor("error")
2447
- }, children: [
2448
- ((_k = (_j = result.metrics) == null ? void 0 : _j.issuesBySeverity) == null ? void 0 : _k.error) ?? 0,
2449
- " errors"
2450
- ] }),
2451
- (((_m = (_l = result.metrics) == null ? void 0 : _l.issuesBySeverity) == null ? void 0 : _m.warning) ?? 0) > 0 && /* @__PURE__ */ jsxs("span", { style: {
2452
- padding: "2px 6px",
2453
- borderRadius: 4,
2454
- fontSize: 11,
2455
- backgroundColor: getSeverityBg("warning"),
2456
- color: getSeverityColor("warning")
2457
- }, children: [
2458
- ((_o = (_n = result.metrics) == null ? void 0 : _n.issuesBySeverity) == null ? void 0 : _o.warning) ?? 0,
2459
- " warnings"
2460
- ] })
3054
+ (((_i = (_h = result.metrics) == null ? void 0 : _h.issuesBySeverity) == null ? void 0 : _i.error) ?? 0) > 0 && /* @__PURE__ */ jsxs(
3055
+ "span",
3056
+ {
3057
+ style: {
3058
+ padding: "2px 6px",
3059
+ borderRadius: 4,
3060
+ fontSize: 11,
3061
+ backgroundColor: getSeverityBg("error"),
3062
+ color: getSeverityColor("error")
3063
+ },
3064
+ children: [
3065
+ ((_k = (_j = result.metrics) == null ? void 0 : _j.issuesBySeverity) == null ? void 0 : _k.error) ?? 0,
3066
+ " errors"
3067
+ ]
3068
+ }
3069
+ ),
3070
+ (((_m = (_l = result.metrics) == null ? void 0 : _l.issuesBySeverity) == null ? void 0 : _m.warning) ?? 0) > 0 && /* @__PURE__ */ jsxs(
3071
+ "span",
3072
+ {
3073
+ style: {
3074
+ padding: "2px 6px",
3075
+ borderRadius: 4,
3076
+ fontSize: 11,
3077
+ backgroundColor: getSeverityBg("warning"),
3078
+ color: getSeverityColor("warning")
3079
+ },
3080
+ children: [
3081
+ ((_o = (_n = result.metrics) == null ? void 0 : _n.issuesBySeverity) == null ? void 0 : _o.warning) ?? 0,
3082
+ " ",
3083
+ "warnings"
3084
+ ]
3085
+ }
3086
+ )
2461
3087
  ] }),
2462
3088
  /* @__PURE__ */ jsxs("span", { style: { fontSize: 12, color: theme.colors.textMuted }, children: [
2463
3089
  ((_p = result.metrics) == null ? void 0 : _p.filesAnalyzed) ?? 0,
@@ -2467,235 +3093,412 @@ function LensDataDebugPanel$1({
2467
3093
  ]
2468
3094
  }
2469
3095
  ),
2470
- isExpanded && /* @__PURE__ */ jsxs("div", { style: {
2471
- padding: 12,
2472
- backgroundColor: theme.colors.backgroundLight,
2473
- borderTop: `1px solid ${theme.colors.border}`
2474
- }, children: [
2475
- /* @__PURE__ */ jsxs("div", { style: {
2476
- display: "grid",
2477
- gridTemplateColumns: "repeat(auto-fit, minmax(120px, 1fr))",
2478
- gap: 8,
2479
- marginBottom: 16,
2480
- padding: 12,
2481
- backgroundColor: theme.colors.surface,
2482
- borderRadius: 4
2483
- }, children: [
2484
- /* @__PURE__ */ jsxs("div", { children: [
2485
- /* @__PURE__ */ jsx("div", { style: { fontSize: 11, color: theme.colors.textMuted }, children: "Files Analyzed" }),
2486
- /* @__PURE__ */ jsx("div", { style: { fontSize: 16, fontWeight: 600, color: theme.colors.text }, children: ((_q = result.metrics) == null ? void 0 : _q.filesAnalyzed) ?? 0 })
2487
- ] }),
2488
- /* @__PURE__ */ jsxs("div", { children: [
2489
- /* @__PURE__ */ jsx("div", { style: { fontSize: 11, color: theme.colors.textMuted }, children: "Total Issues" }),
2490
- /* @__PURE__ */ jsx("div", { style: { fontSize: 16, fontWeight: 600, color: theme.colors.text }, children: ((_r = result.metrics) == null ? void 0 : _r.totalIssues) ?? 0 })
2491
- ] }),
2492
- /* @__PURE__ */ jsxs("div", { children: [
2493
- /* @__PURE__ */ jsx("div", { style: { fontSize: 11, color: theme.colors.textMuted }, children: "Duration" }),
2494
- /* @__PURE__ */ jsxs("div", { style: { fontSize: 16, fontWeight: 600, color: theme.colors.text }, children: [
2495
- ((_s = result.execution) == null ? void 0 : _s.duration) ?? 0,
2496
- "ms"
2497
- ] })
2498
- ] }),
2499
- result.coverage && /* @__PURE__ */ jsxs("div", { children: [
2500
- /* @__PURE__ */ jsx("div", { style: { fontSize: 11, color: theme.colors.textMuted }, children: "Coverage" }),
2501
- /* @__PURE__ */ jsxs("div", { style: { fontSize: 16, fontWeight: 600, color: theme.colors.text }, children: [
2502
- result.coverage.line,
2503
- "%"
2504
- ] })
2505
- ] })
2506
- ] }),
2507
- filesWithIssues.size > 0 ? /* @__PURE__ */ jsxs("div", { children: [
2508
- /* @__PURE__ */ jsxs("div", { style: {
2509
- fontSize: 12,
2510
- fontWeight: 600,
2511
- color: theme.colors.textMuted,
2512
- marginBottom: 8
2513
- }, children: [
2514
- "Files with Issues (",
2515
- filesWithIssues.size,
2516
- ")"
2517
- ] }),
2518
- /* @__PURE__ */ jsx("div", { style: { display: "flex", flexDirection: "column", gap: 4 }, children: Array.from(filesWithIssues.entries()).map(([file, issues]) => {
2519
- const isFileExpanded = expandedFiles.has(file);
2520
- return /* @__PURE__ */ jsxs(
3096
+ isExpanded && /* @__PURE__ */ jsxs(
3097
+ "div",
3098
+ {
3099
+ style: {
3100
+ padding: 12,
3101
+ backgroundColor: theme.colors.backgroundLight,
3102
+ borderTop: `1px solid ${theme.colors.border}`
3103
+ },
3104
+ children: [
3105
+ /* @__PURE__ */ jsxs(
2521
3106
  "div",
2522
3107
  {
2523
3108
  style: {
2524
- border: `1px solid ${theme.colors.border}`,
2525
- borderRadius: 4,
2526
- overflow: "hidden"
3109
+ display: "grid",
3110
+ gridTemplateColumns: "repeat(auto-fit, minmax(120px, 1fr))",
3111
+ gap: 8,
3112
+ marginBottom: 16,
3113
+ padding: 12,
3114
+ backgroundColor: theme.colors.surface,
3115
+ borderRadius: 4
2527
3116
  },
2528
3117
  children: [
2529
- /* @__PURE__ */ jsxs(
2530
- "div",
2531
- {
2532
- onClick: () => toggleFile(file),
2533
- style: {
2534
- display: "flex",
2535
- alignItems: "center",
2536
- justifyContent: "space-between",
2537
- padding: "8px 10px",
2538
- backgroundColor: theme.colors.surface,
2539
- cursor: "pointer"
2540
- },
2541
- children: [
2542
- /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 6 }, children: [
2543
- /* @__PURE__ */ jsx(
2544
- "svg",
2545
- {
2546
- width: "12",
2547
- height: "12",
2548
- viewBox: "0 0 24 24",
2549
- fill: "none",
2550
- stroke: theme.colors.textMuted,
2551
- strokeWidth: "2",
2552
- style: {
2553
- transform: isFileExpanded ? "rotate(90deg)" : "rotate(0deg)",
2554
- transition: "transform 0.15s ease"
2555
- },
2556
- children: /* @__PURE__ */ jsx("polyline", { points: "9,18 15,12 9,6" })
2557
- }
2558
- ),
2559
- /* @__PURE__ */ jsx(
2560
- "span",
2561
- {
2562
- style: {
2563
- color: theme.colors.text,
2564
- cursor: onFileClick ? "pointer" : "default"
2565
- },
2566
- onClick: (e) => {
2567
- if (onFileClick) {
2568
- e.stopPropagation();
2569
- onFileClick(file);
2570
- }
2571
- },
2572
- children: file
2573
- }
2574
- )
2575
- ] }),
2576
- /* @__PURE__ */ jsxs("span", { style: {
3118
+ /* @__PURE__ */ jsxs("div", { children: [
3119
+ /* @__PURE__ */ jsx(
3120
+ "div",
3121
+ {
3122
+ style: { fontSize: 11, color: theme.colors.textMuted },
3123
+ children: "Files Analyzed"
3124
+ }
3125
+ ),
3126
+ /* @__PURE__ */ jsx(
3127
+ "div",
3128
+ {
3129
+ style: {
3130
+ fontSize: 16,
3131
+ fontWeight: 600,
3132
+ color: theme.colors.text
3133
+ },
3134
+ children: ((_q = result.metrics) == null ? void 0 : _q.filesAnalyzed) ?? 0
3135
+ }
3136
+ )
3137
+ ] }),
3138
+ /* @__PURE__ */ jsxs("div", { children: [
3139
+ /* @__PURE__ */ jsx(
3140
+ "div",
3141
+ {
3142
+ style: { fontSize: 11, color: theme.colors.textMuted },
3143
+ children: "Total Issues"
3144
+ }
3145
+ ),
3146
+ /* @__PURE__ */ jsx(
3147
+ "div",
3148
+ {
3149
+ style: {
3150
+ fontSize: 16,
3151
+ fontWeight: 600,
3152
+ color: theme.colors.text
3153
+ },
3154
+ children: ((_r = result.metrics) == null ? void 0 : _r.totalIssues) ?? 0
3155
+ }
3156
+ )
3157
+ ] }),
3158
+ /* @__PURE__ */ jsxs("div", { children: [
3159
+ /* @__PURE__ */ jsx(
3160
+ "div",
3161
+ {
3162
+ style: { fontSize: 11, color: theme.colors.textMuted },
3163
+ children: "Duration"
3164
+ }
3165
+ ),
3166
+ /* @__PURE__ */ jsxs(
3167
+ "div",
3168
+ {
3169
+ style: {
3170
+ fontSize: 16,
3171
+ fontWeight: 600,
3172
+ color: theme.colors.text
3173
+ },
3174
+ children: [
3175
+ ((_s = result.execution) == null ? void 0 : _s.duration) ?? 0,
3176
+ "ms"
3177
+ ]
3178
+ }
3179
+ )
3180
+ ] }),
3181
+ result.coverage && /* @__PURE__ */ jsxs("div", { children: [
3182
+ /* @__PURE__ */ jsx(
3183
+ "div",
3184
+ {
3185
+ style: {
2577
3186
  fontSize: 11,
2578
- padding: "2px 6px",
2579
- borderRadius: 4,
2580
- backgroundColor: getSeverityBg("error"),
2581
- color: getSeverityColor("error")
2582
- }, children: [
2583
- issues.length,
2584
- " issues"
2585
- ] })
2586
- ]
3187
+ color: theme.colors.textMuted
3188
+ },
3189
+ children: "Coverage"
3190
+ }
3191
+ ),
3192
+ /* @__PURE__ */ jsxs(
3193
+ "div",
3194
+ {
3195
+ style: {
3196
+ fontSize: 16,
3197
+ fontWeight: 600,
3198
+ color: theme.colors.text
3199
+ },
3200
+ children: [
3201
+ result.coverage.line,
3202
+ "%"
3203
+ ]
3204
+ }
3205
+ )
3206
+ ] })
3207
+ ]
3208
+ }
3209
+ ),
3210
+ filesWithIssues.size > 0 ? /* @__PURE__ */ jsxs("div", { children: [
3211
+ /* @__PURE__ */ jsxs(
3212
+ "div",
3213
+ {
3214
+ style: {
3215
+ fontSize: 12,
3216
+ fontWeight: 600,
3217
+ color: theme.colors.textMuted,
3218
+ marginBottom: 8
3219
+ },
3220
+ children: [
3221
+ "Files with Issues (",
3222
+ filesWithIssues.size,
3223
+ ")"
3224
+ ]
3225
+ }
3226
+ ),
3227
+ /* @__PURE__ */ jsx(
3228
+ "div",
3229
+ {
3230
+ style: {
3231
+ display: "flex",
3232
+ flexDirection: "column",
3233
+ gap: 4
3234
+ },
3235
+ children: Array.from(filesWithIssues.entries()).map(
3236
+ ([file, issues]) => {
3237
+ const isFileExpanded = expandedFiles.has(file);
3238
+ return /* @__PURE__ */ jsxs(
3239
+ "div",
3240
+ {
3241
+ style: {
3242
+ border: `1px solid ${theme.colors.border}`,
3243
+ borderRadius: 4,
3244
+ overflow: "hidden"
3245
+ },
3246
+ children: [
3247
+ /* @__PURE__ */ jsxs(
3248
+ "div",
3249
+ {
3250
+ onClick: () => toggleFile(file),
3251
+ style: {
3252
+ display: "flex",
3253
+ alignItems: "center",
3254
+ justifyContent: "space-between",
3255
+ padding: "8px 10px",
3256
+ backgroundColor: theme.colors.surface,
3257
+ cursor: "pointer"
3258
+ },
3259
+ children: [
3260
+ /* @__PURE__ */ jsxs(
3261
+ "div",
3262
+ {
3263
+ style: {
3264
+ display: "flex",
3265
+ alignItems: "center",
3266
+ gap: 6
3267
+ },
3268
+ children: [
3269
+ /* @__PURE__ */ jsx(
3270
+ "svg",
3271
+ {
3272
+ width: "12",
3273
+ height: "12",
3274
+ viewBox: "0 0 24 24",
3275
+ fill: "none",
3276
+ stroke: theme.colors.textMuted,
3277
+ strokeWidth: "2",
3278
+ style: {
3279
+ transform: isFileExpanded ? "rotate(90deg)" : "rotate(0deg)",
3280
+ transition: "transform 0.15s ease"
3281
+ },
3282
+ children: /* @__PURE__ */ jsx("polyline", { points: "9,18 15,12 9,6" })
3283
+ }
3284
+ ),
3285
+ /* @__PURE__ */ jsx(
3286
+ "span",
3287
+ {
3288
+ style: {
3289
+ color: theme.colors.text,
3290
+ cursor: onFileClick ? "pointer" : "default"
3291
+ },
3292
+ onClick: (e) => {
3293
+ if (onFileClick) {
3294
+ e.stopPropagation();
3295
+ onFileClick(file);
3296
+ }
3297
+ },
3298
+ children: file
3299
+ }
3300
+ )
3301
+ ]
3302
+ }
3303
+ ),
3304
+ /* @__PURE__ */ jsxs(
3305
+ "span",
3306
+ {
3307
+ style: {
3308
+ fontSize: 11,
3309
+ padding: "2px 6px",
3310
+ borderRadius: 4,
3311
+ backgroundColor: getSeverityBg("error"),
3312
+ color: getSeverityColor("error")
3313
+ },
3314
+ children: [
3315
+ issues.length,
3316
+ " issues"
3317
+ ]
3318
+ }
3319
+ )
3320
+ ]
3321
+ }
3322
+ ),
3323
+ isFileExpanded && /* @__PURE__ */ jsx(
3324
+ "div",
3325
+ {
3326
+ style: {
3327
+ padding: 8,
3328
+ backgroundColor: theme.colors.background,
3329
+ borderTop: `1px solid ${theme.colors.border}`,
3330
+ maxHeight: 300,
3331
+ overflow: "auto"
3332
+ },
3333
+ children: issues.map((issue, issueIdx) => /* @__PURE__ */ jsxs(
3334
+ "div",
3335
+ {
3336
+ onClick: () => onFileClick == null ? void 0 : onFileClick(file, issue.line),
3337
+ style: {
3338
+ display: "flex",
3339
+ gap: 8,
3340
+ padding: "6px 8px",
3341
+ borderRadius: 4,
3342
+ cursor: onFileClick ? "pointer" : "default",
3343
+ transition: "background-color 0.1s ease"
3344
+ },
3345
+ onMouseEnter: (e) => {
3346
+ e.currentTarget.style.backgroundColor = theme.colors.surface;
3347
+ },
3348
+ onMouseLeave: (e) => {
3349
+ e.currentTarget.style.backgroundColor = "transparent";
3350
+ },
3351
+ children: [
3352
+ /* @__PURE__ */ jsxs(
3353
+ "span",
3354
+ {
3355
+ style: {
3356
+ fontSize: 11,
3357
+ color: theme.colors.textMuted,
3358
+ minWidth: 45
3359
+ },
3360
+ children: [
3361
+ "L",
3362
+ issue.line
3363
+ ]
3364
+ }
3365
+ ),
3366
+ /* @__PURE__ */ jsx(
3367
+ "span",
3368
+ {
3369
+ style: {
3370
+ fontSize: 10,
3371
+ padding: "1px 4px",
3372
+ borderRadius: 3,
3373
+ backgroundColor: getSeverityBg(
3374
+ issue.severity
3375
+ ),
3376
+ color: getSeverityColor(
3377
+ issue.severity
3378
+ ),
3379
+ textTransform: "uppercase"
3380
+ },
3381
+ children: issue.severity.charAt(0)
3382
+ }
3383
+ ),
3384
+ /* @__PURE__ */ jsx(
3385
+ "span",
3386
+ {
3387
+ style: {
3388
+ flex: 1,
3389
+ fontSize: 12,
3390
+ color: theme.colors.text
3391
+ },
3392
+ children: issue.message
3393
+ }
3394
+ ),
3395
+ issue.rule && /* @__PURE__ */ jsx(
3396
+ "span",
3397
+ {
3398
+ style: {
3399
+ fontSize: 10,
3400
+ color: theme.colors.textMuted,
3401
+ opacity: 0.7
3402
+ },
3403
+ children: issue.rule
3404
+ }
3405
+ )
3406
+ ]
3407
+ },
3408
+ issueIdx
3409
+ ))
3410
+ }
3411
+ )
3412
+ ]
3413
+ },
3414
+ file
3415
+ );
2587
3416
  }
2588
- ),
2589
- isFileExpanded && /* @__PURE__ */ jsx("div", { style: {
3417
+ )
3418
+ }
3419
+ )
3420
+ ] }) : /* @__PURE__ */ jsx(
3421
+ "div",
3422
+ {
3423
+ style: {
3424
+ padding: 16,
3425
+ textAlign: "center",
3426
+ color: theme.colors.textMuted,
3427
+ backgroundColor: theme.colors.surface,
3428
+ borderRadius: 4
3429
+ },
3430
+ children: "No issues found"
3431
+ }
3432
+ ),
3433
+ result.fileMetrics && result.fileMetrics.length > 0 && /* @__PURE__ */ jsxs("div", { style: { marginTop: 16 }, children: [
3434
+ /* @__PURE__ */ jsxs(
3435
+ "div",
3436
+ {
3437
+ style: {
3438
+ fontSize: 12,
3439
+ fontWeight: 600,
3440
+ color: theme.colors.textMuted,
3441
+ marginBottom: 8
3442
+ },
3443
+ children: [
3444
+ "File Metrics (",
3445
+ result.fileMetrics.length,
3446
+ ")"
3447
+ ]
3448
+ }
3449
+ ),
3450
+ /* @__PURE__ */ jsx(
3451
+ "div",
3452
+ {
3453
+ style: {
3454
+ display: "flex",
3455
+ flexDirection: "column",
3456
+ gap: 2,
2590
3457
  padding: 8,
2591
- backgroundColor: theme.colors.background,
2592
- borderTop: `1px solid ${theme.colors.border}`,
2593
- maxHeight: 300,
2594
- overflow: "auto"
2595
- }, children: issues.map((issue, issueIdx) => /* @__PURE__ */ jsxs(
3458
+ backgroundColor: theme.colors.surface,
3459
+ borderRadius: 4
3460
+ },
3461
+ children: result.fileMetrics.map((fm, idx2) => /* @__PURE__ */ jsxs(
2596
3462
  "div",
2597
3463
  {
2598
- onClick: () => onFileClick == null ? void 0 : onFileClick(file, issue.line),
2599
3464
  style: {
2600
3465
  display: "flex",
2601
- gap: 8,
2602
- padding: "6px 8px",
2603
- borderRadius: 4,
2604
- cursor: onFileClick ? "pointer" : "default",
2605
- transition: "background-color 0.1s ease"
2606
- },
2607
- onMouseEnter: (e) => {
2608
- e.currentTarget.style.backgroundColor = theme.colors.surface;
2609
- },
2610
- onMouseLeave: (e) => {
2611
- e.currentTarget.style.backgroundColor = "transparent";
3466
+ alignItems: "center",
3467
+ justifyContent: "space-between",
3468
+ padding: "4px 8px"
2612
3469
  },
2613
3470
  children: [
2614
- /* @__PURE__ */ jsxs("span", { style: {
2615
- fontSize: 11,
2616
- color: theme.colors.textMuted,
2617
- minWidth: 45
2618
- }, children: [
2619
- "L",
2620
- issue.line
2621
- ] }),
2622
- /* @__PURE__ */ jsx("span", { style: {
2623
- fontSize: 10,
2624
- padding: "1px 4px",
2625
- borderRadius: 3,
2626
- backgroundColor: getSeverityBg(issue.severity),
2627
- color: getSeverityColor(issue.severity),
2628
- textTransform: "uppercase"
2629
- }, children: issue.severity.charAt(0) }),
2630
- /* @__PURE__ */ jsx("span", { style: {
2631
- flex: 1,
2632
- fontSize: 12,
2633
- color: theme.colors.text
2634
- }, children: issue.message }),
2635
- issue.rule && /* @__PURE__ */ jsx("span", { style: {
2636
- fontSize: 10,
2637
- color: theme.colors.textMuted,
2638
- opacity: 0.7
2639
- }, children: issue.rule })
3471
+ /* @__PURE__ */ jsx(
3472
+ "span",
3473
+ {
3474
+ style: { color: theme.colors.text, fontSize: 12 },
3475
+ children: fm.file
3476
+ }
3477
+ ),
3478
+ /* @__PURE__ */ jsxs(
3479
+ "span",
3480
+ {
3481
+ style: {
3482
+ fontSize: 12,
3483
+ fontWeight: 500,
3484
+ color: fm.score >= 80 ? "#22c55e" : fm.score >= 60 ? "#f59e0b" : "#ef4444"
3485
+ },
3486
+ children: [
3487
+ fm.score,
3488
+ "%"
3489
+ ]
3490
+ }
3491
+ )
2640
3492
  ]
2641
3493
  },
2642
- issueIdx
2643
- )) })
2644
- ]
2645
- },
2646
- file
2647
- );
2648
- }) })
2649
- ] }) : /* @__PURE__ */ jsx("div", { style: {
2650
- padding: 16,
2651
- textAlign: "center",
2652
- color: theme.colors.textMuted,
2653
- backgroundColor: theme.colors.surface,
2654
- borderRadius: 4
2655
- }, children: "No issues found" }),
2656
- result.fileMetrics && result.fileMetrics.length > 0 && /* @__PURE__ */ jsxs("div", { style: { marginTop: 16 }, children: [
2657
- /* @__PURE__ */ jsxs("div", { style: {
2658
- fontSize: 12,
2659
- fontWeight: 600,
2660
- color: theme.colors.textMuted,
2661
- marginBottom: 8
2662
- }, children: [
2663
- "File Metrics (",
2664
- result.fileMetrics.length,
2665
- ")"
2666
- ] }),
2667
- /* @__PURE__ */ jsx("div", { style: {
2668
- display: "flex",
2669
- flexDirection: "column",
2670
- gap: 2,
2671
- padding: 8,
2672
- backgroundColor: theme.colors.surface,
2673
- borderRadius: 4
2674
- }, children: result.fileMetrics.map((fm, idx2) => /* @__PURE__ */ jsxs(
2675
- "div",
2676
- {
2677
- style: {
2678
- display: "flex",
2679
- alignItems: "center",
2680
- justifyContent: "space-between",
2681
- padding: "4px 8px"
2682
- },
2683
- children: [
2684
- /* @__PURE__ */ jsx("span", { style: { color: theme.colors.text, fontSize: 12 }, children: fm.file }),
2685
- /* @__PURE__ */ jsxs("span", { style: {
2686
- fontSize: 12,
2687
- fontWeight: 500,
2688
- color: fm.score >= 80 ? "#22c55e" : fm.score >= 60 ? "#f59e0b" : "#ef4444"
2689
- }, children: [
2690
- fm.score,
2691
- "%"
2692
- ] })
2693
- ]
2694
- },
2695
- idx2
2696
- )) })
2697
- ] })
2698
- ] })
3494
+ idx2
3495
+ ))
3496
+ }
3497
+ )
3498
+ ] })
3499
+ ]
3500
+ }
3501
+ )
2699
3502
  ]
2700
3503
  },
2701
3504
  lensKey
@@ -2738,45 +3541,68 @@ const LensDataDebugPanelContent = ({
2738
3541
  flexDirection: "column"
2739
3542
  },
2740
3543
  children: [
2741
- /* @__PURE__ */ jsxs("div", { style: {
2742
- display: "flex",
2743
- alignItems: "center",
2744
- justifyContent: "space-between",
2745
- height: 40,
2746
- flexShrink: 0,
2747
- padding: "0 16px",
2748
- borderBottom: `1px solid ${theme.colors.border}`,
2749
- boxSizing: "border-box"
2750
- }, children: [
2751
- /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 12 }, children: [
2752
- /* @__PURE__ */ jsx(Bug, { size: 18, color: theme.colors.primary }),
2753
- /* @__PURE__ */ jsx(
2754
- "h2",
2755
- {
2756
- style: {
2757
- margin: 0,
2758
- fontSize: 14,
2759
- fontWeight: 600,
2760
- color: theme.colors.text
2761
- },
2762
- children: "Lens Data Debug"
2763
- }
2764
- )
2765
- ] }),
2766
- (lensResultsSlice == null ? void 0 : lensResultsSlice.data) && /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 12, fontSize: 11, color: theme.colors.textMuted }, children: [
2767
- /* @__PURE__ */ jsxs("span", { children: [
2768
- new Set(lensResultsSlice.data.results.map((r2) => {
2769
- var _a;
2770
- return ((_a = r2.package) == null ? void 0 : _a.name) ?? "unknown";
2771
- })).size,
2772
- " packages"
2773
- ] }),
2774
- /* @__PURE__ */ jsxs("span", { children: [
2775
- lensResultsSlice.data.results.length,
2776
- " results"
2777
- ] })
2778
- ] })
2779
- ] }),
3544
+ /* @__PURE__ */ jsxs(
3545
+ "div",
3546
+ {
3547
+ style: {
3548
+ display: "flex",
3549
+ alignItems: "center",
3550
+ justifyContent: "space-between",
3551
+ height: 40,
3552
+ flexShrink: 0,
3553
+ padding: "0 16px",
3554
+ borderBottom: `1px solid ${theme.colors.border}`,
3555
+ boxSizing: "border-box"
3556
+ },
3557
+ children: [
3558
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 12 }, children: [
3559
+ /* @__PURE__ */ jsx(Bug, { size: 18, color: theme.colors.primary }),
3560
+ /* @__PURE__ */ jsx(
3561
+ "h2",
3562
+ {
3563
+ style: {
3564
+ margin: 0,
3565
+ fontSize: 14,
3566
+ fontWeight: 600,
3567
+ color: theme.colors.text
3568
+ },
3569
+ children: "Lens Data Debug"
3570
+ }
3571
+ )
3572
+ ] }),
3573
+ (lensResultsSlice == null ? void 0 : lensResultsSlice.data) && /* @__PURE__ */ jsxs(
3574
+ "div",
3575
+ {
3576
+ style: {
3577
+ display: "flex",
3578
+ alignItems: "center",
3579
+ gap: 12,
3580
+ fontSize: 11,
3581
+ color: theme.colors.textMuted
3582
+ },
3583
+ children: [
3584
+ /* @__PURE__ */ jsxs("span", { children: [
3585
+ new Set(
3586
+ lensResultsSlice.data.results.map(
3587
+ (r2) => {
3588
+ var _a;
3589
+ return ((_a = r2.package) == null ? void 0 : _a.name) ?? "unknown";
3590
+ }
3591
+ )
3592
+ ).size,
3593
+ " ",
3594
+ "packages"
3595
+ ] }),
3596
+ /* @__PURE__ */ jsxs("span", { children: [
3597
+ lensResultsSlice.data.results.length,
3598
+ " results"
3599
+ ] })
3600
+ ]
3601
+ }
3602
+ )
3603
+ ]
3604
+ }
3605
+ ),
2780
3606
  /* @__PURE__ */ jsx(
2781
3607
  "div",
2782
3608
  {
@@ -2785,19 +3611,38 @@ const LensDataDebugPanelContent = ({
2785
3611
  minHeight: 0,
2786
3612
  overflow: "auto"
2787
3613
  },
2788
- children: isLoading ? /* @__PURE__ */ jsx("div", { style: {
2789
- padding: 40,
2790
- textAlign: "center",
2791
- color: theme.colors.textMuted
2792
- }, children: "Loading lens results..." }) : !hasSlice || !(lensResultsSlice == null ? void 0 : lensResultsSlice.data) ? /* @__PURE__ */ jsxs("div", { style: {
2793
- padding: 40,
2794
- textAlign: "center",
2795
- color: theme.colors.textMuted
2796
- }, children: [
2797
- /* @__PURE__ */ jsx(Bug, { size: 48, color: theme.colors.border, style: { marginBottom: 16 } }),
2798
- /* @__PURE__ */ jsx("div", { style: { fontSize: 14, marginBottom: 8 }, children: "No lens data available" }),
2799
- /* @__PURE__ */ jsx("div", { style: { fontSize: 12 }, children: "Run quality-lens-cli or check that the lensResults slice is configured." })
2800
- ] }) : /* @__PURE__ */ jsx(
3614
+ children: isLoading ? /* @__PURE__ */ jsx(
3615
+ "div",
3616
+ {
3617
+ style: {
3618
+ padding: 40,
3619
+ textAlign: "center",
3620
+ color: theme.colors.textMuted
3621
+ },
3622
+ children: "Loading lens results..."
3623
+ }
3624
+ ) : !hasSlice || !(lensResultsSlice == null ? void 0 : lensResultsSlice.data) ? /* @__PURE__ */ jsxs(
3625
+ "div",
3626
+ {
3627
+ style: {
3628
+ padding: 40,
3629
+ textAlign: "center",
3630
+ color: theme.colors.textMuted
3631
+ },
3632
+ children: [
3633
+ /* @__PURE__ */ jsx(
3634
+ Bug,
3635
+ {
3636
+ size: 48,
3637
+ color: theme.colors.border,
3638
+ style: { marginBottom: 16 }
3639
+ }
3640
+ ),
3641
+ /* @__PURE__ */ jsx("div", { style: { fontSize: 14, marginBottom: 8 }, children: "No lens data available" }),
3642
+ /* @__PURE__ */ jsx("div", { style: { fontSize: 12 }, children: "Run quality-lens-cli or check that the lensResults slice is configured." })
3643
+ ]
3644
+ }
3645
+ ) : /* @__PURE__ */ jsx(
2801
3646
  LensDataDebugPanel$1,
2802
3647
  {
2803
3648
  data: lensResultsSlice.data,
@@ -2881,10 +3726,26 @@ function getMetricIcon(key) {
2881
3726
  }
2882
3727
  const METRIC_CONFIG = [
2883
3728
  { key: "types", label: "Types", description: "Type safety score" },
2884
- { key: "documentation", label: "Documentation", description: "Documentation coverage" },
2885
- { key: "tests", label: "Tests", description: "Test coverage and passing rate" },
2886
- { key: "deadCode", label: "Dead Code", description: "Unused code detected" },
2887
- { key: "formatting", label: "Formatting", description: "Code formatting consistency" },
3729
+ {
3730
+ key: "documentation",
3731
+ label: "Documentation",
3732
+ description: "Documentation coverage"
3733
+ },
3734
+ {
3735
+ key: "tests",
3736
+ label: "Tests",
3737
+ description: "Test coverage and passing rate"
3738
+ },
3739
+ {
3740
+ key: "deadCode",
3741
+ label: "Dead Code",
3742
+ description: "Unused code detected"
3743
+ },
3744
+ {
3745
+ key: "formatting",
3746
+ label: "Formatting",
3747
+ description: "Code formatting consistency"
3748
+ },
2888
3749
  { key: "linting", label: "Linting", description: "Linting compliance" }
2889
3750
  ];
2890
3751
  function QualityMetricsList({