@agentuity/cli 0.0.109 → 0.0.111

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 (253) hide show
  1. package/dist/build-report.d.ts +201 -0
  2. package/dist/build-report.d.ts.map +1 -0
  3. package/dist/build-report.js +335 -0
  4. package/dist/build-report.js.map +1 -0
  5. package/dist/cli.d.ts.map +1 -1
  6. package/dist/cli.js +19 -4
  7. package/dist/cli.js.map +1 -1
  8. package/dist/cmd/build/entry-generator.d.ts.map +1 -1
  9. package/dist/cmd/build/entry-generator.js +3 -1
  10. package/dist/cmd/build/entry-generator.js.map +1 -1
  11. package/dist/cmd/build/index.d.ts.map +1 -1
  12. package/dist/cmd/build/index.js +44 -1
  13. package/dist/cmd/build/index.js.map +1 -1
  14. package/dist/cmd/build/typecheck.d.ts +7 -1
  15. package/dist/cmd/build/typecheck.d.ts.map +1 -1
  16. package/dist/cmd/build/typecheck.js +11 -1
  17. package/dist/cmd/build/typecheck.js.map +1 -1
  18. package/dist/cmd/build/vite/agent-discovery.d.ts +1 -1
  19. package/dist/cmd/build/vite/agent-discovery.d.ts.map +1 -1
  20. package/dist/cmd/build/vite/agent-discovery.js +3 -3
  21. package/dist/cmd/build/vite/agent-discovery.js.map +1 -1
  22. package/dist/cmd/build/vite/index.d.ts +2 -1
  23. package/dist/cmd/build/vite/index.d.ts.map +1 -1
  24. package/dist/cmd/build/vite/index.js +3 -2
  25. package/dist/cmd/build/vite/index.js.map +1 -1
  26. package/dist/cmd/build/vite/metadata-generator.d.ts.map +1 -1
  27. package/dist/cmd/build/vite/metadata-generator.js +3 -5
  28. package/dist/cmd/build/vite/metadata-generator.js.map +1 -1
  29. package/dist/cmd/build/vite/registry-generator.d.ts +1 -1
  30. package/dist/cmd/build/vite/registry-generator.d.ts.map +1 -1
  31. package/dist/cmd/build/vite/registry-generator.js +126 -41
  32. package/dist/cmd/build/vite/registry-generator.js.map +1 -1
  33. package/dist/cmd/build/vite/route-discovery.d.ts +6 -0
  34. package/dist/cmd/build/vite/route-discovery.d.ts.map +1 -1
  35. package/dist/cmd/build/vite/route-discovery.js +19 -0
  36. package/dist/cmd/build/vite/route-discovery.js.map +1 -1
  37. package/dist/cmd/build/vite/vite-builder.d.ts +3 -0
  38. package/dist/cmd/build/vite/vite-builder.d.ts.map +1 -1
  39. package/dist/cmd/build/vite/vite-builder.js +10 -2
  40. package/dist/cmd/build/vite/vite-builder.js.map +1 -1
  41. package/dist/cmd/build/vite-bundler.d.ts +3 -0
  42. package/dist/cmd/build/vite-bundler.d.ts.map +1 -1
  43. package/dist/cmd/build/vite-bundler.js +14 -5
  44. package/dist/cmd/build/vite-bundler.js.map +1 -1
  45. package/dist/cmd/cloud/deploy.d.ts.map +1 -1
  46. package/dist/cmd/cloud/deploy.js +149 -10
  47. package/dist/cmd/cloud/deploy.js.map +1 -1
  48. package/dist/cmd/cloud/deployment/show.d.ts.map +1 -1
  49. package/dist/cmd/cloud/deployment/show.js +0 -1
  50. package/dist/cmd/cloud/deployment/show.js.map +1 -1
  51. package/dist/cmd/cloud/sandbox/create.d.ts.map +1 -1
  52. package/dist/cmd/cloud/sandbox/create.js +18 -0
  53. package/dist/cmd/cloud/sandbox/create.js.map +1 -1
  54. package/dist/cmd/cloud/sandbox/delete.d.ts.map +1 -1
  55. package/dist/cmd/cloud/sandbox/delete.js +2 -6
  56. package/dist/cmd/cloud/sandbox/delete.js.map +1 -1
  57. package/dist/cmd/cloud/sandbox/download.d.ts +3 -0
  58. package/dist/cmd/cloud/sandbox/download.d.ts.map +1 -0
  59. package/dist/cmd/cloud/sandbox/download.js +89 -0
  60. package/dist/cmd/cloud/sandbox/download.js.map +1 -0
  61. package/dist/cmd/cloud/sandbox/env.d.ts +3 -0
  62. package/dist/cmd/cloud/sandbox/env.d.ts.map +1 -0
  63. package/dist/cmd/cloud/sandbox/env.js +90 -0
  64. package/dist/cmd/cloud/sandbox/env.js.map +1 -0
  65. package/dist/cmd/cloud/sandbox/get.d.ts.map +1 -1
  66. package/dist/cmd/cloud/sandbox/get.js +5 -0
  67. package/dist/cmd/cloud/sandbox/get.js.map +1 -1
  68. package/dist/cmd/cloud/sandbox/index.d.ts.map +1 -1
  69. package/dist/cmd/cloud/sandbox/index.js +14 -0
  70. package/dist/cmd/cloud/sandbox/index.js.map +1 -1
  71. package/dist/cmd/cloud/sandbox/ls.d.ts +3 -0
  72. package/dist/cmd/cloud/sandbox/ls.d.ts.map +1 -0
  73. package/dist/cmd/cloud/sandbox/ls.js +119 -0
  74. package/dist/cmd/cloud/sandbox/ls.js.map +1 -0
  75. package/dist/cmd/cloud/sandbox/mkdir.d.ts +3 -0
  76. package/dist/cmd/cloud/sandbox/mkdir.d.ts.map +1 -0
  77. package/dist/cmd/cloud/sandbox/mkdir.js +59 -0
  78. package/dist/cmd/cloud/sandbox/mkdir.js.map +1 -0
  79. package/dist/cmd/cloud/sandbox/rm.d.ts +3 -0
  80. package/dist/cmd/cloud/sandbox/rm.d.ts.map +1 -0
  81. package/dist/cmd/cloud/sandbox/rm.js +45 -0
  82. package/dist/cmd/cloud/sandbox/rm.js.map +1 -0
  83. package/dist/cmd/cloud/sandbox/rmdir.d.ts +3 -0
  84. package/dist/cmd/cloud/sandbox/rmdir.d.ts.map +1 -0
  85. package/dist/cmd/cloud/sandbox/rmdir.js +59 -0
  86. package/dist/cmd/cloud/sandbox/rmdir.js.map +1 -0
  87. package/dist/cmd/cloud/sandbox/snapshot/create.d.ts.map +1 -1
  88. package/dist/cmd/cloud/sandbox/snapshot/create.js +0 -2
  89. package/dist/cmd/cloud/sandbox/snapshot/create.js.map +1 -1
  90. package/dist/cmd/cloud/sandbox/snapshot/get.d.ts.map +1 -1
  91. package/dist/cmd/cloud/sandbox/snapshot/get.js +0 -2
  92. package/dist/cmd/cloud/sandbox/snapshot/get.js.map +1 -1
  93. package/dist/cmd/cloud/sandbox/snapshot/list.d.ts.map +1 -1
  94. package/dist/cmd/cloud/sandbox/snapshot/list.js +0 -3
  95. package/dist/cmd/cloud/sandbox/snapshot/list.js.map +1 -1
  96. package/dist/cmd/cloud/sandbox/upload.d.ts +3 -0
  97. package/dist/cmd/cloud/sandbox/upload.d.ts.map +1 -0
  98. package/dist/cmd/cloud/sandbox/upload.js +77 -0
  99. package/dist/cmd/cloud/sandbox/upload.js.map +1 -0
  100. package/dist/cmd/dev/index.d.ts.map +1 -1
  101. package/dist/cmd/dev/index.js +126 -23
  102. package/dist/cmd/dev/index.js.map +1 -1
  103. package/dist/cmd/dev/sync.d.ts.map +1 -1
  104. package/dist/cmd/dev/sync.js +8 -14
  105. package/dist/cmd/dev/sync.js.map +1 -1
  106. package/dist/cmd/git/account/add.d.ts +17 -0
  107. package/dist/cmd/git/account/add.d.ts.map +1 -0
  108. package/dist/cmd/git/account/add.js +244 -0
  109. package/dist/cmd/git/account/add.js.map +1 -0
  110. package/dist/cmd/git/account/index.d.ts +3 -0
  111. package/dist/cmd/git/account/index.d.ts.map +1 -0
  112. package/dist/cmd/git/account/index.js +11 -0
  113. package/dist/cmd/git/account/index.js.map +1 -0
  114. package/dist/cmd/git/account/list.d.ts +2 -0
  115. package/dist/cmd/git/account/list.d.ts.map +1 -0
  116. package/dist/cmd/git/account/list.js +111 -0
  117. package/dist/cmd/git/account/list.js.map +1 -0
  118. package/dist/cmd/git/account/remove.d.ts +2 -0
  119. package/dist/cmd/git/account/remove.d.ts.map +1 -0
  120. package/dist/cmd/git/account/remove.js +171 -0
  121. package/dist/cmd/git/account/remove.js.map +1 -0
  122. package/dist/cmd/git/index.d.ts +3 -0
  123. package/dist/cmd/git/index.d.ts.map +1 -0
  124. package/dist/cmd/git/index.js +19 -0
  125. package/dist/cmd/git/index.js.map +1 -0
  126. package/dist/cmd/git/link.d.ts +32 -0
  127. package/dist/cmd/git/link.d.ts.map +1 -0
  128. package/dist/cmd/git/link.js +357 -0
  129. package/dist/cmd/git/link.js.map +1 -0
  130. package/dist/cmd/git/list.d.ts +2 -0
  131. package/dist/cmd/git/list.d.ts.map +1 -0
  132. package/dist/cmd/git/list.js +137 -0
  133. package/dist/cmd/git/list.js.map +1 -0
  134. package/dist/cmd/git/status.d.ts +2 -0
  135. package/dist/cmd/git/status.d.ts.map +1 -0
  136. package/dist/cmd/git/status.js +119 -0
  137. package/dist/cmd/git/status.js.map +1 -0
  138. package/dist/cmd/git/unlink.d.ts +2 -0
  139. package/dist/cmd/git/unlink.d.ts.map +1 -0
  140. package/dist/cmd/git/unlink.js +98 -0
  141. package/dist/cmd/git/unlink.js.map +1 -0
  142. package/dist/cmd/index.d.ts.map +1 -1
  143. package/dist/cmd/index.js +2 -0
  144. package/dist/cmd/index.js.map +1 -1
  145. package/dist/cmd/integration/api.d.ts +61 -0
  146. package/dist/cmd/integration/api.d.ts.map +1 -0
  147. package/dist/cmd/integration/api.js +176 -0
  148. package/dist/cmd/integration/api.js.map +1 -0
  149. package/dist/cmd/integration/github/connect.d.ts +2 -0
  150. package/dist/cmd/integration/github/connect.d.ts.map +1 -0
  151. package/dist/cmd/integration/github/connect.js +197 -0
  152. package/dist/cmd/integration/github/connect.js.map +1 -0
  153. package/dist/cmd/integration/github/disconnect.d.ts +2 -0
  154. package/dist/cmd/integration/github/disconnect.d.ts.map +1 -0
  155. package/dist/cmd/integration/github/disconnect.js +121 -0
  156. package/dist/cmd/integration/github/disconnect.js.map +1 -0
  157. package/dist/cmd/integration/github/index.d.ts +2 -0
  158. package/dist/cmd/integration/github/index.d.ts.map +1 -0
  159. package/dist/cmd/integration/github/index.js +21 -0
  160. package/dist/cmd/integration/github/index.js.map +1 -0
  161. package/dist/cmd/integration/index.d.ts +2 -0
  162. package/dist/cmd/integration/index.d.ts.map +1 -0
  163. package/dist/cmd/integration/index.js +16 -0
  164. package/dist/cmd/integration/index.js.map +1 -0
  165. package/dist/cmd/project/auth/generate.d.ts +5 -0
  166. package/dist/cmd/project/auth/generate.d.ts.map +1 -0
  167. package/dist/cmd/project/auth/generate.js +102 -0
  168. package/dist/cmd/project/auth/generate.js.map +1 -0
  169. package/dist/cmd/project/auth/index.d.ts +2 -0
  170. package/dist/cmd/project/auth/index.d.ts.map +1 -0
  171. package/dist/cmd/project/auth/index.js +21 -0
  172. package/dist/cmd/project/auth/index.js.map +1 -0
  173. package/dist/cmd/project/auth/init.d.ts +2 -0
  174. package/dist/cmd/project/auth/init.d.ts.map +1 -0
  175. package/dist/cmd/project/auth/init.js +220 -0
  176. package/dist/cmd/project/auth/init.js.map +1 -0
  177. package/dist/cmd/project/auth/shared.d.ts +88 -0
  178. package/dist/cmd/project/auth/shared.d.ts.map +1 -0
  179. package/dist/cmd/project/auth/shared.js +435 -0
  180. package/dist/cmd/project/auth/shared.js.map +1 -0
  181. package/dist/cmd/project/index.d.ts.map +1 -1
  182. package/dist/cmd/project/index.js +9 -1
  183. package/dist/cmd/project/index.js.map +1 -1
  184. package/dist/cmd/project/template-flow.d.ts.map +1 -1
  185. package/dist/cmd/project/template-flow.js +106 -0
  186. package/dist/cmd/project/template-flow.js.map +1 -1
  187. package/dist/config.d.ts +2 -0
  188. package/dist/config.d.ts.map +1 -1
  189. package/dist/config.js +24 -0
  190. package/dist/config.js.map +1 -1
  191. package/dist/errors.d.ts +2 -1
  192. package/dist/errors.d.ts.map +1 -1
  193. package/dist/errors.js +5 -0
  194. package/dist/errors.js.map +1 -1
  195. package/dist/types.d.ts +3 -4
  196. package/dist/types.d.ts.map +1 -1
  197. package/dist/types.js +5 -2
  198. package/dist/types.js.map +1 -1
  199. package/package.json +6 -5
  200. package/src/build-report.ts +457 -0
  201. package/src/cli.ts +20 -4
  202. package/src/cmd/build/entry-generator.ts +3 -1
  203. package/src/cmd/build/index.ts +51 -1
  204. package/src/cmd/build/typecheck.ts +19 -1
  205. package/src/cmd/build/vite/agent-discovery.ts +4 -4
  206. package/src/cmd/build/vite/index.ts +5 -2
  207. package/src/cmd/build/vite/metadata-generator.ts +5 -7
  208. package/src/cmd/build/vite/registry-generator.ts +136 -43
  209. package/src/cmd/build/vite/route-discovery.ts +20 -0
  210. package/src/cmd/build/vite/vite-builder.ts +13 -2
  211. package/src/cmd/build/vite-bundler.ts +17 -4
  212. package/src/cmd/cloud/deploy.ts +183 -12
  213. package/src/cmd/cloud/deployment/show.ts +0 -1
  214. package/src/cmd/cloud/sandbox/create.ts +22 -0
  215. package/src/cmd/cloud/sandbox/delete.ts +2 -6
  216. package/src/cmd/cloud/sandbox/download.ts +96 -0
  217. package/src/cmd/cloud/sandbox/env.ts +104 -0
  218. package/src/cmd/cloud/sandbox/get.ts +5 -0
  219. package/src/cmd/cloud/sandbox/index.ts +14 -0
  220. package/src/cmd/cloud/sandbox/ls.ts +126 -0
  221. package/src/cmd/cloud/sandbox/mkdir.ts +65 -0
  222. package/src/cmd/cloud/sandbox/rm.ts +51 -0
  223. package/src/cmd/cloud/sandbox/rmdir.ts +65 -0
  224. package/src/cmd/cloud/sandbox/snapshot/create.ts +0 -2
  225. package/src/cmd/cloud/sandbox/snapshot/get.ts +0 -2
  226. package/src/cmd/cloud/sandbox/snapshot/list.ts +0 -3
  227. package/src/cmd/cloud/sandbox/upload.ts +83 -0
  228. package/src/cmd/dev/index.ts +147 -33
  229. package/src/cmd/dev/sync.ts +26 -30
  230. package/src/cmd/git/account/add.ts +317 -0
  231. package/src/cmd/git/account/index.ts +12 -0
  232. package/src/cmd/git/account/list.ts +139 -0
  233. package/src/cmd/git/account/remove.ts +212 -0
  234. package/src/cmd/git/index.ts +20 -0
  235. package/src/cmd/git/link.ts +468 -0
  236. package/src/cmd/git/list.ts +161 -0
  237. package/src/cmd/git/status.ts +144 -0
  238. package/src/cmd/git/unlink.ts +117 -0
  239. package/src/cmd/index.ts +2 -0
  240. package/src/cmd/integration/api.ts +379 -0
  241. package/src/cmd/integration/github/connect.ts +242 -0
  242. package/src/cmd/integration/github/disconnect.ts +149 -0
  243. package/src/cmd/integration/github/index.ts +21 -0
  244. package/src/cmd/integration/index.ts +16 -0
  245. package/src/cmd/project/auth/generate.ts +116 -0
  246. package/src/cmd/project/auth/index.ts +21 -0
  247. package/src/cmd/project/auth/init.ts +263 -0
  248. package/src/cmd/project/auth/shared.ts +534 -0
  249. package/src/cmd/project/index.ts +9 -1
  250. package/src/cmd/project/template-flow.ts +125 -0
  251. package/src/config.ts +34 -0
  252. package/src/errors.ts +7 -0
  253. package/src/types.ts +5 -2
@@ -1,5 +1,6 @@
1
1
  import { parse, type GrammarItem } from '../../tsc-output-parser';
2
2
  import { formatTypeScriptErrors, hasErrors } from '../../typescript-errors';
3
+ import type { BuildReportCollector } from '../../build-report';
3
4
 
4
5
  interface TypeError {
5
6
  success: false;
@@ -18,13 +19,20 @@ interface TypeSuccess {
18
19
 
19
20
  type TypeResult = TypeError | TypeSuccess | TypeUnknownError;
20
21
 
22
+ export interface TypecheckOptions {
23
+ /** Optional collector for structured error reporting */
24
+ collector?: BuildReportCollector;
25
+ }
26
+
21
27
  /**
22
28
  * run the typescript compiler and result formatted results
23
29
  *
24
30
  * @param dir the absolute path to the directory containing the project (must have tsconfig.json in this folder)
31
+ * @param options optional configuration including error collector
25
32
  * @returns
26
33
  */
27
- export async function typecheck(dir: string): Promise<TypeResult> {
34
+ export async function typecheck(dir: string, options?: TypecheckOptions): Promise<TypeResult> {
35
+ const { collector } = options ?? {};
28
36
  const result = await Bun.$`bunx tsc --noEmit --skipLibCheck --pretty false`
29
37
  .cwd(dir)
30
38
  .quiet()
@@ -38,6 +46,11 @@ export async function typecheck(dir: string): Promise<TypeResult> {
38
46
  success: true,
39
47
  };
40
48
  } else if (errors && hasErrors(errors)) {
49
+ // Add errors to collector if provided
50
+ if (collector) {
51
+ collector.addTypeScriptErrors(errors);
52
+ }
53
+
41
54
  const formattedErrors = await formatTypeScriptErrors(errors, {
42
55
  projectDir: dir,
43
56
  });
@@ -47,6 +60,11 @@ export async function typecheck(dir: string): Promise<TypeResult> {
47
60
  output: formattedErrors,
48
61
  };
49
62
  } else {
63
+ // Unknown error - add to collector as general error
64
+ if (collector) {
65
+ collector.addGeneralError('typescript', output || result.stderr.toString());
66
+ }
67
+
50
68
  return {
51
69
  success: false,
52
70
  output: output || result.stderr.toString(),
@@ -65,7 +65,7 @@ export interface AgentMetadata {
65
65
 
66
66
  export interface EvalMetadata {
67
67
  id: string;
68
- evalId: string;
68
+ identifier: string;
69
69
  name: string;
70
70
  filename: string;
71
71
  version: string;
@@ -459,13 +459,13 @@ function extractEvalsFromSource(
459
459
 
460
460
  if (evalName) {
461
461
  const id = getEvalId(projectId, deploymentId, filename, evalName, version);
462
- const evalId = generateStableEvalId(projectId, agentId, evalName);
462
+ const identifier = generateStableEvalId(projectId, agentId, evalName);
463
463
 
464
- logger.trace(`Found eval '${evalName}' in ${filename} (evalId: ${evalId})`);
464
+ logger.trace(`Found eval '${evalName}' in ${filename} (identifier: ${identifier})`);
465
465
 
466
466
  evals.push({
467
467
  id,
468
- evalId,
468
+ identifier,
469
469
  name: evalName,
470
470
  filename,
471
471
  version,
@@ -1,7 +1,7 @@
1
1
  import type { Plugin } from 'vite';
2
2
  import { join } from 'node:path';
3
3
  import { createLogger } from '@agentuity/server';
4
- import type { LogLevel } from '../../../types';
4
+ import type { LogLevel, DeployOptions } from '../../../types';
5
5
  import { discoverAgents, type AgentMetadata } from './agent-discovery';
6
6
  import { discoverRoutes, type RouteMetadata, type RouteInfo } from './route-discovery';
7
7
  import { generateAgentRegistry, generateRouteRegistry } from './registry-generator';
@@ -20,6 +20,7 @@ export interface AgentuityPluginOptions {
20
20
  orgId?: string;
21
21
  deploymentId?: string;
22
22
  logLevel?: LogLevel;
23
+ deploymentOptions?: DeployOptions;
23
24
  }
24
25
 
25
26
  /**
@@ -42,6 +43,7 @@ export function agentuityPlugin(options: AgentuityPluginOptions): Plugin {
42
43
  orgId = '',
43
44
  deploymentId = '',
44
45
  logLevel = 'info',
46
+ deploymentOptions,
45
47
  } = options;
46
48
  const logger = createLogger(logLevel);
47
49
  const srcDir = join(rootDir, 'src');
@@ -85,7 +87,7 @@ export function agentuityPlugin(options: AgentuityPluginOptions): Plugin {
85
87
  }
86
88
 
87
89
  if (routeInfoList.length > 0) {
88
- generateRouteRegistry(srcDir, routeInfoList, agents);
90
+ await generateRouteRegistry(srcDir, routeInfoList, agents);
89
91
  logger.trace('Generated route registry with %d route(s)', routeInfoList.length);
90
92
  }
91
93
 
@@ -153,6 +155,7 @@ export function agentuityPlugin(options: AgentuityPluginOptions): Plugin {
153
155
  routes,
154
156
  dev,
155
157
  logger,
158
+ deploymentOptions,
156
159
  });
157
160
 
158
161
  // Write metadata file
@@ -443,7 +443,7 @@ export async function generateMetadata(options: MetadataGeneratorOptions): Promi
443
443
  evals: agent.evals?.map((evalItem) => ({
444
444
  filename: evalItem.filename,
445
445
  id: evalItem.id,
446
- evalId: evalItem.evalId,
446
+ identifier: evalItem.identifier,
447
447
  name: evalItem.name,
448
448
  version: evalItem.version,
449
449
  description: evalItem.description,
@@ -478,12 +478,10 @@ export async function generateMetadata(options: MetadataGeneratorOptions): Promi
478
478
  if (options.deploymentOptions.pullRequestNumber) {
479
479
  git.pull_request = {
480
480
  number: options.deploymentOptions.pullRequestNumber,
481
- commentId: options.deploymentOptions.pullRequestCommentId,
482
- url: options.deploymentOptions.pullRequestURL,
481
+ url: options.deploymentOptions.pullRequestUrl,
483
482
  };
484
- delete git.pullRequestCommentId;
485
483
  delete git.pullRequestNumber;
486
- delete git.pullRequestURL;
484
+ delete git.pullRequestUrl;
487
485
  }
488
486
  metadata.deployment.git = git;
489
487
  }
@@ -706,10 +704,10 @@ function generateAgentsMd(metadata: BuildMetadata): string {
706
704
  lines.push('.agentuity/');
707
705
  lines.push('├── app.js # Bundled server application');
708
706
  lines.push('├── agentuity.metadata.json # Build metadata and schemas');
709
- if (metadata.assets?.some((a) => a.filename.startsWith('client/'))) {
707
+ if (metadata.assets?.some((a: { filename: string }) => a.filename.startsWith('client/'))) {
710
708
  lines.push('├── client/ # Frontend assets (fallback, CDN by default)');
711
709
  }
712
- if (metadata.assets?.some((a) => a.filename.startsWith('public/'))) {
710
+ if (metadata.assets?.some((a: { filename: string }) => a.filename.startsWith('public/'))) {
713
711
  lines.push('├── public/ # Static assets');
714
712
  }
715
713
  lines.push('└── AGENTS.md # This file');
@@ -6,6 +6,7 @@
6
6
 
7
7
  import { join } from 'node:path';
8
8
  import { writeFileSync, mkdirSync, existsSync, unlinkSync, readFileSync } from 'node:fs';
9
+ import { stat } from 'node:fs/promises';
9
10
  import { StructuredError } from '@agentuity/core';
10
11
  import { toCamelCase, toPascalCase } from '../../../utils/string';
11
12
  import type { AgentMetadata } from './agent-discovery';
@@ -29,6 +30,28 @@ function sanitizePathSegment(segment: string): string {
29
30
  return toCamelCase(segment.replace(ROUTE_PARAM_CHARS, ''));
30
31
  }
31
32
 
33
+ /**
34
+ * Generate TypeScript type for path parameters.
35
+ * Returns 'never' if no path params, or '{ param1: string; param2: string }' format.
36
+ */
37
+ function generatePathParamsType(pathParams?: string[]): string {
38
+ if (!pathParams || pathParams.length === 0) {
39
+ return 'never';
40
+ }
41
+ return `{ ${pathParams.map((p) => `${p}: string`).join('; ')} }`;
42
+ }
43
+
44
+ /**
45
+ * Generate TypeScript tuple type for path parameters (for positional args).
46
+ * Returns '[]' if no path params, or '[string, string]' format.
47
+ */
48
+ function generatePathParamsTupleType(pathParams?: string[]): string {
49
+ if (!pathParams || pathParams.length === 0) {
50
+ return '[]';
51
+ }
52
+ return `[${pathParams.map(() => 'string').join(', ')}]`;
53
+ }
54
+
32
55
  /**
33
56
  * Generate src/generated/registry.ts with agent registry and types
34
57
  */
@@ -36,11 +59,14 @@ export function generateAgentRegistry(srcDir: string, agents: AgentMetadata[]):
36
59
  const generatedDir = join(srcDir, 'generated');
37
60
  const registryPath = join(generatedDir, 'registry.ts');
38
61
 
62
+ // Sort agents by name for deterministic output
63
+ const sortedAgents = [...agents].sort((a, b) => a.name.localeCompare(b.name));
64
+
39
65
  // Detect naming collisions in generated identifiers
40
66
  const generatedNames = new Set<string>();
41
67
  const collisions: string[] = [];
42
68
 
43
- for (const agent of agents) {
69
+ for (const agent of sortedAgents) {
44
70
  const camelName = toCamelCase(agent.name);
45
71
 
46
72
  if (generatedNames.has(camelName)) {
@@ -59,7 +85,7 @@ export function generateAgentRegistry(srcDir: string, agents: AgentMetadata[]):
59
85
  }
60
86
 
61
87
  // Generate imports for all agents
62
- const imports = agents
88
+ const imports = sortedAgents
63
89
  .map(({ name, filename }) => {
64
90
  const camelName = toCamelCase(name);
65
91
  // Handle both './agent/...' and 'src/agent/...' formats
@@ -80,7 +106,7 @@ export function generateAgentRegistry(srcDir: string, agents: AgentMetadata[]):
80
106
  .join('\n');
81
107
 
82
108
  // Generate schema type exports for all agents
83
- const schemaTypeExports = agents
109
+ const schemaTypeExports = sortedAgents
84
110
  .map(({ name, description }) => {
85
111
  const camelName = toCamelCase(name);
86
112
  const pascalName = toPascalCase(name);
@@ -122,7 +148,7 @@ export function generateAgentRegistry(srcDir: string, agents: AgentMetadata[]):
122
148
  .join('\n');
123
149
 
124
150
  // Generate flat registry structure with JSDoc
125
- const registry = agents
151
+ const registry = sortedAgents
126
152
  .map(({ name, description }) => {
127
153
  const camelName = toCamelCase(name);
128
154
  const pascalName = toPascalCase(name);
@@ -138,7 +164,7 @@ export function generateAgentRegistry(srcDir: string, agents: AgentMetadata[]):
138
164
 
139
165
  // Generate flat agent type definitions for AgentRegistry interface augmentation
140
166
  // Uses the exported Agent types defined above
141
- const runtimeAgentTypes = agents
167
+ const runtimeAgentTypes = sortedAgents
142
168
  .map(({ name }) => {
143
169
  const camelName = toCamelCase(name);
144
170
  const pascalName = toPascalCase(name);
@@ -231,7 +257,7 @@ function generateRPCRegistryType(
231
257
  apiRoutes: RouteInfo[],
232
258
  websocketRoutes: RouteInfo[],
233
259
  sseRoutes: RouteInfo[],
234
- _agentImports: Map<string, string>,
260
+ agentImports: Map<string, string>,
235
261
  _schemaImportAliases: Map<string, Map<string, string>>,
236
262
  agentMetadataMap: Map<string, AgentMetadata>
237
263
  ): string {
@@ -263,6 +289,10 @@ function generateRPCRegistryType(
263
289
  // Add path segments - sanitize for valid TypeScript property names
264
290
  for (let i = 0; i < pathParts.length; i++) {
265
291
  const part = sanitizePathSegment(pathParts[i]);
292
+ // Skip empty segments (e.g., wildcards like '*' that sanitize to '')
293
+ if (!part) {
294
+ continue;
295
+ }
266
296
  if (!current[part]) {
267
297
  current[part] = {};
268
298
  }
@@ -292,8 +322,12 @@ function generateRPCRegistryType(
292
322
  // Only reference type names if route has actual schemas extracted, otherwise use 'never'
293
323
  // Note: hasValidator may be true (e.g., zValidator('query', ...)) but no schemas extracted
294
324
  // because only 'json' validators extract input schemas
325
+ // Also check if agentVariable exists but import wasn't added (missing agentImportPath)
326
+ const hasValidAgentImport = route.agentVariable
327
+ ? !!agentImports.get(route.agentVariable)
328
+ : false;
295
329
  const hasSchemas =
296
- route.inputSchemaVariable || route.outputSchemaVariable || route.agentVariable;
330
+ route.inputSchemaVariable || route.outputSchemaVariable || hasValidAgentImport;
297
331
 
298
332
  current[terminalMethod] = {
299
333
  input: hasSchemas ? `${pascalName}Input` : 'never',
@@ -315,7 +349,9 @@ function generateRPCRegistryType(
315
349
  function treeToTypeString(node: NestedNode, indent: string = '\t\t'): string {
316
350
  const lines: string[] = [];
317
351
 
318
- for (const [key, value] of Object.entries(node)) {
352
+ // Sort entries alphabetically for deterministic output
353
+ const sortedEntries = Object.entries(node).sort(([a], [b]) => a.localeCompare(b));
354
+ for (const [key, value] of sortedEntries) {
319
355
  if (
320
356
  value &&
321
357
  typeof value === 'object' &&
@@ -349,8 +385,10 @@ function generateRPCRegistryType(
349
385
  jsdoc.push(`${indent} */`);
350
386
  lines.push(...jsdoc);
351
387
 
388
+ const pathParamsType = generatePathParamsType(routeInfo.pathParams);
389
+ const pathParamsTupleType = generatePathParamsTupleType(routeInfo.pathParams);
352
390
  lines.push(
353
- `${indent}${key}: { input: ${value.input}; output: ${value.output}; type: ${value.type} };`
391
+ `${indent}${key}: { input: ${value.input}; output: ${value.output}; type: ${value.type}; params: ${pathParamsType}; paramsTuple: ${pathParamsTupleType} };`
354
392
  );
355
393
  } else {
356
394
  // Nested node
@@ -380,7 +418,7 @@ function generateRPCRuntimeMetadata(
380
418
  sseRoutes: RouteInfo[]
381
419
  ): string {
382
420
  interface MetadataNode {
383
- [key: string]: MetadataNode | { type: string };
421
+ [key: string]: MetadataNode | { type: string; path: string; pathParams?: string[] };
384
422
  }
385
423
 
386
424
  const tree: MetadataNode = {};
@@ -400,6 +438,10 @@ function generateRPCRuntimeMetadata(
400
438
  // Sanitize path segments for valid property names (must match type generation)
401
439
  for (const part of pathParts) {
402
440
  const sanitized = sanitizePathSegment(part);
441
+ // Skip empty segments (e.g., wildcards like '*' that sanitize to '')
442
+ if (!sanitized) {
443
+ continue;
444
+ }
403
445
  if (!current[sanitized]) current[sanitized] = {};
404
446
  current = current[sanitized];
405
447
  }
@@ -414,14 +456,35 @@ function generateRPCRuntimeMetadata(
414
456
  ? 'stream'
415
457
  : route.method.toLowerCase();
416
458
 
417
- current[terminalMethod] = { type: routeType };
459
+ const metadata: { type: string; path: string; pathParams?: string[] } = {
460
+ type: routeType,
461
+ path: route.path,
462
+ };
463
+ if (route.pathParams && route.pathParams.length > 0) {
464
+ metadata.pathParams = route.pathParams;
465
+ }
466
+ current[terminalMethod] = metadata;
418
467
  };
419
468
 
420
469
  apiRoutes.forEach((r) => addRoute(r, r.routeType === 'stream' ? 'stream' : 'api'));
421
470
  websocketRoutes.forEach((r) => addRoute(r, 'websocket'));
422
471
  sseRoutes.forEach((r) => addRoute(r, 'sse'));
423
472
 
424
- return JSON.stringify(tree, null, '\t\t');
473
+ // Sort object keys recursively for deterministic output
474
+ const sortObject = (obj: MetadataNode): MetadataNode => {
475
+ const sorted: MetadataNode = {};
476
+ for (const key of Object.keys(obj).sort()) {
477
+ const value = obj[key];
478
+ if (value && typeof value === 'object' && !('type' in value)) {
479
+ sorted[key] = sortObject(value as MetadataNode);
480
+ } else {
481
+ sorted[key] = value;
482
+ }
483
+ }
484
+ return sorted;
485
+ };
486
+
487
+ return JSON.stringify(sortObject(tree), null, '\t\t');
425
488
  }
426
489
 
427
490
  /**
@@ -430,15 +493,15 @@ function generateRPCRuntimeMetadata(
430
493
  * Creates a module augmentation for @agentuity/react that provides
431
494
  * strongly-typed route keys with input/output schema information.
432
495
  */
433
- export function generateRouteRegistry(
496
+ export async function generateRouteRegistry(
434
497
  srcDir: string,
435
498
  routes: RouteInfo[],
436
499
  agents: AgentMetadata[] = []
437
- ): void {
438
- // Check if project uses @agentuity/react
500
+ ): Promise<void> {
439
501
  const projectRoot = join(srcDir, '..');
440
502
  const packageJsonPath = join(projectRoot, 'package.json');
441
503
  let hasReactDependency = false;
504
+ let hasFrontendDependency = false;
442
505
 
443
506
  try {
444
507
  const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
@@ -446,14 +509,32 @@ export function generateRouteRegistry(
446
509
  packageJson.dependencies?.['@agentuity/react'] ||
447
510
  packageJson.devDependencies?.['@agentuity/react']
448
511
  );
512
+ hasFrontendDependency = !!(
513
+ packageJson.dependencies?.['@agentuity/frontend'] ||
514
+ packageJson.devDependencies?.['@agentuity/frontend']
515
+ );
516
+ } catch {
517
+ // If we can't read package.json, assume no frontend dependencies
518
+ }
519
+
520
+ const webDir = join(srcDir, 'web');
521
+ let hasWebDirectory = false;
522
+ try {
523
+ const webDirStat = await stat(webDir);
524
+ hasWebDirectory = webDirStat.isDirectory();
449
525
  } catch {
450
- // If we can't read package.json, assume no React dependency
526
+ // Directory doesn't exist
451
527
  }
452
528
 
453
- // Filter routes by type
454
- const apiRoutes = routes.filter((r) => r.routeType === 'api' || r.routeType === 'stream');
455
- const websocketRoutes = routes.filter((r) => r.routeType === 'websocket');
456
- const sseRoutes = routes.filter((r) => r.routeType === 'sse');
529
+ const shouldEmitFrontendClient = hasFrontendDependency && !hasReactDependency && hasWebDirectory;
530
+
531
+ // Filter routes by type and sort by path for deterministic output
532
+ const sortByPath = (a: RouteInfo, b: RouteInfo) => a.path.localeCompare(b.path);
533
+ const apiRoutes = routes
534
+ .filter((r) => r.routeType === 'api' || r.routeType === 'stream')
535
+ .sort(sortByPath);
536
+ const websocketRoutes = routes.filter((r) => r.routeType === 'websocket').sort(sortByPath);
537
+ const sseRoutes = routes.filter((r) => r.routeType === 'sse').sort(sortByPath);
457
538
 
458
539
  const allRoutes = [...apiRoutes, ...websocketRoutes, ...sseRoutes];
459
540
 
@@ -637,8 +718,10 @@ export function generateRouteRegistry(
637
718
  agentMeta = agentMetadataMap.get(route.agentVariable);
638
719
  }
639
720
 
640
- if (route.agentVariable) {
641
- const importName = agentImports.get(route.agentVariable)!;
721
+ // Only generate agent-based types if the import was successfully added
722
+ // (import is only added when hasValidator && agentVariable && agentImportPath are all present)
723
+ const importName = route.agentVariable ? agentImports.get(route.agentVariable) : undefined;
724
+ if (importName) {
642
725
  inputType = `InferInput<typeof ${importName}['inputSchema']>`;
643
726
  outputType = `InferOutput<typeof ${importName}['outputSchema']>`;
644
727
  inputSchemaType = `typeof ${importName} extends { inputSchema?: infer I } ? I : never`;
@@ -724,20 +807,28 @@ export function generateRouteRegistry(
724
807
  .replace(/_+/g, '_');
725
808
  const pascalName = toPascalCase(safeName);
726
809
 
810
+ // Use the exported schema types we generated above
811
+ // Note: agentImports.get() may return undefined if import wasn't added
812
+ const importName = route.agentVariable ? agentImports.get(route.agentVariable) : null;
813
+
727
814
  // Use 'never' types if no schemas were actually extracted
728
815
  // Note: hasValidator may be true (e.g., zValidator('query', ...)) but no schemas extracted
729
816
  // because only 'json' validators extract input schemas
730
- if (!route.inputSchemaVariable && !route.outputSchemaVariable && !route.agentVariable) {
817
+ // Also check if agentVariable exists but import wasn't added (missing agentImportPath)
818
+ const hasValidAgentImport = route.agentVariable ? !!importName : false;
819
+
820
+ // Generate pathParams type
821
+ const pathParamsType = generatePathParamsType(route.pathParams);
822
+
823
+ if (!route.inputSchemaVariable && !route.outputSchemaVariable && !hasValidAgentImport) {
731
824
  const streamValue = route.stream === true ? 'true' : 'false';
732
825
  return `\t'${routeKey}': {
733
- \t\tinputSchema: never;
734
- \t\toutputSchema: never;
735
- \t\tstream: ${streamValue};
736
- \t};`;
826
+ \t\tinputSchema: never;
827
+ \t\toutputSchema: never;
828
+ \t\tstream: ${streamValue};
829
+ \t\tparams: ${pathParamsType};
830
+ \t};`;
737
831
  }
738
-
739
- // Use the exported schema types we generated above
740
- const importName = route.agentVariable ? agentImports.get(route.agentVariable)! : null;
741
832
  const streamValue = importName
742
833
  ? `typeof ${importName} extends { stream?: infer S } ? S : false`
743
834
  : route.stream === true
@@ -745,10 +836,11 @@ export function generateRouteRegistry(
745
836
  : 'false';
746
837
 
747
838
  return `\t'${routeKey}': {
748
- \t\tinputSchema: ${pascalName}InputSchema;
749
- \t\toutputSchema: ${pascalName}OutputSchema;
750
- \t\tstream: ${streamValue};
751
- \t};`;
839
+ \t\tinputSchema: ${pascalName}InputSchema;
840
+ \t\toutputSchema: ${pascalName}OutputSchema;
841
+ \t\tstream: ${streamValue};
842
+ \t\tparams: ${pathParamsType};
843
+ \t};`;
752
844
  };
753
845
 
754
846
  // Generate route entries with METHOD prefix for API routes
@@ -778,7 +870,7 @@ export function generateRouteRegistry(
778
870
  const generatedContent = `// @generated
779
871
  // Auto-generated by Agentuity - DO NOT EDIT
780
872
  ${importsStr}${typeImports}${
781
- !hasReactDependency
873
+ shouldEmitFrontendClient
782
874
  ? `
783
875
  import { createClient } from '@agentuity/frontend';`
784
876
  : ''
@@ -803,7 +895,7 @@ ${routeSchemaTypes}
803
895
  * Individual route Input/Output types are exported above for direct usage.
804
896
  */
805
897
  ${
806
- !hasReactDependency
898
+ shouldEmitFrontendClient
807
899
  ? `
808
900
  /**
809
901
  * RPC Route Registry
@@ -868,13 +960,14 @@ if (typeof globalThis !== 'undefined') {
868
960
  (globalThis as Record<string, unknown>).__rpcRouteMetadata = _rpcRouteMetadata;
869
961
  }
870
962
  ${
871
- !hasReactDependency
963
+ shouldEmitFrontendClient
872
964
  ? `
873
965
  /**
874
966
  * Create a type-safe API client with optional configuration.
875
967
  *
876
- * This function is only generated when @agentuity/react is not installed.
877
- * If using React, import createAPIClient from '@agentuity/react' instead.
968
+ * This function is only generated when @agentuity/frontend is installed
969
+ * but @agentuity/react is not. For React apps, import createAPIClient
970
+ * from '@agentuity/react' instead.
878
971
  *
879
972
  * @example
880
973
  * \`\`\`typescript
@@ -893,7 +986,8 @@ export function createAPIClient(options?: Parameters<typeof createClient>[0]): i
893
986
  return createClient(options || {}, _rpcRouteMetadata) as import('@agentuity/frontend').Client<RPCRouteRegistry>;
894
987
  }
895
988
  `
896
- : `
989
+ : hasReactDependency
990
+ ? `
897
991
  /**
898
992
  * Type-safe API client is available from @agentuity/react
899
993
  *
@@ -906,6 +1000,7 @@ export function createAPIClient(options?: Parameters<typeof createClient>[0]): i
906
1000
  * \`\`\`
907
1001
  */
908
1002
  `
1003
+ : ''
909
1004
  }
910
1005
 
911
1006
  // FOUND AN ERROR IN THIS FILE?
@@ -916,9 +1011,7 @@ export function createAPIClient(options?: Parameters<typeof createClient>[0]): i
916
1011
  const generatedDir = join(srcDir, 'generated');
917
1012
  const registryPath = join(generatedDir, 'routes.ts');
918
1013
 
919
- if (!existsSync(generatedDir)) {
920
- mkdirSync(generatedDir, { recursive: true });
921
- }
1014
+ mkdirSync(generatedDir, { recursive: true });
922
1015
 
923
1016
  // Collapse 2+ consecutive empty lines into 1 empty line (3+ \n becomes 2 \n)
924
1017
  const cleanedContent = generatedContent.replace(/\n{3,}/g, '\n\n');
@@ -40,6 +40,24 @@ export interface RouteInfo {
40
40
  inputSchemaCode?: string;
41
41
  outputSchemaCode?: string;
42
42
  stream?: boolean;
43
+ pathParams?: string[];
44
+ }
45
+
46
+ /**
47
+ * Extract path parameters from a route path.
48
+ * Matches patterns like :id, :userId, :id?, *path, etc.
49
+ */
50
+ export function extractPathParams(path: string): string[] {
51
+ const params: string[] = [];
52
+ const parts = path.split('/');
53
+ for (const part of parts) {
54
+ if (part.startsWith(':')) {
55
+ params.push(part.replace(/^:|[?+*]$/g, ''));
56
+ } else if (part.startsWith('*') && part.length > 1) {
57
+ params.push(part.substring(1).replace(/[?+*]$/g, ''));
58
+ }
59
+ }
60
+ return params;
43
61
  }
44
62
 
45
63
  /**
@@ -90,6 +108,7 @@ export async function discoverRoutes(
90
108
 
91
109
  // Convert to RouteInfo for registry
92
110
  for (const route of parsedRoutes) {
111
+ const pathParams = extractPathParams(route.path);
93
112
  routeInfoList.push({
94
113
  method: route.method.toUpperCase(),
95
114
  path: route.path,
@@ -106,6 +125,7 @@ export async function discoverRoutes(
106
125
  : route.type === 'stream'
107
126
  ? true
108
127
  : undefined,
128
+ pathParams: pathParams.length > 0 ? pathParams : undefined,
109
129
  });
110
130
  }
111
131
  }
@@ -10,6 +10,7 @@ import { createRequire } from 'node:module';
10
10
  import type { InlineConfig, Plugin } from 'vite';
11
11
  import type { Logger, DeployOptions } from '../../../types';
12
12
  import { browserEnvPlugin } from './browser-env-plugin';
13
+ import type { BuildReportCollector } from '../../../build-report';
13
14
 
14
15
  /**
15
16
  * Vite plugin to flatten the output structure for index.html
@@ -56,6 +57,8 @@ export interface ViteBuildOptions {
56
57
  workbenchEnabled?: boolean;
57
58
  logger: Logger;
58
59
  deploymentOptions?: DeployOptions;
60
+ /** Optional collector for structured error reporting */
61
+ collector?: BuildReportCollector;
59
62
  }
60
63
 
61
64
  /**
@@ -256,7 +259,7 @@ interface BuildResult {
256
259
  * Run all builds in sequence: client -> workbench (if enabled) -> server
257
260
  */
258
261
  export async function runAllBuilds(options: Omit<ViteBuildOptions, 'mode'>): Promise<BuildResult> {
259
- const { rootDir, projectId = '', dev = false, logger } = options;
262
+ const { rootDir, projectId = '', dev = false, logger, collector } = options;
260
263
 
261
264
  if (!dev) {
262
265
  rmSync(join(rootDir, '.agentuity'), { force: true, recursive: true });
@@ -302,7 +305,7 @@ export async function runAllBuilds(options: Omit<ViteBuildOptions, 'mode'>): Pro
302
305
  // Generate agent and route registries for type augmentation BEFORE builds
303
306
  // (TypeScript needs these files to exist during type checking)
304
307
  generateAgentRegistry(srcDir, agentMetadata);
305
- generateRouteRegistry(srcDir, routeInfoList);
308
+ await generateRouteRegistry(srcDir, routeInfoList);
306
309
  logger.debug('Agent and route registries generated');
307
310
 
308
311
  // Check if web frontend exists
@@ -311,6 +314,7 @@ export async function runAllBuilds(options: Omit<ViteBuildOptions, 'mode'>): Pro
311
314
  // 2. Build client (only if web frontend exists)
312
315
  if (hasWebFrontend) {
313
316
  logger.debug('Building client assets...');
317
+ const endClientDiagnostic = collector?.startDiagnostic('client-build');
314
318
  const started = Date.now();
315
319
  await runViteBuild({
316
320
  ...options,
@@ -320,6 +324,7 @@ export async function runAllBuilds(options: Omit<ViteBuildOptions, 'mode'>): Pro
320
324
  });
321
325
  result.client.included = true;
322
326
  result.client.duration = Date.now() - started;
327
+ endClientDiagnostic?.();
323
328
  } else {
324
329
  logger.debug('Skipping client build - no src/web/index.html found');
325
330
  }
@@ -327,6 +332,7 @@ export async function runAllBuilds(options: Omit<ViteBuildOptions, 'mode'>): Pro
327
332
  // 3. Build workbench (if enabled in config)
328
333
  if (workbenchConfig.enabled) {
329
334
  logger.debug('Building workbench assets...');
335
+ const endWorkbenchDiagnostic = collector?.startDiagnostic('workbench-build');
330
336
  const started = Date.now();
331
337
  await runViteBuild({
332
338
  ...options,
@@ -336,17 +342,21 @@ export async function runAllBuilds(options: Omit<ViteBuildOptions, 'mode'>): Pro
336
342
  });
337
343
  result.workbench.included = true;
338
344
  result.workbench.duration = Date.now() - started;
345
+ endWorkbenchDiagnostic?.();
339
346
  }
340
347
 
341
348
  // 4. Build server
342
349
  logger.debug('Building server...');
350
+ const endServerDiagnostic = collector?.startDiagnostic('server-build');
343
351
  const serverStarted = Date.now();
344
352
  await runViteBuild({ ...options, mode: 'server' });
345
353
  result.server.included = true;
346
354
  result.server.duration = Date.now() - serverStarted;
355
+ endServerDiagnostic?.();
347
356
 
348
357
  // 5. Generate metadata (after all builds complete)
349
358
  logger.debug('Generating metadata...');
359
+ const endMetadataDiagnostic = collector?.startDiagnostic('metadata-generation');
350
360
  const { generateMetadata, writeMetadataFile } = await import('./metadata-generator');
351
361
 
352
362
  // Generate metadata
@@ -363,6 +373,7 @@ export async function runAllBuilds(options: Omit<ViteBuildOptions, 'mode'>): Pro
363
373
  });
364
374
 
365
375
  writeMetadataFile(rootDir, metadata, dev, logger);
376
+ endMetadataDiagnostic?.();
366
377
  logger.debug('Registry and metadata generation complete');
367
378
 
368
379
  logger.debug('All builds complete');