# rpa-core 迁入 Agent-Employee 指南(通俗版) ## 这是一份什么文档? 我们花了两周把 RPA 的"能力层"(跑流程用的几百个能力 + 流程引擎)从现在这个 demo 项目里抽出来, 做成了一个独立软件包,叫 `@rpa/core`,放在本仓库的 `packages/rpa-core/` 目录。 **为什么要抽出来?** 因为这个包以后要搬到另一个项目 Agent-Employee 里用。 抽成独立包的好处:搬过去时不用改一行代码,两边也不用维护两份一样的代码。 **这份文档讲什么?** 讲三件事: 1. 这个包现在长什么样(现状) 2. 到时候怎么搬过去(操作步骤) 3. 以后要支持 Mac 和 Linux 怎么办(三端计划) > 配套文档:`docs/rpa-core-refactor-tasks.md`(当时的改造任务清单)、`docs/dev-conventions.md`(日常开发规范)、`packages/rpa-core/README.md`(包的技术说明书)。 --- ## 一、现状:包已经是什么样了 改造已全部完成并合入 main 分支(6 个阶段提交,`4139400..a8084dc`)。现在: | 你可能想知道的 | 答案 | |---|---| | 包在哪? | `packages/rpa-core/`,包名 `@rpa/core` | | 里面有什么? | 流程引擎(跑流程的循环/变量/错误处理)+ 719 个能力(文件/Excel/HTTP/数据库/邮件/桌面操作等) | | 它依赖 Electron 吗? | **完全不依赖**。有脚本 `npm run check:deps` 天天检查,谁往里加 Electron 代码就报错 | | 它怎么用 Electron 的功能? | 见下面"宿主桥"的解释 | | 怎么证明它能独立跑? | `npm run rpa-cli`:不启动 Electron,直接跑通 5 个代表能力(桌面点击/Excel/HTTP/文件/屏幕) | **几个名词解释(后文会反复出现):** - **宿主**:使用这个包的应用程序。现在宿主是本 demo(Electron 应用),以后宿主是 Agent-Employee。 - **宿主桥(HostBridge)**:包偶尔需要"只有应用程序才有"的功能,比如弹一个窗口、读取 AI 配置。 包不直接去拿,而是定了一个接口说"谁来用我,谁把这几个功能递给我"。 宿主启动时调用 `setHostBridge(...)` 把功能递进来。目前一共只有 4 个功能要递: 弹窗、两组屏幕坐标换算、读 AI 配置。另有 `setSubflowSource(...)` 递子流程仓库(2 个方法)。 - **驱动(Driver)**:真正干"动鼠标、敲键盘、找窗口"这些活的模块。现在的实现叫 `WindowsDriver`(用 PowerShell 实现)。 能力层不直接碰 PowerShell,而是喊"driver,帮我把鼠标移到 x,y"——所以以后要做 Mac 版,只需要再写一个 `MacDriver`,能力层一行不用改。 --- ## 二、到时候怎么搬:三步走 ### 第 -1 步:先知道对面已经有什么(2026-11-05 实地调研) Agent-Employee(`D:\code\Agent-Employee`)是 Electron + SolidJS 客户端 + Bun 执行面 + Java 控制面的结构, 前端 `code/frontend`、后端 `code/backend` 是**两个独立的 bun workspace**(bun@1.4.3,workspaces 含 `apps/*`、`packages/*`、`services/*`)。 关键事实:**对面已经为我们要搬的东西铺好了契约,但还没有实现**。`code/backend/packages/` 下有一批契约包(每个只有 1-9 个声明文件): | 对面现有契约包 | 它声明了什么 | 与 @rpa/core 的关系 | |---|---|---| | `workflow-engine` | workflow / step / approval / failure 状态模型(9 个文件,依赖 plugin-contract、capability-gateway、event-bus) | rpa-core 的 runtime 是它的**执行引擎候选**,迁入时需做状态模型对齐(审批/失败/证据如何挂到我们 RunResult/NodeState 上) | | `capability-gateway` | 所有带副作用的能力执行前必须过:授权 → 租约签发 → 租约校验 → 执行约束;契约含 `CapabilityRunner` / `authorize()` / `execute()` | **权限治理(6.4)的现成落点**。rpa-core 能力执行要包进这个网关,而不是自建 allowlist | | `computer-control` | 跨平台观察、定位、动作抽象与桌面会话策略 | rpa-core 五域 driver 是它的**实现候选**;三端设计(第三节)应对齐这份契约 | | `windows-plugin` | Windows 目标、桌面会话策略、输入类高影响能力、执行器接口 | WindowsDriver 的接入契约 | | `browser-plugin` | 浏览器动作、域名白名单、高影响能力审批边界、证据机制 | demo 侧浏览器能力的对面契约 | | `runtime-governance` / `plugin-contract` | 运行时治理 / 插件契约 | 治理对接的参考 | | `services/windows-runner` | Windows 交互 Runner(**空壳,0 个源文件**) | 对面 README 已明确"Windows 交互 Runner 留在宿主,不放入 Linux 容器"——与 rpa-core 桌面能力只能跑在 Windows 交互会话的约束天然一致 | **结论:迁入的本质不是"新写一套宿主适配",而是"拿 rpa-core 的实现去填对面的契约"。** 这比原计划省了适配层设计,但多了一步契约对齐(接口签名互相对照,差异列清单评审)。 ### 第 0 步:搬家之前,在 demo 里先补三件作业 这些事当时刻意延后了,搬家前必须补上(都在本仓库做,改起来便宜): 1. **Bun 冒烟测试**。Agent-Employee 用 Bun 跑代码,我们一直用 Node。 搬过去第一件事:用 `bun test` 跑包里的纯逻辑测试,确认 exceljs、pdf-lib 这些库在 Bun 下行为一致, 尤其是调 PowerShell 的部分(编码处理容易有差异)。 2. **重新生成能力目录**。跑一次 `npm run catalog`,让每个能力带上 `platformTag: "win32"` 标记 (标记逻辑早就写好了,当时因为数据源不在这台机器上没生效)。 3. **决定用哪种注册方式**。包支持两种注册能力的方式: 旧方式 `import "@rpa/core/capabilities"`(一导入全注册),新方式 `await registerAll(engine)`(想注册哪几组就注册哪几组)。 建议 Agent-Employee 直接用新方式,旧的以后可以废掉。 ### 第 1 步:搬包(半天) 1. **评审**:按 Agent-Employee 团队的流程提交一份架构决策记录(ADR),内容就是本文档第一节 + 对面契约对照表 + 包的 README,不用另写。 2. **搬代码**:把 `packages/rpa-core/` 整个目录用 git 方式搬进 **`code/backend/packages/rpa-core`** (执行面归 backend workspace;对面 bun@1.4.3 的 workspaces 已含 `packages/*`,放进去即生效)。 用 `git subtree` 之类保留提交历史,**千万不要复制文件夹另起炉灶**——两份代码会越走越远。 3. **包名决策**:对面 backend 包统一用 `@agent-worker/*` 前缀(如 `@agent-worker/plugin-contract`)。 建议迁入时改名 `@agent-worker/rpa-core`(一次 commit 完成 rename,包内代码不用动)。 4. **处理 demo 侧**:搬走之后 demo 要么改成只读引用,要么归档。**两边不能同时活跃改代码。** ### 第 2 步:契约对齐 + 宿主适配(核心工作量) 分两类工作: **A. 契约对齐(对面已铺好,我们填实现)**——逐个对照,差异列清单评审后改: | 对面契约 | 对齐内容 | |---|---| | `capability-gateway` | 把 rpa-core 的能力执行包进 `authorize() / execute()` 流程(`CapabilityRunner` 接口);危险能力(System_ExecuteCommand、键鼠注入等)走它的租约与审批,**不再自建 allowlist** | | `workflow-engine` | 状态模型对齐:我们 `RunResult/NodeState`(running/succeeded/failed/...)对照它的 workflow/step/approval/failure;人工审批节点(human-dialog)要能挂进它的 approval 流 | | `computer-control` / `windows-plugin` | 五域 driver 的观察/定位/动作抽象与它们契约互相对照;WindowsDriver 作为执行器接入 | | `browser-plugin` | 浏览器能力对齐域名白名单与审批边界 | **B. 宿主注入(照旧要做,但工作量变小)**: | 要递什么 | 干什么用 | 工作量 | |---|---|---| | `setHostBridge` 4 个方法 | 弹窗、DPI 坐标换算、读 AI 配置 | 小。对面也是 Electron(`code/frontend/apps/desktop`),参考实现照抄本仓库 `src/main/index.ts` 第 28-50 行 | | `setSubflowSource` 2 个方法 | 子流程的存与取 | 小。对面有自己的流程存储,包一层即可 | | **内置浏览器**(`BrowserLike` 接口) | "浏览器打开网址/点按钮/填表单"这组能力需要宿主提供浏览器 | **不确定,是最大变数**。对面的浏览器方案还没定型(browser-plugin 只是契约);需与对面团队评审后再估工作量 | | AI 能力配置 | `ai-caps.ts` 需要 baseUrl/apiKey 等 | 小。对面有模型网关(model-gateway),接它的配置面 | **不搬的东西**(留在 demo / 由 Agent-Employee 重新做): 界面渲染层、悬浮框/取色器、本地视觉(onnxruntime 那套)、流程存储、内置浏览器编排。 完整清单见包 README 的「Electron 相关能力留守清单」。 ### 第 3 步:验收(搬家算不算成功,看这 7 条) 1. `bun test` 包内纯逻辑测试全绿; 2. `npm run rpa-cli` 的等价物在 Bun 下跑通 5 个代表能力; 3. 能力注册数对得上(包内 719 个); 4. `check:deps` 通过(没人在搬家过程中偷偷加回 Electron); 5. 真实操作一遍:弹一次人机对话框、高分屏上拖一次窗口、调一次 AI——验证宿主桥三条路径通了; 6. 契约对齐有书面结论:capability-gateway(能力执行进网关)、workflow-engine(状态模型)、computer-control(driver 抽象)三份对照清单各评审通过; 7. demo 侧(如果还保留)测试全绿。 --- ## 三、以后要支持 Mac 和 Linux 怎么办? 好消息:当初设计时已经把口子留好了——能力层只对"驱动接口"说话,不关心底下是 Windows 还是 Mac。 所以三端化不用推翻任何东西,分两批做: ### 搬家之前(demo 侧,5 件小事) | # | 事项 | 说明 | |---|---|---| | 1 | **平台标记统一机制**(三端优先 win) | 平台归属收敛为一处权威数据:`register-all.ts` 分组表 `PLATFORM_GROUPS`。三个平台类型都能填,但**数据只填 win32**,darwin/linux 仅类型占位;`meta.platforms`(运行时)与 catalog `platformTag`(构建期)都从这张表派生,`build-catalog.mjs` 删掉自带的 `WIN32_GROUPS` 硬编码;加一致性守卫测试,两处不一致 CI 直接红 | | 2 | 驱动改成按系统自动选 | 现在写死 `new WindowsDriver()`;改成看 `process.platform` 自动选,Mac/Linux 上没实现就明确报"该平台暂不支持"(加个 `platform_unsupported` 错误码) | | 3 | 检查能力分组 | Excel COM、Word COM 这些 Windows 专属能力,确保归在能整组过滤的分组里——将来 Mac 版就不注册这组 | | 4 | 测试加平台守卫 | 现在只有 4 个测试文件写了"非 Windows 就跳过",键盘/鼠标/窗口冒烟测试没写。补齐后,Mac/Linux 的 CI 才能跑(跑纯逻辑部分,跳过真桌面操作) | | 5 | 开发规范加一条 | 禁止在能力文件里随手写 `process.platform` 判断(现在 utility-extended 里已有 2 处,收拢到固定位置),防止平台差异到处扩散 | ### 搬家之后(Agent-Employee 侧,按平台写驱动) 0. **先对齐对面的 `computer-control` 契约**:对面已声明"跨平台观察、定位、动作抽象"的契约(还是空壳)。 写 MacDriver / LinuxDriver 之前,先让五域 driver 接口与这份契约对表,避免两边各长各的。 1. **写 MacDriver / LinuxDriver**(接口现成,按五个域补实现): - Linux:鼠标键盘用 xdotool(X11);Wayland 支持受限,是三端里最难的坑;界面元素识别走 AT-SPI; - Mac:鼠标键盘用 cliclick 或 CGEvent;窗口操作走 AppleScript;界面元素走 AX 辅助功能 API。 2. **先评估 macOS 权限问题**:Mac 上 RPA 软件必须引导用户开"辅助功能/屏幕录制"授权(系统 TCC 机制), 这是 Mac 端最大的部署摩擦,做之前先摸清。 3. **Office 替代方案**:Excel/Word 的 COM 自动化只有 Windows 有。Mac 可走 AppleScript + Office, Linux 可走 LibreOffice;或者第一版直接标注"仅 Windows"。 4. **浏览器路径**:外部浏览器启动路径现在写死了 Windows 的(`C:\Program Files\...`),要补 Mac/Linux 的路径表。 5. **剪贴板等小件**:PowerShell 换成 `pbpaste/pbcopy`(Mac)、`xclip`(Linux)。 6. **CI 三个平台各跑一遍**;产品界面按能力标注的平台支持情况置灰不支持的项。 ### 一条原则 **平台标记必须统一,这是硬约束(三端优先 win):** - 平台归属只有**一处权威数据**:包内注册分组表 `PLATFORM_GROUPS`(33 个能力组 × 平台数组)。 - 运行时的 `meta.platforms` 和构建期的 catalog `platformTag` 都**从这张表自动派生**,任何代码不得自行声明第二份平台数据。 - **数据里今天只有 `win32`**;`darwin`/`linux` 只存在于类型枚举里占位,不填任何数据。 - 将来支持新平台 = 新增能力分组 + 表里加一行,仅此而已;守卫测试保证两处派生永远一致,谁绕过就红。 平台差异**只允许**出现在两个地方:`driver/<平台>/` 目录下的驱动实现,以及极少数白名单能力文件。 引擎、注册表、能力接口、宿主桥,永远保持平台无关。 --- ## 附:当时的 10 个关键决策(搬家时不要再讨论一遍) | # | 决策 | |---|---| | 1 | 代码物理搬移(git mv),不是留着引用 | | 2 | 保留全局注册表;进程级状态收进 `createEngine()` 工厂 | | 3 | 集中突击改造,不搞长期双轨 | | 4 | 宿主桥只留 4 个方法(弹窗 / DPI×2 / AI 配置),能不加就不加 | | 5 | 浏览器:外部浏览器(CDP)进包,内置浏览器留宿主 | | 6 | 驱动接口五域划分(鼠标/键盘/窗口/屏幕/元素),Windows 实现原样包装、行为不变 | | 7 | 能力目录只填平台标记数据,界面置灰以后再说 | | 8 | 能力元数据(meta)老能力可选、新能力强制 | | 9 | 注册双入口过渡(副作用导入 + registerAll 显式注册) | | 10 | Bun 冒烟测试延期到搬家时做(本文第二节第 0 步) |