@actiondock/cli 2.0.11 → 2.0.12

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 (54) hide show
  1. package/README.md +15 -2
  2. package/bin/ad.js +13 -2
  3. package/dist/commands/action/create.d.ts +2 -0
  4. package/dist/commands/action/index.d.ts +16 -0
  5. package/dist/commands/action/list.d.ts +5 -0
  6. package/dist/commands/action/run.d.ts +4 -0
  7. package/dist/commands/action/show.d.ts +5 -0
  8. package/dist/commands/action/sync.d.ts +2 -0
  9. package/dist/commands/action/validate.d.ts +5 -0
  10. package/dist/commands/build.d.ts +2 -0
  11. package/dist/commands/config.d.ts +2 -0
  12. package/dist/commands/doctor.d.ts +2 -0
  13. package/dist/commands/export.d.ts +2 -0
  14. package/dist/commands/index.d.ts +2 -0
  15. package/dist/commands/info.d.ts +2 -0
  16. package/dist/commands/init.d.ts +2 -0
  17. package/dist/commands/link.d.ts +2 -0
  18. package/dist/commands/mcp.d.ts +2 -0
  19. package/dist/commands/playbook.d.ts +6 -0
  20. package/dist/commands/profile.d.ts +2 -0
  21. package/dist/commands/runs.d.ts +2 -0
  22. package/dist/commands/serve.d.ts +2 -0
  23. package/dist/commands/state.d.ts +2 -0
  24. package/dist/commands/test.d.ts +2 -0
  25. package/dist/index.d.ts +8 -0
  26. package/dist/index.js +745 -65708
  27. package/{src/utils/bytes.ts → dist/utils/bytes.d.ts} +0 -1
  28. package/{src/utils/filter.ts → dist/utils/filter.d.ts} +0 -1
  29. package/package.json +20 -15
  30. package/src/commands/action/create.ts +0 -129
  31. package/src/commands/action/index.ts +0 -27
  32. package/src/commands/action/list.ts +0 -247
  33. package/src/commands/action/run.ts +0 -197
  34. package/src/commands/action/show.ts +0 -128
  35. package/src/commands/action/sync.ts +0 -76
  36. package/src/commands/action/validate.ts +0 -102
  37. package/src/commands/build.ts +0 -56
  38. package/src/commands/config.ts +0 -583
  39. package/src/commands/doctor.ts +0 -84
  40. package/src/commands/export.ts +0 -196
  41. package/src/commands/index.ts +0 -75
  42. package/src/commands/info.ts +0 -537
  43. package/src/commands/init.ts +0 -24
  44. package/src/commands/link.ts +0 -73
  45. package/src/commands/mcp.ts +0 -195
  46. package/src/commands/playbook.ts +0 -566
  47. package/src/commands/profile.ts +0 -296
  48. package/src/commands/runs.ts +0 -452
  49. package/src/commands/serve.ts +0 -132
  50. package/src/commands/state.ts +0 -590
  51. package/src/commands/test.ts +0 -48
  52. package/src/index.ts +0 -58
  53. /package/{src/commands/action.ts → dist/commands/action.d.ts} +0 -0
  54. /package/{src/utils/duration.ts → dist/utils/duration.d.ts} +0 -0
@@ -1,583 +0,0 @@
1
- import {
2
- createGlobalStorage,
3
- createStorage,
4
- deleteRemoteConfig,
5
- fetchRemoteConfig,
6
- filterWithFallbackInfo,
7
- isSecretConfigKey,
8
- loadProjectConfig,
9
- maskSecretValue,
10
- resolvePackageRoot,
11
- resolveTarget,
12
- setRemoteConfig,
13
- type ConfigItemDefinition,
14
- } from "@actiondock/core";
15
- import { Command } from "commander";
16
- import { ArgumentError, ExecutionError, getEffectiveOptions, renderResult } from "@actiondock/runtime-cli";
17
- import { resolveIntent } from "../utils/filter";
18
-
19
- export function registerConfigCommands(program: Command): void {
20
- const configCmd = program
21
- .command("config")
22
- .description("Manage runtime configuration store (Global & Project-level)");
23
-
24
- // config schema / check
25
- configCmd
26
- .command("schema [identifier]")
27
- .alias("check")
28
- .description("Inspect declared configuration requirements and check resolution status")
29
- .option("-P, --package <id>", "Target package ID or path")
30
- .option("--data-dir <path>", "Custom database storage directory")
31
- .option("--json", "Output as JSON")
32
- .option("--envelope", "Wrap JSON output in standard envelope")
33
- .action((identifier, rawOptions, cmd) => {
34
- try {
35
- const options = getEffectiveOptions(rawOptions, cmd);
36
- const targetPkg = identifier || options.package;
37
- const root = resolvePackageRoot(targetPkg);
38
- if (!root) {
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."
46
- );
47
- }
48
-
49
- const projConfig = loadProjectConfig(root);
50
- const declared = projConfig.config || {};
51
- const declaredKeys = Object.keys(declared);
52
-
53
- const globalStorage = createGlobalStorage(options.dataDir);
54
- const globalConfig = globalStorage.listConfig();
55
- globalStorage.close();
56
-
57
- const projectStorage = createStorage(projConfig.id, {
58
- projectRoot: root,
59
- dataDir: options.dataDir,
60
- });
61
- const projectConfig = projectStorage.listConfig();
62
- projectStorage.close();
63
-
64
- const items = declaredKeys.map((key) => {
65
- const itemDef = declared[key];
66
- const isSecret = isSecretConfigKey(key, itemDef);
67
-
68
- let resolvedValue: unknown;
69
- let source: "project" | "global" | "env" | "default" | "missing" = "missing";
70
- let status: "SET" | "DEFAULT" | "MISSING" = "MISSING";
71
-
72
- if (projectConfig[key] !== undefined) {
73
- resolvedValue = projectConfig[key];
74
- source = "project";
75
- status = "SET";
76
- } else if (globalConfig[key] !== undefined) {
77
- resolvedValue = globalConfig[key];
78
- source = "global";
79
- status = "SET";
80
- } else if (typeof process !== "undefined" && process.env && process.env[key] !== undefined) {
81
- resolvedValue = process.env[key];
82
- source = "env";
83
- status = "SET";
84
- } else if (itemDef.default !== undefined) {
85
- resolvedValue = itemDef.default;
86
- source = "default";
87
- status = "DEFAULT";
88
- }
89
-
90
- const displayValue = isSecret && resolvedValue !== undefined ? maskSecretValue(resolvedValue) : resolvedValue;
91
-
92
- return {
93
- key,
94
- value: displayValue,
95
- status,
96
- source,
97
- secret: isSecret,
98
- description: itemDef.description || "",
99
- required: itemDef.default === undefined,
100
- };
101
- });
102
-
103
- const missingRequired = items.filter((i) => i.status === "MISSING");
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 });
113
- } else {
114
- console.log(`Configuration Requirements for ${projConfig.id} (${root}):\n`);
115
- if (items.length === 0) {
116
- console.log(" (No configuration dependencies declared for this package)");
117
- return;
118
- }
119
-
120
- console.log(
121
- ` ${"KEY".padEnd(24)} ${"STATUS".padEnd(12)} ${"SOURCE".padEnd(10)} ${"SECRET".padEnd(8)} DESCRIPTION`
122
- );
123
- console.log(" " + "-".repeat(85));
124
-
125
- for (const item of items) {
126
- const statusLabel = item.status === "SET" ? "[SET]" : item.status === "DEFAULT" ? "[DEFAULT]" : "[MISSING]";
127
- const secretLabel = item.secret ? "yes" : "no";
128
- console.log(
129
- ` ${item.key.padEnd(24)} ${statusLabel.padEnd(12)} ${item.source.padEnd(10)} ${secretLabel.padEnd(8)} ${item.description}`
130
- );
131
- }
132
-
133
- if (missingRequired.length > 0) {
134
- console.log(`\n[WARNING] ${missingRequired.length} required config(s) not set:`);
135
- for (const m of missingRequired) {
136
- console.log(` - ${m.key}: Run 'ad config set ${m.key} <value>' to configure.`);
137
- }
138
- } else {
139
- console.log("\n[OK] All configuration dependencies are satisfied.");
140
- }
141
- }
142
- } catch (err: any) {
143
- if (err instanceof ArgumentError || err instanceof ExecutionError) {
144
- throw err;
145
- }
146
- throw new ExecutionError(err.message);
147
- }
148
- });
149
-
150
- // config list
151
- configCmd
152
- .command("list [patterns...]")
153
- .description("List configuration entries (Global & Project)")
154
- .option("-P, --package <id>", "Target package ID or path")
155
- .option("-g, --global", "Show only global configurations")
156
- .option("-p, --profile <name>", "Query config on a remote target")
157
- .option("-s, --server <url>", "Remote server URL")
158
- .option("-t, --token <token>", "Auth token for remote server")
159
- .option("-i, --intent <pattern>", "Regex or fuzzy intent filter; falls back to full list when no match")
160
- .option("--reveal, --show-secrets", "Reveal plain text values for secrets")
161
- .option("--no-fallback", "Disable fallback to full list when no items match intent")
162
- .option("--data-dir <path>", "Custom database storage directory")
163
- .option("--json", "Output as JSON")
164
- .option("--envelope", "Wrap JSON output in standard envelope")
165
- .action(async (patterns, rawOptions, cmd) => {
166
- try {
167
- const options = getEffectiveOptions(rawOptions, cmd);
168
- const effectiveIntent = resolveIntent(options.intent, patterns);
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;
172
- const reveal = options.reveal || options.showSecrets;
173
-
174
- const target = resolveTarget({
175
- profile: options.profile,
176
- server: options.server,
177
- token: options.token,
178
- });
179
-
180
- if (target.type === "remote") {
181
- const res = await fetchRemoteConfig(target.serverUrl!, target.token, options.package);
182
- if (isMachine) {
183
- renderResult(res, { json: options.json, envelope: options.envelope });
184
- return;
185
- }
186
- console.log(
187
- `Config on remote server ${target.serverUrl}${target.profileName ? ` (Profile: ${target.profileName})` : ""}:\n`
188
- );
189
- const entries = Object.entries(res.values || {});
190
- if (entries.length === 0) {
191
- console.log(" (No config entries stored)");
192
- } else {
193
- for (const [k, v] of entries) {
194
- console.log(` ${k.padEnd(24)} = ${JSON.stringify(v)}`);
195
- }
196
- }
197
- return;
198
- }
199
-
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);
210
- const globalConfig = globalStorage.listConfig();
211
-
212
- const projectRoot = !options.global ? resolvePackageRoot(options.package) : null;
213
- let projectStored: Record<string, unknown> = {};
214
- let declaredDefaults: Record<string, ConfigItemDefinition> = {};
215
- let packageId = "global";
216
-
217
- if (projectRoot) {
218
- try {
219
- const projConfig = loadProjectConfig(projectRoot);
220
- packageId = projConfig.id;
221
- const projectStorage = createStorage(projConfig.id, {
222
- projectRoot,
223
- dataDir: options.dataDir,
224
- });
225
- projectStored = projectStorage.listConfig();
226
- declaredDefaults = projConfig.config || {};
227
- projectStorage.close();
228
- } catch {
229
- // Ignore project load error
230
- }
231
- }
232
-
233
- globalStorage.close();
234
-
235
- const allKeys = new Set([
236
- ...Object.keys(declaredDefaults),
237
- ...Object.keys(globalConfig),
238
- ...Object.keys(projectStored),
239
- ]);
240
-
241
- const rawList = Array.from(allKeys).map((k) => {
242
- let rawValue: unknown;
243
- let source: "project" | "global" | "env" | "default" = "default";
244
-
245
- if (projectStored[k] !== undefined) {
246
- rawValue = projectStored[k];
247
- source = "project";
248
- } else if (globalConfig[k] !== undefined) {
249
- rawValue = globalConfig[k];
250
- source = "global";
251
- } else if (typeof process !== "undefined" && process.env && process.env[k] !== undefined) {
252
- rawValue = process.env[k];
253
- source = "env";
254
- } else {
255
- rawValue = declaredDefaults[k]?.default;
256
- source = "default";
257
- }
258
-
259
- const isSecret = isSecretConfigKey(k, declaredDefaults[k]);
260
- const displayValue = !reveal && isSecret && rawValue !== undefined ? maskSecretValue(rawValue) : rawValue;
261
-
262
- return {
263
- key: k,
264
- value: displayValue,
265
- source,
266
- secret: isSecret,
267
- description: declaredDefaults[k]?.description || "",
268
- };
269
- });
270
-
271
- const filterRes = filterWithFallbackInfo(
272
- rawList,
273
- effectiveIntent,
274
- [(c) => c.key, (c) => c.value, (c) => c.description, (c) => c.source],
275
- shouldFallback
276
- );
277
-
278
- if (isMachine) {
279
- renderResult(filterRes.items, { json: options.json, envelope: options.envelope });
280
- } else {
281
- const scopeLabel = projectRoot ? `${packageId} (${projectRoot})` : "Global Scope";
282
- console.log(`Configurations [${scopeLabel}]:\n`);
283
- if (filterRes.isFallback && effectiveIntent) {
284
- console.log(`(No config entries matched intent '${effectiveIntent}', showing all entries)\n`);
285
- }
286
- if (filterRes.items.length === 0) {
287
- console.log(" (No configuration entries found)");
288
- }
289
- for (const item of filterRes.items) {
290
- const valStr = typeof item.value === "string" && item.secret && !reveal ? item.value : JSON.stringify(item.value);
291
- const secretBadge = item.secret ? ", secret" : "";
292
- console.log(` ${item.key.padEnd(24)} = ${valStr} (${item.source}${secretBadge})`);
293
- }
294
- }
295
- } catch (err: any) {
296
- if (err instanceof ArgumentError || err instanceof ExecutionError) {
297
- throw err;
298
- }
299
- throw new ExecutionError(err.message);
300
- }
301
- });
302
-
303
- // config get
304
- configCmd
305
- .command("get <key>")
306
- .description("Get a configuration value")
307
- .option("-P, --package <id>", "Target package ID or path")
308
- .option("-g, --global", "Get from global configuration only")
309
- .option("-p, --profile <name>", "Query config on a remote target")
310
- .option("-s, --server <url>", "Remote server URL")
311
- .option("-t, --token <token>", "Auth token for remote server")
312
- .option("--reveal, --show-secrets", "Reveal plain text value for secret")
313
- .option("--data-dir <path>", "Custom database storage directory")
314
- .option("--json", "Output as JSON")
315
- .option("--envelope", "Wrap JSON output in standard envelope")
316
- .action(async (key, rawOptions, cmd) => {
317
- try {
318
- const options = getEffectiveOptions(rawOptions, cmd);
319
- const isMachine = Boolean(options.json || options.envelope);
320
- const target = resolveTarget({
321
- profile: options.profile,
322
- server: options.server,
323
- token: options.token,
324
- });
325
-
326
- if (target.type === "remote") {
327
- const res = await fetchRemoteConfig(target.serverUrl!, target.token, options.package);
328
- const val = res.values?.[key];
329
- if (isMachine) {
330
- renderResult({ key, value: val }, { json: options.json, envelope: options.envelope });
331
- } else {
332
- console.log(val !== undefined ? JSON.stringify(val) : "undefined");
333
- }
334
- return;
335
- }
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
-
346
- const reveal = options.reveal || options.showSecrets;
347
- const globalStorage = createGlobalStorage(options.dataDir);
348
- const globalVal = globalStorage.getConfig(key);
349
- globalStorage.close();
350
-
351
- const projectRoot = !options.global ? resolvePackageRoot(options.package) : null;
352
- let projVal: unknown = undefined;
353
- let fallbackVal: unknown = undefined;
354
- let declaredItem: ConfigItemDefinition | undefined;
355
-
356
- if (projectRoot) {
357
- try {
358
- const projConfig = loadProjectConfig(projectRoot);
359
- declaredItem = projConfig.config?.[key];
360
- const projectStorage = createStorage(projConfig.id, {
361
- projectRoot,
362
- dataDir: options.dataDir,
363
- });
364
- projVal = projectStorage.getConfig(key);
365
- fallbackVal = projConfig.config?.[key]?.default;
366
- projectStorage.close();
367
- } catch {
368
- // Ignore
369
- }
370
- }
371
-
372
- const envVal = typeof process !== "undefined" && process.env ? process.env[key] : undefined;
373
-
374
- const rawEffective =
375
- projVal !== undefined
376
- ? projVal
377
- : globalVal !== undefined
378
- ? globalVal
379
- : envVal !== undefined
380
- ? envVal
381
- : fallbackVal;
382
-
383
- const source: string =
384
- projVal !== undefined
385
- ? "project"
386
- : globalVal !== undefined
387
- ? "global"
388
- : envVal !== undefined
389
- ? "env"
390
- : fallbackVal !== undefined
391
- ? "default"
392
- : "undefined";
393
-
394
- const isSecret = isSecretConfigKey(key, declaredItem);
395
- const effective = !reveal && isSecret && rawEffective !== undefined ? maskSecretValue(rawEffective) : rawEffective;
396
-
397
- if (isMachine) {
398
- renderResult(
399
- {
400
- key,
401
- value: effective,
402
- source,
403
- secret: isSecret,
404
- },
405
- { json: options.json, envelope: options.envelope }
406
- );
407
- } else {
408
- console.log(effective !== undefined ? (typeof effective === "string" && isSecret && !reveal ? effective : JSON.stringify(effective)) : "undefined");
409
- }
410
- } catch (err: any) {
411
- if (err instanceof ArgumentError || err instanceof ExecutionError) {
412
- throw err;
413
- }
414
- throw new ExecutionError(err.message);
415
- }
416
- });
417
-
418
- // config set
419
- configCmd
420
- .command("set <key> <value>")
421
- .description("Set a configuration value (Global by default outside project, or use -g for global)")
422
- .option("-P, --package <id>", "Target package ID or path")
423
- .option("-g, --global", "Set globally across all packages")
424
- .option("-p, --profile <name>", "Set config on a remote target")
425
- .option("-s, --server <url>", "Remote server URL")
426
- .option("-t, --token <token>", "Auth token for remote server")
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) => {
431
- try {
432
- const options = getEffectiveOptions(rawOptions, cmd);
433
- const isMachine = Boolean(options.json || options.envelope);
434
- let parsed: unknown = rawValue;
435
- try {
436
- parsed = JSON.parse(rawValue);
437
- } catch {
438
- parsed = rawValue;
439
- }
440
-
441
- const target = resolveTarget({
442
- profile: options.profile,
443
- server: options.server,
444
- token: options.token,
445
- });
446
-
447
- if (target.type === "remote") {
448
- await setRemoteConfig(target.serverUrl!, key, parsed, target.token, options.package);
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
- }
454
- return;
455
- }
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
-
466
- const projectRoot = !options.global ? resolvePackageRoot(options.package) : null;
467
- const isSecret = isSecretConfigKey(key);
468
- const displayVal = isSecret ? maskSecretValue(parsed) : JSON.stringify(parsed);
469
-
470
- if (options.global || !projectRoot) {
471
- // Set in Global storage
472
- const globalStorage = createGlobalStorage(options.dataDir);
473
- globalStorage.setConfig(key, parsed);
474
- globalStorage.close();
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
- }
480
- } else {
481
- // Set in Project storage
482
- const projConfig = loadProjectConfig(projectRoot);
483
- const storage = createStorage(projConfig.id, {
484
- projectRoot,
485
- dataDir: options.dataDir,
486
- });
487
- storage.setConfig(key, parsed);
488
- storage.close();
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
- }
494
- }
495
- } catch (err: any) {
496
- if (err instanceof ArgumentError || err instanceof ExecutionError) {
497
- throw err;
498
- }
499
- throw new ExecutionError(err.message);
500
- }
501
- });
502
-
503
- // config delete
504
- configCmd
505
- .command("delete <key>")
506
- .alias("rm")
507
- .description("Delete a configuration value")
508
- .option("-P, --package <id>", "Target package ID or path")
509
- .option("-g, --global", "Delete from global configuration")
510
- .option("-p, --profile <name>", "Delete config on a remote target")
511
- .option("-s, --server <url>", "Remote server URL")
512
- .option("-t, --token <token>", "Auth token for remote server")
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) => {
517
- try {
518
- const options = getEffectiveOptions(rawOptions, cmd);
519
- const isMachine = Boolean(options.json || options.envelope);
520
- const target = resolveTarget({
521
- profile: options.profile,
522
- server: options.server,
523
- token: options.token,
524
- });
525
-
526
- if (target.type === "remote") {
527
- const res = await deleteRemoteConfig(target.serverUrl!, key, target.token, options.package);
528
- if (isMachine) {
529
- renderResult(res, { json: options.json, envelope: options.envelope });
530
- } else if (res.deleted) {
531
- console.log(`[OK] Remote config '${key}' deleted from ${target.serverUrl}`);
532
- } else {
533
- console.log(`Remote config '${key}' not found on ${target.serverUrl}`);
534
- }
535
- return;
536
- }
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
-
547
- const projectRoot = !options.global ? resolvePackageRoot(options.package) : null;
548
-
549
- if (options.global || !projectRoot) {
550
- const globalStorage = createGlobalStorage(options.dataDir);
551
- const deleted = globalStorage.deleteConfig(key);
552
- globalStorage.close();
553
- if (isMachine) {
554
- renderResult({ ok: true, key, deleted, scope: "global" }, { json: options.json, envelope: options.envelope });
555
- } else if (deleted) {
556
- console.log(`[OK] Global config '${key}' deleted`);
557
- } else {
558
- console.log(`Global config '${key}' was not found`);
559
- }
560
- } else {
561
- const projConfig = loadProjectConfig(projectRoot);
562
- const storage = createStorage(projConfig.id, {
563
- projectRoot,
564
- dataDir: options.dataDir,
565
- });
566
- const deleted = storage.deleteConfig(key);
567
- storage.close();
568
- if (isMachine) {
569
- renderResult({ ok: true, key, deleted, packageId: projConfig.id }, { json: options.json, envelope: options.envelope });
570
- } else if (deleted) {
571
- console.log(`[OK] Config '${key}' deleted from ${projConfig.id}`);
572
- } else {
573
- console.log(`Config '${key}' was not set in database for ${projConfig.id}`);
574
- }
575
- }
576
- } catch (err: any) {
577
- if (err instanceof ArgumentError || err instanceof ExecutionError) {
578
- throw err;
579
- }
580
- throw new ExecutionError(err.message);
581
- }
582
- });
583
- }
@@ -1,84 +0,0 @@
1
- import { fetchRemoteDoctor, resolveTarget, runDoctorChecks } from "@actiondock/core";
2
- import { ExecutionError, getEffectiveOptions, renderResult } from "@actiondock/runtime-cli";
3
- import { Command } from "commander";
4
-
5
- export function registerDoctorCommand(program: Command): void {
6
- program
7
- .command("doctor")
8
- .description("Check ActionDock environment, registry health, and project diagnostics")
9
- .option("-P, --package <id|path>", "Target package ID or directory path for project diagnostics")
10
- .option("-p, --profile <name>", "Query doctor diagnostics on a remote target")
11
- .option("-s, --server <url>", "Remote server URL")
12
- .option("-t, --token <token>", "Auth token for remote server")
13
- .option("--json", "Output diagnostics report in JSON format")
14
- .option("--envelope", "Wrap JSON output in standard envelope")
15
- .action(async (rawOptions, cmd) => {
16
- try {
17
- const options = getEffectiveOptions(rawOptions, cmd);
18
- const target = resolveTarget({
19
- profile: options.profile,
20
- server: options.server,
21
- token: options.token,
22
- });
23
-
24
- let report;
25
- if (target.type === "remote") {
26
- const remoteRes = await fetchRemoteDoctor(target.serverUrl!, target.token, options.package);
27
- report = remoteRes.report || remoteRes;
28
- } else {
29
- report = await runDoctorChecks({
30
- packageIdOrPath: options.package,
31
- });
32
- }
33
-
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
-
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
-
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)");
69
- }
70
-
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
- });
76
-
77
- if (!report.ok) {
78
- process.exitCode = 1;
79
- }
80
- } catch (err: any) {
81
- throw new ExecutionError(`Doctor failed to run diagnostics: ${err.message}`);
82
- }
83
- });
84
- }