uilint 0.2.17 → 0.2.20

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.
@@ -20,8 +20,8 @@ import {
20
20
  import { render } from "ink";
21
21
 
22
22
  // src/commands/install/components/InstallApp.tsx
23
- import { useState as useState5, useEffect as useEffect2 } from "react";
24
- import { Box as Box4, Text as Text5, useApp as useApp4, useInput as useInput4 } from "ink";
23
+ import { useState as useState6, useEffect as useEffect2 } from "react";
24
+ import { Box as Box5, Text as Text6, useApp as useApp5, useInput as useInput5 } from "ink";
25
25
 
26
26
  // src/commands/install/components/Spinner.tsx
27
27
  import { useState, useEffect } from "react";
@@ -512,6 +512,69 @@ function RuleSelector({
512
512
  ] });
513
513
  }
514
514
 
515
+ // src/commands/install/components/InjectionPointSelector.tsx
516
+ import { useState as useState5 } from "react";
517
+ import { Box as Box4, Text as Text5, useInput as useInput4, useApp as useApp4 } from "ink";
518
+ import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
519
+ function InjectionPointSelector({
520
+ points,
521
+ onSubmit,
522
+ onBack,
523
+ onCancel
524
+ }) {
525
+ const { exit } = useApp4();
526
+ const recommendedIndex = points.findIndex((p) => p.recommended);
527
+ const [cursor, setCursor] = useState5(recommendedIndex >= 0 ? recommendedIndex : 0);
528
+ useInput4((input, key) => {
529
+ if (key.upArrow) {
530
+ setCursor((prev) => prev > 0 ? prev - 1 : points.length - 1);
531
+ } else if (key.downArrow) {
532
+ setCursor((prev) => prev < points.length - 1 ? prev + 1 : 0);
533
+ } else if (key.return) {
534
+ const selected = points[cursor];
535
+ if (selected) {
536
+ onSubmit(selected);
537
+ }
538
+ } else if (input === "b" || key.leftArrow) {
539
+ onBack?.();
540
+ } else if (input === "q" || key.escape) {
541
+ onCancel?.();
542
+ exit();
543
+ }
544
+ });
545
+ return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
546
+ /* @__PURE__ */ jsx5(Box4, { marginBottom: 1, children: /* @__PURE__ */ jsx5(Text5, { bold: true, children: "Where should the devtools component be injected?" }) }),
547
+ points.map((point, index) => {
548
+ const isCursor = index === cursor;
549
+ return /* @__PURE__ */ jsxs4(Box4, { paddingLeft: 1, children: [
550
+ /* @__PURE__ */ jsx5(Text5, { color: isCursor ? "cyan" : void 0, children: isCursor ? "\u203A " : " " }),
551
+ /* @__PURE__ */ jsx5(Box4, { width: 2, children: /* @__PURE__ */ jsx5(Text5, { color: isCursor ? "cyan" : void 0, children: isCursor ? "\u25C9" : "\u25CB" }) }),
552
+ /* @__PURE__ */ jsxs4(Box4, { children: [
553
+ /* @__PURE__ */ jsx5(Text5, { color: isCursor ? "cyan" : void 0, children: point.label }),
554
+ point.hint && /* @__PURE__ */ jsxs4(Text5, { dimColor: true, children: [
555
+ " (",
556
+ point.hint,
557
+ ")"
558
+ ] })
559
+ ] })
560
+ ] }, point.id);
561
+ }),
562
+ /* @__PURE__ */ jsx5(Box4, { marginTop: 1, borderStyle: "single", borderColor: "gray", paddingX: 1, children: /* @__PURE__ */ jsxs4(Text5, { dimColor: true, children: [
563
+ /* @__PURE__ */ jsx5(Text5, { color: "cyan", children: "\u2191\u2193" }),
564
+ " navigate",
565
+ " ",
566
+ /* @__PURE__ */ jsx5(Text5, { color: "cyan", children: "enter" }),
567
+ " select",
568
+ " ",
569
+ /* @__PURE__ */ jsx5(Text5, { color: "cyan", children: "b" }),
570
+ " back",
571
+ " ",
572
+ /* @__PURE__ */ jsx5(Text5, { color: "cyan", children: "q" }),
573
+ " quit"
574
+ ] }) })
575
+ ] });
576
+ }
577
+
515
578
  // src/commands/install/installers/registry.ts
516
579
  var installers = [];
517
580
  function registerInstaller(installer) {
@@ -525,8 +588,315 @@ function getAllInstallers() {
525
588
  return installers;
526
589
  }
527
590
 
591
+ // src/utils/client-boundary-tracer.ts
592
+ import { existsSync, readFileSync } from "fs";
593
+ import { join, dirname, relative } from "path";
594
+ import { parseModule } from "magicast";
595
+ function hasUseClientDirective(filePath) {
596
+ try {
597
+ const content = readFileSync(filePath, "utf-8");
598
+ const mod = parseModule(content);
599
+ const program = mod.$ast;
600
+ if (!program || program.type !== "Program") return false;
601
+ const directives = program.directives ?? [];
602
+ for (const directive of directives) {
603
+ if (directive?.type === "Directive" && directive.value?.type === "DirectiveLiteral" && directive.value.value === "use client") {
604
+ return true;
605
+ }
606
+ }
607
+ const firstStmt = program.body?.[0];
608
+ if (firstStmt?.type === "ExpressionStatement" && (firstStmt.expression?.type === "StringLiteral" || firstStmt.expression?.type === "Literal") && firstStmt.expression.value === "use client") {
609
+ return true;
610
+ }
611
+ return false;
612
+ } catch {
613
+ return false;
614
+ }
615
+ }
616
+ function extractImports(program) {
617
+ const imports = [];
618
+ if (!program || program.type !== "Program") return imports;
619
+ for (const stmt of program.body ?? []) {
620
+ if (stmt?.type !== "ImportDeclaration") continue;
621
+ const source = stmt.source?.value;
622
+ if (typeof source !== "string") continue;
623
+ if (!source.startsWith(".") && !source.startsWith("@/") && !source.startsWith("~/")) {
624
+ continue;
625
+ }
626
+ const specifiers = [];
627
+ for (const spec of stmt.specifiers ?? []) {
628
+ if (spec.type === "ImportDefaultSpecifier") {
629
+ specifiers.push("default");
630
+ } else if (spec.type === "ImportSpecifier") {
631
+ const name = spec.imported?.name ?? spec.imported?.value;
632
+ if (name) specifiers.push(name);
633
+ } else if (spec.type === "ImportNamespaceSpecifier") {
634
+ specifiers.push("*");
635
+ }
636
+ }
637
+ imports.push({ source, specifiers });
638
+ }
639
+ return imports;
640
+ }
641
+ function resolveImportPath(importSource, fromFile, projectPath) {
642
+ const fromDir = dirname(fromFile);
643
+ let basePath;
644
+ if (importSource.startsWith("@/")) {
645
+ const withoutAlias = importSource.slice(2);
646
+ const srcPath = join(projectPath, "src", withoutAlias);
647
+ const rootPath = join(projectPath, withoutAlias);
648
+ basePath = existsSync(dirname(srcPath)) ? srcPath : rootPath;
649
+ } else if (importSource.startsWith("~/")) {
650
+ basePath = join(projectPath, importSource.slice(2));
651
+ } else if (importSource.startsWith(".")) {
652
+ basePath = join(fromDir, importSource);
653
+ } else {
654
+ return null;
655
+ }
656
+ const extensions = [".tsx", ".ts", ".jsx", ".js"];
657
+ for (const ext of extensions) {
658
+ const fullPath = basePath + ext;
659
+ if (existsSync(fullPath)) return fullPath;
660
+ }
661
+ for (const ext of extensions) {
662
+ const indexPath = join(basePath, `index${ext}`);
663
+ if (existsSync(indexPath)) return indexPath;
664
+ }
665
+ if (existsSync(basePath)) return basePath;
666
+ return null;
667
+ }
668
+ function findLayoutFile(projectPath, appRoot) {
669
+ const extensions = [".tsx", ".jsx", ".ts", ".js"];
670
+ for (const ext of extensions) {
671
+ const layoutPath = join(projectPath, appRoot, `layout${ext}`);
672
+ if (existsSync(layoutPath)) return layoutPath;
673
+ }
674
+ return null;
675
+ }
676
+ function traceClientBoundaries(projectPath, appRoot) {
677
+ const layoutFile = findLayoutFile(projectPath, appRoot);
678
+ if (!layoutFile) {
679
+ return null;
680
+ }
681
+ const layoutIsClient = hasUseClientDirective(layoutFile);
682
+ const layoutRelative = relative(projectPath, layoutFile);
683
+ if (layoutIsClient) {
684
+ return {
685
+ layoutIsClient: true,
686
+ clientBoundaries: [],
687
+ layoutFile,
688
+ layoutRelative
689
+ };
690
+ }
691
+ let program;
692
+ try {
693
+ const content = readFileSync(layoutFile, "utf-8");
694
+ const mod = parseModule(content);
695
+ program = mod.$ast;
696
+ } catch {
697
+ return {
698
+ layoutIsClient: false,
699
+ clientBoundaries: [],
700
+ layoutFile,
701
+ layoutRelative
702
+ };
703
+ }
704
+ const imports = extractImports(program);
705
+ const clientBoundaries = [];
706
+ for (const imp of imports) {
707
+ const resolvedPath = resolveImportPath(imp.source, layoutFile, projectPath);
708
+ if (!resolvedPath) continue;
709
+ if (hasUseClientDirective(resolvedPath)) {
710
+ clientBoundaries.push({
711
+ filePath: resolvedPath,
712
+ relativePath: relative(projectPath, resolvedPath),
713
+ componentNames: imp.specifiers,
714
+ importSource: imp.source
715
+ });
716
+ }
717
+ }
718
+ return {
719
+ layoutIsClient: false,
720
+ clientBoundaries,
721
+ layoutFile,
722
+ layoutRelative
723
+ };
724
+ }
725
+ function providersFileExists(projectPath, appRoot) {
726
+ const extensions = [".tsx", ".jsx", ".ts", ".js"];
727
+ const names = ["providers", "Providers"];
728
+ for (const name of names) {
729
+ for (const ext of extensions) {
730
+ const providersPath = join(projectPath, appRoot, `${name}${ext}`);
731
+ if (existsSync(providersPath)) return providersPath;
732
+ }
733
+ }
734
+ return null;
735
+ }
736
+
737
+ // src/commands/install/installers/next-overlay.ts
738
+ function getInjectionPoints(projectPath, appRoot) {
739
+ const points = [];
740
+ const traceResult = traceClientBoundaries(projectPath, appRoot);
741
+ if (!traceResult) {
742
+ points.push({
743
+ id: "create-providers",
744
+ label: "Create providers.tsx",
745
+ hint: "Recommended",
746
+ createProviders: true,
747
+ recommended: true
748
+ });
749
+ return points;
750
+ }
751
+ if (traceResult.layoutIsClient) {
752
+ points.push({
753
+ id: "layout",
754
+ label: "Root layout",
755
+ hint: "Already a client component",
756
+ filePath: traceResult.layoutFile,
757
+ recommended: true
758
+ });
759
+ return points;
760
+ }
761
+ const existingProviders = providersFileExists(projectPath, appRoot);
762
+ if (!existingProviders) {
763
+ points.push({
764
+ id: "create-providers",
765
+ label: "Create providers.tsx",
766
+ hint: "Recommended",
767
+ createProviders: true,
768
+ recommended: true
769
+ });
770
+ }
771
+ for (const boundary of traceResult.clientBoundaries) {
772
+ const componentNames = boundary.componentNames.length > 0 ? boundary.componentNames.join(", ") : "default";
773
+ points.push({
774
+ id: boundary.relativePath,
775
+ label: boundary.relativePath,
776
+ hint: componentNames,
777
+ filePath: boundary.filePath,
778
+ // Mark existing providers as recommended if it exists
779
+ recommended: existingProviders === boundary.filePath
780
+ });
781
+ }
782
+ if (existingProviders) {
783
+ const relativePath = existingProviders.replace(projectPath + "/", "").replace(projectPath, "");
784
+ const alreadyListed = traceResult.clientBoundaries.some(
785
+ (b) => b.filePath === existingProviders
786
+ );
787
+ if (!alreadyListed) {
788
+ points.push({
789
+ id: "existing-providers",
790
+ label: relativePath,
791
+ hint: "Existing providers",
792
+ filePath: existingProviders,
793
+ recommended: true
794
+ });
795
+ }
796
+ }
797
+ if (points.length === 0) {
798
+ points.push({
799
+ id: "create-providers",
800
+ label: "Create providers.tsx",
801
+ hint: "Recommended",
802
+ createProviders: true,
803
+ recommended: true
804
+ });
805
+ }
806
+ return points;
807
+ }
808
+ var nextOverlayInstaller = {
809
+ id: "next",
810
+ name: "Next.js overlay",
811
+ description: "Alt+Click UI inspector for Next.js App Router",
812
+ icon: "\u{1F537}",
813
+ isApplicable(project) {
814
+ return project.nextApps.length > 0;
815
+ },
816
+ getTargets(project) {
817
+ return project.nextApps.map((app) => ({
818
+ id: `next-${app.projectPath}`,
819
+ label: app.projectPath.split("/").pop() || app.projectPath,
820
+ path: app.projectPath,
821
+ hint: "App Router",
822
+ isInstalled: false
823
+ }));
824
+ },
825
+ plan(targets, config, project) {
826
+ const actions = [];
827
+ const dependencies = [];
828
+ if (targets.length === 0) return { actions, dependencies };
829
+ const target = targets[0];
830
+ const appInfo = project.nextApps.find(
831
+ (app) => app.projectPath === target.path
832
+ );
833
+ if (!appInfo) return { actions, dependencies };
834
+ const { projectPath, detection } = appInfo;
835
+ const nextConfig = config;
836
+ const targetFile = nextConfig.selectedTargetFile;
837
+ const createProviders = nextConfig.createProviders;
838
+ actions.push({
839
+ type: "install_next_routes",
840
+ projectPath,
841
+ appRoot: detection.appRoot
842
+ });
843
+ dependencies.push({
844
+ packagePath: projectPath,
845
+ packageManager: project.packageManager,
846
+ packages: ["uilint-react", "uilint-core", "jsx-loc-plugin"]
847
+ });
848
+ actions.push({
849
+ type: "inject_react",
850
+ projectPath,
851
+ appRoot: detection.appRoot,
852
+ mode: "next",
853
+ targetFile,
854
+ createProviders
855
+ });
856
+ actions.push({
857
+ type: "inject_next_config",
858
+ projectPath
859
+ });
860
+ return { actions, dependencies };
861
+ },
862
+ async *execute(targets, config, project) {
863
+ if (targets.length === 0) return;
864
+ const target = targets[0];
865
+ const nextConfig = config;
866
+ yield {
867
+ type: "start",
868
+ message: "Installing Next.js overlay"
869
+ };
870
+ yield {
871
+ type: "progress",
872
+ message: `Installing in ${target.label}`,
873
+ detail: "\u2192 Adding API routes"
874
+ };
875
+ yield {
876
+ type: "progress",
877
+ message: "Installing dependencies",
878
+ detail: "\u2192 uilint-react, uilint-core, jsx-loc-plugin"
879
+ };
880
+ const injectDetail = nextConfig.createProviders ? "\u2192 Creating providers.tsx" : nextConfig.selectedTargetFile ? `\u2192 ${nextConfig.selectedTargetFile.split("/").pop() || "client component"}` : "\u2192 <uilint-devtools /> in root layout";
881
+ yield {
882
+ type: "progress",
883
+ message: "Injecting devtools component",
884
+ detail: injectDetail
885
+ };
886
+ yield {
887
+ type: "progress",
888
+ message: "Configuring jsx-loc-plugin",
889
+ detail: "\u2192 next.config.js"
890
+ };
891
+ yield {
892
+ type: "complete",
893
+ message: "Next.js overlay installed"
894
+ };
895
+ }
896
+ };
897
+
528
898
  // src/commands/install/components/InstallApp.tsx
529
- import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
899
+ import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
530
900
  function getTargetStatus(target) {
531
901
  if (!target.isInstalled) {
532
902
  return "not_installed";
@@ -597,10 +967,10 @@ function buildGlobalConfigItems(selections) {
597
967
  return items;
598
968
  }
599
969
  function Header({ subtitle }) {
600
- return /* @__PURE__ */ jsx5(Box4, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsxs4(Box4, { children: [
601
- /* @__PURE__ */ jsx5(Text5, { bold: true, color: "cyan", children: "\u25C6 UILint" }),
602
- /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: " v0.5.0" }),
603
- subtitle && /* @__PURE__ */ jsxs4(Text5, { dimColor: true, children: [
970
+ return /* @__PURE__ */ jsx6(Box5, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsxs5(Box5, { children: [
971
+ /* @__PURE__ */ jsx6(Text6, { bold: true, color: "cyan", children: "\u25C6 UILint" }),
972
+ /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: " v0.5.0" }),
973
+ subtitle && /* @__PURE__ */ jsxs5(Text6, { dimColor: true, children: [
604
974
  " \xB7 ",
605
975
  subtitle
606
976
  ] })
@@ -614,22 +984,22 @@ function FeatureConfig({
614
984
  onBack,
615
985
  onCancel
616
986
  }) {
617
- useInput4((input, key) => {
987
+ useInput5((input, key) => {
618
988
  if ((input === "b" || key.leftArrow) && canGoBack) {
619
989
  onBack();
620
990
  }
621
991
  });
622
- return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
623
- selectedProject && /* @__PURE__ */ jsxs4(Box4, { marginBottom: 1, children: [
624
- /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "Project: " }),
625
- /* @__PURE__ */ jsx5(Text5, { bold: true, color: "cyan", children: selectedProject.name }),
626
- /* @__PURE__ */ jsxs4(Text5, { dimColor: true, children: [
992
+ return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
993
+ selectedProject && /* @__PURE__ */ jsxs5(Box5, { marginBottom: 1, children: [
994
+ /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "Project: " }),
995
+ /* @__PURE__ */ jsx6(Text6, { bold: true, color: "cyan", children: selectedProject.name }),
996
+ /* @__PURE__ */ jsxs5(Text6, { dimColor: true, children: [
627
997
  " (",
628
998
  selectedProject.hint,
629
999
  ")"
630
1000
  ] })
631
1001
  ] }),
632
- /* @__PURE__ */ jsx5(
1002
+ /* @__PURE__ */ jsx6(
633
1003
  ConfigSelector,
634
1004
  {
635
1005
  items: configItems,
@@ -637,11 +1007,11 @@ function FeatureConfig({
637
1007
  onCancel
638
1008
  }
639
1009
  ),
640
- canGoBack && /* @__PURE__ */ jsx5(Box4, { marginTop: 1, children: /* @__PURE__ */ jsxs4(Text5, { dimColor: true, children: [
1010
+ canGoBack && /* @__PURE__ */ jsx6(Box5, { marginTop: 1, children: /* @__PURE__ */ jsxs5(Text6, { dimColor: true, children: [
641
1011
  "Press ",
642
- /* @__PURE__ */ jsx5(Text5, { color: "cyan", children: "b" }),
1012
+ /* @__PURE__ */ jsx6(Text6, { color: "cyan", children: "b" }),
643
1013
  " or ",
644
- /* @__PURE__ */ jsx5(Text5, { color: "cyan", children: "\u2190" }),
1014
+ /* @__PURE__ */ jsx6(Text6, { color: "cyan", children: "\u2190" }),
645
1015
  " to select a different project"
646
1016
  ] }) })
647
1017
  ] });
@@ -651,16 +1021,19 @@ function InstallApp({
651
1021
  onComplete,
652
1022
  onError
653
1023
  }) {
654
- const { exit } = useApp4();
655
- const [phase, setPhase] = useState5("scanning");
656
- const [project, setProject] = useState5(null);
657
- const [detectedProjects, setDetectedProjects] = useState5([]);
658
- const [selectedProject, setSelectedProject] = useState5(null);
659
- const [selections, setSelections] = useState5([]);
660
- const [configItems, setConfigItems] = useState5([]);
661
- const [selectedFeatureIds, setSelectedFeatureIds] = useState5([]);
662
- const [error, setError] = useState5(null);
1024
+ const { exit } = useApp5();
1025
+ const [phase, setPhase] = useState6("scanning");
1026
+ const [project, setProject] = useState6(null);
1027
+ const [detectedProjects, setDetectedProjects] = useState6([]);
1028
+ const [selectedProject, setSelectedProject] = useState6(null);
1029
+ const [selections, setSelections] = useState6([]);
1030
+ const [configItems, setConfigItems] = useState6([]);
1031
+ const [selectedFeatureIds, setSelectedFeatureIds] = useState6([]);
1032
+ const [error, setError] = useState6(null);
1033
+ const [injectionPoints, setInjectionPoints] = useState6([]);
1034
+ const [selectedInjectionPoint, setSelectedInjectionPoint] = useState6(void 0);
663
1035
  const isEslintSelected = selectedFeatureIds.some((id) => id.startsWith("eslint:"));
1036
+ const isNextSelected = selectedFeatureIds.some((id) => id.startsWith("next:"));
664
1037
  useEffect2(() => {
665
1038
  if (phase !== "scanning") return;
666
1039
  projectPromise.then((proj) => {
@@ -713,22 +1086,62 @@ function InstallApp({
713
1086
  setPhase("select-project");
714
1087
  }
715
1088
  };
716
- const handleFeatureSubmit = (selectedIds) => {
717
- setSelectedFeatureIds(selectedIds);
1089
+ const handleFeatureSubmit = (selectedIds) => {
1090
+ setSelectedFeatureIds(selectedIds);
1091
+ const nextSelected = selectedIds.some((id) => id.startsWith("next:"));
1092
+ if (nextSelected && project && selectedProject) {
1093
+ const appInfo = project.nextApps.find(
1094
+ (app) => app.projectPath === selectedProject.path
1095
+ );
1096
+ if (appInfo) {
1097
+ const points = getInjectionPoints(appInfo.projectPath, appInfo.detection.appRoot);
1098
+ if (points.length === 1) {
1099
+ const point = points[0];
1100
+ setSelectedInjectionPoint({
1101
+ targetFile: point.filePath,
1102
+ createProviders: point.createProviders
1103
+ });
1104
+ proceedAfterInjectionPoint(selectedIds, {
1105
+ targetFile: point.filePath,
1106
+ createProviders: point.createProviders
1107
+ });
1108
+ return;
1109
+ }
1110
+ if (points.length > 1) {
1111
+ setInjectionPoints(points);
1112
+ setPhase("configure-injection-point");
1113
+ return;
1114
+ }
1115
+ }
1116
+ }
1117
+ proceedAfterInjectionPoint(selectedIds, void 0);
1118
+ };
1119
+ const proceedAfterInjectionPoint = (selectedIds, injectionConfig) => {
718
1120
  const eslintSelected = selectedIds.some((id) => id.startsWith("eslint:"));
719
1121
  if (eslintSelected) {
720
1122
  setPhase("configure-eslint");
721
1123
  } else {
722
- finishInstallation(selectedIds, void 0);
1124
+ finishInstallation(selectedIds, void 0, injectionConfig);
723
1125
  }
724
1126
  };
1127
+ const handleInjectionPointSubmit = (point) => {
1128
+ const config = {
1129
+ targetFile: point.filePath,
1130
+ createProviders: point.createProviders
1131
+ };
1132
+ setSelectedInjectionPoint(config);
1133
+ proceedAfterInjectionPoint(selectedFeatureIds, config);
1134
+ };
1135
+ const handleBackFromInjectionPoint = () => {
1136
+ setPhase("configure-features");
1137
+ };
725
1138
  const handleRuleSubmit = (configuredRules) => {
726
- finishInstallation(selectedFeatureIds, configuredRules);
1139
+ finishInstallation(selectedFeatureIds, configuredRules, selectedInjectionPoint);
727
1140
  };
728
1141
  const handleBackToFeatures = () => {
729
1142
  setPhase("configure-features");
730
1143
  };
731
- const finishInstallation = (selectedIds, eslintRules) => {
1144
+ const finishInstallation = (selectedIds, eslintRules, injectionConfig) => {
732
1145
  const selectedSet = new Set(selectedIds);
733
1146
  const updatedSelections = selections.map((sel) => {
734
1147
  const selectedTargets = sel.targets.filter(
@@ -741,33 +1154,33 @@ function InstallApp({
741
1154
  };
742
1155
  });
743
1156
  setSelections(updatedSelections);
744
- onComplete(updatedSelections, eslintRules);
1157
+ onComplete(updatedSelections, eslintRules, injectionConfig);
745
1158
  };
746
1159
  const handleCancel = () => {
747
1160
  exit();
748
1161
  };
749
1162
  if (phase === "scanning") {
750
- return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
751
- /* @__PURE__ */ jsx5(Header, { subtitle: "Install" }),
752
- /* @__PURE__ */ jsxs4(Box4, { children: [
753
- /* @__PURE__ */ jsx5(Spinner, {}),
754
- /* @__PURE__ */ jsx5(Text5, { children: " Scanning project..." })
1163
+ return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
1164
+ /* @__PURE__ */ jsx6(Header, { subtitle: "Install" }),
1165
+ /* @__PURE__ */ jsxs5(Box5, { children: [
1166
+ /* @__PURE__ */ jsx6(Spinner, {}),
1167
+ /* @__PURE__ */ jsx6(Text6, { children: " Scanning project..." })
755
1168
  ] })
756
1169
  ] });
757
1170
  }
758
1171
  if (phase === "error") {
759
- return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
760
- /* @__PURE__ */ jsx5(Header, {}),
761
- /* @__PURE__ */ jsxs4(Box4, { children: [
762
- /* @__PURE__ */ jsx5(Text5, { color: "red", children: "\u2717 " }),
763
- /* @__PURE__ */ jsx5(Text5, { color: "red", children: error?.message || "An unknown error occurred" })
1172
+ return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
1173
+ /* @__PURE__ */ jsx6(Header, {}),
1174
+ /* @__PURE__ */ jsxs5(Box5, { children: [
1175
+ /* @__PURE__ */ jsx6(Text6, { color: "red", children: "\u2717 " }),
1176
+ /* @__PURE__ */ jsx6(Text6, { color: "red", children: error?.message || "An unknown error occurred" })
764
1177
  ] })
765
1178
  ] });
766
1179
  }
767
1180
  if (phase === "select-project") {
768
- return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
769
- /* @__PURE__ */ jsx5(Header, { subtitle: "Install" }),
770
- /* @__PURE__ */ jsx5(
1181
+ return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
1182
+ /* @__PURE__ */ jsx6(Header, { subtitle: "Install" }),
1183
+ /* @__PURE__ */ jsx6(
771
1184
  ProjectSelector,
772
1185
  {
773
1186
  projects: detectedProjects,
@@ -778,9 +1191,9 @@ function InstallApp({
778
1191
  ] });
779
1192
  }
780
1193
  if (phase === "configure-features" && project && configItems.length > 0) {
781
- return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
782
- /* @__PURE__ */ jsx5(Header, { subtitle: "Features" }),
783
- /* @__PURE__ */ jsx5(
1194
+ return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
1195
+ /* @__PURE__ */ jsx6(Header, { subtitle: "Features" }),
1196
+ /* @__PURE__ */ jsx6(
784
1197
  FeatureConfig,
785
1198
  {
786
1199
  selectedProject,
@@ -793,14 +1206,32 @@ function InstallApp({
793
1206
  )
794
1207
  ] });
795
1208
  }
1209
+ if (phase === "configure-injection-point" && injectionPoints.length > 0) {
1210
+ return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
1211
+ /* @__PURE__ */ jsx6(Header, { subtitle: "Injection Point" }),
1212
+ selectedProject && /* @__PURE__ */ jsxs5(Box5, { marginBottom: 1, children: [
1213
+ /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "Project: " }),
1214
+ /* @__PURE__ */ jsx6(Text6, { bold: true, color: "cyan", children: selectedProject.name })
1215
+ ] }),
1216
+ /* @__PURE__ */ jsx6(
1217
+ InjectionPointSelector,
1218
+ {
1219
+ points: injectionPoints,
1220
+ onSubmit: handleInjectionPointSubmit,
1221
+ onBack: handleBackFromInjectionPoint,
1222
+ onCancel: handleCancel
1223
+ }
1224
+ )
1225
+ ] });
1226
+ }
796
1227
  if (phase === "configure-eslint") {
797
- return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
798
- /* @__PURE__ */ jsx5(Header, { subtitle: "ESLint Rules" }),
799
- selectedProject && /* @__PURE__ */ jsxs4(Box4, { marginBottom: 1, children: [
800
- /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "Project: " }),
801
- /* @__PURE__ */ jsx5(Text5, { bold: true, color: "cyan", children: selectedProject.name })
1228
+ return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
1229
+ /* @__PURE__ */ jsx6(Header, { subtitle: "ESLint Rules" }),
1230
+ selectedProject && /* @__PURE__ */ jsxs5(Box5, { marginBottom: 1, children: [
1231
+ /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "Project: " }),
1232
+ /* @__PURE__ */ jsx6(Text6, { bold: true, color: "cyan", children: selectedProject.name })
802
1233
  ] }),
803
- /* @__PURE__ */ jsx5(
1234
+ /* @__PURE__ */ jsx6(
804
1235
  RuleSelector,
805
1236
  {
806
1237
  onSubmit: handleRuleSubmit,
@@ -810,33 +1241,33 @@ function InstallApp({
810
1241
  )
811
1242
  ] });
812
1243
  }
813
- return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
814
- /* @__PURE__ */ jsx5(Header, {}),
815
- /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "Loading..." })
1244
+ return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
1245
+ /* @__PURE__ */ jsx6(Header, {}),
1246
+ /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "Loading..." })
816
1247
  ] });
817
1248
  }
818
1249
 
819
1250
  // src/commands/install/analyze.ts
820
- import { existsSync as existsSync4, readFileSync as readFileSync4 } from "fs";
821
- import { join as join4 } from "path";
1251
+ import { existsSync as existsSync5, readFileSync as readFileSync5 } from "fs";
1252
+ import { join as join5 } from "path";
822
1253
  import { findWorkspaceRoot as findWorkspaceRoot2 } from "uilint-core/node";
823
1254
 
824
1255
  // src/utils/vite-detect.ts
825
- import { existsSync, readdirSync, readFileSync } from "fs";
826
- import { join } from "path";
1256
+ import { existsSync as existsSync2, readdirSync, readFileSync as readFileSync2 } from "fs";
1257
+ import { join as join2 } from "path";
827
1258
  var VITE_CONFIG_EXTS = [".ts", ".mjs", ".js", ".cjs"];
828
1259
  function findViteConfigFile(projectPath) {
829
1260
  for (const ext of VITE_CONFIG_EXTS) {
830
1261
  const rel = `vite.config${ext}`;
831
- if (existsSync(join(projectPath, rel))) return rel;
1262
+ if (existsSync2(join2(projectPath, rel))) return rel;
832
1263
  }
833
1264
  return null;
834
1265
  }
835
1266
  function looksLikeReactPackage(projectPath) {
836
1267
  try {
837
- const pkgPath = join(projectPath, "package.json");
838
- if (!existsSync(pkgPath)) return false;
839
- const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
1268
+ const pkgPath = join2(projectPath, "package.json");
1269
+ if (!existsSync2(pkgPath)) return false;
1270
+ const pkg = JSON.parse(readFileSync2(pkgPath, "utf-8"));
840
1271
  const deps = { ...pkg.dependencies ?? {}, ...pkg.devDependencies ?? {} };
841
1272
  return "react" in deps || "react-dom" in deps;
842
1273
  } catch {
@@ -844,7 +1275,7 @@ function looksLikeReactPackage(projectPath) {
844
1275
  }
845
1276
  }
846
1277
  function fileExists(projectPath, relPath) {
847
- return existsSync(join(projectPath, relPath));
1278
+ return existsSync2(join2(projectPath, relPath));
848
1279
  }
849
1280
  function detectViteReact(projectPath) {
850
1281
  const configFile = findViteConfigFile(projectPath);
@@ -853,17 +1284,17 @@ function detectViteReact(projectPath) {
853
1284
  const entryRoot = "src";
854
1285
  const candidates = [];
855
1286
  const entryCandidates = [
856
- join(entryRoot, "main.tsx"),
857
- join(entryRoot, "main.jsx"),
858
- join(entryRoot, "main.ts"),
859
- join(entryRoot, "main.js")
1287
+ join2(entryRoot, "main.tsx"),
1288
+ join2(entryRoot, "main.jsx"),
1289
+ join2(entryRoot, "main.ts"),
1290
+ join2(entryRoot, "main.js")
860
1291
  ];
861
1292
  for (const rel of entryCandidates) {
862
1293
  if (fileExists(projectPath, rel)) candidates.push(rel);
863
1294
  }
864
1295
  const fallbackCandidates = [
865
- join(entryRoot, "App.tsx"),
866
- join(entryRoot, "App.jsx")
1296
+ join2(entryRoot, "App.tsx"),
1297
+ join2(entryRoot, "App.jsx")
867
1298
  ];
868
1299
  for (const rel of fallbackCandidates) {
869
1300
  if (!candidates.includes(rel) && fileExists(projectPath, rel)) {
@@ -872,7 +1303,7 @@ function detectViteReact(projectPath) {
872
1303
  }
873
1304
  return {
874
1305
  configFile,
875
- configFileAbs: join(projectPath, configFile),
1306
+ configFileAbs: join2(projectPath, configFile),
876
1307
  entryRoot,
877
1308
  candidates
878
1309
  };
@@ -917,7 +1348,7 @@ function findViteReactProjects(rootDir, options) {
917
1348
  if (!ent.isDirectory) continue;
918
1349
  if (ignoreDirs.has(ent.name)) continue;
919
1350
  if (ent.name.startsWith(".") && ent.name !== ".") continue;
920
- walk(join(dir, ent.name), depth + 1);
1351
+ walk(join2(dir, ent.name), depth + 1);
921
1352
  }
922
1353
  }
923
1354
  walk(rootDir, 0);
@@ -925,8 +1356,8 @@ function findViteReactProjects(rootDir, options) {
925
1356
  }
926
1357
 
927
1358
  // src/utils/package-detect.ts
928
- import { existsSync as existsSync2, readdirSync as readdirSync2, readFileSync as readFileSync2 } from "fs";
929
- import { join as join2, relative } from "path";
1359
+ import { existsSync as existsSync3, readdirSync as readdirSync2, readFileSync as readFileSync3 } from "fs";
1360
+ import { join as join3, relative as relative2 } from "path";
930
1361
  var DEFAULT_IGNORE_DIRS2 = /* @__PURE__ */ new Set([
931
1362
  "node_modules",
932
1363
  ".git",
@@ -971,7 +1402,7 @@ function isFrontendPackage(pkgJson) {
971
1402
  return FRONTEND_INDICATORS.some((pkg) => pkg in deps);
972
1403
  }
973
1404
  function isTypeScriptPackage(dir, pkgJson) {
974
- if (existsSync2(join2(dir, "tsconfig.json"))) {
1405
+ if (existsSync3(join3(dir, "tsconfig.json"))) {
975
1406
  return true;
976
1407
  }
977
1408
  const deps = {
@@ -982,7 +1413,7 @@ function isTypeScriptPackage(dir, pkgJson) {
982
1413
  return true;
983
1414
  }
984
1415
  for (const configFile of ESLINT_CONFIG_FILES) {
985
- if (configFile.endsWith(".ts") && existsSync2(join2(dir, configFile))) {
1416
+ if (configFile.endsWith(".ts") && existsSync3(join3(dir, configFile))) {
986
1417
  return true;
987
1418
  }
988
1419
  }
@@ -990,14 +1421,14 @@ function isTypeScriptPackage(dir, pkgJson) {
990
1421
  }
991
1422
  function hasEslintConfig(dir) {
992
1423
  for (const file of ESLINT_CONFIG_FILES) {
993
- if (existsSync2(join2(dir, file))) {
1424
+ if (existsSync3(join3(dir, file))) {
994
1425
  return true;
995
1426
  }
996
1427
  }
997
1428
  try {
998
- const pkgPath = join2(dir, "package.json");
999
- if (existsSync2(pkgPath)) {
1000
- const pkg = JSON.parse(readFileSync2(pkgPath, "utf-8"));
1429
+ const pkgPath = join3(dir, "package.json");
1430
+ if (existsSync3(pkgPath)) {
1431
+ const pkg = JSON.parse(readFileSync3(pkgPath, "utf-8"));
1001
1432
  if (pkg.eslintConfig) return true;
1002
1433
  }
1003
1434
  } catch {
@@ -1010,14 +1441,14 @@ function findPackages(rootDir, options) {
1010
1441
  const results = [];
1011
1442
  const visited = /* @__PURE__ */ new Set();
1012
1443
  function processPackage(dir, isRoot) {
1013
- const pkgPath = join2(dir, "package.json");
1014
- if (!existsSync2(pkgPath)) return null;
1444
+ const pkgPath = join3(dir, "package.json");
1445
+ if (!existsSync3(pkgPath)) return null;
1015
1446
  try {
1016
- const pkg = JSON.parse(readFileSync2(pkgPath, "utf-8"));
1017
- const name = pkg.name || relative(rootDir, dir) || ".";
1447
+ const pkg = JSON.parse(readFileSync3(pkgPath, "utf-8"));
1448
+ const name = pkg.name || relative2(rootDir, dir) || ".";
1018
1449
  return {
1019
1450
  path: dir,
1020
- displayPath: relative(rootDir, dir) || ".",
1451
+ displayPath: relative2(rootDir, dir) || ".",
1021
1452
  name,
1022
1453
  hasEslintConfig: hasEslintConfig(dir),
1023
1454
  isFrontend: isFrontendPackage(pkg),
@@ -1049,7 +1480,7 @@ function findPackages(rootDir, options) {
1049
1480
  if (!ent.isDirectory) continue;
1050
1481
  if (ignoreDirs.has(ent.name)) continue;
1051
1482
  if (ent.name.startsWith(".")) continue;
1052
- walk(join2(dir, ent.name), depth + 1);
1483
+ walk(join3(dir, ent.name), depth + 1);
1053
1484
  }
1054
1485
  }
1055
1486
  walk(rootDir, 0);
@@ -1063,15 +1494,15 @@ function findPackages(rootDir, options) {
1063
1494
  }
1064
1495
 
1065
1496
  // src/utils/eslint-config-inject.ts
1066
- import { existsSync as existsSync3, readFileSync as readFileSync3, writeFileSync } from "fs";
1067
- import { join as join3, relative as relative2, dirname } from "path";
1068
- import { parseExpression, parseModule, generateCode } from "magicast";
1497
+ import { existsSync as existsSync4, readFileSync as readFileSync4, writeFileSync } from "fs";
1498
+ import { join as join4, relative as relative3, dirname as dirname2 } from "path";
1499
+ import { parseExpression, parseModule as parseModule2, generateCode } from "magicast";
1069
1500
  import { findWorkspaceRoot } from "uilint-core/node";
1070
1501
  var CONFIG_EXTENSIONS = [".ts", ".mjs", ".js", ".cjs"];
1071
1502
  function findEslintConfigFile(projectPath) {
1072
1503
  for (const ext of CONFIG_EXTENSIONS) {
1073
- const configPath = join3(projectPath, `eslint.config${ext}`);
1074
- if (existsSync3(configPath)) {
1504
+ const configPath = join4(projectPath, `eslint.config${ext}`);
1505
+ if (existsSync4(configPath)) {
1075
1506
  return configPath;
1076
1507
  }
1077
1508
  }
@@ -1294,9 +1725,9 @@ function chooseUniqueIdentifier(base, used) {
1294
1725
  function addLocalRuleImportsAst(mod, selectedRules, configPath, rulesRoot, fileExtension = ".js") {
1295
1726
  const importNames = /* @__PURE__ */ new Map();
1296
1727
  let changed = false;
1297
- const configDir = dirname(configPath);
1298
- const rulesDir = join3(rulesRoot, ".uilint", "rules");
1299
- const relativeRulesPath = relative2(configDir, rulesDir).replace(/\\/g, "/");
1728
+ const configDir = dirname2(configPath);
1729
+ const rulesDir = join4(rulesRoot, ".uilint", "rules");
1730
+ const relativeRulesPath = relative3(configDir, rulesDir).replace(/\\/g, "/");
1300
1731
  const normalizedRulesPath = relativeRulesPath.startsWith("./") || relativeRulesPath.startsWith("../") ? relativeRulesPath : `./${relativeRulesPath}`;
1301
1732
  const used = collectTopLevelBindings(mod.$ast);
1302
1733
  for (const rule of selectedRules) {
@@ -1322,9 +1753,9 @@ function addLocalRuleRequiresAst(program, selectedRules, configPath, rulesRoot,
1322
1753
  if (!program || program.type !== "Program") {
1323
1754
  return { importNames, changed };
1324
1755
  }
1325
- const configDir = dirname(configPath);
1326
- const rulesDir = join3(rulesRoot, ".uilint", "rules");
1327
- const relativeRulesPath = relative2(configDir, rulesDir).replace(/\\/g, "/");
1756
+ const configDir = dirname2(configPath);
1757
+ const rulesDir = join4(rulesRoot, ".uilint", "rules");
1758
+ const relativeRulesPath = relative3(configDir, rulesDir).replace(/\\/g, "/");
1328
1759
  const normalizedRulesPath = relativeRulesPath.startsWith("./") || relativeRulesPath.startsWith("../") ? relativeRulesPath : `./${relativeRulesPath}`;
1329
1760
  const used = collectTopLevelBindings(program);
1330
1761
  for (const rule of selectedRules) {
@@ -1335,7 +1766,7 @@ function addLocalRuleRequiresAst(program, selectedRules, configPath, rulesRoot,
1335
1766
  importNames.set(rule.id, importName);
1336
1767
  used.add(importName);
1337
1768
  const rulePath = `${normalizedRulesPath}/${rule.id}${fileExtension}`;
1338
- const stmtMod = parseModule(
1769
+ const stmtMod = parseModule2(
1339
1770
  `const ${importName} = require("${rulePath}");`
1340
1771
  );
1341
1772
  const stmt = stmtMod.$ast.body?.[0];
@@ -1384,7 +1815,7 @@ ${rulesPropsCode}
1384
1815
  }
1385
1816
  function getUilintEslintConfigInfoFromSourceAst(source) {
1386
1817
  try {
1387
- const mod = parseModule(source);
1818
+ const mod = parseModule2(source);
1388
1819
  const found = findExportedConfigArrayExpression(mod);
1389
1820
  if (!found) {
1390
1821
  return {
@@ -1482,7 +1913,7 @@ async function installEslintPlugin(opts) {
1482
1913
  };
1483
1914
  }
1484
1915
  const configFilename = getEslintConfigFilename(configPath);
1485
- const original = readFileSync3(configPath, "utf-8");
1916
+ const original = readFileSync4(configPath, "utf-8");
1486
1917
  const isCommonJS = configPath.endsWith(".cjs");
1487
1918
  const ast = getUilintEslintConfigInfoFromSourceAst(original);
1488
1919
  if ("error" in ast) {
@@ -1534,10 +1965,10 @@ async function installEslintPlugin(opts) {
1534
1965
  };
1535
1966
  }
1536
1967
  let modifiedAst = false;
1537
- const localRulesDir = join3(opts.projectPath, ".uilint", "rules");
1968
+ const localRulesDir = join4(opts.projectPath, ".uilint", "rules");
1538
1969
  const workspaceRoot = findWorkspaceRoot(opts.projectPath);
1539
- const workspaceRulesDir = join3(workspaceRoot, ".uilint", "rules");
1540
- const rulesRoot = existsSync3(localRulesDir) ? opts.projectPath : workspaceRoot;
1970
+ const workspaceRulesDir = join4(workspaceRoot, ".uilint", "rules");
1971
+ const rulesRoot = existsSync4(localRulesDir) ? opts.projectPath : workspaceRoot;
1541
1972
  const isTypeScriptConfig = configPath.endsWith(".ts");
1542
1973
  let fileExtension = isTypeScriptConfig ? "" : ".js";
1543
1974
  let ruleImportNames;
@@ -1575,7 +2006,7 @@ async function installEslintPlugin(opts) {
1575
2006
  });
1576
2007
  modifiedAst = true;
1577
2008
  } else {
1578
- const stmtMod = parseModule(
2009
+ const stmtMod = parseModule2(
1579
2010
  `const { createRule } = require("uilint-eslint");`
1580
2011
  );
1581
2012
  const stmt = stmtMod.$ast.body?.[0];
@@ -1612,12 +2043,12 @@ async function installEslintPlugin(opts) {
1612
2043
  async function analyze(projectPath = process.cwd()) {
1613
2044
  const workspaceRoot = findWorkspaceRoot2(projectPath);
1614
2045
  const packageManager = detectPackageManager(projectPath);
1615
- const cursorDir = join4(projectPath, ".cursor");
1616
- const cursorDirExists = existsSync4(cursorDir);
1617
- const styleguidePath = join4(projectPath, ".uilint", "styleguide.md");
1618
- const styleguideExists = existsSync4(styleguidePath);
1619
- const commandsDir = join4(cursorDir, "commands");
1620
- const genstyleguideExists = existsSync4(join4(commandsDir, "genstyleguide.md"));
2046
+ const cursorDir = join5(projectPath, ".cursor");
2047
+ const cursorDirExists = existsSync5(cursorDir);
2048
+ const styleguidePath = join5(projectPath, ".uilint", "styleguide.md");
2049
+ const styleguideExists = existsSync5(styleguidePath);
2050
+ const commandsDir = join5(cursorDir, "commands");
2051
+ const genstyleguideExists = existsSync5(join5(commandsDir, "genstyleguide.md"));
1621
2052
  const nextApps = [];
1622
2053
  const directDetection = detectNextAppRouter(projectPath);
1623
2054
  if (directDetection) {
@@ -1653,7 +2084,7 @@ async function analyze(projectPath = process.cwd()) {
1653
2084
  if (eslintConfigPath) {
1654
2085
  eslintConfigFilename = getEslintConfigFilename(eslintConfigPath);
1655
2086
  try {
1656
- const source = readFileSync4(eslintConfigPath, "utf-8");
2087
+ const source = readFileSync5(eslintConfigPath, "utf-8");
1657
2088
  const info = getUilintEslintConfigInfoFromSource(source);
1658
2089
  hasRules = info.configuredRuleIds.size > 0;
1659
2090
  configuredRuleIds = Array.from(info.configuredRuleIds);
@@ -1691,49 +2122,49 @@ async function analyze(projectPath = process.cwd()) {
1691
2122
 
1692
2123
  // src/commands/install/execute.ts
1693
2124
  import {
1694
- existsSync as existsSync10,
2125
+ existsSync as existsSync11,
1695
2126
  mkdirSync,
1696
2127
  writeFileSync as writeFileSync5,
1697
- readFileSync as readFileSync8,
2128
+ readFileSync as readFileSync9,
1698
2129
  unlinkSync,
1699
2130
  chmodSync
1700
2131
  } from "fs";
1701
- import { dirname as dirname4 } from "path";
2132
+ import { dirname as dirname5 } from "path";
1702
2133
 
1703
2134
  // src/utils/react-inject.ts
1704
- import { existsSync as existsSync5, readFileSync as readFileSync5, writeFileSync as writeFileSync2 } from "fs";
1705
- import { join as join5, relative as relative3 } from "path";
1706
- import { parseModule as parseModule2, generateCode as generateCode2 } from "magicast";
2135
+ import { existsSync as existsSync6, readFileSync as readFileSync6, writeFileSync as writeFileSync2 } from "fs";
2136
+ import { join as join6, relative as relative4 } from "path";
2137
+ import { parseModule as parseModule3, generateCode as generateCode2 } from "magicast";
1707
2138
  function getDefaultCandidates(projectPath, appRoot) {
1708
2139
  const viteMainCandidates = [
1709
- join5(appRoot, "main.tsx"),
1710
- join5(appRoot, "main.jsx"),
1711
- join5(appRoot, "main.ts"),
1712
- join5(appRoot, "main.js")
2140
+ join6(appRoot, "main.tsx"),
2141
+ join6(appRoot, "main.jsx"),
2142
+ join6(appRoot, "main.ts"),
2143
+ join6(appRoot, "main.js")
1713
2144
  ];
1714
2145
  const existingViteMain = viteMainCandidates.filter(
1715
- (rel) => existsSync5(join5(projectPath, rel))
2146
+ (rel) => existsSync6(join6(projectPath, rel))
1716
2147
  );
1717
2148
  if (existingViteMain.length > 0) return existingViteMain;
1718
- const viteAppCandidates = [join5(appRoot, "App.tsx"), join5(appRoot, "App.jsx")];
2149
+ const viteAppCandidates = [join6(appRoot, "App.tsx"), join6(appRoot, "App.jsx")];
1719
2150
  const existingViteApp = viteAppCandidates.filter(
1720
- (rel) => existsSync5(join5(projectPath, rel))
2151
+ (rel) => existsSync6(join6(projectPath, rel))
1721
2152
  );
1722
2153
  if (existingViteApp.length > 0) return existingViteApp;
1723
2154
  const layoutCandidates = [
1724
- join5(appRoot, "layout.tsx"),
1725
- join5(appRoot, "layout.jsx"),
1726
- join5(appRoot, "layout.ts"),
1727
- join5(appRoot, "layout.js")
2155
+ join6(appRoot, "layout.tsx"),
2156
+ join6(appRoot, "layout.jsx"),
2157
+ join6(appRoot, "layout.ts"),
2158
+ join6(appRoot, "layout.js")
1728
2159
  ];
1729
2160
  const existingLayouts = layoutCandidates.filter(
1730
- (rel) => existsSync5(join5(projectPath, rel))
2161
+ (rel) => existsSync6(join6(projectPath, rel))
1731
2162
  );
1732
2163
  if (existingLayouts.length > 0) {
1733
2164
  return existingLayouts;
1734
2165
  }
1735
- const pageCandidates = [join5(appRoot, "page.tsx"), join5(appRoot, "page.jsx")];
1736
- return pageCandidates.filter((rel) => existsSync5(join5(projectPath, rel)));
2166
+ const pageCandidates = [join6(appRoot, "page.tsx"), join6(appRoot, "page.jsx")];
2167
+ return pageCandidates.filter((rel) => existsSync6(join6(projectPath, rel)));
1737
2168
  }
1738
2169
  function isUseClientDirective(stmt) {
1739
2170
  return stmt?.type === "ExpressionStatement" && stmt.expression?.type === "StringLiteral" && stmt.expression.value === "use client";
@@ -1767,12 +2198,12 @@ function ensureNamedImport(program, from, name) {
1767
2198
  (s) => s?.type === "ImportSpecifier" && (s.imported?.name === name || s.imported?.value === name)
1768
2199
  );
1769
2200
  if (has) return { changed: false };
1770
- const spec = parseModule2(`import { ${name} } from "${from}";`).$ast.body?.[0]?.specifiers?.[0];
2201
+ const spec = parseModule3(`import { ${name} } from "${from}";`).$ast.body?.[0]?.specifiers?.[0];
1771
2202
  if (!spec) return { changed: false };
1772
2203
  existing.specifiers = [...existing.specifiers ?? [], spec];
1773
2204
  return { changed: true };
1774
2205
  }
1775
- const importDecl = parseModule2(`import { ${name} } from "${from}";`).$ast.body?.[0];
2206
+ const importDecl = parseModule3(`import { ${name} } from "${from}";`).$ast.body?.[0];
1776
2207
  if (!importDecl) return { changed: false };
1777
2208
  const body = program.body ?? [];
1778
2209
  let insertAt = 0;
@@ -1802,7 +2233,7 @@ function hasUILintDevtoolsJsx(program) {
1802
2233
  function addDevtoolsElementNextJs(program) {
1803
2234
  if (!program || program.type !== "Program") return { changed: false };
1804
2235
  if (hasUILintDevtoolsJsx(program)) return { changed: false };
1805
- const devtoolsMod = parseModule2(
2236
+ const devtoolsMod = parseModule3(
1806
2237
  "const __uilint_devtools = <uilint-devtools />;"
1807
2238
  );
1808
2239
  const devtoolsJsx = devtoolsMod.$ast.body?.[0]?.declarations?.[0]?.init ?? null;
@@ -1840,12 +2271,12 @@ function addDevtoolsElementVite(program) {
1840
2271
  const arg0 = node.arguments?.[0];
1841
2272
  if (!arg0) return;
1842
2273
  if (arg0.type !== "JSXElement" && arg0.type !== "JSXFragment") return;
1843
- const devtoolsMod = parseModule2(
2274
+ const devtoolsMod = parseModule3(
1844
2275
  "const __uilint_devtools = <uilint-devtools />;"
1845
2276
  );
1846
2277
  const devtoolsJsx = devtoolsMod.$ast.body?.[0]?.declarations?.[0]?.init ?? null;
1847
2278
  if (!devtoolsJsx) return;
1848
- const fragmentMod = parseModule2(
2279
+ const fragmentMod = parseModule3(
1849
2280
  "const __fragment = <></>;"
1850
2281
  );
1851
2282
  const fragmentJsx = fragmentMod.$ast.body?.[0]?.declarations?.[0]?.init ?? null;
@@ -1865,7 +2296,7 @@ function ensureSideEffectImport(program, from) {
1865
2296
  if (!program || program.type !== "Program") return { changed: false };
1866
2297
  const existing = findImportDeclaration(program, from);
1867
2298
  if (existing) return { changed: false };
1868
- const importDecl = parseModule2(`import "${from}";`).$ast.body?.[0];
2299
+ const importDecl = parseModule3(`import "${from}";`).$ast.body?.[0];
1869
2300
  if (!importDecl) return { changed: false };
1870
2301
  const body = program.body ?? [];
1871
2302
  let insertAt = 0;
@@ -1881,7 +2312,7 @@ function ensureSideEffectImport(program, from) {
1881
2312
  function addDevtoolsToClientComponent(program) {
1882
2313
  if (!program || program.type !== "Program") return { changed: false };
1883
2314
  if (hasUILintDevtoolsJsx(program)) return { changed: false };
1884
- const devtoolsMod = parseModule2(
2315
+ const devtoolsMod = parseModule3(
1885
2316
  "const __uilint_devtools = <uilint-devtools />;"
1886
2317
  );
1887
2318
  const devtoolsJsx = devtoolsMod.$ast.body?.[0]?.declarations?.[0]?.init ?? null;
@@ -1907,7 +2338,7 @@ function addDevtoolsToClientComponent(program) {
1907
2338
  const arg = node.argument;
1908
2339
  if (!arg) return;
1909
2340
  if (arg.type !== "JSXElement" && arg.type !== "JSXFragment") return;
1910
- const fragmentMod = parseModule2("const __fragment = <></>;");
2341
+ const fragmentMod = parseModule3("const __fragment = <></>;");
1911
2342
  const fragmentJsx = fragmentMod.$ast.body?.[0]?.declarations?.[0]?.init ?? null;
1912
2343
  if (!fragmentJsx) return;
1913
2344
  fragmentJsx.children = [arg, devtoolsJsx];
@@ -1962,7 +2393,7 @@ function wrapChildrenWithProviders(program, providersImportPath) {
1962
2393
  (child) => child?.type === "JSXExpressionContainer" && child.expression?.type === "Identifier" && child.expression.name === "children"
1963
2394
  );
1964
2395
  if (childrenIndex === -1) return;
1965
- const providersMod = parseModule2(
2396
+ const providersMod = parseModule3(
1966
2397
  "const __providers = <Providers>{children}</Providers>;"
1967
2398
  );
1968
2399
  const providersJsx = providersMod.$ast.body?.[0]?.declarations?.[0]?.init ?? null;
@@ -1977,36 +2408,36 @@ function wrapChildrenWithProviders(program, providersImportPath) {
1977
2408
  }
1978
2409
  return { changed: true };
1979
2410
  }
1980
- function findLayoutFile(projectPath, appRoot) {
2411
+ function findLayoutFile2(projectPath, appRoot) {
1981
2412
  const extensions = [".tsx", ".jsx", ".ts", ".js"];
1982
2413
  for (const ext of extensions) {
1983
- const layoutPath = join5(projectPath, appRoot, `layout${ext}`);
1984
- if (existsSync5(layoutPath)) return layoutPath;
2414
+ const layoutPath = join6(projectPath, appRoot, `layout${ext}`);
2415
+ if (existsSync6(layoutPath)) return layoutPath;
1985
2416
  }
1986
2417
  return null;
1987
2418
  }
1988
2419
  async function createProvidersAndModifyLayout(projectPath, appRoot) {
1989
- const layoutPath = findLayoutFile(projectPath, appRoot);
2420
+ const layoutPath = findLayoutFile2(projectPath, appRoot);
1990
2421
  if (!layoutPath) {
1991
2422
  throw new Error(`Could not find layout file in ${appRoot}`);
1992
2423
  }
1993
2424
  const isTypeScript = layoutPath.endsWith(".tsx") || layoutPath.endsWith(".ts");
1994
2425
  const providersExt = isTypeScript ? ".tsx" : ".jsx";
1995
- const providersPath = join5(projectPath, appRoot, `providers${providersExt}`);
1996
- if (existsSync5(providersPath)) {
2426
+ const providersPath = join6(projectPath, appRoot, `providers${providersExt}`);
2427
+ if (existsSync6(providersPath)) {
1997
2428
  throw new Error(
1998
2429
  `providers${providersExt} already exists. Please select it from the list instead.`
1999
2430
  );
2000
2431
  }
2001
2432
  const providersContent = generateProvidersContent(isTypeScript);
2002
2433
  writeFileSync2(providersPath, providersContent, "utf-8");
2003
- const layoutContent = readFileSync5(layoutPath, "utf-8");
2434
+ const layoutContent = readFileSync6(layoutPath, "utf-8");
2004
2435
  let layoutMod;
2005
2436
  try {
2006
- layoutMod = parseModule2(layoutContent);
2437
+ layoutMod = parseModule3(layoutContent);
2007
2438
  } catch {
2008
2439
  throw new Error(
2009
- `Unable to parse ${relative3(projectPath, layoutPath)} as JavaScript/TypeScript.`
2440
+ `Unable to parse ${relative4(projectPath, layoutPath)} as JavaScript/TypeScript.`
2010
2441
  );
2011
2442
  }
2012
2443
  const layoutProgram = layoutMod.$ast;
@@ -2016,8 +2447,8 @@ async function createProvidersAndModifyLayout(projectPath, appRoot) {
2016
2447
  writeFileSync2(layoutPath, updatedLayout, "utf-8");
2017
2448
  }
2018
2449
  return {
2019
- providersFile: relative3(projectPath, providersPath),
2020
- layoutFile: relative3(projectPath, layoutPath),
2450
+ providersFile: relative4(projectPath, providersPath),
2451
+ layoutFile: relative4(projectPath, layoutPath),
2021
2452
  modified: true
2022
2453
  };
2023
2454
  }
@@ -2036,14 +2467,14 @@ async function installReactUILintOverlay(opts) {
2036
2467
  }
2037
2468
  if (opts.targetFile) {
2038
2469
  const absTarget2 = opts.targetFile;
2039
- const relTarget = relative3(opts.projectPath, absTarget2);
2040
- if (!existsSync5(absTarget2)) {
2470
+ const relTarget = relative4(opts.projectPath, absTarget2);
2471
+ if (!existsSync6(absTarget2)) {
2041
2472
  throw new Error(`Target file not found: ${relTarget}`);
2042
2473
  }
2043
- const original2 = readFileSync5(absTarget2, "utf-8");
2474
+ const original2 = readFileSync6(absTarget2, "utf-8");
2044
2475
  let mod2;
2045
2476
  try {
2046
- mod2 = parseModule2(original2);
2477
+ mod2 = parseModule3(original2);
2047
2478
  } catch {
2048
2479
  throw new Error(
2049
2480
  `Unable to parse ${relTarget} as JavaScript/TypeScript. Please update it manually.`
@@ -2088,11 +2519,11 @@ async function installReactUILintOverlay(opts) {
2088
2519
  } else {
2089
2520
  chosen = candidates[0];
2090
2521
  }
2091
- const absTarget = join5(opts.projectPath, chosen);
2092
- const original = readFileSync5(absTarget, "utf-8");
2522
+ const absTarget = join6(opts.projectPath, chosen);
2523
+ const original = readFileSync6(absTarget, "utf-8");
2093
2524
  let mod;
2094
2525
  try {
2095
- mod = parseModule2(original);
2526
+ mod = parseModule3(original);
2096
2527
  } catch {
2097
2528
  throw new Error(
2098
2529
  `Unable to parse ${chosen} as JavaScript/TypeScript. Please update it manually.`
@@ -2121,14 +2552,14 @@ async function installReactUILintOverlay(opts) {
2121
2552
  }
2122
2553
 
2123
2554
  // src/utils/next-config-inject.ts
2124
- import { existsSync as existsSync6, readFileSync as readFileSync6, writeFileSync as writeFileSync3 } from "fs";
2125
- import { join as join6 } from "path";
2126
- import { parseModule as parseModule3, generateCode as generateCode3 } from "magicast";
2555
+ import { existsSync as existsSync7, readFileSync as readFileSync7, writeFileSync as writeFileSync3 } from "fs";
2556
+ import { join as join7 } from "path";
2557
+ import { parseModule as parseModule4, generateCode as generateCode3 } from "magicast";
2127
2558
  var CONFIG_EXTENSIONS2 = [".ts", ".mjs", ".js", ".cjs"];
2128
2559
  function findNextConfigFile(projectPath) {
2129
2560
  for (const ext of CONFIG_EXTENSIONS2) {
2130
- const configPath = join6(projectPath, `next.config${ext}`);
2131
- if (existsSync6(configPath)) {
2561
+ const configPath = join7(projectPath, `next.config${ext}`);
2562
+ if (existsSync7(configPath)) {
2132
2563
  return configPath;
2133
2564
  }
2134
2565
  }
@@ -2154,12 +2585,12 @@ function ensureEsmWithJsxLocImport(program) {
2154
2585
  (sp) => sp?.type === "ImportSpecifier" && (sp.imported?.name === "withJsxLoc" || sp.imported?.value === "withJsxLoc")
2155
2586
  );
2156
2587
  if (has) return { changed: false };
2157
- const spec = parseModule3('import { withJsxLoc } from "jsx-loc-plugin";').$ast.body?.[0]?.specifiers?.[0];
2588
+ const spec = parseModule4('import { withJsxLoc } from "jsx-loc-plugin";').$ast.body?.[0]?.specifiers?.[0];
2158
2589
  if (!spec) return { changed: false };
2159
2590
  existing.specifiers = [...existing.specifiers ?? [], spec];
2160
2591
  return { changed: true };
2161
2592
  }
2162
- const importDecl = parseModule3('import { withJsxLoc } from "jsx-loc-plugin";').$ast.body?.[0];
2593
+ const importDecl = parseModule4('import { withJsxLoc } from "jsx-loc-plugin";').$ast.body?.[0];
2163
2594
  if (!importDecl) return { changed: false };
2164
2595
  const body = program.body ?? [];
2165
2596
  let insertAt = 0;
@@ -2182,7 +2613,7 @@ function ensureCjsWithJsxLocRequire(program) {
2182
2613
  return isIdentifier2(p.key, "withJsxLoc");
2183
2614
  });
2184
2615
  if (has) return { changed: false };
2185
- const prop = parseModule3('const { withJsxLoc } = require("jsx-loc-plugin");').$ast.body?.[0]?.declarations?.[0]?.id?.properties?.[0];
2616
+ const prop = parseModule4('const { withJsxLoc } = require("jsx-loc-plugin");').$ast.body?.[0]?.declarations?.[0]?.id?.properties?.[0];
2186
2617
  if (!prop) return { changed: false };
2187
2618
  decl.id.properties = [...decl.id.properties ?? [], prop];
2188
2619
  return { changed: true };
@@ -2191,7 +2622,7 @@ function ensureCjsWithJsxLocRequire(program) {
2191
2622
  }
2192
2623
  }
2193
2624
  }
2194
- const reqDecl = parseModule3('const { withJsxLoc } = require("jsx-loc-plugin");').$ast.body?.[0];
2625
+ const reqDecl = parseModule4('const { withJsxLoc } = require("jsx-loc-plugin");').$ast.body?.[0];
2195
2626
  if (!reqDecl) return { changed: false };
2196
2627
  program.body.unshift(reqDecl);
2197
2628
  return { changed: true };
@@ -2241,10 +2672,10 @@ async function installJsxLocPlugin(opts) {
2241
2672
  return { configFile: null, modified: false };
2242
2673
  }
2243
2674
  const configFilename = getNextConfigFilename(configPath);
2244
- const original = readFileSync6(configPath, "utf-8");
2675
+ const original = readFileSync7(configPath, "utf-8");
2245
2676
  let mod;
2246
2677
  try {
2247
- mod = parseModule3(original);
2678
+ mod = parseModule4(original);
2248
2679
  } catch {
2249
2680
  return { configFile: configFilename, modified: false };
2250
2681
  }
@@ -2271,14 +2702,14 @@ async function installJsxLocPlugin(opts) {
2271
2702
  }
2272
2703
 
2273
2704
  // src/utils/vite-config-inject.ts
2274
- import { existsSync as existsSync7, readFileSync as readFileSync7, writeFileSync as writeFileSync4 } from "fs";
2275
- import { join as join7 } from "path";
2276
- import { parseModule as parseModule4, generateCode as generateCode4 } from "magicast";
2705
+ import { existsSync as existsSync8, readFileSync as readFileSync8, writeFileSync as writeFileSync4 } from "fs";
2706
+ import { join as join8 } from "path";
2707
+ import { parseModule as parseModule5, generateCode as generateCode4 } from "magicast";
2277
2708
  var CONFIG_EXTENSIONS3 = [".ts", ".mjs", ".js", ".cjs"];
2278
2709
  function findViteConfigFile2(projectPath) {
2279
2710
  for (const ext of CONFIG_EXTENSIONS3) {
2280
- const configPath = join7(projectPath, `vite.config${ext}`);
2281
- if (existsSync7(configPath)) return configPath;
2711
+ const configPath = join8(projectPath, `vite.config${ext}`);
2712
+ if (existsSync8(configPath)) return configPath;
2282
2713
  }
2283
2714
  return null;
2284
2715
  }
@@ -2372,12 +2803,12 @@ function ensureEsmJsxLocImport(program) {
2372
2803
  (sp) => sp?.type === "ImportSpecifier" && (sp.imported?.name === "jsxLoc" || sp.imported?.value === "jsxLoc")
2373
2804
  );
2374
2805
  if (has) return { changed: false };
2375
- const spec = parseModule4('import { jsxLoc } from "jsx-loc-plugin/vite";').$ast.body?.[0]?.specifiers?.[0];
2806
+ const spec = parseModule5('import { jsxLoc } from "jsx-loc-plugin/vite";').$ast.body?.[0]?.specifiers?.[0];
2376
2807
  if (!spec) return { changed: false };
2377
2808
  existing.specifiers = [...existing.specifiers ?? [], spec];
2378
2809
  return { changed: true };
2379
2810
  }
2380
- const importDecl = parseModule4('import { jsxLoc } from "jsx-loc-plugin/vite";').$ast.body?.[0];
2811
+ const importDecl = parseModule5('import { jsxLoc } from "jsx-loc-plugin/vite";').$ast.body?.[0];
2381
2812
  if (!importDecl) return { changed: false };
2382
2813
  const body = program.body ?? [];
2383
2814
  let insertAt = 0;
@@ -2400,7 +2831,7 @@ function ensureCjsJsxLocRequire(program) {
2400
2831
  return isIdentifier3(p.key, "jsxLoc");
2401
2832
  });
2402
2833
  if (has) return { changed: false };
2403
- const prop = parseModule4('const { jsxLoc } = require("jsx-loc-plugin/vite");').$ast.body?.[0]?.declarations?.[0]?.id?.properties?.[0];
2834
+ const prop = parseModule5('const { jsxLoc } = require("jsx-loc-plugin/vite");').$ast.body?.[0]?.declarations?.[0]?.id?.properties?.[0];
2404
2835
  if (!prop) return { changed: false };
2405
2836
  decl.id.properties = [...decl.id.properties ?? [], prop];
2406
2837
  return { changed: true };
@@ -2409,7 +2840,7 @@ function ensureCjsJsxLocRequire(program) {
2409
2840
  }
2410
2841
  }
2411
2842
  }
2412
- const reqDecl = parseModule4('const { jsxLoc } = require("jsx-loc-plugin/vite");').$ast.body?.[0];
2843
+ const reqDecl = parseModule5('const { jsxLoc } = require("jsx-loc-plugin/vite");').$ast.body?.[0];
2413
2844
  if (!reqDecl) return { changed: false };
2414
2845
  program.body.unshift(reqDecl);
2415
2846
  return { changed: true };
@@ -2426,7 +2857,7 @@ function pluginsHasJsxLoc(arr) {
2426
2857
  function ensurePluginsContainsJsxLoc(configObj) {
2427
2858
  const pluginsProp = getObjectProperty(configObj, "plugins");
2428
2859
  if (!pluginsProp) {
2429
- const prop = parseModule4("export default { plugins: [jsxLoc()] };").$ast.body?.find((s) => s.type === "ExportDefaultDeclaration")?.declaration?.properties?.find((p) => {
2860
+ const prop = parseModule5("export default { plugins: [jsxLoc()] };").$ast.body?.find((s) => s.type === "ExportDefaultDeclaration")?.declaration?.properties?.find((p) => {
2430
2861
  const k = p?.key;
2431
2862
  return k?.type === "Identifier" && k.name === "plugins" || isStringLiteral3(k) && k.value === "plugins";
2432
2863
  });
@@ -2438,12 +2869,12 @@ function ensurePluginsContainsJsxLoc(configObj) {
2438
2869
  if (!value) return { changed: false };
2439
2870
  if (value.type === "ArrayExpression") {
2440
2871
  if (pluginsHasJsxLoc(value)) return { changed: false };
2441
- const jsxLocCall2 = parseModule4("const __x = jsxLoc();").$ast.body?.[0]?.declarations?.[0]?.init;
2872
+ const jsxLocCall2 = parseModule5("const __x = jsxLoc();").$ast.body?.[0]?.declarations?.[0]?.init;
2442
2873
  if (!jsxLocCall2) return { changed: false };
2443
2874
  value.elements.push(jsxLocCall2);
2444
2875
  return { changed: true };
2445
2876
  }
2446
- const jsxLocCall = parseModule4("const __x = jsxLoc();").$ast.body?.[0]?.declarations?.[0]?.init;
2877
+ const jsxLocCall = parseModule5("const __x = jsxLoc();").$ast.body?.[0]?.declarations?.[0]?.init;
2447
2878
  if (!jsxLocCall) return { changed: false };
2448
2879
  const spread = { type: "SpreadElement", argument: value };
2449
2880
  pluginsProp.value = { type: "ArrayExpression", elements: [spread, jsxLocCall] };
@@ -2453,11 +2884,11 @@ async function installViteJsxLocPlugin(opts) {
2453
2884
  const configPath = findViteConfigFile2(opts.projectPath);
2454
2885
  if (!configPath) return { configFile: null, modified: false };
2455
2886
  const configFilename = getViteConfigFilename(configPath);
2456
- const original = readFileSync7(configPath, "utf-8");
2887
+ const original = readFileSync8(configPath, "utf-8");
2457
2888
  const isCjs = configPath.endsWith(".cjs");
2458
2889
  let mod;
2459
2890
  try {
2460
- mod = parseModule4(original);
2891
+ mod = parseModule5(original);
2461
2892
  } catch {
2462
2893
  return { configFile: configFilename, modified: false };
2463
2894
  }
@@ -2482,9 +2913,9 @@ async function installViteJsxLocPlugin(opts) {
2482
2913
  }
2483
2914
 
2484
2915
  // src/utils/next-routes.ts
2485
- import { existsSync as existsSync8 } from "fs";
2916
+ import { existsSync as existsSync9 } from "fs";
2486
2917
  import { mkdir, writeFile } from "fs/promises";
2487
- import { join as join8 } from "path";
2918
+ import { join as join9 } from "path";
2488
2919
  var DEV_SOURCE_ROUTE_TS = `/**
2489
2920
  * Dev-only API route for fetching source files
2490
2921
  *
@@ -2940,40 +3371,40 @@ export async function GET(request: NextRequest) {
2940
3371
  }
2941
3372
  `;
2942
3373
  async function writeRouteFile(absPath, relPath, content, opts) {
2943
- if (existsSync8(absPath) && !opts.force) return;
3374
+ if (existsSync9(absPath) && !opts.force) return;
2944
3375
  await writeFile(absPath, content, "utf-8");
2945
3376
  }
2946
3377
  async function installNextUILintRoutes(opts) {
2947
- const baseRel = join8(opts.appRoot, "api", ".uilint");
2948
- const baseAbs = join8(opts.projectPath, baseRel);
2949
- await mkdir(join8(baseAbs, "source"), { recursive: true });
3378
+ const baseRel = join9(opts.appRoot, "api", ".uilint");
3379
+ const baseAbs = join9(opts.projectPath, baseRel);
3380
+ await mkdir(join9(baseAbs, "source"), { recursive: true });
2950
3381
  await writeRouteFile(
2951
- join8(baseAbs, "source", "route.ts"),
2952
- join8(baseRel, "source", "route.ts"),
3382
+ join9(baseAbs, "source", "route.ts"),
3383
+ join9(baseRel, "source", "route.ts"),
2953
3384
  DEV_SOURCE_ROUTE_TS,
2954
3385
  opts
2955
3386
  );
2956
- await mkdir(join8(baseAbs, "screenshots"), { recursive: true });
3387
+ await mkdir(join9(baseAbs, "screenshots"), { recursive: true });
2957
3388
  await writeRouteFile(
2958
- join8(baseAbs, "screenshots", "route.ts"),
2959
- join8(baseRel, "screenshots", "route.ts"),
3389
+ join9(baseAbs, "screenshots", "route.ts"),
3390
+ join9(baseRel, "screenshots", "route.ts"),
2960
3391
  SCREENSHOT_ROUTE_TS,
2961
3392
  opts
2962
3393
  );
2963
3394
  }
2964
3395
 
2965
3396
  // src/utils/prettier.ts
2966
- import { existsSync as existsSync9 } from "fs";
3397
+ import { existsSync as existsSync10 } from "fs";
2967
3398
  import { spawn } from "child_process";
2968
- import { join as join9, dirname as dirname3 } from "path";
3399
+ import { join as join10, dirname as dirname4 } from "path";
2969
3400
  function getPrettierPath(projectPath) {
2970
- const localPath = join9(projectPath, "node_modules", ".bin", "prettier");
2971
- if (existsSync9(localPath)) return localPath;
3401
+ const localPath = join10(projectPath, "node_modules", ".bin", "prettier");
3402
+ if (existsSync10(localPath)) return localPath;
2972
3403
  let dir = projectPath;
2973
3404
  for (let i = 0; i < 10; i++) {
2974
- const binPath = join9(dir, "node_modules", ".bin", "prettier");
2975
- if (existsSync9(binPath)) return binPath;
2976
- const parent = dirname3(dir);
3405
+ const binPath = join10(dir, "node_modules", ".bin", "prettier");
3406
+ if (existsSync10(binPath)) return binPath;
3407
+ const parent = dirname4(dir);
2977
3408
  if (parent === dir) break;
2978
3409
  dir = parent;
2979
3410
  }
@@ -3114,7 +3545,7 @@ async function executeAction(action, options) {
3114
3545
  wouldDo: `Create directory: ${action.path}`
3115
3546
  };
3116
3547
  }
3117
- if (!existsSync10(action.path)) {
3548
+ if (!existsSync11(action.path)) {
3118
3549
  mkdirSync(action.path, { recursive: true });
3119
3550
  }
3120
3551
  return { action, success: true };
@@ -3127,8 +3558,8 @@ async function executeAction(action, options) {
3127
3558
  wouldDo: `Create file: ${action.path}${action.permissions ? ` (mode: ${action.permissions.toString(8)})` : ""}`
3128
3559
  };
3129
3560
  }
3130
- const dir = dirname4(action.path);
3131
- if (!existsSync10(dir)) {
3561
+ const dir = dirname5(action.path);
3562
+ if (!existsSync11(dir)) {
3132
3563
  mkdirSync(dir, { recursive: true });
3133
3564
  }
3134
3565
  writeFileSync5(action.path, action.content, "utf-8");
@@ -3146,15 +3577,15 @@ async function executeAction(action, options) {
3146
3577
  };
3147
3578
  }
3148
3579
  let existing = {};
3149
- if (existsSync10(action.path)) {
3580
+ if (existsSync11(action.path)) {
3150
3581
  try {
3151
- existing = JSON.parse(readFileSync8(action.path, "utf-8"));
3582
+ existing = JSON.parse(readFileSync9(action.path, "utf-8"));
3152
3583
  } catch {
3153
3584
  }
3154
3585
  }
3155
3586
  const merged = deepMerge(existing, action.merge);
3156
- const dir = dirname4(action.path);
3157
- if (!existsSync10(dir)) {
3587
+ const dir = dirname5(action.path);
3588
+ if (!existsSync11(dir)) {
3158
3589
  mkdirSync(dir, { recursive: true });
3159
3590
  }
3160
3591
  writeFileSync5(action.path, JSON.stringify(merged, null, 2), "utf-8");
@@ -3168,7 +3599,7 @@ async function executeAction(action, options) {
3168
3599
  wouldDo: `Delete file: ${action.path}`
3169
3600
  };
3170
3601
  }
3171
- if (existsSync10(action.path)) {
3602
+ if (existsSync11(action.path)) {
3172
3603
  unlinkSync(action.path);
3173
3604
  }
3174
3605
  return { action, success: true };
@@ -3181,8 +3612,8 @@ async function executeAction(action, options) {
3181
3612
  wouldDo: `Append to file: ${action.path}`
3182
3613
  };
3183
3614
  }
3184
- if (existsSync10(action.path)) {
3185
- const content = readFileSync8(action.path, "utf-8");
3615
+ if (existsSync11(action.path)) {
3616
+ const content = readFileSync9(action.path, "utf-8");
3186
3617
  if (action.ifNotContains && content.includes(action.ifNotContains)) {
3187
3618
  return { action, success: true };
3188
3619
  }
@@ -3549,7 +3980,7 @@ async function execute(plan, options = {}) {
3549
3980
  import { ruleRegistry as ruleRegistry3 } from "uilint-eslint";
3550
3981
 
3551
3982
  // src/commands/install/installers/genstyleguide.ts
3552
- import { join as join10 } from "path";
3983
+ import { join as join11 } from "path";
3553
3984
  var genstyleguideInstaller = {
3554
3985
  id: "genstyleguide",
3555
3986
  name: "/genstyleguide command",
@@ -3559,7 +3990,7 @@ var genstyleguideInstaller = {
3559
3990
  return true;
3560
3991
  },
3561
3992
  getTargets(project) {
3562
- const commandPath = join10(project.cursorDir.path, "commands", "genstyleguide.md");
3993
+ const commandPath = join11(project.cursorDir.path, "commands", "genstyleguide.md");
3563
3994
  const isInstalled = project.commands.genstyleguide;
3564
3995
  return [
3565
3996
  {
@@ -3572,7 +4003,7 @@ var genstyleguideInstaller = {
3572
4003
  },
3573
4004
  plan(targets, config, project) {
3574
4005
  const actions = [];
3575
- const commandsDir = join10(project.cursorDir.path, "commands");
4006
+ const commandsDir = join11(project.cursorDir.path, "commands");
3576
4007
  if (!project.cursorDir.exists) {
3577
4008
  actions.push({
3578
4009
  type: "create_directory",
@@ -3585,7 +4016,7 @@ var genstyleguideInstaller = {
3585
4016
  });
3586
4017
  actions.push({
3587
4018
  type: "create_file",
3588
- path: join10(commandsDir, "genstyleguide.md"),
4019
+ path: join11(commandsDir, "genstyleguide.md"),
3589
4020
  content: GENSTYLEGUIDE_COMMAND_MD
3590
4021
  });
3591
4022
  return {
@@ -3615,8 +4046,8 @@ var genstyleguideInstaller = {
3615
4046
  };
3616
4047
 
3617
4048
  // src/commands/install/installers/skill.ts
3618
- import { existsSync as existsSync11 } from "fs";
3619
- import { join as join11 } from "path";
4049
+ import { existsSync as existsSync12 } from "fs";
4050
+ import { join as join12 } from "path";
3620
4051
  var skillInstaller = {
3621
4052
  id: "skill",
3622
4053
  name: "UI Consistency Agent skill",
@@ -3626,9 +4057,9 @@ var skillInstaller = {
3626
4057
  return true;
3627
4058
  },
3628
4059
  getTargets(project) {
3629
- const skillsDir = join11(project.cursorDir.path, "skills", "ui-consistency-enforcer");
3630
- const skillMdPath = join11(skillsDir, "SKILL.md");
3631
- const isInstalled = existsSync11(skillMdPath);
4060
+ const skillsDir = join12(project.cursorDir.path, "skills", "ui-consistency-enforcer");
4061
+ const skillMdPath = join12(skillsDir, "SKILL.md");
4062
+ const isInstalled = existsSync12(skillMdPath);
3632
4063
  return [
3633
4064
  {
3634
4065
  id: "ui-consistency-skill",
@@ -3647,21 +4078,21 @@ var skillInstaller = {
3647
4078
  path: project.cursorDir.path
3648
4079
  });
3649
4080
  }
3650
- const skillsDir = join11(project.cursorDir.path, "skills");
4081
+ const skillsDir = join12(project.cursorDir.path, "skills");
3651
4082
  actions.push({
3652
4083
  type: "create_directory",
3653
4084
  path: skillsDir
3654
4085
  });
3655
4086
  try {
3656
4087
  const skill = loadSkill("ui-consistency-enforcer");
3657
- const skillDir = join11(skillsDir, skill.name);
4088
+ const skillDir = join12(skillsDir, skill.name);
3658
4089
  actions.push({
3659
4090
  type: "create_directory",
3660
4091
  path: skillDir
3661
4092
  });
3662
4093
  for (const file of skill.files) {
3663
- const filePath = join11(skillDir, file.relativePath);
3664
- const fileDir = join11(
4094
+ const filePath = join12(skillDir, file.relativePath);
4095
+ const fileDir = join12(
3665
4096
  skillDir,
3666
4097
  file.relativePath.split("/").slice(0, -1).join("/")
3667
4098
  );
@@ -3718,7 +4149,7 @@ var skillInstaller = {
3718
4149
  };
3719
4150
 
3720
4151
  // src/commands/install/installers/eslint.ts
3721
- import { join as join12 } from "path";
4152
+ import { join as join13 } from "path";
3722
4153
  import { ruleRegistry as ruleRegistry2, getRulesByCategory as getRulesByCategory2 } from "uilint-eslint";
3723
4154
  function getUpgradeInfo(configuredRuleIds) {
3724
4155
  const configuredSet = new Set(configuredRuleIds);
@@ -3894,7 +4325,7 @@ var eslintInstaller = {
3894
4325
  for (const target of targets) {
3895
4326
  const pkgInfo = project.packages.find((p) => p.path === target.path);
3896
4327
  if (!pkgInfo || !pkgInfo.eslintConfigPath) continue;
3897
- const rulesDir = join12(target.path, ".uilint", "rules");
4328
+ const rulesDir = join13(target.path, ".uilint", "rules");
3898
4329
  actions.push({
3899
4330
  type: "create_directory",
3900
4331
  path: rulesDir
@@ -3912,7 +4343,7 @@ var eslintInstaller = {
3912
4343
  hasExistingRules: pkgInfo.hasUilintRules
3913
4344
  });
3914
4345
  }
3915
- const gitignorePath = join12(project.workspaceRoot, ".gitignore");
4346
+ const gitignorePath = join13(project.workspaceRoot, ".gitignore");
3916
4347
  actions.push({
3917
4348
  type: "append_to_file",
3918
4349
  path: gitignorePath,
@@ -3946,312 +4377,6 @@ var eslintInstaller = {
3946
4377
  }
3947
4378
  };
3948
4379
 
3949
- // src/utils/client-boundary-tracer.ts
3950
- import { existsSync as existsSync12, readFileSync as readFileSync9 } from "fs";
3951
- import { join as join13, dirname as dirname5, relative as relative4 } from "path";
3952
- import { parseModule as parseModule5 } from "magicast";
3953
- function hasUseClientDirective(filePath) {
3954
- try {
3955
- const content = readFileSync9(filePath, "utf-8");
3956
- const mod = parseModule5(content);
3957
- const program = mod.$ast;
3958
- if (!program || program.type !== "Program") return false;
3959
- const directives = program.directives ?? [];
3960
- for (const directive of directives) {
3961
- if (directive?.type === "Directive" && directive.value?.type === "DirectiveLiteral" && directive.value.value === "use client") {
3962
- return true;
3963
- }
3964
- }
3965
- const firstStmt = program.body?.[0];
3966
- if (firstStmt?.type === "ExpressionStatement" && (firstStmt.expression?.type === "StringLiteral" || firstStmt.expression?.type === "Literal") && firstStmt.expression.value === "use client") {
3967
- return true;
3968
- }
3969
- return false;
3970
- } catch {
3971
- return false;
3972
- }
3973
- }
3974
- function extractImports(program) {
3975
- const imports = [];
3976
- if (!program || program.type !== "Program") return imports;
3977
- for (const stmt of program.body ?? []) {
3978
- if (stmt?.type !== "ImportDeclaration") continue;
3979
- const source = stmt.source?.value;
3980
- if (typeof source !== "string") continue;
3981
- if (!source.startsWith(".") && !source.startsWith("@/") && !source.startsWith("~/")) {
3982
- continue;
3983
- }
3984
- const specifiers = [];
3985
- for (const spec of stmt.specifiers ?? []) {
3986
- if (spec.type === "ImportDefaultSpecifier") {
3987
- specifiers.push("default");
3988
- } else if (spec.type === "ImportSpecifier") {
3989
- const name = spec.imported?.name ?? spec.imported?.value;
3990
- if (name) specifiers.push(name);
3991
- } else if (spec.type === "ImportNamespaceSpecifier") {
3992
- specifiers.push("*");
3993
- }
3994
- }
3995
- imports.push({ source, specifiers });
3996
- }
3997
- return imports;
3998
- }
3999
- function resolveImportPath(importSource, fromFile, projectPath) {
4000
- const fromDir = dirname5(fromFile);
4001
- let basePath;
4002
- if (importSource.startsWith("@/")) {
4003
- const withoutAlias = importSource.slice(2);
4004
- const srcPath = join13(projectPath, "src", withoutAlias);
4005
- const rootPath = join13(projectPath, withoutAlias);
4006
- basePath = existsSync12(dirname5(srcPath)) ? srcPath : rootPath;
4007
- } else if (importSource.startsWith("~/")) {
4008
- basePath = join13(projectPath, importSource.slice(2));
4009
- } else if (importSource.startsWith(".")) {
4010
- basePath = join13(fromDir, importSource);
4011
- } else {
4012
- return null;
4013
- }
4014
- const extensions = [".tsx", ".ts", ".jsx", ".js"];
4015
- for (const ext of extensions) {
4016
- const fullPath = basePath + ext;
4017
- if (existsSync12(fullPath)) return fullPath;
4018
- }
4019
- for (const ext of extensions) {
4020
- const indexPath = join13(basePath, `index${ext}`);
4021
- if (existsSync12(indexPath)) return indexPath;
4022
- }
4023
- if (existsSync12(basePath)) return basePath;
4024
- return null;
4025
- }
4026
- function findLayoutFile2(projectPath, appRoot) {
4027
- const extensions = [".tsx", ".jsx", ".ts", ".js"];
4028
- for (const ext of extensions) {
4029
- const layoutPath = join13(projectPath, appRoot, `layout${ext}`);
4030
- if (existsSync12(layoutPath)) return layoutPath;
4031
- }
4032
- return null;
4033
- }
4034
- function traceClientBoundaries(projectPath, appRoot) {
4035
- const layoutFile = findLayoutFile2(projectPath, appRoot);
4036
- if (!layoutFile) {
4037
- return null;
4038
- }
4039
- const layoutIsClient = hasUseClientDirective(layoutFile);
4040
- const layoutRelative = relative4(projectPath, layoutFile);
4041
- if (layoutIsClient) {
4042
- return {
4043
- layoutIsClient: true,
4044
- clientBoundaries: [],
4045
- layoutFile,
4046
- layoutRelative
4047
- };
4048
- }
4049
- let program;
4050
- try {
4051
- const content = readFileSync9(layoutFile, "utf-8");
4052
- const mod = parseModule5(content);
4053
- program = mod.$ast;
4054
- } catch {
4055
- return {
4056
- layoutIsClient: false,
4057
- clientBoundaries: [],
4058
- layoutFile,
4059
- layoutRelative
4060
- };
4061
- }
4062
- const imports = extractImports(program);
4063
- const clientBoundaries = [];
4064
- for (const imp of imports) {
4065
- const resolvedPath = resolveImportPath(imp.source, layoutFile, projectPath);
4066
- if (!resolvedPath) continue;
4067
- if (hasUseClientDirective(resolvedPath)) {
4068
- clientBoundaries.push({
4069
- filePath: resolvedPath,
4070
- relativePath: relative4(projectPath, resolvedPath),
4071
- componentNames: imp.specifiers,
4072
- importSource: imp.source
4073
- });
4074
- }
4075
- }
4076
- return {
4077
- layoutIsClient: false,
4078
- clientBoundaries,
4079
- layoutFile,
4080
- layoutRelative
4081
- };
4082
- }
4083
- function providersFileExists(projectPath, appRoot) {
4084
- const extensions = [".tsx", ".jsx", ".ts", ".js"];
4085
- const names = ["providers", "Providers"];
4086
- for (const name of names) {
4087
- for (const ext of extensions) {
4088
- const providersPath = join13(projectPath, appRoot, `${name}${ext}`);
4089
- if (existsSync12(providersPath)) return providersPath;
4090
- }
4091
- }
4092
- return null;
4093
- }
4094
-
4095
- // src/commands/install/installers/next-overlay.ts
4096
- var nextOverlayInstaller = {
4097
- id: "next",
4098
- name: "Next.js overlay",
4099
- description: "Alt+Click UI inspector for Next.js App Router",
4100
- icon: "\u{1F537}",
4101
- isApplicable(project) {
4102
- return project.nextApps.length > 0;
4103
- },
4104
- getTargets(project) {
4105
- const targets = [];
4106
- for (const app of project.nextApps) {
4107
- const traceResult = traceClientBoundaries(
4108
- app.projectPath,
4109
- app.detection.appRoot
4110
- );
4111
- if (!traceResult) {
4112
- targets.push({
4113
- id: `next-${app.projectPath}`,
4114
- label: app.projectPath.split("/").pop() || app.projectPath,
4115
- path: app.projectPath,
4116
- hint: "App Router (no layout found)",
4117
- isInstalled: false
4118
- });
4119
- continue;
4120
- }
4121
- if (traceResult.layoutIsClient) {
4122
- targets.push({
4123
- id: `next-${app.projectPath}`,
4124
- label: app.projectPath.split("/").pop() || app.projectPath,
4125
- path: app.projectPath,
4126
- hint: "App Router",
4127
- isInstalled: false,
4128
- targetFile: traceResult.layoutFile
4129
- });
4130
- continue;
4131
- }
4132
- const existingProviders = providersFileExists(
4133
- app.projectPath,
4134
- app.detection.appRoot
4135
- );
4136
- if (!existingProviders) {
4137
- targets.push({
4138
- id: `next-${app.projectPath}-create-providers`,
4139
- label: `${app.projectPath.split("/").pop() || app.projectPath}`,
4140
- path: app.projectPath,
4141
- hint: "Create providers.tsx (Recommended)",
4142
- isInstalled: false,
4143
- createProviders: true
4144
- });
4145
- }
4146
- for (const boundary of traceResult.clientBoundaries) {
4147
- const componentNames = boundary.componentNames.length > 0 ? boundary.componentNames.join(", ") : "default";
4148
- targets.push({
4149
- id: `next-${app.projectPath}-${boundary.relativePath}`,
4150
- label: `${app.projectPath.split("/").pop() || app.projectPath}`,
4151
- path: app.projectPath,
4152
- hint: `${boundary.relativePath} (${componentNames})`,
4153
- isInstalled: false,
4154
- targetFile: boundary.filePath
4155
- });
4156
- }
4157
- if (existingProviders) {
4158
- const relativePath = existingProviders.replace(app.projectPath + "/", "").replace(app.projectPath, "");
4159
- const alreadyListed = traceResult.clientBoundaries.some(
4160
- (b) => b.filePath === existingProviders
4161
- );
4162
- if (!alreadyListed) {
4163
- targets.push({
4164
- id: `next-${app.projectPath}-existing-providers`,
4165
- label: `${app.projectPath.split("/").pop() || app.projectPath}`,
4166
- path: app.projectPath,
4167
- hint: `${relativePath} (existing)`,
4168
- isInstalled: false,
4169
- targetFile: existingProviders
4170
- });
4171
- }
4172
- }
4173
- if (targets.filter((t) => t.path === app.projectPath).length === 0) {
4174
- targets.push({
4175
- id: `next-${app.projectPath}-create-providers`,
4176
- label: `${app.projectPath.split("/").pop() || app.projectPath}`,
4177
- path: app.projectPath,
4178
- hint: "Create providers.tsx",
4179
- isInstalled: false,
4180
- createProviders: true
4181
- });
4182
- }
4183
- }
4184
- return targets;
4185
- },
4186
- plan(targets, config, project) {
4187
- const actions = [];
4188
- const dependencies = [];
4189
- if (targets.length === 0) return { actions, dependencies };
4190
- const target = targets[0];
4191
- const appInfo = project.nextApps.find(
4192
- (app) => app.projectPath === target.path
4193
- );
4194
- if (!appInfo) return { actions, dependencies };
4195
- const { projectPath, detection } = appInfo;
4196
- actions.push({
4197
- type: "install_next_routes",
4198
- projectPath,
4199
- appRoot: detection.appRoot
4200
- });
4201
- dependencies.push({
4202
- packagePath: projectPath,
4203
- packageManager: project.packageManager,
4204
- packages: ["uilint-react", "uilint-core", "jsx-loc-plugin"]
4205
- });
4206
- actions.push({
4207
- type: "inject_react",
4208
- projectPath,
4209
- appRoot: detection.appRoot,
4210
- mode: "next",
4211
- targetFile: target.targetFile,
4212
- createProviders: target.createProviders
4213
- });
4214
- actions.push({
4215
- type: "inject_next_config",
4216
- projectPath
4217
- });
4218
- return { actions, dependencies };
4219
- },
4220
- async *execute(targets, config, project) {
4221
- if (targets.length === 0) return;
4222
- const target = targets[0];
4223
- yield {
4224
- type: "start",
4225
- message: "Installing Next.js overlay"
4226
- };
4227
- yield {
4228
- type: "progress",
4229
- message: `Installing in ${target.label}`,
4230
- detail: "\u2192 Adding API routes"
4231
- };
4232
- yield {
4233
- type: "progress",
4234
- message: "Installing dependencies",
4235
- detail: "\u2192 uilint-react, uilint-core, jsx-loc-plugin"
4236
- };
4237
- const injectDetail = target.createProviders ? "\u2192 Creating providers.tsx" : target.targetFile ? `\u2192 ${target.hint || "client component"}` : "\u2192 <uilint-devtools /> in root layout";
4238
- yield {
4239
- type: "progress",
4240
- message: "Injecting devtools component",
4241
- detail: injectDetail
4242
- };
4243
- yield {
4244
- type: "progress",
4245
- message: "Configuring jsx-loc-plugin",
4246
- detail: "\u2192 next.config.js"
4247
- };
4248
- yield {
4249
- type: "complete",
4250
- message: "Next.js overlay installed"
4251
- };
4252
- }
4253
- };
4254
-
4255
4380
  // src/commands/install/installers/vite-overlay.ts
4256
4381
  var viteOverlayInstaller = {
4257
4382
  id: "vite",
@@ -4338,8 +4463,8 @@ registerInstaller(nextOverlayInstaller);
4338
4463
  registerInstaller(viteOverlayInstaller);
4339
4464
 
4340
4465
  // src/commands/install-ui.tsx
4341
- import { jsx as jsx6 } from "react/jsx-runtime";
4342
- function selectionsToUserChoices(selections, project, eslintRules) {
4466
+ import { jsx as jsx7 } from "react/jsx-runtime";
4467
+ function selectionsToUserChoices(selections, project, eslintRules, injectionPointConfig) {
4343
4468
  const items = [];
4344
4469
  const choices = { items };
4345
4470
  for (const selection of selections) {
@@ -4371,9 +4496,9 @@ function selectionsToUserChoices(selections, project, eslintRules) {
4371
4496
  choices.next = {
4372
4497
  projectPath: appInfo.projectPath,
4373
4498
  detection: appInfo.detection,
4374
- // Pass through targetFile and createProviders from the selected target
4375
- targetFile: target?.targetFile,
4376
- createProviders: target?.createProviders
4499
+ // Use injection point from follow-up UI selection
4500
+ targetFile: injectionPointConfig?.targetFile,
4501
+ createProviders: injectionPointConfig?.createProviders
4377
4502
  };
4378
4503
  }
4379
4504
  } else if (installer.id === "vite") {
@@ -4404,18 +4529,18 @@ async function installUI(options = {}, executeOptions = {}) {
4404
4529
  }
4405
4530
  const projectPromise = analyze(projectPath);
4406
4531
  const { waitUntilExit } = render(
4407
- /* @__PURE__ */ jsx6(
4532
+ /* @__PURE__ */ jsx7(
4408
4533
  InstallApp,
4409
4534
  {
4410
4535
  projectPromise,
4411
- onComplete: async (selections, eslintRules) => {
4536
+ onComplete: async (selections, eslintRules, injectionPointConfig) => {
4412
4537
  const project = await projectPromise;
4413
- const choices = selectionsToUserChoices(selections, project, eslintRules);
4538
+ const choices = selectionsToUserChoices(selections, project, eslintRules, injectionPointConfig);
4414
4539
  if (choices.items.length === 0) {
4415
4540
  console.log("\nNo items selected for installation");
4416
4541
  process.exit(0);
4417
4542
  }
4418
- const { createPlan } = await import("./plan-2YRYL4YC.js");
4543
+ const { createPlan } = await import("./plan-SIXVCXCK.js");
4419
4544
  const plan = createPlan(project, choices, { force: options.force });
4420
4545
  const result = await execute(plan, {
4421
4546
  ...executeOptions,
@@ -4440,4 +4565,4 @@ async function installUI(options = {}, executeOptions = {}) {
4440
4565
  export {
4441
4566
  installUI
4442
4567
  };
4443
- //# sourceMappingURL=install-ui-VNIKF2YT.js.map
4568
+ //# sourceMappingURL=install-ui-FE5AA75P.js.map