@agentuity/cli 2.0.11 → 2.0.13

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 (274) hide show
  1. package/dist/cache/resource-region.d.ts.map +1 -1
  2. package/dist/cache/resource-region.js +48 -25
  3. package/dist/cache/resource-region.js.map +1 -1
  4. package/dist/cli.d.ts.map +1 -1
  5. package/dist/cli.js +15 -8
  6. package/dist/cli.js.map +1 -1
  7. package/dist/cmd/build/vite/bun-dev-server.d.ts +20 -0
  8. package/dist/cmd/build/vite/bun-dev-server.d.ts.map +1 -1
  9. package/dist/cmd/build/vite/bun-dev-server.js +62 -4
  10. package/dist/cmd/build/vite/bun-dev-server.js.map +1 -1
  11. package/dist/cmd/build/vite/index.d.ts +0 -1
  12. package/dist/cmd/build/vite/index.d.ts.map +1 -1
  13. package/dist/cmd/build/vite/index.js +0 -1
  14. package/dist/cmd/build/vite/index.js.map +1 -1
  15. package/dist/cmd/build/vite/static-renderer.d.ts +17 -0
  16. package/dist/cmd/build/vite/static-renderer.d.ts.map +1 -1
  17. package/dist/cmd/build/vite/static-renderer.js +18 -6
  18. package/dist/cmd/build/vite/static-renderer.js.map +1 -1
  19. package/dist/cmd/build/vite/vite-asset-server-config.d.ts.map +1 -1
  20. package/dist/cmd/build/vite/vite-asset-server-config.js +34 -27
  21. package/dist/cmd/build/vite/vite-asset-server-config.js.map +1 -1
  22. package/dist/cmd/build/vite/vite-asset-server.d.ts +9 -0
  23. package/dist/cmd/build/vite/vite-asset-server.d.ts.map +1 -1
  24. package/dist/cmd/build/vite/vite-asset-server.js +5 -1
  25. package/dist/cmd/build/vite/vite-asset-server.js.map +1 -1
  26. package/dist/cmd/build/vite/vite-builder.d.ts.map +1 -1
  27. package/dist/cmd/build/vite/vite-builder.js +12 -1
  28. package/dist/cmd/build/vite/vite-builder.js.map +1 -1
  29. package/dist/cmd/build/vite/ws-proxy.d.ts +15 -1
  30. package/dist/cmd/build/vite/ws-proxy.d.ts.map +1 -1
  31. package/dist/cmd/build/vite/ws-proxy.js +33 -0
  32. package/dist/cmd/build/vite/ws-proxy.js.map +1 -1
  33. package/dist/cmd/cloud/deploy.d.ts.map +1 -1
  34. package/dist/cmd/cloud/deploy.js +98 -39
  35. package/dist/cmd/cloud/deploy.js.map +1 -1
  36. package/dist/cmd/cloud/sandbox/checkpoint/create.d.ts.map +1 -1
  37. package/dist/cmd/cloud/sandbox/checkpoint/create.js +3 -4
  38. package/dist/cmd/cloud/sandbox/checkpoint/create.js.map +1 -1
  39. package/dist/cmd/cloud/sandbox/checkpoint/delete.d.ts.map +1 -1
  40. package/dist/cmd/cloud/sandbox/checkpoint/delete.js +3 -4
  41. package/dist/cmd/cloud/sandbox/checkpoint/delete.js.map +1 -1
  42. package/dist/cmd/cloud/sandbox/checkpoint/list.d.ts.map +1 -1
  43. package/dist/cmd/cloud/sandbox/checkpoint/list.js +3 -4
  44. package/dist/cmd/cloud/sandbox/checkpoint/list.js.map +1 -1
  45. package/dist/cmd/cloud/sandbox/checkpoint/restore.d.ts.map +1 -1
  46. package/dist/cmd/cloud/sandbox/checkpoint/restore.js +3 -4
  47. package/dist/cmd/cloud/sandbox/checkpoint/restore.js.map +1 -1
  48. package/dist/cmd/cloud/sandbox/create.d.ts.map +1 -1
  49. package/dist/cmd/cloud/sandbox/create.js +13 -4
  50. package/dist/cmd/cloud/sandbox/create.js.map +1 -1
  51. package/dist/cmd/cloud/sandbox/delete.d.ts.map +1 -1
  52. package/dist/cmd/cloud/sandbox/delete.js +3 -4
  53. package/dist/cmd/cloud/sandbox/delete.js.map +1 -1
  54. package/dist/cmd/cloud/sandbox/env.d.ts.map +1 -1
  55. package/dist/cmd/cloud/sandbox/env.js +3 -5
  56. package/dist/cmd/cloud/sandbox/env.js.map +1 -1
  57. package/dist/cmd/cloud/sandbox/exec.d.ts.map +1 -1
  58. package/dist/cmd/cloud/sandbox/exec.js +114 -41
  59. package/dist/cmd/cloud/sandbox/exec.js.map +1 -1
  60. package/dist/cmd/cloud/sandbox/execution/list.d.ts.map +1 -1
  61. package/dist/cmd/cloud/sandbox/execution/list.js +3 -5
  62. package/dist/cmd/cloud/sandbox/execution/list.js.map +1 -1
  63. package/dist/cmd/cloud/sandbox/fs/cp.d.ts.map +1 -1
  64. package/dist/cmd/cloud/sandbox/fs/cp.js +61 -113
  65. package/dist/cmd/cloud/sandbox/fs/cp.js.map +1 -1
  66. package/dist/cmd/cloud/sandbox/fs/download.d.ts.map +1 -1
  67. package/dist/cmd/cloud/sandbox/fs/download.js +11 -22
  68. package/dist/cmd/cloud/sandbox/fs/download.js.map +1 -1
  69. package/dist/cmd/cloud/sandbox/fs/ls.d.ts.map +1 -1
  70. package/dist/cmd/cloud/sandbox/fs/ls.js +3 -5
  71. package/dist/cmd/cloud/sandbox/fs/ls.js.map +1 -1
  72. package/dist/cmd/cloud/sandbox/fs/mkdir.d.ts.map +1 -1
  73. package/dist/cmd/cloud/sandbox/fs/mkdir.js +3 -5
  74. package/dist/cmd/cloud/sandbox/fs/mkdir.js.map +1 -1
  75. package/dist/cmd/cloud/sandbox/fs/rm.d.ts.map +1 -1
  76. package/dist/cmd/cloud/sandbox/fs/rm.js +3 -5
  77. package/dist/cmd/cloud/sandbox/fs/rm.js.map +1 -1
  78. package/dist/cmd/cloud/sandbox/fs/rmdir.d.ts.map +1 -1
  79. package/dist/cmd/cloud/sandbox/fs/rmdir.js +3 -5
  80. package/dist/cmd/cloud/sandbox/fs/rmdir.js.map +1 -1
  81. package/dist/cmd/cloud/sandbox/fs/upload.d.ts.map +1 -1
  82. package/dist/cmd/cloud/sandbox/fs/upload.js +7 -8
  83. package/dist/cmd/cloud/sandbox/fs/upload.js.map +1 -1
  84. package/dist/cmd/cloud/sandbox/get.d.ts.map +1 -1
  85. package/dist/cmd/cloud/sandbox/get.js +21 -7
  86. package/dist/cmd/cloud/sandbox/get.js.map +1 -1
  87. package/dist/cmd/cloud/sandbox/job/create.d.ts.map +1 -1
  88. package/dist/cmd/cloud/sandbox/job/create.js +3 -4
  89. package/dist/cmd/cloud/sandbox/job/create.js.map +1 -1
  90. package/dist/cmd/cloud/sandbox/job/destroy.d.ts.map +1 -1
  91. package/dist/cmd/cloud/sandbox/job/destroy.js +3 -4
  92. package/dist/cmd/cloud/sandbox/job/destroy.js.map +1 -1
  93. package/dist/cmd/cloud/sandbox/job/get.d.ts.map +1 -1
  94. package/dist/cmd/cloud/sandbox/job/get.js +3 -4
  95. package/dist/cmd/cloud/sandbox/job/get.js.map +1 -1
  96. package/dist/cmd/cloud/sandbox/job/list.d.ts.map +1 -1
  97. package/dist/cmd/cloud/sandbox/job/list.js +3 -4
  98. package/dist/cmd/cloud/sandbox/job/list.js.map +1 -1
  99. package/dist/cmd/cloud/sandbox/job/logs.d.ts.map +1 -1
  100. package/dist/cmd/cloud/sandbox/job/logs.js +4 -4
  101. package/dist/cmd/cloud/sandbox/job/logs.js.map +1 -1
  102. package/dist/cmd/cloud/sandbox/pause.d.ts.map +1 -1
  103. package/dist/cmd/cloud/sandbox/pause.js +21 -5
  104. package/dist/cmd/cloud/sandbox/pause.js.map +1 -1
  105. package/dist/cmd/cloud/sandbox/resume.d.ts.map +1 -1
  106. package/dist/cmd/cloud/sandbox/resume.js +3 -4
  107. package/dist/cmd/cloud/sandbox/resume.js.map +1 -1
  108. package/dist/cmd/cloud/sandbox/run.d.ts.map +1 -1
  109. package/dist/cmd/cloud/sandbox/run.js +36 -7
  110. package/dist/cmd/cloud/sandbox/run.js.map +1 -1
  111. package/dist/cmd/cloud/sandbox/snapshot/create.js +4 -4
  112. package/dist/cmd/cloud/sandbox/snapshot/create.js.map +1 -1
  113. package/dist/cmd/cloud/sandbox/util.d.ts +19 -0
  114. package/dist/cmd/cloud/sandbox/util.d.ts.map +1 -1
  115. package/dist/cmd/cloud/sandbox/util.js +40 -2
  116. package/dist/cmd/cloud/sandbox/util.js.map +1 -1
  117. package/dist/cmd/coder/create.js +7 -7
  118. package/dist/cmd/coder/create.js.map +1 -1
  119. package/dist/cmd/coder/start.d.ts.map +1 -1
  120. package/dist/cmd/coder/start.js +3 -0
  121. package/dist/cmd/coder/start.js.map +1 -1
  122. package/dist/cmd/coder/tui-init.js +1 -1
  123. package/dist/cmd/coder/tui-init.js.map +1 -1
  124. package/dist/cmd/coder/update.js +8 -8
  125. package/dist/cmd/coder/update.js.map +1 -1
  126. package/dist/cmd/coder/workspace/common.d.ts +29 -0
  127. package/dist/cmd/coder/workspace/common.d.ts.map +1 -0
  128. package/dist/cmd/coder/workspace/common.js +83 -0
  129. package/dist/cmd/coder/workspace/common.js.map +1 -0
  130. package/dist/cmd/coder/workspace/create.d.ts.map +1 -1
  131. package/dist/cmd/coder/workspace/create.js +57 -32
  132. package/dist/cmd/coder/workspace/create.js.map +1 -1
  133. package/dist/cmd/coder/workspace/get.d.ts.map +1 -1
  134. package/dist/cmd/coder/workspace/get.js +2 -5
  135. package/dist/cmd/coder/workspace/get.js.map +1 -1
  136. package/dist/cmd/coder/workspace/index.d.ts.map +1 -1
  137. package/dist/cmd/coder/workspace/index.js +11 -1
  138. package/dist/cmd/coder/workspace/index.js.map +1 -1
  139. package/dist/cmd/coder/workspace/list.d.ts.map +1 -1
  140. package/dist/cmd/coder/workspace/list.js +4 -0
  141. package/dist/cmd/coder/workspace/list.js.map +1 -1
  142. package/dist/cmd/coder/workspace/refresh.d.ts +2 -0
  143. package/dist/cmd/coder/workspace/refresh.d.ts.map +1 -0
  144. package/dist/cmd/coder/workspace/refresh.js +59 -0
  145. package/dist/cmd/coder/workspace/refresh.js.map +1 -0
  146. package/dist/cmd/coder/workspace/update.d.ts +2 -0
  147. package/dist/cmd/coder/workspace/update.d.ts.map +1 -0
  148. package/dist/cmd/coder/workspace/update.js +131 -0
  149. package/dist/cmd/coder/workspace/update.js.map +1 -0
  150. package/dist/cmd/coder/workspace/validate-dependencies.d.ts +2 -0
  151. package/dist/cmd/coder/workspace/validate-dependencies.d.ts.map +1 -0
  152. package/dist/cmd/coder/workspace/validate-dependencies.js +70 -0
  153. package/dist/cmd/coder/workspace/validate-dependencies.js.map +1 -0
  154. package/dist/cmd/dev/dev-lock.d.ts.map +1 -1
  155. package/dist/cmd/dev/dev-lock.js +43 -17
  156. package/dist/cmd/dev/dev-lock.js.map +1 -1
  157. package/dist/cmd/dev/index.d.ts.map +1 -1
  158. package/dist/cmd/dev/index.js +211 -125
  159. package/dist/cmd/dev/index.js.map +1 -1
  160. package/dist/cmd/dev/process-manager.d.ts +41 -1
  161. package/dist/cmd/dev/process-manager.d.ts.map +1 -1
  162. package/dist/cmd/dev/process-manager.js +160 -31
  163. package/dist/cmd/dev/process-manager.js.map +1 -1
  164. package/dist/cmd/project/create.d.ts.map +1 -1
  165. package/dist/cmd/project/create.js +0 -2
  166. package/dist/cmd/project/create.js.map +1 -1
  167. package/dist/cmd/project/index.d.ts.map +1 -1
  168. package/dist/cmd/project/index.js +0 -3
  169. package/dist/cmd/project/index.js.map +1 -1
  170. package/dist/cmd/project/random-name.d.ts +17 -0
  171. package/dist/cmd/project/random-name.d.ts.map +1 -0
  172. package/dist/cmd/project/random-name.js +144 -0
  173. package/dist/cmd/project/random-name.js.map +1 -0
  174. package/dist/cmd/project/template-flow.d.ts +0 -1
  175. package/dist/cmd/project/template-flow.d.ts.map +1 -1
  176. package/dist/cmd/project/template-flow.js +180 -275
  177. package/dist/cmd/project/template-flow.js.map +1 -1
  178. package/dist/composite-logger.d.ts.map +1 -1
  179. package/dist/composite-logger.js +19 -0
  180. package/dist/composite-logger.js.map +1 -1
  181. package/dist/config.d.ts +18 -16
  182. package/dist/config.d.ts.map +1 -1
  183. package/dist/config.js +46 -16
  184. package/dist/config.js.map +1 -1
  185. package/dist/tui/prompt.d.ts +29 -0
  186. package/dist/tui/prompt.d.ts.map +1 -1
  187. package/dist/tui/prompt.js +180 -8
  188. package/dist/tui/prompt.js.map +1 -1
  189. package/package.json +7 -7
  190. package/src/cache/resource-region.ts +68 -44
  191. package/src/cli.ts +30 -8
  192. package/src/cmd/ai/prompt/web.md +43 -17
  193. package/src/cmd/build/vite/bun-dev-server.ts +92 -6
  194. package/src/cmd/build/vite/index.ts +0 -1
  195. package/src/cmd/build/vite/static-renderer.ts +18 -7
  196. package/src/cmd/build/vite/vite-asset-server-config.ts +37 -27
  197. package/src/cmd/build/vite/vite-asset-server.ts +5 -1
  198. package/src/cmd/build/vite/vite-builder.ts +12 -1
  199. package/src/cmd/build/vite/ws-proxy.ts +52 -3
  200. package/src/cmd/cloud/deploy.ts +117 -49
  201. package/src/cmd/cloud/sandbox/checkpoint/create.ts +10 -4
  202. package/src/cmd/cloud/sandbox/checkpoint/delete.ts +10 -4
  203. package/src/cmd/cloud/sandbox/checkpoint/list.ts +10 -4
  204. package/src/cmd/cloud/sandbox/checkpoint/restore.ts +10 -4
  205. package/src/cmd/cloud/sandbox/create.ts +14 -4
  206. package/src/cmd/cloud/sandbox/delete.ts +10 -4
  207. package/src/cmd/cloud/sandbox/env.ts +10 -5
  208. package/src/cmd/cloud/sandbox/exec.ts +157 -42
  209. package/src/cmd/cloud/sandbox/execution/list.ts +10 -5
  210. package/src/cmd/cloud/sandbox/fs/cp.ts +94 -126
  211. package/src/cmd/cloud/sandbox/fs/download.ts +18 -25
  212. package/src/cmd/cloud/sandbox/fs/ls.ts +10 -5
  213. package/src/cmd/cloud/sandbox/fs/mkdir.ts +10 -5
  214. package/src/cmd/cloud/sandbox/fs/rm.ts +10 -5
  215. package/src/cmd/cloud/sandbox/fs/rmdir.ts +10 -5
  216. package/src/cmd/cloud/sandbox/fs/upload.ts +14 -8
  217. package/src/cmd/cloud/sandbox/get.ts +28 -7
  218. package/src/cmd/cloud/sandbox/job/create.ts +10 -4
  219. package/src/cmd/cloud/sandbox/job/destroy.ts +10 -4
  220. package/src/cmd/cloud/sandbox/job/get.ts +10 -4
  221. package/src/cmd/cloud/sandbox/job/list.ts +10 -4
  222. package/src/cmd/cloud/sandbox/job/logs.ts +11 -4
  223. package/src/cmd/cloud/sandbox/pause.ts +31 -5
  224. package/src/cmd/cloud/sandbox/resume.ts +10 -4
  225. package/src/cmd/cloud/sandbox/run.ts +49 -11
  226. package/src/cmd/cloud/sandbox/snapshot/create.ts +6 -6
  227. package/src/cmd/cloud/sandbox/util.ts +63 -2
  228. package/src/cmd/coder/create.ts +8 -8
  229. package/src/cmd/coder/start.ts +3 -0
  230. package/src/cmd/coder/tui-init.ts +1 -1
  231. package/src/cmd/coder/update.ts +7 -7
  232. package/src/cmd/coder/workspace/common.ts +103 -0
  233. package/src/cmd/coder/workspace/create.ts +84 -37
  234. package/src/cmd/coder/workspace/get.ts +2 -5
  235. package/src/cmd/coder/workspace/index.ts +13 -1
  236. package/src/cmd/coder/workspace/list.ts +4 -0
  237. package/src/cmd/coder/workspace/refresh.ts +63 -0
  238. package/src/cmd/coder/workspace/update.ts +154 -0
  239. package/src/cmd/coder/workspace/validate-dependencies.ts +75 -0
  240. package/src/cmd/dev/dev-lock.ts +50 -16
  241. package/src/cmd/dev/index.ts +249 -134
  242. package/src/cmd/dev/process-manager.ts +173 -33
  243. package/src/cmd/project/create.ts +0 -2
  244. package/src/cmd/project/index.ts +0 -3
  245. package/src/cmd/project/random-name.ts +152 -0
  246. package/src/cmd/project/template-flow.ts +196 -305
  247. package/src/composite-logger.ts +20 -0
  248. package/src/config.ts +69 -19
  249. package/src/tui/prompt.ts +214 -8
  250. package/dist/cmd/build/vite/public-asset-path-plugin.d.ts +0 -45
  251. package/dist/cmd/build/vite/public-asset-path-plugin.d.ts.map +0 -1
  252. package/dist/cmd/build/vite/public-asset-path-plugin.js +0 -166
  253. package/dist/cmd/build/vite/public-asset-path-plugin.js.map +0 -1
  254. package/dist/cmd/project/auth/generate.d.ts +0 -5
  255. package/dist/cmd/project/auth/generate.d.ts.map +0 -1
  256. package/dist/cmd/project/auth/generate.js +0 -102
  257. package/dist/cmd/project/auth/generate.js.map +0 -1
  258. package/dist/cmd/project/auth/index.d.ts +0 -2
  259. package/dist/cmd/project/auth/index.d.ts.map +0 -1
  260. package/dist/cmd/project/auth/index.js +0 -21
  261. package/dist/cmd/project/auth/index.js.map +0 -1
  262. package/dist/cmd/project/auth/init.d.ts +0 -2
  263. package/dist/cmd/project/auth/init.d.ts.map +0 -1
  264. package/dist/cmd/project/auth/init.js +0 -213
  265. package/dist/cmd/project/auth/init.js.map +0 -1
  266. package/dist/cmd/project/auth/shared.d.ts +0 -93
  267. package/dist/cmd/project/auth/shared.d.ts.map +0 -1
  268. package/dist/cmd/project/auth/shared.js +0 -475
  269. package/dist/cmd/project/auth/shared.js.map +0 -1
  270. package/src/cmd/build/vite/public-asset-path-plugin.ts +0 -209
  271. package/src/cmd/project/auth/generate.ts +0 -116
  272. package/src/cmd/project/auth/index.ts +0 -21
  273. package/src/cmd/project/auth/init.ts +0 -256
  274. package/src/cmd/project/auth/shared.ts +0 -591
@@ -31,16 +31,14 @@ import * as tui from '../../tui';
31
31
  import { createPrompt, note } from '../../tui';
32
32
  import type { AuthData, Config } from '../../types';
33
33
  import { getGithubBotIdentity } from '../git/api';
34
- import {
35
- ensureAuthDependencies,
36
- generateAuthFileContent,
37
- generateAuthSchemaSql,
38
- printIntegrationExamples,
39
- runAuthMigrations,
40
- } from './auth/shared';
41
34
  import { downloadTemplate, initGitRepo, setupProject } from './download';
35
+ import { suggestBucketName, suggestDatabaseName } from './random-name';
42
36
  import { fetchTemplates, type TemplateInfo } from './templates';
43
37
 
38
+ // Domain validator shared between the multi-select branch and the standalone prompt.
39
+ const DOMAIN_REGEX =
40
+ /^(?=.{1,253}$)(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[A-Za-z]{2,63}$/;
41
+
44
42
  interface CreateFlowOptions {
45
43
  projectName?: string;
46
44
  dir?: string;
@@ -59,7 +57,6 @@ interface CreateFlowOptions {
59
57
  apiClient?: APIClient;
60
58
  database?: string;
61
59
  storage?: string;
62
- enableAuth?: boolean;
63
60
  }
64
61
 
65
62
  export interface CreateFlowResult {
@@ -92,7 +89,6 @@ export async function runCreateFlow(options: CreateFlowOptions): Promise<CreateF
92
89
  domains,
93
90
  database: databaseOption,
94
91
  storage: storageOption,
95
- enableAuth: enableAuthOption,
96
92
  } = options;
97
93
 
98
94
  const isHeadless = !process.stdin.isTTY || !process.stdout.isTTY;
@@ -290,7 +286,7 @@ export async function runCreateFlow(options: CreateFlowOptions): Promise<CreateF
290
286
  };
291
287
  }
292
288
 
293
- // Add separator bar if we're going to show resource prompts
289
+ // Resource provisioning gates
294
290
  const canProvision = auth && apiClient && catalystClient && orgId && region;
295
291
  // Only count as resource flags if actually requesting provisioning (not explicit skip)
296
292
  const hasResourceFlags =
@@ -314,23 +310,63 @@ export async function runCreateFlow(options: CreateFlowOptions): Promise<CreateF
314
310
  );
315
311
  }
316
312
 
317
- // Validate that --enable-auth requires authentication and registration
318
- if (enableAuthOption && !canProvision) {
319
- logger.fatal(
320
- 'Cannot enable Agentuity Auth without being authenticated and registering the project.\n' +
321
- 'Remove --no-register or omit --enable-auth flag.',
322
- ErrorCode.VALIDATION_FAILED
323
- );
324
- }
325
-
326
313
  if (canProvision) {
327
- // Fetch resources for selected org and region using Catalyst API (needed for both interactive and CLI flags)
328
- let resources: Awaited<ReturnType<typeof listResources>> | undefined;
314
+ // CLI flags pre-resolve their respective per-resource decision; the multi-select
315
+ // is only used for resources where the user didn't pass a flag.
316
+ const dbFlagAction = resolveFlagAction(databaseOption, 'database');
317
+ const storageFlagAction = resolveFlagAction(storageOption, 'storage');
318
+ const domainFlagProvided = (domains?.length ?? 0) > 0;
319
+
320
+ // Determine which resources should run through the configuration phase.
321
+ // In interactive mode, ask the user via a single multi-select.
322
+ // In headless / non-interactive mode, only flagged resources are considered.
323
+ let wantDb = dbFlagAction !== undefined && dbFlagAction !== 'Skip';
324
+ let wantStorage = storageFlagAction !== undefined && storageFlagAction !== 'Skip';
325
+ let wantDomain = domainFlagProvided;
329
326
 
327
+ if (isInteractive) {
328
+ // Build multi-select options dynamically: only show resources the user hasn't
329
+ // already decided about via CLI flags. If all three came from flags, skip the prompt.
330
+ const msOptions: {
331
+ value: 'database' | 'storage' | 'domain';
332
+ label: string;
333
+ hint?: string;
334
+ }[] = [];
335
+ if (dbFlagAction === undefined) {
336
+ msOptions.push({ value: 'database', label: 'SQL Database', hint: 'PostgreSQL' });
337
+ }
338
+ if (storageFlagAction === undefined) {
339
+ msOptions.push({ value: 'storage', label: 'Storage Bucket', hint: 'S3-compatible' });
340
+ }
341
+ if (!domainFlagProvided) {
342
+ msOptions.push({ value: 'domain', label: 'Custom Domain', hint: 'BYO domain' });
343
+ }
344
+
345
+ if (msOptions.length > 0) {
346
+ const picked = await prompt.multiselect<'database' | 'storage' | 'domain'>({
347
+ message: 'What would you like to set up? (all optional)',
348
+ options: msOptions,
349
+ initial: [],
350
+ });
351
+ if (dbFlagAction === undefined) wantDb = picked.includes('database');
352
+ if (storageFlagAction === undefined) wantStorage = picked.includes('storage');
353
+ if (!domainFlagProvided) wantDomain = picked.includes('domain');
354
+ }
355
+ }
356
+
357
+ // Fetch existing resources only if we'll actually need them.
358
+ // Need them when:
359
+ // - user wants db/storage in interactive mode (to offer "use existing")
360
+ // - a CLI flag pointed at an existing resource by name
361
+ let resources: Awaited<ReturnType<typeof listResources>> | undefined;
330
362
  const needResources =
331
- isInteractive ||
332
- (databaseOption && databaseOption !== 'skip' && databaseOption !== 'new') ||
333
- (storageOption && storageOption !== 'skip' && storageOption !== 'new');
363
+ (isInteractive && (wantDb || wantStorage)) ||
364
+ (databaseOption !== undefined &&
365
+ dbFlagAction !== 'Create New' &&
366
+ dbFlagAction !== 'Skip') ||
367
+ (storageOption !== undefined &&
368
+ storageFlagAction !== 'Create New' &&
369
+ storageFlagAction !== 'Skip');
334
370
 
335
371
  if (needResources) {
336
372
  resources = await tui.spinner({
@@ -348,316 +384,173 @@ export async function runCreateFlow(options: CreateFlowOptions): Promise<CreateF
348
384
  logger.debug(
349
385
  `Storage buckets: ${resources.s3.map((b) => b.bucket_name).join(', ') || '(none)'}`
350
386
  );
351
- }
352
387
 
353
- // Determine database action: CLI flag > interactive prompt > skip (headless)
354
- let db_action: string;
355
- if (databaseOption !== undefined) {
356
- // CLI flag provided - normalize to expected values
357
- if (databaseOption.toLowerCase() === 'new') {
358
- db_action = 'Create New';
359
- } else if (databaseOption.toLowerCase() === 'skip') {
360
- db_action = 'Skip';
361
- } else {
362
- // Existing database name - validate it exists
363
- const existingDb = resources?.db.find((d) => d.name === databaseOption);
364
- if (!existingDb) {
365
- logger.fatal(
366
- `Database '${databaseOption}' not found. Use 'new' to create a new database or 'skip' to skip.`,
367
- ErrorCode.RESOURCE_NOT_FOUND
368
- );
369
- }
370
- db_action = databaseOption;
388
+ // Validate flag-supplied resource names against the fetched list.
389
+ if (
390
+ databaseOption !== undefined &&
391
+ dbFlagAction !== 'Create New' &&
392
+ dbFlagAction !== 'Skip' &&
393
+ !resources.db.find((d) => d.name === dbFlagAction)
394
+ ) {
395
+ logger.fatal(
396
+ `Database '${databaseOption}' not found. Use 'new' to create a new database or 'skip' to skip.`,
397
+ ErrorCode.RESOURCE_NOT_FOUND
398
+ );
371
399
  }
372
- } else if (isInteractive) {
373
- db_action = await prompt.select({
374
- message: 'Create SQL Database?',
375
- options: [
376
- { value: 'Skip', label: 'Skip or Setup later' },
377
- { value: 'Create New', label: 'Create a new database' },
378
- ...resources!.db.map((db) => ({
379
- value: db.name,
380
- label: `Use database: ${tui.tuiColors.primary(db.name)}`,
381
- })),
382
- ],
383
- });
384
- } else {
385
- // Headless without flag - skip
386
- db_action = 'Skip';
387
- }
388
-
389
- // Determine storage action: CLI flag > interactive prompt > skip (headless)
390
- let s3_action: string;
391
- if (storageOption !== undefined) {
392
- // CLI flag provided - normalize to expected values
393
- if (storageOption.toLowerCase() === 'new') {
394
- s3_action = 'Create New';
395
- } else if (storageOption.toLowerCase() === 'skip') {
396
- s3_action = 'Skip';
397
- } else {
398
- // Existing bucket name - validate it exists
399
- const existingBucket = resources?.s3.find((b) => b.bucket_name === storageOption);
400
- if (!existingBucket) {
401
- logger.fatal(
402
- `Storage bucket '${storageOption}' not found. Use 'new' to create a new bucket or 'skip' to skip.`,
403
- ErrorCode.RESOURCE_NOT_FOUND
404
- );
405
- }
406
- s3_action = storageOption;
400
+ if (
401
+ storageOption !== undefined &&
402
+ storageFlagAction !== 'Create New' &&
403
+ storageFlagAction !== 'Skip' &&
404
+ !resources.s3.find((b) => b.bucket_name === storageFlagAction)
405
+ ) {
406
+ logger.fatal(
407
+ `Storage bucket '${storageOption}' not found. Use 'new' to create a new bucket or 'skip' to skip.`,
408
+ ErrorCode.RESOURCE_NOT_FOUND
409
+ );
407
410
  }
408
- } else if (isInteractive) {
409
- s3_action = await prompt.select({
410
- message: 'Create Storage Bucket?',
411
- options: [
412
- { value: 'Skip', label: 'Skip or Setup later' },
413
- { value: 'Create New', label: 'Create a new bucket' },
414
- ...resources!.s3.map((bucket) => ({
415
- value: bucket.bucket_name,
416
- label: `Use bucket: ${tui.tuiColors.primary(bucket.bucket_name)}`,
417
- })),
418
- ],
419
- });
420
- } else {
421
- // Headless without flag - skip
422
- s3_action = 'Skip';
423
411
  }
424
412
 
425
- // Custom DNS: only prompt in interactive mode if not already provided
426
- if (!domains?.length && isInteractive) {
427
- const customDns = await prompt.text({
428
- message: 'Setup custom DNS?',
429
- hint: 'Enter a domain name or press Enter to skip',
430
- validate: (val: string) =>
431
- val === ''
432
- ? true
433
- : /^(?=.{1,253}$)(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[A-Za-z]{2,63}$/.test(
434
- val
435
- ),
436
- });
437
- if (customDns) {
438
- _domains = [customDns];
413
+ // === Configure each selected resource: Database Storage Domain ===
414
+
415
+ // Database
416
+ if (wantDb) {
417
+ let dbAction = dbFlagAction;
418
+ if (dbAction === undefined && isInteractive) {
419
+ const existing = resources?.db ?? [];
420
+ if (existing.length > 0) {
421
+ dbAction = await prompt.select<string>({
422
+ message: 'SQL Database',
423
+ options: [
424
+ { value: 'Create New', label: 'Create a new database' },
425
+ ...existing.map((db) => ({
426
+ value: db.name,
427
+ label: `Use database: ${tui.tuiColors.primary(db.name)}`,
428
+ })),
429
+ ],
430
+ });
431
+ } else {
432
+ // No existing databases — user already opted in via the multi-select, so create new.
433
+ dbAction = 'Create New';
434
+ }
439
435
  }
440
- }
441
436
 
442
- // Process storage action
443
- switch (s3_action) {
444
- case 'Create New': {
445
- let bucketName: string | undefined;
446
- let bucketDescription: string | undefined;
437
+ if (dbAction === 'Create New') {
438
+ let dbName: string | undefined;
439
+ let dbDescription: string | undefined;
447
440
 
448
- // Only prompt for name/description in interactive mode
449
441
  if (isInteractive) {
450
- const bucketNameInput = await prompt.text({
451
- message: 'Bucket name',
452
- hint: 'Optional - lowercase letters, digits, hyphens only',
442
+ const suggestion = suggestDatabaseName(projectName);
443
+ const dbNameInput = await prompt.text({
444
+ message: 'Database name',
445
+ hint: 'Optional · lowercase letters, digits, underscores',
446
+ placeholder: suggestion,
453
447
  validate: (value: string) => {
454
448
  const trimmed = value.trim();
455
449
  if (trimmed === '') return true;
456
- const result = validateBucketName(trimmed);
450
+ const result = validateDatabaseName(trimmed);
457
451
  return result.valid ? true : result.error!;
458
452
  },
459
453
  });
460
- bucketName = bucketNameInput.trim() || undefined;
461
- bucketDescription =
454
+ dbName = dbNameInput.trim() || undefined;
455
+ dbDescription =
462
456
  (await prompt.text({
463
- message: 'Bucket description',
464
- hint: 'Optional - press Enter to skip',
457
+ message: 'Database description',
458
+ hint: 'Optional · press Enter to skip',
465
459
  })) || undefined;
466
460
  }
467
461
 
468
462
  const created = await tui.spinner({
469
- message: 'Provisioning New Bucket',
463
+ message: 'Provisioning New SQL Database',
470
464
  clearOnSuccess: true,
471
465
  callback: async () => {
472
466
  return createResources(catalystClient!, orgId!, region!, [
473
- {
474
- type: 's3',
475
- name: bucketName,
476
- description: bucketDescription,
477
- },
467
+ { type: 'db', name: dbName, description: dbDescription },
478
468
  ]);
479
469
  },
480
470
  });
481
- // Collect env vars from newly created resource
482
- if (created[0]?.env) {
483
- Object.assign(resourceEnvVars, created[0].env);
484
- }
485
- break;
486
- }
487
- case 'Skip': {
488
- break;
471
+ if (created[0]?.env) Object.assign(resourceEnvVars, created[0].env);
472
+ } else if (dbAction && dbAction !== 'Skip') {
473
+ // Existing database selected — reuse its env vars.
474
+ const selectedDb = resources?.db.find((d) => d.name === dbAction);
475
+ if (selectedDb?.env) Object.assign(resourceEnvVars, selectedDb.env);
489
476
  }
490
- default: {
491
- // User selected an existing bucket - get env vars from the resources list
492
- const selectedBucket = resources?.s3.find((b) => b.bucket_name === s3_action);
493
- if (selectedBucket?.env) {
494
- Object.assign(resourceEnvVars, selectedBucket.env);
477
+ }
478
+
479
+ // Storage
480
+ if (wantStorage) {
481
+ let s3Action = storageFlagAction;
482
+ if (s3Action === undefined && isInteractive) {
483
+ const existing = resources?.s3 ?? [];
484
+ if (existing.length > 0) {
485
+ s3Action = await prompt.select<string>({
486
+ message: 'Storage Bucket',
487
+ options: [
488
+ { value: 'Create New', label: 'Create a new bucket' },
489
+ ...existing.map((bucket) => ({
490
+ value: bucket.bucket_name,
491
+ label: `Use bucket: ${tui.tuiColors.primary(bucket.bucket_name)}`,
492
+ })),
493
+ ],
494
+ });
495
+ } else {
496
+ s3Action = 'Create New';
495
497
  }
496
- break;
497
498
  }
498
- }
499
499
 
500
- // Process database action
501
- switch (db_action) {
502
- case 'Create New': {
503
- let dbName: string | undefined;
504
- let dbDescription: string | undefined;
500
+ if (s3Action === 'Create New') {
501
+ let bucketName: string | undefined;
502
+ let bucketDescription: string | undefined;
505
503
 
506
- // Only prompt for name/description in interactive mode
507
504
  if (isInteractive) {
508
- const dbNameInput = await prompt.text({
509
- message: 'Database name',
510
- hint: 'Optional - lowercase letters, digits, underscores only',
505
+ const suggestion = suggestBucketName(projectName);
506
+ const bucketNameInput = await prompt.text({
507
+ message: 'Bucket name',
508
+ hint: 'Optional · lowercase letters, digits, hyphens',
509
+ placeholder: suggestion,
511
510
  validate: (value: string) => {
512
511
  const trimmed = value.trim();
513
512
  if (trimmed === '') return true;
514
- const result = validateDatabaseName(trimmed);
513
+ const result = validateBucketName(trimmed);
515
514
  return result.valid ? true : result.error!;
516
515
  },
517
516
  });
518
- dbName = dbNameInput.trim() || undefined;
519
- dbDescription =
517
+ bucketName = bucketNameInput.trim() || undefined;
518
+ bucketDescription =
520
519
  (await prompt.text({
521
- message: 'Database description',
522
- hint: 'Optional - press Enter to skip',
520
+ message: 'Bucket description',
521
+ hint: 'Optional · press Enter to skip',
523
522
  })) || undefined;
524
523
  }
525
524
 
526
525
  const created = await tui.spinner({
527
- message: 'Provisioning New SQL Database',
526
+ message: 'Provisioning New Bucket',
528
527
  clearOnSuccess: true,
529
528
  callback: async () => {
530
529
  return createResources(catalystClient!, orgId!, region!, [
531
- {
532
- type: 'db',
533
- name: dbName,
534
- description: dbDescription,
535
- },
530
+ { type: 's3', name: bucketName, description: bucketDescription },
536
531
  ]);
537
532
  },
538
533
  });
539
- // Collect env vars from newly created resource
540
- if (created[0]?.env) {
541
- Object.assign(resourceEnvVars, created[0].env);
542
- }
543
- break;
544
- }
545
- case 'Skip': {
546
- break;
547
- }
548
- default: {
549
- // User selected an existing database - get env vars from the resources list
550
- const selectedDb = resources?.db.find((d) => d.name === db_action);
551
- if (selectedDb?.env) {
552
- Object.assign(resourceEnvVars, selectedDb.env);
553
- }
554
- break;
555
- }
556
- }
557
- }
558
-
559
- // Auth setup - either from template, CLI flag, or user choice
560
- const templateHasAuth = selectedTemplate.id === 'agentuity-auth';
561
-
562
- let authEnabled = templateHasAuth; // Auth templates have auth enabled by default
563
- let authDatabaseName: string | undefined;
564
- let authDatabaseUrl: string | undefined;
565
-
566
- // Handle auth enablement: CLI flag > interactive prompt > disabled (headless)
567
- if (enableAuthOption !== undefined) {
568
- // CLI flag provided
569
- authEnabled = enableAuthOption;
570
- } else if (canProvision && isInteractive && !templateHasAuth) {
571
- // For non-auth templates in interactive mode, ask if they want to enable auth
572
- const enableAuth = await prompt.select({
573
- message: 'Enable Agentuity Authentication?',
574
- options: [
575
- { value: 'no', label: "No, I'll add auth later" },
576
- { value: 'yes', label: 'Yes, set up Agentuity Auth' },
577
- ],
578
- });
579
-
580
- if (enableAuth === 'yes') {
581
- authEnabled = true;
582
- }
583
- }
584
- // In headless mode without --enable-auth flag, authEnabled stays false (unless template has auth)
585
-
586
- // Set up database and secret for any auth-enabled project
587
- if (authEnabled && canProvision) {
588
- // If a database was already selected/created above, use it for auth
589
- if (resourceEnvVars.DATABASE_URL) {
590
- authDatabaseUrl = resourceEnvVars.DATABASE_URL;
591
- // Extract database name from URL using proper URL parsing
592
- try {
593
- const dbUrl = new URL(authDatabaseUrl);
594
- const dbName = dbUrl.pathname.replace(/^\/+/, ''); // Remove leading slashes
595
- // Validate: non-empty and contains only safe characters
596
- if (dbName && /^[A-Za-z0-9_-]+$/.test(dbName)) {
597
- authDatabaseName = dbName;
598
- }
599
- } catch {
600
- // Invalid URL format, authDatabaseName stays undefined
601
- }
602
- } else {
603
- // No database selected yet, create one for auth
604
- const created = await tui.spinner({
605
- message: 'Provisioning database for auth',
606
- clearOnSuccess: true,
607
- callback: async () => {
608
- return createResources(catalystClient!, orgId!, region!, [{ type: 'db' }]);
609
- },
610
- });
611
- const createdDb = created[0];
612
- if (!createdDb) {
613
- logger.fatal('Failed to create database for auth', ErrorCode.RESOURCE_NOT_FOUND);
614
- return undefined as never;
615
- }
616
- authDatabaseName = createdDb.name;
617
-
618
- // Get env vars from created resource
619
- if (createdDb.env) {
620
- authDatabaseUrl = createdDb.env.DATABASE_URL;
621
- // Also add to resourceEnvVars if not already set
622
- if (!resourceEnvVars.DATABASE_URL) {
623
- Object.assign(resourceEnvVars, createdDb.env);
624
- }
534
+ if (created[0]?.env) Object.assign(resourceEnvVars, created[0].env);
535
+ } else if (s3Action && s3Action !== 'Skip') {
536
+ const selectedBucket = resources?.s3.find((b) => b.bucket_name === s3Action);
537
+ if (selectedBucket?.env) Object.assign(resourceEnvVars, selectedBucket.env);
625
538
  }
626
539
  }
627
540
 
628
- // Install auth dependencies (skip for agentuity-auth template which has them)
629
- if (!templateHasAuth) {
630
- await ensureAuthDependencies({ projectDir: dest, logger });
631
-
632
- // Generate auth.ts
633
- const authFilePath = resolve(dest, 'src', 'auth.ts');
634
- if (!existsSync(authFilePath)) {
635
- const srcDir = resolve(dest, 'src');
636
- if (!existsSync(srcDir)) {
637
- await Bun.write(resolve(srcDir, '.gitkeep'), '');
638
- }
639
- await Bun.write(authFilePath, generateAuthFileContent());
640
- tui.success('Created src/auth.ts');
641
- }
642
- }
643
-
644
- // Run migrations
645
- if (authDatabaseName) {
646
- const sql = await tui.spinner({
647
- message: 'Preparing auth database schema...',
648
- clearOnSuccess: true,
649
- callback: () => generateAuthSchemaSql(logger, dest),
650
- });
651
-
652
- await runAuthMigrations({
653
- logger,
654
- auth,
655
- orgId,
656
- region,
657
- databaseName: authDatabaseName,
658
- sql,
659
- config,
541
+ // Custom Domain
542
+ if (wantDomain && !domainFlagProvided && isInteractive) {
543
+ const customDns = await prompt.text({
544
+ message: 'Custom domain',
545
+ hint: 'e.g. agents.example.com',
546
+ validate: (val: string) =>
547
+ val === ''
548
+ ? 'Domain is required (or go back and uncheck Custom Domain)'
549
+ : DOMAIN_REGEX.test(val)
550
+ ? true
551
+ : 'Invalid domain',
660
552
  });
553
+ if (customDns) _domains = [customDns];
661
554
  }
662
555
  }
663
556
 
@@ -702,28 +595,9 @@ export async function runCreateFlow(options: CreateFlowOptions): Promise<CreateF
702
595
  },
703
596
  });
704
597
 
705
- // Add auth secret to resourceEnvVars if auth is enabled
706
- if (authEnabled && !resourceEnvVars.AGENTUITY_AUTH_SECRET) {
707
- const devSecret = `dev-${crypto.randomUUID()}`;
708
- resourceEnvVars.AGENTUITY_AUTH_SECRET = devSecret;
709
- }
710
-
711
598
  // Write resource environment variables to .env
712
599
  if (Object.keys(resourceEnvVars).length > 0) {
713
600
  await addResourceEnvVars(dest, resourceEnvVars);
714
-
715
- // Show user feedback for auth-related env vars
716
- if (authEnabled) {
717
- if (resourceEnvVars.DATABASE_URL) {
718
- tui.success('DATABASE_URL added to .env');
719
- }
720
- if (resourceEnvVars.AGENTUITY_AUTH_SECRET) {
721
- tui.success('AGENTUITY_AUTH_SECRET added to .env');
722
- tui.info(
723
- `Generate one with: ${tui.muted('npx @better-auth/cli secret')} or ${tui.muted('openssl rand -hex 32')}`
724
- );
725
- }
726
- }
727
601
  }
728
602
 
729
603
  // After registration, push any existing env/secrets from .env
@@ -819,11 +693,6 @@ export async function runCreateFlow(options: CreateFlowOptions): Promise<CreateF
819
693
  }
820
694
  }
821
695
 
822
- // Print auth integration examples if auth was enabled (skip for auth template - already set up)
823
- if (authEnabled && !templateHasAuth) {
824
- printIntegrationExamples();
825
- }
826
-
827
696
  return {
828
697
  projectId,
829
698
  orgId,
@@ -838,6 +707,28 @@ export async function runCreateFlow(options: CreateFlowOptions): Promise<CreateF
838
707
  };
839
708
  }
840
709
 
710
+ /**
711
+ * Normalize a CLI flag value (`--database` / `--storage`) into the same
712
+ * action vocabulary the interactive flow uses:
713
+ * - 'new' -> 'Create New'
714
+ * - 'skip' -> 'Skip'
715
+ * - any other string -> treated as an existing-resource name (returned as-is)
716
+ * - undefined -> undefined (no flag passed; multi-select decides)
717
+ *
718
+ * The existence check for named resources happens later, after the resource
719
+ * list is fetched.
720
+ */
721
+ function resolveFlagAction(
722
+ flag: string | undefined,
723
+ _kind: 'database' | 'storage'
724
+ ): string | undefined {
725
+ if (flag === undefined) return undefined;
726
+ const lower = flag.toLowerCase();
727
+ if (lower === 'new') return 'Create New';
728
+ if (lower === 'skip') return 'Skip';
729
+ return flag;
730
+ }
731
+
841
732
  /**
842
733
  * Sanitize a project name to create a safe directory/package name
843
734
  * - Converts to lowercase
@@ -7,6 +7,12 @@
7
7
  */
8
8
 
9
9
  import type { Logger } from '@agentuity/core';
10
+ import { format } from 'node:util';
11
+ import { ErrorCode, getExitCode } from './errors';
12
+
13
+ function isErrorCode(value: unknown): value is ErrorCode {
14
+ return typeof value === 'string' && Object.values(ErrorCode).includes(value as ErrorCode);
15
+ }
10
16
 
11
17
  /**
12
18
  * A logger that delegates to multiple child loggers
@@ -45,6 +51,20 @@ export class CompositeLogger implements Logger {
45
51
  }
46
52
 
47
53
  fatal(message: unknown, ...args: unknown[]): never {
54
+ const maybeErrorCode = args[args.length - 1];
55
+ if (isErrorCode(maybeErrorCode)) {
56
+ const formatArgs = args.slice(0, -1);
57
+ const formattedMessage = format(message, ...formatArgs);
58
+ for (const logger of this.loggers) {
59
+ try {
60
+ logger.error(formattedMessage);
61
+ } catch {
62
+ // Keep fatal exits reliable even if one delegate cannot write.
63
+ }
64
+ }
65
+ process.exit(getExitCode(maybeErrorCode));
66
+ }
67
+
48
68
  // Call fatal on all loggers, but only the first one will exit
49
69
  for (const logger of this.loggers) {
50
70
  try {