@agentuity/cli 1.0.59 → 2.0.0-beta.1

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 (189) hide show
  1. package/bin/cli.ts +2 -3
  2. package/dist/cmd/build/app-config-extractor.d.ts +27 -0
  3. package/dist/cmd/build/app-config-extractor.d.ts.map +1 -0
  4. package/dist/cmd/build/app-config-extractor.js +152 -0
  5. package/dist/cmd/build/app-config-extractor.js.map +1 -0
  6. package/dist/cmd/build/app-router-detector.d.ts +2 -5
  7. package/dist/cmd/build/app-router-detector.d.ts.map +1 -1
  8. package/dist/cmd/build/app-router-detector.js +130 -154
  9. package/dist/cmd/build/app-router-detector.js.map +1 -1
  10. package/dist/cmd/build/ci.d.ts.map +1 -1
  11. package/dist/cmd/build/ci.js +5 -21
  12. package/dist/cmd/build/ci.js.map +1 -1
  13. package/dist/cmd/build/ids.d.ts +11 -0
  14. package/dist/cmd/build/ids.d.ts.map +1 -0
  15. package/dist/cmd/build/ids.js +18 -0
  16. package/dist/cmd/build/ids.js.map +1 -0
  17. package/dist/cmd/build/index.d.ts.map +1 -1
  18. package/dist/cmd/build/index.js +8 -0
  19. package/dist/cmd/build/index.js.map +1 -1
  20. package/dist/cmd/build/vite/agent-discovery.d.ts +8 -4
  21. package/dist/cmd/build/vite/agent-discovery.d.ts.map +1 -1
  22. package/dist/cmd/build/vite/agent-discovery.js +166 -487
  23. package/dist/cmd/build/vite/agent-discovery.js.map +1 -1
  24. package/dist/cmd/build/vite/bun-dev-server.d.ts +43 -14
  25. package/dist/cmd/build/vite/bun-dev-server.d.ts.map +1 -1
  26. package/dist/cmd/build/vite/bun-dev-server.js +290 -129
  27. package/dist/cmd/build/vite/bun-dev-server.js.map +1 -1
  28. package/dist/cmd/build/vite/config-loader.d.ts +15 -20
  29. package/dist/cmd/build/vite/config-loader.d.ts.map +1 -1
  30. package/dist/cmd/build/vite/config-loader.js +41 -74
  31. package/dist/cmd/build/vite/config-loader.js.map +1 -1
  32. package/dist/cmd/build/vite/docs-generator.d.ts.map +1 -1
  33. package/dist/cmd/build/vite/docs-generator.js +0 -2
  34. package/dist/cmd/build/vite/docs-generator.js.map +1 -1
  35. package/dist/cmd/build/vite/index.d.ts.map +1 -1
  36. package/dist/cmd/build/vite/index.js +0 -36
  37. package/dist/cmd/build/vite/index.js.map +1 -1
  38. package/dist/cmd/build/vite/lifecycle-generator.d.ts +10 -2
  39. package/dist/cmd/build/vite/lifecycle-generator.d.ts.map +1 -1
  40. package/dist/cmd/build/vite/lifecycle-generator.js +302 -23
  41. package/dist/cmd/build/vite/lifecycle-generator.js.map +1 -1
  42. package/dist/cmd/build/vite/route-discovery.d.ts +11 -38
  43. package/dist/cmd/build/vite/route-discovery.d.ts.map +1 -1
  44. package/dist/cmd/build/vite/route-discovery.js +97 -177
  45. package/dist/cmd/build/vite/route-discovery.js.map +1 -1
  46. package/dist/cmd/build/vite/server-bundler.js +1 -1
  47. package/dist/cmd/build/vite/server-bundler.js.map +1 -1
  48. package/dist/cmd/build/vite/static-renderer.d.ts +0 -2
  49. package/dist/cmd/build/vite/static-renderer.d.ts.map +1 -1
  50. package/dist/cmd/build/vite/static-renderer.js +19 -13
  51. package/dist/cmd/build/vite/static-renderer.js.map +1 -1
  52. package/dist/cmd/build/vite/vite-asset-server-config.d.ts +6 -3
  53. package/dist/cmd/build/vite/vite-asset-server-config.d.ts.map +1 -1
  54. package/dist/cmd/build/vite/vite-asset-server-config.js +175 -69
  55. package/dist/cmd/build/vite/vite-asset-server-config.js.map +1 -1
  56. package/dist/cmd/build/vite/vite-asset-server.d.ts +8 -3
  57. package/dist/cmd/build/vite/vite-asset-server.d.ts.map +1 -1
  58. package/dist/cmd/build/vite/vite-asset-server.js +14 -13
  59. package/dist/cmd/build/vite/vite-asset-server.js.map +1 -1
  60. package/dist/cmd/build/vite/vite-builder.d.ts.map +1 -1
  61. package/dist/cmd/build/vite/vite-builder.js +42 -190
  62. package/dist/cmd/build/vite/vite-builder.js.map +1 -1
  63. package/dist/cmd/build/vite/ws-proxy.d.ts +53 -0
  64. package/dist/cmd/build/vite/ws-proxy.d.ts.map +1 -0
  65. package/dist/cmd/build/vite/ws-proxy.js +95 -0
  66. package/dist/cmd/build/vite/ws-proxy.js.map +1 -0
  67. package/dist/cmd/build/vite-bundler.d.ts.map +1 -1
  68. package/dist/cmd/build/vite-bundler.js +0 -3
  69. package/dist/cmd/build/vite-bundler.js.map +1 -1
  70. package/dist/cmd/cloud/deploy-fork.d.ts.map +1 -1
  71. package/dist/cmd/cloud/deploy-fork.js +15 -36
  72. package/dist/cmd/cloud/deploy-fork.js.map +1 -1
  73. package/dist/cmd/cloud/sandbox/exec.d.ts.map +1 -1
  74. package/dist/cmd/cloud/sandbox/exec.js +28 -86
  75. package/dist/cmd/cloud/sandbox/exec.js.map +1 -1
  76. package/dist/cmd/cloud/sandbox/run.d.ts.map +1 -1
  77. package/dist/cmd/cloud/sandbox/run.js +2 -9
  78. package/dist/cmd/cloud/sandbox/run.js.map +1 -1
  79. package/dist/cmd/cloud/sandbox/snapshot/build.js +2 -2
  80. package/dist/cmd/cloud/sandbox/snapshot/build.js.map +1 -1
  81. package/dist/cmd/coder/hub-url.d.ts.map +1 -1
  82. package/dist/cmd/coder/hub-url.js +1 -3
  83. package/dist/cmd/coder/hub-url.js.map +1 -1
  84. package/dist/cmd/coder/start.js +6 -6
  85. package/dist/cmd/coder/start.js.map +1 -1
  86. package/dist/cmd/coder/tui-init.d.ts +2 -2
  87. package/dist/cmd/coder/tui-init.js +2 -2
  88. package/dist/cmd/coder/tui-init.js.map +1 -1
  89. package/dist/cmd/dev/file-watcher.d.ts.map +1 -1
  90. package/dist/cmd/dev/file-watcher.js +2 -8
  91. package/dist/cmd/dev/file-watcher.js.map +1 -1
  92. package/dist/cmd/dev/index.d.ts.map +1 -1
  93. package/dist/cmd/dev/index.js +432 -752
  94. package/dist/cmd/dev/index.js.map +1 -1
  95. package/dist/cmd/dev/process-manager.d.ts +104 -0
  96. package/dist/cmd/dev/process-manager.d.ts.map +1 -0
  97. package/dist/cmd/dev/process-manager.js +204 -0
  98. package/dist/cmd/dev/process-manager.js.map +1 -0
  99. package/dist/errors.d.ts +10 -24
  100. package/dist/errors.d.ts.map +1 -1
  101. package/dist/errors.js +12 -42
  102. package/dist/errors.js.map +1 -1
  103. package/dist/schema-generator.d.ts.map +1 -1
  104. package/dist/schema-generator.js +12 -2
  105. package/dist/schema-generator.js.map +1 -1
  106. package/dist/tui.d.ts.map +1 -1
  107. package/dist/tui.js +5 -19
  108. package/dist/tui.js.map +1 -1
  109. package/dist/utils/version-mismatch.d.ts +39 -0
  110. package/dist/utils/version-mismatch.d.ts.map +1 -0
  111. package/dist/utils/version-mismatch.js +161 -0
  112. package/dist/utils/version-mismatch.js.map +1 -0
  113. package/package.json +6 -6
  114. package/src/cmd/ai/prompt/agent.md +0 -1
  115. package/src/cmd/ai/prompt/api.md +0 -7
  116. package/src/cmd/ai/prompt/web.md +51 -213
  117. package/src/cmd/build/app-config-extractor.ts +186 -0
  118. package/src/cmd/build/app-router-detector.ts +152 -182
  119. package/src/cmd/build/ci.ts +5 -21
  120. package/src/cmd/build/ids.ts +19 -0
  121. package/src/cmd/build/index.ts +10 -0
  122. package/src/cmd/build/vite/agent-discovery.ts +208 -679
  123. package/src/cmd/build/vite/bun-dev-server.ts +383 -146
  124. package/src/cmd/build/vite/config-loader.ts +45 -77
  125. package/src/cmd/build/vite/docs-generator.ts +0 -2
  126. package/src/cmd/build/vite/index.ts +1 -42
  127. package/src/cmd/build/vite/lifecycle-generator.ts +345 -21
  128. package/src/cmd/build/vite/route-discovery.ts +116 -274
  129. package/src/cmd/build/vite/server-bundler.ts +1 -1
  130. package/src/cmd/build/vite/static-renderer.ts +23 -15
  131. package/src/cmd/build/vite/vite-asset-server-config.ts +200 -70
  132. package/src/cmd/build/vite/vite-asset-server.ts +25 -15
  133. package/src/cmd/build/vite/vite-builder.ts +49 -220
  134. package/src/cmd/build/vite/ws-proxy.ts +126 -0
  135. package/src/cmd/build/vite-bundler.ts +0 -4
  136. package/src/cmd/cloud/deploy-fork.ts +16 -39
  137. package/src/cmd/cloud/sandbox/exec.ts +23 -130
  138. package/src/cmd/cloud/sandbox/run.ts +2 -9
  139. package/src/cmd/cloud/sandbox/snapshot/build.ts +2 -2
  140. package/src/cmd/coder/hub-url.ts +1 -3
  141. package/src/cmd/coder/start.ts +6 -6
  142. package/src/cmd/coder/tui-init.ts +4 -4
  143. package/src/cmd/dev/file-watcher.ts +2 -9
  144. package/src/cmd/dev/index.ts +476 -859
  145. package/src/cmd/dev/process-manager.ts +261 -0
  146. package/src/errors.ts +12 -44
  147. package/src/schema-generator.ts +12 -2
  148. package/src/tui.ts +5 -18
  149. package/src/utils/version-mismatch.ts +204 -0
  150. package/dist/cmd/build/ast.d.ts +0 -78
  151. package/dist/cmd/build/ast.d.ts.map +0 -1
  152. package/dist/cmd/build/ast.js +0 -2703
  153. package/dist/cmd/build/ast.js.map +0 -1
  154. package/dist/cmd/build/entry-generator.d.ts +0 -25
  155. package/dist/cmd/build/entry-generator.d.ts.map +0 -1
  156. package/dist/cmd/build/entry-generator.js +0 -695
  157. package/dist/cmd/build/entry-generator.js.map +0 -1
  158. package/dist/cmd/build/vite/api-mount-path.d.ts +0 -61
  159. package/dist/cmd/build/vite/api-mount-path.d.ts.map +0 -1
  160. package/dist/cmd/build/vite/api-mount-path.js +0 -83
  161. package/dist/cmd/build/vite/api-mount-path.js.map +0 -1
  162. package/dist/cmd/build/vite/registry-generator.d.ts +0 -19
  163. package/dist/cmd/build/vite/registry-generator.d.ts.map +0 -1
  164. package/dist/cmd/build/vite/registry-generator.js +0 -1108
  165. package/dist/cmd/build/vite/registry-generator.js.map +0 -1
  166. package/dist/cmd/build/webanalytics-generator.d.ts +0 -16
  167. package/dist/cmd/build/webanalytics-generator.d.ts.map +0 -1
  168. package/dist/cmd/build/webanalytics-generator.js +0 -178
  169. package/dist/cmd/build/webanalytics-generator.js.map +0 -1
  170. package/dist/cmd/build/workbench.d.ts +0 -7
  171. package/dist/cmd/build/workbench.d.ts.map +0 -1
  172. package/dist/cmd/build/workbench.js +0 -55
  173. package/dist/cmd/build/workbench.js.map +0 -1
  174. package/dist/utils/route-migration.d.ts +0 -62
  175. package/dist/utils/route-migration.d.ts.map +0 -1
  176. package/dist/utils/route-migration.js +0 -630
  177. package/dist/utils/route-migration.js.map +0 -1
  178. package/dist/utils/stream-capture.d.ts +0 -9
  179. package/dist/utils/stream-capture.d.ts.map +0 -1
  180. package/dist/utils/stream-capture.js +0 -34
  181. package/dist/utils/stream-capture.js.map +0 -1
  182. package/src/cmd/build/ast.ts +0 -3529
  183. package/src/cmd/build/entry-generator.ts +0 -760
  184. package/src/cmd/build/vite/api-mount-path.ts +0 -87
  185. package/src/cmd/build/vite/registry-generator.ts +0 -1267
  186. package/src/cmd/build/webanalytics-generator.ts +0 -197
  187. package/src/cmd/build/workbench.ts +0 -58
  188. package/src/utils/route-migration.ts +0 -757
  189. package/src/utils/stream-capture.ts +0 -39
@@ -5,48 +5,11 @@
5
5
  */
6
6
 
7
7
  import { join } from 'node:path';
8
- import { existsSync, renameSync, rmSync } from 'node:fs';
9
- import { createRequire } from 'node:module';
10
- import type { InlineConfig, Plugin } from 'vite';
8
+ import { existsSync, rmSync } from 'node:fs';
9
+ import type { InlineConfig } from 'vite';
11
10
  import type { Logger, DeployOptions } from '../../../types';
12
- import { browserEnvPlugin } from './browser-env-plugin';
13
- import { tailwindSourcePlugin } from './tailwind-source-plugin';
14
- import { beaconPlugin } from './beacon-plugin';
15
- import { publicAssetPathPlugin } from './public-asset-path-plugin';
16
11
  import type { BuildReportCollector } from '../../../build-report';
17
12
 
18
- /**
19
- * Vite plugin to flatten the output structure for index.html
20
- *
21
- * When root is set to the project root (for TanStack Router compatibility),
22
- * Vite outputs index.html to .agentuity/client/src/web/index.html instead of
23
- * .agentuity/client/index.html. This plugin moves it to the expected location.
24
- */
25
- function flattenHtmlOutputPlugin(outDir: string): Plugin {
26
- return {
27
- name: 'agentuity:flatten-html-output',
28
- apply: 'build',
29
- closeBundle() {
30
- const nestedHtmlPath = join(outDir, 'src', 'web', 'index.html');
31
- const targetHtmlPath = join(outDir, 'index.html');
32
-
33
- if (existsSync(nestedHtmlPath)) {
34
- renameSync(nestedHtmlPath, targetHtmlPath);
35
-
36
- // Clean up empty src/web directory structure
37
- const srcWebDir = join(outDir, 'src', 'web');
38
- const srcDir = join(outDir, 'src');
39
- try {
40
- rmSync(srcWebDir, { recursive: true, force: true });
41
- rmSync(srcDir, { recursive: true, force: true });
42
- } catch {
43
- // Ignore cleanup errors
44
- }
45
- }
46
- },
47
- };
48
- }
49
-
50
13
  export interface ViteBuildOptions {
51
14
  rootDir: string;
52
15
  mode: 'client' | 'server' | 'workbench';
@@ -75,25 +38,7 @@ export interface ViteBuildOptions {
75
38
  * Uses inline Vite config (customizable via agentuity.config.ts)
76
39
  */
77
40
  export async function runViteBuild(options: ViteBuildOptions): Promise<void> {
78
- const {
79
- rootDir,
80
- mode,
81
- dev = false,
82
- projectId = '',
83
- deploymentId = '',
84
- logger,
85
- profile,
86
- } = options;
87
-
88
- const isViteDebug =
89
- process.env.AGENTUITY_VITE_DEBUG === '1' || process.env.AGENTUITY_VITE_DEBUG === 'true';
90
- if (isViteDebug) {
91
- logger.debug('Vite debug logging enabled via AGENTUITY_VITE_DEBUG');
92
- const existing = process.env.DEBUG || '';
93
- if (!existing.includes('vite:')) {
94
- process.env.DEBUG = existing ? `${existing},vite:*` : 'vite:*';
95
- }
96
- }
41
+ const { rootDir, mode, dev = false, logger, profile } = options;
97
42
 
98
43
  logger.debug(`Running Vite build for mode: ${mode}`);
99
44
 
@@ -126,24 +71,7 @@ export async function runViteBuild(options: ViteBuildOptions): Promise<void> {
126
71
  profile,
127
72
  });
128
73
 
129
- // Load workbench config for entry file generation
130
- const { loadAgentuityConfig, getWorkbenchConfig } = await import('./config-loader');
131
- const config = await loadAgentuityConfig(rootDir, logger);
132
- const workbenchConfig = getWorkbenchConfig(config, dev);
133
-
134
- // Then, generate the entry file
135
- const { generateEntryFile } = await import('../entry-generator');
136
- await generateEntryFile({
137
- rootDir,
138
- projectId,
139
- deploymentId: deploymentId || '',
140
- logger,
141
- mode: dev ? 'dev' : 'prod',
142
- workbench: workbenchConfig.configured ? workbenchConfig : undefined,
143
- analytics: config?.analytics,
144
- });
145
-
146
- // Finally, build with Bun.build
74
+ // Build with Bun.build (app.ts is the entrypoint)
147
75
  const { installExternalsAndBuild } = await import('./server-bundler');
148
76
  await installExternalsAndBuild({
149
77
  rootDir,
@@ -153,137 +81,56 @@ export async function runViteBuild(options: ViteBuildOptions): Promise<void> {
153
81
  return;
154
82
  }
155
83
 
156
- // Dynamically import vite and react plugin
157
- // Try project's node_modules first (for custom vite configs), fall back to CLI's
158
- const projectRequire = createRequire(join(rootDir, 'package.json'));
159
- let vitePath = 'vite';
160
- let reactPluginPath = '@vitejs/plugin-react';
161
- try {
162
- vitePath = projectRequire.resolve('vite');
163
- reactPluginPath = projectRequire.resolve('@vitejs/plugin-react');
164
- } catch {
165
- // Project doesn't have vite, use CLI's bundled version
166
- }
167
- const { build: viteBuild } = await import(vitePath);
168
- const reactModule = await import(reactPluginPath);
169
- const react = reactModule.default;
84
+ // Dynamically import vite for workbench builds
85
+ const { build: viteBuild } = await import('vite');
170
86
 
171
- // For client/workbench, use inline config (no agentuity plugin needed)
87
+ // For client/workbench, use inline config with vite.config.ts loading
172
88
  let viteConfig: InlineConfig;
173
89
 
174
90
  if (mode === 'client') {
175
- // Vite needs index.html as entry point for web apps
176
- const htmlPath = join(rootDir, 'src', 'web', 'index.html');
177
-
178
- // Use workbench config passed from runAllBuilds
179
- const {
180
- workbenchEnabled = false,
181
- workbenchRoute = '/workbench',
182
- analyticsEnabled = false,
183
- } = options;
184
-
185
- // Determine CDN base URL for production builds
186
- // Use CDN for all non-dev builds with a deploymentId (including local region)
187
- const isLocalRegion = options.region === 'local';
188
- const cdnDomain = isLocalRegion
189
- ? 'localstack-static-assets.t3.storageapi.dev'
190
- : 'cdn.agentuity.com';
191
- const cdnBaseUrl =
192
- !dev && deploymentId ? `https://${cdnDomain}/${deploymentId}/client/` : undefined;
193
-
194
- // Load custom user plugins from agentuity.config.ts if it exists
91
+ // For client builds, spawn vite as a subprocess.
92
+ // This avoids issues with Bun's module loading that cause problems
93
+ // with certain plugins like @sveltejs/vite-plugin-svelte.
94
+ // The vite.config.ts in the project handles all configuration.
95
+ const buildMode = dev ? 'development' : 'production';
195
96
  const clientOutDir = join(rootDir, '.agentuity/client');
196
- const { loadAgentuityConfig, hasFrameworkPlugin } = await import('./config-loader');
197
- const userConfig = await loadAgentuityConfig(rootDir, logger);
198
- const userPlugins = userConfig?.plugins || [];
199
-
200
- // Auto-add React plugin if no framework plugin is present (backwards compatibility)
201
- if (userPlugins.length === 0 || !hasFrameworkPlugin(userPlugins)) {
202
- logger.debug(
203
- 'No framework plugin found in agentuity.config.ts plugins, adding React automatically'
204
- );
205
- userPlugins.unshift(react());
206
- }
207
97
 
208
- if (userPlugins.length > 0) {
209
- logger.debug('Loaded %d custom plugin(s) from agentuity.config.ts', userPlugins.length);
210
- }
98
+ logger.debug('Spawning vite build for client (subprocess mode)');
99
+ logger.debug(' outDir: %s', clientOutDir);
100
+ logger.debug(' mode: %s', buildMode);
101
+
102
+ const viteProcess = Bun.spawn(
103
+ ['bun', 'x', 'vite', 'build', '--mode', buildMode, '--outDir', clientOutDir],
104
+ {
105
+ cwd: rootDir,
106
+ stdout: 'inherit',
107
+ stderr: 'inherit',
108
+ }
109
+ );
211
110
 
212
- const plugins = [
213
- tailwindSourcePlugin(),
214
- ...userPlugins,
215
- browserEnvPlugin(),
216
- // Fix incorrect public asset paths and rewrite to CDN URLs
217
- publicAssetPathPlugin({ cdnBaseUrl }),
218
- flattenHtmlOutputPlugin(clientOutDir),
219
- // Emit analytics beacon as hashed CDN asset (prod builds only)
220
- beaconPlugin({ enabled: analyticsEnabled && !dev }),
221
- ];
222
-
223
- // Merge custom define values from user config
224
- const userDefine = userConfig?.define || {};
225
- if (Object.keys(userDefine).length > 0) {
226
- logger.debug(
227
- 'Loaded %d custom define(s) from agentuity.config.ts',
228
- Object.keys(userDefine).length
229
- );
111
+ const exitCode = await viteProcess.exited;
112
+
113
+ if (exitCode !== 0) {
114
+ throw new Error(`Vite build exited with code ${exitCode}`);
230
115
  }
231
116
 
232
- viteConfig = {
233
- // Use project root as Vite root so plugins (e.g., TanStack Router) resolve paths
234
- // from the repo root, matching where agentuity.config.ts is located
235
- root: rootDir,
236
- plugins,
237
- envPrefix: ['VITE_', 'AGENTUITY_PUBLIC_', 'PUBLIC_'],
238
- publicDir: join(rootDir, 'src', 'web', 'public'),
239
- base: cdnBaseUrl, // CDN URL for production assets
240
- define: {
241
- // Merge user-defined constants first
242
- ...userDefine,
243
- // Then add default defines (these will override any user-defined protected keys)
244
- // Set workbench path if enabled (use import.meta.env for client code)
245
- 'import.meta.env.AGENTUITY_PUBLIC_WORKBENCH_PATH': workbenchEnabled
246
- ? JSON.stringify(workbenchRoute)
247
- : 'undefined',
248
- },
249
- build: {
250
- outDir: clientOutDir,
251
- rollupOptions: {
252
- input: htmlPath,
253
- },
254
- manifest: true,
255
- emptyOutDir: true,
256
- // Copy public files to output for CDN upload (production builds only)
257
- // In dev mode, Vite serves them directly from src/web/public/
258
- copyPublicDir: !dev,
259
- },
260
- logLevel: isViteDebug ? 'info' : 'warn',
261
- };
117
+ logger.debug('Vite build complete for mode: client');
118
+ return;
262
119
  } else if (mode === 'workbench') {
263
120
  const { workbenchRoute = '/workbench' } = options;
264
121
  // Ensure route ends with / for Vite base
265
122
  const base = workbenchRoute.endsWith('/') ? workbenchRoute : `${workbenchRoute}/`;
266
123
 
267
- // Load custom user config for define values (same as client mode)
268
- const { loadAgentuityConfig } = await import('./config-loader');
269
- const userConfig = await loadAgentuityConfig(rootDir, logger);
270
- const userDefine = userConfig?.define || {};
271
- if (Object.keys(userDefine).length > 0) {
272
- logger.debug(
273
- 'Loaded %d custom define(s) from agentuity.config.ts for workbench',
274
- Object.keys(userDefine).length
275
- );
276
- }
124
+ // Workbench is built with React (internal UI)
125
+ // Use CLI's bundled React plugin since workbench is our code
126
+ const reactModule = await import('@vitejs/plugin-react');
127
+ const react = reactModule.default;
277
128
 
278
129
  viteConfig = {
279
130
  root: join(rootDir, '.agentuity/workbench-src'), // Use generated workbench source
280
131
  base, // All workbench assets are under the configured route
281
132
  plugins: [react()],
282
133
  envPrefix: ['VITE_', 'AGENTUITY_PUBLIC_', 'PUBLIC_'],
283
- define: {
284
- // Merge user-defined constants
285
- ...userDefine,
286
- },
287
134
  build: {
288
135
  outDir: join(rootDir, '.agentuity/workbench'),
289
136
  rollupOptions: {
@@ -292,14 +139,13 @@ export async function runViteBuild(options: ViteBuildOptions): Promise<void> {
292
139
  manifest: true,
293
140
  emptyOutDir: true,
294
141
  },
295
- logLevel: isViteDebug ? 'info' : 'warn',
142
+ logLevel: 'warn',
296
143
  };
297
144
  } else {
298
145
  throw new Error(`Unknown build mode: ${mode}`);
299
146
  }
300
147
 
301
- // Build with Vite
302
- // Force the build to use the correct mode
148
+ // For workbench mode, use programmatic vite build
303
149
  const buildMode = dev ? 'development' : 'production';
304
150
 
305
151
  await viteBuild({
@@ -334,21 +180,11 @@ export async function runAllBuilds(options: Omit<ViteBuildOptions, 'mode'>): Pro
334
180
  static: { included: false, duration: 0, routes: 0 },
335
181
  };
336
182
 
337
- // Load config to check if workbench is enabled (dev mode only)
338
- const { loadAgentuityConfig, getWorkbenchConfig } = await import('./config-loader');
339
- const config = await loadAgentuityConfig(rootDir, logger);
340
-
341
- // Copy bundle files if configured (before build so build output takes priority)
342
- if (config?.bundle?.length) {
343
- const { copyBundleFiles } = await import('./bundle-files');
344
- const outDir = join(rootDir, '.agentuity');
345
- const count = await copyBundleFiles(rootDir, outDir, config.bundle, logger);
346
- if (count > 0) {
347
- logger.debug(`Copied ${count} bundle file(s) to .agentuity`);
348
- }
349
- }
183
+ // Load runtime config from createApp() in app.ts (v2 approach)
184
+ const { getWorkbenchConfig, loadRuntimeConfig } = await import('./config-loader');
185
+ const runtimeConfig = await loadRuntimeConfig(rootDir, logger);
350
186
 
351
- const workbenchConfig = getWorkbenchConfig(config, dev);
187
+ const workbenchConfig = getWorkbenchConfig(dev, runtimeConfig);
352
188
  // Generate workbench files BEFORE any builds if enabled (dev mode only)
353
189
  if (workbenchConfig.enabled) {
354
190
  logger.debug('Workbench enabled (dev mode), generating files before build...');
@@ -358,7 +194,6 @@ export async function runAllBuilds(options: Omit<ViteBuildOptions, 'mode'>): Pro
358
194
 
359
195
  // 1. Discover agents and routes BEFORE builds
360
196
  logger.debug('Discovering agents and routes...');
361
- const { generateAgentRegistry, generateRouteRegistry } = await import('./registry-generator');
362
197
  const { discoverAgents } = await import('./agent-discovery');
363
198
  const { discoverRoutes } = await import('./route-discovery');
364
199
 
@@ -369,24 +204,18 @@ export async function runAllBuilds(options: Omit<ViteBuildOptions, 'mode'>): Pro
369
204
  options.deploymentId || '',
370
205
  logger
371
206
  );
372
- const { routes, routeInfoList } = await discoverRoutes(
373
- srcDir,
374
- projectId,
375
- options.deploymentId || '',
376
- logger
377
- );
207
+ const { routes } = await discoverRoutes(srcDir, projectId, options.deploymentId || '', logger);
378
208
 
379
- // Generate agent and route registries for type augmentation BEFORE builds
380
- // (TypeScript needs these files to exist during type checking)
381
- generateAgentRegistry(srcDir, agentMetadata);
382
- await generateRouteRegistry(srcDir, routeInfoList);
383
- logger.debug('Agent and route registries generated');
209
+ // Agent metadata is used for metadata.json generation (no registry codegen needed)
384
210
 
385
211
  // Check if web frontend exists
386
212
  const hasWebFrontend = await Bun.file(join(rootDir, 'src', 'web', 'index.html')).exists();
387
213
 
388
214
  // Check if analytics is enabled
389
- const analyticsEnabled = config?.analytics !== false;
215
+ // v2: analytics config comes from createApp()
216
+ const analyticsFromRuntime = runtimeConfig?.analytics;
217
+ const analyticsEnabled =
218
+ analyticsFromRuntime !== undefined ? analyticsFromRuntime !== false : true;
390
219
 
391
220
  // 2. Build client (only if web frontend exists)
392
221
  if (hasWebFrontend) {
@@ -407,15 +236,15 @@ export async function runAllBuilds(options: Omit<ViteBuildOptions, 'mode'>): Pro
407
236
  logger.debug('Skipping client build - no src/web/index.html found');
408
237
  }
409
238
 
410
- // 2b. Static rendering (if configured)
411
- if (config?.render === 'static' && hasWebFrontend) {
239
+ // 2b. Static rendering (if entry-server.tsx exists)
240
+ const entryServerPath = join(rootDir, 'src', 'web', 'entry-server.tsx');
241
+ if (existsSync(entryServerPath) && hasWebFrontend) {
412
242
  logger.debug('Running static rendering (pre-rendering all routes)...');
413
243
  const endStaticDiagnostic = collector?.startDiagnostic('static-render');
414
244
  const { runStaticRender } = await import('./static-renderer');
415
245
  const staticResult = await runStaticRender({
416
246
  rootDir,
417
247
  logger,
418
- userPlugins: config?.plugins || [],
419
248
  });
420
249
  result.static.included = true;
421
250
  result.static.duration = staticResult.duration;
@@ -0,0 +1,126 @@
1
+ /**
2
+ * WebSocket-aware front-door TCP proxy for dev mode.
3
+ *
4
+ * Bun's node:http has several bugs that prevent Vite's built-in http-proxy
5
+ * from proxying WebSocket upgrades (see linked PRs). Rather than polyfilling
6
+ * those bugs, this module places a lightweight `net.createServer` on the
7
+ * user-facing port. It inspects the first bytes of each TCP connection and
8
+ * routes accordingly:
9
+ *
10
+ * - **WebSocket upgrades to backend paths** → piped directly to Bun backend
11
+ * (Bun's native `server.upgrade()` works perfectly over raw TCP)
12
+ * - **Everything else** (HTTP requests, Vite HMR WebSocket) → piped to Vite
13
+ *
14
+ * From the browser's perspective there is only one port. Vite and Bun both
15
+ * listen on internal ports that are never exposed.
16
+ *
17
+ * Bun bugs this works around:
18
+ * - https://github.com/oven-sh/bun/pull/27237 (socket.write drops data)
19
+ * - https://github.com/oven-sh/bun/pull/26264 (missing destroySoon)
20
+ * - https://github.com/oven-sh/bun/pull/27859 (http.request upgrade event)
21
+ * - Server-side upgrade socket read broken (HTTP parser doesn't hand off)
22
+ *
23
+ * This entire module can be removed once those Bun PRs are merged and the
24
+ * Vite `ws: true` proxy works natively under Bun.
25
+ *
26
+ * ```
27
+ * Browser ──TCP──▶ net.Server (:3500, user-facing)
28
+ * │
29
+ * ┌───────────┴───────────┐
30
+ * ▼ (WS upgrade to ▼ (everything else)
31
+ * backend paths)
32
+ * Bun backend (:3501) Vite server (:3502)
33
+ * ```
34
+ */
35
+
36
+ import { createServer, connect, type Server } from 'node:net';
37
+ import type { Logger } from '../../../types';
38
+
39
+ export interface WsProxyOptions {
40
+ /** Port the front-door proxy listens on (user-facing) */
41
+ port: number;
42
+ /** Port of the Vite dev server (internal) */
43
+ vitePort: number;
44
+ /** Port of the Bun backend server (internal) */
45
+ backendPort: number;
46
+ /** Route path prefixes that should be proxied to the backend */
47
+ routePaths: string[];
48
+ logger: Logger;
49
+ }
50
+
51
+ /**
52
+ * Start a front-door TCP proxy that routes WebSocket upgrades to the Bun
53
+ * backend and everything else to Vite. Returns the `net.Server` instance.
54
+ */
55
+ export function startWsProxy(options: WsProxyOptions): Promise<Server> {
56
+ const { port, vitePort, backendPort, routePaths, logger } = options;
57
+
58
+ // Prefixes whose WebSocket upgrades go to Bun instead of Vite
59
+ const wsPathPrefixes = ['/_agentuity', ...routePaths];
60
+
61
+ return new Promise((resolve, reject) => {
62
+ const server = createServer((socket) => {
63
+ let handled = false;
64
+
65
+ // Peek at the first chunk to decide where to route
66
+ socket.once('data', (firstChunk) => {
67
+ handled = true;
68
+
69
+ const header = firstChunk.toString('utf8', 0, Math.min(firstChunk.length, 4096));
70
+
71
+ // Detect: is this a WebSocket upgrade for a backend path?
72
+ const isUpgrade = /upgrade:\s*websocket/i.test(header);
73
+ let targetPort = vitePort;
74
+
75
+ if (isUpgrade) {
76
+ const pathMatch = header.match(/^(?:GET|POST)\s+(\S+)/);
77
+ const pathname = (pathMatch?.[1] ?? '/').split('?')[0] ?? '/';
78
+
79
+ const isBackendPath = wsPathPrefixes.some(
80
+ (prefix) => pathname === prefix || pathname.startsWith(prefix + '/')
81
+ );
82
+
83
+ if (isBackendPath) {
84
+ targetPort = backendPort;
85
+ logger.debug('WS upgrade %s → Bun :%d', pathname, backendPort);
86
+ }
87
+ }
88
+
89
+ const target = connect(targetPort, '127.0.0.1');
90
+
91
+ target.on('connect', () => {
92
+ target.write(firstChunk);
93
+ socket.pipe(target);
94
+ target.pipe(socket);
95
+ });
96
+
97
+ target.on('error', () => {
98
+ if (!socket.destroyed) socket.destroy();
99
+ });
100
+ socket.on('error', () => {
101
+ if (!target.destroyed) target.destroy();
102
+ });
103
+ });
104
+
105
+ // Client disconnected before sending anything
106
+ socket.on('close', () => {
107
+ if (!handled) socket.destroy();
108
+ });
109
+ socket.on('error', () => {
110
+ if (!handled) socket.destroy();
111
+ });
112
+ });
113
+
114
+ server.on('error', reject);
115
+
116
+ server.listen(port, '127.0.0.1', () => {
117
+ logger.debug(
118
+ 'WS front-door proxy on :%d (Vite :%d, Bun :%d)',
119
+ port,
120
+ vitePort,
121
+ backendPort
122
+ );
123
+ resolve(server);
124
+ });
125
+ });
126
+ }
@@ -10,7 +10,6 @@ import { StructuredError } from '@agentuity/core';
10
10
  import type { Logger, DeployOptions } from '../../types';
11
11
  import { runAllBuilds } from './vite/vite-builder';
12
12
  import { checkAndUpgradeDependencies } from '../../utils/dependency-checker';
13
- import { promptRouteMigration } from '../../utils/route-migration';
14
13
  import { checkBunVersion } from '../../utils/bun-version-checker';
15
14
  import * as tui from '../../tui';
16
15
  import type { BuildReportCollector } from '../../build-report';
@@ -90,9 +89,6 @@ export async function viteBundle(options: ViteBundleOptions): Promise<{ output:
90
89
  });
91
90
  }
92
91
 
93
- // Check if project can migrate from file-based to explicit routing
94
- await promptRouteMigration(rootDir, logger);
95
-
96
92
  try {
97
93
  // Run all builds (client -> workbench -> server)
98
94
  logger.debug('Starting builds...');
@@ -13,7 +13,7 @@
13
13
  import { spawn, type Subprocess } from 'bun';
14
14
  import { tmpdir } from 'node:os';
15
15
  import { join } from 'node:path';
16
- import { appendFileSync, createWriteStream, existsSync, readFileSync, unlinkSync } from 'node:fs';
16
+ import { existsSync, readFileSync, unlinkSync } from 'node:fs';
17
17
  import type { APIClient } from '../../api';
18
18
  import { getUserAgent } from '../../api';
19
19
  import { isUnicode } from '../../tui/symbols';
@@ -37,14 +37,12 @@ export interface ForkDeployResult {
37
37
  }
38
38
 
39
39
  /**
40
- * Stream data to a Pulse stream URL.
41
- * Accepts a string, Blob/BunFile, or ReadableStream as the body to avoid
42
- * loading large outputs into memory.
40
+ * Stream data to a Pulse stream URL
43
41
  */
44
42
  async function streamToPulse(
45
43
  streamURL: string,
46
44
  sdkKey: string,
47
- data: string | Blob | ReadableStream<Uint8Array>,
45
+ data: string,
48
46
  logger: Logger
49
47
  ): Promise<void> {
50
48
  try {
@@ -76,8 +74,7 @@ export async function runForkedDeploy(options: ForkDeployOptions): Promise<ForkD
76
74
  const buildLogsStreamURL = deployment.buildLogsStreamURL;
77
75
  const reportFile = join(tmpdir(), `agentuity-deploy-${deploymentId}.json`);
78
76
  const cleanLogsFile = join(tmpdir(), `agentuity-deploy-${deploymentId}-logs.txt`);
79
- const rawLogsFile = join(tmpdir(), `agentuity-deploy-${deploymentId}-raw.txt`);
80
- const rawLogsWriter = createWriteStream(rawLogsFile);
77
+ let outputBuffer = '';
81
78
  let proc: Subprocess | null = null;
82
79
  let cancelled = false;
83
80
 
@@ -198,6 +195,7 @@ export async function runForkedDeploy(options: ForkDeployOptions): Promise<ForkD
198
195
 
199
196
  const handleOutput = async (stream: ReadableStream<Uint8Array>, isStderr: boolean) => {
200
197
  const reader = stream.getReader();
198
+ const decoder = new TextDecoder();
201
199
  const target = isStderr ? process.stderr : process.stdout;
202
200
 
203
201
  try {
@@ -205,9 +203,8 @@ export async function runForkedDeploy(options: ForkDeployOptions): Promise<ForkD
205
203
  const { done, value } = await reader.read();
206
204
  if (done) break;
207
205
 
208
- // Stream raw bytes to disk instead of accumulating in memory.
209
- // This prevents OOM / ERR_STRING_TOO_LONG crashes on large builds.
210
- rawLogsWriter.write(value);
206
+ const text = decoder.decode(value, { stream: true });
207
+ outputBuffer += text;
211
208
  target.write(value);
212
209
  }
213
210
  } catch (err) {
@@ -226,11 +223,6 @@ export async function runForkedDeploy(options: ForkDeployOptions): Promise<ForkD
226
223
 
227
224
  await Promise.all([stdoutPromise, stderrPromise]);
228
225
 
229
- // Close the raw logs writer so the file is fully flushed before reading
230
- await new Promise<void>((resolve) => {
231
- rawLogsWriter.end(resolve);
232
- });
233
-
234
226
  const exitCode = await proc.exited;
235
227
  logger.debug('Child process exited with code: %d', exitCode);
236
228
 
@@ -257,11 +249,12 @@ export async function runForkedDeploy(options: ForkDeployOptions): Promise<ForkD
257
249
  logger.debug('Failed to read clean logs file: %s', err);
258
250
  }
259
251
  }
252
+ // Fall back to raw output if no clean logs
253
+ if (!logsContent && outputBuffer) {
254
+ logsContent = outputBuffer;
255
+ }
260
256
  if (logsContent) {
261
257
  await streamToPulse(buildLogsStreamURL, sdkKey, logsContent, logger);
262
- } else if (existsSync(rawLogsFile)) {
263
- // Stream raw logs file directly to Pulse without loading into memory
264
- await streamToPulse(buildLogsStreamURL, sdkKey, Bun.file(rawLogsFile), logger);
265
258
  }
266
259
  }
267
260
 
@@ -314,27 +307,11 @@ export async function runForkedDeploy(options: ForkDeployOptions): Promise<ForkD
314
307
  // ignore
315
308
  }
316
309
  }
317
- if (logsContent) {
318
- logsContent += `\n\n--- FORK ERROR ---\n${errorMessage}\n`;
319
- await streamToPulse(buildLogsStreamURL, sdkKey, logsContent, logger);
320
- } else {
321
- // Append error to raw logs file and stream it without loading into memory
322
- try {
323
- appendFileSync(rawLogsFile, `\n\n--- FORK ERROR ---\n${errorMessage}\n`);
324
- } catch {
325
- // ignore — file may not exist if child never produced output
326
- }
327
- if (existsSync(rawLogsFile)) {
328
- await streamToPulse(buildLogsStreamURL, sdkKey, Bun.file(rawLogsFile), logger);
329
- } else {
330
- await streamToPulse(
331
- buildLogsStreamURL,
332
- sdkKey,
333
- `--- FORK ERROR ---\n${errorMessage}\n`,
334
- logger
335
- );
336
- }
310
+ if (!logsContent) {
311
+ logsContent = outputBuffer;
337
312
  }
313
+ logsContent += `\n\n--- FORK ERROR ---\n${errorMessage}\n`;
314
+ await streamToPulse(buildLogsStreamURL, sdkKey, logsContent, logger);
338
315
  }
339
316
 
340
317
  try {
@@ -383,7 +360,7 @@ export async function runForkedDeploy(options: ForkDeployOptions): Promise<ForkD
383
360
  process.off('SIGTERM', sigtermHandler);
384
361
 
385
362
  // Clean up temp files
386
- for (const file of [reportFile, cleanLogsFile, rawLogsFile]) {
363
+ for (const file of [reportFile, cleanLogsFile]) {
387
364
  if (existsSync(file)) {
388
365
  try {
389
366
  unlinkSync(file);