ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Search 浏览器 Bench 驱动协议实战指南:用 `./bench` 从命令行驱动 macOS 浏览器

Search 浏览器 Bench 驱动协议实战指南:用 `./bench` 从命令行驱动 macOS 浏览器 【免费下载链接】SearchA small, fast WebKit browser for macOS, by Office Commun.项目地址https://gitcode.com/gh_mirrors/search59/Search点击查看免费下载本文档基于 skill/search-bench/SKILL.md 整理并结合 Sources/Search/Bench.swift、bench、fresh.sh、Sources/Search/Store.swift 等源码补充了底层实现依据。导读./bench是 Search 仓库根目录下的一段命令行驱动脚本它让你在不触碰正在使用的浏览器窗口的前提下从 Shell 打开独立 bench 标签页、等待加载、读取页面文本、执行 JavaScript、点击、输入、提交表单、截图、探测窗口 Chrome以及安装/操作 Chrome 扩展。本文从“如何让一个测试世界test world开始监听”讲起到标签页生命周期、页面操作、Chrome 探测与 UI 切换、扩展测试、错误排查逐条给出可复制的命令与 JSON 输出说明并结合仓库源码解释其底层工作原理。一、什么是 bench一行命令驱动正在运行的 SearchSearch 是一个原生 macOS 浏览器仓库根目录见 Sources/Search。./bench位于仓库根目录通过 Unix socket 与正在运行的 Search 进程对话它在你现有的标签行末尾追加一个带烧瓶图标的 bench 标签页这些标签页不会被选中、不进会话、不写历史脚本让它关闭时才关闭——全程不影响正在使用浏览器的人。在 Sources/Search/Bench.swift 的头部注释中可以看到这套设计的完整说明默认关闭需要在Settings › General › Let a script drive Search手动打开打开后应用在一个只属于当前用户的 Unix socket 上监听socket 位于应用自己的数据目录见 Bench.socket即Store.file(bench.sock)协议为一行 JSON 进、一行 JSON 出、一次请求一个连接bench脚本只是这个协议在 Shell 侧的一个封装bench 中的ask()函数负责连接、发送、读取并解析单行 JSON 响应它打开的标签页永远不会替用户选中因此不会抢走窗口焦点。./bench help会打印完整命令语法bench 的模块 docstring。SKILL.md 明确要求当用户提出“测试 Search、驱动浏览器、运行 ./bench、在 Search 中打开页面、给标签页截图、检查面板、测试扩展”等需求时就应使用本文档描述的方法。二、选择目标进程三个世界world每条 bench 命令都会发送到某一个世界。同一个世界的一切调用必须使用相同的标志不要混用。标志对应的浏览器Socket 目录--test世界test~/Library/Application Support/Search (test)/--world NAME世界NAME只允许小写字母、数字、连字符~/Library/Application Support/Search (NAME)/无标志用户实际安装使用的浏览器~/Library/Application Support/Search/底层判定逻辑在 Sources/Search/Store.swift只要环境变量里有SEARCH_PROBE或者可执行文件路径包含/.build/即从构建目录直接运行的开发版二进制该进程就是测试运行SEARCH_PROBE1或SEARCH_PROBE为空时进入世界testSEARCH_PROBENAME进入命名世界。因此.build/下的 swift build 产物永远属于世界test./fresh.sh启动build/Search.app时设置SEARCH_PROBE同样属于测试世界fresh.sh。2.1 为什么必须用测试世界凡是要改动 Chrome界面框架、安装或卸载扩展、调整窗口大小、发送真实按键事件、选中标签页的操作都必须使用测试世界。原因有三隔离性测试世界有自己的数据目录、自己的设置 suite、自己的 WebKit 存储cookie 与登录态详见 Store.swift 的 world 与 probeStore 实现——测试永远不会碰真实浏览器里的会话、固定标签、历史与密码安全护栏select、key、resize、ext-answer等命令在无标志真实浏览器下会直接失败并报错见 Bench.swift 中select的实现it would take your window over确认对话框--yes只能在测试运行中跳过扩展的安装确认弹窗真实浏览器无法被强制跳过见 extensionCommand 中 skip 的计算。2.2 在真实浏览器上只做只读操作在用户明确要求驱动他们正在使用的那个窗口时只能使用tabs、probe以及针对 bench 标签页的页面类命令。ui、select、key、resize以及所有ext-*命令留给测试世界除非用户点名要求在自己的浏览器上做这些改动。look外观与sidebar侧边栏属于已保存偏好这类设置改动要谨慎对待。三、让一个测试世界开始监听每个世界只能有一个进程在监听。只有可执行路径是仓库的build/Search.app或.build/二进制、或其环境包含SEARCH_PROBE的进程才可以被退出。不要碰/Applications/Search.app——它和测试副本的 bundle id、进程名相同killall、按名字退出 Search、osascript退出都会同时命中真实安装的浏览器。启动与确认步骤./bench --test tabs或--world NAME。能打印出标签列表说明这个世界正在监听不要再启动第二个如果输出Search isnt listening该世界没有进程在运行先写入开关再启动defaults write SUITE bench -bool true然后./fresh.sh again。命名世界用SEARCH_PROBENAME ./fresh.sh again测试进程在跑但 socket 已死写入 default、结束该 pid然后./fresh.sh again。注意开关在启动时读取重复./bench --test tabs直到打印出结果启动需要一点时间各世界的 settings suite 为世界test→com.officecommun.search.test命名世界 →com.officecommun.search.test.NAME。3.1./fresh.sh的擦除语义./fresh.sh不带参数会删除该世界的数据目录、settings suite、WebKit 存储然后打开它fresh.sh。注意suite 删除会连同 bench 开关一起清掉所以一次“擦除”之后必须按顺序重新defaults write→ 退出它刚打开的进程 →./fresh.sh again。擦除只应在用户要求“干净浏览器”时进行。如果./bench tabs无标志没在监听让用户手动打开 Settings › General › Let a script drive Search不要替安装版写 defaults。3.2 为什么开关要在启动前写入./fresh.sh在缺少build/Search.app时会先构建它fresh.sh。它打开的世界其 bench 开关是开启且隐藏的一个跑到前台的测试运行会触发 probe 自身的护栏然后拒绝该次运行后续的所有命令见 Bench.swift 的 watchScreens测试运行中任何窗口出现在屏幕上都记为失败并隐藏应用。所以必须在启动前写开关而不是启动后——否则世界会带着窗口打开只能作废重来。四、标签页属于脚本、不属于用户的标签./bench tabs每行打印一个标签页⚗表示 bench 标签页烧瓶图标●表示用户当前所在的标签页尾部…表示仍在加载尾部z表示已休眠。4.1 基本操作与 ID 规则open会在行尾追加一个 bench 标签页并打印其 id。务必保存这个 id传 id 时使用tabs打印出的前缀即可匹配规则是标签页 UUID 的前缀首个匹配生效见 find(_:in:)id 取自 UUID 前 8 位小写见 short(_:)close ID拒绝关闭任何非 bench 标签页close all会关闭包括其他脚本打开的所有 bench 标签页。只关闭你自己打开的那些 idgo、click、type、submit、eval、text、shot、sleep都作用于你传入的标签页 id。除非用户点名要用他们的标签页否则只传⚗的 idbench 标签页不会被选中、不存会话、不写历史。你未选中的 bench 页面会被布局在屏幕外的一个 1280×800 窗口里——这正是shot截图的内容对应 house(_:) 与 makeRoom()WebKit 只有在页面有尺寸且有窗口时才排版和绘制所以 bench 为页面准备了一个远离所有屏幕的-20000,-20000窗口用完包括后续命令失败时关闭你打开的 id。关闭 socket 会连带关闭遗留的 bench 标签页Bench.stop 会遍历并关闭所有tab.bench同一世界一次只发一条 bench 命令。一条不回复的命令约 25 秒后被截断见 handle 中的 patience 计算wait用你传入的秒数加 5import-file用 120 秒其余一律 25 秒。4.2 一条完整的页面会话示例id$(./bench --test open https://example.com) ./bench --test wait $id 20 ./bench --test text $id ./bench --test shot $id $TMPDIR/search-bench.png ./bench --test close $id五、页面命令详解5.1 地址解析规则open和go接受地址而非搜索词且不能含空格。支持的 schemehttp、https、file、about、data。没有 scheme 的主机会补https://但以下情况补http://localhost、*.localhost、*.local以及局域网地址127.0.0.1、0.0.0.0、192.168.*、10.*、172.16.0.0–172.31.255.255。这套判定在 Sources/Search/Address.swift 中实现注释说明得很清楚A local server almost never has a certificate——本地服务器几乎不会有证书用 https 只会连接失败。open needs a url错误即来自这里拒绝了一个非地址字符串。5.2wait等页面加载完成wait输出 JSON。当loading为false时就绪可以继续下一步timeout: true表示到时间仍在加载对应 wait(for:until:_:) 的截止时间逻辑默认 20 秒failure是加载错误慢页面请把第二个参数调大。5.3text读取页面正文text返回document.body.innerText截断上限为 120000 字符见 Bench.swift 的 text 分支。截断时输出里带truncated标记且 stderr 打印[… truncated]。如果文本为空先evaldocument.readyState和location.href确认页面确实为空再下结论。5.4eval执行 JavaScripteval ID JS的脚本作为一个带引号的参数传入。返回值是 JSON如果结果不是合法 JSON则按字符串输出对应 plain(_:)JSONSerialization.isValidJSONObject通过则原样返回否则String(describing:)。5.5click/type/submit基于 CSS 选择器的页面交互三者都接受一个 CSS 选择器用document.querySelector解析记得加引号。返回{ok: true}或错误nothing matched / no form。type设置控件的 value 并触发input与change事件contenteditable 元素则写入textContent并派发 input 事件。底层实现见 act(_:selector:text:)——它通过原型上的 value setter 写入并派发事件注释说明这样frameworks notice即与密码填充器同一路径前端框架能感知到submit提交选择器所在表单选择器本身是form时直接提交该元素优先form.requestSubmit()否则form.submit()真实点击用tap ID SELECTOR [MODS…]测试世界专用通过 AppKit 合成鼠标 down/up 事件直接交给视图是可信的、如人手般的点击而click只是在页面里调用element.click()——密码管理器等对此会正确忽略见 Bench.swift 的 tap 分支。textSign in形式可按按钮/链接的文字选取元素locate(_:)。5.6shot截图shot打印 PNG 路径读取该文件即可。它截的是网页内容不是标签栏或窗口要截 Chrome 用probe读 JSON、用strip/column/picture出图。可选最后一个参数是截图宽度points对应 shoot(_:) 的snapshotWidth。务必把路径放在$TMPDIR下这是当前账户自己的临时目录/tmp是共享的一张含登录态的页面截图不该留在任何人都能覆盖的地方。5.7go跳转go ID URL在你已有的 bench 标签页里加载新地址。六、Chrome探测窗口状态与切换界面6.1probe只读地看窗口probe以 JSON 打印窗口状态Bench.swift 的 probe 分支各面板是否打开settings、welcome、passwords、history、downloads、bookmarks含bookmarksOpen/bookmarkCard/bookmarkCount地址栏是否打开field以及补全建议suggesting、offering模态框标题modal、当前 key windowkey、look、appearance每个窗口的 framewindows[].frame为 [x, y, width, height]与红绿灯按钮位置lights当活动页在主窗口时还会报告sidebar侧边栏开关、sidePositionleft或right、sideWidth、activePageFramex、y、width、height单位 points从窗口左上角算起。SKILL.md 的结论是用probe看 Chromeshot看不到 Chrome。6.2ui切换界面ui KEY VALUE修改 Chrome 并返回{ok: true}。在测试世界上使用除非用户要求在自己的浏览器上改。支持的表KeyValuesettingspasswordswelcomehistorydownloadsbookmarkshiddensidebarextensionson或offsideleft或rightlooklight、dark或system仓库中的./bench ui实际支持更多键如import、spaces、hides、folded、peek、pages120、fullscreen等见 bench 脚本的 ui 分支 与 Bench.swift 的 ui 分支。其中look、sidebar、side是会被记住的偏好。extensions on打开拼图按钮菜单ext-menu PATH把该菜单写成 PNG。6.3 其他窗口级命令测试世界专用resize WIDTH HEIGHT [STEPS]分步拖拽窗口到指定尺寸模拟人手拖角实现返回最终尺寸与红绿灯位置key ID TEXT向标签页发送真实按键事件返回页面未消费的按键数sentBackUnused见 Bench.swift 的 key 分支键码由 keyCode(for:) 按美式键盘映射sleep ID立即尝试休眠标签页报告它保持唤醒的原因。bench 标签页保持唤醒windows [list|new|close N|reopen|frame N X Y W H|front N|link URL]多窗口管理--window N放在任何命令前可把命令指向第 N 个窗口bench。七、扩展测试macOS 15.4扩展功能需要 macOS 15.4 或更高版本且必须在测试世界上操作。此处的 id 来自./bench extensions输出的扩展 id不是标签页 id。7.1 安装ext-add接受 Chrome Web Store 链接或 idext-folder接受包含manifest.json的文件夹。两者都先返回{started: true}安装尚未完成见 extensionCommand。测试运行时必须加--yes否则应用会停在确认对话框上./bench --test ext-add https://chromewebstore.google.com/detail/… --yes ./bench --test extensions轮询extensions直到该扩展的busy为然后读取它的loaded、errors、reported字段extensions 分支 会报告 id、名称、版本、是否启用、是否加载、base URL、错误详情、badge 等。7.2 交互与生命周期ext-press ID打开它的 popup。popup 处于打开状态时ext-popup ID JS在其中运行 JavaScriptext-shot ID PATH写入 PNGext-page ID [PATH]在 bench 标签页中打开扩展自带的某个页面打印该标签页 id之后在那里eval就带着扩展的 API 运行ext-reload ID重新加载文件夹安装的扩展会重新拷贝一份ext-pin ID [on|off]、ext-enable ID on|off、ext-remove ID改变该世界的扩展状态ext-answer yes|no|ask测试世界专用预先回答后续的权限问题并列出被问过什么capture/capture-stop ID查询/停止扩展的屏幕录制对应 ExtensionCapture。仓库中关于扩展的进一步实现可参考 ExtensionFiles.swift 与 Tests/run-extension-files-tests.sh该脚本单独编译 ExtensionFiles 与 ExtensionFilesTests.swift 做原子替换与旧文件夹清理的回归测试。八、失败与排错脚本以非零状态退出并打印error: …。相信这条字符串。常见错误错误信息含义与处理isnt listening进程没起来或开关是关的。按上文“让一个测试世界开始监听”处理no tabid 已过期。重新tabsnot a bench tabclose指向了用户的标签页only works on a --test run/only in a test runselect、key、resize、ext-answer指向了安装版浏览器no popup open先对该 id 执行ext-press再 shot 或 eval popupunknown command执行./bench help。脚本比这份文档新语法以 help 为准open needs a url字符串不是合法地址。参见上文 scheme 规则另外两类值得注意的输出信号测试运行中任何窗口进入屏幕该次运行的每个回答都会带上onScreen字段./bench会打印error: a window came onto a screen in this test run并以状态 3 退出bench、Bench.swift 的 watchScreens——这是刻意设计让窗口出现在屏幕上的测试运行必须丢弃./bench --test与SEARCH_PROBE进程的对应关系由 Store.testing 保证.build/二进制即使没有SEARCH_PROBE也永远是test世界。九、安全与隔离设计为什么可以放心驱动从源码看bench 的安全模型是多层的这也是它可以在有人正在使用的浏览器旁边安全运行的原因Socket 权限socket 文件chmod 0600且每次 accept 后用getpeereid校验对端 uid 与当前用户一致Bench.start、accept()测试世界完全隔离自己的数据目录、settings suite、WebKit 网站数据存储Store.swift。./fresh.sh的擦除只针对这三处fresh.sh真实会话、固定标签、历史与登录态永远不在脚本可达范围内同意开关ConsentSettings 里的开关不仅写 defaults还会在钥匙串的数据保护分区留下标记标记由 Search 的签名 profile 保护没有标记时启动会把开关复位并提示Consent 枚举不抢焦点bench 标签页从不被选中未查看的页面被安置在屏幕外窗口house/makeRoomBench.swift超时兜底每个请求都有硬性超时默认 25 秒页面不回话也不会卡死整条 benchhandle。相关资源命令权威语法./bench help脚本 docstring服务端协议实现Sources/Search/Bench.swift测试世界与存储隔离Sources/Search/Store.swift世界启动脚本fresh.sh地址解析规则Sources/Search/Address.swift扩展文件处理测试Tests/run-extension-files-tests.sh相关回归测试目录Tests/HistoryRegression/README.md赞分享【免费下载链接】SearchA small, fast WebKit browser for macOS, by Office Commun.项目地址https://gitcode.com/gh_mirrors/search59/Search点击查看免费下载相关推荐CLI-Anything Safari用 Click 命令行驱动 safari-mcp实现 macOS 浏览器自动化CLI Anything Safari用 Click 命令行驱动 safari mcp实现 macOS 浏览器自动化 clI Anything 的 Safa人工智能AI AgentAI 技能工具调用CLIOpenCLI Claude 适配器实战用命令行驱动 claude.ai 浏览器会话OpenCLI Claude 适配器实战用命令行驱动 claude.ai 浏览器会话 本指南聚焦 OpenCLI 的 claude 浏览器适配器Browse开发工具CLI人工智能AI 应用浏览器控制GUI 自动化OpenCLI Gemini Adapter 实战指南用浏览器会话在命令行驱动 Gemini WebOpenCLI Gemini Adapter 实战指南用浏览器会话在命令行驱动 Gemini Web 本指南围绕 docs/adapters/browser/开发工具CLI人工智能AI 应用浏览器控制GUI 自动化上一篇Mac Mouse Fix终极指南如何让普通鼠标在macOS上获得超越苹果触控板的体验下一篇XML智能编辑让复杂文档处理效率提升60%的开源解决方案创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表