uilint 0.2.148 → 0.2.150

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
@@ -16,7 +16,7 @@ import {
16
16
  import {
17
17
  discoverPlugins,
18
18
  loadPluginESLintRules
19
- } from "./chunk-5QUW7BNW.js";
19
+ } from "./chunk-GFJDTSYD.js";
20
20
  import {
21
21
  createSpinner,
22
22
  intro,
@@ -2590,7 +2590,10 @@ function processLintResults(absolutePath, projectCwd, messages, onProgress) {
2590
2590
  onProgress(`JSX map: ${spans.length} element(s)`);
2591
2591
  } catch (e) {
2592
2592
  onProgress("JSX map failed (falling back to unmapped issues)");
2593
- logServerError("JSX map failed", e instanceof Error ? e.message : String(e));
2593
+ logServerError(
2594
+ "JSX map failed",
2595
+ e instanceof Error ? e.message : String(e)
2596
+ );
2594
2597
  spans = [];
2595
2598
  lineStarts = [];
2596
2599
  codeLength = 0;
@@ -2617,13 +2620,17 @@ function processLintResults(absolutePath, projectCwd, messages, onProgress) {
2617
2620
  });
2618
2621
  const mappedCount = issues.filter((i) => Boolean(i.dataLoc)).length;
2619
2622
  if (issues.length > 0) {
2620
- onProgress(`Mapped ${mappedCount}/${issues.length} issue(s) to JSX elements`);
2623
+ onProgress(
2624
+ `Mapped ${mappedCount}/${issues.length} issue(s) to JSX elements`
2625
+ );
2621
2626
  }
2622
2627
  if (fileCode && issues.length > 0) {
2623
2628
  onProgress("Extracting scope info...");
2624
2629
  issues = enrichIssuesWithScopeInfo(issues, fileCode);
2625
2630
  const scopeCount = issues.filter((i) => Boolean(i.scopeInfo)).length;
2626
- onProgress(`Enriched ${scopeCount}/${issues.length} issue(s) with scope info`);
2631
+ onProgress(
2632
+ `Enriched ${scopeCount}/${issues.length} issue(s) with scope info`
2633
+ );
2627
2634
  }
2628
2635
  return issues;
2629
2636
  }
@@ -2655,7 +2662,9 @@ async function lintFileFast(filePath, onProgress) {
2655
2662
  );
2656
2663
  if (!eslint) {
2657
2664
  logWarning(
2658
- `ESLint not found in project. Install it in ${pc.dim(projectCwd)} to enable server-side linting.`
2665
+ `ESLint not found in project. Install it in ${pc.dim(
2666
+ projectCwd
2667
+ )} to enable server-side linting.`
2659
2668
  );
2660
2669
  onProgress("ESLint not available (install eslint in this project)");
2661
2670
  return [];
@@ -2664,11 +2673,19 @@ async function lintFileFast(filePath, onProgress) {
2664
2673
  onProgress("Running ESLint...");
2665
2674
  const results = await eslint.lintFiles([absolutePath]);
2666
2675
  const messages = Array.isArray(results) && results.length > 0 ? results[0].messages || [] : [];
2667
- const issues = processLintResults(absolutePath, projectCwd, messages, onProgress);
2676
+ const issues = processLintResults(
2677
+ absolutePath,
2678
+ projectCwd,
2679
+ messages,
2680
+ onProgress
2681
+ );
2668
2682
  fastCache.set(absolutePath, { issues, mtimeMs, timestamp: Date.now() });
2669
2683
  return issues;
2670
2684
  } catch (error) {
2671
- logServerError("ESLint fast pass failed", error instanceof Error ? error.message : String(error));
2685
+ logServerError(
2686
+ "ESLint fast pass failed",
2687
+ error instanceof Error ? error.message : String(error)
2688
+ );
2672
2689
  return [];
2673
2690
  }
2674
2691
  }
@@ -2704,7 +2721,12 @@ async function runSemanticAnalysisAsync(filePath, ws, requestId) {
2704
2721
  const styleguideHash = hashContentSync(styleguide);
2705
2722
  const projectRoot = findWorkspaceRoot4(fileDir) || fileDir;
2706
2723
  const relativeFilePath = relative2(projectRoot, absolutePath);
2707
- const cached = getCacheEntry(projectRoot, relativeFilePath, fileHash, styleguideHash);
2724
+ const cached = getCacheEntry(
2725
+ projectRoot,
2726
+ relativeFilePath,
2727
+ fileHash,
2728
+ styleguideHash
2729
+ );
2708
2730
  if (cached) {
2709
2731
  logSemanticSkipped(filePath, "cache fresh");
2710
2732
  return;
@@ -2723,7 +2745,11 @@ async function runSemanticAnalysisAsync(filePath, ws, requestId) {
2723
2745
  requestId,
2724
2746
  phase: "Running semantic analysis (async)..."
2725
2747
  });
2726
- startBackgroundTask("semantic-analysis", "Semantic Analysis", `Analyzing ${filePath}...`);
2748
+ startBackgroundTask(
2749
+ "semantic-analysis",
2750
+ "Semantic Analysis",
2751
+ `Analyzing ${filePath}...`
2752
+ );
2727
2753
  broadcast({
2728
2754
  type: "plugin:operation:start",
2729
2755
  pluginId: "semantic",
@@ -2737,8 +2763,18 @@ async function runSemanticAnalysisAsync(filePath, ws, requestId) {
2737
2763
  const ok = await client.isAvailable();
2738
2764
  if (!ok) {
2739
2765
  logServerWarning("Semantic analysis: Ollama not available");
2740
- updateBackgroundTaskProgress("semantic-analysis", 0, 0, 0, "Ollama not available");
2741
- completeBackgroundTask("semantic-analysis", void 0, "Ollama not available");
2766
+ updateBackgroundTaskProgress(
2767
+ "semantic-analysis",
2768
+ 0,
2769
+ 0,
2770
+ 0,
2771
+ "Ollama not available"
2772
+ );
2773
+ completeBackgroundTask(
2774
+ "semantic-analysis",
2775
+ void 0,
2776
+ "Ollama not available"
2777
+ );
2742
2778
  broadcast({
2743
2779
  type: "plugin:operation:error",
2744
2780
  pluginId: "semantic",
@@ -2748,7 +2784,13 @@ async function runSemanticAnalysisAsync(filePath, ws, requestId) {
2748
2784
  completeSemanticFile("error", "Ollama not available");
2749
2785
  return;
2750
2786
  }
2751
- updateBackgroundTaskProgress("semantic-analysis", 50, 0, 0, "Waiting for LLM response...");
2787
+ updateBackgroundTaskProgress(
2788
+ "semantic-analysis",
2789
+ 50,
2790
+ 0,
2791
+ 0,
2792
+ "Waiting for LLM response..."
2793
+ );
2752
2794
  updateSemanticBatchProgress(
2753
2795
  `Analyzing ${relative2(serverAppRootForVision, absolutePath)}...`
2754
2796
  );
@@ -2830,7 +2872,11 @@ async function runSemanticAnalysisAsync(filePath, ws, requestId) {
2830
2872
  async function runVisionAnalysisInBackground(ws, message) {
2831
2873
  const { route, timestamp, screenshot, screenshotFile, manifest, requestId } = message;
2832
2874
  setPluginStatus("vision", "processing", `Analyzing ${route}...`);
2833
- startBackgroundTask("vision-analysis", "Vision Analysis", `Analyzing ${route}...`);
2875
+ startBackgroundTask(
2876
+ "vision-analysis",
2877
+ "Vision Analysis",
2878
+ `Analyzing ${route}...`
2879
+ );
2834
2880
  broadcast({
2835
2881
  type: "plugin:operation:start",
2836
2882
  pluginId: "vision",
@@ -2847,7 +2893,11 @@ async function runVisionAnalysisInBackground(ws, message) {
2847
2893
  error: "uilint-vision is not installed",
2848
2894
  requestId
2849
2895
  });
2850
- completeBackgroundTask("vision-analysis", void 0, "uilint-vision not installed");
2896
+ completeBackgroundTask(
2897
+ "vision-analysis",
2898
+ void 0,
2899
+ "uilint-vision not installed"
2900
+ );
2851
2901
  setPluginStatus("vision", "error", "uilint-vision not installed");
2852
2902
  setTimeout(() => setPluginStatus("vision", "idle"), 3e3);
2853
2903
  broadcast({
@@ -2866,7 +2916,13 @@ async function runVisionAnalysisInBackground(ws, message) {
2866
2916
  });
2867
2917
  const startedAt = Date.now();
2868
2918
  const analyzer = await getVisionAnalyzerInstance();
2869
- updateBackgroundTaskProgress("vision-analysis", 10, 0, 0, "Waiting for Ollama...");
2919
+ updateBackgroundTaskProgress(
2920
+ "vision-analysis",
2921
+ 10,
2922
+ 0,
2923
+ 0,
2924
+ "Waiting for Ollama..."
2925
+ );
2870
2926
  const releaseOllama = await acquireOllamaMutex("vision");
2871
2927
  try {
2872
2928
  const analyzerObj = analyzer;
@@ -2884,7 +2940,11 @@ async function runVisionAnalysisInBackground(ws, message) {
2884
2940
  error: "No screenshot provided for vision analysis",
2885
2941
  requestId
2886
2942
  });
2887
- completeBackgroundTask("vision-analysis", void 0, "No screenshot provided");
2943
+ completeBackgroundTask(
2944
+ "vision-analysis",
2945
+ void 0,
2946
+ "No screenshot provided"
2947
+ );
2888
2948
  setPluginStatus("vision", "error", "No screenshot provided");
2889
2949
  setTimeout(() => setPluginStatus("vision", "idle"), 3e3);
2890
2950
  broadcast({
@@ -2895,7 +2955,13 @@ async function runVisionAnalysisInBackground(ws, message) {
2895
2955
  });
2896
2956
  return;
2897
2957
  }
2898
- updateBackgroundTaskProgress("vision-analysis", 30, 0, 0, "Running vision analysis...");
2958
+ updateBackgroundTaskProgress(
2959
+ "vision-analysis",
2960
+ 30,
2961
+ 0,
2962
+ 0,
2963
+ "Running vision analysis..."
2964
+ );
2899
2965
  broadcast({
2900
2966
  type: "plugin:operation:progress",
2901
2967
  pluginId: "vision",
@@ -2922,7 +2988,11 @@ async function runVisionAnalysisInBackground(ws, message) {
2922
2988
  });
2923
2989
  if (typeof screenshotFile === "string" && screenshotFile.length > 0) {
2924
2990
  if (isValidScreenshotFilename(screenshotFile)) {
2925
- const screenshotsDir = join3(serverAppRootForVision, ".uilint", "screenshots");
2991
+ const screenshotsDir = join3(
2992
+ serverAppRootForVision,
2993
+ ".uilint",
2994
+ "screenshots"
2995
+ );
2926
2996
  const imagePath = join3(screenshotsDir, screenshotFile);
2927
2997
  try {
2928
2998
  if (existsSync5(imagePath)) {
@@ -2962,7 +3032,9 @@ async function runVisionAnalysisInBackground(ws, message) {
2962
3032
  analysisTime: result.analysisTime,
2963
3033
  requestId
2964
3034
  });
2965
- const msg = `${resultIssues.length} issue(s) in ${(elapsed / 1e3).toFixed(1)}s`;
3035
+ const msg = `${resultIssues.length} issue(s) in ${(elapsed / 1e3).toFixed(
3036
+ 1
3037
+ )}s`;
2966
3038
  completeBackgroundTask("vision-analysis", msg);
2967
3039
  setPluginStatus("vision", "complete", msg);
2968
3040
  setTimeout(() => setPluginStatus("vision", "idle"), 3e3);
@@ -3054,7 +3126,12 @@ async function handleMessage(ws, data) {
3054
3126
  const fastClientIssues = fastIssues.filter((i) => !isSentinelIssue(i));
3055
3127
  logLintDone(filePath, fastClientIssues.length, fastElapsed);
3056
3128
  updateCacheCount(fastCache.size + semanticCache.size);
3057
- sendMessage(ws, { type: "lint:result", filePath, requestId, issues: fastClientIssues });
3129
+ sendMessage(ws, {
3130
+ type: "lint:result",
3131
+ filePath,
3132
+ requestId,
3133
+ issues: fastClientIssues
3134
+ });
3058
3135
  sendMessage(ws, {
3059
3136
  type: "lint:progress",
3060
3137
  filePath,
@@ -3063,7 +3140,10 @@ async function handleMessage(ws, data) {
3063
3140
  });
3064
3141
  if (isSemanticRuleEnabled()) {
3065
3142
  runSemanticAnalysisAsync(filePath, ws, requestId).catch((err) => {
3066
- logServerError("Async semantic analysis failed", err instanceof Error ? err.message : String(err));
3143
+ logServerError(
3144
+ "Async semantic analysis failed",
3145
+ err instanceof Error ? err.message : String(err)
3146
+ );
3067
3147
  });
3068
3148
  } else {
3069
3149
  logSemanticSkipped(filePath, "rule not enabled");
@@ -3087,7 +3167,12 @@ async function handleMessage(ws, data) {
3087
3167
  logRuleInternalError(se.ruleId ?? "unknown", filePath, se.message);
3088
3168
  }
3089
3169
  const fastFiltered = fastIssues.filter((i) => !isSentinelIssue(i)).filter((issue) => issue.dataLoc === dataLoc);
3090
- sendMessage(ws, { type: "lint:result", filePath, requestId, issues: fastFiltered });
3170
+ sendMessage(ws, {
3171
+ type: "lint:result",
3172
+ filePath,
3173
+ requestId,
3174
+ issues: fastFiltered
3175
+ });
3091
3176
  {
3092
3177
  const elapsed = Date.now() - startedAt;
3093
3178
  sendMessage(ws, {
@@ -3099,7 +3184,10 @@ async function handleMessage(ws, data) {
3099
3184
  }
3100
3185
  if (isSemanticRuleEnabled()) {
3101
3186
  runSemanticAnalysisAsync(filePath, ws, requestId).catch((err) => {
3102
- logServerError("Async semantic analysis failed", err instanceof Error ? err.message : String(err));
3187
+ logServerError(
3188
+ "Async semantic analysis failed",
3189
+ err instanceof Error ? err.message : String(err)
3190
+ );
3103
3191
  });
3104
3192
  } else {
3105
3193
  logSemanticSkipped(filePath, "rule not enabled");
@@ -3140,7 +3228,10 @@ async function handleMessage(ws, data) {
3140
3228
  const visionMsg = message;
3141
3229
  logVisionAnalyze(visionMsg.route, visionMsg.requestId);
3142
3230
  runVisionAnalysisInBackground(ws, visionMsg).catch((err) => {
3143
- logServerError("Vision analysis failed", err instanceof Error ? err.message : String(err));
3231
+ logServerError(
3232
+ "Vision analysis failed",
3233
+ err instanceof Error ? err.message : String(err)
3234
+ );
3144
3235
  });
3145
3236
  break;
3146
3237
  }
@@ -3150,12 +3241,21 @@ async function handleMessage(ws, data) {
3150
3241
  try {
3151
3242
  const analyzer = await getVisionAnalyzerInstance();
3152
3243
  if (!analyzer) {
3153
- sendMessage(ws, { type: "vision:status", available: false, requestId });
3244
+ sendMessage(ws, {
3245
+ type: "vision:status",
3246
+ available: false,
3247
+ requestId
3248
+ });
3154
3249
  break;
3155
3250
  }
3156
3251
  const analyzerObj = analyzer;
3157
3252
  const model = typeof analyzerObj.getModel === "function" ? analyzerObj.getModel() : void 0;
3158
- sendMessage(ws, { type: "vision:status", available: true, model, requestId });
3253
+ sendMessage(ws, {
3254
+ type: "vision:status",
3255
+ available: true,
3256
+ model,
3257
+ requestId
3258
+ });
3159
3259
  } catch {
3160
3260
  sendMessage(ws, { type: "vision:status", available: false, requestId });
3161
3261
  }
@@ -3497,17 +3597,23 @@ function isCoverageRuleEnabled(appRoot) {
3497
3597
  async function buildCoverageData(appRoot) {
3498
3598
  if (isPreparingCoverage) return;
3499
3599
  isPreparingCoverage = true;
3600
+ setPluginStatus("coverage", "processing", "Checking coverage setup...");
3500
3601
  try {
3501
3602
  if (!isCoverageRuleEnabled(appRoot)) {
3502
3603
  logServerInfo("Coverage rule not enabled, skipping preparation");
3604
+ setPluginStatus("coverage", "complete", "Rule not enabled");
3605
+ setTimeout(() => setPluginStatus("coverage", "idle"), 3e3);
3503
3606
  return;
3504
3607
  }
3505
3608
  const setup = detectCoverageSetup(appRoot);
3506
3609
  if (!needsCoveragePreparation(setup)) {
3507
3610
  logServerInfo("Coverage data is up-to-date");
3611
+ setPluginStatus("coverage", "complete", "Coverage data up-to-date");
3612
+ setTimeout(() => setPluginStatus("coverage", "idle"), 3e3);
3508
3613
  return;
3509
3614
  }
3510
3615
  startBackgroundTask("coverage-prep", "Coverage Prep", "Starting...");
3616
+ setPluginStatus("coverage", "processing", "Starting coverage preparation...");
3511
3617
  broadcast({ type: "coverage:setup:start" });
3512
3618
  const skipPackageInstall = process.env.UILINT_SKIP_COVERAGE_INSTALL === "1";
3513
3619
  const skipTests = process.env.UILINT_SKIP_COVERAGE_TESTS === "1";
@@ -3524,21 +3630,24 @@ async function buildCoverageData(appRoot) {
3524
3630
  void 0,
3525
3631
  message
3526
3632
  );
3633
+ setPluginStatus("coverage", "processing", message);
3527
3634
  broadcast({ type: "coverage:setup:progress", message, phase });
3528
3635
  }
3529
3636
  });
3530
3637
  if (result.error) {
3531
3638
  completeBackgroundTask("coverage-prep", void 0, result.error);
3639
+ setPluginStatus("coverage", "error", result.error);
3640
+ setTimeout(() => setPluginStatus("coverage", "idle"), 3e3);
3532
3641
  } else {
3533
3642
  const parts = [];
3534
3643
  if (result.packageAdded) parts.push("package installed");
3535
3644
  if (result.configModified) parts.push("config modified");
3536
3645
  if (result.testsRan) parts.push("tests ran");
3537
3646
  if (result.coverageGenerated) parts.push("coverage generated");
3538
- completeBackgroundTask(
3539
- "coverage-prep",
3540
- `Coverage prepared: ${parts.join(", ")} in ${(result.duration / 1e3).toFixed(1)}s`
3541
- );
3647
+ const successMsg = `Coverage prepared: ${parts.join(", ")} in ${(result.duration / 1e3).toFixed(1)}s`;
3648
+ completeBackgroundTask("coverage-prep", successMsg);
3649
+ setPluginStatus("coverage", "complete", successMsg);
3650
+ setTimeout(() => setPluginStatus("coverage", "idle"), 3e3);
3542
3651
  }
3543
3652
  broadcast({
3544
3653
  type: "coverage:setup:complete",
@@ -3547,6 +3656,8 @@ async function buildCoverageData(appRoot) {
3547
3656
  } catch (error) {
3548
3657
  const msg = error instanceof Error ? error.message : String(error);
3549
3658
  completeBackgroundTask("coverage-prep", void 0, msg);
3659
+ setPluginStatus("coverage", "error", msg);
3660
+ setTimeout(() => setPluginStatus("coverage", "idle"), 3e3);
3550
3661
  broadcast({ type: "coverage:setup:error", error: msg });
3551
3662
  } finally {
3552
3663
  isPreparingCoverage = false;
@@ -3617,8 +3728,9 @@ async function serve(options) {
3617
3728
  if (useDashboardUI) {
3618
3729
  enableDashboard();
3619
3730
  registerPlugin("semantic", "Semantic", "qwen3-vl:8b-instruct");
3620
- registerPlugin("vision", "Vision", "gemma3:4b");
3731
+ registerPlugin("vision", "Vision", "qwen3-vl:8b-instruct");
3621
3732
  registerPlugin("duplicates", "Duplicates", "nomic-embed-text");
3733
+ registerPlugin("coverage", "Coverage", "vitest");
3622
3734
  } else {
3623
3735
  disableDashboard();
3624
3736
  }
@@ -3651,43 +3763,45 @@ async function serve(options) {
3651
3763
  if (port !== preferredPort) {
3652
3764
  logServerInfo(`Port ${preferredPort} in use, using ${port}`);
3653
3765
  }
3654
- const httpServer = createServer((req, res) => {
3655
- if (req.method === "OPTIONS") {
3656
- res.writeHead(204, {
3657
- "Access-Control-Allow-Origin": "*",
3658
- "Access-Control-Allow-Methods": "GET, OPTIONS",
3659
- "Access-Control-Allow-Headers": "Content-Type"
3660
- });
3661
- res.end();
3662
- return;
3663
- }
3664
- const parsedUrl = new URL(req.url ?? "/", `http://localhost:${port}`);
3665
- if (parsedUrl.pathname === "/_uilint/info") {
3666
- const probePath = parsedUrl.searchParams.get("probe");
3667
- let probeExists;
3668
- if (probePath) {
3669
- const absolute = join3(appRoot, probePath);
3670
- probeExists = existsSync5(absolute);
3766
+ const httpServer = createServer(
3767
+ (req, res) => {
3768
+ if (req.method === "OPTIONS") {
3769
+ res.writeHead(204, {
3770
+ "Access-Control-Allow-Origin": "*",
3771
+ "Access-Control-Allow-Methods": "GET, OPTIONS",
3772
+ "Access-Control-Allow-Headers": "Content-Type"
3773
+ });
3774
+ res.end();
3775
+ return;
3671
3776
  }
3672
- res.writeHead(200, {
3673
- "Content-Type": "application/json",
3674
- "Access-Control-Allow-Origin": "*"
3675
- });
3676
- res.end(
3677
- JSON.stringify({
3678
- appRoot,
3679
- workspaceRoot: wsRoot,
3680
- serverCwd: cwd,
3681
- port,
3682
- pid: process.pid,
3683
- ...probeExists !== void 0 && { probeExists }
3684
- })
3685
- );
3686
- return;
3777
+ const parsedUrl = new URL(req.url ?? "/", `http://localhost:${port}`);
3778
+ if (parsedUrl.pathname === "/_uilint/info") {
3779
+ const probePath = parsedUrl.searchParams.get("probe");
3780
+ let probeExists;
3781
+ if (probePath) {
3782
+ const absolute = join3(appRoot, probePath);
3783
+ probeExists = existsSync5(absolute);
3784
+ }
3785
+ res.writeHead(200, {
3786
+ "Content-Type": "application/json",
3787
+ "Access-Control-Allow-Origin": "*"
3788
+ });
3789
+ res.end(
3790
+ JSON.stringify({
3791
+ appRoot,
3792
+ workspaceRoot: wsRoot,
3793
+ serverCwd: cwd,
3794
+ port,
3795
+ pid: process.pid,
3796
+ ...probeExists !== void 0 && { probeExists }
3797
+ })
3798
+ );
3799
+ return;
3800
+ }
3801
+ res.writeHead(404);
3802
+ res.end();
3687
3803
  }
3688
- res.writeHead(404);
3689
- res.end();
3690
- });
3804
+ );
3691
3805
  const wss = new WebSocketServer({ noServer: true });
3692
3806
  httpServer.on("upgrade", (request, socket, head) => {
3693
3807
  wss.handleUpgrade(request, socket, head, (ws) => {
@@ -5929,7 +6043,7 @@ program.command("update").description("Update existing style guide with new styl
5929
6043
  llm: options.llm
5930
6044
  });
5931
6045
  });
5932
- var initCommand = program.command("init").description("Initialize UILint integration").option("--force", "Overwrite existing configuration files").option("--react", "Install React DevTool (non-interactive)").option("--eslint", "Install ESLint rules (non-interactive)").option("--genstyleguide", "Generate styleguide (non-interactive)").option("--skill", "Install Claude skill (non-interactive)");
6046
+ var initCommand = program.command("init").description("Initialize UILint integration").option("--force", "Overwrite existing configuration files").option("--react", "Install React DevTool (non-interactive)").option("--eslint", "Install ESLint rules (non-interactive)").option("--genstyleguide", "Generate styleguide (non-interactive)").option("--skill", "Install Claude skill (non-interactive)").option("--vision", "Install Vision Analysis plugin").option("--semantic", "Install Semantic Analysis plugin").option("--duplicates", "Install Duplicates Detection plugin");
5933
6047
  program.command("remove").description("Remove UILint components from your project").option("--dry-run", "Preview changes without removing anything").option("-y, --yes", "Skip confirmation prompt").action(async (options) => {
5934
6048
  const { removeUI } = await import("./remove-ui-GZRFA2AC.js");
5935
6049
  await removeUI({ dryRun: options.dryRun, yes: options.yes });
@@ -5940,7 +6054,9 @@ program.command("serve").description("Start WebSocket server for real-time UI li
5940
6054
  noDashboard: !options.dashboard
5941
6055
  });
5942
6056
  });
5943
- program.command("vision").description("Analyze a screenshot with Ollama vision models (requires a manifest)").option("--list", "List available .uilint/screenshots sidecars and exit").option(
6057
+ program.command("vision").description(
6058
+ "Analyze a screenshot with Ollama vision models (requires a manifest)"
6059
+ ).option("--list", "List available .uilint/screenshots sidecars and exit").option(
5944
6060
  "--screenshots-dir <path>",
5945
6061
  "Screenshots directory for --list (default: nearest .uilint/screenshots)"
5946
6062
  ).option("--image <path>", "Path to a screenshot image (png/jpg)").option(
@@ -5949,7 +6065,10 @@ program.command("vision").description("Analyze a screenshot with Ollama vision m
5949
6065
  ).option("--manifest-file <path>", "Path to a manifest JSON file (array)").option("--manifest-json <json>", "Inline manifest JSON (array)").option("--route <route>", "Optional route label (e.g., /todos)").option(
5950
6066
  "-s, --styleguide <path>",
5951
6067
  "Path to style guide file OR project directory (falls back to upward search)"
5952
- ).option("-o, --output <format>", "Output format: text or json", "text").option("--model <name>", "Ollama vision model override", void 0).option("--base-url <url>", "Ollama base URL (default: http://localhost:11434)").option("--stream", "Stream model output/progress to stderr (text mode only)").option("--debug", "Enable debug logging (stderr)").option(
6068
+ ).option("-o, --output <format>", "Output format: text or json", "text").option("--model <name>", "Ollama vision model override", void 0).option(
6069
+ "--base-url <url>",
6070
+ "Ollama base URL (default: http://localhost:11434)"
6071
+ ).option("--stream", "Stream model output/progress to stderr (text mode only)").option("--debug", "Enable debug logging (stderr)").option(
5953
6072
  "--debug-full",
5954
6073
  "Print full prompt/styleguide and include base64 in dumps (can be very large)"
5955
6074
  ).option(
@@ -5983,7 +6102,7 @@ program.addCommand(createDuplicatesCommand());
5983
6102
  program.addCommand(createManifestCommand());
5984
6103
  program.addCommand(createSocketCommand());
5985
6104
  program.command("upgrade").description("Update installed ESLint rules to latest versions").option("--check", "Show available updates without applying").option("-y, --yes", "Auto-confirm all updates").option("--dry-run", "Show what would change without modifying files").option("--rule <id>", "Upgrade only a specific rule").action(async (options) => {
5986
- const { upgrade } = await import("./upgrade-2UKW3SIQ.js");
6105
+ const { upgrade } = await import("./upgrade-WP6U3LEO.js");
5987
6106
  await upgrade({
5988
6107
  check: options.check,
5989
6108
  yes: options.yes,
@@ -5992,14 +6111,21 @@ program.command("upgrade").description("Update installed ESLint rules to latest
5992
6111
  });
5993
6112
  });
5994
6113
  async function main() {
5995
- const { discoverPlugins: discoverPlugins2 } = await import("./plugin-loader-LUIV7MLR.js");
6114
+ const { discoverPlugins: discoverPlugins2 } = await import("./plugin-loader-V5CAMTYQ.js");
5996
6115
  const pluginManifests = await discoverPlugins2();
6116
+ const KNOWN_PLUGIN_FLAGS = ["vision", "semantic", "duplicates"];
5997
6117
  for (const manifest of pluginManifests) {
5998
- initCommand.option(`--${manifest.cliFlag}`, manifest.cliDescription);
6118
+ if (!KNOWN_PLUGIN_FLAGS.includes(manifest.cliFlag)) {
6119
+ initCommand.option(`--${manifest.cliFlag}`, manifest.cliDescription);
6120
+ }
5999
6121
  }
6000
6122
  initCommand.action(async (options) => {
6001
- const plugins = pluginManifests.filter((m) => options[m.cliFlag]).map((m) => m.cliFlag);
6002
- const { initUI } = await import("./init-ui-QQXIZSKI.js");
6123
+ const allFlags = /* @__PURE__ */ new Set([
6124
+ ...KNOWN_PLUGIN_FLAGS,
6125
+ ...pluginManifests.map((m) => m.cliFlag)
6126
+ ]);
6127
+ const plugins = [...allFlags].filter((flag) => options[flag]);
6128
+ const { initUI } = await import("./init-ui-CIK6YKOZ.js");
6003
6129
  await initUI({
6004
6130
  force: options.force,
6005
6131
  react: options.react,