@agentuity/cli 2.0.10 → 2.0.12

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 (233) 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/cmd/build/vite/agent-discovery.js +4 -4
  5. package/dist/cmd/build/vite/agent-discovery.js.map +1 -1
  6. package/dist/cmd/build/vite/bun-dev-server.d.ts +20 -0
  7. package/dist/cmd/build/vite/bun-dev-server.d.ts.map +1 -1
  8. package/dist/cmd/build/vite/bun-dev-server.js +62 -4
  9. package/dist/cmd/build/vite/bun-dev-server.js.map +1 -1
  10. package/dist/cmd/build/vite/index.d.ts +0 -1
  11. package/dist/cmd/build/vite/index.d.ts.map +1 -1
  12. package/dist/cmd/build/vite/index.js +0 -1
  13. package/dist/cmd/build/vite/index.js.map +1 -1
  14. package/dist/cmd/build/vite/static-renderer.d.ts +17 -0
  15. package/dist/cmd/build/vite/static-renderer.d.ts.map +1 -1
  16. package/dist/cmd/build/vite/static-renderer.js +18 -6
  17. package/dist/cmd/build/vite/static-renderer.js.map +1 -1
  18. package/dist/cmd/build/vite/vite-asset-server-config.d.ts.map +1 -1
  19. package/dist/cmd/build/vite/vite-asset-server-config.js +34 -27
  20. package/dist/cmd/build/vite/vite-asset-server-config.js.map +1 -1
  21. package/dist/cmd/build/vite/vite-asset-server.d.ts +9 -0
  22. package/dist/cmd/build/vite/vite-asset-server.d.ts.map +1 -1
  23. package/dist/cmd/build/vite/vite-asset-server.js +5 -1
  24. package/dist/cmd/build/vite/vite-asset-server.js.map +1 -1
  25. package/dist/cmd/build/vite/vite-builder.d.ts.map +1 -1
  26. package/dist/cmd/build/vite/vite-builder.js +12 -1
  27. package/dist/cmd/build/vite/vite-builder.js.map +1 -1
  28. package/dist/cmd/build/vite/ws-proxy.d.ts +15 -1
  29. package/dist/cmd/build/vite/ws-proxy.d.ts.map +1 -1
  30. package/dist/cmd/build/vite/ws-proxy.js +33 -0
  31. package/dist/cmd/build/vite/ws-proxy.js.map +1 -1
  32. package/dist/cmd/cloud/deploy.d.ts.map +1 -1
  33. package/dist/cmd/cloud/deploy.js +98 -39
  34. package/dist/cmd/cloud/deploy.js.map +1 -1
  35. package/dist/cmd/cloud/sandbox/checkpoint/create.d.ts.map +1 -1
  36. package/dist/cmd/cloud/sandbox/checkpoint/create.js +3 -4
  37. package/dist/cmd/cloud/sandbox/checkpoint/create.js.map +1 -1
  38. package/dist/cmd/cloud/sandbox/checkpoint/delete.d.ts.map +1 -1
  39. package/dist/cmd/cloud/sandbox/checkpoint/delete.js +3 -4
  40. package/dist/cmd/cloud/sandbox/checkpoint/delete.js.map +1 -1
  41. package/dist/cmd/cloud/sandbox/checkpoint/list.d.ts.map +1 -1
  42. package/dist/cmd/cloud/sandbox/checkpoint/list.js +3 -4
  43. package/dist/cmd/cloud/sandbox/checkpoint/list.js.map +1 -1
  44. package/dist/cmd/cloud/sandbox/checkpoint/restore.d.ts.map +1 -1
  45. package/dist/cmd/cloud/sandbox/checkpoint/restore.js +3 -4
  46. package/dist/cmd/cloud/sandbox/checkpoint/restore.js.map +1 -1
  47. package/dist/cmd/cloud/sandbox/create.d.ts.map +1 -1
  48. package/dist/cmd/cloud/sandbox/create.js +13 -4
  49. package/dist/cmd/cloud/sandbox/create.js.map +1 -1
  50. package/dist/cmd/cloud/sandbox/delete.d.ts.map +1 -1
  51. package/dist/cmd/cloud/sandbox/delete.js +3 -4
  52. package/dist/cmd/cloud/sandbox/delete.js.map +1 -1
  53. package/dist/cmd/cloud/sandbox/env.d.ts.map +1 -1
  54. package/dist/cmd/cloud/sandbox/env.js +3 -5
  55. package/dist/cmd/cloud/sandbox/env.js.map +1 -1
  56. package/dist/cmd/cloud/sandbox/exec.d.ts.map +1 -1
  57. package/dist/cmd/cloud/sandbox/exec.js +114 -41
  58. package/dist/cmd/cloud/sandbox/exec.js.map +1 -1
  59. package/dist/cmd/cloud/sandbox/execution/list.d.ts.map +1 -1
  60. package/dist/cmd/cloud/sandbox/execution/list.js +3 -5
  61. package/dist/cmd/cloud/sandbox/execution/list.js.map +1 -1
  62. package/dist/cmd/cloud/sandbox/fs/cp.d.ts.map +1 -1
  63. package/dist/cmd/cloud/sandbox/fs/cp.js +61 -113
  64. package/dist/cmd/cloud/sandbox/fs/cp.js.map +1 -1
  65. package/dist/cmd/cloud/sandbox/fs/download.d.ts.map +1 -1
  66. package/dist/cmd/cloud/sandbox/fs/download.js +11 -22
  67. package/dist/cmd/cloud/sandbox/fs/download.js.map +1 -1
  68. package/dist/cmd/cloud/sandbox/fs/ls.d.ts.map +1 -1
  69. package/dist/cmd/cloud/sandbox/fs/ls.js +3 -5
  70. package/dist/cmd/cloud/sandbox/fs/ls.js.map +1 -1
  71. package/dist/cmd/cloud/sandbox/fs/mkdir.d.ts.map +1 -1
  72. package/dist/cmd/cloud/sandbox/fs/mkdir.js +3 -5
  73. package/dist/cmd/cloud/sandbox/fs/mkdir.js.map +1 -1
  74. package/dist/cmd/cloud/sandbox/fs/rm.d.ts.map +1 -1
  75. package/dist/cmd/cloud/sandbox/fs/rm.js +3 -5
  76. package/dist/cmd/cloud/sandbox/fs/rm.js.map +1 -1
  77. package/dist/cmd/cloud/sandbox/fs/rmdir.d.ts.map +1 -1
  78. package/dist/cmd/cloud/sandbox/fs/rmdir.js +3 -5
  79. package/dist/cmd/cloud/sandbox/fs/rmdir.js.map +1 -1
  80. package/dist/cmd/cloud/sandbox/fs/upload.d.ts.map +1 -1
  81. package/dist/cmd/cloud/sandbox/fs/upload.js +7 -8
  82. package/dist/cmd/cloud/sandbox/fs/upload.js.map +1 -1
  83. package/dist/cmd/cloud/sandbox/get.d.ts.map +1 -1
  84. package/dist/cmd/cloud/sandbox/get.js +21 -7
  85. package/dist/cmd/cloud/sandbox/get.js.map +1 -1
  86. package/dist/cmd/cloud/sandbox/job/create.d.ts.map +1 -1
  87. package/dist/cmd/cloud/sandbox/job/create.js +3 -4
  88. package/dist/cmd/cloud/sandbox/job/create.js.map +1 -1
  89. package/dist/cmd/cloud/sandbox/job/destroy.d.ts.map +1 -1
  90. package/dist/cmd/cloud/sandbox/job/destroy.js +3 -4
  91. package/dist/cmd/cloud/sandbox/job/destroy.js.map +1 -1
  92. package/dist/cmd/cloud/sandbox/job/get.d.ts.map +1 -1
  93. package/dist/cmd/cloud/sandbox/job/get.js +3 -4
  94. package/dist/cmd/cloud/sandbox/job/get.js.map +1 -1
  95. package/dist/cmd/cloud/sandbox/job/list.d.ts.map +1 -1
  96. package/dist/cmd/cloud/sandbox/job/list.js +3 -4
  97. package/dist/cmd/cloud/sandbox/job/list.js.map +1 -1
  98. package/dist/cmd/cloud/sandbox/job/logs.d.ts.map +1 -1
  99. package/dist/cmd/cloud/sandbox/job/logs.js +4 -4
  100. package/dist/cmd/cloud/sandbox/job/logs.js.map +1 -1
  101. package/dist/cmd/cloud/sandbox/pause.d.ts.map +1 -1
  102. package/dist/cmd/cloud/sandbox/pause.js +21 -5
  103. package/dist/cmd/cloud/sandbox/pause.js.map +1 -1
  104. package/dist/cmd/cloud/sandbox/resume.d.ts.map +1 -1
  105. package/dist/cmd/cloud/sandbox/resume.js +3 -4
  106. package/dist/cmd/cloud/sandbox/resume.js.map +1 -1
  107. package/dist/cmd/cloud/sandbox/run.d.ts.map +1 -1
  108. package/dist/cmd/cloud/sandbox/run.js +36 -7
  109. package/dist/cmd/cloud/sandbox/run.js.map +1 -1
  110. package/dist/cmd/cloud/sandbox/util.d.ts +19 -0
  111. package/dist/cmd/cloud/sandbox/util.d.ts.map +1 -1
  112. package/dist/cmd/cloud/sandbox/util.js +40 -2
  113. package/dist/cmd/cloud/sandbox/util.js.map +1 -1
  114. package/dist/cmd/coder/create.d.ts.map +1 -1
  115. package/dist/cmd/coder/create.js +18 -0
  116. package/dist/cmd/coder/create.js.map +1 -1
  117. package/dist/cmd/coder/index.d.ts.map +1 -1
  118. package/dist/cmd/coder/index.js +4 -0
  119. package/dist/cmd/coder/index.js.map +1 -1
  120. package/dist/cmd/coder/start.d.ts.map +1 -1
  121. package/dist/cmd/coder/start.js +52 -1
  122. package/dist/cmd/coder/start.js.map +1 -1
  123. package/dist/cmd/coder/tui-init.js +1 -1
  124. package/dist/cmd/coder/tui-init.js.map +1 -1
  125. package/dist/cmd/coder/update.d.ts.map +1 -1
  126. package/dist/cmd/coder/update.js +21 -1
  127. package/dist/cmd/coder/update.js.map +1 -1
  128. package/dist/cmd/coder/workspace/create.d.ts.map +1 -1
  129. package/dist/cmd/coder/workspace/create.js +57 -13
  130. package/dist/cmd/coder/workspace/create.js.map +1 -1
  131. package/dist/cmd/coder/workspace/index.d.ts.map +1 -1
  132. package/dist/cmd/coder/workspace/index.js +1 -1
  133. package/dist/cmd/coder/workspace/index.js.map +1 -1
  134. package/dist/cmd/coder/workspace/list.js +2 -2
  135. package/dist/cmd/coder/workspace/list.js.map +1 -1
  136. package/dist/cmd/dev/dev-lock.d.ts.map +1 -1
  137. package/dist/cmd/dev/dev-lock.js +43 -17
  138. package/dist/cmd/dev/dev-lock.js.map +1 -1
  139. package/dist/cmd/dev/index.d.ts.map +1 -1
  140. package/dist/cmd/dev/index.js +211 -125
  141. package/dist/cmd/dev/index.js.map +1 -1
  142. package/dist/cmd/dev/process-manager.d.ts +41 -1
  143. package/dist/cmd/dev/process-manager.d.ts.map +1 -1
  144. package/dist/cmd/dev/process-manager.js +160 -31
  145. package/dist/cmd/dev/process-manager.js.map +1 -1
  146. package/dist/cmd/project/create.d.ts.map +1 -1
  147. package/dist/cmd/project/create.js +0 -2
  148. package/dist/cmd/project/create.js.map +1 -1
  149. package/dist/cmd/project/index.d.ts.map +1 -1
  150. package/dist/cmd/project/index.js +0 -3
  151. package/dist/cmd/project/index.js.map +1 -1
  152. package/dist/cmd/project/template-flow.d.ts +0 -1
  153. package/dist/cmd/project/template-flow.d.ts.map +1 -1
  154. package/dist/cmd/project/template-flow.js +1 -124
  155. package/dist/cmd/project/template-flow.js.map +1 -1
  156. package/dist/types.d.ts +1 -1
  157. package/package.json +7 -7
  158. package/src/cache/resource-region.ts +68 -44
  159. package/src/cmd/ai/prompt/web.md +43 -17
  160. package/src/cmd/build/vite/agent-discovery.ts +4 -4
  161. package/src/cmd/build/vite/bun-dev-server.ts +92 -6
  162. package/src/cmd/build/vite/index.ts +0 -1
  163. package/src/cmd/build/vite/static-renderer.ts +18 -7
  164. package/src/cmd/build/vite/vite-asset-server-config.ts +37 -27
  165. package/src/cmd/build/vite/vite-asset-server.ts +5 -1
  166. package/src/cmd/build/vite/vite-builder.ts +12 -1
  167. package/src/cmd/build/vite/ws-proxy.ts +52 -3
  168. package/src/cmd/cloud/deploy.ts +117 -49
  169. package/src/cmd/cloud/sandbox/checkpoint/create.ts +10 -4
  170. package/src/cmd/cloud/sandbox/checkpoint/delete.ts +10 -4
  171. package/src/cmd/cloud/sandbox/checkpoint/list.ts +10 -4
  172. package/src/cmd/cloud/sandbox/checkpoint/restore.ts +10 -4
  173. package/src/cmd/cloud/sandbox/create.ts +14 -4
  174. package/src/cmd/cloud/sandbox/delete.ts +10 -4
  175. package/src/cmd/cloud/sandbox/env.ts +10 -5
  176. package/src/cmd/cloud/sandbox/exec.ts +157 -42
  177. package/src/cmd/cloud/sandbox/execution/list.ts +10 -5
  178. package/src/cmd/cloud/sandbox/fs/cp.ts +94 -126
  179. package/src/cmd/cloud/sandbox/fs/download.ts +18 -25
  180. package/src/cmd/cloud/sandbox/fs/ls.ts +10 -5
  181. package/src/cmd/cloud/sandbox/fs/mkdir.ts +10 -5
  182. package/src/cmd/cloud/sandbox/fs/rm.ts +10 -5
  183. package/src/cmd/cloud/sandbox/fs/rmdir.ts +10 -5
  184. package/src/cmd/cloud/sandbox/fs/upload.ts +14 -8
  185. package/src/cmd/cloud/sandbox/get.ts +28 -7
  186. package/src/cmd/cloud/sandbox/job/create.ts +10 -4
  187. package/src/cmd/cloud/sandbox/job/destroy.ts +10 -4
  188. package/src/cmd/cloud/sandbox/job/get.ts +10 -4
  189. package/src/cmd/cloud/sandbox/job/list.ts +10 -4
  190. package/src/cmd/cloud/sandbox/job/logs.ts +11 -4
  191. package/src/cmd/cloud/sandbox/pause.ts +31 -5
  192. package/src/cmd/cloud/sandbox/resume.ts +10 -4
  193. package/src/cmd/cloud/sandbox/run.ts +49 -11
  194. package/src/cmd/cloud/sandbox/util.ts +63 -2
  195. package/src/cmd/coder/create.ts +24 -1
  196. package/src/cmd/coder/index.ts +4 -0
  197. package/src/cmd/coder/start.ts +63 -1
  198. package/src/cmd/coder/tui-init.ts +1 -1
  199. package/src/cmd/coder/update.ts +18 -1
  200. package/src/cmd/coder/workspace/create.ts +84 -15
  201. package/src/cmd/coder/workspace/index.ts +3 -1
  202. package/src/cmd/coder/workspace/list.ts +2 -2
  203. package/src/cmd/dev/dev-lock.ts +50 -16
  204. package/src/cmd/dev/index.ts +249 -134
  205. package/src/cmd/dev/process-manager.ts +173 -33
  206. package/src/cmd/project/create.ts +0 -2
  207. package/src/cmd/project/index.ts +0 -3
  208. package/src/cmd/project/template-flow.ts +0 -147
  209. package/dist/cmd/build/vite/public-asset-path-plugin.d.ts +0 -45
  210. package/dist/cmd/build/vite/public-asset-path-plugin.d.ts.map +0 -1
  211. package/dist/cmd/build/vite/public-asset-path-plugin.js +0 -166
  212. package/dist/cmd/build/vite/public-asset-path-plugin.js.map +0 -1
  213. package/dist/cmd/project/auth/generate.d.ts +0 -5
  214. package/dist/cmd/project/auth/generate.d.ts.map +0 -1
  215. package/dist/cmd/project/auth/generate.js +0 -102
  216. package/dist/cmd/project/auth/generate.js.map +0 -1
  217. package/dist/cmd/project/auth/index.d.ts +0 -2
  218. package/dist/cmd/project/auth/index.d.ts.map +0 -1
  219. package/dist/cmd/project/auth/index.js +0 -21
  220. package/dist/cmd/project/auth/index.js.map +0 -1
  221. package/dist/cmd/project/auth/init.d.ts +0 -2
  222. package/dist/cmd/project/auth/init.d.ts.map +0 -1
  223. package/dist/cmd/project/auth/init.js +0 -213
  224. package/dist/cmd/project/auth/init.js.map +0 -1
  225. package/dist/cmd/project/auth/shared.d.ts +0 -93
  226. package/dist/cmd/project/auth/shared.d.ts.map +0 -1
  227. package/dist/cmd/project/auth/shared.js +0 -475
  228. package/dist/cmd/project/auth/shared.js.map +0 -1
  229. package/src/cmd/build/vite/public-asset-path-plugin.ts +0 -209
  230. package/src/cmd/project/auth/generate.ts +0 -116
  231. package/src/cmd/project/auth/index.ts +0 -21
  232. package/src/cmd/project/auth/init.ts +0 -256
  233. package/src/cmd/project/auth/shared.ts +0 -591
@@ -7,6 +7,14 @@
7
7
  * - Graceful shutdown (SIGINT/SIGTERM)
8
8
  *
9
9
  * This prevents orphan processes and port conflicts between dev sessions.
10
+ *
11
+ * Key design decisions:
12
+ * - Process tree killing: Uses process.kill(-pid) to kill entire process groups,
13
+ * preventing orphaned child processes (e.g., Bun backend spawning workers).
14
+ * - Per-process SIGTERM→SIGKILL escalation: Each process gets its own grace
15
+ * period instead of waiting for all processes to exit before force-killing.
16
+ * - Last-resort synchronous cleanup: forceKillAllSync() can be called from
17
+ * process.on('exit') handlers where async operations are not possible.
10
18
  */
11
19
 
12
20
  import type { Logger } from '../../types';
@@ -39,6 +47,12 @@ export interface ManagedServer {
39
47
  description: string;
40
48
  /** The port this server uses */
41
49
  port?: number;
50
+ /**
51
+ * Maximum time (ms) to wait for this server's close() to resolve before
52
+ * moving on. Defaults to 1000ms. Servers like Vite that own filesystem
53
+ * watchers and HMR sockets may need more time.
54
+ */
55
+ closeTimeoutMs?: number;
42
56
  }
43
57
 
44
58
  /**
@@ -114,11 +128,71 @@ export class ProcessManager {
114
128
  return ports;
115
129
  }
116
130
 
131
+ /**
132
+ * Whether cleanup has already completed.
133
+ * Used by forceKillAllSync() to avoid redundant work.
134
+ */
135
+ get isCleanedUp(): boolean {
136
+ return this.cleaningUp && this.processes.length === 0 && this.servers.length === 0;
137
+ }
138
+
139
+ /**
140
+ * Kill a process and its entire process tree.
141
+ *
142
+ * Uses process.kill(-pid) to send the signal to the entire process group.
143
+ * This ensures child processes (e.g., workers spawned by Bun) are also killed.
144
+ * Falls back to direct PID kill if process group kill fails (e.g., EPERM or
145
+ * the process is not a group leader).
146
+ */
147
+ private killProcessTree(pid: number, signal: NodeJS.Signals): boolean {
148
+ // Safety: never send signals to PID 0 (own process group), PID 1 (init/systemd),
149
+ // or negative PIDs (which would be double-negated). process.kill(-1) is
150
+ // especially dangerous as it signals every process the user owns.
151
+ if (pid <= 1) {
152
+ this.logger.debug('Refusing to kill dangerous pid %d, skipping process tree kill', pid);
153
+ return false;
154
+ }
155
+
156
+ // Try killing the entire process group first (negative PID)
157
+ try {
158
+ process.kill(-pid, signal);
159
+ this.logger.debug('Sent %s to process group -%d', signal, pid);
160
+ return true;
161
+ } catch (err) {
162
+ const error = err as NodeJS.ErrnoException;
163
+ // ESRCH = no such process/group, EPERM = not a group leader or no permission
164
+ if (error.code !== 'ESRCH') {
165
+ this.logger.debug(
166
+ 'Process group kill failed for pid %d (%s), falling back to direct kill',
167
+ pid,
168
+ error.code
169
+ );
170
+ }
171
+ }
172
+
173
+ // Fall back to direct PID kill
174
+ try {
175
+ process.kill(pid, signal);
176
+ this.logger.debug('Sent %s to pid %d (direct)', signal, pid);
177
+ return true;
178
+ } catch (err) {
179
+ const error = err as NodeJS.ErrnoException;
180
+ if (error.code !== 'ESRCH') {
181
+ this.logger.debug('Direct kill failed for pid %d: %s', pid, error.code);
182
+ }
183
+ return false;
184
+ }
185
+ }
186
+
117
187
  /**
118
188
  * Clean up all tracked processes and servers.
119
189
  *
190
+ * Uses per-process SIGTERM→SIGKILL escalation: each process gets up to
191
+ * `timeout` ms to exit gracefully after SIGTERM. Processes that exit early
192
+ * don't delay cleanup of other processes.
193
+ *
120
194
  * @param reason - Why cleanup is happening (for logging)
121
- * @param timeout - Max time to wait for graceful shutdown (ms)
195
+ * @param timeout - Max time to wait for graceful shutdown per process (ms)
122
196
  */
123
197
  async cleanup(reason: string, timeout = 3000): Promise<void> {
124
198
  if (this.cleaningUp) {
@@ -129,61 +203,94 @@ export class ProcessManager {
129
203
 
130
204
  this.logger.debug('Starting cleanup (reason: %s)', reason);
131
205
 
132
- // Kill processes in reverse order (LIFO)
133
- for (let i = this.processes.length - 1; i >= 0; i--) {
134
- const proc = this.processes[i];
135
- if (!proc) continue;
136
-
137
- try {
138
- if (proc.process.exitCode === null) {
139
- this.logger.debug(
140
- 'Killing process %s (pid=%s)',
141
- proc.id,
142
- proc.process.pid ?? 'unknown'
143
- );
144
- proc.process.kill('SIGTERM');
145
- }
146
- } catch (err) {
147
- this.logger.debug('Error killing process %s: %s', proc.id, err);
148
- }
149
- }
206
+ // Snapshot processes and servers before cleanup so we can clear tracking
207
+ // lists early. This prevents the exit handler from re-killing already
208
+ // handled processes.
209
+ const processSnapshot = [...this.processes];
210
+ const serverSnapshot = [...this.servers];
150
211
 
151
- // Close servers
152
- for (let i = this.servers.length - 1; i >= 0; i--) {
153
- const server = this.servers[i];
212
+ // Close servers first (reverse order, LIFO)
213
+ for (let i = serverSnapshot.length - 1; i >= 0; i--) {
214
+ const server = serverSnapshot[i];
154
215
  if (!server) continue;
155
216
 
217
+ const closeTimeout = server.closeTimeoutMs ?? 1000;
156
218
  try {
157
- this.logger.debug('Closing server %s', server.id);
219
+ this.logger.debug('Closing server %s (timeout=%dms)', server.id, closeTimeout);
158
220
  const closePromise = server.server.close();
159
221
  if (closePromise instanceof Promise) {
222
+ let timedOut = false;
160
223
  await Promise.race([
161
224
  closePromise,
162
- new Promise<void>((resolve) => setTimeout(resolve, 1000)),
225
+ new Promise<void>((resolve) =>
226
+ setTimeout(() => {
227
+ timedOut = true;
228
+ resolve();
229
+ }, closeTimeout)
230
+ ),
163
231
  ]);
232
+ if (timedOut) {
233
+ this.logger.debug(
234
+ 'Server %s did not close within %dms, continuing cleanup',
235
+ server.id,
236
+ closeTimeout
237
+ );
238
+ }
164
239
  }
165
240
  } catch (err) {
166
241
  this.logger.debug('Error closing server %s: %s', server.id, err);
167
242
  }
168
243
  }
169
244
 
170
- // Wait for processes to exit, then force-kill if needed
245
+ // Send SIGTERM to all processes in reverse order (LIFO), targeting
246
+ // process trees so child processes also receive the signal.
247
+ for (let i = processSnapshot.length - 1; i >= 0; i--) {
248
+ const proc = processSnapshot[i];
249
+ if (!proc) continue;
250
+
251
+ try {
252
+ if (proc.process.exitCode === null) {
253
+ const pid = proc.process.pid;
254
+ this.logger.debug('Killing process %s (pid=%s)', proc.id, pid ?? 'unknown');
255
+ if (pid) {
256
+ this.killProcessTree(pid, 'SIGTERM');
257
+ } else {
258
+ proc.process.kill('SIGTERM');
259
+ }
260
+ }
261
+ } catch (err) {
262
+ this.logger.debug('Error killing process %s: %s', proc.id, err);
263
+ }
264
+ }
265
+
266
+ // Wait for processes to exit, then force-kill individually.
267
+ // Each process gets up to `timeout` ms from the initial SIGTERM.
171
268
  const startTime = Date.now();
172
269
  while (Date.now() - startTime < timeout) {
173
- const allExited = this.processes.every((p) => p.process.exitCode !== null);
270
+ const allExited = processSnapshot.every((p) => p.process.exitCode !== null);
174
271
  if (allExited) break;
175
272
  await new Promise((resolve) => setTimeout(resolve, 100));
176
273
  }
177
274
 
178
- // Force kill any remaining
179
- for (const proc of this.processes) {
180
- if (proc.process.exitCode === null) {
181
- try {
182
- this.logger.debug('Force killing process %s', proc.id);
275
+ // Force kill any remaining processes and their process trees.
276
+ // When a PID is available, always attempt process-group SIGKILL even if
277
+ // the leader has already exited: on Unix, process groups persist after
278
+ // the leader exits and signaling via negative PGID still reaches
279
+ // remaining members. killProcessTree() handles ESRCH gracefully.
280
+ for (const proc of processSnapshot) {
281
+ const pid = proc.process.pid;
282
+ const shouldForceTreeKill = typeof pid === 'number' && pid > 1;
283
+ if (!shouldForceTreeKill && proc.process.exitCode !== null) continue;
284
+
285
+ try {
286
+ this.logger.debug('Force killing process %s (pid=%s)', proc.id, pid ?? 'unknown');
287
+ if (shouldForceTreeKill) {
288
+ this.killProcessTree(pid, 'SIGKILL');
289
+ } else {
183
290
  proc.process.kill('SIGKILL');
184
- } catch (err) {
185
- this.logger.debug('Error force killing process %s: %s', proc.id, err);
186
291
  }
292
+ } catch (err) {
293
+ this.logger.debug('Error force killing process %s: %s', proc.id, err);
187
294
  }
188
295
  }
189
296
 
@@ -192,6 +299,39 @@ export class ProcessManager {
192
299
  this.servers = [];
193
300
  }
194
301
 
302
+ /**
303
+ * Synchronous last-resort cleanup for use in process.on('exit') handlers.
304
+ *
305
+ * Sends SIGKILL to all tracked process trees. This is intentionally
306
+ * aggressive because it's the final opportunity to prevent orphans.
307
+ * Only runs if async cleanup() hasn't already completed.
308
+ */
309
+ forceKillAllSync(): void {
310
+ if (this.isCleanedUp) return;
311
+
312
+ for (const proc of this.processes) {
313
+ if (proc.process.exitCode !== null) continue;
314
+ const pid = proc.process.pid;
315
+ try {
316
+ if (pid && pid > 1) {
317
+ // Try process group kill first, fall back to direct
318
+ try {
319
+ process.kill(-pid, 'SIGKILL');
320
+ } catch {
321
+ process.kill(pid, 'SIGKILL');
322
+ }
323
+ } else {
324
+ proc.process.kill('SIGKILL');
325
+ }
326
+ } catch {
327
+ // Best effort in exit handler — nothing else we can do
328
+ }
329
+ }
330
+
331
+ this.processes = [];
332
+ this.servers = [];
333
+ }
334
+
195
335
  /**
196
336
  * Verify that all ports used by tracked processes are released.
197
337
  * Used after cleanup to ensure no orphan processes remain.
@@ -80,7 +80,6 @@ export const createProjectSubcommand = createSubcommand({
80
80
  .string()
81
81
  .optional()
82
82
  .describe('Storage action: "skip", "new", or existing bucket name'),
83
- enableAuth: z.boolean().optional().describe('Enable Agentuity Auth'),
84
83
  }),
85
84
  response: ProjectCreateResponseSchema,
86
85
  },
@@ -115,7 +114,6 @@ export const createProjectSubcommand = createSubcommand({
115
114
  region,
116
115
  database: opts.database,
117
116
  storage: opts.storage,
118
- enableAuth: opts.enableAuth,
119
117
  });
120
118
 
121
119
  // Exit with error code if setup failed and not in JSON mode
@@ -4,7 +4,6 @@ import { importSubcommand } from './import';
4
4
  import { listSubcommand } from './list';
5
5
  import { deleteSubcommand } from './delete';
6
6
  import { showSubcommand } from './show';
7
- import { authCommand } from './auth';
8
7
  import { addCommand } from './add';
9
8
  import { hostnameCommand } from './hostname';
10
9
  import { domainCommand } from './domain';
@@ -18,7 +17,6 @@ export const command = createCommand({
18
17
  { command: getCommand('project create my-agent'), description: 'Create a new project' },
19
18
  { command: getCommand('project import'), description: 'Import an existing project' },
20
19
  { command: getCommand('project list'), description: 'List all projects' },
21
- { command: getCommand('project auth init'), description: 'Set up Agentuity Auth' },
22
20
  { command: getCommand('project add database'), description: 'Link an existing database' },
23
21
  {
24
22
  command: getCommand('project add storage'),
@@ -39,7 +37,6 @@ export const command = createCommand({
39
37
  listSubcommand,
40
38
  deleteSubcommand,
41
39
  showSubcommand,
42
- authCommand,
43
40
  addCommand,
44
41
  hostnameCommand,
45
42
  domainCommand,
@@ -31,13 +31,6 @@ 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';
42
35
  import { fetchTemplates, type TemplateInfo } from './templates';
43
36
 
@@ -59,7 +52,6 @@ interface CreateFlowOptions {
59
52
  apiClient?: APIClient;
60
53
  database?: string;
61
54
  storage?: string;
62
- enableAuth?: boolean;
63
55
  }
64
56
 
65
57
  export interface CreateFlowResult {
@@ -92,7 +84,6 @@ export async function runCreateFlow(options: CreateFlowOptions): Promise<CreateF
92
84
  domains,
93
85
  database: databaseOption,
94
86
  storage: storageOption,
95
- enableAuth: enableAuthOption,
96
87
  } = options;
97
88
 
98
89
  const isHeadless = !process.stdin.isTTY || !process.stdout.isTTY;
@@ -314,15 +305,6 @@ export async function runCreateFlow(options: CreateFlowOptions): Promise<CreateF
314
305
  );
315
306
  }
316
307
 
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
308
  if (canProvision) {
327
309
  // Fetch resources for selected org and region using Catalyst API (needed for both interactive and CLI flags)
328
310
  let resources: Awaited<ReturnType<typeof listResources>> | undefined;
@@ -556,111 +538,6 @@ export async function runCreateFlow(options: CreateFlowOptions): Promise<CreateF
556
538
  }
557
539
  }
558
540
 
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
- }
625
- }
626
- }
627
-
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,
660
- });
661
- }
662
- }
663
-
664
541
  let projectId: string | undefined;
665
542
 
666
543
  if (auth && apiClient && orgId) {
@@ -702,28 +579,9 @@ export async function runCreateFlow(options: CreateFlowOptions): Promise<CreateF
702
579
  },
703
580
  });
704
581
 
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
582
  // Write resource environment variables to .env
712
583
  if (Object.keys(resourceEnvVars).length > 0) {
713
584
  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
585
  }
728
586
 
729
587
  // After registration, push any existing env/secrets from .env
@@ -819,11 +677,6 @@ export async function runCreateFlow(options: CreateFlowOptions): Promise<CreateF
819
677
  }
820
678
  }
821
679
 
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
680
  return {
828
681
  projectId,
829
682
  orgId,
@@ -1,45 +0,0 @@
1
- /**
2
- * Vite plugin to fix incorrect public asset paths
3
- *
4
- * Developers should use /public/ paths for static assets from src/web/public/.
5
- * In production, these paths are transformed to CDN URLs.
6
- *
7
- * This plugin:
8
- * 1. During build: Rewrites /public/* paths to CDN URLs
9
- * 2. During dev: Warns only about incorrect source paths (src/web/public/)
10
- *
11
- * Supported patterns (work in dev, rewritten to CDN in production):
12
- * - '/public/foo.svg' → CDN URL (recommended)
13
- * - './public/foo.svg' → CDN URL
14
- * - 'url(/public/foo.svg)' → CDN URL (CSS unquoted)
15
- * - 'url(./public/foo.svg)' → CDN URL (CSS unquoted)
16
- *
17
- * Incorrect patterns (warned in dev, rewritten in production):
18
- * - '/src/web/public/foo.svg' → CDN URL
19
- * - './src/web/public/foo.svg' → CDN URL
20
- * - 'src/web/public/foo.svg' → CDN URL
21
- */
22
- import type { Plugin } from 'vite';
23
- export interface PublicAssetPathPluginOptions {
24
- /** Whether to show warnings in dev mode (default: true) */
25
- warnInDev?: boolean;
26
- /** CDN base URL for production builds (e.g., 'https://cdn.agentuity.com/{deploymentId}/client/') */
27
- cdnBaseUrl?: string;
28
- }
29
- /**
30
- * Vite plugin that fixes public asset paths and rewrites to CDN URLs
31
- *
32
- * Rewrites all public asset paths to CDN URLs in production.
33
- *
34
- * @example
35
- * // In vite config:
36
- * plugins: [publicAssetPathPlugin({ cdnBaseUrl: 'https://cdn.example.com/deploy/client/' })]
37
- *
38
- * // In code, use /public/ paths:
39
- * <img src="/public/logo.svg" />
40
- *
41
- * // Transforms in production:
42
- * // '/public/logo.svg' → 'https://cdn.example.com/deploy/client/logo.svg'
43
- */
44
- export declare function publicAssetPathPlugin(options?: PublicAssetPathPluginOptions): Plugin;
45
- //# sourceMappingURL=public-asset-path-plugin.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"public-asset-path-plugin.d.ts","sourceRoot":"","sources":["../../../../src/cmd/build/vite/public-asset-path-plugin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAEnC,MAAM,WAAW,4BAA4B;IAC5C,2DAA2D;IAC3D,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,oGAAoG;IACpG,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB;AAwDD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,GAAE,4BAAiC,GAAG,MAAM,CA4GxF"}