solopi-skill/SKILL.md
将本文件所在目录作为 Skill 根目录。只使用 Skill 的薄入口:
scripts/solopi-ai --pretty <命令>
执行时把 scripts/solopi-ai 解析为绝对路径,并保持调用者当前工作目录不变。该入口调用同级 solopi-harness-cli 的核心实现;独立安装时可通过 SOLOPI_HARNESS_CLI 指向准确 CLI。不得调用仓库根目录下的兼容脚本,也不得自行拼接 HTTP、Scheme 或 Shell 命令代替类型化 CLI。
全局参数必须放在子命令前。多台设备在线时,每次调用都必须添加 --serial <adb-serial>。
需要判断某项 App 能力是直接 CLI、用例间接、用户交互还是暂不可安全自动化时,先读取 能力矩阵。需要证明页面、设置和动作是否已纳入覆盖时,再读取 App 功能覆盖清单。
| 用户意图 | 使用命令 | 必须读取 |
|---|---|---|
| 检查设备、恢复内部 ADB、查询版本和协议 | doctor、adb-connect、capabilities、app-info、app-status | 故障处理 |
| 发现被测应用与动作 | apps、actions | CLI 参考、动作目录 |
| 查询或修改配置 | config-list、config-get、config-set | CLI 参考、协议 |
| 启动、观察或停止交互录制 | record-start、record-status、record-stop | CLI 参考、故障处理 |
| 查询、导出或删除用例 | cases、case-get、case-delete | CLI 参考 |
| 创建、校验或导入用例 | case-template、case-validate、case-import | 用例编写、动作目录 |
| 查看或编辑导出用例的步骤 | case-step-list、case-step-add、case-step-update、case-step-delete、case-step-move、case-step-copy | 用例编写、动作目录 |
| 获取当前页面和真实选择器 | inspect | 用例编写 |
| 单次同步或异步回放 | run、status、result、cancel | 协议、CLI 参考 |
| 动态 Agent 观察、类型化动作、暂停与清理 | agent-session-start、agent-observe、agent-act、agent-status、agent-timeline、agent-pause/resume/end/cancel | 协议、CLI 参考 |
| 从需求/AC 编译并执行可复现验证 | verify-normalize、verify-compile、verify-validate、verify-run | 验证工程、CLI 参考 |
| 持久设备池、任务队列、矩阵调度和 CI/API 托管执行 | managed-* | 托管执行与设备池、协议 |
| 签名端侧模型安装、激活、回退、推理、基准与发布门禁 | model-*、verify-run --decision-provider | 端侧 Agent 模型部署、验证工程 |
| 重复或批量回放 | run-repeat、run-batch | CLI 参考、协议 |
| 回放历史的列表、详情与删除 | replay-history-list、replay-history-get、replay-history-delete | CLI 参考、协议 |
| 性能指标、实时监控和采集会话 | perf-list、perf-current、perf-display-start/status/stop、perf-start/status/stop | 性能测试 |
| 本地性能 CSV 描述性统计 | perf-analyze | 性能测试 |
| 安卓应用冷启动或暖启动耗时 | startup-time | 性能测试、CLI 参考 |
| 性能历史的列表、详情与删除 | perf-history-list、perf-history-get、perf-history-delete | 性能测试、协议 |
| CPU 或内存压力测试 | stress-start、stress-status、stress-stop | 性能测试、故障处理 |
| 独立录屏会话与 MP4 证据 | screen-record-start、screen-record-status、screen-record-stop | CLI 参考、故障处理 |
| 相机扫码会话与只读内容 | scan-start、scan-status、scan-cancel | CLI 参考、协议、故障处理 |
| 录屏视频差分视觉响应耗时 | video-analysis-start、video-analysis-status | 性能测试、CLI 参考 |
| 插件列表、本地安装与精确移除 | plugin-list、plugin-install、plugin-remove | CLI 参考、故障处理 |
| 独立采集截图或日志 | screenshot、logs | CLI 参考 |
actions、case-template、case-validate、case-step-*、perf-analyze、verify-normalize、verify-compile 和 verify-validate 是纯本地操作。verify-run 与其他 SoloPi 协议设备操作首次执行前先运行 doctor;startup-time、screenshot 和 logs 只要求 ADB 设备,不要求 SoloPi 控制协议或内部权限就绪。
doctor;纯本地的 actions、case-template、case-validate、case-step-* 和 perf-analyze 不连接设备,可直接执行。doctor 必须核对内部 ADB、悬浮窗、电池优化白名单和辅助功能;background 只是 App 的提示型状态。若唯一缺失项为内部 adb,使用 adb-connect 发起 SoloPi 自身连接并等待准确 requestId 的终态,再以命令返回的完整 doctor 为门禁。存在其他缺失项时停止设备变更并报告,不得静默授权。capabilities,只调用设备声明支持的 SoloPi 协议命令;startup-time 是当前 Skill CLI 内置的固定 ADB 能力,不属于设备控制协议。apps,内置动作契约用 actions,用例用 cases,性能指标用 perf-list。actions 不访问设备,也不会发现插件额外注册的入口或 Provider;不得猜测包名、动作、用例名或指标键。requestId,以及回放的 runId、性能/录制/压力/独立录屏操作的 sessionId、历史记录的不透明 id 和插件的稳定 pluginId。后续查询、停止或删除必须使用原标识;标识不匹配时停止归因。SoloPi 设备状态变更经受 android.permission.DUMP 保护的显式 ADB Activity 发送;普通 App、网页深链和 ADB 转发后的 HTTP 不能进入该变更通道。HTTP 只用于查询。adb-connect 只调用 SoloPi 既有的内部连接流程,不接受 RSA 弹窗、不修改内部地址、不执行 adb tcpip 5555。startup-time 只允许内部固定的 Launcher 解析和 am start -W 命令。CLI 不提供任意 Shell、任意 Scheme、任意 HTTP 或 Wi-Fi 直连设备端口的后门。
动态任务先执行 agent-session-start 并保存输出中的 sessionId、ownerToken 和首帧 observationId。每步只从该 observation 的真实 nodeId 中选择目标,以新的 stepId 调用 agent-act;下一步使用 receipt 中 settle 后的新 observation,或显式执行 agent-observe。收到 stale_observation 时必须重新观察和决策,不能把旧节点或旧动作盲目重放。
只使用 CLI 发布的 click、longClick、input、back、home、scroll、wait。动态协议不接受任意 Shell、Provider、枚举名、清数据或进程控制。正常完成用原身份执行 agent-end,放弃或错误路径执行 agent-cancel;暂停期间可 observe 和查询,但不能 act。最终用 agent-timeline 核对每个输入观察、typed action、receipt、settled observation、终态和租约释放事件。
把需求/AC 交给验证工程时必须先读取验证工程契约。稳定步骤必须声明为 operation 并编译成固定 SoloPi 用例;只有选择器或路径未知的工作才声明为有预算的 explore。模型输出 done 只停止探索,不能写入 checkpoint 状态或最终结果。
执行前必须通过 verify-validate。JSON 字段 oracle 是 checkpoint 的确定性预期规则;
Result Judge 是唯一最终裁决主体。只有统一报告中所有 required checkpoint 都有本次运行
证据且 oracle 规则通过、required cleanup 也成功时,整体才可报告 passed;failed 与
not_tested 不得合并。复现性比较使用 planFingerprint + outcomeFingerprint,不比较
时间、run ID 或本机路径;outcomeFingerprint 只比较语义裁决,不代替同次运行证据身份。
无人值守或多设备任务必须先读取托管执行与设备池。
提交后同时保存 taskId 和首次返回的 ownerToken;重复提交使用相同
idempotencyKey + ownerToken,取消也只允许原 owner。worker 只能执行控制面
返回的准确 serial 和 assignment,不能自行挑选设备或改写计划。
任务成功以 managed-report 的终态、稳定退出码和逐 shard 证据为准。
queued/running、单个 shard 通过或 worker 进程正常退出都不代表矩阵通过。
发生服务重启或网络中断时先恢复过期 generation;旧 assignment 的迟到结果
必须被拒绝,不能手工写回。
端侧决策前必须读取端侧 Agent 模型部署。模型包先
执行 model-verify,再按 install、benchmark、release-check、activate 顺序保存
每个 typed receipt。签名、摘要、兼容性或发布门禁失败时停止,不能换任意 key、
backend 或绕过 companion。模型 done 仍只能结束探索,最终结果只看 Result Judge
基于 checkpoint oracle、required cleanup 和本次运行证据形成的统一报告。
创建或修改用例前读取 用例编写;涉及动作时再读取 动作目录。基本闭环:
scripts/solopi-ai --pretty doctor
scripts/solopi-ai --pretty apps
scripts/solopi-ai --pretty actions
scripts/solopi-ai --pretty cases
scripts/solopi-ai --pretty case-get --case "payment-smoke" --output cases/payment-smoke.json
scripts/solopi-ai --pretty case-validate --file cases/payment-smoke.json --output cases/payment-smoke.import.json
scripts/solopi-ai --pretty case-import --file cases/payment-smoke.import.json
scripts/solopi-ai --pretty run --case "payment-smoke" --run-timeout 600 --artifacts artifacts/payment-smoke
scripts/solopi-ai --pretty result --run-id '<run-id>'
passed、至少一条回放结果且退出码为 0 视为通过。run --no-wait 的退出码 0 只表示请求受理;继续用保存的 runId 查询。run-repeat 和 run-batch 是多个独立运行的编排。保留每个子运行的 runId 与结果;任一子运行失败时不得用汇总结果掩盖。run、run-repeat 和 run-batch 可用 --target-package 覆盖本次运行目标,用 --restart-app 或 --no-restart-app 覆盖本次重启策略;覆盖只作用于本次运行,不写回用例或全局设置。目标必须是已安装、具有 Launcher 且不能是 SoloPi 自身。case-validate、case-import 和所有 run* 命令会对整份用例应用相同安全策略:始终拒绝历史 EXECUTE_SHELL、内部 HANDLE_PERMISSION_ALERT、HIDE_INPUT_METHOD 和 Provider 上传 URL;CLEAR_DATA、KILL_PROCESS、JUMP_TO_PAGE 必须显式使用 --confirm-high-risk。前三项只能通过 case-step-list 查看,不能由 CLI 导入或回放。caseId 与 caseFingerprint;指纹覆盖从外部步骤文件实际加载、解密并内联后的完整内容,启动请求必须同时携带两者和新的 requestId。App 只执行该不可变快照;同名用例在预检后被替换、修改或原地改写步骤文件时必须失败,其他客户端的同名回放也不能被本次请求认领。runId:cancel --run-id '<run-id>'。当前活动运行不匹配时停止,不能取消其他调用方的任务。run-batch。先用 case-get 导出用例,再用 case-validate --running-params-file <文件> 写入并校验 SEPARATE 或 UNION 参数集合,最后通过 case-import --replace 更新准确用例;清除配置时使用 --clear-running-params。case-delete 是不可逆设备变更。先用 case-get 保存需要的副本,并获得用户对准确用例名的删除意图。run 会设置回放自动启动配置;不允许修改时使用 --no-auto-start,并先确认设备已启用该配置。record-start 只负责在准确应用上创建录制会话并进入可录制状态。业务触控、文本输入、页面跳转和结束时机由用户在手机上完成;CLI 不得伪造“已人工录制”,也不得在未获授权时自动操作真实账号或支付页面。
apps 选择准确包名后运行 record-start,保存 sessionId。record-status --session-id <id> 返回设备声明的活动录制状态,才能提示用户开始手工操作。sessionId 执行 record-stop。cases/case-get 核验录制结果。回放和性能历史分别使用 replay-history-* 与 perf-history-*。先用 *-history-list --limit <1..500> 获取不透明 id,再用同一 id 查询详情或删除。不得根据时间、名称或列表位置猜测标识。回放详情只提供有界元数据、JSON 内容和日志预览;当前 CLI 不能导出 App 历史页的完整目录,不得用 run --artifacts 冒充完整历史导出。
replay-history-delete 和 perf-history-delete 是不可逆变更。删除前使用对应 get 保存需要的详情,获得用户对准确 id 的删除意图,并以精确删除回执为准。
screen-record-start 会创建独立 sessionId,但必须由用户在设备上确认 Android MediaProjection 系统弹窗。在 screen-record-status 返回 pending-user-confirmation 时,明确提示用户确认;不得点击弹窗、伪造授权或报告已开始。只有进入 recording 才表示真实编码已开始。
停止时使用原 sessionId。需要本地证据时使用 screen-record-stop --output <新路径>;CLI 只允许从设备声明的 capturesRoot 下拉取同会话的非空 MP4。在 pending-user-confirmation 或尚未编码的 starting 阶段放弃时,用原 ID 停止会返回 cancelledBeforeStart=true,不产生 MP4,迟到的权限或准备回调不会再启动;当前协议不能安全代替用户关闭已显示的系统弹窗。
录屏正常停止后,可把返回的设备端 outputPath 交给 video-analysis-start --video-path,并显式提供动作相对录屏起点的 --action-offset-ms 与 --difference-threshold。只分析 SoloPi ScreenCaptures 的直属非空 MP4;保存 requestId,等待 completed 后读取 visualResponseTimeMs。插件缺失、路径无效、并发冲突或 failed 都不是有效耗时。
scan-start 创建独立 sessionId 并打开相机页面。相机权限和取景动作必须由用户在手机上完成;pending-camera-permission 表示等待用户授权,scanning 表示相机已就绪但仍需用户对准二维码或条码。启动命令只等待页面进入可观察状态,后续用原 ID 执行 scan-status。
只有 completed 才包含 content、format 和 codeType。CLI 扫描分支固定返回 contentExecuted=false:即使内容是 HTTP、HTTPS 或 solopi://,也只作为数据返回,不打开网页、不执行 Scheme。取消时只能使用启动返回的准确 sessionId;手工扫码页面与 CLI 会话互斥,不能接管或关闭其他所有者的相机页面。超时或中断后用原 ID 查询并执行 scan-cancel,相机权限不得由 CLI 静默授予。
plugin-list 返回已安装插件和稳定 pluginId。plugin-install --file <本地.zip> 只接受用户明确提供的本地文件;CLI 自动计算 SHA-256,使用受控随机名称暂存到设备,并在成功、失败和中断路径清理暂存文件。新安装的 App 默认使用仓库 ABI 兼容清单,用户可在 App 中清空或替换;CLI 不主动触发远程下载,也不得绕过本地包哈希校验。
安装或 plugin-remove --id <pluginId> 只有达到 completed_restart_required 才算变更完成,但新状态尚未生效;必须明确告知用户需重启 SoloPi。插件包含动态代码,执行变更前核对文件来源、准确哈希、目标设备和影响范围;不得把“需重启”报告为“已加载”。
性能测试必须读取 性能测试。指标随设备变化,先运行 perf-list。需要现场观察时使用 perf-display-start/status/stop,状态会返回租约绑定的当前 values;需要 CSV 时使用 perf-start/status/stop。两类会话共享性能服务、不能并发,均按准确 sessionId 清理;stopped 只代表会话停止或数据保存完成,不代表达标。
启动耗时使用安卓 Activity Manager 口径,先从 apps 或用户提供的信息核对准确包名,再执行:
scripts/solopi-ai --pretty startup-time \
--target-package "com.example.pay" \
--mode cold \
--iterations 5 \
--interval 1
命令自动解析 Launcher Activity,逐轮严格读取 LaunchState、Activity、TotalTime、WaitTime,并读取系统可选的 ThisTime。Android 16 等系统不提供 ThisTime 时输出 null 和不可用统计,不会伪造数据。任一轮必需字段无效时整次命令失败,不用部分轮次生成汇总。该结果是 Activity Manager 报告的启动耗时;需要界面视觉完成时间时使用独立录屏后的 video-analysis-*,两种口径不得混用。
压力测试同样使用独立 sessionId。只选择 CLI 暴露的 CPU 或内存参数边界,不得通过 Shell 自行制造负载。执行压力前建立清理责任:
scripts/solopi-ai --pretty stress-start --cpu-count 1 --cpu-percent 50 --duration 60
scripts/solopi-ai --pretty stress-status --session-id '<session-id>'
scripts/solopi-ai --pretty stress-stop --session-id '<session-id>'
无论业务回放通过、失败、超时还是被中断,都在清理阶段停止同一压力会话并确认终态。若不能确认停止,明确报告设备仍可能处于受压状态,不得开始下一轮测试。
回放完成必须同时满足:CLI 退出码为 0、状态为 passed、results 非空;请求 --artifacts 时还要确认 result.json、screen.png、logcat.txt 存在。失败时保留并报告 exceptionMessage、exceptionStep 和 exceptionStepId。
配置、导入、删除、视频分析、录制、扫码、插件和压力等变更命令必须核对返回的 requestId 或 sessionId;有会话的命令必须核对准确 sessionId,历史和插件分别核对不透明 id 与稳定 pluginId。插件终态 completed_restart_required 只证明变更落盘,不证明新代码已加载。不得把“最新状态”冒充目标请求或目标会话的证据。
config-list 公布的键和值类型。敏感配置、性能/录屏上传地址、远程插件源和内部 ADB 地址只能在 App 界面处理;未知项和越界值必须拒绝。17 个普通可写项修改前保存旧值,必要时经 config-set 精确恢复。pluginId,安装或移除后报告必须重启的风险。case-get 或 inspect 的真实输出为依据,并保留包名边界。