react-doctor 0.9.2 → 0.9.3-dev.9bb44e7

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.
@@ -1,6 +1,6 @@
1
1
 
2
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="d3f7c231-0bd2-5808-8ce4-be477335e722")}catch(e){}}();
3
- import { A as toForwardSlashes, B as highlighter, C as buildRulePriorityMap, D as resolveBlockingLevel, E as formatLearnMoreLine, F as isCiEnvironment, G as sync, H as mergeReactDoctorConfigs, I as DIAGNOSTIC_CATEGORY_BUCKETS, K as void_, L as Progress, M as isUnicodeSupported, N as METRIC, O as isReactDoctorWorkflowInstalled, P as TUI_REPORT_DETAIL_WIDTH_FRACTION, R as Reporter, S as hasLintHardFailure, T as formatFixRecipeLine, U as resolveScanTarget, V as mapWithConcurrency, W as runPromise, _ as canAnimateOnboarding, a as resolveCliInspectOptions, b as buildCodeFrame, c as detectLaunchableAgents, d as launchCliAgent, f as isShareOptedOut, g as doctorFace, h as easeOutCubic, i as selectProjects, j as findNearestPackageDirectory, k as recordCount, l as CLI_AGENT_BINARIES, m as printFooter, n as shouldFailScanGate, o as countUniqueScannedFiles, p as inspect, q as succeed, r as discoverWorkspacePackages, s as setUpGitHubActions, t as exitGracefully, u as copyToClipboard, v as computeProjectedScore, w as buildSortedRuleGroups, x as buildNoScoreMessage, y as formatElapsedTime, z as getCategoryImpact } from "./cli.js";
2
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="898bdb3e-afed-5fca-92a2-f14d1e8ca6fb")}catch(e){}}();
3
+ import { A as toForwardSlashes, B as getCategoryImpact, C as buildRulePriorityMap, D as resolveBlockingLevel, E as formatLearnMoreLine, F as TUI_REPORT_DETAIL_WIDTH_FRACTION, G as runPromise, H as mapWithConcurrency, I as isCiEnvironment, J as succeed, K as sync, L as DIAGNOSTIC_CATEGORY_BUCKETS, M as isUnicodeSupported, N as METRIC, O as isReactDoctorWorkflowInstalled, P as TUI_REPORT_COMPACT_MAX_ROWS, R as Progress, S as hasLintHardFailure, T as formatFixRecipeLine, U as mergeReactDoctorConfigs, V as highlighter, W as resolveScanTarget, _ as canAnimateOnboarding, a as resolveCliInspectOptions, b as buildCodeFrame, c as detectLaunchableAgents, d as launchCliAgent, f as isShareOptedOut, g as doctorFace, h as easeOutCubic, i as selectProjects, j as findNearestPackageDirectory, k as recordCount, l as CLI_AGENT_BINARIES, m as printFooter, n as shouldFailScanGate, o as countUniqueScannedFiles, p as createInvocationInspect, q as void_, r as discoverWorkspacePackages, s as setUpGitHubActions, t as exitGracefully, u as copyToClipboard, v as computeProjectedScore, w as buildSortedRuleGroups, x as buildNoScoreMessage, y as formatElapsedTime, z as Reporter } from "./cli.js";
4
4
  import path from "node:path";
5
5
  import { performance } from "node:perf_hooks";
6
6
  import { getSkillAgentConfig } from "agent-install";
@@ -428,14 +428,11 @@ const buildIssuePrompt = ({ row, projectName }) => {
428
428
  };
429
429
  //#endregion
430
430
  //#region src/cli/ink/components/diagnostic-action-menu.tsx
431
- const MODAL_BACKGROUND = "black";
432
- const MODAL_SELECTED_BACKGROUND = "white";
433
431
  const DiagnosticActionMenu = ({ title, itemLabels, focusedIndex, maxWidth }) => {
434
432
  return /* @__PURE__ */ jsxs(Box, {
435
433
  width: Math.max(24, Math.min(44, maxWidth)),
436
434
  borderStyle: "round",
437
- borderColor: "gray",
438
- backgroundColor: MODAL_BACKGROUND,
435
+ borderColor: "cyan",
439
436
  paddingX: 2,
440
437
  paddingY: 1,
441
438
  flexDirection: "column",
@@ -455,14 +452,12 @@ const DiagnosticActionMenu = ({ title, itemLabels, focusedIndex, maxWidth }) =>
455
452
  flexDirection: "column",
456
453
  children: itemLabels.map((label, index) => {
457
454
  const isFocused = index === focusedIndex;
458
- return /* @__PURE__ */ jsx(Box, {
459
- backgroundColor: isFocused ? MODAL_SELECTED_BACKGROUND : void 0,
460
- children: /* @__PURE__ */ jsxs(Text, {
461
- wrap: "truncate-end",
462
- bold: isFocused,
463
- color: isFocused ? "black" : "gray",
464
- children: [isFocused ? "› " : " ", label]
465
- })
455
+ return /* @__PURE__ */ jsxs(Text, {
456
+ wrap: "truncate-end",
457
+ bold: isFocused,
458
+ color: isFocused ? "cyan" : void 0,
459
+ dimColor: !isFocused,
460
+ children: [isFocused ? "› " : " ", label]
466
461
  }, label);
467
462
  })
468
463
  }),
@@ -514,110 +509,97 @@ const DiagnosticDetail = ({ row, rootDirectory }) => {
514
509
  const impact = getCategoryImpact(row.category);
515
510
  return /* @__PURE__ */ jsxs(Box, {
516
511
  flexDirection: "column",
517
- children: [
518
- /* @__PURE__ */ jsxs(Text, {
519
- wrap: "truncate-end",
520
- children: [
521
- /* @__PURE__ */ jsxs(Text, {
522
- color: variant.color,
523
- children: [
524
- " ",
525
- variant.icon,
526
- " "
527
- ]
528
- }),
529
- /* @__PURE__ */ jsx(Text, {
530
- color: variant.color,
531
- bold: true,
532
- children: row.title
533
- }),
534
- row.siteCount > 1 ? /* @__PURE__ */ jsxs(Text, {
535
- dimColor: true,
536
- children: [" ×", row.siteCount]
537
- }) : null
538
- ]
539
- }),
540
- /* @__PURE__ */ jsxs(Box, {
541
- flexDirection: "column",
542
- paddingLeft: 4,
543
- children: [
544
- /* @__PURE__ */ jsxs(Text, {
545
- dimColor: true,
546
- wrap: "truncate-end",
547
- children: [
548
- row.category,
549
- " · ",
550
- variant.label
551
- ]
552
- }),
553
- impact ? /* @__PURE__ */ jsx(Text, {
554
- dimColor: true,
555
- wrap: "wrap",
556
- children: impact
557
- }) : null,
558
- /* @__PURE__ */ jsx(Text, {
512
+ children: [/* @__PURE__ */ jsxs(Text, {
513
+ wrap: "truncate-end",
514
+ children: [
515
+ /* @__PURE__ */ jsxs(Text, {
516
+ color: variant.color,
517
+ children: [variant.icon, " "]
518
+ }),
519
+ /* @__PURE__ */ jsx(Text, {
520
+ color: variant.color,
521
+ bold: true,
522
+ children: row.title
523
+ }),
524
+ row.siteCount > 1 ? /* @__PURE__ */ jsxs(Text, {
525
+ dimColor: true,
526
+ children: [" ×", row.siteCount]
527
+ }) : null
528
+ ]
529
+ }), /* @__PURE__ */ jsxs(Box, {
530
+ flexDirection: "column",
531
+ paddingLeft: 2,
532
+ children: [
533
+ /* @__PURE__ */ jsxs(Text, {
534
+ dimColor: true,
535
+ wrap: "truncate-end",
536
+ children: [
537
+ row.category,
538
+ " · ",
539
+ variant.label,
540
+ " · ",
541
+ row.location
542
+ ]
543
+ }),
544
+ impact ? /* @__PURE__ */ jsx(Text, {
545
+ dimColor: true,
546
+ wrap: "wrap",
547
+ children: impact
548
+ }) : null,
549
+ /* @__PURE__ */ jsx(Text, {
550
+ wrap: "wrap",
551
+ children: representative.message
552
+ }),
553
+ codeFrame ? /* @__PURE__ */ jsx(Box, {
554
+ marginTop: 1,
555
+ children: /* @__PURE__ */ jsx(Text, { children: codeFrame })
556
+ }) : null,
557
+ representative.help ? /* @__PURE__ */ jsx(Box, {
558
+ marginTop: 1,
559
+ children: /* @__PURE__ */ jsxs(Text, {
559
560
  wrap: "wrap",
560
- children: representative.message
561
- }),
562
- /* @__PURE__ */ jsx(Text, {
563
- dimColor: true,
561
+ children: [/* @__PURE__ */ jsx(Text, {
562
+ color: "cyan",
563
+ children: "Fix "
564
+ }), representative.help]
565
+ })
566
+ }) : null,
567
+ row.learnMore ? /* @__PURE__ */ jsx(Box, {
568
+ marginTop: 1,
569
+ children: /* @__PURE__ */ jsx(Text, {
570
+ color: "blue",
564
571
  wrap: "truncate-end",
565
- children: row.location
572
+ children: row.learnMore
566
573
  })
567
- ]
568
- }),
569
- codeFrame ? /* @__PURE__ */ jsx(Box, {
570
- marginTop: 1,
571
- marginLeft: 4,
572
- borderStyle: "round",
573
- borderColor: "gray",
574
- paddingX: 1,
575
- alignSelf: "flex-start",
576
- children: /* @__PURE__ */ jsx(Text, { children: codeFrame })
577
- }) : null,
578
- representative.help ? /* @__PURE__ */ jsx(Box, {
579
- marginTop: 1,
580
- paddingLeft: 4,
581
- children: /* @__PURE__ */ jsxs(Text, {
582
- dimColor: true,
583
- wrap: "wrap",
584
- children: ["→ ", representative.help]
585
- })
586
- }) : null,
587
- row.learnMore ? /* @__PURE__ */ jsx(Box, {
588
- marginTop: 1,
589
- paddingLeft: 4,
590
- children: /* @__PURE__ */ jsx(Text, {
591
- color: "cyan",
592
- wrap: "truncate-end",
593
- children: row.learnMore
594
- })
595
- }) : null
596
- ]
574
+ }) : null
575
+ ]
576
+ })]
597
577
  });
598
578
  };
599
579
  //#endregion
600
580
  //#region src/cli/ink/components/diagnostic-item.tsx
601
581
  const DiagnosticItem = ({ row, isSelected, isRead }) => {
602
582
  const variant = severityVariant(row.severity);
583
+ const shouldHighlightSeverity = isSelected || !isRead;
584
+ let marker = "• ";
585
+ if (isRead) marker = " ";
586
+ if (isSelected) marker = "› ";
587
+ let markerColor = shouldHighlightSeverity ? variant.color : void 0;
588
+ if (isSelected) markerColor = "cyan";
603
589
  return /* @__PURE__ */ jsxs(Text, {
604
590
  wrap: "truncate-end",
605
- dimColor: isRead,
591
+ dimColor: isRead && !isSelected,
606
592
  children: [
607
593
  /* @__PURE__ */ jsx(Text, {
608
- color: isSelected ? variant.color : void 0,
609
- children: isSelected ? "›" : " "
610
- }),
611
- /* @__PURE__ */ jsx(Text, {
612
- color: isRead ? void 0 : variant.color,
613
- children: isRead ? " " : " •"
594
+ color: markerColor,
595
+ children: marker
614
596
  }),
615
597
  /* @__PURE__ */ jsx(Text, {
616
- color: isRead ? void 0 : variant.color,
617
- children: ` ${variant.icon} `
598
+ color: shouldHighlightSeverity ? variant.color : void 0,
599
+ children: `${variant.icon} `
618
600
  }),
619
601
  /* @__PURE__ */ jsx(Text, {
620
- color: isRead ? void 0 : variant.color,
602
+ color: shouldHighlightSeverity ? variant.color : void 0,
621
603
  bold: isSelected,
622
604
  children: row.title
623
605
  }),
@@ -633,9 +615,8 @@ const DiagnosticItem = ({ row, isSelected, isRead }) => {
633
615
  const StatusBar = ({ total, errorCount, warningCount, position, groupCount, unreadCount, projectCount, keyHints = /* @__PURE__ */ jsx(Text, {
634
616
  dimColor: true,
635
617
  children: "↑/↓ to move"
636
- }), exitHint = "q to quit" }) => /* @__PURE__ */ jsxs(Text, {
637
- wrap: "truncate-end",
638
- children: [
618
+ }), exitHint = "q to quit", compact = false }) => {
619
+ const counts = /* @__PURE__ */ jsxs(Fragment, { children: [
639
620
  /* @__PURE__ */ jsxs(Text, {
640
621
  bold: true,
641
622
  children: [
@@ -646,7 +627,7 @@ const StatusBar = ({ total, errorCount, warningCount, position, groupCount, unre
646
627
  }),
647
628
  /* @__PURE__ */ jsx(Text, {
648
629
  dimColor: true,
649
- children: " › "
630
+ children: " "
650
631
  }),
651
632
  /* @__PURE__ */ jsxs(Text, {
652
633
  color: "red",
@@ -654,46 +635,80 @@ const StatusBar = ({ total, errorCount, warningCount, position, groupCount, unre
654
635
  }),
655
636
  /* @__PURE__ */ jsx(Text, {
656
637
  dimColor: true,
657
- children: ", "
638
+ children: " "
658
639
  }),
659
640
  /* @__PURE__ */ jsxs(Text, {
660
641
  color: "yellow",
661
- dimColor: true,
662
642
  children: [warningCount, " warnings"]
663
- }),
664
- unreadCount !== void 0 ? /* @__PURE__ */ jsxs(Text, {
665
- color: unreadCount > 0 ? "cyan" : void 0,
666
- dimColor: unreadCount === 0,
667
- children: [
668
- " · ",
669
- unreadCount,
670
- " unread"
671
- ]
672
- }) : null,
673
- projectCount !== void 0 ? /* @__PURE__ */ jsxs(Text, {
674
- dimColor: true,
643
+ })
644
+ ] });
645
+ if (compact) return /* @__PURE__ */ jsxs(Text, {
646
+ wrap: "truncate-end",
647
+ children: [
648
+ counts,
649
+ /* @__PURE__ */ jsxs(Text, {
650
+ dimColor: true,
651
+ children: [
652
+ " · ",
653
+ position,
654
+ "/",
655
+ groupCount,
656
+ " · "
657
+ ]
658
+ }),
659
+ keyHints,
660
+ /* @__PURE__ */ jsxs(Text, {
661
+ dimColor: true,
662
+ children: [" · ", exitHint]
663
+ })
664
+ ]
665
+ });
666
+ return /* @__PURE__ */ jsxs(Box, {
667
+ flexDirection: "column",
668
+ children: [/* @__PURE__ */ jsxs(Text, {
669
+ wrap: "truncate-end",
675
670
  children: [
676
- " · ",
677
- projectCount,
678
- " ",
679
- projectCount === 1 ? "project" : "projects"
671
+ counts,
672
+ /* @__PURE__ */ jsxs(Text, {
673
+ dimColor: true,
674
+ children: [
675
+ " · ",
676
+ position,
677
+ "/",
678
+ groupCount
679
+ ]
680
+ }),
681
+ projectCount !== void 0 ? /* @__PURE__ */ jsxs(Text, {
682
+ dimColor: true,
683
+ children: [
684
+ " · ",
685
+ projectCount,
686
+ " ",
687
+ projectCount === 1 ? "project" : "projects"
688
+ ]
689
+ }) : null
680
690
  ]
681
- }) : null,
682
- /* @__PURE__ */ jsxs(Text, {
683
- dimColor: true,
691
+ }), /* @__PURE__ */ jsxs(Text, {
692
+ wrap: "truncate-end",
684
693
  children: [
685
- " ",
686
- position,
687
- "/",
688
- groupCount,
689
- " · ",
694
+ unreadCount !== void 0 ? /* @__PURE__ */ jsxs(Text, {
695
+ color: unreadCount > 0 ? "cyan" : void 0,
696
+ dimColor: unreadCount === 0,
697
+ children: [
698
+ unreadCount,
699
+ " unread",
700
+ " · "
701
+ ]
702
+ }) : null,
690
703
  keyHints,
691
- " · ",
692
- exitHint
704
+ /* @__PURE__ */ jsxs(Text, {
705
+ dimColor: true,
706
+ children: [" · ", exitHint]
707
+ })
693
708
  ]
694
- })
695
- ]
696
- });
709
+ })]
710
+ });
711
+ };
697
712
  //#endregion
698
713
  //#region src/cli/ink/components/diagnostic-list.tsx
699
714
  const ADD_TO_CI_KEY = "a";
@@ -715,6 +730,7 @@ const DiagnosticList = ({ header, rows, width, listColumnWidth, detailColumnWidt
715
730
  const [isMenuOpen, setIsMenuOpen] = useState(false);
716
731
  const [menuIndex, setMenuIndex] = useState(0);
717
732
  const isSplit = layout === "split";
733
+ const isCompact = layout === "compact";
718
734
  const { rows: terminalRows } = useStdoutDimensions();
719
735
  const { selectedIndex, visibleStart, visibleEnd } = useScrollViewport({
720
736
  itemCount: entries.length,
@@ -726,6 +742,8 @@ const DiagnosticList = ({ header, rows, width, listColumnWidth, detailColumnWidt
726
742
  const selectedEntry = entries[selectedIndex];
727
743
  const selected = selectedEntry?.kind === "item" ? selectedEntry.row : null;
728
744
  const selectedRuleKey = selected?.ruleKey ?? null;
745
+ const initialSelectedRuleKey = useRef(selectedRuleKey);
746
+ const didRecordFindingNavigation = useRef(false);
729
747
  const [readRuleKeys, setReadRuleKeys] = useState(() => /* @__PURE__ */ new Set());
730
748
  const [copiedRuleKey, setCopiedRuleKey] = useState(null);
731
749
  const menuLabels = useMemo(() => ["Copy prompt", ...launchableAgents.map((agentId) => getSkillAgentConfig(agentId).displayName)], [launchableAgents]);
@@ -733,6 +751,11 @@ const DiagnosticList = ({ header, rows, width, listColumnWidth, detailColumnWidt
733
751
  if (!selectedRuleKey) return;
734
752
  setReadRuleKeys((previous) => previous.has(selectedRuleKey) ? previous : new Set(previous).add(selectedRuleKey));
735
753
  }, [selectedRuleKey]);
754
+ useEffect(() => {
755
+ if (!selectedRuleKey || selectedRuleKey === initialSelectedRuleKey.current || didRecordFindingNavigation.current) return;
756
+ didRecordFindingNavigation.current = true;
757
+ recordCount(METRIC.tuiFindingNavigated);
758
+ }, [selectedRuleKey]);
736
759
  const copySelectedPrompt = () => {
737
760
  if (!selected) return;
738
761
  const prompt = buildIssuePrompt({
@@ -772,6 +795,7 @@ const DiagnosticList = ({ header, rows, width, listColumnWidth, detailColumnWidt
772
795
  return onExit();
773
796
  }
774
797
  if (key.return && selected) {
798
+ recordCount(METRIC.tuiActionMenuOpened);
775
799
  setMenuIndex(0);
776
800
  setIsMenuOpen(true);
777
801
  }
@@ -782,6 +806,18 @@ const DiagnosticList = ({ header, rows, width, listColumnWidth, detailColumnWidt
782
806
  if (key.downArrow || input === "j") return setMenuIndex((index) => Math.min(menuLabels.length - 1, index + 1));
783
807
  if (key.return) return runMenuItem();
784
808
  }, { isActive: isMenuOpen });
809
+ if (isMenuOpen && selected) return /* @__PURE__ */ jsx(Box, {
810
+ width,
811
+ height: Math.max(6, terminalRows - 2),
812
+ justifyContent: "center",
813
+ alignItems: "center",
814
+ children: /* @__PURE__ */ jsx(DiagnosticActionMenu, {
815
+ title: selected.title,
816
+ itemLabels: menuLabels,
817
+ focusedIndex: menuIndex,
818
+ maxWidth: width
819
+ })
820
+ });
785
821
  const errorRows = rows.filter((row) => row.severity === "error");
786
822
  const warningRows = rows.filter((row) => row.severity === "warning");
787
823
  const itemPosition = entries.slice(0, selectedIndex + 1).filter((entry) => entry.kind === "item").length;
@@ -802,20 +838,7 @@ const DiagnosticList = ({ header, rows, width, listColumnWidth, detailColumnWidt
802
838
  children: "✓ Copied fix prompt"
803
839
  })
804
840
  }) : null] });
805
- const keyHints = useMemo(() => isMenuOpen ? /* @__PURE__ */ jsxs(Fragment, { children: [
806
- /* @__PURE__ */ jsx(Text, {
807
- dimColor: true,
808
- children: "↑/↓ select · "
809
- }),
810
- /* @__PURE__ */ jsx(Text, {
811
- color: "cyan",
812
- children: "enter"
813
- }),
814
- /* @__PURE__ */ jsx(Text, {
815
- dimColor: true,
816
- children: " run · esc close"
817
- })
818
- ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
841
+ const keyHints = /* @__PURE__ */ jsxs(Fragment, { children: [
819
842
  /* @__PURE__ */ jsx(Text, {
820
843
  dimColor: true,
821
844
  children: "↑/↓ move · "
@@ -842,9 +865,9 @@ const DiagnosticList = ({ header, rows, width, listColumnWidth, detailColumnWidt
842
865
  children: " add CI"
843
866
  })
844
867
  ] }) : null
845
- ] }), [isMenuOpen, showCiCallout]);
868
+ ] });
846
869
  const statusBar = /* @__PURE__ */ jsx(Box, {
847
- marginTop: 1,
870
+ marginTop: isCompact ? 0 : 1,
848
871
  children: /* @__PURE__ */ jsx(StatusBar, {
849
872
  total: sumSites(rows),
850
873
  errorCount: sumSites(errorRows),
@@ -853,62 +876,54 @@ const DiagnosticList = ({ header, rows, width, listColumnWidth, detailColumnWidt
853
876
  groupCount: rows.length,
854
877
  unreadCount,
855
878
  projectCount,
856
- keyHints,
857
- exitHint
879
+ keyHints: isCompact && copiedRuleKey === selectedRuleKey ? /* @__PURE__ */ jsx(Text, {
880
+ color: "green",
881
+ children: "✓ Copied fix prompt"
882
+ }) : keyHints,
883
+ exitHint,
884
+ compact: isCompact
858
885
  })
859
886
  });
860
- const overlay = isMenuOpen && selected ? /* @__PURE__ */ jsx(Box, {
861
- position: "absolute",
862
- top: 0,
863
- left: 0,
864
- width,
865
- height: Math.max(6, terminalRows - 2),
866
- justifyContent: "center",
867
- alignItems: "center",
868
- children: /* @__PURE__ */ jsx(DiagnosticActionMenu, {
869
- title: selected.title,
870
- itemLabels: menuLabels,
871
- focusedIndex: menuIndex,
872
- maxWidth: width
873
- })
874
- }) : null;
875
887
  if (isSplit) return /* @__PURE__ */ jsxs(Box, {
876
888
  flexDirection: "column",
877
889
  width,
878
- position: "relative",
879
- children: [
880
- /* @__PURE__ */ jsxs(Box, {
881
- flexDirection: "row",
882
- children: [/* @__PURE__ */ jsxs(Box, {
883
- flexDirection: "column",
884
- width: listColumnWidth,
885
- marginRight: 1,
886
- children: [header, /* @__PURE__ */ jsx(Box, {
887
- marginTop: 1,
888
- children: listColumn
889
- })]
890
- }), /* @__PURE__ */ jsx(Box, {
891
- flexDirection: "column",
892
- width: detailColumnWidth,
893
- borderStyle: "single",
894
- borderColor: "gray",
895
- borderTop: false,
896
- borderRight: false,
897
- borderBottom: false,
898
- paddingLeft: 1,
899
- height: detailHeight,
900
- overflowY: "hidden",
901
- children: detailContent
890
+ children: [/* @__PURE__ */ jsxs(Box, {
891
+ flexDirection: "row",
892
+ children: [/* @__PURE__ */ jsxs(Box, {
893
+ flexDirection: "column",
894
+ width: listColumnWidth,
895
+ marginRight: 1,
896
+ children: [header, /* @__PURE__ */ jsx(Box, {
897
+ marginTop: 1,
898
+ children: listColumn
902
899
  })]
903
- }),
904
- statusBar,
905
- overlay
900
+ }), /* @__PURE__ */ jsx(Box, {
901
+ flexDirection: "column",
902
+ width: detailColumnWidth,
903
+ borderStyle: "single",
904
+ borderColor: "gray",
905
+ borderTop: false,
906
+ borderRight: false,
907
+ borderBottom: false,
908
+ paddingLeft: 1,
909
+ height: detailHeight,
910
+ overflowY: "hidden",
911
+ children: detailContent
912
+ })]
913
+ }), statusBar]
914
+ });
915
+ if (isCompact) return /* @__PURE__ */ jsxs(Box, {
916
+ flexDirection: "column",
917
+ width,
918
+ children: [
919
+ header,
920
+ listColumn,
921
+ statusBar
906
922
  ]
907
923
  });
908
924
  return /* @__PURE__ */ jsxs(Box, {
909
925
  flexDirection: "column",
910
926
  width,
911
- position: "relative",
912
927
  children: [
913
928
  header,
914
929
  /* @__PURE__ */ jsx(Box, {
@@ -925,8 +940,7 @@ const DiagnosticList = ({ header, rows, width, listColumnWidth, detailColumnWidt
925
940
  overflowY: "hidden",
926
941
  children: detailContent
927
942
  }),
928
- statusBar,
929
- overlay
943
+ statusBar
930
944
  ]
931
945
  });
932
946
  };
@@ -991,7 +1005,7 @@ const scoreColorName = (score) => {
991
1005
  //#endregion
992
1006
  //#region src/cli/ink/components/score-header.tsx
993
1007
  const BRANDING = "https://react.doctor";
994
- const ScoreHeader = ({ score, projectedScore, projectName, issueCount, noScoreMessage, width }) => {
1008
+ const ScoreHeader = ({ score, projectedScore, projectName, issueCount, noScoreMessage, width, compact = false }) => {
995
1009
  const { columns } = useStdoutDimensions();
996
1010
  const availableWidth = width ?? columns;
997
1011
  const { stdout } = useStdout();
@@ -1001,6 +1015,42 @@ const ScoreHeader = ({ score, projectedScore, projectName, issueCount, noScoreMe
1001
1015
  projectedScore,
1002
1016
  animate: animate && score !== null
1003
1017
  });
1018
+ if (compact) return score ? /* @__PURE__ */ jsxs(Text, {
1019
+ wrap: "truncate-end",
1020
+ children: [
1021
+ /* @__PURE__ */ jsx(Text, {
1022
+ color: scoreColorName(score.score),
1023
+ bold: true,
1024
+ children: displayScore
1025
+ }),
1026
+ /* @__PURE__ */ jsxs(Text, {
1027
+ dimColor: true,
1028
+ children: [
1029
+ " / ",
1030
+ 100,
1031
+ " "
1032
+ ]
1033
+ }),
1034
+ /* @__PURE__ */ jsx(Text, {
1035
+ color: scoreColorName(score.score),
1036
+ children: score.label
1037
+ }),
1038
+ /* @__PURE__ */ jsxs(Text, {
1039
+ dimColor: true,
1040
+ children: [" · ", projectName]
1041
+ })
1042
+ ]
1043
+ }) : /* @__PURE__ */ jsxs(Text, {
1044
+ wrap: "truncate-end",
1045
+ children: [
1046
+ "React Doctor",
1047
+ " ",
1048
+ /* @__PURE__ */ jsxs(Text, {
1049
+ dimColor: true,
1050
+ children: ["· ", noScoreMessage ?? `${issueCount} issues · ${projectName}`]
1051
+ })
1052
+ ]
1053
+ });
1004
1054
  if (!score) return /* @__PURE__ */ jsxs(Box, {
1005
1055
  flexDirection: "column",
1006
1056
  paddingLeft: 2,
@@ -1136,8 +1186,8 @@ const ScoreHeader = ({ score, projectedScore, projectName, issueCount, noScoreMe
1136
1186
  };
1137
1187
  //#endregion
1138
1188
  //#region src/cli/ink/components/report.tsx
1139
- const STACKED_FIXED_ROWS = 10;
1140
- const SPLIT_CHROME_ROWS = 9;
1189
+ const STACKED_FIXED_ROWS = 11;
1190
+ const SPLIT_CHROME_ROWS = 10;
1141
1191
  const EMPTY_LAUNCHABLE_AGENTS = [];
1142
1192
  const Report = ({ report, onExit, launchableAgents = EMPTY_LAUNCHABLE_AGENTS, onHandoff, canAddToCi, onAddToCi, projectCount, priorityScores, exitHint = "q to quit" }) => {
1143
1193
  const { rows: terminalRows, columns } = useStdoutDimensions();
@@ -1151,17 +1201,38 @@ const Report = ({ report, onExit, launchableAgents = EMPTY_LAUNCHABLE_AGENTS, on
1151
1201
  }, { isActive: diagnosticRows.length === 0 });
1152
1202
  const width = Math.max(24, columns - 2);
1153
1203
  const isWide = columns >= 120 && terminalRows >= 22;
1154
- const detailHeight = isWide ? Math.max(0, terminalRows - 2) : Math.max(0, Math.min(15, terminalRows - STACKED_FIXED_ROWS - 3));
1155
- const listHeight = Math.max(3, terminalRows - (isWide ? SPLIT_CHROME_ROWS : STACKED_FIXED_ROWS + detailHeight));
1204
+ const isCompact = !isWide && terminalRows <= TUI_REPORT_COMPACT_MAX_ROWS;
1205
+ const didRecordCompactReport = useRef(false);
1206
+ const didRecordStackedReportCap = useRef(false);
1207
+ useEffect(() => {
1208
+ if (!isCompact || didRecordCompactReport.current) return;
1209
+ didRecordCompactReport.current = true;
1210
+ recordCount(METRIC.tuiCompactReportShown);
1211
+ }, [isCompact]);
1212
+ const detailHeight = isWide ? Math.max(0, terminalRows - 3) : Math.max(0, Math.min(15, terminalRows - STACKED_FIXED_ROWS - 3));
1213
+ const availableListHeight = Math.max(3, terminalRows - (isWide ? SPLIT_CHROME_ROWS : STACKED_FIXED_ROWS + detailHeight));
1214
+ const isStackedReportCapped = !isCompact && !isWide && availableListHeight > 16;
1215
+ useEffect(() => {
1216
+ if (!isStackedReportCapped || didRecordStackedReportCap.current) return;
1217
+ didRecordStackedReportCap.current = true;
1218
+ recordCount(METRIC.tuiStackedReportCapped);
1219
+ }, [isStackedReportCapped]);
1220
+ let listHeight = availableListHeight;
1221
+ if (isCompact) listHeight = Math.max(3, terminalRows - 1 - 1);
1222
+ else if (!isWide) listHeight = Math.min(16, availableListHeight);
1156
1223
  const detailColumnWidth = Math.max(20, Math.floor(width * TUI_REPORT_DETAIL_WIDTH_FRACTION));
1157
1224
  const listColumnWidth = Math.max(20, width - detailColumnWidth - 3);
1225
+ let layout = "stacked";
1226
+ if (isCompact) layout = "compact";
1227
+ else if (isWide) layout = "split";
1158
1228
  const scoreHeader = /* @__PURE__ */ jsx(ScoreHeader, {
1159
1229
  score: report.score,
1160
1230
  projectedScore: report.projectedScore,
1161
1231
  projectName: report.projectName,
1162
1232
  issueCount: report.diagnostics.length,
1163
1233
  noScoreMessage: report.noScoreMessage,
1164
- width: isWide ? listColumnWidth : width
1234
+ width: isWide ? listColumnWidth : width,
1235
+ compact: isCompact
1165
1236
  });
1166
1237
  if (diagnosticRows.length === 0) {
1167
1238
  const lintFailureReason = report.lintFailureReason;
@@ -1194,7 +1265,7 @@ const Report = ({ report, onExit, launchableAgents = EMPTY_LAUNCHABLE_AGENTS, on
1194
1265
  detailColumnWidth,
1195
1266
  listHeight,
1196
1267
  detailHeight,
1197
- layout: isWide ? "split" : "stacked",
1268
+ layout,
1198
1269
  rootDirectory: report.rootDirectory,
1199
1270
  projectName: report.projectName,
1200
1271
  launchableAgents,
@@ -1228,7 +1299,7 @@ const Scanning = ({ progressText, liveCount, recent }) => {
1228
1299
  ]
1229
1300
  }) : null
1230
1301
  ]
1231
- }), recent.map((diagnostic) => {
1302
+ }), recent.map((diagnostic, diagnosticIndex) => {
1232
1303
  const variant = severityVariant(diagnostic.severity === "error" ? "error" : "warning");
1233
1304
  const location = formatDiagnosticSite(diagnostic);
1234
1305
  return /* @__PURE__ */ jsxs(Text, {
@@ -1245,7 +1316,7 @@ const Scanning = ({ progressText, liveCount, recent }) => {
1245
1316
  children: [" ", location]
1246
1317
  })
1247
1318
  ]
1248
- }, `${diagnostic.filePath}:${diagnostic.line}:${diagnostic.column}:${diagnostic.plugin}:${diagnostic.rule}`);
1319
+ }, `${diagnostic.filePath}:${diagnostic.line}:${diagnostic.column}:${diagnostic.plugin}:${diagnostic.rule}:${diagnosticIndex}`);
1249
1320
  })]
1250
1321
  });
1251
1322
  };
@@ -1539,11 +1610,11 @@ const runMountedScan = async (rootDirectory, presentation, blockingLevel, execut
1539
1610
  throw error;
1540
1611
  }
1541
1612
  };
1542
- const runSingleProjectScan = async (rootScanTarget, projectDirectory, input, blockingLevel) => {
1613
+ const runSingleProjectScan = async (rootScanTarget, projectDirectory, input, blockingLevel, inspectProject) => {
1543
1614
  const projectScan = await resolveProjectScan(rootScanTarget, projectDirectory);
1544
1615
  const presentation = resolveScanPresentation(input, [projectScan]);
1545
1616
  return runMountedScan(projectScan.directory, presentation, blockingLevel, async (context) => {
1546
- const result = await inspect(projectScan.directory, {
1617
+ const result = await inspectProject(projectScan.directory, {
1547
1618
  ...resolveTuiInspectOptions(input, projectScan.config),
1548
1619
  isCi: isCiEnvironment(),
1549
1620
  configOverride: projectScan.config,
@@ -1574,7 +1645,7 @@ const runSingleProjectScan = async (rootScanTarget, projectDirectory, input, blo
1574
1645
  };
1575
1646
  });
1576
1647
  };
1577
- const runMultiProjectScan = async (rootScanTarget, directories, input, blockingLevel) => {
1648
+ const runMultiProjectScan = async (rootScanTarget, directories, input, blockingLevel, inspectProject) => {
1578
1649
  const rootDirectory = rootScanTarget.resolvedDirectory;
1579
1650
  const projectScans = await mapWithConcurrency([...directories], 4, (projectDirectory) => resolveProjectScan(rootScanTarget, projectDirectory));
1580
1651
  return runMountedScan(rootDirectory, resolveScanPresentation(input, projectScans), blockingLevel, async (context) => {
@@ -1582,7 +1653,7 @@ const runMultiProjectScan = async (rootScanTarget, directories, input, blockingL
1582
1653
  let finishedCount = 0;
1583
1654
  context.store.setProgress(`Scanning ${directories.length} projects…`);
1584
1655
  const results = await mapWithConcurrency(projectScans, 4, async (projectScan) => {
1585
- const result = await inspect(projectScan.directory, {
1656
+ const result = await inspectProject(projectScan.directory, {
1586
1657
  ...resolveTuiInspectOptions(input, projectScan.config),
1587
1658
  isCi: isCiEnvironment(),
1588
1659
  configOverride: projectScan.config,
@@ -1649,13 +1720,14 @@ const runScanApp = async (input) => {
1649
1720
  share: input.share ?? scanTarget.userConfig?.share ?? true
1650
1721
  };
1651
1722
  const selectedDirectories = await resolveSelectedDirectories(rootDirectory, resolvedInput);
1723
+ const inspectProject = createInvocationInspect(input.options?.concurrency);
1652
1724
  const blockingLevel = resolveBlockingLevel({ blocking: resolvedInput.blocking }, scanTarget.userConfig);
1653
1725
  if (selectedDirectories.length === 0) return { shouldFail: false };
1654
- if (selectedDirectories.length === 1) return runSingleProjectScan(scanTarget, selectedDirectories[0], resolvedInput, blockingLevel);
1655
- return runMultiProjectScan(scanTarget, selectedDirectories, resolvedInput, blockingLevel);
1726
+ if (selectedDirectories.length === 1) return runSingleProjectScan(scanTarget, selectedDirectories[0], resolvedInput, blockingLevel, inspectProject);
1727
+ return runMultiProjectScan(scanTarget, selectedDirectories, resolvedInput, blockingLevel, inspectProject);
1656
1728
  };
1657
1729
  //#endregion
1658
1730
  export { runScanApp };
1659
1731
 
1660
- //# sourceMappingURL=run-scan-app-DZ5jGWFf.js.map
1661
- //# debugId=d3f7c231-0bd2-5808-8ce4-be477335e722
1732
+ //# sourceMappingURL=run-scan-app-DHRvqfkX.js.map
1733
+ //# debugId=898bdb3e-afed-5fca-92a2-f14d1e8ca6fb