@agentuity/cli 0.0.95 → 0.0.96
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 +54 -0
- package/dist/auth.d.ts +1 -1
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +8 -5
- package/dist/auth.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +190 -27
- package/dist/cli.js.map +1 -1
- package/dist/cmd/build/entry-generator.d.ts +20 -0
- package/dist/cmd/build/entry-generator.d.ts.map +1 -0
- package/dist/cmd/build/entry-generator.js +366 -0
- package/dist/cmd/build/entry-generator.js.map +1 -0
- package/dist/cmd/build/index.d.ts.map +1 -1
- package/dist/cmd/build/index.js +5 -23
- package/dist/cmd/build/index.js.map +1 -1
- package/dist/cmd/build/vite/agent-discovery.d.ts +33 -0
- package/dist/cmd/build/vite/agent-discovery.d.ts.map +1 -0
- package/dist/cmd/build/vite/agent-discovery.js +297 -0
- package/dist/cmd/build/vite/agent-discovery.js.map +1 -0
- package/dist/cmd/build/vite/browser-env-plugin.d.ts +9 -0
- package/dist/cmd/build/vite/browser-env-plugin.d.ts.map +1 -0
- package/dist/cmd/build/vite/browser-env-plugin.js +28 -0
- package/dist/cmd/build/vite/browser-env-plugin.js.map +1 -0
- package/dist/cmd/build/vite/bun-dev-server.d.ts +29 -0
- package/dist/cmd/build/vite/bun-dev-server.d.ts.map +1 -0
- package/dist/cmd/build/vite/bun-dev-server.js +54 -0
- package/dist/cmd/build/vite/bun-dev-server.js.map +1 -0
- package/dist/cmd/build/vite/config-loader.d.ts +23 -0
- package/dist/cmd/build/vite/config-loader.d.ts.map +1 -0
- package/dist/cmd/build/vite/config-loader.js +50 -0
- package/dist/cmd/build/vite/config-loader.js.map +1 -0
- package/dist/cmd/build/vite/index.d.ts +26 -0
- package/dist/cmd/build/vite/index.d.ts.map +1 -0
- package/dist/cmd/build/vite/index.js +127 -0
- package/dist/cmd/build/vite/index.js.map +1 -0
- package/dist/cmd/build/vite/lifecycle-generator.d.ts +11 -0
- package/dist/cmd/build/vite/lifecycle-generator.d.ts.map +1 -0
- package/dist/cmd/build/vite/lifecycle-generator.js +35 -0
- package/dist/cmd/build/vite/lifecycle-generator.js.map +1 -0
- package/dist/cmd/build/vite/metadata-generator.d.ts +32 -0
- package/dist/cmd/build/vite/metadata-generator.d.ts.map +1 -0
- package/dist/cmd/build/vite/metadata-generator.js +489 -0
- package/dist/cmd/build/vite/metadata-generator.js.map +1 -0
- package/dist/cmd/build/vite/patch-plugin.d.ts +21 -0
- package/dist/cmd/build/vite/patch-plugin.d.ts.map +1 -0
- package/dist/cmd/build/vite/patch-plugin.js +70 -0
- package/dist/cmd/build/vite/patch-plugin.js.map +1 -0
- package/dist/cmd/build/vite/registry-generator.d.ts +19 -0
- package/dist/cmd/build/vite/registry-generator.d.ts.map +1 -0
- package/dist/cmd/build/{route-registry.js → vite/registry-generator.js} +126 -48
- package/dist/cmd/build/vite/registry-generator.js.map +1 -0
- package/dist/cmd/build/vite/route-discovery.d.ts +58 -0
- package/dist/cmd/build/vite/route-discovery.d.ts.map +1 -0
- package/dist/cmd/build/vite/route-discovery.js +125 -0
- package/dist/cmd/build/vite/route-discovery.js.map +1 -0
- package/dist/cmd/build/vite/server-bundler.d.ts +16 -0
- package/dist/cmd/build/vite/server-bundler.d.ts.map +1 -0
- package/dist/cmd/build/vite/server-bundler.js +194 -0
- package/dist/cmd/build/vite/server-bundler.js.map +1 -0
- package/dist/cmd/build/vite/vite-asset-server-config.d.ts +19 -0
- package/dist/cmd/build/vite/vite-asset-server-config.d.ts.map +1 -0
- package/dist/cmd/build/vite/vite-asset-server-config.js +105 -0
- package/dist/cmd/build/vite/vite-asset-server-config.js.map +1 -0
- package/dist/cmd/build/vite/vite-asset-server.d.ts +23 -0
- package/dist/cmd/build/vite/vite-asset-server.d.ts.map +1 -0
- package/dist/cmd/build/vite/vite-asset-server.js +40 -0
- package/dist/cmd/build/vite/vite-asset-server.js.map +1 -0
- package/dist/cmd/build/vite/vite-builder.d.ts +44 -0
- package/dist/cmd/build/vite/vite-builder.d.ts.map +1 -0
- package/dist/cmd/build/vite/vite-builder.js +232 -0
- package/dist/cmd/build/vite/vite-builder.js.map +1 -0
- package/dist/cmd/build/vite/workbench-generator.d.ts +10 -0
- package/dist/cmd/build/vite/workbench-generator.d.ts.map +1 -0
- package/dist/cmd/build/vite/workbench-generator.js +135 -0
- package/dist/cmd/build/vite/workbench-generator.js.map +1 -0
- package/dist/cmd/build/vite-bundler.d.ts +23 -0
- package/dist/cmd/build/vite-bundler.d.ts.map +1 -0
- package/dist/cmd/build/vite-bundler.js +79 -0
- package/dist/cmd/build/vite-bundler.js.map +1 -0
- package/dist/cmd/cloud/agent/get.d.ts.map +1 -1
- package/dist/cmd/cloud/agent/get.js +1 -0
- package/dist/cmd/cloud/agent/get.js.map +1 -1
- package/dist/cmd/cloud/agent/list.d.ts.map +1 -1
- package/dist/cmd/cloud/agent/list.js +1 -0
- package/dist/cmd/cloud/agent/list.js.map +1 -1
- package/dist/cmd/cloud/db/get.d.ts.map +1 -1
- package/dist/cmd/cloud/db/get.js +1 -0
- package/dist/cmd/cloud/db/get.js.map +1 -1
- package/dist/cmd/cloud/db/list.d.ts.map +1 -1
- package/dist/cmd/cloud/db/list.js +1 -0
- package/dist/cmd/cloud/db/list.js.map +1 -1
- package/dist/cmd/cloud/deploy.d.ts.map +1 -1
- package/dist/cmd/cloud/deploy.js +152 -128
- package/dist/cmd/cloud/deploy.js.map +1 -1
- package/dist/cmd/cloud/deployment/list.d.ts.map +1 -1
- package/dist/cmd/cloud/deployment/list.js +4 -0
- package/dist/cmd/cloud/deployment/list.js.map +1 -1
- package/dist/cmd/cloud/env/list.d.ts.map +1 -1
- package/dist/cmd/cloud/env/list.js +1 -0
- package/dist/cmd/cloud/env/list.js.map +1 -1
- package/dist/cmd/cloud/keyvalue/get.d.ts.map +1 -1
- package/dist/cmd/cloud/keyvalue/get.js +1 -0
- package/dist/cmd/cloud/keyvalue/get.js.map +1 -1
- package/dist/cmd/cloud/keyvalue/keys.d.ts.map +1 -1
- package/dist/cmd/cloud/keyvalue/keys.js +1 -0
- package/dist/cmd/cloud/keyvalue/keys.js.map +1 -1
- package/dist/cmd/cloud/keyvalue/list-namespaces.d.ts.map +1 -1
- package/dist/cmd/cloud/keyvalue/list-namespaces.js +1 -0
- package/dist/cmd/cloud/keyvalue/list-namespaces.js.map +1 -1
- package/dist/cmd/cloud/keyvalue/stats.d.ts.map +1 -1
- package/dist/cmd/cloud/keyvalue/stats.js +1 -0
- package/dist/cmd/cloud/keyvalue/stats.js.map +1 -1
- package/dist/cmd/cloud/secret/list.d.ts.map +1 -1
- package/dist/cmd/cloud/secret/list.js +1 -0
- package/dist/cmd/cloud/secret/list.js.map +1 -1
- package/dist/cmd/cloud/session/list.d.ts.map +1 -1
- package/dist/cmd/cloud/session/list.js +4 -0
- package/dist/cmd/cloud/session/list.js.map +1 -1
- package/dist/cmd/cloud/storage/get.d.ts.map +1 -1
- package/dist/cmd/cloud/storage/get.js +1 -0
- package/dist/cmd/cloud/storage/get.js.map +1 -1
- package/dist/cmd/cloud/storage/list.d.ts.map +1 -1
- package/dist/cmd/cloud/storage/list.js +3 -0
- package/dist/cmd/cloud/storage/list.js.map +1 -1
- package/dist/cmd/cloud/stream/get.d.ts.map +1 -1
- package/dist/cmd/cloud/stream/get.js +1 -0
- package/dist/cmd/cloud/stream/get.js.map +1 -1
- package/dist/cmd/cloud/stream/list.d.ts.map +1 -1
- package/dist/cmd/cloud/stream/list.js +1 -0
- package/dist/cmd/cloud/stream/list.js.map +1 -1
- package/dist/cmd/cloud/vector/get.d.ts.map +1 -1
- package/dist/cmd/cloud/vector/get.js +1 -0
- package/dist/cmd/cloud/vector/get.js.map +1 -1
- package/dist/cmd/cloud/vector/search.d.ts.map +1 -1
- package/dist/cmd/cloud/vector/search.js +1 -0
- package/dist/cmd/cloud/vector/search.js.map +1 -1
- package/dist/cmd/dev/index.d.ts.map +1 -1
- package/dist/cmd/dev/index.js +289 -758
- package/dist/cmd/dev/index.js.map +1 -1
- package/dist/cmd/dev/sync.d.ts +1 -1
- package/dist/cmd/dev/sync.d.ts.map +1 -1
- package/dist/cmd/dev/sync.js +3 -0
- package/dist/cmd/dev/sync.js.map +1 -1
- package/dist/cmd/profile/show.d.ts.map +1 -1
- package/dist/cmd/profile/show.js +3 -4
- package/dist/cmd/profile/show.js.map +1 -1
- package/dist/cmd/project/create.d.ts.map +1 -1
- package/dist/cmd/project/create.js +3 -4
- package/dist/cmd/project/create.js.map +1 -1
- package/dist/cmd/project/list.d.ts.map +1 -1
- package/dist/cmd/project/list.js +1 -0
- package/dist/cmd/project/list.js.map +1 -1
- package/dist/cmd/project/show.d.ts.map +1 -1
- package/dist/cmd/project/show.js +1 -0
- package/dist/cmd/project/show.js.map +1 -1
- package/dist/cmd/upgrade/index.d.ts.map +1 -1
- package/dist/cmd/upgrade/index.js +5 -3
- package/dist/cmd/upgrade/index.js.map +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +29 -11
- package/dist/config.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/runtime-bootstrap.d.ts +3 -2
- package/dist/runtime-bootstrap.d.ts.map +1 -1
- package/dist/runtime-bootstrap.js +7 -2
- package/dist/runtime-bootstrap.js.map +1 -1
- package/dist/schemas/deploy.d.ts +1 -1
- package/dist/types.d.ts +40 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utils/bun-version-checker.d.ts +11 -0
- package/dist/utils/bun-version-checker.d.ts.map +1 -0
- package/dist/utils/bun-version-checker.js +56 -0
- package/dist/utils/bun-version-checker.js.map +1 -0
- package/dist/version-check.d.ts.map +1 -1
- package/dist/version-check.js +5 -2
- package/dist/version-check.js.map +1 -1
- package/package.json +10 -3
- package/src/auth.ts +9 -5
- package/src/cli.ts +228 -29
- package/src/cmd/build/entry-generator.ts +404 -0
- package/src/cmd/build/index.ts +7 -28
- package/src/cmd/build/vite/agent-discovery.ts +467 -0
- package/src/cmd/build/vite/browser-env-plugin.ts +34 -0
- package/src/cmd/build/vite/bun-dev-server.ts +78 -0
- package/src/cmd/build/vite/config-loader.ts +70 -0
- package/src/cmd/build/vite/index.ts +166 -0
- package/src/cmd/build/vite/lifecycle-generator.ts +43 -0
- package/src/cmd/build/vite/metadata-generator.ts +602 -0
- package/src/cmd/build/vite/patch-plugin.ts +88 -0
- package/src/cmd/build/vite/registry-generator.ts +288 -0
- package/src/cmd/build/vite/route-discovery.ts +186 -0
- package/src/cmd/build/vite/server-bundler.ts +258 -0
- package/src/cmd/build/vite/vite-asset-server-config.ts +134 -0
- package/src/cmd/build/vite/vite-asset-server.ts +63 -0
- package/src/cmd/build/vite/vite-builder.ts +284 -0
- package/src/cmd/build/vite/workbench-generator.ts +152 -0
- package/src/cmd/build/vite-bundler.ts +110 -0
- package/src/cmd/cloud/agent/get.ts +2 -0
- package/src/cmd/cloud/agent/list.ts +1 -0
- package/src/cmd/cloud/db/get.ts +1 -0
- package/src/cmd/cloud/db/list.ts +1 -0
- package/src/cmd/cloud/deploy.ts +175 -144
- package/src/cmd/cloud/deployment/list.ts +4 -0
- package/src/cmd/cloud/env/list.ts +1 -0
- package/src/cmd/cloud/keyvalue/get.ts +1 -0
- package/src/cmd/cloud/keyvalue/keys.ts +1 -0
- package/src/cmd/cloud/keyvalue/list-namespaces.ts +1 -0
- package/src/cmd/cloud/keyvalue/stats.ts +2 -0
- package/src/cmd/cloud/secret/list.ts +1 -0
- package/src/cmd/cloud/session/list.ts +4 -0
- package/src/cmd/cloud/storage/get.ts +1 -0
- package/src/cmd/cloud/storage/list.ts +4 -0
- package/src/cmd/cloud/stream/get.ts +1 -0
- package/src/cmd/cloud/stream/list.ts +1 -0
- package/src/cmd/cloud/vector/get.ts +1 -0
- package/src/cmd/cloud/vector/search.ts +1 -0
- package/src/cmd/dev/index.ts +319 -921
- package/src/cmd/dev/sync.ts +5 -1
- package/src/cmd/profile/show.ts +3 -4
- package/src/cmd/project/create.ts +3 -4
- package/src/cmd/project/list.ts +1 -0
- package/src/cmd/project/show.ts +1 -0
- package/src/cmd/upgrade/index.ts +6 -3
- package/src/config.ts +31 -11
- package/src/index.ts +2 -0
- package/src/runtime-bootstrap.ts +8 -2
- package/src/types.ts +48 -1
- package/src/utils/bun-version-checker.ts +70 -0
- package/src/version-check.ts +6 -2
- package/dist/cmd/build/bundler.d.ts +0 -28
- package/dist/cmd/build/bundler.d.ts.map +0 -1
- package/dist/cmd/build/bundler.js +0 -800
- package/dist/cmd/build/bundler.js.map +0 -1
- package/dist/cmd/build/config-loader.d.ts +0 -16
- package/dist/cmd/build/config-loader.d.ts.map +0 -1
- package/dist/cmd/build/config-loader.js +0 -227
- package/dist/cmd/build/config-loader.js.map +0 -1
- package/dist/cmd/build/file.d.ts +0 -2
- package/dist/cmd/build/file.d.ts.map +0 -1
- package/dist/cmd/build/file.js +0 -10
- package/dist/cmd/build/file.js.map +0 -1
- package/dist/cmd/build/fix-duplicate-exports.d.ts +0 -2
- package/dist/cmd/build/fix-duplicate-exports.d.ts.map +0 -1
- package/dist/cmd/build/fix-duplicate-exports.js +0 -170
- package/dist/cmd/build/fix-duplicate-exports.js.map +0 -1
- package/dist/cmd/build/plugin.d.ts +0 -6
- package/dist/cmd/build/plugin.d.ts.map +0 -1
- package/dist/cmd/build/plugin.js +0 -645
- package/dist/cmd/build/plugin.js.map +0 -1
- package/dist/cmd/build/route-discovery.d.ts +0 -54
- package/dist/cmd/build/route-discovery.d.ts.map +0 -1
- package/dist/cmd/build/route-discovery.js +0 -148
- package/dist/cmd/build/route-discovery.js.map +0 -1
- package/dist/cmd/build/route-registry.d.ts +0 -38
- package/dist/cmd/build/route-registry.d.ts.map +0 -1
- package/dist/cmd/build/route-registry.js.map +0 -1
- package/src/cmd/build/bundler.ts +0 -965
- package/src/cmd/build/config-loader.ts +0 -268
- package/src/cmd/build/file.ts +0 -10
- package/src/cmd/build/fix-duplicate-exports.ts +0 -207
- package/src/cmd/build/plugin.ts +0 -782
- package/src/cmd/build/route-discovery.ts +0 -202
- package/src/cmd/build/route-registry.ts +0 -222
package/dist/cmd/dev/index.js
CHANGED
|
@@ -1,24 +1,35 @@
|
|
|
1
|
-
/** biome-ignore-all lint/style/useTemplate: its easier */
|
|
2
1
|
import { z } from 'zod';
|
|
3
2
|
import { resolve, join } from 'node:path';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { getBuildMetadata } from '../build/plugin';
|
|
7
|
-
import { existsSync, watch, statSync, readdirSync } from 'node:fs';
|
|
8
|
-
import { getDefaultConfigDir, loadProjectSDKKey, saveProjectDir, saveConfig, loadBuildMetadata, } from '../../config';
|
|
3
|
+
import { existsSync } from 'node:fs';
|
|
4
|
+
import { internalExit } from '@agentuity/runtime';
|
|
9
5
|
import { createCommand } from '../../types';
|
|
6
|
+
import { startBunDevServer } from '../build/vite/bun-dev-server';
|
|
10
7
|
import * as tui from '../../tui';
|
|
11
|
-
import {
|
|
8
|
+
import { getCommand } from '../../command-prefix';
|
|
12
9
|
import { generateEndpoint } from './api';
|
|
13
|
-
import { APIClient,
|
|
10
|
+
import { APIClient, getAPIBaseURL, getAppBaseURL, getGravityDevModeURL } from '../../api';
|
|
14
11
|
import { download } from './download';
|
|
15
12
|
import { createDevmodeSyncService } from './sync';
|
|
16
13
|
import { getDevmodeDeploymentId } from '../build/ast';
|
|
17
|
-
import {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
14
|
+
import { getDefaultConfigDir, saveConfig } from '../../config';
|
|
15
|
+
const DEFAULT_PORT = 3500;
|
|
16
|
+
const MIN_PORT = 1024;
|
|
17
|
+
const MAX_PORT = 65535;
|
|
18
|
+
const getDefaultPort = () => {
|
|
19
|
+
const envPort = process.env.PORT;
|
|
20
|
+
if (!envPort) {
|
|
21
|
+
return DEFAULT_PORT;
|
|
22
|
+
}
|
|
23
|
+
const trimmed = envPort.trim();
|
|
24
|
+
if (!trimmed || !/^\d+$/.test(trimmed)) {
|
|
25
|
+
return DEFAULT_PORT;
|
|
26
|
+
}
|
|
27
|
+
const parsed = Number(trimmed);
|
|
28
|
+
if (!Number.isInteger(parsed) || parsed < MIN_PORT || parsed > MAX_PORT) {
|
|
29
|
+
return DEFAULT_PORT;
|
|
30
|
+
}
|
|
31
|
+
return parsed;
|
|
32
|
+
};
|
|
22
33
|
const shouldDisableInteractive = (interactive) => {
|
|
23
34
|
if (!interactive) {
|
|
24
35
|
return true;
|
|
@@ -47,27 +58,20 @@ export const command = createCommand({
|
|
|
47
58
|
.describe('Turn on or off the public url'),
|
|
48
59
|
port: z
|
|
49
60
|
.number()
|
|
50
|
-
.min(
|
|
51
|
-
.max(
|
|
52
|
-
.default(
|
|
53
|
-
.describe('The TCP port to start the dev
|
|
54
|
-
watch: z
|
|
55
|
-
.array(z.string())
|
|
56
|
-
.optional()
|
|
57
|
-
.describe('Additional paths to watch for changes (e.g., --watch ../packages/workbench/dist)'),
|
|
61
|
+
.min(MIN_PORT)
|
|
62
|
+
.max(MAX_PORT)
|
|
63
|
+
.default(getDefaultPort())
|
|
64
|
+
.describe('The TCP port to start the dev server (also reads from PORT env)'),
|
|
58
65
|
}),
|
|
59
66
|
},
|
|
60
67
|
optional: { auth: 'Continue without an account (local only)', project: true },
|
|
61
68
|
async handler(ctx) {
|
|
62
|
-
const { opts, logger,
|
|
69
|
+
const { opts, logger, project, projectDir, auth } = ctx;
|
|
63
70
|
let { config } = ctx;
|
|
64
|
-
|
|
65
|
-
const useMockService = process.env.DEVMODE_SYNC_SERVICE_MOCK === 'true';
|
|
66
|
-
const apiClient = new APIClient(getAPIBaseURL(config), logger, config);
|
|
67
|
-
const syncService = createDevmodeSyncService({ logger, apiClient, mock: useMockService });
|
|
68
|
-
const rootDir = projectDir;
|
|
71
|
+
const rootDir = resolve(projectDir);
|
|
69
72
|
const appTs = join(rootDir, 'app.ts');
|
|
70
73
|
const srcDir = join(rootDir, 'src');
|
|
74
|
+
// Verify required files exist
|
|
71
75
|
const mustHaves = [join(rootDir, 'package.json'), appTs, srcDir];
|
|
72
76
|
const missing = [];
|
|
73
77
|
const interactive = !shouldDisableInteractive(opts.interactive);
|
|
@@ -81,17 +85,22 @@ export const command = createCommand({
|
|
|
81
85
|
for (const filename of missing) {
|
|
82
86
|
tui.bullet(`Missing ${filename}`);
|
|
83
87
|
}
|
|
84
|
-
|
|
88
|
+
internalExit(1);
|
|
85
89
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
90
|
+
// Setup devmode and gravity (if using public URL)
|
|
91
|
+
const useMockService = process.env.DEVMODE_SYNC_SERVICE_MOCK === 'true';
|
|
92
|
+
const apiClient = auth ? new APIClient(getAPIBaseURL(config), logger, config) : null;
|
|
93
|
+
createDevmodeSyncService({
|
|
94
|
+
logger,
|
|
95
|
+
apiClient,
|
|
96
|
+
mock: useMockService,
|
|
97
|
+
});
|
|
89
98
|
let devmode;
|
|
90
99
|
let gravityBin;
|
|
91
100
|
let gravityURL;
|
|
92
101
|
let appURL;
|
|
93
102
|
if (auth && project && opts.public) {
|
|
94
|
-
// Generate devmode endpoint
|
|
103
|
+
// Generate devmode endpoint for public URL
|
|
95
104
|
const endpoint = await tui.spinner({
|
|
96
105
|
message: 'Connecting to Gravity',
|
|
97
106
|
callback: () => {
|
|
@@ -108,11 +117,7 @@ export const command = createCommand({
|
|
|
108
117
|
devmode = endpoint;
|
|
109
118
|
gravityURL = getGravityDevModeURL(project.region, config);
|
|
110
119
|
appURL = `${getAppBaseURL(config)}/r/${project.projectId}`;
|
|
111
|
-
|
|
112
|
-
}
|
|
113
|
-
logger.debug('Getting devmode deployment id for projectId: %s, endpointId: %s', project?.projectId, devmode?.id);
|
|
114
|
-
const deploymentId = getDevmodeDeploymentId(project?.projectId ?? '', devmode?.id ?? '');
|
|
115
|
-
if (devmode && opts.public) {
|
|
120
|
+
// Download gravity client
|
|
116
121
|
const configDir = getDefaultConfigDir();
|
|
117
122
|
const gravityDir = join(configDir, 'gravity');
|
|
118
123
|
let mustCheck = true;
|
|
@@ -136,15 +141,21 @@ export const command = createCommand({
|
|
|
136
141
|
config = _config;
|
|
137
142
|
}
|
|
138
143
|
}
|
|
139
|
-
|
|
140
|
-
const
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
144
|
+
// Get workbench info from config (new Vite approach)
|
|
145
|
+
const { loadAgentuityConfig, getWorkbenchConfig } = await import('../build/vite/config-loader');
|
|
146
|
+
const agentuityConfig = await loadAgentuityConfig(rootDir, ctx.logger);
|
|
147
|
+
const workbenchConfigData = getWorkbenchConfig(agentuityConfig, true); // dev mode
|
|
148
|
+
const workbench = {
|
|
149
|
+
hasWorkbench: workbenchConfigData.enabled,
|
|
150
|
+
config: workbenchConfigData.enabled
|
|
151
|
+
? { route: workbenchConfigData.route, headers: workbenchConfigData.headers }
|
|
152
|
+
: null,
|
|
153
|
+
};
|
|
154
|
+
const deploymentId = getDevmodeDeploymentId(project?.projectId ?? '', devmode?.id ?? '');
|
|
155
|
+
// Calculate URLs for banner
|
|
145
156
|
const padding = 12;
|
|
146
|
-
const workbenchUrl = auth &&
|
|
147
|
-
? `${getAppBaseURL(config)}/
|
|
157
|
+
const workbenchUrl = auth && project?.projectId
|
|
158
|
+
? `${getAppBaseURL(config)}/w/${project.projectId}`
|
|
148
159
|
: `http://127.0.0.1:${opts.port}${workbench.config?.route ?? '/workbench'}`;
|
|
149
160
|
const devmodebody = tui.muted(tui.padRight('Local:', padding)) +
|
|
150
161
|
tui.link(`http://127.0.0.1:${opts.port}`) +
|
|
@@ -158,761 +169,281 @@ export const command = createCommand({
|
|
|
158
169
|
tui.muted(tui.padRight('Dashboard:', padding)) +
|
|
159
170
|
(appURL ? tui.link(appURL) : tui.warn('Disabled')) +
|
|
160
171
|
'\n' +
|
|
161
|
-
(
|
|
172
|
+
(interactive
|
|
162
173
|
? '\n' + tui.muted('Press ') + tui.bold('h') + tui.muted(' for keyboard shortcuts')
|
|
163
174
|
: '');
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
centerTitle: false,
|
|
170
|
-
});
|
|
171
|
-
}
|
|
172
|
-
showBanner();
|
|
173
|
-
// Load .env file(s) based on config profile (Bun no longer auto-loads .env files)
|
|
174
|
-
const isProduction = process.env.NODE_ENV === 'production' || config?.name !== 'local';
|
|
175
|
-
const envFiles = getEnvFilePaths(rootDir, {
|
|
176
|
-
configName: config?.name,
|
|
177
|
-
isProduction,
|
|
175
|
+
tui.banner('⨺ Agentuity DevMode', devmodebody, {
|
|
176
|
+
padding: 2,
|
|
177
|
+
topSpacer: false,
|
|
178
|
+
bottomSpacer: false,
|
|
179
|
+
centerTitle: false,
|
|
178
180
|
});
|
|
179
|
-
//
|
|
180
|
-
let
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
if (process.env.AGENTUITY_SDK_LOG_LEVEL) {
|
|
201
|
-
env.AGENTUITY_SDK_LOG_LEVEL = process.env.AGENTUITY_SDK_LOG_LEVEL;
|
|
202
|
-
}
|
|
203
|
-
env.AGENTUITY_FORCE_LOCAL_SERVICES = opts.local === true ? 'true' : 'false';
|
|
204
|
-
if (project) {
|
|
205
|
-
env.AGENTUITY_TRANSPORT_URL = serviceUrls.catalyst;
|
|
206
|
-
env.AGENTUITY_CATALYST_URL = serviceUrls.catalyst;
|
|
207
|
-
env.AGENTUITY_VECTOR_URL = serviceUrls.vector;
|
|
208
|
-
env.AGENTUITY_KEYVALUE_URL = serviceUrls.keyvalue;
|
|
209
|
-
env.AGENTUITY_STREAM_URL = serviceUrls.stream;
|
|
210
|
-
env.AGENTUITY_CLOUD_ORG_ID = project.orgId;
|
|
211
|
-
env.AGENTUITY_CLOUD_PROJECT_ID = project.projectId;
|
|
212
|
-
}
|
|
213
|
-
if (!process.stdout.isTTY) {
|
|
214
|
-
env.NO_COLOR = '1';
|
|
215
|
-
}
|
|
216
|
-
const agentuityDir = resolve(rootDir, '.agentuity');
|
|
217
|
-
const appPath = resolve(agentuityDir, 'app.js');
|
|
218
|
-
// Load existing metadata file to use as previousMetadata for sync
|
|
219
|
-
// This prevents reinserting agents/evals that haven't changed
|
|
220
|
-
let previousMetadata;
|
|
221
|
-
try {
|
|
222
|
-
previousMetadata = await loadBuildMetadata(agentuityDir);
|
|
223
|
-
logger.debug('Loaded previous metadata with %d agent(s)', previousMetadata.agents?.length ?? 0);
|
|
224
|
-
}
|
|
225
|
-
catch (_error) {
|
|
226
|
-
// File doesn't exist yet (first run), that's okay
|
|
227
|
-
logger.debug('No previous metadata file found, will treat all agents/evals as new');
|
|
228
|
-
previousMetadata = undefined;
|
|
229
|
-
}
|
|
230
|
-
// Watch directories instead of files to survive atomic replacements (sed -i, cp)
|
|
231
|
-
const watches = [rootDir];
|
|
232
|
-
// Add additional watch paths from options
|
|
233
|
-
if (opts.watch) {
|
|
234
|
-
for (const watchPath of opts.watch) {
|
|
235
|
-
const resolvedPath = resolve(rootDir, watchPath);
|
|
236
|
-
if (existsSync(resolvedPath)) {
|
|
237
|
-
watches.push(resolvedPath);
|
|
238
|
-
logger.debug('Added additional watch path: %s', resolvedPath);
|
|
239
|
-
}
|
|
240
|
-
else {
|
|
241
|
-
logger.warn('Watch path does not exist: %s', resolvedPath);
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
const watchers = [];
|
|
246
|
-
let failures = 0;
|
|
247
|
-
let running = false;
|
|
248
|
-
let pid = 0;
|
|
249
|
-
let failed = false;
|
|
250
|
-
let devServer;
|
|
251
|
-
let exitPromise;
|
|
252
|
-
let restarting = false;
|
|
253
|
-
let shuttingDownForRestart = false;
|
|
254
|
-
let pendingRestart = false;
|
|
255
|
-
let building = false;
|
|
256
|
-
let buildCompletedAt = 0;
|
|
257
|
-
const BUILD_COOLDOWN_MS = 500; // Ignore file changes for 500ms after build completes
|
|
258
|
-
const templatedDirectories = new Map(); // Track directories that just had templates created
|
|
259
|
-
let metadata;
|
|
260
|
-
let showInitialReadyMessage = true;
|
|
261
|
-
let serverStartTime = 0;
|
|
262
|
-
let gravityClient;
|
|
263
|
-
let initialStartupComplete = false;
|
|
264
|
-
const gravityBinExists = gravityBin ? await Bun.file(gravityBin).exists() : true;
|
|
265
|
-
if (!gravityBinExists) {
|
|
266
|
-
logger.error(`Gravity binary not found at ${gravityBin}, skipping gravity client startup`);
|
|
267
|
-
}
|
|
268
|
-
async function restartGravityClient() {
|
|
269
|
-
if (gravityClient) {
|
|
270
|
-
gravityClient.kill('SIGINT');
|
|
271
|
-
gravityClient.kill();
|
|
272
|
-
}
|
|
273
|
-
if (!devmode || !opts.public) {
|
|
274
|
-
return;
|
|
275
|
-
}
|
|
276
|
-
try {
|
|
277
|
-
gravityClient = Bun.spawn([
|
|
278
|
-
gravityBin,
|
|
279
|
-
'--endpoint-id',
|
|
280
|
-
devmode.id,
|
|
281
|
-
'--port',
|
|
282
|
-
env.PORT,
|
|
283
|
-
'--url',
|
|
284
|
-
gravityURL,
|
|
285
|
-
'--log-level',
|
|
286
|
-
process.env.AGENTUITY_GRAVITY_LOG_LEVEL ?? 'error',
|
|
287
|
-
], {
|
|
288
|
-
cwd: rootDir,
|
|
289
|
-
stdout: 'inherit',
|
|
290
|
-
stderr: 'inherit',
|
|
291
|
-
stdin: 'ignore',
|
|
292
|
-
env: { ...env, AGENTUITY_SDK_KEY: sdkKey },
|
|
293
|
-
});
|
|
294
|
-
const handler = () => {
|
|
295
|
-
gravityClient?.kill('SIGINT');
|
|
296
|
-
};
|
|
297
|
-
process.on('SIGINT', handler);
|
|
298
|
-
gravityClient.exited
|
|
299
|
-
.then(() => {
|
|
300
|
-
logger.debug('gravity client exited');
|
|
301
|
-
})
|
|
302
|
-
.finally(() => {
|
|
303
|
-
process.off('SIGINT', handler);
|
|
304
|
-
});
|
|
305
|
-
}
|
|
306
|
-
catch (err) {
|
|
307
|
-
logger.error('Failed to spawn gravity client: %s', err instanceof Error ? err.message : String(err));
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
// Track restart timestamps to detect restart loops
|
|
311
|
-
const restartTimestamps = [];
|
|
312
|
-
const MAX_RESTARTS = 10;
|
|
313
|
-
const TIME_WINDOW_MS = 10000; // 10 seconds
|
|
314
|
-
function checkRestartThrottle() {
|
|
315
|
-
const now = Date.now();
|
|
316
|
-
restartTimestamps.push(now);
|
|
317
|
-
// Remove timestamps older than the time window
|
|
318
|
-
while (restartTimestamps.length > 0 && now - restartTimestamps[0] > TIME_WINDOW_MS) {
|
|
319
|
-
restartTimestamps.shift();
|
|
320
|
-
}
|
|
321
|
-
// Check if we've exceeded the threshold
|
|
322
|
-
if (restartTimestamps.length >= MAX_RESTARTS) {
|
|
323
|
-
tui.error(`Detected ${MAX_RESTARTS} restarts in ${TIME_WINDOW_MS / 1000} seconds`);
|
|
324
|
-
tui.error('This usually indicates a file watcher loop (e.g., log files in the project root)');
|
|
325
|
-
tui.fatal('Too many rapid restarts, exiting to prevent infinite loop');
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
let lastErrorLineCount = 0;
|
|
329
|
-
let showedRestartMessage = false;
|
|
330
|
-
function clearRestartMessage() {
|
|
331
|
-
if (showedRestartMessage) {
|
|
332
|
-
process.stdout.write('\x1b[1A\x1b[2K');
|
|
333
|
-
showedRestartMessage = false;
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
function failure(msg) {
|
|
337
|
-
failed = true;
|
|
338
|
-
failures++;
|
|
339
|
-
// Exit immediately on initial startup failure
|
|
340
|
-
if (!initialStartupComplete) {
|
|
341
|
-
tui.fatal(msg);
|
|
342
|
-
}
|
|
343
|
-
// During hot reload, show error but don't exit unless too many failures
|
|
344
|
-
if (failures >= 5) {
|
|
345
|
-
tui.error(msg);
|
|
346
|
-
tui.fatal('too many failures, exiting');
|
|
347
|
-
}
|
|
348
|
-
else {
|
|
349
|
-
// Ensure we're on a new line before printing error
|
|
350
|
-
tui.error(msg);
|
|
351
|
-
// Track lines: 1 for "✗ Building..." + 1 for error message
|
|
352
|
-
lastErrorLineCount = 2;
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
function clearLastError() {
|
|
356
|
-
if (lastErrorLineCount > 0) {
|
|
357
|
-
// Move cursor up and clear each line
|
|
358
|
-
for (let i = 0; i < lastErrorLineCount; i++) {
|
|
359
|
-
process.stdout.write('\x1b[1A\x1b[2K');
|
|
360
|
-
}
|
|
361
|
-
lastErrorLineCount = 0;
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
const kill = async () => {
|
|
365
|
-
if (!running || !devServer) {
|
|
366
|
-
logger.trace('kill() called but server not running');
|
|
367
|
-
return;
|
|
368
|
-
}
|
|
369
|
-
logger.trace('Killing dev server (pid: %d)', pid);
|
|
370
|
-
shuttingDownForRestart = true;
|
|
371
|
-
running = false;
|
|
372
|
-
process.kill(pid, 'SIGINT');
|
|
373
|
-
try {
|
|
374
|
-
// Kill the process group (negative PID kills entire group)
|
|
375
|
-
process.kill(-pid, 'SIGTERM');
|
|
376
|
-
logger.trace('Sent SIGTERM to process group');
|
|
377
|
-
}
|
|
378
|
-
catch {
|
|
379
|
-
// Fallback: kill the direct process
|
|
181
|
+
// Restart loop - allows server to restart on file changes
|
|
182
|
+
let shouldRestart = false;
|
|
183
|
+
let viteServer = null;
|
|
184
|
+
let gravityProcess = null;
|
|
185
|
+
const restartServer = () => {
|
|
186
|
+
shouldRestart = true;
|
|
187
|
+
};
|
|
188
|
+
const showWelcome = () => {
|
|
189
|
+
logger.info('DevMode ready 🚀');
|
|
190
|
+
};
|
|
191
|
+
// Make restart function available globally for HMR plugin
|
|
192
|
+
globalThis.__AGENTUITY_RESTART__ = restartServer;
|
|
193
|
+
// Setup signal handlers once before the loop
|
|
194
|
+
const cleanup = async () => {
|
|
195
|
+
tui.info('Shutting down...');
|
|
196
|
+
// Close Vite asset server first
|
|
197
|
+
if (viteServer) {
|
|
198
|
+
await viteServer.close();
|
|
199
|
+
}
|
|
200
|
+
// Kill gravity client with SIGTERM first, then SIGKILL as fallback
|
|
201
|
+
if (gravityProcess) {
|
|
380
202
|
try {
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
203
|
+
gravityProcess.kill('SIGTERM');
|
|
204
|
+
// Give it a moment to gracefully shutdown
|
|
205
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
206
|
+
if (gravityProcess.exitCode === null) {
|
|
207
|
+
gravityProcess.kill('SIGKILL');
|
|
384
208
|
}
|
|
385
209
|
}
|
|
386
|
-
catch {
|
|
387
|
-
|
|
388
|
-
logger.trace('Process already dead');
|
|
210
|
+
catch (err) {
|
|
211
|
+
logger.debug('Error killing gravity process: %s', err);
|
|
389
212
|
}
|
|
390
213
|
}
|
|
391
|
-
|
|
392
|
-
if (exitPromise) {
|
|
393
|
-
logger.trace('Waiting for dev server to exit...');
|
|
394
|
-
await exitPromise;
|
|
395
|
-
logger.trace('Dev server exited');
|
|
396
|
-
}
|
|
397
|
-
devServer = undefined;
|
|
398
|
-
exitPromise = undefined;
|
|
399
|
-
shuttingDownForRestart = false;
|
|
400
|
-
};
|
|
401
|
-
// Handle signals to ensure entire process tree is killed
|
|
402
|
-
const cleanup = (exitCode = 0) => {
|
|
403
|
-
logger.trace('cleanup() called with exitCode=%d', exitCode);
|
|
404
|
-
if (gravityClient) {
|
|
405
|
-
logger.debug('calling kill on gravity client with pid: %d', gravityClient.pid);
|
|
406
|
-
gravityClient.kill('SIGINT');
|
|
407
|
-
gravityClient = undefined;
|
|
408
|
-
}
|
|
409
|
-
if (pid && running) {
|
|
410
|
-
kill();
|
|
411
|
-
}
|
|
412
|
-
for (const watcher of watchers) {
|
|
413
|
-
watcher.close();
|
|
414
|
-
}
|
|
415
|
-
watchers.length = 0;
|
|
416
|
-
process.exit(exitCode);
|
|
214
|
+
internalExit(0);
|
|
417
215
|
};
|
|
418
216
|
process.on('SIGINT', cleanup);
|
|
419
217
|
process.on('SIGTERM', cleanup);
|
|
420
|
-
|
|
218
|
+
// Ensure gravity client is always killed on exit (even if cleanup is bypassed)
|
|
219
|
+
// Use SIGKILL for immediate termination since the process is already exiting
|
|
421
220
|
process.on('exit', () => {
|
|
422
|
-
|
|
423
|
-
if (gravityClient) {
|
|
221
|
+
if (gravityProcess && gravityProcess.exitCode === null) {
|
|
424
222
|
try {
|
|
425
|
-
|
|
223
|
+
gravityProcess.kill('SIGKILL');
|
|
426
224
|
}
|
|
427
|
-
catch {
|
|
428
|
-
// Ignore errors
|
|
225
|
+
catch (_err) {
|
|
226
|
+
// Ignore errors during exit cleanup
|
|
429
227
|
}
|
|
430
228
|
}
|
|
431
229
|
});
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
230
|
+
while (true) {
|
|
231
|
+
shouldRestart = false;
|
|
232
|
+
try {
|
|
233
|
+
// Generate entry file for Vite before starting dev server
|
|
234
|
+
await tui.spinner({
|
|
235
|
+
message: 'Generating entry file',
|
|
236
|
+
callback: async () => {
|
|
237
|
+
const { generateEntryFile } = await import('../build/entry-generator');
|
|
238
|
+
await generateEntryFile({
|
|
239
|
+
rootDir,
|
|
240
|
+
projectId: project?.projectId ?? '',
|
|
241
|
+
deploymentId,
|
|
242
|
+
logger,
|
|
243
|
+
mode: 'dev',
|
|
244
|
+
});
|
|
245
|
+
},
|
|
246
|
+
clearOnSuccess: true,
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
catch (error) {
|
|
250
|
+
tui.error(`Failed to generate entry file: ${error}`);
|
|
251
|
+
tui.warn('Waiting for file changes to retry...');
|
|
252
|
+
// Wait for next restart trigger
|
|
253
|
+
await new Promise((resolve) => {
|
|
254
|
+
const checkRestart = setInterval(() => {
|
|
255
|
+
if (shouldRestart) {
|
|
256
|
+
clearInterval(checkRestart);
|
|
257
|
+
resolve();
|
|
258
|
+
}
|
|
259
|
+
}, 100);
|
|
260
|
+
});
|
|
261
|
+
continue;
|
|
438
262
|
}
|
|
439
|
-
logger.trace('restart() called, restarting=%s, running=%s', restarting, running);
|
|
440
|
-
restarting = true;
|
|
441
|
-
pendingRestart = false;
|
|
442
|
-
failed = false;
|
|
443
263
|
try {
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
clearOnSuccess: true,
|
|
493
|
-
truncate: false,
|
|
494
|
-
maxLinesOutput: 2,
|
|
495
|
-
maxLinesOnFailure: 15,
|
|
496
|
-
});
|
|
497
|
-
if (tscExitCode !== 0) {
|
|
498
|
-
logger.trace('tsc failed with exit code %d', tscExitCode);
|
|
499
|
-
failure('Type check failed');
|
|
500
|
-
return;
|
|
501
|
-
}
|
|
502
|
-
logger.trace('tsc completed successfully');
|
|
503
|
-
await restartGravityClient();
|
|
504
|
-
},
|
|
264
|
+
// Start Bun dev server (with Vite asset server for HMR)
|
|
265
|
+
const result = await startBunDevServer({
|
|
266
|
+
rootDir,
|
|
267
|
+
port: opts.port,
|
|
268
|
+
projectId: project?.projectId,
|
|
269
|
+
orgId: project?.orgId,
|
|
270
|
+
deploymentId,
|
|
271
|
+
logger,
|
|
272
|
+
});
|
|
273
|
+
viteServer = result.viteAssetServer.server;
|
|
274
|
+
// Note: Bun server runs in-process, no separate app process needed
|
|
275
|
+
// Wait for app.ts to finish loading (Vite is ready but app may still be initializing)
|
|
276
|
+
// Give it 2 seconds to ensure app initialization completes
|
|
277
|
+
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
278
|
+
}
|
|
279
|
+
catch (error) {
|
|
280
|
+
tui.error(`Failed to start dev server: ${error}`);
|
|
281
|
+
tui.warn('Waiting for file changes to retry...');
|
|
282
|
+
// Wait for next restart trigger
|
|
283
|
+
await new Promise((resolve) => {
|
|
284
|
+
const checkRestart = setInterval(() => {
|
|
285
|
+
if (shouldRestart) {
|
|
286
|
+
clearInterval(checkRestart);
|
|
287
|
+
resolve();
|
|
288
|
+
}
|
|
289
|
+
}, 100);
|
|
290
|
+
});
|
|
291
|
+
continue;
|
|
292
|
+
}
|
|
293
|
+
try {
|
|
294
|
+
// Start gravity client if we have devmode
|
|
295
|
+
if (gravityBin && gravityURL && devmode) {
|
|
296
|
+
logger.trace('Starting gravity client: %s', gravityBin);
|
|
297
|
+
gravityProcess = Bun.spawn([
|
|
298
|
+
gravityBin,
|
|
299
|
+
'--endpoint-id',
|
|
300
|
+
devmode.id,
|
|
301
|
+
'--port',
|
|
302
|
+
opts.port.toString(),
|
|
303
|
+
'--url',
|
|
304
|
+
gravityURL,
|
|
305
|
+
'--log-level',
|
|
306
|
+
process.env.AGENTUITY_GRAVITY_LOG_LEVEL ?? 'error',
|
|
307
|
+
], {
|
|
308
|
+
cwd: rootDir,
|
|
309
|
+
stdout: 'pipe',
|
|
310
|
+
stderr: 'pipe',
|
|
311
|
+
detached: false, // Ensure gravity dies with parent process
|
|
505
312
|
});
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
failure(err);
|
|
515
|
-
return;
|
|
313
|
+
// Log gravity output
|
|
314
|
+
(async () => {
|
|
315
|
+
try {
|
|
316
|
+
if (gravityProcess?.stdout) {
|
|
317
|
+
for await (const chunk of gravityProcess.stdout) {
|
|
318
|
+
const text = new TextDecoder().decode(chunk);
|
|
319
|
+
logger.debug('[gravity] %s', text.trim());
|
|
320
|
+
}
|
|
516
321
|
}
|
|
517
322
|
}
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
}
|
|
529
|
-
// Reset failure counter on successful build
|
|
530
|
-
failures = 0;
|
|
531
|
-
logger.trace('Checking if app file exists: %s', appPath);
|
|
532
|
-
if (!existsSync(appPath)) {
|
|
533
|
-
logger.trace('App file not found: %s', appPath);
|
|
534
|
-
failure(`App file not found: ${appPath}`);
|
|
535
|
-
return;
|
|
536
|
-
}
|
|
537
|
-
logger.trace('App file exists, getting build metadata...');
|
|
538
|
-
metadata = getBuildMetadata();
|
|
539
|
-
logger.trace('Build metadata retrieved');
|
|
540
|
-
// Sync agents and evals to API if in devmode with auth
|
|
541
|
-
if (auth && project && apiClient) {
|
|
542
|
-
try {
|
|
543
|
-
logger.debug('Loading build metadata for sync...');
|
|
544
|
-
const currentMetadata = await loadBuildMetadata(agentuityDir);
|
|
545
|
-
logger.debug('Found %d agent(s) and %d route(s) in metadata', currentMetadata.agents?.length ?? 0, currentMetadata.routes?.length ?? 0);
|
|
546
|
-
if (currentMetadata.agents) {
|
|
547
|
-
for (const agent of currentMetadata.agents) {
|
|
548
|
-
logger.debug('Agent: id=%s, name=%s, version=%s, evals=%d', agent.id, agent.name, agent.version, agent.evals?.length ?? 0);
|
|
549
|
-
if (agent.evals) {
|
|
550
|
-
for (const evalItem of agent.evals) {
|
|
551
|
-
logger.debug(' Eval: id=%s, name=%s, version=%s', evalItem.id, evalItem.name, evalItem.version);
|
|
552
|
-
}
|
|
323
|
+
catch (err) {
|
|
324
|
+
logger.error('Error reading gravity stdout: %s', err);
|
|
325
|
+
}
|
|
326
|
+
})();
|
|
327
|
+
(async () => {
|
|
328
|
+
try {
|
|
329
|
+
if (gravityProcess?.stderr) {
|
|
330
|
+
for await (const chunk of gravityProcess.stderr) {
|
|
331
|
+
const text = new TextDecoder().decode(chunk);
|
|
332
|
+
logger.warn('[gravity] %s', text.trim());
|
|
553
333
|
}
|
|
554
334
|
}
|
|
555
335
|
}
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
previousMetadata = currentMetadata;
|
|
559
|
-
logger.debug('Sync completed successfully');
|
|
560
|
-
}
|
|
561
|
-
catch (error) {
|
|
562
|
-
logger.error('Failed to sync agents/evals: %s', error);
|
|
563
|
-
if (error instanceof Error) {
|
|
564
|
-
logger.error('Error stack: %s', error.stack);
|
|
336
|
+
catch (err) {
|
|
337
|
+
logger.error('Error reading gravity stderr: %s', err);
|
|
565
338
|
}
|
|
566
|
-
|
|
567
|
-
|
|
339
|
+
})();
|
|
340
|
+
logger.debug('Gravity client started');
|
|
568
341
|
}
|
|
569
|
-
|
|
570
|
-
|
|
342
|
+
// Sync service integration
|
|
343
|
+
// TODO: Integrate sync service with Vite's buildStart/buildEnd hooks
|
|
344
|
+
// The sync service will be called when metadata changes are detected
|
|
345
|
+
// Handle keyboard shortcuts
|
|
346
|
+
if (interactive && process.stdin.isTTY && process.stdout.isTTY) {
|
|
347
|
+
process.stdin.setRawMode(true);
|
|
348
|
+
process.stdin.resume();
|
|
349
|
+
process.stdin.setEncoding('utf8');
|
|
350
|
+
const showHelp = () => {
|
|
351
|
+
console.log('\n' + tui.bold('Keyboard Shortcuts:'));
|
|
352
|
+
console.log(tui.muted(' h') + ' - show this help');
|
|
353
|
+
console.log(tui.muted(' c') + ' - clear console');
|
|
354
|
+
console.log(tui.muted(' q') + ' - quit\n');
|
|
355
|
+
};
|
|
356
|
+
process.stdin.on('data', (data) => {
|
|
357
|
+
const key = data.toString();
|
|
358
|
+
// Handle Ctrl+C
|
|
359
|
+
if (key === '\u0003') {
|
|
360
|
+
internalExit(0);
|
|
361
|
+
}
|
|
362
|
+
switch (key) {
|
|
363
|
+
case 'h':
|
|
364
|
+
showHelp();
|
|
365
|
+
break;
|
|
366
|
+
case 'c':
|
|
367
|
+
console.clear();
|
|
368
|
+
tui.banner('⨺ Agentuity DevMode', devmodebody, {
|
|
369
|
+
padding: 2,
|
|
370
|
+
topSpacer: false,
|
|
371
|
+
bottomSpacer: false,
|
|
372
|
+
centerTitle: false,
|
|
373
|
+
});
|
|
374
|
+
break;
|
|
375
|
+
case 'q':
|
|
376
|
+
internalExit(0);
|
|
377
|
+
break;
|
|
378
|
+
default:
|
|
379
|
+
console.log(data);
|
|
380
|
+
break;
|
|
381
|
+
}
|
|
382
|
+
});
|
|
571
383
|
}
|
|
572
|
-
|
|
573
|
-
//
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
env,
|
|
384
|
+
showWelcome();
|
|
385
|
+
// Wait for restart signal
|
|
386
|
+
await new Promise((resolve) => {
|
|
387
|
+
const checkRestart = setInterval(() => {
|
|
388
|
+
if (shouldRestart) {
|
|
389
|
+
clearInterval(checkRestart);
|
|
390
|
+
resolve();
|
|
391
|
+
}
|
|
392
|
+
}, 100);
|
|
582
393
|
});
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
serverStartTime = Date.now();
|
|
589
|
-
logger.trace('Dev server started (pid: %d)', pid);
|
|
590
|
-
if (showInitialReadyMessage) {
|
|
591
|
-
showInitialReadyMessage = false;
|
|
592
|
-
logger.info('DevMode ready 🚀');
|
|
593
|
-
logger.trace('Initial ready message logged');
|
|
594
|
-
// Mark initial startup complete immediately to prevent watcher restarts
|
|
595
|
-
initialStartupComplete = true;
|
|
596
|
-
logger.trace('Initial startup complete, file watcher restarts now enabled');
|
|
394
|
+
// Restart triggered - cleanup and loop
|
|
395
|
+
tui.info('Restarting server...');
|
|
396
|
+
// Close Vite asset server
|
|
397
|
+
if (viteServer) {
|
|
398
|
+
await viteServer.close();
|
|
597
399
|
}
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
});
|
|
605
|
-
}, 500);
|
|
606
|
-
logger.trace('Attaching exit handler to dev server process...');
|
|
607
|
-
// Attach non-blocking exit handler
|
|
608
|
-
exitPromise
|
|
609
|
-
.then((exitCode) => {
|
|
610
|
-
const runtime = Date.now() - serverStartTime;
|
|
611
|
-
logger.trace('Dev server exited with code %d (shuttingDownForRestart=%s, runtime=%dms)', exitCode, shuttingDownForRestart, runtime);
|
|
612
|
-
running = false;
|
|
613
|
-
devServer = undefined;
|
|
614
|
-
exitPromise = undefined;
|
|
615
|
-
// If server exited immediately after starting (< 2 seconds), treat as failure and restart
|
|
616
|
-
if (runtime < 2000 && !shuttingDownForRestart) {
|
|
617
|
-
logger.trace('Server exited too quickly, treating as failure and restarting');
|
|
618
|
-
failure('Server exited immediately after starting');
|
|
619
|
-
// Trigger a restart after a short delay
|
|
620
|
-
setTimeout(() => {
|
|
621
|
-
if (!running && !restarting) {
|
|
622
|
-
logger.trace('Triggering restart after quick exit');
|
|
623
|
-
restart();
|
|
624
|
-
}
|
|
625
|
-
}, 100);
|
|
626
|
-
return;
|
|
627
|
-
}
|
|
628
|
-
// Only exit the CLI if this is a clean exit AND not a restart AND server ran for a while
|
|
629
|
-
if (exitCode === 0 && !shuttingDownForRestart && runtime >= 2000) {
|
|
630
|
-
logger.trace('Clean exit, stopping CLI');
|
|
631
|
-
cleanup(exitCode);
|
|
632
|
-
}
|
|
633
|
-
// Non-zero exit codes are treated as restartable failures
|
|
634
|
-
// But if it's exit code 1 (common error exit), also exit the CLI
|
|
635
|
-
if (exitCode === 1 && !shuttingDownForRestart && runtime >= 2000) {
|
|
636
|
-
logger.trace('Server exited with error code 1, stopping CLI');
|
|
637
|
-
cleanup(exitCode);
|
|
638
|
-
}
|
|
639
|
-
})
|
|
640
|
-
.catch((error) => {
|
|
641
|
-
logger.trace('Dev server exit error (shuttingDownForRestart=%s): %s', shuttingDownForRestart, error);
|
|
642
|
-
running = false;
|
|
643
|
-
devServer = undefined;
|
|
644
|
-
exitPromise = undefined;
|
|
645
|
-
if (!shuttingDownForRestart) {
|
|
646
|
-
if (error instanceof Error) {
|
|
647
|
-
failure(`Dev server failed: ${error.message}`);
|
|
648
|
-
}
|
|
649
|
-
else {
|
|
650
|
-
failure('Dev server failed');
|
|
400
|
+
if (gravityProcess) {
|
|
401
|
+
try {
|
|
402
|
+
gravityProcess.kill('SIGTERM');
|
|
403
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
404
|
+
if (gravityProcess.exitCode === null) {
|
|
405
|
+
gravityProcess.kill('SIGKILL');
|
|
651
406
|
}
|
|
652
407
|
}
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
logger.trace('Restart caught error: %s', error);
|
|
657
|
-
if (error instanceof Error) {
|
|
658
|
-
logger.trace('Error message: %s, stack: %s', error.message, error.stack);
|
|
659
|
-
failure(`Dev server failed: ${error.message}`);
|
|
660
|
-
}
|
|
661
|
-
else {
|
|
662
|
-
logger.trace('Non-Error exception: %s', String(error));
|
|
663
|
-
failure('Dev server failed');
|
|
664
|
-
}
|
|
665
|
-
running = false;
|
|
666
|
-
devServer = undefined;
|
|
667
|
-
}
|
|
668
|
-
finally {
|
|
669
|
-
logger.trace('Entering restart() finally block...');
|
|
670
|
-
const hadPendingRestart = pendingRestart;
|
|
671
|
-
restarting = false;
|
|
672
|
-
pendingRestart = false;
|
|
673
|
-
logger.trace('restart() completed, restarting=%s, hadPendingRestart=%s', restarting, hadPendingRestart);
|
|
674
|
-
// If another restart was queued while we were restarting, trigger it now
|
|
675
|
-
if (hadPendingRestart) {
|
|
676
|
-
logger.trace('Triggering queued restart');
|
|
677
|
-
setImmediate(restart);
|
|
408
|
+
catch (err) {
|
|
409
|
+
logger.debug('Error killing gravity process during restart: %s', err);
|
|
410
|
+
}
|
|
678
411
|
}
|
|
412
|
+
// Brief pause before restart
|
|
413
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
679
414
|
}
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
if (canDoInput) {
|
|
687
|
-
logger.trace('Setting up keyboard shortcuts');
|
|
688
|
-
process.stdin.setRawMode(true);
|
|
689
|
-
process.stdin.resume();
|
|
690
|
-
process.stdin.setEncoding('utf8');
|
|
691
|
-
const showHelp = () => {
|
|
692
|
-
console.log('\n' + tui.bold('Keyboard Shortcuts:'));
|
|
693
|
-
console.log(tui.muted(' h') + ' - show this help');
|
|
694
|
-
console.log(tui.muted(' c') + ' - clear console');
|
|
695
|
-
console.log(tui.muted(' r') + ' - restart server');
|
|
696
|
-
console.log(tui.muted(' o') + ' - show routes');
|
|
697
|
-
console.log(tui.muted(' a') + ' - show agents');
|
|
698
|
-
console.log(tui.muted(' q') + ' - quit\n');
|
|
699
|
-
};
|
|
700
|
-
const showRoutes = () => {
|
|
701
|
-
tui.info('API Route Detail');
|
|
702
|
-
tui.table(metadata?.routes ?? [], ['method', 'path', 'filename']);
|
|
703
|
-
};
|
|
704
|
-
const showAgents = () => {
|
|
705
|
-
tui.info('Agent Detail');
|
|
706
|
-
tui.table(metadata?.agents ?? [], ['name', 'filename', 'description']);
|
|
707
|
-
};
|
|
708
|
-
process.stdin.on('data', (data) => {
|
|
709
|
-
const key = data.toString();
|
|
710
|
-
// Handle Ctrl+C
|
|
711
|
-
if (key === '\u0003') {
|
|
712
|
-
cleanup();
|
|
713
|
-
return;
|
|
714
|
-
}
|
|
715
|
-
// Handle other shortcuts
|
|
716
|
-
switch (key) {
|
|
717
|
-
case 'h':
|
|
718
|
-
showHelp();
|
|
719
|
-
break;
|
|
720
|
-
case 'c':
|
|
721
|
-
console.clear();
|
|
722
|
-
showBanner();
|
|
723
|
-
break;
|
|
724
|
-
case 'r':
|
|
725
|
-
tui.info('Manually restarting server...');
|
|
726
|
-
restart();
|
|
727
|
-
break;
|
|
728
|
-
case 'o':
|
|
729
|
-
showRoutes();
|
|
730
|
-
break;
|
|
731
|
-
case 'a':
|
|
732
|
-
showAgents();
|
|
733
|
-
break;
|
|
734
|
-
case 'q':
|
|
735
|
-
tui.info('Shutting down...');
|
|
736
|
-
cleanup();
|
|
737
|
-
break;
|
|
738
|
-
}
|
|
739
|
-
});
|
|
740
|
-
logger.trace('✓ Keyboard shortcuts enabled');
|
|
741
|
-
}
|
|
742
|
-
else {
|
|
743
|
-
if (process.stdin) {
|
|
744
|
-
// still need to monitor stdin in case we are pipeing into another process or file etc
|
|
745
|
-
if (typeof process.stdin.setRawMode === 'function') {
|
|
746
|
-
process.stdin.setRawMode(true);
|
|
415
|
+
catch (error) {
|
|
416
|
+
tui.error(`Error during server operation: ${error}`);
|
|
417
|
+
tui.warn('Waiting for file changes to retry...');
|
|
418
|
+
// Cleanup on error - close Vite asset server
|
|
419
|
+
if (viteServer) {
|
|
420
|
+
await viteServer.close();
|
|
747
421
|
}
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
return;
|
|
755
|
-
}
|
|
756
|
-
});
|
|
757
|
-
}
|
|
758
|
-
logger.trace('❌ Keyboard shortcuts disabled');
|
|
759
|
-
}
|
|
760
|
-
// Patterns to ignore (generated files that change during build)
|
|
761
|
-
const ignorePatterns = [
|
|
762
|
-
/\.generated\.(js|ts|d\.ts)$/,
|
|
763
|
-
/registry\.generated\.ts$/,
|
|
764
|
-
/types\.generated\.d\.ts$/,
|
|
765
|
-
/client\.generated\.js$/,
|
|
766
|
-
/\.tmp$/,
|
|
767
|
-
/\.tsbuildinfo$/,
|
|
768
|
-
/\.agentuity\//,
|
|
769
|
-
// Ignore temporary files created by sed (e.g., sedUprJj0)
|
|
770
|
-
/\/sed[A-Za-z0-9]+$/,
|
|
771
|
-
];
|
|
772
|
-
// Helper to check if a file is a temporary file created by sed
|
|
773
|
-
const isSedTempFile = (filePath) => {
|
|
774
|
-
const basename = filePath.split('/').pop() || '';
|
|
775
|
-
return /^sed[A-Za-z0-9]+$/.test(basename);
|
|
776
|
-
};
|
|
777
|
-
logger.trace('Setting up file watchers for: %s', watches.join(', '));
|
|
778
|
-
for (const watchDir of watches) {
|
|
779
|
-
try {
|
|
780
|
-
logger.trace('Setting up watcher for %s', watchDir);
|
|
781
|
-
const watcher = watch(watchDir, { recursive: true }, (eventType, changedFile) => {
|
|
782
|
-
const absPath = changedFile ? resolve(watchDir, changedFile) : watchDir;
|
|
783
|
-
// Ignore file changes during initial startup to prevent spurious restarts
|
|
784
|
-
if (!initialStartupComplete) {
|
|
785
|
-
logger.trace('File change ignored (initial startup): %s (event: %s, file: %s)', watchDir, eventType, changedFile);
|
|
786
|
-
return;
|
|
787
|
-
}
|
|
788
|
-
// Ignore file changes during active build to prevent loops
|
|
789
|
-
if (building) {
|
|
790
|
-
logger.trace('File change ignored (build in progress): %s (event: %s, file: %s)', watchDir, eventType, changedFile);
|
|
791
|
-
return;
|
|
792
|
-
}
|
|
793
|
-
// Ignore file changes immediately after build completes (cooldown period)
|
|
794
|
-
// This prevents restarts from build output files that are written asynchronously
|
|
795
|
-
if (buildCompletedAt > 0 && Date.now() - buildCompletedAt < BUILD_COOLDOWN_MS) {
|
|
796
|
-
logger.trace('File change ignored (build cooldown): %s (event: %s, file: %s)', watchDir, eventType, changedFile);
|
|
797
|
-
return;
|
|
798
|
-
}
|
|
799
|
-
// Ignore node_modules folder
|
|
800
|
-
if (absPath.includes('node_modules')) {
|
|
801
|
-
logger.trace('File change ignored (node_modules): %s (event: %s, file: %s)', watchDir, eventType, changedFile);
|
|
802
|
-
return;
|
|
803
|
-
}
|
|
804
|
-
// Ignore .git folder
|
|
805
|
-
if (changedFile && (changedFile === '.git' || changedFile.startsWith('.git/'))) {
|
|
806
|
-
logger.trace('File change ignored (.git folder): %s (event: %s, file: %s)', watchDir, eventType, changedFile);
|
|
807
|
-
return;
|
|
808
|
-
}
|
|
809
|
-
// Ignore changes in .agentuity directory (build output)
|
|
810
|
-
// Check both relative path and normalized absolute path
|
|
811
|
-
const isInAgentuityDir = (changedFile &&
|
|
812
|
-
(changedFile === '.agentuity' || changedFile.startsWith('.agentuity/'))) ||
|
|
813
|
-
resolve(absPath).startsWith(agentuityDir);
|
|
814
|
-
if (isInAgentuityDir) {
|
|
815
|
-
logger.trace('File change ignored (.agentuity dir): %s (event: %s, file: %s)', watchDir, eventType, changedFile);
|
|
816
|
-
return;
|
|
817
|
-
}
|
|
818
|
-
// Ignore changes to src/web/public directory (static assets, not code)
|
|
819
|
-
if (changedFile && changedFile === 'src/web/public') {
|
|
820
|
-
logger.trace('File change ignored (static assets dir): %s (event: %s, file: %s)', watchDir, eventType, changedFile);
|
|
821
|
-
return;
|
|
822
|
-
}
|
|
823
|
-
// Check for .tmp file renames that replace watched files (BEFORE ignoring)
|
|
824
|
-
// This handles cases like sed -i.tmp where agent.ts.tmp is renamed to agent.ts
|
|
825
|
-
if (eventType === 'rename' && changedFile && changedFile.endsWith('.tmp')) {
|
|
826
|
-
const targetFile = changedFile.slice(0, -4); // Remove .tmp suffix
|
|
827
|
-
const targetAbsPath = resolve(watchDir, targetFile);
|
|
828
|
-
// Only trigger restart for source files (ts, tsx, js, jsx, etc.)
|
|
829
|
-
const isSourceFile = /\.(ts|tsx|js|jsx|mjs|cjs)$/.test(targetFile);
|
|
830
|
-
// Check if target file exists and is not in ignored directories
|
|
831
|
-
const targetExists = existsSync(targetAbsPath);
|
|
832
|
-
const inNodeModules = targetAbsPath.includes('node_modules');
|
|
833
|
-
const inAgentuityDir = (targetFile &&
|
|
834
|
-
(targetFile === '.agentuity' || targetFile.startsWith('.agentuity/'))) ||
|
|
835
|
-
resolve(targetAbsPath).startsWith(agentuityDir);
|
|
836
|
-
let isDirectory = false;
|
|
837
|
-
if (targetExists) {
|
|
838
|
-
try {
|
|
839
|
-
isDirectory = statSync(targetAbsPath).isDirectory();
|
|
840
|
-
}
|
|
841
|
-
catch (err) {
|
|
842
|
-
logger.trace('Failed to stat target file: %s', err);
|
|
843
|
-
}
|
|
844
|
-
}
|
|
845
|
-
if (isSourceFile &&
|
|
846
|
-
targetExists &&
|
|
847
|
-
!inNodeModules &&
|
|
848
|
-
!inAgentuityDir &&
|
|
849
|
-
!isDirectory) {
|
|
850
|
-
logger.trace('File change detected (temp file rename): %s -> %s', absPath, targetAbsPath);
|
|
851
|
-
restart();
|
|
852
|
-
return;
|
|
853
|
-
}
|
|
854
|
-
}
|
|
855
|
-
// Ignore generated files to prevent restart loops
|
|
856
|
-
if (changedFile) {
|
|
857
|
-
// Check for sed temporary files
|
|
858
|
-
if (isSedTempFile(changedFile)) {
|
|
859
|
-
logger.trace('File change ignored (sed temp file): %s (event: %s, file: %s)', watchDir, eventType, changedFile);
|
|
860
|
-
return;
|
|
861
|
-
}
|
|
862
|
-
// Check other ignore patterns
|
|
863
|
-
for (const pattern of ignorePatterns) {
|
|
864
|
-
if (pattern.test(changedFile)) {
|
|
865
|
-
logger.trace('File change ignored (generated file): %s (event: %s, file: %s)', watchDir, eventType, changedFile);
|
|
866
|
-
return;
|
|
867
|
-
}
|
|
422
|
+
if (gravityProcess) {
|
|
423
|
+
try {
|
|
424
|
+
gravityProcess.kill('SIGTERM');
|
|
425
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
426
|
+
if (gravityProcess.exitCode === null) {
|
|
427
|
+
gravityProcess.kill('SIGKILL');
|
|
868
428
|
}
|
|
869
429
|
}
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
existsSync(absPath) &&
|
|
873
|
-
statSync(absPath).isDirectory() &&
|
|
874
|
-
readdirSync(absPath).length === 0) {
|
|
875
|
-
if (changedFile?.startsWith('src/agent/')) {
|
|
876
|
-
logger.debug('agent directory created: %s', changedFile);
|
|
877
|
-
createAgentTemplates(absPath);
|
|
878
|
-
// Mark this directory as recently templated to avoid immediate rebuild
|
|
879
|
-
templatedDirectories.set(absPath, Date.now());
|
|
880
|
-
// Schedule cleanup of this marker after enough time for file events
|
|
881
|
-
setTimeout(() => templatedDirectories.delete(absPath), 1000);
|
|
882
|
-
// Don't restart - wait for the template files to trigger the rebuild
|
|
883
|
-
return;
|
|
884
|
-
}
|
|
885
|
-
else if (changedFile?.startsWith('src/api/')) {
|
|
886
|
-
logger.debug('api directory created: %s', changedFile);
|
|
887
|
-
createAPITemplates(absPath);
|
|
888
|
-
// Mark this directory as recently templated to avoid immediate rebuild
|
|
889
|
-
templatedDirectories.set(absPath, Date.now());
|
|
890
|
-
// Schedule cleanup of this marker after enough time for file events
|
|
891
|
-
setTimeout(() => templatedDirectories.delete(absPath), 1000);
|
|
892
|
-
// Don't restart - wait for the template files to trigger the rebuild
|
|
893
|
-
return;
|
|
894
|
-
}
|
|
430
|
+
catch (err) {
|
|
431
|
+
logger.debug('Error killing gravity process on error: %s', err);
|
|
895
432
|
}
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
433
|
+
}
|
|
434
|
+
if (viteServer)
|
|
435
|
+
await viteServer.close();
|
|
436
|
+
// Wait for next restart trigger
|
|
437
|
+
await new Promise((resolve) => {
|
|
438
|
+
const checkRestart = setInterval(() => {
|
|
439
|
+
if (shouldRestart) {
|
|
440
|
+
clearInterval(checkRestart);
|
|
441
|
+
resolve();
|
|
901
442
|
}
|
|
902
|
-
}
|
|
903
|
-
logger.trace('File change detected: %s (event: %s, file: %s)', absPath, eventType, changedFile);
|
|
904
|
-
restart();
|
|
443
|
+
}, 100);
|
|
905
444
|
});
|
|
906
|
-
watchers.push(watcher);
|
|
907
|
-
logger.trace('✓ Watcher added for %s', watchDir);
|
|
908
|
-
}
|
|
909
|
-
catch (error) {
|
|
910
|
-
logger.error('Failed to setup watcher for %s: %s', watchDir, error);
|
|
911
445
|
}
|
|
912
446
|
}
|
|
913
|
-
logger.debug('Dev server watching for changes');
|
|
914
|
-
// Keep the handler alive indefinitely
|
|
915
|
-
await new Promise(() => { }).catch(() => cleanup());
|
|
916
447
|
},
|
|
917
448
|
});
|
|
918
449
|
//# sourceMappingURL=index.js.map
|