@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/export.ts
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { basename } from "node:path";
|
|
3
|
+
import { exportCompositeSkill, exportSkill, exportSkillBatch } from "@actiondock/builder";
|
|
4
|
+
import { discoverProjects, findProjectRoot, listLinkedPackages, resolvePackageRoot } from "@actiondock/core";
|
|
5
|
+
import { ExecutionError } from "@actiondock/runtime-cli";
|
|
2
6
|
import { Command } from "commander";
|
|
3
7
|
|
|
8
|
+
function parseListOption(val: string, prev: string[] = []): string[] {
|
|
9
|
+
const parts = val.split(",").map((s) => s.trim()).filter(Boolean);
|
|
10
|
+
return [...prev, ...parts];
|
|
11
|
+
}
|
|
12
|
+
|
|
4
13
|
export function registerExportCommand(program: Command): void {
|
|
5
14
|
const exportCmd = program
|
|
6
15
|
.command("export")
|
|
@@ -9,7 +18,18 @@ export function registerExportCommand(program: Command): void {
|
|
|
9
18
|
exportCmd
|
|
10
19
|
.command("skill")
|
|
11
20
|
.description("Export Skill directory for AI Agents (default: source skill; use -s/--standalone for pre-built standalone binary)")
|
|
12
|
-
.option(
|
|
21
|
+
.option(
|
|
22
|
+
"-P, --package <id...>",
|
|
23
|
+
"Target package ID(s) or path(s) (can be specified multiple times or comma-separated)",
|
|
24
|
+
parseListOption,
|
|
25
|
+
[]
|
|
26
|
+
)
|
|
27
|
+
.option("--workspace", "Export all packages discovered in current workspace")
|
|
28
|
+
.option("--all", "Export all linked packages from global registry")
|
|
29
|
+
.option(
|
|
30
|
+
"--bundle [name]",
|
|
31
|
+
"Export multiple packages as a unified composite Skill bundle (defaults to workspace directory name if omitted)"
|
|
32
|
+
)
|
|
13
33
|
.option("-s, --standalone", "Export pre-compiled standalone binary skill (for environments without ActionDock runtime)")
|
|
14
34
|
.option("-t, --target <target>", "Target compilation platform for standalone mode (e.g. host, linux-x64, darwin-arm64, windows-x64)")
|
|
15
35
|
.option("-o, --out <path>", "Output skill directory")
|
|
@@ -20,25 +40,126 @@ export function registerExportCommand(program: Command): void {
|
|
|
20
40
|
.option("--bytecode", "Compile JavaScript to bytecode in standalone mode (default: true)", true)
|
|
21
41
|
.option("--no-bytecode", "Disable bytecode compilation in standalone mode")
|
|
22
42
|
.option("-z, --archive", "Create a .zip archive of the exported skill")
|
|
43
|
+
.option("--skill-md <path>", "Use specified existing SKILL.md file instead of auto-generating")
|
|
23
44
|
.action(async (options) => {
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
45
|
+
const isStandalone = Boolean(options.standalone);
|
|
46
|
+
|
|
47
|
+
if (options.bundle && isStandalone) {
|
|
48
|
+
throw new ExecutionError(
|
|
49
|
+
"Composite Skill export (--bundle) currently only supports source mode. Please remove --standalone to export as a composite workspace Skill."
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const sourceCount =
|
|
54
|
+
(options.all ? 1 : 0) +
|
|
55
|
+
(options.workspace ? 1 : 0) +
|
|
56
|
+
(options.package && options.package.length > 0 ? 1 : 0);
|
|
57
|
+
if (sourceCount > 1) {
|
|
58
|
+
throw new ExecutionError(
|
|
59
|
+
"Options -P/--package, --workspace, and --all are mutually exclusive. Please specify only one package selection mode."
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
let roots: string[] = [];
|
|
27
64
|
|
|
28
|
-
if (
|
|
29
|
-
|
|
30
|
-
|
|
65
|
+
if (options.all) {
|
|
66
|
+
const linked = listLinkedPackages();
|
|
67
|
+
roots = linked.map((p) => p.path).filter((p) => existsSync(p));
|
|
68
|
+
if (roots.length === 0) {
|
|
69
|
+
throw new ExecutionError("No linked packages found in global registry.");
|
|
70
|
+
}
|
|
71
|
+
} else if (options.workspace) {
|
|
72
|
+
const cwd = process.cwd();
|
|
73
|
+
const discovered = discoverProjects(cwd);
|
|
74
|
+
roots = discovered.length > 0 ? discovered : (findProjectRoot(cwd) ? [findProjectRoot(cwd)!] : []);
|
|
75
|
+
if (roots.length === 0) {
|
|
76
|
+
throw new ExecutionError(
|
|
77
|
+
`No ActionDock packages found in workspace '${cwd}'.\nMake sure child directories contain actiondock.json.`
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
} else if (options.package && options.package.length > 0) {
|
|
81
|
+
for (const pkgIdOrPath of options.package) {
|
|
82
|
+
const root = resolvePackageRoot(pkgIdOrPath);
|
|
83
|
+
if (!root) {
|
|
84
|
+
throw new ExecutionError(`Package '${pkgIdOrPath}' not found in linked packages or path`);
|
|
85
|
+
}
|
|
86
|
+
if (!roots.includes(root)) {
|
|
87
|
+
roots.push(root);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
} else {
|
|
91
|
+
const root = findProjectRoot();
|
|
92
|
+
if (root) {
|
|
93
|
+
roots.push(root);
|
|
31
94
|
} else {
|
|
32
|
-
|
|
33
|
-
"
|
|
95
|
+
throw new ExecutionError(
|
|
96
|
+
"Not in an ActionDock project (actiondock.json not found).\nPlease specify -P, --package <id>, --workspace, --all, or cd into a project directory."
|
|
34
97
|
);
|
|
35
98
|
}
|
|
36
|
-
process.exit(1);
|
|
37
99
|
}
|
|
38
100
|
|
|
39
|
-
|
|
101
|
+
if (roots.length > 1 && (options.actions || options.playbook)) {
|
|
102
|
+
throw new ExecutionError(
|
|
103
|
+
"Filtering options (--actions, --playbook) can only be used when exporting a single package."
|
|
104
|
+
);
|
|
105
|
+
}
|
|
40
106
|
|
|
41
107
|
try {
|
|
108
|
+
if (options.bundle !== undefined) {
|
|
109
|
+
const bundleName =
|
|
110
|
+
typeof options.bundle === "string" && options.bundle.trim()
|
|
111
|
+
? options.bundle.trim()
|
|
112
|
+
: basename(process.cwd());
|
|
113
|
+
console.log(`Exporting composite Skill bundle '${bundleName}' (${roots.length} package${roots.length > 1 ? "s" : ""})...`);
|
|
114
|
+
const result = await exportCompositeSkill({
|
|
115
|
+
bundleName,
|
|
116
|
+
projectRoots: roots,
|
|
117
|
+
outDir: options.out,
|
|
118
|
+
archive: options.archive,
|
|
119
|
+
workspaceRoot: options.workspace ? process.cwd() : undefined,
|
|
120
|
+
skillMdPath: options.skillMd,
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
console.log(`[OK] Successfully exported Composite Skill: ${result.bundleName}`);
|
|
124
|
+
console.log(` Packages: ${result.packagesCount}`);
|
|
125
|
+
console.log(` Actions: ${result.actionsCount}`);
|
|
126
|
+
console.log(` Playbooks: ${result.playbooksCount}`);
|
|
127
|
+
console.log(` Skill Dir: ${result.skillDir}`);
|
|
128
|
+
if (result.usedExistingSkillMd) {
|
|
129
|
+
console.log(` SKILL.md: Reused existing file from ${result.usedExistingSkillMd}`);
|
|
130
|
+
}
|
|
131
|
+
if (result.archivePath) {
|
|
132
|
+
console.log(` Archive: ${result.archivePath}`);
|
|
133
|
+
}
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (roots.length > 1) {
|
|
138
|
+
console.log(`Batch exporting ${roots.length} Skill packages...`);
|
|
139
|
+
const batchRes = await exportSkillBatch({
|
|
140
|
+
projectRoots: roots,
|
|
141
|
+
mode: isStandalone ? "standalone" : "source",
|
|
142
|
+
standalone: isStandalone,
|
|
143
|
+
target: options.target,
|
|
144
|
+
outDir: options.out,
|
|
145
|
+
archive: options.archive,
|
|
146
|
+
playbooks: options.playbook,
|
|
147
|
+
actions: options.actions,
|
|
148
|
+
minify: options.minify,
|
|
149
|
+
bytecode: options.bytecode,
|
|
150
|
+
skillMdPath: options.skillMd,
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
console.log(`[OK] Successfully batch exported ${batchRes.results.length} Skill packages to: ${batchRes.outDir}`);
|
|
154
|
+
for (const res of batchRes.results) {
|
|
155
|
+
console.log(` - ${res.packageId} (v${res.version}): ${res.actionsCount} actions, ${res.playbooksCount} playbooks -> ${res.skillDir}`);
|
|
156
|
+
}
|
|
157
|
+
console.log(` Total Actions: ${batchRes.totalActions}`);
|
|
158
|
+
console.log(` Total Playbooks: ${batchRes.totalPlaybooks}`);
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const root = roots[0];
|
|
42
163
|
console.log(`Exporting ${isStandalone ? "standalone binary" : "source"} Skill artifact...`);
|
|
43
164
|
const result = await exportSkill({
|
|
44
165
|
projectRoot: root,
|
|
@@ -51,6 +172,7 @@ export function registerExportCommand(program: Command): void {
|
|
|
51
172
|
actions: options.actions,
|
|
52
173
|
minify: options.minify,
|
|
53
174
|
bytecode: options.bytecode,
|
|
175
|
+
skillMdPath: options.skillMd,
|
|
54
176
|
});
|
|
55
177
|
|
|
56
178
|
console.log(`[OK] Successfully exported ${result.mode === "standalone" ? "Standalone" : "Source"} Skill: ${result.packageId} (v${result.version})`);
|
|
@@ -58,13 +180,17 @@ export function registerExportCommand(program: Command): void {
|
|
|
58
180
|
console.log(` Actions: ${result.actionsCount}`);
|
|
59
181
|
console.log(` Playbooks: ${result.playbooksCount}`);
|
|
60
182
|
console.log(` Skill Dir: ${result.skillDir}`);
|
|
183
|
+
if (result.usedExistingSkillMd) {
|
|
184
|
+
console.log(` SKILL.md: Reused existing file from ${result.usedExistingSkillMd}`);
|
|
185
|
+
}
|
|
61
186
|
if (result.archivePath) {
|
|
62
187
|
console.log(` Archive: ${result.archivePath}`);
|
|
63
188
|
}
|
|
64
189
|
} catch (err: any) {
|
|
65
|
-
|
|
66
|
-
process.exit(1);
|
|
190
|
+
throw new ExecutionError(`Export failed: ${err.message}`);
|
|
67
191
|
}
|
|
68
192
|
});
|
|
69
193
|
}
|
|
70
194
|
|
|
195
|
+
|
|
196
|
+
|
package/src/commands/index.ts
CHANGED
|
@@ -15,13 +15,43 @@ import { registerServeCommand } from "./serve";
|
|
|
15
15
|
import { registerStateCommands } from "./state";
|
|
16
16
|
import { registerTestCommand } from "./test";
|
|
17
17
|
|
|
18
|
+
function applyCommonOptions(cmd: Command): void {
|
|
19
|
+
const hasOpt = (flagName: string) =>
|
|
20
|
+
cmd.options.some((o) => o.name() === flagName || o.long === `--${flagName}`);
|
|
21
|
+
|
|
22
|
+
if (!hasOpt("json")) {
|
|
23
|
+
cmd.option("--json", "Output as JSON");
|
|
24
|
+
}
|
|
25
|
+
if (!hasOpt("envelope")) {
|
|
26
|
+
cmd.option("--envelope", "Wrap JSON output in standard envelope");
|
|
27
|
+
}
|
|
28
|
+
if (!hasOpt("dataDir") && !hasOpt("data-dir")) {
|
|
29
|
+
cmd.option("--data-dir <path>", "Custom database storage directory");
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
for (const sub of cmd.commands) {
|
|
33
|
+
applyCommonOptions(sub);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
18
37
|
export function createCliProgram(): Command {
|
|
19
38
|
const program = new Command();
|
|
20
39
|
|
|
21
40
|
program
|
|
22
41
|
.name("ad")
|
|
23
42
|
.description("ActionDock (ad) 2.0 - Toolchain for building and shipping standalone AI Agent Actions & Skills")
|
|
24
|
-
.version("2.0.
|
|
43
|
+
.version("2.0.11-beta.0", "-v, --version");
|
|
44
|
+
|
|
45
|
+
program.option("-V", "output the version number");
|
|
46
|
+
program.on("option:V", () => {
|
|
47
|
+
(program as any)._outputConfiguration.writeOut(`${program.version()}\n`);
|
|
48
|
+
(program as any)._exit(0, "commander.version", program.version()!);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// 禁用 Commander 内部直接 process.exit,统一由顶层调度器管控退出码
|
|
52
|
+
program.exitOverride((err) => {
|
|
53
|
+
throw err;
|
|
54
|
+
});
|
|
25
55
|
|
|
26
56
|
registerInitCommand(program);
|
|
27
57
|
registerInfoCommand(program);
|
|
@@ -39,5 +69,7 @@ export function createCliProgram(): Command {
|
|
|
39
69
|
registerServeCommand(program);
|
|
40
70
|
registerMcpCommands(program);
|
|
41
71
|
|
|
72
|
+
applyCommonOptions(program);
|
|
73
|
+
|
|
42
74
|
return program;
|
|
43
75
|
}
|
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
|
}
|