@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.
@@ -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
- console.error(`Error: ${err.message}`);
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
- console.error(`Failed to start ActionDock server: ${err.message}`);
130
- process.exit(1);
129
+ throw new ExecutionError(`Failed to start ActionDock server: ${err.message}`);
131
130
  }
132
131
  });
133
132
  }
@@ -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
- console.error(`Error: Package '${targetPackage}' not found in linked packages or path`);
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
- process.exit(1);
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
- .action(async (prefix = "", options) => {
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 (options.json) {
81
- console.log(JSON.stringify(res.keys, null, 2));
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
- console.error(`Error: Package '${options.package}' not found in linked packages or path`);
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, { projectRoot: targetRoot });
106
+ const storage = createStorage(projConfig.id, {
107
+ projectRoot: targetRoot,
108
+ dataDir: options.dataDir,
109
+ });
105
110
 
106
- if (options.detail && options.json) {
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
- console.log(JSON.stringify(filterRes.items, null, 2));
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 (options.json) {
138
- console.log(JSON.stringify(filterRes.items, null, 2));
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, { projectRoot: pkg.path });
186
+ const storage = createStorage(projConfig.id, {
187
+ projectRoot: pkg.path,
188
+ dataDir: options.dataDir,
189
+ });
178
190
 
179
- if (options.detail && options.json) {
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 (options.json) {
247
- console.log(JSON.stringify(filteredPackages, null, 2));
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
- console.error(`Error: ${err.message}`);
263
- process.exit(1);
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
- .action(async (rawKey, options) => {
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 (options.json) {
291
- console.log(JSON.stringify(res, null, 2));
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, { projectRoot: root });
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
- console.error(`Error: State key '${key}' not found in ${projConfig.id}`);
318
- process.exit(1);
336
+ throw new ExecutionError(`State key '${key}' not found in ${projConfig.id}`);
319
337
  }
320
338
 
321
- if (options.json) {
322
- console.log(
323
- JSON.stringify(
324
- {
325
- key,
326
- packageId: projConfig.id,
327
- namespace: entryNamespace,
328
- value: val,
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
- console.error(`Error: ${err.message}`);
339
- process.exit(1);
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
- .action(async (rawKey, rawValue, options) => {
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
- console.log(`[OK] State '${rawKey}' updated on remote server ${target.serverUrl}`);
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, { projectRoot: root });
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
- console.log(
399
- `[OK] State '${displayKey}' set to ${JSON.stringify(parsed)}${options.ttl ? ` (TTL: ${options.ttl}s)` : ""} in ${projConfig.id}`
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
- console.error(`Error: ${err.message}`);
403
- process.exit(1);
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
- .action(async (rawKey, options) => {
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
- console.log(`[OK] State '${rawKey}' deleted from remote server ${target.serverUrl}`);
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, { projectRoot: root });
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
- console.log(`[OK] State '${key}' deleted from ${projConfig.id}`);
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
- console.error(`Error: State key '${key}' not found in ${projConfig.id}`);
446
- process.exit(1);
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
- console.error(`Error: ${err.message}`);
451
- process.exit(1);
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
- .action(async (prefix = "", options) => {
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
- console.log(`[OK] Cleared ${res.clearedCount} state entry(s) on remote server ${target.serverUrl}`);
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, { projectRoot: root });
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
- console.log(`[OK] Cleared ${count} state entry(s) (${scopeDesc}) from ${projConfig.id}`);
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
- console.error(`Error: ${err.message}`);
505
- process.exit(1);
585
+ if (err instanceof ArgumentError || err instanceof ExecutionError) throw err;
586
+ throw new ExecutionError(err.message);
506
587
  }
507
588
  });
508
589
  }
@@ -42,7 +42,7 @@ export function registerTestCommand(program: Command): void {
42
42
  });
43
43
 
44
44
  if (proc.status !== 0) {
45
- process.exit(proc.status ?? 1);
45
+ process.exitCode = proc.status ?? 1;
46
46
  }
47
47
  });
48
48
  }
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<void> {
14
+ export async function main(argv: string[] = process.argv): Promise<number> {
12
15
  setupNodeRuntime();
13
16
  const program = createCliProgram();
14
- await program.parseAsync(argv);
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.exit(1);
55
+ process.exitCode = 1;
21
56
  });
22
57
  }
58
+
@@ -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
- }
@@ -1,24 +1,2 @@
1
- /**
2
- * Resolves effective intent string from an explicit option (--intent)
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
+