@agentuity/cli 0.0.97 → 0.0.99

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.
Files changed (53) hide show
  1. package/dist/banner.d.ts.map +1 -1
  2. package/dist/banner.js +22 -6
  3. package/dist/banner.js.map +1 -1
  4. package/dist/cmd/build/entry-generator.d.ts.map +1 -1
  5. package/dist/cmd/build/entry-generator.js +85 -64
  6. package/dist/cmd/build/entry-generator.js.map +1 -1
  7. package/dist/cmd/build/vite/bun-dev-server.d.ts +3 -7
  8. package/dist/cmd/build/vite/bun-dev-server.d.ts.map +1 -1
  9. package/dist/cmd/build/vite/bun-dev-server.js +38 -16
  10. package/dist/cmd/build/vite/bun-dev-server.js.map +1 -1
  11. package/dist/cmd/build/vite/server-bundler.d.ts.map +1 -1
  12. package/dist/cmd/build/vite/server-bundler.js +11 -1
  13. package/dist/cmd/build/vite/server-bundler.js.map +1 -1
  14. package/dist/cmd/build/vite/vite-asset-server-config.d.ts.map +1 -1
  15. package/dist/cmd/build/vite/vite-asset-server-config.js +17 -1
  16. package/dist/cmd/build/vite/vite-asset-server-config.js.map +1 -1
  17. package/dist/cmd/build/vite/vite-asset-server.js +1 -1
  18. package/dist/cmd/build/vite/vite-asset-server.js.map +1 -1
  19. package/dist/cmd/build/vite/vite-builder.d.ts.map +1 -1
  20. package/dist/cmd/build/vite/vite-builder.js +21 -2
  21. package/dist/cmd/build/vite/vite-builder.js.map +1 -1
  22. package/dist/cmd/cloud/deploy.d.ts.map +1 -1
  23. package/dist/cmd/cloud/deploy.js +32 -21
  24. package/dist/cmd/cloud/deploy.js.map +1 -1
  25. package/dist/cmd/dev/file-watcher.d.ts +24 -0
  26. package/dist/cmd/dev/file-watcher.d.ts.map +1 -0
  27. package/dist/cmd/dev/file-watcher.js +183 -0
  28. package/dist/cmd/dev/file-watcher.js.map +1 -0
  29. package/dist/cmd/dev/index.d.ts.map +1 -1
  30. package/dist/cmd/dev/index.js +61 -23
  31. package/dist/cmd/dev/index.js.map +1 -1
  32. package/dist/cmd/setup/index.d.ts.map +1 -1
  33. package/dist/cmd/setup/index.js +3 -3
  34. package/dist/cmd/setup/index.js.map +1 -1
  35. package/dist/repl.js +2 -2
  36. package/dist/repl.js.map +1 -1
  37. package/dist/types.d.ts +6 -0
  38. package/dist/types.d.ts.map +1 -1
  39. package/dist/types.js.map +1 -1
  40. package/package.json +8 -4
  41. package/src/banner.ts +25 -6
  42. package/src/cmd/build/entry-generator.ts +85 -65
  43. package/src/cmd/build/vite/bun-dev-server.ts +45 -18
  44. package/src/cmd/build/vite/server-bundler.ts +16 -1
  45. package/src/cmd/build/vite/vite-asset-server-config.ts +22 -1
  46. package/src/cmd/build/vite/vite-asset-server.ts +1 -1
  47. package/src/cmd/build/vite/vite-builder.ts +29 -2
  48. package/src/cmd/cloud/deploy.ts +41 -24
  49. package/src/cmd/dev/file-watcher.ts +234 -0
  50. package/src/cmd/dev/index.ts +69 -24
  51. package/src/cmd/setup/index.ts +7 -3
  52. package/src/repl.ts +2 -2
  53. package/src/types.ts +6 -0
@@ -4,6 +4,7 @@ import { createPublicKey } from 'node:crypto';
4
4
  import { createReadStream, createWriteStream, existsSync, mkdirSync, writeFileSync } from 'node:fs';
5
5
  import { tmpdir } from 'node:os';
6
6
  import { StructuredError } from '@agentuity/core';
7
+ import { isRunningFromExecutable } from '../upgrade';
7
8
  import { createSubcommand } from '../../types';
8
9
  import * as tui from '../../tui';
9
10
  import { saveProjectDir, getDefaultConfigDir } from '../../config';
@@ -335,33 +336,49 @@ export const deploySubcommand = createSubcommand({
335
336
  );
336
337
  }
337
338
 
338
- const promises: Promise<Response>[] = [];
339
- for (const asset of build.assets) {
340
- const assetUrl = instructions.assets[asset.filename];
341
- if (!assetUrl) {
342
- return stepError(
343
- `server did not provide upload URL for asset "${asset.filename}"; upload aborted`
344
- );
345
- }
339
+ // Workaround for Bun crash in compiled executables (https://github.com/agentuity/sdk/issues/191)
340
+ // Use limited concurrency (2 at a time) for executables to avoid parallel fetch crash
341
+ const isExecutable = isRunningFromExecutable();
342
+ const concurrency = isExecutable ? 2 : build.assets.length;
346
343
 
347
- // Asset filename already includes the subdirectory (e.g., "client/assets/main-abc123.js")
348
- const file = Bun.file(join(projectDir, '.agentuity', asset.filename));
349
- promises.push(
350
- fetch(assetUrl, {
351
- method: 'PUT',
352
- duplex: 'half',
353
- headers: {
354
- 'Content-Type': asset.contentType,
355
- },
356
- body: file,
357
- })
344
+ if (isExecutable) {
345
+ ctx.logger.trace(
346
+ `Running from executable - using limited concurrency (${concurrency} uploads at a time)`
358
347
  );
359
348
  }
360
- ctx.logger.trace('Waiting for asset uploads');
361
- const resps = await Promise.all(promises);
362
- for (const r of resps) {
363
- if (!r.ok) {
364
- return stepError(`error uploading asset: ${await r.text()}`);
349
+
350
+ // Process assets in batches with limited concurrency
351
+ for (let i = 0; i < build.assets.length; i += concurrency) {
352
+ const batch = build.assets.slice(i, i + concurrency);
353
+ const promises: Promise<Response>[] = [];
354
+
355
+ for (const asset of batch) {
356
+ const assetUrl = instructions.assets[asset.filename];
357
+ if (!assetUrl) {
358
+ return stepError(
359
+ `server did not provide upload URL for asset "${asset.filename}"; upload aborted`
360
+ );
361
+ }
362
+
363
+ // Asset filename already includes the subdirectory (e.g., "client/assets/main-abc123.js")
364
+ const file = Bun.file(join(projectDir, '.agentuity', asset.filename));
365
+ promises.push(
366
+ fetch(assetUrl, {
367
+ method: 'PUT',
368
+ duplex: 'half',
369
+ headers: {
370
+ 'Content-Type': asset.contentType,
371
+ },
372
+ body: file,
373
+ })
374
+ );
375
+ }
376
+
377
+ const resps = await Promise.all(promises);
378
+ for (const r of resps) {
379
+ if (!r.ok) {
380
+ return stepError(`error uploading asset: ${await r.text()}`);
381
+ }
365
382
  }
366
383
  }
367
384
  ctx.logger.trace('Asset uploads complete');
@@ -0,0 +1,234 @@
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 } from 'node:fs';
9
+ import { resolve } from 'node:path';
10
+ import type { Logger } from '../../types';
11
+
12
+ export interface FileWatcherOptions {
13
+ rootDir: string;
14
+ logger: Logger;
15
+ onRestart: () => void;
16
+ additionalPaths?: string[];
17
+ }
18
+
19
+ export interface FileWatcherManager {
20
+ start: () => void;
21
+ stop: () => void;
22
+ pause: () => void;
23
+ resume: () => void;
24
+ }
25
+
26
+ /**
27
+ * Create a file watcher manager for hot reload
28
+ */
29
+ export function createFileWatcher(options: FileWatcherOptions): FileWatcherManager {
30
+ const { rootDir, logger, onRestart, additionalPaths = [] } = options;
31
+
32
+ const watchers: FSWatcher[] = [];
33
+ let paused = false;
34
+ let buildCooldownTimer: NodeJS.Timeout | null = null;
35
+
36
+ // Watch the entire root directory recursively
37
+ // This is simpler and more reliable than watching individual paths
38
+ const watchDirs = [rootDir];
39
+
40
+ // Directories to ignore
41
+ const ignorePaths = [
42
+ '.agentuity',
43
+ 'node_modules',
44
+ '.git',
45
+ 'dist',
46
+ 'build',
47
+ '.next',
48
+ '.turbo',
49
+ 'src/web', // Vite handles frontend with HMR - no backend restart needed
50
+ ];
51
+
52
+ /**
53
+ * Check if a path should be ignored
54
+ */
55
+ function shouldIgnorePath(changedFile: string | null, watchDir: string): boolean {
56
+ if (!changedFile) return false;
57
+
58
+ const absPath = resolve(watchDir, changedFile);
59
+
60
+ // Check against ignore list - match both relative path and absolute path
61
+ for (const ignorePath of ignorePaths) {
62
+ // Check relative path from watchDir
63
+ if (
64
+ changedFile === ignorePath ||
65
+ changedFile.startsWith(`${ignorePath}/`) ||
66
+ changedFile.startsWith(`${ignorePath}\\`)
67
+ ) {
68
+ logger.trace('File change ignored (%s): %s', ignorePath, changedFile);
69
+ return true;
70
+ }
71
+
72
+ // Check if absolute path contains the ignore pattern
73
+ const ignoreAbsPath = resolve(rootDir, ignorePath);
74
+ if (
75
+ absPath === ignoreAbsPath ||
76
+ absPath.startsWith(`${ignoreAbsPath}/`) ||
77
+ absPath.startsWith(`${ignoreAbsPath}\\`)
78
+ ) {
79
+ logger.trace('File change ignored (%s): %s', ignorePath, changedFile);
80
+ return true;
81
+ }
82
+
83
+ // Also check if changedFile path includes the ignore pattern anywhere
84
+ // This handles cases like "some/path/.agentuity/file.js"
85
+ const normalizedChanged = changedFile.replace(/\\/g, '/');
86
+ const normalizedIgnore = ignorePath.replace(/\\/g, '/');
87
+ if (
88
+ normalizedChanged.includes(`/${normalizedIgnore}/`) ||
89
+ normalizedChanged.includes(`/${normalizedIgnore}`)
90
+ ) {
91
+ logger.trace('File change ignored (%s in path): %s', ignorePath, changedFile);
92
+ return true;
93
+ }
94
+ }
95
+
96
+ // Ignore temp files from editors
97
+ if (changedFile.match(/\.(tmp|swp|swo|swx)$|~$/)) {
98
+ logger.trace('File change ignored (temp file): %s', changedFile);
99
+ return true;
100
+ }
101
+
102
+ // Ignore hidden files (except .env)
103
+ if (changedFile.startsWith('.') && !changedFile.startsWith('.env')) {
104
+ logger.trace('File change ignored (hidden file): %s', changedFile);
105
+ return true;
106
+ }
107
+
108
+ return false;
109
+ }
110
+
111
+ /**
112
+ * Handle file change event
113
+ */
114
+ function handleFileChange(eventType: string, changedFile: string | null, watchDir: string) {
115
+ if (paused) {
116
+ logger.trace('File change ignored (watcher paused): %s', changedFile);
117
+ return;
118
+ }
119
+
120
+ if (shouldIgnorePath(changedFile, watchDir)) {
121
+ return;
122
+ }
123
+
124
+ // During build cooldown, ignore changes (they're likely build outputs)
125
+ if (buildCooldownTimer) {
126
+ logger.trace('File change ignored (build cooldown): %s', changedFile);
127
+ return;
128
+ }
129
+
130
+ logger.debug('File changed (%s): %s', eventType, changedFile || watchDir);
131
+ onRestart();
132
+ }
133
+
134
+ /**
135
+ * Start watching files
136
+ */
137
+ function start() {
138
+ logger.debug('Starting file watchers for hot reload...');
139
+
140
+ // Watch root directory (already absolute path)
141
+ for (const watchPath of watchDirs) {
142
+ try {
143
+ logger.trace('Setting up watcher for: %s', watchPath);
144
+
145
+ const watcher = watch(watchPath, { recursive: true }, (eventType, changedFile) => {
146
+ handleFileChange(eventType, changedFile, watchPath);
147
+ });
148
+
149
+ watchers.push(watcher);
150
+ logger.trace('Watcher started for: %s', watchPath);
151
+ } catch (error) {
152
+ logger.warn('Failed to start watcher for %s: %s', watchPath, error);
153
+ }
154
+ }
155
+
156
+ // Watch additional paths if provided
157
+ if (additionalPaths && additionalPaths.length > 0) {
158
+ for (const additionalPath of additionalPaths) {
159
+ const fullPath = resolve(rootDir, additionalPath);
160
+ try {
161
+ logger.trace('Setting up watcher for additional path: %s', fullPath);
162
+
163
+ const watcher = watch(fullPath, { recursive: true }, (eventType, changedFile) => {
164
+ handleFileChange(eventType, changedFile, fullPath);
165
+ });
166
+
167
+ watchers.push(watcher);
168
+ logger.trace('Watcher started for additional path: %s', fullPath);
169
+ } catch (error) {
170
+ logger.warn('Failed to start watcher for %s: %s', fullPath, error);
171
+ }
172
+ }
173
+ }
174
+
175
+ logger.debug('File watchers started (%d paths)', watchers.length);
176
+ }
177
+
178
+ /**
179
+ * Stop all watchers
180
+ */
181
+ function stop() {
182
+ logger.debug('Stopping file watchers...');
183
+
184
+ for (const watcher of watchers) {
185
+ try {
186
+ watcher.close();
187
+ } catch (error) {
188
+ logger.trace('Error closing watcher: %s', error);
189
+ }
190
+ }
191
+
192
+ watchers.length = 0;
193
+
194
+ if (buildCooldownTimer) {
195
+ clearTimeout(buildCooldownTimer);
196
+ buildCooldownTimer = null;
197
+ }
198
+
199
+ logger.debug('File watchers stopped');
200
+ }
201
+
202
+ /**
203
+ * Temporarily pause watching (e.g., during build)
204
+ */
205
+ function pause() {
206
+ paused = true;
207
+ logger.trace('File watchers paused');
208
+
209
+ // Set cooldown timer to ignore changes for a bit after build
210
+ if (buildCooldownTimer) {
211
+ clearTimeout(buildCooldownTimer);
212
+ }
213
+
214
+ buildCooldownTimer = setTimeout(() => {
215
+ buildCooldownTimer = null;
216
+ logger.trace('Build cooldown expired');
217
+ }, 500); // 500ms cooldown
218
+ }
219
+
220
+ /**
221
+ * Resume watching
222
+ */
223
+ function resume() {
224
+ paused = false;
225
+ logger.trace('File watchers resumed');
226
+ }
227
+
228
+ return {
229
+ start,
230
+ stop,
231
+ pause,
232
+ resume,
233
+ };
234
+ }
@@ -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
- // Restart loop - allows server to restart on file changes
224
- let shouldRestart = false;
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
- // Make restart function available globally for HMR plugin
237
- (globalThis as Record<string, unknown>).__AGENTUITY_RESTART__ = restartServer;
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 client is always killed on exit (even if cleanup is bypassed)
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 (_err) {
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 (with Vite asset server for HMR)
317
- const result = await startBunDevServer({
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
- console.log(data);
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
- tui.info('Restarting server...');
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 - close Vite asset server
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) => {
@@ -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 (_err) {
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 (_err) {
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
  /**