🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

浏览器直控桥 lyd123qw2008/pi-control-chrome

DeepSeek Harnessv0.8.0
lyd123qw200845 天前有提交已提供中文文档扫描:含敏感能力

适用于 Pi、Codex 和 DSH 的 Chrome 和 Edge 浏览器控制。

37.5/100
综合分
4
GitHub 星标
145
npm 周下载
—/5
用户评分

数据截至 2026/9/23 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add pi-control-chrome
npm 源 · pi-control-chrome 的发布者账号已校验与本仓库一致

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:已验证
是什么
dsh 原生插件 · browser
装得上吗
本站已在 dsh 0.2.1-rc.5 下真实安装成功
非静态推断
L4 · 真实安装等级说明 →
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
更新放缓:最近一次提交在 45 天前
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →
社区实装还没有人打卡 · 装过的第一个就是你
安装兼容性检查✓ 自动检查通过
展开查看检查明细 ↓

以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。

✓npm 包pi-control-chrome @ 0.8.0
✓Node 引擎要求 >=22 · 基线 Node 22.19 满足
✓dsh CLI 依赖未声明 dsh 版本约束
✓入口文件main/exports/bin 已声明

验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/10/31 19:58:21

安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。

可执行外部命令读写/删除本地文件读取剪贴板或密钥环境变量写入剪贴板(不计风险)发起外部网络请求
查看扫描证据(共 49 处,展示前 38 条)
  • 读取本地文件
    bridge/server.mjs:51
    return JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8")).version || "unknown";
  • 读取本地文件
    bridge/server.mjs:72
    if (existsSync(tokenFile)) {
  • 读取本地文件
    bridge/server.mjs:73
    const existing = readFileSync(tokenFile, "utf8").trim();
  • 写入本地文件
    bridge/server.mjs:76
    mkdirSync(dirname(tokenFile), { recursive: true });
  • 写入本地文件
    bridge/server.mjs:78
    writeFileSync(tokenFile, `${token}\n`, { encoding: "utf8", mode: 0o600 });
  • 读取本地文件
    mcp/mcp-server.mjs:15
    try { return JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8")).version || "unknown"; } catch { return "unknown"; }
  • 读取密钥环境变量
    mcp/mcp-server.mjs:30
    const TOKEN_FILE = process.env.PI_CONTROL_CHROME_TOKEN_FILE || join(process.env.USERPROFILE || process.env.HOME || process.cwd(), ".pi", "agent", "pi-
  • 发起网络请求
    mcp/mcp-server.mjs:520
    const response = await fetch(`${BRIDGE_ORIGIN}/health`, { signal: AbortSignal.timeout(1_500) });
  • 执行外部命令来自配置/变量
    mcp/mcp-server.mjs:556
    const child = spawn(process.execPath, [
  • 发起网络请求
    mcp/mcp-server.mjs:716
    const result = await client.request("status", { ...params, browserId: args.browserId, acknowledgeBrowserId: args.acknowledgeBrowserId }, requestTimeou
  • 发起网络请求
    mcp/mcp-server.mjs:746
    const cleanupResult = await client.request("cleanup", params, requestTimeout(args, "cleanup"), signal);
  • 发起网络请求
    mcp/mcp-server.mjs:747
    await client.request("target_lease", withSession({ action: "release_session" }), requestTimeout(args, "target_lease"), signal);
  • 发起网络请求
    mcp/mcp-server.mjs:752
    return client.request(spec.method, params, requestTimeout(args, spec.method), signal);
  • 写入本地文件
    mcp/mcp-server.mjs:790
    mkdirSync(dirname(path), { recursive: true });
  • 写入本地文件
    mcp/mcp-server.mjs:791
    writeFileSync(path, Buffer.from(data, "base64"));
  • 发起网络请求
    mcp/mcp-server.mjs:839
    await bridgeClient.request("cleanup", withSession({ mode: "context" }), 5_000);
  • 发起网络请求
    skills/pi-control-chrome/scripts/browser.mjs:98
    const response = await fetch(`${BRIDGE_ORIGIN}/health`, { signal: AbortSignal.timeout(3_000) });
  • 发起网络请求
    skills/pi-control-chrome/scripts/browser.mjs:104
    const response = await fetch(`${BRIDGE_ORIGIN}/pair`, { signal: AbortSignal.timeout(3_000) });
  • 发起网络请求
    skills/pi-control-chrome/scripts/browser.mjs:480
    return client.request("list_tabs", { responseMode: raw ? "raw" : "compact" });
  • 发起网络请求
    skills/pi-control-chrome/scripts/browser.mjs:509
    const created = await client.request("new_tab", { url, active, sessionId, wait: true, timeoutMs }, rpcTimeoutMs);
  • 发起网络请求
    skills/pi-control-chrome/scripts/browser.mjs:537
    const snapshot = await client.request("snapshot", { ...target, ...observationOptions, responseMode });
  • 发起网络请求
    skills/pi-control-chrome/scripts/browser.mjs:539
    const extracted = await client.request("extract", { ...snapshotTarget, ...observationOptions, responseMode });
  • 写入本地文件
    skills/pi-control-chrome/scripts/browser.mjs:557
    mkdirSync(dirname(target), { recursive: true });
  • 写入本地文件
    skills/pi-control-chrome/scripts/browser.mjs:558
    writeFileSync(target, Buffer.from(captured.data, "base64"));
  • 写入本地文件
    skills/pi-control-chrome/scripts/browser.mjs:727
    mkdirSync(dirname(target), { recursive: true });
  • 写入本地文件
    skills/pi-control-chrome/scripts/browser.mjs:729
    writeFileSync(target, data);
  • 发起网络请求
    extension/background.js:1212
    const response = await fetch(`${BRIDGE_ORIGIN}/pair`, { cache: "no-store" });
  • 读取剪贴板
    extension/background.js:8618
    ? await executeInTab(tabId, async () => navigator.clipboard.readText(), [], expectedFence)
  • 写入剪贴板
    extension/background.js:8620
    await navigator.clipboard.writeText(String(nextText ?? ""));
  • 发起网络请求
    pi-extension/index.ts:132
    const response = await fetch(`${origin}${path}`, { signal: AbortSignal.timeout(timeoutMs) });
  • 发起网络请求
    pi-extension/index.ts:305
    const control = await this.request("bridge_restart", {
  • 读取本地文件
    pi-extension/index.ts:371
    if (!existsSync(bridgePath)) throw new Error(`Missing Pi browser bridge: ${bridgePath}`);
  • 执行外部命令来自配置/变量
    pi-extension/index.ts:373
    const child = spawn(process.execPath, [
  • 发起网络请求
    pi-extension/index.ts:611
    const request = () => route === undefined ? bridge.request(method, params, undefined, signal) : bridge.request(method, params, route, signal);
  • 发起网络请求
    pi-extension/index.ts:621
    return await bridge.request(method, params, { browserId: route.browserId }, signal);
  • 发起网络请求
    pi-extension/index.ts:1427
    const result = await bridge.request("reload_extension", {
  • 写入本地文件
    pi-extension/index.ts:1899
    await mkdir(dirname(savedPath), { recursive: true });
  • 写入本地文件
    pi-extension/index.ts:1900
    await writeFile(savedPath, Buffer.from(result.data, "base64"));
扫描于 2026/11/3(0 天前) · 范围 入口闭包 + 全包扫描 · 来源 npm 发布包

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

功能亮点

  • 驱动真实配置档与标签页
  • 原生CDP与AX语义

为 Pi、Codex 和 DSH 提供 Chrome 与 Edge 浏览器控制。通过 MV3 扩展和本地回环 Bridge 驱动你真实的浏览器配置档、登录状态和标签页——原生 CDP,AX 优先语义,无需另开浏览器。

v0.8.02026-09-19
· 亮点 · 本地 MCP 适配器从 codex/ 改名为 mcp/。已发布的包保留 ./codex/mcp-server.mjs 导出和 pi-control-chrome-codex 可执行文件作为兼容别名,并新增 pi-control-chrome-mcp。 · 通用 MCP 客户端现在默认收到完整的 44 项浏览器操作目录。Codex 仍通过 .mcp.json 中指定的 PI_CONTROL_CHROME_TOOLS=codex 模式,有意限制为 13 个模型可见工具。 · 未限定选择器的快照现在会短暂采样仍在加载的顶层文档:已稳定的后续结果带 settleSamples;仍处于加载状态但结果一致的带 unsettled: true。限定选择器的快照仍由调用方自行判断就绪状态。 · 根目录与随包分发的 DSH 技能已同步,包括新的快照约定和 mcp/ 适配器位置。 · 已发布内容 | 发布面 | 版本 | | --- | --- | | Pi 根包 | pi-control-chrome@0.8.0 | | Manifest V3 扩展 | 0.8.0 | | DSH 配套包 | @lyd123qw2008/dsh-tool-control-chrome@0.8.0 | 根包和配套包均从提交 a6d6680 发布。 · 验证 · CI push 门禁和 Compatibility push 门禁在确切的发布提交上通过,包括隔离的 Chrome/Edge 矩阵。 · 根包 Trusted Publishing 和 DSH 配套包 Trusted Publishing 均通过。 · 注册表元数据确认两个根可执行入口:pi-control-chrome-mcp 和兼容别名 pi-control-chrome-codex,二者都指向 mcp/mcp-server.mjs。 · 可复用的配置档更新以 dsh-profile-config#19 合并:其 lockfile 将 DSH 配套包和传递依赖的根包都解析为 0.8.0。 · 当前生效的 DSH 配置档已固定 pi-control-chrome@0.8.0;其冻结安装和组合配置档导出确认了已安装的 mcp/mcp-server.mjs node-repl 服务商路径。 · 升级说明 当前生效的配置档直接通过 node-repl cap.chrome 服务商使用 pi-control-chrome,因此有意固定根包,而不是挂载配套的 DSH 插件。本次发布期间没有重启任何 DSH 进程。请手动重启 DSH,以加载更新后的生效配置档和服务商配置。
v0.6.22026-09-15
· v0.6.2 — 继承来的标签页终于能真正关掉了 补丁版本,把 0.6.1 开了头的事做完。0.6.1 让关闭、释放和清理能跨扩展运行时世代,但它们仍拿实时标签页围栏去比对归属记录里存的围栏——而被替换的运行时按定义就复现不出那个围栏。于是真正遗留的标签页照样回 BROWSER_TAB_FENCE_CHANGED,依旧关不掉:同一堵墙,只是深了一层检查。实测看到,记录里带的是 tab:bb6803dd…,新运行时报的却是 tab:d0f05bd3…。 关闭、释放或清理继承来的 Agent 记录时,现在改用 tabId 加上本会话自己的归属记录来识别标签页,并用当前运行时实际观测到的围栏。用户主动认领的标签页仍按更严格的规则处理,绑定文档的操作依旧以 BROWSER_TAB_RUNTIME_INHERITED 失败关闭,并指明可行的退出方式。 · 版本 | 层面 | 版本 | | --- | --- | | pi-control-chrome | 0.6.2 | | extension/manifest.json | 0.6.2 | | @lyd123qw2008/dsh-tool-control-chrome | 0.6.2(依赖 pi-control-chrome@^0.6.0) | | Codex 插件清单 | 0.6.2 | · 验证 · 实测:重载 0.6.2 扩展后,早先扩展运行时留下的标签页干净关闭(browser_close_tab → {"closed":1803052087})。 · 单元用例没给该记录注册围栏 token,这正是被替换运行时的样子。 · CI: · 兼容性: · 发布(Pi): · 发布(DSH): · npm: · npm: 当前 DSH 配置档链接的是本地检出,所以无需重装。
v0.6.12026-09-15
· v0.6.1 — 读取必须说明丢了什么,失败必须说明该怎么办 补丁版本:用真实页面验证 0.6.0 运行时后修掉三处行为问题,外加同一次验证中发现的恢复路径修复。 · 版本 | 层面 | 版本 | | --- | --- | | pi-control-chrome | 0.6.1 | | extension/manifest.json | 0.6.1 | | @lyd123qw2008/dsh-tool-control-chrome | 0.6.1(依赖 pi-control-chrome@^0.6.0) | | Codex 插件清单 | 0.6.1 | · 修复 · 第二次投影不再抹掉第一次的省略报告。Bridge 渲染一份紧凑响应,宿主再投影一次;重新投影时重算了自己的省略集合,于是一份实时 Jenkins 摘要返回 truncated: true 和 omitted: {}——不完整,却对缺了什么只字不提。现在上游的计数和指引会一并带过来,连续裁剪也会累加,因为它们是按不同来源计量的。同一个页面现在报告 omitted {"characters":6886,"controls":225,"regions":1},并给出下一步和恢复路径。 · 效果后等待会说明失败原因。waitForTabState 抛出的是不带错误码的异常,而另一条等待路径早已报告结构化的 BROWSER_WAIT_TIMEOUT,不确定性信封只能转发带错误码的失败。一次 navigate(wait: true) 遇到页面重定向(/git → /git/)现在报告 BROWSER_WAIT_TIMEOUT,附带 postEffectUrlMismatch 和 postEffectLoaded,这样重定向就能和标签页围栏变化区分开。页面 URL 和标题不会进入信封。 · 表格的形状不再被当成页面数据读取。图表图例的表头行曾发布 w: Description · %,单字符占位单元格曾发布 x: x。现在跳过表头行和单字符标签;真正的行头配对仍会发布。 · 会话能清理自己运行时的遗留。某个会话打开的标签页,一旦记录它的扩展运行时被替换,就会变得既读不了也关不掉。现在关闭它是调用会话自己的记账,browser_release 只丢弃记录、不碰标签页,browser_cleanup 关闭继承来的智能体标签页。被认领的用户标签页仍按更严格的方式处理,绑定文档的工作仍以 BROWSER_TAB_RUNTIME_INHERITED 失败关闭,并指明可用的退出方式。 · 验证 · CI: · 兼容性: · 发布(Pi): · npm: · DSH 配套包 · @lyd123qw2008/dsh-tool-control-chrome@0.6.1 从同一提交发布,声明 pi-control-chrome@^0.6.0(0.6.0 上的插入符已允许 0.6.1)。 · 发布(DSH): · npm: · 当前启用的 DSH 配置档链接的是本地检出,因此无需重装;维护者重启了 DSH,重启后的运行时检查通过(runtime.fresh: true,requiredCapabilityRevision 8,一份被截断的摘要报告了真实的省略计数)。 · 更正 本版本中「会话能清理自己运行时的遗留」这项修复并不完整:close、release 和 cleanup 仍在比对记录的标签页围栏,所以真正遗留的标签页直到 v0.6.2 移除该比对后才能关闭。要获得上述行为,请升级到 0.6.2。
数据来自仓库的 GitHub Release,可能与插件实际版本不一致。

README

由 DeepSeek 最新模型翻译生成
pi-control-chrome English · 简体中文 面向 Pi、Codex 和 DSH 的、与 Codex 对齐的 Chrome 和 Edge 浏览器控制。它通过本地 WebSocket Bridge 和 Manifest V3 扩展复用用户现有的 Chromium 配置文件。 Stage 1/2 核心实现已完成。后续阶段的能力仍单独记录在 FEATURES.md 中。 它提供什么 - 复用当前的 Chrome 或 Edge 配置文件、登录状态、cookie、扩展和标签页。 - 让 Pi 检查并认领明确选定的现有标签页,默认不移动它们。 - 将 Agent 创建的标签页放入专用的蓝色 Pi 标签组。 - 跟踪 Agent 所有权、会话、handoff 和 deliverable 生命周期状态。 - 在回合结束时关闭未标记的 Agent 临时标签页,释放已认领的用户标签页而不关闭它们,并仅保留为当前回合标记的 handoff 或 deliverable 标签页。 - 提供 DOM、无障碍、定位器、坐标和原生 CDP 控制。 - 默认返回有界的语义页面状态:可见/可操作的快照节点、20,000 字符/200 节点的快照和 DOM-CUA 预算,以及共享的 12,000 字符提取预算。
展开完整文档(README 剩余 1 节)
pi-control-chrome

English · 简体中文

面向 Pi、Codex 和 DSH 的、与 Codex 对齐的 Chrome 和 Edge 浏览器控制。它通过本地 WebSocket Bridge 和 Manifest V3 扩展复用用户现有的 Chromium 配置文件。

Stage 1/2 核心实现已完成。后续阶段的能力仍单独记录在 FEATURES.md 中。

它提供什么

- 复用当前的 Chrome 或 Edge 配置文件、登录状态、cookie、扩展和标签页。
- 让 Pi 检查并认领明确选定的现有标签页,默认不移动它们。
- 将 Agent 创建的标签页放入专用的蓝色 Pi 标签组。
- 跟踪 Agent 所有权、会话、handoff 和 deliverable 生命周期状态。
- 在回合结束时关闭未标记的 Agent 临时标签页,释放已认领的用户标签页而不关闭它们,并仅保留为当前回合标记的 handoff 或 deliverable 标签页。
- 提供 DOM、无障碍、定位器、坐标和原生 CDP 控制。
- 默认返回有界的语义页面状态:可见/可操作的快照节点、20,000 字符/200 节点的快照和 DOM-CUA 预算,以及共享的 12,000 字符提取预算。默认包含同源 iframe 文本,并带有有界的 frames 诊断信息;传入 includeFrames: false 可仅检查外壳。browser_snapshot 保留 refs 和 snapshotId,而 Pi/DSH 投影会省略重复的原始无障碍和 frameTree 数据;Bridge 会通告 capabilities.compactResponses 并协商紧凑的页面读取响应,而未指定模式仍保持与旧版消费者兼容的原始格式;当标签页元数据已携带标题和 URL 时,投影不会在页面结果中重复它们,并且在没有可用语义状态时,完整页面文本保留给 browser_extract。
- 无障碍读取优先使用真实的 Chromium AX 树,并支持完整、增量差异和未更改状态;可操作/可聚焦的 AX 节点可能携带文档作用域的 aN refs,这些 refs 需要匹配的 snapshotId 才能进行操作。敏感值在 AX 和定位器结果中保持脱敏。如果 Accessibility 域不可用,读取会安全回退到 DOM 语义树。仅在需要完整 AX 状态时传入 disableDiffing: true。快照、无障碍、提取和 DOM-CUA 读取接受可选的 selector、includeFrames 和输出预算。Pi 和 DSH 适配器在分发前会省略空的可选 selector、snapshotId、incarnation 和截图 path 字段。
- 普通的 role/name、label 和可访问文本定位器、等待和交互目标现在优先尝试 Chromium AX。AX 解析计算出的 role/name/state,然后在现有 document/frame 围栏下映射当前后端 DOM 节点;成功的操作将内部来源暴露为 resolvedBy: "chromium_ax"。AX 歧义、不完整的树和不安全的 DOM 映射会失败关闭。只有不可用的 Accessibility 域,或者自定义可点击元素在 AX 中缺失的纯文本目标,才会使用有界 DOM 回退;选择器、测试 ID 和占位符仍然由 DOM 驱动。
- 在通过 Bridge 返回之前,将 browser_evaluate 结果限制为深度 8、2,000 个数组项、200 个对象字段和 200,000 个字符。
- 支持截图、页面提取、Console、Network、JavaScript 对话框、文件上传、下载和剪贴板文本。Console 和 Network 列表每次读取最多保留 200 个条目和 20,000 个序列化字符;Console 读取支持有界的 only: "errors" 过滤以及 since/nextSince 游标,包括 pageerror 事件。
- browser_probe_interaction 只执行一个显式页面操作,并在返回前提供操作前后的文档身份、操作确认、操作后的 Console 错误、稳定状态以及操作后的目标状态,用于 UI 回归诊断。它绝不会重放不确定的副作用。
- 捕获普通活动标签页视口截图,而无需打开 DevTools 调试器会话;整页和后台标签页捕获使用短暂的会话自有调试器租约。
- 在 MV3 worker 重启后持久保留调试器租约身份。普通清理会报告未经验证的旧租约,而不是分离未跟踪的目标;显式陈旧恢复会在分离之前验证当前标签页围栏和 CDP 目标身份。
- Fences 标签页通过标签页围栏和文档身份进行处理。快照引用是文档作用域的:同一元素在文档的整个生命周期内保持其编号,并且引用比发布它的观测更长寿(从页面文档注册表解析,并报告为 resolvedBy: document_registry)。DOM-CUA 节点 ID 是其原始文档内的实时观测:标题/焦点变化、用户切换标签页、后续观测以及无关的 DOM 变动都不会使其失效;原始分离节点仅当存在唯一且强等价的替代节点时才能重新绑定一次。导航、重新加载和文档替换仍是硬边界,会以 BROWSER_DOCUMENT_CHANGED 拒绝旧观测;标签页关闭和标签页围栏变化会分别以 BROWSER_TAB_CLOSED 和 BROWSER_TAB_FENCE_CHANGED 拒绝它们;navigate(wait: false)、back、forward 和 reload 返回一个标记为 transitionPending 的标签页,其句柄省略不稳定的 URL/标题和文档化身字段,因此在进行文档绑定工作之前请等待或重新观测。只读页面读取会重新观测用户标签页,并在其文档变化时重试一次,而丢失文档身份的副作用操作会返回不确定结果,且不会自动重放。
- 通过应用心跳保持 Manifest V3 Bridge 套接字活跃,防止空闲 worker 挂起在长时间浏览器等待期间造成可避免的连接代际变动。
- 包含一个可复用的 pi-control-chrome Skill。浏览器工具 schema 在该 Skill 为当前会话显式加载之前是隐藏的;捆绑的 CLI 仍可用于显式的人工/开发者工作流和测试。

语义页面交互

常见的点击和表单工具接受语义 target,例如 { "role": "button", "name": "Submit" }、{ "label": "Email" }、{ "placeholder": "Search" }、{ "text": "Next" } 或 { "testId": "submit-button" }。语义交互会等待一个可见匹配项,并在目标缺失、隐藏、禁用或有歧义时失败关闭;仅当多个匹配是有意为之的时候,才使用显式的从零开始的 index。操作会在可见性过滤之后应用该索引,因此隐藏的重复控件不会消耗它。Role/name、label 和 accessible-text 目标优先使用 Chromium 计算出的 AX 语义,并在成功映射的操作上返回 resolvedBy: "chromium_ax";CSS 选择器、测试 ID 和占位符继续通过 DOM 解析。同源 iframe AX 节点参与同一有界语义读取,而跨源 frame 内容仍是诊断边界。browser_snapshot 返回文档作用域的实时 eN 引用和一个 snapshotId;在每次基于引用的交互或元素状态等待时传入匹配的 snapshotId。解析器首先使用原始已连接元素,并允许一次唯一、强等价的同文档重新绑定;CSS 选择器仍然受支持。
动作和元素状态定位器所使用的文本目标会将匹配的文本叶子节点投射到其最近的可操作祖先节点,因此 isEnabled 和 browser_wait 会报告接收该操作的控件的状态。browser_wait 支持 load、url、text、text_gone、visible、hidden 和 enabled。文本条件使用 text;元素条件使用与交互所接受的相同的语义 target。url 和 urlIncludes 可以约束每一个等待条件。当目标没有可见匹配项时,hidden 会成功,包括目标不存在或多个隐藏匹配项的情况;visible 和 enabled 要求恰好一个可见匹配项,而多个可见匹配项会以失败关闭(fail closed)。对于 visible 和 enabled,显式索引会在可见性过滤之后应用。浏览器页面匹配在所选标签页内运行,而 Bridge 会继续强制执行现有的浏览器目标和连接代际防护。如果产生副作用的交互在导航后丢失了其注入的结果,它会报告结果不确定,并且绝不会被自动重放。

架构

Pi Extension
↕ WebSocket
127.0.0.1 Local Bridge
↕ WebSocket
Chrome / Edge Manifest V3 Extension
↕
Current Chromium Profile

Bridge 绑定到回环地址,并要求本地配对令牌才能进行 WebSocket 操作。其 /pair 引导响应有意对该回环端口上的任何调用者可用,以便未打包的扩展无需读取主机令牌文件即可完成配对;因此,任何能够访问该端口的本地进程或已安装扩展都被信任拥有浏览器控制权。请让 Bridge 端口远离网络代理。由主机启动的实例会暴露一个非机密的实例 ID、启动器标签和能力列表;当 Bridge 暴露 capabilities.localUserRestart: true 且没有待处理的浏览器请求时,同一本地用户控制域中的任何已配对 DSH 或 Pi Host 都可以请求协作重启。实例 ID 可防止过期的重启竞态,而重启锁会串行化并发请求。当未知的旧版 Bridge 未暴露本地用户能力时,它们会保持不变。安装扩展并完成本地配对即为信任步骤;正常的浏览器操作不会请求重复的逐操作授权。

安装

从 npm 安装(推荐)

pi install npm:pi-control-chrome

从 GitHub 安装

pi install git:github.com/lyd123qw2008/pi-control-chrome

从本地检出安装

pi install /pi-control-chrome

该包通过其 package.json 的 pi 清单注册 Pi 扩展和捆绑的 Skill。它需要 Node.js 22 或更高版本。

DSH 集成本仓库还包含独立的 @lyd123qw2008/dsh-tool-control-chrome 包。它将与面向模型的 DeepSeek Harness 工具相同的浏览器控制界面注册,并通过本地 Bridge 路由调用。在活动的 DSH Profile 中安装该 DSH 包:

dsh plugin --profile web add @lyd123qw2008/dsh-tool-control-chrome

然后,在手动安装时,将其 cordis.patch.yml 中的 insert 条目合并到现有的 cordis.patch.yml 中(dsh plugin --profile web add 会自动应用该 bundle 补丁),并将 Bridge 设置保留在 /settings.yaml 中。

该 DSH 包复用本项目的 Bridge 和 Manifest V3 扩展。其默认的 lazyTools: true 模式最初仅暴露 pi-control-chrome Skill 元数据;在 Skill 成功加载后,所有 43 个 browser_ 工具都会在该 Agent 中注册,并在当前 Agent 会话的后续轮次中保持活动状态。在轮次结束时,宿主会关闭未标记的 Agent 临时标签页,释放已认领的用户标签页而不关闭它们,并解除会话调试器租约。Bridge、浏览器工具和 Browser 绑定在后续轮次中仍然可用。模型必须调用 browser_mark_handoff 或 browser_mark_deliverable,才能在当前轮次清理过程中保留 Agent 标签页,并在需要时在后续轮次中重复标记。只有用户明确要求关闭临时标签页、释放认领或清理浏览器任务时,才可以触发 browser_cleanup;它会立即执行任务清理,同时保留惰性工具和健康的 Bridge。browser_context_reset 是另一个由用户明确请求的独立操作,用于最终确定资源并停用惰性工具。Agent 和插件处置会重试最终清理;在清理成功之前,失败的恢复会阻止复用同一会话 ID 的替代 Agent。设置 lazyTools: false 可实现立即可见。Pi 会注册相同的原生工具一次,但在显式执行 /skill:pi-control-chrome 扩展或另一次成功的 Skill 激活之前,会通过其活动工具集将其隐藏。普通网页搜索不会激活浏览器控制。该 DSH 包还提供仅供人工使用的 /chrome status、/chrome targets、/chrome profile [browserId]、/chrome connect、/chrome disconnect、/chrome doctor、/chrome restart 和 /chrome tabs 命令。它不会自动安装浏览器扩展、读取 Chrome Profile 文件,也不会将 Bridge 暴露到回环地址之外。

Codex CLI 和 Desktop 该仓库包含一个 Codex 插件清单和一个本地 MCP stdio 适配器。安装包含此适配器的软件包版本后,使用 codex mcp add pi-control-chrome -- pi-control-chrome-codex 注册它,或将 codex mcp add 指向此检出目录中的 mcp/mcp-server.mjs。通用 MCP 适配器默认公开完整的浏览器工具目录;检入的 Codex 配置显式选择其受限的 codex 模式,包括在用户明确确认后执行 browser_restart。它不会打开额外的 MCP 端口。有关设置、模式和安全规则,请参阅 mcp/README.md。

加载浏览器扩展

Pi 无法自动安装未打包的浏览器扩展。请在 Chrome 或 Edge 中一次性加载共享的 extension/ 目录:

1. 打开 chrome://extensions 或 edge://extensions。
2. 启用 开发者模式。
3. 选择 加载已解压的扩展程序。
4. 选择仓库或已安装软件包的 extension/ 目录。
5. 启动或重新加载 Pi。

在 Pi 中检查连接:

/chrome status
/chrome targets
/chrome profile
/chrome tabs

该扩展由 Chrome 和 Edge 共享,并使用 Chromium Manifest V3 能力检测,而非单独的浏览器特定实现。现在,一个 Bridge 可以同时保持多个已识别的浏览器目标连接。每个目标以其稳定的 browserId 为键;请求使用目标限定路由和连接代际隔离,因此配置文件 A 的较新连接无法替换配置文件 B,也无法满足配置文件 A 的过期请求。当有多个目标可用时,请使用 /chrome profile 或 browser_status/Skill CLI 的 --browser-id 显式选择一个;运行时绝不会根据最新连接或活动窗口进行猜测。

Skill CLI

捆绑的脚本用于显式的人工/开发者工作流和自动化测试。它们直接连接到 Bridge,不得由模型 shell 调用以替代受 Skill 门控的原生工具:

node skills/pi-control-chrome/scripts/browser.mjs status --browser-id
node skills/pi-control-chrome/scripts/browser.mjs tabs --browser-id --json
node skills/pi-control-chrome/scripts/browser.mjs group --browser-id --json
node skills/pi-control-chrome/scripts/browser.mjs view https://example.com --browser-id --session example-session --turn 1 --screenshot "$env:TEMP\example.png"
node skills/pi-control-chrome/scripts/browser.mjs cleanup --browser-id --session [--recover-stale]
受管理的 CLI 命令使用显式的生命周期标识:open 和 cleanup 需要 --session ,而 view 需要同时提供 --session 和 --turn ,除非它被显式标记为临时。CLI 不会从进程 id 推导归属关系,因此后续调用可以安全地定位到相同的标签页。仅在扩展运行时变更后需要做出显式恢复决策时,才使用 cleanup --recover-stale;它会遗忘匹配的未知化身归属记录,而不会关闭这些标签页,并在 recovered 中报告它们的 id 以供手动检查。

捆绑脚本支持以下环境变量。当本地 Bridge 使用另一个回环端口时,Pi 扩展也接受 PI_CONTROL_CHROME_BRIDGE_PORT;其主机仍为 127.0.0.1:

PI_CONTROL_CHROME_BRIDGE_HOST # bundled CLI only
PI_CONTROL_CHROME_BRIDGE_PORT # bundled CLI and Pi extension

已检入的浏览器扩展仍连接到 127.0.0.1:17318,其 manifest CSP 允许列表固定为该端点。在将 Pi 扩展或 DSH 客户端指向另一个端点之前,请使用匹配的重新构建的扩展和 CSP。

使用原生的 browser_ Pi 或 DSH 工具进行模型浏览器工作。它们会保留当前的 Agent 会话、目标标识和标签页归属保护。用户标签页仍是有效的浏览器目标,但在用户或 DSH UI 处于活动状态时,其文档可能会被替换;只读页面读取会重新观察一次正在变化的文档,而具有副作用的操作则保留严格的文档防护。自动化浏览器验证应使用 Agent 拥有的测试标签页或隔离的浏览器配置文件,而不是活动的 DSH GUI 标签页。

开发与测试

cd /pi-control-chrome
npm install
npm run check
npm test
npm run test:pi:lifecycle
npm run test:skill
npm run pack:check
npm run test:package-install

npm run test:skill 需要已连接的 Chrome 或 Edge 配置文件以及本地 Bridge。它会创建临时 Agent 标签页,因此当存在多个就绪目标时,它会跳过而不是选择其中一个;仅在明确授权某个目标时才设置 PI_CONTROL_CHROME_TEST_BROWSER_ID。高覆盖率的浏览器冒烟测试为:

npm run smoke:e2e

多目标验收测试会启动所配置浏览器(默认为 Edge,或在选中时使用 Chrome for Testing)的两个隔离临时配置文件,并验证显式路由、目标断开隔离以及同一配置文件重连防护:

npm run smoke:e2e:multi-profile

冒烟测试默认使用 Edge。当前工作树已在 Edge 和 Chrome for Testing 149.0.7827.55 上通过了相同的隔离覆盖。使用以下命令针对 Chrome for Testing 运行它:

$env:PI_CONTROL_CHROME_BROWSER = "\chrome-for-testing\chrome.exe"
npm run smoke:e2e
这会请求一个唯一的临时 --user-data-dir,而不是常规用户配置文件。如果浏览器进程在扩展握手之前退出,测试框架就会失败,这可以检测到常见的 Windows 单例委派;Chrome for Testing 提供了最可靠的隔离可执行文件。已安装的 Google Chrome 可能会拒绝命令行未打包扩展标志;对于常规配置文件检查,请从 chrome://extensions 手动加载 extension/。

设计原则

1. 一次安装,低摩擦运行。 扩展安装和本地配对是面向用户的信任步骤。
2. 扩展是浏览器能力边界。 Pi 仅通过本地 Bridge 与其通信。
3. 默认保留用户标签页。 认领标签页会建立控制所有权;它不会将标签页移入 Agent 组。
4. Agent 标签页可回收。 Agent 创建的标签页带有所有权和会话元数据,并根据生命周期策略进行清理。
5. Chrome 和 Edge 共享同一实现。 该扩展使用 Manifest V3 和能力检测。
6. 在不复制私有 Codex 运行时代码的情况下对齐可观察行为。 Pi 使用自己的 Bridge 协议和 Extension API。
7. 能力层,而非站点适配器。 插件理解页面结构、身份、安全边界和通用原语;产品的 DOM、工作流和字段名称属于调用方 Skill。参见能力层与个性化层。

文档

- ARCHITECTURE.md — 英文架构文档。
- README-zh-CN.md — 简体中文指南。
- FEATURES.md — 功能范围与未来工作。
- CODEX-ALIGNMENT.zh-CN.md — Codex 行为对齐说明。
- DECISIONS.zh-CN.md — 项目决策。
- docs/RELEASE-CHECKLIST.zh-CN.md — 包/版本、依赖、PR、npm 发布和活跃 DSH Profile 发布检查清单。
- skills/pi-control-chrome-release/SKILL.md — Pi 和 DSH 包的可执行发布流程。
- skills/pi-control-chrome/SKILL.md — 捆绑的 Pi Skill。
- CHANGELOG.md — 发布历史。
- BROWSER-ACTIVATION-DESIGN.zh-CN.md — 浏览器能力激活与按需 Skill 设计。
- docs/BROWSER-LIFECYCLE-CODEX-ALIGNED.zh-CN.md — 已实现的与 Codex 对齐的浏览器生命周期。
- docs/BROWSER-OUTPUT-COMPACTION-DESIGN.zh-CN.md — 已实现的面向模型的有界浏览器输出与 AX 修订设计。
- docs/AGENT-BROWSER-RUNTIME-DESIGN.zh-CN.md — Agent 优先的实时引用运行时设计、实现状态以及 AX 运行时状态。

当前未来范围

以下事项计划在后续阶段实现,不会阻塞当前的浏览器控制循环:

- WebMCP、GSuite 导出以及浏览历史 API。
- 专用媒体下载接口。
- 超出当前 Bridge 目标和扩展能力握手范围的能力发现。
- Chrome 应用商店和 Edge 加载项发布包。
- 专用的 Brave 和 Chromium 验收覆盖。
- 跨 Bridge 编排以及在一个会话中同时控制多个目标。

许可证

MIT。参见 LICENSE。
预览分享卡片长什么样 ↓lyd123qw2008/pi-control-chrome
分享 · DeepSeek Harness Hub
lyd123qw2008/pi-control-chrome

适用于 Pi、Codex 和 DSH 的 Chrome 和 Edge 浏览器控制。

回到顶部