@actiondock/cli 2.0.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 +85 -0
- package/bin/ac.js +4 -0
- package/dist/index.js +44620 -0
- package/package.json +51 -0
- package/src/commands/action.ts +602 -0
- package/src/commands/build.ts +54 -0
- package/src/commands/config.ts +398 -0
- package/src/commands/doctor.ts +64 -0
- package/src/commands/export.ts +70 -0
- package/src/commands/index.ts +43 -0
- package/src/commands/info.ts +539 -0
- package/src/commands/init.ts +24 -0
- package/src/commands/link.ts +74 -0
- package/src/commands/mcp.ts +199 -0
- package/src/commands/playbook.ts +359 -0
- package/src/commands/profile.ts +263 -0
- package/src/commands/runs.ts +319 -0
- package/src/commands/serve.ts +101 -0
- package/src/commands/state.ts +396 -0
- package/src/commands/test.ts +26 -0
- package/src/index.ts +20 -0
- package/src/utils/bytes.ts +36 -0
- package/src/utils/duration.ts +1 -0
- package/src/utils/filter.ts +24 -0
|
@@ -0,0 +1,398 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createGlobalStorage,
|
|
3
|
+
createStorage,
|
|
4
|
+
filterWithFallbackInfo,
|
|
5
|
+
isSecretConfigKey,
|
|
6
|
+
loadProjectConfig,
|
|
7
|
+
maskSecretValue,
|
|
8
|
+
resolvePackageRoot,
|
|
9
|
+
type ConfigItemDefinition,
|
|
10
|
+
} from "@actiondock/core";
|
|
11
|
+
import { Command } from "commander";
|
|
12
|
+
import { resolveIntent } from "../utils/filter";
|
|
13
|
+
|
|
14
|
+
export function registerConfigCommands(program: Command): void {
|
|
15
|
+
const configCmd = program
|
|
16
|
+
.command("config")
|
|
17
|
+
.description("Manage runtime configuration store (Global & Project-level)");
|
|
18
|
+
|
|
19
|
+
// config schema / check
|
|
20
|
+
configCmd
|
|
21
|
+
.command("schema [identifier]")
|
|
22
|
+
.alias("check")
|
|
23
|
+
.description("Inspect declared configuration requirements and check resolution status")
|
|
24
|
+
.option("-P, --package <id>", "Target package ID or path")
|
|
25
|
+
.option("--json", "Output as JSON")
|
|
26
|
+
.action((identifier, options) => {
|
|
27
|
+
try {
|
|
28
|
+
const root = resolvePackageRoot(identifier || options.package);
|
|
29
|
+
if (!root) {
|
|
30
|
+
console.error(
|
|
31
|
+
"Error: Not in an ActionDock project.\nUsage: ac config schema [package-id] or cd into a project directory."
|
|
32
|
+
);
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const projConfig = loadProjectConfig(root);
|
|
37
|
+
const declared = projConfig.config || {};
|
|
38
|
+
const declaredKeys = Object.keys(declared);
|
|
39
|
+
|
|
40
|
+
const globalStorage = createGlobalStorage();
|
|
41
|
+
const globalConfig = globalStorage.listConfig();
|
|
42
|
+
globalStorage.close();
|
|
43
|
+
|
|
44
|
+
const projectStorage = createStorage(projConfig.id, { projectRoot: root });
|
|
45
|
+
const projectConfig = projectStorage.listConfig();
|
|
46
|
+
projectStorage.close();
|
|
47
|
+
|
|
48
|
+
const items = declaredKeys.map((key) => {
|
|
49
|
+
const itemDef = declared[key];
|
|
50
|
+
const isSecret = isSecretConfigKey(key, itemDef);
|
|
51
|
+
|
|
52
|
+
let resolvedValue: unknown;
|
|
53
|
+
let source: "project" | "global" | "env" | "default" | "missing" = "missing";
|
|
54
|
+
let status: "SET" | "DEFAULT" | "MISSING" = "MISSING";
|
|
55
|
+
|
|
56
|
+
if (projectConfig[key] !== undefined) {
|
|
57
|
+
resolvedValue = projectConfig[key];
|
|
58
|
+
source = "project";
|
|
59
|
+
status = "SET";
|
|
60
|
+
} else if (globalConfig[key] !== undefined) {
|
|
61
|
+
resolvedValue = globalConfig[key];
|
|
62
|
+
source = "global";
|
|
63
|
+
status = "SET";
|
|
64
|
+
} else if (typeof process !== "undefined" && process.env && process.env[key] !== undefined) {
|
|
65
|
+
resolvedValue = process.env[key];
|
|
66
|
+
source = "env";
|
|
67
|
+
status = "SET";
|
|
68
|
+
} else if (itemDef.default !== undefined) {
|
|
69
|
+
resolvedValue = itemDef.default;
|
|
70
|
+
source = "default";
|
|
71
|
+
status = "DEFAULT";
|
|
72
|
+
} else {
|
|
73
|
+
status = "MISSING";
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return {
|
|
77
|
+
key,
|
|
78
|
+
description: itemDef.description || "",
|
|
79
|
+
secret: isSecret,
|
|
80
|
+
default: itemDef.default,
|
|
81
|
+
status,
|
|
82
|
+
source,
|
|
83
|
+
value: isSecret && resolvedValue !== undefined ? maskSecretValue(resolvedValue) : resolvedValue,
|
|
84
|
+
required: itemDef.default === undefined,
|
|
85
|
+
};
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
const missingRequired = items.filter((i) => i.status === "MISSING");
|
|
89
|
+
|
|
90
|
+
if (options.json) {
|
|
91
|
+
console.log(
|
|
92
|
+
JSON.stringify(
|
|
93
|
+
{
|
|
94
|
+
packageId: projConfig.id,
|
|
95
|
+
projectRoot: root,
|
|
96
|
+
allReady: missingRequired.length === 0,
|
|
97
|
+
configs: items,
|
|
98
|
+
},
|
|
99
|
+
null,
|
|
100
|
+
2
|
|
101
|
+
)
|
|
102
|
+
);
|
|
103
|
+
} else {
|
|
104
|
+
console.log(`Configuration Requirements for ${projConfig.id} (${root}):\n`);
|
|
105
|
+
if (items.length === 0) {
|
|
106
|
+
console.log(" (No configuration dependencies declared for this package)");
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
console.log(
|
|
111
|
+
` ${"KEY".padEnd(24)} ${"STATUS".padEnd(12)} ${"SOURCE".padEnd(10)} ${"SECRET".padEnd(8)} DESCRIPTION`
|
|
112
|
+
);
|
|
113
|
+
console.log(" " + "-".repeat(85));
|
|
114
|
+
|
|
115
|
+
for (const item of items) {
|
|
116
|
+
const statusLabel = item.status === "SET" ? "[SET]" : item.status === "DEFAULT" ? "[DEFAULT]" : "[MISSING]";
|
|
117
|
+
const secretLabel = item.secret ? "yes" : "no";
|
|
118
|
+
console.log(
|
|
119
|
+
` ${item.key.padEnd(24)} ${statusLabel.padEnd(12)} ${item.source.padEnd(10)} ${secretLabel.padEnd(8)} ${item.description}`
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (missingRequired.length > 0) {
|
|
124
|
+
console.log(`\n[WARNING] ${missingRequired.length} required config(s) not set:`);
|
|
125
|
+
for (const m of missingRequired) {
|
|
126
|
+
console.log(` - ${m.key}: Run 'ac config set ${m.key} <value>' to configure.`);
|
|
127
|
+
}
|
|
128
|
+
} else {
|
|
129
|
+
console.log("\n[OK] All configuration dependencies are satisfied.");
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
} catch (err: any) {
|
|
133
|
+
console.error(`Error: ${err.message}`);
|
|
134
|
+
process.exit(1);
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
// config list
|
|
139
|
+
configCmd
|
|
140
|
+
.command("list [patterns...]")
|
|
141
|
+
.description("List configuration entries (Global & Project)")
|
|
142
|
+
.option("-P, --package <id>", "Target package ID or path")
|
|
143
|
+
.option("-g, --global", "Show only global configurations")
|
|
144
|
+
.option("-i, --intent <pattern>", "Regex or fuzzy intent filter; falls back to full list when no match")
|
|
145
|
+
.option("--reveal, --show-secrets", "Reveal plain text values for secrets")
|
|
146
|
+
.option("--no-fallback", "Disable fallback to full list when no items match intent")
|
|
147
|
+
.option("--json", "Output as JSON")
|
|
148
|
+
.action((patterns, options) => {
|
|
149
|
+
try {
|
|
150
|
+
const effectiveIntent = resolveIntent(options.intent, patterns);
|
|
151
|
+
const shouldFallback = options.fallback !== false;
|
|
152
|
+
const reveal = options.reveal || options.showSecrets;
|
|
153
|
+
|
|
154
|
+
const globalStorage = createGlobalStorage();
|
|
155
|
+
const globalConfig = globalStorage.listConfig();
|
|
156
|
+
|
|
157
|
+
const projectRoot = !options.global ? resolvePackageRoot(options.package) : null;
|
|
158
|
+
let projectStored: Record<string, unknown> = {};
|
|
159
|
+
let declaredDefaults: Record<string, ConfigItemDefinition> = {};
|
|
160
|
+
let packageId = "global";
|
|
161
|
+
|
|
162
|
+
if (projectRoot) {
|
|
163
|
+
try {
|
|
164
|
+
const projConfig = loadProjectConfig(projectRoot);
|
|
165
|
+
packageId = projConfig.id;
|
|
166
|
+
const projectStorage = createStorage(projConfig.id, { projectRoot });
|
|
167
|
+
projectStored = projectStorage.listConfig();
|
|
168
|
+
declaredDefaults = projConfig.config || {};
|
|
169
|
+
projectStorage.close();
|
|
170
|
+
} catch {
|
|
171
|
+
// Ignore project load error
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
globalStorage.close();
|
|
176
|
+
|
|
177
|
+
const allKeys = new Set([
|
|
178
|
+
...Object.keys(declaredDefaults),
|
|
179
|
+
...Object.keys(globalConfig),
|
|
180
|
+
...Object.keys(projectStored),
|
|
181
|
+
]);
|
|
182
|
+
|
|
183
|
+
const rawList = Array.from(allKeys).map((k) => {
|
|
184
|
+
let rawValue: unknown;
|
|
185
|
+
let source: "project" | "global" | "env" | "default" = "default";
|
|
186
|
+
|
|
187
|
+
if (projectStored[k] !== undefined) {
|
|
188
|
+
rawValue = projectStored[k];
|
|
189
|
+
source = "project";
|
|
190
|
+
} else if (globalConfig[k] !== undefined) {
|
|
191
|
+
rawValue = globalConfig[k];
|
|
192
|
+
source = "global";
|
|
193
|
+
} else if (typeof process !== "undefined" && process.env && process.env[k] !== undefined) {
|
|
194
|
+
rawValue = process.env[k];
|
|
195
|
+
source = "env";
|
|
196
|
+
} else {
|
|
197
|
+
rawValue = declaredDefaults[k]?.default;
|
|
198
|
+
source = "default";
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const isSecret = isSecretConfigKey(k, declaredDefaults[k]);
|
|
202
|
+
const displayValue = !reveal && isSecret && rawValue !== undefined ? maskSecretValue(rawValue) : rawValue;
|
|
203
|
+
|
|
204
|
+
return {
|
|
205
|
+
key: k,
|
|
206
|
+
value: displayValue,
|
|
207
|
+
source,
|
|
208
|
+
secret: isSecret,
|
|
209
|
+
description: declaredDefaults[k]?.description || "",
|
|
210
|
+
};
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
const filterRes = filterWithFallbackInfo(
|
|
214
|
+
rawList,
|
|
215
|
+
effectiveIntent,
|
|
216
|
+
[(c) => c.key, (c) => c.value, (c) => c.description, (c) => c.source],
|
|
217
|
+
shouldFallback
|
|
218
|
+
);
|
|
219
|
+
|
|
220
|
+
if (options.json) {
|
|
221
|
+
console.log(JSON.stringify(filterRes.items, null, 2));
|
|
222
|
+
} else {
|
|
223
|
+
const scopeLabel = projectRoot ? `${packageId} (${projectRoot})` : "Global Scope";
|
|
224
|
+
console.log(`Configurations [${scopeLabel}]:\n`);
|
|
225
|
+
if (filterRes.isFallback && effectiveIntent) {
|
|
226
|
+
console.log(`(No config entries matched intent '${effectiveIntent}', showing all entries)\n`);
|
|
227
|
+
}
|
|
228
|
+
if (filterRes.items.length === 0) {
|
|
229
|
+
console.log(" (No configuration entries found)");
|
|
230
|
+
}
|
|
231
|
+
for (const item of filterRes.items) {
|
|
232
|
+
const valStr = typeof item.value === "string" && item.secret && !reveal ? item.value : JSON.stringify(item.value);
|
|
233
|
+
const secretBadge = item.secret ? ", secret" : "";
|
|
234
|
+
console.log(` ${item.key.padEnd(24)} = ${valStr} (${item.source}${secretBadge})`);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
} catch (err: any) {
|
|
238
|
+
console.error(`Error: ${err.message}`);
|
|
239
|
+
process.exit(1);
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
// config get
|
|
244
|
+
configCmd
|
|
245
|
+
.command("get <key>")
|
|
246
|
+
.description("Get a configuration value")
|
|
247
|
+
.option("-P, --package <id>", "Target package ID or path")
|
|
248
|
+
.option("-g, --global", "Get from global configuration only")
|
|
249
|
+
.option("--reveal, --show-secrets", "Reveal plain text value for secret")
|
|
250
|
+
.option("--json", "Output as JSON")
|
|
251
|
+
.action((key, options) => {
|
|
252
|
+
try {
|
|
253
|
+
const reveal = options.reveal || options.showSecrets;
|
|
254
|
+
const globalStorage = createGlobalStorage();
|
|
255
|
+
const globalVal = globalStorage.getConfig(key);
|
|
256
|
+
globalStorage.close();
|
|
257
|
+
|
|
258
|
+
const projectRoot = !options.global ? resolvePackageRoot(options.package) : null;
|
|
259
|
+
let projVal: unknown = undefined;
|
|
260
|
+
let fallbackVal: unknown = undefined;
|
|
261
|
+
let declaredItem: ConfigItemDefinition | undefined;
|
|
262
|
+
|
|
263
|
+
if (projectRoot) {
|
|
264
|
+
try {
|
|
265
|
+
const projConfig = loadProjectConfig(projectRoot);
|
|
266
|
+
declaredItem = projConfig.config?.[key];
|
|
267
|
+
const projectStorage = createStorage(projConfig.id, { projectRoot });
|
|
268
|
+
projVal = projectStorage.getConfig(key);
|
|
269
|
+
fallbackVal = projConfig.config?.[key]?.default;
|
|
270
|
+
projectStorage.close();
|
|
271
|
+
} catch {
|
|
272
|
+
// Ignore
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
const envVal = typeof process !== "undefined" && process.env ? process.env[key] : undefined;
|
|
277
|
+
|
|
278
|
+
const rawEffective =
|
|
279
|
+
projVal !== undefined
|
|
280
|
+
? projVal
|
|
281
|
+
: globalVal !== undefined
|
|
282
|
+
? globalVal
|
|
283
|
+
: envVal !== undefined
|
|
284
|
+
? envVal
|
|
285
|
+
: fallbackVal;
|
|
286
|
+
|
|
287
|
+
const source: string =
|
|
288
|
+
projVal !== undefined
|
|
289
|
+
? "project"
|
|
290
|
+
: globalVal !== undefined
|
|
291
|
+
? "global"
|
|
292
|
+
: envVal !== undefined
|
|
293
|
+
? "env"
|
|
294
|
+
: fallbackVal !== undefined
|
|
295
|
+
? "default"
|
|
296
|
+
: "undefined";
|
|
297
|
+
|
|
298
|
+
const isSecret = isSecretConfigKey(key, declaredItem);
|
|
299
|
+
const effective = !reveal && isSecret && rawEffective !== undefined ? maskSecretValue(rawEffective) : rawEffective;
|
|
300
|
+
|
|
301
|
+
if (options.json) {
|
|
302
|
+
console.log(
|
|
303
|
+
JSON.stringify(
|
|
304
|
+
{
|
|
305
|
+
key,
|
|
306
|
+
value: effective,
|
|
307
|
+
source,
|
|
308
|
+
secret: isSecret,
|
|
309
|
+
},
|
|
310
|
+
null,
|
|
311
|
+
2
|
|
312
|
+
)
|
|
313
|
+
);
|
|
314
|
+
} else {
|
|
315
|
+
console.log(effective !== undefined ? (typeof effective === "string" && isSecret && !reveal ? effective : JSON.stringify(effective)) : "undefined");
|
|
316
|
+
}
|
|
317
|
+
} catch (err: any) {
|
|
318
|
+
console.error(`Error: ${err.message}`);
|
|
319
|
+
process.exit(1);
|
|
320
|
+
}
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
// config set
|
|
324
|
+
configCmd
|
|
325
|
+
.command("set <key> <value>")
|
|
326
|
+
.description("Set a configuration value (Global by default outside project, or use -g for global)")
|
|
327
|
+
.option("-P, --package <id>", "Target package ID or path")
|
|
328
|
+
.option("-g, --global", "Set globally across all packages")
|
|
329
|
+
.action((key, rawValue, options) => {
|
|
330
|
+
try {
|
|
331
|
+
let parsed: unknown = rawValue;
|
|
332
|
+
try {
|
|
333
|
+
parsed = JSON.parse(rawValue);
|
|
334
|
+
} catch {
|
|
335
|
+
parsed = rawValue;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
const projectRoot = !options.global ? resolvePackageRoot(options.package) : null;
|
|
339
|
+
const isSecret = isSecretConfigKey(key);
|
|
340
|
+
const displayVal = isSecret ? maskSecretValue(parsed) : JSON.stringify(parsed);
|
|
341
|
+
|
|
342
|
+
if (options.global || !projectRoot) {
|
|
343
|
+
// Set in Global storage (~/.actiondock/global.db)
|
|
344
|
+
const globalStorage = createGlobalStorage();
|
|
345
|
+
globalStorage.setConfig(key, parsed);
|
|
346
|
+
globalStorage.close();
|
|
347
|
+
console.log(`[OK] Global config '${key}' set to ${displayVal}`);
|
|
348
|
+
} else {
|
|
349
|
+
// Set in Project storage
|
|
350
|
+
const projConfig = loadProjectConfig(projectRoot);
|
|
351
|
+
const storage = createStorage(projConfig.id, { projectRoot });
|
|
352
|
+
storage.setConfig(key, parsed);
|
|
353
|
+
storage.close();
|
|
354
|
+
console.log(`[OK] Config '${key}' set to ${displayVal} in ${projConfig.id}`);
|
|
355
|
+
}
|
|
356
|
+
} catch (err: any) {
|
|
357
|
+
console.error(`Error: ${err.message}`);
|
|
358
|
+
process.exit(1);
|
|
359
|
+
}
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
// config delete
|
|
363
|
+
configCmd
|
|
364
|
+
.command("delete <key>")
|
|
365
|
+
.alias("rm")
|
|
366
|
+
.description("Delete a configuration value")
|
|
367
|
+
.option("-P, --package <id>", "Target package ID or path")
|
|
368
|
+
.option("-g, --global", "Delete from global configuration")
|
|
369
|
+
.action((key, options) => {
|
|
370
|
+
try {
|
|
371
|
+
const projectRoot = !options.global ? resolvePackageRoot(options.package) : null;
|
|
372
|
+
|
|
373
|
+
if (options.global || !projectRoot) {
|
|
374
|
+
const globalStorage = createGlobalStorage();
|
|
375
|
+
const deleted = globalStorage.deleteConfig(key);
|
|
376
|
+
globalStorage.close();
|
|
377
|
+
if (deleted) {
|
|
378
|
+
console.log(`[OK] Global config '${key}' deleted`);
|
|
379
|
+
} else {
|
|
380
|
+
console.log(`Global config '${key}' was not found`);
|
|
381
|
+
}
|
|
382
|
+
} else {
|
|
383
|
+
const projConfig = loadProjectConfig(projectRoot);
|
|
384
|
+
const storage = createStorage(projConfig.id, { projectRoot });
|
|
385
|
+
const deleted = storage.deleteConfig(key);
|
|
386
|
+
storage.close();
|
|
387
|
+
if (deleted) {
|
|
388
|
+
console.log(`[OK] Config '${key}' deleted from ${projConfig.id}`);
|
|
389
|
+
} else {
|
|
390
|
+
console.log(`Config '${key}' was not set in database for ${projConfig.id}`);
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
} catch (err: any) {
|
|
394
|
+
console.error(`Error: ${err.message}`);
|
|
395
|
+
process.exit(1);
|
|
396
|
+
}
|
|
397
|
+
});
|
|
398
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { runDoctorChecks } from "@actiondock/core";
|
|
2
|
+
import { Command } from "commander";
|
|
3
|
+
|
|
4
|
+
export function registerDoctorCommand(program: Command): void {
|
|
5
|
+
program
|
|
6
|
+
.command("doctor")
|
|
7
|
+
.description("Check ActionDock environment, registry health, and project diagnostics")
|
|
8
|
+
.option("-P, --package <id|path>", "Target package ID or directory path for project diagnostics")
|
|
9
|
+
.option("--json", "Output diagnostics report in JSON format")
|
|
10
|
+
.action(async (options) => {
|
|
11
|
+
try {
|
|
12
|
+
const report = await runDoctorChecks({
|
|
13
|
+
packageIdOrPath: options.package,
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
if (options.json) {
|
|
17
|
+
console.log(JSON.stringify(report, null, 2));
|
|
18
|
+
if (!report.ok) {
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
console.log("[DOCTOR] ActionDock System & Project Diagnostics\n");
|
|
25
|
+
|
|
26
|
+
// 1. Runtime & Environment Group
|
|
27
|
+
console.log("[Runtime & Environment]");
|
|
28
|
+
const envChecks = report.checks.filter((c) => c.category === "runtime" || c.category === "storage" || c.category === "registry");
|
|
29
|
+
for (const c of envChecks) {
|
|
30
|
+
const tag = c.status === "ok" ? "[OK]" : c.status === "warn" ? "[WARN]" : "[ERROR]";
|
|
31
|
+
console.log(` ${tag} ${c.name}: ${c.message}`);
|
|
32
|
+
if (c.fix) {
|
|
33
|
+
console.log(` Fix: ${c.fix}`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// 2. Project Group
|
|
38
|
+
if (report.hasProject) {
|
|
39
|
+
console.log(`\n[Project: ${report.packageId || "unknown"}] (${report.projectRoot})`);
|
|
40
|
+
const projChecks = report.checks.filter((c) => c.category === "project");
|
|
41
|
+
for (const c of projChecks) {
|
|
42
|
+
const tag = c.status === "ok" ? "[OK]" : c.status === "warn" ? "[WARN]" : "[ERROR]";
|
|
43
|
+
console.log(` ${tag} ${c.name}: ${c.message}`);
|
|
44
|
+
if (c.fix) {
|
|
45
|
+
console.log(` Fix: ${c.fix}`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
} else {
|
|
49
|
+
console.log("\n[Project Context]");
|
|
50
|
+
console.log(" [INFO] Not inside an ActionDock project directory (skipped project checks)");
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// 3. Summary
|
|
54
|
+
console.log(`\n[Summary] ${report.summary.ok} passed, ${report.summary.warn} warning(s), ${report.summary.error} error(s)`);
|
|
55
|
+
|
|
56
|
+
if (!report.ok) {
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
} catch (err: any) {
|
|
60
|
+
console.error(`[ERROR] Doctor failed to run diagnostics: ${err.message}`);
|
|
61
|
+
process.exit(1);
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { exportSkill, findProjectRoot, resolvePackageRoot } from "@actiondock/core";
|
|
2
|
+
import { Command } from "commander";
|
|
3
|
+
|
|
4
|
+
export function registerExportCommand(program: Command): void {
|
|
5
|
+
const exportCmd = program
|
|
6
|
+
.command("export")
|
|
7
|
+
.description("Export project artifacts");
|
|
8
|
+
|
|
9
|
+
exportCmd
|
|
10
|
+
.command("skill")
|
|
11
|
+
.description("Export Skill directory for AI Agents (default: source skill; use -s/--standalone for pre-built standalone binary)")
|
|
12
|
+
.option("-P, --package <id>", "Target package ID or path")
|
|
13
|
+
.option("-s, --standalone", "Export pre-compiled standalone binary skill (for environments without ActionDock runtime)")
|
|
14
|
+
.option("-t, --target <target>", "Target compilation platform for standalone mode (e.g. host, linux-x64, darwin-arm64, windows-x64)")
|
|
15
|
+
.option("-o, --out <path>", "Output skill directory")
|
|
16
|
+
.option("-p, --playbook <playbooks...>", "Only export specific playbook(s) and their dependent actions (Playbook-driven minimal export)")
|
|
17
|
+
.option("-a, --actions <actions...>", "Only export specific action(s)")
|
|
18
|
+
.option("-m, --minify", "Minify bundled JavaScript in standalone mode (default: true)", true)
|
|
19
|
+
.option("--no-minify", "Disable JavaScript minification in standalone mode")
|
|
20
|
+
.option("--bytecode", "Compile JavaScript to bytecode in standalone mode (default: true)", true)
|
|
21
|
+
.option("--no-bytecode", "Disable bytecode compilation in standalone mode")
|
|
22
|
+
.option("-z, --archive", "Create a .zip archive of the exported skill")
|
|
23
|
+
.action(async (options) => {
|
|
24
|
+
const root = options.package
|
|
25
|
+
? resolvePackageRoot(options.package)
|
|
26
|
+
: findProjectRoot();
|
|
27
|
+
|
|
28
|
+
if (!root) {
|
|
29
|
+
if (options.package) {
|
|
30
|
+
console.error(`Error: Package '${options.package}' not found in linked packages or path`);
|
|
31
|
+
} else {
|
|
32
|
+
console.error(
|
|
33
|
+
"Error: Not in an ActionDock project (actiondock.json not found).\nPlease specify -P, --package <id> or cd into a project directory."
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const isStandalone = Boolean(options.standalone);
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
console.log(`Exporting ${isStandalone ? "standalone binary" : "source"} Skill artifact...`);
|
|
43
|
+
const result = await exportSkill({
|
|
44
|
+
projectRoot: root,
|
|
45
|
+
mode: isStandalone ? "standalone" : "source",
|
|
46
|
+
standalone: isStandalone,
|
|
47
|
+
target: options.target,
|
|
48
|
+
outDir: options.out,
|
|
49
|
+
archive: options.archive,
|
|
50
|
+
playbooks: options.playbook,
|
|
51
|
+
actions: options.actions,
|
|
52
|
+
minify: options.minify,
|
|
53
|
+
bytecode: options.bytecode,
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
console.log(`[OK] Successfully exported ${result.mode === "standalone" ? "Standalone" : "Source"} Skill: ${result.packageId} (v${result.version})`);
|
|
57
|
+
console.log(` Mode: ${result.mode}${result.mode === "standalone" ? ` (target: ${result.target})` : ""}`);
|
|
58
|
+
console.log(` Actions: ${result.actionsCount}`);
|
|
59
|
+
console.log(` Playbooks: ${result.playbooksCount}`);
|
|
60
|
+
console.log(` Skill Dir: ${result.skillDir}`);
|
|
61
|
+
if (result.archivePath) {
|
|
62
|
+
console.log(` Archive: ${result.archivePath}`);
|
|
63
|
+
}
|
|
64
|
+
} catch (err: any) {
|
|
65
|
+
console.error(`Export failed: ${err.message}`);
|
|
66
|
+
process.exit(1);
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { registerActionCommands } from "./action";
|
|
3
|
+
import { registerBuildCommand } from "./build";
|
|
4
|
+
import { registerConfigCommands } from "./config";
|
|
5
|
+
import { registerDoctorCommand } from "./doctor";
|
|
6
|
+
import { registerExportCommand } from "./export";
|
|
7
|
+
import { registerInfoCommand } from "./info";
|
|
8
|
+
import { registerInitCommand } from "./init";
|
|
9
|
+
import { registerLinkCommands } from "./link";
|
|
10
|
+
import { registerMcpCommands } from "./mcp";
|
|
11
|
+
import { registerPlaybookCommands } from "./playbook";
|
|
12
|
+
import { registerProfileCommands } from "./profile";
|
|
13
|
+
import { registerRunsCommands } from "./runs";
|
|
14
|
+
import { registerServeCommand } from "./serve";
|
|
15
|
+
import { registerStateCommands } from "./state";
|
|
16
|
+
import { registerTestCommand } from "./test";
|
|
17
|
+
|
|
18
|
+
export function createCliProgram(): Command {
|
|
19
|
+
const program = new Command();
|
|
20
|
+
|
|
21
|
+
program
|
|
22
|
+
.name("ac")
|
|
23
|
+
.description("ActionDock (ac) 2.0 - Toolchain for building and shipping standalone AI Agent Actions & Skills")
|
|
24
|
+
.version("2.0.0");
|
|
25
|
+
|
|
26
|
+
registerInitCommand(program);
|
|
27
|
+
registerInfoCommand(program);
|
|
28
|
+
registerDoctorCommand(program);
|
|
29
|
+
registerActionCommands(program);
|
|
30
|
+
registerPlaybookCommands(program);
|
|
31
|
+
registerConfigCommands(program);
|
|
32
|
+
registerStateCommands(program);
|
|
33
|
+
registerRunsCommands(program);
|
|
34
|
+
registerTestCommand(program);
|
|
35
|
+
registerBuildCommand(program);
|
|
36
|
+
registerExportCommand(program);
|
|
37
|
+
registerLinkCommands(program);
|
|
38
|
+
registerProfileCommands(program);
|
|
39
|
+
registerServeCommand(program);
|
|
40
|
+
registerMcpCommands(program);
|
|
41
|
+
|
|
42
|
+
return program;
|
|
43
|
+
}
|