uilint 0.2.9 → 0.2.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,8 +1,14 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
+ confirm,
3
4
  detectNextAppRouter,
4
- findNextAppRouterProjects
5
- } from "./chunk-RHTG6DUD.js";
5
+ findNextAppRouterProjects,
6
+ log,
7
+ multiselect,
8
+ note,
9
+ pc,
10
+ select
11
+ } from "./chunk-FRNXXIEM.js";
6
12
  import {
7
13
  GENSTYLEGUIDE_COMMAND_MD,
8
14
  loadSkill
@@ -12,8 +18,8 @@ import {
12
18
  import { render } from "ink";
13
19
 
14
20
  // src/commands/install/components/InstallApp.tsx
15
- import { useState as useState3, useEffect as useEffect2 } from "react";
16
- import { Box as Box3, Text as Text4, useApp as useApp2 } from "ink";
21
+ import { useState as useState5, useEffect as useEffect2 } from "react";
22
+ import { Box as Box4, Text as Text5, useApp as useApp4, useInput as useInput4 } from "ink";
17
23
 
18
24
  // src/commands/install/components/Spinner.tsx
19
25
  import { useState, useEffect } from "react";
@@ -33,39 +39,132 @@ function Spinner() {
33
39
  return /* @__PURE__ */ jsx(Text, { color: "cyan", children: frames[frame] });
34
40
  }
35
41
 
36
- // src/commands/install/components/MultiSelect.tsx
37
- import { useState as useState2, useCallback } from "react";
42
+ // src/commands/install/components/ProjectSelector.tsx
43
+ import { useState as useState2 } from "react";
38
44
  import { Box, Text as Text2, useInput, useApp } from "ink";
39
45
  import { jsx as jsx2, jsxs } from "react/jsx-runtime";
46
+ function getDetectedProjects(project) {
47
+ const projects = [];
48
+ for (const app of project.nextApps) {
49
+ const relativePath = app.projectPath.replace(project.workspaceRoot + "/", "");
50
+ projects.push({
51
+ id: `next:${app.projectPath}`,
52
+ name: relativePath || ".",
53
+ path: app.projectPath,
54
+ type: "nextjs",
55
+ hint: "Next.js App Router",
56
+ isConfigured: false
57
+ // TODO: detect if overlay is installed
58
+ });
59
+ }
60
+ for (const app of project.viteApps) {
61
+ const relativePath = app.projectPath.replace(project.workspaceRoot + "/", "");
62
+ projects.push({
63
+ id: `vite:${app.projectPath}`,
64
+ name: relativePath || ".",
65
+ path: app.projectPath,
66
+ type: "vite",
67
+ hint: "Vite + React",
68
+ isConfigured: false
69
+ });
70
+ }
71
+ return projects;
72
+ }
73
+ function FrameworkBadge({ type }) {
74
+ switch (type) {
75
+ case "nextjs":
76
+ return /* @__PURE__ */ jsx2(Text2, { color: "white", backgroundColor: "black", children: " Next.js " });
77
+ case "vite":
78
+ return /* @__PURE__ */ jsx2(Text2, { color: "black", backgroundColor: "yellow", children: " Vite " });
79
+ default:
80
+ return /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "Other" });
81
+ }
82
+ }
83
+ function ProjectSelector({
84
+ projects,
85
+ onSelect,
86
+ onCancel
87
+ }) {
88
+ const { exit } = useApp();
89
+ const [cursor, setCursor] = useState2(0);
90
+ useInput((input, key) => {
91
+ if (key.upArrow) {
92
+ setCursor((prev) => prev > 0 ? prev - 1 : projects.length - 1);
93
+ } else if (key.downArrow) {
94
+ setCursor((prev) => prev < projects.length - 1 ? prev + 1 : 0);
95
+ } else if (key.return) {
96
+ const selected = projects[cursor];
97
+ if (selected) {
98
+ onSelect(selected);
99
+ }
100
+ } else if (input === "q" || key.escape) {
101
+ onCancel?.();
102
+ exit();
103
+ }
104
+ });
105
+ if (projects.length === 0) {
106
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
107
+ /* @__PURE__ */ jsx2(Text2, { color: "yellow", children: "No projects detected." }),
108
+ /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "UILint works with Next.js (App Router) and Vite + React projects." })
109
+ ] });
110
+ }
111
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
112
+ /* @__PURE__ */ jsx2(Box, { marginBottom: 1, children: /* @__PURE__ */ jsx2(Text2, { bold: true, children: "Select a project to configure:" }) }),
113
+ projects.map((project, index) => {
114
+ const isCursor = index === cursor;
115
+ return /* @__PURE__ */ jsxs(Box, { paddingLeft: 1, children: [
116
+ /* @__PURE__ */ jsx2(Text2, { color: isCursor ? "cyan" : void 0, children: isCursor ? "\u203A " : " " }),
117
+ /* @__PURE__ */ jsx2(Box, { width: 12, children: /* @__PURE__ */ jsx2(FrameworkBadge, { type: project.type }) }),
118
+ /* @__PURE__ */ jsx2(Box, { width: 30, children: /* @__PURE__ */ jsx2(Text2, { color: isCursor ? "cyan" : void 0, bold: isCursor, children: project.name }) }),
119
+ project.isConfigured && /* @__PURE__ */ jsx2(Text2, { color: "green", dimColor: true, children: "configured" })
120
+ ] }, project.id);
121
+ }),
122
+ /* @__PURE__ */ jsx2(Box, { marginTop: 1, borderStyle: "single", borderColor: "gray", paddingX: 1, children: /* @__PURE__ */ jsxs(Text2, { dimColor: true, children: [
123
+ /* @__PURE__ */ jsx2(Text2, { color: "cyan", children: "\u2191\u2193" }),
124
+ " navigate",
125
+ " ",
126
+ /* @__PURE__ */ jsx2(Text2, { color: "cyan", children: "enter" }),
127
+ " select",
128
+ " ",
129
+ /* @__PURE__ */ jsx2(Text2, { color: "cyan", children: "q" }),
130
+ " quit"
131
+ ] }) })
132
+ ] });
133
+ }
134
+
135
+ // src/commands/install/components/MultiSelect.tsx
136
+ import { useState as useState3, useCallback } from "react";
137
+ import { Box as Box2, Text as Text3, useInput as useInput2, useApp as useApp2 } from "ink";
138
+ import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
40
139
  function StatusIndicator({ status, isSelected }) {
41
140
  if (status === "installed") {
42
- return /* @__PURE__ */ jsx2(Text2, { color: "green", children: "\u2713" });
141
+ return /* @__PURE__ */ jsx3(Text3, { color: "green", children: "\u2713" });
43
142
  }
44
143
  if (isSelected || status === "selected") {
45
- return /* @__PURE__ */ jsx2(Text2, { color: "cyan", children: "\u25C9" });
144
+ return /* @__PURE__ */ jsx3(Text3, { color: "cyan", children: "\u25C9" });
46
145
  }
47
146
  if (status === "partial") {
48
- return /* @__PURE__ */ jsx2(Text2, { color: "yellow", children: "\u25D0" });
147
+ return /* @__PURE__ */ jsx3(Text3, { color: "yellow", children: "\u25D0" });
49
148
  }
50
- return /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "\u25CB" });
149
+ return /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "\u25CB" });
51
150
  }
52
151
  function StatusLabel({ status }) {
53
152
  if (status === "installed") {
54
- return /* @__PURE__ */ jsx2(Text2, { color: "green", dimColor: true, children: "installed" });
153
+ return /* @__PURE__ */ jsx3(Text3, { color: "green", dimColor: true, children: "installed" });
55
154
  }
56
155
  if (status === "partial") {
57
- return /* @__PURE__ */ jsx2(Text2, { color: "yellow", dimColor: true, children: "partial" });
156
+ return /* @__PURE__ */ jsx3(Text3, { color: "yellow", dimColor: true, children: "partial" });
58
157
  }
59
- return /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "-" });
158
+ return /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "-" });
60
159
  }
61
160
  function ConfigSelector({
62
161
  items,
63
162
  onSubmit,
64
163
  onCancel
65
164
  }) {
66
- const { exit } = useApp();
67
- const [cursor, setCursor] = useState2(0);
68
- const [selected, setSelected] = useState2(() => {
165
+ const { exit } = useApp2();
166
+ const [cursor, setCursor] = useState3(0);
167
+ const [selected, setSelected] = useState3(() => {
69
168
  return new Set(
70
169
  items.filter((item) => item.status !== "installed" && !item.disabled).map((item) => item.id)
71
170
  );
@@ -89,7 +188,7 @@ function ConfigSelector({
89
188
  return next;
90
189
  });
91
190
  }, [cursor, flatItems]);
92
- useInput((input, key) => {
191
+ useInput2((input, key) => {
93
192
  if (key.upArrow) {
94
193
  setCursor((prev) => prev > 0 ? prev - 1 : flatItems.length - 1);
95
194
  } else if (key.downArrow) {
@@ -112,12 +211,12 @@ function ConfigSelector({
112
211
  }
113
212
  });
114
213
  let globalIndex = 0;
115
- return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
214
+ return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", children: [
116
215
  categories.map((category) => {
117
216
  const categoryItems = itemsByCategory.get(category) || [];
118
217
  const categoryIcon = categoryItems[0]?.categoryIcon || "\u2022";
119
- return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [
120
- /* @__PURE__ */ jsx2(Box, { children: /* @__PURE__ */ jsxs(Text2, { bold: true, color: "white", children: [
218
+ return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", marginBottom: 1, children: [
219
+ /* @__PURE__ */ jsx3(Box2, { children: /* @__PURE__ */ jsxs2(Text3, { bold: true, color: "white", children: [
121
220
  categoryIcon,
122
221
  " ",
123
222
  category
@@ -127,45 +226,45 @@ function ConfigSelector({
127
226
  const isCursor = itemIndex === cursor;
128
227
  const isItemSelected = selected.has(item.id);
129
228
  const isDisabled = item.disabled || item.status === "installed";
130
- return /* @__PURE__ */ jsxs(Box, { paddingLeft: 2, children: [
131
- /* @__PURE__ */ jsx2(Text2, { color: isCursor ? "cyan" : void 0, children: isCursor ? "\u203A " : " " }),
132
- /* @__PURE__ */ jsx2(Box, { width: 2, children: /* @__PURE__ */ jsx2(StatusIndicator, { status: item.status, isSelected: isItemSelected }) }),
133
- /* @__PURE__ */ jsx2(Box, { width: 28, children: /* @__PURE__ */ jsx2(
134
- Text2,
229
+ return /* @__PURE__ */ jsxs2(Box2, { paddingLeft: 2, children: [
230
+ /* @__PURE__ */ jsx3(Text3, { color: isCursor ? "cyan" : void 0, children: isCursor ? "\u203A " : " " }),
231
+ /* @__PURE__ */ jsx3(Box2, { width: 2, children: /* @__PURE__ */ jsx3(StatusIndicator, { status: item.status, isSelected: isItemSelected }) }),
232
+ /* @__PURE__ */ jsx3(Box2, { width: 28, children: /* @__PURE__ */ jsx3(
233
+ Text3,
135
234
  {
136
235
  color: isDisabled ? void 0 : isCursor ? "cyan" : void 0,
137
236
  dimColor: isDisabled,
138
237
  children: item.label
139
238
  }
140
239
  ) }),
141
- /* @__PURE__ */ jsx2(Box, { width: 20, children: /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: item.hint || "" }) }),
142
- /* @__PURE__ */ jsx2(StatusLabel, { status: item.status })
240
+ /* @__PURE__ */ jsx3(Box2, { width: 20, children: /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: item.hint || "" }) }),
241
+ /* @__PURE__ */ jsx3(StatusLabel, { status: item.status })
143
242
  ] }, item.id);
144
243
  })
145
244
  ] }, category);
146
245
  }),
147
- /* @__PURE__ */ jsx2(Box, { marginTop: 1, borderStyle: "single", borderColor: "gray", paddingX: 1, children: /* @__PURE__ */ jsxs(Text2, { dimColor: true, children: [
148
- /* @__PURE__ */ jsx2(Text2, { color: "cyan", children: "\u2191\u2193" }),
246
+ /* @__PURE__ */ jsx3(Box2, { marginTop: 1, borderStyle: "single", borderColor: "gray", paddingX: 1, children: /* @__PURE__ */ jsxs2(Text3, { dimColor: true, children: [
247
+ /* @__PURE__ */ jsx3(Text3, { color: "cyan", children: "\u2191\u2193" }),
149
248
  " navigate",
150
249
  " ",
151
- /* @__PURE__ */ jsx2(Text2, { color: "cyan", children: "space" }),
250
+ /* @__PURE__ */ jsx3(Text3, { color: "cyan", children: "space" }),
152
251
  " toggle",
153
252
  " ",
154
- /* @__PURE__ */ jsx2(Text2, { color: "cyan", children: "a" }),
253
+ /* @__PURE__ */ jsx3(Text3, { color: "cyan", children: "a" }),
155
254
  " all",
156
255
  " ",
157
- /* @__PURE__ */ jsx2(Text2, { color: "cyan", children: "n" }),
256
+ /* @__PURE__ */ jsx3(Text3, { color: "cyan", children: "n" }),
158
257
  " none",
159
258
  " ",
160
- /* @__PURE__ */ jsx2(Text2, { color: "cyan", children: "enter" }),
259
+ /* @__PURE__ */ jsx3(Text3, { color: "cyan", children: "enter" }),
161
260
  " apply",
162
261
  " ",
163
- /* @__PURE__ */ jsx2(Text2, { color: "cyan", children: "q" }),
262
+ /* @__PURE__ */ jsx3(Text3, { color: "cyan", children: "q" }),
164
263
  " quit"
165
264
  ] }) }),
166
- /* @__PURE__ */ jsx2(Box, { marginTop: 1, children: /* @__PURE__ */ jsxs(Text2, { children: [
167
- /* @__PURE__ */ jsx2(Text2, { color: "cyan", children: selected.size }),
168
- /* @__PURE__ */ jsxs(Text2, { dimColor: true, children: [
265
+ /* @__PURE__ */ jsx3(Box2, { marginTop: 1, children: /* @__PURE__ */ jsxs2(Text3, { children: [
266
+ /* @__PURE__ */ jsx3(Text3, { color: "cyan", children: selected.size }),
267
+ /* @__PURE__ */ jsxs2(Text3, { dimColor: true, children: [
169
268
  " item",
170
269
  selected.size !== 1 ? "s" : "",
171
270
  " selected"
@@ -174,109 +273,234 @@ function ConfigSelector({
174
273
  ] });
175
274
  }
176
275
 
177
- // src/commands/install/components/ProgressList.tsx
178
- import { Box as Box2, Text as Text3, Static } from "ink";
179
- import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
180
- function CompletedTask({ task }) {
181
- return /* @__PURE__ */ jsxs2(Box2, { children: [
182
- /* @__PURE__ */ jsx3(Text3, { color: "green", children: "\u2713 " }),
183
- /* @__PURE__ */ jsx3(Text3, { children: task.message })
184
- ] });
185
- }
186
- function RunningTask({ task }) {
187
- return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", children: [
188
- /* @__PURE__ */ jsxs2(Box2, { children: [
189
- /* @__PURE__ */ jsx3(Spinner, {}),
190
- /* @__PURE__ */ jsxs2(Text3, { children: [
191
- " ",
192
- task.message
193
- ] })
194
- ] }),
195
- task.detail && /* @__PURE__ */ jsx3(Box2, { paddingLeft: 2, children: /* @__PURE__ */ jsxs2(Text3, { dimColor: true, children: [
196
- "\u2514\u2500 ",
197
- task.detail
198
- ] }) })
199
- ] });
200
- }
201
- function ErrorTask({ task }) {
202
- return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", children: [
203
- /* @__PURE__ */ jsxs2(Box2, { children: [
204
- /* @__PURE__ */ jsx3(Text3, { color: "red", children: "\u2717 " }),
205
- /* @__PURE__ */ jsx3(Text3, { color: "red", children: task.message })
206
- ] }),
207
- task.error && /* @__PURE__ */ jsx3(Box2, { paddingLeft: 2, children: /* @__PURE__ */ jsxs2(Text3, { color: "red", dimColor: true, children: [
208
- "\u2514\u2500 ",
209
- task.error
210
- ] }) })
211
- ] });
276
+ // src/commands/install/components/RuleSelector.tsx
277
+ import { useState as useState4, useMemo } from "react";
278
+ import { Box as Box3, Text as Text4, useInput as useInput3, useApp as useApp3 } from "ink";
279
+ import { getRulesByCategory } from "uilint-eslint";
280
+ import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
281
+ function SeverityBadge({ severity }) {
282
+ if (severity === "error") {
283
+ return /* @__PURE__ */ jsx4(Text4, { color: "red", children: "error" });
284
+ }
285
+ if (severity === "warn") {
286
+ return /* @__PURE__ */ jsx4(Text4, { color: "yellow", children: "warn" });
287
+ }
288
+ return /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "off" });
212
289
  }
213
- function PendingTask({ task }) {
214
- return /* @__PURE__ */ jsx3(Box2, { children: /* @__PURE__ */ jsxs2(Text3, { dimColor: true, children: [
215
- "\u25CB ",
216
- task.message
290
+ function CategoryHeader({ name, icon }) {
291
+ return /* @__PURE__ */ jsx4(Box3, { marginTop: 1, marginBottom: 0, children: /* @__PURE__ */ jsxs3(Text4, { bold: true, color: "white", children: [
292
+ icon,
293
+ " ",
294
+ name
217
295
  ] }) });
218
296
  }
219
- function ProgressList({ tasks }) {
220
- const completedTasks = tasks.filter((t) => t.status === "complete");
221
- const runningTasks = tasks.filter((t) => t.status === "running");
222
- const errorTasks = tasks.filter((t) => t.status === "error");
223
- const pendingTasks = tasks.filter((t) => t.status === "pending");
224
- return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", children: [
225
- completedTasks.length > 0 && /* @__PURE__ */ jsx3(Static, { items: completedTasks, children: (task) => /* @__PURE__ */ jsx3(CompletedTask, { task }, task.id) }),
226
- runningTasks.map((task) => /* @__PURE__ */ jsx3(RunningTask, { task }, task.id)),
227
- errorTasks.map((task) => /* @__PURE__ */ jsx3(ErrorTask, { task }, task.id)),
228
- pendingTasks.map((task) => /* @__PURE__ */ jsx3(PendingTask, { task }, task.id))
229
- ] });
230
- }
231
- function progressEventsToTasks(events) {
232
- const tasks = [];
233
- let taskIdCounter = 0;
234
- for (const event of events) {
235
- if (event.type === "start") {
236
- tasks.push({
237
- id: `task-${taskIdCounter++}`,
238
- status: "running",
239
- message: event.message,
240
- detail: event.detail
241
- });
242
- } else if (event.type === "progress") {
243
- const lastRunning = tasks.reverse().find((t) => t.status === "running");
244
- tasks.reverse();
245
- if (lastRunning) {
246
- lastRunning.message = event.message;
247
- lastRunning.detail = event.detail;
248
- } else {
249
- tasks.push({
250
- id: `task-${taskIdCounter++}`,
251
- status: "running",
252
- message: event.message,
253
- detail: event.detail
297
+ function RuleSelector({
298
+ onSubmit,
299
+ onBack,
300
+ onCancel
301
+ }) {
302
+ const { exit } = useApp3();
303
+ const staticRules = useMemo(() => getRulesByCategory("static"), []);
304
+ const semanticRules = useMemo(() => getRulesByCategory("semantic"), []);
305
+ const allRules = useMemo(() => [...staticRules, ...semanticRules], [staticRules, semanticRules]);
306
+ const [cursor, setCursor] = useState4(0);
307
+ const [viewMode, setViewMode] = useState4("list");
308
+ const [ruleStates, setRuleStates] = useState4(
309
+ () => {
310
+ const map = /* @__PURE__ */ new Map();
311
+ for (const rule of staticRules) {
312
+ map.set(rule.id, {
313
+ enabled: true,
314
+ severity: rule.defaultSeverity === "off" ? "warn" : rule.defaultSeverity
254
315
  });
255
316
  }
256
- } else if (event.type === "complete") {
257
- const lastRunning = tasks.reverse().find((t) => t.status === "running");
258
- tasks.reverse();
259
- if (lastRunning) {
260
- lastRunning.status = "complete";
261
- lastRunning.detail = void 0;
317
+ for (const rule of semanticRules) {
318
+ map.set(rule.id, {
319
+ enabled: false,
320
+ severity: rule.defaultSeverity === "off" ? "warn" : rule.defaultSeverity
321
+ });
262
322
  }
263
- } else if (event.type === "error") {
264
- const lastRunning = tasks.reverse().find((t) => t.status === "running");
265
- tasks.reverse();
266
- if (lastRunning) {
267
- lastRunning.status = "error";
268
- lastRunning.error = event.error;
269
- } else {
270
- tasks.push({
271
- id: `task-${taskIdCounter++}`,
272
- status: "error",
273
- message: event.message,
274
- error: event.error
323
+ return map;
324
+ }
325
+ );
326
+ const currentRule = allRules[cursor];
327
+ const currentState = currentRule ? ruleStates.get(currentRule.id) : void 0;
328
+ const toggleRule = () => {
329
+ if (!currentRule) return;
330
+ setRuleStates((prev) => {
331
+ const next = new Map(prev);
332
+ const current = next.get(currentRule.id);
333
+ next.set(currentRule.id, { ...current, enabled: !current.enabled });
334
+ return next;
335
+ });
336
+ };
337
+ const cycleSeverity = () => {
338
+ if (!currentRule) return;
339
+ setRuleStates((prev) => {
340
+ const next = new Map(prev);
341
+ const current = next.get(currentRule.id);
342
+ const newSeverity = current.severity === "error" ? "warn" : "error";
343
+ next.set(currentRule.id, { ...current, severity: newSeverity });
344
+ return next;
345
+ });
346
+ };
347
+ const handleSubmit = () => {
348
+ const configuredRules = [];
349
+ for (const rule of allRules) {
350
+ const state = ruleStates.get(rule.id);
351
+ if (state?.enabled) {
352
+ configuredRules.push({
353
+ rule,
354
+ severity: state.severity,
355
+ options: rule.defaultOptions
275
356
  });
276
357
  }
277
358
  }
359
+ onSubmit(configuredRules);
360
+ };
361
+ useInput3((input, key) => {
362
+ if (viewMode === "docs") {
363
+ if (key.escape || key.return || input === "d" || input === "q") {
364
+ setViewMode("list");
365
+ }
366
+ return;
367
+ }
368
+ if (key.upArrow) {
369
+ setCursor((prev) => prev > 0 ? prev - 1 : allRules.length - 1);
370
+ } else if (key.downArrow) {
371
+ setCursor((prev) => prev < allRules.length - 1 ? prev + 1 : 0);
372
+ } else if (input === " ") {
373
+ toggleRule();
374
+ } else if (input === "s") {
375
+ cycleSeverity();
376
+ } else if (input === "d") {
377
+ setViewMode("docs");
378
+ } else if (key.return) {
379
+ handleSubmit();
380
+ } else if (key.escape || input === "q") {
381
+ onCancel?.();
382
+ exit();
383
+ } else if ((input === "b" || key.leftArrow) && onBack) {
384
+ onBack();
385
+ } else if (input === "a") {
386
+ setRuleStates((prev) => {
387
+ const next = new Map(prev);
388
+ for (const rule of allRules) {
389
+ const current = next.get(rule.id);
390
+ next.set(rule.id, { ...current, enabled: true });
391
+ }
392
+ return next;
393
+ });
394
+ } else if (input === "n") {
395
+ setRuleStates((prev) => {
396
+ const next = new Map(prev);
397
+ for (const rule of allRules) {
398
+ const current = next.get(rule.id);
399
+ next.set(rule.id, { ...current, enabled: false });
400
+ }
401
+ return next;
402
+ });
403
+ }
404
+ });
405
+ if (viewMode === "docs" && currentRule) {
406
+ const docLines = currentRule.docs.trim().split("\n").slice(0, 20);
407
+ return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", children: [
408
+ /* @__PURE__ */ jsxs3(Box3, { marginBottom: 1, children: [
409
+ /* @__PURE__ */ jsx4(Text4, { bold: true, color: "cyan", children: currentRule.name }),
410
+ /* @__PURE__ */ jsxs3(Text4, { dimColor: true, children: [
411
+ " - ",
412
+ currentRule.description
413
+ ] })
414
+ ] }),
415
+ /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", borderStyle: "single", borderColor: "gray", paddingX: 1, children: [
416
+ docLines.map((line, i) => /* @__PURE__ */ jsx4(Text4, { dimColor: line.startsWith("#"), children: line }, i)),
417
+ currentRule.docs.split("\n").length > 20 && /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "... (truncated)" })
418
+ ] }),
419
+ /* @__PURE__ */ jsx4(Box3, { marginTop: 1, children: /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "Press any key to return to list" }) })
420
+ ] });
278
421
  }
279
- return tasks;
422
+ const enabledCount = Array.from(ruleStates.values()).filter((s) => s.enabled).length;
423
+ const errorCount = Array.from(ruleStates.entries()).filter(
424
+ ([id, s]) => s.enabled && s.severity === "error"
425
+ ).length;
426
+ const warnCount = enabledCount - errorCount;
427
+ let globalIndex = 0;
428
+ return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", children: [
429
+ /* @__PURE__ */ jsx4(Box3, { marginBottom: 1, children: /* @__PURE__ */ jsx4(Text4, { bold: true, children: "Configure ESLint Rules" }) }),
430
+ /* @__PURE__ */ jsx4(CategoryHeader, { name: "Static Rules", icon: "\u{1F4CB}" }),
431
+ /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: " Pattern-based, fast analysis" }),
432
+ staticRules.map((rule) => {
433
+ const itemIndex = globalIndex++;
434
+ const isCursor = itemIndex === cursor;
435
+ const state = ruleStates.get(rule.id);
436
+ return /* @__PURE__ */ jsxs3(Box3, { paddingLeft: 2, children: [
437
+ /* @__PURE__ */ jsx4(Text4, { color: isCursor ? "cyan" : void 0, children: isCursor ? "\u203A " : " " }),
438
+ /* @__PURE__ */ jsx4(Box3, { width: 3, children: /* @__PURE__ */ jsx4(Text4, { color: state.enabled ? "green" : void 0, dimColor: !state.enabled, children: state.enabled ? "\u2713" : "\u25CB" }) }),
439
+ /* @__PURE__ */ jsx4(Box3, { width: 30, children: /* @__PURE__ */ jsx4(
440
+ Text4,
441
+ {
442
+ color: isCursor ? "cyan" : void 0,
443
+ dimColor: !state.enabled,
444
+ bold: isCursor,
445
+ children: rule.name
446
+ }
447
+ ) }),
448
+ /* @__PURE__ */ jsx4(Box3, { width: 8, children: state.enabled ? /* @__PURE__ */ jsx4(SeverityBadge, { severity: state.severity }) : /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "-" }) })
449
+ ] }, rule.id);
450
+ }),
451
+ /* @__PURE__ */ jsx4(CategoryHeader, { name: "Semantic Rules", icon: "\u{1F9E0}" }),
452
+ /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: " LLM-powered analysis (requires Ollama)" }),
453
+ semanticRules.map((rule) => {
454
+ const itemIndex = globalIndex++;
455
+ const isCursor = itemIndex === cursor;
456
+ const state = ruleStates.get(rule.id);
457
+ return /* @__PURE__ */ jsxs3(Box3, { paddingLeft: 2, children: [
458
+ /* @__PURE__ */ jsx4(Text4, { color: isCursor ? "cyan" : void 0, children: isCursor ? "\u203A " : " " }),
459
+ /* @__PURE__ */ jsx4(Box3, { width: 3, children: /* @__PURE__ */ jsx4(Text4, { color: state.enabled ? "green" : void 0, dimColor: !state.enabled, children: state.enabled ? "\u2713" : "\u25CB" }) }),
460
+ /* @__PURE__ */ jsx4(Box3, { width: 30, children: /* @__PURE__ */ jsx4(
461
+ Text4,
462
+ {
463
+ color: isCursor ? "cyan" : void 0,
464
+ dimColor: !state.enabled,
465
+ bold: isCursor,
466
+ children: rule.name
467
+ }
468
+ ) }),
469
+ /* @__PURE__ */ jsx4(Box3, { width: 8, children: state.enabled ? /* @__PURE__ */ jsx4(SeverityBadge, { severity: state.severity }) : /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "-" }) })
470
+ ] }, rule.id);
471
+ }),
472
+ currentRule && /* @__PURE__ */ jsx4(Box3, { marginTop: 1, paddingX: 2, children: /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: currentRule.description }) }),
473
+ /* @__PURE__ */ jsx4(Box3, { marginTop: 1, borderStyle: "single", borderColor: "gray", paddingX: 1, children: /* @__PURE__ */ jsxs3(Text4, { dimColor: true, children: [
474
+ /* @__PURE__ */ jsx4(Text4, { color: "cyan", children: "\u2191\u2193" }),
475
+ " navigate",
476
+ " ",
477
+ /* @__PURE__ */ jsx4(Text4, { color: "cyan", children: "space" }),
478
+ " toggle",
479
+ " ",
480
+ /* @__PURE__ */ jsx4(Text4, { color: "cyan", children: "s" }),
481
+ " severity",
482
+ " ",
483
+ /* @__PURE__ */ jsx4(Text4, { color: "cyan", children: "d" }),
484
+ " docs",
485
+ " ",
486
+ /* @__PURE__ */ jsx4(Text4, { color: "cyan", children: "a" }),
487
+ " all",
488
+ " ",
489
+ /* @__PURE__ */ jsx4(Text4, { color: "cyan", children: "n" }),
490
+ " none",
491
+ " ",
492
+ /* @__PURE__ */ jsx4(Text4, { color: "cyan", children: "enter" }),
493
+ " confirm"
494
+ ] }) }),
495
+ /* @__PURE__ */ jsx4(Box3, { marginTop: 1, children: /* @__PURE__ */ jsxs3(Text4, { children: [
496
+ /* @__PURE__ */ jsx4(Text4, { color: "cyan", children: enabledCount }),
497
+ /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: " rules enabled (" }),
498
+ /* @__PURE__ */ jsx4(Text4, { color: "red", children: errorCount }),
499
+ /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: " errors, " }),
500
+ /* @__PURE__ */ jsx4(Text4, { color: "yellow", children: warnCount }),
501
+ /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: " warnings)" })
502
+ ] }) })
503
+ ] });
280
504
  }
281
505
 
282
506
  // src/commands/install/installers/registry.ts
@@ -293,76 +517,138 @@ function getAllInstallers() {
293
517
  }
294
518
 
295
519
  // src/commands/install/components/InstallApp.tsx
296
- import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
297
- function buildConfigItems(project, selections) {
520
+ import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
521
+ function buildConfigItemsForProject(project, selectedProject, selections) {
298
522
  const items = [];
299
523
  for (const selection of selections) {
300
524
  const { installer, targets } = selection;
301
- const categoryMap = {
302
- genstyleguide: { name: "Commands", icon: "\u{1F4DD}" },
303
- skill: { name: "Agent Skills", icon: "\u26A1" },
304
- next: { name: "UI Overlay", icon: "\u{1F537}" },
305
- vite: { name: "UI Overlay", icon: "\u26A1" },
306
- eslint: { name: "ESLint Plugin", icon: "\u{1F50D}" }
525
+ const relevantTargets = targets.filter((target) => {
526
+ if (installer.id === "next" || installer.id === "vite") {
527
+ return target.path === selectedProject.path;
528
+ }
529
+ if (installer.id === "eslint") {
530
+ return target.path === selectedProject.path;
531
+ }
532
+ return true;
533
+ });
534
+ if (relevantTargets.length === 0) continue;
535
+ const displayInfo = {
536
+ next: { category: "UI Analysis", icon: "\u{1F50D}" },
537
+ vite: { category: "UI Analysis", icon: "\u{1F50D}" },
538
+ eslint: { category: "ESLint Rules", icon: "\u{1F4CB}" },
539
+ genstyleguide: { category: "Cursor Integration", icon: "\u{1F4DD}" },
540
+ skill: { category: "Cursor Integration", icon: "\u26A1" }
307
541
  };
308
- const category = categoryMap[installer.id] || { name: "Other", icon: "\u2022" };
542
+ const info = displayInfo[installer.id] || { category: "Other", icon: "\u2022" };
543
+ for (const target of relevantTargets) {
544
+ items.push({
545
+ id: `${installer.id}:${target.id}`,
546
+ label: installer.name,
547
+ hint: target.hint,
548
+ status: target.isInstalled ? "installed" : "not_installed",
549
+ category: info.category,
550
+ categoryIcon: info.icon
551
+ });
552
+ }
553
+ }
554
+ return items;
555
+ }
556
+ function buildGlobalConfigItems(selections) {
557
+ const items = [];
558
+ for (const selection of selections) {
559
+ const { installer, targets } = selection;
560
+ if (installer.id !== "genstyleguide" && installer.id !== "skill") {
561
+ continue;
562
+ }
563
+ const displayInfo = {
564
+ genstyleguide: { category: "Cursor Integration", icon: "\u{1F4DD}" },
565
+ skill: { category: "Cursor Integration", icon: "\u26A1" }
566
+ };
567
+ const info = displayInfo[installer.id] || { category: "Other", icon: "\u2022" };
309
568
  for (const target of targets) {
310
569
  items.push({
311
570
  id: `${installer.id}:${target.id}`,
312
- label: target.label,
571
+ label: installer.name,
313
572
  hint: target.hint,
314
573
  status: target.isInstalled ? "installed" : "not_installed",
315
- category: category.name,
316
- categoryIcon: category.icon
574
+ category: info.category,
575
+ categoryIcon: info.icon
317
576
  });
318
577
  }
319
578
  }
320
579
  return items;
321
580
  }
322
581
  function Header({ subtitle }) {
323
- return /* @__PURE__ */ jsx4(Box3, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsxs3(Box3, { children: [
324
- /* @__PURE__ */ jsx4(Text4, { bold: true, color: "cyan", children: "\u25C6 UILint" }),
325
- /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: " v0.5.0" }),
326
- subtitle && /* @__PURE__ */ jsxs3(Text4, { dimColor: true, children: [
582
+ return /* @__PURE__ */ jsx5(Box4, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsxs4(Box4, { children: [
583
+ /* @__PURE__ */ jsx5(Text5, { bold: true, color: "cyan", children: "\u25C6 UILint" }),
584
+ /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: " v0.5.0" }),
585
+ subtitle && /* @__PURE__ */ jsxs4(Text5, { dimColor: true, children: [
327
586
  " \xB7 ",
328
587
  subtitle
329
588
  ] })
330
589
  ] }) });
331
590
  }
332
- function ProjectContext({ project }) {
333
- const parts = [];
334
- parts.push(project.packageManager);
335
- if (project.nextApps.length > 0) {
336
- parts.push(`${project.nextApps.length} Next.js app${project.nextApps.length > 1 ? "s" : ""}`);
337
- }
338
- if (project.viteApps.length > 0) {
339
- parts.push(`${project.viteApps.length} Vite app${project.viteApps.length > 1 ? "s" : ""}`);
340
- }
341
- const eslintCount = project.packages.filter((p) => p.eslintConfigPath).length;
342
- if (eslintCount > 0) {
343
- parts.push(`${eslintCount} ESLint config${eslintCount > 1 ? "s" : ""}`);
344
- }
345
- return /* @__PURE__ */ jsx4(Box3, { marginBottom: 1, children: /* @__PURE__ */ jsxs3(Text4, { dimColor: true, children: [
346
- "Detected: ",
347
- parts.join(" \xB7 ")
348
- ] }) });
591
+ function FeatureConfig({
592
+ selectedProject,
593
+ configItems,
594
+ canGoBack,
595
+ onSubmit,
596
+ onBack,
597
+ onCancel
598
+ }) {
599
+ useInput4((input, key) => {
600
+ if ((input === "b" || key.leftArrow) && canGoBack) {
601
+ onBack();
602
+ }
603
+ });
604
+ return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
605
+ selectedProject && /* @__PURE__ */ jsxs4(Box4, { marginBottom: 1, children: [
606
+ /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "Project: " }),
607
+ /* @__PURE__ */ jsx5(Text5, { bold: true, color: "cyan", children: selectedProject.name }),
608
+ /* @__PURE__ */ jsxs4(Text5, { dimColor: true, children: [
609
+ " (",
610
+ selectedProject.hint,
611
+ ")"
612
+ ] })
613
+ ] }),
614
+ /* @__PURE__ */ jsx5(
615
+ ConfigSelector,
616
+ {
617
+ items: configItems,
618
+ onSubmit,
619
+ onCancel
620
+ }
621
+ ),
622
+ canGoBack && /* @__PURE__ */ jsx5(Box4, { marginTop: 1, children: /* @__PURE__ */ jsxs4(Text5, { dimColor: true, children: [
623
+ "Press ",
624
+ /* @__PURE__ */ jsx5(Text5, { color: "cyan", children: "b" }),
625
+ " or ",
626
+ /* @__PURE__ */ jsx5(Text5, { color: "cyan", children: "\u2190" }),
627
+ " to select a different project"
628
+ ] }) })
629
+ ] });
349
630
  }
350
631
  function InstallApp({
351
632
  projectPromise,
352
633
  onComplete,
353
634
  onError
354
635
  }) {
355
- const { exit } = useApp2();
356
- const [state, setState] = useState3("scanning");
357
- const [project, setProject] = useState3(null);
358
- const [selections, setSelections] = useState3([]);
359
- const [configItems, setConfigItems] = useState3([]);
360
- const [progressEvents] = useState3([]);
361
- const [error, setError] = useState3(null);
636
+ const { exit } = useApp4();
637
+ const [phase, setPhase] = useState5("scanning");
638
+ const [project, setProject] = useState5(null);
639
+ const [detectedProjects, setDetectedProjects] = useState5([]);
640
+ const [selectedProject, setSelectedProject] = useState5(null);
641
+ const [selections, setSelections] = useState5([]);
642
+ const [configItems, setConfigItems] = useState5([]);
643
+ const [selectedFeatureIds, setSelectedFeatureIds] = useState5([]);
644
+ const [error, setError] = useState5(null);
645
+ const isEslintSelected = selectedFeatureIds.some((id) => id.startsWith("eslint:"));
362
646
  useEffect2(() => {
363
- if (state !== "scanning") return;
647
+ if (phase !== "scanning") return;
364
648
  projectPromise.then((proj) => {
365
649
  setProject(proj);
650
+ const projects = getDetectedProjects(proj);
651
+ setDetectedProjects(projects);
366
652
  const installers2 = getAllInstallers();
367
653
  const initialSelections = installers2.filter((installer) => installer.isApplicable(proj)).map((installer) => {
368
654
  const targets = installer.getTargets(proj);
@@ -374,16 +660,55 @@ function InstallApp({
374
660
  };
375
661
  });
376
662
  setSelections(initialSelections);
377
- const items = buildConfigItems(proj, initialSelections);
378
- setConfigItems(items);
379
- setState("configuring");
663
+ if (projects.length === 1) {
664
+ const singleProject = projects[0];
665
+ setSelectedProject(singleProject);
666
+ const items = buildConfigItemsForProject(proj, singleProject, initialSelections);
667
+ setConfigItems(items);
668
+ setPhase("configure-features");
669
+ } else if (projects.length === 0) {
670
+ setPhase("configure-features");
671
+ const items = buildGlobalConfigItems(initialSelections);
672
+ setConfigItems(items);
673
+ } else {
674
+ setPhase("select-project");
675
+ }
380
676
  }).catch((err) => {
381
677
  setError(err);
382
- setState("error");
678
+ setPhase("error");
383
679
  onError?.(err);
384
680
  });
385
- }, [state, projectPromise, onError]);
386
- const handleConfigSubmit = (selectedIds) => {
681
+ }, [phase, projectPromise, onError]);
682
+ const handleProjectSelect = (selected) => {
683
+ setSelectedProject(selected);
684
+ if (project) {
685
+ const items = buildConfigItemsForProject(project, selected, selections);
686
+ setConfigItems(items);
687
+ }
688
+ setPhase("configure-features");
689
+ };
690
+ const handleBackToProject = () => {
691
+ if (detectedProjects.length > 1) {
692
+ setSelectedProject(null);
693
+ setPhase("select-project");
694
+ }
695
+ };
696
+ const handleFeatureSubmit = (selectedIds) => {
697
+ setSelectedFeatureIds(selectedIds);
698
+ const eslintSelected = selectedIds.some((id) => id.startsWith("eslint:"));
699
+ if (eslintSelected) {
700
+ setPhase("configure-eslint");
701
+ } else {
702
+ finishInstallation(selectedIds, void 0);
703
+ }
704
+ };
705
+ const handleRuleSubmit = (configuredRules) => {
706
+ finishInstallation(selectedFeatureIds, configuredRules);
707
+ };
708
+ const handleBackToFeatures = () => {
709
+ setPhase("configure-features");
710
+ };
711
+ const finishInstallation = (selectedIds, eslintRules) => {
387
712
  const selectedSet = new Set(selectedIds);
388
713
  const updatedSelections = selections.map((sel) => {
389
714
  const selectedTargets = sel.targets.filter(
@@ -396,62 +721,78 @@ function InstallApp({
396
721
  };
397
722
  });
398
723
  setSelections(updatedSelections);
399
- onComplete(updatedSelections);
724
+ onComplete(updatedSelections, eslintRules);
400
725
  };
401
726
  const handleCancel = () => {
402
727
  exit();
403
728
  };
404
- if (state === "scanning") {
405
- return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", children: [
406
- /* @__PURE__ */ jsx4(Header, { subtitle: "Install" }),
407
- /* @__PURE__ */ jsxs3(Box3, { children: [
408
- /* @__PURE__ */ jsx4(Spinner, {}),
409
- /* @__PURE__ */ jsx4(Text4, { children: " Scanning project..." })
729
+ if (phase === "scanning") {
730
+ return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
731
+ /* @__PURE__ */ jsx5(Header, { subtitle: "Install" }),
732
+ /* @__PURE__ */ jsxs4(Box4, { children: [
733
+ /* @__PURE__ */ jsx5(Spinner, {}),
734
+ /* @__PURE__ */ jsx5(Text5, { children: " Scanning project..." })
410
735
  ] })
411
736
  ] });
412
737
  }
413
- if (state === "error") {
414
- return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", children: [
415
- /* @__PURE__ */ jsx4(Header, {}),
416
- /* @__PURE__ */ jsxs3(Box3, { children: [
417
- /* @__PURE__ */ jsx4(Text4, { color: "red", children: "\u2717 " }),
418
- /* @__PURE__ */ jsx4(Text4, { color: "red", children: error?.message || "An unknown error occurred" })
738
+ if (phase === "error") {
739
+ return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
740
+ /* @__PURE__ */ jsx5(Header, {}),
741
+ /* @__PURE__ */ jsxs4(Box4, { children: [
742
+ /* @__PURE__ */ jsx5(Text5, { color: "red", children: "\u2717 " }),
743
+ /* @__PURE__ */ jsx5(Text5, { color: "red", children: error?.message || "An unknown error occurred" })
419
744
  ] })
420
745
  ] });
421
746
  }
422
- if (state === "configuring" && project && configItems.length > 0) {
423
- return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", children: [
424
- /* @__PURE__ */ jsx4(Header, { subtitle: "Configuration" }),
425
- /* @__PURE__ */ jsx4(ProjectContext, { project }),
426
- /* @__PURE__ */ jsx4(
427
- ConfigSelector,
747
+ if (phase === "select-project") {
748
+ return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
749
+ /* @__PURE__ */ jsx5(Header, { subtitle: "Install" }),
750
+ /* @__PURE__ */ jsx5(
751
+ ProjectSelector,
428
752
  {
429
- items: configItems,
430
- onSubmit: handleConfigSubmit,
753
+ projects: detectedProjects,
754
+ onSelect: handleProjectSelect,
431
755
  onCancel: handleCancel
432
756
  }
433
757
  )
434
758
  ] });
435
759
  }
436
- if (state === "executing") {
437
- const tasks = progressEventsToTasks(progressEvents);
438
- return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", children: [
439
- /* @__PURE__ */ jsx4(Header, { subtitle: "Installing" }),
440
- /* @__PURE__ */ jsx4(ProgressList, { tasks })
760
+ if (phase === "configure-features" && project && configItems.length > 0) {
761
+ return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
762
+ /* @__PURE__ */ jsx5(Header, { subtitle: "Features" }),
763
+ /* @__PURE__ */ jsx5(
764
+ FeatureConfig,
765
+ {
766
+ selectedProject,
767
+ configItems,
768
+ canGoBack: detectedProjects.length > 1,
769
+ onSubmit: handleFeatureSubmit,
770
+ onBack: handleBackToProject,
771
+ onCancel: handleCancel
772
+ }
773
+ )
441
774
  ] });
442
775
  }
443
- if (state === "complete") {
444
- return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", children: [
445
- /* @__PURE__ */ jsx4(Header, {}),
446
- /* @__PURE__ */ jsxs3(Box3, { children: [
447
- /* @__PURE__ */ jsx4(Text4, { color: "green", children: "\u2713 " }),
448
- /* @__PURE__ */ jsx4(Text4, { children: "Configuration applied successfully!" })
449
- ] })
776
+ if (phase === "configure-eslint") {
777
+ return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
778
+ /* @__PURE__ */ jsx5(Header, { subtitle: "ESLint Rules" }),
779
+ selectedProject && /* @__PURE__ */ jsxs4(Box4, { marginBottom: 1, children: [
780
+ /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "Project: " }),
781
+ /* @__PURE__ */ jsx5(Text5, { bold: true, color: "cyan", children: selectedProject.name })
782
+ ] }),
783
+ /* @__PURE__ */ jsx5(
784
+ RuleSelector,
785
+ {
786
+ onSubmit: handleRuleSubmit,
787
+ onBack: handleBackToFeatures,
788
+ onCancel: handleCancel
789
+ }
790
+ )
450
791
  ] });
451
792
  }
452
- return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", children: [
453
- /* @__PURE__ */ jsx4(Header, {}),
454
- /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "Loading..." })
793
+ return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
794
+ /* @__PURE__ */ jsx5(Header, {}),
795
+ /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "Loading..." })
455
796
  ] });
456
797
  }
457
798
 
@@ -1393,14 +1734,14 @@ async function analyze(projectPath = process.cwd()) {
1393
1734
 
1394
1735
  // src/commands/install/execute.ts
1395
1736
  import {
1396
- existsSync as existsSync10,
1737
+ existsSync as existsSync11,
1397
1738
  mkdirSync,
1398
1739
  writeFileSync as writeFileSync5,
1399
1740
  readFileSync as readFileSync8,
1400
1741
  unlinkSync,
1401
1742
  chmodSync
1402
1743
  } from "fs";
1403
- import { dirname as dirname3 } from "path";
1744
+ import { dirname as dirname4 } from "path";
1404
1745
 
1405
1746
  // src/utils/react-inject.ts
1406
1747
  import { existsSync as existsSync6, readFileSync as readFileSync5, writeFileSync as writeFileSync2 } from "fs";
@@ -2441,6 +2782,145 @@ async function installNextUILintRoutes(opts) {
2441
2782
  );
2442
2783
  }
2443
2784
 
2785
+ // src/utils/prettier.ts
2786
+ import { existsSync as existsSync10 } from "fs";
2787
+ import { spawn as spawn2 } from "child_process";
2788
+ import { join as join10, dirname as dirname3 } from "path";
2789
+ function getPrettierPath(projectPath) {
2790
+ const localPath = join10(projectPath, "node_modules", ".bin", "prettier");
2791
+ if (existsSync10(localPath)) return localPath;
2792
+ let dir = projectPath;
2793
+ for (let i = 0; i < 10; i++) {
2794
+ const binPath = join10(dir, "node_modules", ".bin", "prettier");
2795
+ if (existsSync10(binPath)) return binPath;
2796
+ const parent = dirname3(dir);
2797
+ if (parent === dir) break;
2798
+ dir = parent;
2799
+ }
2800
+ return null;
2801
+ }
2802
+ function getPmRunner(pm) {
2803
+ switch (pm) {
2804
+ case "pnpm":
2805
+ return { command: "pnpm", args: ["exec"] };
2806
+ case "yarn":
2807
+ return { command: "yarn", args: [] };
2808
+ case "bun":
2809
+ return { command: "bunx", args: [] };
2810
+ case "npm":
2811
+ default:
2812
+ return { command: "npx", args: [] };
2813
+ }
2814
+ }
2815
+ async function formatWithPrettier(filePath, projectPath) {
2816
+ const prettierPath = getPrettierPath(projectPath);
2817
+ if (!prettierPath) {
2818
+ const pm = detectPackageManager(projectPath);
2819
+ const runner = getPmRunner(pm);
2820
+ return new Promise((resolve) => {
2821
+ const args = [...runner.args, "prettier", "--write", filePath];
2822
+ const child = spawn2(runner.command, args, {
2823
+ cwd: projectPath,
2824
+ stdio: "pipe",
2825
+ shell: process.platform === "win32"
2826
+ });
2827
+ let stderr = "";
2828
+ child.stderr?.on("data", (data) => {
2829
+ stderr += data.toString();
2830
+ });
2831
+ child.on("error", () => {
2832
+ resolve({ formatted: false, error: "prettier not available" });
2833
+ });
2834
+ child.on("close", (code) => {
2835
+ if (code === 0) {
2836
+ resolve({ formatted: true });
2837
+ } else {
2838
+ resolve({ formatted: false, error: stderr || "prettier failed" });
2839
+ }
2840
+ });
2841
+ });
2842
+ }
2843
+ return new Promise((resolve) => {
2844
+ const child = spawn2(prettierPath, ["--write", filePath], {
2845
+ cwd: projectPath,
2846
+ stdio: "pipe",
2847
+ shell: process.platform === "win32"
2848
+ });
2849
+ let stderr = "";
2850
+ child.stderr?.on("data", (data) => {
2851
+ stderr += data.toString();
2852
+ });
2853
+ child.on("error", (err) => {
2854
+ resolve({ formatted: false, error: err.message });
2855
+ });
2856
+ child.on("close", (code) => {
2857
+ if (code === 0) {
2858
+ resolve({ formatted: true });
2859
+ } else {
2860
+ resolve({ formatted: false, error: stderr || `exit code ${code}` });
2861
+ }
2862
+ });
2863
+ });
2864
+ }
2865
+ async function formatFilesWithPrettier(filePaths, projectPath) {
2866
+ if (filePaths.length === 0) {
2867
+ return { formatted: [], failed: [] };
2868
+ }
2869
+ const prettierPath = getPrettierPath(projectPath);
2870
+ const formatted = [];
2871
+ const failed = [];
2872
+ if (!prettierPath) {
2873
+ const pm = detectPackageManager(projectPath);
2874
+ const runner = getPmRunner(pm);
2875
+ return new Promise((resolve) => {
2876
+ const args = [...runner.args, "prettier", "--write", ...filePaths];
2877
+ const child = spawn2(runner.command, args, {
2878
+ cwd: projectPath,
2879
+ stdio: "pipe",
2880
+ shell: process.platform === "win32"
2881
+ });
2882
+ child.on("error", () => {
2883
+ resolve({ formatted: [], failed: filePaths });
2884
+ });
2885
+ child.on("close", (code) => {
2886
+ if (code === 0) {
2887
+ resolve({ formatted: filePaths, failed: [] });
2888
+ } else {
2889
+ resolve({ formatted: [], failed: filePaths });
2890
+ }
2891
+ });
2892
+ });
2893
+ }
2894
+ return new Promise((resolve) => {
2895
+ const child = spawn2(prettierPath, ["--write", ...filePaths], {
2896
+ cwd: projectPath,
2897
+ stdio: "pipe",
2898
+ shell: process.platform === "win32"
2899
+ });
2900
+ child.on("error", () => {
2901
+ resolve({ formatted: [], failed: filePaths });
2902
+ });
2903
+ child.on("close", (code) => {
2904
+ if (code === 0) {
2905
+ resolve({ formatted: filePaths, failed: [] });
2906
+ } else {
2907
+ Promise.all(
2908
+ filePaths.map(async (fp) => {
2909
+ const result = await formatWithPrettier(fp, projectPath);
2910
+ if (result.formatted) {
2911
+ formatted.push(fp);
2912
+ } else {
2913
+ failed.push(fp);
2914
+ }
2915
+ })
2916
+ ).then(() => {
2917
+ resolve({ formatted, failed });
2918
+ });
2919
+ }
2920
+ });
2921
+ });
2922
+ }
2923
+
2444
2924
  // src/commands/install/execute.ts
2445
2925
  async function executeAction(action, options) {
2446
2926
  const { dryRun = false } = options;
@@ -2454,7 +2934,7 @@ async function executeAction(action, options) {
2454
2934
  wouldDo: `Create directory: ${action.path}`
2455
2935
  };
2456
2936
  }
2457
- if (!existsSync10(action.path)) {
2937
+ if (!existsSync11(action.path)) {
2458
2938
  mkdirSync(action.path, { recursive: true });
2459
2939
  }
2460
2940
  return { action, success: true };
@@ -2467,8 +2947,8 @@ async function executeAction(action, options) {
2467
2947
  wouldDo: `Create file: ${action.path}${action.permissions ? ` (mode: ${action.permissions.toString(8)})` : ""}`
2468
2948
  };
2469
2949
  }
2470
- const dir = dirname3(action.path);
2471
- if (!existsSync10(dir)) {
2950
+ const dir = dirname4(action.path);
2951
+ if (!existsSync11(dir)) {
2472
2952
  mkdirSync(dir, { recursive: true });
2473
2953
  }
2474
2954
  writeFileSync5(action.path, action.content, "utf-8");
@@ -2486,15 +2966,15 @@ async function executeAction(action, options) {
2486
2966
  };
2487
2967
  }
2488
2968
  let existing = {};
2489
- if (existsSync10(action.path)) {
2969
+ if (existsSync11(action.path)) {
2490
2970
  try {
2491
2971
  existing = JSON.parse(readFileSync8(action.path, "utf-8"));
2492
2972
  } catch {
2493
2973
  }
2494
2974
  }
2495
2975
  const merged = deepMerge(existing, action.merge);
2496
- const dir = dirname3(action.path);
2497
- if (!existsSync10(dir)) {
2976
+ const dir = dirname4(action.path);
2977
+ if (!existsSync11(dir)) {
2498
2978
  mkdirSync(dir, { recursive: true });
2499
2979
  }
2500
2980
  writeFileSync5(action.path, JSON.stringify(merged, null, 2), "utf-8");
@@ -2508,7 +2988,7 @@ async function executeAction(action, options) {
2508
2988
  wouldDo: `Delete file: ${action.path}`
2509
2989
  };
2510
2990
  }
2511
- if (existsSync10(action.path)) {
2991
+ if (existsSync11(action.path)) {
2512
2992
  unlinkSync(action.path);
2513
2993
  }
2514
2994
  return { action, success: true };
@@ -2521,7 +3001,7 @@ async function executeAction(action, options) {
2521
3001
  wouldDo: `Append to file: ${action.path}`
2522
3002
  };
2523
3003
  }
2524
- if (existsSync10(action.path)) {
3004
+ if (existsSync11(action.path)) {
2525
3005
  const content = readFileSync8(action.path, "utf-8");
2526
3006
  if (action.ifNotContains && content.includes(action.ifNotContains)) {
2527
3007
  return { action, success: true };
@@ -2739,8 +3219,71 @@ function buildSummary(actionsPerformed, dependencyResults, items) {
2739
3219
  viteApp
2740
3220
  };
2741
3221
  }
3222
+ function collectFormattableFiles(actionsPerformed) {
3223
+ const formattableExtensions = /* @__PURE__ */ new Set([
3224
+ ".ts",
3225
+ ".tsx",
3226
+ ".js",
3227
+ ".jsx",
3228
+ ".mjs",
3229
+ ".cjs",
3230
+ ".json"
3231
+ ]);
3232
+ const files = [];
3233
+ for (const result of actionsPerformed) {
3234
+ if (!result.success) continue;
3235
+ const { action } = result;
3236
+ let filePath;
3237
+ switch (action.type) {
3238
+ case "create_file":
3239
+ filePath = action.path;
3240
+ break;
3241
+ case "merge_json":
3242
+ filePath = action.path;
3243
+ break;
3244
+ case "append_to_file":
3245
+ filePath = action.path;
3246
+ break;
3247
+ case "inject_eslint":
3248
+ filePath = action.configPath;
3249
+ break;
3250
+ case "inject_next_config":
3251
+ case "inject_vite_config":
3252
+ case "inject_react":
3253
+ break;
3254
+ }
3255
+ if (filePath) {
3256
+ const ext = filePath.slice(filePath.lastIndexOf(".")).toLowerCase();
3257
+ if (formattableExtensions.has(ext)) {
3258
+ files.push(filePath);
3259
+ }
3260
+ }
3261
+ }
3262
+ return files;
3263
+ }
3264
+ function getProjectPathFromActions(actionsPerformed) {
3265
+ for (const result of actionsPerformed) {
3266
+ if (!result.success) continue;
3267
+ const { action } = result;
3268
+ switch (action.type) {
3269
+ case "inject_eslint":
3270
+ return action.packagePath;
3271
+ case "inject_react":
3272
+ case "inject_next_config":
3273
+ case "inject_vite_config":
3274
+ case "install_next_routes":
3275
+ return action.projectPath;
3276
+ }
3277
+ }
3278
+ return void 0;
3279
+ }
2742
3280
  async function execute(plan, options = {}) {
2743
- const { dryRun = false, installDependencies: installDependencies2 = installDependencies } = options;
3281
+ const {
3282
+ dryRun = false,
3283
+ installDependencies: installDependencies2 = installDependencies,
3284
+ projectPath,
3285
+ skipPrettier = false
3286
+ } = options;
2744
3287
  const actionsPerformed = [];
2745
3288
  const dependencyResults = [];
2746
3289
  for (const action of plan.actions) {
@@ -2774,6 +3317,18 @@ async function execute(plan, options = {}) {
2774
3317
  });
2775
3318
  }
2776
3319
  }
3320
+ if (!dryRun && !skipPrettier) {
3321
+ const filesToFormat = collectFormattableFiles(actionsPerformed);
3322
+ if (filesToFormat.length > 0) {
3323
+ const formatProjectPath = projectPath || plan.dependencies[0]?.packagePath || getProjectPathFromActions(actionsPerformed);
3324
+ if (formatProjectPath) {
3325
+ await formatFilesWithPrettier(filesToFormat, formatProjectPath).catch(
3326
+ () => {
3327
+ }
3328
+ );
3329
+ }
3330
+ }
3331
+ }
2777
3332
  const actionsFailed = actionsPerformed.filter((r) => !r.success);
2778
3333
  const depsFailed = dependencyResults.filter((r) => !r.success);
2779
3334
  const success = actionsFailed.length === 0 && depsFailed.length === 0;
@@ -2807,10 +3362,10 @@ async function execute(plan, options = {}) {
2807
3362
  }
2808
3363
 
2809
3364
  // src/commands/install-ui.tsx
2810
- import { ruleRegistry as ruleRegistry2 } from "uilint-eslint";
3365
+ import { ruleRegistry as ruleRegistry3 } from "uilint-eslint";
2811
3366
 
2812
3367
  // src/commands/install/installers/genstyleguide.ts
2813
- import { join as join10 } from "path";
3368
+ import { join as join11 } from "path";
2814
3369
  var genstyleguideInstaller = {
2815
3370
  id: "genstyleguide",
2816
3371
  name: "/genstyleguide command",
@@ -2820,7 +3375,7 @@ var genstyleguideInstaller = {
2820
3375
  return true;
2821
3376
  },
2822
3377
  getTargets(project) {
2823
- const commandPath = join10(project.cursorDir.path, "commands", "genstyleguide.md");
3378
+ const commandPath = join11(project.cursorDir.path, "commands", "genstyleguide.md");
2824
3379
  const isInstalled = project.commands.genstyleguide;
2825
3380
  return [
2826
3381
  {
@@ -2833,7 +3388,7 @@ var genstyleguideInstaller = {
2833
3388
  },
2834
3389
  plan(targets, config, project) {
2835
3390
  const actions = [];
2836
- const commandsDir = join10(project.cursorDir.path, "commands");
3391
+ const commandsDir = join11(project.cursorDir.path, "commands");
2837
3392
  if (!project.cursorDir.exists) {
2838
3393
  actions.push({
2839
3394
  type: "create_directory",
@@ -2846,7 +3401,7 @@ var genstyleguideInstaller = {
2846
3401
  });
2847
3402
  actions.push({
2848
3403
  type: "create_file",
2849
- path: join10(commandsDir, "genstyleguide.md"),
3404
+ path: join11(commandsDir, "genstyleguide.md"),
2850
3405
  content: GENSTYLEGUIDE_COMMAND_MD
2851
3406
  });
2852
3407
  return {
@@ -2876,8 +3431,8 @@ var genstyleguideInstaller = {
2876
3431
  };
2877
3432
 
2878
3433
  // src/commands/install/installers/skill.ts
2879
- import { existsSync as existsSync11 } from "fs";
2880
- import { join as join11 } from "path";
3434
+ import { existsSync as existsSync12 } from "fs";
3435
+ import { join as join12 } from "path";
2881
3436
  var skillInstaller = {
2882
3437
  id: "skill",
2883
3438
  name: "UI Consistency Agent skill",
@@ -2887,9 +3442,9 @@ var skillInstaller = {
2887
3442
  return true;
2888
3443
  },
2889
3444
  getTargets(project) {
2890
- const skillsDir = join11(project.cursorDir.path, "skills", "ui-consistency-enforcer");
2891
- const skillMdPath = join11(skillsDir, "SKILL.md");
2892
- const isInstalled = existsSync11(skillMdPath);
3445
+ const skillsDir = join12(project.cursorDir.path, "skills", "ui-consistency-enforcer");
3446
+ const skillMdPath = join12(skillsDir, "SKILL.md");
3447
+ const isInstalled = existsSync12(skillMdPath);
2893
3448
  return [
2894
3449
  {
2895
3450
  id: "ui-consistency-skill",
@@ -2908,21 +3463,21 @@ var skillInstaller = {
2908
3463
  path: project.cursorDir.path
2909
3464
  });
2910
3465
  }
2911
- const skillsDir = join11(project.cursorDir.path, "skills");
3466
+ const skillsDir = join12(project.cursorDir.path, "skills");
2912
3467
  actions.push({
2913
3468
  type: "create_directory",
2914
3469
  path: skillsDir
2915
3470
  });
2916
3471
  try {
2917
3472
  const skill = loadSkill("ui-consistency-enforcer");
2918
- const skillDir = join11(skillsDir, skill.name);
3473
+ const skillDir = join12(skillsDir, skill.name);
2919
3474
  actions.push({
2920
3475
  type: "create_directory",
2921
3476
  path: skillDir
2922
3477
  });
2923
3478
  for (const file of skill.files) {
2924
- const filePath = join11(skillDir, file.relativePath);
2925
- const fileDir = join11(
3479
+ const filePath = join12(skillDir, file.relativePath);
3480
+ const fileDir = join12(
2926
3481
  skillDir,
2927
3482
  file.relativePath.split("/").slice(0, -1).join("/")
2928
3483
  );
@@ -2979,13 +3534,19 @@ var skillInstaller = {
2979
3534
  };
2980
3535
 
2981
3536
  // src/commands/install/installers/eslint.ts
2982
- import { join as join12 } from "path";
2983
- import { ruleRegistry } from "uilint-eslint";
2984
- import { createRequire } from "module";
2985
- var require2 = createRequire(import.meta.url);
3537
+ import { join as join13 } from "path";
3538
+ import { ruleRegistry as ruleRegistry2, getRulesByCategory as getRulesByCategory2 } from "uilint-eslint";
2986
3539
  function toInstallSpecifier(pkgName) {
2987
3540
  return pkgName;
2988
3541
  }
3542
+ function formatRuleOption(rule) {
3543
+ const severityBadge = rule.defaultSeverity === "error" ? pc.red("error") : pc.yellow("warn");
3544
+ return {
3545
+ value: rule.id,
3546
+ label: `${rule.name}`,
3547
+ hint: `${rule.description} [${severityBadge}]`
3548
+ };
3549
+ }
2989
3550
  var eslintInstaller = {
2990
3551
  id: "eslint",
2991
3552
  name: "ESLint plugin",
@@ -3004,20 +3565,130 @@ var eslintInstaller = {
3004
3565
  }));
3005
3566
  },
3006
3567
  async configure(targets, project) {
3007
- const selectedRules = ruleRegistry;
3008
- return {
3009
- selectedRules
3010
- };
3568
+ const staticRules = getRulesByCategory2("static");
3569
+ const semanticRules = getRulesByCategory2("semantic");
3570
+ const installMode = await select({
3571
+ message: "How would you like to configure UILint ESLint rules?",
3572
+ options: [
3573
+ {
3574
+ value: "recommended",
3575
+ label: "Recommended (static rules only)",
3576
+ hint: "Best for most projects - fast and reliable"
3577
+ },
3578
+ {
3579
+ value: "strict",
3580
+ label: "Strict (all rules including semantic)",
3581
+ hint: "Includes LLM-powered analysis - requires Ollama"
3582
+ },
3583
+ {
3584
+ value: "custom",
3585
+ label: "Custom selection",
3586
+ hint: "Choose individual rules and configure severity"
3587
+ }
3588
+ ]
3589
+ });
3590
+ let selectedRuleIds;
3591
+ let configuredRules;
3592
+ if (installMode === "recommended") {
3593
+ configuredRules = staticRules.map((rule) => ({
3594
+ rule,
3595
+ severity: rule.defaultSeverity,
3596
+ options: rule.defaultOptions
3597
+ }));
3598
+ } else if (installMode === "strict") {
3599
+ configuredRules = ruleRegistry2.map((rule) => ({
3600
+ rule,
3601
+ severity: rule.defaultSeverity,
3602
+ options: rule.defaultOptions
3603
+ }));
3604
+ } else {
3605
+ log(pc.dim("\n\u{1F4CB} Static rules (pattern-based, fast):"));
3606
+ const selectedStaticIds = await multiselect({
3607
+ message: "Select static rules to enable:",
3608
+ options: staticRules.map(formatRuleOption),
3609
+ initialValues: staticRules.map((r) => r.id)
3610
+ });
3611
+ const includeSemanticRules = await confirm({
3612
+ message: `Include semantic rules? ${pc.dim(
3613
+ "(requires Ollama for LLM analysis)"
3614
+ )}`,
3615
+ initialValue: false
3616
+ });
3617
+ let selectedSemanticIds = [];
3618
+ if (includeSemanticRules) {
3619
+ log(
3620
+ pc.dim("\n\u{1F9E0} Semantic rules (LLM-powered, slower):")
3621
+ );
3622
+ selectedSemanticIds = await multiselect({
3623
+ message: "Select semantic rules:",
3624
+ options: semanticRules.map(formatRuleOption),
3625
+ initialValues: semanticRules.map((r) => r.id)
3626
+ });
3627
+ }
3628
+ selectedRuleIds = [...selectedStaticIds, ...selectedSemanticIds];
3629
+ const configureSeverity = await confirm({
3630
+ message: "Would you like to customize severity levels?",
3631
+ initialValue: false
3632
+ });
3633
+ configuredRules = [];
3634
+ for (const ruleId of selectedRuleIds) {
3635
+ const rule = ruleRegistry2.find((r) => r.id === ruleId);
3636
+ if (configureSeverity) {
3637
+ const severity = await select({
3638
+ message: `${rule.name} - severity:`,
3639
+ options: [
3640
+ {
3641
+ value: rule.defaultSeverity,
3642
+ label: `${rule.defaultSeverity} (default)`
3643
+ },
3644
+ ...rule.defaultSeverity !== "error" ? [{ value: "error", label: "error" }] : [],
3645
+ ...rule.defaultSeverity !== "warn" ? [{ value: "warn", label: "warn" }] : []
3646
+ ],
3647
+ initialValue: rule.defaultSeverity
3648
+ });
3649
+ configuredRules.push({
3650
+ rule,
3651
+ severity,
3652
+ options: rule.defaultOptions
3653
+ });
3654
+ } else {
3655
+ configuredRules.push({
3656
+ rule,
3657
+ severity: rule.defaultSeverity,
3658
+ options: rule.defaultOptions
3659
+ });
3660
+ }
3661
+ }
3662
+ }
3663
+ const errorCount = configuredRules.filter(
3664
+ (r) => r.severity === "error"
3665
+ ).length;
3666
+ const warnCount = configuredRules.filter(
3667
+ (r) => r.severity === "warn"
3668
+ ).length;
3669
+ log("");
3670
+ note(
3671
+ configuredRules.map(
3672
+ (cr) => `${cr.severity === "error" ? "\u{1F534}" : "\u{1F7E1}"} ${cr.rule.name} (${cr.severity})`
3673
+ ).join("\n"),
3674
+ `Selected ${configuredRules.length} rules (${errorCount} errors, ${warnCount} warnings)`
3675
+ );
3676
+ return { configuredRules };
3011
3677
  },
3012
3678
  plan(targets, config, project) {
3013
3679
  const actions = [];
3014
3680
  const dependencies = [];
3015
3681
  const eslintConfig = config;
3016
- const { selectedRules } = eslintConfig;
3682
+ const { configuredRules } = eslintConfig;
3683
+ const rulesWithSeverity = configuredRules.map((cr) => ({
3684
+ ...cr.rule,
3685
+ defaultSeverity: cr.severity,
3686
+ defaultOptions: cr.options
3687
+ }));
3017
3688
  for (const target of targets) {
3018
3689
  const pkgInfo = project.packages.find((p) => p.path === target.path);
3019
3690
  if (!pkgInfo || !pkgInfo.eslintConfigPath) continue;
3020
- const rulesDir = join12(target.path, ".uilint", "rules");
3691
+ const rulesDir = join13(target.path, ".uilint", "rules");
3021
3692
  actions.push({
3022
3693
  type: "create_directory",
3023
3694
  path: rulesDir
@@ -3031,11 +3702,11 @@ var eslintInstaller = {
3031
3702
  type: "inject_eslint",
3032
3703
  packagePath: target.path,
3033
3704
  configPath: pkgInfo.eslintConfigPath,
3034
- rules: selectedRules,
3705
+ rules: rulesWithSeverity,
3035
3706
  hasExistingRules: pkgInfo.hasUilintRules
3036
3707
  });
3037
3708
  }
3038
- const gitignorePath = join12(project.workspaceRoot, ".gitignore");
3709
+ const gitignorePath = join13(project.workspaceRoot, ".gitignore");
3039
3710
  actions.push({
3040
3711
  type: "append_to_file",
3041
3712
  path: gitignorePath,
@@ -3058,7 +3729,7 @@ var eslintInstaller = {
3058
3729
  };
3059
3730
  yield {
3060
3731
  type: "progress",
3061
- message: `Injecting ${eslintConfig.selectedRules.length} rules`,
3732
+ message: `Injecting ${eslintConfig.configuredRules.length} rules`,
3062
3733
  detail: `\u2192 ${target.hint}`
3063
3734
  };
3064
3735
  }
@@ -3238,8 +3909,8 @@ registerInstaller(nextOverlayInstaller);
3238
3909
  registerInstaller(viteOverlayInstaller);
3239
3910
 
3240
3911
  // src/commands/install-ui.tsx
3241
- import { jsx as jsx5 } from "react/jsx-runtime";
3242
- function selectionsToUserChoices(selections, project) {
3912
+ import { jsx as jsx6 } from "react/jsx-runtime";
3913
+ function selectionsToUserChoices(selections, project, eslintRules) {
3243
3914
  const items = [];
3244
3915
  const choices = { items };
3245
3916
  for (const selection of selections) {
@@ -3253,7 +3924,13 @@ function selectionsToUserChoices(selections, project) {
3253
3924
  items.push("eslint");
3254
3925
  choices.eslint = {
3255
3926
  packagePaths: targets.map((t) => t.path),
3256
- selectedRules: ruleRegistry2
3927
+ // Use configured rules if provided, otherwise fall back to all rules
3928
+ selectedRules: eslintRules ? eslintRules.map((cr) => ({
3929
+ ...cr.rule,
3930
+ // Override severity with user's selection
3931
+ defaultSeverity: cr.severity,
3932
+ defaultOptions: cr.options
3933
+ })) : ruleRegistry3
3257
3934
  };
3258
3935
  } else if (installer.id === "next") {
3259
3936
  items.push("next");
@@ -3295,20 +3972,23 @@ async function installUI(options = {}, executeOptions = {}) {
3295
3972
  }
3296
3973
  const projectPromise = analyze(projectPath);
3297
3974
  const { waitUntilExit } = render(
3298
- /* @__PURE__ */ jsx5(
3975
+ /* @__PURE__ */ jsx6(
3299
3976
  InstallApp,
3300
3977
  {
3301
3978
  projectPromise,
3302
- onComplete: async (selections) => {
3979
+ onComplete: async (selections, eslintRules) => {
3303
3980
  const project = await projectPromise;
3304
- const choices = selectionsToUserChoices(selections, project);
3981
+ const choices = selectionsToUserChoices(selections, project, eslintRules);
3305
3982
  if (choices.items.length === 0) {
3306
3983
  console.log("\nNo items selected for installation");
3307
3984
  process.exit(0);
3308
3985
  }
3309
3986
  const { createPlan } = await import("./plan-PX7FFJ25.js");
3310
3987
  const plan = createPlan(project, choices, { force: options.force });
3311
- const result = await execute(plan, executeOptions);
3988
+ const result = await execute(plan, {
3989
+ ...executeOptions,
3990
+ projectPath: project.projectPath
3991
+ });
3312
3992
  if (result.success) {
3313
3993
  console.log("\n\u2713 Installation completed successfully!");
3314
3994
  } else {
@@ -3328,4 +4008,4 @@ async function installUI(options = {}, executeOptions = {}) {
3328
4008
  export {
3329
4009
  installUI
3330
4010
  };
3331
- //# sourceMappingURL=install-ui-OEFHX4FG.js.map
4011
+ //# sourceMappingURL=install-ui-KI7YHOVZ.js.map