@actiondock/cli 2.0.8 → 2.0.10
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 +65067 -0
- package/package.json +16 -8
- 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 +9 -9
- 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/info.ts
CHANGED
|
@@ -5,13 +5,14 @@ import {
|
|
|
5
5
|
findProjectRoot,
|
|
6
6
|
getRegistryStatus,
|
|
7
7
|
listLinkedPackages,
|
|
8
|
-
|
|
8
|
+
loadManifest,
|
|
9
9
|
loadPlaybooks,
|
|
10
10
|
loadProjectConfig,
|
|
11
11
|
resolvePackageRoot,
|
|
12
12
|
resolveTarget,
|
|
13
13
|
} from "@actiondock/core";
|
|
14
14
|
import { Command } from "commander";
|
|
15
|
+
import { ArgumentError, CliError, ExecutionError, getEffectiveOptions, renderResult } from "@actiondock/runtime-cli";
|
|
15
16
|
import { resolveIntent } from "../utils/filter";
|
|
16
17
|
|
|
17
18
|
interface AggregatedPackage {
|
|
@@ -29,7 +30,16 @@ interface AggregatedPackage {
|
|
|
29
30
|
|
|
30
31
|
async function getProjectDetailInfo(root: string) {
|
|
31
32
|
const config = loadProjectConfig(root);
|
|
32
|
-
const
|
|
33
|
+
const manifest = loadManifest(root);
|
|
34
|
+
const actionsMap = new Map<string, { id: string; description?: string }>();
|
|
35
|
+
if (manifest?.actions) {
|
|
36
|
+
for (const [id, item] of Object.entries(manifest.actions)) {
|
|
37
|
+
actionsMap.set(id, {
|
|
38
|
+
id,
|
|
39
|
+
description: item.description,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
}
|
|
33
43
|
const playbooks = loadPlaybooks(root, config.playbooksDir);
|
|
34
44
|
|
|
35
45
|
return {
|
|
@@ -40,13 +50,13 @@ async function getProjectDetailInfo(root: string) {
|
|
|
40
50
|
projectRoot: root,
|
|
41
51
|
actionsDir: config.actionsDir || "actions",
|
|
42
52
|
playbooksDir: config.playbooksDir || "playbooks",
|
|
43
|
-
actionsCount:
|
|
53
|
+
actionsCount: actionsMap.size,
|
|
44
54
|
playbooksCount: playbooks.size,
|
|
45
|
-
actions: Array.from(
|
|
55
|
+
actions: Array.from(actionsMap.keys()),
|
|
46
56
|
playbooks: Array.from(playbooks.keys()),
|
|
47
57
|
configDeclared: config.config ? Object.keys(config.config) : [],
|
|
48
58
|
configDef: config.config,
|
|
49
|
-
actionsMap
|
|
59
|
+
actionsMap,
|
|
50
60
|
playbooksMap: playbooks,
|
|
51
61
|
};
|
|
52
62
|
}
|
|
@@ -184,15 +194,21 @@ export function registerInfoCommand(program: Command): void {
|
|
|
184
194
|
.option("-p, --profile <name>", "Query against a specific profile")
|
|
185
195
|
.option("-s, --server <url>", "Remote server URL")
|
|
186
196
|
.option("-t, --token <token>", "Auth token for remote server")
|
|
197
|
+
.option("--fallback", "Enable fallback to full list when no items match intent")
|
|
187
198
|
.option(
|
|
188
199
|
"--no-fallback",
|
|
189
200
|
"Disable fallback to full list when no items match intent"
|
|
190
201
|
)
|
|
191
202
|
.option("--json", "Output information as JSON")
|
|
192
|
-
.
|
|
203
|
+
.option("--envelope", "Wrap JSON output in standard envelope")
|
|
204
|
+
.option("--data-dir <path>", "Custom database storage directory")
|
|
205
|
+
.action(async (patterns: string[] = [], rawOptions: any, cmd: any) => {
|
|
193
206
|
try {
|
|
207
|
+
const options = getEffectiveOptions(rawOptions, cmd);
|
|
194
208
|
const effectiveIntent = resolveIntent(options.intent, patterns);
|
|
195
|
-
const
|
|
209
|
+
const isMachine = Boolean(options.json || options.envelope);
|
|
210
|
+
const fallbackExplicit = options.fallback === true || (Array.isArray(process.argv) && process.argv.includes("--fallback"));
|
|
211
|
+
const shouldFallback = isMachine ? fallbackExplicit : options.fallback !== false;
|
|
196
212
|
|
|
197
213
|
const target = resolveTarget({
|
|
198
214
|
profile: options.profile,
|
|
@@ -212,8 +228,8 @@ export function registerInfoCommand(program: Command): void {
|
|
|
212
228
|
}
|
|
213
229
|
);
|
|
214
230
|
|
|
215
|
-
if (
|
|
216
|
-
|
|
231
|
+
if (isMachine) {
|
|
232
|
+
renderResult(remoteInfo, { json: options.json, envelope: options.envelope });
|
|
217
233
|
return;
|
|
218
234
|
}
|
|
219
235
|
|
|
@@ -304,8 +320,8 @@ export function registerInfoCommand(program: Command): void {
|
|
|
304
320
|
// Local Tree
|
|
305
321
|
if (options.tree) {
|
|
306
322
|
const status = getRegistryStatus();
|
|
307
|
-
if (
|
|
308
|
-
|
|
323
|
+
if (isMachine) {
|
|
324
|
+
renderResult(status, { json: options.json, envelope: options.envelope });
|
|
309
325
|
} else {
|
|
310
326
|
printRegistryTree(status);
|
|
311
327
|
}
|
|
@@ -317,17 +333,16 @@ export function registerInfoCommand(program: Command): void {
|
|
|
317
333
|
const directRoot = resolvePackageRoot(options.package);
|
|
318
334
|
if (directRoot) {
|
|
319
335
|
const detail = await getProjectDetailInfo(directRoot);
|
|
320
|
-
if (
|
|
321
|
-
|
|
336
|
+
if (isMachine) {
|
|
337
|
+
renderResult(projectDetailToJson(detail), { json: options.json, envelope: options.envelope });
|
|
322
338
|
} else {
|
|
323
339
|
printProjectDetail(detail);
|
|
324
340
|
}
|
|
325
341
|
return;
|
|
326
342
|
}
|
|
327
|
-
|
|
328
|
-
`
|
|
343
|
+
throw new ArgumentError(
|
|
344
|
+
`Package '${options.package}' not found in linked packages or path`
|
|
329
345
|
);
|
|
330
|
-
process.exit(1);
|
|
331
346
|
}
|
|
332
347
|
|
|
333
348
|
// 3. Collect local candidate packages (current project + linked packages)
|
|
@@ -339,7 +354,8 @@ export function registerInfoCommand(program: Command): void {
|
|
|
339
354
|
if (currentRoot) {
|
|
340
355
|
try {
|
|
341
356
|
const config = loadProjectConfig(currentRoot);
|
|
342
|
-
const
|
|
357
|
+
const manifest = loadManifest(currentRoot);
|
|
358
|
+
const manifestActionIds = manifest?.actions ? Object.keys(manifest.actions) : [];
|
|
343
359
|
const playbooks = loadPlaybooks(currentRoot, config.playbooksDir);
|
|
344
360
|
aggregated.push({
|
|
345
361
|
id: config.id,
|
|
@@ -347,9 +363,9 @@ export function registerInfoCommand(program: Command): void {
|
|
|
347
363
|
version: config.version,
|
|
348
364
|
description: config.description,
|
|
349
365
|
path: currentRoot,
|
|
350
|
-
actionsCount:
|
|
366
|
+
actionsCount: manifestActionIds.length,
|
|
351
367
|
playbooksCount: playbooks.size,
|
|
352
|
-
actions:
|
|
368
|
+
actions: manifestActionIds,
|
|
353
369
|
playbooks: Array.from(playbooks.keys()),
|
|
354
370
|
configDeclared: config.config ? Object.keys(config.config) : [],
|
|
355
371
|
});
|
|
@@ -364,7 +380,8 @@ export function registerInfoCommand(program: Command): void {
|
|
|
364
380
|
if (seenPaths.has(pkg.path)) continue;
|
|
365
381
|
try {
|
|
366
382
|
const config = loadProjectConfig(pkg.path);
|
|
367
|
-
const
|
|
383
|
+
const manifest = loadManifest(pkg.path);
|
|
384
|
+
const manifestActionIds = manifest?.actions ? Object.keys(manifest.actions) : [];
|
|
368
385
|
const playbooks = loadPlaybooks(pkg.path, config.playbooksDir);
|
|
369
386
|
|
|
370
387
|
aggregated.push({
|
|
@@ -373,9 +390,9 @@ export function registerInfoCommand(program: Command): void {
|
|
|
373
390
|
version: config.version,
|
|
374
391
|
description: config.description,
|
|
375
392
|
path: pkg.path,
|
|
376
|
-
actionsCount:
|
|
393
|
+
actionsCount: manifestActionIds.length,
|
|
377
394
|
playbooksCount: playbooks.size,
|
|
378
|
-
actions:
|
|
395
|
+
actions: manifestActionIds,
|
|
379
396
|
playbooks: Array.from(playbooks.keys()),
|
|
380
397
|
configDeclared: config.config ? Object.keys(config.config) : [],
|
|
381
398
|
});
|
|
@@ -389,8 +406,8 @@ export function registerInfoCommand(program: Command): void {
|
|
|
389
406
|
if (!effectiveIntent) {
|
|
390
407
|
if (currentRoot) {
|
|
391
408
|
const detail = await getProjectDetailInfo(currentRoot);
|
|
392
|
-
if (
|
|
393
|
-
|
|
409
|
+
if (isMachine) {
|
|
410
|
+
renderResult(projectDetailToJson(detail), { json: options.json, envelope: options.envelope });
|
|
394
411
|
} else {
|
|
395
412
|
printProjectDetail(detail);
|
|
396
413
|
}
|
|
@@ -398,19 +415,21 @@ export function registerInfoCommand(program: Command): void {
|
|
|
398
415
|
}
|
|
399
416
|
|
|
400
417
|
if (aggregated.length === 0) {
|
|
418
|
+
if (isMachine) {
|
|
419
|
+
renderResult({ linkedPackages: [] }, { json: options.json, envelope: options.envelope });
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
401
422
|
console.log(
|
|
402
423
|
"No ActionDock project in current directory, and no packages linked."
|
|
403
424
|
);
|
|
404
425
|
console.log(
|
|
405
|
-
"Run 'ad link' inside an Action package
|
|
426
|
+
"Run 'ad link' inside an Action package or specify a target package."
|
|
406
427
|
);
|
|
407
428
|
return;
|
|
408
429
|
}
|
|
409
430
|
|
|
410
|
-
if (
|
|
411
|
-
|
|
412
|
-
JSON.stringify({ linkedPackages: aggregated }, null, 2)
|
|
413
|
-
);
|
|
431
|
+
if (isMachine) {
|
|
432
|
+
renderResult({ linkedPackages: aggregated }, { json: options.json, envelope: options.envelope });
|
|
414
433
|
} else {
|
|
415
434
|
printAggregatedPackages(aggregated);
|
|
416
435
|
}
|
|
@@ -423,8 +442,8 @@ export function registerInfoCommand(program: Command): void {
|
|
|
423
442
|
const directRoot = resolvePackageRoot(patterns[0]);
|
|
424
443
|
if (directRoot) {
|
|
425
444
|
const detail = await getProjectDetailInfo(directRoot);
|
|
426
|
-
if (
|
|
427
|
-
|
|
445
|
+
if (isMachine) {
|
|
446
|
+
renderResult(projectDetailToJson(detail), { json: options.json, envelope: options.envelope });
|
|
428
447
|
} else {
|
|
429
448
|
printProjectDetail(detail);
|
|
430
449
|
}
|
|
@@ -433,10 +452,13 @@ export function registerInfoCommand(program: Command): void {
|
|
|
433
452
|
}
|
|
434
453
|
|
|
435
454
|
if (aggregated.length === 0) {
|
|
436
|
-
|
|
437
|
-
|
|
455
|
+
if (isMachine) {
|
|
456
|
+
renderResult({ linkedPackages: [], matchedCount: 0, isFallback: false }, { json: options.json, envelope: options.envelope });
|
|
457
|
+
return;
|
|
458
|
+
}
|
|
459
|
+
throw new ExecutionError(
|
|
460
|
+
`No ActionDock project or linked packages available to match '${effectiveIntent}'`
|
|
438
461
|
);
|
|
439
|
-
process.exit(1);
|
|
440
462
|
}
|
|
441
463
|
|
|
442
464
|
// 5.2 Intent filtering across candidate packages
|
|
@@ -456,61 +478,58 @@ export function registerInfoCommand(program: Command): void {
|
|
|
456
478
|
|
|
457
479
|
// Subcase A: 0 items matched
|
|
458
480
|
if (filterRes.matchedCount === 0) {
|
|
459
|
-
if (!
|
|
460
|
-
if (
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
console.error(
|
|
464
|
-
`Error: No packages matched intent '${effectiveIntent}'`
|
|
465
|
-
);
|
|
481
|
+
if (!filterRes.isFallback) {
|
|
482
|
+
if (isMachine) {
|
|
483
|
+
renderResult({ linkedPackages: [], matchedCount: 0, isFallback: false }, { json: options.json, envelope: options.envelope });
|
|
484
|
+
return;
|
|
466
485
|
}
|
|
467
|
-
|
|
486
|
+
throw new ExecutionError(
|
|
487
|
+
`No packages matched intent '${effectiveIntent}'`
|
|
488
|
+
);
|
|
468
489
|
}
|
|
469
490
|
|
|
470
491
|
// Fallback enabled: display all packages with a notice
|
|
471
|
-
if (
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
null,
|
|
476
|
-
2
|
|
477
|
-
)
|
|
492
|
+
if (isMachine) {
|
|
493
|
+
renderResult(
|
|
494
|
+
{ linkedPackages: filterRes.items, isFallback: true, matchedCount: 0 },
|
|
495
|
+
{ json: options.json, envelope: options.envelope }
|
|
478
496
|
);
|
|
479
|
-
|
|
480
|
-
console.log(
|
|
481
|
-
`(No linked packages matched intent '${effectiveIntent}', showing all packages)\n`
|
|
482
|
-
);
|
|
483
|
-
printAggregatedPackages(filterRes.items);
|
|
497
|
+
return;
|
|
484
498
|
}
|
|
499
|
+
console.log(
|
|
500
|
+
`(No linked packages matched intent '${effectiveIntent}', showing all packages)\n`
|
|
501
|
+
);
|
|
502
|
+
printAggregatedPackages(filterRes.items);
|
|
485
503
|
return;
|
|
486
504
|
}
|
|
487
505
|
|
|
488
|
-
// Subcase B:
|
|
489
|
-
if (
|
|
506
|
+
// Subcase B: Matched items in machine mode
|
|
507
|
+
if (isMachine) {
|
|
508
|
+
renderResult(
|
|
509
|
+
{ linkedPackages: filterRes.items, matchedCount: filterRes.matchedCount, isFallback: false },
|
|
510
|
+
{ json: options.json, envelope: options.envelope }
|
|
511
|
+
);
|
|
512
|
+
return;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
// Subcase C: Exactly 1 item matched in human terminal mode -> Display full project detail
|
|
516
|
+
if (filterRes.matchedCount === 1) {
|
|
490
517
|
const matchedPkg = filterRes.items[0];
|
|
491
518
|
const detail = await getProjectDetailInfo(matchedPkg.path);
|
|
492
|
-
|
|
493
|
-
console.log(JSON.stringify(projectDetailToJson(detail), null, 2));
|
|
494
|
-
} else {
|
|
495
|
-
printProjectDetail(detail);
|
|
496
|
-
}
|
|
519
|
+
printProjectDetail(detail);
|
|
497
520
|
return;
|
|
498
521
|
}
|
|
499
522
|
|
|
500
|
-
// Subcase
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
} else {
|
|
506
|
-
printAggregatedPackages(filterRes.items, {
|
|
507
|
-
header: `ActionDock Linked Packages (${filterRes.matchedCount} matches for '${effectiveIntent}'):\n`,
|
|
508
|
-
showTip: true,
|
|
509
|
-
});
|
|
510
|
-
}
|
|
523
|
+
// Subcase D: Multiple items matched in human terminal mode -> Display filtered summary list
|
|
524
|
+
printAggregatedPackages(filterRes.items, {
|
|
525
|
+
header: `ActionDock Linked Packages (${filterRes.matchedCount} matches for '${effectiveIntent}'):\n`,
|
|
526
|
+
showTip: true,
|
|
527
|
+
});
|
|
511
528
|
} catch (err: any) {
|
|
512
|
-
|
|
513
|
-
|
|
529
|
+
if (err instanceof CliError) {
|
|
530
|
+
throw err;
|
|
531
|
+
}
|
|
532
|
+
throw new ExecutionError(err.message);
|
|
514
533
|
}
|
|
515
534
|
});
|
|
516
535
|
}
|
package/src/commands/init.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { initProject } from "@actiondock/core";
|
|
2
|
+
import { ExecutionError } from "@actiondock/runtime-cli";
|
|
2
3
|
import { Command } from "commander";
|
|
3
4
|
|
|
4
5
|
export function registerInitCommand(program: Command): void {
|
|
@@ -17,8 +18,7 @@ export function registerInitCommand(program: Command): void {
|
|
|
17
18
|
});
|
|
18
19
|
console.log(`Successfully initialized ActionDock project in ${dir}`);
|
|
19
20
|
} catch (err: any) {
|
|
20
|
-
|
|
21
|
-
process.exit(1);
|
|
21
|
+
throw new ExecutionError(err.message);
|
|
22
22
|
}
|
|
23
23
|
});
|
|
24
24
|
}
|
package/src/commands/link.ts
CHANGED
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
pruneRegistry,
|
|
4
4
|
unlinkPackage,
|
|
5
5
|
} from "@actiondock/core";
|
|
6
|
+
import { ExecutionError } from "@actiondock/runtime-cli";
|
|
6
7
|
import { Command } from "commander";
|
|
7
8
|
|
|
8
9
|
export function registerLinkCommands(program: Command): void {
|
|
@@ -27,8 +28,7 @@ export function registerLinkCommands(program: Command): void {
|
|
|
27
28
|
console.log(`[OK] Linked package '${result.id}' (v${result.version}) from ${result.path}`);
|
|
28
29
|
}
|
|
29
30
|
} catch (err: any) {
|
|
30
|
-
|
|
31
|
-
process.exit(1);
|
|
31
|
+
throw new ExecutionError(err.message);
|
|
32
32
|
}
|
|
33
33
|
});
|
|
34
34
|
|
|
@@ -67,8 +67,7 @@ export function registerLinkCommands(program: Command): void {
|
|
|
67
67
|
console.log(`Package or workspace '${identifier || process.cwd()}' was not linked in registry`);
|
|
68
68
|
}
|
|
69
69
|
} catch (err: any) {
|
|
70
|
-
|
|
71
|
-
process.exit(1);
|
|
70
|
+
throw new ExecutionError(err.message);
|
|
72
71
|
}
|
|
73
72
|
});
|
|
74
73
|
}
|
package/src/commands/mcp.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { resolve } from "node:path";
|
|
|
2
2
|
import { findProjectRoot, loadProjectConfig } from "@actiondock/core";
|
|
3
3
|
import { startMcpHttpServer, startMcpStdio } from "@actiondock/mcp";
|
|
4
4
|
import { Command } from "commander";
|
|
5
|
+
import { ExecutionError } from "@actiondock/runtime-cli";
|
|
5
6
|
import { parseByteSize } from "../utils/bytes";
|
|
6
7
|
import { parseDuration } from "../utils/duration";
|
|
7
8
|
|
|
@@ -35,8 +36,7 @@ export function registerMcpCommands(program: Command): void {
|
|
|
35
36
|
try {
|
|
36
37
|
timeoutMs = parseDuration(options.timeout);
|
|
37
38
|
} catch (err: any) {
|
|
38
|
-
|
|
39
|
-
process.exit(1);
|
|
39
|
+
throw new ExecutionError(err.message);
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
42
|
|
|
@@ -56,8 +56,7 @@ export function registerMcpCommands(program: Command): void {
|
|
|
56
56
|
timeoutMs,
|
|
57
57
|
});
|
|
58
58
|
} catch (err: any) {
|
|
59
|
-
|
|
60
|
-
process.exit(1);
|
|
59
|
+
throw new ExecutionError(`Failed to start MCP STDIO server: ${err.message}`);
|
|
61
60
|
}
|
|
62
61
|
});
|
|
63
62
|
|
|
@@ -106,8 +105,7 @@ export function registerMcpCommands(program: Command): void {
|
|
|
106
105
|
try {
|
|
107
106
|
maxBodyBytes = parseByteSize(options.maxBody);
|
|
108
107
|
} catch (err: any) {
|
|
109
|
-
|
|
110
|
-
process.exit(1);
|
|
108
|
+
throw new ExecutionError(err.message);
|
|
111
109
|
}
|
|
112
110
|
}
|
|
113
111
|
|
|
@@ -116,8 +114,7 @@ export function registerMcpCommands(program: Command): void {
|
|
|
116
114
|
try {
|
|
117
115
|
timeoutMs = parseDuration(options.timeout);
|
|
118
116
|
} catch (err: any) {
|
|
119
|
-
|
|
120
|
-
process.exit(1);
|
|
117
|
+
throw new ExecutionError(err.message);
|
|
121
118
|
}
|
|
122
119
|
}
|
|
123
120
|
|
|
@@ -192,8 +189,7 @@ export function registerMcpCommands(program: Command): void {
|
|
|
192
189
|
process.exit(0);
|
|
193
190
|
});
|
|
194
191
|
} catch (err: any) {
|
|
195
|
-
|
|
196
|
-
process.exit(1);
|
|
192
|
+
throw new ExecutionError(`Failed to start ActionDock MCP HTTP server: ${err.message}`);
|
|
197
193
|
}
|
|
198
194
|
});
|
|
199
195
|
}
|