uilint 0.2.33 → 0.2.35

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.
@@ -14,8 +14,9 @@ import {
14
14
  note,
15
15
  pc,
16
16
  select,
17
+ text,
17
18
  uninstallEslintPlugin
18
- } from "./chunk-W6X3RNOE.js";
19
+ } from "./chunk-YS2QQOCB.js";
19
20
  import {
20
21
  GENSTYLEGUIDE_COMMAND_MD,
21
22
  loadSkill,
@@ -31,8 +32,8 @@ import {
31
32
  import { render } from "ink";
32
33
 
33
34
  // src/commands/install/components/InstallApp.tsx
34
- import { useState as useState6, useEffect as useEffect2 } from "react";
35
- import { Box as Box5, Text as Text6, useApp as useApp5, useInput as useInput5 } from "ink";
35
+ import { useState as useState7, useEffect as useEffect2 } from "react";
36
+ import { Box as Box6, Text as Text7, useApp as useApp5, useInput as useInput6 } from "ink";
36
37
 
37
38
  // src/commands/install/components/Spinner.tsx
38
39
  import { useState, useEffect } from "react";
@@ -316,21 +317,274 @@ function ConfigSelector({
316
317
  }
317
318
 
318
319
  // src/commands/install/components/RuleSelector.tsx
319
- import { useState as useState4, useMemo } from "react";
320
- import { Box as Box3, Text as Text4, useInput as useInput3, useApp as useApp3 } from "ink";
321
- import { getRulesByCategory } from "uilint-eslint";
320
+ import { useState as useState5, useMemo } from "react";
321
+ import { Box as Box4, Text as Text5, useInput as useInput4, useApp as useApp3 } from "ink";
322
+ import { getRulesByCategory, getCategoryMeta } from "uilint-eslint";
323
+
324
+ // src/commands/install/components/OptionField.tsx
325
+ import { useState as useState4 } from "react";
326
+ import { Box as Box3, Text as Text4, useInput as useInput3 } from "ink";
322
327
  import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
328
+ function BooleanField({
329
+ field,
330
+ value,
331
+ onChange,
332
+ isActive
333
+ }) {
334
+ const checked = Boolean(value);
335
+ useInput3(
336
+ (input) => {
337
+ if (isActive && input === " ") {
338
+ onChange(!checked);
339
+ }
340
+ },
341
+ { isActive }
342
+ );
343
+ return /* @__PURE__ */ jsxs3(Box3, { children: [
344
+ /* @__PURE__ */ jsx4(Text4, { color: isActive ? "cyan" : void 0, children: isActive ? "\u203A " : " " }),
345
+ /* @__PURE__ */ jsx4(Text4, { color: checked ? "green" : "gray", children: checked ? "[\u2713]" : "[ ]" }),
346
+ /* @__PURE__ */ jsxs3(Text4, { children: [
347
+ " ",
348
+ field.label
349
+ ] }),
350
+ field.description && /* @__PURE__ */ jsxs3(Text4, { dimColor: true, children: [
351
+ " - ",
352
+ field.description
353
+ ] })
354
+ ] });
355
+ }
356
+ function NumberField({
357
+ field,
358
+ value,
359
+ onChange,
360
+ isActive
361
+ }) {
362
+ const [inputValue, setInputValue] = useState4(String(value ?? field.defaultValue ?? ""));
363
+ const [error, setError] = useState4(null);
364
+ useInput3(
365
+ (input, key) => {
366
+ if (!isActive) return;
367
+ if (key.backspace || key.delete) {
368
+ const newValue = inputValue.slice(0, -1);
369
+ setInputValue(newValue);
370
+ const num = Number(newValue);
371
+ if (!isNaN(num) && newValue !== "") {
372
+ onChange(num);
373
+ setError(null);
374
+ } else if (newValue === "") {
375
+ setError(null);
376
+ } else {
377
+ setError("Enter a valid number");
378
+ }
379
+ } else if (/^[0-9.-]$/.test(input)) {
380
+ const newValue = inputValue + input;
381
+ setInputValue(newValue);
382
+ const num = Number(newValue);
383
+ if (!isNaN(num)) {
384
+ onChange(num);
385
+ setError(null);
386
+ } else {
387
+ setError("Enter a valid number");
388
+ }
389
+ }
390
+ },
391
+ { isActive }
392
+ );
393
+ return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", children: [
394
+ /* @__PURE__ */ jsxs3(Box3, { children: [
395
+ /* @__PURE__ */ jsx4(Text4, { color: isActive ? "cyan" : void 0, children: isActive ? "\u203A " : " " }),
396
+ /* @__PURE__ */ jsxs3(Text4, { children: [
397
+ field.label,
398
+ ": "
399
+ ] }),
400
+ /* @__PURE__ */ jsx4(Text4, { color: isActive ? "cyan" : void 0, underline: isActive, children: inputValue || field.placeholder || "" }),
401
+ field.description && /* @__PURE__ */ jsxs3(Text4, { dimColor: true, children: [
402
+ " (",
403
+ field.description,
404
+ ")"
405
+ ] })
406
+ ] }),
407
+ error && /* @__PURE__ */ jsx4(Box3, { paddingLeft: 4, children: /* @__PURE__ */ jsx4(Text4, { color: "red", children: error }) })
408
+ ] });
409
+ }
410
+ function TextField({
411
+ field,
412
+ value,
413
+ onChange,
414
+ isActive
415
+ }) {
416
+ const displayValue = Array.isArray(value) ? value.join(", ") : String(value ?? field.defaultValue ?? "");
417
+ const [inputValue, setInputValue] = useState4(displayValue);
418
+ useInput3(
419
+ (input, key) => {
420
+ if (!isActive) return;
421
+ if (key.backspace || key.delete) {
422
+ const newValue = inputValue.slice(0, -1);
423
+ setInputValue(newValue);
424
+ onChange(newValue);
425
+ } else if (input && !key.ctrl && !key.meta) {
426
+ const newValue = inputValue + input;
427
+ setInputValue(newValue);
428
+ onChange(newValue);
429
+ }
430
+ },
431
+ { isActive }
432
+ );
433
+ return /* @__PURE__ */ jsxs3(Box3, { children: [
434
+ /* @__PURE__ */ jsx4(Text4, { color: isActive ? "cyan" : void 0, children: isActive ? "\u203A " : " " }),
435
+ /* @__PURE__ */ jsxs3(Text4, { children: [
436
+ field.label,
437
+ ": "
438
+ ] }),
439
+ /* @__PURE__ */ jsx4(Text4, { color: isActive ? "cyan" : void 0, underline: isActive, children: inputValue || field.placeholder || "(empty)" }),
440
+ field.description && /* @__PURE__ */ jsxs3(Text4, { dimColor: true, children: [
441
+ " (",
442
+ field.description,
443
+ ")"
444
+ ] })
445
+ ] });
446
+ }
447
+ function SelectField({
448
+ field,
449
+ value,
450
+ onChange,
451
+ isActive
452
+ }) {
453
+ const options = field.options ?? [];
454
+ const currentIndex = options.findIndex(
455
+ (opt) => String(opt.value) === String(value)
456
+ );
457
+ const selectedIndex = currentIndex >= 0 ? currentIndex : 0;
458
+ useInput3(
459
+ (input, key) => {
460
+ if (!isActive || options.length === 0) return;
461
+ if (input === " " || key.rightArrow) {
462
+ const newIndex = selectedIndex < options.length - 1 ? selectedIndex + 1 : 0;
463
+ onChange(options[newIndex].value);
464
+ } else if (key.leftArrow) {
465
+ const newIndex = selectedIndex > 0 ? selectedIndex - 1 : options.length - 1;
466
+ onChange(options[newIndex].value);
467
+ }
468
+ },
469
+ { isActive }
470
+ );
471
+ const selectedOption = options[selectedIndex];
472
+ return /* @__PURE__ */ jsxs3(Box3, { children: [
473
+ /* @__PURE__ */ jsx4(Text4, { color: isActive ? "cyan" : void 0, children: isActive ? "\u203A " : " " }),
474
+ /* @__PURE__ */ jsxs3(Text4, { children: [
475
+ field.label,
476
+ ": "
477
+ ] }),
478
+ /* @__PURE__ */ jsxs3(Text4, { color: isActive ? "cyan" : void 0, bold: isActive, children: [
479
+ "\u25C0 ",
480
+ selectedOption?.label ?? "(none)",
481
+ " \u25B6"
482
+ ] }),
483
+ field.description && /* @__PURE__ */ jsxs3(Text4, { dimColor: true, children: [
484
+ " (",
485
+ field.description,
486
+ ")"
487
+ ] })
488
+ ] });
489
+ }
490
+ function MultiselectField({
491
+ field,
492
+ value,
493
+ onChange,
494
+ isActive
495
+ }) {
496
+ const options = field.options ?? [];
497
+ const selectedValues = new Set(
498
+ Array.isArray(value) ? value.map(String) : []
499
+ );
500
+ const [cursor, setCursor] = useState4(0);
501
+ useInput3(
502
+ (input, key) => {
503
+ if (!isActive || options.length === 0) return;
504
+ if (key.upArrow) {
505
+ setCursor((prev) => prev > 0 ? prev - 1 : options.length - 1);
506
+ } else if (key.downArrow) {
507
+ setCursor((prev) => prev < options.length - 1 ? prev + 1 : 0);
508
+ } else if (input === " ") {
509
+ const opt = options[cursor];
510
+ const newSelected = new Set(selectedValues);
511
+ if (newSelected.has(String(opt.value))) {
512
+ newSelected.delete(String(opt.value));
513
+ } else {
514
+ newSelected.add(String(opt.value));
515
+ }
516
+ onChange(Array.from(newSelected));
517
+ }
518
+ },
519
+ { isActive }
520
+ );
521
+ return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", children: [
522
+ /* @__PURE__ */ jsxs3(Box3, { children: [
523
+ /* @__PURE__ */ jsx4(Text4, { color: isActive ? "cyan" : void 0, children: isActive ? "\u203A " : " " }),
524
+ /* @__PURE__ */ jsx4(Text4, { children: field.label }),
525
+ field.description && /* @__PURE__ */ jsxs3(Text4, { dimColor: true, children: [
526
+ " - ",
527
+ field.description
528
+ ] })
529
+ ] }),
530
+ isActive && /* @__PURE__ */ jsx4(Box3, { flexDirection: "column", paddingLeft: 4, children: options.map((opt, i) => {
531
+ const isSelected = selectedValues.has(String(opt.value));
532
+ const isCursor = i === cursor;
533
+ return /* @__PURE__ */ jsxs3(Box3, { children: [
534
+ /* @__PURE__ */ jsx4(Text4, { color: isCursor ? "cyan" : void 0, children: isCursor ? "\u203A " : " " }),
535
+ /* @__PURE__ */ jsx4(Text4, { color: isSelected ? "green" : void 0, children: isSelected ? "[\u2713]" : "[ ]" }),
536
+ /* @__PURE__ */ jsxs3(Text4, { color: isCursor ? "cyan" : void 0, children: [
537
+ " ",
538
+ opt.label
539
+ ] })
540
+ ] }, String(opt.value));
541
+ }) }),
542
+ !isActive && /* @__PURE__ */ jsx4(Box3, { paddingLeft: 4, children: /* @__PURE__ */ jsxs3(Text4, { dimColor: true, children: [
543
+ "Selected: ",
544
+ Array.from(selectedValues).length > 0 ? Array.from(selectedValues).join(", ") : "(none)"
545
+ ] }) })
546
+ ] });
547
+ }
548
+ function OptionField(props) {
549
+ const { field } = props;
550
+ switch (field.type) {
551
+ case "boolean":
552
+ return /* @__PURE__ */ jsx4(BooleanField, { ...props });
553
+ case "number":
554
+ return /* @__PURE__ */ jsx4(NumberField, { ...props });
555
+ case "text":
556
+ return /* @__PURE__ */ jsx4(TextField, { ...props });
557
+ case "select":
558
+ return /* @__PURE__ */ jsx4(SelectField, { ...props });
559
+ case "multiselect":
560
+ return /* @__PURE__ */ jsx4(MultiselectField, { ...props });
561
+ default:
562
+ return /* @__PURE__ */ jsx4(Box3, { children: /* @__PURE__ */ jsxs3(Text4, { dimColor: true, children: [
563
+ "Unknown field type: ",
564
+ field.type
565
+ ] }) });
566
+ }
567
+ }
568
+ function convertFieldValue(value, field, defaultValue) {
569
+ if (Array.isArray(defaultValue) && field.type === "text" && typeof value === "string") {
570
+ return value.split(",").map((s) => s.trim()).filter(Boolean);
571
+ }
572
+ return value;
573
+ }
574
+
575
+ // src/commands/install/components/RuleSelector.tsx
576
+ import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
323
577
  function SeverityBadge({ severity }) {
324
578
  if (severity === "error") {
325
- return /* @__PURE__ */ jsx4(Text4, { color: "red", children: "error" });
579
+ return /* @__PURE__ */ jsx5(Text5, { color: "red", children: "error" });
326
580
  }
327
581
  if (severity === "warn") {
328
- return /* @__PURE__ */ jsx4(Text4, { color: "yellow", children: "warn" });
582
+ return /* @__PURE__ */ jsx5(Text5, { color: "yellow", children: "warn" });
329
583
  }
330
- return /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "off" });
584
+ return /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "off" });
331
585
  }
332
586
  function CategoryHeader({ name, icon }) {
333
- return /* @__PURE__ */ jsx4(Box3, { marginTop: 1, marginBottom: 0, children: /* @__PURE__ */ jsxs3(Text4, { bold: true, color: "white", children: [
587
+ return /* @__PURE__ */ jsx5(Box4, { marginTop: 1, marginBottom: 0, children: /* @__PURE__ */ jsxs4(Text5, { bold: true, color: "white", children: [
334
588
  icon,
335
589
  " ",
336
590
  name
@@ -345,28 +599,35 @@ function RuleSelector({
345
599
  const staticRules = useMemo(() => getRulesByCategory("static"), []);
346
600
  const semanticRules = useMemo(() => getRulesByCategory("semantic"), []);
347
601
  const allRules = useMemo(() => [...staticRules, ...semanticRules], [staticRules, semanticRules]);
348
- const [cursor, setCursor] = useState4(0);
349
- const [viewMode, setViewMode] = useState4("list");
350
- const [ruleStates, setRuleStates] = useState4(
602
+ const [cursor, setCursor] = useState5(0);
603
+ const [viewMode, setViewMode] = useState5("list");
604
+ const [ruleStates, setRuleStates] = useState5(
351
605
  () => {
352
606
  const map = /* @__PURE__ */ new Map();
353
- for (const rule of staticRules) {
354
- map.set(rule.id, {
355
- enabled: true,
356
- severity: rule.defaultSeverity === "off" ? "warn" : rule.defaultSeverity
357
- });
358
- }
359
- for (const rule of semanticRules) {
607
+ for (const rule of allRules) {
608
+ const categoryMeta = getCategoryMeta(rule.category);
609
+ const enabled = rule.defaultEnabled ?? categoryMeta?.defaultEnabled ?? false;
360
610
  map.set(rule.id, {
361
- enabled: false,
611
+ enabled,
362
612
  severity: rule.defaultSeverity === "off" ? "warn" : rule.defaultSeverity
363
613
  });
364
614
  }
365
615
  return map;
366
616
  }
367
617
  );
618
+ const [customOptions, setCustomOptions] = useState5(/* @__PURE__ */ new Map());
619
+ const [editingRuleIndex, setEditingRuleIndex] = useState5(0);
620
+ const [editingFieldCursor, setEditingFieldCursor] = useState5(0);
621
+ const [confirmCursor, setConfirmCursor] = useState5(1);
368
622
  const currentRule = allRules[cursor];
369
- const currentState = currentRule ? ruleStates.get(currentRule.id) : void 0;
623
+ const enabledRulesWithOptions = useMemo(() => {
624
+ return allRules.filter((rule) => {
625
+ const state = ruleStates.get(rule.id);
626
+ return state?.enabled && rule.optionSchema && rule.optionSchema.fields.length > 0;
627
+ });
628
+ }, [allRules, ruleStates]);
629
+ const currentEditingRule = enabledRulesWithOptions[editingRuleIndex];
630
+ const currentEditingFields = currentEditingRule?.optionSchema?.fields ?? [];
370
631
  const toggleRule = () => {
371
632
  if (!currentRule) return;
372
633
  setRuleStates((prev) => {
@@ -386,27 +647,122 @@ function RuleSelector({
386
647
  return next;
387
648
  });
388
649
  };
389
- const handleSubmit = () => {
650
+ const finalSubmit = () => {
390
651
  const configuredRules = [];
391
652
  for (const rule of allRules) {
392
653
  const state = ruleStates.get(rule.id);
393
654
  if (state?.enabled) {
655
+ const custom = customOptions.get(rule.id);
656
+ const baseOptions = rule.defaultOptions?.[0] ?? {};
394
657
  configuredRules.push({
395
658
  rule,
396
659
  severity: state.severity,
397
- options: rule.defaultOptions
660
+ options: custom ? [{ ...baseOptions, ...custom }] : rule.defaultOptions
398
661
  });
399
662
  }
400
663
  }
401
664
  onSubmit(configuredRules);
402
665
  };
403
- useInput3((input, key) => {
666
+ const handleListSubmit = () => {
667
+ if (enabledRulesWithOptions.length > 0) {
668
+ setViewMode("confirm-options");
669
+ setConfirmCursor(1);
670
+ } else {
671
+ finalSubmit();
672
+ }
673
+ };
674
+ const handleConfirmSelection = () => {
675
+ if (confirmCursor === 0) {
676
+ setEditingRuleIndex(0);
677
+ setEditingFieldCursor(0);
678
+ if (enabledRulesWithOptions[0]) {
679
+ initializeRuleOptions(enabledRulesWithOptions[0]);
680
+ }
681
+ setViewMode("edit-options");
682
+ } else {
683
+ finalSubmit();
684
+ }
685
+ };
686
+ const initializeRuleOptions = (rule) => {
687
+ if (!customOptions.has(rule.id) && rule.optionSchema) {
688
+ const baseOptions = rule.defaultOptions?.[0] ?? {};
689
+ const initial = {};
690
+ for (const field of rule.optionSchema.fields) {
691
+ initial[field.key] = baseOptions[field.key] ?? field.defaultValue;
692
+ }
693
+ setCustomOptions((prev) => {
694
+ const next = new Map(prev);
695
+ next.set(rule.id, initial);
696
+ return next;
697
+ });
698
+ }
699
+ };
700
+ const updateFieldValue = (fieldKey, value) => {
701
+ if (!currentEditingRule) return;
702
+ setCustomOptions((prev) => {
703
+ const next = new Map(prev);
704
+ const current = next.get(currentEditingRule.id) ?? {};
705
+ next.set(currentEditingRule.id, { ...current, [fieldKey]: value });
706
+ return next;
707
+ });
708
+ };
709
+ const nextEditingRule = () => {
710
+ if (editingRuleIndex < enabledRulesWithOptions.length - 1) {
711
+ const nextIndex = editingRuleIndex + 1;
712
+ setEditingRuleIndex(nextIndex);
713
+ setEditingFieldCursor(0);
714
+ if (enabledRulesWithOptions[nextIndex]) {
715
+ initializeRuleOptions(enabledRulesWithOptions[nextIndex]);
716
+ }
717
+ } else {
718
+ finalSubmit();
719
+ }
720
+ };
721
+ const skipCurrentRule = () => {
722
+ if (currentEditingRule) {
723
+ setCustomOptions((prev) => {
724
+ const next = new Map(prev);
725
+ next.delete(currentEditingRule.id);
726
+ return next;
727
+ });
728
+ }
729
+ nextEditingRule();
730
+ };
731
+ useInput4((input, key) => {
404
732
  if (viewMode === "docs") {
405
733
  if (key.escape || key.return || input === "d" || input === "q") {
406
734
  setViewMode("list");
407
735
  }
408
736
  return;
409
737
  }
738
+ if (viewMode === "confirm-options") {
739
+ if (key.upArrow || key.downArrow) {
740
+ setConfirmCursor((prev) => prev === 0 ? 1 : 0);
741
+ } else if (key.return || input === " ") {
742
+ handleConfirmSelection();
743
+ } else if (key.escape || input === "q") {
744
+ setViewMode("list");
745
+ }
746
+ return;
747
+ }
748
+ if (viewMode === "edit-options") {
749
+ if (key.upArrow) {
750
+ setEditingFieldCursor(
751
+ (prev) => prev > 0 ? prev - 1 : currentEditingFields.length - 1
752
+ );
753
+ } else if (key.downArrow) {
754
+ setEditingFieldCursor(
755
+ (prev) => prev < currentEditingFields.length - 1 ? prev + 1 : 0
756
+ );
757
+ } else if (key.return) {
758
+ nextEditingRule();
759
+ } else if (key.escape) {
760
+ skipCurrentRule();
761
+ } else if (input === "q") {
762
+ setViewMode("list");
763
+ }
764
+ return;
765
+ }
410
766
  if (key.upArrow) {
411
767
  setCursor((prev) => prev > 0 ? prev - 1 : allRules.length - 1);
412
768
  } else if (key.downArrow) {
@@ -418,7 +774,7 @@ function RuleSelector({
418
774
  } else if (input === "d") {
419
775
  setViewMode("docs");
420
776
  } else if (key.return) {
421
- handleSubmit();
777
+ handleListSubmit();
422
778
  } else if (key.escape || input === "q") {
423
779
  onCancel?.();
424
780
  exit();
@@ -446,40 +802,136 @@ function RuleSelector({
446
802
  });
447
803
  if (viewMode === "docs" && currentRule) {
448
804
  const docLines = currentRule.docs.trim().split("\n").slice(0, 20);
449
- return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", children: [
450
- /* @__PURE__ */ jsxs3(Box3, { marginBottom: 1, children: [
451
- /* @__PURE__ */ jsx4(Text4, { bold: true, color: "cyan", children: currentRule.name }),
452
- /* @__PURE__ */ jsxs3(Text4, { dimColor: true, children: [
805
+ return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
806
+ /* @__PURE__ */ jsxs4(Box4, { marginBottom: 1, children: [
807
+ /* @__PURE__ */ jsx5(Text5, { bold: true, color: "cyan", children: currentRule.name }),
808
+ /* @__PURE__ */ jsxs4(Text5, { dimColor: true, children: [
453
809
  " - ",
454
810
  currentRule.description
455
811
  ] })
456
812
  ] }),
457
- /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", borderStyle: "single", borderColor: "gray", paddingX: 1, children: [
458
- docLines.map((line, i) => /* @__PURE__ */ jsx4(Text4, { dimColor: line.startsWith("#"), children: line }, i)),
459
- currentRule.docs.split("\n").length > 20 && /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "... (truncated)" })
813
+ /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", borderStyle: "single", borderColor: "gray", paddingX: 1, children: [
814
+ docLines.map((line, i) => /* @__PURE__ */ jsx5(Text5, { dimColor: line.startsWith("#"), children: line }, i)),
815
+ currentRule.docs.split("\n").length > 20 && /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "... (truncated)" })
816
+ ] }),
817
+ /* @__PURE__ */ jsx5(Box4, { marginTop: 1, children: /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "Press any key to return to list" }) })
818
+ ] });
819
+ }
820
+ if (viewMode === "confirm-options") {
821
+ return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
822
+ /* @__PURE__ */ jsx5(Box4, { marginBottom: 1, children: /* @__PURE__ */ jsx5(Text5, { bold: true, children: "Configure Rule Options" }) }),
823
+ /* @__PURE__ */ jsx5(Box4, { marginBottom: 1, children: /* @__PURE__ */ jsxs4(Text5, { children: [
824
+ /* @__PURE__ */ jsx5(Text5, { color: "cyan", children: enabledRulesWithOptions.length }),
825
+ /* @__PURE__ */ jsx5(Text5, { children: " selected rules have configurable options. Would you like to customize them?" })
826
+ ] }) }),
827
+ /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", paddingLeft: 2, children: [
828
+ /* @__PURE__ */ jsxs4(Box4, { children: [
829
+ /* @__PURE__ */ jsx5(Text5, { color: confirmCursor === 0 ? "cyan" : void 0, children: confirmCursor === 0 ? "\u203A " : " " }),
830
+ /* @__PURE__ */ jsx5(Text5, { color: confirmCursor === 0 ? "cyan" : void 0, bold: confirmCursor === 0, children: "Yes" }),
831
+ /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: " - Configure each rule's options" })
832
+ ] }),
833
+ /* @__PURE__ */ jsxs4(Box4, { children: [
834
+ /* @__PURE__ */ jsx5(Text5, { color: confirmCursor === 1 ? "cyan" : void 0, children: confirmCursor === 1 ? "\u203A " : " " }),
835
+ /* @__PURE__ */ jsx5(Text5, { color: confirmCursor === 1 ? "cyan" : void 0, bold: confirmCursor === 1, children: "No" }),
836
+ /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: " - Use defaults for all rules" })
837
+ ] })
838
+ ] }),
839
+ /* @__PURE__ */ jsx5(Box4, { marginTop: 1, children: /* @__PURE__ */ jsxs4(Text5, { dimColor: true, children: [
840
+ "Rules with options:",
841
+ " ",
842
+ enabledRulesWithOptions.map((r) => r.name).join(", ")
843
+ ] }) }),
844
+ /* @__PURE__ */ jsx5(Box4, { marginTop: 1, borderStyle: "single", borderColor: "gray", paddingX: 1, children: /* @__PURE__ */ jsxs4(Text5, { dimColor: true, children: [
845
+ /* @__PURE__ */ jsx5(Text5, { color: "cyan", children: "\u2191\u2193" }),
846
+ " select",
847
+ " ",
848
+ /* @__PURE__ */ jsx5(Text5, { color: "cyan", children: "enter" }),
849
+ " confirm",
850
+ " ",
851
+ /* @__PURE__ */ jsx5(Text5, { color: "cyan", children: "esc" }),
852
+ " back"
853
+ ] }) })
854
+ ] });
855
+ }
856
+ if (viewMode === "edit-options" && currentEditingRule) {
857
+ const ruleOptions = customOptions.get(currentEditingRule.id) ?? {};
858
+ const baseOptions = currentEditingRule.defaultOptions?.[0] ?? {};
859
+ return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
860
+ /* @__PURE__ */ jsxs4(Box4, { marginBottom: 1, children: [
861
+ /* @__PURE__ */ jsxs4(Text5, { bold: true, color: "cyan", children: [
862
+ currentEditingRule.icon ?? "\u2699\uFE0F",
863
+ " ",
864
+ currentEditingRule.name
865
+ ] }),
866
+ /* @__PURE__ */ jsxs4(Text5, { dimColor: true, children: [
867
+ " (",
868
+ editingRuleIndex + 1,
869
+ "/",
870
+ enabledRulesWithOptions.length,
871
+ ")"
872
+ ] })
460
873
  ] }),
461
- /* @__PURE__ */ jsx4(Box3, { marginTop: 1, children: /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "Press any key to return to list" }) })
874
+ /* @__PURE__ */ jsx5(Box4, { marginBottom: 1, children: /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: currentEditingRule.description }) }),
875
+ /* @__PURE__ */ jsx5(Box4, { flexDirection: "column", children: currentEditingFields.map((field, i) => {
876
+ const currentValue = ruleOptions[field.key] ?? baseOptions[field.key] ?? field.defaultValue;
877
+ const defaultValue = baseOptions[field.key] ?? field.defaultValue;
878
+ return /* @__PURE__ */ jsx5(
879
+ OptionField,
880
+ {
881
+ field,
882
+ value: currentValue,
883
+ onChange: (newValue) => {
884
+ const converted = convertFieldValue(newValue, field, defaultValue);
885
+ updateFieldValue(field.key, converted);
886
+ },
887
+ isActive: i === editingFieldCursor
888
+ },
889
+ field.key
890
+ );
891
+ }) }),
892
+ /* @__PURE__ */ jsx5(Box4, { marginTop: 1, borderStyle: "single", borderColor: "gray", paddingX: 1, children: /* @__PURE__ */ jsxs4(Text5, { dimColor: true, children: [
893
+ /* @__PURE__ */ jsx5(Text5, { color: "cyan", children: "\u2191\u2193" }),
894
+ " navigate",
895
+ " ",
896
+ /* @__PURE__ */ jsx5(Text5, { color: "cyan", children: "space" }),
897
+ " toggle",
898
+ " ",
899
+ /* @__PURE__ */ jsx5(Text5, { color: "cyan", children: "enter" }),
900
+ " next rule",
901
+ " ",
902
+ /* @__PURE__ */ jsx5(Text5, { color: "cyan", children: "esc" }),
903
+ " skip (use defaults)"
904
+ ] }) })
462
905
  ] });
463
906
  }
464
907
  const enabledCount = Array.from(ruleStates.values()).filter((s) => s.enabled).length;
465
908
  const errorCount = Array.from(ruleStates.entries()).filter(
466
- ([id, s]) => s.enabled && s.severity === "error"
909
+ ([, s]) => s.enabled && s.severity === "error"
467
910
  ).length;
468
911
  const warnCount = enabledCount - errorCount;
469
912
  let globalIndex = 0;
470
- return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", children: [
471
- /* @__PURE__ */ jsx4(Box3, { marginBottom: 1, children: /* @__PURE__ */ jsx4(Text4, { bold: true, children: "Configure ESLint Rules" }) }),
472
- /* @__PURE__ */ jsx4(CategoryHeader, { name: "Static Rules", icon: "\u{1F4CB}" }),
473
- /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: " Pattern-based, fast analysis" }),
913
+ return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
914
+ /* @__PURE__ */ jsx5(Box4, { marginBottom: 1, children: /* @__PURE__ */ jsx5(Text5, { bold: true, children: "Configure ESLint Rules" }) }),
915
+ (() => {
916
+ const cat = getCategoryMeta("static");
917
+ return cat ? /* @__PURE__ */ jsxs4(Fragment2, { children: [
918
+ /* @__PURE__ */ jsx5(CategoryHeader, { name: cat.name, icon: cat.icon }),
919
+ /* @__PURE__ */ jsxs4(Text5, { dimColor: true, children: [
920
+ " ",
921
+ cat.description
922
+ ] })
923
+ ] }) : null;
924
+ })(),
474
925
  staticRules.map((rule) => {
475
926
  const itemIndex = globalIndex++;
476
927
  const isCursor = itemIndex === cursor;
477
928
  const state = ruleStates.get(rule.id);
478
- return /* @__PURE__ */ jsxs3(Box3, { paddingLeft: 2, children: [
479
- /* @__PURE__ */ jsx4(Text4, { color: isCursor ? "cyan" : void 0, children: isCursor ? "\u203A " : " " }),
480
- /* @__PURE__ */ jsx4(Box3, { width: 3, children: /* @__PURE__ */ jsx4(Text4, { color: state.enabled ? "green" : void 0, dimColor: !state.enabled, children: state.enabled ? "\u2713" : "\u25CB" }) }),
481
- /* @__PURE__ */ jsx4(Box3, { width: 30, children: /* @__PURE__ */ jsx4(
482
- Text4,
929
+ const hasOptions = rule.optionSchema && rule.optionSchema.fields.length > 0;
930
+ return /* @__PURE__ */ jsxs4(Box4, { paddingLeft: 2, children: [
931
+ /* @__PURE__ */ jsx5(Text5, { color: isCursor ? "cyan" : void 0, children: isCursor ? "\u203A " : " " }),
932
+ /* @__PURE__ */ jsx5(Box4, { width: 3, children: /* @__PURE__ */ jsx5(Text5, { color: state.enabled ? "green" : void 0, dimColor: !state.enabled, children: state.enabled ? "\u2713" : "\u25CB" }) }),
933
+ /* @__PURE__ */ jsx5(Box4, { width: 30, children: /* @__PURE__ */ jsx5(
934
+ Text5,
483
935
  {
484
936
  color: isCursor ? "cyan" : void 0,
485
937
  dimColor: !state.enabled,
@@ -487,20 +939,30 @@ function RuleSelector({
487
939
  children: rule.name
488
940
  }
489
941
  ) }),
490
- /* @__PURE__ */ jsx4(Box3, { width: 8, children: state.enabled ? /* @__PURE__ */ jsx4(SeverityBadge, { severity: state.severity }) : /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "-" }) })
942
+ /* @__PURE__ */ jsx5(Box4, { width: 8, children: state.enabled ? /* @__PURE__ */ jsx5(SeverityBadge, { severity: state.severity }) : /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "-" }) }),
943
+ hasOptions && state.enabled && /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: " \u2699" })
491
944
  ] }, rule.id);
492
945
  }),
493
- /* @__PURE__ */ jsx4(CategoryHeader, { name: "Semantic Rules", icon: "\u{1F9E0}" }),
494
- /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: " LLM-powered analysis (requires Ollama)" }),
946
+ (() => {
947
+ const cat = getCategoryMeta("semantic");
948
+ return cat ? /* @__PURE__ */ jsxs4(Fragment2, { children: [
949
+ /* @__PURE__ */ jsx5(CategoryHeader, { name: cat.name, icon: cat.icon }),
950
+ /* @__PURE__ */ jsxs4(Text5, { dimColor: true, children: [
951
+ " ",
952
+ cat.description
953
+ ] })
954
+ ] }) : null;
955
+ })(),
495
956
  semanticRules.map((rule) => {
496
957
  const itemIndex = globalIndex++;
497
958
  const isCursor = itemIndex === cursor;
498
959
  const state = ruleStates.get(rule.id);
499
- return /* @__PURE__ */ jsxs3(Box3, { paddingLeft: 2, children: [
500
- /* @__PURE__ */ jsx4(Text4, { color: isCursor ? "cyan" : void 0, children: isCursor ? "\u203A " : " " }),
501
- /* @__PURE__ */ jsx4(Box3, { width: 3, children: /* @__PURE__ */ jsx4(Text4, { color: state.enabled ? "green" : void 0, dimColor: !state.enabled, children: state.enabled ? "\u2713" : "\u25CB" }) }),
502
- /* @__PURE__ */ jsx4(Box3, { width: 30, children: /* @__PURE__ */ jsx4(
503
- Text4,
960
+ const hasOptions = rule.optionSchema && rule.optionSchema.fields.length > 0;
961
+ return /* @__PURE__ */ jsxs4(Box4, { paddingLeft: 2, children: [
962
+ /* @__PURE__ */ jsx5(Text5, { color: isCursor ? "cyan" : void 0, children: isCursor ? "\u203A " : " " }),
963
+ /* @__PURE__ */ jsx5(Box4, { width: 3, children: /* @__PURE__ */ jsx5(Text5, { color: state.enabled ? "green" : void 0, dimColor: !state.enabled, children: state.enabled ? "\u2713" : "\u25CB" }) }),
964
+ /* @__PURE__ */ jsx5(Box4, { width: 30, children: /* @__PURE__ */ jsx5(
965
+ Text5,
504
966
  {
505
967
  color: isCursor ? "cyan" : void 0,
506
968
  dimColor: !state.enabled,
@@ -508,47 +970,53 @@ function RuleSelector({
508
970
  children: rule.name
509
971
  }
510
972
  ) }),
511
- /* @__PURE__ */ jsx4(Box3, { width: 8, children: state.enabled ? /* @__PURE__ */ jsx4(SeverityBadge, { severity: state.severity }) : /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "-" }) })
973
+ /* @__PURE__ */ jsx5(Box4, { width: 8, children: state.enabled ? /* @__PURE__ */ jsx5(SeverityBadge, { severity: state.severity }) : /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "-" }) }),
974
+ hasOptions && state.enabled && /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: " \u2699" })
512
975
  ] }, rule.id);
513
976
  }),
514
- currentRule && /* @__PURE__ */ jsx4(Box3, { marginTop: 1, paddingX: 2, children: /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: currentRule.description }) }),
515
- /* @__PURE__ */ jsx4(Box3, { marginTop: 1, borderStyle: "single", borderColor: "gray", paddingX: 1, children: /* @__PURE__ */ jsxs3(Text4, { dimColor: true, children: [
516
- /* @__PURE__ */ jsx4(Text4, { color: "cyan", children: "\u2191\u2193" }),
977
+ currentRule && /* @__PURE__ */ jsx5(Box4, { marginTop: 1, paddingX: 2, children: /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: currentRule.description }) }),
978
+ /* @__PURE__ */ jsx5(Box4, { marginTop: 1, borderStyle: "single", borderColor: "gray", paddingX: 1, children: /* @__PURE__ */ jsxs4(Text5, { dimColor: true, children: [
979
+ /* @__PURE__ */ jsx5(Text5, { color: "cyan", children: "\u2191\u2193" }),
517
980
  " navigate",
518
981
  " ",
519
- /* @__PURE__ */ jsx4(Text4, { color: "cyan", children: "space" }),
982
+ /* @__PURE__ */ jsx5(Text5, { color: "cyan", children: "space" }),
520
983
  " toggle",
521
984
  " ",
522
- /* @__PURE__ */ jsx4(Text4, { color: "cyan", children: "s" }),
985
+ /* @__PURE__ */ jsx5(Text5, { color: "cyan", children: "s" }),
523
986
  " severity",
524
987
  " ",
525
- /* @__PURE__ */ jsx4(Text4, { color: "cyan", children: "d" }),
988
+ /* @__PURE__ */ jsx5(Text5, { color: "cyan", children: "d" }),
526
989
  " docs",
527
990
  " ",
528
- /* @__PURE__ */ jsx4(Text4, { color: "cyan", children: "a" }),
991
+ /* @__PURE__ */ jsx5(Text5, { color: "cyan", children: "a" }),
529
992
  " all",
530
993
  " ",
531
- /* @__PURE__ */ jsx4(Text4, { color: "cyan", children: "n" }),
994
+ /* @__PURE__ */ jsx5(Text5, { color: "cyan", children: "n" }),
532
995
  " none",
533
996
  " ",
534
- /* @__PURE__ */ jsx4(Text4, { color: "cyan", children: "enter" }),
997
+ /* @__PURE__ */ jsx5(Text5, { color: "cyan", children: "enter" }),
535
998
  " confirm"
536
999
  ] }) }),
537
- /* @__PURE__ */ jsx4(Box3, { marginTop: 1, children: /* @__PURE__ */ jsxs3(Text4, { children: [
538
- /* @__PURE__ */ jsx4(Text4, { color: "cyan", children: enabledCount }),
539
- /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: " rules enabled (" }),
540
- /* @__PURE__ */ jsx4(Text4, { color: "red", children: errorCount }),
541
- /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: " errors, " }),
542
- /* @__PURE__ */ jsx4(Text4, { color: "yellow", children: warnCount }),
543
- /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: " warnings)" })
1000
+ /* @__PURE__ */ jsx5(Box4, { marginTop: 1, children: /* @__PURE__ */ jsxs4(Text5, { children: [
1001
+ /* @__PURE__ */ jsx5(Text5, { color: "cyan", children: enabledCount }),
1002
+ /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: " rules enabled (" }),
1003
+ /* @__PURE__ */ jsx5(Text5, { color: "red", children: errorCount }),
1004
+ /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: " errors, " }),
1005
+ /* @__PURE__ */ jsx5(Text5, { color: "yellow", children: warnCount }),
1006
+ /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: " warnings)" }),
1007
+ enabledRulesWithOptions.length > 0 && /* @__PURE__ */ jsxs4(Text5, { dimColor: true, children: [
1008
+ ", ",
1009
+ enabledRulesWithOptions.length,
1010
+ " with options \u2699"
1011
+ ] })
544
1012
  ] }) })
545
1013
  ] });
546
1014
  }
547
1015
 
548
1016
  // src/commands/install/components/InjectionPointSelector.tsx
549
- import { useState as useState5 } from "react";
550
- import { Box as Box4, Text as Text5, useInput as useInput4, useApp as useApp4 } from "ink";
551
- import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
1017
+ import { useState as useState6 } from "react";
1018
+ import { Box as Box5, Text as Text6, useInput as useInput5, useApp as useApp4 } from "ink";
1019
+ import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
552
1020
  function InjectionPointSelector({
553
1021
  points,
554
1022
  onSubmit,
@@ -557,8 +1025,8 @@ function InjectionPointSelector({
557
1025
  }) {
558
1026
  const { exit } = useApp4();
559
1027
  const recommendedIndex = points.findIndex((p) => p.recommended);
560
- const [cursor, setCursor] = useState5(recommendedIndex >= 0 ? recommendedIndex : 0);
561
- useInput4((input, key) => {
1028
+ const [cursor, setCursor] = useState6(recommendedIndex >= 0 ? recommendedIndex : 0);
1029
+ useInput5((input, key) => {
562
1030
  if (key.upArrow) {
563
1031
  setCursor((prev) => prev > 0 ? prev - 1 : points.length - 1);
564
1032
  } else if (key.downArrow) {
@@ -575,16 +1043,16 @@ function InjectionPointSelector({
575
1043
  exit();
576
1044
  }
577
1045
  });
578
- return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
579
- /* @__PURE__ */ jsx5(Box4, { marginBottom: 1, children: /* @__PURE__ */ jsx5(Text5, { bold: true, children: "Where should the devtools component be injected?" }) }),
1046
+ return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
1047
+ /* @__PURE__ */ jsx6(Box5, { marginBottom: 1, children: /* @__PURE__ */ jsx6(Text6, { bold: true, children: "Where should the devtools component be injected?" }) }),
580
1048
  points.map((point, index) => {
581
1049
  const isCursor = index === cursor;
582
- return /* @__PURE__ */ jsxs4(Box4, { paddingLeft: 1, children: [
583
- /* @__PURE__ */ jsx5(Text5, { color: isCursor ? "cyan" : void 0, children: isCursor ? "\u203A " : " " }),
584
- /* @__PURE__ */ jsx5(Box4, { width: 2, children: /* @__PURE__ */ jsx5(Text5, { color: isCursor ? "cyan" : void 0, children: isCursor ? "\u25C9" : "\u25CB" }) }),
585
- /* @__PURE__ */ jsxs4(Box4, { children: [
586
- /* @__PURE__ */ jsx5(Text5, { color: isCursor ? "cyan" : void 0, children: point.label }),
587
- point.hint && /* @__PURE__ */ jsxs4(Text5, { dimColor: true, children: [
1050
+ return /* @__PURE__ */ jsxs5(Box5, { paddingLeft: 1, children: [
1051
+ /* @__PURE__ */ jsx6(Text6, { color: isCursor ? "cyan" : void 0, children: isCursor ? "\u203A " : " " }),
1052
+ /* @__PURE__ */ jsx6(Box5, { width: 2, children: /* @__PURE__ */ jsx6(Text6, { color: isCursor ? "cyan" : void 0, children: isCursor ? "\u25C9" : "\u25CB" }) }),
1053
+ /* @__PURE__ */ jsxs5(Box5, { children: [
1054
+ /* @__PURE__ */ jsx6(Text6, { color: isCursor ? "cyan" : void 0, children: point.label }),
1055
+ point.hint && /* @__PURE__ */ jsxs5(Text6, { dimColor: true, children: [
588
1056
  " (",
589
1057
  point.hint,
590
1058
  ")"
@@ -592,17 +1060,17 @@ function InjectionPointSelector({
592
1060
  ] })
593
1061
  ] }, point.id);
594
1062
  }),
595
- /* @__PURE__ */ jsx5(Box4, { marginTop: 1, borderStyle: "single", borderColor: "gray", paddingX: 1, children: /* @__PURE__ */ jsxs4(Text5, { dimColor: true, children: [
596
- /* @__PURE__ */ jsx5(Text5, { color: "cyan", children: "\u2191\u2193" }),
1063
+ /* @__PURE__ */ jsx6(Box5, { marginTop: 1, borderStyle: "single", borderColor: "gray", paddingX: 1, children: /* @__PURE__ */ jsxs5(Text6, { dimColor: true, children: [
1064
+ /* @__PURE__ */ jsx6(Text6, { color: "cyan", children: "\u2191\u2193" }),
597
1065
  " navigate",
598
1066
  " ",
599
- /* @__PURE__ */ jsx5(Text5, { color: "cyan", children: "enter" }),
1067
+ /* @__PURE__ */ jsx6(Text6, { color: "cyan", children: "enter" }),
600
1068
  " select",
601
1069
  " ",
602
- /* @__PURE__ */ jsx5(Text5, { color: "cyan", children: "b" }),
1070
+ /* @__PURE__ */ jsx6(Text6, { color: "cyan", children: "b" }),
603
1071
  " back",
604
1072
  " ",
605
- /* @__PURE__ */ jsx5(Text5, { color: "cyan", children: "q" }),
1073
+ /* @__PURE__ */ jsx6(Text6, { color: "cyan", children: "q" }),
606
1074
  " quit"
607
1075
  ] }) })
608
1076
  ] });
@@ -967,7 +1435,7 @@ var nextOverlayInstaller = {
967
1435
  };
968
1436
 
969
1437
  // src/commands/install/components/InstallApp.tsx
970
- import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
1438
+ import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
971
1439
  function getTargetStatus(target) {
972
1440
  if (!target.isInstalled) {
973
1441
  return "not_installed";
@@ -1052,10 +1520,10 @@ function checkNodeVersion() {
1052
1520
  };
1053
1521
  }
1054
1522
  function Header({ subtitle }) {
1055
- return /* @__PURE__ */ jsx6(Box5, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsxs5(Box5, { children: [
1056
- /* @__PURE__ */ jsx6(Text6, { bold: true, color: "cyan", children: "\u25C6 UILint" }),
1057
- /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: " v0.5.0" }),
1058
- subtitle && /* @__PURE__ */ jsxs5(Text6, { dimColor: true, children: [
1523
+ return /* @__PURE__ */ jsx7(Box6, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsxs6(Box6, { children: [
1524
+ /* @__PURE__ */ jsx7(Text7, { bold: true, color: "cyan", children: "\u25C6 UILint" }),
1525
+ /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: " v0.5.0" }),
1526
+ subtitle && /* @__PURE__ */ jsxs6(Text7, { dimColor: true, children: [
1059
1527
  " \xB7 ",
1060
1528
  subtitle
1061
1529
  ] })
@@ -1069,22 +1537,22 @@ function FeatureConfig({
1069
1537
  onBack,
1070
1538
  onCancel
1071
1539
  }) {
1072
- useInput5((input, key) => {
1540
+ useInput6((input, key) => {
1073
1541
  if ((input === "b" || key.leftArrow) && canGoBack) {
1074
1542
  onBack();
1075
1543
  }
1076
1544
  });
1077
- return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
1078
- selectedProject && /* @__PURE__ */ jsxs5(Box5, { marginBottom: 1, children: [
1079
- /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "Project: " }),
1080
- /* @__PURE__ */ jsx6(Text6, { bold: true, color: "cyan", children: selectedProject.name }),
1081
- /* @__PURE__ */ jsxs5(Text6, { dimColor: true, children: [
1545
+ return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
1546
+ selectedProject && /* @__PURE__ */ jsxs6(Box6, { marginBottom: 1, children: [
1547
+ /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: "Project: " }),
1548
+ /* @__PURE__ */ jsx7(Text7, { bold: true, color: "cyan", children: selectedProject.name }),
1549
+ /* @__PURE__ */ jsxs6(Text7, { dimColor: true, children: [
1082
1550
  " (",
1083
1551
  selectedProject.hint,
1084
1552
  ")"
1085
1553
  ] })
1086
1554
  ] }),
1087
- /* @__PURE__ */ jsx6(
1555
+ /* @__PURE__ */ jsx7(
1088
1556
  ConfigSelector,
1089
1557
  {
1090
1558
  items: configItems,
@@ -1092,11 +1560,11 @@ function FeatureConfig({
1092
1560
  onCancel
1093
1561
  }
1094
1562
  ),
1095
- canGoBack && /* @__PURE__ */ jsx6(Box5, { marginTop: 1, children: /* @__PURE__ */ jsxs5(Text6, { dimColor: true, children: [
1563
+ canGoBack && /* @__PURE__ */ jsx7(Box6, { marginTop: 1, children: /* @__PURE__ */ jsxs6(Text7, { dimColor: true, children: [
1096
1564
  "Press ",
1097
- /* @__PURE__ */ jsx6(Text6, { color: "cyan", children: "b" }),
1565
+ /* @__PURE__ */ jsx7(Text7, { color: "cyan", children: "b" }),
1098
1566
  " or ",
1099
- /* @__PURE__ */ jsx6(Text6, { color: "cyan", children: "\u2190" }),
1567
+ /* @__PURE__ */ jsx7(Text7, { color: "cyan", children: "\u2190" }),
1100
1568
  " to select a different project"
1101
1569
  ] }) })
1102
1570
  ] });
@@ -1107,18 +1575,18 @@ function InstallApp({
1107
1575
  onError
1108
1576
  }) {
1109
1577
  const { exit } = useApp5();
1110
- const [phase, setPhase] = useState6("checking-requirements");
1111
- const [nodeVersionCheck, setNodeVersionCheck] = useState6(null);
1112
- const [project, setProject] = useState6(null);
1113
- const [detectedProjects, setDetectedProjects] = useState6([]);
1114
- const [selectedProject, setSelectedProject] = useState6(null);
1115
- const [selections, setSelections] = useState6([]);
1116
- const [configItems, setConfigItems] = useState6([]);
1117
- const [selectedFeatureIds, setSelectedFeatureIds] = useState6([]);
1118
- const [uninstallFeatureIds, setUninstallFeatureIds] = useState6([]);
1119
- const [error, setError] = useState6(null);
1120
- const [injectionPoints, setInjectionPoints] = useState6([]);
1121
- const [selectedInjectionPoint, setSelectedInjectionPoint] = useState6(void 0);
1578
+ const [phase, setPhase] = useState7("checking-requirements");
1579
+ const [nodeVersionCheck, setNodeVersionCheck] = useState7(null);
1580
+ const [project, setProject] = useState7(null);
1581
+ const [detectedProjects, setDetectedProjects] = useState7([]);
1582
+ const [selectedProject, setSelectedProject] = useState7(null);
1583
+ const [selections, setSelections] = useState7([]);
1584
+ const [configItems, setConfigItems] = useState7([]);
1585
+ const [selectedFeatureIds, setSelectedFeatureIds] = useState7([]);
1586
+ const [uninstallFeatureIds, setUninstallFeatureIds] = useState7([]);
1587
+ const [error, setError] = useState7(null);
1588
+ const [injectionPoints, setInjectionPoints] = useState7([]);
1589
+ const [selectedInjectionPoint, setSelectedInjectionPoint] = useState7(void 0);
1122
1590
  const isEslintSelected = selectedFeatureIds.some((id) => id.startsWith("eslint:"));
1123
1591
  const isNextSelected = selectedFeatureIds.some((id) => id.startsWith("next:"));
1124
1592
  useEffect2(() => {
@@ -1277,36 +1745,36 @@ function InstallApp({
1277
1745
  exit();
1278
1746
  };
1279
1747
  if (phase === "checking-requirements") {
1280
- return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
1281
- /* @__PURE__ */ jsx6(Header, { subtitle: "Install" }),
1282
- /* @__PURE__ */ jsxs5(Box5, { children: [
1283
- /* @__PURE__ */ jsx6(Spinner, {}),
1284
- /* @__PURE__ */ jsx6(Text6, { children: " Checking requirements..." })
1748
+ return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
1749
+ /* @__PURE__ */ jsx7(Header, { subtitle: "Install" }),
1750
+ /* @__PURE__ */ jsxs6(Box6, { children: [
1751
+ /* @__PURE__ */ jsx7(Spinner, {}),
1752
+ /* @__PURE__ */ jsx7(Text7, { children: " Checking requirements..." })
1285
1753
  ] })
1286
1754
  ] });
1287
1755
  }
1288
1756
  if (phase === "scanning") {
1289
- return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
1290
- /* @__PURE__ */ jsx6(Header, { subtitle: "Install" }),
1291
- /* @__PURE__ */ jsxs5(Box5, { children: [
1292
- /* @__PURE__ */ jsx6(Spinner, {}),
1293
- /* @__PURE__ */ jsx6(Text6, { children: " Scanning project..." })
1757
+ return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
1758
+ /* @__PURE__ */ jsx7(Header, { subtitle: "Install" }),
1759
+ /* @__PURE__ */ jsxs6(Box6, { children: [
1760
+ /* @__PURE__ */ jsx7(Spinner, {}),
1761
+ /* @__PURE__ */ jsx7(Text7, { children: " Scanning project..." })
1294
1762
  ] })
1295
1763
  ] });
1296
1764
  }
1297
1765
  if (phase === "error") {
1298
- return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
1299
- /* @__PURE__ */ jsx6(Header, {}),
1300
- /* @__PURE__ */ jsxs5(Box5, { children: [
1301
- /* @__PURE__ */ jsx6(Text6, { color: "red", children: "\u2717 " }),
1302
- /* @__PURE__ */ jsx6(Text6, { color: "red", children: error?.message || "An unknown error occurred" })
1766
+ return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
1767
+ /* @__PURE__ */ jsx7(Header, {}),
1768
+ /* @__PURE__ */ jsxs6(Box6, { children: [
1769
+ /* @__PURE__ */ jsx7(Text7, { color: "red", children: "\u2717 " }),
1770
+ /* @__PURE__ */ jsx7(Text7, { color: "red", children: error?.message || "An unknown error occurred" })
1303
1771
  ] })
1304
1772
  ] });
1305
1773
  }
1306
1774
  if (phase === "select-project") {
1307
- return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
1308
- /* @__PURE__ */ jsx6(Header, { subtitle: "Install" }),
1309
- /* @__PURE__ */ jsx6(
1775
+ return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
1776
+ /* @__PURE__ */ jsx7(Header, { subtitle: "Install" }),
1777
+ /* @__PURE__ */ jsx7(
1310
1778
  ProjectSelector,
1311
1779
  {
1312
1780
  projects: detectedProjects,
@@ -1317,9 +1785,9 @@ function InstallApp({
1317
1785
  ] });
1318
1786
  }
1319
1787
  if (phase === "configure-features" && project && configItems.length > 0) {
1320
- return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
1321
- /* @__PURE__ */ jsx6(Header, { subtitle: "Features" }),
1322
- /* @__PURE__ */ jsx6(
1788
+ return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
1789
+ /* @__PURE__ */ jsx7(Header, { subtitle: "Features" }),
1790
+ /* @__PURE__ */ jsx7(
1323
1791
  FeatureConfig,
1324
1792
  {
1325
1793
  selectedProject,
@@ -1333,13 +1801,13 @@ function InstallApp({
1333
1801
  ] });
1334
1802
  }
1335
1803
  if (phase === "configure-injection-point" && injectionPoints.length > 0) {
1336
- return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
1337
- /* @__PURE__ */ jsx6(Header, { subtitle: "Injection Point" }),
1338
- selectedProject && /* @__PURE__ */ jsxs5(Box5, { marginBottom: 1, children: [
1339
- /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "Project: " }),
1340
- /* @__PURE__ */ jsx6(Text6, { bold: true, color: "cyan", children: selectedProject.name })
1804
+ return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
1805
+ /* @__PURE__ */ jsx7(Header, { subtitle: "Injection Point" }),
1806
+ selectedProject && /* @__PURE__ */ jsxs6(Box6, { marginBottom: 1, children: [
1807
+ /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: "Project: " }),
1808
+ /* @__PURE__ */ jsx7(Text7, { bold: true, color: "cyan", children: selectedProject.name })
1341
1809
  ] }),
1342
- /* @__PURE__ */ jsx6(
1810
+ /* @__PURE__ */ jsx7(
1343
1811
  InjectionPointSelector,
1344
1812
  {
1345
1813
  points: injectionPoints,
@@ -1351,13 +1819,13 @@ function InstallApp({
1351
1819
  ] });
1352
1820
  }
1353
1821
  if (phase === "configure-eslint") {
1354
- return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
1355
- /* @__PURE__ */ jsx6(Header, { subtitle: "ESLint Rules" }),
1356
- selectedProject && /* @__PURE__ */ jsxs5(Box5, { marginBottom: 1, children: [
1357
- /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "Project: " }),
1358
- /* @__PURE__ */ jsx6(Text6, { bold: true, color: "cyan", children: selectedProject.name })
1822
+ return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
1823
+ /* @__PURE__ */ jsx7(Header, { subtitle: "ESLint Rules" }),
1824
+ selectedProject && /* @__PURE__ */ jsxs6(Box6, { marginBottom: 1, children: [
1825
+ /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: "Project: " }),
1826
+ /* @__PURE__ */ jsx7(Text7, { bold: true, color: "cyan", children: selectedProject.name })
1359
1827
  ] }),
1360
- /* @__PURE__ */ jsx6(
1828
+ /* @__PURE__ */ jsx7(
1361
1829
  RuleSelector,
1362
1830
  {
1363
1831
  onSubmit: handleRuleSubmit,
@@ -1367,9 +1835,9 @@ function InstallApp({
1367
1835
  )
1368
1836
  ] });
1369
1837
  }
1370
- return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
1371
- /* @__PURE__ */ jsx6(Header, {}),
1372
- /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "Loading..." })
1838
+ return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
1839
+ /* @__PURE__ */ jsx7(Header, {}),
1840
+ /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: "Loading..." })
1373
1841
  ] });
1374
1842
  }
1375
1843
 
@@ -3996,7 +4464,7 @@ async function execute(plan, options = {}) {
3996
4464
  }
3997
4465
 
3998
4466
  // src/commands/install-ui.tsx
3999
- import { ruleRegistry as ruleRegistry3 } from "uilint-eslint";
4467
+ import { ruleRegistry as ruleRegistry2 } from "uilint-eslint";
4000
4468
 
4001
4469
  // src/commands/install/installers/genstyleguide.ts
4002
4470
  import { join as join12 } from "path";
@@ -4187,10 +4655,92 @@ var skillInstaller = {
4187
4655
 
4188
4656
  // src/commands/install/installers/eslint.ts
4189
4657
  import { join as join14 } from "path";
4190
- import { ruleRegistry as ruleRegistry2, getRulesByCategory as getRulesByCategory2 } from "uilint-eslint";
4658
+ import { ruleRegistry, getRulesByCategory as getRulesByCategory2, getCategoryMeta as getCategoryMeta2 } from "uilint-eslint";
4659
+ async function promptForField(field, currentValue) {
4660
+ const hint = field.description ? pc.dim(` ${field.description}`) : "";
4661
+ switch (field.type) {
4662
+ case "boolean":
4663
+ return confirm({
4664
+ message: field.label,
4665
+ initialValue: currentValue ?? field.defaultValue ?? false
4666
+ });
4667
+ case "number": {
4668
+ const numResult = await text({
4669
+ message: field.label + hint,
4670
+ placeholder: field.placeholder || String(currentValue ?? field.defaultValue ?? ""),
4671
+ defaultValue: String(currentValue ?? field.defaultValue ?? ""),
4672
+ validate: (value) => {
4673
+ const num = Number(value);
4674
+ if (isNaN(num)) return "Please enter a valid number";
4675
+ return void 0;
4676
+ }
4677
+ });
4678
+ return Number(numResult);
4679
+ }
4680
+ case "text": {
4681
+ const defaultVal = currentValue ?? field.defaultValue ?? "";
4682
+ const displayDefault = Array.isArray(defaultVal) ? defaultVal.join(", ") : String(defaultVal);
4683
+ return text({
4684
+ message: field.label + hint,
4685
+ placeholder: field.placeholder || displayDefault,
4686
+ defaultValue: displayDefault
4687
+ });
4688
+ }
4689
+ case "select":
4690
+ if (!field.options?.length) {
4691
+ return currentValue ?? field.defaultValue;
4692
+ }
4693
+ return select({
4694
+ message: field.label + hint,
4695
+ options: field.options.map((opt) => ({
4696
+ value: String(opt.value),
4697
+ label: opt.label
4698
+ })),
4699
+ initialValue: String(currentValue ?? field.defaultValue)
4700
+ });
4701
+ case "multiselect":
4702
+ if (!field.options?.length) {
4703
+ return currentValue ?? field.defaultValue;
4704
+ }
4705
+ return multiselect({
4706
+ message: field.label + hint,
4707
+ options: field.options.map((opt) => ({
4708
+ value: String(opt.value),
4709
+ label: opt.label
4710
+ })),
4711
+ initialValues: Array.isArray(currentValue) ? currentValue.map(String) : Array.isArray(field.defaultValue) ? field.defaultValue.map(String) : []
4712
+ });
4713
+ default:
4714
+ return currentValue ?? field.defaultValue;
4715
+ }
4716
+ }
4717
+ function convertFieldValue2(value, field, defaultValue) {
4718
+ if (Array.isArray(defaultValue) && field.type === "text" && typeof value === "string") {
4719
+ return value.split(",").map((s) => s.trim()).filter(Boolean);
4720
+ }
4721
+ return value;
4722
+ }
4723
+ async function configureRuleOptions(rule) {
4724
+ if (!rule.optionSchema?.fields?.length) {
4725
+ return void 0;
4726
+ }
4727
+ log("");
4728
+ log(
4729
+ pc.bold(pc.cyan(`${rule.icon ?? "\u2699\uFE0F"} ${rule.name}`)) + pc.dim(` - ${rule.description}`)
4730
+ );
4731
+ const baseOptions = rule.defaultOptions?.[0] ?? {};
4732
+ const options = {};
4733
+ for (const field of rule.optionSchema.fields) {
4734
+ const currentValue = baseOptions[field.key];
4735
+ const defaultValue = currentValue ?? field.defaultValue;
4736
+ const value = await promptForField(field, currentValue);
4737
+ options[field.key] = convertFieldValue2(value, field, defaultValue);
4738
+ }
4739
+ return options;
4740
+ }
4191
4741
  function getUpgradeInfo(configuredRuleIds) {
4192
4742
  const configuredSet = new Set(configuredRuleIds);
4193
- const allRuleIds = ruleRegistry2.map((r) => r.id);
4743
+ const allRuleIds = ruleRegistry.map((r) => r.id);
4194
4744
  const missingRules = allRuleIds.filter((id) => !configuredSet.has(id));
4195
4745
  if (missingRules.length === 0) {
4196
4746
  return void 0;
@@ -4205,8 +4755,8 @@ function formatRuleOption(rule) {
4205
4755
  const severityBadge = rule.defaultSeverity === "error" ? pc.red("error") : pc.yellow("warn");
4206
4756
  return {
4207
4757
  value: rule.id,
4208
- label: `${rule.name}`,
4209
- hint: `${rule.description} [${severityBadge}]`
4758
+ label: `${rule.icon ?? ""} ${rule.name}`.trim(),
4759
+ hint: `${rule.hint ?? rule.description} [${severityBadge}]`
4210
4760
  };
4211
4761
  }
4212
4762
  var eslintInstaller = {
@@ -4267,33 +4817,37 @@ var eslintInstaller = {
4267
4817
  options: rule.defaultOptions
4268
4818
  }));
4269
4819
  } else if (installMode === "strict") {
4270
- configuredRules = ruleRegistry2.map((rule) => ({
4820
+ configuredRules = ruleRegistry.map((rule) => ({
4271
4821
  rule,
4272
4822
  severity: rule.defaultSeverity,
4273
4823
  options: rule.defaultOptions
4274
4824
  }));
4275
4825
  } else {
4276
- log(pc.dim("\n\u{1F4CB} Static rules (pattern-based, fast):"));
4826
+ const staticCat = getCategoryMeta2("static");
4827
+ const semanticCat = getCategoryMeta2("semantic");
4828
+ log(pc.dim(`
4829
+ ${staticCat?.icon ?? "\u{1F4CB}"} ${staticCat?.name ?? "Static rules"} (${staticCat?.description ?? "pattern-based, fast"}):`));
4277
4830
  const selectedStaticIds = await multiselect({
4278
4831
  message: "Select static rules to enable:",
4279
4832
  options: staticRules.map(formatRuleOption),
4280
- initialValues: staticRules.map((r) => r.id)
4833
+ initialValues: staticRules.filter((r) => r.defaultEnabled ?? staticCat?.defaultEnabled ?? true).map((r) => r.id)
4281
4834
  });
4282
4835
  const includeSemanticRules = await confirm({
4283
4836
  message: `Include semantic rules? ${pc.dim(
4284
- "(requires Ollama for LLM analysis)"
4837
+ `(${semanticCat?.description ?? "LLM-powered analysis"})`
4285
4838
  )}`,
4286
4839
  initialValue: false
4287
4840
  });
4288
4841
  let selectedSemanticIds = [];
4289
4842
  if (includeSemanticRules) {
4290
4843
  log(
4291
- pc.dim("\n\u{1F9E0} Semantic rules (LLM-powered, slower):")
4844
+ pc.dim(`
4845
+ ${semanticCat?.icon ?? "\u{1F9E0}"} ${semanticCat?.name ?? "Semantic rules"} (${semanticCat?.description ?? "LLM-powered, slower"}):`)
4292
4846
  );
4293
4847
  selectedSemanticIds = await multiselect({
4294
4848
  message: "Select semantic rules:",
4295
4849
  options: semanticRules.map(formatRuleOption),
4296
- initialValues: semanticRules.map((r) => r.id)
4850
+ initialValues: semanticRules.filter((r) => r.defaultEnabled ?? semanticCat?.defaultEnabled ?? false).map((r) => r.id)
4297
4851
  });
4298
4852
  }
4299
4853
  selectedRuleIds = [...selectedStaticIds, ...selectedSemanticIds];
@@ -4303,7 +4857,7 @@ var eslintInstaller = {
4303
4857
  });
4304
4858
  configuredRules = [];
4305
4859
  for (const ruleId of selectedRuleIds) {
4306
- const rule = ruleRegistry2.find((r) => r.id === ruleId);
4860
+ const rule = ruleRegistry.find((r) => r.id === ruleId);
4307
4861
  if (configureSeverity) {
4308
4862
  const severity = await select({
4309
4863
  message: `${rule.name} - severity:`,
@@ -4331,34 +4885,64 @@ var eslintInstaller = {
4331
4885
  }
4332
4886
  }
4333
4887
  }
4888
+ const rulesWithOptions = configuredRules.filter(
4889
+ (cr) => cr.rule.optionSchema && cr.rule.optionSchema.fields.length > 0
4890
+ );
4891
+ if (rulesWithOptions.length > 0) {
4892
+ const customizeOptions = await confirm({
4893
+ message: `Customize rule options? ${pc.dim(
4894
+ `(${rulesWithOptions.length} rules have configurable options)`
4895
+ )}`,
4896
+ initialValue: false
4897
+ });
4898
+ if (customizeOptions) {
4899
+ for (const cr of configuredRules) {
4900
+ if (cr.rule.optionSchema && cr.rule.optionSchema.fields.length > 0) {
4901
+ const options = await configureRuleOptions(cr.rule);
4902
+ if (options) {
4903
+ const existingOptions = cr.options && cr.options.length > 0 ? cr.options[0] : {};
4904
+ cr.options = [{ ...existingOptions, ...options }];
4905
+ }
4906
+ }
4907
+ }
4908
+ }
4909
+ }
4334
4910
  const errorCount = configuredRules.filter(
4335
4911
  (r) => r.severity === "error"
4336
4912
  ).length;
4337
4913
  const warnCount = configuredRules.filter(
4338
4914
  (r) => r.severity === "warn"
4339
4915
  ).length;
4340
- const hasSemanticDuplicates = configuredRules.some(
4341
- (cr) => cr.rule.id === "no-semantic-duplicates"
4342
- );
4343
4916
  log("");
4344
4917
  note(
4345
4918
  configuredRules.map(
4346
- (cr) => `${cr.severity === "error" ? "\u{1F534}" : "\u{1F7E1}"} ${cr.rule.name} (${cr.severity})`
4919
+ (cr) => `${cr.severity === "error" ? "\u{1F534}" : "\u{1F7E1}"} ${cr.rule.icon ?? ""} ${cr.rule.name} (${cr.severity})`
4347
4920
  ).join("\n"),
4348
4921
  `Selected ${configuredRules.length} rules (${errorCount} errors, ${warnCount} warnings)`
4349
4922
  );
4350
- if (hasSemanticDuplicates) {
4923
+ const rulesWithInstructions = configuredRules.filter(
4924
+ (cr) => cr.rule.postInstallInstructions || (cr.rule.requirements?.length ?? 0) > 0
4925
+ );
4926
+ if (rulesWithInstructions.length > 0) {
4351
4927
  log("");
4352
- log(
4353
- pc.yellow(
4354
- "\u26A0\uFE0F The no-semantic-duplicates rule requires a semantic index."
4355
- )
4356
- );
4357
- log(
4358
- pc.dim(
4359
- " Run 'uilint duplicates index' in each target app to build it."
4360
- )
4361
- );
4928
+ log(pc.bold("\u{1F4CB} Setup Requirements:"));
4929
+ for (const cr of rulesWithInstructions) {
4930
+ if (cr.rule.requirements?.length) {
4931
+ for (const req of cr.rule.requirements) {
4932
+ log(
4933
+ pc.yellow(` \u26A0\uFE0F ${cr.rule.name}: ${req.description}`)
4934
+ );
4935
+ if (req.setupHint) {
4936
+ log(pc.dim(` \u2192 ${req.setupHint}`));
4937
+ }
4938
+ }
4939
+ }
4940
+ if (cr.rule.postInstallInstructions) {
4941
+ log(
4942
+ pc.cyan(` \u2139\uFE0F ${cr.rule.name}: ${cr.rule.postInstallInstructions}`)
4943
+ );
4944
+ }
4945
+ }
4362
4946
  }
4363
4947
  return { configuredRules };
4364
4948
  },
@@ -4572,7 +5156,7 @@ registerInstaller(nextOverlayInstaller);
4572
5156
  registerInstaller(viteOverlayInstaller);
4573
5157
 
4574
5158
  // src/commands/install-ui.tsx
4575
- import { jsx as jsx7 } from "react/jsx-runtime";
5159
+ import { jsx as jsx8 } from "react/jsx-runtime";
4576
5160
  function limitList(items, max) {
4577
5161
  if (items.length <= max) return items;
4578
5162
  return [...items.slice(0, max), pc.dim(`\u2026and ${items.length - max} more`)];
@@ -4692,7 +5276,7 @@ function selectionsToUserChoices(selections, project, eslintRules, injectionPoin
4692
5276
  // Override severity with user's selection
4693
5277
  defaultSeverity: cr.severity,
4694
5278
  defaultOptions: cr.options
4695
- })) : ruleRegistry3
5279
+ })) : ruleRegistry2
4696
5280
  };
4697
5281
  } else if (installer.id === "next") {
4698
5282
  items.push("next");
@@ -4737,7 +5321,7 @@ async function installUI(options = {}, executeOptions = {}) {
4737
5321
  }
4738
5322
  const projectPromise = analyze(projectPath);
4739
5323
  const { waitUntilExit } = render(
4740
- /* @__PURE__ */ jsx7(
5324
+ /* @__PURE__ */ jsx8(
4741
5325
  InstallApp,
4742
5326
  {
4743
5327
  projectPromise,
@@ -4750,7 +5334,7 @@ async function installUI(options = {}, executeOptions = {}) {
4750
5334
  console.log("\nNo changes selected");
4751
5335
  process.exit(0);
4752
5336
  }
4753
- const { createPlan } = await import("./plan-E7ZMQPPE.js");
5337
+ const { createPlan } = await import("./plan-QVR3RBLG.js");
4754
5338
  const plan = createPlan(project, choices, { force: options.force });
4755
5339
  if (hasUninstalls && uninstallSelections) {
4756
5340
  for (const selection of uninstallSelections) {
@@ -4802,4 +5386,4 @@ ${pc.blue("Running tests with coverage...")}`);
4802
5386
  export {
4803
5387
  installUI
4804
5388
  };
4805
- //# sourceMappingURL=install-ui-ZXMZNRU2.js.map
5389
+ //# sourceMappingURL=install-ui-JV4G2CAC.js.map