@agentuity/cli 0.0.103 → 0.0.105
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/bin/cli.ts +6 -3
- package/dist/cmd/ai/prompt/version.d.ts +1 -0
- package/dist/cmd/ai/prompt/version.d.ts.map +1 -1
- package/dist/cmd/ai/prompt/version.js +3 -2
- package/dist/cmd/ai/prompt/version.js.map +1 -1
- package/dist/cmd/build/ast.d.ts.map +1 -1
- package/dist/cmd/build/ast.js +50 -34
- package/dist/cmd/build/ast.js.map +1 -1
- package/dist/cmd/build/entry-generator.d.ts.map +1 -1
- package/dist/cmd/build/entry-generator.js +21 -17
- package/dist/cmd/build/entry-generator.js.map +1 -1
- package/dist/cmd/build/vite/agent-discovery.d.ts.map +1 -1
- package/dist/cmd/build/vite/agent-discovery.js +41 -2
- package/dist/cmd/build/vite/agent-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/vite-asset-server.d.ts.map +1 -1
- package/dist/cmd/build/vite/vite-asset-server.js +53 -4
- 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 +3 -0
- package/dist/cmd/build/vite/vite-builder.js.map +1 -1
- package/dist/cmd/dev/dev-lock.d.ts +62 -0
- package/dist/cmd/dev/dev-lock.d.ts.map +1 -0
- package/dist/cmd/dev/dev-lock.js +250 -0
- package/dist/cmd/dev/dev-lock.js.map +1 -0
- package/dist/cmd/dev/index.d.ts.map +1 -1
- package/dist/cmd/dev/index.js +69 -12
- package/dist/cmd/dev/index.js.map +1 -1
- package/dist/cmd/dev/sync.js +6 -6
- package/dist/cmd/dev/sync.js.map +1 -1
- package/dist/cmd/project/download.d.ts +1 -0
- package/dist/cmd/project/download.d.ts.map +1 -1
- package/dist/cmd/project/download.js +7 -5
- package/dist/cmd/project/download.js.map +1 -1
- package/dist/cmd/project/template-flow.d.ts.map +1 -1
- package/dist/cmd/project/template-flow.js +3 -1
- package/dist/cmd/project/template-flow.js.map +1 -1
- package/package.json +4 -4
- package/src/cmd/ai/prompt/api.md +26 -21
- package/src/cmd/ai/prompt/version.ts +3 -2
- package/src/cmd/build/ast.ts +52 -34
- package/src/cmd/build/entry-generator.ts +21 -18
- package/src/cmd/build/vite/agent-discovery.ts +45 -3
- package/src/cmd/build/vite/server-bundler.ts +1 -1
- package/src/cmd/build/vite/vite-asset-server.ts +56 -4
- package/src/cmd/build/vite/vite-builder.ts +4 -1
- package/src/cmd/dev/dev-lock.ts +332 -0
- package/src/cmd/dev/index.ts +79 -12
- package/src/cmd/dev/sync.ts +6 -6
- package/src/cmd/project/download.ts +8 -6
- package/src/cmd/project/template-flow.ts +4 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentuity/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.105",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"author": "Agentuity employees and contributors",
|
|
6
6
|
"type": "module",
|
|
@@ -40,8 +40,8 @@
|
|
|
40
40
|
"prepublishOnly": "bun run clean && bun run build"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@agentuity/core": "0.0.
|
|
44
|
-
"@agentuity/server": "0.0.
|
|
43
|
+
"@agentuity/core": "0.0.105",
|
|
44
|
+
"@agentuity/server": "0.0.105",
|
|
45
45
|
"@datasert/cronjs-parser": "^1.4.0",
|
|
46
46
|
"@terascope/fetch-github-release": "^2.2.1",
|
|
47
47
|
"@vitejs/plugin-react": "^5.1.2",
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"zod": "^4.1.12"
|
|
62
62
|
},
|
|
63
63
|
"devDependencies": {
|
|
64
|
-
"@agentuity/test-utils": "0.0.
|
|
64
|
+
"@agentuity/test-utils": "0.0.105",
|
|
65
65
|
"@types/adm-zip": "^0.5.7",
|
|
66
66
|
"@types/bun": "latest",
|
|
67
67
|
"@types/tar-fs": "^2.0.4",
|
package/src/cmd/ai/prompt/api.md
CHANGED
|
@@ -311,40 +311,45 @@ return c.json({ data: 'value' }, 200, {
|
|
|
311
311
|
## Streaming Routes
|
|
312
312
|
|
|
313
313
|
```typescript
|
|
314
|
-
import { createRouter } from '@agentuity/runtime';
|
|
314
|
+
import { createRouter, stream, sse, websocket } from '@agentuity/runtime';
|
|
315
315
|
|
|
316
316
|
const router = createRouter();
|
|
317
317
|
|
|
318
|
-
// Stream response
|
|
319
|
-
router.
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
controller
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
}
|
|
318
|
+
// Stream response (use with POST)
|
|
319
|
+
router.post(
|
|
320
|
+
'/events',
|
|
321
|
+
stream((c) => {
|
|
322
|
+
return new ReadableStream({
|
|
323
|
+
start(controller) {
|
|
324
|
+
controller.enqueue('event 1\n');
|
|
325
|
+
controller.enqueue('event 2\n');
|
|
326
|
+
controller.close();
|
|
327
|
+
},
|
|
328
|
+
});
|
|
329
|
+
})
|
|
330
|
+
);
|
|
328
331
|
|
|
329
|
-
// Server-Sent Events
|
|
330
|
-
router.
|
|
331
|
-
|
|
332
|
+
// Server-Sent Events (use with GET)
|
|
333
|
+
router.get(
|
|
334
|
+
'/notifications',
|
|
335
|
+
sse((c, stream) => {
|
|
332
336
|
stream.writeSSE({ data: 'Hello', event: 'message' });
|
|
333
337
|
stream.writeSSE({ data: 'World', event: 'message' });
|
|
334
|
-
}
|
|
335
|
-
|
|
338
|
+
})
|
|
339
|
+
);
|
|
336
340
|
|
|
337
|
-
// WebSocket
|
|
338
|
-
router.
|
|
339
|
-
|
|
341
|
+
// WebSocket (use with GET)
|
|
342
|
+
router.get(
|
|
343
|
+
'/ws',
|
|
344
|
+
websocket((c, ws) => {
|
|
340
345
|
ws.onOpen(() => {
|
|
341
346
|
ws.send('Connected!');
|
|
342
347
|
});
|
|
343
348
|
ws.onMessage((event) => {
|
|
344
349
|
ws.send(`Echo: ${event.data}`);
|
|
345
350
|
});
|
|
346
|
-
}
|
|
347
|
-
|
|
351
|
+
})
|
|
352
|
+
);
|
|
348
353
|
|
|
349
354
|
export default router;
|
|
350
355
|
```
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* This allows detecting if the source template has changed.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
const HASH_REGEX = /\n?<!-- prompt_hash: ([a-f0-9]+)
|
|
11
|
+
const HASH_REGEX = /\n?<!-- prompt_hash: ([a-f0-9]+) -->\n?$/;
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* Compute SHA256 hash of content using Bun's built-in hasher.
|
|
@@ -37,10 +37,11 @@ export function extractHash(content: string): string | null {
|
|
|
37
37
|
|
|
38
38
|
/**
|
|
39
39
|
* Generate content with hash comment appended.
|
|
40
|
+
* Ensures the output ends with a newline for POSIX compliance and Prettier compatibility.
|
|
40
41
|
*/
|
|
41
42
|
export function appendHashComment(content: string): string {
|
|
42
43
|
const hash = computeHash(content);
|
|
43
|
-
return `${content}\n<!-- prompt_hash: ${hash}
|
|
44
|
+
return `${content}\n<!-- prompt_hash: ${hash} -->\n`;
|
|
44
45
|
}
|
|
45
46
|
|
|
46
47
|
/**
|
package/src/cmd/build/ast.ts
CHANGED
|
@@ -1315,6 +1315,52 @@ export async function parseRoute(
|
|
|
1315
1315
|
case 'delete': {
|
|
1316
1316
|
if (action && (action as ASTLiteral).type === 'Literal') {
|
|
1317
1317
|
suffix = String((action as ASTLiteral).value);
|
|
1318
|
+
|
|
1319
|
+
// Check if any argument is a middleware function call (websocket, sse, stream, cron)
|
|
1320
|
+
// New pattern: router.get('/ws', websocket((c, ws) => { ... }))
|
|
1321
|
+
for (const arg of statement.expression.arguments) {
|
|
1322
|
+
if ((arg as ASTCallExpression).type === 'CallExpression') {
|
|
1323
|
+
const callExpr = arg as ASTCallExpression;
|
|
1324
|
+
// Only handle simple Identifier callees (e.g., websocket(), sse())
|
|
1325
|
+
// Skip MemberExpression callees (e.g., obj.method())
|
|
1326
|
+
if (callExpr.callee.type !== 'Identifier') {
|
|
1327
|
+
continue;
|
|
1328
|
+
}
|
|
1329
|
+
const calleeName = (callExpr.callee as ASTNodeIdentifier).name;
|
|
1330
|
+
if (
|
|
1331
|
+
calleeName === 'websocket' ||
|
|
1332
|
+
calleeName === 'sse' ||
|
|
1333
|
+
calleeName === 'stream'
|
|
1334
|
+
) {
|
|
1335
|
+
type = calleeName;
|
|
1336
|
+
break;
|
|
1337
|
+
}
|
|
1338
|
+
if (calleeName === 'cron') {
|
|
1339
|
+
type = 'cron';
|
|
1340
|
+
// First argument to cron() is the schedule expression
|
|
1341
|
+
if (callExpr.arguments && callExpr.arguments.length > 0) {
|
|
1342
|
+
const cronArg = callExpr.arguments[0] as ASTLiteral;
|
|
1343
|
+
if (cronArg.type === 'Literal') {
|
|
1344
|
+
const expression = String(cronArg.value);
|
|
1345
|
+
try {
|
|
1346
|
+
parseCronExpression(expression, {
|
|
1347
|
+
hasSeconds: false,
|
|
1348
|
+
});
|
|
1349
|
+
} catch (ex) {
|
|
1350
|
+
throw new InvalidRouterConfigError({
|
|
1351
|
+
filename,
|
|
1352
|
+
cause: ex,
|
|
1353
|
+
line: body.loc?.start?.line,
|
|
1354
|
+
message: `invalid cron expression "${expression}" in ${filename} at line ${body.loc?.start?.line}`,
|
|
1355
|
+
});
|
|
1356
|
+
}
|
|
1357
|
+
config = { expression };
|
|
1358
|
+
}
|
|
1359
|
+
}
|
|
1360
|
+
break;
|
|
1361
|
+
}
|
|
1362
|
+
}
|
|
1363
|
+
}
|
|
1318
1364
|
} else {
|
|
1319
1365
|
throw new InvalidRouterConfigError({
|
|
1320
1366
|
filename,
|
|
@@ -1327,6 +1373,8 @@ export async function parseRoute(
|
|
|
1327
1373
|
case 'stream':
|
|
1328
1374
|
case 'sse':
|
|
1329
1375
|
case 'websocket': {
|
|
1376
|
+
// DEPRECATED: router.stream(), router.sse(), router.websocket()
|
|
1377
|
+
// These methods now throw errors at runtime
|
|
1330
1378
|
type = method;
|
|
1331
1379
|
method = 'post';
|
|
1332
1380
|
const theaction = action as ASTLiteral;
|
|
@@ -1336,39 +1384,9 @@ export async function parseRoute(
|
|
|
1336
1384
|
}
|
|
1337
1385
|
break;
|
|
1338
1386
|
}
|
|
1339
|
-
case 'sms': {
|
|
1340
|
-
type = method;
|
|
1341
|
-
method = 'post';
|
|
1342
|
-
const theaction = action as ASTObjectExpression;
|
|
1343
|
-
if (theaction.type === 'ObjectExpression') {
|
|
1344
|
-
config = {};
|
|
1345
|
-
theaction.properties.forEach((p) => {
|
|
1346
|
-
if (p.value.type === 'Literal') {
|
|
1347
|
-
const literal = p.value as ASTLiteral;
|
|
1348
|
-
config![p.key.name] = literal.value;
|
|
1349
|
-
}
|
|
1350
|
-
});
|
|
1351
|
-
const number = theaction.properties.find((p) => p.key.name === 'number');
|
|
1352
|
-
if (number && number.value.type === 'Literal') {
|
|
1353
|
-
const phoneNumber = number.value as ASTLiteral;
|
|
1354
|
-
suffix = hash(String(phoneNumber.value));
|
|
1355
|
-
break;
|
|
1356
|
-
}
|
|
1357
|
-
}
|
|
1358
|
-
break;
|
|
1359
|
-
}
|
|
1360
|
-
case 'email': {
|
|
1361
|
-
type = method;
|
|
1362
|
-
method = 'post';
|
|
1363
|
-
const theaction = action as ASTLiteral;
|
|
1364
|
-
if (theaction.type === 'Literal') {
|
|
1365
|
-
const email = String(theaction.value);
|
|
1366
|
-
suffix = hash(email);
|
|
1367
|
-
break;
|
|
1368
|
-
}
|
|
1369
|
-
break;
|
|
1370
|
-
}
|
|
1371
1387
|
case 'cron': {
|
|
1388
|
+
// DEPRECATED: router.cron()
|
|
1389
|
+
// This method now throws errors at runtime
|
|
1372
1390
|
type = method;
|
|
1373
1391
|
method = 'post';
|
|
1374
1392
|
const theaction = action as ASTLiteral;
|
|
@@ -1437,8 +1455,8 @@ export async function parseRoute(
|
|
|
1437
1455
|
}
|
|
1438
1456
|
}
|
|
1439
1457
|
|
|
1440
|
-
// For WebSocket/SSE routes that don't use validator(), fall back to exported schemas
|
|
1441
|
-
if (!routeConfig.hasValidator && (type === 'websocket' || type === 'sse')) {
|
|
1458
|
+
// For WebSocket/SSE/stream routes that don't use validator(), fall back to exported schemas
|
|
1459
|
+
if (!routeConfig.hasValidator && (type === 'websocket' || type === 'sse' || type === 'stream')) {
|
|
1442
1460
|
if (!routeConfig.inputSchemaVariable && exportedInputSchemaName) {
|
|
1443
1461
|
routeConfig.inputSchemaVariable = exportedInputSchemaName;
|
|
1444
1462
|
}
|
|
@@ -131,10 +131,10 @@ app.route('/', workbenchRouter);
|
|
|
131
131
|
`
|
|
132
132
|
: '';
|
|
133
133
|
|
|
134
|
-
// Asset proxy routes - generated
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
134
|
+
// Asset proxy routes - Always generated, but only active at runtime when:
|
|
135
|
+
// - NODE_ENV !== 'production' (isDevelopment())
|
|
136
|
+
// - and process.env.VITE_PORT is set
|
|
137
|
+
const assetProxyRoutes = `
|
|
138
138
|
// Asset proxy routes - Development mode only (proxies to Vite asset server)
|
|
139
139
|
if (isDevelopment() && process.env.VITE_PORT) {
|
|
140
140
|
const VITE_ASSET_PORT = parseInt(process.env.VITE_PORT, 10);
|
|
@@ -193,8 +193,7 @@ if (isDevelopment() && process.env.VITE_PORT) {
|
|
|
193
193
|
app.get('/*.tsx', proxyToVite);
|
|
194
194
|
app.get('/*.css', proxyToVite);
|
|
195
195
|
}
|
|
196
|
-
|
|
197
|
-
: '';
|
|
196
|
+
`;
|
|
198
197
|
|
|
199
198
|
// Runtime mode detection helper (defined at top level for reuse)
|
|
200
199
|
// Dynamic property access prevents Bun.build from inlining NODE_ENV at build time
|
|
@@ -330,13 +329,18 @@ if (isDevelopment()) {
|
|
|
330
329
|
if (typeof Bun !== 'undefined') {
|
|
331
330
|
// Enable process exit protection now that we're starting the server
|
|
332
331
|
enableProcessExitProtection();
|
|
333
|
-
|
|
332
|
+
|
|
334
333
|
const port = parseInt(process.env.PORT || '3500', 10);
|
|
335
334
|
const server = Bun.serve({
|
|
336
|
-
fetch:
|
|
335
|
+
fetch: (req, server) => {
|
|
336
|
+
// Get timeout from config on each request (0 = no timeout)
|
|
337
|
+
server.timeout(req, getAppConfig()?.requestTimeout ?? 0);
|
|
338
|
+
return app.fetch(req, server);
|
|
339
|
+
},
|
|
337
340
|
websocket,
|
|
338
341
|
port,
|
|
339
342
|
hostname: '127.0.0.1',
|
|
343
|
+
development: isDevelopment(),
|
|
340
344
|
});
|
|
341
345
|
|
|
342
346
|
// Make server available globally for health checks
|
|
@@ -428,16 +432,6 @@ if (isDevelopment()) {
|
|
|
428
432
|
const serverUrl = \`http://127.0.0.1:\${process.env.PORT || '3500'}\`;
|
|
429
433
|
const otel = register({ processors: [], logLevel: (process.env.AGENTUITY_LOG_LEVEL || 'info') as LogLevel });
|
|
430
434
|
|
|
431
|
-
// Get app state and config for use below
|
|
432
|
-
const appState = getAppState();
|
|
433
|
-
const appConfig = getAppConfig();
|
|
434
|
-
|
|
435
|
-
createServices(otel.logger, appConfig, serverUrl);
|
|
436
|
-
|
|
437
|
-
// Make logger and tracer globally available for user's app.ts
|
|
438
|
-
setGlobalLogger(otel.logger);
|
|
439
|
-
setGlobalTracer(otel.tracer);
|
|
440
|
-
|
|
441
435
|
// Step 2: Create router and set as global
|
|
442
436
|
const app = createRouter();
|
|
443
437
|
setGlobalRouter(app);
|
|
@@ -466,6 +460,15 @@ app.use('/api/*', createAgentMiddleware(''));
|
|
|
466
460
|
await import('../../app.js');
|
|
467
461
|
|
|
468
462
|
// Step 5: Initialize providers
|
|
463
|
+
const appState = getAppState();
|
|
464
|
+
const appConfig = getAppConfig();
|
|
465
|
+
|
|
466
|
+
createServices(otel.logger, appConfig, serverUrl);
|
|
467
|
+
|
|
468
|
+
// Make logger and tracer globally available for user's app.ts
|
|
469
|
+
setGlobalLogger(otel.logger);
|
|
470
|
+
setGlobalTracer(otel.tracer);
|
|
471
|
+
|
|
469
472
|
const threadProvider = getThreadProvider();
|
|
470
473
|
const sessionProvider = getSessionProvider();
|
|
471
474
|
|
|
@@ -397,13 +397,15 @@ function extractEvalsFromSource(
|
|
|
397
397
|
|
|
398
398
|
if (isCreateEvalCall) {
|
|
399
399
|
const callExpr = n as unknown as ASTCallExpression;
|
|
400
|
+
let evalName: string | undefined;
|
|
401
|
+
let description: string | undefined;
|
|
402
|
+
|
|
400
403
|
if (callExpr.arguments.length >= 2) {
|
|
404
|
+
// Format: agent.createEval('name', { config })
|
|
401
405
|
const nameArg = callExpr.arguments[0] as ASTLiteral;
|
|
402
|
-
|
|
406
|
+
evalName = String(nameArg.value);
|
|
403
407
|
|
|
404
408
|
const callargexp = callExpr.arguments[1] as ASTObjectExpression;
|
|
405
|
-
let description: string | undefined;
|
|
406
|
-
|
|
407
409
|
if (callargexp.properties) {
|
|
408
410
|
for (const prop of callargexp.properties) {
|
|
409
411
|
if (prop.key.name === 'metadata' && prop.value.type === 'ObjectExpression') {
|
|
@@ -415,7 +417,47 @@ function extractEvalsFromSource(
|
|
|
415
417
|
}
|
|
416
418
|
}
|
|
417
419
|
}
|
|
420
|
+
} else if (callExpr.arguments.length === 1) {
|
|
421
|
+
// Format: agent.createEval(presetEval({ name: '...', ... }))
|
|
422
|
+
// or: agent.createEval(presetEval()) - uses preset's default name
|
|
423
|
+
// or: agent.createEval({ name: '...', ... })
|
|
424
|
+
const arg = callExpr.arguments[0] as ASTNode;
|
|
425
|
+
|
|
426
|
+
// Handle CallExpression: presetEval({ name: '...' }) or presetEval()
|
|
427
|
+
if (arg.type === 'CallExpression') {
|
|
428
|
+
const innerCall = arg as unknown as ASTCallExpression;
|
|
429
|
+
|
|
430
|
+
// Try to get name from the call arguments first
|
|
431
|
+
if (innerCall.arguments.length >= 1) {
|
|
432
|
+
const configArg = innerCall.arguments[0] as ASTObjectExpression;
|
|
433
|
+
if (configArg.type === 'ObjectExpression' && configArg.properties) {
|
|
434
|
+
const configMap = parseObjectExpressionToMap(configArg);
|
|
435
|
+
evalName = configMap.get('name');
|
|
436
|
+
description = configMap.get('description');
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// Fallback: use the callee name as the eval name (e.g., politeness())
|
|
441
|
+
if (!evalName && innerCall.callee) {
|
|
442
|
+
const callee = innerCall.callee as ASTNode;
|
|
443
|
+
if (callee.type === 'Identifier') {
|
|
444
|
+
evalName = (callee as ASTNodeIdentifier).name;
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
// Handle ObjectExpression: { name: '...', handler: ... }
|
|
450
|
+
if (arg.type === 'ObjectExpression') {
|
|
451
|
+
const configArg = arg as ASTObjectExpression;
|
|
452
|
+
if (configArg.properties) {
|
|
453
|
+
const configMap = parseObjectExpressionToMap(configArg);
|
|
454
|
+
evalName = configMap.get('name');
|
|
455
|
+
description = configMap.get('description');
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
}
|
|
418
459
|
|
|
460
|
+
if (evalName) {
|
|
419
461
|
const id = getEvalId(projectId, deploymentId, filename, evalName, version);
|
|
420
462
|
const evalId = generateStableEvalId(projectId, agentId, evalName);
|
|
421
463
|
|
|
@@ -95,7 +95,7 @@ export async function installExternalsAndBuild(options: ServerBundleOptions): Pr
|
|
|
95
95
|
}
|
|
96
96
|
}
|
|
97
97
|
} catch (error) {
|
|
98
|
-
logger.
|
|
98
|
+
logger.debug('Failed to load agentuity.config.ts for externals:', error);
|
|
99
99
|
}
|
|
100
100
|
}
|
|
101
101
|
|
|
@@ -49,11 +49,63 @@ export async function startViteAssetServer(
|
|
|
49
49
|
// Create Vite server with config
|
|
50
50
|
const server = await createServer(config);
|
|
51
51
|
|
|
52
|
-
// Start listening
|
|
53
|
-
|
|
52
|
+
// Start listening with timeout to prevent hangs
|
|
53
|
+
// Vite will choose alternate port if preferred is taken
|
|
54
|
+
const STARTUP_TIMEOUT_MS = 30000; // 30 seconds
|
|
54
55
|
|
|
55
|
-
|
|
56
|
-
|
|
56
|
+
try {
|
|
57
|
+
await Promise.race([
|
|
58
|
+
server.listen(),
|
|
59
|
+
new Promise<never>((_, reject) => {
|
|
60
|
+
const timeoutId = setTimeout(() => {
|
|
61
|
+
reject(
|
|
62
|
+
new Error(
|
|
63
|
+
`Vite asset server failed to start within ${STARTUP_TIMEOUT_MS / 1000}s`
|
|
64
|
+
)
|
|
65
|
+
);
|
|
66
|
+
}, STARTUP_TIMEOUT_MS);
|
|
67
|
+
// Clean up timeout when listen succeeds (via finally in the outer try)
|
|
68
|
+
server.httpServer?.once('listening', () => clearTimeout(timeoutId));
|
|
69
|
+
}),
|
|
70
|
+
]);
|
|
71
|
+
} catch (error) {
|
|
72
|
+
// Attempt to close the server on failure
|
|
73
|
+
try {
|
|
74
|
+
await server.close();
|
|
75
|
+
} catch {
|
|
76
|
+
// Ignore close errors
|
|
77
|
+
}
|
|
78
|
+
throw error;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Helper to get port from httpServer
|
|
82
|
+
const getPortFromHttpServer = (): number | null => {
|
|
83
|
+
const httpServer = server.httpServer;
|
|
84
|
+
if (httpServer) {
|
|
85
|
+
const address = httpServer.address();
|
|
86
|
+
if (address && typeof address === 'object' && 'port' in address) {
|
|
87
|
+
return address.port;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return null;
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
// Get the actual port Vite is using from the httpServer
|
|
94
|
+
// server.config.server.port is the requested port, not the actual one
|
|
95
|
+
let actualPort = preferredPort;
|
|
96
|
+
|
|
97
|
+
// The resolved URL contains the actual port being used
|
|
98
|
+
const resolvedUrls = server.resolvedUrls;
|
|
99
|
+
if (resolvedUrls?.local && resolvedUrls.local.length > 0) {
|
|
100
|
+
try {
|
|
101
|
+
const url = new URL(resolvedUrls.local[0]);
|
|
102
|
+
actualPort = parseInt(url.port, 10) || preferredPort;
|
|
103
|
+
} catch {
|
|
104
|
+
actualPort = getPortFromHttpServer() ?? preferredPort;
|
|
105
|
+
}
|
|
106
|
+
} else {
|
|
107
|
+
actualPort = getPortFromHttpServer() ?? preferredPort;
|
|
108
|
+
}
|
|
57
109
|
|
|
58
110
|
logger.debug(`✅ Vite asset server started on port ${actualPort}`);
|
|
59
111
|
if (actualPort !== preferredPort) {
|
|
@@ -240,6 +240,10 @@ interface BuildResult {
|
|
|
240
240
|
export async function runAllBuilds(options: Omit<ViteBuildOptions, 'mode'>): Promise<BuildResult> {
|
|
241
241
|
const { rootDir, projectId = '', dev = false, logger } = options;
|
|
242
242
|
|
|
243
|
+
if (!dev) {
|
|
244
|
+
rmSync(join(rootDir, '.agentuity'), { force: true, recursive: true });
|
|
245
|
+
}
|
|
246
|
+
|
|
243
247
|
const result: BuildResult = {
|
|
244
248
|
workbench: { included: false, duration: 0 },
|
|
245
249
|
client: { included: false, duration: 0 },
|
|
@@ -250,7 +254,6 @@ export async function runAllBuilds(options: Omit<ViteBuildOptions, 'mode'>): Pro
|
|
|
250
254
|
const { loadAgentuityConfig, getWorkbenchConfig } = await import('./config-loader');
|
|
251
255
|
const config = await loadAgentuityConfig(rootDir, logger);
|
|
252
256
|
const workbenchConfig = getWorkbenchConfig(config, dev);
|
|
253
|
-
|
|
254
257
|
// Generate workbench files BEFORE any builds if enabled (dev mode only)
|
|
255
258
|
if (workbenchConfig.enabled) {
|
|
256
259
|
logger.debug('Workbench enabled (dev mode), generating files before build...');
|