关于 chrome-relay
Chrome Relay 是通过浏览器扩展和本地原生主机控制真实 Chrome 的 Agent 命令行工具。它可面向已登录的浏览器配置文件,并提供页面检查、交互、网络数据查看和文件上传命令。
主要功能
- 01将命令路由到浏览器配置文件
- 02通过可操作引用检查页面
- 03点击、填充、输入和导航
- 04等待页面条件并查看变化
- 05捕获截图和网络数据
- 06通过不同策略上传文件
适用场景
- 01自动执行已登录浏览器会话中的任务
- 02检查并操作网页
- 03在多个 Chrome 配置文件间工作
- 04通过浏览器表单上传文件
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ kiluazen/ kstack --skill chrome-relay安装后在 Claude Code 中输入/chrome-relay确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
README.mdreferences/patterns.mdtroubleshooting.md详细介绍
Chrome Relay
通过 Chrome 扩展 + 本地原生主机驱动用户的真实 Chrome。需要登录状态的浏览器数据(身份验证 Cookie、会话、已安装的扩展)时,优先使用它。
设置
- Chrome 扩展
- CLI:
npm install -g chrome-relay@latest chrome-relay install chrome-relay --version chrome-relay doctor
使用最新的 CLI。多浏览器/配置文件路由和上传功能要求版本 >= 0.8.0;Dia 检测和适合 Agent 的配置文件选择器要求版本 >= 0.8.1。如果安装后显示的版本仍低于 0.8,请先停止操作并解决 PATH 中的过时二进制文件,再使用 0.8 版命令:
chrome-relay --version
which -a chrome-relay # macOS/Linux; use `where chrome-relay` on Windows
在会话开始时,运行 chrome-relay profile list。如果只有一个已连接实例,普通命令无需配置文件标志。如果有多个实例,这条命令会准确告知你可访问哪些浏览器和配置文件,供你在操作前确认。
核心循环
chrome-relay tabs # find or create a tab
chrome-relay navigate "https://kushalsm.com" --new # background tab by default
chrome-relay snapshot --tab 1234 -i # see the page: actionable elements get @refs
chrome-relay click @e12 # act on refs, no --tab, no selector
chrome-relay fill @e14 "hello"
chrome-relay wait --text "Saved" --tab 1234 # block until the page reacts
chrome-relay snapshot --tab 1234 --diff # print only what changed (~100 tokens)
快照输出是精简的缩进文本,大多数页面通常为 1 到 15 KB。直接阅读即可,无需使用 jq:
- link "Hacker News" [ref=e4]
- textbox "Search" [ref=e41]: current value
- checkbox "Remember me" [checked, ref=e42]
- clickable "Open card" [ref=e88] # cursor-pointer div the AX tree missed
引用自带其所属标签页。 click @e12 会在生成 e12 的标签页上执行操作,而非活动标签页。即使用户继续浏览,也能安全使用。如果与之矛盾的 --tab 会导致错误 target_conflict。
引用的有效期。 引用在同一页面的 DOM 变化期间仍然有效(缓存的 backendNodeId;节点被替换时会通过角色 + 名称重新查找并恢复),但在真正导航后会失效。失效的引用会返回 error.code = stale_ref。请重新运行 snapshot。
拦截。 引用点击前会先对目标点进行命中测试。如果覆盖层 / 粘性页眉 / 模态框占据该位置,就会返回 error.code = click_intercepted 并指出拦截元素。请将其关闭或滚动页面,然后重试。点击并未执行。fill/type 不会进行此项检查(被遮挡的输入框仍可写入)。
工具一览
| 命令 | 功能 |
|---|---|
tabs | 列出窗口和标签页及其 tabId |
navigate <url> | 在当前标签页中打开。--new 会在后台标签页中打开(默认)。--active 会将其切换到前台。--tab <id> 可指定现有标签页。 |
snapshot --tab <id> -i | 获取包含可操作 @refs 的页面快照:无障碍树加上光标交互式扫描,共用一个 ref 空间,并使用紧凑文本。-d N 限制深度,-s <css> 将范围限定到子树,-u 包含 href,--diff 仅输出自上次快照以来的更改,--json 输出包含 refs 映射的结构化封装。 |
wait <css|@ref> / wait --text / --url <glob> / --load networkidle / --fn <js> | 阻塞直到条件成立(每次调用一个条件,默认 10s,最多 25s)。wait 1500 只会休眠。超时错误会包含当前页面状态。 |
get text|value|attr|count|title|url <target> | 获取单个值,直接输出到 stdout。不获取完整快照。get text @e12、get attr @e7 href、get count ".row"。 |
batch '[{"name":"chrome_...","args":{...}}, ...]' | 在一轮往返中按顺序调用 N 个工具,默认遇错即停。使用底层工具名称。 |
skills get core | 打印此操作手册,版本与已安装的二进制文件匹配。 |
click <@ref | selector> --tab <id> | 在元素中心执行可信的悬停、按下和释放(pointerType: "mouse")。Ref 无需 --tab。 |
click --x N --y N --tab <id> | 坐标模式点击,适用于没有 DOM 句柄的 canvas/SVG 图表内部。 |
hover <@ref | selector | --x --y> | 仅移动指针。触发 :hover 样式。 |
fill <@ref | selector> <value> | 将值原子式写入 <input>/<textarea>/<select>。绕过 React 的值跟踪器。Ref 可访问 shadow DOM 内部(选择器无法访问)。 |
type <text> [-s <@ref | selector>] | CDP Input.insertText。适用于 contenteditable / Draft.js / Lexical / ProseMirror。会在插入点追加;如果输入框已有内容,请先清空。 |
keys <chord> --tab <id> | 单个按键或组合键:Enter、Tab、Escape、Cmd+K、Shift+ArrowDown。 |
js <code> --tab <id> | 在 MAIN world 中执行 Runtime.evaluate。使用 return 返回值。支持顶层 await。 |
screenshot --tab <id> -o <path> | PNG。--full 可截取视口以外的内容。--max-edge N 可调整尺寸。 |
screencast --tab <id> -o <path> | 通过 CDP 录制标签页(由绘制事件驱动)。需要活动标签页。 |
network --tab <id> | 每个标签页最近 200 条 HTTP 请求/响应的环形缓冲区。Chrome 仍保留请求正文时,network body <requestId> 可获取正文。network har --with-bodies 可导出包含正文的 HAR。 |
console --tab <id> | 最近 200 条 console.log/warn/error 和页面异常。 |
viewport | 模拟设备视口、DPR、移动设备标志、触控和 UA。 |
workspace / group | 管理命名窗口 / 标签页组,以便多个 Agent 分别操作不同窗口。 |
switch <tabId> / close <tabIds...> | 激活或关闭标签页 |
self-reload | 重建后重启扩展的 service worker |
release-notes --since <ver> / update | 可查询的更新日志;Agent 可读取 JSON。 |
call <tool> [json] | 对任意内部工具进行原始透传调用。 |
read / ax / click-ax | 已弃用。分别是 snapshot / click @ref 的别名。将被移除;新工作中请勿使用。 |
选择合适的文本工具
| 目标元素 | 工具 |
|---|---|
<input>、<textarea>、<select>(包括由 React 控制的元素和 shadow DOM) | fill @ref |
[contenteditable]、role="textbox"、Draft.js / Lexical / ProseMirror、X 撰写框、LinkedIn 私信、新版 Reddit 撰写框 | type |
| 提交、导航菜单、修饰键快捷键 | keys |
| 组合框 / 自动完成选项选择 | 在筛选框中使用 type,然后使用 keys ArrowDown,再使用 keys Enter(原因) |
| 框架内部操作、抓取数据、自定义控件 | js |
多个浏览器和配置文件(CLI >= 0.8)
主要支持的目标是 Google Chrome(包括多个 Chrome 配置文件)、Dia 和 Brave。一个 CLI 可访问所有已连接且安装了扩展程序的实例;每个 Chrome 配置文件都是一个可单独寻址的实例。
安装程序还知道 Chrome Canary、Chromium、Edge、Vivaldi、Arc 和 Opera 的原生主机清单路径。除非当前任务已验证,否则请将它们视为兼容性目标;不要声称仅凭检测到清单就能证明浏览器得到全面支持。
请在每个希望能够访问的浏览器/配置文件中安装一次扩展程序,然后运行一次 chrome-relay install,以便每个检测到的浏览器都能启动自己的主机。
chrome-relay profile list # who's connected: label, browser, id prefix
chrome-relay profile label work # one connected: label it directly
chrome-relay --profile 3f2a profile label personal # several: first pick by id prefix
chrome-relay --profile work tabs # scope any command (global or per-command flag)
chrome-relay click @3f2a:e12 # snapshot refs are profile-qualified and route by THEMSELVES
连接了一个实例:无需标志,所有操作都会自动路由。连接了多个实例:未指定范围的命令会以 profile_ambiguous 失败。将此错误视为选择器:从错误中选择一个准确的 --profile <label|idprefix> 条目,然后重新运行命令。它绝不会自行猜测。引用会像携带标签页信息一样携带配置文件信息,因此执行一次 snapshot 后,你通常不再需要这个标志。使用 chrome-relay profile unlabel <name> 释放过期标签。
上传(CLI >= 0.8)
有三种策略,不会自动回退——失败信息会指出所用策略,请选择下一种策略:
chrome-relay upload set --selector 'input[type=file]' --tab 123 ./cv.pdf # direct; works on HIDDEN inputs
chrome-relay upload choose --click-ref @e4 ./cv.pdf # trigger opens the OS picker: intercepted, NO dialog appears
chrome-relay upload drop --selector '.dropzone' ./avatar.png
文件使用路径——Chrome 会自行读取,没有大小限制。遇到 not_a_file_input → 使用 choose。遇到 no_file_chooser → 触发方式错误,或者这是一个拖放区域。遇到 file_access_denied → 前往 chrome://extensions → Chrome Relay → “Allow access to file URLs”。set/choose 会返回调用后输入框实际保存的内容。
元素寻址:回退顺序
- 来自
snapshot -i的@ref:默认方式。适用于按钮/链接/输入框、有名称的内容、带 cursor-pointer 的 div 集合(扫描结果)以及影子 DOM。 - CSS 选择器:已知静态选择器且不需要快照时使用。
- 先用
js探查,再按坐标点击:适用于 canvas 内部元素和 SVG 图表分段(匿名<path>元素在任何地方都没有 DOM 句柄):chrome-relay js --tab 1234 "const r = document.querySelector('svg path').getBoundingClientRect(); return {x: r.x + r.width/2, y: r.y + r.height/2}" chrome-relay click --tab 1234 --x 312 --y 218
不要轮询。使用等待。
每次操作后都获取快照会浪费轮次。对于不断变化的页面,可使用以下轻量循环:
chrome-relay click @e12
chrome-relay wait --text "Saved" --tab 1234 # or wait <selector> / --url / --load
chrome-relay snapshot --tab 1234 --diff # only the changes, refs included
常见注意事项
- **
snapshot -i用于执行操作,而非提取事实。**它只会输出带引用的元素。非交互式值(仪表板指标、段落文本、图表标签)会被省略。实测中,Cloudflare Pages 指标页面在-i模式下所有数字都消失了。要读取事实,请使用完整的snapshot、get text <target>或js投影。 - **
type会追加内容。**它会在光标处插入。如果输入框已有值(自动保存的草稿、默认文本),请先通过js或keys清除(Cmd+A 后按 Backspace)。 - 页面导航后引用会失效。
stale_ref表示页面在此期间发生了变化;请重新获取快照。不要重试同一个引用。 - **坐标很快就会过期。**读取
getBoundingClientRect后,页面滚动或重排,再点击就可能点错元素。尤其是自动补全弹窗,请使用键盘导航,不要按坐标点击。 - **点击“成功”,但什么都没发生。**首先诊断:
document.elementFromPoint(x, y)。如果返回的是包装元素或表单背景,说明坐标错误。如果返回正确的元素,但状态没有改变,你可能正在使用低于 0.5.20 的 chrome-relay。请升级。
更多操作示例:references/patterns.md
故障模式:references/troubleshooting.md
操作指南
- 不要过早放弃。 点击失败是有用信息,不是停止信号。添加一个
capture:true的文档级监听器,并观察触发了什么:chrome-relay js --tab 1234 " ['pointerdown','mousedown','click'].forEach(t => document.addEventListener(t, e => console.log(t, e.target.tagName, e.target.className), {capture:true}) ); return 'listening' " # do the action, then: chrome-relay console --tab 1234 - 不要回显密钥。 通过
js提取令牌 / API 密钥时,直接将结果写入文件。切勿执行echo $TOKEN或将其插入 shell 字符串。它会出现在滚屏内容、日志和工具记录中。 - 对
network输出进行脱敏。 请求 / 响应标头包含 Cookie、身份验证 / CSRF 令牌、账户和项目 ID。切勿将原始chrome-relay network输出粘贴到聊天、文档、问题或提交中。仅筛选所需字段(url、status、timings),或先对标头进行脱敏。 - 执行不可逆操作前先截图(提交表单、发送消息、更改账户)。保存截图路径。
防护措施
- 错误采用结构化格式:根据
relayError.code(stale_ref、click_intercepted、element_not_found、target_conflict、profile_ambiguous、timeout)进行分支判断,而不是根据消息文本判断。 - 如果标志不明确,以
chrome-relay <command> --help为准。这些文档可能不是最新的。