uilint 0.2.12 → 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 };
@@ -3373,7 +3322,7 @@ async function execute(plan, options = {}) {
3373
3322
  import { ruleRegistry as ruleRegistry3 } from "uilint-eslint";
3374
3323
 
3375
3324
  // src/commands/install/installers/genstyleguide.ts
3376
- import { join as join11 } from "path";
3325
+ import { join as join10 } from "path";
3377
3326
  var genstyleguideInstaller = {
3378
3327
  id: "genstyleguide",
3379
3328
  name: "/genstyleguide command",
@@ -3383,7 +3332,7 @@ var genstyleguideInstaller = {
3383
3332
  return true;
3384
3333
  },
3385
3334
  getTargets(project) {
3386
- const commandPath = join11(project.cursorDir.path, "commands", "genstyleguide.md");
3335
+ const commandPath = join10(project.cursorDir.path, "commands", "genstyleguide.md");
3387
3336
  const isInstalled = project.commands.genstyleguide;
3388
3337
  return [
3389
3338
  {
@@ -3396,7 +3345,7 @@ var genstyleguideInstaller = {
3396
3345
  },
3397
3346
  plan(targets, config, project) {
3398
3347
  const actions = [];
3399
- const commandsDir = join11(project.cursorDir.path, "commands");
3348
+ const commandsDir = join10(project.cursorDir.path, "commands");
3400
3349
  if (!project.cursorDir.exists) {
3401
3350
  actions.push({
3402
3351
  type: "create_directory",
@@ -3409,7 +3358,7 @@ var genstyleguideInstaller = {
3409
3358
  });
3410
3359
  actions.push({
3411
3360
  type: "create_file",
3412
- path: join11(commandsDir, "genstyleguide.md"),
3361
+ path: join10(commandsDir, "genstyleguide.md"),
3413
3362
  content: GENSTYLEGUIDE_COMMAND_MD
3414
3363
  });
3415
3364
  return {
@@ -3439,8 +3388,8 @@ var genstyleguideInstaller = {
3439
3388
  };
3440
3389
 
3441
3390
  // src/commands/install/installers/skill.ts
3442
- import { existsSync as existsSync12 } from "fs";
3443
- import { join as join12 } from "path";
3391
+ import { existsSync as existsSync11 } from "fs";
3392
+ import { join as join11 } from "path";
3444
3393
  var skillInstaller = {
3445
3394
  id: "skill",
3446
3395
  name: "UI Consistency Agent skill",
@@ -3450,9 +3399,9 @@ var skillInstaller = {
3450
3399
  return true;
3451
3400
  },
3452
3401
  getTargets(project) {
3453
- const skillsDir = join12(project.cursorDir.path, "skills", "ui-consistency-enforcer");
3454
- const skillMdPath = join12(skillsDir, "SKILL.md");
3455
- 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);
3456
3405
  return [
3457
3406
  {
3458
3407
  id: "ui-consistency-skill",
@@ -3471,21 +3420,21 @@ var skillInstaller = {
3471
3420
  path: project.cursorDir.path
3472
3421
  });
3473
3422
  }
3474
- const skillsDir = join12(project.cursorDir.path, "skills");
3423
+ const skillsDir = join11(project.cursorDir.path, "skills");
3475
3424
  actions.push({
3476
3425
  type: "create_directory",
3477
3426
  path: skillsDir
3478
3427
  });
3479
3428
  try {
3480
3429
  const skill = loadSkill("ui-consistency-enforcer");
3481
- const skillDir = join12(skillsDir, skill.name);
3430
+ const skillDir = join11(skillsDir, skill.name);
3482
3431
  actions.push({
3483
3432
  type: "create_directory",
3484
3433
  path: skillDir
3485
3434
  });
3486
3435
  for (const file of skill.files) {
3487
- const filePath = join12(skillDir, file.relativePath);
3488
- const fileDir = join12(
3436
+ const filePath = join11(skillDir, file.relativePath);
3437
+ const fileDir = join11(
3489
3438
  skillDir,
3490
3439
  file.relativePath.split("/").slice(0, -1).join("/")
3491
3440
  );
@@ -3542,8 +3491,21 @@ var skillInstaller = {
3542
3491
  };
3543
3492
 
3544
3493
  // src/commands/install/installers/eslint.ts
3545
- import { join as join13 } from "path";
3494
+ import { join as join12 } from "path";
3546
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
+ }
3547
3509
  function toInstallSpecifier(pkgName) {
3548
3510
  return pkgName;
3549
3511
  }
@@ -3564,13 +3526,22 @@ var eslintInstaller = {
3564
3526
  return project.packages.some((pkg) => pkg.eslintConfigPath !== null);
3565
3527
  },
3566
3528
  getTargets(project) {
3567
- return project.packages.filter((pkg) => pkg.eslintConfigPath !== null).map((pkg) => ({
3568
- id: `eslint-${pkg.name}`,
3569
- label: pkg.name,
3570
- path: pkg.path,
3571
- hint: pkg.eslintConfigFilename || "ESLint config detected",
3572
- isInstalled: pkg.hasUilintRules
3573
- }));
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
+ });
3574
3545
  },
3575
3546
  async configure(targets, project) {
3576
3547
  const staticRules = getRulesByCategory2("static");
@@ -3696,14 +3667,14 @@ var eslintInstaller = {
3696
3667
  for (const target of targets) {
3697
3668
  const pkgInfo = project.packages.find((p) => p.path === target.path);
3698
3669
  if (!pkgInfo || !pkgInfo.eslintConfigPath) continue;
3699
- const rulesDir = join13(target.path, ".uilint", "rules");
3670
+ const rulesDir = join12(target.path, ".uilint", "rules");
3700
3671
  actions.push({
3701
3672
  type: "create_directory",
3702
3673
  path: rulesDir
3703
3674
  });
3704
3675
  dependencies.push({
3705
3676
  packagePath: target.path,
3706
- packageManager: project.packageManager,
3677
+ packageManager: detectPackageManager(target.path),
3707
3678
  packages: [toInstallSpecifier("uilint-eslint"), "typescript-eslint"]
3708
3679
  });
3709
3680
  actions.push({
@@ -3714,7 +3685,7 @@ var eslintInstaller = {
3714
3685
  hasExistingRules: pkgInfo.hasUilintRules
3715
3686
  });
3716
3687
  }
3717
- const gitignorePath = join13(project.workspaceRoot, ".gitignore");
3688
+ const gitignorePath = join12(project.workspaceRoot, ".gitignore");
3718
3689
  actions.push({
3719
3690
  type: "append_to_file",
3720
3691
  path: gitignorePath,
@@ -3971,41 +3942,6 @@ function selectionsToUserChoices(selections, project, eslintRules) {
3971
3942
  function isInteractiveTerminal() {
3972
3943
  return Boolean(process.stdin.isTTY && process.stdout.isTTY);
3973
3944
  }
3974
- function getRecommendedCommand(pm) {
3975
- switch (pm) {
3976
- case "pnpm":
3977
- return "pnpm dlx uilint install";
3978
- case "yarn":
3979
- return "yarn dlx uilint install";
3980
- case "bun":
3981
- return "bunx uilint install";
3982
- case "npm":
3983
- default:
3984
- return "npx uilint install";
3985
- }
3986
- }
3987
- async function warnOnPackageManagerMismatch(projectPromise) {
3988
- const executionPm = detectExecutionPackageManager();
3989
- if (!executionPm) return;
3990
- const project = await projectPromise;
3991
- const projectPm = project.packageManager;
3992
- if (executionPm === projectPm) return;
3993
- const recommendedCmd = getRecommendedCommand(projectPm);
3994
- printBox(
3995
- "Package manager mismatch detected",
3996
- [
3997
- `This project uses ${projectPm}, but you ran this command with ${executionPm}.`,
3998
- "",
3999
- `This may create unwanted lockfiles (e.g., package-lock.json).`,
4000
- "",
4001
- "Recommended:",
4002
- ` ${recommendedCmd}`,
4003
- "",
4004
- "Continuing anyway..."
4005
- ],
4006
- "warning"
4007
- );
4008
- }
4009
3945
  async function installUI(options = {}, executeOptions = {}) {
4010
3946
  const projectPath = process.cwd();
4011
3947
  if (!isInteractiveTerminal()) {
@@ -4014,7 +3950,6 @@ async function installUI(options = {}, executeOptions = {}) {
4014
3950
  process.exit(1);
4015
3951
  }
4016
3952
  const projectPromise = analyze(projectPath);
4017
- await warnOnPackageManagerMismatch(projectPromise);
4018
3953
  const { waitUntilExit } = render(
4019
3954
  /* @__PURE__ */ jsx6(
4020
3955
  InstallApp,
@@ -4027,7 +3962,7 @@ async function installUI(options = {}, executeOptions = {}) {
4027
3962
  console.log("\nNo items selected for installation");
4028
3963
  process.exit(0);
4029
3964
  }
4030
- const { createPlan } = await import("./plan-PX7FFJ25.js");
3965
+ const { createPlan } = await import("./plan-G43256ML.js");
4031
3966
  const plan = createPlan(project, choices, { force: options.force });
4032
3967
  const result = await execute(plan, {
4033
3968
  ...executeOptions,
@@ -4052,4 +3987,4 @@ async function installUI(options = {}, executeOptions = {}) {
4052
3987
  export {
4053
3988
  installUI
4054
3989
  };
4055
- //# sourceMappingURL=install-ui-LK7HD2IM.js.map
3990
+ //# sourceMappingURL=install-ui-H2KOQ6SP.js.map