LobeHub Slack 机器人端到端自动化测试指南:用 osascript 驱动真实 macOS 桌面应用
导读
本文介绍 LobeHub 在 .agents 验收体系(acceptance)中针对 Slack 机器人渠道 的端到端验证方案:如何通过 AppleScript / osascript 驱动真实运行的 Slack macOS 桌面应用,完成"激活应用 → 快速切换跳转频道 → 发送消息 → 等待响应 → 截屏取证"的完整链路,从而验证 LobeHub 通过 Slack 渠道接入的机器人是否真实可用。读完本文,你将掌握这套 test-slack-bot.sh 驱动脚本的用法、其背后每个 AppleScript 操作的作用原理,以及屏幕录制(Screen Recording)权限预检等关键前置条件,可直接用于在本地 macOS 上复现同样的机器人渠道测试。
这套测试体系在整个项目中的位置
Slack 机器人测试属于 LobeHub 仓库内 .agents 下项目技能 agent-testing-bot(见 技能总览)。该技能是对通用 acceptance 技能的扩展:当待验证的行为发生在机器人渠道(Discord / Slack / Telegram / WeChat / Lark / QQ / iMessage)时,唯一的验证方式是驱动真实的原生聊天应用做端到端测试,这只能通过 osascript 或 iMessage 桥接在 macOS 上完成,而无法在无头(headless)环境中运行。
它并不替换通用验收技能的 PLAN → EXECUTE → FINISH 三阶段流程与 result.json → report-init.sh → lh acceptance run ingest 的报告发布管线,只是在 EXECUTE 阶段为机器人渠道补充"用什么工具驱动、如何截图取证"这一层。每个平台目录下固定包含两份资产:
index.md—— 激活、导航、发消息、验证的原子操作片段(即本文主体对应的原文档);test-<platform>-bot.sh—— 封装上述步骤的可执行驱动脚本。
Slack 平台对应 slack/ 目录,入口文档为 .agents/skills/agent-testing-bot/slack/index.md。
前置条件:macOS 原生自动化
Slack 渠道测试的每一步都是通过 osascript 向真实 macOS 应用注入系统事件(激活、击键、点击、读辅助功能、截屏),因此有几个硬性前置条件:
- Slack 桌面应用已安装并保持登录状态 —— 脚本不会替你登录,目标应用必须处于已运行、可交互状态。
- 辅助功能(Accessibility)权限 ——
System Events自动化要求驱动方(运行命令的终端应用,如 Terminal / iTerm / Agent 宿主)在"系统设置 → 隐私与安全性 → 辅助功能"中已获得授权,首次运行会弹出授权提示。 - 屏幕录制(Screen Recording / TCC)权限 + 屏幕处于点亮状态 —— 机器人取证依赖操作系统级
screencapture,而非浏览器 CDP,因此当权限缺失或显示器处于睡眠 / 锁屏 / 屏保状态时,截图会整体全黑,容易被误判为正常取证结果。
关于 osascript 的通用自动化模式(激活应用、逐字符输入、剪贴板粘贴、快捷键、点击、窗口信息读取、截屏等),仓库整理了一份共享参考:.agents/acceptance/references/osascript.md,首次运行机器人测试前应先通读。
屏幕录制预检门禁
capture-app-window.sh 与机器人渠道取证脚本在截屏前都会经过预检脚本 check-screen-recording.sh,其退出码语义为:
| 退出码 | 含义 |
|---|---|
| 0 | 系统级截屏可用(权限已授予且当前帧非全黑);非 macOS 平台同样返回 0(改用 CDP 取证) |
| 3 | 屏幕录制权限未授予给负责的应用,需在系统设置中开启后彻底退出并重启该应用 |
| 4 | 权限看似正常但画面全黑,通常是显示器睡眠 / 锁屏 / 屏保,需唤醒解锁,或用 caffeinate -d 保持屏幕常亮 |
| 2 | 无法判定(缺少 screencapture / clang / swift 等工具链) |
因此在任何机器人截屏取证之前应先执行:
./.agents/acceptance/scripts/check-screen-recording.sh # exit 0 = OS 截屏可用
并在整个截屏会话期间保持显示器常亮:
caffeinate -dimsu & # 会话结束后记得 kill 该进程
之所以要求如此严格,从源码看(见 check-screen-recording.sh)该脚本做了两层检测:先用 CGPreflightScreenCaptureAccess 探测 TCC 权限位,再真实截取一帧、用 sips 缩放到 16×16 后通过 Python 计算全屏最亮像素,若最亮通道值低于 12/255 即判定画面为黑——用"可度量"代替"猜测",避免产生误导性的黑色取证图。
驱动脚本的统一契约
仓库中所有基于 osascript 的平台脚本共享同一套命令行接口(见 SKILL.md):
./$PLATFORM/test-$PLATFORM-bot.sh $CHANNEL_OR_CONTACT $MESSAGE [$WAIT_SECONDS] [$SCREENSHOT_PATH]
Slack 驱动脚本 test-slack-bot.sh 的参数为:
| 参数 | 必填 | 默认值 | 说明 |
|---|---|---|---|
<channel> |
是 | — | 通过快速切换器(Quick Switcher,Cmd+K)跳转的频道名,如 bot-testing |
<message> |
是 | — | 要发送的消息内容,如 @mybot hello 或 /ask 问题 |
[wait_seconds] |
否 | 10 |
等待机器人响应的时间(秒) |
[screenshot_path] |
否 | /tmp/slack-bot-test.png |
截图输出路径 |
典型用法:
# 发送普通 @消息,等待 10 秒后截屏
./.agents/skills/agent-testing-bot/slack/test-slack-bot.sh "bot-testing" "@mybot hello"
# 发送斜杠命令并给出更长的等待窗口
./.agents/skills/agent-testing-bot/slack/test-slack-bot.sh "bot-testing" "/ask What is 2+2?" 20
# 自定义等待与截图路径
./.agents/skills/agent-testing-bot/slack/test-slack-bot.sh "general" "Hey bot" 15 /tmp/my-test.png
脚本内部按"激活 → 跳转 → 发送 → 等待 → 截屏"五步执行,其中截屏复用通用技能的工具链 capture-app-window.sh(由驱动脚本以相对路径调用:capture-app-window.sh)。从脚本源码可以看到,发送消息统一采用剪贴板粘贴而非逐字符输入,以规避长文本与特殊字符问题:
# 脚本实际行为:把整条消息放入剪贴板,Cmd+V 粘贴,再按回车
osascript -e '
set the clipboard to "'"$MESSAGE"'"
tell application "System Events"
keystroke "v" using command down
delay 0.3
key code 36 -- Enter
end tell
'
注:
capture-app-window.sh会用 Swift 通过CGWindowListCopyWindowInfo按进程名查找窗口层为 0、宽高大于 200 的窗口,取其CGWindowID后用screencapture -l <id>只截该窗口;找不到窗口时才回退为全屏截图。
逐场景操作手册(原文档核心内容)
下面是 slack/index.md 中给出的全部手动操作片段,结合驱动脚本可组合出任意定制化测试。
1. 激活 Slack 并跳转到测试频道
# 激活 Slack
osascript -e 'tell application "Slack" to activate'
sleep 1
# 打开快速切换器(Cmd+K)
osascript -e 'tell application "System Events" to keystroke "k" using command down'
sleep 0.5
# 输入频道名
osascript -e 'tell application "System Events" to keystroke "bot-testing"'
sleep 1
# 回车确认(key code 36 即 Enter)
osascript -e 'tell application "System Events" to key code 36'
sleep 2
要点:keystroke "k" using command down 触发 Slack 的 Quick Switcher;随后输入的频道名会被自动补全;key code 36 是硬件键码,不受键盘布局影响,等效于按下回车。各步骤之间的 sleep / delay 是为了给应用留出处理 UI 事件的时间——这是 macOS UI 自动化中常见的稳定性手段(osascript.md)。
2. 向机器人发送普通消息
跳转频道成功后,消息输入框处于聚焦状态,可直接输入:
# 直接消息输入(跳转频道后已聚焦)
osascript -e 'tell application "System Events" to keystroke "@mybot hello"'
sleep 0.3
osascript -e 'tell application "System Events" to key code 36' # 回车发送
3. 发送长消息(走剪贴板)
对于长文本或含特殊字符的消息,逐字符 keystroke 既慢又可能在非 ASCII 字符上出错,正确姿势是先写入剪贴板再 Cmd+V 粘贴(osascript.md 明确提示:超过约 20 个字符或含 CJK / emoji 的消息都应改用剪贴板粘贴):
osascript -e '
tell application "Slack" to activate
delay 0.5
set the clipboard to "A long test message for the bot..."
tell application "System Events"
keystroke "v" using command down
delay 0.3
key code 36 -- 回车发送
end tell
'
这也是 test-slack-bot.sh 驱动脚本内部唯一采用的发送方式,可测试长提示词、多行指令等场景。
4. 测试斜杠命令(Slash Command)
若待验证的机器人能力通过斜杠命令暴露,可直接输入命令文本:
osascript -e '
tell application "Slack" to activate
delay 0.5
tell application "System Events"
keystroke "/ask What is the meaning of life?"
delay 0.5
key code 36
end tell
'
Slack 会先弹出命令补全浮层,随后回车即发送。若要在驱动脚本中复用该场景,把命令作为 $MESSAGE 传入即可,例如 ./test-slack-bot.sh "bot-testing" "/ask What is 2+2?" 20。
5. 验证机器人响应并取证
发送后等待足够的响应时间,再截屏作为视觉证据:
sleep 10
screencapture /tmp/slack-bot-response.png
在完整工作流里,更推荐用驱动脚本封装好的窗口级截屏(只截 Slack 窗口、自动回退全屏),再由 Agent 的 Read 工具对截图做视觉核对:
./.agents/acceptance/scripts/capture-app-window.sh "Slack" /tmp/slack-bot-response.png
组合一个完整的 Slack 机器人测试会话
将上文片段按 acceptance 体系的"单一事实来源"原则组合,一次最小可用测试会话为:
# 0) 预检:确保 OS 截屏不会全黑
./.agents/acceptance/scripts/check-screen-recording.sh
caffeinate -dimsu &
# 1) 激活 + 跳转(Cmd+K 快速切换器)
osascript -e 'tell application "Slack" to activate'
sleep 1
osascript -e 'tell application "System Events" to keystroke "k" using command down'
sleep 0.5
osascript -e 'tell application "System Events" to keystroke "bot-testing"'
sleep 1
osascript -e 'tell application "System Events" to key code 36'
sleep 2
# 2) 发送消息(剪贴板粘贴,规避非 ASCII 与长文本问题)
osascript -e '
set the clipboard to "@mybot hello"
tell application "System Events"
keystroke "v" using command down
delay 0.3
key code 36
end tell
'
# 3) 等待响应并截屏取证
sleep 10
screencapture /tmp/slack-bot-response.png
# 4) 会话结束,解除常亮
kill %1
对于日常回归,直接用驱动脚本即可把上面五步压缩为一条命令,并把证据产出一并完成。
常见坑与规避建议
仓库在 osascript 通用参考中沉淀了以下易错点,对 Slack 测试同样成立:
keystroke长文本极慢:超过约 20 个字符请走set the clipboard+Cmd+V。keystroke会弄乱非 ASCII:CJK、emoji、特殊字符务必用剪贴板粘贴,否则消息内容可能被篡改。key code 36才是回车:硬件键码与键盘布局无关;Tab 为 48、Escape 为 53。entire contents of window极慢:读取辅助功能树在复杂 UI 上开销很大,优先用截屏 + 视觉工具核对而非遍历元素。- OS 截屏遇黑屏:显示器睡眠 / 锁屏 / 屏保或 TCC 权限缺失都会导致全黑伪证据,务必用 check-screen-recording.sh 预检并以
caffeinate保持屏幕常亮。
局限性与适用范围
需要明确的是:机器人渠道测试是 macOS-only,且不依赖 LobeHub 的 CDP 取证链路(agent-browser)。由于依赖 OS 级截屏与真实原生应用,它无法在无头 / 云端环境运行;在 Linux / CI 上应采用 CDP 类证据(agent-browser screenshot、cdp-screenshot.sh)代替。此外,该测试路线只适用于待验证行为确实落在机器人渠道(如 LobeHub 的 Slack 等 Bot Channel 适配)的场景;对于 CLI / Web / Electron 的变更,请走通用 acceptance 技能对应的验证面,而不是套用本文的 Slack 自动化。
若要在仓库中查看同类的其他平台指南作为参考对照,可阅读同一技能下的 Discord 指南、telegram/、wechat/、lark/、qq/ 目录下的 index.md,它们的驱动脚本契约完全一致,区别仅在应用名、进程名与快速切换快捷键(如 Discord / Slack 用 Cmd+K,Telegram / WeChat 用 Cmd+F)。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0627
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00