# dbx dev 真机调试

**硬门禁：只有用户已经明确选择使用 `dbx dev` 连接手机并直接推送 Page / Widget / 卡片时，才使用本文流程。**

如果用户只说“想看真机效果”“测试手机里的渲染”“真机验证页面/卡片”或“真机预览一下”，但没有选择具体方式，停止本文流程并先询问：

> 你想通过哪种方式验证真机效果：使用 UGC Bot 扫码预览已上传并云构建的版本，还是使用 `dbx dev` 连接手机并直接推送页面/卡片？

等待用户回答期间，不下载真机工具，不进入或列出 `device` 真机模式及其中的 `qr` / `pages` / `page` / `widgets` / `widget` 命令，也不要默认改用 Web 模拟器或 simulator。用户选择 UGC Bot 后，改读 [overview.md](overview.md) 的 build 流程。

“真机调试”专指本文的 `dbx dev` 设备连接与 Page / Widget 推送。产物上传并云构建后在版本详情页扫码、进入 UGC Bot 调试对话的流程称为“真机预览”，不属于本文。

门禁满足后，使用 `dbx dev` 前台 REPL 连接真机、打开 Page 或推送 Widget。本文流程不替代 `dbx simulator eval` 的 Skill / MCP / Manifest 链路验证。

如果项目存在 `business-templates.yaml`，先读 [业务模板调试边界](business-template-debug.md)。真机调试资源准备时，必须将它与当前 Manifest、前端资源及其它真机调试产物一起上传打包；不能复用模拟器创建 Sandbox Session 时的模板上传，也不能用 `--business-templates-only` 代替真机调试整包。

## 适用场景与边界

| 目标                            | 使用方式                                            | 成功证据                                     |
| ------------------------------- | --------------------------------------------------- | -------------------------------------------- |
| 真机打开指定页面                | 真机模式内执行 `page <page-url>`                    | 用户确认手机实际打开；CLI 仅证明请求已发送。 |
| 真机推送卡片                    | 真机模式内执行 `widget <widget-id> --data '<json>'` | 用户确认设备已显示并正确渲染。               |
| Skill / MCP / Manifest 出卡链路 | 改用 `dbx simulator eval`                           | `Verdict: PASS`、tool report 与 card delta。 |

不要把 `status: ok`、`page pushed` 或 `widget pushed` 描述成“设备已渲染成功”；它们最多证明 dev service 接收并派发了请求。

## 启动前检查

1. 确认 dbx 项目根目录：应有 `manifest.yaml`、运行态 `skill/SKILL.md` 和 `.dbx` 状态目录。
2. 项目存在 `business-templates.yaml` 时，确认它已纳入本次 Manifest、前端资源和其它真机调试产物组成的完整调试包。
3. 确认前端工程目录。前端目录由项目布局和 `.dbx/config.json` 自动解析。
4. 确认 MCP endpoint 对本机可访问。若端口已有监听进程，先识别或复用它；不要为“清端口”直接结束未知进程。
5. 交互式终端会启动 Ink REPL；无 TTY 时会以前台模式持续运行 dev service，并在启动后打印 Web Simulator 地址。使用 Ctrl+C 或默认 `kill`（SIGTERM）停止。

标准启动命令：

```bash
dbx dev \
  --mcp-endpoint <streamable_http_mcp_endpoint>
```

项目根和前端目录均由当前项目布局自动解析：

```bash
dbx dev --mcp-endpoint <streamable_http_mcp_endpoint>
```

如果启动报路径错误，先逐项确认上述目录与 `manifest.yaml` / `skill/SKILL.md`，再补 `--manifest` 或 `--skill`；不要靠猜测项目结构反复试命令。

## REPL 工作流

### 1. 进入真机模式并扫码

在执行 `device` 前，先明确告诉用户：

> 即将准备真机调试。首次运行或工具更新时，CLI 会先下载本机开发者工具（当前 macOS 包约 117 MB；实际大小、进度和耗时以终端显示为准），下载完成后才生成二维码。二维码生成后 CLI 默认等待 60 秒，并自动在默认浏览器打开二维码图片；请保持手机豆包已登录并在图片出现后尽快扫码。若超时，我会在真机模式执行 `qr` 重新生成。

然后在 REPL 执行：

```text
device
```

- REPL 提示符会切换为 `device ›`，此后直接输入 `qr` / `pages` / `page` / `widgets` / `widget` / `sessions` / `use-session` / `get-console` / `take-screenshot` / `get-page-tree` / `get-computed-style`，不要再加 `device` 前缀。命令列表会随模式动态显示；执行 `<命令> --help` 查看参数，执行 `back` 返回主命令。
- CLI 会在工具准备阶段持续显示下载进度和实际耗时；不要在下载未完成时要求用户扫码或声称二维码已生成。
- CLI 默认在浏览器打开仅本机可访问的临时二维码页面，不落盘 PNG。
- 需要导出并向用户直接展示二维码文件时执行 `device --qr-file <绝对路径/文件.png>`；二维码超时后在真机模式执行 `qr --qr-file <绝对路径/文件.png>` 重新生成。将该 PNG 附加为图片后再请用户扫码，不要要求用户“查看终端”或复用已超时文件。
- 用户本人完成扫码和手机端授权；Agent 只负责发起与观察连接状态。
- 看到设备连接事件后，再在真机模式用 `page <page-url>` 或 `widget <widget-id>` 验证。若只看到超时、没有设备连接事件，重新生成二维码；不要把它归因成 Manifest 权限问题。
- 出现“超时”与稍后设备连接并存时，如实说明状态矛盾，并让用户确认设备是否实际收到页面或卡片。

### 2. 发现可调试目标

进入真机模式后执行：

```text
pages
widgets
```

Page 只使用 `pages` 列出的完整 URL，Widget 只使用 `widgets` 列出的 ID。当前 REPL 可能不会拒绝未知值，因此“opened/pushed / status: ok”不能作为成功证据。

参数含义或数据格式不明确时，不要靠试错补全；先从项目的 Manifest、已有调试配置和已确认的数据契约中获取依据，仍无法确认时向用户说明缺少的信息。

### 3. 选择并检查 Lynx session

需要读取日志、截图、DOM 或 computed style 时，先列出当前可检查目标：

```text
sessions
```

输出中的 target ref 格式为 `@<clientId>:<sessionId>`，并可能标记：

- `[latest]`：本次扫码鉴权 client 内最新活跃的 Lynx Page / 卡片。
- `[cli]`：CLI 已通过 `use-session` 固定的目标。
- `[electron]`：Electron 当前显示的目标，仅作提示。

CLI 与 Electron 的选择互不联动。固定 CLI 目标或恢复 latest：

```text
use-session @3:5
use-session latest
```

对单次命令临时指定目标时使用 `--target`；它不会改写 `use-session` 的状态：

```text
get-console --target @3:5
take-screenshot --target @3:5 --output page.jpeg --json
get-page-tree --target @3:5 --json
get-computed-style @3:5:42 --properties color,font-size --json
```

- `get-console` 只持续输出命令启动后新产生的日志，不读取或持久化历史；按 Ctrl+C 只停止本次监听并返回 `device ›`。
- `take-screenshot` 默认复用目标 session 最近一条 `Page.screencastFrame`。在 `device --agent` 模式下，CLI 会临时执行 `Page.enable` / `Page.startScreencast`，收到一帧后确认并停止 screencast，因此截图不依赖 Electron。主动请求不会设置 `mode`，保留设备当前的 `lynxview` / `fullscreen` 设置；frame 本身不携带 mode，JSON 不会虚构该字段。长生命周期的 inspection session 只缓存最近一帧，不会累积截图历史。
- `get-page-tree --json` 返回 DevTools Elements DOM 树、节点文本、完整 attributes 和 `@client:session:node` node-ref。
- `get-computed-style` 必须使用当前 DOM 快照生成的 node-ref；页面导航或 DOM 重建后 ref 可能失效，应重新执行 `get-page-tree`。
- Agent 消费结果时优先使用 `--json`。`get-page-tree`、`get-computed-style` 和 `take-screenshot` 支持该选项；不要虚构非交互式 `dbx --json dev device ...` 命令。

### 4. 打开 Page

```text
page <page-url>
```

需要调试页面入参时，将参数编码到 URL query；参数结构必须来自已确认的项目数据契约。执行后请用户确认手机端结果。

### 5. 推送 Widget 与准备 JSON

```text
widget <widget-id>
widget <widget-id> --data '<json>'
```

参数或用法不确定时，先在真机模式执行 `widget --help` 或 `help widget`；两者都不会推送卡片，不要猜测 flag 名称。

按此顺序准备数据，不要凭业务名称杜撰字段：

1. 从真机模式的 `widgets` 取得真实 `widget-id`。
2. 在 `manifest.yaml` 中找到绑定该 widget 的 `entities.<entity>.tool_card_binding`。
3. 使用 `entities.<entity>.schema`、项目已有示例和 Widget 的公开数据契约组成调试 JSON。
4. 只填已确认字段；业务必填字段或嵌套结构不明确时，先向用户确认或读取对应前端数据契约。

无效 JSON 的报错通常可直接修复；但未知 widget ID 仍可能显示成功，因此必须让用户确认真机渲染。长 JSON 先在文件或编辑器中校验，再粘贴到 REPL，避免终端回显换行干扰判断。

### 6. Web 与停止

- `web` 提示 URL 未就绪，或启动日志包含 Web SDK / JSON 解析错误时，记录完整错误和 log id；不要宣称 Web 调试已启动。继续用真机验证，或排查当前 `dbx dev` 会话的 Web SDK 配置。
- 调试结束时退出 REPL（例如按 Ctrl+C），或在另一个终端执行 `dbx dev stop`。如果进程和监听端口已消失但状态仍为 `stopping`，保留 `.dbx` 会话信息并报告为 CLI 状态残留；不要直接删除状态目录。

## 问答：权限、授权与无法继续

先分类，再向用户说明“缺什么”和“谁需要操作”。区分应用开发权限与设备白名单、真机扫码授权、Manifest 权限、用户登录授权和本地服务问题；不要把网络、设备连接或页面渲染问题笼统说成“没有权限”。

| 现象或提问                                          | 先核验                                                                                         | 应告知用户 / 下一步                                                                                                                                                                 |
| --------------------------------------------------- | ---------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 生成二维码失败                                      | 核对智能服务 AppKey 是否为目标应用，以及当前 dbx 登录用户是否具有该智能服务的开发权限。        | 这是**应用开发权限**问题。请应用管理员确认 AppKey，并为当前登录用户授予该智能服务的开发权限后重试；不要改用其他应用的 AppKey 绕过。                                                 |
| “为什么需要我扫码？”                                | 当前是否执行了 `device`。                                                                      | 这是**真机调试授权**，不是 Manifest 中的 JSB / Tool 权限。请用户用已登录豆包扫码授权；超时则重新生成二维码。                                                                        |
| 扫码后手机验签失败                                  | 保留原始错误，确认扫码手机的豆包 UID 是否已配置到该智能服务的调试白名单。                      | 这是**设备白名单**问题，不是 Manifest 权限或普通登录。请应用管理员通过受控渠道将该 UID 加入目标智能服务白名单后，重新生成二维码并扫码；不要在终端日志或对话中暴露 UID。             |
| “我还缺哪些应用权限？”                              | 读取 `manifest.yaml` 的 `permissions` 与目标 `tools.<tool>.tool_permissions`。                 | 明确缺少的 `scope_name`、用途及 `is_must_need`。版本级 `permissions` 必须声明该 scope，目标 Tool 必须引用它。详细配置读 [manifest-guide.md](manifest-guide.md)。                    |
| “为什么工具要求登录或手机号？”                      | 读取目标 Tool 的 `login_type`、`login_params` 与 `mcp_server.user_auth`。                      | 这是**用户登录授权**，不是设备扫码。若登录配置或服务端回调不存在，要求应用/后端负责人提供并实现对应公网 HTTPS 接口；不要伪造 token、URL 或用户身份。详细流程读 [auth.md](auth.md)。 |
| MCP 返回 401、token 过期或 scope 不足               | 确认 `X-DB-ACCESS-TOKEN`、`login_type`、`fetch_token_url` / `refresh_token_url` 与服务端日志。 | 请用户重新完成登录授权；若仍失败，说明缺少的是后端登录配置或 scope，而不是让用户重复扫码。                                                                                          |
| 真机模式的 `page` / `widget` 显示成功但手机没有变化 | 核对 ID 是否来自真机模式的 `pages` / `widgets`，并确认设备连接事件与手机实际画面。             | 这不是权限结论。先说明“请求已派发、渲染未确认”，再排查 ID、设备连接和前端渲染。                                                                                                     |
| MCP endpoint 不可访问或端口已占用                   | 检查 endpoint、服务进程和端口归属。                                                            | 这是**本地服务/网络**问题，不是用户权限。不要结束未知占用进程；请项目负责人确认要复用、停止还是换端口。                                                                             |
| `web` 无法打开                                      | 记录 Web SDK / URL 错误。                                                                      | 这是**Web 调试器**问题，不是扫码或 Manifest 权限。使用真机调试或排查当前 `dbx dev` 会话继续隔离。                                                                                   |

在任何权限问答中，先给出已确认的配置证据和对应权限层；无法从 Manifest、登录配置或日志确认时，明确说“待确认”，并说明需要哪个文件、错误码或负责人信息。
