@agentuity/cli 1.0.47 → 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.
- package/dist/cmd/build/app-router-detector.d.ts +2 -5
- package/dist/cmd/build/app-router-detector.d.ts.map +1 -1
- package/dist/cmd/build/app-router-detector.js +130 -154
- package/dist/cmd/build/app-router-detector.js.map +1 -1
- package/dist/cmd/build/ids.d.ts +11 -0
- package/dist/cmd/build/ids.d.ts.map +1 -0
- package/dist/cmd/build/ids.js +18 -0
- package/dist/cmd/build/ids.js.map +1 -0
- package/dist/cmd/build/vite/agent-discovery.d.ts +8 -4
- package/dist/cmd/build/vite/agent-discovery.d.ts.map +1 -1
- package/dist/cmd/build/vite/agent-discovery.js +166 -487
- package/dist/cmd/build/vite/agent-discovery.js.map +1 -1
- package/dist/cmd/build/vite/bun-dev-server.d.ts +10 -16
- package/dist/cmd/build/vite/bun-dev-server.d.ts.map +1 -1
- package/dist/cmd/build/vite/bun-dev-server.js +67 -134
- package/dist/cmd/build/vite/bun-dev-server.js.map +1 -1
- package/dist/cmd/build/vite/docs-generator.d.ts.map +1 -1
- package/dist/cmd/build/vite/docs-generator.js +0 -2
- package/dist/cmd/build/vite/docs-generator.js.map +1 -1
- package/dist/cmd/build/vite/index.d.ts.map +1 -1
- package/dist/cmd/build/vite/index.js +0 -36
- package/dist/cmd/build/vite/index.js.map +1 -1
- package/dist/cmd/build/vite/lifecycle-generator.d.ts +10 -2
- package/dist/cmd/build/vite/lifecycle-generator.d.ts.map +1 -1
- package/dist/cmd/build/vite/lifecycle-generator.js +302 -23
- package/dist/cmd/build/vite/lifecycle-generator.js.map +1 -1
- package/dist/cmd/build/vite/route-discovery.d.ts +11 -38
- package/dist/cmd/build/vite/route-discovery.d.ts.map +1 -1
- package/dist/cmd/build/vite/route-discovery.js +97 -177
- package/dist/cmd/build/vite/route-discovery.js.map +1 -1
- package/dist/cmd/build/vite/server-bundler.js +1 -1
- package/dist/cmd/build/vite/server-bundler.js.map +1 -1
- package/dist/cmd/build/vite/static-renderer.d.ts.map +1 -1
- package/dist/cmd/build/vite/static-renderer.js +1 -9
- package/dist/cmd/build/vite/static-renderer.js.map +1 -1
- package/dist/cmd/build/vite/vite-asset-server-config.d.ts +6 -3
- package/dist/cmd/build/vite/vite-asset-server-config.d.ts.map +1 -1
- package/dist/cmd/build/vite/vite-asset-server-config.js +171 -18
- package/dist/cmd/build/vite/vite-asset-server-config.js.map +1 -1
- package/dist/cmd/build/vite/vite-asset-server.d.ts +8 -3
- package/dist/cmd/build/vite/vite-asset-server.d.ts.map +1 -1
- package/dist/cmd/build/vite/vite-asset-server.js +14 -13
- package/dist/cmd/build/vite/vite-asset-server.js.map +1 -1
- package/dist/cmd/build/vite/vite-builder.d.ts.map +1 -1
- package/dist/cmd/build/vite/vite-builder.js +6 -34
- package/dist/cmd/build/vite/vite-builder.js.map +1 -1
- package/dist/cmd/build/vite/ws-proxy.d.ts +53 -0
- package/dist/cmd/build/vite/ws-proxy.d.ts.map +1 -0
- package/dist/cmd/build/vite/ws-proxy.js +95 -0
- package/dist/cmd/build/vite/ws-proxy.js.map +1 -0
- package/dist/cmd/build/vite-bundler.d.ts.map +1 -1
- package/dist/cmd/build/vite-bundler.js +0 -3
- package/dist/cmd/build/vite-bundler.js.map +1 -1
- package/dist/cmd/dev/file-watcher.d.ts.map +1 -1
- package/dist/cmd/dev/file-watcher.js +2 -8
- package/dist/cmd/dev/file-watcher.js.map +1 -1
- package/dist/cmd/dev/index.d.ts.map +1 -1
- package/dist/cmd/dev/index.js +369 -720
- package/dist/cmd/dev/index.js.map +1 -1
- package/package.json +6 -8
- package/src/cmd/ai/prompt/agent.md +0 -1
- package/src/cmd/ai/prompt/api.md +0 -7
- package/src/cmd/ai/prompt/web.md +51 -213
- package/src/cmd/build/app-router-detector.ts +152 -182
- package/src/cmd/build/ids.ts +19 -0
- package/src/cmd/build/vite/agent-discovery.ts +208 -679
- package/src/cmd/build/vite/bun-dev-server.ts +78 -154
- package/src/cmd/build/vite/docs-generator.ts +0 -2
- package/src/cmd/build/vite/index.ts +1 -42
- package/src/cmd/build/vite/lifecycle-generator.ts +345 -21
- package/src/cmd/build/vite/route-discovery.ts +116 -274
- package/src/cmd/build/vite/server-bundler.ts +1 -1
- package/src/cmd/build/vite/static-renderer.ts +1 -11
- package/src/cmd/build/vite/vite-asset-server-config.ts +196 -20
- package/src/cmd/build/vite/vite-asset-server.ts +25 -15
- package/src/cmd/build/vite/vite-builder.ts +6 -51
- package/src/cmd/build/vite/ws-proxy.ts +126 -0
- package/src/cmd/build/vite-bundler.ts +0 -4
- package/src/cmd/dev/file-watcher.ts +2 -9
- package/src/cmd/dev/index.ts +409 -832
- package/dist/cmd/build/ast.d.ts +0 -78
- package/dist/cmd/build/ast.d.ts.map +0 -1
- package/dist/cmd/build/ast.js +0 -2703
- package/dist/cmd/build/ast.js.map +0 -1
- package/dist/cmd/build/entry-generator.d.ts +0 -25
- package/dist/cmd/build/entry-generator.d.ts.map +0 -1
- package/dist/cmd/build/entry-generator.js +0 -695
- package/dist/cmd/build/entry-generator.js.map +0 -1
- package/dist/cmd/build/vite/api-mount-path.d.ts +0 -61
- package/dist/cmd/build/vite/api-mount-path.d.ts.map +0 -1
- package/dist/cmd/build/vite/api-mount-path.js +0 -83
- package/dist/cmd/build/vite/api-mount-path.js.map +0 -1
- package/dist/cmd/build/vite/registry-generator.d.ts +0 -19
- package/dist/cmd/build/vite/registry-generator.d.ts.map +0 -1
- package/dist/cmd/build/vite/registry-generator.js +0 -1108
- package/dist/cmd/build/vite/registry-generator.js.map +0 -1
- package/dist/cmd/build/webanalytics-generator.d.ts +0 -16
- package/dist/cmd/build/webanalytics-generator.d.ts.map +0 -1
- package/dist/cmd/build/webanalytics-generator.js +0 -178
- package/dist/cmd/build/webanalytics-generator.js.map +0 -1
- package/dist/cmd/build/workbench.d.ts +0 -7
- package/dist/cmd/build/workbench.d.ts.map +0 -1
- package/dist/cmd/build/workbench.js +0 -55
- package/dist/cmd/build/workbench.js.map +0 -1
- package/dist/utils/route-migration.d.ts +0 -62
- package/dist/utils/route-migration.d.ts.map +0 -1
- package/dist/utils/route-migration.js +0 -630
- package/dist/utils/route-migration.js.map +0 -1
- package/src/cmd/build/ast.ts +0 -3529
- package/src/cmd/build/entry-generator.ts +0 -760
- package/src/cmd/build/vite/api-mount-path.ts +0 -87
- package/src/cmd/build/vite/registry-generator.ts +0 -1267
- package/src/cmd/build/webanalytics-generator.ts +0 -197
- package/src/cmd/build/workbench.ts +0 -58
- package/src/utils/route-migration.ts +0 -757
|
@@ -1,20 +1,163 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Vite
|
|
2
|
+
* Vite Dev Server Configuration
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
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
|
|
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
|
-
//
|
|
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
|
-
//
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
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
|
|
105
|
-
//
|
|
106
|
-
|
|
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
|
|
285
|
+
// Don't open browser automatically
|
|
114
286
|
open: false,
|
|
115
287
|
},
|
|
116
288
|
|
|
@@ -159,6 +331,10 @@ export async function generateAssetServerConfig(
|
|
|
159
331
|
browserEnvPlugin(),
|
|
160
332
|
// Warn about incorrect public asset paths in dev mode
|
|
161
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),
|
|
162
338
|
];
|
|
163
339
|
})(),
|
|
164
340
|
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Vite
|
|
2
|
+
* Vite Dev Server (Primary)
|
|
3
3
|
*
|
|
4
|
-
* Starts
|
|
5
|
-
*
|
|
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 {
|
|
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
|
|
85
|
+
logger.debug('Starting Vite dev server (primary, proxying backend on port %d)...', backendPort);
|
|
74
86
|
|
|
75
|
-
// Find an available port
|
|
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
|
|
92
|
+
`Port ${preferredPort} is in use, using port ${availablePort} for Vite dev server`
|
|
83
93
|
);
|
|
84
94
|
}
|
|
85
95
|
|
|
86
|
-
// Generate
|
|
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.
|
|
134
|
-
logger.debug(`
|
|
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
|
}
|
|
@@ -74,25 +74,7 @@ export interface ViteBuildOptions {
|
|
|
74
74
|
* Uses inline Vite config (customizable via agentuity.config.ts)
|
|
75
75
|
*/
|
|
76
76
|
export async function runViteBuild(options: ViteBuildOptions): Promise<void> {
|
|
77
|
-
const {
|
|
78
|
-
rootDir,
|
|
79
|
-
mode,
|
|
80
|
-
dev = false,
|
|
81
|
-
projectId = '',
|
|
82
|
-
deploymentId = '',
|
|
83
|
-
logger,
|
|
84
|
-
profile,
|
|
85
|
-
} = options;
|
|
86
|
-
|
|
87
|
-
const isViteDebug =
|
|
88
|
-
process.env.AGENTUITY_VITE_DEBUG === '1' || process.env.AGENTUITY_VITE_DEBUG === 'true';
|
|
89
|
-
if (isViteDebug) {
|
|
90
|
-
logger.debug('Vite debug logging enabled via AGENTUITY_VITE_DEBUG');
|
|
91
|
-
const existing = process.env.DEBUG || '';
|
|
92
|
-
if (!existing.includes('vite:')) {
|
|
93
|
-
process.env.DEBUG = existing ? `${existing},vite:*` : 'vite:*';
|
|
94
|
-
}
|
|
95
|
-
}
|
|
77
|
+
const { rootDir, mode, dev = false, deploymentId = '', logger, profile } = options;
|
|
96
78
|
|
|
97
79
|
logger.debug(`Running Vite build for mode: ${mode}`);
|
|
98
80
|
|
|
@@ -125,24 +107,7 @@ export async function runViteBuild(options: ViteBuildOptions): Promise<void> {
|
|
|
125
107
|
profile,
|
|
126
108
|
});
|
|
127
109
|
|
|
128
|
-
//
|
|
129
|
-
const { loadAgentuityConfig, getWorkbenchConfig } = await import('./config-loader');
|
|
130
|
-
const config = await loadAgentuityConfig(rootDir, logger);
|
|
131
|
-
const workbenchConfig = getWorkbenchConfig(config, dev);
|
|
132
|
-
|
|
133
|
-
// Then, generate the entry file
|
|
134
|
-
const { generateEntryFile } = await import('../entry-generator');
|
|
135
|
-
await generateEntryFile({
|
|
136
|
-
rootDir,
|
|
137
|
-
projectId,
|
|
138
|
-
deploymentId: deploymentId || '',
|
|
139
|
-
logger,
|
|
140
|
-
mode: dev ? 'dev' : 'prod',
|
|
141
|
-
workbench: workbenchConfig.configured ? workbenchConfig : undefined,
|
|
142
|
-
analytics: config?.analytics,
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
// Finally, build with Bun.build
|
|
110
|
+
// Build with Bun.build (app.ts is the entrypoint)
|
|
146
111
|
const { installExternalsAndBuild } = await import('./server-bundler');
|
|
147
112
|
await installExternalsAndBuild({
|
|
148
113
|
rootDir,
|
|
@@ -255,7 +220,7 @@ export async function runViteBuild(options: ViteBuildOptions): Promise<void> {
|
|
|
255
220
|
// In dev mode, Vite serves them directly from src/web/public/
|
|
256
221
|
copyPublicDir: !dev,
|
|
257
222
|
},
|
|
258
|
-
logLevel:
|
|
223
|
+
logLevel: 'warn',
|
|
259
224
|
};
|
|
260
225
|
} else if (mode === 'workbench') {
|
|
261
226
|
const { workbenchRoute = '/workbench' } = options;
|
|
@@ -290,7 +255,7 @@ export async function runViteBuild(options: ViteBuildOptions): Promise<void> {
|
|
|
290
255
|
manifest: true,
|
|
291
256
|
emptyOutDir: true,
|
|
292
257
|
},
|
|
293
|
-
logLevel:
|
|
258
|
+
logLevel: 'warn',
|
|
294
259
|
};
|
|
295
260
|
} else {
|
|
296
261
|
throw new Error(`Unknown build mode: ${mode}`);
|
|
@@ -356,7 +321,6 @@ export async function runAllBuilds(options: Omit<ViteBuildOptions, 'mode'>): Pro
|
|
|
356
321
|
|
|
357
322
|
// 1. Discover agents and routes BEFORE builds
|
|
358
323
|
logger.debug('Discovering agents and routes...');
|
|
359
|
-
const { generateAgentRegistry, generateRouteRegistry } = await import('./registry-generator');
|
|
360
324
|
const { discoverAgents } = await import('./agent-discovery');
|
|
361
325
|
const { discoverRoutes } = await import('./route-discovery');
|
|
362
326
|
|
|
@@ -367,18 +331,9 @@ export async function runAllBuilds(options: Omit<ViteBuildOptions, 'mode'>): Pro
|
|
|
367
331
|
options.deploymentId || '',
|
|
368
332
|
logger
|
|
369
333
|
);
|
|
370
|
-
const { routes
|
|
371
|
-
srcDir,
|
|
372
|
-
projectId,
|
|
373
|
-
options.deploymentId || '',
|
|
374
|
-
logger
|
|
375
|
-
);
|
|
334
|
+
const { routes } = await discoverRoutes(srcDir, projectId, options.deploymentId || '', logger);
|
|
376
335
|
|
|
377
|
-
//
|
|
378
|
-
// (TypeScript needs these files to exist during type checking)
|
|
379
|
-
generateAgentRegistry(srcDir, agentMetadata);
|
|
380
|
-
await generateRouteRegistry(srcDir, routeInfoList);
|
|
381
|
-
logger.debug('Agent and route registries generated');
|
|
336
|
+
// Agent metadata is used for metadata.json generation (no registry codegen needed)
|
|
382
337
|
|
|
383
338
|
// Check if web frontend exists
|
|
384
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...');
|
|
@@ -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
|
|
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/
|
|
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) {
|