From caa8e19332d9fce888f1bce8ac04a7966fd2b7f9 Mon Sep 17 00:00:00 2001 From: yu <1919727607@qq.com> Date: Wed, 4 Nov 2026 12:36:03 +0800 Subject: [PATCH] =?UTF-8?q?=E9=98=B6=E6=AE=B51-rpa-core=E5=BB=BA=E5=8C=85:?= =?UTF-8?q?=20engine+31=E4=B8=AA=E7=BA=AFNode=E8=83=BD=E5=8A=9B=E8=BF=81?= =?UTF-8?q?=E5=85=A5packages/rpa-core,=20=E9=A2=86=E5=9F=9F=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=E5=8D=95=E4=B8=80=E6=BA=90=E5=8C=96,=20createEngine?= =?UTF-8?q?=E5=B7=A5=E5=8E=82=E6=94=B6=E6=8B=A2=E6=A8=A1=E5=9D=97=E7=BA=A7?= =?UTF-8?q?=E7=8A=B6=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - engine/(registry/types/runtime/expression)物理迁入包, 解耦shared/types(域类型归包, 宿主type-only re-export) - 31个纯Node能力+27个测试迁入包; 宿主留守Electron/浏览器/AI依赖能力, index.ts经@rpa/core/capabilities拉起 - 新增createEngine()/defaultEngine: excel缓存/Excel句柄/db连接/FTP客户端/OCR实例/拟真设置挂引擎实例 - remaining-core子流程依赖改为host-bridge注入, 包内不再import宿主flows - 宿主main/index.ts启动时注入子流程源; electron-vite/vitest/tsconfig配@rpa/core源码别名 - 验证: typecheck绿, 快照909个id diff为零, 332测试过(2个桌面冒烟因会话无交互SetForegroundWindow被拒, 环境阻塞) --- electron.vite.config.ts | 9 +- package.json | 3 + packages/rpa-core/package.json | 40 ++++ .../app-system-regression.test.ts | 2 +- .../capabilities/app-system-smoke.test.ts | 2 +- .../src}/capabilities/basic-encryption.ts | 0 .../src}/capabilities/basic-manual.test.ts | 2 +- .../src}/capabilities/capabilities.test.ts | 2 +- .../src}/capabilities/common-final.ts | 0 .../rpa-core/src}/capabilities/control.ts | 0 .../src}/capabilities/cv-vision.test.ts | 0 .../rpa-core/src}/capabilities/cv-vision.ts | 0 .../src}/capabilities/data-extended.test.ts | 2 +- .../src}/capabilities/data-extended.ts | 0 .../src}/capabilities/data-file-smoke.test.ts | 2 +- .../capabilities/data-table-common.test.ts | 2 +- .../src}/capabilities/data-table-common.ts | 0 .../rpa-core/src}/capabilities/data.ts | 0 .../src}/capabilities/desktop-uia.test.ts | 0 .../rpa-core/src}/capabilities/desktop-uia.ts | 0 .../rpa-core/src}/capabilities/desktop.ts | 15 +- .../src}/capabilities/excel-com.test.ts | 2 +- .../rpa-core/src}/capabilities/excel-com.ts | 0 .../src}/capabilities/excel-common.test.ts | 2 +- .../src}/capabilities/excel-common.ts | 0 .../src}/capabilities/excel-store.test.ts | 2 +- .../rpa-core/src}/capabilities/excel-store.ts | 11 +- .../src}/capabilities/extended.test.ts | 2 +- .../rpa-core/src}/capabilities/extended.ts | 0 .../rpa-core/src}/capabilities/files.test.ts | 2 +- .../rpa-core/src}/capabilities/files.ts | 0 .../rpa-core/src}/capabilities/ftp.ts | 11 +- .../rpa-core/src}/capabilities/http.ts | 0 packages/rpa-core/src/capabilities/index.ts | 39 ++++ .../capabilities/keyboard-send-smoke.test.ts | 2 +- .../src}/capabilities/mail-remaining.ts | 0 .../src}/capabilities/message-recv.test.ts | 2 +- .../rpa-core/src}/capabilities/message.ts | 0 .../rpa-core/src}/capabilities/ocr-caps.ts | 7 +- .../src}/capabilities/ocr-smoke.test.ts | 2 +- .../src}/capabilities/office-aliases.test.ts | 6 +- .../src}/capabilities/office-aliases.ts | 0 .../capabilities/office-file-extended.test.ts | 2 +- .../src}/capabilities/office-file-extended.ts | 0 .../rpa-core/src}/capabilities/office.ts | 4 +- .../src}/capabilities/pdf-high.test.ts | 2 +- .../rpa-core/src}/capabilities/pdf.ts | 0 .../relativeposition-smoke.test.ts | 2 +- .../src}/capabilities/remaining-core.ts | 13 +- .../src}/capabilities/system-extended.test.ts | 2 +- .../src}/capabilities/system-extended.ts | 0 .../rpa-core/src}/capabilities/time-caps.ts | 0 .../capabilities/utility-extended.test.ts | 2 +- .../src}/capabilities/utility-extended.ts | 0 .../src}/capabilities/vision-helpers.test.ts | 0 .../src}/capabilities/vision-match.test.ts | 0 .../rpa-core/src}/capabilities/vision.ts | 0 .../src}/capabilities/windows-system.ts | 0 .../src}/capabilities/word-extended.test.ts | 2 +- .../src}/capabilities/word-extended.ts | 0 .../rpa-core/src}/capabilities/word.ts | 0 packages/rpa-core/src/engine/engine.ts | 49 +++++ .../rpa-core/src}/engine/expression.ts | 0 packages/rpa-core/src/engine/host-bridge.ts | 22 ++ .../rpa-core/src}/engine/registry.ts | 0 .../src}/engine/runtime.error-route.test.ts | 2 +- .../src}/engine/runtime.integration.test.ts | 2 +- .../rpa-core/src}/engine/runtime.ts | 2 +- .../rpa-core/src}/engine/types.ts | 2 +- packages/rpa-core/src/index.ts | 43 ++++ packages/rpa-core/src/types.ts | 187 ++++++++++++++++ packages/rpa-core/tsconfig.json | 16 ++ packages/rpa-core/vitest.config.ts | 8 + resources/capability-snapshot.json | 2 +- scripts/app-system-tests.test.mjs | 6 +- src/main/browser/external.ts | 2 +- src/main/browser/session.ts | 2 +- src/main/browser/transport.ts | 2 +- src/main/capabilities/ai-caps.ts | 4 +- src/main/capabilities/ai-service.ts | 2 +- src/main/capabilities/browser-common.test.ts | 4 +- src/main/capabilities/browser-common.ts | 4 +- src/main/capabilities/browser-control.test.ts | 4 +- src/main/capabilities/browser-control.ts | 4 +- src/main/capabilities/browser-dom.test.ts | 4 +- src/main/capabilities/browser-dom.ts | 4 +- .../capabilities/browser-extended.test.ts | 4 +- src/main/capabilities/browser-extended.ts | 4 +- src/main/capabilities/browser.test.ts | 4 +- src/main/capabilities/browser.ts | 6 +- .../capabilities/capability-audit.test.ts | 2 +- .../capabilities/catalog-properties.test.ts | 2 +- src/main/capabilities/common-final.test.ts | 6 +- src/main/capabilities/human-dialog.ts | 4 +- src/main/capabilities/index.ts | 41 +--- .../capabilities/mouse-moveto-smoke.test.ts | 4 +- .../capabilities/net-message-smoke.test.ts | 8 +- .../capabilities/remaining-completion.test.ts | 2 +- src/main/capabilities/web-batch2.ts | 4 +- src/main/capabilities/web-crawl.ts | 4 +- src/main/capabilities/web-real-smoke.test.ts | 4 +- src/main/capabilities/window-extended.test.ts | 4 +- src/main/capabilities/window-extended.ts | 6 +- src/main/desktop-pick.ts | 2 +- src/main/index.ts | 5 +- src/main/local-vision/ui-detect-service.ts | 2 +- src/main/run/manager.ts | 2 +- src/main/vision-lab.ts | 2 +- src/shared/types.ts | 200 ++---------------- tsconfig.json | 12 +- vitest.config.ts | 7 + 111 files changed, 581 insertions(+), 337 deletions(-) create mode 100644 packages/rpa-core/package.json rename {src/main => packages/rpa-core/src}/capabilities/app-system-regression.test.ts (98%) rename {src/main => packages/rpa-core/src}/capabilities/app-system-smoke.test.ts (99%) rename {src/main => packages/rpa-core/src}/capabilities/basic-encryption.ts (100%) rename {src/main => packages/rpa-core/src}/capabilities/basic-manual.test.ts (95%) rename {src/main => packages/rpa-core/src}/capabilities/capabilities.test.ts (99%) rename {src/main => packages/rpa-core/src}/capabilities/common-final.ts (100%) rename {src/main => packages/rpa-core/src}/capabilities/control.ts (100%) rename {src/main => packages/rpa-core/src}/capabilities/cv-vision.test.ts (100%) rename {src/main => packages/rpa-core/src}/capabilities/cv-vision.ts (100%) rename {src/main => packages/rpa-core/src}/capabilities/data-extended.test.ts (98%) rename {src/main => packages/rpa-core/src}/capabilities/data-extended.ts (100%) rename {src/main => packages/rpa-core/src}/capabilities/data-file-smoke.test.ts (99%) rename {src/main => packages/rpa-core/src}/capabilities/data-table-common.test.ts (97%) rename {src/main => packages/rpa-core/src}/capabilities/data-table-common.ts (100%) rename {src/main => packages/rpa-core/src}/capabilities/data.ts (100%) rename {src/main => packages/rpa-core/src}/capabilities/desktop-uia.test.ts (100%) rename {src/main => packages/rpa-core/src}/capabilities/desktop-uia.ts (100%) rename {src/main => packages/rpa-core/src}/capabilities/desktop.ts (98%) rename {src/main => packages/rpa-core/src}/capabilities/excel-com.test.ts (98%) rename {src/main => packages/rpa-core/src}/capabilities/excel-com.ts (100%) rename {src/main => packages/rpa-core/src}/capabilities/excel-common.test.ts (99%) rename {src/main => packages/rpa-core/src}/capabilities/excel-common.ts (100%) rename {src/main => packages/rpa-core/src}/capabilities/excel-store.test.ts (98%) rename {src/main => packages/rpa-core/src}/capabilities/excel-store.ts (76%) rename {src/main => packages/rpa-core/src}/capabilities/extended.test.ts (98%) rename {src/main => packages/rpa-core/src}/capabilities/extended.ts (100%) rename {src/main => packages/rpa-core/src}/capabilities/files.test.ts (97%) rename {src/main => packages/rpa-core/src}/capabilities/files.ts (100%) rename {src/main => packages/rpa-core/src}/capabilities/ftp.ts (96%) rename {src/main => packages/rpa-core/src}/capabilities/http.ts (100%) create mode 100644 packages/rpa-core/src/capabilities/index.ts rename {src/main => packages/rpa-core/src}/capabilities/keyboard-send-smoke.test.ts (98%) rename {src/main => packages/rpa-core/src}/capabilities/mail-remaining.ts (100%) rename {src/main => packages/rpa-core/src}/capabilities/message-recv.test.ts (97%) rename {src/main => packages/rpa-core/src}/capabilities/message.ts (100%) rename {src/main => packages/rpa-core/src}/capabilities/ocr-caps.ts (95%) rename {src/main => packages/rpa-core/src}/capabilities/ocr-smoke.test.ts (98%) rename {src/main => packages/rpa-core/src}/capabilities/office-aliases.test.ts (96%) rename {src/main => packages/rpa-core/src}/capabilities/office-aliases.ts (100%) rename {src/main => packages/rpa-core/src}/capabilities/office-file-extended.test.ts (98%) rename {src/main => packages/rpa-core/src}/capabilities/office-file-extended.ts (100%) rename {src/main => packages/rpa-core/src}/capabilities/office.ts (98%) rename {src/main => packages/rpa-core/src}/capabilities/pdf-high.test.ts (97%) rename {src/main => packages/rpa-core/src}/capabilities/pdf.ts (100%) rename {src/main => packages/rpa-core/src}/capabilities/relativeposition-smoke.test.ts (96%) rename {src/main => packages/rpa-core/src}/capabilities/remaining-core.ts (96%) rename {src/main => packages/rpa-core/src}/capabilities/system-extended.test.ts (97%) rename {src/main => packages/rpa-core/src}/capabilities/system-extended.ts (100%) rename {src/main => packages/rpa-core/src}/capabilities/time-caps.ts (100%) rename {src/main => packages/rpa-core/src}/capabilities/utility-extended.test.ts (99%) rename {src/main => packages/rpa-core/src}/capabilities/utility-extended.ts (100%) rename {src/main => packages/rpa-core/src}/capabilities/vision-helpers.test.ts (100%) rename {src/main => packages/rpa-core/src}/capabilities/vision-match.test.ts (100%) rename {src/main => packages/rpa-core/src}/capabilities/vision.ts (100%) rename {src/main => packages/rpa-core/src}/capabilities/windows-system.ts (100%) rename {src/main => packages/rpa-core/src}/capabilities/word-extended.test.ts (98%) rename {src/main => packages/rpa-core/src}/capabilities/word-extended.ts (100%) rename {src/main => packages/rpa-core/src}/capabilities/word.ts (100%) create mode 100644 packages/rpa-core/src/engine/engine.ts rename {src/main => packages/rpa-core/src}/engine/expression.ts (100%) create mode 100644 packages/rpa-core/src/engine/host-bridge.ts rename {src/main => packages/rpa-core/src}/engine/registry.ts (100%) rename {src/main => packages/rpa-core/src}/engine/runtime.error-route.test.ts (98%) rename {src/main => packages/rpa-core/src}/engine/runtime.integration.test.ts (99%) rename {src/main => packages/rpa-core/src}/engine/runtime.ts (99%) rename {src/main => packages/rpa-core/src}/engine/types.ts (99%) create mode 100644 packages/rpa-core/src/index.ts create mode 100644 packages/rpa-core/src/types.ts create mode 100644 packages/rpa-core/tsconfig.json create mode 100644 packages/rpa-core/vitest.config.ts diff --git a/electron.vite.config.ts b/electron.vite.config.ts index ef3260b..de253f4 100644 --- a/electron.vite.config.ts +++ b/electron.vite.config.ts @@ -6,9 +6,12 @@ export default defineConfig({ main: { plugins: [externalizeDepsPlugin()], resolve: { - alias: { - "@shared": resolve("src/shared") - } + alias: [ + { find: "@shared", replacement: resolve("src/shared") }, + // rpa-core 包以源码形式打进主进程产物(不作为外部依赖运行时 require) + { find: /^@rpa\/core$/, replacement: resolve("packages/rpa-core/src/index.ts") }, + { find: /^@rpa\/core\/capabilities$/, replacement: resolve("packages/rpa-core/src/capabilities/index.ts") } + ] }, build: { rollupOptions: { diff --git a/package.json b/package.json index 96604c6..ade7d55 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,9 @@ "private": true, "description": "Canvas-based RPA desktop application", "main": "./out/main/index.js", + "workspaces": [ + "packages/*" + ], "scripts": { "dev": "electron-vite dev", "dev:local": "node scripts/dev-safe.mjs", diff --git a/packages/rpa-core/package.json b/packages/rpa-core/package.json new file mode 100644 index 0000000..bbf675c --- /dev/null +++ b/packages/rpa-core/package.json @@ -0,0 +1,40 @@ +{ + "name": "@rpa/core", + "version": "0.1.0", + "private": true, + "description": "RPA 能力层:零 Electron 依赖的流程引擎、能力注册表与纯 Node 能力", + "main": "./src/index.ts", + "types": "./src/index.ts", + "exports": { + ".": "./src/index.ts", + "./capabilities": "./src/capabilities/index.ts" + }, + "scripts": { + "test": "vitest run", + "typecheck": "tsc --noEmit -p tsconfig.json" + }, + "dependencies": { + "@gutenye/ocr-node": "^1.4.9", + "adm-zip": "^0.5.16", + "basic-ftp": "^6.2.3", + "exceljs": "^4.4.0", + "imapflow": "^2.10.0", + "mailparser": "^3.14.1", + "mssql": "^12.7.13", + "mysql2": "^3.24.6", + "nodemailer": "^6.9.16", + "pdf-lib": "^1.17.1", + "pg": "^8.23.1", + "pngjs": "^7.0.0", + "sm-crypto": "^0.5.8" + }, + "devDependencies": { + "@types/adm-zip": "^0.5.7", + "@types/mssql": "^12.3.0", + "@types/nodemailer": "^6.4.17", + "@types/pg": "^8.23.1", + "@types/pngjs": "^6.0.5", + "typescript": "^5.7.2", + "vitest": "^2.1.8" + } +} diff --git a/src/main/capabilities/app-system-regression.test.ts b/packages/rpa-core/src/capabilities/app-system-regression.test.ts similarity index 98% rename from src/main/capabilities/app-system-regression.test.ts rename to packages/rpa-core/src/capabilities/app-system-regression.test.ts index 919cbb4..135b084 100644 --- a/src/main/capabilities/app-system-regression.test.ts +++ b/packages/rpa-core/src/capabilities/app-system-regression.test.ts @@ -1,5 +1,5 @@ import { afterEach, describe, expect, it, vi } from "vitest"; -import type { CatalogComponent, FlowNode } from "../../shared/types"; +import type { CatalogComponent, FlowNode } from "../types"; import type { RunContext } from "../engine/types"; import { getHandler } from "../engine/registry"; diff --git a/src/main/capabilities/app-system-smoke.test.ts b/packages/rpa-core/src/capabilities/app-system-smoke.test.ts similarity index 99% rename from src/main/capabilities/app-system-smoke.test.ts rename to packages/rpa-core/src/capabilities/app-system-smoke.test.ts index 942d5d4..ed9c2ae 100644 --- a/src/main/capabilities/app-system-smoke.test.ts +++ b/packages/rpa-core/src/capabilities/app-system-smoke.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from "vitest"; import { getHandler } from "../engine/registry"; -import type { CatalogComponent, FlowNode } from "../../shared/types"; +import type { CatalogComponent, FlowNode } from "../types"; import type { RunContext } from "../engine/types"; import "./data"; import "./desktop"; diff --git a/src/main/capabilities/basic-encryption.ts b/packages/rpa-core/src/capabilities/basic-encryption.ts similarity index 100% rename from src/main/capabilities/basic-encryption.ts rename to packages/rpa-core/src/capabilities/basic-encryption.ts diff --git a/src/main/capabilities/basic-manual.test.ts b/packages/rpa-core/src/capabilities/basic-manual.test.ts similarity index 95% rename from src/main/capabilities/basic-manual.test.ts rename to packages/rpa-core/src/capabilities/basic-manual.test.ts index 8cf2f21..08c871d 100644 --- a/src/main/capabilities/basic-manual.test.ts +++ b/packages/rpa-core/src/capabilities/basic-manual.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from "vitest"; import { getHandler } from "../engine/registry"; -import type { CatalogComponent, FlowNode } from "../../shared/types"; +import type { CatalogComponent, FlowNode } from "../types"; import type { RunContext } from "../engine/types"; import "./desktop"; import "./basic-encryption"; diff --git a/src/main/capabilities/capabilities.test.ts b/packages/rpa-core/src/capabilities/capabilities.test.ts similarity index 99% rename from src/main/capabilities/capabilities.test.ts rename to packages/rpa-core/src/capabilities/capabilities.test.ts index 44aafcf..a92c106 100644 --- a/src/main/capabilities/capabilities.test.ts +++ b/packages/rpa-core/src/capabilities/capabilities.test.ts @@ -7,7 +7,7 @@ import { PDFDocument } from "pdf-lib"; import { PNG } from "pngjs"; import { getHandler } from "../engine/registry"; import type { RunContext } from "../engine/types"; -import type { CatalogComponent, FlowNode } from "../../shared/types"; +import type { CatalogComponent, FlowNode } from "../types"; import "./desktop"; import "./office"; import "./pdf"; diff --git a/src/main/capabilities/common-final.ts b/packages/rpa-core/src/capabilities/common-final.ts similarity index 100% rename from src/main/capabilities/common-final.ts rename to packages/rpa-core/src/capabilities/common-final.ts diff --git a/src/main/capabilities/control.ts b/packages/rpa-core/src/capabilities/control.ts similarity index 100% rename from src/main/capabilities/control.ts rename to packages/rpa-core/src/capabilities/control.ts diff --git a/src/main/capabilities/cv-vision.test.ts b/packages/rpa-core/src/capabilities/cv-vision.test.ts similarity index 100% rename from src/main/capabilities/cv-vision.test.ts rename to packages/rpa-core/src/capabilities/cv-vision.test.ts diff --git a/src/main/capabilities/cv-vision.ts b/packages/rpa-core/src/capabilities/cv-vision.ts similarity index 100% rename from src/main/capabilities/cv-vision.ts rename to packages/rpa-core/src/capabilities/cv-vision.ts diff --git a/src/main/capabilities/data-extended.test.ts b/packages/rpa-core/src/capabilities/data-extended.test.ts similarity index 98% rename from src/main/capabilities/data-extended.test.ts rename to packages/rpa-core/src/capabilities/data-extended.test.ts index ecd4cf8..690a1f7 100644 --- a/src/main/capabilities/data-extended.test.ts +++ b/packages/rpa-core/src/capabilities/data-extended.test.ts @@ -2,7 +2,7 @@ import { mkdtemp, readFile, rm } from "node:fs/promises"; import os from "node:os"; import path from "node:path"; import { afterEach, describe, expect, it, vi } from "vitest"; -import type { Catalog, CatalogComponent, FlowNode } from "../../shared/types"; +import type { Catalog, CatalogComponent, FlowNode } from "../types"; import type { RunContext } from "../engine/types"; import { getHandler } from "../engine/registry"; import "./data-extended"; diff --git a/src/main/capabilities/data-extended.ts b/packages/rpa-core/src/capabilities/data-extended.ts similarity index 100% rename from src/main/capabilities/data-extended.ts rename to packages/rpa-core/src/capabilities/data-extended.ts diff --git a/src/main/capabilities/data-file-smoke.test.ts b/packages/rpa-core/src/capabilities/data-file-smoke.test.ts similarity index 99% rename from src/main/capabilities/data-file-smoke.test.ts rename to packages/rpa-core/src/capabilities/data-file-smoke.test.ts index 37145d2..32df5df 100644 --- a/src/main/capabilities/data-file-smoke.test.ts +++ b/packages/rpa-core/src/capabilities/data-file-smoke.test.ts @@ -4,7 +4,7 @@ import path from "node:path"; import { afterAll, describe, expect, it } from "vitest"; import { capabilityIds, getHandler } from "../engine/registry"; import { RuntimeError } from "../engine/types"; -import type { CatalogComponent, FlowNode } from "../../shared/types"; +import type { CatalogComponent, FlowNode } from "../types"; import type { RunContext } from "../engine/types"; import "./data"; import "./data-extended"; diff --git a/src/main/capabilities/data-table-common.test.ts b/packages/rpa-core/src/capabilities/data-table-common.test.ts similarity index 97% rename from src/main/capabilities/data-table-common.test.ts rename to packages/rpa-core/src/capabilities/data-table-common.test.ts index 5b97a29..8e2761c 100644 --- a/src/main/capabilities/data-table-common.test.ts +++ b/packages/rpa-core/src/capabilities/data-table-common.test.ts @@ -2,7 +2,7 @@ import { mkdtemp, rm } from "node:fs/promises"; import os from "node:os"; import path from "node:path"; import { afterEach, describe, expect, it } from "vitest"; -import type { CatalogComponent, FlowNode } from "../../shared/types"; +import type { CatalogComponent, FlowNode } from "../types"; import type { RunContext } from "../engine/types"; import { getHandler } from "../engine/registry"; import "./data-table-common"; diff --git a/src/main/capabilities/data-table-common.ts b/packages/rpa-core/src/capabilities/data-table-common.ts similarity index 100% rename from src/main/capabilities/data-table-common.ts rename to packages/rpa-core/src/capabilities/data-table-common.ts diff --git a/src/main/capabilities/data.ts b/packages/rpa-core/src/capabilities/data.ts similarity index 100% rename from src/main/capabilities/data.ts rename to packages/rpa-core/src/capabilities/data.ts diff --git a/src/main/capabilities/desktop-uia.test.ts b/packages/rpa-core/src/capabilities/desktop-uia.test.ts similarity index 100% rename from src/main/capabilities/desktop-uia.test.ts rename to packages/rpa-core/src/capabilities/desktop-uia.test.ts diff --git a/src/main/capabilities/desktop-uia.ts b/packages/rpa-core/src/capabilities/desktop-uia.ts similarity index 100% rename from src/main/capabilities/desktop-uia.ts rename to packages/rpa-core/src/capabilities/desktop-uia.ts diff --git a/src/main/capabilities/desktop.ts b/packages/rpa-core/src/capabilities/desktop.ts similarity index 98% rename from src/main/capabilities/desktop.ts rename to packages/rpa-core/src/capabilities/desktop.ts index ae3b614..8d0e26e 100644 --- a/src/main/capabilities/desktop.ts +++ b/packages/rpa-core/src/capabilities/desktop.ts @@ -2,21 +2,12 @@ import { execFile } from "node:child_process"; import { promisify } from "node:util"; import { register } from "../engine/registry"; import { RuntimeError, type CapabilityHandler } from "../engine/types"; +import { type ManualOperationSettings, defaultEngine } from "../engine/engine"; const execFileAsync = promisify(execFile); -interface ManualOperationSettings { - enabled: boolean; - randomMove: boolean; - randomClick: boolean; - randomSleep: boolean; - minMs: number; - maxMs: number; -} - -const manualOperation: ManualOperationSettings = { - enabled: false, randomMove: true, randomClick: true, randomSleep: true, minMs: 1000, maxMs: 3000 -}; +// 人为拟真设置本体挂在引擎实例上(任务 1.3),此处委托 defaultEngine。 +const manualOperation: ManualOperationSettings = defaultEngine.manualOperation; function jitter(value: number, amount = 3): number { return Math.max(0, Math.round(value + (Math.random() * amount * 2 - amount))); diff --git a/src/main/capabilities/excel-com.test.ts b/packages/rpa-core/src/capabilities/excel-com.test.ts similarity index 98% rename from src/main/capabilities/excel-com.test.ts rename to packages/rpa-core/src/capabilities/excel-com.test.ts index baaef13..c0728a9 100644 --- a/src/main/capabilities/excel-com.test.ts +++ b/packages/rpa-core/src/capabilities/excel-com.test.ts @@ -4,7 +4,7 @@ import path from "node:path"; import { afterEach, describe, expect, it } from "vitest"; import ExcelJS from "exceljs"; import { getHandler } from "../engine/registry"; -import type { CatalogComponent, FlowNode } from "../../shared/types"; +import type { CatalogComponent, FlowNode } from "../types"; import type { RunContext } from "../engine/types"; import "./excel-com"; diff --git a/src/main/capabilities/excel-com.ts b/packages/rpa-core/src/capabilities/excel-com.ts similarity index 100% rename from src/main/capabilities/excel-com.ts rename to packages/rpa-core/src/capabilities/excel-com.ts diff --git a/src/main/capabilities/excel-common.test.ts b/packages/rpa-core/src/capabilities/excel-common.test.ts similarity index 99% rename from src/main/capabilities/excel-common.test.ts rename to packages/rpa-core/src/capabilities/excel-common.test.ts index 8a90917..7780a4d 100644 --- a/src/main/capabilities/excel-common.test.ts +++ b/packages/rpa-core/src/capabilities/excel-common.test.ts @@ -3,7 +3,7 @@ import os from "node:os"; import path from "node:path"; import ExcelJS from "exceljs"; import { afterEach, describe, expect, it } from "vitest"; -import type { Catalog, CatalogComponent, FlowNode } from "../../shared/types"; +import type { Catalog, CatalogComponent, FlowNode } from "../types"; import type { RunContext } from "../engine/types"; import { getHandler } from "../engine/registry"; import "./index"; diff --git a/src/main/capabilities/excel-common.ts b/packages/rpa-core/src/capabilities/excel-common.ts similarity index 100% rename from src/main/capabilities/excel-common.ts rename to packages/rpa-core/src/capabilities/excel-common.ts diff --git a/src/main/capabilities/excel-store.test.ts b/packages/rpa-core/src/capabilities/excel-store.test.ts similarity index 98% rename from src/main/capabilities/excel-store.test.ts rename to packages/rpa-core/src/capabilities/excel-store.test.ts index 250f139..110cb24 100644 --- a/src/main/capabilities/excel-store.test.ts +++ b/packages/rpa-core/src/capabilities/excel-store.test.ts @@ -3,7 +3,7 @@ import os from "node:os"; import path from "node:path"; import ExcelJS from "exceljs"; import { afterEach, describe, expect, it } from "vitest"; -import type { CatalogComponent, FlowNode } from "../../shared/types"; +import type { CatalogComponent, FlowNode } from "../types"; import type { RunContext } from "../engine/types"; import { getHandler } from "../engine/registry"; import "./office"; diff --git a/src/main/capabilities/excel-store.ts b/packages/rpa-core/src/capabilities/excel-store.ts similarity index 76% rename from src/main/capabilities/excel-store.ts rename to packages/rpa-core/src/capabilities/excel-store.ts index f4e55a5..fa39a1b 100644 --- a/src/main/capabilities/excel-store.ts +++ b/packages/rpa-core/src/capabilities/excel-store.ts @@ -1,10 +1,11 @@ import ExcelJS from "exceljs"; import path from "node:path"; +import { defaultEngine } from "../engine/engine"; // Excel 工作簿共享缓存:同一文件路径在整条流程中复用同一个 ExcelJS 实例。 // 此前 office.ts / office-file-extended.ts / excel-common.ts / extended.ts 各自持有 // 工作簿实例并整簿写回磁盘,后保存者会把先保存者的修改整体覆盖掉。 -const cache = new Map(); +// 缓存本体挂在引擎实例上(任务 1.3),此处委托 defaultEngine。 function keyOf(filePath: string): string { return path.resolve(filePath); @@ -13,22 +14,22 @@ function keyOf(filePath: string): string { /** 按路径取工作簿:命中缓存直接复用,未命中从磁盘读取后登记。 */ export async function acquireWorkbook(filePath: string): Promise { const key = keyOf(filePath); - let workbook = cache.get(key); + let workbook = defaultEngine.excelCache.get(key); if (!workbook) { workbook = new ExcelJS.Workbook(); await workbook.xlsx.readFile(key); - cache.set(key, workbook); + defaultEngine.excelCache.set(key, workbook); } return workbook; } /** 把一个新建/另建的工作簿实例登记为该路径的共享实例。 */ export function publishWorkbook(filePath: string, workbook: ExcelJS.Workbook): ExcelJS.Workbook { - cache.set(keyOf(filePath), workbook); + defaultEngine.excelCache.set(keyOf(filePath), workbook); return workbook; } /** 释放路径对应的共享实例(关闭工作簿时调用)。 */ export function releaseWorkbook(filePath: string): void { - cache.delete(keyOf(filePath)); + defaultEngine.excelCache.delete(keyOf(filePath)); } diff --git a/src/main/capabilities/extended.test.ts b/packages/rpa-core/src/capabilities/extended.test.ts similarity index 98% rename from src/main/capabilities/extended.test.ts rename to packages/rpa-core/src/capabilities/extended.test.ts index f07884e..b169114 100644 --- a/src/main/capabilities/extended.test.ts +++ b/packages/rpa-core/src/capabilities/extended.test.ts @@ -3,7 +3,7 @@ import os from "node:os"; import path from "node:path"; import ExcelJS from "exceljs"; import { afterEach, describe, expect, it } from "vitest"; -import type { CatalogComponent, FlowNode } from "../../shared/types"; +import type { CatalogComponent, FlowNode } from "../types"; import type { RunContext } from "../engine/types"; import { getHandler } from "../engine/registry"; import "./extended"; diff --git a/src/main/capabilities/extended.ts b/packages/rpa-core/src/capabilities/extended.ts similarity index 100% rename from src/main/capabilities/extended.ts rename to packages/rpa-core/src/capabilities/extended.ts diff --git a/src/main/capabilities/files.test.ts b/packages/rpa-core/src/capabilities/files.test.ts similarity index 97% rename from src/main/capabilities/files.test.ts rename to packages/rpa-core/src/capabilities/files.test.ts index a464102..d454a0b 100644 --- a/src/main/capabilities/files.test.ts +++ b/packages/rpa-core/src/capabilities/files.test.ts @@ -3,7 +3,7 @@ import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises"; import os from "node:os"; import path from "node:path"; import { afterEach, describe, expect, it, vi } from "vitest"; -import type { CatalogComponent, FlowNode } from "../../shared/types"; +import type { CatalogComponent, FlowNode } from "../types"; import type { RunContext } from "../engine/types"; import { getHandler } from "../engine/registry"; import "./files"; diff --git a/src/main/capabilities/files.ts b/packages/rpa-core/src/capabilities/files.ts similarity index 100% rename from src/main/capabilities/files.ts rename to packages/rpa-core/src/capabilities/files.ts diff --git a/src/main/capabilities/ftp.ts b/packages/rpa-core/src/capabilities/ftp.ts similarity index 96% rename from src/main/capabilities/ftp.ts rename to packages/rpa-core/src/capabilities/ftp.ts index e5a6012..aee2509 100644 --- a/src/main/capabilities/ftp.ts +++ b/packages/rpa-core/src/capabilities/ftp.ts @@ -3,11 +3,10 @@ import path from "node:path"; import fs from "node:fs"; import { register } from "../engine/registry"; import { RuntimeError } from "../engine/types"; - -const flags = globalThis as { __rpaFtpClient?: Client }; +import { defaultEngine } from "../engine/engine"; async function requireClient(nodeId: string): Promise { - if (flags.__rpaFtpClient) return flags.__rpaFtpClient; + if (defaultEngine.ftpClient) return defaultEngine.ftpClient; throw new RuntimeError("validation_error", "尚未连接 FTP,请先使用 FTP_Connect", { nodeId, componentId: nodeId, recommendation: "先运行 FTP_Connect 建立连接" }); } @@ -27,14 +26,14 @@ register("FTP_Connect", async (ctx, node, args) => { const secure = String(args.ftp_type ?? "").toLowerCase().includes("ftps"); const client = new Client(10_000); await client.access({ host, port, secure, user, password }); - flags.__rpaFtpClient = client; + defaultEngine.ftpClient = client; ctx.log("已连接 FTP:" + host + ":" + port, "info", node.id); return { connected: true, host, port }; }); register("FTP_Disconnect", async (ctx, node) => { - flags.__rpaFtpClient?.close(); - flags.__rpaFtpClient = undefined; + defaultEngine.ftpClient?.close(); + defaultEngine.ftpClient = undefined; ctx.log("已断开 FTP 连接", "info", node.id); return { disconnected: true }; }); diff --git a/src/main/capabilities/http.ts b/packages/rpa-core/src/capabilities/http.ts similarity index 100% rename from src/main/capabilities/http.ts rename to packages/rpa-core/src/capabilities/http.ts diff --git a/packages/rpa-core/src/capabilities/index.ts b/packages/rpa-core/src/capabilities/index.ts new file mode 100644 index 0000000..d14b9ff --- /dev/null +++ b/packages/rpa-core/src/capabilities/index.ts @@ -0,0 +1,39 @@ +/** + * rpa-core 纯 Node 能力注册入口。 + * + * import 本模块即完成全部纯 Node 能力的副作用注册(与改造前 + * src/main/capabilities/index.ts 的加载顺序保持一致,别名/重复 id 的 + * last-wins 语义不变)。依赖 Electron 或宿主模块的能力(human-dialog / + * window-extended / ai-service / ai-caps / browser* / web-batch2 / web-crawl) + * 留在宿主 src/main/capabilities,阶段 2 通过 HostBridge 迁入。 + */ +import "./control"; +import "./files"; +import "./http"; +import "./data"; +import "./office"; +import "./desktop"; +import "./desktop-uia"; +import "./time-caps"; +import "./windows-system"; +import "./ftp"; +import "./ocr-caps"; +import "./pdf"; +import "./word"; +import "./word-extended"; +import "./message"; +import "./vision"; +import "./cv-vision"; +import "./extended"; +import "./system-extended"; +import "./office-file-extended"; +import "./office-aliases"; +import "./excel-common"; +import "./excel-com"; +import "./data-extended"; +import "./utility-extended"; +import "./data-table-common"; +import "./basic-encryption"; +import "./mail-remaining"; +import "./remaining-core"; +import "./common-final"; diff --git a/src/main/capabilities/keyboard-send-smoke.test.ts b/packages/rpa-core/src/capabilities/keyboard-send-smoke.test.ts similarity index 98% rename from src/main/capabilities/keyboard-send-smoke.test.ts rename to packages/rpa-core/src/capabilities/keyboard-send-smoke.test.ts index 2bdd632..c7d27a5 100644 --- a/src/main/capabilities/keyboard-send-smoke.test.ts +++ b/packages/rpa-core/src/capabilities/keyboard-send-smoke.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from "vitest"; -import type { CatalogComponent, FlowNode } from "../../shared/types"; +import type { CatalogComponent, FlowNode } from "../types"; import { getHandler } from "../engine/registry"; import type { RunContext } from "../engine/types"; import "./desktop"; diff --git a/src/main/capabilities/mail-remaining.ts b/packages/rpa-core/src/capabilities/mail-remaining.ts similarity index 100% rename from src/main/capabilities/mail-remaining.ts rename to packages/rpa-core/src/capabilities/mail-remaining.ts diff --git a/src/main/capabilities/message-recv.test.ts b/packages/rpa-core/src/capabilities/message-recv.test.ts similarity index 97% rename from src/main/capabilities/message-recv.test.ts rename to packages/rpa-core/src/capabilities/message-recv.test.ts index b996ae3..5d5b536 100644 --- a/src/main/capabilities/message-recv.test.ts +++ b/packages/rpa-core/src/capabilities/message-recv.test.ts @@ -1,6 +1,6 @@ import net from "node:net"; import { afterEach, describe, expect, it } from "vitest"; -import type { CatalogComponent, FlowNode } from "../../shared/types"; +import type { CatalogComponent, FlowNode } from "../types"; import type { RunContext } from "../engine/types"; import { getHandler, hasCapability } from "../engine/registry"; import "./message"; diff --git a/src/main/capabilities/message.ts b/packages/rpa-core/src/capabilities/message.ts similarity index 100% rename from src/main/capabilities/message.ts rename to packages/rpa-core/src/capabilities/message.ts diff --git a/src/main/capabilities/ocr-caps.ts b/packages/rpa-core/src/capabilities/ocr-caps.ts similarity index 95% rename from src/main/capabilities/ocr-caps.ts rename to packages/rpa-core/src/capabilities/ocr-caps.ts index e2bef41..42cd0d0 100644 --- a/src/main/capabilities/ocr-caps.ts +++ b/packages/rpa-core/src/capabilities/ocr-caps.ts @@ -2,17 +2,16 @@ import path from "node:path"; import { promises as fs } from "node:fs"; import { register } from "../engine/registry"; import { RuntimeError } from "../engine/types"; +import { defaultEngine } from "../engine/engine"; interface OcrWord { text: string; x: number; y: number; width: number; height: number; confidence: number } interface RapidOcrLine { text: string; mean: number; box?: number[][] } -let ocrInstance: unknown = null; - async function getOcr(): Promise<{ detect: (image: string) => Promise<{ texts: RapidOcrLine[] }> }> { - if (ocrInstance) return ocrInstance as { detect: (image: string) => Promise<{ texts: RapidOcrLine[] }> }; + if (defaultEngine.ocrInstance) return defaultEngine.ocrInstance as { detect: (image: string) => Promise<{ texts: RapidOcrLine[] }> }; const mod = await import("@gutenye/ocr-node"); const instance = await mod.default.create(); - ocrInstance = instance; + defaultEngine.ocrInstance = instance; return instance; } diff --git a/src/main/capabilities/ocr-smoke.test.ts b/packages/rpa-core/src/capabilities/ocr-smoke.test.ts similarity index 98% rename from src/main/capabilities/ocr-smoke.test.ts rename to packages/rpa-core/src/capabilities/ocr-smoke.test.ts index b23192e..ed7283c 100644 --- a/src/main/capabilities/ocr-smoke.test.ts +++ b/packages/rpa-core/src/capabilities/ocr-smoke.test.ts @@ -1,7 +1,7 @@ import { existsSync } from "node:fs"; import { describe, expect, it } from "vitest"; import { getHandler } from "../engine/registry"; -import type { CatalogComponent, FlowNode } from "../../shared/types"; +import type { CatalogComponent, FlowNode } from "../types"; import type { RunContext } from "../engine/types"; import "./ocr-caps"; import "./remaining-core"; diff --git a/src/main/capabilities/office-aliases.test.ts b/packages/rpa-core/src/capabilities/office-aliases.test.ts similarity index 96% rename from src/main/capabilities/office-aliases.test.ts rename to packages/rpa-core/src/capabilities/office-aliases.test.ts index f89e59a..74c6122 100644 --- a/src/main/capabilities/office-aliases.test.ts +++ b/packages/rpa-core/src/capabilities/office-aliases.test.ts @@ -2,9 +2,8 @@ import { readFile, mkdtemp, rm } from "node:fs/promises"; import os from "node:os"; import path from "node:path"; import ExcelJS from "exceljs"; -import { fileURLToPath } from "node:url"; import { afterEach, describe, expect, it } from "vitest"; -import type { Catalog, CatalogComponent, FlowNode } from "../../shared/types"; +import type { Catalog, CatalogComponent, FlowNode } from "../types"; import type { RunContext } from "../engine/types"; import { getHandler } from "../engine/registry"; import "./office"; @@ -21,7 +20,8 @@ afterEach(async () => Promise.all(dirs.splice(0).map((dir) => rm(dir, { recursiv describe("common Excel aliases", () => { it("registers only real catalog aliases", async () => { - const catalog = JSON.parse(await readFile(path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../../../resources/catalog.json"), "utf8")) as Catalog; + // vitest 工作目录为仓库根,包内测试统一以 cwd 定位仓库资源 + const catalog = JSON.parse(await readFile(path.resolve(process.cwd(), "resources/catalog.json"), "utf8")) as Catalog; const ids = new Set(catalog.components.map((item) => item.id)); expect(EXCEL_COMMON_ALIASES.length).toBeGreaterThanOrEqual(25); for (const id of EXCEL_COMMON_ALIASES) { expect(ids.has(id), id).toBe(true); expect(getHandler(id), id).toBeTruthy(); } diff --git a/src/main/capabilities/office-aliases.ts b/packages/rpa-core/src/capabilities/office-aliases.ts similarity index 100% rename from src/main/capabilities/office-aliases.ts rename to packages/rpa-core/src/capabilities/office-aliases.ts diff --git a/src/main/capabilities/office-file-extended.test.ts b/packages/rpa-core/src/capabilities/office-file-extended.test.ts similarity index 98% rename from src/main/capabilities/office-file-extended.test.ts rename to packages/rpa-core/src/capabilities/office-file-extended.test.ts index 3ba3b6d..cecb290 100644 --- a/src/main/capabilities/office-file-extended.test.ts +++ b/packages/rpa-core/src/capabilities/office-file-extended.test.ts @@ -4,7 +4,7 @@ import os from "node:os"; import path from "node:path"; import { PDFDocument } from "pdf-lib"; import { afterEach, describe, expect, it } from "vitest"; -import type { CatalogComponent, FlowNode } from "../../shared/types"; +import type { CatalogComponent, FlowNode } from "../types"; import { getHandler } from "../engine/registry"; import type { RunContext } from "../engine/types"; import "./office-file-extended"; diff --git a/src/main/capabilities/office-file-extended.ts b/packages/rpa-core/src/capabilities/office-file-extended.ts similarity index 100% rename from src/main/capabilities/office-file-extended.ts rename to packages/rpa-core/src/capabilities/office-file-extended.ts diff --git a/src/main/capabilities/office.ts b/packages/rpa-core/src/capabilities/office.ts similarity index 98% rename from src/main/capabilities/office.ts rename to packages/rpa-core/src/capabilities/office.ts index 9786cb2..cf5d9d2 100644 --- a/src/main/capabilities/office.ts +++ b/packages/rpa-core/src/capabilities/office.ts @@ -3,6 +3,7 @@ import { promises as fs } from "node:fs"; import path from "node:path"; import { register } from "../engine/registry"; import { RuntimeError, type CapabilityHandler } from "../engine/types"; +import { defaultEngine } from "../engine/engine"; import { acquireWorkbook, publishWorkbook, releaseWorkbook } from "./excel-store"; interface ExcelHandle { @@ -10,7 +11,8 @@ interface ExcelHandle { path: string; } -const workbooks = new Map(); +// 句柄 id → 工作簿;本体挂在引擎实例上(任务 1.3),此处委托 defaultEngine。 +const workbooks = defaultEngine.excelHandles; function value(args: Record, keys: string[], fallback = ""): unknown { for (const key of keys) { diff --git a/src/main/capabilities/pdf-high.test.ts b/packages/rpa-core/src/capabilities/pdf-high.test.ts similarity index 97% rename from src/main/capabilities/pdf-high.test.ts rename to packages/rpa-core/src/capabilities/pdf-high.test.ts index 2e0378c..954c75f 100644 --- a/src/main/capabilities/pdf-high.test.ts +++ b/packages/rpa-core/src/capabilities/pdf-high.test.ts @@ -5,7 +5,7 @@ import { afterEach, describe, expect, it } from "vitest"; import { PDFDocument, StandardFonts } from "pdf-lib"; import { PNG } from "pngjs"; import { getHandler } from "../engine/registry"; -import type { CatalogComponent, FlowNode } from "../../shared/types"; +import type { CatalogComponent, FlowNode } from "../types"; import type { RunContext } from "../engine/types"; import "./pdf"; diff --git a/src/main/capabilities/pdf.ts b/packages/rpa-core/src/capabilities/pdf.ts similarity index 100% rename from src/main/capabilities/pdf.ts rename to packages/rpa-core/src/capabilities/pdf.ts diff --git a/src/main/capabilities/relativeposition-smoke.test.ts b/packages/rpa-core/src/capabilities/relativeposition-smoke.test.ts similarity index 96% rename from src/main/capabilities/relativeposition-smoke.test.ts rename to packages/rpa-core/src/capabilities/relativeposition-smoke.test.ts index 17e7604..9ccdf8f 100644 --- a/src/main/capabilities/relativeposition-smoke.test.ts +++ b/packages/rpa-core/src/capabilities/relativeposition-smoke.test.ts @@ -1,7 +1,7 @@ import { existsSync } from "node:fs"; import { describe, expect, it } from "vitest"; import { getHandler } from "../engine/registry"; -import type { CatalogComponent, FlowNode } from "../../shared/types"; +import type { CatalogComponent, FlowNode } from "../types"; import type { RunContext } from "../engine/types"; import "./vision"; import "./remaining-core"; diff --git a/src/main/capabilities/remaining-core.ts b/packages/rpa-core/src/capabilities/remaining-core.ts similarity index 96% rename from src/main/capabilities/remaining-core.ts rename to packages/rpa-core/src/capabilities/remaining-core.ts index c739423..9ef3f88 100644 --- a/src/main/capabilities/remaining-core.ts +++ b/packages/rpa-core/src/capabilities/remaining-core.ts @@ -3,6 +3,8 @@ import path from "node:path"; import { getHandler, register } from "../engine/registry"; import { runFlow } from "../engine/runtime"; import { RuntimeError, type CapabilityHandler, type RunContext } from "../engine/types"; +import { defaultEngine } from "../engine/engine"; +import { getSubflowSource } from "../engine/host-bridge"; import { powershell, psString } from "./desktop"; import { findImage } from "./vision"; @@ -24,7 +26,8 @@ function required(value: string, label: string, node: { id: string; componentId: return value; } -const dbConnections = new Map(); +// 连接 id → 数据库连接;本体挂在引擎实例上(任务 1.3)。 +const dbConnections = defaultEngine.dbConnections as Map; function dbConfig(args: Record): Record { const inline = record(args.DatabaseConfig || args.config || args.connectionID); const merged = { ...inline, ...args }; @@ -67,12 +70,14 @@ register("Database_CloseDBConnect", async (_ctx, _node, args) => { dbConnections.delete(key); return { closed: true }; }); async function callSubflow(ctx: RunContext, node: { id: string; componentId: string }, args: Record) { - const { listFlows, getFlow } = await import("../flows"); + // 子流程仓库属宿主职责:经 host-bridge 注入(阶段 2 正式化),包内不 import "../flows" + const source = getSubflowSource(); + if (!source) throw new RuntimeError("validation_error", "子流程源未注入", { nodeId: node.id, componentId: node.componentId, recommendation: "宿主需在启动时调用 setSubflowSource()" }); const wanted = text(args, ["module_name", "module", "flow"]); - const rows = await listFlows(); const found = rows.find((row) => row.id === wanted || row.name === wanted); + const rows = await source.listFlows(); const found = rows.find((row) => row.id === wanted || row.name === wanted); if (!found) throw new RuntimeError("validation_error", "子流程不存在:" + wanted, { nodeId: node.id, componentId: node.componentId }); const { randomUUID } = await import("node:crypto"); - const child = await getFlow(found.id); const inputs = record(args.args || args.input); + const child = await source.getFlow(found.id); const inputs = record(args.args || args.input); return await runFlow(child, { runId: randomUUID(), evidenceDir: ctx.evidenceDir, signal: ctx.signal, emit: ctx.emit, log: ctx.log, componentOf: ctx.componentOf, browser: ctx.browser, variables: { ...ctx.vars, ...inputs } }); } register("child_modules_v1", async (ctx, node, args) => callSubflow(ctx, node, args)); diff --git a/src/main/capabilities/system-extended.test.ts b/packages/rpa-core/src/capabilities/system-extended.test.ts similarity index 97% rename from src/main/capabilities/system-extended.test.ts rename to packages/rpa-core/src/capabilities/system-extended.test.ts index 8a8b3c5..4a0bd73 100644 --- a/src/main/capabilities/system-extended.test.ts +++ b/packages/rpa-core/src/capabilities/system-extended.test.ts @@ -2,7 +2,7 @@ import { spawn } from "node:child_process"; import os from "node:os"; import path from "node:path"; import { afterEach, describe, expect, it } from "vitest"; -import type { CatalogComponent, FlowNode } from "../../shared/types"; +import type { CatalogComponent, FlowNode } from "../types"; import type { RunContext } from "../engine/types"; import { getHandler } from "../engine/registry"; import "./system-extended"; diff --git a/src/main/capabilities/system-extended.ts b/packages/rpa-core/src/capabilities/system-extended.ts similarity index 100% rename from src/main/capabilities/system-extended.ts rename to packages/rpa-core/src/capabilities/system-extended.ts diff --git a/src/main/capabilities/time-caps.ts b/packages/rpa-core/src/capabilities/time-caps.ts similarity index 100% rename from src/main/capabilities/time-caps.ts rename to packages/rpa-core/src/capabilities/time-caps.ts diff --git a/src/main/capabilities/utility-extended.test.ts b/packages/rpa-core/src/capabilities/utility-extended.test.ts similarity index 99% rename from src/main/capabilities/utility-extended.test.ts rename to packages/rpa-core/src/capabilities/utility-extended.test.ts index 59b63df..c00ff69 100644 --- a/src/main/capabilities/utility-extended.test.ts +++ b/packages/rpa-core/src/capabilities/utility-extended.test.ts @@ -2,7 +2,7 @@ import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises"; import os from "node:os"; import path from "node:path"; import { afterEach, describe, expect, it } from "vitest"; -import type { Catalog, CatalogComponent, FlowDefinition, FlowNode } from "../../shared/types"; +import type { Catalog, CatalogComponent, FlowDefinition, FlowNode } from "../types"; import type { RunContext } from "../engine/types"; import { getHandler } from "../engine/registry"; import "./utility-extended"; diff --git a/src/main/capabilities/utility-extended.ts b/packages/rpa-core/src/capabilities/utility-extended.ts similarity index 100% rename from src/main/capabilities/utility-extended.ts rename to packages/rpa-core/src/capabilities/utility-extended.ts diff --git a/src/main/capabilities/vision-helpers.test.ts b/packages/rpa-core/src/capabilities/vision-helpers.test.ts similarity index 100% rename from src/main/capabilities/vision-helpers.test.ts rename to packages/rpa-core/src/capabilities/vision-helpers.test.ts diff --git a/src/main/capabilities/vision-match.test.ts b/packages/rpa-core/src/capabilities/vision-match.test.ts similarity index 100% rename from src/main/capabilities/vision-match.test.ts rename to packages/rpa-core/src/capabilities/vision-match.test.ts diff --git a/src/main/capabilities/vision.ts b/packages/rpa-core/src/capabilities/vision.ts similarity index 100% rename from src/main/capabilities/vision.ts rename to packages/rpa-core/src/capabilities/vision.ts diff --git a/src/main/capabilities/windows-system.ts b/packages/rpa-core/src/capabilities/windows-system.ts similarity index 100% rename from src/main/capabilities/windows-system.ts rename to packages/rpa-core/src/capabilities/windows-system.ts diff --git a/src/main/capabilities/word-extended.test.ts b/packages/rpa-core/src/capabilities/word-extended.test.ts similarity index 98% rename from src/main/capabilities/word-extended.test.ts rename to packages/rpa-core/src/capabilities/word-extended.test.ts index 348fa9c..04996cc 100644 --- a/src/main/capabilities/word-extended.test.ts +++ b/packages/rpa-core/src/capabilities/word-extended.test.ts @@ -2,7 +2,7 @@ import { mkdtemp, readFile, rm } from "node:fs/promises"; import os from "node:os"; import path from "node:path"; import { afterEach, describe, expect, it } from "vitest"; -import type { CatalogComponent, FlowNode } from "../../shared/types"; +import type { CatalogComponent, FlowNode } from "../types"; import type { RunContext } from "../engine/types"; import { getHandler } from "../engine/registry"; import "./word"; diff --git a/src/main/capabilities/word-extended.ts b/packages/rpa-core/src/capabilities/word-extended.ts similarity index 100% rename from src/main/capabilities/word-extended.ts rename to packages/rpa-core/src/capabilities/word-extended.ts diff --git a/src/main/capabilities/word.ts b/packages/rpa-core/src/capabilities/word.ts similarity index 100% rename from src/main/capabilities/word.ts rename to packages/rpa-core/src/capabilities/word.ts diff --git a/packages/rpa-core/src/engine/engine.ts b/packages/rpa-core/src/engine/engine.ts new file mode 100644 index 0000000..70fe406 --- /dev/null +++ b/packages/rpa-core/src/engine/engine.ts @@ -0,0 +1,49 @@ +import type { Client } from "basic-ftp"; +import type { Workbook as ExcelJSWorkbook } from "exceljs"; + +/** 人为拟真操作的开关与随机参数(desktop 能力的进程级设置)。 */ +export interface ManualOperationSettings { + enabled: boolean; + randomMove: boolean; + randomClick: boolean; + randomSleep: boolean; + minMs: number; + maxMs: number; +} + +/** + * 引擎实例状态容器(任务 1.3,R4:模块级全局状态收拢)。 + * + * 折中方案(决策记录 2026-11-04):能力文件的 register() 调用与全局注册表保持不变, + * 但 Excel 缓存、数据库连接、FTP 客户端等进程级可变状态统一挂到引擎实例上。 + * 包内各能力模块通过 defaultEngine 访问;宿主/CLI 可用 createEngine() 产生隔离实例, + * 或拿到 defaultEngine 做测试间重置。 + */ +export class RpaEngine { + /** excel-store:路径 → ExcelJS 工作簿共享缓存 */ + readonly excelCache = new Map(); + /** office.ts:Excel 句柄 id → 工作簿 */ + readonly excelHandles = new Map(); + /** remaining-core:连接 id → 数据库连接(mysql2/pg/mssql) */ + readonly dbConnections = new Map(); + /** ftp.ts:当前 FTP 连接 */ + ftpClient?: Client; + /** ocr-caps.ts:懒加载的 OCR 实例 */ + ocrInstance?: unknown; + /** desktop.ts:人为拟真操作设置 */ + manualOperation: ManualOperationSettings = { + enabled: false, + randomMove: true, + randomClick: true, + randomSleep: true, + minMs: 1000, + maxMs: 3000 + }; +} + +export function createEngine(): RpaEngine { + return new RpaEngine(); +} + +/** 能力模块内部使用的默认引擎实例(与全局注册表配套的进程级单例)。 */ +export const defaultEngine = createEngine(); diff --git a/src/main/engine/expression.ts b/packages/rpa-core/src/engine/expression.ts similarity index 100% rename from src/main/engine/expression.ts rename to packages/rpa-core/src/engine/expression.ts diff --git a/packages/rpa-core/src/engine/host-bridge.ts b/packages/rpa-core/src/engine/host-bridge.ts new file mode 100644 index 0000000..bf49407 --- /dev/null +++ b/packages/rpa-core/src/engine/host-bridge.ts @@ -0,0 +1,22 @@ +import type { FlowDefinition } from "../types"; + +/** + * 宿主桥(HostBridge 候选,阶段 2 正式化接口)。 + * + * 包内个别能力需要宿主数据(目前仅子流程仓库),通过显式 setter 注入, + * 包本身不得 import 宿主模块。宿主启动时调用 setSubflowSource()。 + */ +export interface SubflowSource { + listFlows(): Promise>; + getFlow(id: string): Promise; +} + +let subflowSource: SubflowSource | undefined; + +export function setSubflowSource(source: SubflowSource): void { + subflowSource = source; +} + +export function getSubflowSource(): SubflowSource | undefined { + return subflowSource; +} diff --git a/src/main/engine/registry.ts b/packages/rpa-core/src/engine/registry.ts similarity index 100% rename from src/main/engine/registry.ts rename to packages/rpa-core/src/engine/registry.ts diff --git a/src/main/engine/runtime.error-route.test.ts b/packages/rpa-core/src/engine/runtime.error-route.test.ts similarity index 98% rename from src/main/engine/runtime.error-route.test.ts rename to packages/rpa-core/src/engine/runtime.error-route.test.ts index f33d4d4..d6e3f16 100644 --- a/src/main/engine/runtime.error-route.test.ts +++ b/packages/rpa-core/src/engine/runtime.error-route.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from "vitest"; -import type { CatalogComponent, FlowDefinition } from "../../shared/types"; +import type { CatalogComponent, FlowDefinition } from "../types"; import { register } from "./registry"; import { runFlow } from "./runtime"; diff --git a/src/main/engine/runtime.integration.test.ts b/packages/rpa-core/src/engine/runtime.integration.test.ts similarity index 99% rename from src/main/engine/runtime.integration.test.ts rename to packages/rpa-core/src/engine/runtime.integration.test.ts index d1f4d24..a177106 100644 --- a/src/main/engine/runtime.integration.test.ts +++ b/packages/rpa-core/src/engine/runtime.integration.test.ts @@ -10,7 +10,7 @@ import type { FlowEdge, FlowNode, RunEvent -} from "../../shared/types"; +} from "../types"; import "../capabilities"; import { register } from "./registry"; import { runFlow } from "./runtime"; diff --git a/src/main/engine/runtime.ts b/packages/rpa-core/src/engine/runtime.ts similarity index 99% rename from src/main/engine/runtime.ts rename to packages/rpa-core/src/engine/runtime.ts index 05b54fb..90fba10 100644 --- a/src/main/engine/runtime.ts +++ b/packages/rpa-core/src/engine/runtime.ts @@ -1,4 +1,4 @@ -import type { FlowDefinition, FlowNode, RunError } from "../../shared/types"; +import type { FlowDefinition, FlowNode, RunError } from "../types"; import { evaluate, evaluateCondition, interpolate, toNumber } from "./expression"; import { getHandler } from "./registry"; import { diff --git a/src/main/engine/types.ts b/packages/rpa-core/src/engine/types.ts similarity index 99% rename from src/main/engine/types.ts rename to packages/rpa-core/src/engine/types.ts index 7d607df..19f42e3 100644 --- a/src/main/engine/types.ts +++ b/packages/rpa-core/src/engine/types.ts @@ -1,4 +1,4 @@ -import type { CatalogComponent, FlowDefinition, FlowNode, RunError, RunEvent } from "../../shared/types"; +import type { CatalogComponent, FlowDefinition, FlowNode, RunError, RunEvent } from "../types"; export interface BrowserLike { navigate(url: string): Promise<{ url: string; title: string }>; diff --git a/packages/rpa-core/src/index.ts b/packages/rpa-core/src/index.ts new file mode 100644 index 0000000..e36cd81 --- /dev/null +++ b/packages/rpa-core/src/index.ts @@ -0,0 +1,43 @@ +/** + * @rpa/core 包入口。 + * + * 只导出引擎 API 与类型,不做能力注册副作用; + * 纯 Node 能力通过 `@rpa/core/capabilities` 子路径按需拉起(保持与 demo 宿主 + * src/main/capabilities/index.ts 相同的副作用注册模型,见任务 4.2 再显式化)。 + */ +export { createEngine, defaultEngine, RpaEngine, type ManualOperationSettings } from "./engine/engine"; +export { register, getHandler, hasCapability, capabilityIds, capabilityCount } from "./engine/registry"; +export { runFlow } from "./engine/runtime"; +export { RuntimeError, BreakSignal, ContinueSignal, StopSignal, asRuntimeError } from "./engine/types"; +export { setSubflowSource, getSubflowSource, type SubflowSource } from "./engine/host-bridge"; +// PowerShell 助手(阶段 3 将移入 driver/windows/):宿主留守能力(window-extended 等)经此引用 +export { powershell, psString } from "./capabilities/desktop"; +export type { + BrowserLike, + BrowserTabInfo, + BrowserElementReference, + BrowserElementInfo, + BrowserSelectOption, + BrowserSelectState, + BrowserSimilarElementOptions, + BrowserElementRegion, + RunContext, + CapabilityHandler, + NodeState, + RunResult +} from "./engine/types"; +export type { + CatalogWidget, + CatalogField, + CatalogOutput, + CatalogComponent, + CatalogGroup, + Catalog, + FlowVariable, + FlowNodeOptions, + FlowNode, + FlowEdge, + FlowDefinition, + RunError, + RunEvent +} from "./types"; diff --git a/packages/rpa-core/src/types.ts b/packages/rpa-core/src/types.ts new file mode 100644 index 0000000..afa0d01 --- /dev/null +++ b/packages/rpa-core/src/types.ts @@ -0,0 +1,187 @@ +/** + * rpa-core 领域类型(任务 1.2,类型单一源) + * + * 从 src/shared/types 拆出:与流程/目录/运行相关、引擎必须依赖的模型归包所有。 + * 宿主专属类型(AppInfo / AppSettings / FlowSummary / VisionLab* 等)留在 src/shared/types, + * 该文件通过 type-only re-export 引用本文件,保证全仓不出现两份定义。 + */ + +export type CatalogWidget = + | "text" + | "textarea" + | "number" + | "select" + | "radio" + | "boolean" + | "file" + | "folder" + | "element" + | "code" + | "secret" + | "region" + | "hidden"; + +export interface CatalogField { + key: string; + label: string; + widget: CatalogWidget; + type: "string" | "number" | "boolean" | "object"; + displayType: string; + required: boolean; + defaultValue: string; + placeholder: string; + description: string; + advanced: boolean; + valueTypes: string[]; + /** 下拉/单选选项:字符串(显示=存储值)或 { label, value }(显示与存储分离) */ + options?: Array; + unit?: string; +} + +export interface CatalogOutput { + label: string; + key: string; + suggestedName: string; + valueTypes: string[]; + fields: Array<{ key: string; label: string; defaultValue: string; valueTypes: string[] }>; +} + +export interface CatalogComponent { + id: string; + name: string; + kind: "vendor" | "native" | "trigger"; + group: string; + categories: string[]; + categorySignature: string; + description: string; + messageTemplate: string; + baseType: string; + functionName: string; + functionCalls: Array<{ function: string; args: string[]; assignTo: string }>; + version: string; + tags: string[]; + platformTag: string | null; + icon: string; + risk: "low" | "high"; + fields: CatalogField[]; + output: CatalogOutput; + slots: string[]; + nodeKind?: string; + /** 同名旧版本 / 重复别名指向的保留能力 ID。 */ + duplicateOf?: string; +} + +export interface CatalogGroup { + id: string; + label: string; + icon: string; + count: number; +} + +export interface Catalog { + schemaVersion: number; + generatedAt: string; + counts: { + total: number; + vendor: number; + native: number; + triggers: number; + fields: number; + }; + groups: CatalogGroup[]; + components: CatalogComponent[]; +} + +export interface FlowVariable { + name: string; + type: string; + defaultValue?: string; + description?: string; + scope?: "flow" | "local"; +} + +export interface FlowNodeOptions { + outputVar?: string; + delayBeforeMs?: number; + delayAfterMs?: number; + timeoutMs?: number; + retryCount?: number; + retryIntervalMs?: number; + skipOnError?: boolean; + logException?: boolean; + errorRouteEnabled?: boolean; +} + +export interface FlowNode { + id: string; + componentId: string; + label?: string; + position: { x: number; y: number }; + values: Record; + options: FlowNodeOptions; + parentId?: string | null; + slot?: string; + enabled?: boolean; + width?: number; + height?: number; +} + +export interface FlowEdge { + id: string; + source: string; + target: string; + sourceHandle?: string | null; + targetHandle?: string | null; + label?: string; +} + +export interface FlowDefinition { + schemaVersion: 1; + id: string; + name: string; + description?: string; + enabled?: boolean; + trigger?: { + type: "manual" | "schedule" | "file"; + label: string; + }; + variables: FlowVariable[]; + nodes: FlowNode[]; + edges: FlowEdge[]; + meta: { + createdAt: string; + updatedAt: string; + appVersion: string; + }; +} + +export interface RunError { + code: string; + reason: string; + recommendation?: string; + location?: { flowId?: string; nodeId?: string; componentId?: string; arg?: string }; + detail?: string; +} + +export interface RunEvent { + type: + | "run.started" + | "node.started" + | "node.log" + | "node.finished" + | "run.finished" + | "run.total"; + runId: string; + nodeId?: string; + level?: "info" | "warn" | "error"; + message?: string; + status?: string; + output?: unknown; + error?: RunError; + durationMs?: number; + evidence?: string[]; + attempt?: number; + startedAt?: string; + nodeLabel?: string; + total?: number; +} diff --git a/packages/rpa-core/tsconfig.json b/packages/rpa-core/tsconfig.json new file mode 100644 index 0000000..9270318 --- /dev/null +++ b/packages/rpa-core/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "ESNext", + "moduleResolution": "Bundler", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "allowSyntheticDefaultImports": true, + "forceConsistentCasingInFileNames": true, + "noEmit": true, + "types": ["node"] + }, + "include": ["src/**/*.ts"] +} diff --git a/packages/rpa-core/vitest.config.ts b/packages/rpa-core/vitest.config.ts new file mode 100644 index 0000000..aefc1a2 --- /dev/null +++ b/packages/rpa-core/vitest.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + test: { + // 与根配置一致:桌面自动化冒烟测试共用同一物理桌面,串行执行防焦点竞争。 + fileParallelism: false + } +}); diff --git a/resources/capability-snapshot.json b/resources/capability-snapshot.json index b514967..8e7d48a 100644 --- a/resources/capability-snapshot.json +++ b/resources/capability-snapshot.json @@ -1,5 +1,5 @@ { - "generatedAt": "2026-11-04T03:53:23.689Z", + "generatedAt": "2026-11-04T04:34:06.782Z", "count": 909, "ids": [ "App_GetPid", diff --git a/scripts/app-system-tests.test.mjs b/scripts/app-system-tests.test.mjs index fa63ab3..d936b79 100644 --- a/scripts/app-system-tests.test.mjs +++ b/scripts/app-system-tests.test.mjs @@ -5,8 +5,8 @@ import { afterEach, describe, expect, it } from "vitest"; import { buildSuite, bundleRoot } from "./app-system-test-flows.mjs"; import { installBundle, upgradeBundle, makeReport, caseResults } from "./app-system-tests.mjs"; import { applyCatalogOverrides } from "./catalog-overrides.mjs"; -import { hasCapability } from "../src/main/capabilities/index.ts"; -import { runFlow } from "../src/main/engine/runtime.ts"; +import { hasCapability, runFlow } from "@rpa/core"; +import "../src/main/capabilities/index.ts"; import { validateFlow } from "../src/renderer/src/validation/flowValidation.ts"; const containers = new Set(["logic_control_try_catch", "logic_control_if_else"]); @@ -58,7 +58,7 @@ describe("应用与系统测试流程包", () => { const options = component.fields.find(field => field.key === "into_type").options; expect(options.length).toBeGreaterThanOrEqual(4); for (const option of options) { - const output = await import("../src/main/engine/registry.ts").then(({ getHandler }) => getHandler(id)({}, { id: "type-test", componentId: id }, { val: 42, into_type: option.value }, component)); + const output = await import("@rpa/core").then(({ getHandler }) => getHandler(id)({}, { id: "type-test", componentId: id }, { val: 42, into_type: option.value }, component)); if (id === "Basic_JudgeDataType") expect(typeof output).toBe("boolean"); } } diff --git a/src/main/browser/external.ts b/src/main/browser/external.ts index 900adb1..7685edd 100644 --- a/src/main/browser/external.ts +++ b/src/main/browser/external.ts @@ -2,7 +2,7 @@ import { execFile, spawn, type ChildProcess } from "node:child_process"; import { promises as fs } from "node:fs"; import os from "node:os"; import path from "node:path"; -import { RuntimeError } from "../engine/types"; +import { RuntimeError } from "@rpa/core"; import { ExternalTransport } from "./transport"; /** diff --git a/src/main/browser/session.ts b/src/main/browser/session.ts index 9e44d58..cc2ff55 100644 --- a/src/main/browser/session.ts +++ b/src/main/browser/session.ts @@ -30,7 +30,7 @@ import { type BrowserSelectState, type BrowserSimilarElementOptions, type BrowserTabInfo -} from "../engine/types"; +} from "@rpa/core"; function assertUrl(raw: string): URL { let url: URL; diff --git a/src/main/browser/transport.ts b/src/main/browser/transport.ts index 8c69f18..c312225 100644 --- a/src/main/browser/transport.ts +++ b/src/main/browser/transport.ts @@ -1,6 +1,6 @@ import type { BrowserWindow } from "electron"; import WebSocket from "ws"; -import { RuntimeError } from "../engine/types"; +import { RuntimeError } from "@rpa/core"; /** * CDP 传输层抽象。 diff --git a/src/main/capabilities/ai-caps.ts b/src/main/capabilities/ai-caps.ts index 9265c5f..5255419 100644 --- a/src/main/capabilities/ai-caps.ts +++ b/src/main/capabilities/ai-caps.ts @@ -1,5 +1,5 @@ -import { register } from "../engine/registry"; -import { RuntimeError } from "../engine/types"; +import { register } from "@rpa/core"; +import { RuntimeError } from "@rpa/core"; import { chatCompletion, requireAiConfig } from "./ai-service"; function inputText(args: Record, nodeId: string): string { diff --git a/src/main/capabilities/ai-service.ts b/src/main/capabilities/ai-service.ts index e859c11..9d7a84a 100644 --- a/src/main/capabilities/ai-service.ts +++ b/src/main/capabilities/ai-service.ts @@ -1,5 +1,5 @@ import { loadSettings } from "../settings"; -import { RuntimeError } from "../engine/types"; +import { RuntimeError } from "@rpa/core"; export type ChatContentPart = | { type: "text"; text: string } diff --git a/src/main/capabilities/browser-common.test.ts b/src/main/capabilities/browser-common.test.ts index 7363142..48fb8cb 100644 --- a/src/main/capabilities/browser-common.test.ts +++ b/src/main/capabilities/browser-common.test.ts @@ -2,7 +2,7 @@ import { readFileSync } from "node:fs"; import { resolve } from "node:path"; import { beforeEach, describe, expect, it, vi } from "vitest"; import type { CatalogComponent, FlowNode } from "../../shared/types"; -import { getHandler } from "../engine/registry"; +import { getHandler } from "@rpa/core"; import { RuntimeError, type BrowserElementInfo, @@ -10,7 +10,7 @@ import { type BrowserLike, type BrowserSelectState, type RunContext -} from "../engine/types"; +} from "@rpa/core"; import { BROWSER_COMMON_IDS } from "./browser-common"; const component = {} as CatalogComponent; diff --git a/src/main/capabilities/browser-common.ts b/src/main/capabilities/browser-common.ts index c77f20e..1fa61dc 100644 --- a/src/main/capabilities/browser-common.ts +++ b/src/main/capabilities/browser-common.ts @@ -1,6 +1,6 @@ import { browserSession } from "../browser/session"; -import { register } from "../engine/registry"; -import { RuntimeError, type BrowserElementInfo, type BrowserLike, type RunContext } from "../engine/types"; +import { register } from "@rpa/core"; +import { RuntimeError, type BrowserElementInfo, type BrowserLike, type RunContext } from "@rpa/core"; const GET_ELEMENT_IDS = ["Element_GetElement", "Element_GetElementV1", "Element_GetElementV2", "Element_GetElementNew"]; const GET_INFO_IDS = ["Element_GetElementInfo", "Element_GetElementInfo_V1"]; diff --git a/src/main/capabilities/browser-control.test.ts b/src/main/capabilities/browser-control.test.ts index 6f67a0e..b0aa33d 100644 --- a/src/main/capabilities/browser-control.test.ts +++ b/src/main/capabilities/browser-control.test.ts @@ -2,8 +2,8 @@ import { readFileSync } from "node:fs"; import { resolve } from "node:path"; import { beforeEach, describe, expect, it, vi } from "vitest"; import type { CatalogComponent, FlowNode } from "../../shared/types"; -import type { BrowserLike, RunContext } from "../engine/types"; -import { getHandler } from "../engine/registry"; +import type { BrowserLike, RunContext } from "@rpa/core"; +import { getHandler } from "@rpa/core"; import { BROWSER_CONTROL_IDS } from "./browser-control"; const component = {} as CatalogComponent; const node = (id: string): FlowNode => ({ id, componentId: id, position: { x: 0, y: 0 }, values: {}, options: {} }); diff --git a/src/main/capabilities/browser-control.ts b/src/main/capabilities/browser-control.ts index 3f573bd..7448e65 100644 --- a/src/main/capabilities/browser-control.ts +++ b/src/main/capabilities/browser-control.ts @@ -1,8 +1,8 @@ import path from "node:path"; import { promises as fs } from "node:fs"; import { browserSession } from "../browser/session"; -import { register } from "../engine/registry"; -import { RuntimeError, type BrowserLike, type RunContext } from "../engine/types"; +import { register } from "@rpa/core"; +import { RuntimeError, type BrowserLike, type RunContext } from "@rpa/core"; async function session(ctx: RunContext): Promise { if (!ctx.browser) ctx.browser = await browserSession(); return ctx.browser; } function selector(args: Record): unknown { const value = args.uiSelector ?? args.download_selector ?? args.selector; if (value === undefined || value === null || value === "") throw new RuntimeError("validation_error", "元素选择器为空"); return value; } diff --git a/src/main/capabilities/browser-dom.test.ts b/src/main/capabilities/browser-dom.test.ts index b88de2a..612dba3 100644 --- a/src/main/capabilities/browser-dom.test.ts +++ b/src/main/capabilities/browser-dom.test.ts @@ -2,8 +2,8 @@ import { readFileSync } from "node:fs"; import { resolve } from "node:path"; import { beforeEach, describe, expect, it, vi } from "vitest"; import type { CatalogComponent, FlowNode } from "../../shared/types"; -import { getHandler } from "../engine/registry"; -import { RuntimeError, type BrowserElementRegion, type BrowserLike, type RunContext } from "../engine/types"; +import { getHandler } from "@rpa/core"; +import { RuntimeError, type BrowserElementRegion, type BrowserLike, type RunContext } from "@rpa/core"; import { BROWSER_DOM_IDS } from "./browser-dom"; const component = {} as CatalogComponent; diff --git a/src/main/capabilities/browser-dom.ts b/src/main/capabilities/browser-dom.ts index 80c6add..e86649f 100644 --- a/src/main/capabilities/browser-dom.ts +++ b/src/main/capabilities/browser-dom.ts @@ -1,7 +1,7 @@ import path from "node:path"; import { browserSession } from "../browser/session"; -import { register } from "../engine/registry"; -import { RuntimeError, type BrowserLike, type RunContext } from "../engine/types"; +import { register } from "@rpa/core"; +import { RuntimeError, type BrowserLike, type RunContext } from "@rpa/core"; export const BROWSER_DOM_IDS = [ "Element_GetAttribute", "Element_GetAttribute_v1", "Element_GetAttribute_v2", "Element_GetAttribute_v3", diff --git a/src/main/capabilities/browser-extended.test.ts b/src/main/capabilities/browser-extended.test.ts index 31da0e2..9359bd5 100644 --- a/src/main/capabilities/browser-extended.test.ts +++ b/src/main/capabilities/browser-extended.test.ts @@ -2,8 +2,8 @@ import { readFileSync } from "node:fs"; import { resolve } from "node:path"; import { beforeEach, describe, expect, it, vi } from "vitest"; import type { CatalogComponent, FlowNode } from "../../shared/types"; -import { getHandler } from "../engine/registry"; -import { RuntimeError, type BrowserLike, type RunContext } from "../engine/types"; +import { getHandler } from "@rpa/core"; +import { RuntimeError, type BrowserLike, type RunContext } from "@rpa/core"; import "./browser-extended"; const EXTENDED_IDS = [ diff --git a/src/main/capabilities/browser-extended.ts b/src/main/capabilities/browser-extended.ts index 9e78d93..345a3af 100644 --- a/src/main/capabilities/browser-extended.ts +++ b/src/main/capabilities/browser-extended.ts @@ -1,6 +1,6 @@ import { browserSession } from "../browser/session"; -import { register } from "../engine/registry"; -import { RuntimeError, type BrowserLike, type RunContext } from "../engine/types"; +import { register } from "@rpa/core"; +import { RuntimeError, type BrowserLike, type RunContext } from "@rpa/core"; const CLICK_IDS = ["Element_Click_V1", "Element_Click_V2", "Element_Click_V4", "Element_Click_V5"]; const TEXT_INPUT_IDS = ["Element_SetValue_V1", "Element_SetValue_V2", "Element_SetValue_V3", "Element_SetValue_V5"]; diff --git a/src/main/capabilities/browser.test.ts b/src/main/capabilities/browser.test.ts index 639effb..7157f97 100644 --- a/src/main/capabilities/browser.test.ts +++ b/src/main/capabilities/browser.test.ts @@ -1,7 +1,7 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; import type { CatalogComponent, FlowNode } from "../../shared/types"; -import { getHandler } from "../engine/registry"; -import { RuntimeError, type BrowserLike, type RunContext } from "../engine/types"; +import { getHandler } from "@rpa/core"; +import { RuntimeError, type BrowserLike, type RunContext } from "@rpa/core"; import "./browser"; const component = {} as CatalogComponent; diff --git a/src/main/capabilities/browser.ts b/src/main/capabilities/browser.ts index 173ccc3..796de5a 100644 --- a/src/main/capabilities/browser.ts +++ b/src/main/capabilities/browser.ts @@ -1,7 +1,7 @@ -import { register } from "../engine/registry"; -import { RuntimeError } from "../engine/types"; +import { register } from "@rpa/core"; +import { RuntimeError } from "@rpa/core"; import { browserSession, externalBrowserSession } from "../browser/session"; -import type { BrowserLike, RunContext } from "../engine/types"; +import type { BrowserLike, RunContext } from "@rpa/core"; async function session(ctx: RunContext): Promise { if (!ctx.browser) ctx.browser = await browserSession(); diff --git a/src/main/capabilities/capability-audit.test.ts b/src/main/capabilities/capability-audit.test.ts index 53c6a22..8288e17 100644 --- a/src/main/capabilities/capability-audit.test.ts +++ b/src/main/capabilities/capability-audit.test.ts @@ -1,7 +1,7 @@ import { readFile } from "node:fs/promises"; import { describe, expect, it } from "vitest"; import type { Catalog } from "../../shared/types"; -import { hasCapability } from "../engine/registry"; +import { hasCapability } from "@rpa/core"; import "./index"; const planned = [ diff --git a/src/main/capabilities/catalog-properties.test.ts b/src/main/capabilities/catalog-properties.test.ts index ed2202e..3c2b94c 100644 --- a/src/main/capabilities/catalog-properties.test.ts +++ b/src/main/capabilities/catalog-properties.test.ts @@ -1,7 +1,7 @@ import type { Catalog, CatalogComponent, CatalogField } from "../../shared/types"; import { readFile } from "node:fs/promises"; import { describe, expect, it } from "vitest"; -import { hasCapability } from "../engine/registry"; +import { hasCapability } from "@rpa/core"; import "./index"; const widgets = new Set(["text","textarea","number","select","radio","boolean","file","folder","element","code","secret","region","hidden"]); diff --git a/src/main/capabilities/common-final.test.ts b/src/main/capabilities/common-final.test.ts index bdd29a5..993844e 100644 --- a/src/main/capabilities/common-final.test.ts +++ b/src/main/capabilities/common-final.test.ts @@ -5,9 +5,9 @@ import path from "node:path"; import { PDFDocument } from "pdf-lib"; import { afterEach, describe, expect, it } from "vitest"; import type { CatalogComponent, FlowNode } from "../../shared/types"; -import type { RunContext } from "../engine/types"; -import { getHandler } from "../engine/registry"; -import "./desktop"; import "./pdf"; import "./system-extended"; import "./window-extended"; import "./common-final"; +import type { RunContext } from "@rpa/core"; +import { getHandler } from "@rpa/core"; +import "@rpa/core/capabilities"; import "./window-extended"; const dirs: string[] = []; const context = { vars: {} } as RunContext; const component = {} as CatalogComponent; const node = (id: string): FlowNode => ({ id, componentId: id, position: { x: 0, y: 0 }, values: {}, options: {} }); diff --git a/src/main/capabilities/human-dialog.ts b/src/main/capabilities/human-dialog.ts index e1a7fc8..3dbbd6a 100644 --- a/src/main/capabilities/human-dialog.ts +++ b/src/main/capabilities/human-dialog.ts @@ -1,6 +1,6 @@ import { BrowserWindow } from "electron"; -import { register } from "../engine/registry"; -import { RuntimeError } from "../engine/types"; +import { register } from "@rpa/core"; +import { RuntimeError } from "@rpa/core"; interface FormFieldSpec { key?: string; name?: string; label?: string; type?: string; value?: string; options?: unknown[] } diff --git a/src/main/capabilities/index.ts b/src/main/capabilities/index.ts index ff63b65..7b96fa0 100644 --- a/src/main/capabilities/index.ts +++ b/src/main/capabilities/index.ts @@ -1,44 +1,21 @@ -import "./control"; -import "./files"; -import "./http"; -import "./data"; +/** + * 宿主能力注册入口。 + * + * 纯 Node 能力已迁入 @rpa/core(packages/rpa-core),第一行 import 拉起包内全部注册; + * 此处只保留依赖 Electron / 宿主模块的能力,阶段 2 通过 HostBridge 逐步迁入。 + * 导出顺序整体保持改造前 index.ts 的注册顺序(别名/重复 id last-wins 语义不变)。 + */ +import "@rpa/core/capabilities"; import "./browser"; import "./browser-extended"; import "./browser-dom"; import "./browser-common"; import "./browser-control"; -import "./office"; -import "./desktop"; -import "./desktop-uia"; import "./web-batch2"; import "./web-crawl"; import "./human-dialog"; -import "./time-caps"; -import "./windows-system"; -import "./ftp"; import "./ai-service"; import "./ai-caps"; -import "./ocr-caps"; -import "./pdf"; -import "./word"; -import "./word-extended"; -import "./message"; -import "./vision"; -import "./cv-vision"; -import "./extended"; -import "./system-extended"; -import "./office-file-extended"; -import "./office-aliases"; -import "./excel-common"; -import "./excel-com"; import "./window-extended"; -import "./data-extended"; -import "./utility-extended"; -import "./data-table-common"; -import "./basic-encryption"; -import "./mail-remaining"; -import "./remaining-core"; -import "./common-final"; - -export { capabilityCount, capabilityIds, getHandler, hasCapability, register } from "../engine/registry"; +export { capabilityCount, capabilityIds, getHandler, hasCapability, register } from "@rpa/core"; diff --git a/src/main/capabilities/mouse-moveto-smoke.test.ts b/src/main/capabilities/mouse-moveto-smoke.test.ts index 5716a0c..cd11077 100644 --- a/src/main/capabilities/mouse-moveto-smoke.test.ts +++ b/src/main/capabilities/mouse-moveto-smoke.test.ts @@ -2,8 +2,8 @@ import { execFile } from "node:child_process"; import { promisify } from "node:util"; import { afterEach, describe, expect, it } from "vitest"; import type { CatalogComponent, FlowNode } from "../../shared/types"; -import { getHandler } from "../engine/registry"; -import type { RunContext } from "../engine/types"; +import { getHandler } from "@rpa/core"; +import type { RunContext } from "@rpa/core"; import "./window-extended"; const run = promisify(execFile); diff --git a/src/main/capabilities/net-message-smoke.test.ts b/src/main/capabilities/net-message-smoke.test.ts index 1a2e7f5..301f746 100644 --- a/src/main/capabilities/net-message-smoke.test.ts +++ b/src/main/capabilities/net-message-smoke.test.ts @@ -1,12 +1,10 @@ import { createServer, type IncomingMessage, type ServerResponse, type Server } from "node:http"; import net from "node:net"; import { describe, expect, it } from "vitest"; -import { getHandler } from "../engine/registry"; +import { getHandler } from "@rpa/core"; import type { CatalogComponent, FlowNode } from "../../shared/types"; -import type { RunContext } from "../engine/types"; -import "./http"; -import "./message"; -import "./common-final"; +import type { RunContext } from "@rpa/core"; +import "@rpa/core/capabilities"; import "./ai-caps"; const ctx = { diff --git a/src/main/capabilities/remaining-completion.test.ts b/src/main/capabilities/remaining-completion.test.ts index 3a1599e..e1c1782 100644 --- a/src/main/capabilities/remaining-completion.test.ts +++ b/src/main/capabilities/remaining-completion.test.ts @@ -1,6 +1,6 @@ import { readFile } from "node:fs/promises"; import { describe, expect, it } from "vitest"; -import { capabilityCount, hasCapability } from "../engine/registry"; +import { capabilityCount, hasCapability } from "@rpa/core"; import "./index"; const selected = [ diff --git a/src/main/capabilities/web-batch2.ts b/src/main/capabilities/web-batch2.ts index 4bec738..6777d7f 100644 --- a/src/main/capabilities/web-batch2.ts +++ b/src/main/capabilities/web-batch2.ts @@ -1,6 +1,6 @@ import { browserSession } from "../browser/session"; -import { register } from "../engine/registry"; -import { RuntimeError, type BrowserLike, type BrowserTabInfo, type RunContext } from "../engine/types"; +import { register } from "@rpa/core"; +import { RuntimeError, type BrowserLike, type BrowserTabInfo, type RunContext } from "@rpa/core"; /** 优先使用流程中「打开网页」已建立的浏览器会话(含外部 Edge/Chrome),否则退回内置 */ async function currentSession(ctx: RunContext): Promise { diff --git a/src/main/capabilities/web-crawl.ts b/src/main/capabilities/web-crawl.ts index 18e8894..b6027f0 100644 --- a/src/main/capabilities/web-crawl.ts +++ b/src/main/capabilities/web-crawl.ts @@ -1,6 +1,6 @@ import { browserSession, externalBrowserSession } from "../browser/session"; -import { register } from "../engine/registry"; -import { RuntimeError, type BrowserLike, type RunContext } from "../engine/types"; +import { register } from "@rpa/core"; +import { RuntimeError, type BrowserLike, type RunContext } from "@rpa/core"; /** * 采集/监听组件的浏览器会话解析: diff --git a/src/main/capabilities/web-real-smoke.test.ts b/src/main/capabilities/web-real-smoke.test.ts index e923c0f..6277593 100644 --- a/src/main/capabilities/web-real-smoke.test.ts +++ b/src/main/capabilities/web-real-smoke.test.ts @@ -4,9 +4,9 @@ import { tmpdir } from "node:os"; import path from "node:path"; import { afterAll, beforeAll, describe, expect, it } from "vitest"; import type { CatalogComponent, FlowNode } from "../../shared/types"; -import { getHandler } from "../engine/registry"; +import { getHandler } from "@rpa/core"; import { externalBrowserSession } from "../browser/session"; -import type { BrowserLike, RunContext } from "../engine/types"; +import type { BrowserLike, RunContext } from "@rpa/core"; import "./browser"; import "./browser-common"; import "./browser-control"; diff --git a/src/main/capabilities/window-extended.test.ts b/src/main/capabilities/window-extended.test.ts index f50411a..344c8d6 100644 --- a/src/main/capabilities/window-extended.test.ts +++ b/src/main/capabilities/window-extended.test.ts @@ -1,7 +1,7 @@ import { describe, expect, it } from "vitest"; import type { CatalogComponent, FlowNode } from "../../shared/types"; -import type { RunContext } from "../engine/types"; -import { getHandler } from "../engine/registry"; +import type { RunContext } from "@rpa/core"; +import { getHandler } from "@rpa/core"; import "./window-extended"; const context = {} as RunContext; diff --git a/src/main/capabilities/window-extended.ts b/src/main/capabilities/window-extended.ts index 2e3ff9b..d503a12 100644 --- a/src/main/capabilities/window-extended.ts +++ b/src/main/capabilities/window-extended.ts @@ -1,6 +1,6 @@ -import { register } from "../engine/registry"; -import { RuntimeError, type CapabilityHandler } from "../engine/types"; -import { powershell, psString } from "./desktop"; +import { register } from "@rpa/core"; +import { RuntimeError, type CapabilityHandler } from "@rpa/core"; +import { powershell, psString } from "@rpa/core"; import { screen } from "electron"; const WINDOW_API = `Add-Type @' diff --git a/src/main/desktop-pick.ts b/src/main/desktop-pick.ts index fc0c0c7..67b8a8a 100644 --- a/src/main/desktop-pick.ts +++ b/src/main/desktop-pick.ts @@ -4,7 +4,7 @@ import fs from "node:fs"; import path from "node:path"; import { app, BrowserWindow, desktopCapturer, globalShortcut, screen } from "electron"; -import { RuntimeError } from "./engine/types"; +import { RuntimeError } from "@rpa/core"; import { detectUiElements, localUiModelPath } from "./local-vision/ui-detect-service"; import { assignPaneOcr, recognizePane } from "./local-vision/pane-ocr-service"; diff --git a/src/main/index.ts b/src/main/index.ts index 719441a..7cdcc42 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -11,7 +11,7 @@ import { import "./capabilities"; import { catalogPath, loadCatalog } from "./catalog"; import { createDemoFlow, createExampleFlows, createFlow, deleteFlow, getFlow, listFlows, saveFlow } from "./flows"; -import { capabilityCount, capabilityIds } from "./engine/registry"; +import { capabilityCount, capabilityIds, setSubflowSource } from "@rpa/core"; import { closeBrowserSession, setMainWindowGetter, startRun, stopRun } from "./run/manager"; import { registerOverlayIpc } from "./overlay"; import { fixtureUrl, startFixtureServer, stopFixtureServer } from "./fixture/server"; @@ -21,6 +21,9 @@ import { pickDesktopElement, listVisibleWindows, pickScreenRegion } from "./desk import { detectVisionLabTarget, listVisionLabSources } from "./vision-lab"; import { logMain } from "./logger"; +// 子流程仓库在宿主(flows.ts),包内能力经 host-bridge 取用(阶段 2 正式化 HostBridge) +setSubflowSource({ listFlows: async () => listFlows(), getFlow: async (id) => getFlow(id) }); + let mainWindow: BrowserWindow | null = null; if (process.env.RPA_ENABLE_GPU !== "1") app.disableHardwareAcceleration(); diff --git a/src/main/local-vision/ui-detect-service.ts b/src/main/local-vision/ui-detect-service.ts index 0a7495a..9a5b8a4 100644 --- a/src/main/local-vision/ui-detect-service.ts +++ b/src/main/local-vision/ui-detect-service.ts @@ -2,7 +2,7 @@ import fs from "node:fs"; import path from "node:path"; import { Worker } from "node:worker_threads"; import { app } from "electron"; -import { RuntimeError } from "../engine/types"; +import { RuntimeError } from "@rpa/core"; import type { LocalUiBox } from "./ui-detect-worker"; export interface UiDetectOptions { diff --git a/src/main/run/manager.ts b/src/main/run/manager.ts index 29ac82f..a74757b 100644 --- a/src/main/run/manager.ts +++ b/src/main/run/manager.ts @@ -4,7 +4,7 @@ import fs from "node:fs"; import path from "node:path"; import type { FlowDefinition, RunEvent } from "../../shared/types"; import { loadCatalog } from "../catalog"; -import { runFlow } from "../engine/runtime"; +import { runFlow } from "@rpa/core"; import { BrowserSession } from "../browser/session"; const active = new Map(); diff --git a/src/main/vision-lab.ts b/src/main/vision-lab.ts index 819a731..3bf3caf 100644 --- a/src/main/vision-lab.ts +++ b/src/main/vision-lab.ts @@ -1,7 +1,7 @@ import { desktopCapturer } from "electron"; import path from "node:path"; import type { VisionLabDetectRequest, VisionLabDetection, VisionLabSource } from "../shared/types"; -import { RuntimeError } from "./engine/types"; +import { RuntimeError } from "@rpa/core"; import { defaultUiModelPath, detectUiElements } from "./local-vision/ui-detect-service"; function sourceKind(sourceId: string): "window" | "screen" { diff --git a/src/shared/types.ts b/src/shared/types.ts index f87cd5d..0c0fdda 100644 --- a/src/shared/types.ts +++ b/src/shared/types.ts @@ -1,151 +1,27 @@ -export type CatalogWidget = - | "text" - | "textarea" - | "number" - | "select" - | "radio" - | "boolean" - | "file" - | "folder" - | "element" - | "code" - | "secret" - | "region" - | "hidden"; +/** + * 共享类型:宿主专属模型定义 + 领域类型 re-export。 + * + * 领域类型(Catalog/Flow/RunError/RunEvent 等)已迁入 @rpa/core(packages/rpa-core/src/types.ts), + * 此处 type-only re-export 保持既有 import 路径(@shared/types)不变,全仓单一来源、无复制。 + */ -export interface CatalogField { - key: string; - label: string; - widget: CatalogWidget; - type: "string" | "number" | "boolean" | "object"; - displayType: string; - required: boolean; - defaultValue: string; - placeholder: string; - description: string; - advanced: boolean; - valueTypes: string[]; - /** 下拉/单选选项:字符串(显示=存储值)或 { label, value }(显示与存储分离) */ - options?: Array; - unit?: string; -} +export type { + CatalogWidget, + CatalogField, + CatalogOutput, + CatalogComponent, + CatalogGroup, + Catalog, + FlowVariable, + FlowNodeOptions, + FlowNode, + FlowEdge, + FlowDefinition, + RunError, + RunEvent +} from "@rpa/core"; -export interface CatalogOutput { - label: string; - key: string; - suggestedName: string; - valueTypes: string[]; - fields: Array<{ key: string; label: string; defaultValue: string; valueTypes: string[] }>; -} - -export interface CatalogComponent { - id: string; - name: string; - kind: "vendor" | "native" | "trigger"; - group: string; - categories: string[]; - categorySignature: string; - description: string; - messageTemplate: string; - baseType: string; - functionName: string; - functionCalls: Array<{ function: string; args: string[]; assignTo: string }>; - version: string; - tags: string[]; - platformTag: string | null; - icon: string; - risk: "low" | "high"; - fields: CatalogField[]; - output: CatalogOutput; - slots: string[]; - nodeKind?: string; - /** 同名旧版本 / 重复别名指向的保留能力 ID。 */ - duplicateOf?: string; -} - -export interface CatalogGroup { - id: string; - label: string; - icon: string; - count: number; -} - -export interface Catalog { - schemaVersion: number; - generatedAt: string; - counts: { - total: number; - vendor: number; - native: number; - triggers: number; - fields: number; - }; - groups: CatalogGroup[]; - components: CatalogComponent[]; -} - -export interface FlowVariable { - name: string; - type: string; - defaultValue?: string; - description?: string; - scope?: "flow" | "local"; -} - -export interface FlowNodeOptions { - outputVar?: string; - delayBeforeMs?: number; - delayAfterMs?: number; - timeoutMs?: number; - retryCount?: number; - retryIntervalMs?: number; - skipOnError?: boolean; - logException?: boolean; - errorRouteEnabled?: boolean; -} - -export interface FlowNode { - id: string; - componentId: string; - label?: string; - position: { x: number; y: number }; - values: Record; - options: FlowNodeOptions; - parentId?: string | null; - slot?: string; - enabled?: boolean; - width?: number; - height?: number; -} - -export interface FlowEdge { - id: string; - source: string; - target: string; - sourceHandle?: string | null; - targetHandle?: string | null; - label?: string; -} - -export interface FlowDefinition { - schemaVersion: 1; - id: string; - name: string; - description?: string; - enabled?: boolean; - trigger?: { - type: "manual" | "schedule" | "file"; - label: string; - }; - variables: FlowVariable[]; - nodes: FlowNode[]; - edges: FlowEdge[]; - meta: { - createdAt: string; - updatedAt: string; - appVersion: string; - }; -} +import type { FlowDefinition, RunError } from "@rpa/core"; export interface FlowSaveOptions { /** 编辑器加载任务时磁盘上的 updatedAt,用于外部修改冲突检测 */ @@ -220,38 +96,6 @@ export interface RunNodeState { attempt?: number; } -export interface RunError { - code: string; - reason: string; - recommendation?: string; - location?: { flowId?: string; nodeId?: string; componentId?: string; arg?: string }; - detail?: string; -} - -export interface RunEvent { - type: - | "run.started" - | "node.started" - | "node.log" - | "node.finished" - | "run.finished" - | "run.total"; - runId: string; - nodeId?: string; - level?: "info" | "warn" | "error"; - message?: string; - status?: string; - output?: unknown; - error?: RunError; - durationMs?: number; - evidence?: string[]; - attempt?: number; - startedAt?: string; - nodeLabel?: string; - total?: number; -} - - export interface VisionLabSource { id: string; kind: "window" | "screen"; diff --git a/tsconfig.json b/tsconfig.json index d4e4201..3f434f6 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -13,10 +13,18 @@ "baseUrl": ".", "paths": { "@shared/*": ["src/shared/*"], - "@renderer/*": ["src/renderer/src/*"] + "@renderer/*": ["src/renderer/src/*"], + "@rpa/core": ["packages/rpa-core/src/index.ts"], + "@rpa/core/capabilities": ["packages/rpa-core/src/capabilities/index.ts"] }, "types": ["node"] }, - "include": ["src/**/*.ts", "src/**/*.tsx", "electron.vite.config.ts", "scripts/**/*.mjs"], + "include": [ + "src/**/*.ts", + "src/**/*.tsx", + "packages/rpa-core/src/**/*.ts", + "electron.vite.config.ts", + "scripts/**/*.mjs" + ], "exclude": ["node_modules", "out", "release"] } diff --git a/vitest.config.ts b/vitest.config.ts index aa3ba6b..0e9d3eb 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -1,6 +1,13 @@ +import { resolve } from "node:path"; import { defineConfig } from "vitest/config"; export default defineConfig({ + resolve: { + alias: [ + { find: /^@rpa\/core$/, replacement: resolve("packages/rpa-core/src/index.ts") }, + { find: /^@rpa\/core\/capabilities$/, replacement: resolve("packages/rpa-core/src/capabilities/index.ts") } + ] + }, test: { // 桌面自动化冒烟测试(键盘/鼠标/窗口焦点/剪贴板)共用同一物理桌面, // 并发执行会互相抢占焦点导致偶发失败,因此测试文件一律串行执行。