【免费下载链接】paseo
Orchestrate multiple coding agents from desktop and mobile
本文是 Paseo 仓库开发流程的核心质量规范(对应 docs/qa.md)。Paseo 是一个同时覆盖桌面端(macOS / Windows / Linux / Electron)与移动端(iOS / Android / Web)的多 Agent 编排产品,其质量体系围绕四个问题展开:功能是否真的好用、是否引入回归、是否覆盖所有受影响的平台、自动化测试是否真实有效。读完本文,你将掌握 Paseo 评审每一个 Pull Request 时使用的证据标准、平台覆盖矩阵、性能回归验证方法,以及"真实测试优先于 Mock"的自动化覆盖底线,并能直接落地到自己的变更提交中。
一、四问门槛:QA 是 Paseo 产品开发的最大瓶颈
Paseo 明确把 QA 视为产品开发的主要瓶颈,并为此设定了四条硬性门槛。每一个 Pull Request 都必须为它触及的问题提供证据,没有证据的 PR 会被直接关闭:
- Does it work well?功能是否真正好用?
- Does it regress anything else?是否让其他功能回退?
- Was it tested on every platform it affects?是否在它影响到的每一个平台上测试过?
- Is there automated coverage, and is that coverage real?是否有自动化覆盖,且该覆盖是否真实有效?
这四问不是抽象口号,而是评审动作的判定标准:变更触及哪一问,就必须为该问提交对应证据。对于插件变更,还要先在 docs/plugins.md 中核对 SDK 导入边界,并把边界测试与两个运行时加载器(index.server.ts子进程与index.client.tsx客户端)一并纳入证据。
二、什么是"证据":可以被别人复核的东西
证据的定义是**"别人能看得见的东西"**,而不是你的自我声明。可接受的证据形式包括:
- 你运行过的命令及其输出(原样粘贴)
- 你新增的测试及其结果
- 改动前后的截图
- 交互过程录制的视频
- 日志、请求、响应
规范要求按需脱敏、保留技术细节。特别值得注意的是:如果工作是 Agent 完成的,必须提交它的原始输出——因为摘要会丢失别人核验所需的关键细节。
三、第一问:Does it work well——能用但不流畅就不算完成
一个"能用"但卡顿、布局跳动或偏移两个像素的功能不算完成。对 UI 而言,这意味着视觉、交互和性能三方面都要匹配设计系统,设计基准是 docs/design.md。
最常见的两类问题被单独点名:
- 布局漂移(Layout shift):内容随数据到达而跳动、徽章出现时行高变化、首次渲染时面板重排。要求观察慢网速和首屏加载时的表现,而不是只在一切预热之后检查。
- 对齐(Alignment):元素对齐到"字形"而不是"触摸目标"。具体对齐规则见 docs/design.md 的第 8 节——行首图标、标题、尾部按钮标签必须落在同一导轨(rail)上,对齐的是墨迹而非内边距。
设计规范在仓库里有完整的落地实现:token 全部收敛在 packages/app/src/styles/theme.ts,按钮统一使用<Button>(packages/app/src/components/ui/button.tsx),状态徽章统一使用<StatusBadge>(packages/app/src/components/ui/status-badge.tsx)。QA 的第一问实际上要求你对照这些组件基线而非"手搓样式"来验收。
四、第二问:Does it regress anything else——组合式架构下的回归面
Paseo 天生是**可组合(composable)**的设计,这意味着你的改动旁边就是你没碰过的功能。规范给出的两个典型例子:
- 改动 Agent 列表,会影响归档(archive)、子 Agent(subagents)和标签(tabs);
- 改动 Git 操作,会影响 worktree 和检出流程(checkout flow)。
因此要求"打开周围的表面"逐一验证。性能也是回归的一部分:Paseo 是 Expo React Native 应用,不是套了原生壳的 Web 应用——你写的不是 CSS,样式解析方式不同,各平台的性能特征也不同。在桌面 dev build 里"秒开"的交互,在手机上可能明显变慢。
如果改动触及热路径——终端(terminal)、消息列表(message list)、Git 轮询(git polling)——必须提交改动前后的数字。终端流水线及其基准见 docs/terminal-performance.md,渲染器与 React 性能分析见 docs/development.md。
以终端热路径为例,docs/terminal-performance.md 给出了完整的测量手段,QA 报告可以直接引用:
- Node-only 基准(快速迭代):
npx tsx scripts/benchmark-terminal-latency.ts,启动隔离 daemon(全新PASEO_HOME、随机端口,绝不用 6767),测量回显延迟百分位、突发抖动与快照次数,结果写入/tmp/paseo-terminal-bench/; - 浏览器性能 spec(用户感知路径):
PASEO_TERMINAL_PERF_E2E=1门控下的 packages/app/e2e/browser/terminal-performance.spec.ts 与 terminal-keystroke-stress.spec.ts; - 生产观测:grep
daemon.log中的ws_runtime_metrics,读取eventLoopDelay与bufferedAmount——eventLoopDelay是"daemon 是否繁忙"的 ground truth,其 p99/max 直接约束终端帧的最坏延迟。
五、第三问:Every platform it affects——平台覆盖矩阵
你的代码不只运行在你测试过的平台上。同一套应用会发布到iOS、Android、浏览器 Web,以及 macOS / Windows / Linux 上的 Electron,daemon 则运行在三大桌面操作系统外加 Docker。
规范不要求你拥有每一台设备,但要求你明确说出覆盖了什么。每个 PR 都应填写这张平台矩阵:
| Platform | Tested | Notes |
|---|---|---|
| iOS | ||
| Android | ||
| Web | ||
| Desktop macOS | ||
| Desktop Windows | ||
| Desktop Linux |
合理范围内尽量安装环境:一台机器上的 iOS 模拟器 + Android 模拟器就能覆盖大部分平台差距,参见 docs/development.md 与 docs/android.md。
两个跨平台注意点:
- 代码在哪里运行:平台门控规则见仓库根目录 CLAUDE.md 的 platform gating 一节。反复踩坑的领域各有专门文档:docs/hover.md(hover 在原生端不触发)、docs/unistyles.md(Unistyles 与 Reanimated 冲突)、docs/floating-panels.md(浮动面板与键盘布局)、docs/mobile-panels.md(移动端面板)、docs/expo-router.md(路由与启动恢复)。
- 版本漂移:App 与 daemon 是独立发布的,版本会双向漂移(新 App 配旧 daemon、旧 App 配新 daemon 都会真实存在)。这套契约独立成文,见 docs/protocol-compatibility.md——协议层变更必须证明"六个月前的 App 仍能解析这个消息、六个月前的 daemon 仍能满足这个 App"。
从源码结构看,客户端能力由packages/client包统一声明(packages/client/src),App、CLI、插件继承这些默认值,这正是"每平台行为一致"的实现基础:能力检测只发生在一处,下游读取的都是干净形状。
六、第四问:Automated coverage that means something——测试只有在验证真实事物时才算数
测试只有在真实执行时才构成证据:
- Bug 修复需要回归测试,且该测试必须因为报告的原因在旧代码上失败;
- 功能需要走用户或调用方实际使用的同一接口的测试;
- Web 流程需要真实的 Playwright 运行,而不是 mock 出来的近似;
- Agent provider 工作需要能判断"它成功了"的人对着真实 provider 手动验证——fixture 和 mock 只能证明 fixture 能解析,仅此而已。
"把行为 mock 掉、断言内部实现、或者能在坏代码上通过的测试"都是在宣称并不存在的覆盖。完整标准见 docs/testing.md(含如何在不冻结机器的情况下跑测试套件)。
6.1 测试只有两种形状
docs/testing.md 明确:仓库里每个测试只属于两种形态之一——
- 带端口与适配器的单元测试(unit tests with ports and adapters):生产代码通过注入接口接收真实世界依赖(DB、HTTP、CLI 进程、时钟、随机性、文件系统、其他模块),测试用与生产模块同目录的、类型化的内存 fake 来接线。禁止
vi.mock、vi.hoisted、vi.spyOn自身导出、JSDOM、@testing-library组件挂载、RN 测试渲染器、全局猴子补丁与 fake-server fixtures。一旦需要其中任何一样,说明生产模块缺少端口——先修接缝,再对着 fake adapter 写测试。 - 真实端到端测试(real end-to-end):真实 daemon、真实网络、真实浏览器(App 代码用 Playwright),或真实隔离的服务器实例(daemon 代码)。没有 JSDOM,没有 mock 传输。
介于两者之间的东西——JSDOM 里的组件测试、mock 被测模块的 vitest 测试、断言私有状态的测试——被明确判定为"正在被淘汰的废料"。
6.2 测试文件后缀即分类
Vitest 按后缀识别测试归属,后缀决定了它属于哪个类别、在哪条流水线运行:
| Suffix | What it is | Where it runs |
|---|---|---|
*.test.ts(x) | 单元测试——纯、快、无 daemon | npm run test:unit |
*.posix.test.ts | 需要 POSIX 专属行为的单元测试 | 单元测试,Windows 上跳过 |
*.browser.test.ts | 需要真实浏览器(DOM)的 App 测试 | npm run test:browser(Vitest browser 模式,Playwright provider,headless Chromium) |
*.e2e.test.ts | 针对真实 daemon 的端到端测试 | npm run test:e2e |
*.real.e2e.test.ts | 命中真实 provider(Claude/Codex/Copilot/OpenCode/Pi)的 E2E,需在packages/server/.env.test配置凭据 | npm run test:integration:real/test:e2e:real |
*.local.e2e.test.ts | 需要本地专属资源的 E2E | npm run test:integration:local/test:e2e:local |
浏览器 Playwright spec 位于 packages/app/e2e/browser/,桌面 Playwright 与真实 Electron E2E 位于 packages/desktop/e2e/,两套共享的 harness 代码在 packages/app/e2e/support/。App 侧命中真实 provider 的 spec 用*.real.spec.ts后缀,默认浏览器 project 会忽略该后缀,因此 CI 无需 provider 凭据也能全绿——真实 provider 冒烟测试必须放在*.real.e2e.test.ts,即使有环境变量保护也不能降级到*.test.ts。
6.3 驱动真实 daemon:ad-hoc daemon 测试
"真实 daemon"如何落地?docs/ad-hoc-daemon-testing.md 提供了隔离进程内 daemon 测试 harness,不触碰 6767 端口的常驻 daemon。要点(仅供测试代码使用,产品启动路径必须走scripts/supervisor-entrypoint.ts):
import os from "node:os"; import path from "node:path"; import { mkdir, mkdtemp, rm } from "node:fs/promises"; import pino from "pino"; import { createPaseoDaemon } from "./bootstrap.js"; import { DaemonClient } from "./test-utils/daemon-client.js"; const logger = pino({ level: "warn" }); const paseoHomeRoot = await mkdtemp(path.join(os.tmpdir(), "paseo-test-")); const paseoHome = path.join(paseoHomeRoot, ".paseo"); await mkdir(paseoHome, { recursive: true }); const staticDir = await mkdtemp(path.join(os.tmpdir(), "paseo-static-")); const daemon = await createPaseoDaemon( { listen: "127.0.0.1:0", // OS 分配空闲端口 paseoHome, corsAllowedOrigins: [], hostnames: true, mcpEnabled: false, staticDir, mcpDebug: false, agentClients: {}, agentStoragePath: path.join(paseoHome, "agents"), relayEnabled: false, relayEndpoint: "relay.paseo.sh:443", appBaseUrl: "https://app.paseo.sh", }, logger, ); await daemon.start(); const target = daemon.getListenTarget(); const port = target!.type === "tcp" ? target!.port : null; const client = new DaemonClient({ url: `ws://127.0.0.1:${port}/ws`, appVersion: "0.1.70", }); await client.connect(); await client.fetchAgents({ subscribe: {} }); // ... do your testing ... await client.close(); await daemon.stop(); await rm(paseoHomeRoot, { recursive: true, force: true }); await rm(staticDir, { recursive: true, force: true });运行方式:npx tsx packages/server/src/server/your-script.ts。常用测试工具位于 packages/server/src/test-utils/,如vitest-setup.ts统一加载.env.test并设置PASEO_SUPERVISED=0、禁用 Git/SSH 交互提示。
该文档还总结了多条实战 gotcha,写测试时可直接引用:
- appVersion 门控 provider 可见性:daemon 对未携带
appVersion >= 0.1.45的客户端隐藏非 legacy provider(claude/codex/opencode 之外的),DaemonClient默认不发版本号,所以 ACP 类自定义 provider 在快照里不可见,必须显式传appVersion; - provider 快照是异步的:首次
getProvidersSnapshot()大概率返回status: "loading",要轮询等待目标 provider 就绪; - 多数操作前必须
fetchAgents():缺了这次握手,get_providers_snapshot_request之类的消息会静默挂起; - 永远用
listen: "127.0.0.1:0":让 OS 分配端口,硬编码端口会与常驻 daemon 或其他测试冲突; - 脚本必须放在
packages/server/src/下:测试工具通过 TypeScript 项目做相对导入; - 失败也要清理:用 try/finally 保证 daemon 停止、临时目录删除;
- ACP provider 会拉起真实进程:probe 模型与模式需要二进制在 PATH 上,探测可能耗时 5–15 秒。
6.4 移动端测试:Agent Device 与 Maestro
移动端 QA 的主格式是Agent Device.ad脚本(docs/mobile-testing.md):Agent 交互式发现可用流程、保存成功命令,replay runner 在本地或 CI 执行同一份"打字计划"。录制流程的典型命令:
agent-device open sh.paseo.debug \ --platform ios \ --session terminal-author \ --save-script ./packages/app/e2e/mobile/agent-device/terminal.ios.ad agent-device snapshot -i --session terminal-author agent-device press 'id="workspace-header-menu-trigger"' --session terminal-author # Continue the flow and verify its result with wait/get/is/find. agent-device close --session terminal-author运行整套移动套件:npm run test:e2e:mobile。最小的可读示例见 packages/app/e2e/mobile/agent-device/native-terminal-basic.ios.ad 与 native-terminal-basic.android.ad。遗留的 Maestro 流程在 packages/app/maestro/(含可复用子流程 packages/app/maestro/flows/),可通过agent-device test <path> --maestro执行其受支持子集作为迁移路径。移动端 QA 的核心主张与第四问完全一致:takeScreenshot是证据不是断言,断言必须用wait、get、is、find;选择器优先基于稳定的 app ID(testID/nativeID),不要用文本匹配。
6.5 桌面端:浏览器捕获 harness 与打包冒烟
桌面端的真实-Electron 验证路径是浏览器捕获 harness(docs/browser-capture-harness.md),它验证单元测试看不到的 compositor 行为:驻留 automation<webview>的生产停车状态、停车 guest 可绘制且有可拷贝的视口帧、首次呈现前的 1280x800 逻辑像素默认值、capturePage与 CDP 全页截图在停车状态返回真实像素等。运行:
npm run capture-harness --workspace=@getpaseo/desktop而打包后的桌面冒烟测试则是生产启动路径的外部观察者(docs/testing.md 的 Packaged desktop smoke 一节):harness 用隔离的 user data 与 daemon 状态启动打包应用,通过 Chromium 调试协议连接真实渲染器,要求同时满足"paseo://app/渲染器挂载进#root""沙箱 preload 暴露桌面桥""渲染器经正常启动 bootstrap 拉起全新桌面托管 daemon""打包 CLI 能查询该 daemon 并运行终端命令"。本地模拟:
PASEO_DESKTOP_SMOKE=1 \ PASEO_DESKTOP_SMOKE_ARTIFACT_DIR=/tmp/paseo-desktop-smoke \ npm run build:desktop -- --publish never --linux --x64 --dir该冒烟测试有一个著名的历史教训:永远不要在 harness 里"修复"chrome-sandbox——旧版 unpacked 冒烟把它改成 4755 权限,掩盖了损坏的安装包。
七、PR 测试路由:按行为而非按包归属分配检查
PR 检查按"每个套件证明的行为"路由,配置文件是 .github/ci-paths.yml。原则是:包不继承其运行时消费者的全部测试套件——App 改动不跑 CLI 或 Electron 包装器测试,protocol 改动不跑每个 import 它的包。跨包静态兼容性属于typecheck;完整的集成覆盖在合入 main 之后及手动 CI 运行中执行。路由使用稳定的领域目录,浏览器改动选择必需的 Playwright shards,桌面改动选择既有的必需桌面任务;打包(Desktop Packages、Docker、Nix workflows)只在 main 上运行。
对 QA 的直接含义:你在 PR 里声明的证据要匹配路由到你的检查——改 App 就附上 App 的 Playwright spec 证据,改 daemon 就附上真实 daemon 的 E2E 证据,而不是用别的包的测试结果凑数。
八、本地运行建议:套件很重,不要冻住你的机器
仓库测试套件很重,批量运行会冻结机器(尤其多个 Agent 并行时)。docs/testing.md 给出明确的操作纪律:
- 只跑你改过的文件:
npx vitest run <path> --bail=1 - 不要随意对整个 workspace 跑
npm run test - 需要广泛扫描时重定向到文件再读:
npx vitest run <path> --bail=1 > /tmp/test-output.txt 2>&1 - 永远不要重跑另一个 Agent 已报绿的套件
- 需要全量信心时推到 CI 看 GitHub Actions
- 永远不要在本地跑完整 Playwright E2E 套件——交给 CI;只允许跑你改动或需要证明的定向 spec
这也是"确定性优先"的延伸:测试每次运行必须产生相同结果,不允许条件断言、时间/随机/网络抖动依赖、弱断言(toBeTruthy、toBeDefined)。Flaky 测试是一个 bug——永不因为 flaky 而删除测试,而是找到方差来源(时间、随机、竞态、共享状态、非确定性输出、环境漂移)并修复它。Agent 认证交给 provider 自己处理,测试中不添加认证检查、环境变量门或条件跳过,认证失败就如实报告。
九、结语:QA 是一份证据文化
Paseo 的 QA 规范可以用一句话收束:质量把关不靠信任,靠可复核的证据。四条门槛中的每一条,都有对应的仓库内工具与文档可以落地——设计基线看 docs/design.md,热路径性能看 docs/terminal-performance.md,平台门控看根目录 CLAUDE.md,协议兼容看 docs/protocol-compatibility.md,测试标准看 docs/testing.md(含 ad-hoc daemon 测试 docs/ad-hoc-daemon-testing.md、移动端 docs/mobile-testing.md、桌面截图 harness docs/browser-capture-harness.md)。提交 PR 之前,逐条核对四问,附上别人能复核的证据——这就是 Paseo 的合格线。
【免费下载链接】paseo
Orchestrate multiple coding agents from desktop and mobile
相关推荐
Impeccable Polish 精修流程:以证据驱动、沿整条路径收尾的发布前质量把关
Impeccable Polish 精修流程:以证据驱动、沿整条路径收尾的发布前质量把关 导读 polish 是 Impeccable 设计技能中负责"发布前最
AI 技能前端CLIdsh-pluginOpenSRE 网关核心架构解析:gateway/core 的进程编排、容量闸门与 Agent 驱动边界
OpenSRE 网关核心架构解析:gateway/core 的进程编排、容量闸门与 Agent 驱动边界 本指南以仓库 gateway/core/AGENTS.
人工智能AI Agent运维可观测性根因分析工具调用后端MCP ClientsOpenClaw Auto QA 实战指南:多子系统并行、根因优先的全仓库自主质量活动编排
OpenClaw Auto QA 实战指南:多子系统并行、根因优先的全仓库自主质量活动编排 本文基于 .agents/skills/auto qa/SKILL.
AI 应用AI Agent交互助手后端即时通讯网关
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考