devlens-mcp 0.3.0
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/.claude/settings.json +12 -0
- package/.claude/settings.local.json +17 -0
- package/INSTALLATION_GUIDE.md +354 -0
- package/QUICK_START.md +153 -0
- package/README.md +354 -0
- package/bin/cli.ts +22 -0
- package/bin/register.ts +96 -0
- package/dist/bin/cli.d.ts +3 -0
- package/dist/bin/cli.d.ts.map +1 -0
- package/dist/bin/cli.js +20 -0
- package/dist/bin/cli.js.map +1 -0
- package/dist/bin/register.d.ts +10 -0
- package/dist/bin/register.d.ts.map +1 -0
- package/dist/bin/register.js +92 -0
- package/dist/bin/register.js.map +1 -0
- package/dist/src/config/devlens-config.d.ts +92 -0
- package/dist/src/config/devlens-config.d.ts.map +1 -0
- package/dist/src/config/devlens-config.js +70 -0
- package/dist/src/config/devlens-config.js.map +1 -0
- package/dist/src/index.d.ts +35 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +8 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/metro/cdp-client.d.ts +48 -0
- package/dist/src/metro/cdp-client.d.ts.map +1 -0
- package/dist/src/metro/cdp-client.js +127 -0
- package/dist/src/metro/cdp-client.js.map +1 -0
- package/dist/src/metro/log-collector.d.ts +30 -0
- package/dist/src/metro/log-collector.d.ts.map +1 -0
- package/dist/src/metro/log-collector.js +114 -0
- package/dist/src/metro/log-collector.js.map +1 -0
- package/dist/src/metro/metro-bridge.d.ts +56 -0
- package/dist/src/metro/metro-bridge.d.ts.map +1 -0
- package/dist/src/metro/metro-bridge.js +255 -0
- package/dist/src/metro/metro-bridge.js.map +1 -0
- package/dist/src/metro/network-inspector.d.ts +34 -0
- package/dist/src/metro/network-inspector.d.ts.map +1 -0
- package/dist/src/metro/network-inspector.js +100 -0
- package/dist/src/metro/network-inspector.js.map +1 -0
- package/dist/src/platform/android/adb.d.ts +50 -0
- package/dist/src/platform/android/adb.d.ts.map +1 -0
- package/dist/src/platform/android/adb.js +137 -0
- package/dist/src/platform/android/adb.js.map +1 -0
- package/dist/src/platform/android/android-device.d.ts +21 -0
- package/dist/src/platform/android/android-device.d.ts.map +1 -0
- package/dist/src/platform/android/android-device.js +94 -0
- package/dist/src/platform/android/android-device.js.map +1 -0
- package/dist/src/platform/android/ui-automator.d.ts +17 -0
- package/dist/src/platform/android/ui-automator.d.ts.map +1 -0
- package/dist/src/platform/android/ui-automator.js +126 -0
- package/dist/src/platform/android/ui-automator.js.map +1 -0
- package/dist/src/platform/device-manager.d.ts +28 -0
- package/dist/src/platform/device-manager.d.ts.map +1 -0
- package/dist/src/platform/device-manager.js +185 -0
- package/dist/src/platform/device-manager.js.map +1 -0
- package/dist/src/platform/device.d.ts +86 -0
- package/dist/src/platform/device.d.ts.map +1 -0
- package/dist/src/platform/device.js +7 -0
- package/dist/src/platform/device.js.map +1 -0
- package/dist/src/platform/ios/accessibility.d.ts +17 -0
- package/dist/src/platform/ios/accessibility.d.ts.map +1 -0
- package/dist/src/platform/ios/accessibility.js +159 -0
- package/dist/src/platform/ios/accessibility.js.map +1 -0
- package/dist/src/platform/ios/ios-device.d.ts +22 -0
- package/dist/src/platform/ios/ios-device.d.ts.map +1 -0
- package/dist/src/platform/ios/ios-device.js +97 -0
- package/dist/src/platform/ios/ios-device.js.map +1 -0
- package/dist/src/platform/ios/simctl.d.ts +54 -0
- package/dist/src/platform/ios/simctl.d.ts.map +1 -0
- package/dist/src/platform/ios/simctl.js +192 -0
- package/dist/src/platform/ios/simctl.js.map +1 -0
- package/dist/src/server.d.ts +3 -0
- package/dist/src/server.d.ts.map +1 -0
- package/dist/src/server.js +176 -0
- package/dist/src/server.js.map +1 -0
- package/dist/src/snapshot/formatter.d.ts +18 -0
- package/dist/src/snapshot/formatter.d.ts.map +1 -0
- package/dist/src/snapshot/formatter.js +86 -0
- package/dist/src/snapshot/formatter.js.map +1 -0
- package/dist/src/snapshot/ref-registry.d.ts +67 -0
- package/dist/src/snapshot/ref-registry.d.ts.map +1 -0
- package/dist/src/snapshot/ref-registry.js +169 -0
- package/dist/src/snapshot/ref-registry.js.map +1 -0
- package/dist/src/snapshot/snapshot-differ.d.ts +57 -0
- package/dist/src/snapshot/snapshot-differ.d.ts.map +1 -0
- package/dist/src/snapshot/snapshot-differ.js +153 -0
- package/dist/src/snapshot/snapshot-differ.js.map +1 -0
- package/dist/src/tools/app-tools.d.ts +71 -0
- package/dist/src/tools/app-tools.d.ts.map +1 -0
- package/dist/src/tools/app-tools.js +97 -0
- package/dist/src/tools/app-tools.js.map +1 -0
- package/dist/src/tools/device-tools.d.ts +53 -0
- package/dist/src/tools/device-tools.d.ts.map +1 -0
- package/dist/src/tools/device-tools.js +86 -0
- package/dist/src/tools/device-tools.js.map +1 -0
- package/dist/src/tools/ds-tools.d.ts +65 -0
- package/dist/src/tools/ds-tools.d.ts.map +1 -0
- package/dist/src/tools/ds-tools.js +314 -0
- package/dist/src/tools/ds-tools.js.map +1 -0
- package/dist/src/tools/interaction-tools.d.ts +248 -0
- package/dist/src/tools/interaction-tools.d.ts.map +1 -0
- package/dist/src/tools/interaction-tools.js +391 -0
- package/dist/src/tools/interaction-tools.js.map +1 -0
- package/dist/src/tools/metro-tools.d.ts +115 -0
- package/dist/src/tools/metro-tools.d.ts.map +1 -0
- package/dist/src/tools/metro-tools.js +270 -0
- package/dist/src/tools/metro-tools.js.map +1 -0
- package/dist/src/tools/navigation-tools.d.ts +36 -0
- package/dist/src/tools/navigation-tools.d.ts.map +1 -0
- package/dist/src/tools/navigation-tools.js +60 -0
- package/dist/src/tools/navigation-tools.js.map +1 -0
- package/dist/src/tools/screenshot-tools.d.ts +298 -0
- package/dist/src/tools/screenshot-tools.d.ts.map +1 -0
- package/dist/src/tools/screenshot-tools.js +565 -0
- package/dist/src/tools/screenshot-tools.js.map +1 -0
- package/dist/src/tools/snapshot-tools.d.ts +161 -0
- package/dist/src/tools/snapshot-tools.d.ts.map +1 -0
- package/dist/src/tools/snapshot-tools.js +479 -0
- package/dist/src/tools/snapshot-tools.js.map +1 -0
- package/dist/src/utils/image-preprocess.d.ts +49 -0
- package/dist/src/utils/image-preprocess.d.ts.map +1 -0
- package/dist/src/utils/image-preprocess.js +322 -0
- package/dist/src/utils/image-preprocess.js.map +1 -0
- package/dist/src/utils/retry.d.ts +21 -0
- package/dist/src/utils/retry.d.ts.map +1 -0
- package/dist/src/utils/retry.js +33 -0
- package/dist/src/utils/retry.js.map +1 -0
- package/dist/src/visual/comparator.d.ts +51 -0
- package/dist/src/visual/comparator.d.ts.map +1 -0
- package/dist/src/visual/comparator.js +119 -0
- package/dist/src/visual/comparator.js.map +1 -0
- package/dist/src/visual/layout-analyzer.d.ts +64 -0
- package/dist/src/visual/layout-analyzer.d.ts.map +1 -0
- package/dist/src/visual/layout-analyzer.js +198 -0
- package/dist/src/visual/layout-analyzer.js.map +1 -0
- package/dist/src/visual/screenshot.d.ts +17 -0
- package/dist/src/visual/screenshot.d.ts.map +1 -0
- package/dist/src/visual/screenshot.js +39 -0
- package/dist/src/visual/screenshot.js.map +1 -0
- package/docs/figma-workflow.md +289 -0
- package/docs/setup-guide.md +360 -0
- package/docs/tool-reference.md +622 -0
- package/package.json +57 -0
- package/src/config/devlens-config.ts +76 -0
- package/src/index.ts +5 -0
- package/src/metro/cdp-client.ts +160 -0
- package/src/metro/log-collector.ts +137 -0
- package/src/metro/metro-bridge.ts +307 -0
- package/src/metro/network-inspector.ts +134 -0
- package/src/platform/android/adb.ts +200 -0
- package/src/platform/android/android-device.ts +116 -0
- package/src/platform/android/ui-automator.ts +141 -0
- package/src/platform/device-manager.ts +229 -0
- package/src/platform/device.ts +110 -0
- package/src/platform/ios/accessibility.ts +189 -0
- package/src/platform/ios/ios-device.ts +116 -0
- package/src/platform/ios/simctl.ts +244 -0
- package/src/server.ts +228 -0
- package/src/snapshot/formatter.ts +102 -0
- package/src/snapshot/ref-registry.ts +230 -0
- package/src/snapshot/snapshot-differ.ts +220 -0
- package/src/tools/app-tools.ts +111 -0
- package/src/tools/device-tools.ts +96 -0
- package/src/tools/ds-tools.ts +395 -0
- package/src/tools/interaction-tools.ts +467 -0
- package/src/tools/metro-tools.ts +320 -0
- package/src/tools/navigation-tools.ts +71 -0
- package/src/tools/screenshot-tools.ts +698 -0
- package/src/tools/snapshot-tools.ts +585 -0
- package/src/utils/image-preprocess.ts +430 -0
- package/src/utils/retry.ts +51 -0
- package/src/visual/comparator.ts +191 -0
- package/src/visual/layout-analyzer.ts +283 -0
- package/src/visual/screenshot.ts +49 -0
- package/tsconfig.json +20 -0
|
@@ -0,0 +1,565 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.screenshotToolSchemas = void 0;
|
|
4
|
+
exports.createScreenshotToolHandlers = createScreenshotToolHandlers;
|
|
5
|
+
const zod_1 = require("zod");
|
|
6
|
+
const screenshot_js_1 = require("../visual/screenshot.js");
|
|
7
|
+
const comparator_js_1 = require("../visual/comparator.js");
|
|
8
|
+
const layout_analyzer_js_1 = require("../visual/layout-analyzer.js");
|
|
9
|
+
const image_preprocess_js_1 = require("../utils/image-preprocess.js");
|
|
10
|
+
/**
|
|
11
|
+
* Resolve an image source (file path, HTTP URL, or base64) to a Buffer.
|
|
12
|
+
*/
|
|
13
|
+
async function resolveImageToBuffer(source, isBase64 = false) {
|
|
14
|
+
if (isBase64) {
|
|
15
|
+
return { buffer: Buffer.from(source, "base64") };
|
|
16
|
+
}
|
|
17
|
+
if (source.startsWith("http://") || source.startsWith("https://")) {
|
|
18
|
+
const controller = new AbortController();
|
|
19
|
+
const timeout = setTimeout(() => controller.abort(), 15000);
|
|
20
|
+
try {
|
|
21
|
+
const response = await fetch(source, { signal: controller.signal });
|
|
22
|
+
clearTimeout(timeout);
|
|
23
|
+
if (!response.ok) {
|
|
24
|
+
return {
|
|
25
|
+
buffer: Buffer.alloc(0),
|
|
26
|
+
error: `Failed to fetch image: ${response.status} ${response.statusText}`,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
return { buffer: Buffer.from(await response.arrayBuffer()) };
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
clearTimeout(timeout);
|
|
33
|
+
return {
|
|
34
|
+
buffer: Buffer.alloc(0),
|
|
35
|
+
error: `Failed to fetch image from URL: ${error.message}`,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
// Local file path
|
|
40
|
+
const { readFile } = await import("fs/promises");
|
|
41
|
+
const buffer = await readFile(source);
|
|
42
|
+
return { buffer };
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Run comparison and return MCP content blocks with similarity, diff image, etc.
|
|
46
|
+
*/
|
|
47
|
+
async function buildComparisonResult(deviceBuffer, referenceBuffer, options) {
|
|
48
|
+
const result = await (0, comparator_js_1.compareScreenshots)(deviceBuffer, referenceBuffer, {
|
|
49
|
+
threshold: options.threshold,
|
|
50
|
+
resizeStrategy: options.resizeStrategy,
|
|
51
|
+
preprocessReference: options.preprocessReference,
|
|
52
|
+
});
|
|
53
|
+
const { readFile } = await import("fs/promises");
|
|
54
|
+
const diffBuffer = await readFile(result.diffImagePath);
|
|
55
|
+
const diffBase64 = diffBuffer.toString("base64");
|
|
56
|
+
const deviceBase64 = deviceBuffer.toString("base64");
|
|
57
|
+
const referenceBase64 = referenceBuffer.toString("base64");
|
|
58
|
+
const textParts = [
|
|
59
|
+
`Similarity: ${(result.similarity * 100).toFixed(1)}%`,
|
|
60
|
+
`Different pixels: ${result.diffPixels} / ${result.totalPixels}`,
|
|
61
|
+
`Diff image: ${result.diffImagePath}`,
|
|
62
|
+
``,
|
|
63
|
+
result.summary,
|
|
64
|
+
];
|
|
65
|
+
if (options.layoutReport) {
|
|
66
|
+
textParts.push(``, (0, layout_analyzer_js_1.formatLayoutReport)(options.layoutReport));
|
|
67
|
+
}
|
|
68
|
+
textParts.push(``, `Images (left to right): Device screenshot | Figma reference | Diff (red = differences)`);
|
|
69
|
+
return {
|
|
70
|
+
content: [
|
|
71
|
+
{
|
|
72
|
+
type: "text",
|
|
73
|
+
text: textParts.join("\n"),
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
type: "image",
|
|
77
|
+
data: deviceBase64,
|
|
78
|
+
mimeType: "image/png",
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
type: "image",
|
|
82
|
+
data: referenceBase64,
|
|
83
|
+
mimeType: "image/png",
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
type: "image",
|
|
87
|
+
data: diffBase64,
|
|
88
|
+
mimeType: "image/png",
|
|
89
|
+
},
|
|
90
|
+
],
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
exports.screenshotToolSchemas = {
|
|
94
|
+
devlens_screenshot: {
|
|
95
|
+
description: "Take a screenshot of the current device screen. Returns the image as base64 (for AI vision analysis) and optionally saves to a file.",
|
|
96
|
+
parameters: zod_1.z.object({
|
|
97
|
+
filename: zod_1.z
|
|
98
|
+
.string()
|
|
99
|
+
.optional()
|
|
100
|
+
.describe("File path to save the screenshot. If not provided, saves to /tmp/ with a timestamp."),
|
|
101
|
+
}),
|
|
102
|
+
},
|
|
103
|
+
devlens_compare_screenshot: {
|
|
104
|
+
description: "Compare the current device screen against a reference image (e.g., a Figma design export). Accepts a local file path, HTTP/HTTPS URL, or base64-encoded image data. Returns a similarity score (0-1), a diff image highlighting differences, and a summary. For Figma workflow: use Figma MCP's get_screenshot to get base64, then pass it here as referenceImageBase64.",
|
|
105
|
+
parameters: zod_1.z.object({
|
|
106
|
+
referenceImagePath: zod_1.z
|
|
107
|
+
.string()
|
|
108
|
+
.optional()
|
|
109
|
+
.describe("Path to the reference PNG file, or an HTTP/HTTPS URL to fetch it from."),
|
|
110
|
+
referenceImageBase64: zod_1.z
|
|
111
|
+
.string()
|
|
112
|
+
.optional()
|
|
113
|
+
.describe("Base64-encoded PNG image data (without data URI prefix). Use this when passing images from other MCP tools like Figma MCP's get_screenshot."),
|
|
114
|
+
threshold: zod_1.z
|
|
115
|
+
.number()
|
|
116
|
+
.default(0.1)
|
|
117
|
+
.describe("Color difference threshold (0-1). Lower = stricter matching. Default: 0.1"),
|
|
118
|
+
resizeStrategy: zod_1.z
|
|
119
|
+
.enum(["fit", "scale", "crop"])
|
|
120
|
+
.default("fit")
|
|
121
|
+
.describe('"fit" (default) resizes both to smaller dimensions. "scale" resizes smaller to larger. "crop" extracts the overlapping region.'),
|
|
122
|
+
preprocessReference: zod_1.z
|
|
123
|
+
.boolean()
|
|
124
|
+
.default(false)
|
|
125
|
+
.describe("Automatically remove Figma presentation artifacts (rounded corners, grey backgrounds, black bars) from the reference image before comparison. Recommended for Figma exports. Default: false"),
|
|
126
|
+
cropRef: zod_1.z
|
|
127
|
+
.string()
|
|
128
|
+
.optional()
|
|
129
|
+
.describe("Crop the device screenshot to this element's bounds before comparing. Useful for comparing a specific component instead of the full screen."),
|
|
130
|
+
region: zod_1.z
|
|
131
|
+
.object({
|
|
132
|
+
x: zod_1.z.number().describe("Left edge in pixels"),
|
|
133
|
+
y: zod_1.z.number().describe("Top edge in pixels"),
|
|
134
|
+
width: zod_1.z.number().describe("Width in pixels"),
|
|
135
|
+
height: zod_1.z.number().describe("Height in pixels"),
|
|
136
|
+
})
|
|
137
|
+
.optional()
|
|
138
|
+
.describe("Crop the device screenshot to this pixel region before comparing. Use to exclude status bars or focus on a specific area."),
|
|
139
|
+
}),
|
|
140
|
+
},
|
|
141
|
+
devlens_element_screenshot: {
|
|
142
|
+
description: "Take a screenshot of a specific element by its ref ID. Crops the full screenshot to the element's bounds. Useful for comparing individual components against Figma designs.",
|
|
143
|
+
parameters: zod_1.z.object({
|
|
144
|
+
ref: zod_1.z.string().describe("Element ref from devlens_snapshot"),
|
|
145
|
+
filename: zod_1.z
|
|
146
|
+
.string()
|
|
147
|
+
.optional()
|
|
148
|
+
.describe("File path to save the cropped screenshot"),
|
|
149
|
+
}),
|
|
150
|
+
},
|
|
151
|
+
devlens_compare_images: {
|
|
152
|
+
description: "Compare two saved images (file paths or HTTP URLs). Useful for A/B comparison of before/after screenshots, or comparing two different device screenshots.",
|
|
153
|
+
parameters: zod_1.z.object({
|
|
154
|
+
imageA: zod_1.z
|
|
155
|
+
.string()
|
|
156
|
+
.describe("Path or HTTP URL of the first image"),
|
|
157
|
+
imageB: zod_1.z
|
|
158
|
+
.string()
|
|
159
|
+
.describe("Path or HTTP URL of the second image"),
|
|
160
|
+
threshold: zod_1.z
|
|
161
|
+
.number()
|
|
162
|
+
.default(0.1)
|
|
163
|
+
.describe("Color difference threshold (0-1). Default: 0.1"),
|
|
164
|
+
resizeStrategy: zod_1.z
|
|
165
|
+
.enum(["fit", "scale", "crop"])
|
|
166
|
+
.default("fit")
|
|
167
|
+
.describe("How to handle dimension mismatches (default: fit)"),
|
|
168
|
+
preprocessImageB: zod_1.z
|
|
169
|
+
.boolean()
|
|
170
|
+
.default(false)
|
|
171
|
+
.describe("Preprocess imageB to remove presentation artifacts. Useful if imageB is a Figma export. Default: false"),
|
|
172
|
+
}),
|
|
173
|
+
},
|
|
174
|
+
devlens_compare_with_figma: {
|
|
175
|
+
description: "Compare the current device screen directly against a Figma design. Fetches the Figma frame as a PNG via the Figma REST API and compares it with the device screenshot. Requires FIGMA_TOKEN environment variable. This is the recommended tool for the Figma design verification loop. Automatically removes Figma presentation artifacts (rounded corners, backgrounds) by default.",
|
|
176
|
+
parameters: zod_1.z.object({
|
|
177
|
+
figmaUrl: zod_1.z
|
|
178
|
+
.string()
|
|
179
|
+
.optional()
|
|
180
|
+
.describe('Full Figma URL (e.g., "https://figma.com/design/ABC123/MyApp?node-id=10-200"). The fileKey and nodeId will be extracted automatically.'),
|
|
181
|
+
fileKey: zod_1.z
|
|
182
|
+
.string()
|
|
183
|
+
.optional()
|
|
184
|
+
.describe("Figma file key. Use this instead of figmaUrl if you already have the key."),
|
|
185
|
+
nodeId: zod_1.z
|
|
186
|
+
.string()
|
|
187
|
+
.optional()
|
|
188
|
+
.describe('Figma node ID (e.g., "10:200" or "10-200"). Use with fileKey.'),
|
|
189
|
+
scale: zod_1.z
|
|
190
|
+
.number()
|
|
191
|
+
.default(2)
|
|
192
|
+
.describe("Export scale for the Figma image (default: 2)"),
|
|
193
|
+
threshold: zod_1.z
|
|
194
|
+
.number()
|
|
195
|
+
.default(0.1)
|
|
196
|
+
.describe("Color difference threshold (0-1). Default: 0.1"),
|
|
197
|
+
resizeStrategy: zod_1.z
|
|
198
|
+
.enum(["fit", "scale", "crop"])
|
|
199
|
+
.default("fit")
|
|
200
|
+
.describe("How to handle dimension mismatches (default: fit)"),
|
|
201
|
+
preprocessReference: zod_1.z
|
|
202
|
+
.boolean()
|
|
203
|
+
.default(true)
|
|
204
|
+
.describe("Automatically remove Figma presentation artifacts (rounded corners, grey backgrounds, black bars). Default: true for Figma exports"),
|
|
205
|
+
cropRef: zod_1.z
|
|
206
|
+
.string()
|
|
207
|
+
.optional()
|
|
208
|
+
.describe("Crop the device screenshot to this element's bounds before comparing."),
|
|
209
|
+
region: zod_1.z
|
|
210
|
+
.object({
|
|
211
|
+
x: zod_1.z.number().describe("Left edge in pixels"),
|
|
212
|
+
y: zod_1.z.number().describe("Top edge in pixels"),
|
|
213
|
+
width: zod_1.z.number().describe("Width in pixels"),
|
|
214
|
+
height: zod_1.z.number().describe("Height in pixels"),
|
|
215
|
+
})
|
|
216
|
+
.optional()
|
|
217
|
+
.describe("Crop the device screenshot to this pixel region before comparing."),
|
|
218
|
+
layoutReport: zod_1.z
|
|
219
|
+
.boolean()
|
|
220
|
+
.default(true)
|
|
221
|
+
.describe("When true (default), runs per-element layout analysis using the accessibility tree. Scales each element's device bounds into Figma image space and compares each region independently. Returns per-element scores like '[X] [e5] ToolsGrid: 44% <- investigate'. Requires devlens_snapshot to have been called first."),
|
|
222
|
+
}),
|
|
223
|
+
},
|
|
224
|
+
};
|
|
225
|
+
function createScreenshotToolHandlers(deviceManager, refRegistry) {
|
|
226
|
+
return {
|
|
227
|
+
devlens_screenshot: async (params) => {
|
|
228
|
+
const device = await deviceManager.getDevice();
|
|
229
|
+
const { buffer, base64 } = await (0, screenshot_js_1.captureScreenshot)(device);
|
|
230
|
+
const filePath = params.filename || (0, screenshot_js_1.defaultScreenshotPath)();
|
|
231
|
+
await (0, screenshot_js_1.saveScreenshot)(buffer, filePath);
|
|
232
|
+
return {
|
|
233
|
+
content: [
|
|
234
|
+
{
|
|
235
|
+
type: "image",
|
|
236
|
+
data: base64,
|
|
237
|
+
mimeType: "image/png",
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
type: "text",
|
|
241
|
+
text: `Screenshot saved to: ${filePath}`,
|
|
242
|
+
},
|
|
243
|
+
],
|
|
244
|
+
};
|
|
245
|
+
},
|
|
246
|
+
devlens_compare_screenshot: async (params) => {
|
|
247
|
+
if (!params.referenceImagePath && !params.referenceImageBase64) {
|
|
248
|
+
return {
|
|
249
|
+
content: [
|
|
250
|
+
{
|
|
251
|
+
type: "text",
|
|
252
|
+
text: "Provide either referenceImagePath or referenceImageBase64.",
|
|
253
|
+
},
|
|
254
|
+
],
|
|
255
|
+
isError: true,
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
// Resolve reference image
|
|
259
|
+
let refResult;
|
|
260
|
+
if (params.referenceImageBase64) {
|
|
261
|
+
refResult = await resolveImageToBuffer(params.referenceImageBase64, true);
|
|
262
|
+
}
|
|
263
|
+
else {
|
|
264
|
+
refResult = await resolveImageToBuffer(params.referenceImagePath);
|
|
265
|
+
}
|
|
266
|
+
if (refResult.error) {
|
|
267
|
+
return {
|
|
268
|
+
content: [{ type: "text", text: refResult.error }],
|
|
269
|
+
isError: true,
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
const device = await deviceManager.getDevice();
|
|
273
|
+
const { buffer } = await (0, screenshot_js_1.captureScreenshot)(device);
|
|
274
|
+
// Apply crop to device screenshot if requested
|
|
275
|
+
let compareBuffer = buffer;
|
|
276
|
+
if (params.cropRef) {
|
|
277
|
+
const entry = refRegistry.resolve(params.cropRef);
|
|
278
|
+
if (!entry) {
|
|
279
|
+
return {
|
|
280
|
+
content: [
|
|
281
|
+
{
|
|
282
|
+
type: "text",
|
|
283
|
+
text: `cropRef "${params.cropRef}" not found. Run devlens_snapshot first.`,
|
|
284
|
+
},
|
|
285
|
+
],
|
|
286
|
+
isError: true,
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
compareBuffer = await (0, screenshot_js_1.cropToElement)(buffer, entry.bounds);
|
|
290
|
+
}
|
|
291
|
+
else if (params.region) {
|
|
292
|
+
const sharp = (await import("sharp")).default;
|
|
293
|
+
compareBuffer = await sharp(buffer)
|
|
294
|
+
.extract({
|
|
295
|
+
left: params.region.x,
|
|
296
|
+
top: params.region.y,
|
|
297
|
+
width: params.region.width,
|
|
298
|
+
height: params.region.height,
|
|
299
|
+
})
|
|
300
|
+
.png()
|
|
301
|
+
.toBuffer();
|
|
302
|
+
}
|
|
303
|
+
return buildComparisonResult(compareBuffer, refResult.buffer, {
|
|
304
|
+
threshold: params.threshold,
|
|
305
|
+
resizeStrategy: params.resizeStrategy,
|
|
306
|
+
preprocessReference: params.preprocessReference,
|
|
307
|
+
});
|
|
308
|
+
},
|
|
309
|
+
devlens_element_screenshot: async (params) => {
|
|
310
|
+
const entry = refRegistry.resolve(params.ref);
|
|
311
|
+
if (!entry) {
|
|
312
|
+
return {
|
|
313
|
+
content: [
|
|
314
|
+
{
|
|
315
|
+
type: "text",
|
|
316
|
+
text: `Ref "${params.ref}" not found. Run devlens_snapshot first.`,
|
|
317
|
+
},
|
|
318
|
+
],
|
|
319
|
+
isError: true,
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
const device = await deviceManager.getDevice();
|
|
323
|
+
const fullScreenshot = await device.takeScreenshot();
|
|
324
|
+
const cropped = await (0, screenshot_js_1.cropToElement)(fullScreenshot, entry.bounds);
|
|
325
|
+
const base64 = cropped.toString("base64");
|
|
326
|
+
if (params.filename) {
|
|
327
|
+
await (0, screenshot_js_1.saveScreenshot)(cropped, params.filename);
|
|
328
|
+
}
|
|
329
|
+
return {
|
|
330
|
+
content: [
|
|
331
|
+
{
|
|
332
|
+
type: "image",
|
|
333
|
+
data: base64,
|
|
334
|
+
mimeType: "image/png",
|
|
335
|
+
},
|
|
336
|
+
{
|
|
337
|
+
type: "text",
|
|
338
|
+
text: `Element [${params.ref}] screenshot (${entry.bounds.width}x${entry.bounds.height})${params.filename ? ` saved to: ${params.filename}` : ""}`,
|
|
339
|
+
},
|
|
340
|
+
],
|
|
341
|
+
};
|
|
342
|
+
},
|
|
343
|
+
devlens_compare_images: async (params) => {
|
|
344
|
+
const resultA = await resolveImageToBuffer(params.imageA);
|
|
345
|
+
if (resultA.error) {
|
|
346
|
+
return {
|
|
347
|
+
content: [{ type: "text", text: `Image A: ${resultA.error}` }],
|
|
348
|
+
isError: true,
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
const resultB = await resolveImageToBuffer(params.imageB);
|
|
352
|
+
if (resultB.error) {
|
|
353
|
+
return {
|
|
354
|
+
content: [{ type: "text", text: `Image B: ${resultB.error}` }],
|
|
355
|
+
isError: true,
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
return buildComparisonResult(resultA.buffer, resultB.buffer, {
|
|
359
|
+
threshold: params.threshold,
|
|
360
|
+
resizeStrategy: params.resizeStrategy,
|
|
361
|
+
preprocessReference: params.preprocessImageB,
|
|
362
|
+
});
|
|
363
|
+
},
|
|
364
|
+
devlens_compare_with_figma: async (params) => {
|
|
365
|
+
// 1. Resolve Figma token
|
|
366
|
+
const figmaToken = process.env.FIGMA_TOKEN;
|
|
367
|
+
if (!figmaToken) {
|
|
368
|
+
return {
|
|
369
|
+
content: [
|
|
370
|
+
{
|
|
371
|
+
type: "text",
|
|
372
|
+
text: [
|
|
373
|
+
"FIGMA_TOKEN environment variable is not set.",
|
|
374
|
+
"",
|
|
375
|
+
"To use this tool, set FIGMA_TOKEN in your MCP config:",
|
|
376
|
+
' "env": { "FIGMA_TOKEN": "figd_xxxxx" }',
|
|
377
|
+
"",
|
|
378
|
+
"Generate a token at: https://www.figma.com/developers/api#access-tokens",
|
|
379
|
+
].join("\n"),
|
|
380
|
+
},
|
|
381
|
+
],
|
|
382
|
+
isError: true,
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
// 2. Resolve fileKey and nodeId
|
|
386
|
+
let fileKey = params.fileKey;
|
|
387
|
+
let nodeId = params.nodeId;
|
|
388
|
+
if (params.figmaUrl) {
|
|
389
|
+
const urlMatch = params.figmaUrl.match(/figma\.com\/design\/([^/]+)\/[^?]+\?.*node-id=(\d+-\d+)/);
|
|
390
|
+
if (!urlMatch) {
|
|
391
|
+
return {
|
|
392
|
+
content: [
|
|
393
|
+
{
|
|
394
|
+
type: "text",
|
|
395
|
+
text: `Could not parse Figma URL. Expected format: https://figma.com/design/<fileKey>/<name>?node-id=<id>\nGot: ${params.figmaUrl}`,
|
|
396
|
+
},
|
|
397
|
+
],
|
|
398
|
+
isError: true,
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
fileKey = urlMatch[1];
|
|
402
|
+
nodeId = urlMatch[2].replace("-", ":");
|
|
403
|
+
}
|
|
404
|
+
if (!fileKey || !nodeId) {
|
|
405
|
+
return {
|
|
406
|
+
content: [
|
|
407
|
+
{
|
|
408
|
+
type: "text",
|
|
409
|
+
text: "Provide either figmaUrl, or both fileKey and nodeId.",
|
|
410
|
+
},
|
|
411
|
+
],
|
|
412
|
+
isError: true,
|
|
413
|
+
};
|
|
414
|
+
}
|
|
415
|
+
// Normalize nodeId: accept "10-200" or "10:200"
|
|
416
|
+
const normalizedNodeId = nodeId.replace("-", ":");
|
|
417
|
+
// 3. Fetch Figma image export
|
|
418
|
+
let figmaBuffer;
|
|
419
|
+
try {
|
|
420
|
+
const apiUrl = `https://api.figma.com/v1/images/${fileKey}?ids=${encodeURIComponent(normalizedNodeId)}&format=png&scale=${params.scale}`;
|
|
421
|
+
const controller = new AbortController();
|
|
422
|
+
const timeout = setTimeout(() => controller.abort(), 20000);
|
|
423
|
+
const apiResponse = await fetch(apiUrl, {
|
|
424
|
+
headers: { "X-Figma-Token": figmaToken },
|
|
425
|
+
signal: controller.signal,
|
|
426
|
+
});
|
|
427
|
+
clearTimeout(timeout);
|
|
428
|
+
if (!apiResponse.ok) {
|
|
429
|
+
const body = await apiResponse.text().catch(() => "");
|
|
430
|
+
return {
|
|
431
|
+
content: [
|
|
432
|
+
{
|
|
433
|
+
type: "text",
|
|
434
|
+
text: `Figma API error (${apiResponse.status}): ${body || apiResponse.statusText}\n\nCheck that FIGMA_TOKEN is valid and you have access to file ${fileKey}.`,
|
|
435
|
+
},
|
|
436
|
+
],
|
|
437
|
+
isError: true,
|
|
438
|
+
};
|
|
439
|
+
}
|
|
440
|
+
const apiData = (await apiResponse.json());
|
|
441
|
+
if (apiData.err) {
|
|
442
|
+
const isNotExportable = apiData.err.toLowerCase().includes("not exportable");
|
|
443
|
+
return {
|
|
444
|
+
content: [
|
|
445
|
+
{
|
|
446
|
+
type: "text",
|
|
447
|
+
text: isNotExportable
|
|
448
|
+
? [
|
|
449
|
+
`Figma API error: ${apiData.err}`,
|
|
450
|
+
"",
|
|
451
|
+
"The file has export restrictions enabled. To fix this:",
|
|
452
|
+
" 1. Open the Figma file",
|
|
453
|
+
" 2. Click the file name → Share",
|
|
454
|
+
" 3. Click the gear/settings icon",
|
|
455
|
+
' 4. Turn off "Prevent viewers from copying and exporting"',
|
|
456
|
+
"",
|
|
457
|
+
"If you don't own the file, ask the owner to disable that setting,",
|
|
458
|
+
"or duplicate the file to your own drafts (File → Duplicate to your drafts).",
|
|
459
|
+
].join("\n")
|
|
460
|
+
: `Figma API error: ${apiData.err}`,
|
|
461
|
+
},
|
|
462
|
+
],
|
|
463
|
+
isError: true,
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
const imageUrl = Object.values(apiData.images)[0];
|
|
467
|
+
if (!imageUrl) {
|
|
468
|
+
return {
|
|
469
|
+
content: [
|
|
470
|
+
{
|
|
471
|
+
type: "text",
|
|
472
|
+
text: `Figma returned no image for node ${normalizedNodeId}. Check that the node ID exists in file ${fileKey}.`,
|
|
473
|
+
},
|
|
474
|
+
],
|
|
475
|
+
isError: true,
|
|
476
|
+
};
|
|
477
|
+
}
|
|
478
|
+
// Fetch the actual image
|
|
479
|
+
const imgResult = await resolveImageToBuffer(imageUrl);
|
|
480
|
+
if (imgResult.error) {
|
|
481
|
+
return {
|
|
482
|
+
content: [
|
|
483
|
+
{ type: "text", text: `Failed to download Figma image: ${imgResult.error}` },
|
|
484
|
+
],
|
|
485
|
+
isError: true,
|
|
486
|
+
};
|
|
487
|
+
}
|
|
488
|
+
figmaBuffer = imgResult.buffer;
|
|
489
|
+
}
|
|
490
|
+
catch (error) {
|
|
491
|
+
return {
|
|
492
|
+
content: [
|
|
493
|
+
{
|
|
494
|
+
type: "text",
|
|
495
|
+
text: `Figma API request failed: ${error.message}`,
|
|
496
|
+
},
|
|
497
|
+
],
|
|
498
|
+
isError: true,
|
|
499
|
+
};
|
|
500
|
+
}
|
|
501
|
+
// 4. Capture device screenshot and apply crop
|
|
502
|
+
const device = await deviceManager.getDevice();
|
|
503
|
+
const { buffer } = await (0, screenshot_js_1.captureScreenshot)(device);
|
|
504
|
+
let compareBuffer = buffer;
|
|
505
|
+
if (params.cropRef) {
|
|
506
|
+
const entry = refRegistry.resolve(params.cropRef);
|
|
507
|
+
if (!entry) {
|
|
508
|
+
return {
|
|
509
|
+
content: [
|
|
510
|
+
{
|
|
511
|
+
type: "text",
|
|
512
|
+
text: `cropRef "${params.cropRef}" not found. Run devlens_snapshot first.`,
|
|
513
|
+
},
|
|
514
|
+
],
|
|
515
|
+
isError: true,
|
|
516
|
+
};
|
|
517
|
+
}
|
|
518
|
+
compareBuffer = await (0, screenshot_js_1.cropToElement)(buffer, entry.bounds);
|
|
519
|
+
}
|
|
520
|
+
else if (params.region) {
|
|
521
|
+
const sharp = (await import("sharp")).default;
|
|
522
|
+
compareBuffer = await sharp(buffer)
|
|
523
|
+
.extract({
|
|
524
|
+
left: params.region.x,
|
|
525
|
+
top: params.region.y,
|
|
526
|
+
width: params.region.width,
|
|
527
|
+
height: params.region.height,
|
|
528
|
+
})
|
|
529
|
+
.png()
|
|
530
|
+
.toBuffer();
|
|
531
|
+
}
|
|
532
|
+
// 5. Preprocess Figma buffer once — reused for both layout report and comparison
|
|
533
|
+
let processedFigmaBuffer = figmaBuffer;
|
|
534
|
+
if (params.preprocessReference) {
|
|
535
|
+
const ppResult = await (0, image_preprocess_js_1.preprocessImage)(figmaBuffer, { strategy: "auto" });
|
|
536
|
+
processedFigmaBuffer = ppResult.buffer;
|
|
537
|
+
}
|
|
538
|
+
// 6. Layout report — per-element region comparison using accessibility tree
|
|
539
|
+
let layoutReportData;
|
|
540
|
+
if (params.layoutReport) {
|
|
541
|
+
const refs = refRegistry.getAllRefs();
|
|
542
|
+
if (refs.length > 0) {
|
|
543
|
+
try {
|
|
544
|
+
const deviceInfo = await device.getInfo();
|
|
545
|
+
// When cropRef/region is set, the compareBuffer is already cropped.
|
|
546
|
+
// Use the full device screenshot for layout analysis with all refs.
|
|
547
|
+
layoutReportData = await (0, layout_analyzer_js_1.buildLayoutReport)(buffer, processedFigmaBuffer, refs, deviceInfo.screenWidth, deviceInfo.screenHeight);
|
|
548
|
+
}
|
|
549
|
+
catch (err) {
|
|
550
|
+
console.error("[devlens] Layout report failed:", err.message);
|
|
551
|
+
// Don't fail the whole comparison — just omit layout section
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
// 7. Compare — pass already-preprocessed buffer, skip internal preprocess
|
|
556
|
+
return buildComparisonResult(compareBuffer, processedFigmaBuffer, {
|
|
557
|
+
threshold: params.threshold,
|
|
558
|
+
resizeStrategy: params.resizeStrategy,
|
|
559
|
+
preprocessReference: false, // already done above
|
|
560
|
+
layoutReport: layoutReportData,
|
|
561
|
+
});
|
|
562
|
+
},
|
|
563
|
+
};
|
|
564
|
+
}
|
|
565
|
+
//# sourceMappingURL=screenshot-tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"screenshot-tools.js","sourceRoot":"","sources":["../../../src/tools/screenshot-tools.ts"],"names":[],"mappings":"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"}
|