Add cross-border-ecommerce/hubstudio-bridge
This commit is contained in:
@@ -0,0 +1,479 @@
|
|||||||
|
---
|
||||||
|
name: hubstudio-bridge
|
||||||
|
description: "HubStudio 浏览器环境 AI 自动化 — 通过 Hermes + Desktop Bridge 操控 HubStudio 浏览器环境/云手机,自然语言驱动:列出环境、启动环境、获取调试端口、对接 Playwright/Selenium。"
|
||||||
|
version: 1.3.0
|
||||||
|
author: Hermes Agent
|
||||||
|
metadata:
|
||||||
|
hermes:
|
||||||
|
tags: [hubstudio, 浏览器环境, 云手机, browser-automation, cross-border]
|
||||||
|
related_skills:
|
||||||
|
- ziniao-bridge
|
||||||
|
- bridge-cdp-agent
|
||||||
|
- drissionpage-toolkit
|
||||||
|
cron_compatible: true
|
||||||
|
---
|
||||||
|
|
||||||
|
# HubStudio Bridge
|
||||||
|
|
||||||
|
通过 Hermes + AtomK Desktop 连接 HubStudio Local API,用自然语言管理浏览器环境与云手机。
|
||||||
|
|
||||||
|
**触发词:** "HubStudio" / "hubstudio" / "浏览器环境" / "云手机" / "启动环境" / "列出环境"
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 架构总览
|
||||||
|
|
||||||
|
```
|
||||||
|
自然语言指令
|
||||||
|
↓
|
||||||
|
Hermes Agent (解析意图)
|
||||||
|
↓
|
||||||
|
Bridge POST /api/command {action: "hubstudio_cdp.navigate", params: {...}}
|
||||||
|
↓ WS → type: "command"
|
||||||
|
AtomK Desktop bridge-manager.ts
|
||||||
|
↓ messageRouter.dispatch()
|
||||||
|
├─ hubstudio.* → HubstudioClient → HubStudio API (6873)
|
||||||
|
└─ hubstudio_cdp.* → HubStudioCDPController → Playwright connectOverCDP
|
||||||
|
→ HubStudio 独立 Chrome (58289)
|
||||||
|
```
|
||||||
|
|
||||||
|
**前提条件:**
|
||||||
|
- HubStudio 客户端与 AtomK Desktop 在同一台 Windows/Mac 机器
|
||||||
|
- HubStudio 客户端已启动(Local API 模式)
|
||||||
|
- API 凭证已配置(app_id + app_secret)
|
||||||
|
- Desktop 已更新到包含 `hubstudio-cdp-controller.ts` 的版本
|
||||||
|
|
||||||
|
### ✅ CDP 中继:hubstudio_cdp.* 命令(Desktop v4.0.x+)
|
||||||
|
|
||||||
|
Desktop 侧新增 `HubStudioCDPController`(`src/main/hubstudio-cdp-controller.ts`),
|
||||||
|
通过 Playwright `connectOverCDP` 连接 HubStudio 独立 Chrome 实例。
|
||||||
|
Bridge 通过 `POST /api/command` 端点(`cloud-bridge/server.py`)转发命令。
|
||||||
|
|
||||||
|
| 命令 | 参数 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| `hubstudio_cdp.navigate` | `{envCode, url, waitUntil?, timeout?}` | 在 HubStudio Chrome 中导航 |
|
||||||
|
| `hubstudio_cdp.evaluate` | `{envCode, expression}` | 执行 JS 并返回结果 |
|
||||||
|
| `hubstudio_cdp.click` | `{envCode, x, y}` | 在指定坐标点击 |
|
||||||
|
| `hubstudio_cdp.screenshot` | `{envCode, fullPage?, quality?}` | 截图(返回 base64 JPEG) |
|
||||||
|
| `hubstudio_cdp.snapshot` | `{envCode}` | 获取页面可访问性树快照 |
|
||||||
|
| `hubstudio_cdp.disconnect` | `{envCode}` | 断开 CDP 连接 |
|
||||||
|
| `hubstudio_cdp.status` | — | 查看当前 CDP 连接状态 |
|
||||||
|
|
||||||
|
**自动连接**:`hubstudio.open_env` 成功后自动调用 `hubstudioCdp.connect(containerCode, port)`,
|
||||||
|
响应中会包含 `cdpConnected: true`。
|
||||||
|
|
||||||
|
**自动断开**:`hubstudio.close_env` 会先断开 CDP 再关闭浏览器。
|
||||||
|
|
||||||
|
### ⚠️ CDP 端口可达性
|
||||||
|
|
||||||
|
HubStudio Chrome 的 CDP 端口(如 58289)只在 Windows 本机(127.0.0.1)可达。
|
||||||
|
Desktop 通过本机 Playwright `connectOverCDP` 连接,Bridge 通过 Desktop WS 隧道
|
||||||
|
中转 CDP 命令。不能从 Bridge/Linux 侧直连 HubStudio CDP 端口。
|
||||||
|
|
||||||
|
**验证端口可达性:** `scripts/hubstudio-cdp-direct-test.py` — 在 Windows 上运行。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## HubStudio Local API
|
||||||
|
|
||||||
|
> 📖 完整 API 文档: `references/hubstudio-api.md`(源: api-docs.hubstudio.cn)
|
||||||
|
> 📦 HubStudio Skill 项目: `references/hubstudio-skill-project.md`(OpenClaw 技能包, 56 条命令映射)
|
||||||
|
|
||||||
|
### 基础 URL
|
||||||
|
|
||||||
|
```
|
||||||
|
http://127.0.0.1:6873
|
||||||
|
```
|
||||||
|
|
||||||
|
### 认证方式
|
||||||
|
|
||||||
|
所有请求携带 Header:
|
||||||
|
```
|
||||||
|
Authorization: Bearer {API_SECRET}
|
||||||
|
Accept-Language: zh-CN
|
||||||
|
```
|
||||||
|
API Secret 来自 Hubstudio 客户端设置页「API 接口」→「复制 API 密钥」
|
||||||
|
|
||||||
|
### Desktop 端调用
|
||||||
|
|
||||||
|
Desktop v4.0.2 内置 `hubstudio-client.ts`(Electron 主进程,**无 CORS 限制**),支持完整的 Hubstudio API:
|
||||||
|
|
||||||
|
```
|
||||||
|
hubstudio.list_envs → POST /api/v1/env/list → 列出所有浏览器环境
|
||||||
|
hubstudio.open_env → POST /api/v1/browser/start → 启动环境 → debuggingPort
|
||||||
|
hubstudio.close_env → POST /api/v1/browser/close → 关闭环境
|
||||||
|
hubstudio.opened_envs → POST /api/v1/browser/opened → 已打开环境列表
|
||||||
|
hubstudio.status → 健康检查
|
||||||
|
```
|
||||||
|
|
||||||
|
## 核心接口
|
||||||
|
|
||||||
|
### 1. 列出所有浏览器环境
|
||||||
|
|
||||||
|
```
|
||||||
|
POST /api/v1/env/list
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{"current": 1, "size": 200}
|
||||||
|
```
|
||||||
|
|
||||||
|
返回示例:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 0,
|
||||||
|
"data": {
|
||||||
|
"records": [
|
||||||
|
{
|
||||||
|
"containerCode": "1502764609",
|
||||||
|
"containerName": "环境A-亚马逊",
|
||||||
|
"remark": "美西",
|
||||||
|
"proxyTypeName": "socks5",
|
||||||
|
"ipAddress": "103.136.249.48"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"total": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 启动浏览器环境
|
||||||
|
|
||||||
|
```
|
||||||
|
POST /api/v1/browser/start
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"containerCode": "1502764609",
|
||||||
|
"isHeadless": false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
返回:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 0,
|
||||||
|
"data": {
|
||||||
|
"containerCode": "1502764609",
|
||||||
|
"debuggingPort": "59591",
|
||||||
|
"webdriver": "C:\\...webdriver.exe",
|
||||||
|
"browserPath": "C:\\...chrome_130\\hubstudio",
|
||||||
|
"statusCode": "0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 关闭浏览器环境
|
||||||
|
|
||||||
|
```
|
||||||
|
POST /api/v1/browser/close
|
||||||
|
{"containerCode": "1502764609"}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. 获取已打开环境
|
||||||
|
|
||||||
|
```
|
||||||
|
POST /api/v1/browser/opened
|
||||||
|
{}
|
||||||
|
→ {"code":0, "data":["1502764609","11320340"]}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 操作模式
|
||||||
|
|
||||||
|
### 模式 A:Bridge 命令路由(Desktop v4.0.2+,推荐)
|
||||||
|
|
||||||
|
Desktop v4.0.2 内置完整 `hubstudio-client.ts` + `bridge-message-router.ts` hubstudio.* 路由。
|
||||||
|
Hermes → Bridge → Desktop 主进程直接调 Hubstudio Local API,**无 CORS 限制**。
|
||||||
|
|
||||||
|
```
|
||||||
|
Hermes Agent
|
||||||
|
→ Bridge WS (type: "command", method: "hubstudio.list_envs")
|
||||||
|
→ Desktop bridge-manager.ts
|
||||||
|
→ messageRouter.dispatch()
|
||||||
|
→ HubstudioClient.listEnvs()
|
||||||
|
→ POST http://127.0.0.1:6873/api/v1/env/list
|
||||||
|
→ 返回 → Bridge → Hermes
|
||||||
|
```
|
||||||
|
|
||||||
|
支持的命令:
|
||||||
|
| 命令 | 参数 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| `hubstudio.status` | — | 健康检查/连接测试 |
|
||||||
|
| `hubstudio.list_envs` | `{page?, size?}` | 列出浏览器环境 |
|
||||||
|
| `hubstudio.open_env` | `{containerCode, isHeadless?}` | 启动环境 → debuggingPort + **自动连 CDP** |
|
||||||
|
| `hubstudio.close_env` | `{containerCode}` | 关闭环境 + **自动断 CDP** |
|
||||||
|
| `hubstudio.opened_envs` | — | 已打开环境列表 |
|
||||||
|
| `hubstudio_cdp.navigate` | `{envCode, url, waitUntil?, timeout?}` | HubStudio Chrome 中导航 |
|
||||||
|
| `hubstudio_cdp.evaluate` | `{envCode, expression}` | 执行 JS 返回结果 |
|
||||||
|
| `hubstudio_cdp.click` | `{envCode, x, y}` | 坐标点击 |
|
||||||
|
| `hubstudio_cdp.screenshot` | `{envCode, fullPage?, quality?}` | 截图(base64 JPEG) |
|
||||||
|
| `hubstudio_cdp.snapshot` | `{envCode}` | 可访问性树快照 |
|
||||||
|
| `hubstudio_cdp.disconnect` | `{envCode}` | 断开 CDP 连接 |
|
||||||
|
| `hubstudio_cdp.status` | — | CDP 连接状态 |
|
||||||
|
|
||||||
|
### 模式 B:CDP evaluate(备选,有 CORS 问题)
|
||||||
|
|
||||||
|
仅在 Bridge 命令路由不可用时使用。CDP Chrome 调 HubStudio API 会被 CORS 拦截。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 典型操作场景
|
||||||
|
|
||||||
|
### 场景 1:列出所有环境
|
||||||
|
|
||||||
|
**自然语言:** "列出我所有 HubStudio 浏览器环境"
|
||||||
|
|
||||||
|
**执行:**
|
||||||
|
```
|
||||||
|
GET /api/env/list
|
||||||
|
→ 解析 → 表格展示环境名称、ID、状态
|
||||||
|
```
|
||||||
|
|
||||||
|
### 场景 2:启动环境 + 获取端口
|
||||||
|
|
||||||
|
**自然语言:** "启动 HubStudio 环境 1502764609"
|
||||||
|
|
||||||
|
**执行:**
|
||||||
|
```
|
||||||
|
POST /api/env/open {"envId": "1502764609"}
|
||||||
|
→ 获取 debuggingPort
|
||||||
|
→ Playwright connectOverCDP(port)
|
||||||
|
→ 可以继续操控该环境
|
||||||
|
```
|
||||||
|
|
||||||
|
### 场景 3:关闭环境
|
||||||
|
|
||||||
|
**自然语言:** "关闭环境 1502764609"
|
||||||
|
|
||||||
|
**执行:**
|
||||||
|
```
|
||||||
|
POST /api/env/close {"envId": "1502764609"}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 场景 4:巡检所有环境状态
|
||||||
|
|
||||||
|
**自然语言:** "检查所有 HubStudio 环境状态"
|
||||||
|
|
||||||
|
**执行:**
|
||||||
|
```
|
||||||
|
GET /api/env/list → 遍历 → GET /api/env/status?envId=xxx
|
||||||
|
→ 汇总报告
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Desktop 端调用方式
|
||||||
|
|
||||||
|
Desktop v4.0.2 内置 `hubstudio-client.ts`(Electron 主进程,无 CORS 限制)。
|
||||||
|
Bridge 命令通过 `bridge-message-router.ts` 分发到 `HubstudioClient` 方法。
|
||||||
|
|
||||||
|
凭证配置:Desktop Chrome Bridge 页面 → 「紫鸟 & Hubstudio API」:
|
||||||
|
- App ID: Hubstudio 客户端设置 → API 接口 → app_id
|
||||||
|
- App Secret: 同上 → API 密钥(RSA 私钥,~1600 字符 PEM)
|
||||||
|
- Base URL: `http://127.0.0.1:6873`(默认,本地地址)
|
||||||
|
|
||||||
|
存储:`~/.atomk/hubstudio.json`(Electron safeStorage 加密)。
|
||||||
|
|
||||||
|
## 典型操作场景
|
||||||
|
|
||||||
|
### 场景 1:列出所有环境
|
||||||
|
|
||||||
|
**自然语言:** "列出我所有 Hubstudio 浏览器环境"
|
||||||
|
|
||||||
|
**执行:**
|
||||||
|
```
|
||||||
|
hubstudio.list_envs
|
||||||
|
→ POST /api/v1/env/list {current:1, size:200}
|
||||||
|
→ 表格展示环境名称、ID、状态
|
||||||
|
```
|
||||||
|
|
||||||
|
### 场景 2:启动环境 + 获取端口
|
||||||
|
|
||||||
|
**自然语言:** "启动 HubStudio 环境 1502764609"
|
||||||
|
|
||||||
|
**执行:**
|
||||||
|
```
|
||||||
|
hubstudio.open_env {containerCode: "1502764609"}
|
||||||
|
→ POST /api/v1/browser/start
|
||||||
|
→ 获取 debuggingPort(如 58289)
|
||||||
|
→ ⚠️ 此端口仅在 Windows 本机可达,不能从 Bridge/Linux 连接
|
||||||
|
→ 在 Windows 上用 DrissionPage 直连: Chromium(addr_or_opts='127.0.0.1:58289')
|
||||||
|
```
|
||||||
|
|
||||||
|
详见上方「架构限制」节和 `scripts/hubstudio-cdp-direct-test.py` 测试脚本。
|
||||||
|
|
||||||
|
### 场景 3:关闭环境
|
||||||
|
|
||||||
|
**自然语言:** "关闭环境 1502764609"
|
||||||
|
|
||||||
|
**执行:**
|
||||||
|
```
|
||||||
|
hubstudio.close_env {containerCode: "1502764609"}
|
||||||
|
→ POST /api/v1/browser/close
|
||||||
|
```
|
||||||
|
|
||||||
|
HubStudio root (127.0.0.1:6873) 在某些情况下 `Page.navigate` 会超时(15s)。
|
||||||
|
这是因为 CDP Chrome 保持空白 about:blank page 时 navigate 阻塞。
|
||||||
|
|
||||||
|
**修复**:`/cdp/send` → `Target.createTarget` 直接创建新 tab:
|
||||||
|
```javascript
|
||||||
|
fetch('/cdp/send', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {..., 'X-Desktop-Id': '<slot>'},
|
||||||
|
body: JSON.stringify({method: 'Target.createTarget', params: {url: 'http://127.0.0.1:6873'}})
|
||||||
|
})
|
||||||
|
// 返回 {targetId: "6034BA..."} — 可直接用于 evaluate
|
||||||
|
```
|
||||||
|
无需后续 `/cdp/attach`,新 target 自动 attach。
|
||||||
|
|
||||||
|
### APP Secret 格式
|
||||||
|
|
||||||
|
HubStudio APP Secret 是 **RSA 私钥**(PEM base64, PKCS#8 格式,~1600 字符)。
|
||||||
|
不是普通短字符串。存储在 `.env` 文件时必须完整保留,不可截断。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 与 紫鸟(ziniao) 的区别
|
||||||
|
|
||||||
|
| | HubStudio | 紫鸟(Ziniao) |
|
||||||
|
|------|-----------|-------------|
|
||||||
|
| API 端口 | 6873 | 19481(默认) |
|
||||||
|
| 认证方式 | Bearer API_SECRET | Bearer apiKey |
|
||||||
|
| 环境标识 | containerCode | storeId |
|
||||||
|
| 功能 | 浏览器环境 + 云手机 | 店铺浏览器 |
|
||||||
|
| Desktop 集成 | v4.0.2 已集成 | v4.0.0 已集成 |
|
||||||
|
| Bridge 路由 | hubstudio.* (5 methods) | ziniao.* (5 methods) |
|
||||||
|
| API 文档 | api-docs.hubstudio.cn | 紫鸟开放平台 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Skill 注册与 Desktop 发现
|
||||||
|
|
||||||
|
Hermes Agent 在 Bridge 服务器(Linux)上运行,Desktop 在用户本机(Windows/Mac)。Skill 文件在服务器上创建后,Desktop 看不到。
|
||||||
|
|
||||||
|
Desktop 从两个源发现 skill:
|
||||||
|
|
||||||
|
1. **本地已安装** — Desktop 扫描本机 `~/.hermes/skills/<category>/<name>/SKILL.md`
|
||||||
|
2. **Gitea 注册表** — Desktop 拉取 `admin9webs/atomk-hermes-skills` 仓库
|
||||||
|
|
||||||
|
推送 skill 到 Gitea 注册表的命令:
|
||||||
|
```
|
||||||
|
PUT /api/v1/repos/admin9webs/atomk-hermes-skills/contents/skills/<category>/<name>/SKILL.md
|
||||||
|
```
|
||||||
|
使用 Basic Auth,body 含 base64 编码内容 + `branch: main`。
|
||||||
|
|
||||||
|
Gitea 注册表根路径:
|
||||||
|
```
|
||||||
|
https://gitea9webs.sh3.ikuai7.com/admin9webs/atomk-hermes-skills
|
||||||
|
```
|
||||||
|
|
||||||
|
> ⚠️ Desktop 必须在技能管理页面刷新注册表才能看到新推送的 skill。在 Desktop 中点击"安装"后,skill 文件写入本机 `~/.hermes/skills/`,此后出现在本地已安装列表。
|
||||||
|
|
||||||
|
## Bridge /api/command 端点
|
||||||
|
|
||||||
|
Desktop 的 hubstudio.* / hubstudio_cdp.* / playwright.* / ziniao.* 命令通过 Bridge 的
|
||||||
|
`POST /api/command` 端点转发(`cloud-bridge/server.py`):
|
||||||
|
|
||||||
|
```
|
||||||
|
Hermes → POST /api/command {action: "hubstudio_cdp.navigate", params: {...}}
|
||||||
|
→ Bridge WS → Desktop bridge-manager.ts
|
||||||
|
→ MessageRouter.dispatch({method: action, params})
|
||||||
|
→ 返回 {type: "command_response", id, ok, data}
|
||||||
|
```
|
||||||
|
|
||||||
|
**认证**:Bearer token + `X-Desktop-Id` header 指定目标 Desktop。
|
||||||
|
|
||||||
|
**请求格式**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"action": "hubstudio.open_env",
|
||||||
|
"params": {"containerCode": "xxx"},
|
||||||
|
"id": "optional-custom-id"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**响应格式**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"action": "hubstudio.open_env",
|
||||||
|
"ok": true,
|
||||||
|
"data": {"debuggingPort": "58289", "cdpConnected": true}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**端点注册**:9228 和 9229 端口都已注册。路由在 `/api/{path:.*}` wildcard 之前。
|
||||||
|
超时:60 秒(与 proxy_handler 共用 `PROXY_DEFAULT_TIMEOUT`)。
|
||||||
|
|
||||||
|
> 📖 安全审查报告:`references/security-review-2026-07.md`
|
||||||
|
> 📜 Windows 直连测试脚本:`scripts/hubstudio-cdp-direct-test.py`
|
||||||
|
|
||||||
|
## 安全特性
|
||||||
|
|
||||||
|
### evaluate() 封禁
|
||||||
|
|
||||||
|
`hubstudio_cdp.evaluate` 在 Bridge 路由层已封禁(与 `playwright.execute` 一致的安全策略)。
|
||||||
|
任何通过 Bridge 发送的 `hubstudio_cdp.evaluate` 命令都会返回错误:
|
||||||
|
`"hubstudio_cdp.evaluate is not available via Bridge (arbitrary JS execution risk)"`
|
||||||
|
|
||||||
|
如需在 HubStudio Chrome 中执行 JS,必须在 Desktop 本机通过 `HubStudioCDPController.evaluate()` 内部调用。
|
||||||
|
|
||||||
|
### SSRF 防护
|
||||||
|
|
||||||
|
所有导航命令(`hubstudio_cdp.navigate` / `playwright.navigate` / `ziniao.screenshot`)
|
||||||
|
共用 `isPrivateHost()` 方法进行内网地址检测,拒绝以下目标:
|
||||||
|
- localhost / 127.0.0.1 / 0.0.0.0 / ::1 / [::1]
|
||||||
|
- 10.x / 172.16-31.x / 192.168.x / 169.254.x(RFC 1918 + link-local)
|
||||||
|
- IPv4-mapped IPv6 地址(`::ffff:127.0.0.1` 等)
|
||||||
|
|
||||||
|
### CDP Session 管理
|
||||||
|
|
||||||
|
`hubstudio_cdp.snapshot` 使用 `try/finally detach` 确保 CDPSession 不泄漏。
|
||||||
|
节点数上限 5000,超出自动截断(防大型页面 OOM)。
|
||||||
|
|
||||||
|
### 并发安全
|
||||||
|
|
||||||
|
`HubStudioCDPController.connect()` 使用 `pendingConnects` Map 防止同一 envCode
|
||||||
|
的并发连接导致 Browser 对象泄漏。
|
||||||
|
|
||||||
|
## 操作纪律
|
||||||
|
|
||||||
|
1. **串行操作**:多环境操作默认串行,避免资源冲突
|
||||||
|
2. **操作间隔**:启停环境间至少间隔 2 秒
|
||||||
|
3. **进程清理**:操作完成后关闭不需要的环境释放资源
|
||||||
|
4. **凭证安全**:APP_SECRET 不写入日志、不暴露在 shell 命令中
|
||||||
|
5. **推送注册表**:新增或修改 server 端 skill 后,必须同步推送到 Gitea 注册表,否则 Desktop 看不到
|
||||||
|
6. **Windows 直连用 DrissionPage**:连接 HubStudio 独立 Chrome 时,优先用 `DrissionPage`(`pip install DrissionPage`),无需额外安装浏览器。Playwright 需要 `playwright install chromium`(下载 ~150MB),仅在 DrissionPage 不兼容时回退。
|
||||||
|
|
||||||
|
## 常见坑
|
||||||
|
|
||||||
|
1. **🛑 Bridge 重启后 Desktop WS 断开,需手动重启 Desktop**:`systemctl restart cloud-bridge` 会断开所有 Desktop WS 连接。Desktop 不会自动重连(需用户手动重启 Desktop App)。重启后 slot ID 会变化(如 `desktop-mr2xlvo9` → `desktop-mr372rlv`),需重新从 `/health` 发现新 slot。
|
||||||
|
2. **🛑 list_envs 返回空可能是凭证问题,不是代码 bug**:`hubstudioAvailable: true` 只表示 API 可达。如果 HubStudio API 返回空环境列表(`envCount: 0`),检查 Desktop Chrome Bridge 页面的 HubStudio 凭证(App ID / App Secret)是否正确。凭证存储在 Windows 本机 `~/.atomk/hubstudio.json`(Electron safeStorage 加密),不在 Bridge 服务器上。
|
||||||
|
3. **🛑 HubStudio CDP 端口仅在 Windows 本机可达**:HubStudio Chrome 的 `debuggingPort`(如 58289)绑定在 `127.0.0.1`,Bridge(Linux)无法直连。所有 CDP 操作必须通过 Desktop 的 `HubStudioCDPController` 中转。Windows 本地测试可用:`Chromium(addr_or_opts='127.0.0.1:58289')`。
|
||||||
|
4. **🛑 DrissionPage pip install 需 `--user`(无管理员权限时)**:`pip install --user DrissionPage` — 直接 `pip install` 在 `C:\Python310` 下可能触发 `PermissionError`。
|
||||||
|
5. **🛑 opened_envs 返回 E010006 → 可能是零环境,不是认证错误**:`hubstudio.opened_envs` 返回 `ok: false, error: "internal_error", message: "getOpenedEnvs 失败: code=E010006"` 时,如果同时 `hubstudio.list_envs` 也返回空列表且 `hubstudio.status` 返回 `hubstudioAvailable: true, envCount: 0`,说明 HubStudio API 连接正常但账户下没有任何浏览器环境。这不是凭证问题——应先指导用户在 HubStudio 客户端创建浏览器环境,然后再重试。
|
||||||
|
6. **🛑 hubstudio_cdp.* 命令超时 = Desktop 代码版本不匹配**:命令超时(60s 无响应)的最常见原因是 Desktop 在运行构建版 `.exe` 而非 `npm run dev` 开发模式。构建版不含最新合并的 `hubstudio-cdp-controller.ts`。解决:`npm run dev` 热加载最新代码,或 rebuild Desktop。
|
||||||
|
7. **🛑 Desktop rebuild 触发条件**:只改 `src/main/` 下的 TypeScript 在 dev 模式无需 rebuild。只有改 `src/renderer/` 或需要分发包时才需要完整 build。
|
||||||
|
8. **🛑 Bridge 重启不自动更新 Desktop 代码**:`systemctl restart cloud-bridge.service` 只重启 Bridge Server(使 `/api/command` 等新端点生效)。Desktop 侧的代码更新需 Desktop App 重启(dev 模式热加载)或 rebuild。
|
||||||
|
9. **🛑 hubstudio_cdp.connect 端口校验**:`hubstudio_cdp.connect` handler 强制校验 port 为 1-65535 的数字(`typeof port !== 'number'`),字符串会被拒绝。`open_env` 返回的 `debuggingPort` 是字符串,Desktop 内部已做 `parseInt` 转换。
|
||||||
|
11. **🛑 SOCKS5 代理延迟(中国→境外)**:HubStudio 环境使用境外 SOCKS5 代理时,`hubstudio_cdp.*` CDP 操作非常慢(30-90s)。Cloud Bridge 会话中 browser_console fetch() 的 30s 硬超时会导致所有 CDP 命令超时。`hubstudio.open_env` 等管理命令仍是快速的。解决方案:用 cron no_agent 脚本 + urllib.request(timeout=90) 执行 CDP 操作。详见 `bridge-cdp-agent` 的 `references/hubstudio-cdp-socks5.md`。
|
||||||
|
① Desktop 代码版本 — 确认运行的是含 `hubstudio-cdp-controller.ts` 的版本(v4.0.17+),检查 health 返回的 version 字段
|
||||||
|
② Bridge 代码版本 — 确认 `cloud-bridge/server.py` 含 `/api/command` 端点(`grep command_handler server.py`)
|
||||||
|
③ Bridge 是否重启 — `/api/command` 端点生效需 `sudo systemctl restart cloud-bridge.service`(注意:重启会导致 Desktop WS 断开)
|
||||||
|
④ 构建产物含 handler — `grep "hubstudio_cdp" out/main/index.js` 确认编译正确
|
||||||
|
⑤ Desktop DevTools Console — 搜索 `[Router]` 看 handler 是否被调用、是否有 JS 错误
|
||||||
|
⑥ 对比 `playwright.status`(应正常)vs `hubstudio_cdp.status`(超时)— 两者同路径,差异说明问题在 MessageRouter handler 层而非路由层
|
||||||
|
⑦ **🔴 bridge-manager.ts 路由守卫遗漏 `hubstudio_cdp.*` — 字符串前缀不匹配**:
|
||||||
|
`src/main/bridge-manager.ts` L443 的路由条件只检查 `action.startsWith('hubstudio.')`(带**点**),
|
||||||
|
但 `hubstudio_cdp.*` 命令使用**下划线**连接(`hubstudio_cdp.status`)。
|
||||||
|
`'hubstudio_cdp.status'.startsWith('hubstudio.')` → **false** → 命令被路由守卫拦截,
|
||||||
|
掉入 `switch(action)` 无匹配项 → 静默丢弃 → 不发送 `command_response` → Bridge 等 60s 超时 → 504。
|
||||||
|
**修复**:在 L443 添加 `|| action.startsWith('hubstudio_cdp.')`。
|
||||||
|
PR #14 (commit `89e8c8d`) 已在 2026-07-03 修复,合入 Desktop **v4.0.18+**。
|
||||||
|
**诊断脚本**:`scripts/hubstudio-cdp-routing-test.py` — 一键测试三个命令并输出诊断结论。
|
||||||
|
**诊断实录**:`references/hubstudio-cdp-routing-504-diagnosis.md` — 完整的五步诊断过程。
|
||||||
|
**验证方式**:`hubstudio.status`✅ + `playwright.status`✅ + `hubstudio_cdp.status`❌504 = 本 bug。
|
||||||
|
常见根因(按概率排序):
|
||||||
|
(a) **bridge-manager.ts 路由守卫遗漏 hubstudio_cdp 前缀**(本项 ⑦)— 源码层面 bug,Desktop dev/exe 都受影响
|
||||||
|
(b) Desktop 运行构建版 .exe 而非最新 dev 代码 — 构建版不含 hubstudio-cdp-controller.ts
|
||||||
|
(c) Bridge 未重启不含 /api/command 端点
|
||||||
Reference in New Issue
Block a user