uilint 0.2.13 → 0.2.14

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.
@@ -7,13 +7,14 @@ import {
7
7
  multiselect,
8
8
  note,
9
9
  pc,
10
- printBox,
11
10
  select
12
- } from "./chunk-EYCSOCU4.js";
11
+ } from "./chunk-FRNXXIEM.js";
13
12
  import {
14
13
  GENSTYLEGUIDE_COMMAND_MD,
14
+ detectPackageManager,
15
+ installDependencies,
15
16
  loadSkill
16
- } from "./chunk-2RNDQVEK.js";
17
+ } from "./chunk-PBEKMDUH.js";
17
18
 
18
19
  // src/commands/install-ui.tsx
19
20
  import { render } from "ink";
@@ -141,6 +142,9 @@ function StatusIndicator({ status, isSelected }) {
141
142
  if (status === "installed") {
142
143
  return /* @__PURE__ */ jsx3(Text3, { color: "green", children: "\u2713" });
143
144
  }
145
+ if (status === "upgradeable") {
146
+ return isSelected ? /* @__PURE__ */ jsx3(Text3, { color: "blue", children: "\u2B06" }) : /* @__PURE__ */ jsx3(Text3, { color: "green", children: "\u2713" });
147
+ }
144
148
  if (isSelected || status === "selected") {
145
149
  return /* @__PURE__ */ jsx3(Text3, { color: "cyan", children: "\u25C9" });
146
150
  }
@@ -153,6 +157,9 @@ function StatusLabel({ status }) {
153
157
  if (status === "installed") {
154
158
  return /* @__PURE__ */ jsx3(Text3, { color: "green", dimColor: true, children: "installed" });
155
159
  }
160
+ if (status === "upgradeable") {
161
+ return /* @__PURE__ */ jsx3(Text3, { color: "blue", dimColor: true, children: "upgrade available" });
162
+ }
156
163
  if (status === "partial") {
157
164
  return /* @__PURE__ */ jsx3(Text3, { color: "yellow", dimColor: true, children: "partial" });
158
165
  }
@@ -178,7 +185,8 @@ function ConfigSelector({
178
185
  const flatItems = items;
179
186
  const handleToggle = useCallback(() => {
180
187
  const item = flatItems[cursor];
181
- if (!item || item.disabled || item.status === "installed") return;
188
+ const canToggle = item && !item.disabled && item.status !== "installed";
189
+ if (!canToggle) return;
182
190
  setSelected((prev) => {
183
191
  const next = new Set(prev);
184
192
  if (next.has(item.id)) {
@@ -519,6 +527,15 @@ function getAllInstallers() {
519
527
 
520
528
  // src/commands/install/components/InstallApp.tsx
521
529
  import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
530
+ function getTargetStatus(target) {
531
+ if (!target.isInstalled) {
532
+ return "not_installed";
533
+ }
534
+ if (target.canUpgrade) {
535
+ return "upgradeable";
536
+ }
537
+ return "installed";
538
+ }
522
539
  function buildConfigItemsForProject(project, selectedProject, selections) {
523
540
  const items = [];
524
541
  for (const selection of selections) {
@@ -546,7 +563,7 @@ function buildConfigItemsForProject(project, selectedProject, selections) {
546
563
  id: `${installer.id}:${target.id}`,
547
564
  label: installer.name,
548
565
  hint: target.hint,
549
- status: target.isInstalled ? "installed" : "not_installed",
566
+ status: getTargetStatus(target),
550
567
  category: info.category,
551
568
  categoryIcon: info.icon
552
569
  });
@@ -571,7 +588,7 @@ function buildGlobalConfigItems(selections) {
571
588
  id: `${installer.id}:${target.id}`,
572
589
  label: installer.name,
573
590
  hint: target.hint,
574
- status: target.isInstalled ? "installed" : "not_installed",
591
+ status: getTargetStatus(target),
575
592
  category: info.category,
576
593
  categoryIcon: info.icon
577
594
  });
@@ -653,11 +670,13 @@ function InstallApp({
653
670
  const installers2 = getAllInstallers();
654
671
  const initialSelections = installers2.filter((installer) => installer.isApplicable(proj)).map((installer) => {
655
672
  const targets = installer.getTargets(proj);
656
- const nonInstalledTargets = targets.filter((t) => !t.isInstalled);
673
+ const actionableTargets = targets.filter(
674
+ (t) => !t.isInstalled || t.canUpgrade
675
+ );
657
676
  return {
658
677
  installer,
659
678
  targets,
660
- selected: nonInstalledTargets.length > 0
679
+ selected: actionableTargets.length > 0
661
680
  };
662
681
  });
663
682
  setSelections(initialSelections);
@@ -798,8 +817,8 @@ function InstallApp({
798
817
  }
799
818
 
800
819
  // src/commands/install/analyze.ts
801
- import { existsSync as existsSync5, readFileSync as readFileSync4 } from "fs";
802
- import { join as join5 } from "path";
820
+ import { existsSync as existsSync4, readFileSync as readFileSync4 } from "fs";
821
+ import { join as join4 } from "path";
803
822
  import { findWorkspaceRoot as findWorkspaceRoot2 } from "uilint-core/node";
804
823
 
805
824
  // src/utils/vite-detect.ts
@@ -1043,86 +1062,16 @@ function findPackages(rootDir, options) {
1043
1062
  });
1044
1063
  }
1045
1064
 
1046
- // src/utils/package-manager.ts
1047
- import { existsSync as existsSync3 } from "fs";
1048
- import { spawn } from "child_process";
1049
- import { dirname, join as join3 } from "path";
1050
- function detectExecutionPackageManager() {
1051
- const userAgent = process.env.npm_config_user_agent;
1052
- if (userAgent) {
1053
- if (userAgent.startsWith("pnpm/")) return "pnpm";
1054
- if (userAgent.startsWith("yarn/")) return "yarn";
1055
- if (userAgent.startsWith("bun/")) return "bun";
1056
- if (userAgent.startsWith("npm/")) return "npm";
1057
- }
1058
- const execPath = process.env.npm_execpath;
1059
- if (execPath) {
1060
- if (execPath.includes("pnpm")) return "pnpm";
1061
- if (execPath.includes("yarn")) return "yarn";
1062
- if (execPath.includes("bun")) return "bun";
1063
- if (execPath.includes("npm")) return "npm";
1064
- }
1065
- return null;
1066
- }
1067
- function detectPackageManager(projectPath) {
1068
- let dir = projectPath;
1069
- for (; ; ) {
1070
- if (existsSync3(join3(dir, "pnpm-lock.yaml"))) return "pnpm";
1071
- if (existsSync3(join3(dir, "pnpm-workspace.yaml"))) return "pnpm";
1072
- if (existsSync3(join3(dir, "yarn.lock"))) return "yarn";
1073
- if (existsSync3(join3(dir, "bun.lockb"))) return "bun";
1074
- if (existsSync3(join3(dir, "bun.lock"))) return "bun";
1075
- if (existsSync3(join3(dir, "package-lock.json"))) return "npm";
1076
- const parent = dirname(dir);
1077
- if (parent === dir) break;
1078
- dir = parent;
1079
- }
1080
- return "npm";
1081
- }
1082
- function spawnAsync(command, args, cwd) {
1083
- return new Promise((resolve, reject) => {
1084
- const child = spawn(command, args, {
1085
- cwd,
1086
- stdio: "inherit",
1087
- shell: process.platform === "win32"
1088
- });
1089
- child.on("error", reject);
1090
- child.on("close", (code) => {
1091
- if (code === 0) resolve();
1092
- else
1093
- reject(new Error(`${command} ${args.join(" ")} exited with ${code}`));
1094
- });
1095
- });
1096
- }
1097
- async function installDependencies(pm, projectPath, packages) {
1098
- if (!packages.length) return;
1099
- switch (pm) {
1100
- case "pnpm":
1101
- await spawnAsync("pnpm", ["add", ...packages], projectPath);
1102
- return;
1103
- case "yarn":
1104
- await spawnAsync("yarn", ["add", ...packages], projectPath);
1105
- return;
1106
- case "bun":
1107
- await spawnAsync("bun", ["add", ...packages], projectPath);
1108
- return;
1109
- case "npm":
1110
- default:
1111
- await spawnAsync("npm", ["install", "--save", ...packages], projectPath);
1112
- return;
1113
- }
1114
- }
1115
-
1116
1065
  // src/utils/eslint-config-inject.ts
1117
- import { existsSync as existsSync4, readFileSync as readFileSync3, writeFileSync } from "fs";
1118
- import { join as join4, relative as relative2, dirname as dirname2 } from "path";
1066
+ import { existsSync as existsSync3, readFileSync as readFileSync3, writeFileSync } from "fs";
1067
+ import { join as join3, relative as relative2, dirname } from "path";
1119
1068
  import { parseExpression, parseModule, generateCode } from "magicast";
1120
1069
  import { findWorkspaceRoot } from "uilint-core/node";
1121
1070
  var CONFIG_EXTENSIONS = [".ts", ".mjs", ".js", ".cjs"];
1122
1071
  function findEslintConfigFile(projectPath) {
1123
1072
  for (const ext of CONFIG_EXTENSIONS) {
1124
- const configPath = join4(projectPath, `eslint.config${ext}`);
1125
- if (existsSync4(configPath)) {
1073
+ const configPath = join3(projectPath, `eslint.config${ext}`);
1074
+ if (existsSync3(configPath)) {
1126
1075
  return configPath;
1127
1076
  }
1128
1077
  }
@@ -1345,8 +1294,8 @@ function chooseUniqueIdentifier(base, used) {
1345
1294
  function addLocalRuleImportsAst(mod, selectedRules, configPath, rulesRoot, fileExtension = ".js") {
1346
1295
  const importNames = /* @__PURE__ */ new Map();
1347
1296
  let changed = false;
1348
- const configDir = dirname2(configPath);
1349
- const rulesDir = join4(rulesRoot, ".uilint", "rules");
1297
+ const configDir = dirname(configPath);
1298
+ const rulesDir = join3(rulesRoot, ".uilint", "rules");
1350
1299
  const relativeRulesPath = relative2(configDir, rulesDir).replace(/\\/g, "/");
1351
1300
  const normalizedRulesPath = relativeRulesPath.startsWith("./") || relativeRulesPath.startsWith("../") ? relativeRulesPath : `./${relativeRulesPath}`;
1352
1301
  const used = collectTopLevelBindings(mod.$ast);
@@ -1373,8 +1322,8 @@ function addLocalRuleRequiresAst(program, selectedRules, configPath, rulesRoot,
1373
1322
  if (!program || program.type !== "Program") {
1374
1323
  return { importNames, changed };
1375
1324
  }
1376
- const configDir = dirname2(configPath);
1377
- const rulesDir = join4(rulesRoot, ".uilint", "rules");
1325
+ const configDir = dirname(configPath);
1326
+ const rulesDir = join3(rulesRoot, ".uilint", "rules");
1378
1327
  const relativeRulesPath = relative2(configDir, rulesDir).replace(/\\/g, "/");
1379
1328
  const normalizedRulesPath = relativeRulesPath.startsWith("./") || relativeRulesPath.startsWith("../") ? relativeRulesPath : `./${relativeRulesPath}`;
1380
1329
  const used = collectTopLevelBindings(program);
@@ -1585,10 +1534,10 @@ async function installEslintPlugin(opts) {
1585
1534
  };
1586
1535
  }
1587
1536
  let modifiedAst = false;
1588
- const localRulesDir = join4(opts.projectPath, ".uilint", "rules");
1537
+ const localRulesDir = join3(opts.projectPath, ".uilint", "rules");
1589
1538
  const workspaceRoot = findWorkspaceRoot(opts.projectPath);
1590
- const workspaceRulesDir = join4(workspaceRoot, ".uilint", "rules");
1591
- const rulesRoot = existsSync4(localRulesDir) ? opts.projectPath : workspaceRoot;
1539
+ const workspaceRulesDir = join3(workspaceRoot, ".uilint", "rules");
1540
+ const rulesRoot = existsSync3(localRulesDir) ? opts.projectPath : workspaceRoot;
1592
1541
  const isTypeScriptConfig = configPath.endsWith(".ts");
1593
1542
  let fileExtension = isTypeScriptConfig ? "" : ".js";
1594
1543
  let ruleImportNames;
@@ -1663,12 +1612,12 @@ async function installEslintPlugin(opts) {
1663
1612
  async function analyze(projectPath = process.cwd()) {
1664
1613
  const workspaceRoot = findWorkspaceRoot2(projectPath);
1665
1614
  const packageManager = detectPackageManager(projectPath);
1666
- const cursorDir = join5(projectPath, ".cursor");
1667
- const cursorDirExists = existsSync5(cursorDir);
1668
- const styleguidePath = join5(projectPath, ".uilint", "styleguide.md");
1669
- const styleguideExists = existsSync5(styleguidePath);
1670
- const commandsDir = join5(cursorDir, "commands");
1671
- const genstyleguideExists = existsSync5(join5(commandsDir, "genstyleguide.md"));
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"));
1672
1621
  const nextApps = [];
1673
1622
  const directDetection = detectNextAppRouter(projectPath);
1674
1623
  if (directDetection) {
@@ -1742,49 +1691,49 @@ async function analyze(projectPath = process.cwd()) {
1742
1691
 
1743
1692
  // src/commands/install/execute.ts
1744
1693
  import {
1745
- existsSync as existsSync11,
1694
+ existsSync as existsSync10,
1746
1695
  mkdirSync,
1747
1696
  writeFileSync as writeFileSync5,
1748
1697
  readFileSync as readFileSync8,
1749
1698
  unlinkSync,
1750
1699
  chmodSync
1751
1700
  } from "fs";
1752
- import { dirname as dirname4 } from "path";
1701
+ import { dirname as dirname3 } from "path";
1753
1702
 
1754
1703
  // src/utils/react-inject.ts
1755
- import { existsSync as existsSync6, readFileSync as readFileSync5, writeFileSync as writeFileSync2 } from "fs";
1756
- import { join as join6 } from "path";
1704
+ import { existsSync as existsSync5, readFileSync as readFileSync5, writeFileSync as writeFileSync2 } from "fs";
1705
+ import { join as join5 } from "path";
1757
1706
  import { parseModule as parseModule2, generateCode as generateCode2 } from "magicast";
1758
1707
  function getDefaultCandidates(projectPath, appRoot) {
1759
1708
  const viteMainCandidates = [
1760
- join6(appRoot, "main.tsx"),
1761
- join6(appRoot, "main.jsx"),
1762
- join6(appRoot, "main.ts"),
1763
- join6(appRoot, "main.js")
1709
+ join5(appRoot, "main.tsx"),
1710
+ join5(appRoot, "main.jsx"),
1711
+ join5(appRoot, "main.ts"),
1712
+ join5(appRoot, "main.js")
1764
1713
  ];
1765
1714
  const existingViteMain = viteMainCandidates.filter(
1766
- (rel) => existsSync6(join6(projectPath, rel))
1715
+ (rel) => existsSync5(join5(projectPath, rel))
1767
1716
  );
1768
1717
  if (existingViteMain.length > 0) return existingViteMain;
1769
- const viteAppCandidates = [join6(appRoot, "App.tsx"), join6(appRoot, "App.jsx")];
1718
+ const viteAppCandidates = [join5(appRoot, "App.tsx"), join5(appRoot, "App.jsx")];
1770
1719
  const existingViteApp = viteAppCandidates.filter(
1771
- (rel) => existsSync6(join6(projectPath, rel))
1720
+ (rel) => existsSync5(join5(projectPath, rel))
1772
1721
  );
1773
1722
  if (existingViteApp.length > 0) return existingViteApp;
1774
1723
  const layoutCandidates = [
1775
- join6(appRoot, "layout.tsx"),
1776
- join6(appRoot, "layout.jsx"),
1777
- join6(appRoot, "layout.ts"),
1778
- join6(appRoot, "layout.js")
1724
+ join5(appRoot, "layout.tsx"),
1725
+ join5(appRoot, "layout.jsx"),
1726
+ join5(appRoot, "layout.ts"),
1727
+ join5(appRoot, "layout.js")
1779
1728
  ];
1780
1729
  const existingLayouts = layoutCandidates.filter(
1781
- (rel) => existsSync6(join6(projectPath, rel))
1730
+ (rel) => existsSync5(join5(projectPath, rel))
1782
1731
  );
1783
1732
  if (existingLayouts.length > 0) {
1784
1733
  return existingLayouts;
1785
1734
  }
1786
- const pageCandidates = [join6(appRoot, "page.tsx"), join6(appRoot, "page.jsx")];
1787
- return pageCandidates.filter((rel) => existsSync6(join6(projectPath, rel)));
1735
+ const pageCandidates = [join5(appRoot, "page.tsx"), join5(appRoot, "page.jsx")];
1736
+ return pageCandidates.filter((rel) => existsSync5(join5(projectPath, rel)));
1788
1737
  }
1789
1738
  function isUseClientDirective(stmt) {
1790
1739
  return stmt?.type === "ExpressionStatement" && stmt.expression?.type === "StringLiteral" && stmt.expression.value === "use client";
@@ -1916,7 +1865,7 @@ async function installReactUILintOverlay(opts) {
1916
1865
  } else {
1917
1866
  chosen = candidates[0];
1918
1867
  }
1919
- const absTarget = join6(opts.projectPath, chosen);
1868
+ const absTarget = join5(opts.projectPath, chosen);
1920
1869
  const original = readFileSync5(absTarget, "utf-8");
1921
1870
  let mod;
1922
1871
  try {
@@ -1949,14 +1898,14 @@ async function installReactUILintOverlay(opts) {
1949
1898
  }
1950
1899
 
1951
1900
  // src/utils/next-config-inject.ts
1952
- import { existsSync as existsSync7, readFileSync as readFileSync6, writeFileSync as writeFileSync3 } from "fs";
1953
- import { join as join7 } from "path";
1901
+ import { existsSync as existsSync6, readFileSync as readFileSync6, writeFileSync as writeFileSync3 } from "fs";
1902
+ import { join as join6 } from "path";
1954
1903
  import { parseModule as parseModule3, generateCode as generateCode3 } from "magicast";
1955
1904
  var CONFIG_EXTENSIONS2 = [".ts", ".mjs", ".js", ".cjs"];
1956
1905
  function findNextConfigFile(projectPath) {
1957
1906
  for (const ext of CONFIG_EXTENSIONS2) {
1958
- const configPath = join7(projectPath, `next.config${ext}`);
1959
- if (existsSync7(configPath)) {
1907
+ const configPath = join6(projectPath, `next.config${ext}`);
1908
+ if (existsSync6(configPath)) {
1960
1909
  return configPath;
1961
1910
  }
1962
1911
  }
@@ -2099,14 +2048,14 @@ async function installJsxLocPlugin(opts) {
2099
2048
  }
2100
2049
 
2101
2050
  // src/utils/vite-config-inject.ts
2102
- import { existsSync as existsSync8, readFileSync as readFileSync7, writeFileSync as writeFileSync4 } from "fs";
2103
- import { join as join8 } from "path";
2051
+ import { existsSync as existsSync7, readFileSync as readFileSync7, writeFileSync as writeFileSync4 } from "fs";
2052
+ import { join as join7 } from "path";
2104
2053
  import { parseModule as parseModule4, generateCode as generateCode4 } from "magicast";
2105
2054
  var CONFIG_EXTENSIONS3 = [".ts", ".mjs", ".js", ".cjs"];
2106
2055
  function findViteConfigFile2(projectPath) {
2107
2056
  for (const ext of CONFIG_EXTENSIONS3) {
2108
- const configPath = join8(projectPath, `vite.config${ext}`);
2109
- if (existsSync8(configPath)) return configPath;
2057
+ const configPath = join7(projectPath, `vite.config${ext}`);
2058
+ if (existsSync7(configPath)) return configPath;
2110
2059
  }
2111
2060
  return null;
2112
2061
  }
@@ -2310,9 +2259,9 @@ async function installViteJsxLocPlugin(opts) {
2310
2259
  }
2311
2260
 
2312
2261
  // src/utils/next-routes.ts
2313
- import { existsSync as existsSync9 } from "fs";
2262
+ import { existsSync as existsSync8 } from "fs";
2314
2263
  import { mkdir, writeFile } from "fs/promises";
2315
- import { join as join9 } from "path";
2264
+ import { join as join8 } from "path";
2316
2265
  var DEV_SOURCE_ROUTE_TS = `/**
2317
2266
  * Dev-only API route for fetching source files
2318
2267
  *
@@ -2768,40 +2717,40 @@ export async function GET(request: NextRequest) {
2768
2717
  }
2769
2718
  `;
2770
2719
  async function writeRouteFile(absPath, relPath, content, opts) {
2771
- if (existsSync9(absPath) && !opts.force) return;
2720
+ if (existsSync8(absPath) && !opts.force) return;
2772
2721
  await writeFile(absPath, content, "utf-8");
2773
2722
  }
2774
2723
  async function installNextUILintRoutes(opts) {
2775
- const baseRel = join9(opts.appRoot, "api", ".uilint");
2776
- const baseAbs = join9(opts.projectPath, baseRel);
2777
- await mkdir(join9(baseAbs, "source"), { recursive: true });
2724
+ const baseRel = join8(opts.appRoot, "api", ".uilint");
2725
+ const baseAbs = join8(opts.projectPath, baseRel);
2726
+ await mkdir(join8(baseAbs, "source"), { recursive: true });
2778
2727
  await writeRouteFile(
2779
- join9(baseAbs, "source", "route.ts"),
2780
- join9(baseRel, "source", "route.ts"),
2728
+ join8(baseAbs, "source", "route.ts"),
2729
+ join8(baseRel, "source", "route.ts"),
2781
2730
  DEV_SOURCE_ROUTE_TS,
2782
2731
  opts
2783
2732
  );
2784
- await mkdir(join9(baseAbs, "screenshots"), { recursive: true });
2733
+ await mkdir(join8(baseAbs, "screenshots"), { recursive: true });
2785
2734
  await writeRouteFile(
2786
- join9(baseAbs, "screenshots", "route.ts"),
2787
- join9(baseRel, "screenshots", "route.ts"),
2735
+ join8(baseAbs, "screenshots", "route.ts"),
2736
+ join8(baseRel, "screenshots", "route.ts"),
2788
2737
  SCREENSHOT_ROUTE_TS,
2789
2738
  opts
2790
2739
  );
2791
2740
  }
2792
2741
 
2793
2742
  // src/utils/prettier.ts
2794
- import { existsSync as existsSync10 } from "fs";
2795
- import { spawn as spawn2 } from "child_process";
2796
- import { join as join10, dirname as dirname3 } from "path";
2743
+ import { existsSync as existsSync9 } from "fs";
2744
+ import { spawn } from "child_process";
2745
+ import { join as join9, dirname as dirname2 } from "path";
2797
2746
  function getPrettierPath(projectPath) {
2798
- const localPath = join10(projectPath, "node_modules", ".bin", "prettier");
2799
- if (existsSync10(localPath)) return localPath;
2747
+ const localPath = join9(projectPath, "node_modules", ".bin", "prettier");
2748
+ if (existsSync9(localPath)) return localPath;
2800
2749
  let dir = projectPath;
2801
2750
  for (let i = 0; i < 10; i++) {
2802
- const binPath = join10(dir, "node_modules", ".bin", "prettier");
2803
- if (existsSync10(binPath)) return binPath;
2804
- const parent = dirname3(dir);
2751
+ const binPath = join9(dir, "node_modules", ".bin", "prettier");
2752
+ if (existsSync9(binPath)) return binPath;
2753
+ const parent = dirname2(dir);
2805
2754
  if (parent === dir) break;
2806
2755
  dir = parent;
2807
2756
  }
@@ -2827,7 +2776,7 @@ async function formatWithPrettier(filePath, projectPath) {
2827
2776
  const runner = getPmRunner(pm);
2828
2777
  return new Promise((resolve) => {
2829
2778
  const args = [...runner.args, "prettier", "--write", filePath];
2830
- const child = spawn2(runner.command, args, {
2779
+ const child = spawn(runner.command, args, {
2831
2780
  cwd: projectPath,
2832
2781
  stdio: "pipe",
2833
2782
  shell: process.platform === "win32"
@@ -2849,7 +2798,7 @@ async function formatWithPrettier(filePath, projectPath) {
2849
2798
  });
2850
2799
  }
2851
2800
  return new Promise((resolve) => {
2852
- const child = spawn2(prettierPath, ["--write", filePath], {
2801
+ const child = spawn(prettierPath, ["--write", filePath], {
2853
2802
  cwd: projectPath,
2854
2803
  stdio: "pipe",
2855
2804
  shell: process.platform === "win32"
@@ -2882,7 +2831,7 @@ async function formatFilesWithPrettier(filePaths, projectPath) {
2882
2831
  const runner = getPmRunner(pm);
2883
2832
  return new Promise((resolve) => {
2884
2833
  const args = [...runner.args, "prettier", "--write", ...filePaths];
2885
- const child = spawn2(runner.command, args, {
2834
+ const child = spawn(runner.command, args, {
2886
2835
  cwd: projectPath,
2887
2836
  stdio: "pipe",
2888
2837
  shell: process.platform === "win32"
@@ -2900,7 +2849,7 @@ async function formatFilesWithPrettier(filePaths, projectPath) {
2900
2849
  });
2901
2850
  }
2902
2851
  return new Promise((resolve) => {
2903
- const child = spawn2(prettierPath, ["--write", ...filePaths], {
2852
+ const child = spawn(prettierPath, ["--write", ...filePaths], {
2904
2853
  cwd: projectPath,
2905
2854
  stdio: "pipe",
2906
2855
  shell: process.platform === "win32"
@@ -2942,7 +2891,7 @@ async function executeAction(action, options) {
2942
2891
  wouldDo: `Create directory: ${action.path}`
2943
2892
  };
2944
2893
  }
2945
- if (!existsSync11(action.path)) {
2894
+ if (!existsSync10(action.path)) {
2946
2895
  mkdirSync(action.path, { recursive: true });
2947
2896
  }
2948
2897
  return { action, success: true };
@@ -2955,8 +2904,8 @@ async function executeAction(action, options) {
2955
2904
  wouldDo: `Create file: ${action.path}${action.permissions ? ` (mode: ${action.permissions.toString(8)})` : ""}`
2956
2905
  };
2957
2906
  }
2958
- const dir = dirname4(action.path);
2959
- if (!existsSync11(dir)) {
2907
+ const dir = dirname3(action.path);
2908
+ if (!existsSync10(dir)) {
2960
2909
  mkdirSync(dir, { recursive: true });
2961
2910
  }
2962
2911
  writeFileSync5(action.path, action.content, "utf-8");
@@ -2974,15 +2923,15 @@ async function executeAction(action, options) {
2974
2923
  };
2975
2924
  }
2976
2925
  let existing = {};
2977
- if (existsSync11(action.path)) {
2926
+ if (existsSync10(action.path)) {
2978
2927
  try {
2979
2928
  existing = JSON.parse(readFileSync8(action.path, "utf-8"));
2980
2929
  } catch {
2981
2930
  }
2982
2931
  }
2983
2932
  const merged = deepMerge(existing, action.merge);
2984
- const dir = dirname4(action.path);
2985
- if (!existsSync11(dir)) {
2933
+ const dir = dirname3(action.path);
2934
+ if (!existsSync10(dir)) {
2986
2935
  mkdirSync(dir, { recursive: true });
2987
2936
  }
2988
2937
  writeFileSync5(action.path, JSON.stringify(merged, null, 2), "utf-8");
@@ -2996,7 +2945,7 @@ async function executeAction(action, options) {
2996
2945
  wouldDo: `Delete file: ${action.path}`
2997
2946
  };
2998
2947
  }
2999
- if (existsSync11(action.path)) {
2948
+ if (existsSync10(action.path)) {
3000
2949
  unlinkSync(action.path);
3001
2950
  }
3002
2951
  return { action, success: true };
@@ -3009,7 +2958,7 @@ async function executeAction(action, options) {
3009
2958
  wouldDo: `Append to file: ${action.path}`
3010
2959
  };
3011
2960
  }
3012
- if (existsSync11(action.path)) {
2961
+ if (existsSync10(action.path)) {
3013
2962
  const content = readFileSync8(action.path, "utf-8");
3014
2963
  if (action.ifNotContains && content.includes(action.ifNotContains)) {
3015
2964
  return { action, success: true };
@@ -3371,11 +3320,9 @@ async function execute(plan, options = {}) {
3371
3320
 
3372
3321
  // src/commands/install-ui.tsx
3373
3322
  import { ruleRegistry as ruleRegistry3 } from "uilint-eslint";
3374
- import { existsSync as existsSync13 } from "fs";
3375
- import { join as join14 } from "path";
3376
3323
 
3377
3324
  // src/commands/install/installers/genstyleguide.ts
3378
- import { join as join11 } from "path";
3325
+ import { join as join10 } from "path";
3379
3326
  var genstyleguideInstaller = {
3380
3327
  id: "genstyleguide",
3381
3328
  name: "/genstyleguide command",
@@ -3385,7 +3332,7 @@ var genstyleguideInstaller = {
3385
3332
  return true;
3386
3333
  },
3387
3334
  getTargets(project) {
3388
- const commandPath = join11(project.cursorDir.path, "commands", "genstyleguide.md");
3335
+ const commandPath = join10(project.cursorDir.path, "commands", "genstyleguide.md");
3389
3336
  const isInstalled = project.commands.genstyleguide;
3390
3337
  return [
3391
3338
  {
@@ -3398,7 +3345,7 @@ var genstyleguideInstaller = {
3398
3345
  },
3399
3346
  plan(targets, config, project) {
3400
3347
  const actions = [];
3401
- const commandsDir = join11(project.cursorDir.path, "commands");
3348
+ const commandsDir = join10(project.cursorDir.path, "commands");
3402
3349
  if (!project.cursorDir.exists) {
3403
3350
  actions.push({
3404
3351
  type: "create_directory",
@@ -3411,7 +3358,7 @@ var genstyleguideInstaller = {
3411
3358
  });
3412
3359
  actions.push({
3413
3360
  type: "create_file",
3414
- path: join11(commandsDir, "genstyleguide.md"),
3361
+ path: join10(commandsDir, "genstyleguide.md"),
3415
3362
  content: GENSTYLEGUIDE_COMMAND_MD
3416
3363
  });
3417
3364
  return {
@@ -3441,8 +3388,8 @@ var genstyleguideInstaller = {
3441
3388
  };
3442
3389
 
3443
3390
  // src/commands/install/installers/skill.ts
3444
- import { existsSync as existsSync12 } from "fs";
3445
- import { join as join12 } from "path";
3391
+ import { existsSync as existsSync11 } from "fs";
3392
+ import { join as join11 } from "path";
3446
3393
  var skillInstaller = {
3447
3394
  id: "skill",
3448
3395
  name: "UI Consistency Agent skill",
@@ -3452,9 +3399,9 @@ var skillInstaller = {
3452
3399
  return true;
3453
3400
  },
3454
3401
  getTargets(project) {
3455
- const skillsDir = join12(project.cursorDir.path, "skills", "ui-consistency-enforcer");
3456
- const skillMdPath = join12(skillsDir, "SKILL.md");
3457
- const isInstalled = existsSync12(skillMdPath);
3402
+ const skillsDir = join11(project.cursorDir.path, "skills", "ui-consistency-enforcer");
3403
+ const skillMdPath = join11(skillsDir, "SKILL.md");
3404
+ const isInstalled = existsSync11(skillMdPath);
3458
3405
  return [
3459
3406
  {
3460
3407
  id: "ui-consistency-skill",
@@ -3473,21 +3420,21 @@ var skillInstaller = {
3473
3420
  path: project.cursorDir.path
3474
3421
  });
3475
3422
  }
3476
- const skillsDir = join12(project.cursorDir.path, "skills");
3423
+ const skillsDir = join11(project.cursorDir.path, "skills");
3477
3424
  actions.push({
3478
3425
  type: "create_directory",
3479
3426
  path: skillsDir
3480
3427
  });
3481
3428
  try {
3482
3429
  const skill = loadSkill("ui-consistency-enforcer");
3483
- const skillDir = join12(skillsDir, skill.name);
3430
+ const skillDir = join11(skillsDir, skill.name);
3484
3431
  actions.push({
3485
3432
  type: "create_directory",
3486
3433
  path: skillDir
3487
3434
  });
3488
3435
  for (const file of skill.files) {
3489
- const filePath = join12(skillDir, file.relativePath);
3490
- const fileDir = join12(
3436
+ const filePath = join11(skillDir, file.relativePath);
3437
+ const fileDir = join11(
3491
3438
  skillDir,
3492
3439
  file.relativePath.split("/").slice(0, -1).join("/")
3493
3440
  );
@@ -3544,8 +3491,21 @@ var skillInstaller = {
3544
3491
  };
3545
3492
 
3546
3493
  // src/commands/install/installers/eslint.ts
3547
- import { join as join13 } from "path";
3494
+ import { join as join12 } from "path";
3548
3495
  import { ruleRegistry as ruleRegistry2, getRulesByCategory as getRulesByCategory2 } from "uilint-eslint";
3496
+ function getUpgradeInfo(configuredRuleIds) {
3497
+ const configuredSet = new Set(configuredRuleIds);
3498
+ const allRuleIds = ruleRegistry2.map((r) => r.id);
3499
+ const missingRules = allRuleIds.filter((id) => !configuredSet.has(id));
3500
+ if (missingRules.length === 0) {
3501
+ return void 0;
3502
+ }
3503
+ const summary = missingRules.length === 1 ? "1 new rule available" : `${missingRules.length} new rules available`;
3504
+ return {
3505
+ missingRules,
3506
+ summary
3507
+ };
3508
+ }
3549
3509
  function toInstallSpecifier(pkgName) {
3550
3510
  return pkgName;
3551
3511
  }
@@ -3566,13 +3526,22 @@ var eslintInstaller = {
3566
3526
  return project.packages.some((pkg) => pkg.eslintConfigPath !== null);
3567
3527
  },
3568
3528
  getTargets(project) {
3569
- return project.packages.filter((pkg) => pkg.eslintConfigPath !== null).map((pkg) => ({
3570
- id: `eslint-${pkg.name}`,
3571
- label: pkg.name,
3572
- path: pkg.path,
3573
- hint: pkg.eslintConfigFilename || "ESLint config detected",
3574
- isInstalled: pkg.hasUilintRules
3575
- }));
3529
+ return project.packages.filter((pkg) => pkg.eslintConfigPath !== null).map((pkg) => {
3530
+ const upgradeInfo = pkg.hasUilintRules ? getUpgradeInfo(pkg.configuredRuleIds) : void 0;
3531
+ let hint = pkg.eslintConfigFilename || "ESLint config detected";
3532
+ if (upgradeInfo?.summary) {
3533
+ hint = `${hint} \xB7 ${upgradeInfo.summary}`;
3534
+ }
3535
+ return {
3536
+ id: `eslint-${pkg.name}`,
3537
+ label: pkg.name,
3538
+ path: pkg.path,
3539
+ hint,
3540
+ isInstalled: pkg.hasUilintRules,
3541
+ canUpgrade: upgradeInfo !== void 0,
3542
+ upgradeInfo
3543
+ };
3544
+ });
3576
3545
  },
3577
3546
  async configure(targets, project) {
3578
3547
  const staticRules = getRulesByCategory2("static");
@@ -3698,14 +3667,14 @@ var eslintInstaller = {
3698
3667
  for (const target of targets) {
3699
3668
  const pkgInfo = project.packages.find((p) => p.path === target.path);
3700
3669
  if (!pkgInfo || !pkgInfo.eslintConfigPath) continue;
3701
- const rulesDir = join13(target.path, ".uilint", "rules");
3670
+ const rulesDir = join12(target.path, ".uilint", "rules");
3702
3671
  actions.push({
3703
3672
  type: "create_directory",
3704
3673
  path: rulesDir
3705
3674
  });
3706
3675
  dependencies.push({
3707
3676
  packagePath: target.path,
3708
- packageManager: project.packageManager,
3677
+ packageManager: detectPackageManager(target.path),
3709
3678
  packages: [toInstallSpecifier("uilint-eslint"), "typescript-eslint"]
3710
3679
  });
3711
3680
  actions.push({
@@ -3716,7 +3685,7 @@ var eslintInstaller = {
3716
3685
  hasExistingRules: pkgInfo.hasUilintRules
3717
3686
  });
3718
3687
  }
3719
- const gitignorePath = join13(project.workspaceRoot, ".gitignore");
3688
+ const gitignorePath = join12(project.workspaceRoot, ".gitignore");
3720
3689
  actions.push({
3721
3690
  type: "append_to_file",
3722
3691
  path: gitignorePath,
@@ -3973,56 +3942,6 @@ function selectionsToUserChoices(selections, project, eslintRules) {
3973
3942
  function isInteractiveTerminal() {
3974
3943
  return Boolean(process.stdin.isTTY && process.stdout.isTTY);
3975
3944
  }
3976
- function getRecommendedCommand(pm) {
3977
- switch (pm) {
3978
- case "pnpm":
3979
- return "pnpm dlx uilint install";
3980
- case "yarn":
3981
- return "yarn dlx uilint install";
3982
- case "bun":
3983
- return "bunx uilint install";
3984
- case "npm":
3985
- default:
3986
- return "npx uilint install";
3987
- }
3988
- }
3989
- async function warnOnPackageManagerMismatch(projectPromise) {
3990
- const executionPm = detectExecutionPackageManager();
3991
- if (!executionPm) return;
3992
- const project = await projectPromise;
3993
- const packageManagers = /* @__PURE__ */ new Set();
3994
- const hasRootPackageJson = existsSync13(join14(project.projectPath, "package.json"));
3995
- if (hasRootPackageJson) {
3996
- packageManagers.add(project.packageManager);
3997
- } else {
3998
- for (const pkg of project.packages) {
3999
- const pm = detectPackageManager(pkg.path);
4000
- packageManagers.add(pm);
4001
- }
4002
- }
4003
- const specificPackageManagers = Array.from(packageManagers).filter(
4004
- (pm) => pm !== "npm" || hasRootPackageJson
4005
- );
4006
- if (specificPackageManagers.length === 0) return;
4007
- if (specificPackageManagers.includes(executionPm)) return;
4008
- const primaryPm = specificPackageManagers[0];
4009
- const recommendedCmd = getRecommendedCommand(primaryPm);
4010
- const pmList = specificPackageManagers.length === 1 ? specificPackageManagers[0] : specificPackageManagers.join(", ");
4011
- printBox(
4012
- "Package manager mismatch detected",
4013
- [
4014
- `This project uses ${pmList}, but you ran this command with ${executionPm}.`,
4015
- "",
4016
- `Running with ${executionPm} may create unwanted lockfiles.`,
4017
- "",
4018
- "Recommended:",
4019
- ` ${recommendedCmd}`,
4020
- "",
4021
- "Continuing anyway..."
4022
- ],
4023
- "warning"
4024
- );
4025
- }
4026
3945
  async function installUI(options = {}, executeOptions = {}) {
4027
3946
  const projectPath = process.cwd();
4028
3947
  if (!isInteractiveTerminal()) {
@@ -4031,7 +3950,6 @@ async function installUI(options = {}, executeOptions = {}) {
4031
3950
  process.exit(1);
4032
3951
  }
4033
3952
  const projectPromise = analyze(projectPath);
4034
- await warnOnPackageManagerMismatch(projectPromise);
4035
3953
  const { waitUntilExit } = render(
4036
3954
  /* @__PURE__ */ jsx6(
4037
3955
  InstallApp,
@@ -4044,7 +3962,7 @@ async function installUI(options = {}, executeOptions = {}) {
4044
3962
  console.log("\nNo items selected for installation");
4045
3963
  process.exit(0);
4046
3964
  }
4047
- const { createPlan } = await import("./plan-PX7FFJ25.js");
3965
+ const { createPlan } = await import("./plan-G43256ML.js");
4048
3966
  const plan = createPlan(project, choices, { force: options.force });
4049
3967
  const result = await execute(plan, {
4050
3968
  ...executeOptions,
@@ -4069,4 +3987,4 @@ async function installUI(options = {}, executeOptions = {}) {
4069
3987
  export {
4070
3988
  installUI
4071
3989
  };
4072
- //# sourceMappingURL=install-ui-ITXPOUVQ.js.map
3990
+ //# sourceMappingURL=install-ui-H2KOQ6SP.js.map