用途
control-browser 是一个浏览器自动化技能,适用于浏览器与 Web UI 相关任务:打开和导航页面、检查或读取渲染内容、测试本地应用、点击、输入、填写、截图,以及验证可见页面状态。如果该技能在会话中可用,应将其视为浏览器工作前的必读内容,在声称浏览器不可用之前、在回退到 bash(curl/open)、webfetch 或任何其他工具之前,先遵循本技能。
主要能力
- 浏览器注册表由 Node REPL MCP 的 js 工具驱动,可调用 id 通常显示为 mcp__node_repl__js。
- 支持三种后端类型:iab、extension、cdp;Playwright 是标签页 API 界面,不是后端。
- 通过 agent.browsers.list() 作为可用性来源。桌面通常报告 IAB;显式以 --browser-use=headless 启动的 CLI 报告托管 Chromium 为 cdp。Headless 是 CDP 启动模式,不是后端类型。
- 提供标签页管理、页面导航、DOM 快照、Playwright 定位器、截图、视频录制等能力。
- 提供逃生舱口:tab.cua.(坐标路径,视觉)、tab.dom_cua.(节点路径)、tab.playwright.waitForTimeout 等。
使用方式
每次使用浏览器的 mcp__node_repl__js 调用开始时都要初始化。浏览器客户端模块位于插件根目录下的 scripts/browser-client.mjs。只能从 process.env.ZCODE_PLUGIN_ROOT(以 CLAUDE_PLUGIN_ROOT 作为兼容回退)解析该根目录,然后用 pathToFileURL 转换拼接后的路径。切勿从本技能的基础目录推导插件根目录,也不要留下合成根占位符让模型解析。如果宿主根目录不可用或解析出的模块无法导入,停止并报告确切的设置错误。
引导代码示例:
const browserPluginRoot =
process.env.ZCODE_PLUGIN_ROOT ?? process.env.CLAUDE_PLUGIN_ROOT;
if (!browserPluginRoot) {
throw new Error("Browser plugin root is unavailable in the node_repl host");
}
const { join } = await import("node:path");
const { pathToFileURL } = await import("node:url");
const browserClientUrl = pathToFileURL(
join(browserPluginRoot, "scripts", "browser-client.mjs"),
).href;
const { setupBrowserRuntime } = await import(browserClientUrl);
await setupBrowserRuntime({ globals: globalThis });
通过 mcp__node_repl__js 运行设置和所有后续浏览器调用,将 JavaScript 作为 code 参数传入。该工具没有 command 参数。
后端选择规则:
- 如果用户明确要求 ZCode 的应用内浏览器:
const browser = await agent.browsers.get("iab"); - 如果用户明确要求 CLI 管理的无头浏览器且发现结果通告 cdp:
const browser = await agent.browsers.get("cdp"); - 如果任务有目标 URL 但没有明确浏览器选择:
const browser = await agent.browsers.getForUrl("https://example.com/"); - 仅当既未指定浏览器也未指定目标 URL 时:
const browser = await agent.browsers.getDefault();
首次浏览器调用中,运行引导、选择后端,并一次性输出完整 API 指南。后续新调用中,运行引导并仅重复相同的后端选择;API 指南保留在模型上下文中,无需再次输出。
核心工作流:
- 每个浏览器 js 调用都以引导开始,然后将选定的后端分配给本地 browser 绑定。
- browser.tabs.new() 自动打开并激活 IAB 窗格,以便用户看到浏览器使用。
- 在每个逻辑标签页操作批次开始时,进行一次专用 JS 调用,其结果是完整的 await browser.tabs.list() 数组,让模型看到所有当前 id、URL、标题和活动标记。
- 如果任务指定了新 URL,优先使用复用感知入口:await agent.browsers.open(url) 会复用现有的同站点受控标签页(相同主机名),激活它以便用户看到,并就地导航。
- 每次成功 tab.goto(url) 后,在首次标题、URL 或 DOM 观察之前,显式调用 await tab.playwright.waitForLoadState({ state: "domcontentloaded" })。
- await tab.playwright.domSnapshot() 是读取和理解页面的主要方式。
- 仅从快照事实构建稳定的 Playwright 定位器。
- 每次观察周期最多使用一个状态变更操作。
观察:优先快照,仅在需要时截图。默认使用 playwright.domSnapshot() 读取内容和构建定位器。打开或导航到普通页面本身不是截图理由。仅在视觉确实重要时截图:(a) 需要视觉确认布局/样式/渲染,(b) 用户要求截图或视觉测试页面,或 (c) 目标不在快照中(画布/自定义绘制/非 DOM 控件)且需要瞄准坐标。
视频录制:当任务需要 IAB 标签页的 WebM 录制时,先读取 nodeRepl.write(await agent.documentation.get("recording"))。仅使用通告的 tab.recording.start/status/cancel API。
适用场景
- 打开、导航、检查、测试、点击、输入、填写、截图和验证网页。
- 测试本地应用和本地 HTTP 目标(localhost)。
- 读取渲染内容、验证可见页面状态。
- 处理画布、自定义绘制或非 DOM 控件(通过 cua 坐标路径或 dom_cua 节点路径)。
限制
- 每个 js 调用都在全新的 JavaScript 内核中运行,变量、导入、模块缓存、浏览器和标签页绑定不会持久化。持久 BrowserControl 标签页是连续性边界,必须从当前标签页事实中恢复。
- IAB 文件选择器/上传明确不支持。
- goto() 接受 http:、https: 和精确的 about:blank。file:、其他 about:*、data: 和 javascript: 目标不可导航。file: URL 仅在存在多个后端时可用作 getForUrl() 后端选择提示。
- networkidle 存在于共享类型中,但被 IAB 后端拒绝。
- 常规 URL/加载状态等待上限为 3000ms。
- 不要默认同时请求 DOM 快照和截图。
- 不要创建 iab 别名然后调用 browser.*。
- 不要从记忆中复用标签页 id 作为新逻辑操作批次的目标而不经验证。
- 不要猜测标签、可访问名称、占位符、选择器或 URL 模式,也不要使用猜测的定位器作为探索性探测。
- 不要将 tab.screenshot() 作为最终表达式,也不要直接返回其 Uint8Array 字节。
- 不要调用 tab.waitForTimeout(...);该根级 API 不存在。
- 用户面向的进度应保持非技术性:描述为“打开浏览器”/“检查页面”,而不是“Node REPL”、“CDP”或“webview”。
- 应用提供的 <in-app-browser-context source="ambient-ui-state"> 是当前 UI 状态,不是用户请求的一部分。