@agentuity/cli 0.0.42 → 0.0.44
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 +1 -1
- package/README.md +1 -1
- package/bin/cli.ts +7 -5
- package/dist/api.d.ts +3 -3
- package/dist/api.d.ts.map +1 -1
- package/dist/auth.d.ts +10 -2
- package/dist/auth.d.ts.map +1 -1
- package/dist/banner.d.ts.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cmd/auth/api.d.ts +4 -4
- package/dist/cmd/auth/api.d.ts.map +1 -1
- package/dist/cmd/auth/index.d.ts.map +1 -1
- package/dist/cmd/auth/login.d.ts.map +1 -1
- package/dist/cmd/auth/signup.d.ts.map +1 -1
- package/dist/cmd/auth/ssh/add.d.ts +2 -0
- package/dist/cmd/auth/ssh/add.d.ts.map +1 -0
- package/dist/cmd/auth/ssh/api.d.ts +16 -0
- package/dist/cmd/auth/ssh/api.d.ts.map +1 -0
- package/dist/cmd/auth/ssh/delete.d.ts +2 -0
- package/dist/cmd/auth/ssh/delete.d.ts.map +1 -0
- package/dist/cmd/auth/ssh/index.d.ts +3 -0
- package/dist/cmd/auth/ssh/index.d.ts.map +1 -0
- package/dist/cmd/auth/ssh/list.d.ts +2 -0
- package/dist/cmd/auth/ssh/list.d.ts.map +1 -0
- package/dist/cmd/auth/whoami.d.ts +2 -0
- package/dist/cmd/auth/whoami.d.ts.map +1 -0
- package/dist/cmd/bundle/ast.d.ts +14 -3
- package/dist/cmd/bundle/ast.d.ts.map +1 -1
- package/dist/cmd/bundle/ast.test.d.ts +2 -0
- package/dist/cmd/bundle/ast.test.d.ts.map +1 -0
- package/dist/cmd/bundle/bundler.d.ts +6 -1
- package/dist/cmd/bundle/bundler.d.ts.map +1 -1
- package/dist/cmd/bundle/file.d.ts.map +1 -1
- package/dist/cmd/bundle/fix-duplicate-exports.d.ts +2 -0
- package/dist/cmd/bundle/fix-duplicate-exports.d.ts.map +1 -0
- package/dist/cmd/bundle/fix-duplicate-exports.test.d.ts +2 -0
- package/dist/cmd/bundle/fix-duplicate-exports.test.d.ts.map +1 -0
- package/dist/cmd/bundle/index.d.ts +1 -1
- package/dist/cmd/bundle/index.d.ts.map +1 -1
- package/dist/cmd/bundle/plugin.d.ts +2 -0
- package/dist/cmd/bundle/plugin.d.ts.map +1 -1
- package/dist/cmd/cloud/deploy.d.ts.map +1 -0
- package/dist/cmd/cloud/domain.d.ts +17 -0
- package/dist/cmd/cloud/domain.d.ts.map +1 -0
- package/dist/cmd/cloud/index.d.ts.map +1 -0
- package/dist/cmd/cloud/resource/add.d.ts +2 -0
- package/dist/cmd/cloud/resource/add.d.ts.map +1 -0
- package/dist/cmd/cloud/resource/delete.d.ts +2 -0
- package/dist/cmd/cloud/resource/delete.d.ts.map +1 -0
- package/dist/cmd/cloud/resource/index.d.ts +3 -0
- package/dist/cmd/cloud/resource/index.d.ts.map +1 -0
- package/dist/cmd/cloud/resource/list.d.ts +2 -0
- package/dist/cmd/cloud/resource/list.d.ts.map +1 -0
- package/dist/cmd/cloud/scp/download.d.ts +2 -0
- package/dist/cmd/cloud/scp/download.d.ts.map +1 -0
- package/dist/cmd/cloud/scp/index.d.ts +3 -0
- package/dist/cmd/cloud/scp/index.d.ts.map +1 -0
- package/dist/cmd/cloud/scp/upload.d.ts +2 -0
- package/dist/cmd/cloud/scp/upload.d.ts.map +1 -0
- package/dist/cmd/cloud/ssh.d.ts +2 -0
- package/dist/cmd/cloud/ssh.d.ts.map +1 -0
- package/dist/cmd/dev/api.d.ts +18 -0
- package/dist/cmd/dev/api.d.ts.map +1 -0
- package/dist/cmd/dev/download.d.ts +11 -0
- package/dist/cmd/dev/download.d.ts.map +1 -0
- package/dist/cmd/dev/index.d.ts.map +1 -1
- package/dist/cmd/dev/templates.d.ts +3 -0
- package/dist/cmd/dev/templates.d.ts.map +1 -0
- package/dist/cmd/env/delete.d.ts +2 -0
- package/dist/cmd/env/delete.d.ts.map +1 -0
- package/dist/cmd/env/get.d.ts +2 -0
- package/dist/cmd/env/get.d.ts.map +1 -0
- package/dist/cmd/env/import.d.ts +2 -0
- package/dist/cmd/env/import.d.ts.map +1 -0
- package/dist/cmd/env/index.d.ts +2 -0
- package/dist/cmd/env/index.d.ts.map +1 -0
- package/dist/cmd/env/list.d.ts.map +1 -0
- package/dist/cmd/env/pull.d.ts +2 -0
- package/dist/cmd/env/pull.d.ts.map +1 -0
- package/dist/cmd/env/push.d.ts +2 -0
- package/dist/cmd/env/push.d.ts.map +1 -0
- package/dist/cmd/env/set.d.ts +2 -0
- package/dist/cmd/env/set.d.ts.map +1 -0
- package/dist/cmd/profile/show.d.ts.map +1 -1
- package/dist/cmd/project/create.d.ts.map +1 -1
- package/dist/cmd/project/delete.d.ts.map +1 -1
- package/dist/cmd/project/download.d.ts +1 -1
- package/dist/cmd/project/download.d.ts.map +1 -1
- package/dist/cmd/project/list.d.ts.map +1 -1
- package/dist/cmd/project/show.d.ts.map +1 -1
- package/dist/cmd/project/template-flow.d.ts +5 -1
- package/dist/cmd/project/template-flow.d.ts.map +1 -1
- package/dist/cmd/secret/delete.d.ts +2 -0
- package/dist/cmd/secret/delete.d.ts.map +1 -0
- package/dist/cmd/secret/get.d.ts +2 -0
- package/dist/cmd/secret/get.d.ts.map +1 -0
- package/dist/cmd/secret/import.d.ts +2 -0
- package/dist/cmd/secret/import.d.ts.map +1 -0
- package/dist/cmd/secret/index.d.ts +2 -0
- package/dist/cmd/secret/index.d.ts.map +1 -0
- package/dist/cmd/secret/list.d.ts +2 -0
- package/dist/cmd/secret/list.d.ts.map +1 -0
- package/dist/cmd/secret/pull.d.ts +2 -0
- package/dist/cmd/secret/pull.d.ts.map +1 -0
- package/dist/cmd/secret/push.d.ts +2 -0
- package/dist/cmd/secret/push.d.ts.map +1 -0
- package/dist/cmd/secret/set.d.ts +2 -0
- package/dist/cmd/secret/set.d.ts.map +1 -0
- package/dist/cmd/version/index.d.ts.map +1 -1
- package/dist/config.d.ts +11 -3
- package/dist/config.d.ts.map +1 -1
- package/dist/crypto/box.d.ts +65 -0
- package/dist/crypto/box.d.ts.map +1 -0
- package/dist/crypto/box.test.d.ts +2 -0
- package/dist/crypto/box.test.d.ts.map +1 -0
- package/dist/download.d.ts.map +1 -1
- package/dist/env-util.d.ts +67 -0
- package/dist/env-util.d.ts.map +1 -0
- package/dist/env-util.test.d.ts +2 -0
- package/dist/env-util.test.d.ts.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/schema-parser.d.ts.map +1 -1
- package/dist/steps.d.ts +4 -1
- package/dist/steps.d.ts.map +1 -1
- package/dist/terminal.d.ts.map +1 -1
- package/dist/tui.d.ts +32 -2
- package/dist/tui.d.ts.map +1 -1
- package/dist/types.d.ts +250 -127
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/detectSubagent.d.ts +15 -0
- package/dist/utils/detectSubagent.d.ts.map +1 -0
- package/dist/utils/zip.d.ts +7 -0
- package/dist/utils/zip.d.ts.map +1 -0
- package/package.json +11 -3
- package/src/api-errors.md +2 -2
- package/src/api.ts +12 -7
- package/src/auth.ts +116 -7
- package/src/banner.ts +13 -6
- package/src/cli.ts +709 -36
- package/src/cmd/auth/api.ts +10 -16
- package/src/cmd/auth/index.ts +3 -1
- package/src/cmd/auth/login.ts +24 -8
- package/src/cmd/auth/signup.ts +15 -11
- package/src/cmd/auth/ssh/add.ts +263 -0
- package/src/cmd/auth/ssh/api.ts +94 -0
- package/src/cmd/auth/ssh/delete.ts +102 -0
- package/src/cmd/auth/ssh/index.ts +10 -0
- package/src/cmd/auth/ssh/list.ts +74 -0
- package/src/cmd/auth/whoami.ts +69 -0
- package/src/cmd/bundle/ast.test.ts +565 -0
- package/src/cmd/bundle/ast.ts +457 -44
- package/src/cmd/bundle/bundler.ts +255 -57
- package/src/cmd/bundle/file.ts +6 -12
- package/src/cmd/bundle/fix-duplicate-exports.test.ts +387 -0
- package/src/cmd/bundle/fix-duplicate-exports.ts +204 -0
- package/src/cmd/bundle/index.ts +11 -11
- package/src/cmd/bundle/patch/aisdk.ts +1 -1
- package/src/cmd/bundle/plugin.ts +373 -53
- package/src/cmd/cloud/deploy.ts +336 -0
- package/src/cmd/cloud/domain.ts +92 -0
- package/src/cmd/cloud/index.ts +11 -0
- package/src/cmd/cloud/resource/add.ts +56 -0
- package/src/cmd/cloud/resource/delete.ts +120 -0
- package/src/cmd/cloud/resource/index.ts +11 -0
- package/src/cmd/cloud/resource/list.ts +69 -0
- package/src/cmd/cloud/scp/download.ts +59 -0
- package/src/cmd/cloud/scp/index.ts +9 -0
- package/src/cmd/cloud/scp/upload.ts +62 -0
- package/src/cmd/cloud/ssh.ts +68 -0
- package/src/cmd/dev/api.ts +46 -0
- package/src/cmd/dev/download.ts +111 -0
- package/src/cmd/dev/index.ts +362 -34
- package/src/cmd/dev/templates.ts +84 -0
- package/src/cmd/env/delete.ts +47 -0
- package/src/cmd/env/get.ts +53 -0
- package/src/cmd/env/import.ts +102 -0
- package/src/cmd/env/index.ts +22 -0
- package/src/cmd/env/list.ts +56 -0
- package/src/cmd/env/pull.ts +80 -0
- package/src/cmd/env/push.ts +37 -0
- package/src/cmd/env/set.ts +71 -0
- package/src/cmd/index.ts +2 -2
- package/src/cmd/profile/show.ts +15 -6
- package/src/cmd/project/create.ts +7 -2
- package/src/cmd/project/delete.ts +75 -18
- package/src/cmd/project/download.ts +3 -3
- package/src/cmd/project/list.ts +8 -8
- package/src/cmd/project/show.ts +3 -7
- package/src/cmd/project/template-flow.ts +186 -48
- package/src/cmd/secret/delete.ts +40 -0
- package/src/cmd/secret/get.ts +54 -0
- package/src/cmd/secret/import.ts +64 -0
- package/src/cmd/secret/index.ts +22 -0
- package/src/cmd/secret/list.ts +56 -0
- package/src/cmd/secret/pull.ts +78 -0
- package/src/cmd/secret/push.ts +37 -0
- package/src/cmd/secret/set.ts +45 -0
- package/src/cmd/version/index.ts +2 -1
- package/src/config.ts +257 -27
- package/src/crypto/box.test.ts +431 -0
- package/src/crypto/box.ts +477 -0
- package/src/download.ts +1 -0
- package/src/env-util.test.ts +194 -0
- package/src/env-util.ts +290 -0
- package/src/index.ts +5 -1
- package/src/schema-parser.ts +2 -3
- package/src/steps.ts +144 -10
- package/src/terminal.ts +24 -23
- package/src/tui.ts +208 -68
- package/src/types.ts +292 -202
- package/src/utils/detectSubagent.ts +31 -0
- package/src/utils/zip.ts +38 -0
- package/dist/cmd/example/create-user.d.ts +0 -2
- package/dist/cmd/example/create-user.d.ts.map +0 -1
- package/dist/cmd/example/create.d.ts +0 -2
- package/dist/cmd/example/create.d.ts.map +0 -1
- package/dist/cmd/example/deploy.d.ts.map +0 -1
- package/dist/cmd/example/index.d.ts.map +0 -1
- package/dist/cmd/example/list.d.ts.map +0 -1
- package/dist/cmd/example/optional-auth.d.ts +0 -3
- package/dist/cmd/example/optional-auth.d.ts.map +0 -1
- package/dist/cmd/example/run-command.d.ts +0 -2
- package/dist/cmd/example/run-command.d.ts.map +0 -1
- package/dist/cmd/example/sound.d.ts +0 -3
- package/dist/cmd/example/sound.d.ts.map +0 -1
- package/dist/cmd/example/spinner.d.ts +0 -2
- package/dist/cmd/example/spinner.d.ts.map +0 -1
- package/dist/cmd/example/steps.d.ts +0 -2
- package/dist/cmd/example/steps.d.ts.map +0 -1
- package/dist/cmd/example/version.d.ts +0 -2
- package/dist/cmd/example/version.d.ts.map +0 -1
- package/dist/logger.d.ts +0 -24
- package/dist/logger.d.ts.map +0 -1
- package/src/cmd/example/create-user.ts +0 -38
- package/src/cmd/example/create.ts +0 -31
- package/src/cmd/example/deploy.ts +0 -36
- package/src/cmd/example/index.ts +0 -29
- package/src/cmd/example/list.ts +0 -32
- package/src/cmd/example/optional-auth.ts +0 -38
- package/src/cmd/example/run-command.ts +0 -45
- package/src/cmd/example/sound.ts +0 -14
- package/src/cmd/example/spinner.ts +0 -44
- package/src/cmd/example/steps.ts +0 -66
- package/src/cmd/example/version.ts +0 -13
- package/src/logger.ts +0 -235
- /package/dist/cmd/{example → cloud}/deploy.d.ts +0 -0
- /package/dist/cmd/{example → cloud}/index.d.ts +0 -0
- /package/dist/cmd/{example → env}/list.d.ts +0 -0
package/src/cmd/dev/index.ts
CHANGED
|
@@ -1,26 +1,49 @@
|
|
|
1
|
-
|
|
1
|
+
/** biome-ignore-all lint/style/useTemplate: its easier */
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
+
import type { BuildMetadata } from '@agentuity/server';
|
|
3
4
|
import { resolve, join } from 'node:path';
|
|
4
5
|
import { bundle } from '../bundle/bundler';
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import
|
|
6
|
+
import { getBuildMetadata } from '../bundle/plugin';
|
|
7
|
+
import { existsSync, type FSWatcher, watch, statSync, readdirSync } from 'node:fs';
|
|
8
|
+
import {
|
|
9
|
+
getDefaultConfigDir,
|
|
10
|
+
loadDevelopmentProjectSDKKey,
|
|
11
|
+
saveProjectDir,
|
|
12
|
+
saveConfig,
|
|
13
|
+
} from '../../config';
|
|
14
|
+
import { type Config, createCommand } from '../../types';
|
|
8
15
|
import * as tui from '../../tui';
|
|
16
|
+
import { createAgentTemplates, createAPITemplates } from './templates';
|
|
17
|
+
import { generateEndpoint, type DevmodeResponse } from './api';
|
|
18
|
+
import { APIClient, getAPIBaseURL } from '../../api';
|
|
19
|
+
import { download } from './download';
|
|
9
20
|
|
|
10
21
|
export const command = createCommand({
|
|
11
22
|
name: 'dev',
|
|
12
23
|
description: 'Build and run the development server',
|
|
13
24
|
schema: {
|
|
14
25
|
options: z.object({
|
|
15
|
-
|
|
26
|
+
local: z.boolean().optional().describe('Turn on local services (instead of cloud)'),
|
|
27
|
+
public: z
|
|
28
|
+
.boolean()
|
|
29
|
+
.optional()
|
|
30
|
+
.default(!process.env.CI)
|
|
31
|
+
.describe('Turn on or off the public url'),
|
|
32
|
+
port: z
|
|
33
|
+
.number()
|
|
34
|
+
.min(1024) // should we allow a lower root port? probably not?
|
|
35
|
+
.max(65535)
|
|
36
|
+
.default(3500)
|
|
37
|
+
.describe('The TCP port to start the dev start'),
|
|
16
38
|
}),
|
|
17
39
|
},
|
|
18
|
-
|
|
40
|
+
optional: { auth: 'Continue without an account (local only)', project: true },
|
|
19
41
|
|
|
20
42
|
async handler(ctx) {
|
|
21
|
-
const { opts, logger } = ctx;
|
|
43
|
+
const { opts, logger, options, project, projectDir, auth } = ctx;
|
|
44
|
+
let { config } = ctx;
|
|
22
45
|
|
|
23
|
-
const rootDir =
|
|
46
|
+
const rootDir = projectDir;
|
|
24
47
|
const appTs = join(rootDir, 'app.ts');
|
|
25
48
|
const srcDir = join(rootDir, 'src');
|
|
26
49
|
const mustHaves = [join(rootDir, 'package.json'), appTs, srcDir];
|
|
@@ -40,13 +63,69 @@ export const command = createCommand({
|
|
|
40
63
|
process.exit(1);
|
|
41
64
|
}
|
|
42
65
|
|
|
66
|
+
await saveProjectDir(rootDir);
|
|
67
|
+
|
|
68
|
+
let devmode: DevmodeResponse | undefined;
|
|
69
|
+
let gravityBin: string | undefined;
|
|
70
|
+
|
|
71
|
+
if (auth && project && opts.public) {
|
|
72
|
+
// Only create apiClient if auth is available
|
|
73
|
+
const apiClient = new APIClient(getAPIBaseURL(config), logger, config);
|
|
74
|
+
const endpoint = await tui.spinner({
|
|
75
|
+
message: 'Connecting to Gravity',
|
|
76
|
+
callback: () => {
|
|
77
|
+
return generateEndpoint(apiClient, project.projectId, config?.devmode?.hostname);
|
|
78
|
+
},
|
|
79
|
+
clearOnSuccess: true,
|
|
80
|
+
});
|
|
81
|
+
const _config = { ...config } as Config;
|
|
82
|
+
_config.devmode = {
|
|
83
|
+
hostname: endpoint.hostname,
|
|
84
|
+
};
|
|
85
|
+
await saveConfig(_config);
|
|
86
|
+
config = _config;
|
|
87
|
+
devmode = endpoint;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (devmode) {
|
|
91
|
+
const configDir = getDefaultConfigDir();
|
|
92
|
+
const gravityDir = join(configDir, 'gravity');
|
|
93
|
+
let mustCheck = true;
|
|
94
|
+
if (
|
|
95
|
+
config?.gravity?.version &&
|
|
96
|
+
existsSync(join(gravityDir, config.gravity.version, 'gravity')) &&
|
|
97
|
+
config?.gravity?.checked
|
|
98
|
+
) {
|
|
99
|
+
if (Date.now() - config.gravity.checked < 3.6e6) {
|
|
100
|
+
mustCheck = false;
|
|
101
|
+
gravityBin = join(gravityDir, config.gravity.version, 'gravity');
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
if (mustCheck) {
|
|
105
|
+
const res = await download(gravityDir);
|
|
106
|
+
gravityBin = res.filename;
|
|
107
|
+
const _config = { ...config } as Config;
|
|
108
|
+
_config.gravity = {
|
|
109
|
+
checked: Date.now(),
|
|
110
|
+
version: res.version,
|
|
111
|
+
};
|
|
112
|
+
await saveConfig(_config);
|
|
113
|
+
config = _config;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const canDoInput = !!(process.stdin.isTTY && process.stdout.isTTY && !process.env.CI);
|
|
118
|
+
|
|
43
119
|
const devmodebody =
|
|
44
|
-
tui.muted('Local:
|
|
45
|
-
tui.link(
|
|
46
|
-
'\n
|
|
47
|
-
tui.muted('
|
|
48
|
-
tui.
|
|
49
|
-
|
|
120
|
+
tui.muted(tui.padRight('Local:', 10)) +
|
|
121
|
+
tui.link(`http://127.0.0.1:${opts.port}`) +
|
|
122
|
+
'\n' +
|
|
123
|
+
tui.muted(tui.padRight('Public:', 10)) +
|
|
124
|
+
(devmode?.hostname ? tui.link(`https://${devmode.hostname}`) : tui.warn('Disabled')) +
|
|
125
|
+
'\n' +
|
|
126
|
+
(canDoInput
|
|
127
|
+
? '\n' + tui.muted('Press ') + tui.bold('h') + tui.muted(' for keyboard shortcuts')
|
|
128
|
+
: '');
|
|
50
129
|
|
|
51
130
|
function showBanner() {
|
|
52
131
|
tui.banner('⨺ Agentuity DevMode', devmodebody, {
|
|
@@ -63,8 +142,39 @@ export const command = createCommand({
|
|
|
63
142
|
env.AGENTUITY_SDK_DEV_MODE = 'true';
|
|
64
143
|
env.AGENTUITY_ENV = 'development';
|
|
65
144
|
env.NODE_ENV = 'development';
|
|
66
|
-
env.PORT =
|
|
145
|
+
env.PORT = Number(opts.port).toFixed();
|
|
67
146
|
env.AGENTUITY_PORT = env.PORT;
|
|
147
|
+
if (options.logLevel !== undefined) env.AGENTUITY_LOG_LEVEL = options.logLevel;
|
|
148
|
+
// Pass through AGENTUITY_SDK_LOG_LEVEL for internal SDK logger
|
|
149
|
+
if (process.env.AGENTUITY_SDK_LOG_LEVEL) {
|
|
150
|
+
env.AGENTUITY_SDK_LOG_LEVEL = process.env.AGENTUITY_SDK_LOG_LEVEL;
|
|
151
|
+
}
|
|
152
|
+
env.AGENTUITY_FORCE_LOCAL_SERVICES = opts.local === true ? 'true' : 'false';
|
|
153
|
+
if (config?.overrides?.transport_url) {
|
|
154
|
+
env.AGENTUITY_TRANSPORT_URL = config.overrides.transport_url;
|
|
155
|
+
}
|
|
156
|
+
if (config?.overrides?.catalyst_url) {
|
|
157
|
+
env.AGENTUITY_CATALYST_URL = config.overrides.catalyst_url;
|
|
158
|
+
}
|
|
159
|
+
if (config?.overrides?.vector_url) {
|
|
160
|
+
env.AGENTUITY_VECTOR_URL = config.overrides.vector_url;
|
|
161
|
+
}
|
|
162
|
+
if (config?.overrides?.object_url) {
|
|
163
|
+
env.AGENTUITY_OBJECTSTORE_URL = config.overrides.object_url;
|
|
164
|
+
}
|
|
165
|
+
if (config?.overrides?.kv_url) {
|
|
166
|
+
env.AGENTUITY_KEYVALUE_URL = config.overrides.kv_url;
|
|
167
|
+
}
|
|
168
|
+
if (config?.overrides?.stream_url) {
|
|
169
|
+
env.AGENTUITY_STREAM_URL = config.overrides.stream_url;
|
|
170
|
+
}
|
|
171
|
+
if (project) {
|
|
172
|
+
env.AGENTUITY_CLOUD_ORG_ID = project.orgId;
|
|
173
|
+
env.AGENTUITY_CLOUD_PROJECT_ID = project.projectId;
|
|
174
|
+
}
|
|
175
|
+
if (!process.stdout.isTTY) {
|
|
176
|
+
env.NO_COLOR = '1';
|
|
177
|
+
}
|
|
68
178
|
|
|
69
179
|
const agentuityDir = resolve(rootDir, '.agentuity');
|
|
70
180
|
const appPath = resolve(agentuityDir, 'app.js');
|
|
@@ -82,7 +192,57 @@ export const command = createCommand({
|
|
|
82
192
|
let shuttingDownForRestart = false;
|
|
83
193
|
let pendingRestart = false;
|
|
84
194
|
let building = false;
|
|
85
|
-
let
|
|
195
|
+
let buildCompletedAt = 0;
|
|
196
|
+
const BUILD_COOLDOWN_MS = 500; // Ignore file changes for 500ms after build completes
|
|
197
|
+
let metadata: Partial<BuildMetadata> | undefined;
|
|
198
|
+
let showInitialReadyMessage = true;
|
|
199
|
+
let serverStartTime = 0;
|
|
200
|
+
let gravityClient: Bun.Subprocess | undefined;
|
|
201
|
+
|
|
202
|
+
if (gravityBin && devmode && project) {
|
|
203
|
+
const sdkKey = await loadDevelopmentProjectSDKKey(rootDir);
|
|
204
|
+
if (!sdkKey) {
|
|
205
|
+
tui.warning(`Couldn't find the AGENTUITY_SDK_KEY in ${rootDir} .env file`);
|
|
206
|
+
} else {
|
|
207
|
+
const gravityBinExists = await Bun.file(gravityBin).exists();
|
|
208
|
+
if (!gravityBinExists) {
|
|
209
|
+
logger.error(
|
|
210
|
+
`Gravity binary not found at ${gravityBin}, skipping gravity client startup`
|
|
211
|
+
);
|
|
212
|
+
} else {
|
|
213
|
+
try {
|
|
214
|
+
gravityClient = Bun.spawn(
|
|
215
|
+
[
|
|
216
|
+
gravityBin,
|
|
217
|
+
'--endpoint-id',
|
|
218
|
+
devmode.id,
|
|
219
|
+
'--port',
|
|
220
|
+
env.PORT,
|
|
221
|
+
'--url',
|
|
222
|
+
config?.overrides?.gravity_url ?? 'grpc://devmode.agentuity.com',
|
|
223
|
+
'--log-level',
|
|
224
|
+
'error',
|
|
225
|
+
],
|
|
226
|
+
{
|
|
227
|
+
cwd: rootDir,
|
|
228
|
+
stdout: 'inherit',
|
|
229
|
+
stderr: 'inherit',
|
|
230
|
+
stdin: 'ignore',
|
|
231
|
+
env: { ...env, AGENTUITY_SDK_KEY: sdkKey },
|
|
232
|
+
}
|
|
233
|
+
);
|
|
234
|
+
gravityClient.exited.then(() => {
|
|
235
|
+
logger.debug('gravity client exited');
|
|
236
|
+
});
|
|
237
|
+
} catch (err) {
|
|
238
|
+
logger.error(
|
|
239
|
+
'Failed to spawn gravity client: %s',
|
|
240
|
+
err instanceof Error ? err.message : String(err)
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
86
246
|
|
|
87
247
|
// Track restart timestamps to detect restart loops
|
|
88
248
|
const restartTimestamps: number[] = [];
|
|
@@ -94,7 +254,7 @@ export const command = createCommand({
|
|
|
94
254
|
restartTimestamps.push(now);
|
|
95
255
|
|
|
96
256
|
// Remove timestamps older than the time window
|
|
97
|
-
while (restartTimestamps.length > 0 && now - restartTimestamps[0]
|
|
257
|
+
while (restartTimestamps.length > 0 && now - restartTimestamps[0] > TIME_WINDOW_MS) {
|
|
98
258
|
restartTimestamps.shift();
|
|
99
259
|
}
|
|
100
260
|
|
|
@@ -158,7 +318,13 @@ export const command = createCommand({
|
|
|
158
318
|
};
|
|
159
319
|
|
|
160
320
|
// Handle signals to ensure entire process tree is killed
|
|
161
|
-
const cleanup = () => {
|
|
321
|
+
const cleanup = (exitCode = 0) => {
|
|
322
|
+
logger.trace('cleanup() called with exitCode=%d', exitCode);
|
|
323
|
+
if (gravityClient) {
|
|
324
|
+
logger.debug('calling kill on gravity client with pid: %d', gravityClient.pid);
|
|
325
|
+
gravityClient.kill('SIGINT');
|
|
326
|
+
gravityClient = undefined;
|
|
327
|
+
}
|
|
162
328
|
if (pid && running) {
|
|
163
329
|
kill();
|
|
164
330
|
}
|
|
@@ -166,11 +332,22 @@ export const command = createCommand({
|
|
|
166
332
|
watcher.close();
|
|
167
333
|
}
|
|
168
334
|
watchers.length = 0;
|
|
169
|
-
process.exit(
|
|
335
|
+
process.exit(exitCode);
|
|
170
336
|
};
|
|
171
337
|
|
|
172
338
|
process.on('SIGINT', cleanup);
|
|
173
339
|
process.on('SIGTERM', cleanup);
|
|
340
|
+
process.on('SIGQUIT', cleanup);
|
|
341
|
+
process.on('exit', () => {
|
|
342
|
+
// Synchronous cleanup on exit
|
|
343
|
+
if (gravityClient) {
|
|
344
|
+
try {
|
|
345
|
+
gravityClient.kill('SIGINT');
|
|
346
|
+
} catch {
|
|
347
|
+
// Ignore errors
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
});
|
|
174
351
|
|
|
175
352
|
async function restart() {
|
|
176
353
|
// Queue restart if already restarting
|
|
@@ -195,6 +372,7 @@ export const command = createCommand({
|
|
|
195
372
|
} else {
|
|
196
373
|
logger.trace('Initial server start');
|
|
197
374
|
}
|
|
375
|
+
logger.trace('Starting typecheck and build...');
|
|
198
376
|
await Promise.all([
|
|
199
377
|
tui.runCommand({
|
|
200
378
|
command: 'tsc',
|
|
@@ -207,35 +385,44 @@ export const command = createCommand({
|
|
|
207
385
|
}),
|
|
208
386
|
tui.spinner('Building project', async () => {
|
|
209
387
|
try {
|
|
388
|
+
logger.trace('Bundle starting...');
|
|
210
389
|
building = true;
|
|
211
390
|
await bundle({
|
|
212
391
|
rootDir,
|
|
213
392
|
dev: true,
|
|
214
393
|
});
|
|
215
394
|
building = false;
|
|
216
|
-
|
|
395
|
+
buildCompletedAt = Date.now();
|
|
396
|
+
logger.trace('Bundle completed successfully');
|
|
397
|
+
} catch (error) {
|
|
217
398
|
building = false;
|
|
399
|
+
logger.trace('Bundle failed: %s', error);
|
|
218
400
|
failure('Build failed');
|
|
219
401
|
}
|
|
220
402
|
}),
|
|
221
403
|
]);
|
|
404
|
+
logger.trace('Typecheck and build completed');
|
|
222
405
|
|
|
223
406
|
if (failed) {
|
|
407
|
+
logger.trace('Restart failed, returning early');
|
|
224
408
|
return;
|
|
225
409
|
}
|
|
226
410
|
|
|
411
|
+
logger.trace('Checking if app file exists: %s', appPath);
|
|
227
412
|
if (!existsSync(appPath)) {
|
|
413
|
+
logger.trace('App file not found: %s', appPath);
|
|
228
414
|
failure(`App file not found: ${appPath}`);
|
|
229
415
|
return;
|
|
230
416
|
}
|
|
417
|
+
logger.trace('App file exists, getting build metadata...');
|
|
231
418
|
|
|
232
|
-
metadata =
|
|
233
|
-
|
|
234
|
-
env.AGENTUITY_LOG_LEVEL = logger.level;
|
|
419
|
+
metadata = getBuildMetadata();
|
|
420
|
+
logger.trace('Build metadata retrieved');
|
|
235
421
|
|
|
236
422
|
logger.trace('Starting dev server: %s', appPath);
|
|
237
423
|
// Use shell to run in a process group for proper cleanup
|
|
238
424
|
// The 'exec' ensures the shell is replaced by the actual process
|
|
425
|
+
logger.trace('Spawning dev server process...');
|
|
239
426
|
devServer = Bun.spawn(['sh', '-c', `exec bun run "${appPath}"`], {
|
|
240
427
|
cwd: rootDir,
|
|
241
428
|
stdout: 'inherit',
|
|
@@ -244,33 +431,57 @@ export const command = createCommand({
|
|
|
244
431
|
env,
|
|
245
432
|
});
|
|
246
433
|
|
|
434
|
+
logger.trace('Dev server process spawned, setting up state...');
|
|
247
435
|
running = true;
|
|
248
436
|
failed = false;
|
|
249
437
|
pid = devServer.pid;
|
|
250
438
|
exitPromise = devServer.exited;
|
|
439
|
+
serverStartTime = Date.now();
|
|
251
440
|
logger.trace('Dev server started (pid: %d)', pid);
|
|
252
441
|
|
|
442
|
+
if (showInitialReadyMessage) {
|
|
443
|
+
showInitialReadyMessage = false;
|
|
444
|
+
logger.info('DevMode ready 🚀');
|
|
445
|
+
logger.trace('Initial ready message logged');
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
logger.trace('Attaching exit handler to dev server process...');
|
|
253
449
|
// Attach non-blocking exit handler
|
|
254
450
|
exitPromise
|
|
255
451
|
.then((exitCode) => {
|
|
452
|
+
const runtime = Date.now() - serverStartTime;
|
|
256
453
|
logger.trace(
|
|
257
|
-
'Dev server exited with code %d (shuttingDownForRestart=%s)',
|
|
454
|
+
'Dev server exited with code %d (shuttingDownForRestart=%s, runtime=%dms)',
|
|
258
455
|
exitCode,
|
|
259
|
-
shuttingDownForRestart
|
|
456
|
+
shuttingDownForRestart,
|
|
457
|
+
runtime
|
|
260
458
|
);
|
|
261
459
|
running = false;
|
|
262
460
|
devServer = undefined;
|
|
263
461
|
exitPromise = undefined;
|
|
264
|
-
//
|
|
265
|
-
if (
|
|
462
|
+
// If server exited immediately after starting (< 2 seconds), treat as failure and restart
|
|
463
|
+
if (runtime < 2000 && !shuttingDownForRestart) {
|
|
464
|
+
logger.trace('Server exited too quickly, treating as failure and restarting');
|
|
465
|
+
failure('Server exited immediately after starting');
|
|
466
|
+
// Trigger a restart after a short delay
|
|
467
|
+
setTimeout(() => {
|
|
468
|
+
if (!running && !restarting) {
|
|
469
|
+
logger.trace('Triggering restart after quick exit');
|
|
470
|
+
restart();
|
|
471
|
+
}
|
|
472
|
+
}, 100);
|
|
473
|
+
return;
|
|
474
|
+
}
|
|
475
|
+
// Only exit the CLI if this is a clean exit AND not a restart AND server ran for a while
|
|
476
|
+
if (exitCode === 0 && !shuttingDownForRestart && runtime >= 2000) {
|
|
266
477
|
logger.trace('Clean exit, stopping CLI');
|
|
267
|
-
|
|
478
|
+
cleanup(exitCode);
|
|
268
479
|
}
|
|
269
480
|
// Non-zero exit codes are treated as restartable failures
|
|
270
481
|
// But if it's exit code 1 (common error exit), also exit the CLI
|
|
271
|
-
if (exitCode === 1 && !shuttingDownForRestart) {
|
|
482
|
+
if (exitCode === 1 && !shuttingDownForRestart && runtime >= 2000) {
|
|
272
483
|
logger.trace('Server exited with error code 1, stopping CLI');
|
|
273
|
-
|
|
484
|
+
cleanup(exitCode);
|
|
274
485
|
}
|
|
275
486
|
})
|
|
276
487
|
.catch((error) => {
|
|
@@ -291,14 +502,18 @@ export const command = createCommand({
|
|
|
291
502
|
}
|
|
292
503
|
});
|
|
293
504
|
} catch (error) {
|
|
505
|
+
logger.trace('Restart caught error: %s', error);
|
|
294
506
|
if (error instanceof Error) {
|
|
507
|
+
logger.trace('Error message: %s, stack: %s', error.message, error.stack);
|
|
295
508
|
failure(`Dev server failed: ${error.message}`);
|
|
296
509
|
} else {
|
|
510
|
+
logger.trace('Non-Error exception: %s', String(error));
|
|
297
511
|
failure('Dev server failed');
|
|
298
512
|
}
|
|
299
513
|
running = false;
|
|
300
514
|
devServer = undefined;
|
|
301
515
|
} finally {
|
|
516
|
+
logger.trace('Entering restart() finally block...');
|
|
302
517
|
const hadPendingRestart = pendingRestart;
|
|
303
518
|
restarting = false;
|
|
304
519
|
pendingRestart = false;
|
|
@@ -321,7 +536,7 @@ export const command = createCommand({
|
|
|
321
536
|
logger.trace('Initial restart completed, setting up watchers');
|
|
322
537
|
|
|
323
538
|
// Setup keyboard shortcuts (only if we have a TTY)
|
|
324
|
-
if (
|
|
539
|
+
if (canDoInput) {
|
|
325
540
|
logger.trace('Setting up keyboard shortcuts');
|
|
326
541
|
process.stdin.setRawMode(true);
|
|
327
542
|
process.stdin.resume();
|
|
@@ -383,6 +598,23 @@ export const command = createCommand({
|
|
|
383
598
|
});
|
|
384
599
|
|
|
385
600
|
logger.trace('✓ Keyboard shortcuts enabled');
|
|
601
|
+
} else {
|
|
602
|
+
if (process.stdin) {
|
|
603
|
+
// still need to monitor stdin in case we are pipeing into another process or file etc
|
|
604
|
+
if (typeof process.stdin.setRawMode === 'function') {
|
|
605
|
+
process.stdin.setRawMode(true);
|
|
606
|
+
}
|
|
607
|
+
process.stdin.resume();
|
|
608
|
+
process.stdin.on('data', (data) => {
|
|
609
|
+
const key = data.toString();
|
|
610
|
+
// Handle Ctrl+C
|
|
611
|
+
if (key === '\u0003') {
|
|
612
|
+
cleanup();
|
|
613
|
+
return;
|
|
614
|
+
}
|
|
615
|
+
});
|
|
616
|
+
}
|
|
617
|
+
logger.trace('❌ Keyboard shortcuts disabled');
|
|
386
618
|
}
|
|
387
619
|
|
|
388
620
|
// Patterns to ignore (generated files that change during build)
|
|
@@ -391,14 +623,25 @@ export const command = createCommand({
|
|
|
391
623
|
/registry\.generated\.ts$/,
|
|
392
624
|
/types\.generated\.d\.ts$/,
|
|
393
625
|
/client\.generated\.js$/,
|
|
626
|
+
/\.tmp$/,
|
|
627
|
+
/\.tsbuildinfo$/,
|
|
628
|
+
/\.agentuity\//,
|
|
629
|
+
// Ignore temporary files created by sed (e.g., sedUprJj0)
|
|
630
|
+
/\/sed[A-Za-z0-9]+$/,
|
|
394
631
|
];
|
|
395
632
|
|
|
633
|
+
// Helper to check if a file is a temporary file created by sed
|
|
634
|
+
const isSedTempFile = (filePath: string): boolean => {
|
|
635
|
+
const basename = filePath.split('/').pop() || '';
|
|
636
|
+
return /^sed[A-Za-z0-9]+$/.test(basename);
|
|
637
|
+
};
|
|
638
|
+
|
|
396
639
|
logger.trace('Setting up file watchers for: %s', watches.join(', '));
|
|
397
640
|
for (const watchDir of watches) {
|
|
398
641
|
try {
|
|
399
642
|
logger.trace('Setting up watcher for %s', watchDir);
|
|
400
643
|
const watcher = watch(watchDir, { recursive: true }, (eventType, changedFile) => {
|
|
401
|
-
const absPath = changedFile ?
|
|
644
|
+
const absPath = changedFile ? resolve(watchDir, changedFile) : watchDir;
|
|
402
645
|
|
|
403
646
|
// Ignore file changes during active build to prevent loops
|
|
404
647
|
if (building) {
|
|
@@ -411,6 +654,18 @@ export const command = createCommand({
|
|
|
411
654
|
return;
|
|
412
655
|
}
|
|
413
656
|
|
|
657
|
+
// Ignore file changes immediately after build completes (cooldown period)
|
|
658
|
+
// This prevents restarts from build output files that are written asynchronously
|
|
659
|
+
if (buildCompletedAt > 0 && Date.now() - buildCompletedAt < BUILD_COOLDOWN_MS) {
|
|
660
|
+
logger.trace(
|
|
661
|
+
'File change ignored (build cooldown): %s (event: %s, file: %s)',
|
|
662
|
+
watchDir,
|
|
663
|
+
eventType,
|
|
664
|
+
changedFile
|
|
665
|
+
);
|
|
666
|
+
return;
|
|
667
|
+
}
|
|
668
|
+
|
|
414
669
|
// Ignore node_modules folder
|
|
415
670
|
if (absPath.includes('node_modules')) {
|
|
416
671
|
logger.trace(
|
|
@@ -423,7 +678,12 @@ export const command = createCommand({
|
|
|
423
678
|
}
|
|
424
679
|
|
|
425
680
|
// Ignore changes in .agentuity directory (build output)
|
|
426
|
-
|
|
681
|
+
// Check both relative path and normalized absolute path
|
|
682
|
+
const isInAgentuityDir =
|
|
683
|
+
(changedFile &&
|
|
684
|
+
(changedFile === '.agentuity' || changedFile.startsWith('.agentuity/'))) ||
|
|
685
|
+
resolve(absPath).startsWith(agentuityDir);
|
|
686
|
+
if (isInAgentuityDir) {
|
|
427
687
|
logger.trace(
|
|
428
688
|
'File change ignored (.agentuity dir): %s (event: %s, file: %s)',
|
|
429
689
|
watchDir,
|
|
@@ -444,8 +704,61 @@ export const command = createCommand({
|
|
|
444
704
|
return;
|
|
445
705
|
}
|
|
446
706
|
|
|
707
|
+
// Check for .tmp file renames that replace watched files (BEFORE ignoring)
|
|
708
|
+
// This handles cases like sed -i.tmp where agent.ts.tmp is renamed to agent.ts
|
|
709
|
+
if (eventType === 'rename' && changedFile && changedFile.endsWith('.tmp')) {
|
|
710
|
+
const targetFile = changedFile.slice(0, -4); // Remove .tmp suffix
|
|
711
|
+
const targetAbsPath = resolve(watchDir, targetFile);
|
|
712
|
+
|
|
713
|
+
// Only trigger restart for source files (ts, tsx, js, jsx, etc.)
|
|
714
|
+
const isSourceFile = /\.(ts|tsx|js|jsx|mjs|cjs)$/.test(targetFile);
|
|
715
|
+
|
|
716
|
+
// Check if target file exists and is not in ignored directories
|
|
717
|
+
const targetExists = existsSync(targetAbsPath);
|
|
718
|
+
const inNodeModules = targetAbsPath.includes('node_modules');
|
|
719
|
+
const inAgentuityDir =
|
|
720
|
+
(targetFile &&
|
|
721
|
+
(targetFile === '.agentuity' || targetFile.startsWith('.agentuity/'))) ||
|
|
722
|
+
resolve(targetAbsPath).startsWith(agentuityDir);
|
|
723
|
+
let isDirectory = false;
|
|
724
|
+
if (targetExists) {
|
|
725
|
+
try {
|
|
726
|
+
isDirectory = statSync(targetAbsPath).isDirectory();
|
|
727
|
+
} catch (err) {
|
|
728
|
+
logger.trace('Failed to stat target file: %s', err);
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
if (
|
|
733
|
+
isSourceFile &&
|
|
734
|
+
targetExists &&
|
|
735
|
+
!inNodeModules &&
|
|
736
|
+
!inAgentuityDir &&
|
|
737
|
+
!isDirectory
|
|
738
|
+
) {
|
|
739
|
+
logger.trace(
|
|
740
|
+
'File change detected (temp file rename): %s -> %s',
|
|
741
|
+
absPath,
|
|
742
|
+
targetAbsPath
|
|
743
|
+
);
|
|
744
|
+
restart();
|
|
745
|
+
return;
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
|
|
447
749
|
// Ignore generated files to prevent restart loops
|
|
448
750
|
if (changedFile) {
|
|
751
|
+
// Check for sed temporary files
|
|
752
|
+
if (isSedTempFile(changedFile)) {
|
|
753
|
+
logger.trace(
|
|
754
|
+
'File change ignored (sed temp file): %s (event: %s, file: %s)',
|
|
755
|
+
watchDir,
|
|
756
|
+
eventType,
|
|
757
|
+
changedFile
|
|
758
|
+
);
|
|
759
|
+
return;
|
|
760
|
+
}
|
|
761
|
+
// Check other ignore patterns
|
|
449
762
|
for (const pattern of ignorePatterns) {
|
|
450
763
|
if (pattern.test(changedFile)) {
|
|
451
764
|
logger.trace(
|
|
@@ -459,6 +772,21 @@ export const command = createCommand({
|
|
|
459
772
|
}
|
|
460
773
|
}
|
|
461
774
|
|
|
775
|
+
if (
|
|
776
|
+
eventType === 'rename' &&
|
|
777
|
+
existsSync(absPath) &&
|
|
778
|
+
statSync(absPath).isDirectory() &&
|
|
779
|
+
readdirSync(absPath).length === 0
|
|
780
|
+
) {
|
|
781
|
+
if (changedFile?.startsWith('src/agents/')) {
|
|
782
|
+
logger.debug('agent directory created: %s', changedFile);
|
|
783
|
+
createAgentTemplates(absPath);
|
|
784
|
+
} else if (changedFile?.startsWith('src/apis/')) {
|
|
785
|
+
logger.debug('api directory created: %s', changedFile);
|
|
786
|
+
createAPITemplates(absPath);
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
|
|
462
790
|
logger.trace(
|
|
463
791
|
'File change detected: %s (event: %s, file: %s)',
|
|
464
792
|
absPath,
|
|
@@ -476,6 +804,6 @@ export const command = createCommand({
|
|
|
476
804
|
logger.debug('Dev server watching for changes');
|
|
477
805
|
|
|
478
806
|
// Keep the handler alive indefinitely
|
|
479
|
-
await new Promise(() => {});
|
|
807
|
+
await new Promise(() => {}).catch(() => cleanup());
|
|
480
808
|
},
|
|
481
809
|
});
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/* eslint-disable no-control-regex */
|
|
2
|
+
import { writeFileSync } from 'node:fs';
|
|
3
|
+
import { basename, join } from 'node:path';
|
|
4
|
+
|
|
5
|
+
const newAgentTemplate = (name: string) => `import { createAgent } from '@agentuity/runtime';
|
|
6
|
+
import { z } from 'zod';
|
|
7
|
+
|
|
8
|
+
const agent = createAgent({
|
|
9
|
+
metadata: {
|
|
10
|
+
name: '${name}',
|
|
11
|
+
description: 'Add my agent description here',
|
|
12
|
+
},
|
|
13
|
+
schema: {
|
|
14
|
+
input: z.string(),
|
|
15
|
+
output: z.string(),
|
|
16
|
+
},
|
|
17
|
+
handler: async (_c, input) => {
|
|
18
|
+
// TODO: add your code here
|
|
19
|
+
return input;
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
export default agent;
|
|
24
|
+
`;
|
|
25
|
+
|
|
26
|
+
const newAgentRouteTemplate = (name: string) => `import { createRouter } from '@agentuity/runtime';
|
|
27
|
+
|
|
28
|
+
const router = createRouter();
|
|
29
|
+
|
|
30
|
+
router.get('/', async (c) => {
|
|
31
|
+
// TODO: add your code here
|
|
32
|
+
const output = await c.agent.${name}.run('hello world');
|
|
33
|
+
return c.text(output);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
export default router;
|
|
37
|
+
|
|
38
|
+
`;
|
|
39
|
+
|
|
40
|
+
const newAPIRouteTemplate = (_name: string) => `import { createRouter } from '@agentuity/runtime';
|
|
41
|
+
|
|
42
|
+
const router = createRouter();
|
|
43
|
+
|
|
44
|
+
router.get('/', async (c) => {
|
|
45
|
+
// TODO: add your code here
|
|
46
|
+
return c.text('Hello');
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
export default router;
|
|
50
|
+
|
|
51
|
+
`;
|
|
52
|
+
|
|
53
|
+
const invalidDirRegex = /[<>:"/\\|?*]/;
|
|
54
|
+
|
|
55
|
+
// biome-ignore lint/suspicious/noControlCharactersInRegex: checking for invalid control characters in directory names
|
|
56
|
+
const invalidControlChars = /[\u0000-\u001F]/;
|
|
57
|
+
const reservedWindowsNames = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])$/i;
|
|
58
|
+
const invalidTrailing = /[. ]$/;
|
|
59
|
+
|
|
60
|
+
function isValidDirectoryName(name: string): boolean {
|
|
61
|
+
return (
|
|
62
|
+
!invalidDirRegex.test(name) &&
|
|
63
|
+
!invalidControlChars.test(name) &&
|
|
64
|
+
!reservedWindowsNames.test(name) &&
|
|
65
|
+
!invalidTrailing.test(name)
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function createAgentTemplates(dir: string) {
|
|
70
|
+
const name = basename(dir);
|
|
71
|
+
if (!isValidDirectoryName(name)) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
writeFileSync(join(dir, 'agent.ts'), newAgentTemplate(name));
|
|
75
|
+
writeFileSync(join(dir, 'route.ts'), newAgentRouteTemplate(name));
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function createAPITemplates(dir: string) {
|
|
79
|
+
const name = basename(dir);
|
|
80
|
+
if (!isValidDirectoryName(name)) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
writeFileSync(join(dir, 'route.ts'), newAPIRouteTemplate(name));
|
|
84
|
+
}
|