@agentuity/cli 1.0.48 → 2.0.0-beta.0

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 (124) hide show
  1. package/dist/cmd/build/app-router-detector.d.ts +2 -5
  2. package/dist/cmd/build/app-router-detector.d.ts.map +1 -1
  3. package/dist/cmd/build/app-router-detector.js +130 -154
  4. package/dist/cmd/build/app-router-detector.js.map +1 -1
  5. package/dist/cmd/build/ids.d.ts +11 -0
  6. package/dist/cmd/build/ids.d.ts.map +1 -0
  7. package/dist/cmd/build/ids.js +18 -0
  8. package/dist/cmd/build/ids.js.map +1 -0
  9. package/dist/cmd/build/vite/agent-discovery.d.ts +8 -4
  10. package/dist/cmd/build/vite/agent-discovery.d.ts.map +1 -1
  11. package/dist/cmd/build/vite/agent-discovery.js +166 -487
  12. package/dist/cmd/build/vite/agent-discovery.js.map +1 -1
  13. package/dist/cmd/build/vite/bun-dev-server.d.ts +10 -16
  14. package/dist/cmd/build/vite/bun-dev-server.d.ts.map +1 -1
  15. package/dist/cmd/build/vite/bun-dev-server.js +67 -134
  16. package/dist/cmd/build/vite/bun-dev-server.js.map +1 -1
  17. package/dist/cmd/build/vite/docs-generator.d.ts.map +1 -1
  18. package/dist/cmd/build/vite/docs-generator.js +0 -2
  19. package/dist/cmd/build/vite/docs-generator.js.map +1 -1
  20. package/dist/cmd/build/vite/index.d.ts.map +1 -1
  21. package/dist/cmd/build/vite/index.js +0 -36
  22. package/dist/cmd/build/vite/index.js.map +1 -1
  23. package/dist/cmd/build/vite/lifecycle-generator.d.ts +10 -2
  24. package/dist/cmd/build/vite/lifecycle-generator.d.ts.map +1 -1
  25. package/dist/cmd/build/vite/lifecycle-generator.js +302 -23
  26. package/dist/cmd/build/vite/lifecycle-generator.js.map +1 -1
  27. package/dist/cmd/build/vite/route-discovery.d.ts +11 -38
  28. package/dist/cmd/build/vite/route-discovery.d.ts.map +1 -1
  29. package/dist/cmd/build/vite/route-discovery.js +97 -177
  30. package/dist/cmd/build/vite/route-discovery.js.map +1 -1
  31. package/dist/cmd/build/vite/server-bundler.js +1 -1
  32. package/dist/cmd/build/vite/server-bundler.js.map +1 -1
  33. package/dist/cmd/build/vite/static-renderer.d.ts.map +1 -1
  34. package/dist/cmd/build/vite/static-renderer.js +1 -9
  35. package/dist/cmd/build/vite/static-renderer.js.map +1 -1
  36. package/dist/cmd/build/vite/vite-asset-server-config.d.ts +6 -3
  37. package/dist/cmd/build/vite/vite-asset-server-config.d.ts.map +1 -1
  38. package/dist/cmd/build/vite/vite-asset-server-config.js +171 -21
  39. package/dist/cmd/build/vite/vite-asset-server-config.js.map +1 -1
  40. package/dist/cmd/build/vite/vite-asset-server.d.ts +8 -3
  41. package/dist/cmd/build/vite/vite-asset-server.d.ts.map +1 -1
  42. package/dist/cmd/build/vite/vite-asset-server.js +14 -13
  43. package/dist/cmd/build/vite/vite-asset-server.js.map +1 -1
  44. package/dist/cmd/build/vite/vite-builder.d.ts.map +1 -1
  45. package/dist/cmd/build/vite/vite-builder.js +6 -36
  46. package/dist/cmd/build/vite/vite-builder.js.map +1 -1
  47. package/dist/cmd/build/vite/ws-proxy.d.ts +53 -0
  48. package/dist/cmd/build/vite/ws-proxy.d.ts.map +1 -0
  49. package/dist/cmd/build/vite/ws-proxy.js +95 -0
  50. package/dist/cmd/build/vite/ws-proxy.js.map +1 -0
  51. package/dist/cmd/build/vite-bundler.d.ts.map +1 -1
  52. package/dist/cmd/build/vite-bundler.js +0 -3
  53. package/dist/cmd/build/vite-bundler.js.map +1 -1
  54. package/dist/cmd/cloud/deploy.d.ts.map +1 -1
  55. package/dist/cmd/cloud/deploy.js +0 -1
  56. package/dist/cmd/cloud/deploy.js.map +1 -1
  57. package/dist/cmd/dev/file-watcher.d.ts.map +1 -1
  58. package/dist/cmd/dev/file-watcher.js +2 -8
  59. package/dist/cmd/dev/file-watcher.js.map +1 -1
  60. package/dist/cmd/dev/index.d.ts.map +1 -1
  61. package/dist/cmd/dev/index.js +369 -720
  62. package/dist/cmd/dev/index.js.map +1 -1
  63. package/package.json +6 -8
  64. package/src/cmd/ai/prompt/agent.md +0 -1
  65. package/src/cmd/ai/prompt/api.md +0 -7
  66. package/src/cmd/ai/prompt/web.md +51 -213
  67. package/src/cmd/build/app-router-detector.ts +152 -182
  68. package/src/cmd/build/ids.ts +19 -0
  69. package/src/cmd/build/vite/agent-discovery.ts +208 -679
  70. package/src/cmd/build/vite/bun-dev-server.ts +78 -154
  71. package/src/cmd/build/vite/docs-generator.ts +0 -2
  72. package/src/cmd/build/vite/index.ts +1 -42
  73. package/src/cmd/build/vite/lifecycle-generator.ts +345 -21
  74. package/src/cmd/build/vite/route-discovery.ts +116 -274
  75. package/src/cmd/build/vite/server-bundler.ts +1 -1
  76. package/src/cmd/build/vite/static-renderer.ts +1 -11
  77. package/src/cmd/build/vite/vite-asset-server-config.ts +196 -23
  78. package/src/cmd/build/vite/vite-asset-server.ts +25 -15
  79. package/src/cmd/build/vite/vite-builder.ts +6 -53
  80. package/src/cmd/build/vite/ws-proxy.ts +126 -0
  81. package/src/cmd/build/vite-bundler.ts +0 -4
  82. package/src/cmd/cloud/deploy.ts +0 -1
  83. package/src/cmd/dev/file-watcher.ts +2 -9
  84. package/src/cmd/dev/index.ts +409 -832
  85. package/dist/cmd/build/ast.d.ts +0 -78
  86. package/dist/cmd/build/ast.d.ts.map +0 -1
  87. package/dist/cmd/build/ast.js +0 -2703
  88. package/dist/cmd/build/ast.js.map +0 -1
  89. package/dist/cmd/build/entry-generator.d.ts +0 -25
  90. package/dist/cmd/build/entry-generator.d.ts.map +0 -1
  91. package/dist/cmd/build/entry-generator.js +0 -695
  92. package/dist/cmd/build/entry-generator.js.map +0 -1
  93. package/dist/cmd/build/vite/api-mount-path.d.ts +0 -61
  94. package/dist/cmd/build/vite/api-mount-path.d.ts.map +0 -1
  95. package/dist/cmd/build/vite/api-mount-path.js +0 -83
  96. package/dist/cmd/build/vite/api-mount-path.js.map +0 -1
  97. package/dist/cmd/build/vite/registry-generator.d.ts +0 -19
  98. package/dist/cmd/build/vite/registry-generator.d.ts.map +0 -1
  99. package/dist/cmd/build/vite/registry-generator.js +0 -1108
  100. package/dist/cmd/build/vite/registry-generator.js.map +0 -1
  101. package/dist/cmd/build/vite/tailwind-source-plugin.d.ts +0 -13
  102. package/dist/cmd/build/vite/tailwind-source-plugin.d.ts.map +0 -1
  103. package/dist/cmd/build/vite/tailwind-source-plugin.js +0 -44
  104. package/dist/cmd/build/vite/tailwind-source-plugin.js.map +0 -1
  105. package/dist/cmd/build/webanalytics-generator.d.ts +0 -16
  106. package/dist/cmd/build/webanalytics-generator.d.ts.map +0 -1
  107. package/dist/cmd/build/webanalytics-generator.js +0 -178
  108. package/dist/cmd/build/webanalytics-generator.js.map +0 -1
  109. package/dist/cmd/build/workbench.d.ts +0 -7
  110. package/dist/cmd/build/workbench.d.ts.map +0 -1
  111. package/dist/cmd/build/workbench.js +0 -55
  112. package/dist/cmd/build/workbench.js.map +0 -1
  113. package/dist/utils/route-migration.d.ts +0 -62
  114. package/dist/utils/route-migration.d.ts.map +0 -1
  115. package/dist/utils/route-migration.js +0 -630
  116. package/dist/utils/route-migration.js.map +0 -1
  117. package/src/cmd/build/ast.ts +0 -3529
  118. package/src/cmd/build/entry-generator.ts +0 -760
  119. package/src/cmd/build/vite/api-mount-path.ts +0 -87
  120. package/src/cmd/build/vite/registry-generator.ts +0 -1267
  121. package/src/cmd/build/vite/tailwind-source-plugin.ts +0 -54
  122. package/src/cmd/build/webanalytics-generator.ts +0 -197
  123. package/src/cmd/build/workbench.ts +0 -58
  124. package/src/utils/route-migration.ts +0 -757
@@ -1,20 +1,163 @@
1
1
  /**
2
- * Vite Asset Server Configuration
2
+ * Vite Dev Server Configuration
3
3
  *
4
- * Minimal Vite config for serving frontend assets with HMR only.
5
- * Does NOT handle API routes, workbench, or WebSocket - that's the Bun server's job.
4
+ * Vite is the primary dev server — serves frontend assets natively and proxies
5
+ * API/WebSocket requests to the Bun backend server.
6
6
  */
7
7
 
8
8
  import { join } from 'node:path';
9
+ import { existsSync } from 'node:fs';
9
10
  import { createRequire } from 'node:module';
10
- import type { InlineConfig } from 'vite';
11
+ import type { InlineConfig, Plugin } from 'vite';
11
12
  import type { Logger } from '../../../types';
12
13
 
13
14
  export interface GenerateAssetServerConfigOptions {
14
15
  rootDir: string;
15
16
  logger: Logger;
16
17
  workbenchPath?: string;
17
- port: number; // The port Vite will run on (for HMR client configuration)
18
+ port: number; // The port Vite will listen on (user-facing)
19
+ backendPort: number; // The port Bun backend is running on (internal)
20
+ /** User-defined route mount paths from createApp({ router }) (e.g., ['/api', '/v1']) */
21
+ routePaths?: string[];
22
+ }
23
+
24
+ /**
25
+ * Vite plugin that injects analytics scripts in dev mode.
26
+ *
27
+ * In production the beacon plugin handles this at build time. In dev mode
28
+ * the analytics config + session + beacon scripts are served by the Bun
29
+ * backend at /_agentuity/webanalytics/* routes, but we need to inject the
30
+ * `<script>` tags into the HTML so the browser loads them.
31
+ */
32
+ function devAnalyticsPlugin(): Plugin {
33
+ return {
34
+ name: 'agentuity:dev-analytics',
35
+ transformIndexHtml: {
36
+ order: 'pre',
37
+ handler(html) {
38
+ // Default analytics config — matches resolveAnalyticsConfig(undefined) in runtime
39
+ const config = {
40
+ enabled: true,
41
+ trackClicks: true,
42
+ trackScroll: true,
43
+ trackOutboundLinks: true,
44
+ trackForms: false,
45
+ trackWebVitals: true,
46
+ trackErrors: true,
47
+ trackSPANavigation: true,
48
+ isDevmode: true,
49
+ };
50
+
51
+ const injection =
52
+ `<script>window.__AGENTUITY_ANALYTICS__=${JSON.stringify(config)};</script>` +
53
+ '<script src="/_agentuity/webanalytics/session.js" async></script>' +
54
+ '<script src="/_agentuity/webanalytics/analytics.js"></script>';
55
+
56
+ if (html.includes('</head>')) {
57
+ return html.replace('</head>', `${injection}</head>`);
58
+ }
59
+ return html;
60
+ },
61
+ },
62
+ };
63
+ }
64
+
65
+ /**
66
+ * Vite plugin that serves src/web/index.html as the SPA fallback.
67
+ *
68
+ * Vite's built-in SPA fallback only serves index.html from the project root.
69
+ * Since Agentuity apps keep their HTML entry at src/web/index.html, we need
70
+ * this plugin to rewrite the URL so Vite's built-in transform pipeline
71
+ * (including React Fast Refresh injection) processes it correctly.
72
+ */
73
+ function spaFallbackPlugin(rootDir: string, routePaths: string[], workbenchPath?: string): Plugin {
74
+ const htmlPath = join(rootDir, 'src', 'web', 'index.html');
75
+ const hasHtml = existsSync(htmlPath);
76
+
77
+ return {
78
+ name: 'agentuity:spa-fallback',
79
+ configureServer(server) {
80
+ if (!hasHtml) return;
81
+
82
+ server.middlewares.use(async (req, res, next) => {
83
+ // Only handle GET/HEAD navigation requests
84
+ if (req.method !== 'GET' && req.method !== 'HEAD') return next();
85
+
86
+ const url = req.url || '/';
87
+ const pathname = url.split('?')[0] || '/';
88
+ const accept = req.headers.accept || '';
89
+ const secFetchDest = req.headers['sec-fetch-dest'] || '';
90
+
91
+ // For robustness, treat unknown GET/HEAD routes as potential SPA navigations.
92
+ // We still avoid intercepting assets/backend paths via the filters below.
93
+ // (This also makes non-browser readiness probes like fetch('/streams') work.)
94
+ const isDocumentRequest = secFetchDest === 'document' || accept.includes('text/html');
95
+
96
+ // Skip file requests (have an extension)
97
+ if (pathname !== '/' && /\.[a-zA-Z0-9]+$/.test(pathname)) return next();
98
+
99
+ // For non-document requests, only allow root path fallback.
100
+ // (e.g. don't turn module/script fetches into HTML accidentally)
101
+ if (!isDocumentRequest && pathname === '/') {
102
+ // allow root fallback for simple probes
103
+ }
104
+
105
+ // Skip Vite/module/internal asset paths
106
+ if (
107
+ pathname.startsWith('/@vite') ||
108
+ pathname.startsWith('/@react-refresh') ||
109
+ pathname.startsWith('/@id/') ||
110
+ pathname.startsWith('/@fs/') ||
111
+ pathname.startsWith('/node_modules/') ||
112
+ pathname.startsWith('/src/') ||
113
+ (pathname.startsWith('/@') && !pathname.startsWith('/_agentuity'))
114
+ ) {
115
+ return next();
116
+ }
117
+
118
+ // Skip paths that are proxied to the Bun backend
119
+ if (
120
+ pathname.startsWith('/_agentuity') ||
121
+ pathname.startsWith('/_health') ||
122
+ pathname.startsWith('/_idle')
123
+ ) {
124
+ return next();
125
+ }
126
+ // Skip workbench path (served by Bun)
127
+ if (
128
+ workbenchPath &&
129
+ (pathname === workbenchPath || pathname.startsWith(workbenchPath + '/'))
130
+ ) {
131
+ return next();
132
+ }
133
+ for (const rp of routePaths) {
134
+ if (pathname === rp || pathname.startsWith(rp + '/')) return next();
135
+ }
136
+
137
+ // If this isn't clearly a document navigation, still allow SPA fallback
138
+ // for extensionless client-side routes like /streams, /rpc, /webrtc.
139
+ // We already excluded backend paths and asset/module paths above.
140
+
141
+ try {
142
+ let html = await Bun.file(htmlPath).text();
143
+ // Match old devHtmlHandler behavior from the generated Bun entry:
144
+ // rewrite relative paths so the app works from / and client-side routes.
145
+ html = html
146
+ .replace(/src="\.\//g, 'src="/src/web/')
147
+ .replace(/href="\.\//g, 'href="/src/web/');
148
+
149
+ // Let Vite inject HMR client, React refresh preamble, etc.
150
+ html = await server.transformIndexHtml(url, html, req.originalUrl);
151
+
152
+ res.statusCode = 200;
153
+ res.setHeader('Content-Type', 'text/html; charset=utf-8');
154
+ res.end(html);
155
+ } catch (error) {
156
+ next(error as Error);
157
+ }
158
+ });
159
+ },
160
+ };
18
161
  }
19
162
 
20
163
  /**
@@ -23,7 +166,7 @@ export interface GenerateAssetServerConfigOptions {
23
166
  export async function generateAssetServerConfig(
24
167
  options: GenerateAssetServerConfigOptions
25
168
  ): Promise<InlineConfig> {
26
- const { rootDir, logger, workbenchPath, port } = options;
169
+ const { rootDir, logger, workbenchPath, port, backendPort, routePaths = ['/api'] } = options;
27
170
 
28
171
  // Load custom user config for define values and plugins
29
172
  const { loadAgentuityConfig } = await import('./config-loader');
@@ -90,27 +233,56 @@ export async function generateAssetServerConfig(
90
233
  envPrefix: ['VITE_', 'AGENTUITY_PUBLIC_', 'PUBLIC_'],
91
234
 
92
235
  server: {
93
- // Use the port we selected
236
+ // Vite is the primary dev server — listens on the user-facing port
94
237
  port,
95
238
  strictPort: true, // Port is pre-verified as available by findAvailablePort()
96
239
  host: '127.0.0.1',
97
240
 
98
- // CORS headers to allow Bun server on port 3500 to proxy requests
99
- cors: {
100
- origin: 'http://127.0.0.1:3500',
101
- credentials: true,
241
+ // Proxy backend routes to Bun server (HTTP only).
242
+ // WebSocket upgrades are handled by the front-door TCP proxy (ws-proxy.ts)
243
+ // which routes them directly to the Bun backend, bypassing Vite entirely.
244
+ // This avoids Bun's broken node:http upgrade socket implementation.
245
+ proxy: {
246
+ // User-defined route mounts (from createApp({ router }))
247
+ ...Object.fromEntries(
248
+ routePaths.map((routePath) => [
249
+ routePath,
250
+ {
251
+ target: `http://127.0.0.1:${backendPort}`,
252
+ changeOrigin: true,
253
+ },
254
+ ])
255
+ ),
256
+ // Agentuity system routes (workbench API, health, analytics, etc.)
257
+ '/_agentuity': {
258
+ target: `http://127.0.0.1:${backendPort}`,
259
+ changeOrigin: true,
260
+ },
261
+ // Workbench UI route (served by Bun, references /@fs/* paths handled by Vite)
262
+ ...(workbenchPath
263
+ ? {
264
+ [workbenchPath]: {
265
+ target: `http://127.0.0.1:${backendPort}`,
266
+ changeOrigin: true,
267
+ },
268
+ }
269
+ : {}),
270
+ // Legacy health check routes
271
+ '/_health': {
272
+ target: `http://127.0.0.1:${backendPort}`,
273
+ changeOrigin: true,
274
+ },
275
+ '/_idle': {
276
+ target: `http://127.0.0.1:${backendPort}`,
277
+ changeOrigin: true,
278
+ },
102
279
  },
103
280
 
104
- // HMR configuration for development with tunnel support (*.agentuity.live)
105
- // Do NOT set host/protocol - let Vite auto-detect from page origin
106
- // This allows HMR to work both locally and through the Gravity tunnel
107
- // The Bun server proxies /__vite_hmr WebSocket connections to Vite
108
- hmr: {
109
- // Use a dedicated path for HMR WebSocket to enable proxying
110
- path: '/__vite_hmr',
111
- },
281
+ // HMR works natively Vite is the primary server, no proxy needed
282
+ // Auto-detect host/protocol from page origin for tunnel support
283
+ hmr: true,
112
284
 
113
- // Don't open browser - Bun server will be the entry point
285
+ // Don't open browser automatically
114
286
  open: false,
115
287
  },
116
288
 
@@ -132,7 +304,6 @@ export async function generateAssetServerConfig(
132
304
  // Try project's node_modules first, fall back to CLI's bundled version
133
305
  plugins: await (async () => {
134
306
  const { browserEnvPlugin } = await import('./browser-env-plugin');
135
- const { tailwindSourcePlugin } = await import('./tailwind-source-plugin');
136
307
  const { publicAssetPathPlugin } = await import('./public-asset-path-plugin');
137
308
  const { hasFrameworkPlugin } = await import('./config-loader');
138
309
 
@@ -154,14 +325,16 @@ export async function generateAssetServerConfig(
154
325
  }
155
326
 
156
327
  return [
157
- // Fix Tailwind oxide scanner hang in containers
158
- tailwindSourcePlugin(),
159
328
  // User-defined plugins from agentuity.config.ts (framework plugin + extras)
160
329
  ...resolvedUserPlugins,
161
330
  // Browser env plugin to map process.env to import.meta.env
162
331
  browserEnvPlugin(),
163
332
  // Warn about incorrect public asset paths in dev mode
164
333
  publicAssetPathPlugin({ warnInDev: true }),
334
+ // Inject analytics scripts in dev HTML
335
+ devAnalyticsPlugin(),
336
+ // SPA fallback: serve src/web/index.html for navigation requests
337
+ spaFallbackPlugin(rootDir, routePaths, workbenchPath),
165
338
  ];
166
339
  })(),
167
340
 
@@ -1,8 +1,9 @@
1
1
  /**
2
- * Vite Asset Server
2
+ * Vite Dev Server (Primary)
3
3
  *
4
- * Starts a minimal Vite dev server for frontend asset transformation and HMR only.
5
- * Does NOT handle API routes or WebSocket - the Bun server proxies to this.
4
+ * Starts Vite as the primary dev server on the user-facing port.
5
+ * Serves frontend assets natively and proxies API/WebSocket requests
6
+ * to the Bun backend server.
6
7
  */
7
8
 
8
9
  import { join } from 'node:path';
@@ -21,6 +22,10 @@ export interface StartViteAssetServerOptions {
21
22
  rootDir: string;
22
23
  logger: Logger;
23
24
  workbenchPath?: string;
25
+ port?: number; // Preferred user-facing port (default: 3500)
26
+ backendPort: number; // Port of the Bun backend server
27
+ /** User-defined route mount paths from createApp({ router }) */
28
+ routePaths?: string[];
24
29
  }
25
30
 
26
31
  /**
@@ -68,27 +73,34 @@ async function findAvailablePort(
68
73
  export async function startViteAssetServer(
69
74
  options: StartViteAssetServerOptions
70
75
  ): Promise<ViteAssetServerResult> {
71
- const { rootDir, logger, workbenchPath } = options;
76
+ const {
77
+ rootDir,
78
+ logger,
79
+ workbenchPath,
80
+ port: preferredPort = 3500,
81
+ backendPort,
82
+ routePaths,
83
+ } = options;
72
84
 
73
- logger.debug('Starting Vite asset server (HMR only)...');
85
+ logger.debug('Starting Vite dev server (primary, proxying backend on port %d)...', backendPort);
74
86
 
75
- // Find an available port before starting Vite
76
- // This avoids relying on Vite's strictPort:false fallback which can fail
77
- const preferredPort = 5173;
87
+ // Find an available port for the user-facing Vite server
78
88
  const availablePort = await findAvailablePort(preferredPort, '127.0.0.1');
79
89
 
80
90
  if (availablePort !== preferredPort) {
81
91
  logger.info(
82
- `Port ${preferredPort} is in use, using port ${availablePort} for Vite asset server`
92
+ `Port ${preferredPort} is in use, using port ${availablePort} for Vite dev server`
83
93
  );
84
94
  }
85
95
 
86
- // Generate minimal config with the available port
96
+ // Generate config with proxy to Bun backend
87
97
  const config = await generateAssetServerConfig({
88
98
  rootDir,
89
99
  logger,
90
100
  workbenchPath,
91
101
  port: availablePort,
102
+ backendPort,
103
+ routePaths,
92
104
  });
93
105
 
94
106
  // Dynamically import vite from the project's node_modules
@@ -130,11 +142,9 @@ export async function startViteAssetServer(
130
142
  // Port was pre-verified and strictPort:true ensures Vite uses exactly this port
131
143
  const actualPort = availablePort;
132
144
 
133
- logger.info(`Vite asset server running on port ${actualPort}`);
134
- logger.debug(`Asset server will handle: HMR, React transformation, source maps`);
135
- logger.debug(
136
- `HMR WebSocket configured at /__vite_hmr (proxied through Bun server for tunnel support)`
137
- );
145
+ logger.debug(`Vite dev server running on port ${actualPort} (primary)`);
146
+ logger.debug(`Frontend: HMR, React transformation, source maps (native)`);
147
+ logger.debug(`Backend: proxying to Bun on port ${backendPort}`);
138
148
 
139
149
  return { server, port: actualPort };
140
150
  }
@@ -10,7 +10,6 @@ import { createRequire } from 'node:module';
10
10
  import type { InlineConfig, Plugin } from 'vite';
11
11
  import type { Logger, DeployOptions } from '../../../types';
12
12
  import { browserEnvPlugin } from './browser-env-plugin';
13
- import { tailwindSourcePlugin } from './tailwind-source-plugin';
14
13
  import { beaconPlugin } from './beacon-plugin';
15
14
  import { publicAssetPathPlugin } from './public-asset-path-plugin';
16
15
  import type { BuildReportCollector } from '../../../build-report';
@@ -75,25 +74,7 @@ export interface ViteBuildOptions {
75
74
  * Uses inline Vite config (customizable via agentuity.config.ts)
76
75
  */
77
76
  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
- }
77
+ const { rootDir, mode, dev = false, deploymentId = '', logger, profile } = options;
97
78
 
98
79
  logger.debug(`Running Vite build for mode: ${mode}`);
99
80
 
@@ -126,24 +107,7 @@ export async function runViteBuild(options: ViteBuildOptions): Promise<void> {
126
107
  profile,
127
108
  });
128
109
 
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
110
+ // Build with Bun.build (app.ts is the entrypoint)
147
111
  const { installExternalsAndBuild } = await import('./server-bundler');
148
112
  await installExternalsAndBuild({
149
113
  rootDir,
@@ -210,7 +174,6 @@ export async function runViteBuild(options: ViteBuildOptions): Promise<void> {
210
174
  }
211
175
 
212
176
  const plugins = [
213
- tailwindSourcePlugin(),
214
177
  ...userPlugins,
215
178
  browserEnvPlugin(),
216
179
  // Fix incorrect public asset paths and rewrite to CDN URLs
@@ -257,7 +220,7 @@ export async function runViteBuild(options: ViteBuildOptions): Promise<void> {
257
220
  // In dev mode, Vite serves them directly from src/web/public/
258
221
  copyPublicDir: !dev,
259
222
  },
260
- logLevel: isViteDebug ? 'info' : 'warn',
223
+ logLevel: 'warn',
261
224
  };
262
225
  } else if (mode === 'workbench') {
263
226
  const { workbenchRoute = '/workbench' } = options;
@@ -292,7 +255,7 @@ export async function runViteBuild(options: ViteBuildOptions): Promise<void> {
292
255
  manifest: true,
293
256
  emptyOutDir: true,
294
257
  },
295
- logLevel: isViteDebug ? 'info' : 'warn',
258
+ logLevel: 'warn',
296
259
  };
297
260
  } else {
298
261
  throw new Error(`Unknown build mode: ${mode}`);
@@ -358,7 +321,6 @@ export async function runAllBuilds(options: Omit<ViteBuildOptions, 'mode'>): Pro
358
321
 
359
322
  // 1. Discover agents and routes BEFORE builds
360
323
  logger.debug('Discovering agents and routes...');
361
- const { generateAgentRegistry, generateRouteRegistry } = await import('./registry-generator');
362
324
  const { discoverAgents } = await import('./agent-discovery');
363
325
  const { discoverRoutes } = await import('./route-discovery');
364
326
 
@@ -369,18 +331,9 @@ export async function runAllBuilds(options: Omit<ViteBuildOptions, 'mode'>): Pro
369
331
  options.deploymentId || '',
370
332
  logger
371
333
  );
372
- const { routes, routeInfoList } = await discoverRoutes(
373
- srcDir,
374
- projectId,
375
- options.deploymentId || '',
376
- logger
377
- );
334
+ const { routes } = await discoverRoutes(srcDir, projectId, options.deploymentId || '', logger);
378
335
 
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');
336
+ // Agent metadata is used for metadata.json generation (no registry codegen needed)
384
337
 
385
338
  // Check if web frontend exists
386
339
  const hasWebFrontend = await Bun.file(join(rootDir, 'src', 'web', 'index.html')).exists();
@@ -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...');
@@ -804,7 +804,6 @@ export const deploySubcommand = createSubcommand({
804
804
  duplex: 'half',
805
805
  headers: {
806
806
  'Content-Type': 'application/zip',
807
- 'Content-Length': String(fileSize),
808
807
  },
809
808
  body: zipfile,
810
809
  signal: stepCtx.signal,
@@ -8,7 +8,7 @@
8
8
  import { watch, type FSWatcher, statSync, readdirSync, lstatSync } from 'node:fs';
9
9
  import { resolve, relative } from 'node:path';
10
10
  import type { Logger } from '../../types';
11
- import { createAgentTemplates, createAPITemplates } from './templates';
11
+ import { createAgentTemplates } from './templates';
12
12
 
13
13
  export interface FileWatcherOptions {
14
14
  rootDir: string;
@@ -219,7 +219,7 @@ export function createFileWatcher(options: FileWatcherOptions): FileWatcherManag
219
219
  isDirectory = false;
220
220
  }
221
221
 
222
- // Check if an empty directory was created in src/agent/ or src/api/
222
+ // Check if an empty directory was created in src/agent/
223
223
  // This helps with developer experience by auto-scaffolding template files
224
224
  if (changedFile && eventType === 'rename' && isDirectory) {
225
225
  try {
@@ -229,19 +229,12 @@ export function createFileWatcher(options: FileWatcherOptions): FileWatcherManag
229
229
  // Check if it's empty
230
230
  const contents = readdirSync(absPath);
231
231
  if (contents.length === 0) {
232
- // Check if this is an agent or API directory
233
232
  if (
234
233
  normalizedPath.startsWith('src/agent/') ||
235
234
  normalizedPath.includes('/src/agent/')
236
235
  ) {
237
236
  logger.debug('Agent directory created: %s', changedFile);
238
237
  createAgentTemplates(absPath);
239
- } else if (
240
- normalizedPath.startsWith('src/api/') ||
241
- normalizedPath.includes('/src/api/')
242
- ) {
243
- logger.debug('API directory created: %s', changedFile);
244
- createAPITemplates(absPath);
245
238
  }
246
239
  }
247
240
  } catch (error) {