Files
workbuddy_skills/dsh-workflow/references/dsh-change-workflow/08-浏览器验证栈详解.md
T

77 lines
7.2 KiB
Markdown
Raw Normal View History

# 浏览器验证栈详解 · browser-harness 调用 / Lexical 输入难点 / 独立 headless 定型做法 / 必踩坑
> **归属**:技能 `dsh-change-workflow` 的详情档(**按需读**,不是每次都要读)。
> **本档覆盖**:正确调用(Windows,2026-09-11 实测可用) · ⛔ dsh composer(Lexical)输入难点 · 三个必踩坑(原行 L231–L293)。
> **主文件 / 判据与流程主干** = `../SKILL.md`(§1 六阶段流程 · §2 红线 R1–R8 原文速查 · §3 本机 Git Bash 环境坑 · §4 并行调度结论)。
> **来源**:2026-09-22「技能重组线」把 `../SKILL.md` 的 L231–L293 段**逐行原样**下沉到本文件,未改一字。
> **跨档引用**:正文里的「§N / 见 §8 坑 N / 见下表」等编号,用 `../SKILL.md` 末节「详情索引」的原章节列定位。
> **维护**:本文件与 `../SKILL.md` 的指针行成对;改内容时同时核对主文件的指针描述是否仍准确。
---
### 正确调用(Windows,2026-09-11 实测可用)
```bash
export PATH="/c/Users/Administrator/.local/bin:$PATH" # 全局 console script 在这个目录
export BU_CDP_URL="http://127.0.0.1:9223" # 指向独立 headless 实例
env -u HTTP_PROXY -u HTTPS_PROXY -u http_proxy -u https_proxy NO_PROXY="127.0.0.1,localhost" \
browser-harness <<'PY' # helper 已预导入;⛔ 别裸调 python -m
print(page_info())
PY
# 本 checkout(E:/ProgramData/.workbuddy/skills/browser-harness/)另有 dev 启动器:./browser-harness
# 🔴 2026-09-25 实测更正:旧写法 R="C:/Users/Administrator/.workbuddy/skills/browser-harness" +
# "$R/.venv/Scripts/python.exe -m browser_harness.run" **已作废** —— C: 侧该目录不存在、本机 checkout 里也没有 .venv。
```
helper:`js / click_at_xy / type_text / fill_input / press_key / switch_tab / close_tab / capture_screenshot / list_tabs / wait`。
### ⛔ dsh composer(Lexical)输入难点(2026-09-11 未攻克)
- composer 真身:`div[contenteditable="true"][data-lexical-editor="true"][data-composer-input="true"]`(class `uV2eYG_input`)。
- `type_text()` = `Input.insertText` → **绕过框架监听**,Lexical 模型不更新 = 没输入。
- `fill_input()`(逐字符 `press_key` + `input/change`)实测**也未生效**。
- 真因:**目标标签不是前台标签** → `el.focus()` 后 `document.activeElement` 仍是 `BODY`,CDP 鼠标/键盘到不了该标签;
`switch_tab` + `ensure_real_tab` + `Page.bringToFront` 都没解决。
- **对照**:Playwright 的 `page.click()` + `page.keyboard.type()` **成功过**(能真实发出消息并拿到回复)。
→ 结论:**要在独占浏览器里跑**(不与用户标签争前台);**传输层 bug 一律用 curl 验证**,浏览器只用于视觉/交互确认。
⚠️ **工具选择口径(🔴 2026-09-25 用户明令 —— 这条优先于下面所有旧实测)**:
**只允许一件工具** —— `browser-harness`(路径与调用见上)。此前「两件(含 `agent-browser`)」的口径**作废**。
⛔ **Playwright / `playwright-core` 全面禁止**(用户 2026-09-13 明令)。
本机现状:`agent-browser` 的 daemon **起不来**(2026-09-13 实测:`open` 挂住零输出,而 `--version` / `node -e` 正常;Chrome 153 已装)
⇒ **该件已禁用**(见上条),此段只作背景。
`browser-harness` **必须用下面「独立 headless 实例」那套**(至少先 `list_tabs()` 确认),绝不附着用户日常 Chrome。
拿不到浏览器时,**静态页与 API 取数一律用 `curl`/`WebFetch`**,UI 结构用「无浏览器 harness」验收(见阶段 4 第 8 条三层验收)。
⛔ **`agent-browser` 2026-09-11 实测记录(该件**已禁用**;此段仅作历史背景,❌ 不得据此恢复使用)**:
① 自带 Chromium 要从 `storage.googleapis.com` 下 196MB → **必然超时失败**;
② 改用本机 Chrome + `--cdp` 时,环境里有 `HTTP_PROXY=http://127.0.0.1:2349`(WorkBuddy 服务代理),
CLI 连 `127.0.0.1` 的 CDP **也走代理** → `Timeout connecting to CDP`
(要先 `env -u HTTP_PROXY -u HTTPS_PROXY -u http_proxy -u https_proxy NO_PROXY="127.0.0.1,localhost"` 才通);
③ 即使通了,**标签/会话状态不一致**:`tab list` 显示 `[t1] about:blank`,而 `get url` 报 `login.html`;
`open <实例子域>` 不生效。→ **要浏览器就用下面这套 browser-harness**。
**核心教训:不要用用户日常 Chrome。** 直接 `new_tab` 到用户正在用的浏览器会反复弹「允许远程调试?」——用户会烦。根因:**绕过 wrapper / 启动器**(直接用 `python -m browser_harness.run`)就不会设 `BH_RUNTIME_DIR_SHARED=1`,daemon 无法常驻复用 → 每次调用新建连接 → **每次弹一次授权**。⇒ 2026-09-25 起**统一走全局 console script `browser-harness`**(或本 checkout 的 `./browser-harness`),⛔ 不再裸调 `python -m`。
**定型做法 = 起独立 headless 实例(零弹窗、不碰用户浏览器、cookie 隔离)**:
```bash
# ① 一次性启动(后台常驻;PATH 必须先修好,否则 rm/node 会失败导致 Chrome 根本没起)
export PATH="/e/ProgramData/.workbuddy/binaries/PortableGit/versions/1.2.0/usr/bin:/e/ProgramData/.workbuddy/binaries/PortableGit/versions/1.2.0/mingw64/bin:/c/Windows/System32:/c/Windows:$PATH"
"/c/Program Files/Google/Chrome/Application/chrome.exe" \
--headless=new --remote-debugging-port=9223 --remote-allow-origins='*' \
--user-data-dir='C:\Users\Administrator\AppData\Local\Temp\chrome-bh-dsh' \
--no-first-run --no-default-browser-check --no-proxy-server --disable-gpu about:blank
# ② 探活:curl -s --noproxy '*' http://127.0.0.1:9223/json/version
```
```bash
# ③ 每次验证(把 python 脚本写成文件后重定向进 stdin,避免 heredoc 引号地狱)
export PATH="/c/Users/Administrator/.local/bin:$PATH"
export BU_CDP_URL="http://127.0.0.1:9223"
browser-harness < "E:/<你的工作区>/tmp/shot.py" # 或 heredoc;脚本走 stdin
```
**登录态**:DB 直插临时 session(`user_agent=poc-ui`,用后即删),取 token 后
`cdp("Network.setCookie", name="sid", value=TOKEN, domain=".ai1net.com", path="/", secure=True)` → `Page.reload`。
用户侧真实浏览器完全不受影响(不覆盖其 sid)。
**三个必踩坑**:
- **`Emulation.setDeviceMetricsOverride` 按 target 生效** → 必须**先 `new_tab` 再设覆盖**;设在旧标签上再开新标签 = 覆盖丢失(截图只有 758×482)。
- **hash 残留会骗人**:页面停在上次的 `#/plugins/manual`,重载后目标元素不存在 → `js()` 返回 null / 元素测量得 `0/0`。**验证脚本必须显式导航到目标 tab**。
- **Chrome 必须先 `--headless=new` 前台跑通再加后台**;后台启动失败时先看 task 输出(常见是 PATH 未设导致前置 `rm` 失败,`&&` 短路,Chrome 从未执行)。
- 收尾:临时 session 删除;独立 Chrome 可留着复用(内存小),要停就 kill **9223** 端口对应进程。