rpa-core-runtime 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (210) hide show
  1. rpa_core_runtime-0.1.0/.gitignore +15 -0
  2. rpa_core_runtime-0.1.0/.harness/PROGRESS.md +64 -0
  3. rpa_core_runtime-0.1.0/.harness/adr/0001-clean-room-rpa-core.md +28 -0
  4. rpa_core_runtime-0.1.0/.harness/adr/0002-effect-replay-contract.md +60 -0
  5. rpa_core_runtime-0.1.0/.harness/adr/0003-windows-desktop-driver.md +83 -0
  6. rpa_core_runtime-0.1.0/.harness/adr/0004-checkpoint-recovery.md +68 -0
  7. rpa_core_runtime-0.1.0/.harness/adr/0005-pause-continue.md +53 -0
  8. rpa_core_runtime-0.1.0/.harness/adr/0006-api-surface.md +83 -0
  9. rpa_core_runtime-0.1.0/.harness/adr/0007-devserver-capture.md +69 -0
  10. rpa_core_runtime-0.1.0/.harness/adr/0008-editor-ui.md +39 -0
  11. rpa_core_runtime-0.1.0/.harness/adr/0010-editor-host.md +40 -0
  12. rpa_core_runtime-0.1.0/.harness/architecture.md +53 -0
  13. rpa_core_runtime-0.1.0/.harness/feature_list.json +146 -0
  14. rpa_core_runtime-0.1.0/.harness/invariants.md +18 -0
  15. rpa_core_runtime-0.1.0/.harness/project_state.json +37 -0
  16. rpa_core_runtime-0.1.0/.harness/scripts/check_all.py +17 -0
  17. rpa_core_runtime-0.1.0/.harness/scripts/check_architecture.py +110 -0
  18. rpa_core_runtime-0.1.0/.harness/scripts/check_tasks.py +57 -0
  19. rpa_core_runtime-0.1.0/.harness/scripts/set_feature.py +20 -0
  20. rpa_core_runtime-0.1.0/.harness/tasks/BACKLOG.md +101 -0
  21. rpa_core_runtime-0.1.0/.harness/tasks/M1.1-runtime.md +52 -0
  22. rpa_core_runtime-0.1.0/.harness/tasks/M1.2-effects.md +50 -0
  23. rpa_core_runtime-0.1.0/.harness/tasks/M10-capture.md +49 -0
  24. rpa_core_runtime-0.1.0/.harness/tasks/M11-editor-tree.md +62 -0
  25. rpa_core_runtime-0.1.0/.harness/tasks/M12-editor-polish.md +49 -0
  26. rpa_core_runtime-0.1.0/.harness/tasks/M13-element-library.md +45 -0
  27. rpa_core_runtime-0.1.0/.harness/tasks/M13.1-flow-dir-assets.md +41 -0
  28. rpa_core_runtime-0.1.0/.harness/tasks/M14-extension.md +60 -0
  29. rpa_core_runtime-0.1.0/.harness/tasks/M14.5-cli-parity.md +43 -0
  30. rpa_core_runtime-0.1.0/.harness/tasks/M15-workbuddy-connector.md +56 -0
  31. rpa_core_runtime-0.1.0/.harness/tasks/M17-editor-advanced.md +35 -0
  32. rpa_core_runtime-0.1.0/.harness/tasks/M2-desktop.md +51 -0
  33. rpa_core_runtime-0.1.0/.harness/tasks/M2.1-element-importer.md +40 -0
  34. rpa_core_runtime-0.1.0/.harness/tasks/M2.2-uia-winforms.md +52 -0
  35. rpa_core_runtime-0.1.0/.harness/tasks/M3-recovery.md +52 -0
  36. rpa_core_runtime-0.1.0/.harness/tasks/M4-pause-resume.md +52 -0
  37. rpa_core_runtime-0.1.0/.harness/tasks/M4.5-data-commands.md +39 -0
  38. rpa_core_runtime-0.1.0/.harness/tasks/M5-api-decision.md +47 -0
  39. rpa_core_runtime-0.1.0/.harness/tasks/M6-api-usage.md +41 -0
  40. rpa_core_runtime-0.1.0/.harness/tasks/M7-command-surface.md +47 -0
  41. rpa_core_runtime-0.1.0/.harness/tasks/M8-devserver.md +54 -0
  42. rpa_core_runtime-0.1.0/.harness/tasks/M9-editor.md +47 -0
  43. rpa_core_runtime-0.1.0/.python-version +1 -0
  44. rpa_core_runtime-0.1.0/AGENTS.md +46 -0
  45. rpa_core_runtime-0.1.0/PKG-INFO +213 -0
  46. rpa_core_runtime-0.1.0/README.md +202 -0
  47. rpa_core_runtime-0.1.0/WORKLOG.md +52 -0
  48. rpa_core_runtime-0.1.0/commands/browser/click.json +17 -0
  49. rpa_core_runtime-0.1.0/commands/browser/close.json +17 -0
  50. rpa_core_runtime-0.1.0/commands/browser/getText.json +17 -0
  51. rpa_core_runtime-0.1.0/commands/browser/input.json +17 -0
  52. rpa_core_runtime-0.1.0/commands/browser/launch.json +35 -0
  53. rpa_core_runtime-0.1.0/commands/browser/navigate.json +17 -0
  54. rpa_core_runtime-0.1.0/commands/browser/queryAll.json +17 -0
  55. rpa_core_runtime-0.1.0/commands/browser/waitFor.json +17 -0
  56. rpa_core_runtime-0.1.0/commands/data/format.json +30 -0
  57. rpa_core_runtime-0.1.0/commands/data/limit.json +33 -0
  58. rpa_core_runtime-0.1.0/commands/data/writeJson.json +17 -0
  59. rpa_core_runtime-0.1.0/commands/data/writeText.json +31 -0
  60. rpa_core_runtime-0.1.0/commands/desktop/attachWindow.json +17 -0
  61. rpa_core_runtime-0.1.0/commands/desktop/click.json +17 -0
  62. rpa_core_runtime-0.1.0/commands/desktop/closeSession.json +17 -0
  63. rpa_core_runtime-0.1.0/commands/desktop/findElement.json +17 -0
  64. rpa_core_runtime-0.1.0/commands/desktop/getText.json +17 -0
  65. rpa_core_runtime-0.1.0/commands/desktop/input.json +17 -0
  66. rpa_core_runtime-0.1.0/commands/desktop_win32/attachWindow.json +17 -0
  67. rpa_core_runtime-0.1.0/commands/desktop_win32/click.json +17 -0
  68. rpa_core_runtime-0.1.0/commands/desktop_win32/closeSession.json +17 -0
  69. rpa_core_runtime-0.1.0/commands/desktop_win32/findElement.json +17 -0
  70. rpa_core_runtime-0.1.0/commands/desktop_win32/getText.json +17 -0
  71. rpa_core_runtime-0.1.0/commands/desktop_win32/hotkey.json +17 -0
  72. rpa_core_runtime-0.1.0/commands/desktop_win32/input.json +17 -0
  73. rpa_core_runtime-0.1.0/commands/desktop_win32/menuSelect.json +17 -0
  74. rpa_core_runtime-0.1.0/docs/api-usage.md +117 -0
  75. rpa_core_runtime-0.1.0/docs/architecture-eli5.html +192 -0
  76. rpa_core_runtime-0.1.0/docs/capture-browserskill.md +82 -0
  77. rpa_core_runtime-0.1.0/docs/capture-transport.md +106 -0
  78. rpa_core_runtime-0.1.0/docs/desktop_backends.md +35 -0
  79. rpa_core_runtime-0.1.0/docs/devserver.md +148 -0
  80. rpa_core_runtime-0.1.0/docs/editor-design.md +205 -0
  81. rpa_core_runtime-0.1.0/docs/m2_1_legacy_element_inventory.md +30 -0
  82. rpa_core_runtime-0.1.0/docs/runtime_flow.html +498 -0
  83. rpa_core_runtime-0.1.0/docs/system_context.puml +66 -0
  84. rpa_core_runtime-0.1.0/examples/api-usage/run_workflow.py +60 -0
  85. rpa_core_runtime-0.1.0/examples/api-usage/workflow.json +34 -0
  86. rpa_core_runtime-0.1.0/examples/baidu-news-top10/workflow.json +81 -0
  87. rpa_core_runtime-0.1.0/examples/search-and-save/workflow-headed-demo.json +26 -0
  88. rpa_core_runtime-0.1.0/examples/search-and-save/workflow.json +26 -0
  89. rpa_core_runtime-0.1.0/examples/uia-desktop/workflow.json +184 -0
  90. rpa_core_runtime-0.1.0/examples/windows-desktop/README.md +58 -0
  91. rpa_core_runtime-0.1.0/examples/windows-desktop/fixture/README.md +3 -0
  92. rpa_core_runtime-0.1.0/examples/windows-desktop/fixture/app/MainForm.cs +64 -0
  93. rpa_core_runtime-0.1.0/examples/windows-desktop/fixture/app/Program.cs +16 -0
  94. rpa_core_runtime-0.1.0/examples/windows-desktop/fixture/app/README.md +4 -0
  95. rpa_core_runtime-0.1.0/examples/windows-desktop/fixture/app/RpaCore.DesktopFixtureApp.csproj +9 -0
  96. rpa_core_runtime-0.1.0/examples/windows-desktop/workflow.json +115 -0
  97. rpa_core_runtime-0.1.0/extension/README.md +25 -0
  98. rpa_core_runtime-0.1.0/extension/background.js +80 -0
  99. rpa_core_runtime-0.1.0/extension/content.js +107 -0
  100. rpa_core_runtime-0.1.0/extension/manifest.json +21 -0
  101. rpa_core_runtime-0.1.0/extension/popup.html +24 -0
  102. rpa_core_runtime-0.1.0/extension/popup.js +23 -0
  103. rpa_core_runtime-0.1.0/project_overview.html +333 -0
  104. rpa_core_runtime-0.1.0/pyproject.toml +45 -0
  105. rpa_core_runtime-0.1.0/src/rpa_core/__init__.py +3 -0
  106. rpa_core_runtime-0.1.0/src/rpa_core/bsk_client.py +126 -0
  107. rpa_core_runtime-0.1.0/src/rpa_core/capture/__init__.py +13 -0
  108. rpa_core_runtime-0.1.0/src/rpa_core/capture/browser.py +300 -0
  109. rpa_core_runtime-0.1.0/src/rpa_core/capture/browser_bsk.py +253 -0
  110. rpa_core_runtime-0.1.0/src/rpa_core/capture/desktop.py +107 -0
  111. rpa_core_runtime-0.1.0/src/rpa_core/capture/desktop_agent.py +656 -0
  112. rpa_core_runtime-0.1.0/src/rpa_core/capture/extension.py +55 -0
  113. rpa_core_runtime-0.1.0/src/rpa_core/capture/hybrid.py +92 -0
  114. rpa_core_runtime-0.1.0/src/rpa_core/catalog/__init__.py +3 -0
  115. rpa_core_runtime-0.1.0/src/rpa_core/catalog/loader.py +48 -0
  116. rpa_core_runtime-0.1.0/src/rpa_core/cli.py +381 -0
  117. rpa_core_runtime-0.1.0/src/rpa_core/compiler/__init__.py +4 -0
  118. rpa_core_runtime-0.1.0/src/rpa_core/compiler/compiler.py +125 -0
  119. rpa_core_runtime-0.1.0/src/rpa_core/compiler/plan.py +11 -0
  120. rpa_core_runtime-0.1.0/src/rpa_core/devserver/__init__.py +5 -0
  121. rpa_core_runtime-0.1.0/src/rpa_core/devserver/app.py +415 -0
  122. rpa_core_runtime-0.1.0/src/rpa_core/devserver/server.py +282 -0
  123. rpa_core_runtime-0.1.0/src/rpa_core/devserver/static/app.js +1773 -0
  124. rpa_core_runtime-0.1.0/src/rpa_core/devserver/static/i18n.js +120 -0
  125. rpa_core_runtime-0.1.0/src/rpa_core/devserver/static/icons.js +24 -0
  126. rpa_core_runtime-0.1.0/src/rpa_core/devserver/static/index.html +82 -0
  127. rpa_core_runtime-0.1.0/src/rpa_core/devserver/static/styles.css +145 -0
  128. rpa_core_runtime-0.1.0/src/rpa_core/devserver/store.py +126 -0
  129. rpa_core_runtime-0.1.0/src/rpa_core/executors/__init__.py +15 -0
  130. rpa_core_runtime-0.1.0/src/rpa_core/executors/base.py +15 -0
  131. rpa_core_runtime-0.1.0/src/rpa_core/executors/browser.py +429 -0
  132. rpa_core_runtime-0.1.0/src/rpa_core/executors/browser_bsk.py +98 -0
  133. rpa_core_runtime-0.1.0/src/rpa_core/executors/desktop.py +326 -0
  134. rpa_core_runtime-0.1.0/src/rpa_core/executors/desktop_win32.py +329 -0
  135. rpa_core_runtime-0.1.0/src/rpa_core/executors/python_worker.py +84 -0
  136. rpa_core_runtime-0.1.0/src/rpa_core/executors/registry.py +18 -0
  137. rpa_core_runtime-0.1.0/src/rpa_core/importer/__init__.py +13 -0
  138. rpa_core_runtime-0.1.0/src/rpa_core/importer/legacy_elements.py +240 -0
  139. rpa_core_runtime-0.1.0/src/rpa_core/model/__init__.py +15 -0
  140. rpa_core_runtime-0.1.0/src/rpa_core/model/capture.py +76 -0
  141. rpa_core_runtime-0.1.0/src/rpa_core/model/command.py +212 -0
  142. rpa_core_runtime-0.1.0/src/rpa_core/model/desktop.py +32 -0
  143. rpa_core_runtime-0.1.0/src/rpa_core/model/errors.py +36 -0
  144. rpa_core_runtime-0.1.0/src/rpa_core/model/runtime.py +37 -0
  145. rpa_core_runtime-0.1.0/src/rpa_core/model/workflow.py +82 -0
  146. rpa_core_runtime-0.1.0/src/rpa_core/runtime/__init__.py +3 -0
  147. rpa_core_runtime-0.1.0/src/rpa_core/runtime/checkpoint.py +91 -0
  148. rpa_core_runtime-0.1.0/src/rpa_core/runtime/events.py +54 -0
  149. rpa_core_runtime-0.1.0/src/rpa_core/runtime/orchestrator.py +787 -0
  150. rpa_core_runtime-0.1.0/src/rpa_core/runtime/resolver.py +54 -0
  151. rpa_core_runtime-0.1.0/src/rpa_core/workers/__init__.py +1 -0
  152. rpa_core_runtime-0.1.0/src/rpa_core/workers/python_worker.py +128 -0
  153. rpa_core_runtime-0.1.0/test.txt +1 -0
  154. rpa_core_runtime-0.1.0/testapps/desktop/Program.cs +152 -0
  155. rpa_core_runtime-0.1.0/tests/__init__.py +0 -0
  156. rpa_core_runtime-0.1.0/tests/contract/test_browser_bsk_executor.py +258 -0
  157. rpa_core_runtime-0.1.0/tests/contract/test_browser_contract.py +26 -0
  158. rpa_core_runtime-0.1.0/tests/contract/test_capture_bsk_contract.py +250 -0
  159. rpa_core_runtime-0.1.0/tests/contract/test_capture_contract.py +377 -0
  160. rpa_core_runtime-0.1.0/tests/contract/test_capture_extension.py +195 -0
  161. rpa_core_runtime-0.1.0/tests/contract/test_capture_hybrid.py +211 -0
  162. rpa_core_runtime-0.1.0/tests/contract/test_cli_parity.py +204 -0
  163. rpa_core_runtime-0.1.0/tests/contract/test_desktop_contract.py +174 -0
  164. rpa_core_runtime-0.1.0/tests/contract/test_devserver.py +273 -0
  165. rpa_core_runtime-0.1.0/tests/contract/test_editor_i18n.py +56 -0
  166. rpa_core_runtime-0.1.0/tests/contract/test_public_api.py +64 -0
  167. rpa_core_runtime-0.1.0/tests/contract/test_python_worker.py +159 -0
  168. rpa_core_runtime-0.1.0/tests/contract/test_python_worker_cancellation.py +63 -0
  169. rpa_core_runtime-0.1.0/tests/contract/test_workbuddy_connector.py +70 -0
  170. rpa_core_runtime-0.1.0/tests/e2e/test_capture.py +233 -0
  171. rpa_core_runtime-0.1.0/tests/e2e/test_editor.py +428 -0
  172. rpa_core_runtime-0.1.0/tests/e2e/test_editor_element_edit.py +147 -0
  173. rpa_core_runtime-0.1.0/tests/e2e/test_search_and_save.py +90 -0
  174. rpa_core_runtime-0.1.0/tests/e2e/test_uia_desktop.py +152 -0
  175. rpa_core_runtime-0.1.0/tests/e2e/test_windows_desktop.py +71 -0
  176. rpa_core_runtime-0.1.0/tests/fixtures/legacy-elements/elements.json +29 -0
  177. rpa_core_runtime-0.1.0/tests/unit/test_cancellation.py +66 -0
  178. rpa_core_runtime-0.1.0/tests/unit/test_checkpoint_recovery.py +343 -0
  179. rpa_core_runtime-0.1.0/tests/unit/test_desktop_hover_drill.py +83 -0
  180. rpa_core_runtime-0.1.0/tests/unit/test_devserver_store.py +95 -0
  181. rpa_core_runtime-0.1.0/tests/unit/test_effect_contract.py +221 -0
  182. rpa_core_runtime-0.1.0/tests/unit/test_legacy_element_importer.py +58 -0
  183. rpa_core_runtime-0.1.0/tests/unit/test_orchestrator_guards.py +134 -0
  184. rpa_core_runtime-0.1.0/tests/unit/test_pause.py +275 -0
  185. rpa_core_runtime-0.1.0/tests/unit/test_protocols.py +74 -0
  186. rpa_core_runtime-0.1.0/tests/unit/test_resolver.py +34 -0
  187. rpa_core_runtime-0.1.0/tests/unit/test_runtime.py +62 -0
  188. rpa_core_runtime-0.1.0/tests/unit/test_runtime_correctness.py +281 -0
  189. rpa_core_runtime-0.1.0/testsite/index.html +47 -0
  190. rpa_core_runtime-0.1.0/uv.lock +549 -0
  191. rpa_core_runtime-0.1.0/workbuddy-connector/cli.json +27 -0
  192. rpa_core_runtime-0.1.0/workbuddy-connector/connector-meta.json +22 -0
  193. rpa_core_runtime-0.1.0/workbuddy-connector/icon.svg +8 -0
  194. rpa_core_runtime-0.1.0/workbuddy-connector/skills/rpa-automation/SKILL.md +75 -0
  195. rpa_core_runtime-0.1.0/workbuddy-connector/skills/rpa-automation/references/commands-reference.md +53 -0
  196. rpa_core_runtime-0.1.0/workbuddy-connector/skills/rpa-automation/references/error-codes.md +33 -0
  197. rpa_core_runtime-0.1.0/workbuddy-connector/skills/rpa-automation/references/workflow-format.md +38 -0
  198. rpa_core_runtime-0.1.0/workbuddy-connector.zip +0 -0
  199. rpa_core_runtime-0.1.0/workflows/.capture-extension-token +1 -0
  200. rpa_core_runtime-0.1.0/workflows/.gitkeep +0 -0
  201. rpa_core_runtime-0.1.0/workflows/demo/elements/bingSearchBox.json +26 -0
  202. rpa_core_runtime-0.1.0/workflows/demo/elements/extFirst.json +23 -0
  203. rpa_core_runtime-0.1.0/workflows/demo/elements/extSecond.json +25 -0
  204. rpa_core_runtime-0.1.0/workflows/demo/elements/hybridExt3.json +23 -0
  205. rpa_core_runtime-0.1.0/workflows/demo/elements/hybridTest.json +20 -0
  206. rpa_core_runtime-0.1.0/workflows/demo/elements/hybridWeb.json +22 -0
  207. rpa_core_runtime-0.1.0/workflows/demo/elements/hybridWeb2.json +21 -0
  208. rpa_core_runtime-0.1.0/workflows/demo/elements/hybridWeb3.json +22 -0
  209. rpa_core_runtime-0.1.0/workflows/demo/elements/uiaFallback.json +20 -0
  210. rpa_core_runtime-0.1.0/workflows/demo/elements/xhsElement.json +23 -0
@@ -0,0 +1,15 @@
1
+ .venv/
2
+ __pycache__/
3
+ *.py[cod]
4
+ .pytest_cache/
5
+ .ruff_cache/
6
+ dist/
7
+ build/
8
+ run_artifacts/
9
+ examples/api-usage/artifacts/
10
+ playwright-report/
11
+ test-results/
12
+ .DS_Store
13
+
14
+ _tmp_*/
15
+ /elements/
@@ -0,0 +1,64 @@
1
+ # Progress
2
+
3
+ Format: `YYYY-MM-DD | feature | status | evidence`
4
+
5
+ 2026-08-28 | project-harness | done | architecture/invariant docs + full mechanical gate
6
+ 2026-08-28 | protocol-models | done | typed workflow, command, result, error, event, and run models
7
+ 2026-08-28 | catalog-compiler | done | immutable 9-command catalog with digest and static reference/capability checks
8
+ 2026-08-28 | orchestrator | done | timeout/retry/cancel/event/terminal-result ownership verified
9
+ 2026-08-28 | browser-playwright | done | explicit UUID browser session and real Chromium contract verified
10
+ 2026-08-28 | python-worker | done | subprocess JSON worker with workspace containment and UTF-8 path regression
11
+ 2026-08-28 | vertical-slice | done | deterministic search-and-save CLI and Chromium E2E passed
12
+ 2026-08-28 | orchestrator-hardening | done | lexical catch scope, async run evidence I/O, bounded foreach, explicit result guards, workflow timeout; 11 tests + full gate passed
13
+ 2026-08-28 | resolver-contract | done | whole-token references, fail-fast malformed references, mapping-only paths, condition tests, and nested compiler scope propagation; 15 tests + full gate passed
14
+ 2026-08-28 | runtime-correctness | done | stable errors/context, timeout and subprocess cleanup, bounded retry/deadline, persistence failure semantics; 24 tests + full gate passed
15
+ 2026-08-28 | effect-contract | done | typed effect/replay/idempotency policy, unsafe retry rejection, committed and unknown evidence, browser/worker E2E; 30 tests + full gate passed
16
+ 2026-08-31 | M2-desktop | active | 新增 desktop.win32 独立后端与记事本 Win32 垂直切片,桌面 locator 扩展 backend/className/controlId/foundIndex/menuPath,Win32 记事本 E2E 与合同测试已通过;UIA 主线保留待后续 WinForms 验证
17
+ 2026-08-31 | M2.1-legacy-element-importer | done | 旧元素静态盘点文档、LegacyElementImporter、provenance/diagnostic 模型与确定性导入测试已补齐;导入器仅处理静态数据,不触及 rpa_script runtime
18
+ 2026-09-01 | M3-checkpoint-recovery | done | ADR 0004 状态机契约、版本化原子 checkpoint + 路径键完成集合、resume(plan, run_id) 恢复门槛、indeterminate/recovery_required 终态与人工恢复入口(含 CLI resume)、7 项崩溃注入测试;48 tests + full gate passed
19
+ 2026-09-01 | M4-pause-resume | done | ADR 0005 暂停契约(action 入口 + attempt 前生效、取消>暂停>超时)、RunStatus.PAUSED 驻留状态、pauseRequested/runPaused 事件、resume 复用 M3 五道门、规则 8 修订;7 项边界测试;55 tests + full gate passed
20
+ 2026-09-01 | M2.2-uia-winforms | done | WinForms 测试应用全链路 UIA E2E(输入/提交/读回 + 对话框双 session,3 连跑一致)、timeoutMs 轮询与 EnumWindows 兜底修复 owned 弹窗枚举盲区、manifest 对称合同测试、docs/desktop_backends.md;60 tests + full gate passed
21
+ 2026-09-01 | baidu-news-example | added | 真实站点示例 examples/baidu-news-top10(百度搜索"新闻"保存首页结果标题到 run_artifacts/baidu-top10.txt);browser.launch 扩展 userAgent 参数并移除 automation 标志(headless 被百度安全验证拦截,headed + 正常 UA 放行);python worker 修复相对 path 按 workspace 解析(补越界拒绝测试);61 tests + full gate passed
22
+ 2026-09-01 | M4.5-data-commands | done | data.writeText(text/lines 二选一,workspace 包含校验,UTF-8)与 data.limit(前 N 条截断,pure/safe)入册,catalog 25 条;百度示例升级为纯文本产物(limit 10 + 按行输出);65 tests + full gate passed
23
+ 2026-09-01 | M5-api-decision | done | ADR 0006:进程内 Python API 冻结为 v1(不建 facade)、HTTP 推迟并附重估条件、排除清单结论、三个待定问题全部结案;公开签名契约测试 4 项;工作区分批提交完成(M3+M4 / M2.2 / baidu / harness / M4.5);69 tests + full gate passed
24
+ 2026-09-01 | M6-api-usage | done | docs/api-usage.md(四步模式、状态机消费指引、恢复/暂停语义)+ examples/api-usage 可运行示例(run → 读证据 → pause → resume 实测)+ README 链接;70 tests + full gate passed
25
+ 2026-09-01 | M7-command-surface | done | win32 timeoutMs 对称(findElement 声明未实现一并修复)、data.format({name} 占位符 fail-fast)入册 catalog 26 条、UIA COM 繁忙轮询容错;S0 实验:Chrome 152 封锁默认 profile CDP 端口 → 捕获传输定为扩展为主/持久 profile 为辅(决策并入 ADR 0007);72 tests × 3 轮 + full gate passed
26
+ 2026-09-01 | capture-transport-scheme | added | 调研 Panerelay(chrome.debugger+Native Messaging→CDP 兼容端点)与 Playwright MCP(持久 profile 默认方案印证);实测 chrome://inspect 授权开关(9222 监听、/json/* 404、需显式 WebSocket URL);传输方案定稿 docs/capture-transport.md(持久 profile 主 + chrome://inspect/Panerelay/MCP 扩展/自研扩展降级链),S1 验证协议与 M8 计划更新
27
+ 2026-09-02 | M11-editor-tree | done | 维护者确认切片 1 拖拽体验后完成切片 2-5:控制节点属性表单(if/forEach/try/return)、多选+批量移动/删除(同列表连续性校验、容器连带确认)、Ctrl+C/V 子树复制粘贴(全树 id 重映射)、快照式撤销/重做(50 步上限)、选中集以节点身份重寻;93 tests + full gate passed
28
+ 2026-09-02 | M12-editor-polish | done | docs/editor-design.md 方案落地:i18n.js 展示层(26 命令中文名 + kind/effect/ops/字段/术语表)+ 防漂移合同门禁、命令面板两行卡片根除横向滚动条、画布节点卡片中文重构 + 分支标签中文、if 操作符中文下拉、页脚术语表、悬浮操作条;修复 413 未排空 body 的 RST 健壮性缺口;99 tests + full gate passed
29
+ 2026-09-02 | M10-capture | done | 桌面 UIA 窗口作用域 hit-test(免疫安全软件覆盖层)+ 浏览器 persistent/chrome-inspect-ws 双传输 + picker 注入与 selector 回验、ElementDescriptor 落库(/api/elements)、browser.launch userDataDir;真实 E2E ×2(浏览器合成点击 + 桌面执行器回验命中);修复 agent stdout 编码/注册表死锁/413 排空;105 tests + full gate passed
30
+ 2026-09-01 | M8-devserver | done | ADR 0007 定稿(devserver 隔离边界/捕获契约/两个待定问题结案)、rpa_core.devserver 骨架(catalog/compile/workflows CRUD + 捕获 501 占位,stdlib 零新依赖)、CLI devserver 子命令、架构检查新增 devserver 隔离断言、11 项合同测试;curl 全流程实测通过;full gate 83 tests 全绿;S1 验证移入 M10 计划单(M10 前置,需登录态 Chrome 人工协作)
31
+ 2026-09-01 | M9-editor | done | ADR 0008 放行编辑器 UI(零构建硬边界)、devserver/static/index.html 单页(命令面板 + 线性画布 + schema 表单 + 编译回显 + 打开/保存闭环)、GET / 唯一静态路由;Playwright Chromium E2E 全流程 3 连跑稳定 + 3 项合同测试;E2E 首跑即捕获并修复编译成功分支漏设 .ok class 缺陷;87 tests + full gate 全绿
32
+ 2026-09-01 | S1-verification | done | 用户日常 Edge 152 实测:DevToolsActivePort 文件读 WS URL(免 UI 交互)、/json/* 404 防扫描确认、connect_over_cdp 枚举真实标签页 + 新标签页操作(example.com picker 注入回验 + 百度搜索 URL 直达)+ 原生 CDP session;user-browser 子类型定案 chrome-inspect-ws 补录 ADR 0007 §4;遗留:开关持久性待重启确认、登录态断言顺延 M10b
33
+ 2026-09-01 | capture-extension-research | added | 复核调研 chrome-relay(Native Messaging 免弹窗、Python host 可行)与 Playwright MCP --extension(核实默认每连接批准 + profile 唯一 token 绕过 + 标签组隔离);修正"扩展=零弹窗"误判;降级链定稿:M10a 持久 profile → M10b chrome-inspect-ws(S1 通过)→ M10c 自研扩展(token 配对,立项不实装);Panerelay/MCP 传输降记录备查,capture-transport.md §2.3-§2.5/§3 与 ADR 0007 §4 已更新
34
+ 2026-09-01 | M9.1-editor-dnd | done | 编辑器拖拽:命令面板拖入画布任意位置插入(上/下半区落点指示)+ 画布节点拖拽排序,HTML5 DnD 零依赖;E2E 扩展拖入插入与重排断言 3 连跑稳定;87 tests + full gate 全绿
35
+ 2026-09-01 | M11-editor-tree | active | 结构化树形画布立项:范式决策(树形非 DAG、快照撤销 50 步、静态拆分 allowlist)、拖拽先行验证片为显式确认门;实现由独立 agent 按 M11 任务单执行
36
+ 2026-09-02 | M11-editor-tree | slice0+1 done | 切片 0(/static/{name} 硬编码 allowlist 路由 + 面板分组数据源)与切片 1(路径寻址树模型/全树唯一 id/禁止移入自身子树、递归缩进色带渲染、控制流分组、DnD v2 子树拖拽+空容器落点+48px 边缘自动滚动、schema default 构造)完成;静态文件拆分 index.html/app.js/styles.css;嵌套拖入保存读回 E2E ×3 稳定 + /static 合同测试 2 项;90 tests + full gate 全绿;**暂停等待维护者确认拖拽体验**
37
+ 2026-09-02 | plan-adjustment | done | 维护者决策:M13 编辑器元素库扩展为捕获→编辑→回验→保存三段式;chrome-inspect-ws 每次连接弹窗成本不可接受,M10c 自研捕获扩展提前为 M14 实装(token 配对免弹窗),chrome-inspect-ws 降为备选;混合 auto 捕获顺延 M15
38
+ 2026-09-02 | M13-element-library | done | 元素库面板+插入到节点+删除+结构校验(verify)+selector 捕获按钮;POST/DELETE/verify 端点与 do_DELETE handler;合同+3、E2E+2;110 tests + full gate passed
39
+ 2026-09-02 | M13.1-flow-dir-assets | done | 每流程一个目录(WorkflowDirStore <name>/workflow.json) + 元素资产 <name>/elements/*.json 入版本库;元素端点嵌套 /api/workflows/{name}/elements[/{el}[/verify]];capture pick saveAs 需 flow;DevServer 去 elements_root、CLI 去 --elements;前端元素库按当前流程(命名/打开即刷新);ADR 0007 §2 修订;contract/e2e flow 化 + store 单测;122 tests + full gate passed
40
+ 2026-09-02 | browserskill-spike | added | Tencent/BrowserSkill 调研 + S2 部分实测(Edge 152,bsk 0.1.11):selector 直通 click/fill/press/evaluate 全链路通过,evaluate 注入 picker + 合成点击 + 回验通过;发现 ControlOverlay 全屏遮罩拦截并以 elementsFromPoint 变体解出;record 语义 trace 无 selector 实证(范式不符);M14 调整为 bsk 单扩展路线,自研扩展降兜底;真实点选/小红书/iframe 验证待补;docs/capture-browserskill.md
41
+ 2026-09-03 | M14-bsk-capture | slice done | bsk CLI/daemon 0.1.11 安装 + Edge/Chrome 扩展连接确认;probe 验证 evaluate 注入 picker(elementsFromPoint 变体绕过 ControlOverlay)→ Ctrl+Click 手势(普通点击穿透)→ 轮询读回 → 回验命中;BrowserBskCaptureSession 实装(session start/stop 映射、取消强制 stop、runner 注入可测);devserver transport 白名单加 bsk + cli 工厂分发;合同测试 8 项 + transport 契约 1 项;实机验收:Edge 必应搜索框 Ctrl+Click 捕获 #sb_form_q 落库 workflows/demo/elements/bingSearchBox.json + 重新导航回验命中 1;131 tests + full gate passed
42
+ 2026-09-03 | editor-host-adr | done | ADR 0010:编辑器保持 web 页面,遮挡实证矩阵(bsk Agent Window 独立 / 窗口作用域 hit-test 免疫 / 仅裸屏幕兜底路径会遮挡);桌面客户端薄壳入 BACKLOG 远期(重估条件三条);M14 desktop 捕获分支补先 attach 目标窗口
43
+ 2026-09-03 | M14.5-cli-parity | done | CLI 通道对齐(ADR 0006 §6 落地):catalog(digest+清单与 load_catalog 同源)/ capture browser|desktop(一次性会话,bsk 默认 + Ctrl+Click 合成、desktop F9/point,save-as+flow 落库 flow 元素资产,cancel+close 强制)/ elements list|show|verify;元素校验下沉 model/capture.py(devserver 薄封装);cli_parity 合同 7 项;138 tests + full gate passed
44
+ 2026-09-03 | M14a-bsk-executor | done | browser.launch v1.1.0 新增 transport:bsk(+browserInstanceId,能力差异声明 CSS only/仅主 frame);executors/browser_bsk.py BskSession(运行期会话,session start/stop 映射、取消检查、close 强制 stop);抽能力层 bsk_client.py(devserver 捕获与执行器共用,协议单实现);executor 合同 10 项(launch/分发/click/input/getText/queryAll/waitFor 超时与取消/会话丢失映射/close 强制 stop);i18n 补 transport/browserInstanceId 中文标签;148 tests + full gate passed
45
+ 2026-09-03 | bsk-borrow-mode | done | 捕获用户已打开标签页:bsk tab list/borrow/return 链路 probe 实测(用户 7 个标签页枚举、借用进 Agent Window、evaluate 读回、归还原窗口原位置);BrowserBskCaptureSession 加 page_url 借用模式(子串匹配用户标签页 → picker 注入该页 --tab-id → close 先归还再 stop);bsk_client 补 tab_* 封装 + 数组载荷错误映射修复;devserver bsk transport 透传 pageUrl;合同 +3;151 tests + full gate passed
46
+ 2026-09-03 | desktop-hover-capture | done | 桌面 hover 捕获模式:悬浮高亮框(layered 顶层点击穿透窗口 + region 边框裁剪)随鼠标移动实时框选 UIA 命中元素,作用域取悬停元素根窗口(免疫覆盖层);F9 或 Ctrl+Click 捕获、Esc 取消;agent --hover / DesktopCaptureSession(hover) / devserver hover=true / CLI --hover 四通道一致;自检 probe 合成鼠标移动+F9 捕获 submitButton verifyCount=1;合同 +2;153 tests + full gate passed
47
+ 2026-09-03 | desktop-hover-fixes | done | hover 捕获实机反馈修复:region API 用 pywin32 不存在的 CreateRectRgn(改 gdi32 ctypes)导致悬浮框首移即崩且被静默吞掉;Ctrl+C 慢取消——desktop pick 长 timeout queue.get 在 Windows 吞键盘中断,改 0.5s 短切片轮询 + CLI KeyboardInterrupt 即时 cancel/close 返回 130;hover 捕获瞬间以当前点重命中取根窗口(防 hover last_root 滞后打偏);hover probe 合成移动+F9 复测通过;153 tests + full gate passed
48
+ 2026-09-03 | hover-fine-drill | done | hover 捕获细粒度:_drill_to_leaf 从 ElementFromPoint 向下钻取最深包含点叶子(面积最小、max_depth 12、max_children 200 防浏览器 Document 爆炸、children/rect 异常容错、同 handle 防环);细粒度 E2E 实证小 Label(controlType=Text automationId=nameLabel verifyCount=1);钻取纯逻辑单测 6 项(替身树);159 tests + full gate passed
49
+ 2026-09-03 | hover-blindspots | done | hover 捕获盲区修复:UIA 虚拟元素(无 win32 handle)钻取断链——XAML(Terminal 标签)/桌面 ListItem 由 win32 窗口链(WindowFromPoint→最深子窗口→GA_ROOT)定位根窗口 + 窗口作用域最小包含枚举兜底;_hover_hit 双通道取更细 rect;浏览器窗口类跳过窗口枚举(属 bsk 页内领域);Terminal 标签实测命中 HeaderTextBlock(rect 比整 tab 小 3 倍);浏览器 UI 区域(标签栏/工具栏)确认为 Chromium 设计不进 UIA(非缺陷);159 tests + full gate passed
50
+ 2026-09-03 | hover-perf-browser-ui | done | hover 性能+浏览器 UI:根因定位(Chrome UIA 树 handle 全 0,drill 同 handle 防环误杀第一层;窗口枚举改含点优先 DFS,DOM 宿主 Chrome_RenderWidgetHostHWND/RootWebArea 跳子树但 UI 骨架照走);浏览器 UI 骨架(TabStrip/Omnibox 地址栏/工具栏按钮)UIA 原生可达实证;DFS 节流 150ms(粗命中区域),帧率 avg 49ms→14ms、p95 81ms→41ms;_smallest_containing_wrapper/_describe_wrapper 旧全树枚举路径删除;159 tests + full gate passed
51
+ 2026-09-03 | hover-virtual-handle-fix | done | 桌面图标 hover 卡顿根因:虚拟元素 handle=None 被快路径整个跳过 → 每帧强制 Progman 全树 DFS(340ms/帧);修复为 handle 只用于根窗口定位、rect 不依赖 handle(ElementFromPoint 直接给细粒度 ListItem);hover_hit 图标区 340ms→12ms avg;full gate 159 tests passed
52
+ 2026-09-03 | hover-frame-pacing | done | hover 残留微卡修复:GDI region inner 句柄每帧泄漏补 DeleteObject;show_rect rect 未变时跳过重建+SetWindowPos;hit 节流 60ms→30ms、帧间隔 30ms→15ms(高亮跟随 16fps→~30fps);细粒度 hover probe 复测通过;full gate passed
53
+ 2026-09-03 | hover-sweep-skip-fix | done | 横扫漏框根因:图标间隙命中大背景 Pane 每帧触发 Progman 全树 DFS(300ms 卡顿帧=整图标滑过);改为 DFS 仅在快路径完全失败(rect=None)时兜底,粗容器 hover 期间直接框粗 rect(响应优先),捕获瞬间仍全量 DFS 保精度;Terminal 置顶时快路径实证可达 TextBlock/分裂 Image;合成横扫 5/5 图标全中;159 tests + full gate passed
54
+ 2026-09-03 | capture-latency-reuse | done | 捕获瞬间延迟优化:hover 循环缓存最后命中元素(last_leaf+last_rect+last_root),F9/Ctrl+Click 时鼠标仍在该 rect 内则直接 describe 复用,省一次 hit-test+DFS(桌面图标区 capture_with_retry 全量 DFS 500-1000ms → 复用后 68ms 实测);hover_hit 返回 4 元组带 leaf;全门禁 159 tests(记事本 E2E 门禁内又抖一次、单独重跑过,老毛病非本次引入)
55
+ 2026-09-03 | element-edit-confirm | done | 元素编辑确认切片:捕获后编辑对话框(改名/改 selector/metadata 只读/捕获时命中数展示/同名覆盖保护 confirm)→ 确认入库;元素库面板点元素名打开同一对话框编辑(改名=删旧存新);捕获会话 pick 后未 cancel 的资源泄漏修复;E2E +3(对话框打开保存/取消不覆盖/改名删旧);162 tests + full gate passed
56
+ 2026-09-03 | capture-extension-selfbuilt | done | 自研 content-script 捕获扩展实装(无缝场景:Chrome/Edge 各装一份、全页面 hover+Ctrl+Click、零逐次授权):extension/ MV3 零构建(manifest+content picker 复用已验证 elementsFromPoint 变体+background 短轮询+popup token 配对);devserver 三个端点(token 配对/pending/result)+ transport=extension + ExtensionCaptureSession(threading.Event,无子进程);不走 WS(stdlib 无 WS 服务端);CLI --transport extension;合同 7 项(配对/未配对 501/错 token 403/pending/result 回传/落库 flow/取消);169 tests + full gate passed;实机验收(装扩展+配对+跨浏览器捕获)待人工
57
+ 2026-09-03 | capture-extension-e2e | done | 自研扩展实机验收通过:Edge 装扩展+token 配对(一次)→ 小红书搜索框 Ctrl+Click 捕获落库;同一会话切 Chrome → 煎蛋导航条再捕获——跨浏览器/跨页无缝衔接、零弹窗;demo 流程元素资产新增 extFirst/extSecond;pending 会话正确撤防
58
+ 2026-09-03 | capture-ext-tofu-hover-cleanup | done | 扩展两个 UX 修复:(1) token 配对免手动——扩展自动生成 token + devserver TOFU 首次接触采纳持久化(workflows/.capture-extension-token),popup 改为只读展示/重新生成;合同测试同步 TOFU 语义(缺 token 403/首次采纳/错 token 403);(2) 鼠标离开网页红框残留——content.js 加 mouseleave/blur/scroll 时 hideBox;169 tests + full gate passed
59
+ 2026-09-03 | hybrid-capture | done | 混合捕获 auto(装了扩展网页走插件、没装走 UIA):desktop_agent --hybrid(浏览器内容区 Chrome_RenderWidgetHostHWND 抑制高亮+忽略捕获手势让位扩展);HybridCaptureSession 双通道先回传者胜(扩展回传→取消桌面 agent;桌面先回→正常返回);devserver desktop hover 在已配对扩展时自动升级 hybrid(可 hybrid:false 关闭);desktop pick 落库放开 kind==browser(混合会话扩展结果);合同 5 项(未配对不 hybrid/配对自动 hybrid+pending 可见/扩展先赢/桌面先赢/混合落库);174 tests + full gate passed
60
+ 2026-09-03 | hybrid-acceptance | done | 混合捕获实机验收:插件腿(网页正文 Ctrl+Click 捕获小红书 AI 搜索框 #search-input-ai verifyCount=1,kind=browser 带 url)+ UIA 腿(桌面图标/终端控件)+ 让位(正文区桌面红框让位页内红框)双通道通过;修复 stale-root bug(无 handle 虚拟元素的根窗口用 win32 链解析,metadata 不再陈旧);full gate 174 tests
61
+ 2026-09-03 | uia-web-fallback-disproven | done | 实测:没装扩展时 UIA 兜底捕获 Chrome 网页正文命中渲染层 Pane(Intermediate D3D Window),verifyCount=29 不唯一不可用——网页正文无可靠 UIA 退路,网页捕获只有扩展/bsk 两条正路;UIA 正确用途=桌面应用+浏览器 UI 骨架;结论记入 capture-transport.md §2.6 防翻案
62
+ 2026-09-03 | element-capture-entry | done | 元素库「+捕获」入口:面板头部按钮 → 网页(extension 无缝,默认)/ 桌面(hover,已配对自动 hybrid)二选菜单;captureIntoField 重构为通用 captureElement + captureBrowserElement/captureDesktopElement + _confirmAndSave 复用编辑确认对话框;E2E +1(菜单开合);full gate 175 tests(门禁内 uia/win32 桌面 E2E 各抖一次,单独重跑均过——环境敏感老毛病)
63
+ 2026-09-03 | M14-extension | done | M14 浏览器捕获收口:bsk 执行传输(M14a)+ 自研 content-script 扩展(无缝捕获主路线)+ 混合捕获(HybridCaptureSession 先回传者胜)+ 桌面 hover(细粒度钻取+性能+盲区)+ 元素编辑确认 + 「+捕获」入口 + 借用模式(用户已开页面)+ token TOFU 免配对;实机验收全过;175 tests;feature capture-extension 通过。active → M15 WorkBuddy 连接器
64
+ 2026-09-03 | M15-workbuddy-connector | done | WorkBuddy 连接器入驻(CLI+Skill):CLI 补 auth/status/unauth 三件套(无认证固定 ready + statusMatch 契约);workbuddy-connector/ 目录(connector-meta.json type:cli + cli.json runtime python + icon.svg + skills/rpa-automation/SKILL.md + references 三件套);CLI 入口统一 UTF-8(修 cp936 导致 statusMatch 解码失败);修真实部署缺口:commands/ 打进 wheel(hatch force-include)+ 包内优先解析;合同 6 项 + 检查清单脚本化全过 + 干净 venv 本地路径安装验证;181 tests + full gate passed
@@ -0,0 +1,28 @@
1
+ # ADR 0001: Clean-room executor-oriented RPA core
2
+
3
+ - Status: accepted
4
+ - Date: 2026-08-27
5
+
6
+ ## Context
7
+
8
+ The sibling `rpa_script` project proves browser and Windows automation behavior but combines workflow control flow, dynamic command registration, runtime routing, browser sessions, database compatibility, and code generation in one system. Incremental replacement would require multiple old and new execution models to coexist.
9
+
10
+ ## Decision
11
+
12
+ Build a bounded architecture-validation project with:
13
+
14
+ - native workflow AST;
15
+ - command manifests as the single metadata source;
16
+ - static compilation to a catalog-pinned plan;
17
+ - an orchestrator that exclusively owns workflow state;
18
+ - explicit executors returning `CommandResult`;
19
+ - Playwright as the first browser driver;
20
+ - subprocess isolation for Python commands;
21
+ - append-only run events and terminal results;
22
+ - a lightweight mechanical harness.
23
+
24
+ The project does not import runtime code from `rpa_script`. It may use legacy data only as inert fixtures.
25
+
26
+ ## Consequences
27
+
28
+ The first version has less feature coverage but can validate the core contracts independently. UI, API, database, DSH, MCP, scheduling, installation, and multi-platform desktop drivers remain out of scope until the vertical slice passes its decision gate.
@@ -0,0 +1,60 @@
1
+ # ADR 0002:副作用、重放与幂等契约
2
+
3
+ - 状态:已接受
4
+ - 日期:2026-08-28
5
+
6
+ ## 背景
7
+
8
+ M1.1 已经实现有界自动重试,但仅使用 `manifest.retryable` 和 executor 返回的 `error.retryable` 判断。这个条件无法回答命令是否可能已经改变外部状态。浏览器点击、页面导航、文件写入和 session 生命周期都可能在“外部操作成功、结果尚未返回”时失败。如果 Runtime 仅凭错误类型重试,可能重复提交表单、重复触发服务端操作或破坏 session 状态。
9
+
10
+ ## 决策
11
+
12
+ 每个 stable command 必须声明一个 `effect` policy,包含三个独立维度:
13
+
14
+ - `kind`:`pure`、`read`、`idempotent-write`、`unsafe-write`、`session`。
15
+ - `replay`:`safe`、`idempotent`、`unsafe`。
16
+ - `idempotency`:`none`、`derived`、`required`。
17
+
18
+ 约束如下:
19
+
20
+ 1. 只有 `replay=safe` 或 `replay=idempotent` 的命令可以声明 `retryable=true`。
21
+ 2. `replay=idempotent` 时,`idempotency` 不能为 `none`。
22
+ 3. `unsafe-write` 和 `session` 在首版中必须使用 `replay=unsafe`,禁止自动重试。
23
+ 4. `pure` 和 `read` 使用 `replay=safe`。
24
+ 5. `idempotent-write` 使用 `replay=idempotent`,其幂等键必须由输入提供或从稳定资源标识派生。
25
+ 6. Compiler 拒绝 workflow 为 `replay=unsafe` 的 action 配置 `retry_count > 0`。
26
+ 7. Runtime 再次检查该约束,防止绕过 Compiler 的手工 plan 或未来兼容路径。
27
+
28
+ `CommandResult.effects` 改为类型化的 `EffectRecord[]`。每条记录至少包含:
29
+
30
+ - 确定性的 `effectId`;
31
+ - `kind`;
32
+ - 生命周期 `status`:`prepared`、`committed`、`failed`、`unknown`;
33
+ - `resource`;
34
+ - 可选 `idempotencyKey`;
35
+ - 可选诊断 `details`。
36
+
37
+ `effectId` 使用 `runId + stepId + attempt + effect index + kind + resource` 派生,保证同一次 attempt 内稳定、不同 attempt 之间不同。它是审计关联 ID,不是 exactly-once token。
38
+
39
+ 首版记录成功结果产生的 `committed` effect。失败发生在外部结果不确定的边界时,executor 后续应返回 `unknown` effect;本里程碑不实现恢复或自动补偿。
40
+
41
+ ## 命令分类
42
+
43
+ - `browser.launch`:`session / unsafe / none`
44
+ - `browser.navigate`:`unsafe-write / unsafe / none`
45
+ - `browser.click`:`unsafe-write / unsafe / none`
46
+ - `browser.input`:`unsafe-write / unsafe / none`
47
+ - `browser.waitFor`:`read / safe / none`
48
+ - `browser.getText`:`read / safe / none`
49
+ - `browser.queryAll`:`read / safe / none`
50
+ - `browser.close`:`session / unsafe / none`
51
+ - `data.writeJson`:`idempotent-write / idempotent / derived`,幂等键由规范化输出路径派生。
52
+
53
+ `browser.navigate` 不声明安全重放,因为导航目标可能通过 GET 或重定向触发服务端副作用。保守分类优先于未经证明的可重试性。
54
+
55
+ ## 后果
56
+
57
+ - 部分原本标记为 `retryable=true` 的命令会被改为不可自动重试。
58
+ - Read effect 也会持久化,因为它是实际执行证据,而不仅是 manifest 推导信息。
59
+ - Runtime 可以在持久化恢复实现前阻止最危险的重复副作用。
60
+ - 该契约不提供分布式事务、exactly-once、补偿或崩溃恢复保证。
@@ -0,0 +1,83 @@
1
+ # ADR 0003:Windows 桌面驱动采用 UI Automation 语义层
2
+
3
+ - 状态:已接受
4
+ - 日期:2026-08-28
5
+
6
+ ## 背景
7
+
8
+ 桌面自动化不存在一种同时覆盖所有 Windows 图形界面的通用技术:
9
+
10
+ - Win32 HWND/message 面向窗口句柄和标准控件协议,适合已知经典控件,但对 owner-draw、自绘区域、跨进程指针参数、UIPI 权限边界和现代 UI 框架能力有限。
11
+ - Microsoft UI Automation(UIA)面向可访问性语义树和 Control Pattern。经典 Win32 标准控件、WinForms、WPF 以及正确暴露 provider/AutomationPeer 的应用通常适合;自绘、虚拟化、DirectX/canvas、部分 Electron 自定义区域可能缺少稳定节点。
12
+ - 图像识别/OCR 面向最终像素,能覆盖无语义树界面和远程桌面画面,但受 DPI、缩放、主题、遮挡、压缩和焦点影响,动作通常需要坐标或真实输入,风险高于语义操作。
13
+ - Office 等复杂应用的业务对象通常更适合专用 Object Model/COM adapter,而不是把所有业务语义压进 UIA。
14
+
15
+ M2 的目的不是覆盖全部桌面应用,而是验证 rpa_core 的 executor 协议能承载第二类结构化驱动。
16
+
17
+ ## 技术验证
18
+
19
+ 在 Windows 10、Python 3.12.12、pywinauto 0.6.9 上验证了一个确定性 WinForms 测试程序:
20
+
21
+ - UIA 能枚举稳定的 `automationId`、`controlType` 和 `name`;
22
+ - `set_edit_text` 可以在不激活窗口的情况下写入标准 Edit;
23
+ - Invoke Pattern 可以在不移动鼠标的情况下触发 Button;
24
+ - Text 控件结果可以通过 UIA 回读。
25
+
26
+ ## 决策
27
+
28
+ M2 使用 `pywinauto` 的 `uia` backend 处理标准语义控件,同时补充 `win32` backend 处理经典窗口、菜单和模态对话框。
29
+
30
+ - 依赖仅在 `sys_platform == 'win32'` 时安装。
31
+ - 所有操作要求显式 `sessionId`,session 绑定 `processId + nativeWindowHandle`。
32
+ - Locator 分为两类:
33
+ - UIA: `automationId`、`controlType`、`name`
34
+ - Win32: `title`、`className`、`handle`、`controlId`、`menuPath`、`foundIndex`
35
+ - `desktop.attachWindow` / `desktop.win32.attachWindow` 要求显式 backend,匹配规则由 backend 决定。零匹配返回 `ELEMENT_NOT_FOUND`,多匹配返回 `AMBIGUOUS_MATCH`。
36
+ - `desktop.findElement` / `desktop.win32.findElement` 同样要求唯一匹配,并返回 session 内部的 `elementId`。Element reference 不得跨 session 使用。
37
+ - UIA 输入优先 Value Pattern/`set_edit_text`;点击优先 Invoke Pattern/`invoke`;Win32 菜单/对话框优先 `menu_select`、`click_input`、消息级方法。两条路径都不应该静默降级。
38
+ - UIA 操作由每个 executor 实例的单线程池串行执行,避免同一 session 的 COM/UIA 调用并发交错。
39
+ - asyncio task 取消不能强杀已经进入底层 COM 的线程。每次 UIA 查询使用底层 timeout;外层超时后 session 标记为丢失,后续操作返回 `SESSION_LOST`。本里程碑不宣称可以安全中止任意卡死的第三方 provider。
40
+ - `desktop.closeSession` 只释放 rpa_core session 和 element reference,不关闭目标应用。
41
+
42
+ ## 分层边界
43
+
44
+ 后续桌面能力按以下层次扩展:
45
+
46
+ 1. 应用专用 API/Object Model(当业务语义明显更强时);
47
+ 2. UIA 语义树;
48
+ 3. Win32 message 白名单 adapter;
49
+ 4. 图像/OCR 与坐标动作。
50
+
51
+ 禁止从 UIA 静默降级到坐标点击。降级必须由 workflow 明确选择不同 locator/driver,并在证据中记录实际使用层。
52
+
53
+ 图像库、截图 provenance、DPI/坐标系、置信度、模板版本和 OCR 结果属于后续独立里程碑,不进入 M2。
54
+
55
+ ## 适用边界
56
+
57
+ 适合 UIA 优先:
58
+
59
+ - 经典 Win32 标准控件;
60
+ - WinForms/WPF 标准控件;
61
+ - 正确暴露 accessibility tree 的 Electron/Chromium 桌面应用;
62
+ - 具有稳定 UIA provider 的企业桌面软件。
63
+
64
+ 需要专用 adapter 或视觉层:
65
+
66
+ - Office 文档、工作簿等业务对象;
67
+ - owner-draw、自绘 canvas、DirectX、游戏;
68
+ - 缺少 accessibility tree 的 Electron 自定义区域;
69
+ - RDP/Citrix 中只暴露远程画面的客户端窗口。
70
+
71
+ ## 参考资料
72
+
73
+ - Microsoft UI Automation Overview: https://learn.microsoft.com/en-us/windows/win32/winauto/uiauto-uiautomationoverview
74
+ - UI Automation Providers Overview: https://learn.microsoft.com/en-us/windows/win32/winauto/uiauto-providersoverview
75
+ - UI Automation Control Patterns: https://learn.microsoft.com/en-us/windows/win32/winauto/uiauto-controlpattern-ids
76
+ - pywinauto Getting Started: https://pywinauto.readthedocs.io/en/latest/getting_started.html
77
+ - Microsoft VDI automation limitations: https://learn.microsoft.com/en-us/troubleshoot/power-platform/power-automate/desktop-flows/cannot-record-in-vdi-environments
78
+
79
+ ## 后果
80
+
81
+ - M2 能覆盖一大类标准企业桌面应用和经典 Win32 菜单/对话框,但不承诺所有 Windows GUI 均可自动化。
82
+ - 图像识别/OCR 继续后置,避免在结构化驱动尚未稳定时引入元素图片库、坐标系和置信度模型。
83
+ - pywinauto/pywin32 是 Windows 专用依赖;跨平台稳定性由 manifest capability 和 executor registration 保证,而不是在非 Windows 上模拟桌面行为。
@@ -0,0 +1,68 @@
1
+ # ADR 0004:检查点持久化与恢复状态机
2
+
3
+ - 状态:已接受
4
+ - 日期:2026-09-01
5
+
6
+ ## 背景
7
+
8
+ M1.2 确立了副作用契约:每个命令声明 `effect.kind / replay / idempotency`,失败时 executor 返回 `unknown` effect 表示"外部结果不确定"。Runtime 此前不持久化执行进度:进程崩溃或运行失败后,只能从头重跑整个 workflow, unsafe-write 命令(browser.navigate、browser.click、desktop.click 等)会被无条件重复执行。
9
+
10
+ M3 需要在不引入 exactly-once、分布式调度或数据库的前提下,给出安全的节点边界检查点与恢复语义。本 ADR 修改 runtime 状态机契约:`RunStatus` 新增 `recovery_required` 与 `indeterminate` 两个终态取值。
11
+
12
+ ## 决策
13
+
14
+ ### 检查点内容与写入时机
15
+
16
+ checkpoint 为 `version = 1` 的 JSON 文档,写入 `run_dir/checkpoint.json`:
17
+
18
+ - `version`:格式版本,resume 时校验,非 `1` 视为损坏。
19
+ - `workflowId` / `catalogDigest`:resume 时必须与重新编译的 plan 一致。
20
+ - `completedSteps`:已持久完成的 action 的路径键(见下)。
21
+ - `scopes`:`inputs`、`steps`、`loop` 与 try 错误变量快照;resume 使用快照中的 inputs,不接受新 inputs。
22
+ - `returnValue`:仅当 workflow 已执行 `return` 后才是真实返回值;action 边界写 `null`。
23
+
24
+ 完成键使用节点路径而不是裸节点 id:`forEach` 的第 i 次迭代的子节点路径附加 `#i` 段(如 `loop/#0/step`)。这保证 foreach 恢复时按迭代跳过,而不是把后续迭代全部误判为已完成。
25
+
26
+ 写入时机:action 成功且输出校验通过后、`stepCompleted` 事件之前,先原子写 checkpoint(临时文件 + replace)。崩溃窗口语义:
27
+
28
+ - checkpoint 已写入、事件未写:resume 跳过该 step,事件证据缺失但执行最多一次。
29
+ - checkpoint 未写入:resume 重新执行该 step。对 `replay=safe` / `idempotent` 的命令这是契约允许的重放;对 `replay=unsafe` 的命令,重放风险由人工 resume 决定承担。
30
+
31
+ 写入失败(`CheckpointError`)不会静默继续:run 终态记为 `recovery_required`。终态证据(`runFinished` + `result.json`)持久化之后的最终 checkpoint 写入是 best-effort,失败不改变终态,只留下较旧的检查点(见后果)。
32
+
33
+ ### 状态机
34
+
35
+ `RunStatus` 终态语义扩展:
36
+
37
+ - `indeterminate`:某 step 失败且其结果携带 `status=unknown` 的 effect 记录,即外部写入结果未知。此时 runtime 绝不自动重试(即使 manifest 声明 `retryable=true`),也绝不判定成功;终态 `indeterminate`,错误载荷保留原始错误码与 unknown effect 证据。这是 M1.2"失败 + unknown effect 记为 failed"契约的修订。
38
+ - `recovery_required`:action 边界的 checkpoint 持久化失败。run 证据完整,但进度快照可能落后于实际副作用,恢复需要人工确认。
39
+ - `succeeded` / `failed` / `cancelled` / `abandoned`:语义不变。
40
+
41
+ ### Resume 前置检查
42
+
43
+ `resume(plan, run_id)` 依次校验,任何一步失败即拒绝,不产生新的 run 证据:
44
+
45
+ 1. checkpoint 存在且通过 `version=1` 结构校验(损坏、非对象、缺字段 → `CheckpointError`)。
46
+ 2. `workflowId` 与 plan 一致。
47
+ 3. `catalogDigest` 与 plan 一致(catalog 或 workflow 变更后旧检查点作废,必须重跑)。
48
+ 4. 读取 `result.json`:若上次终态为 `indeterminate` 且未显式传 `allow_indeterminate=True`,抛出 `RecoveryRequiredError`,要求人工确认后才能继续。`result.json` 缺失(真实崩溃场景)或损坏时不阻塞,checkpoint 是恢复进度的权威来源。
49
+
50
+ ### 恢复执行规则
51
+
52
+ - deadline 不持久化(monotonic 时间跨进程无意义);resume 以全新 `workflow.timeout_seconds` 预算执行。
53
+ - 执行从根节点重新走一遍:路径键在 `completedSteps` 中的 action 直接跳过,不产生命令调用与事件;其余节点正常执行,条件分支依据快照 scopes 重新求值。
54
+ - 失败的 run 可以 resume:未完成的 step(含失败的那个)会重新执行。对 unsafe-write 命令,这是人工决策的一部分。
55
+ - 浏览器与桌面 session 不跨进程存活:checkpoint 中的 `sessionId` 输出在 resume 后指向已死亡的 session,后续使用它的 step 会以 `SESSION_NOT_FOUND` / `SESSION_LOST` 失败。首版不为 session 做重建,workflow 需要重新 launch 或由人工介入。
56
+
57
+ ### 人工恢复入口
58
+
59
+ - `Orchestrator.resume(plan, run_id, allow_indeterminate=True)`:显式确认 unknown effect 后继续。
60
+ - CLI `resume <workflow> --run-id <id> [--allow-indeterminate]`:对 indeterminate run 提供同一入口。
61
+
62
+ ## 后果
63
+
64
+ - 安全(safe/idempotent)副作用在节点边界获得 at-most-once;unsafe 副作用仅在"结果已知且已 checkpoint"时获得 at-most-once,其余窗口仍是 at-least-once,由人工 resume 承担。
65
+ - `recovery_required` 终态下最终 step 的完成可能未入 checkpoint,resume 可能重放该 step;操作者必须核对副作用安全性。
66
+ - try 的 catch 分支若被崩溃打断,resume 时 try 主体全部"已完成"而不再抛错,剩余 catch step 不会补跑;该限制在引入显式 catch 恢复标记前记录为已知缺口。
67
+ - 状态机消费方(未来 API/UI)必须处理 `indeterminate` 与 `recovery_required`,不能把它们折叠进 `failed`。
68
+ - 本契约不提供 exactly-once、自动补偿或跨机恢复。
@@ -0,0 +1,53 @@
1
+ # ADR 0005:暂停与继续
2
+
3
+ - 状态:已接受
4
+ - 日期:2026-09-01
5
+
6
+ ## 背景
7
+
8
+ M3 落地了节点边界检查点与恢复(ADR 0004),恢复的触发只有"崩溃 / 失败后人工 resume"。运维上还需要一种**主动的、干净的**停止:操作者预感外部条件将变化(如要登录、要换环境)时,希望在当前命令完成后停下来,之后从断点继续,而不是取消后从头重跑。
9
+
10
+ 本 ADR 修改 runtime 状态机契约:`RunStatus` 新增 `paused`,并修订"每个 run 必达终态"的绝对表述(AGENTS.md 规则 8)。
11
+
12
+ ## 决策
13
+
14
+ ### `paused` 是持久化的驻留状态,不是进程内挂起
15
+
16
+ `RunHandle.pause()` 只置一个请求标记。生效点永远是 **action 边界**:进行中的 attempt 自然跑完(暂停不打断、不取消任何进行中的命令),随后在下一个节点入口停止。停止时 run 像其他终态一样收口:`pauseRequested` / `runPaused` / `runFinished` 事件、`result.json`(`status=paused`)、最终 checkpoint 全部落盘,run task 结束,执行器持有的 run 内资源随 attempt 语义释放。
17
+
18
+ 首版明确排除进程内挂起(suspend task、保活 session、冻结 deadline)——那需要资源租约和心跳,属于后续里程碑。
19
+
20
+ ### invariant 8 修订
21
+
22
+ 原规则:"每个 run 到达终态:succeeded / failed / cancelled / abandoned。" 修订为:"**每个 run 到达终态,或到达持久化的 `paused` 状态;`paused` 不是终态,负有后续义务——要么被 resume,要么被显式放弃(abandoned)。**" 运行时自身不引入 TTL 或自动放弃;`abandoned` 的边界不变(仍是显式人工动作的终态)。
23
+
24
+ ### 触发与边界契约
25
+
26
+ - `pause()` 可在 run 任意时刻调用;请求不排队、可被后续取消覆盖。
27
+ - 生效点只有两处:**action 节点入口**(未开始任何校验、事件与命令前)和**重试循环顶部**(每次新 attempt 开始前,含退避后的重试)。控制节点(sequence / if / forEach / try)不触发暂停;已完成节点静默跳过。
28
+ - 因此:若剩余动作全部已完成(如恰好在收尾时请求暂停),run 正常 `succeeded`,暂停不落位。
29
+ - 暂停不吞错误:暂停请求挂着时某步终局失败,run 仍判 `failed`;步骤被 try/catch 正常处理后继续走到下一个 action 边界才停。
30
+ - `pauseRequested` 事件记录被拒之门外 action 的 nodeId,`runPaused` 随附当时已完成步骤清单。
31
+
32
+ ### 优先级:取消 > 暂停 > 超时
33
+
34
+ - **取消 > 暂停**:两个请求同时挂起,终态 `cancelled`(取消检查在节点入口和 attempt 竞争中都先于暂停)。
35
+ - **暂停 > 超时(attempt 层面)**:暂停后不再开始新 attempt,因此不会产生新的 attempt 超时;边界处即使 deadline 已耗尽,也是先判暂停。
36
+ - **超时是唯一能打断进行中 attempt 的非取消因素**:workflow deadline 在 attempt 进行中触发时,run 判 `failed(TIMEOUT)`,即使暂停请求已挂起——暂停契约只承诺"边界处干净地停",不撤销已开始 attempt 的时限。此边界情形是已知且被测试锁定的。
37
+
38
+ ### deadline 与 session
39
+
40
+ - `paused` 不冻结时间:deadline 只约束执行中的 run;暂停后 run 已结束,无时间语义。
41
+ - resume(无论从 failed 还是 paused)按 ADR 0004 重新计费 `workflow.timeout_seconds`。
42
+ - session 无保活承诺:暂停期间浏览器 / 桌面 session 可能存活(同进程)也可能死亡(新进程 resume);恢复后按 ADR 0004 的 session 丢失契约处理(`SESSION_NOT_FOUND` / `SESSION_LOST`)。需要 session 的 workflow 应在暂停后重新 launch。
43
+
44
+ ### 恢复
45
+
46
+ `resume()` 对 `paused` run 无特殊门槛——完全复用 ADR 0004 的五道门(结构校验、workflowId、catalogDigest、indeterminate 人工确认、恢复执行)。`indeterminate` 与 `recovery_required` 的门槛对一切 resume 生效,不因来源是 paused 而放宽。
47
+
48
+ ## 后果
49
+
50
+ - `RunStatus` 消费方必须显式处理 `paused`,不得折叠进 `failed` / `cancelled`;它是唯一"非终态但已落盘证据"的取值。
51
+ - 暂停的实时性以节点为界:长 attempt(如长超时命令)会推迟暂停生效点;需要即时停止应使用取消。
52
+ - pause/resume 之间系统状态可能变化,workflow 作者应把暂停点当作与崩溃点同等对待(副作用契约完全一致)。
53
+ - 不提供调度器自动 resume、跨进程暂停信号或暂停期间资源租约。
@@ -0,0 +1,83 @@
1
+ # ADR 0006:第一 API 面决策
2
+
3
+ - 状态:已接受
4
+ - 日期:2026-09-01
5
+
6
+ ## 背景
7
+
8
+ runtime 状态机(ADR 0004 恢复、ADR 0005 暂停)、三类执行器与 25 条命令契约均已通过验收;第一个调用方是 CLI。仓库外开始出现集成诉求:用 Python 驱动 rpa_core 跑 workflow 的脚本、未来的任务编排层与 DSH 插件。AGENTS.md 规则 10 的排除清单(FastAPI / 数据库 / UI / MCP / 调度器 / 安装器)需要在本 ADR 中逐项给出"是否放行"的结论。
9
+
10
+ ## 现有公开面盘点
11
+
12
+ 进程内可直接 import 的稳定入口:
13
+
14
+ - `rpa_core.runtime.Orchestrator`:`start(plan, inputs)` / `run(plan, inputs)` / `resume(plan, run_id, *, allow_indeterminate)`;`RunHandle`:`cancel()` / `pause()` / `wait()` / `cancel_and_wait()` / `pause_and_wait()`
15
+ - `rpa_core.runtime.checkpoint.CheckpointStore`(M3 恢复的进度权威)
16
+ - `rpa_core.runtime.events.EventWriter`(append-only events.jsonl)
17
+ - `rpa_core.catalog.load_catalog` / `rpa_core.compiler.WorkflowCompiler.compile`(编译与 dry-run 校验已是公开纯函数)
18
+ - 证据产物约定:`<artifacts>/<run_id>/` 下的 `events.jsonl`、`result.json`、`checkpoint.json`
19
+ - CLI 子命令:`validate` / `run` / `resume`(`--allow-indeterminate`)
20
+
21
+ 状态机取值:`succeeded / failed / cancelled / abandoned / indeterminate / recovery_required / paused`(M3/M4 契约,禁止折叠)。
22
+
23
+ ## 候选调用方与需求
24
+
25
+ | 调用方 | 需求 | 不需要 |
26
+ |---|---|---|
27
+ | Python 自动化脚本(首批) | 编译 workflow → run → 读 RunResult / artifacts;失败后 resume;长任务 pause | 高并发、远程调用 |
28
+ | 任务编排器(中期) | 批量提交 run、按事件流感知进度、崩溃后按 checkpoint 恢复 | 多租户 |
29
+ | DSH 插件 / UI(远期) | 进度订阅、人工确认入口(indeterminate ack) | —— |
30
+
31
+ ## 决策
32
+
33
+ ### 1. 第一形态 = 进程内 Python API(即现有公开面冻结为 API v1)
34
+
35
+ **不新建 facade 层。** `Orchestrator / RunHandle / load_catalog / WorkflowCompiler` 的现有签名即 API v1 契约,用合同测试冻结:
36
+
37
+ - 调用方式:调用方自行 `load_catalog(commands) → WorkflowCompiler.compile(workflow, capabilities) → Orchestrator(catalog, registry, artifacts).run(plan)`;四步皆是公开纯函数/类,无隐藏状态。
38
+ - 生命周期归调用方:executor registry 的创建与 `close()` 由调用方持有(与 CLI 相同模式);一个进程一个 registry。
39
+ - `RunResult` 与 artifacts 文件是唯一结果通道;`events.jsonl` 是唯一进度通道。
40
+
41
+ 理由:调用方与 runtime 同进程同语言,无序列化/网络边界;现有签名已被 CLI 与 65 项测试实际验证;新增 facade 在只有一个调用方时是纯间接层。
42
+
43
+ ### 2. HTTP 服务:推迟,不放行进当前阶段
44
+
45
+ 否决理由(记录备查,非永久否决):
46
+
47
+ - 单进程 asyncio orchestrator 与多请求并发模型存在生命周期冲突(长任务 run、取消、暂停都挂在进程内 task 上),需要 run 注册表 + 进程外可观测性,复杂度未换回当前不存在的需求。
48
+ - 需要新增错误映射、认证、部署面,全部落在规则 10 排除清单。
49
+ - 触发重估条件:出现**跨进程/跨机**调用方,或编排器需要被非 Python 生态驱动。
50
+
51
+ ### 3. 排除清单结论(规则 10)
52
+
53
+ - 放行:无新增。进程内 API 本就存在,无需放行动作。
54
+ - 继续排除:FastAPI / 任何 HTTP 框架(本 ADR 明确推迟)、数据库(artifacts 文件即存储)、UI、MCP、调度器、安装器——各自需要新的 ADR。
55
+
56
+ ### 4. API 面必须保留的运行约束(合同测试锁定)
57
+
58
+ 1. 状态不折叠:`indeterminate` / `recovery_required` / `paused` 是独立 `RunStatus` 取值,任何入口不得映射为 `failed` / `cancelled`。
59
+ 2. 人工恢复门槛不可绕过:对 `indeterminate` run,`resume()` 不带 `allow_indeterminate=True` 必须拒绝。
60
+ 3. catalog 快照:一次 plan 编译绑定一份 digest;resume 校验 digest,不匹配拒绝。
61
+ 4. 用户代码不进 orchestrator 进程:data/transform 命令只经 `python.worker` 子进程。
62
+
63
+ ### 5. 三个待定问题的结论
64
+
65
+ - **dry-run 编译校验**:已满足——`WorkflowCompiler.compile` 公开且在 run 前抛出全部静态错误;CLI `validate` 即其薄封装。不新增 API。
66
+ - **events 订阅模型**:v1 = 调用方轮询/ tail `events.jsonl`(append-only、seq 单调,已是稳定契约)。进程内回调注册推迟到出现真实长驻调用方时再议(会引入背压问题)。
67
+ - **catalog 刷新**:长驻调用方在每次提交新 run 前**重建** catalog/plan(`load_catalog` 是廉价纯函数);不提供驻留式 reload,避免"一次运行两份契约"的窗口。
68
+
69
+ ## 后果
70
+
71
+ - API v1 契约 = 冻结签名;后续不兼容变更需要新 ADR 与版本号动作。
72
+ - 调用方入门文档(`docs/api-usage.md`)与合同测试落在下一里程碑(M6)。
73
+ - HTTP 重估条件已写明,避免"是否该上服务"反复讨论。
74
+ - 规则 10 的排除清单除本 ADR 明确推迟的 HTTP 外维持不变。
75
+
76
+ ## §6 通道对齐原则(2026-09-03 增补,维护者提议)
77
+
78
+ **能力层(rpa_core 包)是唯一能力实现;CLI 与 devserver 是两个薄通道。**
79
+
80
+ - **CLI 优先**:能力层每项能力必须有 CLI 入口(agent/脚本通道,M15 WorkBuddy 主路径);devserver 只做人类交互,不得独占能力。
81
+ - **devserver 复用方式 = 直接 import 能力层**(现状即如此,架构检查强制隔离),**不是 spawn 解析 CLI 子进程**(stdout 解析脆弱、双进程开销)。唯一例外是运行操控(长任务/取消),子进程隔离是机制选择,见运行控制 backlog 条目。
82
+ - 新能力落地顺序:库函数 → CLI 子命令 →(如需人类交互)devserver 端点。
83
+ - 当前缺口(CLI 无入口,仅 devserver 有):`catalog` 摘要、`capture` 交互捕获、`elements` 读写/verify——入 BACKLOG「CLI 通道对齐」条目补齐。
@@ -0,0 +1,69 @@
1
+ # ADR 0007:设计期 dev server 与捕获传输契约
2
+
3
+ - 状态:已接受
4
+ - 日期:2026-09-01
5
+ - 关联:ADR 0006(HTTP 运行操控推迟)、`docs/capture-transport.md`(传输决策矩阵)、M8 任务单
6
+
7
+ ## 背景
8
+
9
+ M9 拖拽编辑器与 M10 元素捕获需要一个稳定的设计期 API:读取命令目录、dry-run 编译 workflow、读写 workflow 文件。ADR 0006 推迟的是"承载 run 的 HTTP 服务",与本 ADR 的设计期工具不冲突——dev server 永远不启动、暂停或恢复 run。
10
+
11
+ M7 S0 实测(Chrome 152 封锁默认 profile CDP 端口)已在 `docs/capture-transport.md` 定稿浏览器捕获传输方案;本 ADR 将其固化为 dev server 端点契约。
12
+
13
+ ## 决策
14
+
15
+ ### 1. 新顶层包 `rpa_core.devserver` 与架构边界
16
+
17
+ - 依赖方向:`devserver` 可 import `model`、`catalog`、`compiler`(只读复用);**禁止** import `runtime`、`executors`、`workers`、`cli`。由架构检查脚本断言。
18
+ - 定位:设计期工具,与运行时进程隔离。dev server 进程内不存在 orchestrator、registry 或任何 run 状态。
19
+ - 实现载体:stdlib `http.server`(`ThreadingHTTPServer`),零新依赖。规则 10 的 FastAPI/框架排除维持不变。
20
+
21
+ ### 2. workflow 文件目录约定(待定问题结案)
22
+
23
+ - 默认目录:**仓库根 `workflows/`**,纳入 git 管理(倾向已确认为决策)。dev server 构造参数 `workflows_root` 可覆盖,测试与多根场景使用。
24
+ - 文件名即 workflow 名,模式 `[A-Za-z][A-Za-z0-9_-]*`(无分隔符、无 `..`,从源头杜绝路径逃逸);磁盘文件 `<name>.json`。
25
+ - 受限根目录:所有读写 `resolve()` 后必须仍位于根目录内,越界一律拒绝。
26
+ - PUT 语义:只要求 body 是合法 JSON 对象并原样落盘(编辑器需保存编译不过的草稿);静态校验走 `POST /api/compile`。
27
+
28
+ > **2026-09-02 修订(每流程一个目录 + 元素即流程资产)**:目录形态改为**每流程一个目录**——`<workflows_root>/<流程名>/workflow.json`(实现 `WorkflowDirStore`,list 只统计含 `workflow.json` 的子目录,delete 空目录一并移除)。**捕获元素作为该流程的元素资产**存放 `<流程名>/elements/<元素>.json`(可入版本库),不再有全局 `elements/` 根;元素端点嵌套于流程资源:`/api/workflows/{name}/elements[/{element}[/verify]]`。capture `pick` 的 `saveAs` 需同时带 `flow`。workflow 名正则、越界拒绝、原子写等安全不变式保持不变;根目录遗留的平铺 `<name>.json` 不再识别。
29
+
30
+ ### 3. 端点契约
31
+
32
+ 统一响应:JSON;错误形态 `{"error": <CODE>, "message": <str>}`。默认监听 `127.0.0.1:8765`。
33
+
34
+ | 端点 | 方法 | 语义 |
35
+ |---|---|---|
36
+ | `/api/catalog` | GET | manifest 元数据 `{digest, commands: [{id, version, kind, effect, input_schema, output_schema, errors}]}`,与 `load_catalog` 同源同快照 |
37
+ | `/api/compile` | POST | body `{"workflow": {...}, "capabilities": [...]?}`(capabilities 缺省 = CLI 五项);dry-run 响应 `{valid, errors[], catalog_digest}`,不产生 ExecutionPlan 副作用 |
38
+ | `/api/workflows` | GET | 列出根目录内全部 workflow 名 |
39
+ | `/api/workflows/{name}` | GET/PUT | 读/写 workflow 文件;PUT 响应 `{name, bytes}` |
40
+ | `/api/capture/desktop/{start,pick,cancel}` | POST | 桌面捕获会话(UIA hit-test),M8 仅契约 |
41
+ | `/api/capture/browser/{start,pick,cancel}` | POST | 浏览器捕获会话,M8 仅契约 |
42
+
43
+ 错误码与状态码:`BAD_REQUEST`(400)、`FORBIDDEN`(403,越界/非法名)、`NOT_FOUND`(404)、`METHOD_NOT_ALLOWED`(405)、`PAYLOAD_TOO_LARGE`(413)、`NOT_IMPLEMENTED`(501,捕获端点 M10 前占位)。
44
+
45
+ ### 4. 浏览器捕获传输契约
46
+
47
+ - `POST /api/capture/browser/start` body 必含 `transport`,取值 `"persistent"`(专用持久 profile,M10a 主路线)或 `"user-browser"`(复用登录态)。
48
+ - **S1 结论(2026-09-01,Edge 152.0.4191.53 实测)**:`user-browser` 子类型定案为 **`chrome-inspect-ws`**(`userBrowserType` 参数)——用户在 `edge://inspect/#remote-debugging` 手动开启授权开关后,服务端读取 User Data 目录下 `DevToolsActivePort` 文件(首行端口 + 次行浏览器 UUID 路径)构造 `ws://127.0.0.1:<port><path>` 直连;`/json/*` 发现端点 404(防扫描)不可用。`connect_over_cdp`、picker 注入、原生 CDP session 均已实测通过(证据见 `docs/capture-transport.md` §2.2/§4)。开关跨重启持久性待重启确认。
49
+ - **降级链(2026-09-01 复核定稿)**:M10a 持久 profile(主)→ M10b `chrome-inspect-ws`(次,S1 已验证)→ M10c 自研捕获扩展(三,token 配对反连 dev server 为主设计 / Native Messaging 为备选,已立项不实装);Panerelay 与 Playwright MCP 扩展传输降为记录备查(弹窗成本矩阵与依据见 `docs/capture-transport.md` §2.3–§2.5、§3)。
50
+ - 持久 profile 模式所需的 `browser.launch` manifest 扩展(`userDataDir`)随 M10a 实装。
51
+
52
+ ### 5. 桌面捕获契约(待定问题结案)
53
+
54
+ - 捕获路径:UIA hit-test(不涉及浏览器 CDP 限制)。
55
+ - **捕获会话状态放独立子进程**:UIA/COM 初始化会污染宿主进程 COM 状态,dev server 服务进程必须保持无 COM 状态;子进程经 stdout JSON 与 dev server 通信(与 `python.worker` 同构的隔离模式)。
56
+ - M8 仅定义端点与 501 占位,子进程协议随 M10 实装。
57
+
58
+ ### 6. 安全边界
59
+
60
+ - 仅监听 `127.0.0.1`;构造参数不接受非回环 host。
61
+ - 请求体上限 1 MiB(`PAYLOAD_TOO_LARGE`)。
62
+ - workflow 名与路径越界拒绝(见 §2)。
63
+ - 无认证:设计期本地工具,配合仅回环监听;远程/多用户场景需要新 ADR。
64
+
65
+ ## 后果
66
+
67
+ - M9 编辑器可依赖 catalog/compile/workflows 三组端点开发;M10 捕获按 §4/§5 契约实装。
68
+ - dev server 与运行时的隔离由架构检查机械保证;两个进程形态(设计期 HTTP、运行期进程内 API)互不依赖。
69
+ - S1 验证结论(user-browser 子类型定案)落地时仅扩充 `transport` 的取值枚举,不改端点形态。
@@ -0,0 +1,39 @@
1
+ # ADR 0008:编辑器 UI 放行与零构建形态
2
+
3
+ - 状态:已接受
4
+ - 日期:2026-09-01
5
+ - 关联:ADR 0006(UI 排除结论)、ADR 0007(dev server)、M9 任务单、规则 10
6
+
7
+ ## 背景
8
+
9
+ M8 dev server 交付了 catalog / compile / workflows 三组设计期 API,编辑器(M9)成为下一个调用方。规则 10 要求 UI 在第一垂直切片通过前排除——该门槛早已通过(M1 vertical-slice);ADR 0006 亦写明"UI 需要新的 ADR"。本 ADR 决定编辑器是否放行以及采用什么形态。
10
+
11
+ `project_state.json` 的排除清单中 "React UI" 是当时对"重型前端"的排除意向,需在此明确解释。
12
+
13
+ ## 决策
14
+
15
+ ### 1. 放行:设计期编辑器 UI
16
+
17
+ - 排除门槛已满足:第一垂直切片(M1)与运行时核心契约均通过验收;UI 依附的 dev server(ADR 0007)已存在且与运行时隔离。
18
+ - 放行范围仅限**设计期编辑器**,由 dev server 托管;运行期操控 UI(run/pause/resume over HTTP)仍按 ADR 0006 推迟不变。
19
+
20
+ ### 2. 形态:零构建静态单页(vanilla HTML/JS/CSS)
21
+
22
+ - 无框架、无 npm、无打包器、无 CDN 外链——页面资产是仓库内静态文件,仅由 dev server 的 `GET /` 单条静态路由提供(不开放任意文件路径,维持 ADR 0007 安全边界)。
23
+ - 理由:编辑器调用面只有 5 个本地端点,vanilla JS 完全够用;零构建消除工具链与供应链依赖,与仓库"stdlib 优先、零新依赖"的取向一致;无构建产物即无缓存失效问题,刷新即最新。
24
+ - "React UI" 排除解释:排除的是 React 及同类框架/构建工具链,不是一切 UI。若未来编辑器复杂度(M11+ 树形编辑、元素库)超出 vanilla 可维护范围,重估需新 ADR。
25
+
26
+ ### 3. 架构边界不变
27
+
28
+ - 编辑器页面是 dev server(设计期包)的一部分,不触碰 `runtime`/`executors`;架构检查的 devserver 隔离断言继续覆盖。
29
+ - 编辑器对 workflow 的读写一律走 HTTP API(与外部调用方同权),不读盘直连。
30
+
31
+ ### 4. 静态资源拆分(M11 修订)
32
+
33
+ - 编辑器单页允许拆分为多个静态文件(index.html / app.js / styles.css),由 dev server 的 `GET /static/{name}` 提供;**server.py 硬编码文件名 allowlist**,不开放任意路径、不做目录列举(维持 ADR 0007 安全边界)。零构建约束不变:无框架、无打包器、无 CDN 外链。
34
+
35
+ ## 后果
36
+
37
+ - M9 可以启动,交付物为 `devserver` 托管的单页编辑器。
38
+ - 规则 10 排除清单更新:UI(设计期编辑器)放行;FastAPI、数据库、MCP、调度器、安装器维持排除。
39
+ - 零构建约束成为 M9/M11 编辑器演进的硬边界,超出时触发新 ADR。