dsh-pad-kit 0.0.0-stage → 1.0.1

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.
@@ -0,0 +1,126 @@
1
+ # 让别人的 DSH 自己装这个插件(@ 一下就装)
2
+
3
+ > 这段是写给 **DSH 里的 agent** 看的。用户把压缩包拖进对话、或者说一句「按 AGENT-INSTALL.md 装这个插件」,agent 照下面做即可。
4
+
5
+ ## 用户要说的那一句话(模板)
6
+
7
+ ```
8
+ 把附件这个 dsh-pad-kit.zip 装成 DSH 插件,装完告诉我怎么重启
9
+ ```
10
+
11
+ 或者(已经解压到本地时):
12
+
13
+ ```
14
+ 把 D:\下载\dsh-pad-kit 装成 DSH 插件
15
+ ```
16
+
17
+ ---
18
+
19
+ ## Agent 执行清单
20
+
21
+ 前提:DSH 的 home 是 `%USERPROFILE%\.dsh`(下文记作 `<dsh>`),profile 是 `web`。
22
+ 写入 `<dsh>` 属于工作区之外,需要提权 —— 用户会看到一次确认弹窗,点允许即可。
23
+
24
+ ### 1. 解压 / 定位插件目录
25
+
26
+ 压缩包里应当有这些条目(缺任何一个都不能装):
27
+
28
+ ```
29
+ package.json
30
+ cordis.patch.yml
31
+ lib\plugin.js
32
+ dsh-android-kit.tgz
33
+ kit\termux.apk
34
+ install-windows.ps1
35
+ ```
36
+
37
+ 解压到一个临时目录,记作 `<src>`。
38
+
39
+ ### 2. 复制到插件目录
40
+
41
+ ```
42
+ <dsh>\plugins\dsh-pad-kit\
43
+ ```
44
+
45
+ 目标已存在时不要整个覆盖,只覆盖上面那几个关键文件(避免把用户的 `tablets.json` 状态搞乱 —— 状态实际不在插件目录里,但仍建议保守)。
46
+
47
+ ### 3. 建 junction(让 Node 按包名解析)
48
+
49
+ ```
50
+ cmd /c mklink /J "<dsh>\profiles\web\node_modules\@local\dsh-pad-kit" "<dsh>\plugins\dsh-pad-kit"
51
+ ```
52
+
53
+ macOS / Linux 用 `ln -s`。
54
+
55
+ ### 4. 在 profile 里登记依赖
56
+
57
+ 编辑 `<dsh>\profiles\web\package.json`:
58
+
59
+ ```json
60
+ "dependencies": {
61
+ "@local/dsh-pad-kit": "link:C:/Users/<用户>/.dsh/plugins/dsh-pad-kit"
62
+ }
63
+ ```
64
+
65
+ - 先备份成 `package.json.bak-pad-kit`
66
+ - 路径用正斜杠
67
+ - **保持 UTF-8 无 BOM**
68
+ - 不要用 `Set-Content`(会把中文写坏),用 `[System.IO.File]::WriteAllText($p, $json, (New-Object System.Text.UTF8Encoding($false)))`
69
+
70
+ ### 5. 追加激活行
71
+
72
+ 在 `<dsh>\profiles\web\cordis.patch.yml` 末尾追加(先备份成 `.bak-pad-kit`):
73
+
74
+ ```yaml
75
+ # dsh-pad-kit:平板上跑 DSH + 电脑 SSH 远程管理
76
+ - insert:
77
+ - id: pad-kit
78
+ name: '@local/dsh-pad-kit'
79
+ config:
80
+ httpPort: 8090
81
+ apkName: termux.apk
82
+ timeoutMs: 120000
83
+ ```
84
+
85
+ 幂等:文件里已经有 `- id: pad-kit` 就不要重复追加。
86
+
87
+ ### 6. 校验(不重启也能查)
88
+
89
+ ```powershell
90
+ node --check "<dsh>\plugins\dsh-pad-kit\lib\plugin.js"
91
+ node --input-type=module -e "const m = await import('file:///<dsh>/plugins/dsh-pad-kit/lib/plugin.js'); console.log(m.name, Object.keys(m));"
92
+ ```
93
+
94
+ 应当打印 `pad-kit`,且导出里包含 `renderPage`、`renderBootstrap`、`renderInstallScript`。
95
+
96
+ ### 7. 告诉用户重启
97
+
98
+ **新增插件行不会热加载**,必须重启 DSH。重启后工具列表里会出现 7 个 `tablet_*` 工具:
99
+
100
+ ```
101
+ tablet_install_page tablet_bootstrap tablet_targets tablet_kit_status
102
+ tablet_kit_setup tablet_kit_url tablet_kit_apk tablet_info
103
+ tablet_sh tablet_ls tablet_read tablet_write
104
+ tablet_pull tablet_push tablet_install_apk tablet_launch
105
+ tablet_wake
106
+ ```
107
+
108
+ ---
109
+
110
+ ## 装完怎么用(给用户看的三句话)
111
+
112
+ 1. 在 DSH 里调用 `tablet_install_page`,拿到一个 `http://<电脑IP>:8090/` 地址
113
+ 2. 平板上打开这个地址,按页面走(没有 Termux 就下 APK,有就直接粘一行命令)
114
+ 3. 装完平板会打印一个网址,用平板自己的浏览器打开就是 DSH Web
115
+
116
+ ---
117
+
118
+ ## 常见失败
119
+
120
+ | 现象 | 原因 | 处理 |
121
+ |---|---|---|
122
+ | 提权被拒 | 沙箱不允许写 `%USERPROFILE%\.dsh` | 重新跑一次并点允许;或手动把 `<src>` 拷到 `<dsh>\plugins\dsh-pad-kit` |
123
+ | 找不到 `profiles\web` | DSH 从没启动过 | 先启动一次 DSH(会生成 profile),再装 |
124
+ | 重启后没有 `tablet_*` | 激活行没写进去 / 依赖没登记 | 检查 `cordis.patch.yml` 有没有 `- id: pad-kit`,`package.json` 有没有 `@local/dsh-pad-kit` |
125
+ | 工具报「当前 DSH 版本不支持」 | 宿主 DSH 低于 `0.1.7-rc.2` | 升级 DSH 后重启 |
126
+ | `node --check` 报 `Invalid or unexpected token` | 文件被按 GBK 重写坏了 | 从解压目录重新复制 `lib\plugin.js`,不要用 `Set-Content` 改它 |
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 LongSiQi
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,343 @@
1
- # Temporary Holding Version
1
+ # dsh-pad-kit
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
+ **在安卓平板上本地运行 DeepSeek Harness(DSH)**,用平板自己的浏览器打开。
4
+
5
+ 它操作的是平板自己的文件、应用和命令 —— 不是在平板上远程操控电脑上的文件。
6
+
7
+ ## 装这个插件
8
+
9
+ DSH 里 **插件 → 添加插件**,输入框里填下面任意一种,点「安装」,装完点「立即启用」:
10
+
11
+ | 来源 | 填什么 |
12
+ |---|---|
13
+ | npm 包 | `dsh-pad-kit` |
14
+ | GitHub | `github:longsiqi-123/dsh-pad-kit` |
15
+ | GitHub(完整地址) | `https://github.com/longsiqi-123/dsh-pad-kit` |
16
+ | 本地压缩包 | `…\dist\dsh-pad-kit.zip` 的绝对路径 |
17
+ | 本地目录 | 解压后那个文件夹的绝对路径 |
18
+
19
+ 命令行等价:
20
+
21
+ ```bash
22
+ dsh plugin add dsh-pad-kit
23
+ dsh plugin add github:longsiqi-123/dsh-pad-kit
24
+ ```
25
+
26
+ 装完**需要重启一次 DSH**,`tablet_*` 这 7 个工具才会出现在工具列表里(新增插件行不热加载)。
27
+
28
+ ## 一、它是什么
29
+
30
+ | 谁 | 得到什么 |
31
+ |---|---|
32
+ | **平板** | 平板浏览器里的 **Web 网页**,打开就是 DSH 本体,重启后照样能用 |
33
+ | **电脑** | DSH 里多出 7 个 `tablet_*` 工具,负责安装与状态检查 |
34
+ | 安装方式 | 局域网私有部署,安装页形如 `http://<电脑IP>:8090/`(同一 Wi-Fi 内有效,不是公网网址) |
35
+
36
+ 全程不用 adb、不用 root、不用数据线。电脑只是安装工,装完关掉也不影响平板使用。
37
+
38
+ ## 二、平板上怎么用
39
+
40
+ 1. 平板浏览器打开那个 **Web 网页**,收藏书签或加到桌面
41
+ 2. 就是完整的 DSH Web 界面:新会话、插件、工作区都跑在平板本地
42
+ 3. 平板重启后入口不变,自动跳到当次有效地址,不用重新找
43
+
44
+ 打不开就是平板上的服务没起来,电脑侧跑一次 `tablet_kit_setup`。
45
+
46
+ ---
47
+
48
+ ## 三、为什么需要它(三个硬问题)
49
+
50
+ DSH 官方没有 Android 版,唯一能在平板本地跑的是 CLI + Web GUI(`npm i -g @deepseek-ai/dsh`)。
51
+ 但直接装上有三处硬伤,本套件逐一补掉:
52
+
53
+ | # | 坑 | 直接装会看到 | 这里的处理 |
54
+ |---|---|---|---|
55
+ | 1 | 原生绑定没有 `android-arm64` 预编译包 | `dsh: host preparation failed: No usable native binding found for node-addon-require-builtin-android-arm64 (auto)` | 在平板现场用 `node-gyp` 编译 `require_builtin.node`(`narb_product=require-builtin`),包装成可选包塞进 dsh 的 `node_modules` |
56
+ | 2 | Android 没有 `flock` | 每轮对话报 `本轮运行失败 flock is not supported on android-arm64` | 给 `@deepseek-ai/node-addon-system/lib/flock.js` 放行 `android`,单实例运行直接跳过加锁 |
57
+ | 3 | Android 禁硬链接 | `EACCES: permission denied, link '...jsonl.zstd.tmp' -> '...jsonl.zstd'` | 会话持久化里的 `link()` 改成「失败就 `copyFile`」,保留原有的不覆盖语义 |
58
+
59
+ 三个补丁都是**锚点匹配 + 幂等**:锚点对不上就退出、不写文件;已打过会打印「跳过」。所以反复执行无害。
60
+
61
+ ---
62
+
63
+ ## 四、前提条件
64
+
65
+ | # | 条件 | 怎么检查 | 不满足会怎样 |
66
+ |---|---|---|---|
67
+ | 1 | 平板是 **arm64/aarch64**、Android 7+ | Termux 里 `getprop ro.product.cpu.abi` → `arm64-v8a` | node 或编译产物跑不起来 |
68
+ | 2 | 电脑和平板**在同一 Wi-Fi、同一网段、双向能连 TCP**(未开 AP 隔离/访客网络) | 平板浏览器能打开 `http://<电脑IP>:8090/`;装完后电脑能 `ssh -p 8022` 到平板 | 平板连不上电脑→装不上;电脑连不上平板→远程工具全挂 |
69
+ | 3 | 电脑防火墙放行 **TCP 8090**(安装期间) | `curl` 一直转圈就是没放行 | 命令卡住或直接失败 |
70
+ | 4 | 平板允许**安装未知来源应用** | 设置 → 应用 → 特殊权限 | Termux 装不上,后面全断 |
71
+ | 5 | 平板能访问 **npm** | Termux 里 `curl -I https://registry.npmjs.org` | 装 dsh 失败 |
72
+ | 6 | 平板约 **1.5 GB** 空闲空间 | `df -h /data` | 编译到一半 No space |
73
+ | 7 | 安装那 1~3 分钟里**平板不锁屏**、Termux 在前台 | — | Termux 被冻结,编译中断 |
74
+ | 8 | 电脑有 **OpenSSH 客户端** | `ssh -V`(Win10 1809+ 自带) | 远程工具全部不可用 |
75
+ | 9 | 电脑侧 DSH **重启过一次** | 工具列表里出现 `tablet_*` | 新增插件行不热加载,工具不会出现 |
76
+ | 10 | 电脑侧 DSH **≥ 0.1.7-rc.2**(要支持用户插件机制) | DSH 版本号;插件启动时会自检 | 所有 `tablet_*` 工具直接返回「当前 DSH 版本不支持」 |
77
+
78
+ > 第 10 条的细节:版本依次从 `DSH_VERSION` 环境变量、`process.argv` 上级目录的 `package.json` 里取,
79
+ > 都识别不到时**放行**(避免误伤)。低于门槛时不会装到一半才失败,而是一开始就给结论。
80
+ > 只有第 7 条是"必须有人在平板前面"的。整个流程里人工只出现两次:**第一次装 Termux 并粘一行命令**、**Termux 被冻结后切回前台**。
81
+
82
+ ---
83
+
84
+ ## 五、连接是怎么建立的(不用数据线、不用 adb)
85
+
86
+ 全程没有任何"直连"要求,靠的是**同一局域网内的三段访问**:
87
+
88
+ ```
89
+ 平板浏览器 ──① 打开安装页 ──▶ 电脑:8090 (平板主动,HTTP)
90
+ 平板 Termux ──② 报到 ───────▶ 电脑:8090 /register (平板主动,HTTP)
91
+ 电脑 DSH ───③ SSH 运维 ────▶ 平板:8022 (电脑主动,SSH)
92
+ ```
93
+
94
+ - ① ② 是**平板连电脑**:安装阶段的前置条件,平板必须能打开 `http://<电脑IP>:8090/`
95
+ - ③ 是**电脑连平板**:安装脚本会在平板上起 `sshd`(8022),之后大多数套件工具走这条
96
+ - 三段都只要求「同一网段 + TCP 能通」:不用数据线、不用 adb、不用 root、不用公网 IP
97
+
98
+ ### 怎么确认连接成立
99
+
100
+ ```bash
101
+ # ① 平板 → 电脑:平板浏览器打开 http://<电脑IP>:8090/ ,能看到安装页
102
+ # ② 报到:跑完那行 curl,电脑侧 tablet_targets 里冒出 u0_aXXX@<平板IP>:8022
103
+ # ③ 电脑 → 平板:ssh -p 8022 <termux用户>@<平板IP> echo ok → 打印 ok
104
+ ```
105
+
106
+ ### 连不上的三种典型原因
107
+
108
+ | 现象 | 原因 |
109
+ |---|---|
110
+ | 平板打不开 8090 | 不在同一 Wi-Fi;路由器开了 AP 隔离/访客网络;电脑防火墙拦了 8090 |
111
+ | 能开安装页但没报到 | 平板没跑那行 curl;或平板走的是蜂窝流量(与电脑不同网段) |
112
+ | 报到了但 ssh 连不上 | Termux 被系统冻结(切前台 / `termux-wake-lock`);或平板 DHCP 换了 IP |
113
+
114
+ ## 六、平板端:安装与开机自启
115
+
116
+ ### 安装页会自动分岔
117
+
118
+ 打开 `http://<电脑IP>:8090/`,页面第一屏就问「平板有没有 Termux」:
119
+
120
+ | 平板状态 | 你要做的 | 之后 |
121
+ |---|---|---|
122
+ | **没有** Termux | 点「下载 Termux APK」→ 装 → 打开 | 再走下面「已有」那一行 |
123
+ | **已有** Termux | 在 Termux 里粘一行 | `curl -fL http://<电脑IP>:8090/bootstrap.sh \| bash` |
124
+
125
+ 那一行命令进 Termux 后**先自检、再决定装什么**,任意一项不过就直接给结论:
126
+
127
+ | 自检项 | 不通过时做什么 |
128
+ |---|---|
129
+ | 是否在 Termux 里(`$PREFIX` + `/data/data/com.termux`) | 退出,提示先装 Termux |
130
+ | `pkg` 命令是否存在 | 判定为应用商店旧版(0.101),要求换 F-Droid/GitHub 版 |
131
+ | 架构是 arm64 | 非 arm64 直接退出 |
132
+ | Android ≥ 7.0(SDK 24) | 退出并说明 |
133
+ | `/data` 剩余 ≥ 1.5 GB | 退出并说出还差多少 |
134
+ | `curl` 能跑 | 自动 `apt update && apt full-upgrade` 修 libssl 符号;仍坏才退出 |
135
+ | 能连通电脑 `8090/healthz` | 退出,列出三个常见原因(不同 Wi-Fi / AP 隔离 / 防火墙) |
136
+ | `sshd` 存在 | 自动 `pkg install openssh`;缺包就切官方源重试 |
137
+
138
+ 八项全过才动手装 DSH 本体 —— 环境不对会在几秒内给结论,不会装到一半才失败。
139
+
140
+ ### 开机自启(Termux:Boot)
141
+
142
+ 安装脚本会把开机脚本写好:
143
+
144
+ ```
145
+ ~/.termux/boot/start-dsh.sh # wakelock → sleep 8 → bash ~/start-dsh.sh → 日志进 ~/dsh-boot.log
146
+ ```
147
+
148
+ 但 **Android 只认装了 Termux:Boot 应用的开机脚本**,否则这个目录没人读。所以:
149
+
150
+ | 状态 | 你要做的 |
151
+ |---|---|
152
+ | 还没装 Termux:Boot | 打开安装页点「下载 Termux:Boot APK(0.8.1)」,装完打开它一次 |
153
+ | 已装 | 不用管,重启平板后 DSH 会自己起来 |
154
+ | 验证 | 重启后平板浏览器打开那个网页地址,能开就是成功;不行看 `cat ~/dsh-boot.log` |
155
+
156
+ 装 Termux:Boot 不需要 root,也不改任何系统设置 —— 它只是把自己注册成开机广播接收器。
157
+
158
+ ---
159
+
160
+ ## 七、全流程时间线
161
+
162
+ ```
163
+ T0 电脑:调 tablet_install_page
164
+ → 插件生成 SSH 密钥(%USERPROFILE%\.dsh\pad-kit\id_ed25519,没有才生成)
165
+ → 起局域网安装页,返回 http://172.24.x.x:8090/
166
+
167
+ T1 平板:浏览器打开该地址(页面上有二维码)
168
+ → 「下载 Termux APK」→ 允许未知来源 → 安装 Termux ← 人工动作 1
169
+
170
+ T2 平板:打开 Termux,粘贴页面上那一行:
171
+ curl -fL http://172.24.x.x:8090/bootstrap.sh | bash ← 人工动作 2
172
+
173
+ T3 平板自动(约 10 秒)
174
+ ├─ pkg install openssh curl
175
+ ├─ 把电脑公钥写进 ~/.ssh/authorized_keys
176
+ ├─ ssh-keygen -A ;nohup sshd(监听 8022)
177
+ └─ curl /register?user=u0_aXXX&port=8022 → 向电脑报到
178
+
179
+ T4 电脑:插件收到报到,写 ~/.dsh/pad-kit/tablets.json
180
+ 到这里「通道 + 认证」都通了
181
+
182
+ T5 平板自动(1~3 分钟,最容易失败的一段)
183
+ ├─ pkg install nodejs clang make python3 binutils
184
+ ├─ npm i -g @deepseek-ai/dsh --ignore-scripts
185
+ ├─ 编译 require_builtin.node 并装成 android-arm64 可选包
186
+ ├─ 补丁 1:放行 android 的 flock
187
+ ├─ 补丁 2:硬链接失败降级 copyFile
188
+ └─ 起服务与固定入口,打印 FIXED_URL
189
+
190
+ T6 电脑:tablet_targets → u0_aXXX@172.24.x.x:8022
191
+ tablet_kit_status → NODE / DSH / BINDING / FLOCK=patched / LINK=patched / HOME_3081=302
192
+
193
+ T7 平板:用平板自己的浏览器打开那个 Web 网页 → 就是平板上的 DSH 本体
194
+ ```
195
+
196
+ ---
197
+
198
+ ## 八、每步谁做、失败怎么办
199
+
200
+ | 步骤 | 谁做 | 耗时 | 失败信号 | 处理 |
201
+ |---|---|---|---|---|
202
+ | 起安装页 | 插件(一条命令) | 1 秒 | `端口 8090 已被占用` | 改配置 `httpPort` 换端口 |
203
+ | 装 Termux | **人** | 1 分钟 | 提示"禁止安装" | 开未知来源权限 |
204
+ | 粘那一行 | **人** | 5 秒 | `curl: not found` | Termux 没装好,重来 |
205
+ | 建 SSH 通道 | 平板自动 | 10 秒 | 报到失败 | 仍可用 `tablet_targets` 手动登记 `host/user/port` |
206
+ | 装 node + dsh | 平板自动 | 1~2 分钟 | `E: Unable to locate package` | 换 termux 源(见故障排查) |
207
+ | 编译原生绑定 | 平板自动 | 1~2 分钟 | `CMake does not seem to be available` | `pkg install clang make python3` |
208
+ | 打补丁 | 平板自动 | 2 秒 | 锚点不匹配 → 直接退出不写文件 | dsh 升级后重跑 `tablet_kit_setup` |
209
+ | 起服务 | 平板自动 | 3 秒 | 网页返回 503 | `tablet_kit_setup` 重跑 |
210
+ | 日常控制 | 电脑(工具) | 毫秒级 | `banner exchange` 超时 | `tablet_wake`,或把 Termux 切前台 |
211
+
212
+ ---
213
+
214
+ ## 九、工具(本包 7 个)
215
+
216
+ ### 套件工具(`pad-kit`,管安装与状态)
217
+
218
+ | 工具 | 作用 |
219
+ |---|---|
220
+ | `tablet_install_page` | 起局域网安装页,返回可发给平板的地址 |
221
+ | `tablet_bootstrap` | 输出 `bootstrap.sh`;`sshonly: true` 只建 SSH 通道、不装 DSH |
222
+ | `tablet_targets` | 列出已报到平板;也能手动登记 |
223
+ | `tablet_kit_status` | 一条命令看全套健康度(版本 / 绑定 / 补丁 / 网页入口 / token) |
224
+ | `tablet_kit_setup` | 远程重跑安装脚本(升级、修复) |
225
+ | `tablet_kit_url` | 取固定入口 + token 直连地址 |
226
+ | `tablet_kit_apk` | Termux APK 的局域网下载地址 |
227
+
228
+ ### 另需单独安装的 `dsh-tablet`(本仓库不含,管日常操作)
229
+
230
+ | 工具 | 作用 |
231
+ |---|---|
232
+ | `tablet_sh` | **主力**:执行任意 shell 命令 |
233
+ | `tablet_info` | 型号、Android 版本、ABI、内存、存储、运行时长 |
234
+ | `tablet_ls` / `tablet_read` / `tablet_write` | 列目录、读文件、写文件 |
235
+ | `tablet_push` / `tablet_pull` | 电脑 ⇄ 平板传文件(scp) |
236
+ | `tablet_install_apk` | 推 APK 并打开安装界面(**最后一下"安装"要人点**) |
237
+ | `tablet_launch` | 起 App(解析主 Activity 后 `am start`) |
238
+ | `tablet_wake` | `termux-wake-lock`,防冻结 |
239
+
240
+ **目标解析顺序**:调用参数 → 配置 `sshHost/sshUser` → 最近一次报到。第一次之后基本不用传参数。
241
+
242
+ ---
243
+
244
+ ## 十、做不到的事
245
+
246
+ | 想做的 | 能否 | 原因 |
247
+ |---|---|---|
248
+ | 看平板屏幕 | ❌ | Termux 无 `screencap`,无 adb,无 root |
249
+ | 模拟点击/滑动 | ❌ | 无 `input`,无 root,无 `termux-api` |
250
+ | 静默装 APK | ❌ | Android 要求用户点确认,无 root 没有例外 |
251
+ | 后台自动拉起浏览器 | ❌ | Android 10+ 禁后台启动 Activity,`am start` 静默失败(退出码仍 0) |
252
+ | 操作别的 App 的内部按钮 | ❌ | 只能启动,不能操控 UI |
253
+
254
+ 结论:电脑侧这套工具是**命令行级远程控制 + 文件通道**,不是远程桌面。
255
+
256
+ 要分清两个界面,别混:
257
+
258
+ | 界面 | 跑在哪 | 操作的是谁的东西 |
259
+ |---|---|---|
260
+ | **平板浏览器里的 DSH**(装完就有,主角) | 平板本机 | **平板自己的**文件、目录、命令 —— 这才是本套件的目的 |
261
+ | 电脑 DSH 里的 `tablet_*` 工具(配角) | 电脑 | 通过 SSH 去动平板;只是安装和运维通道 |
262
+
263
+ **不会发生的事**:平板的 Web 界面读不到电脑的 `C:`、`D:` 盘,所有路径都在平板内;电脑关机后平板浏览器照样能用。
264
+
265
+ ---
266
+
267
+ ## 十一、已知问题与设计取舍
268
+
269
+ 这些是刻意记下来的,不是待办清单的隐饰:
270
+
271
+ | 问题 | 现状 | 建议 |
272
+ |---|---|---|
273
+ | **报到是"最近一次优先"** | 同网段任何设备都能 `POST /register` 把自己登记成候选目标 | 只用可信网络;需要确定性时在配置里写死 `sshHost/sshUser` |
274
+ | **平板 IP 会变**(DHCP) | 变 IP 后旧记录连不上 | 重跑一次 bootstrap(会重新报到),或 `tablet_targets` 手动改 |
275
+ | **多台平板** | 只按最近报到选一台 | 显式传 `host`/`user`,或用配置固定 |
276
+ | **仅 IPv6 的网络** | 未适配(`/register` 只去掉 `::ffff:` 前缀,SSH 连 IPv6 需要方括号) | 用有 IPv4 的网络 |
277
+ | **Termux 签名冲突** | 平板上若已有 F-Droid 版 Termux,装我们这份 GitHub debug 版会签名冲突 | 先卸载旧版(会丢数据),或直接沿用旧版 Termux——`bootstrap.sh` 不挑来源 |
278
+ | **Google Play 版 Termux** | 早已停止维护,装不上新版包 | 不要用 |
279
+ | **npm 慢** | `setup.sh` 用默认源 | 平板能访问 `registry.npmmirror.com` 的话,可先 `npm config set registry https://registry.npmmirror.com` 再跑 |
280
+ | **dsh 升级后补丁失效** | `npm i -g` 会覆盖被补丁的文件 | 升级后跑一次 `tablet_kit_setup`;`tablet_kit_status` 会显示 `FLOCK/LINK=failed` 提示 |
281
+ | **node 大版本变化** | 编译产物按 napi-v9 打,跨大版本可能需重编 | 重跑 `tablet_kit_setup` |
282
+ | **安装期间锁屏** | 编译中途被冻结 → 半成品 | 安装时别锁屏,Termux 留前台 |
283
+ | **Windows 缺 ssh 客户端** | `ssh.exe` 不存在时报 `ssh 不存在` | 设置 → 应用 → 可选功能 → 添加 OpenSSH 客户端 |
284
+ | **macOS/Linux 路径** | 已按平台取 `ssh`/`ssh-keygen` | 无 |
285
+ | **安装页常驻** | 装完仍在监听 8090 | 可接受;不想开就在配置里换端口或重启 DSH |
286
+
287
+ ---
288
+
289
+ ## 十二、故障排查
290
+
291
+ | 现象 | 原因 | 处理 |
292
+ |---|---|---|
293
+ | `还未认到平板` / 工具提示先装 | 平板没报到过 | 先 `tablet_install_page`,平板跑完那行命令 |
294
+ | `连不上 …: Termux 的 sshd 没应答` | Termux 被冻结 | 平板:`termux-wake-lock`;设置 → 电池 → 后台耗电管理 → Termux → 不受限制 |
295
+ | `SSH 公钥被拒绝` | 公钥没写进去 | 重跑 bootstrap,或把 `~/.dsh/pad-kit/id_ed25519.pub` 追加到平板 `~/.ssh/authorized_keys` |
296
+ | `E: Unable to locate package openssh` | pkg 镜像缺包 | `echo "deb https://packages.termux.dev/apt/termux-main stable main" > $PREFIX/etc/apt/sources.list && apt update` |
297
+ | `CMake does not seem to be available` | 缺编译工具链 | `pkg install -y clang make python3 binutils` |
298
+ | `flock is not supported` 又出现 | 补丁被 npm 覆盖 | `tablet_kit_setup` |
299
+ | 网页返回 503 | 平板上 dsh 没在跑 | `tablet_sh "bash ~/start-dsh.sh"` |
300
+ | 平板浏览器打不开安装页 | 不同网段 / AP 隔离 / 防火墙 | 检查同 Wi-Fi、放行 8090 |
301
+ | 工具列表里没有 `tablet_*` | 新增插件行不热加载 | 重启 DSH |
302
+
303
+ ---
304
+
305
+ ## 十三、安全与卸载
306
+
307
+ **安全**:安装页会把**公钥**暴露给同网段(公钥本身无害),但 `/register` 接受任意设备的报到,等于"最近报到的设备会被当作目标"。在不可信网络里务必显式配 `sshHost`;平板侧 sshd 只允许公钥登录,不要打开密码登录。
308
+
309
+ **卸载**
310
+
311
+ 平板上:
312
+
313
+ ```bash
314
+ pkill -f dsh
315
+ rm -rf ~/dsh-android-kit ~/dsh-home.js ~/start-dsh.sh ~/dshpad ~/.dsh-kit
316
+ npm rm -g @deepseek-ai/dsh
317
+ ```
318
+
319
+ 电脑上:删掉 `cordis.patch.yml` 里的 `- insert: id: pad-kit` 那段、删掉 `package.json` 里的 `@local/dsh-pad-kit`、删掉 `~/.dsh/plugins/dsh-pad-kit`,重启 DSH。
320
+
321
+ ---
322
+
323
+ ## 十四、目录结构
324
+
325
+ ```
326
+ dsh-pad-kit/
327
+ ├── install-windows.ps1 Windows 一键安装(幂等)
328
+ ├── install-unix.sh macOS/Linux 一键安装(幂等)
329
+ ├── installer-page.js 不装插件也能用的独立安装页(node installer-page.js)
330
+ ├── lib/plugin.js 插件本体(7 个工具 + 局域网安装页)
331
+ ├── kit/ 推给平板的脚本
332
+ │ ├── setup.sh 平板侧一键脚本(6 步)
333
+ │ ├── install-addon.sh 安装编译出的原生绑定
334
+ │ ├── patch-flock.js 补丁 1
335
+ │ ├── patch-link.js 补丁 2
336
+ │ ├── narb-build.tgz 原生绑定源码包(binding.gyp 已设 require-builtin)
337
+ │ ├── dsh-home.js 固定入口跳转页
338
+ │ ├── start-dsh.sh 启动器(含 wake-lock)
339
+ │ └── termux.apk Termux(arm64,GitHub debug 版,35,106,607 字节)
340
+ ├── dsh-android-kit.tgz 上面 kit/ 的打包(不含 APK,避免重复)
341
+ ├── package.json / cordis.patch.yml
342
+ └── README.md / 使用说明.md
343
+ ```
@@ -0,0 +1,9 @@
1
+ # pad-kit:在安卓平板上本地跑 DSH;电脑侧只负责安装与远程运维
2
+ # 挂在 profile 的 cordis.patch.yml 里即可;这里的 config 只留必要项,目标平板自动从报到的 tablets.json 解析
3
+ - insert:
4
+ - id: pad-kit
5
+ name: '@local/dsh-pad-kit'
6
+ config:
7
+ httpPort: 8090
8
+ apkName: termux.apk
9
+ timeoutMs: 120000
Binary file
@@ -0,0 +1,86 @@
1
+ #!/usr/bin/env bash
2
+ # dsh-pad-kit 电脑端安装器(macOS / Linux)
3
+ # 用法:
4
+ # bash install-unix.sh
5
+ # DSH_HOME=~/.dsh PROFILE=web bash install-unix.sh
6
+ # 作用:放插件 → 建软链 → 在 profile 登记依赖 → 追加激活行。幂等。
7
+ set -euo pipefail
8
+
9
+ PKG_NAME='@local/dsh-pad-kit'
10
+ PLUGIN_DIR_NAME='dsh-pad-kit'
11
+ SRC="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
12
+ DSH_HOME="${DSH_HOME:-$HOME/.dsh}"
13
+ PROFILE="${PROFILE:-web}"
14
+ PROFILE_DIR="$DSH_HOME/profiles/$PROFILE"
15
+ TARGET="$DSH_HOME/plugins/$PLUGIN_DIR_NAME"
16
+
17
+ say() { printf '%s\n' "$*"; }
18
+ fail() { printf '错误:%s\n' "$*" >&2; exit 1; }
19
+
20
+ say "==> 1/5 检查来源目录"
21
+ for f in package.json cordis.patch.yml lib/plugin.js dsh-android-kit.tgz kit/termux.apk; do
22
+ [ -f "$SRC/$f" ] || fail "来源里缺少 $f(请在解压后的 $PLUGIN_DIR_NAME 目录里运行本脚本)"
23
+ done
24
+ say " 来源 OK:$SRC"
25
+
26
+ say "==> 2/5 安装到 $TARGET"
27
+ mkdir -p "$DSH_HOME/plugins"
28
+ if [ -d "$TARGET" ]; then
29
+ for f in package.json cordis.patch.yml dsh-android-kit.tgz; do cp -f "$SRC/$f" "$TARGET/$f"; done
30
+ mkdir -p "$TARGET/lib" "$TARGET/kit"
31
+ cp -f "$SRC/lib/"*.js "$TARGET/lib/" 2>/dev/null || true
32
+ cp -f "$SRC/kit/"* "$TARGET/kit/" 2>/dev/null || true
33
+ say " 已存在,已就地更新关键文件"
34
+ else
35
+ cp -R "$SRC" "$TARGET"
36
+ say " 已复制"
37
+ fi
38
+
39
+ say "==> 3/5 建软链(让 node 能按包名解析)"
40
+ [ -d "$PROFILE_DIR" ] || fail "找不到 profile 目录:$PROFILE_DIR(DSH 至少启动过一次吗?)"
41
+ mkdir -p "$PROFILE_DIR/node_modules/@local"
42
+ rm -f "$PROFILE_DIR/node_modules/@local/$PLUGIN_DIR_NAME"
43
+ ln -s "$TARGET" "$PROFILE_DIR/node_modules/@local/$PLUGIN_DIR_NAME"
44
+ say " OK:$PROFILE_DIR/node_modules/@local/$PLUGIN_DIR_NAME"
45
+
46
+ say "==> 4/5 在 profile package.json 里登记依赖"
47
+ PKG_FILE="$PROFILE_DIR/package.json"
48
+ [ -f "$PKG_FILE" ] || fail "找不到 $PKG_FILE"
49
+ cp -f "$PKG_FILE" "$PKG_FILE.bak-pad-kit"
50
+ node -e '
51
+ const fs = require("fs");
52
+ const [file, name, value] = process.argv.slice(1);
53
+ const json = JSON.parse(fs.readFileSync(file, "utf8"));
54
+ json.dependencies = json.dependencies || {};
55
+ json.dependencies[name] = value;
56
+ fs.writeFileSync(file, JSON.stringify(json, null, 2) + "\n");
57
+ ' "$PKG_FILE" "$PKG_NAME" "link:$TARGET"
58
+ say " OK(备份:$PKG_FILE.bak-pad-kit)"
59
+
60
+ say "==> 5/5 在 cordis.patch.yml 追加激活行"
61
+ PATCH_FILE="$PROFILE_DIR/cordis.patch.yml"
62
+ [ -f "$PATCH_FILE" ] || fail "找不到 $PATCH_FILE"
63
+ cp -f "$PATCH_FILE" "$PATCH_FILE.bak-pad-kit"
64
+ if grep -qE '^[[:space:]]*-[[:space:]]*id:[[:space:]]*pad-kit[[:space:]]*$' "$PATCH_FILE"; then
65
+ say " 已存在 pad-kit 行,跳过"
66
+ else
67
+ cat >> "$PATCH_FILE" <<EOF
68
+
69
+ # dsh-pad-kit:平板上跑 DSH + 电脑 SSH 远程管理
70
+ - insert:
71
+ - id: pad-kit
72
+ name: '$PKG_NAME'
73
+ config:
74
+ httpPort: 8090
75
+ apkName: termux.apk
76
+ timeoutMs: 120000
77
+ EOF
78
+ say " 已追加"
79
+ fi
80
+
81
+ say ""
82
+ say "完成。还有两步是必须人工做的:"
83
+ say " 1) 重启 DSH(新增插件行不会热加载),重启后会出现 7 个 tablet_* 工具"
84
+ say " 2) 首次装平板时,防火墙放行一次 TCP 8090"
85
+ say ""
86
+ say "下一步:在 DSH 里调用 tablet_install_page,按返回的地址在平板上操作。"