@actiondock/core 2.7.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 (236) 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 +102 -10
  18. package/dist/errors.js +103 -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 -24
  33. package/dist/index.js +19 -23
  34. package/dist/input/advice.d.ts +5 -1
  35. package/dist/input/advice.js +163 -214
  36. package/dist/input/describe.d.ts +1 -1
  37. package/dist/input/flat-errors.d.ts +5 -6
  38. package/dist/input/flat-errors.js +6 -6
  39. package/dist/input/flat-materializer.js +42 -44
  40. package/dist/invocation/index.d.ts +2 -0
  41. package/dist/invocation/index.js +2 -0
  42. package/dist/invocation/policy.d.ts +157 -0
  43. package/dist/invocation/policy.js +231 -0
  44. package/dist/invocation/types.d.ts +172 -0
  45. package/dist/invocation/types.js +97 -0
  46. package/dist/ipc/diagnostic.d.ts +0 -12
  47. package/dist/ipc/diagnostic.js +0 -21
  48. package/dist/ipc/host.d.ts +4 -4
  49. package/dist/ipc/host.js +44 -47
  50. package/dist/ipc/index.d.ts +1 -1
  51. package/dist/ipc/index.js +1 -1
  52. package/dist/ipc/service.d.ts +40 -0
  53. package/dist/ipc/service.js +349 -0
  54. package/dist/ipc/types.d.ts +21 -15
  55. package/dist/node/index.d.ts +1 -0
  56. package/dist/node/index.js +1 -0
  57. package/dist/node/module-loader.d.ts +63 -0
  58. package/dist/node/module-loader.js +112 -0
  59. package/dist/package/index.d.ts +23 -0
  60. package/dist/package/index.js +18 -0
  61. package/dist/{app/app.d.ts → package/runtime.d.ts} +41 -20
  62. package/dist/{app/app.js → package/runtime.js} +140 -95
  63. package/dist/{app → package}/static-index.js +58 -41
  64. package/dist/package/storage-view.d.ts +13 -0
  65. package/dist/package/storage-view.js +22 -0
  66. package/dist/{app → package}/types.d.ts +76 -57
  67. package/dist/package/types.js +22 -0
  68. package/dist/platform/index.d.ts +1 -1
  69. package/dist/platform/index.js +1 -1
  70. package/dist/platform/node.d.ts +48 -0
  71. package/dist/platform/node.js +96 -0
  72. package/dist/platform/types.d.ts +0 -9
  73. package/dist/process/control-arbiter.d.ts +2 -1
  74. package/dist/process/control-arbiter.js +1 -2
  75. package/dist/process/driver.d.ts +9 -8
  76. package/dist/process/driver.js +11 -22
  77. package/dist/process/index.d.ts +2 -0
  78. package/dist/process/index.js +2 -0
  79. package/dist/process/managed-record.d.ts +2 -2
  80. package/dist/process/process-driver.d.ts +109 -0
  81. package/dist/process/process-driver.js +650 -0
  82. package/dist/process/process-executor.d.ts +47 -0
  83. package/dist/process/process-executor.js +296 -0
  84. package/dist/process/process-manager.js +48 -26
  85. package/dist/process/run-executor.js +12 -12
  86. package/dist/profile/client-actions.js +2 -2
  87. package/dist/profile/client-health.js +2 -2
  88. package/dist/profile/client-query.js +5 -6
  89. package/dist/profile/client-transport.d.ts +19 -17
  90. package/dist/profile/client-transport.js +47 -80
  91. package/dist/profile/client.d.ts +2 -2
  92. package/dist/profile/client.js +1 -1
  93. package/dist/profile/index.d.ts +1 -0
  94. package/dist/profile/index.js +1 -0
  95. package/dist/profile/manager.d.ts +5 -0
  96. package/dist/profile/manager.js +41 -6
  97. package/dist/project/closure.js +2 -2
  98. package/dist/project/index.d.ts +8 -1
  99. package/dist/project/index.js +10 -1
  100. package/dist/project/init.js +2 -2
  101. package/dist/project/loader.d.ts +1 -1
  102. package/dist/project/loader.js +26 -29
  103. package/dist/project/transactions.js +5 -10
  104. package/dist/registry/index.d.ts +3 -1
  105. package/dist/registry/index.js +2 -1
  106. package/dist/registry/lock.d.ts +28 -7
  107. package/dist/registry/lock.js +136 -16
  108. package/dist/registry/registry.d.ts +1 -5
  109. package/dist/registry/registry.js +1 -53
  110. package/dist/registry/scan.d.ts +0 -15
  111. package/dist/registry/scan.js +0 -59
  112. package/dist/registry/store.d.ts +42 -0
  113. package/dist/registry/store.js +43 -0
  114. package/dist/registry/types.d.ts +0 -24
  115. package/dist/runtime/action-collection.d.ts +1 -1
  116. package/dist/runtime/action-registry.d.ts +0 -4
  117. package/dist/runtime/action-registry.js +0 -7
  118. package/dist/runtime/context.js +5 -11
  119. package/dist/runtime/events.js +3 -6
  120. package/dist/runtime/identity.d.ts +22 -0
  121. package/dist/runtime/identity.js +10 -0
  122. package/dist/runtime/index.d.ts +1 -2
  123. package/dist/runtime/index.js +1 -2
  124. package/dist/runtime/module-loader.d.ts +2 -34
  125. package/dist/runtime/module-loader.js +1 -16
  126. package/dist/runtime/process.d.ts +6 -24
  127. package/dist/runtime/process.js +1 -118
  128. package/dist/runtime/run-persistence.js +2 -5
  129. package/dist/runtime/runner.d.ts +33 -93
  130. package/dist/runtime/runner.js +132 -364
  131. package/dist/runtime/standalone.d.ts +23 -8
  132. package/dist/runtime/standalone.js +100 -147
  133. package/dist/server/body.d.ts +16 -8
  134. package/dist/server/body.js +33 -16
  135. package/dist/server/dispatcher.d.ts +6 -10
  136. package/dist/server/dispatcher.js +24 -32
  137. package/dist/server/http-server.d.ts +87 -0
  138. package/dist/server/http-server.js +304 -0
  139. package/dist/server/index.d.ts +11 -0
  140. package/dist/server/index.js +10 -0
  141. package/dist/server/mcp-endpoint.d.ts +61 -0
  142. package/dist/server/mcp-endpoint.js +118 -0
  143. package/dist/server/routes/actions.js +34 -28
  144. package/dist/server/routes/common.d.ts +10 -14
  145. package/dist/server/routes/common.js +32 -56
  146. package/dist/server/routes/config.js +54 -64
  147. package/dist/server/routes/doctor.d.ts +1 -1
  148. package/dist/server/routes/doctor.js +10 -18
  149. package/dist/server/routes/health.d.ts +1 -1
  150. package/dist/server/routes/health.js +2 -3
  151. package/dist/server/routes/info.d.ts +2 -2
  152. package/dist/server/routes/info.js +12 -13
  153. package/dist/server/routes/playbooks.js +16 -29
  154. package/dist/server/routes/runs.js +95 -117
  155. package/dist/server/routes/state.js +63 -62
  156. package/dist/server/server.d.ts +2 -2
  157. package/dist/server/server.js +43 -227
  158. package/dist/server/types.d.ts +8 -19
  159. package/dist/service/factory.d.ts +12 -0
  160. package/dist/service/factory.js +85 -0
  161. package/dist/{target → service}/index.d.ts +1 -1
  162. package/dist/{target → service}/index.js +1 -1
  163. package/dist/service/local.d.ts +27 -0
  164. package/dist/service/local.js +138 -0
  165. package/dist/{target → service}/remote-errors.d.ts +3 -6
  166. package/dist/service/remote-errors.js +38 -0
  167. package/dist/{target → service}/remote-polling.d.ts +2 -2
  168. package/dist/{target → service}/remote-polling.js +8 -8
  169. package/dist/service/remote.d.ts +34 -0
  170. package/dist/service/remote.js +634 -0
  171. package/dist/service/sse-stream.d.ts +24 -0
  172. package/dist/service/sse-stream.js +139 -0
  173. package/dist/service/types.d.ts +272 -0
  174. package/dist/service/types.js +32 -0
  175. package/dist/storage/data-dir-lock.js +10 -5
  176. package/dist/storage/driver.d.ts +2 -1
  177. package/dist/storage/driver.js +3 -52
  178. package/dist/storage/index.d.ts +1 -0
  179. package/dist/storage/index.js +1 -0
  180. package/dist/storage/lock-core.d.ts +2 -6
  181. package/dist/storage/lock-core.js +4 -17
  182. package/dist/storage/params.d.ts +2 -8
  183. package/dist/storage/params.js +2 -8
  184. package/dist/storage/sqlite-driver.d.ts +40 -0
  185. package/dist/storage/sqlite-driver.js +116 -0
  186. package/dist/storage/sqlite.js +21 -6
  187. package/dist/storage/types.d.ts +4 -4
  188. package/dist/storage/types.js +2 -2
  189. package/dist/utils/index.d.ts +53 -0
  190. package/dist/utils/index.js +99 -4
  191. package/dist/utils/process.d.ts +10 -0
  192. package/dist/utils/process.js +21 -0
  193. package/dist/version.d.ts +1 -1
  194. package/dist/version.js +1 -1
  195. package/package.json +41 -3
  196. package/dist/app/index.d.ts +0 -2
  197. package/dist/app/index.js +0 -2
  198. package/dist/app/types.js +0 -1
  199. package/dist/catalog/action-index.d.ts +0 -9
  200. package/dist/catalog/action-index.js +0 -95
  201. package/dist/catalog/action-resolver.d.ts +0 -20
  202. package/dist/catalog/action-resolver.js +0 -95
  203. package/dist/catalog/location-registry.d.ts +0 -15
  204. package/dist/catalog/location-registry.js +0 -138
  205. package/dist/catalog/package-catalog.d.ts +0 -7
  206. package/dist/catalog/package-catalog.js +0 -77
  207. package/dist/catalog/types.d.ts +0 -68
  208. package/dist/catalog/types.js +0 -1
  209. package/dist/export/index.d.ts +0 -1
  210. package/dist/export/index.js +0 -1
  211. package/dist/export/templates.d.ts +0 -71
  212. package/dist/export/templates.js +0 -635
  213. package/dist/ipc/target.d.ts +0 -74
  214. package/dist/ipc/target.js +0 -365
  215. package/dist/platform/default.d.ts +0 -38
  216. package/dist/platform/default.js +0 -78
  217. package/dist/project/resolver.d.ts +0 -116
  218. package/dist/project/resolver.js +0 -376
  219. package/dist/registry/resolve.d.ts +0 -62
  220. package/dist/registry/resolve.js +0 -195
  221. package/dist/runtime/execution-manager.d.ts +0 -48
  222. package/dist/runtime/execution-manager.js +0 -66
  223. package/dist/runtime/package-runner-factory.d.ts +0 -82
  224. package/dist/runtime/package-runner-factory.js +0 -186
  225. package/dist/target/local.d.ts +0 -53
  226. package/dist/target/local.js +0 -349
  227. package/dist/target/remote-errors.js +0 -51
  228. package/dist/target/remote.d.ts +0 -86
  229. package/dist/target/remote.js +0 -818
  230. package/dist/target/target.d.ts +0 -6
  231. package/dist/target/target.js +0 -37
  232. package/dist/target/types.d.ts +0 -261
  233. package/dist/target/types.js +0 -35
  234. /package/dist/{app → package}/static-index.d.ts +0 -0
  235. /package/dist/{target → service}/sse-parser.d.ts +0 -0
  236. /package/dist/{target → service}/sse-parser.js +0 -0
@@ -1,14 +1,22 @@
1
- import { CAPABILITY_UNAVAILABLE } from "../../errors.js";
1
+ import { CAPABILITY_UNAVAILABLE, CONFIG_DELETE_ERROR, CONFIG_ENV_ERROR, CONFIG_LIST_ERROR, CONFIG_SET_ERROR, INVALID_ARGUMENT, INVALID_PACKAGE_ID, PACKAGE_NOT_ALLOWED, PACKAGE_NOT_FOUND, PATH_TRAVERSAL, } from "../../errors.js";
2
2
  import { resolveEnvValue } from "../../runtime/index.js";
3
- import { isSecretConfigKey, maskSecretValue, sanitizeConfigDefinitions } from "../../storage/index.js";
3
+ import { isSecretConfigKey, sanitizeConfigDefinitions } from "../../storage/index.js";
4
4
  import { readJsonBody } from "../body.js";
5
- import { assertPackageAllowed, getSubPath, jsonResponse, resolveAppForPackage } from "./common.js";
5
+ import { getSubPath, jsonResponse, resolveTargetPackageId } from "./common.js";
6
+ function isClientConfigError(err) {
7
+ return (err?.code === PACKAGE_NOT_FOUND ||
8
+ err?.code === INVALID_PACKAGE_ID ||
9
+ err?.code === PATH_TRAVERSAL ||
10
+ err?.code === INVALID_ARGUMENT ||
11
+ err?.status === 400 ||
12
+ err?.status === 404);
13
+ }
6
14
  /**
7
15
  * 处理配置元数据与当前值读取、更新及删除接口。
8
16
  * 在未显式开启管理功能 (options.enableManagement !== true) 时返回 403 拒绝。
9
17
  */
10
18
  export async function handleConfigRoutes(ctx) {
11
- const { req, url, pathname, corsHeaders, options, host, target } = ctx;
19
+ const { req, url, pathname, corsHeaders, options, service } = ctx;
12
20
  const subpath = getSubPath(pathname);
13
21
  const isConfigRoute = subpath === "/config" ||
14
22
  subpath.startsWith("/config/") ||
@@ -17,7 +25,7 @@ export async function handleConfigRoutes(ctx) {
17
25
  return null;
18
26
  }
19
27
  // 校验管理能力开关
20
- if (options.enableManagement !== true) {
28
+ if (options.enableManagement !== true || !service.management?.config) {
21
29
  return jsonResponse({
22
30
  ok: false,
23
31
  error: {
@@ -29,16 +37,14 @@ export async function handleConfigRoutes(ctx) {
29
37
  // 1. Config Env Check: GET /config/env
30
38
  if (subpath === "/config/env" && req.method === "GET") {
31
39
  try {
40
+ const pkgs = await service.discovery.listPackages();
32
41
  const pkgParam = url.searchParams.get("package") || url.searchParams.get("packageId") || undefined;
33
- if (pkgParam) {
34
- assertPackageAllowed(pkgParam, options);
35
- }
36
- const app = resolveAppForPackage(pkgParam, host, target, options);
37
- assertPackageAllowed(app.packageId, options);
38
- const declared = app.projectConfig?.config || {};
42
+ const targetPackageId = resolveTargetPackageId(pkgs, pkgParam, options);
43
+ const pkg = pkgs.find((p) => p.id === targetPackageId);
44
+ const declared = pkg?.config || {};
39
45
  const envChecks = [];
40
46
  for (const [k, def] of Object.entries(declared)) {
41
- const resolved = resolveEnvValue(k, def, app.packageId);
47
+ const resolved = resolveEnvValue(k, def, targetPackageId);
42
48
  const matchedEnv = resolved?.envKey || null;
43
49
  envChecks.push({
44
50
  key: k,
@@ -49,61 +55,55 @@ export async function handleConfigRoutes(ctx) {
49
55
  secret: isSecretConfigKey(k, def),
50
56
  });
51
57
  }
52
- return jsonResponse({ ok: true, packageId: app.packageId, envChecks }, 200, corsHeaders);
58
+ return jsonResponse({ ok: true, packageId: targetPackageId, envChecks }, 200, corsHeaders);
53
59
  }
54
60
  catch (err) {
55
- if (err.code === "PACKAGE_NOT_ALLOWED" || err.status === 403) {
61
+ if (err.code === PACKAGE_NOT_ALLOWED || err.status === 403) {
56
62
  return jsonResponse({
57
63
  ok: false,
58
64
  error: {
59
- code: "PACKAGE_NOT_ALLOWED",
65
+ code: PACKAGE_NOT_ALLOWED,
60
66
  message: err.message || "Package is not in the allowed package list",
61
67
  },
62
68
  }, 403, corsHeaders);
63
69
  }
64
- const isClient = err.message?.includes("Unknown or unregistered package") ||
65
- err.message?.includes("Invalid packageId") ||
66
- err.message?.includes("escapes boundary");
67
- return jsonResponse({ ok: false, error: { code: isClient ? "INVALID_ARGUMENT" : "CONFIG_ENV_ERROR", message: err.message } }, isClient ? 400 : 500, corsHeaders);
70
+ const isClient = isClientConfigError(err);
71
+ return jsonResponse({ ok: false, error: { code: isClient ? INVALID_ARGUMENT : CONFIG_ENV_ERROR, message: err.message } }, isClient ? 400 : 500, corsHeaders);
68
72
  }
69
73
  }
70
74
  // 2. Config Query: GET /config
71
75
  if (subpath === "/config" && req.method === "GET") {
72
76
  try {
77
+ const pkgs = await service.discovery.listPackages();
73
78
  const pkgParam = url.searchParams.get("package") || url.searchParams.get("packageId") || undefined;
74
- if (pkgParam) {
75
- assertPackageAllowed(pkgParam, options);
76
- }
77
- const app = resolveAppForPackage(pkgParam, host, target, options);
78
- assertPackageAllowed(app.packageId, options);
79
- const stored = app.storage.listConfig();
80
- const rawDeclared = app.projectConfig?.config || {};
79
+ const targetPackageId = resolveTargetPackageId(pkgs, pkgParam, options);
80
+ const pkg = pkgs.find((p) => p.id === targetPackageId);
81
+ const rawDeclared = pkg?.config || {};
81
82
  const declared = sanitizeConfigDefinitions(rawDeclared) || {};
83
+ const views = await service.management.config.list(targetPackageId);
82
84
  const maskedValues = {};
83
- for (const [k, v] of Object.entries(stored)) {
84
- if (isSecretConfigKey(k, rawDeclared[k])) {
85
- maskedValues[k] = maskSecretValue(v);
85
+ for (const v of views) {
86
+ if (v.secret) {
87
+ maskedValues[v.key] = "********";
86
88
  }
87
89
  else {
88
- maskedValues[k] = v;
90
+ maskedValues[v.key] = v.value;
89
91
  }
90
92
  }
91
- return jsonResponse({ ok: true, packageId: app.packageId, declared, values: maskedValues }, 200, corsHeaders);
93
+ return jsonResponse({ ok: true, packageId: targetPackageId, declared, values: maskedValues }, 200, corsHeaders);
92
94
  }
93
95
  catch (err) {
94
- if (err.code === "PACKAGE_NOT_ALLOWED" || err.status === 403) {
96
+ if (err.code === PACKAGE_NOT_ALLOWED || err.status === 403) {
95
97
  return jsonResponse({
96
98
  ok: false,
97
99
  error: {
98
- code: "PACKAGE_NOT_ALLOWED",
100
+ code: PACKAGE_NOT_ALLOWED,
99
101
  message: err.message || "Package is not in the allowed package list",
100
102
  },
101
103
  }, 403, corsHeaders);
102
104
  }
103
- const isClient = err.message?.includes("Unknown or unregistered package") ||
104
- err.message?.includes("Invalid packageId") ||
105
- err.message?.includes("escapes boundary");
106
- return jsonResponse({ ok: false, error: { code: isClient ? "INVALID_ARGUMENT" : "CONFIG_LIST_ERROR", message: err.message } }, isClient ? 400 : 500, corsHeaders);
105
+ const isClient = isClientConfigError(err);
106
+ return jsonResponse({ ok: false, error: { code: isClient ? INVALID_ARGUMENT : CONFIG_LIST_ERROR, message: err.message } }, isClient ? 400 : 500, corsHeaders);
107
107
  }
108
108
  }
109
109
  // 3. Config Update: PUT / POST /config
@@ -111,32 +111,27 @@ export async function handleConfigRoutes(ctx) {
111
111
  try {
112
112
  const body = await readJsonBody(req, { maxBytes: options.maxBodyBytes });
113
113
  const pkgParam = url.searchParams.get("package") || url.searchParams.get("packageId") || body.package || undefined;
114
- if (pkgParam) {
115
- assertPackageAllowed(pkgParam, options);
116
- }
117
- const app = resolveAppForPackage(pkgParam, host, target, options);
118
- assertPackageAllowed(app.packageId, options);
114
+ const pkgs = await service.discovery.listPackages();
115
+ const targetPackageId = resolveTargetPackageId(pkgs, pkgParam, options);
119
116
  const key = body.key;
120
117
  if (!key) {
121
- return jsonResponse({ ok: false, error: { code: "INVALID_ARGUMENT", message: "Config 'key' is required" } }, 400, corsHeaders);
118
+ return jsonResponse({ ok: false, error: { code: INVALID_ARGUMENT, message: "Config 'key' is required" } }, 400, corsHeaders);
122
119
  }
123
- await app.setConfig(key, body.value);
124
- return jsonResponse({ ok: true, packageId: app.packageId, key, message: "updated" }, 200, corsHeaders);
120
+ await service.management.config.set(targetPackageId, key, body.value);
121
+ return jsonResponse({ ok: true, packageId: targetPackageId, key, message: "updated" }, 200, corsHeaders);
125
122
  }
126
123
  catch (err) {
127
- if (err.code === "PACKAGE_NOT_ALLOWED" || err.status === 403) {
124
+ if (err.code === PACKAGE_NOT_ALLOWED || err.status === 403) {
128
125
  return jsonResponse({
129
126
  ok: false,
130
127
  error: {
131
- code: "PACKAGE_NOT_ALLOWED",
128
+ code: PACKAGE_NOT_ALLOWED,
132
129
  message: err.message || "Package is not in the allowed package list",
133
130
  },
134
131
  }, 403, corsHeaders);
135
132
  }
136
- const isClient = err.message?.includes("Unknown or unregistered package") ||
137
- err.message?.includes("Invalid packageId") ||
138
- err.message?.includes("escapes boundary");
139
- return jsonResponse({ ok: false, error: { code: isClient ? "INVALID_ARGUMENT" : "CONFIG_SET_ERROR", message: err.message } }, isClient ? 400 : 500, corsHeaders);
133
+ const isClient = isClientConfigError(err);
134
+ return jsonResponse({ ok: false, error: { code: isClient ? INVALID_ARGUMENT : CONFIG_SET_ERROR, message: err.message } }, isClient ? 400 : 500, corsHeaders);
140
135
  }
141
136
  }
142
137
  // 4. Config Delete: DELETE /config/:key
@@ -145,28 +140,23 @@ export async function handleConfigRoutes(ctx) {
145
140
  try {
146
141
  const key = decodeURIComponent(configKeyMatch[1]);
147
142
  const pkgParam = url.searchParams.get("package") || url.searchParams.get("packageId") || undefined;
148
- if (pkgParam) {
149
- assertPackageAllowed(pkgParam, options);
150
- }
151
- const app = resolveAppForPackage(pkgParam, host, target, options);
152
- assertPackageAllowed(app.packageId, options);
153
- const deleted = app.storage.deleteConfig(key);
154
- return jsonResponse({ ok: true, packageId: app.packageId, key, deleted }, 200, corsHeaders);
143
+ const pkgs = await service.discovery.listPackages();
144
+ const targetPackageId = resolveTargetPackageId(pkgs, pkgParam, options);
145
+ const deleted = await service.management.config.delete(targetPackageId, key);
146
+ return jsonResponse({ ok: true, packageId: targetPackageId, key, deleted }, 200, corsHeaders);
155
147
  }
156
148
  catch (err) {
157
- if (err.code === "PACKAGE_NOT_ALLOWED" || err.status === 403) {
149
+ if (err.code === PACKAGE_NOT_ALLOWED || err.status === 403) {
158
150
  return jsonResponse({
159
151
  ok: false,
160
152
  error: {
161
- code: "PACKAGE_NOT_ALLOWED",
153
+ code: PACKAGE_NOT_ALLOWED,
162
154
  message: err.message || "Package is not in the allowed package list",
163
155
  },
164
156
  }, 403, corsHeaders);
165
157
  }
166
- const isClient = err.message?.includes("Unknown or unregistered package") ||
167
- err.message?.includes("Invalid packageId") ||
168
- err.message?.includes("escapes boundary");
169
- return jsonResponse({ ok: false, error: { code: isClient ? "INVALID_ARGUMENT" : "CONFIG_DELETE_ERROR", message: err.message } }, isClient ? 400 : 500, corsHeaders);
158
+ const isClient = isClientConfigError(err);
159
+ return jsonResponse({ ok: false, error: { code: isClient ? INVALID_ARGUMENT : CONFIG_DELETE_ERROR, message: err.message } }, isClient ? 400 : 500, corsHeaders);
170
160
  }
171
161
  }
172
162
  return null;
@@ -1,5 +1,5 @@
1
1
  import { type RouteContext } from "./common.js";
2
2
  /**
3
- * 处理环境与依赖诊断接口(GET /api/v2/doctor、/doctor 与兼容别名 /api/v1/doctor)。
3
+ * 处理环境与依赖诊断接口(GET /api/v2/doctor 与 /doctor)。
4
4
  */
5
5
  export declare function handleDoctorRoute(ctx: RouteContext): Promise<Response | null>;
@@ -1,10 +1,11 @@
1
+ import { DOCTOR_ERROR, PACKAGE_NOT_ALLOWED } from "../../errors.js";
1
2
  import { runDoctorChecks } from "../../doctor/doctor.js";
2
3
  import { assertPackageAllowed, getSubPath, jsonResponse } from "./common.js";
3
4
  /**
4
- * 处理环境与依赖诊断接口(GET /api/v2/doctor、/doctor 与兼容别名 /api/v1/doctor)。
5
+ * 处理环境与依赖诊断接口(GET /api/v2/doctor 与 /doctor)。
5
6
  */
6
7
  export async function handleDoctorRoute(ctx) {
7
- const { req, url, pathname, corsHeaders, projectRoot, customHome, host, target, options } = ctx;
8
+ const { req, url, pathname, corsHeaders, projectRoot, customHome, service, options } = ctx;
8
9
  const subpath = getSubPath(pathname);
9
10
  if (subpath !== "/doctor" || req.method !== "GET") {
10
11
  return null;
@@ -16,7 +17,7 @@ export async function handleDoctorRoute(ctx) {
16
17
  return jsonResponse({
17
18
  ok: false,
18
19
  error: {
19
- code: "PACKAGE_NOT_ALLOWED",
20
+ code: PACKAGE_NOT_ALLOWED,
20
21
  message: "Global doctor check is forbidden when package allowlist is active. Please specify an allowed package.",
21
22
  },
22
23
  }, 403, corsHeaders);
@@ -27,18 +28,9 @@ export async function handleDoctorRoute(ctx) {
27
28
  }
28
29
  let packageRoot;
29
30
  if (targetPkg) {
30
- if (host) {
31
- packageRoot = host.getApp(targetPkg)?.packageRoot;
32
- }
33
- if (!packageRoot && target?.unwrap) {
34
- const inner = target.unwrap();
35
- if (inner && "getApp" in inner && typeof inner.getApp === "function") {
36
- packageRoot = inner.getApp(targetPkg)?.packageRoot;
37
- }
38
- else if (inner && "packageId" in inner && inner.packageId === targetPkg) {
39
- packageRoot = inner.packageRoot;
40
- }
41
- }
31
+ const pkgs = await service.discovery.listPackages();
32
+ const matched = pkgs.find((p) => p.id === targetPkg || p.packageRoot === targetPkg);
33
+ packageRoot = matched?.packageRoot;
42
34
  }
43
35
  const report = await runDoctorChecks({
44
36
  cwd: packageRoot || projectRoot || process.cwd(),
@@ -49,15 +41,15 @@ export async function handleDoctorRoute(ctx) {
49
41
  return jsonResponse({ ok: true, report }, 200, corsHeaders);
50
42
  }
51
43
  catch (err) {
52
- if (err.code === "PACKAGE_NOT_ALLOWED" || err.status === 403) {
44
+ if (err.code === PACKAGE_NOT_ALLOWED || err.status === 403) {
53
45
  return jsonResponse({
54
46
  ok: false,
55
47
  error: {
56
- code: "PACKAGE_NOT_ALLOWED",
48
+ code: PACKAGE_NOT_ALLOWED,
57
49
  message: err.message || "Package is not in the allowed package list",
58
50
  },
59
51
  }, 403, corsHeaders);
60
52
  }
61
- return jsonResponse({ ok: false, error: { code: "DOCTOR_ERROR", message: err.message } }, 500, corsHeaders);
53
+ return jsonResponse({ ok: false, error: { code: DOCTOR_ERROR, message: err.message } }, 500, corsHeaders);
62
54
  }
63
55
  }
@@ -1,5 +1,5 @@
1
1
  import { type RouteContext } from "./common.js";
2
2
  /**
3
- * 处理健康检查与就绪状态接口(支持 /api/v2/health、/health 与兼容别名 /api/v1/health)。
3
+ * 处理健康检查与就绪状态接口(支持 /api/v2/health 与 /health)。
4
4
  */
5
5
  export declare function handleHealthRoute(ctx: RouteContext): Promise<Response | null>;
@@ -3,13 +3,12 @@ import { UNAUTHORIZED } from "../../errors.js";
3
3
  import { verifyBearerToken } from "../security.js";
4
4
  import { jsonResponse } from "./common.js";
5
5
  /**
6
- * 处理健康检查与就绪状态接口(支持 /api/v2/health、/health 与兼容别名 /api/v1/health)。
6
+ * 处理健康检查与就绪状态接口(支持 /api/v2/health 与 /health)。
7
7
  */
8
8
  export async function handleHealthRoute(ctx) {
9
9
  const { req, pathname, corsHeaders, options, projectRoot } = ctx;
10
10
  if (pathname !== "/api/v2/health" &&
11
- pathname !== "/health" &&
12
- pathname !== "/api/v1/health") {
11
+ pathname !== "/health") {
13
12
  return null;
14
13
  }
15
14
  if (!verifyBearerToken(req, options.token, options)) {
@@ -1,7 +1,7 @@
1
1
  import { type RouteContext } from "./common.js";
2
2
  /**
3
3
  * 处理系统自省与包信息接口:
4
- * - GET /api/v2/info 与 GET /info -> 委托 target.info()
5
- * - GET /api/v2/packages 与 GET /packages -> 委托 host.info() 或 target.info()
4
+ * - GET /api/v2/info 与 GET /info -> 委托 service.info()
5
+ * - GET /api/v2/packages 与 GET /packages -> 委托 service.discovery.listPackages()
6
6
  */
7
7
  export declare function handleInfoRoute(ctx: RouteContext): Promise<Response | null>;
@@ -1,5 +1,5 @@
1
1
  import { filterWithFallbackInfo } from "../../filter/index.js";
2
- import { PACKAGE_NOT_FOUND } from "../../errors.js";
2
+ import { INFO_ERROR, PACKAGE_NOT_ALLOWED, PACKAGE_NOT_FOUND, PACKAGES_INFO_ERROR } from "../../errors.js";
3
3
  import { ACTIONDOCK_VERSION } from "../../version.js";
4
4
  import { sanitizeConfigDefinitions } from "../../storage/index.js";
5
5
  import { assertPackageAllowed, getSubPath, jsonResponse } from "./common.js";
@@ -18,11 +18,11 @@ function sanitizePackage(pkg, exposeDebugInfo) {
18
18
  }
19
19
  /**
20
20
  * 处理系统自省与包信息接口:
21
- * - GET /api/v2/info 与 GET /info -> 委托 target.info()
22
- * - GET /api/v2/packages 与 GET /packages -> 委托 host.info() 或 target.info()
21
+ * - GET /api/v2/info 与 GET /info -> 委托 service.info()
22
+ * - GET /api/v2/packages 与 GET /packages -> 委托 service.discovery.listPackages()
23
23
  */
24
24
  export async function handleInfoRoute(ctx) {
25
- const { req, url, pathname, corsHeaders, options, target, host, projectRoot } = ctx;
25
+ const { req, url, pathname, corsHeaders, options, service, projectRoot } = ctx;
26
26
  const subpath = getSubPath(pathname);
27
27
  // 1. Packages List: GET /api/v2/packages, /packages
28
28
  if ((subpath === "/packages" || pathname === "/api/v2/packages" || pathname === "/packages") && req.method === "GET") {
@@ -31,7 +31,7 @@ export async function handleInfoRoute(ctx) {
31
31
  if (targetPkg) {
32
32
  assertPackageAllowed(targetPkg, options);
33
33
  }
34
- const rawPackages = target ? await target.listPackages() : (host ? await host.info() : []);
34
+ const rawPackages = await service.discovery.listPackages();
35
35
  let packages = rawPackages.map((p) => sanitizePackage(p, options.exposeDebugInfo));
36
36
  if (options.packageAllowlist && Array.isArray(options.packageAllowlist) && options.packageAllowlist.length > 0) {
37
37
  packages = packages.filter((p) => p.id && options.packageAllowlist.includes(p.id));
@@ -42,18 +42,18 @@ export async function handleInfoRoute(ctx) {
42
42
  }, 200, corsHeaders);
43
43
  }
44
44
  catch (err) {
45
- if (err.code === "PACKAGE_NOT_ALLOWED" || err.status === 403) {
45
+ if (err.code === PACKAGE_NOT_ALLOWED || err.status === 403) {
46
46
  return jsonResponse({
47
47
  ok: false,
48
48
  error: {
49
- code: "PACKAGE_NOT_ALLOWED",
49
+ code: PACKAGE_NOT_ALLOWED,
50
50
  message: err.message || "Package is not in the allowed package list",
51
51
  },
52
52
  }, 403, corsHeaders);
53
53
  }
54
54
  return jsonResponse({
55
55
  ok: false,
56
- error: { code: "PACKAGES_INFO_ERROR", message: err.message },
56
+ error: { code: PACKAGES_INFO_ERROR, message: err.message },
57
57
  }, 500, corsHeaders);
58
58
  }
59
59
  }
@@ -66,8 +66,7 @@ export async function handleInfoRoute(ctx) {
66
66
  if (targetPkg) {
67
67
  assertPackageAllowed(targetPkg, options);
68
68
  }
69
- const targetInfo = await target.info();
70
- const rawPackages = targetInfo.packages || [];
69
+ const rawPackages = await service.info();
71
70
  let packages = rawPackages.map((p) => sanitizePackage(p, options.exposeDebugInfo));
72
71
  if (options.packageAllowlist && Array.isArray(options.packageAllowlist) && options.packageAllowlist.length > 0) {
73
72
  packages = packages.filter((p) => p.id && options.packageAllowlist.includes(p.id));
@@ -139,18 +138,18 @@ export async function handleInfoRoute(ctx) {
139
138
  }, 200, corsHeaders);
140
139
  }
141
140
  catch (err) {
142
- if (err.code === "PACKAGE_NOT_ALLOWED" || err.status === 403) {
141
+ if (err.code === PACKAGE_NOT_ALLOWED || err.status === 403) {
143
142
  return jsonResponse({
144
143
  ok: false,
145
144
  error: {
146
- code: "PACKAGE_NOT_ALLOWED",
145
+ code: PACKAGE_NOT_ALLOWED,
147
146
  message: err.message || "Package is not in the allowed package list",
148
147
  },
149
148
  }, 403, corsHeaders);
150
149
  }
151
150
  return jsonResponse({
152
151
  ok: false,
153
- error: { code: "INFO_ERROR", message: err.message },
152
+ error: { code: INFO_ERROR, message: err.message },
154
153
  }, 500, corsHeaders);
155
154
  }
156
155
  }
@@ -1,10 +1,11 @@
1
1
  import { filterByIntent } from "../../filter/index.js";
2
+ import { PACKAGE_NOT_ALLOWED, PLAYBOOK_NOT_FOUND, PLAYBOOKS_LIST_ERROR } from "../../errors.js";
2
3
  import { assertPackageAllowed, getSubPath, jsonResponse } from "./common.js";
3
4
  /**
4
5
  * 处理 Playbook 规程相关的 HTTP 路由(列表与 SOP 详情查询)。
5
6
  */
6
7
  export async function handlePlaybooksRoutes(ctx) {
7
- const { req, url, pathname, corsHeaders, target, host, options } = ctx;
8
+ const { req, url, pathname, corsHeaders, service, options } = ctx;
8
9
  const subpath = getSubPath(pathname);
9
10
  // 1. Playbooks List: GET /api/v2/playbooks, GET /playbooks
10
11
  if (subpath === "/playbooks" && req.method === "GET") {
@@ -14,7 +15,7 @@ export async function handlePlaybooksRoutes(ctx) {
14
15
  if (targetPkg) {
15
16
  assertPackageAllowed(targetPkg, options);
16
17
  }
17
- let pbs = await target.listPlaybooks({ intent, package: targetPkg });
18
+ let pbs = await service.discovery.listPlaybooks({ intent, package: targetPkg });
18
19
  if (targetPkg) {
19
20
  pbs = pbs.filter((p) => p.packageId === targetPkg);
20
21
  }
@@ -27,16 +28,16 @@ export async function handlePlaybooksRoutes(ctx) {
27
28
  return jsonResponse(pbs, 200, corsHeaders);
28
29
  }
29
30
  catch (err) {
30
- if (err.code === "PACKAGE_NOT_ALLOWED" || err.status === 403) {
31
+ if (err.code === PACKAGE_NOT_ALLOWED || err.status === 403) {
31
32
  return jsonResponse({
32
33
  ok: false,
33
34
  error: {
34
- code: "PACKAGE_NOT_ALLOWED",
35
+ code: PACKAGE_NOT_ALLOWED,
35
36
  message: err.message || "Package is not in the allowed package list",
36
37
  },
37
38
  }, 403, corsHeaders);
38
39
  }
39
- return jsonResponse({ ok: false, error: { code: "PLAYBOOKS_LIST_ERROR", message: err.message } }, 500, corsHeaders);
40
+ return jsonResponse({ ok: false, error: { code: PLAYBOOKS_LIST_ERROR, message: err.message } }, 500, corsHeaders);
40
41
  }
41
42
  }
42
43
  // 2. Multi-package Playbook Show: GET /api/v2/packages/:packageId/playbooks/:playbookId
@@ -51,21 +52,21 @@ export async function handlePlaybooksRoutes(ctx) {
51
52
  return jsonResponse({
52
53
  ok: false,
53
54
  error: {
54
- code: "PACKAGE_NOT_ALLOWED",
55
+ code: PACKAGE_NOT_ALLOWED,
55
56
  message: err.message || `Package '${packageId}' is not in the allowed package list`,
56
57
  },
57
58
  }, 403, corsHeaders);
58
59
  }
59
60
  const ref = `${packageId}/${playbookId}`;
60
61
  try {
61
- const pb = await target.describePlaybook(ref);
62
+ const pb = await service.discovery.describePlaybook(ref);
62
63
  return jsonResponse(pb, 200, corsHeaders);
63
64
  }
64
65
  catch (err) {
65
66
  return jsonResponse({
66
67
  ok: false,
67
68
  error: {
68
- code: "PLAYBOOK_NOT_FOUND",
69
+ code: PLAYBOOK_NOT_FOUND,
69
70
  message: err.message || `Playbook '${playbookId}' not found in package '${packageId}'`,
70
71
  },
71
72
  }, 404, corsHeaders);
@@ -84,31 +85,17 @@ export async function handlePlaybooksRoutes(ctx) {
84
85
  return jsonResponse({
85
86
  ok: false,
86
87
  error: {
87
- code: "PACKAGE_NOT_ALLOWED",
88
+ code: PACKAGE_NOT_ALLOWED,
88
89
  message: err.message || `Package '${pkgFromRef}' is not in the allowed package list`,
89
90
  },
90
91
  }, 403, corsHeaders);
91
92
  }
92
93
  }
93
94
  try {
94
- const pb = await target.describePlaybook(playbookId);
95
- const unwrapped = target.unwrap?.();
96
- let pkgId = pb.packageId || (unwrapped && "packageId" in unwrapped ? unwrapped.packageId : undefined);
97
- if (!pkgId && host) {
98
- for (const app of host.listApps()) {
99
- try {
100
- const map = app.getStaticPlaybookMap?.();
101
- const cleanId = playbookId.replace(/\.md$/, "");
102
- if (map?.has(cleanId) || map?.has(playbookId)) {
103
- pkgId = app.packageId;
104
- break;
105
- }
106
- }
107
- catch { }
108
- }
109
- }
95
+ const pb = await service.discovery.describePlaybook(playbookId);
96
+ let pkgId = pb.packageId;
110
97
  if (!pkgId) {
111
- const allPbs = await target.listPlaybooks().catch(() => []);
98
+ const allPbs = await service.discovery.listPlaybooks().catch(() => []);
112
99
  const matched = allPbs.find((p) => p.id === playbookId || p.id.endsWith(`/${playbookId}`));
113
100
  if (matched?.packageId) {
114
101
  pkgId = matched.packageId;
@@ -118,16 +105,16 @@ export async function handlePlaybooksRoutes(ctx) {
118
105
  return jsonResponse(pb, 200, corsHeaders);
119
106
  }
120
107
  catch (err) {
121
- if (err.code === "PACKAGE_NOT_ALLOWED" || err.status === 403) {
108
+ if (err.code === PACKAGE_NOT_ALLOWED || err.status === 403) {
122
109
  return jsonResponse({
123
110
  ok: false,
124
111
  error: {
125
- code: "PACKAGE_NOT_ALLOWED",
112
+ code: PACKAGE_NOT_ALLOWED,
126
113
  message: err.message || "Package is not in the allowed package list",
127
114
  },
128
115
  }, 403, corsHeaders);
129
116
  }
130
- return jsonResponse({ ok: false, error: { code: "PLAYBOOK_NOT_FOUND", message: err.message } }, 404, corsHeaders);
117
+ return jsonResponse({ ok: false, error: { code: PLAYBOOK_NOT_FOUND, message: err.message } }, 404, corsHeaders);
131
118
  }
132
119
  }
133
120
  return null;