uilint 0.2.58 → 0.2.60
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 +99 -1
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -1404,7 +1404,7 @@ async function update(options) {
|
|
|
1404
1404
|
}
|
|
1405
1405
|
|
|
1406
1406
|
// src/commands/serve.ts
|
|
1407
|
-
import { existsSync as existsSync5, statSync as statSync3, readdirSync, readFileSync } from "fs";
|
|
1407
|
+
import { existsSync as existsSync5, statSync as statSync3, readdirSync, readFileSync, mkdirSync as mkdirSync4, writeFileSync as writeFileSync4 } from "fs";
|
|
1408
1408
|
import { createRequire } from "module";
|
|
1409
1409
|
import { dirname as dirname5, resolve as resolve5, relative, join as join3, parse as parse2 } from "path";
|
|
1410
1410
|
import { WebSocketServer, WebSocket } from "ws";
|
|
@@ -1897,7 +1897,13 @@ async function handleMessage(ws, data) {
|
|
|
1897
1897
|
)}`
|
|
1898
1898
|
);
|
|
1899
1899
|
} else if (message.type === "vision:analyze") {
|
|
1900
|
+
} else if (message.type === "vision:check") {
|
|
1900
1901
|
} else if (message.type === "config:set") {
|
|
1902
|
+
} else if (message.type === "screenshot:save") {
|
|
1903
|
+
const rid = message.requestId;
|
|
1904
|
+
logInfo(
|
|
1905
|
+
`${pc.dim("[ws]")} ${pc.bold("screenshot:save")} ${pc.dim(message.route)}${rid ? ` ${pc.dim(`(req ${rid})`)}` : ""}`
|
|
1906
|
+
);
|
|
1901
1907
|
}
|
|
1902
1908
|
switch (message.type) {
|
|
1903
1909
|
case "lint:file": {
|
|
@@ -2159,6 +2165,29 @@ ${stack}` : ""
|
|
|
2159
2165
|
}
|
|
2160
2166
|
break;
|
|
2161
2167
|
}
|
|
2168
|
+
case "vision:check": {
|
|
2169
|
+
const { requestId } = message;
|
|
2170
|
+
logInfo(
|
|
2171
|
+
`${pc.dim("[ws]")} ${pc.bold("vision:check")}${requestId ? ` ${pc.dim(`(req ${requestId})`)}` : ""}`
|
|
2172
|
+
);
|
|
2173
|
+
try {
|
|
2174
|
+
const analyzer = getVisionAnalyzerInstance();
|
|
2175
|
+
const model = typeof analyzer.getModel === "function" ? analyzer.getModel() : void 0;
|
|
2176
|
+
sendMessage(ws, {
|
|
2177
|
+
type: "vision:status",
|
|
2178
|
+
available: true,
|
|
2179
|
+
model,
|
|
2180
|
+
requestId
|
|
2181
|
+
});
|
|
2182
|
+
} catch (error) {
|
|
2183
|
+
sendMessage(ws, {
|
|
2184
|
+
type: "vision:status",
|
|
2185
|
+
available: false,
|
|
2186
|
+
requestId
|
|
2187
|
+
});
|
|
2188
|
+
}
|
|
2189
|
+
break;
|
|
2190
|
+
}
|
|
2162
2191
|
case "config:set": {
|
|
2163
2192
|
const { key, value } = message;
|
|
2164
2193
|
handleConfigSet(key, value);
|
|
@@ -2234,6 +2263,75 @@ ${stack}` : ""
|
|
|
2234
2263
|
}
|
|
2235
2264
|
break;
|
|
2236
2265
|
}
|
|
2266
|
+
case "screenshot:save": {
|
|
2267
|
+
const { dataUrl, route, timestamp, requestId } = message;
|
|
2268
|
+
try {
|
|
2269
|
+
if (!dataUrl || typeof dataUrl !== "string") {
|
|
2270
|
+
sendMessage(ws, {
|
|
2271
|
+
type: "screenshot:error",
|
|
2272
|
+
error: "Invalid dataUrl: must be a non-empty string",
|
|
2273
|
+
requestId
|
|
2274
|
+
});
|
|
2275
|
+
break;
|
|
2276
|
+
}
|
|
2277
|
+
const dataUrlPattern = /^data:image\/png;base64,/;
|
|
2278
|
+
if (!dataUrlPattern.test(dataUrl)) {
|
|
2279
|
+
sendMessage(ws, {
|
|
2280
|
+
type: "screenshot:error",
|
|
2281
|
+
error: "Invalid dataUrl: must be a base64 PNG data URL (data:image/png;base64,...)",
|
|
2282
|
+
requestId
|
|
2283
|
+
});
|
|
2284
|
+
break;
|
|
2285
|
+
}
|
|
2286
|
+
const base64Data = dataUrl.replace(dataUrlPattern, "");
|
|
2287
|
+
const sanitizedRoute = route.replace(/^\//, "").replace(/\//g, "-").replace(/[^a-zA-Z0-9_-]/g, "_") || "root";
|
|
2288
|
+
const filename = `uilint-${timestamp}-${sanitizedRoute}.png`;
|
|
2289
|
+
if (!isValidScreenshotFilename(filename)) {
|
|
2290
|
+
sendMessage(ws, {
|
|
2291
|
+
type: "screenshot:error",
|
|
2292
|
+
error: `Generated filename is invalid: ${filename}`,
|
|
2293
|
+
requestId
|
|
2294
|
+
});
|
|
2295
|
+
break;
|
|
2296
|
+
}
|
|
2297
|
+
const screenshotsDir = join3(serverAppRootForVision, ".uilint", "screenshots");
|
|
2298
|
+
if (!existsSync5(screenshotsDir)) {
|
|
2299
|
+
mkdirSync4(screenshotsDir, { recursive: true });
|
|
2300
|
+
}
|
|
2301
|
+
const imagePath = join3(screenshotsDir, filename);
|
|
2302
|
+
const imageBuffer = Buffer.from(base64Data, "base64");
|
|
2303
|
+
writeFileSync4(imagePath, imageBuffer);
|
|
2304
|
+
const sidecarFilename = filename.replace(/\.png$/, ".json");
|
|
2305
|
+
const sidecarPath = join3(screenshotsDir, sidecarFilename);
|
|
2306
|
+
const sidecarData = {
|
|
2307
|
+
route,
|
|
2308
|
+
timestamp,
|
|
2309
|
+
filename,
|
|
2310
|
+
savedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2311
|
+
};
|
|
2312
|
+
writeFileSync4(sidecarPath, JSON.stringify(sidecarData, null, 2));
|
|
2313
|
+
logInfo(
|
|
2314
|
+
`${pc.dim("[ws]")} screenshot:saved ${pc.dim(filename)} ${pc.dim(
|
|
2315
|
+
`(${Math.round(imageBuffer.length / 1024)}kb)`
|
|
2316
|
+
)}`
|
|
2317
|
+
);
|
|
2318
|
+
sendMessage(ws, {
|
|
2319
|
+
type: "screenshot:saved",
|
|
2320
|
+
filename,
|
|
2321
|
+
path: imagePath,
|
|
2322
|
+
requestId
|
|
2323
|
+
});
|
|
2324
|
+
} catch (error) {
|
|
2325
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
2326
|
+
logError(`${pc.dim("[ws]")} screenshot:error ${errorMessage}`);
|
|
2327
|
+
sendMessage(ws, {
|
|
2328
|
+
type: "screenshot:error",
|
|
2329
|
+
error: errorMessage,
|
|
2330
|
+
requestId
|
|
2331
|
+
});
|
|
2332
|
+
}
|
|
2333
|
+
break;
|
|
2334
|
+
}
|
|
2237
2335
|
}
|
|
2238
2336
|
}
|
|
2239
2337
|
function handleDisconnect(ws) {
|