@agentuity/cli 0.0.100 → 0.0.101
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/AGENTS.md +1 -1
- package/dist/api.d.ts +1 -0
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +1 -1
- package/dist/api.js.map +1 -1
- package/dist/cmd/build/ast.d.ts +2 -1
- package/dist/cmd/build/ast.d.ts.map +1 -1
- package/dist/cmd/build/ast.js +135 -47
- 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 +220 -188
- 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 +103 -45
- package/dist/cmd/build/vite/agent-discovery.js.map +1 -1
- package/dist/cmd/build/vite/bun-dev-server.js +1 -1
- package/dist/cmd/build/vite/bun-dev-server.js.map +1 -1
- package/dist/cmd/build/vite/docs-generator.d.ts +13 -0
- package/dist/cmd/build/vite/docs-generator.d.ts.map +1 -0
- package/dist/cmd/build/vite/docs-generator.js +81 -0
- package/dist/cmd/build/vite/docs-generator.js.map +1 -0
- package/dist/cmd/build/vite/index.d.ts +3 -3
- package/dist/cmd/build/vite/index.d.ts.map +1 -1
- package/dist/cmd/build/vite/index.js +9 -7
- package/dist/cmd/build/vite/index.js.map +1 -1
- package/dist/cmd/build/vite/lifecycle-generator.d.ts +1 -1
- package/dist/cmd/build/vite/lifecycle-generator.d.ts.map +1 -1
- package/dist/cmd/build/vite/lifecycle-generator.js +19 -5
- package/dist/cmd/build/vite/lifecycle-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 +145 -0
- package/dist/cmd/build/vite/metadata-generator.js.map +1 -1
- package/dist/cmd/build/vite/registry-generator.d.ts +3 -3
- package/dist/cmd/build/vite/registry-generator.d.ts.map +1 -1
- package/dist/cmd/build/vite/registry-generator.js +627 -103
- package/dist/cmd/build/vite/registry-generator.js.map +1 -1
- package/dist/cmd/build/vite/route-discovery.d.ts +4 -0
- package/dist/cmd/build/vite/route-discovery.d.ts.map +1 -1
- package/dist/cmd/build/vite/route-discovery.js.map +1 -1
- package/dist/cmd/build/vite/server-bundler.d.ts.map +1 -1
- package/dist/cmd/build/vite/server-bundler.js +18 -1
- package/dist/cmd/build/vite/server-bundler.js.map +1 -1
- package/dist/cmd/build/vite/vite-builder.d.ts +1 -1
- package/dist/cmd/build/vite/vite-builder.d.ts.map +1 -1
- package/dist/cmd/build/vite/vite-builder.js +28 -18
- package/dist/cmd/build/vite/vite-builder.js.map +1 -1
- package/dist/cmd/build/vite-bundler.js +6 -6
- package/dist/cmd/build/vite-bundler.js.map +1 -1
- package/dist/cmd/cloud/deploy.d.ts.map +1 -1
- package/dist/cmd/cloud/deploy.js +11 -5
- package/dist/cmd/cloud/deploy.js.map +1 -1
- package/dist/cmd/dev/file-watcher.d.ts.map +1 -1
- package/dist/cmd/dev/file-watcher.js +4 -2
- 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 +102 -21
- package/dist/cmd/dev/index.js.map +1 -1
- package/dist/cmd/dev/sync.d.ts.map +1 -1
- package/dist/cmd/dev/sync.js +19 -3
- package/dist/cmd/dev/sync.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +8 -0
- package/dist/config.js.map +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -1
- package/dist/index.js.map +1 -1
- package/package.json +5 -8
- package/src/api.ts +1 -1
- package/src/cmd/build/ast.ts +161 -48
- package/src/cmd/build/entry-generator.ts +225 -190
- package/src/cmd/build/vite/agent-discovery.ts +151 -58
- package/src/cmd/build/vite/bun-dev-server.ts +1 -1
- package/src/cmd/build/vite/docs-generator.ts +87 -0
- package/src/cmd/build/vite/index.ts +9 -7
- package/src/cmd/build/vite/lifecycle-generator.ts +19 -5
- package/src/cmd/build/vite/metadata-generator.ts +178 -0
- package/src/cmd/build/vite/registry-generator.ts +727 -108
- package/src/cmd/build/vite/route-discovery.ts +4 -0
- package/src/cmd/build/vite/server-bundler.ts +20 -1
- package/src/cmd/build/vite/vite-builder.ts +44 -30
- package/src/cmd/build/vite-bundler.ts +6 -6
- package/src/cmd/cloud/deploy.ts +15 -5
- package/src/cmd/dev/file-watcher.ts +8 -2
- package/src/cmd/dev/index.ts +141 -30
- package/src/cmd/dev/sync.ts +41 -6
- package/src/config.ts +9 -0
- package/src/index.ts +0 -5
- package/src/runtime-bootstrap.md +1 -1
- package/dist/runtime-bootstrap.d.ts +0 -56
- package/dist/runtime-bootstrap.d.ts.map +0 -1
- package/dist/runtime-bootstrap.js +0 -95
- package/dist/runtime-bootstrap.js.map +0 -1
- package/src/runtime-bootstrap.ts +0 -131
|
@@ -33,8 +33,12 @@ export interface RouteInfo {
|
|
|
33
33
|
routeType: 'api' | 'sms' | 'email' | 'cron' | 'websocket' | 'sse' | 'stream';
|
|
34
34
|
agentVariable?: string;
|
|
35
35
|
agentImportPath?: string;
|
|
36
|
+
agentName?: string;
|
|
37
|
+
agentDescription?: string;
|
|
36
38
|
inputSchemaVariable?: string;
|
|
37
39
|
outputSchemaVariable?: string;
|
|
40
|
+
inputSchemaCode?: string;
|
|
41
|
+
outputSchemaCode?: string;
|
|
38
42
|
stream?: boolean;
|
|
39
43
|
}
|
|
40
44
|
|
|
@@ -24,7 +24,7 @@ export async function installExternalsAndBuild(options: ServerBundleOptions): Pr
|
|
|
24
24
|
|
|
25
25
|
logger.debug('[server-bundler] Starting server bundle process');
|
|
26
26
|
|
|
27
|
-
const entryPath = join(rootDir, '
|
|
27
|
+
const entryPath = join(rootDir, 'src/generated/app.ts');
|
|
28
28
|
const outDir = join(rootDir, '.agentuity');
|
|
29
29
|
|
|
30
30
|
logger.debug(`[server-bundler] Entry: ${entryPath}, OutDir: ${outDir}`);
|
|
@@ -246,6 +246,10 @@ export async function installExternalsAndBuild(options: ServerBundleOptions): Pr
|
|
|
246
246
|
minify: !dev,
|
|
247
247
|
sourcemap: (dev ? 'inline' : 'external') as 'inline' | 'external',
|
|
248
248
|
external,
|
|
249
|
+
// CRITICAL: Disable environment variable inlining for server builds
|
|
250
|
+
// Server code must read process.env at RUNTIME, not have values baked in at build time
|
|
251
|
+
// Without this, NODE_ENV and other env vars get inlined as string literals
|
|
252
|
+
env: 'disable' as const,
|
|
249
253
|
define: userDefine, // Include custom define values from agentuity.config.ts
|
|
250
254
|
plugins: [patchPlugin],
|
|
251
255
|
naming: {
|
|
@@ -257,6 +261,12 @@ export async function installExternalsAndBuild(options: ServerBundleOptions): Pr
|
|
|
257
261
|
`Bun.build config: ${JSON.stringify({ ...buildConfig, external: `[${external.length} packages]` }, null, 2)}`
|
|
258
262
|
);
|
|
259
263
|
|
|
264
|
+
// WORKAROUND: Temporarily delete NODE_ENV to prevent Bun.build from inlining it
|
|
265
|
+
// See: https://github.com/oven-sh/bun/issues/20183
|
|
266
|
+
// Even with env: 'disable', Bun.build still inlines NODE_ENV at build time
|
|
267
|
+
const originalNodeEnv = process.env.NODE_ENV;
|
|
268
|
+
delete process.env.NODE_ENV;
|
|
269
|
+
|
|
260
270
|
// Verify entry point exists before building
|
|
261
271
|
if (!(await Bun.file(entryPath).exists())) {
|
|
262
272
|
throw new Error(`Entry point not found: ${entryPath}`);
|
|
@@ -268,6 +278,10 @@ export async function installExternalsAndBuild(options: ServerBundleOptions): Pr
|
|
|
268
278
|
try {
|
|
269
279
|
result = await Bun.build(buildConfig);
|
|
270
280
|
} catch (error: unknown) {
|
|
281
|
+
// Restore NODE_ENV after build attempt
|
|
282
|
+
if (originalNodeEnv !== undefined) {
|
|
283
|
+
process.env.NODE_ENV = originalNodeEnv;
|
|
284
|
+
}
|
|
271
285
|
logger.error('Bun.build threw an exception');
|
|
272
286
|
|
|
273
287
|
// Handle AggregateError with build/resolve messages
|
|
@@ -286,6 +300,11 @@ export async function installExternalsAndBuild(options: ServerBundleOptions): Pr
|
|
|
286
300
|
throw error;
|
|
287
301
|
}
|
|
288
302
|
|
|
303
|
+
// Restore NODE_ENV after successful build
|
|
304
|
+
if (originalNodeEnv !== undefined) {
|
|
305
|
+
process.env.NODE_ENV = originalNodeEnv;
|
|
306
|
+
}
|
|
307
|
+
|
|
289
308
|
if (!result.success) {
|
|
290
309
|
logger.error('Bun.build failed for server');
|
|
291
310
|
logger.error(
|
|
@@ -25,7 +25,7 @@ export interface ViteBuildOptions {
|
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
27
|
* Run a Vite build for the specified mode
|
|
28
|
-
*
|
|
28
|
+
* Uses inline Vite config (customizable via agentuity.config.ts)
|
|
29
29
|
*/
|
|
30
30
|
export async function runViteBuild(options: ViteBuildOptions): Promise<void> {
|
|
31
31
|
const { rootDir, mode, dev = false, projectId = '', deploymentId = '', logger } = options;
|
|
@@ -35,7 +35,17 @@ export async function runViteBuild(options: ViteBuildOptions): Promise<void> {
|
|
|
35
35
|
// For server mode, use Bun.build (preserves process.env at runtime)
|
|
36
36
|
if (mode === 'server') {
|
|
37
37
|
try {
|
|
38
|
-
|
|
38
|
+
const srcDir = join(rootDir, 'src');
|
|
39
|
+
|
|
40
|
+
// Generate documentation files (if they don't exist)
|
|
41
|
+
const { generateDocumentation } = await import('./docs-generator');
|
|
42
|
+
await generateDocumentation(srcDir, logger);
|
|
43
|
+
|
|
44
|
+
// Generate lifecycle types (if setup() exists)
|
|
45
|
+
const { generateLifecycleTypes } = await import('./lifecycle-generator');
|
|
46
|
+
await generateLifecycleTypes(rootDir, srcDir, logger);
|
|
47
|
+
|
|
48
|
+
// Then, generate the entry file
|
|
39
49
|
const { generateEntryFile } = await import('../entry-generator');
|
|
40
50
|
await generateEntryFile({
|
|
41
51
|
rootDir,
|
|
@@ -45,7 +55,7 @@ export async function runViteBuild(options: ViteBuildOptions): Promise<void> {
|
|
|
45
55
|
mode: dev ? 'dev' : 'prod',
|
|
46
56
|
});
|
|
47
57
|
|
|
48
|
-
//
|
|
58
|
+
// Finally, build with Bun.build
|
|
49
59
|
const { installExternalsAndBuild } = await import('./server-bundler');
|
|
50
60
|
await installExternalsAndBuild({
|
|
51
61
|
rootDir,
|
|
@@ -213,10 +223,36 @@ export async function runAllBuilds(options: Omit<ViteBuildOptions, 'mode'>): Pro
|
|
|
213
223
|
await generateWorkbenchFiles(rootDir, projectId, workbenchConfig, logger);
|
|
214
224
|
}
|
|
215
225
|
|
|
226
|
+
// 1. Discover agents and routes BEFORE builds
|
|
227
|
+
logger.debug('Discovering agents and routes...');
|
|
228
|
+
const { generateAgentRegistry, generateRouteRegistry } = await import('./registry-generator');
|
|
229
|
+
const { discoverAgents } = await import('./agent-discovery');
|
|
230
|
+
const { discoverRoutes } = await import('./route-discovery');
|
|
231
|
+
|
|
232
|
+
const srcDir = join(rootDir, 'src');
|
|
233
|
+
const agentMetadata = await discoverAgents(
|
|
234
|
+
srcDir,
|
|
235
|
+
projectId,
|
|
236
|
+
options.deploymentId || '',
|
|
237
|
+
logger
|
|
238
|
+
);
|
|
239
|
+
const { routes, routeInfoList } = await discoverRoutes(
|
|
240
|
+
srcDir,
|
|
241
|
+
projectId,
|
|
242
|
+
options.deploymentId || '',
|
|
243
|
+
logger
|
|
244
|
+
);
|
|
245
|
+
|
|
246
|
+
// Generate agent and route registries for type augmentation BEFORE builds
|
|
247
|
+
// (TypeScript needs these files to exist during type checking)
|
|
248
|
+
generateAgentRegistry(srcDir, agentMetadata);
|
|
249
|
+
generateRouteRegistry(srcDir, routeInfoList);
|
|
250
|
+
logger.debug('Agent and route registries generated');
|
|
251
|
+
|
|
216
252
|
// Check if web frontend exists
|
|
217
253
|
const hasWebFrontend = await Bun.file(join(rootDir, 'src', 'web', 'index.html')).exists();
|
|
218
254
|
|
|
219
|
-
//
|
|
255
|
+
// 2. Build client (only if web frontend exists)
|
|
220
256
|
if (hasWebFrontend) {
|
|
221
257
|
logger.debug('Building client assets...');
|
|
222
258
|
try {
|
|
@@ -237,7 +273,7 @@ export async function runAllBuilds(options: Omit<ViteBuildOptions, 'mode'>): Pro
|
|
|
237
273
|
logger.debug('Skipping client build - no src/web/index.html found');
|
|
238
274
|
}
|
|
239
275
|
|
|
240
|
-
//
|
|
276
|
+
// 3. Build workbench (if enabled in config)
|
|
241
277
|
if (workbenchConfig.enabled) {
|
|
242
278
|
logger.debug('Building workbench assets...');
|
|
243
279
|
try {
|
|
@@ -256,7 +292,7 @@ export async function runAllBuilds(options: Omit<ViteBuildOptions, 'mode'>): Pro
|
|
|
256
292
|
}
|
|
257
293
|
}
|
|
258
294
|
|
|
259
|
-
//
|
|
295
|
+
// 4. Build server
|
|
260
296
|
logger.debug('Building server...');
|
|
261
297
|
try {
|
|
262
298
|
const started = Date.now();
|
|
@@ -268,31 +304,9 @@ export async function runAllBuilds(options: Omit<ViteBuildOptions, 'mode'>): Pro
|
|
|
268
304
|
throw error;
|
|
269
305
|
}
|
|
270
306
|
|
|
271
|
-
//
|
|
272
|
-
logger.debug('Generating
|
|
307
|
+
// 5. Generate metadata (after all builds complete)
|
|
308
|
+
logger.debug('Generating metadata...');
|
|
273
309
|
const { generateMetadata, writeMetadataFile } = await import('./metadata-generator');
|
|
274
|
-
const { generateAgentRegistry, generateRouteRegistry } = await import('./registry-generator');
|
|
275
|
-
const { discoverAgents } = await import('./agent-discovery');
|
|
276
|
-
const { discoverRoutes } = await import('./route-discovery');
|
|
277
|
-
|
|
278
|
-
const srcDir = join(rootDir, 'src');
|
|
279
|
-
const agentMetadata = await discoverAgents(
|
|
280
|
-
srcDir,
|
|
281
|
-
projectId,
|
|
282
|
-
options.deploymentId || '',
|
|
283
|
-
logger
|
|
284
|
-
);
|
|
285
|
-
const { routes, routeInfoList } = await discoverRoutes(
|
|
286
|
-
srcDir,
|
|
287
|
-
projectId,
|
|
288
|
-
options.deploymentId || '',
|
|
289
|
-
logger
|
|
290
|
-
);
|
|
291
|
-
|
|
292
|
-
// Generate agent and route registries for type augmentation
|
|
293
|
-
generateAgentRegistry(srcDir, agentMetadata);
|
|
294
|
-
generateRouteRegistry(srcDir, routeInfoList);
|
|
295
|
-
logger.debug('Agent and route registries generated');
|
|
296
310
|
|
|
297
311
|
// Generate metadata
|
|
298
312
|
const metadata = await generateMetadata({
|
|
@@ -75,8 +75,8 @@ export async function viteBundle(options: ViteBundleOptions): Promise<{ output:
|
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
try {
|
|
78
|
-
// Run all
|
|
79
|
-
logger.debug('Starting
|
|
78
|
+
// Run all builds (client -> workbench -> server)
|
|
79
|
+
logger.debug('Starting builds...');
|
|
80
80
|
|
|
81
81
|
const result = await runAllBuilds({
|
|
82
82
|
rootDir,
|
|
@@ -90,16 +90,16 @@ export async function viteBundle(options: ViteBundleOptions): Promise<{ output:
|
|
|
90
90
|
});
|
|
91
91
|
|
|
92
92
|
if (result.client.included) {
|
|
93
|
-
output.push(tui.muted(`✓ Client
|
|
93
|
+
output.push(tui.muted(`✓ Client built in ${result.client.duration}ms`));
|
|
94
94
|
}
|
|
95
95
|
if (result.workbench.included) {
|
|
96
|
-
output.push(tui.muted(`✓ Workbench
|
|
96
|
+
output.push(tui.muted(`✓ Workbench built in ${result.workbench.duration}ms`));
|
|
97
97
|
}
|
|
98
98
|
if (result.server.included) {
|
|
99
|
-
output.push(tui.muted(`✓ Server
|
|
99
|
+
output.push(tui.muted(`✓ Server built in ${result.server.duration}ms`));
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
-
logger.debug('
|
|
102
|
+
logger.debug('All builds complete');
|
|
103
103
|
|
|
104
104
|
return { output };
|
|
105
105
|
} catch (error) {
|
package/src/cmd/cloud/deploy.ts
CHANGED
|
@@ -6,8 +6,9 @@ import { tmpdir } from 'node:os';
|
|
|
6
6
|
import { StructuredError } from '@agentuity/core';
|
|
7
7
|
import { isRunningFromExecutable } from '../upgrade';
|
|
8
8
|
import { createSubcommand } from '../../types';
|
|
9
|
+
import { getUserAgent } from '../../api';
|
|
9
10
|
import * as tui from '../../tui';
|
|
10
|
-
import { saveProjectDir, getDefaultConfigDir } from '../../config';
|
|
11
|
+
import { saveProjectDir, getDefaultConfigDir, loadProjectSDKKey } from '../../config';
|
|
11
12
|
import {
|
|
12
13
|
runSteps,
|
|
13
14
|
stepSuccess,
|
|
@@ -106,6 +107,15 @@ export const deploySubcommand = createSubcommand({
|
|
|
106
107
|
let statusResult: DeploymentStatusResult | undefined;
|
|
107
108
|
const logs: string[] = [];
|
|
108
109
|
|
|
110
|
+
const sdkKey = await loadProjectSDKKey(ctx.logger, ctx.projectDir);
|
|
111
|
+
|
|
112
|
+
// Ensure SDK key is present before proceeding
|
|
113
|
+
if (!sdkKey) {
|
|
114
|
+
ctx.logger.fatal(
|
|
115
|
+
'SDK key not found. Run "agentuity auth login" to authenticate or set AGENTUITY_SDK_KEY environment variable.'
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
|
|
109
119
|
try {
|
|
110
120
|
await saveProjectDir(projectDir);
|
|
111
121
|
|
|
@@ -241,10 +251,6 @@ export const deploySubcommand = createSubcommand({
|
|
|
241
251
|
const deploymentZip = join(tmpdir(), `${deployment.id}.zip`);
|
|
242
252
|
await zipDir(join(projectDir, '.agentuity'), deploymentZip, {
|
|
243
253
|
filter: (_filename: string, relative: string) => {
|
|
244
|
-
// Exclude Vite-specific build artifacts
|
|
245
|
-
if (relative.endsWith('.generated.ts')) {
|
|
246
|
-
return false;
|
|
247
|
-
}
|
|
248
254
|
if (relative.startsWith('.vite/')) {
|
|
249
255
|
return false;
|
|
250
256
|
}
|
|
@@ -444,6 +450,10 @@ export const deploySubcommand = createSubcommand({
|
|
|
444
450
|
logger.debug('fetching stream: %s/%s', streamsUrl, streamId);
|
|
445
451
|
const resp = await fetch(`${streamsUrl}/${streamId}`, {
|
|
446
452
|
signal: logStreamController.signal,
|
|
453
|
+
headers: {
|
|
454
|
+
Authorization: `Bearer ${sdkKey}`,
|
|
455
|
+
'User-Agent': getUserAgent(),
|
|
456
|
+
},
|
|
447
457
|
});
|
|
448
458
|
if (!resp.ok || !resp.body) {
|
|
449
459
|
ctx.logger.trace(
|
|
@@ -142,10 +142,16 @@ export function createFileWatcher(options: FileWatcherOptions): FileWatcherManag
|
|
|
142
142
|
const contents = readdirSync(absPath);
|
|
143
143
|
if (contents.length === 0) {
|
|
144
144
|
// Check if this is an agent or API directory
|
|
145
|
-
if (
|
|
145
|
+
if (
|
|
146
|
+
normalizedPath.startsWith('src/agent/') ||
|
|
147
|
+
normalizedPath.includes('/src/agent/')
|
|
148
|
+
) {
|
|
146
149
|
logger.debug('Agent directory created: %s', changedFile);
|
|
147
150
|
createAgentTemplates(absPath);
|
|
148
|
-
} else if (
|
|
151
|
+
} else if (
|
|
152
|
+
normalizedPath.startsWith('src/api/') ||
|
|
153
|
+
normalizedPath.includes('/src/api/')
|
|
154
|
+
) {
|
|
149
155
|
logger.debug('API directory created: %s', changedFile);
|
|
150
156
|
createAPITemplates(absPath);
|
|
151
157
|
}
|
package/src/cmd/dev/index.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { resolve, join } from 'node:path';
|
|
3
3
|
import { existsSync } from 'node:fs';
|
|
4
|
-
import {
|
|
4
|
+
import { getServiceUrls } from '@agentuity/server';
|
|
5
5
|
import { createCommand } from '../../types';
|
|
6
6
|
import { startBunDevServer } from '../build/vite/bun-dev-server';
|
|
7
7
|
import { startViteAssetServer } from '../build/vite/vite-asset-server';
|
|
@@ -99,6 +99,13 @@ export const command = createCommand({
|
|
|
99
99
|
|
|
100
100
|
const interactive = !shouldDisableInteractive(opts.interactive);
|
|
101
101
|
|
|
102
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
103
|
+
let originalExit = (globalThis as any).AGENTUITY_PROCESS_EXIT;
|
|
104
|
+
|
|
105
|
+
if (!originalExit) {
|
|
106
|
+
originalExit = process.exit.bind(process);
|
|
107
|
+
}
|
|
108
|
+
|
|
102
109
|
for (const filename of mustHaves) {
|
|
103
110
|
if (!existsSync(filename)) {
|
|
104
111
|
missing.push(filename);
|
|
@@ -110,17 +117,22 @@ export const command = createCommand({
|
|
|
110
117
|
for (const filename of missing) {
|
|
111
118
|
tui.bullet(`Missing ${filename}`);
|
|
112
119
|
}
|
|
113
|
-
|
|
120
|
+
originalExit(1);
|
|
114
121
|
}
|
|
115
122
|
|
|
116
123
|
// Setup devmode and gravity (if using public URL)
|
|
117
124
|
const useMockService = process.env.DEVMODE_SYNC_SERVICE_MOCK === 'true';
|
|
118
125
|
const apiClient = auth ? new APIClient(getAPIBaseURL(config), logger, config) : null;
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
126
|
+
const syncService = apiClient
|
|
127
|
+
? createDevmodeSyncService({
|
|
128
|
+
logger,
|
|
129
|
+
apiClient,
|
|
130
|
+
mock: useMockService,
|
|
131
|
+
})
|
|
132
|
+
: null;
|
|
133
|
+
|
|
134
|
+
// Track previous metadata for sync diffing
|
|
135
|
+
let previousMetadata: Awaited<ReturnType<typeof import('../build/vite/metadata-generator').generateMetadata>> | undefined;
|
|
124
136
|
|
|
125
137
|
let devmode: DevmodeResponse | undefined;
|
|
126
138
|
let gravityBin: string | undefined;
|
|
@@ -224,8 +236,8 @@ export const command = createCommand({
|
|
|
224
236
|
|
|
225
237
|
// Start Vite asset server ONCE before restart loop
|
|
226
238
|
// Vite handles frontend HMR independently and stays running across backend restarts
|
|
227
|
-
let vitePort: number;
|
|
228
239
|
let viteServer: ServerLike | null = null;
|
|
240
|
+
let vitePort: number;
|
|
229
241
|
|
|
230
242
|
try {
|
|
231
243
|
logger.debug('Starting Vite asset server...');
|
|
@@ -241,13 +253,15 @@ export const command = createCommand({
|
|
|
241
253
|
);
|
|
242
254
|
} catch (error) {
|
|
243
255
|
tui.error(`Failed to start Vite asset server: ${error}`);
|
|
244
|
-
|
|
256
|
+
originalExit(1);
|
|
257
|
+
return;
|
|
245
258
|
}
|
|
246
259
|
|
|
247
260
|
// Restart loop - allows BACKEND server to restart on file changes
|
|
248
261
|
// Vite stays running and handles frontend changes via HMR
|
|
249
262
|
let shouldRestart = false;
|
|
250
263
|
let gravityProcess: ProcessLike | null = null;
|
|
264
|
+
let stdinListenerRegistered = false; // Track if stdin listener is already registered
|
|
251
265
|
|
|
252
266
|
const restartServer = () => {
|
|
253
267
|
shouldRestart = true;
|
|
@@ -293,11 +307,22 @@ export const command = createCommand({
|
|
|
293
307
|
}
|
|
294
308
|
}
|
|
295
309
|
|
|
296
|
-
|
|
310
|
+
originalExit(0);
|
|
297
311
|
};
|
|
298
312
|
|
|
299
|
-
|
|
300
|
-
|
|
313
|
+
// SIGINT/SIGTERM: coordinate shutdown between bundle and dev resources
|
|
314
|
+
let devShutdownHandled = false;
|
|
315
|
+
process.on('SIGINT', async () => {
|
|
316
|
+
if (devShutdownHandled) return;
|
|
317
|
+
devShutdownHandled = true;
|
|
318
|
+
// The bundle handles its own shutdown, we clean up dev resources
|
|
319
|
+
await cleanup();
|
|
320
|
+
});
|
|
321
|
+
process.on('SIGTERM', async () => {
|
|
322
|
+
if (devShutdownHandled) return;
|
|
323
|
+
devShutdownHandled = true;
|
|
324
|
+
await cleanup();
|
|
325
|
+
});
|
|
301
326
|
|
|
302
327
|
// Ensure Vite and gravity are always killed on exit (even if cleanup is bypassed)
|
|
303
328
|
process.on('exit', () => {
|
|
@@ -329,23 +354,76 @@ export const command = createCommand({
|
|
|
329
354
|
fileWatcher.pause();
|
|
330
355
|
|
|
331
356
|
try {
|
|
332
|
-
// Generate entry file for
|
|
357
|
+
// Generate entry file and bundle for dev server (with LLM patches)
|
|
333
358
|
await tui.spinner({
|
|
334
|
-
message: '
|
|
359
|
+
message: 'Building dev bundle',
|
|
335
360
|
callback: async () => {
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
361
|
+
const { generateEntryFile } = await import('../build/entry-generator');
|
|
362
|
+
await generateEntryFile({
|
|
363
|
+
rootDir,
|
|
364
|
+
projectId: project?.projectId ?? '',
|
|
365
|
+
deploymentId,
|
|
366
|
+
logger,
|
|
367
|
+
mode: 'dev',
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
// Bundle the app with LLM patches (dev mode = no minification)
|
|
371
|
+
const { installExternalsAndBuild } = await import('../build/vite/server-bundler');
|
|
372
|
+
await installExternalsAndBuild({
|
|
373
|
+
rootDir,
|
|
374
|
+
dev: true, // DevMode: no minification, inline sourcemaps
|
|
375
|
+
logger,
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
// Generate metadata file (needed for eval ID lookup at runtime)
|
|
379
|
+
const { discoverAgents } = await import('../build/vite/agent-discovery');
|
|
380
|
+
const { discoverRoutes } = await import('../build/vite/route-discovery');
|
|
381
|
+
const { generateMetadata, writeMetadataFile } = await import(
|
|
382
|
+
'../build/vite/metadata-generator'
|
|
383
|
+
);
|
|
384
|
+
|
|
385
|
+
const srcDir = join(rootDir, 'src');
|
|
386
|
+
const agents = await discoverAgents(
|
|
387
|
+
srcDir,
|
|
388
|
+
project?.projectId ?? '',
|
|
389
|
+
deploymentId,
|
|
390
|
+
logger
|
|
391
|
+
);
|
|
392
|
+
const { routes } = await discoverRoutes(
|
|
393
|
+
srcDir,
|
|
394
|
+
project?.projectId ?? '',
|
|
395
|
+
deploymentId,
|
|
396
|
+
logger
|
|
397
|
+
);
|
|
398
|
+
|
|
399
|
+
const metadata = await generateMetadata({
|
|
400
|
+
rootDir,
|
|
401
|
+
projectId: project?.projectId ?? '',
|
|
402
|
+
orgId: project?.orgId ?? '',
|
|
403
|
+
deploymentId,
|
|
404
|
+
agents,
|
|
405
|
+
routes,
|
|
406
|
+
dev: true,
|
|
407
|
+
logger,
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
writeMetadataFile(rootDir, metadata, true, logger);
|
|
411
|
+
|
|
412
|
+
// Sync metadata with backend (creates agents and evals in the database)
|
|
413
|
+
if (syncService && project?.projectId) {
|
|
414
|
+
await syncService.sync(
|
|
415
|
+
metadata,
|
|
416
|
+
previousMetadata,
|
|
417
|
+
project.projectId,
|
|
418
|
+
deploymentId
|
|
419
|
+
);
|
|
420
|
+
previousMetadata = metadata;
|
|
421
|
+
}
|
|
344
422
|
},
|
|
345
423
|
clearOnSuccess: true,
|
|
346
424
|
});
|
|
347
425
|
} catch (error) {
|
|
348
|
-
tui.error(`Failed to
|
|
426
|
+
tui.error(`Failed to build dev bundle: ${error}`);
|
|
349
427
|
tui.warn('Waiting for file changes to retry...');
|
|
350
428
|
|
|
351
429
|
// Resume watcher to detect changes for retry
|
|
@@ -364,6 +442,34 @@ export const command = createCommand({
|
|
|
364
442
|
}
|
|
365
443
|
|
|
366
444
|
try {
|
|
445
|
+
// Set environment variables for LLM provider patches BEFORE starting server
|
|
446
|
+
// These must be set so the bundled patches can route LLM calls through AI Gateway
|
|
447
|
+
const serviceUrls = getServiceUrls(project?.region);
|
|
448
|
+
|
|
449
|
+
process.env.AGENTUITY_SDK_DEV_MODE = 'true';
|
|
450
|
+
process.env.AGENTUITY_ENV = 'development';
|
|
451
|
+
process.env.NODE_ENV = 'development';
|
|
452
|
+
if (project?.region) {
|
|
453
|
+
process.env.AGENTUITY_REGION = project.region;
|
|
454
|
+
}
|
|
455
|
+
process.env.PORT = String(opts.port);
|
|
456
|
+
process.env.AGENTUITY_PORT = process.env.PORT;
|
|
457
|
+
|
|
458
|
+
if (project) {
|
|
459
|
+
process.env.AGENTUITY_TRANSPORT_URL = serviceUrls.catalyst;
|
|
460
|
+
process.env.AGENTUITY_CATALYST_URL = serviceUrls.catalyst;
|
|
461
|
+
process.env.AGENTUITY_VECTOR_URL = serviceUrls.vector;
|
|
462
|
+
process.env.AGENTUITY_KEYVALUE_URL = serviceUrls.keyvalue;
|
|
463
|
+
process.env.AGENTUITY_STREAM_URL = serviceUrls.stream;
|
|
464
|
+
process.env.AGENTUITY_CLOUD_ORG_ID = project.orgId;
|
|
465
|
+
process.env.AGENTUITY_CLOUD_PROJECT_ID = project.projectId;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
// Set Vite port for asset proxying in bundled app
|
|
469
|
+
process.env.VITE_PORT = String(vitePort);
|
|
470
|
+
|
|
471
|
+
logger.debug('Set VITE_PORT=%s for asset proxying', process.env.VITE_PORT);
|
|
472
|
+
|
|
367
473
|
// Start Bun dev server (Vite already running, just start backend)
|
|
368
474
|
await startBunDevServer({
|
|
369
475
|
rootDir,
|
|
@@ -375,8 +481,6 @@ export const command = createCommand({
|
|
|
375
481
|
vitePort, // Pass port of already-running Vite server
|
|
376
482
|
});
|
|
377
483
|
|
|
378
|
-
// Note: Bun server runs in-process, no separate app process needed
|
|
379
|
-
|
|
380
484
|
// Wait for app.ts to finish loading (Vite is ready but app may still be initializing)
|
|
381
485
|
// Give it 2 seconds to ensure app initialization completes
|
|
382
486
|
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
@@ -454,8 +558,14 @@ export const command = createCommand({
|
|
|
454
558
|
// TODO: Integrate sync service with Vite's buildStart/buildEnd hooks
|
|
455
559
|
// The sync service will be called when metadata changes are detected
|
|
456
560
|
|
|
457
|
-
// Handle keyboard shortcuts
|
|
458
|
-
if (
|
|
561
|
+
// Handle keyboard shortcuts - only register listener once
|
|
562
|
+
if (
|
|
563
|
+
interactive &&
|
|
564
|
+
process.stdin.isTTY &&
|
|
565
|
+
process.stdout.isTTY &&
|
|
566
|
+
!stdinListenerRegistered
|
|
567
|
+
) {
|
|
568
|
+
stdinListenerRegistered = true;
|
|
459
569
|
process.stdin.setRawMode(true);
|
|
460
570
|
process.stdin.resume();
|
|
461
571
|
process.stdin.setEncoding('utf8');
|
|
@@ -470,9 +580,10 @@ export const command = createCommand({
|
|
|
470
580
|
process.stdin.on('data', (data) => {
|
|
471
581
|
const key = data.toString();
|
|
472
582
|
|
|
473
|
-
// Handle Ctrl+C
|
|
583
|
+
// Handle Ctrl+C - send SIGINT to trigger graceful shutdown
|
|
474
584
|
if (key === '\u0003') {
|
|
475
|
-
|
|
585
|
+
process.kill(process.pid, 'SIGINT');
|
|
586
|
+
return;
|
|
476
587
|
}
|
|
477
588
|
|
|
478
589
|
switch (key) {
|
|
@@ -489,7 +600,7 @@ export const command = createCommand({
|
|
|
489
600
|
});
|
|
490
601
|
break;
|
|
491
602
|
case 'q':
|
|
492
|
-
|
|
603
|
+
originalExit(0);
|
|
493
604
|
break;
|
|
494
605
|
default:
|
|
495
606
|
process.stdout.write(data);
|
package/src/cmd/dev/sync.ts
CHANGED
|
@@ -171,9 +171,21 @@ class DevmodeSyncService implements IDevmodeSyncService {
|
|
|
171
171
|
for (const agent of currentMetadata.agents || []) {
|
|
172
172
|
if (agent.evals) {
|
|
173
173
|
currentEvalCount += agent.evals.length;
|
|
174
|
+
this.logger.info(
|
|
175
|
+
'[CLI EVAL SYNC] Agent "%s" has %d eval(s)',
|
|
176
|
+
agent.name,
|
|
177
|
+
agent.evals.length
|
|
178
|
+
);
|
|
179
|
+
for (const evalItem of agent.evals) {
|
|
180
|
+
this.logger.info(
|
|
181
|
+
'[CLI EVAL SYNC] - %s (evalId: %s)',
|
|
182
|
+
evalItem.name,
|
|
183
|
+
evalItem.evalId
|
|
184
|
+
);
|
|
185
|
+
}
|
|
174
186
|
}
|
|
175
187
|
}
|
|
176
|
-
this.logger.
|
|
188
|
+
this.logger.info('[CLI EVAL SYNC] Total current eval(s): %d', currentEvalCount);
|
|
177
189
|
|
|
178
190
|
// Get agents and evals to sync using shared diff logic
|
|
179
191
|
const { create: agentsToCreate, delete: agentsToDelete } = getAgentsToSync(
|
|
@@ -261,7 +273,14 @@ class DevmodeSyncService implements IDevmodeSyncService {
|
|
|
261
273
|
evalsToDelete: string[],
|
|
262
274
|
deploymentId: string
|
|
263
275
|
): Promise<void> {
|
|
276
|
+
this.logger.info(
|
|
277
|
+
'[CLI EVAL SYNC] syncEvals called: %d to create, %d to delete',
|
|
278
|
+
evals.length,
|
|
279
|
+
evalsToDelete.length
|
|
280
|
+
);
|
|
281
|
+
|
|
264
282
|
if (evals.length === 0 && evalsToDelete.length === 0) {
|
|
283
|
+
this.logger.info('[CLI EVAL SYNC] No evals to sync, skipping');
|
|
265
284
|
return;
|
|
266
285
|
}
|
|
267
286
|
|
|
@@ -270,12 +289,28 @@ class DevmodeSyncService implements IDevmodeSyncService {
|
|
|
270
289
|
create: evals,
|
|
271
290
|
delete: evalsToDelete,
|
|
272
291
|
};
|
|
273
|
-
this.logger.trace(
|
|
274
|
-
'[CLI EVAL SYNC] Sending payload to POST /cli/devmode/eval: %s',
|
|
275
|
-
JSON.stringify(payload, null, 2)
|
|
276
|
-
);
|
|
277
292
|
|
|
278
|
-
|
|
293
|
+
this.logger.info('[CLI EVAL SYNC] Sending payload to POST /cli/devmode/eval:');
|
|
294
|
+
for (const evalItem of evals) {
|
|
295
|
+
this.logger.info(
|
|
296
|
+
'[CLI EVAL SYNC] - %s (id: %s, evalId: %s)',
|
|
297
|
+
evalItem.name,
|
|
298
|
+
evalItem.id,
|
|
299
|
+
evalItem.evalId
|
|
300
|
+
);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
try {
|
|
304
|
+
await this.apiClient.post(
|
|
305
|
+
'/cli/devmode/eval',
|
|
306
|
+
payload,
|
|
307
|
+
z.object({ success: z.boolean() })
|
|
308
|
+
);
|
|
309
|
+
this.logger.info('[CLI EVAL SYNC] Sync successful');
|
|
310
|
+
} catch (error) {
|
|
311
|
+
this.logger.error('[CLI EVAL SYNC] Sync failed: %s', error);
|
|
312
|
+
throw error;
|
|
313
|
+
}
|
|
279
314
|
}
|
|
280
315
|
}
|
|
281
316
|
|
package/src/config.ts
CHANGED
|
@@ -364,6 +364,15 @@ export async function getAuth(): Promise<AuthData | null> {
|
|
|
364
364
|
};
|
|
365
365
|
}
|
|
366
366
|
|
|
367
|
+
// Priority 1a: Allow automated login from environment variables (this is set in deployment)
|
|
368
|
+
if (process.env.AGENTUITY_API_KEY) {
|
|
369
|
+
return {
|
|
370
|
+
apiKey: process.env.AGENTUITY_API_KEY,
|
|
371
|
+
userId: '',
|
|
372
|
+
expires: new Date(Date.now() + 30 * 60_000),
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
|
|
367
376
|
// Priority 2: On macOS, try to read from Keychain
|
|
368
377
|
if (isMacOS()) {
|
|
369
378
|
try {
|
package/src/index.ts
CHANGED
|
@@ -75,11 +75,6 @@ export { showBanner } from './banner';
|
|
|
75
75
|
export { discoverCommands } from './cmd';
|
|
76
76
|
export { detectColorScheme } from './terminal';
|
|
77
77
|
export { getCommandPrefix, getCommand } from './command-prefix';
|
|
78
|
-
export {
|
|
79
|
-
bootstrapRuntimeEnv,
|
|
80
|
-
type RuntimeBootstrapOptions,
|
|
81
|
-
type RuntimeBootstrapResult,
|
|
82
|
-
} from './runtime-bootstrap';
|
|
83
78
|
export * as tui from './tui';
|
|
84
79
|
export {
|
|
85
80
|
createRepl,
|
package/src/runtime-bootstrap.md
CHANGED
|
@@ -43,7 +43,7 @@ Call `bootstrapRuntimeEnv()` at the top of your `app.ts` **before** `createApp()
|
|
|
43
43
|
|
|
44
44
|
```ts
|
|
45
45
|
import { createApp } from '@agentuity/runtime';
|
|
46
|
-
import { bootstrapRuntimeEnv } from '@agentuity/
|
|
46
|
+
import { bootstrapRuntimeEnv } from '@agentuity/runtime';
|
|
47
47
|
|
|
48
48
|
// Bootstrap runtime environment based on active profile
|
|
49
49
|
await bootstrapRuntimeEnv();
|