@actiondock/cli 2.0.9 → 2.0.11-beta.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/README.md +17 -0
- package/dist/index.js +46701 -35780
- package/package.json +7 -7
- package/src/commands/action/create.ts +129 -0
- package/src/commands/action/index.ts +27 -0
- package/src/commands/action/list.ts +247 -0
- package/src/commands/action/run.ts +197 -0
- package/src/commands/action/show.ts +128 -0
- package/src/commands/action/sync.ts +76 -0
- package/src/commands/action/validate.ts +102 -0
- package/src/commands/action.ts +1 -633
- package/src/commands/build.ts +19 -17
- package/src/commands/config.ts +168 -69
- package/src/commands/doctor.ts +44 -42
- package/src/commands/export.ts +140 -14
- package/src/commands/index.ts +33 -1
- package/src/commands/info.ts +93 -74
- package/src/commands/init.ts +2 -2
- package/src/commands/link.ts +3 -4
- package/src/commands/mcp.ts +6 -10
- package/src/commands/playbook.ts +289 -161
- package/src/commands/profile.ts +125 -92
- package/src/commands/runs.ts +92 -49
- package/src/commands/serve.ts +3 -4
- package/src/commands/state.ts +145 -64
- package/src/commands/test.ts +1 -1
- package/src/index.ts +39 -3
- package/src/utils/bytes.ts +1 -35
- package/src/utils/filter.ts +2 -24
package/src/commands/config.ts
CHANGED
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
type ConfigItemDefinition,
|
|
14
14
|
} from "@actiondock/core";
|
|
15
15
|
import { Command } from "commander";
|
|
16
|
+
import { ArgumentError, ExecutionError, getEffectiveOptions, renderResult } from "@actiondock/runtime-cli";
|
|
16
17
|
import { resolveIntent } from "../utils/filter";
|
|
17
18
|
|
|
18
19
|
export function registerConfigCommands(program: Command): void {
|
|
@@ -26,26 +27,37 @@ export function registerConfigCommands(program: Command): void {
|
|
|
26
27
|
.alias("check")
|
|
27
28
|
.description("Inspect declared configuration requirements and check resolution status")
|
|
28
29
|
.option("-P, --package <id>", "Target package ID or path")
|
|
30
|
+
.option("--data-dir <path>", "Custom database storage directory")
|
|
29
31
|
.option("--json", "Output as JSON")
|
|
30
|
-
.
|
|
32
|
+
.option("--envelope", "Wrap JSON output in standard envelope")
|
|
33
|
+
.action((identifier, rawOptions, cmd) => {
|
|
31
34
|
try {
|
|
32
|
-
const
|
|
35
|
+
const options = getEffectiveOptions(rawOptions, cmd);
|
|
36
|
+
const targetPkg = identifier || options.package;
|
|
37
|
+
const root = resolvePackageRoot(targetPkg);
|
|
33
38
|
if (!root) {
|
|
34
|
-
|
|
35
|
-
|
|
39
|
+
if (targetPkg) {
|
|
40
|
+
throw new ArgumentError(
|
|
41
|
+
`Package '${targetPkg}' not found in linked packages or path`
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
throw new ArgumentError(
|
|
45
|
+
"Not in an ActionDock project.\nUsage: ad config schema [package-id] or cd into a project directory."
|
|
36
46
|
);
|
|
37
|
-
process.exit(1);
|
|
38
47
|
}
|
|
39
48
|
|
|
40
49
|
const projConfig = loadProjectConfig(root);
|
|
41
50
|
const declared = projConfig.config || {};
|
|
42
51
|
const declaredKeys = Object.keys(declared);
|
|
43
52
|
|
|
44
|
-
const globalStorage = createGlobalStorage();
|
|
53
|
+
const globalStorage = createGlobalStorage(options.dataDir);
|
|
45
54
|
const globalConfig = globalStorage.listConfig();
|
|
46
55
|
globalStorage.close();
|
|
47
56
|
|
|
48
|
-
const projectStorage = createStorage(projConfig.id, {
|
|
57
|
+
const projectStorage = createStorage(projConfig.id, {
|
|
58
|
+
projectRoot: root,
|
|
59
|
+
dataDir: options.dataDir,
|
|
60
|
+
});
|
|
49
61
|
const projectConfig = projectStorage.listConfig();
|
|
50
62
|
projectStorage.close();
|
|
51
63
|
|
|
@@ -89,20 +101,15 @@ export function registerConfigCommands(program: Command): void {
|
|
|
89
101
|
});
|
|
90
102
|
|
|
91
103
|
const missingRequired = items.filter((i) => i.status === "MISSING");
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
},
|
|
102
|
-
null,
|
|
103
|
-
2
|
|
104
|
-
)
|
|
105
|
-
);
|
|
104
|
+
const payload = {
|
|
105
|
+
packageId: projConfig.id,
|
|
106
|
+
projectRoot: root,
|
|
107
|
+
allReady: missingRequired.length === 0,
|
|
108
|
+
configs: items,
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
if (options.json || options.envelope) {
|
|
112
|
+
renderResult(payload, { json: options.json, envelope: options.envelope });
|
|
106
113
|
} else {
|
|
107
114
|
console.log(`Configuration Requirements for ${projConfig.id} (${root}):\n`);
|
|
108
115
|
if (items.length === 0) {
|
|
@@ -133,8 +140,10 @@ export function registerConfigCommands(program: Command): void {
|
|
|
133
140
|
}
|
|
134
141
|
}
|
|
135
142
|
} catch (err: any) {
|
|
136
|
-
|
|
137
|
-
|
|
143
|
+
if (err instanceof ArgumentError || err instanceof ExecutionError) {
|
|
144
|
+
throw err;
|
|
145
|
+
}
|
|
146
|
+
throw new ExecutionError(err.message);
|
|
138
147
|
}
|
|
139
148
|
});
|
|
140
149
|
|
|
@@ -150,11 +159,16 @@ export function registerConfigCommands(program: Command): void {
|
|
|
150
159
|
.option("-i, --intent <pattern>", "Regex or fuzzy intent filter; falls back to full list when no match")
|
|
151
160
|
.option("--reveal, --show-secrets", "Reveal plain text values for secrets")
|
|
152
161
|
.option("--no-fallback", "Disable fallback to full list when no items match intent")
|
|
162
|
+
.option("--data-dir <path>", "Custom database storage directory")
|
|
153
163
|
.option("--json", "Output as JSON")
|
|
154
|
-
.
|
|
164
|
+
.option("--envelope", "Wrap JSON output in standard envelope")
|
|
165
|
+
.action(async (patterns, rawOptions, cmd) => {
|
|
155
166
|
try {
|
|
167
|
+
const options = getEffectiveOptions(rawOptions, cmd);
|
|
156
168
|
const effectiveIntent = resolveIntent(options.intent, patterns);
|
|
157
|
-
const
|
|
169
|
+
const isMachine = Boolean(options.json || options.envelope);
|
|
170
|
+
const fallbackExplicit = options.fallback === true || (Array.isArray(process.argv) && process.argv.includes("--fallback"));
|
|
171
|
+
const shouldFallback = isMachine ? fallbackExplicit : options.fallback !== false;
|
|
158
172
|
const reveal = options.reveal || options.showSecrets;
|
|
159
173
|
|
|
160
174
|
const target = resolveTarget({
|
|
@@ -165,8 +179,8 @@ export function registerConfigCommands(program: Command): void {
|
|
|
165
179
|
|
|
166
180
|
if (target.type === "remote") {
|
|
167
181
|
const res = await fetchRemoteConfig(target.serverUrl!, target.token, options.package);
|
|
168
|
-
if (
|
|
169
|
-
|
|
182
|
+
if (isMachine) {
|
|
183
|
+
renderResult(res, { json: options.json, envelope: options.envelope });
|
|
170
184
|
return;
|
|
171
185
|
}
|
|
172
186
|
console.log(
|
|
@@ -183,7 +197,16 @@ export function registerConfigCommands(program: Command): void {
|
|
|
183
197
|
return;
|
|
184
198
|
}
|
|
185
199
|
|
|
186
|
-
|
|
200
|
+
if (options.package && !options.global) {
|
|
201
|
+
const directRoot = resolvePackageRoot(options.package);
|
|
202
|
+
if (!directRoot) {
|
|
203
|
+
throw new ArgumentError(
|
|
204
|
+
`Package '${options.package}' not found in linked packages or path`
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const globalStorage = createGlobalStorage(options.dataDir);
|
|
187
210
|
const globalConfig = globalStorage.listConfig();
|
|
188
211
|
|
|
189
212
|
const projectRoot = !options.global ? resolvePackageRoot(options.package) : null;
|
|
@@ -195,7 +218,10 @@ export function registerConfigCommands(program: Command): void {
|
|
|
195
218
|
try {
|
|
196
219
|
const projConfig = loadProjectConfig(projectRoot);
|
|
197
220
|
packageId = projConfig.id;
|
|
198
|
-
const projectStorage = createStorage(projConfig.id, {
|
|
221
|
+
const projectStorage = createStorage(projConfig.id, {
|
|
222
|
+
projectRoot,
|
|
223
|
+
dataDir: options.dataDir,
|
|
224
|
+
});
|
|
199
225
|
projectStored = projectStorage.listConfig();
|
|
200
226
|
declaredDefaults = projConfig.config || {};
|
|
201
227
|
projectStorage.close();
|
|
@@ -249,8 +275,8 @@ export function registerConfigCommands(program: Command): void {
|
|
|
249
275
|
shouldFallback
|
|
250
276
|
);
|
|
251
277
|
|
|
252
|
-
if (
|
|
253
|
-
|
|
278
|
+
if (isMachine) {
|
|
279
|
+
renderResult(filterRes.items, { json: options.json, envelope: options.envelope });
|
|
254
280
|
} else {
|
|
255
281
|
const scopeLabel = projectRoot ? `${packageId} (${projectRoot})` : "Global Scope";
|
|
256
282
|
console.log(`Configurations [${scopeLabel}]:\n`);
|
|
@@ -267,8 +293,10 @@ export function registerConfigCommands(program: Command): void {
|
|
|
267
293
|
}
|
|
268
294
|
}
|
|
269
295
|
} catch (err: any) {
|
|
270
|
-
|
|
271
|
-
|
|
296
|
+
if (err instanceof ArgumentError || err instanceof ExecutionError) {
|
|
297
|
+
throw err;
|
|
298
|
+
}
|
|
299
|
+
throw new ExecutionError(err.message);
|
|
272
300
|
}
|
|
273
301
|
});
|
|
274
302
|
|
|
@@ -282,9 +310,13 @@ export function registerConfigCommands(program: Command): void {
|
|
|
282
310
|
.option("-s, --server <url>", "Remote server URL")
|
|
283
311
|
.option("-t, --token <token>", "Auth token for remote server")
|
|
284
312
|
.option("--reveal, --show-secrets", "Reveal plain text value for secret")
|
|
313
|
+
.option("--data-dir <path>", "Custom database storage directory")
|
|
285
314
|
.option("--json", "Output as JSON")
|
|
286
|
-
.
|
|
315
|
+
.option("--envelope", "Wrap JSON output in standard envelope")
|
|
316
|
+
.action(async (key, rawOptions, cmd) => {
|
|
287
317
|
try {
|
|
318
|
+
const options = getEffectiveOptions(rawOptions, cmd);
|
|
319
|
+
const isMachine = Boolean(options.json || options.envelope);
|
|
288
320
|
const target = resolveTarget({
|
|
289
321
|
profile: options.profile,
|
|
290
322
|
server: options.server,
|
|
@@ -294,16 +326,25 @@ export function registerConfigCommands(program: Command): void {
|
|
|
294
326
|
if (target.type === "remote") {
|
|
295
327
|
const res = await fetchRemoteConfig(target.serverUrl!, target.token, options.package);
|
|
296
328
|
const val = res.values?.[key];
|
|
297
|
-
if (
|
|
298
|
-
|
|
329
|
+
if (isMachine) {
|
|
330
|
+
renderResult({ key, value: val }, { json: options.json, envelope: options.envelope });
|
|
299
331
|
} else {
|
|
300
332
|
console.log(val !== undefined ? JSON.stringify(val) : "undefined");
|
|
301
333
|
}
|
|
302
334
|
return;
|
|
303
335
|
}
|
|
304
336
|
|
|
337
|
+
if (options.package && !options.global) {
|
|
338
|
+
const directRoot = resolvePackageRoot(options.package);
|
|
339
|
+
if (!directRoot) {
|
|
340
|
+
throw new ArgumentError(
|
|
341
|
+
`Package '${options.package}' not found in linked packages or path`
|
|
342
|
+
);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
305
346
|
const reveal = options.reveal || options.showSecrets;
|
|
306
|
-
const globalStorage = createGlobalStorage();
|
|
347
|
+
const globalStorage = createGlobalStorage(options.dataDir);
|
|
307
348
|
const globalVal = globalStorage.getConfig(key);
|
|
308
349
|
globalStorage.close();
|
|
309
350
|
|
|
@@ -316,7 +357,10 @@ export function registerConfigCommands(program: Command): void {
|
|
|
316
357
|
try {
|
|
317
358
|
const projConfig = loadProjectConfig(projectRoot);
|
|
318
359
|
declaredItem = projConfig.config?.[key];
|
|
319
|
-
const projectStorage = createStorage(projConfig.id, {
|
|
360
|
+
const projectStorage = createStorage(projConfig.id, {
|
|
361
|
+
projectRoot,
|
|
362
|
+
dataDir: options.dataDir,
|
|
363
|
+
});
|
|
320
364
|
projVal = projectStorage.getConfig(key);
|
|
321
365
|
fallbackVal = projConfig.config?.[key]?.default;
|
|
322
366
|
projectStorage.close();
|
|
@@ -350,25 +394,24 @@ export function registerConfigCommands(program: Command): void {
|
|
|
350
394
|
const isSecret = isSecretConfigKey(key, declaredItem);
|
|
351
395
|
const effective = !reveal && isSecret && rawEffective !== undefined ? maskSecretValue(rawEffective) : rawEffective;
|
|
352
396
|
|
|
353
|
-
if (
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
null,
|
|
363
|
-
2
|
|
364
|
-
)
|
|
397
|
+
if (isMachine) {
|
|
398
|
+
renderResult(
|
|
399
|
+
{
|
|
400
|
+
key,
|
|
401
|
+
value: effective,
|
|
402
|
+
source,
|
|
403
|
+
secret: isSecret,
|
|
404
|
+
},
|
|
405
|
+
{ json: options.json, envelope: options.envelope }
|
|
365
406
|
);
|
|
366
407
|
} else {
|
|
367
408
|
console.log(effective !== undefined ? (typeof effective === "string" && isSecret && !reveal ? effective : JSON.stringify(effective)) : "undefined");
|
|
368
409
|
}
|
|
369
410
|
} catch (err: any) {
|
|
370
|
-
|
|
371
|
-
|
|
411
|
+
if (err instanceof ArgumentError || err instanceof ExecutionError) {
|
|
412
|
+
throw err;
|
|
413
|
+
}
|
|
414
|
+
throw new ExecutionError(err.message);
|
|
372
415
|
}
|
|
373
416
|
});
|
|
374
417
|
|
|
@@ -381,8 +424,13 @@ export function registerConfigCommands(program: Command): void {
|
|
|
381
424
|
.option("-p, --profile <name>", "Set config on a remote target")
|
|
382
425
|
.option("-s, --server <url>", "Remote server URL")
|
|
383
426
|
.option("-t, --token <token>", "Auth token for remote server")
|
|
384
|
-
.
|
|
427
|
+
.option("--data-dir <path>", "Custom database storage directory")
|
|
428
|
+
.option("--json", "Output as JSON")
|
|
429
|
+
.option("--envelope", "Wrap JSON output in standard envelope")
|
|
430
|
+
.action(async (key, rawValue, rawOptions, cmd) => {
|
|
385
431
|
try {
|
|
432
|
+
const options = getEffectiveOptions(rawOptions, cmd);
|
|
433
|
+
const isMachine = Boolean(options.json || options.envelope);
|
|
386
434
|
let parsed: unknown = rawValue;
|
|
387
435
|
try {
|
|
388
436
|
parsed = JSON.parse(rawValue);
|
|
@@ -398,31 +446,57 @@ export function registerConfigCommands(program: Command): void {
|
|
|
398
446
|
|
|
399
447
|
if (target.type === "remote") {
|
|
400
448
|
await setRemoteConfig(target.serverUrl!, key, parsed, target.token, options.package);
|
|
401
|
-
|
|
449
|
+
if (isMachine) {
|
|
450
|
+
renderResult({ ok: true, key, value: parsed }, { json: options.json, envelope: options.envelope });
|
|
451
|
+
} else {
|
|
452
|
+
console.log(`[OK] Remote config '${key}' updated on ${target.serverUrl}`);
|
|
453
|
+
}
|
|
402
454
|
return;
|
|
403
455
|
}
|
|
404
456
|
|
|
457
|
+
if (options.package && !options.global) {
|
|
458
|
+
const directRoot = resolvePackageRoot(options.package);
|
|
459
|
+
if (!directRoot) {
|
|
460
|
+
throw new ArgumentError(
|
|
461
|
+
`Package '${options.package}' not found in linked packages or path`
|
|
462
|
+
);
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
|
|
405
466
|
const projectRoot = !options.global ? resolvePackageRoot(options.package) : null;
|
|
406
467
|
const isSecret = isSecretConfigKey(key);
|
|
407
468
|
const displayVal = isSecret ? maskSecretValue(parsed) : JSON.stringify(parsed);
|
|
408
469
|
|
|
409
470
|
if (options.global || !projectRoot) {
|
|
410
|
-
// Set in Global storage
|
|
411
|
-
const globalStorage = createGlobalStorage();
|
|
471
|
+
// Set in Global storage
|
|
472
|
+
const globalStorage = createGlobalStorage(options.dataDir);
|
|
412
473
|
globalStorage.setConfig(key, parsed);
|
|
413
474
|
globalStorage.close();
|
|
414
|
-
|
|
475
|
+
if (isMachine) {
|
|
476
|
+
renderResult({ ok: true, key, value: parsed, scope: "global" }, { json: options.json, envelope: options.envelope });
|
|
477
|
+
} else {
|
|
478
|
+
console.log(`[OK] Global config '${key}' set to ${displayVal}`);
|
|
479
|
+
}
|
|
415
480
|
} else {
|
|
416
481
|
// Set in Project storage
|
|
417
482
|
const projConfig = loadProjectConfig(projectRoot);
|
|
418
|
-
const storage = createStorage(projConfig.id, {
|
|
483
|
+
const storage = createStorage(projConfig.id, {
|
|
484
|
+
projectRoot,
|
|
485
|
+
dataDir: options.dataDir,
|
|
486
|
+
});
|
|
419
487
|
storage.setConfig(key, parsed);
|
|
420
488
|
storage.close();
|
|
421
|
-
|
|
489
|
+
if (isMachine) {
|
|
490
|
+
renderResult({ ok: true, key, value: parsed, packageId: projConfig.id }, { json: options.json, envelope: options.envelope });
|
|
491
|
+
} else {
|
|
492
|
+
console.log(`[OK] Config '${key}' set to ${displayVal} in ${projConfig.id}`);
|
|
493
|
+
}
|
|
422
494
|
}
|
|
423
495
|
} catch (err: any) {
|
|
424
|
-
|
|
425
|
-
|
|
496
|
+
if (err instanceof ArgumentError || err instanceof ExecutionError) {
|
|
497
|
+
throw err;
|
|
498
|
+
}
|
|
499
|
+
throw new ExecutionError(err.message);
|
|
426
500
|
}
|
|
427
501
|
});
|
|
428
502
|
|
|
@@ -436,8 +510,13 @@ export function registerConfigCommands(program: Command): void {
|
|
|
436
510
|
.option("-p, --profile <name>", "Delete config on a remote target")
|
|
437
511
|
.option("-s, --server <url>", "Remote server URL")
|
|
438
512
|
.option("-t, --token <token>", "Auth token for remote server")
|
|
439
|
-
.
|
|
513
|
+
.option("--data-dir <path>", "Custom database storage directory")
|
|
514
|
+
.option("--json", "Output as JSON")
|
|
515
|
+
.option("--envelope", "Wrap JSON output in standard envelope")
|
|
516
|
+
.action(async (key, rawOptions, cmd) => {
|
|
440
517
|
try {
|
|
518
|
+
const options = getEffectiveOptions(rawOptions, cmd);
|
|
519
|
+
const isMachine = Boolean(options.json || options.envelope);
|
|
441
520
|
const target = resolveTarget({
|
|
442
521
|
profile: options.profile,
|
|
443
522
|
server: options.server,
|
|
@@ -446,7 +525,9 @@ export function registerConfigCommands(program: Command): void {
|
|
|
446
525
|
|
|
447
526
|
if (target.type === "remote") {
|
|
448
527
|
const res = await deleteRemoteConfig(target.serverUrl!, key, target.token, options.package);
|
|
449
|
-
if (
|
|
528
|
+
if (isMachine) {
|
|
529
|
+
renderResult(res, { json: options.json, envelope: options.envelope });
|
|
530
|
+
} else if (res.deleted) {
|
|
450
531
|
console.log(`[OK] Remote config '${key}' deleted from ${target.serverUrl}`);
|
|
451
532
|
} else {
|
|
452
533
|
console.log(`Remote config '${key}' not found on ${target.serverUrl}`);
|
|
@@ -454,31 +535,49 @@ export function registerConfigCommands(program: Command): void {
|
|
|
454
535
|
return;
|
|
455
536
|
}
|
|
456
537
|
|
|
538
|
+
if (options.package && !options.global) {
|
|
539
|
+
const directRoot = resolvePackageRoot(options.package);
|
|
540
|
+
if (!directRoot) {
|
|
541
|
+
throw new ArgumentError(
|
|
542
|
+
`Package '${options.package}' not found in linked packages or path`
|
|
543
|
+
);
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
|
|
457
547
|
const projectRoot = !options.global ? resolvePackageRoot(options.package) : null;
|
|
458
548
|
|
|
459
549
|
if (options.global || !projectRoot) {
|
|
460
|
-
const globalStorage = createGlobalStorage();
|
|
550
|
+
const globalStorage = createGlobalStorage(options.dataDir);
|
|
461
551
|
const deleted = globalStorage.deleteConfig(key);
|
|
462
552
|
globalStorage.close();
|
|
463
|
-
if (
|
|
553
|
+
if (isMachine) {
|
|
554
|
+
renderResult({ ok: true, key, deleted, scope: "global" }, { json: options.json, envelope: options.envelope });
|
|
555
|
+
} else if (deleted) {
|
|
464
556
|
console.log(`[OK] Global config '${key}' deleted`);
|
|
465
557
|
} else {
|
|
466
558
|
console.log(`Global config '${key}' was not found`);
|
|
467
559
|
}
|
|
468
560
|
} else {
|
|
469
561
|
const projConfig = loadProjectConfig(projectRoot);
|
|
470
|
-
const storage = createStorage(projConfig.id, {
|
|
562
|
+
const storage = createStorage(projConfig.id, {
|
|
563
|
+
projectRoot,
|
|
564
|
+
dataDir: options.dataDir,
|
|
565
|
+
});
|
|
471
566
|
const deleted = storage.deleteConfig(key);
|
|
472
567
|
storage.close();
|
|
473
|
-
if (
|
|
568
|
+
if (isMachine) {
|
|
569
|
+
renderResult({ ok: true, key, deleted, packageId: projConfig.id }, { json: options.json, envelope: options.envelope });
|
|
570
|
+
} else if (deleted) {
|
|
474
571
|
console.log(`[OK] Config '${key}' deleted from ${projConfig.id}`);
|
|
475
572
|
} else {
|
|
476
573
|
console.log(`Config '${key}' was not set in database for ${projConfig.id}`);
|
|
477
574
|
}
|
|
478
575
|
}
|
|
479
576
|
} catch (err: any) {
|
|
480
|
-
|
|
481
|
-
|
|
577
|
+
if (err instanceof ArgumentError || err instanceof ExecutionError) {
|
|
578
|
+
throw err;
|
|
579
|
+
}
|
|
580
|
+
throw new ExecutionError(err.message);
|
|
482
581
|
}
|
|
483
582
|
});
|
|
484
583
|
}
|
package/src/commands/doctor.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { fetchRemoteDoctor, resolveTarget, runDoctorChecks } from "@actiondock/core";
|
|
2
|
+
import { ExecutionError, getEffectiveOptions, renderResult } from "@actiondock/runtime-cli";
|
|
2
3
|
import { Command } from "commander";
|
|
3
4
|
|
|
4
5
|
export function registerDoctorCommand(program: Command): void {
|
|
@@ -10,8 +11,10 @@ export function registerDoctorCommand(program: Command): void {
|
|
|
10
11
|
.option("-s, --server <url>", "Remote server URL")
|
|
11
12
|
.option("-t, --token <token>", "Auth token for remote server")
|
|
12
13
|
.option("--json", "Output diagnostics report in JSON format")
|
|
13
|
-
.
|
|
14
|
+
.option("--envelope", "Wrap JSON output in standard envelope")
|
|
15
|
+
.action(async (rawOptions, cmd) => {
|
|
14
16
|
try {
|
|
17
|
+
const options = getEffectiveOptions(rawOptions, cmd);
|
|
15
18
|
const target = resolveTarget({
|
|
16
19
|
profile: options.profile,
|
|
17
20
|
server: options.server,
|
|
@@ -28,55 +31,54 @@ export function registerDoctorCommand(program: Command): void {
|
|
|
28
31
|
});
|
|
29
32
|
}
|
|
30
33
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
? `[DOCTOR] Remote ActionDock Server Diagnostics (${target.serverUrl}${target.profileName ? ` - Profile: ${target.profileName}` : ""})\n`
|
|
41
|
-
: "[DOCTOR] ActionDock System & Project Diagnostics\n";
|
|
42
|
-
console.log(title);
|
|
34
|
+
renderResult(report, {
|
|
35
|
+
json: options.json,
|
|
36
|
+
envelope: options.envelope,
|
|
37
|
+
humanFormatter: () => {
|
|
38
|
+
const lines: string[] = [];
|
|
39
|
+
const title = target.type === "remote"
|
|
40
|
+
? `[DOCTOR] Remote ActionDock Server Diagnostics (${target.serverUrl}${target.profileName ? ` - Profile: ${target.profileName}` : ""})\n`
|
|
41
|
+
: "[DOCTOR] ActionDock System & Project Diagnostics\n";
|
|
42
|
+
lines.push(title);
|
|
43
43
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
44
|
+
// 1. Runtime & Environment Group
|
|
45
|
+
lines.push("[Runtime & Environment]");
|
|
46
|
+
const envChecks = (report.checks || []).filter((c: any) => c.category === "runtime" || c.category === "storage" || c.category === "registry");
|
|
47
|
+
for (const c of envChecks) {
|
|
48
|
+
const tag = c.status === "ok" ? "[OK]" : c.status === "warn" ? "[WARN]" : "[ERROR]";
|
|
49
|
+
lines.push(` ${tag} ${c.name}: ${c.message}`);
|
|
50
|
+
if (c.fix) {
|
|
51
|
+
lines.push(` Fix: ${c.fix}`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
54
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
55
|
+
// 2. Project Group
|
|
56
|
+
if (report.hasProject) {
|
|
57
|
+
lines.push(`\n[Project: ${report.packageId || "unknown"}] (${report.projectRoot})`);
|
|
58
|
+
const projChecks = (report.checks || []).filter((c: any) => c.category === "project");
|
|
59
|
+
for (const c of projChecks) {
|
|
60
|
+
const tag = c.status === "ok" ? "[OK]" : c.status === "warn" ? "[WARN]" : "[ERROR]";
|
|
61
|
+
lines.push(` ${tag} ${c.name}: ${c.message}`);
|
|
62
|
+
if (c.fix) {
|
|
63
|
+
lines.push(` Fix: ${c.fix}`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
} else {
|
|
67
|
+
lines.push("\n[Project Context]");
|
|
68
|
+
lines.push(" [INFO] Not inside an ActionDock project directory (skipped project checks)");
|
|
64
69
|
}
|
|
65
|
-
}
|
|
66
|
-
} else {
|
|
67
|
-
console.log("\n[Project Context]");
|
|
68
|
-
console.log(" [INFO] Not inside an ActionDock project directory (skipped project checks)");
|
|
69
|
-
}
|
|
70
70
|
|
|
71
|
-
|
|
72
|
-
|
|
71
|
+
// 3. Summary
|
|
72
|
+
lines.push(`\n[Summary] ${report.summary.ok} passed, ${report.summary.warn} warning(s), ${report.summary.error} error(s)`);
|
|
73
|
+
return lines.join("\n");
|
|
74
|
+
},
|
|
75
|
+
});
|
|
73
76
|
|
|
74
77
|
if (!report.ok) {
|
|
75
|
-
process.
|
|
78
|
+
process.exitCode = 1;
|
|
76
79
|
}
|
|
77
80
|
} catch (err: any) {
|
|
78
|
-
|
|
79
|
-
process.exit(1);
|
|
81
|
+
throw new ExecutionError(`Doctor failed to run diagnostics: ${err.message}`);
|
|
80
82
|
}
|
|
81
83
|
});
|
|
82
84
|
}
|