关于 serve-sim
serve-sim 技能指导 Agent 使用 CLI 操控 Apple Simulator,适合 iOS、iPad 和 Apple Watch 应用测试。内容涵盖交互、画面串流、摄像头输入及辅助功能检查等操作。
主要功能
- 01点击、滑动及多步手势
- 02浏览器预览模拟器画面
- 03注入合成摄像头画面
- 04管理应用隐私权限
- 05读取辅助功能树
- 06旋转设备及发送硬件按钮
适用场景
- 01自动化测试模拟器中的应用流程
- 02通过浏览器远程查看模拟器
- 03测试应用摄像头输入与权限
- 04按辅助功能元素定位界面控件
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ evanbacon/ serve-sim --skill serve-sim安装后在 Claude Code 中输入/serve-sim确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
README.mdevals/evals.jsonreferences/buttons-rotation.mdca-debug.mdcamera.mdendpoints.mdgestures.mdpermissions.mdworkflows.mdscripts/check-prereqs.shensure-running.sh详细介绍
serve-sim
使用 serve-sim CLI,让 Agent 操控 Apple 模拟器(iOS、iPad、Apple Watch)。serve-sim 会启动一个 Swift 辅助程序,通过 simctl io 捕获模拟器帧缓冲区,将其作为 MJPEG 流和二进制 WebSocket 输入通道公开,并在其上提供 React 预览界面。本技能将向 Agent 介绍完整的 CLI 命令、手势 JSON 格式、注意事项和推荐工作流。
适用场景
- 用户希望 Agent 对正在运行的 Apple 模拟器轻点、滑动、拖动、捏合或发送硬件按钮操作。
- 用户希望将模拟器画面流式传输到浏览器(本地、局域网或通过隧道),以便查看或远程控制。
- 用户希望向模拟器上的特定应用注入合成摄像头画面(文件、网络摄像头或动画占位画面)。
- 用户希望切换 CoreAnimation 调试叠加层(屏幕外渲染、混合图层、慢速动画)以进行性能调优。
- 用户希望以编程方式模拟内存警告或旋转设备。
- 用户希望读取模拟器的辅助功能树,以便查找 UI 元素,无需依赖像素位置。
- 用户希望授予、撤销或重置应用的隐私权限——摄像头、照片、位置、联系人或推送通知。
不适用场景
- Android 模拟器 → 使用
adb shell工具。 - 构建或安装 iOS 应用 → 使用
xcodebuild或xcrun simctl install。 - React Native 应用内运行时调试(Redux 状态、网络检查、组件树)→ 使用 rn-debugger 工具。
- 真实 iOS 硬件设备 → 使用
xcrun devicectl或 Xcode。
前置条件
执行任何其他操作之前,请确认主机满足以下条件。如果缺少任何一项,请明确告知用户需要安装什么——不要继续操作。
| 要求 | 检查命令 | 原因 |
|---|---|---|
| macOS 主机 | uname -s 返回 Darwin | serve-sim 仅能在 macOS 上运行 |
| Xcode CLI 工具 | xcrun --version 退出码为 0 | simctl 是底层模拟器驱动程序 |
| Node.js ≥18 | node --version ≥18 | serve-sim 是通过 npx 运行的 npm 包 |
| macOS 14+(可选) | sw_vers -productVersion ≥14 | 仅 camera 子命令需要 |
提供了一个打包好的辅助脚本:scripts/check-prereqs.sh。运行该脚本;如果退出码非零,请将提示信息告知用户。
大多数子命令都要求模拟器已启动。使用 xcrun simctl list devices booted 检查。如果没有已启动的模拟器,请告知用户打开 Xcode → Simulator,或运行 xcrun simctl boot <UDID>。
工作原理
┌──────────────┐ simctl io ┌─────────────────┐ MJPEG / WS ┌─────────┐
│ iOS Simulator│ ──────────► │ serve-sim-bin │ ───────────► │ Browser │
└──────────────┘ (Swift) │ (per-device) │ └─────────┘
└─────────────────┘
▲
state file in
$TMPDIR/serve-sim/
▲
┌──────────────────┐
│ serve-sim CLI │
└──────────────────┘
Agent 必须遵守的关键规则:
- 所有坐标均为 0..1 归一化坐标,显示屏左上角为
(0, 0),右下角为(1, 1)。切勿传入像素坐标。 - 每台设备对应一个辅助程序。支持多个已启动的模拟器:可传入多个设备名称,或连接到所有设备。
- 状态保存在
$TMPDIR/serve-sim/server-{udid}.json中。使用serve-sim --list查询;除非清楚自己在做什么,否则不要直接读取 JSON 文件。 - 辅助程序会记住通过
rotate设置的方向,并在客户端旋转之后的手势。旋转后发送原始坐标的 Agent 无需手动校正。
常见操作
| 目标 | 命令 | 说明 |
|---|---|---|
| 启动预览服务器 | npx serve-sim [device] | 默认预览地址为 http://localhost:3200,流地址为 :3100。以前台进程运行。 |
| 无头模式/以守护进程启动 | npx serve-sim --detach [device] | 返回包含 pid、port、url 的 JSON。可用于 Agent 循环。 |
| 在宿主的预览中显示流 | npx serve-sim --detach -q → 将 url 交给宿主的预览工具 | 参见“在 Agent 的预览中显示流”一节。 |
| 列出正在运行的流 | npx serve-sim --list | 添加 -q 可仅输出 JSON。 |
| 停止所有辅助进程 | npx serve-sim --kill | 传入 [device] 可停止指定设备。 |
| 单次轻点 | npx serve-sim tap <x> <y> | <x> <y> 的取值范围为 0..1。普通轻点请使用此命令,而不是 gesture。 参见下文的“关键注意事项”。 |
| 多步手势 | npx serve-sim gesture '<json>' | 参见 references/gestures.md。 |
| 硬件按钮 | npx serve-sim button <name> | 可用名称:home、swipe_home、app_switcher、lock、siri、side_button。参见 references/buttons-rotation.md。 |
| 旋转设备 | npx serve-sim rotate <orientation> | portrait、portrait_upside_down、landscape_left、landscape_right。 |
| 模拟内存警告 | npx serve-sim memory-warning | 等同于“调试”→“模拟内存警告”。 |
| CoreAnimation 调试 | npx serve-sim ca-debug <option> <on|off> | 选项:blended、copies、misaligned、offscreen、slow-animations。参见 references/ca-debug.md。 |
| 注入摄像头画面 | npx serve-sim camera <bundle-id> [--file <path>|--webcam [name]] | (重新)启动应用并附加摄像头 dylib。仅适用于 macOS 14 及更高版本。参见 references/camera.md。 |
| 热切换摄像头源 | npx serve-sim camera switch <placeholder|webcam|file> [arg] | 无需重新启动应用。 |
| 管理应用权限 | npx serve-sim permissions <grant|revoke|reset|list> <permission> <bundle-id> | 摄像头、照片、位置、推送通知、联系人等。参见 references/permissions.md。 |
| 读取无障碍树 | curl http://localhost:3100/ax | 返回 axe 风格的 JSON。所有端点见 references/endpoints.md。 |
当有多个设备处于启动状态时,大多数子命令都接受 -d <udid|name>,用于指定目标设备。
关键注意事项:轻点优先使用 tap,而不是 gesture
每次调用 serve-sim gesture 都会建立独立的 WebSocket。如果连续调用两次 gesture——一次使用 {"type":"begin",...},另一次使用 {"type":"end",...}——由于两次调用之间存在一定延迟,模拟器会将触摸识别为长按,而不是轻点。这是协议的一项刻意限制,并非需要设法绕过的错误。
规则:对于任何单次轻点,请使用 serve-sim tap <x> <y>。只有在拖动、滑动或多步交互(必须让 begin → move × N → end 共用同一套 socket)时,才使用 gesture。
指定目标设备
启动多个模拟器时,每个子命令都接受 -d <udid|name>。名称匹配不区分大小写,并与 xcrun simctl list devices booted 返回的设备名称进行比对。示例:
npx serve-sim tap 0.5 0.5 -d "iPhone 16 Pro"
npx serve-sim button home -d ABC12345-...
npx serve-sim --list # show all running streams
如果用户只启动了一个模拟器,可以完全省略 -d。此技能应优先自动检测,而不是硬编码设备名称。
输出模式
默认情况下,serve-sim 会向 stdout 输出人类可读的状态信息。对于 Agent 循环,建议使用 JSON 输出:
npx serve-sim --list -q # JSON array of running streams
npx serve-sim --detach -q # JSON with pid/port/url after spawn
npx serve-sim camera status -q # JSON with {alive, source, mirror, ...}
以编程方式解析 -q 输出。切勿解析不带 -q 的人类可读输出,因为它可能随版本变化。
在 Agent 的预览中显示串流
当用户要求“在这里查看模拟器”“在预览中查看”“在此工具中打开”或类似操作时,目标是将模拟器串流到用户正在聊天的同一界面中。serve-sim 会返回一个常规 HTTP URL,Agent 需要显示该 URL;如果宿主提供预览工具,则将 URL 交给该工具。
步骤:
-
启动 serve-sim 并获取 URL:
npx serve-sim --detach -q这会返回类似
{"pid":..., "port":3200, "url":"http://localhost:3200", "streamUrl":"http://localhost:3100", ...}的 JSON。url字段是面向用户的预览 UI;streamUrl是原始 MJPEG 端点。 -
始终在回复中直接显示 URL,以便用户可以在任何浏览器中手动打开。
-
检查宿主的预览工具,如果存在,则将 URL 交给该工具。工具集中可能出现的名称包括:
preview_start(Claude Code)——使用{ url: "<url>" }调用。mcp__Claude_Preview__preview_start(某些 MCP 配置)。browser_open、open_url或类似的 URL 打开工具——传入 URL。- Cursor / Codex CLI / 其他工具可能不会向 Agent 提供预览工具。这种情况下,只需打印 URL 并告知用户如何打开它(使用浏览器、IDE 内置浏览器窗格等)。
-
不要假设一定存在某种特定预览工具。 检查当前会话中可用的工具。如果有符合上述描述的工具,请使用它。如果没有,则回退到步骤 2(醒目地打印 URL)。
串流会一直运行,直到执行 npx serve-sim --kill。多个客户端(宿主的预览、用户的浏览器和隧道)可以同时读取同一个 URL。
完整操作流程请参阅 references/workflows.md 中的工作流“在宿主的预览中显示模拟器串流”。
工作流
如需完整的端到端操作流程(UI 自动化、摄像头测试、基于无障碍功能的点击、深层链接流程、预览交接),请参阅 references/workflows.md。该参考文档涵盖了 serve-sim 自带 AGENTS.md 中记录的模式。
清理
完成后始终停止辅助进程,除非用户明确要求继续运行:
npx serve-sim --kill # stop all
npx serve-sim --kill "iPhone 16 Pro" # stop one
残留的辅助进程会占用端口 3200/3100,妨碍重新启动。
反模式
- 不要传入像素坐标。 所有坐标都已归一化到
0..1。如果用户提供像素值,请用GET /config报告的屏幕尺寸进行换算。 - 不要将
gesture用于普通点击。 请使用tap。参阅上文的“关键注意事项”。 - 不要假设
npx serve-sim已在运行。 使用--list或检查$TMPDIR/serve-sim/server-{udid}.json进行确认。如果文件不存在,请显式启动。 - 首次在会话中调用时,不要跳过先决条件检查。 macOS 版本不匹配、缺少 Xcode CLI 工具或 Node 版本低于 18,都会导致后续出现难以理解的错误。
- 不要臆造按钮名称。 只有以下六个有效:
home、swipe_home、app_switcher、lock、siri、side_button。权威列表请参阅 references/buttons-rotation.md。 - 不要解析非静默的人类可读输出。 使用
-q获取 JSON。 - 不要让摄像头辅助进程在无关任务期间继续运行。 完成后使用
npx serve-sim camera --stop-webcam将其停止。 - 如果无障碍查询没有匹配结果,不要猜测坐标。 如果你获取了 AX 树(例如通过
GET /ax)来查找目标元素,但查询没有返回结果,请明确报告失败——点击猜测的位置通常远不如向用户报告“未找到目标”。请参阅 references/workflows.md 中工作流 1 的防护模式。
参考索引
- references/gestures.md — 手势 JSON 的精确格式、边界值、多点触控以及拖动/滑动操作示例。
- references/buttons-rotation.md — 六种有效按钮和四种方向,以及行为说明。
- references/camera.md — 合成摄像头注入:占位符、文件、网络摄像头、镜像模式和热切换。
- references/permissions.md — 授予/撤销应用隐私权限,包括推送通知权限。
- references/ca-debug.md — 五个 CoreAnimation 调试标志及其适用场景。
- references/endpoints.md — 适用于绕过 CLI 的 Agent 的 HTTP 和 WebSocket 端点。
- references/workflows.md — UI 自动化、摄像头测试和深层链接流程的端到端示例。