@ponydev/dsh-phone 0.0.0-stage → 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/AGENTS.md ADDED
@@ -0,0 +1,77 @@
1
+ # AGENTS.md — dsh-phone 项目规范(AI / 自动化代理)
2
+
3
+ 本文件是**在这个仓库里工作时必须遵守的项目级规范**。全局规范见 `~/.dsh/AGENTS.md`;本文件只写项目特有约束。架构、布局与取舍见 [`docs/DESIGN.md`](docs/DESIGN.md)。
4
+
5
+ ## 0. 一句话
6
+
7
+ DSH Web 插件:**右侧栏预览并点按控制已连接的 Android 设备**(adb),H.264 实时流 + 无 WebCodecs 时回退截图轮询。
8
+
9
+ **能力边界**:只认 adb(Android)。hdc(鸿蒙)与 iOS 走 `lib/transport.js` 的 `PhoneTransport` 接口后续接入;UI 容器固定用 DSH 原生 `sidebar-right`,不自造悬浮层。
10
+
11
+ ## 1. 目录与职责
12
+
13
+ ```
14
+ lib/index.js Host 入口(/phone/* RPC、connection.admit 围栏、targets、stream 路由、错误映射)
15
+ lib/adb.js adb 定位 / devices 解析 / getprop 平台 / wm size / 截图 / 输入 / 串行化
16
+ lib/stream.js screenrecord H.264 子进程(续接、背压、断开 kill)、清晰度预设、按比例算 size
17
+ lib/targets.js 常用连接目标($DSH_HOME/phone/targets.json,0600,只存地址/时间)
18
+ lib/transport.js PhoneTransport 接口 + AdbTransport(hdc / iOS 的挂载点)
19
+ lib/client.js ModuleLoader bundle(tab 类型、列表、预览、WebCodecs、i18n、样式)
20
+ cordis.patch.yml bundle 补丁(插入 phone 行、默认配置)
21
+ scripts/smoke.mjs 离线冒烟(解析/白名单/targets/尺寸计算;有 adb 时做真实列表)
22
+ scripts/check-i18n.mjs zh/en 字典键一致 + 代码用键存在
23
+ scripts/release-notes.mjs 从 CHANGELOG 抽取当前版本条目
24
+ scripts/render-test.mjs 离线渲染 harness(列表/预览/浮窗/诊断/流五种状态)
25
+ docs/DESIGN.md 架构与布局;docs/mockups 原型;docs/screenshots 截图
26
+ ```
27
+
28
+ **约束**:Host 与 Client 不能互相 import;Client 不读文件/环境变量;跨端数据只走 `/phone/*` RPC。
29
+
30
+ ## 2. 修改前必须做
31
+
32
+ 1. `git status`、`git log --oneline -3`、`git worktree list` 确认工作区状态;
33
+ 2. 涉及 UI 先读 [`docs/DESIGN.md`](docs/DESIGN.md);
34
+ 3. 涉及设备操作先在真机确认(USB 优先);不要假设云手机型号/分辨率。
35
+
36
+ ## 3. 提交前必须通过
37
+
38
+ ```bash
39
+ npm run check # 语法 + i18n 键一致性
40
+ npm run smoke # 解析/白名单/targets/尺寸(无 adb 自动 SKIP)
41
+ npm pack --dry-run # 发布内容检查
42
+ ```
43
+
44
+ CI 重复执行以上检查;失败不合并。
45
+
46
+ ## 4. 安全不变量(不可破坏)
47
+
48
+ 1. **serial 白名单**:`shot` / `input` / `stream` / `screen-info` 前,serial 必须出现在最新 `adb devices -l` 里;
49
+ 2. 一律 `execFile('adb', [args...])`,不拼 shell;`connect` 地址走 `host:port` 正则;
50
+ 3. 不暴露任意 `adb shell`;不实现 root;
51
+ 4. 路由复用 `connection.admit` 的 Host/Origin + Cookie 认证,未认证 401;
52
+ 5. `targets.json` 只存地址和最近使用时间,权限 600,不存凭据;
53
+ 6. 日志不打印凭据、完整截图或设备个人数据。
54
+
55
+ ## 5. UI 规范(DSH 原生)
56
+
57
+ - 只用 `--dsw-*` token,禁止硬编码色值(fallback 除外);
58
+ - 文案全走 i18n(zh/en 键完全一致,`scripts/check-i18n.mjs` 强制);
59
+ - 列表:平铺一列,平台图标(Android/HarmonyOS/iOS)+ 连接方式/系统两个小标签;
60
+ - 预览:H.264 → WebCodecs;底部悬浮胶囊(`◀ ○ □ │ 📷`);顶部设备下拉、清晰度、旋转、更多;
61
+ - **不做**分辨率/网速等元数据栏;v1 **不做**文字输入框;
62
+ - 断开连接放在设备下拉菜单里并二次确认。
63
+
64
+ ## 6. 不要做的事
65
+
66
+ - 不要用 `ctx.connection.rpc.handle()`(web 组合下会失败),必须 `webServer.register` + `connection.admit`;
67
+ - 不要引入构建工具/打包器/运行时依赖(手写 ModuleLoader bundle 是刻意设计);
68
+ - 不要在 `inject` 里放可选服务(用 `ctx.get` 宽松读取);
69
+ - 不要把真实设备截图提交进仓库(docs 截图用 /tmp 合成素材 + `render-test.mjs` 生成);
70
+ - 不要提交 `node_modules/`、`*.tgz`、临时脚本、密钥。
71
+
72
+ ## 7. 版本与发布
73
+
74
+ - 版本号语义化;**发布只由 `v*` tag 触发**,禁止手动 `npm publish`(首次 0.1.0 例外,已完成);
75
+ - 每个版本必须更新 `CHANGELOG.md`(`## <semver> — <YYYY-MM-DD>`),Release 正文由它抽取;
76
+ - npm Trusted Publishing(OIDC)已配置:PonyDevAI/dsh-phone + workflow `release.yml`,发布免 2FA;
77
+ - 提交信息用 Conventional Commits;作者使用全局 git config,不写 AI 署名。
package/CHANGELOG.md ADDED
@@ -0,0 +1,35 @@
1
+ # Changelog
2
+
3
+ ## 0.1.1 — 2026-10-24
4
+
5
+ ### 变更
6
+ - 仓库规范与 `dsh-model-usage` / `dsh-tailscale` 对齐:补 `AGENTS.md`、`docs/DESIGN.md`、scripts 命名(`check-i18n` / `release-notes`)、npm `files`、CI/release workflow
7
+ - 发布内容补齐 `docs`、`AGENTS.md`、`CONTRIBUTING.md`、`RELEASE.md`
8
+ - npm Trusted Publisher(OIDC)配置完成,后续 tag 发版免 2FA
9
+ - 文档目录整理:`docs/DESIGN.md`、`docs/mockups/`、`docs/screenshots/01..03`
10
+
11
+ ## 0.1.0 — 2026-10-24
12
+
13
+ - 首个可用版本:右侧栏「手机」tab + 会话头部手机图标
14
+ - 设备列表:USB / Wi-Fi / 模拟器 / 云手机分组,含状态点
15
+ - 预览:轮询 `adb exec-out screencap -p`,等比机身 bezel,无元数据栏、无输入框
16
+ - 点按 / 拖拽 → `adb shell input tap|swipe`
17
+ - 顶栏:设备下拉、返回 / 主页 / 多任务 / 截图 / 更多(电源、旋转、重连、复制 serial、断开)
18
+ - 连接:`adb connect <ip>:<port>`
19
+ - Host:`/phone/*` 路由 + `connection.admit` 认证围栏;serial 白名单;execFile 无 shell
20
+ - 常用连接目标:连接成功自动记录(`$DSH_HOME/phone/targets.json`,最近 12 条),未连接目标也显示在列表,点击直接 `adb connect`
21
+ - `⋯ → adb 诊断`:adb 路径/版本、每台设备状态,可复制
22
+ - 列表改为平铺,不再按「云手机」分组;只保留连接方式标签(USB / Wi-Fi / Tailscale / emulator)
23
+ - Tailscale 判定:`unicom-openclaw-*`、`*.ts.net`、`100.64.0.0/10`
24
+ - 真机验证:Pixel 7a 上 tap / swipe / 返回 / 主页 均已实测(点开「网络和互联网」「关于本机」,列表滚动)
25
+ - H.264 实时预览:Host `POST /phone/stream` 直接 pipe `screenrecord --output-format=h264`;客户端 Annex-B → avcC → WebCodecs VideoDecoder → canvas,约 20–30fps
26
+ - 不支持 WebCodecs 的浏览器自动回退截图轮询;`screen-info` 提供设备真实分辨率做坐标换算
27
+ - 操作栏改为底部悬浮胶囊(HarmonyOS 风格三键 + 截图),不占画面高度;顶部设备下拉/清晰度/旋转/更多;断开连接收进设备菜单并二次确认
28
+ - 顶部新增清晰度切换:流畅 360x800/2M、标准 540x1200/6M、高清 720x1600/10M,只影响流输出,不改设备分辨率
29
+ - 胶囊细节:返回键改为 Android 三角、按钮 42px、上下留距 24px、玻璃材质(blur + 高光 + 阴影)
30
+ - 修复云手机画面比例:`wm size` 优先 Override size;流的 size 按设备实际比例等比缩放(同一档在不同设备输出不同分辨率)
31
+ - 清晰度改为按设备 serial 记忆;只在选中设备后显示切换按钮
32
+ - 预览放大:顶部对齐、边距压到最小(高度约占舞台 88%);`⋯ → 沉浸模式` 可隐藏胶囊再放大
33
+ - 胶囊收紧凑:高度 54→42、按钮 42→36、上下 padding 6→3、左右 12→14,两端为标准半圆(半径=高度/2)
34
+ - 设备图标按系统显示:Android 机器人 / HarmonyOS / iOS(iOS 待 transport),22px 实心标记、无底色;行内同时显示连接方式与系统两个小标签
35
+ - 测试:`npm run smoke`(含 targets 存储、getprop 解析、平台判定)、`scripts/render-test.mjs`(列表/预览/浮窗/诊断/流五种状态)
@@ -0,0 +1,53 @@
1
+ # 贡献指南
2
+
3
+ ## 环境要求
4
+
5
+ - Node.js 24+
6
+ - 已安装 DSH(`@deepseek-ai/dsh` ≥ 0.2.0-rc.2)
7
+ - 本机有 `adb`(Android platform-tools),设备已授权 USB 调试
8
+ - 本地开发无需构建(ESM + 手写 ModuleLoader bundle)
9
+
10
+ 项目规范见 [`AGENTS.md`](AGENTS.md),架构与布局见 [`docs/DESIGN.md`](docs/DESIGN.md)。
11
+
12
+ ## 本地开发
13
+
14
+ ```bash
15
+ # 1. 链接安装到当前 web profile
16
+ dsh plugin --profile web add link:$PWD
17
+
18
+ # 2. Host 侧(lib/index.js、lib/adb.js、lib/stream.js、lib/targets.js)改完必须重启 dsh web
19
+ launchctl kickstart -k gui/$(id -u)/local.deepseek-harness.web
20
+
21
+ # 3. Client 侧(lib/client.js)改完刷新页面即可(⌘⇧R)
22
+ ```
23
+
24
+ 离线 UI 验证(不依赖宿主,也不需要会话):
25
+
26
+ ```bash
27
+ # 先准备一张真实截图
28
+ adb -s <serial> exec-out screencap -p > /tmp/dsh-phone-shot.png
29
+ npm run test-ui # 输出 /tmp/dsh-phone-render.png
30
+ open /tmp/dsh-phone-render.html
31
+
32
+ # 流链路(H.264 → WebCodecs → canvas)
33
+ adb -s <serial> exec-out screenrecord --output-format=h264 --time-limit=5 --size=540x1200 - > /tmp/p1-video.h264
34
+ node scripts/render-test.mjs /tmp/dsh-phone-shot.png /tmp/p1-video.h264
35
+ open '/tmp/dsh-phone-render.html#stream'
36
+ ```
37
+
38
+ ## 提交前检查
39
+
40
+ ```bash
41
+ npm run check # 语法 + i18n 键一致性
42
+ npm run smoke # 解析/白名单/targets/尺寸(无 adb 自动 SKIP)
43
+ npm pack --dry-run # 发布内容检查
44
+ ```
45
+
46
+ ## 约定
47
+
48
+ - 只用 `execFile` + 参数数组,不拼 shell;新增命令必须进白名单。
49
+ - serial 必须先过 `adb devices` 列表校验;不要假设云手机型号/分辨率(用 `wm size`)。
50
+ - 不新增运行时依赖;不引入构建工具。
51
+ - 颜色只用 `--dsw-*` token,文案走 zh/en 字典;不做元数据栏、不做文字输入。
52
+ - 真实设备截图不要提交到仓库;docs 截图用合成素材生成。
53
+ - Conventional Commits:`feat:` / `fix:` / `docs:` / `ci:` / `chore:` / `refactor:`;不写 AI 署名。
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Pony
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,154 @@
1
- # Temporary Holding Version
1
+ # dsh-phone
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ [![npm](https://img.shields.io/npm/v/@ponydev/dsh-phone)](https://www.npmjs.com/package/@ponydev/dsh-phone)
4
+ [![license](https://img.shields.io/npm/l/@ponydev/dsh-phone)](LICENSE)
5
+
6
+ DSH Web 插件:在右侧栏预览已连接的 Android 设备,点画面就是点手机。
7
+
8
+ | 设备列表 | 预览画面 |
9
+ |---|---|
10
+ | ![设备列表](docs/screenshots/01-devices.png) | ![预览画面](docs/screenshots/02-preview.png) |
11
+
12
+ ![完整界面](docs/screenshots/03-overview.png)
13
+
14
+ ## 功能
15
+
16
+ - **会话头部手机图标**:点一下展开右侧栏,角标显示在线设备数。
17
+ - **设备列表**:平铺一列,不按手机类型分组;图标按设备系统显示(Android / HarmonyOS / iOS),旁边两个小标签分别标连接方式(USB / Wi-Fi / Tailscale / emulator)和系统(Android / HarmonyOS / iOS),状态点区分 `device` / `unauthorized` / `offline` / `已保存`。
18
+ - **预览**:H.264 流(`screenrecord` → WebCodecs → canvas),约 20–30fps;不支持 WebCodecs 时自动回退截图轮询。设备画面按右侧栏高度等比缩放,带机身 bezel。
19
+ - **点按**:点击 = `tap`,拖拽 = `swipe`(坐标按 `wm size` 的设备像素换算,和流分辨率无关)。
20
+ - **操作栏**:底部是「返回 / 主页 / 多任务 | 截图」,顶部只有设备下拉、旋转、更多。
21
+ - **连接**:`adb connect <ip>:<port>`(无线调试、Tailscale 云手机);连接过的目标自动记到 `$DSH_HOME/phone/targets.json`,未连接时也显示在列表里,点一下就直接连。
22
+ - **诊断**:`⋯ → adb 诊断` 看 adb 路径/版本、每台设备状态,一键复制。
23
+ - **更多**:电源、旋转、重新连接、adb 诊断、浮窗打开、复制 serial、断开。
24
+ - 连接方式由 serial 判断:`usb:` 属性 → USB;`unicom-openclaw-*` 或 `100.64.0.0/10` → Tailscale;其余带端口 → Wi-Fi。
25
+ - 系统平台由 `getprop` 判断(`ro.build.version.harmony*` / `hw_sc.build.platform.version` → HarmonyOS,其余 Android);iOS 图标等接入 WDA transport 后生效。
26
+ - 没有分辨率/网速元数据栏,没有文字输入框。
27
+
28
+ ## 安装
29
+
30
+ ```sh
31
+ # 本地开发(link 到当前 clone)
32
+ dsh plugin --profile web add link:/Users/pony/deepseek/plugins/dsh-phone
33
+
34
+ # 从 npm(发布后)
35
+ dsh plugin --profile web add @ponydev/dsh-phone
36
+ ```
37
+
38
+ 装完重启 `dsh web`。右侧栏 tab 类型和头部图标在重启后的页面里出现。
39
+
40
+ ## 配置
41
+
42
+ `cordis.patch.yml` 里可以覆盖:
43
+
44
+ ```yaml
45
+ - insert:
46
+ - id: phone
47
+ name: "@ponydev/dsh-phone"
48
+ config:
49
+ adbPath: adb # 或 /Users/pony/Library/Android/sdk/platform-tools/adb
50
+ pollMs: 700
51
+ streamTimeLimit: 180 # screenrecord 单次上限,到点自动续
52
+ streamBitRate: 6000000 # 客户端清晰度会覆盖这两项
53
+ streamSize: 540x1200
54
+ ```
55
+
56
+ 客户端清晰度预设(顶部切换,**按设备 serial 分别记忆**):
57
+
58
+ | 档位 | 目标短边 | bitrate | Pixel 1080x2400 | 云手机 720x1280 | 云手机 1256x2584 |
59
+ |---|---|---|---|---|---|
60
+ | 流畅 | 360 | 2 Mbps | 360x800 | 360x640 | 360x740 |
61
+ | 标准 | 540 | 6 Mbps | 540x1200 | 540x960 | 540x1110 |
62
+ | 高清 | 720 | 10 Mbps | 720x1600 | 720x1280 | 720x1482 |
63
+
64
+ 输出尺寸按设备**实际显示分辨率**等比计算(`wm size` 优先取 Override size),不会把 9:20 的比例硬套到别的手机。
65
+ ```
66
+
67
+ `adb` 查找顺序:`adbPath` → `PATH` → `$ANDROID_HOME/platform-tools/adb` → `$ANDROID_SDK_ROOT/platform-tools/adb` → `~/Library/Android/sdk/platform-tools/adb` → `/opt/homebrew/bin/adb`。
68
+
69
+ ## 接口
70
+
71
+ Host 半区挂 `/phone` 前缀(`webServer.register` + `connection.admit` 认证围栏),纯 JSON:
72
+
73
+ | 接口 | 说明 |
74
+ |---|---|
75
+ | `POST /phone/health` | adb 路径/版本、设备数 |
76
+ | `POST /phone/devices` | `adb devices -l` 解析结果 |
77
+ | `POST /phone/connect` | `{ address }` |
78
+ | `POST /phone/disconnect` | `{ serial }` |
79
+ | `POST /phone/shot` | `{ serial }` → `image/png` 原始字节 |
80
+ | `POST /phone/input` | `{ serial, event }`,event 支持 `tap` / `swipe` / `key` / `rotate` |
81
+ | `POST /phone/stream` | `{ serial }` → `video/h264` chunked Annex-B 流 |
82
+ | `POST /phone/screen-info` | `{ serial }` → `{ width, height }`(`wm size`) |
83
+ | `POST /phone/targets` | 已保存的连接目标(最近 12 条,含 pinned/lastSeenAt) |
84
+ | `POST /phone/targets/remove` | `{ address }` |
85
+
86
+ 成功 `{ ok: true, value }`,失败 `{ ok: false, error: { code, message } }`。
87
+
88
+ ## 安全
89
+
90
+ - 所有 adb 调用 `execFile` + 参数数组,不经过 shell。
91
+ - serial 必须出现在最新 `adb devices -l` 里才允许 `shot` / `input`;`connect` 地址走 `host:port` 正则。
92
+ - 不暴露任意 `adb shell` 命令。
93
+ - 路由复用 DSH 的 Host/Origin + Cookie 认证,未认证返回 401。
94
+
95
+ ## 关于右侧栏宽度
96
+
97
+ DSH 右侧栏第一次打开是**视口宽度的 45%**(1440 屏 ≈ 648px),之后记住你拖出来的像素宽度;这是 frame 级设置,**插件没有 API 改**。
98
+
99
+ 而手机画面是按高度等比缩放的,1440×900 下大约 361px 宽 —— 所以默认宽度下画面两侧会有留白。两个办法:
100
+
101
+ 1. 手动把右侧栏拖窄一次(DSH 会记住);
102
+ 2. 打开手机后点 `⋯ → 浮窗打开`,插件会按画面宽度算一个 `324–361px` 的浮窗并放到右侧。
103
+
104
+ ## 操作布局
105
+
106
+ ```
107
+ [ Pixel 7a ▾ ] [旋转] [⋯]
108
+ ────────────────────────────────────────────
109
+ (设备画面)
110
+ ────────────────────────────────────────────
111
+ [←] [○] [□] │ [📷]
112
+ ```
113
+ - 底部:返回 / 主页 / 多任务,右侧分隔后是截图。
114
+ - 顶部:设备下拉、旋转、更多(电源、重连、诊断、浮窗、复制 serial、设备列表)。
115
+ - 「断开连接」放在设备下拉菜单里,需要点两次确认(防止误触)。
116
+
117
+ ## 已知限制
118
+
119
+ - 画面默认走 H.264 流(约 20–30fps);没有 WebCodecs 的浏览器会回退到 1–2fps 轮询截图。
120
+ - 流是 `screenrecord`,没有声音;单次 180s 上限由 Host 自动续接(断开 <1s)。
121
+ - 单个右侧栏 tab,设备在 tab 内切换;不支持同一 pane 多设备并排(后续可开 `multiple`)。
122
+ - 没有文字输入(`adb shell input text` 只支持 ASCII,中文要 ADBKeyboard)。
123
+ - 「已保存」目标是地址级记录,没有备注名;显示名直接是 `ip:port` / 主机名。
124
+ - 只支持 Android/adb;hdc(鸿蒙)和 iOS 走 `PhoneTransport` 接口后加。
125
+ - 右侧栏是 per-session 的,没有会话的页面不显示手机图标。
126
+ - 需要设备上已授权 USB 调试;`unauthorized` 会提示去手机上点允许。
127
+
128
+ ## 开发
129
+
130
+ ```sh
131
+ npm run check # node --check 四个 lib 文件
132
+ npm run smoke # 解析/白名单/真机 adb 冒烟
133
+ node scripts/render-test.mjs [screenshot.png]
134
+ # 离线渲染列表 + 预览,输出 /tmp/dsh-phone-render.html/.png
135
+ ```
136
+
137
+ `scripts/render-test.mjs` 默认用 `/tmp/dsh-phone-shot.png` 作为画面占位;可以先用
138
+ `adb -s <serial> exec-out screencap -p > /tmp/dsh-phone-shot.png` 生成。
139
+
140
+ ## 结构
141
+
142
+ ```
143
+ lib/index.js Host:/phone 路由、认证围栏、错误映射
144
+ lib/adb.js adb 定位 / devices 解析 / 截图 / 输入 / 串行化
145
+ lib/transport.js PhoneTransport 接口 + AdbTransport(hdc / iOS 后加)
146
+ lib/client.js ModuleLoader bundle:tab 类型、列表、预览、i18n、样式
147
+ cordis.patch.yml bundle 补丁
148
+ scripts/ smoke + 离线渲染
149
+ docs/ DESIGN.md、mockup、截图
150
+ ```
151
+
152
+ ## License
153
+
154
+ MIT
package/RELEASE.md ADDED
@@ -0,0 +1,62 @@
1
+ # 发布规范(自动发布 · Tag 触发)
2
+
3
+ 本项目**不手动 `npm publish`**。发布唯一入口是**推送 `v*` tag**,由 GitHub Actions 自动完成。
4
+
5
+ ## 链路
6
+
7
+ ```
8
+ git push --follow-tags
9
+ │
10
+ ▼
11
+ GitHub Actions: .github/workflows/release.yml (触发: push tags: v*)
12
+ 1. 校验 tag 与 package.json 版本一致(不一致 → 失败)
13
+ 2. 语法检查 + 冒烟测试 + i18n 键一致性
14
+ 3. npm Trusted Publishing(OIDC)发布,附 provenance
15
+ - 版本已存在则跳过(幂等,可安全重跑)
16
+ 4. GitHub Release 正文 = CHANGELOG 当前版本条目
17
+ ```
18
+
19
+ CI(`.github/workflows/ci.yml`)在 push `main` / PR 时只跑检查(语法 + 冒烟 + i18n + `npm pack` 内容校验),**不会发布**。
20
+
21
+ ## CHANGELOG 与 Release 正文(强制)
22
+
23
+ - **每个版本必须在 `CHANGELOG.md` 有对应 `## <版本>` 条目**,缺失时 release workflow 直接失败(`scripts/release-notes.mjs`);
24
+ - GitHub Release 正文 = 自动从 CHANGELOG 抽取当前版本条目,不手写;
25
+ - 分类固定:`新增` / `变更` / `修复` / `移除` / `安全`(无内容的分类省略)。
26
+
27
+ ## 认证方式(OIDC,永不过期)
28
+
29
+ 使用 **npm Trusted Publishing(OIDC)**,已配置(2026-10-24):
30
+
31
+ | 项 | 值 |
32
+ |---|---|
33
+ | Organization or user | `PonyDevAI` |
34
+ | Repository | `dsh-phone` |
35
+ | Workflow filename | `release.yml` |
36
+ | 权限 | `publish`、`stage publish` |
37
+ | trust id | `9f7b6ffa-aa7a-4126-b527-27cfb56ad670` |
38
+
39
+ - **不需要** `NPM_TOKEN` secret、不需要 OTP、不会过期;
40
+ - 发布包自动获得 `dist.attestations.provenance`(SLSA v1);
41
+ - 首次发布 `0.1.0` 是本地网页授权 + OTP 完成的;从 `0.1.1` 起全部走 tag → Actions。
42
+
43
+ ## 标准发版步骤
44
+
45
+ ```bash
46
+ # 1. 更新 CHANGELOG.md(新增版本条目)与 package.json version
47
+ npm run check && npm run smoke
48
+ # 2. 提交并打 tag
49
+ git add -A && git commit -m "chore(release): vX.Y.Z"
50
+ git tag vX.Y.Z
51
+ git push --follow-tags
52
+ # 3. 验证
53
+ gh run watch --repo PonyDevAI/dsh-phone
54
+ npm view dsh-phone version
55
+ gh release view vX.Y.Z --repo PonyDevAI/dsh-phone
56
+ ```
57
+
58
+ ## 排障
59
+
60
+ - publish 步骤报 trusted publisher 错误:核对 repo / workflow 文件名 / environment 与 npm 设置完全一致;
61
+ - 版本已存在但 Release 没建:workflow 中 publish 会自动跳过,检查 CHANGELOG 是否缺当前版本条目;
62
+ - 需要临时救火时可在本地 `npm publish`(需要 2FA/OTP),事后仍以 tag 为唯一发版入口。
@@ -0,0 +1,9 @@
1
+ - insert:
2
+ - id: phone
3
+ name: "@ponydev/dsh-phone"
4
+ config:
5
+ adbPath: adb
6
+ pollMs: 700
7
+ streamTimeLimit: 180
8
+ streamBitRate: 6000000
9
+ streamSize: 540x1200