mcpField
S
sim-use

sim-use

github.com/lycorp-jpAgent 工作流1.5k163 次安装1 周前更新
代码仓库

关于 sim-use

sim-use 是通过 sim-use 命令行操作移动设备模拟器的 Agent 技能,并有限支持实体 iOS 设备。它采用观察、操作、验证的循环,侧重选择器交互和设备能力限制的检查。

主要功能

  1. 01通过界面大纲观察屏幕
  2. 02使用选择器点击界面元素
  3. 03输入、粘贴文本并执行手势和滚动
  4. 04通过界面或截图验证操作
  5. 05批量执行已知的 iOS 交互序列

适用场景

  1. 01在移动设备模拟器中运行脚本流程
  2. 02检查并测试应用界面状态
  3. 03在输入框中录入 Unicode 或多行文本
  4. 04采集模拟器会话的视觉证据

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/lycorp-jp/sim-use --skill sim-use

安装后在 Claude Code 中输入/sim-use确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
batch-reference.md
cheatsheet.md
crash-awareness.md
pitfalls.md
scripts/
preflight.py

详细介绍

0. 预检

首次与设备交互前,请运行预检:

python3 scripts/preflight.py --device <UDID>

这会验证 sim-use 已安装且与该技能兼容、设备可访问,并且守护进程运行正常。如果没有该脚本,请手动执行以下检查:

  1. sim-use --version — 确认 sim-use 位于 PATH 中,且支持该技能文档中列出的命令。
  2. sim-use devices — 确认目标设备已列出,且已启动/连接。
  3. sim-use ui --device <UDID> — 确认可以读取屏幕。

WARN UI content 行仍表示预检通过:读取操作成功,但大纲可能遗漏应用控件。请参阅 常见问题 索引。

仅当只有一个模拟器已启动或只有一个守护进程正在运行时,--device 才是可选项。对于 Android,请运行一次 sim-use android init --device <serial> 以安装桥接 APK。已连接的实体 iPhone/iPad 会以 physical 类型显示在 sim-use devices 中,也可以通过顶层动词操作——但仅限 ui、基于选择器的 tap 和 screenshot;该目标不支持其他所有动词。操作实体 iOS 设备前,请参阅下文的 实体 iOS 设备。Linux 版 sim-use 仅支持操作 Android:其中不提供 sim-use ios …、record-video/stream-video、viewer 和 init,每个动词都需要 --device <serial>,并且 sim-use devices 只会列出 Android 设备。

1. 观察—操作循环

每次交互都遵循同一流程:观察 → 操作 → 验证。

观察
sim-use ui --device <UDID>

读取大纲。每个元素都有一个 @N 别名,以及可选的 #<id> 标识符。列表单元格带有 #N(主列表)或 #N@M(限定范围)。

JSON 输出中的帧(--json:entries[].frame、screen)使用平台原生单位——iOS 使用点,Android 使用像素。在跨平台计算坐标前,务必根据外层对象的 platform 字段确定平台。始终将 --json 与 --no-raw 搭配使用——请参阅下文的 精简输出。

操作

按优先顺序选择一个选择器:

选择器使用时机
tap @N紧接 ui 使用。速度最快,且由缓存支持。
tap #<id>在轻微布局变化下仍然稳定。从大纲中复制。
tap --label 'X'用于脚本化流程。搭配 --wait-timeout 处理状态转换。
tap --label-regex '...'用于带计数器/时间戳的动态标签。使用 ^...$ 锚定。
tap --label-contains 'X'不清楚确切标签时进行子字符串匹配。
tap -x N -y N / tap --point x,y作为最后手段,用于没有 AX 数据的元素。可直接使用大纲打印的数字,适用于任意方向和显示屏;--coordinate-space native 用于设备原生的纵向点坐标。

使用 --element-type 或 --frame minY=0.7r 区分冲突项(参阅 references/cheatsheet.md)。

验证

操作后务必验证——命令会立即返回,不会等待完成:

sim-use ui --device <UDID>       # read the new screen state
sim-use screenshot --device <UDID> --output after.png
控制输出大小

读取命令输出的每个字节都会占用上下文。以下默认做法有助于降低循环开销:

  • 优先使用默认的文本大纲,而不是 --json。大纲包含一次点击所需的所有信息(@N / #<id> 别名、角色、框架、状态);需要用于坐标计算的结构化字段(entries[].frame、screen)或未截断的完整文本时,再使用 --json(大纲会将标签截断为 60 个字素,将 value= 截断为 30 个字素)。
  • 使用 --json 时,添加 --no-raw。data.raw 是原始无障碍树,通常占据输出的大部分字节,只有在调试 sim-use 本身时才有用。
  • 每次操作只执行一次 ui:第 N 步的验证读取,就是第 N+1 步的观察读取。两者之间不要再运行第二次 ui。
  • 使用文本大纲验证,而不是截图。读取截图的开销是典型大纲的数倍;仅在确实需要进行视觉检查(颜色、图像、布局)时才截图。
  • 在 iOS 上等待过渡时,优先使用 tap --label 'X' --wait-timeout 3(轮询元素),而不是循环运行 ui。Android 的 tap 没有 --wait-timeout;请改为在命令之间使用 sleep。
  • 对于已知的多步 iOS 操作序列,使用 sim-use ios batch(参见 references/batch-reference.md)——一次调用,一次输出。
常用操作
任务命令
向下滚动sim-use gesture scroll-up --device <UDID>(scroll-up = 内容向上移动 = 页面向下滚动)
输入文本sim-use type 'hello' --device <UDID>
粘贴 Unicode聚焦输入框,然后执行 sim-use paste 'こんにちは 🎉' --device <UDID>;iOS 在 Simulator.app 或 Device Hub 中均可使用,且不受键盘模式影响
硬件按钮sim-use button home --device <UDID>
Android 返回sim-use button back --device <UDID>
等待动画在命令之间执行 sleep 0.4,或使用 --pre-delay 0.5
切换开关sim-use tap @N --duration 0.05 --device <UDID>(UISwitch 需要短暂按住)
滑动sim-use swipe --from 50,500 --to 350,500 --device <UDID>
捏合放大sim-use gesture pinch-out --device <UDID>(双指张开)
旋转(双指手势)sim-use gesture rotate-cw --angle 90 --device <UDID>
旋转设备(iOS)sim-use ios rotate landscape-left --device <UDID>——界面名称以 App: 标题打印的名称为准;之后重新运行 ui
折叠 / 展开(iPhone Duo)sim-use ios fold closed|open --device <UDID>;sim-use ios fold --device <UDID> 会报告当前启用的显示屏;之后重新运行 ui
录制证据 GIFsim-use record-video --output demo.gif --device <UDID>——使用 SIGINT/SIGTERM 停止(绝不要使用 SIGKILL);停止后会转码;在 PR 中自动内嵌播放;添加 --gif-markers 可插入 START/END 循环边界卡片
在 iOS 模拟器中粘贴

对于 Unicode 和兼容输入法的文本,优先使用 paste。默认行为会保留当前焦点字段中的插入点和选区。--replace 会先全选。使用 --via-menu --target-id <id> 或 --target-x/--target-y 可显式聚焦目标。两种方式都会使用系统原生的“粘贴”操作;无需更改硬件键盘或同步设置。

对于多行文本或包含 Shell 特殊字符的文本,请使用 printf '%s' "$TEXT" | sim-use paste --stdin --device <UDID> 或 paste --file <path>。仍会遵循控件的原生规则,包括单行规范化和智能粘贴空格。如果无法使用“全选”,且无法通过辅助功能确认字段为空,--replace 会在粘贴前失败。切勿将此拒绝视为替换成功。对于来源未知或不明确的菜单操作,也会拒绝;不要通过点击应用中标签相同的按钮来绕过此拒绝。务必核实字段中的实际内容。如果命令报告可能已发送粘贴操作,请先检查字段再重试;命令不会自动重新发送粘贴操作。

共享剪贴板同步也可能覆盖 Mac 和其他设备上的内容。请确保只有一个剪贴板写入方处于活动状态。sim-use 会串行处理自身的粘贴操作,并检查是否意外读回了内容,但无法阻止外部写入。切勿打印无关的剪贴板数据,也不要用旧备份覆盖较新的外部内容。

批量粘贴支持默认粘贴、替换、文件和显式菜单目标;paste --stdin 不能作为批处理步骤,因为 stdin 属于整个批处理。发生暂时性的启动就绪错误后,失败的批处理不会自动重放。重试前请检查 UI 和已完成的步骤,包括使用 --continue-on-error 时。

实体 iOS 设备(实验性)

顶层动词会自动路由到实体 UDID,但仅限其中三个:ui、tap(#<id> / --id / --label / --label-contains / --element-type 形式)和 screenshot。切勿假定其能力与模拟器一致——其他所有动词或形式(坐标、@N/#N 别名、滑动/手势/多点触控、输入/粘贴、录制、--value/--label-regex/--frame/--duration/--wait-timeout)都会拒绝执行,并在 hint 中说明原因和最接近的替代方案;请阅读提示,不要重试。sim-use ios-device 命名空间是 ios/android 的实体设备专用对应版本(动词相同,另支持 ECID 寻址和树调优标志)。

**ui / tap 的硬性要求:**设备必须已配对、受信任、解锁并开启开发者模式,且前台目标应用必须使用开发签名,并设置 get-task-allow=true。使用 Development 配置文件安装的 Release 配置二进制文件受支持。Distribution、Ad Hoc、TestFlight、App Store 和系统应用均不受支持;不要重试,也不要声称成功。sim-use 本身不会安装或签署任何 runner,也不需要 Developer Disk Image。screenshot 不受签名规则限制——它通过 CoreDevice 运行并截取任何屏幕,包括系统应用。

# Physical-device preflight — physical rows carry kind `physical`
sim-use devices

# Observe → act → verify, same loop and verbs as the simulator
sim-use ui --device <UDID>
sim-use tap --label "Friends" --element-type Button --device <UDID>
sim-use ui --device <UDID>

# For dynamic labels
sim-use tap --label-contains "Reply" --element-type Button --device <UDID>

# By stable identifier (the #id shown in ui) — positional or --id
sim-use tap '#BackButton' --device <UDID>

# Screenshot — any screen, not limited to development-signed apps
sim-use screenshot --output shot.png --device <UDID>

此实验性功能的规则:

  1. **将层级结构错误视为能力限制。**如果命令提示层级结构不可用,请确认屏幕已解锁,并检查已安装应用最终的 get-task-allow 权限。不要改用坐标或焦点遍历。
  2. **使用 #id 或标签点击,不要使用 @N。**元素句柄会随 DTX 连接失效,因此没有 @N 别名(也不支持坐标——没有几何信息)。使用大纲中显示的 #id(位置参数 #<id> 或 --id)——它稳定可靠,在标签动态变化时尤其适用——或使用 --label / --label-contains,并通过 --element-type 消除歧义。导航栏的返回按钮会显示为普通的 Button "<previous screen title>" #BackButton;像点击其他元素一样,点击 #BackButton(或显示的标签)即可返回——没有专用的“back”动词。
  3. **始终验证。**Activate 会立即返回,不等待操作结果。重新运行 sim-use ui,确认状态符合预期后再继续。
  4. **遵守能力限制提示。**出现 not supported on physical iOS devices 错误,说明该通道不支持此操作,并非暂时性故障——请遵循提示(通常是使用 ui 和 tap '#<id>' / --label),不要重试或替换为看似相近的形式。所有动词都支持 --json,并使用标准的 {ok, data} 封装;实体设备结果包含 "kind":"physical",且不含几何字段(screen、x/y)。
  5. **按秒而非毫秒预留时间。**完整树需要几秒钟。sim-use ios-device ui --fast 速度更快,但会省略嵌套元素;不要高频轮询。

如果 ui 成功却返回零个元素,或 tap 对不存在或有歧义的标签报告成功,请视为 sim-use 的错误;命令理应明确报错。

2. 常见问题

快速症状索引——详细操作方法请参阅 references/pitfalls.md。

症状原因解决方法
tap --label 点到了错误的元素标签冲突(例如,标题栏和标签栏包含相同文本)添加 --frame minY=0.7r 或 --element-type 以缩小范围
导航后 tap @N 失败别名缓存已过期点按前重新运行 ui
App: 行显示了错误的应用系统层(提醒、共享表单)位于最上层先将其关闭,然后重新运行 ui
出现 multipleMatches 错误多个元素匹配同一选择器使用 --frame、--element-type 或更具体的选择器
点按成功,但没有任何反应动画正在进行,或元素尚不可交互添加 --pre-delay 0.3 或 --wait-timeout 3
iOS:paste 失败或文本缺失没有聚焦的字段、自定义编辑菜单、粘贴提示,或外部剪贴板写入器聚焦该字段,或使用 paste --via-menu --target-id <id>;检查提示并确认实际字段内容。不要改用 type 来替代 Unicode 输入
Android:paste 被拒绝后台剪贴板访问被阻止改用 type
大纲中的标签显示 U+FFFCiOS 图标占位符字符使用排除该前缀的 --label-regex 进行匹配
[i] … covers ~N% of the screen 警告(文本输出,或 --json 顶层的 advisory 键)选择器解析到了一个几乎占满全屏的包装元素(Flutter/画布 UI 中很常见),点按落在其中心,因此可能没有点中目标控件重新运行 ui,通过 @N/#<id> 定位控件,或传入明确的 -x/-y/--point
[i] Screen orientation could not be confirmed…/…coordinates may be stale… 提示设备/应用已旋转(App: 标题显示类似 (landscape-right) 的标记),且方向自动校准无法验证坐标映射;或者 @N 快照早于旋转操作重新运行 ui 并再次点按;校准成功后,选择器会自动处理旋转。明确指定的 -x/-y/--point 使用大纲(视觉空间)坐标,并依赖同一校准;--coordinate-space native 用于设备原生纵向坐标
大纲为空或未显示应用中可见的控件,或出现 [i] … recovered from other processes … 提示(--json:advisory.kind: remote_content_recovery)应用提供了空的辅助功能树。系统选择器中属于正常情况。其他情况下,在 iOS 模拟器上,一个可能原因是应用启动时辅助功能处于关闭状态将大纲与屏幕进行对照。如果缺少控件,请参阅缺失的应用控件
iOS:在所有屏幕上,ui 都报错 No translation object returned for simulator <UDID> for the frontmost application,而 screenshot 和 ui --point 仍可正常工作模拟器的辅助功能桥接(CoreSimulatorBridge)已过期按照错误提示操作:运行 xcrun simctl spawn <UDID> launchctl stop com.apple.CoreSimulator.bridge(launchd 会立即重启它),然后重试 ui。刚启动模拟器后,先等待几秒再重试
iOS:ui 标题以 inner display、cover display(较早的版本中,内屏显示为 display LCD-1)或 display Resizable 560x874 结尾应用正在指定的 Duo 屏幕或 Xcode 27 调整大小模式显示屏上运行。内屏处于激活状态并不代表铰链已完全打开。--json 保留原始名称;主屏/外屏上没有 data.display。Touch、ui、ui --point、screenshot 和 record-video/stream-video(h264、bgra)都会自动路由按常规方式操作——选择器和 @N 会定位到该显示屏;iOS 27.1 SDK 应用的竖栏(返回按钮、标签)会最后列为 [Trailing …]/[Leading …]。明确指定的 -x/-y 使用 ui 在那里打印的数值;--coordinate-space native 表示该显示屏的原生坐标点。请参阅 iPhone Duo 和 调整大小模式

3. 崩溃感知

完整协议请参阅 references/crash-awareness.md。摘要:

sim-use 会监视目标进程是否在命令之间消失。检测到崩溃时:

================ PROCESS DISAPPEARED ================
com.example.app (pid 12345) was alive at the previous command and is GONE now.

在 Android 上,ui 还会直接通过无障碍树检测 AOSP 系统崩溃对话框。

必须执行的响应:

  1. 停止。 不要悄悄重新启动或继续操作。
  2. 使用横幅文本向用户报告崩溃。
  3. 等待用户指示后再继续。

有意重新启动后,调用 sim-use app-state --reset 清除信号。

4. 升级处理

遇到以下情况时,停止操作并询问用户:

  • 使用现有消歧条件无法解决选择器冲突。
  • 预检失败,且自动修复未能恢复。
  • 任务需要执行破坏性操作(删除数据、卸载应用)。
  • 同一操作已重试 3 次,但没有进展。

5. 退出检查清单

在报告任务已完成之前:

  1. 运行 sim-use ui(或 screenshot)以捕获最终状态。
  2. 确认屏幕与预期结果相符。
  3. 如果结果不明确,向用户展示最终的 ui 输出或截图。

评论

支持 Markdown