uilint 0.2.3 → 0.2.5

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.
package/dist/index.js CHANGED
@@ -357,8 +357,8 @@ import { dirname, join as join2 } from "path";
357
357
  import { fileURLToPath } from "url";
358
358
  function getCLIVersion() {
359
359
  try {
360
- const __dirname2 = dirname(fileURLToPath(import.meta.url));
361
- const pkgPath = join2(__dirname2, "..", "..", "package.json");
360
+ const __dirname3 = dirname(fileURLToPath(import.meta.url));
361
+ const pkgPath = join2(__dirname3, "..", "..", "package.json");
362
362
  const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
363
363
  return pkg.version || "0.0.0";
364
364
  } catch {
@@ -1475,13 +1475,13 @@ async function update(options) {
1475
1475
  }
1476
1476
 
1477
1477
  // src/commands/install.ts
1478
- import { join as join15 } from "path";
1478
+ import { join as join16 } from "path";
1479
1479
  import { ruleRegistry as ruleRegistry2 } from "uilint-eslint";
1480
1480
 
1481
1481
  // src/commands/install/analyze.ts
1482
1482
  import { existsSync as existsSync9, readFileSync as readFileSync5 } from "fs";
1483
1483
  import { join as join8 } from "path";
1484
- import { findWorkspaceRoot as findWorkspaceRoot4 } from "uilint-core/node";
1484
+ import { findWorkspaceRoot as findWorkspaceRoot5 } from "uilint-core/node";
1485
1485
 
1486
1486
  // src/utils/next-detect.ts
1487
1487
  import { existsSync as existsSync4, readdirSync } from "fs";
@@ -1714,6 +1714,24 @@ function isFrontendPackage(pkgJson) {
1714
1714
  };
1715
1715
  return FRONTEND_INDICATORS.some((pkg) => pkg in deps);
1716
1716
  }
1717
+ function isTypeScriptPackage(dir, pkgJson) {
1718
+ if (existsSync6(join5(dir, "tsconfig.json"))) {
1719
+ return true;
1720
+ }
1721
+ const deps = {
1722
+ ...pkgJson.dependencies,
1723
+ ...pkgJson.devDependencies
1724
+ };
1725
+ if ("typescript" in deps) {
1726
+ return true;
1727
+ }
1728
+ for (const configFile of ESLINT_CONFIG_FILES) {
1729
+ if (configFile.endsWith(".ts") && existsSync6(join5(dir, configFile))) {
1730
+ return true;
1731
+ }
1732
+ }
1733
+ return false;
1734
+ }
1717
1735
  function hasEslintConfig(dir) {
1718
1736
  for (const file of ESLINT_CONFIG_FILES) {
1719
1737
  if (existsSync6(join5(dir, file))) {
@@ -1747,7 +1765,8 @@ function findPackages(rootDir, options) {
1747
1765
  name,
1748
1766
  hasEslintConfig: hasEslintConfig(dir),
1749
1767
  isFrontend: isFrontendPackage(pkg),
1750
- isRoot
1768
+ isRoot,
1769
+ isTypeScript: isTypeScriptPackage(dir, pkg)
1751
1770
  };
1752
1771
  } catch {
1753
1772
  return null;
@@ -1853,8 +1872,9 @@ async function installDependencies(pm, projectPath, packages) {
1853
1872
 
1854
1873
  // src/utils/eslint-config-inject.ts
1855
1874
  import { existsSync as existsSync8, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "fs";
1856
- import { join as join7 } from "path";
1875
+ import { join as join7, relative as relative2, dirname as dirname6 } from "path";
1857
1876
  import { parseExpression, parseModule, generateCode } from "magicast";
1877
+ import { findWorkspaceRoot as findWorkspaceRoot4 } from "uilint-core/node";
1858
1878
  var CONFIG_EXTENSIONS = [".ts", ".mjs", ".js", ".cjs"];
1859
1879
  function findEslintConfigFile(projectPath) {
1860
1880
  for (const ext of CONFIG_EXTENSIONS) {
@@ -1869,25 +1889,6 @@ function getEslintConfigFilename(configPath) {
1869
1889
  const parts = configPath.split("/");
1870
1890
  return parts[parts.length - 1] || "eslint.config.mjs";
1871
1891
  }
1872
- function hasUilintImport(source) {
1873
- return source.includes('from "uilint-eslint"') || source.includes("from 'uilint-eslint'") || source.includes('require("uilint-eslint")') || source.includes("require('uilint-eslint')");
1874
- }
1875
- function hasUilintConfigsUsage(source) {
1876
- return /\builint\s*\.\s*configs\s*\./.test(source);
1877
- }
1878
- function walkAst(node, visit) {
1879
- if (!node || typeof node !== "object") return;
1880
- visit(node);
1881
- for (const key of Object.keys(node)) {
1882
- const v = node[key];
1883
- if (!v) continue;
1884
- if (Array.isArray(v)) {
1885
- for (const item of v) walkAst(item, visit);
1886
- } else if (typeof v === "object" && v.type) {
1887
- walkAst(v, visit);
1888
- }
1889
- }
1890
- }
1891
1892
  function isIdentifier(node, name) {
1892
1893
  return !!node && node.type === "Identifier" && (name ? node.name === name : typeof node.name === "string");
1893
1894
  }
@@ -1912,35 +1913,6 @@ function hasSpreadProperties(obj) {
1912
1913
  (p2) => p2 && (p2.type === "SpreadElement" || p2.type === "SpreadProperty")
1913
1914
  );
1914
1915
  }
1915
- var IGNORED_AST_KEYS = /* @__PURE__ */ new Set([
1916
- "loc",
1917
- "start",
1918
- "end",
1919
- "extra",
1920
- "leadingComments",
1921
- "trailingComments",
1922
- "innerComments"
1923
- ]);
1924
- function normalizeAstForCompare(node) {
1925
- if (node === null) return null;
1926
- if (node === void 0) return void 0;
1927
- if (typeof node !== "object") return node;
1928
- if (Array.isArray(node)) return node.map(normalizeAstForCompare);
1929
- const out = {};
1930
- const keys = Object.keys(node).filter((k) => !IGNORED_AST_KEYS.has(k)).sort();
1931
- for (const k of keys) {
1932
- if (k.startsWith("$")) continue;
1933
- out[k] = normalizeAstForCompare(node[k]);
1934
- }
1935
- return out;
1936
- }
1937
- function astEquivalent(a, b) {
1938
- try {
1939
- return JSON.stringify(normalizeAstForCompare(a)) === JSON.stringify(normalizeAstForCompare(b));
1940
- } catch {
1941
- return false;
1942
- }
1943
- }
1944
1916
  function collectUilintRuleIdsFromRulesObject(rulesObj) {
1945
1917
  const ids = /* @__PURE__ */ new Set();
1946
1918
  if (!rulesObj || rulesObj.type !== "ObjectExpression") return ids;
@@ -1951,8 +1923,9 @@ function collectUilintRuleIdsFromRulesObject(rulesObj) {
1951
1923
  if (!isStringLiteral(key)) continue;
1952
1924
  const val = key.value;
1953
1925
  if (typeof val !== "string") continue;
1954
- if (!val.startsWith("uilint/")) continue;
1955
- ids.add(val.slice("uilint/".length));
1926
+ if (val.startsWith("uilint/")) {
1927
+ ids.add(val.slice("uilint/".length));
1928
+ }
1956
1929
  }
1957
1930
  return ids;
1958
1931
  }
@@ -2045,24 +2018,6 @@ function findExportedConfigArrayExpression(mod) {
2045
2018
  }
2046
2019
  return null;
2047
2020
  }
2048
- function findUsesUilintConfigs(program2) {
2049
- let found = false;
2050
- walkAst(program2, (n) => {
2051
- if (found) return;
2052
- if (n?.type === "MemberExpression") {
2053
- const obj = n.object;
2054
- const prop = n.property;
2055
- if (isIdentifier(prop, "configs") && isIdentifier(obj, "uilint")) {
2056
- found = true;
2057
- return;
2058
- }
2059
- if (obj?.type === "MemberExpression" && isIdentifier(obj.object, "uilint") && isIdentifier(obj.property, "configs")) {
2060
- found = true;
2061
- }
2062
- }
2063
- });
2064
- return found;
2065
- }
2066
2021
  function collectConfiguredUilintRuleIdsFromConfigArray(arrayExpr) {
2067
2022
  const ids = /* @__PURE__ */ new Set();
2068
2023
  if (!arrayExpr || arrayExpr.type !== "ArrayExpression") return ids;
@@ -2115,69 +2070,68 @@ function chooseUniqueIdentifier(base, used) {
2115
2070
  while (used.has(`${base}${i}`)) i++;
2116
2071
  return `${base}${i}`;
2117
2072
  }
2118
- function getEsmUilintDefaultImportLocal(mod) {
2119
- const items = mod?.imports?.$items ?? [];
2120
- const found = items.find(
2121
- (it) => it?.from === "uilint-eslint" && it?.imported === "default"
2122
- );
2123
- return found?.local ?? null;
2124
- }
2125
- function ensureUilintImportAst(mod) {
2126
- const existing = getEsmUilintDefaultImportLocal(mod);
2127
- if (existing) return { local: existing, changed: false };
2128
- mod.imports.$prepend({
2129
- imported: "default",
2130
- local: "uilint",
2131
- from: "uilint-eslint"
2132
- });
2133
- return { local: "uilint", changed: true };
2134
- }
2135
- function findCjsUilintRequireBinding(program2) {
2136
- if (!program2 || program2.type !== "Program") return null;
2137
- for (const stmt of program2.body ?? []) {
2138
- if (stmt?.type !== "VariableDeclaration") continue;
2139
- for (const decl of stmt.declarations ?? []) {
2140
- const id = decl?.id;
2141
- const init = decl?.init;
2142
- if (!isIdentifier(id)) continue;
2143
- if (init?.type === "CallExpression" && isIdentifier(init.callee, "require") && isStringLiteral(init.arguments?.[0]) && init.arguments[0].value === "uilint-eslint") {
2144
- return id.name;
2145
- }
2146
- }
2073
+ function addLocalRuleImportsAst(mod, selectedRules, configPath, rulesRoot, fileExtension = ".js") {
2074
+ const importNames = /* @__PURE__ */ new Map();
2075
+ let changed = false;
2076
+ const configDir = dirname6(configPath);
2077
+ const rulesDir = join7(rulesRoot, ".uilint", "rules");
2078
+ const relativeRulesPath = relative2(configDir, rulesDir).replace(/\\/g, "/");
2079
+ const normalizedRulesPath = relativeRulesPath.startsWith("./") || relativeRulesPath.startsWith("../") ? relativeRulesPath : `./${relativeRulesPath}`;
2080
+ const used = collectTopLevelBindings(mod.$ast);
2081
+ for (const rule of selectedRules) {
2082
+ const importName = chooseUniqueIdentifier(
2083
+ `${rule.id.replace(/-([a-z])/g, (_, c) => c.toUpperCase()).replace(/^./, (c) => c.toUpperCase())}Rule`,
2084
+ used
2085
+ );
2086
+ importNames.set(rule.id, importName);
2087
+ used.add(importName);
2088
+ const rulePath = `${normalizedRulesPath}/${rule.id}${fileExtension}`;
2089
+ mod.imports.$add({
2090
+ imported: "default",
2091
+ local: importName,
2092
+ from: rulePath
2093
+ });
2094
+ changed = true;
2147
2095
  }
2148
- return null;
2096
+ return { importNames, changed };
2149
2097
  }
2150
- function ensureUilintRequireAst(program2) {
2098
+ function addLocalRuleRequiresAst(program2, selectedRules, configPath, rulesRoot, fileExtension = ".js") {
2099
+ const importNames = /* @__PURE__ */ new Map();
2100
+ let changed = false;
2151
2101
  if (!program2 || program2.type !== "Program") {
2152
- return { local: "uilint", changed: false };
2102
+ return { importNames, changed };
2153
2103
  }
2154
- const existing = findCjsUilintRequireBinding(program2);
2155
- if (existing) return { local: existing, changed: false };
2104
+ const configDir = dirname6(configPath);
2105
+ const rulesDir = join7(rulesRoot, ".uilint", "rules");
2106
+ const relativeRulesPath = relative2(configDir, rulesDir).replace(/\\/g, "/");
2107
+ const normalizedRulesPath = relativeRulesPath.startsWith("./") || relativeRulesPath.startsWith("../") ? relativeRulesPath : `./${relativeRulesPath}`;
2156
2108
  const used = collectTopLevelBindings(program2);
2157
- const local = chooseUniqueIdentifier("uilint", used);
2158
- const stmtMod = parseModule(`const ${local} = require("uilint-eslint");`);
2159
- const stmt = stmtMod.$ast.body?.[0];
2160
- if (!stmt) return { local, changed: false };
2161
- let insertAt = 0;
2162
- const first = program2.body?.[0];
2163
- if (first?.type === "ExpressionStatement" && first.expression?.type === "StringLiteral" && first.expression.value === "use strict") {
2164
- insertAt = 1;
2165
- }
2166
- program2.body.splice(insertAt, 0, stmt);
2167
- return { local, changed: true };
2168
- }
2169
- function buildUilintRuleProperty(rule) {
2170
- const ruleKey = `uilint/${rule.id}`;
2171
- const valueCode = rule.defaultOptions && rule.defaultOptions.length > 0 ? `["${rule.defaultSeverity}", ...${JSON.stringify(
2172
- rule.defaultOptions,
2173
- null,
2174
- 2
2175
- )}]` : `"${rule.defaultSeverity}"`;
2176
- const expr = parseExpression(`({ "${ruleKey}": ${valueCode} })`);
2177
- const obj = expr.$ast;
2178
- return obj.properties?.[0];
2179
- }
2180
- function appendUilintConfigBlockToArray(arrayExpr, selectedRules, uilintRef) {
2109
+ for (const rule of selectedRules) {
2110
+ const importName = chooseUniqueIdentifier(
2111
+ `${rule.id.replace(/-([a-z])/g, (_, c) => c.toUpperCase()).replace(/^./, (c) => c.toUpperCase())}Rule`,
2112
+ used
2113
+ );
2114
+ importNames.set(rule.id, importName);
2115
+ used.add(importName);
2116
+ const rulePath = `${normalizedRulesPath}/${rule.id}${fileExtension}`;
2117
+ const stmtMod = parseModule(
2118
+ `const ${importName} = require("${rulePath}");`
2119
+ );
2120
+ const stmt = stmtMod.$ast.body?.[0];
2121
+ if (stmt) {
2122
+ let insertAt = 0;
2123
+ const first = program2.body?.[0];
2124
+ if (first?.type === "ExpressionStatement" && first.expression?.type === "StringLiteral" && first.expression.value === "use strict") {
2125
+ insertAt = 1;
2126
+ }
2127
+ program2.body.splice(insertAt, 0, stmt);
2128
+ changed = true;
2129
+ }
2130
+ }
2131
+ return { importNames, changed };
2132
+ }
2133
+ function appendUilintConfigBlockToArray(arrayExpr, selectedRules, ruleImportNames) {
2134
+ const pluginRulesCode = Array.from(ruleImportNames.entries()).map(([ruleId, importName]) => ` "${ruleId}": ${importName},`).join("\n");
2181
2135
  const rulesPropsCode = selectedRules.map((r) => {
2182
2136
  const ruleKey = `uilint/${r.id}`;
2183
2137
  const valueCode = r.defaultOptions && r.defaultOptions.length > 0 ? `["${r.defaultSeverity}", ...${JSON.stringify(
@@ -2193,7 +2147,13 @@ function appendUilintConfigBlockToArray(arrayExpr, selectedRules, uilintRef) {
2193
2147
  "app/**/*.{js,jsx,ts,tsx}",
2194
2148
  "pages/**/*.{js,jsx,ts,tsx}",
2195
2149
  ],
2196
- plugins: { uilint: ${uilintRef} },
2150
+ plugins: {
2151
+ uilint: {
2152
+ rules: {
2153
+ ${pluginRulesCode}
2154
+ },
2155
+ },
2156
+ },
2197
2157
  rules: {
2198
2158
  ${rulesPropsCode}
2199
2159
  },
@@ -2210,14 +2170,13 @@ function getUilintEslintConfigInfoFromSourceAst(source) {
2210
2170
  error: "Could not locate an exported ESLint flat config array (expected `export default [...]`, `export default defineConfig([...])`, `module.exports = [...]`, or `module.exports = defineConfig([...])`)."
2211
2171
  };
2212
2172
  }
2213
- const usesUilintConfigs = findUsesUilintConfigs(found.program);
2214
2173
  const configuredRuleIds = collectConfiguredUilintRuleIdsFromConfigArray(
2215
2174
  found.arrayExpr
2216
2175
  );
2217
2176
  const existingUilint = findExistingUilintRulesObject(found.arrayExpr);
2218
- const configured = usesUilintConfigs || configuredRuleIds.size > 0 || existingUilint.configObj !== null || hasUilintImport(source);
2177
+ const configured = configuredRuleIds.size > 0 || existingUilint.configObj !== null;
2219
2178
  return {
2220
- info: { usesUilintConfigs, configuredRuleIds, configured },
2179
+ info: { configuredRuleIds, configured },
2221
2180
  mod,
2222
2181
  arrayExpr: found.arrayExpr,
2223
2182
  kind: found.kind
@@ -2232,11 +2191,9 @@ function getUilintEslintConfigInfoFromSource(source) {
2232
2191
  const ast = getUilintEslintConfigInfoFromSourceAst(source);
2233
2192
  if ("error" in ast) {
2234
2193
  const configuredRuleIds = extractConfiguredUilintRuleIds(source);
2235
- const usesUilintConfigs = hasUilintConfigsUsage(source);
2236
2194
  return {
2237
- usesUilintConfigs,
2238
2195
  configuredRuleIds,
2239
- configured: usesUilintConfigs || configuredRuleIds.size > 0 || hasUilintImport(source)
2196
+ configured: configuredRuleIds.size > 0
2240
2197
  };
2241
2198
  }
2242
2199
  return ast.info;
@@ -2279,10 +2236,15 @@ async function installEslintPlugin(opts) {
2279
2236
  };
2280
2237
  }
2281
2238
  const { info, mod, arrayExpr, kind } = ast;
2282
- const usesUilintConfigs = info.usesUilintConfigs;
2283
2239
  const configuredIds = info.configuredRuleIds;
2284
- const missingRules = usesUilintConfigs ? [] : getMissingSelectedRules(opts.selectedRules, configuredIds);
2285
- const rulesToUpdate = usesUilintConfigs ? [] : getRulesNeedingUpdate(opts.selectedRules, configuredIds);
2240
+ const missingRules = getMissingSelectedRules(
2241
+ opts.selectedRules,
2242
+ configuredIds
2243
+ );
2244
+ const rulesToUpdate = getRulesNeedingUpdate(
2245
+ opts.selectedRules,
2246
+ configuredIds
2247
+ );
2286
2248
  let rulesToApply = [];
2287
2249
  if (!info.configured) {
2288
2250
  rulesToApply = opts.selectedRules;
@@ -2303,47 +2265,79 @@ async function installEslintPlugin(opts) {
2303
2265
  }
2304
2266
  }
2305
2267
  }
2268
+ if (rulesToApply.length === 0) {
2269
+ return {
2270
+ configFile: configFilename,
2271
+ modified: false,
2272
+ missingRuleIds: missingRules.map((r) => r.id),
2273
+ configured: info.configured
2274
+ };
2275
+ }
2306
2276
  let modifiedAst = false;
2307
- if (!usesUilintConfigs && rulesToApply.length > 0) {
2308
- const existing = findExistingUilintRulesObject(arrayExpr);
2309
- if (existing.safeToMutate && existing.rulesObj) {
2310
- let changedRules = false;
2311
- for (const rule of rulesToApply) {
2312
- const fullKey = `uilint/${rule.id}`;
2313
- const props = existing.rulesObj.properties ?? [];
2314
- const existingProp = props.find((p2) => {
2315
- if (!p2) return false;
2316
- if (p2.type !== "ObjectProperty" && p2.type !== "Property")
2317
- return false;
2318
- return isStringLiteral(p2.key) && p2.key.value === fullKey;
2319
- });
2320
- const newProp = buildUilintRuleProperty(rule);
2321
- if (!newProp) continue;
2322
- if (existingProp) {
2323
- if (!astEquivalent(existingProp.value, newProp.value)) {
2324
- existingProp.value = newProp.value;
2325
- changedRules = true;
2326
- }
2327
- } else {
2328
- props.push(newProp);
2329
- changedRules = true;
2330
- }
2331
- }
2332
- if (changedRules) modifiedAst = true;
2333
- } else {
2334
- const uilintRef = kind === "esm" ? ensureUilintImportAst(mod).local : ensureUilintRequireAst(mod.$ast).local;
2335
- appendUilintConfigBlockToArray(arrayExpr, rulesToApply, uilintRef);
2336
- modifiedAst = true;
2277
+ const localRulesDir = join7(opts.projectPath, ".uilint", "rules");
2278
+ const workspaceRoot = findWorkspaceRoot4(opts.projectPath);
2279
+ const workspaceRulesDir = join7(workspaceRoot, ".uilint", "rules");
2280
+ const rulesRoot = existsSync8(localRulesDir) ? opts.projectPath : workspaceRoot;
2281
+ let fileExtension = ".js";
2282
+ if (rulesToApply.length > 0) {
2283
+ const firstRulePath = join7(
2284
+ rulesRoot,
2285
+ ".uilint",
2286
+ "rules",
2287
+ `${rulesToApply[0].id}.ts`
2288
+ );
2289
+ if (existsSync8(firstRulePath)) {
2290
+ fileExtension = ".ts";
2337
2291
  }
2338
- } else if (!info.configured && !usesUilintConfigs) {
2339
2292
  }
2340
- if (modifiedAst || info.configured) {
2293
+ let ruleImportNames;
2294
+ if (kind === "esm") {
2295
+ const result = addLocalRuleImportsAst(
2296
+ mod,
2297
+ rulesToApply,
2298
+ configPath,
2299
+ rulesRoot,
2300
+ fileExtension
2301
+ );
2302
+ ruleImportNames = result.importNames;
2303
+ if (result.changed) modifiedAst = true;
2304
+ } else {
2305
+ const result = addLocalRuleRequiresAst(
2306
+ mod.$ast,
2307
+ rulesToApply,
2308
+ configPath,
2309
+ rulesRoot,
2310
+ fileExtension
2311
+ );
2312
+ ruleImportNames = result.importNames;
2313
+ if (result.changed) modifiedAst = true;
2314
+ }
2315
+ if (ruleImportNames && ruleImportNames.size > 0) {
2316
+ appendUilintConfigBlockToArray(arrayExpr, rulesToApply, ruleImportNames);
2317
+ modifiedAst = true;
2318
+ }
2319
+ if (!info.configured) {
2341
2320
  if (kind === "esm") {
2342
- const { changed } = ensureUilintImportAst(mod);
2343
- if (changed) modifiedAst = true;
2344
- } else if (kind === "cjs") {
2345
- const { changed } = ensureUilintRequireAst(mod.$ast);
2346
- if (changed) modifiedAst = true;
2321
+ mod.imports.$add({
2322
+ imported: "createRule",
2323
+ local: "createRule",
2324
+ from: "uilint-eslint"
2325
+ });
2326
+ modifiedAst = true;
2327
+ } else {
2328
+ const stmtMod = parseModule(
2329
+ `const { createRule } = require("uilint-eslint");`
2330
+ );
2331
+ const stmt = stmtMod.$ast.body?.[0];
2332
+ if (stmt) {
2333
+ let insertAt = 0;
2334
+ const first = mod.$ast.body?.[0];
2335
+ if (first?.type === "ExpressionStatement" && first.expression?.type === "StringLiteral" && first.expression.value === "use strict") {
2336
+ insertAt = 1;
2337
+ }
2338
+ mod.$ast.body.splice(insertAt, 0, stmt);
2339
+ modifiedAst = true;
2340
+ }
2347
2341
  }
2348
2342
  }
2349
2343
  const updated = modifiedAst ? generateCode(mod).code : original;
@@ -2375,7 +2369,7 @@ function safeParseJson(filePath) {
2375
2369
  }
2376
2370
  }
2377
2371
  async function analyze2(projectPath = process.cwd()) {
2378
- const workspaceRoot = findWorkspaceRoot4(projectPath);
2372
+ const workspaceRoot = findWorkspaceRoot5(projectPath);
2379
2373
  const packageManager = detectPackageManager(projectPath);
2380
2374
  const cursorDir = join8(projectPath, ".cursor");
2381
2375
  const cursorDirExists = existsSync9(cursorDir);
@@ -2435,7 +2429,7 @@ async function analyze2(projectPath = process.cwd()) {
2435
2429
  try {
2436
2430
  const source = readFileSync5(eslintConfigPath, "utf-8");
2437
2431
  const info = getUilintEslintConfigInfoFromSource(source);
2438
- hasRules = info.configuredRuleIds.size > 0 || info.usesUilintConfigs;
2432
+ hasRules = info.configuredRuleIds.size > 0;
2439
2433
  configuredRuleIds = Array.from(info.configuredRuleIds);
2440
2434
  } catch {
2441
2435
  }
@@ -2483,8 +2477,8 @@ async function analyze2(projectPath = process.cwd()) {
2483
2477
  }
2484
2478
 
2485
2479
  // src/commands/install/plan.ts
2486
- import { join as join10 } from "path";
2487
- import { createRequire } from "module";
2480
+ import { join as join11 } from "path";
2481
+ import { createRequire as createRequire2 } from "module";
2488
2482
 
2489
2483
  // src/commands/install/constants.ts
2490
2484
  var HOOKS_CONFIG = {
@@ -2874,10 +2868,10 @@ Generate in \`.uilint/rules/\`:
2874
2868
 
2875
2869
  // src/utils/skill-loader.ts
2876
2870
  import { readFileSync as readFileSync6, readdirSync as readdirSync4, statSync as statSync2, existsSync as existsSync10 } from "fs";
2877
- import { join as join9, dirname as dirname6, relative as relative2 } from "path";
2871
+ import { join as join9, dirname as dirname7, relative as relative3 } from "path";
2878
2872
  import { fileURLToPath as fileURLToPath2 } from "url";
2879
2873
  var __filename = fileURLToPath2(import.meta.url);
2880
- var __dirname = dirname6(__filename);
2874
+ var __dirname = dirname7(__filename);
2881
2875
  function getSkillsDir() {
2882
2876
  const devPath = join9(__dirname, "..", "..", "skills");
2883
2877
  const prodPath = join9(__dirname, "..", "skills");
@@ -2900,7 +2894,7 @@ function collectFiles(dir, baseDir) {
2900
2894
  if (stat.isDirectory()) {
2901
2895
  files.push(...collectFiles(fullPath, baseDir));
2902
2896
  } else if (stat.isFile()) {
2903
- const relativePath = relative2(baseDir, fullPath);
2897
+ const relativePath = relative3(baseDir, fullPath);
2904
2898
  const content = readFileSync6(fullPath, "utf-8");
2905
2899
  files.push({ relativePath, content });
2906
2900
  }
@@ -2921,11 +2915,154 @@ function loadSkill(name) {
2921
2915
  return { name, files };
2922
2916
  }
2923
2917
 
2924
- // src/commands/install/plan.ts
2918
+ // src/utils/rule-loader.ts
2919
+ import { readFileSync as readFileSync7, existsSync as existsSync11 } from "fs";
2920
+ import { join as join10, dirname as dirname8 } from "path";
2921
+ import { fileURLToPath as fileURLToPath3 } from "url";
2922
+ import { createRequire } from "module";
2923
+ var __filename2 = fileURLToPath3(import.meta.url);
2924
+ var __dirname2 = dirname8(__filename2);
2925
2925
  var require2 = createRequire(import.meta.url);
2926
+ function findNodeModulesPackageRoot(pkgName, startDir) {
2927
+ let dir = startDir;
2928
+ while (true) {
2929
+ const candidate = join10(dir, "node_modules", pkgName);
2930
+ if (existsSync11(join10(candidate, "package.json"))) return candidate;
2931
+ const parent = dirname8(dir);
2932
+ if (parent === dir) break;
2933
+ dir = parent;
2934
+ }
2935
+ return null;
2936
+ }
2937
+ function getUilintEslintPackageRoot() {
2938
+ const fromCwd = findNodeModulesPackageRoot("uilint-eslint", process.cwd());
2939
+ if (fromCwd) return fromCwd;
2940
+ const fromHere = findNodeModulesPackageRoot("uilint-eslint", __dirname2);
2941
+ if (fromHere) return fromHere;
2942
+ try {
2943
+ const entry = require2.resolve("uilint-eslint");
2944
+ const entryDir = dirname8(entry);
2945
+ return dirname8(entryDir);
2946
+ } catch (e) {
2947
+ const msg = e instanceof Error ? e.message : String(e);
2948
+ throw new Error(
2949
+ `Unable to locate uilint-eslint in node_modules (searched upwards from cwd and uilint's install path).
2950
+ Resolver error: ${msg}
2951
+ Fix: ensure uilint-eslint is installed in the target project (or workspace) and try again.`
2952
+ );
2953
+ }
2954
+ }
2955
+ function getUilintEslintSrcDir() {
2956
+ const devPath = join10(
2957
+ __dirname2,
2958
+ "..",
2959
+ "..",
2960
+ "..",
2961
+ "..",
2962
+ "uilint-eslint",
2963
+ "src"
2964
+ );
2965
+ if (existsSync11(devPath)) return devPath;
2966
+ const pkgRoot = getUilintEslintPackageRoot();
2967
+ const srcPath = join10(pkgRoot, "src");
2968
+ if (existsSync11(srcPath)) return srcPath;
2969
+ throw new Error(
2970
+ 'Could not find uilint-eslint "src/" directory. If you are using a published install of uilint-eslint, ensure it includes source files, or run a JS-only rules install.'
2971
+ );
2972
+ }
2973
+ function getUilintEslintDistDir() {
2974
+ const devPath = join10(
2975
+ __dirname2,
2976
+ "..",
2977
+ "..",
2978
+ "..",
2979
+ "..",
2980
+ "uilint-eslint",
2981
+ "dist"
2982
+ );
2983
+ if (existsSync11(devPath)) return devPath;
2984
+ const pkgRoot = getUilintEslintPackageRoot();
2985
+ const distPath = join10(pkgRoot, "dist");
2986
+ if (existsSync11(distPath)) return distPath;
2987
+ throw new Error(
2988
+ 'Could not find uilint-eslint "dist/" directory. This is a bug in uilint installation.'
2989
+ );
2990
+ }
2991
+ function transformRuleContent(content) {
2992
+ let transformed = content;
2993
+ transformed = transformed.replace(
2994
+ /import\s+{\s*createRule\s*}\s+from\s+["']\.\.\/utils\/create-rule\.js["'];?/g,
2995
+ 'import { createRule } from "uilint-eslint";'
2996
+ );
2997
+ transformed = transformed.replace(
2998
+ /import\s+createRule\s+from\s+["']\.\.\/utils\/create-rule\.js["'];?/g,
2999
+ 'import { createRule } from "uilint-eslint";'
3000
+ );
3001
+ transformed = transformed.replace(
3002
+ /import\s+{([^}]+)}\s+from\s+["']\.\.\/utils\/([^"']+)\.js["'];?/g,
3003
+ (match, imports, utilFile) => {
3004
+ const utilsFromPackage = ["cache", "styleguide-loader", "import-graph"];
3005
+ if (utilsFromPackage.includes(utilFile)) {
3006
+ return `import {${imports}} from "uilint-eslint";`;
3007
+ }
3008
+ return match;
3009
+ }
3010
+ );
3011
+ return transformed;
3012
+ }
3013
+ function loadRule(ruleId, options = { typescript: true }) {
3014
+ const { typescript } = options;
3015
+ const extension = typescript ? ".ts" : ".js";
3016
+ if (typescript) {
3017
+ const rulesDir = join10(getUilintEslintSrcDir(), "rules");
3018
+ const implPath = join10(rulesDir, `${ruleId}.ts`);
3019
+ const testPath = join10(rulesDir, `${ruleId}.test.ts`);
3020
+ if (!existsSync11(implPath)) {
3021
+ throw new Error(`Rule "${ruleId}" not found at ${implPath}`);
3022
+ }
3023
+ const rawContent = readFileSync7(implPath, "utf-8");
3024
+ const transformedContent = transformRuleContent(rawContent);
3025
+ const implementation = {
3026
+ relativePath: `${ruleId}.ts`,
3027
+ content: transformedContent
3028
+ };
3029
+ const test = existsSync11(testPath) ? {
3030
+ relativePath: `${ruleId}.test.ts`,
3031
+ content: transformRuleContent(readFileSync7(testPath, "utf-8"))
3032
+ } : void 0;
3033
+ return {
3034
+ ruleId,
3035
+ implementation,
3036
+ test
3037
+ };
3038
+ } else {
3039
+ const rulesDir = join10(getUilintEslintDistDir(), "rules");
3040
+ const implPath = join10(rulesDir, `${ruleId}.js`);
3041
+ if (!existsSync11(implPath)) {
3042
+ throw new Error(
3043
+ `Rule "${ruleId}" not found at ${implPath}. For JavaScript-only projects, uilint-eslint must be built to include compiled rule files in dist/rules/. If you're developing uilint-eslint, run 'pnpm build' in packages/uilint-eslint. If you're using a published package, ensure it includes the dist/ directory.`
3044
+ );
3045
+ }
3046
+ const content = readFileSync7(implPath, "utf-8");
3047
+ const implementation = {
3048
+ relativePath: `${ruleId}.js`,
3049
+ content
3050
+ };
3051
+ return {
3052
+ ruleId,
3053
+ implementation
3054
+ };
3055
+ }
3056
+ }
3057
+ function loadSelectedRules(ruleIds, options = { typescript: true }) {
3058
+ return ruleIds.map((id) => loadRule(id, options));
3059
+ }
3060
+
3061
+ // src/commands/install/plan.ts
3062
+ var require3 = createRequire2(import.meta.url);
2926
3063
  function getSelfDependencyVersionRange(pkgName) {
2927
3064
  try {
2928
- const pkgJson = require2("uilint/package.json");
3065
+ const pkgJson = require3("uilint/package.json");
2929
3066
  const deps = pkgJson?.dependencies;
2930
3067
  const optDeps = pkgJson?.optionalDependencies;
2931
3068
  const peerDeps = pkgJson?.peerDependencies;
@@ -3000,7 +3137,7 @@ function createPlan(state, choices, options = {}) {
3000
3137
  }
3001
3138
  }
3002
3139
  if (items.includes("hooks")) {
3003
- const hooksDir = join10(state.cursorDir.path, "hooks");
3140
+ const hooksDir = join11(state.cursorDir.path, "hooks");
3004
3141
  actions.push({
3005
3142
  type: "create_directory",
3006
3143
  path: hooksDir
@@ -3026,63 +3163,66 @@ function createPlan(state, choices, options = {}) {
3026
3163
  });
3027
3164
  actions.push({
3028
3165
  type: "create_file",
3029
- path: join10(hooksDir, "uilint-session-start.sh"),
3166
+ path: join11(hooksDir, "uilint-session-start.sh"),
3030
3167
  content: SESSION_START_SCRIPT,
3031
3168
  permissions: 493
3032
3169
  });
3033
3170
  actions.push({
3034
3171
  type: "create_file",
3035
- path: join10(hooksDir, "uilint-track.sh"),
3172
+ path: join11(hooksDir, "uilint-track.sh"),
3036
3173
  content: TRACK_SCRIPT,
3037
3174
  permissions: 493
3038
3175
  });
3039
3176
  actions.push({
3040
3177
  type: "create_file",
3041
- path: join10(hooksDir, "uilint-session-end.sh"),
3178
+ path: join11(hooksDir, "uilint-session-end.sh"),
3042
3179
  content: SESSION_END_SCRIPT,
3043
3180
  permissions: 493
3044
3181
  });
3045
3182
  }
3046
3183
  if (items.includes("genstyleguide")) {
3047
- const commandsDir = join10(state.cursorDir.path, "commands");
3184
+ const commandsDir = join11(state.cursorDir.path, "commands");
3048
3185
  actions.push({
3049
3186
  type: "create_directory",
3050
3187
  path: commandsDir
3051
3188
  });
3052
3189
  actions.push({
3053
3190
  type: "create_file",
3054
- path: join10(commandsDir, "genstyleguide.md"),
3191
+ path: join11(commandsDir, "genstyleguide.md"),
3055
3192
  content: GENSTYLEGUIDE_COMMAND_MD
3056
3193
  });
3057
3194
  }
3058
3195
  if (items.includes("genrules")) {
3059
- const commandsDir = join10(state.cursorDir.path, "commands");
3196
+ const commandsDir = join11(state.cursorDir.path, "commands");
3060
3197
  actions.push({
3061
3198
  type: "create_directory",
3062
3199
  path: commandsDir
3063
3200
  });
3064
3201
  actions.push({
3065
3202
  type: "create_file",
3066
- path: join10(commandsDir, "genrules.md"),
3203
+ path: join11(commandsDir, "genrules.md"),
3067
3204
  content: GENRULES_COMMAND_MD
3068
3205
  });
3069
3206
  }
3070
3207
  if (items.includes("skill")) {
3071
- const skillsDir = join10(state.cursorDir.path, "skills");
3208
+ const skillsDir = join11(state.cursorDir.path, "skills");
3072
3209
  actions.push({
3073
3210
  type: "create_directory",
3074
3211
  path: skillsDir
3075
3212
  });
3076
3213
  try {
3077
3214
  const skill = loadSkill("ui-consistency-enforcer");
3078
- const skillDir = join10(skillsDir, skill.name);
3215
+ const skillDir = join11(skillsDir, skill.name);
3079
3216
  actions.push({
3080
3217
  type: "create_directory",
3081
3218
  path: skillDir
3082
3219
  });
3083
3220
  for (const file of skill.files) {
3084
- const filePath = join10(skillDir, file.relativePath);
3085
- const fileDir = join10(skillDir, file.relativePath.split("/").slice(0, -1).join("/"));
3221
+ const filePath = join11(skillDir, file.relativePath);
3222
+ const fileDir = join11(
3223
+ skillDir,
3224
+ file.relativePath.split("/").slice(0, -1).join("/")
3225
+ );
3086
3226
  if (fileDir !== skillDir && file.relativePath.includes("/")) {
3087
3227
  actions.push({
3088
3228
  type: "create_directory",
@@ -3142,6 +3282,32 @@ function createPlan(state, choices, options = {}) {
3142
3282
  const { packagePaths, selectedRules } = choices.eslint;
3143
3283
  for (const pkgPath of packagePaths) {
3144
3284
  const pkgInfo = state.packages.find((p2) => p2.path === pkgPath);
3285
+ const rulesDir = join11(pkgPath, ".uilint", "rules");
3286
+ actions.push({
3287
+ type: "create_directory",
3288
+ path: rulesDir
3289
+ });
3290
+ const isTypeScript = pkgInfo?.isTypeScript ?? true;
3291
+ const ruleFiles = loadSelectedRules(
3292
+ selectedRules.map((r) => r.id),
3293
+ {
3294
+ typescript: isTypeScript
3295
+ }
3296
+ );
3297
+ for (const ruleFile of ruleFiles) {
3298
+ actions.push({
3299
+ type: "create_file",
3300
+ path: join11(rulesDir, ruleFile.implementation.relativePath),
3301
+ content: ruleFile.implementation.content
3302
+ });
3303
+ if (ruleFile.test && isTypeScript) {
3304
+ actions.push({
3305
+ type: "create_file",
3306
+ path: join11(rulesDir, ruleFile.test.relativePath),
3307
+ content: ruleFile.test.content
3308
+ });
3309
+ }
3310
+ }
3145
3311
  dependencies.push({
3146
3312
  packagePath: pkgPath,
3147
3313
  packageManager: state.packageManager,
@@ -3157,7 +3323,7 @@ function createPlan(state, choices, options = {}) {
3157
3323
  });
3158
3324
  }
3159
3325
  }
3160
- const gitignorePath = join10(state.workspaceRoot, ".gitignore");
3326
+ const gitignorePath = join11(state.workspaceRoot, ".gitignore");
3161
3327
  actions.push({
3162
3328
  type: "append_to_file",
3163
3329
  path: gitignorePath,
@@ -3170,49 +3336,49 @@ function createPlan(state, choices, options = {}) {
3170
3336
 
3171
3337
  // src/commands/install/execute.ts
3172
3338
  import {
3173
- existsSync as existsSync15,
3339
+ existsSync as existsSync16,
3174
3340
  mkdirSync as mkdirSync3,
3175
3341
  writeFileSync as writeFileSync7,
3176
- readFileSync as readFileSync10,
3342
+ readFileSync as readFileSync11,
3177
3343
  unlinkSync,
3178
3344
  chmodSync
3179
3345
  } from "fs";
3180
- import { dirname as dirname7 } from "path";
3346
+ import { dirname as dirname9 } from "path";
3181
3347
 
3182
3348
  // src/utils/react-inject.ts
3183
- import { existsSync as existsSync11, readFileSync as readFileSync7, writeFileSync as writeFileSync4 } from "fs";
3184
- import { join as join11 } from "path";
3349
+ import { existsSync as existsSync12, readFileSync as readFileSync8, writeFileSync as writeFileSync4 } from "fs";
3350
+ import { join as join12 } from "path";
3185
3351
  import { parseModule as parseModule2, generateCode as generateCode2 } from "magicast";
3186
3352
  function getDefaultCandidates(projectPath, appRoot) {
3187
3353
  const viteMainCandidates = [
3188
- join11(appRoot, "main.tsx"),
3189
- join11(appRoot, "main.jsx"),
3190
- join11(appRoot, "main.ts"),
3191
- join11(appRoot, "main.js")
3354
+ join12(appRoot, "main.tsx"),
3355
+ join12(appRoot, "main.jsx"),
3356
+ join12(appRoot, "main.ts"),
3357
+ join12(appRoot, "main.js")
3192
3358
  ];
3193
3359
  const existingViteMain = viteMainCandidates.filter(
3194
- (rel) => existsSync11(join11(projectPath, rel))
3360
+ (rel) => existsSync12(join12(projectPath, rel))
3195
3361
  );
3196
3362
  if (existingViteMain.length > 0) return existingViteMain;
3197
- const viteAppCandidates = [join11(appRoot, "App.tsx"), join11(appRoot, "App.jsx")];
3363
+ const viteAppCandidates = [join12(appRoot, "App.tsx"), join12(appRoot, "App.jsx")];
3198
3364
  const existingViteApp = viteAppCandidates.filter(
3199
- (rel) => existsSync11(join11(projectPath, rel))
3365
+ (rel) => existsSync12(join12(projectPath, rel))
3200
3366
  );
3201
3367
  if (existingViteApp.length > 0) return existingViteApp;
3202
3368
  const layoutCandidates = [
3203
- join11(appRoot, "layout.tsx"),
3204
- join11(appRoot, "layout.jsx"),
3205
- join11(appRoot, "layout.ts"),
3206
- join11(appRoot, "layout.js")
3369
+ join12(appRoot, "layout.tsx"),
3370
+ join12(appRoot, "layout.jsx"),
3371
+ join12(appRoot, "layout.ts"),
3372
+ join12(appRoot, "layout.js")
3207
3373
  ];
3208
3374
  const existingLayouts = layoutCandidates.filter(
3209
- (rel) => existsSync11(join11(projectPath, rel))
3375
+ (rel) => existsSync12(join12(projectPath, rel))
3210
3376
  );
3211
3377
  if (existingLayouts.length > 0) {
3212
3378
  return existingLayouts;
3213
3379
  }
3214
- const pageCandidates = [join11(appRoot, "page.tsx"), join11(appRoot, "page.jsx")];
3215
- return pageCandidates.filter((rel) => existsSync11(join11(projectPath, rel)));
3380
+ const pageCandidates = [join12(appRoot, "page.tsx"), join12(appRoot, "page.jsx")];
3381
+ return pageCandidates.filter((rel) => existsSync12(join12(projectPath, rel)));
3216
3382
  }
3217
3383
  function isUseClientDirective(stmt) {
3218
3384
  return stmt?.type === "ExpressionStatement" && stmt.expression?.type === "StringLiteral" && stmt.expression.value === "use client";
@@ -3225,16 +3391,16 @@ function findImportDeclaration(program2, from) {
3225
3391
  }
3226
3392
  return null;
3227
3393
  }
3228
- function walkAst2(node, visit) {
3394
+ function walkAst(node, visit) {
3229
3395
  if (!node || typeof node !== "object") return;
3230
3396
  if (node.type) visit(node);
3231
3397
  for (const key of Object.keys(node)) {
3232
3398
  const v = node[key];
3233
3399
  if (!v) continue;
3234
3400
  if (Array.isArray(v)) {
3235
- for (const item of v) walkAst2(item, visit);
3401
+ for (const item of v) walkAst(item, visit);
3236
3402
  } else if (typeof v === "object" && v.type) {
3237
- walkAst2(v, visit);
3403
+ walkAst(v, visit);
3238
3404
  }
3239
3405
  }
3240
3406
  }
@@ -3266,7 +3432,7 @@ function ensureNamedImport(program2, from, name) {
3266
3432
  }
3267
3433
  function hasUILintProviderJsx(program2) {
3268
3434
  let found = false;
3269
- walkAst2(program2, (node) => {
3435
+ walkAst(program2, (node) => {
3270
3436
  if (found) return;
3271
3437
  if (node.type !== "JSXElement") return;
3272
3438
  const name = node.openingElement?.name;
@@ -3286,7 +3452,7 @@ function wrapFirstChildrenExpressionWithProvider(program2) {
3286
3452
  if (!providerJsx || providerJsx.type !== "JSXElement")
3287
3453
  return { changed: false };
3288
3454
  let replaced = false;
3289
- walkAst2(program2, (node) => {
3455
+ walkAst(program2, (node) => {
3290
3456
  if (replaced) return;
3291
3457
  if (node.type === "JSXExpressionContainer" && node.expression?.type === "Identifier" && node.expression.name === "children") {
3292
3458
  Object.keys(node).forEach((k) => delete node[k]);
@@ -3310,7 +3476,7 @@ function wrapFirstRenderCallArgumentWithProvider(program2) {
3310
3476
  return { changed: false };
3311
3477
  providerJsx.children = providerJsx.children ?? [];
3312
3478
  let wrapped = false;
3313
- walkAst2(program2, (node) => {
3479
+ walkAst(program2, (node) => {
3314
3480
  if (wrapped) return;
3315
3481
  if (node.type !== "CallExpression") return;
3316
3482
  const callee = node.callee;
@@ -3345,8 +3511,8 @@ async function installReactUILintOverlay(opts) {
3345
3511
  } else {
3346
3512
  chosen = candidates[0];
3347
3513
  }
3348
- const absTarget = join11(opts.projectPath, chosen);
3349
- const original = readFileSync7(absTarget, "utf-8");
3514
+ const absTarget = join12(opts.projectPath, chosen);
3515
+ const original = readFileSync8(absTarget, "utf-8");
3350
3516
  let mod;
3351
3517
  try {
3352
3518
  mod = parseModule2(original);
@@ -3380,14 +3546,14 @@ async function installReactUILintOverlay(opts) {
3380
3546
  }
3381
3547
 
3382
3548
  // src/utils/next-config-inject.ts
3383
- import { existsSync as existsSync12, readFileSync as readFileSync8, writeFileSync as writeFileSync5 } from "fs";
3384
- import { join as join12 } from "path";
3549
+ import { existsSync as existsSync13, readFileSync as readFileSync9, writeFileSync as writeFileSync5 } from "fs";
3550
+ import { join as join13 } from "path";
3385
3551
  import { parseModule as parseModule3, generateCode as generateCode3 } from "magicast";
3386
3552
  var CONFIG_EXTENSIONS2 = [".ts", ".mjs", ".js", ".cjs"];
3387
3553
  function findNextConfigFile(projectPath) {
3388
3554
  for (const ext of CONFIG_EXTENSIONS2) {
3389
- const configPath = join12(projectPath, `next.config${ext}`);
3390
- if (existsSync12(configPath)) {
3555
+ const configPath = join13(projectPath, `next.config${ext}`);
3556
+ if (existsSync13(configPath)) {
3391
3557
  return configPath;
3392
3558
  }
3393
3559
  }
@@ -3500,7 +3666,7 @@ async function installJsxLocPlugin(opts) {
3500
3666
  return { configFile: null, modified: false };
3501
3667
  }
3502
3668
  const configFilename = getNextConfigFilename(configPath);
3503
- const original = readFileSync8(configPath, "utf-8");
3669
+ const original = readFileSync9(configPath, "utf-8");
3504
3670
  let mod;
3505
3671
  try {
3506
3672
  mod = parseModule3(original);
@@ -3530,14 +3696,14 @@ async function installJsxLocPlugin(opts) {
3530
3696
  }
3531
3697
 
3532
3698
  // src/utils/vite-config-inject.ts
3533
- import { existsSync as existsSync13, readFileSync as readFileSync9, writeFileSync as writeFileSync6 } from "fs";
3534
- import { join as join13 } from "path";
3699
+ import { existsSync as existsSync14, readFileSync as readFileSync10, writeFileSync as writeFileSync6 } from "fs";
3700
+ import { join as join14 } from "path";
3535
3701
  import { parseModule as parseModule4, generateCode as generateCode4 } from "magicast";
3536
3702
  var CONFIG_EXTENSIONS3 = [".ts", ".mjs", ".js", ".cjs"];
3537
3703
  function findViteConfigFile2(projectPath) {
3538
3704
  for (const ext of CONFIG_EXTENSIONS3) {
3539
- const configPath = join13(projectPath, `vite.config${ext}`);
3540
- if (existsSync13(configPath)) return configPath;
3705
+ const configPath = join14(projectPath, `vite.config${ext}`);
3706
+ if (existsSync14(configPath)) return configPath;
3541
3707
  }
3542
3708
  return null;
3543
3709
  }
@@ -3712,7 +3878,7 @@ async function installViteJsxLocPlugin(opts) {
3712
3878
  const configPath = findViteConfigFile2(opts.projectPath);
3713
3879
  if (!configPath) return { configFile: null, modified: false };
3714
3880
  const configFilename = getViteConfigFilename(configPath);
3715
- const original = readFileSync9(configPath, "utf-8");
3881
+ const original = readFileSync10(configPath, "utf-8");
3716
3882
  const isCjs = configPath.endsWith(".cjs");
3717
3883
  let mod;
3718
3884
  try {
@@ -3741,9 +3907,9 @@ async function installViteJsxLocPlugin(opts) {
3741
3907
  }
3742
3908
 
3743
3909
  // src/utils/next-routes.ts
3744
- import { existsSync as existsSync14 } from "fs";
3910
+ import { existsSync as existsSync15 } from "fs";
3745
3911
  import { mkdir, writeFile } from "fs/promises";
3746
- import { join as join14 } from "path";
3912
+ import { join as join15 } from "path";
3747
3913
  var DEV_SOURCE_ROUTE_TS = `/**
3748
3914
  * Dev-only API route for fetching source files
3749
3915
  *
@@ -4199,23 +4365,23 @@ export async function GET(request: NextRequest) {
4199
4365
  }
4200
4366
  `;
4201
4367
  async function writeRouteFile(absPath, relPath, content, opts) {
4202
- if (existsSync14(absPath) && !opts.force) return;
4368
+ if (existsSync15(absPath) && !opts.force) return;
4203
4369
  await writeFile(absPath, content, "utf-8");
4204
4370
  }
4205
4371
  async function installNextUILintRoutes(opts) {
4206
- const baseRel = join14(opts.appRoot, "api", ".uilint");
4207
- const baseAbs = join14(opts.projectPath, baseRel);
4208
- await mkdir(join14(baseAbs, "source"), { recursive: true });
4372
+ const baseRel = join15(opts.appRoot, "api", ".uilint");
4373
+ const baseAbs = join15(opts.projectPath, baseRel);
4374
+ await mkdir(join15(baseAbs, "source"), { recursive: true });
4209
4375
  await writeRouteFile(
4210
- join14(baseAbs, "source", "route.ts"),
4211
- join14(baseRel, "source", "route.ts"),
4376
+ join15(baseAbs, "source", "route.ts"),
4377
+ join15(baseRel, "source", "route.ts"),
4212
4378
  DEV_SOURCE_ROUTE_TS,
4213
4379
  opts
4214
4380
  );
4215
- await mkdir(join14(baseAbs, "screenshots"), { recursive: true });
4381
+ await mkdir(join15(baseAbs, "screenshots"), { recursive: true });
4216
4382
  await writeRouteFile(
4217
- join14(baseAbs, "screenshots", "route.ts"),
4218
- join14(baseRel, "screenshots", "route.ts"),
4383
+ join15(baseAbs, "screenshots", "route.ts"),
4384
+ join15(baseRel, "screenshots", "route.ts"),
4219
4385
  SCREENSHOT_ROUTE_TS,
4220
4386
  opts
4221
4387
  );
@@ -4234,7 +4400,7 @@ async function executeAction(action, options) {
4234
4400
  wouldDo: `Create directory: ${action.path}`
4235
4401
  };
4236
4402
  }
4237
- if (!existsSync15(action.path)) {
4403
+ if (!existsSync16(action.path)) {
4238
4404
  mkdirSync3(action.path, { recursive: true });
4239
4405
  }
4240
4406
  return { action, success: true };
@@ -4247,8 +4413,8 @@ async function executeAction(action, options) {
4247
4413
  wouldDo: `Create file: ${action.path}${action.permissions ? ` (mode: ${action.permissions.toString(8)})` : ""}`
4248
4414
  };
4249
4415
  }
4250
- const dir = dirname7(action.path);
4251
- if (!existsSync15(dir)) {
4416
+ const dir = dirname9(action.path);
4417
+ if (!existsSync16(dir)) {
4252
4418
  mkdirSync3(dir, { recursive: true });
4253
4419
  }
4254
4420
  writeFileSync7(action.path, action.content, "utf-8");
@@ -4266,15 +4432,15 @@ async function executeAction(action, options) {
4266
4432
  };
4267
4433
  }
4268
4434
  let existing = {};
4269
- if (existsSync15(action.path)) {
4435
+ if (existsSync16(action.path)) {
4270
4436
  try {
4271
- existing = JSON.parse(readFileSync10(action.path, "utf-8"));
4437
+ existing = JSON.parse(readFileSync11(action.path, "utf-8"));
4272
4438
  } catch {
4273
4439
  }
4274
4440
  }
4275
4441
  const merged = deepMerge(existing, action.merge);
4276
- const dir = dirname7(action.path);
4277
- if (!existsSync15(dir)) {
4442
+ const dir = dirname9(action.path);
4443
+ if (!existsSync16(dir)) {
4278
4444
  mkdirSync3(dir, { recursive: true });
4279
4445
  }
4280
4446
  writeFileSync7(action.path, JSON.stringify(merged, null, 2), "utf-8");
@@ -4288,7 +4454,7 @@ async function executeAction(action, options) {
4288
4454
  wouldDo: `Delete file: ${action.path}`
4289
4455
  };
4290
4456
  }
4291
- if (existsSync15(action.path)) {
4457
+ if (existsSync16(action.path)) {
4292
4458
  unlinkSync(action.path);
4293
4459
  }
4294
4460
  return { action, success: true };
@@ -4301,8 +4467,8 @@ async function executeAction(action, options) {
4301
4467
  wouldDo: `Append to file: ${action.path}`
4302
4468
  };
4303
4469
  }
4304
- if (existsSync15(action.path)) {
4305
- const content = readFileSync10(action.path, "utf-8");
4470
+ if (existsSync16(action.path)) {
4471
+ const content = readFileSync11(action.path, "utf-8");
4306
4472
  if (action.ifNotContains && content.includes(action.ifNotContains)) {
4307
4473
  return { action, success: true };
4308
4474
  }
@@ -4988,7 +5154,7 @@ function displayResults(result) {
4988
5154
  if (summary.nextApp) {
4989
5155
  installedItems.push(
4990
5156
  `${pc.cyan("Next Routes")} \u2192 ${pc.dim(
4991
- join15(summary.nextApp.appRoot, "api/.uilint")
5157
+ join16(summary.nextApp.appRoot, "api/.uilint")
4992
5158
  )}`
4993
5159
  );
4994
5160
  installedItems.push(
@@ -5123,19 +5289,19 @@ async function install(options = {}, prompter = cliPrompter, executeOptions = {}
5123
5289
  }
5124
5290
 
5125
5291
  // src/commands/serve.ts
5126
- import { existsSync as existsSync17, statSync as statSync4, readdirSync as readdirSync5, readFileSync as readFileSync11 } from "fs";
5127
- import { createRequire as createRequire2 } from "module";
5128
- import { dirname as dirname9, resolve as resolve5, relative as relative3, join as join17, parse as parse2 } from "path";
5292
+ import { existsSync as existsSync18, statSync as statSync4, readdirSync as readdirSync5, readFileSync as readFileSync12 } from "fs";
5293
+ import { createRequire as createRequire3 } from "module";
5294
+ import { dirname as dirname11, resolve as resolve5, relative as relative4, join as join18, parse as parse2 } from "path";
5129
5295
  import { WebSocketServer, WebSocket } from "ws";
5130
5296
  import { watch } from "chokidar";
5131
5297
  import {
5132
- findWorkspaceRoot as findWorkspaceRoot5,
5298
+ findWorkspaceRoot as findWorkspaceRoot6,
5133
5299
  getVisionAnalyzer as getCoreVisionAnalyzer
5134
5300
  } from "uilint-core/node";
5135
5301
 
5136
5302
  // src/utils/vision-run.ts
5137
- import { dirname as dirname8, join as join16, parse } from "path";
5138
- import { existsSync as existsSync16, statSync as statSync3, mkdirSync as mkdirSync4, writeFileSync as writeFileSync8 } from "fs";
5303
+ import { dirname as dirname10, join as join17, parse } from "path";
5304
+ import { existsSync as existsSync17, statSync as statSync3, mkdirSync as mkdirSync4, writeFileSync as writeFileSync8 } from "fs";
5139
5305
  import {
5140
5306
  ensureOllamaReady as ensureOllamaReady5,
5141
5307
  findStyleGuidePath as findStyleGuidePath4,
@@ -5149,7 +5315,7 @@ async function resolveVisionStyleGuide(args) {
5149
5315
  const startDir = args.startDir ?? projectPath;
5150
5316
  if (args.styleguide) {
5151
5317
  const styleguideArg = resolvePathSpecifier(args.styleguide, projectPath);
5152
- if (existsSync16(styleguideArg)) {
5318
+ if (existsSync17(styleguideArg)) {
5153
5319
  const stat = statSync3(styleguideArg);
5154
5320
  if (stat.isFile()) {
5155
5321
  return {
@@ -5193,7 +5359,7 @@ function writeVisionDebugDump(params) {
5193
5359
  );
5194
5360
  const safeStamp = params.now.toISOString().replace(/[:.]/g, "-");
5195
5361
  const dumpFile = resolvedDirOrFile.endsWith(".json") || resolvedDirOrFile.endsWith(".jsonl") ? resolvedDirOrFile : `${resolvedDirOrFile}/vision-debug-${safeStamp}.json`;
5196
- mkdirSync4(dirname8(dumpFile), { recursive: true });
5362
+ mkdirSync4(dirname10(dumpFile), { recursive: true });
5197
5363
  writeFileSync8(
5198
5364
  dumpFile,
5199
5365
  JSON.stringify(
@@ -5282,7 +5448,7 @@ async function runVisionAnalysis(args) {
5282
5448
  }
5283
5449
  function writeVisionMarkdownReport(args) {
5284
5450
  const p2 = parse(args.imagePath);
5285
- const outPath = args.outPath ?? join16(p2.dir, `${p2.name || p2.base}.vision.md`);
5451
+ const outPath = args.outPath ?? join17(p2.dir, `${p2.name || p2.base}.vision.md`);
5286
5452
  const lines = [];
5287
5453
  lines.push(`# UILint Vision Report`);
5288
5454
  lines.push(``);
@@ -5318,7 +5484,7 @@ function writeVisionMarkdownReport(args) {
5318
5484
  lines.push("```");
5319
5485
  lines.push(``);
5320
5486
  const content = lines.join("\n");
5321
- mkdirSync4(dirname8(outPath), { recursive: true });
5487
+ mkdirSync4(dirname10(outPath), { recursive: true });
5322
5488
  writeFileSync8(outPath, content, "utf-8");
5323
5489
  return { outPath, content };
5324
5490
  }
@@ -5354,7 +5520,7 @@ var resolvedPathCache = /* @__PURE__ */ new Map();
5354
5520
  var subscriptions = /* @__PURE__ */ new Map();
5355
5521
  var fileWatcher = null;
5356
5522
  var connectedClients = 0;
5357
- var localRequire = createRequire2(import.meta.url);
5523
+ var localRequire = createRequire3(import.meta.url);
5358
5524
  function buildLineStarts(code) {
5359
5525
  const starts = [0];
5360
5526
  for (let i = 0; i < code.length; i++) {
@@ -5432,10 +5598,10 @@ function findESLintCwd(startDir) {
5432
5598
  let dir = startDir;
5433
5599
  for (let i = 0; i < 30; i++) {
5434
5600
  for (const cfg of ESLINT_CONFIG_FILES2) {
5435
- if (existsSync17(join17(dir, cfg))) return dir;
5601
+ if (existsSync18(join18(dir, cfg))) return dir;
5436
5602
  }
5437
- if (existsSync17(join17(dir, "package.json"))) return dir;
5438
- const parent = dirname9(dir);
5603
+ if (existsSync18(join18(dir, "package.json"))) return dir;
5604
+ const parent = dirname11(dir);
5439
5605
  if (parent === dir) break;
5440
5606
  dir = parent;
5441
5607
  }
@@ -5448,7 +5614,7 @@ function normalizeDataLocFilePath(absoluteFilePath, projectCwd) {
5448
5614
  const abs = normalizePathSlashes(resolve5(absoluteFilePath));
5449
5615
  const cwd = normalizePathSlashes(resolve5(projectCwd));
5450
5616
  if (abs === cwd || abs.startsWith(cwd + "/")) {
5451
- return normalizePathSlashes(relative3(cwd, abs));
5617
+ return normalizePathSlashes(relative4(cwd, abs));
5452
5618
  }
5453
5619
  return abs;
5454
5620
  }
@@ -5460,25 +5626,25 @@ function resolveRequestedFilePath(filePath) {
5460
5626
  if (cached) return cached;
5461
5627
  const cwd = process.cwd();
5462
5628
  const fromCwd = resolve5(cwd, filePath);
5463
- if (existsSync17(fromCwd)) {
5629
+ if (existsSync18(fromCwd)) {
5464
5630
  resolvedPathCache.set(filePath, fromCwd);
5465
5631
  return fromCwd;
5466
5632
  }
5467
- const wsRoot = findWorkspaceRoot5(cwd);
5633
+ const wsRoot = findWorkspaceRoot6(cwd);
5468
5634
  const fromWs = resolve5(wsRoot, filePath);
5469
- if (existsSync17(fromWs)) {
5635
+ if (existsSync18(fromWs)) {
5470
5636
  resolvedPathCache.set(filePath, fromWs);
5471
5637
  return fromWs;
5472
5638
  }
5473
5639
  for (const top of ["apps", "packages"]) {
5474
- const base = join17(wsRoot, top);
5475
- if (!existsSync17(base)) continue;
5640
+ const base = join18(wsRoot, top);
5641
+ if (!existsSync18(base)) continue;
5476
5642
  try {
5477
5643
  const entries = readdirSync5(base, { withFileTypes: true });
5478
5644
  for (const ent of entries) {
5479
5645
  if (!ent.isDirectory()) continue;
5480
5646
  const p2 = resolve5(base, ent.name, filePath);
5481
- if (existsSync17(p2)) {
5647
+ if (existsSync18(p2)) {
5482
5648
  resolvedPathCache.set(filePath, p2);
5483
5649
  return p2;
5484
5650
  }
@@ -5493,7 +5659,7 @@ async function getESLintForProject(projectCwd) {
5493
5659
  const cached = eslintInstances.get(projectCwd);
5494
5660
  if (cached) return cached;
5495
5661
  try {
5496
- const req = createRequire2(join17(projectCwd, "package.json"));
5662
+ const req = createRequire3(join18(projectCwd, "package.json"));
5497
5663
  const mod = req("eslint");
5498
5664
  const ESLintCtor = mod?.ESLint ?? mod?.default?.ESLint ?? mod?.default ?? mod;
5499
5665
  if (!ESLintCtor) return null;
@@ -5506,7 +5672,7 @@ async function getESLintForProject(projectCwd) {
5506
5672
  }
5507
5673
  async function lintFile(filePath, onProgress) {
5508
5674
  const absolutePath = resolveRequestedFilePath(filePath);
5509
- if (!existsSync17(absolutePath)) {
5675
+ if (!existsSync18(absolutePath)) {
5510
5676
  onProgress(`File not found: ${pc.dim(absolutePath)}`);
5511
5677
  return [];
5512
5678
  }
@@ -5522,7 +5688,7 @@ async function lintFile(filePath, onProgress) {
5522
5688
  onProgress("Cache hit (unchanged)");
5523
5689
  return cached.issues;
5524
5690
  }
5525
- const fileDir = dirname9(absolutePath);
5691
+ const fileDir = dirname11(absolutePath);
5526
5692
  const projectCwd = findESLintCwd(fileDir);
5527
5693
  onProgress(`Resolving ESLint project... ${pc.dim(projectCwd)}`);
5528
5694
  const eslint = await getESLintForProject(projectCwd);
@@ -5545,7 +5711,7 @@ async function lintFile(filePath, onProgress) {
5545
5711
  let codeLength = 0;
5546
5712
  try {
5547
5713
  onProgress("Building JSX map...");
5548
- const code = readFileSync11(absolutePath, "utf-8");
5714
+ const code = readFileSync12(absolutePath, "utf-8");
5549
5715
  codeLength = code.length;
5550
5716
  lineStarts = buildLineStarts(code);
5551
5717
  spans = buildJsxElementSpans(code, dataLocFile);
@@ -5627,9 +5793,9 @@ async function handleMessage(ws, data) {
5627
5793
  });
5628
5794
  const startedAt = Date.now();
5629
5795
  const resolved = resolveRequestedFilePath(filePath);
5630
- if (!existsSync17(resolved)) {
5796
+ if (!existsSync18(resolved)) {
5631
5797
  const cwd = process.cwd();
5632
- const wsRoot = findWorkspaceRoot5(cwd);
5798
+ const wsRoot = findWorkspaceRoot6(cwd);
5633
5799
  logWarning(
5634
5800
  [
5635
5801
  `${pc.dim("[ws]")} File not found for request`,
@@ -5789,14 +5955,14 @@ async function handleMessage(ws, data) {
5789
5955
  )}`
5790
5956
  );
5791
5957
  } else {
5792
- const screenshotsDir = join17(
5958
+ const screenshotsDir = join18(
5793
5959
  serverAppRootForVision,
5794
5960
  ".uilint",
5795
5961
  "screenshots"
5796
5962
  );
5797
- const imagePath = join17(screenshotsDir, screenshotFile);
5963
+ const imagePath = join18(screenshotsDir, screenshotFile);
5798
5964
  try {
5799
- if (!existsSync17(imagePath)) {
5965
+ if (!existsSync18(imagePath)) {
5800
5966
  logWarning(
5801
5967
  `Skipping vision report write: screenshot file not found ${pc.dim(
5802
5968
  imagePath
@@ -5904,7 +6070,7 @@ function handleFileChange(filePath) {
5904
6070
  async function serve(options) {
5905
6071
  const port = options.port || 9234;
5906
6072
  const cwd = process.cwd();
5907
- const wsRoot = findWorkspaceRoot5(cwd);
6073
+ const wsRoot = findWorkspaceRoot6(cwd);
5908
6074
  const appRoot = pickAppRoot({ cwd, workspaceRoot: wsRoot });
5909
6075
  serverAppRootForVision = appRoot;
5910
6076
  logInfo(`Workspace root: ${pc.dim(wsRoot)}`);
@@ -5957,10 +6123,10 @@ async function serve(options) {
5957
6123
  }
5958
6124
 
5959
6125
  // src/commands/vision.ts
5960
- import { dirname as dirname10, resolve as resolve6, join as join18 } from "path";
6126
+ import { dirname as dirname12, resolve as resolve6, join as join19 } from "path";
5961
6127
  import {
5962
- existsSync as existsSync18,
5963
- readFileSync as readFileSync12,
6128
+ existsSync as existsSync19,
6129
+ readFileSync as readFileSync13,
5964
6130
  readdirSync as readdirSync6
5965
6131
  } from "fs";
5966
6132
  import {
@@ -6006,17 +6172,17 @@ function debugLog3(enabled, message, obj) {
6006
6172
  function findScreenshotsDirUpwards(startDir) {
6007
6173
  let dir = startDir;
6008
6174
  for (let i = 0; i < 20; i++) {
6009
- const candidate = join18(dir, ".uilint", "screenshots");
6010
- if (existsSync18(candidate)) return candidate;
6011
- const parent = dirname10(dir);
6175
+ const candidate = join19(dir, ".uilint", "screenshots");
6176
+ if (existsSync19(candidate)) return candidate;
6177
+ const parent = dirname12(dir);
6012
6178
  if (parent === dir) break;
6013
6179
  dir = parent;
6014
6180
  }
6015
6181
  return null;
6016
6182
  }
6017
6183
  function listScreenshotSidecars(dirPath) {
6018
- if (!existsSync18(dirPath)) return [];
6019
- const entries = readdirSync6(dirPath).filter((f) => f.endsWith(".json")).map((f) => join18(dirPath, f));
6184
+ if (!existsSync19(dirPath)) return [];
6185
+ const entries = readdirSync6(dirPath).filter((f) => f.endsWith(".json")).map((f) => join19(dirPath, f));
6020
6186
  const out = [];
6021
6187
  for (const p2 of entries) {
6022
6188
  try {
@@ -6045,11 +6211,11 @@ function listScreenshotSidecars(dirPath) {
6045
6211
  return out;
6046
6212
  }
6047
6213
  function readImageAsBase64(imagePath) {
6048
- const bytes = readFileSync12(imagePath);
6214
+ const bytes = readFileSync13(imagePath);
6049
6215
  return { base64: bytes.toString("base64"), sizeBytes: bytes.byteLength };
6050
6216
  }
6051
6217
  function loadJsonFile(filePath) {
6052
- const raw = readFileSync12(filePath, "utf-8");
6218
+ const raw = readFileSync13(filePath, "utf-8");
6053
6219
  return JSON.parse(raw);
6054
6220
  }
6055
6221
  function formatIssuesText(issues) {
@@ -6123,13 +6289,13 @@ async function vision(options) {
6123
6289
  await flushLangfuse();
6124
6290
  process.exit(1);
6125
6291
  }
6126
- if (imagePath && !existsSync18(imagePath)) {
6292
+ if (imagePath && !existsSync19(imagePath)) {
6127
6293
  throw new Error(`Image not found: ${imagePath}`);
6128
6294
  }
6129
- if (sidecarPath && !existsSync18(sidecarPath)) {
6295
+ if (sidecarPath && !existsSync19(sidecarPath)) {
6130
6296
  throw new Error(`Sidecar not found: ${sidecarPath}`);
6131
6297
  }
6132
- if (manifestFilePath && !existsSync18(manifestFilePath)) {
6298
+ if (manifestFilePath && !existsSync19(manifestFilePath)) {
6133
6299
  throw new Error(`Manifest file not found: ${manifestFilePath}`);
6134
6300
  }
6135
6301
  const sidecar = sidecarPath ? loadJsonFile(sidecarPath) : null;
@@ -6154,7 +6320,7 @@ async function vision(options) {
6154
6320
  const resolved = await resolveVisionStyleGuide({
6155
6321
  projectPath,
6156
6322
  styleguide: options.styleguide,
6157
- startDir: startPath ? dirname10(startPath) : projectPath
6323
+ startDir: startPath ? dirname12(startPath) : projectPath
6158
6324
  });
6159
6325
  styleGuide = resolved.styleGuide;
6160
6326
  styleguideLocation = resolved.styleguideLocation;
@@ -6203,7 +6369,7 @@ async function vision(options) {
6203
6369
  const resolvedImagePath = imagePath || (() => {
6204
6370
  const screenshotFile = typeof sidecar?.screenshotFile === "string" ? sidecar.screenshotFile : typeof sidecar?.filename === "string" ? sidecar.filename : void 0;
6205
6371
  if (!screenshotFile) return null;
6206
- const baseDir = sidecarPath ? dirname10(sidecarPath) : projectPath;
6372
+ const baseDir = sidecarPath ? dirname12(sidecarPath) : projectPath;
6207
6373
  const abs = resolve6(baseDir, screenshotFile);
6208
6374
  return abs;
6209
6375
  })();
@@ -6212,7 +6378,7 @@ async function vision(options) {
6212
6378
  "No image path could be resolved. Provide --image or a sidecar with `screenshotFile`/`filename`."
6213
6379
  );
6214
6380
  }
6215
- if (!existsSync18(resolvedImagePath)) {
6381
+ if (!existsSync19(resolvedImagePath)) {
6216
6382
  throw new Error(`Image not found: ${resolvedImagePath}`);
6217
6383
  }
6218
6384
  const { base64, sizeBytes } = readImageAsBase64(resolvedImagePath);
@@ -6440,8 +6606,8 @@ async function vision(options) {
6440
6606
  }
6441
6607
 
6442
6608
  // src/commands/session.ts
6443
- import { existsSync as existsSync19, readFileSync as readFileSync13, writeFileSync as writeFileSync10, unlinkSync as unlinkSync2 } from "fs";
6444
- import { basename, dirname as dirname11, resolve as resolve7 } from "path";
6609
+ import { existsSync as existsSync20, readFileSync as readFileSync14, writeFileSync as writeFileSync10, unlinkSync as unlinkSync2 } from "fs";
6610
+ import { basename, dirname as dirname13, resolve as resolve7 } from "path";
6445
6611
  import { createStyleSummary as createStyleSummary3 } from "uilint-core";
6446
6612
  import {
6447
6613
  ensureOllamaReady as ensureOllamaReady7,
@@ -6452,11 +6618,11 @@ import {
6452
6618
  var SESSION_FILE = "/tmp/uilint-session.json";
6453
6619
  var UI_FILE_EXTENSIONS = [".tsx", ".jsx", ".css", ".scss", ".module.css"];
6454
6620
  function readSession() {
6455
- if (!existsSync19(SESSION_FILE)) {
6621
+ if (!existsSync20(SESSION_FILE)) {
6456
6622
  return { files: [], startedAt: (/* @__PURE__ */ new Date()).toISOString() };
6457
6623
  }
6458
6624
  try {
6459
- const content = readFileSync13(SESSION_FILE, "utf-8");
6625
+ const content = readFileSync14(SESSION_FILE, "utf-8");
6460
6626
  return JSON.parse(content);
6461
6627
  } catch {
6462
6628
  return { files: [], startedAt: (/* @__PURE__ */ new Date()).toISOString() };
@@ -6474,7 +6640,7 @@ function isScannableMarkupFile(filePath) {
6474
6640
  );
6475
6641
  }
6476
6642
  async function sessionClear() {
6477
- if (existsSync19(SESSION_FILE)) {
6643
+ if (existsSync20(SESSION_FILE)) {
6478
6644
  unlinkSync2(SESSION_FILE);
6479
6645
  }
6480
6646
  console.log(JSON.stringify({ cleared: true }));
@@ -6545,13 +6711,13 @@ async function sessionScan(options = {}) {
6545
6711
  const client = await createLLMClient({});
6546
6712
  const results = [];
6547
6713
  for (const filePath of session.files) {
6548
- if (!existsSync19(filePath)) continue;
6714
+ if (!existsSync20(filePath)) continue;
6549
6715
  if (!isScannableMarkupFile(filePath)) continue;
6550
6716
  try {
6551
6717
  const absolutePath = resolve7(process.cwd(), filePath);
6552
- const htmlLike = readFileSync13(filePath, "utf-8");
6718
+ const htmlLike = readFileSync14(filePath, "utf-8");
6553
6719
  const snapshot = parseCLIInput2(htmlLike);
6554
- const tailwindSearchDir = dirname11(absolutePath);
6720
+ const tailwindSearchDir = dirname13(absolutePath);
6555
6721
  const tailwindTheme = readTailwindThemeTokens3(tailwindSearchDir);
6556
6722
  const styleSummary = createStyleSummary3(snapshot.styles, {
6557
6723
  html: snapshot.html,
@@ -6604,7 +6770,7 @@ async function sessionScan(options = {}) {
6604
6770
  };
6605
6771
  console.log(JSON.stringify(result));
6606
6772
  }
6607
- if (existsSync19(SESSION_FILE)) {
6773
+ if (existsSync20(SESSION_FILE)) {
6608
6774
  unlinkSync2(SESSION_FILE);
6609
6775
  }
6610
6776
  await flushLangfuse();
@@ -6615,9 +6781,9 @@ async function sessionList() {
6615
6781
  }
6616
6782
 
6617
6783
  // src/index.ts
6618
- import { readFileSync as readFileSync14 } from "fs";
6619
- import { dirname as dirname12, join as join19 } from "path";
6620
- import { fileURLToPath as fileURLToPath3 } from "url";
6784
+ import { readFileSync as readFileSync15 } from "fs";
6785
+ import { dirname as dirname14, join as join20 } from "path";
6786
+ import { fileURLToPath as fileURLToPath4 } from "url";
6621
6787
  function assertNodeVersion(minMajor) {
6622
6788
  const ver = process.versions.node || "";
6623
6789
  const majorStr = ver.split(".")[0] || "";
@@ -6633,9 +6799,9 @@ assertNodeVersion(20);
6633
6799
  var program = new Command();
6634
6800
  function getCLIVersion2() {
6635
6801
  try {
6636
- const __dirname2 = dirname12(fileURLToPath3(import.meta.url));
6637
- const pkgPath = join19(__dirname2, "..", "package.json");
6638
- const pkg = JSON.parse(readFileSync14(pkgPath, "utf-8"));
6802
+ const __dirname3 = dirname14(fileURLToPath4(import.meta.url));
6803
+ const pkgPath = join20(__dirname3, "..", "package.json");
6804
+ const pkg = JSON.parse(readFileSync15(pkgPath, "utf-8"));
6639
6805
  return pkg.version || "0.0.0";
6640
6806
  } catch {
6641
6807
  return "0.0.0";