@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.
Files changed (63) hide show
  1. package/bin/cli.ts +20 -8
  2. package/dist/cli.d.ts.map +1 -1
  3. package/dist/cli.js +16 -0
  4. package/dist/cli.js.map +1 -1
  5. package/dist/cmd/ai/prompt/agent.d.ts.map +1 -1
  6. package/dist/cmd/ai/prompt/agent.js +24 -25
  7. package/dist/cmd/ai/prompt/agent.js.map +1 -1
  8. package/dist/cmd/ai/prompt/api.d.ts.map +1 -1
  9. package/dist/cmd/ai/prompt/api.js +12 -9
  10. package/dist/cmd/ai/prompt/api.js.map +1 -1
  11. package/dist/cmd/build/ast.js +4 -4
  12. package/dist/cmd/build/ast.js.map +1 -1
  13. package/dist/cmd/build/bundler.js +2 -2
  14. package/dist/cmd/build/bundler.js.map +1 -1
  15. package/dist/cmd/build/plugin.d.ts.map +1 -1
  16. package/dist/cmd/build/plugin.js +9 -14
  17. package/dist/cmd/build/plugin.js.map +1 -1
  18. package/dist/cmd/dev/index.js +2 -2
  19. package/dist/cmd/dev/index.js.map +1 -1
  20. package/dist/cmd/dev/templates.d.ts.map +1 -1
  21. package/dist/cmd/dev/templates.js +10 -3
  22. package/dist/cmd/dev/templates.js.map +1 -1
  23. package/dist/cmd/project/download.js +10 -10
  24. package/dist/cmd/project/download.js.map +1 -1
  25. package/dist/config.d.ts.map +1 -1
  26. package/dist/config.js +48 -87
  27. package/dist/config.js.map +1 -1
  28. package/dist/keychain.d.ts +31 -0
  29. package/dist/keychain.d.ts.map +1 -0
  30. package/dist/keychain.js +135 -0
  31. package/dist/keychain.js.map +1 -0
  32. package/dist/utils/detectSubagent.d.ts +1 -1
  33. package/dist/utils/detectSubagent.js +3 -3
  34. package/dist/utils/detectSubagent.js.map +1 -1
  35. package/package.json +3 -3
  36. package/src/cli.ts +19 -0
  37. package/src/cmd/ai/prompt/agent.ts +24 -25
  38. package/src/cmd/ai/prompt/api.ts +12 -9
  39. package/src/cmd/build/ast.ts +4 -4
  40. package/src/cmd/build/bundler.ts +2 -2
  41. package/src/cmd/build/plugin.ts +9 -14
  42. package/src/cmd/dev/index.ts +2 -2
  43. package/src/cmd/dev/templates.ts +10 -3
  44. package/src/cmd/project/download.ts +10 -10
  45. package/src/config.ts +54 -97
  46. package/src/keychain.ts +176 -0
  47. package/src/utils/detectSubagent.ts +3 -3
  48. package/dist/cmd/build/ast.test.d.ts +0 -2
  49. package/dist/cmd/build/ast.test.d.ts.map +0 -1
  50. package/dist/cmd/build/ast.test.js +0 -339
  51. package/dist/cmd/build/ast.test.js.map +0 -1
  52. package/dist/cmd/build/fix-duplicate-exports.test.d.ts +0 -2
  53. package/dist/cmd/build/fix-duplicate-exports.test.d.ts.map +0 -1
  54. package/dist/cmd/build/fix-duplicate-exports.test.js +0 -300
  55. package/dist/cmd/build/fix-duplicate-exports.test.js.map +0 -1
  56. package/dist/crypto/box.test.d.ts +0 -2
  57. package/dist/crypto/box.test.d.ts.map +0 -1
  58. package/dist/crypto/box.test.js +0 -317
  59. package/dist/crypto/box.test.js.map +0 -1
  60. package/dist/env-util.test.d.ts +0 -2
  61. package/dist/env-util.test.d.ts.map +0 -1
  62. package/dist/env-util.test.js +0 -146
  63. package/dist/env-util.test.js.map +0 -1
@@ -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: agents/parent/child/agent.ts or agents/parent/child/route.ts
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: agents/parent/child/agent.ts or agents/parent/child/route.ts
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: ['agents', 'parent', 'child', 'agent.ts' | 'route.ts' | 'route']
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] === 'agents';
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,8FAA8F;IAC9F,iFAAiF;IACjF,MAAM,UAAU,GAAG,SAAS,CAAC,MAAM,KAAK,CAAC,IAAI,SAAS,CAAC,CAAC,CAAC,KAAK,QAAQ,CAAC;IACvE,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"}
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.67",
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.67",
39
- "@agentuity/server": "0.0.67",
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/agents/
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 { z } from 'zod';
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: z.object({
55
- name: z.string(),
56
- age: z.number()
54
+ input: s.object({
55
+ name: s.string(),
56
+ age: s.number()
57
57
  }),
58
- output: z.string(),
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 { z } from 'zod';
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: z.object({ message: z.string() }),
82
- output: z.object({ result: z.string() }),
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('/', zValidator('json', agent.inputSchema), async (c) => {
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/agents/
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 { z } from 'zod';
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: z.object({ action: z.enum(['info', 'count']) }),
238
- output: z.object({
239
- message: z.string(),
240
- timestamp: z.string()
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 { z } from 'zod';
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: z.object({
266
- action: z.enum(['list', 'add', 'remove']),
267
- name: z.string().optional(),
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: z.object({
270
- members: z.array(z.string()),
271
- parentInfo: z.string().optional(),
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 Zod validation
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}
@@ -26,7 +26,7 @@ Each API folder must contain:
26
26
 
27
27
  Example structure:
28
28
  \`\`\`
29
- src/apis/
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 { zValidator } from '@hono/zod-validator';
70
- import { z } from 'zod';
69
+ import { s } from '@agentuity/schema';
71
70
 
72
71
  const router = createRouter();
73
72
 
74
- const createUserSchema = z.object({
75
- name: z.string(),
76
- email: z.string().email(),
77
- age: z.number().min(0),
73
+ const createUserSchema = s.object({
74
+ name: s.string(),
75
+ email: s.string(),
76
+ age: s.number(),
78
77
  });
79
78
 
80
- router.post('/', zValidator('json', createUserSchema), async (c) => {
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 zValidator with Zod schemas or any Standard Schema compatible library
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
  `;
@@ -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\/agents\//, '')
932
- .replace(/^src\/apis\//, '');
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/agents');
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/agents') ? '/agent' : '/api';
938
+ const routePrefix = filename.includes('src/agent') ? '/agent' : '/api';
939
939
 
940
940
  try {
941
941
  for (const body of ast.body) {
@@ -85,10 +85,10 @@ export async function bundle({
85
85
 
86
86
  const appEntrypoints: string[] = [];
87
87
 
88
- for (const folder of ['apis', 'agents']) {
88
+ for (const folder of ['web', 'agent']) {
89
89
  const dir = join(srcDir, folder);
90
90
  if (!existsSync(dir)) {
91
- if (folder === 'agents') {
91
+ if (folder === 'agent') {
92
92
  throw new AgentsDirNotFoundError({ message: `Expected directory not found: ${dir}` });
93
93
  }
94
94
  continue;
@@ -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(/^\.\/agents\//, './');
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, 'agents');
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 agents directory exists
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: agents/parent/child/agent.ts
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('/apis/', '/api/')
529
- .replace('/apis', '/api')
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., 'agents/eval/agent' -> 'agents/eval/eval.ts')
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/agents/lifecycle/agent.ts -> ./agents/lifecycle/agent
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)
@@ -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/agents/')) {
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/apis/')) {
1008
+ } else if (changedFile?.startsWith('src/web/')) {
1009
1009
  logger.debug('api directory created: %s', changedFile);
1010
1010
  createAPITemplates(absPath);
1011
1011
  }
@@ -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 { z } from 'zod';
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: z.string(),
16
- output: z.string(),
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 agentsDir = join(dest, 'src', 'agents');
285
- if (existsSync(agentsDir)) {
286
- const agentsAPIFile = join(agentsDir, 'AGENTS.md');
287
- await Bun.write(agentsAPIFile, generateAgentPrompt());
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 apisDir = join(dest, 'src', 'apis');
291
- if (existsSync(apisDir)) {
292
- const agentsAPIsFile = join(apisDir, 'AGENTS.md');
293
- await Bun.write(agentsAPIsFile, generateAPIPrompt());
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 agentsWebFile = join(webDir, 'AGENTS.md');
299
- await Bun.write(agentsWebFile, generateWebPrompt());
298
+ const webFile = join(webDir, 'AGENTS.md');
299
+ await Bun.write(webFile, generateWebPrompt());
300
300
  }
301
301
  }
302
302