@actiondock/core 2.5.0 → 2.6.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 (134) hide show
  1. package/dist/app/app.d.ts +14 -1
  2. package/dist/app/app.js +88 -215
  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 +2 -0
  25. package/dist/errors.js +2 -0
  26. package/dist/execution/service.js +14 -9
  27. package/dist/host/host.d.ts +33 -0
  28. package/dist/host/host.js +222 -362
  29. package/dist/host/routing.d.ts +92 -0
  30. package/dist/host/routing.js +238 -0
  31. package/dist/host/types.d.ts +8 -0
  32. package/dist/ipc/host.js +38 -0
  33. package/dist/platform/types.d.ts +7 -0
  34. package/dist/process/control-arbiter.d.ts +107 -0
  35. package/dist/process/control-arbiter.js +251 -0
  36. package/dist/process/diagnostics-sink.d.ts +26 -0
  37. package/dist/process/diagnostics-sink.js +35 -0
  38. package/dist/process/index.d.ts +7 -0
  39. package/dist/process/index.js +7 -0
  40. package/dist/process/input-dispatcher.d.ts +88 -0
  41. package/dist/process/input-dispatcher.js +240 -0
  42. package/dist/process/managed-record.d.ts +78 -0
  43. package/dist/process/managed-record.js +1 -0
  44. package/dist/process/process-manager.d.ts +15 -56
  45. package/dist/process/process-manager.js +119 -707
  46. package/dist/process/reservation-table.d.ts +39 -0
  47. package/dist/process/reservation-table.js +80 -0
  48. package/dist/process/run-executor.d.ts +16 -0
  49. package/dist/process/run-executor.js +155 -0
  50. package/dist/process/terminal-output-cache.d.ts +66 -0
  51. package/dist/process/terminal-output-cache.js +132 -0
  52. package/dist/profile/client-actions.d.ts +56 -0
  53. package/dist/profile/client-actions.js +215 -0
  54. package/dist/profile/client-config.d.ts +20 -0
  55. package/dist/profile/client-config.js +51 -0
  56. package/dist/profile/client-health.d.ts +14 -0
  57. package/dist/profile/client-health.js +68 -0
  58. package/dist/profile/client-playbooks.d.ts +19 -0
  59. package/dist/profile/client-playbooks.js +36 -0
  60. package/dist/profile/client-query.d.ts +30 -0
  61. package/dist/profile/client-query.js +70 -0
  62. package/dist/profile/client-runs.d.ts +42 -0
  63. package/dist/profile/client-runs.js +58 -0
  64. package/dist/profile/client-state.d.ts +56 -0
  65. package/dist/profile/client-state.js +83 -0
  66. package/dist/profile/client-transport.d.ts +61 -0
  67. package/dist/profile/client-transport.js +155 -0
  68. package/dist/profile/client.d.ts +23 -142
  69. package/dist/profile/client.js +28 -588
  70. package/dist/profile/manager.js +1 -1
  71. package/dist/project/closure.d.ts +4 -4
  72. package/dist/project/closure.js +11 -5
  73. package/dist/project/init.js +2 -2
  74. package/dist/project/loader.d.ts +0 -25
  75. package/dist/project/loader.js +1 -154
  76. package/dist/project/transactions.d.ts +12 -14
  77. package/dist/project/transactions.js +60 -836
  78. package/dist/registry/registry.js +6 -4
  79. package/dist/registry/resolve.js +1 -1
  80. package/dist/runtime/action-registry.d.ts +45 -0
  81. package/dist/runtime/action-registry.js +108 -0
  82. package/dist/runtime/clock.d.ts +5 -17
  83. package/dist/runtime/clock.js +5 -15
  84. package/dist/runtime/context.d.ts +3 -0
  85. package/dist/runtime/context.js +17 -56
  86. package/dist/runtime/index.d.ts +3 -0
  87. package/dist/runtime/index.js +3 -0
  88. package/dist/runtime/package-runner-factory.d.ts +82 -0
  89. package/dist/runtime/package-runner-factory.js +186 -0
  90. package/dist/runtime/run-persistence.d.ts +85 -0
  91. package/dist/runtime/run-persistence.js +111 -0
  92. package/dist/runtime/runner.d.ts +23 -33
  93. package/dist/runtime/runner.js +92 -286
  94. package/dist/runtime/standalone.d.ts +11 -1
  95. package/dist/runtime/standalone.js +137 -25
  96. package/dist/server/dispatcher.d.ts +8 -3
  97. package/dist/server/dispatcher.js +16 -40
  98. package/dist/server/routes/runs.js +6 -4
  99. package/dist/server/security.d.ts +1 -7
  100. package/dist/server/security.js +2 -13
  101. package/dist/storage/clock.d.ts +25 -0
  102. package/dist/storage/clock.js +23 -0
  103. package/dist/storage/data-dir-lock.d.ts +3 -36
  104. package/dist/storage/data-dir-lock.js +48 -881
  105. package/dist/storage/index.d.ts +8 -1
  106. package/dist/storage/index.js +8 -2
  107. package/dist/storage/lazy.js +1 -0
  108. package/dist/storage/lock-core.d.ts +162 -0
  109. package/dist/storage/lock-core.js +885 -0
  110. package/dist/storage/sqlite.d.ts +19 -6
  111. package/dist/storage/sqlite.js +81 -89
  112. package/dist/storage/types.d.ts +27 -5
  113. package/dist/storage/types.js +21 -0
  114. package/dist/storage/utils.d.ts +22 -0
  115. package/dist/storage/utils.js +34 -0
  116. package/dist/target/local.d.ts +1 -0
  117. package/dist/target/local.js +23 -17
  118. package/dist/target/remote-errors.d.ts +21 -0
  119. package/dist/target/remote-errors.js +51 -0
  120. package/dist/target/remote-polling.d.ts +35 -0
  121. package/dist/target/remote-polling.js +104 -0
  122. package/dist/target/remote.d.ts +4 -0
  123. package/dist/target/remote.js +108 -301
  124. package/dist/target/sse-parser.d.ts +35 -0
  125. package/dist/target/sse-parser.js +163 -0
  126. package/dist/target/target.js +2 -0
  127. package/dist/target/types.d.ts +6 -0
  128. package/dist/utils/index.d.ts +1 -0
  129. package/dist/utils/index.js +1 -0
  130. package/dist/utils/net.d.ts +10 -0
  131. package/dist/utils/net.js +16 -0
  132. package/dist/version.d.ts +1 -1
  133. package/dist/version.js +1 -1
  134. 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
  /** 远程状态键不存在 */
package/dist/errors.js CHANGED
@@ -61,6 +61,8 @@ export const EXECUTION_ABORTED = "EXECUTION_ABORTED";
61
61
  export const TIMEOUT = "TIMEOUT";
62
62
  /** 远程服务器网络连接失败 */
63
63
  export const NETWORK_ERROR = "NETWORK_ERROR";
64
+ /** 远程事件流全部候选路由均不可用 */
65
+ export const REMOTE_STREAM_UNAVAILABLE = "REMOTE_STREAM_UNAVAILABLE";
64
66
  /** 远程目标未启用管理接口能力 */
65
67
  export const CAPABILITY_UNAVAILABLE = "CAPABILITY_UNAVAILABLE";
66
68
  /** 远程状态键不存在 */