@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
@@ -260,27 +260,52 @@ export function App() {
260
260
 
261
261
  ## Static Assets
262
262
 
263
- Place static files in the **public/** folder:
263
+ Agentuity uses the standard Vite asset conventions. There are two ways to
264
+ reference static files:
265
+
266
+ ### Import the asset (recommended for JS/TSX)
267
+
268
+ For anything referenced from a component, `import` the file. Vite emits a
269
+ content-hashed copy at build time and replaces the import with the final URL
270
+ (including the production CDN when deployed):
271
+
272
+ ```typescript
273
+ import logoUrl from './assets/logo.svg';
274
+
275
+ export function Header() {
276
+ return <img src={logoUrl} alt="Logo" />;
277
+ }
278
+ ```
279
+
280
+ This works for images, fonts, videos, JSON, and any other static file type
281
+ Vite understands. Because the filename is hashed, the browser can cache it
282
+ forever and the CDN serves it from the edge.
283
+
284
+ ### Use `publicDir` (for HTML-referenced files and root-served assets)
285
+
286
+ Files under `src/web/public/` are copied to the build root as-is and served
287
+ at the URL root — **without** a `/public/` prefix. Use this for files that
288
+ must live at a specific URL (e.g. `robots.txt`, `favicon.ico`, a PWA
289
+ `manifest.json`) or that are referenced from `index.html`:
264
290
 
265
291
  ```
266
292
  src/web/public/
267
- ├── logo.svg
268
- ├── styles.css
269
- └── script.js
293
+ ├── favicon.ico → served at /favicon.ico
294
+ ├── robots.txt → served at /robots.txt
295
+ └── styles.css → served at /styles.css
270
296
  ```
271
297
 
272
- Reference them in your HTML or components:
273
-
274
298
  ```html
275
- <!-- In index.html -->
276
- <link rel="stylesheet" href="/public/styles.css" />
277
- <script src="/public/script.js"></script>
299
+ <!-- In index.html — Vite rewrites root paths to the CDN in production -->
300
+ <link rel="stylesheet" href="/styles.css" />
301
+ <script src="/script.js"></script>
302
+ <link rel="icon" href="/favicon.ico" />
278
303
  ```
279
304
 
280
- ```typescript
281
- // In React components
282
- <img src="/public/logo.svg" alt="Logo" />
283
- ```
305
+ > **Do not** use a `/public/` prefix (e.g. `/public/logo.svg`). That path
306
+ > is not served and will 404 in production. This is enforced by a build-time
307
+ > lint — the build fails if `/public/...` or `src/web/public/...` appears in
308
+ > any string literal under `src/web/`.
284
309
 
285
310
  ## Styling
286
311
 
@@ -294,7 +319,7 @@ Reference them in your HTML or components:
294
319
 
295
320
  ### CSS Files
296
321
 
297
- Create `public/styles.css`:
322
+ Create `src/web/public/styles.css`:
298
323
 
299
324
  ```css
300
325
  body {
@@ -307,7 +332,7 @@ body {
307
332
  Import in `index.html`:
308
333
 
309
334
  ```html
310
- <link rel="stylesheet" href="/public/styles.css" />
335
+ <link rel="stylesheet" href="/styles.css" />
311
336
  ```
312
337
 
313
338
  ### Style Tag in Component
@@ -334,7 +359,7 @@ Import in `index.html`:
334
359
  - Use **useAuth** for authentication state management
335
360
  - Handle loading and error states in UI
336
361
  - Place reusable components in separate files
337
- - Keep static assets in the **public/** folder
362
+ - Put assets in `src/web/public/` (for root-served files) or alongside your components (for imported files)
338
363
 
339
364
  ## Rules
340
365
 
@@ -343,5 +368,6 @@ Import in `index.html`:
343
368
  - **index.html** must have a `<div id="root"></div>`
344
369
  - Route types are derived from your Hono router via `hc<typeof router>()`
345
370
  - The web app is served at `/` by default
346
- - Static files in `public/` are served at `/public/*`
371
+ - Files in `src/web/public/` are served at the URL root (`/filename`, **not** `/public/filename`)
372
+ - For assets referenced from JS/TSX, use `import url from './path.svg'` — never a string literal like `/public/foo.svg`
347
373
  - Module script tag: `<script type="module" src="/web/frontend.tsx"></script>`
@@ -17,14 +17,35 @@ import type { Logger } from '../../../types';
17
17
  import { getAgentEnv } from '../../../agent-detection';
18
18
  import { createServer as createNetServer } from 'node:net';
19
19
 
20
+ /**
21
+ * Minimal handle for the spawned Bun subprocess. Mirrors the shape used
22
+ * elsewhere (procManager, killBunSubprocess) so callers can register
23
+ * the process with their tracking layer without depending on Bun-specific
24
+ * Subprocess types.
25
+ */
26
+ export interface BunSubprocessHandle {
27
+ kill: (signal?: number | NodeJS.Signals) => void;
28
+ exitCode: number | null;
29
+ pid?: number;
30
+ }
31
+
20
32
  export interface BunDevServerOptions {
21
33
  rootDir: string;
22
34
  port?: number;
23
35
  logger: Logger;
24
- vitePort: number;
36
+ vitePort: number; // Kept for backward compatibility — no longer used internally
25
37
  inspect?: boolean;
26
38
  inspectWait?: boolean;
27
39
  inspectBrk?: boolean;
40
+ /**
41
+ * Optional callback fired the moment `Bun.spawn` returns, BEFORE the
42
+ * readiness wait. Lets callers register the subprocess with a process
43
+ * manager / shutdown handler immediately, eliminating the multi-second
44
+ * window during which a SIGINT could orphan the child.
45
+ *
46
+ * If this throws, the subprocess is killed and the error is rethrown.
47
+ */
48
+ onSpawn?: (proc: BunSubprocessHandle) => void;
28
49
  }
29
50
 
30
51
  export interface BunDevServerResult {
@@ -311,9 +332,17 @@ export function buildStartupErrorMessage(
311
332
  * are re-evaluated.
312
333
  */
313
334
  export async function startBunDevServer(options: BunDevServerOptions): Promise<BunDevServerResult> {
314
- const { rootDir, port = 3500, logger, vitePort, inspect, inspectWait, inspectBrk } = options;
315
-
316
- logger.debug('Starting Bun dev server (Vite already running on port %d)...', vitePort);
335
+ const {
336
+ rootDir,
337
+ port = 3500,
338
+ logger,
339
+ vitePort: _vitePort,
340
+ inspect,
341
+ inspectWait,
342
+ inspectBrk,
343
+ } = options;
344
+
345
+ logger.debug('Starting Bun dev server (port %d)...', port);
317
346
 
318
347
  const appPath = `${rootDir}/app.ts`;
319
348
 
@@ -391,6 +420,15 @@ export async function startBunDevServer(options: BunDevServerOptions): Promise<B
391
420
  PORT: String(port),
392
421
  FORCE_COLOR: '1', // Enable colors even though stdout is piped
393
422
  },
423
+ // Make the child a process-group leader so the CLI's procManager /
424
+ // killBunSubprocess() can signal the whole tree via process.kill(-pid, ...).
425
+ // Without detached:true, bun --hot and any workers it spawns share our
426
+ // process group, process.kill(-pid) fails with EPERM (not a group leader),
427
+ // and we fall back to a direct PID kill that leaves children orphaned.
428
+ //
429
+ // We intentionally do NOT call .unref() here — the parent still tracks
430
+ // and drives the child's lifecycle, and piped stdio is unaffected.
431
+ detached: true,
394
432
  });
395
433
 
396
434
  // Start capturing streams in the background (don't await, we need to check server readiness)
@@ -404,6 +442,35 @@ export async function startBunDevServer(options: BunDevServerOptions): Promise<B
404
442
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
405
443
  (globalThis as any).__AGENTUITY_BUN_SUBPROCESS__ = bunProcess;
406
444
 
445
+ // Notify caller IMMEDIATELY so the subprocess can be registered with the
446
+ // process manager before the readiness wait below. Without this, a SIGINT
447
+ // during the up-to-5s readiness wait would leave the subprocess unmanaged
448
+ // (only the synchronous exit-handler safety net would catch it).
449
+ if (options.onSpawn) {
450
+ try {
451
+ options.onSpawn(bunProcess as BunSubprocessHandle);
452
+ } catch (err) {
453
+ logger.debug('onSpawn callback threw, killing subprocess: %s', err);
454
+ const pid = bunProcess.pid;
455
+ try {
456
+ if (typeof pid === 'number' && pid > 1 && process.platform !== 'win32') {
457
+ try {
458
+ process.kill(-pid, 'SIGKILL');
459
+ } catch {
460
+ bunProcess.kill('SIGKILL');
461
+ }
462
+ } else {
463
+ bunProcess.kill('SIGKILL');
464
+ }
465
+ } catch {
466
+ // Best effort
467
+ }
468
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
469
+ (globalThis as any).__AGENTUITY_BUN_SUBPROCESS__ = undefined;
470
+ throw err;
471
+ }
472
+ }
473
+
407
474
  // Wait for server to start listening
408
475
  const maxRetries = 50;
409
476
  const retryDelay = 100;
@@ -436,8 +503,28 @@ export async function startBunDevServer(options: BunDevServerOptions): Promise<B
436
503
  }
437
504
 
438
505
  if (!serverReady) {
506
+ // The subprocess is spawned with detached:true and is therefore the
507
+ // leader of its own process group. bunProcess.kill() only targets the
508
+ // direct PID, which would leave any workers/grandchildren orphaned.
509
+ // Signal the whole process group with SIGKILL and fall back to the
510
+ // handle's kill() if the group-kill fails (EPERM, not-group-leader,
511
+ // or Windows where negative PIDs aren't supported).
512
+ const pid = bunProcess.pid;
439
513
  try {
440
- bunProcess.kill();
514
+ if (typeof pid === 'number' && pid > 1 && process.platform !== 'win32') {
515
+ try {
516
+ process.kill(-pid, 'SIGKILL');
517
+ } catch (groupErr) {
518
+ logger.debug(
519
+ 'Process-group SIGKILL failed for pid %d (%s), falling back to direct kill',
520
+ pid,
521
+ (groupErr as NodeJS.ErrnoException).code ?? groupErr
522
+ );
523
+ bunProcess.kill('SIGKILL');
524
+ }
525
+ } else {
526
+ bunProcess.kill('SIGKILL');
527
+ }
441
528
  } catch (err) {
442
529
  logger.debug('Error killing subprocess during startup failure: %s', err);
443
530
  }
@@ -452,7 +539,6 @@ export async function startBunDevServer(options: BunDevServerOptions): Promise<B
452
539
  }
453
540
 
454
541
  logger.debug(`Bun dev server started on http://127.0.0.1:${port} (--hot mode)`);
455
- logger.debug(`Proxied to Vite:${vitePort}`);
456
542
 
457
543
  return { bunServerPort: port };
458
544
  }
@@ -1,3 +1,2 @@
1
1
  // Re-export plugins for direct use in vite.config.ts
2
2
  export { browserEnvPlugin } from './browser-env-plugin';
3
- export { publicAssetPathPlugin } from './public-asset-path-plugin';
@@ -18,7 +18,7 @@ import { mkdirSync, writeFileSync, readFileSync, existsSync, rmSync } from 'node
18
18
  import type { Logger } from '../../../types';
19
19
 
20
20
  /** Minimal shape of a TanStack Router route tree node. */
21
- interface RouteTreeNode {
21
+ export interface RouteTreeNode {
22
22
  path?: string;
23
23
  options?: { path?: string };
24
24
  children?: Record<string, RouteTreeNode>;
@@ -32,7 +32,7 @@ interface RouteTreeNode {
32
32
  * under layout routes have relative paths (e.g., '/key-value' under a
33
33
  * '/reference/api' layout should resolve to '/reference/api/key-value').
34
34
  */
35
- function extractRoutePaths(node: RouteTreeNode): string[] {
35
+ export function extractRoutePaths(node: RouteTreeNode): string[] {
36
36
  const paths = new Set<string>();
37
37
 
38
38
  function walk(route: RouteTreeNode, parentPath: string) {
@@ -40,18 +40,29 @@ function extractRoutePaths(node: RouteTreeNode): string[] {
40
40
 
41
41
  // Build the full path by accumulating segments from parent routes.
42
42
  // - Layout routes have no path (undefined) and don't contribute to the URL.
43
- // - Index routes have path '/' and resolve to the parent path itself.
43
+ // - Index routes have path '/' and resolve to the parent path itself
44
+ // (e.g., the '/' child of the root is the landing page; the '/' child
45
+ // of a '/docs' layout is '/docs'). They do not append anything.
44
46
  // - Leaf/layout routes have paths like '/reference/api' or '/key-value'.
45
47
  let currentPath = parentPath;
46
- if (segment && segment !== '/') {
48
+ let isIndexRoute = false;
49
+ if (segment === '/') {
50
+ isIndexRoute = true;
51
+ } else if (segment) {
47
52
  // Non-root segment: append to parent path.
48
53
  // Segments always start with '/' (TanStack Router convention).
49
54
  currentPath = parentPath === '/' ? segment : parentPath + segment;
50
55
  }
51
56
 
52
- // Add non-parameterized, non-empty paths
53
- if (currentPath && !currentPath.includes('$')) {
54
- const normalized = currentPath === '/' ? '/' : currentPath.replace(/\/+$/, '');
57
+ // Decide which URL, if any, to emit for this node.
58
+ // - Index routes emit the parent URL, defaulting to '/' when the parent
59
+ // itself is pathless (i.e., the site root). Without this, a
60
+ // `createFileRoute('/')` route is never pre-rendered and the
61
+ // landing page ships with the unreplaced <!--app-html--> placeholder.
62
+ // - Non-index routes emit their own accumulated path.
63
+ const emit = isIndexRoute ? parentPath || '/' : currentPath;
64
+ if (emit && !emit.includes('$')) {
65
+ const normalized = emit === '/' ? '/' : emit.replace(/\/+$/, '');
55
66
  if (normalized) {
56
67
  paths.add(normalized);
57
68
  }
@@ -22,6 +22,37 @@ export interface GenerateAssetServerConfigOptions {
22
22
  liveHostname?: string;
23
23
  }
24
24
 
25
+ /**
26
+ * Shared proxy configuration for backend routes.
27
+ *
28
+ * Includes `configure` callback that gracefully handles ECONNREFUSED errors
29
+ * when the Bun backend isn't ready yet (startup race condition or brief
30
+ * disconnect during --hot reload). Instead of logging noisy errors, the
31
+ * proxy returns 503 Service Unavailable with a retry hint.
32
+ */
33
+ function backendProxyOptions(backendPort: number) {
34
+ return {
35
+ target: `http://127.0.0.1:${backendPort}`,
36
+ changeOrigin: true,
37
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
38
+ configure: (proxy: any, _options: any) => {
39
+ proxy.on('error', (err: Error & { code?: string }, _req: any, res: any) => {
40
+ if (err.code === 'ECONNREFUSED' && res && !res.writableEnded) {
41
+ res.statusCode = 503;
42
+ res.setHeader('Content-Type', 'application/json');
43
+ res.end(
44
+ JSON.stringify({
45
+ error: 'Backend unavailable',
46
+ message: 'The Bun backend is not ready yet. Retrying shortly...',
47
+ retry: true,
48
+ })
49
+ );
50
+ }
51
+ });
52
+ },
53
+ };
54
+ }
55
+
25
56
  /**
26
57
  * Vite plugin that injects analytics scripts in dev mode.
27
58
  *
@@ -95,7 +126,7 @@ function spaFallbackPlugin(rootDir: string, routePaths: string[], workbenchPath?
95
126
  const isDocumentRequest = secFetchDest === 'document' || accept.includes('text/html');
96
127
 
97
128
  // Skip file requests (have an extension)
98
- if (pathname !== '/' && /\.[a-zA-Z0-9]+$/.test(pathname)) return next();
129
+ if (pathname !== '/' && /\.[\w-]+$/.test(pathname)) return next();
99
130
 
100
131
  // For non-document requests, only allow root path fallback.
101
132
  // (e.g. don't turn module/script fetches into HTML accidentally)
@@ -241,37 +272,19 @@ export async function generateAssetServerConfig(
241
272
  proxy: {
242
273
  // User-defined route mounts (from createApp({ router }))
243
274
  ...Object.fromEntries(
244
- routePaths.map((routePath) => [
245
- routePath,
246
- {
247
- target: `http://127.0.0.1:${backendPort}`,
248
- changeOrigin: true,
249
- },
250
- ])
275
+ routePaths.map((routePath) => [routePath, backendProxyOptions(backendPort)])
251
276
  ),
252
277
  // Agentuity system routes (workbench API, health, analytics, etc.)
253
- '/_agentuity': {
254
- target: `http://127.0.0.1:${backendPort}`,
255
- changeOrigin: true,
256
- },
278
+ '/_agentuity': backendProxyOptions(backendPort),
257
279
  // Workbench UI route (served by Bun, references /@fs/* paths handled by Vite)
258
280
  ...(workbenchPath
259
281
  ? {
260
- [workbenchPath]: {
261
- target: `http://127.0.0.1:${backendPort}`,
262
- changeOrigin: true,
263
- },
282
+ [workbenchPath]: backendProxyOptions(backendPort),
264
283
  }
265
284
  : {}),
266
285
  // Legacy health check routes
267
- '/_health': {
268
- target: `http://127.0.0.1:${backendPort}`,
269
- changeOrigin: true,
270
- },
271
- '/_idle': {
272
- target: `http://127.0.0.1:${backendPort}`,
273
- changeOrigin: true,
274
- },
286
+ '/_health': backendProxyOptions(backendPort),
287
+ '/_idle': backendProxyOptions(backendPort),
275
288
  },
276
289
 
277
290
  // HMR works natively — Vite is the primary server, no proxy needed
@@ -296,13 +309,10 @@ export async function generateAssetServerConfig(
296
309
  // Agentuity-specific plugins (Vite loads user plugins from vite.config.ts automatically)
297
310
  plugins: await (async () => {
298
311
  const { browserEnvPlugin } = await import('./browser-env-plugin');
299
- const { publicAssetPathPlugin } = await import('./public-asset-path-plugin');
300
312
 
301
313
  return [
302
314
  // Browser env plugin to map process.env to import.meta.env
303
315
  browserEnvPlugin(),
304
- // Warn about incorrect public asset paths in dev mode
305
- publicAssetPathPlugin({ warnInDev: true }),
306
316
  // Inject analytics scripts in dev HTML
307
317
  devAnalyticsPlugin(),
308
318
  // SPA fallback: serve src/web/index.html for navigation requests
@@ -50,8 +50,12 @@ function isPortAvailable(port: number, host: string): Promise<boolean> {
50
50
  /**
51
51
  * Find an available port starting from the preferred port.
52
52
  * Tries incrementing ports up to maxAttempts times.
53
+ *
54
+ * Exported so the dev command can pre-resolve the Vite port before
55
+ * starting the Bun backend (env vars like AGENTUITY_BASE_URL need
56
+ * the real port before Bun initializes CORS).
53
57
  */
54
- async function findAvailablePort(
58
+ export async function findAvailablePort(
55
59
  preferredPort: number,
56
60
  host: string = '127.0.0.1',
57
61
  maxAttempts: number = 20
@@ -227,6 +227,7 @@ import { join } from 'node:path';
227
227
  export default defineConfig({
228
228
  plugins: [react()],
229
229
  root: '.',
230
+ publicDir: 'src/web/public',
230
231
  build: {
231
232
  rollupOptions: {
232
233
  input: join(__dirname, 'src/web/index.html'),
@@ -244,17 +245,27 @@ export default defineConfig({
244
245
  ? `https://${options.region === 'local' ? 'localstack-static-assets.t3.storageapi.dev' : 'cdn.agentuity.com'}/${options.deploymentId}/client/`
245
246
  : undefined;
246
247
 
248
+ // Pass the user's vite.config.ts directly to the subprocess. We used to
249
+ // wrap it in an auto-generated `.agentuity/vite.client.config.ts` to
250
+ // merge a lint plugin in, but that wrapper added complexity (plugin-path
251
+ // resolution, a junk file in the deploy bundle) for a warning-only
252
+ // linter. If we need to inject plugins again, expose them as a published
253
+ // CLI export and have users add them in their own vite.config.ts.
247
254
  const args = [
248
255
  'bun',
249
256
  'x',
250
257
  'vite',
251
258
  'build',
259
+ '--config',
260
+ viteConfigPath,
252
261
  '--mode',
253
262
  buildMode,
254
263
  '--outDir',
255
264
  clientOutDir,
265
+ // `warn` surfaces Vite warnings (e.g. large-chunk notices) without
266
+ // adding its own info-level chatter.
256
267
  '--logLevel',
257
- 'error',
268
+ 'warn',
258
269
  '--clearScreen',
259
270
  'false',
260
271
  ];
@@ -33,7 +33,7 @@
33
33
  * ```
34
34
  */
35
35
 
36
- import { createServer, connect, type Server } from 'node:net';
36
+ import { createServer, connect, type Server, type Socket } from 'node:net';
37
37
  import type { Logger } from '../../../types';
38
38
 
39
39
  export interface WsProxyOptions {
@@ -48,18 +48,44 @@ export interface WsProxyOptions {
48
48
  logger: Logger;
49
49
  }
50
50
 
51
+ /**
52
+ * Front-door TCP proxy server.
53
+ *
54
+ * Extends `net.Server` with a `closeAll()` method that destroys all live
55
+ * client + upstream sockets and waits for the listening socket to close.
56
+ * The native `Server.close()` only stops accepting new connections — long-
57
+ * lived piped sockets (Vite HMR WebSocket, backend WS) keep the listener
58
+ * bound until they close on their own. During dev-mode shutdown we want
59
+ * the user-facing port released immediately, so cleanup paths should
60
+ * prefer `closeAll()` over `close()`.
61
+ */
62
+ export interface WsProxyServer extends Server {
63
+ closeAll(): Promise<void>;
64
+ }
65
+
51
66
  /**
52
67
  * Start a front-door TCP proxy that routes WebSocket upgrades to the Bun
53
68
  * backend and everything else to Vite. Returns the `net.Server` instance.
54
69
  */
55
- export function startWsProxy(options: WsProxyOptions): Promise<Server> {
70
+ export function startWsProxy(options: WsProxyOptions): Promise<WsProxyServer> {
56
71
  const { port, vitePort, backendPort, routePaths, logger } = options;
57
72
 
58
73
  // Prefixes whose WebSocket upgrades go to Bun instead of Vite
59
74
  const wsPathPrefixes = ['/_agentuity', ...routePaths];
60
75
 
76
+ // Track every live socket pair so shutdown can drop them. Without this,
77
+ // `server.close()` waits for active connections to terminate by themselves
78
+ // (e.g. browser HMR WebSockets), which can keep the user-facing port bound
79
+ // for many seconds after dev mode exits.
80
+ const liveSockets = new Set<Socket>();
81
+ const trackSocket = (sock: Socket) => {
82
+ liveSockets.add(sock);
83
+ sock.once('close', () => liveSockets.delete(sock));
84
+ };
85
+
61
86
  return new Promise((resolve, reject) => {
62
87
  const server = createServer((socket) => {
88
+ trackSocket(socket);
63
89
  let handled = false;
64
90
 
65
91
  // Peek at the first chunk to decide where to route
@@ -87,6 +113,7 @@ export function startWsProxy(options: WsProxyOptions): Promise<Server> {
87
113
  }
88
114
 
89
115
  const target = connect(targetPort, '127.0.0.1');
116
+ trackSocket(target);
90
117
 
91
118
  target.on('connect', () => {
92
119
  target.write(firstChunk);
@@ -109,7 +136,29 @@ export function startWsProxy(options: WsProxyOptions): Promise<Server> {
109
136
  socket.on('error', () => {
110
137
  if (!handled) socket.destroy();
111
138
  });
112
- });
139
+ }) as WsProxyServer;
140
+
141
+ // Async close that destroys live sockets first, then waits for the
142
+ // listener to close. Idempotent: safe to call after the server has
143
+ // already been closed by other means.
144
+ server.closeAll = () => {
145
+ return new Promise<void>((resolveClose) => {
146
+ for (const sock of liveSockets) {
147
+ try {
148
+ if (!sock.destroyed) sock.destroy();
149
+ } catch {
150
+ // Best effort
151
+ }
152
+ }
153
+ liveSockets.clear();
154
+
155
+ if (!server.listening) {
156
+ resolveClose();
157
+ return;
158
+ }
159
+ server.close(() => resolveClose());
160
+ });
161
+ };
113
162
 
114
163
  server.on('error', reject);
115
164