@agentuity/cli 1.0.59 → 2.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (189) hide show
  1. package/bin/cli.ts +2 -3
  2. package/dist/cmd/build/app-config-extractor.d.ts +27 -0
  3. package/dist/cmd/build/app-config-extractor.d.ts.map +1 -0
  4. package/dist/cmd/build/app-config-extractor.js +152 -0
  5. package/dist/cmd/build/app-config-extractor.js.map +1 -0
  6. package/dist/cmd/build/app-router-detector.d.ts +2 -5
  7. package/dist/cmd/build/app-router-detector.d.ts.map +1 -1
  8. package/dist/cmd/build/app-router-detector.js +130 -154
  9. package/dist/cmd/build/app-router-detector.js.map +1 -1
  10. package/dist/cmd/build/ci.d.ts.map +1 -1
  11. package/dist/cmd/build/ci.js +5 -21
  12. package/dist/cmd/build/ci.js.map +1 -1
  13. package/dist/cmd/build/ids.d.ts +11 -0
  14. package/dist/cmd/build/ids.d.ts.map +1 -0
  15. package/dist/cmd/build/ids.js +18 -0
  16. package/dist/cmd/build/ids.js.map +1 -0
  17. package/dist/cmd/build/index.d.ts.map +1 -1
  18. package/dist/cmd/build/index.js +8 -0
  19. package/dist/cmd/build/index.js.map +1 -1
  20. package/dist/cmd/build/vite/agent-discovery.d.ts +8 -4
  21. package/dist/cmd/build/vite/agent-discovery.d.ts.map +1 -1
  22. package/dist/cmd/build/vite/agent-discovery.js +166 -487
  23. package/dist/cmd/build/vite/agent-discovery.js.map +1 -1
  24. package/dist/cmd/build/vite/bun-dev-server.d.ts +43 -14
  25. package/dist/cmd/build/vite/bun-dev-server.d.ts.map +1 -1
  26. package/dist/cmd/build/vite/bun-dev-server.js +290 -129
  27. package/dist/cmd/build/vite/bun-dev-server.js.map +1 -1
  28. package/dist/cmd/build/vite/config-loader.d.ts +15 -20
  29. package/dist/cmd/build/vite/config-loader.d.ts.map +1 -1
  30. package/dist/cmd/build/vite/config-loader.js +41 -74
  31. package/dist/cmd/build/vite/config-loader.js.map +1 -1
  32. package/dist/cmd/build/vite/docs-generator.d.ts.map +1 -1
  33. package/dist/cmd/build/vite/docs-generator.js +0 -2
  34. package/dist/cmd/build/vite/docs-generator.js.map +1 -1
  35. package/dist/cmd/build/vite/index.d.ts.map +1 -1
  36. package/dist/cmd/build/vite/index.js +0 -36
  37. package/dist/cmd/build/vite/index.js.map +1 -1
  38. package/dist/cmd/build/vite/lifecycle-generator.d.ts +10 -2
  39. package/dist/cmd/build/vite/lifecycle-generator.d.ts.map +1 -1
  40. package/dist/cmd/build/vite/lifecycle-generator.js +302 -23
  41. package/dist/cmd/build/vite/lifecycle-generator.js.map +1 -1
  42. package/dist/cmd/build/vite/route-discovery.d.ts +11 -38
  43. package/dist/cmd/build/vite/route-discovery.d.ts.map +1 -1
  44. package/dist/cmd/build/vite/route-discovery.js +97 -177
  45. package/dist/cmd/build/vite/route-discovery.js.map +1 -1
  46. package/dist/cmd/build/vite/server-bundler.js +1 -1
  47. package/dist/cmd/build/vite/server-bundler.js.map +1 -1
  48. package/dist/cmd/build/vite/static-renderer.d.ts +0 -2
  49. package/dist/cmd/build/vite/static-renderer.d.ts.map +1 -1
  50. package/dist/cmd/build/vite/static-renderer.js +19 -13
  51. package/dist/cmd/build/vite/static-renderer.js.map +1 -1
  52. package/dist/cmd/build/vite/vite-asset-server-config.d.ts +6 -3
  53. package/dist/cmd/build/vite/vite-asset-server-config.d.ts.map +1 -1
  54. package/dist/cmd/build/vite/vite-asset-server-config.js +175 -69
  55. package/dist/cmd/build/vite/vite-asset-server-config.js.map +1 -1
  56. package/dist/cmd/build/vite/vite-asset-server.d.ts +8 -3
  57. package/dist/cmd/build/vite/vite-asset-server.d.ts.map +1 -1
  58. package/dist/cmd/build/vite/vite-asset-server.js +14 -13
  59. package/dist/cmd/build/vite/vite-asset-server.js.map +1 -1
  60. package/dist/cmd/build/vite/vite-builder.d.ts.map +1 -1
  61. package/dist/cmd/build/vite/vite-builder.js +42 -190
  62. package/dist/cmd/build/vite/vite-builder.js.map +1 -1
  63. package/dist/cmd/build/vite/ws-proxy.d.ts +53 -0
  64. package/dist/cmd/build/vite/ws-proxy.d.ts.map +1 -0
  65. package/dist/cmd/build/vite/ws-proxy.js +95 -0
  66. package/dist/cmd/build/vite/ws-proxy.js.map +1 -0
  67. package/dist/cmd/build/vite-bundler.d.ts.map +1 -1
  68. package/dist/cmd/build/vite-bundler.js +0 -3
  69. package/dist/cmd/build/vite-bundler.js.map +1 -1
  70. package/dist/cmd/cloud/deploy-fork.d.ts.map +1 -1
  71. package/dist/cmd/cloud/deploy-fork.js +15 -36
  72. package/dist/cmd/cloud/deploy-fork.js.map +1 -1
  73. package/dist/cmd/cloud/sandbox/exec.d.ts.map +1 -1
  74. package/dist/cmd/cloud/sandbox/exec.js +28 -86
  75. package/dist/cmd/cloud/sandbox/exec.js.map +1 -1
  76. package/dist/cmd/cloud/sandbox/run.d.ts.map +1 -1
  77. package/dist/cmd/cloud/sandbox/run.js +2 -9
  78. package/dist/cmd/cloud/sandbox/run.js.map +1 -1
  79. package/dist/cmd/cloud/sandbox/snapshot/build.js +2 -2
  80. package/dist/cmd/cloud/sandbox/snapshot/build.js.map +1 -1
  81. package/dist/cmd/coder/hub-url.d.ts.map +1 -1
  82. package/dist/cmd/coder/hub-url.js +1 -3
  83. package/dist/cmd/coder/hub-url.js.map +1 -1
  84. package/dist/cmd/coder/start.js +6 -6
  85. package/dist/cmd/coder/start.js.map +1 -1
  86. package/dist/cmd/coder/tui-init.d.ts +2 -2
  87. package/dist/cmd/coder/tui-init.js +2 -2
  88. package/dist/cmd/coder/tui-init.js.map +1 -1
  89. package/dist/cmd/dev/file-watcher.d.ts.map +1 -1
  90. package/dist/cmd/dev/file-watcher.js +2 -8
  91. package/dist/cmd/dev/file-watcher.js.map +1 -1
  92. package/dist/cmd/dev/index.d.ts.map +1 -1
  93. package/dist/cmd/dev/index.js +432 -752
  94. package/dist/cmd/dev/index.js.map +1 -1
  95. package/dist/cmd/dev/process-manager.d.ts +104 -0
  96. package/dist/cmd/dev/process-manager.d.ts.map +1 -0
  97. package/dist/cmd/dev/process-manager.js +204 -0
  98. package/dist/cmd/dev/process-manager.js.map +1 -0
  99. package/dist/errors.d.ts +10 -24
  100. package/dist/errors.d.ts.map +1 -1
  101. package/dist/errors.js +12 -42
  102. package/dist/errors.js.map +1 -1
  103. package/dist/schema-generator.d.ts.map +1 -1
  104. package/dist/schema-generator.js +12 -2
  105. package/dist/schema-generator.js.map +1 -1
  106. package/dist/tui.d.ts.map +1 -1
  107. package/dist/tui.js +5 -19
  108. package/dist/tui.js.map +1 -1
  109. package/dist/utils/version-mismatch.d.ts +39 -0
  110. package/dist/utils/version-mismatch.d.ts.map +1 -0
  111. package/dist/utils/version-mismatch.js +161 -0
  112. package/dist/utils/version-mismatch.js.map +1 -0
  113. package/package.json +6 -6
  114. package/src/cmd/ai/prompt/agent.md +0 -1
  115. package/src/cmd/ai/prompt/api.md +0 -7
  116. package/src/cmd/ai/prompt/web.md +51 -213
  117. package/src/cmd/build/app-config-extractor.ts +186 -0
  118. package/src/cmd/build/app-router-detector.ts +152 -182
  119. package/src/cmd/build/ci.ts +5 -21
  120. package/src/cmd/build/ids.ts +19 -0
  121. package/src/cmd/build/index.ts +10 -0
  122. package/src/cmd/build/vite/agent-discovery.ts +208 -679
  123. package/src/cmd/build/vite/bun-dev-server.ts +383 -146
  124. package/src/cmd/build/vite/config-loader.ts +45 -77
  125. package/src/cmd/build/vite/docs-generator.ts +0 -2
  126. package/src/cmd/build/vite/index.ts +1 -42
  127. package/src/cmd/build/vite/lifecycle-generator.ts +345 -21
  128. package/src/cmd/build/vite/route-discovery.ts +116 -274
  129. package/src/cmd/build/vite/server-bundler.ts +1 -1
  130. package/src/cmd/build/vite/static-renderer.ts +23 -15
  131. package/src/cmd/build/vite/vite-asset-server-config.ts +200 -70
  132. package/src/cmd/build/vite/vite-asset-server.ts +25 -15
  133. package/src/cmd/build/vite/vite-builder.ts +49 -220
  134. package/src/cmd/build/vite/ws-proxy.ts +126 -0
  135. package/src/cmd/build/vite-bundler.ts +0 -4
  136. package/src/cmd/cloud/deploy-fork.ts +16 -39
  137. package/src/cmd/cloud/sandbox/exec.ts +23 -130
  138. package/src/cmd/cloud/sandbox/run.ts +2 -9
  139. package/src/cmd/cloud/sandbox/snapshot/build.ts +2 -2
  140. package/src/cmd/coder/hub-url.ts +1 -3
  141. package/src/cmd/coder/start.ts +6 -6
  142. package/src/cmd/coder/tui-init.ts +4 -4
  143. package/src/cmd/dev/file-watcher.ts +2 -9
  144. package/src/cmd/dev/index.ts +476 -859
  145. package/src/cmd/dev/process-manager.ts +261 -0
  146. package/src/errors.ts +12 -44
  147. package/src/schema-generator.ts +12 -2
  148. package/src/tui.ts +5 -18
  149. package/src/utils/version-mismatch.ts +204 -0
  150. package/dist/cmd/build/ast.d.ts +0 -78
  151. package/dist/cmd/build/ast.d.ts.map +0 -1
  152. package/dist/cmd/build/ast.js +0 -2703
  153. package/dist/cmd/build/ast.js.map +0 -1
  154. package/dist/cmd/build/entry-generator.d.ts +0 -25
  155. package/dist/cmd/build/entry-generator.d.ts.map +0 -1
  156. package/dist/cmd/build/entry-generator.js +0 -695
  157. package/dist/cmd/build/entry-generator.js.map +0 -1
  158. package/dist/cmd/build/vite/api-mount-path.d.ts +0 -61
  159. package/dist/cmd/build/vite/api-mount-path.d.ts.map +0 -1
  160. package/dist/cmd/build/vite/api-mount-path.js +0 -83
  161. package/dist/cmd/build/vite/api-mount-path.js.map +0 -1
  162. package/dist/cmd/build/vite/registry-generator.d.ts +0 -19
  163. package/dist/cmd/build/vite/registry-generator.d.ts.map +0 -1
  164. package/dist/cmd/build/vite/registry-generator.js +0 -1108
  165. package/dist/cmd/build/vite/registry-generator.js.map +0 -1
  166. package/dist/cmd/build/webanalytics-generator.d.ts +0 -16
  167. package/dist/cmd/build/webanalytics-generator.d.ts.map +0 -1
  168. package/dist/cmd/build/webanalytics-generator.js +0 -178
  169. package/dist/cmd/build/webanalytics-generator.js.map +0 -1
  170. package/dist/cmd/build/workbench.d.ts +0 -7
  171. package/dist/cmd/build/workbench.d.ts.map +0 -1
  172. package/dist/cmd/build/workbench.js +0 -55
  173. package/dist/cmd/build/workbench.js.map +0 -1
  174. package/dist/utils/route-migration.d.ts +0 -62
  175. package/dist/utils/route-migration.d.ts.map +0 -1
  176. package/dist/utils/route-migration.js +0 -630
  177. package/dist/utils/route-migration.js.map +0 -1
  178. package/dist/utils/stream-capture.d.ts +0 -9
  179. package/dist/utils/stream-capture.d.ts.map +0 -1
  180. package/dist/utils/stream-capture.js +0 -34
  181. package/dist/utils/stream-capture.js.map +0 -1
  182. package/src/cmd/build/ast.ts +0 -3529
  183. package/src/cmd/build/entry-generator.ts +0 -760
  184. package/src/cmd/build/vite/api-mount-path.ts +0 -87
  185. package/src/cmd/build/vite/registry-generator.ts +0 -1267
  186. package/src/cmd/build/webanalytics-generator.ts +0 -197
  187. package/src/cmd/build/workbench.ts +0 -58
  188. package/src/utils/route-migration.ts +0 -757
  189. package/src/utils/stream-capture.ts +0 -39
@@ -1,108 +1,76 @@
1
1
  /**
2
- * Config loader for agentuity.config.ts
2
+ * Config loader for v2
3
+ *
4
+ * In v2, all runtime config (analytics, workbench) goes in createApp().
5
+ * Vite-specific config (plugins, define, render, bundle) goes in vite.config.ts.
6
+ *
7
+ * Runtime config values are extracted from app.ts via app-config-extractor.
3
8
  */
4
9
 
5
- import { join } from 'node:path';
6
10
  import type { Logger } from '../../../types';
7
- import type { AgentuityConfig } from '../../../types';
11
+ import { extractAppConfig, type ExtractedAppConfig } from '../app-config-extractor';
8
12
 
9
13
  /**
10
- * Load agentuity.config.ts from the project root
11
- * Returns null if the file doesn't exist or fails to load
14
+ * Load runtime config from createApp() in app.ts (v2 approach).
15
+ *
16
+ * This is the only way to get analytics/workbench config in v2.
17
+ * The CLI reads these values directly from the user's createApp() call.
12
18
  */
13
- export async function loadAgentuityConfig(
19
+ export async function loadRuntimeConfig(
14
20
  rootDir: string,
15
21
  logger: Logger
16
- ): Promise<AgentuityConfig | null> {
17
- const configPath = join(rootDir, 'agentuity.config.ts');
18
-
19
- if (!(await Bun.file(configPath).exists())) {
20
- logger.trace('No agentuity.config.ts found');
21
- return null;
22
- }
23
-
24
- try {
25
- const config = await import(configPath);
26
- const userConfig = config.default as AgentuityConfig | undefined;
27
-
28
- if (!userConfig) {
29
- logger.warn('agentuity.config.ts does not export a default configuration');
30
- return null;
31
- }
32
-
33
- logger.trace('Loaded agentuity.config.ts');
34
- return userConfig;
35
- } catch (error) {
36
- logger.warn('Failed to load agentuity.config.ts:', error);
37
- return null;
38
- }
22
+ ): Promise<ExtractedAppConfig> {
23
+ return extractAppConfig(rootDir, logger);
39
24
  }
40
25
 
41
26
  /**
42
- * Get workbench configuration with defaults
43
- * NOTE: Workbench is only enabled at runtime in dev mode, but we need to know
44
- * if it's configured at build time so we can generate the correct code.
27
+ * Get workbench configuration with defaults.
45
28
  *
46
- * Presence of workbench config implicitly enables it (no explicit 'enabled' flag needed)
47
- * Missing workbench config implicitly disables it
29
+ * In v2, workbench config is extracted from createApp() in app.ts.
48
30
  */
49
31
  export function getWorkbenchConfig(
50
- config: AgentuityConfig | null,
51
- dev: boolean
32
+ dev: boolean,
33
+ runtimeConfig?: ExtractedAppConfig
52
34
  ): {
53
35
  configured: boolean;
54
36
  enabled: boolean;
55
37
  route: string;
56
38
  headers: Record<string, string>;
57
39
  } {
58
- const configured = config?.workbench !== undefined;
40
+ const workbenchFromRuntime = runtimeConfig?.workbench;
59
41
 
60
42
  // Workbench is enabled if:
61
43
  // 1. In dev mode (never in production)
62
- // 2. Config has a workbench object (presence implies enablement)
63
- const enabled = dev && configured;
44
+ // 2. Workbench is configured in createApp()
45
+ const hasWorkbench = workbenchFromRuntime !== undefined;
46
+ const configured = hasWorkbench;
47
+ const enabled = dev && hasWorkbench;
64
48
 
65
- const workbench = config?.workbench || {};
49
+ // Extract values from createApp()
50
+ let route = '/workbench';
51
+ let headers: Record<string, string> = {};
52
+
53
+ if (workbenchFromRuntime !== undefined) {
54
+ if (typeof workbenchFromRuntime === 'string') {
55
+ route = workbenchFromRuntime;
56
+ } else if (typeof workbenchFromRuntime === 'object' && workbenchFromRuntime !== null) {
57
+ if ('route' in workbenchFromRuntime && typeof workbenchFromRuntime.route === 'string') {
58
+ route = workbenchFromRuntime.route;
59
+ }
60
+ if (
61
+ 'headers' in workbenchFromRuntime &&
62
+ typeof workbenchFromRuntime.headers === 'object'
63
+ ) {
64
+ headers = workbenchFromRuntime.headers as Record<string, string>;
65
+ }
66
+ }
67
+ // boolean true uses defaults
68
+ }
66
69
 
67
70
  return {
68
71
  configured,
69
72
  enabled,
70
- route: workbench.route ?? '/workbench',
71
- headers: workbench.headers ?? {},
73
+ route,
74
+ headers,
72
75
  };
73
76
  }
74
-
75
- /**
76
- * Known Vite framework plugin name prefixes.
77
- * Each framework's Vite plugin registers one or more plugins whose names
78
- * start with these prefixes. We match against these to detect whether the
79
- * user has already configured a framework plugin in their agentuity.config.ts.
80
- */
81
- const FRAMEWORK_PLUGIN_PREFIXES = [
82
- 'vite:react', // @vitejs/plugin-react (vite:react-babel, vite:react-refresh, …)
83
- 'vite:preact', // @preact/preset-vite
84
- 'vite-plugin-svelte', // @sveltejs/vite-plugin-svelte
85
- 'vite:vue', // @vitejs/plugin-vue (vite:vue, vite:vue-jsx)
86
- 'vite-plugin-solid', // vite-plugin-solid
87
- 'solid', // vite-plugin-solid also uses plain "solid"
88
- ];
89
-
90
- /**
91
- * Check if the user's plugins include any known UI-framework Vite plugin
92
- * (React, Svelte, Vue, Solid, Preact, …).
93
- *
94
- * Detection is name-based: Vite plugins expose a `name` property and every
95
- * major framework plugin uses a predictable prefix. This avoids dynamically
96
- * importing every possible framework just to compare names.
97
- */
98
- export function hasFrameworkPlugin(userPlugins: import('vite').PluginOption[]): boolean {
99
- const flat = (userPlugins as unknown[]).flat(Infinity).filter(Boolean);
100
- return flat.some(
101
- (p: unknown) =>
102
- p &&
103
- typeof p === 'object' &&
104
- 'name' in p &&
105
- typeof (p as { name: unknown }).name === 'string' &&
106
- FRAMEWORK_PLUGIN_PREFIXES.some((prefix) => (p as { name: string }).name.startsWith(prefix))
107
- );
108
- }
@@ -18,7 +18,6 @@ This directory contains auto-generated TypeScript files created by the Agentuity
18
18
  ## Generated Files
19
19
 
20
20
  - \`registry.ts\` - Agent registry from \`src/agent/**\`
21
- - \`routes.ts\` - Route registry from \`src/api/**\`
22
21
  - \`app.ts\` - Application entry point
23
22
  - \`analytics-config.ts\` - Web analytics configuration from \`agentuity.json\`
24
23
  - \`webanalytics.ts\` - Web analytics injection and route registration
@@ -63,7 +62,6 @@ const AGENTS_MD_CONTENT = `# AI Agent Instructions
63
62
  ## What Gets Generated
64
63
 
65
64
  - \`registry.ts\` - Built from agent discovery in \`src/agent/\`
66
- - \`routes.ts\` - Built from route discovery in \`src/api/\`
67
65
  - \`app.ts\` - Entry point assembled from project configuration
68
66
  - \`analytics-config.ts\` - Web analytics configuration from \`agentuity.json\`
69
67
  - \`webanalytics.ts\` - Web analytics injection and route registration
@@ -3,13 +3,10 @@ import { join } from 'node:path';
3
3
  import { createLogger } from '@agentuity/server';
4
4
  import type { LogLevel, DeployOptions } from '../../../types';
5
5
  import { discoverAgents, type AgentMetadata } from './agent-discovery';
6
- import { discoverRoutes, type RouteMetadata, type RouteInfo } from './route-discovery';
7
- import { generateAgentRegistry, generateRouteRegistry } from './registry-generator';
6
+ import { discoverRoutes, type RouteMetadata } from './route-discovery';
8
7
  import { generateLifecycleTypes } from './lifecycle-generator';
9
8
  import { generateEnvTypes } from './env-types-generator';
10
9
  import { generateMetadata, writeMetadataFile, generateRouteMapping } from './metadata-generator';
11
- import { generateEntryFile } from '../entry-generator';
12
- import { loadAgentuityConfig, getWorkbenchConfig } from './config-loader';
13
10
 
14
11
  // Re-export plugins
15
12
  export { browserEnvPlugin } from './browser-env-plugin';
@@ -59,7 +56,6 @@ export function agentuityPlugin(options: AgentuityPluginOptions): Plugin {
59
56
  // Store discovered metadata
60
57
  let agents: AgentMetadata[] = [];
61
58
  let routes: RouteMetadata[] = [];
62
- let routeInfoList: RouteInfo[] = [];
63
59
 
64
60
  logger.trace('Initializing Agentuity Vite plugin', { dev, rootDir, projectId, deploymentId });
65
61
 
@@ -73,31 +69,12 @@ export function agentuityPlugin(options: AgentuityPluginOptions): Plugin {
73
69
  async buildStart() {
74
70
  logger.trace('buildStart: Discovering agents and routes');
75
71
 
76
- // Load agentuity.config.ts for entry file generation
77
- const config = await loadAgentuityConfig(rootDir, logger);
78
- const workbenchConfig = getWorkbenchConfig(config, dev);
79
-
80
- // Note: Workbench files are generated in runAllBuilds() BEFORE builds start (dev mode only)
81
- // We just need the config here for entry file generation
82
-
83
72
  // Discover agents (read-only)
84
73
  agents = await discoverAgents(srcDir, projectId, deploymentId, logger);
85
74
 
86
75
  // Discover routes (read-only)
87
76
  const routeDiscovery = await discoverRoutes(srcDir, projectId, deploymentId, logger);
88
77
  routes = routeDiscovery.routes;
89
- routeInfoList = routeDiscovery.routeInfoList;
90
-
91
- // Generate registries
92
- if (agents.length > 0) {
93
- generateAgentRegistry(srcDir, agents);
94
- logger.trace('Generated agent registry with %d agent(s)', agents.length);
95
- }
96
-
97
- if (routeInfoList.length > 0) {
98
- await generateRouteRegistry(srcDir, routeInfoList, agents);
99
- logger.trace('Generated route registry with %d route(s)', routeInfoList.length);
100
- }
101
78
 
102
79
  // Generate lifecycle types
103
80
  logger.debug('[vite-plugin] About to call generateLifecycleTypes');
@@ -115,17 +92,6 @@ export function agentuityPlugin(options: AgentuityPluginOptions): Plugin {
115
92
  });
116
93
  logger.debug(`[vite-plugin] generateEnvTypes returned: ${envTypesResult}`);
117
94
 
118
- // Generate entry file (pass workbench and analytics config)
119
- await generateEntryFile({
120
- rootDir,
121
- projectId,
122
- deploymentId,
123
- logger,
124
- mode: dev ? 'dev' : 'prod',
125
- workbench: workbenchConfig.configured ? workbenchConfig : undefined,
126
- analytics: config?.analytics,
127
- });
128
-
129
95
  logger.trace('buildStart: Discovery complete');
130
96
  },
131
97
 
@@ -137,9 +103,6 @@ export function agentuityPlugin(options: AgentuityPluginOptions): Plugin {
137
103
  if (id === 'virtual:agentuity/agents') {
138
104
  return '\0virtual:agentuity/agents';
139
105
  }
140
- if (id === 'virtual:agentuity/routes') {
141
- return '\0virtual:agentuity/routes';
142
- }
143
106
  return null;
144
107
  },
145
108
 
@@ -152,10 +115,6 @@ export function agentuityPlugin(options: AgentuityPluginOptions): Plugin {
152
115
  // Re-export from generated registry
153
116
  return `export { agentRegistry } from '../src/generated/registry.js';`;
154
117
  }
155
- if (id === '\0virtual:agentuity/routes') {
156
- // Re-export from generated route registry
157
- return `export { routeRegistry } from '../src/generated/routes.js';`;
158
- }
159
118
  return null;
160
119
  },
161
120
 
@@ -1,15 +1,331 @@
1
1
  /**
2
2
  * Lifecycle Types Generator
3
3
  *
4
- * Generates src/generated/lifecycle.d.ts by analyzing app.ts for setup() function
4
+ * Generates src/generated/state.ts and src/generated/router.ts by analyzing
5
+ * app.ts for a setup() function.
6
+ *
7
+ * Uses TypeScript's type checker to extract the real return type of setup —
8
+ * no AST literal guessing needed.
5
9
  */
6
10
 
7
- import { join } from 'node:path';
8
- import { generateLifecycleTypes as generateLifecycleTypesFromAST } from '../ast';
11
+ import ts from 'typescript';
12
+ import { join, relative, dirname } from 'node:path';
13
+ import { mkdirSync } from 'node:fs';
14
+ import { StructuredError } from '@agentuity/core';
9
15
  import type { Logger } from '../../../types';
16
+ import { toForwardSlash } from '../../../utils/normalize-path';
17
+
18
+ const RuntimePackageNotFound = StructuredError('RuntimePackageNotFound');
19
+
20
+ /**
21
+ * Use the TypeScript type checker to extract the return type of the setup
22
+ * function passed to createApp(). Works with inline setup, exported setup,
23
+ * variable references, async functions — anything TS can resolve.
24
+ */
25
+ function extractSetupReturnType(appFilePath: string, logger: Logger): string | null {
26
+ const compilerOptions: ts.CompilerOptions = {
27
+ target: ts.ScriptTarget.ESNext,
28
+ module: ts.ModuleKind.ESNext,
29
+ moduleResolution: ts.ModuleResolutionKind.Bundler,
30
+ strict: true,
31
+ skipLibCheck: true,
32
+ noEmit: true,
33
+ allowJs: true,
34
+ esModuleInterop: true,
35
+ };
36
+
37
+ const program = ts.createProgram([appFilePath], compilerOptions);
38
+ const checker = program.getTypeChecker();
39
+ const sourceFile = program.getSourceFile(appFilePath);
40
+
41
+ if (!sourceFile) {
42
+ logger.debug('[lifecycle] Could not load source file');
43
+ return null;
44
+ }
45
+
46
+ let setupType: ts.Type | null = null;
47
+
48
+ function unwrapPromise(type: ts.Type): ts.Type {
49
+ // Check for Promise by looking at typeArguments on TypeReference
50
+ const typeRef = type as ts.TypeReference;
51
+ if (typeRef.typeArguments && typeRef.typeArguments.length > 0) {
52
+ const symbol = type.getSymbol() ?? type.aliasSymbol;
53
+ if (symbol?.name === 'Promise') {
54
+ return typeRef.typeArguments[0]!;
55
+ }
56
+ }
57
+ return type;
58
+ }
59
+
60
+ function extractFromProperty(prop: ts.ObjectLiteralElementLike): void {
61
+ if (setupType) return;
62
+
63
+ // Handle: setup: () => { ... } or setup: myFunc
64
+ if (
65
+ ts.isPropertyAssignment(prop) &&
66
+ ts.isIdentifier(prop.name) &&
67
+ prop.name.text === 'setup'
68
+ ) {
69
+ const type = checker.getTypeAtLocation(prop.initializer);
70
+ const callSigs = type.getCallSignatures();
71
+ if (callSigs.length > 0) {
72
+ setupType = unwrapPromise(checker.getReturnTypeOfSignature(callSigs[0]!));
73
+ }
74
+ return;
75
+ }
76
+
77
+ // Handle shorthand: createApp({ setup })
78
+ if (ts.isShorthandPropertyAssignment(prop) && prop.name.text === 'setup') {
79
+ const type = checker.getTypeAtLocation(prop.name);
80
+ const callSigs = type.getCallSignatures();
81
+ if (callSigs.length > 0) {
82
+ setupType = unwrapPromise(checker.getReturnTypeOfSignature(callSigs[0]!));
83
+ }
84
+ }
85
+ }
86
+
87
+ function visit(node: ts.Node): void {
88
+ if (setupType) return;
89
+
90
+ // Find createApp(...) call — with or without await
91
+ let callExpr: ts.CallExpression | undefined;
92
+
93
+ if (ts.isCallExpression(node) && ts.isIdentifier(node.expression)) {
94
+ if (node.expression.text === 'createApp') callExpr = node;
95
+ } else if (ts.isAwaitExpression(node) && ts.isCallExpression(node.expression)) {
96
+ const call = node.expression;
97
+ if (ts.isIdentifier(call.expression) && call.expression.text === 'createApp') {
98
+ callExpr = call;
99
+ }
100
+ }
101
+
102
+ if (callExpr && callExpr.arguments.length > 0) {
103
+ const configArg = callExpr.arguments[0];
104
+ if (configArg && ts.isObjectLiteralExpression(configArg)) {
105
+ for (const prop of configArg.properties) {
106
+ extractFromProperty(prop);
107
+ if (setupType) return;
108
+ }
109
+ }
110
+ }
111
+
112
+ ts.forEachChild(node, visit);
113
+ }
114
+
115
+ visit(sourceFile);
116
+
117
+ // Fallback: look for an exported function named `setup` in the file
118
+ // (user may define `export function setup()` without passing it to createApp)
119
+ if (!setupType) {
120
+ for (const stmt of sourceFile.statements) {
121
+ if (
122
+ ts.isFunctionDeclaration(stmt) &&
123
+ stmt.name?.text === 'setup' &&
124
+ stmt.modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword)
125
+ ) {
126
+ const type = checker.getTypeAtLocation(stmt);
127
+ const callSigs = type.getCallSignatures();
128
+ if (callSigs.length > 0) {
129
+ setupType = unwrapPromise(checker.getReturnTypeOfSignature(callSigs[0]!));
130
+ }
131
+ break;
132
+ }
133
+
134
+ // Handle: export const setup = () => { ... }
135
+ if (
136
+ ts.isVariableStatement(stmt) &&
137
+ stmt.modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword)
138
+ ) {
139
+ for (const decl of stmt.declarationList.declarations) {
140
+ if (ts.isIdentifier(decl.name) && decl.name.text === 'setup' && decl.initializer) {
141
+ const type = checker.getTypeAtLocation(decl.initializer);
142
+ const callSigs = type.getCallSignatures();
143
+ if (callSigs.length > 0) {
144
+ setupType = unwrapPromise(checker.getReturnTypeOfSignature(callSigs[0]!));
145
+ }
146
+ break;
147
+ }
148
+ }
149
+ if (setupType) break;
150
+ }
151
+ }
152
+ }
153
+
154
+ if (!setupType) {
155
+ return null;
156
+ }
157
+
158
+ // Print the type as a string — TS gives us the real resolved type
159
+ const typeString = checker.typeToString(
160
+ setupType,
161
+ undefined,
162
+ ts.TypeFormatFlags.NoTruncation | ts.TypeFormatFlags.MultilineObjectLiterals
163
+ );
164
+
165
+ return typeString;
166
+ }
167
+
168
+ /**
169
+ * Find the @agentuity/runtime package by walking up the directory tree.
170
+ */
171
+ async function findRuntimePackage(rootDir: string, logger: Logger): Promise<string> {
172
+ let currentDir = rootDir;
173
+ const searchedPaths: string[] = [];
174
+
175
+ while (currentDir && currentDir !== '/' && currentDir !== '.') {
176
+ const candidatePath = join(currentDir, 'node_modules', '@agentuity', 'runtime');
177
+ searchedPaths.push(candidatePath);
178
+ if (await Bun.file(join(candidatePath, 'package.json')).exists()) {
179
+ logger.debug(`Found runtime package at: ${candidatePath}`);
180
+ return candidatePath;
181
+ }
182
+
183
+ const packagesPath = join(currentDir, 'packages', 'runtime');
184
+ searchedPaths.push(packagesPath);
185
+ if (await Bun.file(join(packagesPath, 'package.json')).exists()) {
186
+ logger.debug(`Found runtime package (source) at: ${packagesPath}`);
187
+ return packagesPath;
188
+ }
189
+
190
+ const parent = dirname(currentDir);
191
+ if (parent === currentDir) break;
192
+ currentDir = parent;
193
+ }
194
+
195
+ throw new RuntimePackageNotFound({
196
+ message:
197
+ `@agentuity/runtime package not found.\n` +
198
+ `Searched paths:\n${searchedPaths.map((p) => ` - ${p}`).join('\n')}\n` +
199
+ `Make sure dependencies are installed by running 'bun install' or 'npm install'`,
200
+ });
201
+ }
202
+
203
+ function generateStateContent(appStateType: string): string {
204
+ return `// @generated
205
+ // AUTO-GENERATED from app.ts setup() return type
206
+ // This file is auto-generated by the build tool - do not edit manually
10
207
 
11
208
  /**
12
- * Setup lifecycle types by analyzing app.ts for setup() function
209
+ * Application state type inferred from your createApp setup function.
210
+ * This type is automatically generated and available throughout your app via ctx.app.
211
+ *
212
+ * @example
213
+ * \`\`\`typescript
214
+ * // In your agents:
215
+ * const agent = createAgent({
216
+ * handler: async (ctx, input) => {
217
+ * // ctx.app is strongly typed as GeneratedAppState
218
+ * const value = ctx.app; // All properties from your setup return value
219
+ * return 'result';
220
+ * }
221
+ * });
222
+ * \`\`\`
223
+ */
224
+ export type GeneratedAppState = ${appStateType};
225
+
226
+ // Augment the @agentuity/runtime module with AppState
227
+ declare module '@agentuity/runtime' {
228
+ interface AppState extends GeneratedAppState {}
229
+ }
230
+
231
+ // FOUND AN ERROR IN THIS FILE?
232
+ // Please file an issue at https://github.com/agentuity/sdk/issues
233
+ // or if you know the fix please submit a PR!
234
+ `;
235
+ }
236
+
237
+ function generateRouterWrapper(runtimeImportPath: string): string {
238
+ return `// @generated
239
+ // AUTO-GENERATED runtime wrapper
240
+ // This file is auto-generated by the build tool - do not edit manually
241
+
242
+ // Import augmentations file (NOT type-only) to trigger module augmentation
243
+ import type { GeneratedAppState } from './state';
244
+ import './state';
245
+
246
+ // Import from actual package location
247
+ import { createRouter as baseCreateRouter, type Env } from '${runtimeImportPath}/src/index';
248
+ import type { Hono } from 'hono';
249
+
250
+ // Type aliases to avoid repeating the generic parameter
251
+ type AppEnv = Env<GeneratedAppState>;
252
+ type AppRouter = Hono<AppEnv>;
253
+
254
+ /**
255
+ * Creates a Hono router with extended methods for Agentuity-specific routing patterns.
256
+ *
257
+ * @returns Extended Hono router with custom methods and app state typing
258
+ *
259
+ * @example
260
+ * \`\`\`typescript
261
+ * const router = createRouter();
262
+ * router.get('/hello', (c) => c.text('Hello!'));
263
+ * router.get('/db', (c) => {
264
+ * const db = c.var.app; // Your app state from createApp setup
265
+ * return c.json({ connected: true });
266
+ * });
267
+ * \`\`\`
268
+ */
269
+ export function createRouter(): AppRouter {
270
+ return baseCreateRouter() as unknown as AppRouter;
271
+ }
272
+
273
+ // Re-export everything else
274
+ export * from '${runtimeImportPath}/src/index';
275
+
276
+ // FOUND AN ERROR IN THIS FILE?
277
+ // Please file an issue at https://github.com/agentuity/sdk/issues
278
+ // or if you know the fix please submit a PR!
279
+ `;
280
+ }
281
+
282
+ async function updateTsconfigPathMapping(
283
+ rootDir: string,
284
+ shouldAdd: boolean,
285
+ logger: Logger
286
+ ): Promise<void> {
287
+ const tsconfigPath = join(rootDir, 'tsconfig.json');
288
+ if (!(await Bun.file(tsconfigPath).exists())) {
289
+ logger.debug('No tsconfig.json found, skipping path mapping update');
290
+ return;
291
+ }
292
+
293
+ try {
294
+ const tsconfigContent = await Bun.file(tsconfigPath).text();
295
+ const { parseJSONC } = await import('../../../utils/jsonc');
296
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
297
+ const tsconfig = parseJSONC(tsconfigContent) as any;
298
+ const before = JSON.stringify(tsconfig);
299
+
300
+ if (!tsconfig.compilerOptions) tsconfig.compilerOptions = {};
301
+ if (!tsconfig.compilerOptions.paths) tsconfig.compilerOptions.paths = {};
302
+
303
+ if (shouldAdd) {
304
+ tsconfig.compilerOptions.paths['@agentuity/runtime'] = ['./src/generated/router.ts'];
305
+ logger.debug('Added @agentuity/runtime path mapping to tsconfig.json');
306
+ } else {
307
+ if (tsconfig.compilerOptions.paths['@agentuity/runtime']) {
308
+ delete tsconfig.compilerOptions.paths['@agentuity/runtime'];
309
+ logger.debug('Removed @agentuity/runtime path mapping from tsconfig.json');
310
+ }
311
+ if (Object.keys(tsconfig.compilerOptions.paths).length === 0) {
312
+ delete tsconfig.compilerOptions.paths;
313
+ }
314
+ }
315
+
316
+ if (JSON.stringify(tsconfig) === before) return;
317
+ await Bun.write(tsconfigPath, JSON.stringify(tsconfig, null, '\t') + '\n');
318
+ } catch (error) {
319
+ logger.warn('Failed to update tsconfig.json:', error);
320
+ }
321
+ }
322
+
323
+ /**
324
+ * Setup lifecycle types by analyzing app.ts for setup() function.
325
+ *
326
+ * Uses TypeScript's type checker to extract the real return type — handles
327
+ * inline setup, exported setup, variable references, async functions, and
328
+ * any other pattern TS can resolve.
13
329
  */
14
330
  export async function generateLifecycleTypes(
15
331
  rootDir: string,
@@ -17,11 +333,8 @@ export async function generateLifecycleTypes(
17
333
  logger: Logger
18
334
  ): Promise<boolean> {
19
335
  logger.debug('[lifecycle] Starting lifecycle type generation...');
20
- logger.debug(`[lifecycle] rootDir: ${rootDir}`);
21
- logger.debug(`[lifecycle] srcDir: ${srcDir}`);
22
336
 
23
337
  const outDir = join(srcDir, 'generated');
24
- logger.debug(`[lifecycle] outDir: ${outDir}`);
25
338
 
26
339
  // Look for app.ts in both root and src directories
27
340
  const rootAppFile = join(rootDir, 'app.ts');
@@ -30,28 +343,39 @@ export async function generateLifecycleTypes(
30
343
  let appFile = '';
31
344
  if (await Bun.file(rootAppFile).exists()) {
32
345
  appFile = rootAppFile;
33
- logger.debug(`[lifecycle] Found app.ts at root: ${rootAppFile}`);
34
346
  } else if (await Bun.file(srcAppFile).exists()) {
35
347
  appFile = srcAppFile;
36
- logger.debug(`[lifecycle] Found app.ts in src: ${srcAppFile}`);
37
348
  }
38
349
 
39
350
  if (!appFile || !(await Bun.file(appFile).exists())) {
40
- logger.debug('[lifecycle] No app.ts found for lifecycle types generation');
351
+ logger.debug('[lifecycle] No app.ts found');
41
352
  return false;
42
353
  }
43
354
 
44
- try {
45
- logger.debug(`[lifecycle] Calling generateLifecycleTypesFromAST...`);
46
- const result = await generateLifecycleTypesFromAST(rootDir, outDir, appFile);
47
- if (result) {
48
- logger.debug(`[lifecycle] Lifecycle types generated successfully in ${outDir}`);
49
- } else {
50
- logger.debug('[lifecycle] generateLifecycleTypesFromAST returned false (no setup found)');
51
- }
52
- return result;
53
- } catch (error) {
54
- logger.error('[lifecycle] Failed to generate lifecycle types:', error);
355
+ // Use TypeScript type checker to extract the setup return type
356
+ const appStateType = extractSetupReturnType(appFile, logger);
357
+
358
+ if (!appStateType) {
359
+ logger.debug('[lifecycle] No setup() function found in createApp');
360
+ await updateTsconfigPathMapping(rootDir, false, logger);
55
361
  return false;
56
362
  }
363
+
364
+ logger.debug(`[lifecycle] Extracted setup return type: ${appStateType}`);
365
+
366
+ // Generate files
367
+ mkdirSync(outDir, { recursive: true });
368
+
369
+ const runtimePkgPath = await findRuntimePackage(rootDir, logger);
370
+ const runtimeImportPath = toForwardSlash(relative(outDir, runtimePkgPath));
371
+
372
+ await Bun.write(join(outDir, 'state.ts'), generateStateContent(appStateType));
373
+ logger.debug(`Generated lifecycle types: ${join(outDir, 'state.ts')}`);
374
+
375
+ await Bun.write(join(outDir, 'router.ts'), generateRouterWrapper(runtimeImportPath));
376
+ logger.debug(`Generated lifecycle wrapper: ${join(outDir, 'router.ts')}`);
377
+
378
+ await updateTsconfigPathMapping(rootDir, true, logger);
379
+
380
+ return true;
57
381
  }