@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/serve.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { findProjectRoot, loadProjectConfig, startActionDockServer } from "@acti
|
|
|
3
3
|
import { createActionDockMcpServer } from "@actiondock/mcp";
|
|
4
4
|
import { createMcpHandler } from "@modelcontextprotocol/server";
|
|
5
5
|
import { Command } from "commander";
|
|
6
|
+
import { ExecutionError } from "@actiondock/runtime-cli";
|
|
6
7
|
import { parseByteSize } from "../utils/bytes";
|
|
7
8
|
|
|
8
9
|
export function registerServeCommand(program: Command): void {
|
|
@@ -36,8 +37,7 @@ export function registerServeCommand(program: Command): void {
|
|
|
36
37
|
try {
|
|
37
38
|
maxBodyBytes = parseByteSize(options.maxBody);
|
|
38
39
|
} catch (err: any) {
|
|
39
|
-
|
|
40
|
-
process.exit(1);
|
|
40
|
+
throw new ExecutionError(err.message);
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
43
|
|
|
@@ -126,8 +126,7 @@ export function registerServeCommand(program: Command): void {
|
|
|
126
126
|
process.exit(0);
|
|
127
127
|
});
|
|
128
128
|
} catch (err: any) {
|
|
129
|
-
|
|
130
|
-
process.exit(1);
|
|
129
|
+
throw new ExecutionError(`Failed to start ActionDock server: ${err.message}`);
|
|
131
130
|
}
|
|
132
131
|
});
|
|
133
132
|
}
|
package/src/commands/state.ts
CHANGED
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
resolveTarget,
|
|
14
14
|
setRemoteStateKey,
|
|
15
15
|
} from "@actiondock/core";
|
|
16
|
+
import { ArgumentError, ExecutionError, getEffectiveOptions, renderResult } from "@actiondock/runtime-cli";
|
|
16
17
|
import { Command } from "commander";
|
|
17
18
|
import { resolveIntent } from "../utils/filter";
|
|
18
19
|
|
|
@@ -31,13 +32,11 @@ function getTargetRoot(packageOption?: string, keyHint?: string): { root: string
|
|
|
31
32
|
const root = resolvePackageRoot(targetPackage);
|
|
32
33
|
if (!root) {
|
|
33
34
|
if (targetPackage) {
|
|
34
|
-
|
|
35
|
-
} else {
|
|
36
|
-
console.error(
|
|
37
|
-
"Error: Not in an ActionDock project (actiondock.json not found).\nPlease specify -P, --package <id> or cd into a project directory."
|
|
38
|
-
);
|
|
35
|
+
throw new ArgumentError(`Package '${targetPackage}' not found in linked packages or path`);
|
|
39
36
|
}
|
|
40
|
-
|
|
37
|
+
throw new ArgumentError(
|
|
38
|
+
"Not in an ActionDock project (actiondock.json not found).\nPlease specify -P, --package <id> or cd into a project directory."
|
|
39
|
+
);
|
|
41
40
|
}
|
|
42
41
|
return { root, key: effectiveKey };
|
|
43
42
|
}
|
|
@@ -59,11 +58,15 @@ export function registerStateCommands(program: Command): void {
|
|
|
59
58
|
.option("-i, --intent <pattern>", "Regex or fuzzy intent filter; falls back to full list when no match")
|
|
60
59
|
.option("--no-fallback", "Disable fallback to full list when no items match intent")
|
|
61
60
|
.option("-d, --detail", "Show detailed state entry objects (including namespace, expiration, update time)")
|
|
61
|
+
.option("--data-dir <path>", "Custom database storage directory")
|
|
62
62
|
.option("--json", "Output as JSON")
|
|
63
|
-
.
|
|
63
|
+
.option("--envelope", "Wrap JSON output in standard envelope")
|
|
64
|
+
.action(async (prefix = "", rawOptions, cmd) => {
|
|
64
65
|
try {
|
|
66
|
+
const options = getEffectiveOptions(rawOptions, cmd);
|
|
65
67
|
const effectiveIntent = resolveIntent(options.intent, prefix ? [prefix] : []);
|
|
66
68
|
const shouldFallback = options.fallback !== false;
|
|
69
|
+
const isMachine = Boolean(options.json || options.envelope);
|
|
67
70
|
|
|
68
71
|
const target = resolveTarget({
|
|
69
72
|
profile: options.profile,
|
|
@@ -77,8 +80,8 @@ export function registerStateCommands(program: Command): void {
|
|
|
77
80
|
namespace: options.namespace,
|
|
78
81
|
prefix,
|
|
79
82
|
});
|
|
80
|
-
if (
|
|
81
|
-
|
|
83
|
+
if (isMachine) {
|
|
84
|
+
renderResult(res.keys, { json: options.json, envelope: options.envelope });
|
|
82
85
|
return;
|
|
83
86
|
}
|
|
84
87
|
console.log(
|
|
@@ -95,15 +98,17 @@ export function registerStateCommands(program: Command): void {
|
|
|
95
98
|
: findProjectRoot();
|
|
96
99
|
|
|
97
100
|
if (options.package && !targetRoot) {
|
|
98
|
-
|
|
99
|
-
process.exit(1);
|
|
101
|
+
throw new ArgumentError(`Package '${options.package}' not found in linked packages or path`);
|
|
100
102
|
}
|
|
101
103
|
|
|
102
104
|
if (targetRoot) {
|
|
103
105
|
const projConfig = loadProjectConfig(targetRoot);
|
|
104
|
-
const storage = createStorage(projConfig.id, {
|
|
106
|
+
const storage = createStorage(projConfig.id, {
|
|
107
|
+
projectRoot: targetRoot,
|
|
108
|
+
dataDir: options.dataDir,
|
|
109
|
+
});
|
|
105
110
|
|
|
106
|
-
if (options.detail &&
|
|
111
|
+
if (options.detail && isMachine) {
|
|
107
112
|
const entries = await storage.listStateEntries({
|
|
108
113
|
namespace: options.namespace,
|
|
109
114
|
prefix: prefix || undefined,
|
|
@@ -117,7 +122,7 @@ export function registerStateCommands(program: Command): void {
|
|
|
117
122
|
shouldFallback
|
|
118
123
|
);
|
|
119
124
|
|
|
120
|
-
|
|
125
|
+
renderResult(filterRes.items, { json: options.json, envelope: options.envelope });
|
|
121
126
|
return;
|
|
122
127
|
}
|
|
123
128
|
|
|
@@ -134,8 +139,8 @@ export function registerStateCommands(program: Command): void {
|
|
|
134
139
|
shouldFallback
|
|
135
140
|
);
|
|
136
141
|
|
|
137
|
-
if (
|
|
138
|
-
|
|
142
|
+
if (isMachine) {
|
|
143
|
+
renderResult(filterRes.items, { json: options.json, envelope: options.envelope });
|
|
139
144
|
} else {
|
|
140
145
|
const nsDesc = options.namespace ? ` [namespace: ${options.namespace}]` : "";
|
|
141
146
|
const filterDesc = prefix ? ` (filter: ${prefix})` : "";
|
|
@@ -157,6 +162,10 @@ export function registerStateCommands(program: Command): void {
|
|
|
157
162
|
// Outside project: list state keys across all linked packages
|
|
158
163
|
const linkedList = listLinkedPackages();
|
|
159
164
|
if (linkedList.length === 0) {
|
|
165
|
+
if (isMachine) {
|
|
166
|
+
renderResult([], { json: options.json, envelope: options.envelope });
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
160
169
|
console.log("No ActionDock project in current directory, and no packages linked.");
|
|
161
170
|
console.log("Run 'ad link' inside an Action package to register it.");
|
|
162
171
|
return;
|
|
@@ -174,9 +183,12 @@ export function registerStateCommands(program: Command): void {
|
|
|
174
183
|
if (!existsSync(pkg.path)) continue;
|
|
175
184
|
try {
|
|
176
185
|
const projConfig = loadProjectConfig(pkg.path);
|
|
177
|
-
const storage = createStorage(projConfig.id, {
|
|
186
|
+
const storage = createStorage(projConfig.id, {
|
|
187
|
+
projectRoot: pkg.path,
|
|
188
|
+
dataDir: options.dataDir,
|
|
189
|
+
});
|
|
178
190
|
|
|
179
|
-
if (options.detail &&
|
|
191
|
+
if (options.detail && isMachine) {
|
|
180
192
|
const entries = await storage.listStateEntries({
|
|
181
193
|
namespace: options.namespace,
|
|
182
194
|
prefix: prefix || undefined,
|
|
@@ -243,8 +255,8 @@ export function registerStateCommands(program: Command): void {
|
|
|
243
255
|
}
|
|
244
256
|
}
|
|
245
257
|
|
|
246
|
-
if (
|
|
247
|
-
|
|
258
|
+
if (isMachine) {
|
|
259
|
+
renderResult(filteredPackages, { json: options.json, envelope: options.envelope });
|
|
248
260
|
} else {
|
|
249
261
|
console.log("State Keys in Linked Packages:\n");
|
|
250
262
|
for (const pkg of filteredPackages) {
|
|
@@ -259,8 +271,8 @@ export function registerStateCommands(program: Command): void {
|
|
|
259
271
|
}
|
|
260
272
|
}
|
|
261
273
|
} catch (err: any) {
|
|
262
|
-
|
|
263
|
-
|
|
274
|
+
if (err instanceof ArgumentError || err instanceof ExecutionError) throw err;
|
|
275
|
+
throw new ExecutionError(err.message);
|
|
264
276
|
}
|
|
265
277
|
});
|
|
266
278
|
|
|
@@ -273,9 +285,13 @@ export function registerStateCommands(program: Command): void {
|
|
|
273
285
|
.option("-p, --profile <name>", "Query state on a remote target")
|
|
274
286
|
.option("-s, --server <url>", "Remote server URL")
|
|
275
287
|
.option("-t, --token <token>", "Auth token for remote server")
|
|
288
|
+
.option("--data-dir <path>", "Custom database storage directory")
|
|
276
289
|
.option("--json", "Output as JSON")
|
|
277
|
-
.
|
|
290
|
+
.option("--envelope", "Wrap JSON output in standard envelope")
|
|
291
|
+
.action(async (rawKey, rawOptions, cmd) => {
|
|
278
292
|
try {
|
|
293
|
+
const options = getEffectiveOptions(rawOptions, cmd);
|
|
294
|
+
const isMachine = Boolean(options.json || options.envelope);
|
|
279
295
|
const target = resolveTarget({
|
|
280
296
|
profile: options.profile,
|
|
281
297
|
server: options.server,
|
|
@@ -287,8 +303,8 @@ export function registerStateCommands(program: Command): void {
|
|
|
287
303
|
package: options.package,
|
|
288
304
|
namespace: options.namespace,
|
|
289
305
|
});
|
|
290
|
-
if (
|
|
291
|
-
|
|
306
|
+
if (isMachine) {
|
|
307
|
+
renderResult(res, { json: options.json, envelope: options.envelope });
|
|
292
308
|
} else {
|
|
293
309
|
console.log(res.value !== undefined ? JSON.stringify(res.value, null, 2) : "undefined");
|
|
294
310
|
}
|
|
@@ -297,7 +313,10 @@ export function registerStateCommands(program: Command): void {
|
|
|
297
313
|
|
|
298
314
|
const { root, key } = getTargetRoot(options.package, rawKey);
|
|
299
315
|
const projConfig = loadProjectConfig(root);
|
|
300
|
-
const storage = createStorage(projConfig.id, {
|
|
316
|
+
const storage = createStorage(projConfig.id, {
|
|
317
|
+
projectRoot: root,
|
|
318
|
+
dataDir: options.dataDir,
|
|
319
|
+
});
|
|
301
320
|
|
|
302
321
|
let val: unknown;
|
|
303
322
|
let entryNamespace = options.namespace || "";
|
|
@@ -314,29 +333,25 @@ export function registerStateCommands(program: Command): void {
|
|
|
314
333
|
storage.close();
|
|
315
334
|
|
|
316
335
|
if (val === undefined) {
|
|
317
|
-
|
|
318
|
-
process.exit(1);
|
|
336
|
+
throw new ExecutionError(`State key '${key}' not found in ${projConfig.id}`);
|
|
319
337
|
}
|
|
320
338
|
|
|
321
|
-
if (
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
null,
|
|
331
|
-
2
|
|
332
|
-
)
|
|
339
|
+
if (isMachine) {
|
|
340
|
+
renderResult(
|
|
341
|
+
{
|
|
342
|
+
key,
|
|
343
|
+
packageId: projConfig.id,
|
|
344
|
+
namespace: entryNamespace,
|
|
345
|
+
value: val,
|
|
346
|
+
},
|
|
347
|
+
{ json: options.json, envelope: options.envelope }
|
|
333
348
|
);
|
|
334
349
|
} else {
|
|
335
350
|
console.log(val !== undefined ? JSON.stringify(val, null, 2) : "undefined");
|
|
336
351
|
}
|
|
337
352
|
} catch (err: any) {
|
|
338
|
-
|
|
339
|
-
|
|
353
|
+
if (err instanceof ArgumentError || err instanceof ExecutionError) throw err;
|
|
354
|
+
throw new ExecutionError(err.message);
|
|
340
355
|
}
|
|
341
356
|
});
|
|
342
357
|
|
|
@@ -350,8 +365,13 @@ export function registerStateCommands(program: Command): void {
|
|
|
350
365
|
.option("-s, --server <url>", "Remote server URL")
|
|
351
366
|
.option("-t, --token <token>", "Auth token for remote server")
|
|
352
367
|
.option("--ttl <seconds>", "Time to live in seconds", (v) => parseInt(v, 10))
|
|
353
|
-
.
|
|
368
|
+
.option("--data-dir <path>", "Custom database storage directory")
|
|
369
|
+
.option("--json", "Output as JSON")
|
|
370
|
+
.option("--envelope", "Wrap JSON output in standard envelope")
|
|
371
|
+
.action(async (rawKey, rawValue, rawOptions, cmd) => {
|
|
354
372
|
try {
|
|
373
|
+
const options = getEffectiveOptions(rawOptions, cmd);
|
|
374
|
+
const isMachine = Boolean(options.json || options.envelope);
|
|
355
375
|
let parsed: unknown = rawValue;
|
|
356
376
|
try {
|
|
357
377
|
parsed = JSON.parse(rawValue);
|
|
@@ -371,13 +391,23 @@ export function registerStateCommands(program: Command): void {
|
|
|
371
391
|
namespace: options.namespace,
|
|
372
392
|
ttl: options.ttl,
|
|
373
393
|
});
|
|
374
|
-
|
|
394
|
+
if (isMachine) {
|
|
395
|
+
renderResult(
|
|
396
|
+
{ ok: true, key: rawKey, value: parsed, ttl: options.ttl },
|
|
397
|
+
{ json: options.json, envelope: options.envelope }
|
|
398
|
+
);
|
|
399
|
+
} else {
|
|
400
|
+
console.log(`[OK] State '${rawKey}' updated on remote server ${target.serverUrl}`);
|
|
401
|
+
}
|
|
375
402
|
return;
|
|
376
403
|
}
|
|
377
404
|
|
|
378
405
|
const { root, key } = getTargetRoot(options.package, rawKey);
|
|
379
406
|
const projConfig = loadProjectConfig(root);
|
|
380
|
-
const storage = createStorage(projConfig.id, {
|
|
407
|
+
const storage = createStorage(projConfig.id, {
|
|
408
|
+
projectRoot: root,
|
|
409
|
+
dataDir: options.dataDir,
|
|
410
|
+
});
|
|
381
411
|
|
|
382
412
|
let ns = "";
|
|
383
413
|
let actualKey = key;
|
|
@@ -395,12 +425,25 @@ export function registerStateCommands(program: Command): void {
|
|
|
395
425
|
storage.close();
|
|
396
426
|
|
|
397
427
|
const displayKey = ns ? `${ns}:${actualKey}` : actualKey;
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
428
|
+
if (isMachine) {
|
|
429
|
+
renderResult(
|
|
430
|
+
{
|
|
431
|
+
ok: true,
|
|
432
|
+
key: displayKey,
|
|
433
|
+
value: parsed,
|
|
434
|
+
ttl: options.ttl,
|
|
435
|
+
packageId: projConfig.id,
|
|
436
|
+
},
|
|
437
|
+
{ json: options.json, envelope: options.envelope }
|
|
438
|
+
);
|
|
439
|
+
} else {
|
|
440
|
+
console.log(
|
|
441
|
+
`[OK] State '${displayKey}' set to ${JSON.stringify(parsed)}${options.ttl ? ` (TTL: ${options.ttl}s)` : ""} in ${projConfig.id}`
|
|
442
|
+
);
|
|
443
|
+
}
|
|
401
444
|
} catch (err: any) {
|
|
402
|
-
|
|
403
|
-
|
|
445
|
+
if (err instanceof ArgumentError || err instanceof ExecutionError) throw err;
|
|
446
|
+
throw new ExecutionError(err.message);
|
|
404
447
|
}
|
|
405
448
|
});
|
|
406
449
|
|
|
@@ -415,8 +458,13 @@ export function registerStateCommands(program: Command): void {
|
|
|
415
458
|
.option("-s, --server <url>", "Remote server URL")
|
|
416
459
|
.option("-t, --token <token>", "Auth token for remote server")
|
|
417
460
|
.option("--silent", "Do not exit with error if key is not found")
|
|
418
|
-
.
|
|
461
|
+
.option("--data-dir <path>", "Custom database storage directory")
|
|
462
|
+
.option("--json", "Output as JSON")
|
|
463
|
+
.option("--envelope", "Wrap JSON output in standard envelope")
|
|
464
|
+
.action(async (rawKey, rawOptions, cmd) => {
|
|
419
465
|
try {
|
|
466
|
+
const options = getEffectiveOptions(rawOptions, cmd);
|
|
467
|
+
const isMachine = Boolean(options.json || options.envelope);
|
|
420
468
|
const target = resolveTarget({
|
|
421
469
|
profile: options.profile,
|
|
422
470
|
server: options.server,
|
|
@@ -428,27 +476,40 @@ export function registerStateCommands(program: Command): void {
|
|
|
428
476
|
package: options.package,
|
|
429
477
|
namespace: options.namespace,
|
|
430
478
|
});
|
|
431
|
-
|
|
479
|
+
if (isMachine) {
|
|
480
|
+
renderResult({ ok: true, key: rawKey }, { json: options.json, envelope: options.envelope });
|
|
481
|
+
} else {
|
|
482
|
+
console.log(`[OK] State '${rawKey}' deleted from remote server ${target.serverUrl}`);
|
|
483
|
+
}
|
|
432
484
|
return;
|
|
433
485
|
}
|
|
434
486
|
|
|
435
487
|
const { root, key } = getTargetRoot(options.package, rawKey);
|
|
436
488
|
const projConfig = loadProjectConfig(root);
|
|
437
|
-
const storage = createStorage(projConfig.id, {
|
|
489
|
+
const storage = createStorage(projConfig.id, {
|
|
490
|
+
projectRoot: root,
|
|
491
|
+
dataDir: options.dataDir,
|
|
492
|
+
});
|
|
438
493
|
const deleted = await storage.deleteStateSmart(key, options.namespace);
|
|
439
494
|
storage.close();
|
|
440
495
|
|
|
441
496
|
if (deleted) {
|
|
442
|
-
|
|
497
|
+
if (isMachine) {
|
|
498
|
+
renderResult({ ok: true, key, deleted: true, packageId: projConfig.id }, { json: options.json, envelope: options.envelope });
|
|
499
|
+
} else {
|
|
500
|
+
console.log(`[OK] State '${key}' deleted from ${projConfig.id}`);
|
|
501
|
+
}
|
|
443
502
|
} else {
|
|
444
503
|
if (!options.silent) {
|
|
445
|
-
|
|
446
|
-
|
|
504
|
+
throw new ExecutionError(`State key '${key}' not found in ${projConfig.id}`);
|
|
505
|
+
}
|
|
506
|
+
if (isMachine) {
|
|
507
|
+
renderResult({ ok: true, key, deleted: false, packageId: projConfig.id }, { json: options.json, envelope: options.envelope });
|
|
447
508
|
}
|
|
448
509
|
}
|
|
449
510
|
} catch (err: any) {
|
|
450
|
-
|
|
451
|
-
|
|
511
|
+
if (err instanceof ArgumentError || err instanceof ExecutionError) throw err;
|
|
512
|
+
throw new ExecutionError(err.message);
|
|
452
513
|
}
|
|
453
514
|
});
|
|
454
515
|
|
|
@@ -463,8 +524,13 @@ export function registerStateCommands(program: Command): void {
|
|
|
463
524
|
.option("-s, --server <url>", "Remote server URL")
|
|
464
525
|
.option("-t, --token <token>", "Auth token for remote server")
|
|
465
526
|
.option("-a, --all", "Clear all state entries across all namespaces in this package")
|
|
466
|
-
.
|
|
527
|
+
.option("--data-dir <path>", "Custom database storage directory")
|
|
528
|
+
.option("--json", "Output as JSON")
|
|
529
|
+
.option("--envelope", "Wrap JSON output in standard envelope")
|
|
530
|
+
.action(async (prefix = "", rawOptions, cmd) => {
|
|
467
531
|
try {
|
|
532
|
+
const options = getEffectiveOptions(rawOptions, cmd);
|
|
533
|
+
const isMachine = Boolean(options.json || options.envelope);
|
|
468
534
|
const target = resolveTarget({
|
|
469
535
|
profile: options.profile,
|
|
470
536
|
server: options.server,
|
|
@@ -478,13 +544,20 @@ export function registerStateCommands(program: Command): void {
|
|
|
478
544
|
prefix,
|
|
479
545
|
all: Boolean(options.all),
|
|
480
546
|
});
|
|
481
|
-
|
|
547
|
+
if (isMachine) {
|
|
548
|
+
renderResult(res, { json: options.json, envelope: options.envelope });
|
|
549
|
+
} else {
|
|
550
|
+
console.log(`[OK] Cleared ${res.clearedCount} state entry(s) on remote server ${target.serverUrl}`);
|
|
551
|
+
}
|
|
482
552
|
return;
|
|
483
553
|
}
|
|
484
554
|
|
|
485
555
|
const { root } = getTargetRoot(options.package);
|
|
486
556
|
const projConfig = loadProjectConfig(root);
|
|
487
|
-
const storage = createStorage(projConfig.id, {
|
|
557
|
+
const storage = createStorage(projConfig.id, {
|
|
558
|
+
projectRoot: root,
|
|
559
|
+
dataDir: options.dataDir,
|
|
560
|
+
});
|
|
488
561
|
const count = await storage.clearState({
|
|
489
562
|
namespace: options.namespace,
|
|
490
563
|
all: options.all,
|
|
@@ -499,10 +572,18 @@ export function registerStateCommands(program: Command): void {
|
|
|
499
572
|
: prefix
|
|
500
573
|
? `prefix '${prefix}'`
|
|
501
574
|
: "root namespace";
|
|
502
|
-
|
|
575
|
+
|
|
576
|
+
if (isMachine) {
|
|
577
|
+
renderResult(
|
|
578
|
+
{ ok: true, clearedCount: count, scope: scopeDesc, packageId: projConfig.id },
|
|
579
|
+
{ json: options.json, envelope: options.envelope }
|
|
580
|
+
);
|
|
581
|
+
} else {
|
|
582
|
+
console.log(`[OK] Cleared ${count} state entry(s) (${scopeDesc}) from ${projConfig.id}`);
|
|
583
|
+
}
|
|
503
584
|
} catch (err: any) {
|
|
504
|
-
|
|
505
|
-
|
|
585
|
+
if (err instanceof ArgumentError || err instanceof ExecutionError) throw err;
|
|
586
|
+
throw new ExecutionError(err.message);
|
|
506
587
|
}
|
|
507
588
|
});
|
|
508
589
|
}
|
package/src/commands/test.ts
CHANGED
package/src/index.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { formatError } from "@actiondock/runtime-cli";
|
|
1
2
|
import { setupNodeRuntime } from "@actiondock/runtime-node";
|
|
3
|
+
import { CommanderError } from "commander";
|
|
2
4
|
import { createCliProgram } from "./commands";
|
|
3
5
|
|
|
4
6
|
export * from "./commands";
|
|
@@ -7,16 +9,50 @@ export * from "./commands";
|
|
|
7
9
|
* ActionDock CLI 主执行入口函数。
|
|
8
10
|
*
|
|
9
11
|
* @param argv 命令行参数数组(默认使用 process.argv)
|
|
12
|
+
* @returns 进程退出码
|
|
10
13
|
*/
|
|
11
|
-
export async function main(argv: string[] = process.argv): Promise<
|
|
14
|
+
export async function main(argv: string[] = process.argv): Promise<number> {
|
|
12
15
|
setupNodeRuntime();
|
|
13
16
|
const program = createCliProgram();
|
|
14
|
-
|
|
17
|
+
|
|
18
|
+
const isMachine = argv.includes("--json") || argv.includes("--envelope");
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
await program.parseAsync(argv);
|
|
22
|
+
return typeof process.exitCode === "number" ? process.exitCode : 0;
|
|
23
|
+
} catch (err: unknown) {
|
|
24
|
+
if (err instanceof CommanderError) {
|
|
25
|
+
if (err.exitCode === 0) {
|
|
26
|
+
return 0;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const formatted = formatError(err);
|
|
31
|
+
if (isMachine) {
|
|
32
|
+
const errorEnv = {
|
|
33
|
+
ok: false,
|
|
34
|
+
error: {
|
|
35
|
+
code: formatted.code,
|
|
36
|
+
message: formatted.message,
|
|
37
|
+
...(formatted.details !== undefined ? { details: formatted.details } : {}),
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
console.log(JSON.stringify(errorEnv, null, 2));
|
|
41
|
+
} else {
|
|
42
|
+
const msg = formatted.message.startsWith("Error: ")
|
|
43
|
+
? formatted.message
|
|
44
|
+
: `Error: ${formatted.message}`;
|
|
45
|
+
console.error(msg);
|
|
46
|
+
}
|
|
47
|
+
process.exitCode = formatted.exitCode;
|
|
48
|
+
return formatted.exitCode;
|
|
49
|
+
}
|
|
15
50
|
}
|
|
16
51
|
|
|
17
52
|
if ((import.meta as any).main) {
|
|
18
53
|
main().catch((err) => {
|
|
19
54
|
console.error("Fatal error:", err);
|
|
20
|
-
process.
|
|
55
|
+
process.exitCode = 1;
|
|
21
56
|
});
|
|
22
57
|
}
|
|
58
|
+
|
package/src/utils/bytes.ts
CHANGED
|
@@ -1,36 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
* Parses human-readable byte size string into number of bytes.
|
|
3
|
-
* e.g. "1mb" -> 1048576, "500kb" -> 512000, "1048576" -> 1048576
|
|
4
|
-
*/
|
|
5
|
-
export function parseByteSize(str: string): number {
|
|
6
|
-
const trimmed = str.trim().toLowerCase();
|
|
7
|
-
const match = trimmed.match(/^(\d+(?:\.\d+)?)\s*([a-z]+)?$/);
|
|
8
|
-
if (!match) {
|
|
9
|
-
const num = Number(trimmed);
|
|
10
|
-
if (!isNaN(num) && num > 0) return num;
|
|
11
|
-
throw new Error(`Invalid byte size format: '${str}'. Examples: '1mb', '500kb', '1048576'`);
|
|
12
|
-
}
|
|
1
|
+
export { parseByteSize } from "@actiondock/runtime-cli";
|
|
13
2
|
|
|
14
|
-
const value = parseFloat(match[1]);
|
|
15
|
-
const unit = match[2] || "b";
|
|
16
|
-
|
|
17
|
-
switch (unit) {
|
|
18
|
-
case "b":
|
|
19
|
-
case "bytes":
|
|
20
|
-
return Math.floor(value);
|
|
21
|
-
case "k":
|
|
22
|
-
case "kb":
|
|
23
|
-
case "kib":
|
|
24
|
-
return Math.floor(value * 1024);
|
|
25
|
-
case "m":
|
|
26
|
-
case "mb":
|
|
27
|
-
case "mib":
|
|
28
|
-
return Math.floor(value * 1024 * 1024);
|
|
29
|
-
case "g":
|
|
30
|
-
case "gb":
|
|
31
|
-
case "gib":
|
|
32
|
-
return Math.floor(value * 1024 * 1024 * 1024);
|
|
33
|
-
default:
|
|
34
|
-
throw new Error(`Unsupported byte size unit '${unit}' in '${str}'`);
|
|
35
|
-
}
|
|
36
|
-
}
|
package/src/utils/filter.ts
CHANGED
|
@@ -1,24 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
* and optional positional pattern arguments.
|
|
4
|
-
* Multiple terms are combined with '|' (regex OR).
|
|
5
|
-
*/
|
|
6
|
-
export function resolveIntent(
|
|
7
|
-
optionsIntent?: string,
|
|
8
|
-
positionalPatterns?: string[]
|
|
9
|
-
): string | undefined {
|
|
10
|
-
const parts: string[] = [];
|
|
11
|
-
if (optionsIntent && optionsIntent.trim()) {
|
|
12
|
-
parts.push(optionsIntent.trim());
|
|
13
|
-
}
|
|
14
|
-
if (positionalPatterns && positionalPatterns.length > 0) {
|
|
15
|
-
for (const p of positionalPatterns) {
|
|
16
|
-
if (typeof p === "string" && p.trim()) {
|
|
17
|
-
parts.push(p.trim());
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
if (parts.length === 0) return undefined;
|
|
22
|
-
if (parts.length === 1) return parts[0];
|
|
23
|
-
return parts.join("|");
|
|
24
|
-
}
|
|
1
|
+
export { resolveIntent } from "@actiondock/runtime-cli";
|
|
2
|
+
|