@agentuity/cli 2.0.10 → 2.0.12
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/cache/resource-region.d.ts.map +1 -1
- package/dist/cache/resource-region.js +48 -25
- package/dist/cache/resource-region.js.map +1 -1
- package/dist/cmd/build/vite/agent-discovery.js +4 -4
- package/dist/cmd/build/vite/agent-discovery.js.map +1 -1
- package/dist/cmd/build/vite/bun-dev-server.d.ts +20 -0
- package/dist/cmd/build/vite/bun-dev-server.d.ts.map +1 -1
- package/dist/cmd/build/vite/bun-dev-server.js +62 -4
- 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/static-renderer.d.ts +17 -0
- package/dist/cmd/build/vite/static-renderer.d.ts.map +1 -1
- package/dist/cmd/build/vite/static-renderer.js +18 -6
- package/dist/cmd/build/vite/static-renderer.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 +34 -27
- package/dist/cmd/build/vite/vite-asset-server-config.js.map +1 -1
- package/dist/cmd/build/vite/vite-asset-server.d.ts +9 -0
- package/dist/cmd/build/vite/vite-asset-server.d.ts.map +1 -1
- package/dist/cmd/build/vite/vite-asset-server.js +5 -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 +12 -1
- package/dist/cmd/build/vite/vite-builder.js.map +1 -1
- package/dist/cmd/build/vite/ws-proxy.d.ts +15 -1
- package/dist/cmd/build/vite/ws-proxy.d.ts.map +1 -1
- package/dist/cmd/build/vite/ws-proxy.js +33 -0
- package/dist/cmd/build/vite/ws-proxy.js.map +1 -1
- package/dist/cmd/cloud/deploy.d.ts.map +1 -1
- package/dist/cmd/cloud/deploy.js +98 -39
- package/dist/cmd/cloud/deploy.js.map +1 -1
- package/dist/cmd/cloud/sandbox/checkpoint/create.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/checkpoint/create.js +3 -4
- package/dist/cmd/cloud/sandbox/checkpoint/create.js.map +1 -1
- package/dist/cmd/cloud/sandbox/checkpoint/delete.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/checkpoint/delete.js +3 -4
- package/dist/cmd/cloud/sandbox/checkpoint/delete.js.map +1 -1
- package/dist/cmd/cloud/sandbox/checkpoint/list.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/checkpoint/list.js +3 -4
- package/dist/cmd/cloud/sandbox/checkpoint/list.js.map +1 -1
- package/dist/cmd/cloud/sandbox/checkpoint/restore.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/checkpoint/restore.js +3 -4
- package/dist/cmd/cloud/sandbox/checkpoint/restore.js.map +1 -1
- package/dist/cmd/cloud/sandbox/create.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/create.js +13 -4
- package/dist/cmd/cloud/sandbox/create.js.map +1 -1
- package/dist/cmd/cloud/sandbox/delete.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/delete.js +3 -4
- package/dist/cmd/cloud/sandbox/delete.js.map +1 -1
- package/dist/cmd/cloud/sandbox/env.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/env.js +3 -5
- package/dist/cmd/cloud/sandbox/env.js.map +1 -1
- package/dist/cmd/cloud/sandbox/exec.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/exec.js +114 -41
- package/dist/cmd/cloud/sandbox/exec.js.map +1 -1
- package/dist/cmd/cloud/sandbox/execution/list.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/execution/list.js +3 -5
- package/dist/cmd/cloud/sandbox/execution/list.js.map +1 -1
- package/dist/cmd/cloud/sandbox/fs/cp.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/fs/cp.js +61 -113
- package/dist/cmd/cloud/sandbox/fs/cp.js.map +1 -1
- package/dist/cmd/cloud/sandbox/fs/download.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/fs/download.js +11 -22
- package/dist/cmd/cloud/sandbox/fs/download.js.map +1 -1
- package/dist/cmd/cloud/sandbox/fs/ls.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/fs/ls.js +3 -5
- package/dist/cmd/cloud/sandbox/fs/ls.js.map +1 -1
- package/dist/cmd/cloud/sandbox/fs/mkdir.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/fs/mkdir.js +3 -5
- package/dist/cmd/cloud/sandbox/fs/mkdir.js.map +1 -1
- package/dist/cmd/cloud/sandbox/fs/rm.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/fs/rm.js +3 -5
- package/dist/cmd/cloud/sandbox/fs/rm.js.map +1 -1
- package/dist/cmd/cloud/sandbox/fs/rmdir.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/fs/rmdir.js +3 -5
- package/dist/cmd/cloud/sandbox/fs/rmdir.js.map +1 -1
- package/dist/cmd/cloud/sandbox/fs/upload.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/fs/upload.js +7 -8
- package/dist/cmd/cloud/sandbox/fs/upload.js.map +1 -1
- package/dist/cmd/cloud/sandbox/get.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/get.js +21 -7
- package/dist/cmd/cloud/sandbox/get.js.map +1 -1
- package/dist/cmd/cloud/sandbox/job/create.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/job/create.js +3 -4
- package/dist/cmd/cloud/sandbox/job/create.js.map +1 -1
- package/dist/cmd/cloud/sandbox/job/destroy.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/job/destroy.js +3 -4
- package/dist/cmd/cloud/sandbox/job/destroy.js.map +1 -1
- package/dist/cmd/cloud/sandbox/job/get.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/job/get.js +3 -4
- package/dist/cmd/cloud/sandbox/job/get.js.map +1 -1
- package/dist/cmd/cloud/sandbox/job/list.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/job/list.js +3 -4
- package/dist/cmd/cloud/sandbox/job/list.js.map +1 -1
- package/dist/cmd/cloud/sandbox/job/logs.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/job/logs.js +4 -4
- package/dist/cmd/cloud/sandbox/job/logs.js.map +1 -1
- package/dist/cmd/cloud/sandbox/pause.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/pause.js +21 -5
- package/dist/cmd/cloud/sandbox/pause.js.map +1 -1
- package/dist/cmd/cloud/sandbox/resume.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/resume.js +3 -4
- package/dist/cmd/cloud/sandbox/resume.js.map +1 -1
- package/dist/cmd/cloud/sandbox/run.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/run.js +36 -7
- package/dist/cmd/cloud/sandbox/run.js.map +1 -1
- package/dist/cmd/cloud/sandbox/util.d.ts +19 -0
- package/dist/cmd/cloud/sandbox/util.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/util.js +40 -2
- package/dist/cmd/cloud/sandbox/util.js.map +1 -1
- package/dist/cmd/coder/create.d.ts.map +1 -1
- package/dist/cmd/coder/create.js +18 -0
- package/dist/cmd/coder/create.js.map +1 -1
- package/dist/cmd/coder/index.d.ts.map +1 -1
- package/dist/cmd/coder/index.js +4 -0
- package/dist/cmd/coder/index.js.map +1 -1
- package/dist/cmd/coder/start.d.ts.map +1 -1
- package/dist/cmd/coder/start.js +52 -1
- package/dist/cmd/coder/start.js.map +1 -1
- package/dist/cmd/coder/tui-init.js +1 -1
- package/dist/cmd/coder/tui-init.js.map +1 -1
- package/dist/cmd/coder/update.d.ts.map +1 -1
- package/dist/cmd/coder/update.js +21 -1
- package/dist/cmd/coder/update.js.map +1 -1
- package/dist/cmd/coder/workspace/create.d.ts.map +1 -1
- package/dist/cmd/coder/workspace/create.js +57 -13
- package/dist/cmd/coder/workspace/create.js.map +1 -1
- package/dist/cmd/coder/workspace/index.d.ts.map +1 -1
- package/dist/cmd/coder/workspace/index.js +1 -1
- package/dist/cmd/coder/workspace/index.js.map +1 -1
- package/dist/cmd/coder/workspace/list.js +2 -2
- package/dist/cmd/coder/workspace/list.js.map +1 -1
- package/dist/cmd/dev/dev-lock.d.ts.map +1 -1
- package/dist/cmd/dev/dev-lock.js +43 -17
- package/dist/cmd/dev/dev-lock.js.map +1 -1
- package/dist/cmd/dev/index.d.ts.map +1 -1
- package/dist/cmd/dev/index.js +211 -125
- package/dist/cmd/dev/index.js.map +1 -1
- package/dist/cmd/dev/process-manager.d.ts +41 -1
- package/dist/cmd/dev/process-manager.d.ts.map +1 -1
- package/dist/cmd/dev/process-manager.js +160 -31
- package/dist/cmd/dev/process-manager.js.map +1 -1
- package/dist/cmd/project/create.d.ts.map +1 -1
- package/dist/cmd/project/create.js +0 -2
- package/dist/cmd/project/create.js.map +1 -1
- package/dist/cmd/project/index.d.ts.map +1 -1
- package/dist/cmd/project/index.js +0 -3
- package/dist/cmd/project/index.js.map +1 -1
- package/dist/cmd/project/template-flow.d.ts +0 -1
- package/dist/cmd/project/template-flow.d.ts.map +1 -1
- package/dist/cmd/project/template-flow.js +1 -124
- package/dist/cmd/project/template-flow.js.map +1 -1
- package/dist/types.d.ts +1 -1
- package/package.json +7 -7
- package/src/cache/resource-region.ts +68 -44
- package/src/cmd/ai/prompt/web.md +43 -17
- package/src/cmd/build/vite/agent-discovery.ts +4 -4
- package/src/cmd/build/vite/bun-dev-server.ts +92 -6
- package/src/cmd/build/vite/index.ts +0 -1
- package/src/cmd/build/vite/static-renderer.ts +18 -7
- package/src/cmd/build/vite/vite-asset-server-config.ts +37 -27
- package/src/cmd/build/vite/vite-asset-server.ts +5 -1
- package/src/cmd/build/vite/vite-builder.ts +12 -1
- package/src/cmd/build/vite/ws-proxy.ts +52 -3
- package/src/cmd/cloud/deploy.ts +117 -49
- package/src/cmd/cloud/sandbox/checkpoint/create.ts +10 -4
- package/src/cmd/cloud/sandbox/checkpoint/delete.ts +10 -4
- package/src/cmd/cloud/sandbox/checkpoint/list.ts +10 -4
- package/src/cmd/cloud/sandbox/checkpoint/restore.ts +10 -4
- package/src/cmd/cloud/sandbox/create.ts +14 -4
- package/src/cmd/cloud/sandbox/delete.ts +10 -4
- package/src/cmd/cloud/sandbox/env.ts +10 -5
- package/src/cmd/cloud/sandbox/exec.ts +157 -42
- package/src/cmd/cloud/sandbox/execution/list.ts +10 -5
- package/src/cmd/cloud/sandbox/fs/cp.ts +94 -126
- package/src/cmd/cloud/sandbox/fs/download.ts +18 -25
- package/src/cmd/cloud/sandbox/fs/ls.ts +10 -5
- package/src/cmd/cloud/sandbox/fs/mkdir.ts +10 -5
- package/src/cmd/cloud/sandbox/fs/rm.ts +10 -5
- package/src/cmd/cloud/sandbox/fs/rmdir.ts +10 -5
- package/src/cmd/cloud/sandbox/fs/upload.ts +14 -8
- package/src/cmd/cloud/sandbox/get.ts +28 -7
- package/src/cmd/cloud/sandbox/job/create.ts +10 -4
- package/src/cmd/cloud/sandbox/job/destroy.ts +10 -4
- package/src/cmd/cloud/sandbox/job/get.ts +10 -4
- package/src/cmd/cloud/sandbox/job/list.ts +10 -4
- package/src/cmd/cloud/sandbox/job/logs.ts +11 -4
- package/src/cmd/cloud/sandbox/pause.ts +31 -5
- package/src/cmd/cloud/sandbox/resume.ts +10 -4
- package/src/cmd/cloud/sandbox/run.ts +49 -11
- package/src/cmd/cloud/sandbox/util.ts +63 -2
- package/src/cmd/coder/create.ts +24 -1
- package/src/cmd/coder/index.ts +4 -0
- package/src/cmd/coder/start.ts +63 -1
- package/src/cmd/coder/tui-init.ts +1 -1
- package/src/cmd/coder/update.ts +18 -1
- package/src/cmd/coder/workspace/create.ts +84 -15
- package/src/cmd/coder/workspace/index.ts +3 -1
- package/src/cmd/coder/workspace/list.ts +2 -2
- package/src/cmd/dev/dev-lock.ts +50 -16
- package/src/cmd/dev/index.ts +249 -134
- package/src/cmd/dev/process-manager.ts +173 -33
- package/src/cmd/project/create.ts +0 -2
- package/src/cmd/project/index.ts +0 -3
- package/src/cmd/project/template-flow.ts +0 -147
- package/dist/cmd/build/vite/public-asset-path-plugin.d.ts +0 -45
- package/dist/cmd/build/vite/public-asset-path-plugin.d.ts.map +0 -1
- package/dist/cmd/build/vite/public-asset-path-plugin.js +0 -166
- package/dist/cmd/build/vite/public-asset-path-plugin.js.map +0 -1
- package/dist/cmd/project/auth/generate.d.ts +0 -5
- package/dist/cmd/project/auth/generate.d.ts.map +0 -1
- package/dist/cmd/project/auth/generate.js +0 -102
- package/dist/cmd/project/auth/generate.js.map +0 -1
- package/dist/cmd/project/auth/index.d.ts +0 -2
- package/dist/cmd/project/auth/index.d.ts.map +0 -1
- package/dist/cmd/project/auth/index.js +0 -21
- package/dist/cmd/project/auth/index.js.map +0 -1
- package/dist/cmd/project/auth/init.d.ts +0 -2
- package/dist/cmd/project/auth/init.d.ts.map +0 -1
- package/dist/cmd/project/auth/init.js +0 -213
- package/dist/cmd/project/auth/init.js.map +0 -1
- package/dist/cmd/project/auth/shared.d.ts +0 -93
- package/dist/cmd/project/auth/shared.d.ts.map +0 -1
- package/dist/cmd/project/auth/shared.js +0 -475
- package/dist/cmd/project/auth/shared.js.map +0 -1
- package/src/cmd/build/vite/public-asset-path-plugin.ts +0 -209
- package/src/cmd/project/auth/generate.ts +0 -116
- package/src/cmd/project/auth/index.ts +0 -21
- package/src/cmd/project/auth/init.ts +0 -256
- package/src/cmd/project/auth/shared.ts +0 -591
package/src/cmd/dev/index.ts
CHANGED
|
@@ -45,27 +45,38 @@ interface ServerLike {
|
|
|
45
45
|
/**
|
|
46
46
|
* Kill any lingering gravity processes from previous dev sessions.
|
|
47
47
|
* This is a defensive measure to clean up orphaned processes.
|
|
48
|
+
*
|
|
49
|
+
* When a projectId is provided, only kills gravity processes for that specific
|
|
50
|
+
* project. Otherwise falls back to killing all gravity processes (used during
|
|
51
|
+
* startup before project info is available).
|
|
48
52
|
*/
|
|
49
|
-
async function killLingeringGravityProcesses(
|
|
50
|
-
|
|
51
|
-
|
|
53
|
+
async function killLingeringGravityProcesses(
|
|
54
|
+
logger: {
|
|
55
|
+
debug: (msg: string, ...args: unknown[]) => void;
|
|
56
|
+
},
|
|
57
|
+
projectId?: string
|
|
58
|
+
): Promise<void> {
|
|
52
59
|
// Only attempt on Unix-like systems (macOS, Linux)
|
|
53
60
|
if (process.platform === 'win32') {
|
|
54
61
|
return;
|
|
55
62
|
}
|
|
56
63
|
|
|
57
64
|
try {
|
|
58
|
-
//
|
|
59
|
-
//
|
|
60
|
-
|
|
61
|
-
|
|
65
|
+
// Scope the pkill pattern to the specific project when possible,
|
|
66
|
+
// avoiding killing gravity processes from other dev sessions.
|
|
67
|
+
const pattern = projectId ? `gravity.*--project-id.*${projectId}` : 'gravity.*--endpoint-id';
|
|
68
|
+
|
|
69
|
+
const result = Bun.spawnSync(['pkill', '-f', pattern], {
|
|
62
70
|
stdout: 'ignore',
|
|
63
71
|
stderr: 'ignore',
|
|
64
72
|
});
|
|
65
73
|
|
|
66
74
|
// Exit code 0 = processes killed, 1 = no matching processes, other = error
|
|
67
75
|
if (result.exitCode === 0) {
|
|
68
|
-
logger.debug(
|
|
76
|
+
logger.debug(
|
|
77
|
+
'Killed lingering gravity processes%s from previous session',
|
|
78
|
+
projectId ? ` (project ${projectId})` : ''
|
|
79
|
+
);
|
|
69
80
|
// Brief pause to let processes fully terminate
|
|
70
81
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
71
82
|
} else if (result.exitCode === 1) {
|
|
@@ -78,19 +89,46 @@ async function killLingeringGravityProcesses(logger: {
|
|
|
78
89
|
|
|
79
90
|
/**
|
|
80
91
|
* Kill the Bun backend subprocess if one is running.
|
|
92
|
+
*
|
|
93
|
+
* @param forceKill - If true, sends SIGKILL instead of SIGTERM. Used in
|
|
94
|
+
* process.on('exit') handlers where there's no time for graceful shutdown.
|
|
95
|
+
* Also kills the entire process tree to prevent orphaned child processes.
|
|
81
96
|
*/
|
|
82
|
-
function killBunSubprocess(
|
|
97
|
+
function killBunSubprocess(
|
|
98
|
+
logger: { debug: (msg: string, ...args: unknown[]) => void },
|
|
99
|
+
forceKill = false
|
|
100
|
+
): void {
|
|
83
101
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
84
102
|
const globalAny = globalThis as any;
|
|
85
103
|
const bunSubprocess = globalAny.__AGENTUITY_BUN_SUBPROCESS__ as ProcessLike | undefined;
|
|
86
104
|
if (!bunSubprocess) return;
|
|
87
105
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
106
|
+
const signal: NodeJS.Signals = forceKill ? 'SIGKILL' : 'SIGTERM';
|
|
107
|
+
const pid = bunSubprocess.pid;
|
|
108
|
+
|
|
109
|
+
// Kill the entire process tree if we have a PID (guard against dangerous PIDs)
|
|
110
|
+
if (pid && pid > 1) {
|
|
111
|
+
try {
|
|
112
|
+
process.kill(-pid, signal);
|
|
113
|
+
logger.debug('Sent %s to Bun subprocess process group -%d', signal, pid);
|
|
114
|
+
} catch {
|
|
115
|
+
// Process group kill failed, fall back to direct kill
|
|
116
|
+
try {
|
|
117
|
+
bunSubprocess.kill(signal);
|
|
118
|
+
logger.debug('Sent %s to Bun subprocess pid %d (direct)', signal, pid);
|
|
119
|
+
} catch (err) {
|
|
120
|
+
logger.debug('Error killing Bun subprocess: %s', err);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
} else {
|
|
124
|
+
try {
|
|
125
|
+
bunSubprocess.kill(signal);
|
|
126
|
+
logger.debug('Bun subprocess killed with %s', signal);
|
|
127
|
+
} catch (err) {
|
|
128
|
+
logger.debug('Error killing Bun subprocess: %s', err);
|
|
129
|
+
}
|
|
93
130
|
}
|
|
131
|
+
|
|
94
132
|
globalAny.__AGENTUITY_BUN_SUBPROCESS__ = undefined;
|
|
95
133
|
}
|
|
96
134
|
|
|
@@ -326,9 +364,9 @@ export const command = createCommand({
|
|
|
326
364
|
// and creates a new lockfile for this session
|
|
327
365
|
const devLock = await prepareDevLock(rootDir, opts.port, logger);
|
|
328
366
|
|
|
329
|
-
// Kill any lingering gravity processes from previous dev sessions
|
|
330
|
-
//
|
|
331
|
-
await killLingeringGravityProcesses(logger);
|
|
367
|
+
// Kill any lingering gravity processes from previous dev sessions.
|
|
368
|
+
// Scoped to this project to avoid killing gravity from other dev sessions.
|
|
369
|
+
await killLingeringGravityProcesses(logger, project?.projectId);
|
|
332
370
|
|
|
333
371
|
// Check and upgrade @agentuity/* dependencies if needed
|
|
334
372
|
const upgradeResult = await checkAndUpgradeDependencies(rootDir, logger);
|
|
@@ -534,102 +572,47 @@ export const command = createCommand({
|
|
|
534
572
|
};
|
|
535
573
|
}
|
|
536
574
|
|
|
537
|
-
//
|
|
538
|
-
//
|
|
539
|
-
//
|
|
575
|
+
// --- State for long-running processes ---
|
|
576
|
+
// Declared early so signal handlers can reference them before
|
|
577
|
+
// servers are started.
|
|
540
578
|
let viteServer: ServerLike | null = null;
|
|
541
|
-
let
|
|
579
|
+
let frontDoorServer: import('../build/vite/ws-proxy').WsProxyServer | null = null;
|
|
580
|
+
let gravityProcess: ProcessLike | null = null;
|
|
581
|
+
let gravityHeartbeatInterval: ReturnType<typeof setInterval> | null = null;
|
|
582
|
+
let stdinListenerRegistered = false;
|
|
583
|
+
let stdinDataHandler: ((data: Buffer | string) => void) | null = null;
|
|
584
|
+
let shutdownRequested = false;
|
|
542
585
|
|
|
543
586
|
// Initialize process manager to track all servers/processes
|
|
544
587
|
const procManager = initProcessManager(logger);
|
|
545
588
|
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
port: viteInternalPort,
|
|
553
|
-
backendPort: bunBackendPort,
|
|
554
|
-
routePaths,
|
|
555
|
-
liveHostname: devmode?.hostname,
|
|
556
|
-
});
|
|
557
|
-
viteServer = viteResult.server;
|
|
558
|
-
vitePort = viteResult.port;
|
|
559
|
-
|
|
560
|
-
// Register Vite server with process manager
|
|
561
|
-
procManager.registerServer({
|
|
562
|
-
id: 'vite',
|
|
563
|
-
server: viteServer,
|
|
564
|
-
description: 'Vite dev server (frontend assets)',
|
|
565
|
-
port: vitePort,
|
|
566
|
-
});
|
|
567
|
-
|
|
568
|
-
// Update dev lock with actual Vite port
|
|
569
|
-
await devLock.updatePorts({ vite: vitePort });
|
|
570
|
-
|
|
571
|
-
logger.debug(
|
|
572
|
-
`Vite dev server running on port ${vitePort} (internal, proxying backend on port ${bunBackendPort})`
|
|
573
|
-
);
|
|
574
|
-
} catch (error) {
|
|
575
|
-
tui.error(`Failed to start Vite dev server: ${error}`);
|
|
576
|
-
await procManager.cleanup('vite startup failure');
|
|
577
|
-
await devLock.release();
|
|
578
|
-
originalExit(1);
|
|
579
|
-
return;
|
|
580
|
-
}
|
|
581
|
-
|
|
582
|
-
// Start the front-door TCP proxy on the user-facing port.
|
|
583
|
-
// Routes WebSocket upgrades (for /api/*, /_agentuity/*) directly to Bun
|
|
584
|
-
// and everything else (HTTP, HMR WebSocket) to Vite.
|
|
585
|
-
// This works around Bun's broken node:http upgrade socket implementation.
|
|
586
|
-
let frontDoorServer: import('node:net').Server | null = null;
|
|
587
|
-
try {
|
|
588
|
-
const { startWsProxy } = await import('../build/vite/ws-proxy');
|
|
589
|
-
frontDoorServer = await startWsProxy({
|
|
590
|
-
port: opts.port,
|
|
591
|
-
vitePort,
|
|
592
|
-
backendPort: bunBackendPort,
|
|
593
|
-
routePaths,
|
|
594
|
-
logger,
|
|
595
|
-
});
|
|
589
|
+
// Resolve the actual Vite port BEFORE starting Bun so that env vars
|
|
590
|
+
// like AGENTUITY_BASE_URL contain the correct port. The runtime's
|
|
591
|
+
// CORS trusted-origins are built once at startup, so a late update
|
|
592
|
+
// would leave the backend with stale origins.
|
|
593
|
+
const { findAvailablePort } = await import('../build/vite/vite-asset-server');
|
|
594
|
+
const vitePort = await findAvailablePort(viteInternalPort, '127.0.0.1');
|
|
596
595
|
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
server: {
|
|
601
|
-
close: () => {
|
|
602
|
-
frontDoorServer?.close();
|
|
603
|
-
},
|
|
604
|
-
},
|
|
605
|
-
description: 'Front-door TCP proxy (WS routing)',
|
|
606
|
-
port: opts.port,
|
|
607
|
-
});
|
|
608
|
-
|
|
609
|
-
logger.debug(
|
|
610
|
-
`Front-door proxy on port ${opts.port} (Vite:${vitePort}, Bun:${bunBackendPort})`
|
|
596
|
+
if (vitePort !== viteInternalPort) {
|
|
597
|
+
logger.info(
|
|
598
|
+
`Port ${viteInternalPort} is in use, using port ${vitePort} for Vite dev server`
|
|
611
599
|
);
|
|
612
|
-
} catch (error) {
|
|
613
|
-
tui.error(`Failed to start front-door proxy: ${error}`);
|
|
614
|
-
await procManager.cleanup('front-door proxy startup failure');
|
|
615
|
-
await devLock.release();
|
|
616
|
-
originalExit(1);
|
|
617
|
-
return;
|
|
618
600
|
}
|
|
619
601
|
|
|
620
|
-
//
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
let
|
|
602
|
+
// Separate guard flags:
|
|
603
|
+
// - cleanupStarted: prevents double-entry into cleanup()
|
|
604
|
+
// - shutdownRequested: breaks the main wait loop (set inside cleanup
|
|
605
|
+
// AFTER the cleanupStarted guard passes, so the loop resolves only
|
|
606
|
+
// once cleanup has actually started running)
|
|
607
|
+
let cleanupStarted = false;
|
|
626
608
|
|
|
627
609
|
/**
|
|
628
610
|
* Centralized cleanup function for all resources.
|
|
629
611
|
* Uses the process manager for tracked servers/processes.
|
|
630
612
|
*/
|
|
631
613
|
const cleanup = async (exitAfter = false, exitCode = 0, silent = false) => {
|
|
632
|
-
if (
|
|
614
|
+
if (cleanupStarted) return;
|
|
615
|
+
cleanupStarted = true;
|
|
633
616
|
shutdownRequested = true;
|
|
634
617
|
|
|
635
618
|
if (!silent) {
|
|
@@ -647,7 +630,7 @@ export const command = createCommand({
|
|
|
647
630
|
|
|
648
631
|
// Additional cleanup for non-tracked resources
|
|
649
632
|
await devLock.release();
|
|
650
|
-
await killLingeringGravityProcesses(logger);
|
|
633
|
+
await killLingeringGravityProcesses(logger, project?.projectId);
|
|
651
634
|
|
|
652
635
|
if (exitAfter) {
|
|
653
636
|
if (stdinListenerRegistered && process.stdin.isTTY) {
|
|
@@ -673,7 +656,6 @@ export const command = createCommand({
|
|
|
673
656
|
if (exitingFromSignal) return;
|
|
674
657
|
exitingFromSignal = true;
|
|
675
658
|
if (reason) logger.debug('DevMode terminating (%d): %s', code, reason);
|
|
676
|
-
shutdownRequested = true;
|
|
677
659
|
cleanup(true, code).catch(() => originalExit(1));
|
|
678
660
|
};
|
|
679
661
|
|
|
@@ -693,21 +675,16 @@ export const command = createCommand({
|
|
|
693
675
|
);
|
|
694
676
|
});
|
|
695
677
|
process.on('exit', () => {
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
} catch {
|
|
707
|
-
// Ignore
|
|
708
|
-
}
|
|
709
|
-
}
|
|
710
|
-
killBunSubprocess(logger);
|
|
678
|
+
// Last-resort synchronous cleanup. Only runs aggressive SIGKILL
|
|
679
|
+
// if the async cleanup() hasn't already handled everything.
|
|
680
|
+
// This prevents the race where both cleanup paths try to kill
|
|
681
|
+
// the same processes.
|
|
682
|
+
procManager.forceKillAllSync();
|
|
683
|
+
|
|
684
|
+
// SIGKILL the Bun subprocess tree as a final safety net.
|
|
685
|
+
// forceKill=true ensures we use SIGKILL (no time for graceful
|
|
686
|
+
// shutdown in an exit handler) and target the process group.
|
|
687
|
+
killBunSubprocess(logger, true);
|
|
711
688
|
releaseLockSync(rootDir);
|
|
712
689
|
});
|
|
713
690
|
|
|
@@ -861,6 +838,10 @@ export const command = createCommand({
|
|
|
861
838
|
// Note: AGENTUITY_SDK_KEY, NODE_ENV, AGENTUITY_ENV, and
|
|
862
839
|
// AGENTUITY_TRANSPORT_URL are already set in Step 0b (before
|
|
863
840
|
// agent discovery) to support gateway env patching.
|
|
841
|
+
//
|
|
842
|
+
// vitePort is pre-resolved (via findAvailablePort) before Bun
|
|
843
|
+
// starts, so env vars like AGENTUITY_BASE_URL are correct when
|
|
844
|
+
// the runtime builds its CORS trusted-origin set.
|
|
864
845
|
|
|
865
846
|
process.env.AGENTUITY_SDK_DEV_MODE = 'true';
|
|
866
847
|
process.env.AGENTUITY_RUNTIME = 'yes';
|
|
@@ -910,29 +891,141 @@ export const command = createCommand({
|
|
|
910
891
|
inspect: opts.inspect,
|
|
911
892
|
inspectWait: opts.inspectWait,
|
|
912
893
|
inspectBrk: opts.inspectBrk,
|
|
894
|
+
// Register the subprocess BEFORE the readiness wait so a SIGINT
|
|
895
|
+
// during startup can clean it up via procManager. Without this,
|
|
896
|
+
// the only safety net is the synchronous process.on('exit')
|
|
897
|
+
// handler, which is fragile and runs too late on some signals.
|
|
898
|
+
onSpawn: (proc) => {
|
|
899
|
+
procManager.registerProcess({
|
|
900
|
+
id: 'bun-backend',
|
|
901
|
+
process: proc,
|
|
902
|
+
description: 'Bun backend server (--hot)',
|
|
903
|
+
port: bunBackendPort,
|
|
904
|
+
critical: true,
|
|
905
|
+
});
|
|
906
|
+
},
|
|
913
907
|
});
|
|
908
|
+
} catch (error) {
|
|
909
|
+
tui.error(`Failed to start Bun backend server: ${error}`);
|
|
910
|
+
await cleanup(true, 1, true);
|
|
911
|
+
return;
|
|
912
|
+
}
|
|
914
913
|
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
914
|
+
// ================================================================
|
|
915
|
+
// Step 4: Start Vite asset server (frontend + API proxy)
|
|
916
|
+
// ================================================================
|
|
917
|
+
// Vite starts AFTER the Bun backend so that its proxy is ready
|
|
918
|
+
// to forward API requests immediately — no ECONNREFUSED race.
|
|
919
|
+
|
|
920
|
+
try {
|
|
921
|
+
logger.debug('Starting Vite dev server (internal port %d)...', viteInternalPort);
|
|
922
|
+
const viteResult = await startViteAssetServer({
|
|
923
|
+
rootDir,
|
|
924
|
+
logger,
|
|
925
|
+
workbenchPath: workbench.config?.route,
|
|
926
|
+
port: vitePort,
|
|
927
|
+
backendPort: bunBackendPort,
|
|
928
|
+
routePaths,
|
|
929
|
+
liveHostname: devmode?.hostname,
|
|
930
|
+
});
|
|
931
|
+
viteServer = viteResult.server;
|
|
932
|
+
|
|
933
|
+
// Verify Vite used the port we pre-resolved (should always match
|
|
934
|
+
// since strictPort:true is set and we already confirmed availability).
|
|
935
|
+
if (viteResult.port !== vitePort) {
|
|
936
|
+
logger.warn(
|
|
937
|
+
`Vite started on port ${viteResult.port} instead of expected ${vitePort} — env vars may be incorrect`
|
|
938
|
+
);
|
|
927
939
|
}
|
|
940
|
+
|
|
941
|
+
// Register Vite server with process manager.
|
|
942
|
+
// We wrap close() to first force-drop keep-alive HTTP/HMR sockets via
|
|
943
|
+
// httpServer.closeAllConnections() (Node 18.2+). Without this, idle
|
|
944
|
+
// keep-alive connections keep the listener bound until they time out,
|
|
945
|
+
// which leaves the Vite port reserved for several seconds after the
|
|
946
|
+
// CLI exits. We also extend the close timeout (Vite's chokidar +
|
|
947
|
+
// HMR teardown can exceed 1s under load).
|
|
948
|
+
const viteForCleanup = viteServer;
|
|
949
|
+
procManager.registerServer({
|
|
950
|
+
id: 'vite',
|
|
951
|
+
server: {
|
|
952
|
+
close: async () => {
|
|
953
|
+
try {
|
|
954
|
+
const http = (
|
|
955
|
+
viteForCleanup as unknown as {
|
|
956
|
+
httpServer?: {
|
|
957
|
+
closeAllConnections?: () => void;
|
|
958
|
+
closeIdleConnections?: () => void;
|
|
959
|
+
};
|
|
960
|
+
}
|
|
961
|
+
).httpServer;
|
|
962
|
+
http?.closeIdleConnections?.();
|
|
963
|
+
http?.closeAllConnections?.();
|
|
964
|
+
} catch {
|
|
965
|
+
// Best effort — these methods are runtime-dependent.
|
|
966
|
+
}
|
|
967
|
+
await viteForCleanup.close();
|
|
968
|
+
},
|
|
969
|
+
},
|
|
970
|
+
description: 'Vite dev server (frontend assets)',
|
|
971
|
+
port: vitePort,
|
|
972
|
+
closeTimeoutMs: 3000,
|
|
973
|
+
});
|
|
974
|
+
|
|
975
|
+
// Update dev lock with actual Vite port
|
|
976
|
+
await devLock.updatePorts({ vite: vitePort });
|
|
977
|
+
|
|
978
|
+
logger.debug(
|
|
979
|
+
`Vite dev server running on port ${vitePort} (internal, proxying backend on port ${bunBackendPort})`
|
|
980
|
+
);
|
|
928
981
|
} catch (error) {
|
|
929
|
-
tui.error(`Failed to start
|
|
982
|
+
tui.error(`Failed to start Vite dev server: ${error}`);
|
|
930
983
|
await cleanup(true, 1, true);
|
|
931
984
|
return;
|
|
932
985
|
}
|
|
933
986
|
|
|
934
987
|
// ================================================================
|
|
935
|
-
// Step
|
|
988
|
+
// Step 5: Start front-door TCP proxy (user-facing port)
|
|
989
|
+
// ================================================================
|
|
990
|
+
// Routes WebSocket upgrades (for /api/*, /_agentuity/*) directly to Bun
|
|
991
|
+
// and everything else (HTTP, HMR WebSocket) to Vite.
|
|
992
|
+
// This works around Bun's broken node:http upgrade socket implementation.
|
|
993
|
+
|
|
994
|
+
try {
|
|
995
|
+
const { startWsProxy } = await import('../build/vite/ws-proxy');
|
|
996
|
+
frontDoorServer = await startWsProxy({
|
|
997
|
+
port: opts.port,
|
|
998
|
+
vitePort,
|
|
999
|
+
backendPort: bunBackendPort,
|
|
1000
|
+
routePaths,
|
|
1001
|
+
logger,
|
|
1002
|
+
});
|
|
1003
|
+
|
|
1004
|
+
// Register front-door proxy with process manager. Use closeAll()
|
|
1005
|
+
// (returns a Promise) so cleanup actually waits for the listener
|
|
1006
|
+
// to release the user-facing port instead of fire-and-forgetting.
|
|
1007
|
+
// closeAll() also destroys live piped sockets (HMR WS, backend WS)
|
|
1008
|
+
// so the listener doesn't sit waiting for clients to disconnect.
|
|
1009
|
+
procManager.registerServer({
|
|
1010
|
+
id: 'front-door-proxy',
|
|
1011
|
+
server: {
|
|
1012
|
+
close: () => frontDoorServer?.closeAll() ?? Promise.resolve(),
|
|
1013
|
+
},
|
|
1014
|
+
description: 'Front-door TCP proxy (WS routing)',
|
|
1015
|
+
port: opts.port,
|
|
1016
|
+
});
|
|
1017
|
+
|
|
1018
|
+
logger.debug(
|
|
1019
|
+
`Front-door proxy on port ${opts.port} (Vite:${vitePort}, Bun:${bunBackendPort})`
|
|
1020
|
+
);
|
|
1021
|
+
} catch (error) {
|
|
1022
|
+
tui.error(`Failed to start front-door proxy: ${error}`);
|
|
1023
|
+
await cleanup(true, 1, true);
|
|
1024
|
+
return;
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
// ================================================================
|
|
1028
|
+
// Step 6: Start gravity tunnel (if public URL enabled)
|
|
936
1029
|
// ================================================================
|
|
937
1030
|
|
|
938
1031
|
if (gravityBin && gravityURL && devmode && project) {
|
|
@@ -945,6 +1038,15 @@ export const command = createCommand({
|
|
|
945
1038
|
return;
|
|
946
1039
|
}
|
|
947
1040
|
|
|
1041
|
+
// Gravity must target the user-facing front-door proxy port.
|
|
1042
|
+
// The front-door proxy (ws-proxy) is the only server that correctly
|
|
1043
|
+
// routes public WebSocket upgrades to /api/* through to the Bun backend.
|
|
1044
|
+
// We read the actual bound port from the front-door server to avoid any
|
|
1045
|
+
// mismatch with opts.port (e.g. if the port was overridden or shifted).
|
|
1046
|
+
const frontDoorPort =
|
|
1047
|
+
(frontDoorServer?.address() as import('node:net').AddressInfo | null)?.port ??
|
|
1048
|
+
opts.port;
|
|
1049
|
+
|
|
948
1050
|
try {
|
|
949
1051
|
gravityProcess = Bun.spawn(
|
|
950
1052
|
[
|
|
@@ -952,7 +1054,7 @@ export const command = createCommand({
|
|
|
952
1054
|
'--endpoint-id',
|
|
953
1055
|
devmode.id,
|
|
954
1056
|
'--port',
|
|
955
|
-
|
|
1057
|
+
frontDoorPort.toString(),
|
|
956
1058
|
'--url',
|
|
957
1059
|
gravityURL,
|
|
958
1060
|
'--log-level',
|
|
@@ -969,10 +1071,24 @@ export const command = createCommand({
|
|
|
969
1071
|
cwd: rootDir,
|
|
970
1072
|
stdout: 'pipe',
|
|
971
1073
|
stderr: 'pipe',
|
|
972
|
-
|
|
1074
|
+
// Make the child a process-group leader so process.kill(-pid, signal)
|
|
1075
|
+
// from procManager.killProcessTree() actually reaches the whole tree
|
|
1076
|
+
// (otherwise it fails with EPERM and falls back to a direct PID kill
|
|
1077
|
+
// that leaves any grandchildren running). We intentionally do NOT call
|
|
1078
|
+
// .unref() — we still want the parent to track the child's lifecycle
|
|
1079
|
+
// and drive cleanup on Ctrl-C / shutdown.
|
|
1080
|
+
detached: true,
|
|
1081
|
+
// Pass a clean env without PORT to prevent the inherited
|
|
1082
|
+
// PORT (set to bunBackendPort) from leaking into gravity.
|
|
1083
|
+
env: {
|
|
1084
|
+
...process.env,
|
|
1085
|
+
PORT: undefined,
|
|
1086
|
+
},
|
|
973
1087
|
}
|
|
974
1088
|
);
|
|
975
1089
|
|
|
1090
|
+
logger.debug('Gravity tunnel targeting front-door proxy on port %d', frontDoorPort);
|
|
1091
|
+
|
|
976
1092
|
const gravityPid = (gravityProcess as { pid?: number }).pid;
|
|
977
1093
|
if (gravityPid) {
|
|
978
1094
|
await devLock.registerChild({
|
|
@@ -1046,7 +1162,7 @@ export const command = createCommand({
|
|
|
1046
1162
|
}
|
|
1047
1163
|
|
|
1048
1164
|
// ================================================================
|
|
1049
|
-
// Step
|
|
1165
|
+
// Step 7: Keyboard shortcuts + wait for shutdown
|
|
1050
1166
|
// ================================================================
|
|
1051
1167
|
|
|
1052
1168
|
if (interactive && process.stdin.isTTY && process.stdout.isTTY) {
|
|
@@ -1069,7 +1185,6 @@ export const command = createCommand({
|
|
|
1069
1185
|
process.stdin.removeListener('data', stdinDataHandler);
|
|
1070
1186
|
stdinDataHandler = null;
|
|
1071
1187
|
}
|
|
1072
|
-
shutdownRequested = true;
|
|
1073
1188
|
cleanup(true, 0).catch(() => originalExit(1));
|
|
1074
1189
|
return;
|
|
1075
1190
|
}
|
|
@@ -1109,7 +1224,7 @@ export const command = createCommand({
|
|
|
1109
1224
|
} finally {
|
|
1110
1225
|
/* brute force clean up */
|
|
1111
1226
|
await devLock.release();
|
|
1112
|
-
await killLingeringGravityProcesses(logger);
|
|
1227
|
+
await killLingeringGravityProcesses(logger, project?.projectId);
|
|
1113
1228
|
releaseLockSync(rootDir);
|
|
1114
1229
|
}
|
|
1115
1230
|
},
|