uilint 0.2.148 → 0.2.149
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 +180 -66
- package/dist/index.js.map +1 -1
- package/package.json +8 -8
package/dist/index.js
CHANGED
|
@@ -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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
2741
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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, {
|
|
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(
|
|
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, {
|
|
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(
|
|
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(
|
|
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, {
|
|
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, {
|
|
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
|
}
|
|
@@ -3617,7 +3717,7 @@ async function serve(options) {
|
|
|
3617
3717
|
if (useDashboardUI) {
|
|
3618
3718
|
enableDashboard();
|
|
3619
3719
|
registerPlugin("semantic", "Semantic", "qwen3-vl:8b-instruct");
|
|
3620
|
-
registerPlugin("vision", "Vision", "
|
|
3720
|
+
registerPlugin("vision", "Vision", "qwen3-vl:8b-instruct");
|
|
3621
3721
|
registerPlugin("duplicates", "Duplicates", "nomic-embed-text");
|
|
3622
3722
|
} else {
|
|
3623
3723
|
disableDashboard();
|
|
@@ -3651,43 +3751,45 @@ async function serve(options) {
|
|
|
3651
3751
|
if (port !== preferredPort) {
|
|
3652
3752
|
logServerInfo(`Port ${preferredPort} in use, using ${port}`);
|
|
3653
3753
|
}
|
|
3654
|
-
const httpServer = createServer(
|
|
3655
|
-
|
|
3656
|
-
|
|
3657
|
-
|
|
3658
|
-
|
|
3659
|
-
|
|
3660
|
-
|
|
3661
|
-
|
|
3662
|
-
|
|
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);
|
|
3754
|
+
const httpServer = createServer(
|
|
3755
|
+
(req, res) => {
|
|
3756
|
+
if (req.method === "OPTIONS") {
|
|
3757
|
+
res.writeHead(204, {
|
|
3758
|
+
"Access-Control-Allow-Origin": "*",
|
|
3759
|
+
"Access-Control-Allow-Methods": "GET, OPTIONS",
|
|
3760
|
+
"Access-Control-Allow-Headers": "Content-Type"
|
|
3761
|
+
});
|
|
3762
|
+
res.end();
|
|
3763
|
+
return;
|
|
3671
3764
|
}
|
|
3672
|
-
|
|
3673
|
-
|
|
3674
|
-
|
|
3675
|
-
|
|
3676
|
-
|
|
3677
|
-
|
|
3678
|
-
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
|
|
3682
|
-
|
|
3683
|
-
|
|
3684
|
-
|
|
3685
|
-
|
|
3686
|
-
|
|
3765
|
+
const parsedUrl = new URL(req.url ?? "/", `http://localhost:${port}`);
|
|
3766
|
+
if (parsedUrl.pathname === "/_uilint/info") {
|
|
3767
|
+
const probePath = parsedUrl.searchParams.get("probe");
|
|
3768
|
+
let probeExists;
|
|
3769
|
+
if (probePath) {
|
|
3770
|
+
const absolute = join3(appRoot, probePath);
|
|
3771
|
+
probeExists = existsSync5(absolute);
|
|
3772
|
+
}
|
|
3773
|
+
res.writeHead(200, {
|
|
3774
|
+
"Content-Type": "application/json",
|
|
3775
|
+
"Access-Control-Allow-Origin": "*"
|
|
3776
|
+
});
|
|
3777
|
+
res.end(
|
|
3778
|
+
JSON.stringify({
|
|
3779
|
+
appRoot,
|
|
3780
|
+
workspaceRoot: wsRoot,
|
|
3781
|
+
serverCwd: cwd,
|
|
3782
|
+
port,
|
|
3783
|
+
pid: process.pid,
|
|
3784
|
+
...probeExists !== void 0 && { probeExists }
|
|
3785
|
+
})
|
|
3786
|
+
);
|
|
3787
|
+
return;
|
|
3788
|
+
}
|
|
3789
|
+
res.writeHead(404);
|
|
3790
|
+
res.end();
|
|
3687
3791
|
}
|
|
3688
|
-
|
|
3689
|
-
res.end();
|
|
3690
|
-
});
|
|
3792
|
+
);
|
|
3691
3793
|
const wss = new WebSocketServer({ noServer: true });
|
|
3692
3794
|
httpServer.on("upgrade", (request, socket, head) => {
|
|
3693
3795
|
wss.handleUpgrade(request, socket, head, (ws) => {
|
|
@@ -5929,7 +6031,7 @@ program.command("update").description("Update existing style guide with new styl
|
|
|
5929
6031
|
llm: options.llm
|
|
5930
6032
|
});
|
|
5931
6033
|
});
|
|
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)");
|
|
6034
|
+
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
6035
|
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
6036
|
const { removeUI } = await import("./remove-ui-GZRFA2AC.js");
|
|
5935
6037
|
await removeUI({ dryRun: options.dryRun, yes: options.yes });
|
|
@@ -5940,7 +6042,9 @@ program.command("serve").description("Start WebSocket server for real-time UI li
|
|
|
5940
6042
|
noDashboard: !options.dashboard
|
|
5941
6043
|
});
|
|
5942
6044
|
});
|
|
5943
|
-
program.command("vision").description(
|
|
6045
|
+
program.command("vision").description(
|
|
6046
|
+
"Analyze a screenshot with Ollama vision models (requires a manifest)"
|
|
6047
|
+
).option("--list", "List available .uilint/screenshots sidecars and exit").option(
|
|
5944
6048
|
"--screenshots-dir <path>",
|
|
5945
6049
|
"Screenshots directory for --list (default: nearest .uilint/screenshots)"
|
|
5946
6050
|
).option("--image <path>", "Path to a screenshot image (png/jpg)").option(
|
|
@@ -5949,7 +6053,10 @@ program.command("vision").description("Analyze a screenshot with Ollama vision m
|
|
|
5949
6053
|
).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
6054
|
"-s, --styleguide <path>",
|
|
5951
6055
|
"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(
|
|
6056
|
+
).option("-o, --output <format>", "Output format: text or json", "text").option("--model <name>", "Ollama vision model override", void 0).option(
|
|
6057
|
+
"--base-url <url>",
|
|
6058
|
+
"Ollama base URL (default: http://localhost:11434)"
|
|
6059
|
+
).option("--stream", "Stream model output/progress to stderr (text mode only)").option("--debug", "Enable debug logging (stderr)").option(
|
|
5953
6060
|
"--debug-full",
|
|
5954
6061
|
"Print full prompt/styleguide and include base64 in dumps (can be very large)"
|
|
5955
6062
|
).option(
|
|
@@ -5994,11 +6101,18 @@ program.command("upgrade").description("Update installed ESLint rules to latest
|
|
|
5994
6101
|
async function main() {
|
|
5995
6102
|
const { discoverPlugins: discoverPlugins2 } = await import("./plugin-loader-LUIV7MLR.js");
|
|
5996
6103
|
const pluginManifests = await discoverPlugins2();
|
|
6104
|
+
const KNOWN_PLUGIN_FLAGS = ["vision", "semantic", "duplicates"];
|
|
5997
6105
|
for (const manifest of pluginManifests) {
|
|
5998
|
-
|
|
6106
|
+
if (!KNOWN_PLUGIN_FLAGS.includes(manifest.cliFlag)) {
|
|
6107
|
+
initCommand.option(`--${manifest.cliFlag}`, manifest.cliDescription);
|
|
6108
|
+
}
|
|
5999
6109
|
}
|
|
6000
6110
|
initCommand.action(async (options) => {
|
|
6001
|
-
const
|
|
6111
|
+
const allFlags = /* @__PURE__ */ new Set([
|
|
6112
|
+
...KNOWN_PLUGIN_FLAGS,
|
|
6113
|
+
...pluginManifests.map((m) => m.cliFlag)
|
|
6114
|
+
]);
|
|
6115
|
+
const plugins = [...allFlags].filter((flag) => options[flag]);
|
|
6002
6116
|
const { initUI } = await import("./init-ui-QQXIZSKI.js");
|
|
6003
6117
|
await initUI({
|
|
6004
6118
|
force: options.force,
|