deepadb 1.0.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/LICENSE +21 -0
- package/README.md +631 -0
- package/build/bridge/adb-bridge.d.ts +65 -0
- package/build/bridge/adb-bridge.d.ts.map +1 -0
- package/build/bridge/adb-bridge.js +164 -0
- package/build/bridge/adb-bridge.js.map +1 -0
- package/build/bridge/device-manager.d.ts +41 -0
- package/build/bridge/device-manager.d.ts.map +1 -0
- package/build/bridge/device-manager.js +109 -0
- package/build/bridge/device-manager.js.map +1 -0
- package/build/bridge/local-bridge.d.ts +92 -0
- package/build/bridge/local-bridge.d.ts.map +1 -0
- package/build/bridge/local-bridge.js +345 -0
- package/build/bridge/local-bridge.js.map +1 -0
- package/build/config/config.d.ts +39 -0
- package/build/config/config.d.ts.map +1 -0
- package/build/config/config.js +84 -0
- package/build/config/config.js.map +1 -0
- package/build/graphql-api.d.ts +36 -0
- package/build/graphql-api.d.ts.map +1 -0
- package/build/graphql-api.js +296 -0
- package/build/graphql-api.js.map +1 -0
- package/build/http-transport.d.ts +26 -0
- package/build/http-transport.d.ts.map +1 -0
- package/build/http-transport.js +105 -0
- package/build/http-transport.js.map +1 -0
- package/build/index.d.ts +14 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +66 -0
- package/build/index.js.map +1 -0
- package/build/middleware/chipset.d.ts +29 -0
- package/build/middleware/chipset.d.ts.map +1 -0
- package/build/middleware/chipset.js +123 -0
- package/build/middleware/chipset.js.map +1 -0
- package/build/middleware/cleanup.d.ts +24 -0
- package/build/middleware/cleanup.d.ts.map +1 -0
- package/build/middleware/cleanup.js +53 -0
- package/build/middleware/cleanup.js.map +1 -0
- package/build/middleware/fetch-utils.d.ts +19 -0
- package/build/middleware/fetch-utils.d.ts.map +1 -0
- package/build/middleware/fetch-utils.js +64 -0
- package/build/middleware/fetch-utils.js.map +1 -0
- package/build/middleware/logger.d.ts +17 -0
- package/build/middleware/logger.d.ts.map +1 -0
- package/build/middleware/logger.js +38 -0
- package/build/middleware/logger.js.map +1 -0
- package/build/middleware/output-processor.d.ts +57 -0
- package/build/middleware/output-processor.d.ts.map +1 -0
- package/build/middleware/output-processor.js +162 -0
- package/build/middleware/output-processor.js.map +1 -0
- package/build/middleware/sanitize.d.ts +30 -0
- package/build/middleware/sanitize.d.ts.map +1 -0
- package/build/middleware/sanitize.js +46 -0
- package/build/middleware/sanitize.js.map +1 -0
- package/build/middleware/security.d.ts +52 -0
- package/build/middleware/security.d.ts.map +1 -0
- package/build/middleware/security.js +123 -0
- package/build/middleware/security.js.map +1 -0
- package/build/middleware/ui-dump.d.ts +23 -0
- package/build/middleware/ui-dump.d.ts.map +1 -0
- package/build/middleware/ui-dump.js +59 -0
- package/build/middleware/ui-dump.js.map +1 -0
- package/build/server.d.ts +18 -0
- package/build/server.d.ts.map +1 -0
- package/build/server.js +133 -0
- package/build/server.js.map +1 -0
- package/build/tool-context.d.ts +22 -0
- package/build/tool-context.d.ts.map +1 -0
- package/build/tool-context.js +9 -0
- package/build/tool-context.js.map +1 -0
- package/build/tools/accessibility.d.ts +10 -0
- package/build/tools/accessibility.d.ts.map +1 -0
- package/build/tools/accessibility.js +259 -0
- package/build/tools/accessibility.js.map +1 -0
- package/build/tools/at-commands.d.ts +20 -0
- package/build/tools/at-commands.d.ts.map +1 -0
- package/build/tools/at-commands.js +378 -0
- package/build/tools/at-commands.js.map +1 -0
- package/build/tools/baseband.d.ts +15 -0
- package/build/tools/baseband.d.ts.map +1 -0
- package/build/tools/baseband.js +323 -0
- package/build/tools/baseband.js.map +1 -0
- package/build/tools/build.d.ts +6 -0
- package/build/tools/build.d.ts.map +1 -0
- package/build/tools/build.js +80 -0
- package/build/tools/build.js.map +1 -0
- package/build/tools/ci.d.ts +9 -0
- package/build/tools/ci.d.ts.map +1 -0
- package/build/tools/ci.js +163 -0
- package/build/tools/ci.js.map +1 -0
- package/build/tools/control.d.ts +10 -0
- package/build/tools/control.d.ts.map +1 -0
- package/build/tools/control.js +197 -0
- package/build/tools/control.js.map +1 -0
- package/build/tools/device-farm.d.ts +10 -0
- package/build/tools/device-farm.d.ts.map +1 -0
- package/build/tools/device-farm.js +140 -0
- package/build/tools/device-farm.js.map +1 -0
- package/build/tools/device-profiles.d.ts +16 -0
- package/build/tools/device-profiles.d.ts.map +1 -0
- package/build/tools/device-profiles.js +272 -0
- package/build/tools/device-profiles.js.map +1 -0
- package/build/tools/device.d.ts +6 -0
- package/build/tools/device.d.ts.map +1 -0
- package/build/tools/device.js +72 -0
- package/build/tools/device.js.map +1 -0
- package/build/tools/diagnostics.d.ts +7 -0
- package/build/tools/diagnostics.d.ts.map +1 -0
- package/build/tools/diagnostics.js +153 -0
- package/build/tools/diagnostics.js.map +1 -0
- package/build/tools/emulator.d.ts +9 -0
- package/build/tools/emulator.d.ts.map +1 -0
- package/build/tools/emulator.js +223 -0
- package/build/tools/emulator.js.map +1 -0
- package/build/tools/files.d.ts +6 -0
- package/build/tools/files.d.ts.map +1 -0
- package/build/tools/files.js +78 -0
- package/build/tools/files.js.map +1 -0
- package/build/tools/firmware-analysis.d.ts +24 -0
- package/build/tools/firmware-analysis.d.ts.map +1 -0
- package/build/tools/firmware-analysis.js +623 -0
- package/build/tools/firmware-analysis.js.map +1 -0
- package/build/tools/forwarding.d.ts +7 -0
- package/build/tools/forwarding.d.ts.map +1 -0
- package/build/tools/forwarding.js +64 -0
- package/build/tools/forwarding.js.map +1 -0
- package/build/tools/health.d.ts +7 -0
- package/build/tools/health.d.ts.map +1 -0
- package/build/tools/health.js +112 -0
- package/build/tools/health.js.map +1 -0
- package/build/tools/logcat-watch.d.ts +11 -0
- package/build/tools/logcat-watch.d.ts.map +1 -0
- package/build/tools/logcat-watch.js +209 -0
- package/build/tools/logcat-watch.js.map +1 -0
- package/build/tools/logs.d.ts +6 -0
- package/build/tools/logs.d.ts.map +1 -0
- package/build/tools/logs.js +83 -0
- package/build/tools/logs.js.map +1 -0
- package/build/tools/mirroring.d.ts +14 -0
- package/build/tools/mirroring.d.ts.map +1 -0
- package/build/tools/mirroring.js +243 -0
- package/build/tools/mirroring.js.map +1 -0
- package/build/tools/multi-device.d.ts +9 -0
- package/build/tools/multi-device.d.ts.map +1 -0
- package/build/tools/multi-device.js +138 -0
- package/build/tools/multi-device.js.map +1 -0
- package/build/tools/network-capture.d.ts +10 -0
- package/build/tools/network-capture.d.ts.map +1 -0
- package/build/tools/network-capture.js +143 -0
- package/build/tools/network-capture.js.map +1 -0
- package/build/tools/network-discovery.d.ts +21 -0
- package/build/tools/network-discovery.d.ts.map +1 -0
- package/build/tools/network-discovery.js +284 -0
- package/build/tools/network-discovery.js.map +1 -0
- package/build/tools/ota-monitor.d.ts +16 -0
- package/build/tools/ota-monitor.d.ts.map +1 -0
- package/build/tools/ota-monitor.js +211 -0
- package/build/tools/ota-monitor.js.map +1 -0
- package/build/tools/packages.d.ts +6 -0
- package/build/tools/packages.d.ts.map +1 -0
- package/build/tools/packages.js +237 -0
- package/build/tools/packages.js.map +1 -0
- package/build/tools/plugins.d.ts +22 -0
- package/build/tools/plugins.d.ts.map +1 -0
- package/build/tools/plugins.js +118 -0
- package/build/tools/plugins.js.map +1 -0
- package/build/tools/prompts.d.ts +9 -0
- package/build/tools/prompts.d.ts.map +1 -0
- package/build/tools/prompts.js +94 -0
- package/build/tools/prompts.js.map +1 -0
- package/build/tools/qemu.d.ts +18 -0
- package/build/tools/qemu.d.ts.map +1 -0
- package/build/tools/qemu.js +791 -0
- package/build/tools/qemu.js.map +1 -0
- package/build/tools/registry.d.ts +13 -0
- package/build/tools/registry.d.ts.map +1 -0
- package/build/tools/registry.js +221 -0
- package/build/tools/registry.js.map +1 -0
- package/build/tools/regression.d.ts +10 -0
- package/build/tools/regression.d.ts.map +1 -0
- package/build/tools/regression.js +215 -0
- package/build/tools/regression.js.map +1 -0
- package/build/tools/resources.d.ts +10 -0
- package/build/tools/resources.d.ts.map +1 -0
- package/build/tools/resources.js +77 -0
- package/build/tools/resources.js.map +1 -0
- package/build/tools/ril-intercept.d.ts +24 -0
- package/build/tools/ril-intercept.d.ts.map +1 -0
- package/build/tools/ril-intercept.js +273 -0
- package/build/tools/ril-intercept.js.map +1 -0
- package/build/tools/screen-record.d.ts +9 -0
- package/build/tools/screen-record.d.ts.map +1 -0
- package/build/tools/screen-record.js +95 -0
- package/build/tools/screen-record.js.map +1 -0
- package/build/tools/screenshot-diff.d.ts +13 -0
- package/build/tools/screenshot-diff.d.ts.map +1 -0
- package/build/tools/screenshot-diff.js +370 -0
- package/build/tools/screenshot-diff.js.map +1 -0
- package/build/tools/selinux-audit.d.ts +17 -0
- package/build/tools/selinux-audit.d.ts.map +1 -0
- package/build/tools/selinux-audit.js +301 -0
- package/build/tools/selinux-audit.js.map +1 -0
- package/build/tools/shell.d.ts +6 -0
- package/build/tools/shell.d.ts.map +1 -0
- package/build/tools/shell.js +63 -0
- package/build/tools/shell.js.map +1 -0
- package/build/tools/snapshot.d.ts +9 -0
- package/build/tools/snapshot.d.ts.map +1 -0
- package/build/tools/snapshot.js +192 -0
- package/build/tools/snapshot.js.map +1 -0
- package/build/tools/split-apk.d.ts +13 -0
- package/build/tools/split-apk.d.ts.map +1 -0
- package/build/tools/split-apk.js +229 -0
- package/build/tools/split-apk.js.map +1 -0
- package/build/tools/test-gen.d.ts +14 -0
- package/build/tools/test-gen.d.ts.map +1 -0
- package/build/tools/test-gen.js +252 -0
- package/build/tools/test-gen.js.map +1 -0
- package/build/tools/testing.d.ts +9 -0
- package/build/tools/testing.d.ts.map +1 -0
- package/build/tools/testing.js +144 -0
- package/build/tools/testing.js.map +1 -0
- package/build/tools/thermal-power.d.ts +19 -0
- package/build/tools/thermal-power.d.ts.map +1 -0
- package/build/tools/thermal-power.js +330 -0
- package/build/tools/thermal-power.js.map +1 -0
- package/build/tools/ui.d.ts +6 -0
- package/build/tools/ui.d.ts.map +1 -0
- package/build/tools/ui.js +266 -0
- package/build/tools/ui.js.map +1 -0
- package/build/tools/wireless.d.ts +7 -0
- package/build/tools/wireless.d.ts.map +1 -0
- package/build/tools/wireless.js +78 -0
- package/build/tools/wireless.js.map +1 -0
- package/build/tools/workflow-market.d.ts +17 -0
- package/build/tools/workflow-market.d.ts.map +1 -0
- package/build/tools/workflow-market.js +237 -0
- package/build/tools/workflow-market.js.map +1 -0
- package/build/tools/workflow.d.ts +32 -0
- package/build/tools/workflow.d.ts.map +1 -0
- package/build/tools/workflow.js +374 -0
- package/build/tools/workflow.js.map +1 -0
- package/build/ws-transport.d.ts +30 -0
- package/build/ws-transport.d.ts.map +1 -0
- package/build/ws-transport.js +133 -0
- package/build/ws-transport.js.map +1 -0
- package/package.json +37 -0
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Screenshot Diffing Tools — Pixel-level screenshot comparison for visual regression detection.
|
|
3
|
+
*
|
|
4
|
+
* Extends the regression detection capabilities with visual comparison.
|
|
5
|
+
* Captures baseline screenshots, compares current screen state against them,
|
|
6
|
+
* and reports differences. Uses raw screencap data for pixel-level comparison
|
|
7
|
+
* without external image processing dependencies.
|
|
8
|
+
*
|
|
9
|
+
* Baselines are saved as PNG files in {tempDir}/screenshot-baselines/.
|
|
10
|
+
*/
|
|
11
|
+
import { z } from "zod";
|
|
12
|
+
import { join } from "path";
|
|
13
|
+
import { mkdirSync, writeFileSync, readFileSync, existsSync, readdirSync, statSync, unlinkSync } from "fs";
|
|
14
|
+
import { createHash } from "crypto";
|
|
15
|
+
import { inflateSync } from "zlib";
|
|
16
|
+
import { OutputProcessor } from "../middleware/output-processor.js";
|
|
17
|
+
import { isOnDevice } from "../config/config.js";
|
|
18
|
+
import { shellEscape } from "../middleware/sanitize.js";
|
|
19
|
+
function getBaselineDir(tempDir) {
|
|
20
|
+
return join(tempDir, "screenshot-baselines");
|
|
21
|
+
}
|
|
22
|
+
function sanitizeName(name) {
|
|
23
|
+
return name.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Capture a screenshot and return the local PNG path plus basic metadata.
|
|
27
|
+
* Uses /data/local/tmp/ on-device to avoid scoped storage issues.
|
|
28
|
+
* Cleans up the remote file in a finally block to prevent device file leaks.
|
|
29
|
+
*/
|
|
30
|
+
async function captureScreenshot(ctx, serial, localPath) {
|
|
31
|
+
const remoteDir = isOnDevice() ? "/data/local/tmp" : "/sdcard";
|
|
32
|
+
const remotePath = `${remoteDir}/DA_diff_${Date.now()}.png`;
|
|
33
|
+
try {
|
|
34
|
+
await ctx.bridge.shell(`screencap -p '${shellEscape(remotePath)}'`, { device: serial, timeout: 15000 });
|
|
35
|
+
await ctx.bridge.exec(["pull", remotePath, localPath], { device: serial, timeout: 30000 });
|
|
36
|
+
// Get dimensions from device
|
|
37
|
+
const sizeResult = await ctx.bridge.shell("wm size", { device: serial, ignoreExitCode: true });
|
|
38
|
+
const sizeMatch = sizeResult.stdout.match(/(\d+)x(\d+)/);
|
|
39
|
+
const width = sizeMatch ? parseInt(sizeMatch[1], 10) : 0;
|
|
40
|
+
const height = sizeMatch ? parseInt(sizeMatch[2], 10) : 0;
|
|
41
|
+
// Compute hash and size
|
|
42
|
+
const fileData = readFileSync(localPath);
|
|
43
|
+
const sha256 = createHash("sha256").update(fileData).digest("hex");
|
|
44
|
+
const fileSize = fileData.length;
|
|
45
|
+
return { width, height, fileSize, sha256 };
|
|
46
|
+
}
|
|
47
|
+
finally {
|
|
48
|
+
// Always clean up the device-side screenshot, even if pull/hash throws
|
|
49
|
+
await ctx.bridge.shell(`rm '${shellEscape(remotePath)}'`, { device: serial, ignoreExitCode: true }).catch(() => { });
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Decode a PNG file into raw RGBA pixel data.
|
|
54
|
+
* Parses IHDR for dimensions, concatenates IDAT chunks, inflates, and unfilters.
|
|
55
|
+
* Only handles RGBA (colorType 6) and RGB (colorType 2) — the formats produced
|
|
56
|
+
* by Android's screencap. Returns null if decoding fails.
|
|
57
|
+
*/
|
|
58
|
+
function decodePngPixels(pngPath) {
|
|
59
|
+
try {
|
|
60
|
+
const buf = readFileSync(pngPath);
|
|
61
|
+
// Verify PNG signature
|
|
62
|
+
if (buf.length < 8 || buf[0] !== 0x89 || buf[1] !== 0x50)
|
|
63
|
+
return null;
|
|
64
|
+
let offset = 8;
|
|
65
|
+
let width = 0, height = 0, colorType = 0;
|
|
66
|
+
const idatChunks = [];
|
|
67
|
+
while (offset + 12 <= buf.length) {
|
|
68
|
+
const length = buf.readUInt32BE(offset);
|
|
69
|
+
if (offset + 12 + length > buf.length)
|
|
70
|
+
break;
|
|
71
|
+
const type = buf.slice(offset + 4, offset + 8).toString("ascii");
|
|
72
|
+
const data = buf.slice(offset + 8, offset + 8 + length);
|
|
73
|
+
if (type === "IHDR" && length >= 13) {
|
|
74
|
+
width = data.readUInt32BE(0);
|
|
75
|
+
height = data.readUInt32BE(4);
|
|
76
|
+
colorType = data[9];
|
|
77
|
+
}
|
|
78
|
+
else if (type === "IDAT") {
|
|
79
|
+
idatChunks.push(data);
|
|
80
|
+
}
|
|
81
|
+
else if (type === "IEND") {
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
offset += 12 + length;
|
|
85
|
+
}
|
|
86
|
+
if (width === 0 || height === 0 || idatChunks.length === 0)
|
|
87
|
+
return null;
|
|
88
|
+
const bytesPerPixel = colorType === 6 ? 4 : colorType === 2 ? 3 : 0;
|
|
89
|
+
if (bytesPerPixel === 0)
|
|
90
|
+
return null; // Unsupported color type
|
|
91
|
+
const compressed = Buffer.concat(idatChunks);
|
|
92
|
+
const raw = inflateSync(compressed);
|
|
93
|
+
const rowBytes = 1 + width * bytesPerPixel;
|
|
94
|
+
if (raw.length < rowBytes * height)
|
|
95
|
+
return null;
|
|
96
|
+
// Unfilter — reconstruct actual pixel values from filtered rows
|
|
97
|
+
const pixels = Buffer.alloc(width * height * bytesPerPixel);
|
|
98
|
+
const prevRow = Buffer.alloc(width * bytesPerPixel);
|
|
99
|
+
for (let y = 0; y < height; y++) {
|
|
100
|
+
const rowStart = y * rowBytes;
|
|
101
|
+
const filterType = raw[rowStart];
|
|
102
|
+
const pixelRowStart = y * width * bytesPerPixel;
|
|
103
|
+
for (let x = 0; x < width * bytesPerPixel; x++) {
|
|
104
|
+
let val = raw[rowStart + 1 + x];
|
|
105
|
+
const a = x >= bytesPerPixel ? pixels[pixelRowStart + x - bytesPerPixel] : 0;
|
|
106
|
+
const b = prevRow[x];
|
|
107
|
+
const c = x >= bytesPerPixel ? prevRow[x - bytesPerPixel] : 0;
|
|
108
|
+
switch (filterType) {
|
|
109
|
+
case 0: break;
|
|
110
|
+
case 1:
|
|
111
|
+
val = (val + a) & 0xFF;
|
|
112
|
+
break;
|
|
113
|
+
case 2:
|
|
114
|
+
val = (val + b) & 0xFF;
|
|
115
|
+
break;
|
|
116
|
+
case 3:
|
|
117
|
+
val = (val + Math.floor((a + b) / 2)) & 0xFF;
|
|
118
|
+
break;
|
|
119
|
+
case 4: {
|
|
120
|
+
const p = a + b - c;
|
|
121
|
+
const pa = Math.abs(p - a), pb = Math.abs(p - b), pc = Math.abs(p - c);
|
|
122
|
+
val = (val + (pa <= pb && pa <= pc ? a : pb <= pc ? b : c)) & 0xFF;
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
125
|
+
default: break; // Unknown filter — treat as None
|
|
126
|
+
}
|
|
127
|
+
pixels[pixelRowStart + x] = val;
|
|
128
|
+
}
|
|
129
|
+
pixels.copy(prevRow, 0, pixelRowStart, pixelRowStart + width * bytesPerPixel);
|
|
130
|
+
}
|
|
131
|
+
return { width, height, bytesPerPixel, pixels };
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
return null; // Any decoding failure returns null — caller falls back to byte comparison
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Compare two PNG files at the pixel level.
|
|
139
|
+
* Decodes both PNGs and compares actual RGB pixel values, ignoring alpha.
|
|
140
|
+
* Falls back to byte-level comparison if PNG decoding fails.
|
|
141
|
+
*/
|
|
142
|
+
function compareScreenshots(pathA, pathB) {
|
|
143
|
+
// Attempt pixel-level comparison
|
|
144
|
+
const imgA = decodePngPixels(pathA);
|
|
145
|
+
const imgB = decodePngPixels(pathB);
|
|
146
|
+
if (imgA && imgB && imgA.width === imgB.width && imgA.height === imgB.height) {
|
|
147
|
+
const totalPixels = imgA.width * imgA.height;
|
|
148
|
+
const bpp = imgA.bytesPerPixel;
|
|
149
|
+
let diffPixels = 0;
|
|
150
|
+
let minX = imgA.width, maxX = 0, minY = imgA.height, maxY = 0;
|
|
151
|
+
for (let y = 0; y < imgA.height; y++) {
|
|
152
|
+
for (let x = 0; x < imgA.width; x++) {
|
|
153
|
+
const off = (y * imgA.width + x) * bpp;
|
|
154
|
+
let same = true;
|
|
155
|
+
// Compare RGB channels only (skip alpha at index 3 for RGBA)
|
|
156
|
+
for (let c = 0; c < Math.min(bpp, 3); c++) {
|
|
157
|
+
if (imgA.pixels[off + c] !== imgB.pixels[off + c]) {
|
|
158
|
+
same = false;
|
|
159
|
+
break;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
if (!same) {
|
|
163
|
+
diffPixels++;
|
|
164
|
+
if (x < minX)
|
|
165
|
+
minX = x;
|
|
166
|
+
if (x > maxX)
|
|
167
|
+
maxX = x;
|
|
168
|
+
if (y < minY)
|
|
169
|
+
minY = y;
|
|
170
|
+
if (y > maxY)
|
|
171
|
+
maxY = y;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
const region = diffPixels > 0
|
|
176
|
+
? { minX, minY, maxX, maxY, width: maxX - minX + 1, height: maxY - minY + 1 }
|
|
177
|
+
: null;
|
|
178
|
+
return {
|
|
179
|
+
totalPixels,
|
|
180
|
+
diffPixels,
|
|
181
|
+
diffPercent: totalPixels > 0 ? (diffPixels / totalPixels) * 100 : 0,
|
|
182
|
+
identical: diffPixels === 0,
|
|
183
|
+
region,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
// Fallback: byte-level comparison (if decoding fails or dimensions differ)
|
|
187
|
+
const bufA = readFileSync(pathA);
|
|
188
|
+
const bufB = readFileSync(pathB);
|
|
189
|
+
if (bufA.equals(bufB)) {
|
|
190
|
+
return { totalPixels: 0, diffPixels: 0, diffPercent: 0, identical: true, region: null };
|
|
191
|
+
}
|
|
192
|
+
// Byte diff as rough estimate — report as negative diffPixels to signal fallback
|
|
193
|
+
const maxLen = Math.max(bufA.length, bufB.length);
|
|
194
|
+
let diffBytes = Math.abs(bufA.length - bufB.length);
|
|
195
|
+
for (let i = 0; i < Math.min(bufA.length, bufB.length); i++) {
|
|
196
|
+
if (bufA[i] !== bufB[i])
|
|
197
|
+
diffBytes++;
|
|
198
|
+
}
|
|
199
|
+
return {
|
|
200
|
+
totalPixels: maxLen,
|
|
201
|
+
diffPixels: diffBytes,
|
|
202
|
+
diffPercent: maxLen > 0 ? (diffBytes / maxLen) * 100 : 0,
|
|
203
|
+
identical: false,
|
|
204
|
+
region: null,
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
export function registerScreenshotDiffTools(ctx) {
|
|
208
|
+
ctx.server.tool("adb_screenshot_baseline", "Capture a named screenshot baseline for later comparison. Saves the screenshot and metadata to the baselines directory.", {
|
|
209
|
+
name: z.string().describe("Baseline name (e.g., 'home_screen', 'login_page', 'threat_alert')"),
|
|
210
|
+
device: z.string().optional().describe("Device serial"),
|
|
211
|
+
}, async ({ name, device }) => {
|
|
212
|
+
try {
|
|
213
|
+
const resolved = await ctx.deviceManager.resolveDevice(device);
|
|
214
|
+
const serial = resolved.serial;
|
|
215
|
+
const dir = getBaselineDir(ctx.config.tempDir);
|
|
216
|
+
if (!existsSync(dir))
|
|
217
|
+
mkdirSync(dir, { recursive: true });
|
|
218
|
+
const safeName = sanitizeName(name);
|
|
219
|
+
const pngPath = join(dir, `${safeName}.png`);
|
|
220
|
+
const metaPath = join(dir, `${safeName}.meta.json`);
|
|
221
|
+
const { width, height, fileSize, sha256 } = await captureScreenshot(ctx, serial, pngPath);
|
|
222
|
+
const meta = {
|
|
223
|
+
name,
|
|
224
|
+
timestamp: new Date().toISOString(),
|
|
225
|
+
device: serial,
|
|
226
|
+
width,
|
|
227
|
+
height,
|
|
228
|
+
sha256,
|
|
229
|
+
fileSize,
|
|
230
|
+
};
|
|
231
|
+
writeFileSync(metaPath, JSON.stringify(meta, null, 2));
|
|
232
|
+
return {
|
|
233
|
+
content: [{
|
|
234
|
+
type: "text",
|
|
235
|
+
text: `Screenshot baseline saved: ${safeName}\nPath: ${pngPath}\nDimensions: ${width}x${height}\nSize: ${(fileSize / 1024).toFixed(1)} KB\nSHA-256: ${sha256.substring(0, 16)}...`,
|
|
236
|
+
}],
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
catch (error) {
|
|
240
|
+
return { content: [{ type: "text", text: OutputProcessor.formatError(error) }], isError: true };
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
ctx.server.tool("adb_screenshot_diff", "Compare the current screen against a saved screenshot baseline. Decodes PNGs and performs pixel-level comparison (RGB channels), reporting exact pixel difference count, percentage, and the bounding box of the changed region. Supports a tolerance threshold for absorbing minor dynamic elements like clocks or notification badges.", {
|
|
244
|
+
baseline: z.string().describe("Baseline name to compare against (from adb_screenshot_baseline)"),
|
|
245
|
+
tolerancePercent: z.number().min(0).max(100).optional().default(0)
|
|
246
|
+
.describe("Pixel difference percentage threshold below which the result reports IDENTICAL. 0 = exact match required. 1-2 absorbs clock/status bar changes."),
|
|
247
|
+
device: z.string().optional().describe("Device serial"),
|
|
248
|
+
}, async ({ baseline, tolerancePercent, device }) => {
|
|
249
|
+
try {
|
|
250
|
+
const resolved = await ctx.deviceManager.resolveDevice(device);
|
|
251
|
+
const serial = resolved.serial;
|
|
252
|
+
const dir = getBaselineDir(ctx.config.tempDir);
|
|
253
|
+
const safeName = sanitizeName(baseline);
|
|
254
|
+
const baselinePngPath = join(dir, `${safeName}.png`);
|
|
255
|
+
const baselineMetaPath = join(dir, `${safeName}.meta.json`);
|
|
256
|
+
if (!existsSync(baselinePngPath)) {
|
|
257
|
+
return {
|
|
258
|
+
content: [{ type: "text", text: `Baseline "${baseline}" not found. Use adb_screenshot_baseline to create one first.` }],
|
|
259
|
+
isError: true,
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
// Capture current screenshot
|
|
263
|
+
const currentPngPath = join(dir, `_diff_current_${Date.now()}.png`);
|
|
264
|
+
const current = await captureScreenshot(ctx, serial, currentPngPath);
|
|
265
|
+
// Load baseline metadata if available
|
|
266
|
+
let baselineMeta = null;
|
|
267
|
+
if (existsSync(baselineMetaPath)) {
|
|
268
|
+
try {
|
|
269
|
+
baselineMeta = JSON.parse(readFileSync(baselineMetaPath, "utf-8"));
|
|
270
|
+
}
|
|
271
|
+
catch { /* ignore corrupt meta */ }
|
|
272
|
+
}
|
|
273
|
+
// Quick hash comparison — exact match fast path
|
|
274
|
+
const baselineHash = createHash("sha256").update(readFileSync(baselinePngPath)).digest("hex");
|
|
275
|
+
const hashMatch = baselineHash === current.sha256;
|
|
276
|
+
// Pixel-level comparison (only needed if hashes differ)
|
|
277
|
+
const diff = hashMatch ? null : compareScreenshots(baselinePngPath, currentPngPath);
|
|
278
|
+
const withinTolerance = diff !== null && tolerancePercent > 0 && diff.diffPercent <= tolerancePercent;
|
|
279
|
+
const isMatch = hashMatch || withinTolerance;
|
|
280
|
+
const sections = [];
|
|
281
|
+
sections.push(`=== Screenshot Diff: ${baseline} ===`);
|
|
282
|
+
if (baselineMeta) {
|
|
283
|
+
sections.push(`Baseline: ${baselineMeta.timestamp} (${baselineMeta.width}x${baselineMeta.height})`);
|
|
284
|
+
}
|
|
285
|
+
sections.push(`Current: ${current.width}x${current.height}, ${(current.fileSize / 1024).toFixed(1)} KB`);
|
|
286
|
+
if (tolerancePercent > 0) {
|
|
287
|
+
sections.push(`Tolerance: ${tolerancePercent}%`);
|
|
288
|
+
}
|
|
289
|
+
if (hashMatch) {
|
|
290
|
+
sections.push(`\nResult: ✓ IDENTICAL — screens match exactly.`);
|
|
291
|
+
}
|
|
292
|
+
else if (diff) {
|
|
293
|
+
if (withinTolerance) {
|
|
294
|
+
sections.push(`\nResult: ✓ IDENTICAL (within ${tolerancePercent}% tolerance)`);
|
|
295
|
+
sections.push(`Pixel difference: ${diff.diffPixels.toLocaleString()} of ${diff.totalPixels.toLocaleString()} pixels (${diff.diffPercent.toFixed(4)}%)`);
|
|
296
|
+
}
|
|
297
|
+
else {
|
|
298
|
+
sections.push(`\nResult: ✗ DIFFERENT`);
|
|
299
|
+
sections.push(`Changed pixels: ${diff.diffPixels.toLocaleString()} of ${diff.totalPixels.toLocaleString()} (${diff.diffPercent.toFixed(4)}%)`);
|
|
300
|
+
}
|
|
301
|
+
// Region analysis
|
|
302
|
+
if (diff.region) {
|
|
303
|
+
const r = diff.region;
|
|
304
|
+
sections.push(`Changed region: (${r.minX},${r.minY}) → (${r.maxX},${r.maxY}) — ${r.width}×${r.height} px`);
|
|
305
|
+
if (current.height > 0) {
|
|
306
|
+
const topPct = ((r.minY / current.height) * 100).toFixed(1);
|
|
307
|
+
const botPct = ((r.maxY / current.height) * 100).toFixed(1);
|
|
308
|
+
sections.push(`Vertical span: ${topPct}%–${botPct}% of screen height`);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
// Dimension comparison
|
|
312
|
+
if (baselineMeta) {
|
|
313
|
+
if (baselineMeta.width !== current.width || baselineMeta.height !== current.height) {
|
|
314
|
+
sections.push(`Dimensions changed: ${baselineMeta.width}x${baselineMeta.height} → ${current.width}x${current.height}`);
|
|
315
|
+
}
|
|
316
|
+
const sizeDiff = current.fileSize - baselineMeta.fileSize;
|
|
317
|
+
const sizePct = baselineMeta.fileSize > 0 ? ((sizeDiff / baselineMeta.fileSize) * 100).toFixed(1) : "N/A";
|
|
318
|
+
sections.push(`File size: ${(baselineMeta.fileSize / 1024).toFixed(1)} KB → ${(current.fileSize / 1024).toFixed(1)} KB (${sizeDiff > 0 ? "+" : ""}${sizePct}%)`);
|
|
319
|
+
}
|
|
320
|
+
if (!isMatch) {
|
|
321
|
+
sections.push(`\nCurrent screenshot saved: ${currentPngPath}`);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
// Clean up current screenshot if match (exact or within tolerance)
|
|
325
|
+
if (isMatch) {
|
|
326
|
+
try {
|
|
327
|
+
unlinkSync(currentPngPath);
|
|
328
|
+
}
|
|
329
|
+
catch { /* ignore */ }
|
|
330
|
+
}
|
|
331
|
+
return { content: [{ type: "text", text: sections.join("\n") }] };
|
|
332
|
+
}
|
|
333
|
+
catch (error) {
|
|
334
|
+
return { content: [{ type: "text", text: OutputProcessor.formatError(error) }], isError: true };
|
|
335
|
+
}
|
|
336
|
+
});
|
|
337
|
+
ctx.server.tool("adb_screenshot_history", "List all saved screenshot baselines with their metadata (timestamp, dimensions, device, file size).", {}, async () => {
|
|
338
|
+
try {
|
|
339
|
+
const dir = getBaselineDir(ctx.config.tempDir);
|
|
340
|
+
if (!existsSync(dir)) {
|
|
341
|
+
return { content: [{ type: "text", text: "No screenshot baselines found. Use adb_screenshot_baseline to create one." }] };
|
|
342
|
+
}
|
|
343
|
+
const metaFiles = readdirSync(dir).filter((f) => f.endsWith(".meta.json")).sort();
|
|
344
|
+
if (metaFiles.length === 0) {
|
|
345
|
+
return { content: [{ type: "text", text: "No screenshot baselines found." }] };
|
|
346
|
+
}
|
|
347
|
+
const lines = [`${metaFiles.length} screenshot baseline(s):\n`];
|
|
348
|
+
for (const metaFile of metaFiles) {
|
|
349
|
+
try {
|
|
350
|
+
const meta = JSON.parse(readFileSync(join(dir, metaFile), "utf-8"));
|
|
351
|
+
const pngFile = metaFile.replace(".meta.json", ".png");
|
|
352
|
+
const pngPath = join(dir, pngFile);
|
|
353
|
+
const exists = existsSync(pngPath);
|
|
354
|
+
const sizeKb = exists ? (statSync(pngPath).size / 1024).toFixed(1) : "?";
|
|
355
|
+
lines.push(`${meta.name}`);
|
|
356
|
+
lines.push(` ${meta.timestamp.substring(0, 19)} | ${meta.width}x${meta.height} | ${sizeKb} KB | device: ${meta.device}`);
|
|
357
|
+
}
|
|
358
|
+
catch {
|
|
359
|
+
lines.push(`${metaFile.replace(".meta.json", "")} — metadata corrupt`);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
lines.push(`\nBaseline directory: ${dir}`);
|
|
363
|
+
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
364
|
+
}
|
|
365
|
+
catch (error) {
|
|
366
|
+
return { content: [{ type: "text", text: OutputProcessor.formatError(error) }], isError: true };
|
|
367
|
+
}
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
//# sourceMappingURL=screenshot-diff.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"screenshot-diff.js","sourceRoot":"","sources":["../../src/tools/screenshot-diff.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SELinux & Permission Auditing — OS-level security inspection.
|
|
3
|
+
*
|
|
4
|
+
* Inspects SELinux enforcement mode, queries policy denials from
|
|
5
|
+
* kernel audit logs, and audits runtime permission grants against
|
|
6
|
+
* actual usage to detect over-provisioning.
|
|
7
|
+
*
|
|
8
|
+
* Extends the existing accessibility and security auditing capabilities
|
|
9
|
+
* to the Android OS permission layer. Useful for security hardening,
|
|
10
|
+
* compliance checks, and understanding app permission behavior.
|
|
11
|
+
*
|
|
12
|
+
* Root access recommended for full audit log access; basic SELinux
|
|
13
|
+
* mode and permission grant queries work without root.
|
|
14
|
+
*/
|
|
15
|
+
import { ToolContext } from "../tool-context.js";
|
|
16
|
+
export declare function registerSelinuxAuditTools(ctx: ToolContext): void;
|
|
17
|
+
//# sourceMappingURL=selinux-audit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selinux-audit.d.ts","sourceRoot":"","sources":["../../src/tools/selinux-audit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAiFjD,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,WAAW,GAAG,IAAI,CAkRhE"}
|