portholejs 0.1.1 → 0.2.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/README.md +130 -46
- package/client-dist/assets/index-DluwPdUK.js +49 -0
- package/client-dist/index.html +1 -1
- package/dist/cli.js +351 -83
- package/dist/cli.js.map +1 -1
- package/dist/control-client.d.ts +1 -0
- package/dist/control-client.d.ts.map +1 -1
- package/dist/control-client.js +10 -2
- package/dist/control-client.js.map +1 -1
- package/dist/engine/scrcpy-engine.d.ts +2 -2
- package/dist/engine/scrcpy-engine.d.ts.map +1 -1
- package/dist/engine/scrcpy-engine.js.map +1 -1
- package/dist/engine/types.d.ts +3 -8
- package/dist/engine/types.d.ts.map +1 -1
- package/dist/focus-navigation.d.ts +27 -0
- package/dist/focus-navigation.d.ts.map +1 -0
- package/dist/focus-navigation.js +118 -0
- package/dist/focus-navigation.js.map +1 -0
- package/dist/gesture.d.ts +14 -0
- package/dist/gesture.d.ts.map +1 -0
- package/dist/gesture.js +110 -0
- package/dist/gesture.js.map +1 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/input-validation.d.ts.map +1 -1
- package/dist/input-validation.js +4 -56
- package/dist/input-validation.js.map +1 -1
- package/dist/input.d.ts +1 -21
- package/dist/input.d.ts.map +1 -1
- package/dist/keycodes.d.ts +2 -1
- package/dist/keycodes.d.ts.map +1 -1
- package/dist/keycodes.js.map +1 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +183 -1
- package/dist/mcp/server.js.map +1 -1
- package/dist/mp4-writer.d.ts +18 -0
- package/dist/mp4-writer.d.ts.map +1 -0
- package/dist/mp4-writer.js +195 -0
- package/dist/mp4-writer.js.map +1 -0
- package/dist/protocol.d.ts +74 -2
- package/dist/protocol.d.ts.map +1 -1
- package/dist/protocol.js +154 -7
- package/dist/protocol.js.map +1 -1
- package/dist/recording.d.ts +22 -0
- package/dist/recording.d.ts.map +1 -0
- package/dist/recording.js +132 -0
- package/dist/recording.js.map +1 -0
- package/dist/screen-diff.d.ts +21 -0
- package/dist/screen-diff.d.ts.map +1 -0
- package/dist/screen-diff.js +70 -0
- package/dist/screen-diff.js.map +1 -0
- package/dist/server/http.d.ts +5 -4
- package/dist/server/http.d.ts.map +1 -1
- package/dist/server/http.js +69 -31
- package/dist/server/http.js.map +1 -1
- package/dist/server/ws.d.ts +4 -3
- package/dist/server/ws.d.ts.map +1 -1
- package/dist/server/ws.js +32 -18
- package/dist/server/ws.js.map +1 -1
- package/dist/session.d.ts +25 -10
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +117 -67
- package/dist/session.js.map +1 -1
- package/dist/state.d.ts.map +1 -1
- package/dist/state.js +1 -3
- package/dist/state.js.map +1 -1
- package/package.json +18 -3
- package/skills/porthole/SKILL.md +130 -0
- package/client-dist/assets/index-C_qSS_Gy.js +0 -49
package/README.md
CHANGED
|
@@ -65,6 +65,7 @@ in sync (see `src/engine/scrcpy-engine.ts`).
|
|
|
65
65
|
|
|
66
66
|
```sh
|
|
67
67
|
npx portholejs start Pixel_8_Pro_API_34
|
|
68
|
+
npx portholejs start Pixel_8_Pro_API_34 Television_1080p_API_34
|
|
68
69
|
```
|
|
69
70
|
|
|
70
71
|
For a headless agent workflow:
|
|
@@ -76,54 +77,82 @@ npx portholejs screenshot -q
|
|
|
76
77
|
npx portholejs kill -q
|
|
77
78
|
```
|
|
78
79
|
|
|
80
|
+
## Things to try
|
|
81
|
+
|
|
82
|
+
Test a TV app **without touching a remote**: `porthole focus-on "Library"
|
|
83
|
+
--select` walks the D-pad focus to any element by its text and presses OK —
|
|
84
|
+
then `porthole focused -q` tells you exactly where leanback focus landed, as
|
|
85
|
+
JSON. Record a bug repro as a real video with
|
|
86
|
+
`porthole record repro.mp4 --duration 30s` while you swipe, scroll, and
|
|
87
|
+
long-press the phone from the CLI (`porthole scroll down`,
|
|
88
|
+
`porthole swipe 0.5 0.05 0.5 0.7` opens the notification shade). Catch visual
|
|
89
|
+
regressions in one line: save a baseline with `porthole screenshot -o good.png`,
|
|
90
|
+
then `porthole assert-screen good.png --threshold 0.02` exits non-zero and
|
|
91
|
+
writes a diff image the moment the screen drifts. Stream a **phone and a TV
|
|
92
|
+
side by side** from one command — `porthole start Pixel_8 Tv_1080p` puts both
|
|
93
|
+
in the same browser tab with a device picker. And the whole loop works with no
|
|
94
|
+
human at all: add the MCP server to Claude Code (below) and ask it to _"open
|
|
95
|
+
my app on the TV emulator, navigate to Settings, and check nothing crashed"_ —
|
|
96
|
+
it will drive the D-pad, read the UI as JSON (`dump_ui`), and pull
|
|
97
|
+
`get_crashes` on its own. If anything misbehaves, `porthole doctor` diagnoses
|
|
98
|
+
your setup in seconds.
|
|
99
|
+
|
|
79
100
|
## CLI Reference
|
|
80
101
|
|
|
81
|
-
| Command
|
|
82
|
-
|
|
|
83
|
-
| `porthole start [avd]`
|
|
84
|
-
| `porthole list`
|
|
85
|
-
| `porthole kill [avd]`
|
|
86
|
-
| `porthole tap <x> <y>`
|
|
87
|
-
| `porthole
|
|
88
|
-
| `porthole
|
|
89
|
-
| `porthole
|
|
90
|
-
| `porthole
|
|
91
|
-
| `porthole
|
|
92
|
-
| `porthole
|
|
93
|
-
| `porthole
|
|
94
|
-
| `porthole
|
|
95
|
-
| `porthole
|
|
96
|
-
| `porthole
|
|
97
|
-
| `porthole
|
|
98
|
-
| `porthole
|
|
99
|
-
| `porthole
|
|
100
|
-
| `porthole
|
|
102
|
+
| Command | Purpose |
|
|
103
|
+
| ------------------------------------ | --------------------------------------------------- |
|
|
104
|
+
| `porthole start [avd...]` | Boot or attach one or more emulators and serve them |
|
|
105
|
+
| `porthole list` | List AVDs, running emulators, and known sessions |
|
|
106
|
+
| `porthole kill [avd]` | Stop emulators Porthole booted and detached servers |
|
|
107
|
+
| `porthole tap <x> <y>` | Touch normalized phone coordinates from `0..1` |
|
|
108
|
+
| `porthole swipe <x1> <y1> <x2> <y2>` | Swipe between normalized phone coordinates |
|
|
109
|
+
| `porthole longpress <x> <y>` | Long-press normalized phone coordinates |
|
|
110
|
+
| `porthole scroll <direction>` | Scroll phone content up, down, left, or right |
|
|
111
|
+
| `porthole key <keycode>` | Send an Android keycode down/up pair |
|
|
112
|
+
| `porthole remote <button>` | Press a TV D-pad/media button |
|
|
113
|
+
| `porthole text "<string>"` | Type text into the active session |
|
|
114
|
+
| `porthole screenshot [-o file.png]` | Save a PNG screenshot |
|
|
115
|
+
| `porthole assert-screen <png>` | Compare the current screen with a PNG baseline |
|
|
116
|
+
| `porthole record <out.mp4>` | Record the current H.264 stream to MP4 |
|
|
117
|
+
| `porthole focused` | Print the currently focused UI node |
|
|
118
|
+
| `porthole focus-on <text>` | Move TV D-pad focus to matching text |
|
|
119
|
+
| `porthole dump-ui [--filter text]` | Dump the Android UI hierarchy |
|
|
120
|
+
| `porthole wait-for <text>` | Wait until UI text appears |
|
|
121
|
+
| `porthole open-url <url>` | Open a URL or Android deep link |
|
|
122
|
+
| `porthole stop-app <package>` | Force-stop an app |
|
|
123
|
+
| `porthole clear-app <package>` | Clear app data |
|
|
124
|
+
| `porthole rotate <orientation>` | Rotate a phone emulator |
|
|
125
|
+
| `porthole emu <args...>` | Pass through to `adb emu` |
|
|
126
|
+
| `porthole doctor` | Diagnose Node/SDK/adb/AVD/session problems |
|
|
127
|
+
| `porthole mcp` | Run the MCP server over stdio |
|
|
101
128
|
|
|
102
129
|
Common options:
|
|
103
130
|
|
|
104
|
-
| Option | Meaning
|
|
105
|
-
| ----------------------- |
|
|
106
|
-
| `-p, --port <port>` | Preview/control port, default `3200`
|
|
107
|
-
| `-d, --device <serial>` |
|
|
108
|
-
| `--host <host>` | Bind address, default `127.0.0.1`
|
|
109
|
-
| `--no-preview` | Do not open the browser automatically
|
|
110
|
-
| `--detach` | Start the preview server in the background
|
|
111
|
-
| `--mjpeg` | Force MJPEG screenshot polling
|
|
112
|
-
| `-q, --quiet` | Emit one JSON object/array on stdout
|
|
113
|
-
| `--max-size <px>` | Maximum scrcpy stream dimension
|
|
114
|
-
| `--max-fps <fps>` | Maximum scrcpy FPS
|
|
115
|
-
| `--bitrate <bps>` | Scrcpy video bitrate
|
|
116
|
-
| `--wipe-data` | Wipe emulator data before boot
|
|
117
|
-
| `--no-snapshot` | Disable loading/saving emulator snapshots
|
|
118
|
-
| `--cold-boot` | Alias for `--no-snapshot`
|
|
119
|
-
| `--gpu <mode>` | Pass emulator GPU mode
|
|
120
|
-
| `--keep-alive` | Leave a Porthole-booted emulator running on exit
|
|
131
|
+
| Option | Meaning |
|
|
132
|
+
| ----------------------- | ------------------------------------------------------- |
|
|
133
|
+
| `-p, --port <port>` | Preview/control port, default `3200` |
|
|
134
|
+
| `-d, --device <serial>` | Target a running emulator serial; comma-list on `start` |
|
|
135
|
+
| `--host <host>` | Bind address, default `127.0.0.1` |
|
|
136
|
+
| `--no-preview` | Do not open the browser automatically |
|
|
137
|
+
| `--detach` | Start the preview server in the background |
|
|
138
|
+
| `--mjpeg` | Force MJPEG screenshot polling |
|
|
139
|
+
| `-q, --quiet` | Emit one JSON object/array on stdout |
|
|
140
|
+
| `--max-size <px>` | Maximum scrcpy stream dimension |
|
|
141
|
+
| `--max-fps <fps>` | Maximum scrcpy FPS |
|
|
142
|
+
| `--bitrate <bps>` | Scrcpy video bitrate |
|
|
143
|
+
| `--wipe-data` | Wipe emulator data before boot |
|
|
144
|
+
| `--no-snapshot` | Disable loading/saving emulator snapshots |
|
|
145
|
+
| `--cold-boot` | Alias for `--no-snapshot` |
|
|
146
|
+
| `--gpu <mode>` | Pass emulator GPU mode |
|
|
147
|
+
| `--keep-alive` | Leave a Porthole-booted emulator running on exit |
|
|
121
148
|
|
|
122
149
|
Quiet schemas are intentionally simple: `list -q` returns
|
|
123
|
-
`{ "devices": [...], "sessions": [...] }`; `start --detach -q`
|
|
124
|
-
session record with `url`, `pid`, `serial`, `avdName`, `port`, and
|
|
125
|
-
|
|
126
|
-
`{ "ok": true, "
|
|
150
|
+
`{ "devices": [...], "sessions": [...] }`; single-device `start --detach -q`
|
|
151
|
+
returns the session record with `url`, `pid`, `serial`, `avdName`, `port`, and
|
|
152
|
+
`profile`; multi-device detached starts return `{ "sessions": [...] }`; input
|
|
153
|
+
commands return `{ "ok": true, "session": ... }`; `screenshot -q` returns
|
|
154
|
+
`{ "ok": true, "path": "...", "session": ... }`. Pass `-d <serial>` to
|
|
155
|
+
port-scoped commands when a server is streaming more than one emulator.
|
|
127
156
|
|
|
128
157
|
## MCP Setup
|
|
129
158
|
|
|
@@ -147,15 +176,70 @@ claude mcp add porthole -- npx portholejs mcp
|
|
|
147
176
|
```
|
|
148
177
|
|
|
149
178
|
Useful MCP tools: `list_devices`, `boot_device`, `wait_for_boot`,
|
|
150
|
-
`attach_device`, `tap`, `
|
|
151
|
-
`
|
|
152
|
-
`
|
|
179
|
+
`attach_device`, `tap`, `swipe`, `long_press`, `scroll`, `key`, `remote`,
|
|
180
|
+
`type_text`, `screenshot`, `assert_screen`, `start_recording`, `stop_recording`,
|
|
181
|
+
`dump_ui`, `get_focused`, `focus_on`, `find_element`, `wait_for`, `open_url`,
|
|
182
|
+
`stop_app`, `clear_app`, `get_crashes`, `read_logcat`, and `install_apk`.
|
|
183
|
+
|
|
184
|
+
## Agent Skill
|
|
185
|
+
|
|
186
|
+
Porthole ships an agent skill (`skills/porthole/`) that teaches agents the full workflow: doctor triage,
|
|
187
|
+
boot/attach, semantic UI assertions, TV navigation, and cleanup.
|
|
188
|
+
|
|
189
|
+
Install it by copying the skill directory into your skills folder — for the
|
|
190
|
+
current project:
|
|
191
|
+
|
|
192
|
+
```sh
|
|
193
|
+
mkdir -p .claude/skills
|
|
194
|
+
cp -r node_modules/portholejs/skills/porthole .claude/skills/
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
or for all your projects:
|
|
198
|
+
|
|
199
|
+
```sh
|
|
200
|
+
mkdir -p ~/.claude/skills
|
|
201
|
+
cp -r node_modules/portholejs/skills/porthole ~/.claude/skills/
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
From a clone of this repository, copy `skills/porthole` instead. Claude Code
|
|
205
|
+
picks the skill up automatically; ask it to "test my app on the Android
|
|
206
|
+
emulator" and it will follow the Porthole workflow.
|
|
207
|
+
|
|
208
|
+
## GitHub Action
|
|
209
|
+
|
|
210
|
+
Porthole ships an in-repo GitHub Action for CI smoke tests. It wraps
|
|
211
|
+
`reactivecircus/android-emulator-runner`, starts `npx --yes portholejs` against
|
|
212
|
+
the booted emulator, and runs your script while the emulator is alive.
|
|
213
|
+
|
|
214
|
+
```yaml
|
|
215
|
+
jobs:
|
|
216
|
+
tv-smoke:
|
|
217
|
+
runs-on: ubuntu-latest
|
|
218
|
+
steps:
|
|
219
|
+
- uses: actions/checkout@v4
|
|
220
|
+
- id: porthole
|
|
221
|
+
uses: giolaq/porthole@main
|
|
222
|
+
with:
|
|
223
|
+
avd-name: porthole-tv
|
|
224
|
+
api-level: "35"
|
|
225
|
+
profile: tv
|
|
226
|
+
script: |
|
|
227
|
+
mkdir -p artifacts
|
|
228
|
+
"$PORTHOLE_CLI" focus-on "Library" --select -q -p "$PORTHOLE_PORT"
|
|
229
|
+
"$PORTHOLE_CLI" screenshot -o artifacts/library.png -q -p "$PORTHOLE_PORT"
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
The action exposes `url`, `serial`, and `port` outputs, and also sets
|
|
233
|
+
`PORTHOLE_URL`, `PORTHOLE_SERIAL`, `PORTHOLE_PORT`, and `PORTHOLE_CLI` for the
|
|
234
|
+
smoke script. See `docs/github-action-example.yml` for a fuller `focus-on` /
|
|
235
|
+
`assert-screen` workflow that uploads screenshot artifacts on failure.
|
|
153
236
|
|
|
154
237
|
## Browser UI
|
|
155
238
|
|
|
156
|
-
The preview shows
|
|
239
|
+
The preview shows device tabs, stream status, screenshots, copy-to-clipboard,
|
|
157
240
|
stream stats, logcat, drag-and-drop APK install/file push, phone hardware keys,
|
|
158
|
-
and a TV D-pad remote.
|
|
241
|
+
and a TV D-pad remote. Switching tabs re-subscribes to that device's stream
|
|
242
|
+
without reloading the page. TV sessions reject touch input server-side.
|
|
159
243
|
|
|
160
244
|
Video uses WebCodecs by default. Browsers without `VideoDecoder` automatically
|
|
161
245
|
fall back to `/stream.mjpeg`, and `--mjpeg` or `?video=mjpeg` forces that mode.
|