@agentuity/cli 0.0.100 → 0.0.102

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 (264) hide show
  1. package/AGENTS.md +19 -188
  2. package/bin/cli.ts +13 -6
  3. package/dist/api.d.ts +1 -0
  4. package/dist/api.d.ts.map +1 -1
  5. package/dist/api.js +1 -1
  6. package/dist/api.js.map +1 -1
  7. package/dist/cli.d.ts.map +1 -1
  8. package/dist/cli.js +41 -12
  9. package/dist/cli.js.map +1 -1
  10. package/dist/cmd/ai/index.d.ts.map +1 -1
  11. package/dist/cmd/ai/index.js +6 -1
  12. package/dist/cmd/ai/index.js.map +1 -1
  13. package/dist/cmd/ai/prompt/agent.d.ts +7 -0
  14. package/dist/cmd/ai/prompt/agent.d.ts.map +1 -1
  15. package/dist/cmd/ai/prompt/agent.js +12 -323
  16. package/dist/cmd/ai/prompt/agent.js.map +1 -1
  17. package/dist/cmd/ai/prompt/api.d.ts +7 -0
  18. package/dist/cmd/ai/prompt/api.d.ts.map +1 -1
  19. package/dist/cmd/ai/prompt/api.js +12 -260
  20. package/dist/cmd/ai/prompt/api.js.map +1 -1
  21. package/dist/cmd/ai/prompt/version.d.ts +35 -0
  22. package/dist/cmd/ai/prompt/version.d.ts.map +1 -0
  23. package/dist/cmd/ai/prompt/version.js +55 -0
  24. package/dist/cmd/ai/prompt/version.js.map +1 -0
  25. package/dist/cmd/ai/prompt/web.d.ts +7 -0
  26. package/dist/cmd/ai/prompt/web.d.ts.map +1 -1
  27. package/dist/cmd/ai/prompt/web.js +12 -283
  28. package/dist/cmd/ai/prompt/web.js.map +1 -1
  29. package/dist/cmd/ai/skills/generate.d.ts +3 -0
  30. package/dist/cmd/ai/skills/generate.d.ts.map +1 -0
  31. package/dist/cmd/ai/skills/generate.js +65 -0
  32. package/dist/cmd/ai/skills/generate.js.map +1 -0
  33. package/dist/cmd/ai/skills/generator.d.ts +4 -0
  34. package/dist/cmd/ai/skills/generator.d.ts.map +1 -0
  35. package/dist/cmd/ai/skills/generator.js +402 -0
  36. package/dist/cmd/ai/skills/generator.js.map +1 -0
  37. package/dist/cmd/ai/skills/index.d.ts +4 -0
  38. package/dist/cmd/ai/skills/index.d.ts.map +1 -0
  39. package/dist/cmd/ai/skills/index.js +21 -0
  40. package/dist/cmd/ai/skills/index.js.map +1 -0
  41. package/dist/cmd/auth/signup.d.ts.map +1 -1
  42. package/dist/cmd/auth/signup.js +1 -0
  43. package/dist/cmd/auth/signup.js.map +1 -1
  44. package/dist/cmd/build/ast.d.ts +2 -1
  45. package/dist/cmd/build/ast.d.ts.map +1 -1
  46. package/dist/cmd/build/ast.js +135 -47
  47. package/dist/cmd/build/ast.js.map +1 -1
  48. package/dist/cmd/build/entry-generator.d.ts.map +1 -1
  49. package/dist/cmd/build/entry-generator.js +255 -188
  50. package/dist/cmd/build/entry-generator.js.map +1 -1
  51. package/dist/cmd/build/vite/agent-discovery.d.ts.map +1 -1
  52. package/dist/cmd/build/vite/agent-discovery.js +103 -45
  53. package/dist/cmd/build/vite/agent-discovery.js.map +1 -1
  54. package/dist/cmd/build/vite/bun-dev-server.d.ts +7 -1
  55. package/dist/cmd/build/vite/bun-dev-server.d.ts.map +1 -1
  56. package/dist/cmd/build/vite/bun-dev-server.js +52 -26
  57. package/dist/cmd/build/vite/bun-dev-server.js.map +1 -1
  58. package/dist/cmd/build/vite/docs-generator.d.ts +13 -0
  59. package/dist/cmd/build/vite/docs-generator.d.ts.map +1 -0
  60. package/dist/cmd/build/vite/docs-generator.js +81 -0
  61. package/dist/cmd/build/vite/docs-generator.js.map +1 -0
  62. package/dist/cmd/build/vite/index.d.ts +3 -3
  63. package/dist/cmd/build/vite/index.d.ts.map +1 -1
  64. package/dist/cmd/build/vite/index.js +9 -7
  65. package/dist/cmd/build/vite/index.js.map +1 -1
  66. package/dist/cmd/build/vite/lifecycle-generator.d.ts +1 -1
  67. package/dist/cmd/build/vite/lifecycle-generator.d.ts.map +1 -1
  68. package/dist/cmd/build/vite/lifecycle-generator.js +19 -5
  69. package/dist/cmd/build/vite/lifecycle-generator.js.map +1 -1
  70. package/dist/cmd/build/vite/metadata-generator.d.ts.map +1 -1
  71. package/dist/cmd/build/vite/metadata-generator.js +203 -7
  72. package/dist/cmd/build/vite/metadata-generator.js.map +1 -1
  73. package/dist/cmd/build/vite/prompt-generator.d.ts +23 -0
  74. package/dist/cmd/build/vite/prompt-generator.d.ts.map +1 -0
  75. package/dist/cmd/build/vite/prompt-generator.js +123 -0
  76. package/dist/cmd/build/vite/prompt-generator.js.map +1 -0
  77. package/dist/cmd/build/vite/registry-generator.d.ts +3 -3
  78. package/dist/cmd/build/vite/registry-generator.d.ts.map +1 -1
  79. package/dist/cmd/build/vite/registry-generator.js +644 -103
  80. package/dist/cmd/build/vite/registry-generator.js.map +1 -1
  81. package/dist/cmd/build/vite/route-discovery.d.ts +4 -0
  82. package/dist/cmd/build/vite/route-discovery.d.ts.map +1 -1
  83. package/dist/cmd/build/vite/route-discovery.js.map +1 -1
  84. package/dist/cmd/build/vite/server-bundler.d.ts +4 -0
  85. package/dist/cmd/build/vite/server-bundler.d.ts.map +1 -1
  86. package/dist/cmd/build/vite/server-bundler.js +63 -17
  87. package/dist/cmd/build/vite/server-bundler.js.map +1 -1
  88. package/dist/cmd/build/vite/vite-asset-server-config.d.ts.map +1 -1
  89. package/dist/cmd/build/vite/vite-asset-server-config.js +4 -0
  90. package/dist/cmd/build/vite/vite-asset-server-config.js.map +1 -1
  91. package/dist/cmd/build/vite/vite-builder.d.ts +1 -1
  92. package/dist/cmd/build/vite/vite-builder.d.ts.map +1 -1
  93. package/dist/cmd/build/vite/vite-builder.js +118 -96
  94. package/dist/cmd/build/vite/vite-builder.js.map +1 -1
  95. package/dist/cmd/build/vite-bundler.js +6 -6
  96. package/dist/cmd/build/vite-bundler.js.map +1 -1
  97. package/dist/cmd/cloud/deploy.d.ts.map +1 -1
  98. package/dist/cmd/cloud/deploy.js +89 -32
  99. package/dist/cmd/cloud/deploy.js.map +1 -1
  100. package/dist/cmd/cloud/keyvalue/create-namespace.d.ts.map +1 -1
  101. package/dist/cmd/cloud/keyvalue/create-namespace.js +3 -1
  102. package/dist/cmd/cloud/keyvalue/create-namespace.js.map +1 -1
  103. package/dist/cmd/cloud/keyvalue/delete-namespace.d.ts.map +1 -1
  104. package/dist/cmd/cloud/keyvalue/delete-namespace.js +3 -1
  105. package/dist/cmd/cloud/keyvalue/delete-namespace.js.map +1 -1
  106. package/dist/cmd/cloud/keyvalue/delete.d.ts.map +1 -1
  107. package/dist/cmd/cloud/keyvalue/delete.js +3 -1
  108. package/dist/cmd/cloud/keyvalue/delete.js.map +1 -1
  109. package/dist/cmd/cloud/keyvalue/set.d.ts.map +1 -1
  110. package/dist/cmd/cloud/keyvalue/set.js +4 -2
  111. package/dist/cmd/cloud/keyvalue/set.js.map +1 -1
  112. package/dist/cmd/cloud/stream/get.d.ts.map +1 -1
  113. package/dist/cmd/cloud/stream/get.js +2 -13
  114. package/dist/cmd/cloud/stream/get.js.map +1 -1
  115. package/dist/cmd/cloud/vector/delete-namespace.d.ts +3 -0
  116. package/dist/cmd/cloud/vector/delete-namespace.d.ts.map +1 -0
  117. package/dist/cmd/cloud/vector/delete-namespace.js +77 -0
  118. package/dist/cmd/cloud/vector/delete-namespace.js.map +1 -0
  119. package/dist/cmd/cloud/vector/index.d.ts.map +1 -1
  120. package/dist/cmd/cloud/vector/index.js +21 -4
  121. package/dist/cmd/cloud/vector/index.js.map +1 -1
  122. package/dist/cmd/cloud/vector/list-namespaces.d.ts +3 -0
  123. package/dist/cmd/cloud/vector/list-namespaces.d.ts.map +1 -0
  124. package/dist/cmd/cloud/vector/list-namespaces.js +42 -0
  125. package/dist/cmd/cloud/vector/list-namespaces.js.map +1 -0
  126. package/dist/cmd/cloud/vector/stats.d.ts +3 -0
  127. package/dist/cmd/cloud/vector/stats.d.ts.map +1 -0
  128. package/dist/cmd/cloud/vector/stats.js +142 -0
  129. package/dist/cmd/cloud/vector/stats.js.map +1 -0
  130. package/dist/cmd/cloud/vector/upsert.d.ts +3 -0
  131. package/dist/cmd/cloud/vector/upsert.d.ts.map +1 -0
  132. package/dist/cmd/cloud/vector/upsert.js +192 -0
  133. package/dist/cmd/cloud/vector/upsert.js.map +1 -0
  134. package/dist/cmd/dev/file-watcher.d.ts.map +1 -1
  135. package/dist/cmd/dev/file-watcher.js +94 -33
  136. package/dist/cmd/dev/file-watcher.js.map +1 -1
  137. package/dist/cmd/dev/index.d.ts.map +1 -1
  138. package/dist/cmd/dev/index.js +298 -61
  139. package/dist/cmd/dev/index.js.map +1 -1
  140. package/dist/cmd/dev/skills.d.ts +10 -0
  141. package/dist/cmd/dev/skills.d.ts.map +1 -0
  142. package/dist/cmd/dev/skills.js +57 -0
  143. package/dist/cmd/dev/skills.js.map +1 -0
  144. package/dist/cmd/dev/sync.d.ts.map +1 -1
  145. package/dist/cmd/dev/sync.js +19 -3
  146. package/dist/cmd/dev/sync.js.map +1 -1
  147. package/dist/cmd/index.d.ts.map +1 -1
  148. package/dist/cmd/index.js +1 -0
  149. package/dist/cmd/index.js.map +1 -1
  150. package/dist/cmd/project/create.d.ts.map +1 -1
  151. package/dist/cmd/project/create.js +3 -0
  152. package/dist/cmd/project/create.js.map +1 -1
  153. package/dist/cmd/project/template-flow.d.ts +1 -0
  154. package/dist/cmd/project/template-flow.d.ts.map +1 -1
  155. package/dist/cmd/project/template-flow.js +30 -5
  156. package/dist/cmd/project/template-flow.js.map +1 -1
  157. package/dist/cmd/setup/index.d.ts.map +1 -1
  158. package/dist/cmd/setup/index.js +1 -0
  159. package/dist/cmd/setup/index.js.map +1 -1
  160. package/dist/cmd/upgrade/index.d.ts +15 -0
  161. package/dist/cmd/upgrade/index.d.ts.map +1 -1
  162. package/dist/cmd/upgrade/index.js +59 -4
  163. package/dist/cmd/upgrade/index.js.map +1 -1
  164. package/dist/config.d.ts.map +1 -1
  165. package/dist/config.js +8 -0
  166. package/dist/config.js.map +1 -1
  167. package/dist/domain.d.ts +45 -0
  168. package/dist/domain.d.ts.map +1 -0
  169. package/dist/domain.js +200 -0
  170. package/dist/domain.js.map +1 -0
  171. package/dist/index.d.ts +0 -1
  172. package/dist/index.d.ts.map +1 -1
  173. package/dist/index.js +0 -1
  174. package/dist/index.js.map +1 -1
  175. package/dist/schema-generator.d.ts +2 -0
  176. package/dist/schema-generator.d.ts.map +1 -1
  177. package/dist/schema-generator.js +18 -0
  178. package/dist/schema-generator.js.map +1 -1
  179. package/dist/steps.d.ts +1 -1
  180. package/dist/steps.d.ts.map +1 -1
  181. package/dist/steps.js +16 -5
  182. package/dist/steps.js.map +1 -1
  183. package/dist/tui/prompt.d.ts +1 -2
  184. package/dist/tui/prompt.d.ts.map +1 -1
  185. package/dist/tui/prompt.js +8 -4
  186. package/dist/tui/prompt.js.map +1 -1
  187. package/dist/tui.d.ts +16 -0
  188. package/dist/tui.d.ts.map +1 -1
  189. package/dist/tui.js +23 -2
  190. package/dist/tui.js.map +1 -1
  191. package/dist/types.d.ts +9 -2
  192. package/dist/types.d.ts.map +1 -1
  193. package/dist/types.js +3 -3
  194. package/dist/types.js.map +1 -1
  195. package/package.json +5 -8
  196. package/src/api.ts +1 -1
  197. package/src/cli.ts +47 -12
  198. package/src/cmd/ai/index.ts +6 -1
  199. package/src/cmd/ai/prompt/agent.md +306 -0
  200. package/src/cmd/ai/prompt/agent.ts +12 -322
  201. package/src/cmd/ai/prompt/api.md +360 -0
  202. package/src/cmd/ai/prompt/api.ts +13 -260
  203. package/src/cmd/ai/prompt/version.ts +61 -0
  204. package/src/cmd/ai/prompt/web.md +509 -0
  205. package/src/cmd/ai/prompt/web.ts +12 -282
  206. package/src/cmd/ai/skills/generate.ts +75 -0
  207. package/src/cmd/ai/skills/generator.ts +519 -0
  208. package/src/cmd/ai/skills/index.ts +23 -0
  209. package/src/cmd/auth/signup.ts +1 -0
  210. package/src/cmd/build/ast.ts +161 -48
  211. package/src/cmd/build/entry-generator.ts +258 -187
  212. package/src/cmd/build/vite/agent-discovery.ts +151 -58
  213. package/src/cmd/build/vite/bun-dev-server.ts +57 -27
  214. package/src/cmd/build/vite/docs-generator.ts +87 -0
  215. package/src/cmd/build/vite/index.ts +9 -7
  216. package/src/cmd/build/vite/lifecycle-generator.ts +19 -5
  217. package/src/cmd/build/vite/metadata-generator.ts +251 -7
  218. package/src/cmd/build/vite/prompt-generator.ts +169 -0
  219. package/src/cmd/build/vite/registry-generator.ts +750 -108
  220. package/src/cmd/build/vite/route-discovery.ts +4 -0
  221. package/src/cmd/build/vite/server-bundler.ts +73 -23
  222. package/src/cmd/build/vite/vite-asset-server-config.ts +5 -0
  223. package/src/cmd/build/vite/vite-builder.ts +134 -100
  224. package/src/cmd/build/vite-bundler.ts +6 -6
  225. package/src/cmd/cloud/deploy.ts +114 -36
  226. package/src/cmd/cloud/keyvalue/create-namespace.ts +3 -1
  227. package/src/cmd/cloud/keyvalue/delete-namespace.ts +3 -1
  228. package/src/cmd/cloud/keyvalue/delete.ts +3 -1
  229. package/src/cmd/cloud/keyvalue/set.ts +4 -2
  230. package/src/cmd/cloud/stream/get.ts +2 -9
  231. package/src/cmd/cloud/vector/delete-namespace.ts +89 -0
  232. package/src/cmd/cloud/vector/index.ts +21 -4
  233. package/src/cmd/cloud/vector/list-namespaces.ts +46 -0
  234. package/src/cmd/cloud/vector/stats.ts +160 -0
  235. package/src/cmd/cloud/vector/upsert.ts +216 -0
  236. package/src/cmd/dev/file-watcher.ts +109 -34
  237. package/src/cmd/dev/index.ts +364 -60
  238. package/src/cmd/dev/skills.ts +82 -0
  239. package/src/cmd/dev/sync.ts +41 -6
  240. package/src/cmd/index.ts +1 -0
  241. package/src/cmd/project/create.ts +3 -0
  242. package/src/cmd/project/template-flow.ts +37 -5
  243. package/src/cmd/setup/index.ts +1 -0
  244. package/src/cmd/upgrade/index.ts +68 -4
  245. package/src/config.ts +9 -0
  246. package/src/domain.ts +273 -0
  247. package/src/index.ts +0 -5
  248. package/src/runtime-bootstrap.md +1 -1
  249. package/src/schema-generator.ts +23 -0
  250. package/src/steps.ts +16 -5
  251. package/src/tui/prompt.ts +11 -5
  252. package/src/tui.ts +21 -2
  253. package/src/types/md.d.ts +8 -0
  254. package/src/types.ts +12 -3
  255. package/dist/cmd/cloud/domain.d.ts +0 -17
  256. package/dist/cmd/cloud/domain.d.ts.map +0 -1
  257. package/dist/cmd/cloud/domain.js +0 -79
  258. package/dist/cmd/cloud/domain.js.map +0 -1
  259. package/dist/runtime-bootstrap.d.ts +0 -56
  260. package/dist/runtime-bootstrap.d.ts.map +0 -1
  261. package/dist/runtime-bootstrap.js +0 -95
  262. package/dist/runtime-bootstrap.js.map +0 -1
  263. package/src/cmd/cloud/domain.ts +0 -100
  264. package/src/runtime-bootstrap.ts +0 -131
@@ -1,20 +1,33 @@
1
1
  /**
2
2
  * Registry Generator
3
3
  *
4
- * Generates .agentuity/registry.generated.ts from discovered agents
4
+ * Generates src/generated/registry.ts from discovered agents
5
5
  */
6
6
  import { join } from 'node:path';
7
- import { writeFileSync, mkdirSync, existsSync, unlinkSync } from 'node:fs';
7
+ import { writeFileSync, mkdirSync, existsSync, unlinkSync, readFileSync } from 'node:fs';
8
8
  import { StructuredError } from '@agentuity/core';
9
9
  import { toCamelCase, toPascalCase } from '../../../utils/string';
10
10
  const AgentIdentifierCollisionError = StructuredError('AgentIdentifierCollisionError');
11
11
  /**
12
- * Generate .agentuity/registry.generated.ts with agent registry and types
12
+ * Regex to strip route parameter characters that produce invalid TypeScript property names:
13
+ * - Leading : (path parameters, e.g., :id)
14
+ * - Leading * (wildcard routes, e.g., *path)
15
+ * - Trailing ?, +, * (optional/one-or-more/wildcard modifiers, e.g., :userId?)
16
+ */
17
+ const ROUTE_PARAM_CHARS = /^[:*]|[?+*]$/g;
18
+ /**
19
+ * Sanitize a route path segment for use as a TypeScript property name.
20
+ * Strips route parameter characters and converts to camelCase.
21
+ */
22
+ function sanitizePathSegment(segment) {
23
+ return toCamelCase(segment.replace(ROUTE_PARAM_CHARS, ''));
24
+ }
25
+ /**
26
+ * Generate src/generated/registry.ts with agent registry and types
13
27
  */
14
28
  export function generateAgentRegistry(srcDir, agents) {
15
- const projectRoot = join(srcDir, '..');
16
- const agentuityDir = join(projectRoot, '.agentuity');
17
- const registryPath = join(agentuityDir, 'registry.generated.ts');
29
+ const generatedDir = join(srcDir, 'generated');
30
+ const registryPath = join(generatedDir, 'registry.ts');
18
31
  // Detect naming collisions in generated identifiers
19
32
  const generatedNames = new Set();
20
33
  const collisions = [];
@@ -39,57 +52,126 @@ export function generateAgentRegistry(srcDir, agents) {
39
52
  // Handle both './agent/...' and 'src/agent/...' formats
40
53
  let relativePath = filename;
41
54
  if (relativePath.startsWith('./agent/')) {
42
- relativePath = relativePath.replace(/^\.\/agent\//, '../src/agent/');
55
+ // ./agent/foo.ts -> ../agent/foo.js (use .js extension for TypeScript)
56
+ relativePath = relativePath
57
+ .replace(/^\.\/agent\//, '../agent/')
58
+ .replace(/\.tsx?$/, '.js');
43
59
  }
44
60
  else if (relativePath.startsWith('src/agent/')) {
45
- relativePath = '../' + relativePath;
61
+ // src/agent/foo.ts -> ../agent/foo.js (use .js extension for TypeScript)
62
+ relativePath = relativePath
63
+ .replace(/^src\/agent\//, '../agent/')
64
+ .replace(/\.tsx?$/, '.js');
46
65
  }
47
66
  return `import ${camelName} from '${relativePath}';`;
48
67
  })
49
68
  .join('\n');
50
- // Generate flat registry structure
51
- const registry = agents
52
- .map(({ name }) => {
69
+ // Generate schema type exports for all agents
70
+ const schemaTypeExports = agents
71
+ .map(({ name, description }) => {
53
72
  const camelName = toCamelCase(name);
54
- return ` ${camelName}: ${camelName},`;
73
+ const pascalName = toPascalCase(name);
74
+ const descComment = description ? `\n * ${description}` : '';
75
+ const parts = [
76
+ '',
77
+ `/**`,
78
+ ` * Input type for ${name} agent${descComment}`,
79
+ ` */`,
80
+ `export type ${pascalName}Input = InferInput<typeof ${camelName}['inputSchema']>;`,
81
+ '',
82
+ `/**`,
83
+ ` * Output type for ${name} agent${descComment}`,
84
+ ` */`,
85
+ `export type ${pascalName}Output = InferOutput<typeof ${camelName}['outputSchema']>;`,
86
+ '',
87
+ `/**`,
88
+ ` * Input schema type for ${name} agent${descComment}`,
89
+ ` */`,
90
+ `export type ${pascalName}InputSchema = typeof ${camelName}['inputSchema'];`,
91
+ '',
92
+ `/**`,
93
+ ` * Output schema type for ${name} agent${descComment}`,
94
+ ` */`,
95
+ `export type ${pascalName}OutputSchema = typeof ${camelName}['outputSchema'];`,
96
+ '',
97
+ `/**`,
98
+ ` * Agent type for ${name}${descComment}`,
99
+ ` */`,
100
+ `export type ${pascalName}Agent = AgentRunner<`,
101
+ `\t${pascalName}InputSchema,`,
102
+ `\t${pascalName}OutputSchema,`,
103
+ `\ttypeof ${camelName}['stream'] extends true ? true : false`,
104
+ `>;`,
105
+ ];
106
+ return parts.join('\n');
55
107
  })
56
108
  .join('\n');
57
- // Generate type exports for all agents
58
- const typeExports = agents
59
- .map(({ name }) => {
109
+ // Generate flat registry structure with JSDoc
110
+ const registry = agents
111
+ .map(({ name, description }) => {
60
112
  const camelName = toCamelCase(name);
61
113
  const pascalName = toPascalCase(name);
62
- return `export type ${pascalName}Runner = AgentRunner<typeof ${camelName}['inputSchema'], typeof ${camelName}['outputSchema'], typeof ${camelName}['stream'] extends true ? true : false>;`;
114
+ const descComment = description ? `\n\t * ${description}` : '';
115
+ return `\t/**
116
+ \t * ${name}${descComment}
117
+ \t * @type {${pascalName}Agent}
118
+ \t */
119
+ \t${camelName},`;
63
120
  })
64
121
  .join('\n');
65
122
  // Generate flat agent type definitions for AgentRegistry interface augmentation
123
+ // Uses the exported Agent types defined above
66
124
  const runtimeAgentTypes = agents
67
125
  .map(({ name }) => {
68
126
  const camelName = toCamelCase(name);
69
- return ` ${camelName}: AgentRunner<typeof ${camelName}['inputSchema'], typeof ${camelName}['outputSchema'], typeof ${camelName}['stream'] extends true ? true : false>;`;
127
+ const pascalName = toPascalCase(name);
128
+ return ` ${camelName}: ${pascalName}Agent;`;
70
129
  })
71
130
  .join('\n');
72
- const generatedContent = `/// <reference types="hono" />
73
- // Auto-generated by Agentuity - do not edit manually
131
+ const generatedContent = `// @generated
132
+ // Auto-generated by Agentuity - DO NOT EDIT
74
133
  ${imports}
75
- import type { AgentRunner, Logger } from '@agentuity/runtime';
76
- import type { KeyValueStorage, StreamStorage, VectorStorage } from '@agentuity/core';
134
+ import type { AgentRunner } from '@agentuity/runtime';
135
+ import type { InferInput, InferOutput } from '@agentuity/core';
136
+
137
+ // ============================================================================
138
+ // Schema Type Exports
139
+ // ============================================================================
140
+ ${schemaTypeExports}
141
+
142
+ // ============================================================================
143
+ // Agent Definitions
144
+ // ============================================================================
77
145
 
78
146
  /**
147
+ * Agent Definitions
148
+ *
79
149
  * Registry of all agents in this application.
80
150
  * Provides strongly-typed access to agent metadata and runner functions.
81
- * Auto-generated from your agent files during build.
151
+ *
152
+ * @remarks
153
+ * This object is auto-generated from your agent files during build.
154
+ * Each agent has corresponding Input, Output, and Runner types exported above.
155
+ *
156
+ * @example
157
+ * \`\`\`typescript
158
+ * import { AgentDefinitions, SessionBasicInput } from './generated/registry';
159
+ *
160
+ * // Access agent definition
161
+ * const agent = AgentDefinitions.sessionBasic;
162
+ *
163
+ * // Use typed schema types
164
+ * const input: SessionBasicInput = { ... };
165
+ * const result = await agent.run(input);
166
+ * \`\`\`
82
167
  */
83
- export const agentRegistry = {
168
+ export const AgentDefinitions = {
84
169
  ${registry}
85
170
  } as const;
86
171
 
87
- // Local type aliases for Hono augmentation
88
- type LocalAgentName = keyof typeof agentRegistry;
89
- type LocalAgentRegistry = typeof agentRegistry;
90
-
91
- // Typed runners for each agent
92
- ${typeExports}
172
+ // ============================================================================
173
+ // Module Augmentation
174
+ // ============================================================================
93
175
 
94
176
  // Augment @agentuity/runtime types with strongly-typed agents from this project
95
177
  declare module "@agentuity/runtime" {
@@ -99,32 +181,220 @@ ${runtimeAgentTypes}
99
181
  }
100
182
  }
101
183
 
102
- // NOTE: Hono Context properties are accessed via c.var (e.g., c.var.logger, c.var.kv)
103
- // The Variables interface in @agentuity/runtime defines all available context properties
184
+ // FOUND AN ERROR IN THIS FILE?
185
+ // Please file an issue at https://github.com/agentuity/sdk/issues
186
+ // or if you know the fix please submit a PR!
104
187
  `;
105
188
  const agentsDir = join(srcDir, 'agent');
106
189
  const legacyTypesPath = join(agentsDir, 'types.generated.d.ts');
107
- // Ensure .agentuity directory exists
108
- if (!existsSync(agentuityDir)) {
109
- mkdirSync(agentuityDir, { recursive: true });
190
+ // Ensure src/generated directory exists
191
+ if (!existsSync(generatedDir)) {
192
+ mkdirSync(generatedDir, { recursive: true });
110
193
  }
111
- writeFileSync(registryPath, generatedContent, 'utf-8');
112
- // Remove legacy types.generated.d.ts if it exists (now consolidated into registry.generated.ts)
194
+ // Collapse 2+ consecutive empty lines into 1 empty line (3+ \n becomes 2 \n)
195
+ const cleanedContent = generatedContent.replace(/\n{3,}/g, '\n\n');
196
+ writeFileSync(registryPath, cleanedContent, 'utf-8');
197
+ // Remove legacy types.generated.d.ts if it exists (legacy cleanup)
113
198
  if (existsSync(legacyTypesPath)) {
114
199
  unlinkSync(legacyTypesPath);
115
200
  }
116
201
  }
202
+ /**
203
+ * Helper function to generate RPC-style nested registry type.
204
+ * Converts routes like "POST /api/hello" to nested structure: post.api.hello
205
+ */
206
+ function generateRPCRegistryType(apiRoutes, websocketRoutes, sseRoutes, _agentImports, _schemaImportAliases, agentMetadataMap) {
207
+ const tree = {};
208
+ // Helper to add route to tree
209
+ const addRoute = (route, routeType) => {
210
+ const method = route.method.toLowerCase();
211
+ // Strip /api prefix from path
212
+ let cleanPath = route.path;
213
+ if (cleanPath.startsWith('/api/')) {
214
+ cleanPath = cleanPath.substring(4); // Remove '/api'
215
+ }
216
+ else if (cleanPath === '/api') {
217
+ cleanPath = '/';
218
+ }
219
+ const pathParts = cleanPath.split('/').filter(Boolean);
220
+ // Navigate/create tree structure: path segments first, then method
221
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
222
+ let current = tree;
223
+ // Add path segments - sanitize for valid TypeScript property names
224
+ for (let i = 0; i < pathParts.length; i++) {
225
+ const part = sanitizePathSegment(pathParts[i]);
226
+ if (!current[part]) {
227
+ current[part] = {};
228
+ }
229
+ current = current[part];
230
+ }
231
+ // Determine terminal method name based on route type
232
+ // For stream types (websocket, sse, stream), use the type name as the method
233
+ // For regular API routes, use the HTTP method
234
+ const terminalMethod = routeType === 'websocket'
235
+ ? 'websocket'
236
+ : routeType === 'sse'
237
+ ? 'eventstream'
238
+ : routeType === 'stream'
239
+ ? 'stream'
240
+ : method;
241
+ // Add method as final level with schema types
242
+ const routeKey = `${route.method.toUpperCase()} ${route.path}`;
243
+ const safeName = routeKey
244
+ .replace(/[^a-zA-Z0-9]/g, '_')
245
+ .replace(/^_+|_+$/g, '')
246
+ .replace(/_+/g, '_');
247
+ const pascalName = toPascalCase(safeName);
248
+ // Only reference type names if route has schemas, otherwise use 'never'
249
+ const hasSchemas = route.hasValidator ||
250
+ route.inputSchemaVariable ||
251
+ route.outputSchemaVariable ||
252
+ route.agentVariable;
253
+ current[terminalMethod] = {
254
+ input: hasSchemas ? `${pascalName}Input` : 'never',
255
+ output: hasSchemas ? `${pascalName}Output` : 'never',
256
+ type: `'${routeType}'`,
257
+ route,
258
+ };
259
+ };
260
+ // Add all routes with their types
261
+ apiRoutes.forEach((route) => {
262
+ const routeType = route.routeType === 'stream' ? 'stream' : 'api';
263
+ addRoute(route, routeType);
264
+ });
265
+ websocketRoutes.forEach((route) => addRoute(route, 'websocket'));
266
+ sseRoutes.forEach((route) => addRoute(route, 'sse'));
267
+ // Convert tree to TypeScript type string
268
+ function treeToTypeString(node, indent = '\t\t') {
269
+ const lines = [];
270
+ for (const [key, value] of Object.entries(node)) {
271
+ if (value &&
272
+ typeof value === 'object' &&
273
+ 'input' in value &&
274
+ 'output' in value &&
275
+ 'type' in value &&
276
+ 'route' in value) {
277
+ // Leaf node with schema and type - add JSDoc
278
+ const route = value.route;
279
+ const jsdoc = [];
280
+ // Access route info from value
281
+ const routeInfo = route;
282
+ // Look up agent metadata
283
+ let agentMeta;
284
+ if (routeInfo.agentVariable) {
285
+ agentMeta = agentMetadataMap.get(routeInfo.agentVariable);
286
+ }
287
+ // Build JSDoc comment
288
+ jsdoc.push(`${indent}/**`);
289
+ jsdoc.push(`${indent} * Route: ${routeInfo.method.toUpperCase()} ${routeInfo.path}`);
290
+ if (agentMeta?.name) {
291
+ jsdoc.push(`${indent} * @agent ${agentMeta.name}`);
292
+ }
293
+ if (agentMeta?.description) {
294
+ jsdoc.push(`${indent} * @description ${agentMeta.description}`);
295
+ }
296
+ jsdoc.push(`${indent} */`);
297
+ lines.push(...jsdoc);
298
+ lines.push(`${indent}${key}: { input: ${value.input}; output: ${value.output}; type: ${value.type} };`);
299
+ }
300
+ else {
301
+ // Nested node
302
+ lines.push(`${indent}${key}: {`);
303
+ lines.push(treeToTypeString(value, indent + '\t'));
304
+ lines.push(`${indent}};`);
305
+ }
306
+ }
307
+ return lines.join('\n');
308
+ }
309
+ if (Object.keys(tree).length === 0) {
310
+ return '\t\t// No routes discovered';
311
+ }
312
+ return treeToTypeString(tree);
313
+ }
314
+ /**
315
+ * Generate runtime metadata object for RPC routes.
316
+ * This allows the client to know route types at runtime.
317
+ */
318
+ function generateRPCRuntimeMetadata(apiRoutes, websocketRoutes, sseRoutes) {
319
+ const tree = {};
320
+ const addRoute = (route, routeType) => {
321
+ let cleanPath = route.path;
322
+ if (cleanPath.startsWith('/api/')) {
323
+ cleanPath = cleanPath.substring(4);
324
+ }
325
+ else if (cleanPath === '/api') {
326
+ cleanPath = '/';
327
+ }
328
+ const pathParts = cleanPath.split('/').filter(Boolean);
329
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
330
+ let current = tree;
331
+ // Sanitize path segments for valid property names (must match type generation)
332
+ for (const part of pathParts) {
333
+ const sanitized = sanitizePathSegment(part);
334
+ if (!current[sanitized])
335
+ current[sanitized] = {};
336
+ current = current[sanitized];
337
+ }
338
+ // Use terminal method name based on route type
339
+ const terminalMethod = routeType === 'websocket'
340
+ ? 'websocket'
341
+ : routeType === 'sse'
342
+ ? 'eventstream'
343
+ : routeType === 'stream'
344
+ ? 'stream'
345
+ : route.method.toLowerCase();
346
+ current[terminalMethod] = { type: routeType };
347
+ };
348
+ apiRoutes.forEach((r) => addRoute(r, r.routeType === 'stream' ? 'stream' : 'api'));
349
+ websocketRoutes.forEach((r) => addRoute(r, 'websocket'));
350
+ sseRoutes.forEach((r) => addRoute(r, 'sse'));
351
+ return JSON.stringify(tree, null, '\t\t');
352
+ }
117
353
  /**
118
354
  * Generate RouteRegistry type definitions from discovered routes.
119
355
  *
120
356
  * Creates a module augmentation for @agentuity/react that provides
121
357
  * strongly-typed route keys with input/output schema information.
122
358
  */
123
- export function generateRouteRegistry(srcDir, routes) {
359
+ export function generateRouteRegistry(srcDir, routes, agents = []) {
360
+ // Check if project uses @agentuity/react
361
+ const projectRoot = join(srcDir, '..');
362
+ const packageJsonPath = join(projectRoot, 'package.json');
363
+ let hasReactDependency = false;
364
+ try {
365
+ const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
366
+ hasReactDependency = !!(packageJson.dependencies?.['@agentuity/react'] ||
367
+ packageJson.devDependencies?.['@agentuity/react']);
368
+ }
369
+ catch {
370
+ // If we can't read package.json, assume no React dependency
371
+ }
124
372
  // Filter routes by type
125
373
  const apiRoutes = routes.filter((r) => r.routeType === 'api' || r.routeType === 'stream');
126
374
  const websocketRoutes = routes.filter((r) => r.routeType === 'websocket');
127
375
  const sseRoutes = routes.filter((r) => r.routeType === 'sse');
376
+ const allRoutes = [...apiRoutes, ...websocketRoutes, ...sseRoutes];
377
+ // Create maps for agent metadata lookup
378
+ const agentMetadataMap = new Map();
379
+ const agentNameMap = new Map();
380
+ // Map by agent name for easy lookup
381
+ agents.forEach((agent) => {
382
+ agentNameMap.set(agent.name, agent);
383
+ });
384
+ // Map agent import variables to metadata by extracting agent name from import path
385
+ allRoutes.forEach((route) => {
386
+ if (route.agentVariable && route.agentImportPath) {
387
+ // Extract agent name from import path (e.g., "@agent/hello" -> "hello")
388
+ const match = route.agentImportPath.match(/@agent[s]?\/([^/]+)/);
389
+ if (match) {
390
+ const agentName = match[1];
391
+ const metadata = agentNameMap.get(agentName);
392
+ if (metadata) {
393
+ agentMetadataMap.set(route.agentVariable, metadata);
394
+ }
395
+ }
396
+ }
397
+ });
128
398
  if (apiRoutes.length === 0 && websocketRoutes.length === 0 && sseRoutes.length === 0) {
129
399
  return;
130
400
  }
@@ -132,31 +402,84 @@ export function generateRouteRegistry(srcDir, routes) {
132
402
  const imports = [];
133
403
  const agentImports = new Map();
134
404
  const routeFileImports = new Map();
135
- const allRoutes = [...apiRoutes, ...websocketRoutes, ...sseRoutes];
136
- // Collect agent imports
405
+ // Collect agent and schema imports from routes with validators or exported schemas
137
406
  allRoutes.forEach((route) => {
138
- if (!route.hasValidator)
407
+ const hasSchemaVars = !!route.inputSchemaVariable || !!route.outputSchemaVariable;
408
+ if (!route.hasValidator && !hasSchemaVars && !route.agentVariable)
139
409
  return;
140
- if (route.agentVariable && route.agentImportPath && !agentImports.has(route.agentVariable)) {
410
+ // Collect agent imports (when using agent.validator())
411
+ if (route.hasValidator &&
412
+ route.agentVariable &&
413
+ route.agentImportPath &&
414
+ !agentImports.has(route.agentVariable)) {
141
415
  let resolvedPath = route.agentImportPath;
142
- if (resolvedPath.startsWith('@agent/')) {
143
- resolvedPath = `../src/agent/${resolvedPath.substring('@agent/'.length)}`;
416
+ if (resolvedPath.startsWith('@agents/') || resolvedPath.startsWith('@agent/')) {
417
+ // Handle both @agents/ and @agent/ aliases -> ../agent/
418
+ const suffix = resolvedPath.startsWith('@agents/')
419
+ ? resolvedPath.substring('@agents/'.length)
420
+ : resolvedPath.substring('@agent/'.length);
421
+ // Convert @agent/hello -> ../agent/hello/index.js
422
+ // Convert @agent/hello/agent -> ../agent/hello/agent.js
423
+ if (!suffix.includes('/')) {
424
+ // Bare module (e.g., @agent/hello) - add /index.js
425
+ resolvedPath = `../agent/${suffix}/index.js`;
426
+ }
427
+ else {
428
+ // File path (e.g., @agent/hello/agent) - add .js
429
+ const finalPath = suffix.endsWith('.js')
430
+ ? suffix
431
+ : suffix.replace(/\.tsx?$/, '') + '.js';
432
+ resolvedPath = `../agent/${finalPath}`;
433
+ }
144
434
  }
145
435
  else if (resolvedPath.startsWith('@api/')) {
146
- resolvedPath = `../src/web/${resolvedPath.substring('@api/'.length)}`;
436
+ // src/generated/ -> src/api/ is ../api/
437
+ const suffix = resolvedPath.substring('@api/'.length);
438
+ const finalPath = suffix.endsWith('.js')
439
+ ? suffix
440
+ : suffix.replace(/\.tsx?$/, '') + '.js';
441
+ resolvedPath = `../api/${finalPath}`;
147
442
  }
148
443
  else if (resolvedPath.startsWith('./') || resolvedPath.startsWith('../')) {
444
+ // Resolve relative import from route file's directory
149
445
  const routeDir = route.filename.substring(0, route.filename.lastIndexOf('/'));
150
- resolvedPath = `../${routeDir}/${resolvedPath}`;
446
+ // Join and normalize the path
447
+ const joined = `${routeDir}/${resolvedPath}`;
448
+ // Normalize by resolving .. and . segments
449
+ const normalized = joined
450
+ .split('/')
451
+ .reduce((acc, segment) => {
452
+ if (segment === '..') {
453
+ acc.pop();
454
+ }
455
+ else if (segment !== '.' && segment !== '') {
456
+ acc.push(segment);
457
+ }
458
+ return acc;
459
+ }, [])
460
+ .join('/');
461
+ // Remove 'src/' prefix if present (routes are in src/, generated is in src/generated/)
462
+ const withoutSrc = normalized.startsWith('src/') ? normalized.substring(4) : normalized;
463
+ // Make it relative from src/generated/
464
+ resolvedPath = `../${withoutSrc}`;
465
+ // Add .js extension if not already present
466
+ if (!resolvedPath.endsWith('.js')) {
467
+ resolvedPath = resolvedPath.replace(/\.tsx?$/, '') + '.js';
468
+ }
151
469
  }
152
- const uniqueImportName = `agent_${route.agentVariable}`;
470
+ const uniqueImportName = route.agentVariable;
153
471
  imports.push(`import type ${uniqueImportName} from '${resolvedPath}';`);
154
472
  agentImports.set(route.agentVariable, uniqueImportName);
155
473
  }
156
474
  // Collect schema variable imports
157
475
  if (route.inputSchemaVariable || route.outputSchemaVariable) {
158
476
  const filename = route.filename.replace(/\\/g, '/');
159
- const importPath = `../${filename.replace(/\.ts$/, '')}`;
477
+ // Remove 'src/' prefix if present (routes.filename might be './api/...' or 'src/api/...')
478
+ const withoutSrc = filename.startsWith('src/') ? filename.substring(4) : filename;
479
+ const withoutLeadingDot = withoutSrc.startsWith('./')
480
+ ? withoutSrc.substring(2)
481
+ : withoutSrc;
482
+ const importPath = `../${withoutLeadingDot.replace(/\.ts$/, '')}`;
160
483
  if (!routeFileImports.has(importPath)) {
161
484
  routeFileImports.set(importPath, new Set());
162
485
  }
@@ -168,83 +491,301 @@ export function generateRouteRegistry(srcDir, routes) {
168
491
  }
169
492
  }
170
493
  });
171
- // Generate schema imports
494
+ // Generate schema imports with unique aliases to avoid conflicts
495
+ const schemaImportAliases = new Map(); // importPath -> (schemaName -> alias)
496
+ let aliasCounter = 0;
172
497
  routeFileImports.forEach((schemas, importPath) => {
173
- const schemaList = Array.from(schemas).join(', ');
174
- imports.push(`import type { ${schemaList} } from '${importPath}';`);
498
+ const aliases = new Map();
499
+ const importParts = [];
500
+ for (const schemaName of Array.from(schemas)) {
501
+ // Create a unique alias for this schema to avoid collisions
502
+ const alias = `${schemaName}_${aliasCounter++}`;
503
+ aliases.set(schemaName, alias);
504
+ importParts.push(`${schemaName} as ${alias}`);
505
+ }
506
+ schemaImportAliases.set(importPath, aliases);
507
+ imports.push(`import type { ${importParts.join(', ')} } from '${importPath}';`);
175
508
  });
176
- const importsStr = imports.join('\n');
177
- // Helper to generate route entry
178
- const generateRouteEntry = (route) => {
179
- const routeKey = route.path;
180
- if (!route.hasValidator) {
181
- const streamValue = route.stream === true ? 'true' : 'false';
182
- return ` '${routeKey}': {
183
- inputSchema: never;
184
- outputSchema: never;
185
- stream: ${streamValue};
186
- };`;
509
+ const importsStr = imports.length > 0 ? imports.join('\n') + '\n' : '';
510
+ // Add InferInput/InferOutput imports if we have any routes with schemas
511
+ const hasSchemas = allRoutes.some((r) => r.hasValidator || r.inputSchemaVariable || r.outputSchemaVariable || r.agentVariable);
512
+ const typeImports = hasSchemas
513
+ ? `import type { InferInput, InferOutput } from '@agentuity/core';\n`
514
+ : '';
515
+ // Generate individual route schema types
516
+ const routeSchemaTypes = allRoutes
517
+ .filter((r) => r.hasValidator || r.inputSchemaVariable || r.outputSchemaVariable || r.agentVariable)
518
+ .map((route) => {
519
+ const routeKey = route.method ? `${route.method.toUpperCase()} ${route.path}` : route.path;
520
+ const safeName = routeKey
521
+ .replace(/[^a-zA-Z0-9]/g, '_')
522
+ .replace(/^_+|_+$/g, '')
523
+ .replace(/_+/g, '_');
524
+ const pascalName = toPascalCase(safeName);
525
+ let inputType = 'never';
526
+ let outputType = 'never';
527
+ let inputSchemaType = 'never';
528
+ let outputSchemaType = 'never';
529
+ let agentMeta;
530
+ // Look up agent metadata if available
531
+ if (route.agentVariable) {
532
+ agentMeta = agentMetadataMap.get(route.agentVariable);
187
533
  }
188
534
  if (route.agentVariable) {
189
535
  const importName = agentImports.get(route.agentVariable);
190
- return ` '${routeKey}': {
191
- inputSchema: typeof ${importName} extends { inputSchema?: infer I } ? I : never;
192
- outputSchema: typeof ${importName} extends { outputSchema?: infer O } ? O : never;
193
- stream: typeof ${importName} extends { stream?: infer S } ? S : false;
194
- };`;
536
+ inputType = `InferInput<typeof ${importName}['inputSchema']>`;
537
+ outputType = `InferOutput<typeof ${importName}['outputSchema']>`;
538
+ inputSchemaType = `typeof ${importName} extends { inputSchema?: infer I } ? I : never`;
539
+ outputSchemaType = `typeof ${importName} extends { outputSchema?: infer O } ? O : never`;
195
540
  }
196
- if (route.inputSchemaVariable || route.outputSchemaVariable) {
197
- const inputType = route.inputSchemaVariable
198
- ? `typeof ${route.inputSchemaVariable}`
199
- : 'never';
200
- const outputType = route.outputSchemaVariable
201
- ? `typeof ${route.outputSchemaVariable}`
202
- : 'never';
541
+ else if (route.inputSchemaVariable || route.outputSchemaVariable) {
542
+ // Get the aliased schema names for this route's file
543
+ const filename = route.filename.replace(/\\/g, '/');
544
+ const withoutSrc = filename.startsWith('src/') ? filename.substring(4) : filename;
545
+ const withoutLeadingDot = withoutSrc.startsWith('./')
546
+ ? withoutSrc.substring(2)
547
+ : withoutSrc;
548
+ const importPath = `../${withoutLeadingDot.replace(/\.ts$/, '')}`;
549
+ const aliases = schemaImportAliases.get(importPath);
550
+ const inputAlias = route.inputSchemaVariable && aliases?.get(route.inputSchemaVariable);
551
+ const outputAlias = route.outputSchemaVariable && aliases?.get(route.outputSchemaVariable);
552
+ inputType = inputAlias ? `InferInput<typeof ${inputAlias}>` : 'never';
553
+ outputType = outputAlias ? `InferOutput<typeof ${outputAlias}>` : 'never';
554
+ inputSchemaType = inputAlias ? `typeof ${inputAlias}` : 'never';
555
+ outputSchemaType = outputAlias ? `typeof ${outputAlias}` : 'never';
556
+ }
557
+ if (inputType === 'never' && outputType === 'never') {
558
+ return ''; // Skip routes without schemas
559
+ }
560
+ // Build JSDoc with agent description and schema details
561
+ const inputJSDoc = ['/**', ` * Input type for route: ${routeKey}`];
562
+ if (agentMeta?.description) {
563
+ inputJSDoc.push(` * @description ${agentMeta.description}`);
564
+ }
565
+ if (agentMeta?.inputSchemaCode) {
566
+ inputJSDoc.push(` * @schema ${agentMeta.inputSchemaCode}`);
567
+ }
568
+ inputJSDoc.push(' */');
569
+ const outputJSDoc = ['/**', ` * Output type for route: ${routeKey}`];
570
+ if (agentMeta?.description) {
571
+ outputJSDoc.push(` * @description ${agentMeta.description}`);
572
+ }
573
+ if (agentMeta?.outputSchemaCode) {
574
+ outputJSDoc.push(` * @schema ${agentMeta.outputSchemaCode}`);
575
+ }
576
+ outputJSDoc.push(' */');
577
+ const parts = [
578
+ '',
579
+ ...inputJSDoc,
580
+ `export type ${pascalName}Input = ${inputType};`,
581
+ '',
582
+ ...outputJSDoc,
583
+ `export type ${pascalName}Output = ${outputType};`,
584
+ '',
585
+ `/**`,
586
+ ` * Input schema type for route: ${routeKey}`,
587
+ ` */`,
588
+ `export type ${pascalName}InputSchema = ${inputSchemaType};`,
589
+ '',
590
+ `/**`,
591
+ ` * Output schema type for route: ${routeKey}`,
592
+ ` */`,
593
+ `export type ${pascalName}OutputSchema = ${outputSchemaType};`,
594
+ ];
595
+ return parts.join('\n');
596
+ })
597
+ .filter(Boolean)
598
+ .join('\n');
599
+ // Helper to generate route entry - uses exported schema types
600
+ const generateRouteEntry = (route, pathIncludesMethod = false) => {
601
+ const routeKey = route.path;
602
+ // For WebSocket/SSE routes, we need to include the method in the type name
603
+ // to match the generated types (which use "POST /api/websocket/echo" as the routeKey)
604
+ // For API routes, the method is already in the path from the caller
605
+ const typeRouteKey = pathIncludesMethod
606
+ ? route.path
607
+ : `${route.method?.toUpperCase()} ${route.path}`;
608
+ const safeName = typeRouteKey
609
+ .replace(/[^a-zA-Z0-9]/g, '_')
610
+ .replace(/^_+|_+$/g, '')
611
+ .replace(/_+/g, '_');
612
+ const pascalName = toPascalCase(safeName);
613
+ if (!route.hasValidator &&
614
+ !route.inputSchemaVariable &&
615
+ !route.outputSchemaVariable &&
616
+ !route.agentVariable) {
203
617
  const streamValue = route.stream === true ? 'true' : 'false';
204
- return ` '${routeKey}': {
205
- inputSchema: ${inputType};
206
- outputSchema: ${outputType};
207
- stream: ${streamValue};
208
- };`;
209
- }
210
- return ` '${routeKey}': {
211
- inputSchema: any;
212
- outputSchema: any;
213
- };`;
618
+ return `\t'${routeKey}': {
619
+ \t\tinputSchema: never;
620
+ \t\toutputSchema: never;
621
+ \t\tstream: ${streamValue};
622
+ \t};`;
623
+ }
624
+ // Use the exported schema types we generated above
625
+ const importName = route.agentVariable ? agentImports.get(route.agentVariable) : null;
626
+ const streamValue = importName
627
+ ? `typeof ${importName} extends { stream?: infer S } ? S : false`
628
+ : route.stream === true
629
+ ? 'true'
630
+ : 'false';
631
+ return `\t'${routeKey}': {
632
+ \t\tinputSchema: ${pascalName}InputSchema;
633
+ \t\toutputSchema: ${pascalName}OutputSchema;
634
+ \t\tstream: ${streamValue};
635
+ \t};`;
214
636
  };
215
637
  // Generate route entries with METHOD prefix for API routes
216
638
  const apiRouteEntries = apiRoutes
217
639
  .map((route) => {
218
640
  const routeKey = `${route.method.toUpperCase()} ${route.path}`;
219
- return generateRouteEntry({ ...route, path: routeKey });
641
+ return generateRouteEntry({ ...route, path: routeKey }, true);
220
642
  })
221
643
  .join('\n');
222
- const websocketRouteEntries = websocketRoutes.map(generateRouteEntry).join('\n');
223
- const sseRouteEntries = sseRoutes.map(generateRouteEntry).join('\n');
224
- const generatedContent = `// Auto-generated by Agentuity - do not edit manually
225
- ${importsStr}
644
+ const websocketRouteEntries = websocketRoutes
645
+ .map((r) => generateRouteEntry(r, false))
646
+ .join('\n');
647
+ const sseRouteEntries = sseRoutes.map((r) => generateRouteEntry(r, false)).join('\n');
648
+ // Generate RPC-style nested registry type
649
+ const rpcRegistryType = generateRPCRegistryType(apiRoutes, websocketRoutes, sseRoutes, agentImports, schemaImportAliases, agentMetadataMap);
650
+ const rpcRuntimeMetadata = generateRPCRuntimeMetadata(apiRoutes, websocketRoutes, sseRoutes);
651
+ const generatedContent = `// @generated
652
+ // Auto-generated by Agentuity - DO NOT EDIT
653
+ ${importsStr}${typeImports}${!hasReactDependency
654
+ ? `
655
+ import { createClient } from '@agentuity/frontend';`
656
+ : ''}
657
+ // ============================================================================
658
+ // Route Schema Type Exports
659
+ // ============================================================================
660
+ ${routeSchemaTypes}
661
+
662
+ // ============================================================================
663
+ // Route Definitions
664
+ // ============================================================================
226
665
 
227
- // Augment @agentuity/react types with project-specific routes
666
+ /**
667
+ * Route Definitions
668
+ *
669
+ * Type-safe route registry for all API routes, WebSocket connections, and SSE endpoints.
670
+ * Used by @agentuity/react for client-side type-safe routing.
671
+ *
672
+ * @remarks
673
+ * This module augmentation is auto-generated from your route files during build.
674
+ * Individual route Input/Output types are exported above for direct usage.
675
+ */
676
+ ${!hasReactDependency
677
+ ? `
678
+ /**
679
+ * RPC Route Registry
680
+ *
681
+ * Nested structure for RPC-style client access (e.g., client.hello.post())
682
+ * Used by createClient() from @agentuity/frontend for type-safe RPC calls.
683
+ */
684
+ export interface RPCRouteRegistry {
685
+ ${rpcRegistryType}
686
+ }
687
+ `
688
+ : ''}
228
689
  declare module '@agentuity/react' {
229
- export interface RouteRegistry {
690
+ \t/**
691
+ \t * API Route Registry
692
+ \t *
693
+ \t * Maps route keys (METHOD /path) to their input/output schemas
694
+ \t */
695
+ \texport interface RouteRegistry {
230
696
  ${apiRouteEntries}
231
- }
232
-
233
- export interface WebSocketRouteRegistry {
697
+ \t}
698
+ \t
699
+ \t/**
700
+ \t * WebSocket Route Registry
701
+ \t *
702
+ \t * Maps WebSocket route paths to their schemas
703
+ \t */
704
+ \texport interface WebSocketRouteRegistry {
234
705
  ${websocketRouteEntries}
235
- }
236
-
237
- export interface SSERouteRegistry {
706
+ \t}
707
+ \t
708
+ \t/**
709
+ \t * Server-Sent Events Route Registry
710
+ \t *
711
+ \t * Maps SSE route paths to their schemas
712
+ \t */
713
+ \texport interface SSERouteRegistry {
238
714
  ${sseRouteEntries}
239
- }
715
+ \t}
716
+
717
+ \t/**
718
+ \t * RPC Route Registry
719
+ \t *
720
+ \t * Nested structure for RPC-style client access (e.g., client.hello.post())
721
+ \t * Used by createClient() from @agentuity/core for type-safe RPC calls.
722
+ \t */
723
+ \texport interface RPCRouteRegistry {
724
+ ${rpcRegistryType}
725
+ \t}
726
+ }
727
+
728
+ /**
729
+ * Runtime metadata for RPC routes.
730
+ * Contains route type information for client routing decisions.
731
+ * @internal
732
+ */
733
+ const _rpcRouteMetadata = ${rpcRuntimeMetadata} as const;
734
+
735
+ // Store metadata globally for createAPIClient() to access
736
+ if (typeof globalThis !== 'undefined') {
737
+ (globalThis as Record<string, unknown>).__rpcRouteMetadata = _rpcRouteMetadata;
738
+ }
739
+ ${!hasReactDependency
740
+ ? `
741
+ /**
742
+ * Create a type-safe API client with optional configuration.
743
+ *
744
+ * This function is only generated when @agentuity/react is not installed.
745
+ * If using React, import createAPIClient from '@agentuity/react' instead.
746
+ *
747
+ * @example
748
+ * \`\`\`typescript
749
+ * import { createAPIClient } from './generated/routes';
750
+ *
751
+ * // Basic usage
752
+ * const api = createAPIClient();
753
+ * const result = await api.hello.post({ name: 'World' });
754
+ *
755
+ * // With custom headers
756
+ * const api = createAPIClient({ headers: { 'X-Custom-Header': 'value' } });
757
+ * await api.hello.post({ name: 'World' });
758
+ * \`\`\`
759
+ */
760
+ export function createAPIClient(options?: Parameters<typeof createClient>[0]): import('@agentuity/frontend').Client<RPCRouteRegistry> {
761
+ return createClient(options || {}, _rpcRouteMetadata) as import('@agentuity/frontend').Client<RPCRouteRegistry>;
240
762
  }
763
+ `
764
+ : `
765
+ /**
766
+ * Type-safe API client is available from @agentuity/react
767
+ *
768
+ * @example
769
+ * \`\`\`typescript
770
+ * import { createAPIClient } from '@agentuity/react';
771
+ *
772
+ * const api = createAPIClient();
773
+ * const result = await api.hello.post({ name: 'World' });
774
+ * \`\`\`
775
+ */
776
+ `}
777
+
778
+ // FOUND AN ERROR IN THIS FILE?
779
+ // Please file an issue at https://github.com/agentuity/sdk/issues
780
+ // or if you know the fix please submit a PR!
241
781
  `;
242
- const projectRoot = join(srcDir, '..');
243
- const agentuityDir = join(projectRoot, '.agentuity');
244
- const registryPath = join(agentuityDir, 'routes.generated.ts');
245
- if (!existsSync(agentuityDir)) {
246
- mkdirSync(agentuityDir, { recursive: true });
782
+ const generatedDir = join(srcDir, 'generated');
783
+ const registryPath = join(generatedDir, 'routes.ts');
784
+ if (!existsSync(generatedDir)) {
785
+ mkdirSync(generatedDir, { recursive: true });
247
786
  }
248
- writeFileSync(registryPath, generatedContent, 'utf-8');
787
+ // Collapse 2+ consecutive empty lines into 1 empty line (3+ \n becomes 2 \n)
788
+ const cleanedContent = generatedContent.replace(/\n{3,}/g, '\n\n');
789
+ writeFileSync(registryPath, cleanedContent, 'utf-8');
249
790
  }
250
791
  //# sourceMappingURL=registry-generator.js.map