@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.
- package/AGENTS.md +19 -188
- package/bin/cli.ts +13 -6
- package/dist/api.d.ts +1 -0
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +1 -1
- package/dist/api.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +41 -12
- package/dist/cli.js.map +1 -1
- package/dist/cmd/ai/index.d.ts.map +1 -1
- package/dist/cmd/ai/index.js +6 -1
- package/dist/cmd/ai/index.js.map +1 -1
- package/dist/cmd/ai/prompt/agent.d.ts +7 -0
- package/dist/cmd/ai/prompt/agent.d.ts.map +1 -1
- package/dist/cmd/ai/prompt/agent.js +12 -323
- package/dist/cmd/ai/prompt/agent.js.map +1 -1
- package/dist/cmd/ai/prompt/api.d.ts +7 -0
- package/dist/cmd/ai/prompt/api.d.ts.map +1 -1
- package/dist/cmd/ai/prompt/api.js +12 -260
- package/dist/cmd/ai/prompt/api.js.map +1 -1
- package/dist/cmd/ai/prompt/version.d.ts +35 -0
- package/dist/cmd/ai/prompt/version.d.ts.map +1 -0
- package/dist/cmd/ai/prompt/version.js +55 -0
- package/dist/cmd/ai/prompt/version.js.map +1 -0
- package/dist/cmd/ai/prompt/web.d.ts +7 -0
- package/dist/cmd/ai/prompt/web.d.ts.map +1 -1
- package/dist/cmd/ai/prompt/web.js +12 -283
- package/dist/cmd/ai/prompt/web.js.map +1 -1
- package/dist/cmd/ai/skills/generate.d.ts +3 -0
- package/dist/cmd/ai/skills/generate.d.ts.map +1 -0
- package/dist/cmd/ai/skills/generate.js +65 -0
- package/dist/cmd/ai/skills/generate.js.map +1 -0
- package/dist/cmd/ai/skills/generator.d.ts +4 -0
- package/dist/cmd/ai/skills/generator.d.ts.map +1 -0
- package/dist/cmd/ai/skills/generator.js +402 -0
- package/dist/cmd/ai/skills/generator.js.map +1 -0
- package/dist/cmd/ai/skills/index.d.ts +4 -0
- package/dist/cmd/ai/skills/index.d.ts.map +1 -0
- package/dist/cmd/ai/skills/index.js +21 -0
- package/dist/cmd/ai/skills/index.js.map +1 -0
- package/dist/cmd/auth/signup.d.ts.map +1 -1
- package/dist/cmd/auth/signup.js +1 -0
- package/dist/cmd/auth/signup.js.map +1 -1
- package/dist/cmd/build/ast.d.ts +2 -1
- package/dist/cmd/build/ast.d.ts.map +1 -1
- package/dist/cmd/build/ast.js +135 -47
- package/dist/cmd/build/ast.js.map +1 -1
- package/dist/cmd/build/entry-generator.d.ts.map +1 -1
- package/dist/cmd/build/entry-generator.js +255 -188
- package/dist/cmd/build/entry-generator.js.map +1 -1
- package/dist/cmd/build/vite/agent-discovery.d.ts.map +1 -1
- package/dist/cmd/build/vite/agent-discovery.js +103 -45
- package/dist/cmd/build/vite/agent-discovery.js.map +1 -1
- package/dist/cmd/build/vite/bun-dev-server.d.ts +7 -1
- package/dist/cmd/build/vite/bun-dev-server.d.ts.map +1 -1
- package/dist/cmd/build/vite/bun-dev-server.js +52 -26
- package/dist/cmd/build/vite/bun-dev-server.js.map +1 -1
- package/dist/cmd/build/vite/docs-generator.d.ts +13 -0
- package/dist/cmd/build/vite/docs-generator.d.ts.map +1 -0
- package/dist/cmd/build/vite/docs-generator.js +81 -0
- package/dist/cmd/build/vite/docs-generator.js.map +1 -0
- package/dist/cmd/build/vite/index.d.ts +3 -3
- package/dist/cmd/build/vite/index.d.ts.map +1 -1
- package/dist/cmd/build/vite/index.js +9 -7
- package/dist/cmd/build/vite/index.js.map +1 -1
- package/dist/cmd/build/vite/lifecycle-generator.d.ts +1 -1
- package/dist/cmd/build/vite/lifecycle-generator.d.ts.map +1 -1
- package/dist/cmd/build/vite/lifecycle-generator.js +19 -5
- package/dist/cmd/build/vite/lifecycle-generator.js.map +1 -1
- package/dist/cmd/build/vite/metadata-generator.d.ts.map +1 -1
- package/dist/cmd/build/vite/metadata-generator.js +203 -7
- package/dist/cmd/build/vite/metadata-generator.js.map +1 -1
- package/dist/cmd/build/vite/prompt-generator.d.ts +23 -0
- package/dist/cmd/build/vite/prompt-generator.d.ts.map +1 -0
- package/dist/cmd/build/vite/prompt-generator.js +123 -0
- package/dist/cmd/build/vite/prompt-generator.js.map +1 -0
- package/dist/cmd/build/vite/registry-generator.d.ts +3 -3
- package/dist/cmd/build/vite/registry-generator.d.ts.map +1 -1
- package/dist/cmd/build/vite/registry-generator.js +644 -103
- package/dist/cmd/build/vite/registry-generator.js.map +1 -1
- package/dist/cmd/build/vite/route-discovery.d.ts +4 -0
- package/dist/cmd/build/vite/route-discovery.d.ts.map +1 -1
- package/dist/cmd/build/vite/route-discovery.js.map +1 -1
- package/dist/cmd/build/vite/server-bundler.d.ts +4 -0
- package/dist/cmd/build/vite/server-bundler.d.ts.map +1 -1
- package/dist/cmd/build/vite/server-bundler.js +63 -17
- package/dist/cmd/build/vite/server-bundler.js.map +1 -1
- package/dist/cmd/build/vite/vite-asset-server-config.d.ts.map +1 -1
- package/dist/cmd/build/vite/vite-asset-server-config.js +4 -0
- package/dist/cmd/build/vite/vite-asset-server-config.js.map +1 -1
- package/dist/cmd/build/vite/vite-builder.d.ts +1 -1
- package/dist/cmd/build/vite/vite-builder.d.ts.map +1 -1
- package/dist/cmd/build/vite/vite-builder.js +118 -96
- package/dist/cmd/build/vite/vite-builder.js.map +1 -1
- package/dist/cmd/build/vite-bundler.js +6 -6
- package/dist/cmd/build/vite-bundler.js.map +1 -1
- package/dist/cmd/cloud/deploy.d.ts.map +1 -1
- package/dist/cmd/cloud/deploy.js +89 -32
- package/dist/cmd/cloud/deploy.js.map +1 -1
- package/dist/cmd/cloud/keyvalue/create-namespace.d.ts.map +1 -1
- package/dist/cmd/cloud/keyvalue/create-namespace.js +3 -1
- package/dist/cmd/cloud/keyvalue/create-namespace.js.map +1 -1
- package/dist/cmd/cloud/keyvalue/delete-namespace.d.ts.map +1 -1
- package/dist/cmd/cloud/keyvalue/delete-namespace.js +3 -1
- package/dist/cmd/cloud/keyvalue/delete-namespace.js.map +1 -1
- package/dist/cmd/cloud/keyvalue/delete.d.ts.map +1 -1
- package/dist/cmd/cloud/keyvalue/delete.js +3 -1
- package/dist/cmd/cloud/keyvalue/delete.js.map +1 -1
- package/dist/cmd/cloud/keyvalue/set.d.ts.map +1 -1
- package/dist/cmd/cloud/keyvalue/set.js +4 -2
- package/dist/cmd/cloud/keyvalue/set.js.map +1 -1
- package/dist/cmd/cloud/stream/get.d.ts.map +1 -1
- package/dist/cmd/cloud/stream/get.js +2 -13
- package/dist/cmd/cloud/stream/get.js.map +1 -1
- package/dist/cmd/cloud/vector/delete-namespace.d.ts +3 -0
- package/dist/cmd/cloud/vector/delete-namespace.d.ts.map +1 -0
- package/dist/cmd/cloud/vector/delete-namespace.js +77 -0
- package/dist/cmd/cloud/vector/delete-namespace.js.map +1 -0
- package/dist/cmd/cloud/vector/index.d.ts.map +1 -1
- package/dist/cmd/cloud/vector/index.js +21 -4
- package/dist/cmd/cloud/vector/index.js.map +1 -1
- package/dist/cmd/cloud/vector/list-namespaces.d.ts +3 -0
- package/dist/cmd/cloud/vector/list-namespaces.d.ts.map +1 -0
- package/dist/cmd/cloud/vector/list-namespaces.js +42 -0
- package/dist/cmd/cloud/vector/list-namespaces.js.map +1 -0
- package/dist/cmd/cloud/vector/stats.d.ts +3 -0
- package/dist/cmd/cloud/vector/stats.d.ts.map +1 -0
- package/dist/cmd/cloud/vector/stats.js +142 -0
- package/dist/cmd/cloud/vector/stats.js.map +1 -0
- package/dist/cmd/cloud/vector/upsert.d.ts +3 -0
- package/dist/cmd/cloud/vector/upsert.d.ts.map +1 -0
- package/dist/cmd/cloud/vector/upsert.js +192 -0
- package/dist/cmd/cloud/vector/upsert.js.map +1 -0
- package/dist/cmd/dev/file-watcher.d.ts.map +1 -1
- package/dist/cmd/dev/file-watcher.js +94 -33
- 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 +298 -61
- package/dist/cmd/dev/index.js.map +1 -1
- package/dist/cmd/dev/skills.d.ts +10 -0
- package/dist/cmd/dev/skills.d.ts.map +1 -0
- package/dist/cmd/dev/skills.js +57 -0
- package/dist/cmd/dev/skills.js.map +1 -0
- package/dist/cmd/dev/sync.d.ts.map +1 -1
- package/dist/cmd/dev/sync.js +19 -3
- package/dist/cmd/dev/sync.js.map +1 -1
- package/dist/cmd/index.d.ts.map +1 -1
- package/dist/cmd/index.js +1 -0
- package/dist/cmd/index.js.map +1 -1
- package/dist/cmd/project/create.d.ts.map +1 -1
- package/dist/cmd/project/create.js +3 -0
- package/dist/cmd/project/create.js.map +1 -1
- package/dist/cmd/project/template-flow.d.ts +1 -0
- package/dist/cmd/project/template-flow.d.ts.map +1 -1
- package/dist/cmd/project/template-flow.js +30 -5
- package/dist/cmd/project/template-flow.js.map +1 -1
- package/dist/cmd/setup/index.d.ts.map +1 -1
- package/dist/cmd/setup/index.js +1 -0
- package/dist/cmd/setup/index.js.map +1 -1
- package/dist/cmd/upgrade/index.d.ts +15 -0
- package/dist/cmd/upgrade/index.d.ts.map +1 -1
- package/dist/cmd/upgrade/index.js +59 -4
- package/dist/cmd/upgrade/index.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +8 -0
- package/dist/config.js.map +1 -1
- package/dist/domain.d.ts +45 -0
- package/dist/domain.d.ts.map +1 -0
- package/dist/domain.js +200 -0
- package/dist/domain.js.map +1 -0
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -1
- package/dist/index.js.map +1 -1
- package/dist/schema-generator.d.ts +2 -0
- package/dist/schema-generator.d.ts.map +1 -1
- package/dist/schema-generator.js +18 -0
- package/dist/schema-generator.js.map +1 -1
- package/dist/steps.d.ts +1 -1
- package/dist/steps.d.ts.map +1 -1
- package/dist/steps.js +16 -5
- package/dist/steps.js.map +1 -1
- package/dist/tui/prompt.d.ts +1 -2
- package/dist/tui/prompt.d.ts.map +1 -1
- package/dist/tui/prompt.js +8 -4
- package/dist/tui/prompt.js.map +1 -1
- package/dist/tui.d.ts +16 -0
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +23 -2
- package/dist/tui.js.map +1 -1
- package/dist/types.d.ts +9 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +3 -3
- package/dist/types.js.map +1 -1
- package/package.json +5 -8
- package/src/api.ts +1 -1
- package/src/cli.ts +47 -12
- package/src/cmd/ai/index.ts +6 -1
- package/src/cmd/ai/prompt/agent.md +306 -0
- package/src/cmd/ai/prompt/agent.ts +12 -322
- package/src/cmd/ai/prompt/api.md +360 -0
- package/src/cmd/ai/prompt/api.ts +13 -260
- package/src/cmd/ai/prompt/version.ts +61 -0
- package/src/cmd/ai/prompt/web.md +509 -0
- package/src/cmd/ai/prompt/web.ts +12 -282
- package/src/cmd/ai/skills/generate.ts +75 -0
- package/src/cmd/ai/skills/generator.ts +519 -0
- package/src/cmd/ai/skills/index.ts +23 -0
- package/src/cmd/auth/signup.ts +1 -0
- package/src/cmd/build/ast.ts +161 -48
- package/src/cmd/build/entry-generator.ts +258 -187
- package/src/cmd/build/vite/agent-discovery.ts +151 -58
- package/src/cmd/build/vite/bun-dev-server.ts +57 -27
- package/src/cmd/build/vite/docs-generator.ts +87 -0
- package/src/cmd/build/vite/index.ts +9 -7
- package/src/cmd/build/vite/lifecycle-generator.ts +19 -5
- package/src/cmd/build/vite/metadata-generator.ts +251 -7
- package/src/cmd/build/vite/prompt-generator.ts +169 -0
- package/src/cmd/build/vite/registry-generator.ts +750 -108
- package/src/cmd/build/vite/route-discovery.ts +4 -0
- package/src/cmd/build/vite/server-bundler.ts +73 -23
- package/src/cmd/build/vite/vite-asset-server-config.ts +5 -0
- package/src/cmd/build/vite/vite-builder.ts +134 -100
- package/src/cmd/build/vite-bundler.ts +6 -6
- package/src/cmd/cloud/deploy.ts +114 -36
- package/src/cmd/cloud/keyvalue/create-namespace.ts +3 -1
- package/src/cmd/cloud/keyvalue/delete-namespace.ts +3 -1
- package/src/cmd/cloud/keyvalue/delete.ts +3 -1
- package/src/cmd/cloud/keyvalue/set.ts +4 -2
- package/src/cmd/cloud/stream/get.ts +2 -9
- package/src/cmd/cloud/vector/delete-namespace.ts +89 -0
- package/src/cmd/cloud/vector/index.ts +21 -4
- package/src/cmd/cloud/vector/list-namespaces.ts +46 -0
- package/src/cmd/cloud/vector/stats.ts +160 -0
- package/src/cmd/cloud/vector/upsert.ts +216 -0
- package/src/cmd/dev/file-watcher.ts +109 -34
- package/src/cmd/dev/index.ts +364 -60
- package/src/cmd/dev/skills.ts +82 -0
- package/src/cmd/dev/sync.ts +41 -6
- package/src/cmd/index.ts +1 -0
- package/src/cmd/project/create.ts +3 -0
- package/src/cmd/project/template-flow.ts +37 -5
- package/src/cmd/setup/index.ts +1 -0
- package/src/cmd/upgrade/index.ts +68 -4
- package/src/config.ts +9 -0
- package/src/domain.ts +273 -0
- package/src/index.ts +0 -5
- package/src/runtime-bootstrap.md +1 -1
- package/src/schema-generator.ts +23 -0
- package/src/steps.ts +16 -5
- package/src/tui/prompt.ts +11 -5
- package/src/tui.ts +21 -2
- package/src/types/md.d.ts +8 -0
- package/src/types.ts +12 -3
- package/dist/cmd/cloud/domain.d.ts +0 -17
- package/dist/cmd/cloud/domain.d.ts.map +0 -1
- package/dist/cmd/cloud/domain.js +0 -79
- package/dist/cmd/cloud/domain.js.map +0 -1
- package/dist/runtime-bootstrap.d.ts +0 -56
- package/dist/runtime-bootstrap.d.ts.map +0 -1
- package/dist/runtime-bootstrap.js +0 -95
- package/dist/runtime-bootstrap.js.map +0 -1
- package/src/cmd/cloud/domain.ts +0 -100
- package/src/runtime-bootstrap.ts +0 -131
|
@@ -1,20 +1,33 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Registry Generator
|
|
3
3
|
*
|
|
4
|
-
* Generates
|
|
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
|
-
*
|
|
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
|
|
16
|
-
const
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
51
|
-
const
|
|
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
|
-
|
|
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
|
|
58
|
-
const
|
|
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
|
-
|
|
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
|
-
|
|
127
|
+
const pascalName = toPascalCase(name);
|
|
128
|
+
return ` ${camelName}: ${pascalName}Agent;`;
|
|
70
129
|
})
|
|
71
130
|
.join('\n');
|
|
72
|
-
const generatedContent =
|
|
73
|
-
// Auto-generated by Agentuity -
|
|
131
|
+
const generatedContent = `// @generated
|
|
132
|
+
// Auto-generated by Agentuity - DO NOT EDIT
|
|
74
133
|
${imports}
|
|
75
|
-
import type { AgentRunner
|
|
76
|
-
import type {
|
|
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
|
-
*
|
|
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
|
|
168
|
+
export const AgentDefinitions = {
|
|
84
169
|
${registry}
|
|
85
170
|
} as const;
|
|
86
171
|
|
|
87
|
-
//
|
|
88
|
-
|
|
89
|
-
|
|
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
|
-
//
|
|
103
|
-
//
|
|
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
|
|
108
|
-
if (!existsSync(
|
|
109
|
-
mkdirSync(
|
|
190
|
+
// Ensure src/generated directory exists
|
|
191
|
+
if (!existsSync(generatedDir)) {
|
|
192
|
+
mkdirSync(generatedDir, { recursive: true });
|
|
110
193
|
}
|
|
111
|
-
|
|
112
|
-
|
|
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
|
-
|
|
136
|
-
// Collect agent imports
|
|
405
|
+
// Collect agent and schema imports from routes with validators or exported schemas
|
|
137
406
|
allRoutes.forEach((route) => {
|
|
138
|
-
|
|
407
|
+
const hasSchemaVars = !!route.inputSchemaVariable || !!route.outputSchemaVariable;
|
|
408
|
+
if (!route.hasValidator && !hasSchemaVars && !route.agentVariable)
|
|
139
409
|
return;
|
|
140
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
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
|
|
174
|
-
|
|
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
|
-
//
|
|
178
|
-
const
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
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
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
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
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
const
|
|
201
|
-
?
|
|
202
|
-
:
|
|
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
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
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
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
243
|
-
const
|
|
244
|
-
|
|
245
|
-
|
|
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
|
-
|
|
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
|