@agentuity/cli 0.0.101 → 0.0.102
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 +19 -188
- package/bin/cli.ts +13 -6
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +41 -12
- package/dist/cli.js.map +1 -1
- package/dist/cmd/ai/index.d.ts.map +1 -1
- package/dist/cmd/ai/index.js +6 -1
- package/dist/cmd/ai/index.js.map +1 -1
- package/dist/cmd/ai/prompt/agent.d.ts +7 -0
- package/dist/cmd/ai/prompt/agent.d.ts.map +1 -1
- package/dist/cmd/ai/prompt/agent.js +12 -323
- package/dist/cmd/ai/prompt/agent.js.map +1 -1
- package/dist/cmd/ai/prompt/api.d.ts +7 -0
- package/dist/cmd/ai/prompt/api.d.ts.map +1 -1
- package/dist/cmd/ai/prompt/api.js +12 -260
- package/dist/cmd/ai/prompt/api.js.map +1 -1
- package/dist/cmd/ai/prompt/version.d.ts +35 -0
- package/dist/cmd/ai/prompt/version.d.ts.map +1 -0
- package/dist/cmd/ai/prompt/version.js +55 -0
- package/dist/cmd/ai/prompt/version.js.map +1 -0
- package/dist/cmd/ai/prompt/web.d.ts +7 -0
- package/dist/cmd/ai/prompt/web.d.ts.map +1 -1
- package/dist/cmd/ai/prompt/web.js +12 -283
- package/dist/cmd/ai/prompt/web.js.map +1 -1
- package/dist/cmd/ai/skills/generate.d.ts +3 -0
- package/dist/cmd/ai/skills/generate.d.ts.map +1 -0
- package/dist/cmd/ai/skills/generate.js +65 -0
- package/dist/cmd/ai/skills/generate.js.map +1 -0
- package/dist/cmd/ai/skills/generator.d.ts +4 -0
- package/dist/cmd/ai/skills/generator.d.ts.map +1 -0
- package/dist/cmd/ai/skills/generator.js +402 -0
- package/dist/cmd/ai/skills/generator.js.map +1 -0
- package/dist/cmd/ai/skills/index.d.ts +4 -0
- package/dist/cmd/ai/skills/index.d.ts.map +1 -0
- package/dist/cmd/ai/skills/index.js +21 -0
- package/dist/cmd/ai/skills/index.js.map +1 -0
- package/dist/cmd/auth/signup.d.ts.map +1 -1
- package/dist/cmd/auth/signup.js +1 -0
- package/dist/cmd/auth/signup.js.map +1 -1
- package/dist/cmd/build/entry-generator.d.ts.map +1 -1
- package/dist/cmd/build/entry-generator.js +40 -5
- package/dist/cmd/build/entry-generator.js.map +1 -1
- package/dist/cmd/build/vite/bun-dev-server.d.ts +7 -1
- package/dist/cmd/build/vite/bun-dev-server.d.ts.map +1 -1
- package/dist/cmd/build/vite/bun-dev-server.js +52 -26
- package/dist/cmd/build/vite/bun-dev-server.js.map +1 -1
- package/dist/cmd/build/vite/metadata-generator.d.ts.map +1 -1
- package/dist/cmd/build/vite/metadata-generator.js +58 -7
- package/dist/cmd/build/vite/metadata-generator.js.map +1 -1
- package/dist/cmd/build/vite/prompt-generator.d.ts +23 -0
- package/dist/cmd/build/vite/prompt-generator.d.ts.map +1 -0
- package/dist/cmd/build/vite/prompt-generator.js +123 -0
- package/dist/cmd/build/vite/prompt-generator.js.map +1 -0
- package/dist/cmd/build/vite/registry-generator.d.ts.map +1 -1
- package/dist/cmd/build/vite/registry-generator.js +28 -11
- package/dist/cmd/build/vite/registry-generator.js.map +1 -1
- package/dist/cmd/build/vite/server-bundler.d.ts +4 -0
- package/dist/cmd/build/vite/server-bundler.d.ts.map +1 -1
- package/dist/cmd/build/vite/server-bundler.js +45 -16
- 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 +4 -0
- package/dist/cmd/build/vite/vite-asset-server-config.js.map +1 -1
- package/dist/cmd/build/vite/vite-builder.d.ts.map +1 -1
- package/dist/cmd/build/vite/vite-builder.js +99 -87
- 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 +78 -27
- package/dist/cmd/cloud/deploy.js.map +1 -1
- package/dist/cmd/cloud/keyvalue/create-namespace.d.ts.map +1 -1
- package/dist/cmd/cloud/keyvalue/create-namespace.js +3 -1
- package/dist/cmd/cloud/keyvalue/create-namespace.js.map +1 -1
- package/dist/cmd/cloud/keyvalue/delete-namespace.d.ts.map +1 -1
- package/dist/cmd/cloud/keyvalue/delete-namespace.js +3 -1
- package/dist/cmd/cloud/keyvalue/delete-namespace.js.map +1 -1
- package/dist/cmd/cloud/keyvalue/delete.d.ts.map +1 -1
- package/dist/cmd/cloud/keyvalue/delete.js +3 -1
- package/dist/cmd/cloud/keyvalue/delete.js.map +1 -1
- package/dist/cmd/cloud/keyvalue/set.d.ts.map +1 -1
- package/dist/cmd/cloud/keyvalue/set.js +4 -2
- package/dist/cmd/cloud/keyvalue/set.js.map +1 -1
- package/dist/cmd/cloud/stream/get.d.ts.map +1 -1
- package/dist/cmd/cloud/stream/get.js +2 -13
- package/dist/cmd/cloud/stream/get.js.map +1 -1
- package/dist/cmd/cloud/vector/delete-namespace.d.ts +3 -0
- package/dist/cmd/cloud/vector/delete-namespace.d.ts.map +1 -0
- package/dist/cmd/cloud/vector/delete-namespace.js +77 -0
- package/dist/cmd/cloud/vector/delete-namespace.js.map +1 -0
- package/dist/cmd/cloud/vector/index.d.ts.map +1 -1
- package/dist/cmd/cloud/vector/index.js +21 -4
- package/dist/cmd/cloud/vector/index.js.map +1 -1
- package/dist/cmd/cloud/vector/list-namespaces.d.ts +3 -0
- package/dist/cmd/cloud/vector/list-namespaces.d.ts.map +1 -0
- package/dist/cmd/cloud/vector/list-namespaces.js +42 -0
- package/dist/cmd/cloud/vector/list-namespaces.js.map +1 -0
- package/dist/cmd/cloud/vector/stats.d.ts +3 -0
- package/dist/cmd/cloud/vector/stats.d.ts.map +1 -0
- package/dist/cmd/cloud/vector/stats.js +142 -0
- package/dist/cmd/cloud/vector/stats.js.map +1 -0
- package/dist/cmd/cloud/vector/upsert.d.ts +3 -0
- package/dist/cmd/cloud/vector/upsert.d.ts.map +1 -0
- package/dist/cmd/cloud/vector/upsert.js +192 -0
- package/dist/cmd/cloud/vector/upsert.js.map +1 -0
- package/dist/cmd/dev/file-watcher.d.ts.map +1 -1
- package/dist/cmd/dev/file-watcher.js +90 -31
- 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 +213 -57
- package/dist/cmd/dev/index.js.map +1 -1
- package/dist/cmd/dev/skills.d.ts +10 -0
- package/dist/cmd/dev/skills.d.ts.map +1 -0
- package/dist/cmd/dev/skills.js +57 -0
- package/dist/cmd/dev/skills.js.map +1 -0
- package/dist/cmd/dev/sync.js +7 -7
- package/dist/cmd/dev/sync.js.map +1 -1
- package/dist/cmd/index.d.ts.map +1 -1
- package/dist/cmd/index.js +1 -0
- package/dist/cmd/index.js.map +1 -1
- package/dist/cmd/project/create.d.ts.map +1 -1
- package/dist/cmd/project/create.js +3 -0
- package/dist/cmd/project/create.js.map +1 -1
- package/dist/cmd/project/template-flow.d.ts +1 -0
- package/dist/cmd/project/template-flow.d.ts.map +1 -1
- package/dist/cmd/project/template-flow.js +30 -5
- package/dist/cmd/project/template-flow.js.map +1 -1
- package/dist/cmd/setup/index.d.ts.map +1 -1
- package/dist/cmd/setup/index.js +1 -0
- package/dist/cmd/setup/index.js.map +1 -1
- package/dist/cmd/upgrade/index.d.ts +15 -0
- package/dist/cmd/upgrade/index.d.ts.map +1 -1
- package/dist/cmd/upgrade/index.js +59 -4
- package/dist/cmd/upgrade/index.js.map +1 -1
- package/dist/domain.d.ts +45 -0
- package/dist/domain.d.ts.map +1 -0
- package/dist/domain.js +200 -0
- package/dist/domain.js.map +1 -0
- package/dist/schema-generator.d.ts +2 -0
- package/dist/schema-generator.d.ts.map +1 -1
- package/dist/schema-generator.js +18 -0
- package/dist/schema-generator.js.map +1 -1
- package/dist/steps.d.ts +1 -1
- package/dist/steps.d.ts.map +1 -1
- package/dist/steps.js +16 -5
- package/dist/steps.js.map +1 -1
- package/dist/tui/prompt.d.ts +1 -2
- package/dist/tui/prompt.d.ts.map +1 -1
- package/dist/tui/prompt.js +8 -4
- package/dist/tui/prompt.js.map +1 -1
- package/dist/tui.d.ts +16 -0
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +23 -2
- package/dist/tui.js.map +1 -1
- package/dist/types.d.ts +9 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +3 -3
- package/dist/types.js.map +1 -1
- package/package.json +4 -4
- package/src/cli.ts +47 -12
- package/src/cmd/ai/index.ts +6 -1
- package/src/cmd/ai/prompt/agent.md +306 -0
- package/src/cmd/ai/prompt/agent.ts +12 -322
- package/src/cmd/ai/prompt/api.md +360 -0
- package/src/cmd/ai/prompt/api.ts +13 -260
- package/src/cmd/ai/prompt/version.ts +61 -0
- package/src/cmd/ai/prompt/web.md +509 -0
- package/src/cmd/ai/prompt/web.ts +12 -282
- package/src/cmd/ai/skills/generate.ts +75 -0
- package/src/cmd/ai/skills/generator.ts +519 -0
- package/src/cmd/ai/skills/index.ts +23 -0
- package/src/cmd/auth/signup.ts +1 -0
- package/src/cmd/build/entry-generator.ts +43 -7
- package/src/cmd/build/vite/bun-dev-server.ts +57 -27
- package/src/cmd/build/vite/metadata-generator.ts +73 -7
- package/src/cmd/build/vite/prompt-generator.ts +169 -0
- package/src/cmd/build/vite/registry-generator.ts +33 -10
- package/src/cmd/build/vite/server-bundler.ts +53 -22
- package/src/cmd/build/vite/vite-asset-server-config.ts +5 -0
- package/src/cmd/build/vite/vite-builder.ts +107 -87
- package/src/cmd/cloud/deploy.ts +99 -31
- package/src/cmd/cloud/keyvalue/create-namespace.ts +3 -1
- package/src/cmd/cloud/keyvalue/delete-namespace.ts +3 -1
- package/src/cmd/cloud/keyvalue/delete.ts +3 -1
- package/src/cmd/cloud/keyvalue/set.ts +4 -2
- package/src/cmd/cloud/stream/get.ts +2 -9
- package/src/cmd/cloud/vector/delete-namespace.ts +89 -0
- package/src/cmd/cloud/vector/index.ts +21 -4
- package/src/cmd/cloud/vector/list-namespaces.ts +46 -0
- package/src/cmd/cloud/vector/stats.ts +160 -0
- package/src/cmd/cloud/vector/upsert.ts +216 -0
- package/src/cmd/dev/file-watcher.ts +101 -32
- package/src/cmd/dev/index.ts +304 -111
- package/src/cmd/dev/skills.ts +82 -0
- package/src/cmd/dev/sync.ts +7 -7
- package/src/cmd/index.ts +1 -0
- package/src/cmd/project/create.ts +3 -0
- package/src/cmd/project/template-flow.ts +37 -5
- package/src/cmd/setup/index.ts +1 -0
- package/src/cmd/upgrade/index.ts +68 -4
- package/src/domain.ts +273 -0
- package/src/schema-generator.ts +23 -0
- package/src/steps.ts +16 -5
- package/src/tui/prompt.ts +11 -5
- package/src/tui.ts +21 -2
- package/src/types/md.d.ts +8 -0
- package/src/types.ts +12 -3
- package/dist/cmd/cloud/domain.d.ts +0 -17
- package/dist/cmd/cloud/domain.d.ts.map +0 -1
- package/dist/cmd/cloud/domain.js +0 -79
- package/dist/cmd/cloud/domain.js.map +0 -1
- package/src/cmd/cloud/domain.ts +0 -100
package/src/cmd/dev/index.ts
CHANGED
|
@@ -15,6 +15,7 @@ import { getDevmodeDeploymentId } from '../build/ast';
|
|
|
15
15
|
import { getDefaultConfigDir, saveConfig } from '../../config';
|
|
16
16
|
import type { Config } from '../../types';
|
|
17
17
|
import { createFileWatcher } from './file-watcher';
|
|
18
|
+
import { regenerateSkillsAsync } from './skills';
|
|
18
19
|
|
|
19
20
|
const DEFAULT_PORT = 3500;
|
|
20
21
|
const MIN_PORT = 1024;
|
|
@@ -32,6 +33,81 @@ interface ServerLike {
|
|
|
32
33
|
close: () => void;
|
|
33
34
|
}
|
|
34
35
|
|
|
36
|
+
interface BunServer {
|
|
37
|
+
stop: (closeActiveConnections?: boolean) => void;
|
|
38
|
+
port: number;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Kill any lingering gravity processes from previous dev sessions.
|
|
43
|
+
* This is a defensive measure to clean up orphaned processes.
|
|
44
|
+
*/
|
|
45
|
+
async function killLingeringGravityProcesses(
|
|
46
|
+
logger: { debug: (msg: string, ...args: unknown[]) => void }
|
|
47
|
+
): Promise<void> {
|
|
48
|
+
// Only attempt on Unix-like systems (macOS, Linux)
|
|
49
|
+
if (process.platform === 'win32') {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
try {
|
|
54
|
+
// Use pkill to kill gravity processes owned by current user
|
|
55
|
+
// The -f flag matches against full command line
|
|
56
|
+
// We specifically match the gravity binary name to avoid killing unrelated processes
|
|
57
|
+
const result = Bun.spawnSync(['pkill', '-f', 'gravity.*--endpoint-id'], {
|
|
58
|
+
stdout: 'ignore',
|
|
59
|
+
stderr: 'ignore',
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
// Exit code 0 = processes killed, 1 = no matching processes, other = error
|
|
63
|
+
if (result.exitCode === 0) {
|
|
64
|
+
logger.debug('Killed lingering gravity processes from previous session');
|
|
65
|
+
// Brief pause to let processes fully terminate
|
|
66
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
67
|
+
}
|
|
68
|
+
} catch {
|
|
69
|
+
// pkill not available or failed - not critical, continue
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Stop the existing Bun server if one is running.
|
|
75
|
+
* Waits for the port to become available before returning.
|
|
76
|
+
*/
|
|
77
|
+
async function stopBunServer(
|
|
78
|
+
port: number,
|
|
79
|
+
logger: { debug: (msg: string, ...args: unknown[]) => void }
|
|
80
|
+
): Promise<void> {
|
|
81
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
82
|
+
const globalAny = globalThis as any;
|
|
83
|
+
const server = globalAny.__AGENTUITY_SERVER__ as BunServer | undefined;
|
|
84
|
+
if (!server) return;
|
|
85
|
+
|
|
86
|
+
try {
|
|
87
|
+
logger.debug('Stopping previous Bun server...');
|
|
88
|
+
server.stop(true); // Close active connections immediately
|
|
89
|
+
} catch (err) {
|
|
90
|
+
logger.debug('Error stopping previous Bun server: %s', err);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Wait for socket to close to avoid EADDRINUSE races
|
|
94
|
+
for (let i = 0; i < 20; i++) {
|
|
95
|
+
try {
|
|
96
|
+
await fetch(`http://127.0.0.1:${port}/`, {
|
|
97
|
+
method: 'HEAD',
|
|
98
|
+
signal: AbortSignal.timeout(200),
|
|
99
|
+
});
|
|
100
|
+
// Still responding, wait a bit more
|
|
101
|
+
await new Promise((r) => setTimeout(r, 50));
|
|
102
|
+
} catch {
|
|
103
|
+
// Connection refused or timeout => server is down
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
globalAny.__AGENTUITY_SERVER__ = undefined;
|
|
109
|
+
}
|
|
110
|
+
|
|
35
111
|
const getDefaultPort = (): number => {
|
|
36
112
|
const envPort = process.env.PORT;
|
|
37
113
|
if (!envPort) {
|
|
@@ -120,6 +196,10 @@ export const command = createCommand({
|
|
|
120
196
|
originalExit(1);
|
|
121
197
|
}
|
|
122
198
|
|
|
199
|
+
// Kill any lingering gravity processes from previous dev sessions
|
|
200
|
+
// This prevents "zombie" gravity clients from blocking the public URL
|
|
201
|
+
await killLingeringGravityProcesses(logger);
|
|
202
|
+
|
|
123
203
|
// Setup devmode and gravity (if using public URL)
|
|
124
204
|
const useMockService = process.env.DEVMODE_SYNC_SERVICE_MOCK === 'true';
|
|
125
205
|
const apiClient = auth ? new APIClient(getAPIBaseURL(config), logger, config) : null;
|
|
@@ -132,7 +212,9 @@ export const command = createCommand({
|
|
|
132
212
|
: null;
|
|
133
213
|
|
|
134
214
|
// Track previous metadata for sync diffing
|
|
135
|
-
let previousMetadata:
|
|
215
|
+
let previousMetadata:
|
|
216
|
+
| Awaited<ReturnType<typeof import('../build/vite/metadata-generator').generateMetadata>>
|
|
217
|
+
| undefined;
|
|
136
218
|
|
|
137
219
|
let devmode: DevmodeResponse | undefined;
|
|
138
220
|
let gravityBin: string | undefined;
|
|
@@ -234,6 +316,12 @@ export const command = createCommand({
|
|
|
234
316
|
centerTitle: false,
|
|
235
317
|
});
|
|
236
318
|
|
|
319
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
320
|
+
const cliVersion = ((global as any).__CLI_SCHEMA__?.version as string) ?? '';
|
|
321
|
+
if (cliVersion) {
|
|
322
|
+
regenerateSkillsAsync(rootDir, cliVersion, logger).catch(() => {});
|
|
323
|
+
}
|
|
324
|
+
|
|
237
325
|
// Start Vite asset server ONCE before restart loop
|
|
238
326
|
// Vite handles frontend HMR independently and stays running across backend restarts
|
|
239
327
|
let viteServer: ServerLike | null = null;
|
|
@@ -281,16 +369,36 @@ export const command = createCommand({
|
|
|
281
369
|
// Start file watcher (will be paused during builds)
|
|
282
370
|
fileWatcher.start();
|
|
283
371
|
|
|
284
|
-
//
|
|
285
|
-
|
|
286
|
-
|
|
372
|
+
// Track if cleanup is in progress to avoid duplicate cleanup
|
|
373
|
+
let cleaningUp = false;
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* Centralized cleanup function for all resources.
|
|
377
|
+
* Called on restart, shutdown, and fatal errors.
|
|
378
|
+
* @param exitAfter - If true, exit the process after cleanup
|
|
379
|
+
* @param exitCode - Exit code to use if exitAfter is true
|
|
380
|
+
* @param silent - If true, don't show "Shutting down" message
|
|
381
|
+
*/
|
|
382
|
+
const cleanup = async (exitAfter = false, exitCode = 0, silent = false) => {
|
|
383
|
+
if (cleaningUp) return;
|
|
384
|
+
cleaningUp = true;
|
|
385
|
+
|
|
386
|
+
if (!silent) {
|
|
387
|
+
tui.info('Shutting down...');
|
|
388
|
+
}
|
|
287
389
|
|
|
288
|
-
// Stop file watcher
|
|
289
|
-
|
|
390
|
+
// Stop file watcher first to prevent restart triggers during cleanup
|
|
391
|
+
try {
|
|
392
|
+
fileWatcher.stop();
|
|
393
|
+
} catch (err) {
|
|
394
|
+
logger.debug('Error stopping file watcher: %s', err);
|
|
395
|
+
}
|
|
290
396
|
|
|
291
|
-
//
|
|
292
|
-
|
|
293
|
-
await
|
|
397
|
+
// Stop Bun server
|
|
398
|
+
try {
|
|
399
|
+
await stopBunServer(opts.port, logger);
|
|
400
|
+
} catch (err) {
|
|
401
|
+
logger.debug('Error stopping Bun server during cleanup: %s', err);
|
|
294
402
|
}
|
|
295
403
|
|
|
296
404
|
// Kill gravity client with SIGTERM first, then SIGKILL as fallback
|
|
@@ -298,37 +406,114 @@ export const command = createCommand({
|
|
|
298
406
|
try {
|
|
299
407
|
gravityProcess.kill('SIGTERM');
|
|
300
408
|
// Give it a moment to gracefully shutdown
|
|
301
|
-
await new Promise((resolve) => setTimeout(resolve,
|
|
409
|
+
await new Promise((resolve) => setTimeout(resolve, 150));
|
|
302
410
|
if (gravityProcess.exitCode === null) {
|
|
303
411
|
gravityProcess.kill('SIGKILL');
|
|
304
412
|
}
|
|
305
413
|
} catch (err) {
|
|
306
414
|
logger.debug('Error killing gravity process: %s', err);
|
|
415
|
+
} finally {
|
|
416
|
+
gravityProcess = null;
|
|
307
417
|
}
|
|
308
418
|
}
|
|
309
419
|
|
|
310
|
-
|
|
420
|
+
// Close Vite asset server last (it handles frontend, should stay up longest)
|
|
421
|
+
if (viteServer) {
|
|
422
|
+
try {
|
|
423
|
+
await viteServer.close();
|
|
424
|
+
} catch (err) {
|
|
425
|
+
logger.debug('Error closing Vite server: %s', err);
|
|
426
|
+
} finally {
|
|
427
|
+
viteServer = null;
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
// Reset cleanup flag if not exiting (allows restart)
|
|
432
|
+
if (!exitAfter) {
|
|
433
|
+
cleaningUp = false;
|
|
434
|
+
} else {
|
|
435
|
+
originalExit(exitCode);
|
|
436
|
+
}
|
|
437
|
+
};
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* Cleanup for restart: stops Bun server and Gravity, keeps Vite running
|
|
441
|
+
*/
|
|
442
|
+
const cleanupForRestart = async () => {
|
|
443
|
+
logger.debug('Cleaning up for restart...');
|
|
444
|
+
|
|
445
|
+
// Stop Bun server
|
|
446
|
+
try {
|
|
447
|
+
await stopBunServer(opts.port, logger);
|
|
448
|
+
} catch (err) {
|
|
449
|
+
logger.debug('Error stopping Bun server for restart: %s', err);
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
// Kill gravity client
|
|
453
|
+
if (gravityProcess) {
|
|
454
|
+
try {
|
|
455
|
+
gravityProcess.kill('SIGTERM');
|
|
456
|
+
await new Promise((resolve) => setTimeout(resolve, 150));
|
|
457
|
+
if (gravityProcess.exitCode === null) {
|
|
458
|
+
gravityProcess.kill('SIGKILL');
|
|
459
|
+
}
|
|
460
|
+
} catch (err) {
|
|
461
|
+
logger.debug('Error killing gravity process for restart: %s', err);
|
|
462
|
+
} finally {
|
|
463
|
+
gravityProcess = null;
|
|
464
|
+
}
|
|
465
|
+
}
|
|
311
466
|
};
|
|
312
467
|
|
|
313
468
|
// SIGINT/SIGTERM: coordinate shutdown between bundle and dev resources
|
|
314
|
-
let
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
469
|
+
let signalHandlersRegistered = false;
|
|
470
|
+
if (!signalHandlersRegistered) {
|
|
471
|
+
signalHandlersRegistered = true;
|
|
472
|
+
|
|
473
|
+
const safeExit = async (code: number, reason?: string) => {
|
|
474
|
+
if (reason) {
|
|
475
|
+
logger.debug('DevMode terminating (%d) due to: %s', code, reason);
|
|
476
|
+
}
|
|
477
|
+
await cleanup(true, code);
|
|
478
|
+
};
|
|
479
|
+
|
|
480
|
+
process.on('SIGINT', () => {
|
|
481
|
+
void safeExit(0, 'SIGINT');
|
|
482
|
+
});
|
|
326
483
|
|
|
327
|
-
|
|
484
|
+
process.on('SIGTERM', () => {
|
|
485
|
+
void safeExit(0, 'SIGTERM');
|
|
486
|
+
});
|
|
487
|
+
|
|
488
|
+
// Handle uncaught exceptions - clean up and exit rather than limping on
|
|
489
|
+
process.on('uncaughtException', (err) => {
|
|
490
|
+
tui.error(
|
|
491
|
+
`Uncaught exception: ${err instanceof Error ? err.stack ?? err.message : String(err)}`
|
|
492
|
+
);
|
|
493
|
+
void safeExit(1, 'uncaughtException');
|
|
494
|
+
});
|
|
495
|
+
|
|
496
|
+
// Handle unhandled rejections - log but don't exit (usually recoverable)
|
|
497
|
+
process.on('unhandledRejection', (reason) => {
|
|
498
|
+
logger.warn(
|
|
499
|
+
'Unhandled promise rejection: %s',
|
|
500
|
+
reason instanceof Error ? reason.stack ?? reason.message : String(reason)
|
|
501
|
+
);
|
|
502
|
+
});
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
// Ensure resources are always cleaned up on exit (synchronous fallback)
|
|
328
506
|
process.on('exit', () => {
|
|
507
|
+
// Kill gravity client with SIGKILL for immediate termination
|
|
508
|
+
if (gravityProcess && gravityProcess.exitCode === null) {
|
|
509
|
+
try {
|
|
510
|
+
gravityProcess.kill('SIGKILL');
|
|
511
|
+
} catch {
|
|
512
|
+
// Ignore errors during exit cleanup
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
|
|
329
516
|
// Close Vite server synchronously if possible
|
|
330
|
-
// Note: Vite's close() is async, but we can't await in 'exit' handler
|
|
331
|
-
// Most Vite implementations handle sync close gracefully
|
|
332
517
|
if (viteServer) {
|
|
333
518
|
try {
|
|
334
519
|
viteServer.close();
|
|
@@ -337,10 +522,12 @@ export const command = createCommand({
|
|
|
337
522
|
}
|
|
338
523
|
}
|
|
339
524
|
|
|
340
|
-
//
|
|
341
|
-
|
|
525
|
+
// Stop Bun server synchronously (best effort)
|
|
526
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
527
|
+
const server = (globalThis as any).__AGENTUITY_SERVER__;
|
|
528
|
+
if (server?.stop) {
|
|
342
529
|
try {
|
|
343
|
-
|
|
530
|
+
server.stop(true);
|
|
344
531
|
} catch {
|
|
345
532
|
// Ignore errors during exit cleanup
|
|
346
533
|
}
|
|
@@ -358,67 +545,90 @@ export const command = createCommand({
|
|
|
358
545
|
await tui.spinner({
|
|
359
546
|
message: 'Building dev bundle',
|
|
360
547
|
callback: async () => {
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
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
|
-
});
|
|
548
|
+
// Step 1: Generate workbench files if enabled (must be done before entry generation)
|
|
549
|
+
if (workbenchConfigData.enabled) {
|
|
550
|
+
logger.debug('Workbench enabled, generating source files before bundle...');
|
|
551
|
+
const { generateWorkbenchFiles } = await import(
|
|
552
|
+
'../build/vite/workbench-generator'
|
|
553
|
+
);
|
|
554
|
+
await generateWorkbenchFiles(
|
|
555
|
+
rootDir,
|
|
556
|
+
project?.projectId ?? '',
|
|
557
|
+
workbenchConfigData,
|
|
558
|
+
logger
|
|
559
|
+
);
|
|
560
|
+
}
|
|
409
561
|
|
|
410
|
-
|
|
562
|
+
// Step 2: Generate entry file with workbench config
|
|
563
|
+
// Note: vitePort is NOT passed here - the app reads process.env.VITE_PORT at runtime
|
|
564
|
+
const { generateEntryFile } = await import('../build/entry-generator');
|
|
565
|
+
await generateEntryFile({
|
|
566
|
+
rootDir,
|
|
567
|
+
projectId: project?.projectId ?? '',
|
|
568
|
+
deploymentId,
|
|
569
|
+
logger,
|
|
570
|
+
mode: 'dev',
|
|
571
|
+
workbench: workbenchConfigData.enabled ? workbenchConfigData : undefined,
|
|
572
|
+
});
|
|
573
|
+
|
|
574
|
+
// Step 3: Bundle the app with LLM patches (dev mode = no minification)
|
|
575
|
+
// This produces .agentuity/app.js with AI Gateway routing patches applied
|
|
576
|
+
const { installExternalsAndBuild } = await import('../build/vite/server-bundler');
|
|
577
|
+
await installExternalsAndBuild({
|
|
578
|
+
rootDir,
|
|
579
|
+
dev: true, // DevMode: no minification, inline sourcemaps
|
|
580
|
+
logger,
|
|
581
|
+
});
|
|
582
|
+
|
|
583
|
+
// Generate metadata file (needed for eval ID lookup at runtime)
|
|
584
|
+
const { discoverAgents } = await import('../build/vite/agent-discovery');
|
|
585
|
+
const { discoverRoutes } = await import('../build/vite/route-discovery');
|
|
586
|
+
const { generateMetadata, writeMetadataFile } = await import(
|
|
587
|
+
'../build/vite/metadata-generator'
|
|
588
|
+
);
|
|
411
589
|
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
590
|
+
const srcDir = join(rootDir, 'src');
|
|
591
|
+
|
|
592
|
+
// Generate/update prompt files (non-blocking)
|
|
593
|
+
import('../build/vite/prompt-generator')
|
|
594
|
+
.then(({ generatePromptFiles }) => generatePromptFiles(srcDir, logger))
|
|
595
|
+
.catch((err) => logger.warn('Failed to generate prompt files: %s', err.message));
|
|
596
|
+
const agents = await discoverAgents(
|
|
597
|
+
srcDir,
|
|
598
|
+
project?.projectId ?? '',
|
|
599
|
+
deploymentId,
|
|
600
|
+
logger
|
|
419
601
|
);
|
|
420
|
-
|
|
421
|
-
|
|
602
|
+
const { routes } = await discoverRoutes(
|
|
603
|
+
srcDir,
|
|
604
|
+
project?.projectId ?? '',
|
|
605
|
+
deploymentId,
|
|
606
|
+
logger
|
|
607
|
+
);
|
|
608
|
+
|
|
609
|
+
const metadata = await generateMetadata({
|
|
610
|
+
rootDir,
|
|
611
|
+
projectId: project?.projectId ?? '',
|
|
612
|
+
orgId: project?.orgId ?? '',
|
|
613
|
+
deploymentId,
|
|
614
|
+
agents,
|
|
615
|
+
routes,
|
|
616
|
+
dev: true,
|
|
617
|
+
logger,
|
|
618
|
+
});
|
|
619
|
+
|
|
620
|
+
writeMetadataFile(rootDir, metadata, true, logger);
|
|
621
|
+
|
|
622
|
+
// Sync metadata with backend (creates agents and evals in the database)
|
|
623
|
+
if (syncService && project?.projectId) {
|
|
624
|
+
await syncService.sync(
|
|
625
|
+
metadata,
|
|
626
|
+
previousMetadata,
|
|
627
|
+
project.projectId,
|
|
628
|
+
deploymentId
|
|
629
|
+
);
|
|
630
|
+
previousMetadata = metadata;
|
|
631
|
+
}
|
|
422
632
|
},
|
|
423
633
|
clearOnSuccess: true,
|
|
424
634
|
});
|
|
@@ -600,7 +810,7 @@ export const command = createCommand({
|
|
|
600
810
|
});
|
|
601
811
|
break;
|
|
602
812
|
case 'q':
|
|
603
|
-
|
|
813
|
+
void cleanup(true, 0);
|
|
604
814
|
break;
|
|
605
815
|
default:
|
|
606
816
|
process.stdout.write(data);
|
|
@@ -627,18 +837,8 @@ export const command = createCommand({
|
|
|
627
837
|
// Restart triggered - cleanup and loop (Vite stays running)
|
|
628
838
|
logger.debug('Restarting backend server...');
|
|
629
839
|
|
|
630
|
-
//
|
|
631
|
-
|
|
632
|
-
try {
|
|
633
|
-
gravityProcess.kill('SIGTERM');
|
|
634
|
-
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
635
|
-
if (gravityProcess.exitCode === null) {
|
|
636
|
-
gravityProcess.kill('SIGKILL');
|
|
637
|
-
}
|
|
638
|
-
} catch (err) {
|
|
639
|
-
logger.debug('Error killing gravity process during restart: %s', err);
|
|
640
|
-
}
|
|
641
|
-
}
|
|
840
|
+
// Clean up Bun server and Gravity (Vite stays running)
|
|
841
|
+
await cleanupForRestart();
|
|
642
842
|
|
|
643
843
|
// Brief pause before restart
|
|
644
844
|
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
@@ -647,17 +847,10 @@ export const command = createCommand({
|
|
|
647
847
|
tui.warn('Waiting for file changes to retry...');
|
|
648
848
|
|
|
649
849
|
// Cleanup on error (Vite stays running)
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
if (gravityProcess.exitCode === null) {
|
|
655
|
-
gravityProcess.kill('SIGKILL');
|
|
656
|
-
}
|
|
657
|
-
} catch (err) {
|
|
658
|
-
logger.debug('Error killing gravity process on error: %s', err);
|
|
659
|
-
}
|
|
660
|
-
}
|
|
850
|
+
await cleanupForRestart();
|
|
851
|
+
|
|
852
|
+
// Resume file watcher to detect changes for retry
|
|
853
|
+
fileWatcher.resume();
|
|
661
854
|
|
|
662
855
|
// Wait for next restart trigger
|
|
663
856
|
await new Promise<void>((resolve) => {
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { join } from 'node:path';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
|
+
import { semver } from 'bun';
|
|
4
|
+
import type { Logger } from '@agentuity/core';
|
|
5
|
+
|
|
6
|
+
const SKILLS_DIR = '.agents/skills/agentuity/cli';
|
|
7
|
+
const VERSION_FILE = 'version.txt';
|
|
8
|
+
|
|
9
|
+
interface SkillsCheckResult {
|
|
10
|
+
needsRegeneration: boolean;
|
|
11
|
+
reason?: 'missing' | 'outdated' | 'version-missing';
|
|
12
|
+
currentVersion?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export async function checkSkillsVersion(
|
|
16
|
+
projectDir: string,
|
|
17
|
+
cliVersion: string
|
|
18
|
+
): Promise<SkillsCheckResult> {
|
|
19
|
+
const skillsDir = join(projectDir, SKILLS_DIR);
|
|
20
|
+
const versionFile = join(skillsDir, VERSION_FILE);
|
|
21
|
+
|
|
22
|
+
if (!existsSync(skillsDir)) {
|
|
23
|
+
return { needsRegeneration: true, reason: 'missing' };
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (!existsSync(versionFile)) {
|
|
27
|
+
return { needsRegeneration: true, reason: 'version-missing' };
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const currentVersion = (await Bun.file(versionFile).text()).trim();
|
|
31
|
+
if (!currentVersion) {
|
|
32
|
+
return { needsRegeneration: true, reason: 'version-missing' };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
try {
|
|
36
|
+
const order = semver.order(currentVersion, cliVersion);
|
|
37
|
+
if (order < 0) {
|
|
38
|
+
return { needsRegeneration: true, reason: 'outdated', currentVersion };
|
|
39
|
+
}
|
|
40
|
+
} catch {
|
|
41
|
+
return { needsRegeneration: true, reason: 'outdated', currentVersion };
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return { needsRegeneration: false, currentVersion };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export async function regenerateSkillsAsync(
|
|
48
|
+
projectDir: string,
|
|
49
|
+
cliVersion: string,
|
|
50
|
+
logger: Logger
|
|
51
|
+
): Promise<void> {
|
|
52
|
+
const result = await checkSkillsVersion(projectDir, cliVersion);
|
|
53
|
+
|
|
54
|
+
if (!result.needsRegeneration) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const reasonMsg =
|
|
59
|
+
result.reason === 'missing'
|
|
60
|
+
? 'Skills not found'
|
|
61
|
+
: result.reason === 'version-missing'
|
|
62
|
+
? 'Skills version unknown'
|
|
63
|
+
: `Skills outdated (${result.currentVersion} < ${cliVersion})`;
|
|
64
|
+
|
|
65
|
+
logger.debug(`${reasonMsg}, regenerating...`);
|
|
66
|
+
|
|
67
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
68
|
+
const schema = (global as any).__CLI_SCHEMA__;
|
|
69
|
+
if (!schema) {
|
|
70
|
+
logger.debug('CLI schema not available, skipping skill regeneration');
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
try {
|
|
75
|
+
const outputDir = join(projectDir, '.agents');
|
|
76
|
+
const { generateSkills } = await import('../ai/skills/generator');
|
|
77
|
+
await generateSkills(schema, outputDir, false);
|
|
78
|
+
logger.debug(`Skills regenerated to ${outputDir}/skills/agentuity/cli`);
|
|
79
|
+
} catch (error) {
|
|
80
|
+
logger.debug(`Failed to regenerate skills: ${error}`);
|
|
81
|
+
}
|
|
82
|
+
}
|
package/src/cmd/dev/sync.ts
CHANGED
|
@@ -171,13 +171,13 @@ 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.
|
|
174
|
+
this.logger.debug(
|
|
175
175
|
'[CLI EVAL SYNC] Agent "%s" has %d eval(s)',
|
|
176
176
|
agent.name,
|
|
177
177
|
agent.evals.length
|
|
178
178
|
);
|
|
179
179
|
for (const evalItem of agent.evals) {
|
|
180
|
-
this.logger.
|
|
180
|
+
this.logger.debug(
|
|
181
181
|
'[CLI EVAL SYNC] - %s (evalId: %s)',
|
|
182
182
|
evalItem.name,
|
|
183
183
|
evalItem.evalId
|
|
@@ -185,7 +185,7 @@ class DevmodeSyncService implements IDevmodeSyncService {
|
|
|
185
185
|
}
|
|
186
186
|
}
|
|
187
187
|
}
|
|
188
|
-
this.logger.
|
|
188
|
+
this.logger.debug('[CLI EVAL SYNC] Total current eval(s): %d', currentEvalCount);
|
|
189
189
|
|
|
190
190
|
// Get agents and evals to sync using shared diff logic
|
|
191
191
|
const { create: agentsToCreate, delete: agentsToDelete } = getAgentsToSync(
|
|
@@ -280,7 +280,7 @@ class DevmodeSyncService implements IDevmodeSyncService {
|
|
|
280
280
|
);
|
|
281
281
|
|
|
282
282
|
if (evals.length === 0 && evalsToDelete.length === 0) {
|
|
283
|
-
this.logger.
|
|
283
|
+
this.logger.debug('[CLI EVAL SYNC] No evals to sync, skipping');
|
|
284
284
|
return;
|
|
285
285
|
}
|
|
286
286
|
|
|
@@ -290,9 +290,9 @@ class DevmodeSyncService implements IDevmodeSyncService {
|
|
|
290
290
|
delete: evalsToDelete,
|
|
291
291
|
};
|
|
292
292
|
|
|
293
|
-
this.logger.
|
|
293
|
+
this.logger.debug('[CLI EVAL SYNC] Sending payload to POST /cli/devmode/eval:');
|
|
294
294
|
for (const evalItem of evals) {
|
|
295
|
-
this.logger.
|
|
295
|
+
this.logger.debug(
|
|
296
296
|
'[CLI EVAL SYNC] - %s (id: %s, evalId: %s)',
|
|
297
297
|
evalItem.name,
|
|
298
298
|
evalItem.id,
|
|
@@ -306,7 +306,7 @@ class DevmodeSyncService implements IDevmodeSyncService {
|
|
|
306
306
|
payload,
|
|
307
307
|
z.object({ success: z.boolean() })
|
|
308
308
|
);
|
|
309
|
-
this.logger.
|
|
309
|
+
this.logger.debug('[CLI EVAL SYNC] Sync successful');
|
|
310
310
|
} catch (error) {
|
|
311
311
|
this.logger.error('[CLI EVAL SYNC] Sync failed: %s', error);
|
|
312
312
|
throw error;
|
package/src/cmd/index.ts
CHANGED
|
@@ -39,6 +39,7 @@ export async function discoverCommands(): Promise<CommandDefinition[]> {
|
|
|
39
39
|
description: subcommand.description,
|
|
40
40
|
aliases: subcommand.aliases,
|
|
41
41
|
hidden: true,
|
|
42
|
+
skipSkill: true,
|
|
42
43
|
requires: subcommand.requires,
|
|
43
44
|
optional: subcommand.optional,
|
|
44
45
|
schema: subcommand.schema,
|
|
@@ -12,6 +12,7 @@ const ProjectCreateResponseSchema = z.object({
|
|
|
12
12
|
template: z.string().describe('Template used'),
|
|
13
13
|
installed: z.boolean().describe('Whether dependencies were installed'),
|
|
14
14
|
built: z.boolean().describe('Whether the project was built'),
|
|
15
|
+
domains: z.array(z.string()).optional().describe('Array of custom domains'),
|
|
15
16
|
});
|
|
16
17
|
|
|
17
18
|
export const createProjectSubcommand = createSubcommand({
|
|
@@ -40,6 +41,7 @@ export const createProjectSubcommand = createSubcommand({
|
|
|
40
41
|
options: z.object({
|
|
41
42
|
name: z.string().optional().describe('Project name'),
|
|
42
43
|
dir: z.string().optional().describe('Directory to create the project in'),
|
|
44
|
+
domains: z.array(z.string()).optional().describe('Array of custom domains'),
|
|
43
45
|
template: z.string().optional().describe('Template to use'),
|
|
44
46
|
templateDir: z
|
|
45
47
|
.string()
|
|
@@ -84,6 +86,7 @@ export const createProjectSubcommand = createSubcommand({
|
|
|
84
86
|
await runCreateFlow({
|
|
85
87
|
projectName: opts.name,
|
|
86
88
|
dir: opts.dir,
|
|
89
|
+
domains: opts.domains,
|
|
87
90
|
template: opts.template,
|
|
88
91
|
templateDir: opts.templateDir,
|
|
89
92
|
templateBranch: opts.templateBranch,
|