- GUI 自动化
- MCP 服务
- AI 应用
【免费下载链接】Peekaboo
Peekaboo is a macOS CLI & optional MCP server that enables AI agents to capture screenshots of applications, or the entire system, with optional visual question answering through local or remote AI models.
peekaboo menubar是 Peekaboo CLI 中专门用于操作 macOS 状态栏图标(status items,即 menu bar extras,例如 Wi-Fi、蓝牙、电池以及各类第三方托盘图标)的轻量级子命令。它通过MenuServiceBridge直接与菜单栏服务通信,帮助 AI Agent 以"先只读枚举、后显式授权点击"的安全方式完成状态栏交互,是自动化流程中点击系统托盘图标的标准化入口。读完本文,你将掌握menubar list/menubar click的完整参数用法、--foreground强制同意机制、按应用(--app/--pid)作用域定位 AX 状态项的原理,以及--verify多重弹窗验证策略。
命令定位:状态栏专用,与传统应用菜单互补
Peekaboo 的菜单类命令有明确分工:peekaboo menu处理传统的应用菜单(如 File、Edit),而peekaboo menubar严格面向菜单栏右侧的状态栏图标。在 MenuBarCommand.swift 的命令描述中可以看到,menubar的子命令注册为list与click两个真正的 Commander 子命令,且命令名不含连字符(不是menu-bar)。
两者的核心差异体现在交互代价上:
menubar list是只读操作,始终在后台完成,不打断用户当前工作;menubar click会打开全局状态栏 UI(弹出 popover/菜单),因此强制要求显式的--foreground同意,其语义在源码中定义为 "Allow opening global menu bar UI (required for click)"(见 MenuBarCommand.swift)。
子命令与关键选项总览
menubar包含两个子命令,均支持全局的--json结构化输出与--verbose详细模式:
| 子命令 | 说明 |
|---|---|
list | 打印每个可见状态栏图标及其索引;--json额外输出 bundle ID 与 AX 标识符 |
click | 按名称或索引点击状态栏图标;结合--app/--pid可点击特定应用拥有的 AX 状态项 |
click子命令的完整选项(与 MenuBarCommand.swift 的 Commander 绑定一一对应):
| 参数 | 类型 | 说明 |
|---|---|---|
[itemName] | 位置参数 | 目标状态栏项目名称,传递给click |
--index <n> | 数字 | 按列表索引定位(与menubar list展示的排序一致,0 起) |
--app <name-or-bundle-id> | 字符串 | 仅限带名称的click:在指定应用中检查 AX 状态项,与--pid、--index互斥 |
--pid <pid> | 数字 | 仅限带名称的click:在指定正 PID 进程中检查 AX 状态项,与--app、--index互斥 |
--foreground | 标志 | click必需;允许 Peekaboo 打开全局状态栏 UI 并打断当前前台工作流 |
--verify | 标志 | 点击后确认同一 PID 拥有的 popover 出现,或焦点已转移到所属应用/窗口(含 OCR 兜底) |
--includeRawDebug(仅list) | 标志 | 在 JSON 输出中包含原始调试字段(窗口 owner/layer) |
| 全局标志 | — | --json输出结构化负载;--verbose在列出时增加描述信息 |
list:只读枚举状态栏清单
peekaboo menubar list通过MenuServiceBridge.listMenuBarItems获取清单(见 PeekabooBridgeClient+MenusDockDialogs.swift),底层走 Bridge 通道,不触发任何前台交互。
人类可读输出
默认输出格式由 MenuBarItemListOutput.swift 定义:
$ peekaboo menubar list Menu Bar Items (5): [0] <untitled> Frame: 0,0 24×22 [1] Wi-Fi Description: Wi-Fi status Frame: 300,0 20×20 ...每行展示[索引] 名称,并在可用时附带 Description 与屏幕坐标 Frame。当列表非空时,命令还会打印一行提示,引导你使用peekaboo menubar click --index <index> --foreground或peekaboo menubar click "<name>" --foreground(此行为同样有测试覆盖,见 MenuBarCommandConsentTests.swift)。若未检测到任何状态项,则输出No menu bar items detected.。
JSON 输出字段
--json输出包含items与menu_bar_items(同一数组的别名,兼容不同消费方)以及count。每个MenuBarItemInfo条目(定义于 MenuServiceProtocol.swift)包含:
| 字段 | 含义 |
|---|---|
title | 面向用户展示的名称 |
rawTitle | 系统报告的原始名称(可能形如Item-0) |
index | 菜单栏中的序号 |
isVisible | 当前是否可见 |
description | 可选描述 |
bundleIdentifier | 所属应用的 bundle ID(如com.apple.controlcenter) |
ownerName | 所属应用名或 owner 字符串(如Control Center) |
identifier/axIdentifier | AX 稳定标识符 |
axDescription | AX 帮助文本 |
frame | 屏幕坐标包围盒 |
rawWindowID/rawWindowLayer/rawOwnerPID | 原始窗口 ID、窗口层(菜单项常见 24/25)、拥有进程 PID |
rawSource | 数据来源(如cgs、cgwindow、ax-control-center) |
selectionEvidence | 精确的状态项身份与有序清单摘要,供后续点击操作校验 |
--verbose模式会追加 owner 名称与隐藏状态等诊断信息;--includeRawDebug则会补全rawWindowID/rawWindowLayer等原始调试字段。
click:名称、索引与应用作用域三种定位方式
menubar click的目标解析分为**无作用域(全局清单)与应用作用域(--app/--pid)**两条路径,两者都要求先满足--foreground。
强制的前置同意:--foreground
在 MenuBarCommand.swift 中,clickMenuBarItem的第一道关卡就是检查--foreground;缺失时直接抛出MenuBarClickPreflight.foregroundConsentRequired,其错误信息为 "Menu bar clicks require --foreground because status items open global UI."。这保证在任何状态项查找之前就完成拒绝,避免产生无谓的查询与副作用。
对应的测试foreground consent precedes explicit named preparation与named click without foreground refuses before lookup or dispatch验证了:缺少--foreground时prepareCalls、listCallCount、namedClickCalls、indexClickCalls全部为零,即不触发任何查找或分发(见 MenuBarCommandConsentTests.swift)。
无作用域:按索引或按名称
无--app/--pid时,命令先通过listMenuBarItems拿到当前显示的 WindowServer 清单,再由MenuBarItemSelector(见 DeterministicDesktopLeafSelector.swift)完成匹配:
- 按索引:
--index <n>直接对应list展示的序号。索引越界/过期会以MENU_ITEM_NOT_FOUND拒绝,提示重新执行menubar list获取当前索引。 - 按名称:大小写不敏感的模糊匹配(匹配字段覆盖
title、rawTitle、identifier、axDescription、ownerName)。
关键的设计保证是名称目标在分发阶段始终保持名称绑定:即使两次调用之间状态栏发生重排,点击也不会被错误重定向到另一个索引——resolveClickTarget中索引选择器只负责"定位候选",真正下发时仍走 named 请求(MenuBarItemActionRequest(named:...)),相关测试foreground named click preserves name-based dispatch断言namedClickCalls == ["Wi-Fi"]而indexClickCalls为空(见 MenuBarCommandConsentTests.swift)。
此外,无作用域的名称/索引保留"显示的 WindowServer 清单 + 精确窗口路径":一个唯一显示的名称不会触发全局 AX 扫描,因此无关的图形辅助进程无法阻塞该路径;只有含糊匹配或过期的显示证据会在分发前被拒绝。
应用作用域:--app 与 --pid
click <name> --app ...或--pid ...走 scoped 准备路径:命令先通过MenuBarClickPreflight.prepare调用MenuServiceBridge.prepareMenuBarItem,在指定应用代(generation)内部、带有 deadline 地准备一份AXExtrasMenuBar清单。参数校验规则在 MenuBarCommand.swift 中明确:
--app与--pid二选一,同时给出报VALIDATION_ERROR;--index不能与--app/--pid组合;- PID 必须是正数,空字符串、
PID:0前缀等非法应用标识会被拒绝; - 名称与索引不能同时给出。
准备阶段会记录原始 owner 选择器、进程代与选中项证据;分发阶段对证据做复验,并在最终读取之间核对原生叶节点身份,不借用 Control Center 代理的窗口 ID,且准备过程从不聚焦应用。若应用名/bundle ID 指向的应用在当前代中缺失、不可读、已变化或匹配含糊,一律在分发前拒绝;不确定的 AX 提交绝不通过其他路由重试。
作用域内匹配的细节语义:在显式 owner 内,项目文本只匹配原生叶节点的 title、help、description 或 identifier;应用名与 bundle ID 是 owner 选择器,不是额外的项目名别名。作用域点击与无作用域点击一样强制--foreground,且不能使用--index,也绝不回退到其他应用或全局清单。若运行时未协商scopedMenuBarActions,较旧的 Bridge host 会直接拒绝而非忽略 owner 作用域(见 PeekabooBridgeClient+MenusDockDialogs.swift)。
同时,兼容性说明:既有的编程式clickMenuExtraAPI 仍保留仅依赖 Accessibility 的系统菜单路径(不需要 CG 窗口或 Event Synthesizing 权限);原始命名的 SDK 调用保留 AX 优先查找与既有的安全分发前兜底。这两条兼容路由都不会取代CLI 与当前受证明的远程命名调用所使用的"证据绑定"请求。
错误输出契约
名称缺失、索引过期、作用域不匹配等失败统一在分发前以MENU_ITEM_NOT_FOUND拒绝,JSON 负载包含effect: refused、retry_safe: true、mutation_dispatched: false(源码定义于 MenuBarCommand.swift)。测试missing named item is one typed pre-dispatch refusal断言了完整的错误消息Menu bar item not found: Missing及上述字段(见 MenuBarCommandConsentTests.swift)。
verify:点击后的多重弹窗验证链
--verify的核心实现在 MenuBarClickVerifier.swift,验证按以下优先级逐步进行,任一步成功即返回verified: true及对应method:
- popover 解析(无 OCR):轮询
MenuBarPopoverResolver,在给定超时(默认 1.5s)内寻找与点击项同 PID 的弹出窗口。解析依据依次为 owner PID(置信度 1.0)、owner 名称(0.9)、排名/首选 X 坐标(0.4),原因标记如owner_pid、owner_name、preferred_x、window_rank(见 MenuBarPopoverResolver.swift)。 - 焦点窗口变化:确认点击后前台应用是否变为 owner,或聚焦窗口的 ID/标题是否发生变化(
focused_window,置信度 0.7)。 - owner 窗口出现:检查 layer 0 上是否出现 owner 的可见窗口(
owner_pid_window,置信度 0.6),通过ObservationMenuBarWindowCatalog按 PID 或按名称/标题匹配。 - OCR 兜底(默认开启):对排名靠前的候选窗口执行 OCR,要求 popover 文本包含目标标题/owner 名,并将验证锚定到点击项的 X 坐标;区域 OCR 兜底(
ocr_area)也在允许时启用。OCR 需要屏幕录制(Screen Recording)权限。 - AX 菜单检查(默认关闭):仅当环境变量
PEEKABOO_MENUBAR_AX_VERIFY=1时才通过isMenuExtraMenuOpen检查 AX 菜单是否展开(ax_menu)。
两个验证开关的环境变量语义:
| 环境变量 | 默认 | 作用 |
|---|---|---|
PEEKABOO_MENUBAR_OCR_VERIFY=0 | OCR 开启 | 显式关闭 OCR 验证(仍要求 popover 文本包含目标标题/owner) |
PEEKABOO_MENUBAR_AX_VERIFY=1 | AX 关闭 | 显式开启 AX 菜单检查(可选,依赖 Accessibility) |
验证成功后,JSON 输出的verified为true,effect 升级为confirmed;验证失败会抛出operationError("Menu bar verification failed: popover not detected")。此外,点击结果会记录屏幕坐标数据(若可得),便于你关联交互发生的屏幕位置。
完整可运行的实战示例
# 1. 只读列出所有状态栏图标及其索引(后台进行,无需 --foreground) peekaboo menubar list # 2. 按名称点击 Wi-Fi 图标(必须显式 --foreground) peekaboo menubar click "Wi-Fi" --foreground # 3. 点击并验证 popover 已打开(OCR 验证默认开启) peekaboo menubar click "Wi-Fi" --verify --foreground # 4. 直接按索引点击第三个图标,并输出结构化 JSON peekaboo menubar click --index 3 --foreground --json # 5. 显式定位第三方应用 AX 拥有的状态项(按 bundle ID) peekaboo menubar click "Status Item" --app com.example.StatusApp --foreground --json # 6. 把命名项绑定到从应用列表取得的 PID peekaboo menubar click "Status Item" --pid 12345 --foreground --json # 7. 带原始调试字段的 JSON 清单(list 专属) peekaboo menubar list --json --includeRawDebugclick --foreground --json的成功负载示例(ClickJSONOutput,见 MenuBarCommand.swift)包含success、clicked(元素描述)、executionTime、verified与selectedLeafEvidence数组;非 JSON 模式下,验证成功会额外打印✅ Clicked menu bar item: ...与🔎 Verified menu bar click (<method>),--verbose下还会显示耗时。
故障排查
- 先确认权限:使用
peekaboo permissions status验证 Screen Recording 与 Accessibility 权限均已授予(OCR 验证依赖屏幕录制,AX 依赖辅助功能)。 - 确认进程与当前 UI:用
peekaboo app list确认目标进程,用peekaboo window list确认其精确窗口,再用peekaboo see查看当前界面,再重试。 - 用结构化输出定位问题:重跑时加
--json或--verbose,可以拿到具体的错误码(如MENU_ITEM_NOT_FOUND、VALIDATION_ERROR)、hint与retry_safe字段,便于判断是名称/索引过期、作用域冲突还是缺少同意。 - 索引过期:状态栏重排后索引会失效,先
peekaboo menubar list刷新,再按新索引操作;名称目标则不受重排影响。 - 验证失败:若
--verify报 "popover not detected",先确认点击确实产生了弹出 UI;可临时设PEEKABOO_MENUBAR_OCR_VERIFY=0排除 OCR 因素,或设PEEKABOO_MENUBAR_AX_VERIFY=1尝试 AX 路径。
小结
peekaboo menubar把 macOS 状态栏交互收敛为"只读枚举 + 显式授权点击"两段式流程:list始终在后台提供权威清单,click以--foreground作为强制门槛,再通过名称/索引/应用作用域三种定位与--verify的五级验证链(popover、焦点变化、owner 窗口、OCR、AX),在可审计的证据绑定机制下完成点击。理解这些选项与拒绝语义,你就能在自动化流程中安全、可靠地驱动 Wi-Fi、蓝牙、电池等系统状态项与第三方托盘应用。
- GUI 自动化
- MCP 服务
- AI 应用
【免费下载链接】Peekaboo
Peekaboo is a macOS CLI & optional MCP server that enables AI agents to capture screenshots of applications, or the entire system, with optional visual question answering through local or remote AI models.
相关推荐
Peekaboo dialog 命令实战指南:用 Accessibility 精确驱动 macOS 对话框、输入与文件面板
Peekaboo dialog 命令实战指南:用 Accessibility 精确驱动 macOS 对话框、输入与文件面板 peekaboo dialog 是
GUI 自动化MCP 服务AI 应用如何快速上手Cosmos3-Nano:5分钟从零开始的多模态AI模型部署指南
如何快速上手Cosmos3 Nano:5分钟从零开始的多模态AI模型部署指南 Cosmos3 Nano 是NVIDIA推出的全能多模态世界模型,专为物理AI应用
人工智能基础模型大模型多模态媒体生成具身智能命令名称
命令名称 简洁的命令描述 可选的第二行描述 更多信息:<官方文档链接 示例描述: 命令 选项 {{参数}} 另一个示例描述: 命令 选项1 选项2 {{值1}}
文档教程知识库
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考