@agentuity/cli 0.0.67 → 0.0.69
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/bin/cli.ts +20 -8
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +16 -0
- package/dist/cli.js.map +1 -1
- package/dist/cmd/ai/prompt/agent.d.ts.map +1 -1
- package/dist/cmd/ai/prompt/agent.js +24 -25
- package/dist/cmd/ai/prompt/agent.js.map +1 -1
- package/dist/cmd/ai/prompt/api.d.ts.map +1 -1
- package/dist/cmd/ai/prompt/api.js +12 -9
- package/dist/cmd/ai/prompt/api.js.map +1 -1
- package/dist/cmd/build/ast.js +4 -4
- package/dist/cmd/build/ast.js.map +1 -1
- package/dist/cmd/build/bundler.js +2 -2
- package/dist/cmd/build/bundler.js.map +1 -1
- package/dist/cmd/build/plugin.d.ts.map +1 -1
- package/dist/cmd/build/plugin.js +9 -14
- package/dist/cmd/build/plugin.js.map +1 -1
- package/dist/cmd/dev/index.js +2 -2
- package/dist/cmd/dev/index.js.map +1 -1
- package/dist/cmd/dev/templates.d.ts.map +1 -1
- package/dist/cmd/dev/templates.js +10 -3
- package/dist/cmd/dev/templates.js.map +1 -1
- package/dist/cmd/project/download.js +10 -10
- package/dist/cmd/project/download.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +48 -87
- package/dist/config.js.map +1 -1
- package/dist/keychain.d.ts +31 -0
- package/dist/keychain.d.ts.map +1 -0
- package/dist/keychain.js +135 -0
- package/dist/keychain.js.map +1 -0
- package/dist/utils/detectSubagent.d.ts +1 -1
- package/dist/utils/detectSubagent.js +3 -3
- package/dist/utils/detectSubagent.js.map +1 -1
- package/package.json +3 -3
- package/src/cli.ts +19 -0
- package/src/cmd/ai/prompt/agent.ts +24 -25
- package/src/cmd/ai/prompt/api.ts +12 -9
- package/src/cmd/build/ast.ts +4 -4
- package/src/cmd/build/bundler.ts +2 -2
- package/src/cmd/build/plugin.ts +9 -14
- package/src/cmd/dev/index.ts +2 -2
- package/src/cmd/dev/templates.ts +10 -3
- package/src/cmd/project/download.ts +10 -10
- package/src/config.ts +54 -97
- package/src/keychain.ts +176 -0
- package/src/utils/detectSubagent.ts +3 -3
- package/dist/cmd/build/ast.test.d.ts +0 -2
- package/dist/cmd/build/ast.test.d.ts.map +0 -1
- package/dist/cmd/build/ast.test.js +0 -339
- package/dist/cmd/build/ast.test.js.map +0 -1
- package/dist/cmd/build/fix-duplicate-exports.test.d.ts +0 -2
- package/dist/cmd/build/fix-duplicate-exports.test.d.ts.map +0 -1
- package/dist/cmd/build/fix-duplicate-exports.test.js +0 -300
- package/dist/cmd/build/fix-duplicate-exports.test.js.map +0 -1
- package/dist/crypto/box.test.d.ts +0 -2
- package/dist/crypto/box.test.d.ts.map +0 -1
- package/dist/crypto/box.test.js +0 -317
- package/dist/crypto/box.test.js.map +0 -1
- package/dist/env-util.test.d.ts +0 -2
- package/dist/env-util.test.d.ts.map +0 -1
- package/dist/env-util.test.js +0 -146
- package/dist/env-util.test.js.map +0 -1
package/dist/keychain.js
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* macOS Keychain integration for secure auth token storage
|
|
3
|
+
*
|
|
4
|
+
* Stores auth tokens encrypted in the macOS Keychain using a per-device AES-256 key.
|
|
5
|
+
* No user prompts required - fully automatic and secure.
|
|
6
|
+
*/
|
|
7
|
+
const SERVICE_PREFIX = 'com.agentuity.cli';
|
|
8
|
+
const KEY_ACCOUNT = 'aes-encryption-key';
|
|
9
|
+
/**
|
|
10
|
+
* Check if we're running on macOS
|
|
11
|
+
*/
|
|
12
|
+
export function isMacOS() {
|
|
13
|
+
return process.platform === 'darwin';
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Get or create an AES encryption key stored in the macOS Keychain
|
|
17
|
+
*/
|
|
18
|
+
async function ensureEncryptionKey(service) {
|
|
19
|
+
// Try to read existing key
|
|
20
|
+
const find = Bun.spawn(['security', 'find-generic-password', '-s', service, '-a', KEY_ACCOUNT, '-w'], { stderr: 'ignore' });
|
|
21
|
+
const stdout = await new Response(find.stdout).text();
|
|
22
|
+
if (stdout.length > 0) {
|
|
23
|
+
const b64 = stdout.trim();
|
|
24
|
+
return Uint8Array.from(Buffer.from(b64, 'base64'));
|
|
25
|
+
}
|
|
26
|
+
// Create a new 32-byte (256-bit) AES key
|
|
27
|
+
const key = crypto.getRandomValues(new Uint8Array(32));
|
|
28
|
+
const b64 = Buffer.from(key).toString('base64');
|
|
29
|
+
// Store in macOS Keychain (no user prompts with -U flag)
|
|
30
|
+
const add = Bun.spawn([
|
|
31
|
+
'security',
|
|
32
|
+
'add-generic-password',
|
|
33
|
+
'-s',
|
|
34
|
+
service,
|
|
35
|
+
'-a',
|
|
36
|
+
KEY_ACCOUNT,
|
|
37
|
+
'-w',
|
|
38
|
+
b64,
|
|
39
|
+
'-U', // Update without user confirmation
|
|
40
|
+
]);
|
|
41
|
+
await add.exited;
|
|
42
|
+
return key;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Encrypt data using AES-256-GCM
|
|
46
|
+
*/
|
|
47
|
+
async function encrypt(data, keyBytes) {
|
|
48
|
+
const key = await crypto.subtle.importKey('raw', keyBytes, 'AES-GCM', false, ['encrypt']);
|
|
49
|
+
const iv = crypto.getRandomValues(new Uint8Array(12));
|
|
50
|
+
const plaintext = new TextEncoder().encode(data);
|
|
51
|
+
const ciphertext = new Uint8Array(await crypto.subtle.encrypt({ name: 'AES-GCM', iv }, key, plaintext));
|
|
52
|
+
// Combine IV + ciphertext
|
|
53
|
+
const combined = new Uint8Array(iv.length + ciphertext.length);
|
|
54
|
+
combined.set(iv, 0);
|
|
55
|
+
combined.set(ciphertext, iv.length);
|
|
56
|
+
return combined;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Decrypt data using AES-256-GCM
|
|
60
|
+
*/
|
|
61
|
+
async function decrypt(combined, keyBytes) {
|
|
62
|
+
const key = await crypto.subtle.importKey('raw', keyBytes, 'AES-GCM', false, ['decrypt']);
|
|
63
|
+
const iv = combined.slice(0, 12);
|
|
64
|
+
const ciphertext = combined.slice(12);
|
|
65
|
+
const plaintext = await crypto.subtle.decrypt({ name: 'AES-GCM', iv }, key, ciphertext);
|
|
66
|
+
return new TextDecoder().decode(plaintext);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Store auth data in macOS Keychain
|
|
70
|
+
*/
|
|
71
|
+
export async function saveAuthToKeychain(profileName, authData) {
|
|
72
|
+
const service = `${SERVICE_PREFIX}.${profileName}`;
|
|
73
|
+
const account = 'auth-token';
|
|
74
|
+
// Get or create encryption key
|
|
75
|
+
const key = await ensureEncryptionKey(service);
|
|
76
|
+
// Encrypt the auth data
|
|
77
|
+
const json = JSON.stringify(authData);
|
|
78
|
+
const encrypted = await encrypt(json, key);
|
|
79
|
+
const b64 = Buffer.from(encrypted).toString('base64');
|
|
80
|
+
// Store encrypted auth in keychain
|
|
81
|
+
// First try to delete if exists, then add
|
|
82
|
+
const del = Bun.spawn(['security', 'delete-generic-password', '-s', service, '-a', account], {
|
|
83
|
+
stderr: 'ignore',
|
|
84
|
+
});
|
|
85
|
+
await del.exited;
|
|
86
|
+
const add = Bun.spawn([
|
|
87
|
+
'security',
|
|
88
|
+
'add-generic-password',
|
|
89
|
+
'-s',
|
|
90
|
+
service,
|
|
91
|
+
'-a',
|
|
92
|
+
account,
|
|
93
|
+
'-w',
|
|
94
|
+
b64,
|
|
95
|
+
'-U',
|
|
96
|
+
]);
|
|
97
|
+
await add.exited;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Retrieve auth data from macOS Keychain
|
|
101
|
+
*/
|
|
102
|
+
export async function getAuthFromKeychain(profileName) {
|
|
103
|
+
const service = `${SERVICE_PREFIX}.${profileName}`;
|
|
104
|
+
const account = 'auth-token';
|
|
105
|
+
try {
|
|
106
|
+
// Get the encrypted auth data
|
|
107
|
+
const find = Bun.spawn(['security', 'find-generic-password', '-s', service, '-a', account, '-w'], { stderr: 'ignore' });
|
|
108
|
+
const stdout = await new Response(find.stdout).text();
|
|
109
|
+
if (stdout.length === 0) {
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
const b64 = stdout.trim();
|
|
113
|
+
const encrypted = Uint8Array.from(Buffer.from(b64, 'base64'));
|
|
114
|
+
// Get the encryption key
|
|
115
|
+
const key = await ensureEncryptionKey(service);
|
|
116
|
+
// Decrypt the auth data
|
|
117
|
+
const json = await decrypt(encrypted, key);
|
|
118
|
+
return JSON.parse(json);
|
|
119
|
+
}
|
|
120
|
+
catch {
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Delete auth data from macOS Keychain
|
|
126
|
+
*/
|
|
127
|
+
export async function deleteAuthFromKeychain(profileName) {
|
|
128
|
+
const service = `${SERVICE_PREFIX}.${profileName}`;
|
|
129
|
+
const account = 'auth-token';
|
|
130
|
+
const del = Bun.spawn(['security', 'delete-generic-password', '-s', service, '-a', account], {
|
|
131
|
+
stderr: 'ignore',
|
|
132
|
+
});
|
|
133
|
+
await del.exited;
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=keychain.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keychain.js","sourceRoot":"","sources":["../src/keychain.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Detects if a file path represents a subagent based on path structure.
|
|
3
3
|
*
|
|
4
|
-
* Subagents follow the pattern:
|
|
4
|
+
* Subagents follow the pattern: agent/parent/child/agent.ts or agent/parent/child/route.ts
|
|
5
5
|
* The path structure is currently hardcoded to 4 segments but could be made configurable later.
|
|
6
6
|
*
|
|
7
7
|
* @param filePath - The file path to analyze (can include leading './')
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Detects if a file path represents a subagent based on path structure.
|
|
3
3
|
*
|
|
4
|
-
* Subagents follow the pattern:
|
|
4
|
+
* Subagents follow the pattern: agent/parent/child/agent.ts or agent/parent/child/route.ts
|
|
5
5
|
* The path structure is currently hardcoded to 4 segments but could be made configurable later.
|
|
6
6
|
*
|
|
7
7
|
* @param filePath - The file path to analyze (can include leading './')
|
|
@@ -16,9 +16,9 @@ export function detectSubagent(filePath, srcDir) {
|
|
|
16
16
|
}
|
|
17
17
|
// Strip leading './' and split into parts, filtering out empty segments
|
|
18
18
|
const pathParts = normalizedPath.replace(/^\.\//, '').split('/').filter(Boolean);
|
|
19
|
-
// Path structure assumption: ['
|
|
19
|
+
// Path structure assumption: ['agent', 'parent', 'child', 'agent.ts' | 'route.ts' | 'route']
|
|
20
20
|
// Currently hardcoded to 4 segments - consider making configurable in the future
|
|
21
|
-
const isSubagent = pathParts.length === 4 && pathParts[0] === '
|
|
21
|
+
const isSubagent = pathParts.length === 4 && pathParts[0] === 'agent';
|
|
22
22
|
const parentName = isSubagent ? pathParts[1] : null;
|
|
23
23
|
return { isSubagent, parentName };
|
|
24
24
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"detectSubagent.js","sourceRoot":"","sources":["../../src/utils/detectSubagent.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,MAAM,UAAU,cAAc,CAC7B,QAAgB,EAChB,MAAe;IAEf,IAAI,cAAc,GAAG,QAAQ,CAAC;IAE9B,2BAA2B;IAC3B,IAAI,MAAM,IAAI,cAAc,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QACjD,cAAc,GAAG,cAAc,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACrD,CAAC;IAED,wEAAwE;IACxE,MAAM,SAAS,GAAG,cAAc,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAEjF,
|
|
1
|
+
{"version":3,"file":"detectSubagent.js","sourceRoot":"","sources":["../../src/utils/detectSubagent.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,MAAM,UAAU,cAAc,CAC7B,QAAgB,EAChB,MAAe;IAEf,IAAI,cAAc,GAAG,QAAQ,CAAC;IAE9B,2BAA2B;IAC3B,IAAI,MAAM,IAAI,cAAc,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QACjD,cAAc,GAAG,cAAc,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACrD,CAAC;IAED,wEAAwE;IACxE,MAAM,SAAS,GAAG,cAAc,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAEjF,6FAA6F;IAC7F,iFAAiF;IACjF,MAAM,UAAU,GAAG,SAAS,CAAC,MAAM,KAAK,CAAC,IAAI,SAAS,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC;IACtE,MAAM,UAAU,GAAG,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAEpD,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,CAAC;AACnC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentuity/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.69",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"author": "Agentuity employees and contributors",
|
|
6
6
|
"type": "module",
|
|
@@ -35,8 +35,8 @@
|
|
|
35
35
|
"prepublishOnly": "bun run clean && bun run build"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@agentuity/core": "0.0.
|
|
39
|
-
"@agentuity/server": "0.0.
|
|
38
|
+
"@agentuity/core": "0.0.69",
|
|
39
|
+
"@agentuity/server": "0.0.69",
|
|
40
40
|
"@datasert/cronjs-parser": "^1.4.0",
|
|
41
41
|
"@terascope/fetch-github-release": "^2.2.1",
|
|
42
42
|
"acorn-loose": "^8.5.2",
|
package/src/cli.ts
CHANGED
|
@@ -286,6 +286,10 @@ export async function createCLI(version: string): Promise<Command> {
|
|
|
286
286
|
// Custom error handling for argument/command parsing errors
|
|
287
287
|
program.configureOutput({
|
|
288
288
|
outputError: (str, write) => {
|
|
289
|
+
// Suppress "unknown option '--help'" error since we handle help flags specially
|
|
290
|
+
if (str.includes("unknown option '--help'")) {
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
289
293
|
// Intercept commander.js error messages
|
|
290
294
|
if (str.includes('too many arguments') || str.includes('unknown command')) {
|
|
291
295
|
// Extract potential command name from error context
|
|
@@ -540,6 +544,14 @@ async function registerSubcommand(
|
|
|
540
544
|
for (const nestedSub of subDef.subcommands) {
|
|
541
545
|
await registerSubcommand(cmd, nestedSub, baseCtx);
|
|
542
546
|
}
|
|
547
|
+
|
|
548
|
+
// Add a virtual 'help' subcommand
|
|
549
|
+
cmd.command('help', { hidden: true })
|
|
550
|
+
.description('Display help')
|
|
551
|
+
.action(() => {
|
|
552
|
+
cmd.help();
|
|
553
|
+
});
|
|
554
|
+
|
|
543
555
|
return;
|
|
544
556
|
}
|
|
545
557
|
|
|
@@ -1305,6 +1317,13 @@ export async function registerCommands(
|
|
|
1305
1317
|
for (const sub of cmdDef.subcommands) {
|
|
1306
1318
|
await registerSubcommand(cmd, sub, baseCtx);
|
|
1307
1319
|
}
|
|
1320
|
+
|
|
1321
|
+
// Add a virtual 'help' subcommand for commands with subcommands
|
|
1322
|
+
cmd.command('help', { hidden: true })
|
|
1323
|
+
.description('Display help')
|
|
1324
|
+
.action(() => {
|
|
1325
|
+
cmd.help();
|
|
1326
|
+
});
|
|
1308
1327
|
} else {
|
|
1309
1328
|
await registerSubcommand(
|
|
1310
1329
|
program,
|
|
@@ -27,7 +27,7 @@ Each agent folder must contain:
|
|
|
27
27
|
|
|
28
28
|
Example structure:
|
|
29
29
|
\`\`\`
|
|
30
|
-
src/
|
|
30
|
+
src/agent/
|
|
31
31
|
├── hello/
|
|
32
32
|
│ ├── agent.ts
|
|
33
33
|
│ └── route.ts
|
|
@@ -43,7 +43,7 @@ src/agents/
|
|
|
43
43
|
|
|
44
44
|
\`\`\`typescript
|
|
45
45
|
import { createAgent } from '@agentuity/runtime';
|
|
46
|
-
import {
|
|
46
|
+
import { s } from '@agentuity/schema';
|
|
47
47
|
|
|
48
48
|
const agent = createAgent({
|
|
49
49
|
metadata: {
|
|
@@ -51,11 +51,11 @@ const agent = createAgent({
|
|
|
51
51
|
description: 'What this agent does',
|
|
52
52
|
},
|
|
53
53
|
schema: {
|
|
54
|
-
input:
|
|
55
|
-
name:
|
|
56
|
-
age:
|
|
54
|
+
input: s.object({
|
|
55
|
+
name: s.string(),
|
|
56
|
+
age: s.number()
|
|
57
57
|
}),
|
|
58
|
-
output:
|
|
58
|
+
output: s.string(),
|
|
59
59
|
},
|
|
60
60
|
handler: async (c, input) => {
|
|
61
61
|
// Access context: c.app, c.config, c.logger, c.kv, c.vector, c.stream
|
|
@@ -70,7 +70,7 @@ export default agent;
|
|
|
70
70
|
|
|
71
71
|
\`\`\`typescript
|
|
72
72
|
import { createAgent, type AppState } from '@agentuity/runtime';
|
|
73
|
-
import {
|
|
73
|
+
import { s } from '@agentuity/schema';
|
|
74
74
|
|
|
75
75
|
const agent = createAgent({
|
|
76
76
|
metadata: {
|
|
@@ -78,8 +78,8 @@ const agent = createAgent({
|
|
|
78
78
|
description: 'Agent with setup and shutdown',
|
|
79
79
|
},
|
|
80
80
|
schema: {
|
|
81
|
-
input:
|
|
82
|
-
output:
|
|
81
|
+
input: s.object({ message: s.string() }),
|
|
82
|
+
output: s.object({ result: s.string() }),
|
|
83
83
|
},
|
|
84
84
|
setup: async (app: AppState) => {
|
|
85
85
|
// Initialize resources (runs once on startup)
|
|
@@ -128,7 +128,6 @@ Routes expose HTTP endpoints for your agent:
|
|
|
128
128
|
|
|
129
129
|
\`\`\`typescript
|
|
130
130
|
import { createRouter } from '@agentuity/runtime';
|
|
131
|
-
import { zValidator } from '@hono/zod-validator';
|
|
132
131
|
import agent from './agent';
|
|
133
132
|
|
|
134
133
|
const router = createRouter();
|
|
@@ -140,7 +139,7 @@ router.get('/', async (c) => {
|
|
|
140
139
|
});
|
|
141
140
|
|
|
142
141
|
// POST /agent/hello with validation
|
|
143
|
-
router.post('/',
|
|
142
|
+
router.post('/', agent.validator(), async (c) => {
|
|
144
143
|
const data = c.req.valid('json');
|
|
145
144
|
const result = await c.agent.hello.run(data);
|
|
146
145
|
return c.text(result);
|
|
@@ -211,7 +210,7 @@ Agents can have subagents organized one level deep. This is useful for grouping
|
|
|
211
210
|
### Directory Structure for Subagents
|
|
212
211
|
|
|
213
212
|
\`\`\`
|
|
214
|
-
src/
|
|
213
|
+
src/agent/
|
|
215
214
|
└── team/ # Parent agent
|
|
216
215
|
├── agent.ts # Parent agent
|
|
217
216
|
├── route.ts # Parent routes
|
|
@@ -227,17 +226,17 @@ src/agents/
|
|
|
227
226
|
|
|
228
227
|
\`\`\`typescript
|
|
229
228
|
import { createAgent } from '@agentuity/runtime';
|
|
230
|
-
import {
|
|
229
|
+
import { s } from '@agentuity/schema';
|
|
231
230
|
|
|
232
231
|
const agent = createAgent({
|
|
233
232
|
metadata: {
|
|
234
233
|
name: 'Team Manager',
|
|
235
234
|
},
|
|
236
235
|
schema: {
|
|
237
|
-
input:
|
|
238
|
-
output:
|
|
239
|
-
message:
|
|
240
|
-
timestamp:
|
|
236
|
+
input: s.object({ action: s.union([s.literal('info'), s.literal('count')]) }),
|
|
237
|
+
output: s.object({
|
|
238
|
+
message: s.string(),
|
|
239
|
+
timestamp: s.string()
|
|
241
240
|
}),
|
|
242
241
|
},
|
|
243
242
|
handler: async (ctx, { action }) => {
|
|
@@ -255,20 +254,20 @@ export default agent;
|
|
|
255
254
|
|
|
256
255
|
\`\`\`typescript
|
|
257
256
|
import { createAgent } from '@agentuity/runtime';
|
|
258
|
-
import {
|
|
257
|
+
import { s } from '@agentuity/schema';
|
|
259
258
|
|
|
260
259
|
const agent = createAgent({
|
|
261
260
|
metadata: {
|
|
262
261
|
name: 'Members Subagent',
|
|
263
262
|
},
|
|
264
263
|
schema: {
|
|
265
|
-
input:
|
|
266
|
-
action:
|
|
267
|
-
name:
|
|
264
|
+
input: s.object({
|
|
265
|
+
action: s.union([s.literal('list'), s.literal('add'), s.literal('remove')]),
|
|
266
|
+
name: s.optional(s.string()),
|
|
268
267
|
}),
|
|
269
|
-
output:
|
|
270
|
-
members:
|
|
271
|
-
parentInfo:
|
|
268
|
+
output: s.object({
|
|
269
|
+
members: s.array(s.string()),
|
|
270
|
+
parentInfo: s.optional(s.string()),
|
|
272
271
|
}),
|
|
273
272
|
},
|
|
274
273
|
handler: async (ctx, { action, name }) => {
|
|
@@ -331,7 +330,7 @@ Routes for subagents automatically mount under the parent path:
|
|
|
331
330
|
- Each agent folder name becomes the agent's route name (e.g., \`hello/\` → \`/agent/hello\`)
|
|
332
331
|
- **agent.ts** must export default the agent instance
|
|
333
332
|
- **route.ts** must export default the router instance
|
|
334
|
-
- Input/output schemas are enforced with
|
|
333
|
+
- Input/output schemas are enforced with @agentuity/schema validation
|
|
335
334
|
- Setup return value type automatically flows to ctx.config (fully typed)
|
|
336
335
|
- Use c.logger for logging, not console.log
|
|
337
336
|
- Agent names in routes are accessed via c.agent.{folderName}
|
package/src/cmd/ai/prompt/api.ts
CHANGED
|
@@ -26,7 +26,7 @@ Each API folder must contain:
|
|
|
26
26
|
|
|
27
27
|
Example structure:
|
|
28
28
|
\`\`\`
|
|
29
|
-
src/
|
|
29
|
+
src/web/
|
|
30
30
|
├── status/
|
|
31
31
|
│ └── route.ts
|
|
32
32
|
├── users/
|
|
@@ -66,18 +66,21 @@ export default router;
|
|
|
66
66
|
|
|
67
67
|
\`\`\`typescript
|
|
68
68
|
import { createRouter } from '@agentuity/runtime';
|
|
69
|
-
import {
|
|
70
|
-
import { z } from 'zod';
|
|
69
|
+
import { s } from '@agentuity/schema';
|
|
71
70
|
|
|
72
71
|
const router = createRouter();
|
|
73
72
|
|
|
74
|
-
const createUserSchema =
|
|
75
|
-
name:
|
|
76
|
-
email:
|
|
77
|
-
age:
|
|
73
|
+
const createUserSchema = s.object({
|
|
74
|
+
name: s.string(),
|
|
75
|
+
email: s.string(),
|
|
76
|
+
age: s.number(),
|
|
78
77
|
});
|
|
79
78
|
|
|
80
|
-
|
|
79
|
+
const validator = createRouter.validator({
|
|
80
|
+
input: createUserSchema,
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
router.post('/', validator, async (c) => {
|
|
81
84
|
const data = c.req.valid('json');
|
|
82
85
|
// data is fully typed: { name: string, email: string, age: number }
|
|
83
86
|
return c.json({
|
|
@@ -267,7 +270,7 @@ return c.json({ data: 'value' }, 200, {
|
|
|
267
270
|
- **route.ts** must export default the router instance
|
|
268
271
|
- Use c.var.logger for logging, not console.log
|
|
269
272
|
- All agents are accessible via c.agent.{agentName}
|
|
270
|
-
- Validation should use
|
|
273
|
+
- Validation should use @agentuity/schema or any Standard Schema compatible library
|
|
271
274
|
- Return appropriate HTTP status codes
|
|
272
275
|
- APIs run at \`/api/{folderName}\` by default
|
|
273
276
|
`;
|
package/src/cmd/build/ast.ts
CHANGED
|
@@ -928,14 +928,14 @@ export async function parseRoute(
|
|
|
928
928
|
|
|
929
929
|
// Detect if this is a subagent route and build proper path
|
|
930
930
|
const relativePath = relative(rootDir, dir)
|
|
931
|
-
.replace(/^src\/
|
|
932
|
-
.replace(/^src\/
|
|
931
|
+
.replace(/^src\/agent\//, '')
|
|
932
|
+
.replace(/^src\/web\//, '');
|
|
933
933
|
const pathParts = relativePath.split('/').filter(Boolean);
|
|
934
|
-
const isSubagent = pathParts.length === 2 && filename.includes('src/
|
|
934
|
+
const isSubagent = pathParts.length === 2 && filename.includes('src/agent');
|
|
935
935
|
const routeName = isSubagent ? pathParts.join('/') : name;
|
|
936
936
|
|
|
937
937
|
const routes: RouteDefinition = [];
|
|
938
|
-
const routePrefix = filename.includes('src/
|
|
938
|
+
const routePrefix = filename.includes('src/agent') ? '/agent' : '/api';
|
|
939
939
|
|
|
940
940
|
try {
|
|
941
941
|
for (const body of ast.body) {
|
package/src/cmd/build/bundler.ts
CHANGED
|
@@ -85,10 +85,10 @@ export async function bundle({
|
|
|
85
85
|
|
|
86
86
|
const appEntrypoints: string[] = [];
|
|
87
87
|
|
|
88
|
-
for (const folder of ['
|
|
88
|
+
for (const folder of ['web', 'agent']) {
|
|
89
89
|
const dir = join(srcDir, folder);
|
|
90
90
|
if (!existsSync(dir)) {
|
|
91
|
-
if (folder === '
|
|
91
|
+
if (folder === 'agent') {
|
|
92
92
|
throw new AgentsDirNotFoundError({ message: `Expected directory not found: ${dir}` });
|
|
93
93
|
}
|
|
94
94
|
continue;
|
package/src/cmd/build/plugin.ts
CHANGED
|
@@ -142,7 +142,7 @@ function generateAgentRegistry(srcDir: string, agentInfo: Array<Record<string, s
|
|
|
142
142
|
.map(({ name, path, parent }) => {
|
|
143
143
|
const fullName = parent ? `${parent}.${name}` : name;
|
|
144
144
|
const camelName = toCamelCase(fullName.replace('.', '_'));
|
|
145
|
-
const relativePath = path.replace(/^\.\/
|
|
145
|
+
const relativePath = path.replace(/^\.\/agent\//, './');
|
|
146
146
|
return `import ${camelName}Agent from '${relativePath}';`;
|
|
147
147
|
})
|
|
148
148
|
.join('\n');
|
|
@@ -340,11 +340,11 @@ ${reactAgentTypes}
|
|
|
340
340
|
}
|
|
341
341
|
`;
|
|
342
342
|
|
|
343
|
-
const agentsDir = join(srcDir, '
|
|
343
|
+
const agentsDir = join(srcDir, 'agent');
|
|
344
344
|
const registryPath = join(agentsDir, 'registry.generated.ts');
|
|
345
345
|
const legacyTypesPath = join(agentsDir, 'types.generated.d.ts');
|
|
346
346
|
|
|
347
|
-
// Ensure
|
|
347
|
+
// Ensure agent directory exists
|
|
348
348
|
if (!existsSync(agentsDir)) {
|
|
349
349
|
mkdirSync(agentsDir, { recursive: true });
|
|
350
350
|
}
|
|
@@ -435,7 +435,7 @@ const AgentuityBundler: BunPlugin = {
|
|
|
435
435
|
newsource = ns;
|
|
436
436
|
|
|
437
437
|
// Detect if this is a subagent by checking path structure
|
|
438
|
-
// Note: Path structure assumption - 4 segments:
|
|
438
|
+
// Note: Path structure assumption - 4 segments: agent/parent/child/agent.ts
|
|
439
439
|
const { isSubagent, parentName } = detectSubagent(args.path, srcDir);
|
|
440
440
|
if (isSubagent && parentName) {
|
|
441
441
|
md.set('parent', parentName);
|
|
@@ -519,16 +519,11 @@ const AgentuityBundler: BunPlugin = {
|
|
|
519
519
|
// Detect if this is a subagent route using shared utility
|
|
520
520
|
const { isSubagent, parentName } = detectSubagent(route);
|
|
521
521
|
|
|
522
|
-
const agentPath = route
|
|
523
|
-
.replace(/\/route$/, '/*')
|
|
524
|
-
.replace('/agents', '/agent')
|
|
525
|
-
.replace('./', '/');
|
|
522
|
+
const agentPath = route.replace(/\/route$/, '/*').replace('./', '/');
|
|
526
523
|
const routePath = route
|
|
527
524
|
.replace(/\/route$/, '')
|
|
528
|
-
.replace('/
|
|
529
|
-
.replace('/
|
|
530
|
-
.replace('/agents', '/agent')
|
|
531
|
-
.replace('/agents', '/agent')
|
|
525
|
+
.replace('/web/', '/api/')
|
|
526
|
+
.replace('/web', '/api')
|
|
532
527
|
.replace('./', '/');
|
|
533
528
|
|
|
534
529
|
const definitions = await parseRoute(
|
|
@@ -575,7 +570,7 @@ const AgentuityBundler: BunPlugin = {
|
|
|
575
570
|
if (hasAgent) {
|
|
576
571
|
const agentRegistrationName =
|
|
577
572
|
isSubagent && parentName ? `${parentName}.${name}` : name;
|
|
578
|
-
// Build evals path from agent path (e.g., '
|
|
573
|
+
// Build evals path from agent path (e.g., 'agent/eval/agent' -> 'agent/eval/eval.ts')
|
|
579
574
|
const agentDirPath = agent.replace(/\/agent$/, '');
|
|
580
575
|
const evalsPath = join(srcDir, agentDirPath, 'eval.ts');
|
|
581
576
|
const evalsImport = existsSync(evalsPath)
|
|
@@ -694,7 +689,7 @@ import { readFileSync, existsSync } from 'node:fs';
|
|
|
694
689
|
: join(rootDir, filename);
|
|
695
690
|
|
|
696
691
|
// Convert to path relative to srcDir like route-based agents
|
|
697
|
-
// e.g., /path/to/src/
|
|
692
|
+
// e.g., /path/to/src/agent/lifecycle/agent.ts -> ./agent/lifecycle/agent
|
|
698
693
|
const agentPath = absolutePath.replace(srcDir, '.').replace('.ts', '');
|
|
699
694
|
|
|
700
695
|
// Extract folder name as agent name (same as route-based logic)
|
package/src/cmd/dev/index.ts
CHANGED
|
@@ -1002,10 +1002,10 @@ export const command = createCommand({
|
|
|
1002
1002
|
statSync(absPath).isDirectory() &&
|
|
1003
1003
|
readdirSync(absPath).length === 0
|
|
1004
1004
|
) {
|
|
1005
|
-
if (changedFile?.startsWith('src/
|
|
1005
|
+
if (changedFile?.startsWith('src/agent/')) {
|
|
1006
1006
|
logger.debug('agent directory created: %s', changedFile);
|
|
1007
1007
|
createAgentTemplates(absPath);
|
|
1008
|
-
} else if (changedFile?.startsWith('src/
|
|
1008
|
+
} else if (changedFile?.startsWith('src/web/')) {
|
|
1009
1009
|
logger.debug('api directory created: %s', changedFile);
|
|
1010
1010
|
createAPITemplates(absPath);
|
|
1011
1011
|
}
|
package/src/cmd/dev/templates.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { basename, join } from 'node:path';
|
|
|
4
4
|
import { toCamelCase } from '../../utils/string';
|
|
5
5
|
|
|
6
6
|
const newAgentTemplate = (name: string) => `import { createAgent } from '@agentuity/runtime';
|
|
7
|
-
import {
|
|
7
|
+
import { s } from '@agentuity/schema';
|
|
8
8
|
|
|
9
9
|
const agent = createAgent({
|
|
10
10
|
metadata: {
|
|
@@ -12,8 +12,8 @@ const agent = createAgent({
|
|
|
12
12
|
description: 'Add your agent description here',
|
|
13
13
|
},
|
|
14
14
|
schema: {
|
|
15
|
-
input:
|
|
16
|
-
output:
|
|
15
|
+
input: s.string(),
|
|
16
|
+
output: s.string(),
|
|
17
17
|
},
|
|
18
18
|
handler: async (_c, input) => {
|
|
19
19
|
// TODO: add your code here
|
|
@@ -27,6 +27,7 @@ export default agent;
|
|
|
27
27
|
const newAgentRouteTemplate = (name: string) => {
|
|
28
28
|
const camelName = toCamelCase(name);
|
|
29
29
|
return `import { createRouter } from '@agentuity/runtime';
|
|
30
|
+
import agent from './agent';
|
|
30
31
|
|
|
31
32
|
const router = createRouter();
|
|
32
33
|
|
|
@@ -36,6 +37,12 @@ router.get('/', async (c) => {
|
|
|
36
37
|
return c.text(output);
|
|
37
38
|
});
|
|
38
39
|
|
|
40
|
+
router.post('/', agent.validator(), async (c) => {
|
|
41
|
+
const data = c.req.valid('json');
|
|
42
|
+
const output = await c.agent.${camelName}.run(data);
|
|
43
|
+
return c.json(output);
|
|
44
|
+
});
|
|
45
|
+
|
|
39
46
|
export default router;
|
|
40
47
|
|
|
41
48
|
`;
|
|
@@ -281,22 +281,22 @@ export async function setupProject(options: SetupOptions): Promise<void> {
|
|
|
281
281
|
}
|
|
282
282
|
|
|
283
283
|
// generate and write AGENTS.md for each of the main folders
|
|
284
|
-
const
|
|
285
|
-
if (existsSync(
|
|
286
|
-
const
|
|
287
|
-
await Bun.write(
|
|
284
|
+
const agentDir = join(dest, 'src', 'agent');
|
|
285
|
+
if (existsSync(agentDir)) {
|
|
286
|
+
const agentAPIFile = join(agentDir, 'AGENTS.md');
|
|
287
|
+
await Bun.write(agentAPIFile, generateAgentPrompt());
|
|
288
288
|
}
|
|
289
289
|
|
|
290
|
-
const
|
|
291
|
-
if (existsSync(
|
|
292
|
-
const
|
|
293
|
-
await Bun.write(
|
|
290
|
+
const apiDir = join(dest, 'src', 'api');
|
|
291
|
+
if (existsSync(apiDir)) {
|
|
292
|
+
const agentAPIFile = join(apiDir, 'AGENTS.md');
|
|
293
|
+
await Bun.write(agentAPIFile, generateAPIPrompt());
|
|
294
294
|
}
|
|
295
295
|
|
|
296
296
|
const webDir = join(dest, 'src', 'web');
|
|
297
297
|
if (existsSync(webDir)) {
|
|
298
|
-
const
|
|
299
|
-
await Bun.write(
|
|
298
|
+
const webFile = join(webDir, 'AGENTS.md');
|
|
299
|
+
await Bun.write(webFile, generateWebPrompt());
|
|
300
300
|
}
|
|
301
301
|
}
|
|
302
302
|
|