@ponydev/dsh-phone 0.3.1 → 0.4.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/AGENTS.md CHANGED
@@ -6,13 +6,15 @@
6
6
 
7
7
  DSH Web 插件:**右侧栏预览并点按控制已连接的 Android 设备**(adb),H.264 实时流 + 无 WebCodecs 时回退截图轮询。
8
8
 
9
- **能力边界**:只认 adb(Android)。hdc(鸿蒙)与 iOS 走 `lib/transport.js` 的 `PhoneTransport` 接口后续接入;UI 容器固定用 DSH 原生 `sidebar-right`,不自造悬浮层。
9
+ **能力边界**:Android 走 adb;iOS 只做**模拟器**(simctl 生命周期 + idb 实时/输入,物理 iPhone 不支持);HarmonyOS 模拟器走 DevEco `Emulator` CLI、真机走 hdc。UI 容器固定用 DSH 原生 `sidebar-right`,不自造悬浮层。
10
10
 
11
11
  ## 1. 目录与职责
12
12
 
13
13
  ```
14
14
  lib/index.js Host 入口(/phone/* RPC、connection.admit 围栏、targets、stream 路由、错误映射)
15
15
  lib/adb.js adb 定位 / devices 解析 / getprop 平台 / wm size / 截图 / 输入 / 串行化
16
+ lib/ios.js iOS 模拟器:simctl 列表/创建/boot/删除/截图 + idb H.264 流/输入
17
+ lib/hos.js HarmonyOS:Emulator CLI(生命周期/创建/截图/点击)+ hdc(真机/截图/uitest)
16
18
  lib/stream.js screenrecord H.264 子进程(续接、背压、断开 kill)、清晰度预设、按比例算 size
17
19
  lib/targets.js 常用连接目标($DSH_HOME/phone/targets.json,0600,只存地址/时间)
18
20
  lib/transport.js PhoneTransport 接口 + AdbTransport(hdc / iOS 的挂载点)
@@ -22,6 +24,7 @@ scripts/smoke.mjs 离线冒烟(解析/白名单/targets/尺寸计
22
24
  scripts/check-i18n.mjs zh/en 字典键一致 + 代码用键存在
23
25
  scripts/release-notes.mjs 从 CHANGELOG 抽取当前版本条目
24
26
  scripts/render-test.mjs 离线渲染 harness(列表/预览/浮窗/诊断/流五种状态)
27
+ scripts/hos-smoke.mjs 鸿蒙 transport 只读冒烟(Emulator CLI + hdc)
25
28
  docs/DESIGN.md 架构与布局;docs/mockups 原型;docs/screenshots 截图
26
29
  ```
27
30
 
@@ -36,13 +39,19 @@ docs/DESIGN.md 架构与布局;docs/mockups 原型;docs/scree
36
39
  ## 3. 提交前必须通过
37
40
 
38
41
  ```bash
39
- npm run check # 语法 + i18n 键一致性
42
+ npm run check # 语法 + i18n + 隐私/截图门禁
40
43
  npm run smoke # 解析/白名单/targets/尺寸(无 adb 自动 SKIP)
41
44
  npm pack --dry-run # 发布内容检查
42
45
  ```
43
46
 
44
47
  CI 重复执行以上检查;失败不合并。
45
48
 
49
+ ## 3.1 隐私与截图门禁(不可绕过)
50
+
51
+ 1. `docs/screenshots/`、`docs/mockups/` 下的图**只能**由 `scripts/render-test.mjs` + **假 fixtures** 生成,禁止提交真机 / 真实账户截图;
52
+ 2. docs 截图必须在 `docs/screenshots/MANIFEST.md` 登记来源(`- \`路径\` ← \`scripts/xxx.mjs\``),由 `scripts/check-shots.mjs` 强制;
53
+ 3. 提交前 `npm run check` 已包含 `scripts/check-privacy.mjs` + `scripts/check-shots.mjs` 隐私门禁;命中即失败,不要为通过而放宽规则。
54
+
46
55
  ## 4. 安全不变量(不可破坏)
47
56
 
48
57
  1. **serial 白名单**:`shot` / `input` / `stream` / `screen-info` 前,serial 必须出现在最新 `adb devices -l` 里;
package/CHANGELOG.md CHANGED
@@ -1,5 +1,28 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.4.0 — 2026-10-26
4
+
5
+ ### 新增
6
+ - **iOS 模拟器**:`xcrun simctl` 列表 / 创建 / boot / 关机 / 删除 / 截图;面板可自动进入并轮询预览
7
+ - **HarmonyOS 模拟器**:DevEco `Emulator` CLI 列表 / 创建 / 启动 / 停止 / 删除 / 截图 / 点击 / 滑动 / 旋转 / 电源
8
+ - **HarmonyOS 真机**:`hdc` 设备列表 / 截图 / 点击 / 滑动 / 按键 / 文字输入
9
+ - 「添加设备」菜单:Android 连接 / 创建 iOS 模拟器 / 创建鸿蒙模拟器
10
+ - 设备操作菜单:iOS 模拟器关机 / 删除,鸿蒙模拟器停止 / 删除
11
+ - 平台图标与标签:iOS 模拟器、HarmonyOS 模拟器 / 真机
12
+
13
+ ### 变更
14
+ - Host `/phone/*` 按设备 transport 分发(adb / simctl / emulator / hdc);`health` 返回 iOS 与 HarmonyOS 能力
15
+ - 鸿蒙暂不支持实时流,自动回退截图轮询(iOS 实时流与输入需要 idb,未装时只读预览)
16
+ - 新增 `lib/ios.js`、`lib/hos.js` 与 `scripts/hos-smoke.mjs`
17
+
18
+ ## 0.3.2 — 2026-10-26
19
+
20
+ ### 变更
21
+ - 隐私清理:文档、mockup、冒烟测试与离线 harness 里的真实设备序列号 / Tailscale CGNAT IP / 私有主机名统一替换为示例值
22
+ - 新增 `scripts/check-privacy.mjs` 与 `scripts/check-shots.mjs` 门禁,接入 `npm run check`、CI 与 release workflow
23
+ - npm `files` 的 `docs` 收紧为 `docs/*.md`,不再把 docs 截图 / mockup 图片打包进发布物
24
+ - 截图:删除真实截图 `01-devices` / `02-preview` 与 mockups 图片,只保留由 `scripts/render-test.mjs` + 假 fixtures 重生成的 `03-overview`,并在 `docs/screenshots/MANIFEST.md` 登记来源
25
+
3
26
  ## 0.3.1 — 2026-10-25
4
27
 
5
28
  ### 修复
@@ -58,8 +81,8 @@
58
81
  - 常用连接目标:连接成功自动记录(`$DSH_HOME/phone/targets.json`,最近 12 条),未连接目标也显示在列表,点击直接 `adb connect`
59
82
  - `⋯ → adb 诊断`:adb 路径/版本、每台设备状态,可复制
60
83
  - 列表改为平铺,不再按「云手机」分组;只保留连接方式标签(USB / Wi-Fi / Tailscale / emulator)
61
- - Tailscale 判定:`unicom-openclaw-*`、`*.ts.net`、`100.64.0.0/10`
62
- - 真机验证:Pixel 7a 上 tap / swipe / 返回 / 主页 均已实测(点开「网络和互联网」「关于本机」,列表滚动)
84
+ - Tailscale 判定:`*.ts.net`、`100.64.0.0/10`
85
+ - 真机验证:Android 真机上 tap / swipe / 返回 / 主页 均已实测(点开「网络和互联网」「关于本机」,列表滚动)
63
86
  - H.264 实时预览:Host `POST /phone/stream` 直接 pipe `screenrecord --output-format=h264`;客户端 Annex-B → avcC → WebCodecs VideoDecoder → canvas,约 20–30fps
64
87
  - 不支持 WebCodecs 的浏览器自动回退截图轮询;`screen-info` 提供设备真实分辨率做坐标换算
65
88
  - 操作栏改为底部悬浮胶囊(HarmonyOS 风格三键 + 截图),不占画面高度;顶部设备下拉/清晰度/旋转/更多;断开连接收进设备菜单并二次确认
package/CONTRIBUTING.md CHANGED
@@ -24,7 +24,7 @@ launchctl kickstart -k gui/$(id -u)/local.deepseek-harness.web
24
24
  离线 UI 验证(不依赖宿主,也不需要会话):
25
25
 
26
26
  ```bash
27
- # 先准备一张真实截图
27
+ # 先准备一张画面占位图(本地调试可用真机截图;提交进 docs 的截图必须用合成占位图)
28
28
  adb -s <serial> exec-out screencap -p > /tmp/dsh-phone-shot.png
29
29
  npm run test-ui # 输出 /tmp/dsh-phone-render.png
30
30
  open /tmp/dsh-phone-render.html
@@ -38,7 +38,7 @@ open '/tmp/dsh-phone-render.html#stream'
38
38
  ## 提交前检查
39
39
 
40
40
  ```bash
41
- npm run check # 语法 + i18n 键一致性
41
+ npm run check # 语法 + i18n + 隐私/截图门禁
42
42
  npm run smoke # 解析/白名单/targets/尺寸(无 adb 自动 SKIP)
43
43
  npm pack --dry-run # 发布内容检查
44
44
  ```
@@ -49,5 +49,6 @@ npm pack --dry-run # 发布内容检查
49
49
  - serial 必须先过 `adb devices` 列表校验;不要假设云手机型号/分辨率(用 `wm size`)。
50
50
  - 不新增运行时依赖;不引入构建工具。
51
51
  - 颜色只用 `--dsw-*` token,文案走 zh/en 字典;不做元数据栏、不做文字输入。
52
- - 真实设备截图不要提交到仓库;docs 截图用合成素材生成。
52
+ - **截图只能由 `scripts/render-test.mjs` + 假 fixtures 生成**;不要把真机 / 真实账户截图提交到仓库。
53
+ - docs 截图必须在 `docs/screenshots/MANIFEST.md` 登记来源;提交前 `npm run check` 含隐私门禁(`check-privacy` + `check-shots`),命中即失败。
53
54
  - Conventional Commits:`feat:` / `fix:` / `docs:` / `ci:` / `chore:` / `refactor:`;不写 AI 署名。
package/README.md CHANGED
@@ -5,10 +5,6 @@
5
5
 
6
6
  DSH Web 插件:在右侧栏预览已连接的 Android 设备,点画面就是点手机。
7
7
 
8
- | 设备列表 | 预览画面 |
9
- |---|---|
10
- | ![设备列表](docs/screenshots/01-devices.png) | ![预览画面](docs/screenshots/02-preview.png) |
11
-
12
8
  ![完整界面](docs/screenshots/03-overview.png)
13
9
 
14
10
  ## 功能
@@ -21,7 +17,7 @@ DSH Web 插件:在右侧栏预览已连接的 Android 设备,点画面就是
21
17
  - **连接**:`adb connect <ip>:<port>`(无线调试、Tailscale 云手机);连接过的目标自动记到 `$DSH_HOME/phone/targets.json`,未连接时也显示在列表里,点一下就直接连。
22
18
  - **诊断**:`⋯ → adb 诊断` 看 adb 路径/版本、每台设备状态,一键复制。
23
19
  - **更多**:电源、旋转、重新连接、adb 诊断、浮窗打开、复制 serial、断开。
24
- - 连接方式由 serial 判断:`usb:` 属性 → USB;`unicom-openclaw-*` 或 `100.64.0.0/10` → Tailscale;其余带端口 → Wi-Fi。
20
+ - 连接方式由 serial 判断:`usb:` 属性 → USB;`*.ts.net` 或 `100.64.0.0/10` → Tailscale;其余带端口 → Wi-Fi。
25
21
  - 系统平台由 `getprop` 判断(`ro.build.version.harmony*` / `hw_sc.build.platform.version` → HarmonyOS,其余 Android);iOS 图标等接入 WDA transport 后生效。
26
22
  - 没有分辨率/网速元数据栏,没有文字输入框。
27
23
 
@@ -29,7 +25,7 @@ DSH Web 插件:在右侧栏预览已连接的 Android 设备,点画面就是
29
25
 
30
26
  ```sh
31
27
  # 本地开发(link 到当前 clone)
32
- dsh plugin --profile web add link:/Users/pony/deepseek/plugins/dsh-phone
28
+ dsh plugin --profile web add link:~/deepseek/plugins/dsh-phone
33
29
 
34
30
  # 从 npm(发布后)
35
31
  dsh plugin --profile web add @ponydev/dsh-phone
@@ -46,7 +42,7 @@ dsh plugin --profile web add @ponydev/dsh-phone
46
42
  - id: phone
47
43
  name: "@ponydev/dsh-phone"
48
44
  config:
49
- adbPath: adb # 或 /Users/pony/Library/Android/sdk/platform-tools/adb
45
+ adbPath: adb # 或 ~/Library/Android/sdk/platform-tools/adb
50
46
  pollMs: 700
51
47
  streamTimeLimit: 180 # screenrecord 单次上限,到点自动续
52
48
  streamBitRate: 6000000 # 客户端清晰度会覆盖这两项
@@ -114,35 +110,50 @@ DSH 右侧栏第一次打开是**视口宽度的 45%**(1440 屏 ≈ 648px)
114
110
  - 顶部:设备下拉、旋转、更多(电源、重连、诊断、浮窗、复制 serial、设备列表)。
115
111
  - 「断开连接」放在设备下拉菜单里,需要点两次确认(防止误触)。
116
112
 
113
+ ## 平台支持
114
+
115
+ | 平台 | 后端 | 画面 | 操作 | 创建 |
116
+ |---|---|---|---|---|
117
+ | Android 真机 / 云手机 | adb(USB / TCP / Tailscale) | H.264 20–30fps | tap / swipe / 按键 | — |
118
+ | iOS 模拟器 | `xcrun simctl` + idb(可选) | 截图轮询 1–2fps;装 idb 后 H.264 | 装 idb 后 tap / swipe / 按键 | ✅ 选择机型 + 运行时 |
119
+ | HarmonyOS 模拟器 | DevEco `Emulator` CLI | 截图轮询 1–2fps | tap / swipe / 旋转 / 电源 / 按键 / 文字 | ✅ 选择系统镜像 |
120
+ | HarmonyOS 真机 | hdc | 截图轮询 1–2fps | tap / swipe / 按键 / 文字 | — |
121
+
122
+ - iOS 依赖 macOS + Xcode;实时画面/输入需要 `idb`(`brew install facebook/fb/idb-companion` + `pip install fb-idb`),未装时只读预览。
123
+ - HarmonyOS 依赖 DevEco Studio(`Emulator` CLI)与 `hdc`;hdc 没有 screenrecord,只能截图轮询。
124
+ - 物理 iPhone / iPad 不支持(Apple 未公开投屏/注入 API,Claude Code Desktop 也只支持模拟器)。
125
+
117
126
  ## 已知限制
118
127
 
119
- - 画面默认走 H.264 流(约 20–30fps);没有 WebCodecs 的浏览器会回退到 1–2fps 轮询截图。
120
- - 流是 `screenrecord`,没有声音;单次 180s 上限由 Host 自动续接(断开 <1s)。
128
+ - Android 画面默认走 H.264 流(约 20–30fps);没有 WebCodecs 的浏览器会回退到 1–2fps 轮询截图。
129
+ - Android 流是 `screenrecord`,没有声音;单次 180s 上限由 Host 自动续接(断开 <1s)。
121
130
  - 单个右侧栏 tab,设备在 tab 内切换;不支持同一 pane 多设备并排(后续可开 `multiple`)。
122
- - 没有文字输入(`adb shell input text` 只支持 ASCII,中文要 ADBKeyboard)。
131
+ - Android 文字输入(`adb shell input text` 只支持 ASCII,中文要 ADBKeyboard);鸿蒙用 `uitest uiInput text`。
123
132
  - 「已保存」目标是地址级记录,没有备注名;显示名直接是 `ip:port` / 主机名。
124
- - 只支持 Android/adb;hdc(鸿蒙)和 iOS 走 `PhoneTransport` 接口后加。
125
133
  - 右侧栏是 per-session 的,没有会话的页面不显示手机图标。
126
- - 需要设备上已授权 USB 调试;`unauthorized` 会提示去手机上点允许。
134
+ - Android 需要设备上已授权 USB 调试;`unauthorized` 会提示去手机上点允许。
127
135
 
128
136
  ## 开发
129
137
 
130
138
  ```sh
131
- npm run check # node --check 四个 lib 文件
139
+ npm run check # 语法 + i18n + 隐私/截图门禁
132
140
  npm run smoke # 解析/白名单/真机 adb 冒烟
141
+ npm run smoke:hos # 鸿蒙 Emulator CLI / hdc 只读冒烟(需要 DevEco)
133
142
  node scripts/render-test.mjs [screenshot.png]
134
143
  # 离线渲染列表 + 预览,输出 /tmp/dsh-phone-render.html/.png
135
144
  ```
136
145
 
137
- `scripts/render-test.mjs` 默认用 `/tmp/dsh-phone-shot.png` 作为画面占位;可以先用
138
- `adb -s <serial> exec-out screencap -p > /tmp/dsh-phone-shot.png` 生成。
146
+ `scripts/render-test.mjs` 默认用 `/tmp/dsh-phone-shot.png` 作为画面占位。本地调试可以用真机截图,
147
+ 但**提交进 docs 的截图必须用合成占位图**(真机截图只放 /tmp,不进仓库)。
139
148
 
140
149
  ## 结构
141
150
 
142
151
  ```
143
- lib/index.js Host:/phone 路由、认证围栏、错误映射
144
- lib/adb.js adb 定位 / devices 解析 / 截图 / 输入 / 串行化
145
- lib/transport.js PhoneTransport 接口 + AdbTransport(hdc / iOS 后加)
152
+ lib/index.js Host:/phone 路由、认证围栏、按 transport 分发
153
+ lib/adb.js Android:adb 定位 / devices 解析 / 截图 / 输入 / 串行化
154
+ lib/ios.js iOS 模拟器:simctl 生命周期/创建/截图 + idb 实时流/输入
155
+ lib/hos.js HarmonyOS:DevEco Emulator CLI + hdc(真机)
156
+ lib/transport.js PhoneTransport 接口 + AdbTransport
146
157
  lib/client.js ModuleLoader bundle:tab 类型、列表、预览、i18n、样式
147
158
  cordis.patch.yml bundle 补丁
148
159
  scripts/ smoke + 离线渲染
package/cordis.patch.yml CHANGED
@@ -3,6 +3,10 @@
3
3
  name: "@ponydev/dsh-phone"
4
4
  config:
5
5
  adbPath: adb
6
+ xcrun: xcrun
7
+ idb: idb
8
+ hdcPath: hdc
9
+ emulatorPath: ''
6
10
  pollMs: 700
7
11
  streamTimeLimit: 180
8
12
  streamBitRate: 6000000
package/docs/DESIGN.md CHANGED
@@ -4,9 +4,7 @@
4
4
  > 参考 Codex Mobile Dev 的右侧设备面板:**顶上只有一行「设备下拉 + 几个图标」,下面整块留给设备画面**。
5
5
  > 本文是布局、命名与技术方案,**尚未开始写代码**。
6
6
 
7
- ![设备列表](mockups/list.png)
8
-
9
- ![设备画面](mockups/device.png)
7
+ 原型(离线 HTML,假数据,可用浏览器直接打开):[`docs/mockups/mockup.html`](mockups/mockup.html)
10
8
 
11
9
  ---
12
10
 
@@ -65,12 +63,12 @@
65
63
  [ 选择设备 ▾ ] [刷新] [+]
66
64
  ──────────────────────────────────────────────────────
67
65
  已连接
68
- ▢ Pixel 7a [USB] 34201JEHN07681 ›
69
- ▢ Pixel 7a [Wi-Fi] 100.107.25.26:5555 ›
70
- ▢ 小米 13 [thor] 100.90.248.53:5555 ›
66
+ ▢ Pixel 7a [USB] SERIAL0123456789AB ›
67
+ ▢ Pixel 7a [Wi-Fi] 100.64.0.11:5555 ›
68
+ ▢ 小米 13 [thor] 100.64.0.12:5555 ›
71
69
  云手机
72
- ☁ 云手机 pony unicom-openclaw-pony:5555 ›
73
- ☁ 云手机 test unicom-openclaw-test:5555 ›
70
+ ☁ 云手机 A node-a.example-tailnet.ts.net:5555 ›
71
+ ☁ 云手机 B node-b.example-tailnet.ts.net:5555 ›
74
72
  ──────────────────────────────────────────────────────
75
73
  ● 5 台在线
76
74
  ```
@@ -246,3 +244,23 @@ Host 侧定义 `PhoneTransport { id, list, connect, shot, input }`:
246
244
  2. 设备多时:默认「一个 tab 内切换」(本文)还是「每台设备一个 tab」?
247
245
 
248
246
  (图标位置 = 会话头部工具区、名字 = `dsh-phone`、无元数据列、无输入框,已按你的意思定下。)
247
+
248
+
249
+ ## 多平台 transport(0.4.0)
250
+
251
+ ```
252
+ /phone/* ── resolveDevice(serial) ──┬── adb Android 真机 / 云手机(H.264 screenrecord)
253
+ ├── simctl iOS 模拟器(截图;idb 提供 H.264 + HID)
254
+ ├── emulator HarmonyOS 模拟器(DevEco Emulator CLI)
255
+ └── hdc HarmonyOS 真机(snapshot_display + uitest)
256
+ ```
257
+
258
+ - **iOS**:只支持模拟器。生命周期/创建走公开 `xcrun simctl`;实时画面与点击/输入走 `idb`
259
+ (Meta FBSimulatorControl,Claude Code Desktop 内部也是 CoreSimulator/SimulatorKit 私有栈)。
260
+ idb 的 `video-stream --format h264` 输出 Annex-B,直接复用客户端的 WebCodecs 管线;
261
+ `idb describe` 的 `screen_dimensions.density` 用于像素 → point 坐标换算。
262
+ - **HarmonyOS 模拟器**:`Emulator -list/-create/-start/-stop/-delete/-screenshot/-click/-slide/-rotation/-power`;
263
+ 按键与文字借道 hdc `uitest uiInput`(模拟器没有对应 CLI)。
264
+ - **HarmonyOS 真机**:`hdc list targets` + `snapshot_display` + `uitest uiInput`;没有 screenrecord,只能截图轮询。
265
+ - **物理 iPhone / iPad 不支持**:Apple 没有公开投屏/HID 注入 API(Claude 同样只做模拟器;
266
+ Codex 用 Xcode 27 CoreDevice 私有 HEVC + UniversalHID,不在本项目范围)。
package/lib/adb.js CHANGED
@@ -88,7 +88,7 @@ function isCgnatSerial(serial) {
88
88
  export function classifyDevice(serial, props = {}) {
89
89
  if (props.usb) return 'usb'
90
90
  if (/^emulator-\d+$/.test(serial)) return 'emulator'
91
- if (/^unicom-openclaw-|\.ts\.net/.test(serial)) return 'tailscale'
91
+ if (/\.ts\.net/.test(serial)) return 'tailscale'
92
92
  if (isCgnatSerial(serial)) return 'tailscale'
93
93
  if (serial.includes(':')) return 'wifi'
94
94
  return 'usb'
@@ -323,7 +323,7 @@ export class Adb {
323
323
 
324
324
  async connect(address) {
325
325
  if (typeof address !== 'string' || !ADDRESS_RE.test(address.trim())) {
326
- throw fail('bad-address', '地址格式应为 host:port,例如 100.90.248.53:5555')
326
+ throw fail('bad-address', '地址格式应为 host:port,例如 192.0.2.53:5555')
327
327
  }
328
328
  const { stdout } = await this._run(['connect', address.trim()], { timeout: 8000 })
329
329
  this._devices.at = 0