@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.
- package/dist/app/app.d.ts +14 -1
- package/dist/app/app.js +88 -215
- package/dist/app/static-index.d.ts +39 -0
- package/dist/app/static-index.js +164 -0
- package/dist/app/types.d.ts +5 -0
- package/dist/catalog/action-index.js +6 -4
- package/dist/catalog/package-catalog.js +2 -1
- package/dist/doctor/checks/index.d.ts +5 -0
- package/dist/doctor/checks/index.js +5 -0
- package/dist/doctor/checks/project-locate.d.ts +6 -0
- package/dist/doctor/checks/project-locate.js +36 -0
- package/dist/doctor/checks/project.d.ts +6 -0
- package/dist/doctor/checks/project.js +383 -0
- package/dist/doctor/checks/registry.d.ts +13 -0
- package/dist/doctor/checks/registry.js +207 -0
- package/dist/doctor/checks/runtime.d.ts +13 -0
- package/dist/doctor/checks/runtime.js +90 -0
- package/dist/doctor/checks/storage.d.ts +5 -0
- package/dist/doctor/checks/storage.js +34 -0
- package/dist/doctor/context.d.ts +35 -0
- package/dist/doctor/context.js +11 -0
- package/dist/doctor/doctor.d.ts +5 -0
- package/dist/doctor/doctor.js +33 -602
- package/dist/errors.d.ts +2 -0
- package/dist/errors.js +2 -0
- package/dist/execution/service.js +14 -9
- package/dist/host/host.d.ts +33 -0
- package/dist/host/host.js +222 -362
- package/dist/host/routing.d.ts +92 -0
- package/dist/host/routing.js +238 -0
- package/dist/host/types.d.ts +8 -0
- package/dist/ipc/host.js +38 -0
- package/dist/platform/types.d.ts +7 -0
- package/dist/process/control-arbiter.d.ts +107 -0
- package/dist/process/control-arbiter.js +251 -0
- package/dist/process/diagnostics-sink.d.ts +26 -0
- package/dist/process/diagnostics-sink.js +35 -0
- package/dist/process/index.d.ts +7 -0
- package/dist/process/index.js +7 -0
- package/dist/process/input-dispatcher.d.ts +88 -0
- package/dist/process/input-dispatcher.js +240 -0
- package/dist/process/managed-record.d.ts +78 -0
- package/dist/process/managed-record.js +1 -0
- package/dist/process/process-manager.d.ts +15 -56
- package/dist/process/process-manager.js +119 -707
- package/dist/process/reservation-table.d.ts +39 -0
- package/dist/process/reservation-table.js +80 -0
- package/dist/process/run-executor.d.ts +16 -0
- package/dist/process/run-executor.js +155 -0
- package/dist/process/terminal-output-cache.d.ts +66 -0
- package/dist/process/terminal-output-cache.js +132 -0
- package/dist/profile/client-actions.d.ts +56 -0
- package/dist/profile/client-actions.js +215 -0
- package/dist/profile/client-config.d.ts +20 -0
- package/dist/profile/client-config.js +51 -0
- package/dist/profile/client-health.d.ts +14 -0
- package/dist/profile/client-health.js +68 -0
- package/dist/profile/client-playbooks.d.ts +19 -0
- package/dist/profile/client-playbooks.js +36 -0
- package/dist/profile/client-query.d.ts +30 -0
- package/dist/profile/client-query.js +70 -0
- package/dist/profile/client-runs.d.ts +42 -0
- package/dist/profile/client-runs.js +58 -0
- package/dist/profile/client-state.d.ts +56 -0
- package/dist/profile/client-state.js +83 -0
- package/dist/profile/client-transport.d.ts +61 -0
- package/dist/profile/client-transport.js +155 -0
- package/dist/profile/client.d.ts +23 -142
- package/dist/profile/client.js +28 -588
- package/dist/profile/manager.js +1 -1
- package/dist/project/closure.d.ts +4 -4
- package/dist/project/closure.js +11 -5
- package/dist/project/init.js +2 -2
- package/dist/project/loader.d.ts +0 -25
- package/dist/project/loader.js +1 -154
- package/dist/project/transactions.d.ts +12 -14
- package/dist/project/transactions.js +60 -836
- package/dist/registry/registry.js +6 -4
- package/dist/registry/resolve.js +1 -1
- package/dist/runtime/action-registry.d.ts +45 -0
- package/dist/runtime/action-registry.js +108 -0
- package/dist/runtime/clock.d.ts +5 -17
- package/dist/runtime/clock.js +5 -15
- package/dist/runtime/context.d.ts +3 -0
- package/dist/runtime/context.js +17 -56
- package/dist/runtime/index.d.ts +3 -0
- package/dist/runtime/index.js +3 -0
- package/dist/runtime/package-runner-factory.d.ts +82 -0
- package/dist/runtime/package-runner-factory.js +186 -0
- package/dist/runtime/run-persistence.d.ts +85 -0
- package/dist/runtime/run-persistence.js +111 -0
- package/dist/runtime/runner.d.ts +23 -33
- package/dist/runtime/runner.js +92 -286
- package/dist/runtime/standalone.d.ts +11 -1
- package/dist/runtime/standalone.js +137 -25
- package/dist/server/dispatcher.d.ts +8 -3
- package/dist/server/dispatcher.js +16 -40
- package/dist/server/routes/runs.js +6 -4
- package/dist/server/security.d.ts +1 -7
- package/dist/server/security.js +2 -13
- package/dist/storage/clock.d.ts +25 -0
- package/dist/storage/clock.js +23 -0
- package/dist/storage/data-dir-lock.d.ts +3 -36
- package/dist/storage/data-dir-lock.js +48 -881
- package/dist/storage/index.d.ts +8 -1
- package/dist/storage/index.js +8 -2
- package/dist/storage/lazy.js +1 -0
- package/dist/storage/lock-core.d.ts +162 -0
- package/dist/storage/lock-core.js +885 -0
- package/dist/storage/sqlite.d.ts +19 -6
- package/dist/storage/sqlite.js +81 -89
- package/dist/storage/types.d.ts +27 -5
- package/dist/storage/types.js +21 -0
- package/dist/storage/utils.d.ts +22 -0
- package/dist/storage/utils.js +34 -0
- package/dist/target/local.d.ts +1 -0
- package/dist/target/local.js +23 -17
- package/dist/target/remote-errors.d.ts +21 -0
- package/dist/target/remote-errors.js +51 -0
- package/dist/target/remote-polling.d.ts +35 -0
- package/dist/target/remote-polling.js +104 -0
- package/dist/target/remote.d.ts +4 -0
- package/dist/target/remote.js +108 -301
- package/dist/target/sse-parser.d.ts +35 -0
- package/dist/target/sse-parser.js +163 -0
- package/dist/target/target.js +2 -0
- package/dist/target/types.d.ts +6 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -0
- package/dist/utils/net.d.ts +10 -0
- package/dist/utils/net.js +16 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +2 -2
package/dist/doctor/doctor.js
CHANGED
|
@@ -1,613 +1,44 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
|
|
24
|
-
const
|
|
25
|
-
|
|
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
|
/** 远程状态键不存在 */
|