portholejs 0.1.0 → 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.
Files changed (72) hide show
  1. package/LICENSE +186 -0
  2. package/README.md +285 -0
  3. package/client-dist/assets/index-DluwPdUK.js +49 -0
  4. package/client-dist/index.html +1 -1
  5. package/dist/cli.js +351 -83
  6. package/dist/cli.js.map +1 -1
  7. package/dist/control-client.d.ts +1 -0
  8. package/dist/control-client.d.ts.map +1 -1
  9. package/dist/control-client.js +10 -2
  10. package/dist/control-client.js.map +1 -1
  11. package/dist/engine/scrcpy-engine.d.ts +2 -2
  12. package/dist/engine/scrcpy-engine.d.ts.map +1 -1
  13. package/dist/engine/scrcpy-engine.js.map +1 -1
  14. package/dist/engine/types.d.ts +3 -8
  15. package/dist/engine/types.d.ts.map +1 -1
  16. package/dist/focus-navigation.d.ts +27 -0
  17. package/dist/focus-navigation.d.ts.map +1 -0
  18. package/dist/focus-navigation.js +118 -0
  19. package/dist/focus-navigation.js.map +1 -0
  20. package/dist/gesture.d.ts +14 -0
  21. package/dist/gesture.d.ts.map +1 -0
  22. package/dist/gesture.js +110 -0
  23. package/dist/gesture.js.map +1 -0
  24. package/dist/index.d.ts +3 -1
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +1 -0
  27. package/dist/index.js.map +1 -1
  28. package/dist/input-validation.d.ts.map +1 -1
  29. package/dist/input-validation.js +4 -56
  30. package/dist/input-validation.js.map +1 -1
  31. package/dist/input.d.ts +1 -21
  32. package/dist/input.d.ts.map +1 -1
  33. package/dist/keycodes.d.ts +2 -1
  34. package/dist/keycodes.d.ts.map +1 -1
  35. package/dist/keycodes.js.map +1 -1
  36. package/dist/mcp/server.d.ts.map +1 -1
  37. package/dist/mcp/server.js +183 -1
  38. package/dist/mcp/server.js.map +1 -1
  39. package/dist/mp4-writer.d.ts +18 -0
  40. package/dist/mp4-writer.d.ts.map +1 -0
  41. package/dist/mp4-writer.js +195 -0
  42. package/dist/mp4-writer.js.map +1 -0
  43. package/dist/protocol.d.ts +74 -2
  44. package/dist/protocol.d.ts.map +1 -1
  45. package/dist/protocol.js +154 -7
  46. package/dist/protocol.js.map +1 -1
  47. package/dist/recording.d.ts +22 -0
  48. package/dist/recording.d.ts.map +1 -0
  49. package/dist/recording.js +132 -0
  50. package/dist/recording.js.map +1 -0
  51. package/dist/screen-diff.d.ts +21 -0
  52. package/dist/screen-diff.d.ts.map +1 -0
  53. package/dist/screen-diff.js +70 -0
  54. package/dist/screen-diff.js.map +1 -0
  55. package/dist/server/http.d.ts +5 -4
  56. package/dist/server/http.d.ts.map +1 -1
  57. package/dist/server/http.js +69 -31
  58. package/dist/server/http.js.map +1 -1
  59. package/dist/server/ws.d.ts +4 -3
  60. package/dist/server/ws.d.ts.map +1 -1
  61. package/dist/server/ws.js +32 -18
  62. package/dist/server/ws.js.map +1 -1
  63. package/dist/session.d.ts +25 -10
  64. package/dist/session.d.ts.map +1 -1
  65. package/dist/session.js +117 -67
  66. package/dist/session.js.map +1 -1
  67. package/dist/state.d.ts.map +1 -1
  68. package/dist/state.js +1 -3
  69. package/dist/state.js.map +1 -1
  70. package/package.json +18 -3
  71. package/skills/porthole/SKILL.md +130 -0
  72. package/client-dist/assets/index-C_qSS_Gy.js +0 -49
@@ -1 +1 @@
1
- {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAEnD,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,aAAa,CAAC;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,qBAAqB,EAAE,CAAC;CACnC;AAED,wBAAgB,SAAS,IAAI,MAAM,CAElC;AAED,wBAAsB,SAAS,CAAC,IAAI,SAAc,GAAG,OAAO,CAAC,aAAa,CAAC,CAY1E;AAED,wBAAsB,UAAU,CAC9B,KAAK,EAAE,aAAa,EACpB,IAAI,SAAc,GACjB,OAAO,CAAC,IAAI,CAAC,CAKf;AAED,wBAAsB,aAAa,CACjC,MAAM,EAAE,qBAAqB,EAC7B,IAAI,SAAc,GACjB,OAAO,CAAC,IAAI,CAAC,CAUf;AAED,wBAAsB,aAAa,CACjC,KAAK,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,EACvD,IAAI,SAAc,GACjB,OAAO,CAAC,IAAI,CAAC,CAef;AAED,wBAAsB,wBAAwB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAK/E"}
1
+ {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAEnD,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,aAAa,CAAC;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,qBAAqB,EAAE,CAAC;CACnC;AAED,wBAAgB,SAAS,IAAI,MAAM,CAElC;AAED,wBAAsB,SAAS,CAAC,IAAI,SAAc,GAAG,OAAO,CAAC,aAAa,CAAC,CAY1E;AAED,wBAAsB,UAAU,CAC9B,KAAK,EAAE,aAAa,EACpB,IAAI,SAAc,GACjB,OAAO,CAAC,IAAI,CAAC,CAKf;AAED,wBAAsB,aAAa,CACjC,MAAM,EAAE,qBAAqB,EAC7B,IAAI,SAAc,GACjB,OAAO,CAAC,IAAI,CAAC,CAKf;AAED,wBAAsB,aAAa,CACjC,KAAK,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,EACvD,IAAI,SAAc,GACjB,OAAO,CAAC,IAAI,CAAC,CAef;AAED,wBAAsB,wBAAwB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAK/E"}
package/dist/state.js CHANGED
@@ -26,9 +26,7 @@ export async function writeState(state, path = statePath()) {
26
26
  }
27
27
  export async function upsertSession(record, path = statePath()) {
28
28
  const state = await readState(path);
29
- const sessions = state.sessions.filter((session) => session.serial !== record.serial &&
30
- session.port !== record.port &&
31
- session.pid !== record.pid);
29
+ const sessions = state.sessions.filter((session) => session.serial !== record.serial);
32
30
  sessions.push(record);
33
31
  await writeState({ sessions }, path);
34
32
  }
package/dist/state.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"state.js","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC1E,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAoB1C,MAAM,UAAU,SAAS;IACvB,OAAO,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,IAAI,IAAI,CAAC,MAAM,EAAE,EAAE,UAAU,EAAE,YAAY,CAAC,CAAC;AACxF,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,IAAI,GAAG,SAAS,EAAE;IAChD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACzC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAA2B,CAAC;QACzD,OAAO;YACL,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC;gBACtC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,eAAe,CAAC;gBACzC,CAAC,CAAC,EAAE;SACP,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;IAC1B,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,KAAoB,EACpB,IAAI,GAAG,SAAS,EAAE;IAElB,MAAM,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAChD,MAAM,OAAO,GAAG,GAAG,IAAI,IAAI,OAAO,CAAC,GAAG,MAAM,CAAC;IAC7C,MAAM,SAAS,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IAChE,MAAM,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;AAC9B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,MAA6B,EAC7B,IAAI,GAAG,SAAS,EAAE;IAElB,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,CAAC;IACpC,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC,MAAM,CACpC,CAAC,OAAO,EAAE,EAAE,CACV,OAAO,CAAC,MAAM,KAAK,MAAM,CAAC,MAAM;QAChC,OAAO,CAAC,IAAI,KAAK,MAAM,CAAC,IAAI;QAC5B,OAAO,CAAC,GAAG,KAAK,MAAM,CAAC,GAAG,CAC7B,CAAC;IACF,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACtB,MAAM,UAAU,CAAC,EAAE,QAAQ,EAAE,EAAE,IAAI,CAAC,CAAC;AACvC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,KAAuD,EACvD,IAAI,GAAG,SAAS,EAAE;IAElB,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,CAAC;IACpC,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE;QACjD,IAAI,KAAK,CAAC,MAAM,IAAI,OAAO,CAAC,MAAM,KAAK,KAAK,CAAC,MAAM;YAAE,OAAO,KAAK,CAAC;QAClE,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,IAAI,OAAO,CAAC,IAAI,KAAK,KAAK,CAAC,IAAI;YAAE,OAAO,KAAK,CAAC;QAC1E,IAAI,KAAK,CAAC,GAAG,KAAK,SAAS,IAAI,OAAO,CAAC,GAAG,KAAK,KAAK,CAAC,GAAG;YAAE,OAAO,KAAK,CAAC;QACvE,OAAO,IAAI,CAAC;IACd,CAAC,CAAC,CAAC;IAEH,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAChC,OAAO;IACT,CAAC;IAED,MAAM,UAAU,CAAC,EAAE,QAAQ,EAAE,EAAE,IAAI,CAAC,CAAC;AACvC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAAC,MAAc;IAC3D,MAAM,KAAK,GAAG,MAAM,SAAS,EAAE,CAAC;IAChC,OAAO,KAAK,CAAC,QAAQ,CAAC,IAAI,CACxB,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,KAAK,MAAM,IAAI,OAAO,CAAC,UAAU,CAC7D,CAAC;AACJ,CAAC;AAED,SAAS,eAAe,CAAC,KAAc;IACrC,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IACtD,MAAM,MAAM,GAAG,KAAgC,CAAC;IAChD,OAAO,CACL,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ;QACjC,OAAO,MAAM,CAAC,OAAO,KAAK,QAAQ;QAClC,CAAC,MAAM,CAAC,OAAO,KAAK,OAAO,IAAI,MAAM,CAAC,OAAO,KAAK,IAAI,CAAC;QACvD,OAAO,MAAM,CAAC,GAAG,KAAK,QAAQ;QAC9B,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ;QAC/B,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ;QAC/B,OAAO,MAAM,CAAC,GAAG,KAAK,QAAQ;QAC9B,OAAO,MAAM,CAAC,SAAS,KAAK,QAAQ;QACpC,OAAO,MAAM,CAAC,UAAU,KAAK,SAAS,CACvC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"state.js","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,15 +1,28 @@
1
1
  {
2
2
  "name": "portholejs",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "A window into your Android emulator — stream and control AVDs from the browser",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ },
13
+ "./protocol": {
14
+ "types": "./dist/protocol.d.ts",
15
+ "import": "./dist/protocol.js"
16
+ },
17
+ "./package.json": "./package.json"
18
+ },
8
19
  "bin": {
9
20
  "porthole": "dist/cli.js"
10
21
  },
11
22
  "scripts": {
12
- "build": "tsc && node scripts/copy-package-assets.mjs",
23
+ "build": "npm run build:ts && npm run copy-package-assets",
24
+ "build:ts": "tsc",
25
+ "copy-package-assets": "node scripts/copy-package-assets.mjs",
13
26
  "typecheck": "tsc --noEmit",
14
27
  "postinstall": "node scripts/download-scrcpy-server.mjs",
15
28
  "prepublishOnly": "npm run build --prefix ../.."
@@ -38,7 +51,8 @@
38
51
  "dist/",
39
52
  "!dist/__tests__/",
40
53
  "scripts/download-scrcpy-server.mjs",
41
- "client-dist/"
54
+ "client-dist/",
55
+ "skills/"
42
56
  ],
43
57
  "engines": {
44
58
  "node": ">=20"
@@ -52,6 +66,7 @@
52
66
  "@yume-chan/stream-extra": "^2.5.3",
53
67
  "commander": "^14.0.3",
54
68
  "jpeg-js": "^0.4.4",
69
+ "pixelmatch": "^7.2.0",
55
70
  "pngjs": "^7.0.0",
56
71
  "ws": "^8.21.0"
57
72
  },
@@ -0,0 +1,130 @@
1
+ ---
2
+ name: porthole
3
+ description: Boot, stream, and control Android phone/TV emulators headlessly with the porthole CLI or MCP tools — screenshots, touch/D-pad input, semantic UI dumps, logcat, and APK install. Use when asked to run, test, drive, or inspect an Android emulator or AVD, navigate an Android TV app, or verify Android UI state from an agent workflow.
4
+ ---
5
+
6
+ # Porthole Agent Skill
7
+
8
+ Use Porthole when you need to inspect or control an Android emulator from an
9
+ agent workflow. Porthole supports Android emulator AVDs only; do not use it for
10
+ iOS, physical Android devices, or audio.
11
+
12
+ ## Workflow
13
+
14
+ 1. List devices:
15
+
16
+ ```sh
17
+ porthole list -q
18
+ ```
19
+
20
+ If anything fails at any step (SDK missing, port busy, offline adb,
21
+ missing scrcpy-server), diagnose first:
22
+
23
+ ```sh
24
+ porthole doctor -q
25
+ ```
26
+
27
+ 2. Start a session. Prefer detached JSON mode for automation:
28
+
29
+ ```sh
30
+ porthole start <AVD_NAME> --detach -q
31
+ porthole start <PHONE_AVD> <TV_AVD> --detach -q
32
+ ```
33
+
34
+ In GitHub Actions, prefer the bundled repository action so the emulator,
35
+ Porthole server, and smoke script share one lifecycle:
36
+
37
+ ```yaml
38
+ - uses: giolaq/porthole@main
39
+ with:
40
+ profile: tv
41
+ script: |
42
+ "$PORTHOLE_CLI" focus-on "Library" --select -q -p "$PORTHOLE_PORT"
43
+ ```
44
+
45
+ 3. Verify the screen:
46
+
47
+ ```sh
48
+ porthole screenshot -q
49
+ porthole assert-screen baseline.png --threshold 0.02 -q
50
+ porthole record run.mp4 --duration 10s -q
51
+ ```
52
+
53
+ 4. Drive input:
54
+
55
+ ```sh
56
+ porthole tap 0.5 0.9
57
+ porthole scroll down
58
+ porthole swipe 0.5 0.85 0.5 0.2
59
+ porthole longpress 0.5 0.5
60
+ porthole key 4
61
+ porthole text "hello"
62
+ ```
63
+
64
+ When one Porthole server is streaming multiple emulators, pass
65
+ `-d <serial>` to target the right device:
66
+
67
+ ```sh
68
+ porthole tap 0.5 0.9 -d emulator-5554
69
+ porthole remote dpad_down -d emulator-5556
70
+ ```
71
+
72
+ 5. For Android TV, use remote buttons instead of touch:
73
+
74
+ ```sh
75
+ porthole remote dpad_down
76
+ porthole focus-on "Library" --select
77
+ porthole remote select
78
+ porthole remote back
79
+ ```
80
+
81
+ 6. Read logs when behavior is unclear:
82
+
83
+ ```sh
84
+ curl "http://127.0.0.1:3200/api/logcat?lines=200"
85
+ ```
86
+
87
+ 7. Clean up:
88
+
89
+ ```sh
90
+ porthole kill -q
91
+ ```
92
+
93
+ ## Semantic UI
94
+
95
+ Prefer semantic checks before screenshot interpretation when possible:
96
+
97
+ ```sh
98
+ porthole focused -q
99
+ porthole dump-ui --filter "Settings" -q
100
+ porthole wait-for "Continue" --timeout 10000 -q
101
+ porthole open-url "example://deep/link"
102
+ ```
103
+
104
+ For TV AVDs, prefer `focus-on` / `focus_on` for named destinations. Use
105
+ `remote`, then `focused`, then assert the focused node's `text`, `resourceId`,
106
+ or `contentDesc` for manual focus work. For phones, `find_element` is exposed
107
+ through MCP and can tap the center of a matching node.
108
+
109
+ Note: `focused` is a D-pad/leanback concept. On phone profiles it usually
110
+ returns `null` — that is expected, not an error; use `dump-ui` or
111
+ `find_element` on phones instead.
112
+
113
+ ## MCP Loop
114
+
115
+ When MCP is configured, use:
116
+
117
+ - `list_devices` to pick an AVD
118
+ - `boot_device` and `wait_for_boot` for cold starts
119
+ - `attach_device` before input and screenshots
120
+ - `screenshot` after each meaningful input step
121
+ - `assert_screen` when a baseline image is available
122
+ - `start_recording` and `stop_recording` when an MP4 artifact is useful
123
+ - `dump_ui`, `get_focused`, and `wait_for` for semantic assertions
124
+ - `get_crashes` after risky actions
125
+ - `focus_on` or `remote` for TV navigation
126
+ - `tap`, `swipe`, `scroll`, and `long_press` only for phone profiles
127
+ - `read_logcat` to diagnose crashes or focus issues
128
+ - `install_apk` to load a freshly built APK
129
+
130
+ Keep the loop tight: input, screenshot, compare, adjust.