@actiondock/cli 2.0.11 → 2.2.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.
Files changed (123) hide show
  1. package/README.md +41 -21
  2. package/bin/ad.js +29 -31
  3. package/dist/commands/action/create.d.ts +10 -0
  4. package/dist/commands/action/create.js +120 -0
  5. package/dist/commands/add.d.ts +7 -0
  6. package/dist/commands/add.js +144 -0
  7. package/dist/commands/build.d.ts +3 -0
  8. package/dist/commands/build.js +83 -0
  9. package/dist/commands/config/delete.d.ts +9 -0
  10. package/dist/commands/config/delete.js +52 -0
  11. package/dist/commands/config/env.d.ts +9 -0
  12. package/dist/commands/config/env.js +85 -0
  13. package/dist/commands/config/get.d.ts +9 -0
  14. package/dist/commands/config/get.js +120 -0
  15. package/dist/commands/config/index.d.ts +9 -0
  16. package/dist/commands/config/index.js +23 -0
  17. package/dist/commands/config/list.d.ts +9 -0
  18. package/dist/commands/config/list.js +137 -0
  19. package/dist/commands/config/schema.d.ts +9 -0
  20. package/dist/commands/config/schema.js +121 -0
  21. package/dist/commands/config/set.d.ts +9 -0
  22. package/dist/commands/config/set.js +85 -0
  23. package/dist/commands/describe.d.ts +9 -0
  24. package/dist/commands/describe.js +68 -0
  25. package/dist/commands/doctor.d.ts +3 -0
  26. package/dist/commands/doctor.js +82 -0
  27. package/dist/commands/export.d.ts +3 -0
  28. package/dist/commands/export.js +212 -0
  29. package/dist/commands/generate.d.ts +9 -0
  30. package/dist/commands/generate.js +44 -0
  31. package/dist/commands/index.d.ts +32 -0
  32. package/dist/commands/index.js +111 -0
  33. package/dist/commands/info.d.ts +9 -0
  34. package/dist/commands/info.js +210 -0
  35. package/dist/commands/init.d.ts +2 -0
  36. package/dist/commands/init.js +24 -0
  37. package/dist/commands/link.d.ts +2 -0
  38. package/dist/commands/link.js +71 -0
  39. package/dist/commands/list.d.ts +9 -0
  40. package/dist/commands/list.js +77 -0
  41. package/dist/commands/mcp.d.ts +9 -0
  42. package/dist/commands/mcp.js +172 -0
  43. package/dist/commands/new.d.ts +9 -0
  44. package/dist/commands/new.js +33 -0
  45. package/dist/commands/pack.d.ts +3 -0
  46. package/dist/commands/pack.js +63 -0
  47. package/dist/commands/playbook.d.ts +10 -0
  48. package/dist/commands/playbook.js +433 -0
  49. package/dist/commands/profile.d.ts +2 -0
  50. package/dist/commands/profile.js +253 -0
  51. package/dist/commands/remove.d.ts +7 -0
  52. package/dist/commands/remove.js +118 -0
  53. package/dist/commands/run.d.ts +13 -0
  54. package/dist/commands/run.js +146 -0
  55. package/dist/commands/runs.d.ts +9 -0
  56. package/dist/commands/runs.js +245 -0
  57. package/dist/commands/serve.d.ts +9 -0
  58. package/dist/commands/serve.js +129 -0
  59. package/dist/commands/state-list.d.ts +24 -0
  60. package/dist/commands/state-list.js +82 -0
  61. package/dist/commands/state.d.ts +9 -0
  62. package/dist/commands/state.js +310 -0
  63. package/dist/commands/test.d.ts +2 -0
  64. package/dist/commands/test.js +44 -0
  65. package/dist/commands/validate.d.ts +9 -0
  66. package/dist/commands/validate.js +106 -0
  67. package/dist/errors.d.ts +43 -0
  68. package/dist/errors.js +103 -0
  69. package/dist/index.d.ts +15 -0
  70. package/dist/index.js +47 -65969
  71. package/dist/prompt.d.ts +53 -0
  72. package/dist/prompt.js +192 -0
  73. package/dist/renderer.d.ts +197 -0
  74. package/dist/renderer.js +502 -0
  75. package/dist/services/index.d.ts +1 -0
  76. package/dist/services/index.js +1 -0
  77. package/dist/services/inspect.d.ts +23 -0
  78. package/dist/services/inspect.js +96 -0
  79. package/dist/standalone/index.d.ts +16 -0
  80. package/dist/standalone/index.js +22 -0
  81. package/dist/types.d.ts +132 -0
  82. package/dist/types.js +9 -0
  83. package/dist/utils/bytes.d.ts +1 -0
  84. package/dist/utils/bytes.js +1 -0
  85. package/dist/utils/duration.js +1 -0
  86. package/dist/utils/filter.d.ts +1 -0
  87. package/dist/utils/filter.js +1 -0
  88. package/dist/utils/index.d.ts +6 -0
  89. package/dist/utils/index.js +6 -0
  90. package/dist/utils/spawn.d.ts +27 -0
  91. package/dist/utils/spawn.js +35 -0
  92. package/dist/utils/target.d.ts +45 -0
  93. package/dist/utils/target.js +78 -0
  94. package/dist/utils/utils.d.ts +38 -0
  95. package/dist/utils/utils.js +111 -0
  96. package/package.json +20 -17
  97. package/src/commands/action/create.ts +0 -129
  98. package/src/commands/action/index.ts +0 -27
  99. package/src/commands/action/list.ts +0 -247
  100. package/src/commands/action/run.ts +0 -197
  101. package/src/commands/action/show.ts +0 -128
  102. package/src/commands/action/sync.ts +0 -76
  103. package/src/commands/action/validate.ts +0 -102
  104. package/src/commands/action.ts +0 -1
  105. package/src/commands/build.ts +0 -56
  106. package/src/commands/config.ts +0 -583
  107. package/src/commands/doctor.ts +0 -84
  108. package/src/commands/export.ts +0 -196
  109. package/src/commands/index.ts +0 -75
  110. package/src/commands/info.ts +0 -537
  111. package/src/commands/init.ts +0 -24
  112. package/src/commands/link.ts +0 -73
  113. package/src/commands/mcp.ts +0 -195
  114. package/src/commands/playbook.ts +0 -566
  115. package/src/commands/profile.ts +0 -296
  116. package/src/commands/runs.ts +0 -452
  117. package/src/commands/serve.ts +0 -132
  118. package/src/commands/state.ts +0 -590
  119. package/src/commands/test.ts +0 -48
  120. package/src/index.ts +0 -58
  121. package/src/utils/bytes.ts +0 -2
  122. package/src/utils/filter.ts +0 -2
  123. /package/{src/utils/duration.ts → dist/utils/duration.d.ts} +0 -0
@@ -1,590 +0,0 @@
1
- import { existsSync } from "node:fs";
2
- import {
3
- clearRemoteState,
4
- createStorage,
5
- deleteRemoteStateKey,
6
- fetchRemoteStateList,
7
- filterWithFallbackInfo,
8
- findProjectRoot,
9
- getRemoteStateKey,
10
- listLinkedPackages,
11
- loadProjectConfig,
12
- resolvePackageRoot,
13
- resolveTarget,
14
- setRemoteStateKey,
15
- } from "@actiondock/core";
16
- import { ArgumentError, ExecutionError, getEffectiveOptions, renderResult } from "@actiondock/runtime-cli";
17
- import { Command } from "commander";
18
- import { resolveIntent } from "../utils/filter";
19
-
20
- function getTargetRoot(packageOption?: string, keyHint?: string): { root: string; key: string } {
21
- let targetPackage = packageOption;
22
- let effectiveKey = keyHint || "";
23
-
24
- if (!targetPackage && keyHint) {
25
- if (keyHint.includes("/")) {
26
- const slashIdx = keyHint.indexOf("/");
27
- targetPackage = keyHint.slice(0, slashIdx);
28
- effectiveKey = keyHint.slice(slashIdx + 1);
29
- }
30
- }
31
-
32
- const root = resolvePackageRoot(targetPackage);
33
- if (!root) {
34
- if (targetPackage) {
35
- throw new ArgumentError(`Package '${targetPackage}' not found in linked packages or path`);
36
- }
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
- );
40
- }
41
- return { root, key: effectiveKey };
42
- }
43
-
44
- export function registerStateCommands(program: Command): void {
45
- const stateCmd = program
46
- .command("state")
47
- .description("Inspect and manage Shared State store");
48
-
49
- // state list
50
- stateCmd
51
- .command("list [prefix]")
52
- .description("List state keys matching prefix, namespace, or intent pattern (in current project or linked packages)")
53
- .option("-P, --package <id>", "Target package ID or path")
54
- .option("-n, --namespace <ns>", "Filter by specific namespace")
55
- .option("-p, --profile <name>", "Query state on a remote target")
56
- .option("-s, --server <url>", "Remote server URL")
57
- .option("-t, --token <token>", "Auth token for remote server")
58
- .option("-i, --intent <pattern>", "Regex or fuzzy intent filter; falls back to full list when no match")
59
- .option("--no-fallback", "Disable fallback to full list when no items match intent")
60
- .option("-d, --detail", "Show detailed state entry objects (including namespace, expiration, update time)")
61
- .option("--data-dir <path>", "Custom database storage directory")
62
- .option("--json", "Output as JSON")
63
- .option("--envelope", "Wrap JSON output in standard envelope")
64
- .action(async (prefix = "", rawOptions, cmd) => {
65
- try {
66
- const options = getEffectiveOptions(rawOptions, cmd);
67
- const effectiveIntent = resolveIntent(options.intent, prefix ? [prefix] : []);
68
- const shouldFallback = options.fallback !== false;
69
- const isMachine = Boolean(options.json || options.envelope);
70
-
71
- const target = resolveTarget({
72
- profile: options.profile,
73
- server: options.server,
74
- token: options.token,
75
- });
76
-
77
- if (target.type === "remote") {
78
- const res = await fetchRemoteStateList(target.serverUrl!, target.token, {
79
- package: options.package,
80
- namespace: options.namespace,
81
- prefix,
82
- });
83
- if (isMachine) {
84
- renderResult(res.keys, { json: options.json, envelope: options.envelope });
85
- return;
86
- }
87
- console.log(
88
- `State keys on remote server ${target.serverUrl}${target.profileName ? ` (Profile: ${target.profileName})` : ""} (${res.keys.length}):\n`
89
- );
90
- for (const k of res.keys) {
91
- console.log(` - ${k}`);
92
- }
93
- return;
94
- }
95
-
96
- const targetRoot = options.package
97
- ? resolvePackageRoot(options.package)
98
- : findProjectRoot();
99
-
100
- if (options.package && !targetRoot) {
101
- throw new ArgumentError(`Package '${options.package}' not found in linked packages or path`);
102
- }
103
-
104
- if (targetRoot) {
105
- const projConfig = loadProjectConfig(targetRoot);
106
- const storage = createStorage(projConfig.id, {
107
- projectRoot: targetRoot,
108
- dataDir: options.dataDir,
109
- });
110
-
111
- if (options.detail && isMachine) {
112
- const entries = await storage.listStateEntries({
113
- namespace: options.namespace,
114
- prefix: prefix || undefined,
115
- });
116
- storage.close();
117
-
118
- const filterRes = filterWithFallbackInfo(
119
- entries,
120
- effectiveIntent,
121
- [(e) => e.fullKey, (e) => e.key, (e) => e.namespace],
122
- shouldFallback
123
- );
124
-
125
- renderResult(filterRes.items, { json: options.json, envelope: options.envelope });
126
- return;
127
- }
128
-
129
- const allKeys = await storage.listStateKeys(
130
- options.namespace !== undefined ? options.namespace : null,
131
- prefix
132
- );
133
- storage.close();
134
-
135
- const filterRes = filterWithFallbackInfo(
136
- allKeys,
137
- effectiveIntent,
138
- [(k) => k],
139
- shouldFallback
140
- );
141
-
142
- if (isMachine) {
143
- renderResult(filterRes.items, { json: options.json, envelope: options.envelope });
144
- } else {
145
- const nsDesc = options.namespace ? ` [namespace: ${options.namespace}]` : "";
146
- const filterDesc = prefix ? ` (filter: ${prefix})` : "";
147
- console.log(`State keys for ${projConfig.id} (${targetRoot})${nsDesc}${filterDesc}:\n`);
148
- if (filterRes.isFallback && effectiveIntent) {
149
- console.log(`(No state keys matched intent '${effectiveIntent}', showing all keys)\n`);
150
- }
151
- if (filterRes.items.length === 0) {
152
- console.log(" (no state keys found)\n");
153
- } else {
154
- for (const k of filterRes.items) {
155
- console.log(` - ${k}`);
156
- }
157
- }
158
- }
159
- return;
160
- }
161
-
162
- // Outside project: list state keys across all linked packages
163
- const linkedList = listLinkedPackages();
164
- if (linkedList.length === 0) {
165
- if (isMachine) {
166
- renderResult([], { json: options.json, envelope: options.envelope });
167
- return;
168
- }
169
- console.log("No ActionDock project in current directory, and no packages linked.");
170
- console.log("Run 'ad link' inside an Action package to register it.");
171
- return;
172
- }
173
-
174
- const aggregated: Array<{
175
- packageId: string;
176
- packageName: string;
177
- path: string;
178
- keys: string[];
179
- entries?: any[];
180
- }> = [];
181
-
182
- for (const pkg of linkedList) {
183
- if (!existsSync(pkg.path)) continue;
184
- try {
185
- const projConfig = loadProjectConfig(pkg.path);
186
- const storage = createStorage(projConfig.id, {
187
- projectRoot: pkg.path,
188
- dataDir: options.dataDir,
189
- });
190
-
191
- if (options.detail && isMachine) {
192
- const entries = await storage.listStateEntries({
193
- namespace: options.namespace,
194
- prefix: prefix || undefined,
195
- });
196
- storage.close();
197
- aggregated.push({
198
- packageId: pkg.id,
199
- packageName: pkg.name,
200
- path: pkg.path,
201
- keys: entries.map((e) => e.fullKey),
202
- entries,
203
- });
204
- } else {
205
- const keys = await storage.listStateKeys(
206
- options.namespace !== undefined ? options.namespace : null,
207
- prefix
208
- );
209
- storage.close();
210
- aggregated.push({
211
- packageId: pkg.id,
212
- packageName: pkg.name,
213
- path: pkg.path,
214
- keys,
215
- });
216
- }
217
- } catch {
218
- // Ignore broken linked package
219
- }
220
- }
221
-
222
- let filteredPackages: typeof aggregated = [];
223
- if (!effectiveIntent) {
224
- filteredPackages = aggregated;
225
- } else {
226
- for (const pkg of aggregated) {
227
- const pkgMatches = filterWithFallbackInfo(
228
- [pkg],
229
- effectiveIntent,
230
- [(p) => p.packageId, (p) => p.packageName, (p) => p.path],
231
- false
232
- ).matchedCount > 0;
233
-
234
- if (pkgMatches) {
235
- filteredPackages.push(pkg);
236
- } else {
237
- const matchedKeys = filterWithFallbackInfo(
238
- pkg.keys,
239
- effectiveIntent,
240
- [(k) => k],
241
- false
242
- ).items;
243
-
244
- if (matchedKeys.length > 0) {
245
- filteredPackages.push({
246
- ...pkg,
247
- keys: matchedKeys,
248
- });
249
- }
250
- }
251
- }
252
-
253
- if (filteredPackages.length === 0 && shouldFallback) {
254
- filteredPackages = aggregated;
255
- }
256
- }
257
-
258
- if (isMachine) {
259
- renderResult(filteredPackages, { json: options.json, envelope: options.envelope });
260
- } else {
261
- console.log("State Keys in Linked Packages:\n");
262
- for (const pkg of filteredPackages) {
263
- console.log(`* Package: ${pkg.packageId} (${pkg.path})`);
264
- if (pkg.keys.length === 0) {
265
- console.log(" (no state keys found)");
266
- } else {
267
- for (const k of pkg.keys) {
268
- console.log(` - ${k}`);
269
- }
270
- }
271
- }
272
- }
273
- } catch (err: any) {
274
- if (err instanceof ArgumentError || err instanceof ExecutionError) throw err;
275
- throw new ExecutionError(err.message);
276
- }
277
- });
278
-
279
- // state get
280
- stateCmd
281
- .command("get <key>")
282
- .description("Get a state value by key, namespace:key, or package/namespace:key")
283
- .option("-P, --package <id>", "Target package ID or path")
284
- .option("-n, --namespace <ns>", "Target namespace")
285
- .option("-p, --profile <name>", "Query state on a remote target")
286
- .option("-s, --server <url>", "Remote server URL")
287
- .option("-t, --token <token>", "Auth token for remote server")
288
- .option("--data-dir <path>", "Custom database storage directory")
289
- .option("--json", "Output as JSON")
290
- .option("--envelope", "Wrap JSON output in standard envelope")
291
- .action(async (rawKey, rawOptions, cmd) => {
292
- try {
293
- const options = getEffectiveOptions(rawOptions, cmd);
294
- const isMachine = Boolean(options.json || options.envelope);
295
- const target = resolveTarget({
296
- profile: options.profile,
297
- server: options.server,
298
- token: options.token,
299
- });
300
-
301
- if (target.type === "remote") {
302
- const res = await getRemoteStateKey(target.serverUrl!, rawKey, target.token, {
303
- package: options.package,
304
- namespace: options.namespace,
305
- });
306
- if (isMachine) {
307
- renderResult(res, { json: options.json, envelope: options.envelope });
308
- } else {
309
- console.log(res.value !== undefined ? JSON.stringify(res.value, null, 2) : "undefined");
310
- }
311
- return;
312
- }
313
-
314
- const { root, key } = getTargetRoot(options.package, rawKey);
315
- const projConfig = loadProjectConfig(root);
316
- const storage = createStorage(projConfig.id, {
317
- projectRoot: root,
318
- dataDir: options.dataDir,
319
- });
320
-
321
- let val: unknown;
322
- let entryNamespace = options.namespace || "";
323
-
324
- if (options.namespace !== undefined) {
325
- val = await storage.getState(options.namespace, key);
326
- } else {
327
- const entry = await storage.findState(key);
328
- if (entry) {
329
- val = entry.value;
330
- entryNamespace = entry.namespace;
331
- }
332
- }
333
- storage.close();
334
-
335
- if (val === undefined) {
336
- throw new ExecutionError(`State key '${key}' not found in ${projConfig.id}`);
337
- }
338
-
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 }
348
- );
349
- } else {
350
- console.log(val !== undefined ? JSON.stringify(val, null, 2) : "undefined");
351
- }
352
- } catch (err: any) {
353
- if (err instanceof ArgumentError || err instanceof ExecutionError) throw err;
354
- throw new ExecutionError(err.message);
355
- }
356
- });
357
-
358
- // state set
359
- stateCmd
360
- .command("set <key> <value>")
361
- .description("Set a state value by key, namespace:key, or package/namespace:key")
362
- .option("-P, --package <id>", "Target package ID or path")
363
- .option("-n, --namespace <ns>", "Target namespace")
364
- .option("-p, --profile <name>", "Set state on a remote target")
365
- .option("-s, --server <url>", "Remote server URL")
366
- .option("-t, --token <token>", "Auth token for remote server")
367
- .option("--ttl <seconds>", "Time to live in seconds", (v) => parseInt(v, 10))
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) => {
372
- try {
373
- const options = getEffectiveOptions(rawOptions, cmd);
374
- const isMachine = Boolean(options.json || options.envelope);
375
- let parsed: unknown = rawValue;
376
- try {
377
- parsed = JSON.parse(rawValue);
378
- } catch {
379
- parsed = rawValue;
380
- }
381
-
382
- const target = resolveTarget({
383
- profile: options.profile,
384
- server: options.server,
385
- token: options.token,
386
- });
387
-
388
- if (target.type === "remote") {
389
- await setRemoteStateKey(target.serverUrl!, rawKey, parsed, target.token, {
390
- package: options.package,
391
- namespace: options.namespace,
392
- ttl: options.ttl,
393
- });
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
- }
402
- return;
403
- }
404
-
405
- const { root, key } = getTargetRoot(options.package, rawKey);
406
- const projConfig = loadProjectConfig(root);
407
- const storage = createStorage(projConfig.id, {
408
- projectRoot: root,
409
- dataDir: options.dataDir,
410
- });
411
-
412
- let ns = "";
413
- let actualKey = key;
414
-
415
- if (options.namespace !== undefined) {
416
- ns = options.namespace;
417
- actualKey = key;
418
- } else if (key.includes(":")) {
419
- const colonIdx = key.indexOf(":");
420
- ns = key.slice(0, colonIdx);
421
- actualKey = key.slice(colonIdx + 1);
422
- }
423
-
424
- await storage.setState(ns, actualKey, parsed, options.ttl);
425
- storage.close();
426
-
427
- const displayKey = ns ? `${ns}:${actualKey}` : actualKey;
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
- }
444
- } catch (err: any) {
445
- if (err instanceof ArgumentError || err instanceof ExecutionError) throw err;
446
- throw new ExecutionError(err.message);
447
- }
448
- });
449
-
450
- // state delete
451
- stateCmd
452
- .command("delete <key>")
453
- .alias("rm")
454
- .description("Delete a state value by key, namespace:key, or package/namespace:key")
455
- .option("-P, --package <id>", "Target package ID or path")
456
- .option("-n, --namespace <ns>", "Target namespace")
457
- .option("-p, --profile <name>", "Delete state on a remote target")
458
- .option("-s, --server <url>", "Remote server URL")
459
- .option("-t, --token <token>", "Auth token for remote server")
460
- .option("--silent", "Do not exit with error if key is not found")
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) => {
465
- try {
466
- const options = getEffectiveOptions(rawOptions, cmd);
467
- const isMachine = Boolean(options.json || options.envelope);
468
- const target = resolveTarget({
469
- profile: options.profile,
470
- server: options.server,
471
- token: options.token,
472
- });
473
-
474
- if (target.type === "remote") {
475
- await deleteRemoteStateKey(target.serverUrl!, rawKey, target.token, {
476
- package: options.package,
477
- namespace: options.namespace,
478
- });
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
- }
484
- return;
485
- }
486
-
487
- const { root, key } = getTargetRoot(options.package, rawKey);
488
- const projConfig = loadProjectConfig(root);
489
- const storage = createStorage(projConfig.id, {
490
- projectRoot: root,
491
- dataDir: options.dataDir,
492
- });
493
- const deleted = await storage.deleteStateSmart(key, options.namespace);
494
- storage.close();
495
-
496
- if (deleted) {
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
- }
502
- } else {
503
- if (!options.silent) {
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 });
508
- }
509
- }
510
- } catch (err: any) {
511
- if (err instanceof ArgumentError || err instanceof ExecutionError) throw err;
512
- throw new ExecutionError(err.message);
513
- }
514
- });
515
-
516
- // state clear
517
- stateCmd
518
- .command("clear [prefix]")
519
- .alias("clean")
520
- .description("Clear state entries by namespace, prefix, or all")
521
- .option("-P, --package <id>", "Target package ID or path")
522
- .option("-n, --namespace <ns>", "Target namespace to clear")
523
- .option("-p, --profile <name>", "Clear state on a remote target")
524
- .option("-s, --server <url>", "Remote server URL")
525
- .option("-t, --token <token>", "Auth token for remote server")
526
- .option("-a, --all", "Clear all state entries across all namespaces in this package")
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) => {
531
- try {
532
- const options = getEffectiveOptions(rawOptions, cmd);
533
- const isMachine = Boolean(options.json || options.envelope);
534
- const target = resolveTarget({
535
- profile: options.profile,
536
- server: options.server,
537
- token: options.token,
538
- });
539
-
540
- if (target.type === "remote") {
541
- const res = await clearRemoteState(target.serverUrl!, target.token, {
542
- package: options.package,
543
- namespace: options.namespace,
544
- prefix,
545
- all: Boolean(options.all),
546
- });
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
- }
552
- return;
553
- }
554
-
555
- const { root } = getTargetRoot(options.package);
556
- const projConfig = loadProjectConfig(root);
557
- const storage = createStorage(projConfig.id, {
558
- projectRoot: root,
559
- dataDir: options.dataDir,
560
- });
561
- const count = await storage.clearState({
562
- namespace: options.namespace,
563
- all: options.all,
564
- prefix: prefix || undefined,
565
- });
566
- storage.close();
567
-
568
- const scopeDesc = options.all
569
- ? "all namespaces"
570
- : options.namespace
571
- ? `namespace '${options.namespace}'`
572
- : prefix
573
- ? `prefix '${prefix}'`
574
- : "root namespace";
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
- }
584
- } catch (err: any) {
585
- if (err instanceof ArgumentError || err instanceof ExecutionError) throw err;
586
- throw new ExecutionError(err.message);
587
- }
588
- });
589
- }
590
-
@@ -1,48 +0,0 @@
1
- import { spawnSync } from "node:child_process";
2
- import { existsSync, readFileSync } from "node:fs";
3
- import { join } from "node:path";
4
- import { findProjectRoot } from "@actiondock/core";
5
- import { Command } from "commander";
6
-
7
- export function registerTestCommand(program: Command): void {
8
- program
9
- .command("test [pattern]")
10
- .description("Run project tests using configured test runner (node:test or bun test)")
11
- .action((pattern) => {
12
- const root = findProjectRoot();
13
- const cwd = root || process.cwd();
14
-
15
- const pkgJsonPath = join(cwd, "package.json");
16
- let testCmd = "npm";
17
- let testArgs = ["test"];
18
-
19
- if (existsSync(pkgJsonPath)) {
20
- try {
21
- const pkg = JSON.parse(readFileSync(pkgJsonPath, "utf-8"));
22
- if (pkg.scripts?.test?.includes("bun test") && typeof (globalThis as any).Bun !== "undefined") {
23
- testCmd = "bun";
24
- testArgs = ["test"];
25
- }
26
- } catch {
27
- // ignore
28
- }
29
- }
30
-
31
- if (pattern) {
32
- if (testCmd === "npm") {
33
- testArgs.push("--", pattern);
34
- } else {
35
- testArgs.push(pattern);
36
- }
37
- }
38
-
39
- const proc = spawnSync(testCmd, testArgs, {
40
- cwd,
41
- stdio: "inherit",
42
- });
43
-
44
- if (proc.status !== 0) {
45
- process.exitCode = proc.status ?? 1;
46
- }
47
- });
48
- }
package/src/index.ts DELETED
@@ -1,58 +0,0 @@
1
- import { formatError } from "@actiondock/runtime-cli";
2
- import { setupNodeRuntime } from "@actiondock/runtime-node";
3
- import { CommanderError } from "commander";
4
- import { createCliProgram } from "./commands";
5
-
6
- export * from "./commands";
7
-
8
- /**
9
- * ActionDock CLI 主执行入口函数。
10
- *
11
- * @param argv 命令行参数数组(默认使用 process.argv)
12
- * @returns 进程退出码
13
- */
14
- export async function main(argv: string[] = process.argv): Promise<number> {
15
- setupNodeRuntime();
16
- const program = createCliProgram();
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
- }
50
- }
51
-
52
- if ((import.meta as any).main) {
53
- main().catch((err) => {
54
- console.error("Fatal error:", err);
55
- process.exitCode = 1;
56
- });
57
- }
58
-
@@ -1,2 +0,0 @@
1
- export { parseByteSize } from "@actiondock/runtime-cli";
2
-
@@ -1,2 +0,0 @@
1
- export { resolveIntent } from "@actiondock/runtime-cli";
2
-