@agentuity/cli 0.0.98 → 0.0.100
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.map +1 -1
- package/dist/auth.js +5 -0
- package/dist/auth.js.map +1 -1
- package/dist/banner.d.ts.map +1 -1
- package/dist/banner.js +22 -6
- package/dist/banner.js.map +1 -1
- package/dist/cmd/build/entry-generator.d.ts.map +1 -1
- package/dist/cmd/build/entry-generator.js +84 -61
- package/dist/cmd/build/entry-generator.js.map +1 -1
- package/dist/cmd/build/vite/bun-dev-server.d.ts +3 -7
- package/dist/cmd/build/vite/bun-dev-server.d.ts.map +1 -1
- package/dist/cmd/build/vite/bun-dev-server.js +5 -14
- package/dist/cmd/build/vite/bun-dev-server.js.map +1 -1
- package/dist/cmd/build/vite/index.d.ts +0 -1
- package/dist/cmd/build/vite/index.d.ts.map +1 -1
- package/dist/cmd/build/vite/index.js +0 -1
- package/dist/cmd/build/vite/index.js.map +1 -1
- package/dist/cmd/build/vite/server-bundler.d.ts.map +1 -1
- package/dist/cmd/build/vite/server-bundler.js +41 -1
- package/dist/cmd/build/vite/server-bundler.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 +17 -1
- package/dist/cmd/build/vite/vite-asset-server-config.js.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 +22 -4
- package/dist/cmd/build/vite/vite-builder.js.map +1 -1
- package/dist/cmd/cloud/deploy.d.ts.map +1 -1
- package/dist/cmd/cloud/deploy.js +32 -21
- package/dist/cmd/cloud/deploy.js.map +1 -1
- package/dist/cmd/dev/file-watcher.d.ts +24 -0
- package/dist/cmd/dev/file-watcher.d.ts.map +1 -0
- package/dist/cmd/dev/file-watcher.js +213 -0
- package/dist/cmd/dev/file-watcher.js.map +1 -0
- package/dist/cmd/dev/index.d.ts.map +1 -1
- package/dist/cmd/dev/index.js +61 -23
- package/dist/cmd/dev/index.js.map +1 -1
- package/dist/cmd/project/create.d.ts.map +1 -1
- package/dist/cmd/project/create.js +8 -2
- package/dist/cmd/project/create.js.map +1 -1
- package/dist/cmd/setup/index.d.ts.map +1 -1
- package/dist/cmd/setup/index.js +3 -3
- package/dist/cmd/setup/index.js.map +1 -1
- package/dist/repl.js +2 -2
- package/dist/repl.js.map +1 -1
- package/dist/types.d.ts +6 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +8 -4
- package/src/auth.ts +6 -0
- package/src/banner.ts +25 -6
- package/src/cmd/build/entry-generator.ts +84 -62
- package/src/cmd/build/vite/bun-dev-server.ts +8 -18
- package/src/cmd/build/vite/index.ts +0 -1
- package/src/cmd/build/vite/server-bundler.ts +52 -1
- package/src/cmd/build/vite/vite-asset-server-config.ts +22 -1
- package/src/cmd/build/vite/vite-asset-server.ts +1 -1
- package/src/cmd/build/vite/vite-builder.ts +30 -4
- package/src/cmd/cloud/deploy.ts +41 -24
- package/src/cmd/dev/file-watcher.ts +264 -0
- package/src/cmd/dev/index.ts +69 -24
- package/src/cmd/project/create.ts +13 -3
- package/src/cmd/setup/index.ts +7 -3
- package/src/repl.ts +2 -2
- package/src/types.ts +6 -0
- package/dist/cmd/build/vite/patch-plugin.d.ts +0 -21
- package/dist/cmd/build/vite/patch-plugin.d.ts.map +0 -1
- package/dist/cmd/build/vite/patch-plugin.js +0 -70
- package/dist/cmd/build/vite/patch-plugin.js.map +0 -1
- package/src/cmd/build/vite/patch-plugin.ts +0 -88
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File Watcher for Dev Server Hot Reload
|
|
3
|
+
*
|
|
4
|
+
* Watches source files and triggers server restart on changes.
|
|
5
|
+
* Handles both backend (API, agents, lib) and generates restart signals.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { watch, type FSWatcher, statSync, readdirSync } from 'node:fs';
|
|
9
|
+
import { resolve } from 'node:path';
|
|
10
|
+
import type { Logger } from '../../types';
|
|
11
|
+
import { createAgentTemplates, createAPITemplates } from './templates';
|
|
12
|
+
|
|
13
|
+
export interface FileWatcherOptions {
|
|
14
|
+
rootDir: string;
|
|
15
|
+
logger: Logger;
|
|
16
|
+
onRestart: () => void;
|
|
17
|
+
additionalPaths?: string[];
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface FileWatcherManager {
|
|
21
|
+
start: () => void;
|
|
22
|
+
stop: () => void;
|
|
23
|
+
pause: () => void;
|
|
24
|
+
resume: () => void;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Create a file watcher manager for hot reload
|
|
29
|
+
*/
|
|
30
|
+
export function createFileWatcher(options: FileWatcherOptions): FileWatcherManager {
|
|
31
|
+
const { rootDir, logger, onRestart, additionalPaths = [] } = options;
|
|
32
|
+
|
|
33
|
+
const watchers: FSWatcher[] = [];
|
|
34
|
+
let paused = false;
|
|
35
|
+
let buildCooldownTimer: NodeJS.Timeout | null = null;
|
|
36
|
+
|
|
37
|
+
// Watch the entire root directory recursively
|
|
38
|
+
// This is simpler and more reliable than watching individual paths
|
|
39
|
+
const watchDirs = [rootDir];
|
|
40
|
+
|
|
41
|
+
// Directories to ignore
|
|
42
|
+
const ignorePaths = [
|
|
43
|
+
'.agentuity',
|
|
44
|
+
'node_modules',
|
|
45
|
+
'.git',
|
|
46
|
+
'dist',
|
|
47
|
+
'build',
|
|
48
|
+
'.next',
|
|
49
|
+
'.turbo',
|
|
50
|
+
'src/web', // Vite handles frontend with HMR - no backend restart needed
|
|
51
|
+
];
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Check if a path should be ignored
|
|
55
|
+
*/
|
|
56
|
+
function shouldIgnorePath(changedFile: string | null, watchDir: string): boolean {
|
|
57
|
+
if (!changedFile) return false;
|
|
58
|
+
|
|
59
|
+
const absPath = resolve(watchDir, changedFile);
|
|
60
|
+
|
|
61
|
+
// Check against ignore list - match both relative path and absolute path
|
|
62
|
+
for (const ignorePath of ignorePaths) {
|
|
63
|
+
// Check relative path from watchDir
|
|
64
|
+
if (
|
|
65
|
+
changedFile === ignorePath ||
|
|
66
|
+
changedFile.startsWith(`${ignorePath}/`) ||
|
|
67
|
+
changedFile.startsWith(`${ignorePath}\\`)
|
|
68
|
+
) {
|
|
69
|
+
logger.trace('File change ignored (%s): %s', ignorePath, changedFile);
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Check if absolute path contains the ignore pattern
|
|
74
|
+
const ignoreAbsPath = resolve(rootDir, ignorePath);
|
|
75
|
+
if (
|
|
76
|
+
absPath === ignoreAbsPath ||
|
|
77
|
+
absPath.startsWith(`${ignoreAbsPath}/`) ||
|
|
78
|
+
absPath.startsWith(`${ignoreAbsPath}\\`)
|
|
79
|
+
) {
|
|
80
|
+
logger.trace('File change ignored (%s): %s', ignorePath, changedFile);
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Also check if changedFile path includes the ignore pattern anywhere
|
|
85
|
+
// This handles cases like "some/path/.agentuity/file.js"
|
|
86
|
+
const normalizedChanged = changedFile.replace(/\\/g, '/');
|
|
87
|
+
const normalizedIgnore = ignorePath.replace(/\\/g, '/');
|
|
88
|
+
if (
|
|
89
|
+
normalizedChanged.includes(`/${normalizedIgnore}/`) ||
|
|
90
|
+
normalizedChanged.includes(`/${normalizedIgnore}`)
|
|
91
|
+
) {
|
|
92
|
+
logger.trace('File change ignored (%s in path): %s', ignorePath, changedFile);
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Ignore temp files from editors
|
|
98
|
+
if (changedFile.match(/\.(tmp|swp|swo|swx)$|~$/)) {
|
|
99
|
+
logger.trace('File change ignored (temp file): %s', changedFile);
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Ignore hidden files (except .env)
|
|
104
|
+
if (changedFile.startsWith('.') && !changedFile.startsWith('.env')) {
|
|
105
|
+
logger.trace('File change ignored (hidden file): %s', changedFile);
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Handle file change event
|
|
114
|
+
*/
|
|
115
|
+
function handleFileChange(eventType: string, changedFile: string | null, watchDir: string) {
|
|
116
|
+
if (paused) {
|
|
117
|
+
logger.trace('File change ignored (watcher paused): %s', changedFile);
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (shouldIgnorePath(changedFile, watchDir)) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// During build cooldown, ignore changes (they're likely build outputs)
|
|
126
|
+
if (buildCooldownTimer) {
|
|
127
|
+
logger.trace('File change ignored (build cooldown): %s', changedFile);
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Check if an empty directory was created in src/agent/ or src/api/
|
|
132
|
+
// This helps with developer experience by auto-scaffolding template files
|
|
133
|
+
if (changedFile && eventType === 'rename') {
|
|
134
|
+
try {
|
|
135
|
+
const absPath = resolve(watchDir, changedFile);
|
|
136
|
+
// Normalize the path for comparison (use forward slashes)
|
|
137
|
+
const normalizedPath = changedFile.replace(/\\/g, '/');
|
|
138
|
+
|
|
139
|
+
// Check if it's a directory and empty
|
|
140
|
+
const stats = statSync(absPath);
|
|
141
|
+
if (stats.isDirectory()) {
|
|
142
|
+
const contents = readdirSync(absPath);
|
|
143
|
+
if (contents.length === 0) {
|
|
144
|
+
// Check if this is an agent or API directory
|
|
145
|
+
if (normalizedPath.startsWith('src/agent/') || normalizedPath.includes('/src/agent/')) {
|
|
146
|
+
logger.debug('Agent directory created: %s', changedFile);
|
|
147
|
+
createAgentTemplates(absPath);
|
|
148
|
+
} else if (normalizedPath.startsWith('src/api/') || normalizedPath.includes('/src/api/')) {
|
|
149
|
+
logger.debug('API directory created: %s', changedFile);
|
|
150
|
+
createAPITemplates(absPath);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
} catch (error) {
|
|
155
|
+
// File might have been deleted or doesn't exist yet - this is normal
|
|
156
|
+
logger.trace('Unable to check directory for template creation: %s', error);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
logger.debug('File changed (%s): %s', eventType, changedFile || watchDir);
|
|
161
|
+
onRestart();
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Start watching files
|
|
166
|
+
*/
|
|
167
|
+
function start() {
|
|
168
|
+
logger.debug('Starting file watchers for hot reload...');
|
|
169
|
+
|
|
170
|
+
// Watch root directory (already absolute path)
|
|
171
|
+
for (const watchPath of watchDirs) {
|
|
172
|
+
try {
|
|
173
|
+
logger.trace('Setting up watcher for: %s', watchPath);
|
|
174
|
+
|
|
175
|
+
const watcher = watch(watchPath, { recursive: true }, (eventType, changedFile) => {
|
|
176
|
+
handleFileChange(eventType, changedFile, watchPath);
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
watchers.push(watcher);
|
|
180
|
+
logger.trace('Watcher started for: %s', watchPath);
|
|
181
|
+
} catch (error) {
|
|
182
|
+
logger.warn('Failed to start watcher for %s: %s', watchPath, error);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Watch additional paths if provided
|
|
187
|
+
if (additionalPaths && additionalPaths.length > 0) {
|
|
188
|
+
for (const additionalPath of additionalPaths) {
|
|
189
|
+
const fullPath = resolve(rootDir, additionalPath);
|
|
190
|
+
try {
|
|
191
|
+
logger.trace('Setting up watcher for additional path: %s', fullPath);
|
|
192
|
+
|
|
193
|
+
const watcher = watch(fullPath, { recursive: true }, (eventType, changedFile) => {
|
|
194
|
+
handleFileChange(eventType, changedFile, fullPath);
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
watchers.push(watcher);
|
|
198
|
+
logger.trace('Watcher started for additional path: %s', fullPath);
|
|
199
|
+
} catch (error) {
|
|
200
|
+
logger.warn('Failed to start watcher for %s: %s', fullPath, error);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
logger.debug('File watchers started (%d paths)', watchers.length);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Stop all watchers
|
|
210
|
+
*/
|
|
211
|
+
function stop() {
|
|
212
|
+
logger.debug('Stopping file watchers...');
|
|
213
|
+
|
|
214
|
+
for (const watcher of watchers) {
|
|
215
|
+
try {
|
|
216
|
+
watcher.close();
|
|
217
|
+
} catch (error) {
|
|
218
|
+
logger.trace('Error closing watcher: %s', error);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
watchers.length = 0;
|
|
223
|
+
|
|
224
|
+
if (buildCooldownTimer) {
|
|
225
|
+
clearTimeout(buildCooldownTimer);
|
|
226
|
+
buildCooldownTimer = null;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
logger.debug('File watchers stopped');
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Temporarily pause watching (e.g., during build)
|
|
234
|
+
*/
|
|
235
|
+
function pause() {
|
|
236
|
+
paused = true;
|
|
237
|
+
logger.trace('File watchers paused');
|
|
238
|
+
|
|
239
|
+
// Set cooldown timer to ignore changes for a bit after build
|
|
240
|
+
if (buildCooldownTimer) {
|
|
241
|
+
clearTimeout(buildCooldownTimer);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
buildCooldownTimer = setTimeout(() => {
|
|
245
|
+
buildCooldownTimer = null;
|
|
246
|
+
logger.trace('Build cooldown expired');
|
|
247
|
+
}, 500); // 500ms cooldown
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Resume watching
|
|
252
|
+
*/
|
|
253
|
+
function resume() {
|
|
254
|
+
paused = false;
|
|
255
|
+
logger.trace('File watchers resumed');
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
return {
|
|
259
|
+
start,
|
|
260
|
+
stop,
|
|
261
|
+
pause,
|
|
262
|
+
resume,
|
|
263
|
+
};
|
|
264
|
+
}
|
package/src/cmd/dev/index.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { existsSync } from 'node:fs';
|
|
|
4
4
|
import { internalExit } from '@agentuity/runtime';
|
|
5
5
|
import { createCommand } from '../../types';
|
|
6
6
|
import { startBunDevServer } from '../build/vite/bun-dev-server';
|
|
7
|
+
import { startViteAssetServer } from '../build/vite/vite-asset-server';
|
|
7
8
|
import * as tui from '../../tui';
|
|
8
9
|
import { getCommand } from '../../command-prefix';
|
|
9
10
|
import { generateEndpoint, type DevmodeResponse } from './api';
|
|
@@ -13,6 +14,7 @@ import { createDevmodeSyncService } from './sync';
|
|
|
13
14
|
import { getDevmodeDeploymentId } from '../build/ast';
|
|
14
15
|
import { getDefaultConfigDir, saveConfig } from '../../config';
|
|
15
16
|
import type { Config } from '../../types';
|
|
17
|
+
import { createFileWatcher } from './file-watcher';
|
|
16
18
|
|
|
17
19
|
const DEFAULT_PORT = 3500;
|
|
18
20
|
const MIN_PORT = 1024;
|
|
@@ -220,9 +222,31 @@ export const command = createCommand({
|
|
|
220
222
|
centerTitle: false,
|
|
221
223
|
});
|
|
222
224
|
|
|
223
|
-
//
|
|
224
|
-
|
|
225
|
+
// Start Vite asset server ONCE before restart loop
|
|
226
|
+
// Vite handles frontend HMR independently and stays running across backend restarts
|
|
227
|
+
let vitePort: number;
|
|
225
228
|
let viteServer: ServerLike | null = null;
|
|
229
|
+
|
|
230
|
+
try {
|
|
231
|
+
logger.debug('Starting Vite asset server...');
|
|
232
|
+
const viteResult = await startViteAssetServer({
|
|
233
|
+
rootDir,
|
|
234
|
+
logger,
|
|
235
|
+
workbenchPath: workbench.config?.route,
|
|
236
|
+
});
|
|
237
|
+
viteServer = viteResult.server;
|
|
238
|
+
vitePort = viteResult.port;
|
|
239
|
+
logger.debug(
|
|
240
|
+
`Vite asset server running on port ${vitePort} (stays running across backend restarts)`
|
|
241
|
+
);
|
|
242
|
+
} catch (error) {
|
|
243
|
+
tui.error(`Failed to start Vite asset server: ${error}`);
|
|
244
|
+
internalExit(1);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Restart loop - allows BACKEND server to restart on file changes
|
|
248
|
+
// Vite stays running and handles frontend changes via HMR
|
|
249
|
+
let shouldRestart = false;
|
|
226
250
|
let gravityProcess: ProcessLike | null = null;
|
|
227
251
|
|
|
228
252
|
const restartServer = () => {
|
|
@@ -233,13 +257,23 @@ export const command = createCommand({
|
|
|
233
257
|
logger.info('DevMode ready 🚀');
|
|
234
258
|
};
|
|
235
259
|
|
|
236
|
-
//
|
|
237
|
-
|
|
260
|
+
// Create file watcher for backend hot reload
|
|
261
|
+
const fileWatcher = createFileWatcher({
|
|
262
|
+
rootDir,
|
|
263
|
+
logger,
|
|
264
|
+
onRestart: restartServer,
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
// Start file watcher (will be paused during builds)
|
|
268
|
+
fileWatcher.start();
|
|
238
269
|
|
|
239
270
|
// Setup signal handlers once before the loop
|
|
240
271
|
const cleanup = async () => {
|
|
241
272
|
tui.info('Shutting down...');
|
|
242
273
|
|
|
274
|
+
// Stop file watcher
|
|
275
|
+
fileWatcher.stop();
|
|
276
|
+
|
|
243
277
|
// Close Vite asset server first
|
|
244
278
|
if (viteServer) {
|
|
245
279
|
await viteServer.close();
|
|
@@ -265,13 +299,24 @@ export const command = createCommand({
|
|
|
265
299
|
process.on('SIGINT', cleanup);
|
|
266
300
|
process.on('SIGTERM', cleanup);
|
|
267
301
|
|
|
268
|
-
// Ensure gravity
|
|
269
|
-
// Use SIGKILL for immediate termination since the process is already exiting
|
|
302
|
+
// Ensure Vite and gravity are always killed on exit (even if cleanup is bypassed)
|
|
270
303
|
process.on('exit', () => {
|
|
304
|
+
// Close Vite server synchronously if possible
|
|
305
|
+
// Note: Vite's close() is async, but we can't await in 'exit' handler
|
|
306
|
+
// Most Vite implementations handle sync close gracefully
|
|
307
|
+
if (viteServer) {
|
|
308
|
+
try {
|
|
309
|
+
viteServer.close();
|
|
310
|
+
} catch {
|
|
311
|
+
// Ignore errors during exit cleanup
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// Kill gravity client with SIGKILL for immediate termination
|
|
271
316
|
if (gravityProcess && gravityProcess.exitCode === null) {
|
|
272
317
|
try {
|
|
273
318
|
gravityProcess.kill('SIGKILL');
|
|
274
|
-
} catch
|
|
319
|
+
} catch {
|
|
275
320
|
// Ignore errors during exit cleanup
|
|
276
321
|
}
|
|
277
322
|
}
|
|
@@ -280,6 +325,9 @@ export const command = createCommand({
|
|
|
280
325
|
while (true) {
|
|
281
326
|
shouldRestart = false;
|
|
282
327
|
|
|
328
|
+
// Pause file watcher during build to avoid loops
|
|
329
|
+
fileWatcher.pause();
|
|
330
|
+
|
|
283
331
|
try {
|
|
284
332
|
// Generate entry file for Vite before starting dev server
|
|
285
333
|
await tui.spinner({
|
|
@@ -300,6 +348,9 @@ export const command = createCommand({
|
|
|
300
348
|
tui.error(`Failed to generate entry file: ${error}`);
|
|
301
349
|
tui.warn('Waiting for file changes to retry...');
|
|
302
350
|
|
|
351
|
+
// Resume watcher to detect changes for retry
|
|
352
|
+
fileWatcher.resume();
|
|
353
|
+
|
|
303
354
|
// Wait for next restart trigger
|
|
304
355
|
await new Promise<void>((resolve) => {
|
|
305
356
|
const checkRestart = setInterval(() => {
|
|
@@ -313,17 +364,17 @@ export const command = createCommand({
|
|
|
313
364
|
}
|
|
314
365
|
|
|
315
366
|
try {
|
|
316
|
-
// Start Bun dev server (
|
|
317
|
-
|
|
367
|
+
// Start Bun dev server (Vite already running, just start backend)
|
|
368
|
+
await startBunDevServer({
|
|
318
369
|
rootDir,
|
|
319
370
|
port: opts.port,
|
|
320
371
|
projectId: project?.projectId,
|
|
321
372
|
orgId: project?.orgId,
|
|
322
373
|
deploymentId,
|
|
323
374
|
logger,
|
|
375
|
+
vitePort, // Pass port of already-running Vite server
|
|
324
376
|
});
|
|
325
377
|
|
|
326
|
-
viteServer = result.viteAssetServer.server;
|
|
327
378
|
// Note: Bun server runs in-process, no separate app process needed
|
|
328
379
|
|
|
329
380
|
// Wait for app.ts to finish loading (Vite is ready but app may still be initializing)
|
|
@@ -441,7 +492,7 @@ export const command = createCommand({
|
|
|
441
492
|
internalExit(0);
|
|
442
493
|
break;
|
|
443
494
|
default:
|
|
444
|
-
|
|
495
|
+
process.stdout.write(data);
|
|
445
496
|
break;
|
|
446
497
|
}
|
|
447
498
|
});
|
|
@@ -449,6 +500,9 @@ export const command = createCommand({
|
|
|
449
500
|
|
|
450
501
|
showWelcome();
|
|
451
502
|
|
|
503
|
+
// Start/resume file watcher now that server is ready
|
|
504
|
+
fileWatcher.resume();
|
|
505
|
+
|
|
452
506
|
// Wait for restart signal
|
|
453
507
|
await new Promise<void>((resolve) => {
|
|
454
508
|
const checkRestart = setInterval(() => {
|
|
@@ -459,14 +513,10 @@ export const command = createCommand({
|
|
|
459
513
|
}, 100);
|
|
460
514
|
});
|
|
461
515
|
|
|
462
|
-
// Restart triggered - cleanup and loop
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
// Close Vite asset server
|
|
466
|
-
if (viteServer) {
|
|
467
|
-
await viteServer.close();
|
|
468
|
-
}
|
|
516
|
+
// Restart triggered - cleanup and loop (Vite stays running)
|
|
517
|
+
logger.debug('Restarting backend server...');
|
|
469
518
|
|
|
519
|
+
// Kill gravity client (if running)
|
|
470
520
|
if (gravityProcess) {
|
|
471
521
|
try {
|
|
472
522
|
gravityProcess.kill('SIGTERM');
|
|
@@ -485,11 +535,7 @@ export const command = createCommand({
|
|
|
485
535
|
tui.error(`Error during server operation: ${error}`);
|
|
486
536
|
tui.warn('Waiting for file changes to retry...');
|
|
487
537
|
|
|
488
|
-
// Cleanup on error
|
|
489
|
-
if (viteServer) {
|
|
490
|
-
await viteServer.close();
|
|
491
|
-
}
|
|
492
|
-
|
|
538
|
+
// Cleanup on error (Vite stays running)
|
|
493
539
|
if (gravityProcess) {
|
|
494
540
|
try {
|
|
495
541
|
gravityProcess.kill('SIGTERM');
|
|
@@ -501,7 +547,6 @@ export const command = createCommand({
|
|
|
501
547
|
logger.debug('Error killing gravity process on error: %s', err);
|
|
502
548
|
}
|
|
503
549
|
}
|
|
504
|
-
if (viteServer) await viteServer.close();
|
|
505
550
|
|
|
506
551
|
// Wait for next restart trigger
|
|
507
552
|
await new Promise<void>((resolve) => {
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { createSubcommand } from '../../types';
|
|
1
|
+
import { createSubcommand, type CommandContext, type AuthData } from '../../types';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import { runCreateFlow } from './template-flow';
|
|
4
4
|
import { getCommand } from '../../command-prefix';
|
|
5
|
+
import type { APIClient as APIClientType } from '../../api';
|
|
5
6
|
|
|
6
7
|
const ProjectCreateResponseSchema = z.object({
|
|
7
8
|
success: z.boolean().describe('Whether the operation succeeded'),
|
|
@@ -21,7 +22,7 @@ export const createProjectSubcommand = createSubcommand({
|
|
|
21
22
|
banner: true,
|
|
22
23
|
toplevel: true,
|
|
23
24
|
idempotent: false,
|
|
24
|
-
optional: { auth: true,
|
|
25
|
+
optional: { auth: true, region: true, apiClient: true },
|
|
25
26
|
examples: [
|
|
26
27
|
{ command: getCommand('project create'), description: 'Create new item' },
|
|
27
28
|
{ command: getCommand('project create --name my-ai-agent'), description: 'Create new item' },
|
|
@@ -69,7 +70,16 @@ export const createProjectSubcommand = createSubcommand({
|
|
|
69
70
|
},
|
|
70
71
|
|
|
71
72
|
async handler(ctx) {
|
|
72
|
-
const { logger, opts, auth, config, apiClient,
|
|
73
|
+
const { logger, opts, auth, config, apiClient, region } = ctx;
|
|
74
|
+
|
|
75
|
+
// Only get org if registering
|
|
76
|
+
let orgId: string | undefined;
|
|
77
|
+
if (opts.register === true && auth && apiClient) {
|
|
78
|
+
const { optionalOrg } = await import('../../auth');
|
|
79
|
+
orgId = await optionalOrg(
|
|
80
|
+
ctx as CommandContext & { apiClient?: APIClientType; auth?: AuthData }
|
|
81
|
+
);
|
|
82
|
+
}
|
|
73
83
|
|
|
74
84
|
await runCreateFlow({
|
|
75
85
|
projectName: opts.name,
|
package/src/cmd/setup/index.ts
CHANGED
|
@@ -29,10 +29,14 @@ export const command = createCommand({
|
|
|
29
29
|
tui.output(`${tui.muted('To get started, run:')}`);
|
|
30
30
|
tui.newline();
|
|
31
31
|
tui.output(
|
|
32
|
-
`${getCommand('login')} ${tui.muted('Login to an existing account (or signup)')}`
|
|
32
|
+
`${tui.colorPrimary(getCommand('login'))} ${tui.muted('Login to an existing account (or signup)')}`
|
|
33
|
+
);
|
|
34
|
+
tui.output(
|
|
35
|
+
`${tui.colorPrimary(getCommand('create'))} ${tui.muted('Create a project')}`
|
|
36
|
+
);
|
|
37
|
+
tui.output(
|
|
38
|
+
`${tui.colorPrimary(getCommand('help'))} ${tui.muted('List commands and options')}`
|
|
33
39
|
);
|
|
34
|
-
tui.output(`${getCommand('create')} ${tui.muted('Create a project')}`);
|
|
35
|
-
tui.output(`${getCommand('help')} ${tui.muted('List commands and options')}`);
|
|
36
40
|
} else {
|
|
37
41
|
tui.success('Welcome back! 🙌');
|
|
38
42
|
}
|
package/src/repl.ts
CHANGED
|
@@ -236,7 +236,7 @@ async function loadHistory(name: string): Promise<string[]> {
|
|
|
236
236
|
|
|
237
237
|
const content = await Bun.file(historyFile).text();
|
|
238
238
|
return content.split('\n').filter((line) => line.trim());
|
|
239
|
-
} catch
|
|
239
|
+
} catch {
|
|
240
240
|
return [];
|
|
241
241
|
}
|
|
242
242
|
}
|
|
@@ -253,7 +253,7 @@ async function saveHistory(name: string, history: string[]): Promise<void> {
|
|
|
253
253
|
|
|
254
254
|
const historyFile = join(historyDir, `${name}.txt`);
|
|
255
255
|
await Bun.write(historyFile, history.join('\n'));
|
|
256
|
-
} catch
|
|
256
|
+
} catch {
|
|
257
257
|
// Silently fail - history is not critical
|
|
258
258
|
}
|
|
259
259
|
}
|
package/src/types.ts
CHANGED
|
@@ -137,6 +137,12 @@ export interface AgentuityConfig {
|
|
|
137
137
|
* These are added AFTER Agentuity's built-in plugins
|
|
138
138
|
*/
|
|
139
139
|
plugins?: Array<import('vite').Plugin>;
|
|
140
|
+
/**
|
|
141
|
+
* Additional define constants for code replacement in Vite builds
|
|
142
|
+
* These are merged with Agentuity's default defines
|
|
143
|
+
* Note: Cannot override AGENTUITY_PUBLIC_* or process.env.NODE_ENV
|
|
144
|
+
*/
|
|
145
|
+
define?: Record<string, string>;
|
|
140
146
|
}
|
|
141
147
|
|
|
142
148
|
/**
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Vite Plugin for Runtime Patching
|
|
3
|
-
*
|
|
4
|
-
* Applies runtime patches to AI SDK packages to inject:
|
|
5
|
-
* - Agentuity AI Gateway routing
|
|
6
|
-
* - Telemetry enablement
|
|
7
|
-
* - Environment variable guards
|
|
8
|
-
*
|
|
9
|
-
* This plugin uses Vite's transform hook to modify module code during bundling.
|
|
10
|
-
*/
|
|
11
|
-
import type { Plugin } from 'vite';
|
|
12
|
-
import type { Logger } from '../../../types';
|
|
13
|
-
export interface PatchPluginOptions {
|
|
14
|
-
logger: Logger;
|
|
15
|
-
dev?: boolean;
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* Create Vite plugin that patches AI SDK modules at build time
|
|
19
|
-
*/
|
|
20
|
-
export declare function patchPlugin(options: PatchPluginOptions): Plugin;
|
|
21
|
-
//# sourceMappingURL=patch-plugin.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"patch-plugin.d.ts","sourceRoot":"","sources":["../../../../src/cmd/build/vite/patch-plugin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AACnC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAG7C,MAAM,WAAW,kBAAkB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,OAAO,CAAC;CACd;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,MAAM,CAgE/D"}
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Vite Plugin for Runtime Patching
|
|
3
|
-
*
|
|
4
|
-
* Applies runtime patches to AI SDK packages to inject:
|
|
5
|
-
* - Agentuity AI Gateway routing
|
|
6
|
-
* - Telemetry enablement
|
|
7
|
-
* - Environment variable guards
|
|
8
|
-
*
|
|
9
|
-
* This plugin uses Vite's transform hook to modify module code during bundling.
|
|
10
|
-
*/
|
|
11
|
-
import { generatePatches, applyPatch } from '../patch';
|
|
12
|
-
/**
|
|
13
|
-
* Create Vite plugin that patches AI SDK modules at build time
|
|
14
|
-
*/
|
|
15
|
-
export function patchPlugin(options) {
|
|
16
|
-
const { logger } = options;
|
|
17
|
-
const patches = generatePatches();
|
|
18
|
-
// Log registered patches
|
|
19
|
-
logger.trace('Patch plugin initialized with %d patch(es)', patches.size);
|
|
20
|
-
for (const [moduleName] of patches) {
|
|
21
|
-
logger.trace(' - %s', moduleName);
|
|
22
|
-
}
|
|
23
|
-
return {
|
|
24
|
-
name: 'agentuity:patch',
|
|
25
|
-
enforce: 'post', // Run after other transforms
|
|
26
|
-
/**
|
|
27
|
-
* Transform hook - patches modules during bundling
|
|
28
|
-
*/
|
|
29
|
-
async transform(code, id) {
|
|
30
|
-
// Check if this module needs patching
|
|
31
|
-
for (const [moduleName, patch] of patches) {
|
|
32
|
-
// Match module by package name
|
|
33
|
-
const normalizedId = id.replace(/\\/g, '/');
|
|
34
|
-
// Check if this file matches the patch module
|
|
35
|
-
// Example: node_modules/@ai-sdk/openai/dist/index.js
|
|
36
|
-
if (!normalizedId.includes(`node_modules/${moduleName}/`)) {
|
|
37
|
-
continue;
|
|
38
|
-
}
|
|
39
|
-
// If patch specifies a filename, ensure it matches
|
|
40
|
-
if (patch.filename) {
|
|
41
|
-
const expectedPath = `${moduleName}/${patch.filename}`;
|
|
42
|
-
if (!normalizedId.includes(expectedPath) &&
|
|
43
|
-
!normalizedId.includes(`${expectedPath}.js`) &&
|
|
44
|
-
!normalizedId.includes(`${expectedPath}.mjs`) &&
|
|
45
|
-
!normalizedId.includes(`${expectedPath}.ts`)) {
|
|
46
|
-
continue;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
// Apply the patch
|
|
50
|
-
logger.debug('Applying patch to %s', moduleName);
|
|
51
|
-
try {
|
|
52
|
-
const [patchedCode] = await applyPatch(id, patch);
|
|
53
|
-
// Return transformed code with source map
|
|
54
|
-
return {
|
|
55
|
-
code: patchedCode,
|
|
56
|
-
map: null, // Could add source map generation here
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
catch (error) {
|
|
60
|
-
logger.warn('Failed to apply patch to %s: %s', moduleName, error);
|
|
61
|
-
// Continue without patching on error
|
|
62
|
-
return null;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
// No patch needed
|
|
66
|
-
return null;
|
|
67
|
-
},
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
//# sourceMappingURL=patch-plugin.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"patch-plugin.js","sourceRoot":"","sources":["../../../../src/cmd/build/vite/patch-plugin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAOvD;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,OAA2B;IACtD,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IAC3B,MAAM,OAAO,GAAG,eAAe,EAAE,CAAC;IAElC,yBAAyB;IACzB,MAAM,CAAC,KAAK,CAAC,4CAA4C,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IACzE,KAAK,MAAM,CAAC,UAAU,CAAC,IAAI,OAAO,EAAE,CAAC;QACpC,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;IACpC,CAAC;IAED,OAAO;QACN,IAAI,EAAE,iBAAiB;QACvB,OAAO,EAAE,MAAM,EAAE,6BAA6B;QAE9C;;WAEG;QACH,KAAK,CAAC,SAAS,CAAC,IAAY,EAAE,EAAU;YACvC,sCAAsC;YACtC,KAAK,MAAM,CAAC,UAAU,EAAE,KAAK,CAAC,IAAI,OAAO,EAAE,CAAC;gBAC3C,+BAA+B;gBAC/B,MAAM,YAAY,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;gBAE5C,8CAA8C;gBAC9C,qDAAqD;gBACrD,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,gBAAgB,UAAU,GAAG,CAAC,EAAE,CAAC;oBAC3D,SAAS;gBACV,CAAC;gBAED,mDAAmD;gBACnD,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;oBACpB,MAAM,YAAY,GAAG,GAAG,UAAU,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;oBACvD,IACC,CAAC,YAAY,CAAC,QAAQ,CAAC,YAAY,CAAC;wBACpC,CAAC,YAAY,CAAC,QAAQ,CAAC,GAAG,YAAY,KAAK,CAAC;wBAC5C,CAAC,YAAY,CAAC,QAAQ,CAAC,GAAG,YAAY,MAAM,CAAC;wBAC7C,CAAC,YAAY,CAAC,QAAQ,CAAC,GAAG,YAAY,KAAK,CAAC,EAC3C,CAAC;wBACF,SAAS;oBACV,CAAC;gBACF,CAAC;gBAED,kBAAkB;gBAClB,MAAM,CAAC,KAAK,CAAC,sBAAsB,EAAE,UAAU,CAAC,CAAC;gBAEjD,IAAI,CAAC;oBACJ,MAAM,CAAC,WAAW,CAAC,GAAG,MAAM,UAAU,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;oBAElD,0CAA0C;oBAC1C,OAAO;wBACN,IAAI,EAAE,WAAW;wBACjB,GAAG,EAAE,IAAI,EAAE,uCAAuC;qBAClD,CAAC;gBACH,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBAChB,MAAM,CAAC,IAAI,CAAC,iCAAiC,EAAE,UAAU,EAAE,KAAK,CAAC,CAAC;oBAClE,qCAAqC;oBACrC,OAAO,IAAI,CAAC;gBACb,CAAC;YACF,CAAC;YAED,kBAAkB;YAClB,OAAO,IAAI,CAAC;QACb,CAAC;KACD,CAAC;AACH,CAAC"}
|