@principal-ade/code-quality-panels 0.1.25 → 0.1.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -370,7 +370,16 @@ var LENS_REGISTRY = [
370
370
  outputsAggregate: true,
371
371
  colorScheme: "issues",
372
372
  description: "Pluggable linting utility for JavaScript and TypeScript",
373
- command: "eslint"
373
+ command: "eslint",
374
+ fileMetricsRequirements: {
375
+ completeCommand: "npx eslint . --format json",
376
+ requiredFlags: ["--format json"],
377
+ formatFlag: "--format json",
378
+ withoutConfig: "Only files with issues are reported in the output",
379
+ fallbackStrategy: "source-file-count",
380
+ nativelyComplete: false,
381
+ notes: "ESLint JSON output only includes files that have issues. Clean files are not listed."
382
+ }
374
383
  },
375
384
  {
376
385
  id: "biome-lint",
@@ -382,7 +391,16 @@ var LENS_REGISTRY = [
382
391
  outputsAggregate: true,
383
392
  colorScheme: "issues",
384
393
  description: "Fast linter for JavaScript and TypeScript",
385
- command: "biome lint"
394
+ command: "biome lint",
395
+ fileMetricsRequirements: {
396
+ completeCommand: "npx @biomejs/biome lint . --reporter=json",
397
+ requiredFlags: ["--reporter=json"],
398
+ formatFlag: "--reporter=json",
399
+ withoutConfig: "Output cannot be parsed for file metrics",
400
+ fallbackStrategy: "source-file-count",
401
+ nativelyComplete: true,
402
+ notes: "Biome JSON output includes all analyzed files."
403
+ }
386
404
  },
387
405
  {
388
406
  id: "oxlint",
@@ -394,7 +412,15 @@ var LENS_REGISTRY = [
394
412
  outputsAggregate: true,
395
413
  colorScheme: "issues",
396
414
  description: "Blazing fast JavaScript/TypeScript linter",
397
- command: "oxlint"
415
+ command: "oxlint",
416
+ fileMetricsRequirements: {
417
+ completeCommand: "npx oxlint --format json",
418
+ requiredFlags: ["--format json"],
419
+ formatFlag: "--format json",
420
+ withoutConfig: "Output cannot be parsed for file metrics",
421
+ fallbackStrategy: "source-file-count",
422
+ nativelyComplete: false
423
+ }
398
424
  },
399
425
  // Python linting
400
426
  {
@@ -407,7 +433,16 @@ var LENS_REGISTRY = [
407
433
  outputsAggregate: true,
408
434
  colorScheme: "issues",
409
435
  description: "Extremely fast Python linter",
410
- command: "ruff check"
436
+ command: "ruff check",
437
+ fileMetricsRequirements: {
438
+ completeCommand: "ruff check . --output-format=json",
439
+ requiredFlags: ["--output-format=json"],
440
+ formatFlag: "--output-format=json",
441
+ withoutConfig: "Output cannot be parsed for file metrics",
442
+ fallbackStrategy: "source-file-count",
443
+ nativelyComplete: false,
444
+ notes: "Ruff JSON output only includes files with issues."
445
+ }
411
446
  },
412
447
  {
413
448
  id: "pylint",
@@ -418,7 +453,15 @@ var LENS_REGISTRY = [
418
453
  outputsAggregate: true,
419
454
  colorScheme: "issues",
420
455
  description: "Python static code analyzer",
421
- command: "pylint"
456
+ command: "pylint",
457
+ fileMetricsRequirements: {
458
+ completeCommand: "pylint --output-format=json .",
459
+ requiredFlags: ["--output-format=json"],
460
+ formatFlag: "--output-format=json",
461
+ withoutConfig: "Output cannot be parsed for file metrics",
462
+ fallbackStrategy: "source-file-count",
463
+ nativelyComplete: false
464
+ }
422
465
  },
423
466
  // Go linting
424
467
  {
@@ -442,7 +485,16 @@ var LENS_REGISTRY = [
442
485
  outputsAggregate: true,
443
486
  colorScheme: "issues",
444
487
  description: "Rust linter",
445
- command: "cargo clippy"
488
+ command: "cargo clippy",
489
+ fileMetricsRequirements: {
490
+ completeCommand: "cargo clippy --workspace --all-features --message-format json -- -D warnings",
491
+ requiredFlags: ["--message-format json"],
492
+ formatFlag: "--message-format json",
493
+ withoutConfig: "Only files with issues are reported in the output",
494
+ fallbackStrategy: "source-file-count",
495
+ nativelyComplete: false,
496
+ notes: "Clippy JSON output only includes files with issues. Use cargo metadata to get complete file list."
497
+ }
446
498
  },
447
499
  // ============================================================
448
500
  // FORMATTING - Code formatting
@@ -457,7 +509,15 @@ var LENS_REGISTRY = [
457
509
  outputsAggregate: true,
458
510
  colorScheme: "binary",
459
511
  description: "Opinionated code formatter",
460
- command: "prettier --check"
512
+ command: "prettier --check",
513
+ fileMetricsRequirements: {
514
+ completeCommand: "npx prettier --check . --no-error-on-unmatched-pattern --log-level debug",
515
+ requiredFlags: ["--check", "--log-level debug"],
516
+ withoutConfig: "Without --log-level debug, file list is not available",
517
+ fallbackStrategy: "source-file-count",
518
+ nativelyComplete: true,
519
+ notes: "Prettier with --log-level debug lists all checked files. This is the reference implementation for complete file metrics."
520
+ }
461
521
  },
462
522
  {
463
523
  id: "biome-format",
@@ -469,7 +529,15 @@ var LENS_REGISTRY = [
469
529
  outputsAggregate: true,
470
530
  colorScheme: "binary",
471
531
  description: "Fast code formatter for JavaScript and TypeScript",
472
- command: "biome format"
532
+ command: "biome format",
533
+ fileMetricsRequirements: {
534
+ completeCommand: "npx @biomejs/biome format . --reporter=json",
535
+ requiredFlags: ["--reporter=json"],
536
+ formatFlag: "--reporter=json",
537
+ withoutConfig: "Output cannot be parsed for file metrics",
538
+ fallbackStrategy: "source-file-count",
539
+ nativelyComplete: true
540
+ }
473
541
  },
474
542
  // Python formatting
475
543
  {
@@ -517,7 +585,15 @@ var LENS_REGISTRY = [
517
585
  outputsAggregate: true,
518
586
  colorScheme: "binary",
519
587
  description: "Rust code formatter",
520
- command: "cargo fmt --check"
588
+ command: "cargo fmt --check",
589
+ fileMetricsRequirements: {
590
+ completeCommand: "cargo fmt --all --check",
591
+ requiredFlags: ["--check"],
592
+ withoutConfig: "Without --check, files are modified in place",
593
+ fallbackStrategy: "source-file-count",
594
+ nativelyComplete: false,
595
+ notes: "rustfmt only outputs files that need formatting. Use cargo metadata or glob for complete file list."
596
+ }
521
597
  },
522
598
  // ============================================================
523
599
  // TYPES - Type checking
@@ -532,7 +608,15 @@ var LENS_REGISTRY = [
532
608
  outputsAggregate: true,
533
609
  colorScheme: "issues",
534
610
  description: "TypeScript type checker",
535
- command: "tsc --noEmit"
611
+ command: "tsc --noEmit",
612
+ fileMetricsRequirements: {
613
+ completeCommand: "npx tsc --noEmit --listFiles",
614
+ requiredFlags: ["--listFiles"],
615
+ withoutConfig: "Only files with type errors are reported. Cannot determine total files analyzed.",
616
+ fallbackStrategy: "source-file-count",
617
+ nativelyComplete: false,
618
+ notes: "The --listFiles flag is REQUIRED to get the complete list of files TypeScript analyzed. Without it, only files with errors appear in output."
619
+ }
536
620
  },
537
621
  // Python type checking
538
622
  {
@@ -583,7 +667,16 @@ var LENS_REGISTRY = [
583
667
  outputsAggregate: true,
584
668
  colorScheme: "coverage",
585
669
  description: "JavaScript testing framework",
586
- command: "jest --coverage"
670
+ command: "jest --coverage",
671
+ fileMetricsRequirements: {
672
+ completeCommand: "npx jest --coverage --json --outputFile=jest-results.json",
673
+ requiredFlags: ["--coverage", "--json"],
674
+ formatFlag: "--json",
675
+ withoutConfig: "Without --coverage, no per-file coverage data is available. Without --json, output cannot be parsed.",
676
+ fallbackStrategy: "coverage-only",
677
+ nativelyComplete: false,
678
+ notes: "Jest coverage data provides per-file metrics for source files. Test file results are separate from source coverage."
679
+ }
587
680
  },
588
681
  {
589
682
  id: "vitest",
@@ -595,7 +688,16 @@ var LENS_REGISTRY = [
595
688
  outputsAggregate: true,
596
689
  colorScheme: "coverage",
597
690
  description: "Vite-native testing framework",
598
- command: "vitest run --coverage"
691
+ command: "vitest run --coverage",
692
+ fileMetricsRequirements: {
693
+ completeCommand: "npx vitest run --coverage --reporter=json",
694
+ requiredFlags: ["--coverage", "--reporter=json"],
695
+ formatFlag: "--reporter=json",
696
+ withoutConfig: "Without --coverage, no per-file coverage data is available",
697
+ fallbackStrategy: "coverage-only",
698
+ nativelyComplete: false,
699
+ notes: "Vitest coverage provides per-file metrics. Requires @vitest/coverage-v8 or @vitest/coverage-istanbul."
700
+ }
599
701
  },
600
702
  {
601
703
  id: "bun-test",
@@ -607,7 +709,35 @@ var LENS_REGISTRY = [
607
709
  outputsAggregate: true,
608
710
  colorScheme: "coverage",
609
711
  description: "Bun native test runner",
610
- command: "bun test"
712
+ command: "bun test",
713
+ fileMetricsRequirements: {
714
+ completeCommand: "bun test --coverage",
715
+ requiredFlags: ["--coverage"],
716
+ withoutConfig: "Without --coverage, no per-file coverage data is available",
717
+ fallbackStrategy: "coverage-only",
718
+ nativelyComplete: false,
719
+ notes: "Bun test coverage is built-in but requires --coverage flag."
720
+ }
721
+ },
722
+ {
723
+ id: "node-test",
724
+ name: "Node Test",
725
+ category: "tests",
726
+ languages: ["typescript", "javascript"],
727
+ alternativeTo: ["jest", "vitest", "bun-test"],
728
+ outputsFileMetrics: true,
729
+ outputsAggregate: true,
730
+ colorScheme: "coverage",
731
+ description: "Node.js native test runner",
732
+ command: "node --test",
733
+ fileMetricsRequirements: {
734
+ completeCommand: "node --test --experimental-test-coverage",
735
+ requiredFlags: ["--experimental-test-coverage"],
736
+ withoutConfig: "Without --experimental-test-coverage, no per-file coverage data is available",
737
+ fallbackStrategy: "coverage-only",
738
+ nativelyComplete: false,
739
+ notes: "Node.js native test runner (node:test) uses TAP output format. Coverage requires --experimental-test-coverage flag (Node 20+). Also works with tsx --test for TypeScript."
740
+ }
611
741
  },
612
742
  // Python testing
613
743
  {
@@ -643,7 +773,37 @@ var LENS_REGISTRY = [
643
773
  outputsAggregate: true,
644
774
  colorScheme: "coverage",
645
775
  description: "Rust test runner",
646
- command: "cargo test"
776
+ command: "cargo test",
777
+ fileMetricsRequirements: {
778
+ completeCommand: "cargo test --workspace --no-fail-fast -- -Z unstable-options --format json",
779
+ requiredFlags: ["--format json"],
780
+ formatFlag: "--format json",
781
+ withoutConfig: "Without JSON format, output cannot be parsed for test results",
782
+ fallbackStrategy: "coverage-only",
783
+ nativelyComplete: false,
784
+ notes: "JSON format requires nightly or -Z unstable-options. Consider cargo-nextest for stable JSON output."
785
+ }
786
+ },
787
+ {
788
+ id: "cargo-nextest",
789
+ name: "Cargo Nextest",
790
+ category: "tests",
791
+ languages: ["rust"],
792
+ alternativeTo: ["cargo-test"],
793
+ outputsFileMetrics: true,
794
+ outputsAggregate: true,
795
+ colorScheme: "coverage",
796
+ description: "Next-generation Rust test runner",
797
+ command: "cargo nextest run",
798
+ fileMetricsRequirements: {
799
+ completeCommand: "cargo nextest run --workspace --message-format libtest-json",
800
+ requiredFlags: ["--message-format libtest-json"],
801
+ formatFlag: "--message-format libtest-json",
802
+ withoutConfig: "Without JSON format, output cannot be parsed",
803
+ fallbackStrategy: "coverage-only",
804
+ nativelyComplete: false,
805
+ notes: "Nextest provides stable JSON output without nightly features."
806
+ }
647
807
  },
648
808
  // ============================================================
649
809
  // DEAD CODE - Unused code detection
@@ -658,7 +818,16 @@ var LENS_REGISTRY = [
658
818
  outputsAggregate: true,
659
819
  colorScheme: "issues",
660
820
  description: "Find unused files, dependencies and exports",
661
- command: "knip"
821
+ command: "knip",
822
+ fileMetricsRequirements: {
823
+ completeCommand: "npx knip --reporter json",
824
+ requiredFlags: ["--reporter json"],
825
+ formatFlag: "--reporter json",
826
+ withoutConfig: "Output cannot be parsed for file metrics",
827
+ fallbackStrategy: "source-file-count",
828
+ nativelyComplete: false,
829
+ notes: "Knip reports unused files and exports. It does not list all analyzed files, only those with issues."
830
+ }
662
831
  },
663
832
  // Python
664
833
  {
@@ -684,7 +853,16 @@ var LENS_REGISTRY = [
684
853
  outputsAggregate: true,
685
854
  colorScheme: "binary",
686
855
  description: "Documentation coverage checker",
687
- command: "alexandria lint"
856
+ command: "alexandria lint",
857
+ fileMetricsRequirements: {
858
+ completeCommand: "npx @principal-ai/alexandria-cli coverage --json",
859
+ requiredFlags: ["--json"],
860
+ formatFlag: "--json",
861
+ withoutConfig: "Output cannot be parsed for file metrics",
862
+ fallbackStrategy: "source-file-count",
863
+ nativelyComplete: true,
864
+ notes: "Alexandria reports documentation coverage for all analyzed files."
865
+ }
688
866
  },
689
867
  {
690
868
  id: "typedoc",
@@ -1544,7 +1722,10 @@ function QualityHexagonExpandable({
1544
1722
  },
1545
1723
  children: metricConfig.map(({ key, label }) => {
1546
1724
  const value = metrics[key];
1547
- const configured = isMetricConfigured(key, lensesRan);
1725
+ const configured = isMetricConfigured(
1726
+ key,
1727
+ lensesRan
1728
+ );
1548
1729
  return /* @__PURE__ */ jsxs(
1549
1730
  "div",
1550
1731
  {
@@ -2179,7 +2360,10 @@ const LEGACY_FALLBACKS = {
2179
2360
  function getColorModeForMetric(metric, lensesRan) {
2180
2361
  if (!isValidHexagonMetric(metric)) return null;
2181
2362
  const hexagonMetric = metric;
2182
- const colorMode = getColorModeForHexagonMetric(hexagonMetric, lensesRan ?? []);
2363
+ const colorMode = getColorModeForHexagonMetric(
2364
+ hexagonMetric,
2365
+ lensesRan ?? []
2366
+ );
2183
2367
  if (!colorMode && lensesRan === void 0) {
2184
2368
  return LEGACY_FALLBACKS[hexagonMetric] ?? null;
2185
2369
  }
@@ -2413,7 +2597,10 @@ const QualityHexagonPanelContent = ({
2413
2597
  });
2414
2598
  },
2415
2599
  onMetricClick: (metric) => {
2416
- const colorMode = getColorModeForMetric(metric, pkg.lensesRan);
2600
+ const colorMode = getColorModeForMetric(
2601
+ metric,
2602
+ pkg.lensesRan
2603
+ );
2417
2604
  if (colorMode) {
2418
2605
  events.emit({
2419
2606
  type: "quality:colorMode:select",
@@ -3236,10 +3423,25 @@ function LensDataDebugPanel$1({
3236
3423
  const [expandedFiles, setExpandedFiles] = React2.useState(
3237
3424
  /* @__PURE__ */ new Set()
3238
3425
  );
3426
+ const [expandedAnalyzedFiles, setExpandedAnalyzedFiles] = React2.useState(/* @__PURE__ */ new Set());
3427
+ React2.useEffect(() => {
3428
+ if (initialSelectedPackage) {
3429
+ setSelectedPackage((current) => {
3430
+ if (current !== initialSelectedPackage) {
3431
+ setExpandedLens(null);
3432
+ setExpandedFiles(/* @__PURE__ */ new Set());
3433
+ setExpandedAnalyzedFiles(/* @__PURE__ */ new Set());
3434
+ return initialSelectedPackage;
3435
+ }
3436
+ return current;
3437
+ });
3438
+ }
3439
+ }, [initialSelectedPackage]);
3239
3440
  const handlePackageSelect = (pkg) => {
3240
3441
  setSelectedPackage(pkg);
3241
3442
  setExpandedLens(null);
3242
3443
  setExpandedFiles(/* @__PURE__ */ new Set());
3444
+ setExpandedAnalyzedFiles(/* @__PURE__ */ new Set());
3243
3445
  onPackageSelect == null ? void 0 : onPackageSelect(pkg);
3244
3446
  };
3245
3447
  const toggleLens = (lensId) => {
@@ -3255,6 +3457,15 @@ function LensDataDebugPanel$1({
3255
3457
  }
3256
3458
  setExpandedFiles(newSet);
3257
3459
  };
3460
+ const toggleAnalyzedFiles = (lensKey) => {
3461
+ const newSet = new Set(expandedAnalyzedFiles);
3462
+ if (newSet.has(lensKey)) {
3463
+ newSet.delete(lensKey);
3464
+ } else {
3465
+ newSet.add(lensKey);
3466
+ }
3467
+ setExpandedAnalyzedFiles(newSet);
3468
+ };
3258
3469
  const selectedResults = selectedPackage ? packageGroups.get(selectedPackage) || [] : [];
3259
3470
  return /* @__PURE__ */ jsxs(
3260
3471
  "div",
@@ -3270,62 +3481,7 @@ function LensDataDebugPanel$1({
3270
3481
  fontSize: 13
3271
3482
  },
3272
3483
  children: [
3273
- packageNames.length > 1 && /* @__PURE__ */ jsx(
3274
- "div",
3275
- {
3276
- style: {
3277
- display: "flex",
3278
- flexWrap: "wrap",
3279
- gap: 8,
3280
- marginBottom: 8
3281
- },
3282
- children: packageNames.map((pkg) => {
3283
- const summary = getPackageSummary(packageGroups.get(pkg) || []);
3284
- const isSelected = selectedPackage === pkg;
3285
- return /* @__PURE__ */ jsxs(
3286
- "button",
3287
- {
3288
- onClick: () => handlePackageSelect(pkg),
3289
- style: {
3290
- display: "flex",
3291
- alignItems: "center",
3292
- gap: 8,
3293
- padding: "8px 12px",
3294
- borderRadius: 6,
3295
- border: `1px solid ${isSelected ? theme.colors.primary : theme.colors.border}`,
3296
- backgroundColor: isSelected ? theme.colors.surface : "transparent",
3297
- color: theme.colors.text,
3298
- cursor: "pointer",
3299
- transition: "all 0.15s ease"
3300
- },
3301
- children: [
3302
- /* @__PURE__ */ jsx("span", { style: { fontWeight: 500 }, children: pkg }),
3303
- /* @__PURE__ */ jsxs(
3304
- "span",
3305
- {
3306
- style: {
3307
- fontSize: 11,
3308
- padding: "2px 6px",
3309
- borderRadius: 4,
3310
- backgroundColor: summary.totalErrors > 0 ? getSeverityBg("error") : summary.totalWarnings > 0 ? getSeverityBg("warning") : "rgba(34, 197, 94, 0.1)",
3311
- color: summary.totalErrors > 0 ? getSeverityColor("error") : summary.totalWarnings > 0 ? getSeverityColor("warning") : "#22c55e"
3312
- },
3313
- children: [
3314
- summary.passCount,
3315
- "/",
3316
- summary.lensCount,
3317
- " pass"
3318
- ]
3319
- }
3320
- )
3321
- ]
3322
- },
3323
- pkg
3324
- );
3325
- })
3326
- }
3327
- ),
3328
- packageNames.length === 1 && /* @__PURE__ */ jsxs(
3484
+ selectedPackage && !onPackageSelect && /* @__PURE__ */ jsxs(
3329
3485
  "div",
3330
3486
  {
3331
3487
  style: {
@@ -3338,7 +3494,26 @@ function LensDataDebugPanel$1({
3338
3494
  marginBottom: 8
3339
3495
  },
3340
3496
  children: [
3341
- /* @__PURE__ */ jsx("span", { style: { fontWeight: 600, color: theme.colors.text }, children: packageNames[0] }),
3497
+ packageNames.length > 1 ? /* @__PURE__ */ jsx(
3498
+ "select",
3499
+ {
3500
+ value: selectedPackage,
3501
+ onChange: (e) => handlePackageSelect(e.target.value),
3502
+ style: {
3503
+ padding: "4px 8px",
3504
+ borderRadius: 4,
3505
+ border: `1px solid ${theme.colors.border}`,
3506
+ backgroundColor: theme.colors.background,
3507
+ color: theme.colors.text,
3508
+ fontFamily: "monospace",
3509
+ fontSize: 13,
3510
+ fontWeight: 600,
3511
+ cursor: "pointer",
3512
+ outline: "none"
3513
+ },
3514
+ children: packageNames.map((pkg) => /* @__PURE__ */ jsx("option", { value: pkg, children: pkg }, pkg))
3515
+ }
3516
+ ) : /* @__PURE__ */ jsx("span", { style: { fontWeight: 600, color: theme.colors.text }, children: selectedPackage }),
3342
3517
  (() => {
3343
3518
  const summary = getPackageSummary(selectedResults);
3344
3519
  return /* @__PURE__ */ jsxs(
@@ -3363,21 +3538,8 @@ function LensDataDebugPanel$1({
3363
3538
  ]
3364
3539
  }
3365
3540
  ),
3366
- !selectedPackage && packageNames.length > 1 && /* @__PURE__ */ jsx(
3367
- "div",
3368
- {
3369
- style: {
3370
- padding: 24,
3371
- textAlign: "center",
3372
- color: theme.colors.textMuted,
3373
- backgroundColor: theme.colors.surface,
3374
- borderRadius: 6
3375
- },
3376
- children: "Select a package above to view lens results"
3377
- }
3378
- ),
3379
3541
  selectedPackage && selectedResults.map((result, idx) => {
3380
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s;
3542
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x;
3381
3543
  const lensKey = `${((_a = result.lens) == null ? void 0 : _a.id) ?? "unknown"}-${idx}`;
3382
3544
  const isExpanded = expandedLens === lensKey;
3383
3545
  const filesWithIssues = getFilesWithIssues(result.issues ?? []);
@@ -3600,6 +3762,149 @@ function LensDataDebugPanel$1({
3600
3762
  ]
3601
3763
  }
3602
3764
  ),
3765
+ result.coverage && /* @__PURE__ */ jsxs("div", { style: { marginTop: 16 }, children: [
3766
+ /* @__PURE__ */ jsx(
3767
+ "div",
3768
+ {
3769
+ style: {
3770
+ fontSize: 12,
3771
+ fontWeight: 600,
3772
+ color: theme.colors.textMuted,
3773
+ marginBottom: 8
3774
+ },
3775
+ children: "Coverage Data"
3776
+ }
3777
+ ),
3778
+ /* @__PURE__ */ jsxs(
3779
+ "div",
3780
+ {
3781
+ style: {
3782
+ padding: 12,
3783
+ backgroundColor: theme.colors.surface,
3784
+ borderRadius: 4
3785
+ },
3786
+ children: [
3787
+ /* @__PURE__ */ jsxs(
3788
+ "div",
3789
+ {
3790
+ style: {
3791
+ display: "grid",
3792
+ gridTemplateColumns: "repeat(auto-fit, minmax(100px, 1fr))",
3793
+ gap: 12,
3794
+ marginBottom: 12
3795
+ },
3796
+ children: [
3797
+ /* @__PURE__ */ jsxs("div", { children: [
3798
+ /* @__PURE__ */ jsx(
3799
+ "div",
3800
+ {
3801
+ style: {
3802
+ fontSize: 11,
3803
+ color: theme.colors.textMuted
3804
+ },
3805
+ children: "Line"
3806
+ }
3807
+ ),
3808
+ /* @__PURE__ */ jsxs("div", { style: { fontSize: 14, fontWeight: 600 }, children: [
3809
+ result.coverage.line,
3810
+ "%"
3811
+ ] })
3812
+ ] }),
3813
+ result.coverage.branch !== void 0 && /* @__PURE__ */ jsxs("div", { children: [
3814
+ /* @__PURE__ */ jsx(
3815
+ "div",
3816
+ {
3817
+ style: {
3818
+ fontSize: 11,
3819
+ color: theme.colors.textMuted
3820
+ },
3821
+ children: "Branch"
3822
+ }
3823
+ ),
3824
+ /* @__PURE__ */ jsxs("div", { style: { fontSize: 14, fontWeight: 600 }, children: [
3825
+ result.coverage.branch,
3826
+ "%"
3827
+ ] })
3828
+ ] }),
3829
+ result.coverage.function !== void 0 && /* @__PURE__ */ jsxs("div", { children: [
3830
+ /* @__PURE__ */ jsx(
3831
+ "div",
3832
+ {
3833
+ style: {
3834
+ fontSize: 11,
3835
+ color: theme.colors.textMuted
3836
+ },
3837
+ children: "Function"
3838
+ }
3839
+ ),
3840
+ /* @__PURE__ */ jsxs("div", { style: { fontSize: 14, fontWeight: 600 }, children: [
3841
+ result.coverage.function,
3842
+ "%"
3843
+ ] })
3844
+ ] }),
3845
+ result.coverage.statement !== void 0 && /* @__PURE__ */ jsxs("div", { children: [
3846
+ /* @__PURE__ */ jsx(
3847
+ "div",
3848
+ {
3849
+ style: {
3850
+ fontSize: 11,
3851
+ color: theme.colors.textMuted
3852
+ },
3853
+ children: "Statement"
3854
+ }
3855
+ ),
3856
+ /* @__PURE__ */ jsxs("div", { style: { fontSize: 14, fontWeight: 600 }, children: [
3857
+ result.coverage.statement,
3858
+ "%"
3859
+ ] })
3860
+ ] })
3861
+ ]
3862
+ }
3863
+ ),
3864
+ /* @__PURE__ */ jsxs(
3865
+ "div",
3866
+ {
3867
+ style: {
3868
+ padding: 8,
3869
+ borderRadius: 4,
3870
+ backgroundColor: ((_t = result.coverage.files) == null ? void 0 : _t.length) ? "rgba(34, 197, 94, 0.1)" : "rgba(239, 68, 68, 0.1)",
3871
+ border: `1px solid ${((_u = result.coverage.files) == null ? void 0 : _u.length) ? "#22c55e" : "#ef4444"}`
3872
+ },
3873
+ children: [
3874
+ /* @__PURE__ */ jsxs(
3875
+ "div",
3876
+ {
3877
+ style: {
3878
+ fontSize: 12,
3879
+ fontWeight: 500,
3880
+ color: ((_v = result.coverage.files) == null ? void 0 : _v.length) ? "#22c55e" : "#ef4444"
3881
+ },
3882
+ children: [
3883
+ "coverage.files: ",
3884
+ ((_w = result.coverage.files) == null ? void 0 : _w.length) ?? 0,
3885
+ " ",
3886
+ "entries"
3887
+ ]
3888
+ }
3889
+ ),
3890
+ !((_x = result.coverage.files) == null ? void 0 : _x.length) && /* @__PURE__ */ jsx(
3891
+ "div",
3892
+ {
3893
+ style: {
3894
+ fontSize: 11,
3895
+ color: "#ef4444",
3896
+ marginTop: 4
3897
+ },
3898
+ children: "Warning: Coverage won't appear on map visualization!"
3899
+ }
3900
+ )
3901
+ ]
3902
+ }
3903
+ )
3904
+ ]
3905
+ }
3906
+ )
3907
+ ] }),
3603
3908
  filesWithIssues.size > 0 ? /* @__PURE__ */ jsxs("div", { children: [
3604
3909
  /* @__PURE__ */ jsxs(
3605
3910
  "div",
@@ -3888,6 +4193,98 @@ function LensDataDebugPanel$1({
3888
4193
  ))
3889
4194
  }
3890
4195
  )
4196
+ ] }),
4197
+ result.analyzedFiles && result.analyzedFiles.length > 0 && /* @__PURE__ */ jsxs("div", { style: { marginTop: 16 }, children: [
4198
+ /* @__PURE__ */ jsxs(
4199
+ "div",
4200
+ {
4201
+ onClick: () => toggleAnalyzedFiles(lensKey),
4202
+ style: {
4203
+ fontSize: 12,
4204
+ fontWeight: 600,
4205
+ color: theme.colors.textMuted,
4206
+ marginBottom: 8,
4207
+ cursor: "pointer",
4208
+ display: "flex",
4209
+ alignItems: "center",
4210
+ gap: 6
4211
+ },
4212
+ children: [
4213
+ /* @__PURE__ */ jsx(
4214
+ "svg",
4215
+ {
4216
+ width: "12",
4217
+ height: "12",
4218
+ viewBox: "0 0 24 24",
4219
+ fill: "none",
4220
+ stroke: "currentColor",
4221
+ strokeWidth: "2",
4222
+ style: {
4223
+ transform: expandedAnalyzedFiles.has(lensKey) ? "rotate(90deg)" : "rotate(0deg)",
4224
+ transition: "transform 0.15s ease"
4225
+ },
4226
+ children: /* @__PURE__ */ jsx("polyline", { points: "9,18 15,12 9,6" })
4227
+ }
4228
+ ),
4229
+ "Analyzed Files (",
4230
+ result.analyzedFiles.length,
4231
+ ")"
4232
+ ]
4233
+ }
4234
+ ),
4235
+ expandedAnalyzedFiles.has(lensKey) && /* @__PURE__ */ jsx(
4236
+ "div",
4237
+ {
4238
+ style: {
4239
+ maxHeight: 300,
4240
+ overflow: "auto",
4241
+ padding: 8,
4242
+ backgroundColor: theme.colors.surface,
4243
+ borderRadius: 4
4244
+ },
4245
+ children: result.analyzedFiles.map((file, idx2) => /* @__PURE__ */ jsxs(
4246
+ "div",
4247
+ {
4248
+ style: {
4249
+ display: "flex",
4250
+ alignItems: "center",
4251
+ justifyContent: "space-between",
4252
+ padding: "4px 8px",
4253
+ fontSize: 12,
4254
+ borderRadius: 2,
4255
+ backgroundColor: file.hasIssues ? "rgba(239, 68, 68, 0.05)" : "transparent"
4256
+ },
4257
+ children: [
4258
+ /* @__PURE__ */ jsx(
4259
+ "span",
4260
+ {
4261
+ style: {
4262
+ color: theme.colors.text,
4263
+ cursor: onFileClick ? "pointer" : "default"
4264
+ },
4265
+ onClick: () => onFileClick == null ? void 0 : onFileClick(file.path),
4266
+ children: file.path
4267
+ }
4268
+ ),
4269
+ file.hasIssues && /* @__PURE__ */ jsx(
4270
+ "span",
4271
+ {
4272
+ style: {
4273
+ fontSize: 10,
4274
+ color: "#ef4444",
4275
+ padding: "1px 4px",
4276
+ borderRadius: 2,
4277
+ backgroundColor: "rgba(239, 68, 68, 0.1)"
4278
+ },
4279
+ children: "issues"
4280
+ }
4281
+ )
4282
+ ]
4283
+ },
4284
+ idx2
4285
+ ))
4286
+ }
4287
+ )
3891
4288
  ] })
3892
4289
  ]
3893
4290
  }
@@ -3903,15 +4300,54 @@ function LensDataDebugPanel$1({
3903
4300
  }
3904
4301
  const LensDataDebugPanelContent = ({
3905
4302
  context,
3906
- actions
4303
+ actions,
4304
+ events
3907
4305
  }) => {
4306
+ var _a;
3908
4307
  const { theme } = useTheme();
4308
+ const [selectedPackage, setSelectedPackage] = React2__default.useState(
4309
+ null
4310
+ );
3909
4311
  const lensResultsSlice = context.getSlice("lensResults");
3910
4312
  const hasSlice = context.hasSlice("lensResults");
3911
4313
  const isLoading = (lensResultsSlice == null ? void 0 : lensResultsSlice.loading) ?? false;
4314
+ const { packageNames, packagePathMap } = React2__default.useMemo(() => {
4315
+ var _a2;
4316
+ if (!((_a2 = lensResultsSlice == null ? void 0 : lensResultsSlice.data) == null ? void 0 : _a2.results))
4317
+ return { packageNames: [], packagePathMap: /* @__PURE__ */ new Map() };
4318
+ const names = /* @__PURE__ */ new Set();
4319
+ const pathMap = /* @__PURE__ */ new Map();
4320
+ lensResultsSlice.data.results.forEach((r2) => {
4321
+ var _a3, _b;
4322
+ const name = ((_a3 = r2.package) == null ? void 0 : _a3.name) ?? "unknown";
4323
+ const path = ((_b = r2.package) == null ? void 0 : _b.path) ?? "";
4324
+ names.add(name);
4325
+ if (path) pathMap.set(path, name);
4326
+ pathMap.set(name, name);
4327
+ });
4328
+ return { packageNames: Array.from(names), packagePathMap: pathMap };
4329
+ }, [(_a = lensResultsSlice == null ? void 0 : lensResultsSlice.data) == null ? void 0 : _a.results]);
4330
+ React2__default.useEffect(() => {
4331
+ if (packageNames.length > 0 && !selectedPackage) {
4332
+ setSelectedPackage(packageNames[0]);
4333
+ }
4334
+ }, [packageNames, selectedPackage]);
4335
+ React2__default.useEffect(() => {
4336
+ if (!events) return;
4337
+ const cleanup = events.on("package:select", (event) => {
4338
+ const payload = event.payload;
4339
+ if (!payload) return;
4340
+ const matchedPackage = packagePathMap.get(payload.packagePath) ?? packagePathMap.get(payload.packageName) ?? // Also try matching the last segment of the path
4341
+ packagePathMap.get(payload.packagePath.split("/").pop() ?? "");
4342
+ if (matchedPackage) {
4343
+ setSelectedPackage(matchedPackage);
4344
+ }
4345
+ });
4346
+ return cleanup;
4347
+ }, [events, packagePathMap]);
3912
4348
  const handleFileClick = (file, line) => {
3913
- var _a, _b, _c;
3914
- const repoPath = (_a = context.currentScope.repository) == null ? void 0 : _a.path;
4349
+ var _a2, _b, _c;
4350
+ const repoPath = (_a2 = context.currentScope.repository) == null ? void 0 : _a2.path;
3915
4351
  const fullPath = repoPath ? `${repoPath}/${file}` : file;
3916
4352
  if (line) {
3917
4353
  (_b = actions.openFile) == null ? void 0 : _b.call(actions, `${fullPath}:${line}`);
@@ -3963,34 +4399,34 @@ const LensDataDebugPanelContent = ({
3963
4399
  }
3964
4400
  )
3965
4401
  ] }),
3966
- (lensResultsSlice == null ? void 0 : lensResultsSlice.data) && /* @__PURE__ */ jsxs(
4402
+ (lensResultsSlice == null ? void 0 : lensResultsSlice.data) && packageNames.length > 0 && /* @__PURE__ */ jsx(
3967
4403
  "div",
3968
4404
  {
3969
4405
  style: {
3970
4406
  display: "flex",
3971
4407
  alignItems: "center",
3972
4408
  gap: 12,
3973
- fontSize: 11,
3974
- color: theme.colors.textMuted
4409
+ fontSize: 12
3975
4410
  },
3976
- children: [
3977
- /* @__PURE__ */ jsxs("span", { children: [
3978
- new Set(
3979
- lensResultsSlice.data.results.map(
3980
- (r2) => {
3981
- var _a;
3982
- return ((_a = r2.package) == null ? void 0 : _a.name) ?? "unknown";
3983
- }
3984
- )
3985
- ).size,
3986
- " ",
3987
- "packages"
3988
- ] }),
3989
- /* @__PURE__ */ jsxs("span", { children: [
3990
- lensResultsSlice.data.results.length,
3991
- " results"
3992
- ] })
3993
- ]
4411
+ children: packageNames.length > 1 ? /* @__PURE__ */ jsx(
4412
+ "select",
4413
+ {
4414
+ value: selectedPackage ?? "",
4415
+ onChange: (e) => setSelectedPackage(e.target.value),
4416
+ style: {
4417
+ padding: "4px 8px",
4418
+ borderRadius: 4,
4419
+ border: `1px solid ${theme.colors.border}`,
4420
+ backgroundColor: theme.colors.surface,
4421
+ color: theme.colors.text,
4422
+ fontFamily: theme.fonts.body,
4423
+ fontSize: 12,
4424
+ cursor: "pointer",
4425
+ outline: "none"
4426
+ },
4427
+ children: packageNames.map((pkg) => /* @__PURE__ */ jsx("option", { value: pkg, children: pkg }, pkg))
4428
+ }
4429
+ ) : /* @__PURE__ */ jsx("span", { style: { color: theme.colors.textMuted }, children: packageNames[0] })
3994
4430
  }
3995
4431
  )
3996
4432
  ]
@@ -4040,7 +4476,9 @@ const LensDataDebugPanelContent = ({
4040
4476
  {
4041
4477
  data: lensResultsSlice.data,
4042
4478
  theme,
4043
- onFileClick: handleFileClick
4479
+ onFileClick: handleFileClick,
4480
+ selectedPackage: selectedPackage ?? void 0,
4481
+ onPackageSelect: setSelectedPackage
4044
4482
  }
4045
4483
  )
4046
4484
  }