- doc/API.md:补方法/路径标题,权限分层修正,新增 AI 控制台(/api/agent/*)、系统备份(/api/system/backup/*)、设备自动发现(/api/devices/discovery/*)、tap_text/summary/health/devices-apps 等整节端点,去 STF 残留 - doc/TASK_DEV.md:STF 时代描述清理;新增 §2.10 generic_steps(18 节点与必填/嵌套/静默跳过语义)、§2.11 自定义动作与单步测试、/api/jobs 盲存校验语义、resolve_serials/抢占语义、模板构造函数签名修正 - doc/DEPLOY.md:数据备份改为推荐「系统→数据备份」功能并说明重启生效目录,端口表 STF7100→MCP8033,补 start.sh 生产链路与 MCP_PLATFORM_PASS 同步,故障排查去 STF - doc/MCP.md:加「现状边界」(平台级任务 CRUD 未 MCP 化,规划见 AI_TASK_GEN §9),busy/平台会话说明,MCP_ALLOWED_SERIALS 语义纠正 - doc/MCP_DESIGN.md:加实现现状对照、错误码、独立容器改演进备选、里程碑状态、API 映射表按实现重写 - doc/ARCHITECTURE.md:Tab/子分栏/线程模型/数据表/蓝图表去 STF,补 device_discovery/agent/system_backup/经验巡检等 - doc/DEVELOPMENT.md:新增 §5.6「改动必须同步文档」红线、§2.3 配置键速查、蓝图化新增 API 流程、文档索引补登记 - doc/STF_REMOVAL.md:加历史记录状态横幅 - doc/AI_TASK_GEN.md:新增 AI 建任务设计稿(含 §9 需转 MCP 工具分层)
160 lines
9.5 KiB
Markdown
160 lines
9.5 KiB
Markdown
# 摘除 STF 迁移计划
|
||
|
||
> **状态:历史迁移记录(2026-08)。** 本文档为当时摘除 STF 的计划与进度,不代表现状。
|
||
> 截至 dev HEAD,代码已不再依赖 STF(`core/stf_client.py` 等已删,`config.py` STF 键标注废弃)。
|
||
> "当前实现"以 [doc/ARCHITECTURE.md](ARCHITECTURE.md) / [doc/DEVELOPMENT.md](DEVELOPMENT.md) 为准;
|
||
> 220 侧 STF 容器是否已 `docker stop` 见下文"待人工确认",需人工核实。
|
||
|
||
背景:全舰队设备为 Tailscale IP:5555 直连(adb key 沿用 STF 的),单实例部署。
|
||
STF 当前仅提供:occupy/release 互斥、present+ready 健康信号、设备池清单(与
|
||
220 的 connect_devices.sh 双维护)、remoteConnect 桥接(IP:port 已禁用)、网页看屏。
|
||
任务本体跑 uiautomator2(atx-agent),与 STF agent(jp.co.cyberagent.stf)无关。
|
||
|
||
摘除收益:告别 agent 安装死锁(MIUI 弹窗)、STF 容器重启风险、occupy 冲突悬空;
|
||
调度直接基于 adb 真实现状。风险点:多实例互斥(当前单实例无此需求,见阶段 3)。
|
||
|
||
## 已确认的决策(2026-08-17)
|
||
|
||
1. **设备清单放本地 SQLite**(data/users.db 新增 devices 表),220 的 connect_devices.sh
|
||
退役(其"每 5 分钟补连"职责由平台定时器 + SSH 兜底接管,或直接依赖 adb 重试)
|
||
2. **USB 有线设备保留支持**——当前舰队 0 台 USB(全 IP:5555),但能力要保留。
|
||
实施中发现 **220 的 adb 容器是 host 网络模式、5037 已监听所有网卡(含 Tailscale
|
||
100.100.10.1),无需改动 220 任何配置**。平台用 `adb -H 100.100.10.1 -P 5037`
|
||
和 `adbutils.AdbClient(host=..., port=5037)`(u2 底层)驱动远端 USB 设备;
|
||
本机 USB 设备照旧走本地 adb。已验证(阶段 2 完成)
|
||
3. **网页远程看屏**——原计划 ws-scrcpy **不在 npm 分发**(仅 GitHub,国内下载不可靠),
|
||
改**自建**:MJPEG 流(u2/atx-agent minicap 截图,~5fps,实测 0.19s/帧)+ u2 触控
|
||
(tap/swipe/key/text),管理页新子分栏,零新依赖(阶段 2 完成)
|
||
|
||
---
|
||
|
||
## 迁移难度与程度评估(2026-08-17)
|
||
|
||
### 代码量
|
||
|
||
| 项 | 量级 |
|
||
|---|---|
|
||
| 删除 `core/stf_client.py` 及引用 | ~250 行 |
|
||
| 新增 `core/device_pool.py`(清单+在线状态) | ~150 行 |
|
||
| 新增 devices 表 CRUD(复用现有 SQLite 基建) | ~120 行 |
|
||
| 修改 `task_manager`(resolve_serials/调度) | ~120 行 |
|
||
| 重写 `device_worker.STFDevice`(去 occupy/release) | ~80 行 |
|
||
| 修改 `web_server` 约 8 处调用点 | ~60 行 |
|
||
| 改造 `stf_device_mgmt`(SSH 脚本 → SQLite 管理) | ~100 行 |
|
||
| 前端 6 个文件文案/组件 | ~80 行 |
|
||
|
||
净效果:**-600 行 / +400 行 / 改 ~300 行**,集中在 task_manager 与 device_worker 两个核心文件。
|
||
|
||
### 分项难度(单人)
|
||
|
||
| 模块 | 难度 | 估算 | 关键点 |
|
||
|---|---|---|---|
|
||
| 设备池 SQLite + device_pool | 低 | 0.5-1 天 | 表结构 + CRUD + 管理页改数据源 |
|
||
| 调度替换 | 中 | 1-2 天 | 内存锁已有(`_running[serial]`),换数据源 + 对照验证 |
|
||
| web_server 调用点 | 低 | 0.5 天 | 8 处机械替换 |
|
||
| USB 支持 | 中 | 1 天 | 220 容器发端口 + adb_helper 支持 `-H/-P` + u2 远程 server;**需一台真机验证** |
|
||
| 网页看屏(ws-scrcpy) | 中 | 0.5-1 天 | 独立 Node 服务 + 内嵌页 + 认证联动 |
|
||
| 界面清理 | 低 | 0.5 天 | 文案/按钮/列 |
|
||
| 回归验证 | 中 | 1 天 | 调度/抢占/重试/离线跳过/亮屏/剪贴板/终端/看屏 |
|
||
|
||
**总计约 4-6 人日**,分 4 个 commit 阶段,每阶段可独立回滚。
|
||
|
||
### 风险
|
||
|
||
- **中**:USB 真机方案当前无设备可验,落地时需借一台 USB 设备
|
||
- **低**:离线跳过判定语义变化(STF 状态 → adb 状态),个别边界行为可能微变,需对照
|
||
- **低**:唯一动 220 的地方 = adb 容器发布 5037 端口(一次性)
|
||
- **低**:ws-scrcpy 是新增 Node 依赖,需评估其维护性与内存占用(可先试用再定)
|
||
|
||
### 实施顺序(调整后)
|
||
|
||
- **阶段 0**:SQLite 设备表 + `core/device_pool.py`(纯新增,STF 照常跑)
|
||
- **阶段 1**:调度/生命周期替换(STF 保留运行对照验证)
|
||
- **阶段 2**:USB 远程 adb server 打通 + ws-scrcpy 看屏部署
|
||
- **阶段 3**:界面清理 + 220 停 STF 容器(`docker stop` 不删,可回滚)
|
||
|
||
---
|
||
|
||
## 阶段 0:新建设备池模块(纯新增,不改行为)
|
||
|
||
新建 `core/device_pool.py` + devices 表(data/users.db):
|
||
|
||
- devices 表:serial(主键)、name、enabled、note、created_at;管理页增删改
|
||
- `list_configured()` — 读 SQLite devices 表(取代 SSH 读 220 脚本)
|
||
- `list_online()` — 本机 `adb devices` 中 state=device 的设备(实时)
|
||
- `is_online(serial)` — 在 list_online 中;可选 `adb -s get-state` 兜底(带超时)
|
||
- `list_ready()` — list_configured 与 list_online 的交集(取代 STF list_free_devices)
|
||
- 全模块不 connect/不 kill-server/disconnect,遵守既有红线
|
||
- 迁移脚本:现有 8 台设备从 STF 池导入 devices 表
|
||
|
||
产出:`core/device_pool.py` + `doc/ARCHITECTURE.md` 设备章节初稿 + 数据迁移脚本。
|
||
|
||
## 阶段 1:替换调度与生命周期(STF 保留运行,可对照验证)
|
||
|
||
| 位置 | 现状 | 改为 |
|
||
|---|---|---|
|
||
| `task_manager.resolve_serials` (145-183) | `stf.list_free_devices()` / `list_all_devices()` | `device_pool.list_ready()`;preempt 模式 = 全部 list_online |
|
||
| `resolve_serials` skip_offline 过滤 (166-183) | STF present/ready 判定 | `device_pool.is_online()`;跳过原因文案"离线/未连接" |
|
||
| `device_worker.STFDevice.acquire` (45-70) | `stf.occupy()` + 直连/桥接 | 去掉 occupy(互斥由 `_running[serial]` 负责);**USB 桥接保留到阶段 2**(避免迁移期 USB 断档,阶段 2 换成 220 adb server);保留 adb_connect 重试 + 2s 等待 |
|
||
| `STFDevice.release` (78-93) | `stf.release()` | 置空(仅保留 USB 隧道断开) |
|
||
| `STFDevice._pick_free` (72-76) | `list_free_devices` | `device_pool.list_ready()` |
|
||
| `_ForegroundScanner` (234-386) | `list_all_devices` / `list_my_devices` / remote_connect | `device_pool.list_online()`;桥接分支删除 |
|
||
| `web_server.api_device_screen_all` (646) | STF present 列表 | `device_pool.list_online()` |
|
||
| `web_server` 设备列表 (924 / 1011 / 1079) | STF 池合并 | SQLite devices 表 + 本地 adb(`_merged_device_list` 改数据源,保留 stf_not_ready 状态的等价物"未连接") |
|
||
| `web_server.api_release` (740) / 启动清理 (1581) | release_all_mine | 删除或改为清理本实例 `_running` 状态(重启本就清零) |
|
||
|
||
验证清单(阶段 1 完成后全跑一遍):
|
||
- [ ] 任务调度(serial/group/all 三种模式)+ 抢占/归还 + 重试 + 离线跳过
|
||
- [ ] 一键亮屏/息屏、剪贴板注入、应用版本查询、维护终端设备列表
|
||
- [ ] 前台 App 扫描
|
||
- [ ] 对照 STF 状态确认无行为差异
|
||
|
||
## 阶段 2:USB 打通 + 网页看屏(阶段 1 稳定运行 ≥ 3 天后)
|
||
|
||
- **USB 远程 adb server**:
|
||
- 220 侧一次性改动:adb 容器发布 5037 端口(`docker run -p 5037:5037` 或 iptables),
|
||
Tailscale 可达
|
||
- `core/adb_helper._adb` 支持 `-H <220-tailscale-ip> -P 5037`(仅 USB 序列号设备)
|
||
- u2 连接:USB 设备走 `adbutils.Adb(host=220_ip, port=5037)` → `u2.Device(dev)`
|
||
(已验证 u2 3.7.0 底层 adbutils 支持远程 adb server)
|
||
- 本机 USB 设备照旧走本地 adb,零改动
|
||
- 需要一台真机 USB 设备验证
|
||
- **网页看屏(ws-scrcpy)**:
|
||
- 平台机部署 ws-scrcpy(Node 服务,WebRTC 低延迟流 + 触控),本机 adb 为数据源
|
||
- 管理员页面新增「远程看屏」入口,iframe 内嵌;登录态复用(ws-scrcpy 自身鉴权
|
||
走 token 或仅内网/Tailscale 暴露)
|
||
- 备选方案(若 ws-scrcpy 试用不达标):自建 minicap JPEG 流 + u2 触控注入(2-3 天)
|
||
|
||
## 阶段 3:界面清理 + STF 停用(已完成代码部分,2026-08-18)
|
||
|
||
✅ 已完成的代码部分(commit a5ce57b,-956 行):
|
||
- 删「一键重启 STF 容器」区块、设备表 STF 占用列、强制释放占用按钮
|
||
- 删「STF 设备管理」子分栏(设备池管理面板接管)+ 卸载/检查 STF agent 按钮
|
||
- 删除 `core/stf_client.py`、`core/stf_device_mgmt.py` 及全部引用(含 web_server
|
||
全部 STF API、启动残留清理、设备池首导 seed)
|
||
- 错误类(STFError/DeviceOfflineError)迁入 `core/device_worker.py`;
|
||
`create_worker`/`BaseWorker` 去掉 stf 参数;`stf_occupied` 字段全链路移除
|
||
- 文案清理(tools/apps/editor/monitor)+ `config.py` STF/SSH 配置标注废弃
|
||
- 文档更新(ARCHITECTURE/DEPLOY)
|
||
|
||
⏳ 待人工确认的最后一步(220 侧):
|
||
- **停 STF 容器**(`docker stop stf`,不删除,可 `docker start stf` 回滚)
|
||
- 保留 adb 容器(host 网络 5037,USB 设备远程驱动依赖它);
|
||
connect_devices.sh cron 可留可退役(对网络设备补连已无必要,无害)
|
||
- 停容器前请确认:任务调度/看屏/设备池管理已稳定运行 ≥1 天
|
||
|
||
## 阶段 4(可选,未来多实例/多机时)
|
||
|
||
跨实例互斥:SQLite 行锁替代 occupy——
|
||
```sql
|
||
UPDATE device_locks SET owner=?, ts=? WHERE serial=? AND (owner IS NULL OR owner=?)
|
||
```
|
||
|
||
---
|
||
|
||
## 回滚方式
|
||
|
||
- 每个阶段一个 commit,问题可整体 `git revert`;STF 阶段 3 前一直运行,随时回切
|
||
- 阶段 3 的 STF 容器是 `docker stop` 而非删除,回滚 = `git revert` + `docker start stf`
|
||
- 每个阶段 commit 后在 dev 观察 ≥3 天再进下一阶段
|