@actiondock/core 2.6.0 → 2.8.0

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 (268) hide show
  1. package/README.md +61 -68
  2. package/dist/catalog/action-catalog.d.ts +56 -0
  3. package/dist/catalog/action-catalog.js +202 -0
  4. package/dist/catalog/discovery.d.ts +60 -0
  5. package/dist/catalog/discovery.js +119 -0
  6. package/dist/catalog/graph.d.ts +190 -0
  7. package/dist/catalog/graph.js +589 -0
  8. package/dist/catalog/index.d.ts +5 -5
  9. package/dist/catalog/index.js +5 -5
  10. package/dist/catalog/resolve-action.d.ts +43 -0
  11. package/dist/catalog/resolve-action.js +119 -0
  12. package/dist/catalog/resolve-playbook.d.ts +26 -0
  13. package/dist/catalog/resolve-playbook.js +114 -0
  14. package/dist/doctor/checks/project.js +27 -8
  15. package/dist/doctor/checks/registry.js +2 -2
  16. package/dist/doctor/checks/runtime.js +34 -1
  17. package/dist/errors.d.ts +122 -10
  18. package/dist/errors.js +123 -10
  19. package/dist/execution/service.d.ts +18 -16
  20. package/dist/execution/service.js +183 -252
  21. package/dist/execution/types.d.ts +25 -69
  22. package/dist/execution/types.js +2 -1
  23. package/dist/filter/intent.d.ts +8 -9
  24. package/dist/filter/intent.js +49 -10
  25. package/dist/graph/index.d.ts +4 -0
  26. package/dist/graph/index.js +4 -0
  27. package/dist/host/host.d.ts +74 -32
  28. package/dist/host/host.js +585 -336
  29. package/dist/host/routing.d.ts +15 -48
  30. package/dist/host/routing.js +90 -153
  31. package/dist/host/types.d.ts +50 -17
  32. package/dist/index.d.ts +21 -22
  33. package/dist/index.js +19 -21
  34. package/dist/input/advice.d.ts +104 -0
  35. package/dist/input/advice.js +716 -0
  36. package/dist/input/describe.d.ts +106 -0
  37. package/dist/input/describe.js +176 -0
  38. package/dist/input/file-input.d.ts +54 -0
  39. package/dist/input/file-input.js +124 -0
  40. package/dist/input/flat-decode.d.ts +11 -0
  41. package/dist/input/flat-decode.js +13 -0
  42. package/dist/input/flat-errors.d.ts +71 -0
  43. package/dist/input/flat-errors.js +87 -0
  44. package/dist/input/flat-materializer.d.ts +29 -0
  45. package/dist/input/flat-materializer.js +177 -0
  46. package/dist/input/flat-parser.d.ts +50 -0
  47. package/dist/input/flat-parser.js +169 -0
  48. package/dist/input/flat-predicates.d.ts +34 -0
  49. package/dist/input/flat-predicates.js +50 -0
  50. package/dist/input/index.d.ts +14 -0
  51. package/dist/input/index.js +14 -0
  52. package/dist/input/input-resolver.d.ts +63 -0
  53. package/dist/input/input-resolver.js +254 -0
  54. package/dist/input/json-depth-scanner.d.ts +17 -0
  55. package/dist/input/json-depth-scanner.js +49 -0
  56. package/dist/input/metadata.d.ts +99 -0
  57. package/dist/input/metadata.js +99 -0
  58. package/dist/input/stdin-input.d.ts +26 -0
  59. package/dist/input/stdin-input.js +125 -0
  60. package/dist/input/utf8.d.ts +19 -0
  61. package/dist/input/utf8.js +36 -0
  62. package/dist/input/validation-mapper.d.ts +27 -0
  63. package/dist/input/validation-mapper.js +144 -0
  64. package/dist/invocation/index.d.ts +2 -0
  65. package/dist/invocation/index.js +2 -0
  66. package/dist/invocation/policy.d.ts +157 -0
  67. package/dist/invocation/policy.js +231 -0
  68. package/dist/invocation/types.d.ts +172 -0
  69. package/dist/invocation/types.js +97 -0
  70. package/dist/ipc/diagnostic.d.ts +0 -12
  71. package/dist/ipc/diagnostic.js +0 -21
  72. package/dist/ipc/host.d.ts +4 -4
  73. package/dist/ipc/host.js +44 -47
  74. package/dist/ipc/index.d.ts +1 -1
  75. package/dist/ipc/index.js +1 -1
  76. package/dist/ipc/service.d.ts +40 -0
  77. package/dist/ipc/service.js +349 -0
  78. package/dist/ipc/types.d.ts +21 -15
  79. package/dist/json/index.d.ts +1 -0
  80. package/dist/json/index.js +1 -0
  81. package/dist/json/value-validator.d.ts +88 -0
  82. package/dist/json/value-validator.js +330 -0
  83. package/dist/node/index.d.ts +1 -0
  84. package/dist/node/index.js +1 -0
  85. package/dist/node/module-loader.d.ts +63 -0
  86. package/dist/node/module-loader.js +112 -0
  87. package/dist/package/index.d.ts +23 -0
  88. package/dist/package/index.js +18 -0
  89. package/dist/{app/app.d.ts → package/runtime.d.ts} +41 -20
  90. package/dist/{app/app.js → package/runtime.js} +140 -95
  91. package/dist/{app → package}/static-index.js +58 -41
  92. package/dist/package/storage-view.d.ts +13 -0
  93. package/dist/package/storage-view.js +22 -0
  94. package/dist/{app → package}/types.d.ts +76 -57
  95. package/dist/package/types.js +22 -0
  96. package/dist/platform/index.d.ts +1 -1
  97. package/dist/platform/index.js +1 -1
  98. package/dist/platform/node.d.ts +48 -0
  99. package/dist/platform/node.js +96 -0
  100. package/dist/platform/types.d.ts +0 -9
  101. package/dist/process/control-arbiter.d.ts +2 -1
  102. package/dist/process/control-arbiter.js +1 -2
  103. package/dist/process/driver.d.ts +9 -8
  104. package/dist/process/driver.js +11 -22
  105. package/dist/process/index.d.ts +2 -0
  106. package/dist/process/index.js +2 -0
  107. package/dist/process/managed-record.d.ts +2 -2
  108. package/dist/process/process-driver.d.ts +109 -0
  109. package/dist/process/process-driver.js +650 -0
  110. package/dist/process/process-executor.d.ts +47 -0
  111. package/dist/process/process-executor.js +296 -0
  112. package/dist/process/process-manager.js +48 -26
  113. package/dist/process/run-executor.js +12 -12
  114. package/dist/profile/client-actions.js +2 -2
  115. package/dist/profile/client-health.js +3 -2
  116. package/dist/profile/client-query.js +5 -6
  117. package/dist/profile/client-transport.d.ts +19 -17
  118. package/dist/profile/client-transport.js +48 -80
  119. package/dist/profile/client.d.ts +2 -2
  120. package/dist/profile/client.js +1 -1
  121. package/dist/profile/index.d.ts +1 -0
  122. package/dist/profile/index.js +1 -0
  123. package/dist/profile/manager.d.ts +5 -0
  124. package/dist/profile/manager.js +41 -6
  125. package/dist/project/closure.js +2 -2
  126. package/dist/project/index.d.ts +8 -1
  127. package/dist/project/index.js +10 -1
  128. package/dist/project/init.js +2 -2
  129. package/dist/project/loader.d.ts +1 -1
  130. package/dist/project/loader.js +26 -29
  131. package/dist/project/transactions.js +5 -10
  132. package/dist/registry/index.d.ts +3 -1
  133. package/dist/registry/index.js +2 -1
  134. package/dist/registry/lock.d.ts +28 -7
  135. package/dist/registry/lock.js +136 -16
  136. package/dist/registry/registry.d.ts +1 -5
  137. package/dist/registry/registry.js +1 -53
  138. package/dist/registry/scan.d.ts +0 -15
  139. package/dist/registry/scan.js +0 -59
  140. package/dist/registry/store.d.ts +42 -0
  141. package/dist/registry/store.js +43 -0
  142. package/dist/registry/types.d.ts +0 -24
  143. package/dist/runtime/action-collection.d.ts +1 -1
  144. package/dist/runtime/action-registry.d.ts +0 -4
  145. package/dist/runtime/action-registry.js +0 -7
  146. package/dist/runtime/context.js +5 -11
  147. package/dist/runtime/events.js +3 -6
  148. package/dist/runtime/identity.d.ts +22 -0
  149. package/dist/runtime/identity.js +10 -0
  150. package/dist/runtime/index.d.ts +1 -2
  151. package/dist/runtime/index.js +1 -2
  152. package/dist/runtime/module-loader.d.ts +2 -34
  153. package/dist/runtime/module-loader.js +1 -16
  154. package/dist/runtime/process.d.ts +6 -24
  155. package/dist/runtime/process.js +1 -118
  156. package/dist/runtime/run-persistence.js +2 -5
  157. package/dist/runtime/runner.d.ts +33 -103
  158. package/dist/runtime/runner.js +142 -404
  159. package/dist/runtime/standalone.d.ts +37 -9
  160. package/dist/runtime/standalone.js +195 -136
  161. package/dist/schema/index.d.ts +1 -0
  162. package/dist/schema/index.js +1 -0
  163. package/dist/schema/validator.d.ts +10 -0
  164. package/dist/schema/validator.js +48 -54
  165. package/dist/server/body.d.ts +16 -8
  166. package/dist/server/body.js +33 -16
  167. package/dist/server/dispatcher.d.ts +6 -10
  168. package/dist/server/dispatcher.js +24 -32
  169. package/dist/server/http-server.d.ts +87 -0
  170. package/dist/server/http-server.js +304 -0
  171. package/dist/server/index.d.ts +11 -0
  172. package/dist/server/index.js +10 -0
  173. package/dist/server/mcp-endpoint.d.ts +61 -0
  174. package/dist/server/mcp-endpoint.js +118 -0
  175. package/dist/server/routes/actions.js +34 -28
  176. package/dist/server/routes/common.d.ts +10 -14
  177. package/dist/server/routes/common.js +32 -56
  178. package/dist/server/routes/config.js +54 -64
  179. package/dist/server/routes/doctor.d.ts +1 -1
  180. package/dist/server/routes/doctor.js +10 -18
  181. package/dist/server/routes/health.d.ts +1 -1
  182. package/dist/server/routes/health.js +2 -3
  183. package/dist/server/routes/info.d.ts +2 -2
  184. package/dist/server/routes/info.js +12 -13
  185. package/dist/server/routes/playbooks.js +16 -29
  186. package/dist/server/routes/runs.js +95 -117
  187. package/dist/server/routes/state.js +63 -62
  188. package/dist/server/server.d.ts +2 -2
  189. package/dist/server/server.js +43 -227
  190. package/dist/server/types.d.ts +8 -19
  191. package/dist/service/factory.d.ts +12 -0
  192. package/dist/service/factory.js +85 -0
  193. package/dist/{target → service}/index.d.ts +1 -1
  194. package/dist/{target → service}/index.js +1 -1
  195. package/dist/service/local.d.ts +27 -0
  196. package/dist/service/local.js +138 -0
  197. package/dist/{target → service}/remote-errors.d.ts +3 -6
  198. package/dist/service/remote-errors.js +38 -0
  199. package/dist/{target → service}/remote-polling.d.ts +2 -2
  200. package/dist/{target → service}/remote-polling.js +8 -8
  201. package/dist/service/remote.d.ts +34 -0
  202. package/dist/service/remote.js +634 -0
  203. package/dist/service/sse-stream.d.ts +24 -0
  204. package/dist/service/sse-stream.js +139 -0
  205. package/dist/service/types.d.ts +272 -0
  206. package/dist/service/types.js +32 -0
  207. package/dist/storage/data-dir-lock.js +10 -5
  208. package/dist/storage/driver.d.ts +2 -1
  209. package/dist/storage/driver.js +3 -52
  210. package/dist/storage/index.d.ts +1 -0
  211. package/dist/storage/index.js +1 -0
  212. package/dist/storage/lock-core.d.ts +2 -6
  213. package/dist/storage/lock-core.js +4 -17
  214. package/dist/storage/params.d.ts +2 -8
  215. package/dist/storage/params.js +2 -8
  216. package/dist/storage/sqlite-driver.d.ts +40 -0
  217. package/dist/storage/sqlite-driver.js +116 -0
  218. package/dist/storage/sqlite.js +21 -6
  219. package/dist/storage/types.d.ts +4 -4
  220. package/dist/storage/types.js +2 -2
  221. package/dist/utils/index.d.ts +53 -0
  222. package/dist/utils/index.js +99 -4
  223. package/dist/utils/process.d.ts +10 -0
  224. package/dist/utils/process.js +21 -0
  225. package/dist/version.d.ts +1 -1
  226. package/dist/version.js +1 -1
  227. package/package.json +41 -3
  228. package/dist/app/index.d.ts +0 -2
  229. package/dist/app/index.js +0 -2
  230. package/dist/app/types.js +0 -1
  231. package/dist/catalog/action-index.d.ts +0 -9
  232. package/dist/catalog/action-index.js +0 -95
  233. package/dist/catalog/action-resolver.d.ts +0 -20
  234. package/dist/catalog/action-resolver.js +0 -95
  235. package/dist/catalog/location-registry.d.ts +0 -15
  236. package/dist/catalog/location-registry.js +0 -138
  237. package/dist/catalog/package-catalog.d.ts +0 -7
  238. package/dist/catalog/package-catalog.js +0 -77
  239. package/dist/catalog/types.d.ts +0 -68
  240. package/dist/catalog/types.js +0 -1
  241. package/dist/export/index.d.ts +0 -1
  242. package/dist/export/index.js +0 -1
  243. package/dist/export/templates.d.ts +0 -71
  244. package/dist/export/templates.js +0 -623
  245. package/dist/ipc/target.d.ts +0 -74
  246. package/dist/ipc/target.js +0 -365
  247. package/dist/platform/default.d.ts +0 -38
  248. package/dist/platform/default.js +0 -78
  249. package/dist/project/resolver.d.ts +0 -116
  250. package/dist/project/resolver.js +0 -376
  251. package/dist/registry/resolve.d.ts +0 -62
  252. package/dist/registry/resolve.js +0 -195
  253. package/dist/runtime/execution-manager.d.ts +0 -48
  254. package/dist/runtime/execution-manager.js +0 -66
  255. package/dist/runtime/package-runner-factory.d.ts +0 -82
  256. package/dist/runtime/package-runner-factory.js +0 -186
  257. package/dist/target/local.d.ts +0 -53
  258. package/dist/target/local.js +0 -349
  259. package/dist/target/remote-errors.js +0 -51
  260. package/dist/target/remote.d.ts +0 -86
  261. package/dist/target/remote.js +0 -818
  262. package/dist/target/target.d.ts +0 -6
  263. package/dist/target/target.js +0 -37
  264. package/dist/target/types.d.ts +0 -261
  265. package/dist/target/types.js +0 -35
  266. /package/dist/{app → package}/static-index.d.ts +0 -0
  267. /package/dist/{target → service}/sse-parser.d.ts +0 -0
  268. /package/dist/{target → service}/sse-parser.js +0 -0
package/README.md CHANGED
@@ -1,115 +1,108 @@
1
1
  # @actiondock/core
2
2
 
3
- ActionDock 2.0 核心领域模型与调度引擎。
3
+ ActionDock 2.x Node-first 原生运行时与核心领域。
4
4
 
5
5
  [![Node.js](https://img.shields.io/badge/Node.js-%3E%3D24.12.0-green?logo=node.js)](https://nodejs.org/)
6
6
  [![TypeScript](https://img.shields.io/badge/TypeScript-5.0+-blue?logo=typescript)](https://www.typescriptlang.org/)
7
7
  [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
8
8
 
9
- `@actiondock/core` 承载 ActionDock 的领域对象、状态机、数据目录排他锁、统一调用门面、依赖事务管理与执行服务,是与具体宿主环境解耦的通用内核。
9
+ `@actiondock/core` 是 ActionDock 2.x 的核心领域内核与 Node-first 原生运行时。统一暴露最小化核心服务门面(`createActionDock`、`connectActionDock`)、标准服务端口体系(`DiscoveryPort`、`ExecutionPort`、`RunsPort`、`EventsPort`、`ConfigPort`、`StatePort`)、统一错误模型(`ActionDockError`)、原生平台装配(`createNodePlatform`)、服务启动(`startActionDockServer`)与包图依赖契约(`PackageGraph`),内部驱动存储引擎、受管进程与 HTTP 网络服务。
10
10
 
11
11
  ---
12
12
 
13
- ## 统一调用门面与异常
13
+ ## 子路径导出规范
14
14
 
15
- ### ActionDockTarget 统一调用门面
15
+ 为保障边界清晰与根入口极简,`@actiondock/core` 提供精细化子路径导出:
16
16
 
17
- [ActionDockTarget](./src/target/types.ts) 为命令行工具、上层服务与应用集成屏蔽本地执行、远程服务与跨进程通信的物理拓扑差异:
18
-
19
- - 本地门面 LocalTarget:直接调用本地加载的 ActionDockApp 或 ActionDockHost 实例,在同进程内高效执行。
20
- - 远程门面 RemoteTarget:通过 HTTP 协议与远程 ActionDock 服务通信,支持鉴权令牌与请求超时控制。
21
- - 跨进程门面 IpcTarget:通过 Node.js 进程间通信通道与子进程交互,包含诊断流速率保护与反压控制。
22
-
23
- ### TargetError 结构化异常
24
-
25
- [TargetError](./src/target/types.ts) 继承标准 Error,提供机器可读的结构化错误码与附加详情:
26
-
27
- - `TARGET_PROTOCOL_UNSUPPORTED`:协议版本或特性不受支持。
28
- - `TARGET_CAPABILITY_UNAVAILABLE`:目标端未启用或缺失所需能力。
29
- - `TARGET_RESULT_UNKNOWN`:连接超时或中断导致执行结果状态未知。
17
+ - `.`:核心公共根入口,仅暴露 minimal 服务门面、服务端口、平台工厂与核心契约。
18
+ - `./server`:HTTP 服务容器、路由分发、TLS 安全与服务端守护进程。
19
+ - `./project`:项目元数据、清单与依赖管理、依赖闭包及原子事务。
20
+ - `./registry`:包注册表、软链接治理与包根目录寻址。
21
+ - `./profile`:远程连接配置与管理客户端。
22
+ - `./graph`:包图模型与动作目录解析。
23
+ - `./package`:包级运行时、存储驱动与参数解析工具。
30
24
 
31
25
  ---
32
26
 
33
- ## 数据目录锁与故障恢复
34
-
35
- [DataDirLock](./src/storage/data-dir-lock.ts) 在数据目录下维护 `.actiondock.data.lock` 排他文件锁,记录宿主主进程与受管子进程状态,防止多实例并发冲突:
36
-
37
- - `DATA_DIR_IN_USE`:检测到已有活跃宿主主进程正在持有该数据目录,拒绝并发启动。
38
- - `DATA_DIR_RECOVERY_REQUIRED`:检测到前序宿主主进程异常退出,但仍有关联受管子进程处于运行状态,触发故障恢复拦截。
39
- - 正常退出时自动释放并移除锁文件;非正常退出且无任何残留进程时允许安全接管。
40
-
41
- ---
27
+ ## 统一执行主链
42
28
 
43
- ## 依赖管理与锁定规范
29
+ ActionDock 2.x 将所有调用形态(命令行、协议服务、微服务与测试沙箱)收敛至统一的确定性执行主链:
44
30
 
45
- 基于 `actiondock.lock.json`(规范版本 `lockfileVersion: 1`)提供严格的依赖版本锁定与原子事务保护:
31
+ ```text
32
+ Service -> Resolution -> PackageRuntime -> ExecutionService -> ActionRunner -> Action
33
+ ```
46
34
 
47
- - 依赖解析:[ActionPackageResolver](./src/project/resolver.ts) 递归解析本地包依赖与符号链接,避免重复加载。
48
- - 原子事务:[beginTransaction](./src/project/transactions.ts) 在执行依赖增删(如 `ad add` 与 `ad remove`)前为 `package.json`、`actiondock.json` 与 `actiondock.lock.json` 创建磁盘快照。若安装或校验流程失败,自动执行原子回滚并恢复原始状态。
35
+ - 服务接入:通过统一服务门面或标准服务端口接收外部调用请求与入参数据。
36
+ - 解析定位:通过 `resolveAction` 依赖单一事实源完成动作寻址与跨包引用消歧。
37
+ - 运行时装配:基于包图节点构建隔离的包级执行上下文与依赖环境。
38
+ - 执行协调:统筹并发配额、追踪根调用与协同取消信号。
39
+ - 动作执行:驱动单一终态状态机,执行入参出参模式校验、循环依赖拦截与状态持久化。
40
+ - 业务执行:执行开发者编写的纯粹业务逻辑并产出强类型结果。
49
41
 
50
42
  ---
51
43
 
52
- ## 核心领域模型
44
+ ## 统一服务门面与标准服务端口
53
45
 
54
- - ProjectConfig:定义在 `actiondock.json` 中的项目规范,包含包标识、名称、版本号、目录配置以及配置项元数据。
55
- - PlaybookDefinition:智能体操作规程定义,由 Markdown 文本与其头部 YAML 元数据构成,静态记录任务步骤与调用的 Action 依赖列表。
56
- - ConfigItemDefinition:单项配置规范,涵盖默认值、类型约束、敏感脱敏标记及绑定的外部环境变量。
46
+ ### 统一服务门面
57
47
 
58
- ---
48
+ 通过顶层工厂函数提供无缝屏蔽本地与远程拓扑差异的服务门面:
59
49
 
60
- ## 关键抽象契约
50
+ - 本地服务门面 `createActionDock`:创建本地 `ActionDockService` 服务端口实例,在当前 Node.js 进程内装配原生运行时驱动并高效执行。
51
+ - 远端服务门面 `connectActionDock`:创建远端 `ActionDockService` 服务端口实例,通过 HTTP 协议与远端 ActionDock 服务通信,支持鉴权令牌、请求超时控制与证书安全校验。
61
52
 
62
- ### SqliteDriver 驱动接口
53
+ ### 标准服务端口体系
63
54
 
64
- 解耦底层数据库实现,提供一致的参数化执行与事务契约:
55
+ 系统将所有对外能力解耦并收敛为六大标准服务端口契约:
65
56
 
66
- - `exec(sql: string): void`:执行无返回值的 SQL 语句。
67
- - `prepare(sql: string): SqliteStatement`:编译 SQL 模板,生成预编译语句对象。
68
- - `transaction<T>(fn: () => T): T`:同步事务执行器,在出现异常时自动回滚,并在驱动层严格拦截异步 Promise 以避免事务泄漏。
69
- - `close(): void`:释放数据库连接与文件句柄。
57
+ - 发现端口 `DiscoveryPort`:负责包与动作的元数据发现、清单检索、全文过滤与规程查询。
58
+ - 执行端口 `ExecutionPort`:负责动作的同步阻塞执行(`run`)与异步启动执行(`start`)。
59
+ - 运行端口 `RunsPort`:负责任务运行历史列表、单次详情查询与协同取消(`cancel`)。
60
+ - 事件端口 `EventsPort`:负责任务执行实时事件流订阅。
61
+ - 配置端口 `ConfigPort`:负责运行时分层配置读取、持久化配置管理与环境变量满足度体检。
62
+ - 状态端口 `StatePort`:负责包级与动作级持久化键值存取、前缀列举与过期清理。
70
63
 
71
- ### ProcessDriver 进程驱动契约与受管进程架构
64
+ ---
72
65
 
73
- Core 层内置完整的工业级受管进程治理体系,全面解耦具体操作系统运行时:
66
+ ## 单一事实源架构原则
74
67
 
75
- - ProcessManager 进程调度引擎:承载受管进程全生命周期状态机(`starting`、`running`、`stopping`、`exited`、`failed`、`lost`),提供独占控制权令牌分配与续租排队、有界环形输出日志管理、输入队列异步调度、资源硬性限额与宿主/作用域配额审计。
76
- - ContextProcessAPI 运行上下文适配器:将 ProcessAPI 绑定至具体的 ActionContext 执行链路,自动注入所有者身份与运行标识,跟踪持有的控制令牌;当 Run 结束或异常而未显式释放控制权时,自动触发目标进程隔离或终止。
77
- - ProcessDriver 平台驱动契约:定义平台底层派生与进程控制的抽象接口(`getCapabilities`、`spawn`、`write`、`inputEOF`、`terminate` 等),屏蔽各操作系统底层实现差异。
78
- - ProcessOutputLog 有界环形输出日志:单进程独立的有界内存日志缓冲区,支持基于字节游标的分页查询与长轮询等待,自动识别缓冲区淘汰断层。
79
- - ProcessMetadataStore 元数据存储接口:提供进程运行记录与幂等请求键索引的持久化抽象,默认提供纯内存实现 MemoryProcessMetadataStore。
80
- - ProcessExecutor 进程执行器接口:抽象跨平台的子进程操作,向后兼容一次性命令执行。
68
+ ActionDock 2.x 全面贯彻单一事实源设计,彻底杜绝各模块私自实现短名搜索或启发式猜测:
69
+
70
+ - 包图发现单一事实源 `PackageDiscovery`:自顶向下扫描工作区与全局注册表,建立包目录索引。
71
+ - 包拓扑图单一事实源 `PackageGraph`:维护包节点身份标识、实例版本与拓扑依赖关系。
72
+ - 动作目录单一事实源 `ActionCatalog`:统一聚合索引所有已加载包的动作元数据,提供确定性的多维检索能力。
73
+ - 动作解析单一事实源 `resolveAction`:作为全系统动作引用的唯一解析函数。优先支持包限定斜杠语法(`<package-id>/<action-id>`)与当前调用方所属包优先匹配;严格禁止冒号历史语法(`pkg:action`)。
74
+ - 调用治理策略单一事实源 `InvocationPolicy`:统筹管理根任务最大并发配额(默认 32)、子任务并发上限(默认 64)与最大调用嵌套深度(默认 16)。
81
75
 
82
76
  ---
83
77
 
84
- ## 执行核心与状态机
78
+ ## 原生运行时驱动
85
79
 
86
- ### ActionRunner 执行状态机
80
+ `@actiondock/core` 深度集成 Node.js 24 原生能力,无需编译外部二进制扩展:
87
81
 
88
- [ActionRunner](./src/execution/runner.ts) 是单个 Action 执行的核心引擎,负责完整的生命周期状态流转与契约保障:
82
+ - 原生存储驱动 `NodeSqliteDriver`:基于 Node.js 原生 `node:sqlite`(`DatabaseSync`)构建同步存储驱动。默认启用预写日志模式(WAL)、外键约束检查与忙等待超时。
83
+ - 受管进程平台驱动 `NodeProcessDriver`:实现完整的受管进程治理体系。基于管道彻底切断子进程与宿主标准流的物理连通;支持跨平台独立进程组管理与信号派发;提供独占控制权租约、逐流增量读取与优雅终止。
84
+ - 原生网络服务容器 `NodeHttpServer`:基于 Node.js 原生 `node:http` 承载 RESTful 微服务与 Server-Sent Events 事件流。
85
+ - 原生模块加载器 `NodeModuleLoader`:基于 Node.js 原生类型擦除机制直接加载 TypeScript 源码,免除前置编译转译开销。
86
+ - 原生文件系统抽象 `NodeFileSystem`:提供跨平台文件读写与原子文件事务保障。
89
87
 
90
- - 调用链环路检测:基于调用栈跟踪,当检测到依赖循环调用时立即拦截并返回错误信封。
91
- - 模式严格校验:在 Action 执行前校验输入数据是否满足模式规范,校验失败时直接阻断并生成结构化诊断信息。
92
- - 运行记录持久化:在 SQLite 中写入 `running` 状态记录,并在结束时流转至对应终态。
93
- - 生命周期状态转换:涵盖 `running`、`success`、`failed`、`timed_out`、`cancelled`、`interrupted` 状态。
94
- - 上下文环境合成:动态构建 ActionContext,集成配置优先级解析器、状态存储器与标准错误流日志记录器。
88
+ ---
95
89
 
96
- ### DefaultExecutionService 统一执行服务
90
+ ## 数据目录锁与故障自愈
97
91
 
98
- [DefaultExecutionService](./src/execution/service.ts) 负责系统层面的并发控制、任务追踪与生命周期协同:
92
+ 通过 `DataDirLock` 在数据目录下维护 `.actiondock.data.lock` 排他文件锁,记录宿主进程与受管子进程状态:
99
93
 
100
- - 并发度控制:维护活跃任务表,支持配置系统最大并发上限,超限时排队或拒绝。
101
- - 全链路追踪:为每次执行分配全局唯一的根运行标识与父子调用关联。
102
- - 协同取消传播:支持根据运行标识获取执行句柄,向下游所有派生子任务广播取消信号。
103
- - 事件汇聚分发:将执行过程中的状态变更事件统一推送到事件接收器中。
94
+ - 活跃进程冲突防护:检测到已有活跃宿主主进程正在持有该数据目录时,抛出 `DATA_DIR_IN_USE` 错误拒绝并发启动。
95
+ - 孤儿进程保护:检测到前序宿主主进程异常退出但仍有关联受管子进程处于运行状态时,抛出 `DATA_DIR_RECOVERY_REQUIRED` 错误,阻止脏写并等待子进程回收。
96
+ - 故障自动恢复:前序宿主进程与关联子进程均已死亡时,当前宿主自动接管排他锁并安全清理残留会话。
104
97
 
105
98
  ---
106
99
 
107
- ## 运行时可插拔设计
100
+ ## 依赖管理与原子事务
108
101
 
109
- `@actiondock/core` 保持平台中立,不绑定任何特定运行环境:
102
+ 基于 `actiondock.lock.json`(规范版本 `lockfileVersion: 1`)提供严格的依赖版本锁定与原子事务保护:
110
103
 
111
- - 在日常生产与 Node.js 运行时中,通过 [@actiondock/runtime-node](../runtime-node/README.md) 注入默认同步存储驱动与 Node.js 进程执行器(另有独立异步驱动 WorkerSqliteDriver 可选)。
112
- - 在自动化测试中,通过 [@actiondock/testing](../testing/README.md) 注入纯内存存储驱动 MemoryStorage 与模拟进程执行器 MockProcessExecutor。
104
+ - 依赖图构建:`PackageGraphBuilder` 递归解析本地包依赖与符号链接,统一建立拓扑图并检测版本冲突。
105
+ - 原子事务:`beginTransaction` 在执行依赖增删(如 `ad add` 与 `ad remove`)前为 `package.json`、`actiondock.json` 与 `actiondock.lock.json` 创建快照。若安装或校验流程失败,自动执行原子回滚并恢复原始状态。
113
106
 
114
107
  ---
115
108
 
@@ -0,0 +1,56 @@
1
+ import type { ActionContract, ActionRef } from "@actiondock/sdk";
2
+ import type { PackageIdentity } from "../runtime/identity.js";
3
+ import type { PackageGraph } from "./graph.js";
4
+ /**
5
+ * 动作目录候选条目规范。
6
+ */
7
+ export interface ActionCandidate {
8
+ /** 所属包唯一逻辑标识 */
9
+ readonly packageId: string;
10
+ /** 所属包唯一身份标识值对象 */
11
+ readonly packageIdentity: PackageIdentity;
12
+ /** 动作唯一标识符 */
13
+ readonly actionId: string;
14
+ /** 动作契约元数据定义 */
15
+ readonly contract: ActionContract;
16
+ /** 动作执行入口相对文件路径 */
17
+ readonly entry: string;
18
+ /** 所属包根目录绝对物理路径 */
19
+ readonly packageRoot: string;
20
+ }
21
+ /**
22
+ * 动作目录索引 ActionCatalog 契约。
23
+ */
24
+ export interface ActionCatalog {
25
+ /**
26
+ * 按动作引用查找候选动作列表。
27
+ * 若指定了 packageId,仅匹配对应包;若未指定 packageId,返回全部同名候选。
28
+ */
29
+ find(ref: ActionRef | string): ActionCandidate[];
30
+ /**
31
+ * 获取已索引候选动作集合(可选限定指定包)。
32
+ */
33
+ list(packageId?: string): ActionCandidate[];
34
+ /**
35
+ * 精确获取特定包内的特定动作候选。
36
+ */
37
+ get(packageId: string, actionId: string): ActionCandidate | undefined;
38
+ }
39
+ /**
40
+ * 动作目录默认实现 DefaultActionCatalog。
41
+ * 基于 PackageGraph 与包内 manifest/actions 构建 Action 索引。
42
+ */
43
+ export declare class DefaultActionCatalog implements ActionCatalog {
44
+ private readonly byPackageAndAction;
45
+ private readonly byActionId;
46
+ private readonly byPackageId;
47
+ private readonly graph;
48
+ private readonly actionsProvider?;
49
+ constructor(graph: PackageGraph, actionsProvider?: (packageId: string) => Map<string, any> | undefined);
50
+ private checkDynamicAction;
51
+ private addCandidate;
52
+ private indexGraph;
53
+ find(ref: ActionRef | string): ActionCandidate[];
54
+ list(packageId?: string): ActionCandidate[];
55
+ get(packageId: string, actionId: string): ActionCandidate | undefined;
56
+ }
@@ -0,0 +1,202 @@
1
+ import { existsSync, readdirSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { parseActionRef } from "./resolve-action.js";
4
+ /**
5
+ * 推断清单声明的 Action 入口相对路径:优先 .ts,不存在时回退 .js,兼容纯 JS 包。
6
+ */
7
+ function inferActionEntry(packageRoot, manifest, actionId) {
8
+ const actionsDir = manifest?.actionsDir || "actions";
9
+ const tsEntry = join(actionsDir, `${actionId}.ts`);
10
+ return existsSync(join(packageRoot, tsEntry)) ? tsEntry : join(actionsDir, `${actionId}.js`);
11
+ }
12
+ /**
13
+ * 动作目录默认实现 DefaultActionCatalog。
14
+ * 基于 PackageGraph 与包内 manifest/actions 构建 Action 索引。
15
+ */
16
+ export class DefaultActionCatalog {
17
+ byPackageAndAction = new Map();
18
+ byActionId = new Map();
19
+ byPackageId = new Map();
20
+ graph;
21
+ actionsProvider;
22
+ constructor(graph, actionsProvider) {
23
+ this.graph = graph;
24
+ this.actionsProvider = actionsProvider;
25
+ this.indexGraph(graph, actionsProvider);
26
+ }
27
+ checkDynamicAction(packageId, actionId) {
28
+ if (!this.actionsProvider)
29
+ return undefined;
30
+ const provided = this.actionsProvider(packageId);
31
+ if (!provided)
32
+ return undefined;
33
+ const act = provided.get(actionId);
34
+ if (!act)
35
+ return undefined;
36
+ const node = this.graph.packages.get(packageId);
37
+ if (!node)
38
+ return undefined;
39
+ const candidate = {
40
+ packageId,
41
+ packageIdentity: node.identity,
42
+ actionId,
43
+ contract: {
44
+ id: actionId,
45
+ description: act?.description,
46
+ inputSchema: act?.inputSchema,
47
+ outputSchema: act?.outputSchema,
48
+ uses: act?.uses,
49
+ tags: act?.tags,
50
+ annotations: act?.annotations,
51
+ },
52
+ entry: act?.entry || "",
53
+ packageRoot: node.root || "",
54
+ };
55
+ this.addCandidate(candidate);
56
+ return candidate;
57
+ }
58
+ addCandidate(candidate) {
59
+ const qualifiedKey = `${candidate.packageId}/${candidate.actionId}`;
60
+ this.byPackageAndAction.set(qualifiedKey, candidate);
61
+ let forAction = this.byActionId.get(candidate.actionId);
62
+ if (!forAction) {
63
+ forAction = [];
64
+ this.byActionId.set(candidate.actionId, forAction);
65
+ }
66
+ forAction.push(candidate);
67
+ let forPackage = this.byPackageId.get(candidate.packageId);
68
+ if (!forPackage) {
69
+ forPackage = [];
70
+ this.byPackageId.set(candidate.packageId, forPackage);
71
+ }
72
+ forPackage.push(candidate);
73
+ }
74
+ indexGraph(graph, actionsProvider) {
75
+ for (const node of graph.packages.values()) {
76
+ const packageId = node.identity.id;
77
+ const manifest = node.manifest;
78
+ // 1. 清单显式 actions 声明优先索引
79
+ if (manifest?.actions && typeof manifest.actions === "object") {
80
+ for (const [actionId, item] of Object.entries(manifest.actions)) {
81
+ const entry = item?.entry || inferActionEntry(node.root, manifest, actionId);
82
+ const candidate = {
83
+ packageId,
84
+ packageIdentity: node.identity,
85
+ actionId,
86
+ contract: {
87
+ id: actionId,
88
+ description: item?.description,
89
+ inputSchema: item?.inputSchema,
90
+ outputSchema: item?.outputSchema,
91
+ uses: item?.uses,
92
+ tags: item?.tags,
93
+ annotations: item?.annotations,
94
+ },
95
+ entry,
96
+ packageRoot: node.root,
97
+ };
98
+ this.addCandidate(candidate);
99
+ }
100
+ }
101
+ // 2. 内存动态注入动作索引(测试或 Host 注册场景)
102
+ if (actionsProvider) {
103
+ const dynActions = actionsProvider(packageId);
104
+ if (dynActions && typeof dynActions.entries === "function") {
105
+ for (const [actionId, act] of dynActions.entries()) {
106
+ const qualifiedKey = `${packageId}/${actionId}`;
107
+ if (!this.byPackageAndAction.has(qualifiedKey)) {
108
+ const contract = act?.contract || { id: actionId };
109
+ const candidate = {
110
+ packageId,
111
+ packageIdentity: node.identity,
112
+ actionId,
113
+ contract,
114
+ entry: "",
115
+ packageRoot: node.root,
116
+ };
117
+ this.addCandidate(candidate);
118
+ }
119
+ }
120
+ }
121
+ }
122
+ // 3. actions 目录回退扫描
123
+ const actionsDir = join(node.root, manifest?.actionsDir || "actions");
124
+ if (existsSync(actionsDir)) {
125
+ try {
126
+ const files = readdirSync(actionsDir);
127
+ for (const file of files) {
128
+ if (file.endsWith(".ts") || file.endsWith(".js")) {
129
+ if (file.endsWith(".d.ts") || file.endsWith(".test.ts") || file.endsWith(".spec.ts")) {
130
+ continue;
131
+ }
132
+ const actionId = file.replace(/\.(ts|js)$/, "");
133
+ const qualifiedKey = `${packageId}/${actionId}`;
134
+ if (!this.byPackageAndAction.has(qualifiedKey)) {
135
+ const candidate = {
136
+ packageId,
137
+ packageIdentity: node.identity,
138
+ actionId,
139
+ contract: { id: actionId },
140
+ entry: join(manifest?.actionsDir || "actions", file),
141
+ packageRoot: node.root,
142
+ };
143
+ this.addCandidate(candidate);
144
+ }
145
+ }
146
+ }
147
+ }
148
+ catch {
149
+ // 忽略扫描目录异常
150
+ }
151
+ }
152
+ }
153
+ }
154
+ find(ref) {
155
+ const parsed = parseActionRef(ref);
156
+ if (parsed.packageId) {
157
+ const item = this.get(parsed.packageId, parsed.actionId);
158
+ return item ? [item] : [];
159
+ }
160
+ if (this.actionsProvider) {
161
+ for (const node of this.graph.packages.values()) {
162
+ const key = `${node.identity.id}/${parsed.actionId}`;
163
+ if (!this.byPackageAndAction.has(key)) {
164
+ this.checkDynamicAction(node.identity.id, parsed.actionId);
165
+ }
166
+ }
167
+ }
168
+ return this.byActionId.get(parsed.actionId) || [];
169
+ }
170
+ list(packageId) {
171
+ if (packageId) {
172
+ if (this.actionsProvider) {
173
+ const provided = this.actionsProvider(packageId);
174
+ if (provided) {
175
+ for (const actionId of provided.keys()) {
176
+ if (!this.byPackageAndAction.has(`${packageId}/${actionId}`)) {
177
+ this.checkDynamicAction(packageId, actionId);
178
+ }
179
+ }
180
+ }
181
+ }
182
+ return this.byPackageId.get(packageId) || [];
183
+ }
184
+ if (this.actionsProvider) {
185
+ for (const node of this.graph.packages.values()) {
186
+ const provided = this.actionsProvider(node.identity.id);
187
+ if (provided) {
188
+ for (const actionId of provided.keys()) {
189
+ if (!this.byPackageAndAction.has(`${node.identity.id}/${actionId}`)) {
190
+ this.checkDynamicAction(node.identity.id, actionId);
191
+ }
192
+ }
193
+ }
194
+ }
195
+ }
196
+ return Array.from(this.byPackageAndAction.values());
197
+ }
198
+ get(packageId, actionId) {
199
+ return (this.byPackageAndAction.get(`${packageId}/${actionId}`) ||
200
+ this.checkDynamicAction(packageId, actionId));
201
+ }
202
+ }
@@ -0,0 +1,60 @@
1
+ import type { ActionDockManifest } from "../project/types.js";
2
+ import { type RegistryStore } from "../registry/store.js";
3
+ import type { PackageIdentity } from "../runtime/identity.js";
4
+ /**
5
+ * 发现的包基本信息规范。
6
+ */
7
+ export interface DiscoveredPackage {
8
+ /** 逻辑包唯一标识符 */
9
+ readonly id: string;
10
+ /** 包物理根目录绝对路径 */
11
+ readonly root: string;
12
+ /** 包清单定义 */
13
+ readonly manifest: ActionDockManifest;
14
+ /** 包物理与快照身份凭证(可选,由已有运行时传入) */
15
+ readonly identity?: PackageIdentity;
16
+ /** 是否来自工作区目录扫描发现 */
17
+ readonly isWorkspaceChild?: boolean;
18
+ /** 是否为当前工作目录工程 */
19
+ readonly isCurrentProject?: boolean;
20
+ /** 是否来自显式链接的外部包 */
21
+ readonly isLinked?: boolean;
22
+ }
23
+ /**
24
+ * 包发现配置选项。
25
+ */
26
+ export interface PackageDiscoveryOptions {
27
+ /** 当前项目根路径(可选) */
28
+ currentProjectRoot?: string;
29
+ /** 自定义 ActionDock 主目录路径(用于定位注册表) */
30
+ customHome?: string;
31
+ /** 显式注入的注册表存储实例(可选,默认使用 DefaultRegistryStore) */
32
+ registryStore?: RegistryStore;
33
+ /** 附加显式包根目录集合 */
34
+ packageRoots?: string[];
35
+ /** 附加显式工作区根目录集合 */
36
+ workspaceRoots?: string[];
37
+ /** 工作区目录扫描最大深度(默认 3) */
38
+ workspaceScanDepth?: number;
39
+ /** 是否扫描已注册链接包(默认为 true) */
40
+ scanLinkedPackages?: boolean;
41
+ }
42
+ /**
43
+ * 包发现单一事实源 PackageDiscovery。
44
+ * 负责聚合当前工程、用户显式注册包位置与工作区根目录,输出已发现包集合。
45
+ * 纯粹负责发现物理位置并去重冲突检测,严禁进行依赖鉴权或动作调用拦截。
46
+ */
47
+ export declare class PackageDiscovery {
48
+ private readonly options;
49
+ /** 包标识到物理根路径(realpath 归一)的查重映射,避免注册路径的线性全表扫描 */
50
+ private readonly idRealPaths;
51
+ constructor(options?: PackageDiscoveryOptions);
52
+ /**
53
+ * 同步发现所有可用包基本信息集合。
54
+ */
55
+ discoverSync(): DiscoveredPackage[];
56
+ /**
57
+ * 异步发现所有可用包基本信息集合。
58
+ */
59
+ discover(): Promise<DiscoveredPackage[]>;
60
+ }
@@ -0,0 +1,119 @@
1
+ import { existsSync, realpathSync } from "node:fs";
2
+ import { resolve } from "node:path";
3
+ import { loadProjectConfig } from "../project/loader.js";
4
+ import { loadManifest } from "../project/manifest.js";
5
+ import { DefaultRegistryStore } from "../registry/store.js";
6
+ import { discoverProjectConfigs } from "../registry/scan.js";
7
+ /**
8
+ * 包发现单一事实源 PackageDiscovery。
9
+ * 负责聚合当前工程、用户显式注册包位置与工作区根目录,输出已发现包集合。
10
+ * 纯粹负责发现物理位置并去重冲突检测,严禁进行依赖鉴权或动作调用拦截。
11
+ */
12
+ export class PackageDiscovery {
13
+ options;
14
+ /** 包标识到物理根路径(realpath 归一)的查重映射,避免注册路径的线性全表扫描 */
15
+ idRealPaths = new Map();
16
+ constructor(options = {}) {
17
+ this.options = options;
18
+ }
19
+ /**
20
+ * 同步发现所有可用包基本信息集合。
21
+ */
22
+ discoverSync() {
23
+ const packages = new Map();
24
+ this.idRealPaths.clear();
25
+ const registryStore = this.options.registryStore || new DefaultRegistryStore(this.options.customHome);
26
+ const scanLinked = this.options.scanLinkedPackages !== false;
27
+ const registerPackage = (pathOrRoot, flags) => {
28
+ const abs = resolve(pathOrRoot);
29
+ if (!existsSync(abs))
30
+ return;
31
+ const real = realpathSync(abs);
32
+ if (packages.has(real)) {
33
+ const existing = packages.get(real);
34
+ if (flags.isCurrentProject && !existing.isCurrentProject) {
35
+ packages.set(real, { ...existing, isCurrentProject: true });
36
+ }
37
+ return;
38
+ }
39
+ let manifest;
40
+ try {
41
+ manifest = loadManifest(abs) || loadProjectConfig(abs);
42
+ }
43
+ catch (err) {
44
+ if (flags.isCurrentProject) {
45
+ throw err;
46
+ }
47
+ console.warn(`[PackageDiscovery] Skipping invalid package at '${abs}': ${err?.message || String(err)}`);
48
+ return;
49
+ }
50
+ // 以 id 到物理路径的映射做常数查重,替代全表线性扫描;同物理路径重复注册静默去重
51
+ const idRealPaths = this.idRealPaths;
52
+ const existingReal = idRealPaths.get(manifest.id);
53
+ if (existingReal !== undefined && existingReal !== real) {
54
+ throw new Error(`PACKAGE_ID_CONFLICT: Package ID '${manifest.id}' is declared by multiple directories: '${existingReal}' and '${abs}'`);
55
+ }
56
+ idRealPaths.set(manifest.id, real);
57
+ packages.set(real, {
58
+ id: manifest.id,
59
+ root: abs,
60
+ manifest,
61
+ ...flags,
62
+ });
63
+ };
64
+ // 1. 当前工程根路径
65
+ if (this.options.currentProjectRoot) {
66
+ registerPackage(this.options.currentProjectRoot, { isCurrentProject: true });
67
+ }
68
+ // 2. 显式包路径
69
+ if (this.options.packageRoots) {
70
+ for (const p of this.options.packageRoots) {
71
+ registerPackage(p, { isLinked: true });
72
+ }
73
+ }
74
+ // 3. 注册表登记位置
75
+ if (scanLinked) {
76
+ try {
77
+ const regData = registryStore.load();
78
+ if (regData.packages) {
79
+ for (const pkg of Object.values(regData.packages)) {
80
+ if (pkg.path) {
81
+ registerPackage(pkg.path, { isLinked: true });
82
+ }
83
+ }
84
+ }
85
+ if (regData.workspaces) {
86
+ for (const wsPath of Object.keys(regData.workspaces)) {
87
+ if (existsSync(wsPath)) {
88
+ const configs = discoverProjectConfigs(wsPath, this.options.workspaceScanDepth ?? 3);
89
+ for (const item of configs) {
90
+ registerPackage(item.root, { isWorkspaceChild: true });
91
+ }
92
+ }
93
+ }
94
+ }
95
+ }
96
+ catch (err) {
97
+ console.warn(`[PackageDiscovery] Failed to load registry locations: ${err?.message || String(err)}`);
98
+ }
99
+ }
100
+ // 4. 显式附加工作区根目录
101
+ if (this.options.workspaceRoots) {
102
+ for (const wsPath of this.options.workspaceRoots) {
103
+ if (existsSync(wsPath)) {
104
+ const configs = discoverProjectConfigs(wsPath, this.options.workspaceScanDepth ?? 3);
105
+ for (const item of configs) {
106
+ registerPackage(item.root, { isWorkspaceChild: true });
107
+ }
108
+ }
109
+ }
110
+ }
111
+ return Array.from(packages.values());
112
+ }
113
+ /**
114
+ * 异步发现所有可用包基本信息集合。
115
+ */
116
+ async discover() {
117
+ return this.discoverSync();
118
+ }
119
+ }