@agentuity/cli 0.0.99 → 0.0.101

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 (107) hide show
  1. package/AGENTS.md +1 -1
  2. package/dist/api.d.ts +1 -0
  3. package/dist/api.d.ts.map +1 -1
  4. package/dist/api.js +1 -1
  5. package/dist/api.js.map +1 -1
  6. package/dist/auth.d.ts.map +1 -1
  7. package/dist/auth.js +5 -0
  8. package/dist/auth.js.map +1 -1
  9. package/dist/cmd/build/ast.d.ts +2 -1
  10. package/dist/cmd/build/ast.d.ts.map +1 -1
  11. package/dist/cmd/build/ast.js +135 -47
  12. package/dist/cmd/build/ast.js.map +1 -1
  13. package/dist/cmd/build/entry-generator.d.ts.map +1 -1
  14. package/dist/cmd/build/entry-generator.js +220 -188
  15. package/dist/cmd/build/entry-generator.js.map +1 -1
  16. package/dist/cmd/build/vite/agent-discovery.d.ts.map +1 -1
  17. package/dist/cmd/build/vite/agent-discovery.js +103 -45
  18. package/dist/cmd/build/vite/agent-discovery.js.map +1 -1
  19. package/dist/cmd/build/vite/bun-dev-server.js +1 -1
  20. package/dist/cmd/build/vite/bun-dev-server.js.map +1 -1
  21. package/dist/cmd/build/vite/docs-generator.d.ts +13 -0
  22. package/dist/cmd/build/vite/docs-generator.d.ts.map +1 -0
  23. package/dist/cmd/build/vite/docs-generator.js +81 -0
  24. package/dist/cmd/build/vite/docs-generator.js.map +1 -0
  25. package/dist/cmd/build/vite/index.d.ts +3 -4
  26. package/dist/cmd/build/vite/index.d.ts.map +1 -1
  27. package/dist/cmd/build/vite/index.js +9 -8
  28. package/dist/cmd/build/vite/index.js.map +1 -1
  29. package/dist/cmd/build/vite/lifecycle-generator.d.ts +1 -1
  30. package/dist/cmd/build/vite/lifecycle-generator.d.ts.map +1 -1
  31. package/dist/cmd/build/vite/lifecycle-generator.js +19 -5
  32. package/dist/cmd/build/vite/lifecycle-generator.js.map +1 -1
  33. package/dist/cmd/build/vite/metadata-generator.d.ts.map +1 -1
  34. package/dist/cmd/build/vite/metadata-generator.js +145 -0
  35. package/dist/cmd/build/vite/metadata-generator.js.map +1 -1
  36. package/dist/cmd/build/vite/registry-generator.d.ts +3 -3
  37. package/dist/cmd/build/vite/registry-generator.d.ts.map +1 -1
  38. package/dist/cmd/build/vite/registry-generator.js +627 -103
  39. package/dist/cmd/build/vite/registry-generator.js.map +1 -1
  40. package/dist/cmd/build/vite/route-discovery.d.ts +4 -0
  41. package/dist/cmd/build/vite/route-discovery.d.ts.map +1 -1
  42. package/dist/cmd/build/vite/route-discovery.js.map +1 -1
  43. package/dist/cmd/build/vite/server-bundler.d.ts.map +1 -1
  44. package/dist/cmd/build/vite/server-bundler.js +48 -1
  45. package/dist/cmd/build/vite/server-bundler.js.map +1 -1
  46. package/dist/cmd/build/vite/vite-builder.d.ts +1 -1
  47. package/dist/cmd/build/vite/vite-builder.d.ts.map +1 -1
  48. package/dist/cmd/build/vite/vite-builder.js +30 -21
  49. package/dist/cmd/build/vite/vite-builder.js.map +1 -1
  50. package/dist/cmd/build/vite-bundler.js +6 -6
  51. package/dist/cmd/build/vite-bundler.js.map +1 -1
  52. package/dist/cmd/cloud/deploy.d.ts.map +1 -1
  53. package/dist/cmd/cloud/deploy.js +11 -5
  54. package/dist/cmd/cloud/deploy.js.map +1 -1
  55. package/dist/cmd/dev/file-watcher.d.ts.map +1 -1
  56. package/dist/cmd/dev/file-watcher.js +33 -1
  57. package/dist/cmd/dev/file-watcher.js.map +1 -1
  58. package/dist/cmd/dev/index.d.ts.map +1 -1
  59. package/dist/cmd/dev/index.js +102 -21
  60. package/dist/cmd/dev/index.js.map +1 -1
  61. package/dist/cmd/dev/sync.d.ts.map +1 -1
  62. package/dist/cmd/dev/sync.js +19 -3
  63. package/dist/cmd/dev/sync.js.map +1 -1
  64. package/dist/cmd/project/create.d.ts.map +1 -1
  65. package/dist/cmd/project/create.js +8 -2
  66. package/dist/cmd/project/create.js.map +1 -1
  67. package/dist/config.d.ts.map +1 -1
  68. package/dist/config.js +8 -0
  69. package/dist/config.js.map +1 -1
  70. package/dist/index.d.ts +0 -1
  71. package/dist/index.d.ts.map +1 -1
  72. package/dist/index.js +0 -1
  73. package/dist/index.js.map +1 -1
  74. package/package.json +5 -8
  75. package/src/api.ts +1 -1
  76. package/src/auth.ts +6 -0
  77. package/src/cmd/build/ast.ts +161 -48
  78. package/src/cmd/build/entry-generator.ts +225 -190
  79. package/src/cmd/build/vite/agent-discovery.ts +151 -58
  80. package/src/cmd/build/vite/bun-dev-server.ts +1 -1
  81. package/src/cmd/build/vite/docs-generator.ts +87 -0
  82. package/src/cmd/build/vite/index.ts +9 -8
  83. package/src/cmd/build/vite/lifecycle-generator.ts +19 -5
  84. package/src/cmd/build/vite/metadata-generator.ts +178 -0
  85. package/src/cmd/build/vite/registry-generator.ts +727 -108
  86. package/src/cmd/build/vite/route-discovery.ts +4 -0
  87. package/src/cmd/build/vite/server-bundler.ts +56 -1
  88. package/src/cmd/build/vite/vite-builder.ts +46 -33
  89. package/src/cmd/build/vite-bundler.ts +6 -6
  90. package/src/cmd/cloud/deploy.ts +15 -5
  91. package/src/cmd/dev/file-watcher.ts +37 -1
  92. package/src/cmd/dev/index.ts +141 -30
  93. package/src/cmd/dev/sync.ts +41 -6
  94. package/src/cmd/project/create.ts +13 -3
  95. package/src/config.ts +9 -0
  96. package/src/index.ts +0 -5
  97. package/src/runtime-bootstrap.md +1 -1
  98. package/dist/cmd/build/vite/patch-plugin.d.ts +0 -21
  99. package/dist/cmd/build/vite/patch-plugin.d.ts.map +0 -1
  100. package/dist/cmd/build/vite/patch-plugin.js +0 -70
  101. package/dist/cmd/build/vite/patch-plugin.js.map +0 -1
  102. package/dist/runtime-bootstrap.d.ts +0 -56
  103. package/dist/runtime-bootstrap.d.ts.map +0 -1
  104. package/dist/runtime-bootstrap.js +0 -95
  105. package/dist/runtime-bootstrap.js.map +0 -1
  106. package/src/cmd/build/vite/patch-plugin.ts +0 -88
  107. package/src/runtime-bootstrap.ts +0 -131
@@ -306,7 +306,8 @@ function extractAgentMetadata(
306
306
  }
307
307
 
308
308
  /**
309
- * Extract evals from eval.ts file (READ-ONLY)
309
+ * Extract evals from a file (READ-ONLY)
310
+ * Finds createEval calls regardless of whether they're exported or not
310
311
  */
311
312
  async function extractEvalMetadata(
312
313
  evalsPath: string,
@@ -322,72 +323,135 @@ async function extractEvalMetadata(
322
323
 
323
324
  try {
324
325
  const evalsSource = await evalsFile.text();
326
+ return extractEvalsFromSource(
327
+ evalsSource,
328
+ evalsPath,
329
+ agentId,
330
+ projectId,
331
+ deploymentId,
332
+ logger
333
+ );
334
+ } catch (error) {
335
+ logger.warn(`Failed to parse evals from ${evalsPath}: ${error}`);
336
+ return [];
337
+ }
338
+ }
339
+
340
+ /**
341
+ * Extract evals from source code (READ-ONLY)
342
+ * Finds all createEval calls in the source, exported or not
343
+ */
344
+ function extractEvalsFromSource(
345
+ source: string,
346
+ filename: string,
347
+ agentId: string,
348
+ projectId: string,
349
+ deploymentId: string,
350
+ logger: Logger
351
+ ): EvalMetadata[] {
352
+ // Quick check - skip if no createEval in source
353
+ if (!source.includes('createEval')) {
354
+ return [];
355
+ }
356
+
357
+ try {
325
358
  const transpiler = new Bun.Transpiler({ loader: 'ts', target: 'bun' });
326
- const evalsContents = transpiler.transformSync(evalsSource);
327
- const version = hash(evalsContents);
359
+ const contents = transpiler.transformSync(source);
360
+ const version = hash(contents);
328
361
 
329
- const ast = acornLoose.parse(evalsContents, { ecmaVersion: 'latest', sourceType: 'module' });
362
+ const ast = acornLoose.parse(contents, { ecmaVersion: 'latest', sourceType: 'module' });
330
363
  const evals: EvalMetadata[] = [];
331
364
 
332
- // Find createEval calls
333
- for (const node of (ast as { body: ASTNode[] }).body) {
334
- if (node.type === 'ExportNamedDeclaration') {
335
- const declaration = (
336
- node as unknown as { declaration: { declarations?: ASTVariableDeclarator[] } }
337
- ).declaration;
338
-
339
- if (declaration?.declarations) {
340
- for (const decl of declaration.declarations) {
341
- if (decl.init && decl.init.type === 'CallExpression') {
342
- const callExpr = decl.init as ASTCallExpression;
343
-
344
- if (
345
- callExpr.callee.type === 'Identifier' &&
346
- (callExpr.callee as ASTNodeIdentifier).name === 'createEval' &&
347
- callExpr.arguments.length >= 2
348
- ) {
349
- const nameArg = callExpr.arguments[0] as ASTLiteral;
350
- const evalName = String(nameArg.value);
351
-
352
- const callargexp = callExpr.arguments[1] as ASTObjectExpression;
353
- let description: string | undefined;
354
-
355
- for (const prop of callargexp.properties) {
356
- if (
357
- prop.key.name === 'metadata' &&
358
- prop.value.type === 'ObjectExpression'
359
- ) {
360
- const metadataMap = parseObjectExpressionToMap(
361
- prop.value as ASTObjectExpression
362
- );
363
- description = metadataMap.get('description');
364
- break;
365
- }
366
- }
365
+ // Recursively find all createEval calls in the AST
366
+ function findCreateEvalCalls(node: unknown): void {
367
+ if (!node || typeof node !== 'object') return;
368
+
369
+ const n = node as Record<string, unknown>;
370
+
371
+ // Check if this is a createEval call (either direct or method call)
372
+ // Direct: createEval('name', {...})
373
+ // Method: agent.createEval('name', {...})
374
+ let isCreateEvalCall = false;
375
+
376
+ if (n.type === 'CallExpression' && n.callee && typeof n.callee === 'object') {
377
+ const callee = n.callee as ASTNode & { property?: ASTNodeIdentifier };
378
+
379
+ // Direct function call: createEval(...)
380
+ if (
381
+ callee.type === 'Identifier' &&
382
+ (callee as ASTNodeIdentifier).name === 'createEval'
383
+ ) {
384
+ isCreateEvalCall = true;
385
+ }
386
+
387
+ // Method call: someAgent.createEval(...)
388
+ if (
389
+ callee.type === 'MemberExpression' &&
390
+ callee.property &&
391
+ callee.property.type === 'Identifier' &&
392
+ callee.property.name === 'createEval'
393
+ ) {
394
+ isCreateEvalCall = true;
395
+ }
396
+ }
397
+
398
+ if (isCreateEvalCall) {
399
+ const callExpr = n as unknown as ASTCallExpression;
400
+ if (callExpr.arguments.length >= 2) {
401
+ const nameArg = callExpr.arguments[0] as ASTLiteral;
402
+ const evalName = String(nameArg.value);
367
403
 
368
- const id = getEvalId(projectId, deploymentId, evalsPath, evalName, version);
369
- const evalId = generateStableEvalId(projectId, agentId, evalName);
370
-
371
- evals.push({
372
- id,
373
- evalId,
374
- name: evalName,
375
- filename: evalsPath,
376
- version,
377
- description,
378
- agentIdentifier: agentId,
379
- projectId,
380
- });
404
+ const callargexp = callExpr.arguments[1] as ASTObjectExpression;
405
+ let description: string | undefined;
406
+
407
+ if (callargexp.properties) {
408
+ for (const prop of callargexp.properties) {
409
+ if (prop.key.name === 'metadata' && prop.value.type === 'ObjectExpression') {
410
+ const metadataMap = parseObjectExpressionToMap(
411
+ prop.value as ASTObjectExpression
412
+ );
413
+ description = metadataMap.get('description');
414
+ break;
381
415
  }
382
416
  }
383
417
  }
418
+
419
+ const id = getEvalId(projectId, deploymentId, filename, evalName, version);
420
+ const evalId = generateStableEvalId(projectId, agentId, evalName);
421
+
422
+ logger.trace(`Found eval '${evalName}' in ${filename} (evalId: ${evalId})`);
423
+
424
+ evals.push({
425
+ id,
426
+ evalId,
427
+ name: evalName,
428
+ filename,
429
+ version,
430
+ description,
431
+ agentIdentifier: agentId,
432
+ projectId,
433
+ });
434
+ }
435
+ }
436
+
437
+ // Recursively search child nodes
438
+ for (const key of Object.keys(n)) {
439
+ const value = n[key];
440
+ if (Array.isArray(value)) {
441
+ for (const item of value) {
442
+ findCreateEvalCalls(item);
443
+ }
444
+ } else if (value && typeof value === 'object') {
445
+ findCreateEvalCalls(value);
384
446
  }
385
447
  }
386
448
  }
387
449
 
450
+ findCreateEvalCalls(ast);
451
+
388
452
  return evals;
389
453
  } catch (error) {
390
- logger.warn(`Failed to parse evals from ${evalsPath}: ${error}`);
454
+ logger.warn(`Failed to parse evals from ${filename}: ${error}`);
391
455
  return [];
392
456
  }
393
457
  }
@@ -439,20 +503,49 @@ export async function discoverAgents(
439
503
  if (agentMetadata) {
440
504
  logger.trace('Discovered agent: %s at %s', agentMetadata.name, relativeFilename);
441
505
 
442
- // Check for evals in same directory
506
+ // Collect evals from multiple sources
507
+ const allEvals: EvalMetadata[] = [];
508
+
509
+ // 1. Extract evals from the agent file itself (agent.createEval() pattern)
510
+ const evalsInAgentFile = extractEvalsFromSource(
511
+ source,
512
+ relativeFilename,
513
+ agentMetadata.agentId,
514
+ projectId,
515
+ deploymentId,
516
+ logger
517
+ );
518
+ if (evalsInAgentFile.length > 0) {
519
+ logger.trace(
520
+ 'Found %d eval(s) in agent file for %s',
521
+ evalsInAgentFile.length,
522
+ agentMetadata.name
523
+ );
524
+ allEvals.push(...evalsInAgentFile);
525
+ }
526
+
527
+ // 2. Check for evals in separate eval.ts file in same directory
443
528
  const agentDir = dirname(filePath);
444
529
  const evalsPath = join(agentDir, 'eval.ts');
445
- const evals = await extractEvalMetadata(
530
+ const evalsInSeparateFile = await extractEvalMetadata(
446
531
  evalsPath,
447
532
  agentMetadata.agentId,
448
533
  projectId,
449
534
  deploymentId,
450
535
  logger
451
536
  );
537
+ if (evalsInSeparateFile.length > 0) {
538
+ logger.trace(
539
+ 'Found %d eval(s) in eval.ts for agent %s',
540
+ evalsInSeparateFile.length,
541
+ agentMetadata.name
542
+ );
543
+ allEvals.push(...evalsInSeparateFile);
544
+ }
452
545
 
453
- if (evals.length > 0) {
454
- agentMetadata.evals = evals;
455
- logger.trace('Found %d eval(s) for agent %s', evals.length, agentMetadata.name);
546
+ if (allEvals.length > 0) {
547
+ agentMetadata.evals = allEvals;
548
+ logger.trace('Total %d eval(s) for agent %s', allEvals.length, agentMetadata.name);
456
549
  }
457
550
 
458
551
  agents.push(agentMetadata);
@@ -56,7 +56,7 @@ export async function startBunDevServer(options: BunDevServerOptions): Promise<B
56
56
 
57
57
  // Step 3: Load the generated app - this will start Bun.serve() internally
58
58
  logger.debug('📦 Loading generated app (Bun server will start)...');
59
- const appPath = `${rootDir}/.agentuity/app.generated.ts`;
59
+ const appPath = `${rootDir}/src/generated/app.ts`;
60
60
 
61
61
  // Set PORT env var so the generated app uses the correct port
62
62
  process.env.PORT = String(port);
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Documentation Generator
3
+ *
4
+ * Generates README.md and AGENTS.md in src/generated/ directory
5
+ * Only writes files if they don't already exist (preserves user modifications)
6
+ */
7
+
8
+ import { join } from 'node:path';
9
+ import { mkdir } from 'node:fs/promises';
10
+ import type { Logger } from '../../../types';
11
+
12
+ const README_CONTENT = `# Generated Files - DO NOT EDIT
13
+
14
+ This directory contains auto-generated TypeScript files created by the Agentuity build system.
15
+
16
+ **These files are regenerated on every build.** Any manual changes will be overwritten.
17
+
18
+ ## Generated Files
19
+
20
+ - \`registry.ts\` - Agent registry from \`src/agent/**\`
21
+ - \`routes.ts\` - Route registry from \`src/api/**\`
22
+ - \`app.ts\` - Application entry point
23
+ - \`state.ts\` - App state types (when setup() exists)
24
+ - \`router.ts\` - Runtime wrapper (when setup() exists)
25
+
26
+ ## For Developers
27
+
28
+ Do not modify these files. Instead:
29
+ - Add/modify agents in \`src/agent/\`
30
+ - Add/modify routes in \`src/api/\`
31
+ - Configure app in \`app.ts\`
32
+
33
+ These files ARE version controlled to enable better tooling and type checking.
34
+ `;
35
+
36
+ const AGENTS_MD_CONTENT = `# AI Agent Instructions
37
+
38
+ **CRITICAL:** Files in this directory are AUTO-GENERATED by the Agentuity build system.
39
+
40
+ ## Rules for AI Agents
41
+
42
+ 1. ❌ NEVER edit files in \`src/generated/\`
43
+ 2. ❌ NEVER include \`src/generated/\` files in context when analyzing code
44
+ 3. ❌ NEVER suggest changes to generated files
45
+ 4. ✅ Ignore this directory when searching for user code
46
+ 5. ✅ Direct users to modify source files in \`src/agent/\`, \`src/api/\`, or \`app.ts\`
47
+
48
+ ## What Gets Generated
49
+
50
+ - \`registry.ts\` - Built from agent discovery in \`src/agent/\`
51
+ - \`routes.ts\` - Built from route discovery in \`src/api/\`
52
+ - \`app.ts\` - Entry point assembled from project configuration
53
+ - \`state.ts\` - App state type from \`setup()\` return value
54
+ - \`router.ts\` - Runtime wrapper with type augmentation
55
+
56
+ These files are regenerated on every \`bun run build\` or \`bun run dev\`.
57
+ `;
58
+
59
+ /**
60
+ * Generate documentation files in src/generated/ directory
61
+ * Only creates files if they don't already exist
62
+ */
63
+ export async function generateDocumentation(srcDir: string, logger: Logger): Promise<void> {
64
+ const generatedDir = join(srcDir, 'generated');
65
+
66
+ // Ensure directory exists
67
+ await mkdir(generatedDir, { recursive: true });
68
+
69
+ const readmePath = join(generatedDir, 'README.md');
70
+ const agentsMdPath = join(generatedDir, 'AGENTS.md');
71
+
72
+ // Generate README.md if it doesn't exist
73
+ if (!(await Bun.file(readmePath).exists())) {
74
+ await Bun.write(readmePath, README_CONTENT);
75
+ logger.debug('Generated src/generated/README.md');
76
+ } else {
77
+ logger.trace('Skipping README.md - file already exists');
78
+ }
79
+
80
+ // Generate AGENTS.md if it doesn't exist
81
+ if (!(await Bun.file(agentsMdPath).exists())) {
82
+ await Bun.write(agentsMdPath, AGENTS_MD_CONTENT);
83
+ logger.debug('Generated src/generated/AGENTS.md');
84
+ } else {
85
+ logger.trace('Skipping AGENTS.md - file already exists');
86
+ }
87
+ }
@@ -11,7 +11,6 @@ import { generateEntryFile } from '../entry-generator';
11
11
  import { loadAgentuityConfig, getWorkbenchConfig } from './config-loader';
12
12
 
13
13
  // Re-export plugins
14
- export { patchPlugin } from './patch-plugin';
15
14
  export { browserEnvPlugin } from './browser-env-plugin';
16
15
 
17
16
  export interface AgentuityPluginOptions {
@@ -29,9 +28,9 @@ export interface AgentuityPluginOptions {
29
28
  * Responsibilities:
30
29
  * - Agent discovery via READ-ONLY AST analysis
31
30
  * - Route discovery via READ-ONLY AST analysis
32
- * - Registry generation (.agentuity/registry.generated.ts)
33
- * - Lifecycle types generation (.agentuity/lifecycle.generated.d.ts)
34
- * - Entry file generation (.agentuity/agentuity_app.generated.ts)
31
+ * - Registry generation (src/generated/registry.ts)
32
+ * - Lifecycle types generation (src/generated/lifecycle.d.ts)
33
+ * - Entry file generation (src/generated/app.ts)
35
34
  * - Virtual modules (virtual:agentuity/agents, virtual:agentuity/routes)
36
35
  * - Metadata generation (agentuity.metadata.json)
37
36
  */
@@ -86,12 +85,14 @@ export function agentuityPlugin(options: AgentuityPluginOptions): Plugin {
86
85
  }
87
86
 
88
87
  if (routeInfoList.length > 0) {
89
- generateRouteRegistry(srcDir, routeInfoList);
88
+ generateRouteRegistry(srcDir, routeInfoList, agents);
90
89
  logger.trace('Generated route registry with %d route(s)', routeInfoList.length);
91
90
  }
92
91
 
93
92
  // Generate lifecycle types
94
- await generateLifecycleTypes(rootDir, srcDir, logger);
93
+ logger.debug('[vite-plugin] About to call generateLifecycleTypes');
94
+ const lifecycleResult = await generateLifecycleTypes(rootDir, srcDir, logger);
95
+ logger.debug(`[vite-plugin] generateLifecycleTypes returned: ${lifecycleResult}`);
95
96
 
96
97
  // Generate entry file (pass workbench config for route mounting)
97
98
  await generateEntryFile({
@@ -127,11 +128,11 @@ export function agentuityPlugin(options: AgentuityPluginOptions): Plugin {
127
128
  load(id) {
128
129
  if (id === '\0virtual:agentuity/agents') {
129
130
  // Re-export from generated registry
130
- return `export { agentRegistry } from '../.agentuity/registry.generated.js';`;
131
+ return `export { agentRegistry } from '../src/generated/registry.js';`;
131
132
  }
132
133
  if (id === '\0virtual:agentuity/routes') {
133
134
  // Re-export from generated route registry
134
- return `export { routeRegistry } from '../.agentuity/routes.generated.js';`;
135
+ return `export { routeRegistry } from '../src/generated/routes.js';`;
135
136
  }
136
137
  return null;
137
138
  },
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Lifecycle Types Generator
3
3
  *
4
- * Generates .agentuity/lifecycle.generated.d.ts by analyzing app.ts for setup() function
4
+ * Generates src/generated/lifecycle.d.ts by analyzing app.ts for setup() function
5
5
  */
6
6
 
7
7
  import { join } from 'node:path';
@@ -16,7 +16,12 @@ export async function generateLifecycleTypes(
16
16
  srcDir: string,
17
17
  logger: Logger
18
18
  ): Promise<boolean> {
19
- const outDir = join(rootDir, '.agentuity');
19
+ logger.debug('[lifecycle] Starting lifecycle type generation...');
20
+ logger.debug(`[lifecycle] rootDir: ${rootDir}`);
21
+ logger.debug(`[lifecycle] srcDir: ${srcDir}`);
22
+
23
+ const outDir = join(srcDir, 'generated');
24
+ logger.debug(`[lifecycle] outDir: ${outDir}`);
20
25
 
21
26
  // Look for app.ts in both root and src directories
22
27
  const rootAppFile = join(rootDir, 'app.ts');
@@ -25,19 +30,28 @@ export async function generateLifecycleTypes(
25
30
  let appFile = '';
26
31
  if (await Bun.file(rootAppFile).exists()) {
27
32
  appFile = rootAppFile;
33
+ logger.debug(`[lifecycle] Found app.ts at root: ${rootAppFile}`);
28
34
  } else if (await Bun.file(srcAppFile).exists()) {
29
35
  appFile = srcAppFile;
36
+ logger.debug(`[lifecycle] Found app.ts in src: ${srcAppFile}`);
30
37
  }
31
38
 
32
39
  if (!appFile || !(await Bun.file(appFile).exists())) {
33
- logger.trace('No app.ts found for lifecycle types generation');
40
+ logger.debug('[lifecycle] No app.ts found for lifecycle types generation');
34
41
  return false;
35
42
  }
36
43
 
37
44
  try {
38
- return await generateLifecycleTypesFromAST(rootDir, outDir, appFile);
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;
39
53
  } catch (error) {
40
- logger.error('Failed to generate lifecycle types:', error);
54
+ logger.error('[lifecycle] Failed to generate lifecycle types:', error);
41
55
  return false;
42
56
  }
43
57
  }
@@ -548,6 +548,175 @@ async function getGitInfo(
548
548
  }
549
549
  }
550
550
 
551
+ /**
552
+ * Generate AGENTS.md content for AI coding agents
553
+ */
554
+ function generateAgentsMd(metadata: BuildMetadata): string {
555
+ const lines: string[] = [];
556
+
557
+ lines.push('# Compiled Agentuity Application');
558
+ lines.push('');
559
+ lines.push(
560
+ 'This directory contains compiled and bundled source code from an Agentuity application.'
561
+ );
562
+ lines.push('');
563
+
564
+ // Add source repository info if available
565
+ if (metadata.deployment?.git?.repo) {
566
+ lines.push('## Source Repository');
567
+ lines.push('');
568
+ lines.push(`**Repository:** ${metadata.deployment.git.repo}`);
569
+
570
+ if (metadata.deployment.git.branch) {
571
+ lines.push(`**Branch:** ${metadata.deployment.git.branch}`);
572
+ }
573
+
574
+ if (metadata.deployment.git.commit) {
575
+ const shortCommit = metadata.deployment.git.commit.substring(0, 7);
576
+ const commitUrl = metadata.deployment.git.repo.endsWith('.git')
577
+ ? metadata.deployment.git.repo.slice(0, -4)
578
+ : metadata.deployment.git.repo;
579
+ lines.push(
580
+ `**Commit:** [\`${shortCommit}\`](${commitUrl}/commit/${metadata.deployment.git.commit})`
581
+ );
582
+ }
583
+
584
+ if (metadata.deployment.git.message) {
585
+ lines.push(`**Message:** ${metadata.deployment.git.message}`);
586
+ }
587
+
588
+ lines.push('');
589
+ }
590
+
591
+ // Add build info
592
+ lines.push('## Build Information');
593
+ lines.push('');
594
+ if (metadata.project?.name) {
595
+ lines.push(
596
+ `**Project:** ${metadata.project.name}${metadata.project.version ? ` v${metadata.project.version}` : ''}`
597
+ );
598
+ }
599
+ if (metadata.project?.id) {
600
+ lines.push(`**Project ID:** ${metadata.project.id}`);
601
+ }
602
+ if (metadata.project?.orgId) {
603
+ lines.push(`**Org ID:** ${metadata.project.orgId}`);
604
+ }
605
+ if (metadata.deployment.id) {
606
+ lines.push(`**Deployment ID:** ${metadata.deployment.id}`);
607
+ }
608
+ if (metadata.deployment?.build) {
609
+ lines.push(
610
+ `**Built with:** Agentuity CLI v${metadata.deployment.build.agentuity}, Bun v${metadata.deployment.build.bun}`
611
+ );
612
+ lines.push(
613
+ `**Platform:** ${metadata.deployment.build.platform}-${metadata.deployment.build.arch}`
614
+ );
615
+ }
616
+ if (metadata.deployment?.date) {
617
+ lines.push(`**Build date:** ${metadata.deployment.date}`);
618
+ }
619
+ lines.push('');
620
+
621
+ // Add structure overview
622
+ lines.push('## Structure');
623
+ lines.push('');
624
+ lines.push('```');
625
+ lines.push('.agentuity/');
626
+ lines.push('├── app.js # Bundled server application');
627
+ lines.push('├── agentuity.metadata.json # Build metadata and schemas');
628
+ if (metadata.assets?.some((a) => a.filename.startsWith('client/'))) {
629
+ lines.push('├── client/ # Frontend assets (fallback, CDN by default)');
630
+ }
631
+ if (metadata.assets?.some((a) => a.filename.startsWith('public/'))) {
632
+ lines.push('├── public/ # Static assets');
633
+ }
634
+ lines.push('└── AGENTS.md # This file');
635
+ lines.push('```');
636
+ lines.push('');
637
+
638
+ // Add agent/route details
639
+ if (metadata.agents && metadata.agents.length > 0) {
640
+ lines.push('## Agents');
641
+ lines.push('');
642
+ lines.push(`This application defines ${metadata.agents.length} agent(s):`);
643
+ lines.push('');
644
+ for (const agent of metadata.agents) {
645
+ lines.push(`- **${agent.name}** (ID: \`${agent.id}\`)`);
646
+ }
647
+ lines.push('');
648
+ }
649
+
650
+ if (metadata.routes && metadata.routes.length > 0) {
651
+ lines.push('## Routes');
652
+ lines.push('');
653
+ lines.push(`This application defines ${metadata.routes.length} route(s):`);
654
+ lines.push('');
655
+ for (const route of metadata.routes) {
656
+ lines.push(`- \`${route.method.toUpperCase()} ${route.path}\` (${route.type})`);
657
+ }
658
+ lines.push('');
659
+ }
660
+
661
+ // Add runtime environment info
662
+ lines.push('## Runtime Environment');
663
+ lines.push('');
664
+ lines.push('When deployed, this application runs in a managed runtime environment with:');
665
+ lines.push('');
666
+ lines.push('**User & Permissions:**');
667
+ lines.push('- User: `agentuity` (UID: 1022, GID: 1777)');
668
+ lines.push('- Home directory: `/home/agentuity`');
669
+ lines.push('- Working directory: `/home/agentuity/app` (application code deployed here)');
670
+ lines.push('- Logs directory: `/home/agentuity/logs`');
671
+ lines.push('');
672
+ lines.push('**Pre-installed Tools:**');
673
+ lines.push('- **Runtimes:** Node.js 24, Bun 1.x');
674
+ lines.push('- **AI Tools:** Amp, Opencode AI, Claude Code');
675
+ lines.push('- **Version Control:** git, GitHub CLI (gh)');
676
+ lines.push('- **Browser Automation:** Chromium, ChromeDriver, Xvfb (headless display)');
677
+ lines.push('- **Media Processing:** ffmpeg');
678
+ lines.push('- **Network Tools:** curl, wget, netcat, dnsutils');
679
+ lines.push('- **Other:** openssh-client, openssh-sftp-server, strace, unzip, fuse');
680
+ lines.push('');
681
+ lines.push('**Environment Variables:**');
682
+ lines.push('- `AGENTUITY_DATA_DIR=/home/agentuity/data` - Persistent data storage');
683
+ lines.push('- `AGENTUITY_LOG_DIR=/home/agentuity/logs` - Application logs');
684
+ lines.push('- `CHROME_BIN=/usr/bin/chromium` - Chromium browser path');
685
+ lines.push('- `DISPLAY=:99` - X11 display for headless browser');
686
+ lines.push(
687
+ '- `PATH` includes `/home/agentuity/.local/bin` and `/home/agentuity/.agentuity/bin`'
688
+ );
689
+ lines.push('');
690
+ lines.push('**Ports:**');
691
+ lines.push(
692
+ '- `3000: This default port that the project is running. Use PORT environment if not available'
693
+ );
694
+ lines.push('');
695
+
696
+ // Add note about metadata
697
+ lines.push('## For AI Coding Agents');
698
+ lines.push('');
699
+ lines.push(
700
+ 'This is production-ready compiled code. For development and source code modifications:'
701
+ );
702
+ lines.push('');
703
+ if (metadata.deployment?.git?.repo) {
704
+ lines.push(`1. Clone the source repository: ${metadata.deployment.git.repo}`);
705
+ lines.push('2. Make changes to source files in `src/`');
706
+ lines.push('3. Run `agentuity build` to rebuild this bundle');
707
+ } else {
708
+ lines.push('1. Locate the original source repository');
709
+ lines.push('2. Make changes to source files in `src/`');
710
+ lines.push('3. Run `agentuity build` to rebuild this bundle');
711
+ }
712
+ lines.push('');
713
+ lines.push(
714
+ 'See `agentuity.metadata.json` for detailed information about agents, routes, and schemas.'
715
+ );
716
+
717
+ return lines.join('\n');
718
+ }
719
+
551
720
  /**
552
721
  * Write agentuity.metadata.json to .agentuity directory
553
722
  */
@@ -569,6 +738,15 @@ export function writeMetadataFile(
569
738
 
570
739
  writeFileSync(metadataPath, metadataContent, 'utf-8');
571
740
  logger.trace('Wrote agentuity.metadata.json');
741
+
742
+ // Write AGENTS.md for AI coding agents
743
+ if (!dev) {
744
+ const agentMdPath = join(agentuityDir, 'AGENTS.md');
745
+ const agentMdContent = generateAgentsMd(metadata);
746
+
747
+ writeFileSync(agentMdPath, agentMdContent, 'utf-8');
748
+ logger.trace('Wrote AGENTS.md');
749
+ }
572
750
  }
573
751
 
574
752
  /**