@actiondock/core 2.5.1 → 2.7.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 (175) hide show
  1. package/dist/app/app.d.ts +14 -1
  2. package/dist/app/app.js +88 -222
  3. package/dist/app/static-index.d.ts +39 -0
  4. package/dist/app/static-index.js +164 -0
  5. package/dist/app/types.d.ts +5 -0
  6. package/dist/catalog/action-index.js +6 -4
  7. package/dist/catalog/package-catalog.js +2 -1
  8. package/dist/doctor/checks/index.d.ts +5 -0
  9. package/dist/doctor/checks/index.js +5 -0
  10. package/dist/doctor/checks/project-locate.d.ts +6 -0
  11. package/dist/doctor/checks/project-locate.js +36 -0
  12. package/dist/doctor/checks/project.d.ts +6 -0
  13. package/dist/doctor/checks/project.js +383 -0
  14. package/dist/doctor/checks/registry.d.ts +13 -0
  15. package/dist/doctor/checks/registry.js +207 -0
  16. package/dist/doctor/checks/runtime.d.ts +13 -0
  17. package/dist/doctor/checks/runtime.js +90 -0
  18. package/dist/doctor/checks/storage.d.ts +5 -0
  19. package/dist/doctor/checks/storage.js +34 -0
  20. package/dist/doctor/context.d.ts +35 -0
  21. package/dist/doctor/context.js +11 -0
  22. package/dist/doctor/doctor.d.ts +5 -0
  23. package/dist/doctor/doctor.js +33 -602
  24. package/dist/errors.d.ts +22 -0
  25. package/dist/errors.js +22 -0
  26. package/dist/execution/service.js +14 -9
  27. package/dist/export/templates.js +42 -30
  28. package/dist/host/host.d.ts +33 -0
  29. package/dist/host/host.js +222 -362
  30. package/dist/host/routing.d.ts +92 -0
  31. package/dist/host/routing.js +238 -0
  32. package/dist/host/types.d.ts +8 -0
  33. package/dist/index.d.ts +3 -1
  34. package/dist/index.js +3 -1
  35. package/dist/input/advice.d.ts +100 -0
  36. package/dist/input/advice.js +767 -0
  37. package/dist/input/describe.d.ts +106 -0
  38. package/dist/input/describe.js +176 -0
  39. package/dist/input/file-input.d.ts +54 -0
  40. package/dist/input/file-input.js +124 -0
  41. package/dist/input/flat-decode.d.ts +11 -0
  42. package/dist/input/flat-decode.js +13 -0
  43. package/dist/input/flat-errors.d.ts +72 -0
  44. package/dist/input/flat-errors.js +87 -0
  45. package/dist/input/flat-materializer.d.ts +29 -0
  46. package/dist/input/flat-materializer.js +179 -0
  47. package/dist/input/flat-parser.d.ts +50 -0
  48. package/dist/input/flat-parser.js +169 -0
  49. package/dist/input/flat-predicates.d.ts +34 -0
  50. package/dist/input/flat-predicates.js +50 -0
  51. package/dist/input/index.d.ts +14 -0
  52. package/dist/input/index.js +14 -0
  53. package/dist/input/input-resolver.d.ts +63 -0
  54. package/dist/input/input-resolver.js +254 -0
  55. package/dist/input/json-depth-scanner.d.ts +17 -0
  56. package/dist/input/json-depth-scanner.js +49 -0
  57. package/dist/input/metadata.d.ts +99 -0
  58. package/dist/input/metadata.js +99 -0
  59. package/dist/input/stdin-input.d.ts +26 -0
  60. package/dist/input/stdin-input.js +125 -0
  61. package/dist/input/utf8.d.ts +19 -0
  62. package/dist/input/utf8.js +36 -0
  63. package/dist/input/validation-mapper.d.ts +27 -0
  64. package/dist/input/validation-mapper.js +144 -0
  65. package/dist/ipc/host.js +38 -0
  66. package/dist/json/index.d.ts +1 -0
  67. package/dist/json/index.js +1 -0
  68. package/dist/json/value-validator.d.ts +88 -0
  69. package/dist/json/value-validator.js +330 -0
  70. package/dist/platform/types.d.ts +7 -0
  71. package/dist/process/control-arbiter.d.ts +107 -0
  72. package/dist/process/control-arbiter.js +251 -0
  73. package/dist/process/diagnostics-sink.d.ts +26 -0
  74. package/dist/process/diagnostics-sink.js +35 -0
  75. package/dist/process/index.d.ts +7 -0
  76. package/dist/process/index.js +7 -0
  77. package/dist/process/input-dispatcher.d.ts +88 -0
  78. package/dist/process/input-dispatcher.js +240 -0
  79. package/dist/process/managed-record.d.ts +78 -0
  80. package/dist/process/managed-record.js +1 -0
  81. package/dist/process/process-manager.d.ts +15 -56
  82. package/dist/process/process-manager.js +119 -707
  83. package/dist/process/reservation-table.d.ts +39 -0
  84. package/dist/process/reservation-table.js +80 -0
  85. package/dist/process/run-executor.d.ts +16 -0
  86. package/dist/process/run-executor.js +155 -0
  87. package/dist/process/terminal-output-cache.d.ts +66 -0
  88. package/dist/process/terminal-output-cache.js +132 -0
  89. package/dist/profile/client-actions.d.ts +56 -0
  90. package/dist/profile/client-actions.js +215 -0
  91. package/dist/profile/client-config.d.ts +20 -0
  92. package/dist/profile/client-config.js +51 -0
  93. package/dist/profile/client-health.d.ts +14 -0
  94. package/dist/profile/client-health.js +69 -0
  95. package/dist/profile/client-playbooks.d.ts +19 -0
  96. package/dist/profile/client-playbooks.js +36 -0
  97. package/dist/profile/client-query.d.ts +30 -0
  98. package/dist/profile/client-query.js +70 -0
  99. package/dist/profile/client-runs.d.ts +42 -0
  100. package/dist/profile/client-runs.js +58 -0
  101. package/dist/profile/client-state.d.ts +56 -0
  102. package/dist/profile/client-state.js +83 -0
  103. package/dist/profile/client-transport.d.ts +61 -0
  104. package/dist/profile/client-transport.js +156 -0
  105. package/dist/profile/client.d.ts +23 -142
  106. package/dist/profile/client.js +28 -588
  107. package/dist/profile/manager.js +1 -1
  108. package/dist/project/closure.d.ts +4 -4
  109. package/dist/project/closure.js +11 -5
  110. package/dist/project/init.js +2 -2
  111. package/dist/project/loader.d.ts +0 -25
  112. package/dist/project/loader.js +1 -154
  113. package/dist/project/transactions.d.ts +12 -14
  114. package/dist/project/transactions.js +60 -836
  115. package/dist/registry/registry.js +6 -4
  116. package/dist/registry/resolve.js +1 -1
  117. package/dist/runtime/action-registry.d.ts +45 -0
  118. package/dist/runtime/action-registry.js +108 -0
  119. package/dist/runtime/clock.d.ts +5 -17
  120. package/dist/runtime/clock.js +5 -15
  121. package/dist/runtime/context.d.ts +3 -0
  122. package/dist/runtime/context.js +17 -56
  123. package/dist/runtime/index.d.ts +3 -0
  124. package/dist/runtime/index.js +3 -0
  125. package/dist/runtime/package-runner-factory.d.ts +82 -0
  126. package/dist/runtime/package-runner-factory.js +186 -0
  127. package/dist/runtime/run-persistence.d.ts +85 -0
  128. package/dist/runtime/run-persistence.js +111 -0
  129. package/dist/runtime/runner.d.ts +25 -45
  130. package/dist/runtime/runner.js +130 -354
  131. package/dist/runtime/standalone.d.ts +25 -2
  132. package/dist/runtime/standalone.js +305 -87
  133. package/dist/schema/index.d.ts +1 -0
  134. package/dist/schema/index.js +1 -0
  135. package/dist/schema/validator.d.ts +10 -0
  136. package/dist/schema/validator.js +48 -54
  137. package/dist/server/dispatcher.d.ts +8 -3
  138. package/dist/server/dispatcher.js +16 -40
  139. package/dist/server/routes/runs.js +6 -4
  140. package/dist/server/security.d.ts +1 -7
  141. package/dist/server/security.js +2 -13
  142. package/dist/storage/clock.d.ts +25 -0
  143. package/dist/storage/clock.js +23 -0
  144. package/dist/storage/data-dir-lock.d.ts +3 -36
  145. package/dist/storage/data-dir-lock.js +48 -881
  146. package/dist/storage/index.d.ts +8 -1
  147. package/dist/storage/index.js +8 -2
  148. package/dist/storage/lazy.js +1 -0
  149. package/dist/storage/lock-core.d.ts +162 -0
  150. package/dist/storage/lock-core.js +885 -0
  151. package/dist/storage/sqlite.d.ts +19 -6
  152. package/dist/storage/sqlite.js +81 -89
  153. package/dist/storage/types.d.ts +27 -5
  154. package/dist/storage/types.js +21 -0
  155. package/dist/storage/utils.d.ts +22 -0
  156. package/dist/storage/utils.js +34 -0
  157. package/dist/target/local.d.ts +1 -0
  158. package/dist/target/local.js +23 -17
  159. package/dist/target/remote-errors.d.ts +21 -0
  160. package/dist/target/remote-errors.js +51 -0
  161. package/dist/target/remote-polling.d.ts +35 -0
  162. package/dist/target/remote-polling.js +104 -0
  163. package/dist/target/remote.d.ts +4 -0
  164. package/dist/target/remote.js +108 -301
  165. package/dist/target/sse-parser.d.ts +35 -0
  166. package/dist/target/sse-parser.js +163 -0
  167. package/dist/target/target.js +2 -0
  168. package/dist/target/types.d.ts +6 -0
  169. package/dist/utils/index.d.ts +1 -0
  170. package/dist/utils/index.js +1 -0
  171. package/dist/utils/net.d.ts +10 -0
  172. package/dist/utils/net.js +16 -0
  173. package/dist/version.d.ts +1 -1
  174. package/dist/version.js +1 -1
  175. package/package.json +2 -2
@@ -1,613 +1,44 @@
1
- import { existsSync, readFileSync, statSync } from "node:fs";
2
- import { dirname, join, relative } from "node:path";
3
- import { ActionResolver } from "../catalog/action-resolver.js";
4
- import { discoverActionFiles, findProjectRoot, loadActions, loadPlaybooks, loadProjectConfig } from "../project/loader.js";
5
- import { loadManifest, MANIFEST_FILE_NAME } from "../project/manifest.js";
6
- import { getRegistryStatus, listLinkedPackages, resolvePackageRoot } from "../registry/registry.js";
7
- import { createGlobalStorage, createStorage, resolveDatabasePath } from "../storage/index.js";
8
- import { findExecutable, getActionDockHome } from "../utils/index.js";
9
- function compareSemver(v1, v2) {
10
- const p1 = v1.replace(/^v/, "").split(".").map(Number);
11
- const p2 = v2.replace(/^v/, "").split(".").map(Number);
12
- for (let i = 0; i < Math.max(p1.length, p2.length); i++) {
13
- const num1 = p1[i] || 0;
14
- const num2 = p2[i] || 0;
15
- if (num1 > num2)
16
- return 1;
17
- if (num1 < num2)
18
- return -1;
19
- }
20
- return 0;
21
- }
1
+ import { createDoctorCheckContext } from "./context.js";
2
+ import { checkBunRuntime, checkCliExecutable, checkGlobalRegistry, checkGlobalStorage, checkLinkedPackageDependencies, checkNodeRuntime, checkProject, checkUsesClosure, locateProject, } from "./checks/index.js";
3
+ /**
4
+ * 检查注册表:按诊断执行顺序排列的检查阶段。
5
+ * 运行时 存储 注册表 → 工程定位 → 工程级详情,与报告展示顺序一一对应。
6
+ */
7
+ const doctorCheckRegistry = [
8
+ checkNodeRuntime,
9
+ checkBunRuntime,
10
+ checkCliExecutable,
11
+ checkGlobalStorage,
12
+ checkGlobalRegistry,
13
+ checkLinkedPackageDependencies,
14
+ checkUsesClosure,
15
+ locateProject,
16
+ checkProject,
17
+ ];
18
+ /**
19
+ * 执行环境与依赖体检诊断。
20
+ * 按注册表顺序执行各检查阶段(各阶段自行兜底异常,转为对应检查项呈现),
21
+ * 最终汇总各状态计数并输出结构化诊断报告。
22
+ */
22
23
  export async function runDoctorChecks(options) {
23
- const cwd = options?.cwd || process.cwd();
24
- const checks = [];
25
- // 1. Check Node.js Runtime
26
- const nodeVersion = process.versions.node;
27
- if (nodeVersion) {
28
- const isGte24 = compareSemver(nodeVersion, "24.12.0") >= 0;
29
- checks.push({
30
- id: "runtime.node",
31
- category: "runtime",
32
- name: "Node.js Runtime",
33
- status: isGte24 ? "ok" : "warn",
34
- message: `v${nodeVersion} (${isGte24 ? ">= 24.12.0 supported" : ">= 24.12.0 recommended"})`,
35
- fix: isGte24 ? undefined : "Upgrade Node.js to v24.12.0 or higher",
36
- });
37
- }
38
- // 2. Check Bun Runtime (Optional environment for cross-runtime compatibility testing)
39
- const bunVersion = (typeof globalThis.Bun !== "undefined" && globalThis.Bun.version) || process.versions.bun;
40
- if (bunVersion) {
41
- checks.push({
42
- id: "runtime.bun",
43
- category: "runtime",
44
- name: "Bun Runtime",
45
- status: "ok",
46
- message: `v${bunVersion} (available for cross-environment testing)`,
47
- });
48
- }
49
- else {
50
- checks.push({
51
- id: "runtime.bun",
52
- category: "runtime",
53
- name: "Bun Runtime",
54
- status: "ok",
55
- message: "Bun runtime not detected (optional, used for cross-environment compatibility testing)",
56
- });
57
- }
58
- // 3. Check CLI in PATH
59
- const adPath = findExecutable("ad");
60
- if (adPath) {
61
- checks.push({
62
- id: "runtime.cli",
63
- category: "runtime",
64
- name: "CLI Executable",
65
- status: "ok",
66
- message: `Found 'ad' in PATH at ${adPath}`,
67
- });
68
- }
69
- else {
70
- checks.push({
71
- id: "runtime.cli",
72
- category: "runtime",
73
- name: "CLI Executable",
74
- status: "warn",
75
- message: "'ad' command not found in PATH",
76
- fix: "Run 'npm install -g @actiondock/cli' or in SDK workspace run 'cd packages/cli && npm link'",
77
- });
78
- }
79
- // 3. Check Global Storage
80
- const globalHome = getActionDockHome(options?.customHome);
81
- try {
82
- const globalStorage = createGlobalStorage(options?.customHome);
83
- await globalStorage.setConfig("_doctor_probe_", "ok");
84
- await globalStorage.deleteConfig("_doctor_probe_");
85
- globalStorage.close();
86
- checks.push({
87
- id: "storage.global",
88
- category: "storage",
89
- name: "Global Storage",
90
- status: "ok",
91
- message: `Global SQLite database verified at ${globalHome}`,
92
- });
93
- }
94
- catch (err) {
95
- checks.push({
96
- id: "storage.global",
97
- category: "storage",
98
- name: "Global Storage",
99
- status: "error",
100
- message: `Failed to access global storage: ${err.message}`,
101
- fix: `Ensure directory '${globalHome}' is writable`,
102
- });
103
- }
104
- // 4. Check Global Registry Health
105
- try {
106
- const regStatus = getRegistryStatus(options?.customHome);
107
- if (regStatus.staleCount > 0) {
108
- checks.push({
109
- id: "registry.global",
110
- category: "registry",
111
- name: "Global Registry",
112
- status: "warn",
113
- message: `${regStatus.totalPackagesCount} package(s), ${regStatus.workspaces.length} workspace(s), but ${regStatus.staleCount} stale path(s) detected`,
114
- fix: "Run 'ad unlink --prune' to clean up stale entries from registry",
115
- });
116
- }
117
- else {
118
- checks.push({
119
- id: "registry.global",
120
- category: "registry",
121
- name: "Global Registry",
122
- status: "ok",
123
- message: `${regStatus.totalPackagesCount} linked package(s), ${regStatus.workspaces.length} workspace(s) (0 stale)`,
124
- });
125
- }
126
- }
127
- catch (err) {
128
- checks.push({
129
- id: "registry.global",
130
- category: "registry",
131
- name: "Global Registry",
132
- status: "error",
133
- message: `Failed to read registry: ${err.message}`,
134
- });
135
- }
136
- // 5. Check Linked Package Dependencies (node_modules completeness)
137
- try {
138
- let linkedList = listLinkedPackages(options?.customHome);
139
- if (options?.packageAllowlist && options.packageAllowlist.length > 0) {
140
- linkedList = linkedList.filter((pkg) => options.packageAllowlist.includes(pkg.id));
141
- }
142
- const missingNodeModules = [];
143
- for (const pkg of linkedList) {
144
- if (!existsSync(pkg.path))
145
- continue;
146
- const pkgJsonPath = join(pkg.path, "package.json");
147
- if (!existsSync(pkgJsonPath))
148
- continue;
149
- try {
150
- const pkgJson = JSON.parse(readFileSync(pkgJsonPath, "utf-8"));
151
- const hasDeps = (pkgJson.dependencies && Object.keys(pkgJson.dependencies).length > 0) ||
152
- (pkgJson.devDependencies && Object.keys(pkgJson.devDependencies).length > 0);
153
- if (hasDeps && !existsSync(join(pkg.path, "node_modules"))) {
154
- missingNodeModules.push(pkg.id);
155
- }
156
- }
157
- catch {
158
- // 忽略异常 JSON
159
- }
160
- }
161
- if (missingNodeModules.length > 0) {
162
- checks.push({
163
- id: "registry.dependencies",
164
- category: "registry",
165
- name: "Linked Package Dependencies",
166
- status: "warn",
167
- message: `${missingNodeModules.length} linked package(s) declare dependencies but miss node_modules: ${missingNodeModules.join(", ")}`,
168
- fix: "Run 'npm install' in the affected package directories, or execute 'ad run' to auto-install",
169
- });
170
- }
171
- else {
172
- checks.push({
173
- id: "registry.dependencies",
174
- category: "registry",
175
- name: "Linked Package Dependencies",
176
- status: "ok",
177
- message: linkedList.length > 0
178
- ? "All linked packages have dependencies installed"
179
- : "No linked packages requiring dependency verification",
180
- });
181
- }
182
- }
183
- catch {
184
- // 忽略依赖检查异常
185
- }
186
- // 6. Check Cross-Package Uses Dependency Closure
187
- try {
188
- let linkedList = listLinkedPackages(options?.customHome);
189
- if (options?.packageAllowlist && options.packageAllowlist.length > 0) {
190
- linkedList = linkedList.filter((pkg) => options.packageAllowlist.includes(pkg.id));
191
- }
192
- let packagesToCheck = linkedList.map((p) => ({
193
- id: p.id,
194
- root: p.path,
195
- }));
196
- const curProjectRoot = options?.packageIdOrPath
197
- ? resolvePackageRoot(options.packageIdOrPath, cwd, options?.customHome) || findProjectRoot(options.packageIdOrPath)
198
- : findProjectRoot(cwd);
199
- if (curProjectRoot && !packagesToCheck.some((p) => p.root === curProjectRoot)) {
200
- try {
201
- const cfg = loadProjectConfig(curProjectRoot);
202
- packagesToCheck.push({ id: cfg.id, root: curProjectRoot });
203
- }
204
- catch {
205
- // 忽略配置异常
206
- }
207
- }
208
- if (options?.packageAllowlist && options.packageAllowlist.length > 0) {
209
- packagesToCheck = packagesToCheck.filter((p) => options.packageAllowlist.includes(p.id));
210
- }
211
- const unresolvableUses = [];
212
- for (const pkg of packagesToCheck) {
213
- if (!existsSync(pkg.root))
214
- continue;
215
- const manifest = loadManifest(pkg.root);
216
- if (!manifest || !manifest.actions)
217
- continue;
218
- for (const [actionId, actionEntry] of Object.entries(manifest.actions)) {
219
- if (!Array.isArray(actionEntry.uses))
220
- continue;
221
- for (const rawRef of actionEntry.uses) {
222
- if (typeof rawRef !== "string" || !rawRef.trim())
223
- continue;
224
- let parsed;
225
- try {
226
- parsed = ActionResolver.parseRef(rawRef);
227
- }
228
- catch {
229
- unresolvableUses.push(`${pkg.id}/${actionId} -> '${rawRef}'`);
230
- continue;
231
- }
232
- if (parsed.packageId) {
233
- const depRoot = resolvePackageRoot(parsed.packageId, pkg.root, options?.customHome);
234
- if (!depRoot || !existsSync(depRoot)) {
235
- unresolvableUses.push(`${pkg.id}/${actionId} -> '${rawRef}'`);
236
- }
237
- }
238
- }
239
- }
240
- }
241
- if (unresolvableUses.length > 0) {
242
- checks.push({
243
- id: "registry.uses_closure",
244
- category: "registry",
245
- name: "Cross-Package Uses Dependencies",
246
- status: "warn",
247
- message: `${unresolvableUses.length} unresolvable cross-package dependency reference(s) found in manifest uses: ${unresolvableUses.join(", ")}`,
248
- fix: "Link missing packages with 'ad link', or correct unresolvable uses declarations",
249
- });
250
- }
251
- else {
252
- checks.push({
253
- id: "registry.uses_closure",
254
- category: "registry",
255
- name: "Cross-Package Uses Dependencies",
256
- status: "ok",
257
- message: "All cross-package uses declarations in manifests resolved successfully",
258
- });
259
- }
260
- }
261
- catch {
262
- // 忽略闭包检查异常
263
- }
264
- // 7. Check Project Context
265
- let projectRoot = null;
266
- if (options?.packageIdOrPath) {
267
- projectRoot =
268
- resolvePackageRoot(options.packageIdOrPath, cwd, options?.customHome) ||
269
- findProjectRoot(options.packageIdOrPath);
270
- }
271
- else {
272
- projectRoot = findProjectRoot(cwd);
273
- }
274
- let packageId;
275
- if (projectRoot) {
276
- try {
277
- const config = loadProjectConfig(projectRoot);
278
- if (options?.packageAllowlist &&
279
- Array.isArray(options.packageAllowlist) &&
280
- options.packageAllowlist.length > 0 &&
281
- !options.packageAllowlist.includes(config.id)) {
282
- projectRoot = null;
283
- }
284
- }
285
- catch {
286
- // 忽略预校验异常,交由后续详细诊断处理
287
- }
288
- }
289
- if (projectRoot) {
290
- try {
291
- const config = loadProjectConfig(projectRoot);
292
- packageId = config.id;
293
- // Project Config Check
294
- checks.push({
295
- id: "project.config",
296
- category: "project",
297
- name: "Project Configuration",
298
- status: "ok",
299
- message: `Valid (${config.id} v${config.version})`,
300
- });
301
- // SDK Resolution Check
302
- const hasSdkInNodeModules = existsSync(join(projectRoot, "node_modules", "@actiondock", "sdk")) ||
303
- existsSync(join(projectRoot, "node_modules", "@actiondock", "sdk", "package.json"));
304
- if (hasSdkInNodeModules) {
305
- checks.push({
306
- id: "project.sdk",
307
- category: "project",
308
- name: "SDK Dependency",
309
- status: "ok",
310
- message: "Resolved @actiondock/sdk in node_modules",
311
- });
312
- }
313
- else {
314
- checks.push({
315
- id: "project.sdk",
316
- category: "project",
317
- name: "SDK Dependency",
318
- status: "warn",
319
- message: "@actiondock/sdk not found in project node_modules",
320
- fix: "Run 'npm link @actiondock/sdk' or 'npm install' in project directory",
321
- });
322
- }
323
- // Project Runtime Database Check
324
- const dbPath = resolveDatabasePath(config.id, { customHome: options?.customHome });
325
- try {
326
- const projectStorage = createStorage(config.id, { customHome: options?.customHome });
327
- await projectStorage.setConfig("_doctor_probe_", "ok");
328
- await projectStorage.deleteConfig("_doctor_probe_");
329
- projectStorage.close();
330
- checks.push({
331
- id: "project.storage",
332
- category: "project",
333
- name: "Project Database",
334
- status: "ok",
335
- message: `Database writable at ${dbPath}`,
336
- });
337
- }
338
- catch (err) {
339
- checks.push({
340
- id: "project.storage",
341
- category: "project",
342
- name: "Project Database",
343
- status: "error",
344
- message: `Failed to write project runtime database: ${err.message}`,
345
- fix: `Check write permissions for '${dirname(dbPath)}'`,
346
- });
347
- }
348
- // Actions Check
349
- try {
350
- const manifest = loadManifest(projectRoot);
351
- let actionsCount = 0;
352
- if (manifest?.actions) {
353
- actionsCount = Object.keys(manifest.actions).length;
354
- }
355
- else {
356
- const actions = await loadActions(projectRoot, config.actionsDir, { autoInstall: false });
357
- actionsCount = actions.size;
358
- }
359
- if (actionsCount === 0) {
360
- checks.push({
361
- id: "project.actions",
362
- category: "project",
363
- name: "Actions",
364
- status: "warn",
365
- message: `No actions found in '${config.actionsDir || "actions"}'`,
366
- fix: "Run 'ad action new <id>' to create your first action",
367
- });
368
- }
369
- else {
370
- checks.push({
371
- id: "project.actions",
372
- category: "project",
373
- name: "Actions",
374
- status: "ok",
375
- message: `${actionsCount} action(s) valid and loaded`,
376
- });
377
- }
378
- }
379
- catch (err) {
380
- checks.push({
381
- id: "project.actions",
382
- category: "project",
383
- name: "Actions",
384
- status: "error",
385
- message: `Failed to load actions: ${err.message}`,
386
- });
387
- }
388
- // Project Manifest Check (Lightweight Static Detection)
389
- try {
390
- const manifestPath = join(projectRoot, MANIFEST_FILE_NAME);
391
- const manifest = loadManifest(projectRoot);
392
- const actionFiles = discoverActionFiles(projectRoot, config.actionsDir || "actions");
393
- if (!existsSync(manifestPath)) {
394
- if (actionFiles.length > 0) {
395
- checks.push({
396
- id: "project.manifest",
397
- category: "project",
398
- name: "Action Manifest",
399
- status: "warn",
400
- message: `${MANIFEST_FILE_NAME} not found (${actionFiles.length} action source file(s) exist)`,
401
- fix: "Run 'ad validate' to generate or check manifest",
402
- });
403
- }
404
- }
405
- else if (manifest && manifest.actions) {
406
- const missingFiles = Object.entries(manifest.actions)
407
- .filter(([_, item]) => !existsSync(join(projectRoot, item.entry)))
408
- .map(([id, item]) => `${id} (${item.entry})`);
409
- const manifestEntries = new Set(Object.values(manifest.actions).map((a) => a.entry.replace(/\\/g, "/")));
410
- const untracked = actionFiles
411
- .map((f) => relative(projectRoot, f).replace(/\\/g, "/"))
412
- .filter((rel) => !manifestEntries.has(rel));
413
- if (missingFiles.length > 0) {
414
- checks.push({
415
- id: "project.manifest",
416
- category: "project",
417
- name: "Action Manifest",
418
- status: "warn",
419
- message: `${missingFiles.length} action(s) in manifest point to missing files: ${missingFiles.join(", ")}`,
420
- fix: "Run 'ad validate' to check or update actiondock.json",
421
- });
422
- }
423
- else if (untracked.length > 0) {
424
- checks.push({
425
- id: "project.manifest",
426
- category: "project",
427
- name: "Action Manifest",
428
- status: "warn",
429
- message: `${untracked.length} action file(s) not declared in manifest: ${untracked.join(", ")}`,
430
- fix: "Run 'ad validate' to check or update actiondock.json",
431
- });
432
- }
433
- else {
434
- const manifestStat = statSync(manifestPath);
435
- const newerFiles = actionFiles.filter((f) => statSync(f).mtimeMs > manifestStat.mtimeMs + 2000);
436
- if (newerFiles.length > 0) {
437
- checks.push({
438
- id: "project.manifest",
439
- category: "project",
440
- name: "Action Manifest",
441
- status: "ok",
442
- message: `Manifest valid (Note: ${newerFiles.length} action file(s) modified after manifest; run 'ad validate' if definitions changed)`,
443
- });
444
- }
445
- else {
446
- checks.push({
447
- id: "project.manifest",
448
- category: "project",
449
- name: "Action Manifest",
450
- status: "ok",
451
- message: "Manifest synchronized with action files",
452
- });
453
- }
454
- }
455
- }
456
- }
457
- catch (err) {
458
- checks.push({
459
- id: "project.manifest",
460
- category: "project",
461
- name: "Action Manifest",
462
- status: "error",
463
- message: `Failed to inspect manifest: ${err.message}`,
464
- });
465
- }
466
- // Project Declared Files & Source Boundaries Check
467
- try {
468
- const declaredFiles = config.files || [];
469
- const hasSrc = existsSync(join(projectRoot, "src"));
470
- const hasLib = existsSync(join(projectRoot, "lib"));
471
- if (declaredFiles.length > 0) {
472
- const missingDeclared = declaredFiles.filter((f) => !existsSync(join(projectRoot, f)));
473
- if (missingDeclared.length > 0) {
474
- checks.push({
475
- id: "project.files",
476
- category: "project",
477
- name: "Declared Files",
478
- status: "error",
479
- message: `${missingDeclared.length} path(s) declared in 'files' do not exist: ${missingDeclared.join(", ")}`,
480
- fix: `Verify and update 'files' in ${MANIFEST_FILE_NAME}`,
481
- });
482
- }
483
- else {
484
- checks.push({
485
- id: "project.files",
486
- category: "project",
487
- name: "Declared Files",
488
- status: "ok",
489
- message: `All ${declaredFiles.length} declared file/directory boundaries verified`,
490
- });
491
- }
492
- }
493
- else if (hasSrc || hasLib) {
494
- const actionFiles = discoverActionFiles(projectRoot, config.actionsDir || "actions");
495
- let hasReferenceToSrcOrLib = false;
496
- for (const actFile of actionFiles) {
497
- try {
498
- const src = readFileSync(actFile, "utf-8");
499
- if (/['"](?:\.\.\/(?:src|lib)|\.\/(?:src|lib))[^'"]*['"]/.test(src)) {
500
- hasReferenceToSrcOrLib = true;
501
- break;
502
- }
503
- }
504
- catch {
505
- // 忽略单个文件读取异常
506
- }
507
- }
508
- if (hasReferenceToSrcOrLib) {
509
- checks.push({
510
- id: "project.files",
511
- category: "project",
512
- name: "Declared Files",
513
- status: "error",
514
- message: `Actions import modules from ${hasSrc ? "'src/'" : ""}${hasSrc && hasLib ? " and " : ""}${hasLib ? "'lib/'" : ""}, but 'files' is not declared in ${MANIFEST_FILE_NAME}`,
515
- fix: `Add "files": [${hasSrc ? '"src"' : ""}${hasSrc && hasLib ? ', "lib"' : hasLib && !hasSrc ? '"lib"' : ""}] to ${MANIFEST_FILE_NAME}`,
516
- });
517
- }
518
- else {
519
- checks.push({
520
- id: "project.files",
521
- category: "project",
522
- name: "Declared Files",
523
- status: "ok",
524
- message: `Project source directories clean (no undeclared references to ${hasSrc ? "src/" : "lib/"})`,
525
- });
526
- }
527
- }
528
- }
529
- catch {
530
- // 忽略文件边界检测异常
531
- }
532
- // Playbooks Check
533
- try {
534
- const playbooks = loadPlaybooks(projectRoot, config.playbooksDir);
535
- checks.push({
536
- id: "project.playbooks",
537
- category: "project",
538
- name: "Playbooks",
539
- status: "ok",
540
- message: `${playbooks.size} playbook(s) valid`,
541
- });
542
- }
543
- catch (err) {
544
- checks.push({
545
- id: "project.playbooks",
546
- category: "project",
547
- name: "Playbooks",
548
- status: "warn",
549
- message: `Playbooks issue: ${err.message}`,
550
- });
551
- }
552
- // Config readiness check
553
- if (config.config && Object.keys(config.config).length > 0) {
554
- const missingKeys = [];
555
- const projectStorage = createStorage(config.id, { customHome: options?.customHome });
556
- for (const [key, def] of Object.entries(config.config)) {
557
- const inStorage = await projectStorage.getConfig(key);
558
- const envNames = Array.isArray(def.env) ? def.env : def.env ? [def.env] : [key];
559
- const inEnv = envNames.some((e) => process.env[e] !== undefined);
560
- const isRequired = def.required || (def.default === undefined && def.secret);
561
- if ((isRequired || def.default === undefined) && inStorage === undefined && !inEnv) {
562
- missingKeys.push(key);
563
- }
564
- }
565
- projectStorage.close();
566
- if (missingKeys.length > 0) {
567
- checks.push({
568
- id: "project.config_readiness",
569
- category: "project",
570
- name: "Config Readiness",
571
- status: "warn",
572
- message: `Required config item(s) missing: ${missingKeys.join(", ")}`,
573
- fix: `Run 'ad config set <KEY> <VALUE>' to configure missing keys`,
574
- });
575
- }
576
- else {
577
- checks.push({
578
- id: "project.config_readiness",
579
- category: "project",
580
- name: "Config Readiness",
581
- status: "ok",
582
- message: "All declared configuration dependencies satisfied",
583
- });
584
- }
585
- }
586
- }
587
- catch (err) {
588
- checks.push({
589
- id: "project.config",
590
- category: "project",
591
- name: "Project Configuration",
592
- status: "error",
593
- message: `Invalid actiondock.json: ${err.message}`,
594
- });
595
- }
24
+ const ctx = createDoctorCheckContext(options);
25
+ for (const check of doctorCheckRegistry) {
26
+ await check.run(ctx);
596
27
  }
597
- const okCount = checks.filter((c) => c.status === "ok").length;
598
- const warnCount = checks.filter((c) => c.status === "warn").length;
599
- const errorCount = checks.filter((c) => c.status === "error").length;
28
+ const okCount = ctx.checks.filter((c) => c.status === "ok").length;
29
+ const warnCount = ctx.checks.filter((c) => c.status === "warn").length;
30
+ const errorCount = ctx.checks.filter((c) => c.status === "error").length;
600
31
  return {
601
32
  ok: errorCount === 0,
602
- hasProject: !!projectRoot,
603
- projectRoot: projectRoot || undefined,
604
- packageId,
33
+ hasProject: !!ctx.projectRoot,
34
+ projectRoot: ctx.projectRoot || undefined,
35
+ packageId: ctx.packageId,
605
36
  summary: {
606
- total: checks.length,
37
+ total: ctx.checks.length,
607
38
  ok: okCount,
608
39
  warn: warnCount,
609
40
  error: errorCount,
610
41
  },
611
- checks,
42
+ checks: ctx.checks,
612
43
  };
613
44
  }
package/dist/errors.d.ts CHANGED
@@ -61,6 +61,8 @@ export declare const EXECUTION_ABORTED = "EXECUTION_ABORTED";
61
61
  export declare const TIMEOUT = "TIMEOUT";
62
62
  /** 远程服务器网络连接失败 */
63
63
  export declare const NETWORK_ERROR = "NETWORK_ERROR";
64
+ /** 远程事件流全部候选路由均不可用 */
65
+ export declare const REMOTE_STREAM_UNAVAILABLE = "REMOTE_STREAM_UNAVAILABLE";
64
66
  /** 远程目标未启用管理接口能力 */
65
67
  export declare const CAPABILITY_UNAVAILABLE = "CAPABILITY_UNAVAILABLE";
66
68
  /** 远程状态键不存在 */
@@ -150,6 +152,26 @@ export declare const QUEUE_FULL = "QUEUE_FULL";
150
152
  export declare const QUOTA_EXCEEDED = "QUOTA_EXCEEDED";
151
153
  /** 输入通道已关闭拒绝继续写入 */
152
154
  export declare const INPUT_CLOSED = "INPUT_CLOSED";
155
+ /** 扁平入参赋值表达式格式非法 */
156
+ export declare const INVALID_FLAT_ARGUMENT = "INVALID_FLAT_ARGUMENT";
157
+ /** 完整 JSON 文档解析失败 */
158
+ export declare const INVALID_JSON = "INVALID_JSON";
159
+ /** JSON 字面量解析失败或包含非有限数值 */
160
+ export declare const INVALID_JSON_LITERAL = "INVALID_JSON_LITERAL";
161
+ /** 扁平入参路径冲突 */
162
+ export declare const INPUT_PATH_CONFLICT = "INPUT_PATH_CONFLICT";
163
+ /** 扁平入参超出安全阈值上限 */
164
+ export declare const FLAT_INPUT_LIMIT_EXCEEDED = "FLAT_INPUT_LIMIT_EXCEEDED";
165
+ /** 输入数据超出上限(字节大小、嵌套深度等) */
166
+ export declare const INPUT_LIMIT_EXCEEDED = "INPUT_LIMIT_EXCEEDED";
167
+ /** 输入违反 ActionDock 安全策略(如包含全局禁止属性) */
168
+ export declare const INPUT_POLICY_VIOLATION = "INPUT_POLICY_VIOLATION";
169
+ /** 输入源互斥冲突 */
170
+ export declare const INPUT_CONFLICT = "INPUT_CONFLICT";
171
+ /** 输入文件不存在 */
172
+ export declare const INPUT_FILE_NOT_FOUND = "INPUT_FILE_NOT_FOUND";
173
+ /** 输入文件或流读取失败 */
174
+ export declare const INPUT_FILE_READ_FAILED = "INPUT_FILE_READ_FAILED";
153
175
  /**
154
176
  * 进程领域结构化异常类。
155
177
  */