@agentuity/cli 0.1.42 → 0.1.44
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/auth.d.ts +2 -2
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +7 -5
- package/dist/auth.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +24 -12
- package/dist/cli.js.map +1 -1
- package/dist/cmd/build/entry-generator.d.ts.map +1 -1
- package/dist/cmd/build/entry-generator.js +163 -18
- package/dist/cmd/build/entry-generator.js.map +1 -1
- package/dist/cmd/build/vite/metadata-generator.d.ts.map +1 -1
- package/dist/cmd/build/vite/metadata-generator.js +19 -9
- package/dist/cmd/build/vite/metadata-generator.js.map +1 -1
- package/dist/cmd/build/vite/public-asset-path-plugin.d.ts +24 -15
- package/dist/cmd/build/vite/public-asset-path-plugin.d.ts.map +1 -1
- package/dist/cmd/build/vite/public-asset-path-plugin.js +92 -47
- package/dist/cmd/build/vite/public-asset-path-plugin.js.map +1 -1
- package/dist/cmd/build/vite/vite-asset-server-config.d.ts.map +1 -1
- package/dist/cmd/build/vite/vite-asset-server-config.js +9 -6
- package/dist/cmd/build/vite/vite-asset-server-config.js.map +1 -1
- package/dist/cmd/build/vite/vite-asset-server.d.ts.map +1 -1
- package/dist/cmd/build/vite/vite-asset-server.js +1 -1
- 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 +12 -11
- package/dist/cmd/build/vite/vite-builder.js.map +1 -1
- package/dist/cmd/cloud/env/org-util.d.ts +2 -1
- package/dist/cmd/cloud/env/org-util.d.ts.map +1 -1
- package/dist/cmd/cloud/env/org-util.js +4 -2
- package/dist/cmd/cloud/env/org-util.js.map +1 -1
- package/dist/cmd/cloud/stream/create.d.ts +3 -0
- package/dist/cmd/cloud/stream/create.d.ts.map +1 -0
- package/dist/cmd/cloud/stream/create.js +227 -0
- package/dist/cmd/cloud/stream/create.js.map +1 -0
- package/dist/cmd/cloud/stream/delete.d.ts.map +1 -1
- package/dist/cmd/cloud/stream/delete.js +2 -1
- package/dist/cmd/cloud/stream/delete.js.map +1 -1
- package/dist/cmd/cloud/stream/get.d.ts.map +1 -1
- package/dist/cmd/cloud/stream/get.js +2 -1
- package/dist/cmd/cloud/stream/get.js.map +1 -1
- package/dist/cmd/cloud/stream/index.d.ts.map +1 -1
- package/dist/cmd/cloud/stream/index.js +10 -1
- package/dist/cmd/cloud/stream/index.js.map +1 -1
- package/dist/cmd/cloud/stream/list.d.ts.map +1 -1
- package/dist/cmd/cloud/stream/list.js +2 -1
- package/dist/cmd/cloud/stream/list.js.map +1 -1
- package/dist/cmd/cloud/stream/util.d.ts +6 -5
- package/dist/cmd/cloud/stream/util.d.ts.map +1 -1
- package/dist/cmd/cloud/stream/util.js +26 -5
- package/dist/cmd/cloud/stream/util.js.map +1 -1
- package/dist/cmd/support/report.d.ts.map +1 -1
- package/dist/cmd/support/report.js +58 -23
- package/dist/cmd/support/report.js.map +1 -1
- package/dist/cmd/upgrade/index.d.ts.map +1 -1
- package/dist/cmd/upgrade/index.js +23 -0
- package/dist/cmd/upgrade/index.js.map +1 -1
- package/dist/cmd/upgrade/npm-availability.d.ts +44 -0
- package/dist/cmd/upgrade/npm-availability.d.ts.map +1 -0
- package/dist/cmd/upgrade/npm-availability.js +73 -0
- package/dist/cmd/upgrade/npm-availability.js.map +1 -0
- package/dist/internal-logger.d.ts +7 -0
- package/dist/internal-logger.d.ts.map +1 -1
- package/dist/internal-logger.js +82 -28
- package/dist/internal-logger.js.map +1 -1
- package/dist/tui.d.ts +9 -1
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +39 -14
- package/dist/tui.js.map +1 -1
- package/dist/version-check.d.ts.map +1 -1
- package/dist/version-check.js +13 -2
- package/dist/version-check.js.map +1 -1
- package/package.json +8 -7
- package/src/auth.ts +9 -5
- package/src/cli.ts +44 -12
- package/src/cmd/build/entry-generator.ts +163 -18
- package/src/cmd/build/vite/metadata-generator.ts +20 -9
- package/src/cmd/build/vite/public-asset-path-plugin.ts +105 -53
- package/src/cmd/build/vite/vite-asset-server-config.ts +9 -6
- package/src/cmd/build/vite/vite-asset-server.ts +3 -1
- package/src/cmd/build/vite/vite-builder.ts +21 -20
- package/src/cmd/cloud/env/org-util.ts +5 -2
- package/src/cmd/cloud/stream/create.ts +248 -0
- package/src/cmd/cloud/stream/delete.ts +2 -1
- package/src/cmd/cloud/stream/get.ts +2 -1
- package/src/cmd/cloud/stream/index.ts +10 -1
- package/src/cmd/cloud/stream/list.ts +2 -1
- package/src/cmd/cloud/stream/util.ts +39 -12
- package/src/cmd/support/report.ts +82 -28
- package/src/cmd/upgrade/index.ts +25 -0
- package/src/cmd/upgrade/npm-availability.ts +105 -0
- package/src/internal-logger.ts +91 -27
- package/src/tui.ts +42 -14
- package/src/version-check.ts +19 -3
package/src/cli.ts
CHANGED
|
@@ -1198,9 +1198,12 @@ async function registerSubcommand(
|
|
|
1198
1198
|
// Recreate apiClient with auth credentials
|
|
1199
1199
|
ctx.apiClient = createAPIClient(baseCtx, ctx.config as Config | null);
|
|
1200
1200
|
}
|
|
1201
|
+
// Auto-select org when --confirm flag is used
|
|
1202
|
+
const autoSelectOrg = options.confirm === true;
|
|
1201
1203
|
if (normalized.requiresOrg) {
|
|
1202
1204
|
ctx.orgId = await requireOrg(
|
|
1203
|
-
ctx as CommandContext & { apiClient: APIClientType }
|
|
1205
|
+
ctx as CommandContext & { apiClient: APIClientType },
|
|
1206
|
+
autoSelectOrg
|
|
1204
1207
|
);
|
|
1205
1208
|
}
|
|
1206
1209
|
// Skip org handling if --no-register is set (org only needed for registration)
|
|
@@ -1212,7 +1215,8 @@ async function registerSubcommand(
|
|
|
1212
1215
|
|
|
1213
1216
|
if (normalized.optionalOrg && ctx.auth && !skipOrg) {
|
|
1214
1217
|
ctx.orgId = await selectOptionalOrg(
|
|
1215
|
-
ctx as CommandContext & { apiClient: APIClientType }
|
|
1218
|
+
ctx as CommandContext & { apiClient: APIClientType },
|
|
1219
|
+
autoSelectOrg
|
|
1216
1220
|
);
|
|
1217
1221
|
}
|
|
1218
1222
|
// Skip region handling if --no-register is set (region only needed for registration)
|
|
@@ -1302,8 +1306,13 @@ async function registerSubcommand(
|
|
|
1302
1306
|
// Recreate apiClient with auth credentials
|
|
1303
1307
|
ctx.apiClient = createAPIClient(baseCtx, ctx.config as Config | null);
|
|
1304
1308
|
}
|
|
1309
|
+
// Auto-select org when --confirm flag is used
|
|
1310
|
+
const autoSelectOrg2 = options.confirm === true;
|
|
1305
1311
|
if (normalized.requiresOrg) {
|
|
1306
|
-
ctx.orgId = await requireOrg(
|
|
1312
|
+
ctx.orgId = await requireOrg(
|
|
1313
|
+
ctx as CommandContext & { apiClient: APIClientType },
|
|
1314
|
+
autoSelectOrg2
|
|
1315
|
+
);
|
|
1307
1316
|
}
|
|
1308
1317
|
// Skip org handling if --no-register is set (org only needed for registration)
|
|
1309
1318
|
const skipOrg =
|
|
@@ -1314,7 +1323,8 @@ async function registerSubcommand(
|
|
|
1314
1323
|
|
|
1315
1324
|
if (normalized.optionalOrg && ctx.auth && !skipOrg) {
|
|
1316
1325
|
ctx.orgId = await selectOptionalOrg(
|
|
1317
|
-
ctx as CommandContext & { apiClient: APIClientType }
|
|
1326
|
+
ctx as CommandContext & { apiClient: APIClientType },
|
|
1327
|
+
autoSelectOrg2
|
|
1318
1328
|
);
|
|
1319
1329
|
}
|
|
1320
1330
|
// Skip region handling if --no-register is set (region only needed for registration)
|
|
@@ -1454,9 +1464,12 @@ async function registerSubcommand(
|
|
|
1454
1464
|
!!ctx.apiClient,
|
|
1455
1465
|
!!auth
|
|
1456
1466
|
);
|
|
1467
|
+
// Auto-select org when --confirm flag is used
|
|
1468
|
+
const autoSelectOrg3 = options.confirm === true;
|
|
1457
1469
|
if (normalized.requiresOrg && ctx.apiClient) {
|
|
1458
1470
|
ctx.orgId = await requireOrg(
|
|
1459
|
-
ctx as CommandContext & { apiClient: APIClientType }
|
|
1471
|
+
ctx as CommandContext & { apiClient: APIClientType },
|
|
1472
|
+
autoSelectOrg3
|
|
1460
1473
|
);
|
|
1461
1474
|
}
|
|
1462
1475
|
// Skip org handling if --no-register is set (org only needed for registration)
|
|
@@ -1468,7 +1481,8 @@ async function registerSubcommand(
|
|
|
1468
1481
|
|
|
1469
1482
|
if (normalized.optionalOrg && ctx.apiClient && auth && !skipOrg) {
|
|
1470
1483
|
ctx.orgId = await selectOptionalOrg(
|
|
1471
|
-
ctx as CommandContext & { apiClient?: APIClientType; auth?: AuthData }
|
|
1484
|
+
ctx as CommandContext & { apiClient?: APIClientType; auth?: AuthData },
|
|
1485
|
+
autoSelectOrg3
|
|
1472
1486
|
);
|
|
1473
1487
|
baseCtx.logger.trace('selected orgId: %s', ctx.orgId);
|
|
1474
1488
|
}
|
|
@@ -1551,8 +1565,13 @@ async function registerSubcommand(
|
|
|
1551
1565
|
// Recreate apiClient with auth credentials if auth was provided
|
|
1552
1566
|
ctx.apiClient = createAPIClient(baseCtx, ctx.config as Config | null);
|
|
1553
1567
|
}
|
|
1568
|
+
// Auto-select org when --confirm flag is used
|
|
1569
|
+
const autoSelectOrg4 = options.confirm === true;
|
|
1554
1570
|
if (normalized.requiresOrg && ctx.apiClient) {
|
|
1555
|
-
ctx.orgId = await requireOrg(
|
|
1571
|
+
ctx.orgId = await requireOrg(
|
|
1572
|
+
ctx as CommandContext & { apiClient: APIClientType },
|
|
1573
|
+
autoSelectOrg4
|
|
1574
|
+
);
|
|
1556
1575
|
}
|
|
1557
1576
|
// Skip org handling if --no-register is set (org only needed for registration)
|
|
1558
1577
|
// For non-schema commands, check options directly (Commander passes all options)
|
|
@@ -1563,7 +1582,8 @@ async function registerSubcommand(
|
|
|
1563
1582
|
|
|
1564
1583
|
if (normalized.optionalOrg && ctx.apiClient && !skipOrg) {
|
|
1565
1584
|
ctx.orgId = await selectOptionalOrg(
|
|
1566
|
-
ctx as CommandContext & { apiClient?: APIClientType; auth?: AuthData }
|
|
1585
|
+
ctx as CommandContext & { apiClient?: APIClientType; auth?: AuthData },
|
|
1586
|
+
autoSelectOrg4
|
|
1567
1587
|
);
|
|
1568
1588
|
}
|
|
1569
1589
|
// Skip region handling if --no-register is set (region only needed for registration)
|
|
@@ -1656,14 +1676,18 @@ async function registerSubcommand(
|
|
|
1656
1676
|
if (normalized.requiresAPIClient && !ctx.apiClient) {
|
|
1657
1677
|
ctx.apiClient = createAPIClient(baseCtx, ctx.config as Config | null);
|
|
1658
1678
|
}
|
|
1679
|
+
// Auto-select org when --confirm flag is used
|
|
1680
|
+
const autoSelectOrg5 = options.confirm === true;
|
|
1659
1681
|
if (normalized.requiresOrg && ctx.apiClient) {
|
|
1660
1682
|
ctx.orgId = await requireOrg(
|
|
1661
|
-
ctx as CommandContext & { apiClient: APIClientType }
|
|
1683
|
+
ctx as CommandContext & { apiClient: APIClientType },
|
|
1684
|
+
autoSelectOrg5
|
|
1662
1685
|
);
|
|
1663
1686
|
}
|
|
1664
1687
|
if (normalized.optionalOrg && ctx.apiClient && ctx.auth) {
|
|
1665
1688
|
ctx.orgId = await requireOrg(
|
|
1666
|
-
ctx as CommandContext & { apiClient: APIClientType }
|
|
1689
|
+
ctx as CommandContext & { apiClient: APIClientType },
|
|
1690
|
+
autoSelectOrg5
|
|
1667
1691
|
);
|
|
1668
1692
|
}
|
|
1669
1693
|
await executeOrValidate(
|
|
@@ -1697,11 +1721,19 @@ async function registerSubcommand(
|
|
|
1697
1721
|
if (normalized.requiresAPIClient && !ctx.apiClient) {
|
|
1698
1722
|
ctx.apiClient = createAPIClient(baseCtx, ctx.config as Config | null);
|
|
1699
1723
|
}
|
|
1724
|
+
// Auto-select org when --confirm flag is used
|
|
1725
|
+
const autoSelectOrg6 = options.confirm === true;
|
|
1700
1726
|
if (normalized.requiresOrg && ctx.apiClient) {
|
|
1701
|
-
ctx.orgId = await requireOrg(
|
|
1727
|
+
ctx.orgId = await requireOrg(
|
|
1728
|
+
ctx as CommandContext & { apiClient: APIClientType },
|
|
1729
|
+
autoSelectOrg6
|
|
1730
|
+
);
|
|
1702
1731
|
}
|
|
1703
1732
|
if (normalized.optionalOrg && ctx.apiClient && ctx.auth) {
|
|
1704
|
-
ctx.orgId = await requireOrg(
|
|
1733
|
+
ctx.orgId = await requireOrg(
|
|
1734
|
+
ctx as CommandContext & { apiClient: APIClientType },
|
|
1735
|
+
autoSelectOrg6
|
|
1736
|
+
);
|
|
1705
1737
|
}
|
|
1706
1738
|
if ((normalized.requiresRegion || normalized.optionalRegion) && ctx.apiClient) {
|
|
1707
1739
|
const apiClient: APIClientType = ctx.apiClient as APIClientType;
|
|
@@ -154,10 +154,11 @@ if (hasWorkbench) {
|
|
|
154
154
|
if (isDevelopment() && process.env.VITE_PORT) {
|
|
155
155
|
const VITE_ASSET_PORT = parseInt(process.env.VITE_PORT, 10);
|
|
156
156
|
|
|
157
|
-
const proxyToVite = async (c: Context) => {
|
|
158
|
-
const
|
|
157
|
+
const proxyToVite = async (c: Context, pathOverride?: string) => {
|
|
158
|
+
const targetPath = pathOverride ?? c.req.path;
|
|
159
|
+
const viteUrl = \`http://127.0.0.1:\${VITE_ASSET_PORT}\${targetPath}\`;
|
|
159
160
|
try {
|
|
160
|
-
otel.logger.debug(\`[Proxy] \${c.req.method} \${c.req.path} -> Vite:\${VITE_ASSET_PORT}\`);
|
|
161
|
+
otel.logger.debug(\`[Proxy] \${c.req.method} \${c.req.path} -> Vite:\${VITE_ASSET_PORT}\${targetPath}\`);
|
|
161
162
|
const res = await fetch(viteUrl, { signal: AbortSignal.timeout(10000) });
|
|
162
163
|
otel.logger.debug(\`[Proxy] \${c.req.path} -> \${res.status} (\${res.headers.get('content-type')})\`);
|
|
163
164
|
return new Response(res.body, {
|
|
@@ -174,35 +175,144 @@ if (isDevelopment() && process.env.VITE_PORT) {
|
|
|
174
175
|
}
|
|
175
176
|
};
|
|
176
177
|
|
|
178
|
+
// HMR WebSocket proxy - enables hot reload through tunnels (*.agentuity.live)
|
|
179
|
+
// This proxies the Vite HMR WebSocket connection from the Bun server to Vite
|
|
180
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
181
|
+
const viteHmrWebsocket = (globalThis as any).__AGENTUITY_VITE_HMR_WEBSOCKET__ = {
|
|
182
|
+
// Map of client WebSocket -> Vite WebSocket
|
|
183
|
+
connections: new Map<WebSocket, WebSocket>(),
|
|
184
|
+
|
|
185
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
186
|
+
open(clientWs: any) {
|
|
187
|
+
// Get the query string from ws.data (set during upgrade)
|
|
188
|
+
const queryString = clientWs.data?.queryString || '';
|
|
189
|
+
const viteWsUrl = \`ws://127.0.0.1:\${VITE_ASSET_PORT}/__vite_hmr\${queryString}\`;
|
|
190
|
+
otel.logger.debug('[HMR Proxy] Client connected, opening connection to Vite at %s', viteWsUrl);
|
|
191
|
+
|
|
192
|
+
// Connect to Vite with the 'vite-hmr' subprotocol (required by Vite)
|
|
193
|
+
const viteWs = new WebSocket(viteWsUrl, ['vite-hmr']);
|
|
194
|
+
|
|
195
|
+
viteWs.onopen = () => {
|
|
196
|
+
otel.logger.debug('[HMR Proxy] Connected to Vite HMR server');
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
viteWs.onmessage = (event) => {
|
|
200
|
+
// Forward messages from Vite to client
|
|
201
|
+
if (clientWs.readyState === WebSocket.OPEN) {
|
|
202
|
+
clientWs.send(event.data);
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
viteWs.onerror = (error) => {
|
|
207
|
+
otel.logger.error('[HMR Proxy] Vite WebSocket error: %s', error);
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
viteWs.onclose = () => {
|
|
211
|
+
otel.logger.debug('[HMR Proxy] Vite WebSocket closed');
|
|
212
|
+
viteHmrWebsocket.connections.delete(clientWs);
|
|
213
|
+
if (clientWs.readyState === WebSocket.OPEN) {
|
|
214
|
+
clientWs.close();
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
viteHmrWebsocket.connections.set(clientWs, viteWs);
|
|
219
|
+
},
|
|
220
|
+
|
|
221
|
+
message(clientWs: WebSocket, message: string | Buffer) {
|
|
222
|
+
// Forward messages from client to Vite
|
|
223
|
+
const viteWs = viteHmrWebsocket.connections.get(clientWs);
|
|
224
|
+
if (viteWs && viteWs.readyState === WebSocket.OPEN) {
|
|
225
|
+
viteWs.send(message);
|
|
226
|
+
}
|
|
227
|
+
},
|
|
228
|
+
|
|
229
|
+
close(clientWs: WebSocket) {
|
|
230
|
+
otel.logger.debug('[HMR Proxy] Client WebSocket closed');
|
|
231
|
+
const viteWs = viteHmrWebsocket.connections.get(clientWs);
|
|
232
|
+
if (viteWs) {
|
|
233
|
+
viteWs.close();
|
|
234
|
+
viteHmrWebsocket.connections.delete(clientWs);
|
|
235
|
+
}
|
|
236
|
+
},
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
// Register HMR WebSocket route - must be before other routes
|
|
240
|
+
app.get('/__vite_hmr', (c: Context) => {
|
|
241
|
+
const upgradeHeader = c.req.header('upgrade');
|
|
242
|
+
if (upgradeHeader?.toLowerCase() === 'websocket') {
|
|
243
|
+
// Get the Bun server from context using Hono's pattern
|
|
244
|
+
// When app.fetch(req, server) is called, Hono stores server as c.env
|
|
245
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
246
|
+
const server = 'server' in (c.env as any) ? (c.env as any).server : c.env;
|
|
247
|
+
|
|
248
|
+
if (server?.upgrade) {
|
|
249
|
+
// Extract query string to forward to Vite (includes token parameter)
|
|
250
|
+
const url = new URL(c.req.url);
|
|
251
|
+
const queryString = url.search; // Includes the '?' prefix
|
|
252
|
+
|
|
253
|
+
// Get the requested WebSocket subprotocol (Vite uses 'vite-hmr')
|
|
254
|
+
const requestedProtocol = c.req.header('sec-websocket-protocol');
|
|
255
|
+
|
|
256
|
+
const success = server.upgrade(c.req.raw, {
|
|
257
|
+
data: { type: 'vite-hmr', queryString },
|
|
258
|
+
// Echo back the requested subprotocol so the browser accepts the connection
|
|
259
|
+
headers: requestedProtocol ? {
|
|
260
|
+
'Sec-WebSocket-Protocol': requestedProtocol,
|
|
261
|
+
} : undefined,
|
|
262
|
+
});
|
|
263
|
+
if (success) {
|
|
264
|
+
otel.logger.debug('[HMR Proxy] WebSocket upgrade successful (protocol: %s)', requestedProtocol || 'none');
|
|
265
|
+
return new Response(null);
|
|
266
|
+
}
|
|
267
|
+
otel.logger.error('[HMR Proxy] WebSocket upgrade returned false');
|
|
268
|
+
} else {
|
|
269
|
+
otel.logger.error('[HMR Proxy] Server upgrade method not available. c.env type: %s, keys: %s',
|
|
270
|
+
typeof c.env,
|
|
271
|
+
Object.keys(c.env || {}).join(', '));
|
|
272
|
+
}
|
|
273
|
+
return c.text('WebSocket upgrade failed', 500);
|
|
274
|
+
}
|
|
275
|
+
// Non-WebSocket request to HMR endpoint - proxy to Vite
|
|
276
|
+
return proxyToVite(c);
|
|
277
|
+
});
|
|
278
|
+
|
|
177
279
|
// Vite client scripts and HMR
|
|
178
|
-
app.get('/@vite/*', proxyToVite);
|
|
179
|
-
app.get('/@react-refresh', proxyToVite);
|
|
280
|
+
app.get('/@vite/*', (c: Context) => proxyToVite(c));
|
|
281
|
+
app.get('/@react-refresh', (c: Context) => proxyToVite(c));
|
|
180
282
|
|
|
181
283
|
// Source files for HMR
|
|
182
|
-
app.get('/src/web/*', proxyToVite);
|
|
183
|
-
app.get('/src/*', proxyToVite); // Catch-all for other source files
|
|
284
|
+
app.get('/src/web/*', (c: Context) => proxyToVite(c));
|
|
285
|
+
app.get('/src/*', (c: Context) => proxyToVite(c)); // Catch-all for other source files
|
|
184
286
|
|
|
185
287
|
// Workbench source files (in .agentuity/workbench-src/)
|
|
186
|
-
app.get('/.agentuity/workbench-src/*', proxyToVite);
|
|
288
|
+
app.get('/.agentuity/workbench-src/*', (c: Context) => proxyToVite(c));
|
|
187
289
|
|
|
188
290
|
// Node modules (Vite transforms these)
|
|
189
|
-
app.get('/node_modules/*', proxyToVite);
|
|
291
|
+
app.get('/node_modules/*', (c: Context) => proxyToVite(c));
|
|
190
292
|
|
|
191
293
|
// Scoped packages (e.g., @agentuity/*, @types/*)
|
|
192
|
-
app.get('/@*', proxyToVite);
|
|
294
|
+
app.get('/@*', (c: Context) => proxyToVite(c));
|
|
193
295
|
|
|
194
296
|
// File system access (for Vite's @fs protocol)
|
|
195
|
-
app.get('/@fs/*', proxyToVite);
|
|
297
|
+
app.get('/@fs/*', (c: Context) => proxyToVite(c));
|
|
196
298
|
|
|
197
299
|
// Module resolution (for Vite's @id protocol)
|
|
198
|
-
app.get('/@id/*', proxyToVite);
|
|
300
|
+
app.get('/@id/*', (c: Context) => proxyToVite(c));
|
|
301
|
+
|
|
302
|
+
// Static assets - Vite serves src/web/public/* at root, but code uses /public/* paths
|
|
303
|
+
// In production, the plugin transforms /public/foo.svg to CDN URLs
|
|
304
|
+
// Rewrite /public/foo.svg -> /foo.svg before proxying to Vite
|
|
305
|
+
app.get('/public/*', (c: Context) => {
|
|
306
|
+
const rootPath = c.req.path.replace(/^\\/public/, '');
|
|
307
|
+
return proxyToVite(c, rootPath);
|
|
308
|
+
});
|
|
199
309
|
|
|
200
310
|
// Any .js, .jsx, .ts, .tsx files (catch remaining modules)
|
|
201
|
-
app.get('/*.js', proxyToVite);
|
|
202
|
-
app.get('/*.jsx', proxyToVite);
|
|
203
|
-
app.get('/*.ts', proxyToVite);
|
|
204
|
-
app.get('/*.tsx', proxyToVite);
|
|
205
|
-
app.get('/*.css', proxyToVite);
|
|
311
|
+
app.get('/*.js', (c: Context) => proxyToVite(c));
|
|
312
|
+
app.get('/*.jsx', (c: Context) => proxyToVite(c));
|
|
313
|
+
app.get('/*.ts', (c: Context) => proxyToVite(c));
|
|
314
|
+
app.get('/*.tsx', (c: Context) => proxyToVite(c));
|
|
315
|
+
app.get('/*.css', (c: Context) => proxyToVite(c));
|
|
206
316
|
}
|
|
207
317
|
`;
|
|
208
318
|
|
|
@@ -358,13 +468,48 @@ if (typeof Bun !== 'undefined') {
|
|
|
358
468
|
enableProcessExitProtection();
|
|
359
469
|
|
|
360
470
|
const port = parseInt(process.env.PORT || '3500', 10);
|
|
471
|
+
|
|
472
|
+
// Create custom WebSocket handler that supports both regular WebSockets and HMR proxy
|
|
473
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
474
|
+
const hmrHandler = (globalThis as any).__AGENTUITY_VITE_HMR_WEBSOCKET__;
|
|
475
|
+
const customWebsocket = {
|
|
476
|
+
...websocket,
|
|
477
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
478
|
+
open(ws: any) {
|
|
479
|
+
// Check if this is an HMR connection
|
|
480
|
+
if (ws.data?.type === 'vite-hmr' && hmrHandler) {
|
|
481
|
+
hmrHandler.open(ws);
|
|
482
|
+
} else if (websocket.open) {
|
|
483
|
+
websocket.open(ws);
|
|
484
|
+
}
|
|
485
|
+
},
|
|
486
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
487
|
+
message(ws: any, message: string | Buffer) {
|
|
488
|
+
// Check if this is an HMR connection
|
|
489
|
+
if (ws.data?.type === 'vite-hmr' && hmrHandler) {
|
|
490
|
+
hmrHandler.message(ws, message);
|
|
491
|
+
} else if (websocket.message) {
|
|
492
|
+
websocket.message(ws, message);
|
|
493
|
+
}
|
|
494
|
+
},
|
|
495
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
496
|
+
close(ws: any, code?: number, reason?: string) {
|
|
497
|
+
// Check if this is an HMR connection
|
|
498
|
+
if (ws.data?.type === 'vite-hmr' && hmrHandler) {
|
|
499
|
+
hmrHandler.close(ws);
|
|
500
|
+
} else if (websocket.close) {
|
|
501
|
+
websocket.close(ws, code, reason);
|
|
502
|
+
}
|
|
503
|
+
},
|
|
504
|
+
};
|
|
505
|
+
|
|
361
506
|
const server = Bun.serve({
|
|
362
507
|
fetch: (req, server) => {
|
|
363
508
|
// Get timeout from config on each request (0 = no timeout)
|
|
364
509
|
server.timeout(req, getAppConfig()?.requestTimeout ?? 0);
|
|
365
510
|
return app.fetch(req, server);
|
|
366
511
|
},
|
|
367
|
-
websocket,
|
|
512
|
+
websocket: customWebsocket,
|
|
368
513
|
port,
|
|
369
514
|
hostname: '127.0.0.1',
|
|
370
515
|
development: isDevelopment(),
|
|
@@ -370,24 +370,35 @@ export async function generateMetadata(options: MetadataGeneratorOptions): Promi
|
|
|
370
370
|
}
|
|
371
371
|
}
|
|
372
372
|
|
|
373
|
-
// Scan
|
|
374
|
-
|
|
375
|
-
|
|
373
|
+
// Scan client directory for static files copied from public/
|
|
374
|
+
// Vite copies src/web/public/* to .agentuity/client/* (at root, not in public/ subfolder)
|
|
375
|
+
// We need to find these files and add them to assets for CDN upload
|
|
376
|
+
const clientDir = join(agentuityDir, 'client');
|
|
377
|
+
if (existsSync(clientDir)) {
|
|
376
378
|
try {
|
|
377
|
-
function
|
|
379
|
+
function scanClientDirectory(dir: string, prefix: string = '') {
|
|
378
380
|
const entries = readdirSync(dir, { withFileTypes: true });
|
|
379
381
|
for (const entry of entries) {
|
|
380
382
|
const relativePath = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
381
383
|
const fullPath = join(dir, entry.name);
|
|
382
384
|
|
|
385
|
+
// Skip directories we already process (assets from manifest, .vite metadata)
|
|
383
386
|
if (entry.isDirectory()) {
|
|
384
|
-
|
|
387
|
+
if (entry.name === 'assets' || entry.name === '.vite') {
|
|
388
|
+
continue;
|
|
389
|
+
}
|
|
390
|
+
scanClientDirectory(fullPath, relativePath);
|
|
385
391
|
} else if (entry.isFile()) {
|
|
392
|
+
// Skip files we already added from manifest (index.html is the entry point)
|
|
393
|
+
if (entry.name === 'index.html') {
|
|
394
|
+
continue;
|
|
395
|
+
}
|
|
396
|
+
|
|
386
397
|
const stats = statSync(fullPath);
|
|
387
398
|
// Skip empty files
|
|
388
399
|
if (stats.size === 0) continue;
|
|
389
400
|
|
|
390
|
-
const assetPath = `
|
|
401
|
+
const assetPath = `client/${relativePath}`;
|
|
391
402
|
if (!seenAssets.has(assetPath)) {
|
|
392
403
|
seenAssets.add(assetPath);
|
|
393
404
|
const contentType = getContentType(entry.name);
|
|
@@ -406,10 +417,10 @@ export async function generateMetadata(options: MetadataGeneratorOptions): Promi
|
|
|
406
417
|
}
|
|
407
418
|
}
|
|
408
419
|
|
|
409
|
-
|
|
410
|
-
logger.trace(`Found ${assets.length} total assets (including
|
|
420
|
+
scanClientDirectory(clientDir);
|
|
421
|
+
logger.trace(`Found ${assets.length} total assets (including static files)`);
|
|
411
422
|
} catch (error) {
|
|
412
|
-
logger.warn(`Failed to scan
|
|
423
|
+
logger.warn(`Failed to scan client directory for static files: ${error}`);
|
|
413
424
|
}
|
|
414
425
|
}
|
|
415
426
|
|
|
@@ -1,17 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Vite plugin to fix incorrect public asset paths
|
|
3
3
|
*
|
|
4
|
-
* Developers
|
|
5
|
-
*
|
|
4
|
+
* Developers should use /public/ paths for static assets from src/web/public/.
|
|
5
|
+
* In production, these paths are transformed to CDN URLs.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
7
|
+
* This plugin:
|
|
8
|
+
* 1. During build: Rewrites /public/* paths to CDN URLs
|
|
9
|
+
* 2. During dev: Warns only about incorrect source paths (src/web/public/)
|
|
9
10
|
*
|
|
10
|
-
*
|
|
11
|
-
* - '/
|
|
12
|
-
* - './
|
|
13
|
-
*
|
|
14
|
-
*
|
|
11
|
+
* Supported patterns (work in dev, rewritten to CDN in production):
|
|
12
|
+
* - '/public/foo.svg' → CDN URL (recommended)
|
|
13
|
+
* - './public/foo.svg' → CDN URL
|
|
14
|
+
*
|
|
15
|
+
* Incorrect patterns (warned in dev, rewritten in production):
|
|
16
|
+
* - '/src/web/public/foo.svg' → CDN URL
|
|
17
|
+
* - './src/web/public/foo.svg' → CDN URL
|
|
18
|
+
* - 'src/web/public/foo.svg' → CDN URL
|
|
15
19
|
*/
|
|
16
20
|
|
|
17
21
|
import type { Plugin } from 'vite';
|
|
@@ -19,46 +23,69 @@ import type { Plugin } from 'vite';
|
|
|
19
23
|
export interface PublicAssetPathPluginOptions {
|
|
20
24
|
/** Whether to show warnings in dev mode (default: true) */
|
|
21
25
|
warnInDev?: boolean;
|
|
26
|
+
/** CDN base URL for production builds (e.g., 'https://cdn.agentuity.com/{deploymentId}/client/') */
|
|
27
|
+
cdnBaseUrl?: string;
|
|
22
28
|
}
|
|
23
29
|
|
|
24
30
|
interface PathPattern {
|
|
25
31
|
regex: RegExp;
|
|
26
32
|
description: string;
|
|
33
|
+
/** Replacement template - use {base} for the target base URL */
|
|
34
|
+
replacement: string;
|
|
27
35
|
}
|
|
28
36
|
|
|
29
37
|
/**
|
|
30
|
-
*
|
|
31
|
-
* (RegExp with global flag maintains state via lastIndex)
|
|
38
|
+
* Patterns that are incorrect - reference source paths directly
|
|
32
39
|
*/
|
|
33
|
-
function
|
|
40
|
+
function createIncorrectPatterns(): PathPattern[] {
|
|
34
41
|
return [
|
|
35
42
|
// '/src/web/public/...' or './src/web/public/...' or 'src/web/public/...'
|
|
36
43
|
{
|
|
37
44
|
regex: /(['"`])(?:\.?\/)?src\/web\/public\//g,
|
|
38
45
|
description: 'src/web/public/',
|
|
46
|
+
replacement: '$1{base}',
|
|
39
47
|
},
|
|
40
|
-
|
|
48
|
+
];
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Patterns that need rewriting for production CDN
|
|
53
|
+
* Both patterns simply replace the prefix while preserving the rest of the path naturally.
|
|
54
|
+
*/
|
|
55
|
+
function createPublicPatterns(): PathPattern[] {
|
|
56
|
+
return [
|
|
57
|
+
// './public/...' (relative public path) - replace prefix, keep rest
|
|
41
58
|
{
|
|
42
59
|
regex: /(['"`])\.\/public\//g,
|
|
43
60
|
description: './public/',
|
|
61
|
+
replacement: '$1{base}',
|
|
62
|
+
},
|
|
63
|
+
// '/public/...' (absolute public path) - replace prefix, keep rest
|
|
64
|
+
{
|
|
65
|
+
regex: /(['"`])\/public\//g,
|
|
66
|
+
description: '/public/',
|
|
67
|
+
replacement: '$1{base}',
|
|
44
68
|
},
|
|
45
69
|
];
|
|
46
70
|
}
|
|
47
71
|
|
|
48
72
|
/**
|
|
49
|
-
* Vite plugin that fixes
|
|
73
|
+
* Vite plugin that fixes public asset paths and rewrites to CDN URLs
|
|
74
|
+
*
|
|
75
|
+
* Rewrites all public asset paths to CDN URLs in production.
|
|
50
76
|
*
|
|
51
77
|
* @example
|
|
52
78
|
* // In vite config:
|
|
53
|
-
* plugins: [publicAssetPathPlugin()]
|
|
79
|
+
* plugins: [publicAssetPathPlugin({ cdnBaseUrl: 'https://cdn.example.com/deploy/client/' })]
|
|
54
80
|
*
|
|
55
|
-
* //
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
* //
|
|
81
|
+
* // In code, use /public/ paths:
|
|
82
|
+
* <img src="/public/logo.svg" />
|
|
83
|
+
*
|
|
84
|
+
* // Transforms in production:
|
|
85
|
+
* // '/public/logo.svg' → 'https://cdn.example.com/deploy/client/logo.svg'
|
|
59
86
|
*/
|
|
60
87
|
export function publicAssetPathPlugin(options: PublicAssetPathPluginOptions = {}): Plugin {
|
|
61
|
-
const { warnInDev = true } = options;
|
|
88
|
+
const { warnInDev = true, cdnBaseUrl } = options;
|
|
62
89
|
|
|
63
90
|
let isDev = false;
|
|
64
91
|
const warnedFiles = new Map<string, Set<string>>(); // file -> set of patterns warned
|
|
@@ -77,53 +104,78 @@ export function publicAssetPathPlugin(options: PublicAssetPathPluginOptions = {}
|
|
|
77
104
|
}
|
|
78
105
|
|
|
79
106
|
// Quick check: does the code contain any patterns we care about?
|
|
80
|
-
const
|
|
107
|
+
const hasIncorrectSourcePaths = code.includes('src/web/public/');
|
|
108
|
+
const hasPublicPaths = code.includes('/public/') || code.includes('./public/');
|
|
81
109
|
|
|
82
|
-
if (!
|
|
110
|
+
if (!hasIncorrectSourcePaths && !hasPublicPaths) {
|
|
83
111
|
return null;
|
|
84
112
|
}
|
|
85
113
|
|
|
86
|
-
//
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
// Track which patterns were found for warnings
|
|
90
|
-
const foundPatterns: string[] = [];
|
|
91
|
-
let transformed = code;
|
|
92
|
-
|
|
93
|
-
for (const { regex, description } of patterns) {
|
|
94
|
-
if (regex.test(transformed)) {
|
|
95
|
-
foundPatterns.push(description);
|
|
96
|
-
|
|
97
|
-
// Create a fresh regex for the replacement (test() consumed the previous one)
|
|
98
|
-
const replaceRegex = new RegExp(regex.source, regex.flags);
|
|
99
|
-
transformed = transformed.replace(replaceRegex, '$1/public/');
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// In dev mode, optionally warn but don't transform (Vite serves from source paths)
|
|
114
|
+
// In dev mode, only warn about incorrect source paths (src/web/public/)
|
|
115
|
+
// /public/ and ./public/ paths work correctly in dev mode
|
|
104
116
|
if (isDev) {
|
|
105
|
-
if (warnInDev &&
|
|
106
|
-
const
|
|
107
|
-
const
|
|
117
|
+
if (warnInDev && hasIncorrectSourcePaths) {
|
|
118
|
+
const patterns = createIncorrectPatterns();
|
|
119
|
+
const foundPatterns: string[] = [];
|
|
108
120
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
121
|
+
for (const { regex, description } of patterns) {
|
|
122
|
+
if (regex.test(code)) {
|
|
123
|
+
foundPatterns.push(description);
|
|
112
124
|
}
|
|
113
|
-
|
|
125
|
+
}
|
|
114
126
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
)
|
|
127
|
+
if (foundPatterns.length > 0) {
|
|
128
|
+
const fileWarnings = warnedFiles.get(id) || new Set();
|
|
129
|
+
const newWarnings = foundPatterns.filter((p) => !fileWarnings.has(p));
|
|
130
|
+
|
|
131
|
+
if (newWarnings.length > 0) {
|
|
132
|
+
for (const p of newWarnings) {
|
|
133
|
+
fileWarnings.add(p);
|
|
134
|
+
}
|
|
135
|
+
warnedFiles.set(id, fileWarnings);
|
|
136
|
+
|
|
137
|
+
this.warn(
|
|
138
|
+
`Found incorrect asset path(s) in ${id}:\n` +
|
|
139
|
+
newWarnings.map((p) => ` - '${p}' should be '/public/'`).join('\n') +
|
|
140
|
+
`\nUse '/public/...' paths for static assets.`
|
|
141
|
+
);
|
|
142
|
+
}
|
|
120
143
|
}
|
|
121
144
|
}
|
|
122
145
|
// In dev mode, never transform - Vite serves from source paths
|
|
146
|
+
// and the Bun server proxies /public/* to Vite
|
|
123
147
|
return null;
|
|
124
148
|
}
|
|
125
149
|
|
|
126
|
-
//
|
|
150
|
+
// Build mode: transform paths to CDN URLs
|
|
151
|
+
let transformed = code;
|
|
152
|
+
|
|
153
|
+
// Determine target URL: CDN base if provided, otherwise root
|
|
154
|
+
const targetBase = cdnBaseUrl
|
|
155
|
+
? cdnBaseUrl.endsWith('/')
|
|
156
|
+
? cdnBaseUrl
|
|
157
|
+
: `${cdnBaseUrl}/`
|
|
158
|
+
: '/';
|
|
159
|
+
|
|
160
|
+
// Transform incorrect source paths (src/web/public/) → CDN
|
|
161
|
+
if (hasIncorrectSourcePaths) {
|
|
162
|
+
const patterns = createIncorrectPatterns();
|
|
163
|
+
for (const { regex, replacement } of patterns) {
|
|
164
|
+
const replaceRegex = new RegExp(regex.source, regex.flags);
|
|
165
|
+
transformed = transformed.replace(replaceRegex, replacement.replace('{base}', targetBase));
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Transform public paths → CDN
|
|
170
|
+
if (hasPublicPaths) {
|
|
171
|
+
const publicPatterns = createPublicPatterns();
|
|
172
|
+
for (const { regex, replacement } of publicPatterns) {
|
|
173
|
+
const replaceRegex = new RegExp(regex.source, regex.flags);
|
|
174
|
+
transformed = transformed.replace(replaceRegex, replacement.replace('{base}', targetBase));
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Return transformed code if changed
|
|
127
179
|
if (transformed !== code) {
|
|
128
180
|
return {
|
|
129
181
|
code: transformed,
|