@agentuity/cli 1.0.47 → 2.0.0-beta.0
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/dist/cmd/build/app-router-detector.d.ts +2 -5
- package/dist/cmd/build/app-router-detector.d.ts.map +1 -1
- package/dist/cmd/build/app-router-detector.js +130 -154
- package/dist/cmd/build/app-router-detector.js.map +1 -1
- package/dist/cmd/build/ids.d.ts +11 -0
- package/dist/cmd/build/ids.d.ts.map +1 -0
- package/dist/cmd/build/ids.js +18 -0
- package/dist/cmd/build/ids.js.map +1 -0
- package/dist/cmd/build/vite/agent-discovery.d.ts +8 -4
- package/dist/cmd/build/vite/agent-discovery.d.ts.map +1 -1
- package/dist/cmd/build/vite/agent-discovery.js +166 -487
- package/dist/cmd/build/vite/agent-discovery.js.map +1 -1
- package/dist/cmd/build/vite/bun-dev-server.d.ts +10 -16
- package/dist/cmd/build/vite/bun-dev-server.d.ts.map +1 -1
- package/dist/cmd/build/vite/bun-dev-server.js +67 -134
- package/dist/cmd/build/vite/bun-dev-server.js.map +1 -1
- package/dist/cmd/build/vite/docs-generator.d.ts.map +1 -1
- package/dist/cmd/build/vite/docs-generator.js +0 -2
- package/dist/cmd/build/vite/docs-generator.js.map +1 -1
- package/dist/cmd/build/vite/index.d.ts.map +1 -1
- package/dist/cmd/build/vite/index.js +0 -36
- package/dist/cmd/build/vite/index.js.map +1 -1
- package/dist/cmd/build/vite/lifecycle-generator.d.ts +10 -2
- package/dist/cmd/build/vite/lifecycle-generator.d.ts.map +1 -1
- package/dist/cmd/build/vite/lifecycle-generator.js +302 -23
- package/dist/cmd/build/vite/lifecycle-generator.js.map +1 -1
- package/dist/cmd/build/vite/route-discovery.d.ts +11 -38
- package/dist/cmd/build/vite/route-discovery.d.ts.map +1 -1
- package/dist/cmd/build/vite/route-discovery.js +97 -177
- package/dist/cmd/build/vite/route-discovery.js.map +1 -1
- package/dist/cmd/build/vite/server-bundler.js +1 -1
- package/dist/cmd/build/vite/server-bundler.js.map +1 -1
- package/dist/cmd/build/vite/static-renderer.d.ts.map +1 -1
- package/dist/cmd/build/vite/static-renderer.js +1 -9
- package/dist/cmd/build/vite/static-renderer.js.map +1 -1
- package/dist/cmd/build/vite/vite-asset-server-config.d.ts +6 -3
- package/dist/cmd/build/vite/vite-asset-server-config.d.ts.map +1 -1
- package/dist/cmd/build/vite/vite-asset-server-config.js +171 -18
- package/dist/cmd/build/vite/vite-asset-server-config.js.map +1 -1
- package/dist/cmd/build/vite/vite-asset-server.d.ts +8 -3
- package/dist/cmd/build/vite/vite-asset-server.d.ts.map +1 -1
- package/dist/cmd/build/vite/vite-asset-server.js +14 -13
- package/dist/cmd/build/vite/vite-asset-server.js.map +1 -1
- package/dist/cmd/build/vite/vite-builder.d.ts.map +1 -1
- package/dist/cmd/build/vite/vite-builder.js +6 -34
- package/dist/cmd/build/vite/vite-builder.js.map +1 -1
- package/dist/cmd/build/vite/ws-proxy.d.ts +53 -0
- package/dist/cmd/build/vite/ws-proxy.d.ts.map +1 -0
- package/dist/cmd/build/vite/ws-proxy.js +95 -0
- package/dist/cmd/build/vite/ws-proxy.js.map +1 -0
- package/dist/cmd/build/vite-bundler.d.ts.map +1 -1
- package/dist/cmd/build/vite-bundler.js +0 -3
- package/dist/cmd/build/vite-bundler.js.map +1 -1
- package/dist/cmd/dev/file-watcher.d.ts.map +1 -1
- package/dist/cmd/dev/file-watcher.js +2 -8
- package/dist/cmd/dev/file-watcher.js.map +1 -1
- package/dist/cmd/dev/index.d.ts.map +1 -1
- package/dist/cmd/dev/index.js +369 -720
- package/dist/cmd/dev/index.js.map +1 -1
- package/package.json +6 -8
- package/src/cmd/ai/prompt/agent.md +0 -1
- package/src/cmd/ai/prompt/api.md +0 -7
- package/src/cmd/ai/prompt/web.md +51 -213
- package/src/cmd/build/app-router-detector.ts +152 -182
- package/src/cmd/build/ids.ts +19 -0
- package/src/cmd/build/vite/agent-discovery.ts +208 -679
- package/src/cmd/build/vite/bun-dev-server.ts +78 -154
- package/src/cmd/build/vite/docs-generator.ts +0 -2
- package/src/cmd/build/vite/index.ts +1 -42
- package/src/cmd/build/vite/lifecycle-generator.ts +345 -21
- package/src/cmd/build/vite/route-discovery.ts +116 -274
- package/src/cmd/build/vite/server-bundler.ts +1 -1
- package/src/cmd/build/vite/static-renderer.ts +1 -11
- package/src/cmd/build/vite/vite-asset-server-config.ts +196 -20
- package/src/cmd/build/vite/vite-asset-server.ts +25 -15
- package/src/cmd/build/vite/vite-builder.ts +6 -51
- package/src/cmd/build/vite/ws-proxy.ts +126 -0
- package/src/cmd/build/vite-bundler.ts +0 -4
- package/src/cmd/dev/file-watcher.ts +2 -9
- package/src/cmd/dev/index.ts +409 -832
- package/dist/cmd/build/ast.d.ts +0 -78
- package/dist/cmd/build/ast.d.ts.map +0 -1
- package/dist/cmd/build/ast.js +0 -2703
- package/dist/cmd/build/ast.js.map +0 -1
- package/dist/cmd/build/entry-generator.d.ts +0 -25
- package/dist/cmd/build/entry-generator.d.ts.map +0 -1
- package/dist/cmd/build/entry-generator.js +0 -695
- package/dist/cmd/build/entry-generator.js.map +0 -1
- package/dist/cmd/build/vite/api-mount-path.d.ts +0 -61
- package/dist/cmd/build/vite/api-mount-path.d.ts.map +0 -1
- package/dist/cmd/build/vite/api-mount-path.js +0 -83
- package/dist/cmd/build/vite/api-mount-path.js.map +0 -1
- package/dist/cmd/build/vite/registry-generator.d.ts +0 -19
- package/dist/cmd/build/vite/registry-generator.d.ts.map +0 -1
- package/dist/cmd/build/vite/registry-generator.js +0 -1108
- package/dist/cmd/build/vite/registry-generator.js.map +0 -1
- package/dist/cmd/build/webanalytics-generator.d.ts +0 -16
- package/dist/cmd/build/webanalytics-generator.d.ts.map +0 -1
- package/dist/cmd/build/webanalytics-generator.js +0 -178
- package/dist/cmd/build/webanalytics-generator.js.map +0 -1
- package/dist/cmd/build/workbench.d.ts +0 -7
- package/dist/cmd/build/workbench.d.ts.map +0 -1
- package/dist/cmd/build/workbench.js +0 -55
- package/dist/cmd/build/workbench.js.map +0 -1
- package/dist/utils/route-migration.d.ts +0 -62
- package/dist/utils/route-migration.d.ts.map +0 -1
- package/dist/utils/route-migration.js +0 -630
- package/dist/utils/route-migration.js.map +0 -1
- package/src/cmd/build/ast.ts +0 -3529
- package/src/cmd/build/entry-generator.ts +0 -760
- package/src/cmd/build/vite/api-mount-path.ts +0 -87
- package/src/cmd/build/vite/registry-generator.ts +0 -1267
- package/src/cmd/build/webanalytics-generator.ts +0 -197
- package/src/cmd/build/workbench.ts +0 -58
- package/src/utils/route-migration.ts +0 -757
|
@@ -1,1108 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Registry Generator
|
|
3
|
-
*
|
|
4
|
-
* Generates src/generated/registry.ts from discovered agents
|
|
5
|
-
*/
|
|
6
|
-
import { join, dirname, relative, resolve } from 'node:path';
|
|
7
|
-
import { writeFileSync, mkdirSync, existsSync, unlinkSync, readFileSync } from 'node:fs';
|
|
8
|
-
import { stat } from 'node:fs/promises';
|
|
9
|
-
import { StructuredError } from '@agentuity/core';
|
|
10
|
-
import { toCamelCase, toPascalCase } from '../../../utils/string';
|
|
11
|
-
import { toForwardSlash } from '../../../utils/normalize-path';
|
|
12
|
-
/**
|
|
13
|
-
* Rebase a relative import path from the route file's location to the generated file's location.
|
|
14
|
-
* @param routeFilename - The route file path (e.g., 'api/example/route.ts' or './api/example/route.ts')
|
|
15
|
-
* @param schemaImportPath - The import path as written in the route file (e.g., '../../utils/schemas')
|
|
16
|
-
* @param srcDir - The src directory path
|
|
17
|
-
* @returns The rebased import path relative to src/generated/
|
|
18
|
-
*/
|
|
19
|
-
function rebaseImportPath(routeFilename, schemaImportPath, srcDir) {
|
|
20
|
-
// Non-relative imports (bare modules like '@company/schemas') should be used as-is
|
|
21
|
-
if (!schemaImportPath.startsWith('.') && !schemaImportPath.startsWith('/')) {
|
|
22
|
-
return schemaImportPath;
|
|
23
|
-
}
|
|
24
|
-
// Normalize route filename to get its directory relative to srcDir
|
|
25
|
-
let routeDir;
|
|
26
|
-
const cleanFilename = toForwardSlash(routeFilename);
|
|
27
|
-
if (cleanFilename.startsWith('./')) {
|
|
28
|
-
routeDir = dirname(join(srcDir, cleanFilename.substring(2)));
|
|
29
|
-
}
|
|
30
|
-
else if (cleanFilename.startsWith('src/')) {
|
|
31
|
-
routeDir = dirname(join(srcDir, '..', cleanFilename));
|
|
32
|
-
}
|
|
33
|
-
else {
|
|
34
|
-
routeDir = dirname(join(srcDir, cleanFilename));
|
|
35
|
-
}
|
|
36
|
-
// Resolve the schema module path from the route file's directory
|
|
37
|
-
const resolvedSchemaPath = resolve(routeDir, schemaImportPath);
|
|
38
|
-
// Calculate the relative path from src/generated/ to the resolved schema path
|
|
39
|
-
const generatedDir = join(srcDir, 'generated');
|
|
40
|
-
let rebasedPath = toForwardSlash(relative(generatedDir, resolvedSchemaPath));
|
|
41
|
-
// Ensure it starts with './' or '../'
|
|
42
|
-
if (!rebasedPath.startsWith('.') && !rebasedPath.startsWith('/')) {
|
|
43
|
-
rebasedPath = './' + rebasedPath;
|
|
44
|
-
}
|
|
45
|
-
return rebasedPath;
|
|
46
|
-
}
|
|
47
|
-
const AgentIdentifierCollisionError = StructuredError('AgentIdentifierCollisionError');
|
|
48
|
-
/**
|
|
49
|
-
* Regex to strip route parameter characters that produce invalid TypeScript property names:
|
|
50
|
-
* - Leading : (path parameters, e.g., :id)
|
|
51
|
-
* - Leading * (wildcard routes, e.g., *path)
|
|
52
|
-
* - Trailing ?, +, * (optional/one-or-more/wildcard modifiers, e.g., :userId?)
|
|
53
|
-
*/
|
|
54
|
-
const ROUTE_PARAM_CHARS = /^[:*]|[?+*]$/g;
|
|
55
|
-
/**
|
|
56
|
-
* Sanitize a route path segment for use as a TypeScript property name.
|
|
57
|
-
* Strips route parameter characters and converts to camelCase.
|
|
58
|
-
*/
|
|
59
|
-
function sanitizePathSegment(segment) {
|
|
60
|
-
return toCamelCase(segment.replace(ROUTE_PARAM_CHARS, ''));
|
|
61
|
-
}
|
|
62
|
-
/**
|
|
63
|
-
* Valid unquoted TypeScript/JavaScript property name pattern.
|
|
64
|
-
* A property name can be unquoted if it starts with a letter, underscore, or dollar sign,
|
|
65
|
-
* and contains only letters, digits, underscores, or dollar signs.
|
|
66
|
-
*/
|
|
67
|
-
const VALID_UNQUOTED_PROPERTY = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
|
|
68
|
-
/**
|
|
69
|
-
* Quote a property name for TypeScript object type definitions if it contains
|
|
70
|
-
* characters that require quoting (e.g., dots, hyphens, spaces).
|
|
71
|
-
*/
|
|
72
|
-
function quotePropertyName(name) {
|
|
73
|
-
return VALID_UNQUOTED_PROPERTY.test(name) ? name : JSON.stringify(name);
|
|
74
|
-
}
|
|
75
|
-
/**
|
|
76
|
-
* Generate TypeScript type for path parameters.
|
|
77
|
-
* Returns 'never' if no path params, or '{ param1: string; param2: string }' format.
|
|
78
|
-
*/
|
|
79
|
-
function generatePathParamsType(pathParams) {
|
|
80
|
-
if (!pathParams || pathParams.length === 0) {
|
|
81
|
-
return 'never';
|
|
82
|
-
}
|
|
83
|
-
return `{ ${pathParams.map((p) => `${p}: string`).join('; ')} }`;
|
|
84
|
-
}
|
|
85
|
-
/**
|
|
86
|
-
* Generate TypeScript tuple type for path parameters (for positional args).
|
|
87
|
-
* Returns '[]' if no path params, or '[string, string]' format.
|
|
88
|
-
*/
|
|
89
|
-
function generatePathParamsTupleType(pathParams) {
|
|
90
|
-
if (!pathParams || pathParams.length === 0) {
|
|
91
|
-
return '[]';
|
|
92
|
-
}
|
|
93
|
-
return `[${pathParams.map(() => 'string').join(', ')}]`;
|
|
94
|
-
}
|
|
95
|
-
/**
|
|
96
|
-
* Generate src/generated/registry.ts with agent registry and types
|
|
97
|
-
*/
|
|
98
|
-
export function generateAgentRegistry(srcDir, agents) {
|
|
99
|
-
const generatedDir = join(srcDir, 'generated');
|
|
100
|
-
const registryPath = join(generatedDir, 'registry.ts');
|
|
101
|
-
// Sort agents by name for deterministic output
|
|
102
|
-
const sortedAgents = [...agents].sort((a, b) => a.name.localeCompare(b.name));
|
|
103
|
-
// Detect naming collisions in generated identifiers
|
|
104
|
-
const generatedNames = new Set();
|
|
105
|
-
const collisions = [];
|
|
106
|
-
for (const agent of sortedAgents) {
|
|
107
|
-
const camelName = toCamelCase(agent.name);
|
|
108
|
-
if (generatedNames.has(camelName)) {
|
|
109
|
-
collisions.push(`Identifier collision detected: "${camelName}" (from "${agent.name}")`);
|
|
110
|
-
}
|
|
111
|
-
generatedNames.add(camelName);
|
|
112
|
-
}
|
|
113
|
-
if (collisions.length > 0) {
|
|
114
|
-
throw new AgentIdentifierCollisionError({
|
|
115
|
-
message: `Agent identifier naming collisions detected:\n${collisions.join('\n')}\n\n` +
|
|
116
|
-
`This occurs when different agent names produce the same camelCase identifier.\n` +
|
|
117
|
-
`Please rename your agents to avoid this collision.`,
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
// Collect eval files that need to be imported for createEval calls to run
|
|
121
|
-
// These are eval.ts files in the same directory as agents that have evals
|
|
122
|
-
const evalImports = [];
|
|
123
|
-
const seenEvalPaths = new Set();
|
|
124
|
-
for (const agent of sortedAgents) {
|
|
125
|
-
if (agent.evals && agent.evals.length > 0) {
|
|
126
|
-
// Check if any eval comes from a separate eval.ts file (not the agent file itself)
|
|
127
|
-
for (const evalMeta of agent.evals) {
|
|
128
|
-
// Skip if eval is defined in the agent file itself
|
|
129
|
-
if (evalMeta.filename === agent.filename)
|
|
130
|
-
continue;
|
|
131
|
-
// Build the relative path for the eval file
|
|
132
|
-
let evalRelativePath = toForwardSlash(evalMeta.filename);
|
|
133
|
-
if (evalRelativePath.startsWith('./agent/')) {
|
|
134
|
-
evalRelativePath = evalRelativePath
|
|
135
|
-
.replace(/^\.\/agent\//, '../agent/')
|
|
136
|
-
.replace(/\.tsx?$/, '.js');
|
|
137
|
-
}
|
|
138
|
-
else if (evalRelativePath.startsWith('src/agent/')) {
|
|
139
|
-
evalRelativePath = evalRelativePath
|
|
140
|
-
.replace(/^src\/agent\//, '../agent/')
|
|
141
|
-
.replace(/\.tsx?$/, '.js');
|
|
142
|
-
}
|
|
143
|
-
else if (evalRelativePath.includes('/src/agent/')) {
|
|
144
|
-
// Handle absolute paths by extracting the relative part
|
|
145
|
-
evalRelativePath = evalRelativePath
|
|
146
|
-
.replace(/^.*\/src\/agent\//, '../agent/')
|
|
147
|
-
.replace(/\.tsx?$/, '.js');
|
|
148
|
-
}
|
|
149
|
-
// Avoid duplicate imports
|
|
150
|
-
if (!seenEvalPaths.has(evalRelativePath)) {
|
|
151
|
-
seenEvalPaths.add(evalRelativePath);
|
|
152
|
-
evalImports.push(`import '${evalRelativePath}';`);
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
// Generate imports for all agents
|
|
158
|
-
const imports = sortedAgents
|
|
159
|
-
.map(({ name, filename }) => {
|
|
160
|
-
const camelName = toCamelCase(name);
|
|
161
|
-
// Handle both './agent/...' and 'src/agent/...' formats
|
|
162
|
-
let relativePath = toForwardSlash(filename);
|
|
163
|
-
if (relativePath.startsWith('./agent/')) {
|
|
164
|
-
// ./agent/foo.ts -> ../agent/foo.js (use .js extension for TypeScript)
|
|
165
|
-
relativePath = relativePath
|
|
166
|
-
.replace(/^\.\/agent\//, '../agent/')
|
|
167
|
-
.replace(/\.tsx?$/, '.js');
|
|
168
|
-
}
|
|
169
|
-
else if (relativePath.startsWith('src/agent/')) {
|
|
170
|
-
// src/agent/foo.ts -> ../agent/foo.js (use .js extension for TypeScript)
|
|
171
|
-
relativePath = relativePath
|
|
172
|
-
.replace(/^src\/agent\//, '../agent/')
|
|
173
|
-
.replace(/\.tsx?$/, '.js');
|
|
174
|
-
}
|
|
175
|
-
return `import ${camelName} from '${relativePath}';`;
|
|
176
|
-
})
|
|
177
|
-
.join('\n');
|
|
178
|
-
// Generate schema type exports for all agents
|
|
179
|
-
const schemaTypeExports = sortedAgents
|
|
180
|
-
.map(({ name, description }) => {
|
|
181
|
-
const camelName = toCamelCase(name);
|
|
182
|
-
const pascalName = toPascalCase(name);
|
|
183
|
-
const descComment = description ? `\n * ${description}` : '';
|
|
184
|
-
const parts = [
|
|
185
|
-
'',
|
|
186
|
-
`/**`,
|
|
187
|
-
` * Input type for ${name} agent${descComment}`,
|
|
188
|
-
` */`,
|
|
189
|
-
`export type ${pascalName}Input = InferInput<typeof ${camelName}['inputSchema']>;`,
|
|
190
|
-
'',
|
|
191
|
-
`/**`,
|
|
192
|
-
` * Output type for ${name} agent${descComment}`,
|
|
193
|
-
` */`,
|
|
194
|
-
`export type ${pascalName}Output = InferOutput<typeof ${camelName}['outputSchema']>;`,
|
|
195
|
-
'',
|
|
196
|
-
`/**`,
|
|
197
|
-
` * Input schema type for ${name} agent${descComment}`,
|
|
198
|
-
` */`,
|
|
199
|
-
`export type ${pascalName}InputSchema = typeof ${camelName}['inputSchema'];`,
|
|
200
|
-
'',
|
|
201
|
-
`/**`,
|
|
202
|
-
` * Output schema type for ${name} agent${descComment}`,
|
|
203
|
-
` */`,
|
|
204
|
-
`export type ${pascalName}OutputSchema = typeof ${camelName}['outputSchema'];`,
|
|
205
|
-
'',
|
|
206
|
-
`/**`,
|
|
207
|
-
` * Agent type for ${name}${descComment}`,
|
|
208
|
-
` */`,
|
|
209
|
-
`export type ${pascalName}Agent = AgentRunner<`,
|
|
210
|
-
`\t${pascalName}InputSchema,`,
|
|
211
|
-
`\t${pascalName}OutputSchema,`,
|
|
212
|
-
`\ttypeof ${camelName}['stream'] extends true ? true : false`,
|
|
213
|
-
`>;`,
|
|
214
|
-
];
|
|
215
|
-
return parts.join('\n');
|
|
216
|
-
})
|
|
217
|
-
.join('\n');
|
|
218
|
-
// Generate flat registry structure with JSDoc
|
|
219
|
-
const registry = sortedAgents
|
|
220
|
-
.map(({ name, description }) => {
|
|
221
|
-
const camelName = toCamelCase(name);
|
|
222
|
-
const pascalName = toPascalCase(name);
|
|
223
|
-
const descComment = description ? `\n\t * ${description}` : '';
|
|
224
|
-
return `\t/**
|
|
225
|
-
\t * ${name}${descComment}
|
|
226
|
-
\t * @type {${pascalName}Agent}
|
|
227
|
-
\t */
|
|
228
|
-
\t${camelName},`;
|
|
229
|
-
})
|
|
230
|
-
.join('\n');
|
|
231
|
-
// Generate flat agent type definitions for AgentRegistry interface augmentation
|
|
232
|
-
// Uses the exported Agent types defined above
|
|
233
|
-
const runtimeAgentTypes = sortedAgents
|
|
234
|
-
.map(({ name }) => {
|
|
235
|
-
const camelName = toCamelCase(name);
|
|
236
|
-
const pascalName = toPascalCase(name);
|
|
237
|
-
return ` ${camelName}: ${pascalName}Agent;`;
|
|
238
|
-
})
|
|
239
|
-
.join('\n');
|
|
240
|
-
// Build eval imports section (side-effect imports for createEval registration)
|
|
241
|
-
const evalImportsSection = evalImports.length > 0
|
|
242
|
-
? `
|
|
243
|
-
// Eval file imports (side-effect imports to register evals via createEval)
|
|
244
|
-
${evalImports.join('\n')}
|
|
245
|
-
`
|
|
246
|
-
: '';
|
|
247
|
-
const generatedContent = `// @generated
|
|
248
|
-
// Auto-generated by Agentuity - DO NOT EDIT
|
|
249
|
-
${imports}
|
|
250
|
-
import type { AgentRunner } from '@agentuity/runtime';
|
|
251
|
-
import type { InferInput, InferOutput } from '@agentuity/core';
|
|
252
|
-
${evalImportsSection}
|
|
253
|
-
|
|
254
|
-
// ============================================================================
|
|
255
|
-
// Schema Type Exports
|
|
256
|
-
// ============================================================================
|
|
257
|
-
${schemaTypeExports}
|
|
258
|
-
|
|
259
|
-
// ============================================================================
|
|
260
|
-
// Agent Definitions
|
|
261
|
-
// ============================================================================
|
|
262
|
-
|
|
263
|
-
/**
|
|
264
|
-
* Agent Definitions
|
|
265
|
-
*
|
|
266
|
-
* Registry of all agents in this application.
|
|
267
|
-
* Provides strongly-typed access to agent metadata and runner functions.
|
|
268
|
-
*
|
|
269
|
-
* @remarks
|
|
270
|
-
* This object is auto-generated from your agent files during build.
|
|
271
|
-
* Each agent has corresponding Input, Output, and Runner types exported above.
|
|
272
|
-
*
|
|
273
|
-
* @example
|
|
274
|
-
* \`\`\`typescript
|
|
275
|
-
* import { AgentDefinitions, SessionBasicInput } from './generated/registry';
|
|
276
|
-
*
|
|
277
|
-
* // Access agent definition
|
|
278
|
-
* const agent = AgentDefinitions.sessionBasic;
|
|
279
|
-
*
|
|
280
|
-
* // Use typed schema types
|
|
281
|
-
* const input: SessionBasicInput = { ... };
|
|
282
|
-
* const result = await agent.run(input);
|
|
283
|
-
* \`\`\`
|
|
284
|
-
*/
|
|
285
|
-
export const AgentDefinitions = {
|
|
286
|
-
${registry}
|
|
287
|
-
} as const;
|
|
288
|
-
|
|
289
|
-
// ============================================================================
|
|
290
|
-
// Module Augmentation
|
|
291
|
-
// ============================================================================
|
|
292
|
-
|
|
293
|
-
// Augment @agentuity/runtime types with strongly-typed agents from this project
|
|
294
|
-
declare module "@agentuity/runtime" {
|
|
295
|
-
// Augment the AgentRegistry interface with project-specific strongly-typed agents
|
|
296
|
-
export interface AgentRegistry {
|
|
297
|
-
${runtimeAgentTypes}
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
// FOUND AN ERROR IN THIS FILE?
|
|
302
|
-
// Please file an issue at https://github.com/agentuity/sdk/issues
|
|
303
|
-
// or if you know the fix please submit a PR!
|
|
304
|
-
`;
|
|
305
|
-
const agentsDir = join(srcDir, 'agent');
|
|
306
|
-
const legacyTypesPath = join(agentsDir, 'types.generated.d.ts');
|
|
307
|
-
// Ensure src/generated directory exists
|
|
308
|
-
if (!existsSync(generatedDir)) {
|
|
309
|
-
mkdirSync(generatedDir, { recursive: true });
|
|
310
|
-
}
|
|
311
|
-
// Collapse 2+ consecutive empty lines into 1 empty line (3+ \n becomes 2 \n)
|
|
312
|
-
const cleanedContent = generatedContent.replace(/\n{3,}/g, '\n\n');
|
|
313
|
-
writeFileSync(registryPath, cleanedContent, 'utf-8');
|
|
314
|
-
// Remove legacy types.generated.d.ts if it exists (legacy cleanup)
|
|
315
|
-
if (existsSync(legacyTypesPath)) {
|
|
316
|
-
unlinkSync(legacyTypesPath);
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
/**
|
|
320
|
-
* Helper function to generate RPC-style nested registry type.
|
|
321
|
-
* Converts routes like "POST /api/hello" to nested structure: post.api.hello
|
|
322
|
-
*/
|
|
323
|
-
function generateRPCRegistryType(apiRoutes, websocketRoutes, sseRoutes, agentImports, _schemaImportAliases, agentMetadataMap) {
|
|
324
|
-
const tree = {};
|
|
325
|
-
// Helper to add route to tree
|
|
326
|
-
const addRoute = (route, routeType) => {
|
|
327
|
-
const method = route.method.toLowerCase();
|
|
328
|
-
// Strip /api prefix from path
|
|
329
|
-
let cleanPath = route.path;
|
|
330
|
-
if (cleanPath.startsWith('/api/')) {
|
|
331
|
-
cleanPath = cleanPath.substring(4); // Remove '/api'
|
|
332
|
-
}
|
|
333
|
-
else if (cleanPath === '/api') {
|
|
334
|
-
cleanPath = '/';
|
|
335
|
-
}
|
|
336
|
-
const pathParts = cleanPath.split('/').filter(Boolean);
|
|
337
|
-
// Navigate/create tree structure: path segments first, then method
|
|
338
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
339
|
-
let current = tree;
|
|
340
|
-
// Add path segments - sanitize for valid TypeScript property names
|
|
341
|
-
for (let i = 0; i < pathParts.length; i++) {
|
|
342
|
-
const rawPart = pathParts[i];
|
|
343
|
-
if (!rawPart) {
|
|
344
|
-
continue;
|
|
345
|
-
}
|
|
346
|
-
const part = sanitizePathSegment(rawPart);
|
|
347
|
-
// Skip empty segments (e.g., wildcards like '*' that sanitize to '')
|
|
348
|
-
if (!part) {
|
|
349
|
-
continue;
|
|
350
|
-
}
|
|
351
|
-
if (!current[part]) {
|
|
352
|
-
current[part] = {};
|
|
353
|
-
}
|
|
354
|
-
current = current[part];
|
|
355
|
-
}
|
|
356
|
-
// Determine terminal method name based on route type
|
|
357
|
-
// For stream types (websocket, sse, stream), use the type name as the method
|
|
358
|
-
// For regular API routes, use the HTTP method
|
|
359
|
-
const terminalMethod = routeType === 'websocket'
|
|
360
|
-
? 'websocket'
|
|
361
|
-
: routeType === 'sse'
|
|
362
|
-
? 'eventstream'
|
|
363
|
-
: routeType === 'stream'
|
|
364
|
-
? 'stream'
|
|
365
|
-
: method;
|
|
366
|
-
// Add method as final level with schema types
|
|
367
|
-
const routeKey = `${route.method.toUpperCase()} ${route.path}`;
|
|
368
|
-
const safeName = routeKey
|
|
369
|
-
.replace(/[^a-zA-Z0-9]/g, '_')
|
|
370
|
-
.replace(/^_+|_+$/g, '')
|
|
371
|
-
.replace(/_+/g, '_');
|
|
372
|
-
const pascalName = toPascalCase(safeName);
|
|
373
|
-
// Only reference type names if route has actual schemas extracted, otherwise use 'never'
|
|
374
|
-
// Note: hasValidator may be true (e.g., zValidator('query', ...)) but no schemas extracted
|
|
375
|
-
// because only 'json' validators extract input schemas
|
|
376
|
-
// Also check if agentVariable exists but import wasn't added (missing agentImportPath)
|
|
377
|
-
const hasValidAgentImport = route.agentVariable
|
|
378
|
-
? !!agentImports.get(route.agentVariable)
|
|
379
|
-
: false;
|
|
380
|
-
const hasSchemas = route.inputSchemaVariable || route.outputSchemaVariable || hasValidAgentImport;
|
|
381
|
-
current[terminalMethod] = {
|
|
382
|
-
input: hasSchemas ? `${pascalName}Input` : 'never',
|
|
383
|
-
output: hasSchemas ? `${pascalName}Output` : 'never',
|
|
384
|
-
type: `'${routeType}'`,
|
|
385
|
-
route,
|
|
386
|
-
};
|
|
387
|
-
};
|
|
388
|
-
// Add all routes with their types
|
|
389
|
-
apiRoutes.forEach((route) => {
|
|
390
|
-
const routeType = route.routeType === 'stream' ? 'stream' : 'api';
|
|
391
|
-
addRoute(route, routeType);
|
|
392
|
-
});
|
|
393
|
-
websocketRoutes.forEach((route) => addRoute(route, 'websocket'));
|
|
394
|
-
sseRoutes.forEach((route) => addRoute(route, 'sse'));
|
|
395
|
-
// Convert tree to TypeScript type string
|
|
396
|
-
function treeToTypeString(node, indent = '\t\t') {
|
|
397
|
-
const lines = [];
|
|
398
|
-
// Sort entries alphabetically for deterministic output
|
|
399
|
-
const sortedEntries = Object.entries(node).sort(([a], [b]) => a.localeCompare(b));
|
|
400
|
-
for (const [key, value] of sortedEntries) {
|
|
401
|
-
if (value &&
|
|
402
|
-
typeof value === 'object' &&
|
|
403
|
-
'input' in value &&
|
|
404
|
-
'output' in value &&
|
|
405
|
-
'type' in value &&
|
|
406
|
-
'route' in value) {
|
|
407
|
-
// Leaf node with schema and type - add JSDoc
|
|
408
|
-
const route = value.route;
|
|
409
|
-
const jsdoc = [];
|
|
410
|
-
// Access route info from value
|
|
411
|
-
const routeInfo = route;
|
|
412
|
-
// Look up agent metadata
|
|
413
|
-
let agentMeta;
|
|
414
|
-
if (routeInfo.agentVariable) {
|
|
415
|
-
agentMeta = agentMetadataMap.get(routeInfo.agentVariable);
|
|
416
|
-
}
|
|
417
|
-
// Build JSDoc comment
|
|
418
|
-
jsdoc.push(`${indent}/**`);
|
|
419
|
-
jsdoc.push(`${indent} * Route: ${routeInfo.method.toUpperCase()} ${routeInfo.path}`);
|
|
420
|
-
if (agentMeta?.name) {
|
|
421
|
-
jsdoc.push(`${indent} * @agent ${agentMeta.name}`);
|
|
422
|
-
}
|
|
423
|
-
if (agentMeta?.description) {
|
|
424
|
-
jsdoc.push(`${indent} * @description ${agentMeta.description}`);
|
|
425
|
-
}
|
|
426
|
-
jsdoc.push(`${indent} */`);
|
|
427
|
-
lines.push(...jsdoc);
|
|
428
|
-
const pathParamsType = generatePathParamsType(routeInfo.pathParams);
|
|
429
|
-
const pathParamsTupleType = generatePathParamsTupleType(routeInfo.pathParams);
|
|
430
|
-
lines.push(`${indent}${quotePropertyName(key)}: { input: ${value.input}; output: ${value.output}; type: ${value.type}; params: ${pathParamsType}; paramsTuple: ${pathParamsTupleType} };`);
|
|
431
|
-
}
|
|
432
|
-
else {
|
|
433
|
-
// Nested node
|
|
434
|
-
lines.push(`${indent}${quotePropertyName(key)}: {`);
|
|
435
|
-
lines.push(treeToTypeString(value, indent + '\t'));
|
|
436
|
-
lines.push(`${indent}};`);
|
|
437
|
-
}
|
|
438
|
-
}
|
|
439
|
-
return lines.join('\n');
|
|
440
|
-
}
|
|
441
|
-
if (Object.keys(tree).length === 0) {
|
|
442
|
-
return '\t\t// No routes discovered';
|
|
443
|
-
}
|
|
444
|
-
return treeToTypeString(tree);
|
|
445
|
-
}
|
|
446
|
-
/**
|
|
447
|
-
* Generate runtime metadata object for RPC routes.
|
|
448
|
-
* This allows the client to know route types at runtime.
|
|
449
|
-
*/
|
|
450
|
-
function generateRPCRuntimeMetadata(apiRoutes, websocketRoutes, sseRoutes) {
|
|
451
|
-
const tree = {};
|
|
452
|
-
const addRoute = (route, routeType) => {
|
|
453
|
-
let cleanPath = route.path;
|
|
454
|
-
if (cleanPath.startsWith('/api/')) {
|
|
455
|
-
cleanPath = cleanPath.substring(4);
|
|
456
|
-
}
|
|
457
|
-
else if (cleanPath === '/api') {
|
|
458
|
-
cleanPath = '/';
|
|
459
|
-
}
|
|
460
|
-
const pathParts = cleanPath.split('/').filter(Boolean);
|
|
461
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
462
|
-
let current = tree;
|
|
463
|
-
// Sanitize path segments for valid property names (must match type generation)
|
|
464
|
-
for (const part of pathParts) {
|
|
465
|
-
const sanitized = sanitizePathSegment(part);
|
|
466
|
-
// Skip empty segments (e.g., wildcards like '*' that sanitize to '')
|
|
467
|
-
if (!sanitized) {
|
|
468
|
-
continue;
|
|
469
|
-
}
|
|
470
|
-
if (!current[sanitized])
|
|
471
|
-
current[sanitized] = {};
|
|
472
|
-
current = current[sanitized];
|
|
473
|
-
}
|
|
474
|
-
// Use terminal method name based on route type
|
|
475
|
-
const terminalMethod = routeType === 'websocket'
|
|
476
|
-
? 'websocket'
|
|
477
|
-
: routeType === 'sse'
|
|
478
|
-
? 'eventstream'
|
|
479
|
-
: routeType === 'stream'
|
|
480
|
-
? 'stream'
|
|
481
|
-
: route.method.toLowerCase();
|
|
482
|
-
const metadata = {
|
|
483
|
-
type: routeType,
|
|
484
|
-
path: route.path,
|
|
485
|
-
};
|
|
486
|
-
if (route.pathParams && route.pathParams.length > 0) {
|
|
487
|
-
metadata.pathParams = route.pathParams;
|
|
488
|
-
}
|
|
489
|
-
current[terminalMethod] = metadata;
|
|
490
|
-
};
|
|
491
|
-
apiRoutes.forEach((r) => addRoute(r, r.routeType === 'stream' ? 'stream' : 'api'));
|
|
492
|
-
websocketRoutes.forEach((r) => addRoute(r, 'websocket'));
|
|
493
|
-
sseRoutes.forEach((r) => addRoute(r, 'sse'));
|
|
494
|
-
// Sort object keys recursively for deterministic output
|
|
495
|
-
const sortObject = (obj) => {
|
|
496
|
-
const sorted = {};
|
|
497
|
-
for (const key of Object.keys(obj).sort()) {
|
|
498
|
-
const value = obj[key];
|
|
499
|
-
if (value === undefined) {
|
|
500
|
-
continue;
|
|
501
|
-
}
|
|
502
|
-
if (typeof value === 'object' && !('type' in value)) {
|
|
503
|
-
sorted[key] = sortObject(value);
|
|
504
|
-
}
|
|
505
|
-
else {
|
|
506
|
-
sorted[key] = value;
|
|
507
|
-
}
|
|
508
|
-
}
|
|
509
|
-
return sorted;
|
|
510
|
-
};
|
|
511
|
-
return JSON.stringify(sortObject(tree), null, '\t\t');
|
|
512
|
-
}
|
|
513
|
-
/**
|
|
514
|
-
* Generate RouteRegistry type definitions from discovered routes.
|
|
515
|
-
*
|
|
516
|
-
* Creates a module augmentation for @agentuity/react that provides
|
|
517
|
-
* strongly-typed route keys with input/output schema information.
|
|
518
|
-
*/
|
|
519
|
-
export async function generateRouteRegistry(srcDir, routes, agents = []) {
|
|
520
|
-
const projectRoot = join(srcDir, '..');
|
|
521
|
-
const packageJsonPath = join(projectRoot, 'package.json');
|
|
522
|
-
let hasReactDependency = false;
|
|
523
|
-
let hasFrontendDependency = false;
|
|
524
|
-
try {
|
|
525
|
-
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
|
|
526
|
-
hasReactDependency = !!(packageJson.dependencies?.['@agentuity/react'] ||
|
|
527
|
-
packageJson.devDependencies?.['@agentuity/react']);
|
|
528
|
-
hasFrontendDependency = !!(packageJson.dependencies?.['@agentuity/frontend'] ||
|
|
529
|
-
packageJson.devDependencies?.['@agentuity/frontend']);
|
|
530
|
-
}
|
|
531
|
-
catch {
|
|
532
|
-
// If we can't read package.json, assume no frontend dependencies
|
|
533
|
-
}
|
|
534
|
-
const webDir = join(srcDir, 'web');
|
|
535
|
-
let hasWebDirectory = false;
|
|
536
|
-
try {
|
|
537
|
-
const webDirStat = await stat(webDir);
|
|
538
|
-
hasWebDirectory = webDirStat.isDirectory();
|
|
539
|
-
}
|
|
540
|
-
catch {
|
|
541
|
-
// Directory doesn't exist
|
|
542
|
-
}
|
|
543
|
-
const shouldEmitFrontendClient = hasFrontendDependency && !hasReactDependency && hasWebDirectory;
|
|
544
|
-
// Filter routes by type and sort by path for deterministic output
|
|
545
|
-
const sortByPath = (a, b) => a.path.localeCompare(b.path);
|
|
546
|
-
const apiRoutes = routes
|
|
547
|
-
.filter((r) => r.routeType === 'api' || r.routeType === 'stream')
|
|
548
|
-
.sort(sortByPath);
|
|
549
|
-
const websocketRoutes = routes.filter((r) => r.routeType === 'websocket').sort(sortByPath);
|
|
550
|
-
const sseRoutes = routes.filter((r) => r.routeType === 'sse').sort(sortByPath);
|
|
551
|
-
const allRoutes = [...apiRoutes, ...websocketRoutes, ...sseRoutes];
|
|
552
|
-
// Create maps for agent metadata lookup
|
|
553
|
-
const agentMetadataMap = new Map();
|
|
554
|
-
const agentNameMap = new Map();
|
|
555
|
-
// Map by agent name for easy lookup
|
|
556
|
-
agents.forEach((agent) => {
|
|
557
|
-
agentNameMap.set(agent.name, agent);
|
|
558
|
-
});
|
|
559
|
-
// Map agent import variables to metadata by extracting agent name from import path
|
|
560
|
-
allRoutes.forEach((route) => {
|
|
561
|
-
if (route.agentVariable && route.agentImportPath) {
|
|
562
|
-
// Extract agent name from import path (e.g., "@agent/hello" -> "hello")
|
|
563
|
-
const match = route.agentImportPath.match(/@agent[s]?\/([^/]+)/);
|
|
564
|
-
if (match) {
|
|
565
|
-
const agentName = match[1];
|
|
566
|
-
if (agentName) {
|
|
567
|
-
const metadata = agentNameMap.get(agentName);
|
|
568
|
-
if (metadata) {
|
|
569
|
-
agentMetadataMap.set(route.agentVariable, metadata);
|
|
570
|
-
}
|
|
571
|
-
}
|
|
572
|
-
}
|
|
573
|
-
}
|
|
574
|
-
});
|
|
575
|
-
if (apiRoutes.length === 0 && websocketRoutes.length === 0 && sseRoutes.length === 0) {
|
|
576
|
-
// Clean up stale routes.ts from previous builds (issue #924)
|
|
577
|
-
// When all API routes are removed, the old file would reference deleted modules
|
|
578
|
-
const generatedDir = join(srcDir, 'generated');
|
|
579
|
-
const registryPath = join(generatedDir, 'routes.ts');
|
|
580
|
-
if (existsSync(registryPath)) {
|
|
581
|
-
unlinkSync(registryPath);
|
|
582
|
-
}
|
|
583
|
-
return;
|
|
584
|
-
}
|
|
585
|
-
// Generate imports for agents and schemas
|
|
586
|
-
const imports = [];
|
|
587
|
-
const agentImports = new Map();
|
|
588
|
-
const routeFileImports = new Map();
|
|
589
|
-
// Track per-route which import path and schema name to use for alias lookup
|
|
590
|
-
const routeSchemaImportInfo = new Map();
|
|
591
|
-
// Collect agent and schema imports from routes with validators or exported schemas
|
|
592
|
-
allRoutes.forEach((route) => {
|
|
593
|
-
const hasSchemaVars = !!route.inputSchemaVariable || !!route.outputSchemaVariable;
|
|
594
|
-
if (!route.hasValidator && !hasSchemaVars && !route.agentVariable)
|
|
595
|
-
return;
|
|
596
|
-
// Collect agent imports (when using agent.validator())
|
|
597
|
-
if (route.hasValidator &&
|
|
598
|
-
route.agentVariable &&
|
|
599
|
-
route.agentImportPath &&
|
|
600
|
-
!agentImports.has(route.agentVariable)) {
|
|
601
|
-
let resolvedPath = route.agentImportPath;
|
|
602
|
-
if (resolvedPath.startsWith('@agents/') || resolvedPath.startsWith('@agent/')) {
|
|
603
|
-
// Handle both @agents/ and @agent/ aliases -> ../agent/
|
|
604
|
-
const suffix = resolvedPath.startsWith('@agents/')
|
|
605
|
-
? resolvedPath.substring('@agents/'.length)
|
|
606
|
-
: resolvedPath.substring('@agent/'.length);
|
|
607
|
-
// Convert @agent/hello -> ../agent/hello/index.js
|
|
608
|
-
// Convert @agent/hello/agent -> ../agent/hello/agent.js
|
|
609
|
-
if (!suffix.includes('/')) {
|
|
610
|
-
// Bare module (e.g., @agent/hello) - add /index.js
|
|
611
|
-
resolvedPath = `../agent/${suffix}/index.js`;
|
|
612
|
-
}
|
|
613
|
-
else {
|
|
614
|
-
// File path (e.g., @agent/hello/agent) - add .js
|
|
615
|
-
const finalPath = suffix.endsWith('.js')
|
|
616
|
-
? suffix
|
|
617
|
-
: suffix.replace(/\.tsx?$/, '') + '.js';
|
|
618
|
-
resolvedPath = `../agent/${finalPath}`;
|
|
619
|
-
}
|
|
620
|
-
}
|
|
621
|
-
else if (resolvedPath.startsWith('@api/')) {
|
|
622
|
-
// src/generated/ -> src/api/ is ../api/
|
|
623
|
-
const suffix = resolvedPath.substring('@api/'.length);
|
|
624
|
-
const finalPath = suffix.endsWith('.js')
|
|
625
|
-
? suffix
|
|
626
|
-
: suffix.replace(/\.tsx?$/, '') + '.js';
|
|
627
|
-
resolvedPath = `../api/${finalPath}`;
|
|
628
|
-
}
|
|
629
|
-
else if (resolvedPath.startsWith('./') || resolvedPath.startsWith('../')) {
|
|
630
|
-
// Resolve relative import from route file's directory
|
|
631
|
-
// Use schemaSourceFile when available (sub-router routes)
|
|
632
|
-
const normalizedFilename = toForwardSlash(route.schemaSourceFile ?? route.filename);
|
|
633
|
-
const routeDir = normalizedFilename.substring(0, normalizedFilename.lastIndexOf('/'));
|
|
634
|
-
// Join and normalize the path
|
|
635
|
-
const joined = `${routeDir}/${resolvedPath}`;
|
|
636
|
-
// Normalize by resolving .. and . segments
|
|
637
|
-
const normalized = joined
|
|
638
|
-
.split('/')
|
|
639
|
-
.reduce((acc, segment) => {
|
|
640
|
-
if (segment === '..') {
|
|
641
|
-
acc.pop();
|
|
642
|
-
}
|
|
643
|
-
else if (segment !== '.' && segment !== '') {
|
|
644
|
-
acc.push(segment);
|
|
645
|
-
}
|
|
646
|
-
return acc;
|
|
647
|
-
}, [])
|
|
648
|
-
.join('/');
|
|
649
|
-
// Remove 'src/' prefix if present (routes are in src/, generated is in src/generated/)
|
|
650
|
-
const withoutSrc = normalized.startsWith('src/') ? normalized.substring(4) : normalized;
|
|
651
|
-
// Make it relative from src/generated/
|
|
652
|
-
resolvedPath = `../${withoutSrc}`;
|
|
653
|
-
// Check if this is a directory import (no file extension) vs a file import
|
|
654
|
-
// Directory imports like '../agent/translate' should resolve to '../agent/translate/index.js'
|
|
655
|
-
// File imports like '../agent/translate/agent' should resolve to '../agent/translate/agent.js'
|
|
656
|
-
const hasExtension = /\.(ts|tsx|js|jsx|mjs|cjs)$/.test(resolvedPath);
|
|
657
|
-
if (!hasExtension) {
|
|
658
|
-
// No extension - check if it's a directory or a file
|
|
659
|
-
// Try to resolve the actual path on disk to determine
|
|
660
|
-
const absolutePath = join(srcDir, withoutSrc);
|
|
661
|
-
const isDirectory = existsSync(absolutePath) ||
|
|
662
|
-
existsSync(join(absolutePath, 'index.ts')) ||
|
|
663
|
-
existsSync(join(absolutePath, 'index.tsx'));
|
|
664
|
-
const isFile = existsSync(`${absolutePath}.ts`) || existsSync(`${absolutePath}.tsx`);
|
|
665
|
-
if (isDirectory && !isFile) {
|
|
666
|
-
// It's a directory import, add /index.js
|
|
667
|
-
resolvedPath = `${resolvedPath}/index.js`;
|
|
668
|
-
}
|
|
669
|
-
else {
|
|
670
|
-
// It's a file import (or we can't determine), add .js
|
|
671
|
-
resolvedPath = `${resolvedPath}.js`;
|
|
672
|
-
}
|
|
673
|
-
}
|
|
674
|
-
else {
|
|
675
|
-
// Has extension - replace with .js
|
|
676
|
-
resolvedPath = resolvedPath.replace(/\.tsx?$/, '.js');
|
|
677
|
-
}
|
|
678
|
-
}
|
|
679
|
-
const uniqueImportName = route.agentVariable;
|
|
680
|
-
imports.push(`import type ${uniqueImportName} from '${resolvedPath}';`);
|
|
681
|
-
agentImports.set(route.agentVariable, uniqueImportName);
|
|
682
|
-
}
|
|
683
|
-
// Collect schema variable imports
|
|
684
|
-
// If the schema is imported from another file, use that file's path (rebased)
|
|
685
|
-
// Otherwise fall back to the route file path (for locally defined schemas)
|
|
686
|
-
if (route.inputSchemaVariable) {
|
|
687
|
-
let importPath;
|
|
688
|
-
let schemaNameToImport;
|
|
689
|
-
if (route.inputSchemaImportPath) {
|
|
690
|
-
// Schema is imported - rebase the import path from route file to generated file
|
|
691
|
-
// Use schemaSourceFile if available (sub-router routes carry the original file)
|
|
692
|
-
const sourceFile = route.schemaSourceFile ?? route.filename;
|
|
693
|
-
importPath = rebaseImportPath(sourceFile, route.inputSchemaImportPath, srcDir);
|
|
694
|
-
// Use the actual exported name (handles aliased imports like `import { A as B }`)
|
|
695
|
-
schemaNameToImport =
|
|
696
|
-
route.inputSchemaImportedName === 'default'
|
|
697
|
-
? route.inputSchemaVariable
|
|
698
|
-
: (route.inputSchemaImportedName ?? route.inputSchemaVariable);
|
|
699
|
-
}
|
|
700
|
-
else {
|
|
701
|
-
// Schema is locally defined - import from the file that defines/exports it
|
|
702
|
-
// When route is mounted via .route(), schemaSourceFile points to the sub-router file
|
|
703
|
-
const sourceFile = route.schemaSourceFile ?? route.filename;
|
|
704
|
-
const filename = toForwardSlash(sourceFile);
|
|
705
|
-
const withoutSrc = filename.startsWith('src/') ? filename.substring(4) : filename;
|
|
706
|
-
const withoutLeadingDot = withoutSrc.startsWith('./')
|
|
707
|
-
? withoutSrc.substring(2)
|
|
708
|
-
: withoutSrc;
|
|
709
|
-
importPath = `../${withoutLeadingDot.replace(/\.ts$/, '')}`;
|
|
710
|
-
schemaNameToImport = route.inputSchemaVariable;
|
|
711
|
-
}
|
|
712
|
-
if (!routeFileImports.has(importPath)) {
|
|
713
|
-
routeFileImports.set(importPath, new Set());
|
|
714
|
-
}
|
|
715
|
-
routeFileImports.get(importPath).add(schemaNameToImport);
|
|
716
|
-
// Store the resolved import info for later alias lookup
|
|
717
|
-
routeSchemaImportInfo.set(`input:${route.path}:${route.method}`, {
|
|
718
|
-
importPath,
|
|
719
|
-
schemaName: schemaNameToImport,
|
|
720
|
-
});
|
|
721
|
-
}
|
|
722
|
-
if (route.outputSchemaVariable) {
|
|
723
|
-
let importPath;
|
|
724
|
-
let schemaNameToImport;
|
|
725
|
-
if (route.outputSchemaImportPath) {
|
|
726
|
-
// Schema is imported - rebase the import path from route file to generated file
|
|
727
|
-
const sourceFile = route.schemaSourceFile ?? route.filename;
|
|
728
|
-
importPath = rebaseImportPath(sourceFile, route.outputSchemaImportPath, srcDir);
|
|
729
|
-
// Use the actual exported name (handles aliased imports like `import { A as B }`)
|
|
730
|
-
schemaNameToImport =
|
|
731
|
-
route.outputSchemaImportedName === 'default'
|
|
732
|
-
? route.outputSchemaVariable
|
|
733
|
-
: (route.outputSchemaImportedName ?? route.outputSchemaVariable);
|
|
734
|
-
}
|
|
735
|
-
else {
|
|
736
|
-
// Schema is locally defined - import from the file that defines/exports it
|
|
737
|
-
const sourceFile = route.schemaSourceFile ?? route.filename;
|
|
738
|
-
const filename = toForwardSlash(sourceFile);
|
|
739
|
-
const withoutSrc = filename.startsWith('src/') ? filename.substring(4) : filename;
|
|
740
|
-
const withoutLeadingDot = withoutSrc.startsWith('./')
|
|
741
|
-
? withoutSrc.substring(2)
|
|
742
|
-
: withoutSrc;
|
|
743
|
-
importPath = `../${withoutLeadingDot.replace(/\.ts$/, '')}`;
|
|
744
|
-
schemaNameToImport = route.outputSchemaVariable;
|
|
745
|
-
}
|
|
746
|
-
if (!routeFileImports.has(importPath)) {
|
|
747
|
-
routeFileImports.set(importPath, new Set());
|
|
748
|
-
}
|
|
749
|
-
routeFileImports.get(importPath).add(schemaNameToImport);
|
|
750
|
-
// Store the resolved import info for later alias lookup
|
|
751
|
-
routeSchemaImportInfo.set(`output:${route.path}:${route.method}`, {
|
|
752
|
-
importPath,
|
|
753
|
-
schemaName: schemaNameToImport,
|
|
754
|
-
});
|
|
755
|
-
}
|
|
756
|
-
});
|
|
757
|
-
// Generate schema imports, only aliasing when names collide across files
|
|
758
|
-
const schemaImportAliases = new Map(); // importPath -> (schemaName -> alias)
|
|
759
|
-
// First pass: count how many times each schema name appears across all import paths
|
|
760
|
-
const globalNameCount = new Map();
|
|
761
|
-
routeFileImports.forEach((schemas) => {
|
|
762
|
-
for (const schemaName of schemas) {
|
|
763
|
-
globalNameCount.set(schemaName, (globalNameCount.get(schemaName) ?? 0) + 1);
|
|
764
|
-
}
|
|
765
|
-
});
|
|
766
|
-
// Track aliases assigned to duplicated names for uniqueness
|
|
767
|
-
const duplicateCounters = new Map();
|
|
768
|
-
routeFileImports.forEach((schemas, importPath) => {
|
|
769
|
-
const aliases = new Map();
|
|
770
|
-
const importParts = [];
|
|
771
|
-
for (const schemaName of Array.from(schemas)) {
|
|
772
|
-
if ((globalNameCount.get(schemaName) ?? 0) > 1) {
|
|
773
|
-
// Name appears in multiple import paths — alias to avoid collision
|
|
774
|
-
const counter = duplicateCounters.get(schemaName) ?? 0;
|
|
775
|
-
duplicateCounters.set(schemaName, counter + 1);
|
|
776
|
-
const alias = `${schemaName}_${counter}`;
|
|
777
|
-
aliases.set(schemaName, alias);
|
|
778
|
-
importParts.push(`${schemaName} as ${alias}`);
|
|
779
|
-
}
|
|
780
|
-
else {
|
|
781
|
-
// Unique name — import directly, no alias needed
|
|
782
|
-
aliases.set(schemaName, schemaName);
|
|
783
|
-
importParts.push(schemaName);
|
|
784
|
-
}
|
|
785
|
-
}
|
|
786
|
-
schemaImportAliases.set(importPath, aliases);
|
|
787
|
-
imports.push(`import type { ${importParts.join(', ')} } from '${importPath}';`);
|
|
788
|
-
});
|
|
789
|
-
const importsStr = imports.length > 0 ? imports.join('\n') + '\n' : '';
|
|
790
|
-
// Add InferInput/InferOutput imports if we have any routes with schemas
|
|
791
|
-
const hasSchemas = allRoutes.some((r) => r.hasValidator || r.inputSchemaVariable || r.outputSchemaVariable || r.agentVariable);
|
|
792
|
-
const typeImports = hasSchemas
|
|
793
|
-
? `import type { InferInput, InferOutput } from '@agentuity/core';\n`
|
|
794
|
-
: '';
|
|
795
|
-
// Generate individual route schema types
|
|
796
|
-
const routeSchemaTypes = allRoutes
|
|
797
|
-
.filter((r) => r.hasValidator || r.inputSchemaVariable || r.outputSchemaVariable || r.agentVariable)
|
|
798
|
-
.map((route) => {
|
|
799
|
-
const routeKey = route.method ? `${route.method.toUpperCase()} ${route.path}` : route.path;
|
|
800
|
-
const safeName = routeKey
|
|
801
|
-
.replace(/[^a-zA-Z0-9]/g, '_')
|
|
802
|
-
.replace(/^_+|_+$/g, '')
|
|
803
|
-
.replace(/_+/g, '_');
|
|
804
|
-
const pascalName = toPascalCase(safeName);
|
|
805
|
-
let inputType = 'never';
|
|
806
|
-
let outputType = 'never';
|
|
807
|
-
let inputSchemaType = 'never';
|
|
808
|
-
let outputSchemaType = 'never';
|
|
809
|
-
let agentMeta;
|
|
810
|
-
// Look up agent metadata if available
|
|
811
|
-
if (route.agentVariable) {
|
|
812
|
-
agentMeta = agentMetadataMap.get(route.agentVariable);
|
|
813
|
-
}
|
|
814
|
-
// Only generate agent-based types if the import was successfully added
|
|
815
|
-
// (import is only added when hasValidator && agentVariable && agentImportPath are all present)
|
|
816
|
-
const importName = route.agentVariable ? agentImports.get(route.agentVariable) : undefined;
|
|
817
|
-
if (importName) {
|
|
818
|
-
inputType = `InferInput<typeof ${importName}['inputSchema']>`;
|
|
819
|
-
outputType = `InferOutput<typeof ${importName}['outputSchema']>`;
|
|
820
|
-
inputSchemaType = `typeof ${importName} extends { inputSchema?: infer I } ? I : never`;
|
|
821
|
-
outputSchemaType = `typeof ${importName} extends { outputSchema?: infer O } ? O : never`;
|
|
822
|
-
}
|
|
823
|
-
else if (route.inputSchemaVariable || route.outputSchemaVariable) {
|
|
824
|
-
// Get the aliased schema names using the stored import info
|
|
825
|
-
// (which correctly handles schemas imported from shared files)
|
|
826
|
-
const inputInfo = routeSchemaImportInfo.get(`input:${route.path}:${route.method}`);
|
|
827
|
-
const outputInfo = routeSchemaImportInfo.get(`output:${route.path}:${route.method}`);
|
|
828
|
-
let inputAlias;
|
|
829
|
-
let outputAlias;
|
|
830
|
-
if (inputInfo) {
|
|
831
|
-
const aliases = schemaImportAliases.get(inputInfo.importPath);
|
|
832
|
-
inputAlias = aliases?.get(inputInfo.schemaName);
|
|
833
|
-
}
|
|
834
|
-
if (outputInfo) {
|
|
835
|
-
const aliases = schemaImportAliases.get(outputInfo.importPath);
|
|
836
|
-
outputAlias = aliases?.get(outputInfo.schemaName);
|
|
837
|
-
}
|
|
838
|
-
inputType = inputAlias ? `InferInput<typeof ${inputAlias}>` : 'never';
|
|
839
|
-
outputType = outputAlias ? `InferOutput<typeof ${outputAlias}>` : 'never';
|
|
840
|
-
inputSchemaType = inputAlias ? `typeof ${inputAlias}` : 'never';
|
|
841
|
-
outputSchemaType = outputAlias ? `typeof ${outputAlias}` : 'never';
|
|
842
|
-
}
|
|
843
|
-
if (inputType === 'never' && outputType === 'never') {
|
|
844
|
-
return ''; // Skip routes without schemas
|
|
845
|
-
}
|
|
846
|
-
// Build JSDoc with agent description and schema details
|
|
847
|
-
const inputJSDoc = ['/**', ` * Input type for route: ${routeKey}`];
|
|
848
|
-
if (agentMeta?.description) {
|
|
849
|
-
inputJSDoc.push(` * @description ${agentMeta.description}`);
|
|
850
|
-
}
|
|
851
|
-
if (agentMeta?.inputSchemaCode) {
|
|
852
|
-
inputJSDoc.push(` * @schema ${agentMeta.inputSchemaCode}`);
|
|
853
|
-
}
|
|
854
|
-
inputJSDoc.push(' */');
|
|
855
|
-
const outputJSDoc = ['/**', ` * Output type for route: ${routeKey}`];
|
|
856
|
-
if (agentMeta?.description) {
|
|
857
|
-
outputJSDoc.push(` * @description ${agentMeta.description}`);
|
|
858
|
-
}
|
|
859
|
-
if (agentMeta?.outputSchemaCode) {
|
|
860
|
-
outputJSDoc.push(` * @schema ${agentMeta.outputSchemaCode}`);
|
|
861
|
-
}
|
|
862
|
-
outputJSDoc.push(' */');
|
|
863
|
-
const parts = [
|
|
864
|
-
'',
|
|
865
|
-
...inputJSDoc,
|
|
866
|
-
`export type ${pascalName}Input = ${inputType};`,
|
|
867
|
-
'',
|
|
868
|
-
...outputJSDoc,
|
|
869
|
-
`export type ${pascalName}Output = ${outputType};`,
|
|
870
|
-
'',
|
|
871
|
-
`/**`,
|
|
872
|
-
` * Input schema type for route: ${routeKey}`,
|
|
873
|
-
` */`,
|
|
874
|
-
`export type ${pascalName}InputSchema = ${inputSchemaType};`,
|
|
875
|
-
'',
|
|
876
|
-
`/**`,
|
|
877
|
-
` * Output schema type for route: ${routeKey}`,
|
|
878
|
-
` */`,
|
|
879
|
-
`export type ${pascalName}OutputSchema = ${outputSchemaType};`,
|
|
880
|
-
];
|
|
881
|
-
return parts.join('\n');
|
|
882
|
-
})
|
|
883
|
-
.filter(Boolean)
|
|
884
|
-
.join('\n');
|
|
885
|
-
// Helper to generate route entry - uses exported schema types
|
|
886
|
-
const generateRouteEntry = (route, pathIncludesMethod = false) => {
|
|
887
|
-
const routeKey = route.path;
|
|
888
|
-
// For WebSocket/SSE routes, we need to include the method in the type name
|
|
889
|
-
// to match the generated types (which use "POST /api/websocket/echo" as the routeKey)
|
|
890
|
-
// For API routes, the method is already in the path from the caller
|
|
891
|
-
const typeRouteKey = pathIncludesMethod
|
|
892
|
-
? route.path
|
|
893
|
-
: `${route.method?.toUpperCase()} ${route.path}`;
|
|
894
|
-
const safeName = typeRouteKey
|
|
895
|
-
.replace(/[^a-zA-Z0-9]/g, '_')
|
|
896
|
-
.replace(/^_+|_+$/g, '')
|
|
897
|
-
.replace(/_+/g, '_');
|
|
898
|
-
const pascalName = toPascalCase(safeName);
|
|
899
|
-
// Use the exported schema types we generated above
|
|
900
|
-
// Note: agentImports.get() may return undefined if import wasn't added
|
|
901
|
-
const importName = route.agentVariable ? agentImports.get(route.agentVariable) : null;
|
|
902
|
-
// Use 'never' types if no schemas were actually extracted
|
|
903
|
-
// Note: hasValidator may be true (e.g., zValidator('query', ...)) but no schemas extracted
|
|
904
|
-
// because only 'json' validators extract input schemas
|
|
905
|
-
// Also check if agentVariable exists but import wasn't added (missing agentImportPath)
|
|
906
|
-
const hasValidAgentImport = route.agentVariable ? !!importName : false;
|
|
907
|
-
// Generate pathParams type
|
|
908
|
-
const pathParamsType = generatePathParamsType(route.pathParams);
|
|
909
|
-
if (!route.inputSchemaVariable && !route.outputSchemaVariable && !hasValidAgentImport) {
|
|
910
|
-
const streamValue = route.stream === true ? 'true' : 'false';
|
|
911
|
-
return `\t'${routeKey}': {
|
|
912
|
-
\t\tinputSchema: never;
|
|
913
|
-
\t\toutputSchema: never;
|
|
914
|
-
\t\tstream: ${streamValue};
|
|
915
|
-
\t\tparams: ${pathParamsType};
|
|
916
|
-
\t};`;
|
|
917
|
-
}
|
|
918
|
-
const streamValue = importName
|
|
919
|
-
? `typeof ${importName} extends { stream?: infer S } ? S : false`
|
|
920
|
-
: route.stream === true
|
|
921
|
-
? 'true'
|
|
922
|
-
: 'false';
|
|
923
|
-
return `\t'${routeKey}': {
|
|
924
|
-
\t\tinputSchema: ${pascalName}InputSchema;
|
|
925
|
-
\t\toutputSchema: ${pascalName}OutputSchema;
|
|
926
|
-
\t\tstream: ${streamValue};
|
|
927
|
-
\t\tparams: ${pathParamsType};
|
|
928
|
-
\t};`;
|
|
929
|
-
};
|
|
930
|
-
// Generate route entries with METHOD prefix for API routes
|
|
931
|
-
const apiRouteEntries = apiRoutes
|
|
932
|
-
.map((route) => {
|
|
933
|
-
const routeKey = `${route.method.toUpperCase()} ${route.path}`;
|
|
934
|
-
return generateRouteEntry({ ...route, path: routeKey }, true);
|
|
935
|
-
})
|
|
936
|
-
.join('\n');
|
|
937
|
-
const websocketRouteEntries = websocketRoutes
|
|
938
|
-
.map((r) => generateRouteEntry(r, false))
|
|
939
|
-
.join('\n');
|
|
940
|
-
const sseRouteEntries = sseRoutes.map((r) => generateRouteEntry(r, false)).join('\n');
|
|
941
|
-
// Generate RPC-style nested registry type
|
|
942
|
-
const rpcRegistryType = generateRPCRegistryType(apiRoutes, websocketRoutes, sseRoutes, agentImports, schemaImportAliases, agentMetadataMap);
|
|
943
|
-
const rpcRuntimeMetadata = generateRPCRuntimeMetadata(apiRoutes, websocketRoutes, sseRoutes);
|
|
944
|
-
const generatedContent = `// @generated
|
|
945
|
-
// Auto-generated by Agentuity - DO NOT EDIT
|
|
946
|
-
${importsStr}${typeImports}${shouldEmitFrontendClient
|
|
947
|
-
? `
|
|
948
|
-
import { createClient } from '@agentuity/frontend';`
|
|
949
|
-
: ''}
|
|
950
|
-
// ============================================================================
|
|
951
|
-
// Route Schema Type Exports
|
|
952
|
-
// ============================================================================
|
|
953
|
-
${routeSchemaTypes}
|
|
954
|
-
|
|
955
|
-
// ============================================================================
|
|
956
|
-
// Route Definitions
|
|
957
|
-
// ============================================================================
|
|
958
|
-
|
|
959
|
-
/**
|
|
960
|
-
* Route Definitions
|
|
961
|
-
*
|
|
962
|
-
* Type-safe route registry for all API routes, WebSocket connections, and SSE endpoints.
|
|
963
|
-
* Used by @agentuity/react and @agentuity/frontend for client-side type-safe routing.
|
|
964
|
-
*
|
|
965
|
-
* @remarks
|
|
966
|
-
* This module augmentation is auto-generated from your route files during build.
|
|
967
|
-
* Individual route Input/Output types are exported above for direct usage.
|
|
968
|
-
*
|
|
969
|
-
* The augmentation targets @agentuity/frontend (the canonical source of registry types).
|
|
970
|
-
* Since @agentuity/react re-exports these types, the augmentation is visible when
|
|
971
|
-
* importing from either package.
|
|
972
|
-
*/
|
|
973
|
-
${shouldEmitFrontendClient
|
|
974
|
-
? `
|
|
975
|
-
/**
|
|
976
|
-
* RPC Route Registry
|
|
977
|
-
*
|
|
978
|
-
* Nested structure for RPC-style client access (e.g., client.hello.post())
|
|
979
|
-
* Used by createClient() from @agentuity/frontend for type-safe RPC calls.
|
|
980
|
-
*/
|
|
981
|
-
export interface RPCRouteRegistry {
|
|
982
|
-
${rpcRegistryType}
|
|
983
|
-
}
|
|
984
|
-
`
|
|
985
|
-
: ''}
|
|
986
|
-
declare module '@agentuity/frontend' {
|
|
987
|
-
\t/**
|
|
988
|
-
\t * API Route Registry
|
|
989
|
-
\t *
|
|
990
|
-
\t * Maps route keys (METHOD /path) to their input/output schemas
|
|
991
|
-
\t */
|
|
992
|
-
\texport interface RouteRegistry {
|
|
993
|
-
${apiRouteEntries}
|
|
994
|
-
\t}
|
|
995
|
-
\t
|
|
996
|
-
\t/**
|
|
997
|
-
\t * WebSocket Route Registry
|
|
998
|
-
\t *
|
|
999
|
-
\t * Maps WebSocket route paths to their schemas
|
|
1000
|
-
\t */
|
|
1001
|
-
\texport interface WebSocketRouteRegistry {
|
|
1002
|
-
${websocketRouteEntries}
|
|
1003
|
-
\t}
|
|
1004
|
-
\t
|
|
1005
|
-
\t/**
|
|
1006
|
-
\t * Server-Sent Events Route Registry
|
|
1007
|
-
\t *
|
|
1008
|
-
\t * Maps SSE route paths to their schemas
|
|
1009
|
-
\t */
|
|
1010
|
-
\texport interface SSERouteRegistry {
|
|
1011
|
-
${sseRouteEntries}
|
|
1012
|
-
\t}
|
|
1013
|
-
|
|
1014
|
-
\t/**
|
|
1015
|
-
\t * RPC Route Registry
|
|
1016
|
-
\t *
|
|
1017
|
-
\t * Nested structure for RPC-style client access (e.g., client.hello.post())
|
|
1018
|
-
\t * Used by createClient() from @agentuity/frontend for type-safe RPC calls.
|
|
1019
|
-
\t */
|
|
1020
|
-
\texport interface RPCRouteRegistry {
|
|
1021
|
-
${rpcRegistryType}
|
|
1022
|
-
\t}
|
|
1023
|
-
}
|
|
1024
|
-
${hasReactDependency
|
|
1025
|
-
? `
|
|
1026
|
-
// Backward compatibility: also augment @agentuity/react for older versions
|
|
1027
|
-
// that define RouteRegistry locally instead of re-exporting from @agentuity/frontend
|
|
1028
|
-
declare module '@agentuity/react' {
|
|
1029
|
-
\texport interface RouteRegistry {
|
|
1030
|
-
${apiRouteEntries}
|
|
1031
|
-
\t}
|
|
1032
|
-
\texport interface WebSocketRouteRegistry {
|
|
1033
|
-
${websocketRouteEntries}
|
|
1034
|
-
\t}
|
|
1035
|
-
\texport interface SSERouteRegistry {
|
|
1036
|
-
${sseRouteEntries}
|
|
1037
|
-
\t}
|
|
1038
|
-
\texport interface RPCRouteRegistry {
|
|
1039
|
-
${rpcRegistryType}
|
|
1040
|
-
\t}
|
|
1041
|
-
}
|
|
1042
|
-
`
|
|
1043
|
-
: ''}
|
|
1044
|
-
/**
|
|
1045
|
-
* Runtime metadata for RPC routes.
|
|
1046
|
-
* Contains route type information for client routing decisions.
|
|
1047
|
-
* @internal
|
|
1048
|
-
*/
|
|
1049
|
-
const _rpcRouteMetadata = ${rpcRuntimeMetadata} as const;
|
|
1050
|
-
|
|
1051
|
-
// Store metadata globally for createAPIClient() to access
|
|
1052
|
-
if (typeof globalThis !== 'undefined') {
|
|
1053
|
-
(globalThis as Record<string, unknown>).__rpcRouteMetadata = _rpcRouteMetadata;
|
|
1054
|
-
}
|
|
1055
|
-
${shouldEmitFrontendClient
|
|
1056
|
-
? `
|
|
1057
|
-
/**
|
|
1058
|
-
* Create a type-safe API client with optional configuration.
|
|
1059
|
-
*
|
|
1060
|
-
* This function is only generated when @agentuity/frontend is installed
|
|
1061
|
-
* but @agentuity/react is not. For React apps, import createAPIClient
|
|
1062
|
-
* from '@agentuity/react' instead.
|
|
1063
|
-
*
|
|
1064
|
-
* @example
|
|
1065
|
-
* \`\`\`typescript
|
|
1066
|
-
* import { createAPIClient } from './generated/routes';
|
|
1067
|
-
*
|
|
1068
|
-
* // Basic usage
|
|
1069
|
-
* const api = createAPIClient();
|
|
1070
|
-
* const result = await api.hello.post({ name: 'World' });
|
|
1071
|
-
*
|
|
1072
|
-
* // With custom headers
|
|
1073
|
-
* const api = createAPIClient({ headers: { 'X-Custom-Header': 'value' } });
|
|
1074
|
-
* await api.hello.post({ name: 'World' });
|
|
1075
|
-
* \`\`\`
|
|
1076
|
-
*/
|
|
1077
|
-
export function createAPIClient(options?: Parameters<typeof createClient>[0]): import('@agentuity/frontend').Client<RPCRouteRegistry> {
|
|
1078
|
-
return createClient(options || {}, _rpcRouteMetadata) as import('@agentuity/frontend').Client<RPCRouteRegistry>;
|
|
1079
|
-
}
|
|
1080
|
-
`
|
|
1081
|
-
: hasReactDependency
|
|
1082
|
-
? `
|
|
1083
|
-
/**
|
|
1084
|
-
* Type-safe API client is available from @agentuity/react
|
|
1085
|
-
*
|
|
1086
|
-
* @example
|
|
1087
|
-
* \`\`\`typescript
|
|
1088
|
-
* import { createAPIClient } from '@agentuity/react';
|
|
1089
|
-
*
|
|
1090
|
-
* const api = createAPIClient();
|
|
1091
|
-
* const result = await api.hello.post({ name: 'World' });
|
|
1092
|
-
* \`\`\`
|
|
1093
|
-
*/
|
|
1094
|
-
`
|
|
1095
|
-
: ''}
|
|
1096
|
-
|
|
1097
|
-
// FOUND AN ERROR IN THIS FILE?
|
|
1098
|
-
// Please file an issue at https://github.com/agentuity/sdk/issues
|
|
1099
|
-
// or if you know the fix please submit a PR!
|
|
1100
|
-
`;
|
|
1101
|
-
const generatedDir = join(srcDir, 'generated');
|
|
1102
|
-
const registryPath = join(generatedDir, 'routes.ts');
|
|
1103
|
-
mkdirSync(generatedDir, { recursive: true });
|
|
1104
|
-
// Collapse 2+ consecutive empty lines into 1 empty line (3+ \n becomes 2 \n)
|
|
1105
|
-
const cleanedContent = generatedContent.replace(/\n{3,}/g, '\n\n');
|
|
1106
|
-
writeFileSync(registryPath, cleanedContent, 'utf-8');
|
|
1107
|
-
}
|
|
1108
|
-
//# sourceMappingURL=registry-generator.js.map
|