@agentuity/cli 1.0.34 → 1.0.36

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 (105) hide show
  1. package/bin/cli.ts +43 -11
  2. package/dist/ai-help.js +60 -0
  3. package/dist/ai-help.js.map +1 -1
  4. package/dist/cache/agent-intro.d.ts +10 -0
  5. package/dist/cache/agent-intro.d.ts.map +1 -1
  6. package/dist/cache/agent-intro.js +50 -0
  7. package/dist/cache/agent-intro.js.map +1 -1
  8. package/dist/cache/index.d.ts +1 -1
  9. package/dist/cache/index.d.ts.map +1 -1
  10. package/dist/cache/index.js +1 -1
  11. package/dist/cache/index.js.map +1 -1
  12. package/dist/cli.d.ts.map +1 -1
  13. package/dist/cli.js +50 -7
  14. package/dist/cli.js.map +1 -1
  15. package/dist/cmd/ai/intro.d.ts.map +1 -1
  16. package/dist/cmd/ai/intro.js +26 -6
  17. package/dist/cmd/ai/intro.js.map +1 -1
  18. package/dist/cmd/cloud/deploy.d.ts.map +1 -1
  19. package/dist/cmd/cloud/deploy.js +4 -0
  20. package/dist/cmd/cloud/deploy.js.map +1 -1
  21. package/dist/cmd/cloud/keyvalue/create-namespace.js +3 -3
  22. package/dist/cmd/cloud/keyvalue/create-namespace.js.map +1 -1
  23. package/dist/cmd/cloud/keyvalue/delete-namespace.d.ts.map +1 -1
  24. package/dist/cmd/cloud/keyvalue/delete-namespace.js +7 -5
  25. package/dist/cmd/cloud/keyvalue/delete-namespace.js.map +1 -1
  26. package/dist/cmd/cloud/keyvalue/delete.d.ts.map +1 -1
  27. package/dist/cmd/cloud/keyvalue/delete.js +9 -3
  28. package/dist/cmd/cloud/keyvalue/delete.js.map +1 -1
  29. package/dist/cmd/cloud/keyvalue/get.d.ts.map +1 -1
  30. package/dist/cmd/cloud/keyvalue/get.js +6 -3
  31. package/dist/cmd/cloud/keyvalue/get.js.map +1 -1
  32. package/dist/cmd/cloud/keyvalue/keys.d.ts.map +1 -1
  33. package/dist/cmd/cloud/keyvalue/keys.js +9 -3
  34. package/dist/cmd/cloud/keyvalue/keys.js.map +1 -1
  35. package/dist/cmd/cloud/keyvalue/list-namespaces.js +3 -3
  36. package/dist/cmd/cloud/keyvalue/list-namespaces.js.map +1 -1
  37. package/dist/cmd/cloud/keyvalue/repl.d.ts.map +1 -1
  38. package/dist/cmd/cloud/keyvalue/repl.js +3 -1
  39. package/dist/cmd/cloud/keyvalue/repl.js.map +1 -1
  40. package/dist/cmd/cloud/keyvalue/search.d.ts.map +1 -1
  41. package/dist/cmd/cloud/keyvalue/search.js +6 -3
  42. package/dist/cmd/cloud/keyvalue/search.js.map +1 -1
  43. package/dist/cmd/cloud/keyvalue/set.d.ts.map +1 -1
  44. package/dist/cmd/cloud/keyvalue/set.js +7 -5
  45. package/dist/cmd/cloud/keyvalue/set.js.map +1 -1
  46. package/dist/cmd/cloud/keyvalue/stats.d.ts.map +1 -1
  47. package/dist/cmd/cloud/keyvalue/stats.js +6 -3
  48. package/dist/cmd/cloud/keyvalue/stats.js.map +1 -1
  49. package/dist/cmd/cloud/region/index.d.ts.map +1 -1
  50. package/dist/cmd/cloud/region/index.js +3 -1
  51. package/dist/cmd/cloud/region/index.js.map +1 -1
  52. package/dist/cmd/cloud/region/list.d.ts +2 -0
  53. package/dist/cmd/cloud/region/list.d.ts.map +1 -0
  54. package/dist/cmd/cloud/region/list.js +55 -0
  55. package/dist/cmd/cloud/region/list.js.map +1 -0
  56. package/dist/cmd/cloud/task/create.d.ts.map +1 -1
  57. package/dist/cmd/cloud/task/create.js +19 -0
  58. package/dist/cmd/cloud/task/create.js.map +1 -1
  59. package/dist/cmd/project/domain/check.d.ts.map +1 -1
  60. package/dist/cmd/project/domain/check.js +1 -5
  61. package/dist/cmd/project/domain/check.js.map +1 -1
  62. package/dist/domain.d.ts +9 -8
  63. package/dist/domain.d.ts.map +1 -1
  64. package/dist/domain.js +19 -62
  65. package/dist/domain.js.map +1 -1
  66. package/dist/output.d.ts.map +1 -1
  67. package/dist/output.js +45 -1
  68. package/dist/output.js.map +1 -1
  69. package/dist/schema-generator.d.ts +9 -1
  70. package/dist/schema-generator.d.ts.map +1 -1
  71. package/dist/schema-generator.js +57 -24
  72. package/dist/schema-generator.js.map +1 -1
  73. package/dist/schema-parser.d.ts +2 -2
  74. package/dist/schema-parser.d.ts.map +1 -1
  75. package/dist/schema-parser.js +44 -3
  76. package/dist/schema-parser.js.map +1 -1
  77. package/dist/types.d.ts +3 -0
  78. package/dist/types.d.ts.map +1 -1
  79. package/dist/types.js.map +1 -1
  80. package/package.json +6 -6
  81. package/src/ai-help.ts +61 -0
  82. package/src/cache/agent-intro.ts +54 -0
  83. package/src/cache/index.ts +6 -1
  84. package/src/cli.ts +84 -11
  85. package/src/cmd/ai/intro.ts +26 -6
  86. package/src/cmd/cloud/deploy.ts +5 -0
  87. package/src/cmd/cloud/keyvalue/create-namespace.ts +3 -3
  88. package/src/cmd/cloud/keyvalue/delete-namespace.ts +7 -5
  89. package/src/cmd/cloud/keyvalue/delete.ts +9 -3
  90. package/src/cmd/cloud/keyvalue/get.ts +6 -3
  91. package/src/cmd/cloud/keyvalue/keys.ts +9 -3
  92. package/src/cmd/cloud/keyvalue/list-namespaces.ts +3 -3
  93. package/src/cmd/cloud/keyvalue/repl.ts +3 -1
  94. package/src/cmd/cloud/keyvalue/search.ts +6 -3
  95. package/src/cmd/cloud/keyvalue/set.ts +7 -5
  96. package/src/cmd/cloud/keyvalue/stats.ts +6 -3
  97. package/src/cmd/cloud/region/index.ts +3 -1
  98. package/src/cmd/cloud/region/list.ts +62 -0
  99. package/src/cmd/cloud/task/create.ts +22 -0
  100. package/src/cmd/project/domain/check.ts +0 -4
  101. package/src/domain.ts +28 -72
  102. package/src/output.ts +46 -1
  103. package/src/schema-generator.ts +62 -27
  104. package/src/schema-parser.ts +57 -3
  105. package/src/types.ts +3 -0
package/src/cli.ts CHANGED
@@ -291,12 +291,20 @@ function handleValidationError(
291
291
  ? errorMessages[0]
292
292
  : 'Invalid options or arguments';
293
293
 
294
+ const suggestions = [`Run 'agentuity ${commandName} --help' for usage information`];
295
+ // Add agent-friendly hints when running from an AI agent
296
+ if (getExecutingAgent()) {
297
+ suggestions.push(
298
+ `Run 'agentuity ${commandName} --describe' to see the command schema as JSON`,
299
+ `Use --input '{...}' to pass arguments and options as a JSON object`
300
+ );
301
+ }
294
302
  exitWithError(
295
303
  {
296
304
  code: ErrorCode.VALIDATION_FAILED,
297
305
  message: primaryMessage,
298
306
  details: errorMessages.length > 1 ? { errors: errorMessages } : undefined,
299
- suggestions: [`Run 'agentuity ${commandName} --help' for usage information`],
307
+ suggestions,
300
308
  },
301
309
  baseCtx.logger,
302
310
  baseCtx.options.errorFormat ?? 'text'
@@ -520,7 +528,13 @@ export async function createCLI(version: string): Promise<Command> {
520
528
  .option('--explain', 'Show what the command would do without executing', false)
521
529
  .option('--dry-run', 'Execute command without making changes', false)
522
530
  .option('--validate', 'Validate arguments and options without executing', false)
523
- .option('--ai-help', 'Show AI-optimized help in dashdash format', false);
531
+ .option('--ai-help', 'Show AI-optimized help in dashdash format', false)
532
+ .option('--input <json>', 'Pass arguments and options as a JSON object (for agents)')
533
+ .option('--describe', 'Output command schema as JSON for agent introspection', false)
534
+ .option(
535
+ '--fields <fields>',
536
+ 'Filter JSON output to specified fields (comma-separated, dot notation for nested)'
537
+ );
524
538
 
525
539
  const skipVersionCheckOption = program.createOption(
526
540
  '--skip-version-check',
@@ -1035,6 +1049,18 @@ async function registerSubcommand(
1035
1049
  cmd.help();
1036
1050
  });
1037
1051
 
1052
+ // Handle --describe for command-group nodes
1053
+ cmd.action(async () => {
1054
+ if (baseCtx.options.describe) {
1055
+ const { extractSubcommandSchema } = await import('./schema-generator');
1056
+ const schema = extractSubcommandSchema(subcommand);
1057
+ const { outputJSON } = await import('./output');
1058
+ outputJSON(schema);
1059
+ return;
1060
+ }
1061
+ cmd.help();
1062
+ });
1063
+
1038
1064
  // Don't add options to parent commands - only to leaf commands
1039
1065
  return;
1040
1066
  }
@@ -1216,6 +1242,28 @@ async function registerSubcommand(
1216
1242
  const options = cmdObj.opts();
1217
1243
  const args = rawArgs.slice(0, -1);
1218
1244
 
1245
+ // Handle --describe mode: output command schema and exit
1246
+ if (baseCtx.options.describe) {
1247
+ const { extractSubcommandSchema } = await import('./schema-generator');
1248
+ const schema = extractSubcommandSchema(subcommand);
1249
+ const { outputJSON } = await import('./output');
1250
+ outputJSON(schema);
1251
+ return;
1252
+ }
1253
+
1254
+ // One-time hint for agents about structured input/output features
1255
+ // Emitted on stderr so it doesn't interfere with --json stdout
1256
+ const detectedAgent = getExecutingAgent();
1257
+ if (detectedAgent) {
1258
+ const { hasAgentSeenInputHint, markAgentInputHintSeen } = await import('./cache');
1259
+ if (!hasAgentSeenInputHint(detectedAgent)) {
1260
+ markAgentInputHintSeen(detectedAgent);
1261
+ console.error(
1262
+ `[agent] This CLI supports structured I/O for agents: --input <json> (structured input), --describe (schema introspection), --fields (output filtering). Run --ai-help for details.`
1263
+ );
1264
+ }
1265
+ }
1266
+
1219
1267
  // Merge global --org-id and --project-id into subcommand options when the schema
1220
1268
  // defines these fields. Global options (program-level) capture the values first,
1221
1269
  // so subcommand-level options may not have them. Only merge when the user
@@ -1415,9 +1463,13 @@ async function registerSubcommand(
1415
1463
  try {
1416
1464
  // Check if command uses stdin (don't auto-confirm if it does)
1417
1465
  const usesStdin = subcommand.tags?.includes('uses-stdin') ?? false;
1418
- const input = await buildValidationInputAsync(subcommand.schema, args, options, {
1419
- usesStdin,
1420
- });
1466
+ const input = await buildValidationInputAsync(
1467
+ subcommand.schema,
1468
+ args,
1469
+ options,
1470
+ { usesStdin },
1471
+ baseCtx.options.input
1472
+ );
1421
1473
  const ctx: Record<string, unknown> = {
1422
1474
  ...baseCtx,
1423
1475
  config: {
@@ -1705,9 +1757,15 @@ async function registerSubcommand(
1705
1757
  try {
1706
1758
  // Check if command uses stdin (don't auto-confirm if it does)
1707
1759
  const usesStdin = subcommand.tags?.includes('uses-stdin') ?? false;
1708
- const input = await buildValidationInputAsync(subcommand.schema, args, options, {
1709
- usesStdin,
1710
- });
1760
+ const input = await buildValidationInputAsync(
1761
+ subcommand.schema,
1762
+ args,
1763
+ options,
1764
+ {
1765
+ usesStdin,
1766
+ },
1767
+ baseCtx.options.input
1768
+ );
1711
1769
  const ctx: Record<string, unknown> = {
1712
1770
  ...baseCtx,
1713
1771
  config: auth
@@ -1969,9 +2027,15 @@ async function registerSubcommand(
1969
2027
  try {
1970
2028
  // Check if command uses stdin (don't auto-confirm if it does)
1971
2029
  const usesStdin = subcommand.tags?.includes('uses-stdin') ?? false;
1972
- const input = await buildValidationInputAsync(subcommand.schema, args, options, {
1973
- usesStdin,
1974
- });
2030
+ const input = await buildValidationInputAsync(
2031
+ subcommand.schema,
2032
+ args,
2033
+ options,
2034
+ {
2035
+ usesStdin,
2036
+ },
2037
+ baseCtx.options.input
2038
+ );
1975
2039
  const ctx: Record<string, unknown> = {
1976
2040
  ...baseCtx,
1977
2041
  };
@@ -2157,6 +2221,15 @@ export async function registerCommands(
2157
2221
 
2158
2222
  if (cmdDef.handler) {
2159
2223
  cmd.action(async () => {
2224
+ // Handle --describe mode: output command schema and exit
2225
+ if (baseCtx.options.describe) {
2226
+ const { extractCommandSchema } = await import('./schema-generator');
2227
+ const schema = extractCommandSchema(cmdDef);
2228
+ const { outputJSON } = await import('./output');
2229
+ outputJSON(schema);
2230
+ return;
2231
+ }
2232
+
2160
2233
  if (cmdDef.banner) {
2161
2234
  showBanner();
2162
2235
  }
@@ -31,6 +31,7 @@ The Agentuity CLI is designed to be agent-friendly. Here are the key commands:
31
31
 
32
32
  ### Discovery & Introspection
33
33
  \`\`\`bash
34
+ ${getCommand('<command> --describe')} # Get command schema as JSON (args, options, response)
34
35
  ${getCommand('--help=json')} # Get complete CLI schema as JSON
35
36
  ${getCommand('ai capabilities show')} # List all capabilities and workflows
36
37
  ${getCommand('ai schema show')} # Detailed command metadata
@@ -61,22 +62,41 @@ ${getCommand('env set KEY value --secret')} # Set secrets (encrypted)
61
62
 
62
63
  ## Best Practices for AI Agents
63
64
 
64
- 1. **Always use \`--json\` for machine-readable output**
65
+ 1. **Use \`--input <json>\` to pass arguments and options as a single JSON object**
65
66
  \`\`\`bash
66
- ${getCommand('--json project list')}
67
+ ${getCommand('cloud sandbox create --input \'{"runtime":"bun:1","memory":"1Gi","network":true}\'')}
68
+ ${getCommand('cloud kv set --input \'{"namespace":"ns","key":"k","value":"v","ttl":300}\'')}
69
+ \`\`\`
70
+ JSON keys must be the **camelCase schema keys** shown by \`--describe\` output (not kebab-case flag names). For example, the flag \`--dry-run\` becomes \`dryRun\` in JSON. CLI flags take precedence over --input values.
71
+
72
+ 2. **Use \`--describe\` to introspect what a command accepts before calling it**
73
+ \`\`\`bash
74
+ ${getCommand('cloud sandbox create --describe')}
67
75
  \`\`\`
76
+ Returns the full command schema as JSON: arguments, options (with types), response shape, requirements, and examples. No authentication required.
68
77
 
69
- 2. **Use \`--explain\` before destructive operations**
78
+ 3. **Use \`--fields\` with \`--json\` to limit output and protect your context window**
70
79
  \`\`\`bash
71
- ${getCommand('--explain cloud deployment delete <id>')}
80
+ ${getCommand('--json --fields "id,name,status" cloud deployment list')}
72
81
  \`\`\`
82
+ Comma-separated field names, supports dot notation for nested fields (e.g., \`properties.title\`).
73
83
 
74
- 3. **Use \`--dry-run\` to test commands safely**
84
+ 4. **Always use \`--json\` for machine-readable output**
85
+ \`\`\`bash
86
+ ${getCommand('--json project list')}
87
+ \`\`\`
88
+
89
+ 5. **Use \`--dry-run\` to test commands safely before mutating**
75
90
  \`\`\`bash
76
91
  ${getCommand('--dry-run cloud deploy')}
77
92
  \`\`\`
78
93
 
79
- 4. **Check requirements before running commands**
94
+ 6. **Use \`--validate\` to check inputs without executing**
95
+ \`\`\`bash
96
+ ${getCommand('--validate cloud kv set --input \'{"namespace":"ns","key":"k","value":"v"}\'')}
97
+ \`\`\`
98
+
99
+ 7. **Check requirements before running commands**
80
100
  - Many commands require authentication (\`${getCommand('auth login')}\`)
81
101
  - Project commands require an \`agentuity.json\` file in the current directory
82
102
 
@@ -1226,6 +1226,11 @@ export const deploySubcommand = createSubcommand({
1226
1226
  });
1227
1227
  }
1228
1228
 
1229
+ // Trigger TLS certificate provisioning for custom domains (fire-and-forget)
1230
+ if (project.deployment?.domains?.length) {
1231
+ void domain.triggerTLSProvisioning(project.deployment.domains);
1232
+ }
1233
+
1229
1234
  // Write final report on success
1230
1235
  if (opts.reportFile) {
1231
1236
  await collector.forceWrite();
@@ -13,14 +13,14 @@ export const createNamespaceSubcommand = createCommand({
13
13
  optional: { project: true },
14
14
  examples: [
15
15
  {
16
- command: getCommand('kv create-namespace production'),
16
+ command: getCommand('cloud kv create-namespace production'),
17
17
  description: 'Create production namespace',
18
18
  },
19
19
  {
20
- command: getCommand('kv create staging'),
20
+ command: getCommand('cloud kv create staging'),
21
21
  description: 'Create staging namespace (using alias)',
22
22
  },
23
- { command: getCommand('kv create cache'), description: 'Create cache namespace' },
23
+ { command: getCommand('cloud kv create cache'), description: 'Create cache namespace' },
24
24
  ],
25
25
  schema: {
26
26
  args: z.object({
@@ -14,21 +14,23 @@ export const deleteNamespaceSubcommand = createCommand({
14
14
  optional: { project: true },
15
15
  examples: [
16
16
  {
17
- command: getCommand('kv delete-namespace staging'),
17
+ command: getCommand('cloud kv delete-namespace staging'),
18
18
  description: 'Delete staging namespace (interactive)',
19
19
  },
20
20
  {
21
- command: getCommand('kv rm-namespace cache --confirm'),
21
+ command: getCommand('cloud kv rm-namespace cache --confirm'),
22
22
  description: 'Delete cache without confirmation',
23
23
  },
24
24
  {
25
- command: getCommand('kv delete-namespace production --confirm'),
25
+ command: getCommand('cloud kv delete-namespace production --confirm'),
26
26
  description: 'Force delete production',
27
27
  },
28
28
  ],
29
29
  schema: {
30
30
  args: z.object({
31
31
  name: z.string().min(1).max(64).describe('the namespace name'),
32
+ }),
33
+ options: z.object({
32
34
  confirm: z
33
35
  .boolean()
34
36
  .optional()
@@ -43,10 +45,10 @@ export const deleteNamespaceSubcommand = createCommand({
43
45
  },
44
46
 
45
47
  async handler(ctx) {
46
- const { args } = ctx;
48
+ const { args, opts } = ctx;
47
49
  const kv = await createStorageAdapter(ctx);
48
50
 
49
- if (!args.confirm) {
51
+ if (!opts?.confirm) {
50
52
  if (!process.stdin.isTTY) {
51
53
  tui.fatal(
52
54
  'No TTY and --confirm is not set. Refusing to delete',
@@ -19,10 +19,16 @@ export const deleteSubcommand = createCommand({
19
19
  requires: { auth: true, region: true },
20
20
  optional: { project: true },
21
21
  examples: [
22
- { command: getCommand('kv delete production user:123'), description: 'Delete user data' },
23
- { command: getCommand('kv delete cache session:abc'), description: 'Delete cached session' },
24
22
  {
25
- command: getCommand('kv rm staging cache:homepage'),
23
+ command: getCommand('cloud kv delete production user:123'),
24
+ description: 'Delete user data',
25
+ },
26
+ {
27
+ command: getCommand('cloud kv delete cache session:abc'),
28
+ description: 'Delete cached session',
29
+ },
30
+ {
31
+ command: getCommand('cloud kv rm staging cache:homepage'),
26
32
  description: 'Delete homepage cache (using alias)',
27
33
  },
28
34
  ],
@@ -18,9 +18,12 @@ export const getSubcommand = createCommand({
18
18
  requires: { auth: true, region: true },
19
19
  optional: { project: true },
20
20
  examples: [
21
- { command: getCommand('kv get production user:123'), description: 'Get user data' },
22
- { command: getCommand('kv get cache session:abc'), description: 'Get cached session' },
23
- { command: getCommand('kv get staging cache:homepage'), description: 'Get homepage cache' },
21
+ { command: getCommand('cloud kv get production user:123'), description: 'Get user data' },
22
+ { command: getCommand('cloud kv get cache session:abc'), description: 'Get cached session' },
23
+ {
24
+ command: getCommand('cloud kv get staging cache:homepage'),
25
+ description: 'Get homepage cache',
26
+ },
24
27
  ],
25
28
  schema: {
26
29
  args: z.object({
@@ -17,9 +17,15 @@ export const keysSubcommand = createCommand({
17
17
  optional: { project: true },
18
18
  idempotent: true,
19
19
  examples: [
20
- { command: getCommand('kv keys production'), description: 'List all keys in production' },
21
- { command: getCommand('kv ls cache'), description: 'List all cached keys (using alias)' },
22
- { command: getCommand('kv list staging'), description: 'List all staging keys' },
20
+ {
21
+ command: getCommand('cloud kv keys production'),
22
+ description: 'List all keys in production',
23
+ },
24
+ {
25
+ command: getCommand('cloud kv ls cache'),
26
+ description: 'List all cached keys (using alias)',
27
+ },
28
+ { command: getCommand('cloud kv list staging'), description: 'List all staging keys' },
23
29
  ],
24
30
  schema: {
25
31
  args: z.object({
@@ -13,9 +13,9 @@ export const listNamespacesSubcommand = createCommand({
13
13
  requires: { auth: true, region: true },
14
14
  optional: { project: true },
15
15
  examples: [
16
- { command: getCommand('kv list-namespaces'), description: 'List all namespaces' },
17
- { command: getCommand('kv namespaces'), description: 'List namespaces (using alias)' },
18
- { command: getCommand('kv ns'), description: 'List namespaces (short alias)' },
16
+ { command: getCommand('cloud kv list-namespaces'), description: 'List all namespaces' },
17
+ { command: getCommand('cloud kv namespaces'), description: 'List namespaces (using alias)' },
18
+ { command: getCommand('cloud kv ns'), description: 'List namespaces (short alias)' },
19
19
  ],
20
20
  schema: {
21
21
  options: z.object({
@@ -13,7 +13,9 @@ export const replSubcommand = createCommand({
13
13
  idempotent: false,
14
14
  requires: { auth: true, region: true },
15
15
  optional: { project: true },
16
- examples: [{ command: getCommand('kv repl'), description: 'Start interactive KV session' }],
16
+ examples: [
17
+ { command: getCommand('cloud kv repl'), description: 'Start interactive KV session' },
18
+ ],
17
19
 
18
20
  async handler(ctx) {
19
21
  showBanner(undefined, true);
@@ -25,14 +25,17 @@ export const searchSubcommand = createCommand({
25
25
  idempotent: true,
26
26
  examples: [
27
27
  {
28
- command: getCommand('kv search production user'),
28
+ command: getCommand('cloud kv search production user'),
29
29
  description: 'Find all user-related keys',
30
30
  },
31
31
  {
32
- command: getCommand('kv search cache session'),
32
+ command: getCommand('cloud kv search cache session'),
33
33
  description: 'Find all session keys in cache',
34
34
  },
35
- { command: getCommand('kv search staging config'), description: 'Find all config keys' },
35
+ {
36
+ command: getCommand('cloud kv search staging config'),
37
+ description: 'Find all config keys',
38
+ },
36
39
  ],
37
40
  schema: {
38
41
  args: z.object({
@@ -24,16 +24,16 @@ export const setSubcommand = createCommand({
24
24
  examples: [
25
25
  {
26
26
  command: getCommand(
27
- 'kv set production user:123 \'{"name":"Alice","email":"alice@example.com"}\''
27
+ 'cloud kv set production user:123 \'{"name":"Alice","email":"alice@example.com"}\''
28
28
  ),
29
29
  description: 'Store user data',
30
30
  },
31
31
  {
32
- command: getCommand('kv set cache session:abc "session-data-here" --ttl 3600'),
32
+ command: getCommand('cloud kv set cache session:abc "session-data-here" --ttl 3600'),
33
33
  description: 'Store session with 1h TTL',
34
34
  },
35
35
  {
36
- command: getCommand('kv set staging cache:homepage "<!DOCTYPE html>..." --ttl 600'),
36
+ command: getCommand('cloud kv set staging cache:homepage "<!DOCTYPE html>..." --ttl 600'),
37
37
  description: 'Cache homepage for 10m',
38
38
  },
39
39
  ],
@@ -42,6 +42,8 @@ export const setSubcommand = createCommand({
42
42
  namespace: z.string().min(1).max(64).describe('the namespace name'),
43
43
  key: z.string().min(1).max(64).describe('the key name'),
44
44
  value: z.string().min(1).describe('the value'),
45
+ }),
46
+ options: z.object({
45
47
  ttl: z.coerce
46
48
  .number()
47
49
  .refine((val) => val >= 0, {
@@ -54,11 +56,11 @@ export const setSubcommand = createCommand({
54
56
  },
55
57
 
56
58
  async handler(ctx) {
57
- const { args, options } = ctx;
59
+ const { args, opts, options } = ctx;
58
60
  const started = Date.now();
59
61
  const storage = await createStorageAdapter(ctx);
60
62
  const contentType = isPossiblyJSON(args.value) ? 'application/json' : 'text/plain';
61
- const ttl = args.ttl;
63
+ const ttl = opts?.ttl;
62
64
  await storage.set(args.namespace, args.key, args.value, {
63
65
  contentType,
64
66
  ttl,
@@ -40,12 +40,15 @@ export const statsSubcommand = createCommand({
40
40
  optional: { project: true },
41
41
  idempotent: true,
42
42
  examples: [
43
- { command: getCommand('kv stats'), description: 'Show stats for all namespaces' },
43
+ { command: getCommand('cloud kv stats'), description: 'Show stats for all namespaces' },
44
44
  {
45
- command: getCommand('kv stats production'),
45
+ command: getCommand('cloud kv stats production'),
46
46
  description: 'Show stats for production namespace',
47
47
  },
48
- { command: getCommand('kv stats cache'), description: 'Show stats for cache namespace' },
48
+ {
49
+ command: getCommand('cloud kv stats cache'),
50
+ description: 'Show stats for cache namespace',
51
+ },
49
52
  ],
50
53
  schema: {
51
54
  args: z.object({
@@ -3,6 +3,7 @@ import { createSubcommand, createCommand } from '../../../types';
3
3
  import { getCommand } from '../../../command-prefix';
4
4
  import { saveRegion, clearRegion } from '../../../config';
5
5
  import * as tui from '../../../tui';
6
+ import { listSubcommand } from './list';
6
7
 
7
8
  const selectCommand = createSubcommand({
8
9
  name: 'select',
@@ -150,8 +151,9 @@ export const regionSubcommand = createCommand({
150
151
  description: 'Manage default cloud region preference',
151
152
  tags: ['fast'],
152
153
  examples: [
154
+ { command: getCommand('cloud region list'), description: 'List available regions' },
153
155
  { command: getCommand('cloud region select'), description: 'Set default region' },
154
156
  { command: getCommand('cloud region current'), description: 'Show current default' },
155
157
  ],
156
- subcommands: [selectCommand, unselectCommand, currentCommand],
158
+ subcommands: [listSubcommand, selectCommand, unselectCommand, currentCommand],
157
159
  });
@@ -0,0 +1,62 @@
1
+ import { z } from 'zod';
2
+ import { createSubcommand } from '../../../types';
3
+ import { getCommand } from '../../../command-prefix';
4
+ import * as tui from '../../../tui';
5
+
6
+ const RegionSchema = z.object({
7
+ region: z.string().describe('Region code'),
8
+ description: z.string().describe('Human-readable region description'),
9
+ default: z.boolean().describe('Whether this is the default region'),
10
+ });
11
+
12
+ export const listSubcommand = createSubcommand({
13
+ name: 'list',
14
+ description: 'List available cloud regions',
15
+ aliases: ['ls'],
16
+ tags: ['read-only', 'fast', 'requires-auth'],
17
+ requires: { auth: true, regions: true },
18
+ idempotent: true,
19
+ examples: [
20
+ { command: getCommand('cloud region list'), description: 'List all available regions' },
21
+ {
22
+ command: getCommand('cloud region ls'),
23
+ description: 'List all available regions (short alias)',
24
+ },
25
+ {
26
+ command: getCommand('--json cloud region list'),
27
+ description: 'List regions in JSON format',
28
+ },
29
+ ],
30
+ schema: {
31
+ response: z.array(RegionSchema),
32
+ },
33
+
34
+ async handler(ctx) {
35
+ const { regions, options, config } = ctx;
36
+ const defaultRegion = config?.preferences?.region ?? null;
37
+
38
+ const result = regions.map((r) => ({
39
+ region: r.region,
40
+ description: r.description,
41
+ default: r.region === defaultRegion,
42
+ }));
43
+
44
+ if (!options.json) {
45
+ tui.info(`Regions (${regions.length})`);
46
+
47
+ const tableData = regions.map((r) => ({
48
+ Code: r.region,
49
+ Description: r.description,
50
+ Default: r.region === defaultRegion ? 'Yes' : '',
51
+ }));
52
+
53
+ tui.table(tableData, [
54
+ { name: 'Code', alignment: 'left' },
55
+ { name: 'Description', alignment: 'left' },
56
+ { name: 'Default', alignment: 'center' },
57
+ ]);
58
+ }
59
+
60
+ return result;
61
+ },
62
+ });
@@ -18,6 +18,10 @@ const TaskCreateResponseSchema = z.object({
18
18
  status: z.string().describe('Task status'),
19
19
  priority: z.string().describe('Task priority'),
20
20
  created_at: z.string().describe('Creation timestamp'),
21
+ tags: z
22
+ .array(z.object({ id: z.string(), name: z.string() }))
23
+ .optional()
24
+ .describe('Tags attached to the task'),
21
25
  }),
22
26
  attachment: z
23
27
  .object({
@@ -47,6 +51,12 @@ export const createSubcommand = createCommand({
47
51
  ),
48
52
  description: 'Create a feature with priority and description',
49
53
  },
54
+ {
55
+ command: getCommand(
56
+ 'cloud task create "Fix login bug" --type bug --tag sandbox --tag regression'
57
+ ),
58
+ description: 'Create a task with tags (auto-creates tags that do not exist)',
59
+ },
50
60
  {
51
61
  command: getCommand(
52
62
  'cloud task create "Q1 Planning" --type epic --created-id agent_001 --metadata \'{"team":"engineering"}\''
@@ -90,6 +100,10 @@ export const createSubcommand = createCommand({
90
100
  .describe('initial task status (default: open)'),
91
101
  parentId: z.string().optional().describe('parent task ID for subtasks'),
92
102
  assignedId: z.string().optional().describe('ID of the assigned agent or user'),
103
+ tag: z
104
+ .array(z.string())
105
+ .optional()
106
+ .describe('tag name to attach (repeatable, auto-creates missing tags)'),
93
107
  metadata: z.string().optional().describe('JSON metadata object'),
94
108
  file: z.string().optional().describe('file path to attach to the task'),
95
109
  }),
@@ -172,6 +186,7 @@ export const createSubcommand = createCommand({
172
186
  status: opts.status as TaskStatus,
173
187
  parent_id: opts.parentId,
174
188
  assigned_id: opts.assignedId,
189
+ tag_ids: opts.tag,
175
190
  metadata,
176
191
  });
177
192
 
@@ -228,6 +243,10 @@ export const createSubcommand = createCommand({
228
243
  tableData['Description'] = task.description;
229
244
  }
230
245
 
246
+ if (task.tags?.length) {
247
+ tableData['Tags'] = task.tags.map((t) => t.name).join(', ');
248
+ }
249
+
231
250
  if (project) {
232
251
  tableData['Project'] = project.name;
233
252
  }
@@ -248,6 +267,9 @@ export const createSubcommand = createCommand({
248
267
  status: task.status,
249
268
  priority: task.priority,
250
269
  created_at: task.created_at,
270
+ ...(task.tags?.length
271
+ ? { tags: task.tags.map((t) => ({ id: t.id, name: t.name })) }
272
+ : {}),
251
273
  },
252
274
  ...(attachmentInfo ? { attachment: attachmentInfo } : {}),
253
275
  durationMs,
@@ -7,7 +7,6 @@ import { isJSONMode } from '../../../output';
7
7
  import {
8
8
  checkCustomDomainForDNS,
9
9
  isSuccess,
10
- isPending,
11
10
  isMissing,
12
11
  isMisconfigured,
13
12
  isError,
@@ -92,9 +91,6 @@ export const checkSubcommand = createSubcommand({
92
91
  status = tui.colorSuccess(`${tui.ICONS.success} Configured`);
93
92
  statusRaw = 'configured';
94
93
  success = true;
95
- } else if (isPending(r)) {
96
- status = tui.colorWarning('⏳ Pending');
97
- statusRaw = 'pending';
98
94
  } else if (isMisconfigured(r)) {
99
95
  status = tui.colorWarning(`${tui.ICONS.warning} ${r.misconfigured}`);
100
96
  statusRaw = 'misconfigured';