deepadb 1.0.7 → 1.0.9
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/README.md +55 -26
- package/build/index.d.ts +1 -1
- package/build/index.js +1 -1
- package/build/middleware/output-processor.d.ts +1 -1
- package/build/middleware/output-processor.js +1 -1
- package/build/middleware/png-utils.d.ts +44 -0
- package/build/middleware/png-utils.d.ts.map +1 -0
- package/build/middleware/png-utils.js +274 -0
- package/build/middleware/png-utils.js.map +1 -0
- package/build/middleware/ui-dump.d.ts +21 -0
- package/build/middleware/ui-dump.d.ts.map +1 -1
- package/build/middleware/ui-dump.js +38 -0
- package/build/middleware/ui-dump.js.map +1 -1
- package/build/server.d.ts.map +1 -1
- package/build/server.js +4 -2
- package/build/server.js.map +1 -1
- package/build/tools/control.d.ts.map +1 -1
- package/build/tools/control.js +60 -7
- package/build/tools/control.js.map +1 -1
- package/build/tools/diagnostics.d.ts +2 -2
- package/build/tools/diagnostics.d.ts.map +1 -1
- package/build/tools/diagnostics.js +86 -3
- package/build/tools/diagnostics.js.map +1 -1
- package/build/tools/input-gestures.d.ts +11 -0
- package/build/tools/input-gestures.d.ts.map +1 -0
- package/build/tools/input-gestures.js +1020 -0
- package/build/tools/input-gestures.js.map +1 -0
- package/build/tools/packages.d.ts.map +1 -1
- package/build/tools/packages.js +71 -0
- package/build/tools/packages.js.map +1 -1
- package/build/tools/screenshot-diff.d.ts.map +1 -1
- package/build/tools/screenshot-diff.js +1 -86
- package/build/tools/screenshot-diff.js.map +1 -1
- package/build/tools/ui.d.ts.map +1 -1
- package/build/tools/ui.js +162 -49
- package/build/tools/ui.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# DeepADB
|
|
2
2
|
|
|
3
|
-
MCP (Model Context Protocol) server providing full Android Debug Bridge (ADB) integration
|
|
3
|
+
MCP (Model Context Protocol) server providing full Android Debug Bridge (ADB) integration for AI agents. Enables MCP clients to directly interact with connected Android devices — inspecting state, running commands, managing apps, capturing logs, controlling device settings, analyzing UI hierarchies, recording screens, managing emulators, running structured test sessions, orchestrating multi-device operations, capturing network traffic, running CI pipelines, auditing accessibility, detecting performance regressions, executing cloud device farm tests, debugging over WiFi, building projects, and managing community plugins.
|
|
4
4
|
|
|
5
|
-
**
|
|
5
|
+
**180 tools, 4 resources, and 4 prompts across 43 modules** — the most comprehensive ADB MCP server available, with triple transport (stdio + HTTP/SSE + WebSocket), optional GraphQL API, defense-in-depth security, modem firmware analysis, workflow marketplace, AT command interface with multi-chipset support, RIL message interception, device profiling, baseband/modem integration, automated test generation, OTA update monitoring, SELinux auditing, thermal/power profiling, network device discovery, visual regression detection, workflow orchestration, accessibility auditing, and contextual truncation.
|
|
6
6
|
|
|
7
7
|
## Architecture
|
|
8
8
|
|
|
@@ -16,7 +16,7 @@ MCP (Model Context Protocol) server providing full Android Debug Bridge (ADB) in
|
|
|
16
16
|
│ DeepADB Server │
|
|
17
17
|
│ │
|
|
18
18
|
│ ┌─────────────────────────────────────────────┐ │
|
|
19
|
-
│ │ Tool Modules (
|
|
19
|
+
│ │ Tool Modules (43) │ │
|
|
20
20
|
│ │ device │ shell │ packages │ files │ logs │ │
|
|
21
21
|
│ │ diagnostics │ ui │ build │ health │ │
|
|
22
22
|
│ │ wireless │ control │ logcat-watch │ │
|
|
@@ -78,15 +78,15 @@ DeepADB operates in two modes, auto-detected at startup:
|
|
|
78
78
|
```
|
|
79
79
|
AI Agent (PC) ←→ MCP ←→ DeepADB (PC) ←→ ADB (USB) ←→ Android Device
|
|
80
80
|
```
|
|
81
|
-
Standard mode: DeepADB runs on a PC/Mac/Linux host and communicates with the device over USB via ADB. All
|
|
81
|
+
Standard mode: DeepADB runs on a PC/Mac/Linux host and communicates with the device over USB via ADB. All 180 tools work through the ADB bridge with automatic retry on transient failures.
|
|
82
82
|
|
|
83
83
|
### On-Device Mode — direct local execution
|
|
84
84
|
```
|
|
85
85
|
AI Agent (Termux) ←→ MCP (stdio/HTTP) ←→ DeepADB (Termux) ←→ sh/su (local)
|
|
86
86
|
```
|
|
87
|
-
When DeepADB runs directly on the Android device (e.g., inside Termux), it auto-detects the environment and switches to `LocalBridge`. Commands execute directly via `sh`/`su` — no ADB server, no USB, no serialization overhead. All
|
|
87
|
+
When DeepADB runs directly on the Android device (e.g., inside Termux), it auto-detects the environment and switches to `LocalBridge`. Commands execute directly via `sh`/`su` — no ADB server, no USB, no serialization overhead. All 180 tools work identically, with significantly lower latency.
|
|
88
88
|
|
|
89
|
-
**Validated on hardware:**
|
|
89
|
+
**Validated on hardware:** 257/257 tests pass on Pixel 6a (Android 16, Termux + Magisk + QEMU 10.2.1) in on-device mode with DA_TEST_PIN. Includes QEMU/KVM virtualization tests covering setup detection, disk image lifecycle, resource budget reporting, Alpine Linux VM boot with KVM acceleration, big.LITTLE CPU topology detection, guest ADB connectivity error handling, and clean VM shutdown. In ADB mode: 235 total (230 passed with DA_TEST_PIN, 5 QEMU tests auto-skip).
|
|
90
90
|
|
|
91
91
|
**Privilege escalation:** In ADB mode, all shell commands run as uid=2000 (the `shell` user) which has system-level permissions. In Termux, commands run as a regular app user. LocalBridge automatically elevates privileged commands through `su` when root (Magisk) is available:
|
|
92
92
|
- **Command allowlist:** 16 system commands (`settings`, `dumpsys`, `am`, `input`, `screencap`, `screenrecord`, `uiautomator`, `app_process`, `getenforce`, `setenforce`, `cmd`, `pm`, `wm`, `svc`, `ip`, `ifconfig`) are routed through `su -c` to match ADB-mode behavior.
|
|
@@ -136,7 +136,7 @@ DA_GRAPHQL_PORT=4000 npm start
|
|
|
136
136
|
}
|
|
137
137
|
```
|
|
138
138
|
|
|
139
|
-
## Available Tools (
|
|
139
|
+
## Available Tools (180)
|
|
140
140
|
|
|
141
141
|
### Health (1 tool)
|
|
142
142
|
- `adb_health_check` — Comprehensive toolchain validation: ADB binary, server, device connection, authorization, root access, and storage writability
|
|
@@ -150,13 +150,15 @@ DA_GRAPHQL_PORT=4000 npm start
|
|
|
150
150
|
- `adb_shell` — Execute arbitrary shell commands with configurable timeout (security-checked)
|
|
151
151
|
- `adb_root_shell` — Execute commands as root via su (requires rooted device, security-checked)
|
|
152
152
|
|
|
153
|
-
### Packages (
|
|
153
|
+
### Packages (12 tools)
|
|
154
154
|
- `adb_install` — Install APK with replace/downgrade options
|
|
155
155
|
- `adb_uninstall` — Remove package with optional data retention
|
|
156
156
|
- `adb_list_packages` — List packages filtered by name or type (all/system/third-party)
|
|
157
157
|
- `adb_package_info` — Detailed package info (version, permissions, paths)
|
|
158
158
|
- `adb_clear_data` — Clear all app data and cache
|
|
159
|
-
- `adb_grant_permission` — Grant runtime
|
|
159
|
+
- `adb_grant_permission` — Grant a runtime permission to a package
|
|
160
|
+
- `adb_revoke_permission` — Revoke a runtime permission from a package (reset permission state for testing denial flows)
|
|
161
|
+
- `adb_list_permissions` — List all declared and granted permissions for a package, filterable by granted/denied
|
|
160
162
|
- `adb_force_stop` — Force-stop an app immediately
|
|
161
163
|
- `adb_start_app` — Launch an app by package name (resolves launcher activity)
|
|
162
164
|
- `adb_restart_app` — Force-stop then re-launch in one call (configurable delay)
|
|
@@ -179,7 +181,7 @@ DA_GRAPHQL_PORT=4000 npm start
|
|
|
179
181
|
- `adb_logcat_stop` — Stop a watcher session (or all sessions)
|
|
180
182
|
- `adb_logcat_sessions` — List all active watcher sessions with stats
|
|
181
183
|
|
|
182
|
-
### Diagnostics (
|
|
184
|
+
### Diagnostics (9 tools)
|
|
183
185
|
- `adb_dumpsys` — Run dumpsys for any service (or list all services)
|
|
184
186
|
- `adb_telephony` — Cell info, signal strength, and network registration (parallel query)
|
|
185
187
|
- `adb_battery` — Battery status, level, temperature, and charging info
|
|
@@ -187,14 +189,18 @@ DA_GRAPHQL_PORT=4000 npm start
|
|
|
187
189
|
- `adb_top` — CPU and memory usage snapshot
|
|
188
190
|
- `adb_perf_snapshot` — Parallel memory, frame stats, and CPU profiling for a package
|
|
189
191
|
- `adb_bugreport` — Full bug report zip capture (device state, logs, system info)
|
|
192
|
+
- `adb_crash_logs` — ANR traces and tombstone crash dumps from /data/anr/ and /data/tombstones/
|
|
193
|
+
- `adb_heap_dump` — Capture heap dump (.hprof) from a running process for memory analysis
|
|
190
194
|
|
|
191
|
-
### UI (
|
|
195
|
+
### UI (10 tools)
|
|
192
196
|
- `adb_screencap` — Take screenshot with filename sanitization, saves locally
|
|
197
|
+
- `adb_screencap_annotated` — Screenshot with UI element bounding boxes and numbered labels composited onto the PNG. Returns annotated image path plus a text legend. Ideal for LLM workflows that reference elements by number
|
|
193
198
|
- `adb_current_activity` — Get focused activity and top window stack
|
|
194
199
|
- `adb_input` — Send tap, swipe, text, or keyevent input
|
|
195
200
|
- `adb_start_activity` — Launch activities by intent or component name
|
|
196
|
-
- `adb_ui_dump` — Dump full UI hierarchy
|
|
201
|
+
- `adb_ui_dump` — Dump full UI hierarchy. Supports three output formats: `text` (default, human-readable), `tsv` (compact tab-separated for token-efficient automation loops), `xml` (raw uiautomator XML)
|
|
197
202
|
- `adb_ui_find` — Search UI hierarchy by text, resource-id, or content-description (returns tap coordinates)
|
|
203
|
+
- `adb_screen_state` — Combined screen state in one call: foreground activity, screen dimensions and density, orientation, battery level, and a TSV list of interactive elements. Replaces 3–4 separate tool calls
|
|
198
204
|
- `adb_screenrecord_start` — Start recording the device screen (1-180s, stored on device)
|
|
199
205
|
- `adb_screenrecord_stop` — Stop recording and pull the mp4 video file locally
|
|
200
206
|
|
|
@@ -204,7 +210,7 @@ DA_GRAPHQL_PORT=4000 npm start
|
|
|
204
210
|
- `adb_wifi` — Enable or disable WiFi
|
|
205
211
|
- `adb_mobile_data` — Enable or disable mobile data
|
|
206
212
|
- `adb_location` — Set location mode (off/sensors/battery/high)
|
|
207
|
-
- `adb_screen` — Wake, sleep, toggle, or unlock (swipe) the screen
|
|
213
|
+
- `adb_screen` — Wake, sleep, toggle, lock, or unlock the screen. Lock verifies keyguard state via `dumpsys window`. Unlock uses `wm dismiss-keyguard` (works for swipe keyguards); supply `pin` to perform the full PIN entry sequence: wakes screen, swipes up to reveal keypad, types PIN, confirms, and verifies the keyguard sleep token was released
|
|
208
214
|
- `adb_settings_get` — Read any Android setting from system/secure/global namespace
|
|
209
215
|
- `adb_settings_put` — Write any Android setting with read-back verification
|
|
210
216
|
- `adb_reboot` — Reboot device (normal, recovery, or bootloader mode)
|
|
@@ -246,6 +252,28 @@ DA_GRAPHQL_PORT=4000 npm start
|
|
|
246
252
|
- `adb_multi_compare` — Run a command on all devices and highlight output differences
|
|
247
253
|
- `adb_multi_test` — Comparative test workflow: run predefined diagnostic profiles (firmware/security/network/identity/full) or custom command lists across all devices including QEMU guests, compare per-check, report matches and differences
|
|
248
254
|
|
|
255
|
+
### Input Gestures & UI Automation (15 tools)
|
|
256
|
+
- `adb_input_drag` — Drag from point A to point B (uses `draganddrop` with swipe fallback for older Android)
|
|
257
|
+
- `adb_input_fling` — High-velocity fling gesture for momentum-scrolling through lists and paged views (configurable duration 20-200ms)
|
|
258
|
+
- `adb_input_long_press` — Long press at coordinates with configurable hold duration
|
|
259
|
+
- `adb_input_double_tap` — Double tap with configurable interval between taps
|
|
260
|
+
- `adb_input_text` — Dedicated text input with space/special character handling
|
|
261
|
+
- `adb_open_url` — Open a URL on the device via VIEW intent
|
|
262
|
+
- `adb_orientation` — Get or set screen orientation (auto/portrait/landscape/reverse)
|
|
263
|
+
- `adb_clipboard` — Read or write device clipboard
|
|
264
|
+
- `adb_input_pinch` — Multi-touch pinch (zoom out) or spread (zoom in) gesture. Two fingers move symmetrically around a center point. Layered injection: parallel `input swipe` (universal, no root) or raw `sendevent` MT Type B protocol (true multi-touch, root required). Auto-detects touchscreen device and capabilities via `getevent -p`. Configurable center, radius, duration, angle, and interpolation steps
|
|
265
|
+
- `adb_tap_element` — Find element by text/resource-id/content-description and tap its center
|
|
266
|
+
- `adb_wait_element` — Poll UI hierarchy until an element appears or disappears (configurable timeout/poll interval)
|
|
267
|
+
- `adb_wait_stable` — Poll until consecutive UI dumps match (screen stabilization after transitions)
|
|
268
|
+
- `adb_scroll_until` — Scroll repeatedly until a target element is found, with optional auto-tap
|
|
269
|
+
- `adb_screenshot_compressed` — Capture screenshot with size/quality metadata for token-efficient workflows
|
|
270
|
+
- `adb_batch_actions` — Execute multiple input actions (tap/swipe/fling/long_press/double_tap/keyevent/text/drag/pinch/back/home/sleep) in a single tool call with security validation
|
|
271
|
+
|
|
272
|
+
### Device Awareness (3 tools)
|
|
273
|
+
- `adb_screen_size` — Screen resolution, display density (DPI), aspect ratio, and DP width in one call
|
|
274
|
+
- `adb_device_state` — Combined snapshot: battery level/status/temp, network type, WiFi state, screen on/off, orientation, foreground activity
|
|
275
|
+
- `adb_notifications` — Parse active notifications with package, title, text, importance, channel, flags, and timestamp (filterable by package)
|
|
276
|
+
|
|
249
277
|
### Snapshot/Restore (3 tools)
|
|
250
278
|
- `adb_snapshot_capture` — Save comprehensive device state (packages, settings, properties) to JSON
|
|
251
279
|
- `adb_snapshot_compare` — Diff current state against a saved snapshot (added/removed packages, changed settings)
|
|
@@ -412,10 +440,10 @@ Background logcat watchers run as spawned processes with ring buffer accumulatio
|
|
|
412
440
|
Full view tree capture via `uiautomator dump` with parsed XML extraction. Returns structured element data including text, resource-id, content-description, class names, bounds coordinates with tap-ready center points, and interaction flags. Pre-compiled regex attribute extraction for efficient parsing.
|
|
413
441
|
|
|
414
442
|
### Security Middleware
|
|
415
|
-
Multi-layered security activated via `DA_SECURITY=true`. Provides command blocklist/allowlist filtering, rate limiting (commands per minute), and audit logging with automatic credential redaction. Security checks are integrated into `adb_shell`, `adb_root_shell`, `adb_multi_shell`, `adb_multi_compare`, `adb_input`, and `adb_start_activity`. Configurable via environment variables for different deployment scenarios.
|
|
443
|
+
Multi-layered security activated via `DA_SECURITY=true`. Provides command blocklist/allowlist filtering, rate limiting (commands per minute), and audit logging with automatic credential redaction. Security checks are integrated into `adb_shell`, `adb_root_shell`, `adb_multi_shell`, `adb_multi_compare`, `adb_input`, `adb_batch_actions`, and `adb_start_activity`. Configurable via environment variables for different deployment scenarios.
|
|
416
444
|
|
|
417
445
|
### Input Sanitization
|
|
418
|
-
All tools that interpolate user-supplied parameters into shell command strings validate inputs against shell metacharacters before execution. Package names, property keys, service names, setting keys, test identifiers, network interface names, and tcpdump filters are all validated through a centralized `validateShellArg()` function that rejects `;`, `|`, `&`, `$`, backticks, parentheses, and other injection vectors. File paths use single-quoted shell escaping to prevent `$()` command substitution. The `adb_input` tool applies type-specific validation: `tap`/`swipe` accept only numeric coordinates, `keyevent` accepts only alphanumeric keycodes, and `text` is shell-escaped for literal delivery. Deserialized JSON from snapshot files is validated before shell interpolation. Every `z.number()` parameter across all
|
|
446
|
+
All tools that interpolate user-supplied parameters into shell command strings validate inputs against shell metacharacters before execution. Package names, property keys, service names, setting keys, test identifiers, network interface names, and tcpdump filters are all validated through a centralized `validateShellArg()` function that rejects `;`, `|`, `&`, `$`, backticks, parentheses, and other injection vectors. File paths use single-quoted shell escaping to prevent `$()` command substitution. The `adb_input` tool applies type-specific validation: `tap`/`swipe` accept only numeric coordinates, `keyevent` accepts only alphanumeric keycodes, and `text` is shell-escaped for literal delivery. The `adb_batch_actions` tool enforces the same per-action-type validation (digits-only for coordinates, alphanumeric for keycodes, shell-escape for text) and routes every assembled command through the security middleware. Deserialized JSON from snapshot files is validated before shell interpolation. Every `z.number()` parameter across all 180 tools has explicit `.min()/.max()` Zod bounds to prevent resource exhaustion from extreme values. The LocalBridge has explicit handlers for every ADB subcommand used by tool modules, preventing unquoted fallthrough to the default shell handler. In on-device mode, privilege escalation uses a frozen 16-command allowlist and restricted-path regex — the elevation set is `ReadonlySet` + `Object.freeze`, not configurable at runtime. The HTTP/SSE transport denies cross-origin requests by default (configurable via `DA_HTTP_CORS_ORIGIN`), the plugin registry verifies SHA-256 integrity hashes and prevents path traversal via directory containment checks, and the workflow engine enforces step count (200), sleep duration (5 min), and repeat iteration (100) limits. Fetch helpers enforce a 5 MB response body limit. Getprop output parsing handles Windows `\r\n` line endings via `.trim()` before regex matching, and dual SIM slot counts are capped at 4 to prevent resource exhaustion from corrupted device properties.
|
|
419
447
|
|
|
420
448
|
### Multi-Device Orchestration
|
|
421
449
|
Run commands, install APKs, and compare outputs across multiple connected devices in parallel. Essential for comparative testing across Android versions and device models.
|
|
@@ -505,7 +533,7 @@ Scans the local network for ADB-enabled devices via ARP table queries and option
|
|
|
505
533
|
On-device virtual machine management using QEMU with KVM hardware acceleration. Enables running guest Android VMs directly on the physical device — a capability unique to DeepADB. Dynamic resource allocation auto-detects host CPU cores and physical RAM, reserving 1 core and 35% of memory for the host OS to prevent starvation. Multi-VM support tracks resource consumption across concurrent VMs, refusing new VMs when the pool is exhausted rather than degrading host performance. Disk image management with qcow2 (sparse, snapshot-capable) and raw formats. ADB port forwarding to guest VMs enables DeepADB's full tool suite to target both host and guest devices simultaneously. Process lifecycle tracked via the centralized cleanup registry with SIGTERM/SIGKILL shutdown. Path containment verification on all image operations prevents directory traversal.
|
|
506
534
|
|
|
507
535
|
### ToolContext Architecture
|
|
508
|
-
All
|
|
536
|
+
All 43 tool modules receive a unified `ToolContext` dependency bundle containing server, bridge, deviceManager, logger, security, and config. Adding new cross-cutting dependencies requires no module signature changes.
|
|
509
537
|
|
|
510
538
|
## Environment Variables
|
|
511
539
|
|
|
@@ -558,20 +586,20 @@ DeepADB/
|
|
|
558
586
|
│ │ ├── health.ts # Toolchain health check (1 tool)
|
|
559
587
|
│ │ ├── device.ts # Device info and properties (3 tools)
|
|
560
588
|
│ │ ├── shell.ts # Shell and root command execution (2 tools)
|
|
561
|
-
│ │ ├── packages.ts # App lifecycle, install, permissions, intents (
|
|
589
|
+
│ │ ├── packages.ts # App lifecycle, install, permissions, intents (12 tools)
|
|
562
590
|
│ │ ├── files.ts # Push, pull, ls, cat (4 tools)
|
|
563
591
|
│ │ ├── logs.ts # Logcat snapshots — filtered (3 tools)
|
|
564
592
|
│ │ ├── logcat-watch.ts # Persistent logcat with ring buffer and poll (4 tools)
|
|
565
|
-
│ │ ├── diagnostics.ts # dumpsys, telephony, battery, network, perf, bugreport (
|
|
566
|
-
│ │ ├── ui.ts # Screenshots, input, activity, UI hierarchy (
|
|
593
|
+
│ │ ├── diagnostics.ts # dumpsys, telephony, battery, network, perf, bugreport, crash logs, heap dump (9 tools)
|
|
594
|
+
│ │ ├── ui.ts # Screenshots, input, activity, UI hierarchy, annotated screencap, screen state (8 tools)
|
|
567
595
|
│ │ ├── screen-record.ts # Screen video recording start/stop (2 tools)
|
|
568
596
|
│ │ ├── control.ts # Airplane, WiFi, data, location, screen, settings, reboot (9 tools)
|
|
569
597
|
│ │ ├── wireless.ts # WiFi pairing, connect, disconnect, TCP/IP (4 tools)
|
|
570
598
|
│ │ ├── forwarding.ts # Port forwarding and reverse forwarding (3 tools)
|
|
571
599
|
│ │ ├── emulator.ts # AVD list, start, stop with on-device KVM/QEMU detection (3 tools)
|
|
572
|
-
│ │ ├── qemu.ts # QEMU/KVM VM management — setup, images, start, stop, status (
|
|
600
|
+
│ │ ├── qemu.ts # QEMU/KVM VM management — setup, images, start, stop, status, guest ADB connect/disconnect/shell (8 tools)
|
|
573
601
|
│ │ ├── testing.ts # Structured test sessions with numbered steps (3 tools)
|
|
574
|
-
│ │ ├── multi-device.ts # Multi-device shell, install, compare (
|
|
602
|
+
│ │ ├── multi-device.ts # Multi-device shell, install, compare, comparative testing (4 tools)
|
|
575
603
|
│ │ ├── snapshot.ts # Device state capture, compare, restore (3 tools)
|
|
576
604
|
│ │ ├── network-capture.ts # tcpdump start/stop, network connections (3 tools)
|
|
577
605
|
│ │ ├── ci.ts # CI wait-boot, device-ready, run-tests (3 tools)
|
|
@@ -581,7 +609,7 @@ DeepADB/
|
|
|
581
609
|
│ │ ├── regression.ts # Performance baseline and regression detection (3 tools)
|
|
582
610
|
│ │ ├── device-farm.ts # Firebase Test Lab integration via gcloud (3 tools)
|
|
583
611
|
│ │ ├── registry.ts # Community plugin registry search/install (3 tools)
|
|
584
|
-
│ │ ├── at-commands.ts # AT command modem interface, multi-chipset (
|
|
612
|
+
│ │ ├── at-commands.ts # AT command modem interface, multi-chipset, cross-validation (5 tools)
|
|
585
613
|
│ │ ├── screenshot-diff.ts # Visual regression — screenshot baseline/diff (3 tools)
|
|
586
614
|
│ │ ├── workflow.ts # Declarative workflow orchestration engine (3 tools)
|
|
587
615
|
│ │ ├── split-apk.ts # App bundles, split APKs, APEX modules (4 tools)
|
|
@@ -606,6 +634,7 @@ DeepADB/
|
|
|
606
634
|
│ │ ├── sanitize.ts # Shell injection prevention — validateShellArg/validateShellArgs/shellEscape
|
|
607
635
|
│ │ ├── chipset.ts # Shared chipset family detection, modem path mapping, SIM config detection
|
|
608
636
|
│ │ ├── fetch-utils.ts # Shared HTTP helpers with 5 MB streaming response size limit
|
|
637
|
+
│ │ ├── png-utils.ts # Zero-dependency PNG decode/encode/draw primitives for screenshot annotation and diffing
|
|
609
638
|
│ │ ├── ui-dump.ts # Shared uiautomator XML capture with concurrent-safe paths, on-device /data/local/tmp routing, and cleanup
|
|
610
639
|
│ │ ├── cleanup.ts # Centralized process cleanup registry for SIGINT/SIGTERM/exit
|
|
611
640
|
│ │ └── logger.ts # stderr-safe logging (MCP-compliant)
|
|
@@ -620,14 +649,14 @@ DeepADB/
|
|
|
620
649
|
├── LICENSE # MIT license
|
|
621
650
|
├── tests/
|
|
622
651
|
│ ├── run-all.mjs # Run all test suites sequentially with summary (tracks skipped counts)
|
|
623
|
-
│ ├── test-hw.mjs # Hardware core: health, identity, baseband, thermal, profiles, wireless firmware (
|
|
652
|
+
│ ├── test-hw.mjs # Hardware core: health, identity, baseband, thermal, profiles, wireless firmware, crash analysis (34 tests)
|
|
624
653
|
│ ├── test-shell-files.mjs # Shell, filesystem, packages, diagnostics (24 tests)
|
|
625
|
-
│ ├── test-ui-control.mjs # UI hierarchy, screenshots, settings, accessibility (
|
|
654
|
+
│ ├── test-ui-control.mjs # UI hierarchy, screenshots, settings, input gestures, UI automation, device awareness, accessibility, screen lock/unlock, multi-touch (46 tests)
|
|
626
655
|
│ ├── test-monitoring.mjs # Logcat watchers, snapshots, OTA, regression, workflows (25 tests)
|
|
627
656
|
│ ├── test-security.mjs # Input sanitization, shell injection, AT command safety (25 tests)
|
|
628
657
|
│ ├── test-lifecycle.mjs # App lifecycle, file push/pull, input, port forwarding, screen recording, test sessions (22 tests)
|
|
629
|
-
│ ├── test-analysis.mjs # Thermal/snapshot/regression comparison, firmware diff, screenshot diff, test gen, RIL intercept, AT cross-validation (
|
|
630
|
-
│ ├── test-boundaries.mjs # Zod bounds enforcement, input injection, error paths, sensitive data protection (
|
|
658
|
+
│ ├── test-analysis.mjs # Thermal/snapshot/regression comparison, firmware diff, screenshot diff, test gen, RIL intercept, AT cross-validation, permission management (23 tests)
|
|
659
|
+
│ ├── test-boundaries.mjs # Zod bounds enforcement, input injection, error paths, sensitive data protection (31 tests)
|
|
631
660
|
│ ├── test-qemu.mjs # QEMU/KVM setup, image management, VM status, guest connectivity errors (13 on-device tests)
|
|
632
661
|
│ ├── test-qemu-boot.mjs # QEMU Alpine VM boot, KVM acceleration, topology detection, guest ADB connectivity (14 on-device tests)
|
|
633
662
|
│ └── lib/
|
package/build/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* DeepADB — MCP Server for Android Debug Bridge
|
|
4
4
|
*
|
|
5
5
|
* Entry point. Supports three transport modes (mutually exclusive):
|
|
6
|
-
* - stdio (default) — JSON-RPC over stdin/stdout for Claude Code
|
|
6
|
+
* - stdio (default) — JSON-RPC over stdin/stdout for MCP clients (Claude Code, etc.)
|
|
7
7
|
* - HTTP/SSE — Set DA_HTTP_PORT to enable browser-based MCP clients
|
|
8
8
|
* - WebSocket — Set DA_WS_PORT to enable bidirectional streaming (requires `ws` package)
|
|
9
9
|
*
|
package/build/index.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* DeepADB — MCP Server for Android Debug Bridge
|
|
4
4
|
*
|
|
5
5
|
* Entry point. Supports three transport modes (mutually exclusive):
|
|
6
|
-
* - stdio (default) — JSON-RPC over stdin/stdout for Claude Code
|
|
6
|
+
* - stdio (default) — JSON-RPC over stdin/stdout for MCP clients (Claude Code, etc.)
|
|
7
7
|
* - HTTP/SSE — Set DA_HTTP_PORT to enable browser-based MCP clients
|
|
8
8
|
* - WebSocket — Set DA_WS_PORT to enable bidirectional streaming (requires `ws` package)
|
|
9
9
|
*
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Output Processor — Truncation, formatting, structured parsing, and binary handling.
|
|
3
3
|
*
|
|
4
|
-
* Sits between raw ADB output and what gets returned to
|
|
4
|
+
* Sits between raw ADB output and what gets returned to the MCP client.
|
|
5
5
|
* Prevents context window blowout from verbose commands.
|
|
6
6
|
*/
|
|
7
7
|
export declare class OutputProcessor {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Output Processor — Truncation, formatting, structured parsing, and binary handling.
|
|
3
3
|
*
|
|
4
|
-
* Sits between raw ADB output and what gets returned to
|
|
4
|
+
* Sits between raw ADB output and what gets returned to the MCP client.
|
|
5
5
|
* Prevents context window blowout from verbose commands.
|
|
6
6
|
*/
|
|
7
7
|
import { config } from "../config/config.js";
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PNG Utilities — Zero-dependency PNG decode and encode for screenshot analysis and annotation.
|
|
3
|
+
*
|
|
4
|
+
* Provides pixel-level PNG decode (used by screenshot-diff.ts and ui.ts),
|
|
5
|
+
* PNG encode (used by ui.ts for annotated screenshots), and drawing primitives
|
|
6
|
+
* for compositing bounding boxes and number labels onto pixel buffers.
|
|
7
|
+
*
|
|
8
|
+
* No external image library dependencies — uses only Node.js built-ins (zlib, fs).
|
|
9
|
+
*/
|
|
10
|
+
/** Cycling color palette for element bounding box annotation. */
|
|
11
|
+
export declare const ELEMENT_COLORS: ReadonlyArray<readonly [number, number, number]>;
|
|
12
|
+
/**
|
|
13
|
+
* Draw a rectangle border on a pixel buffer (in-place).
|
|
14
|
+
* Coordinates are clamped to image bounds. Thickness applies inward from each edge.
|
|
15
|
+
*/
|
|
16
|
+
export declare function drawRect(pixels: Buffer, imgWidth: number, imgHeight: number, bpp: number, x1: number, y1: number, x2: number, y2: number, color: readonly [number, number, number], thickness?: number): void;
|
|
17
|
+
/**
|
|
18
|
+
* Draw a filled label showing a number at pixel position (x, y).
|
|
19
|
+
* Background uses the provided color; foreground (digit pixels) auto-contrasts.
|
|
20
|
+
* Label is clamped to stay within image bounds.
|
|
21
|
+
* Each digit glyph is 5×7 px with 1 px padding on all sides.
|
|
22
|
+
*/
|
|
23
|
+
export declare function drawLabel(pixels: Buffer, imgWidth: number, imgHeight: number, bpp: number, x: number, y: number, num: number, bgColor: readonly [number, number, number]): void;
|
|
24
|
+
/** Decoded PNG image: raw RGB or RGBA pixel data with dimensions. */
|
|
25
|
+
export interface PngImage {
|
|
26
|
+
width: number;
|
|
27
|
+
height: number;
|
|
28
|
+
bytesPerPixel: number;
|
|
29
|
+
pixels: Buffer;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Decode a PNG file into raw pixel data.
|
|
33
|
+
* Handles RGBA (colorType 6) and RGB (colorType 2) — both produced by Android screencap.
|
|
34
|
+
* All 5 PNG row filter types (None, Sub, Up, Average, Paeth) are unfiltered.
|
|
35
|
+
* Returns null on any parse or decompression error — callers should handle gracefully.
|
|
36
|
+
*/
|
|
37
|
+
export declare function decodePngPixels(pngPath: string): PngImage | null;
|
|
38
|
+
/**
|
|
39
|
+
* Encode a raw pixel buffer as a PNG file in memory.
|
|
40
|
+
* Uses filter type 0 (None) on every scanline and level-1 (fast) deflate.
|
|
41
|
+
* bpp must be 3 (RGB) or 4 (RGBA) to match the input data.
|
|
42
|
+
*/
|
|
43
|
+
export declare function encodePng(width: number, height: number, pixels: Buffer, bpp: 3 | 4): Buffer;
|
|
44
|
+
//# sourceMappingURL=png-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"png-utils.d.ts","sourceRoot":"","sources":["../../src/middleware/png-utils.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAyDH,iEAAiE;AACjE,eAAO,MAAM,cAAc,EAAE,aAAa,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CASlE,CAAC;AAiBX;;;GAGG;AACH,wBAAgB,QAAQ,CACtB,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAChE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAC9C,KAAK,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EACxC,SAAS,SAAI,GACZ,IAAI,CAmBN;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CACvB,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAChE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EACjC,OAAO,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,GACzC,IAAI,CA4CN;AAID,qEAAqE;AACrE,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAU,MAAM,CAAC;IACtB,MAAM,EAAS,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAS,MAAM,CAAC;CACvB;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAkFhE;AAID;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,GAAG,MAAM,CA0B3F"}
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PNG Utilities — Zero-dependency PNG decode and encode for screenshot analysis and annotation.
|
|
3
|
+
*
|
|
4
|
+
* Provides pixel-level PNG decode (used by screenshot-diff.ts and ui.ts),
|
|
5
|
+
* PNG encode (used by ui.ts for annotated screenshots), and drawing primitives
|
|
6
|
+
* for compositing bounding boxes and number labels onto pixel buffers.
|
|
7
|
+
*
|
|
8
|
+
* No external image library dependencies — uses only Node.js built-ins (zlib, fs).
|
|
9
|
+
*/
|
|
10
|
+
import { readFileSync } from "fs";
|
|
11
|
+
import { inflateSync, deflateSync } from "zlib";
|
|
12
|
+
// ── CRC32 ─────────────────────────────────────────────────────────────
|
|
13
|
+
const CRC32_TABLE = (() => {
|
|
14
|
+
const table = [];
|
|
15
|
+
for (let n = 0; n < 256; n++) {
|
|
16
|
+
let c = n;
|
|
17
|
+
for (let k = 0; k < 8; k++) {
|
|
18
|
+
c = (c & 1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1);
|
|
19
|
+
}
|
|
20
|
+
table[n] = c >>> 0;
|
|
21
|
+
}
|
|
22
|
+
return table;
|
|
23
|
+
})();
|
|
24
|
+
function crc32(buf) {
|
|
25
|
+
let crc = 0xFFFFFFFF;
|
|
26
|
+
for (let i = 0; i < buf.length; i++) {
|
|
27
|
+
crc = ((CRC32_TABLE[(crc ^ buf[i]) & 0xFF] ?? 0) ^ (crc >>> 8)) >>> 0;
|
|
28
|
+
}
|
|
29
|
+
return (crc ^ 0xFFFFFFFF) >>> 0;
|
|
30
|
+
}
|
|
31
|
+
function makePngChunk(type, data) {
|
|
32
|
+
const lenBuf = Buffer.allocUnsafe(4);
|
|
33
|
+
lenBuf.writeUInt32BE(data.length, 0);
|
|
34
|
+
const typeBuf = Buffer.from(type, "ascii");
|
|
35
|
+
const crcBuf = Buffer.allocUnsafe(4);
|
|
36
|
+
crcBuf.writeUInt32BE(crc32(Buffer.concat([typeBuf, data])), 0);
|
|
37
|
+
return Buffer.concat([lenBuf, typeBuf, data, crcBuf]);
|
|
38
|
+
}
|
|
39
|
+
// ── 5×7 pixel font for digits 0–9 ─────────────────────────────────────
|
|
40
|
+
/**
|
|
41
|
+
* Each digit: 7 rows, each row a 5-bit mask (MSB = leftmost pixel).
|
|
42
|
+
* Bit 16 (0b10000) = leftmost column, bit 1 (0b00001) = rightmost.
|
|
43
|
+
*/
|
|
44
|
+
const DIGIT_FONT = [
|
|
45
|
+
[14, 17, 17, 17, 17, 17, 14], // 0
|
|
46
|
+
[4, 12, 4, 4, 4, 4, 14], // 1
|
|
47
|
+
[14, 17, 1, 2, 4, 8, 31], // 2
|
|
48
|
+
[30, 1, 1, 14, 1, 1, 30], // 3
|
|
49
|
+
[2, 6, 10, 18, 31, 2, 2], // 4
|
|
50
|
+
[31, 16, 16, 30, 1, 1, 30], // 5
|
|
51
|
+
[14, 16, 16, 30, 17, 17, 14], // 6
|
|
52
|
+
[31, 1, 2, 4, 8, 8, 8], // 7
|
|
53
|
+
[14, 17, 17, 14, 17, 17, 14], // 8
|
|
54
|
+
[14, 17, 17, 15, 1, 1, 14], // 9
|
|
55
|
+
];
|
|
56
|
+
// ── Color palette ──────────────────────────────────────────────────────
|
|
57
|
+
/** Cycling color palette for element bounding box annotation. */
|
|
58
|
+
export const ELEMENT_COLORS = [
|
|
59
|
+
[255, 50, 50], // red
|
|
60
|
+
[50, 210, 50], // green
|
|
61
|
+
[50, 100, 255], // blue
|
|
62
|
+
[255, 200, 0], // yellow
|
|
63
|
+
[0, 210, 210], // cyan
|
|
64
|
+
[255, 100, 200], // pink
|
|
65
|
+
[220, 110, 0], // orange
|
|
66
|
+
[160, 50, 220], // purple
|
|
67
|
+
];
|
|
68
|
+
// ── Pixel operations ───────────────────────────────────────────────────
|
|
69
|
+
/** Write one pixel into a packed row-major RGB/RGBA pixel buffer. No-op if x is out of range. */
|
|
70
|
+
function setPixel(pixels, imgWidth, bpp, x, y, r, g, b) {
|
|
71
|
+
if (x < 0 || x >= imgWidth)
|
|
72
|
+
return;
|
|
73
|
+
const off = (y * imgWidth + x) * bpp;
|
|
74
|
+
pixels[off] = r;
|
|
75
|
+
pixels[off + 1] = g;
|
|
76
|
+
pixels[off + 2] = b;
|
|
77
|
+
if (bpp === 4)
|
|
78
|
+
pixels[off + 3] = 255;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Draw a rectangle border on a pixel buffer (in-place).
|
|
82
|
+
* Coordinates are clamped to image bounds. Thickness applies inward from each edge.
|
|
83
|
+
*/
|
|
84
|
+
export function drawRect(pixels, imgWidth, imgHeight, bpp, x1, y1, x2, y2, color, thickness = 2) {
|
|
85
|
+
x1 = Math.max(0, Math.min(x1, imgWidth - 1));
|
|
86
|
+
y1 = Math.max(0, Math.min(y1, imgHeight - 1));
|
|
87
|
+
x2 = Math.max(0, Math.min(x2, imgWidth - 1));
|
|
88
|
+
y2 = Math.max(0, Math.min(y2, imgHeight - 1));
|
|
89
|
+
const [r, g, b] = color;
|
|
90
|
+
for (let t = 0; t < thickness; t++) {
|
|
91
|
+
const top = y1 + t, bot = y2 - t, left = x1 + t, right = x2 - t;
|
|
92
|
+
if (top > bot || left > right)
|
|
93
|
+
break;
|
|
94
|
+
for (let x = left; x <= right; x++) {
|
|
95
|
+
setPixel(pixels, imgWidth, bpp, x, top, r, g, b);
|
|
96
|
+
setPixel(pixels, imgWidth, bpp, x, bot, r, g, b);
|
|
97
|
+
}
|
|
98
|
+
for (let y = top + 1; y < bot; y++) {
|
|
99
|
+
setPixel(pixels, imgWidth, bpp, left, y, r, g, b);
|
|
100
|
+
setPixel(pixels, imgWidth, bpp, right, y, r, g, b);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Draw a filled label showing a number at pixel position (x, y).
|
|
106
|
+
* Background uses the provided color; foreground (digit pixels) auto-contrasts.
|
|
107
|
+
* Label is clamped to stay within image bounds.
|
|
108
|
+
* Each digit glyph is 5×7 px with 1 px padding on all sides.
|
|
109
|
+
*/
|
|
110
|
+
export function drawLabel(pixels, imgWidth, imgHeight, bpp, x, y, num, bgColor) {
|
|
111
|
+
const text = num.toString();
|
|
112
|
+
const GLYPH_W = 5, GLYPH_H = 7;
|
|
113
|
+
const CHAR_W = 6; // glyph + 1 px gap between digits
|
|
114
|
+
const PAD = 1;
|
|
115
|
+
// Total label dims: pad on each side, glyphs side by side, no trailing gap
|
|
116
|
+
const labelW = text.length * CHAR_W - 1 + PAD * 2;
|
|
117
|
+
const labelH = GLYPH_H + PAD * 2;
|
|
118
|
+
// Clamp to image so label never partially overflows
|
|
119
|
+
const lx = Math.max(0, Math.min(x, imgWidth - labelW));
|
|
120
|
+
const ly = Math.max(0, Math.min(y, imgHeight - labelH));
|
|
121
|
+
const [bgR, bgG, bgB] = bgColor;
|
|
122
|
+
// Perceived brightness for contrast decision (ITU-R BT.601)
|
|
123
|
+
const bright = 0.299 * bgR + 0.587 * bgG + 0.114 * bgB;
|
|
124
|
+
const [fr, fg, fb] = bright < 140
|
|
125
|
+
? [255, 255, 255]
|
|
126
|
+
: [0, 0, 0];
|
|
127
|
+
// Fill background rectangle
|
|
128
|
+
for (let dy = 0; dy < labelH && ly + dy < imgHeight; dy++) {
|
|
129
|
+
for (let dx = 0; dx < labelW && lx + dx < imgWidth; dx++) {
|
|
130
|
+
setPixel(pixels, imgWidth, bpp, lx + dx, ly + dy, bgR, bgG, bgB);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
// Render each digit glyph
|
|
134
|
+
for (let ci = 0; ci < text.length; ci++) {
|
|
135
|
+
const digit = parseInt(text[ci], 10);
|
|
136
|
+
const glyph = DIGIT_FONT[digit] ?? DIGIT_FONT[0];
|
|
137
|
+
for (let row = 0; row < GLYPH_H; row++) {
|
|
138
|
+
const bits = glyph[row] ?? 0;
|
|
139
|
+
for (let col = 0; col < GLYPH_W; col++) {
|
|
140
|
+
if (bits & (16 >> col)) { // 16 = 0b10000; MSB-first 5-bit mask
|
|
141
|
+
const px = lx + PAD + ci * CHAR_W + col;
|
|
142
|
+
const py = ly + PAD + row;
|
|
143
|
+
if (px < imgWidth && py < imgHeight) {
|
|
144
|
+
setPixel(pixels, imgWidth, bpp, px, py, fr, fg, fb);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Decode a PNG file into raw pixel data.
|
|
153
|
+
* Handles RGBA (colorType 6) and RGB (colorType 2) — both produced by Android screencap.
|
|
154
|
+
* All 5 PNG row filter types (None, Sub, Up, Average, Paeth) are unfiltered.
|
|
155
|
+
* Returns null on any parse or decompression error — callers should handle gracefully.
|
|
156
|
+
*/
|
|
157
|
+
export function decodePngPixels(pngPath) {
|
|
158
|
+
try {
|
|
159
|
+
const buf = readFileSync(pngPath);
|
|
160
|
+
// Verify full 8-byte PNG signature — rejects non-PNG files that happen to share partial magic bytes
|
|
161
|
+
const PNG_SIG = [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A];
|
|
162
|
+
if (buf.length < 8 || !PNG_SIG.every((b, i) => buf[i] === b))
|
|
163
|
+
return null;
|
|
164
|
+
let offset = 8;
|
|
165
|
+
let width = 0, height = 0, colorType = 0;
|
|
166
|
+
const idatChunks = [];
|
|
167
|
+
while (offset + 12 <= buf.length) {
|
|
168
|
+
const length = buf.readUInt32BE(offset);
|
|
169
|
+
if (offset + 12 + length > buf.length)
|
|
170
|
+
break;
|
|
171
|
+
const type = buf.slice(offset + 4, offset + 8).toString("ascii");
|
|
172
|
+
const data = buf.slice(offset + 8, offset + 8 + length);
|
|
173
|
+
if (type === "IHDR" && length >= 13) {
|
|
174
|
+
width = data.readUInt32BE(0);
|
|
175
|
+
height = data.readUInt32BE(4);
|
|
176
|
+
colorType = data[9];
|
|
177
|
+
}
|
|
178
|
+
else if (type === "IDAT") {
|
|
179
|
+
idatChunks.push(data);
|
|
180
|
+
}
|
|
181
|
+
else if (type === "IEND") {
|
|
182
|
+
break;
|
|
183
|
+
}
|
|
184
|
+
offset += 12 + length;
|
|
185
|
+
}
|
|
186
|
+
if (width === 0 || height === 0 || idatChunks.length === 0)
|
|
187
|
+
return null;
|
|
188
|
+
const bytesPerPixel = colorType === 6 ? 4 : colorType === 2 ? 3 : 0;
|
|
189
|
+
if (bytesPerPixel === 0)
|
|
190
|
+
return null; // unsupported colorType
|
|
191
|
+
// Defense-in-depth: reject absurd dimensions that would cause OOM.
|
|
192
|
+
// 10000×10000×4 = 400 MB pixel buffer — generous ceiling for any real screenshot.
|
|
193
|
+
const MAX_DIM = 10000;
|
|
194
|
+
if (width > MAX_DIM || height > MAX_DIM)
|
|
195
|
+
return null;
|
|
196
|
+
// Cap decompressed output to prevent zip-bomb decompression attacks.
|
|
197
|
+
// Expected size: (1 + width*bpp) * height — add 1% headroom for safety.
|
|
198
|
+
const expectedRawSize = (1 + width * bytesPerPixel) * height;
|
|
199
|
+
const maxInflateSize = Math.ceil(expectedRawSize * 1.01) + 1024;
|
|
200
|
+
const raw = inflateSync(Buffer.concat(idatChunks), { maxOutputLength: maxInflateSize });
|
|
201
|
+
const rowBytes = 1 + width * bytesPerPixel;
|
|
202
|
+
if (raw.length < rowBytes * height)
|
|
203
|
+
return null;
|
|
204
|
+
const pixels = Buffer.alloc(width * height * bytesPerPixel);
|
|
205
|
+
const prevRow = Buffer.alloc(width * bytesPerPixel);
|
|
206
|
+
for (let y = 0; y < height; y++) {
|
|
207
|
+
const rowStart = y * rowBytes;
|
|
208
|
+
const filterType = raw[rowStart];
|
|
209
|
+
const pixRowStart = y * width * bytesPerPixel;
|
|
210
|
+
for (let x = 0; x < width * bytesPerPixel; x++) {
|
|
211
|
+
let val = raw[rowStart + 1 + x] ?? 0;
|
|
212
|
+
const a = x >= bytesPerPixel ? pixels[pixRowStart + x - bytesPerPixel] : 0;
|
|
213
|
+
const b = prevRow[x];
|
|
214
|
+
const c = x >= bytesPerPixel ? prevRow[x - bytesPerPixel] : 0;
|
|
215
|
+
switch (filterType) {
|
|
216
|
+
case 0: break; // None
|
|
217
|
+
case 1:
|
|
218
|
+
val = (val + a) & 0xFF;
|
|
219
|
+
break; // Sub
|
|
220
|
+
case 2:
|
|
221
|
+
val = (val + b) & 0xFF;
|
|
222
|
+
break; // Up
|
|
223
|
+
case 3:
|
|
224
|
+
val = (val + Math.floor((a + b) / 2)) & 0xFF;
|
|
225
|
+
break; // Average
|
|
226
|
+
case 4: { // Paeth
|
|
227
|
+
const p = a + b - c;
|
|
228
|
+
const pa = Math.abs(p - a), pb = Math.abs(p - b), pc = Math.abs(p - c);
|
|
229
|
+
val = (val + (pa <= pb && pa <= pc ? a : pb <= pc ? b : c)) & 0xFF;
|
|
230
|
+
break;
|
|
231
|
+
}
|
|
232
|
+
default: break; // Unknown filter — treat as None
|
|
233
|
+
}
|
|
234
|
+
pixels[pixRowStart + x] = val;
|
|
235
|
+
}
|
|
236
|
+
pixels.copy(prevRow, 0, pixRowStart, pixRowStart + width * bytesPerPixel);
|
|
237
|
+
}
|
|
238
|
+
return { width, height, bytesPerPixel, pixels };
|
|
239
|
+
}
|
|
240
|
+
catch {
|
|
241
|
+
return null; // Any decode failure is non-fatal for callers
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
// ── PNG encode ─────────────────────────────────────────────────────────
|
|
245
|
+
/**
|
|
246
|
+
* Encode a raw pixel buffer as a PNG file in memory.
|
|
247
|
+
* Uses filter type 0 (None) on every scanline and level-1 (fast) deflate.
|
|
248
|
+
* bpp must be 3 (RGB) or 4 (RGBA) to match the input data.
|
|
249
|
+
*/
|
|
250
|
+
export function encodePng(width, height, pixels, bpp) {
|
|
251
|
+
const SIG = Buffer.from([0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]);
|
|
252
|
+
const ihdr = Buffer.allocUnsafe(13);
|
|
253
|
+
ihdr.writeUInt32BE(width, 0);
|
|
254
|
+
ihdr.writeUInt32BE(height, 4);
|
|
255
|
+
ihdr[8] = 8; // bit depth
|
|
256
|
+
ihdr[9] = bpp === 4 ? 6 : 2; // colorType 6=RGBA, 2=RGB
|
|
257
|
+
ihdr[10] = 0; // compression (deflate)
|
|
258
|
+
ihdr[11] = 0; // filter method
|
|
259
|
+
ihdr[12] = 0; // no interlacing
|
|
260
|
+
// Prepend filter byte 0 (None) to each scanline
|
|
261
|
+
const rowSize = 1 + width * bpp;
|
|
262
|
+
const rawData = Buffer.allocUnsafe(rowSize * height);
|
|
263
|
+
for (let y = 0; y < height; y++) {
|
|
264
|
+
rawData[y * rowSize] = 0; // filter = None
|
|
265
|
+
pixels.copy(rawData, y * rowSize + 1, y * width * bpp, (y + 1) * width * bpp);
|
|
266
|
+
}
|
|
267
|
+
return Buffer.concat([
|
|
268
|
+
SIG,
|
|
269
|
+
makePngChunk("IHDR", ihdr),
|
|
270
|
+
makePngChunk("IDAT", deflateSync(rawData, { level: 1 })),
|
|
271
|
+
makePngChunk("IEND", Buffer.alloc(0)),
|
|
272
|
+
]);
|
|
273
|
+
}
|
|
274
|
+
//# sourceMappingURL=png-utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"png-utils.js","sourceRoot":"","sources":["../../src/middleware/png-utils.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAClC,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,MAAM,CAAC;AAEhD,yEAAyE;AAEzE,MAAM,WAAW,GAAsB,CAAC,GAAG,EAAE;IAC3C,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;QAC7B,IAAI,CAAC,GAAG,CAAC,CAAC;QACV,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAC3B,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;QACrD,CAAC;QACD,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IACrB,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC,CAAC,EAAE,CAAC;AAEL,SAAS,KAAK,CAAC,GAAW;IACxB,IAAI,GAAG,GAAG,UAAU,CAAC;IACrB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACpC,GAAG,GAAG,CAAC,CAAC,WAAW,CAAC,CAAC,GAAG,GAAG,GAAG,CAAC,CAAC,CAAE,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IACzE,CAAC;IACD,OAAO,CAAC,GAAG,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;AAClC,CAAC;AAED,SAAS,YAAY,CAAC,IAAY,EAAE,IAAY;IAC9C,MAAM,MAAM,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;IACrC,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IACrC,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAC3C,MAAM,MAAM,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;IACrC,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC/D,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;AACxD,CAAC;AAED,yEAAyE;AAEzE;;;GAGG;AACH,MAAM,UAAU,GAAmC;IACjD,CAAC,EAAE,EAAC,EAAE,EAAC,EAAE,EAAC,EAAE,EAAC,EAAE,EAAC,EAAE,EAAC,EAAE,CAAC,EAAE,IAAI;IAC5B,CAAE,CAAC,EAAC,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAC,EAAE,CAAC,EAAE,IAAI;IAC5B,CAAC,EAAE,EAAC,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAC,EAAE,CAAC,EAAE,IAAI;IAC5B,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,EAAC,EAAE,EAAE,CAAC,EAAE,CAAC,EAAC,EAAE,CAAC,EAAE,IAAI;IAC5B,CAAE,CAAC,EAAE,CAAC,EAAC,EAAE,EAAC,EAAE,EAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,IAAI;IAC5B,CAAC,EAAE,EAAC,EAAE,EAAC,EAAE,EAAC,EAAE,EAAE,CAAC,EAAE,CAAC,EAAC,EAAE,CAAC,EAAE,IAAI;IAC5B,CAAC,EAAE,EAAC,EAAE,EAAC,EAAE,EAAC,EAAE,EAAC,EAAE,EAAC,EAAE,EAAC,EAAE,CAAC,EAAE,IAAI;IAC5B,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,IAAI;IAC5B,CAAC,EAAE,EAAC,EAAE,EAAC,EAAE,EAAC,EAAE,EAAC,EAAE,EAAC,EAAE,EAAC,EAAE,CAAC,EAAE,IAAI;IAC5B,CAAC,EAAE,EAAC,EAAE,EAAC,EAAE,EAAC,EAAE,EAAE,CAAC,EAAE,CAAC,EAAC,EAAE,CAAC,EAAE,IAAI;CACpB,CAAC;AAEX,0EAA0E;AAE1E,iEAAiE;AACjE,MAAM,CAAC,MAAM,cAAc,GAAqD;IAC9E,CAAC,GAAG,EAAG,EAAE,EAAG,EAAE,CAAC,EAAE,MAAM;IACvB,CAAE,EAAE,EAAE,GAAG,EAAG,EAAE,CAAC,EAAE,QAAQ;IACzB,CAAE,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC,EAAE,OAAO;IACxB,CAAC,GAAG,EAAE,GAAG,EAAI,CAAC,CAAC,EAAE,SAAS;IAC1B,CAAG,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,EAAE,OAAO;IACxB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,EAAE,OAAO;IACxB,CAAC,GAAG,EAAE,GAAG,EAAI,CAAC,CAAC,EAAE,SAAS;IAC1B,CAAC,GAAG,EAAG,EAAE,EAAE,GAAG,CAAC,EAAE,SAAS;CAClB,CAAC;AAEX,0EAA0E;AAE1E,iGAAiG;AACjG,SAAS,QAAQ,CACf,MAAc,EAAE,QAAgB,EAAE,GAAW,EAC7C,CAAS,EAAE,CAAS,EAAE,CAAS,EAAE,CAAS,EAAE,CAAS;IAErD,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,QAAQ;QAAE,OAAO;IACnC,MAAM,GAAG,GAAG,CAAC,CAAC,GAAG,QAAQ,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC;IACrC,MAAM,CAAC,GAAG,CAAC,GAAO,CAAC,CAAC;IACpB,MAAM,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;IACpB,MAAM,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;IACpB,IAAI,GAAG,KAAK,CAAC;QAAE,MAAM,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC;AACvC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,QAAQ,CACtB,MAAc,EAAE,QAAgB,EAAE,SAAiB,EAAE,GAAW,EAChE,EAAU,EAAE,EAAU,EAAE,EAAU,EAAE,EAAU,EAC9C,KAAwC,EACxC,SAAS,GAAG,CAAC;IAEb,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC;IAC7C,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC;IAC9C,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC;IAC7C,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC;IAC9C,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,KAAK,CAAC;IAExB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,EAAE,CAAC,EAAE,EAAE,CAAC;QACnC,MAAM,GAAG,GAAG,EAAE,GAAG,CAAC,EAAE,GAAG,GAAG,EAAE,GAAG,CAAC,EAAE,IAAI,GAAG,EAAE,GAAG,CAAC,EAAE,KAAK,GAAG,EAAE,GAAG,CAAC,CAAC;QAChE,IAAI,GAAG,GAAG,GAAG,IAAI,IAAI,GAAG,KAAK;YAAE,MAAM;QACrC,KAAK,IAAI,CAAC,GAAG,IAAI,EAAE,CAAC,IAAI,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC;YACnC,QAAQ,CAAC,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;YACjD,QAAQ,CAAC,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QACnD,CAAC;QACD,KAAK,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;YACnC,QAAQ,CAAC,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE,IAAI,EAAG,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;YACnD,QAAQ,CAAC,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QACrD,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,SAAS,CACvB,MAAc,EAAE,QAAgB,EAAE,SAAiB,EAAE,GAAW,EAChE,CAAS,EAAE,CAAS,EAAE,GAAW,EACjC,OAA0C;IAE1C,MAAM,IAAI,GAAG,GAAG,CAAC,QAAQ,EAAE,CAAC;IAC5B,MAAM,OAAO,GAAG,CAAC,EAAE,OAAO,GAAG,CAAC,CAAC;IAC/B,MAAM,MAAM,GAAI,CAAC,CAAC,CAAC,kCAAkC;IACrD,MAAM,GAAG,GAAO,CAAC,CAAC;IAClB,2EAA2E;IAC3E,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,GAAG,MAAM,GAAG,CAAC,GAAG,GAAG,GAAG,CAAC,CAAC;IAClD,MAAM,MAAM,GAAG,OAAO,GAAG,GAAG,GAAG,CAAC,CAAC;IAEjC,oDAAoD;IACpD,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,GAAI,MAAM,CAAC,CAAC,CAAC;IACxD,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC,CAAC,CAAC;IAExD,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,OAAO,CAAC;IAChC,4DAA4D;IAC5D,MAAM,MAAM,GAAG,KAAK,GAAG,GAAG,GAAG,KAAK,GAAG,GAAG,GAAG,KAAK,GAAG,GAAG,CAAC;IACvD,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,GAAG,MAAM,GAAG,GAAG;QAC/B,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAU;QAC1B,CAAC,CAAC,CAAG,CAAC,EAAI,CAAC,EAAI,CAAC,CAAU,CAAC;IAE7B,4BAA4B;IAC5B,KAAK,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,MAAM,IAAI,EAAE,GAAG,EAAE,GAAG,SAAS,EAAE,EAAE,EAAE,EAAE,CAAC;QAC1D,KAAK,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,MAAM,IAAI,EAAE,GAAG,EAAE,GAAG,QAAQ,EAAE,EAAE,EAAE,EAAE,CAAC;YACzD,QAAQ,CAAC,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QACnE,CAAC;IACH,CAAC;IAED,0BAA0B;IAC1B,KAAK,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,EAAE,EAAE,EAAE,CAAC;QACxC,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;QACrC,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,IAAI,UAAU,CAAC,CAAC,CAAE,CAAC;QAClD,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,OAAO,EAAE,GAAG,EAAE,EAAE,CAAC;YACvC,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAC7B,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,OAAO,EAAE,GAAG,EAAE,EAAE,CAAC;gBACvC,IAAI,IAAI,GAAG,CAAC,EAAE,IAAI,GAAG,CAAC,EAAE,CAAC,CAAC,qCAAqC;oBAC7D,MAAM,EAAE,GAAG,EAAE,GAAG,GAAG,GAAG,EAAE,GAAG,MAAM,GAAG,GAAG,CAAC;oBACxC,MAAM,EAAE,GAAG,EAAE,GAAG,GAAG,GAAG,GAAG,CAAC;oBAC1B,IAAI,EAAE,GAAG,QAAQ,IAAI,EAAE,GAAG,SAAS,EAAE,CAAC;wBACpC,QAAQ,CAAC,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;oBACtD,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;AACH,CAAC;AAYD;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,OAAe;IAC7C,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;QAClC,oGAAoG;QACpG,MAAM,OAAO,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;QACjE,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;YAAE,OAAO,IAAI,CAAC;QAE1E,IAAI,MAAM,GAAG,CAAC,CAAC;QACf,IAAI,KAAK,GAAG,CAAC,EAAE,MAAM,GAAG,CAAC,EAAE,SAAS,GAAG,CAAC,CAAC;QACzC,MAAM,UAAU,GAAa,EAAE,CAAC;QAEhC,OAAO,MAAM,GAAG,EAAE,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;YACjC,MAAM,MAAM,GAAG,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;YACxC,IAAI,MAAM,GAAG,EAAE,GAAG,MAAM,GAAG,GAAG,CAAC,MAAM;gBAAE,MAAM;YAC7C,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;YACjE,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,MAAM,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC;YAExD,IAAI,IAAI,KAAK,MAAM,IAAI,MAAM,IAAI,EAAE,EAAE,CAAC;gBACpC,KAAK,GAAO,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;gBACjC,MAAM,GAAM,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;gBACjC,SAAS,GAAG,IAAI,CAAC,CAAC,CAAE,CAAC;YACvB,CAAC;iBAAM,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;gBAC3B,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACxB,CAAC;iBAAM,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;gBAC3B,MAAM;YACR,CAAC;YACD,MAAM,IAAI,EAAE,GAAG,MAAM,CAAC;QACxB,CAAC;QAED,IAAI,KAAK,KAAK,CAAC,IAAI,MAAM,KAAK,CAAC,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QACxE,MAAM,aAAa,GAAG,SAAS,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACpE,IAAI,aAAa,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC,CAAC,wBAAwB;QAE9D,mEAAmE;QACnE,kFAAkF;QAClF,MAAM,OAAO,GAAG,KAAK,CAAC;QACtB,IAAI,KAAK,GAAG,OAAO,IAAI,MAAM,GAAG,OAAO;YAAE,OAAO,IAAI,CAAC;QAErD,qEAAqE;QACrE,wEAAwE;QACxE,MAAM,eAAe,GAAG,CAAC,CAAC,GAAG,KAAK,GAAG,aAAa,CAAC,GAAG,MAAM,CAAC;QAC7D,MAAM,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC;QAChE,MAAM,GAAG,GAAO,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,EAAE,eAAe,EAAE,cAAc,EAAE,CAAC,CAAC;QAC5F,MAAM,QAAQ,GAAG,CAAC,GAAG,KAAK,GAAG,aAAa,CAAC;QAC3C,IAAI,GAAG,CAAC,MAAM,GAAG,QAAQ,GAAG,MAAM;YAAE,OAAO,IAAI,CAAC;QAEhD,MAAM,MAAM,GAAI,MAAM,CAAC,KAAK,CAAC,KAAK,GAAG,MAAM,GAAG,aAAa,CAAC,CAAC;QAC7D,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,KAAK,GAAG,aAAa,CAAC,CAAC;QAEpD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAChC,MAAM,QAAQ,GAAM,CAAC,GAAG,QAAQ,CAAC;YACjC,MAAM,UAAU,GAAI,GAAG,CAAC,QAAQ,CAAE,CAAC;YACnC,MAAM,WAAW,GAAG,CAAC,GAAG,KAAK,GAAG,aAAa,CAAC;YAE9C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,GAAG,aAAa,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC/C,IAAI,GAAG,GAAG,GAAG,CAAC,QAAQ,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC;gBACrC,MAAM,CAAC,GAAG,CAAC,IAAI,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,GAAG,CAAC,GAAG,aAAa,CAAE,CAAC,CAAC,CAAC,CAAC,CAAC;gBAC5E,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAE,CAAC;gBACtB,MAAM,CAAC,GAAG,CAAC,IAAI,aAAa,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,aAAa,CAAE,CAAC,CAAC,CAAC,CAAC,CAAC;gBAE/D,QAAQ,UAAU,EAAE,CAAC;oBACnB,KAAK,CAAC,CAAC,CAAC,MAAM,CAA8C,OAAO;oBACnE,KAAK,CAAC;wBAAE,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC;wBAAC,MAAM,CAAqB,MAAM;oBACjE,KAAK,CAAC;wBAAE,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC;wBAAC,MAAM,CAAqB,KAAK;oBAChE,KAAK,CAAC;wBAAE,GAAG,GAAG,CAAC,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;wBAAC,MAAM,CAAC,UAAU;oBACvE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAmD,QAAQ;wBAClE,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;wBACpB,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;wBACvE,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;wBACnE,MAAM;oBACR,CAAC;oBACD,OAAO,CAAC,CAAC,MAAM,CAAC,iCAAiC;gBACnD,CAAC;gBACD,MAAM,CAAC,WAAW,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC;YAChC,CAAC;YACD,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,EAAE,WAAW,EAAE,WAAW,GAAG,KAAK,GAAG,aAAa,CAAC,CAAC;QAC5E,CAAC;QAED,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,CAAC;IAClD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC,CAAC,8CAA8C;IAC7D,CAAC;AACH,CAAC;AAED,0EAA0E;AAE1E;;;;GAIG;AACH,MAAM,UAAU,SAAS,CAAC,KAAa,EAAE,MAAc,EAAE,MAAc,EAAE,GAAU;IACjF,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;IAE1E,MAAM,IAAI,GAAG,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;IACpC,IAAI,CAAC,aAAa,CAAC,KAAK,EAAG,CAAC,CAAC,CAAC;IAC9B,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IAC9B,IAAI,CAAC,CAAC,CAAC,GAAI,CAAC,CAAC,CAAe,YAAY;IACxC,IAAI,CAAC,CAAC,CAAC,GAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,0BAA0B;IACxD,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAe,wBAAwB;IACpD,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAe,gBAAgB;IAC5C,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAe,iBAAiB;IAE7C,gDAAgD;IAChD,MAAM,OAAO,GAAG,CAAC,GAAG,KAAK,GAAG,GAAG,CAAC;IAChC,MAAM,OAAO,GAAG,MAAM,CAAC,WAAW,CAAC,OAAO,GAAG,MAAM,CAAC,CAAC;IACrD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAChC,OAAO,CAAC,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,gBAAgB;QAC1C,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,GAAG,OAAO,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,GAAG,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,GAAG,GAAG,CAAC,CAAC;IAChF,CAAC;IAED,OAAO,MAAM,CAAC,MAAM,CAAC;QACnB,GAAG;QACH,YAAY,CAAC,MAAM,EAAE,IAAI,CAAC;QAC1B,YAAY,CAAC,MAAM,EAAE,WAAW,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;QACxD,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;KACtC,CAAC,CAAC;AACL,CAAC"}
|